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 bool llvm::isGuard(const User *U) {
19   return match(U, m_Intrinsic<Intrinsic::experimental_guard>());
20 }
21 
22 bool llvm::isWidenableBranch(const User *U) {
23   Value *Condition, *WidenableCondition;
24   BasicBlock *GuardedBB, *DeoptBB;
25   return parseWidenableBranch(U, Condition, WidenableCondition, GuardedBB,
26                               DeoptBB);
27 }
28 
29 bool llvm::isGuardAsWidenableBranch(const User *U) {
30   Value *Condition, *WidenableCondition;
31   BasicBlock *GuardedBB, *DeoptBB;
32   if (!parseWidenableBranch(U, Condition, WidenableCondition, GuardedBB,
33                             DeoptBB))
34     return false;
35   SmallPtrSet<const BasicBlock *, 2> Visited;
36   Visited.insert(DeoptBB);
37   do {
38     for (auto &Insn : *DeoptBB) {
39       if (match(&Insn, m_Intrinsic<Intrinsic::experimental_deoptimize>()))
40         return true;
41       if (Insn.mayHaveSideEffects())
42         return false;
43     }
44     DeoptBB = DeoptBB->getUniqueSuccessor();
45     if (!DeoptBB)
46       return false;
47   } while (Visited.insert(DeoptBB).second);
48   return false;
49 }
50 
51 bool llvm::parseWidenableBranch(const User *U, Value *&Condition,
52                                 Value *&WidenableCondition,
53                                 BasicBlock *&IfTrueBB, BasicBlock *&IfFalseBB) {
54 
55   Use *C, *WC;
56   if (parseWidenableBranch(const_cast<User*>(U), C, WC, IfTrueBB, IfFalseBB)) {
57     if (C)
58       Condition = C->get();
59     else
60       Condition = ConstantInt::getTrue(IfTrueBB->getContext());
61     WidenableCondition = WC->get();
62     return true;
63   }
64   return false;
65 }
66 
67 bool llvm::parseWidenableBranch(User *U, Use *&C,Use *&WC,
68                                 BasicBlock *&IfTrueBB, BasicBlock *&IfFalseBB) {
69 
70   auto *BI = dyn_cast<BranchInst>(U);
71   if (!BI || !BI->isConditional())
72     return false;
73   auto *Cond = BI->getCondition();
74   if (!Cond->hasOneUse())
75     return false;
76 
77   IfTrueBB = BI->getSuccessor(0);
78   IfFalseBB = BI->getSuccessor(1);
79 
80   if (match(Cond, m_Intrinsic<Intrinsic::experimental_widenable_condition>())) {
81     WC = &BI->getOperandUse(0);
82     C = nullptr;
83     return true;
84   }
85 
86   // Check for two cases:
87   // 1) br (i1 (and A, WC())), label %IfTrue, label %IfFalse
88   // 2) br (i1 (and WC(), B)), label %IfTrue, label %IfFalse
89   // We do not check for more generalized and trees as we should canonicalize
90   // to the form above in instcombine. (TODO)
91   Value *A, *B;
92   if (!match(Cond, m_And(m_Value(A), m_Value(B))))
93     return false;
94   auto *And = dyn_cast<Instruction>(Cond);
95   if (!And)
96     // Could be a constexpr
97     return false;
98 
99   if (match(A, m_Intrinsic<Intrinsic::experimental_widenable_condition>()) &&
100       A->hasOneUse()) {
101     WC = &And->getOperandUse(0);
102     C = &And->getOperandUse(1);
103     return true;
104   }
105 
106   if (match(B, m_Intrinsic<Intrinsic::experimental_widenable_condition>()) &&
107       B->hasOneUse()) {
108     WC = &And->getOperandUse(1);
109     C = &And->getOperandUse(0);
110     return true;
111   }
112   return false;
113 }
114