diff mbox series

[asmcons] Fix PR rtl-optimization/89313: ICE in process_alt_operands, at lra-constraints.c:2962

Message ID 9875286e-cc51-abed-626a-4b36717e52e3@linux.ibm.com
State New
Headers show
Series [asmcons] Fix PR rtl-optimization/89313: ICE in process_alt_operands, at lra-constraints.c:2962 | expand

Commit Message

Peter Bergner Feb. 21, 2019, 3:19 a.m. UTC
PR89313 exposes a bug in the asmcons pass where it replaces input operands
with matching constraints with their associated output operands, as well as
all other uses of its pseudo registers.  This is normally fine.  However, if
the matched output operand is marked as early clobber, then we cannot replace
the uses of 'input' that do not have matching constraints, since they by
definition conflict with the early clobber output operand and could be
clobbered if assigned to the same register as the output operand.

The patch below fixes the bug by only doing the input pseudo replacement
if the output operand is not early clobber or the input operand is known
to be a matching constraint.

This passed bootstrap and regression testing with no regressions on
both x86_64-linux and powerpc64le-linux.  Ok for mainline?

Peter


gcc/
	PR rtl-optimization/89313
	* function.c (matching_constraint_num): New static function.
	(match_asm_constraints_1): Use it.  Fixup white space and comment.
	Don't replace inputs with non-matching constraints which conflict
	with early clobber outputs.

gcc/testsuite/
	PR rtl-optimization/89313
	* gcc.dg/pr89313.c: New test.

Comments

Segher Boessenkool March 6, 2019, 2:47 p.m. UTC | #1
Hi Peter,

On Wed, Feb 20, 2019 at 09:19:58PM -0600, Peter Bergner wrote:
> PR89313 exposes a bug in the asmcons pass where it replaces input operands
> with matching constraints with their associated output operands, as well as
> all other uses of its pseudo registers.  This is normally fine.  However, if
> the matched output operand is marked as early clobber, then we cannot replace
> the uses of 'input' that do not have matching constraints, since they by
> definition conflict with the early clobber output operand and could be
> clobbered if assigned to the same register as the output operand.
> 
> The patch below fixes the bug by only doing the input pseudo replacement
> if the output operand is not early clobber or the input operand is known
> to be a matching constraint.
> 
> This passed bootstrap and regression testing with no regressions on
> both x86_64-linux and powerpc64le-linux.  Ok for mainline?

Looks fine to me, but I cannot approve it of course.  Some trivial
comments:

> +/* If CONSTRAINT is a matching constraint, then return its number.
> +   Otherwise, return -1.  */
> +
> +static int
> +matching_constraint_num (const char *constraint)
> +{
> +  int match;
> +
> +  if (*constraint == '%')
> +    constraint++;
> +
> +  switch (*constraint)
> +    {
> +    case '0': case '1': case '2': case '3': case '4':
> +    case '5': case '6': case '7': case '8': case '9':
> +      {
> +	char *end;
> +	match = strtoul (constraint, &end, 10);
> +	if (end == constraint)
> +	  match = -1;

This condition is always false, because we have at least one digit.

> +	break;
> +      }
> +
> +    default:
> +      match = -1;
> +      break;
> +    }
> +  return match;
> +}

Which means you can write it as just

static int
matching_constraint_num (const char *constraint)
{
  if (*constraint == '%')
    constraint++;

  if (IN_RANGE (*constraint, '0', '9'))
    return strtoul (constraint, NULL, 10);

  return -1;
}


Segher
Peter Bergner March 6, 2019, 2:56 p.m. UTC | #2
On 3/6/19 8:47 AM, Segher Boessenkool wrote:
> Which means you can write it as just
> 
> static int
> matching_constraint_num (const char *constraint)
> {
>   if (*constraint == '%')
>     constraint++;
> 
>   if (IN_RANGE (*constraint, '0', '9'))
>     return strtoul (constraint, NULL, 10);
> 
>   return -1;
> }

Ok, changed.  Thanks!


