Index: llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp =================================================================== --- llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp +++ llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp @@ -17,6 +17,7 @@ #include "llvm/Transforms/Scalar/DeadStoreElimination.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/PostOrderIterator.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" @@ -28,7 +29,10 @@ #include "llvm/Analysis/MemoryBuiltins.h" #include "llvm/Analysis/MemoryDependenceAnalysis.h" #include "llvm/Analysis/MemoryLocation.h" +#include "llvm/Analysis/MemorySSA.h" +#include "llvm/Analysis/MemorySSAUpdater.h" #include "llvm/Analysis/OrderedBasicBlock.h" +#include "llvm/Analysis/PostDominators.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/Argument.h" @@ -86,6 +90,15 @@ cl::init(true), cl::Hidden, cl::desc("Enable partial store merging in DSE")); +static cl::opt + EnableMemorySSA("enable-dse-memoryssa", cl::init(false), cl::Hidden, + cl::desc("Use the new MemorySSA-backed DSE.")); + +static cl::opt + MaxDSEIteration("dse-max-iteration", cl::init(24), cl::Hidden, + cl::desc("Maximum number of iteration for graph traversal " + "operation inside MemorySSA-backed DSE")); + //===----------------------------------------------------------------------===// // Helper functions //===----------------------------------------------------------------------===// @@ -1324,22 +1337,542 @@ return MadeChange; } +namespace { + +bool isIncomplete(MemoryLocation Loc) { return !Loc.Ptr; } + +/// Check if I is a volatile operation. +/// FIXME: Maybe this should be moved to Value. +bool isVolatile(Instruction *I) { + if (auto *SI = dyn_cast(I)) + return SI->isVolatile(); + if (auto *LI = dyn_cast(I)) + return LI->isVolatile(); + if (auto *MemOp = dyn_cast(I)) + return MemOp->isVolatile(); + return false; +} + +struct DSEContext { + Function &F; + AliasAnalysis &AA; + MemorySSA &MSSA; + DominatorTree &DT; + PostDominatorTree &PDT; + const TargetLibraryInfo &TLI; + bool MadeChange = false; + + /// Index associated of an instruction. it can be used to know the ordering of + /// instruction in a basic block. indexes are in reverse order. + using InstIndex = unsigned; + + /// All instruction instruction that can act as an optimization barrier. + /// eg: throw, fence, atomics ... + /// Those barrier are used to not prevent transformation removal of a store + /// being overriden by another store when an optimization barrier + /// could be executed between the two stores. + /// They are not garanted to prevent optimization based on a non-escaping + /// pointer not being used. + SmallVector OptBarrierInst; + + /// StoreInst or memory intrinsics that writes to memory. mapped to there + /// index in there basic block. + SmallDenseMap InstructionIndex; + + enum DSECandidateFlags : unsigned { + DCF_NormalStore = 0, + DCF_LifetimeEndLike = 1, + }; + + using DSECandidate = PointerIntPair; + + SmallVector DSECandidates; + + /// Set of pointer we know to be non-escaping. + /// non-escaping mean that at the end of the function the value store at there + /// address is not observable. + SmallSet NonEscapingPtr; + + /// state we need to keep track of for every BasicBlock. + struct BBState { + /// Instruction index of the first/last instruction in the basic block that + /// is an optimization barrier. + unsigned FirstBarrierIdx; + unsigned LastBarrierIdx; + + /// Its the PostOrder index of the BasicBlock. it is used to detect + /// backedges. + InstIndex BlockPostOrder; + }; + + /// Map of BasicBlocks to there state. [First, Last[ OptBarrierInst. + SmallDenseMap BBStateMap; + + /// isOveride needs this, but it is currently unused. + InstOverlapIntervalsTy IOL; + + DSEContext(Function &F, AliasAnalysis &AA, MemorySSA &MSSA, DominatorTree &DT, + PostDominatorTree &PDT, const TargetLibraryInfo &TLI) + : F(F), AA(AA), MSSA(MSSA), DT(DT), PDT(PDT), TLI(TLI) {} + bool run(); + void deleteDeadInstruction(Instruction *I); + + MemoryLocation getWriteLoc(Instruction *I) { + assert(I->mayWriteToMemory()); + return getLocForWrite(I); + } + + MemoryLocation getReadLoc(Instruction *I) { + assert(I->mayReadFromMemory() && !isEndLifetimeLike(I)); + if (auto *LI = dyn_cast(I)) + return MemoryLocation::get(LI); + // TODO: extend the definition. to handle libray functions and builtins. + return MemoryLocation(); + } + + enum BarrierPlacement { BP_Before, BP_After }; + + /// check if there is any Instruction form the OptBarrierInst + /// before or after in the current BasicBlock. + template bool hasOptBarrier(Instruction *I) { + BBState &BBS = BBStateMap[I->getParent()]; + if (BBS.FirstBarrierIdx == BBS.LastBarrierIdx) + return false; + if (BP == BP_Before) + return InstructionIndex[I] < OptBarrierInst[BBS.FirstBarrierIdx]; + assert(BP == BP_After); + return InstructionIndex[I] > OptBarrierInst[BBS.LastBarrierIdx - 1]; + } + + bool mayRead(Instruction *I) { + return I->mayReadFromMemory() && !isEndLifetimeLike(I); + } + + bool isFullOverrite(const MemoryLocation &Loc, Instruction *I) { + assert(mustWriteToMemory(I)); + MemoryLocation OtherLoc = getWriteLoc(I); + int64_t DeadOffset, KillerOffset; + OverwriteResult OR = + isOverwriteWrapper(OtherLoc, Loc, KillerOffset, DeadOffset, I); + return OR == OW_Complete; + } + + static Instruction *getMemInst(const MemoryAccess *MA) { + if (!MA) + return nullptr; + if (auto *UOD = dyn_cast(MA)) + return UOD->getMemoryInst(); + return nullptr; + } + + OverwriteResult isOverwriteWrapper(const MemoryLocation &Later, + const MemoryLocation &Earlier, + int64_t &LaterOff, int64_t &EarlierOff, + Instruction *LaterWrite) { + if (isEndLifetimeLike(LaterWrite)) { + if (GetUnderlyingObject(Earlier.Ptr, F.getParent()->getDataLayout()) == + GetUnderlyingObject(Later.Ptr, F.getParent()->getDataLayout())) + return OW_Complete; + return OW_Unknown; + } + return isOverwrite(Later, Earlier, F.getParent()->getDataLayout(), TLI, + EarlierOff, LaterOff, LaterWrite, IOL, AA, &F); + } + + enum TrySimplifyResult { + TSR_Nothing, /// No changes were made. + TSR_HasClobber, /// There is a clobber between the sotres. + TSR_RemovedFirst, /// The first store has been removed. + TSR_RemovedSecond, /// The second other has been removed. + }; + + bool mustWriteToMemory(Instruction *I) { + if (!I->mayWriteToMemory()) + return false; + if (auto *Intr = dyn_cast(I)) { + switch (Intr->getIntrinsicID()) { + case Intrinsic::memcpy: + case Intrinsic::memset: + case Intrinsic::memmove: + case Intrinsic::memcpy_element_unordered_atomic: + case Intrinsic::memset_element_unordered_atomic: + case Intrinsic::memmove_element_unordered_atomic: + /// This is not strictly a write but treating it as such does exactly + /// what we want. + case Intrinsic::lifetime_end: + return true; + default: + return false; + } + } + /// For calls we don't know if they actually write to memory just if they + /// can. + if (isa(I) && !isEndLifetimeLike(I)) + return false; + return true; + } + + bool hasLoadUsersInFunction( + MemoryAccess *Start, const MemoryLocation &FirstLoc, + SmallDenseMap &LastAccessOfPath, + bool isNonEscapingPtr) { + SmallSet Visited; + SmallVector WL; + unsigned Iterations = 0; + Visited.insert(Start); + WL.append(Start->user_begin(), Start->user_end()); + + while (!WL.empty()) { + if (WL.size() + Iterations++ >= MaxDSEIteration) + return true; + MemoryAccess *MA = cast_or_null(WL.pop_back_val()); + if (Visited.find(MA) != Visited.end()) + return true; + if (!MA) + continue; + Visited.insert(MA); + if (Instruction *Access = getMemInst(MA)) { + if (mayRead(Access)) { + MemoryLocation Loc = getReadLoc(Access); + if (isIncomplete(Loc) || !AA.isNoAlias(Loc, FirstLoc)) + return true; + } + if (mustWriteToMemory(Access) && isFullOverrite(FirstLoc, Access)) { + LastAccessOfPath[MA->getBlock()] = MA; + continue; + } + } + + if (MA->user_empty() && isNonEscapingPtr) { + LastAccessOfPath[MA->getBlock()] = MA; + } + + WL.append(MA->user_begin(), MA->user_end()); + } + return false; + } + + bool hasOptBarrierInReachableBB( + SmallDenseMap &LastAccessOfPath, + Instruction *First, bool isNonEscapingPtr) { + // TODO: When a path from the non-escaping pointer reaches the end of the + // function. we do not need to check for optimization barrier because they + // will not skip any overriding instruction as there is none in this case. + // Currently we don't check optimization barriers only for the last + // BasicBlock still check all prior basic block in the path. + + if (isNonEscapingPtr && LastAccessOfPath.empty()) + return false; + + /// Special case for overrite in the same block in the right order. + /// If instruction are in the reverse order we trying to remove stores in a + /// loop so we need to check all reachble basic blocks. + auto SameBBIterator = LastAccessOfPath.find(First->getParent()); + if (SameBBIterator != LastAccessOfPath.end()) { + + if (isNonEscapingPtr && SameBBIterator->second->user_empty()) + return false; + + unsigned FirstIdx = InstructionIndex[First]; + unsigned LastIdx = InstructionIndex[getMemInst(SameBBIterator->second)]; + if (FirstIdx > LastIdx) { + BBState &BBS = BBStateMap[First->getParent()]; + if ((isNonEscapingPtr && SameBBIterator->second->user_empty()) || + BBS.FirstBarrierIdx == BBS.LastBarrierIdx) + return false; + + for (unsigned Idx = BBS.FirstBarrierIdx; Idx < BBS.LastBarrierIdx; + Idx++) + if (OptBarrierInst[Idx] > FirstIdx && OptBarrierInst[Idx] < LastIdx) + return true; + return false; + } + } + + /// We know that the elimination doesn't occur in the same block or the if + /// above would have been taken. + if (!isNonEscapingPtr && succ_empty(First->getParent())) { + assert(LastAccessOfPath.empty()); + return true; + } + + if (hasOptBarrier(First)) + return true; + + SmallSet VisitedBB; + SmallVector WL; + + /// BasicBlock this set of BasicBlock postdominate the BasicBlock of First + /// and a LastAccessOfPath. It is used to reduce the search + /// space of the folowing DFS algorithm. When this block is reached it can + /// be treated as a end of function. + SmallSet EndOfSearchSpace; + unsigned Iterations = 0; + + /// TODO: Enable this for functions with many BasicBlocks only. + for (auto Elem : LastAccessOfPath) { + BasicBlock *PostDom = + PDT.findNearestCommonDominator(Elem.first, First->getParent()); + if (PostDom && PostDom != Elem.first) + EndOfSearchSpace.insert(PostDom); + } + + WL.append(succ_begin(First->getParent()), succ_end(First->getParent())); + + while (!WL.empty()) { + if (WL.size() + Iterations++ >= MaxDSEIteration) + return true; + BasicBlock *N = WL.pop_back_val(); + assert(N); + + if (VisitedBB.find(N) != VisitedBB.end()) + continue; + VisitedBB.insert(N); + + auto LookupResult = LastAccessOfPath.find(N); + if (LookupResult != LastAccessOfPath.end()) { + if (isNonEscapingPtr && LookupResult->second->user_empty()) + continue; + if (hasOptBarrier(getMemInst(LookupResult->second))) + return true; + continue; + } + + if (succ_empty(N) || EndOfSearchSpace.find(N) != EndOfSearchSpace.end()) { + /// We have reached an exit of the function or equivalent. if the + /// pointer can escape the function it is observable. + if (isNonEscapingPtr) + continue; + else + return true; + } + + /// If we are here this block is entirely traversed. + BBState &BBS = BBStateMap[N]; + if (BBS.FirstBarrierIdx != BBS.LastBarrierIdx) + return true; + + WL.append(succ_begin(N), succ_end(N)); + } + + return false; + } + + bool isEndLifetimeLike(Instruction *I) { + if (auto *Intrinsic = dyn_cast(I)) { + return Intrinsic->getIntrinsicID() == Intrinsic::lifetime_end; + } + if (auto *Call = dyn_cast(I)) { + if (isFreeCall(I, &TLI)) + return true; + } + return false; + } + + DSECandidate getDSECandidate(Instruction *I) { + if (isVolatile(I) || I->isAtomic()) + return {nullptr, DCF_NormalStore}; + if (auto *SI = dyn_cast(I)) + return {I, DCF_NormalStore}; + if (isEndLifetimeLike(I)) + return {I, DCF_LifetimeEndLike}; + /// TODO : make DSE remove handle calls too. + return {nullptr, DCF_NormalStore}; + } + + bool isOptBarrier(Instruction *I) { + if (isEndLifetimeLike(I)) + return false; + return I->mayThrow() || I->isAtomic(); + } +}; + +void DSEContext::deleteDeadInstruction(Instruction *I) { + MadeChange = true; + SmallVector NowDeadInsts; + MemorySSAUpdater MSSAUpdater(&MSSA); + + NowDeadInsts.push_back(I); + --NumFastOther; + InstructionIndex.erase(I); + + do { + Instruction *DeadInst = NowDeadInsts.pop_back_val(); + ++NumFastOther; + + // Try to preserve debug information attached to the dead instruction. + salvageDebugInfo(*DeadInst); + + // This instruction is dead, zap it, in stages. Start by removing it from + // MemDep, which needs to know the operands and needs it to be in the + // function. + MSSAUpdater.removeMemoryAccess(DeadInst); + + for (unsigned op = 0, e = DeadInst->getNumOperands(); op != e; ++op) { + Value *Op = DeadInst->getOperand(op); + DeadInst->setOperand(op, nullptr); + + // If this operand just became dead, add it to the NowDeadInsts list. + if (!Op->use_empty()) + continue; + + if (Instruction *OpI = dyn_cast(Op)) + if (isInstructionTriviallyDead(OpI, &TLI)) + NowDeadInsts.push_back(OpI); + } + + DeadInst->eraseFromParent(); + } while (!NowDeadInsts.empty()); +} + +// Expand the set of pointer having the non-escaping property. +static void PropagateNonEscaping(SmallSet &NonEscapingPtr) { + SmallVector WL; + WL.append(NonEscapingPtr.begin(), NonEscapingPtr.end()); + // TODO: Detect whether value in MaybeNonEscaping are actually non escaping. + + while (!WL.empty()) { + const Value *V = WL.pop_back_val(); + NonEscapingPtr.insert(V); + assert(V->getType()->isPointerTy()); + for (const User *U : V->users()) { + if (auto *I = dyn_cast(U)) { + switch (I->getOpcode()) { + case Instruction::GetElementPtr: + case Instruction::BitCast: + WL.push_back(I); + break; + case Instruction::PHI: { + for (const Value *Op : I->operand_values()) { + assert(Op->getType()->isPointerTy()); + if (NonEscapingPtr.find(Op) == NonEscapingPtr.end()) + goto next_user; + } + WL.push_back(I); + break; + } + default: + if (auto *Call = dyn_cast(I)) + if (V == Call->getReturnedArgOperand()) { + WL.push_back(I); + break; + } + /// TODO: there is propably many other ways to propagate down the + /// use chain. + break; + } + } + next_user: + continue; + } + } +} + +bool DSEContext::run() { + InstIndex FuncIdx = 0; + + /// Build the various data structures that are needed for DSE. + for (BasicBlock *BB : post_order(&F)) { + unsigned BBStartOptBarrier = OptBarrierInst.size(); + if (DT.isReachableFromEntry(BB)) + for (Instruction &I : reverse(*BB)) { + + /// We can know they are non-escaping. + if (isa(&I)) + NonEscapingPtr.insert(&I); + + if (isOptBarrier(&I)) + OptBarrierInst.push_back(FuncIdx); + if (I.mayReadOrWriteMemory()) + InstructionIndex.insert(std::make_pair(&I, FuncIdx)); + + DSECandidate Cand = getDSECandidate(&I); + if (Cand.getPointer()) + DSECandidates.push_back(Cand); + FuncIdx++; + } + + BBState &State = BBStateMap[BB]; + State.FirstBarrierIdx = BBStartOptBarrier; + State.LastBarrierIdx = OptBarrierInst.size(); + State.BlockPostOrder = FuncIdx++; + } + + for (Argument &Arg : F.args()) + if (Arg.hasByValOrInAllocaAttr()) + NonEscapingPtr.insert(&Arg); + PropagateNonEscaping(NonEscapingPtr); + + /// Map containing the Last Access of each + SmallDenseMap LastAccessOfPath; + + /// Element are pushed in the DSECandidate in post order so looking at the in + /// reverse order gives better results because of the max traversal depth + /// limit. + for (DSECandidate Cand : reverse(DSECandidates)) { + + /// Check if the instruction hasn't already been deleted. + if (InstructionIndex.find(Cand.getPointer()) == InstructionIndex.end()) + continue; + MemoryLocation CandLoc = getWriteLoc(Cand.getPointer()); + + /// Check if we may have enough information the optimize the store. + if (isIncomplete(CandLoc)) + continue; + + MemoryAccess *MA = MSSA.getMemoryAccess(Cand.getPointer()); + + if (Cand.getInt() & DCF_LifetimeEndLike) { + // traverseMemSSA(MA, Cand.getPointer(), CandLoc, 6); + continue; + } + + bool isNonEscapingPtr = + NonEscapingPtr.find(CandLoc.Ptr) != NonEscapingPtr.end(); + + LastAccessOfPath.clear(); + if (!hasLoadUsersInFunction(MA, CandLoc, LastAccessOfPath, + isNonEscapingPtr) && + !hasOptBarrierInReachableBB(LastAccessOfPath, Cand.getPointer(), + isNonEscapingPtr)) { + NumFastStores++; + deleteDeadInstruction(Cand.getPointer()); + } + continue; + } + return MadeChange; +} + +} // namespace + //===----------------------------------------------------------------------===// // DSE Pass //===----------------------------------------------------------------------===// PreservedAnalyses DSEPass::run(Function &F, FunctionAnalysisManager &AM) { - AliasAnalysis *AA = &AM.getResult(F); - DominatorTree *DT = &AM.getResult(F); - MemoryDependenceResults *MD = &AM.getResult(F); - const TargetLibraryInfo *TLI = &AM.getResult(F); + AliasAnalysis &AA = AM.getResult(F); + const TargetLibraryInfo &TLI = AM.getResult(F); + DominatorTree &DT = AM.getResult(F); - if (!eliminateDeadStores(F, AA, MD, DT, TLI)) - return PreservedAnalyses::all(); + if (EnableMemorySSA) { + MemorySSA &MSSA = AM.getResult(F).getMSSA(); + PostDominatorTree &PDT = AM.getResult(F); + + if (!std::make_unique(F, AA, MSSA, DT, PDT, TLI)->run()) + return PreservedAnalyses::all(); + } else { + MemoryDependenceResults &MD = AM.getResult(F); + + if (!eliminateDeadStores(F, &AA, &MD, &DT, &TLI)) + return PreservedAnalyses::all(); + } PreservedAnalyses PA; PA.preserveSet(); PA.preserve(); - PA.preserve(); + if (EnableMemorySSA) + PA.preserve(); + else + PA.preserve(); return PA; } @@ -1358,25 +1891,45 @@ if (skipFunction(F)) return false; - DominatorTree *DT = &getAnalysis().getDomTree(); - AliasAnalysis *AA = &getAnalysis().getAAResults(); - MemoryDependenceResults *MD = - &getAnalysis().getMemDep(); - const TargetLibraryInfo *TLI = - &getAnalysis().getTLI(F); + AliasAnalysis &AA = getAnalysis().getAAResults(); + DominatorTree &DT = getAnalysis().getDomTree(); + const TargetLibraryInfo &TLI = + getAnalysis().getTLI(F); + + if (EnableMemorySSA) { + MemorySSA &MSSA = getAnalysis().getMSSA(); + PostDominatorTree &PDT = + getAnalysis().getPostDomTree(); + + return std::make_unique(F, AA, MSSA, DT, PDT, TLI)->run(); + } else { + MemoryDependenceResults &MD = + getAnalysis().getMemDep(); - return eliminateDeadStores(F, AA, MD, DT, TLI); + return eliminateDeadStores(F, &AA, &MD, &DT, &TLI); + } } void getAnalysisUsage(AnalysisUsage &AU) const override { AU.setPreservesCFG(); - AU.addRequired(); + AU.addRequired(); - AU.addRequired(); + AU.addRequired(); - AU.addPreserved(); + AU.addPreserved(); - AU.addPreserved(); + AU.addRequired(); + AU.addPreserved(); + + if (EnableMemorySSA) { + AU.addRequired(); + AU.addRequired(); + AU.addPreserved(); + AU.addPreserved(); + } else { + AU.addRequired(); + AU.addPreserved(); + } } }; @@ -1387,8 +1940,10 @@ INITIALIZE_PASS_BEGIN(DSELegacyPass, "dse", "Dead Store Elimination", false, false) INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) +INITIALIZE_PASS_DEPENDENCY(PostDominatorTreeWrapperPass) INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass) INITIALIZE_PASS_DEPENDENCY(GlobalsAAWrapperPass) +INITIALIZE_PASS_DEPENDENCY(MemorySSAWrapperPass) INITIALIZE_PASS_DEPENDENCY(MemoryDependenceWrapperPass) INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass) INITIALIZE_PASS_END(DSELegacyPass, "dse", "Dead Store Elimination", false, Index: llvm/test/Transforms/DeadStoreElimination/multiblock.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/DeadStoreElimination/multiblock.ll @@ -0,0 +1,2020 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt %s -basicaa -dse -enable-dse-memoryssa -S | FileCheck %s + +target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64" +declare void @unknown_func() +declare void @may_throw_func() readnone +declare void @llvm.lifetime.end.p0i32(i64, i32* nocapture) nounwind +declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) nounwind +declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i1) nounwind +declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i32, i1) nounwind +declare noalias i8* @malloc(i32) +declare void @free(i8* nocapture) + +define void @test1(i32* noalias %P) { +; CHECK-LABEL: @test1( +; CHECK-NEXT: br label [[BB1:%.*]] +; CHECK: bb1: +; CHECK-NEXT: store i32 0, i32* [[P:%.*]] +; CHECK-NEXT: ret void +; + %DEAD = load i32, i32* %P + %DEAD2 = add i32 %DEAD, 1 + store i32 %DEAD2, i32* %P + br label %bb1 +bb1: + store i32 0, i32* %P + ret void +} + +define void @test1A(i32* noalias %P) { +; CHECK-LABEL: @test1A( +; CHECK-NEXT: br label [[BB1:%.*]] +; CHECK: bb1: +; CHECK-NEXT: store i32 0, i32* [[P:%.*]] +; CHECK-NEXT: br label [[BB2:%.*]] +; CHECK: bb2: +; CHECK-NEXT: ret void +; + %DEAD = load i32, i32* %P + %DEAD2 = add i32 %DEAD, 1 + store i32 %DEAD2, i32* %P + br label %bb1 +bb1: + store i32 0, i32* %P + br label %bb2 +bb2: + ret void +} + +define void @test2(i32* %P) { +; CHECK-LABEL: @test2( +; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] +; CHECK: bb1: +; CHECK-NEXT: br label [[BB3:%.*]] +; CHECK: bb2: +; CHECK-NEXT: br label [[BB3]] +; CHECK: bb3: +; CHECK-NEXT: store i32 0, i32* [[P:%.*]] +; CHECK-NEXT: ret void +; + store i32 1, i32* %P + br i1 true, label %bb1, label %bb2 +bb1: + br label %bb3 +bb2: + br label %bb3 +bb3: + store i32 0, i32* %P + ret void +} + +define void @test3(i32* noalias %P) { +; CHECK-LABEL: @test3( +; CHECK-NEXT: store i32 0, i32* [[P:%.*]] +; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] +; CHECK: bb1: +; CHECK-NEXT: br label [[BB3:%.*]] +; CHECK: bb2: +; CHECK-NEXT: store i32 1, i32* [[P]] +; CHECK-NEXT: br label [[BB3]] +; CHECK: bb3: +; CHECK-NEXT: ret void +; + store i32 0, i32* %P + br i1 true, label %bb1, label %bb2 +bb1: + br label %bb3 +bb2: + store i32 1, i32* %P + br label %bb3 +bb3: + ret void +} + +define void @test3D() { +; CHECK-LABEL: @test3D( +; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] +; CHECK: bb1: +; CHECK-NEXT: br label [[BB3:%.*]] +; CHECK: bb2: +; CHECK-NEXT: br label [[BB3]] +; CHECK: bb3: +; CHECK-NEXT: ret void +; + %P = alloca i32, i32 1, align 1 + store i32 0, i32* %P + br i1 true, label %bb1, label %bb2 +bb1: + br label %bb3 +bb2: + store i32 1, i32* %P + br label %bb3 +bb3: + ret void +} + +define void @test3A(i32* noalias %P) { +; CHECK-LABEL: @test3A( +; CHECK-NEXT: store i32 0, i32* [[P:%.*]] +; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] +; CHECK: bb1: +; CHECK-NEXT: br label [[BB3:%.*]] +; CHECK: bb2: +; CHECK-NEXT: store i32 0, i32* [[P]] +; CHECK-NEXT: br label [[BB3]] +; CHECK: bb3: +; CHECK-NEXT: ret void +; + store i32 0, i32* %P + br i1 true, label %bb1, label %bb2 +bb1: + br label %bb3 +bb2: + store i32 0, i32* %P + br label %bb3 +bb3: + ret void +} + +define void @test4(i32* noalias %P) { +; CHECK-LABEL: @test4( +; CHECK-NEXT: store i32 0, i32* [[P:%.*]] +; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] +; CHECK: bb1: +; CHECK-NEXT: br label [[BB3:%.*]] +; CHECK: bb2: +; CHECK-NEXT: [[X:%.*]] = load i32, i32* [[P]] +; CHECK-NEXT: br label [[BB3]] +; CHECK: bb3: +; CHECK-NEXT: store i32 1, i32* [[P]] +; CHECK-NEXT: ret void +; + store i32 0, i32* %P + br i1 true, label %bb1, label %bb2 +bb1: + br label %bb3 +bb2: + %x = load i32, i32* %P + br label %bb3 +bb3: + store i32 1, i32* %P + ret void +} + +define void @test4A(i32* noalias %P) { +; CHECK-LABEL: @test4A( +; CHECK-NEXT: store i32 0, i32* [[P:%.*]] +; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] +; CHECK: bb1: +; CHECK-NEXT: br label [[BB3:%.*]] +; CHECK: bb2: +; CHECK-NEXT: [[X:%.*]] = load i32, i32* [[P]] +; CHECK-NEXT: br label [[BB3]] +; CHECK: bb3: +; CHECK-NEXT: store i32 0, i32* [[P]] +; CHECK-NEXT: ret void +; + store i32 0, i32* %P + br i1 true, label %bb1, label %bb2 +bb1: + br label %bb3 +bb2: + %x = load i32, i32* %P + br label %bb3 +bb3: + store i32 0, i32* %P + ret void +} + +define i32 @test4B(i32* noalias %P) { +; CHECK-LABEL: @test4B( +; CHECK-NEXT: store i32 0, i32* [[P:%.*]] +; CHECK-NEXT: [[X:%.*]] = load i32, i32* [[P]] +; CHECK-NEXT: store i32 1, i32* [[P]] +; CHECK-NEXT: ret i32 [[X]] +; + store i32 0, i32* %P + %x = load i32, i32* %P + store i32 1, i32* %P + ret i32 %x +} + +define i32 @test4C(i32* noalias %P) { +; CHECK-LABEL: @test4C( +; CHECK-NEXT: store i32 0, i32* [[P:%.*]] +; CHECK-NEXT: [[X:%.*]] = load i32, i32* [[P]] +; CHECK-NEXT: store i32 0, i32* [[P]] +; CHECK-NEXT: [[X1:%.*]] = load i32, i32* [[P]] +; CHECK-NEXT: store i32 1, i32* [[P]] +; CHECK-NEXT: ret i32 [[X1]] +; + store i32 0, i32* %P + %x = load i32, i32* %P + store i32 1, i32* %P + store i32 0, i32* %P + %x1 = load i32, i32* %P + store i32 1, i32* %P + ret i32 %x1 +} + +define void @test5(i32* noalias %P) { +; CHECK-LABEL: @test5( +; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] +; CHECK: bb1: +; CHECK-NEXT: br label [[BB3:%.*]] +; CHECK: bb2: +; CHECK-NEXT: br label [[BB3]] +; CHECK: bb3: +; CHECK-NEXT: store i32 0, i32* [[P:%.*]] +; CHECK-NEXT: ret void +; + br i1 true, label %bb1, label %bb2 +bb1: + store i32 1, i32* %P + br label %bb3 +bb2: + store i32 1, i32* %P + br label %bb3 +bb3: + store i32 0, i32* %P + ret void +} + +define void @test5A(i32* noalias %P) { +; CHECK-LABEL: @test5A( +; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] +; CHECK: bb1: +; CHECK-NEXT: store i32 0, i32* [[P:%.*]] +; CHECK-NEXT: br label [[BB3:%.*]] +; CHECK: bb2: +; CHECK-NEXT: store i32 1, i32* [[P]] +; CHECK-NEXT: br label [[BB3]] +; CHECK: bb3: +; CHECK-NEXT: ret void +; + store i32 1, i32* %P + br i1 true, label %bb1, label %bb2 +bb1: + store i32 0, i32* %P + br label %bb3 +bb2: + store i32 1, i32* %P + br label %bb3 +bb3: + ret void +} + +define void @test6(i32* noalias %P) { +; CHECK-LABEL: @test6( +; CHECK-NEXT: store i32 0, i32* [[P:%.*]] +; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] +; CHECK: bb1: +; CHECK-NEXT: br label [[BB3:%.*]] +; CHECK: bb2: +; CHECK-NEXT: call void @unknown_func() +; CHECK-NEXT: br label [[BB3]] +; CHECK: bb3: +; CHECK-NEXT: store i32 0, i32* [[P]] +; CHECK-NEXT: ret void +; + store i32 0, i32* %P + br i1 true, label %bb1, label %bb2 +bb1: + br label %bb3 +bb2: + call void @unknown_func() + br label %bb3 +bb3: + store i32 0, i32* %P + ret void +} + +define void @test6A(i32* %P) { +; CHECK-LABEL: @test6A( +; CHECK-NEXT: store i32 0, i32* [[P:%.*]] +; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] +; CHECK: bb1: +; CHECK-NEXT: br label [[BB3:%.*]] +; CHECK: bb2: +; CHECK-NEXT: call void @unknown_func() +; CHECK-NEXT: br label [[BB3]] +; CHECK: bb3: +; CHECK-NEXT: store i32 0, i32* [[P]] +; CHECK-NEXT: ret void +; + store i32 0, i32* %P + br i1 true, label %bb1, label %bb2 +bb1: + br label %bb3 +bb2: + call void @unknown_func() + br label %bb3 +bb3: + store i32 0, i32* %P + ret void +} + +define void @test7(i32* noalias %P, i32* noalias %Q) { +; CHECK-LABEL: @test7( +; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] +; CHECK: bb1: +; CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[P:%.*]] +; CHECK-NEXT: br label [[BB3:%.*]] +; CHECK: bb2: +; CHECK-NEXT: br label [[BB3]] +; CHECK: bb3: +; CHECK-NEXT: store i32 0, i32* [[Q:%.*]] +; CHECK-NEXT: store i32 0, i32* [[P]] +; CHECK-NEXT: ret void +; + store i32 1, i32* %Q + br i1 true, label %bb1, label %bb2 +bb1: + load i32, i32* %P + br label %bb3 +bb2: + br label %bb3 +bb3: + store i32 0, i32* %Q + store i32 0, i32* %P + ret void +} + + +define void @test8(i32* noalias %P) { +; CHECK-LABEL: @test8( +; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] +; CHECK: bb1: +; CHECK-NEXT: br label [[BB3:%.*]] +; CHECK: bb2: +; CHECK-NEXT: br label [[BB3]] +; CHECK: bb3: +; CHECK-NEXT: store i32 0, i32* [[P:%.*]] +; CHECK-NEXT: ret void +; + br i1 true, label %bb1, label %bb2 +bb1: + store i32 1, i32* %P + br label %bb3 +bb2: + store i32 1, i32* %P + br label %bb3 +bb3: + store i32 0, i32* %P + ret void +} + + +define void @test9(i32* noalias %P) { +; CHECK-LABEL: @test9( +; CHECK-NEXT: store i32 0, i32* [[P:%.*]] +; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] +; CHECK: bb1: +; CHECK-NEXT: br label [[BB3:%.*]] +; CHECK: bb2: +; CHECK-NEXT: ret void +; CHECK: bb3: +; CHECK-NEXT: store i32 1, i32* [[P]] +; CHECK-NEXT: ret void +; + store i32 0, i32* %P + br i1 true, label %bb1, label %bb2 +bb1: + br label %bb3 +bb2: + ret void +bb3: + store i32 1, i32* %P + ret void +} + +define void @test9A(i32* noalias %P) { +; CHECK-LABEL: @test9A( +; CHECK-NEXT: store i32 0, i32* [[P:%.*]] +; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] +; CHECK: bb1: +; CHECK-NEXT: br label [[BB3:%.*]] +; CHECK: bb2: +; CHECK-NEXT: ret void +; CHECK: bb3: +; CHECK-NEXT: store i32 0, i32* [[P]] +; CHECK-NEXT: ret void +; + store i32 0, i32* %P + br i1 true, label %bb1, label %bb2 +bb1: + br label %bb3 +bb2: + ret void +bb3: + store i32 0, i32* %P + ret void +} + +define void @test10(i32* noalias %P) { +; CHECK-LABEL: @test10( +; CHECK-NEXT: [[P2:%.*]] = bitcast i32* [[P:%.*]] to i8* +; CHECK-NEXT: store i32 0, i32* [[P]] +; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] +; CHECK: bb1: +; CHECK-NEXT: br label [[BB3:%.*]] +; CHECK: bb2: +; CHECK-NEXT: br label [[BB3]] +; CHECK: bb3: +; CHECK-NEXT: store i8 1, i8* [[P2]] +; CHECK-NEXT: ret void +; + %P2 = bitcast i32* %P to i8* + store i32 0, i32* %P + br i1 true, label %bb1, label %bb2 +bb1: + br label %bb3 +bb2: + br label %bb3 +bb3: + store i8 1, i8* %P2 + ret void +} + + +define void @test11(i32* noalias %P) { +; CHECK-LABEL: @test11( +; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] +; CHECK: bb1: +; CHECK-NEXT: br label [[BB3:%.*]] +; CHECK: bb2: +; CHECK-NEXT: br label [[BB3]] +; CHECK: bb3: +; CHECK-NEXT: store i32 0, i32* [[P:%.*]] +; CHECK-NEXT: ret void +; + %P2 = bitcast i32* %P to i8* + store i8 1, i8* %P2 + br i1 true, label %bb1, label %bb2 +bb1: + br label %bb3 +bb2: + br label %bb3 +bb3: + store i32 0, i32* %P + ret void +} + + +define void @test12(i32* noalias %P) { +; CHECK-LABEL: @test12( +; CHECK-NEXT: [[P2:%.*]] = bitcast i32* [[P:%.*]] to i8* +; CHECK-NEXT: store i32 0, i32* [[P]] +; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] +; CHECK: bb1: +; CHECK-NEXT: br label [[BB3:%.*]] +; CHECK: bb2: +; CHECK-NEXT: ret void +; CHECK: bb3: +; CHECK-NEXT: store i8 0, i8* [[P2]] +; CHECK-NEXT: ret void +; + %P2 = bitcast i32* %P to i8* + store i32 0, i32* %P + br i1 true, label %bb1, label %bb2 +bb1: + br label %bb3 +bb2: + ret void +bb3: + store i8 0, i8* %P2 + ret void +} + + +define void @test13(i32* noalias %P) { +; CHECK-LABEL: @test13( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[FOR:%.*]] +; CHECK: for: +; CHECK-NEXT: store i32 0, i32* [[P:%.*]] +; CHECK-NEXT: br i1 false, label [[FOR]], label [[END:%.*]] +; CHECK: end: +; CHECK-NEXT: ret void +; +entry: + br label %for +for: + store i32 0, i32* %P + br i1 false, label %for, label %end +end: + ret void +} + + +define void @test14(i32* noalias %P) { +; CHECK-LABEL: @test14( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[FOR:%.*]] +; CHECK: for: +; CHECK-NEXT: store i32 0, i32* [[P:%.*]] +; CHECK-NEXT: br i1 false, label [[FOR]], label [[END:%.*]] +; CHECK: end: +; CHECK-NEXT: ret void +; +entry: + store i32 1, i32* %P + br label %for +for: + store i32 0, i32* %P + br i1 false, label %for, label %end +end: + ret void +} + + +define void @test15(i32* noalias %P) { +; CHECK-LABEL: @test15( +; CHECK-NEXT: [[P2:%.*]] = bitcast i32* [[P:%.*]] to i8* +; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB3:%.*]] +; CHECK: bb1: +; CHECK-NEXT: store i32 1, i32* [[P]] +; CHECK-NEXT: br label [[BB3]] +; CHECK: bb3: +; CHECK-NEXT: store i8 2, i8* [[P2]] +; CHECK-NEXT: ret void +; + %P2 = bitcast i32* %P to i8* + br i1 true, label %bb1, label %bb3 +bb1: + store i32 1, i32* %P + br label %bb3 +bb3: + store i8 2, i8* %P2 + ret void +} + + +define void @test16(i32* noalias %P) { +; CHECK-LABEL: @test16( +; CHECK-NEXT: [[P2:%.*]] = bitcast i32* [[P:%.*]] to i8* +; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB3:%.*]] +; CHECK: bb1: +; CHECK-NEXT: br label [[BB3]] +; CHECK: bb3: +; CHECK-NEXT: call void @free(i8* [[P2]]) +; CHECK-NEXT: ret void +; + %P2 = bitcast i32* %P to i8* + store i32 1, i32* %P + br i1 true, label %bb1, label %bb3 +bb1: + store i32 1, i32* %P + br label %bb3 +bb3: + call void @free(i8* %P2) + ret void +} + +define void @test17(i32* noalias %P) { +; CHECK-LABEL: @test17( +; CHECK-NEXT: [[P2:%.*]] = bitcast i32* [[P:%.*]] to i8* +; CHECK-NEXT: store i32 1, i32* [[P]] +; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB3:%.*]] +; CHECK: bb1: +; CHECK-NEXT: call void @unknown_func() +; CHECK-NEXT: br label [[BB3]] +; CHECK: bb3: +; CHECK-NEXT: call void @free(i8* [[P2]]) +; CHECK-NEXT: ret void +; + %P2 = bitcast i32* %P to i8* + store i32 1, i32* %P + br i1 true, label %bb1, label %bb3 +bb1: + call void @unknown_func() + store i32 1, i32* %P + br label %bb3 +bb3: + call void @free(i8* %P2) + ret void +} + +define void @test17A(i32* noalias %P) { +; CHECK-LABEL: @test17A( +; CHECK-NEXT: [[P2:%.*]] = bitcast i32* [[P:%.*]] to i8* +; CHECK-NEXT: store i32 1, i32* [[P]] +; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB3:%.*]] +; CHECK: bb1: +; CHECK-NEXT: call void @unknown_func() +; CHECK-NEXT: br label [[BB3]] +; CHECK: bb3: +; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 4, i8* [[P2]]) +; CHECK-NEXT: ret void +; + %P2 = bitcast i32* %P to i8* + store i32 1, i32* %P + br i1 true, label %bb1, label %bb3 +bb1: + call void @unknown_func() + store i32 1, i32* %P + br label %bb3 +bb3: + call void @llvm.lifetime.end.p0i8(i64 4, i8* %P2) + ret void +} + +define void @test17B(i32* noalias %P) { +; CHECK-LABEL: @test17B( +; CHECK-NEXT: [[P2:%.*]] = getelementptr inbounds i32, i32* [[P:%.*]], i64 1 +; CHECK-NEXT: store i32 1, i32* [[P]] +; CHECK-NEXT: store i32 1, i32* [[P2]] +; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB3:%.*]] +; CHECK: bb1: +; CHECK-NEXT: call void @unknown_func() +; CHECK-NEXT: br label [[BB3]] +; CHECK: bb3: +; CHECK-NEXT: call void @llvm.lifetime.end.p0i32(i64 4, i32* [[P]]) +; CHECK-NEXT: ret void +; + %P2 = getelementptr inbounds i32, i32* %P, i64 1 + store i32 1, i32* %P + store i32 1, i32* %P2 + br i1 true, label %bb1, label %bb3 +bb1: + call void @unknown_func() + store i32 1, i32* %P + store i32 1, i32* %P2 + br label %bb3 +bb3: + call void @llvm.lifetime.end.p0i32(i64 4, i32* %P) + ret void +} + +define void @test18(i32* noalias %P) { +; CHECK-LABEL: @test18( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[P2:%.*]] = bitcast i32* [[P:%.*]] to i8* +; CHECK-NEXT: store i32 0, i32* [[P]] +; CHECK-NEXT: br label [[FOR:%.*]] +; CHECK: for: +; CHECK-NEXT: store i8 1, i8* [[P2]] +; CHECK-NEXT: [[X:%.*]] = load i32, i32* [[P]] +; CHECK-NEXT: store i8 2, i8* [[P2]] +; CHECK-NEXT: br i1 false, label [[FOR]], label [[END:%.*]] +; CHECK: end: +; CHECK-NEXT: ret void +; +entry: + %P2 = bitcast i32* %P to i8* + store i32 0, i32* %P + br label %for +for: + store i8 1, i8* %P2 + %x = load i32, i32* %P + store i8 2, i8* %P2 + br i1 false, label %for, label %end +end: + ret void +} + + +define void @test19(i32* noalias %P) { +; CHECK-LABEL: @test19( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[ARRAYIDX0:%.*]] = getelementptr inbounds i32, i32* [[P:%.*]], i64 1 +; CHECK-NEXT: [[P3:%.*]] = bitcast i32* [[ARRAYIDX0]] to i8* +; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* align 4 [[P3]], i8 0, i64 28, i1 false) +; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] +; CHECK: bb1: +; CHECK-NEXT: br label [[BB3:%.*]] +; CHECK: bb2: +; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds i32, i32* [[P]], i64 1 +; CHECK-NEXT: store i32 1, i32* [[ARRAYIDX1]], align 4 +; CHECK-NEXT: br label [[BB3]] +; CHECK: bb3: +; CHECK-NEXT: ret void +; +entry: + %arrayidx0 = getelementptr inbounds i32, i32* %P, i64 1 + %p3 = bitcast i32* %arrayidx0 to i8* + call void @llvm.memset.p0i8.i64(i8* %p3, i8 0, i64 28, i32 4, i1 false) + br i1 true, label %bb1, label %bb2 +bb1: + br label %bb3 +bb2: + %arrayidx1 = getelementptr inbounds i32, i32* %P, i64 1 + store i32 1, i32* %arrayidx1, align 4 + br label %bb3 +bb3: + ret void +} + + +define void @test20(i32* noalias %P) { +; CHECK-LABEL: @test20( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[ARRAYIDX0:%.*]] = getelementptr inbounds i32, i32* [[P:%.*]], i64 1 +; CHECK-NEXT: [[P3:%.*]] = bitcast i32* [[ARRAYIDX0]] to i8* +; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* align 4 [[P3]], i8 0, i64 28, i1 false) +; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] +; CHECK: bb1: +; CHECK-NEXT: br label [[BB3:%.*]] +; CHECK: bb2: +; CHECK-NEXT: br label [[BB3]] +; CHECK: bb3: +; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds i32, i32* [[P]], i64 1 +; CHECK-NEXT: store i32 1, i32* [[ARRAYIDX1]], align 4 +; CHECK-NEXT: ret void +; +entry: + %arrayidx0 = getelementptr inbounds i32, i32* %P, i64 1 + %p3 = bitcast i32* %arrayidx0 to i8* + call void @llvm.memset.p0i8.i64(i8* %p3, i8 0, i64 28, i32 4, i1 false) + br i1 true, label %bb1, label %bb2 +bb1: + br label %bb3 +bb2: + br label %bb3 +bb3: + %arrayidx1 = getelementptr inbounds i32, i32* %P, i64 1 + store i32 1, i32* %arrayidx1, align 4 + ret void +} + + +define void @test21(i32* noalias %P) { +; CHECK-LABEL: @test21( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[ARRAYIDX0:%.*]] = getelementptr inbounds i32, i32* [[P:%.*]], i64 1 +; CHECK-NEXT: [[P3:%.*]] = bitcast i32* [[ARRAYIDX0]] to i8* +; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* align 4 [[P3]], i8 0, i64 28, i1 false) +; CHECK-NEXT: br label [[FOR:%.*]] +; CHECK: for: +; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds i32, i32* [[P]], i64 1 +; CHECK-NEXT: store i32 1, i32* [[ARRAYIDX1]], align 4 +; CHECK-NEXT: br i1 false, label [[FOR]], label [[END:%.*]] +; CHECK: end: +; CHECK-NEXT: ret void +; +entry: + %arrayidx0 = getelementptr inbounds i32, i32* %P, i64 1 + %p3 = bitcast i32* %arrayidx0 to i8* + call void @llvm.memset.p0i8.i64(i8* %p3, i8 0, i64 28, i32 4, i1 false) + br label %for +for: + %arrayidx1 = getelementptr inbounds i32, i32* %P, i64 1 + store i32 1, i32* %arrayidx1, align 4 + br i1 false, label %for, label %end +end: + ret void +} + +define void @test21A(i32* noalias %P) { +; CHECK-LABEL: @test21A( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[FOR:%.*]] +; CHECK: for: +; CHECK-NEXT: [[X:%.*]] = load i32, i32* [[P:%.*]] +; CHECK-NEXT: store i32 1, i32* [[P]], align 4 +; CHECK-NEXT: [[X1:%.*]] = trunc i32 [[X]] to i1 +; CHECK-NEXT: br i1 [[X1]], label [[FOR]], label [[END:%.*]] +; CHECK: end: +; CHECK-NEXT: store i32 1, i32* [[P]], align 4 +; CHECK-NEXT: ret void +; +entry: + br label %for +for: + %x = load i32, i32* %P + store i32 1, i32* %P, align 4 + %x1 = trunc i32 %x to i1 + br i1 %x1, label %for, label %end +end: + store i32 1, i32* %P, align 4 + ret void +} + +define i32 @test22(i32* %P, i32* noalias %Q, i32* %R) { +; CHECK-LABEL: @test22( +; CHECK-NEXT: store i32 2, i32* [[P:%.*]] +; CHECK-NEXT: store i32 3, i32* [[Q:%.*]] +; CHECK-NEXT: [[L:%.*]] = load i32, i32* [[R:%.*]] +; CHECK-NEXT: ret i32 [[L]] +; + store i32 1, i32* %Q + store i32 2, i32* %P + store i32 3, i32* %Q + %l = load i32, i32* %R + ret i32 %l +} + + +define void @test23(i32* noalias %P) { +; CHECK-LABEL: @test23( +; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] +; CHECK: bb1: +; CHECK-NEXT: br label [[BB3:%.*]] +; CHECK: bb2: +; CHECK-NEXT: call void @unknown_func() +; CHECK-NEXT: br label [[BB3]] +; CHECK: bb3: +; CHECK-NEXT: store i32 0, i32* [[P:%.*]] +; CHECK-NEXT: ret void +; + br i1 true, label %bb1, label %bb2 +bb1: + store i32 0, i32* %P + br label %bb3 +bb2: + call void @unknown_func() + br label %bb3 +bb3: + store i32 0, i32* %P + ret void +} + +define void @test24(i32* noalias %P) { +; CHECK-LABEL: @test24( +; CHECK-NEXT: br i1 true, label [[BB2:%.*]], label [[BB1:%.*]] +; CHECK: bb1: +; CHECK-NEXT: br label [[BB3:%.*]] +; CHECK: bb2: +; CHECK-NEXT: call void @unknown_func() +; CHECK-NEXT: br label [[BB3]] +; CHECK: bb3: +; CHECK-NEXT: store i32 0, i32* [[P:%.*]] +; CHECK-NEXT: ret void +; + br i1 true, label %bb2, label %bb1 +bb1: + store i32 0, i32* %P + br label %bb3 +bb2: + call void @unknown_func() + br label %bb3 +bb3: + store i32 0, i32* %P + ret void +} + + +define void @test25(i32* noalias %P) { +; CHECK-LABEL: @test25( +; CHECK-NEXT: store i32 1, i32* [[P:%.*]] +; CHECK-NEXT: [[P2:%.*]] = bitcast i32* [[P]] to i8* +; CHECK-NEXT: br i1 true, label [[BB2:%.*]], label [[BB1:%.*]] +; CHECK: bb1: +; CHECK-NEXT: br label [[BB3:%.*]] +; CHECK: bb2: +; CHECK-NEXT: call void @free(i8* [[P2]]) +; CHECK-NEXT: ret void +; CHECK: bb3: +; CHECK-NEXT: ret void +; + store i32 1, i32* %P + %P2 = bitcast i32* %P to i8* + br i1 true, label %bb2, label %bb1 +bb1: + br label %bb3 +bb2: + call void @free(i8* %P2) + ret void +bb3: + ret void +} + + +define i8* @test26() { +; CHECK-LABEL: @test26( +; CHECK-NEXT: bb1: +; CHECK-NEXT: br i1 true, label [[BB2:%.*]], label [[BB3:%.*]] +; CHECK: bb2: +; CHECK-NEXT: [[M:%.*]] = call noalias i8* @malloc(i32 10) +; CHECK-NEXT: store i8 1, i8* [[M]] +; CHECK-NEXT: br label [[BB3]] +; CHECK: bb3: +; CHECK-NEXT: [[R:%.*]] = phi i8* [ null, [[BB1:%.*]] ], [ [[M]], [[BB2]] ] +; CHECK-NEXT: ret i8* [[R]] +; +bb1: + br i1 true, label %bb2, label %bb3 +bb2: + %m = call noalias i8* @malloc(i32 10) + store i8 1, i8* %m + br label %bb3 +bb3: + %r = phi i8* [ null, %bb1 ], [ %m, %bb2 ] + ret i8* %r +} + + +define void @test27() { +; CHECK-LABEL: @test27( +; CHECK-NEXT: bb1: +; CHECK-NEXT: br i1 true, label [[BB2:%.*]], label [[BB3:%.*]] +; CHECK: bb2: +; CHECK-NEXT: [[M:%.*]] = call noalias i8* @malloc(i32 10) +; CHECK-NEXT: store i8 1, i8* [[M]] +; CHECK-NEXT: br label [[BB3]] +; CHECK: bb3: +; CHECK-NEXT: [[R:%.*]] = phi i8* [ null, [[BB1:%.*]] ], [ [[M]], [[BB2]] ] +; CHECK-NEXT: ret void +; +bb1: + br i1 true, label %bb2, label %bb3 +bb2: + %m = call noalias i8* @malloc(i32 10) + store i8 1, i8* %m + br label %bb3 +bb3: + %r = phi i8* [ null, %bb1 ], [ %m, %bb2 ] + ret void +} + + +define i8* @test28() { +; CHECK-LABEL: @test28( +; CHECK-NEXT: bb0: +; CHECK-NEXT: [[M:%.*]] = call noalias i8* @malloc(i32 10) +; CHECK-NEXT: [[MC0:%.*]] = bitcast i8* [[M]] to i8* +; CHECK-NEXT: [[MC1:%.*]] = bitcast i8* [[MC0]] to i8* +; CHECK-NEXT: [[MC2:%.*]] = bitcast i8* [[MC1]] to i8* +; CHECK-NEXT: [[MC3:%.*]] = bitcast i8* [[MC2]] to i8* +; CHECK-NEXT: [[MC4:%.*]] = bitcast i8* [[MC3]] to i8* +; CHECK-NEXT: [[MC5:%.*]] = bitcast i8* [[MC4]] to i8* +; CHECK-NEXT: [[MC6:%.*]] = bitcast i8* [[MC5]] to i8* +; CHECK-NEXT: [[M0:%.*]] = bitcast i8* [[MC6]] to i8* +; CHECK-NEXT: store i8 2, i8* [[M]] +; CHECK-NEXT: ret i8* [[M0]] +; +bb0: + %m = call noalias i8* @malloc(i32 10) + %mc0 = bitcast i8* %m to i8* + %mc1 = bitcast i8* %mc0 to i8* + %mc2 = bitcast i8* %mc1 to i8* + %mc3 = bitcast i8* %mc2 to i8* + %mc4 = bitcast i8* %mc3 to i8* + %mc5 = bitcast i8* %mc4 to i8* + %mc6 = bitcast i8* %mc5 to i8* + %m0 = bitcast i8* %mc6 to i8* + store i8 2, i8* %m + ret i8* %m0 +} + + +define void @test_loop(i32 %N, i32* noalias nocapture readonly %A, i32* noalias nocapture readonly %x, i32* noalias nocapture %b) local_unnamed_addr { +; CHECK-LABEL: @test_loop( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CMP27:%.*]] = icmp sgt i32 [[N:%.*]], 0 +; CHECK-NEXT: br i1 [[CMP27]], label [[FOR_BODY4_LR_PH_PREHEADER:%.*]], label [[FOR_COND_CLEANUP:%.*]] +; CHECK: for.body4.lr.ph.preheader: +; CHECK-NEXT: br label [[FOR_BODY4_LR_PH:%.*]] +; CHECK: for.cond.cleanup: +; CHECK-NEXT: ret void +; CHECK: for.body4.lr.ph: +; CHECK-NEXT: [[I_028:%.*]] = phi i32 [ [[INC11:%.*]], [[FOR_COND_CLEANUP3:%.*]] ], [ 0, [[FOR_BODY4_LR_PH_PREHEADER]] ] +; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, i32* [[B:%.*]], i32 [[I_028]] +; CHECK-NEXT: [[MUL:%.*]] = mul nsw i32 [[I_028]], [[N]] +; CHECK-NEXT: br label [[FOR_BODY4:%.*]] +; CHECK: for.cond.cleanup3: +; CHECK-NEXT: store i32 [[ADD9:%.*]], i32* [[ARRAYIDX]], align 4 +; CHECK-NEXT: [[INC11]] = add nuw nsw i32 [[I_028]], 1 +; CHECK-NEXT: [[EXITCOND29:%.*]] = icmp eq i32 [[INC11]], [[N]] +; CHECK-NEXT: br i1 [[EXITCOND29]], label [[FOR_COND_CLEANUP]], label [[FOR_BODY4_LR_PH]] +; CHECK: for.body4: +; CHECK-NEXT: [[TMP0:%.*]] = phi i32 [ 0, [[FOR_BODY4_LR_PH]] ], [ [[ADD9]], [[FOR_BODY4]] ] +; CHECK-NEXT: [[J_026:%.*]] = phi i32 [ 0, [[FOR_BODY4_LR_PH]] ], [ [[INC:%.*]], [[FOR_BODY4]] ] +; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[J_026]], [[MUL]] +; CHECK-NEXT: [[ARRAYIDX5:%.*]] = getelementptr inbounds i32, i32* [[A:%.*]], i32 [[ADD]] +; CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[ARRAYIDX5]], align 4 +; CHECK-NEXT: [[ARRAYIDX6:%.*]] = getelementptr inbounds i32, i32* [[X:%.*]], i32 [[J_026]] +; CHECK-NEXT: [[TMP2:%.*]] = load i32, i32* [[ARRAYIDX6]], align 4 +; CHECK-NEXT: [[MUL7:%.*]] = mul nsw i32 [[TMP2]], [[TMP1]] +; CHECK-NEXT: [[ADD9]] = add nsw i32 [[MUL7]], [[TMP0]] +; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[J_026]], 1 +; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[INC]], [[N]] +; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_COND_CLEANUP3]], label [[FOR_BODY4]] +; +entry: + %cmp27 = icmp sgt i32 %N, 0 + br i1 %cmp27, label %for.body4.lr.ph.preheader, label %for.cond.cleanup + +for.body4.lr.ph.preheader: ; preds = %entry + br label %for.body4.lr.ph + +for.cond.cleanup: ; preds = %for.cond.cleanup3, %entry + ret void + +for.body4.lr.ph: ; preds = %for.body4.lr.ph.preheader, %for.cond.cleanup3 + %i.028 = phi i32 [ %inc11, %for.cond.cleanup3 ], [ 0, %for.body4.lr.ph.preheader ] + %arrayidx = getelementptr inbounds i32, i32* %b, i32 %i.028 + store i32 0, i32* %arrayidx, align 4 + %mul = mul nsw i32 %i.028, %N + br label %for.body4 + +for.cond.cleanup3: ; preds = %for.body4 + store i32 %add9, i32* %arrayidx, align 4 + %inc11 = add nuw nsw i32 %i.028, 1 + %exitcond29 = icmp eq i32 %inc11, %N + br i1 %exitcond29, label %for.cond.cleanup, label %for.body4.lr.ph + +for.body4: ; preds = %for.body4, %for.body4.lr.ph + %0 = phi i32 [ 0, %for.body4.lr.ph ], [ %add9, %for.body4 ] + %j.026 = phi i32 [ 0, %for.body4.lr.ph ], [ %inc, %for.body4 ] + %add = add nsw i32 %j.026, %mul + %arrayidx5 = getelementptr inbounds i32, i32* %A, i32 %add + %1 = load i32, i32* %arrayidx5, align 4 + %arrayidx6 = getelementptr inbounds i32, i32* %x, i32 %j.026 + %2 = load i32, i32* %arrayidx6, align 4 + %mul7 = mul nsw i32 %2, %1 + %add9 = add nsw i32 %mul7, %0 + %inc = add nuw nsw i32 %j.026, 1 + %exitcond = icmp eq i32 %inc, %N + br i1 %exitcond, label %for.cond.cleanup3, label %for.body4 +} + +define void @test50(i32* %P, i1 %B) { +; CHECK-LABEL: @test50( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 +; CHECK-NEXT: store i32 1, i32* [[P:%.*]], align 4 +; CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[FROMBOOL]] to i1 +; CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END15:%.*]] +; CHECK: if.then: +; CHECK-NEXT: [[TOBOOL1:%.*]] = trunc i8 [[FROMBOOL]] to i1 +; CHECK-NEXT: br i1 [[TOBOOL1]], label [[IF_THEN2:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then2: +; CHECK-NEXT: br label [[IF_END14:%.*]] +; CHECK: if.else: +; CHECK-NEXT: [[TOBOOL3:%.*]] = trunc i8 [[FROMBOOL]] to i1 +; CHECK-NEXT: br i1 [[TOBOOL3]], label [[IF_THEN4:%.*]], label [[IF_ELSE5:%.*]] +; CHECK: if.then4: +; CHECK-NEXT: br label [[IF_END13:%.*]] +; CHECK: if.else5: +; CHECK-NEXT: [[TOBOOL6:%.*]] = trunc i8 [[FROMBOOL]] to i1 +; CHECK-NEXT: br i1 [[TOBOOL6]], label [[IF_THEN7:%.*]], label [[IF_ELSE8:%.*]] +; CHECK: if.then7: +; CHECK-NEXT: br label [[IF_END12:%.*]] +; CHECK: if.else8: +; CHECK-NEXT: br label [[WHILE_COND:%.*]] +; CHECK: while.cond: +; CHECK-NEXT: [[TOBOOL9:%.*]] = trunc i8 [[FROMBOOL]] to i1 +; CHECK-NEXT: br i1 [[TOBOOL9]], label [[WHILE_BODY:%.*]], label [[WHILE_END:%.*]] +; CHECK: while.body: +; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[P]], align 4 +; CHECK-NEXT: [[TOBOOL10:%.*]] = icmp ne i32 [[TMP0]], 0 +; CHECK-NEXT: br i1 [[TOBOOL10]], label [[IF_THEN11:%.*]], label [[IF_END:%.*]] +; CHECK: if.then11: +; CHECK-NEXT: br label [[IF_END]] +; CHECK: if.end: +; CHECK-NEXT: br label [[WHILE_COND]] +; CHECK: while.end: +; CHECK-NEXT: br label [[IF_END12]] +; CHECK: if.end12: +; CHECK-NEXT: br label [[IF_END13]] +; CHECK: if.end13: +; CHECK-NEXT: br label [[IF_END14]] +; CHECK: if.end14: +; CHECK-NEXT: br label [[IF_END15]] +; CHECK: if.end15: +; CHECK-NEXT: store i32 0, i32* [[P]], align 4 +; CHECK-NEXT: ret void +; +entry: + %frombool = zext i1 %B to i8 + store i32 1, i32* %P, align 4 + %tobool = trunc i8 %frombool to i1 + br i1 %tobool, label %if.then, label %if.end15 + +if.then: ; preds = %entry + %tobool1 = trunc i8 %frombool to i1 + br i1 %tobool1, label %if.then2, label %if.else + +if.then2: ; preds = %if.then + br label %if.end14 + +if.else: ; preds = %if.then + %tobool3 = trunc i8 %frombool to i1 + br i1 %tobool3, label %if.then4, label %if.else5 + +if.then4: ; preds = %if.else + br label %if.end13 + +if.else5: ; preds = %if.else + %tobool6 = trunc i8 %frombool to i1 + br i1 %tobool6, label %if.then7, label %if.else8 + +if.then7: ; preds = %if.else5 + br label %if.end12 + +if.else8: ; preds = %if.else5 + br label %while.cond + +while.cond: ; preds = %if.end, %if.else8 + %tobool9 = trunc i8 %frombool to i1 + br i1 %tobool9, label %while.body, label %while.end + +while.body: ; preds = %while.cond + %0 = load i32, i32* %P, align 4 + %tobool10 = icmp ne i32 %0, 0 + br i1 %tobool10, label %if.then11, label %if.end + +if.then11: ; preds = %while.body + br label %if.end + +if.end: ; preds = %if.then11, %while.body + br label %while.cond + +while.end: ; preds = %while.cond + br label %if.end12 + +if.end12: ; preds = %while.end, %if.then7 + br label %if.end13 + +if.end13: ; preds = %if.end12, %if.then4 + br label %if.end14 + +if.end14: ; preds = %if.end13, %if.then2 + br label %if.end15 + +if.end15: ; preds = %if.end14, %entry + store i32 0, i32* %P, align 4 + ret void +} + +define void @test51(i32* %P, i1 %B) { +; CHECK-LABEL: @test51( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 +; CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[FROMBOOL]] to i1 +; CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END15:%.*]] +; CHECK: if.then: +; CHECK-NEXT: [[TOBOOL1:%.*]] = trunc i8 [[FROMBOOL]] to i1 +; CHECK-NEXT: br i1 [[TOBOOL1]], label [[IF_THEN2:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then2: +; CHECK-NEXT: br label [[IF_END14:%.*]] +; CHECK: if.else: +; CHECK-NEXT: [[TOBOOL3:%.*]] = trunc i8 [[FROMBOOL]] to i1 +; CHECK-NEXT: br i1 [[TOBOOL3]], label [[IF_THEN4:%.*]], label [[IF_ELSE5:%.*]] +; CHECK: if.then4: +; CHECK-NEXT: br label [[IF_END13:%.*]] +; CHECK: if.else5: +; CHECK-NEXT: [[TOBOOL6:%.*]] = trunc i8 [[FROMBOOL]] to i1 +; CHECK-NEXT: br i1 [[TOBOOL6]], label [[IF_THEN7:%.*]], label [[IF_ELSE8:%.*]] +; CHECK: if.then7: +; CHECK-NEXT: br label [[IF_END12:%.*]] +; CHECK: if.else8: +; CHECK-NEXT: br label [[WHILE_COND:%.*]] +; CHECK: while.cond: +; CHECK-NEXT: [[TOBOOL9:%.*]] = trunc i8 [[FROMBOOL]] to i1 +; CHECK-NEXT: br i1 [[TOBOOL9]], label [[WHILE_BODY:%.*]], label [[WHILE_END:%.*]] +; CHECK: while.body: +; CHECK-NEXT: br i1 [[B]], label [[IF_THEN11:%.*]], label [[IF_END:%.*]] +; CHECK: if.then11: +; CHECK-NEXT: br label [[IF_END]] +; CHECK: if.end: +; CHECK-NEXT: br label [[WHILE_COND]] +; CHECK: while.end: +; CHECK-NEXT: br label [[IF_END12]] +; CHECK: if.end12: +; CHECK-NEXT: br label [[IF_END13]] +; CHECK: if.end13: +; CHECK-NEXT: br label [[IF_END14]] +; CHECK: if.end14: +; CHECK-NEXT: br label [[IF_END15]] +; CHECK: if.end15: +; CHECK-NEXT: store i32 0, i32* [[P:%.*]], align 4 +; CHECK-NEXT: ret void +; +entry: + %frombool = zext i1 %B to i8 + store i32 1, i32* %P, align 4 + %tobool = trunc i8 %frombool to i1 + br i1 %tobool, label %if.then, label %if.end15 + +if.then: ; preds = %entry + %tobool1 = trunc i8 %frombool to i1 + br i1 %tobool1, label %if.then2, label %if.else + +if.then2: ; preds = %if.then + br label %if.end14 + +if.else: ; preds = %if.then + %tobool3 = trunc i8 %frombool to i1 + br i1 %tobool3, label %if.then4, label %if.else5 + +if.then4: ; preds = %if.else + br label %if.end13 + +if.else5: ; preds = %if.else + %tobool6 = trunc i8 %frombool to i1 + br i1 %tobool6, label %if.then7, label %if.else8 + +if.then7: ; preds = %if.else5 + br label %if.end12 + +if.else8: ; preds = %if.else5 + br label %while.cond + +while.cond: ; preds = %if.end, %if.else8 + %tobool9 = trunc i8 %frombool to i1 + br i1 %tobool9, label %while.body, label %while.end + +while.body: ; preds = %while.cond + br i1 %B, label %if.then11, label %if.end + +if.then11: ; preds = %while.body + br label %if.end + +if.end: ; preds = %if.then11, %while.body + br label %while.cond + +while.end: ; preds = %while.cond + br label %if.end12 + +if.end12: ; preds = %while.end, %if.then7 + br label %if.end13 + +if.end13: ; preds = %if.end12, %if.then4 + br label %if.end14 + +if.end14: ; preds = %if.end13, %if.then2 + br label %if.end15 + +if.end15: ; preds = %if.end14, %entry + store i32 0, i32* %P, align 4 + ret void +} + +define void @test52(i32* %P, i1 %B) { +; CHECK-LABEL: @test52( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 +; CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[FROMBOOL]] to i1 +; CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END15:%.*]] +; CHECK: if.then: +; CHECK-NEXT: [[TOBOOL1:%.*]] = trunc i8 [[FROMBOOL]] to i1 +; CHECK-NEXT: br i1 [[TOBOOL1]], label [[IF_THEN2:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then2: +; CHECK-NEXT: br label [[IF_END14:%.*]] +; CHECK: if.else: +; CHECK-NEXT: [[TOBOOL3:%.*]] = trunc i8 [[FROMBOOL]] to i1 +; CHECK-NEXT: br i1 [[TOBOOL3]], label [[IF_THEN4:%.*]], label [[IF_ELSE5:%.*]] +; CHECK: if.then4: +; CHECK-NEXT: br label [[IF_END13:%.*]] +; CHECK: if.else5: +; CHECK-NEXT: [[TOBOOL6:%.*]] = trunc i8 [[FROMBOOL]] to i1 +; CHECK-NEXT: br i1 [[TOBOOL6]], label [[IF_THEN7:%.*]], label [[IF_ELSE8:%.*]] +; CHECK: if.then7: +; CHECK-NEXT: store i32 1, i32* [[P:%.*]], align 4 +; CHECK-NEXT: call void @unknown_func() +; CHECK-NEXT: br label [[IF_END12:%.*]] +; CHECK: if.else8: +; CHECK-NEXT: br label [[WHILE_COND:%.*]] +; CHECK: while.cond: +; CHECK-NEXT: [[TOBOOL9:%.*]] = trunc i8 [[FROMBOOL]] to i1 +; CHECK-NEXT: br i1 [[TOBOOL9]], label [[WHILE_BODY:%.*]], label [[WHILE_END:%.*]] +; CHECK: while.body: +; CHECK-NEXT: br i1 [[B]], label [[IF_THEN11:%.*]], label [[IF_END:%.*]] +; CHECK: if.then11: +; CHECK-NEXT: br label [[IF_END]] +; CHECK: if.end: +; CHECK-NEXT: store i32 1, i32* [[P]], align 4 +; CHECK-NEXT: br label [[WHILE_COND]] +; CHECK: while.end: +; CHECK-NEXT: br label [[IF_END12]] +; CHECK: if.end12: +; CHECK-NEXT: br label [[IF_END13]] +; CHECK: if.end13: +; CHECK-NEXT: br label [[IF_END14]] +; CHECK: if.end14: +; CHECK-NEXT: br label [[IF_END15]] +; CHECK: if.end15: +; CHECK-NEXT: store i32 0, i32* [[P]], align 4 +; CHECK-NEXT: ret void +; +entry: + %frombool = zext i1 %B to i8 + store i32 1, i32* %P, align 4 + %tobool = trunc i8 %frombool to i1 + br i1 %tobool, label %if.then, label %if.end15 + +if.then: ; preds = %entry + %tobool1 = trunc i8 %frombool to i1 + store i32 1, i32* %P, align 4 + br i1 %tobool1, label %if.then2, label %if.else + +if.then2: ; preds = %if.then + store i32 1, i32* %P, align 4 + br label %if.end14 + +if.else: ; preds = %if.then + %tobool3 = trunc i8 %frombool to i1 + store i32 1, i32* %P, align 4 + br i1 %tobool3, label %if.then4, label %if.else5 + +if.then4: ; preds = %if.else + store i32 1, i32* %P, align 4 + br label %if.end13 + +if.else5: ; preds = %if.else + %tobool6 = trunc i8 %frombool to i1 + store i32 1, i32* %P, align 4 + br i1 %tobool6, label %if.then7, label %if.else8 + +if.then7: ; preds = %if.else5 + store i32 1, i32* %P, align 4 + call void @unknown_func() + store i32 1, i32* %P, align 4 + br label %if.end12 + +if.else8: ; preds = %if.else5 + store i32 1, i32* %P, align 4 + br label %while.cond + +while.cond: ; preds = %if.end, %if.else8 + %tobool9 = trunc i8 %frombool to i1 + store i32 1, i32* %P, align 4 + br i1 %tobool9, label %while.body, label %while.end + +while.body: ; preds = %while.cond + store i32 1, i32* %P, align 4 + br i1 %B, label %if.then11, label %if.end + +if.then11: ; preds = %while.body + store i32 1, i32* %P, align 4 + br label %if.end + +if.end: ; preds = %if.then11, %while.body + store i32 1, i32* %P, align 4 + br label %while.cond + +while.end: ; preds = %while.cond + store i32 1, i32* %P, align 4 + br label %if.end12 + +if.end12: ; preds = %while.end, %if.then7 + store i32 1, i32* %P, align 4 + br label %if.end13 + +if.end13: ; preds = %if.end12, %if.then4 + store i32 1, i32* %P, align 4 + br label %if.end14 + +if.end14: ; preds = %if.end13, %if.then2 + store i32 1, i32* %P, align 4 + br label %if.end15 + +if.end15: ; preds = %if.end14, %entry + store i32 0, i32* %P, align 4 + ret void +} + +declare void @may_write_func(i32*) nounwind writeonly + +define void @test53(i32* %P, i1 %B) { +; CHECK-LABEL: @test53( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 +; CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[FROMBOOL]] to i1 +; CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END15:%.*]] +; CHECK: if.then: +; CHECK-NEXT: [[TOBOOL1:%.*]] = trunc i8 [[FROMBOOL]] to i1 +; CHECK-NEXT: br i1 [[TOBOOL1]], label [[IF_THEN2:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then2: +; CHECK-NEXT: br label [[IF_END14:%.*]] +; CHECK: if.else: +; CHECK-NEXT: [[TOBOOL3:%.*]] = trunc i8 [[FROMBOOL]] to i1 +; CHECK-NEXT: br i1 [[TOBOOL3]], label [[IF_THEN4:%.*]], label [[IF_ELSE5:%.*]] +; CHECK: if.then4: +; CHECK-NEXT: br label [[IF_END13:%.*]] +; CHECK: if.else5: +; CHECK-NEXT: [[TOBOOL6:%.*]] = trunc i8 [[FROMBOOL]] to i1 +; CHECK-NEXT: br i1 [[TOBOOL6]], label [[IF_THEN7:%.*]], label [[IF_ELSE8:%.*]] +; CHECK: if.then7: +; CHECK-NEXT: call void @may_write_func(i32* [[P:%.*]]) +; CHECK-NEXT: br label [[IF_END12:%.*]] +; CHECK: if.else8: +; CHECK-NEXT: br label [[WHILE_COND:%.*]] +; CHECK: while.cond: +; CHECK-NEXT: [[TOBOOL9:%.*]] = trunc i8 [[FROMBOOL]] to i1 +; CHECK-NEXT: br i1 [[TOBOOL9]], label [[WHILE_BODY:%.*]], label [[WHILE_END:%.*]] +; CHECK: while.body: +; CHECK-NEXT: br i1 [[B]], label [[IF_THEN11:%.*]], label [[IF_END:%.*]] +; CHECK: if.then11: +; CHECK-NEXT: br label [[IF_END]] +; CHECK: if.end: +; CHECK-NEXT: store i32 1, i32* [[P]], align 4 +; CHECK-NEXT: br label [[WHILE_COND]] +; CHECK: while.end: +; CHECK-NEXT: br label [[IF_END12]] +; CHECK: if.end12: +; CHECK-NEXT: br label [[IF_END13]] +; CHECK: if.end13: +; CHECK-NEXT: br label [[IF_END14]] +; CHECK: if.end14: +; CHECK-NEXT: br label [[IF_END15]] +; CHECK: if.end15: +; CHECK-NEXT: store i32 0, i32* [[P]], align 4 +; CHECK-NEXT: ret void +; +entry: + %frombool = zext i1 %B to i8 + store i32 1, i32* %P, align 4 + %tobool = trunc i8 %frombool to i1 + br i1 %tobool, label %if.then, label %if.end15 + +if.then: ; preds = %entry + store i32 1, i32* %P, align 4 + %tobool1 = trunc i8 %frombool to i1 + br i1 %tobool1, label %if.then2, label %if.else + +if.then2: ; preds = %if.then + store i32 1, i32* %P, align 4 + br label %if.end14 + +if.else: ; preds = %if.then + store i32 1, i32* %P, align 4 + %tobool3 = trunc i8 %frombool to i1 + br i1 %tobool3, label %if.then4, label %if.else5 + +if.then4: ; preds = %if.else + store i32 1, i32* %P, align 4 + br label %if.end13 + +if.else5: ; preds = %if.else + %tobool6 = trunc i8 %frombool to i1 + store i32 1, i32* %P, align 4 + br i1 %tobool6, label %if.then7, label %if.else8 + +if.then7: ; preds = %if.else5 + store i32 1, i32* %P, align 4 + call void @may_write_func(i32* %P) + store i32 1, i32* %P, align 4 + br label %if.end12 + +if.else8: ; preds = %if.else5 + store i32 1, i32* %P, align 4 + br label %while.cond + +while.cond: ; preds = %if.end, %if.else8 + %tobool9 = trunc i8 %frombool to i1 + store i32 1, i32* %P, align 4 + br i1 %tobool9, label %while.body, label %while.end + +while.body: ; preds = %while.cond + store i32 1, i32* %P, align 4 + br i1 %B, label %if.then11, label %if.end + +if.then11: ; preds = %while.body + store i32 1, i32* %P, align 4 + br label %if.end + +if.end: ; preds = %if.then11, %while.body + store i32 1, i32* %P, align 4 + br label %while.cond + +while.end: ; preds = %while.cond + store i32 1, i32* %P, align 4 + br label %if.end12 + +if.end12: ; preds = %while.end, %if.then7 + store i32 1, i32* %P, align 4 + br label %if.end13 + +if.end13: ; preds = %if.end12, %if.then4 + store i32 1, i32* %P, align 4 + br label %if.end14 + +if.end14: ; preds = %if.end13, %if.then2 + store i32 1, i32* %P, align 4 + br label %if.end15 + +if.end15: ; preds = %if.end14, %entry + store i32 0, i32* %P, align 4 + ret void +} + +define void @test54(i32* %P, i1 %B) { +; CHECK-LABEL: @test54( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 +; CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[FROMBOOL]] to i1 +; CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END15:%.*]] +; CHECK: if.then: +; CHECK-NEXT: [[TOBOOL1:%.*]] = trunc i8 [[FROMBOOL]] to i1 +; CHECK-NEXT: br i1 [[TOBOOL1]], label [[IF_THEN2:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then2: +; CHECK-NEXT: br label [[IF_END14:%.*]] +; CHECK: if.else: +; CHECK-NEXT: [[TOBOOL3:%.*]] = trunc i8 [[FROMBOOL]] to i1 +; CHECK-NEXT: br i1 [[TOBOOL3]], label [[IF_THEN4:%.*]], label [[IF_ELSE5:%.*]] +; CHECK: if.then4: +; CHECK-NEXT: br label [[IF_END13:%.*]] +; CHECK: if.else5: +; CHECK-NEXT: [[TOBOOL6:%.*]] = trunc i8 [[FROMBOOL]] to i1 +; CHECK-NEXT: br i1 [[TOBOOL6]], label [[IF_THEN7:%.*]], label [[IF_ELSE8:%.*]] +; CHECK: if.then7: +; CHECK-NEXT: br label [[IF_END12:%.*]] +; CHECK: if.else8: +; CHECK-NEXT: br label [[WHILE_COND:%.*]] +; CHECK: while.cond: +; CHECK-NEXT: [[TOBOOL9:%.*]] = trunc i8 [[FROMBOOL]] to i1 +; CHECK-NEXT: br i1 [[TOBOOL9]], label [[WHILE_BODY:%.*]], label [[WHILE_END:%.*]] +; CHECK: while.body: +; CHECK-NEXT: br i1 [[B]], label [[IF_THEN11:%.*]], label [[IF_END:%.*]] +; CHECK: if.then11: +; CHECK-NEXT: store i32 1, i32* [[P:%.*]], align 4 +; CHECK-NEXT: fence acquire +; CHECK-NEXT: br label [[IF_END]] +; CHECK: if.end: +; CHECK-NEXT: store i32 1, i32* [[P]], align 4 +; CHECK-NEXT: br label [[WHILE_COND]] +; CHECK: while.end: +; CHECK-NEXT: br label [[IF_END12]] +; CHECK: if.end12: +; CHECK-NEXT: br label [[IF_END13]] +; CHECK: if.end13: +; CHECK-NEXT: br label [[IF_END14]] +; CHECK: if.end14: +; CHECK-NEXT: br label [[IF_END15]] +; CHECK: if.end15: +; CHECK-NEXT: store i32 0, i32* [[P]], align 4 +; CHECK-NEXT: ret void +; +entry: + %frombool = zext i1 %B to i8 + store i32 1, i32* %P, align 4 + %tobool = trunc i8 %frombool to i1 + br i1 %tobool, label %if.then, label %if.end15 + +if.then: ; preds = %entry + %tobool1 = trunc i8 %frombool to i1 + store i32 1, i32* %P, align 4 + br i1 %tobool1, label %if.then2, label %if.else + +if.then2: ; preds = %if.then + store i32 1, i32* %P, align 4 + br label %if.end14 + +if.else: ; preds = %if.then + %tobool3 = trunc i8 %frombool to i1 + store i32 1, i32* %P, align 4 + br i1 %tobool3, label %if.then4, label %if.else5 + +if.then4: ; preds = %if.else + store i32 1, i32* %P, align 4 + br label %if.end13 + +if.else5: ; preds = %if.else + %tobool6 = trunc i8 %frombool to i1 + store i32 1, i32* %P, align 4 + br i1 %tobool6, label %if.then7, label %if.else8 + +if.then7: ; preds = %if.else5 + store i32 1, i32* %P, align 4 + br label %if.end12 + +if.else8: ; preds = %if.else5 + store i32 1, i32* %P, align 4 + br label %while.cond + +while.cond: ; preds = %if.end, %if.else8 + %tobool9 = trunc i8 %frombool to i1 + store i32 1, i32* %P, align 4 + br i1 %tobool9, label %while.body, label %while.end + +while.body: ; preds = %while.cond + store i32 1, i32* %P, align 4 + br i1 %B, label %if.then11, label %if.end + +if.then11: ; preds = %while.body + store i32 1, i32* %P, align 4 + fence acquire + store i32 1, i32* %P, align 4 + br label %if.end + +if.end: ; preds = %if.then11, %while.body + store i32 1, i32* %P, align 4 + br label %while.cond + +while.end: ; preds = %while.cond + store i32 1, i32* %P, align 4 + br label %if.end12 + +if.end12: ; preds = %while.end, %if.then7 + store i32 1, i32* %P, align 4 + br label %if.end13 + +if.end13: ; preds = %if.end12, %if.then4 + store i32 1, i32* %P, align 4 + br label %if.end14 + +if.end14: ; preds = %if.end13, %if.then2 + store i32 1, i32* %P, align 4 + br label %if.end15 + +if.end15: ; preds = %if.end14, %entry + store i32 0, i32* %P, align 4 + ret void +} + +define void @test55(i32* %P, i1 %B) { +; CHECK-LABEL: @test55( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 +; CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[FROMBOOL]] to i1 +; CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END15:%.*]] +; CHECK: if.then: +; CHECK-NEXT: [[TOBOOL1:%.*]] = trunc i8 [[FROMBOOL]] to i1 +; CHECK-NEXT: br i1 [[TOBOOL1]], label [[IF_THEN2:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then2: +; CHECK-NEXT: br label [[IF_END14:%.*]] +; CHECK: if.else: +; CHECK-NEXT: [[TOBOOL3:%.*]] = trunc i8 [[FROMBOOL]] to i1 +; CHECK-NEXT: br i1 [[TOBOOL3]], label [[IF_THEN4:%.*]], label [[IF_ELSE5:%.*]] +; CHECK: if.then4: +; CHECK-NEXT: br label [[IF_END13:%.*]] +; CHECK: if.else5: +; CHECK-NEXT: [[TOBOOL6:%.*]] = trunc i8 [[FROMBOOL]] to i1 +; CHECK-NEXT: br i1 [[TOBOOL6]], label [[IF_THEN7:%.*]], label [[IF_ELSE8:%.*]] +; CHECK: if.then7: +; CHECK-NEXT: br label [[IF_END12:%.*]] +; CHECK: if.else8: +; CHECK-NEXT: br label [[WHILE_COND:%.*]] +; CHECK: while.cond: +; CHECK-NEXT: [[TOBOOL9:%.*]] = trunc i8 [[FROMBOOL]] to i1 +; CHECK-NEXT: br i1 [[TOBOOL9]], label [[WHILE_BODY:%.*]], label [[WHILE_END:%.*]] +; CHECK: while.body: +; CHECK-NEXT: br i1 [[B]], label [[IF_THEN11:%.*]], label [[IF_END:%.*]] +; CHECK: if.then11: +; CHECK-NEXT: br label [[IF_END]] +; CHECK: if.end: +; CHECK-NEXT: store i32 1, i32* [[P:%.*]], align 4 +; CHECK-NEXT: br label [[WHILE_COND]] +; CHECK: while.end: +; CHECK-NEXT: br label [[IF_END12]] +; CHECK: if.end12: +; CHECK-NEXT: br label [[IF_END13]] +; CHECK: if.end13: +; CHECK-NEXT: br label [[IF_END14]] +; CHECK: if.end14: +; CHECK-NEXT: br label [[IF_END15]] +; CHECK: if.end15: +; CHECK-NEXT: store i32 0, i32* [[P]], align 4 +; CHECK-NEXT: ret void +; +entry: + %frombool = zext i1 %B to i8 + store i32 1, i32* %P, align 4 + %tobool = trunc i8 %frombool to i1 + br i1 %tobool, label %if.then, label %if.end15 + +if.then: ; preds = %entry + store i32 1, i32* %P, align 4 + %tobool1 = trunc i8 %frombool to i1 + br i1 %tobool1, label %if.then2, label %if.else + +if.then2: ; preds = %if.then + store i32 1, i32* %P, align 4 + br label %if.end14 + +if.else: ; preds = %if.then + store i32 1, i32* %P, align 4 + %tobool3 = trunc i8 %frombool to i1 + br i1 %tobool3, label %if.then4, label %if.else5 + +if.then4: ; preds = %if.else + store i32 1, i32* %P, align 4 + br label %if.end13 + +if.else5: ; preds = %if.else + store i32 1, i32* %P, align 4 + %tobool6 = trunc i8 %frombool to i1 + br i1 %tobool6, label %if.then7, label %if.else8 + +if.then7: ; preds = %if.else5 + store i32 1, i32* %P, align 4 + br label %if.end12 + +if.else8: ; preds = %if.else5 + store i32 1, i32* %P, align 4 + br label %while.cond + +while.cond: ; preds = %if.end, %if.else8 + store i32 1, i32* %P, align 4 + %tobool9 = trunc i8 %frombool to i1 + br i1 %tobool9, label %while.body, label %while.end + +while.body: ; preds = %while.cond + store i32 1, i32* %P, align 4 + br i1 %B, label %if.then11, label %if.end + +if.then11: ; preds = %while.body + store i32 1, i32* %P, align 4 + br label %if.end + +if.end: ; preds = %if.then11, %while.body + store i32 1, i32* %P, align 4 + br label %while.cond + +while.end: ; preds = %while.cond + store i32 1, i32* %P, align 4 + br label %if.end12 + +if.end12: ; preds = %while.end, %if.then7 + store i32 1, i32* %P, align 4 + br label %if.end13 + +if.end13: ; preds = %if.end12, %if.then4 + store i32 1, i32* %P, align 4 + br label %if.end14 + +if.end14: ; preds = %if.end13, %if.then2 + store i32 1, i32* %P, align 4 + br label %if.end15 + +if.end15: ; preds = %if.end14, %entry + store i32 0, i32* %P, align 4 + ret void +} + +define void @test56(i32* %P, i1 %B) { +; CHECK-LABEL: @test56( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 +; CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[FROMBOOL]] to i1 +; CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END15:%.*]] +; CHECK: if.then: +; CHECK-NEXT: store i32 1, i32* [[P:%.*]], align 4 +; CHECK-NEXT: [[TOBOOL1:%.*]] = trunc i8 [[FROMBOOL]] to i1 +; CHECK-NEXT: call void @unknown_func() +; CHECK-NEXT: br i1 [[TOBOOL1]], label [[IF_THEN2:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then2: +; CHECK-NEXT: br label [[IF_END14:%.*]] +; CHECK: if.else: +; CHECK-NEXT: [[TOBOOL3:%.*]] = trunc i8 [[FROMBOOL]] to i1 +; CHECK-NEXT: br i1 [[TOBOOL3]], label [[IF_THEN4:%.*]], label [[IF_ELSE5:%.*]] +; CHECK: if.then4: +; CHECK-NEXT: br label [[IF_END13:%.*]] +; CHECK: if.else5: +; CHECK-NEXT: [[TOBOOL6:%.*]] = trunc i8 [[FROMBOOL]] to i1 +; CHECK-NEXT: br i1 [[TOBOOL6]], label [[IF_THEN7:%.*]], label [[IF_ELSE8:%.*]] +; CHECK: if.then7: +; CHECK-NEXT: store i32 1, i32* [[P]], align 4 +; CHECK-NEXT: call void @may_throw_func() +; CHECK-NEXT: br label [[IF_END12:%.*]] +; CHECK: if.else8: +; CHECK-NEXT: br label [[WHILE_COND:%.*]] +; CHECK: while.cond: +; CHECK-NEXT: [[TOBOOL9:%.*]] = trunc i8 [[FROMBOOL]] to i1 +; CHECK-NEXT: br i1 [[TOBOOL9]], label [[WHILE_BODY:%.*]], label [[WHILE_END:%.*]] +; CHECK: while.body: +; CHECK-NEXT: br i1 [[B]], label [[IF_THEN11:%.*]], label [[IF_END:%.*]] +; CHECK: if.then11: +; CHECK-NEXT: br label [[IF_END]] +; CHECK: if.end: +; CHECK-NEXT: store i32 1, i32* [[P]], align 4 +; CHECK-NEXT: br label [[WHILE_COND]] +; CHECK: while.end: +; CHECK-NEXT: br label [[IF_END12]] +; CHECK: if.end12: +; CHECK-NEXT: br label [[IF_END13]] +; CHECK: if.end13: +; CHECK-NEXT: br label [[IF_END14]] +; CHECK: if.end14: +; CHECK-NEXT: br label [[IF_END15]] +; CHECK: if.end15: +; CHECK-NEXT: call void @llvm.lifetime.end.p0i32(i64 -1, i32* [[P]]) +; CHECK-NEXT: ret void +; +entry: + %frombool = zext i1 %B to i8 + store i32 1, i32* %P, align 4 + %tobool = trunc i8 %frombool to i1 + br i1 %tobool, label %if.then, label %if.end15 + +if.then: ; preds = %entry + store i32 1, i32* %P, align 4 + %tobool1 = trunc i8 %frombool to i1 + call void @unknown_func() + br i1 %tobool1, label %if.then2, label %if.else + +if.then2: ; preds = %if.then + store i32 1, i32* %P, align 4 + br label %if.end14 + +if.else: ; preds = %if.then + store i32 1, i32* %P, align 4 + %tobool3 = trunc i8 %frombool to i1 + br i1 %tobool3, label %if.then4, label %if.else5 + +if.then4: ; preds = %if.else + store i32 1, i32* %P, align 4 + br label %if.end13 + +if.else5: ; preds = %if.else + store i32 1, i32* %P, align 4 + %tobool6 = trunc i8 %frombool to i1 + br i1 %tobool6, label %if.then7, label %if.else8 + +if.then7: ; preds = %if.else5 + store i32 1, i32* %P, align 4 + call void @may_throw_func() + br label %if.end12 + +if.else8: ; preds = %if.else5 + store i32 1, i32* %P, align 4 + br label %while.cond + +while.cond: ; preds = %if.end, %if.else8 + store i32 1, i32* %P, align 4 + %tobool9 = trunc i8 %frombool to i1 + br i1 %tobool9, label %while.body, label %while.end + +while.body: ; preds = %while.cond + store i32 1, i32* %P, align 4 + br i1 %B, label %if.then11, label %if.end + +if.then11: ; preds = %while.body + store i32 1, i32* %P, align 4 + br label %if.end + +if.end: ; preds = %if.then11, %while.body + store i32 1, i32* %P, align 4 + br label %while.cond + +while.end: ; preds = %while.cond + store i32 1, i32* %P, align 4 + br label %if.end12 + +if.end12: ; preds = %while.end, %if.then7 + store i32 1, i32* %P, align 4 + br label %if.end13 + +if.end13: ; preds = %if.end12, %if.then4 + store i32 1, i32* %P, align 4 + br label %if.end14 + +if.end14: ; preds = %if.end13, %if.then2 + store i32 1, i32* %P, align 4 + br label %if.end15 + +if.end15: ; preds = %if.end14, %entry + call void @llvm.lifetime.end.p0i32(i64 -1, i32* %P) + ret void +} + +define void @test56A(i1 %B) { +; CHECK-LABEL: @test56A( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[P:%.*]] = alloca i32, align 1 +; CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8 +; CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[FROMBOOL]] to i1 +; CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END15:%.*]] +; CHECK: if.then: +; CHECK-NEXT: [[TOBOOL1:%.*]] = trunc i8 [[FROMBOOL]] to i1 +; CHECK-NEXT: br i1 [[TOBOOL1]], label [[IF_THEN2:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then2: +; CHECK-NEXT: br label [[IF_END14:%.*]] +; CHECK: if.else: +; CHECK-NEXT: [[TOBOOL3:%.*]] = trunc i8 [[FROMBOOL]] to i1 +; CHECK-NEXT: br i1 [[TOBOOL3]], label [[IF_THEN4:%.*]], label [[IF_ELSE5:%.*]] +; CHECK: if.then4: +; CHECK-NEXT: br label [[IF_END13:%.*]] +; CHECK: if.else5: +; CHECK-NEXT: [[TOBOOL6:%.*]] = trunc i8 [[FROMBOOL]] to i1 +; CHECK-NEXT: br i1 [[TOBOOL6]], label [[IF_THEN7:%.*]], label [[IF_ELSE8:%.*]] +; CHECK: if.then7: +; CHECK-NEXT: br label [[IF_END12:%.*]] +; CHECK: if.else8: +; CHECK-NEXT: br label [[WHILE_COND:%.*]] +; CHECK: while.cond: +; CHECK-NEXT: [[TOBOOL9:%.*]] = trunc i8 [[FROMBOOL]] to i1 +; CHECK-NEXT: br i1 [[TOBOOL9]], label [[WHILE_BODY:%.*]], label [[WHILE_END:%.*]] +; CHECK: while.body: +; CHECK-NEXT: br i1 [[B]], label [[IF_THEN11:%.*]], label [[IF_END:%.*]] +; CHECK: if.then11: +; CHECK-NEXT: br label [[IF_END]] +; CHECK: if.end: +; CHECK-NEXT: store i32 1, i32* [[P]], align 4 +; CHECK-NEXT: br label [[WHILE_COND]] +; CHECK: while.end: +; CHECK-NEXT: br label [[IF_END12]] +; CHECK: if.end12: +; CHECK-NEXT: br label [[IF_END13]] +; CHECK: if.end13: +; CHECK-NEXT: br label [[IF_END14]] +; CHECK: if.end14: +; CHECK-NEXT: br label [[IF_END15]] +; CHECK: if.end15: +; CHECK-NEXT: ret void +; +entry: + %P = alloca i32, i32 1, align 1 + %frombool = zext i1 %B to i8 + store i32 1, i32* %P, align 4 + %tobool = trunc i8 %frombool to i1 + br i1 %tobool, label %if.then, label %if.end15 + +if.then: ; preds = %entry + store i32 1, i32* %P, align 4 + %tobool1 = trunc i8 %frombool to i1 + br i1 %tobool1, label %if.then2, label %if.else + +if.then2: ; preds = %if.then + store i32 1, i32* %P, align 4 + br label %if.end14 + +if.else: ; preds = %if.then + store i32 1, i32* %P, align 4 + %tobool3 = trunc i8 %frombool to i1 + br i1 %tobool3, label %if.then4, label %if.else5 + +if.then4: ; preds = %if.else + store i32 1, i32* %P, align 4 + br label %if.end13 + +if.else5: ; preds = %if.else + store i32 1, i32* %P, align 4 + %tobool6 = trunc i8 %frombool to i1 + br i1 %tobool6, label %if.then7, label %if.else8 + +if.then7: ; preds = %if.else5 + store i32 1, i32* %P, align 4 + br label %if.end12 + +if.else8: ; preds = %if.else5 + store i32 1, i32* %P, align 4 + br label %while.cond + +while.cond: ; preds = %if.end, %if.else8 + store i32 1, i32* %P, align 4 + %tobool9 = trunc i8 %frombool to i1 + br i1 %tobool9, label %while.body, label %while.end + +while.body: ; preds = %while.cond + store i32 1, i32* %P, align 4 + br i1 %B, label %if.then11, label %if.end + +if.then11: ; preds = %while.body + store i32 1, i32* %P, align 4 + br label %if.end + +if.end: ; preds = %if.then11, %while.body + store i32 1, i32* %P, align 4 + br label %while.cond + +while.end: ; preds = %while.cond + store i32 1, i32* %P, align 4 + br label %if.end12 + +if.end12: ; preds = %while.end, %if.then7 + store i32 1, i32* %P, align 4 + br label %if.end13 + +if.end13: ; preds = %if.end12, %if.then4 + store i32 1, i32* %P, align 4 + br label %if.end14 + +if.end14: ; preds = %if.end13, %if.then2 + store i32 1, i32* %P, align 4 + br label %if.end15 + +if.end15: ; preds = %if.end14, %entry + store i32 1, i32* %P, align 4 + ret void +} + +define void @test57(i32* %P, i1 zeroext %B) #0 { +; CHECK-LABEL: @test57( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 false, label [[IF_THEN:%.*]], label [[IF_END:%.*]] +; CHECK: if.then: +; CHECK-NEXT: [[TMP0:%.*]] = bitcast i32* [[P:%.*]] to i64* +; CHECK-NEXT: store i64 0, i64* [[TMP0]], align 8 +; CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds i32, i32* [[P]], i64 1 +; CHECK-NEXT: store i32 1, i32* [[ADD_PTR]], align 4 +; CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[P]], align 4 +; CHECK-NEXT: [[TOBOOL1:%.*]] = icmp ne i32 [[TMP1]], 0 +; CHECK-NEXT: [[FROMBOOL2:%.*]] = zext i1 [[TOBOOL1]] to i8 +; CHECK-NEXT: br label [[IF_END]] +; CHECK: if.end: +; CHECK-NEXT: store i32 0, i32* [[P]], align 4 +; CHECK-NEXT: ret void +; +entry: + store i32 1, i32* %P, align 4 + br i1 0, label %if.then, label %if.end + +if.then: ; preds = %entry + %0 = bitcast i32* %P to i64* + store i64 0, i64* %0, align 8 + %add.ptr = getelementptr inbounds i32, i32* %P, i64 1 + store i32 1, i32* %add.ptr, align 4 + %1 = load i32, i32* %P, align 4 + %tobool1 = icmp ne i32 %1, 0 + %frombool2 = zext i1 %tobool1 to i8 + br label %if.end + +if.end: ; preds = %if.then, %entry + store i32 0, i32* %P, align 4 + ret void +} Index: llvm/test/Transforms/DeadStoreElimination/non-escaping-ptr.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/DeadStoreElimination/non-escaping-ptr.ll @@ -0,0 +1,269 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt %s -basicaa -dse -enable-dse-memoryssa -S | FileCheck %s + +target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64" + +declare i32* @return_first(i32* returned, i32*) +declare i32* @return_second(i32*, i32* returned) + +define void @test1() { +; CHECK-LABEL: @test1( +; CHECK-NEXT: ret void +; + %P = alloca i32, i32 1, align 1 + store i32 0, i32* %P + ret void +} + +define void @test2() { +; CHECK-LABEL: @test2( +; CHECK-NEXT: ret void +; + %P = alloca i32, i32 1, align 1 + %P1 = bitcast i32* %P to i8* + store i8 0, i8* %P1 + ret void +} + +define void @test3() { +; CHECK-LABEL: @test3( +; CHECK-NEXT: ret void +; + %P = alloca i32, i32 4, align 1 + %P1 = bitcast i32* %P to i8* + %P2 = bitcast i8* %P1 to i32* + %P2.gep = getelementptr i32, i32* %P2, i32 4 + %P3 = bitcast i32* %P2.gep to i8* + %P4 = bitcast i8* %P3 to i32* + %P5 = bitcast i32* %P4 to i8* + store i8 0, i8* %P5 + ret void +} + +define void @test4() { +; CHECK-LABEL: @test4( +; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] +; CHECK: bb1: +; CHECK-NEXT: br label [[BB3:%.*]] +; CHECK: bb2: +; CHECK-NEXT: br label [[BB3]] +; CHECK: bb3: +; CHECK-NEXT: ret void +; + %P = alloca i32, i32 4, align 1 + %P1 = bitcast i32* %P to i8* + %P2 = bitcast i8* %P1 to i32* + %P2.gep = getelementptr i32, i32* %P2, i32 4 + br i1 true, label %bb1, label %bb2 +bb1: + %P3.1 = bitcast i32* %P2.gep to i8* + br label %bb3 +bb2: + %P3.2 = bitcast i32* %P2.gep to i8* + br label %bb3 +bb3: + %P3 = phi i8* [ %P3.1, %bb1 ], [%P3.2, %bb2 ] + %P4 = bitcast i8* %P3 to i32* + %P5 = bitcast i32* %P4 to i8* + store i8 0, i8* %P5 + ret void +} + +define void @test5() { +; CHECK-LABEL: @test5( +; CHECK-NEXT: [[P:%.*]] = alloca i32, i32 4, align 1 +; CHECK-NEXT: [[P1:%.*]] = bitcast i32* [[P]] to i8* +; CHECK-NEXT: [[P2:%.*]] = bitcast i8* [[P1]] to i32* +; CHECK-NEXT: [[P2_GEP:%.*]] = getelementptr i32, i32* [[P2]], i32 4 +; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] +; CHECK: bb1: +; CHECK-NEXT: [[P3_3:%.*]] = call i32* @return_first(i32* [[P2_GEP]], i32* null) +; CHECK-NEXT: br label [[BB3:%.*]] +; CHECK: bb2: +; CHECK-NEXT: [[P3_3_I:%.*]] = call i32* @return_second(i32* null, i32* [[P2_GEP]]) +; CHECK-NEXT: br label [[BB3]] +; CHECK: bb3: +; CHECK-NEXT: ret void +; + %P = alloca i32, i32 4, align 1 + %P1 = bitcast i32* %P to i8* + %P2 = bitcast i8* %P1 to i32* + %P2.gep = getelementptr i32, i32* %P2, i32 4 + br i1 true, label %bb1, label %bb2 +bb1: + %P3.3 = call i32* @return_first(i32* %P2.gep, i32* null) + %P3.1 = bitcast i32* %P3.3 to i8* + br label %bb3 +bb2: + %P3.3.i = call i32* @return_second(i32* null, i32* %P2.gep) + %P3.1.i = bitcast i32* %P3.3.i to i8* + br label %bb3 +bb3: + %P3 = phi i8* [ %P3.1, %bb1 ], [%P3.1.i, %bb2 ] + %P4 = bitcast i8* %P3 to i32* + %P5 = bitcast i32* %P4 to i8* + store i8 0, i8* %P5 + ret void +} + +define void @test6() { +; CHECK-LABEL: @test6( +; CHECK-NEXT: [[P:%.*]] = alloca i32, i32 4, align 1 +; CHECK-NEXT: [[P1:%.*]] = bitcast i32* [[P]] to i8* +; CHECK-NEXT: [[P2:%.*]] = bitcast i8* [[P1]] to i32* +; CHECK-NEXT: [[P2_GEP:%.*]] = getelementptr i32, i32* [[P2]], i32 4 +; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] +; CHECK: bb1: +; CHECK-NEXT: [[P3_3:%.*]] = call i32* @return_first(i32* [[P2_GEP]], i32* null) +; CHECK-NEXT: [[P3_1:%.*]] = bitcast i32* [[P3_3]] to i8* +; CHECK-NEXT: br label [[BB3:%.*]] +; CHECK: bb2: +; CHECK-NEXT: [[P3_3_I:%.*]] = call i32* @return_second(i32* [[P2_GEP]], i32* null) +; CHECK-NEXT: [[P3_1_I:%.*]] = bitcast i32* [[P3_3_I]] to i8* +; CHECK-NEXT: br label [[BB3]] +; CHECK: bb3: +; CHECK-NEXT: [[P3:%.*]] = phi i8* [ [[P3_1]], [[BB1]] ], [ [[P3_1_I]], [[BB2]] ] +; CHECK-NEXT: [[P4:%.*]] = bitcast i8* [[P3]] to i32* +; CHECK-NEXT: [[P5:%.*]] = bitcast i32* [[P4]] to i8* +; CHECK-NEXT: store i8 0, i8* [[P5]] +; CHECK-NEXT: ret void +; + %P = alloca i32, i32 4, align 1 + %P1 = bitcast i32* %P to i8* + %P2 = bitcast i8* %P1 to i32* + %P2.gep = getelementptr i32, i32* %P2, i32 4 + br i1 true, label %bb1, label %bb2 +bb1: + %P3.3 = call i32* @return_first(i32* %P2.gep, i32* null) + %P3.1 = bitcast i32* %P3.3 to i8* + br label %bb3 +bb2: + %P3.3.i = call i32* @return_second(i32* %P2.gep, i32* null) + %P3.1.i = bitcast i32* %P3.3.i to i8* + br label %bb3 +bb3: + %P3 = phi i8* [ %P3.1, %bb1 ], [%P3.1.i, %bb2 ] + %P4 = bitcast i8* %P3 to i32* + %P5 = bitcast i32* %P4 to i8* + store i8 0, i8* %P5 + ret void +} + +define void @testA1(i32* %P) { +; CHECK-LABEL: @testA1( +; CHECK-NEXT: store i32 0, i32* [[P:%.*]] +; CHECK-NEXT: ret void +; + store i32 0, i32* %P + ret void +} + +define void @testA2(i32* %P) { +; CHECK-LABEL: @testA2( +; CHECK-NEXT: [[P1:%.*]] = bitcast i32* [[P:%.*]] to i8* +; CHECK-NEXT: store i8 0, i8* [[P1]] +; CHECK-NEXT: ret void +; + %P1 = bitcast i32* %P to i8* + store i8 0, i8* %P1 + ret void +} + +define void @testA3(i32* %P) { +; CHECK-LABEL: @testA3( +; CHECK-NEXT: [[P1:%.*]] = bitcast i32* [[P:%.*]] to i8* +; CHECK-NEXT: [[P2:%.*]] = bitcast i8* [[P1]] to i32* +; CHECK-NEXT: [[P2_GEP:%.*]] = getelementptr i32, i32* [[P2]], i32 4 +; CHECK-NEXT: [[P3:%.*]] = bitcast i32* [[P2_GEP]] to i8* +; CHECK-NEXT: [[P4:%.*]] = bitcast i8* [[P3]] to i32* +; CHECK-NEXT: [[P5:%.*]] = bitcast i32* [[P4]] to i8* +; CHECK-NEXT: store i8 0, i8* [[P5]] +; CHECK-NEXT: ret void +; + %P1 = bitcast i32* %P to i8* + %P2 = bitcast i8* %P1 to i32* + %P2.gep = getelementptr i32, i32* %P2, i32 4 + %P3 = bitcast i32* %P2.gep to i8* + %P4 = bitcast i8* %P3 to i32* + %P5 = bitcast i32* %P4 to i8* + store i8 0, i8* %P5 + ret void +} + +define void @testA4(i32* %P) { +; CHECK-LABEL: @testA4( +; CHECK-NEXT: [[P1:%.*]] = bitcast i32* [[P:%.*]] to i8* +; CHECK-NEXT: [[P2:%.*]] = bitcast i8* [[P1]] to i32* +; CHECK-NEXT: [[P2_GEP:%.*]] = getelementptr i32, i32* [[P2]], i32 4 +; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] +; CHECK: bb1: +; CHECK-NEXT: [[P3_1:%.*]] = bitcast i32* [[P2_GEP]] to i8* +; CHECK-NEXT: br label [[BB3:%.*]] +; CHECK: bb2: +; CHECK-NEXT: [[P3_2:%.*]] = bitcast i32* [[P2_GEP]] to i8* +; CHECK-NEXT: br label [[BB3]] +; CHECK: bb3: +; CHECK-NEXT: [[P3:%.*]] = phi i8* [ [[P3_1]], [[BB1]] ], [ [[P3_2]], [[BB2]] ] +; CHECK-NEXT: [[P4:%.*]] = bitcast i8* [[P3]] to i32* +; CHECK-NEXT: [[P5:%.*]] = bitcast i32* [[P4]] to i8* +; CHECK-NEXT: store i8 0, i8* [[P5]] +; CHECK-NEXT: ret void +; + %P1 = bitcast i32* %P to i8* + %P2 = bitcast i8* %P1 to i32* + %P2.gep = getelementptr i32, i32* %P2, i32 4 + br i1 true, label %bb1, label %bb2 +bb1: + %P3.1 = bitcast i32* %P2.gep to i8* + br label %bb3 +bb2: + %P3.2 = bitcast i32* %P2.gep to i8* + br label %bb3 +bb3: + %P3 = phi i8* [ %P3.1, %bb1 ], [%P3.2, %bb2 ] + %P4 = bitcast i8* %P3 to i32* + %P5 = bitcast i32* %P4 to i8* + store i8 0, i8* %P5 + ret void +} + +define void @testA5(i32* %P) { +; CHECK-LABEL: @testA5( +; CHECK-NEXT: [[P1:%.*]] = bitcast i32* [[P:%.*]] to i8* +; CHECK-NEXT: [[P2:%.*]] = bitcast i8* [[P1]] to i32* +; CHECK-NEXT: [[P2_GEP:%.*]] = getelementptr i32, i32* [[P2]], i32 4 +; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] +; CHECK: bb1: +; CHECK-NEXT: [[P3_3:%.*]] = call i32* @return_first(i32* [[P2_GEP]], i32* null) +; CHECK-NEXT: [[P3_1:%.*]] = bitcast i32* [[P3_3]] to i8* +; CHECK-NEXT: br label [[BB3:%.*]] +; CHECK: bb2: +; CHECK-NEXT: [[P3_3_I:%.*]] = call i32* @return_second(i32* null, i32* [[P2_GEP]]) +; CHECK-NEXT: [[P3_1_I:%.*]] = bitcast i32* [[P3_3_I]] to i8* +; CHECK-NEXT: br label [[BB3]] +; CHECK: bb3: +; CHECK-NEXT: [[P3:%.*]] = phi i8* [ [[P3_1]], [[BB1]] ], [ [[P3_1_I]], [[BB2]] ] +; CHECK-NEXT: [[P4:%.*]] = bitcast i8* [[P3]] to i32* +; CHECK-NEXT: [[P5:%.*]] = bitcast i32* [[P4]] to i8* +; CHECK-NEXT: store i8 0, i8* [[P5]] +; CHECK-NEXT: ret void +; + %P1 = bitcast i32* %P to i8* + %P2 = bitcast i8* %P1 to i32* + %P2.gep = getelementptr i32, i32* %P2, i32 4 + br i1 true, label %bb1, label %bb2 +bb1: + %P3.3 = call i32* @return_first(i32* %P2.gep, i32* null) + %P3.1 = bitcast i32* %P3.3 to i8* + br label %bb3 +bb2: + %P3.3.i = call i32* @return_second(i32* null, i32* %P2.gep) + %P3.1.i = bitcast i32* %P3.3.i to i8* + br label %bb3 +bb3: + %P3 = phi i8* [ %P3.1, %bb1 ], [%P3.1.i, %bb2 ] + %P4 = bitcast i8* %P3 to i32* + %P5 = bitcast i32* %P4 to i8* + store i8 0, i8* %P5 + ret void +}