Coverage Report

Created: 2024-01-17 10:31

/src/llvm-project/llvm/lib/Analysis/GuardUtils.cpp
Line
Count
Source (jump to first uncovered line)
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
3.52M
bool llvm::isGuard(const User *U) {
19
3.52M
  return match(U, m_Intrinsic<Intrinsic::experimental_guard>());
20
3.52M
}
21
22
126k
bool llvm::isWidenableCondition(const Value *V) {
23
126k
  return match(V, m_Intrinsic<Intrinsic::experimental_widenable_condition>());
24
126k
}
25
26
616k
bool llvm::isWidenableBranch(const User *U) {
27
616k
  Value *Condition, *WidenableCondition;
28
616k
  BasicBlock *GuardedBB, *DeoptBB;
29
616k
  return parseWidenableBranch(U, Condition, WidenableCondition, GuardedBB,
30
616k
                              DeoptBB);
31
616k
}
32
33
491k
bool llvm::isGuardAsWidenableBranch(const User *U) {
34
491k
  if (!isWidenableBranch(U))
35
485k
    return false;
36
6.27k
  BasicBlock *DeoptBB = cast<BranchInst>(U)->getSuccessor(1);
37
6.27k
  SmallPtrSet<const BasicBlock *, 2> Visited;
38
6.27k
  Visited.insert(DeoptBB);
39
6.28k
  do {
40
6.82k
    for (auto &Insn : *DeoptBB) {
41
6.82k
      if (match(&Insn, m_Intrinsic<Intrinsic::experimental_deoptimize>()))
42
5.65k
        return true;
43
1.16k
      if (Insn.mayHaveSideEffects())
44
384
        return false;
45
1.16k
    }
46
241
    DeoptBB = DeoptBB->getUniqueSuccessor();
47
241
    if (!DeoptBB)
48
234
      return false;
49
241
  } while (Visited.insert(DeoptBB).second);
50
0
  return false;
51
6.27k
}
52
53
bool llvm::parseWidenableBranch(const User *U, Value *&Condition,
54
                                Value *&WidenableCondition,
55
617k
                                BasicBlock *&IfTrueBB, BasicBlock *&IfFalseBB) {
56
57
617k
  Use *C, *WC;
58
617k
  if (parseWidenableBranch(const_cast<User*>(U), C, WC, IfTrueBB, IfFalseBB)) {
59
14.9k
    if (C)
60
12.0k
      Condition = C->get();
61
2.82k
    else
62
2.82k
      Condition = ConstantInt::getTrue(IfTrueBB->getContext());
63
14.9k
    WidenableCondition = WC->get();
64
14.9k
    return true;
65
14.9k
  }
66
602k
  return false;
67
617k
}
68
69
bool llvm::parseWidenableBranch(User *U, Use *&C,Use *&WC,
70
618k
                                BasicBlock *&IfTrueBB, BasicBlock *&IfFalseBB) {
71
72
618k
  auto *BI = dyn_cast<BranchInst>(U);
73
618k
  if (!BI || !BI->isConditional())
74
450k
    return false;
75
168k
  auto *Cond = BI->getCondition();
76
168k
  if (!Cond->hasOneUse())
77
65.6k
    return false;
78
79
102k
  IfTrueBB = BI->getSuccessor(0);
80
102k
  IfFalseBB = BI->getSuccessor(1);
81
82
102k
  if (match(Cond, m_Intrinsic<Intrinsic::experimental_widenable_condition>())) {
83
3.32k
    WC = &BI->getOperandUse(0);
84
3.32k
    C = nullptr;
85
3.32k
    return true;
86
3.32k
  }
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)
93
99.2k
  Value *A, *B;
94
99.2k
  if (!match(Cond, m_And(m_Value(A), m_Value(B))))
95
82.3k
    return false;
96
16.8k
  auto *And = dyn_cast<Instruction>(Cond);
97
16.8k
  if (!And)
98
    // Could be a constexpr
99
0
    return false;
100
101
16.8k
  if (match(A, m_Intrinsic<Intrinsic::experimental_widenable_condition>()) &&
102
16.8k
      A->hasOneUse()) {
103
817
    WC = &And->getOperandUse(0);
104
817
    C = &And->getOperandUse(1);
105
817
    return true;
106
817
  }
107
108
16.0k
  if (match(B, m_Intrinsic<Intrinsic::experimental_widenable_condition>()) &&
109
16.0k
      B->hasOneUse()) {
110
12.0k
    WC = &And->getOperandUse(1);
111
12.0k
    C = &And->getOperandUse(0);
112
12.0k
    return true;
113
12.0k
  }
114
3.94k
  return false;
