[llvm] [SROA] Improve select folding around casts (PR #222466)
Daniel Donenfeld via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 23 10:58:30 PDT 2026
https://github.com/daniel-donenfeld updated https://github.com/llvm/llvm-project/pull/222466
>From e6391a8ad0b452584cf8f03305e21d2488887073 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/6] [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 6f0c5f646af201f16bbc0c6e801462fb61d1b276 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/6] [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 15c7155df710e..1354fd5db9291 100644
--- a/llvm/lib/Transforms/Scalar/SROA.cpp
+++ b/llvm/lib/Transforms/Scalar/SROA.cpp
@@ -1800,6 +1800,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");
@@ -1933,8 +1939,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.
@@ -4464,6 +4469,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)
@@ -4472,7 +4500,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)
@@ -4507,7 +4536,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);
@@ -4532,12 +4562,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
@@ -4546,6 +4583,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 cf93fc8547031c3bd4f2993297faa2ac41f3dc94 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/6] 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 1354fd5db9291..357f7f513035e 100644
--- a/llvm/lib/Transforms/Scalar/SROA.cpp
+++ b/llvm/lib/Transforms/Scalar/SROA.cpp
@@ -1800,12 +1800,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");
@@ -1939,7 +1933,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.
@@ -4469,29 +4464,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)
@@ -4502,12 +4474,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;
@@ -4517,6 +4491,7 @@ class AggLoadStoreRewriter : public InstVisitor<AggLoadStoreRewriter, bool> {
if (Sel)
return false;
Sel = ZI;
+ SelOpNum = Op.getOperandNo();
if (!ZI->getSrcTy()->isIntegerTy(1))
return false;
continue;
@@ -4534,13 +4509,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;
};
@@ -4583,11 +4553,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 6d079394ab084..4e9d3d6132e18 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 ec55f8029be20..a9fc79f6ac737 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(
@@ -168,8 +169,7 @@ define i32 @test_select_idx_memcpy(i1 %c, ptr %p) {
; CHECK-NEXT: [[ALLOCA_SROA_22_0_COPYLOAD:%.*]] = load i32, ptr [[ALLOCA_SROA_22_0_P_SROA_IDX]], align 1
; 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: [[RES:%.*]] = select i1 [[C]], i32 [[ALLOCA_SROA_22_0_COPYLOAD]], i32 [[ALLOCA_SROA_0_0_COPYLOAD]]
+; CHECK-NEXT: [[RES:%.*]] = select i1 [[C:%.*]], i32 [[ALLOCA_SROA_22_0_COPYLOAD]], i32 [[ALLOCA_SROA_0_0_COPYLOAD]]
; CHECK-NEXT: ret i32 [[RES]]
;
%alloca = alloca [20 x i64], align 8
@@ -184,8 +184,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
@@ -202,8 +201,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
@@ -249,10 +247,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]]
;
@@ -350,6 +347,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 9298642ded9cf..fd23b6662a2f0 100644
--- a/llvm/test/Transforms/SROA/select-load.ll
+++ b/llvm/test/Transforms/SROA/select-load.ll
@@ -476,6 +476,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
-}
>From 21a335f72b03199dee05ccc6595cecbdde299911 Mon Sep 17 00:00:00 2001
From: Daniel Donenfeld <ddonenfeld at nvidia.com>
Date: Tue, 22 Sep 2026 21:55:03 +0000
Subject: [PATCH 4/6] Attempt to add check for volatile accesses
---
llvm/lib/Transforms/Scalar/SROA.cpp | 16 +++++++++--
.../Transforms/SROA/select-gep-addrspace.ll | 28 +++++++++++++++++++
2 files changed, 42 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Transforms/Scalar/SROA.cpp b/llvm/lib/Transforms/Scalar/SROA.cpp
index 357f7f513035e..10f46351c61dd 100644
--- a/llvm/lib/Transforms/Scalar/SROA.cpp
+++ b/llvm/lib/Transforms/Scalar/SROA.cpp
@@ -4472,8 +4472,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()->stripPointerCasts());
+ Value *PtrOp = GEPI.getPointerOperand();
+ Instruction *Sel = dyn_cast<SelectInst>(PtrOp->stripPointerCasts());
unsigned SelOpNum = 0;
for (auto& Op : GEPI.indices()) {
if (auto *SI = dyn_cast<SelectInst>(Op)) {
@@ -4504,6 +4504,18 @@ class AggLoadStoreRewriter : public InstVisitor<AggLoadStoreRewriter, bool> {
if (!Sel)
return false;
+ // Do not duplicate address-space casts for volatile accesses. Unfolding the
+ // GEP can increase code size and register pressure.
+ bool CrossesAddressSpace =
+ Sel && PtrOp->getType()->getPointerAddressSpace() !=
+ Sel->getType()->getPointerAddressSpace();
+ if (CrossesAddressSpace &&
+ any_of(GEPI.users(), [](User *U) {
+ auto *I = dyn_cast<Instruction>(U);
+ return I && I->isVolatile();
+ }))
+ return false;
+
LLVM_DEBUG(dbgs() << " Rewriting gep(select) -> select(gep):\n";
dbgs() << " original: " << *Sel << "\n";
dbgs() << " " << GEPI << "\n";);
diff --git a/llvm/test/Transforms/SROA/select-gep-addrspace.ll b/llvm/test/Transforms/SROA/select-gep-addrspace.ll
index 7ad7652eb63af..c7e99a79bea77 100644
--- a/llvm/test/Transforms/SROA/select-gep-addrspace.ll
+++ b/llvm/test/Transforms/SROA/select-gep-addrspace.ll
@@ -29,3 +29,31 @@ entry:
%value = load volatile i32, ptr addrspace(5) %gep
ret i32 %value
}
+
+; Do not unfold the address-space cast for volatile accesses. The shared
+; select/cast is smaller than duplicating the address calculation per field.
+define i32 @select_gep_addrspace_volatile_as5_to_as0(i1 %cond) {
+; CHECK-LABEL: @select_gep_addrspace_volatile_as5_to_as0(
+; CHECK: [[ALLOC0:%.*]] = alloca %pair, align 8, addrspace(5)
+; CHECK-NEXT: [[ALLOC1:%.*]] = alloca %pair, align 8, addrspace(5)
+; CHECK: [[SELECT:%.*]] = select i1 [[COND:%.*]], ptr addrspace(5) [[ALLOC0]], ptr addrspace(5) [[ALLOC1]]
+; CHECK-NEXT: [[CAST:%.*]] = addrspacecast ptr addrspace(5) [[SELECT]] to ptr
+; CHECK-NEXT: [[GEP0:%.*]] = getelementptr inbounds %pair, ptr [[CAST]], i32 0, i32 0
+; CHECK-NEXT: [[GEP1:%.*]] = getelementptr inbounds %pair, ptr [[CAST]], i32 0, i32 1
+; CHECK-NEXT: [[VAL0:%.*]] = load volatile i32, ptr [[GEP0]], align 4
+; CHECK-NEXT: [[VAL1:%.*]] = load volatile i32, ptr [[GEP1]], align 4
+;
+entry:
+ %alloc0 = alloca %pair, align 8, addrspace(5)
+ %alloc1 = alloca %pair, align 8, addrspace(5)
+ store %pair { i32 0, i32 1 }, ptr addrspace(5) %alloc0, align 8
+ store %pair { i32 2, i32 3 }, ptr addrspace(5) %alloc1, align 8
+ %select = select i1 %cond, ptr addrspace(5) %alloc0, ptr addrspace(5) %alloc1
+ %cast = addrspacecast ptr addrspace(5) %select to ptr
+ %gep0 = getelementptr inbounds %pair, ptr %cast, i32 0, i32 0
+ %gep1 = getelementptr inbounds %pair, ptr %cast, i32 0, i32 1
+ %val0 = load volatile i32, ptr %gep0, align 4
+ %val1 = load volatile i32, ptr %gep1, align 4
+ %sum = add i32 %val0, %val1
+ ret i32 %sum
+}
>From 768f022dd153f03688cd4881522c37fb9e5d13cf Mon Sep 17 00:00:00 2001
From: Daniel Donenfeld <ddonenfeld at nvidia.com>
Date: Wed, 23 Sep 2026 14:09:59 +0000
Subject: [PATCH 5/6] Update tests
---
.../Transforms/SROA/select-gep-addrspace.ll | 69 ++++++++++++++-----
1 file changed, 51 insertions(+), 18 deletions(-)
diff --git a/llvm/test/Transforms/SROA/select-gep-addrspace.ll b/llvm/test/Transforms/SROA/select-gep-addrspace.ll
index c7e99a79bea77..c1874fd5d1306 100644
--- a/llvm/test/Transforms/SROA/select-gep-addrspace.ll
+++ b/llvm/test/Transforms/SROA/select-gep-addrspace.ll
@@ -8,14 +8,38 @@ target datalayout = "e-p:64:64-p5:32:32"
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: [[VALUE:%.*]] = select i1 [[COND:%.*]], i32 1, i32 3
+; 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 i32, ptr addrspace(5) %gep
+ ret i32 %value
+}
+
+define i32 @select_gep_addrspace_volatile_as0_to_as5(i1 %cond) {
+; CHECK-LABEL: @select_gep_addrspace_volatile_as0_to_as5(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[ALLOC0:%.*]] = alloca [[PAIR:%.*]], align 8
+; CHECK-NEXT: [[ALLOC1:%.*]] = alloca [[PAIR]], align 8
+; CHECK-NEXT: [[DOTFCA_0_GEP1:%.*]] = getelementptr inbounds [[PAIR]], ptr [[ALLOC0]], i32 0, i32 0
+; CHECK-NEXT: store i32 0, ptr [[DOTFCA_0_GEP1]], align 4
+; CHECK-NEXT: [[DOTFCA_1_GEP2:%.*]] = getelementptr inbounds [[PAIR]], ptr [[ALLOC0]], i32 0, i32 1
+; CHECK-NEXT: store i32 1, ptr [[DOTFCA_1_GEP2]], align 4
+; CHECK-NEXT: [[DOTFCA_0_GEP:%.*]] = getelementptr inbounds [[PAIR]], ptr [[ALLOC1]], i32 0, i32 0
+; CHECK-NEXT: store i32 2, ptr [[DOTFCA_0_GEP]], align 4
+; CHECK-NEXT: [[DOTFCA_1_GEP:%.*]] = getelementptr inbounds [[PAIR]], ptr [[ALLOC1]], i32 0, i32 1
+; CHECK-NEXT: store i32 3, ptr [[DOTFCA_1_GEP]], align 4
+; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND:%.*]], ptr [[ALLOC0]], ptr [[ALLOC1]]
+; CHECK-NEXT: [[CAST:%.*]] = addrspacecast ptr [[SELECT]] to ptr addrspace(5)
+; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds [[PAIR]], ptr addrspace(5) [[CAST]], i32 0, i32 1
+; CHECK-NEXT: [[VALUE:%.*]] = load volatile i32, ptr addrspace(5) [[GEP]], align 4
; CHECK-NEXT: ret i32 [[VALUE]]
;
entry:
@@ -30,18 +54,27 @@ entry:
ret i32 %value
}
-; Do not unfold the address-space cast for volatile accesses. The shared
-; select/cast is smaller than duplicating the address calculation per field.
define i32 @select_gep_addrspace_volatile_as5_to_as0(i1 %cond) {
; CHECK-LABEL: @select_gep_addrspace_volatile_as5_to_as0(
-; CHECK: [[ALLOC0:%.*]] = alloca %pair, align 8, addrspace(5)
-; CHECK-NEXT: [[ALLOC1:%.*]] = alloca %pair, align 8, addrspace(5)
-; CHECK: [[SELECT:%.*]] = select i1 [[COND:%.*]], ptr addrspace(5) [[ALLOC0]], ptr addrspace(5) [[ALLOC1]]
-; CHECK-NEXT: [[CAST:%.*]] = addrspacecast ptr addrspace(5) [[SELECT]] to ptr
-; CHECK-NEXT: [[GEP0:%.*]] = getelementptr inbounds %pair, ptr [[CAST]], i32 0, i32 0
-; CHECK-NEXT: [[GEP1:%.*]] = getelementptr inbounds %pair, ptr [[CAST]], i32 0, i32 1
-; CHECK-NEXT: [[VAL0:%.*]] = load volatile i32, ptr [[GEP0]], align 4
-; CHECK-NEXT: [[VAL1:%.*]] = load volatile i32, ptr [[GEP1]], align 4
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[ALLOC0:%.*]] = alloca [[PAIR:%.*]], align 8, addrspace(5)
+; CHECK-NEXT: [[ALLOC1:%.*]] = alloca [[PAIR]], align 8, addrspace(5)
+; CHECK-NEXT: [[DOTFCA_0_GEP1:%.*]] = getelementptr inbounds [[PAIR]], ptr addrspace(5) [[ALLOC0]], i32 0, i32 0
+; CHECK-NEXT: store i32 0, ptr addrspace(5) [[DOTFCA_0_GEP1]], align 8
+; CHECK-NEXT: [[DOTFCA_1_GEP2:%.*]] = getelementptr inbounds [[PAIR]], ptr addrspace(5) [[ALLOC0]], i32 0, i32 1
+; CHECK-NEXT: store i32 1, ptr addrspace(5) [[DOTFCA_1_GEP2]], align 4
+; CHECK-NEXT: [[DOTFCA_0_GEP:%.*]] = getelementptr inbounds [[PAIR]], ptr addrspace(5) [[ALLOC1]], i32 0, i32 0
+; CHECK-NEXT: store i32 2, ptr addrspace(5) [[DOTFCA_0_GEP]], align 8
+; CHECK-NEXT: [[DOTFCA_1_GEP:%.*]] = getelementptr inbounds [[PAIR]], ptr addrspace(5) [[ALLOC1]], i32 0, i32 1
+; CHECK-NEXT: store i32 3, ptr addrspace(5) [[DOTFCA_1_GEP]], align 4
+; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND:%.*]], ptr addrspace(5) [[ALLOC0]], ptr addrspace(5) [[ALLOC1]]
+; CHECK-NEXT: [[CAST:%.*]] = addrspacecast ptr addrspace(5) [[SELECT]] to ptr
+; CHECK-NEXT: [[GEP0:%.*]] = getelementptr inbounds [[PAIR]], ptr [[CAST]], i32 0, i32 0
+; CHECK-NEXT: [[GEP1:%.*]] = getelementptr inbounds [[PAIR]], ptr [[CAST]], i32 0, i32 1
+; CHECK-NEXT: [[VAL0:%.*]] = load volatile i32, ptr [[GEP0]], align 4
+; CHECK-NEXT: [[VAL1:%.*]] = load volatile i32, ptr [[GEP1]], align 4
+; CHECK-NEXT: [[SUM:%.*]] = add i32 [[VAL0]], [[VAL1]]
+; CHECK-NEXT: ret i32 [[SUM]]
;
entry:
%alloc0 = alloca %pair, align 8, addrspace(5)
>From b713d7471be5109b3bcf03116778d32c8eab2a3d Mon Sep 17 00:00:00 2001
From: Daniel Donenfeld <ddonenfeld at nvidia.com>
Date: Wed, 23 Sep 2026 17:55:50 +0000
Subject: [PATCH 6/6] Fix issue with volatile change
---
llvm/lib/Transforms/Scalar/SROA.cpp | 6 ++--
llvm/test/Transforms/SROA/select-gep.ll | 47 ++++---------------------
2 files changed, 9 insertions(+), 44 deletions(-)
diff --git a/llvm/lib/Transforms/Scalar/SROA.cpp b/llvm/lib/Transforms/Scalar/SROA.cpp
index 10f46351c61dd..6cf72e72fa1a6 100644
--- a/llvm/lib/Transforms/Scalar/SROA.cpp
+++ b/llvm/lib/Transforms/Scalar/SROA.cpp
@@ -4474,6 +4474,9 @@ class AggLoadStoreRewriter : public InstVisitor<AggLoadStoreRewriter, bool> {
// will become constant after the transform.
Value *PtrOp = GEPI.getPointerOperand();
Instruction *Sel = dyn_cast<SelectInst>(PtrOp->stripPointerCasts());
+ bool CrossesAddressSpace =
+ Sel && PtrOp->getType()->getPointerAddressSpace() !=
+ Sel->getType()->getPointerAddressSpace();
unsigned SelOpNum = 0;
for (auto& Op : GEPI.indices()) {
if (auto *SI = dyn_cast<SelectInst>(Op)) {
@@ -4506,9 +4509,6 @@ class AggLoadStoreRewriter : public InstVisitor<AggLoadStoreRewriter, bool> {
// Do not duplicate address-space casts for volatile accesses. Unfolding the
// GEP can increase code size and register pressure.
- bool CrossesAddressSpace =
- Sel && PtrOp->getType()->getPointerAddressSpace() !=
- Sel->getType()->getPointerAddressSpace();
if (CrossesAddressSpace &&
any_of(GEPI.users(), [](User *U) {
auto *I = dyn_cast<Instruction>(U);
diff --git a/llvm/test/Transforms/SROA/select-gep.ll b/llvm/test/Transforms/SROA/select-gep.ll
index a9fc79f6ac737..fd3b7ad1578a2 100644
--- a/llvm/test/Transforms/SROA/select-gep.ll
+++ b/llvm/test/Transforms/SROA/select-gep.ll
@@ -347,32 +347,6 @@ 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
@@ -520,26 +494,17 @@ define i32 @test_select_fold_split_zero_gep(i1 %cond) {
}
-
-; 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: [[ALLOC2:%.*]] = alloca i32, align 8
; 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 0, ptr [[ALLOC2]], align 8
; 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:%.*]] = select i1 [[COND:%.*]], ptr [[ALLOC2]], ptr [[ALLOC1]]
; 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: [[ALLOC0_SROA_0_0_GEP_SROA_CAST7:%.*]] = getelementptr inbounds [[STRUCT_T:%.*]], ptr addrspace(5) [[ALLOC0_SROA_0_0_GEP_SROA_CAST8]], i32 0, i32 0
; 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: [[VAL2:%.*]] = select i1 [[COND]], i32 1, i32 3
; CHECK-NEXT: [[VAL3:%.*]] = add i32 [[VAL1]], [[VAL2]]
; CHECK-NEXT: ret i32 [[VAL3]]
;
@@ -552,7 +517,7 @@ define i32 @test_select_fold_split_volatile(i1 %cond) {
%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
+ %val2 = load i32, ptr addrspace(5) %gep1
%val3 = add i32 %val1, %val2
ret i32 %val3
}
More information about the llvm-commits
mailing list