llvm-project
171 строка · 5.2 Кб
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
15using namespace llvm;
16using namespace llvm::PatternMatch;
17
18bool llvm::isGuard(const User *U) {
19return match(U, m_Intrinsic<Intrinsic::experimental_guard>());
20}
21
22bool llvm::isWidenableCondition(const Value *V) {
23return match(V, m_Intrinsic<Intrinsic::experimental_widenable_condition>());
24}
25
26bool llvm::isWidenableBranch(const User *U) {
27Value *Condition, *WidenableCondition;
28BasicBlock *GuardedBB, *DeoptBB;
29return parseWidenableBranch(U, Condition, WidenableCondition, GuardedBB,
30DeoptBB);
31}
32
33bool llvm::isGuardAsWidenableBranch(const User *U) {
34if (!isWidenableBranch(U))
35return false;
36BasicBlock *DeoptBB = cast<BranchInst>(U)->getSuccessor(1);
37SmallPtrSet<const BasicBlock *, 2> Visited;
38Visited.insert(DeoptBB);
39do {
40for (auto &Insn : *DeoptBB) {
41if (match(&Insn, m_Intrinsic<Intrinsic::experimental_deoptimize>()))
42return true;
43if (Insn.mayHaveSideEffects())
44return false;
45}
46DeoptBB = DeoptBB->getUniqueSuccessor();
47if (!DeoptBB)
48return false;
49} while (Visited.insert(DeoptBB).second);
50return false;
51}
52
53bool llvm::parseWidenableBranch(const User *U, Value *&Condition,
54Value *&WidenableCondition,
55BasicBlock *&IfTrueBB, BasicBlock *&IfFalseBB) {
56
57Use *C, *WC;
58if (parseWidenableBranch(const_cast<User*>(U), C, WC, IfTrueBB, IfFalseBB)) {
59if (C)
60Condition = C->get();
61else
62Condition = ConstantInt::getTrue(IfTrueBB->getContext());
63WidenableCondition = WC->get();
64return true;
65}
66return false;
67}
68
69bool llvm::parseWidenableBranch(User *U, Use *&C,Use *&WC,
70BasicBlock *&IfTrueBB, BasicBlock *&IfFalseBB) {
71
72auto *BI = dyn_cast<BranchInst>(U);
73if (!BI || !BI->isConditional())
74return false;
75auto *Cond = BI->getCondition();
76if (!Cond->hasOneUse())
77return false;
78
79IfTrueBB = BI->getSuccessor(0);
80IfFalseBB = BI->getSuccessor(1);
81
82if (match(Cond, m_Intrinsic<Intrinsic::experimental_widenable_condition>())) {
83WC = &BI->getOperandUse(0);
84C = nullptr;
85return true;
86}
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)
93Value *A, *B;
94if (!match(Cond, m_And(m_Value(A), m_Value(B))))
95return false;
96auto *And = dyn_cast<Instruction>(Cond);
97if (!And)
98// Could be a constexpr
99return false;
100
101if (match(A, m_Intrinsic<Intrinsic::experimental_widenable_condition>()) &&
102A->hasOneUse()) {
103WC = &And->getOperandUse(0);
104C = &And->getOperandUse(1);
105return true;
106}
107
108if (match(B, m_Intrinsic<Intrinsic::experimental_widenable_condition>()) &&
109B->hasOneUse()) {
110WC = &And->getOperandUse(1);
111C = &And->getOperandUse(0);
112return true;
113}
114return false;
115}
116
117template <typename CallbackType>
118static void parseCondition(Value *Condition,
119CallbackType RecordCheckOrWidenableCond) {
120SmallVector<Value *, 4> Worklist(1, Condition);
121SmallPtrSet<Value *, 4> Visited;
122Visited.insert(Condition);
123do {
124Value *Check = Worklist.pop_back_val();
125Value *LHS, *RHS;
126if (match(Check, m_And(m_Value(LHS), m_Value(RHS)))) {
127if (Visited.insert(LHS).second)
128Worklist.push_back(LHS);
129if (Visited.insert(RHS).second)
130Worklist.push_back(RHS);
131continue;
132}
133if (!RecordCheckOrWidenableCond(Check))
134break;
135} while (!Worklist.empty());
136}
137
138void llvm::parseWidenableGuard(const User *U,
139llvm::SmallVectorImpl<Value *> &Checks) {
140assert((isGuard(U) || isWidenableBranch(U)) && "Should be");
141Value *Condition = isGuard(U) ? cast<IntrinsicInst>(U)->getArgOperand(0)
142: cast<BranchInst>(U)->getCondition();
143
144parseCondition(Condition, [&](Value *Check) {
145if (!isWidenableCondition(Check))
146Checks.push_back(Check);
147return true;
148});
149}
150
151Value *llvm::extractWidenableCondition(const User *U) {
152auto *BI = dyn_cast<BranchInst>(U);
153if (!BI || !BI->isConditional())
154return nullptr;
155
156auto Condition = BI->getCondition();
157if (!Condition->hasOneUse())
158return nullptr;
159
160Value *WidenableCondition = nullptr;
161parseCondition(Condition, [&](Value *Check) {
162// We require widenable_condition has only one use, otherwise we don't
163// consider appropriate branch as widenable.
164if (isWidenableCondition(Check) && Check->hasOneUse()) {
165WidenableCondition = Check;
166return false;
167}
168return true;
169});
170return WidenableCondition;
171}
172