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 IRBuilder<> B(DeoptBlockTerm); 60 auto *DeoptCall = B.CreateCall(DeoptIntrinsic, Args, {DeoptOB}, ""); 61 62 if (DeoptIntrinsic->getReturnType()->isVoidTy()) { 63 B.CreateRetVoid(); 64 } else { 65 DeoptCall->setName("deoptcall"); 66 B.CreateRet(DeoptCall); 67 } 68 69 DeoptCall->setCallingConv(CI->getCallingConv()); 70 DeoptBlockTerm->eraseFromParent(); 71 } 72 73 bool LowerGuardIntrinsic::runOnFunction(Function &F) { 74 // Check if we can cheaply rule out the possibility of not having any work to 75 // do. 76 auto *GuardDecl = F.getParent()->getFunction( 77 Intrinsic::getName(Intrinsic::experimental_guard)); 78 if (!GuardDecl || GuardDecl->use_empty()) 79 return false; 80 81 SmallVector<CallInst *, 8> ToLower; 82 for (auto &I : instructions(F)) 83 if (auto *CI = dyn_cast<CallInst>(&I)) 84 if (auto *F = CI->getCalledFunction()) 85 if (F->getIntrinsicID() == Intrinsic::experimental_guard) 86 ToLower.push_back(CI); 87 88 if (ToLower.empty()) 89 return false; 90 91 auto *DeoptIntrinsic = Intrinsic::getDeclaration( 92 F.getParent(), Intrinsic::experimental_deoptimize, {F.getReturnType()}); 93 DeoptIntrinsic->setCallingConv(GuardDecl->getCallingConv()); 94 95 for (auto *CI : ToLower) { 96 MakeGuardControlFlowExplicit(DeoptIntrinsic, CI); 97 CI->eraseFromParent(); 98 } 99 100 return true; 101 } 102 103 char LowerGuardIntrinsic::ID = 0; 104 INITIALIZE_PASS(LowerGuardIntrinsic, "lower-guard-intrinsic", 105 "Lower the guard intrinsic to normal control flow", false, 106 false) 107 108 Pass *llvm::createLowerGuardIntrinsicPass() { 109 return new LowerGuardIntrinsic(); 110 } 111