Home | History | Annotate | Download | only in Scalar
      1 //===- LowerGuardIntrinsic.cpp - Lower the guard intrinsic ---------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This pass lowers the llvm.experimental.guard intrinsic to a conditional call
     11 // to @llvm.experimental.deoptimize.  Once this happens, the guard can no longer
     12 // be widened.
     13 //
     14 //===----------------------------------------------------------------------===//
     15 
     16 #include "llvm/Transforms/Scalar.h"
     17 #include "llvm/ADT/SmallVector.h"
     18 #include "llvm/IR/BasicBlock.h"
     19 #include "llvm/IR/Function.h"
     20 #include "llvm/IR/InstIterator.h"
     21 #include "llvm/IR/Instructions.h"
     22 #include "llvm/IR/Intrinsics.h"
     23 #include "llvm/IR/IRBuilder.h"
     24 #include "llvm/IR/MDBuilder.h"
     25 #include "llvm/IR/Module.h"
     26 #include "llvm/Pass.h"
     27 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
     28 
     29 using namespace llvm;
     30 
     31 static cl::opt<uint32_t> PredicatePassBranchWeight(
     32     "guards-predicate-pass-branch-weight", cl::Hidden, cl::init(1 << 20),
     33     cl::desc("The probability of a guard failing is assumed to be the "
     34              "reciprocal of this value (default = 1 << 20)"));
     35 
     36 namespace {
     37 struct LowerGuardIntrinsic : public FunctionPass {
     38   static char ID;
     39   LowerGuardIntrinsic() : FunctionPass(ID) {
     40     initializeLowerGuardIntrinsicPass(*PassRegistry::getPassRegistry());
     41   }
     42 
     43   bool runOnFunction(Function &F) override;
     44 };
     45 }
     46 
     47 static void MakeGuardControlFlowExplicit(Function *DeoptIntrinsic,
     48                                          CallInst *CI) {
     49   OperandBundleDef DeoptOB(*CI->getOperandBundle(LLVMContext::OB_deopt));
     50   SmallVector<Value *, 4> Args(std::next(CI->arg_begin()), CI->arg_end());
     51 
     52   auto *CheckBB = CI->getParent();
     53   auto *DeoptBlockTerm =
     54       SplitBlockAndInsertIfThen(CI->getArgOperand(0), CI, true);
     55 
     56   auto *CheckBI = cast<BranchInst>(CheckBB->getTerminator());
     57 
     58   // SplitBlockAndInsertIfThen inserts control flow that branches to
     59   // DeoptBlockTerm if the condition is true.  We want the opposite.
     60   CheckBI->swapSuccessors();
     61 
     62   CheckBI->getSuccessor(0)->setName("guarded");
     63   CheckBI->getSuccessor(1)->setName("deopt");
     64 
     65   if (auto *MD = CI->getMetadata(LLVMContext::MD_make_implicit))
     66     CheckBI->setMetadata(LLVMContext::MD_make_implicit, MD);
     67 
     68   MDBuilder MDB(CI->getContext());
     69   CheckBI->setMetadata(LLVMContext::MD_prof,
     70                        MDB.createBranchWeights(PredicatePassBranchWeight, 1));
     71 
     72   IRBuilder<> B(DeoptBlockTerm);
     73   auto *DeoptCall = B.CreateCall(DeoptIntrinsic, Args, {DeoptOB}, "");
     74 
     75   if (DeoptIntrinsic->getReturnType()->isVoidTy()) {
     76     B.CreateRetVoid();
     77   } else {
     78     DeoptCall->setName("deoptcall");
     79     B.CreateRet(DeoptCall);
     80   }
     81 
     82   DeoptCall->setCallingConv(CI->getCallingConv());
     83   DeoptBlockTerm->eraseFromParent();
     84 }
     85 
     86 bool LowerGuardIntrinsic::runOnFunction(Function &F) {
     87   // Check if we can cheaply rule out the possibility of not having any work to
     88   // do.
     89   auto *GuardDecl = F.getParent()->getFunction(
     90       Intrinsic::getName(Intrinsic::experimental_guard));
     91   if (!GuardDecl || GuardDecl->use_empty())
     92     return false;
     93 
     94   SmallVector<CallInst *, 8> ToLower;
     95   for (auto &I : instructions(F))
     96     if (auto *CI = dyn_cast<CallInst>(&I))
     97       if (auto *F = CI->getCalledFunction())
     98         if (F->getIntrinsicID() == Intrinsic::experimental_guard)
     99           ToLower.push_back(CI);
    100 
    101   if (ToLower.empty())
    102     return false;
    103 
    104   auto *DeoptIntrinsic = Intrinsic::getDeclaration(
    105       F.getParent(), Intrinsic::experimental_deoptimize, {F.getReturnType()});
    106   DeoptIntrinsic->setCallingConv(GuardDecl->getCallingConv());
    107 
    108   for (auto *CI : ToLower) {
    109     MakeGuardControlFlowExplicit(DeoptIntrinsic, CI);
    110     CI->eraseFromParent();
    111   }
    112 
    113   return true;
    114 }
    115 
    116 char LowerGuardIntrinsic::ID = 0;
    117 INITIALIZE_PASS(LowerGuardIntrinsic, "lower-guard-intrinsic",
    118                 "Lower the guard intrinsic to normal control flow", false,
    119                 false)
    120 
    121 Pass *llvm::createLowerGuardIntrinsicPass() {
    122   return new LowerGuardIntrinsic();
    123 }
    124