[llvm-branch-commits] [VectorCombine] Fix miscompile caused by collisions in foldShuffleToIdentity (PR #188668)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Wed Mar 25 20:20:28 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

Author: wanglei (wangleiat)

<details>
<summary>Changes</summary>

`foldShuffleToIdentity` previously used a `SmallPtrSet<Use *, 4>` keyed
only on the first lane's `Use *` to track equivalent sequences. This
caused incorrect folding when different shuffle sequences shared the
same initial `Use *`.

This patch fixes the miscompile by tracking the full `InstLane` sequence
via `SmallVector<SmallVector<InstLane>>`, ensuring exact sequence
matching.

It also corrects an implicit `Use *` to `Value *` conversion by changing
`dyn_cast<Constant>(FrontU)` to `dyn_cast<Constant>(FrontU->get())`.

Fixes #<!-- -->180338


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


2 Files Affected:

- (modified) llvm/lib/Transforms/Vectorize/VectorCombine.cpp (+20-16) 
- (modified) llvm/test/Transforms/VectorCombine/LoongArch/shuffle-identity-miscompile.ll (+4-2) 


``````````diff
diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index 136f4fe238b34..42680c1fe272d 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -3509,22 +3509,26 @@ static bool isFreeConcat(ArrayRef<InstLane> Item, TTI::TargetCostKind CostKind,
   return true;
 }
 
-static Value *generateNewInstTree(ArrayRef<InstLane> Item, FixedVectorType *Ty,
-                                  const SmallPtrSet<Use *, 4> &IdentityLeafs,
-                                  const SmallPtrSet<Use *, 4> &SplatLeafs,
-                                  const SmallPtrSet<Use *, 4> &ConcatLeafs,
-                                  IRBuilderBase &Builder,
-                                  const TargetTransformInfo *TTI) {
+static Value *
+generateNewInstTree(ArrayRef<InstLane> Item, FixedVectorType *Ty,
+                    const SmallVectorImpl<SmallVector<InstLane>> &IdentityLeafs,
+                    const SmallVectorImpl<SmallVector<InstLane>> &SplatLeafs,
+                    const SmallVectorImpl<SmallVector<InstLane>> &ConcatLeafs,
+                    IRBuilderBase &Builder, const TargetTransformInfo *TTI) {
   auto [FrontU, FrontLane] = Item.front();
 
-  if (IdentityLeafs.contains(FrontU)) {
+  auto Contains = [](const SmallVectorImpl<SmallVector<InstLane>> &Set,
+                     ArrayRef<InstLane> Item) {
+    return any_of(Set, [&](ArrayRef<InstLane> E) { return E == Item; });
+  };
+
+  if (Contains(IdentityLeafs, Item))
     return FrontU->get();
-  }
-  if (SplatLeafs.contains(FrontU)) {
+  if (Contains(SplatLeafs, Item)) {
     SmallVector<int, 16> Mask(Ty->getNumElements(), FrontLane);
     return Builder.CreateShuffleVector(FrontU->get(), Mask);
   }
-  if (ConcatLeafs.contains(FrontU)) {
+  if (Contains(ConcatLeafs, Item)) {
     unsigned NumElts =
         cast<FixedVectorType>(FrontU->get()->getType())->getNumElements();
     SmallVector<Value *> Values(Item.size() / NumElts, nullptr);
@@ -3613,7 +3617,7 @@ bool VectorCombine::foldShuffleToIdentity(Instruction &I) {
 
   SmallVector<SmallVector<InstLane>> Worklist;
   Worklist.push_back(Start);
-  SmallPtrSet<Use *, 4> IdentityLeafs, SplatLeafs, ConcatLeafs;
+  SmallVector<SmallVector<InstLane>> IdentityLeafs, SplatLeafs, ConcatLeafs;
   unsigned NumVisited = 0;
 
   while (!Worklist.empty()) {
@@ -3642,11 +3646,11 @@ bool VectorCombine::foldShuffleToIdentity(Instruction &I) {
           return !E.value().first || (IsEquiv(E.value().first->get(), FrontV) &&
                                       E.value().second == (int)E.index());
         })) {
-      IdentityLeafs.insert(FrontU);
+      IdentityLeafs.push_back(std::move(Item));
       continue;
     }
     // Look for constants, for the moment only supporting constant splats.
-    if (auto *C = dyn_cast<Constant>(FrontU);
+    if (auto *C = dyn_cast<Constant>(FrontU->get());
         C && C->getSplatValue() &&
         all_of(drop_begin(Item), [Item](InstLane &IL) {
           Value *FrontV = Item.front().first->get();
@@ -3655,7 +3659,7 @@ bool VectorCombine::foldShuffleToIdentity(Instruction &I) {
                         cast<Constant>(U->get())->getSplatValue() ==
                             cast<Constant>(FrontV)->getSplatValue());
         })) {
-      SplatLeafs.insert(FrontU);
+      SplatLeafs.push_back(std::move(Item));
       continue;
     }
     // Look for a splat value.
@@ -3664,7 +3668,7 @@ bool VectorCombine::foldShuffleToIdentity(Instruction &I) {
           auto [U, Lane] = IL;
           return !U || (U->get() == FrontU->get() && Lane == FrontLane);
         })) {
-      SplatLeafs.insert(FrontU);
+      SplatLeafs.push_back(std::move(Item));
       continue;
     }
 
@@ -3749,7 +3753,7 @@ bool VectorCombine::foldShuffleToIdentity(Instruction &I) {
     }
 
     if (isFreeConcat(Item, CostKind, TTI)) {
-      ConcatLeafs.insert(FrontU);
+      ConcatLeafs.push_back(std::move(Item));
       continue;
     }
 
diff --git a/llvm/test/Transforms/VectorCombine/LoongArch/shuffle-identity-miscompile.ll b/llvm/test/Transforms/VectorCombine/LoongArch/shuffle-identity-miscompile.ll
index 94815d8a604bc..1582dc4c59708 100644
--- a/llvm/test/Transforms/VectorCombine/LoongArch/shuffle-identity-miscompile.ll
+++ b/llvm/test/Transforms/VectorCombine/LoongArch/shuffle-identity-miscompile.ll
@@ -7,8 +7,10 @@ define i32 @shuffle_different_lanes() local_unnamed_addr {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
 ; CHECK-NEXT:    [[TMP0:%.*]] = call <2 x i64> @llvm.loongarch.lsx.vadd.d(<2 x i64> <i64 8067293510808050, i64 0>, <2 x i64> zeroinitializer)
 ; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i64> [[TMP0]] to <2 x i16>
-; CHECK-NEXT:    [[TMP2:%.*]] = trunc <2 x i64> [[TMP0]] to <2 x i16>
-; CHECK-NEXT:    [[TMP3:%.*]] = bitcast <2 x i16> zeroinitializer to i32
+; CHECK-NEXT:    [[TMP2:%.*]] = shufflevector <2 x i64> [[TMP0]], <2 x i64> poison, <2 x i32> <i32 1, i32 1>
+; CHECK-NEXT:    [[TMP4:%.*]] = trunc <2 x i64> [[TMP2]] to <2 x i16>
+; CHECK-NEXT:    [[SHUFFLE_I:%.*]] = sub <2 x i16> [[TMP1]], [[TMP4]]
+; CHECK-NEXT:    [[TMP3:%.*]] = bitcast <2 x i16> [[SHUFFLE_I]] to i32
 ; CHECK-NEXT:    ret i32 [[TMP3]]
 ;
 entry:

``````````

</details>


https://github.com/llvm/llvm-project/pull/188668


More information about the llvm-branch-commits mailing list