From 33e17b4040fa9c2c3b7f8313cb82bfe0720c469c Mon Sep 17 00:00:00 2001 From: Daniel Berlin Date: Sat, 18 Feb 2017 23:06:38 +0000 Subject: [PATCH] PredicateInfo: Clean up predicate info a little, using insertion helpers, and fixing support for the renaming the comparison. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@295581 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Transforms/Utils/PredicateInfo.h | 20 +-- lib/Transforms/Utils/PredicateInfo.cpp | 160 ++++++++++++++---------- test/Transforms/Util/PredicateInfo/condprop.ll | 3 +- test/Transforms/Util/PredicateInfo/testandor.ll | 20 +-- 4 files changed, 119 insertions(+), 84 deletions(-) diff --git a/include/llvm/Transforms/Utils/PredicateInfo.h b/include/llvm/Transforms/Utils/PredicateInfo.h index b1965831135..d9604d3421f 100644 --- a/include/llvm/Transforms/Utils/PredicateInfo.h +++ b/include/llvm/Transforms/Utils/PredicateInfo.h @@ -103,15 +103,15 @@ public: // This can be use by passes, when destroying predicateinfo, to know // whether they can just drop the intrinsic, or have to merge metadata. Value *OriginalOp; - CmpInst *Comparison; + Value *Condition; PredicateBase(const PredicateBase &) = delete; PredicateBase &operator=(const PredicateBase &) = delete; PredicateBase() = delete; virtual ~PredicateBase() = default; protected: - PredicateBase(PredicateType PT, Value *Op, CmpInst *Comparison) - : Type(PT), OriginalOp(Op), Comparison(Comparison) {} + PredicateBase(PredicateType PT, Value *Op, Value *Condition) + : Type(PT), OriginalOp(Op), Condition(Condition) {} }; // Provides predicate information for assumes. Since assumes are always true, @@ -120,8 +120,8 @@ protected: class PredicateAssume : public PredicateBase { public: IntrinsicInst *AssumeInst; - PredicateAssume(Value *Op, IntrinsicInst *AssumeInst, CmpInst *Comparison) - : PredicateBase(PT_Assume, Op, Comparison), AssumeInst(AssumeInst) {} + PredicateAssume(Value *Op, IntrinsicInst *AssumeInst, Value *Condition) + : PredicateBase(PT_Assume, Op, Condition), AssumeInst(AssumeInst) {} PredicateAssume() = delete; static inline bool classof(const PredicateBase *PB) { return PB->Type == PT_Assume; @@ -131,15 +131,15 @@ public: // Provides predicate information for branches. class PredicateBranch : public PredicateBase { public: - // This is the block that is conditional upon the comparison. + // This is the block that is conditional upon the condition. BasicBlock *BranchBB; // This is one of the true/false successors of BranchBB. BasicBlock *SplitBB; // If true, SplitBB is the true successor, otherwise it's the false successor. bool TrueEdge; PredicateBranch(Value *Op, BasicBlock *BranchBB, BasicBlock *SplitBB, - CmpInst *Comparison, bool TakenEdge) - : PredicateBase(PT_Branch, Op, Comparison), BranchBB(BranchBB), + Value *Condition, bool TakenEdge) + : PredicateBase(PT_Branch, Op, Condition), BranchBB(BranchBB), SplitBB(SplitBB), TrueEdge(TakenEdge) {} PredicateBranch() = delete; static inline bool classof(const PredicateBase *PB) { @@ -197,6 +197,8 @@ private: bool stackIsInScope(const ValueDFSStack &, const ValueDFS &) const; void popStackUntilDFSScope(ValueDFSStack &, const ValueDFS &); ValueInfo &getOrCreateValueInfo(Value *); + void addInfoFor(SmallPtrSetImpl &OpsToRename, Value *Op, + PredicateBase *PB); const ValueInfo &getValueInfo(Value *) const; Function &F; DominatorTree &DT; @@ -217,7 +219,7 @@ private: DenseMap> OBBMap; // The set of edges along which we can only handle phi uses, due to critical // edges. - DenseSet PhiUsesOnly; + DenseSet> EdgeUsesOnly; }; // This pass does eager building and then printing of PredicateInfo. It is used diff --git a/lib/Transforms/Utils/PredicateInfo.cpp b/lib/Transforms/Utils/PredicateInfo.cpp index 9762f4fc963..cd3974db8c7 100644 --- a/lib/Transforms/Utils/PredicateInfo.cpp +++ b/lib/Transforms/Utils/PredicateInfo.cpp @@ -69,9 +69,9 @@ struct ValueDFS { // Only one of Def or Use will be set. Value *Def = nullptr; Use *U = nullptr; - // Neither PInfo nor PhiOnly participate in the ordering + // Neither PInfo nor EdgeOnly participate in the ordering PredicateBase *PInfo = nullptr; - bool PhiOnly = false; + bool EdgeOnly = false; }; // This compares ValueDFS structures, creating OrderedBasicBlocks where @@ -195,22 +195,26 @@ bool PredicateInfo::stackIsInScope(const ValueDFSStack &Stack, return false; // If it's a phi only use, make sure it's for this phi node edge, and that the // use is in a phi node. If it's anything else, and the top of the stack is - // phionly, we need to pop the stack. We deliberately sort phi uses next to + // EdgeOnly, we need to pop the stack. We deliberately sort phi uses next to // the defs they must go with so that we can know it's time to pop the stack // when we hit the end of the phi uses for a given def. - if (Stack.back().PhiOnly) { + if (Stack.back().EdgeOnly) { if (!VDUse.U) return false; auto *PHI = dyn_cast(VDUse.U->getUser()); if (!PHI) return false; - // The only phionly defs should be branch info. + // The only EdgeOnly defs should be branch info. auto *PBranch = dyn_cast(Stack.back().PInfo); - assert(PBranch && "Only branches should have PHIOnly defs"); - // Check edge + assert(PBranch && "Only branches should have EdgeOnly defs"); + // Check edge matches us. BasicBlock *EdgePred = PHI->getIncomingBlock(*VDUse.U); if (EdgePred != PBranch->BranchBB) return false; + + // Use dominates, which knows how to handle edge dominance. + return DT.dominates(BasicBlockEdge(PBranch->BranchBB, PBranch->SplitBB), + *VDUse.U); } return (VDUse.DFSIn >= Stack.back().DFSIn && @@ -267,49 +271,57 @@ void collectCmpOps(CmpInst *Comparison, SmallVectorImpl &CmpOperands) { // are only being used in the comparison, which means they will not be useful // for us to consider for predicateinfo. // - // FIXME: LLVM crashes trying to create an intrinsic declaration of some - // pointer to function types that return structs, so we avoid them. - if ((isa(Op0) || isa(Op0)) && !Op0->hasOneUse() && - !(Op0->getType()->isPointerTy() && - Op0->getType()->getPointerElementType()->isFunctionTy())) + if ((isa(Op0) || isa(Op0)) && !Op0->hasOneUse()) CmpOperands.push_back(Op0); - if ((isa(Op1) || isa(Op1)) && !Op1->hasOneUse() && - !(Op1->getType()->isPointerTy() && - Op1->getType()->getPointerElementType()->isFunctionTy())) + if ((isa(Op1) || isa(Op1)) && !Op1->hasOneUse()) CmpOperands.push_back(Op1); } +// Add Op, PB to the list of value infos for Op, and mark Op to be renamed. +void PredicateInfo::addInfoFor(SmallPtrSetImpl &OpsToRename, Value *Op, + PredicateBase *PB) { + OpsToRename.insert(Op); + auto &OperandInfo = getOrCreateValueInfo(Op); + AllInfos.push_back(PB); + OperandInfo.Infos.push_back(PB); +} + // Process an assume instruction and place relevant operations we want to rename // into OpsToRename. void PredicateInfo::processAssume(IntrinsicInst *II, BasicBlock *AssumeBB, SmallPtrSetImpl &OpsToRename) { + // See if we have a comparison we support SmallVector CmpOperands; - // Second, see if we have a comparison we support - SmallVector ComparisonsToProcess; + SmallVector ConditionsToProcess; CmpInst::Predicate Pred; Value *Operand = II->getOperand(0); if (m_c_And(m_Cmp(Pred, m_Value(), m_Value()), m_Cmp(Pred, m_Value(), m_Value())) .match(II->getOperand(0))) { - ComparisonsToProcess.push_back( - cast(Operand)->getOperand(0)); - ComparisonsToProcess.push_back( - cast(Operand)->getOperand(1)); - } else { - ComparisonsToProcess.push_back(Operand); + ConditionsToProcess.push_back(cast(Operand)->getOperand(0)); + ConditionsToProcess.push_back(cast(Operand)->getOperand(1)); + ConditionsToProcess.push_back(Operand); + } else if (isa(Operand)) { + + ConditionsToProcess.push_back(Operand); } - for (auto Comparison : ComparisonsToProcess) { - if (auto *Cmp = dyn_cast(Comparison)) { + for (auto Cond : ConditionsToProcess) { + if (auto *Cmp = dyn_cast(Cond)) { collectCmpOps(Cmp, CmpOperands); // Now add our copy infos for our operands for (auto *Op : CmpOperands) { - OpsToRename.insert(Op); - auto &OperandInfo = getOrCreateValueInfo(Op); - PredicateBase *PB = new PredicateAssume(Op, II, Cmp); - AllInfos.push_back(PB); - OperandInfo.Infos.push_back(PB); + auto *PA = new PredicateAssume(Op, II, Cmp); + addInfoFor(OpsToRename, Op, PA); } CmpOperands.clear(); + } else if (auto *BinOp = dyn_cast(Cond)) { + // Otherwise, it should be an AND. + assert(BinOp->getOpcode() == Instruction::And && + "Should have been an and"); + auto *PA = new PredicateAssume(Cond, II, Cond); + addInfoFor(OpsToRename, Cond, PA); + } else { + llvm_unreachable("Unknown type of condition"); } } } @@ -318,19 +330,37 @@ void PredicateInfo::processAssume(IntrinsicInst *II, BasicBlock *AssumeBB, // renamed into OpsToRename. void PredicateInfo::processBranch(BranchInst *BI, BasicBlock *BranchBB, SmallPtrSetImpl &OpsToRename) { - SmallVector CmpOperands; BasicBlock *FirstBB = BI->getSuccessor(0); BasicBlock *SecondBB = BI->getSuccessor(1); SmallVector SuccsToProcess; - bool isAnd = false; - bool isOr = false; SuccsToProcess.push_back(FirstBB); SuccsToProcess.push_back(SecondBB); - // Second, see if we have a comparison we support - SmallVector ComparisonsToProcess; - CmpInst::Predicate Pred; + SmallVector ConditionsToProcess; + + auto InsertHelper = [&](Value *Op, bool isAnd, bool isOr, Value *Cond) { + for (auto *Succ : SuccsToProcess) { + // Don't try to insert on a self-edge. This is mainly because we will + // eliminate during renaming anyway. + if (Succ == BranchBB) + continue; + bool TakenEdge = (Succ == FirstBB); + // For and, only insert on the true edge + // For or, only insert on the false edge + if ((isAnd && !TakenEdge) || (isOr && TakenEdge)) + continue; + PredicateBase *PB = + new PredicateBranch(Op, BranchBB, Succ, Cond, TakenEdge); + addInfoFor(OpsToRename, Op, PB); + if (!Succ->getSinglePredecessor()) + EdgeUsesOnly.insert({BranchBB, Succ}); + } + }; // Match combinations of conditions. + CmpInst::Predicate Pred; + bool isAnd = false; + bool isOr = false; + SmallVector CmpOperands; if (match(BI->getCondition(), m_And(m_Cmp(Pred, m_Value(), m_Value()), m_Cmp(Pred, m_Value(), m_Value()))) || match(BI->getCondition(), m_Or(m_Cmp(Pred, m_Value(), m_Value()), @@ -340,34 +370,30 @@ void PredicateInfo::processBranch(BranchInst *BI, BasicBlock *BranchBB, isAnd = true; else if (BinOp->getOpcode() == Instruction::Or) isOr = true; - ComparisonsToProcess.push_back(BinOp->getOperand(0)); - ComparisonsToProcess.push_back(BinOp->getOperand(1)); - } else { - ComparisonsToProcess.push_back(BI->getCondition()); + ConditionsToProcess.push_back(BinOp->getOperand(0)); + ConditionsToProcess.push_back(BinOp->getOperand(1)); + ConditionsToProcess.push_back(BI->getCondition()); + } else if (isa(BI->getCondition())) { + ConditionsToProcess.push_back(BI->getCondition()); } - for (auto Comparison : ComparisonsToProcess) { - if (auto *Cmp = dyn_cast(Comparison)) { + for (auto Cond : ConditionsToProcess) { + if (auto *Cmp = dyn_cast(Cond)) { collectCmpOps(Cmp, CmpOperands); // Now add our copy infos for our operands - for (auto *Op : CmpOperands) { - OpsToRename.insert(Op); - auto &OperandInfo = getOrCreateValueInfo(Op); - for (auto *Succ : SuccsToProcess) { - bool TakenEdge = (Succ == FirstBB); - // For and, only insert on the true edge - // For or, only insert on the false edge - if ((isAnd && !TakenEdge) || (isOr && TakenEdge)) - continue; - PredicateBase *PB = - new PredicateBranch(Op, BranchBB, Succ, Cmp, TakenEdge); - AllInfos.push_back(PB); - OperandInfo.Infos.push_back(PB); - if (!Succ->getSinglePredecessor()) - PhiUsesOnly.insert({BranchBB, Succ}); - } - } - CmpOperands.clear(); + for (auto *Op : CmpOperands) + InsertHelper(Op, isAnd, isOr, Cmp); + } else if (auto *BinOp = dyn_cast(Cond)) { + // This must be an AND or an OR. + assert((BinOp->getOpcode() == Instruction::And || + BinOp->getOpcode() == Instruction::Or) && + "Should have been an AND or an OR"); + // The actual value of the binop is not subject to the same restrictions + // as the comparison. It's either true or false on the true/false branch. + InsertHelper(Cond, false, false, Cond); + } else { + llvm_unreachable("Unknown type of condition"); } + CmpOperands.clear(); } } @@ -421,7 +447,8 @@ Value *PredicateInfo::materializeStack(unsigned int &Counter, IRBuilder<> B(PBranch->BranchBB->getTerminator()); Function *IF = Intrinsic::getDeclaration( F.getParent(), Intrinsic::ssa_copy, Op->getType()); - Value *PIC = B.CreateCall(IF, Op, Op->getName() + "." + Twine(Counter++)); + CallInst *PIC = + B.CreateCall(IF, Op, Op->getName() + "." + Twine(Counter++)); PredicateMap.insert({PIC, ValInfo}); Result.Def = PIC; } else { @@ -431,7 +458,7 @@ Value *PredicateInfo::materializeStack(unsigned int &Counter, IRBuilder<> B(PAssume->AssumeInst); Function *IF = Intrinsic::getDeclaration( F.getParent(), Intrinsic::ssa_copy, Op->getType()); - Value *PIC = B.CreateCall(IF, Op); + CallInst *PIC = B.CreateCall(IF, Op); PredicateMap.insert({PIC, ValInfo}); Result.Def = PIC; } @@ -489,14 +516,14 @@ void PredicateInfo::renameUses(SmallPtrSetImpl &OpsToRename) { // If we can only do phi uses, we treat it like it's in the branch // block, and handle it specially. We know that it goes last, and only // dominate phi uses. - if (PhiUsesOnly.count({PBranch->BranchBB, PBranch->SplitBB})) { + if (EdgeUsesOnly.count({PBranch->BranchBB, PBranch->SplitBB})) { VD.LocalNum = LN_Last; auto *DomNode = DT.getNode(PBranch->BranchBB); if (DomNode) { VD.DFSIn = DomNode->getDFSNumIn(); VD.DFSOut = DomNode->getDFSNumOut(); VD.PInfo = PossibleCopy; - VD.PhiOnly = true; + VD.EdgeOnly = true; OrderedUses.push_back(VD); } } else { @@ -540,7 +567,6 @@ void PredicateInfo::renameUses(SmallPtrSetImpl &OpsToRename) { if (OutOfScope || ShouldPush) { // Sync to our current scope. popStackUntilDFSScope(RenameStack, VD); - ShouldPush |= (VD.Def || PossibleCopy); if (ShouldPush) { RenameStack.push_back(VD); } @@ -655,10 +681,10 @@ public: OS << "; Has predicate info\n"; if (const auto *PB = dyn_cast(PI)) OS << "; branch predicate info { TrueEdge: " << PB->TrueEdge - << " Comparison:" << *PB->Comparison << " }\n"; + << " Comparison:" << *PB->Condition << " }\n"; else if (const auto *PA = dyn_cast(PI)) OS << "; assume predicate info {" - << " Comparison:" << *PA->Comparison << " }\n"; + << " Comparison:" << *PA->Condition << " }\n"; } } }; diff --git a/test/Transforms/Util/PredicateInfo/condprop.ll b/test/Transforms/Util/PredicateInfo/condprop.ll index 9c024e06752..e3eaf6ffaf2 100644 --- a/test/Transforms/Util/PredicateInfo/condprop.ll +++ b/test/Transforms/Util/PredicateInfo/condprop.ll @@ -102,6 +102,7 @@ define void @test3(i32 %x, i32 %y) { ; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]]) ; CHECK: [[YZ_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[YZ]]) ; CHECK: [[Y_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[Y]]) +; CHECK: [[Z_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[Z]]) ; CHECK-NEXT: br i1 [[Z]], label [[BOTH_ZERO:%.*]], label [[NOPE:%.*]] ; CHECK: both_zero: ; CHECK-NEXT: call void @foo(i1 [[XZ_0]]) @@ -110,7 +111,7 @@ define void @test3(i32 %x, i32 %y) { ; CHECK-NEXT: call void @bar(i32 [[Y_0]]) ; CHECK-NEXT: ret void ; CHECK: nope: -; CHECK-NEXT: call void @foo(i1 [[Z]]) +; CHECK-NEXT: call void @foo(i1 [[Z_0]]) ; CHECK-NEXT: ret void ; %xz = icmp eq i32 %x, 0 diff --git a/test/Transforms/Util/PredicateInfo/testandor.ll b/test/Transforms/Util/PredicateInfo/testandor.ll index 08924490053..5942ed15531 100644 --- a/test/Transforms/Util/PredicateInfo/testandor.ll +++ b/test/Transforms/Util/PredicateInfo/testandor.ll @@ -14,6 +14,7 @@ define void @testor(i32 %x, i32 %y) { ; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]]) ; CHECK: [[YZ_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[YZ]]) ; CHECK: [[Y_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[Y]]) +; CHECK: [[Z_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[Z]]) ; CHECK-NEXT: br i1 [[Z]], label [[ONEOF:%.*]], label [[NEITHER:%.*]] ; CHECK: oneof: ; CHECK-NEXT: call void @foo(i1 [[XZ]]) @@ -26,7 +27,7 @@ define void @testor(i32 %x, i32 %y) { ; CHECK-NEXT: call void @foo(i1 [[YZ_0]]) ; CHECK-NEXT: call void @bar(i32 [[X_0]]) ; CHECK-NEXT: call void @bar(i32 [[Y_0]]) -; CHECK-NEXT: call void @foo(i1 [[Z]]) +; CHECK-NEXT: call void @foo(i1 [[Z_0]]) ; CHECK-NEXT: ret void ; %xz = icmp eq i32 %x, 0 @@ -57,6 +58,7 @@ define void @testand(i32 %x, i32 %y) { ; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]]) ; CHECK: [[YZ_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[YZ]]) ; CHECK: [[Y_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[Y]]) +; CHECK: [[Z_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[Z]]) ; CHECK-NEXT: br i1 [[Z]], label [[BOTH:%.*]], label [[NOPE:%.*]] ; CHECK: both: ; CHECK-NEXT: call void @foo(i1 [[XZ_0]]) @@ -69,7 +71,7 @@ define void @testand(i32 %x, i32 %y) { ; CHECK-NEXT: call void @foo(i1 [[YZ]]) ; CHECK-NEXT: call void @bar(i32 [[X]]) ; CHECK-NEXT: call void @bar(i32 [[Y]]) -; CHECK-NEXT: call void @foo(i1 [[Z]]) +; CHECK-NEXT: call void @foo(i1 [[Z_0]]) ; CHECK-NEXT: ret void ; %xz = icmp eq i32 %x, 0 @@ -100,6 +102,7 @@ define void @testandsame(i32 %x, i32 %y) { ; CHECK: [[X_0:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]]) ; CHECK: [[X_0_1:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X_0]]) ; CHECK: [[XLT_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[XLT]]) +; CHECK: [[Z_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[Z]]) ; CHECK-NEXT: br i1 [[Z]], label [[BOTH:%.*]], label [[NOPE:%.*]] ; CHECK: both: ; CHECK-NEXT: call void @foo(i1 [[XGT_0]]) @@ -109,7 +112,7 @@ define void @testandsame(i32 %x, i32 %y) { ; CHECK: nope: ; CHECK-NEXT: call void @foo(i1 [[XGT]]) ; CHECK-NEXT: call void @foo(i1 [[XLT]]) -; CHECK-NEXT: call void @foo(i1 [[Z]]) +; CHECK-NEXT: call void @foo(i1 [[Z_0]]) ; CHECK-NEXT: ret void ; %xgt = icmp sgt i32 %x, 0 @@ -137,12 +140,14 @@ define void @testandassume(i32 %x, i32 %y) { ; CHECK: [[TMP2:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[X]]) ; CHECK: [[TMP3:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[YZ]]) ; CHECK: [[TMP4:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[Y]]) -; CHECK-NEXT: call void @llvm.assume(i1 [[Z]]) +; CHECK: [[TMP5:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[Z]]) +; CHECK-NEXT: call void @llvm.assume(i1 [[TMP5]]) ; CHECK: [[DOT0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[TMP1]]) ; CHECK: [[DOT01:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[TMP2]]) ; CHECK: [[DOT02:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[TMP3]]) ; CHECK: [[DOT03:%.*]] = call i32 @llvm.ssa.copy.i32(i32 [[TMP4]]) -; CHECK-NEXT: br i1 [[Z]], label [[BOTH:%.*]], label [[NOPE:%.*]] +; CHECK: [[DOT04:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[TMP5]]) +; CHECK-NEXT: br i1 [[TMP5]], label [[BOTH:%.*]], label [[NOPE:%.*]] ; CHECK: both: ; CHECK-NEXT: call void @foo(i1 [[DOT0]]) ; CHECK-NEXT: call void @foo(i1 [[DOT02]]) @@ -150,7 +155,7 @@ define void @testandassume(i32 %x, i32 %y) { ; CHECK-NEXT: call void @bar(i32 [[DOT03]]) ; CHECK-NEXT: ret void ; CHECK: nope: -; CHECK-NEXT: call void @foo(i1 [[Z]]) +; CHECK-NEXT: call void @foo(i1 [[DOT04]]) ; CHECK-NEXT: ret void ; %xz = icmp eq i32 %x, 0 @@ -177,6 +182,7 @@ define void @testorassume(i32 %x, i32 %y) { ; CHECK-NEXT: [[YZ:%.*]] = icmp eq i32 [[Y:%.*]], 0 ; CHECK-NEXT: [[Z:%.*]] = or i1 [[XZ]], [[YZ]] ; CHECK-NEXT: call void @llvm.assume(i1 [[Z]]) +; CHECK: [[Z_0:%.*]] = call i1 @llvm.ssa.copy.i1(i1 [[Z]]) ; CHECK-NEXT: br i1 [[Z]], label [[BOTH:%.*]], label [[NOPE:%.*]] ; CHECK: both: ; CHECK-NEXT: call void @foo(i1 [[XZ]]) @@ -185,7 +191,7 @@ define void @testorassume(i32 %x, i32 %y) { ; CHECK-NEXT: call void @bar(i32 [[Y]]) ; CHECK-NEXT: ret void ; CHECK: nope: -; CHECK-NEXT: call void @foo(i1 [[Z]]) +; CHECK-NEXT: call void @foo(i1 [[Z_0]]) ; CHECK-NEXT: ret void ; %xz = icmp eq i32 %x, 0 -- 2.11.0