From: Stefan Schulze Frielinghaus <[email protected]>

With the current implementation, for an alternative like {r0}{r1}...{rn}
the last hard register constraint {rn} would always win which is not
what users expect.  Therefore, error out in case of multiple hard
register constraints in one alternative.

As far as I can tell right now, there is no inherent problem with
supporting multiple hard register constraints in one alternative or even
ad-hoc register classes.  However, in light of reaching stage 4, this is
something for another release.

Likewise, a combination of hard register constraints and regular
register constraints is not supported.  Note, a combination of hard
register constraints and non-register constraints as e.g. immediate
constraints is supported.  This is inspired by the i386 target where
constraints like aI are used which could be expressed as {ax}I, too.

gcc/ChangeLog:

        * stmt.cc (parse_output_constraint): Reject multiple hard
        register constraints or a combination of hard register
        constraints and regular register constraints in one alternative.
        (parse_input_constraint): Ditto.

gcc/testsuite/ChangeLog:

        * gcc.dg/asm-hard-reg-error-1.c: Remove tests containing
        multiple hard register constraints in one alternative.
        * gcc.dg/asm-hard-reg-error-6.c: New test.
---
 Bootstrapped and regtested on s390 and x86_64.  Ok for mainline?

 gcc/stmt.cc                                 | 66 ++++++++++++++++++++-
 gcc/testsuite/gcc.dg/asm-hard-reg-error-1.c |  3 +-
 gcc/testsuite/gcc.dg/asm-hard-reg-error-6.c | 35 +++++++++++
 3 files changed, 100 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/asm-hard-reg-error-6.c

