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