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