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
//===- GenericCycleImpl.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 template implementation resides in a separate file so that it
11
/// does not get injected into every .cpp file that includes the
12
/// generic header.
13
///
14
/// DO NOT INCLUDE THIS FILE WHEN MERELY USING CYCLEINFO.
15
///
16
/// This file should only be included by files that implement a
17
/// specialization of the relevant templates. Currently these are:
18
/// - CycleAnalysis.cpp
19
/// - MachineCycleAnalysis.cpp
20
///
21
//===----------------------------------------------------------------------===//
22
 
23
#ifndef LLVM_ADT_GENERICCYCLEIMPL_H
24
#define LLVM_ADT_GENERICCYCLEIMPL_H
25
 
26
#include "llvm/ADT/DenseSet.h"
27
#include "llvm/ADT/DepthFirstIterator.h"
28
#include "llvm/ADT/GenericCycleInfo.h"
29
 
30
#define DEBUG_TYPE "generic-cycle-impl"
31
 
32
namespace llvm {
33
 
34
template <typename ContextT>
35
bool GenericCycle<ContextT>::contains(const GenericCycle *C) const {
36
  if (!C)
37
    return false;
38
 
39
  if (Depth > C->Depth)
40
    return false;
41
  while (Depth < C->Depth)
42
    C = C->ParentCycle;
43
  return this == C;
44
}
45
 
46
template <typename ContextT>
47
void GenericCycle<ContextT>::getExitBlocks(
48
    SmallVectorImpl<BlockT *> &TmpStorage) const {
49
  TmpStorage.clear();
50
 
51
  size_t NumExitBlocks = 0;
52
  for (BlockT *Block : blocks()) {
53
    llvm::append_range(TmpStorage, successors(Block));
54
 
55
    for (size_t Idx = NumExitBlocks, End = TmpStorage.size(); Idx < End;
56
         ++Idx) {
57
      BlockT *Succ = TmpStorage[Idx];
58
      if (!contains(Succ)) {
59
        auto ExitEndIt = TmpStorage.begin() + NumExitBlocks;
60
        if (std::find(TmpStorage.begin(), ExitEndIt, Succ) == ExitEndIt)
61
          TmpStorage[NumExitBlocks++] = Succ;
62
      }
63
    }
64
 
65
    TmpStorage.resize(NumExitBlocks);
66
  }
67
}
68
 
69
template <typename ContextT>
70
auto GenericCycle<ContextT>::getCyclePreheader() const -> BlockT * {
71
  BlockT *Predecessor = getCyclePredecessor();
72
  if (!Predecessor)
73
    return nullptr;
74
 
75
  assert(isReducible() && "Cycle Predecessor must be in a reducible cycle!");
76
 
77
  if (succ_size(Predecessor) != 1)
78
    return nullptr;
79
 
80
  // Make sure we are allowed to hoist instructions into the predecessor.
81
  if (!Predecessor->isLegalToHoistInto())
82
    return nullptr;
83
 
84
  return Predecessor;
85
}
86
 
87
template <typename ContextT>
88
auto GenericCycle<ContextT>::getCyclePredecessor() const -> BlockT * {
89
  if (!isReducible())
90
    return nullptr;
91
 
92
  BlockT *Out = nullptr;
93
 
94
  // Loop over the predecessors of the header node...
95
  BlockT *Header = getHeader();
96
  for (const auto Pred : predecessors(Header)) {
97
    if (!contains(Pred)) {
98
      if (Out && Out != Pred)
99
        return nullptr;
100
      Out = Pred;
101
    }
102
  }
103
 
104
  return Out;
105
}
106
 
107
/// \brief Helper class for computing cycle information.
108
template <typename ContextT> class GenericCycleInfoCompute {
109
  using BlockT = typename ContextT::BlockT;
110
  using CycleInfoT = GenericCycleInfo<ContextT>;
111
  using CycleT = typename CycleInfoT::CycleT;
112
 
113
  CycleInfoT &Info;
114
 
115
  struct DFSInfo {
116
    unsigned Start = 0; // DFS start; positive if block is found
117
    unsigned End = 0;   // DFS end
118
 
119
    DFSInfo() = default;
120
    explicit DFSInfo(unsigned Start) : Start(Start) {}
121
 
122
    /// Whether this node is an ancestor (or equal to) the node \p Other
123
    /// in the DFS tree.
124
    bool isAncestorOf(const DFSInfo &Other) const {
125
      return Start <= Other.Start && Other.End <= End;
126
    }
127
  };
128
 
129
  DenseMap<BlockT *, DFSInfo> BlockDFSInfo;
130
  SmallVector<BlockT *, 8> BlockPreorder;
131
 
132
  GenericCycleInfoCompute(const GenericCycleInfoCompute &) = delete;
133
  GenericCycleInfoCompute &operator=(const GenericCycleInfoCompute &) = delete;
134
 
135
public:
136
  GenericCycleInfoCompute(CycleInfoT &Info) : Info(Info) {}
137
 
138
  void run(BlockT *EntryBlock);
139
 
140
  static void updateDepth(CycleT *SubTree);
141
 
142
private:
143
  void dfs(BlockT *EntryBlock);
144
};
145
 
146
template <typename ContextT>
147
auto GenericCycleInfo<ContextT>::getTopLevelParentCycle(BlockT *Block)
148
    -> CycleT * {
149
  auto Cycle = BlockMapTopLevel.find(Block);
150
  if (Cycle != BlockMapTopLevel.end())
151
    return Cycle->second;
152
 
153
  auto MapIt = BlockMap.find(Block);
154
  if (MapIt == BlockMap.end())
155
    return nullptr;
156
 
157
  auto *C = MapIt->second;
158
  while (C->ParentCycle)
159
    C = C->ParentCycle;
160
  BlockMapTopLevel.try_emplace(Block, C);
161
  return C;
162
}
163
 
164
template <typename ContextT>
165
void GenericCycleInfo<ContextT>::moveTopLevelCycleToNewParent(CycleT *NewParent,
166
                                                              CycleT *Child) {
167
  assert((!Child->ParentCycle && !NewParent->ParentCycle) &&
168
         "NewParent and Child must be both top level cycle!\n");
169
  auto &CurrentContainer =
170
      Child->ParentCycle ? Child->ParentCycle->Children : TopLevelCycles;
171
  auto Pos = llvm::find_if(CurrentContainer, [=](const auto &Ptr) -> bool {
172
    return Child == Ptr.get();
173
  });
174
  assert(Pos != CurrentContainer.end());
175
  NewParent->Children.push_back(std::move(*Pos));
176
  *Pos = std::move(CurrentContainer.back());
177
  CurrentContainer.pop_back();
178
  Child->ParentCycle = NewParent;
179
 
180
  NewParent->Blocks.insert(NewParent->Blocks.end(), Child->block_begin(),
181
                           Child->block_end());
182
 
183
  for (auto &It : BlockMapTopLevel)
184
    if (It.second == Child)
185
      It.second = NewParent;
186
}
187
 
188
/// \brief Main function of the cycle info computations.
189
template <typename ContextT>
190
void GenericCycleInfoCompute<ContextT>::run(BlockT *EntryBlock) {
191
  LLVM_DEBUG(errs() << "Entry block: " << Info.Context.print(EntryBlock)
192
                    << "\n");
193
  dfs(EntryBlock);
194
 
195
  SmallVector<BlockT *, 8> Worklist;
196
 
197
  for (BlockT *HeaderCandidate : llvm::reverse(BlockPreorder)) {
198
    const DFSInfo CandidateInfo = BlockDFSInfo.lookup(HeaderCandidate);
199
 
200
    for (BlockT *Pred : predecessors(HeaderCandidate)) {
201
      const DFSInfo PredDFSInfo = BlockDFSInfo.lookup(Pred);
202
      if (CandidateInfo.isAncestorOf(PredDFSInfo))
203
        Worklist.push_back(Pred);
204
    }
205
    if (Worklist.empty()) {
206
      continue;
207
    }
208
 
209
    // Found a cycle with the candidate as its header.
210
    LLVM_DEBUG(errs() << "Found cycle for header: "
211
                      << Info.Context.print(HeaderCandidate) << "\n");
212
    std::unique_ptr<CycleT> NewCycle = std::make_unique<CycleT>();
213
    NewCycle->appendEntry(HeaderCandidate);
214
    NewCycle->appendBlock(HeaderCandidate);
215
    Info.BlockMap.try_emplace(HeaderCandidate, NewCycle.get());
216
 
217
    // Helper function to process (non-back-edge) predecessors of a discovered
218
    // block and either add them to the worklist or recognize that the given
219
    // block is an additional cycle entry.
220
    auto ProcessPredecessors = [&](BlockT *Block) {
221
      LLVM_DEBUG(errs() << "  block " << Info.Context.print(Block) << ": ");
222
 
223
      bool IsEntry = false;
224
      for (BlockT *Pred : predecessors(Block)) {
225
        const DFSInfo PredDFSInfo = BlockDFSInfo.lookup(Pred);
226
        if (CandidateInfo.isAncestorOf(PredDFSInfo)) {
227
          Worklist.push_back(Pred);
228
        } else {
229
          IsEntry = true;
230
        }
231
      }
232
      if (IsEntry) {
233
        assert(!NewCycle->isEntry(Block));
234
        LLVM_DEBUG(errs() << "append as entry\n");
235
        NewCycle->appendEntry(Block);
236
      } else {
237
        LLVM_DEBUG(errs() << "append as child\n");
238
      }
239
    };
240
 
241
    do {
242
      BlockT *Block = Worklist.pop_back_val();
243
      if (Block == HeaderCandidate)
244
        continue;
245
 
246
      // If the block has already been discovered by some cycle
247
      // (possibly by ourself), then the outermost cycle containing it
248
      // should become our child.
249
      if (auto *BlockParent = Info.getTopLevelParentCycle(Block)) {
250
        LLVM_DEBUG(errs() << "  block " << Info.Context.print(Block) << ": ");
251
 
252
        if (BlockParent != NewCycle.get()) {
253
          LLVM_DEBUG(errs()
254
                     << "discovered child cycle "
255
                     << Info.Context.print(BlockParent->getHeader()) << "\n");
256
          // Make BlockParent the child of NewCycle.
257
          Info.moveTopLevelCycleToNewParent(NewCycle.get(), BlockParent);
258
 
259
          for (auto *ChildEntry : BlockParent->entries())
260
            ProcessPredecessors(ChildEntry);
261
        } else {
262
          LLVM_DEBUG(errs()
263
                     << "known child cycle "
264
                     << Info.Context.print(BlockParent->getHeader()) << "\n");
265
        }
266
      } else {
267
        Info.BlockMap.try_emplace(Block, NewCycle.get());
268
        assert(!is_contained(NewCycle->Blocks, Block));
269
        NewCycle->Blocks.push_back(Block);
270
        ProcessPredecessors(Block);
271
        Info.BlockMapTopLevel.try_emplace(Block, NewCycle.get());
272
      }
273
    } while (!Worklist.empty());
274
 
275
    Info.TopLevelCycles.push_back(std::move(NewCycle));
276
  }
277
 
278
  // Fix top-level cycle links and compute cycle depths.
279
  for (auto *TLC : Info.toplevel_cycles()) {
280
    LLVM_DEBUG(errs() << "top-level cycle: "
281
                      << Info.Context.print(TLC->getHeader()) << "\n");
282
 
283
    TLC->ParentCycle = nullptr;
284
    updateDepth(TLC);
285
  }
286
}
287
 
288
/// \brief Recompute depth values of \p SubTree and all descendants.
289
template <typename ContextT>
290
void GenericCycleInfoCompute<ContextT>::updateDepth(CycleT *SubTree) {
291
  for (CycleT *Cycle : depth_first(SubTree))
292
    Cycle->Depth = Cycle->ParentCycle ? Cycle->ParentCycle->Depth + 1 : 1;
293
}
294
 
295
/// \brief Compute a DFS of basic blocks starting at the function entry.
296
///
297
/// Fills BlockDFSInfo with start/end counters and BlockPreorder.
298
template <typename ContextT>
299
void GenericCycleInfoCompute<ContextT>::dfs(BlockT *EntryBlock) {
300
  SmallVector<unsigned, 8> DFSTreeStack;
301
  SmallVector<BlockT *, 8> TraverseStack;
302
  unsigned Counter = 0;
303
  TraverseStack.emplace_back(EntryBlock);
304
 
305
  do {
306
    BlockT *Block = TraverseStack.back();
307
    LLVM_DEBUG(errs() << "DFS visiting block: " << Info.Context.print(Block)
308
                      << "\n");
309
    if (!BlockDFSInfo.count(Block)) {
310
      // We're visiting the block for the first time. Open its DFSInfo, add
311
      // successors to the traversal stack, and remember the traversal stack
312
      // depth at which the block was opened, so that we can correctly record
313
      // its end time.
314
      LLVM_DEBUG(errs() << "  first encountered at depth "
315
                        << TraverseStack.size() << "\n");
316
 
317
      DFSTreeStack.emplace_back(TraverseStack.size());
318
      llvm::append_range(TraverseStack, successors(Block));
319
 
320
      bool Added = BlockDFSInfo.try_emplace(Block, ++Counter).second;
321
      (void)Added;
322
      assert(Added);
323
      BlockPreorder.push_back(Block);
324
      LLVM_DEBUG(errs() << "  preorder number: " << Counter << "\n");
325
    } else {
326
      assert(!DFSTreeStack.empty());
327
      if (DFSTreeStack.back() == TraverseStack.size()) {
328
        LLVM_DEBUG(errs() << "  ended at " << Counter << "\n");
329
        BlockDFSInfo.find(Block)->second.End = Counter;
330
        DFSTreeStack.pop_back();
331
      } else {
332
        LLVM_DEBUG(errs() << "  already done\n");
333
      }
334
      TraverseStack.pop_back();
335
    }
336
  } while (!TraverseStack.empty());
337
  assert(DFSTreeStack.empty());
338
 
339
  LLVM_DEBUG(
340
    errs() << "Preorder:\n";
341
    for (int i = 0, e = BlockPreorder.size(); i != e; ++i) {
342
      errs() << "  " << Info.Context.print(BlockPreorder[i]) << ": " << i << "\n";
343
    }
344
  );
345
}
346
 
347
/// \brief Reset the object to its initial state.
348
template <typename ContextT> void GenericCycleInfo<ContextT>::clear() {
349
  TopLevelCycles.clear();
350
  BlockMap.clear();
351
  BlockMapTopLevel.clear();
352
}
353
 
354
/// \brief Compute the cycle info for a function.
355
template <typename ContextT>
356
void GenericCycleInfo<ContextT>::compute(FunctionT &F) {
357
  GenericCycleInfoCompute<ContextT> Compute(*this);
358
  Context.setFunction(F);
359
 
360
  LLVM_DEBUG(errs() << "Computing cycles for function: " << F.getName()
361
                    << "\n");
362
  Compute.run(ContextT::getEntryBlock(F));
363
 
364
  assert(validateTree());
365
}
366
 
367
/// \brief Find the innermost cycle containing a given block.
368
///
369
/// \returns the innermost cycle containing \p Block or nullptr if
370
///          it is not contained in any cycle.
371
template <typename ContextT>
372
auto GenericCycleInfo<ContextT>::getCycle(const BlockT *Block) const
373
    -> CycleT * {
374
  auto MapIt = BlockMap.find(Block);
375
  if (MapIt != BlockMap.end())
376
    return MapIt->second;
377
  return nullptr;
378
}
379
 
380
/// \brief get the depth for the cycle which containing a given block.
381
///
382
/// \returns the depth for the innermost cycle containing \p Block or 0 if it is
383
///          not contained in any cycle.
384
template <typename ContextT>
385
unsigned GenericCycleInfo<ContextT>::getCycleDepth(const BlockT *Block) const {
386
  CycleT *Cycle = getCycle(Block);
387
  if (!Cycle)
388
    return 0;
389
  return Cycle->getDepth();
390
}
391
 
392
#ifndef NDEBUG
393
/// \brief Validate the internal consistency of the cycle tree.
394
///
395
/// Note that this does \em not check that cycles are really cycles in the CFG,
396
/// or that the right set of cycles in the CFG were found.
397
template <typename ContextT>
398
bool GenericCycleInfo<ContextT>::validateTree() const {
399
  DenseSet<BlockT *> Blocks;
400
  DenseSet<BlockT *> Entries;
401
 
402
  auto reportError = [](const char *File, int Line, const char *Cond) {
403
    errs() << File << ':' << Line
404
           << ": GenericCycleInfo::validateTree: " << Cond << '\n';
405
  };
406
#define check(cond)                                                            \
407
  do {                                                                         \
408
    if (!(cond)) {                                                             \
409
      reportError(__FILE__, __LINE__, #cond);                                  \
410
      return false;                                                            \
411
    }                                                                          \
412
  } while (false)
413
 
414
  for (const auto *TLC : toplevel_cycles()) {
415
    for (const CycleT *Cycle : depth_first(TLC)) {
416
      if (Cycle->ParentCycle)
417
        check(is_contained(Cycle->ParentCycle->children(), Cycle));
418
 
419
      for (BlockT *Block : Cycle->Blocks) {
420
        auto MapIt = BlockMap.find(Block);
421
        check(MapIt != BlockMap.end());
422
        check(Cycle->contains(MapIt->second));
423
        check(Blocks.insert(Block).second); // duplicates in block list?
424
      }
425
      Blocks.clear();
426
 
427
      check(!Cycle->Entries.empty());
428
      for (BlockT *Entry : Cycle->Entries) {
429
        check(Entries.insert(Entry).second); // duplicate entry?
430
        check(is_contained(Cycle->Blocks, Entry));
431
      }
432
      Entries.clear();
433
 
434
      unsigned ChildDepth = 0;
435
      for (const CycleT *Child : Cycle->children()) {
436
        check(Child->Depth > Cycle->Depth);
437
        if (!ChildDepth) {
438
          ChildDepth = Child->Depth;
439
        } else {
440
          check(ChildDepth == Child->Depth);
441
        }
442
      }
443
    }
444
  }
445
 
446
  for (const auto &Entry : BlockMap) {
447
    BlockT *Block = Entry.first;
448
    for (const CycleT *Cycle = Entry.second; Cycle;
449
         Cycle = Cycle->ParentCycle) {
450
      check(is_contained(Cycle->Blocks, Block));
451
    }
452
  }
453
 
454
#undef check
455
 
456
  return true;
457
}
458
#endif
459
 
460
/// \brief Print the cycle info.
461
template <typename ContextT>
462
void GenericCycleInfo<ContextT>::print(raw_ostream &Out) const {
463
  for (const auto *TLC : toplevel_cycles()) {
464
    for (const CycleT *Cycle : depth_first(TLC)) {
465
      for (unsigned I = 0; I < Cycle->Depth; ++I)
466
        Out << "    ";
467
 
468
      Out << Cycle->print(Context) << '\n';
469
    }
470
  }
471
}
472
 
473
} // namespace llvm
474
 
475
#undef DEBUG_TYPE
476
 
477
#endif // LLVM_ADT_GENERICCYCLEIMPL_H