summaryrefslogtreecommitdiff
path: root/lib/Analysis/BranchProbabilityInfo.cpp
blob: d7fc2c39875f5e9bd5e754514a489f1a3657c532 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
//===-- BranchProbabilityInfo.cpp - Branch Probability Analysis -*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Loops should be simplified before this analysis.
//
//===----------------------------------------------------------------------===//

#include "llvm/Instructions.h"
#include "llvm/Analysis/BranchProbabilityInfo.h"
#include <climits>

using namespace llvm;

INITIALIZE_PASS_BEGIN(BranchProbabilityInfo, "branch-prob",
                      "Branch Probability Analysis", false, true)
INITIALIZE_PASS_DEPENDENCY(LoopInfo)
INITIALIZE_PASS_END(BranchProbabilityInfo, "branch-prob",
                    "Branch Probability Analysis", false, true)

char BranchProbabilityInfo::ID = 0;


// Please note that BranchProbabilityAnalysis is not a FunctionPass.
// It is created by BranchProbabilityInfo (which is a FunctionPass), which
// provides a clear interface. Thanks to that, all heuristics and other
// private methods are hidden in the .cpp file.
class BranchProbabilityAnalysis {

  typedef std::pair<BasicBlock *, BasicBlock *> Edge;

  DenseMap<Edge, unsigned> *Weights;

  BranchProbabilityInfo *BP;

  LoopInfo *LI;


  // Weights are for internal use only. They are used by heuristics to help to
  // estimate edges' probability. Example:
  //
  // Using "Loop Branch Heuristics" we predict weights of edges for the
  // block BB2.
  //         ...
  //          |
  //          V
  //         BB1<-+
  //          |   |
  //          |   | (Weight = 128)
  //          V   |
  //         BB2--+
  //          |
  //          | (Weight = 4)
  //          V
  //         BB3
  //
  // Probability of the edge BB2->BB1 = 128 / (128 + 4) = 0.9696..
  // Probability of the edge BB2->BB3 = 4 / (128 + 4) = 0.0303..

  static const unsigned int LBH_TAKEN_WEIGHT = 128;
  static const unsigned int LBH_NONTAKEN_WEIGHT = 4;

  // Standard weight value. Used when none of the heuristics set weight for
  // the edge.
  static const unsigned int NORMAL_WEIGHT = 16;

  // Minimum weight of an edge. Please note, that weight is NEVER 0.
  static const unsigned int MIN_WEIGHT = 1;

  // Return TRUE if BB leads directly to a Return Instruction.
  static bool isReturningBlock(BasicBlock *BB) {
    SmallPtrSet<BasicBlock *, 8> Visited;

    while (true) {
      TerminatorInst *TI = BB->getTerminator();
      if (isa<ReturnInst>(TI))
        return true;

      if (TI->getNumSuccessors() > 1)
        break;

      // It is unreachable block which we can consider as a return instruction.
      if (TI->getNumSuccessors() == 0)
        return true;

      Visited.insert(BB);
      BB = TI->getSuccessor(0);

      // Stop if cycle is detected.
      if (Visited.count(BB))
        return false;
    }

    return false;
  }

  // Multiply Edge Weight by two.
  void incEdgeWeight(BasicBlock *Src, BasicBlock *Dst) {
    unsigned Weight = BP->getEdgeWeight(Src, Dst);
    unsigned MaxWeight = getMaxWeightFor(Src);

    if (Weight * 2 > MaxWeight)
      BP->setEdgeWeight(Src, Dst, MaxWeight);
    else
      BP->setEdgeWeight(Src, Dst, Weight * 2);
  }

  // Divide Edge Weight by two.
  void decEdgeWeight(BasicBlock *Src, BasicBlock *Dst) {
    unsigned Weight = BP->getEdgeWeight(Src, Dst);

    assert(Weight > 0);
    if (Weight / 2 < MIN_WEIGHT)
      BP->setEdgeWeight(Src, Dst, MIN_WEIGHT);
    else
      BP->setEdgeWeight(Src, Dst, Weight / 2);
  }


