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 } 138