lra-constraints: Fix error-recovery for bad inline-asms [PR97971]
authorJakub Jelinek <jakub@redhat.com>
Wed, 3 Feb 2021 08:07:36 +0000 (09:07 +0100)
committerJakub Jelinek <jakub@redhat.com>
Wed, 3 Feb 2021 08:10:29 +0000 (09:10 +0100)
The following testcase has ice-on-invalid, it can't be reloaded, but we
shouldn't ICE the compiler because the user typed non-sense.

In current_insn_transform we have:
  if (process_alt_operands (reused_alternative_num))
    alt_p = true;

  if (check_only_p)
    return ! alt_p || best_losers != 0;

  /* If insn is commutative (it's safe to exchange a certain pair of
     operands) then we need to try each alternative twice, the second
     time matching those two operands as if we had exchanged them.  To
     do this, really exchange them in operands.

     If we have just tried the alternatives the second time, return
     operands to normal and drop through.  */

  if (reused_alternative_num < 0 && commutative >= 0)
    {
      curr_swapped = !curr_swapped;
      if (curr_swapped)
        {
          swap_operands (commutative);
          goto try_swapped;
        }
      else
        swap_operands (commutative);
    }

  if (! alt_p && ! sec_mem_p)
    {
      /* No alternative works with reloads??  */
      if (INSN_CODE (curr_insn) >= 0)
        fatal_insn ("unable to generate reloads for:", curr_insn);
      error_for_asm (curr_insn,
                     "inconsistent operand constraints in an %<asm%>");
      lra_asm_error_p = true;
...
and so handle inline asms there differently (and delete/nullify them after
this) - fatal_insn is only called for non-inline asm.
But in process_alt_operands we do:
                /* Both the earlyclobber operand and conflicting operand
                   cannot both be user defined hard registers.  */
                if (HARD_REGISTER_P (operand_reg[i])
                    && REG_USERVAR_P (operand_reg[i])
                    && operand_reg[j] != NULL_RTX
                    && HARD_REGISTER_P (operand_reg[j])
                    && REG_USERVAR_P (operand_reg[j]))
                  fatal_insn ("unable to generate reloads for "
                              "impossible constraints:", curr_insn);
and thus ICE even for inline-asms.

I think it is inappropriate to delete/nullify the insn in
process_alt_operands, as it could be done e.g. in the check_only_p mode,
so this patch just returns false in that case, which results in the
caller have alt_p false, and as inline asm isn't simple move, sec_mem_p
will be also false (and it isn't commutative either), so for check_only_p
it will suggests to the callers it isn't ok and otherwise will emit
error and delete/nullify the inline asm insn.

2021-02-03  Jakub Jelinek  <jakub@redhat.com>

PR middle-end/97971
* lra-constraints.c (process_alt_operands): For inline asm, don't call
fatal_insn, but instead return false.

* gcc.target/i386/pr97971.c: New test.

gcc/lra-constraints.c
gcc/testsuite/gcc.target/i386/pr97971.c [new file with mode: 0644]

index e739a466a0de94ffefa2922e8409302607e29842..6a5aa41ed55c4e79e13bc8e3b4f94bfedb90e693 100644 (file)
@@ -3106,8 +3106,13 @@ process_alt_operands (int only_alternative)
                    && operand_reg[j] != NULL_RTX
                    && HARD_REGISTER_P (operand_reg[j])
                    && REG_USERVAR_P (operand_reg[j]))
-                 fatal_insn ("unable to generate reloads for "
-                             "impossible constraints:", curr_insn);
+                 {
+                   /* For asm, let curr_insn_transform diagnose it.  */
+                   if (INSN_CODE (curr_insn) < 0)
+                     return false;
+                   fatal_insn ("unable to generate reloads for "
+                               "impossible constraints:", curr_insn);
+                 }
              }
          if (last_conflict_j < 0)
            continue;
diff --git a/gcc/testsuite/gcc.target/i386/pr97971.c b/gcc/testsuite/gcc.target/i386/pr97971.c
new file mode 100644 (file)
index 0000000..d07a310
--- /dev/null
@@ -0,0 +1,12 @@
+/* PR middle-end/97971 */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+int
+foo (void)
+{
+  register _Complex long a asm ("rax");
+  register int b asm ("rdx");
+  asm ("# %0 %1" : "=&r" (a), "=r" (b));       /* { dg-error "inconsistent operand constraints in an 'asm'" } */
+  return a;
+}