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