[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