1b9e65cbdSMax Kazantsev //===- MakeGuardsExplicit.cpp - Turn guard intrinsics into guard branches -===//
2b9e65cbdSMax Kazantsev //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6b9e65cbdSMax Kazantsev //
7b9e65cbdSMax Kazantsev //===----------------------------------------------------------------------===//
8b9e65cbdSMax Kazantsev //
9b9e65cbdSMax Kazantsev // This pass lowers the @llvm.experimental.guard intrinsic to the new form of
10b9e65cbdSMax Kazantsev // guard represented as widenable explicit branch to the deopt block. The
11b9e65cbdSMax Kazantsev // difference between this pass and LowerGuardIntrinsic is that after this pass
12b9e65cbdSMax Kazantsev // the guard represented as intrinsic:
13b9e65cbdSMax Kazantsev //
14b9e65cbdSMax Kazantsev // call void(i1, ...) @llvm.experimental.guard(i1 %old_cond) [ "deopt"() ]
15b9e65cbdSMax Kazantsev //
16b9e65cbdSMax Kazantsev // transforms to a guard represented as widenable explicit branch:
17b9e65cbdSMax Kazantsev //
18b9e65cbdSMax Kazantsev // %widenable_cond = call i1 @llvm.experimental.widenable.condition()
19b9e65cbdSMax Kazantsev // br i1 (%old_cond & %widenable_cond), label %guarded, label %deopt
20b9e65cbdSMax Kazantsev //
21b9e65cbdSMax Kazantsev // Here:
22b9e65cbdSMax Kazantsev // - The semantics of @llvm.experimental.widenable.condition allows to replace
23b9e65cbdSMax Kazantsev // %widenable_cond with the construction (%widenable_cond & %any_other_cond)
24b9e65cbdSMax Kazantsev // without loss of correctness;
25b9e65cbdSMax Kazantsev // - %guarded is the lower part of old guard intrinsic's parent block split by
26b9e65cbdSMax Kazantsev // the intrinsic call;
27b9e65cbdSMax Kazantsev // - %deopt is a block containing a sole call to @llvm.experimental.deoptimize
28b9e65cbdSMax Kazantsev // intrinsic.
29b9e65cbdSMax Kazantsev //
30b9e65cbdSMax Kazantsev // Therefore, this branch preserves the property of widenability.
31b9e65cbdSMax Kazantsev //
32b9e65cbdSMax Kazantsev //===----------------------------------------------------------------------===//
33b9e65cbdSMax Kazantsev
34b9e65cbdSMax Kazantsev #include "llvm/Transforms/Scalar/MakeGuardsExplicit.h"
35b9e65cbdSMax Kazantsev #include "llvm/Analysis/GuardUtils.h"
36b9e65cbdSMax Kazantsev #include "llvm/IR/InstIterator.h"
37*59630917Sserge-sans-paille #include "llvm/IR/Instructions.h"
38b9e65cbdSMax Kazantsev #include "llvm/IR/Intrinsics.h"
3905da2fe5SReid Kleckner #include "llvm/InitializePasses.h"
40b9e65cbdSMax Kazantsev #include "llvm/Pass.h"
41b9e65cbdSMax Kazantsev #include "llvm/Transforms/Utils/GuardUtils.h"
42b9e65cbdSMax Kazantsev
43b9e65cbdSMax Kazantsev using namespace llvm;
44b9e65cbdSMax Kazantsev
45b9e65cbdSMax Kazantsev namespace {
46b9e65cbdSMax Kazantsev struct MakeGuardsExplicitLegacyPass : public FunctionPass {
47b9e65cbdSMax Kazantsev static char ID;
MakeGuardsExplicitLegacyPass__anon0a60f3090111::MakeGuardsExplicitLegacyPass48b9e65cbdSMax Kazantsev MakeGuardsExplicitLegacyPass() : FunctionPass(ID) {
49b9e65cbdSMax Kazantsev initializeMakeGuardsExplicitLegacyPassPass(*PassRegistry::getPassRegistry());
50b9e65cbdSMax Kazantsev }
51b9e65cbdSMax Kazantsev
52b9e65cbdSMax Kazantsev bool runOnFunction(Function &F) override;
53b9e65cbdSMax Kazantsev };
54b9e65cbdSMax Kazantsev }
55b9e65cbdSMax Kazantsev
turnToExplicitForm(CallInst * Guard,Function * DeoptIntrinsic)56b9e65cbdSMax Kazantsev static void turnToExplicitForm(CallInst *Guard, Function *DeoptIntrinsic) {
57b9e65cbdSMax Kazantsev // Replace the guard with an explicit branch (just like in GuardWidening).
58e47d6da8SJames Y Knight BasicBlock *OriginalBB = Guard->getParent();
59e47d6da8SJames Y Knight (void)OriginalBB;
608ba56f32SPhilip Reames makeGuardControlFlowExplicit(DeoptIntrinsic, Guard, true);
61e47d6da8SJames Y Knight assert(isWidenableBranch(OriginalBB->getTerminator()) && "should hold");
62b9e65cbdSMax Kazantsev
63b9e65cbdSMax Kazantsev Guard->eraseFromParent();
64b9e65cbdSMax Kazantsev }
65b9e65cbdSMax Kazantsev
explicifyGuards(Function & F)66b9e65cbdSMax Kazantsev static bool explicifyGuards(Function &F) {
67b9e65cbdSMax Kazantsev // Check if we can cheaply rule out the possibility of not having any work to
68b9e65cbdSMax Kazantsev // do.
69b9e65cbdSMax Kazantsev auto *GuardDecl = F.getParent()->getFunction(
70b9e65cbdSMax Kazantsev Intrinsic::getName(Intrinsic::experimental_guard));
71b9e65cbdSMax Kazantsev if (!GuardDecl || GuardDecl->use_empty())
72b9e65cbdSMax Kazantsev return false;
73b9e65cbdSMax Kazantsev
74b9e65cbdSMax Kazantsev SmallVector<CallInst *, 8> GuardIntrinsics;
75b9e65cbdSMax Kazantsev for (auto &I : instructions(F))
76b9e65cbdSMax Kazantsev if (isGuard(&I))
77b9e65cbdSMax Kazantsev GuardIntrinsics.push_back(cast<CallInst>(&I));
78b9e65cbdSMax Kazantsev
79b9e65cbdSMax Kazantsev if (GuardIntrinsics.empty())
80b9e65cbdSMax Kazantsev return false;
81b9e65cbdSMax Kazantsev
82b9e65cbdSMax Kazantsev auto *DeoptIntrinsic = Intrinsic::getDeclaration(
83b9e65cbdSMax Kazantsev F.getParent(), Intrinsic::experimental_deoptimize, {F.getReturnType()});
84b9e65cbdSMax Kazantsev DeoptIntrinsic->setCallingConv(GuardDecl->getCallingConv());
85b9e65cbdSMax Kazantsev
86b9e65cbdSMax Kazantsev for (auto *Guard : GuardIntrinsics)
87b9e65cbdSMax Kazantsev turnToExplicitForm(Guard, DeoptIntrinsic);
88b9e65cbdSMax Kazantsev
89b9e65cbdSMax Kazantsev return true;
90b9e65cbdSMax Kazantsev }
91b9e65cbdSMax Kazantsev
runOnFunction(Function & F)92b9e65cbdSMax Kazantsev bool MakeGuardsExplicitLegacyPass::runOnFunction(Function &F) {
93b9e65cbdSMax Kazantsev return explicifyGuards(F);
94b9e65cbdSMax Kazantsev }
95b9e65cbdSMax Kazantsev
96b9e65cbdSMax Kazantsev char MakeGuardsExplicitLegacyPass::ID = 0;
97b9e65cbdSMax Kazantsev INITIALIZE_PASS(MakeGuardsExplicitLegacyPass, "make-guards-explicit",
98b9e65cbdSMax Kazantsev "Lower the guard intrinsic to explicit control flow form",
99b9e65cbdSMax Kazantsev false, false)
100b9e65cbdSMax Kazantsev
run(Function & F,FunctionAnalysisManager &)101b9e65cbdSMax Kazantsev PreservedAnalyses MakeGuardsExplicitPass::run(Function &F,
102b9e65cbdSMax Kazantsev FunctionAnalysisManager &) {
103b9e65cbdSMax Kazantsev if (explicifyGuards(F))
104b9e65cbdSMax Kazantsev return PreservedAnalyses::none();
105b9e65cbdSMax Kazantsev return PreservedAnalyses::all();
106b9e65cbdSMax Kazantsev }
107