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