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
29using namespace llvm;
30
31static 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
36namespace {
37struct 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
47static 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
86bool 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
116char LowerGuardIntrinsic::ID = 0;
117INITIALIZE_PASS(LowerGuardIntrinsic, "lower-guard-intrinsic",
118                "Lower the guard intrinsic to normal control flow", false,
119                false)
120
121Pass *llvm::createLowerGuardIntrinsicPass() {
122  return new LowerGuardIntrinsic();
123}
124