[gcc r16-6805] Deal with combinations of hard register constraints

Stefan Schulze Frielinghaus stefansf@gcc.gnu.org
Thu Jan 15 14:16:35 GMT 2026


https://gcc.gnu.org/g:804912edbfc93b6f68869aff736eec159423fd43

commit r16-6805-g804912edbfc93b6f68869aff736eec159423fd43
Author: Stefan Schulze Frielinghaus <stefansf@gcc.gnu.org>
Date:   Thu Jan 15 15:14:59 2026 +0100

    Deal with combinations of hard register constraints
    
    Currently, multiple hard register constraints in one alternative are not
    supported.  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:
    
            * doc/extend.texi: Document current limitations of hard register
            constraints.
            * 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.

Diff:
---
 gcc/doc/extend.texi                         |  4 ++
 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 +++++++++++++++
 4 files changed, 104 insertions(+), 4 deletions(-)

diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index a5c687f2667e..b4879b3d82ff 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -13544,6 +13544,10 @@ asm ("" : "=r" (x));
 
 are not supported for hard register constraints.  This might be lifted.
 
+Multiple hard register constraints in one alternative are also not supported.
+Furthermore, combinations of hard register constraints and regular register
+constraints in one alternative are not supported, too.
+
 @node Size of an asm
 @subsection Size of an @code{asm}
 
diff --git a/gcc/stmt.cc b/gcc/stmt.cc
index 5816fb9b3b6e..382a2d75c076 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 0a31c8508c76..3569c6d28adc 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 000000000000..f5829bda9213
--- /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;
+}


More information about the Gcc-cvs mailing list