diff options
Diffstat (limited to 'llvm/lib/Transforms/Utils')
-rw-r--r-- | llvm/lib/Transforms/Utils/GuardUtils.cpp | 50 |
1 files changed, 39 insertions, 11 deletions
diff --git a/llvm/lib/Transforms/Utils/GuardUtils.cpp b/llvm/lib/Transforms/Utils/GuardUtils.cpp index b8c4c764e74..241bfbf80bd 100644 --- a/llvm/lib/Transforms/Utils/GuardUtils.cpp +++ b/llvm/lib/Transforms/Utils/GuardUtils.cpp @@ -15,10 +15,12 @@ #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/MDBuilder.h" +#include "llvm/IR/PatternMatch.h" #include "llvm/Support/CommandLine.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" using namespace llvm; +using namespace llvm::PatternMatch; static cl::opt<uint32_t> PredicatePassBranchWeight( "guards-predicate-pass-branch-weight", cl::Hidden, cl::init(1 << 20), @@ -80,23 +82,49 @@ void llvm::makeGuardControlFlowExplicit(Function *DeoptIntrinsic, void llvm::widenWidenableBranch(BranchInst *WidenableBR, Value *NewCond) { assert(isWidenableBranch(WidenableBR) && "precondition"); - Instruction *WCAnd = cast<Instruction>(WidenableBR->getCondition()); - // Condition is only guaranteed to dominate branch - WCAnd->moveBefore(WidenableBR); - Value *OldCond = WCAnd->getOperand(0); - IRBuilder<> B(WCAnd); - WCAnd->setOperand(0, B.CreateAnd(NewCond, OldCond)); + // The tempting trivially option is to produce something like this: + // br (and oldcond, newcond) where oldcond is assumed to contain a widenable + // condition, but that doesn't match the pattern parseWidenableBranch expects + // so we have to be more sophisticated. + if (match(WidenableBR->getCondition(), + m_Intrinsic<Intrinsic::experimental_widenable_condition>())) { + IRBuilder<> B(WidenableBR); + WidenableBR->setCondition(B.CreateAnd(NewCond, + WidenableBR->getCondition())); + } else { + Instruction *WCAnd = cast<Instruction>(WidenableBR->getCondition()); + // Condition is only guaranteed to dominate branch + WCAnd->moveBefore(WidenableBR); + IRBuilder<> B(WCAnd); + const bool Op0IsWC = + match(WCAnd->getOperand(0), + m_Intrinsic<Intrinsic::experimental_widenable_condition>()); + const unsigned CondOpIdx = Op0IsWC ? 1 : 0; + Value *OldCond = WCAnd->getOperand(CondOpIdx); + NewCond = B.CreateAnd(NewCond, OldCond); + WCAnd->setOperand(CondOpIdx, NewCond); + } assert(isWidenableBranch(WidenableBR) && "preserve widenabiliy"); } void llvm::setWidenableBranchCond(BranchInst *WidenableBR, Value *NewCond) { assert(isWidenableBranch(WidenableBR) && "precondition"); - Instruction *WCAnd = cast<Instruction>(WidenableBR->getCondition()); - // Condition is only guaranteed to dominate branch - WCAnd->moveBefore(WidenableBR); - WCAnd->setOperand(0, NewCond); - + if (match(WidenableBR->getCondition(), + m_Intrinsic<Intrinsic::experimental_widenable_condition>())) { + IRBuilder<> B(WidenableBR); + WidenableBR->setCondition(B.CreateAnd(NewCond, + WidenableBR->getCondition())); + } else { + Instruction *WCAnd = cast<Instruction>(WidenableBR->getCondition()); + // Condition is only guaranteed to dominate branch + WCAnd->moveBefore(WidenableBR); + const bool Op0IsWC = + match(WCAnd->getOperand(0), + m_Intrinsic<Intrinsic::experimental_widenable_condition>()); + const unsigned CondOpIdx = Op0IsWC ? 1 : 0; + WCAnd->setOperand(CondOpIdx, NewCond); + } assert(isWidenableBranch(WidenableBR) && "preserve widenabiliy"); } |