[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