Peter
Peter Bergner March 6, 2019, 4:04 p.m. UTC | #3
On 3/6/19 8:56 AM, Peter Bergner wrote:
> On 3/6/19 8:47 AM, Segher Boessenkool wrote:
>> Which means you can write it as just
>>
>> static int
>> matching_constraint_num (const char *constraint)
>> {
>>   if (*constraint == '%')
>>     constraint++;
>>
>>   if (IN_RANGE (*constraint, '0', '9'))
>>     return strtoul (constraint, NULL, 10);
>>
>>   return -1;
>> }
> 
> Ok, changed.  Thanks!

...and re-bootstrapping and regtesting were clean with that change.

Peter
Jeff Law March 25, 2019, 8:36 p.m. UTC | #4
On 2/20/19 8:19 PM, Peter Bergner wrote:
> PR89313 exposes a bug in the asmcons pass where it replaces input operands
> with matching constraints with their associated output operands, as well as
> all other uses of its pseudo registers.  This is normally fine.  However, if
> the matched output operand is marked as early clobber, then we cannot replace
> the uses of 'input' that do not have matching constraints, since they by
> definition conflict with the early clobber output operand and could be
> clobbered if assigned to the same register as the output operand.
> 
> The patch below fixes the bug by only doing the input pseudo replacement
> if the output operand is not early clobber or the input operand is known
> to be a matching constraint.
> 
> This passed bootstrap and regression testing with no regressions on
> both x86_64-linux and powerpc64le-linux.  Ok for mainline?
> 
> Peter
> 
> 
> gcc/
> 	PR rtl-optimization/89313
> 	* function.c (matching_constraint_num): New static function.
> 	(match_asm_constraints_1): Use it.  Fixup white space and comment.
> 	Don't replace inputs with non-matching constraints which conflict
> 	with early clobber outputs.
> 
> gcc/testsuite/
> 	PR rtl-optimization/89313
> 	* gcc.dg/pr89313.c: New test.
OK.
jeff
Peter Bergner March 27, 2019, 5:02 p.m. UTC | #5
On 3/25/19 3:36 PM, Jeff Law wrote:
> On 2/20/19 8:19 PM, Peter Bergner wrote:
>> gcc/
>> 	PR rtl-optimization/89313
>> 	* function.c (matching_constraint_num): New static function.
>> 	(match_asm_constraints_1): Use it.  Fixup white space and comment.
>> 	Don't replace inputs with non-matching constraints which conflict
>> 	with early clobber outputs.
>>
>> gcc/testsuite/
>> 	PR rtl-optimization/89313
>> 	* gcc.dg/pr89313.c: New test.
> OK.

I did another round of bootstrap and regtesting, since I was on vacation
and trunk has changed.  The testing was still clean, so it's committed now.
Thanks!

Peter
diff mbox series

Patch

Index: gcc/function.c
===================================================================
--- gcc/function.c	(revision 268883)
+++ gcc/function.c	(working copy)
@@ -6395,6 +6395,36 @@  make_pass_thread_prologue_and_epilogue (
 }
 
 
+/* If CONSTRAINT is a matching constraint, then return its number.
+   Otherwise, return -1.  */
+
+static int
+matching_constraint_num (const char *constraint)
+{
+  int match;
+
+  if (*constraint == '%')
+    constraint++;
+
+  switch (*constraint)
+    {
+    case '0': case '1': case '2': case '3': case '4':
+    case '5': case '6': case '7': case '8': case '9':
+      {
+	char *end;
+	match = strtoul (constraint, &end, 10);
+	if (end == constraint)
+	  match = -1;
+	break;
+      }
+
+    default:
+      match = -1;
+      break;
+    }
+  return match;
+}
+
 /* This mini-pass fixes fall-out from SSA in asm statements that have
    in-out constraints.  Say you start with
 
@@ -6453,14 +6483,10 @@  match_asm_constraints_1 (rtx_insn *insn,
       rtx input, output;
       rtx_insn *insns;
       const char *constraint = ASM_OPERANDS_INPUT_CONSTRAINT (op, i);
-      char *end;
       int match, j;
 
-      if (*constraint == '%')
-	constraint++;
-
-      match = strtoul (constraint, &end, 10);
-      if (end == constraint)
+      match = matching_constraint_num (constraint);
+      if (match < 0)
 	continue;
 
       gcc_assert (match < noutputs);
@@ -6477,14 +6503,14 @@  match_asm_constraints_1 (rtx_insn *insn,
       /* We can't do anything if the output is also used as input,
 	 as we're going to overwrite it.  */
       for (j = 0; j < ninputs; j++)
