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));
+ }
+}