diff options
Diffstat (limited to 'llvm/lib')
-rw-r--r-- | llvm/lib/Passes/PassBuilder.cpp | 1 | ||||
-rw-r--r-- | llvm/lib/Passes/PassRegistry.def | 1 | ||||
-rw-r--r-- | llvm/lib/Transforms/Scalar/CMakeLists.txt | 1 | ||||
-rw-r--r-- | llvm/lib/Transforms/Scalar/MakeGuardsExplicit.cpp | 120 | ||||
-rw-r--r-- | llvm/lib/Transforms/Scalar/Scalar.cpp | 1 |
5 files changed, 124 insertions, 0 deletions
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp index 460b99c8510..9b03d2b1192 100644 --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -131,6 +131,7 @@ #include "llvm/Transforms/Scalar/LowerAtomic.h" #include "llvm/Transforms/Scalar/LowerExpectIntrinsic.h" #include "llvm/Transforms/Scalar/LowerGuardIntrinsic.h" +#include "llvm/Transforms/Scalar/MakeGuardsExplicit.h" #include "llvm/Transforms/Scalar/MemCpyOptimizer.h" #include "llvm/Transforms/Scalar/MergedLoadStoreMotion.h" #include "llvm/Transforms/Scalar/NaryReassociate.h" diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def index 99bd5d8c972..3f60b3d141b 100644 --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -165,6 +165,7 @@ FUNCTION_PASS("dot-cfg-only", CFGOnlyPrinterPass()) FUNCTION_PASS("early-cse", EarlyCSEPass(/*UseMemorySSA=*/false)) FUNCTION_PASS("early-cse-memssa", EarlyCSEPass(/*UseMemorySSA=*/true)) FUNCTION_PASS("ee-instrument", EntryExitInstrumenterPass(/*PostInlining=*/false)) +FUNCTION_PASS("make-guards-explicit", MakeGuardsExplicitPass()) FUNCTION_PASS("post-inline-ee-instrument", EntryExitInstrumenterPass(/*PostInlining=*/true)) FUNCTION_PASS("gvn-hoist", GVNHoistPass()) FUNCTION_PASS("instcombine", InstCombinePass()) diff --git a/llvm/lib/Transforms/Scalar/CMakeLists.txt b/llvm/lib/Transforms/Scalar/CMakeLists.txt index fce37d4bffb..1dcbaae5343 100644 --- a/llvm/lib/Transforms/Scalar/CMakeLists.txt +++ b/llvm/lib/Transforms/Scalar/CMakeLists.txt @@ -45,6 +45,7 @@ add_llvm_library(LLVMScalarOpts LowerAtomic.cpp LowerExpectIntrinsic.cpp LowerGuardIntrinsic.cpp + MakeGuardsExplicit.cpp MemCpyOptimizer.cpp MergeICmps.cpp MergedLoadStoreMotion.cpp diff --git a/llvm/lib/Transforms/Scalar/MakeGuardsExplicit.cpp b/llvm/lib/Transforms/Scalar/MakeGuardsExplicit.cpp new file mode 100644 index 00000000000..1ba3994eba0 --- /dev/null +++ b/llvm/lib/Transforms/Scalar/MakeGuardsExplicit.cpp @@ -0,0 +1,120 @@ +//===- MakeGuardsExplicit.cpp - Turn guard intrinsics into guard branches -===// +// +// 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 the new form of +// guard represented as widenable explicit branch to the deopt block. The +// difference between this pass and LowerGuardIntrinsic is that after this pass +// the guard represented as intrinsic: +// +// call void(i1, ...) @llvm.experimental.guard(i1 %old_cond) [ "deopt"() ] +// +// transforms to a guard represented as widenable explicit branch: +// +// %widenable_cond = call i1 @llvm.experimental.widenable.condition() +// br i1 (%old_cond & %widenable_cond), label %guarded, label %deopt +// +// Here: +// - The semantics of @llvm.experimental.widenable.condition allows to replace +// %widenable_cond with the construction (%widenable_cond & %any_other_cond) +// without loss of correctness; +// - %guarded is the lower part of old guard intrinsic's parent block split by +// the intrinsic call; +// - %deopt is a block containing a sole call to @llvm.experimental.deoptimize +// intrinsic. +// +// Therefore, this branch preserves the property of widenability. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Transforms/Scalar/MakeGuardsExplicit.h" +#include "llvm/Analysis/GuardUtils.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/Pass.h" +#include "llvm/Transforms/Scalar.h" +#include "llvm/Transforms/Utils/GuardUtils.h" + +using namespace llvm; + +namespace { +struct MakeGuardsExplicitLegacyPass : public FunctionPass { + static char ID; + MakeGuardsExplicitLegacyPass() : FunctionPass(ID) { + initializeMakeGuardsExplicitLegacyPassPass(*PassRegistry::getPassRegistry()); + } + + bool runOnFunction(Function &F) override; +}; +} + +static void turnToExplicitForm(CallInst *Guard, Function *DeoptIntrinsic) { + // Replace the guard with an explicit branch (just like in GuardWidening). + BasicBlock *BB = Guard->getParent(); + makeGuardControlFlowExplicit(DeoptIntrinsic, Guard); + BranchInst *ExplicitGuard = cast<BranchInst>(BB->getTerminator()); + assert(ExplicitGuard->isConditional() && "Must be!"); + + // We want the guard to be expressed as explicit control flow, but still be + // widenable. For that, we add Widenable Condition intrinsic call to the + // guard's condition. + IRBuilder<> B(ExplicitGuard); + auto *WidenableCondition = + B.CreateIntrinsic(Intrinsic::experimental_widenable_condition, + {}, {}, nullptr, "widenable_cond"); + WidenableCondition->setCallingConv(Guard->getCallingConv()); + auto *NewCond = + B.CreateAnd(ExplicitGuard->getCondition(), WidenableCondition); + NewCond->setName("exiplicit_guard_cond"); + ExplicitGuard->setCondition(NewCond); + Guard->eraseFromParent(); +} + +static bool explicifyGuards(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> GuardIntrinsics; + for (auto &I : instructions(F)) + if (isGuard(&I)) + GuardIntrinsics.push_back(cast<CallInst>(&I)); + + if (GuardIntrinsics.empty()) + return false; + + auto *DeoptIntrinsic = Intrinsic::getDeclaration( + F.getParent(), Intrinsic::experimental_deoptimize, {F.getReturnType()}); + DeoptIntrinsic->setCallingConv(GuardDecl->getCallingConv()); + + for (auto *Guard : GuardIntrinsics) + turnToExplicitForm(Guard, DeoptIntrinsic); + + return true; +} + +bool MakeGuardsExplicitLegacyPass::runOnFunction(Function &F) { + return explicifyGuards(F); +} + +char MakeGuardsExplicitLegacyPass::ID = 0; +INITIALIZE_PASS(MakeGuardsExplicitLegacyPass, "make-guards-explicit", + "Lower the guard intrinsic to explicit control flow form", + false, false) + +PreservedAnalyses MakeGuardsExplicitPass::run(Function &F, + FunctionAnalysisManager &) { + if (explicifyGuards(F)) + return PreservedAnalyses::none(); + return PreservedAnalyses::all(); +} diff --git a/llvm/lib/Transforms/Scalar/Scalar.cpp b/llvm/lib/Transforms/Scalar/Scalar.cpp index 89169c4b03a..4a965e8df83 100644 --- a/llvm/lib/Transforms/Scalar/Scalar.cpp +++ b/llvm/lib/Transforms/Scalar/Scalar.cpp @@ -52,6 +52,7 @@ void llvm::initializeScalarOpts(PassRegistry &Registry) { initializeNewGVNLegacyPassPass(Registry); initializeEarlyCSELegacyPassPass(Registry); initializeEarlyCSEMemSSALegacyPassPass(Registry); + initializeMakeGuardsExplicitLegacyPassPass(Registry); initializeGVNHoistLegacyPassPass(Registry); initializeGVNSinkLegacyPassPass(Registry); initializeFlattenCFGPassPass(Registry); |