Skip to content

[SLP]Fix external uses of the pointers of the jumbled copyable loads - #240127

Merged
alexey-bataev merged 1 commit into
mainfrom
users/alexey-bataev/spr/slpfix-external-uses-of-the-pointers-of-the-jumbled-copyable-loads
Nov 8, 2026
Merged

alexey-bataev merged 1 commit into
mainfrom
users/alexey-bataev/spr/slpfix-external-uses-of-the-pointers-of-the-jumbled-copyable-loads

Conversation

@alexey-bataev

Copy link
Copy Markdown
Member

The wide load of the copyable loads uses the pointer of the first load,
which may differ from the main op after reordering. Use it as the root
instruction to correctly detect the pointers, which need extracts.

Fixes #233297 (comment)

Assisted-by: Cursor

Created using spr 1.3.7
@alexey-bataev
alexey-bataev merged commit 5ef6400 into main Nov 8, 2026
11 of 14 checks passed
@alexey-bataev
alexey-bataev deleted the users/alexey-bataev/spr/slpfix-external-uses-of-the-pointers-of-the-jumbled-copyable-loads branch November 8, 2026 12:39
@llvmorg-github-actions

Copy link
Copy Markdown

@llvm/pr-subscribers-llvm-vectorizers

Author: Alexey Bataev (alexey-bataev)

Changes

The wide load of the copyable loads uses the pointer of the first load,
which may differ from the main op after reordering. Use it as the root
instruction to correctly detect the pointers, which need extracts.

Fixes #233297 (comment)

Assisted-by: Cursor


Full diff: https://github.com/llvm/llvm-project/pull/240127.diff

2 Files Affected:

  • (modified) llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp (+3)
  • (modified) llvm/test/Transforms/SLPVectorizer/X86/loads-from-single-predecessor.ll (+58)
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index 920205b1f9ce1..f3efbff76b778 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -8070,6 +8070,9 @@ Instruction *BoUpSLP::getRootEntryInstruction(const TreeEntry &Entry) const {
       Entry.State == TreeEntry::StridedVectorize && Entry.isReverse() &&
       !isWidenedStridedLoad(&Entry))
     return dyn_cast<Instruction>(Entry.Scalars[Entry.ReorderIndices.front()]);
+  // The wide load of the copyable loads uses the pointer of the first load.
+  if (Entry.hasState() && Entry.getOpcode() == Instruction::Load)
+    return Entry.getFirstLoad();
   return Entry.hasState() ? Entry.getMainOp()
                           : dyn_cast<Instruction>(Entry.Scalars.front());
 }
diff --git a/llvm/test/Transforms/SLPVectorizer/X86/loads-from-single-predecessor.ll b/llvm/test/Transforms/SLPVectorizer/X86/loads-from-single-predecessor.ll
index f0e8526fc81d6..2ea4b8ef5c534 100644
--- a/llvm/test/Transforms/SLPVectorizer/X86/loads-from-single-predecessor.ll
+++ b/llvm/test/Transforms/SLPVectorizer/X86/loads-from-single-predecessor.ll
@@ -567,6 +567,64 @@ exit:
   ret i32 0
 }
 
