Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
14 pmbaty 1
//===- Transforms/Utils/SampleProfileInference.h ----------*- 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
//
9
/// \file
10
/// This file provides the interface for the profile inference algorithm, profi.
11
//
12
//===----------------------------------------------------------------------===//
13
 
14
#ifndef LLVM_TRANSFORMS_UTILS_SAMPLEPROFILEINFERENCE_H
15
#define LLVM_TRANSFORMS_UTILS_SAMPLEPROFILEINFERENCE_H
16
 
17
#include "llvm/ADT/DenseMap.h"
18
#include "llvm/ADT/DepthFirstIterator.h"
19
#include "llvm/ADT/SmallVector.h"
20
 
21
#include "llvm/IR/BasicBlock.h"
22
#include "llvm/IR/Instruction.h"
23
#include "llvm/IR/Instructions.h"
24
 
25
namespace llvm {
26
 
27
class Function;
28
class MachineBasicBlock;
29
class MachineFunction;
30
 
31
namespace afdo_detail {
32
 
33
template <class BlockT> struct TypeMap {};
34
template <> struct TypeMap<BasicBlock> {
35
  using BasicBlockT = BasicBlock;
36
  using FunctionT = Function;
37
};
38
template <> struct TypeMap<MachineBasicBlock> {
39
  using BasicBlockT = MachineBasicBlock;
40
  using FunctionT = MachineFunction;
41
};
42
 
43
} // end namespace afdo_detail
44
 
45
struct FlowJump;
46
 
47
/// A wrapper of a binary basic block.
48
struct FlowBlock {
49
  uint64_t Index;
50
  uint64_t Weight{0};
51
  bool HasUnknownWeight{true};
52
  bool IsUnlikely{false};
53
  uint64_t Flow{0};
54
  std::vector<FlowJump *> SuccJumps;
55
  std::vector<FlowJump *> PredJumps;
56
 
57
  /// Check if it is the entry block in the function.
58
  bool isEntry() const { return PredJumps.empty(); }
59
 
60
  /// Check if it is an exit block in the function.
61
  bool isExit() const { return SuccJumps.empty(); }
62
};
63
 
64
/// A wrapper of a jump between two basic blocks.
65
struct FlowJump {
66
  uint64_t Source;
67
  uint64_t Target;
68
  uint64_t Weight{0};
69
  bool HasUnknownWeight{true};
70
  bool IsUnlikely{false};
71
  uint64_t Flow{0};
72
};
73
 
74
/// A wrapper of binary function with basic blocks and jumps.
75
struct FlowFunction {
76
  /// Basic blocks in the function.
77
  std::vector<FlowBlock> Blocks;
78
  /// Jumps between the basic blocks.
79
  std::vector<FlowJump> Jumps;
80
  /// The index of the entry block.
81
  uint64_t Entry{0};
82
};
83
 
84
/// Various thresholds and options controlling the behavior of the profile
85
/// inference algorithm. Default values are tuned for several large-scale
86
/// applications, and can be modified via corresponding command-line flags.
87
struct ProfiParams {
88
  /// Evenly distribute flow when there are multiple equally likely options.
89
  bool EvenFlowDistribution{false};
90
 
91
  /// Evenly re-distribute flow among unknown subgraphs.
92
  bool RebalanceUnknown{false};
93
 
94
  /// Join isolated components having positive flow.
95
  bool JoinIslands{false};
96
 
97
  /// The cost of increasing a block's count by one.
98
  unsigned CostBlockInc{0};
99
 
100
  /// The cost of decreasing a block's count by one.
101
  unsigned CostBlockDec{0};
102
 
103
  /// The cost of increasing a count of zero-weight block by one.
104
  unsigned CostBlockZeroInc{0};
105
 
106
  /// The cost of increasing the entry block's count by one.
107
  unsigned CostBlockEntryInc{0};
108
 
109
  /// The cost of decreasing the entry block's count by one.
110
  unsigned CostBlockEntryDec{0};
111
 
112
  /// The cost of increasing an unknown block's count by one.
113
  unsigned CostBlockUnknownInc{0};
114
 
115
  /// The cost of increasing a jump's count by one.
116
  unsigned CostJumpInc{0};
117
 
118
  /// The cost of increasing a fall-through jump's count by one.
119
  unsigned CostJumpFTInc{0};
120
 
121
  /// The cost of decreasing a jump's count by one.
122
  unsigned CostJumpDec{0};
123
 
124
  /// The cost of decreasing a fall-through jump's count by one.
125
  unsigned CostJumpFTDec{0};
126
 
127
  /// The cost of increasing an unknown jump's count by one.
128
  unsigned CostJumpUnknownInc{0};
129
 
130
  /// The cost of increasing an unknown fall-through jump's count by one.
131
  unsigned CostJumpUnknownFTInc{0};
132
 
133
  /// The cost of taking an unlikely block/jump.
134
  const int64_t CostUnlikely = ((int64_t)1) << 30;
135
};
136
 
137
void applyFlowInference(const ProfiParams &Params, FlowFunction &Func);
138
void applyFlowInference(FlowFunction &Func);
139
 
140
/// Sample profile inference pass.
141
template <typename BT> class SampleProfileInference {
142
public:
143
  using BasicBlockT = typename afdo_detail::TypeMap<BT>::BasicBlockT;
144
  using FunctionT = typename afdo_detail::TypeMap<BT>::FunctionT;
145
  using Edge = std::pair<const BasicBlockT *, const BasicBlockT *>;
146
  using BlockWeightMap = DenseMap<const BasicBlockT *, uint64_t>;
147
  using EdgeWeightMap = DenseMap<Edge, uint64_t>;
148
  using BlockEdgeMap =
149
      DenseMap<const BasicBlockT *, SmallVector<const BasicBlockT *, 8>>;
150
 
151
  SampleProfileInference(FunctionT &F, BlockEdgeMap &Successors,
152
                         BlockWeightMap &SampleBlockWeights)
153
      : F(F), Successors(Successors), SampleBlockWeights(SampleBlockWeights) {}
154
 
155
  /// Apply the profile inference algorithm for a given function
156
  void apply(BlockWeightMap &BlockWeights, EdgeWeightMap &EdgeWeights);
157
 
158
private:
159
  /// Initialize flow function blocks, jumps and misc metadata.
160
  void initFunction(FlowFunction &Func,
161
                    const std::vector<const BasicBlockT *> &BasicBlocks,
162
                    DenseMap<const BasicBlockT *, uint64_t> &BlockIndex);
163
 
164
  /// Try to infer branch probabilities mimicking implementation of
165
  /// BranchProbabilityInfo. Unlikely taken branches are marked so that the
166
  /// inference algorithm can avoid sending flow along corresponding edges.
167
  void findUnlikelyJumps(const std::vector<const BasicBlockT *> &BasicBlocks,
168
                         BlockEdgeMap &Successors, FlowFunction &Func);
169
 
170
  /// Determine whether the block is an exit in the CFG.
171
  bool isExit(const BasicBlockT *BB);
172
 
173
  /// Function.
174
  const FunctionT &F;
175
 
176
  /// Successors for each basic block in the CFG.
177
  BlockEdgeMap &Successors;
178
 
179
  /// Map basic blocks to their sampled weights.
180
  BlockWeightMap &SampleBlockWeights;
181
};
182
 
183
template <typename BT>
184
void SampleProfileInference<BT>::apply(BlockWeightMap &BlockWeights,
185
                                       EdgeWeightMap &EdgeWeights) {
186
  // Find all forwards reachable blocks which the inference algorithm will be
187
  // applied on.
188
  df_iterator_default_set<const BasicBlockT *> Reachable;
189
  for (auto *BB : depth_first_ext(&F, Reachable))
190
    (void)BB /* Mark all reachable blocks */;
191
 
192
  // Find all backwards reachable blocks which the inference algorithm will be
193
  // applied on.
194
  df_iterator_default_set<const BasicBlockT *> InverseReachable;
195
  for (const auto &BB : F) {
196
    // An exit block is a block without any successors.
197
    if (isExit(&BB)) {
198
      for (auto *RBB : inverse_depth_first_ext(&BB, InverseReachable))
199
        (void)RBB;
200
    }
201
  }
202
 
203
  // Keep a stable order for reachable blocks
204
  DenseMap<const BasicBlockT *, uint64_t> BlockIndex;
205
  std::vector<const BasicBlockT *> BasicBlocks;
206
  BlockIndex.reserve(Reachable.size());
207
  BasicBlocks.reserve(Reachable.size());
208
  for (const auto &BB : F) {
209
    if (Reachable.count(&BB) && InverseReachable.count(&BB)) {
210
      BlockIndex[&BB] = BasicBlocks.size();
211
      BasicBlocks.push_back(&BB);
212
    }
213
  }
214
 
215
  BlockWeights.clear();
216
  EdgeWeights.clear();
217
  bool HasSamples = false;
218
  for (const auto *BB : BasicBlocks) {
219
    auto It = SampleBlockWeights.find(BB);
220
    if (It != SampleBlockWeights.end() && It->second > 0) {
221
      HasSamples = true;
222
      BlockWeights[BB] = It->second;
223
    }
224
  }
225
  // Quit early for functions with a single block or ones w/o samples
226
  if (BasicBlocks.size() <= 1 || !HasSamples) {
227
    return;
228
  }
229
 
230
  // Create necessary objects
231
  FlowFunction Func;
232
  initFunction(Func, BasicBlocks, BlockIndex);
233
 
234
  // Create and apply the inference network model.
235
  applyFlowInference(Func);
236
 
237
  // Extract the resulting weights from the control flow
238
  // All weights are increased by one to avoid propagation errors introduced by
239
  // zero weights.
240
  for (const auto *BB : BasicBlocks) {
241
    BlockWeights[BB] = Func.Blocks[BlockIndex[BB]].Flow;
242
  }
243
  for (auto &Jump : Func.Jumps) {
244
    Edge E = std::make_pair(BasicBlocks[Jump.Source], BasicBlocks[Jump.Target]);
245
    EdgeWeights[E] = Jump.Flow;
246
  }
247
 
248
#ifndef NDEBUG
249
  // Unreachable blocks and edges should not have a weight.
250
  for (auto &I : BlockWeights) {
251
    assert(Reachable.contains(I.first));
252
    assert(InverseReachable.contains(I.first));
253
  }
254
  for (auto &I : EdgeWeights) {
255
    assert(Reachable.contains(I.first.first) &&
256
           Reachable.contains(I.first.second));
257
    assert(InverseReachable.contains(I.first.first) &&
258
           InverseReachable.contains(I.first.second));
259
  }
260
#endif
261
}
262
 
263
template <typename BT>
264
void SampleProfileInference<BT>::initFunction(
265
    FlowFunction &Func, const std::vector<const BasicBlockT *> &BasicBlocks,
266
    DenseMap<const BasicBlockT *, uint64_t> &BlockIndex) {
267
  Func.Blocks.reserve(BasicBlocks.size());
268
  // Create FlowBlocks
269
  for (const auto *BB : BasicBlocks) {
270
    FlowBlock Block;
271
    if (SampleBlockWeights.find(BB) != SampleBlockWeights.end()) {
272
      Block.HasUnknownWeight = false;
273
      Block.Weight = SampleBlockWeights[BB];
274
    } else {
275
      Block.HasUnknownWeight = true;
276
      Block.Weight = 0;
277
    }
278
    Block.Index = Func.Blocks.size();
279
    Func.Blocks.push_back(Block);
280
  }
281
  // Create FlowEdges
282
  for (const auto *BB : BasicBlocks) {
283
    for (auto *Succ : Successors[BB]) {
284
      if (!BlockIndex.count(Succ))
285
        continue;
286
      FlowJump Jump;
287
      Jump.Source = BlockIndex[BB];
288
      Jump.Target = BlockIndex[Succ];
289
      Func.Jumps.push_back(Jump);
290
    }
291
  }
292
  for (auto &Jump : Func.Jumps) {
293
    uint64_t Src = Jump.Source;
294
    uint64_t Dst = Jump.Target;
295
    Func.Blocks[Src].SuccJumps.push_back(&Jump);
296
    Func.Blocks[Dst].PredJumps.push_back(&Jump);
297
  }
298
 
299
  // Try to infer probabilities of jumps based on the content of basic block
300
  findUnlikelyJumps(BasicBlocks, Successors, Func);
301
 
302
  // Find the entry block
303
  for (size_t I = 0; I < Func.Blocks.size(); I++) {
304
    if (Func.Blocks[I].isEntry()) {
305
      Func.Entry = I;
306
      break;
307
    }
308
  }
309
  assert(Func.Entry == 0 && "incorrect index of the entry block");
310
 
311
  // Pre-process data: make sure the entry weight is at least 1
312
  auto &EntryBlock = Func.Blocks[Func.Entry];
313
  if (EntryBlock.Weight == 0 && !EntryBlock.HasUnknownWeight) {
314
    EntryBlock.Weight = 1;
315
    EntryBlock.HasUnknownWeight = false;
316
  }
317
}
318
 
319
template <typename BT>
320
inline void SampleProfileInference<BT>::findUnlikelyJumps(
321
    const std::vector<const BasicBlockT *> &BasicBlocks,
322
    BlockEdgeMap &Successors, FlowFunction &Func) {}
323
 
324
template <>
325
inline void SampleProfileInference<BasicBlock>::findUnlikelyJumps(
326
    const std::vector<const BasicBlockT *> &BasicBlocks,
327
    BlockEdgeMap &Successors, FlowFunction &Func) {
328
  for (auto &Jump : Func.Jumps) {
329
    const auto *BB = BasicBlocks[Jump.Source];
330
    const auto *Succ = BasicBlocks[Jump.Target];
331
    const Instruction *TI = BB->getTerminator();
332
    // Check if a block ends with InvokeInst and mark non-taken branch unlikely.
333
    // In that case block Succ should be a landing pad
334
    if (Successors[BB].size() == 2 && Successors[BB].back() == Succ) {
335
      if (isa<InvokeInst>(TI)) {
336
        Jump.IsUnlikely = true;
337
      }
338
    }
339
    const Instruction *SuccTI = Succ->getTerminator();
340
    // Check if the target block contains UnreachableInst and mark it unlikely
341
    if (SuccTI->getNumSuccessors() == 0) {
342
      if (isa<UnreachableInst>(SuccTI)) {
343
        Jump.IsUnlikely = true;
344
      }
345
    }
346
  }
347
}
348
 
349
template <typename BT>
350
inline bool SampleProfileInference<BT>::isExit(const BasicBlockT *BB) {
351
  return BB->succ_empty();
352
}
353
 
354
template <>
355
inline bool SampleProfileInference<BasicBlock>::isExit(const BasicBlock *BB) {
356
  return succ_empty(BB);
357
}
358
 
359
} // end namespace llvm
360
#endif // LLVM_TRANSFORMS_UTILS_SAMPLEPROFILEINFERENCE_H