This patch fixes the regression PR target/123238 on aarch64, using the
changes to aarch64's aarch64_rtx_costs proposed by Tamar Christina.
To explain and motivate things for aarch64:
void foo(char c[])
{
for (int i = 0; i < 8; i++)
c[i] = c[i] != 'a' ? 'c' : 'e';
}
currently generates with -O2 the following:
foo: movi v30.8b, 0x61
ldr d0, [x0]
movi v29.8b, 0x63
movi v31.8b, 0x65
cmeq v30.8b, v0.8b, v30.8b
not v30.8b, v30.8b
bit v31.8b, v29.8b, v30.8b
str d31, [x0]
ret
where a cmeq followed by a not is used to implement NE_EXPR.
c.f. the comment "Handle NE as !EQ" in aarch64-simd.md's expander
of vec_cmp<mode><mode>. With the patch for PR 123238, including this
change to aarch64_rtx_costs to indicate that NE is more expensive
than EQ, the middle-end swaps the VCOND_EXPR, reducing the number of
instructions in the example above [to what it was in GCC 14].
2026-04-01 Tamar Christina <tamar.christina@arm.com>
Roger Sayle <roger@nextmovesoftware.com>
gcc/ChangeLog
PR target/123238
* config/aarch64/aarch64.cc (aarch64_rtx_costs) <case NE/EQ>:
Provide improved costs for scalar and vector comparisons.
gcc/testsuite/ChangeLog
PR target/123238
* gcc.target/aarch64/pr123238.c: New test case.
case GEU:
case LE:
case LEU:
-
- return false; /* All arguments must be in registers. */
+ {
+ op0 = XEXP (x, 0);
+ op1 = XEXP (x, 1);
+ machine_mode inner_mode = GET_MODE (op0);
+ *cost += rtx_cost (op0, inner_mode, code, 0, speed);
+ if (op1 != CONST0_RTX (inner_mode))
+ {
+ unsigned int vec_flags = aarch64_classify_vector_mode (mode);
+ bool unsigned_p = code == LTU || code == LEU || code == GTU
+ || code == GEU;
+ if ((vec_flags & VEC_SVE_DATA) == 0
+ || !aarch64_sve_cmp_immediate_p (op1, !unsigned_p))
+ *cost += rtx_cost (op1, inner_mode, code, 1, speed);
+ if (code == NE && (vec_flags & VEC_ADVSIMD))
+ *cost += COSTS_N_INSNS (1);
+ }
+ return true;
+ }
case FMA:
op0 = XEXP (x, 0);
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+void foo(char c[])
+{
+ for (int i = 0; i < 8; i++)
+ c[i] = c[i] != 'a' ? 'c' : 'e';
+}
+
+void bar(char c[])
+{
+ for (int i = 0; i < 8; i++)
+ c[i] = c[i] == 'a' ? 'c' : 'e';
+}
+
+/* { dg-final { scan-assembler-not "not" } } */