[llvm] [VectorCombine] Fix duplicate freeze scheduling for shared indexes (PR #213461)

Aditya prakash jha via llvm-commits llvm-commits at lists.llvm.org
Sat Aug 1 11:33:48 PDT 2026


https://github.com/AdityaOP007 updated https://github.com/llvm/llvm-project/pull/213461

>From 1367c6100236ece94754b4b1b5dd22b8b0bbff74 Mon Sep 17 00:00:00 2001
From: AdityaOP007 <adityaprakashjha321 at gmail.com>
Date: Sat, 1 Aug 2026 21:28:26 +0530
Subject: [PATCH 1/2] [VectorCombine] Fix duplicate freeze scheduling for
 shared indexes

---
 .../Transforms/Vectorize/VectorCombine.cpp    | 15 +++++----
 .../Transforms/VectorCombine/X86/pr213423.ll  | 33 +++++++++++++++++++
 test.ll                                       |  5 +++
 test2.ll                                      |  7 ++++
 4 files changed, 54 insertions(+), 6 deletions(-)
 create mode 100644 llvm/test/Transforms/VectorCombine/X86/pr213423.ll
 create mode 100644 test.ll
 create mode 100644 test2.ll

diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index 726f564b1aad9..2c1143b0957a6 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -1929,7 +1929,7 @@ static ScalarizationResult canScalarizeAccess(VectorType *VecTy, Value *Idx,
 
   // If the index may be poison, check if we can insert a freeze before the
   // range of the index is restricted.
-  Value *IdxBase;
+  Value *IdxBase = nullptr;
   ConstantInt *CI;
   if (match(Idx, m_And(m_Value(IdxBase), m_ConstantInt(CI)))) {
     IdxRange = IdxRange.binaryAnd(CI->getValue());
@@ -1937,7 +1937,7 @@ static ScalarizationResult canScalarizeAccess(VectorType *VecTy, Value *Idx,
     IdxRange = IdxRange.urem(CI->getValue());
   }
 
-  if (ValidIndices.contains(IdxRange))
+  if (IdxBase && ValidIndices.contains(IdxRange))
     return ScalarizationResult::safeWithFreeze(IdxBase);
   return ScalarizationResult::unsafe();
 }
@@ -2086,7 +2086,7 @@ bool VectorCombine::scalarizeLoadExtract(LoadInst *LI, VectorType *VecTy,
   if (!TTI.allowVectorElementIndexingUsingGEP())
     return false;
 
-  DenseMap<ExtractElementInst *, ScalarizationResult> NeedFreeze;
+  DenseMap<Instruction *, ScalarizationResult> NeedFreeze;
   llvm::scope_exit FailureGuard([&]() {
     // If the transform is aborted, discard the ScalarizationResults.
     for (auto &Pair : NeedFreeze)
@@ -2106,7 +2106,8 @@ bool VectorCombine::scalarizeLoadExtract(LoadInst *LI, VectorType *VecTy,
     if (ScalarIdx.isUnsafe())
       return false;
     if (ScalarIdx.isSafeWithFreeze()) {
-      NeedFreeze.try_emplace(UI, ScalarIdx);
+      NeedFreeze.try_emplace(cast<Instruction>(UI->getIndexOperand()),
+                             ScalarIdx);
       ScalarIdx.discard();
     }
 
@@ -2140,9 +2141,11 @@ bool VectorCombine::scalarizeLoadExtract(LoadInst *LI, VectorType *VecTy,
     Value *Idx = EI->getIndexOperand();
 
     // Insert 'freeze' for poison indexes.
-    auto It = NeedFreeze.find(EI);
-    if (It != NeedFreeze.end())
+    auto It = NeedFreeze.find(cast<Instruction>(Idx));
+    if (It != NeedFreeze.end()) {
       It->second.freeze(Builder, *cast<Instruction>(Idx));
+      NeedFreeze.erase(It);
+    }
 
     Builder.SetInsertPoint(EI);
     Value *GEP =
diff --git a/llvm/test/Transforms/VectorCombine/X86/pr213423.ll b/llvm/test/Transforms/VectorCombine/X86/pr213423.ll
new file mode 100644
index 0000000000000..2b932bca422d6
--- /dev/null
+++ b/llvm/test/Transforms/VectorCombine/X86/pr213423.ll
@@ -0,0 +1,33 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -passes=vector-combine -S | FileCheck %s
+
+; Issue #213423
+; Check that we do not crash when multiple extracts share the same index instruction
+; and it needs to be frozen.
+define void @test_shared_index(ptr %p, i32 %idx.base) {
+; CHECK-LABEL: @test_shared_index(
+; CHECK-NEXT:    [[IDX:%.*]] = and i32 [[IDX_BASE:%.*]], 1
+; CHECK-NEXT:    [[V:%.*]] = load <2 x i32>, ptr [[P:%.*]], align 8
+; CHECK-NEXT:    [[E1:%.*]] = extractelement <2 x i32> [[V]], i32 [[IDX]]
+; CHECK-NEXT:    [[E2:%.*]] = extractelement <2 x i32> [[V]], i32 [[IDX]]
+; CHECK-NEXT:    ret void
+;
+  %idx = and i32 %idx.base, 1
+  %v = load <2 x i32>, ptr %p
+  %e1 = extractelement <2 x i32> %v, i32 %idx
+  %e2 = extractelement <2 x i32> %v, i32 %idx
+  ret void
+}
+
+; Check that we do not use an uninitialized pointer when the index doesn't match and/urem
+; but is naturally in bounds.
+define void @test_uninitialized_base(ptr %p, i1 %idx) {
+; CHECK-LABEL: @test_uninitialized_base(
+; CHECK-NEXT:    [[V:%.*]] = load <2 x i32>, ptr [[P:%.*]], align 8
+; CHECK-NEXT:    [[E:%.*]] = extractelement <2 x i32> [[V]], i1 [[IDX:%.*]]
+; CHECK-NEXT:    ret void
+;
+  %v = load <2 x i32>, ptr %p
+  %e = extractelement <2 x i32> %v, i1 %idx
+  ret void
+}
diff --git a/test.ll b/test.ll
new file mode 100644
index 0000000000000..cc7d1e1111b31
--- /dev/null
+++ b/test.ll
@@ -0,0 +1,5 @@
+define void @test(ptr %p, i1 %idx) {
+  %v = load <2 x i32>, ptr %p
+  %e = extractelement <2 x i32> %v, i1 %idx
+  ret void
+}
diff --git a/test2.ll b/test2.ll
new file mode 100644
index 0000000000000..3b5e2b0a42912
--- /dev/null
+++ b/test2.ll
@@ -0,0 +1,7 @@
+define void @test(ptr %p, i32 %idx.base) {
+  %idx = and i32 %idx.base, 1
+  %v = load <2 x i32>, ptr %p
+  %e1 = extractelement <2 x i32> %v, i32 %idx
+  %e2 = extractelement <2 x i32> %v, i32 %idx
+  ret void
+}

>From edf13de61a098e5b5bf6fa785059b8bf76242bb1 Mon Sep 17 00:00:00 2001
From: AdityaOP007 <adityaprakashjha321 at gmail.com>
Date: Sun, 2 Aug 2026 00:03:27 +0530
Subject: [PATCH 2/2] Update regression test

---
 .../Transforms/Vectorize/VectorCombine.cpp    |  4 +-
 .../Transforms/VectorCombine/X86/pr213423.ll  | 47 ++++++++++---------
 2 files changed, 26 insertions(+), 25 deletions(-)

diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index 2c1143b0957a6..4a0ef49c089f7 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -1929,7 +1929,7 @@ static ScalarizationResult canScalarizeAccess(VectorType *VecTy, Value *Idx,
 
   // If the index may be poison, check if we can insert a freeze before the
   // range of the index is restricted.
-  Value *IdxBase = nullptr;
+  Value *IdxBase;
   ConstantInt *CI;
   if (match(Idx, m_And(m_Value(IdxBase), m_ConstantInt(CI)))) {
     IdxRange = IdxRange.binaryAnd(CI->getValue());
@@ -1937,7 +1937,7 @@ static ScalarizationResult canScalarizeAccess(VectorType *VecTy, Value *Idx,
     IdxRange = IdxRange.urem(CI->getValue());
   }
 
-  if (IdxBase && ValidIndices.contains(IdxRange))
+  if (ValidIndices.contains(IdxRange))
     return ScalarizationResult::safeWithFreeze(IdxBase);
   return ScalarizationResult::unsafe();
 }
diff --git a/llvm/test/Transforms/VectorCombine/X86/pr213423.ll b/llvm/test/Transforms/VectorCombine/X86/pr213423.ll
index 2b932bca422d6..5180f04ee3670 100644
--- a/llvm/test/Transforms/VectorCombine/X86/pr213423.ll
+++ b/llvm/test/Transforms/VectorCombine/X86/pr213423.ll
@@ -1,33 +1,34 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
 ; RUN: opt < %s -passes=vector-combine -S | FileCheck %s
 
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
 ; Issue #213423
 ; Check that we do not crash when multiple extracts share the same index instruction
 ; and it needs to be frozen.
-define void @test_shared_index(ptr %p, i32 %idx.base) {
+define i1 @test_shared_index(i32 %base) {
 ; CHECK-LABEL: @test_shared_index(
-; CHECK-NEXT:    [[IDX:%.*]] = and i32 [[IDX_BASE:%.*]], 1
-; CHECK-NEXT:    [[V:%.*]] = load <2 x i32>, ptr [[P:%.*]], align 8
-; CHECK-NEXT:    [[E1:%.*]] = extractelement <2 x i32> [[V]], i32 [[IDX]]
-; CHECK-NEXT:    [[E2:%.*]] = extractelement <2 x i32> [[V]], i32 [[IDX]]
-; CHECK-NEXT:    ret void
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[V:%.*]] = load <2 x i16>, ptr null, align 4
+; CHECK-NEXT:    [[TMP0:%.*]] = freeze i32 [[BASE:%.*]]
+; CHECK-NEXT:    [[IDX:%.*]] = and i32 [[TMP0]], 0
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i16, ptr null, i32 [[IDX]]
+; CHECK-NEXT:    [[E1:%.*]] = load i16, ptr [[TMP1]], align 2
+; CHECK-NEXT:    [[TMP2:%.*]] = extractelement <2 x i16> [[V]], i32 [[IDX]]
+; CHECK-NEXT:    [[TMP3:%.*]] = getelementptr inbounds i16, ptr null, i32 [[IDX]]
+; CHECK-NEXT:    [[E2:%.*]] = load i16, ptr [[TMP3]], align 2
+; CHECK-NEXT:    [[TMP4:%.*]] = extractelement <2 x i16> [[V]], i32 [[IDX]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ule i16 [[E1]], [[E2]]
+; CHECK-NEXT:    ret i1 [[CMP]]
 ;
-  %idx = and i32 %idx.base, 1
-  %v = load <2 x i32>, ptr %p
-  %e1 = extractelement <2 x i32> %v, i32 %idx
-  %e2 = extractelement <2 x i32> %v, i32 %idx
-  ret void
+entry:
+  %v = load <2 x i16>, ptr null, align 4
+  %idx = and i32 %base, 0
+  %e1 = extractelement <2 x i16> %v, i32 %idx
+  %e2 = extractelement <2 x i16> %v, i32 %idx
+  %cmp = icmp ule i16 %e1, %e2
+  ret i1 %cmp
 }
 
-; Check that we do not use an uninitialized pointer when the index doesn't match and/urem
-; but is naturally in bounds.
-define void @test_uninitialized_base(ptr %p, i1 %idx) {
-; CHECK-LABEL: @test_uninitialized_base(
-; CHECK-NEXT:    [[V:%.*]] = load <2 x i32>, ptr [[P:%.*]], align 8
-; CHECK-NEXT:    [[E:%.*]] = extractelement <2 x i32> [[V]], i1 [[IDX:%.*]]
-; CHECK-NEXT:    ret void
-;
-  %v = load <2 x i32>, ptr %p
-  %e = extractelement <2 x i32> %v, i1 %idx
-  ret void
-}
+



More information about the llvm-commits mailing list