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/Module.h" 25 #include "llvm/Pass.h" 26 #include "llvm/Transforms/Utils/BasicBlockUtils.h" 27 28 using namespace llvm; 29 30 namespace { 31 struct LowerGuardIntrinsic : public FunctionPass { 32 static char ID; 33 LowerGuardIntrinsic() : FunctionPass(ID) { 34 initializeLowerGuardIntrinsicPass(*PassRegistry::getPassRegistry()); 35 } 36 37 bool runOnFunction(Function &F) override; 38 }; 39 } 40 41 static void MakeGuardControlFlowExplicit(Function *DeoptIntrinsic, 42 CallInst *CI) { 43 OperandBundleDef DeoptOB(*CI->getOperandBundle(LLVMContext::OB_deopt)); 44 SmallVector<Value *, 4> Args(std::next(CI->arg_begin()), CI->arg_end()); 45 46 auto *CheckBB = CI->getParent(); 47 auto *DeoptBlockTerm = 48 SplitBlockAndInsertIfThen(CI->getArgOperand(0), CI, true); 49 50 auto *CheckBI = cast<BranchInst>(CheckBB->getTerminator()); 51 52 // SplitBlockAndInsertIfThen inserts control flow that branches to 53 // DeoptBlockTerm if the condition is true. We want the opposite. 54 CheckBI->swapSuccessors(); 55 56 CheckBI->getSuccessor(0)->setName("guarded"); 57 CheckBI->getSuccessor(1)->setName("deopt"); 58 59 if (auto *MD = CI->getMetadata(LLVMContext::MD_make_implicit)) 60 CheckBI->setMetadata(LLVMContext::MD_make_implicit, MD); 61 62 IRBuilder<> B(DeoptBlockTerm); 63 auto *DeoptCall = B.CreateCall(DeoptIntrinsic, Args, {DeoptOB}, ""); 64 65 if (DeoptIntrinsic->getReturnType()->isVoidTy()) { 66 B.CreateRetVoid(); 67 } else { 68 DeoptCall->setName("deoptcall"); 69 B.CreateRet(DeoptCall); 70 } 71 72 DeoptCall->setCallingConv(CI->getCallingConv()); 73 DeoptBlockTerm->eraseFromParent(); 74 } 75 76 bool LowerGuardIntrinsic::runOnFunction(Function &F) { 77 // Check if we can cheaply rule out the possibility of not having any work to 78 // do. 79 auto *GuardDecl = F.getParent()->getFunction( 80 Intrinsic::getName(Intrinsic::experimental_guard)); 81 if (!GuardDecl || GuardDecl->use_empty()) 82 return false; 83 84 SmallVector<CallInst *, 8> ToLower; 85 for (auto &I : instructions(F)) 86 if (auto *CI = dyn_cast<CallInst>(&I)) 87 if (auto *F = CI->getCalledFunction()) 88 if (F->getIntrinsicID() == Intrinsic::experimental_guard) 89 ToLower.push_back(CI); 90 91 if (ToLower.empty()) 92 return false; 93 94 auto *DeoptIntrinsic = Intrinsic::getDeclaration( 95 F.getParent(), Intrinsic::experimental_deoptimize, {F.getReturnType()}); 96 DeoptIntrinsic->setCallingConv(GuardDecl->getCallingConv()); 97 98 for (auto *CI : ToLower) { 99 MakeGuardControlFlowExplicit(DeoptIntrinsic, CI); 100 CI->eraseFromParent(); 101 } 102 103 return true; 104 } 105 106 char LowerGuardIntrinsic::ID = 0; 107 INITIALIZE_PASS(LowerGuardIntrinsic, "lower-guard-intrinsic", 108 "Lower the guard intrinsic to normal control flow", false, 109 false) 110 111 Pass *llvm::createLowerGuardIntrinsicPass() { 112 return new LowerGuardIntrinsic(); 113 } 114