[llvm] [SROA] Improve select folding around casts (PR #222466)
Daniel Donenfeld via llvm-commits
llvm-commits at lists.llvm.org
Fri Sep 18 11:59:12 PDT 2026
https://github.com/daniel-donenfeld updated https://github.com/llvm/llvm-project/pull/222466
>From fe667c391fc70d8b4a347330b49e41edd479c0d8 Mon Sep 17 00:00:00 2001
From: Daniel Donenfeld <ddonenfeld at nvidia.com>
Date: Tue, 15 Sep 2026 20:06:54 +0000
Subject: [PATCH 1/3] [SROA] Add tests for select folding
Generate checks using SROA behavior before extending select folding.
---
.../test/Transforms/SROA/select-fold-split.ll | 197 ++++++++++++++++++
.../SROA/select-speculate-addrspace.ll | 25 +++
2 files changed, 222 insertions(+)
create mode 100644 llvm/test/Transforms/SROA/select-fold-split.ll
create mode 100644 llvm/test/Transforms/SROA/select-speculate-addrspace.ll
diff --git a/llvm/test/Transforms/SROA/select-fold-split.ll b/llvm/test/Transforms/SROA/select-fold-split.ll
new file mode 100644
index 0000000000000..7cde71c8a5a3d
--- /dev/null
+++ b/llvm/test/Transforms/SROA/select-fold-split.ll
@@ -0,0 +1,197 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -passes='sroa<modify-cfg>' -S < %s | FileCheck %s
+
+%struct.T = type { i32, i32 }
+
+define i32 @test_select_fold_split(i1 %cond) {
+; CHECK-LABEL: define i32 @test_select_fold_split(
+; CHECK-SAME: i1 [[COND:%.*]]) {
+; CHECK-NEXT: [[VAL_SROA_SPECULATED:%.*]] = select i1 [[COND]], i32 1, i32 3
+; CHECK-NEXT: ret i32 [[VAL_SROA_SPECULATED]]
+;
+ %alloc0 = alloca %struct.T, align 8
+ %alloc1 = alloca %struct.T, align 8
+ store %struct.T { i32 0, i32 1 }, ptr %alloc0
+ store %struct.T { i32 2, i32 3 }, ptr %alloc1
+ %sel = select i1 %cond, ptr %alloc0, ptr %alloc1
+ %gep = getelementptr inbounds %struct.T, ptr %sel, i32 0, i32 1
+ %val = load i32, ptr %gep
+ ret i32 %val
+}
+
+define i32 @test_select_fold_split_zero(i1 %cond) {
+; CHECK-LABEL: define i32 @test_select_fold_split_zero(
+; CHECK-SAME: i1 [[COND:%.*]]) {
+; CHECK-NEXT: [[VAL_SROA_SPECULATED:%.*]] = select i1 [[COND]], i32 0, i32 2
+; CHECK-NEXT: ret i32 [[VAL_SROA_SPECULATED]]
+;
+ %alloc0 = alloca %struct.T, align 8
+ %alloc1 = alloca %struct.T, align 8
+ store %struct.T { i32 0, i32 1 }, ptr %alloc0
+ store %struct.T { i32 2, i32 3 }, ptr %alloc1
+ %sel = select i1 %cond, ptr %alloc0, ptr %alloc1
+ %gep = getelementptr inbounds %struct.T, ptr %sel, i32 0, i32 0
+ %val = load i32, ptr %gep
+ ret i32 %val
+}
+
+define i32 @test_select_fold_split_var_gep(i1 %cond, i32 %v) {
+; CHECK-LABEL: define i32 @test_select_fold_split_var_gep(
+; CHECK-SAME: i1 [[COND:%.*]], i32 [[V:%.*]]) {
+; CHECK-NEXT: [[ALLOC0:%.*]] = alloca [[STRUCT_T:%.*]], align 8
+; CHECK-NEXT: [[ALLOC1:%.*]] = alloca [[STRUCT_T]], align 8
+; CHECK-NEXT: [[DOTFCA_0_GEP1:%.*]] = getelementptr inbounds [[STRUCT_T]], ptr [[ALLOC0]], i32 0, i32 0
+; CHECK-NEXT: store i32 0, ptr [[DOTFCA_0_GEP1]], align 4
+; CHECK-NEXT: [[DOTFCA_1_GEP2:%.*]] = getelementptr inbounds [[STRUCT_T]], ptr [[ALLOC0]], i32 0, i32 1
+; CHECK-NEXT: store i32 1, ptr [[DOTFCA_1_GEP2]], align 4
+; CHECK-NEXT: [[DOTFCA_0_GEP:%.*]] = getelementptr inbounds [[STRUCT_T]], ptr [[ALLOC1]], i32 0, i32 0
+; CHECK-NEXT: store i32 2, ptr [[DOTFCA_0_GEP]], align 4
+; CHECK-NEXT: [[DOTFCA_1_GEP:%.*]] = getelementptr inbounds [[STRUCT_T]], ptr [[ALLOC1]], i32 0, i32 1
+; CHECK-NEXT: store i32 3, ptr [[DOTFCA_1_GEP]], align 4
+; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND]], ptr [[ALLOC0]], ptr [[ALLOC1]]
+; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds [[STRUCT_T]], ptr [[SEL]], i32 [[V]], i32 1
+; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[GEP]], align 4
+; CHECK-NEXT: ret i32 [[VAL]]
+;
+ %alloc0 = alloca %struct.T, align 8
+ %alloc1 = alloca %struct.T, align 8
+ store %struct.T { i32 0, i32 1 }, ptr %alloc0
+ store %struct.T { i32 2, i32 3 }, ptr %alloc1
+ %sel = select i1 %cond, ptr %alloc0, ptr %alloc1
+ %gep = getelementptr inbounds %struct.T, ptr %sel, i32 %v, i32 1
+ %val = load i32, ptr %gep
+ ret i32 %val
+}
+
+define i32 @test_select_fold_split_addrspace(i1 %cond) {
+; CHECK-LABEL: define i32 @test_select_fold_split_addrspace(
+; CHECK-SAME: i1 [[COND:%.*]]) {
+; CHECK-NEXT: [[VAL:%.*]] = select i1 [[COND]], i32 1, i32 3
+; CHECK-NEXT: ret i32 [[VAL]]
+;
+ %alloc0 = alloca %struct.T, align 16
+ %alloc1 = alloca %struct.T, align 16
+ store %struct.T { i32 0, i32 1 }, ptr %alloc0
+ store %struct.T { i32 2, i32 3 }, ptr %alloc1
+ %sel = select i1 %cond, ptr %alloc0, ptr %alloc1
+ %cast = addrspacecast ptr %sel to ptr addrspace(5)
+ %gep = getelementptr inbounds %struct.T, ptr addrspace(5) %cast, i32 0, i32 1
+ %val = load i32, ptr addrspace(5) %gep
+ ret i32 %val
+}
+
+define i32 @test_select_fold_split_multiple_users_same(i1 %cond) {
+; CHECK-LABEL: define i32 @test_select_fold_split_multiple_users_same(
+; CHECK-SAME: i1 [[COND:%.*]]) {
+; CHECK-NEXT: [[VAL0_SROA_SPECULATED:%.*]] = select i1 [[COND]], i32 0, i32 2
+; CHECK-NEXT: [[VAL1_SROA_SPECULATED:%.*]] = select i1 [[COND]], i32 0, i32 2
+; CHECK-NEXT: [[VAL:%.*]] = add i32 [[VAL0_SROA_SPECULATED]], [[VAL1_SROA_SPECULATED]]
+; CHECK-NEXT: ret i32 [[VAL]]
+;
+ %alloc0 = alloca %struct.T, align 8
+ %alloc1 = alloca %struct.T, align 8
+ store %struct.T { i32 0, i32 1 }, ptr %alloc0
+ store %struct.T { i32 2, i32 3 }, ptr %alloc1
+ %sel = select i1 %cond, ptr %alloc0, ptr %alloc1
+ %gep0 = getelementptr inbounds %struct.T, ptr %sel, i32 0, i32 0
+ %gep1 = getelementptr inbounds %struct.T, ptr %sel, i32 0, i32 0
+ %val0 = load i32, ptr %gep0
+ %val1 = load i32, ptr %gep1
+ %val = add i32 %val0, %val1
+ ret i32 %val
+}
+
+define i32 @test_select_fold_split_multiple_users_different(i1 %cond) {
+; CHECK-LABEL: define i32 @test_select_fold_split_multiple_users_different(
+; CHECK-SAME: i1 [[COND:%.*]]) {
+; CHECK-NEXT: [[VAL0_SROA_SPECULATED:%.*]] = select i1 [[COND]], i32 0, i32 2
+; CHECK-NEXT: [[VAL1_SROA_SPECULATED:%.*]] = select i1 [[COND]], i32 1, i32 3
+; CHECK-NEXT: [[VAL:%.*]] = add i32 [[VAL0_SROA_SPECULATED]], [[VAL1_SROA_SPECULATED]]
+; CHECK-NEXT: ret i32 [[VAL]]
+;
+ %alloc0 = alloca %struct.T, align 8
+ %alloc1 = alloca %struct.T, align 8
+ store %struct.T { i32 0, i32 1 }, ptr %alloc0
+ store %struct.T { i32 2, i32 3 }, ptr %alloc1
+ %sel = select i1 %cond, ptr %alloc0, ptr %alloc1
+ %gep0 = getelementptr inbounds %struct.T, ptr %sel, i32 0, i32 0
+ %gep1 = getelementptr inbounds %struct.T, ptr %sel, i32 0, i32 1
+ %val0 = load i32, ptr %gep0
+ %val1 = load i32, ptr %gep1
+ %val = add i32 %val0, %val1
+ ret i32 %val
+}
+
+define i32 @test_select_fold_split_gep_chain(i1 %cond) {
+; CHECK-LABEL: define i32 @test_select_fold_split_gep_chain(
+; CHECK-SAME: i1 [[COND:%.*]]) {
+; CHECK-NEXT: [[VAL_SROA_SPECULATED:%.*]] = select i1 [[COND]], i32 2, i32 5
+; CHECK-NEXT: ret i32 [[VAL_SROA_SPECULATED]]
+;
+ %alloc0 = alloca [3 x i32], align 8
+ %alloc1 = alloca [3 x i32], align 8
+ store [3 x i32] [i32 0, i32 1, i32 2], ptr %alloc0
+ store [3 x i32] [i32 3, i32 4, i32 5], ptr %alloc1
+ %sel = select i1 %cond, ptr %alloc0, ptr %alloc1
+ %gep0 = getelementptr i32, ptr %sel, i32 0
+ %gep1 = getelementptr i32, ptr %gep0, i32 1
+ %gep2 = getelementptr i32, ptr %gep1, i32 1
+ %val = load i32, ptr %gep2
+ ret i32 %val
+}
+
+define i32 @test_select_fold_split_zero_gep(i1 %cond) {
+; CHECK-LABEL: define i32 @test_select_fold_split_zero_gep(
+; CHECK-SAME: i1 [[COND:%.*]]) {
+; CHECK-NEXT: [[VAL_SROA_SPECULATED:%.*]] = select i1 [[COND]], i32 1, i32 3
+; CHECK-NEXT: ret i32 [[VAL_SROA_SPECULATED]]
+;
+ %alloc0 = alloca %struct.T, align 8
+ %alloc1 = alloca %struct.T, align 8
+ store %struct.T { i32 0, i32 1 }, ptr %alloc0
+ store %struct.T { i32 2, i32 3 }, ptr %alloc1
+ %sel = select i1 %cond, ptr %alloc0, ptr %alloc1
+ %gep0 = getelementptr %struct.T, ptr %sel, i32 0
+ %gep1 = getelementptr inbounds %struct.T, ptr %gep0, i32 0, i32 1
+ %val = load i32, ptr %gep1
+ ret i32 %val
+}
+
+
+
+; Check for correct addrspacecast insertion for loads.
+define i32 @test_select_fold_split_volatile(i1 %cond) {
+; CHECK-LABEL: define i32 @test_select_fold_split_volatile(
+; CHECK-SAME: i1 [[COND:%.*]]) {
+; CHECK-NEXT: [[ALLOC0_SROA_0:%.*]] = alloca i32, align 8
+; CHECK-NEXT: [[DOTFCA_1_GEP2:%.*]] = alloca i32, align 4
+; CHECK-NEXT: [[SEL:%.*]] = alloca i32, align 8
+; CHECK-NEXT: [[DOTFCA_1_GEP:%.*]] = alloca i32, align 4
+; CHECK-NEXT: store i32 0, ptr [[ALLOC0_SROA_0]], align 8
+; CHECK-NEXT: store i32 1, ptr [[DOTFCA_1_GEP2]], align 4
+; CHECK-NEXT: store i32 2, ptr [[SEL]], align 8
+; CHECK-NEXT: store i32 3, ptr [[DOTFCA_1_GEP]], align 4
+; CHECK-NEXT: [[CAST:%.*]] = addrspacecast ptr [[SEL]] to ptr addrspace(5)
+; CHECK-NEXT: [[ALLOC0_SROA_0_0_GEP_SROA_CAST7:%.*]] = addrspacecast ptr [[ALLOC0_SROA_0]] to ptr addrspace(5)
+; CHECK-NEXT: [[GEP0:%.*]] = select i1 [[COND]], ptr addrspace(5) [[ALLOC0_SROA_0_0_GEP_SROA_CAST7]], ptr addrspace(5) [[CAST]]
+; CHECK-NEXT: [[ALLOC1_SROA_2_0_GEP4_SROA_CAST:%.*]] = addrspacecast ptr [[DOTFCA_1_GEP]] to ptr addrspace(5)
+; CHECK-NEXT: [[ALLOC0_SROA_2_0_GEP3_SROA_CAST:%.*]] = addrspacecast ptr [[DOTFCA_1_GEP2]] to ptr addrspace(5)
+; CHECK-NEXT: [[GEP1:%.*]] = select i1 [[COND]], ptr addrspace(5) [[ALLOC0_SROA_2_0_GEP3_SROA_CAST]], ptr addrspace(5) [[ALLOC1_SROA_2_0_GEP4_SROA_CAST]]
+; CHECK-NEXT: [[VAL1:%.*]] = load volatile i32, ptr addrspace(5) [[GEP0]], align 4
+; CHECK-NEXT: [[VAL2:%.*]] = load volatile i32, ptr addrspace(5) [[GEP1]], align 4
+; CHECK-NEXT: [[VAL3:%.*]] = add i32 [[VAL1]], [[VAL2]]
+; CHECK-NEXT: ret i32 [[VAL3]]
+;
+ %alloc0 = alloca %struct.T, align 8
+ %alloc1 = alloca %struct.T, align 8
+ store %struct.T { i32 0, i32 1 }, ptr %alloc0
+ store %struct.T { i32 2, i32 3 }, ptr %alloc1
+ %sel = select i1 %cond, ptr %alloc0, ptr %alloc1
+ %cast = addrspacecast ptr %sel to ptr addrspace(5)
+ %gep0 = getelementptr inbounds %struct.T, ptr addrspace(5) %cast, i32 0, i32 0
+ %gep1 = getelementptr inbounds %struct.T, ptr addrspace(5) %cast, i32 0, i32 1
+ %val1 = load volatile i32, ptr addrspace(5) %gep0
+ %val2 = load volatile i32, ptr addrspace(5) %gep1
+ %val3 = add i32 %val1, %val2
+ ret i32 %val3
+}
diff --git a/llvm/test/Transforms/SROA/select-speculate-addrspace.ll b/llvm/test/Transforms/SROA/select-speculate-addrspace.ll
new file mode 100644
index 0000000000000..e976a158c55a0
--- /dev/null
+++ b/llvm/test/Transforms/SROA/select-speculate-addrspace.ll
@@ -0,0 +1,25 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -passes='sroa<modify-cfg>' -S < %s | FileCheck %s
+
+; Verify that a select of pointers in a non-default address space can be
+; speculated after SROA rewrites one arm to the default address space.
+define i32 @select_speculate_addrspace(i1 %cond) {
+; CHECK-LABEL: define i32 @select_speculate_addrspace(
+; CHECK-SAME: i1 [[COND:%.*]]) {
+; CHECK-NEXT: [[ALLOCA:%.*]] = alloca i32, align 4
+; CHECK-NEXT: [[CAST:%.*]] = addrspacecast ptr [[ALLOCA]] to ptr addrspace(5)
+; CHECK-NEXT: store volatile i32 1, ptr addrspace(5) [[CAST]], align 4
+; CHECK-NEXT: [[LOAD:%.*]] = load i32, ptr [[ALLOCA]], align 4
+; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], i32 [[LOAD]], i32 2
+; CHECK-NEXT: ret i32 [[SELECT]]
+;
+ %alloc0 = alloca i32, align 4
+ %alloc1 = alloca i32, align 4
+ %cast0 = addrspacecast ptr %alloc0 to ptr addrspace(5)
+ %cast1 = addrspacecast ptr %alloc1 to ptr addrspace(5)
+ store volatile i32 1, ptr addrspace(5) %cast0
+ store i32 2, ptr addrspace(5) %cast1
+ %sel = select i1 %cond, ptr addrspace(5) %cast0, ptr addrspace(5) %cast1
+ %val = load i32, ptr addrspace(5) %sel
+ ret i32 %val
+}
>From 3a8e22071aa2d0ef01213279eee57d0c0ce4293e Mon Sep 17 00:00:00 2001
From: Daniel Donenfeld <ddonenfeld at nvidia.com>
Date: Tue, 15 Sep 2026 20:07:14 +0000
Subject: [PATCH 2/3] [SROA] Extend select folding
---
llvm/lib/Transforms/Scalar/SROA.cpp | 51 +++++++++++++++++++++++++----
1 file changed, 45 insertions(+), 6 deletions(-)
diff --git a/llvm/lib/Transforms/Scalar/SROA.cpp b/llvm/lib/Transforms/Scalar/SROA.cpp
index 28466a8de286e..1f266a6121953 100644
--- a/llvm/lib/Transforms/Scalar/SROA.cpp
+++ b/llvm/lib/Transforms/Scalar/SROA.cpp
@@ -1777,6 +1777,12 @@ static void speculateSelectInstLoads(SelectInst &SI, LoadInst &LI,
IRB.SetInsertPoint(&LI);
+ // AddrSpace casts may separate load from select in the initial code.
+ TV = IRB.CreateAddrSpaceCast(TV, LI.getPointerOperandType(),
+ LI.getName() + ".sroa.speculate.cast.true");
+ FV = IRB.CreateAddrSpaceCast(FV, LI.getPointerOperandType(),
+ LI.getName() + ".sroa.speculate.cast.false");
+
LoadInst *TL =
IRB.CreateAlignedLoad(LI.getType(), TV, LI.getAlign(),
LI.getName() + ".sroa.speculate.load.true");
@@ -1911,8 +1917,7 @@ static Value *getAdjustedPtr(IRBuilderTy &IRB, const DataLayout &DL, Value *Ptr,
if (Offset != 0)
Ptr = IRB.CreateInBoundsPtrAdd(Ptr, IRB.getInt(Offset),
NamePrefix + "sroa_idx");
- return IRB.CreatePointerBitCastOrAddrSpaceCast(Ptr, PointerTy,
- NamePrefix + "sroa_cast");
+ return IRB.CreateAddrSpaceCast(Ptr, PointerTy, NamePrefix + "sroa_cast");
}
/// Compute the adjusted alignment for a load or store from an offset.
@@ -4442,6 +4447,29 @@ class AggLoadStoreRewriter : public InstVisitor<AggLoadStoreRewriter, bool> {
return false;
}
+ void removeIntermediateCasts(GetElementPtrInst &GEPI, Instruction *End) {
+ // Remove dead intermediate casts between two instructions.
+ Value *V = GEPI.getPointerOperand();
+ while (V != End && (V->use_empty() ||
+ (V->hasOneUse() && V == GEPI.getPointerOperand()))) {
+ Value *OldV = V;
+ if (auto *GEP = dyn_cast<GEPOperator>(V)) {
+ if (!GEP->hasAllZeroIndices())
+ break;
+ V = GEP->getPointerOperand();
+ } else if (Operator::getOpcode(V) == Instruction::AddrSpaceCast) {
+ V = cast<Operator>(V)->getOperand(0);
+ } else {
+ break;
+ }
+
+ Instruction *I = cast<Instruction>(OldV);
+ I->replaceAllUsesWith(PoisonValue::get(I->getType()));
+ Visited.erase(I);
+ I->eraseFromParent();
+ }
+ }
+
// Unfold gep (select cond, ptr1, ptr2), idx
// => select cond, gep(ptr1, idx), gep(ptr2, idx)
// and gep ptr, (select cond, idx1, idx2)
@@ -4450,7 +4478,8 @@ class AggLoadStoreRewriter : public InstVisitor<AggLoadStoreRewriter, bool> {
bool unfoldGEPSelect(GetElementPtrInst &GEPI) {
// Check whether the GEP has exactly one select operand and all indices
// will become constant after the transform.
- Instruction *Sel = dyn_cast<SelectInst>(GEPI.getPointerOperand());
+ Instruction *Sel =
+ dyn_cast<SelectInst>(GEPI.getPointerOperand()->stripPointerCasts());
for (Value *Op : GEPI.indices()) {
if (auto *SI = dyn_cast<SelectInst>(Op)) {
if (Sel)
@@ -4485,7 +4514,8 @@ class AggLoadStoreRewriter : public InstVisitor<AggLoadStoreRewriter, bool> {
auto GetNewOps = [&](Value *SelOp) {
SmallVector<Value *> NewOps;
for (Value *Op : GEPI.operands())
- if (Op == Sel)
+ if ((Op == Sel) ||
+ (Op == GEPI.getPointerOperand() && Op->stripPointerCasts() == Sel))
NewOps.push_back(SelOp);
else
NewOps.push_back(Op);
@@ -4511,12 +4541,19 @@ class AggLoadStoreRewriter : public InstVisitor<AggLoadStoreRewriter, bool> {
IRB.SetInsertPoint(&GEPI);
GEPNoWrapFlags NW = GEPI.getNoWrapFlags();
+ auto *NTruePtr = TrueOps[0];
+ NTruePtr = IRB.CreateAddrSpaceCast(NTruePtr, GEPI.getPointerOperandType(),
+ NTruePtr->getName() + ".cast");
+ auto *NFalsePtr = FalseOps[0];
+ NFalsePtr = IRB.CreateAddrSpaceCast(NFalsePtr, GEPI.getPointerOperandType(),
+ NFalsePtr->getName() + ".cast");
+
Type *Ty = GEPI.getSourceElementType();
- Value *NTrue = IRB.CreateGEP(Ty, TrueOps[0], ArrayRef(TrueOps).drop_front(),
+ Value *NTrue = IRB.CreateGEP(Ty, NTruePtr, ArrayRef(TrueOps).drop_front(),
True->getName() + ".sroa.gep", NW);
Value *NFalse =
- IRB.CreateGEP(Ty, FalseOps[0], ArrayRef(FalseOps).drop_front(),
+ IRB.CreateGEP(Ty, NFalsePtr, ArrayRef(FalseOps).drop_front(),
False->getName() + ".sroa.gep", NW);
Value *NSel = MDFrom
@@ -4525,6 +4562,8 @@ class AggLoadStoreRewriter : public InstVisitor<AggLoadStoreRewriter, bool> {
: IRB.CreateSelectWithUnknownProfile(
Cond, NTrue, NFalse, DEBUG_TYPE,
Sel->getName() + ".sroa.sel");
+
+ removeIntermediateCasts(GEPI, Sel);
Visited.erase(&GEPI);
GEPI.replaceAllUsesWith(NSel);
GEPI.eraseFromParent();
>From c3b06846336ae09b884dcef183107c9eea4e5655 Mon Sep 17 00:00:00 2001
From: Daniel Donenfeld <ddonenfeld at nvidia.com>
Date: Fri, 18 Sep 2026 18:03:45 +0000
Subject: [PATCH 3/3] Address PR feedback
---
llvm/lib/Transforms/Scalar/SROA.cpp | 54 +----
llvm/test/Transforms/SROA/phi-and-select.ll | 29 ---
.../test/Transforms/SROA/select-fold-split.ll | 197 ----------------
.../Transforms/SROA/select-gep-addrspace.ll | 31 +++
llvm/test/Transforms/SROA/select-gep.ll | 223 +++++++++++++++++-
llvm/test/Transforms/SROA/select-load.ll | 52 ++++
.../SROA/select-speculate-addrspace.ll | 25 --
7 files changed, 311 insertions(+), 300 deletions(-)
delete mode 100644 llvm/test/Transforms/SROA/select-fold-split.ll
create mode 100644 llvm/test/Transforms/SROA/select-gep-addrspace.ll
delete mode 100644 llvm/test/Transforms/SROA/select-speculate-addrspace.ll
diff --git a/llvm/lib/Transforms/Scalar/SROA.cpp b/llvm/lib/Transforms/Scalar/SROA.cpp
index 1f266a6121953..8f526d0cc5e27 100644
--- a/llvm/lib/Transforms/Scalar/SROA.cpp
+++ b/llvm/lib/Transforms/Scalar/SROA.cpp
@@ -1777,12 +1777,6 @@ static void speculateSelectInstLoads(SelectInst &SI, LoadInst &LI,
IRB.SetInsertPoint(&LI);
- // AddrSpace casts may separate load from select in the initial code.
- TV = IRB.CreateAddrSpaceCast(TV, LI.getPointerOperandType(),
- LI.getName() + ".sroa.speculate.cast.true");
- FV = IRB.CreateAddrSpaceCast(FV, LI.getPointerOperandType(),
- LI.getName() + ".sroa.speculate.cast.false");
-
LoadInst *TL =
IRB.CreateAlignedLoad(LI.getType(), TV, LI.getAlign(),
LI.getName() + ".sroa.speculate.load.true");
@@ -1917,7 +1911,8 @@ static Value *getAdjustedPtr(IRBuilderTy &IRB, const DataLayout &DL, Value *Ptr,
if (Offset != 0)
Ptr = IRB.CreateInBoundsPtrAdd(Ptr, IRB.getInt(Offset),
NamePrefix + "sroa_idx");
- return IRB.CreateAddrSpaceCast(Ptr, PointerTy, NamePrefix + "sroa_cast");
+ return IRB.CreatePointerBitCastOrAddrSpaceCast(Ptr, PointerTy,
+ NamePrefix + "sroa_cast");
}
/// Compute the adjusted alignment for a load or store from an offset.
@@ -4447,29 +4442,6 @@ class AggLoadStoreRewriter : public InstVisitor<AggLoadStoreRewriter, bool> {
return false;
}
- void removeIntermediateCasts(GetElementPtrInst &GEPI, Instruction *End) {
- // Remove dead intermediate casts between two instructions.
- Value *V = GEPI.getPointerOperand();
- while (V != End && (V->use_empty() ||
- (V->hasOneUse() && V == GEPI.getPointerOperand()))) {
- Value *OldV = V;
- if (auto *GEP = dyn_cast<GEPOperator>(V)) {
- if (!GEP->hasAllZeroIndices())
- break;
- V = GEP->getPointerOperand();
- } else if (Operator::getOpcode(V) == Instruction::AddrSpaceCast) {
- V = cast<Operator>(V)->getOperand(0);
- } else {
- break;
- }
-
- Instruction *I = cast<Instruction>(OldV);
- I->replaceAllUsesWith(PoisonValue::get(I->getType()));
- Visited.erase(I);
- I->eraseFromParent();
- }
- }
-
// Unfold gep (select cond, ptr1, ptr2), idx
// => select cond, gep(ptr1, idx), gep(ptr2, idx)
// and gep ptr, (select cond, idx1, idx2)
@@ -4480,12 +4452,14 @@ class AggLoadStoreRewriter : public InstVisitor<AggLoadStoreRewriter, bool> {
// will become constant after the transform.
Instruction *Sel =
dyn_cast<SelectInst>(GEPI.getPointerOperand()->stripPointerCasts());
- for (Value *Op : GEPI.indices()) {
+ unsigned SelOpNum = 0;
+ for (auto& Op : GEPI.indices()) {
if (auto *SI = dyn_cast<SelectInst>(Op)) {
if (Sel)
return false;
Sel = SI;
+ SelOpNum = Op.getOperandNo();
if (!isa<ConstantInt>(SI->getTrueValue()) ||
!isa<ConstantInt>(SI->getFalseValue()))
return false;
@@ -4495,6 +4469,7 @@ class AggLoadStoreRewriter : public InstVisitor<AggLoadStoreRewriter, bool> {
if (Sel)
return false;
Sel = ZI;
+ SelOpNum = Op.getOperandNo();
if (!ZI->getSrcTy()->isIntegerTy(1))
return false;
continue;
@@ -4512,13 +4487,8 @@ class AggLoadStoreRewriter : public InstVisitor<AggLoadStoreRewriter, bool> {
dbgs() << " " << GEPI << "\n";);
auto GetNewOps = [&](Value *SelOp) {
- SmallVector<Value *> NewOps;
- for (Value *Op : GEPI.operands())
- if ((Op == Sel) ||
- (Op == GEPI.getPointerOperand() && Op->stripPointerCasts() == Sel))
- NewOps.push_back(SelOp);
- else
- NewOps.push_back(Op);
+ SmallVector<Value *> NewOps(GEPI.operands());
+ NewOps[SelOpNum] = SelOp;
return NewOps;
};
@@ -4562,11 +4532,13 @@ class AggLoadStoreRewriter : public InstVisitor<AggLoadStoreRewriter, bool> {
: IRB.CreateSelectWithUnknownProfile(
Cond, NTrue, NFalse, DEBUG_TYPE,
Sel->getName() + ".sroa.sel");
-
- removeIntermediateCasts(GEPI, Sel);
Visited.erase(&GEPI);
GEPI.replaceAllUsesWith(NSel);
- GEPI.eraseFromParent();
+ RecursivelyDeleteTriviallyDeadInstructions(
+ &GEPI, nullptr, nullptr, [&](Value *V) {
+ if (auto *I = dyn_cast<Instruction>(V))
+ Visited.erase(I);
+ });
Instruction *NSelI = cast<Instruction>(NSel);
Visited.insert(NSelI);
enqueueUsers(*NSelI);
diff --git a/llvm/test/Transforms/SROA/phi-and-select.ll b/llvm/test/Transforms/SROA/phi-and-select.ll
index 5d5a61082688f..2f438a1373b41 100644
--- a/llvm/test/Transforms/SROA/phi-and-select.ll
+++ b/llvm/test/Transforms/SROA/phi-and-select.ll
@@ -81,35 +81,6 @@ entry:
ret float %result
}
-define i32 @test2_addrspacecast() {
-; CHECK-LABEL: @test2_addrspacecast(
-; CHECK-NEXT: entry:
-; CHECK-NEXT: [[A_SROA_0:%.*]] = alloca i32, align 4
-; CHECK-NEXT: [[A_SROA_3:%.*]] = alloca i32, align 4
-; CHECK-NEXT: store i32 0, ptr [[A_SROA_0]], align 4
-; CHECK-NEXT: store i32 1, ptr [[A_SROA_3]], align 4
-; CHECK-NEXT: [[A_SROA_0_0_A_SROA_0_0_V0:%.*]] = load i32, ptr [[A_SROA_0]], align 4
-; CHECK-NEXT: [[A_SROA_3_0_A_SROA_3_4_V1:%.*]] = load i32, ptr [[A_SROA_3]], align 4
-; CHECK-NEXT: [[COND:%.*]] = icmp sle i32 [[A_SROA_0_0_A_SROA_0_0_V0]], [[A_SROA_3_0_A_SROA_3_4_V1]]
-; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], ptr [[A_SROA_3]], ptr [[A_SROA_0]]
-; CHECK-NEXT: [[SELECT_ASC:%.*]] = addrspacecast ptr [[SELECT]] to ptr addrspace(1)
-; CHECK-NEXT: [[RESULT:%.*]] = load i32, ptr addrspace(1) [[SELECT_ASC]], align 4
-; CHECK-NEXT: ret i32 [[RESULT]]
-;
-entry:
- %a = alloca [2 x i32]
- %a1 = getelementptr [2 x i32], ptr %a, i64 0, i32 1
- store i32 0, ptr %a
- store i32 1, ptr %a1
- %v0 = load i32, ptr %a
- %v1 = load i32, ptr %a1
- %cond = icmp sle i32 %v0, %v1
- %select = select i1 %cond, ptr %a1, ptr %a
- %select.asc = addrspacecast ptr %select to ptr addrspace(1)
- %result = load i32, ptr addrspace(1) %select.asc
- ret i32 %result
-}
-
define i32 @test3(i32 %x) {
; CHECK-LABEL: @test3(
; CHECK-NEXT: entry:
diff --git a/llvm/test/Transforms/SROA/select-fold-split.ll b/llvm/test/Transforms/SROA/select-fold-split.ll
deleted file mode 100644
index 7cde71c8a5a3d..0000000000000
--- a/llvm/test/Transforms/SROA/select-fold-split.ll
+++ /dev/null
@@ -1,197 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
-; RUN: opt -passes='sroa<modify-cfg>' -S < %s | FileCheck %s
-
-%struct.T = type { i32, i32 }
-
-define i32 @test_select_fold_split(i1 %cond) {
-; CHECK-LABEL: define i32 @test_select_fold_split(
-; CHECK-SAME: i1 [[COND:%.*]]) {
-; CHECK-NEXT: [[VAL_SROA_SPECULATED:%.*]] = select i1 [[COND]], i32 1, i32 3
-; CHECK-NEXT: ret i32 [[VAL_SROA_SPECULATED]]
-;
- %alloc0 = alloca %struct.T, align 8
- %alloc1 = alloca %struct.T, align 8
- store %struct.T { i32 0, i32 1 }, ptr %alloc0
- store %struct.T { i32 2, i32 3 }, ptr %alloc1
- %sel = select i1 %cond, ptr %alloc0, ptr %alloc1
- %gep = getelementptr inbounds %struct.T, ptr %sel, i32 0, i32 1
- %val = load i32, ptr %gep
- ret i32 %val
-}
-
-define i32 @test_select_fold_split_zero(i1 %cond) {
-; CHECK-LABEL: define i32 @test_select_fold_split_zero(
-; CHECK-SAME: i1 [[COND:%.*]]) {
-; CHECK-NEXT: [[VAL_SROA_SPECULATED:%.*]] = select i1 [[COND]], i32 0, i32 2
-; CHECK-NEXT: ret i32 [[VAL_SROA_SPECULATED]]
-;
- %alloc0 = alloca %struct.T, align 8
- %alloc1 = alloca %struct.T, align 8
- store %struct.T { i32 0, i32 1 }, ptr %alloc0
- store %struct.T { i32 2, i32 3 }, ptr %alloc1
- %sel = select i1 %cond, ptr %alloc0, ptr %alloc1
- %gep = getelementptr inbounds %struct.T, ptr %sel, i32 0, i32 0
- %val = load i32, ptr %gep
- ret i32 %val
-}
-
-define i32 @test_select_fold_split_var_gep(i1 %cond, i32 %v) {
-; CHECK-LABEL: define i32 @test_select_fold_split_var_gep(
-; CHECK-SAME: i1 [[COND:%.*]], i32 [[V:%.*]]) {
-; CHECK-NEXT: [[ALLOC0:%.*]] = alloca [[STRUCT_T:%.*]], align 8
-; CHECK-NEXT: [[ALLOC1:%.*]] = alloca [[STRUCT_T]], align 8
-; CHECK-NEXT: [[DOTFCA_0_GEP1:%.*]] = getelementptr inbounds [[STRUCT_T]], ptr [[ALLOC0]], i32 0, i32 0
-; CHECK-NEXT: store i32 0, ptr [[DOTFCA_0_GEP1]], align 4
-; CHECK-NEXT: [[DOTFCA_1_GEP2:%.*]] = getelementptr inbounds [[STRUCT_T]], ptr [[ALLOC0]], i32 0, i32 1
-; CHECK-NEXT: store i32 1, ptr [[DOTFCA_1_GEP2]], align 4
-; CHECK-NEXT: [[DOTFCA_0_GEP:%.*]] = getelementptr inbounds [[STRUCT_T]], ptr [[ALLOC1]], i32 0, i32 0
-; CHECK-NEXT: store i32 2, ptr [[DOTFCA_0_GEP]], align 4
-; CHECK-NEXT: [[DOTFCA_1_GEP:%.*]] = getelementptr inbounds [[STRUCT_T]], ptr [[ALLOC1]], i32 0, i32 1
-; CHECK-NEXT: store i32 3, ptr [[DOTFCA_1_GEP]], align 4
-; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND]], ptr [[ALLOC0]], ptr [[ALLOC1]]
-; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds [[STRUCT_T]], ptr [[SEL]], i32 [[V]], i32 1
-; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[GEP]], align 4
-; CHECK-NEXT: ret i32 [[VAL]]
-;
- %alloc0 = alloca %struct.T, align 8
- %alloc1 = alloca %struct.T, align 8
- store %struct.T { i32 0, i32 1 }, ptr %alloc0
- store %struct.T { i32 2, i32 3 }, ptr %alloc1
- %sel = select i1 %cond, ptr %alloc0, ptr %alloc1
- %gep = getelementptr inbounds %struct.T, ptr %sel, i32 %v, i32 1
- %val = load i32, ptr %gep
- ret i32 %val
-}
-
-define i32 @test_select_fold_split_addrspace(i1 %cond) {
-; CHECK-LABEL: define i32 @test_select_fold_split_addrspace(
-; CHECK-SAME: i1 [[COND:%.*]]) {
-; CHECK-NEXT: [[VAL:%.*]] = select i1 [[COND]], i32 1, i32 3
-; CHECK-NEXT: ret i32 [[VAL]]
-;
- %alloc0 = alloca %struct.T, align 16
- %alloc1 = alloca %struct.T, align 16
- store %struct.T { i32 0, i32 1 }, ptr %alloc0
- store %struct.T { i32 2, i32 3 }, ptr %alloc1
- %sel = select i1 %cond, ptr %alloc0, ptr %alloc1
- %cast = addrspacecast ptr %sel to ptr addrspace(5)
- %gep = getelementptr inbounds %struct.T, ptr addrspace(5) %cast, i32 0, i32 1
- %val = load i32, ptr addrspace(5) %gep
- ret i32 %val
-}
-
-define i32 @test_select_fold_split_multiple_users_same(i1 %cond) {
-; CHECK-LABEL: define i32 @test_select_fold_split_multiple_users_same(
-; CHECK-SAME: i1 [[COND:%.*]]) {
-; CHECK-NEXT: [[VAL0_SROA_SPECULATED:%.*]] = select i1 [[COND]], i32 0, i32 2
-; CHECK-NEXT: [[VAL1_SROA_SPECULATED:%.*]] = select i1 [[COND]], i32 0, i32 2
-; CHECK-NEXT: [[VAL:%.*]] = add i32 [[VAL0_SROA_SPECULATED]], [[VAL1_SROA_SPECULATED]]
-; CHECK-NEXT: ret i32 [[VAL]]
-;
- %alloc0 = alloca %struct.T, align 8
- %alloc1 = alloca %struct.T, align 8
- store %struct.T { i32 0, i32 1 }, ptr %alloc0
- store %struct.T { i32 2, i32 3 }, ptr %alloc1
- %sel = select i1 %cond, ptr %alloc0, ptr %alloc1
- %gep0 = getelementptr inbounds %struct.T, ptr %sel, i32 0, i32 0
- %gep1 = getelementptr inbounds %struct.T, ptr %sel, i32 0, i32 0
- %val0 = load i32, ptr %gep0
- %val1 = load i32, ptr %gep1
- %val = add i32 %val0, %val1
- ret i32 %val
-}
-
-define i32 @test_select_fold_split_multiple_users_different(i1 %cond) {
-; CHECK-LABEL: define i32 @test_select_fold_split_multiple_users_different(
-; CHECK-SAME: i1 [[COND:%.*]]) {
-; CHECK-NEXT: [[VAL0_SROA_SPECULATED:%.*]] = select i1 [[COND]], i32 0, i32 2
-; CHECK-NEXT: [[VAL1_SROA_SPECULATED:%.*]] = select i1 [[COND]], i32 1, i32 3
-; CHECK-NEXT: [[VAL:%.*]] = add i32 [[VAL0_SROA_SPECULATED]], [[VAL1_SROA_SPECULATED]]
-; CHECK-NEXT: ret i32 [[VAL]]
-;
- %alloc0 = alloca %struct.T, align 8
- %alloc1 = alloca %struct.T, align 8
- store %struct.T { i32 0, i32 1 }, ptr %alloc0
- store %struct.T { i32 2, i32 3 }, ptr %alloc1
- %sel = select i1 %cond, ptr %alloc0, ptr %alloc1
- %gep0 = getelementptr inbounds %struct.T, ptr %sel, i32 0, i32 0
- %gep1 = getelementptr inbounds %struct.T, ptr %sel, i32 0, i32 1
- %val0 = load i32, ptr %gep0
- %val1 = load i32, ptr %gep1
- %val = add i32 %val0, %val1
- ret i32 %val
-}
-
-define i32 @test_select_fold_split_gep_chain(i1 %cond) {
-; CHECK-LABEL: define i32 @test_select_fold_split_gep_chain(
-; CHECK-SAME: i1 [[COND:%.*]]) {
-; CHECK-NEXT: [[VAL_SROA_SPECULATED:%.*]] = select i1 [[COND]], i32 2, i32 5
-; CHECK-NEXT: ret i32 [[VAL_SROA_SPECULATED]]
-;
- %alloc0 = alloca [3 x i32], align 8
- %alloc1 = alloca [3 x i32], align 8
- store [3 x i32] [i32 0, i32 1, i32 2], ptr %alloc0
- store [3 x i32] [i32 3, i32 4, i32 5], ptr %alloc1
- %sel = select i1 %cond, ptr %alloc0, ptr %alloc1
- %gep0 = getelementptr i32, ptr %sel, i32 0
- %gep1 = getelementptr i32, ptr %gep0, i32 1
- %gep2 = getelementptr i32, ptr %gep1, i32 1
- %val = load i32, ptr %gep2
- ret i32 %val
-}
-
-define i32 @test_select_fold_split_zero_gep(i1 %cond) {
-; CHECK-LABEL: define i32 @test_select_fold_split_zero_gep(
-; CHECK-SAME: i1 [[COND:%.*]]) {
-; CHECK-NEXT: [[VAL_SROA_SPECULATED:%.*]] = select i1 [[COND]], i32 1, i32 3
-; CHECK-NEXT: ret i32 [[VAL_SROA_SPECULATED]]
-;
- %alloc0 = alloca %struct.T, align 8
- %alloc1 = alloca %struct.T, align 8
- store %struct.T { i32 0, i32 1 }, ptr %alloc0
- store %struct.T { i32 2, i32 3 }, ptr %alloc1
- %sel = select i1 %cond, ptr %alloc0, ptr %alloc1
- %gep0 = getelementptr %struct.T, ptr %sel, i32 0
- %gep1 = getelementptr inbounds %struct.T, ptr %gep0, i32 0, i32 1
- %val = load i32, ptr %gep1
- ret i32 %val
-}
-
-
-
-; Check for correct addrspacecast insertion for loads.
-define i32 @test_select_fold_split_volatile(i1 %cond) {
-; CHECK-LABEL: define i32 @test_select_fold_split_volatile(
-; CHECK-SAME: i1 [[COND:%.*]]) {
-; CHECK-NEXT: [[ALLOC0_SROA_0:%.*]] = alloca i32, align 8
-; CHECK-NEXT: [[DOTFCA_1_GEP2:%.*]] = alloca i32, align 4
-; CHECK-NEXT: [[SEL:%.*]] = alloca i32, align 8
-; CHECK-NEXT: [[DOTFCA_1_GEP:%.*]] = alloca i32, align 4
-; CHECK-NEXT: store i32 0, ptr [[ALLOC0_SROA_0]], align 8
-; CHECK-NEXT: store i32 1, ptr [[DOTFCA_1_GEP2]], align 4
-; CHECK-NEXT: store i32 2, ptr [[SEL]], align 8
-; CHECK-NEXT: store i32 3, ptr [[DOTFCA_1_GEP]], align 4
-; CHECK-NEXT: [[CAST:%.*]] = addrspacecast ptr [[SEL]] to ptr addrspace(5)
-; CHECK-NEXT: [[ALLOC0_SROA_0_0_GEP_SROA_CAST7:%.*]] = addrspacecast ptr [[ALLOC0_SROA_0]] to ptr addrspace(5)
-; CHECK-NEXT: [[GEP0:%.*]] = select i1 [[COND]], ptr addrspace(5) [[ALLOC0_SROA_0_0_GEP_SROA_CAST7]], ptr addrspace(5) [[CAST]]
-; CHECK-NEXT: [[ALLOC1_SROA_2_0_GEP4_SROA_CAST:%.*]] = addrspacecast ptr [[DOTFCA_1_GEP]] to ptr addrspace(5)
-; CHECK-NEXT: [[ALLOC0_SROA_2_0_GEP3_SROA_CAST:%.*]] = addrspacecast ptr [[DOTFCA_1_GEP2]] to ptr addrspace(5)
-; CHECK-NEXT: [[GEP1:%.*]] = select i1 [[COND]], ptr addrspace(5) [[ALLOC0_SROA_2_0_GEP3_SROA_CAST]], ptr addrspace(5) [[ALLOC1_SROA_2_0_GEP4_SROA_CAST]]
-; CHECK-NEXT: [[VAL1:%.*]] = load volatile i32, ptr addrspace(5) [[GEP0]], align 4
-; CHECK-NEXT: [[VAL2:%.*]] = load volatile i32, ptr addrspace(5) [[GEP1]], align 4
-; CHECK-NEXT: [[VAL3:%.*]] = add i32 [[VAL1]], [[VAL2]]
-; CHECK-NEXT: ret i32 [[VAL3]]
-;
- %alloc0 = alloca %struct.T, align 8
- %alloc1 = alloca %struct.T, align 8
- store %struct.T { i32 0, i32 1 }, ptr %alloc0
- store %struct.T { i32 2, i32 3 }, ptr %alloc1
- %sel = select i1 %cond, ptr %alloc0, ptr %alloc1
- %cast = addrspacecast ptr %sel to ptr addrspace(5)
- %gep0 = getelementptr inbounds %struct.T, ptr addrspace(5) %cast, i32 0, i32 0
- %gep1 = getelementptr inbounds %struct.T, ptr addrspace(5) %cast, i32 0, i32 1
- %val1 = load volatile i32, ptr addrspace(5) %gep0
- %val2 = load volatile i32, ptr addrspace(5) %gep1
- %val3 = add i32 %val1, %val2
- ret i32 %val3
-}
diff --git a/llvm/test/Transforms/SROA/select-gep-addrspace.ll b/llvm/test/Transforms/SROA/select-gep-addrspace.ll
new file mode 100644
index 0000000000000..7ad7652eb63af
--- /dev/null
+++ b/llvm/test/Transforms/SROA/select-gep-addrspace.ll
@@ -0,0 +1,31 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -passes='sroa<modify-cfg>' -S < %s | FileCheck %s
+
+target datalayout = "e-p:64:64-p5:32:32"
+
+%pair = type { i32, i32 }
+
+define i32 @select_gep_addrspace_widths(i1 %cond) {
+; CHECK-LABEL: @select_gep_addrspace_widths(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[ALLOC0:%.*]] = alloca i32, align 4
+; CHECK-NEXT: [[ALLOC1:%.*]] = alloca i32, align 4
+; CHECK-NEXT: store i32 1, ptr [[ALLOC0]], align 4
+; CHECK-NEXT: store i32 3, ptr [[ALLOC1]], align 4
+; CHECK-NEXT: [[ALLOC1_SROA_1_0_GEP_SROA_CAST:%.*]] = addrspacecast ptr [[ALLOC1]] to ptr addrspace(5)
+; CHECK-NEXT: [[ALLOC0_SROA_1_0_GEP_SROA_CAST:%.*]] = addrspacecast ptr [[ALLOC0]] to ptr addrspace(5)
+; CHECK-NEXT: [[CAST:%.*]] = select i1 [[COND:%.*]], ptr addrspace(5) [[ALLOC0_SROA_1_0_GEP_SROA_CAST]], ptr addrspace(5) [[ALLOC1_SROA_1_0_GEP_SROA_CAST]]
+; CHECK-NEXT: [[VALUE:%.*]] = load volatile i32, ptr addrspace(5) [[CAST]], align 4
+; CHECK-NEXT: ret i32 [[VALUE]]
+;
+entry:
+ %alloc0 = alloca %pair, align 8
+ %alloc1 = alloca %pair, align 8
+ store %pair { i32 0, i32 1 }, ptr %alloc0
+ store %pair { i32 2, i32 3 }, ptr %alloc1
+ %select = select i1 %cond, ptr %alloc0, ptr %alloc1
+ %cast = addrspacecast ptr %select to ptr addrspace(5)
+ %gep = getelementptr inbounds %pair, ptr addrspace(5) %cast, i32 0, i32 1
+ %value = load volatile i32, ptr addrspace(5) %gep
+ ret i32 %value
+}
diff --git a/llvm/test/Transforms/SROA/select-gep.ll b/llvm/test/Transforms/SROA/select-gep.ll
index 688ea03cddac0..5fe920413af4a 100644
--- a/llvm/test/Transforms/SROA/select-gep.ll
+++ b/llvm/test/Transforms/SROA/select-gep.ll
@@ -3,6 +3,7 @@
; RUN: opt -S -passes='sroa<modify-cfg>' < %s | FileCheck %s --check-prefixes=CHECK,CHECK-MODIFY-CFG
%pair = type { i32, i32 }
+%struct.T = type { i32, i32 }
define i32 @test_sroa_select_gep(i1 %cond) {
; CHECK-LABEL: @test_sroa_select_gep(
@@ -170,8 +171,7 @@ define i32 @test_select_idx_memcpy(i1 %c, ptr %p) {
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[ALLOCA_SROA_22]], ptr align 1 [[ALLOCA_SROA_22_0_P_SROA_IDX]], i64 4, i1 false)
; CHECK-NEXT: [[ALLOCA_SROA_3_0_P_SROA_IDX:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 28
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[ALLOCA_SROA_3]], ptr align 1 [[ALLOCA_SROA_3_0_P_SROA_IDX]], i64 132, i1 false)
-; CHECK-NEXT: [[IDX:%.*]] = select i1 [[C:%.*]], i64 24, i64 0
-; CHECK-NEXT: [[IDX_SROA_SEL:%.*]] = select i1 [[C]], ptr [[ALLOCA_SROA_22]], ptr [[ALLOCA_SROA_0]]
+; CHECK-NEXT: [[IDX_SROA_SEL:%.*]] = select i1 [[C:%.*]], ptr [[ALLOCA_SROA_22]], ptr [[ALLOCA_SROA_0]]
; CHECK-NEXT: [[RES:%.*]] = load i32, ptr [[IDX_SROA_SEL]], align 4
; CHECK-NEXT: ret i32 [[RES]]
;
@@ -187,8 +187,7 @@ define i32 @test_select_idx_memcpy(i1 %c, ptr %p) {
; promotable.
define i32 @test_select_idx_mem2reg(i1 %c) {
; CHECK-LABEL: @test_select_idx_mem2reg(
-; CHECK-NEXT: [[IDX:%.*]] = select i1 [[C:%.*]], i64 24, i64 0
-; CHECK-NEXT: [[RES_SROA_SPECULATED:%.*]] = select i1 [[C]], i32 2, i32 1
+; CHECK-NEXT: [[RES_SROA_SPECULATED:%.*]] = select i1 [[C:%.*]], i32 2, i32 1
; CHECK-NEXT: ret i32 [[RES_SROA_SPECULATED]]
;
%alloca = alloca [20 x i64], align 8
@@ -205,8 +204,7 @@ define i32 @test_select_idx_mem2reg(i1 %c) {
; splittable and promotable.
define i64 @test_select_like_zext_idx_mem2reg(i1 %c) !prof !0 {
; CHECK-LABEL: @test_select_like_zext_idx_mem2reg(
-; CHECK-NEXT: [[IDX:%.*]] = zext i1 [[C:%.*]] to i64
-; CHECK-NEXT: [[RES:%.*]] = select i1 [[C]], i64 2, i64 1, !prof [[PROF1:![0-9]+]]
+; CHECK-NEXT: [[RES:%.*]] = select i1 [[C:%.*]], i64 2, i64 1, !prof [[PROF1:![0-9]+]]
; CHECK-NEXT: ret i64 [[RES]]
;
%alloca = alloca [2 x i64], align 8
@@ -252,10 +250,9 @@ define i32 @test_select_idx_escaped(i1 %c, ptr %p) {
; CHECK-NEXT: store i32 1, ptr [[ALLOCA]], align 4
; CHECK-NEXT: [[GEP1:%.*]] = getelementptr inbounds i8, ptr [[ALLOCA]], i64 24
; CHECK-NEXT: store i32 2, ptr [[GEP1]], align 4
-; CHECK-NEXT: [[IDX:%.*]] = select i1 [[C:%.*]], i64 24, i64 0
; CHECK-NEXT: [[DOTSROA_GEP:%.*]] = getelementptr inbounds i8, ptr [[ALLOCA]], i64 24
; CHECK-NEXT: [[DOTSROA_GEP1:%.*]] = getelementptr inbounds i8, ptr [[ALLOCA]], i64 0
-; CHECK-NEXT: [[IDX_SROA_SEL:%.*]] = select i1 [[C]], ptr [[DOTSROA_GEP]], ptr [[DOTSROA_GEP1]]
+; CHECK-NEXT: [[IDX_SROA_SEL:%.*]] = select i1 [[C:%.*]], ptr [[DOTSROA_GEP]], ptr [[DOTSROA_GEP1]]
; CHECK-NEXT: [[RES:%.*]] = load i32, ptr [[IDX_SROA_SEL]], align 4
; CHECK-NEXT: ret i32 [[RES]]
;
@@ -353,6 +350,216 @@ define i32 @test_select_idx_not_constant3(i1 %c, ptr %p, i64 %arg) {
ret i32 %res
}
+; The intermediate addrspacecast is dead after unfolding the GEP(select).
+define i32 @test_sroa_select_gep_addrspace(i1 %cond) {
+; CHECK-LABEL: @test_sroa_select_gep_addrspace(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[ALLOC0:%.*]] = alloca i32, align 4
+; CHECK-NEXT: [[ALLOC1:%.*]] = alloca i32, align 4
+; CHECK-NEXT: store i32 1, ptr [[ALLOC0]], align 4
+; CHECK-NEXT: store i32 3, ptr [[ALLOC1]], align 4
+; CHECK-NEXT: [[ALLOC1_SROA_1_0_GEP_SROA_CAST:%.*]] = addrspacecast ptr [[ALLOC1]] to ptr addrspace(5)
+; CHECK-NEXT: [[ALLOC0_SROA_1_0_GEP_SROA_CAST:%.*]] = addrspacecast ptr [[ALLOC0]] to ptr addrspace(5)
+; CHECK-NEXT: [[CAST:%.*]] = select i1 [[COND:%.*]], ptr addrspace(5) [[ALLOC0_SROA_1_0_GEP_SROA_CAST]], ptr addrspace(5) [[ALLOC1_SROA_1_0_GEP_SROA_CAST]]
+; CHECK-NEXT: [[VALUE:%.*]] = load volatile i32, ptr addrspace(5) [[CAST]], align 4
+; CHECK-NEXT: ret i32 [[VALUE]]
+;
+entry:
+ %alloc0 = alloca %pair, align 8
+ %alloc1 = alloca %pair, align 8
+ store %pair { i32 0, i32 1 }, ptr %alloc0
+ store %pair { i32 2, i32 3 }, ptr %alloc1
+ %select = select i1 %cond, ptr %alloc0, ptr %alloc1
+ %cast = addrspacecast ptr %select to ptr addrspace(5)
+ %gep = getelementptr inbounds %pair, ptr addrspace(5) %cast, i32 0, i32 1
+ %value = load volatile i32, ptr addrspace(5) %gep
+ ret i32 %value
+}
+
+define i32 @test_select_fold_split(i1 %cond) {
+; CHECK-LABEL: @test_select_fold_split(
+; CHECK-NEXT: [[VAL_SROA_SPECULATED:%.*]] = select i1 [[COND:%.*]], i32 1, i32 3
+; CHECK-NEXT: ret i32 [[VAL_SROA_SPECULATED]]
+;
+ %alloc0 = alloca %struct.T, align 8
+ %alloc1 = alloca %struct.T, align 8
+ store %struct.T { i32 0, i32 1 }, ptr %alloc0
+ store %struct.T { i32 2, i32 3 }, ptr %alloc1
+ %sel = select i1 %cond, ptr %alloc0, ptr %alloc1
+ %gep = getelementptr inbounds %struct.T, ptr %sel, i32 0, i32 1
+ %val = load i32, ptr %gep
+ ret i32 %val
+}
+
+define i32 @test_select_fold_split_zero(i1 %cond) {
+; CHECK-LABEL: @test_select_fold_split_zero(
+; CHECK-NEXT: [[VAL_SROA_SPECULATED:%.*]] = select i1 [[COND:%.*]], i32 0, i32 2
+; CHECK-NEXT: ret i32 [[VAL_SROA_SPECULATED]]
+;
+ %alloc0 = alloca %struct.T, align 8
+ %alloc1 = alloca %struct.T, align 8
+ store %struct.T { i32 0, i32 1 }, ptr %alloc0
+ store %struct.T { i32 2, i32 3 }, ptr %alloc1
+ %sel = select i1 %cond, ptr %alloc0, ptr %alloc1
+ %gep = getelementptr inbounds %struct.T, ptr %sel, i32 0, i32 0
+ %val = load i32, ptr %gep
+ ret i32 %val
+}
+
+define i32 @test_select_fold_split_var_gep(i1 %cond, i32 %v) {
+; CHECK-LABEL: @test_select_fold_split_var_gep(
+; CHECK-NEXT: [[ALLOC0:%.*]] = alloca [[STRUCT_T:%.*]], align 8
+; CHECK-NEXT: [[ALLOC1:%.*]] = alloca [[STRUCT_T]], align 8
+; CHECK-NEXT: [[DOTFCA_0_GEP1:%.*]] = getelementptr inbounds [[STRUCT_T]], ptr [[ALLOC0]], i32 0, i32 0
+; CHECK-NEXT: store i32 0, ptr [[DOTFCA_0_GEP1]], align 4
+; CHECK-NEXT: [[DOTFCA_1_GEP2:%.*]] = getelementptr inbounds [[STRUCT_T]], ptr [[ALLOC0]], i32 0, i32 1
+; CHECK-NEXT: store i32 1, ptr [[DOTFCA_1_GEP2]], align 4
+; CHECK-NEXT: [[DOTFCA_0_GEP:%.*]] = getelementptr inbounds [[STRUCT_T]], ptr [[ALLOC1]], i32 0, i32 0
+; CHECK-NEXT: store i32 2, ptr [[DOTFCA_0_GEP]], align 4
+; CHECK-NEXT: [[DOTFCA_1_GEP:%.*]] = getelementptr inbounds [[STRUCT_T]], ptr [[ALLOC1]], i32 0, i32 1
+; CHECK-NEXT: store i32 3, ptr [[DOTFCA_1_GEP]], align 4
+; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND:%.*]], ptr [[ALLOC0]], ptr [[ALLOC1]]
+; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds [[STRUCT_T]], ptr [[SEL]], i32 [[V:%.*]], i32 1
+; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[GEP]], align 4
+; CHECK-NEXT: ret i32 [[VAL]]
+;
+ %alloc0 = alloca %struct.T, align 8
+ %alloc1 = alloca %struct.T, align 8
+ store %struct.T { i32 0, i32 1 }, ptr %alloc0
+ store %struct.T { i32 2, i32 3 }, ptr %alloc1
+ %sel = select i1 %cond, ptr %alloc0, ptr %alloc1
+ %gep = getelementptr inbounds %struct.T, ptr %sel, i32 %v, i32 1
+ %val = load i32, ptr %gep
+ ret i32 %val
+}
+
+define i32 @test_select_fold_split_addrspace(i1 %cond) {
+; CHECK-LABEL: @test_select_fold_split_addrspace(
+; CHECK-NEXT: [[VAL:%.*]] = select i1 [[COND:%.*]], i32 1, i32 3
+; CHECK-NEXT: ret i32 [[VAL]]
+;
+ %alloc0 = alloca %struct.T, align 16
+ %alloc1 = alloca %struct.T, align 16
+ store %struct.T { i32 0, i32 1 }, ptr %alloc0
+ store %struct.T { i32 2, i32 3 }, ptr %alloc1
+ %sel = select i1 %cond, ptr %alloc0, ptr %alloc1
+ %cast = addrspacecast ptr %sel to ptr addrspace(5)
+ %gep = getelementptr inbounds %struct.T, ptr addrspace(5) %cast, i32 0, i32 1
+ %val = load i32, ptr addrspace(5) %gep
+ ret i32 %val
+}
+
+define i32 @test_select_fold_split_multiple_users_same(i1 %cond) {
+; CHECK-LABEL: @test_select_fold_split_multiple_users_same(
+; CHECK-NEXT: [[VAL0_SROA_SPECULATED:%.*]] = select i1 [[COND:%.*]], i32 0, i32 2
+; CHECK-NEXT: [[VAL1_SROA_SPECULATED:%.*]] = select i1 [[COND]], i32 0, i32 2
+; CHECK-NEXT: [[VAL:%.*]] = add i32 [[VAL0_SROA_SPECULATED]], [[VAL1_SROA_SPECULATED]]
+; CHECK-NEXT: ret i32 [[VAL]]
+;
+ %alloc0 = alloca %struct.T, align 8
+ %alloc1 = alloca %struct.T, align 8
+ store %struct.T { i32 0, i32 1 }, ptr %alloc0
+ store %struct.T { i32 2, i32 3 }, ptr %alloc1
+ %sel = select i1 %cond, ptr %alloc0, ptr %alloc1
+ %gep0 = getelementptr inbounds %struct.T, ptr %sel, i32 0, i32 0
+ %gep1 = getelementptr inbounds %struct.T, ptr %sel, i32 0, i32 0
+ %val0 = load i32, ptr %gep0
+ %val1 = load i32, ptr %gep1
+ %val = add i32 %val0, %val1
+ ret i32 %val
+}
+
+define i32 @test_select_fold_split_multiple_users_different(i1 %cond) {
+; CHECK-LABEL: @test_select_fold_split_multiple_users_different(
+; CHECK-NEXT: [[VAL0_SROA_SPECULATED:%.*]] = select i1 [[COND:%.*]], i32 0, i32 2
+; CHECK-NEXT: [[VAL1_SROA_SPECULATED:%.*]] = select i1 [[COND]], i32 1, i32 3
+; CHECK-NEXT: [[VAL:%.*]] = add i32 [[VAL0_SROA_SPECULATED]], [[VAL1_SROA_SPECULATED]]
+; CHECK-NEXT: ret i32 [[VAL]]
+;
+ %alloc0 = alloca %struct.T, align 8
+ %alloc1 = alloca %struct.T, align 8
+ store %struct.T { i32 0, i32 1 }, ptr %alloc0
+ store %struct.T { i32 2, i32 3 }, ptr %alloc1
+ %sel = select i1 %cond, ptr %alloc0, ptr %alloc1
+ %gep0 = getelementptr inbounds %struct.T, ptr %sel, i32 0, i32 0
+ %gep1 = getelementptr inbounds %struct.T, ptr %sel, i32 0, i32 1
+ %val0 = load i32, ptr %gep0
+ %val1 = load i32, ptr %gep1
+ %val = add i32 %val0, %val1
+ ret i32 %val
+}
+
+define i32 @test_select_fold_split_gep_chain(i1 %cond) {
+; CHECK-LABEL: @test_select_fold_split_gep_chain(
+; CHECK-NEXT: [[VAL_SROA_SPECULATED:%.*]] = select i1 [[COND:%.*]], i32 2, i32 5
+; CHECK-NEXT: ret i32 [[VAL_SROA_SPECULATED]]
+;
+ %alloc0 = alloca [3 x i32], align 8
+ %alloc1 = alloca [3 x i32], align 8
+ store [3 x i32] [i32 0, i32 1, i32 2], ptr %alloc0
+ store [3 x i32] [i32 3, i32 4, i32 5], ptr %alloc1
+ %sel = select i1 %cond, ptr %alloc0, ptr %alloc1
+ %gep0 = getelementptr i32, ptr %sel, i32 0
+ %gep1 = getelementptr i32, ptr %gep0, i32 1
+ %gep2 = getelementptr i32, ptr %gep1, i32 1
+ %val = load i32, ptr %gep2
+ ret i32 %val
+}
+
+define i32 @test_select_fold_split_zero_gep(i1 %cond) {
+; CHECK-LABEL: @test_select_fold_split_zero_gep(
+; CHECK-NEXT: [[VAL_SROA_SPECULATED:%.*]] = select i1 [[COND:%.*]], i32 1, i32 3
+; CHECK-NEXT: ret i32 [[VAL_SROA_SPECULATED]]
+;
+ %alloc0 = alloca %struct.T, align 8
+ %alloc1 = alloca %struct.T, align 8
+ store %struct.T { i32 0, i32 1 }, ptr %alloc0
+ store %struct.T { i32 2, i32 3 }, ptr %alloc1
+ %sel = select i1 %cond, ptr %alloc0, ptr %alloc1
+ %gep0 = getelementptr %struct.T, ptr %sel, i32 0
+ %gep1 = getelementptr inbounds %struct.T, ptr %gep0, i32 0, i32 1
+ %val = load i32, ptr %gep1
+ ret i32 %val
+}
+
+
+
+; Check for correct addrspacecast insertion for loads.
+define i32 @test_select_fold_split_volatile(i1 %cond) {
+; CHECK-LABEL: @test_select_fold_split_volatile(
+; CHECK-NEXT: [[ALLOC0:%.*]] = alloca i32, align 8
+; CHECK-NEXT: [[DOTFCA_1_GEP2:%.*]] = alloca i32, align 4
+; CHECK-NEXT: [[ALLOC1:%.*]] = alloca i32, align 8
+; CHECK-NEXT: [[DOTFCA_1_GEP:%.*]] = alloca i32, align 4
+; CHECK-NEXT: store i32 0, ptr [[ALLOC0]], align 8
+; CHECK-NEXT: store i32 1, ptr [[DOTFCA_1_GEP2]], align 4
+; CHECK-NEXT: store i32 2, ptr [[ALLOC1]], align 8
+; CHECK-NEXT: store i32 3, ptr [[DOTFCA_1_GEP]], align 4
+; CHECK-NEXT: [[ALLOC1_SROA_0_0_GEP_SROA_CAST6:%.*]] = addrspacecast ptr [[ALLOC1]] to ptr addrspace(5)
+; CHECK-NEXT: [[ALLOC0_SROA_0_0_GEP_SROA_CAST8:%.*]] = addrspacecast ptr [[ALLOC0]] to ptr addrspace(5)
+; CHECK-NEXT: [[ALLOC0_SROA_0_0_GEP_SROA_CAST7:%.*]] = select i1 [[COND:%.*]], ptr addrspace(5) [[ALLOC0_SROA_0_0_GEP_SROA_CAST8]], ptr addrspace(5) [[ALLOC1_SROA_0_0_GEP_SROA_CAST6]]
+; CHECK-NEXT: [[ALLOC1_SROA_2_0_GEP4_SROA_CAST:%.*]] = addrspacecast ptr [[DOTFCA_1_GEP]] to ptr addrspace(5)
+; CHECK-NEXT: [[ALLOC0_SROA_2_0_GEP3_SROA_CAST:%.*]] = addrspacecast ptr [[DOTFCA_1_GEP2]] to ptr addrspace(5)
+; CHECK-NEXT: [[GEP1:%.*]] = select i1 [[COND]], ptr addrspace(5) [[ALLOC0_SROA_2_0_GEP3_SROA_CAST]], ptr addrspace(5) [[ALLOC1_SROA_2_0_GEP4_SROA_CAST]]
+; CHECK-NEXT: [[VAL1:%.*]] = load volatile i32, ptr addrspace(5) [[ALLOC0_SROA_0_0_GEP_SROA_CAST7]], align 4
+; CHECK-NEXT: [[VAL2:%.*]] = load volatile i32, ptr addrspace(5) [[GEP1]], align 4
+; CHECK-NEXT: [[VAL3:%.*]] = add i32 [[VAL1]], [[VAL2]]
+; CHECK-NEXT: ret i32 [[VAL3]]
+;
+ %alloc0 = alloca %struct.T, align 8
+ %alloc1 = alloca %struct.T, align 8
+ store %struct.T { i32 0, i32 1 }, ptr %alloc0
+ store %struct.T { i32 2, i32 3 }, ptr %alloc1
+ %sel = select i1 %cond, ptr %alloc0, ptr %alloc1
+ %cast = addrspacecast ptr %sel to ptr addrspace(5)
+ %gep0 = getelementptr inbounds %struct.T, ptr addrspace(5) %cast, i32 0, i32 0
+ %gep1 = getelementptr inbounds %struct.T, ptr addrspace(5) %cast, i32 0, i32 1
+ %val1 = load volatile i32, ptr addrspace(5) %gep0
+ %val2 = load volatile i32, ptr addrspace(5) %gep1
+ %val3 = add i32 %val1, %val2
+ ret i32 %val3
+}
+
!0 = !{!"function_entry_count", i32 10}
;.
; CHECK-PRESERVE-CFG: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
diff --git a/llvm/test/Transforms/SROA/select-load.ll b/llvm/test/Transforms/SROA/select-load.ll
index 0a7a6d5e5ed4b..73746642b50c8 100644
--- a/llvm/test/Transforms/SROA/select-load.ll
+++ b/llvm/test/Transforms/SROA/select-load.ll
@@ -477,6 +477,58 @@ define void @load_of_select_with_noundef_nonnull(ptr %buffer, i1 %b) {
ret void
}
+define i32 @test_load_addrspacecast_select() {
+; CHECK-LABEL: @test_load_addrspacecast_select(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[A_SROA_0:%.*]] = alloca i32, align 4
+; CHECK-NEXT: [[A_SROA_3:%.*]] = alloca i32, align 4
+; CHECK-NEXT: store i32 0, ptr [[A_SROA_0]], align 4
+; CHECK-NEXT: store i32 1, ptr [[A_SROA_3]], align 4
+; CHECK-NEXT: [[A_SROA_0_0_A_SROA_0_0_V0:%.*]] = load i32, ptr [[A_SROA_0]], align 4
+; CHECK-NEXT: [[A_SROA_3_0_A_SROA_3_4_V1:%.*]] = load i32, ptr [[A_SROA_3]], align 4
+; CHECK-NEXT: [[COND:%.*]] = icmp sle i32 [[A_SROA_0_0_A_SROA_0_0_V0]], [[A_SROA_3_0_A_SROA_3_4_V1]]
+; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], ptr [[A_SROA_3]], ptr [[A_SROA_0]]
+; CHECK-NEXT: [[SELECT_ASC:%.*]] = addrspacecast ptr [[SELECT]] to ptr addrspace(1)
+; CHECK-NEXT: [[RESULT:%.*]] = load i32, ptr addrspace(1) [[SELECT_ASC]], align 4
+; CHECK-NEXT: ret i32 [[RESULT]]
+;
+entry:
+ %a = alloca [2 x i32]
+ %a1 = getelementptr [2 x i32], ptr %a, i64 0, i32 1
+ store i32 0, ptr %a
+ store i32 1, ptr %a1
+ %v0 = load i32, ptr %a
+ %v1 = load i32, ptr %a1
+ %cond = icmp sle i32 %v0, %v1
+ %select = select i1 %cond, ptr %a1, ptr %a
+ %select.asc = addrspacecast ptr %select to ptr addrspace(1)
+ %result = load i32, ptr addrspace(1) %select.asc
+ ret i32 %result
+}
+
+; Verify that a select of pointers in a non-default address space can be
+; speculated after SROA rewrites one arm to the default address space.
+define i32 @select_speculate_addrspace(i1 %cond) {
+; CHECK-LABEL: define i32 @select_speculate_addrspace(
+; CHECK-SAME: i1 [[COND:%.*]]) {
+; CHECK-NEXT: [[ALLOCA:%.*]] = alloca i32, align 4
+; CHECK-NEXT: [[CAST:%.*]] = addrspacecast ptr [[ALLOCA]] to ptr addrspace(5)
+; CHECK-NEXT: store volatile i32 1, ptr addrspace(5) [[CAST]], align 4
+; CHECK-NEXT: [[LOAD:%.*]] = load i32, ptr [[ALLOCA]], align 4
+; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], i32 [[LOAD]], i32 2
+; CHECK-NEXT: ret i32 [[SELECT]]
+;
+ %alloc0 = alloca i32, align 4
+ %alloc1 = alloca i32, align 4
+ %cast0 = addrspacecast ptr %alloc0 to ptr addrspace(5)
+ %cast1 = addrspacecast ptr %alloc1 to ptr addrspace(5)
+ store volatile i32 1, ptr addrspace(5) %cast0
+ store i32 2, ptr addrspace(5) %cast1
+ %sel = select i1 %cond, ptr addrspace(5) %cast0, ptr addrspace(5) %cast1
+ %val = load i32, ptr addrspace(5) %sel
+ ret i32 %val
+}
+
!0 = !{!"branch_weights", i32 1, i32 99}
!1 = !{}
diff --git a/llvm/test/Transforms/SROA/select-speculate-addrspace.ll b/llvm/test/Transforms/SROA/select-speculate-addrspace.ll
deleted file mode 100644
index e976a158c55a0..0000000000000
--- a/llvm/test/Transforms/SROA/select-speculate-addrspace.ll
+++ /dev/null
@@ -1,25 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
-; RUN: opt -passes='sroa<modify-cfg>' -S < %s | FileCheck %s
-
-; Verify that a select of pointers in a non-default address space can be
-; speculated after SROA rewrites one arm to the default address space.
-define i32 @select_speculate_addrspace(i1 %cond) {
-; CHECK-LABEL: define i32 @select_speculate_addrspace(
-; CHECK-SAME: i1 [[COND:%.*]]) {
-; CHECK-NEXT: [[ALLOCA:%.*]] = alloca i32, align 4
-; CHECK-NEXT: [[CAST:%.*]] = addrspacecast ptr [[ALLOCA]] to ptr addrspace(5)
-; CHECK-NEXT: store volatile i32 1, ptr addrspace(5) [[CAST]], align 4
-; CHECK-NEXT: [[LOAD:%.*]] = load i32, ptr [[ALLOCA]], align 4
-; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], i32 [[LOAD]], i32 2
-; CHECK-NEXT: ret i32 [[SELECT]]
-;
- %alloc0 = alloca i32, align 4
- %alloc1 = alloca i32, align 4
- %cast0 = addrspacecast ptr %alloc0 to ptr addrspace(5)
- %cast1 = addrspacecast ptr %alloc1 to ptr addrspace(5)
- store volatile i32 1, ptr addrspace(5) %cast0
- store i32 2, ptr addrspace(5) %cast1
- %sel = select i1 %cond, ptr addrspace(5) %cast0, ptr addrspace(5) %cast1
- %val = load i32, ptr addrspace(5) %sel
- ret i32 %val
-}
More information about the llvm-commits
mailing list