[llvm] [SLP][NFC]Add extra tests for fadd/fsub reordering, NFC (PR #213002)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 30 04:54:51 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: Alexey Bataev (alexey-bataev)
<details>
<summary>Changes</summary>
---
Patch is 26.39 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/213002.diff
1 Files Affected:
- (modified) llvm/test/Transforms/SLPVectorizer/X86/reassociate-ops.ll (+598)
``````````diff
diff --git a/llvm/test/Transforms/SLPVectorizer/X86/reassociate-ops.ll b/llvm/test/Transforms/SLPVectorizer/X86/reassociate-ops.ll
index fe00dc00df394..8c60348ce1707 100644
--- a/llvm/test/Transforms/SLPVectorizer/X86/reassociate-ops.ll
+++ b/llvm/test/Transforms/SLPVectorizer/X86/reassociate-ops.ll
@@ -600,3 +600,601 @@ entry:
store i8 %add1, ptr %idxS1, align 8
ret void
}
+
+; Mixed add/sub chain: lane 0 subtracts B and D, lane 1 subtracts D and B.
+; The flattened subtracted columns must be realigned among themselves only
+; (a subtracted leaf never lands in an added column), so the subtrahends
+; regroup into the consecutive B and D load columns.
+;
+; S[0] = (A[0] - B[0]) + (C[0] - D[0])
+; S[1] = (A[1] - D[1]) + (C[1] - B[1])
+define void @test_reassoc_add_sub(ptr %Aarray, ptr %Barray, ptr %Carray, ptr %Darray, ptr %Sarray) {
+; CHECK-LABEL: define void @test_reassoc_add_sub(
+; CHECK-SAME: ptr [[AARRAY:%.*]], ptr [[BARRAY:%.*]], ptr [[CARRAY:%.*]], ptr [[DARRAY:%.*]], ptr [[SARRAY:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = load <2 x i32>, ptr [[AARRAY]], align 4
+; CHECK-NEXT: [[TMP1:%.*]] = load <2 x i32>, ptr [[BARRAY]], align 4
+; CHECK-NEXT: [[TMP2:%.*]] = load <2 x i32>, ptr [[CARRAY]], align 4
+; CHECK-NEXT: [[TMP3:%.*]] = load <2 x i32>, ptr [[DARRAY]], align 4
+; CHECK-NEXT: [[TMP4:%.*]] = shufflevector <2 x i32> [[TMP1]], <2 x i32> [[TMP3]], <2 x i32> <i32 0, i32 3>
+; CHECK-NEXT: [[TMP5:%.*]] = sub <2 x i32> [[TMP0]], [[TMP4]]
+; CHECK-NEXT: [[TMP8:%.*]] = shufflevector <2 x i32> [[TMP3]], <2 x i32> [[TMP1]], <2 x i32> <i32 0, i32 3>
+; CHECK-NEXT: [[TMP7:%.*]] = sub <2 x i32> [[TMP2]], [[TMP8]]
+; CHECK-NEXT: [[TMP6:%.*]] = add <2 x i32> [[TMP5]], [[TMP7]]
+; CHECK-NEXT: store <2 x i32> [[TMP6]], ptr [[SARRAY]], align 4
+; CHECK-NEXT: ret void
+;
+entry:
+ %idxA1 = getelementptr inbounds i32, ptr %Aarray, i64 1
+ %idxB1 = getelementptr inbounds i32, ptr %Barray, i64 1
+ %idxC1 = getelementptr inbounds i32, ptr %Carray, i64 1
+ %idxD1 = getelementptr inbounds i32, ptr %Darray, i64 1
+ %idxS1 = getelementptr inbounds i32, ptr %Sarray, i64 1
+
+ %A0 = load i32, ptr %Aarray, align 4
+ %A1 = load i32, ptr %idxA1, align 4
+
+ %B0 = load i32, ptr %Barray, align 4
+ %B1 = load i32, ptr %idxB1, align 4
+
+ %C0 = load i32, ptr %Carray, align 4
+ %C1 = load i32, ptr %idxC1, align 4
+
+ %D0 = load i32, ptr %Darray, align 4
+ %D1 = load i32, ptr %idxD1, align 4
+
+ %subA0B0 = sub i32 %A0, %B0
+ %subC0D0 = sub i32 %C0, %D0
+ %add0 = add i32 %subA0B0, %subC0D0
+
+ %subA1D1 = sub i32 %A1, %D1
+ %subC1B1 = sub i32 %C1, %B1
+ %add1 = add i32 %subA1D1, %subC1B1
+
+ store i32 %add0, ptr %Sarray, align 4
+ store i32 %add1, ptr %idxS1, align 4
+ ret void
+}
+
+; A pure subtract chain flattens as a single added leaf minus the summed
+; subtrahends. Every scalar below is "nsw nuw", but a regrouped partial sum
+; can exceed the original running total (the minuend is not part of the
+; negated group), so both wrap flags must be dropped on the vector ops.
+;
+; S[0] = (A[0] - B[0]) - C[0]
+; S[1] = (A[1] - C[1]) - B[1]
+define void @test_reassoc_sub_chain_wrapflags(ptr %Aarray, ptr %Barray, ptr %Carray, ptr %Sarray) {
+; CHECK-LABEL: define void @test_reassoc_sub_chain_wrapflags(
+; CHECK-SAME: ptr [[AARRAY:%.*]], ptr [[BARRAY:%.*]], ptr [[CARRAY:%.*]], ptr [[SARRAY:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = load <2 x i32>, ptr [[AARRAY]], align 4
+; CHECK-NEXT: [[TMP1:%.*]] = load <2 x i32>, ptr [[BARRAY]], align 4
+; CHECK-NEXT: [[TMP2:%.*]] = load <2 x i32>, ptr [[CARRAY]], align 4
+; CHECK-NEXT: [[TMP3:%.*]] = shufflevector <2 x i32> [[TMP1]], <2 x i32> [[TMP2]], <2 x i32> <i32 0, i32 3>
+; CHECK-NEXT: [[TMP6:%.*]] = sub nuw nsw <2 x i32> [[TMP0]], [[TMP3]]
+; CHECK-NEXT: [[TMP5:%.*]] = shufflevector <2 x i32> [[TMP2]], <2 x i32> [[TMP1]], <2 x i32> <i32 0, i32 3>
+; CHECK-NEXT: [[TMP4:%.*]] = sub nuw nsw <2 x i32> [[TMP6]], [[TMP5]]
+; CHECK-NEXT: store <2 x i32> [[TMP4]], ptr [[SARRAY]], align 4
+; CHECK-NEXT: ret void
+;
+entry:
+ %idxA1 = getelementptr inbounds i32, ptr %Aarray, i64 1
+ %idxB1 = getelementptr inbounds i32, ptr %Barray, i64 1
+ %idxC1 = getelementptr inbounds i32, ptr %Carray, i64 1
+ %idxS1 = getelementptr inbounds i32, ptr %Sarray, i64 1
+
+ %A0 = load i32, ptr %Aarray, align 4
+ %A1 = load i32, ptr %idxA1, align 4
+
+ %B0 = load i32, ptr %Barray, align 4
+ %B1 = load i32, ptr %idxB1, align 4
+
+ %C0 = load i32, ptr %Carray, align 4
+ %C1 = load i32, ptr %idxC1, align 4
+
+ %subA0B0 = sub nsw nuw i32 %A0, %B0
+ %sub0 = sub nsw nuw i32 %subA0B0, %C0
+
+ %subA1C1 = sub nsw nuw i32 %A1, %C1
+ %sub1 = sub nsw nuw i32 %subA1C1, %B1
+
+ store i32 %sub0, ptr %Sarray, align 4
+ store i32 %sub1, ptr %idxS1, align 4
+ ret void
+}
+
+; Both lanes pair the same added terms with the operands swapped, so each
+; vector combine exactly reproduces a real source instruction (the added
+; pair is keyed operand-order independently): the (A + B) add and the final
+; subtract keep their own flags instead of falling back to conservative
+; dropping.
+;
+; S[0] = (A[0] + B[0]) - C[0]
+; S[1] = (B[1] + A[1]) - C[1]
+define void @test_reassoc_sub_preserves_flags(ptr %Aarray, ptr %Barray, ptr %Carray, ptr %Sarray) {
+; CHECK-LABEL: define void @test_reassoc_sub_preserves_flags(
+; CHECK-SAME: ptr [[AARRAY:%.*]], ptr [[BARRAY:%.*]], ptr [[CARRAY:%.*]], ptr [[SARRAY:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = load <2 x i32>, ptr [[AARRAY]], align 4
+; CHECK-NEXT: [[TMP1:%.*]] = load <2 x i32>, ptr [[BARRAY]], align 4
+; CHECK-NEXT: [[TMP2:%.*]] = load <2 x i32>, ptr [[CARRAY]], align 4
+; CHECK-NEXT: [[TMP3:%.*]] = add nuw nsw <2 x i32> [[TMP1]], [[TMP0]]
+; CHECK-NEXT: [[TMP4:%.*]] = sub nuw nsw <2 x i32> [[TMP3]], [[TMP2]]
+; CHECK-NEXT: store <2 x i32> [[TMP4]], ptr [[SARRAY]], align 4
+; CHECK-NEXT: ret void
+;
+entry:
+ %idxA1 = getelementptr inbounds i32, ptr %Aarray, i64 1
+ %idxB1 = getelementptr inbounds i32, ptr %Barray, i64 1
+ %idxC1 = getelementptr inbounds i32, ptr %Carray, i64 1
+ %idxS1 = getelementptr inbounds i32, ptr %Sarray, i64 1
+
+ %A0 = load i32, ptr %Aarray, align 4
+ %A1 = load i32, ptr %idxA1, align 4
+
+ %B0 = load i32, ptr %Barray, align 4
+ %B1 = load i32, ptr %idxB1, align 4
+
+ %C0 = load i32, ptr %Carray, align 4
+ %C1 = load i32, ptr %idxC1, align 4
+
+ %addA0B0 = add nuw nsw i32 %A0, %B0
+ %sub0 = sub nuw nsw i32 %addA0B0, %C0
+
+ %addB1A1 = add nuw nsw i32 %B1, %A1
+ %sub1 = sub nuw nsw i32 %addB1A1, %C1
+
+ store i32 %sub0, ptr %Sarray, align 4
+ store i32 %sub1, ptr %idxS1, align 4
+ ret void
+}
+
+; The fadd/fsub counterpart of test_reassoc_add_sub: "fast" carries reassoc,
+; so the float subtracts flatten too; nnan/ninf are dropped on the
+; regrouped vector ops, the rest of the fast-math set is kept.
+;
+; S[0] = (A[0] - B[0]) + (C[0] - D[0])
+; S[1] = (A[1] - D[1]) + (C[1] - B[1])
+define void @test_reassoc_fadd_fsub(ptr %Aarray, ptr %Barray, ptr %Carray, ptr %Darray, ptr %Sarray) {
+; CHECK-LABEL: define void @test_reassoc_fadd_fsub(
+; CHECK-SAME: ptr [[AARRAY:%.*]], ptr [[BARRAY:%.*]], ptr [[CARRAY:%.*]], ptr [[DARRAY:%.*]], ptr [[SARRAY:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = load <2 x double>, ptr [[AARRAY]], align 8
+; CHECK-NEXT: [[TMP1:%.*]] = load <2 x double>, ptr [[BARRAY]], align 8
+; CHECK-NEXT: [[TMP2:%.*]] = load <2 x double>, ptr [[CARRAY]], align 8
+; CHECK-NEXT: [[TMP3:%.*]] = load <2 x double>, ptr [[DARRAY]], align 8
+; CHECK-NEXT: [[TMP4:%.*]] = shufflevector <2 x double> [[TMP1]], <2 x double> [[TMP3]], <2 x i32> <i32 0, i32 3>
+; CHECK-NEXT: [[TMP5:%.*]] = fsub fast <2 x double> [[TMP0]], [[TMP4]]
+; CHECK-NEXT: [[TMP8:%.*]] = shufflevector <2 x double> [[TMP3]], <2 x double> [[TMP1]], <2 x i32> <i32 0, i32 3>
+; CHECK-NEXT: [[TMP7:%.*]] = fsub fast <2 x double> [[TMP2]], [[TMP8]]
+; CHECK-NEXT: [[TMP6:%.*]] = fadd fast <2 x double> [[TMP5]], [[TMP7]]
+; CHECK-NEXT: store <2 x double> [[TMP6]], ptr [[SARRAY]], align 8
+; CHECK-NEXT: ret void
+;
+entry:
+ %idxA1 = getelementptr inbounds double, ptr %Aarray, i64 1
+ %idxB1 = getelementptr inbounds double, ptr %Barray, i64 1
+ %idxC1 = getelementptr inbounds double, ptr %Carray, i64 1
+ %idxD1 = getelementptr inbounds double, ptr %Darray, i64 1
+ %idxS1 = getelementptr inbounds double, ptr %Sarray, i64 1
+
+ %A0 = load double, ptr %Aarray, align 8
+ %A1 = load double, ptr %idxA1, align 8
+
+ %B0 = load double, ptr %Barray, align 8
+ %B1 = load double, ptr %idxB1, align 8
+
+ %C0 = load double, ptr %Carray, align 8
+ %C1 = load double, ptr %idxC1, align 8
+
+ %D0 = load double, ptr %Darray, align 8
+ %D1 = load double, ptr %idxD1, align 8
+
+ %subA0B0 = fsub fast double %A0, %B0
+ %subC0D0 = fsub fast double %C0, %D0
+ %add0 = fadd fast double %subA0B0, %subC0D0
+
+ %subA1D1 = fsub fast double %A1, %D1
+ %subC1B1 = fsub fast double %C1, %B1
+ %add1 = fadd fast double %subA1D1, %subC1B1
+
+ store double %add0, ptr %Sarray, align 8
+ store double %add1, ptr %idxS1, align 8
+ ret void
+}
+
+; Without reassoc a float subtract chain cannot be regrouped, so the
+; flattening must leave it alone entirely.
+;
+; S[0] = (A[0] - B[0]) - C[0]
+; S[1] = (A[1] - B[1]) - C[1]
+define void @test_reassoc_fsub_no_reassoc_flag(ptr %Aarray, ptr %Barray, ptr %Carray, ptr %Sarray) {
+; CHECK-LABEL: define void @test_reassoc_fsub_no_reassoc_flag(
+; CHECK-SAME: ptr [[AARRAY:%.*]], ptr [[BARRAY:%.*]], ptr [[CARRAY:%.*]], ptr [[SARRAY:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = load <2 x double>, ptr [[AARRAY]], align 8
+; CHECK-NEXT: [[TMP1:%.*]] = load <2 x double>, ptr [[BARRAY]], align 8
+; CHECK-NEXT: [[TMP2:%.*]] = load <2 x double>, ptr [[CARRAY]], align 8
+; CHECK-NEXT: [[TMP3:%.*]] = fsub <2 x double> [[TMP0]], [[TMP1]]
+; CHECK-NEXT: [[TMP4:%.*]] = fsub <2 x double> [[TMP3]], [[TMP2]]
+; CHECK-NEXT: store <2 x double> [[TMP4]], ptr [[SARRAY]], align 8
+; CHECK-NEXT: ret void
+;
+entry:
+ %idxA1 = getelementptr inbounds double, ptr %Aarray, i64 1
+ %idxB1 = getelementptr inbounds double, ptr %Barray, i64 1
+ %idxC1 = getelementptr inbounds double, ptr %Carray, i64 1
+ %idxS1 = getelementptr inbounds double, ptr %Sarray, i64 1
+
+ %A0 = load double, ptr %Aarray, align 8
+ %A1 = load double, ptr %idxA1, align 8
+
+ %B0 = load double, ptr %Barray, align 8
+ %B1 = load double, ptr %idxB1, align 8
+
+ %C0 = load double, ptr %Carray, align 8
+ %C1 = load double, ptr %idxC1, align 8
+
+ %subA0B0 = fsub double %A0, %B0
+ %sub0 = fsub double %subA0B0, %C0
+
+ %subA1B1 = fsub double %A1, %B1
+ %sub1 = fsub double %subA1B1, %C1
+
+ store double %sub0, ptr %Sarray, align 8
+ store double %sub1, ptr %idxS1, align 8
+ ret void
+}
+
+; A pure float subtract chain with reassoc flattens like the integer one:
+; the single added leaf minus the summed subtrahends.
+;
+; S[0] = (A[0] - B[0]) - C[0]
+; S[1] = (A[1] - C[1]) - B[1]
+define void @test_reassoc_fsub_chain(ptr %Aarray, ptr %Barray, ptr %Carray, ptr %Sarray) {
+; CHECK-LABEL: define void @test_reassoc_fsub_chain(
+; CHECK-SAME: ptr [[AARRAY:%.*]], ptr [[BARRAY:%.*]], ptr [[CARRAY:%.*]], ptr [[SARRAY:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = load <2 x double>, ptr [[AARRAY]], align 8
+; CHECK-NEXT: [[TMP1:%.*]] = load <2 x double>, ptr [[BARRAY]], align 8
+; CHECK-NEXT: [[TMP2:%.*]] = load <2 x double>, ptr [[CARRAY]], align 8
+; CHECK-NEXT: [[TMP3:%.*]] = shufflevector <2 x double> [[TMP1]], <2 x double> [[TMP2]], <2 x i32> <i32 0, i32 3>
+; CHECK-NEXT: [[TMP4:%.*]] = fsub reassoc <2 x double> [[TMP0]], [[TMP3]]
+; CHECK-NEXT: [[TMP5:%.*]] = shufflevector <2 x double> [[TMP2]], <2 x double> [[TMP1]], <2 x i32> <i32 0, i32 3>
+; CHECK-NEXT: [[TMP6:%.*]] = fsub reassoc <2 x double> [[TMP4]], [[TMP5]]
+; CHECK-NEXT: store <2 x double> [[TMP6]], ptr [[SARRAY]], align 8
+; CHECK-NEXT: ret void
+;
+entry:
+ %idxA1 = getelementptr inbounds double, ptr %Aarray, i64 1
+ %idxB1 = getelementptr inbounds double, ptr %Barray, i64 1
+ %idxC1 = getelementptr inbounds double, ptr %Carray, i64 1
+ %idxS1 = getelementptr inbounds double, ptr %Sarray, i64 1
+
+ %A0 = load double, ptr %Aarray, align 8
+ %A1 = load double, ptr %idxA1, align 8
+
+ %B0 = load double, ptr %Barray, align 8
+ %B1 = load double, ptr %idxB1, align 8
+
+ %C0 = load double, ptr %Carray, align 8
+ %C1 = load double, ptr %idxC1, align 8
+
+ %subA0B0 = fsub reassoc double %A0, %B0
+ %sub0 = fsub reassoc double %subA0B0, %C0
+
+ %subA1C1 = fsub reassoc double %A1, %C1
+ %sub1 = fsub reassoc double %subA1C1, %B1
+
+ store double %sub0, ptr %Sarray, align 8
+ store double %sub1, ptr %idxS1, align 8
+ ret void
+}
+
+; A subtract nested in the subtracted operand flips its own second operand
+; back to a positive leaf: lane 0 is (A + B) - (C - D) = A + B - C + D,
+; lane 1 is (A + D) - (C - B) = A + B - C + D too, so all four terms
+; realign into consecutive load columns, three of them added and C
+; subtracted.
+define void @test_reassoc_sub_nested_signs(ptr %Aarray, ptr %Barray, ptr %Carray, ptr %Darray, ptr %Sarray) {
+; CHECK-LABEL: define void @test_reassoc_sub_nested_signs(
+; CHECK-SAME: ptr [[AARRAY:%.*]], ptr [[BARRAY:%.*]], ptr [[CARRAY:%.*]], ptr [[DARRAY:%.*]], ptr [[SARRAY:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = load <2 x i32>, ptr [[AARRAY]], align 4
+; CHECK-NEXT: [[TMP1:%.*]] = load <2 x i32>, ptr [[BARRAY]], align 4
+; CHECK-NEXT: [[TMP2:%.*]] = load <2 x i32>, ptr [[CARRAY]], align 4
+; CHECK-NEXT: [[TMP3:%.*]] = load <2 x i32>, ptr [[DARRAY]], align 4
+; CHECK-NEXT: [[TMP4:%.*]] = shufflevector <2 x i32> [[TMP1]], <2 x i32> [[TMP3]], <2 x i32> <i32 0, i32 3>
+; CHECK-NEXT: [[TMP5:%.*]] = add <2 x i32> [[TMP0]], [[TMP4]]
+; CHECK-NEXT: [[TMP8:%.*]] = shufflevector <2 x i32> [[TMP3]], <2 x i32> [[TMP1]], <2 x i32> <i32 0, i32 3>
+; CHECK-NEXT: [[TMP7:%.*]] = sub <2 x i32> [[TMP2]], [[TMP8]]
+; CHECK-NEXT: [[TMP6:%.*]] = sub <2 x i32> [[TMP5]], [[TMP7]]
+; CHECK-NEXT: store <2 x i32> [[TMP6]], ptr [[SARRAY]], align 4
+; CHECK-NEXT: ret void
+;
+entry:
+ %idxA1 = getelementptr inbounds i32, ptr %Aarray, i64 1
+ %idxB1 = getelementptr inbounds i32, ptr %Barray, i64 1
+ %idxC1 = getelementptr inbounds i32, ptr %Carray, i64 1
+ %idxD1 = getelementptr inbounds i32, ptr %Darray, i64 1
+ %idxS1 = getelementptr inbounds i32, ptr %Sarray, i64 1
+
+ %A0 = load i32, ptr %Aarray, align 4
+ %A1 = load i32, ptr %idxA1, align 4
+
+ %B0 = load i32, ptr %Barray, align 4
+ %B1 = load i32, ptr %idxB1, align 4
+
+ %C0 = load i32, ptr %Carray, align 4
+ %C1 = load i32, ptr %idxC1, align 4
+
+ %D0 = load i32, ptr %Darray, align 4
+ %D1 = load i32, ptr %idxD1, align 4
+
+ %addA0B0 = add i32 %A0, %B0
+ %subC0D0 = sub i32 %C0, %D0
+ %sub0 = sub i32 %addA0B0, %subC0D0
+
+ %addA1D1 = add i32 %A1, %D1
+ %subC1B1 = sub i32 %C1, %B1
+ %sub1 = sub i32 %addA1D1, %subC1B1
+
+ store i32 %sub0, ptr %Sarray, align 4
+ store i32 %sub1, ptr %idxS1, align 4
+ ret void
+}
+
+; The subtrahends come from a peeled add, so the negated-group combine
+; exactly reproduces that add lane by lane and reuses its flags, and the
+; final subtract exactly reproduces the root scalar and reuses its flags.
+; Only the exact matches permit this; the fallback would have dropped both
+; wrap flags because a negated leaf is present.
+;
+; S[0] = A[0] - (B[0] + C[0])
+; S[1] = A[1] - (C[1] + B[1])
+define void @test_reassoc_sub_neg_group_exact(ptr %Aarray, ptr %Barray, ptr %Carray, ptr %Sarray) {
+; CHECK-LABEL: define void @test_reassoc_sub_neg_group_exact(
+; CHECK-SAME: ptr [[AARRAY:%.*]], ptr [[BARRAY:%.*]], ptr [[CARRAY:%.*]], ptr [[SARRAY:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = load <2 x i32>, ptr [[AARRAY]], align 4
+; CHECK-NEXT: [[TMP1:%.*]] = load <2 x i32>, ptr [[BARRAY]], align 4
+; CHECK-NEXT: [[TMP2:%.*]] = load <2 x i32>, ptr [[CARRAY]], align 4
+; CHECK-NEXT: [[TMP3:%.*]] = add nuw nsw <2 x i32> [[TMP2]], [[TMP1]]
+; CHECK-NEXT: [[TMP4:%.*]] = sub nuw nsw <2 x i32> [[TMP0]], [[TMP3]]
+; CHECK-NEXT: store <2 x i32> [[TMP4]], ptr [[SARRAY]], align 4
+; CHECK-NEXT: ret void
+;
+entry:
+ %idxA1 = getelementptr inbounds i32, ptr %Aarray, i64 1
+ %idxB1 = getelementptr inbounds i32, ptr %Barray, i64 1
+ %idxC1 = getelementptr inbounds i32, ptr %Carray, i64 1
+ %idxS1 = getelementptr inbounds i32, ptr %Sarray, i64 1
+
+ %A0 = load i32, ptr %Aarray, align 4
+ %A1 = load i32, ptr %idxA1, align 4
+
+ %B0 = load i32, ptr %Barray, align 4
+ %B1 = load i32, ptr %idxB1, align 4
+
+ %C0 = load i32, ptr %Carray, align 4
+ %C1 = load i32, ptr %idxC1, align 4
+
+ %addB0C0 = add nuw nsw i32 %B0, %C0
+ %sub0 = sub nuw nsw i32 %A0, %addB0C0
+
+ %addC1B1 = add nuw nsw i32 %C1, %B1
+ %sub1 = sub nuw nsw i32 %A1, %addC1B1
+
+ store i32 %sub0, ptr %Sarray, align 4
+ store i32 %sub1, ptr %idxS1, align 4
+ ret void
+}
+
+; Same shape as above, but the lanes disagree on flags: flag propagation
+; intersects across lanes, so even though every combine exactly reproduces
+; a source instruction, no wrap flags survive.
+;
+; S[0] = A[0] - (B[0] + C[0])
+; S[1] = A[1] - (C[1] + B[1])
+define void @test_reassoc_sub_mixed_lane_flags(ptr %Aarray, ptr %Barray, ptr %Carray, ptr %Sarray) {
+; CHECK-LABEL: define void @test_reassoc_sub_mixed_lane_flags(
+; CHECK-SAME: ptr [[AARRAY:%.*]], ptr [[BARRAY:%.*]], ptr [[CARRAY:%.*]], ptr [[SARRAY:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = load <2 x i32>, ptr [[AARRAY]], align 4
+; CHECK-NEXT: [[TMP1:%.*]] = load <2 x i32>, ptr [[BARRAY]], align 4
+; CHECK-NEXT: [[TMP2:%.*]] = load <2 x i32>, ptr [[CARRAY]], align 4
+; CHECK-NEXT: [[TMP3:%.*]] = add <2 x i32> [[TMP2]], [[TMP1]]
+; CHECK-NEXT: [[TMP4:%.*]] = sub <2 x i32> [[TMP0]], [[TMP3]]
+; CHECK-NEXT: store <2 x i32> [[TMP4]], ptr [[SARRAY]], align 4
+; CHECK-NEXT: ret void
+;
+entry:
+ %idxA1 = getelementptr inbounds i32, ptr %Aarray, i64 1
+ %idxB1 = getelementptr inbounds i32, ptr %Barray, i64 1
+ %idxC1 = getelementptr inbounds i32, ptr %Carray, i64 1
+ %idxS1 = getelementptr inbounds i32, ptr %Sarray, i64 1
+
+ %A0 = load i32, ptr %Aarray, align 4
+ %A1 = load i32, ptr %idxA1, align 4
+
+ %B0 = load i32, ptr %Barray, align 4
+ %B1 = load i32, ptr %idxB1, align 4
+
+ %C0 = load i32, ptr %Carray, align 4
+ %C1 = load i32, ptr %idxC1, align 4
+
+ %addB0C0 = add nuw nsw i32 %B0, %C0
+ %sub0 = sub nuw nsw i32 %A0, %addB0C0
+
+ %addC1B1 = add i32 %C1, %B1
+ %sub1 = sub i32 %A1, %addC1B1
+
+ store i32 %sub0, ptr %Sarray, align 4
+ store i32 %sub1, ptr %idxS1, align 4
+ ret void
+}
+
+; Lane 2 of the peeled subtract column is not an instruction at all: it
+; stands in as a copyable identity leaf (sub(x, 0) == x). The peel happens,
+; but the identity zeros break the load-column structure, so the tie rule
+; keeps the natural two-operand form; the vectorized result must still be
+; correct (note the 0 lane in the subtrahend operand).
+;
+; S[0] = (A[0] - B[0]) + C[0]
+; S[1] = (A[1] - B[1]) + C[1]
+; S[2] = x + C[2]
+; S[3] = (A[3] - B[3]) + C[3]
+define void @test_reassoc_sub_copyable_lane(ptr %Aarray, ptr %Barray, ptr %Carray, i32 %x, ptr %Sarray) {
+; CHECK-LABEL: define void @test_reassoc_sub_copyable_lane(
+; CHECK-SAME: ptr [[AARRAY:%.*]], ptr [[BARRAY:%.*]], ptr [[CARRAY:%.*]], i32 [[X:%.*]], ptr [[SARRAY:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[IDXA2:%.*]] = getelementptr inbounds i32, ptr [[AARRAY]], i64 2
+; CHECK-NEXT: [[IDXA3:%.*]] = getelementptr inbounds i32, ptr [[AARRAY]], i64 3
+; CHECK-NEXT: [[IDXB2:%.*]] = getelementptr inbounds i32, ptr [[BARRAY]], i64 2
+; CHECK-NEXT: [[IDXB3:%.*]] = getelementptr inbounds i32, ptr [[BARRAY]], i64 3
+; CHECK-NEXT: [[A3:%.*]] = load i32, ptr [[IDXA3]], align 4
+; CHECK-NEXT: [[B3:%.*]] = load i32, ptr [[IDXB3]], align 4
+; CHECK-NEXT: [[TMP0:%.*]] = load <2 x i32>, ptr [[AARRAY]], align 4
+; CHECK-NEXT: [[TMP1:%.*]] = load <2 x i32>, ptr [[BARRAY]], ...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/213002
More information about the llvm-commits
mailing list