Index: include/llvm/Transforms/Utils/GuardUtils.h =================================================================== --- /dev/null +++ include/llvm/Transforms/Utils/GuardUtils.h @@ -0,0 +1,30 @@ +//===-- GuardUtils.h - Utils for work with guards ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Utils that are used to perform transformations related to guards and their +// conditions. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_UTILS_GUARDUTILS_H +#define LLVM_TRANSFORMS_UTILS_GUARDUTILS_H + +namespace llvm { + +class CallInst; +class Function; + +/// Splits control flow at point of \p Guard, replacing it with explicit branch +/// by the condition of guard's first argument. The taken branch then goes to +/// the block that contains previous \p Guard's successors, and the non-taken +/// branch goes to a newly-created deopt block that contains a sole call of +/// the deoptimize function \p DeoptIntrinsic. +void makeGuardControlFlowExplicit(Function *DeoptIntrinsic, CallInst *Guard); + +} // llvm + +#endif // LLVM_TRANSFORMS_UTILS_GUARDUTILS_H Index: lib/Transforms/Scalar/LowerGuardIntrinsic.cpp =================================================================== --- lib/Transforms/Scalar/LowerGuardIntrinsic.cpp +++ lib/Transforms/Scalar/LowerGuardIntrinsic.cpp @@ -17,23 +17,16 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Function.h" -#include "llvm/IR/IRBuilder.h" #include "llvm/IR/InstIterator.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Intrinsics.h" -#include "llvm/IR/MDBuilder.h" #include "llvm/IR/Module.h" #include "llvm/Pass.h" #include "llvm/Transforms/Scalar.h" -#include "llvm/Transforms/Utils/BasicBlockUtils.h" +#include "llvm/Transforms/Utils/GuardUtils.h" using namespace llvm; -static cl::opt PredicatePassBranchWeight( - "guards-predicate-pass-branch-weight", cl::Hidden, cl::init(1 << 20), - cl::desc("The probability of a guard failing is assumed to be the " - "reciprocal of this value (default = 1 << 20)")); - namespace { struct LowerGuardIntrinsicLegacyPass : public FunctionPass { static char ID; @@ -46,45 +39,6 @@ }; } -static void MakeGuardControlFlowExplicit(Function *DeoptIntrinsic, - CallInst *CI) { - OperandBundleDef DeoptOB(*CI->getOperandBundle(LLVMContext::OB_deopt)); - SmallVector Args(std::next(CI->arg_begin()), CI->arg_end()); - - auto *CheckBB = CI->getParent(); - auto *DeoptBlockTerm = - SplitBlockAndInsertIfThen(CI->getArgOperand(0), CI, true); - - auto *CheckBI = cast(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"); - - if (auto *MD = CI->getMetadata(LLVMContext::MD_make_implicit)) - CheckBI->setMetadata(LLVMContext::MD_make_implicit, MD); - - MDBuilder MDB(CI->getContext()); - CheckBI->setMetadata(LLVMContext::MD_prof, - MDB.createBranchWeights(PredicatePassBranchWeight, 1)); - - IRBuilder<> B(DeoptBlockTerm); - auto *DeoptCall = B.CreateCall(DeoptIntrinsic, Args, {DeoptOB}, ""); - - if (DeoptIntrinsic->getReturnType()->isVoidTy()) { - B.CreateRetVoid(); - } else { - DeoptCall->setName("deoptcall"); - B.CreateRet(DeoptCall); - } - - DeoptCall->setCallingConv(CI->getCallingConv()); - DeoptBlockTerm->eraseFromParent(); -} - static bool lowerGuardIntrinsic(Function &F) { // Check if we can cheaply rule out the possibility of not having any work to // do. @@ -108,7 +62,7 @@ DeoptIntrinsic->setCallingConv(GuardDecl->getCallingConv()); for (auto *CI : ToLower) { - MakeGuardControlFlowExplicit(DeoptIntrinsic, CI); + makeGuardControlFlowExplicit(DeoptIntrinsic, CI); CI->eraseFromParent(); } Index: lib/Transforms/Utils/CMakeLists.txt =================================================================== --- lib/Transforms/Utils/CMakeLists.txt +++ lib/Transforms/Utils/CMakeLists.txt @@ -18,6 +18,7 @@ FunctionComparator.cpp FunctionImportUtils.cpp GlobalStatus.cpp + GuardUtils.cpp ImplicitControlFlowTracking.cpp InlineFunction.cpp ImportedFunctionsInliningStatistics.cpp Index: lib/Transforms/Utils/GuardUtils.cpp =================================================================== --- /dev/null +++ lib/Transforms/Utils/GuardUtils.cpp @@ -0,0 +1,64 @@ +//===-- GuardUtils.cpp - Utils for work with guards -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Utils that are used to perform transformations related to guards and their +// conditions. +//===----------------------------------------------------------------------===// + +#include "llvm/Transforms/Utils/GuardUtils.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/MDBuilder.h" +#include "llvm/Transforms/Utils/BasicBlockUtils.h" + +using namespace llvm; + +static cl::opt PredicatePassBranchWeight( + "guards-predicate-pass-branch-weight", cl::Hidden, cl::init(1 << 20), + cl::desc("The probability of a guard failing is assumed to be the " + "reciprocal of this value (default = 1 << 20)")); + +void llvm::makeGuardControlFlowExplicit(Function *DeoptIntrinsic, + CallInst *Guard) { + OperandBundleDef DeoptOB(*Guard->getOperandBundle(LLVMContext::OB_deopt)); + SmallVector Args(std::next(Guard->arg_begin()), Guard->arg_end()); + + auto *CheckBB = Guard->getParent(); + auto *DeoptBlockTerm = + SplitBlockAndInsertIfThen(Guard->getArgOperand(0), Guard, true); + + auto *CheckBI = cast(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"); + + if (auto *MD = Guard->getMetadata(LLVMContext::MD_make_implicit)) + CheckBI->setMetadata(LLVMContext::MD_make_implicit, MD); + + MDBuilder MDB(Guard->getContext()); + CheckBI->setMetadata(LLVMContext::MD_prof, + MDB.createBranchWeights(PredicatePassBranchWeight, 1)); + + IRBuilder<> B(DeoptBlockTerm); + auto *DeoptCall = B.CreateCall(DeoptIntrinsic, Args, {DeoptOB}, ""); + + if (DeoptIntrinsic->getReturnType()->isVoidTy()) { + B.CreateRetVoid(); + } else { + DeoptCall->setName("deoptcall"); + B.CreateRet(DeoptCall); + } + + DeoptCall->setCallingConv(Guard->getCallingConv()); + DeoptBlockTerm->eraseFromParent(); +}