LLVM  15.0.0git
GenericCycleImpl.h
Go to the documentation of this file.
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"
29 
30 #define DEBUG_TYPE "generic-cycle-impl"
31 
32 namespace llvm {
33 
34 template <typename ContextT>
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>
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>
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>
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;
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 
133  GenericCycleInfoCompute &operator=(const GenericCycleInfoCompute &) = delete;
134 
135 public:
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>
148  const BlockT *Block) const -> CycleT * {
149  auto MapIt = BlockMap.find(Block);
150  if (MapIt == BlockMap.end())
151  return nullptr;
152 
153  auto *C = MapIt->second;
154  while (C->ParentCycle)
155  C = C->ParentCycle;
156  return C;
157 }
158 
159 template <typename ContextT>
161  CycleT *Child) {
162  auto &CurrentContainer =
163  Child->ParentCycle ? Child->ParentCycle->Children : TopLevelCycles;
164  auto Pos = llvm::find_if(CurrentContainer, [=](const auto &Ptr) -> bool {
165  return Child == Ptr.get();
166  });
167  assert(Pos != CurrentContainer.end());
168  NewParent->Children.push_back(std::move(*Pos));
169  *Pos = std::move(CurrentContainer.back());
170  CurrentContainer.pop_back();
171  Child->ParentCycle = NewParent;
172 }
173 
174 /// \brief Main function of the cycle info computations.
175 template <typename ContextT>
176 void GenericCycleInfoCompute<ContextT>::run(BlockT *EntryBlock) {
177  LLVM_DEBUG(errs() << "Entry block: " << Info.Context.print(EntryBlock)
178  << "\n");
179  dfs(EntryBlock);
180 
181  SmallVector<BlockT *, 8> Worklist;
182 
183  for (BlockT *HeaderCandidate : llvm::reverse(BlockPreorder)) {
184  const DFSInfo CandidateInfo = BlockDFSInfo.lookup(HeaderCandidate);
185 
186  for (BlockT *Pred : predecessors(HeaderCandidate)) {
187  const DFSInfo PredDFSInfo = BlockDFSInfo.lookup(Pred);
188  if (CandidateInfo.isAncestorOf(PredDFSInfo))
189  Worklist.push_back(Pred);
190  }
191  if (Worklist.empty()) {
192  continue;
193  }
194 
195  // Found a cycle with the candidate as its header.
196  LLVM_DEBUG(errs() << "Found cycle for header: "
197  << Info.Context.print(HeaderCandidate) << "\n");
198  std::unique_ptr<CycleT> NewCycle = std::make_unique<CycleT>();
199  NewCycle->appendEntry(HeaderCandidate);
200  NewCycle->appendBlock(HeaderCandidate);
201  Info.BlockMap.try_emplace(HeaderCandidate, NewCycle.get());
202 
203  // Helper function to process (non-back-edge) predecessors of a discovered
204  // block and either add them to the worklist or recognize that the given
205  // block is an additional cycle entry.
206  auto ProcessPredecessors = [&](BlockT *Block) {
207  LLVM_DEBUG(errs() << " block " << Info.Context.print(Block) << ": ");
208 
209  bool IsEntry = false;
210  for (BlockT *Pred : predecessors(Block)) {
211  const DFSInfo PredDFSInfo = BlockDFSInfo.lookup(Pred);
212  if (CandidateInfo.isAncestorOf(PredDFSInfo)) {
213  Worklist.push_back(Pred);
214  } else {
215  IsEntry = true;
216  }
217  }
218  if (IsEntry) {
219  assert(!NewCycle->isEntry(Block));
220  LLVM_DEBUG(errs() << "append as entry\n");
221  NewCycle->appendEntry(Block);
222  } else {
223  LLVM_DEBUG(errs() << "append as child\n");
224  }
225  };
226 
227  do {
228  BlockT *Block = Worklist.pop_back_val();
229  if (Block == HeaderCandidate)
230  continue;
231 
232  // If the block has already been discovered by some cycle
233  // (possibly by ourself), then the outermost cycle containing it
234  // should become our child.
235  if (auto *BlockParent = Info.getTopLevelParentCycle(Block)) {
236  LLVM_DEBUG(errs() << " block " << Info.Context.print(Block) << ": ");
237 
238  if (BlockParent != NewCycle.get()) {
239  LLVM_DEBUG(errs()
240  << "discovered child cycle "
241  << Info.Context.print(BlockParent->getHeader()) << "\n");
242  // Make BlockParent the child of NewCycle.
243  Info.moveToNewParent(NewCycle.get(), BlockParent);
244  NewCycle->Blocks.insert(NewCycle->Blocks.end(),
245  BlockParent->block_begin(),
246  BlockParent->block_end());
247 
248  for (auto *ChildEntry : BlockParent->entries())
249  ProcessPredecessors(ChildEntry);
250  } else {
251  LLVM_DEBUG(errs()
252  << "known child cycle "
253  << Info.Context.print(BlockParent->getHeader()) << "\n");
254  }
255  } else {
256  Info.BlockMap.try_emplace(Block, NewCycle.get());
257  assert(!is_contained(NewCycle->Blocks, Block));
258  NewCycle->Blocks.push_back(Block);
259  ProcessPredecessors(Block);
260  }
261  } while (!Worklist.empty());
262 
263  Info.TopLevelCycles.push_back(std::move(NewCycle));
264  }
265 
266  // Fix top-level cycle links and compute cycle depths.
267  for (auto *TLC : Info.toplevel_cycles()) {
268  LLVM_DEBUG(errs() << "top-level cycle: "
269  << Info.Context.print(TLC->getHeader()) << "\n");
270 
271  TLC->ParentCycle = nullptr;
272  updateDepth(TLC);
273  }
274 }
275 
276 /// \brief Recompute depth values of \p SubTree and all descendants.
277 template <typename ContextT>
279  for (CycleT *Cycle : depth_first(SubTree))
280  Cycle->Depth = Cycle->ParentCycle ? Cycle->ParentCycle->Depth + 1 : 1;
281 }
282 
283 /// \brief Compute a DFS of basic blocks starting at the function entry.
284 ///
285 /// Fills BlockDFSInfo with start/end counters and BlockPreorder.
286 template <typename ContextT>
287 void GenericCycleInfoCompute<ContextT>::dfs(BlockT *EntryBlock) {
288  SmallVector<unsigned, 8> DFSTreeStack;
289  SmallVector<BlockT *, 8> TraverseStack;
290  unsigned Counter = 0;
291  TraverseStack.emplace_back(EntryBlock);
292 
293  do {
294  BlockT *Block = TraverseStack.back();
295  LLVM_DEBUG(errs() << "DFS visiting block: " << Info.Context.print(Block)
296  << "\n");
297  if (!BlockDFSInfo.count(Block)) {
298  // We're visiting the block for the first time. Open its DFSInfo, add
299  // successors to the traversal stack, and remember the traversal stack
300  // depth at which the block was opened, so that we can correctly record
301  // its end time.
302  LLVM_DEBUG(errs() << " first encountered at depth "
303  << TraverseStack.size() << "\n");
304 
305  DFSTreeStack.emplace_back(TraverseStack.size());
306  llvm::append_range(TraverseStack, successors(Block));
307 
308  bool Added = BlockDFSInfo.try_emplace(Block, ++Counter).second;
309  (void)Added;
310  assert(Added);
311  BlockPreorder.push_back(Block);
312  LLVM_DEBUG(errs() << " preorder number: " << Counter << "\n");
313  } else {
314  assert(!DFSTreeStack.empty());
315  if (DFSTreeStack.back() == TraverseStack.size()) {
316  LLVM_DEBUG(errs() << " ended at " << Counter << "\n");
317  BlockDFSInfo.find(Block)->second.End = Counter;
318  DFSTreeStack.pop_back();
319  } else {
320  LLVM_DEBUG(errs() << " already done\n");
321  }
322  TraverseStack.pop_back();
323  }
324  } while (!TraverseStack.empty());
325  assert(DFSTreeStack.empty());
326 
327  LLVM_DEBUG(
328  errs() << "Preorder:\n";
329  for (int i = 0, e = BlockPreorder.size(); i != e; ++i) {
330  errs() << " " << Info.Context.print(BlockPreorder[i]) << ": " << i << "\n";
331  }
332  );
333 }
334 
335 /// \brief Reset the object to its initial state.
336 template <typename ContextT> void GenericCycleInfo<ContextT>::clear() {
337  TopLevelCycles.clear();
338  BlockMap.clear();
339 }
340 
341 /// \brief Compute the cycle info for a function.
342 template <typename ContextT>
344  GenericCycleInfoCompute<ContextT> Compute(*this);
345  Context.setFunction(F);
346 
347  LLVM_DEBUG(errs() << "Computing cycles for function: " << F.getName()
348  << "\n");
349  Compute.run(ContextT::getEntryBlock(F));
350 
351  assert(validateTree());
352 }
353 
354 /// \brief Find the innermost cycle containing a given block.
355 ///
356 /// \returns the innermost cycle containing \p Block or nullptr if
357 /// it is not contained in any cycle.
358 template <typename ContextT>
360  -> CycleT * {
361  auto MapIt = BlockMap.find(Block);
362  if (MapIt != BlockMap.end())
363  return MapIt->second;
364  return nullptr;
365 }
366 
367 /// \brief get the depth for the cycle which containing a given block.
368 ///
369 /// \returns the depth for the innermost cycle containing \p Block or 0 if it is
370 /// not contained in any cycle.
371 template <typename ContextT>
372 unsigned GenericCycleInfo<ContextT>::getCycleDepth(const BlockT *Block) const {
373  CycleT *Cycle = getCycle(Block);
374  if (!Cycle)
375  return 0;
376  return Cycle->getDepth();
377 }
378 
379 #ifndef NDEBUG
380 /// \brief Validate the internal consistency of the cycle tree.
381 ///
382 /// Note that this does \em not check that cycles are really cycles in the CFG,
383 /// or that the right set of cycles in the CFG were found.
384 template <typename ContextT>
386  DenseSet<BlockT *> Blocks;
387  DenseSet<BlockT *> Entries;
388 
389  auto reportError = [](const char *File, int Line, const char *Cond) {
390  errs() << File << ':' << Line
391  << ": GenericCycleInfo::validateTree: " << Cond << '\n';
392  };
393 #define check(cond) \
394  do { \
395  if (!(cond)) { \
396  reportError(__FILE__, __LINE__, #cond); \
397  return false; \
398  } \
399  } while (false)
400 
401  for (const auto *TLC : toplevel_cycles()) {
402  for (const CycleT *Cycle : depth_first(TLC)) {
403  if (Cycle->ParentCycle)
404  check(is_contained(Cycle->ParentCycle->children(), Cycle));
405 
406  for (BlockT *Block : Cycle->Blocks) {
407  auto MapIt = BlockMap.find(Block);
408  check(MapIt != BlockMap.end());
409  check(Cycle->contains(MapIt->second));
410  check(Blocks.insert(Block).second); // duplicates in block list?
411  }
412  Blocks.clear();
413 
414  check(!Cycle->Entries.empty());
415  for (BlockT *Entry : Cycle->Entries) {
416  check(Entries.insert(Entry).second); // duplicate entry?
417  check(is_contained(Cycle->Blocks, Entry));
418  }
419  Entries.clear();
420 
421  unsigned ChildDepth = 0;
422  for (const CycleT *Child : Cycle->children()) {
423  check(Child->Depth > Cycle->Depth);
424  if (!ChildDepth) {
425  ChildDepth = Child->Depth;
426  } else {
427  check(ChildDepth == Child->Depth);
428  }
429  }
430  }
431  }
432 
433  for (const auto &Entry : BlockMap) {
434  BlockT *Block = Entry.first;
435  for (const CycleT *Cycle = Entry.second; Cycle;
436  Cycle = Cycle->ParentCycle) {
437  check(is_contained(Cycle->Blocks, Block));
438  }
439  }
440 
441 #undef check
442 
443  return true;
444 }
445 #endif
446 
447 /// \brief Print the cycle info.
448 template <typename ContextT>
450  for (const auto *TLC : toplevel_cycles()) {
451  for (const CycleT *Cycle : depth_first(TLC)) {
452  for (unsigned I = 0; I < Cycle->Depth; ++I)
453  Out << " ";
454 
455  Out << Cycle->print(Context) << '\n';
456  }
457  }
458 }
459 
460 } // namespace llvm
461 
462 #undef DEBUG_TYPE
463 
464 #endif // LLVM_ADT_GENERICCYCLEIMPL_H
i
i
Definition: README.txt:29
llvm::GenericCycleInfo::getTopLevelParentCycle
CycleT * getTopLevelParentCycle(const BlockT *Block) const
Definition: GenericCycleImpl.h:147
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:17
llvm::GenericCycleInfo< SSAContext >::FunctionT
typename SSAContext ::FunctionT FunctionT
Definition: GenericCycleInfo.h:228
contains
return AArch64::GPR64RegClass contains(Reg)
llvm::SmallVector< BlockT *, 8 >
llvm::GenericCycleInfoCompute::GenericCycleInfoCompute
GenericCycleInfoCompute(CycleInfoT &Info)
Definition: GenericCycleImpl.h:136
llvm::GenericCycleInfo::getCycleDepth
unsigned getCycleDepth(const BlockT *Block) const
get the depth for the cycle which containing a given block.
Definition: GenericCycleImpl.h:372
llvm::Depth
@ Depth
Definition: SIMachineScheduler.h:36
llvm::reverse
auto reverse(ContainerTy &&C, std::enable_if_t< has_rbegin< ContainerTy >::value > *=nullptr)
Definition: STLExtras.h:380
llvm::successors
auto successors(MachineBasicBlock *BB)
Definition: MachineSSAContext.h:29
llvm::GenericCycleInfo::validateTree
bool validateTree() const
Methods for debug and self-test.
Definition: GenericCycleImpl.h:385
llvm::errs
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
Definition: raw_ostream.cpp:893
llvm::SmallVectorImpl::pop_back_val
LLVM_NODISCARD T pop_back_val()
Definition: SmallVector.h:654
llvm::detail::DenseSetImpl< ValueT, DenseMap< ValueT, detail::DenseSetEmpty, DenseMapInfo< ValueT >, detail::DenseSetPair< ValueT > >, DenseMapInfo< ValueT > >::insert
std::pair< iterator, bool > insert(const ValueT &V)
Definition: DenseSet.h:206
LLVM_DEBUG
#define LLVM_DEBUG(X)
Definition: Debug.h:101
DepthFirstIterator.h
F
#define F(x, y, z)
Definition: MD5.cpp:55
Context
LLVMContext & Context
Definition: NVVMIntrRange.cpp:66
llvm::GenericCycle::getCyclePreheader
BlockT * getCyclePreheader() const
Return the preheader block for this cycle.
Definition: GenericCycleImpl.h:70
llvm::GenericCycleInfo::moveToNewParent
void moveToNewParent(CycleT *NewParent, CycleT *Child)
Move Child to NewParent by manipulating Children vectors.
Definition: GenericCycleImpl.h:160
llvm::GenericCycleInfo::CycleT
GenericCycle< ContextT > CycleT
Definition: GenericCycleInfo.h:227
C
(vector float) vec_cmpeq(*A, *B) C
Definition: README_ALTIVEC.txt:86
reportError
static Error reportError(StringRef Message)
Definition: BitcodeAnalyzer.cpp:19
DenseSet.h
check
#define check(cond)
llvm::succ_size
unsigned succ_size(MachineBasicBlock *BB)
Definition: MachineSSAContext.h:31
llvm::GenericCycle
A possibly irreducible generalization of a Loop.
Definition: GenericCycleInfo.h:48
llvm::predecessors
auto predecessors(MachineBasicBlock *BB)
Definition: MachineSSAContext.h:30
llvm::raw_ostream
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:54
llvm::SmallVectorImpl::resize
void resize(size_type N)
Definition: SmallVector.h:619
Info
Analysis containing CSE Info
Definition: CSEInfo.cpp:27
llvm::GenericCycleInfoCompute
Helper class for computing cycle information.
Definition: GenericCycleImpl.h:108
llvm::GenericCycleInfo::compute
void compute(FunctionT &F)
Compute the cycle info for a function.
Definition: GenericCycleImpl.h:343
llvm::GenericCycle::getDepth
unsigned getDepth() const
Definition: GenericCycleInfo.h:123
llvm::DenseSet
Implements a dense probed hash-table based set.
Definition: DenseSet.h:268
llvm::GenericCycleInfoCompute::updateDepth
static void updateDepth(CycleT *SubTree)
Recompute depth values of SubTree and all descendants.
Definition: GenericCycleImpl.h:278
llvm::GenericCycleInfo::getCycle
CycleT * getCycle(const BlockT *Block) const
Find the innermost cycle containing a given block.
Definition: GenericCycleImpl.h:359
GenericCycleInfo.h
Find all cycles in a control-flow graph, including irreducible loops.
llvm::find
auto find(R &&Range, const T &Val)
Provide wrappers to std::find which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1637
const
aarch64 promote const
Definition: AArch64PromoteConstant.cpp:232
move
compiles ldr LCPI1_0 ldr ldr mov lsr tst moveq r1 ldr LCPI1_1 and r0 bx lr It would be better to do something like to fold the shift into the conditional move
Definition: README.txt:546
llvm::numbers::e
constexpr double e
Definition: MathExtras.h:57
llvm::DenseMap< BlockT *, DFSInfo >
I
#define I(x, y, z)
Definition: MD5.cpp:58
llvm::is_contained
bool is_contained(R &&Range, const E &Element)
Wrapper function around std::find to detect if an element exists in a container.
Definition: STLExtras.h:1682
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
llvm::detail::DenseSetImpl< ValueT, DenseMap< ValueT, detail::DenseSetEmpty, DenseMapInfo< ValueT >, detail::DenseSetPair< ValueT > >, DenseMapInfo< ValueT > >::clear
void clear()
Definition: DenseSet.h:92
llvm::GenericCycleInfo
Cycle information for a function.
Definition: GenericCycleInfo.h:44
Cond
SmallVector< MachineOperand, 4 > Cond
Definition: BasicBlockSections.cpp:137
llvm::append_range
void append_range(Container &C, Range &&R)
Wrapper function to append a range to a container.
Definition: STLExtras.h:1823
llvm::GenericCycle::getExitBlocks
void getExitBlocks(SmallVectorImpl< BlockT * > &TmpStorage) const
Return all of the successor blocks of this cycle.
Definition: GenericCycleImpl.h:47
llvm::find_if
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1644
llvm::depth_first
iterator_range< df_iterator< T > > depth_first(const T &G)
Definition: DepthFirstIterator.h:230
llvm::GenericCycleInfo::print
void print(raw_ostream &Out) const
Print the cycle info.
Definition: GenericCycleImpl.h:449
llvm::SmallVectorImpl::clear
void clear()
Definition: SmallVector.h:591
llvm::GenericCycle::getCyclePredecessor
BlockT * getCyclePredecessor() const
If the cycle has exactly one entry with exactly one predecessor, return it, otherwise return nullptr.
Definition: GenericCycleImpl.h:88
llvm::GenericCycle::print
Printable print(const ContextT &Ctx) const
Definition: GenericCycleInfo.h:209
llvm::GenericCycleInfo::clear
void clear()
Reset the object to its initial state.
Definition: GenericCycleImpl.h:336
llvm::GenericCycle::children
iterator_range< const_child_iterator > children() const
Definition: GenericCycleInfo.h:164
llvm::GenericCycleInfo< SSAContext >::BlockT
typename SSAContext ::BlockT BlockT
Definition: GenericCycleInfo.h:226
llvm::GenericCycle::BlockT
typename ContextT::BlockT BlockT
Definition: GenericCycleInfo.h:50
llvm::SmallVectorImpl< BlockT * >
llvm::GenericCycleInfoCompute::run
void run(BlockT *EntryBlock)
Main function of the cycle info computations.
Definition: GenericCycleImpl.h:176
llvm::GenericCycle::contains
bool contains(const BlockT *Block) const
Return whether Block is contained in the cycle.
Definition: GenericCycleInfo.h:111
Other
Optional< std::vector< StOtherPiece > > Other
Definition: ELFYAML.cpp:1238
llvm::SmallVectorImpl::emplace_back
reference emplace_back(ArgTypes &&... Args)
Definition: SmallVector.h:927