Many thanks to Uros and Hongtao for the reviews/feedback. I agree they
are both correct; performing this optimization early during RTL expansion
allows the results to be optimized by early RTL optimization passes, and
performing this optimization late, as a (pair of) define_insn_and_split
patterns, enables this optimization to catch cases where the CONST1_RTX
is exposed by early RTL optimization passes. The obvious solution is
to do both.
This patch has been tested on x86_64-pc-linux-gnu, first only performing
this
transformation during RTL expansion, then only performing this optimization
during combine/split, confirming both approaches pass the new test cases,
with no new failures, both with and without --target_board=unix{-m32}.
Ok for mainline?
2026-05-27 Roger Sayle <[email protected]>
Hongtao Liu <[email protected]>
Uros Bizjak <[email protected]>
gcc/ChangeLog
* config/i386/i386.md (inv_insn): New define_code_attr.
* config/i386/sse.md (<plusminus><mode>3): Accept a CONST_VECTOR
as the second operand. If the second operand is CONST1_RTX,
canonicalize to use CONSTM1_RTX instead.
(*add<mode>3_one): New define_insn_and_split to convert padd +1
to psub -1.
(*sub<mode>3_one): Likewise, a new define_insn_and_split to
convert psub +1 to padd -1.
gcc/testsuite/ChangeLog
* gcc.target/i386/avx512f-simd-1.c: Tweak test case.
* gcc.target/i386/sse2-paddb-2.c: New test case.
* gcc.target/i386/sse2-paddd-2.c: Likewise.
* gcc.target/i386/sse2-paddw-2.c: Likewise.
* gcc.target/i386/sse2-psubb-2.c: Likewise.
* gcc.target/i386/sse2-psubd-2.c: Likewise.
* gcc.target/i386/sse2-psubw-2.c: Likewise.
Thanks again.
Roger
--
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index cd95a286298..ab5399d0621 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -1021,6 +1021,9 @@
[(plus "add") (ss_plus "adds") (us_plus "addus")
(minus "sub") (ss_minus "subs") (us_minus "subus")])
+;; Inverse instruction base name
+(define_code_attr inv_insn [(plus "sub") (minus "add")])
+
(define_code_iterator multdiv [mult div])
(define_code_attr multdiv_mnemonic
diff --git a/gcc/config/i386/sse.md b/gcc/config/i386/sse.md
index de092f4b9ae..ae1f0aa0d86 100644
--- a/gcc/config/i386/sse.md
+++ b/gcc/config/i386/sse.md
@@ -16590,9 +16590,23 @@
[(set (match_operand:VI_AVX2 0 "register_operand")
(plusminus:VI_AVX2
(match_operand:VI_AVX2 1 "vector_operand")
- (match_operand:VI_AVX2 2 "vector_operand")))]
+ (match_operand:VI_AVX2 2 "vector_or_const_vector_operand")))]
"TARGET_SSE2"
- "ix86_fixup_binary_operands_no_copy (<CODE>, <MODE>mode, operands);")
+{
+ /* Expand vector add/sub 1 as vector sub/add -1. */
+ if (rtx_equal_p (operands[2], CONST1_RTX (<MODE>mode)))
+ {
+ operands[2] = force_reg (<MODE>mode, CONSTM1_RTX (<MODE>mode));
+ emit_insn (gen_<inv_insn><mode>3 (operands[0], operands[1],
+ operands[2]));
+ DONE;
+ }
+
+ if (CONST_VECTOR_P (operands[2]))
+ operands[2] = force_reg (<MODE>mode, operands[2]);
+
+ ix86_fixup_binary_operands_no_copy (<CODE>, <MODE>mode, operands);
+})
(define_expand "cond_<insn><mode>"
[(set (match_operand:VI1248_AVX512VLBW 0 "register_operand")
@@ -16677,6 +16691,39 @@
(set_attr "prefix" "evex")
(set_attr "mode" "<sseinsnmode>")])
+/* Split vector add 1 into vector sub -1. */
+(define_insn_and_split "*add<mode>3_one"
+ [(set (match_operand:VI_AVX2 0 "register_operand")
+ (plus:VI_AVX2
+ (match_operand:VI_AVX2 1 "nonimmediate_operand")
+ (match_operand:VI_AVX2 2 "const1_operand")))]
+ "TARGET_SSE2 && ix86_pre_reload_split ()"
+ "#"
+ "&& 1"
+ [(set (match_dup 3) (match_dup 4))
+ (set (match_dup 0) (minus:VI_AVX2 (match_dup 1) (match_dup 3)))]
+{
+ operands[1] = force_reg (<MODE>mode, operands[1]);
+ operands[3] = gen_reg_rtx (<MODE>mode);
+ operands[4] = CONSTM1_RTX (<MODE>mode);
+})
+
+/* Split vector sub 1 into vector add -1. */
+(define_insn_and_split "*sub<mode>3_one"
+ [(set (match_operand:VI_AVX2 0 "register_operand")
+ (minus:VI_AVX2
+ (match_operand:VI_AVX2 1 "nonimmediate_operand")
+ (match_operand:VI_AVX2 2 "const1_operand")))]
+ "TARGET_SSE2 && ix86_pre_reload_split ()"
+ "#"
+ "&& 1"
+ [(set (match_dup 3) (match_dup 4))
+ (set (match_dup 0) (plus:VI_AVX2 (match_dup 3) (match_dup 1)))]
+{
+ operands[3] = gen_reg_rtx (<MODE>mode);
+ operands[4] = CONSTM1_RTX (<MODE>mode);
+})
+
(define_expand "<insn><mode>3<mask_name>"
[(set (match_operand:VI12_AVX2_AVX512BW 0 "register_operand")
(sat_plusminus:VI12_AVX2_AVX512BW
diff --git a/gcc/testsuite/gcc.target/i386/avx512f-simd-1.c
b/gcc/testsuite/gcc.target/i386/avx512f-simd-1.c
index 235fb917e17..77c5f202e2f 100644
--- a/gcc/testsuite/gcc.target/i386/avx512f-simd-1.c
+++ b/gcc/testsuite/gcc.target/i386/avx512f-simd-1.c
@@ -13,7 +13,7 @@ f1 (void)
int i;
#pragma omp simd simdlen (4)
for (i = 0; i < N; ++i)
- a[i] = a[i] + 1;
+ a[i] = a[i] + 11;
}
void
@@ -22,7 +22,7 @@ f2 (void)
int i;
#pragma omp simd simdlen (8)
for (i = 0; i < N; ++i)
- a[i] = a[i] + 2;
+ a[i] = a[i] + 12;
}
void
@@ -31,5 +31,5 @@ f3 (void)
int i;
#pragma omp simd simdlen (16)
for (i = 0; i < N; ++i)
- a[i] = a[i] + 3;
+ a[i] = a[i] + 13;
}
diff --git a/gcc/testsuite/gcc.target/i386/sse2-paddb-2.c
b/gcc/testsuite/gcc.target/i386/sse2-paddb-2.c
new file mode 100644
index 00000000000..f4acff29a20
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/sse2-paddb-2.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -msse2" } */
+
+typedef char v16sqi __attribute__ ((vector_size(16)));
+typedef unsigned char v16uqi __attribute__ ((vector_size(16)));
+
+v16sqi si,so;
+v16uqi ui,uo;
+
+void foo()
+{
+ so = si - 1;
+}
+
+void bar()
+{
+ uo = ui - 1;
+}
+
+/* { dg-final { scan-assembler-times "\[ \t\]paddb\[ \t\]" 2 } } */
diff --git a/gcc/testsuite/gcc.target/i386/sse2-paddd-2.c
b/gcc/testsuite/gcc.target/i386/sse2-paddd-2.c
new file mode 100644
index 00000000000..d48022cbfda
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/sse2-paddd-2.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -msse2" } */
+
+typedef int v4ssi __attribute__ ((vector_size(16)));
+typedef unsigned int v4usi __attribute__ ((vector_size(16)));
+
+v4ssi si,so;
+v4usi ui,uo;
+
+void foo()
+{
+ so = si - 1;
+}
+
+void bar()
+{
+ uo = ui - 1;
+}
+
+/* { dg-final { scan-assembler-times "\[ \t\]paddd\[ \t\]" 2 } } */
diff --git a/gcc/testsuite/gcc.target/i386/sse2-paddw-2.c
b/gcc/testsuite/gcc.target/i386/sse2-paddw-2.c
new file mode 100644
index 00000000000..be81170cbf7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/sse2-paddw-2.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -msse2" } */
+
+typedef short v8shi __attribute__ ((vector_size(16)));
+typedef unsigned short v8uhi __attribute__ ((vector_size(16)));
+
+v8shi si,so;
+v8uhi ui,uo;
+
+void foo()
+{
+ so = si - 1;
+}
+
+void bar()
+{
+ uo = ui - 1;
+}
+
+/* { dg-final { scan-assembler-times "\[ \t\]paddw\[ \t\]" 2 } } */
diff --git a/gcc/testsuite/gcc.target/i386/sse2-psubb-2.c
b/gcc/testsuite/gcc.target/i386/sse2-psubb-2.c
new file mode 100644
index 00000000000..e6f421eb276
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/sse2-psubb-2.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -msse2" } */
+
+typedef char v16sqi __attribute__ ((vector_size(16)));
+typedef unsigned char v16uqi __attribute__ ((vector_size(16)));
+
+v16sqi si,so;
+v16uqi ui,uo;
+
+void foo()
+{
+ so = si + 1;
+}
+
+void bar()
+{
+ uo = ui + 1;
+}
+
+/* { dg-final { scan-assembler-times "\[ \t\]psubb\[ \t\]" 2 } } */
diff --git a/gcc/testsuite/gcc.target/i386/sse2-psubd-2.c
b/gcc/testsuite/gcc.target/i386/sse2-psubd-2.c
new file mode 100644
index 00000000000..aaf7e5a5aae
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/sse2-psubd-2.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -msse2" } */
+
+typedef int v4ssi __attribute__ ((vector_size(16)));
+typedef unsigned int v4usi __attribute__ ((vector_size(16)));
+
+v4ssi si,so;
+v4usi ui,uo;
+
+void foo()
+{
+ so = si + 1;
+}
+
+void bar()
+{
+ uo = ui + 1;
+}
+
+/* { dg-final { scan-assembler-times "\[ \t\]psubd\[ \t\]" 2 } } */
diff --git a/gcc/testsuite/gcc.target/i386/sse2-psubw-2.c
b/gcc/testsuite/gcc.target/i386/sse2-psubw-2.c
new file mode 100644
index 00000000000..8c11012af9a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/sse2-psubw-2.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -msse2" } */
+
+typedef short v8shi __attribute__ ((vector_size(16)));
+typedef unsigned short v8uhi __attribute__ ((vector_size(16)));
+
+v8shi si,so;
+v8uhi ui,uo;
+
+void foo()
+{
+ so = si + 1;
+}
+
+void bar()
+{
+ uo = ui + 1;
+}
+
+/* { dg-final { scan-assembler-times "\[ \t\]psubw\[ \t\]" 2 } } */