[llvm] 03e6d9d - [SROA] For non-speculatable `load`s of `select`s -- split block, insert then/else blocks, form two-entry PHI node

Roman Lebedev via llvm-commits llvm-commits at lists.llvm.org
Thu Dec 8 05:51:59 PST 2022


Author: Roman Lebedev
Date: 2022-12-08T16:51:32+03:00
New Revision: 03e6d9d9d1d48e43f3efc35eb75369b90d4510d5

URL: https://github.com/llvm/llvm-project/commit/03e6d9d9d1d48e43f3efc35eb75369b90d4510d5
DIFF: https://github.com/llvm/llvm-project/commit/03e6d9d9d1d48e43f3efc35eb75369b90d4510d5.diff

LOG: [SROA] For non-speculatable `load`s of `select`s -- split block, insert then/else blocks, form two-entry PHI node

Currently, SROA is CFG-preserving.
Not doing so does not affect any pipeline test. (???)
Internally, SROA requires Dominator Tree, and uses it solely for the final `-mem2reg` call.

By design, we can't really SROA alloca if their address escapes somehow,
but we have logic to deal with `load` of `select`/`PHI`,
where at least one of the possible addresses prevents promotion,
by speculating the `load`s and `select`ing between loaded values.

As one would expect, that requires ensuring that the speculation is actually legal.
Even ignoring complexity bailouts, that logic does not deal with everything,
e.g. `isSafeToLoadUnconditionally()` does not recurse into hands of `select`.
There can also be cases where the load is genuinely non-speculate.

So if we can't prove that the load can be speculated,
unfold the select, produce two-entry phi node, and perform predicated load.

Now, that transformation must obviously update Dominator Tree,
since we require it later on. Doing so is trivial.
Additionally, we don't want to do this for the final SROA invocation (D136806).

In the end, this ends up having negative (!) compile-time cost:
https://llvm-compile-time-tracker.com/compare.php?from=c6d7e80ec4c17a415673b1cfd25924f98ac83608&to=ddf9600365093ea50d7e278696cbfa01641c959d&stat=instructions:u

Though indeed, this only deals with `select`s, `PHI`s are still using speculation.

Should we update some more analysis?

Reviewed By: arsenm

Differential Revision: https://reviews.llvm.org/D138238

Added: 
    

Modified: 
    llvm/include/llvm/Transforms/Scalar.h
    llvm/include/llvm/Transforms/Scalar/SROA.h
    llvm/include/llvm/Transforms/Utils/BasicBlockUtils.h
    llvm/lib/Passes/PassBuilder.cpp
    llvm/lib/Passes/PassBuilderPipelines.cpp
    llvm/lib/Passes/PassRegistry.def
    llvm/lib/Transforms/Scalar/SROA.cpp
    llvm/lib/Transforms/Utils/BasicBlockUtils.cpp
    llvm/test/Transforms/SROA/2009-02-20-InstCombine-SROA.ll
    llvm/test/Transforms/SROA/address-spaces.ll
    llvm/test/Transforms/SROA/addrspacecast.ll
    llvm/test/Transforms/SROA/alignment.ll
    llvm/test/Transforms/SROA/alloca-address-space.ll
    llvm/test/Transforms/SROA/assume.ll
    llvm/test/Transforms/SROA/basictest.ll
    llvm/test/Transforms/SROA/big-endian.ll
    llvm/test/Transforms/SROA/dbg-addr-diamond.ll
    llvm/test/Transforms/SROA/dbg-inline.ll
    llvm/test/Transforms/SROA/dbg-single-piece.ll
    llvm/test/Transforms/SROA/dead-inst.ll
    llvm/test/Transforms/SROA/fca.ll
    llvm/test/Transforms/SROA/ignore-droppable.ll
    llvm/test/Transforms/SROA/invariant-group.ll
    llvm/test/Transforms/SROA/irregular-type.ll
    llvm/test/Transforms/SROA/lifetime-intrinsic.ll
    llvm/test/Transforms/SROA/mem-par-metadata-sroa-cast.ll
    llvm/test/Transforms/SROA/mem-par-metadata-sroa.ll
    llvm/test/Transforms/SROA/non-capturing-call-readonly.ll
    llvm/test/Transforms/SROA/non-integral-pointers.ll
    llvm/test/Transforms/SROA/phi-and-select.ll
    llvm/test/Transforms/SROA/phi-catchswitch.ll
    llvm/test/Transforms/SROA/phi-gep.ll
    llvm/test/Transforms/SROA/phi-speculate-different-load-types.ll
    llvm/test/Transforms/SROA/phi-with-duplicate-pred.ll
    llvm/test/Transforms/SROA/pointer-offset-size.ll
    llvm/test/Transforms/SROA/ppcf128-no-fold.ll
    llvm/test/Transforms/SROA/pr26972.ll
    llvm/test/Transforms/SROA/pr37267.ll
    llvm/test/Transforms/SROA/preserve-nonnull.ll
    llvm/test/Transforms/SROA/scalable-vectors.ll
    llvm/test/Transforms/SROA/select-gep.ll
    llvm/test/Transforms/SROA/select-load.ll
    llvm/test/Transforms/SROA/slice-order-independence.ll
    llvm/test/Transforms/SROA/slice-width.ll
    llvm/test/Transforms/SROA/sroa-common-type-fail-promotion.ll
    llvm/test/Transforms/SROA/std-clamp.ll
    llvm/test/Transforms/SROA/tbaa-struct.ll
    llvm/test/Transforms/SROA/tbaa-struct2.ll
    llvm/test/Transforms/SROA/tbaa-subload.ll
    llvm/test/Transforms/SROA/vector-conversion.ll
    llvm/test/Transforms/SROA/vector-lifetime-intrinsic.ll
    llvm/test/Transforms/SROA/vector-promotion-different-size.ll
    llvm/test/Transforms/SROA/vector-promotion.ll
    llvm/test/Transforms/SROA/vectors-of-pointers.ll

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Transforms/Scalar.h b/llvm/include/llvm/Transforms/Scalar.h
index 85263383b6cab..0eebb63ce63fd 100644
--- a/llvm/include/llvm/Transforms/Scalar.h
+++ b/llvm/include/llvm/Transforms/Scalar.h
@@ -105,7 +105,7 @@ FunctionPass *createBitTrackingDCEPass();
 //
 // SROA - Replace aggregates or pieces of aggregates with scalar SSA values.
 //
-FunctionPass *createSROAPass();
+FunctionPass *createSROAPass(bool PreserveCFG = true);
 
 //===----------------------------------------------------------------------===//
 //

diff  --git a/llvm/include/llvm/Transforms/Scalar/SROA.h b/llvm/include/llvm/Transforms/Scalar/SROA.h
index b74c45e71d955..85b75c4d4640e 100644
--- a/llvm/include/llvm/Transforms/Scalar/SROA.h
+++ b/llvm/include/llvm/Transforms/Scalar/SROA.h
@@ -1,4 +1,4 @@
-//===- SROA.h - Scalar Replacement Of Aggregates ----------------*- C++ -*-===//
+//===- SROA.h - Scalar Replacement Of Aggregates ----------------*- C++ -*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -15,6 +15,8 @@
 #ifndef LLVM_TRANSFORMS_SCALAR_SROA_H
 #define LLVM_TRANSFORMS_SCALAR_SROA_H
 
+#include "llvm/ADT/MapVector.h"
+#include "llvm/ADT/PointerIntPair.h"
 #include "llvm/ADT/SetVector.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/IR/PassManager.h"
@@ -24,8 +26,10 @@
 namespace llvm {
 
 class AllocaInst;
+class LoadInst;
 class AssumptionCache;
 class DominatorTree;
+class DomTreeUpdater;
 class Function;
 class LLVMContext;
 class PHINode;
@@ -41,8 +45,31 @@ class AllocaSlices;
 class Partition;
 class SROALegacyPass;
 
+class SelectHandSpeculativity {
+  unsigned char Storage = 0;
+  using TrueVal = Bitfield::Element<bool, 0, 1>;  // Low 0'th bit.
+  using FalseVal = Bitfield::Element<bool, 1, 1>; // Low 1'th bit.
+public:
+  SelectHandSpeculativity() = default;
+  SelectHandSpeculativity &setAsSpeculatable(bool isTrueVal);
+  bool isSpeculatable(bool isTrueVal) const;
+  bool areAllSpeculatable() const;
+  bool areAnySpeculatable() const;
+  bool areNoneSpeculatable() const;
+  // For interop as int half of PointerIntPair.
+  explicit operator intptr_t() const { return static_cast<intptr_t>(Storage); }
+  explicit SelectHandSpeculativity(intptr_t Storage_) : Storage(Storage_) {}
+};
+static_assert(sizeof(SelectHandSpeculativity) == sizeof(unsigned char));
+
+using PossiblySpeculatableLoad =
+    PointerIntPair<LoadInst *, 2, sroa::SelectHandSpeculativity>;
+using PossiblySpeculatableLoads = SmallVector<PossiblySpeculatableLoad, 2>;
+
 } // end namespace sroa
 
+enum class SROAOptions : bool { ModifyCFG, PreserveCFG };
+
 /// An optimization pass providing Scalar Replacement of Aggregates.
 ///
 /// This pass takes allocations which can be completely analyzed (that is, they
@@ -63,8 +90,9 @@ class SROALegacyPass;
 ///    SSA vector values.
 class SROAPass : public PassInfoMixin<SROAPass> {
   LLVMContext *C = nullptr;
-  DominatorTree *DT = nullptr;
+  DomTreeUpdater *DTU = nullptr;
   AssumptionCache *AC = nullptr;
+  const bool PreserveCFG;
 
   /// Worklist of alloca instructions to simplify.
   ///
@@ -98,27 +126,50 @@ class SROAPass : public PassInfoMixin<SROAPass> {
   /// All of these PHIs have been checked for the safety of speculation and by
   /// being speculated will allow promoting allocas currently in the promotable
   /// queue.
-  SetVector<PHINode *, SmallVector<PHINode *, 2>> SpeculatablePHIs;
+  SetVector<PHINode *, SmallVector<PHINode *, 8>> SpeculatablePHIs;
 
-  /// A worklist of select instructions to speculate prior to promoting
+  /// A worklist of select instructions to rewrite prior to promoting
   /// allocas.
+  SmallMapVector<SelectInst *, sroa::PossiblySpeculatableLoads, 8>
+      SelectsToRewrite;
+
+  /// Select instructions that use an alloca and are subsequently loaded can be
+  /// rewritten to load both input pointers and then select between the result,
+  /// allowing the load of the alloca to be promoted.
+  /// From this:
+  ///   %P2 = select i1 %cond, ptr %Alloca, ptr %Other
+  ///   %V = load <type>, ptr %P2
+  /// to:
+  ///   %V1 = load <type>, ptr %Alloca      -> will be mem2reg'd
+  ///   %V2 = load <type>, ptr %Other
+  ///   %V = select i1 %cond, <type> %V1, <type> %V2
   ///
-  /// All of these select instructions have been checked for the safety of
-  /// speculation and by being speculated will allow promoting allocas
-  /// currently in the promotable queue.
-  SetVector<SelectInst *, SmallVector<SelectInst *, 2>> SpeculatableSelects;
+  /// We can do this to a select if its only uses are loads
+  /// and if either the operand to the select can be loaded unconditionally,
+  ///        or if we are allowed to perform CFG modifications.
+  /// If found an intervening bitcast with a single use of the load,
+  /// allow the promotion.
+  static std::optional<sroa::PossiblySpeculatableLoads>
+  isSafeSelectToSpeculate(SelectInst &SI, bool PreserveCFG);
 
 public:
-  SROAPass() = default;
+  /// If \p PreserveCFG is set, then the pass is not allowed to modify CFG
+  /// in any way, even if it would update CFG analyses.
+  SROAPass(SROAOptions PreserveCFG);
 
   /// Run the pass over the function.
   PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
 
+  void printPipeline(raw_ostream &OS,
+                     function_ref<StringRef(StringRef)> MapClassName2PassName);
+
 private:
   friend class sroa::AllocaSliceRewriter;
   friend class sroa::SROALegacyPass;
 
   /// Helper used by both the public run method and by the legacy pass.
+  PreservedAnalyses runImpl(Function &F, DomTreeUpdater &RunDTU,
+                            AssumptionCache &RunAC);
   PreservedAnalyses runImpl(Function &F, DominatorTree &RunDT,
                             AssumptionCache &RunAC);
 
@@ -126,7 +177,7 @@ class SROAPass : public PassInfoMixin<SROAPass> {
   AllocaInst *rewritePartition(AllocaInst &AI, sroa::AllocaSlices &AS,
                                sroa::Partition &P);
   bool splitAlloca(AllocaInst &AI, sroa::AllocaSlices &AS);
-  bool runOnAlloca(AllocaInst &AI);
+  std::pair<bool /*Changed*/, bool /*CFGChanged*/> runOnAlloca(AllocaInst &AI);
   void clobberUse(Use &U);
   bool deleteDeadInstructions(SmallPtrSetImpl<AllocaInst *> &DeletedAllocas);
   bool promoteAllocas(Function &F);

diff  --git a/llvm/include/llvm/Transforms/Utils/BasicBlockUtils.h b/llvm/include/llvm/Transforms/Utils/BasicBlockUtils.h
index 8215fe492bf31..9d921496ff107 100644
--- a/llvm/include/llvm/Transforms/Utils/BasicBlockUtils.h
+++ b/llvm/include/llvm/Transforms/Utils/BasicBlockUtils.h
@@ -464,10 +464,13 @@ Instruction *SplitBlockAndInsertIfThen(Value *Cond, Instruction *SplitBefore,
 ///     ElseBlock
 ///   SplitBefore
 ///   Tail
+///
+/// Updates DT if given.
 void SplitBlockAndInsertIfThenElse(Value *Cond, Instruction *SplitBefore,
                                    Instruction **ThenTerm,
                                    Instruction **ElseTerm,
-                                   MDNode *BranchWeights = nullptr);
+                                   MDNode *BranchWeights = nullptr,
+                                   DomTreeUpdater *DTU = nullptr);
 
 /// Check whether BB is the merge point of a if-region.
 /// If so, return the branch instruction that determines which entry into

diff  --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index e8a17a6a962e0..152c061fa20b5 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -836,6 +836,19 @@ Expected<GVNOptions> parseGVNOptions(StringRef Params) {
   return Result;
 }
 
+Expected<SROAOptions> parseSROAOptions(StringRef Params) {
+  if (Params.empty() || Params == "modify-cfg")
+    return SROAOptions::ModifyCFG;
+  if (Params == "preserve-cfg")
+    return SROAOptions::PreserveCFG;
+  return make_error<StringError>(
+      formatv("invalid SROA pass parameter '{0}' (either preserve-cfg or "
+              "modify-cfg can be specified)",
+              Params)
+          .str(),
+      inconvertibleErrorCode());
+}
+
 Expected<StackLifetime::LivenessType>
 parseStackLifetimeOptions(StringRef Params) {
   StackLifetime::LivenessType Result = StackLifetime::LivenessType::May;

diff  --git a/llvm/lib/Passes/PassBuilderPipelines.cpp b/llvm/lib/Passes/PassBuilderPipelines.cpp
index 022861318ce95..1b58084677829 100644
--- a/llvm/lib/Passes/PassBuilderPipelines.cpp
+++ b/llvm/lib/Passes/PassBuilderPipelines.cpp
@@ -328,7 +328,7 @@ PassBuilder::buildO1FunctionSimplificationPipeline(OptimizationLevel Level,
 
   // Form SSA out of local memory accesses after breaking apart aggregates into
   // scalars.
-  FPM.addPass(SROAPass());
+  FPM.addPass(SROAPass(SROAOptions::ModifyCFG));
 
   // Catch trivial redundancies
   FPM.addPass(EarlyCSEPass(true /* Enable mem-ssa. */));
@@ -427,7 +427,7 @@ PassBuilder::buildO1FunctionSimplificationPipeline(OptimizationLevel Level,
                                               /*UseBlockFrequencyInfo=*/false));
 
   // Delete small array after loop unroll.
-  FPM.addPass(SROAPass());
+  FPM.addPass(SROAPass(SROAOptions::ModifyCFG));
 
   // Specially optimize memory movement as it doesn't look like dataflow in SSA.
   FPM.addPass(MemCpyOptPass());
@@ -478,7 +478,7 @@ PassBuilder::buildFunctionSimplificationPipeline(OptimizationLevel Level,
 
   // Form SSA out of local memory accesses after breaking apart aggregates into
   // scalars.
-  FPM.addPass(SROAPass());
+  FPM.addPass(SROAPass(SROAOptions::ModifyCFG));
 
   // Catch trivial redundancies
   FPM.addPass(EarlyCSEPass(true /* Enable mem-ssa. */));
@@ -613,7 +613,7 @@ PassBuilder::buildFunctionSimplificationPipeline(OptimizationLevel Level,
                                               /*UseBlockFrequencyInfo=*/false));
 
   // Delete small array after loop unroll.
-  FPM.addPass(SROAPass());
+  FPM.addPass(SROAPass(SROAOptions::ModifyCFG));
 
   // Try vectorization/scalarization transforms that are both improvements
   // themselves and can allow further folds with GVN and InstCombine.
@@ -714,7 +714,7 @@ void PassBuilder::addPGOInstrPasses(ModulePassManager &MPM,
     CGSCCPassManager &CGPipeline = MIWP.getPM();
 
     FunctionPassManager FPM;
-    FPM.addPass(SROAPass());
+    FPM.addPass(SROAPass(SROAOptions::ModifyCFG));
     FPM.addPass(EarlyCSEPass()); // Catch trivial redundancies.
     FPM.addPass(SimplifyCFGPass(SimplifyCFGOptions().convertSwitchRangeToICmp(
         true)));                    // Merge & remove basic blocks.
@@ -963,7 +963,7 @@ PassBuilder::buildModuleSimplificationPipeline(OptimizationLevel Level,
   // Compare/branch metadata may alter the behavior of passes like SimplifyCFG.
   EarlyFPM.addPass(LowerExpectIntrinsicPass());
   EarlyFPM.addPass(SimplifyCFGPass());
-  EarlyFPM.addPass(SROAPass());
+  EarlyFPM.addPass(SROAPass(SROAOptions::ModifyCFG));
   EarlyFPM.addPass(EarlyCSEPass());
   if (Level == OptimizationLevel::O3)
     EarlyFPM.addPass(CallSiteSplittingPass());
@@ -1113,7 +1113,10 @@ void PassBuilder::addVectorPasses(OptimizationLevel Level,
     // Now that we are done with loop unrolling, be it either by LoopVectorizer,
     // or LoopUnroll passes, some variable-offset GEP's into alloca's could have
     // become constant-offset, thus enabling SROA and alloca promotion. Do so.
-    FPM.addPass(SROAPass());
+    // NOTE: we are very late in the pipeline, and we don't have any LICM
+    // or SimplifyCFG passes scheduled after us, that would cleanup
+    // the CFG mess this may created if allowed to modify CFG, so forbid that.
+    FPM.addPass(SROAPass(SROAOptions::PreserveCFG));
   }
 
   if (!IsFullLTO) {
@@ -1204,7 +1207,10 @@ void PassBuilder::addVectorPasses(OptimizationLevel Level,
     // Now that we are done with loop unrolling, be it either by LoopVectorizer,
     // or LoopUnroll passes, some variable-offset GEP's into alloca's could have
     // become constant-offset, thus enabling SROA and alloca promotion. Do so.
-    FPM.addPass(SROAPass());
+    // NOTE: we are very late in the pipeline, and we don't have any LICM
+    // or SimplifyCFG passes scheduled after us, that would cleanup
+    // the CFG mess this may created if allowed to modify CFG, so forbid that.
+    FPM.addPass(SROAPass(SROAOptions::PreserveCFG));
     FPM.addPass(InstCombinePass());
     FPM.addPass(
         RequireAnalysisPass<OptimizationRemarkEmitterAnalysis, Function>());
@@ -1745,7 +1751,7 @@ PassBuilder::buildLTODefaultPipeline(OptimizationLevel Level,
   }
 
   // Break up allocas
-  FPM.addPass(SROAPass());
+  FPM.addPass(SROAPass(SROAOptions::ModifyCFG));
 
   // LTO provides additional opportunities for tailcall elimination due to
   // link-time inlining, and visibility of nocapture attribute.

diff  --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index 6782517834e5c..dc425569c31dd 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -376,7 +376,6 @@ FUNCTION_PASS("sink", SinkingPass())
 FUNCTION_PASS("slp-vectorizer", SLPVectorizerPass())
 FUNCTION_PASS("slsr", StraightLineStrengthReducePass())
 FUNCTION_PASS("speculative-execution", SpeculativeExecutionPass())
-FUNCTION_PASS("sroa", SROAPass())
 FUNCTION_PASS("strip-gc-relocates", StripGCRelocates())
 FUNCTION_PASS("structurizecfg", StructurizeCFGPass())
 FUNCTION_PASS("tailcallelim", TailCallElimPass())
@@ -473,6 +472,13 @@ FUNCTION_PASS_WITH_PARAMS("gvn",
                           "no-load-pre;load-pre;"
                           "no-split-backedge-load-pre;split-backedge-load-pre;"
                           "no-memdep;memdep")
+FUNCTION_PASS_WITH_PARAMS("sroa",
+                          "SROAPass",
+                          [](SROAOptions PreserveCFG) {
+                            return SROAPass(PreserveCFG);
+                          },
+                          parseSROAOptions,
+                          "preserve-cfg;modify-cfg")
 FUNCTION_PASS_WITH_PARAMS("print<stack-lifetime>",
                           "StackLifetimePrinterPass",
                            [](StackLifetime::LivenessType Type) {

diff  --git a/llvm/lib/Transforms/Scalar/SROA.cpp b/llvm/lib/Transforms/Scalar/SROA.cpp
index 6e8e30329e4b1..07bcddc3ab6e4 100644
--- a/llvm/lib/Transforms/Scalar/SROA.cpp
+++ b/llvm/lib/Transforms/Scalar/SROA.cpp
@@ -38,6 +38,7 @@
 #include "llvm/ADT/iterator.h"
 #include "llvm/ADT/iterator_range.h"
 #include "llvm/Analysis/AssumptionCache.h"
+#include "llvm/Analysis/DomTreeUpdater.h"
 #include "llvm/Analysis/GlobalsModRef.h"
 #include "llvm/Analysis/Loads.h"
 #include "llvm/Analysis/PtrUseVisitor.h"
@@ -78,6 +79,7 @@
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/Transforms/Scalar.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
 #include "llvm/Transforms/Utils/Local.h"
 #include "llvm/Transforms/Utils/PromoteMemToReg.h"
 #include <algorithm>
@@ -104,6 +106,8 @@ STATISTIC(MaxUsesPerAllocaPartition, "Maximum number of uses of a partition");
 STATISTIC(NumNewAllocas, "Number of new, smaller allocas introduced");
 STATISTIC(NumPromoted, "Number of allocas promoted to SSA values");
 STATISTIC(NumLoadsSpeculated, "Number of loads speculated to allow promotion");
+STATISTIC(NumLoadsPredicated,
+          "Number of loads rewritten into predicated loads to allow promotion");
 STATISTIC(NumDeleted, "Number of instructions deleted");
 STATISTIC(NumVectorized, "Number of vectorized aggregates");
 
@@ -111,7 +115,6 @@ STATISTIC(NumVectorized, "Number of vectorized aggregates");
 /// GEPs.
 static cl::opt<bool> SROAStrictInbounds("sroa-strict-inbounds", cl::init(false),
                                         cl::Hidden);
-
 namespace {
 
 /// A custom IRBuilder inserter which prefixes all names, but only in
@@ -1306,24 +1309,53 @@ static void speculatePHINodeLoads(IRBuilderTy &IRB, PHINode &PN) {
   PN.eraseFromParent();
 }
 
-/// Select instructions that use an alloca and are subsequently loaded can be
-/// rewritten to load both input pointers and then select between the result,
-/// allowing the load of the alloca to be promoted.
-/// From this:
-///   %P2 = select i1 %cond, i32* %Alloca, i32* %Other
-///   %V = load i32* %P2
-/// to:
-///   %V1 = load i32* %Alloca      -> will be mem2reg'd
-///   %V2 = load i32* %Other
-///   %V = select i1 %cond, i32 %V1, i32 %V2
-///
-/// We can do this to a select if its only uses are loads and if the operand
-/// to the select can be loaded unconditionally. If found an intervening bitcast
-/// with a single use of the load, allow the promotion.
-static bool isSafeSelectToSpeculate(SelectInst &SI) {
-  Value *TValue = SI.getTrueValue();
-  Value *FValue = SI.getFalseValue();
+sroa::SelectHandSpeculativity &
+sroa::SelectHandSpeculativity::setAsSpeculatable(bool isTrueVal) {
+  if (isTrueVal)
+    Bitfield::set<sroa::SelectHandSpeculativity::TrueVal>(Storage, true);
+  else
+    Bitfield::set<sroa::SelectHandSpeculativity::FalseVal>(Storage, true);
+  return *this;
+}
+
+bool sroa::SelectHandSpeculativity::isSpeculatable(bool isTrueVal) const {
+  return isTrueVal
+             ? Bitfield::get<sroa::SelectHandSpeculativity::TrueVal>(Storage)
+             : Bitfield::get<sroa::SelectHandSpeculativity::FalseVal>(Storage);
+}
+
+bool sroa::SelectHandSpeculativity::areAllSpeculatable() const {
+  return isSpeculatable(/*isTrueVal=*/true) &&
+         isSpeculatable(/*isTrueVal=*/false);
+}
+
+bool sroa::SelectHandSpeculativity::areAnySpeculatable() const {
+  return isSpeculatable(/*isTrueVal=*/true) ||
+         isSpeculatable(/*isTrueVal=*/false);
+}
+bool sroa::SelectHandSpeculativity::areNoneSpeculatable() const {
+  return !areAnySpeculatable();
+}
+
+static sroa::SelectHandSpeculativity
+isSafeLoadOfSelectToSpeculate(LoadInst &LI, SelectInst &SI, bool PreserveCFG) {
+  assert(LI.isSimple() && "Only for simple loads");
+  sroa::SelectHandSpeculativity Spec;
+
   const DataLayout &DL = SI.getModule()->getDataLayout();
+  for (Value *Value : {SI.getTrueValue(), SI.getFalseValue()})
+    if (isSafeToLoadUnconditionally(Value, LI.getType(), LI.getAlign(), DL,
+                                    &LI))
+      Spec.setAsSpeculatable(/*isTrueVal=*/Value == SI.getTrueValue());
+    else if (PreserveCFG)
+      return Spec;
+
+  return Spec;
+}
+
+std::optional<sroa::PossiblySpeculatableLoads>
+SROAPass::isSafeSelectToSpeculate(SelectInst &SI, bool PreserveCFG) {
+  PossiblySpeculatableLoads Loads;
 
   for (User *U : SI.users()) {
     LoadInst *LI;
@@ -1333,75 +1365,136 @@ static bool isSafeSelectToSpeculate(SelectInst &SI) {
     else
       LI = dyn_cast<LoadInst>(U);
 
-    if (!LI || !LI->isSimple())
-      return false;
+    // Note that atomic loads can be transformed;
+    // atomic semantics do not have any meaning for a local alloca.
+    if (!LI || LI->isVolatile())
+      return {}; // Give up on this `select`.
 
-    // Both operands to the select need to be dereferenceable, either
-    // absolutely (e.g. allocas) or at this point because we can see other
-    // accesses to it.
-    if (!isSafeToLoadUnconditionally(TValue, LI->getType(),
-                                     LI->getAlign(), DL, LI))
-      return false;
-    if (!isSafeToLoadUnconditionally(FValue, LI->getType(),
-                                     LI->getAlign(), DL, LI))
-      return false;
+    PossiblySpeculatableLoad Load(LI);
+
+    if (!LI->isSimple()) {
+      // If the `load` is not simple, we can't speculatively execute it,
+      // but we could handle this via a CFG modification. But can we?
+      if (PreserveCFG)
+        return {}; // Give up on this `select`.
+      Loads.emplace_back(Load);
+      continue;
+    }
+
+    sroa::SelectHandSpeculativity Spec =
+        isSafeLoadOfSelectToSpeculate(*LI, SI, PreserveCFG);
+    if (PreserveCFG && !Spec.areAllSpeculatable())
+      return {}; // Give up on this `select`.
+
+    Load.setInt(Spec);
+    Loads.emplace_back(Load);
   }
 
-  return true;
+  return Loads;
 }
 
-static void speculateSelectInstLoads(IRBuilderTy &IRB, SelectInst &SI) {
-  LLVM_DEBUG(dbgs() << "    original: " << SI << "\n");
+static void speculateSelectInstLoads(SelectInst &SI, LoadInst &LI,
+                                     IRBuilderTy &IRB) {
+  LLVM_DEBUG(dbgs() << "    original load: " << SI << "\n");
 
   IRB.SetInsertPoint(&SI);
   Value *TV = SI.getTrueValue();
   Value *FV = SI.getFalseValue();
-  // Replace the loads of the select with a select of two loads.
-  while (!SI.use_empty()) {
-    LoadInst *LI;
-    BitCastInst *BC = dyn_cast<BitCastInst>(SI.user_back());
-    if (BC) {
-      assert(BC->hasOneUse() && "Bitcast should have a single use.");
-      LI = cast<LoadInst>(BC->user_back());
-    } else {
-      LI = cast<LoadInst>(SI.user_back());
-    }
+  // Replace the given load of the select with a select of two loads.
+
+  assert(LI.isSimple() && "We only speculate simple loads");
+
+  IRB.SetInsertPoint(&LI);
+  LoadInst *TL =
+      IRB.CreateAlignedLoad(LI.getType(), TV, LI.getAlign(),
+                            LI.getName() + ".sroa.speculate.load.true");
+  LoadInst *FL =
+      IRB.CreateAlignedLoad(LI.getType(), FV, LI.getAlign(),
+                            LI.getName() + ".sroa.speculate.load.false");
+  NumLoadsSpeculated += 2;
+
+  // Transfer alignment and AA info if present.
+  TL->setAlignment(LI.getAlign());
+  FL->setAlignment(LI.getAlign());
+
+  AAMDNodes Tags = LI.getAAMetadata();
+  if (Tags) {
+    TL->setAAMetadata(Tags);
+    FL->setAAMetadata(Tags);
+  }
 
-    assert(LI->isSimple() && "We only speculate simple loads");
+  Value *V = IRB.CreateSelect(SI.getCondition(), TL, FL,
+                              LI.getName() + ".sroa.speculated");
 
-    IRB.SetInsertPoint(LI);
-    Value *NewTV =
-        BC ? IRB.CreateBitCast(TV, BC->getType(), TV->getName() + ".sroa.cast")
-           : TV;
-    Value *NewFV =
-        BC ? IRB.CreateBitCast(FV, BC->getType(), FV->getName() + ".sroa.cast")
-           : FV;
-    LoadInst *TL = IRB.CreateLoad(LI->getType(), NewTV,
-                                  LI->getName() + ".sroa.speculate.load.true");
-    LoadInst *FL = IRB.CreateLoad(LI->getType(), NewFV,
-                                  LI->getName() + ".sroa.speculate.load.false");
-    NumLoadsSpeculated += 2;
-
-    // Transfer alignment and AA info if present.
-    TL->setAlignment(LI->getAlign());
-    FL->setAlignment(LI->getAlign());
-
-    AAMDNodes Tags = LI->getAAMetadata();
-    if (Tags) {
-      TL->setAAMetadata(Tags);
-      FL->setAAMetadata(Tags);
-    }
+  LLVM_DEBUG(dbgs() << "          speculated to: " << *V << "\n");
+  LI.replaceAllUsesWith(V);
+}
 
-    Value *V = IRB.CreateSelect(SI.getCondition(), TL, FL,
-                                LI->getName() + ".sroa.speculated");
+static void rewriteLoadOfSelect(SelectInst &SI, LoadInst &LI,
+                                sroa::SelectHandSpeculativity Spec,
+                                DomTreeUpdater &DTU) {
+  LLVM_DEBUG(dbgs() << "    original load: " << SI << "\n");
+  BasicBlock *Head = LI.getParent();
+  Instruction *ThenTerm = nullptr;
+  Instruction *ElseTerm = nullptr;
+  if (Spec.areNoneSpeculatable())
+    SplitBlockAndInsertIfThenElse(SI.getCondition(), &LI, &ThenTerm, &ElseTerm,
+                                  SI.getMetadata(LLVMContext::MD_prof), &DTU);
+  else {
+    SplitBlockAndInsertIfThen(SI.getCondition(), &LI, /*Unreachable=*/false,
+                              SI.getMetadata(LLVMContext::MD_prof), &DTU,
+                              /*LI=*/nullptr, /*ThenBlock=*/nullptr);
+    if (Spec.isSpeculatable(/*isTrueVal=*/true))
+      cast<BranchInst>(Head->getTerminator())->swapSuccessors();
+  }
+  auto *HeadBI = cast<BranchInst>(Head->getTerminator());
+  Spec = {}; // Do not use `Spec` beyond this point.
+  BasicBlock *Tail = LI.getParent();
+  Tail->setName(Head->getName() + ".cont");
+  auto *PN = PHINode::Create(LI.getType(), 2, "", &LI);
+  for (BasicBlock *SuccBB : successors(Head)) {
+    bool IsThen = SuccBB == HeadBI->getSuccessor(0);
+    int SuccIdx = IsThen ? 0 : 1;
+    auto *NewLoadBB = SuccBB == Tail ? Head : SuccBB;
+    if (NewLoadBB != Head) {
+      NewLoadBB->setName(Head->getName() + (IsThen ? ".then" : ".else"));
+      ++NumLoadsPredicated;
+    } else
+      ++NumLoadsSpeculated;
+    auto *CondLoad = cast<LoadInst>(LI.clone());
+    CondLoad->insertBefore(NewLoadBB->getTerminator());
+    CondLoad->setOperand(0, SI.getOperand(1 + SuccIdx));
+    CondLoad->setName(LI.getName() + (IsThen ? ".then" : ".else") + ".val");
+    PN->addIncoming(CondLoad, NewLoadBB);
+  }
+  PN->takeName(&LI);
+  LLVM_DEBUG(dbgs() << "          to: " << *PN << "\n");
+  LI.replaceAllUsesWith(PN);
+}
 
-    LLVM_DEBUG(dbgs() << "          speculated to: " << *V << "\n");
-    LI->replaceAllUsesWith(V);
+static bool rewriteSelectInstLoads(SelectInst &SI,
+                                   const sroa::PossiblySpeculatableLoads &Loads,
+                                   IRBuilderTy &IRB, DomTreeUpdater *DTU) {
+  bool CFGChanged = false;
+  LLVM_DEBUG(dbgs() << "    original select: " << SI << "\n");
+
+  for (const PossiblySpeculatableLoad &Load : Loads) {
+    LoadInst *LI = Load.getPointer();
+    sroa::SelectHandSpeculativity Spec = Load.getInt();
+    if (Spec.areAllSpeculatable()) {
+      speculateSelectInstLoads(SI, *LI, IRB);
+    } else {
+      assert("Should not get here when not allowed to modify the CFG!");
+      rewriteLoadOfSelect(SI, *LI, Spec, *DTU);
+      CFGChanged = true;
+    }
     LI->eraseFromParent();
-    if (BC)
-      BC->eraseFromParent();
   }
+
+  for (User *U : make_early_inc_range(SI.users()))
+    cast<BitCastInst>(U)->eraseFromParent();
   SI.eraseFromParent();
+  return CFGChanged;
 }
 
 /// Build a GEP out of a base pointer and indices.
@@ -4397,13 +4490,21 @@ AllocaInst *SROAPass::rewritePartition(AllocaInst &AI, AllocaSlices &AS,
       break;
     }
 
-  for (SelectInst *Sel : SelectUsers)
-    if (!isSafeSelectToSpeculate(*Sel)) {
+  SmallVector<std::pair<SelectInst *, PossiblySpeculatableLoads>, 2>
+      NewSelectsToRewrite;
+  NewSelectsToRewrite.reserve(SelectUsers.size());
+  for (SelectInst *Sel : SelectUsers) {
+    std::optional<PossiblySpeculatableLoads> Loads =
+        isSafeSelectToSpeculate(*Sel, PreserveCFG);
+    if (!Loads) {
       Promotable = false;
       PHIUsers.clear();
       SelectUsers.clear();
+      NewSelectsToRewrite.clear();
       break;
     }
+    NewSelectsToRewrite.emplace_back(std::make_pair(Sel, *Loads));
+  }
 
   if (Promotable) {
     for (Use *U : AS.getDeadUsesIfPromotable()) {
@@ -4422,8 +4523,12 @@ AllocaInst *SROAPass::rewritePartition(AllocaInst &AI, AllocaSlices &AS,
       // next iteration.
       for (PHINode *PHIUser : PHIUsers)
         SpeculatablePHIs.insert(PHIUser);
-      for (SelectInst *SelectUser : SelectUsers)
-        SpeculatableSelects.insert(SelectUser);
+      SelectsToRewrite.reserve(SelectsToRewrite.size() +
+                               NewSelectsToRewrite.size());
+      for (auto &&KV : llvm::make_range(
+               std::make_move_iterator(NewSelectsToRewrite.begin()),
+               std::make_move_iterator(NewSelectsToRewrite.end())))
+        SelectsToRewrite.insert(std::move(KV));
       Worklist.insert(NewAI);
     }
   } else {
@@ -4637,14 +4742,19 @@ void SROAPass::clobberUse(Use &U) {
 /// This analyzes the alloca to ensure we can reason about it, builds
 /// the slices of the alloca, and then hands it off to be split and
 /// rewritten as needed.
-bool SROAPass::runOnAlloca(AllocaInst &AI) {
+std::pair<bool /*Changed*/, bool /*CFGChanged*/>
+SROAPass::runOnAlloca(AllocaInst &AI) {
+  bool Changed = false;
+  bool CFGChanged = false;
+
   LLVM_DEBUG(dbgs() << "SROA alloca: " << AI << "\n");
   ++NumAllocasAnalyzed;
 
   // Special case dead allocas, as they're trivial.
   if (AI.use_empty()) {
     AI.eraseFromParent();
-    return true;
+    Changed = true;
+    return {Changed, CFGChanged};
   }
   const DataLayout &DL = AI.getModule()->getDataLayout();
 
@@ -4652,9 +4762,7 @@ bool SROAPass::runOnAlloca(AllocaInst &AI) {
   auto *AT = AI.getAllocatedType();
   if (AI.isArrayAllocation() || !AT->isSized() || isa<ScalableVectorType>(AT) ||
       DL.getTypeAllocSize(AT).getFixedSize() == 0)
-    return false;
-
-  bool Changed = false;
+    return {Changed, CFGChanged};
 
   // First, split any FCA loads and stores touching this alloca to promote
   // better splitting and promotion opportunities.
@@ -4666,7 +4774,7 @@ bool SROAPass::runOnAlloca(AllocaInst &AI) {
   AllocaSlices AS(DL, AI);
   LLVM_DEBUG(AS.print(dbgs()));
   if (AS.isEscaped())
-    return Changed;
+    return {Changed, CFGChanged};
 
   // Delete all the dead users of this alloca before splitting and rewriting it.
   for (Instruction *DeadUser : AS.getDeadUsers()) {
@@ -4688,7 +4796,7 @@ bool SROAPass::runOnAlloca(AllocaInst &AI) {
 
   // No slices to split. Leave the dead alloca for a later pass to clean up.
   if (AS.begin() == AS.end())
-    return Changed;
+    return {Changed, CFGChanged};
 
   Changed |= splitAlloca(AI, AS);
 
@@ -4696,11 +4804,15 @@ bool SROAPass::runOnAlloca(AllocaInst &AI) {
   while (!SpeculatablePHIs.empty())
     speculatePHINodeLoads(IRB, *SpeculatablePHIs.pop_back_val());
 
-  LLVM_DEBUG(dbgs() << "  Speculating Selects\n");
-  while (!SpeculatableSelects.empty())
-    speculateSelectInstLoads(IRB, *SpeculatableSelects.pop_back_val());
+  LLVM_DEBUG(dbgs() << "  Rewriting Selects\n");
+  auto RemainingSelectsToRewrite = SelectsToRewrite.takeVector();
+  while (!RemainingSelectsToRewrite.empty()) {
+    const auto [K, V] = RemainingSelectsToRewrite.pop_back_val();
+    CFGChanged |=
+        rewriteSelectInstLoads(*K, V, IRB, PreserveCFG ? nullptr : DTU);
+  }
 
-  return Changed;
+  return {Changed, CFGChanged};
 }
 
 /// Delete the dead instructions accumulated in this run.
@@ -4759,16 +4871,16 @@ bool SROAPass::promoteAllocas(Function &F) {
   NumPromoted += PromotableAllocas.size();
 
   LLVM_DEBUG(dbgs() << "Promoting allocas with mem2reg...\n");
-  PromoteMemToReg(PromotableAllocas, *DT, AC);
+  PromoteMemToReg(PromotableAllocas, DTU->getDomTree(), AC);
   PromotableAllocas.clear();
   return true;
 }
 
-PreservedAnalyses SROAPass::runImpl(Function &F, DominatorTree &RunDT,
+PreservedAnalyses SROAPass::runImpl(Function &F, DomTreeUpdater &RunDTU,
                                     AssumptionCache &RunAC) {
   LLVM_DEBUG(dbgs() << "SROA function: " << F.getName() << "\n");
   C = &F.getContext();
-  DT = &RunDT;
+  DTU = &RunDTU;
   AC = &RunAC;
 
   BasicBlock &EntryBB = F.getEntryBlock();
@@ -4785,13 +4897,18 @@ PreservedAnalyses SROAPass::runImpl(Function &F, DominatorTree &RunDT,
   }
 
   bool Changed = false;
+  bool CFGChanged = false;
   // A set of deleted alloca instruction pointers which should be removed from
   // the list of promotable allocas.
   SmallPtrSet<AllocaInst *, 4> DeletedAllocas;
 
   do {
     while (!Worklist.empty()) {
-      Changed |= runOnAlloca(*Worklist.pop_back_val());
+      auto [IterationChanged, IterationCFGChanged] =
+          runOnAlloca(*Worklist.pop_back_val());
+      Changed |= IterationChanged;
+      CFGChanged |= IterationCFGChanged;
+
       Changed |= deleteDeadInstructions(DeletedAllocas);
 
       // Remove the deleted allocas from various lists so that we don't try to
@@ -4811,19 +4928,41 @@ PreservedAnalyses SROAPass::runImpl(Function &F, DominatorTree &RunDT,
     PostPromotionWorklist.clear();
   } while (!Worklist.empty());
 
+  assert((!CFGChanged || Changed) && "Can not only modify the CFG.");
+  assert((!CFGChanged || !PreserveCFG) &&
+         "Should not have modified the CFG when told to preserve it.");
+
   if (!Changed)
     return PreservedAnalyses::all();
 
   PreservedAnalyses PA;
-  PA.preserveSet<CFGAnalyses>();
+  if (!CFGChanged)
+    PA.preserveSet<CFGAnalyses>();
+  PA.preserve<DominatorTreeAnalysis>();
   return PA;
 }
 
+PreservedAnalyses SROAPass::runImpl(Function &F, DominatorTree &RunDT,
+                                    AssumptionCache &RunAC) {
+  DomTreeUpdater DTU(RunDT, DomTreeUpdater::UpdateStrategy::Lazy);
+  return runImpl(F, DTU, RunAC);
+}
+
 PreservedAnalyses SROAPass::run(Function &F, FunctionAnalysisManager &AM) {
   return runImpl(F, AM.getResult<DominatorTreeAnalysis>(F),
                  AM.getResult<AssumptionAnalysis>(F));
 }
 
+void SROAPass::printPipeline(
+    raw_ostream &OS, function_ref<StringRef(StringRef)> MapClassName2PassName) {
+  static_cast<PassInfoMixin<SROAPass> *>(this)->printPipeline(
+      OS, MapClassName2PassName);
+  OS << (PreserveCFG ? "<preserve-cfg>" : "<modify-cfg>");
+}
+
+SROAPass::SROAPass(SROAOptions PreserveCFG_)
+    : PreserveCFG(PreserveCFG_ == SROAOptions::PreserveCFG) {}
+
 /// A legacy pass for the legacy pass manager that wraps the \c SROA pass.
 ///
 /// This is in the llvm namespace purely to allow it to be a friend of the \c
@@ -4835,7 +4974,8 @@ class llvm::sroa::SROALegacyPass : public FunctionPass {
 public:
   static char ID;
 
-  SROALegacyPass() : FunctionPass(ID) {
+  SROALegacyPass(SROAOptions PreserveCFG = SROAOptions::PreserveCFG)
+      : FunctionPass(ID), Impl(PreserveCFG) {
     initializeSROALegacyPassPass(*PassRegistry::getPassRegistry());
   }
 
@@ -4853,7 +4993,7 @@ class llvm::sroa::SROALegacyPass : public FunctionPass {
     AU.addRequired<AssumptionCacheTracker>();
     AU.addRequired<DominatorTreeWrapperPass>();
     AU.addPreserved<GlobalsAAWrapperPass>();
-    AU.setPreservesCFG();
+    AU.addPreserved<DominatorTreeWrapperPass>();
   }
 
   StringRef getPassName() const override { return "SROA"; }
@@ -4861,7 +5001,10 @@ class llvm::sroa::SROALegacyPass : public FunctionPass {
 
 char SROALegacyPass::ID = 0;
 
-FunctionPass *llvm::createSROAPass() { return new SROALegacyPass(); }
+FunctionPass *llvm::createSROAPass(bool PreserveCFG) {
+  return new SROALegacyPass(PreserveCFG ? SROAOptions::PreserveCFG
+                                        : SROAOptions::ModifyCFG);
+}
 
 INITIALIZE_PASS_BEGIN(SROALegacyPass, "sroa",
                       "Scalar Replacement Of Aggregates", false, false)

diff  --git a/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp b/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp
index c03fbe9a306a8..9876681a19245 100644
--- a/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp
+++ b/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp
@@ -1545,8 +1545,14 @@ Instruction *llvm::SplitBlockAndInsertIfThen(Value *Cond,
 void llvm::SplitBlockAndInsertIfThenElse(Value *Cond, Instruction *SplitBefore,
                                          Instruction **ThenTerm,
                                          Instruction **ElseTerm,
-                                         MDNode *BranchWeights) {
+                                         MDNode *BranchWeights,
+                                         DomTreeUpdater *DTU) {
   BasicBlock *Head = SplitBefore->getParent();
+
+  SmallPtrSet<BasicBlock *, 8> UniqueOrigSuccessors;
+  if (DTU)
+    UniqueOrigSuccessors.insert(succ_begin(Head), succ_end(Head));
+
   BasicBlock *Tail = Head->splitBasicBlock(SplitBefore->getIterator());
   Instruction *HeadOldTerm = Head->getTerminator();
   LLVMContext &C = Head->getContext();
@@ -1560,6 +1566,19 @@ void llvm::SplitBlockAndInsertIfThenElse(Value *Cond, Instruction *SplitBefore,
     BranchInst::Create(/*ifTrue*/ThenBlock, /*ifFalse*/ElseBlock, Cond);
   HeadNewTerm->setMetadata(LLVMContext::MD_prof, BranchWeights);
   ReplaceInstWithInst(HeadOldTerm, HeadNewTerm);
+  if (DTU) {
+    SmallVector<DominatorTree::UpdateType, 8> Updates;
+    Updates.reserve(4 + 2 * UniqueOrigSuccessors.size());
+    for (BasicBlock *Succ : successors(Head)) {
+      Updates.push_back({DominatorTree::Insert, Head, Succ});
+      Updates.push_back({DominatorTree::Insert, Succ, Tail});
+    }
+    for (BasicBlock *UniqueOrigSuccessor : UniqueOrigSuccessors)
+      Updates.push_back({DominatorTree::Insert, Tail, UniqueOrigSuccessor});
+    for (BasicBlock *UniqueOrigSuccessor : UniqueOrigSuccessors)
+      Updates.push_back({DominatorTree::Delete, Head, UniqueOrigSuccessor});
+    DTU->applyUpdates(Updates);
+  }
 }
 
 BranchInst *llvm::GetIfCondition(BasicBlock *BB, BasicBlock *&IfTrue,

diff  --git a/llvm/test/Transforms/SROA/2009-02-20-InstCombine-SROA.ll b/llvm/test/Transforms/SROA/2009-02-20-InstCombine-SROA.ll
index a83bd3b6893a6..3a8d376bd5c02 100644
--- a/llvm/test/Transforms/SROA/2009-02-20-InstCombine-SROA.ll
+++ b/llvm/test/Transforms/SROA/2009-02-20-InstCombine-SROA.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -passes=sroa -S | FileCheck %s
+; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
 
 ; rdar://6417724
 
@@ -270,3 +271,6 @@ return:                                           ; preds = %_ZSt4findIN9__gnu_c
 declare void @llvm.memcpy.p0.p0.i64(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg) #0
 
 attributes #0 = { argmemonly nofree nosync nounwind willreturn }
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-modify-cfg: {{.*}}
+; CHECK-preserve-cfg: {{.*}}

diff  --git a/llvm/test/Transforms/SROA/address-spaces.ll b/llvm/test/Transforms/SROA/address-spaces.ll
index 70e1a682d7bfc..53ee122ca14bf 100644
--- a/llvm/test/Transforms/SROA/address-spaces.ll
+++ b/llvm/test/Transforms/SROA/address-spaces.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -passes=sroa -S | FileCheck %s
+; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
 target datalayout = "e-p:64:64:64-p1:16:16:16-p3:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-n8:16:32:64"
 
 declare void @llvm.memcpy.p0.p0.i32(ptr nocapture, ptr nocapture readonly, i32, i1)
@@ -157,3 +158,6 @@ define void @test_load_store_
diff _addr_space(ptr addrspace(1) %complex1, ptr add
   store i64 %v2, ptr addrspace(1) %complex2
   ret void
 }
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-modify-cfg: {{.*}}
+; CHECK-preserve-cfg: {{.*}}

diff  --git a/llvm/test/Transforms/SROA/addrspacecast.ll b/llvm/test/Transforms/SROA/addrspacecast.ll
index 40cc0f7fafcd2..9dc56ad529a98 100644
--- a/llvm/test/Transforms/SROA/addrspacecast.ll
+++ b/llvm/test/Transforms/SROA/addrspacecast.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -passes=sroa -S | FileCheck %s
+; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
 
 target datalayout = "e-p:64:64:64-p1:16:16:16-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-n8:16:32:64"
 
@@ -288,12 +289,21 @@ define void @select_addrspacecast(i1 %a, i1 %b) {
 }
 
 define void @select_addrspacecast_const_op(i1 %a, i1 %b) {
-; CHECK-LABEL: @select_addrspacecast_const_op(
-; CHECK-NEXT:    [[C:%.*]] = alloca i64, align 8
-; CHECK-NEXT:    [[C_0_ASC_SROA_CAST:%.*]] = addrspacecast ptr [[C]] to ptr addrspace(1)
-; CHECK-NEXT:    [[COND_IN:%.*]] = select i1 [[B:%.*]], ptr addrspace(1) [[C_0_ASC_SROA_CAST]], ptr addrspace(1) null
-; CHECK-NEXT:    [[COND:%.*]] = load i64, ptr addrspace(1) [[COND_IN]], align 8
-; CHECK-NEXT:    ret void
+; CHECK-preserve-cfg-LABEL: @select_addrspacecast_const_op(
+; CHECK-preserve-cfg-NEXT:    [[C:%.*]] = alloca i64, align 8
+; CHECK-preserve-cfg-NEXT:    [[C_0_ASC_SROA_CAST:%.*]] = addrspacecast ptr [[C]] to ptr addrspace(1)
+; CHECK-preserve-cfg-NEXT:    [[COND_IN:%.*]] = select i1 [[B:%.*]], ptr addrspace(1) [[C_0_ASC_SROA_CAST]], ptr addrspace(1) null
+; CHECK-preserve-cfg-NEXT:    [[COND:%.*]] = load i64, ptr addrspace(1) [[COND_IN]], align 8
+; CHECK-preserve-cfg-NEXT:    ret void
+;
+; CHECK-modify-cfg-LABEL: @select_addrspacecast_const_op(
+; CHECK-modify-cfg-NEXT:    br i1 [[B:%.*]], label [[DOTCONT:%.*]], label [[DOTELSE:%.*]]
+; CHECK-modify-cfg:       .else:
+; CHECK-modify-cfg-NEXT:    [[COND_ELSE_VAL:%.*]] = load i64, ptr addrspace(1) null, align 8
+; CHECK-modify-cfg-NEXT:    br label [[DOTCONT]]
+; CHECK-modify-cfg:       .cont:
+; CHECK-modify-cfg-NEXT:    [[COND:%.*]] = phi i64 [ undef, [[TMP0:%.*]] ], [ [[COND_ELSE_VAL]], [[DOTELSE]] ]
+; CHECK-modify-cfg-NEXT:    ret void
 ;
   %c = alloca i64, align 8
   %p.0.c = select i1 %a, ptr %c, ptr %c

diff  --git a/llvm/test/Transforms/SROA/alignment.ll b/llvm/test/Transforms/SROA/alignment.ll
index 223075830cb72..87442089a9ee0 100644
--- a/llvm/test/Transforms/SROA/alignment.ll
+++ b/llvm/test/Transforms/SROA/alignment.ll
@@ -1,6 +1,7 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -passes=sroa -S | FileCheck %s
-; RUN: opt -passes='debugify,function(sroa)' -S < %s | FileCheck %s -check-prefix CHECK-DEBUGLOC
+; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
+; RUN: opt -passes='debugify,function(sroa<preserve-cfg>)' -S < %s | FileCheck %s -check-prefix CHECK-DEBUGLOC
 
 target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-n8:16:32:64"
 
@@ -456,3 +457,6 @@ define dso_local i32 @pr45010(ptr %A) {
 }
 
 declare void @populate(ptr)
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-modify-cfg: {{.*}}
+; CHECK-preserve-cfg: {{.*}}

diff  --git a/llvm/test/Transforms/SROA/alloca-address-space.ll b/llvm/test/Transforms/SROA/alloca-address-space.ll
index d4f305c39c8fe..cd347ab536ec6 100644
--- a/llvm/test/Transforms/SROA/alloca-address-space.ll
+++ b/llvm/test/Transforms/SROA/alloca-address-space.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -passes=sroa -S | FileCheck %s
+; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
 target datalayout = "e-p:64:64:64-p1:16:16:16-p2:32:32-p3:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-n8:16:32:64-A2"
 
 declare void @llvm.memcpy.p2.p2.i32(ptr addrspace(2) nocapture, ptr addrspace(2) nocapture readonly, i32, i1)
@@ -145,3 +146,6 @@ define void @addressspace_alloca_lifetime() {
 }
 
 declare void @llvm.lifetime.start.p0(i64 %size, ptr nocapture %ptr)
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-modify-cfg: {{.*}}
+; CHECK-preserve-cfg: {{.*}}

diff  --git a/llvm/test/Transforms/SROA/assume.ll b/llvm/test/Transforms/SROA/assume.ll
index d17d23a4c64b8..da667a61afc9c 100644
--- a/llvm/test/Transforms/SROA/assume.ll
+++ b/llvm/test/Transforms/SROA/assume.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -passes=sroa -S | FileCheck %s
+; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
 
 target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
 target triple = "x86_64-unknown-linux-gnu"
@@ -27,3 +28,6 @@ entry:
 declare void @llvm.assume(i1) #0
 
 attributes #0 = { nofree norecurse nounwind willreturn }
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-modify-cfg: {{.*}}
+; CHECK-preserve-cfg: {{.*}}

diff  --git a/llvm/test/Transforms/SROA/basictest.ll b/llvm/test/Transforms/SROA/basictest.ll
index ddf678fa4a37e..711cc3f917507 100644
--- a/llvm/test/Transforms/SROA/basictest.ll
+++ b/llvm/test/Transforms/SROA/basictest.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -passes=sroa -S | FileCheck %s
+; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
 
 target datalayout = "e-p:64:64:64-p1:16:16:16-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-n8:16:32:64"
 
@@ -1408,9 +1409,19 @@ end:
 }
 
 define void @PR15805(i1 %a, i1 %b) {
-; CHECK-LABEL: @PR15805(
-; CHECK-NEXT:    [[COND_SROA_SPECULATED:%.*]] = select i1 [[B:%.*]], i64 undef, i64 undef
-; CHECK-NEXT:    ret void
+; CHECK-preserve-cfg-LABEL: @PR15805(
+; CHECK-preserve-cfg-NEXT:    [[C:%.*]] = alloca i64, align 8
+; CHECK-preserve-cfg-NEXT:    [[COND_IN:%.*]] = select i1 [[B:%.*]], ptr [[C]], ptr [[C]]
+; CHECK-preserve-cfg-NEXT:    [[COND:%.*]] = load i64, ptr [[COND_IN]], align 8
+; CHECK-preserve-cfg-NEXT:    ret void
+;
+; CHECK-modify-cfg-LABEL: @PR15805(
+; CHECK-modify-cfg-NEXT:    br i1 [[B:%.*]], label [[DOTCONT:%.*]], label [[DOTELSE:%.*]]
+; CHECK-modify-cfg:       .else:
+; CHECK-modify-cfg-NEXT:    br label [[DOTCONT]]
+; CHECK-modify-cfg:       .cont:
+; CHECK-modify-cfg-NEXT:    [[COND:%.*]] = phi i64 [ undef, [[TMP0:%.*]] ], [ undef, [[DOTELSE]] ]
+; CHECK-modify-cfg-NEXT:    ret void
 ;
   %c = alloca i64, align 8
   %p.0.c = select i1 %a, ptr %c, ptr %c
@@ -1425,13 +1436,29 @@ define void @PR15805.1(i1 %a, i1 %b, i1 %c2) {
 ; order in which the uses of the alloca are visited.
 ;
 ;
-; CHECK-LABEL: @PR15805.1(
-; CHECK-NEXT:    br label [[EXIT:%.*]]
-; CHECK:       loop:
-; CHECK-NEXT:    [[COND_SROA_SPECULATED:%.*]] = select i1 [[A:%.*]], i64 undef, i64 undef
-; CHECK-NEXT:    br i1 [[C2:%.*]], label [[LOOP:%.*]], label [[EXIT]]
-; CHECK:       exit:
-; CHECK-NEXT:    ret void
+; CHECK-preserve-cfg-LABEL: @PR15805.1(
+; CHECK-preserve-cfg-NEXT:    [[C:%.*]] = alloca i64, align 8
+; CHECK-preserve-cfg-NEXT:    br label [[EXIT:%.*]]
+; CHECK-preserve-cfg:       loop:
+; CHECK-preserve-cfg-NEXT:    [[COND_IN:%.*]] = select i1 [[A:%.*]], ptr [[C]], ptr [[C]]
+; CHECK-preserve-cfg-NEXT:    [[COND:%.*]] = load i64, ptr [[COND_IN]], align 8
+; CHECK-preserve-cfg-NEXT:    br i1 [[C2:%.*]], label [[LOOP:%.*]], label [[EXIT]]
+; CHECK-preserve-cfg:       exit:
+; CHECK-preserve-cfg-NEXT:    ret void
+;
+; CHECK-modify-cfg-LABEL: @PR15805.1(
+; CHECK-modify-cfg-NEXT:    br label [[EXIT:%.*]]
+; CHECK-modify-cfg:       loop:
+; CHECK-modify-cfg-NEXT:    [[C_0_LOAD:%.*]] = load i64, ptr poison, align 8
+; CHECK-modify-cfg-NEXT:    br i1 [[A:%.*]], label [[LOOP_CONT:%.*]], label [[LOOP_ELSE:%.*]]
+; CHECK-modify-cfg:       loop.else:
+; CHECK-modify-cfg-NEXT:    [[C_0_LOAD1:%.*]] = load i64, ptr poison, align 8
+; CHECK-modify-cfg-NEXT:    br label [[LOOP_CONT]]
+; CHECK-modify-cfg:       loop.cont:
+; CHECK-modify-cfg-NEXT:    [[COND:%.*]] = phi i64 [ [[C_0_LOAD]], [[LOOP:%.*]] ], [ [[C_0_LOAD1]], [[LOOP_ELSE]] ]
+; CHECK-modify-cfg-NEXT:    br i1 [[C2:%.*]], label [[LOOP]], label [[EXIT]]
+; CHECK-modify-cfg:       exit:
+; CHECK-modify-cfg-NEXT:    ret void
 ;
   %c = alloca i64, align 8
   br label %exit
@@ -1483,13 +1510,24 @@ define void @PR16651.2(<2 x float> %val, i1 %c1) {
 ; bail on select instructions.
 ;
 ;
-; CHECK-LABEL: @PR16651.2(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[TV1_SROA_0:%.*]] = alloca <2 x float>, align 8
-; CHECK-NEXT:    store <2 x float> [[VAL:%.*]], ptr [[TV1_SROA_0]], align 8
-; CHECK-NEXT:    [[COND105_IN_I_I:%.*]] = select i1 [[C1:%.*]], ptr null, ptr [[TV1_SROA_0]]
-; CHECK-NEXT:    [[COND105_I_I:%.*]] = load float, ptr [[COND105_IN_I_I]], align 8
-; CHECK-NEXT:    ret void
+; CHECK-preserve-cfg-LABEL: @PR16651.2(
+; CHECK-preserve-cfg-NEXT:  entry:
+; CHECK-preserve-cfg-NEXT:    [[TV1_SROA_0:%.*]] = alloca <2 x float>, align 8
+; CHECK-preserve-cfg-NEXT:    store <2 x float> [[VAL:%.*]], ptr [[TV1_SROA_0]], align 8
+; CHECK-preserve-cfg-NEXT:    [[COND105_IN_I_I:%.*]] = select i1 [[C1:%.*]], ptr null, ptr [[TV1_SROA_0]]
+; CHECK-preserve-cfg-NEXT:    [[COND105_I_I:%.*]] = load float, ptr [[COND105_IN_I_I]], align 8
+; CHECK-preserve-cfg-NEXT:    ret void
+;
+; CHECK-modify-cfg-LABEL: @PR16651.2(
+; CHECK-modify-cfg-NEXT:  entry:
+; CHECK-modify-cfg-NEXT:    [[TV1_SROA_0_0_VEC_EXTRACT:%.*]] = extractelement <2 x float> [[VAL:%.*]], i32 0
+; CHECK-modify-cfg-NEXT:    br i1 [[C1:%.*]], label [[ENTRY_THEN:%.*]], label [[ENTRY_CONT:%.*]]
+; CHECK-modify-cfg:       entry.then:
+; CHECK-modify-cfg-NEXT:    [[COND105_I_I_THEN_VAL:%.*]] = load float, ptr null, align 8
+; CHECK-modify-cfg-NEXT:    br label [[ENTRY_CONT]]
+; CHECK-modify-cfg:       entry.cont:
+; CHECK-modify-cfg-NEXT:    [[COND105_I_I:%.*]] = phi float [ [[COND105_I_I_THEN_VAL]], [[ENTRY_THEN]] ], [ [[TV1_SROA_0_0_VEC_EXTRACT]], [[ENTRY:%.*]] ]
+; CHECK-modify-cfg-NEXT:    ret void
 ;
 entry:
   %tv1 = alloca { <2 x float>, <2 x float> }, align 8

diff  --git a/llvm/test/Transforms/SROA/big-endian.ll b/llvm/test/Transforms/SROA/big-endian.ll
index 92098956a58b5..f80d68c24d0c8 100644
--- a/llvm/test/Transforms/SROA/big-endian.ll
+++ b/llvm/test/Transforms/SROA/big-endian.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -passes=sroa -S | FileCheck %s
+; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
 
 target datalayout = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-n8:16:32:64"
 
@@ -230,3 +231,6 @@ entry:
 }
 
 declare void @llvm.memcpy.p0.p0.i64(ptr, ptr, i64, i1)
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-modify-cfg: {{.*}}
+; CHECK-preserve-cfg: {{.*}}

diff  --git a/llvm/test/Transforms/SROA/dbg-addr-diamond.ll b/llvm/test/Transforms/SROA/dbg-addr-diamond.ll
index 652fc82b0fb26..54551058316d8 100644
--- a/llvm/test/Transforms/SROA/dbg-addr-diamond.ll
+++ b/llvm/test/Transforms/SROA/dbg-addr-diamond.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -use-dbg-addr -passes=sroa -S < %s | FileCheck %s
+; RUN: opt -use-dbg-addr -passes='sroa<preserve-cfg>' -S < %s | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt -use-dbg-addr -passes='sroa<modify-cfg>' -S < %s | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
 
 ; ModuleID = '<stdin>'
 source_filename = "newvars.c"
@@ -127,3 +128,6 @@ declare void @llvm.dbg.addr(metadata, metadata, metadata)
 !52 = !{i64 0, i64 4, !53, i64 4, i64 4, !53}
 !53 = !{!31, !31, i64 0}
 !54 = !DILocation(line: 14, column: 1, scope: !8)
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-modify-cfg: {{.*}}
+; CHECK-preserve-cfg: {{.*}}

diff  --git a/llvm/test/Transforms/SROA/dbg-inline.ll b/llvm/test/Transforms/SROA/dbg-inline.ll
index 48498e98c4623..755bb7723fa8b 100644
--- a/llvm/test/Transforms/SROA/dbg-inline.ll
+++ b/llvm/test/Transforms/SROA/dbg-inline.ll
@@ -2,7 +2,8 @@
 ; Test that SROA can deal with allocas that have more than one
 ; dbg.declare hanging off of it.
 
-; RUN: opt < %s -passes=sroa -S | FileCheck %s
+; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
 source_filename = "/tmp/inlinesplit.cpp"
 target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
 target triple = "x86_64-apple-macosx10.15.0"
@@ -69,3 +70,6 @@ attributes #2 = { argmemonly nounwind willreturn }
 !24 = distinct !DILocation(line: 10, column: 10, scope: !8)
 !25 = !DILocation(line: 6, column: 12, scope: !22, inlinedAt: !24)
 !26 = !DILocation(line: 10, column: 3, scope: !8)
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-modify-cfg: {{.*}}
+; CHECK-preserve-cfg: {{.*}}

diff  --git a/llvm/test/Transforms/SROA/dbg-single-piece.ll b/llvm/test/Transforms/SROA/dbg-single-piece.ll
index bb0e51de8f1ae..cb71dd2e78b0d 100644
--- a/llvm/test/Transforms/SROA/dbg-single-piece.ll
+++ b/llvm/test/Transforms/SROA/dbg-single-piece.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -passes=sroa %s -S | FileCheck %s
+; RUN: opt -passes='sroa<preserve-cfg>' %s -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt -passes='sroa<modify-cfg>' %s -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
 
 %foo = type { [8 x i8], [8 x i8] }
@@ -36,3 +37,6 @@ attributes #0 = { nounwind readnone }
 !7 = !DIExpression()
 !8 = !DILocation(line: 947, column: 35, scope: !2)
 !9 = distinct !DICompileUnit(language: DW_LANG_Julia, file: !3)
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-modify-cfg: {{.*}}
+; CHECK-preserve-cfg: {{.*}}

diff  --git a/llvm/test/Transforms/SROA/dead-inst.ll b/llvm/test/Transforms/SROA/dead-inst.ll
index 299bed8b0e5f4..53fa0da7ece68 100644
--- a/llvm/test/Transforms/SROA/dead-inst.ll
+++ b/llvm/test/Transforms/SROA/dead-inst.ll
@@ -1,8 +1,10 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -passes='bdce,sroa<preserve-cfg>,bdce' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt < %s -passes='bdce,sroa<modify-cfg>,bdce' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
+
 ; SROA fails to rewrite allocs but does rewrite some phis and delete
 ; dead instructions. Ensure that this invalidates analyses required
 ; for other passes.
-; RUN: opt < %s -passes=bdce,sroa,bdce -o %t -debug-pass-manager 2>&1 | FileCheck %s
 
 target datalayout = "e-m:e-i64:64-n32:64"
 target triple = "powerpc64le-grtev4-linux-gnu"
@@ -13,6 +15,56 @@ declare void @D(ptr sret(%class.b), ptr dereferenceable(32)) local_unnamed_addr
 
 ; Function Attrs: nounwind
 define void @H(ptr noalias nocapture readnone, [2 x i64], ptr %ptr, i32 signext %v, i64 %l, i64 %idx, ptr nonnull dereferenceable(32) %ptr2) {
+; CHECK-LABEL: @H(
+; CHECK-NEXT:    [[TMP3:%.*]] = alloca [[CLASS_B:%.*]], align 8
+; CHECK-NEXT:    [[TMP4:%.*]] = extractvalue [2 x i64] [[TMP1:%.*]], 1
+; CHECK-NEXT:    switch i64 [[TMP4]], label [[TMP6:%.*]] [
+; CHECK-NEXT:    i64 4, label [[FOO:%.*]]
+; CHECK-NEXT:    i64 5, label [[TMP5:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       5:
+; CHECK-NEXT:    br label [[TMP12:%.*]]
+; CHECK:       6:
+; CHECK-NEXT:    [[TMP7:%.*]] = icmp ugt i64 [[TMP4]], 5
+; CHECK-NEXT:    br i1 [[TMP7]], label [[TMP8:%.*]], label [[TMP12]]
+; CHECK:       8:
+; CHECK-NEXT:    [[TMP9:%.*]] = load i8, ptr inttoptr (i64 4 to ptr), align 4
+; CHECK-NEXT:    [[TMP10:%.*]] = icmp eq i8 [[TMP9]], 47
+; CHECK-NEXT:    [[TMP11:%.*]] = select i1 [[TMP10]], i64 5, i64 4
+; CHECK-NEXT:    br label [[TMP12]]
+; CHECK:       12:
+; CHECK-NEXT:    [[TMP13:%.*]] = phi i64 [ 4, [[TMP5]] ], [ [[TMP11]], [[TMP8]] ], [ 4, [[TMP6]] ]
+; CHECK-NEXT:    [[TMP14:%.*]] = icmp ne i64 [[TMP4]], 0
+; CHECK-NEXT:    [[TMP15:%.*]] = icmp ugt i64 [[TMP4]], [[TMP13]]
+; CHECK-NEXT:    [[TMP16:%.*]] = and i1 [[TMP14]], [[TMP15]]
+; CHECK-NEXT:    br i1 [[TMP16]], label [[TMP17:%.*]], label [[A_EXIT:%.*]]
+; CHECK:       17:
+; CHECK-NEXT:    [[TMP18:%.*]] = tail call ptr @memchr(ptr [[PTR:%.*]], i32 signext [[V:%.*]], i64 [[L:%.*]])
+; CHECK-NEXT:    [[TMP19:%.*]] = icmp eq ptr [[TMP18]], null
+; CHECK-NEXT:    [[TMP20:%.*]] = sext i1 [[TMP19]] to i64
+; CHECK-NEXT:    br label [[A_EXIT]]
+; CHECK:       a.exit:
+; CHECK-NEXT:    [[TMP21:%.*]] = phi i64 [ -1, [[TMP12]] ], [ [[TMP20]], [[TMP17]] ]
+; CHECK-NEXT:    [[TMP22:%.*]] = inttoptr i64 0 to ptr
+; CHECK-NEXT:    [[TMP23:%.*]] = sub nsw i64 [[TMP21]], [[TMP13]]
+; CHECK-NEXT:    call void @llvm.lifetime.start.p0(i64 32, ptr nonnull [[TMP3]])
+; CHECK-NEXT:    [[TMP24:%.*]] = icmp ult i64 [[TMP23]], 2
+; CHECK-NEXT:    br i1 [[TMP24]], label [[G_EXIT:%.*]], label [[TMP25:%.*]]
+; CHECK:       25:
+; CHECK-NEXT:    [[TMP26:%.*]] = getelementptr inbounds i8, ptr [[TMP22]], i64 [[IDX:%.*]]
+; CHECK-NEXT:    [[TMP27:%.*]] = icmp eq ptr [[TMP26]], null
+; CHECK-NEXT:    br i1 [[TMP27]], label [[TMP28:%.*]], label [[TMP29:%.*]]
+; CHECK:       28:
+; CHECK-NEXT:    unreachable
+; CHECK:       29:
+; CHECK-NEXT:    call void @D(ptr nonnull sret([[CLASS_B]]) [[TMP3]], ptr nonnull dereferenceable(32) [[PTR2:%.*]])
+; CHECK-NEXT:    br label [[G_EXIT]]
+; CHECK:       G.exit:
+; CHECK-NEXT:    call void @llvm.lifetime.end.p0(i64 32, ptr nonnull [[TMP3]])
+; CHECK-NEXT:    br label [[FOO]]
+; CHECK:       foo:
+; CHECK-NEXT:    ret void
+;
   %3 = alloca %class.b, align 8
   %.sroa.0 = alloca i64, align 8
   store i64 0, ptr %.sroa.0, align 8
@@ -86,4 +138,5 @@ declare void @llvm.lifetime.start.p0(i64, ptr nocapture)
 ; Function Attrs: argmemonly nounwind
 declare void @llvm.lifetime.end.p0(i64, ptr nocapture)
 ;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
-; CHECK: {{.*}}
+; CHECK-modify-cfg: {{.*}}
+; CHECK-preserve-cfg: {{.*}}

diff  --git a/llvm/test/Transforms/SROA/fca.ll b/llvm/test/Transforms/SROA/fca.ll
index 57aa1b079eaea..6937b05be3a9e 100644
--- a/llvm/test/Transforms/SROA/fca.ll
+++ b/llvm/test/Transforms/SROA/fca.ll
@@ -1,5 +1,7 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -passes=sroa -S | FileCheck %s
+; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
+
 target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-n8:16:32:64"
 
 define { i32, i32 } @test0(i32 %x, i32 %y, { i32, i32 } %v) {
@@ -53,3 +55,6 @@ entry:
   store volatile { i32, i32 } %result, ptr %b
   ret { i32, i32 } %result
 }
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-modify-cfg: {{.*}}
+; CHECK-preserve-cfg: {{.*}}

diff  --git a/llvm/test/Transforms/SROA/ignore-droppable.ll b/llvm/test/Transforms/SROA/ignore-droppable.ll
index e4aaf963a51bf..3dd0e5874d65a 100644
--- a/llvm/test/Transforms/SROA/ignore-droppable.ll
+++ b/llvm/test/Transforms/SROA/ignore-droppable.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -passes=sroa -S | FileCheck %s
+; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
 
 declare void @llvm.assume(i1)
 declare void @llvm.lifetime.start.p0(i64 %size, ptr nocapture %ptr)
@@ -78,3 +79,6 @@ define void @positive_mixed_assume_uses() {
   call void @llvm.assume(i1 true) ["nonnull"(ptr %A), "align"(ptr %A, i64 2), "nonnull"(ptr %A)]
   ret void
 }
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-modify-cfg: {{.*}}
+; CHECK-preserve-cfg: {{.*}}

diff  --git a/llvm/test/Transforms/SROA/invariant-group.ll b/llvm/test/Transforms/SROA/invariant-group.ll
index 8d487ebe842bb..a8007ad2dd6ed 100644
--- a/llvm/test/Transforms/SROA/invariant-group.ll
+++ b/llvm/test/Transforms/SROA/invariant-group.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -passes=sroa -S -o - < %s | FileCheck %s
+; RUN: opt -passes='sroa<preserve-cfg>' -S -o - < %s | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt -passes='sroa<modify-cfg>' -S -o - < %s | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
 
 %t = type { i32, i32 }
 
@@ -79,3 +80,6 @@ define void @g() {
 }
 
 !0 = !{}
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-modify-cfg: {{.*}}
+; CHECK-preserve-cfg: {{.*}}

diff  --git a/llvm/test/Transforms/SROA/irregular-type.ll b/llvm/test/Transforms/SROA/irregular-type.ll
index 78cd6b3f6b1c3..d9f5cf9b3c0d1 100644
--- a/llvm/test/Transforms/SROA/irregular-type.ll
+++ b/llvm/test/Transforms/SROA/irregular-type.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -passes=sroa -S | FileCheck %s
+; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
 
 %S = type { [4 x i8] }
 
@@ -39,3 +40,6 @@ Entry:
   %3 = zext i17 %2 to i32
   ret i32 %3
 }
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-modify-cfg: {{.*}}
+; CHECK-preserve-cfg: {{.*}}

diff  --git a/llvm/test/Transforms/SROA/lifetime-intrinsic.ll b/llvm/test/Transforms/SROA/lifetime-intrinsic.ll
index 68cfd3c787d03..d80da566c69c3 100644
--- a/llvm/test/Transforms/SROA/lifetime-intrinsic.ll
+++ b/llvm/test/Transforms/SROA/lifetime-intrinsic.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -passes=sroa -S | FileCheck %s
+; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
 
 %i32x2 = type { [2 x i32] }
 
@@ -55,3 +56,6 @@ declare void @llvm.lifetime.end.p0(i64, ptr nocapture) #1
 
 attributes #0 = { alwaysinline nounwind }
 attributes #1 = { argmemonly nounwind }
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-modify-cfg: {{.*}}
+; CHECK-preserve-cfg: {{.*}}

diff  --git a/llvm/test/Transforms/SROA/mem-par-metadata-sroa-cast.ll b/llvm/test/Transforms/SROA/mem-par-metadata-sroa-cast.ll
index 032dd1701e596..ac9a6dbdc2669 100644
--- a/llvm/test/Transforms/SROA/mem-par-metadata-sroa-cast.ll
+++ b/llvm/test/Transforms/SROA/mem-par-metadata-sroa-cast.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -passes=sroa -S | FileCheck %s
+; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
 ;
 ; Make sure the llvm.access.group meta-data is preserved
 ; when a load/store is replaced with another load/store by sroa
@@ -35,3 +36,6 @@ entry:
 }
 
 !0 = distinct !{}
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-modify-cfg: {{.*}}
+; CHECK-preserve-cfg: {{.*}}

diff  --git a/llvm/test/Transforms/SROA/mem-par-metadata-sroa.ll b/llvm/test/Transforms/SROA/mem-par-metadata-sroa.ll
index 04d5e6ac46cb8..4df8f39bf2e88 100644
--- a/llvm/test/Transforms/SROA/mem-par-metadata-sroa.ll
+++ b/llvm/test/Transforms/SROA/mem-par-metadata-sroa.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -passes=sroa -S | FileCheck %s
+; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
 ;
 ; Make sure the llvm.access.group meta-data is preserved
 ; when a load/store is replaced with another load/store by sroa
@@ -121,3 +122,6 @@ attributes #1 = { argmemonly nounwind }
 !4 = distinct !{!4, !5, !"_ZNK7ComplexplERKS_: %agg.result"}
 !5 = distinct !{!5, !"_ZNK7ComplexplERKS_"}
 !11 = distinct !{}
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-modify-cfg: {{.*}}
+; CHECK-preserve-cfg: {{.*}}

diff  --git a/llvm/test/Transforms/SROA/non-capturing-call-readonly.ll b/llvm/test/Transforms/SROA/non-capturing-call-readonly.ll
index 33e6003c15607..a2cb0b2531ebe 100644
--- a/llvm/test/Transforms/SROA/non-capturing-call-readonly.ll
+++ b/llvm/test/Transforms/SROA/non-capturing-call-readonly.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -passes=sroa -S | FileCheck %s --check-prefix=CHECK
+; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
 
 define i32 @alloca_used_in_call(ptr %data, i64 %n) {
 ; CHECK-LABEL: @alloca_used_in_call(
@@ -917,3 +918,6 @@ declare dso_local void @byte_user_of_alloca(ptr nocapture readonly)
 declare dso_local i32 @__gxx_personality_v0(...)
 
 declare void @llvm.memcpy.p0.p0.i32(ptr, ptr, i32, i1)
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-modify-cfg: {{.*}}
+; CHECK-preserve-cfg: {{.*}}

diff  --git a/llvm/test/Transforms/SROA/non-integral-pointers.ll b/llvm/test/Transforms/SROA/non-integral-pointers.ll
index 99be316c4732c..a6a0b60fcd008 100644
--- a/llvm/test/Transforms/SROA/non-integral-pointers.ll
+++ b/llvm/test/Transforms/SROA/non-integral-pointers.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -passes=sroa -S < %s | FileCheck %s
+; RUN: opt -passes='sroa<preserve-cfg>' -S < %s | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt -passes='sroa<modify-cfg>' -S < %s | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
 
 ; This test checks that SROA does not introduce ptrtoint and inttoptr
 ; casts from and to non-integral pointers.  The "ni:4" bit in the
@@ -131,3 +132,6 @@ define ptr at f2(ptr addrspace(4) %p) {
 }
 
 declare void @llvm.memset.p0.i64(ptr, i8, i64, i1)
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-modify-cfg: {{.*}}
+; CHECK-preserve-cfg: {{.*}}

diff  --git a/llvm/test/Transforms/SROA/phi-and-select.ll b/llvm/test/Transforms/SROA/phi-and-select.ll
index 15b71590881c2..065ac3039a40a 100644
--- a/llvm/test/Transforms/SROA/phi-and-select.ll
+++ b/llvm/test/Transforms/SROA/phi-and-select.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -passes=sroa -S | FileCheck %s
+; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
 target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-n8:16:32:64"
 
 define i32 @test1() {
@@ -810,13 +811,23 @@ exit:
 
 ; Don't speculate a load based on an earlier volatile operation.
 define i8 @volatile_select(ptr %p, i1 %b) {
-; CHECK-LABEL: @volatile_select(
-; CHECK-NEXT:    [[P2:%.*]] = alloca i8, align 1
-; CHECK-NEXT:    store i8 0, ptr [[P2]], align 1
-; CHECK-NEXT:    store volatile i8 0, ptr [[P:%.*]], align 1
-; CHECK-NEXT:    [[PX:%.*]] = select i1 [[B:%.*]], ptr [[P]], ptr [[P2]]
-; CHECK-NEXT:    [[V2:%.*]] = load i8, ptr [[PX]], align 1
-; CHECK-NEXT:    ret i8 [[V2]]
+; CHECK-preserve-cfg-LABEL: @volatile_select(
+; CHECK-preserve-cfg-NEXT:    [[P2:%.*]] = alloca i8, align 1
+; CHECK-preserve-cfg-NEXT:    store i8 0, ptr [[P2]], align 1
+; CHECK-preserve-cfg-NEXT:    store volatile i8 0, ptr [[P:%.*]], align 1
+; CHECK-preserve-cfg-NEXT:    [[PX:%.*]] = select i1 [[B:%.*]], ptr [[P]], ptr [[P2]]
+; CHECK-preserve-cfg-NEXT:    [[V2:%.*]] = load i8, ptr [[PX]], align 1
+; CHECK-preserve-cfg-NEXT:    ret i8 [[V2]]
+;
+; CHECK-modify-cfg-LABEL: @volatile_select(
+; CHECK-modify-cfg-NEXT:    store volatile i8 0, ptr [[P:%.*]], align 1
+; CHECK-modify-cfg-NEXT:    br i1 [[B:%.*]], label [[DOTTHEN:%.*]], label [[DOTCONT:%.*]]
+; CHECK-modify-cfg:       .then:
+; CHECK-modify-cfg-NEXT:    [[V2_THEN_VAL:%.*]] = load i8, ptr [[P]], align 1
+; CHECK-modify-cfg-NEXT:    br label [[DOTCONT]]
+; CHECK-modify-cfg:       .cont:
+; CHECK-modify-cfg-NEXT:    [[V2:%.*]] = phi i8 [ [[V2_THEN_VAL]], [[DOTTHEN]] ], [ 0, [[TMP0:%.*]] ]
+; CHECK-modify-cfg-NEXT:    ret i8 [[V2]]
 ;
   %p2 = alloca i8
   store i8 0, ptr %p2

diff  --git a/llvm/test/Transforms/SROA/phi-catchswitch.ll b/llvm/test/Transforms/SROA/phi-catchswitch.ll
index ea90101883a66..0de7d0526731f 100644
--- a/llvm/test/Transforms/SROA/phi-catchswitch.ll
+++ b/llvm/test/Transforms/SROA/phi-catchswitch.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -passes=sroa -S | FileCheck %s
+; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
 
 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
 target triple = "wasm32-unknown-unknown"
@@ -63,3 +64,6 @@ bb10:                                             ; preds = %catch.dispatch, %en
   store i32 0, ptr %tmp11, align 4
   unreachable
 }
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-modify-cfg: {{.*}}
+; CHECK-preserve-cfg: {{.*}}

diff  --git a/llvm/test/Transforms/SROA/phi-gep.ll b/llvm/test/Transforms/SROA/phi-gep.ll
index 8ac3a183f206d..075b99acce943 100644
--- a/llvm/test/Transforms/SROA/phi-gep.ll
+++ b/llvm/test/Transforms/SROA/phi-gep.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -passes=sroa < %s | FileCheck %s
+; RUN: opt -S -passes='sroa<preserve-cfg>' < %s | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt -S -passes='sroa<modify-cfg>' < %s | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
 
 %pair = type { i32, i32 }
 
@@ -508,3 +509,6 @@ declare ptr @foo()
 declare i32 @__gxx_personality_v0(...)
 
 declare void @llvm.memcpy.p0.p0.i64(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg)
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-modify-cfg: {{.*}}
+; CHECK-preserve-cfg: {{.*}}

diff  --git a/llvm/test/Transforms/SROA/phi-speculate-
diff erent-load-types.ll b/llvm/test/Transforms/SROA/phi-speculate-
diff erent-load-types.ll
index 7893da340736f..5e98fbfea1493 100644
--- a/llvm/test/Transforms/SROA/phi-speculate-
diff erent-load-types.ll
+++ b/llvm/test/Transforms/SROA/phi-speculate-
diff erent-load-types.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -passes=sroa < %s -S | FileCheck %s
+; RUN: opt -passes='sroa<preserve-cfg>' < %s -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt -passes='sroa<modify-cfg>' < %s -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
 
 define void @f(i1 %i) {
 ; CHECK-LABEL: @f(
@@ -39,3 +40,6 @@ bb2:
 
 declare void @use32(i32)
 declare void @use64(i64)
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-modify-cfg: {{.*}}
+; CHECK-preserve-cfg: {{.*}}

diff  --git a/llvm/test/Transforms/SROA/phi-with-duplicate-pred.ll b/llvm/test/Transforms/SROA/phi-with-duplicate-pred.ll
index 2361a50937fe2..1d20fac624823 100644
--- a/llvm/test/Transforms/SROA/phi-with-duplicate-pred.ll
+++ b/llvm/test/Transforms/SROA/phi-with-duplicate-pred.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -passes=sroa -S | FileCheck %s
+; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
 target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-n8:16:32:64"
 
 @a = external global i16, align 1
@@ -263,3 +264,6 @@ final:
 cleanup7:                                         ; preds = %cleanup
   ret void
 }
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-modify-cfg: {{.*}}
+; CHECK-preserve-cfg: {{.*}}

diff  --git a/llvm/test/Transforms/SROA/pointer-offset-size.ll b/llvm/test/Transforms/SROA/pointer-offset-size.ll
index 76b52098a7e62..498261c1adb9e 100644
--- a/llvm/test/Transforms/SROA/pointer-offset-size.ll
+++ b/llvm/test/Transforms/SROA/pointer-offset-size.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -passes=sroa -S | FileCheck %s
+; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
 target datalayout = "e-p:64:64:64:32"
 
 %struct.test = type { %struct.basic, %struct.basic }
@@ -21,3 +22,6 @@ entry:
 }
 
 declare void @llvm.memcpy.p0.p0.i32(ptr nocapture writeonly, ptr nocapture readonly, i32, i1)
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-modify-cfg: {{.*}}
+; CHECK-preserve-cfg: {{.*}}

diff  --git a/llvm/test/Transforms/SROA/ppcf128-no-fold.ll b/llvm/test/Transforms/SROA/ppcf128-no-fold.ll
index b4a709018af76..74c6f12c7df18 100644
--- a/llvm/test/Transforms/SROA/ppcf128-no-fold.ll
+++ b/llvm/test/Transforms/SROA/ppcf128-no-fold.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -passes=sroa -S | FileCheck %s
+; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
 target datalayout = "E-m:e-i64:64-n32:64"
 target triple = "powerpc64-unknown-linux-gnu"
 
@@ -32,3 +33,6 @@ entry:
 
 attributes #0 = { nounwind }
 
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-modify-cfg: {{.*}}
+; CHECK-preserve-cfg: {{.*}}

diff  --git a/llvm/test/Transforms/SROA/pr26972.ll b/llvm/test/Transforms/SROA/pr26972.ll
index a0e6204873923..a51173892c194 100644
--- a/llvm/test/Transforms/SROA/pr26972.ll
+++ b/llvm/test/Transforms/SROA/pr26972.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -passes=sroa -S | FileCheck %s
+; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
 target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
 target triple = "x86_64-pc-linux"
 
@@ -16,3 +17,6 @@ define void @fn1() {
 }
 
 declare void @llvm.lifetime.end.p0(i64, ptr nocapture)
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-modify-cfg: {{.*}}
+; CHECK-preserve-cfg: {{.*}}

diff  --git a/llvm/test/Transforms/SROA/pr37267.ll b/llvm/test/Transforms/SROA/pr37267.ll
index f78375885fc56..4028fc2b486d0 100644
--- a/llvm/test/Transforms/SROA/pr37267.ll
+++ b/llvm/test/Transforms/SROA/pr37267.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -passes=sroa -S | FileCheck %s
+; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
 target datalayout = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32:64-S128"
 target triple = "sparcv9-sun-solaris"
 
@@ -78,3 +79,6 @@ bb1:
   %rc = add i16 %_tmp13, %_tmp16
   ret i16 %rc
 }
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-modify-cfg: {{.*}}
+; CHECK-preserve-cfg: {{.*}}

diff  --git a/llvm/test/Transforms/SROA/preserve-nonnull.ll b/llvm/test/Transforms/SROA/preserve-nonnull.ll
index b5b885c57c408..92be31840f571 100644
--- a/llvm/test/Transforms/SROA/preserve-nonnull.ll
+++ b/llvm/test/Transforms/SROA/preserve-nonnull.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -passes=sroa -S | FileCheck %s
+; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
 ;
 ; Make sure that SROA doesn't lose nonnull metadata
 ; on loads from allocas that get optimized out.
@@ -81,3 +82,6 @@ entry:
 }
 
 !0 = !{}
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-modify-cfg: {{.*}}
+; CHECK-preserve-cfg: {{.*}}

diff  --git a/llvm/test/Transforms/SROA/scalable-vectors.ll b/llvm/test/Transforms/SROA/scalable-vectors.ll
index 5c66654ba8cc5..510d07a96c6c6 100644
--- a/llvm/test/Transforms/SROA/scalable-vectors.ll
+++ b/llvm/test/Transforms/SROA/scalable-vectors.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -passes=sroa -S | FileCheck %s
+; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
 
 ; This test checks that SROA runs mem2reg on scalable vectors.
 
@@ -78,3 +79,6 @@ define <vscale x 4 x i32> @cast_alloca_from_svint32_t() {
 }
 
 declare void @llvm.memcpy.p0.p0.i64(ptr nocapture, ptr nocapture, i64, i1) nounwind
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-modify-cfg: {{.*}}
+; CHECK-preserve-cfg: {{.*}}

diff  --git a/llvm/test/Transforms/SROA/select-gep.ll b/llvm/test/Transforms/SROA/select-gep.ll
index 9586feb8b1606..23ab6dd470a70 100644
--- a/llvm/test/Transforms/SROA/select-gep.ll
+++ b/llvm/test/Transforms/SROA/select-gep.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -passes=sroa < %s | FileCheck %s
+; RUN: opt -S -passes='sroa<preserve-cfg>' < %s | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt -S -passes='sroa<modify-cfg>' < %s | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
 
 %pair = type { i32, i32 }
 
@@ -77,12 +78,22 @@ bb:
 }
 
 define i32 @test_sroa_select_gep_poison(i1 %cond) {
-; CHECK-LABEL: @test_sroa_select_gep_poison(
-; CHECK-NEXT:  bb:
-; CHECK-NEXT:    [[A_SROA_0:%.*]] = alloca i32, align 4
-; CHECK-NEXT:    [[SELECT_SROA_SEL:%.*]] = select i1 [[COND:%.*]], ptr [[A_SROA_0]], ptr poison
-; CHECK-NEXT:    [[LOAD:%.*]] = load i32, ptr [[SELECT_SROA_SEL]], align 4
-; CHECK-NEXT:    ret i32 [[LOAD]]
+; CHECK-preserve-cfg-LABEL: @test_sroa_select_gep_poison(
+; CHECK-preserve-cfg-NEXT:  bb:
+; CHECK-preserve-cfg-NEXT:    [[A_SROA_0:%.*]] = alloca i32, align 4
+; CHECK-preserve-cfg-NEXT:    [[SELECT_SROA_SEL:%.*]] = select i1 [[COND:%.*]], ptr [[A_SROA_0]], ptr poison
+; CHECK-preserve-cfg-NEXT:    [[LOAD:%.*]] = load i32, ptr [[SELECT_SROA_SEL]], align 4
+; CHECK-preserve-cfg-NEXT:    ret i32 [[LOAD]]
+;
+; CHECK-modify-cfg-LABEL: @test_sroa_select_gep_poison(
+; CHECK-modify-cfg-NEXT:  bb:
+; CHECK-modify-cfg-NEXT:    br i1 [[COND:%.*]], label [[BB_CONT:%.*]], label [[BB_ELSE:%.*]]
+; CHECK-modify-cfg:       bb.else:
+; CHECK-modify-cfg-NEXT:    [[LOAD_ELSE_VAL:%.*]] = load i32, ptr poison, align 4
+; CHECK-modify-cfg-NEXT:    br label [[BB_CONT]]
+; CHECK-modify-cfg:       bb.cont:
+; CHECK-modify-cfg-NEXT:    [[LOAD:%.*]] = phi i32 [ undef, [[BB:%.*]] ], [ [[LOAD_ELSE_VAL]], [[BB_ELSE]] ]
+; CHECK-modify-cfg-NEXT:    ret i32 [[LOAD]]
 ;
 bb:
   %a = alloca %pair, align 4

diff  --git a/llvm/test/Transforms/SROA/select-load.ll b/llvm/test/Transforms/SROA/select-load.ll
index dc6770d694dca..8ed296291c444 100644
--- a/llvm/test/Transforms/SROA/select-load.ll
+++ b/llvm/test/Transforms/SROA/select-load.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -passes=sroa < %s | FileCheck %s
+; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
 
 %st.half = type { half }
 
@@ -82,22 +83,41 @@ define i32 @interfering_lifetime(ptr %data, i64 %indvars.iv) {
 
 ; We should recursively evaluate select's.
 define i32 @clamp_load_to_constant_range(ptr %data, i64 %indvars.iv) {
-; CHECK-LABEL: @clamp_load_to_constant_range(
-; CHECK-NEXT:    [[MIN:%.*]] = alloca i32, align 4
-; CHECK-NEXT:    [[MAX:%.*]] = alloca i32, align 4
-; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[DATA:%.*]], i64 [[INDVARS_IV:%.*]]
-; CHECK-NEXT:    call void @llvm.lifetime.start.p0(i64 4, ptr [[MIN]])
-; CHECK-NEXT:    store i32 0, ptr [[MIN]], align 4
-; CHECK-NEXT:    call void @llvm.lifetime.start.p0(i64 4, ptr [[MAX]])
-; CHECK-NEXT:    store i32 4095, ptr [[MAX]], align 4
-; CHECK-NEXT:    [[I1:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
-; CHECK-NEXT:    [[CMP_I_I:%.*]] = icmp slt i32 [[I1]], 0
-; CHECK-NEXT:    [[I2:%.*]] = tail call i32 @llvm.smax.i32(i32 [[I1]], i32 0)
-; CHECK-NEXT:    [[__B___A_I_I:%.*]] = select i1 [[CMP_I_I]], ptr [[MIN]], ptr [[ARRAYIDX]]
-; CHECK-NEXT:    [[CMP_I1_I:%.*]] = icmp ugt i32 [[I2]], 4095
-; CHECK-NEXT:    [[__B___A_I2_I:%.*]] = select i1 [[CMP_I1_I]], ptr [[MAX]], ptr [[__B___A_I_I]]
-; CHECK-NEXT:    [[I3:%.*]] = load i32, ptr [[__B___A_I2_I]], align 4
-; CHECK-NEXT:    ret i32 [[I3]]
+; CHECK-preserve-cfg-LABEL: @clamp_load_to_constant_range(
+; CHECK-preserve-cfg-NEXT:    [[MIN:%.*]] = alloca i32, align 4
+; CHECK-preserve-cfg-NEXT:    [[MAX:%.*]] = alloca i32, align 4
+; CHECK-preserve-cfg-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[DATA:%.*]], i64 [[INDVARS_IV:%.*]]
+; CHECK-preserve-cfg-NEXT:    call void @llvm.lifetime.start.p0(i64 4, ptr [[MIN]])
+; CHECK-preserve-cfg-NEXT:    store i32 0, ptr [[MIN]], align 4
+; CHECK-preserve-cfg-NEXT:    call void @llvm.lifetime.start.p0(i64 4, ptr [[MAX]])
+; CHECK-preserve-cfg-NEXT:    store i32 4095, ptr [[MAX]], align 4
+; CHECK-preserve-cfg-NEXT:    [[I1:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
+; CHECK-preserve-cfg-NEXT:    [[CMP_I_I:%.*]] = icmp slt i32 [[I1]], 0
+; CHECK-preserve-cfg-NEXT:    [[I2:%.*]] = tail call i32 @llvm.smax.i32(i32 [[I1]], i32 0)
+; CHECK-preserve-cfg-NEXT:    [[__B___A_I_I:%.*]] = select i1 [[CMP_I_I]], ptr [[MIN]], ptr [[ARRAYIDX]]
+; CHECK-preserve-cfg-NEXT:    [[CMP_I1_I:%.*]] = icmp ugt i32 [[I2]], 4095
+; CHECK-preserve-cfg-NEXT:    [[__B___A_I2_I:%.*]] = select i1 [[CMP_I1_I]], ptr [[MAX]], ptr [[__B___A_I_I]]
+; CHECK-preserve-cfg-NEXT:    [[I3:%.*]] = load i32, ptr [[__B___A_I2_I]], align 4
+; CHECK-preserve-cfg-NEXT:    ret i32 [[I3]]
+;
+; CHECK-modify-cfg-LABEL: @clamp_load_to_constant_range(
+; CHECK-modify-cfg-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[DATA:%.*]], i64 [[INDVARS_IV:%.*]]
+; CHECK-modify-cfg-NEXT:    [[I1:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
+; CHECK-modify-cfg-NEXT:    [[CMP_I_I:%.*]] = icmp slt i32 [[I1]], 0
+; CHECK-modify-cfg-NEXT:    [[I2:%.*]] = tail call i32 @llvm.smax.i32(i32 [[I1]], i32 0)
+; CHECK-modify-cfg-NEXT:    [[CMP_I1_I:%.*]] = icmp ugt i32 [[I2]], 4095
+; CHECK-modify-cfg-NEXT:    br i1 [[CMP_I1_I]], label [[DOTCONT:%.*]], label [[DOTELSE:%.*]]
+; CHECK-modify-cfg:       .else:
+; CHECK-modify-cfg-NEXT:    br i1 [[CMP_I_I]], label [[DOTELSE_CONT:%.*]], label [[DOTELSE_ELSE:%.*]]
+; CHECK-modify-cfg:       .else.else:
+; CHECK-modify-cfg-NEXT:    [[I3_ELSE_VAL_ELSE_VAL:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
+; CHECK-modify-cfg-NEXT:    br label [[DOTELSE_CONT]]
+; CHECK-modify-cfg:       .else.cont:
+; CHECK-modify-cfg-NEXT:    [[I3_ELSE_VAL:%.*]] = phi i32 [ 0, [[DOTELSE]] ], [ [[I3_ELSE_VAL_ELSE_VAL]], [[DOTELSE_ELSE]] ]
+; CHECK-modify-cfg-NEXT:    br label [[DOTCONT]]
+; CHECK-modify-cfg:       .cont:
+; CHECK-modify-cfg-NEXT:    [[I3:%.*]] = phi i32 [ 4095, [[TMP0:%.*]] ], [ [[I3_ELSE_VAL]], [[DOTELSE_CONT]] ]
+; CHECK-modify-cfg-NEXT:    ret i32 [[I3]]
 ;
   %min = alloca i32, align 4
   %max = alloca i32, align 4
@@ -117,13 +137,23 @@ define i32 @clamp_load_to_constant_range(ptr %data, i64 %indvars.iv) {
 }
 
 define i32 @non_speculatable_load_of_select(i1 %cond, ptr %else.addr) {
-; CHECK-LABEL: @non_speculatable_load_of_select(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[MIN:%.*]] = alloca i32, align 4
-; CHECK-NEXT:    store i32 0, ptr [[MIN]], align 4
-; CHECK-NEXT:    [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[MIN]], ptr [[ELSE_ADDR:%.*]], !prof [[PROF0:![0-9]+]]
-; CHECK-NEXT:    [[R:%.*]] = load i32, ptr [[ADDR]], align 4
-; CHECK-NEXT:    ret i32 [[R]]
+; CHECK-preserve-cfg-LABEL: @non_speculatable_load_of_select(
+; CHECK-preserve-cfg-NEXT:  entry:
+; CHECK-preserve-cfg-NEXT:    [[MIN:%.*]] = alloca i32, align 4
+; CHECK-preserve-cfg-NEXT:    store i32 0, ptr [[MIN]], align 4
+; CHECK-preserve-cfg-NEXT:    [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[MIN]], ptr [[ELSE_ADDR:%.*]], !prof [[PROF0:![0-9]+]]
+; CHECK-preserve-cfg-NEXT:    [[R:%.*]] = load i32, ptr [[ADDR]], align 4
+; CHECK-preserve-cfg-NEXT:    ret i32 [[R]]
+;
+; CHECK-modify-cfg-LABEL: @non_speculatable_load_of_select(
+; CHECK-modify-cfg-NEXT:  entry:
+; CHECK-modify-cfg-NEXT:    br i1 [[COND:%.*]], label [[ENTRY_CONT:%.*]], label [[ENTRY_ELSE:%.*]], !prof [[PROF0:![0-9]+]]
+; CHECK-modify-cfg:       entry.else:
+; CHECK-modify-cfg-NEXT:    [[R_ELSE_VAL:%.*]] = load i32, ptr [[ELSE_ADDR:%.*]], align 4
+; CHECK-modify-cfg-NEXT:    br label [[ENTRY_CONT]]
+; CHECK-modify-cfg:       entry.cont:
+; CHECK-modify-cfg-NEXT:    [[R:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[R_ELSE_VAL]], [[ENTRY_ELSE]] ]
+; CHECK-modify-cfg-NEXT:    ret i32 [[R]]
 ;
 entry:
   %min = alloca i32, align 4
@@ -133,13 +163,23 @@ entry:
   ret i32 %r
 }
 define i32 @non_speculatable_load_of_select_inverted(i1 %cond, ptr %then.addr) {
-; CHECK-LABEL: @non_speculatable_load_of_select_inverted(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[MAX:%.*]] = alloca i32, align 4
-; CHECK-NEXT:    store i32 4095, ptr [[MAX]], align 4
-; CHECK-NEXT:    [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[THEN_ADDR:%.*]], ptr [[MAX]], !prof [[PROF0]]
-; CHECK-NEXT:    [[R:%.*]] = load i32, ptr [[ADDR]], align 4
-; CHECK-NEXT:    ret i32 [[R]]
+; CHECK-preserve-cfg-LABEL: @non_speculatable_load_of_select_inverted(
+; CHECK-preserve-cfg-NEXT:  entry:
+; CHECK-preserve-cfg-NEXT:    [[MAX:%.*]] = alloca i32, align 4
+; CHECK-preserve-cfg-NEXT:    store i32 4095, ptr [[MAX]], align 4
+; CHECK-preserve-cfg-NEXT:    [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[THEN_ADDR:%.*]], ptr [[MAX]], !prof [[PROF0]]
+; CHECK-preserve-cfg-NEXT:    [[R:%.*]] = load i32, ptr [[ADDR]], align 4
+; CHECK-preserve-cfg-NEXT:    ret i32 [[R]]
+;
+; CHECK-modify-cfg-LABEL: @non_speculatable_load_of_select_inverted(
+; CHECK-modify-cfg-NEXT:  entry:
+; CHECK-modify-cfg-NEXT:    br i1 [[COND:%.*]], label [[ENTRY_THEN:%.*]], label [[ENTRY_CONT:%.*]], !prof [[PROF1:![0-9]+]]
+; CHECK-modify-cfg:       entry.then:
+; CHECK-modify-cfg-NEXT:    [[R_THEN_VAL:%.*]] = load i32, ptr [[THEN_ADDR:%.*]], align 4
+; CHECK-modify-cfg-NEXT:    br label [[ENTRY_CONT]]
+; CHECK-modify-cfg:       entry.cont:
+; CHECK-modify-cfg-NEXT:    [[R:%.*]] = phi i32 [ [[R_THEN_VAL]], [[ENTRY_THEN]] ], [ 4095, [[ENTRY:%.*]] ]
+; CHECK-modify-cfg-NEXT:    ret i32 [[R]]
 ;
 entry:
   %max = alloca i32, align 4
@@ -150,13 +190,21 @@ entry:
 }
 
 define i32 @non_speculatable_volatile_load_of_select(i1 %cond, ptr %else.addr) {
-; CHECK-LABEL: @non_speculatable_volatile_load_of_select(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[MIN:%.*]] = alloca i32, align 4
-; CHECK-NEXT:    store i32 0, ptr [[MIN]], align 4
-; CHECK-NEXT:    [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[MIN]], ptr [[ELSE_ADDR:%.*]], !prof [[PROF0]]
-; CHECK-NEXT:    [[R:%.*]] = load volatile i32, ptr [[ADDR]], align 4
-; CHECK-NEXT:    ret i32 [[R]]
+; CHECK-preserve-cfg-LABEL: @non_speculatable_volatile_load_of_select(
+; CHECK-preserve-cfg-NEXT:  entry:
+; CHECK-preserve-cfg-NEXT:    [[MIN:%.*]] = alloca i32, align 4
+; CHECK-preserve-cfg-NEXT:    store i32 0, ptr [[MIN]], align 4
+; CHECK-preserve-cfg-NEXT:    [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[MIN]], ptr [[ELSE_ADDR:%.*]], !prof [[PROF0]]
+; CHECK-preserve-cfg-NEXT:    [[R:%.*]] = load volatile i32, ptr [[ADDR]], align 4
+; CHECK-preserve-cfg-NEXT:    ret i32 [[R]]
+;
+; CHECK-modify-cfg-LABEL: @non_speculatable_volatile_load_of_select(
+; CHECK-modify-cfg-NEXT:  entry:
+; CHECK-modify-cfg-NEXT:    [[MIN:%.*]] = alloca i32, align 4
+; CHECK-modify-cfg-NEXT:    store i32 0, ptr [[MIN]], align 4
+; CHECK-modify-cfg-NEXT:    [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[MIN]], ptr [[ELSE_ADDR:%.*]], !prof [[PROF1]]
+; CHECK-modify-cfg-NEXT:    [[R:%.*]] = load volatile i32, ptr [[ADDR]], align 4
+; CHECK-modify-cfg-NEXT:    ret i32 [[R]]
 ;
 entry:
   %min = alloca i32, align 4
@@ -166,13 +214,21 @@ entry:
   ret i32 %r
 }
 define i32 @non_speculatable_volatile_load_of_select_inverted(i1 %cond, ptr %then.addr) {
-; CHECK-LABEL: @non_speculatable_volatile_load_of_select_inverted(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[MAX:%.*]] = alloca i32, align 4
-; CHECK-NEXT:    store i32 4095, ptr [[MAX]], align 4
-; CHECK-NEXT:    [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[THEN_ADDR:%.*]], ptr [[MAX]], !prof [[PROF0]]
-; CHECK-NEXT:    [[R:%.*]] = load volatile i32, ptr [[ADDR]], align 4
-; CHECK-NEXT:    ret i32 [[R]]
+; CHECK-preserve-cfg-LABEL: @non_speculatable_volatile_load_of_select_inverted(
+; CHECK-preserve-cfg-NEXT:  entry:
+; CHECK-preserve-cfg-NEXT:    [[MAX:%.*]] = alloca i32, align 4
+; CHECK-preserve-cfg-NEXT:    store i32 4095, ptr [[MAX]], align 4
+; CHECK-preserve-cfg-NEXT:    [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[THEN_ADDR:%.*]], ptr [[MAX]], !prof [[PROF0]]
+; CHECK-preserve-cfg-NEXT:    [[R:%.*]] = load volatile i32, ptr [[ADDR]], align 4
+; CHECK-preserve-cfg-NEXT:    ret i32 [[R]]
+;
+; CHECK-modify-cfg-LABEL: @non_speculatable_volatile_load_of_select_inverted(
+; CHECK-modify-cfg-NEXT:  entry:
+; CHECK-modify-cfg-NEXT:    [[MAX:%.*]] = alloca i32, align 4
+; CHECK-modify-cfg-NEXT:    store i32 4095, ptr [[MAX]], align 4
+; CHECK-modify-cfg-NEXT:    [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[THEN_ADDR:%.*]], ptr [[MAX]], !prof [[PROF1]]
+; CHECK-modify-cfg-NEXT:    [[R:%.*]] = load volatile i32, ptr [[ADDR]], align 4
+; CHECK-modify-cfg-NEXT:    ret i32 [[R]]
 ;
 entry:
   %max = alloca i32, align 4
@@ -183,13 +239,25 @@ entry:
 }
 
 define i32 @non_speculatable_atomic_unord_load_of_select(i1 %cond, ptr %else.addr) {
-; CHECK-LABEL: @non_speculatable_atomic_unord_load_of_select(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[MIN:%.*]] = alloca i32, align 4
-; CHECK-NEXT:    store i32 0, ptr [[MIN]], align 4
-; CHECK-NEXT:    [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[MIN]], ptr [[ELSE_ADDR:%.*]], !prof [[PROF0]]
-; CHECK-NEXT:    [[R:%.*]] = load atomic i32, ptr [[ADDR]] unordered, align 4
-; CHECK-NEXT:    ret i32 [[R]]
+; CHECK-preserve-cfg-LABEL: @non_speculatable_atomic_unord_load_of_select(
+; CHECK-preserve-cfg-NEXT:  entry:
+; CHECK-preserve-cfg-NEXT:    [[MIN:%.*]] = alloca i32, align 4
+; CHECK-preserve-cfg-NEXT:    store i32 0, ptr [[MIN]], align 4
+; CHECK-preserve-cfg-NEXT:    [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[MIN]], ptr [[ELSE_ADDR:%.*]], !prof [[PROF0]]
+; CHECK-preserve-cfg-NEXT:    [[R:%.*]] = load atomic i32, ptr [[ADDR]] unordered, align 4
+; CHECK-preserve-cfg-NEXT:    ret i32 [[R]]
+;
+; CHECK-modify-cfg-LABEL: @non_speculatable_atomic_unord_load_of_select(
+; CHECK-modify-cfg-NEXT:  entry:
+; CHECK-modify-cfg-NEXT:    br i1 [[COND:%.*]], label [[ENTRY_THEN:%.*]], label [[ENTRY_ELSE:%.*]], !prof [[PROF1]]
+; CHECK-modify-cfg:       entry.then:
+; CHECK-modify-cfg-NEXT:    br label [[ENTRY_CONT:%.*]]
+; CHECK-modify-cfg:       entry.else:
+; CHECK-modify-cfg-NEXT:    [[R_ELSE_VAL:%.*]] = load atomic i32, ptr [[ELSE_ADDR:%.*]] unordered, align 4
+; CHECK-modify-cfg-NEXT:    br label [[ENTRY_CONT]]
+; CHECK-modify-cfg:       entry.cont:
+; CHECK-modify-cfg-NEXT:    [[R:%.*]] = phi i32 [ 0, [[ENTRY_THEN]] ], [ [[R_ELSE_VAL]], [[ENTRY_ELSE]] ]
+; CHECK-modify-cfg-NEXT:    ret i32 [[R]]
 ;
 entry:
   %min = alloca i32, align 4
@@ -199,13 +267,25 @@ entry:
   ret i32 %r
 }
 define i32 @non_speculatable_atomic_unord_load_of_select_inverted(i1 %cond, ptr %then.addr) {
-; CHECK-LABEL: @non_speculatable_atomic_unord_load_of_select_inverted(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[MAX:%.*]] = alloca i32, align 4
-; CHECK-NEXT:    store i32 4095, ptr [[MAX]], align 4
-; CHECK-NEXT:    [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[THEN_ADDR:%.*]], ptr [[MAX]], !prof [[PROF0]]
-; CHECK-NEXT:    [[R:%.*]] = load atomic i32, ptr [[ADDR]] unordered, align 4
-; CHECK-NEXT:    ret i32 [[R]]
+; CHECK-preserve-cfg-LABEL: @non_speculatable_atomic_unord_load_of_select_inverted(
+; CHECK-preserve-cfg-NEXT:  entry:
+; CHECK-preserve-cfg-NEXT:    [[MAX:%.*]] = alloca i32, align 4
+; CHECK-preserve-cfg-NEXT:    store i32 4095, ptr [[MAX]], align 4
+; CHECK-preserve-cfg-NEXT:    [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[THEN_ADDR:%.*]], ptr [[MAX]], !prof [[PROF0]]
+; CHECK-preserve-cfg-NEXT:    [[R:%.*]] = load atomic i32, ptr [[ADDR]] unordered, align 4
+; CHECK-preserve-cfg-NEXT:    ret i32 [[R]]
+;
+; CHECK-modify-cfg-LABEL: @non_speculatable_atomic_unord_load_of_select_inverted(
+; CHECK-modify-cfg-NEXT:  entry:
+; CHECK-modify-cfg-NEXT:    br i1 [[COND:%.*]], label [[ENTRY_THEN:%.*]], label [[ENTRY_ELSE:%.*]], !prof [[PROF1]]
+; CHECK-modify-cfg:       entry.then:
+; CHECK-modify-cfg-NEXT:    [[R_THEN_VAL:%.*]] = load atomic i32, ptr [[THEN_ADDR:%.*]] unordered, align 4
+; CHECK-modify-cfg-NEXT:    br label [[ENTRY_CONT:%.*]]
+; CHECK-modify-cfg:       entry.else:
+; CHECK-modify-cfg-NEXT:    br label [[ENTRY_CONT]]
+; CHECK-modify-cfg:       entry.cont:
+; CHECK-modify-cfg-NEXT:    [[R:%.*]] = phi i32 [ [[R_THEN_VAL]], [[ENTRY_THEN]] ], [ 4095, [[ENTRY_ELSE]] ]
+; CHECK-modify-cfg-NEXT:    ret i32 [[R]]
 ;
 entry:
   %max = alloca i32, align 4
@@ -216,14 +296,25 @@ entry:
 }
 
 define i32 @non_speculatable_load_of_select_outer(i1 %cond_inner, i1 %cond_outer, ptr %data_then, ptr %data_else) {
-; CHECK-LABEL: @non_speculatable_load_of_select_outer(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[MIN:%.*]] = alloca i32, align 4
-; CHECK-NEXT:    store i32 0, ptr [[MIN]], align 4
-; CHECK-NEXT:    [[ADDR_DATA:%.*]] = select i1 [[COND_INNER:%.*]], ptr [[DATA_THEN:%.*]], ptr [[DATA_ELSE:%.*]], !prof [[PROF0]]
-; CHECK-NEXT:    [[ADDR:%.*]] = select i1 [[COND_OUTER:%.*]], ptr [[MIN]], ptr [[ADDR_DATA]], !prof [[PROF0]]
-; CHECK-NEXT:    [[R:%.*]] = load i32, ptr [[ADDR]], align 4
-; CHECK-NEXT:    ret i32 [[R]]
+; CHECK-preserve-cfg-LABEL: @non_speculatable_load_of_select_outer(
+; CHECK-preserve-cfg-NEXT:  entry:
+; CHECK-preserve-cfg-NEXT:    [[MIN:%.*]] = alloca i32, align 4
+; CHECK-preserve-cfg-NEXT:    store i32 0, ptr [[MIN]], align 4
+; CHECK-preserve-cfg-NEXT:    [[ADDR_DATA:%.*]] = select i1 [[COND_INNER:%.*]], ptr [[DATA_THEN:%.*]], ptr [[DATA_ELSE:%.*]], !prof [[PROF0]]
+; CHECK-preserve-cfg-NEXT:    [[ADDR:%.*]] = select i1 [[COND_OUTER:%.*]], ptr [[MIN]], ptr [[ADDR_DATA]], !prof [[PROF0]]
+; CHECK-preserve-cfg-NEXT:    [[R:%.*]] = load i32, ptr [[ADDR]], align 4
+; CHECK-preserve-cfg-NEXT:    ret i32 [[R]]
+;
+; CHECK-modify-cfg-LABEL: @non_speculatable_load_of_select_outer(
+; CHECK-modify-cfg-NEXT:  entry:
+; CHECK-modify-cfg-NEXT:    [[ADDR_DATA:%.*]] = select i1 [[COND_INNER:%.*]], ptr [[DATA_THEN:%.*]], ptr [[DATA_ELSE:%.*]], !prof [[PROF1]]
+; CHECK-modify-cfg-NEXT:    br i1 [[COND_OUTER:%.*]], label [[ENTRY_CONT:%.*]], label [[ENTRY_ELSE:%.*]], !prof [[PROF0]]
+; CHECK-modify-cfg:       entry.else:
+; CHECK-modify-cfg-NEXT:    [[R_ELSE_VAL:%.*]] = load i32, ptr [[ADDR_DATA]], align 4
+; CHECK-modify-cfg-NEXT:    br label [[ENTRY_CONT]]
+; CHECK-modify-cfg:       entry.cont:
+; CHECK-modify-cfg-NEXT:    [[R:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[R_ELSE_VAL]], [[ENTRY_ELSE]] ]
+; CHECK-modify-cfg-NEXT:    ret i32 [[R]]
 ;
 entry:
   %min = alloca i32, align 4
@@ -234,14 +325,25 @@ entry:
   ret i32 %r
 }
 define i32 @non_speculatable_load_of_select_outer_inverted(i1 %cond_inner, i1 %cond_outer, ptr %data_then, ptr %data_else) {
-; CHECK-LABEL: @non_speculatable_load_of_select_outer_inverted(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[MIN:%.*]] = alloca i32, align 4
-; CHECK-NEXT:    store i32 0, ptr [[MIN]], align 4
-; CHECK-NEXT:    [[ADDR_DATA:%.*]] = select i1 [[COND_INNER:%.*]], ptr [[DATA_THEN:%.*]], ptr [[DATA_ELSE:%.*]], !prof [[PROF0]]
-; CHECK-NEXT:    [[ADDR:%.*]] = select i1 [[COND_OUTER:%.*]], ptr [[ADDR_DATA]], ptr [[MIN]], !prof [[PROF0]]
-; CHECK-NEXT:    [[R:%.*]] = load i32, ptr [[ADDR]], align 4
-; CHECK-NEXT:    ret i32 [[R]]
+; CHECK-preserve-cfg-LABEL: @non_speculatable_load_of_select_outer_inverted(
+; CHECK-preserve-cfg-NEXT:  entry:
+; CHECK-preserve-cfg-NEXT:    [[MIN:%.*]] = alloca i32, align 4
+; CHECK-preserve-cfg-NEXT:    store i32 0, ptr [[MIN]], align 4
+; CHECK-preserve-cfg-NEXT:    [[ADDR_DATA:%.*]] = select i1 [[COND_INNER:%.*]], ptr [[DATA_THEN:%.*]], ptr [[DATA_ELSE:%.*]], !prof [[PROF0]]
+; CHECK-preserve-cfg-NEXT:    [[ADDR:%.*]] = select i1 [[COND_OUTER:%.*]], ptr [[ADDR_DATA]], ptr [[MIN]], !prof [[PROF0]]
+; CHECK-preserve-cfg-NEXT:    [[R:%.*]] = load i32, ptr [[ADDR]], align 4
+; CHECK-preserve-cfg-NEXT:    ret i32 [[R]]
+;
+; CHECK-modify-cfg-LABEL: @non_speculatable_load_of_select_outer_inverted(
+; CHECK-modify-cfg-NEXT:  entry:
+; CHECK-modify-cfg-NEXT:    [[ADDR_DATA:%.*]] = select i1 [[COND_INNER:%.*]], ptr [[DATA_THEN:%.*]], ptr [[DATA_ELSE:%.*]], !prof [[PROF1]]
+; CHECK-modify-cfg-NEXT:    br i1 [[COND_OUTER:%.*]], label [[ENTRY_THEN:%.*]], label [[ENTRY_CONT:%.*]], !prof [[PROF1]]
+; CHECK-modify-cfg:       entry.then:
+; CHECK-modify-cfg-NEXT:    [[R_THEN_VAL:%.*]] = load i32, ptr [[ADDR_DATA]], align 4
+; CHECK-modify-cfg-NEXT:    br label [[ENTRY_CONT]]
+; CHECK-modify-cfg:       entry.cont:
+; CHECK-modify-cfg-NEXT:    [[R:%.*]] = phi i32 [ [[R_THEN_VAL]], [[ENTRY_THEN]] ], [ 0, [[ENTRY:%.*]] ]
+; CHECK-modify-cfg-NEXT:    ret i32 [[R]]
 ;
 entry:
   %min = alloca i32, align 4
@@ -253,14 +355,23 @@ entry:
 }
 
 define i32 @non_speculatable_load_of_select_inner(i1 %cond_inner, i1 %cond_outer, ptr %data_else, ptr %min_else) {
-; CHECK-LABEL: @non_speculatable_load_of_select_inner(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[MIN:%.*]] = alloca i32, align 4
-; CHECK-NEXT:    store i32 0, ptr [[MIN]], align 4
-; CHECK-NEXT:    [[MIN_ADDR_DATA:%.*]] = select i1 [[COND_INNER:%.*]], ptr [[MIN]], ptr [[MIN_ELSE:%.*]], !prof [[PROF0]]
-; CHECK-NEXT:    [[ADDR:%.*]] = select i1 [[COND_OUTER:%.*]], ptr [[MIN_ADDR_DATA]], ptr [[DATA_ELSE:%.*]], !prof [[PROF0]]
-; CHECK-NEXT:    [[R:%.*]] = load i32, ptr [[ADDR]], align 4
-; CHECK-NEXT:    ret i32 [[R]]
+; CHECK-preserve-cfg-LABEL: @non_speculatable_load_of_select_inner(
+; CHECK-preserve-cfg-NEXT:  entry:
+; CHECK-preserve-cfg-NEXT:    [[MIN:%.*]] = alloca i32, align 4
+; CHECK-preserve-cfg-NEXT:    store i32 0, ptr [[MIN]], align 4
+; CHECK-preserve-cfg-NEXT:    [[MIN_ADDR_DATA:%.*]] = select i1 [[COND_INNER:%.*]], ptr [[MIN]], ptr [[MIN_ELSE:%.*]], !prof [[PROF0]]
+; CHECK-preserve-cfg-NEXT:    [[ADDR:%.*]] = select i1 [[COND_OUTER:%.*]], ptr [[MIN_ADDR_DATA]], ptr [[DATA_ELSE:%.*]], !prof [[PROF0]]
+; CHECK-preserve-cfg-NEXT:    [[R:%.*]] = load i32, ptr [[ADDR]], align 4
+; CHECK-preserve-cfg-NEXT:    ret i32 [[R]]
+;
+; CHECK-modify-cfg-LABEL: @non_speculatable_load_of_select_inner(
+; CHECK-modify-cfg-NEXT:  entry:
+; CHECK-modify-cfg-NEXT:    [[MIN:%.*]] = alloca i32, align 4
+; CHECK-modify-cfg-NEXT:    store i32 0, ptr [[MIN]], align 4
+; CHECK-modify-cfg-NEXT:    [[MIN_ADDR_DATA:%.*]] = select i1 [[COND_INNER:%.*]], ptr [[MIN]], ptr [[MIN_ELSE:%.*]], !prof [[PROF1]]
+; CHECK-modify-cfg-NEXT:    [[ADDR:%.*]] = select i1 [[COND_OUTER:%.*]], ptr [[MIN_ADDR_DATA]], ptr [[DATA_ELSE:%.*]], !prof [[PROF1]]
+; CHECK-modify-cfg-NEXT:    [[R:%.*]] = load i32, ptr [[ADDR]], align 4
+; CHECK-modify-cfg-NEXT:    ret i32 [[R]]
 ;
 entry:
   %min = alloca i32, align 4
@@ -271,14 +382,23 @@ entry:
   ret i32 %r
 }
 define i32 @non_speculatable_load_of_select_inner_inverted(i1 %cond_inner, i1 %cond_outer, ptr %data_else, ptr %min_then) {
-; CHECK-LABEL: @non_speculatable_load_of_select_inner_inverted(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[MIN:%.*]] = alloca i32, align 4
-; CHECK-NEXT:    store i32 0, ptr [[MIN]], align 4
-; CHECK-NEXT:    [[MIN_ADDR_DATA:%.*]] = select i1 [[COND_INNER:%.*]], ptr [[MIN_THEN:%.*]], ptr [[MIN]], !prof [[PROF0]]
-; CHECK-NEXT:    [[ADDR:%.*]] = select i1 [[COND_OUTER:%.*]], ptr [[MIN_ADDR_DATA]], ptr [[DATA_ELSE:%.*]], !prof [[PROF0]]
-; CHECK-NEXT:    [[R:%.*]] = load i32, ptr [[ADDR]], align 4
-; CHECK-NEXT:    ret i32 [[R]]
+; CHECK-preserve-cfg-LABEL: @non_speculatable_load_of_select_inner_inverted(
+; CHECK-preserve-cfg-NEXT:  entry:
+; CHECK-preserve-cfg-NEXT:    [[MIN:%.*]] = alloca i32, align 4
+; CHECK-preserve-cfg-NEXT:    store i32 0, ptr [[MIN]], align 4
+; CHECK-preserve-cfg-NEXT:    [[MIN_ADDR_DATA:%.*]] = select i1 [[COND_INNER:%.*]], ptr [[MIN_THEN:%.*]], ptr [[MIN]], !prof [[PROF0]]
+; CHECK-preserve-cfg-NEXT:    [[ADDR:%.*]] = select i1 [[COND_OUTER:%.*]], ptr [[MIN_ADDR_DATA]], ptr [[DATA_ELSE:%.*]], !prof [[PROF0]]
+; CHECK-preserve-cfg-NEXT:    [[R:%.*]] = load i32, ptr [[ADDR]], align 4
+; CHECK-preserve-cfg-NEXT:    ret i32 [[R]]
+;
+; CHECK-modify-cfg-LABEL: @non_speculatable_load_of_select_inner_inverted(
+; CHECK-modify-cfg-NEXT:  entry:
+; CHECK-modify-cfg-NEXT:    [[MIN:%.*]] = alloca i32, align 4
+; CHECK-modify-cfg-NEXT:    store i32 0, ptr [[MIN]], align 4
+; CHECK-modify-cfg-NEXT:    [[MIN_ADDR_DATA:%.*]] = select i1 [[COND_INNER:%.*]], ptr [[MIN_THEN:%.*]], ptr [[MIN]], !prof [[PROF1]]
+; CHECK-modify-cfg-NEXT:    [[ADDR:%.*]] = select i1 [[COND_OUTER:%.*]], ptr [[MIN_ADDR_DATA]], ptr [[DATA_ELSE:%.*]], !prof [[PROF1]]
+; CHECK-modify-cfg-NEXT:    [[R:%.*]] = load i32, ptr [[ADDR]], align 4
+; CHECK-modify-cfg-NEXT:    ret i32 [[R]]
 ;
 entry:
   %min = alloca i32, align 4

diff  --git a/llvm/test/Transforms/SROA/slice-order-independence.ll b/llvm/test/Transforms/SROA/slice-order-independence.ll
index 47ac791ae56bc..e4a099278fdb6 100644
--- a/llvm/test/Transforms/SROA/slice-order-independence.ll
+++ b/llvm/test/Transforms/SROA/slice-order-independence.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -passes=sroa -S | FileCheck %s
+; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
 target datalayout = "e-p:64:64:64-p1:16:16:16-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-n8:16:32:64"
 
 declare void @llvm.memcpy.p0.p0.i32(ptr nocapture, ptr nocapture, i32, i1) nounwind
@@ -44,3 +45,6 @@ define void @skipped_inttype_last(ptr) {
   %b0 = load i63, ptr %b
   ret void
 }
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-modify-cfg: {{.*}}
+; CHECK-preserve-cfg: {{.*}}

diff  --git a/llvm/test/Transforms/SROA/slice-width.ll b/llvm/test/Transforms/SROA/slice-width.ll
index 7d2aeaaff57bc..8079a9cb10eb2 100644
--- a/llvm/test/Transforms/SROA/slice-width.ll
+++ b/llvm/test/Transforms/SROA/slice-width.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -passes=sroa -S | FileCheck %s
+; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
 target datalayout = "e-p:64:64:64-p1:16:16:16-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-f80:128-v64:64:64-v128:128:128-a0:0:64-n8:16:32:64"
 
 declare void @llvm.memcpy.p0.p0.i32(ptr nocapture, ptr nocapture, i32, i1) nounwind
@@ -157,3 +158,6 @@ define i1 @presplit_overlarge_load() {
   %L2 = load i1, ptr %A
   ret i1 %L2
 }
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-modify-cfg: {{.*}}
+; CHECK-preserve-cfg: {{.*}}

diff  --git a/llvm/test/Transforms/SROA/sroa-common-type-fail-promotion.ll b/llvm/test/Transforms/SROA/sroa-common-type-fail-promotion.ll
index 00cbe56929c02..f037d5cfbadc5 100644
--- a/llvm/test/Transforms/SROA/sroa-common-type-fail-promotion.ll
+++ b/llvm/test/Transforms/SROA/sroa-common-type-fail-promotion.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -passes=sroa -S < %s | FileCheck %s
+; RUN: opt -passes='sroa<preserve-cfg>' -S < %s | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt -passes='sroa<modify-cfg>' -S < %s | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
 
 %"struct.a" = type { <8 x half> }
 %"struct.b" = type { %"struct.a" }
@@ -409,3 +410,6 @@ declare void @llvm.memset.p0.i64(ptr nocapture writeonly, i8, i64, i1) nounwind
 declare void @llvm.memset.p0.i32(ptr nocapture writeonly, i8, i32, i1) nounwind
 attributes #0 = { nounwind readonly }
 
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-modify-cfg: {{.*}}
+; CHECK-preserve-cfg: {{.*}}

diff  --git a/llvm/test/Transforms/SROA/std-clamp.ll b/llvm/test/Transforms/SROA/std-clamp.ll
index b95030245bf25..07ffd11ca5aaa 100644
--- a/llvm/test/Transforms/SROA/std-clamp.ll
+++ b/llvm/test/Transforms/SROA/std-clamp.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -passes=sroa -S | FileCheck %s
+; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
 
 target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
 
@@ -29,3 +30,6 @@ bb:
   %i9 = load float, ptr %i8, align 4
   ret float %i9
 }
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-modify-cfg: {{.*}}
+; CHECK-preserve-cfg: {{.*}}

diff  --git a/llvm/test/Transforms/SROA/tbaa-struct.ll b/llvm/test/Transforms/SROA/tbaa-struct.ll
index 3e9332c5b11c0..d16a84bc02e60 100644
--- a/llvm/test/Transforms/SROA/tbaa-struct.ll
+++ b/llvm/test/Transforms/SROA/tbaa-struct.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -passes=sroa %s | FileCheck %s
+; RUN: opt -S -passes='sroa<preserve-cfg>' %s | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt -S -passes='sroa<modify-cfg>' %s | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
 
 ; SROA should keep `!tbaa.struct` metadata
 
@@ -26,3 +27,6 @@ define void @bar(ptr %y2) {
 !8 = !{!"float", !4, i64 0}
 !10 = !{i64 0, i64 4, !11, i64 4, i64 4, !11}
 !11 = !{!8, !8, i64 0}
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-modify-cfg: {{.*}}
+; CHECK-preserve-cfg: {{.*}}

diff  --git a/llvm/test/Transforms/SROA/tbaa-struct2.ll b/llvm/test/Transforms/SROA/tbaa-struct2.ll
index 484651ab0e483..f37e523d17659 100644
--- a/llvm/test/Transforms/SROA/tbaa-struct2.ll
+++ b/llvm/test/Transforms/SROA/tbaa-struct2.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -passes=sroa %s | FileCheck %s
+; RUN: opt -S -passes='sroa<preserve-cfg>' %s | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt -S -passes='sroa<modify-cfg>' %s | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
 
 ; SROA should correctly offset `!tbaa.struct` metadata
 
@@ -34,3 +35,6 @@ define double @bar(ptr %wishart) {
 !6 = !{!"Simple C++ TBAA"}
 !7 = !{!8, !8, i64 0}
 !8 = !{!"int", !5, i64 0}
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-modify-cfg: {{.*}}
+; CHECK-preserve-cfg: {{.*}}

diff  --git a/llvm/test/Transforms/SROA/tbaa-subload.ll b/llvm/test/Transforms/SROA/tbaa-subload.ll
index c43b78f993901..456ec4802ba76 100644
--- a/llvm/test/Transforms/SROA/tbaa-subload.ll
+++ b/llvm/test/Transforms/SROA/tbaa-subload.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -passes=sroa %s | FileCheck %s
+; RUN: opt -S -passes='sroa<preserve-cfg>' %s | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt -S -passes='sroa<modify-cfg>' %s | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
 
 ; This should not crash
 
@@ -34,3 +35,6 @@ declare void @use(ptr %this)
 !7 = !{!8, !3, i64 8}
 !8 = !{!"_ZTSZN2ax2baEMS_FvvE2an2arE3$_0", !9, i64 0, !3, i64 8}
 !9 = !{!"_ZTS2ar"}
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-modify-cfg: {{.*}}
+; CHECK-preserve-cfg: {{.*}}

diff  --git a/llvm/test/Transforms/SROA/vector-conversion.ll b/llvm/test/Transforms/SROA/vector-conversion.ll
index 3661f481326ff..3a62754672ab7 100644
--- a/llvm/test/Transforms/SROA/vector-conversion.ll
+++ b/llvm/test/Transforms/SROA/vector-conversion.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -passes=sroa -S | FileCheck %s
+; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
 target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-n8:16:32:64"
 
 define <4 x i64> @vector_ptrtoint({<2 x ptr>, <2 x ptr>} %x) {
@@ -98,3 +99,6 @@ define <16 x i8> @vector_ptrtointbitcast_vector({<2 x ptr>, <2 x ptr>} %x) {
 
   ret <16 x i8> %vec
 }
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-modify-cfg: {{.*}}
+; CHECK-preserve-cfg: {{.*}}

diff  --git a/llvm/test/Transforms/SROA/vector-lifetime-intrinsic.ll b/llvm/test/Transforms/SROA/vector-lifetime-intrinsic.ll
index ad34b7b30c085..58eafc2dfe2f4 100644
--- a/llvm/test/Transforms/SROA/vector-lifetime-intrinsic.ll
+++ b/llvm/test/Transforms/SROA/vector-lifetime-intrinsic.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -passes=sroa -S < %s | FileCheck %s
+; RUN: opt -passes='sroa<preserve-cfg>' -S < %s | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt -passes='sroa<modify-cfg>' -S < %s | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
 
 target datalayout = "e-p:64:32-i64:32-v32:32-n32-S64"
 
@@ -30,3 +31,6 @@ bb:
 declare void @wombat3(<3 x float>) #0
 
 attributes #0 = { nounwind }
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-modify-cfg: {{.*}}
+; CHECK-preserve-cfg: {{.*}}

diff  --git a/llvm/test/Transforms/SROA/vector-promotion-
diff erent-size.ll b/llvm/test/Transforms/SROA/vector-promotion-
diff erent-size.ll
index a410c8a5b633e..7b19a21e16c72 100644
--- a/llvm/test/Transforms/SROA/vector-promotion-
diff erent-size.ll
+++ b/llvm/test/Transforms/SROA/vector-promotion-
diff erent-size.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -passes=sroa -S | FileCheck %s
+; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
 target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-n8:16:32:64"
 
 define <4 x i1> @vector_bitcast() {
@@ -27,3 +28,6 @@ define <64 x i16> @vector_bitcast_2(<32 x i16> %v) {
   %load = load <64 x i16>, ptr %p
   ret <64 x i16> %load
 }
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-modify-cfg: {{.*}}
+; CHECK-preserve-cfg: {{.*}}

diff  --git a/llvm/test/Transforms/SROA/vector-promotion.ll b/llvm/test/Transforms/SROA/vector-promotion.ll
index ec3c932e1b6b3..4fe2d2d62a067 100644
--- a/llvm/test/Transforms/SROA/vector-promotion.ll
+++ b/llvm/test/Transforms/SROA/vector-promotion.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -passes=sroa -S | FileCheck %s
+; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
 target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-n8:16:32:64"
 
 %S1 = type { i64, [42 x float] }
@@ -631,3 +632,6 @@ define void @swap-15bytes(ptr %x, ptr %y) {
 
 declare void @llvm.memcpy.p0.p0.i64(ptr, ptr, i64, i1)
 declare void @llvm.lifetime.end.p0(i64, ptr)
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-modify-cfg: {{.*}}
+; CHECK-preserve-cfg: {{.*}}

diff  --git a/llvm/test/Transforms/SROA/vectors-of-pointers.ll b/llvm/test/Transforms/SROA/vectors-of-pointers.ll
index fedbfbeee8e87..d839188f5f3f1 100644
--- a/llvm/test/Transforms/SROA/vectors-of-pointers.ll
+++ b/llvm/test/Transforms/SROA/vectors-of-pointers.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -passes=sroa
+; RUN: opt -S -passes='sroa<preserve-cfg>' < %s | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg
+; RUN: opt -S -passes='sroa<modify-cfg>' < %s | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg
 
 ; Make sure we don't crash on this one.
 
@@ -7,6 +8,18 @@ target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f3
 target triple = "x86_64-apple-macosx10.8.0"
 
 define void @foo(i1 %c1, i1 %c2) {
+; CHECK-LABEL: @foo(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[C1:%.*]], label [[BB0_EXIT158:%.*]], label [[IF_THEN_I_I_I_I_I138:%.*]]
+; CHECK:       if.then.i.i.i.i.i138:
+; CHECK-NEXT:    ret void
+; CHECK:       bb0.exit158:
+; CHECK-NEXT:    br i1 [[C2:%.*]], label [[BB0_EXIT257:%.*]], label [[IF_THEN_I_I_I_I_I237:%.*]]
+; CHECK:       if.then.i.i.i.i.i237:
+; CHECK-NEXT:    unreachable
+; CHECK:       bb0.exit257:
+; CHECK-NEXT:    ret void
+;
 entry:
   %Args.i = alloca <2 x ptr>, align 16
   br i1 %c1, label %bb0.exit158, label %if.then.i.i.i.i.i138
@@ -24,3 +37,6 @@ bb0.exit257:
   %0 = load <2 x ptr>, ptr %Args.i, align 16
   ret void
 }
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-modify-cfg: {{.*}}
+; CHECK-preserve-cfg: {{.*}}


        


More information about the llvm-commits mailing list