115
16.0k
}
116
117
template <typename CallbackType>
118
static void parseCondition(Value *Condition,
119
93.1k
                           CallbackType RecordCheckOrWidenableCond) {
120
93.1k
  SmallVector<Value *, 4> Worklist(1, Condition);
121
93.1k
  SmallPtrSet<Value *, 4> Visited;
122
93.1k
  Visited.insert(Condition);
123
184k
  do {
124
184k
    Value *Check = Worklist.pop_back_val();
125
184k
    Value *LHS, *RHS;
126
184k
    if (match(Check, m_And(m_Value(LHS), m_Value(RHS)))) {
127
57.5k
      if (Visited.insert(LHS).second)
128
53.9k
        Worklist.push_back(LHS);
129
57.5k
      if (Visited.insert(RHS).second)
130
39.5k
        Worklist.push_back(RHS);
131
57.5k
      continue;
132
57.5k
    }
133
126k
    if (!RecordCheckOrWidenableCond(Check))
134
2.75k
      break;
135
181k
  } while (!Worklist.empty());
136
93.1k
}
GuardUtils.cpp:void parseCondition<llvm::parseWidenableGuard(llvm::User const*, llvm::SmallVectorImpl<llvm::Value*>&)::$_0>(llvm::Value*, llvm::parseWidenableGuard(llvm::User const*, llvm::SmallVectorImpl<llvm::Value*>&)::$_0)
Line
Count
Source
119
88.3k
                           CallbackType RecordCheckOrWidenableCond) {
120
88.3k
  SmallVector<Value *, 4> Worklist(1, Condition);
121
88.3k
  SmallPtrSet<Value *, 4> Visited;
122
88.3k
  Visited.insert(Condition);
123
176k
  do {
124
176k
    Value *Check = Worklist.pop_back_val();
125
176k
    Value *LHS, *RHS;
126
176k
    if (match(Check, m_And(m_Value(LHS), m_Value(RHS)))) {
127
54.9k
      if (Visited.insert(LHS).second)
128
51.3k
        Worklist.push_back(LHS);
129
54.9k
      if (Visited.insert(RHS).second)
130
36.9k
        Worklist.push_back(RHS);
131
54.9k
      continue;
132
54.9k
    }
133
121k
    if (!RecordCheckOrWidenableCond(Check))
134
0
      break;
135
176k
  } while (!Worklist.empty());
136
88.3k
}
GuardUtils.cpp:void parseCondition<llvm::extractWidenableCondition(llvm::User const*)::$_1>(llvm::Value*, llvm::extractWidenableCondition(llvm::User const*)::$_1)
Line
Count
Source
119
4.84k
                           CallbackType RecordCheckOrWidenableCond) {
120
4.84k
  SmallVector<Value *, 4> Worklist(1, Condition);
121
4.84k
  SmallPtrSet<Value *, 4> Visited;
122
4.84k
  Visited.insert(Condition);
123
7.68k
  do {
124
7.68k
    Value *Check = Worklist.pop_back_val();
125
7.68k
    Value *LHS, *RHS;
126
7.68k
    if (match(Check, m_And(m_Value(LHS), m_Value(RHS)))) {
127
2.58k
      if (Visited.insert(LHS).second)
128
2.58k
        Worklist.push_back(LHS);
129
2.58k
      if (Visited.insert(RHS).second)
130
2.54k
        Worklist.push_back(RHS);
131
2.58k
      continue;
132
2.58k
    }
133
5.09k
    if (!RecordCheckOrWidenableCond(Check))
134
2.75k
      break;
135
5.09k
  } while (!Worklist.empty());
136
4.84k
}
137
138
void llvm::parseWidenableGuard(const User *U,
139
88.3k
                               llvm::SmallVectorImpl<Value *> &Checks) {
140
88.3k
  assert((isGuard(U) || isWidenableBranch(U)) && "Should be");
141
88.3k
  Value *Condition = isGuard(U) ? cast<IntrinsicInst>(U)->getArgOperand(0)
142
88.3k
                                : cast<BranchInst>(U)->getCondition();
143
144
121k
  parseCondition(Condition, [&](Value *Check) {
145
121k
    if (!isWidenableCondition(Check))
146
118k
      Checks.push_back(Check);
147
121k
    return true;
148
121k
  });
149
88.3k
}
150
151
5.31k
Value *llvm::extractWidenableCondition(const User *U) {
152
5.31k
  auto *BI = dyn_cast<BranchInst>(U);
153
5.31k
  if (!BI || !BI->isConditional())
154
0
    return nullptr;
155
156
5.31k
  auto Condition = BI->getCondition();
157
5.31k
  if (!Condition->hasOneUse())
158
466
    return nullptr;
159
160
4.84k
  Value *WidenableCondition = nullptr;
161
5.09k
  parseCondition(Condition, [&](Value *Check) {
162
    // We require widenable_condition has only one use, otherwise we don't
163
    // consider appropriate branch as widenable.
164
5.09k
    if (isWidenableCondition(Check) && Check->hasOneUse()) {
165
2.75k
      WidenableCondition = Check;
166
2.75k
      return false;
167
2.75k
    }
168
2.34k
    return true;
169
5.09k
  });
170
4.84k
  return WidenableCondition;
171
5.31k
}