diff options
Diffstat (limited to 'llvm')
54 files changed, 948 insertions, 291 deletions
diff --git a/llvm/include/llvm/Transforms/Scalar.h b/llvm/include/llvm/Transforms/Scalar.h index 8526338..0eebb63 100644 --- a/llvm/include/llvm/Transforms/Scalar.h +++ b/llvm/include/llvm/Transforms/Scalar.h @@ -105,7 +105,7 @@ FunctionPass *createBitTrackingDCEPass(); // // SROA - Replace aggregates or pieces of aggregates with scalar SSA values. // -FunctionPass *createSROAPass(); +FunctionPass *createSROAPass(bool PreserveCFG = true); //===----------------------------------------------------------------------===// // diff --git a/llvm/include/llvm/Transforms/Scalar/SROA.h b/llvm/include/llvm/Transforms/Scalar/SROA.h index b74c45e..85b75c4 100644 --- a/llvm/include/llvm/Transforms/Scalar/SROA.h +++ b/llvm/include/llvm/Transforms/Scalar/SROA.h @@ -1,4 +1,4 @@ -//===- SROA.h - Scalar Replacement Of Aggregates ----------------*- C++ -*-===// +//===- SROA.h - Scalar Replacement Of Aggregates ----------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -15,6 +15,8 @@ #ifndef LLVM_TRANSFORMS_SCALAR_SROA_H #define LLVM_TRANSFORMS_SCALAR_SROA_H +#include "llvm/ADT/MapVector.h" +#include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallVector.h" #include "llvm/IR/PassManager.h" @@ -24,8 +26,10 @@ namespace llvm { class AllocaInst; +class LoadInst; class AssumptionCache; class DominatorTree; +class DomTreeUpdater; class Function; class LLVMContext; class PHINode; @@ -41,8 +45,31 @@ class AllocaSlices; class Partition; class SROALegacyPass; +class SelectHandSpeculativity { + unsigned char Storage = 0; + using TrueVal = Bitfield::Element<bool, 0, 1>; // Low 0'th bit. + using FalseVal = Bitfield::Element<bool, 1, 1>; // Low 1'th bit. +public: + SelectHandSpeculativity() = default; + SelectHandSpeculativity &setAsSpeculatable(bool isTrueVal); + bool isSpeculatable(bool isTrueVal) const; + bool areAllSpeculatable() const; + bool areAnySpeculatable() const; + bool areNoneSpeculatable() const; + // For interop as int half of PointerIntPair. + explicit operator intptr_t() const { return static_cast<intptr_t>(Storage); } + explicit SelectHandSpeculativity(intptr_t Storage_) : Storage(Storage_) {} +}; +static_assert(sizeof(SelectHandSpeculativity) == sizeof(unsigned char)); + +using PossiblySpeculatableLoad = + PointerIntPair<LoadInst *, 2, sroa::SelectHandSpeculativity>; +using PossiblySpeculatableLoads = SmallVector<PossiblySpeculatableLoad, 2>; + } // end namespace sroa +enum class SROAOptions : bool { ModifyCFG, PreserveCFG }; + /// An optimization pass providing Scalar Replacement of Aggregates. /// /// This pass takes allocations which can be completely analyzed (that is, they @@ -63,8 +90,9 @@ class SROALegacyPass; /// SSA vector values. class SROAPass : public PassInfoMixin<SROAPass> { LLVMContext *C = nullptr; - DominatorTree *DT = nullptr; + DomTreeUpdater *DTU = nullptr; AssumptionCache *AC = nullptr; + const bool PreserveCFG; /// Worklist of alloca instructions to simplify. /// @@ -98,27 +126,50 @@ class SROAPass : public PassInfoMixin<SROAPass> { /// All of these PHIs have been checked for the safety of speculation and by /// being speculated will allow promoting allocas currently in the promotable /// queue. - SetVector<PHINode *, SmallVector<PHINode *, 2>> SpeculatablePHIs; + SetVector<PHINode *, SmallVector<PHINode *, 8>> SpeculatablePHIs; - /// A worklist of select instructions to speculate prior to promoting + /// A worklist of select instructions to rewrite prior to promoting /// allocas. + SmallMapVector<SelectInst *, sroa::PossiblySpeculatableLoads, 8> + SelectsToRewrite; + + /// Select instructions that use an alloca and are subsequently loaded can be + /// rewritten to load both input pointers and then select between the result, + /// allowing the load of the alloca to be promoted. + /// From this: + /// %P2 = select i1 %cond, ptr %Alloca, ptr %Other + /// %V = load <type>, ptr %P2 + /// to: + /// %V1 = load <type>, ptr %Alloca -> will be mem2reg'd + /// %V2 = load <type>, ptr %Other + /// %V = select i1 %cond, <type> %V1, <type> %V2 /// - /// All of these select instructions have been checked for the safety of - /// speculation and by being speculated will allow promoting allocas - /// currently in the promotable queue. - SetVector<SelectInst *, SmallVector<SelectInst *, 2>> SpeculatableSelects; + /// We can do this to a select if its only uses are loads + /// and if either the operand to the select can be loaded unconditionally, + /// or if we are allowed to perform CFG modifications. + /// If found an intervening bitcast with a single use of the load, + /// allow the promotion. + static std::optional<sroa::PossiblySpeculatableLoads> + isSafeSelectToSpeculate(SelectInst &SI, bool PreserveCFG); public: - SROAPass() = default; + /// If \p PreserveCFG is set, then the pass is not allowed to modify CFG + /// in any way, even if it would update CFG analyses. + SROAPass(SROAOptions PreserveCFG); /// Run the pass over the function. PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); + void printPipeline(raw_ostream &OS, + function_ref<StringRef(StringRef)> MapClassName2PassName); + private: friend class sroa::AllocaSliceRewriter; friend class sroa::SROALegacyPass; /// Helper used by both the public run method and by the legacy pass. + PreservedAnalyses runImpl(Function &F, DomTreeUpdater &RunDTU, + AssumptionCache &RunAC); PreservedAnalyses runImpl(Function &F, DominatorTree &RunDT, AssumptionCache &RunAC); @@ -126,7 +177,7 @@ 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); diff --git a/llvm/include/llvm/Transforms/Utils/BasicBlockUtils.h b/llvm/include/llvm/Transforms/Utils/BasicBlockUtils.h index 8215fe4..9d92149 100644 --- a/llvm/include/llvm/Transforms/Utils/BasicBlockUtils.h +++ b/llvm/include/llvm/Transforms/Utils/BasicBlockUtils.h @@ -464,10 +464,13 @@ Instruction *SplitBlockAndInsertIfThen(Value *Cond, Instruction *SplitBefore, /// ElseBlock /// SplitBefore /// Tail +/// +/// Updates DT if given. void SplitBlockAndInsertIfThenElse(Value *Cond, Instruction *SplitBefore, Instruction **ThenTerm, Instruction **ElseTerm, - MDNode *BranchWeights = nullptr); + MDNode *BranchWeights = nullptr, + DomTreeUpdater *DTU = nullptr); /// Check whether BB is the merge point of a if-region. /// If so, return the branch instruction that determines which entry into diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp index e8a17a6..152c061 100644 --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -836,6 +836,19 @@ Expected<GVNOptions> parseGVNOptions(StringRef Params) { return Result; } +Expected<SROAOptions> parseSROAOptions(StringRef Params) { + if (Params.empty() || Params == "modify-cfg") + return SROAOptions::ModifyCFG; + if (Params == "preserve-cfg") + return SROAOptions::PreserveCFG; + return make_error<StringError>( + formatv("invalid SROA pass parameter '{0}' (either preserve-cfg or " + "modify-cfg can be specified)", + Params) + .str(), + inconvertibleErrorCode()); +} + Expected<StackLifetime::LivenessType> parseStackLifetimeOptions(StringRef Params) { StackLifetime::LivenessType Result = StackLifetime::LivenessType::May; diff --git a/llvm/lib/Passes/PassBuilderPipelines.cpp b/llvm/lib/Passes/PassBuilderPipelines.cpp index 0228613..1b58084 100644 --- a/llvm/lib/Passes/PassBuilderPipelines.cpp +++ b/llvm/lib/Passes/PassBuilderPipelines.cpp @@ -328,7 +328,7 @@ PassBuilder::buildO1FunctionSimplificationPipeline(OptimizationLevel Level, // Form SSA out of local memory accesses after breaking apart aggregates into // scalars. - FPM.addPass(SROAPass()); + FPM.addPass(SROAPass(SROAOptions::ModifyCFG)); // Catch trivial redundancies FPM.addPass(EarlyCSEPass(true /* Enable mem-ssa. */)); @@ -427,7 +427,7 @@ PassBuilder::buildO1FunctionSimplificationPipeline(OptimizationLevel Level, /*UseBlockFrequencyInfo=*/false)); // Delete small array after loop unroll. - FPM.addPass(SROAPass()); + FPM.addPass(SROAPass(SROAOptions::ModifyCFG)); // Specially optimize memory movement as it doesn't look like dataflow in SSA. FPM.addPass(MemCpyOptPass()); @@ -478,7 +478,7 @@ PassBuilder::buildFunctionSimplificationPipeline(OptimizationLevel Level, // Form SSA out of local memory accesses after breaking apart aggregates into // scalars. - FPM.addPass(SROAPass()); + FPM.addPass(SROAPass(SROAOptions::ModifyCFG)); // Catch trivial redundancies FPM.addPass(EarlyCSEPass(true /* Enable mem-ssa. */)); @@ -613,7 +613,7 @@ PassBuilder::buildFunctionSimplificationPipeline(OptimizationLevel Level, /*UseBlockFrequencyInfo=*/false)); // Delete small array after loop unroll. - FPM.addPass(SROAPass()); + FPM.addPass(SROAPass(SROAOptions::ModifyCFG)); // Try vectorization/scalarization transforms that are both improvements // themselves and can allow further folds with GVN and InstCombine. @@ -714,7 +714,7 @@ void PassBuilder::addPGOInstrPasses(ModulePassManager &MPM, CGSCCPassManager &CGPipeline = MIWP.getPM(); FunctionPassManager FPM; - FPM.addPass(SROAPass()); + FPM.addPass(SROAPass(SROAOptions::ModifyCFG)); FPM.addPass(EarlyCSEPass()); // Catch trivial redundancies. FPM.addPass(SimplifyCFGPass(SimplifyCFGOptions().convertSwitchRangeToICmp( true))); // Merge & remove basic blocks. @@ -963,7 +963,7 @@ PassBuilder::buildModuleSimplificationPipeline(OptimizationLevel Level, // Compare/branch metadata may alter the behavior of passes like SimplifyCFG. EarlyFPM.addPass(LowerExpectIntrinsicPass()); EarlyFPM.addPass(SimplifyCFGPass()); - EarlyFPM.addPass(SROAPass()); + EarlyFPM.addPass(SROAPass(SROAOptions::ModifyCFG)); EarlyFPM.addPass(EarlyCSEPass()); if (Level == OptimizationLevel::O3) EarlyFPM.addPass(CallSiteSplittingPass()); @@ -1113,7 +1113,10 @@ void PassBuilder::addVectorPasses(OptimizationLevel Level, // Now that we are done with loop unrolling, be it either by LoopVectorizer, // or LoopUnroll passes, some variable-offset GEP's into alloca's could have // become constant-offset, thus enabling SROA and alloca promotion. Do so. - FPM.addPass(SROAPass()); + // NOTE: we are very late in the pipeline, and we don't have any LICM + // or SimplifyCFG passes scheduled after us, that would cleanup + // the CFG mess this may created if allowed to modify CFG, so forbid that. + FPM.addPass(SROAPass(SROAOptions::PreserveCFG)); } if (!IsFullLTO) { @@ -1204,7 +1207,10 @@ void PassBuilder::addVectorPasses(OptimizationLevel Level, // Now that we are done with loop unrolling, be it either by LoopVectorizer, // or LoopUnroll passes, some variable-offset GEP's into alloca's could have // become constant-offset, thus enabling SROA and alloca promotion. Do so. - FPM.addPass(SROAPass()); + // NOTE: we are very late in the pipeline, and we don't have any LICM + // or SimplifyCFG passes scheduled after us, that would cleanup + // the CFG mess this may created if allowed to modify CFG, so forbid that. + FPM.addPass(SROAPass(SROAOptions::PreserveCFG)); FPM.addPass(InstCombinePass()); FPM.addPass( RequireAnalysisPass<OptimizationRemarkEmitterAnalysis, Function>()); @@ -1745,7 +1751,7 @@ PassBuilder::buildLTODefaultPipeline(OptimizationLevel Level, } // Break up allocas - FPM.addPass(SROAPass()); + FPM.addPass(SROAPass(SROAOptions::ModifyCFG)); // LTO provides additional opportunities for tailcall elimination due to // link-time inlining, and visibility of nocapture attribute. diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def index 6782517..dc42556 100644 --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -376,7 +376,6 @@ FUNCTION_PASS("sink", SinkingPass()) FUNCTION_PASS("slp-vectorizer", SLPVectorizerPass()) FUNCTION_PASS("slsr", StraightLineStrengthReducePass()) FUNCTION_PASS("speculative-execution", SpeculativeExecutionPass()) -FUNCTION_PASS("sroa", SROAPass()) FUNCTION_PASS("strip-gc-relocates", StripGCRelocates()) FUNCTION_PASS("structurizecfg", StructurizeCFGPass()) FUNCTION_PASS("tailcallelim", TailCallElimPass()) @@ -473,6 +472,13 @@ FUNCTION_PASS_WITH_PARAMS("gvn", "no-load-pre;load-pre;" "no-split-backedge-load-pre;split-backedge-load-pre;" "no-memdep;memdep") +FUNCTION_PASS_WITH_PARAMS("sroa", + "SROAPass", + [](SROAOptions PreserveCFG) { + return SROAPass(PreserveCFG); + }, + parseSROAOptions, + "preserve-cfg;modify-cfg") FUNCTION_PASS_WITH_PARAMS("print<stack-lifetime>", "StackLifetimePrinterPass", [](StackLifetime::LivenessType Type) { diff --git a/llvm/lib/Transforms/Scalar/SROA.cpp b/llvm/lib/Transforms/Scalar/SROA.cpp index 6e8e303..07bcddc3 100644 --- a/llvm/lib/Transforms/Scalar/SROA.cpp +++ b/llvm/lib/Transforms/Scalar/SROA.cpp @@ -38,6 +38,7 @@ #include "llvm/ADT/iterator.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Analysis/AssumptionCache.h" +#include "llvm/Analysis/DomTreeUpdater.h" #include "llvm/Analysis/GlobalsModRef.h" #include "llvm/Analysis/Loads.h" #include "llvm/Analysis/PtrUseVisitor.h" @@ -78,6 +79,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Scalar.h" +#include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/Local.h" #include "llvm/Transforms/Utils/PromoteMemToReg.h" #include <algorithm> @@ -104,6 +106,8 @@ STATISTIC(MaxUsesPerAllocaPartition, "Maximum number of uses of a partition"); STATISTIC(NumNewAllocas, "Number of new, smaller allocas introduced"); STATISTIC(NumPromoted, "Number of allocas promoted to SSA values"); STATISTIC(NumLoadsSpeculated, "Number of loads speculated to allow promotion"); +STATISTIC(NumLoadsPredicated, + "Number of loads rewritten into predicated loads to allow promotion"); STATISTIC(NumDeleted, "Number of instructions deleted"); STATISTIC(NumVectorized, "Number of vectorized aggregates"); @@ -111,7 +115,6 @@ STATISTIC(NumVectorized, "Number of vectorized aggregates"); /// GEPs. static cl::opt<bool> SROAStrictInbounds("sroa-strict-inbounds", cl::init(false), cl::Hidden); - namespace { /// A custom IRBuilder inserter which prefixes all names, but only in @@ -1306,24 +1309,53 @@ static void speculatePHINodeLoads(IRBuilderTy &IRB, PHINode &PN) { PN.eraseFromParent(); } -/// Select instructions that use an alloca and are subsequently loaded can be -/// rewritten to load both input pointers and then select between the result, -/// allowing the load of the alloca to be promoted. -/// From this: -/// %P2 = select i1 %cond, i32* %Alloca, i32* %Other -/// %V = load i32* %P2 -/// to: -/// %V1 = load i32* %Alloca -> will be mem2reg'd -/// %V2 = load i32* %Other -/// %V = select i1 %cond, i32 %V1, i32 %V2 -/// -/// We can do this to a select if its only uses are loads and if the operand -/// to the select can be loaded unconditionally. If found an intervening bitcast -/// with a single use of the load, allow the promotion. -static bool isSafeSelectToSpeculate(SelectInst &SI) { - Value *TValue = SI.getTrueValue(); - Value *FValue = SI.getFalseValue(); +sroa::SelectHandSpeculativity & +sroa::SelectHandSpeculativity::setAsSpeculatable(bool isTrueVal) { + if (isTrueVal) + Bitfield::set<sroa::SelectHandSpeculativity::TrueVal>(Storage, true); + else + Bitfield::set<sroa::SelectHandSpeculativity::FalseVal>(Storage, true); + return *this; +} + +bool sroa::SelectHandSpeculativity::isSpeculatable(bool isTrueVal) const { + return isTrueVal + ? Bitfield::get<sroa::SelectHandSpeculativity::TrueVal>(Storage) + : Bitfield::get<sroa::SelectHandSpeculativity::FalseVal>(Storage); +} + +bool sroa::SelectHandSpeculativity::areAllSpeculatable() const { + return isSpeculatable(/*isTrueVal=*/true) && + isSpeculatable(/*isTrueVal=*/false); +} + +bool sroa::SelectHandSpeculativity::areAnySpeculatable() const { + return isSpeculatable(/*isTrueVal=*/true) || + isSpeculatable(/*isTrueVal=*/false); +} +bool sroa::SelectHandSpeculativity::areNoneSpeculatable() const { + return !areAnySpeculatable(); +} + +static sroa::SelectHandSpeculativity +isSafeLoadOfSelectToSpeculate(LoadInst &LI, SelectInst &SI, bool PreserveCFG) { + assert(LI.isSimple() && "Only for simple loads"); + sroa::SelectHandSpeculativity Spec; + const DataLayout &DL = SI.getModule()->getDataLayout(); + for (Value *Value : {SI.getTrueValue(), SI.getFalseValue()}) + if (isSafeToLoadUnconditionally(Value, LI.getType(), LI.getAlign(), DL, + &LI)) + Spec.setAsSpeculatable(/*isTrueVal=*/Value == SI.getTrueValue()); + else if (PreserveCFG) + return Spec; + + return Spec; +} + +std::optional<sroa::PossiblySpeculatableLoads> +SROAPass::isSafeSelectToSpeculate(SelectInst &SI, bool PreserveCFG) { + PossiblySpeculatableLoads Loads; for (User *U : SI.users()) { LoadInst *LI; @@ -1333,75 +1365,136 @@ static bool isSafeSelectToSpeculate(SelectInst &SI) { else LI = dyn_cast<LoadInst>(U); - if (!LI || !LI->isSimple()) - return false; + // Note that atomic loads can be transformed; + // atomic semantics do not have any meaning for a local alloca. + if (!LI || LI->isVolatile()) + return {}; // Give up on this `select`. - // Both operands to the select need to be dereferenceable, either - // absolutely (e.g. allocas) or at this point because we can see other - // accesses to it. - if (!isSafeToLoadUnconditionally(TValue, LI->getType(), - LI->getAlign(), DL, LI)) - return false; - if (!isSafeToLoadUnconditionally(FValue, LI->getType(), - LI->getAlign(), DL, LI)) - return false; + PossiblySpeculatableLoad Load(LI); + + if (!LI->isSimple()) { + // If the `load` is not simple, we can't speculatively execute it, + // but we could handle this via a CFG modification. But can we? + if (PreserveCFG) + return {}; // Give up on this `select`. + Loads.emplace_back(Load); + continue; + } + + sroa::SelectHandSpeculativity Spec = + isSafeLoadOfSelectToSpeculate(*LI, SI, PreserveCFG); + if (PreserveCFG && !Spec.areAllSpeculatable()) + return {}; // Give up on this `select`. + + Load.setInt(Spec); + Loads.emplace_back(Load); } - return true; + return Loads; } -static void speculateSelectInstLoads(IRBuilderTy &IRB, SelectInst &SI) { - LLVM_DEBUG(dbgs() << " original: " << SI << "\n"); +static void speculateSelectInstLoads(SelectInst &SI, LoadInst &LI, + IRBuilderTy &IRB) { + LLVM_DEBUG(dbgs() << " original load: " << SI << "\n"); IRB.SetInsertPoint(&SI); Value *TV = SI.getTrueValue(); Value *FV = SI.getFalseValue(); - // Replace the loads of the select with a select of two loads. - while (!SI.use_empty()) { - LoadInst *LI; - BitCastInst *BC = dyn_cast<BitCastInst>(SI.user_back()); - if (BC) { - assert(BC->hasOneUse() && "Bitcast should have a single use."); - LI = cast<LoadInst>(BC->user_back()); - } else { - LI = cast<LoadInst>(SI.user_back()); - } + // Replace the given load of the select with a select of two loads. + + assert(LI.isSimple() && "We only speculate simple loads"); + + IRB.SetInsertPoint(&LI); + LoadInst *TL = + IRB.CreateAlignedLoad(LI.getType(), TV, LI.getAlign(), + LI.getName() + ".sroa.speculate.load.true"); + LoadInst *FL = + IRB.CreateAlignedLoad(LI.getType(), FV, LI.getAlign(), + LI.getName() + ".sroa.speculate.load.false"); + NumLoadsSpeculated += 2; + + // Transfer alignment and AA info if present. + TL->setAlignment(LI.getAlign()); + FL->setAlignment(LI.getAlign()); + + AAMDNodes Tags = LI.getAAMetadata(); + if (Tags) { + TL->setAAMetadata(Tags); + FL->setAAMetadata(Tags); + } - assert(LI->isSimple() && "We only speculate simple loads"); + Value *V = IRB.CreateSelect(SI.getCondition(), TL, FL, + LI.getName() + ".sroa.speculated"); - IRB.SetInsertPoint(LI); - Value *NewTV = - BC ? IRB.CreateBitCast(TV, BC->getType(), TV->getName() + ".sroa.cast") - : TV; - Value *NewFV = - BC ? IRB.CreateBitCast(FV, BC->getType(), FV->getName() + ".sroa.cast") - : FV; - LoadInst *TL = IRB.CreateLoad(LI->getType(), NewTV, - LI->getName() + ".sroa.speculate.load.true"); - LoadInst *FL = IRB.CreateLoad(LI->getType(), NewFV, - LI->getName() + ".sroa.speculate.load.false"); - NumLoadsSpeculated += 2; - - // Transfer alignment and AA info if present. - TL->setAlignment(LI->getAlign()); - FL->setAlignment(LI->getAlign()); - - AAMDNodes Tags = LI->getAAMetadata(); - if (Tags) { - TL->setAAMetadata(Tags); - FL->setAAMetadata(Tags); - } + LLVM_DEBUG(dbgs() << " speculated to: " << *V << "\n"); + LI.replaceAllUsesWith(V); +} - Value *V = IRB.CreateSelect(SI.getCondition(), TL, FL, - LI->getName() + ".sroa.speculated"); +static void rewriteLoadOfSelect(SelectInst &SI, LoadInst &LI, + sroa::SelectHandSpeculativity Spec, + DomTreeUpdater &DTU) { + LLVM_DEBUG(dbgs() << " original load: " << SI << "\n"); + BasicBlock *Head = LI.getParent(); + Instruction *ThenTerm = nullptr; + Instruction *ElseTerm = nullptr; + if (Spec.areNoneSpeculatable()) + SplitBlockAndInsertIfThenElse(SI.getCondition(), &LI, &ThenTerm, &ElseTerm, + SI.getMetadata(LLVMContext::MD_prof), &DTU); + else { + SplitBlockAndInsertIfThen(SI.getCondition(), &LI, /*Unreachable=*/false, + SI.getMetadata(LLVMContext::MD_prof), &DTU, + /*LI=*/nullptr, /*ThenBlock=*/nullptr); + if (Spec.isSpeculatable(/*isTrueVal=*/true)) + cast<BranchInst>(Head->getTerminator())->swapSuccessors(); + } + auto *HeadBI = cast<BranchInst>(Head->getTerminator()); + Spec = {}; // Do not use `Spec` beyond this point. + BasicBlock *Tail = LI.getParent(); + Tail->setName(Head->getName() + ".cont"); + auto *PN = PHINode::Create(LI.getType(), 2, "", &LI); + for (BasicBlock *SuccBB : successors(Head)) { + bool IsThen = SuccBB == HeadBI->getSuccessor(0); + int SuccIdx = IsThen ? 0 : 1; + auto *NewLoadBB = SuccBB == Tail ? Head : SuccBB; + if (NewLoadBB != Head) { + NewLoadBB->setName(Head->getName() + (IsThen ? ".then" : ".else")); + ++NumLoadsPredicated; + } else + ++NumLoadsSpeculated; + auto *CondLoad = cast<LoadInst>(LI.clone()); + CondLoad->insertBefore(NewLoadBB->getTerminator()); + CondLoad->setOperand(0, SI.getOperand(1 + SuccIdx)); + CondLoad->setName(LI.getName() + (IsThen ? ".then" : ".else") + ".val"); + PN->addIncoming(CondLoad, NewLoadBB); + } + PN->takeName(&LI); + LLVM_DEBUG(dbgs() << " to: " << *PN << "\n"); + LI.replaceAllUsesWith(PN); +} - LLVM_DEBUG(dbgs() << " speculated to: " << *V << "\n"); - LI->replaceAllUsesWith(V); +static bool rewriteSelectInstLoads(SelectInst &SI, + const sroa::PossiblySpeculatableLoads &Loads, + IRBuilderTy &IRB, DomTreeUpdater *DTU) { + bool CFGChanged = false; + LLVM_DEBUG(dbgs() << " original select: " << SI << "\n"); + + for (const PossiblySpeculatableLoad &Load : Loads) { + LoadInst *LI = Load.getPointer(); + sroa::SelectHandSpeculativity Spec = Load.getInt(); + if (Spec.areAllSpeculatable()) { + speculateSelectInstLoads(SI, *LI, IRB); + } else { + assert("Should not get here when not allowed to modify the CFG!"); + rewriteLoadOfSelect(SI, *LI, Spec, *DTU); + CFGChanged = true; + } LI->eraseFromParent(); - if (BC) - BC->eraseFromParent(); } + + for (User *U : make_early_inc_range(SI.users())) + cast<BitCastInst>(U)->eraseFromParent(); SI.eraseFromParent(); + return CFGChanged; } /// Build a GEP out of a base pointer and indices. @@ -4397,13 +4490,21 @@ AllocaInst *SROAPass::rewritePartition(AllocaInst &AI, AllocaSlices &AS, break; } - for (SelectInst *Sel : SelectUsers) - if (!isSafeSelectToSpeculate(*Sel)) { + SmallVector<std::pair<SelectInst *, PossiblySpeculatableLoads>, 2> + NewSelectsToRewrite; + NewSelectsToRewrite.reserve(SelectUsers.size()); + for (SelectInst *Sel : SelectUsers) { + std::optional<PossiblySpeculatableLoads> Loads = + isSafeSelectToSpeculate(*Sel, PreserveCFG); + if (!Loads) { Promotable = false; PHIUsers.clear(); SelectUsers.clear(); + NewSelectsToRewrite.clear(); break; } + NewSelectsToRewrite.emplace_back(std::make_pair(Sel, *Loads)); + } if (Promotable) { for (Use *U : AS.getDeadUsesIfPromotable()) { @@ -4422,8 +4523,12 @@ AllocaInst *SROAPass::rewritePartition(AllocaInst &AI, AllocaSlices &AS, // next iteration. for (PHINode *PHIUser : PHIUsers) SpeculatablePHIs.insert(PHIUser); - for (SelectInst *SelectUser : SelectUsers) - SpeculatableSelects.insert(SelectUser); + SelectsToRewrite.reserve(SelectsToRewrite.size() + + NewSelectsToRewrite.size()); + for (auto &&KV : llvm::make_range( + std::make_move_iterator(NewSelectsToRewrite.begin()), + std::make_move_iterator(NewSelectsToRewrite.end()))) + SelectsToRewrite.insert(std::move(KV)); Worklist.insert(NewAI); } } else { @@ -4637,14 +4742,19 @@ void SROAPass::clobberUse(Use &U) { /// This analyzes the alloca to ensure we can reason about it, builds /// the slices of the alloca, and then hands it off to be split and /// rewritten as needed. -bool SROAPass::runOnAlloca(AllocaInst &AI) { +std::pair<bool /*Changed*/, bool /*CFGChanged*/> +SROAPass::runOnAlloca(AllocaInst &AI) { + bool Changed = false; + bool CFGChanged = false; + LLVM_DEBUG(dbgs() << "SROA alloca: " << AI << "\n"); ++NumAllocasAnalyzed; // Special case dead allocas, as they're trivial. if (AI.use_empty()) { AI.eraseFromParent(); - return true; + Changed = true; + return {Changed, CFGChanged}; } const DataLayout &DL = AI.getModule()->getDataLayout(); @@ -4652,9 +4762,7 @@ bool SROAPass::runOnAlloca(AllocaInst &AI) { auto *AT = AI.getAllocatedType(); if (AI.isArrayAllocation() || !AT->isSized() || isa<ScalableVectorType>(AT) || DL.getTypeAllocSize(AT).getFixedSize() == 0) - return false; - - bool Changed = false; + return {Changed, CFGChanged}; // First, split any FCA loads and stores touching this alloca to promote // better splitting and promotion opportunities. @@ -4666,7 +4774,7 @@ bool SROAPass::runOnAlloca(AllocaInst &AI) { AllocaSlices AS(DL, AI); LLVM_DEBUG(AS.print(dbgs())); if (AS.isEscaped()) - return Changed; + return {Changed, CFGChanged}; // Delete all the dead users of this alloca before splitting and rewriting it. for (Instruction *DeadUser : AS.getDeadUsers()) { @@ -4688,7 +4796,7 @@ bool SROAPass::runOnAlloca(AllocaInst &AI) { // No slices to split. Leave the dead alloca for a later pass to clean up. if (AS.begin() == AS.end()) - return Changed; + return {Changed, CFGChanged}; Changed |= splitAlloca(AI, AS); @@ -4696,11 +4804,15 @@ bool SROAPass::runOnAlloca(AllocaInst &AI) { while (!SpeculatablePHIs.empty()) speculatePHINodeLoads(IRB, *SpeculatablePHIs.pop_back_val()); - LLVM_DEBUG(dbgs() << " Speculating Selects\n"); - while (!SpeculatableSelects.empty()) - speculateSelectInstLoads(IRB, *SpeculatableSelects.pop_back_val()); + LLVM_DEBUG(dbgs() << " Rewriting Selects\n"); + auto RemainingSelectsToRewrite = SelectsToRewrite.takeVector(); + while (!RemainingSelectsToRewrite.empty()) { + const auto [K, V] = RemainingSelectsToRewrite.pop_back_val(); + CFGChanged |= + rewriteSelectInstLoads(*K, V, IRB, PreserveCFG ? nullptr : DTU); + } - return Changed; + return {Changed, CFGChanged}; } /// Delete the dead instructions accumulated in this run. @@ -4759,16 +4871,16 @@ bool SROAPass::promoteAllocas(Function &F) { NumPromoted += PromotableAllocas.size(); LLVM_DEBUG(dbgs() << "Promoting allocas with mem2reg...\n"); - PromoteMemToReg(PromotableAllocas, *DT, AC); + PromoteMemToReg(PromotableAllocas, DTU->getDomTree(), AC); PromotableAllocas.clear(); return true; } -PreservedAnalyses SROAPass::runImpl(Function &F, DominatorTree &RunDT, +PreservedAnalyses SROAPass::runImpl(Function &F, DomTreeUpdater &RunDTU, AssumptionCache &RunAC) { LLVM_DEBUG(dbgs() << "SROA function: " << F.getName() << "\n"); C = &F.getContext(); - DT = &RunDT; + DTU = &RunDTU; AC = &RunAC; BasicBlock &EntryBB = F.getEntryBlock(); @@ -4785,13 +4897,18 @@ PreservedAnalyses SROAPass::runImpl(Function &F, DominatorTree &RunDT, } bool Changed = false; + bool CFGChanged = false; // A set of deleted alloca instruction pointers which should be removed from // the list of promotable allocas. SmallPtrSet<AllocaInst *, 4> DeletedAllocas; do { while (!Worklist.empty()) { - Changed |= runOnAlloca(*Worklist.pop_back_val()); + auto [IterationChanged, IterationCFGChanged] = + runOnAlloca(*Worklist.pop_back_val()); + Changed |= IterationChanged; + CFGChanged |= IterationCFGChanged; + Changed |= deleteDeadInstructions(DeletedAllocas); // Remove the deleted allocas from various lists so that we don't try to @@ -4811,19 +4928,41 @@ PreservedAnalyses SROAPass::runImpl(Function &F, DominatorTree &RunDT, PostPromotionWorklist.clear(); } while (!Worklist.empty()); + assert((!CFGChanged || Changed) && "Can not only modify the CFG."); + assert((!CFGChanged || !PreserveCFG) && + "Should not have modified the CFG when told to preserve it."); + if (!Changed) return PreservedAnalyses::all(); PreservedAnalyses PA; - PA.preserveSet<CFGAnalyses>(); + if (!CFGChanged) + PA.preserveSet<CFGAnalyses>(); + PA.preserve<DominatorTreeAnalysis>(); return PA; } +PreservedAnalyses SROAPass::runImpl(Function &F, DominatorTree &RunDT, + AssumptionCache &RunAC) { + DomTreeUpdater DTU(RunDT, DomTreeUpdater::UpdateStrategy::Lazy); + return runImpl(F, DTU, RunAC); +} + PreservedAnalyses SROAPass::run(Function &F, FunctionAnalysisManager &AM) { return runImpl(F, AM.getResult<DominatorTreeAnalysis>(F), AM.getResult<AssumptionAnalysis>(F)); } +void SROAPass::printPipeline( + raw_ostream &OS, function_ref<StringRef(StringRef)> MapClassName2PassName) { + static_cast<PassInfoMixin<SROAPass> *>(this)->printPipeline( + OS, MapClassName2PassName); + OS << (PreserveCFG ? "<preserve-cfg>" : "<modify-cfg>"); +} + +SROAPass::SROAPass(SROAOptions PreserveCFG_) + : PreserveCFG(PreserveCFG_ == SROAOptions::PreserveCFG) {} + /// A legacy pass for the legacy pass manager that wraps the \c SROA pass. /// /// This is in the llvm namespace purely to allow it to be a friend of the \c @@ -4835,7 +4974,8 @@ class llvm::sroa::SROALegacyPass : public FunctionPass { public: static char ID; - SROALegacyPass() : FunctionPass(ID) { + SROALegacyPass(SROAOptions PreserveCFG = SROAOptions::PreserveCFG) + : FunctionPass(ID), Impl(PreserveCFG) { initializeSROALegacyPassPass(*PassRegistry::getPassRegistry()); } @@ -4853,7 +4993,7 @@ 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) diff --git a/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp b/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp index c03fbe9..9876681 100644 --- a/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp +++ b/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp @@ -1545,8 +1545,14 @@ Instruction *llvm::SplitBlockAndInsertIfThen(Value *Cond, void llvm::SplitBlockAndInsertIfThenElse(Value *Cond, Instruction *SplitBefore, Instruction **ThenTerm, Instruction **ElseTerm, - MDNode *BranchWeights) { + MDNode *BranchWeights, + DomTreeUpdater *DTU) { BasicBlock *Head = SplitBefore->getParent(); + + SmallPtrSet<BasicBlock *, 8> UniqueOrigSuccessors; + if (DTU) + UniqueOrigSuccessors.insert(succ_begin(Head), succ_end(Head)); + BasicBlock *Tail = Head->splitBasicBlock(SplitBefore->getIterator()); Instruction *HeadOldTerm = Head->getTerminator(); LLVMContext &C = Head->getContext(); @@ -1560,6 +1566,19 @@ void llvm::SplitBlockAndInsertIfThenElse(Value *Cond, Instruction *SplitBefore, BranchInst::Create(/*ifTrue*/ThenBlock, /*ifFalse*/ElseBlock, Cond); HeadNewTerm->setMetadata(LLVMContext::MD_prof, BranchWeights); ReplaceInstWithInst(HeadOldTerm, HeadNewTerm); + if (DTU) { + SmallVector<DominatorTree::UpdateType, 8> Updates; + Updates.reserve(4 + 2 * UniqueOrigSuccessors.size()); + for (BasicBlock *Succ : successors(Head)) { + Updates.push_back({DominatorTree::Insert, Head, Succ}); + Updates.push_back({DominatorTree::Insert, Succ, Tail}); + } + for (BasicBlock *UniqueOrigSuccessor : UniqueOrigSuccessors) + Updates.push_back({DominatorTree::Insert, Tail, UniqueOrigSuccessor}); + for (BasicBlock *UniqueOrigSuccessor : UniqueOrigSuccessors) + Updates.push_back({DominatorTree::Delete, Head, UniqueOrigSuccessor}); + DTU->applyUpdates(Updates); + } } BranchInst *llvm::GetIfCondition(BasicBlock *BB, BasicBlock *&IfTrue, diff --git a/llvm/test/Transforms/SROA/2009-02-20-InstCombine-SROA.ll b/llvm/test/Transforms/SROA/2009-02-20-InstCombine-SROA.ll index a83bd3b..3a8d376 100644 --- a/llvm/test/Transforms/SROA/2009-02-20-InstCombine-SROA.ll +++ b/llvm/test/Transforms/SROA/2009-02-20-InstCombine-SROA.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -passes=sroa -S | FileCheck %s +; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg ; rdar://6417724 @@ -270,3 +271,6 @@ return: ; preds = %_ZSt4findIN9__gnu_c declare void @llvm.memcpy.p0.p0.i64(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg) #0 attributes #0 = { argmemonly nofree nosync nounwind willreturn } +;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +; CHECK-modify-cfg: {{.*}} +; CHECK-preserve-cfg: {{.*}} diff --git a/llvm/test/Transforms/SROA/address-spaces.ll b/llvm/test/Transforms/SROA/address-spaces.ll index 70e1a68..53ee122c 100644 --- a/llvm/test/Transforms/SROA/address-spaces.ll +++ b/llvm/test/Transforms/SROA/address-spaces.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -passes=sroa -S | FileCheck %s +; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg target datalayout = "e-p:64:64:64-p1:16:16:16-p3:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-n8:16:32:64" declare void @llvm.memcpy.p0.p0.i32(ptr nocapture, ptr nocapture readonly, i32, i1) @@ -157,3 +158,6 @@ define void @test_load_store_diff_addr_space(ptr addrspace(1) %complex1, ptr add store i64 %v2, ptr addrspace(1) %complex2 ret void } +;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +; CHECK-modify-cfg: {{.*}} +; CHECK-preserve-cfg: {{.*}} diff --git a/llvm/test/Transforms/SROA/addrspacecast.ll b/llvm/test/Transforms/SROA/addrspacecast.ll index 40cc0f7..9dc56ad 100644 --- a/llvm/test/Transforms/SROA/addrspacecast.ll +++ b/llvm/test/Transforms/SROA/addrspacecast.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -passes=sroa -S | FileCheck %s +; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg target datalayout = "e-p:64:64:64-p1:16:16:16-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-n8:16:32:64" @@ -288,12 +289,21 @@ define void @select_addrspacecast(i1 %a, i1 %b) { } define void @select_addrspacecast_const_op(i1 %a, i1 %b) { -; CHECK-LABEL: @select_addrspacecast_const_op( -; CHECK-NEXT: [[C:%.*]] = alloca i64, align 8 -; CHECK-NEXT: [[C_0_ASC_SROA_CAST:%.*]] = addrspacecast ptr [[C]] to ptr addrspace(1) -; CHECK-NEXT: [[COND_IN:%.*]] = select i1 [[B:%.*]], ptr addrspace(1) [[C_0_ASC_SROA_CAST]], ptr addrspace(1) null -; CHECK-NEXT: [[COND:%.*]] = load i64, ptr addrspace(1) [[COND_IN]], align 8 -; CHECK-NEXT: ret void +; CHECK-preserve-cfg-LABEL: @select_addrspacecast_const_op( +; CHECK-preserve-cfg-NEXT: [[C:%.*]] = alloca i64, align 8 +; CHECK-preserve-cfg-NEXT: [[C_0_ASC_SROA_CAST:%.*]] = addrspacecast ptr [[C]] to ptr addrspace(1) +; CHECK-preserve-cfg-NEXT: [[COND_IN:%.*]] = select i1 [[B:%.*]], ptr addrspace(1) [[C_0_ASC_SROA_CAST]], ptr addrspace(1) null +; CHECK-preserve-cfg-NEXT: [[COND:%.*]] = load i64, ptr addrspace(1) [[COND_IN]], align 8 +; CHECK-preserve-cfg-NEXT: ret void +; +; CHECK-modify-cfg-LABEL: @select_addrspacecast_const_op( +; CHECK-modify-cfg-NEXT: br i1 [[B:%.*]], label [[DOTCONT:%.*]], label [[DOTELSE:%.*]] +; CHECK-modify-cfg: .else: +; CHECK-modify-cfg-NEXT: [[COND_ELSE_VAL:%.*]] = load i64, ptr addrspace(1) null, align 8 +; CHECK-modify-cfg-NEXT: br label [[DOTCONT]] +; CHECK-modify-cfg: .cont: +; CHECK-modify-cfg-NEXT: [[COND:%.*]] = phi i64 [ undef, [[TMP0:%.*]] ], [ [[COND_ELSE_VAL]], [[DOTELSE]] ] +; CHECK-modify-cfg-NEXT: ret void ; %c = alloca i64, align 8 %p.0.c = select i1 %a, ptr %c, ptr %c diff --git a/llvm/test/Transforms/SROA/alignment.ll b/llvm/test/Transforms/SROA/alignment.ll index 223075830..8744208 100644 --- a/llvm/test/Transforms/SROA/alignment.ll +++ b/llvm/test/Transforms/SROA/alignment.ll @@ -1,6 +1,7 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -passes=sroa -S | FileCheck %s -; RUN: opt -passes='debugify,function(sroa)' -S < %s | FileCheck %s -check-prefix CHECK-DEBUGLOC +; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg +; RUN: opt -passes='debugify,function(sroa<preserve-cfg>)' -S < %s | FileCheck %s -check-prefix CHECK-DEBUGLOC target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-n8:16:32:64" @@ -456,3 +457,6 @@ define dso_local i32 @pr45010(ptr %A) { } declare void @populate(ptr) +;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +; CHECK-modify-cfg: {{.*}} +; CHECK-preserve-cfg: {{.*}} diff --git a/llvm/test/Transforms/SROA/alloca-address-space.ll b/llvm/test/Transforms/SROA/alloca-address-space.ll index d4f305c..cd347ab 100644 --- a/llvm/test/Transforms/SROA/alloca-address-space.ll +++ b/llvm/test/Transforms/SROA/alloca-address-space.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -passes=sroa -S | FileCheck %s +; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg target datalayout = "e-p:64:64:64-p1:16:16:16-p2:32:32-p3:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-n8:16:32:64-A2" declare void @llvm.memcpy.p2.p2.i32(ptr addrspace(2) nocapture, ptr addrspace(2) nocapture readonly, i32, i1) @@ -145,3 +146,6 @@ define void @addressspace_alloca_lifetime() { } declare void @llvm.lifetime.start.p0(i64 %size, ptr nocapture %ptr) +;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +; CHECK-modify-cfg: {{.*}} +; CHECK-preserve-cfg: {{.*}} diff --git a/llvm/test/Transforms/SROA/assume.ll b/llvm/test/Transforms/SROA/assume.ll index d17d23a..da667a6 100644 --- a/llvm/test/Transforms/SROA/assume.ll +++ b/llvm/test/Transforms/SROA/assume.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -passes=sroa -S | FileCheck %s +; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" @@ -27,3 +28,6 @@ entry: declare void @llvm.assume(i1) #0 attributes #0 = { nofree norecurse nounwind willreturn } +;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +; CHECK-modify-cfg: {{.*}} +; CHECK-preserve-cfg: {{.*}} diff --git a/llvm/test/Transforms/SROA/basictest.ll b/llvm/test/Transforms/SROA/basictest.ll index ddf678f..711cc3f 100644 --- a/llvm/test/Transforms/SROA/basictest.ll +++ b/llvm/test/Transforms/SROA/basictest.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -passes=sroa -S | FileCheck %s +; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg target datalayout = "e-p:64:64:64-p1:16:16:16-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-n8:16:32:64" @@ -1408,9 +1409,19 @@ end: } define void @PR15805(i1 %a, i1 %b) { -; CHECK-LABEL: @PR15805( -; CHECK-NEXT: [[COND_SROA_SPECULATED:%.*]] = select i1 [[B:%.*]], i64 undef, i64 undef -; CHECK-NEXT: ret void +; CHECK-preserve-cfg-LABEL: @PR15805( +; CHECK-preserve-cfg-NEXT: [[C:%.*]] = alloca i64, align 8 +; CHECK-preserve-cfg-NEXT: [[COND_IN:%.*]] = select i1 [[B:%.*]], ptr [[C]], ptr [[C]] +; CHECK-preserve-cfg-NEXT: [[COND:%.*]] = load i64, ptr [[COND_IN]], align 8 +; CHECK-preserve-cfg-NEXT: ret void +; +; CHECK-modify-cfg-LABEL: @PR15805( +; CHECK-modify-cfg-NEXT: br i1 [[B:%.*]], label [[DOTCONT:%.*]], label [[DOTELSE:%.*]] +; CHECK-modify-cfg: .else: +; CHECK-modify-cfg-NEXT: br label [[DOTCONT]] +; CHECK-modify-cfg: .cont: +; CHECK-modify-cfg-NEXT: [[COND:%.*]] = phi i64 [ undef, [[TMP0:%.*]] ], [ undef, [[DOTELSE]] ] +; CHECK-modify-cfg-NEXT: ret void ; %c = alloca i64, align 8 %p.0.c = select i1 %a, ptr %c, ptr %c @@ -1425,13 +1436,29 @@ define void @PR15805.1(i1 %a, i1 %b, i1 %c2) { ; order in which the uses of the alloca are visited. ; ; -; CHECK-LABEL: @PR15805.1( -; CHECK-NEXT: br label [[EXIT:%.*]] -; CHECK: loop: -; CHECK-NEXT: [[COND_SROA_SPECULATED:%.*]] = select i1 [[A:%.*]], i64 undef, i64 undef -; CHECK-NEXT: br i1 [[C2:%.*]], label [[LOOP:%.*]], label [[EXIT]] -; CHECK: exit: -; CHECK-NEXT: ret void +; CHECK-preserve-cfg-LABEL: @PR15805.1( +; CHECK-preserve-cfg-NEXT: [[C:%.*]] = alloca i64, align 8 +; CHECK-preserve-cfg-NEXT: br label [[EXIT:%.*]] +; CHECK-preserve-cfg: loop: +; CHECK-preserve-cfg-NEXT: [[COND_IN:%.*]] = select i1 [[A:%.*]], ptr [[C]], ptr [[C]] +; CHECK-preserve-cfg-NEXT: [[COND:%.*]] = load i64, ptr [[COND_IN]], align 8 +; CHECK-preserve-cfg-NEXT: br i1 [[C2:%.*]], label [[LOOP:%.*]], label [[EXIT]] +; CHECK-preserve-cfg: exit: +; CHECK-preserve-cfg-NEXT: ret void +; +; CHECK-modify-cfg-LABEL: @PR15805.1( +; CHECK-modify-cfg-NEXT: br label [[EXIT:%.*]] +; CHECK-modify-cfg: loop: +; CHECK-modify-cfg-NEXT: [[C_0_LOAD:%.*]] = load i64, ptr poison, align 8 +; CHECK-modify-cfg-NEXT: br i1 [[A:%.*]], label [[LOOP_CONT:%.*]], label [[LOOP_ELSE:%.*]] +; CHECK-modify-cfg: loop.else: +; CHECK-modify-cfg-NEXT: [[C_0_LOAD1:%.*]] = load i64, ptr poison, align 8 +; CHECK-modify-cfg-NEXT: br label [[LOOP_CONT]] +; CHECK-modify-cfg: loop.cont: +; CHECK-modify-cfg-NEXT: [[COND:%.*]] = phi i64 [ [[C_0_LOAD]], [[LOOP:%.*]] ], [ [[C_0_LOAD1]], [[LOOP_ELSE]] ] +; CHECK-modify-cfg-NEXT: br i1 [[C2:%.*]], label [[LOOP]], label [[EXIT]] +; CHECK-modify-cfg: exit: +; CHECK-modify-cfg-NEXT: ret void ; %c = alloca i64, align 8 br label %exit @@ -1483,13 +1510,24 @@ define void @PR16651.2(<2 x float> %val, i1 %c1) { ; bail on select instructions. ; ; -; CHECK-LABEL: @PR16651.2( -; CHECK-NEXT: entry: -; CHECK-NEXT: [[TV1_SROA_0:%.*]] = alloca <2 x float>, align 8 -; CHECK-NEXT: store <2 x float> [[VAL:%.*]], ptr [[TV1_SROA_0]], align 8 -; CHECK-NEXT: [[COND105_IN_I_I:%.*]] = select i1 [[C1:%.*]], ptr null, ptr [[TV1_SROA_0]] -; CHECK-NEXT: [[COND105_I_I:%.*]] = load float, ptr [[COND105_IN_I_I]], align 8 -; CHECK-NEXT: ret void +; CHECK-preserve-cfg-LABEL: @PR16651.2( +; CHECK-preserve-cfg-NEXT: entry: +; CHECK-preserve-cfg-NEXT: [[TV1_SROA_0:%.*]] = alloca <2 x float>, align 8 +; CHECK-preserve-cfg-NEXT: store <2 x float> [[VAL:%.*]], ptr [[TV1_SROA_0]], align 8 +; CHECK-preserve-cfg-NEXT: [[COND105_IN_I_I:%.*]] = select i1 [[C1:%.*]], ptr null, ptr [[TV1_SROA_0]] +; CHECK-preserve-cfg-NEXT: [[COND105_I_I:%.*]] = load float, ptr [[COND105_IN_I_I]], align 8 +; CHECK-preserve-cfg-NEXT: ret void +; +; CHECK-modify-cfg-LABEL: @PR16651.2( +; CHECK-modify-cfg-NEXT: entry: +; CHECK-modify-cfg-NEXT: [[TV1_SROA_0_0_VEC_EXTRACT:%.*]] = extractelement <2 x float> [[VAL:%.*]], i32 0 +; CHECK-modify-cfg-NEXT: br i1 [[C1:%.*]], label [[ENTRY_THEN:%.*]], label [[ENTRY_CONT:%.*]] +; CHECK-modify-cfg: entry.then: +; CHECK-modify-cfg-NEXT: [[COND105_I_I_THEN_VAL:%.*]] = load float, ptr null, align 8 +; CHECK-modify-cfg-NEXT: br label [[ENTRY_CONT]] +; CHECK-modify-cfg: entry.cont: +; CHECK-modify-cfg-NEXT: [[COND105_I_I:%.*]] = phi float [ [[COND105_I_I_THEN_VAL]], [[ENTRY_THEN]] ], [ [[TV1_SROA_0_0_VEC_EXTRACT]], [[ENTRY:%.*]] ] +; CHECK-modify-cfg-NEXT: ret void ; entry: %tv1 = alloca { <2 x float>, <2 x float> }, align 8 diff --git a/llvm/test/Transforms/SROA/big-endian.ll b/llvm/test/Transforms/SROA/big-endian.ll index 9209895..f80d68c 100644 --- a/llvm/test/Transforms/SROA/big-endian.ll +++ b/llvm/test/Transforms/SROA/big-endian.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -passes=sroa -S | FileCheck %s +; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg target datalayout = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-n8:16:32:64" @@ -230,3 +231,6 @@ entry: } declare void @llvm.memcpy.p0.p0.i64(ptr, ptr, i64, i1) +;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +; CHECK-modify-cfg: {{.*}} +; CHECK-preserve-cfg: {{.*}} diff --git a/llvm/test/Transforms/SROA/dbg-addr-diamond.ll b/llvm/test/Transforms/SROA/dbg-addr-diamond.ll index 652fc82..5455105 100644 --- a/llvm/test/Transforms/SROA/dbg-addr-diamond.ll +++ b/llvm/test/Transforms/SROA/dbg-addr-diamond.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt -use-dbg-addr -passes=sroa -S < %s | FileCheck %s +; RUN: opt -use-dbg-addr -passes='sroa<preserve-cfg>' -S < %s | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt -use-dbg-addr -passes='sroa<modify-cfg>' -S < %s | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg ; ModuleID = '<stdin>' source_filename = "newvars.c" @@ -127,3 +128,6 @@ declare void @llvm.dbg.addr(metadata, metadata, metadata) !52 = !{i64 0, i64 4, !53, i64 4, i64 4, !53} !53 = !{!31, !31, i64 0} !54 = !DILocation(line: 14, column: 1, scope: !8) +;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +; CHECK-modify-cfg: {{.*}} +; CHECK-preserve-cfg: {{.*}} diff --git a/llvm/test/Transforms/SROA/dbg-inline.ll b/llvm/test/Transforms/SROA/dbg-inline.ll index 48498e9..755bb772 100644 --- a/llvm/test/Transforms/SROA/dbg-inline.ll +++ b/llvm/test/Transforms/SROA/dbg-inline.ll @@ -2,7 +2,8 @@ ; Test that SROA can deal with allocas that have more than one ; dbg.declare hanging off of it. -; RUN: opt < %s -passes=sroa -S | FileCheck %s +; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg source_filename = "/tmp/inlinesplit.cpp" target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.15.0" @@ -69,3 +70,6 @@ attributes #2 = { argmemonly nounwind willreturn } !24 = distinct !DILocation(line: 10, column: 10, scope: !8) !25 = !DILocation(line: 6, column: 12, scope: !22, inlinedAt: !24) !26 = !DILocation(line: 10, column: 3, scope: !8) +;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +; CHECK-modify-cfg: {{.*}} +; CHECK-preserve-cfg: {{.*}} diff --git a/llvm/test/Transforms/SROA/dbg-single-piece.ll b/llvm/test/Transforms/SROA/dbg-single-piece.ll index bb0e51d..cb71dd2 100644 --- a/llvm/test/Transforms/SROA/dbg-single-piece.ll +++ b/llvm/test/Transforms/SROA/dbg-single-piece.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt -passes=sroa %s -S | FileCheck %s +; RUN: opt -passes='sroa<preserve-cfg>' %s -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt -passes='sroa<modify-cfg>' %s -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" %foo = type { [8 x i8], [8 x i8] } @@ -36,3 +37,6 @@ attributes #0 = { nounwind readnone } !7 = !DIExpression() !8 = !DILocation(line: 947, column: 35, scope: !2) !9 = distinct !DICompileUnit(language: DW_LANG_Julia, file: !3) +;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +; CHECK-modify-cfg: {{.*}} +; CHECK-preserve-cfg: {{.*}} diff --git a/llvm/test/Transforms/SROA/dead-inst.ll b/llvm/test/Transforms/SROA/dead-inst.ll index 299bed8..53fa0da 100644 --- a/llvm/test/Transforms/SROA/dead-inst.ll +++ b/llvm/test/Transforms/SROA/dead-inst.ll @@ -1,8 +1,10 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -passes='bdce,sroa<preserve-cfg>,bdce' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt < %s -passes='bdce,sroa<modify-cfg>,bdce' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg + ; SROA fails to rewrite allocs but does rewrite some phis and delete ; dead instructions. Ensure that this invalidates analyses required ; for other passes. -; RUN: opt < %s -passes=bdce,sroa,bdce -o %t -debug-pass-manager 2>&1 | FileCheck %s target datalayout = "e-m:e-i64:64-n32:64" target triple = "powerpc64le-grtev4-linux-gnu" @@ -13,6 +15,56 @@ declare void @D(ptr sret(%class.b), ptr dereferenceable(32)) local_unnamed_addr ; Function Attrs: nounwind define void @H(ptr noalias nocapture readnone, [2 x i64], ptr %ptr, i32 signext %v, i64 %l, i64 %idx, ptr nonnull dereferenceable(32) %ptr2) { +; CHECK-LABEL: @H( +; CHECK-NEXT: [[TMP3:%.*]] = alloca [[CLASS_B:%.*]], align 8 +; CHECK-NEXT: [[TMP4:%.*]] = extractvalue [2 x i64] [[TMP1:%.*]], 1 +; CHECK-NEXT: switch i64 [[TMP4]], label [[TMP6:%.*]] [ +; CHECK-NEXT: i64 4, label [[FOO:%.*]] +; CHECK-NEXT: i64 5, label [[TMP5:%.*]] +; CHECK-NEXT: ] +; CHECK: 5: +; CHECK-NEXT: br label [[TMP12:%.*]] +; CHECK: 6: +; CHECK-NEXT: [[TMP7:%.*]] = icmp ugt i64 [[TMP4]], 5 +; CHECK-NEXT: br i1 [[TMP7]], label [[TMP8:%.*]], label [[TMP12]] +; CHECK: 8: +; CHECK-NEXT: [[TMP9:%.*]] = load i8, ptr inttoptr (i64 4 to ptr), align 4 +; CHECK-NEXT: [[TMP10:%.*]] = icmp eq i8 [[TMP9]], 47 +; CHECK-NEXT: [[TMP11:%.*]] = select i1 [[TMP10]], i64 5, i64 4 +; CHECK-NEXT: br label [[TMP12]] +; CHECK: 12: +; CHECK-NEXT: [[TMP13:%.*]] = phi i64 [ 4, [[TMP5]] ], [ [[TMP11]], [[TMP8]] ], [ 4, [[TMP6]] ] +; CHECK-NEXT: [[TMP14:%.*]] = icmp ne i64 [[TMP4]], 0 +; CHECK-NEXT: [[TMP15:%.*]] = icmp ugt i64 [[TMP4]], [[TMP13]] +; CHECK-NEXT: [[TMP16:%.*]] = and i1 [[TMP14]], [[TMP15]] +; CHECK-NEXT: br i1 [[TMP16]], label [[TMP17:%.*]], label [[A_EXIT:%.*]] +; CHECK: 17: +; CHECK-NEXT: [[TMP18:%.*]] = tail call ptr @memchr(ptr [[PTR:%.*]], i32 signext [[V:%.*]], i64 [[L:%.*]]) +; CHECK-NEXT: [[TMP19:%.*]] = icmp eq ptr [[TMP18]], null +; CHECK-NEXT: [[TMP20:%.*]] = sext i1 [[TMP19]] to i64 +; CHECK-NEXT: br label [[A_EXIT]] +; CHECK: a.exit: +; CHECK-NEXT: [[TMP21:%.*]] = phi i64 [ -1, [[TMP12]] ], [ [[TMP20]], [[TMP17]] ] +; CHECK-NEXT: [[TMP22:%.*]] = inttoptr i64 0 to ptr +; CHECK-NEXT: [[TMP23:%.*]] = sub nsw i64 [[TMP21]], [[TMP13]] +; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 32, ptr nonnull [[TMP3]]) +; CHECK-NEXT: [[TMP24:%.*]] = icmp ult i64 [[TMP23]], 2 +; CHECK-NEXT: br i1 [[TMP24]], label [[G_EXIT:%.*]], label [[TMP25:%.*]] +; CHECK: 25: +; CHECK-NEXT: [[TMP26:%.*]] = getelementptr inbounds i8, ptr [[TMP22]], i64 [[IDX:%.*]] +; CHECK-NEXT: [[TMP27:%.*]] = icmp eq ptr [[TMP26]], null +; CHECK-NEXT: br i1 [[TMP27]], label [[TMP28:%.*]], label [[TMP29:%.*]] +; CHECK: 28: +; CHECK-NEXT: unreachable +; CHECK: 29: +; CHECK-NEXT: call void @D(ptr nonnull sret([[CLASS_B]]) [[TMP3]], ptr nonnull dereferenceable(32) [[PTR2:%.*]]) +; CHECK-NEXT: br label [[G_EXIT]] +; CHECK: G.exit: +; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 32, ptr nonnull [[TMP3]]) +; CHECK-NEXT: br label [[FOO]] +; CHECK: foo: +; CHECK-NEXT: ret void +; %3 = alloca %class.b, align 8 %.sroa.0 = alloca i64, align 8 store i64 0, ptr %.sroa.0, align 8 @@ -86,4 +138,5 @@ declare void @llvm.lifetime.start.p0(i64, ptr nocapture) ; Function Attrs: argmemonly nounwind declare void @llvm.lifetime.end.p0(i64, ptr nocapture) ;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: -; CHECK: {{.*}} +; CHECK-modify-cfg: {{.*}} +; CHECK-preserve-cfg: {{.*}} diff --git a/llvm/test/Transforms/SROA/fca.ll b/llvm/test/Transforms/SROA/fca.ll index 57aa1b0..6937b05 100644 --- a/llvm/test/Transforms/SROA/fca.ll +++ b/llvm/test/Transforms/SROA/fca.ll @@ -1,5 +1,7 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -passes=sroa -S | FileCheck %s +; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg + target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-n8:16:32:64" define { i32, i32 } @test0(i32 %x, i32 %y, { i32, i32 } %v) { @@ -53,3 +55,6 @@ entry: store volatile { i32, i32 } %result, ptr %b ret { i32, i32 } %result } +;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +; CHECK-modify-cfg: {{.*}} +; CHECK-preserve-cfg: {{.*}} diff --git a/llvm/test/Transforms/SROA/ignore-droppable.ll b/llvm/test/Transforms/SROA/ignore-droppable.ll index e4aaf96..3dd0e58 100644 --- a/llvm/test/Transforms/SROA/ignore-droppable.ll +++ b/llvm/test/Transforms/SROA/ignore-droppable.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -passes=sroa -S | FileCheck %s +; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg declare void @llvm.assume(i1) declare void @llvm.lifetime.start.p0(i64 %size, ptr nocapture %ptr) @@ -78,3 +79,6 @@ define void @positive_mixed_assume_uses() { call void @llvm.assume(i1 true) ["nonnull"(ptr %A), "align"(ptr %A, i64 2), "nonnull"(ptr %A)] ret void } +;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +; CHECK-modify-cfg: {{.*}} +; CHECK-preserve-cfg: {{.*}} diff --git a/llvm/test/Transforms/SROA/invariant-group.ll b/llvm/test/Transforms/SROA/invariant-group.ll index 8d487eb..a8007ad 100644 --- a/llvm/test/Transforms/SROA/invariant-group.ll +++ b/llvm/test/Transforms/SROA/invariant-group.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt -passes=sroa -S -o - < %s | FileCheck %s +; RUN: opt -passes='sroa<preserve-cfg>' -S -o - < %s | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt -passes='sroa<modify-cfg>' -S -o - < %s | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg %t = type { i32, i32 } @@ -79,3 +80,6 @@ define void @g() { } !0 = !{} +;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +; CHECK-modify-cfg: {{.*}} +; CHECK-preserve-cfg: {{.*}} diff --git a/llvm/test/Transforms/SROA/irregular-type.ll b/llvm/test/Transforms/SROA/irregular-type.ll index 78cd6b3..d9f5cf9 100644 --- a/llvm/test/Transforms/SROA/irregular-type.ll +++ b/llvm/test/Transforms/SROA/irregular-type.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -passes=sroa -S | FileCheck %s +; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg %S = type { [4 x i8] } @@ -39,3 +40,6 @@ Entry: %3 = zext i17 %2 to i32 ret i32 %3 } +;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +; CHECK-modify-cfg: {{.*}} +; CHECK-preserve-cfg: {{.*}} diff --git a/llvm/test/Transforms/SROA/lifetime-intrinsic.ll b/llvm/test/Transforms/SROA/lifetime-intrinsic.ll index 68cfd3c..d80da56 100644 --- a/llvm/test/Transforms/SROA/lifetime-intrinsic.ll +++ b/llvm/test/Transforms/SROA/lifetime-intrinsic.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -passes=sroa -S | FileCheck %s +; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg %i32x2 = type { [2 x i32] } @@ -55,3 +56,6 @@ declare void @llvm.lifetime.end.p0(i64, ptr nocapture) #1 attributes #0 = { alwaysinline nounwind } attributes #1 = { argmemonly nounwind } +;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +; CHECK-modify-cfg: {{.*}} +; CHECK-preserve-cfg: {{.*}} diff --git a/llvm/test/Transforms/SROA/mem-par-metadata-sroa-cast.ll b/llvm/test/Transforms/SROA/mem-par-metadata-sroa-cast.ll index 032dd17..ac9a6db 100644 --- a/llvm/test/Transforms/SROA/mem-par-metadata-sroa-cast.ll +++ b/llvm/test/Transforms/SROA/mem-par-metadata-sroa-cast.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -passes=sroa -S | FileCheck %s +; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg ; ; Make sure the llvm.access.group meta-data is preserved ; when a load/store is replaced with another load/store by sroa @@ -35,3 +36,6 @@ entry: } !0 = distinct !{} +;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +; CHECK-modify-cfg: {{.*}} +; CHECK-preserve-cfg: {{.*}} diff --git a/llvm/test/Transforms/SROA/mem-par-metadata-sroa.ll b/llvm/test/Transforms/SROA/mem-par-metadata-sroa.ll index 04d5e6a..4df8f39 100644 --- a/llvm/test/Transforms/SROA/mem-par-metadata-sroa.ll +++ b/llvm/test/Transforms/SROA/mem-par-metadata-sroa.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -passes=sroa -S | FileCheck %s +; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg ; ; Make sure the llvm.access.group meta-data is preserved ; when a load/store is replaced with another load/store by sroa @@ -121,3 +122,6 @@ attributes #1 = { argmemonly nounwind } !4 = distinct !{!4, !5, !"_ZNK7ComplexplERKS_: %agg.result"} !5 = distinct !{!5, !"_ZNK7ComplexplERKS_"} !11 = distinct !{} +;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +; CHECK-modify-cfg: {{.*}} +; CHECK-preserve-cfg: {{.*}} diff --git a/llvm/test/Transforms/SROA/non-capturing-call-readonly.ll b/llvm/test/Transforms/SROA/non-capturing-call-readonly.ll index 33e6003..a2cb0b2 100644 --- a/llvm/test/Transforms/SROA/non-capturing-call-readonly.ll +++ b/llvm/test/Transforms/SROA/non-capturing-call-readonly.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -passes=sroa -S | FileCheck %s --check-prefix=CHECK +; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg define i32 @alloca_used_in_call(ptr %data, i64 %n) { ; CHECK-LABEL: @alloca_used_in_call( @@ -917,3 +918,6 @@ declare dso_local void @byte_user_of_alloca(ptr nocapture readonly) declare dso_local i32 @__gxx_personality_v0(...) declare void @llvm.memcpy.p0.p0.i32(ptr, ptr, i32, i1) +;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +; CHECK-modify-cfg: {{.*}} +; CHECK-preserve-cfg: {{.*}} diff --git a/llvm/test/Transforms/SROA/non-integral-pointers.ll b/llvm/test/Transforms/SROA/non-integral-pointers.ll index 99be316..a6a0b60 100644 --- a/llvm/test/Transforms/SROA/non-integral-pointers.ll +++ b/llvm/test/Transforms/SROA/non-integral-pointers.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt -passes=sroa -S < %s | FileCheck %s +; RUN: opt -passes='sroa<preserve-cfg>' -S < %s | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt -passes='sroa<modify-cfg>' -S < %s | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg ; This test checks that SROA does not introduce ptrtoint and inttoptr ; casts from and to non-integral pointers. The "ni:4" bit in the @@ -131,3 +132,6 @@ define ptr@f2(ptr addrspace(4) %p) { } declare void @llvm.memset.p0.i64(ptr, i8, i64, i1) +;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +; CHECK-modify-cfg: {{.*}} +; CHECK-preserve-cfg: {{.*}} diff --git a/llvm/test/Transforms/SROA/phi-and-select.ll b/llvm/test/Transforms/SROA/phi-and-select.ll index 15b7159..065ac303 100644 --- a/llvm/test/Transforms/SROA/phi-and-select.ll +++ b/llvm/test/Transforms/SROA/phi-and-select.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -passes=sroa -S | FileCheck %s +; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-n8:16:32:64" define i32 @test1() { @@ -810,13 +811,23 @@ exit: ; Don't speculate a load based on an earlier volatile operation. define i8 @volatile_select(ptr %p, i1 %b) { -; CHECK-LABEL: @volatile_select( -; CHECK-NEXT: [[P2:%.*]] = alloca i8, align 1 -; CHECK-NEXT: store i8 0, ptr [[P2]], align 1 -; CHECK-NEXT: store volatile i8 0, ptr [[P:%.*]], align 1 -; CHECK-NEXT: [[PX:%.*]] = select i1 [[B:%.*]], ptr [[P]], ptr [[P2]] -; CHECK-NEXT: [[V2:%.*]] = load i8, ptr [[PX]], align 1 -; CHECK-NEXT: ret i8 [[V2]] +; CHECK-preserve-cfg-LABEL: @volatile_select( +; CHECK-preserve-cfg-NEXT: [[P2:%.*]] = alloca i8, align 1 +; CHECK-preserve-cfg-NEXT: store i8 0, ptr [[P2]], align 1 +; CHECK-preserve-cfg-NEXT: store volatile i8 0, ptr [[P:%.*]], align 1 +; CHECK-preserve-cfg-NEXT: [[PX:%.*]] = select i1 [[B:%.*]], ptr [[P]], ptr [[P2]] +; CHECK-preserve-cfg-NEXT: [[V2:%.*]] = load i8, ptr [[PX]], align 1 +; CHECK-preserve-cfg-NEXT: ret i8 [[V2]] +; +; CHECK-modify-cfg-LABEL: @volatile_select( +; CHECK-modify-cfg-NEXT: store volatile i8 0, ptr [[P:%.*]], align 1 +; CHECK-modify-cfg-NEXT: br i1 [[B:%.*]], label [[DOTTHEN:%.*]], label [[DOTCONT:%.*]] +; CHECK-modify-cfg: .then: +; CHECK-modify-cfg-NEXT: [[V2_THEN_VAL:%.*]] = load i8, ptr [[P]], align 1 +; CHECK-modify-cfg-NEXT: br label [[DOTCONT]] +; CHECK-modify-cfg: .cont: +; CHECK-modify-cfg-NEXT: [[V2:%.*]] = phi i8 [ [[V2_THEN_VAL]], [[DOTTHEN]] ], [ 0, [[TMP0:%.*]] ] +; CHECK-modify-cfg-NEXT: ret i8 [[V2]] ; %p2 = alloca i8 store i8 0, ptr %p2 diff --git a/llvm/test/Transforms/SROA/phi-catchswitch.ll b/llvm/test/Transforms/SROA/phi-catchswitch.ll index ea90101..0de7d05 100644 --- a/llvm/test/Transforms/SROA/phi-catchswitch.ll +++ b/llvm/test/Transforms/SROA/phi-catchswitch.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -passes=sroa -S | FileCheck %s +; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" target triple = "wasm32-unknown-unknown" @@ -63,3 +64,6 @@ bb10: ; preds = %catch.dispatch, %en store i32 0, ptr %tmp11, align 4 unreachable } +;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +; CHECK-modify-cfg: {{.*}} +; CHECK-preserve-cfg: {{.*}} diff --git a/llvm/test/Transforms/SROA/phi-gep.ll b/llvm/test/Transforms/SROA/phi-gep.ll index 8ac3a18..075b99a 100644 --- a/llvm/test/Transforms/SROA/phi-gep.ll +++ b/llvm/test/Transforms/SROA/phi-gep.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt -S -passes=sroa < %s | FileCheck %s +; RUN: opt -S -passes='sroa<preserve-cfg>' < %s | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt -S -passes='sroa<modify-cfg>' < %s | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg %pair = type { i32, i32 } @@ -508,3 +509,6 @@ declare ptr @foo() declare i32 @__gxx_personality_v0(...) declare void @llvm.memcpy.p0.p0.i64(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg) +;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +; CHECK-modify-cfg: {{.*}} +; CHECK-preserve-cfg: {{.*}} diff --git a/llvm/test/Transforms/SROA/phi-speculate-different-load-types.ll b/llvm/test/Transforms/SROA/phi-speculate-different-load-types.ll index 7893da3..5e98fbf 100644 --- a/llvm/test/Transforms/SROA/phi-speculate-different-load-types.ll +++ b/llvm/test/Transforms/SROA/phi-speculate-different-load-types.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt -passes=sroa < %s -S | FileCheck %s +; RUN: opt -passes='sroa<preserve-cfg>' < %s -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt -passes='sroa<modify-cfg>' < %s -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg define void @f(i1 %i) { ; CHECK-LABEL: @f( @@ -39,3 +40,6 @@ bb2: declare void @use32(i32) declare void @use64(i64) +;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +; CHECK-modify-cfg: {{.*}} +; CHECK-preserve-cfg: {{.*}} diff --git a/llvm/test/Transforms/SROA/phi-with-duplicate-pred.ll b/llvm/test/Transforms/SROA/phi-with-duplicate-pred.ll index 2361a50..1d20fac 100644 --- a/llvm/test/Transforms/SROA/phi-with-duplicate-pred.ll +++ b/llvm/test/Transforms/SROA/phi-with-duplicate-pred.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -passes=sroa -S | FileCheck %s +; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-n8:16:32:64" @a = external global i16, align 1 @@ -263,3 +264,6 @@ final: cleanup7: ; preds = %cleanup ret void } +;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +; CHECK-modify-cfg: {{.*}} +; CHECK-preserve-cfg: {{.*}} diff --git a/llvm/test/Transforms/SROA/pointer-offset-size.ll b/llvm/test/Transforms/SROA/pointer-offset-size.ll index 76b5209..498261c 100644 --- a/llvm/test/Transforms/SROA/pointer-offset-size.ll +++ b/llvm/test/Transforms/SROA/pointer-offset-size.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -passes=sroa -S | FileCheck %s +; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg target datalayout = "e-p:64:64:64:32" %struct.test = type { %struct.basic, %struct.basic } @@ -21,3 +22,6 @@ entry: } declare void @llvm.memcpy.p0.p0.i32(ptr nocapture writeonly, ptr nocapture readonly, i32, i1) +;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +; CHECK-modify-cfg: {{.*}} +; CHECK-preserve-cfg: {{.*}} diff --git a/llvm/test/Transforms/SROA/ppcf128-no-fold.ll b/llvm/test/Transforms/SROA/ppcf128-no-fold.ll index b4a7090..74c6f12 100644 --- a/llvm/test/Transforms/SROA/ppcf128-no-fold.ll +++ b/llvm/test/Transforms/SROA/ppcf128-no-fold.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -passes=sroa -S | FileCheck %s +; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg target datalayout = "E-m:e-i64:64-n32:64" target triple = "powerpc64-unknown-linux-gnu" @@ -32,3 +33,6 @@ entry: attributes #0 = { nounwind } +;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +; CHECK-modify-cfg: {{.*}} +; CHECK-preserve-cfg: {{.*}} diff --git a/llvm/test/Transforms/SROA/pr26972.ll b/llvm/test/Transforms/SROA/pr26972.ll index a0e6204..a5117389 100644 --- a/llvm/test/Transforms/SROA/pr26972.ll +++ b/llvm/test/Transforms/SROA/pr26972.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -passes=sroa -S | FileCheck %s +; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-pc-linux" @@ -16,3 +17,6 @@ define void @fn1() { } declare void @llvm.lifetime.end.p0(i64, ptr nocapture) +;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +; CHECK-modify-cfg: {{.*}} +; CHECK-preserve-cfg: {{.*}} diff --git a/llvm/test/Transforms/SROA/pr37267.ll b/llvm/test/Transforms/SROA/pr37267.ll index f783758..4028fc2 100644 --- a/llvm/test/Transforms/SROA/pr37267.ll +++ b/llvm/test/Transforms/SROA/pr37267.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -passes=sroa -S | FileCheck %s +; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg target datalayout = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32:64-S128" target triple = "sparcv9-sun-solaris" @@ -78,3 +79,6 @@ bb1: %rc = add i16 %_tmp13, %_tmp16 ret i16 %rc } +;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +; CHECK-modify-cfg: {{.*}} +; CHECK-preserve-cfg: {{.*}} diff --git a/llvm/test/Transforms/SROA/preserve-nonnull.ll b/llvm/test/Transforms/SROA/preserve-nonnull.ll index b5b885c..92be318 100644 --- a/llvm/test/Transforms/SROA/preserve-nonnull.ll +++ b/llvm/test/Transforms/SROA/preserve-nonnull.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -passes=sroa -S | FileCheck %s +; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg ; ; Make sure that SROA doesn't lose nonnull metadata ; on loads from allocas that get optimized out. @@ -81,3 +82,6 @@ entry: } !0 = !{} +;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +; CHECK-modify-cfg: {{.*}} +; CHECK-preserve-cfg: {{.*}} diff --git a/llvm/test/Transforms/SROA/scalable-vectors.ll b/llvm/test/Transforms/SROA/scalable-vectors.ll index 5c66654..510d07a 100644 --- a/llvm/test/Transforms/SROA/scalable-vectors.ll +++ b/llvm/test/Transforms/SROA/scalable-vectors.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -passes=sroa -S | FileCheck %s +; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg ; This test checks that SROA runs mem2reg on scalable vectors. @@ -78,3 +79,6 @@ define <vscale x 4 x i32> @cast_alloca_from_svint32_t() { } declare void @llvm.memcpy.p0.p0.i64(ptr nocapture, ptr nocapture, i64, i1) nounwind +;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +; CHECK-modify-cfg: {{.*}} +; CHECK-preserve-cfg: {{.*}} diff --git a/llvm/test/Transforms/SROA/select-gep.ll b/llvm/test/Transforms/SROA/select-gep.ll index 9586feb..23ab6dd 100644 --- a/llvm/test/Transforms/SROA/select-gep.ll +++ b/llvm/test/Transforms/SROA/select-gep.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt -S -passes=sroa < %s | FileCheck %s +; RUN: opt -S -passes='sroa<preserve-cfg>' < %s | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt -S -passes='sroa<modify-cfg>' < %s | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg %pair = type { i32, i32 } @@ -77,12 +78,22 @@ bb: } define i32 @test_sroa_select_gep_poison(i1 %cond) { -; CHECK-LABEL: @test_sroa_select_gep_poison( -; CHECK-NEXT: bb: -; CHECK-NEXT: [[A_SROA_0:%.*]] = alloca i32, align 4 -; CHECK-NEXT: [[SELECT_SROA_SEL:%.*]] = select i1 [[COND:%.*]], ptr [[A_SROA_0]], ptr poison -; CHECK-NEXT: [[LOAD:%.*]] = load i32, ptr [[SELECT_SROA_SEL]], align 4 -; CHECK-NEXT: ret i32 [[LOAD]] +; CHECK-preserve-cfg-LABEL: @test_sroa_select_gep_poison( +; CHECK-preserve-cfg-NEXT: bb: +; CHECK-preserve-cfg-NEXT: [[A_SROA_0:%.*]] = alloca i32, align 4 +; CHECK-preserve-cfg-NEXT: [[SELECT_SROA_SEL:%.*]] = select i1 [[COND:%.*]], ptr [[A_SROA_0]], ptr poison +; CHECK-preserve-cfg-NEXT: [[LOAD:%.*]] = load i32, ptr [[SELECT_SROA_SEL]], align 4 +; CHECK-preserve-cfg-NEXT: ret i32 [[LOAD]] +; +; CHECK-modify-cfg-LABEL: @test_sroa_select_gep_poison( +; CHECK-modify-cfg-NEXT: bb: +; CHECK-modify-cfg-NEXT: br i1 [[COND:%.*]], label [[BB_CONT:%.*]], label [[BB_ELSE:%.*]] +; CHECK-modify-cfg: bb.else: +; CHECK-modify-cfg-NEXT: [[LOAD_ELSE_VAL:%.*]] = load i32, ptr poison, align 4 +; CHECK-modify-cfg-NEXT: br label [[BB_CONT]] +; CHECK-modify-cfg: bb.cont: +; CHECK-modify-cfg-NEXT: [[LOAD:%.*]] = phi i32 [ undef, [[BB:%.*]] ], [ [[LOAD_ELSE_VAL]], [[BB_ELSE]] ] +; CHECK-modify-cfg-NEXT: ret i32 [[LOAD]] ; bb: %a = alloca %pair, align 4 diff --git a/llvm/test/Transforms/SROA/select-load.ll b/llvm/test/Transforms/SROA/select-load.ll index dc6770d..8ed2962 100644 --- a/llvm/test/Transforms/SROA/select-load.ll +++ b/llvm/test/Transforms/SROA/select-load.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt -S -passes=sroa < %s | FileCheck %s +; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg %st.half = type { half } @@ -82,22 +83,41 @@ define i32 @interfering_lifetime(ptr %data, i64 %indvars.iv) { ; We should recursively evaluate select's. define i32 @clamp_load_to_constant_range(ptr %data, i64 %indvars.iv) { -; CHECK-LABEL: @clamp_load_to_constant_range( -; CHECK-NEXT: [[MIN:%.*]] = alloca i32, align 4 -; CHECK-NEXT: [[MAX:%.*]] = alloca i32, align 4 -; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[DATA:%.*]], i64 [[INDVARS_IV:%.*]] -; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[MIN]]) -; CHECK-NEXT: store i32 0, ptr [[MIN]], align 4 -; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[MAX]]) -; CHECK-NEXT: store i32 4095, ptr [[MAX]], align 4 -; CHECK-NEXT: [[I1:%.*]] = load i32, ptr [[ARRAYIDX]], align 4 -; CHECK-NEXT: [[CMP_I_I:%.*]] = icmp slt i32 [[I1]], 0 -; CHECK-NEXT: [[I2:%.*]] = tail call i32 @llvm.smax.i32(i32 [[I1]], i32 0) -; CHECK-NEXT: [[__B___A_I_I:%.*]] = select i1 [[CMP_I_I]], ptr [[MIN]], ptr [[ARRAYIDX]] -; CHECK-NEXT: [[CMP_I1_I:%.*]] = icmp ugt i32 [[I2]], 4095 -; CHECK-NEXT: [[__B___A_I2_I:%.*]] = select i1 [[CMP_I1_I]], ptr [[MAX]], ptr [[__B___A_I_I]] -; CHECK-NEXT: [[I3:%.*]] = load i32, ptr [[__B___A_I2_I]], align 4 -; CHECK-NEXT: ret i32 [[I3]] +; CHECK-preserve-cfg-LABEL: @clamp_load_to_constant_range( +; CHECK-preserve-cfg-NEXT: [[MIN:%.*]] = alloca i32, align 4 +; CHECK-preserve-cfg-NEXT: [[MAX:%.*]] = alloca i32, align 4 +; CHECK-preserve-cfg-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[DATA:%.*]], i64 [[INDVARS_IV:%.*]] +; CHECK-preserve-cfg-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[MIN]]) +; CHECK-preserve-cfg-NEXT: store i32 0, ptr [[MIN]], align 4 +; CHECK-preserve-cfg-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[MAX]]) +; CHECK-preserve-cfg-NEXT: store i32 4095, ptr [[MAX]], align 4 +; CHECK-preserve-cfg-NEXT: [[I1:%.*]] = load i32, ptr [[ARRAYIDX]], align 4 +; CHECK-preserve-cfg-NEXT: [[CMP_I_I:%.*]] = icmp slt i32 [[I1]], 0 +; CHECK-preserve-cfg-NEXT: [[I2:%.*]] = tail call i32 @llvm.smax.i32(i32 [[I1]], i32 0) +; CHECK-preserve-cfg-NEXT: [[__B___A_I_I:%.*]] = select i1 [[CMP_I_I]], ptr [[MIN]], ptr [[ARRAYIDX]] +; CHECK-preserve-cfg-NEXT: [[CMP_I1_I:%.*]] = icmp ugt i32 [[I2]], 4095 +; CHECK-preserve-cfg-NEXT: [[__B___A_I2_I:%.*]] = select i1 [[CMP_I1_I]], ptr [[MAX]], ptr [[__B___A_I_I]] +; CHECK-preserve-cfg-NEXT: [[I3:%.*]] = load i32, ptr [[__B___A_I2_I]], align 4 +; CHECK-preserve-cfg-NEXT: ret i32 [[I3]] +; +; CHECK-modify-cfg-LABEL: @clamp_load_to_constant_range( +; CHECK-modify-cfg-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[DATA:%.*]], i64 [[INDVARS_IV:%.*]] +; CHECK-modify-cfg-NEXT: [[I1:%.*]] = load i32, ptr [[ARRAYIDX]], align 4 +; CHECK-modify-cfg-NEXT: [[CMP_I_I:%.*]] = icmp slt i32 [[I1]], 0 +; CHECK-modify-cfg-NEXT: [[I2:%.*]] = tail call i32 @llvm.smax.i32(i32 [[I1]], i32 0) +; CHECK-modify-cfg-NEXT: [[CMP_I1_I:%.*]] = icmp ugt i32 [[I2]], 4095 +; CHECK-modify-cfg-NEXT: br i1 [[CMP_I1_I]], label [[DOTCONT:%.*]], label [[DOTELSE:%.*]] +; CHECK-modify-cfg: .else: +; CHECK-modify-cfg-NEXT: br i1 [[CMP_I_I]], label [[DOTELSE_CONT:%.*]], label [[DOTELSE_ELSE:%.*]] +; CHECK-modify-cfg: .else.else: +; CHECK-modify-cfg-NEXT: [[I3_ELSE_VAL_ELSE_VAL:%.*]] = load i32, ptr [[ARRAYIDX]], align 4 +; CHECK-modify-cfg-NEXT: br label [[DOTELSE_CONT]] +; CHECK-modify-cfg: .else.cont: +; CHECK-modify-cfg-NEXT: [[I3_ELSE_VAL:%.*]] = phi i32 [ 0, [[DOTELSE]] ], [ [[I3_ELSE_VAL_ELSE_VAL]], [[DOTELSE_ELSE]] ] +; CHECK-modify-cfg-NEXT: br label [[DOTCONT]] +; CHECK-modify-cfg: .cont: +; CHECK-modify-cfg-NEXT: [[I3:%.*]] = phi i32 [ 4095, [[TMP0:%.*]] ], [ [[I3_ELSE_VAL]], [[DOTELSE_CONT]] ] +; CHECK-modify-cfg-NEXT: ret i32 [[I3]] ; %min = alloca i32, align 4 %max = alloca i32, align 4 @@ -117,13 +137,23 @@ define i32 @clamp_load_to_constant_range(ptr %data, i64 %indvars.iv) { } define i32 @non_speculatable_load_of_select(i1 %cond, ptr %else.addr) { -; CHECK-LABEL: @non_speculatable_load_of_select( -; CHECK-NEXT: entry: -; CHECK-NEXT: [[MIN:%.*]] = alloca i32, align 4 -; CHECK-NEXT: store i32 0, ptr [[MIN]], align 4 -; CHECK-NEXT: [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[MIN]], ptr [[ELSE_ADDR:%.*]], !prof [[PROF0:![0-9]+]] -; CHECK-NEXT: [[R:%.*]] = load i32, ptr [[ADDR]], align 4 -; CHECK-NEXT: ret i32 [[R]] +; CHECK-preserve-cfg-LABEL: @non_speculatable_load_of_select( +; CHECK-preserve-cfg-NEXT: entry: +; CHECK-preserve-cfg-NEXT: [[MIN:%.*]] = alloca i32, align 4 +; CHECK-preserve-cfg-NEXT: store i32 0, ptr [[MIN]], align 4 +; CHECK-preserve-cfg-NEXT: [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[MIN]], ptr [[ELSE_ADDR:%.*]], !prof [[PROF0:![0-9]+]] +; CHECK-preserve-cfg-NEXT: [[R:%.*]] = load i32, ptr [[ADDR]], align 4 +; CHECK-preserve-cfg-NEXT: ret i32 [[R]] +; +; CHECK-modify-cfg-LABEL: @non_speculatable_load_of_select( +; CHECK-modify-cfg-NEXT: entry: +; CHECK-modify-cfg-NEXT: br i1 [[COND:%.*]], label [[ENTRY_CONT:%.*]], label [[ENTRY_ELSE:%.*]], !prof [[PROF0:![0-9]+]] +; CHECK-modify-cfg: entry.else: +; CHECK-modify-cfg-NEXT: [[R_ELSE_VAL:%.*]] = load i32, ptr [[ELSE_ADDR:%.*]], align 4 +; CHECK-modify-cfg-NEXT: br label [[ENTRY_CONT]] +; CHECK-modify-cfg: entry.cont: +; CHECK-modify-cfg-NEXT: [[R:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[R_ELSE_VAL]], [[ENTRY_ELSE]] ] +; CHECK-modify-cfg-NEXT: ret i32 [[R]] ; entry: %min = alloca i32, align 4 @@ -133,13 +163,23 @@ entry: ret i32 %r } define i32 @non_speculatable_load_of_select_inverted(i1 %cond, ptr %then.addr) { -; CHECK-LABEL: @non_speculatable_load_of_select_inverted( -; CHECK-NEXT: entry: -; CHECK-NEXT: [[MAX:%.*]] = alloca i32, align 4 -; CHECK-NEXT: store i32 4095, ptr [[MAX]], align 4 -; CHECK-NEXT: [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[THEN_ADDR:%.*]], ptr [[MAX]], !prof [[PROF0]] -; CHECK-NEXT: [[R:%.*]] = load i32, ptr [[ADDR]], align 4 -; CHECK-NEXT: ret i32 [[R]] +; CHECK-preserve-cfg-LABEL: @non_speculatable_load_of_select_inverted( +; CHECK-preserve-cfg-NEXT: entry: +; CHECK-preserve-cfg-NEXT: [[MAX:%.*]] = alloca i32, align 4 +; CHECK-preserve-cfg-NEXT: store i32 4095, ptr [[MAX]], align 4 +; CHECK-preserve-cfg-NEXT: [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[THEN_ADDR:%.*]], ptr [[MAX]], !prof [[PROF0]] +; CHECK-preserve-cfg-NEXT: [[R:%.*]] = load i32, ptr [[ADDR]], align 4 +; CHECK-preserve-cfg-NEXT: ret i32 [[R]] +; +; CHECK-modify-cfg-LABEL: @non_speculatable_load_of_select_inverted( +; CHECK-modify-cfg-NEXT: entry: +; CHECK-modify-cfg-NEXT: br i1 [[COND:%.*]], label [[ENTRY_THEN:%.*]], label [[ENTRY_CONT:%.*]], !prof [[PROF1:![0-9]+]] +; CHECK-modify-cfg: entry.then: +; CHECK-modify-cfg-NEXT: [[R_THEN_VAL:%.*]] = load i32, ptr [[THEN_ADDR:%.*]], align 4 +; CHECK-modify-cfg-NEXT: br label [[ENTRY_CONT]] +; CHECK-modify-cfg: entry.cont: +; CHECK-modify-cfg-NEXT: [[R:%.*]] = phi i32 [ [[R_THEN_VAL]], [[ENTRY_THEN]] ], [ 4095, [[ENTRY:%.*]] ] +; CHECK-modify-cfg-NEXT: ret i32 [[R]] ; entry: %max = alloca i32, align 4 @@ -150,13 +190,21 @@ entry: } define i32 @non_speculatable_volatile_load_of_select(i1 %cond, ptr %else.addr) { -; CHECK-LABEL: @non_speculatable_volatile_load_of_select( -; CHECK-NEXT: entry: -; CHECK-NEXT: [[MIN:%.*]] = alloca i32, align 4 -; CHECK-NEXT: store i32 0, ptr [[MIN]], align 4 -; CHECK-NEXT: [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[MIN]], ptr [[ELSE_ADDR:%.*]], !prof [[PROF0]] -; CHECK-NEXT: [[R:%.*]] = load volatile i32, ptr [[ADDR]], align 4 -; CHECK-NEXT: ret i32 [[R]] +; CHECK-preserve-cfg-LABEL: @non_speculatable_volatile_load_of_select( +; CHECK-preserve-cfg-NEXT: entry: +; CHECK-preserve-cfg-NEXT: [[MIN:%.*]] = alloca i32, align 4 +; CHECK-preserve-cfg-NEXT: store i32 0, ptr [[MIN]], align 4 +; CHECK-preserve-cfg-NEXT: [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[MIN]], ptr [[ELSE_ADDR:%.*]], !prof [[PROF0]] +; CHECK-preserve-cfg-NEXT: [[R:%.*]] = load volatile i32, ptr [[ADDR]], align 4 +; CHECK-preserve-cfg-NEXT: ret i32 [[R]] +; +; CHECK-modify-cfg-LABEL: @non_speculatable_volatile_load_of_select( +; CHECK-modify-cfg-NEXT: entry: +; CHECK-modify-cfg-NEXT: [[MIN:%.*]] = alloca i32, align 4 +; CHECK-modify-cfg-NEXT: store i32 0, ptr [[MIN]], align 4 +; CHECK-modify-cfg-NEXT: [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[MIN]], ptr [[ELSE_ADDR:%.*]], !prof [[PROF1]] +; CHECK-modify-cfg-NEXT: [[R:%.*]] = load volatile i32, ptr [[ADDR]], align 4 +; CHECK-modify-cfg-NEXT: ret i32 [[R]] ; entry: %min = alloca i32, align 4 @@ -166,13 +214,21 @@ entry: ret i32 %r } define i32 @non_speculatable_volatile_load_of_select_inverted(i1 %cond, ptr %then.addr) { -; CHECK-LABEL: @non_speculatable_volatile_load_of_select_inverted( -; CHECK-NEXT: entry: -; CHECK-NEXT: [[MAX:%.*]] = alloca i32, align 4 -; CHECK-NEXT: store i32 4095, ptr [[MAX]], align 4 -; CHECK-NEXT: [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[THEN_ADDR:%.*]], ptr [[MAX]], !prof [[PROF0]] -; CHECK-NEXT: [[R:%.*]] = load volatile i32, ptr [[ADDR]], align 4 -; CHECK-NEXT: ret i32 [[R]] +; CHECK-preserve-cfg-LABEL: @non_speculatable_volatile_load_of_select_inverted( +; CHECK-preserve-cfg-NEXT: entry: +; CHECK-preserve-cfg-NEXT: [[MAX:%.*]] = alloca i32, align 4 +; CHECK-preserve-cfg-NEXT: store i32 4095, ptr [[MAX]], align 4 +; CHECK-preserve-cfg-NEXT: [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[THEN_ADDR:%.*]], ptr [[MAX]], !prof [[PROF0]] +; CHECK-preserve-cfg-NEXT: [[R:%.*]] = load volatile i32, ptr [[ADDR]], align 4 +; CHECK-preserve-cfg-NEXT: ret i32 [[R]] +; +; CHECK-modify-cfg-LABEL: @non_speculatable_volatile_load_of_select_inverted( +; CHECK-modify-cfg-NEXT: entry: +; CHECK-modify-cfg-NEXT: [[MAX:%.*]] = alloca i32, align 4 +; CHECK-modify-cfg-NEXT: store i32 4095, ptr [[MAX]], align 4 +; CHECK-modify-cfg-NEXT: [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[THEN_ADDR:%.*]], ptr [[MAX]], !prof [[PROF1]] +; CHECK-modify-cfg-NEXT: [[R:%.*]] = load volatile i32, ptr [[ADDR]], align 4 +; CHECK-modify-cfg-NEXT: ret i32 [[R]] ; entry: %max = alloca i32, align 4 @@ -183,13 +239,25 @@ entry: } define i32 @non_speculatable_atomic_unord_load_of_select(i1 %cond, ptr %else.addr) { -; CHECK-LABEL: @non_speculatable_atomic_unord_load_of_select( -; CHECK-NEXT: entry: -; CHECK-NEXT: [[MIN:%.*]] = alloca i32, align 4 -; CHECK-NEXT: store i32 0, ptr [[MIN]], align 4 -; CHECK-NEXT: [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[MIN]], ptr [[ELSE_ADDR:%.*]], !prof [[PROF0]] -; CHECK-NEXT: [[R:%.*]] = load atomic i32, ptr [[ADDR]] unordered, align 4 -; CHECK-NEXT: ret i32 [[R]] +; CHECK-preserve-cfg-LABEL: @non_speculatable_atomic_unord_load_of_select( +; CHECK-preserve-cfg-NEXT: entry: +; CHECK-preserve-cfg-NEXT: [[MIN:%.*]] = alloca i32, align 4 +; CHECK-preserve-cfg-NEXT: store i32 0, ptr [[MIN]], align 4 +; CHECK-preserve-cfg-NEXT: [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[MIN]], ptr [[ELSE_ADDR:%.*]], !prof [[PROF0]] +; CHECK-preserve-cfg-NEXT: [[R:%.*]] = load atomic i32, ptr [[ADDR]] unordered, align 4 +; CHECK-preserve-cfg-NEXT: ret i32 [[R]] +; +; CHECK-modify-cfg-LABEL: @non_speculatable_atomic_unord_load_of_select( +; CHECK-modify-cfg-NEXT: entry: +; CHECK-modify-cfg-NEXT: br i1 [[COND:%.*]], label [[ENTRY_THEN:%.*]], label [[ENTRY_ELSE:%.*]], !prof [[PROF1]] +; CHECK-modify-cfg: entry.then: +; CHECK-modify-cfg-NEXT: br label [[ENTRY_CONT:%.*]] +; CHECK-modify-cfg: entry.else: +; CHECK-modify-cfg-NEXT: [[R_ELSE_VAL:%.*]] = load atomic i32, ptr [[ELSE_ADDR:%.*]] unordered, align 4 +; CHECK-modify-cfg-NEXT: br label [[ENTRY_CONT]] +; CHECK-modify-cfg: entry.cont: +; CHECK-modify-cfg-NEXT: [[R:%.*]] = phi i32 [ 0, [[ENTRY_THEN]] ], [ [[R_ELSE_VAL]], [[ENTRY_ELSE]] ] +; CHECK-modify-cfg-NEXT: ret i32 [[R]] ; entry: %min = alloca i32, align 4 @@ -199,13 +267,25 @@ entry: ret i32 %r } define i32 @non_speculatable_atomic_unord_load_of_select_inverted(i1 %cond, ptr %then.addr) { -; CHECK-LABEL: @non_speculatable_atomic_unord_load_of_select_inverted( -; CHECK-NEXT: entry: -; CHECK-NEXT: [[MAX:%.*]] = alloca i32, align 4 -; CHECK-NEXT: store i32 4095, ptr [[MAX]], align 4 -; CHECK-NEXT: [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[THEN_ADDR:%.*]], ptr [[MAX]], !prof [[PROF0]] -; CHECK-NEXT: [[R:%.*]] = load atomic i32, ptr [[ADDR]] unordered, align 4 -; CHECK-NEXT: ret i32 [[R]] +; CHECK-preserve-cfg-LABEL: @non_speculatable_atomic_unord_load_of_select_inverted( +; CHECK-preserve-cfg-NEXT: entry: +; CHECK-preserve-cfg-NEXT: [[MAX:%.*]] = alloca i32, align 4 +; CHECK-preserve-cfg-NEXT: store i32 4095, ptr [[MAX]], align 4 +; CHECK-preserve-cfg-NEXT: [[ADDR:%.*]] = select i1 [[COND:%.*]], ptr [[THEN_ADDR:%.*]], ptr [[MAX]], !prof [[PROF0]] +; CHECK-preserve-cfg-NEXT: [[R:%.*]] = load atomic i32, ptr [[ADDR]] unordered, align 4 +; CHECK-preserve-cfg-NEXT: ret i32 [[R]] +; +; CHECK-modify-cfg-LABEL: @non_speculatable_atomic_unord_load_of_select_inverted( +; CHECK-modify-cfg-NEXT: entry: +; CHECK-modify-cfg-NEXT: br i1 [[COND:%.*]], label [[ENTRY_THEN:%.*]], label [[ENTRY_ELSE:%.*]], !prof [[PROF1]] +; CHECK-modify-cfg: entry.then: +; CHECK-modify-cfg-NEXT: [[R_THEN_VAL:%.*]] = load atomic i32, ptr [[THEN_ADDR:%.*]] unordered, align 4 +; CHECK-modify-cfg-NEXT: br label [[ENTRY_CONT:%.*]] +; CHECK-modify-cfg: entry.else: +; CHECK-modify-cfg-NEXT: br label [[ENTRY_CONT]] +; CHECK-modify-cfg: entry.cont: +; CHECK-modify-cfg-NEXT: [[R:%.*]] = phi i32 [ [[R_THEN_VAL]], [[ENTRY_THEN]] ], [ 4095, [[ENTRY_ELSE]] ] +; CHECK-modify-cfg-NEXT: ret i32 [[R]] ; entry: %max = alloca i32, align 4 @@ -216,14 +296,25 @@ entry: } define i32 @non_speculatable_load_of_select_outer(i1 %cond_inner, i1 %cond_outer, ptr %data_then, ptr %data_else) { -; CHECK-LABEL: @non_speculatable_load_of_select_outer( -; CHECK-NEXT: entry: -; CHECK-NEXT: [[MIN:%.*]] = alloca i32, align 4 -; CHECK-NEXT: store i32 0, ptr [[MIN]], align 4 -; CHECK-NEXT: [[ADDR_DATA:%.*]] = select i1 [[COND_INNER:%.*]], ptr [[DATA_THEN:%.*]], ptr [[DATA_ELSE:%.*]], !prof [[PROF0]] -; CHECK-NEXT: [[ADDR:%.*]] = select i1 [[COND_OUTER:%.*]], ptr [[MIN]], ptr [[ADDR_DATA]], !prof [[PROF0]] -; CHECK-NEXT: [[R:%.*]] = load i32, ptr [[ADDR]], align 4 -; CHECK-NEXT: ret i32 [[R]] +; CHECK-preserve-cfg-LABEL: @non_speculatable_load_of_select_outer( +; CHECK-preserve-cfg-NEXT: entry: +; CHECK-preserve-cfg-NEXT: [[MIN:%.*]] = alloca i32, align 4 +; CHECK-preserve-cfg-NEXT: store i32 0, ptr [[MIN]], align 4 +; CHECK-preserve-cfg-NEXT: [[ADDR_DATA:%.*]] = select i1 [[COND_INNER:%.*]], ptr [[DATA_THEN:%.*]], ptr [[DATA_ELSE:%.*]], !prof [[PROF0]] +; CHECK-preserve-cfg-NEXT: [[ADDR:%.*]] = select i1 [[COND_OUTER:%.*]], ptr [[MIN]], ptr [[ADDR_DATA]], !prof [[PROF0]] +; CHECK-preserve-cfg-NEXT: [[R:%.*]] = load i32, ptr [[ADDR]], align 4 +; CHECK-preserve-cfg-NEXT: ret i32 [[R]] +; +; CHECK-modify-cfg-LABEL: @non_speculatable_load_of_select_outer( +; CHECK-modify-cfg-NEXT: entry: +; CHECK-modify-cfg-NEXT: [[ADDR_DATA:%.*]] = select i1 [[COND_INNER:%.*]], ptr [[DATA_THEN:%.*]], ptr [[DATA_ELSE:%.*]], !prof [[PROF1]] +; CHECK-modify-cfg-NEXT: br i1 [[COND_OUTER:%.*]], label [[ENTRY_CONT:%.*]], label [[ENTRY_ELSE:%.*]], !prof [[PROF0]] +; CHECK-modify-cfg: entry.else: +; CHECK-modify-cfg-NEXT: [[R_ELSE_VAL:%.*]] = load i32, ptr [[ADDR_DATA]], align 4 +; CHECK-modify-cfg-NEXT: br label [[ENTRY_CONT]] +; CHECK-modify-cfg: entry.cont: +; CHECK-modify-cfg-NEXT: [[R:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[R_ELSE_VAL]], [[ENTRY_ELSE]] ] +; CHECK-modify-cfg-NEXT: ret i32 [[R]] ; entry: %min = alloca i32, align 4 @@ -234,14 +325,25 @@ entry: ret i32 %r } define i32 @non_speculatable_load_of_select_outer_inverted(i1 %cond_inner, i1 %cond_outer, ptr %data_then, ptr %data_else) { -; CHECK-LABEL: @non_speculatable_load_of_select_outer_inverted( -; CHECK-NEXT: entry: -; CHECK-NEXT: [[MIN:%.*]] = alloca i32, align 4 -; CHECK-NEXT: store i32 0, ptr [[MIN]], align 4 -; CHECK-NEXT: [[ADDR_DATA:%.*]] = select i1 [[COND_INNER:%.*]], ptr [[DATA_THEN:%.*]], ptr [[DATA_ELSE:%.*]], !prof [[PROF0]] -; CHECK-NEXT: [[ADDR:%.*]] = select i1 [[COND_OUTER:%.*]], ptr [[ADDR_DATA]], ptr [[MIN]], !prof [[PROF0]] -; CHECK-NEXT: [[R:%.*]] = load i32, ptr [[ADDR]], align 4 -; CHECK-NEXT: ret i32 [[R]] +; CHECK-preserve-cfg-LABEL: @non_speculatable_load_of_select_outer_inverted( +; CHECK-preserve-cfg-NEXT: entry: +; CHECK-preserve-cfg-NEXT: [[MIN:%.*]] = alloca i32, align 4 +; CHECK-preserve-cfg-NEXT: store i32 0, ptr [[MIN]], align 4 +; CHECK-preserve-cfg-NEXT: [[ADDR_DATA:%.*]] = select i1 [[COND_INNER:%.*]], ptr [[DATA_THEN:%.*]], ptr [[DATA_ELSE:%.*]], !prof [[PROF0]] +; CHECK-preserve-cfg-NEXT: [[ADDR:%.*]] = select i1 [[COND_OUTER:%.*]], ptr [[ADDR_DATA]], ptr [[MIN]], !prof [[PROF0]] +; CHECK-preserve-cfg-NEXT: [[R:%.*]] = load i32, ptr [[ADDR]], align 4 +; CHECK-preserve-cfg-NEXT: ret i32 [[R]] +; +; CHECK-modify-cfg-LABEL: @non_speculatable_load_of_select_outer_inverted( +; CHECK-modify-cfg-NEXT: entry: +; CHECK-modify-cfg-NEXT: [[ADDR_DATA:%.*]] = select i1 [[COND_INNER:%.*]], ptr [[DATA_THEN:%.*]], ptr [[DATA_ELSE:%.*]], !prof [[PROF1]] +; CHECK-modify-cfg-NEXT: br i1 [[COND_OUTER:%.*]], label [[ENTRY_THEN:%.*]], label [[ENTRY_CONT:%.*]], !prof [[PROF1]] +; CHECK-modify-cfg: entry.then: +; CHECK-modify-cfg-NEXT: [[R_THEN_VAL:%.*]] = load i32, ptr [[ADDR_DATA]], align 4 +; CHECK-modify-cfg-NEXT: br label [[ENTRY_CONT]] +; CHECK-modify-cfg: entry.cont: +; CHECK-modify-cfg-NEXT: [[R:%.*]] = phi i32 [ [[R_THEN_VAL]], [[ENTRY_THEN]] ], [ 0, [[ENTRY:%.*]] ] +; CHECK-modify-cfg-NEXT: ret i32 [[R]] ; entry: %min = alloca i32, align 4 @@ -253,14 +355,23 @@ entry: } define i32 @non_speculatable_load_of_select_inner(i1 %cond_inner, i1 %cond_outer, ptr %data_else, ptr %min_else) { -; CHECK-LABEL: @non_speculatable_load_of_select_inner( -; CHECK-NEXT: entry: -; CHECK-NEXT: [[MIN:%.*]] = alloca i32, align 4 -; CHECK-NEXT: store i32 0, ptr [[MIN]], align 4 -; CHECK-NEXT: [[MIN_ADDR_DATA:%.*]] = select i1 [[COND_INNER:%.*]], ptr [[MIN]], ptr [[MIN_ELSE:%.*]], !prof [[PROF0]] -; CHECK-NEXT: [[ADDR:%.*]] = select i1 [[COND_OUTER:%.*]], ptr [[MIN_ADDR_DATA]], ptr [[DATA_ELSE:%.*]], !prof [[PROF0]] -; CHECK-NEXT: [[R:%.*]] = load i32, ptr [[ADDR]], align 4 -; CHECK-NEXT: ret i32 [[R]] +; CHECK-preserve-cfg-LABEL: @non_speculatable_load_of_select_inner( +; CHECK-preserve-cfg-NEXT: entry: +; CHECK-preserve-cfg-NEXT: [[MIN:%.*]] = alloca i32, align 4 +; CHECK-preserve-cfg-NEXT: store i32 0, ptr [[MIN]], align 4 +; CHECK-preserve-cfg-NEXT: [[MIN_ADDR_DATA:%.*]] = select i1 [[COND_INNER:%.*]], ptr [[MIN]], ptr [[MIN_ELSE:%.*]], !prof [[PROF0]] +; CHECK-preserve-cfg-NEXT: [[ADDR:%.*]] = select i1 [[COND_OUTER:%.*]], ptr [[MIN_ADDR_DATA]], ptr [[DATA_ELSE:%.*]], !prof [[PROF0]] +; CHECK-preserve-cfg-NEXT: [[R:%.*]] = load i32, ptr [[ADDR]], align 4 +; CHECK-preserve-cfg-NEXT: ret i32 [[R]] +; +; CHECK-modify-cfg-LABEL: @non_speculatable_load_of_select_inner( +; CHECK-modify-cfg-NEXT: entry: +; CHECK-modify-cfg-NEXT: [[MIN:%.*]] = alloca i32, align 4 +; CHECK-modify-cfg-NEXT: store i32 0, ptr [[MIN]], align 4 +; CHECK-modify-cfg-NEXT: [[MIN_ADDR_DATA:%.*]] = select i1 [[COND_INNER:%.*]], ptr [[MIN]], ptr [[MIN_ELSE:%.*]], !prof [[PROF1]] +; CHECK-modify-cfg-NEXT: [[ADDR:%.*]] = select i1 [[COND_OUTER:%.*]], ptr [[MIN_ADDR_DATA]], ptr [[DATA_ELSE:%.*]], !prof [[PROF1]] +; CHECK-modify-cfg-NEXT: [[R:%.*]] = load i32, ptr [[ADDR]], align 4 +; CHECK-modify-cfg-NEXT: ret i32 [[R]] ; entry: %min = alloca i32, align 4 @@ -271,14 +382,23 @@ entry: ret i32 %r } define i32 @non_speculatable_load_of_select_inner_inverted(i1 %cond_inner, i1 %cond_outer, ptr %data_else, ptr %min_then) { -; CHECK-LABEL: @non_speculatable_load_of_select_inner_inverted( -; CHECK-NEXT: entry: -; CHECK-NEXT: [[MIN:%.*]] = alloca i32, align 4 -; CHECK-NEXT: store i32 0, ptr [[MIN]], align 4 -; CHECK-NEXT: [[MIN_ADDR_DATA:%.*]] = select i1 [[COND_INNER:%.*]], ptr [[MIN_THEN:%.*]], ptr [[MIN]], !prof [[PROF0]] -; CHECK-NEXT: [[ADDR:%.*]] = select i1 [[COND_OUTER:%.*]], ptr [[MIN_ADDR_DATA]], ptr [[DATA_ELSE:%.*]], !prof [[PROF0]] -; CHECK-NEXT: [[R:%.*]] = load i32, ptr [[ADDR]], align 4 -; CHECK-NEXT: ret i32 [[R]] +; CHECK-preserve-cfg-LABEL: @non_speculatable_load_of_select_inner_inverted( +; CHECK-preserve-cfg-NEXT: entry: +; CHECK-preserve-cfg-NEXT: [[MIN:%.*]] = alloca i32, align 4 +; CHECK-preserve-cfg-NEXT: store i32 0, ptr [[MIN]], align 4 +; CHECK-preserve-cfg-NEXT: [[MIN_ADDR_DATA:%.*]] = select i1 [[COND_INNER:%.*]], ptr [[MIN_THEN:%.*]], ptr [[MIN]], !prof [[PROF0]] +; CHECK-preserve-cfg-NEXT: [[ADDR:%.*]] = select i1 [[COND_OUTER:%.*]], ptr [[MIN_ADDR_DATA]], ptr [[DATA_ELSE:%.*]], !prof [[PROF0]] +; CHECK-preserve-cfg-NEXT: [[R:%.*]] = load i32, ptr [[ADDR]], align 4 +; CHECK-preserve-cfg-NEXT: ret i32 [[R]] +; +; CHECK-modify-cfg-LABEL: @non_speculatable_load_of_select_inner_inverted( +; CHECK-modify-cfg-NEXT: entry: +; CHECK-modify-cfg-NEXT: [[MIN:%.*]] = alloca i32, align 4 +; CHECK-modify-cfg-NEXT: store i32 0, ptr [[MIN]], align 4 +; CHECK-modify-cfg-NEXT: [[MIN_ADDR_DATA:%.*]] = select i1 [[COND_INNER:%.*]], ptr [[MIN_THEN:%.*]], ptr [[MIN]], !prof [[PROF1]] +; CHECK-modify-cfg-NEXT: [[ADDR:%.*]] = select i1 [[COND_OUTER:%.*]], ptr [[MIN_ADDR_DATA]], ptr [[DATA_ELSE:%.*]], !prof [[PROF1]] +; CHECK-modify-cfg-NEXT: [[R:%.*]] = load i32, ptr [[ADDR]], align 4 +; CHECK-modify-cfg-NEXT: ret i32 [[R]] ; entry: %min = alloca i32, align 4 diff --git a/llvm/test/Transforms/SROA/slice-order-independence.ll b/llvm/test/Transforms/SROA/slice-order-independence.ll index 47ac791..e4a0992 100644 --- a/llvm/test/Transforms/SROA/slice-order-independence.ll +++ b/llvm/test/Transforms/SROA/slice-order-independence.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -passes=sroa -S | FileCheck %s +; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg target datalayout = "e-p:64:64:64-p1:16:16:16-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-n8:16:32:64" declare void @llvm.memcpy.p0.p0.i32(ptr nocapture, ptr nocapture, i32, i1) nounwind @@ -44,3 +45,6 @@ define void @skipped_inttype_last(ptr) { %b0 = load i63, ptr %b ret void } +;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +; CHECK-modify-cfg: {{.*}} +; CHECK-preserve-cfg: {{.*}} diff --git a/llvm/test/Transforms/SROA/slice-width.ll b/llvm/test/Transforms/SROA/slice-width.ll index 7d2aeaa..8079a9c 100644 --- a/llvm/test/Transforms/SROA/slice-width.ll +++ b/llvm/test/Transforms/SROA/slice-width.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -passes=sroa -S | FileCheck %s +; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg target datalayout = "e-p:64:64:64-p1:16:16:16-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-f80:128-v64:64:64-v128:128:128-a0:0:64-n8:16:32:64" declare void @llvm.memcpy.p0.p0.i32(ptr nocapture, ptr nocapture, i32, i1) nounwind @@ -157,3 +158,6 @@ define i1 @presplit_overlarge_load() { %L2 = load i1, ptr %A ret i1 %L2 } +;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +; CHECK-modify-cfg: {{.*}} +; CHECK-preserve-cfg: {{.*}} diff --git a/llvm/test/Transforms/SROA/sroa-common-type-fail-promotion.ll b/llvm/test/Transforms/SROA/sroa-common-type-fail-promotion.ll index 00cbe569..f037d5c 100644 --- a/llvm/test/Transforms/SROA/sroa-common-type-fail-promotion.ll +++ b/llvm/test/Transforms/SROA/sroa-common-type-fail-promotion.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt -passes=sroa -S < %s | FileCheck %s +; RUN: opt -passes='sroa<preserve-cfg>' -S < %s | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt -passes='sroa<modify-cfg>' -S < %s | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg %"struct.a" = type { <8 x half> } %"struct.b" = type { %"struct.a" } @@ -409,3 +410,6 @@ declare void @llvm.memset.p0.i64(ptr nocapture writeonly, i8, i64, i1) nounwind declare void @llvm.memset.p0.i32(ptr nocapture writeonly, i8, i32, i1) nounwind attributes #0 = { nounwind readonly } +;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +; CHECK-modify-cfg: {{.*}} +; CHECK-preserve-cfg: {{.*}} diff --git a/llvm/test/Transforms/SROA/std-clamp.ll b/llvm/test/Transforms/SROA/std-clamp.ll index b950302..07ffd11 100644 --- a/llvm/test/Transforms/SROA/std-clamp.ll +++ b/llvm/test/Transforms/SROA/std-clamp.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -passes=sroa -S | FileCheck %s +; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" @@ -29,3 +30,6 @@ bb: %i9 = load float, ptr %i8, align 4 ret float %i9 } +;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +; CHECK-modify-cfg: {{.*}} +; CHECK-preserve-cfg: {{.*}} diff --git a/llvm/test/Transforms/SROA/tbaa-struct.ll b/llvm/test/Transforms/SROA/tbaa-struct.ll index 3e9332c..d16a84b 100644 --- a/llvm/test/Transforms/SROA/tbaa-struct.ll +++ b/llvm/test/Transforms/SROA/tbaa-struct.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt -S -passes=sroa %s | FileCheck %s +; RUN: opt -S -passes='sroa<preserve-cfg>' %s | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt -S -passes='sroa<modify-cfg>' %s | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg ; SROA should keep `!tbaa.struct` metadata @@ -26,3 +27,6 @@ define void @bar(ptr %y2) { !8 = !{!"float", !4, i64 0} !10 = !{i64 0, i64 4, !11, i64 4, i64 4, !11} !11 = !{!8, !8, i64 0} +;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +; CHECK-modify-cfg: {{.*}} +; CHECK-preserve-cfg: {{.*}} diff --git a/llvm/test/Transforms/SROA/tbaa-struct2.ll b/llvm/test/Transforms/SROA/tbaa-struct2.ll index 484651a..f37e523 100644 --- a/llvm/test/Transforms/SROA/tbaa-struct2.ll +++ b/llvm/test/Transforms/SROA/tbaa-struct2.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt -S -passes=sroa %s | FileCheck %s +; RUN: opt -S -passes='sroa<preserve-cfg>' %s | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt -S -passes='sroa<modify-cfg>' %s | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg ; SROA should correctly offset `!tbaa.struct` metadata @@ -34,3 +35,6 @@ define double @bar(ptr %wishart) { !6 = !{!"Simple C++ TBAA"} !7 = !{!8, !8, i64 0} !8 = !{!"int", !5, i64 0} +;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +; CHECK-modify-cfg: {{.*}} +; CHECK-preserve-cfg: {{.*}} diff --git a/llvm/test/Transforms/SROA/tbaa-subload.ll b/llvm/test/Transforms/SROA/tbaa-subload.ll index c43b78f..456ec48 100644 --- a/llvm/test/Transforms/SROA/tbaa-subload.ll +++ b/llvm/test/Transforms/SROA/tbaa-subload.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt -S -passes=sroa %s | FileCheck %s +; RUN: opt -S -passes='sroa<preserve-cfg>' %s | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt -S -passes='sroa<modify-cfg>' %s | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg ; This should not crash @@ -34,3 +35,6 @@ declare void @use(ptr %this) !7 = !{!8, !3, i64 8} !8 = !{!"_ZTSZN2ax2baEMS_FvvE2an2arE3$_0", !9, i64 0, !3, i64 8} !9 = !{!"_ZTS2ar"} +;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +; CHECK-modify-cfg: {{.*}} +; CHECK-preserve-cfg: {{.*}} diff --git a/llvm/test/Transforms/SROA/vector-conversion.ll b/llvm/test/Transforms/SROA/vector-conversion.ll index 3661f48..3a62754 100644 --- a/llvm/test/Transforms/SROA/vector-conversion.ll +++ b/llvm/test/Transforms/SROA/vector-conversion.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -passes=sroa -S | FileCheck %s +; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-n8:16:32:64" define <4 x i64> @vector_ptrtoint({<2 x ptr>, <2 x ptr>} %x) { @@ -98,3 +99,6 @@ define <16 x i8> @vector_ptrtointbitcast_vector({<2 x ptr>, <2 x ptr>} %x) { ret <16 x i8> %vec } +;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +; CHECK-modify-cfg: {{.*}} +; CHECK-preserve-cfg: {{.*}} diff --git a/llvm/test/Transforms/SROA/vector-lifetime-intrinsic.ll b/llvm/test/Transforms/SROA/vector-lifetime-intrinsic.ll index ad34b7b..58eafc2 100644 --- a/llvm/test/Transforms/SROA/vector-lifetime-intrinsic.ll +++ b/llvm/test/Transforms/SROA/vector-lifetime-intrinsic.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt -passes=sroa -S < %s | FileCheck %s +; RUN: opt -passes='sroa<preserve-cfg>' -S < %s | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt -passes='sroa<modify-cfg>' -S < %s | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg target datalayout = "e-p:64:32-i64:32-v32:32-n32-S64" @@ -30,3 +31,6 @@ bb: declare void @wombat3(<3 x float>) #0 attributes #0 = { nounwind } +;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +; CHECK-modify-cfg: {{.*}} +; CHECK-preserve-cfg: {{.*}} diff --git a/llvm/test/Transforms/SROA/vector-promotion-different-size.ll b/llvm/test/Transforms/SROA/vector-promotion-different-size.ll index a410c8a..7b19a21 100644 --- a/llvm/test/Transforms/SROA/vector-promotion-different-size.ll +++ b/llvm/test/Transforms/SROA/vector-promotion-different-size.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -passes=sroa -S | FileCheck %s +; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-n8:16:32:64" define <4 x i1> @vector_bitcast() { @@ -27,3 +28,6 @@ define <64 x i16> @vector_bitcast_2(<32 x i16> %v) { %load = load <64 x i16>, ptr %p ret <64 x i16> %load } +;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +; CHECK-modify-cfg: {{.*}} +; CHECK-preserve-cfg: {{.*}} diff --git a/llvm/test/Transforms/SROA/vector-promotion.ll b/llvm/test/Transforms/SROA/vector-promotion.ll index ec3c932..4fe2d2d 100644 --- a/llvm/test/Transforms/SROA/vector-promotion.ll +++ b/llvm/test/Transforms/SROA/vector-promotion.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -passes=sroa -S | FileCheck %s +; RUN: opt < %s -passes='sroa<preserve-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt < %s -passes='sroa<modify-cfg>' -S | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-n8:16:32:64" %S1 = type { i64, [42 x float] } @@ -631,3 +632,6 @@ define void @swap-15bytes(ptr %x, ptr %y) { declare void @llvm.memcpy.p0.p0.i64(ptr, ptr, i64, i1) declare void @llvm.lifetime.end.p0(i64, ptr) +;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +; CHECK-modify-cfg: {{.*}} +; CHECK-preserve-cfg: {{.*}} diff --git a/llvm/test/Transforms/SROA/vectors-of-pointers.ll b/llvm/test/Transforms/SROA/vectors-of-pointers.ll index fedbfbe..d839188 100644 --- a/llvm/test/Transforms/SROA/vectors-of-pointers.ll +++ b/llvm/test/Transforms/SROA/vectors-of-pointers.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -passes=sroa +; RUN: opt -S -passes='sroa<preserve-cfg>' < %s | FileCheck %s --check-prefixes=CHECK,CHECK-preserve-cfg +; RUN: opt -S -passes='sroa<modify-cfg>' < %s | FileCheck %s --check-prefixes=CHECK,CHECK-modify-cfg ; Make sure we don't crash on this one. @@ -7,6 +8,18 @@ target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f3 target triple = "x86_64-apple-macosx10.8.0" define void @foo(i1 %c1, i1 %c2) { +; CHECK-LABEL: @foo( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[C1:%.*]], label [[BB0_EXIT158:%.*]], label [[IF_THEN_I_I_I_I_I138:%.*]] +; CHECK: if.then.i.i.i.i.i138: +; CHECK-NEXT: ret void +; CHECK: bb0.exit158: +; CHECK-NEXT: br i1 [[C2:%.*]], label [[BB0_EXIT257:%.*]], label [[IF_THEN_I_I_I_I_I237:%.*]] +; CHECK: if.then.i.i.i.i.i237: +; CHECK-NEXT: unreachable +; CHECK: bb0.exit257: +; CHECK-NEXT: ret void +; entry: %Args.i = alloca <2 x ptr>, align 16 br i1 %c1, label %bb0.exit158, label %if.then.i.i.i.i.i138 @@ -24,3 +37,6 @@ bb0.exit257: %0 = load <2 x ptr>, ptr %Args.i, align 16 ret void } +;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +; CHECK-modify-cfg: {{.*}} +; CHECK-preserve-cfg: {{.*}} |