10b57cec5SDimitry Andric //===- LowerGuardIntrinsic.cpp - Lower the guard intrinsic ---------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This pass lowers the llvm.experimental.guard intrinsic to a conditional call 100b57cec5SDimitry Andric // to @llvm.experimental.deoptimize. Once this happens, the guard can no longer 110b57cec5SDimitry Andric // be widened. 120b57cec5SDimitry Andric // 130b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 140b57cec5SDimitry Andric 150b57cec5SDimitry Andric #include "llvm/Transforms/Scalar/LowerGuardIntrinsic.h" 160b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 170b57cec5SDimitry Andric #include "llvm/Analysis/GuardUtils.h" 180b57cec5SDimitry Andric #include "llvm/IR/Function.h" 190b57cec5SDimitry Andric #include "llvm/IR/InstIterator.h" 200b57cec5SDimitry Andric #include "llvm/IR/Instructions.h" 210b57cec5SDimitry Andric #include "llvm/IR/Intrinsics.h" 220b57cec5SDimitry Andric #include "llvm/IR/Module.h" 230b57cec5SDimitry Andric #include "llvm/Transforms/Utils/GuardUtils.h" 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric using namespace llvm; 260b57cec5SDimitry Andric 270b57cec5SDimitry Andric static bool lowerGuardIntrinsic(Function &F) { 280b57cec5SDimitry Andric // Check if we can cheaply rule out the possibility of not having any work to 290b57cec5SDimitry Andric // do. 300b57cec5SDimitry Andric auto *GuardDecl = F.getParent()->getFunction( 310b57cec5SDimitry Andric Intrinsic::getName(Intrinsic::experimental_guard)); 320b57cec5SDimitry Andric if (!GuardDecl || GuardDecl->use_empty()) 330b57cec5SDimitry Andric return false; 340b57cec5SDimitry Andric 350b57cec5SDimitry Andric SmallVector<CallInst *, 8> ToLower; 36*81ad6265SDimitry Andric // Traverse through the users of GuardDecl. 37*81ad6265SDimitry Andric // This is presumably cheaper than traversing all instructions in the 38*81ad6265SDimitry Andric // function. 39*81ad6265SDimitry Andric for (auto *U : GuardDecl->users()) 40*81ad6265SDimitry Andric if (auto *CI = dyn_cast<CallInst>(U)) 41*81ad6265SDimitry Andric if (CI->getFunction() == &F) 42*81ad6265SDimitry Andric ToLower.push_back(CI); 430b57cec5SDimitry Andric 440b57cec5SDimitry Andric if (ToLower.empty()) 450b57cec5SDimitry Andric return false; 460b57cec5SDimitry Andric 470b57cec5SDimitry Andric auto *DeoptIntrinsic = Intrinsic::getDeclaration( 480b57cec5SDimitry Andric F.getParent(), Intrinsic::experimental_deoptimize, {F.getReturnType()}); 490b57cec5SDimitry Andric DeoptIntrinsic->setCallingConv(GuardDecl->getCallingConv()); 500b57cec5SDimitry Andric 510b57cec5SDimitry Andric for (auto *CI : ToLower) { 52480093f4SDimitry Andric makeGuardControlFlowExplicit(DeoptIntrinsic, CI, false); 530b57cec5SDimitry Andric CI->eraseFromParent(); 540b57cec5SDimitry Andric } 550b57cec5SDimitry Andric 560b57cec5SDimitry Andric return true; 570b57cec5SDimitry Andric } 580b57cec5SDimitry Andric 590b57cec5SDimitry Andric PreservedAnalyses LowerGuardIntrinsicPass::run(Function &F, 600b57cec5SDimitry Andric FunctionAnalysisManager &AM) { 610b57cec5SDimitry Andric if (lowerGuardIntrinsic(F)) 620b57cec5SDimitry Andric return PreservedAnalyses::none(); 630b57cec5SDimitry Andric 640b57cec5SDimitry Andric return PreservedAnalyses::all(); 650b57cec5SDimitry Andric } 66