1 //===-- GuardUtils.cpp - Utils for work with guards -------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
8 // Utils that are used to perform analyzes related to guards and their
10 //===----------------------------------------------------------------------===//
12 #include "llvm/Analysis/GuardUtils.h"
13 #include "llvm/IR/PatternMatch.h"
16 using namespace llvm::PatternMatch
;
18 bool llvm::isGuard(const User
*U
) {
19 return match(U
, m_Intrinsic
<Intrinsic::experimental_guard
>());
22 bool llvm::isWidenableCondition(const Value
*V
) {
23 return match(V
, m_Intrinsic
<Intrinsic::experimental_widenable_condition
>());
26 bool llvm::isWidenableBranch(const User
*U
) {
27 Value
*Condition
, *WidenableCondition
;
28 BasicBlock
*GuardedBB
, *DeoptBB
;
29 return parseWidenableBranch(U
, Condition
, WidenableCondition
, GuardedBB
,
33 bool llvm::isGuardAsWidenableBranch(const User
*U
) {
34 if (!isWidenableBranch(U
))
36 BasicBlock
*DeoptBB
= cast
<BranchInst
>(U
)->getSuccessor(1);
37 SmallPtrSet
<const BasicBlock
*, 2> Visited
;
38 Visited
.insert(DeoptBB
);
40 for (auto &Insn
: *DeoptBB
) {
41 if (match(&Insn
, m_Intrinsic
<Intrinsic::experimental_deoptimize
>()))
43 if (Insn
.mayHaveSideEffects())
46 DeoptBB
= DeoptBB
->getUniqueSuccessor();
49 } while (Visited
.insert(DeoptBB
).second
);
53 bool llvm::parseWidenableBranch(const User
*U
, Value
*&Condition
,
54 Value
*&WidenableCondition
,
55 BasicBlock
*&IfTrueBB
, BasicBlock
*&IfFalseBB
) {
58 if (parseWidenableBranch(const_cast<User
*>(U
), C
, WC
, IfTrueBB
, IfFalseBB
)) {
62 Condition
= ConstantInt::getTrue(IfTrueBB
->getContext());
63 WidenableCondition
= WC
->get();
69 bool llvm::parseWidenableBranch(User
*U
, Use
*&C
,Use
*&WC
,
70 BasicBlock
*&IfTrueBB
, BasicBlock
*&IfFalseBB
) {
72 auto *BI
= dyn_cast
<BranchInst
>(U
);
73 if (!BI
|| !BI
->isConditional())
75 auto *Cond
= BI
->getCondition();
76 if (!Cond
->hasOneUse())
79 IfTrueBB
= BI
->getSuccessor(0);
80 IfFalseBB
= BI
->getSuccessor(1);
82 if (match(Cond
, m_Intrinsic
<Intrinsic::experimental_widenable_condition
>())) {
83 WC
= &BI
->getOperandUse(0);
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)
94 if (!match(Cond
, m_And(m_Value(A
), m_Value(B
))))
96 auto *And
= dyn_cast
<Instruction
>(Cond
);
98 // Could be a constexpr
101 if (match(A
, m_Intrinsic
<Intrinsic::experimental_widenable_condition
>()) &&
103 WC
= &And
->getOperandUse(0);
104 C
= &And
->getOperandUse(1);
108 if (match(B
, m_Intrinsic
<Intrinsic::experimental_widenable_condition
>()) &&
110 WC
= &And
->getOperandUse(1);
111 C
= &And
->getOperandUse(0);
117 template <typename CallbackType
>
118 static void parseCondition(Value
*Condition
,
119 CallbackType RecordCheckOrWidenableCond
) {
120 SmallVector
<Value
*, 4> Worklist(1, Condition
);
121 SmallPtrSet
<Value
*, 4> Visited
;
122 Visited
.insert(Condition
);
124 Value
*Check
= Worklist
.pop_back_val();
126 if (match(Check
, m_And(m_Value(LHS
), m_Value(RHS
)))) {
127 if (Visited
.insert(LHS
).second
)
128 Worklist
.push_back(LHS
);
129 if (Visited
.insert(RHS
).second
)
130 Worklist
.push_back(RHS
);
133 if (!RecordCheckOrWidenableCond(Check
))
135 } while (!Worklist
.empty());
138 void llvm::parseWidenableGuard(const User
*U
,
139 llvm::SmallVectorImpl
<Value
*> &Checks
) {
140 assert((isGuard(U
) || isWidenableBranch(U
)) && "Should be");
141 Value
*Condition
= isGuard(U
) ? cast
<IntrinsicInst
>(U
)->getArgOperand(0)
142 : cast
<BranchInst
>(U
)->getCondition();
144 parseCondition(Condition
, [&](Value
*Check
) {
145 if (!isWidenableCondition(Check
))
146 Checks
.push_back(Check
);
151 Value
*llvm::extractWidenableCondition(const User
*U
) {
152 auto *BI
= dyn_cast
<BranchInst
>(U
);
153 if (!BI
|| !BI
->isConditional())
156 auto Condition
= BI
->getCondition();
157 if (!Condition
->hasOneUse())
160 Value
*WidenableCondition
= nullptr;
161 parseCondition(Condition
, [&](Value
*Check
) {
162 // We require widenable_condition has only one use, otherwise we don't
163 // consider appropriate branch as widenable.
164 if (isWidenableCondition(Check
) && Check
->hasOneUse()) {
165 WidenableCondition
= Check
;
170 return WidenableCondition
;