10b57cec5SDimitry Andric //===-- GuardUtils.cpp - Utils for work with guards -------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric // Utils that are used to perform analyzes related to guards and their
90b57cec5SDimitry Andric // conditions.
100b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
110b57cec5SDimitry Andric
120b57cec5SDimitry Andric #include "llvm/Analysis/GuardUtils.h"
130b57cec5SDimitry Andric #include "llvm/IR/PatternMatch.h"
140b57cec5SDimitry Andric
150b57cec5SDimitry Andric using namespace llvm;
16480093f4SDimitry Andric using namespace llvm::PatternMatch;
170b57cec5SDimitry Andric
isGuard(const User * U)180b57cec5SDimitry Andric bool llvm::isGuard(const User *U) {
190b57cec5SDimitry Andric return match(U, m_Intrinsic<Intrinsic::experimental_guard>());
200b57cec5SDimitry Andric }
210b57cec5SDimitry Andric
isWidenableCondition(const Value * V)22*5f757f3fSDimitry Andric bool llvm::isWidenableCondition(const Value *V) {
23*5f757f3fSDimitry Andric return match(V, m_Intrinsic<Intrinsic::experimental_widenable_condition>());
24*5f757f3fSDimitry Andric }
25*5f757f3fSDimitry Andric
isWidenableBranch(const User * U)26480093f4SDimitry Andric bool llvm::isWidenableBranch(const User *U) {
27480093f4SDimitry Andric Value *Condition, *WidenableCondition;
28480093f4SDimitry Andric BasicBlock *GuardedBB, *DeoptBB;
29480093f4SDimitry Andric return parseWidenableBranch(U, Condition, WidenableCondition, GuardedBB,
30480093f4SDimitry Andric DeoptBB);
31480093f4SDimitry Andric }
32480093f4SDimitry Andric
isGuardAsWidenableBranch(const User * U)330b57cec5SDimitry Andric bool llvm::isGuardAsWidenableBranch(const User *U) {
34*5f757f3fSDimitry Andric if (!isWidenableBranch(U))
350b57cec5SDimitry Andric return false;
36*5f757f3fSDimitry Andric BasicBlock *DeoptBB = cast<BranchInst>(U)->getSuccessor(1);
3706c3fb27SDimitry Andric SmallPtrSet<const BasicBlock *, 2> Visited;
3806c3fb27SDimitry Andric Visited.insert(DeoptBB);
3906c3fb27SDimitry Andric do {
400b57cec5SDimitry Andric for (auto &Insn : *DeoptBB) {
410b57cec5SDimitry Andric if (match(&Insn, m_Intrinsic<Intrinsic::experimental_deoptimize>()))
420b57cec5SDimitry Andric return true;
430b57cec5SDimitry Andric if (Insn.mayHaveSideEffects())
440b57cec5SDimitry Andric return false;
450b57cec5SDimitry Andric }
4606c3fb27SDimitry Andric DeoptBB = DeoptBB->getUniqueSuccessor();
4706c3fb27SDimitry Andric if (!DeoptBB)
4806c3fb27SDimitry Andric return false;
4906c3fb27SDimitry Andric } while (Visited.insert(DeoptBB).second);
500b57cec5SDimitry Andric return false;
510b57cec5SDimitry Andric }
520b57cec5SDimitry Andric
parseWidenableBranch(const User * U,Value * & Condition,Value * & WidenableCondition,BasicBlock * & IfTrueBB,BasicBlock * & IfFalseBB)530b57cec5SDimitry Andric bool llvm::parseWidenableBranch(const User *U, Value *&Condition,
540b57cec5SDimitry Andric Value *&WidenableCondition,
550b57cec5SDimitry Andric BasicBlock *&IfTrueBB, BasicBlock *&IfFalseBB) {
56480093f4SDimitry Andric
57480093f4SDimitry Andric Use *C, *WC;
58480093f4SDimitry Andric if (parseWidenableBranch(const_cast<User*>(U), C, WC, IfTrueBB, IfFalseBB)) {
59480093f4SDimitry Andric if (C)
60480093f4SDimitry Andric Condition = C->get();
61480093f4SDimitry Andric else
62480093f4SDimitry Andric Condition = ConstantInt::getTrue(IfTrueBB->getContext());
63480093f4SDimitry Andric WidenableCondition = WC->get();
64480093f4SDimitry Andric return true;
65480093f4SDimitry Andric }
660b57cec5SDimitry Andric return false;
67480093f4SDimitry Andric }
68480093f4SDimitry Andric
parseWidenableBranch(User * U,Use * & C,Use * & WC,BasicBlock * & IfTrueBB,BasicBlock * & IfFalseBB)69480093f4SDimitry Andric bool llvm::parseWidenableBranch(User *U, Use *&C,Use *&WC,
70480093f4SDimitry Andric BasicBlock *&IfTrueBB, BasicBlock *&IfFalseBB) {
71480093f4SDimitry Andric
72480093f4SDimitry Andric auto *BI = dyn_cast<BranchInst>(U);
73480093f4SDimitry Andric if (!BI || !BI->isConditional())
74480093f4SDimitry Andric return false;
75480093f4SDimitry Andric auto *Cond = BI->getCondition();
76480093f4SDimitry Andric if (!Cond->hasOneUse())
77480093f4SDimitry Andric return false;
78480093f4SDimitry Andric
79480093f4SDimitry Andric IfTrueBB = BI->getSuccessor(0);
80480093f4SDimitry Andric IfFalseBB = BI->getSuccessor(1);
81480093f4SDimitry Andric
82480093f4SDimitry Andric if (match(Cond, m_Intrinsic<Intrinsic::experimental_widenable_condition>())) {
83480093f4SDimitry Andric WC = &BI->getOperandUse(0);
84480093f4SDimitry Andric C = nullptr;
85480093f4SDimitry Andric return true;
86480093f4SDimitry Andric }
87480093f4SDimitry Andric
88480093f4SDimitry Andric // Check for two cases:
89480093f4SDimitry Andric // 1) br (i1 (and A, WC())), label %IfTrue, label %IfFalse
90480093f4SDimitry Andric // 2) br (i1 (and WC(), B)), label %IfTrue, label %IfFalse
91480093f4SDimitry Andric // We do not check for more generalized and trees as we should canonicalize
92480093f4SDimitry Andric // to the form above in instcombine. (TODO)
93480093f4SDimitry Andric Value *A, *B;
94480093f4SDimitry Andric if (!match(Cond, m_And(m_Value(A), m_Value(B))))
95480093f4SDimitry Andric return false;
96480093f4SDimitry Andric auto *And = dyn_cast<Instruction>(Cond);
97480093f4SDimitry Andric if (!And)
98480093f4SDimitry Andric // Could be a constexpr
99480093f4SDimitry Andric return false;
100480093f4SDimitry Andric
101480093f4SDimitry Andric if (match(A, m_Intrinsic<Intrinsic::experimental_widenable_condition>()) &&
102480093f4SDimitry Andric A->hasOneUse()) {
103480093f4SDimitry Andric WC = &And->getOperandUse(0);
104480093f4SDimitry Andric C = &And->getOperandUse(1);
105480093f4SDimitry Andric return true;
106480093f4SDimitry Andric }
107480093f4SDimitry Andric
108480093f4SDimitry Andric if (match(B, m_Intrinsic<Intrinsic::experimental_widenable_condition>()) &&
109480093f4SDimitry Andric B->hasOneUse()) {
110480093f4SDimitry Andric WC = &And->getOperandUse(1);
111480093f4SDimitry Andric C = &And->getOperandUse(0);
112480093f4SDimitry Andric return true;
113480093f4SDimitry Andric }
114480093f4SDimitry Andric return false;
1150b57cec5SDimitry Andric }
116*5f757f3fSDimitry Andric
117*5f757f3fSDimitry Andric template <typename CallbackType>
parseCondition(Value * Condition,CallbackType RecordCheckOrWidenableCond)118*5f757f3fSDimitry Andric static void parseCondition(Value *Condition,
119*5f757f3fSDimitry Andric CallbackType RecordCheckOrWidenableCond) {
120*5f757f3fSDimitry Andric SmallVector<Value *, 4> Worklist(1, Condition);
121*5f757f3fSDimitry Andric SmallPtrSet<Value *, 4> Visited;
122*5f757f3fSDimitry Andric Visited.insert(Condition);
123*5f757f3fSDimitry Andric do {
124*5f757f3fSDimitry Andric Value *Check = Worklist.pop_back_val();
125*5f757f3fSDimitry Andric Value *LHS, *RHS;
126*5f757f3fSDimitry Andric if (match(Check, m_And(m_Value(LHS), m_Value(RHS)))) {
127*5f757f3fSDimitry Andric if (Visited.insert(LHS).second)
128*5f757f3fSDimitry Andric Worklist.push_back(LHS);
129*5f757f3fSDimitry Andric if (Visited.insert(RHS).second)
130*5f757f3fSDimitry Andric Worklist.push_back(RHS);
131*5f757f3fSDimitry Andric continue;
132*5f757f3fSDimitry Andric }
133*5f757f3fSDimitry Andric if (!RecordCheckOrWidenableCond(Check))
134*5f757f3fSDimitry Andric break;
135*5f757f3fSDimitry Andric } while (!Worklist.empty());
136*5f757f3fSDimitry Andric }
137*5f757f3fSDimitry Andric
parseWidenableGuard(const User * U,llvm::SmallVectorImpl<Value * > & Checks)138*5f757f3fSDimitry Andric void llvm::parseWidenableGuard(const User *U,
139*5f757f3fSDimitry Andric llvm::SmallVectorImpl<Value *> &Checks) {
140*5f757f3fSDimitry Andric assert((isGuard(U) || isWidenableBranch(U)) && "Should be");
141*5f757f3fSDimitry Andric Value *Condition = isGuard(U) ? cast<IntrinsicInst>(U)->getArgOperand(0)
142*5f757f3fSDimitry Andric : cast<BranchInst>(U)->getCondition();
143*5f757f3fSDimitry Andric
144*5f757f3fSDimitry Andric parseCondition(Condition, [&](Value *Check) {
145*5f757f3fSDimitry Andric if (!isWidenableCondition(Check))
146*5f757f3fSDimitry Andric Checks.push_back(Check);
147*5f757f3fSDimitry Andric return true;
148*5f757f3fSDimitry Andric });
149*5f757f3fSDimitry Andric }
150*5f757f3fSDimitry Andric
extractWidenableCondition(const User * U)151*5f757f3fSDimitry Andric Value *llvm::extractWidenableCondition(const User *U) {
152*5f757f3fSDimitry Andric auto *BI = dyn_cast<BranchInst>(U);
153*5f757f3fSDimitry Andric if (!BI || !BI->isConditional())
154*5f757f3fSDimitry Andric return nullptr;
155*5f757f3fSDimitry Andric
156*5f757f3fSDimitry Andric auto Condition = BI->getCondition();
157*5f757f3fSDimitry Andric if (!Condition->hasOneUse())
158*5f757f3fSDimitry Andric return nullptr;
159*5f757f3fSDimitry Andric
160*5f757f3fSDimitry Andric Value *WidenableCondition = nullptr;
161*5f757f3fSDimitry Andric parseCondition(Condition, [&](Value *Check) {
162*5f757f3fSDimitry Andric // We require widenable_condition has only one use, otherwise we don't
163*5f757f3fSDimitry Andric // consider appropriate branch as widenable.
164*5f757f3fSDimitry Andric if (isWidenableCondition(Check) && Check->hasOneUse()) {
165*5f757f3fSDimitry Andric WidenableCondition = Check;
166*5f757f3fSDimitry Andric return false;
167*5f757f3fSDimitry Andric }
168*5f757f3fSDimitry Andric return true;
169*5f757f3fSDimitry Andric });
170*5f757f3fSDimitry Andric return WidenableCondition;
171*5f757f3fSDimitry Andric }
172