diff options
Diffstat (limited to 'llvm/lib/Transforms')
-rw-r--r-- | llvm/lib/Transforms/Scalar/CMakeLists.txt | 1 | ||||
-rw-r--r-- | llvm/lib/Transforms/Scalar/LowerGuardIntrinsic.cpp | 108 | ||||
-rw-r--r-- | llvm/lib/Transforms/Scalar/Scalar.cpp | 1 | ||||
-rw-r--r-- | llvm/lib/Transforms/Utils/InlineFunction.cpp | 12 |
4 files changed, 117 insertions, 5 deletions
diff --git a/llvm/lib/Transforms/Scalar/CMakeLists.txt b/llvm/lib/Transforms/Scalar/CMakeLists.txt index 2684cee838f..f62cf6b92fe 100644 --- a/llvm/lib/Transforms/Scalar/CMakeLists.txt +++ b/llvm/lib/Transforms/Scalar/CMakeLists.txt @@ -32,6 +32,7 @@ add_llvm_library(LLVMScalarOpts LoopVersioningLICM.cpp LowerAtomic.cpp LowerExpectIntrinsic.cpp + LowerGuardIntrinsic.cpp MemCpyOptimizer.cpp MergedLoadStoreMotion.cpp NaryReassociate.cpp diff --git a/llvm/lib/Transforms/Scalar/LowerGuardIntrinsic.cpp b/llvm/lib/Transforms/Scalar/LowerGuardIntrinsic.cpp new file mode 100644 index 00000000000..5f5dd197b44 --- /dev/null +++ b/llvm/lib/Transforms/Scalar/LowerGuardIntrinsic.cpp @@ -0,0 +1,108 @@ +//===- LowerGuardIntrinsic.cpp - Lower the guard intrinsic ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass lowers the llvm.experimental.guard intrinsic to a conditional call +// to @llvm.experimental.deoptimize. Once this happens, the guard can no longer +// be widened. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Transforms/Scalar.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Module.h" +#include "llvm/Pass.h" +#include "llvm/Transforms/Utils/BasicBlockUtils.h" + +using namespace llvm; + +namespace { +struct LowerGuardIntrinsic : public FunctionPass { + static char ID; + LowerGuardIntrinsic() : FunctionPass(ID) { + initializeLowerGuardIntrinsicPass(*PassRegistry::getPassRegistry()); + } + + bool runOnFunction(Function &F) override; +}; +} + +static void MakeGuardControlFlowExplicit(Function *DeoptIntrinsic, + CallInst *CI) { + OperandBundleDef DeoptOB(*CI->getOperandBundle(LLVMContext::OB_deopt)); + SmallVector<Value *, 4> Args(std::next(CI->arg_begin()), CI->arg_end()); + + auto *CheckBB = CI->getParent(); + auto *DeoptBlockTerm = + SplitBlockAndInsertIfThen(CI->getArgOperand(0), CI, true); + + auto *CheckBI = cast<BranchInst>(CheckBB->getTerminator()); + + // SplitBlockAndInsertIfThen inserts control flow that branches to + // DeoptBlockTerm if the condition is true. We want the opposite. + CheckBI->swapSuccessors(); + + CheckBI->getSuccessor(0)->setName("guarded"); + CheckBI->getSuccessor(1)->setName("deopt"); + + IRBuilder<> B(DeoptBlockTerm); + auto *DeoptCall = B.CreateCall(DeoptIntrinsic, Args, {DeoptOB}, ""); + + if (DeoptIntrinsic->getReturnType()->isVoidTy()) { + B.CreateRetVoid(); + } else { + DeoptCall->setName("deoptcall"); + B.CreateRet(DeoptCall); + } + + DeoptBlockTerm->eraseFromParent(); +} + +bool LowerGuardIntrinsic::runOnFunction(Function &F) { + // Check if we can cheaply rule out the possibility of not having any work to + // do. + auto *GuardDecl = F.getParent()->getFunction( + Intrinsic::getName(Intrinsic::experimental_guard)); + if (!GuardDecl || GuardDecl->use_empty()) + return false; + + SmallVector<CallInst *, 8> ToLower; + for (auto &I : instructions(F)) + if (auto *CI = dyn_cast<CallInst>(&I)) + if (auto *F = CI->getCalledFunction()) + if (F->getIntrinsicID() == Intrinsic::experimental_guard) + ToLower.push_back(CI); + + if (ToLower.empty()) + return false; + + auto *DeoptIntrinsic = Intrinsic::getDeclaration( + F.getParent(), Intrinsic::experimental_deoptimize, {F.getReturnType()}); + + for (auto *CI : ToLower) { + MakeGuardControlFlowExplicit(DeoptIntrinsic, CI); + CI->eraseFromParent(); + } + + return true; +} + +char LowerGuardIntrinsic::ID = 0; +INITIALIZE_PASS(LowerGuardIntrinsic, "lower-guard-intrinsic", + "Lower the guard intrinsic to normal control flow", false, + false) + +Pass *llvm::createLowerGuardIntrinsicPass() { + return new LowerGuardIntrinsic(); +} diff --git a/llvm/lib/Transforms/Scalar/Scalar.cpp b/llvm/lib/Transforms/Scalar/Scalar.cpp index 10b14623033..a8c0c14f738 100644 --- a/llvm/lib/Transforms/Scalar/Scalar.cpp +++ b/llvm/lib/Transforms/Scalar/Scalar.cpp @@ -62,6 +62,7 @@ void llvm::initializeScalarOpts(PassRegistry &Registry) { initializeLoopIdiomRecognizePass(Registry); initializeLowerAtomicPass(Registry); initializeLowerExpectIntrinsicPass(Registry); + initializeLowerGuardIntrinsicPass(Registry); initializeMemCpyOptPass(Registry); initializeMergedLoadStoreMotionPass(Registry); initializeNaryReassociatePass(Registry); diff --git a/llvm/lib/Transforms/Utils/InlineFunction.cpp b/llvm/lib/Transforms/Utils/InlineFunction.cpp index 31cf5fbdc85..50eff521318 100644 --- a/llvm/lib/Transforms/Utils/InlineFunction.cpp +++ b/llvm/lib/Transforms/Utils/InlineFunction.cpp @@ -428,12 +428,14 @@ static BasicBlock *HandleCallsInBlockInlinedThroughInvoke( continue; // We do not need to (and in fact, cannot) convert possibly throwing calls - // to @llvm.experimental_deoptimize into invokes. The caller's "segment" of - // the deoptimization continuation attached to the newly inlined - // @llvm.experimental_deoptimize call should contain the exception handling - // logic, if any. + // to @llvm.experimental_deoptimize (resp. @llvm.experimental.guard) into + // invokes. The caller's "segment" of the deoptimization continuation + // attached to the newly inlined @llvm.experimental_deoptimize + // (resp. @llvm.experimental.guard) call should contain the exception + // handling logic, if any. if (auto *F = CI->getCalledFunction()) - if (F->getIntrinsicID() == Intrinsic::experimental_deoptimize) + if (F->getIntrinsicID() == Intrinsic::experimental_deoptimize || + F->getIntrinsicID() == Intrinsic::experimental_guard) continue; if (auto FuncletBundle = CI->getOperandBundle(LLVMContext::OB_funclet)) { |