diff --git a/llvm/include/llvm/Transforms/Utils/Local.h b/llvm/include/llvm/Transforms/Utils/Local.h --- a/llvm/include/llvm/Transforms/Utils/Local.h +++ b/llvm/include/llvm/Transforms/Utils/Local.h @@ -143,7 +143,7 @@ /// recursively. Return true if any instructions were deleted. bool RecursivelyDeleteTriviallyDeadInstructions( Value *V, const TargetLibraryInfo *TLI = nullptr, - MemorySSAUpdater *MSSAU = nullptr); + MemorySSAUpdater *MSSAU = nullptr, AssumptionCache *AC = nullptr); /// Delete all of the instructions in `DeadInsts`, and all other instructions /// that deleting these in turn causes to be trivially dead. @@ -155,7 +155,8 @@ /// empty afterward. void RecursivelyDeleteTriviallyDeadInstructions( SmallVectorImpl &DeadInsts, - const TargetLibraryInfo *TLI = nullptr, MemorySSAUpdater *MSSAU = nullptr); + const TargetLibraryInfo *TLI = nullptr, MemorySSAUpdater *MSSAU = nullptr, + AssumptionCache *AC = nullptr); /// Same functionality as RecursivelyDeleteTriviallyDeadInstructions, but allow /// instructions that are not trivially dead. These will be ignored. @@ -163,7 +164,8 @@ /// were found and deleted. bool RecursivelyDeleteTriviallyDeadInstructionsPermissive( SmallVectorImpl &DeadInsts, - const TargetLibraryInfo *TLI = nullptr, MemorySSAUpdater *MSSAU = nullptr); + const TargetLibraryInfo *TLI = nullptr, MemorySSAUpdater *MSSAU = nullptr, + AssumptionCache *AC = nullptr); /// If the specified value is an effectively dead PHI node, due to being a /// def-use chain of single-use nodes that either forms a cycle or is terminated @@ -242,7 +244,8 @@ /// branches to us and one of our successors, fold the setcc into the /// predecessor and use logical operations to pick the right destination. bool FoldBranchToCommonDest(BranchInst *BI, MemorySSAUpdater *MSSAU = nullptr, - unsigned BonusInstThreshold = 1); + unsigned BonusInstThreshold = 1, + AssumptionCache *AC = nullptr); /// This function takes a virtual register computed by an Instruction and /// replaces it with a slot in the stack frame, allocated via alloca. diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp --- a/llvm/lib/Transforms/IPO/Attributor.cpp +++ b/llvm/lib/Transforms/IPO/Attributor.cpp @@ -7987,7 +7987,7 @@ << ToBeDeletedInsts.size() << " instructions and " << ToBeChangedUses.size() << " uses\n"); - SmallVector DeadInsts; + SmallVector DeadInsts; SmallVector TerminatorsToFold; for (auto &It : ToBeChangedUses) { @@ -8072,7 +8072,11 @@ } } - RecursivelyDeleteTriviallyDeadInstructions(DeadInsts); + for (Instruction *I : DeadInsts) { + AssumptionCache *AC = + InfoCache.AG.getAnalysis(*I->getFunction()); + RecursivelyDeleteTriviallyDeadInstructions(I, nullptr, nullptr, AC); + } if (unsigned NumDeadBlocks = ToBeDeletedBlocks.size()) { SmallVector ToBeDeletedBBs; diff --git a/llvm/lib/Transforms/Scalar/InstSimplifyPass.cpp b/llvm/lib/Transforms/Scalar/InstSimplifyPass.cpp --- a/llvm/lib/Transforms/Scalar/InstSimplifyPass.cpp +++ b/llvm/lib/Transforms/Scalar/InstSimplifyPass.cpp @@ -66,7 +66,8 @@ } } } - RecursivelyDeleteTriviallyDeadInstructions(DeadInstsInBB, SQ.TLI); + RecursivelyDeleteTriviallyDeadInstructions(DeadInstsInBB, SQ.TLI, nullptr, + SQ.AC); } // Place the list of instructions to simplify on the next loop iteration diff --git a/llvm/lib/Transforms/Scalar/LoopInstSimplify.cpp b/llvm/lib/Transforms/Scalar/LoopInstSimplify.cpp --- a/llvm/lib/Transforms/Scalar/LoopInstSimplify.cpp +++ b/llvm/lib/Transforms/Scalar/LoopInstSimplify.cpp @@ -152,7 +152,7 @@ // iteration over all instructions in all the loop blocks. if (!DeadInsts.empty()) { Changed = true; - RecursivelyDeleteTriviallyDeadInstructions(DeadInsts, &TLI, MSSAU); + RecursivelyDeleteTriviallyDeadInstructions(DeadInsts, &TLI, MSSAU, &AC); } if (MSSAU && VerifyMemorySSA) diff --git a/llvm/lib/Transforms/Scalar/NaryReassociate.cpp b/llvm/lib/Transforms/Scalar/NaryReassociate.cpp --- a/llvm/lib/Transforms/Scalar/NaryReassociate.cpp +++ b/llvm/lib/Transforms/Scalar/NaryReassociate.cpp @@ -243,7 +243,7 @@ WeakVH NewIExist = NewI; // If SeenExprs/NewIExist contains I's WeakTrackingVH/WeakVH, that // entry will be replaced with nullptr if deleted. - RecursivelyDeleteTriviallyDeadInstructions(&*I, TLI); + RecursivelyDeleteTriviallyDeadInstructions(&*I, TLI, nullptr, AC); if (!NewIExist) { // Rare occation where the new instruction (NewI) have been removed, // probably due to parts of the input code was dead from the diff --git a/llvm/lib/Transforms/Utils/AssumeBundleBuilder.cpp b/llvm/lib/Transforms/Utils/AssumeBundleBuilder.cpp --- a/llvm/lib/Transforms/Utils/AssumeBundleBuilder.cpp +++ b/llvm/lib/Transforms/Utils/AssumeBundleBuilder.cpp @@ -134,8 +134,11 @@ auto addAttrList = [&](AttributeList AttrList) { for (unsigned Idx = AttributeList::FirstArgIndex; Idx < AttrList.getNumAttrSets(); Idx++) - for (Attribute Attr : AttrList.getAttributes(Idx)) + for (Attribute Attr : AttrList.getAttributes(Idx)) { + if (!Call->getArgOperand(Idx - 1)) + continue; addAttribute(Attr, Call->getArgOperand(Idx - 1)); + } for (Attribute Attr : AttrList.getFnAttributes()) addAttribute(Attr, nullptr); }; @@ -198,9 +201,18 @@ addAttr(Attribute::Alignment, Pointer, MA.valueOrOne().value()); } + bool instructionHasNullOperand(Instruction *I) { + for (Value *V : I->operand_values()) + if (!V) + return true; + return false; + } + void addInstruction(Instruction *I) { if (auto *Call = dyn_cast(I)) return addCall(Call); + if (instructionHasNullOperand(I)) + return; if (auto *Load = dyn_cast(I)) return addAccessedPtr(I, Load->getPointerOperand(), Load->getType(), Load->getAlign()); diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp --- a/llvm/lib/Transforms/Utils/Local.cpp +++ b/llvm/lib/Transforms/Utils/Local.cpp @@ -78,6 +78,7 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/ValueMapper.h" +#include "llvm/Transforms/Utils/AssumeBundleBuilder.h" #include #include #include @@ -441,21 +442,22 @@ /// trivially dead, delete them too, recursively. Return true if any /// instructions were deleted. bool llvm::RecursivelyDeleteTriviallyDeadInstructions( - Value *V, const TargetLibraryInfo *TLI, MemorySSAUpdater *MSSAU) { + Value *V, const TargetLibraryInfo *TLI, MemorySSAUpdater *MSSAU, + AssumptionCache *AC) { Instruction *I = dyn_cast(V); if (!I || !isInstructionTriviallyDead(I, TLI)) return false; SmallVector DeadInsts; DeadInsts.push_back(I); - RecursivelyDeleteTriviallyDeadInstructions(DeadInsts, TLI, MSSAU); + RecursivelyDeleteTriviallyDeadInstructions(DeadInsts, TLI, MSSAU, AC); return true; } bool llvm::RecursivelyDeleteTriviallyDeadInstructionsPermissive( SmallVectorImpl &DeadInsts, const TargetLibraryInfo *TLI, - MemorySSAUpdater *MSSAU) { + MemorySSAUpdater *MSSAU, AssumptionCache *AC) { unsigned S = 0, E = DeadInsts.size(), Alive = 0; for (; S != E; ++S) { auto *I = cast(DeadInsts[S]); @@ -466,13 +468,13 @@ } if (Alive == E) return false; - RecursivelyDeleteTriviallyDeadInstructions(DeadInsts, TLI, MSSAU); + RecursivelyDeleteTriviallyDeadInstructions(DeadInsts, TLI, MSSAU, AC); return true; } void llvm::RecursivelyDeleteTriviallyDeadInstructions( SmallVectorImpl &DeadInsts, const TargetLibraryInfo *TLI, - MemorySSAUpdater *MSSAU) { + MemorySSAUpdater *MSSAU, AssumptionCache *AC) { // Process the dead instruction list until empty. while (!DeadInsts.empty()) { Value *V = DeadInsts.pop_back_val(); @@ -485,6 +487,7 @@ // Don't lose the debug info while deleting the instructions. salvageDebugInfo(*I); + salvageKnowledge(I, AC); // Null out all of the instruction's operands to see if any operand becomes // dead as we go. @@ -571,6 +574,7 @@ const TargetLibraryInfo *TLI) { if (isInstructionTriviallyDead(I, TLI)) { salvageDebugInfo(*I); + salvageKnowledge(I); // Null out all of the instruction's operands to see if any operand becomes // dead as we go. diff --git a/llvm/lib/Transforms/Utils/LoopUnroll.cpp b/llvm/lib/Transforms/Utils/LoopUnroll.cpp --- a/llvm/lib/Transforms/Utils/LoopUnroll.cpp +++ b/llvm/lib/Transforms/Utils/LoopUnroll.cpp @@ -215,7 +215,7 @@ while (!DeadInsts.empty()) { Value *V = DeadInsts.pop_back_val(); if (Instruction *Inst = dyn_cast_or_null(V)) - RecursivelyDeleteTriviallyDeadInstructions(Inst); + RecursivelyDeleteTriviallyDeadInstructions(Inst, nullptr, nullptr, AC); } } diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -203,10 +203,23 @@ bool simplifyBranch(BranchInst *Branch, IRBuilder<> &Builder); bool simplifyUncondBranch(BranchInst *BI, IRBuilder<> &Builder); bool simplifyCondBranch(BranchInst *BI, IRBuilder<> &Builder); + bool SimplifyCondBranchToTwoReturns(BranchInst *BI, IRBuilder<> &Builder); bool tryToSimplifyUncondBranchWithICmpInIt(ICmpInst *ICI, IRBuilder<> &Builder); + bool HoistThenElseCodeToIf(BranchInst *BI, const TargetTransformInfo &TTI); + bool SpeculativelyExecuteBB(BranchInst *BI, BasicBlock *ThenBB, + const TargetTransformInfo &TTI); + bool SimplifyTerminatorOnSelect(Instruction *OldTerm, Value *Cond, + BasicBlock *TrueBB, BasicBlock *FalseBB, + uint32_t TrueWeight, uint32_t FalseWeight); + bool SimplifyBranchOnICmpChain(BranchInst *BI, IRBuilder<> &Builder, + const DataLayout &DL); + bool SimplifySwitchOnSelect(SwitchInst *SI, SelectInst *Select); + bool SimplifyIndirectBrOnSelect(IndirectBrInst *IBI, SelectInst *SI); + bool TurnSwitchRangeIntoICmp(SwitchInst *SI, IRBuilder<> &Builder); + public: SimplifyCFGOpt(const TargetTransformInfo &TTI, const DataLayout &DL, SmallPtrSetImpl *LoopHeaders, @@ -679,8 +692,8 @@ } // end anonymous namespace -static void EraseTerminatorAndDCECond(Instruction *TI, - MemorySSAUpdater *MSSAU = nullptr) { +static void EraseTerminatorAndDCECond(Instruction *TI, MemorySSAUpdater *MSSAU, + AssumptionCache *AC) { Instruction *Cond = nullptr; if (SwitchInst *SI = dyn_cast(TI)) { Cond = dyn_cast(SI->getCondition()); @@ -864,7 +877,7 @@ << "Through successor TI: " << *TI << "Leaving: " << *NI << "\n"); - EraseTerminatorAndDCECond(TI); + EraseTerminatorAndDCECond(TI, nullptr, Options.AC); return true; } @@ -929,7 +942,7 @@ << "Through successor TI: " << *TI << "Leaving: " << *NI << "\n"); - EraseTerminatorAndDCECond(TI); + EraseTerminatorAndDCECond(TI, nullptr, Options.AC); return true; } @@ -1190,7 +1203,7 @@ setBranchWeights(NewSI, MDWeights); } - EraseTerminatorAndDCECond(PTI); + EraseTerminatorAndDCECond(PTI, nullptr, Options.AC); // Okay, last check. If BB is still a successor of PSI, then we must // have an infinite loop case. If so, add an infinitely looping block @@ -1236,8 +1249,8 @@ /// Given a conditional branch that goes to BB1 and BB2, hoist any common code /// in the two blocks up into the branch block. The caller of this function /// guarantees that BI's block dominates BB1 and BB2. -static bool HoistThenElseCodeToIf(BranchInst *BI, - const TargetTransformInfo &TTI) { +bool SimplifyCFGOpt::HoistThenElseCodeToIf(BranchInst *BI, + const TargetTransformInfo &TTI) { // This does very trivial matching, with limited scanning, to find identical // instructions in the two blocks. In particular, we don't want to get into // O(M*N) situations here where M and N are the sizes of BB1 and BB2. As @@ -1427,7 +1440,7 @@ for (BasicBlock *Succ : successors(BB1)) AddPredecessorToBlock(Succ, BIParent, BB1); - EraseTerminatorAndDCECond(BI); + EraseTerminatorAndDCECond(BI, nullptr, Options.AC); return true; } @@ -1970,8 +1983,8 @@ /// \endcode /// /// \returns true if the conditional block is removed. -static bool SpeculativelyExecuteBB(BranchInst *BI, BasicBlock *ThenBB, - const TargetTransformInfo &TTI) { +bool SimplifyCFGOpt::SpeculativelyExecuteBB(BranchInst *BI, BasicBlock *ThenBB, + const TargetTransformInfo &TTI) { // Be conservative for now. FP select instruction can often be expensive. Value *BrCond = BI->getCondition(); if (isa(BrCond)) @@ -2463,8 +2476,8 @@ /// If we found a conditional branch that goes to two returning blocks, /// try to merge them together into one return, /// introducing a select if the return values disagree. -static bool SimplifyCondBranchToTwoReturns(BranchInst *BI, - IRBuilder<> &Builder) { +bool SimplifyCFGOpt::SimplifyCondBranchToTwoReturns(BranchInst *BI, + IRBuilder<> &Builder) { assert(BI->isConditional() && "Must be a conditional branch"); BasicBlock *TrueSucc = BI->getSuccessor(0); BasicBlock *FalseSucc = BI->getSuccessor(1); @@ -2487,7 +2500,7 @@ TrueSucc->removePredecessor(BI->getParent()); FalseSucc->removePredecessor(BI->getParent()); Builder.CreateRetVoid(); - EraseTerminatorAndDCECond(BI); + EraseTerminatorAndDCECond(BI, nullptr, Options.AC); return true; } @@ -2543,7 +2556,7 @@ << "\n " << *BI << "\nNewRet = " << *RI << "\nTRUEBLOCK: " << *TrueSucc << "\nFALSEBLOCK: " << *FalseSucc); - EraseTerminatorAndDCECond(BI); + EraseTerminatorAndDCECond(BI, nullptr, Options.AC); return true; } @@ -2592,7 +2605,8 @@ /// and one of our successors, fold the block into the predecessor and use /// logical operations to pick the right destination. bool llvm::FoldBranchToCommonDest(BranchInst *BI, MemorySSAUpdater *MSSAU, - unsigned BonusInstThreshold) { + unsigned BonusInstThreshold, + AssumptionCache *AC) { BasicBlock *BB = BI->getParent(); const unsigned PredCount = pred_size(BB); @@ -2873,7 +2887,7 @@ // Change PBI from Conditional to Unconditional. BranchInst *New_PBI = BranchInst::Create(TrueDest, PBI); - EraseTerminatorAndDCECond(PBI, MSSAU); + EraseTerminatorAndDCECond(PBI, MSSAU, AC); PBI = New_PBI; } @@ -3057,8 +3071,8 @@ // If QTB does not exist, then QFB's only predecessor has a conditional // branch to QFB and PostBB. BasicBlock *TruePred = QTB ? QTB : QFB->getSinglePredecessor(); - BasicBlock *NewBB = SplitBlockPredecessors(PostBB, { QFB, TruePred}, - "condstore.split"); + BasicBlock *NewBB = + SplitBlockPredecessors(PostBB, {QFB, TruePred}, "condstore.split"); if (!NewBB) return false; PostBB = NewBB; @@ -3523,10 +3537,11 @@ // Takes care of updating the successors and removing the old terminator. // Also makes sure not to introduce new successors by assuming that edges to // non-successor TrueBBs and FalseBBs aren't reachable. -static bool SimplifyTerminatorOnSelect(Instruction *OldTerm, Value *Cond, - BasicBlock *TrueBB, BasicBlock *FalseBB, - uint32_t TrueWeight, - uint32_t FalseWeight) { +bool SimplifyCFGOpt::SimplifyTerminatorOnSelect(Instruction *OldTerm, + Value *Cond, BasicBlock *TrueBB, + BasicBlock *FalseBB, + uint32_t TrueWeight, + uint32_t FalseWeight) { // Remove any superfluous successor edges from the CFG. // First, figure out which successors to preserve. // If TrueBB and FalseBB are equal, only try to preserve one copy of that @@ -3578,7 +3593,7 @@ Builder.CreateBr(FalseBB); } - EraseTerminatorAndDCECond(OldTerm); + EraseTerminatorAndDCECond(OldTerm, nullptr, Options.AC); return true; } @@ -3586,7 +3601,8 @@ // (switch (select cond, X, Y)) on constant X, Y // with a branch - conditional if X and Y lead to distinct BBs, // unconditional otherwise. -static bool SimplifySwitchOnSelect(SwitchInst *SI, SelectInst *Select) { +bool SimplifyCFGOpt::SimplifySwitchOnSelect(SwitchInst *SI, + SelectInst *Select) { // Check for constant integer values in the select. ConstantInt *TrueVal = dyn_cast(Select->getTrueValue()); ConstantInt *FalseVal = dyn_cast(Select->getFalseValue()); @@ -3622,7 +3638,8 @@ // blockaddress(@fn, BlockB))) // with // (br cond, BlockA, BlockB). -static bool SimplifyIndirectBrOnSelect(IndirectBrInst *IBI, SelectInst *SI) { +bool SimplifyCFGOpt::SimplifyIndirectBrOnSelect(IndirectBrInst *IBI, + SelectInst *SI) { // Check that both operands of the select are block addresses. BlockAddress *TBA = dyn_cast(SI->getTrueValue()); BlockAddress *FBA = dyn_cast(SI->getFalseValue()); @@ -3757,8 +3774,9 @@ /// The specified branch is a conditional branch. /// Check to see if it is branching on an or/and chain of icmp instructions, and /// fold it into a switch instruction if so. -static bool SimplifyBranchOnICmpChain(BranchInst *BI, IRBuilder<> &Builder, - const DataLayout &DL) { +bool SimplifyCFGOpt::SimplifyBranchOnICmpChain(BranchInst *BI, + IRBuilder<> &Builder, + const DataLayout &DL) { Instruction *Cond = dyn_cast(BI->getCondition()); if (!Cond) return false; @@ -3866,7 +3884,7 @@ } // Erase the old branch instruction. - EraseTerminatorAndDCECond(BI); + EraseTerminatorAndDCECond(BI, nullptr, Options.AC); LLVM_DEBUG(dbgs() << " ** 'icmp' chain result is:\n" << *BB << '\n'); return true; @@ -4307,7 +4325,7 @@ Builder.CreateAssumption(Cond); Builder.CreateBr(BI->getSuccessor(0)); } - EraseTerminatorAndDCECond(BI); + EraseTerminatorAndDCECond(BI, nullptr, Options.AC); Changed = true; } } else if (auto *SI = dyn_cast(TI)) { @@ -4390,7 +4408,7 @@ return true; } -static void createUnreachableSwitchDefault(SwitchInst *Switch) { +void createUnreachableSwitchDefault(SwitchInst *Switch, AssumptionCache *AC) { LLVM_DEBUG(dbgs() << "SimplifyCFG: switch default is dead.\n"); BasicBlock *NewDefaultBlock = SplitBlockPredecessors(Switch->getDefaultDest(), Switch->getParent(), ""); @@ -4398,12 +4416,13 @@ SplitBlock(&*NewDefaultBlock, &NewDefaultBlock->front()); auto *NewTerminator = NewDefaultBlock->getTerminator(); new UnreachableInst(Switch->getContext(), NewTerminator); - EraseTerminatorAndDCECond(NewTerminator); + EraseTerminatorAndDCECond(NewTerminator, nullptr, AC); } /// Turn a switch with two reachable destinations into an integer range /// comparison and branch. -static bool TurnSwitchRangeIntoICmp(SwitchInst *SI, IRBuilder<> &Builder) { +bool SimplifyCFGOpt::TurnSwitchRangeIntoICmp(SwitchInst *SI, + IRBuilder<> &Builder) { assert(SI->getNumCases() > 1 && "Degenerate switch?"); bool HasDefault = @@ -4512,7 +4531,7 @@ // Clean up the default block - it may have phis or other instructions before // the unreachable terminator. if (!HasDefault) - createUnreachableSwitchDefault(SI); + createUnreachableSwitchDefault(SI, Options.AC); // Drop the switch. SI->eraseFromParent(); @@ -4558,7 +4577,7 @@ if (HasDefault && DeadCases.empty() && NumUnknownBits < 64 /* avoid overflow */ && SI->getNumCases() == (1ULL << NumUnknownBits)) { - createUnreachableSwitchDefault(SI); + createUnreachableSwitchDefault(SI, AC); return true; } @@ -5770,14 +5789,14 @@ if (IBI->getNumDestinations() == 0) { // If the indirectbr has no successors, change it to unreachable. new UnreachableInst(IBI->getContext(), IBI); - EraseTerminatorAndDCECond(IBI); + EraseTerminatorAndDCECond(IBI, nullptr, Options.AC); return true; } if (IBI->getNumDestinations() == 1) { // If the indirectbr has one successor, change it to a direct branch. BranchInst::Create(IBI->getDestination(0), IBI); - EraseTerminatorAndDCECond(IBI); + EraseTerminatorAndDCECond(IBI, nullptr, Options.AC); return true; } @@ -5915,7 +5934,8 @@ // branches to us and our successor, fold the comparison into the // predecessor and use logical operations to update the incoming value // for PHI nodes in common successor. - if (FoldBranchToCommonDest(BI, nullptr, Options.BonusInstThreshold)) + if (FoldBranchToCommonDest(BI, nullptr, Options.BonusInstThreshold, + Options.AC)) return requestResimplify(); return false; } @@ -5972,14 +5992,16 @@ ConstantInt *TorF = *Imp ? ConstantInt::getTrue(BB->getContext()) : ConstantInt::getFalse(BB->getContext()); BI->setCondition(TorF); - RecursivelyDeleteTriviallyDeadInstructions(OldCond); + RecursivelyDeleteTriviallyDeadInstructions(OldCond, nullptr, nullptr, + Options.AC); return requestResimplify(); } // If this basic block is ONLY a compare and a branch, and if a predecessor // branches to us and one of our successors, fold the comparison into the // predecessor and use logical operations to pick the right destination. - if (FoldBranchToCommonDest(BI, nullptr, Options.BonusInstThreshold)) + if (FoldBranchToCommonDest(BI, nullptr, Options.BonusInstThreshold, + Options.AC)) return requestResimplify(); // We have a conditional branch to two blocks that are only reachable diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/byval-2.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/byval-2.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/byval-2.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/byval-2.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes -; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=3 < %s | FileCheck %s +; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=3 < %s | FileCheck %s --check-prefixes=CHECK,NO_ASSUME +; RUN: opt -S -passes=attributor --enable-knowledge-retention -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=3 < %s | FileCheck %s --check-prefixes=CHECK,USE_ASSUME %struct.ss = type { i32, i64 } @@ -15,15 +16,26 @@ } define i32 @test(i32* %X) { -; CHECK-LABEL: define {{[^@]+}}@test -; CHECK-SAME: (i32* nocapture nofree readonly align 4 [[X:%.*]]) -; CHECK-NEXT: entry: -; CHECK-NEXT: [[S:%.*]] = alloca [[STRUCT_SS:%.*]] -; CHECK-NEXT: [[TMP1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 0 -; CHECK-NEXT: store i32 1, i32* [[TMP1]], align 8 -; CHECK-NEXT: [[TMP4:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1 -; CHECK-NEXT: store i64 2, i64* [[TMP4]], align 4 -; CHECK-NEXT: ret i32 0 +; NO_ASSUME-LABEL: define {{[^@]+}}@test +; NO_ASSUME-SAME: (i32* nocapture nofree readonly align 4 [[X:%.*]]) +; NO_ASSUME-NEXT: entry: +; NO_ASSUME-NEXT: [[S:%.*]] = alloca [[STRUCT_SS:%.*]] +; NO_ASSUME-NEXT: [[TMP1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 0 +; NO_ASSUME-NEXT: store i32 1, i32* [[TMP1]], align 8 +; NO_ASSUME-NEXT: [[TMP4:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1 +; NO_ASSUME-NEXT: store i64 2, i64* [[TMP4]], align 4 +; NO_ASSUME-NEXT: ret i32 0 +; +; USE_ASSUME-LABEL: define {{[^@]+}}@test +; USE_ASSUME-SAME: (i32* nocapture nofree readonly align 4 [[X:%.*]]) +; USE_ASSUME-NEXT: entry: +; USE_ASSUME-NEXT: [[S:%.*]] = alloca [[STRUCT_SS:%.*]] +; USE_ASSUME-NEXT: [[TMP1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 0 +; USE_ASSUME-NEXT: store i32 1, i32* [[TMP1]], align 8 +; USE_ASSUME-NEXT: [[TMP4:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1 +; USE_ASSUME-NEXT: store i64 2, i64* [[TMP4]], align 4 +; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "align"(i32* [[X]], i64 4), "align"(%struct.ss* [[S]], i64 8), "dereferenceable"(i32* [[X]], i64 4), "dereferenceable"(%struct.ss* [[S]], i64 12), "nonnull"(%struct.ss* [[S]]), "nonnull"(i32* [[X]]) ] +; USE_ASSUME-NEXT: ret i32 0 ; entry: %S = alloca %struct.ss diff --git a/llvm/test/Transforms/InstSimplify/load.ll b/llvm/test/Transforms/InstSimplify/load.ll --- a/llvm/test/Transforms/InstSimplify/load.ll +++ b/llvm/test/Transforms/InstSimplify/load.ll @@ -1,20 +1,29 @@ -; NOTE: Assertions have been autogenerated by update_test_checks.py -; RUN: opt < %s -instsimplify -S | FileCheck %s +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s --check-prefixes=CHECK,NO_ASSUME +; RUN: opt < %s -instsimplify --enable-knowledge-retention -S | FileCheck %s --check-prefixes=CHECK,USE_ASSUME @zeroinit = constant {} zeroinitializer @undef = constant {} undef define i32 @crash_on_zeroinit() { -; CHECK-LABEL: @crash_on_zeroinit( -; CHECK: ret i32 0 +; NO_ASSUME-LABEL: @crash_on_zeroinit( +; NO_ASSUME-NEXT: ret i32 0 +; +; USE_ASSUME-LABEL: @crash_on_zeroinit( +; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* bitcast ({}* @zeroinit to i32*), i64 4), "nonnull"(i32* bitcast ({}* @zeroinit to i32*)) ] +; USE_ASSUME-NEXT: ret i32 0 ; %load = load i32, i32* bitcast ({}* @zeroinit to i32*) ret i32 %load } define i32 @crash_on_undef() { -; CHECK-LABEL: @crash_on_undef( -; CHECK: ret i32 undef +; NO_ASSUME-LABEL: @crash_on_undef( +; NO_ASSUME-NEXT: ret i32 undef +; +; USE_ASSUME-LABEL: @crash_on_undef( +; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* bitcast ({}* @undef to i32*), i64 4), "nonnull"(i32* bitcast ({}* @undef to i32*)) ] +; USE_ASSUME-NEXT: ret i32 undef ; %load = load i32, i32* bitcast ({}* @undef to i32*) ret i32 %load @@ -23,8 +32,13 @@ @GV = private constant [8 x i32] [i32 42, i32 43, i32 44, i32 45, i32 46, i32 47, i32 48, i32 49] define <8 x i32> @partial_load() { -; CHECK-LABEL: @partial_load( -; CHECK: ret <8 x i32> +; NO_ASSUME-LABEL: @partial_load( +; NO_ASSUME-NEXT: ret <8 x i32> +; +; USE_ASSUME-LABEL: @partial_load( +; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(<8 x i32>* bitcast (i32* getelementptr ([8 x i32], [8 x i32]* @GV, i64 0, i64 -1) to <8 x i32>*), i64 32), "nonnull"(<8 x i32>* bitcast (i32* getelementptr ([8 x i32], [8 x i32]* @GV, i64 0, i64 -1) to <8 x i32>*)) ] +; USE_ASSUME-NEXT: ret <8 x i32> +; %load = load <8 x i32>, <8 x i32>* bitcast (i32* getelementptr ([8 x i32], [8 x i32]* @GV, i64 0, i64 -1) to <8 x i32>*) ret <8 x i32> %load } @@ -33,8 +47,13 @@ ; This does an out of bounds load from the global constant define <3 x float> @load_vec3() { -; CHECK-LABEL: @load_vec3( -; CHECK-NEXT: ret <3 x float> undef +; NO_ASSUME-LABEL: @load_vec3( +; NO_ASSUME-NEXT: ret <3 x float> undef +; +; USE_ASSUME-LABEL: @load_vec3( +; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(<3 x float>* getelementptr inbounds (<3 x float>, <3 x float>* @constvec, i64 1), i64 12), "nonnull"(<3 x float>* getelementptr inbounds (<3 x float>, <3 x float>* @constvec, i64 1)) ] +; USE_ASSUME-NEXT: ret <3 x float> undef +; %1 = load <3 x float>, <3 x float>* getelementptr inbounds (<3 x float>, <3 x float>* @constvec, i64 1) ret <3 x float> %1 } diff --git a/llvm/unittests/Transforms/Utils/LocalTest.cpp b/llvm/unittests/Transforms/Utils/LocalTest.cpp --- a/llvm/unittests/Transforms/Utils/LocalTest.cpp +++ b/llvm/unittests/Transforms/Utils/LocalTest.cpp @@ -25,12 +25,18 @@ TEST(Local, RecursivelyDeleteDeadPHINodes) { LLVMContext C; + auto M = std::make_unique("test", C); IRBuilder<> builder(C); + Function *F = Function::Create(FunctionType::get(Type::getVoidTy(C), false), + GlobalValue::ExternalLinkage, "", &*M); + // Make blocks BasicBlock *bb0 = BasicBlock::Create(C); BasicBlock *bb1 = BasicBlock::Create(C); + bb0->insertInto(F); + bb1->insertInto(F); builder.SetInsertPoint(bb0); PHINode *phi = builder.CreatePHI(Type::getInt32Ty(C), 2); @@ -59,11 +65,6 @@ builder.CreateAdd(phi, phi); EXPECT_TRUE(RecursivelyDeleteDeadPHINode(phi)); - - bb0->dropAllReferences(); - bb1->dropAllReferences(); - delete bb0; - delete bb1; } TEST(Local, RemoveDuplicatePHINodes) {