  unsigned getMaxWeightFor(BasicBlock *BB) const {
    return UINT_MAX / BB->getTerminator()->getNumSuccessors();
  }

public:
  BranchProbabilityAnalysis(DenseMap<Edge, unsigned> *W,
                            BranchProbabilityInfo *BP, LoopInfo *LI)
    : Weights(W), BP(BP), LI(LI) {
  }

  // Return Heuristics
  void calcReturnHeuristics(BasicBlock *BB);

  // Pointer Heuristics
  void calcPointerHeuristics(BasicBlock *BB);

  // Loop Branch Heuristics
  void calcLoopBranchHeuristics(BasicBlock *BB);

  bool runOnFunction(Function &F);
};

// Calculate Edge Weights using "Return Heuristics". Predict a successor which
// leads directly to Return Instruction will not be taken.
void BranchProbabilityAnalysis::calcReturnHeuristics(BasicBlock *BB){
  if (BB->getTerminator()->getNumSuccessors() == 1)
    return;

  for (succ_iterator I = succ_begin(BB), E = succ_end(BB); I != E; ++I) {
    BasicBlock *Succ = *I;
    if (isReturningBlock(Succ)) {
      decEdgeWeight(BB, Succ);
    }
  }
}

// Calculate Edge Weights using "Pointer Heuristics". Predict a comparsion
// between two pointer or pointer and NULL will fail.
void BranchProbabilityAnalysis::calcPointerHeuristics(BasicBlock *BB) {
  BranchInst * BI = dyn_cast<BranchInst>(BB->getTerminator());
  if (!BI || !BI->isConditional())
    return;

  Value *Cond = BI->getCondition();
  ICmpInst *CI = dyn_cast<ICmpInst>(Cond);
  if (!CI)
    return;

  Value *LHS = CI->getOperand(0);
  Value *RHS = CI->getOperand(1);

  if (!LHS->getType()->isPointerTy())
    return;

  assert(RHS->getType()->isPointerTy());

  BasicBlock *Taken = BI->getSuccessor(0);
  BasicBlock *NonTaken = BI->getSuccessor(1);

  // p != 0   ->   isProb = true
  // p == 0   ->   isProb = false
  // p != q   ->   isProb = true
  // p == q   ->   isProb = false;
  bool isProb = !CI->isEquality();
  if (!isProb)
    std::swap(Taken, NonTaken);

  incEdgeWeight(BB, Taken);
  decEdgeWeight(BB, NonTaken);
}

// Calculate Edge Weights using "Loop Branch Heuristics". Predict backedges
// as taken, exiting edges as not-taken.
void BranchProbabilityAnalysis::calcLoopBranchHeuristics(BasicBlock *BB) {
  unsigned numSuccs = BB->getTerminator()->getNumSuccessors();

  Loop *L = LI->getLoopFor(BB);
  if (!L)
    return;

  SmallVector<BasicBlock *, 8> BackEdges;
  SmallVector<BasicBlock *, 8> ExitingEdges;

  for (succ_iterator I = succ_begin(BB), E = succ_end(BB); I != E; ++I) {
    BasicBlock *Succ = *I;
    Loop *SuccL = LI->getLoopFor(Succ);
    if (SuccL != L)
      ExitingEdges.push_back(Succ);
    else if (Succ == L->getHeader())
      BackEdges.push_back(Succ);
  }

  if (unsigned numBackEdges = BackEdges.size()) {
    unsigned backWeight = LBH_TAKEN_WEIGHT / numBackEdges;
    if (backWeight < NORMAL_WEIGHT)
      backWeight = NORMAL_WEIGHT;

    for (SmallVector<BasicBlock *, 8>::iterator EI = BackEdges.begin(),
         EE = BackEdges.end(); EI != EE; ++EI) {
      BasicBlock *Back = *EI;
      BP->setEdgeWeight(BB, Back, backWeight);
    }
  }

  unsigned numExitingEdges = ExitingEdges.size();
  if (unsigned numNonExitingEdges = numSuccs - numExitingEdges) {
    unsigned exitWeight = LBH_NONTAKEN_WEIGHT / numNonExitingEdges;
    if (exitWeight < MIN_WEIGHT)
      exitWeight = MIN_WEIGHT;

    for (SmallVector<BasicBlock *, 8>::iterator EI = ExitingEdges.begin(),
         EE = ExitingEdges.end(); EI != EE; ++EI) {
      BasicBlock *Exiting = *EI;
      BP->setEdgeWeight(BB, Exiting, exitWeight);
    }
  }
}

