[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:53:38 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/3] [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/3] 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
-}
+
>From e61ab84390921d8f6bebcf590ca0c3a221564439 Mon Sep 17 00:00:00 2001
From: AdityaOP007 <adityaprakashjha321 at gmail.com>
Date: Sun, 2 Aug 2026 00:23:25 +0530
Subject: [PATCH 3/3] [VectorCombine] Use dyn_cast for index lookup
---
llvm/lib/Transforms/Vectorize/VectorCombine.cpp | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index 4a0ef49c089f7..3d54b052ae98a 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -2141,10 +2141,12 @@ bool VectorCombine::scalarizeLoadExtract(LoadInst *LI, VectorType *VecTy,
Value *Idx = EI->getIndexOperand();
// Insert 'freeze' for poison indexes.
- auto It = NeedFreeze.find(cast<Instruction>(Idx));
- if (It != NeedFreeze.end()) {
- It->second.freeze(Builder, *cast<Instruction>(Idx));
- NeedFreeze.erase(It);
+ if (auto *IdxInst = dyn_cast<Instruction>(Idx)) {
+ auto It = NeedFreeze.find(IdxInst);
+ if (It != NeedFreeze.end()) {
+ It->second.freeze(Builder, *IdxInst);
+ NeedFreeze.erase(It);
+ }
}
Builder.SetInsertPoint(EI);
More information about the llvm-commits
mailing list