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