diff --git a/gcc/stmt.cc b/gcc/stmt.cc
index 5816fb9b3b6..382a2d75c07 100644
--- a/gcc/stmt.cc
+++ b/gcc/stmt.cc
@@ -322,6 +322,11 @@ parse_output_constraint (const char **constraint_p, int 
operand_num,
 
   unsigned int alt = 0;
   bool early_clobbered = false;
+  /* Currently, multiple hard register constraints in one alternative are not
+     supported.  A combination of hard register constraints and regular
+     register constraints is also not supported.  */
+  bool alt_has_hard_reg_cstr = false;
+  bool alt_has_reg_cstr = false;
 
   /* Loop through the constraint string.  */
   for (p = constraint + 1; *p; )
@@ -357,6 +362,8 @@ parse_output_constraint (const char **constraint_p, int 
operand_num,
        case ',':
          ++alt;
          early_clobbered = false;
+         alt_has_hard_reg_cstr = false;
+         alt_has_reg_cstr = false;
          break;
 
        case '0':  case '1':  case '2':  case '3':  case '4':
@@ -390,6 +397,21 @@ parse_output_constraint (const char **constraint_p, int 
operand_num,
              }
            if (reg_info)
              {
+               if (alt_has_reg_cstr)
+                 {
+                   error (
+                       "hard register constraints and regular register "
+                       "constraints in one alternative are not supported");
+                   return false;
+                 }
+               if (alt_has_hard_reg_cstr)
+                 {
+                   error (
+                       "multiple hard register constraints in one "
+                       "alternative are not supported");
+                   return false;
+                 }
+               alt_has_hard_reg_cstr = true;
                int regno = decode_hard_reg_constraint (p);
                if (regno < 0)
                  {
@@ -441,7 +463,17 @@ parse_output_constraint (const char **constraint_p, int 
operand_num,
          enum constraint_num cn = lookup_constraint (p);
          if (reg_class_for_constraint (cn) != NO_REGS
              || insn_extra_address_constraint (cn))
-           *allows_reg = true;
+           {
+             if (alt_has_hard_reg_cstr)
+               {
+                 error (
+                     "hard register constraints and regular register "
+                     "constraints in one alternative are not supported");
+                 return false;
+               }
+             alt_has_reg_cstr = true;
+             *allows_reg = true;
+           }
          else if (insn_extra_memory_constraint (cn))
            *allows_mem = true;
          else
@@ -503,6 +535,9 @@ parse_input_constraint (const char **constraint_p, int 
input_num,
   *allows_mem = false;
   *allows_reg = false;
 
+  bool alt_has_hard_reg_cstr = false;
+  bool alt_has_reg_cstr = false;
+
   /* Make sure constraint has neither `=', `+', nor '&'.  */
 
   unsigned int alt = 0;
@@ -555,6 +590,8 @@ repeat:
 
       case ',':
        ++alt;
+       alt_has_hard_reg_cstr = false;
+       alt_has_reg_cstr = false;
        break;
 
        /* Whether or not a numeric constraint allows a register is
@@ -607,6 +644,21 @@ repeat:
            }
          if (reg_info)
            {
+             if (alt_has_reg_cstr)
+               {
+                 error (
+                     "hard register constraints and regular register "
+                     "constraints in one alternative are not supported");
+                 return false;
+               }
+             if (alt_has_hard_reg_cstr)
+               {
+                 error (
+                     "multiple hard register constraints in one "
+                     "alternative are not supported");
+                 return false;
+               }
+             alt_has_hard_reg_cstr = true;
              int regno = decode_hard_reg_constraint (constraint + j);
              if (regno < 0)
                {
@@ -666,7 +718,17 @@ repeat:
        enum constraint_num cn = lookup_constraint (constraint + j);
        if (reg_class_for_constraint (cn) != NO_REGS
            || insn_extra_address_constraint (cn))
-         *allows_reg = true;
+         {
+           if (alt_has_hard_reg_cstr)
+             {
+               error (
+                   "hard register constraints and regular register "
+                   "constraints in one alternative are not supported");
+               return false;
+             }
+           alt_has_reg_cstr = true;
+           *allows_reg = true;
+         }
        else if (insn_extra_memory_constraint (cn)
                 || insn_extra_special_memory_constraint (cn)
                 || insn_extra_relaxed_memory_constraint (cn))
diff --git a/gcc/testsuite/gcc.dg/asm-hard-reg-error-1.c 
b/gcc/testsuite/gcc.dg/asm-hard-reg-error-1.c
index 0a31c8508c7..3569c6d28ad 100644
--- a/gcc/testsuite/gcc.dg/asm-hard-reg-error-1.c
+++ b/gcc/testsuite/gcc.dg/asm-hard-reg-error-1.c
@@ -65,7 +65,6 @@ test (void)
   __asm__ ("" :: GPR1","GPR2 (42), GPR2","GPR3 (42));
   __asm__ ("" :: GPR1","GPR2 (42), GPR3","GPR2 (42)); /* { dg-error "multiple 
inputs to hard register" } */
   __asm__ ("" :: GPR1","GPR2 (42), GPR1","GPR3 (42)); /* { dg-error "multiple 
inputs to hard register" } */
-  __asm__ ("" :: GPR1 GPR2 (42), GPR2 (42)); /* { dg-error "multiple inputs to 
hard register" } */
   __asm__ ("" : "+"GPR1 (x), "="GPR1 (y)); /* { dg-error "multiple outputs to 
hard register" } */
   __asm__ ("" : "="GPR1 (y) : GPR1 (42), "0" (42)); /* { dg-error "multiple 
inputs to hard register" } */
   __asm__ ("" : "+"GPR1 (x) : GPR1 (42)); /* { dg-error "multiple inputs to 
hard register" } */
@@ -74,7 +73,7 @@ test (void)
   __asm__ ("" : "="GPR2 (gpr1)); /* { dg-error "constraint and register 'asm' 
for output operand 0 are unsatisfiable" } */
   __asm__ ("" :: GPR2 (gpr1)); /* { dg-error "constraint and register 'asm' 
for input operand 0 are unsatisfiable" } */
   __asm__ ("" : "="GPR1 (x) : "0" (gpr1));
-  __asm__ ("" : "="GPR1 GPR2 (x) : "0" (gpr1)); /* { dg-error "constraint and 
register 'asm' for input operand 0 are unsatisfiable" } */
+  __asm__ ("" : "="GPR2 (x) : "0" (gpr1)); /* { dg-error "constraint and 
register 'asm' for input operand 0 are unsatisfiable" } */
 
   __asm__ ("" : "=&"GPR1 (x) : "0" (gpr1));
   __asm__ ("" : "=&"GPR1 (x) : "0" (42));
diff --git a/gcc/testsuite/gcc.dg/asm-hard-reg-error-6.c 
b/gcc/testsuite/gcc.dg/asm-hard-reg-error-6.c
new file mode 100644
index 00000000000..f5829bda921
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/asm-hard-reg-error-6.c
@@ -0,0 +1,35 @@
+/* { dg-do compile { target lra } } */
+
+#if defined __hppa__
+# define R0 "20"
+# define R1 "21"
+#elif defined __AVR__
+# define R0 "20"
+# define R1 "24"
+#elif defined __PRU__
+# define R0 "0"
+# define R1 "4"
+#else
+# define R0 "0"
+# define R1 "1"
+#endif
+
+int
+test (void)
+{
+  int x;
+
+  __asm__ ("" : "={"R0"}{"R1"}" (x));            /* { dg-error "multiple hard 
register constraints in one alternative are not supported" } */
+  __asm__ ("" : "={"R0"}m{"R1"}" (x) : "r" (x)); /* { dg-error "multiple hard 
register constraints in one alternative are not supported" } */
+  __asm__ ("" : "={"R0"}m" (x) : "r" (x));
+  __asm__ ("" : "=r" (x) : "{"R0"}{"R1"}" (x));  /* { dg-error "multiple hard 
register constraints in one alternative are not supported" } */
+  __asm__ ("" : "=r" (x) : "{"R0"}i{"R1"}" (x)); /* { dg-error "multiple hard 
register constraints in one alternative are not supported" } */
+  __asm__ ("" : "=r" (x) : "{"R0"}i" (x));
+
+  __asm__ ("" : "={"R0"}r" (x) : "r" (x)); /* { dg-error "hard register 
constraints and regular register constraints in one alternative are not 
supported" } */
+  __asm__ ("" : "=r{"R0"}" (x) : "r" (x)); /* { dg-error "hard register 
constraints and regular register constraints in one alternative are not 
supported" } */
+  __asm__ ("" : "=r" (x) : "{"R0"}r" (x)); /* { dg-error "hard register 
constraints and regular register constraints in one alternative are not 
supported" } */
+  __asm__ ("" : "=r" (x) : "r{"R0"}" (x)); /* { dg-error "hard register 
constraints and regular register constraints in one alternative are not 
supported" } */
+
+  return x;
+}
-- 
2.52.0

Reply via email to