bool BranchProbabilityAnalysis::runOnFunction(Function &F) {

  for (Function::iterator I = F.begin(), E = F.end(); I != E; ) {
    BasicBlock *BB = I++;

    // Only LBH uses setEdgeWeight method.
    calcLoopBranchHeuristics(BB);

    // PH and RH use only incEdgeWeight and decEwdgeWeight methods to
    // not efface LBH results.
    calcPointerHeuristics(BB);
    calcReturnHeuristics(BB);
  }

  return false;
}


bool BranchProbabilityInfo::runOnFunction(Function &F) {
  LoopInfo &LI = getAnalysis<LoopInfo>();
  BranchProbabilityAnalysis BPA(&Weights, this, &LI);
  bool ret = BPA.runOnFunction(F);
  return ret;
}

// TODO: This currently hardcodes 80% as a fraction 4/5. We will soon add a
// BranchProbability class to encapsulate the fractional probability and
// define a few static instances of the class for use as predefined thresholds.
bool BranchProbabilityInfo::isEdgeHot(BasicBlock *Src, BasicBlock *Dst) const {
  unsigned Sum = 0;
  for (succ_iterator I = succ_begin(Src), E = succ_end(Src); I != E; ++I) {
    BasicBlock *Succ = *I;
    unsigned Weight = getEdgeWeight(Src, Succ);
    unsigned PrevSum = Sum;

    Sum += Weight;
    assert(Sum > PrevSum); (void) PrevSum;
  }

  return getEdgeWeight(Src, Dst) * 5 > Sum * 4;
}

BasicBlock *BranchProbabilityInfo::getHotSucc(BasicBlock *BB) const {
  unsigned Sum = 0;
  unsigned MaxWeight = 0;
  BasicBlock *MaxSucc = 0;

  for (succ_iterator I = succ_begin(BB), E = succ_end(BB); I != E; ++I) {
    BasicBlock *Succ = *I;
    unsigned Weight = getEdgeWeight(BB, Succ);
    unsigned PrevSum = Sum;

    Sum += Weight;
    assert(Sum > PrevSum); (void) PrevSum;

    if (Weight > MaxWeight) {
      MaxWeight = Weight;
      MaxSucc = Succ;
    }
  }

  if (MaxWeight * 5 > Sum * 4)
    return MaxSucc;

  return 0;
}

// Return edge's weight. If can't find it, return DEFAULT_WEIGHT value.
unsigned
BranchProbabilityInfo::getEdgeWeight(BasicBlock *Src, BasicBlock *Dst) const {
  Edge E(Src, Dst);
  DenseMap<Edge, unsigned>::const_iterator I = Weights.find(E);

  if (I != Weights.end())
    return I->second;

  return DEFAULT_WEIGHT;
}

void BranchProbabilityInfo::setEdgeWeight(BasicBlock *Src, BasicBlock *Dst,
                                     unsigned Weight) {
  Weights[std::make_pair(Src, Dst)] = Weight;
  DEBUG(dbgs() << "setEdgeWeight: " << Src->getNameStr() << " -> "
        << Dst->getNameStr() << " to " << Weight
        << (isEdgeHot(Src, Dst) ? " [is HOT now]\n" : "\n"));
}

raw_ostream &
BranchProbabilityInfo::printEdgeProbability(raw_ostream &OS, BasicBlock *Src,
                                        BasicBlock *Dst) const {

  unsigned Sum = 0;
  for (succ_iterator I = succ_begin(Src), E = succ_end(Src); I != E; ++I) {
    BasicBlock *Succ = *I;
    unsigned Weight = getEdgeWeight(Src, Succ);
    unsigned PrevSum = Sum;

    Sum += Weight;
    assert(Sum > PrevSum); (void) PrevSum;
  }

  double Prob = (double)getEdgeWeight(Src, Dst) / Sum;
  OS << "probability (" << Src->getNameStr() << " --> " << Dst->getNameStr()
     << ") = " << Prob << "\n";

  return OS;
}