/src/llvm-project/llvm/lib/Analysis/GuardUtils.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===-- GuardUtils.cpp - Utils for work with guards -------------*- C++ -*-===// |
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 | | // Utils that are used to perform analyzes related to guards and their |
9 | | // conditions. |
10 | | //===----------------------------------------------------------------------===// |
11 | | |
12 | | #include "llvm/Analysis/GuardUtils.h" |
13 | | #include "llvm/IR/PatternMatch.h" |
14 | | |
15 | | using namespace llvm; |
16 | | using namespace llvm::PatternMatch; |
17 | | |
18 | 3.52M | bool llvm::isGuard(const User *U) { |
19 | 3.52M | return match(U, m_Intrinsic<Intrinsic::experimental_guard>()); |
20 | 3.52M | } |
21 | | |
22 | 126k | bool llvm::isWidenableCondition(const Value *V) { |
23 | 126k | return match(V, m_Intrinsic<Intrinsic::experimental_widenable_condition>()); |
24 | 126k | } |
25 | | |
26 | 616k | bool llvm::isWidenableBranch(const User *U) { |
27 | 616k | Value *Condition, *WidenableCondition; |
28 | 616k | BasicBlock *GuardedBB, *DeoptBB; |
29 | 616k | return parseWidenableBranch(U, Condition, WidenableCondition, GuardedBB, |
30 | 616k | DeoptBB); |
31 | 616k | } |
32 | | |
33 | 491k | bool llvm::isGuardAsWidenableBranch(const User *U) { |
34 | 491k | if (!isWidenableBranch(U)) |
35 | 485k | return false; |
36 | 6.27k | BasicBlock *DeoptBB = cast<BranchInst>(U)->getSuccessor(1); |
37 | 6.27k | SmallPtrSet<const BasicBlock *, 2> Visited; |
38 | 6.27k | Visited.insert(DeoptBB); |
39 | 6.28k | do { |
40 | 6.82k | for (auto &Insn : *DeoptBB) { |
41 | 6.82k | if (match(&Insn, m_Intrinsic<Intrinsic::experimental_deoptimize>())) |
42 | 5.65k | return true; |
43 | 1.16k | if (Insn.mayHaveSideEffects()) |
44 | 384 | return false; |
45 | 1.16k | } |
46 | 241 | DeoptBB = DeoptBB->getUniqueSuccessor(); |
47 | 241 | if (!DeoptBB) |
48 | 234 | return false; |
49 | 241 | } while (Visited.insert(DeoptBB).second); |
50 | 0 | return false; |
51 | 6.27k | } |
52 | | |
53 | | bool llvm::parseWidenableBranch(const User *U, Value *&Condition, |
54 | | Value *&WidenableCondition, |
55 | 617k | BasicBlock *&IfTrueBB, BasicBlock *&IfFalseBB) { |
56 | | |
57 | 617k | Use *C, *WC; |
58 | 617k | if (parseWidenableBranch(const_cast<User*>(U), C, WC, IfTrueBB, IfFalseBB)) { |
59 | 14.9k | if (C) |
60 | 12.0k | Condition = C->get(); |
61 | 2.82k | else |
62 | 2.82k | Condition = ConstantInt::getTrue(IfTrueBB->getContext()); |
63 | 14.9k | WidenableCondition = WC->get(); |
64 | 14.9k | return true; |
65 | 14.9k | } |
66 | 602k | return false; |
67 | 617k | } |
68 | | |
69 | | bool llvm::parseWidenableBranch(User *U, Use *&C,Use *&WC, |
70 | 618k | BasicBlock *&IfTrueBB, BasicBlock *&IfFalseBB) { |
71 | | |
72 | 618k | auto *BI = dyn_cast<BranchInst>(U); |
73 | 618k | if (!BI || !BI->isConditional()) |
74 | 450k | return false; |
75 | 168k | auto *Cond = BI->getCondition(); |
76 | 168k | if (!Cond->hasOneUse()) |
77 | 65.6k | return false; |
78 | | |
79 | 102k | IfTrueBB = BI->getSuccessor(0); |
80 | 102k | IfFalseBB = BI->getSuccessor(1); |
81 | | |
82 | 102k | if (match(Cond, m_Intrinsic<Intrinsic::experimental_widenable_condition>())) { |
83 | 3.32k | WC = &BI->getOperandUse(0); |
84 | 3.32k | C = nullptr; |
85 | 3.32k | return true; |
86 | 3.32k | } |
87 | | |
88 | | // Check for two cases: |
89 | | // 1) br (i1 (and A, WC())), label %IfTrue, label %IfFalse |
90 | | // 2) br (i1 (and WC(), B)), label %IfTrue, label %IfFalse |
91 | | // We do not check for more generalized and trees as we should canonicalize |
92 | | // to the form above in instcombine. (TODO) |
93 | 99.2k | Value *A, *B; |
94 | 99.2k | if (!match(Cond, m_And(m_Value(A), m_Value(B)))) |
95 | 82.3k | return false; |
96 | 16.8k | auto *And = dyn_cast<Instruction>(Cond); |
97 | 16.8k | if (!And) |
98 | | // Could be a constexpr |
99 | 0 | return false; |
100 | | |
101 | 16.8k | if (match(A, m_Intrinsic<Intrinsic::experimental_widenable_condition>()) && |
102 | 16.8k | A->hasOneUse()) { |
103 | 817 | WC = &And->getOperandUse(0); |
104 | 817 | C = &And->getOperandUse(1); |
105 | 817 | return true; |
106 | 817 | } |
107 | | |
108 | 16.0k | if (match(B, m_Intrinsic<Intrinsic::experimental_widenable_condition>()) && |
109 | 16.0k | B->hasOneUse()) { |
110 | 12.0k | WC = &And->getOperandUse(1); |
111 | 12.0k | C = &And->getOperandUse(0); |
112 | 12.0k | return true; |
113 | 12.0k | } |
114 | 3.94k | return false; |
115 | 16.0k | } |
116 | | |
117 | | template <typename CallbackType> |
118 | | static void parseCondition(Value *Condition, |
119 | 93.1k | CallbackType RecordCheckOrWidenableCond) { |
120 | 93.1k | SmallVector<Value *, 4> Worklist(1, Condition); |
121 | 93.1k | SmallPtrSet<Value *, 4> Visited; |
122 | 93.1k | Visited.insert(Condition); |
123 | 184k | do { |
124 | 184k | Value *Check = Worklist.pop_back_val(); |
125 | 184k | Value *LHS, *RHS; |
126 | 184k | if (match(Check, m_And(m_Value(LHS), m_Value(RHS)))) { |
127 | 57.5k | if (Visited.insert(LHS).second) |
128 | 53.9k | Worklist.push_back(LHS); |
129 | 57.5k | if (Visited.insert(RHS).second) |
130 | 39.5k | Worklist.push_back(RHS); |
131 | 57.5k | continue; |
132 | 57.5k | } |
133 | 126k | if (!RecordCheckOrWidenableCond(Check)) |
134 | 2.75k | break; |
135 | 181k | } while (!Worklist.empty()); |
136 | 93.1k | } GuardUtils.cpp:void parseCondition<llvm::parseWidenableGuard(llvm::User const*, llvm::SmallVectorImpl<llvm::Value*>&)::$_0>(llvm::Value*, llvm::parseWidenableGuard(llvm::User const*, llvm::SmallVectorImpl<llvm::Value*>&)::$_0) Line | Count | Source | 119 | 88.3k | CallbackType RecordCheckOrWidenableCond) { | 120 | 88.3k | SmallVector<Value *, 4> Worklist(1, Condition); | 121 | 88.3k | SmallPtrSet<Value *, 4> Visited; | 122 | 88.3k | Visited.insert(Condition); | 123 | 176k | do { | 124 | 176k | Value *Check = Worklist.pop_back_val(); | 125 | 176k | Value *LHS, *RHS; | 126 | 176k | if (match(Check, m_And(m_Value(LHS), m_Value(RHS)))) { | 127 | 54.9k | if (Visited.insert(LHS).second) | 128 | 51.3k | Worklist.push_back(LHS); | 129 | 54.9k | if (Visited.insert(RHS).second) | 130 | 36.9k | Worklist.push_back(RHS); | 131 | 54.9k | continue; | 132 | 54.9k | } | 133 | 121k | if (!RecordCheckOrWidenableCond(Check)) | 134 | 0 | break; | 135 | 176k | } while (!Worklist.empty()); | 136 | 88.3k | } |
GuardUtils.cpp:void parseCondition<llvm::extractWidenableCondition(llvm::User const*)::$_1>(llvm::Value*, llvm::extractWidenableCondition(llvm::User const*)::$_1) Line | Count | Source | 119 | 4.84k | CallbackType RecordCheckOrWidenableCond) { | 120 | 4.84k | SmallVector<Value *, 4> Worklist(1, Condition); | 121 | 4.84k | SmallPtrSet<Value *, 4> Visited; | 122 | 4.84k | Visited.insert(Condition); | 123 | 7.68k | do { | 124 | 7.68k | Value *Check = Worklist.pop_back_val(); | 125 | 7.68k | Value *LHS, *RHS; | 126 | 7.68k | if (match(Check, m_And(m_Value(LHS), m_Value(RHS)))) { | 127 | 2.58k | if (Visited.insert(LHS).second) | 128 | 2.58k | Worklist.push_back(LHS); | 129 | 2.58k | if (Visited.insert(RHS).second) | 130 | 2.54k | Worklist.push_back(RHS); | 131 | 2.58k | continue; | 132 | 2.58k | } | 133 | 5.09k | if (!RecordCheckOrWidenableCond(Check)) | 134 | 2.75k | break; | 135 | 5.09k | } while (!Worklist.empty()); | 136 | 4.84k | } |
|
137 | | |
138 | | void llvm::parseWidenableGuard(const User *U, |
139 | 88.3k | llvm::SmallVectorImpl<Value *> &Checks) { |
140 | 88.3k | assert((isGuard(U) || isWidenableBranch(U)) && "Should be"); |
141 | 88.3k | Value *Condition = isGuard(U) ? cast<IntrinsicInst>(U)->getArgOperand(0) |
142 | 88.3k | : cast<BranchInst>(U)->getCondition(); |
143 | | |
144 | 121k | parseCondition(Condition, [&](Value *Check) { |
145 | 121k | if (!isWidenableCondition(Check)) |
146 | 118k | Checks.push_back(Check); |
147 | 121k | return true; |
148 | 121k | }); |
149 | 88.3k | } |
150 | | |
151 | 5.31k | Value *llvm::extractWidenableCondition(const User *U) { |
152 | 5.31k | auto *BI = dyn_cast<BranchInst>(U); |
153 | 5.31k | if (!BI || !BI->isConditional()) |
154 | 0 | return nullptr; |
155 | | |
156 | 5.31k | auto Condition = BI->getCondition(); |
157 | 5.31k | if (!Condition->hasOneUse()) |
158 | 466 | return nullptr; |
159 | | |
160 | 4.84k | Value *WidenableCondition = nullptr; |
161 | 5.09k | parseCondition(Condition, [&](Value *Check) { |
162 | | // We require widenable_condition has only one use, otherwise we don't |
163 | | // consider appropriate branch as widenable. |
164 | 5.09k | if (isWidenableCondition(Check) && Check->hasOneUse()) { |
165 | 2.75k | WidenableCondition = Check; |
166 | 2.75k | return false; |
167 | 2.75k | } |
168 | 2.34k | return true; |
169 | 5.09k | }); |
170 | 4.84k | return WidenableCondition; |
171 | 5.31k | } |