+; The pointers of the jumbled loads are vectorized, the first load is not the
+; main op of the node.
+define i64 @jumbled_vectorized_ptrs(ptr %b, ptr noalias %dst, i1 %c) {
+; CHECK-LABEL: define i64 @jumbled_vectorized_ptrs(
+; CHECK-SAME: ptr [[B:%.*]], ptr noalias [[DST:%.*]], i1 [[C:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[TMP0:%.*]] = insertelement <4 x ptr> poison, ptr [[B]], i64 0
+; CHECK-NEXT:    [[TMP1:%.*]] = shufflevector <4 x ptr> [[TMP0]], <4 x ptr> poison, <4 x i32> zeroinitializer
+; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds i8, <4 x ptr> [[TMP1]], <4 x i64> <i64 16, i64 8, i64 24, i64 32>
+; CHECK-NEXT:    [[G0:%.*]] = getelementptr inbounds i8, ptr [[B]], i64 8
+; CHECK-NEXT:    [[G2:%.*]] = getelementptr inbounds i8, ptr [[B]], i64 24
+; CHECK-NEXT:    [[L2:%.*]] = load i64, ptr [[G2]], align 8
+; CHECK-NEXT:    br i1 [[C]], label %[[BB:.*]], label %[[EXIT:.*]]
+; CHECK:       [[BB]]:
+; CHECK-NEXT:    [[TMP3:%.*]] = ptrtoint <4 x ptr> [[TMP2]] to <4 x i64>
+; CHECK-NEXT:    [[TMP4:%.*]] = load <4 x i64>, ptr [[G0]], align 8
+; CHECK-NEXT:    [[TMP5:%.*]] = shufflevector <4 x i64> [[TMP4]], <4 x i64> poison, <4 x i32> <i32 1, i32 0, i32 2, i32 3>
+; CHECK-NEXT:    [[TMP6:%.*]] = add <4 x i64> [[TMP5]], [[TMP3]]
+; CHECK-NEXT:    store <4 x i64> [[TMP6]], ptr [[DST]], align 8
+; CHECK-NEXT:    br label %[[EXIT]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    [[R:%.*]] = phi i64 [ [[L2]], %[[ENTRY]] ], [ 0, %[[BB]] ]
+; CHECK-NEXT:    ret i64 [[R]]
+;
+entry:
+  %g0 = getelementptr inbounds i8, ptr %b, i64 8
+  %g1 = getelementptr inbounds i8, ptr %b, i64 16
+  %g2 = getelementptr inbounds i8, ptr %b, i64 24
+  %g3 = getelementptr inbounds i8, ptr %b, i64 32
+  %l2 = load i64, ptr %g2, align 8
+  br i1 %c, label %bb, label %exit
+
+bb:
+  %l1 = load i64, ptr %g1, align 8
+  %l0 = load i64, ptr %g0, align 8
+  %l3 = load i64, ptr %g3, align 8
+  %p1 = ptrtoint ptr %g1 to i64
+  %p0 = ptrtoint ptr %g0 to i64
+  %p2 = ptrtoint ptr %g2 to i64
+  %p3 = ptrtoint ptr %g3 to i64
+  %s1 = add i64 %l1, %p1
+  %s0 = add i64 %l0, %p0
+  %s2 = add i64 %l2, %p2
+  %s3 = add i64 %l3, %p3
+  %d1 = getelementptr inbounds i64, ptr %dst, i64 1
+  %d2 = getelementptr inbounds i64, ptr %dst, i64 2
+  %d3 = getelementptr inbounds i64, ptr %dst, i64 3
+  store i64 %s1, ptr %dst, align 8
+  store i64 %s0, ptr %d1, align 8
+  store i64 %s2, ptr %d2, align 8
+  store i64 %s3, ptr %d3, align 8
+  br label %exit
+
+exit:
+  %r = phi i64 [ %l2, %entry ], [ 0, %bb ]
+  ret i64 %r
+}
+
 !0 = !{!1, !1, i64 0}
 !1 = !{!"int", !2, i64 0}
 !2 = !{!"omnipotent char", !4, i64 0}

@llvmorg-github-actions

Copy link
Copy Markdown

@llvm/pr-subscribers-llvm-transforms

Author: Alexey Bataev (alexey-bataev)

Changes

The wide load of the copyable loads uses the pointer of the first load,
which may differ from the main op after reordering. Use it as the root
instruction to correctly detect the pointers, which need extracts.

Fixes #233297 (comment)

Assisted-by: Cursor


Full diff: https://github.com/llvm/llvm-project/pull/240127.diff

2 Files Affected:

  • (modified) llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp (+3)
  • (modified) llvm/test/Transforms/SLPVectorizer/X86/loads-from-single-predecessor.ll (+58)
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index 920205b1f9ce1..f3efbff76b778 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -8070,6 +8070,9 @@ Instruction *BoUpSLP::getRootEntryInstruction(const TreeEntry &Entry) const {
       Entry.State == TreeEntry::StridedVectorize && Entry.isReverse() &&
       !isWidenedStridedLoad(&Entry))
     return dyn_cast<Instruction>(Entry.Scalars[Entry.ReorderIndices.front()]);
+  // The wide load of the copyable loads uses the pointer of the first load.
+  if (Entry.hasState() && Entry.getOpcode() == Instruction::Load)
+    return Entry.getFirstLoad();
   return Entry.hasState() ? Entry.getMainOp()
                           : dyn_cast<Instruction>(Entry.Scalars.front());
 }
diff --git a/llvm/test/Transforms/SLPVectorizer/X86/loads-from-single-predecessor.ll b/llvm/test/Transforms/SLPVectorizer/X86/loads-from-single-predecessor.ll
index f0e8526fc81d6..2ea4b8ef5c534 100644
--- a/llvm/test/Transforms/SLPVectorizer/X86/loads-from-single-predecessor.ll
+++ b/llvm/test/Transforms/SLPVectorizer/X86/loads-from-single-predecessor.ll
@@ -567,6 +567,64 @@ exit:
   ret i32 0
 }
 
+; The pointers of the jumbled loads are vectorized, the first load is not the
+; main op of the node.
+define i64 @jumbled_vectorized_ptrs(ptr %b, ptr noalias %dst, i1 %c) {
+; CHECK-LABEL: define i64 @jumbled_vectorized_ptrs(
+; CHECK-SAME: ptr [[B:%.*]], ptr noalias [[DST:%.*]], i1 [[C:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[TMP0:%.*]] = insertelement <4 x ptr> poison, ptr [[B]], i64 0
+; CHECK-NEXT:    [[TMP1:%.*]] = shufflevector <4 x ptr> [[TMP0]], <4 x ptr> poison, <4 x i32> zeroinitializer
+; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds i8, <4 x ptr> [[TMP1]], <4 x i64> <i64 16, i64 8, i64 24, i64 32>
+; CHECK-NEXT:    [[G0:%.*]] = getelementptr inbounds i8, ptr [[B]], i64 8
+; CHECK-NEXT:    [[G2:%.*]] = getelementptr inbounds i8, ptr [[B]], i64 24
+; CHECK-NEXT:    [[L2:%.*]] = load i64, ptr [[G2]], align 8
+; CHECK-NEXT:    br i1 [[C]], label %[[BB:.*]], label %[[EXIT:.*]]
+; CHECK:       [[BB]]:
+; CHECK-NEXT:    [[TMP3:%.*]] = ptrtoint <4 x ptr> [[TMP2]] to <4 x i64>
+; CHECK-NEXT:    [[TMP4:%.*]] = load <4 x i64>, ptr [[G0]], align 8
+; CHECK-NEXT:    [[TMP5:%.*]] = shufflevector <4 x i64> [[TMP4]], <4 x i64> poison, <4 x i32> <i32 1, i32 0, i32 2, i32 3>
+; CHECK-NEXT:    [[TMP6:%.*]] = add <4 x i64> [[TMP5]], [[TMP3]]
+; CHECK-NEXT:    store <4 x i64> [[TMP6]], ptr [[DST]], align 8
+; CHECK-NEXT:    br label %[[EXIT]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    [[R:%.*]] = phi i64 [ [[L2]], %[[ENTRY]] ], [ 0, %[[BB]] ]
+; CHECK-NEXT:    ret i64 [[R]]
+;
+entry:
+  %g0 = getelementptr inbounds i8, ptr %b, i64 8
+  %g1 = getelementptr inbounds i8, ptr %b, i64 16
+  %g2 = getelementptr inbounds i8, ptr %b, i64 24
+  %g3 = getelementptr inbounds i8, ptr %b, i64 32
+  %l2 = load i64, ptr %g2, align 8
+  br i1 %c, label %bb, label %exit
+
+bb:
+  %l1 = load i64, ptr %g1, align 8
+  %l0 = load i64, ptr %g0, align 8
+  %l3 = load i64, ptr %g3, align 8
+  %p1 = ptrtoint ptr %g1 to i64
+  %p0 = ptrtoint ptr %g0 to i64
+  %p2 = ptrtoint ptr %g2 to i64
+  %p3 = ptrtoint ptr %g3 to i64
+  %s1 = add i64 %l1, %p1
+  %s0 = add i64 %l0, %p0
+  %s2 = add i64 %l2, %p2
+  %s3 = add i64 %l3, %p3
+  %d1 = getelementptr inbounds i64, ptr %dst, i64 1
+  %d2 = getelementptr inbounds i64, ptr %dst, i64 2
+  %d3 = getelementptr inbounds i64, ptr %dst, i64 3
+  store i64 %s1, ptr %dst, align 8
+  store i64 %s0, ptr %d1, align 8
+  store i64 %s2, ptr %d2, align 8
+  store i64 %s3, ptr %d3, align 8
+  br label %exit
+
+exit:
+  %r = phi i64 [ %l2, %entry ], [ 0, %bb ]
+  ret i64 %r
+}
+
 !0 = !{!1, !1, i64 0}
 !1 = !{!"int", !2, i64 0}
 !2 = !{!"omnipotent char", !4, i64 0}

llvm-upstreamsync Bot pushed a commit to qualcomm/cpullvm-toolchain that referenced this pull request Nov 8, 2026
…able loads

The wide load of the copyable loads uses the pointer of the first load,
which may differ from the main op after reordering. Use it as the root
instruction to correctly detect the pointers, which need extracts.

Fixes llvm/llvm-project#233297 (comment)

Assisted-by: Cursor

Reviewers:

Pull Request: llvm/llvm-project#240127
llvm-sync Bot pushed a commit to arm/arm-toolchain that referenced this pull request Nov 8, 2026
…able loads

The wide load of the copyable loads uses the pointer of the first load,
which may differ from the main op after reordering. Use it as the root
instruction to correctly detect the pointers, which need extracts.

Fixes llvm/llvm-project#233297 (comment)

Assisted-by: Cursor

Reviewers:

Pull Request: llvm/llvm-project#240127
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant