[SROA] For non-speculatable `load`s of `select`s -- split block, insert then/else...
authorRoman Lebedev <lebedev.ri@gmail.com>
Thu, 8 Dec 2022 16:51:30 +0000 (19:51 +0300)
committerRoman Lebedev <lebedev.ri@gmail.com>
Thu, 8 Dec 2022 17:19:55 +0000 (20:19 +0300)
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

This reverts commit 739611870d3b06605afe25cc07833f6a62de9545,
and recommits 03e6d9d9d1d48e43f3efc35eb75369b90d4510d5
with a fixed assertion - we should check that DTU is there,
not just assert false...

54 files changed:
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

index 8526338..0eebb63 100644 (file)
@@ -105,7 +105,7 @@ FunctionPass *createBitTrackingDCEPass();
 //
 // SROA - Replace aggregates or pieces of aggregates with scalar SSA values.
 //
-FunctionPass *createSROAPass();
+FunctionPass *createSROAPass(bool PreserveCFG = true);
 
 //===----------------------------------------------------------------------===//
 //
index b74c45e..85b75c4 100644 (file)
@@ -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"
 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 @@ private:
   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);
index 8215fe4..9d92149 100644 (file)
@@ -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
index e8a17a6..152c061 100644 (file)
@@ -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;
index 0228613..1b58084 100644 (file)
@@ -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.
index 6782517..dc42556 100644 (file)
@@ -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) {
index 6e8e303..cf988e0 100644 (file)
@@ -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(DTU && "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 @@ public:
     AU.addRequired<AssumptionCacheTracker>();
     AU.addRequired<DominatorTreeWrapperPass>();
     AU.addPreserved<GlobalsAAWrapperPass>();
-    AU.setPreservesCFG();
+    AU.addPreserved<DominatorTreeWrapperPass>();
   }
 
   StringRef getPassName() const override { return "SROA"; }
@@ -4861,7 +5001,10 @@ public:
 
 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)
index c03fbe9..9876681 100644 (file)
@@ -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,
index a83bd3b..d29c0aa 100644 (file)
@@ -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: {{.*}}
index 70e1a68..f90dbdf 100644 (file)
@@ -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: {{.*}}
index 40cc0f7..74201d5 100644 (file)
@@ -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
index 2230758..b870a15 100644 (file)
@@ -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: {{.*}}
index d4f305c..4c638a9 100644 (file)
@@ -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: {{.*}}
index d17d23a..50bddc8 100644 (file)
@@ -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: {{.*}}
index ddf678f..de7e11d 100644 (file)
@@ -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
index 9209895..a3dd523 100644 (file)
@@ -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: {{.*}}
index 652fc82..7099198 100644 (file)
@@ -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: {{.*}}
index 48498e9..58086f1 100644 (file)
@@ -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: {{.*}}
index bb0e51d..c60be8d 100644 (file)
@@ -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: {{.*}}
index 299bed8..44ae821 100644 (file)
@@ -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: {{.*}}
index 57aa1b0..b8e33cd 100644 (file)
@@ -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: {{.*}}
index e4aaf96..2d090a5 100644 (file)
@@ -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: {{.*}}
index 8d487eb..083fa72 100644 (file)
@@ -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: {{.*}}
index 78cd6b3..eec9912 100644 (file)
@@ -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: {{.*}}
index 68cfd3c..b9e8873 100644 (file)
@@ -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: {{.*}}
index 032dd17..0df3b14 100644 (file)
@@ -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: {{.*}}
index 04d5e6a..bc05971 100644 (file)
@@ -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: {{.*}}
index 33e6003..3756afa 100644 (file)
@@ -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: {{.*}}
index 99be316..b45d46e 100644 (file)
@@ -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@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: {{.*}}
index 15b7159..54cfb10 100644 (file)
@@ -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
index ea90101..250f8a1 100644 (file)
@@ -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: {{.*}}
index 8ac3a18..a8c3331 100644 (file)
@@ -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: {{.*}}
index 7893da3..b418b65 100644 (file)
@@ -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: {{.*}}
index 2361a50..a51c757 100644 (file)
@@ -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: {{.*}}
index 76b5209..779b6d5 100644 (file)
@@ -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: {{.*}}
index b4a7090..f5804ee 100644 (file)
@@ -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: {{.*}}
index a0e6204..a2872c7 100644 (file)
@@ -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: {{.*}}
index f783758..4121ccb 100644 (file)
@@ -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: {{.*}}
index b5b885c..175574b 100644 (file)
@@ -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: {{.*}}
index 5c66654..2b2f6f1 100644 (file)
@@ -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: {{.*}}
index 9586feb..5a790c5 100644 (file)
@@ -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
index dc6770d..aac7af9 100644 (file)
@@ -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
index 47ac791..cc6b6c3 100644 (file)
@@ -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: {{.*}}
index 7d2aeaa..43d8a0a 100644 (file)
@@ -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: {{.*}}
index 00cbe56..2734c1a 100644 (file)
@@ -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: {{.*}}
index b950302..acd8b6e 100644 (file)
@@ -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: {{.*}}
index 3e9332c..6d15a3a 100644 (file)
@@ -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: {{.*}}
index 484651a..f2e4cf8 100644 (file)
@@ -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: {{.*}}
index c43b78f..3851203 100644 (file)
@@ -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: {{.*}}
index 3661f48..3a798ab 100644 (file)
@@ -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: {{.*}}
index ad34b7b..561315b 100644 (file)
@@ -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: {{.*}}
index a410c8a..869b711 100644 (file)
@@ -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: {{.*}}
index ec3c932..2c48fb7 100644 (file)
@@ -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: {{.*}}
index fedbfbe..925a0e7 100644 (file)
@@ -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: {{.*}}