-        if (reg_overlap_mentioned_p (output, RTVEC_ELT (inputs, j)))
+	if (reg_overlap_mentioned_p (output, RTVEC_ELT (inputs, j)))
 	  break;
       if (j != ninputs)
 	continue;
 
       /* Avoid changing the same input several times.  For
 	 asm ("" : "=mr" (out1), "=mr" (out2) : "0" (in), "1" (in));
-	 only change in once (to out1), rather than changing it
+	 only change it once (to out1), rather than changing it
 	 first to out1 and afterwards to out2.  */
       if (i > 0)
 	{
@@ -6502,6 +6528,9 @@  match_asm_constraints_1 (rtx_insn *insn,
       end_sequence ();
       emit_insn_before (insns, insn);
 
+      constraint = ASM_OPERANDS_OUTPUT_CONSTRAINT(SET_SRC(p_sets[match]));
+      bool early_clobber_p = strchr (constraint, '&') != NULL;
+
       /* Now replace all mentions of the input with output.  We can't
 	 just replace the occurrence in inputs[i], as the register might
 	 also be used in some other input (or even in an address of an
@@ -6523,7 +6552,14 @@  match_asm_constraints_1 (rtx_insn *insn,
 	 value, but different pseudos) where we formerly had only one.
 	 With more complicated asms this might lead to reload failures
 	 which wouldn't have happen without this pass.  So, iterate over
-	 all operands and replace all occurrences of the register used.  */
+	 all operands and replace all occurrences of the register used.
+
+	 However, if one or more of the 'input' uses have a non-matching
+	 constraint and the matched output operand is an early clobber
+	 operand, then do not replace the input operand, since by definition
+	 it conflicts with the output operand and cannot share the same
+	 register.  See PR89313 for details.  */
+
       for (j = 0; j < noutputs; j++)
 	if (!rtx_equal_p (SET_DEST (p_sets[j]), input)
 	    && reg_overlap_mentioned_p (input, SET_DEST (p_sets[j])))
@@ -6531,8 +6567,13 @@  match_asm_constraints_1 (rtx_insn *insn,
 					      input, output);
       for (j = 0; j < ninputs; j++)
 	if (reg_overlap_mentioned_p (input, RTVEC_ELT (inputs, j)))
-	  RTVEC_ELT (inputs, j) = replace_rtx (RTVEC_ELT (inputs, j),
-					       input, output);
+	  {
+	    if (!early_clobber_p
+		|| match == matching_constraint_num
+			      (ASM_OPERANDS_INPUT_CONSTRAINT (op, j)))
+	      RTVEC_ELT (inputs, j) = replace_rtx (RTVEC_ELT (inputs, j),
+						   input, output);
+	  }
 
       changed = true;
     }
Index: gcc/testsuite/gcc.dg/pr89313.c
===================================================================
--- gcc/testsuite/gcc.dg/pr89313.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/pr89313.c	(working copy)
@@ -0,0 +1,26 @@ 
+/* PR rtl-optimization/89313  */
+/* { dg-do compile { target aarch64*-*-* arm*-*-* i?86-*-* powerpc*-*-* s390*-*-* x86_64-*-* } } */
+/* { dg-options "-O2" } */
+
+#if defined (__aarch64__)
+# define REG "x0"
+#elif defined (__arm__)
+# define REG "r0"
+#elif defined (__i386__)
+# define REG "%eax"
+#elif defined (__powerpc__)
+# define REG "r3"
+#elif defined (__s390__)
+# define REG "0"
+#elif defined (__x86_64__)
+# define REG "rax"
+#endif
+
+long
+bug (long arg)
+{
+  register long output asm (REG);
+  long input = arg;
+  asm ("blah %0, %1, %2" : "=&r" (output) : "r" (input), "0" (input));
+  return output;
+}