Hello,

Since r11-2903-g6b3034eaba83935d9f6dfb20d2efbdb34b5b00bf introduced a
canonicalization from mult to shift on address reloads, a missing
pattern in the AArch64 backend was exposed.

In particular, we were missing the ashift variant of
*add_<optab><mode>_multp2 (this mult variant is redundant and was
removed in r11-3033-g2f8ae301f6a125f50b0a758047fcddae7b68daa8).

This patch adds that missing pattern (fixing PR96998), updates
aarch64_is_extend_from_extract() to work for the shift pattern (instead
of the redundant mult variant) and updates callers in the cost
calculations to apply the costing for the shift variant instead.

Testing:
 * Bootstrap and regtest on aarch64-none-linux-gnu, no regressions.
 * Checked new unit test passes on arm-none-linux-gnueabihf.
 * Checked new unit test isn't run on x86 (inline asm uses
   arm/aarch64-specific constraint).
 * Tested linux-next tree no longer encounters this ICE on arm64 with
   patched GCC (unfortunately still doesn't compile successfully due to
   a fix for PR96475 which introduces an ICE on arm64).

OK for trunk?

Thanks,
Alex

---

gcc/ChangeLog:

        PR target/96998
        * config/aarch64/aarch64.c (aarch64_is_extend_from_extract): Update to
        work for shift pattern instead of mult.
        (aarch64_strip_extend): Cost extract+shift pattern instead of
        now-removed extract+mult pattern.
        (aarch64_rtx_arith_op_extract_p): Likewise.
        * config/aarch64/aarch64.md (*add_<optab><mode>_shftex): New.

gcc/testsuite/ChangeLog:

        PR target/96998
        * gcc.c-torture/compile/pr96998.c: New test.

diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index b6d74496cd0..55e0fc4e683 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -2815,27 +2815,24 @@ aarch64_is_noplt_call_p (rtx sym)
    represent an expression that matches an extend operation.  The
    operands represent the parameters from
 
-   (extract:MODE (mult (reg) (MULT_IMM)) (EXTRACT_IMM) (const_int 0)).  */
+   (extract:MODE (ashift (reg) (SHIFT_IMM)) (EXTRACT_IMM) (const_int 0)).  */
 bool
-aarch64_is_extend_from_extract (scalar_int_mode mode, rtx mult_imm,
+aarch64_is_extend_from_extract (scalar_int_mode mode, rtx shift_imm,
                                rtx extract_imm)
 {
-  HOST_WIDE_INT mult_val, extract_val;
+  HOST_WIDE_INT shift_val, extract_val;
 
-  if (! CONST_INT_P (mult_imm) || ! CONST_INT_P (extract_imm))
+  if (! CONST_INT_P (shift_imm) || ! CONST_INT_P (extract_imm))
     return false;
 
-  mult_val = INTVAL (mult_imm);
+  shift_val = INTVAL (shift_imm);
   extract_val = INTVAL (extract_imm);
 
-  if (extract_val > 8
-      && extract_val < GET_MODE_BITSIZE (mode)
-      && exact_log2 (extract_val & ~7) > 0
-      && (extract_val & 7) <= 4
-      && mult_val == (1 << (extract_val & 7)))
-    return true;
-
-  return false;
+  return extract_val > 8
+         && extract_val < GET_MODE_BITSIZE (mode)
+         && exact_log2 (extract_val & ~7) > 0
+         && shift_val <= 4
+         && shift_val == (extract_val & 7);
 }
 
 /* Emit an insn that's a simple single-set.  Both the operands must be
@@ -11262,7 +11259,7 @@ aarch64_strip_extend (rtx x, bool strip_shift)
   /* Zero and sign extraction of a widened value.  */
   if ((GET_CODE (op) == ZERO_EXTRACT || GET_CODE (op) == SIGN_EXTRACT)
       && XEXP (op, 2) == const0_rtx
-      && GET_CODE (XEXP (op, 0)) == MULT
+      && GET_CODE (XEXP (op, 0)) == ASHIFT
       && aarch64_is_extend_from_extract (mode, XEXP (XEXP (op, 0), 1),
                                         XEXP (op, 1)))
     return XEXP (XEXP (op, 0), 0);
@@ -11617,7 +11614,7 @@ aarch64_rtx_arith_op_extract_p (rtx x, scalar_int_mode 
mode)
       rtx op1 = XEXP (x, 1);
       rtx op2 = XEXP (x, 2);
 
-      if (GET_CODE (op0) == MULT
+      if (GET_CODE (op0) == ASHIFT
          && CONST_INT_P (op1)
          && op2 == const0_rtx
          && CONST_INT_P (XEXP (op0, 1))
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index dbc6b1db176..4bb7b318b99 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -2471,6 +2471,19 @@ (define_insn "*add_<optab><ALLX:mode>_<GPI:mode>"
   [(set_attr "type" "alu_ext")]
 )
 
+(define_insn "*add_<optab><mode>_shftex"
+  [(set (match_operand:GPI 0 "register_operand" "=rk")
+       (plus:GPI (ANY_EXTRACT:GPI
+                   (ashift:GPI (match_operand:GPI 1 "register_operand" "r")
+                               (match_operand 2 "aarch64_shift_imm_<mode>" 
"n"))
+                   (match_operand 3 "const_int_operand" "n")
+                   (const_int 0))
+                 (match_operand:GPI 4 "register_operand" "r")))]
+  "aarch64_is_extend_from_extract (<MODE>mode, operands[2], operands[3])"
+  "add\\t%<w>0, %<w>4, %<w>1, <su>xt%e3 %2"
+  [(set_attr "type" "alu_ext")]
+)
+
 ;; zero_extend version of above
 (define_insn "*add_<optab><SHORT:mode>_si_uxtw"
   [(set (match_operand:DI 0 "register_operand" "=rk")
diff --git a/gcc/testsuite/gcc.c-torture/compile/pr96998.c 
b/gcc/testsuite/gcc.c-torture/compile/pr96998.c
new file mode 100644
index 00000000000..a75d5dcfe08
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/compile/pr96998.c
@@ -0,0 +1,15 @@
+/* { dg-do compile { target arm*-*-* aarch64*-*-* } } */
+
+int h(void);
+struct c d;
+struct c {
+  int e[1];
+};
+
+void f(void) {
+  int g;
+  for (;; g = h()) {
+    int *i = &d.e[g];
+    asm("" : "=Q"(*i));
+  }
+}

Reply via email to