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/Pass.h" |
40 | #include "llvm/Transforms/Utils/GuardUtils.h" |
41 | |
42 | using namespace llvm; |
43 | |
44 | static void turnToExplicitForm(CallInst *Guard, Function *DeoptIntrinsic) { |
45 | // Replace the guard with an explicit branch (just like in GuardWidening). |
46 | BasicBlock *OriginalBB = Guard->getParent(); |
47 | (void)OriginalBB; |
48 | makeGuardControlFlowExplicit(DeoptIntrinsic, Guard, UseWC: true); |
49 | assert(isWidenableBranch(OriginalBB->getTerminator()) && "should hold" ); |
50 | |
51 | Guard->eraseFromParent(); |
52 | } |
53 | |
54 | static bool explicifyGuards(Function &F) { |
55 | // Check if we can cheaply rule out the possibility of not having any work to |
56 | // do. |
57 | auto *GuardDecl = Intrinsic::getDeclarationIfExists( |
58 | M: F.getParent(), id: Intrinsic::experimental_guard); |
59 | if (!GuardDecl || GuardDecl->use_empty()) |
60 | return false; |
61 | |
62 | SmallVector<CallInst *, 8> GuardIntrinsics; |
63 | for (auto &I : instructions(F)) |
64 | if (isGuard(U: &I)) |
65 | GuardIntrinsics.push_back(Elt: cast<CallInst>(Val: &I)); |
66 | |
67 | if (GuardIntrinsics.empty()) |
68 | return false; |
69 | |
70 | auto *DeoptIntrinsic = Intrinsic::getOrInsertDeclaration( |
71 | M: F.getParent(), id: Intrinsic::experimental_deoptimize, Tys: {F.getReturnType()}); |
72 | DeoptIntrinsic->setCallingConv(GuardDecl->getCallingConv()); |
73 | |
74 | for (auto *Guard : GuardIntrinsics) |
75 | turnToExplicitForm(Guard, DeoptIntrinsic); |
76 | |
77 | return true; |
78 | } |
79 | |
80 | PreservedAnalyses MakeGuardsExplicitPass::run(Function &F, |
81 | FunctionAnalysisManager &) { |
82 | if (explicifyGuards(F)) |
83 | return PreservedAnalyses::none(); |
84 | return PreservedAnalyses::all(); |
85 | } |
86 | |