]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/lib/Transforms/Scalar/LowerGuardIntrinsic.cpp
Merge llvm, clang, lld and lldb trunk r300890, and update build glue.
[FreeBSD/FreeBSD.git] / contrib / llvm / lib / Transforms / Scalar / LowerGuardIntrinsic.cpp
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/LowerGuardIntrinsic.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/Scalar.h"
28 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
29
30 using namespace llvm;
31
32 static cl::opt<uint32_t> PredicatePassBranchWeight(
33     "guards-predicate-pass-branch-weight", cl::Hidden, cl::init(1 << 20),
34     cl::desc("The probability of a guard failing is assumed to be the "
35              "reciprocal of this value (default = 1 << 20)"));
36
37 namespace {
38 struct LowerGuardIntrinsicLegacyPass : public FunctionPass {
39   static char ID;
40   LowerGuardIntrinsicLegacyPass() : FunctionPass(ID) {
41     initializeLowerGuardIntrinsicLegacyPassPass(
42         *PassRegistry::getPassRegistry());
43   }
44
45   bool runOnFunction(Function &F) override;
46 };
47 }
48
49 static void MakeGuardControlFlowExplicit(Function *DeoptIntrinsic,
50                                          CallInst *CI) {
51   OperandBundleDef DeoptOB(*CI->getOperandBundle(LLVMContext::OB_deopt));
52   SmallVector<Value *, 4> Args(std::next(CI->arg_begin()), CI->arg_end());
53
54   auto *CheckBB = CI->getParent();
55   auto *DeoptBlockTerm =
56       SplitBlockAndInsertIfThen(CI->getArgOperand(0), CI, true);
57
58   auto *CheckBI = cast<BranchInst>(CheckBB->getTerminator());
59
60   // SplitBlockAndInsertIfThen inserts control flow that branches to
61   // DeoptBlockTerm if the condition is true.  We want the opposite.
62   CheckBI->swapSuccessors();
63
64   CheckBI->getSuccessor(0)->setName("guarded");
65   CheckBI->getSuccessor(1)->setName("deopt");
66
67   if (auto *MD = CI->getMetadata(LLVMContext::MD_make_implicit))
68     CheckBI->setMetadata(LLVMContext::MD_make_implicit, MD);
69
70   MDBuilder MDB(CI->getContext());
71   CheckBI->setMetadata(LLVMContext::MD_prof,
72                        MDB.createBranchWeights(PredicatePassBranchWeight, 1));
73
74   IRBuilder<> B(DeoptBlockTerm);
75   auto *DeoptCall = B.CreateCall(DeoptIntrinsic, Args, {DeoptOB}, "");
76
77   if (DeoptIntrinsic->getReturnType()->isVoidTy()) {
78     B.CreateRetVoid();
79   } else {
80     DeoptCall->setName("deoptcall");
81     B.CreateRet(DeoptCall);
82   }
83
84   DeoptCall->setCallingConv(CI->getCallingConv());
85   DeoptBlockTerm->eraseFromParent();
86 }
87
88 static bool lowerGuardIntrinsic(Function &F) {
89   // Check if we can cheaply rule out the possibility of not having any work to
90   // do.
91   auto *GuardDecl = F.getParent()->getFunction(
92       Intrinsic::getName(Intrinsic::experimental_guard));
93   if (!GuardDecl || GuardDecl->use_empty())
94     return false;
95
96   SmallVector<CallInst *, 8> ToLower;
97   for (auto &I : instructions(F))
98     if (auto *CI = dyn_cast<CallInst>(&I))
99       if (auto *F = CI->getCalledFunction())
100         if (F->getIntrinsicID() == Intrinsic::experimental_guard)
101           ToLower.push_back(CI);
102
103   if (ToLower.empty())
104     return false;
105
106   auto *DeoptIntrinsic = Intrinsic::getDeclaration(
107       F.getParent(), Intrinsic::experimental_deoptimize, {F.getReturnType()});
108   DeoptIntrinsic->setCallingConv(GuardDecl->getCallingConv());
109
110   for (auto *CI : ToLower) {
111     MakeGuardControlFlowExplicit(DeoptIntrinsic, CI);
112     CI->eraseFromParent();
113   }
114
115   return true;
116 }
117
118 bool LowerGuardIntrinsicLegacyPass::runOnFunction(Function &F) {
119   return lowerGuardIntrinsic(F);
120 }
121
122 char LowerGuardIntrinsicLegacyPass::ID = 0;
123 INITIALIZE_PASS(LowerGuardIntrinsicLegacyPass, "lower-guard-intrinsic",
124                 "Lower the guard intrinsic to normal control flow", false,
125                 false)
126
127 Pass *llvm::createLowerGuardIntrinsicPass() {
128   return new LowerGuardIntrinsicLegacyPass();
129 }
130
131 PreservedAnalyses LowerGuardIntrinsicPass::run(Function &F,
132                                                FunctionAnalysisManager &AM) {
133   if (lowerGuardIntrinsic(F))
134     return PreservedAnalyses::none();
135
136   return PreservedAnalyses::all();
137 }