123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368 |
- #pragma once
- #ifdef __GNUC__
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wunused-parameter"
- #endif
- //===- GenericCycleInfo.h - Info for Cycles in any IR ------*- C++ -*------===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- ///
- /// \file
- /// \brief Find all cycles in a control-flow graph, including irreducible loops.
- ///
- /// See docs/CycleTerminology.rst for a formal definition of cycles.
- ///
- /// Briefly:
- /// - A cycle is a generalization of a loop which can represent
- /// irreducible control flow.
- /// - Cycles identified in a program are implementation defined,
- /// depending on the DFS traversal chosen.
- /// - Cycles are well-nested, and form a forest with a parent-child
- /// relationship.
- /// - In any choice of DFS, every natural loop L is represented by a
- /// unique cycle C which is a superset of L.
- /// - In the absence of irreducible control flow, the cycles are
- /// exactly the natural loops in the program.
- ///
- //===----------------------------------------------------------------------===//
- #ifndef LLVM_ADT_GENERICCYCLEINFO_H
- #define LLVM_ADT_GENERICCYCLEINFO_H
- #include "llvm/ADT/ArrayRef.h"
- #include "llvm/ADT/DenseMap.h"
- #include "llvm/ADT/GenericSSAContext.h"
- #include "llvm/ADT/GraphTraits.h"
- #include "llvm/ADT/SmallVector.h"
- #include "llvm/ADT/iterator.h"
- #include "llvm/Support/Debug.h"
- #include "llvm/Support/Printable.h"
- #include "llvm/Support/raw_ostream.h"
- #include <vector>
- namespace llvm {
- template <typename ContextT> class GenericCycleInfo;
- template <typename ContextT> class GenericCycleInfoCompute;
- /// A possibly irreducible generalization of a \ref Loop.
- template <typename ContextT> class GenericCycle {
- public:
- using BlockT = typename ContextT::BlockT;
- using FunctionT = typename ContextT::FunctionT;
- template <typename> friend class GenericCycleInfo;
- template <typename> friend class GenericCycleInfoCompute;
- private:
- /// The parent cycle. Is null for the root "cycle". Top-level cycles point
- /// at the root.
- GenericCycle *ParentCycle = nullptr;
- /// The entry block(s) of the cycle. The header is the only entry if
- /// this is a loop. Is empty for the root "cycle", to avoid
- /// unnecessary memory use.
- SmallVector<BlockT *, 1> Entries;
- /// Child cycles, if any.
- std::vector<std::unique_ptr<GenericCycle>> Children;
- /// Basic blocks that are contained in the cycle, including entry blocks,
- /// and including blocks that are part of a child cycle.
- std::vector<BlockT *> Blocks;
- /// Depth of the cycle in the tree. The root "cycle" is at depth 0.
- ///
- /// \note Depths are not necessarily contiguous. However, child loops always
- /// have strictly greater depth than their parents, and sibling loops
- /// always have the same depth.
- unsigned Depth = 0;
- void clear() {
- Entries.clear();
- Children.clear();
- Blocks.clear();
- Depth = 0;
- ParentCycle = nullptr;
- }
- void appendEntry(BlockT *Block) { Entries.push_back(Block); }
- void appendBlock(BlockT *Block) { Blocks.push_back(Block); }
- GenericCycle(const GenericCycle &) = delete;
- GenericCycle &operator=(const GenericCycle &) = delete;
- GenericCycle(GenericCycle &&Rhs) = delete;
- GenericCycle &operator=(GenericCycle &&Rhs) = delete;
- public:
- GenericCycle() = default;
- /// \brief Whether the cycle is a natural loop.
- bool isReducible() const { return Entries.size() == 1; }
- BlockT *getHeader() const { return Entries[0]; }
- const SmallVectorImpl<BlockT *> & getEntries() const {
- return Entries;
- }
- /// \brief Return whether \p Block is an entry block of the cycle.
- bool isEntry(const BlockT *Block) const {
- return is_contained(Entries, Block);
- }
- /// \brief Return whether \p Block is contained in the cycle.
- bool contains(const BlockT *Block) const {
- return is_contained(Blocks, Block);
- }
- /// \brief Returns true iff this cycle contains \p C.
- ///
- /// Note: Non-strict containment check, i.e. returns true if C is the
- /// same cycle.
- bool contains(const GenericCycle *C) const;
- const GenericCycle *getParentCycle() const { return ParentCycle; }
- GenericCycle *getParentCycle() { return ParentCycle; }
- unsigned getDepth() const { return Depth; }
- /// Return all of the successor blocks of this cycle.
- ///
- /// These are the blocks _outside of the current cycle_ which are
- /// branched to.
- void getExitBlocks(SmallVectorImpl<BlockT *> &TmpStorage) const;
- /// Return the preheader block for this cycle. Pre-header is well-defined for
- /// reducible cycle in docs/LoopTerminology.rst as: the only one entering
- /// block and its only edge is to the entry block. Return null for irreducible
- /// cycles.
- BlockT *getCyclePreheader() const;
- /// If the cycle has exactly one entry with exactly one predecessor, return
- /// it, otherwise return nullptr.
- BlockT *getCyclePredecessor() const;
- /// Iteration over child cycles.
- //@{
- using const_child_iterator_base =
- typename std::vector<std::unique_ptr<GenericCycle>>::const_iterator;
- struct const_child_iterator
- : iterator_adaptor_base<const_child_iterator, const_child_iterator_base> {
- using Base =
- iterator_adaptor_base<const_child_iterator, const_child_iterator_base>;
- const_child_iterator() = default;
- explicit const_child_iterator(const_child_iterator_base I) : Base(I) {}
- const const_child_iterator_base &wrapped() { return Base::wrapped(); }
- GenericCycle *operator*() const { return Base::I->get(); }
- };
- const_child_iterator child_begin() const {
- return const_child_iterator{Children.begin()};
- }
- const_child_iterator child_end() const {
- return const_child_iterator{Children.end()};
- }
- size_t getNumChildren() const { return Children.size(); }
- iterator_range<const_child_iterator> children() const {
- return llvm::make_range(const_child_iterator{Children.begin()},
- const_child_iterator{Children.end()});
- }
- //@}
- /// Iteration over blocks in the cycle (including entry blocks).
- //@{
- using const_block_iterator = typename std::vector<BlockT *>::const_iterator;
- const_block_iterator block_begin() const {
- return const_block_iterator{Blocks.begin()};
- }
- const_block_iterator block_end() const {
- return const_block_iterator{Blocks.end()};
- }
- size_t getNumBlocks() const { return Blocks.size(); }
- iterator_range<const_block_iterator> blocks() const {
- return llvm::make_range(block_begin(), block_end());
- }
- //@}
- /// Iteration over entry blocks.
- //@{
- using const_entry_iterator =
- typename SmallVectorImpl<BlockT *>::const_iterator;
- size_t getNumEntries() const { return Entries.size(); }
- iterator_range<const_entry_iterator> entries() const {
- return llvm::make_range(Entries.begin(), Entries.end());
- }
- //@}
- Printable printEntries(const ContextT &Ctx) const {
- return Printable([this, &Ctx](raw_ostream &Out) {
- bool First = true;
- for (auto *Entry : Entries) {
- if (!First)
- Out << ' ';
- First = false;
- Out << Ctx.print(Entry);
- }
- });
- }
- Printable print(const ContextT &Ctx) const {
- return Printable([this, &Ctx](raw_ostream &Out) {
- Out << "depth=" << Depth << ": entries(" << printEntries(Ctx) << ')';
- for (auto *Block : Blocks) {
- if (isEntry(Block))
- continue;
- Out << ' ' << Ctx.print(Block);
- }
- });
- }
- };
- /// \brief Cycle information for a function.
- template <typename ContextT> class GenericCycleInfo {
- public:
- using BlockT = typename ContextT::BlockT;
- using CycleT = GenericCycle<ContextT>;
- using FunctionT = typename ContextT::FunctionT;
- template <typename> friend class GenericCycle;
- template <typename> friend class GenericCycleInfoCompute;
- private:
- ContextT Context;
- /// Map basic blocks to their inner-most containing cycle.
- DenseMap<BlockT *, CycleT *> BlockMap;
- /// Map basic blocks to their top level containing cycle.
- DenseMap<BlockT *, CycleT *> BlockMapTopLevel;
- /// Top-level cycles discovered by any DFS.
- ///
- /// Note: The implementation treats the nullptr as the parent of
- /// every top-level cycle. See \ref contains for an example.
- std::vector<std::unique_ptr<CycleT>> TopLevelCycles;
- /// Move \p Child to \p NewParent by manipulating Children vectors.
- ///
- /// Note: This is an incomplete operation that does not update the depth of
- /// the subtree.
- void moveTopLevelCycleToNewParent(CycleT *NewParent, CycleT *Child);
- public:
- GenericCycleInfo() = default;
- GenericCycleInfo(GenericCycleInfo &&) = default;
- GenericCycleInfo &operator=(GenericCycleInfo &&) = default;
- void clear();
- void compute(FunctionT &F);
- FunctionT *getFunction() const { return Context.getFunction(); }
- const ContextT &getSSAContext() const { return Context; }
- CycleT *getCycle(const BlockT *Block) const;
- unsigned getCycleDepth(const BlockT *Block) const;
- CycleT *getTopLevelParentCycle(BlockT *Block);
- /// Methods for debug and self-test.
- //@{
- #ifndef NDEBUG
- bool validateTree() const;
- #endif
- void print(raw_ostream &Out) const;
- void dump() const { print(dbgs()); }
- //@}
- /// Iteration over top-level cycles.
- //@{
- using const_toplevel_iterator_base =
- typename std::vector<std::unique_ptr<CycleT>>::const_iterator;
- struct const_toplevel_iterator
- : iterator_adaptor_base<const_toplevel_iterator,
- const_toplevel_iterator_base> {
- using Base = iterator_adaptor_base<const_toplevel_iterator,
- const_toplevel_iterator_base>;
- const_toplevel_iterator() = default;
- explicit const_toplevel_iterator(const_toplevel_iterator_base I)
- : Base(I) {}
- const const_toplevel_iterator_base &wrapped() { return Base::wrapped(); }
- CycleT *operator*() const { return Base::I->get(); }
- };
- const_toplevel_iterator toplevel_begin() const {
- return const_toplevel_iterator{TopLevelCycles.begin()};
- }
- const_toplevel_iterator toplevel_end() const {
- return const_toplevel_iterator{TopLevelCycles.end()};
- }
- iterator_range<const_toplevel_iterator> toplevel_cycles() const {
- return llvm::make_range(const_toplevel_iterator{TopLevelCycles.begin()},
- const_toplevel_iterator{TopLevelCycles.end()});
- }
- //@}
- };
- /// \brief GraphTraits for iterating over a sub-tree of the CycleT tree.
- template <typename CycleRefT, typename ChildIteratorT> struct CycleGraphTraits {
- using NodeRef = CycleRefT;
- using nodes_iterator = ChildIteratorT;
- using ChildIteratorType = nodes_iterator;
- static NodeRef getEntryNode(NodeRef Graph) { return Graph; }
- static ChildIteratorType child_begin(NodeRef Ref) {
- return Ref->child_begin();
- }
- static ChildIteratorType child_end(NodeRef Ref) { return Ref->child_end(); }
- // Not implemented:
- // static nodes_iterator nodes_begin(GraphType *G)
- // static nodes_iterator nodes_end (GraphType *G)
- // nodes_iterator/begin/end - Allow iteration over all nodes in the graph
- // typedef EdgeRef - Type of Edge token in the graph, which should
- // be cheap to copy.
- // typedef ChildEdgeIteratorType - Type used to iterate over children edges in
- // graph, dereference to a EdgeRef.
- // static ChildEdgeIteratorType child_edge_begin(NodeRef)
- // static ChildEdgeIteratorType child_edge_end(NodeRef)
- // Return iterators that point to the beginning and ending of the
- // edge list for the given callgraph node.
- //
- // static NodeRef edge_dest(EdgeRef)
- // Return the destination node of an edge.
- // static unsigned size (GraphType *G)
- // Return total number of nodes in the graph
- };
- template <typename BlockT>
- struct GraphTraits<const GenericCycle<BlockT> *>
- : CycleGraphTraits<const GenericCycle<BlockT> *,
- typename GenericCycle<BlockT>::const_child_iterator> {};
- template <typename BlockT>
- struct GraphTraits<GenericCycle<BlockT> *>
- : CycleGraphTraits<GenericCycle<BlockT> *,
- typename GenericCycle<BlockT>::const_child_iterator> {};
- } // namespace llvm
- #endif // LLVM_ADT_GENERICCYCLEINFO_H
- #ifdef __GNUC__
- #pragma GCC diagnostic pop
- #endif
|