Compiler projects using llvm
//===- GIMatchDag.h - Represent a DAG to be matched -----------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_UTILS_TABLEGEN_GIMATCHDAG_H
#define LLVM_UTILS_TABLEGEN_GIMATCHDAG_H

#include "GIMatchDagEdge.h"
#include "GIMatchDagInstr.h"
#include "GIMatchDagOperands.h"
#include "GIMatchDagPredicate.h"
#include "GIMatchDagPredicateDependencyEdge.h"

namespace llvm {

/// This class manages lifetimes for data associated with the GIMatchDag object.
class GIMatchDagContext {
  GIMatchDagOperandListContext OperandListCtx;

public:
  const GIMatchDagOperandList &makeEmptyOperandList() {
    return OperandListCtx.makeEmptyOperandList();
  }

  const GIMatchDagOperandList &makeOperandList(const CodeGenInstruction &I) {
    return OperandListCtx.makeOperandList(I);
  }

  const GIMatchDagOperandList &makeMIPredicateOperandList() {
    return OperandListCtx.makeMIPredicateOperandList();
  }


  const GIMatchDagOperandList &makeTwoMOPredicateOperandList() {
    return OperandListCtx.makeTwoMOPredicateOperandList();
  }

  void print(raw_ostream &OS) const {
    OperandListCtx.print(OS);
  }

#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
  LLVM_DUMP_METHOD void dump() const { print(errs()); }
#endif // if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
};

class GIMatchDag {
public:
  using InstrNodesVec = std::vector<std::unique_ptr<GIMatchDagInstr>>;
  using instr_node_iterator = raw_pointer_iterator<InstrNodesVec::iterator>;
  using const_instr_node_iterator =
      raw_pointer_iterator<InstrNodesVec::const_iterator>;

  using EdgesVec = std::vector<std::unique_ptr<GIMatchDagEdge>>;
  using edge_iterator = raw_pointer_iterator<EdgesVec::iterator>;
  using const_edge_iterator = raw_pointer_iterator<EdgesVec::const_iterator>;

  using PredicateNodesVec = std::vector<std::unique_ptr<GIMatchDagPredicate>>;
  using predicate_iterator = raw_pointer_iterator<PredicateNodesVec::iterator>;
  using const_predicate_iterator =
      raw_pointer_iterator<PredicateNodesVec::const_iterator>;

  using PredicateDependencyEdgesVec =
      std::vector<std::unique_ptr<GIMatchDagPredicateDependencyEdge>>;
  using predicate_edge_iterator =
      raw_pointer_iterator<PredicateDependencyEdgesVec::iterator>;
  using const_predicate_edge_iterator =
      raw_pointer_iterator<PredicateDependencyEdgesVec::const_iterator>;

protected:
  GIMatchDagContext &Ctx;
  InstrNodesVec InstrNodes;
  PredicateNodesVec PredicateNodes;
  EdgesVec Edges;
  PredicateDependencyEdgesVec PredicateDependencies;
  std::vector<GIMatchDagInstr *> MatchRoots;
  // FIXME: This is a temporary measure while we still accept arbitrary code
  //        blocks to fix up the matcher while it's being developed.
  bool HasPostMatchPredicate = false;

public:
  GIMatchDag(GIMatchDagContext &Ctx) : Ctx(Ctx) {}
  GIMatchDag(const GIMatchDag &) = delete;

  GIMatchDagContext &getContext() const { return Ctx; }
  edge_iterator edges_begin() {
    return raw_pointer_iterator<EdgesVec::iterator>(Edges.begin());
  }
  edge_iterator edges_end() {
    return raw_pointer_iterator<EdgesVec::iterator>(Edges.end());
  }
  const_edge_iterator edges_begin() const {
    return raw_pointer_iterator<EdgesVec::const_iterator>(Edges.begin());
  }
  const_edge_iterator edges_end() const {
    return raw_pointer_iterator<EdgesVec::const_iterator>(Edges.end());
  }
  iterator_range<edge_iterator> edges() {
    return make_range(edges_begin(), edges_end());
  }
  iterator_range<const_edge_iterator> edges() const {
    return make_range(edges_begin(), edges_end());
  }
  iterator_range<std::vector<GIMatchDagInstr *>::iterator> roots() {
    return make_range(MatchRoots.begin(), MatchRoots.end());
  }
  iterator_range<std::vector<GIMatchDagInstr *>::const_iterator> roots() const {
    return make_range(MatchRoots.begin(), MatchRoots.end());
  }

  instr_node_iterator instr_nodes_begin() {
    return raw_pointer_iterator<InstrNodesVec::iterator>(InstrNodes.begin());
  }
  instr_node_iterator instr_nodes_end() {
    return raw_pointer_iterator<InstrNodesVec::iterator>(InstrNodes.end());
  }
  const_instr_node_iterator instr_nodes_begin() const {
    return raw_pointer_iterator<InstrNodesVec::const_iterator>(
        InstrNodes.begin());
  }
  const_instr_node_iterator instr_nodes_end() const {
    return raw_pointer_iterator<InstrNodesVec::const_iterator>(
        InstrNodes.end());
  }
  iterator_range<instr_node_iterator> instr_nodes() {
    return make_range(instr_nodes_begin(), instr_nodes_end());
  }
  iterator_range<const_instr_node_iterator> instr_nodes() const {
    return make_range(instr_nodes_begin(), instr_nodes_end());
  }
  predicate_edge_iterator predicate_edges_begin() {
    return raw_pointer_iterator<PredicateDependencyEdgesVec::iterator>(
        PredicateDependencies.begin());
  }
  predicate_edge_iterator predicate_edges_end() {
    return raw_pointer_iterator<PredicateDependencyEdgesVec::iterator>(
        PredicateDependencies.end());
  }
  const_predicate_edge_iterator predicate_edges_begin() const {
    return raw_pointer_iterator<PredicateDependencyEdgesVec::const_iterator>(
        PredicateDependencies.begin());
  }
  const_predicate_edge_iterator predicate_edges_end() const {
    return raw_pointer_iterator<PredicateDependencyEdgesVec::const_iterator>(
        PredicateDependencies.end());
  }
  iterator_range<predicate_edge_iterator> predicate_edges() {
    return make_range(predicate_edges_begin(), predicate_edges_end());
  }
  iterator_range<const_predicate_edge_iterator> predicate_edges() const {
    return make_range(predicate_edges_begin(), predicate_edges_end());
  }
  predicate_iterator predicates_begin() {
    return raw_pointer_iterator<PredicateNodesVec::iterator>(
        PredicateNodes.begin());
  }
  predicate_iterator predicates_end() {
    return raw_pointer_iterator<PredicateNodesVec::iterator>(
        PredicateNodes.end());
  }
  const_predicate_iterator predicates_begin() const {
    return raw_pointer_iterator<PredicateNodesVec::const_iterator>(
        PredicateNodes.begin());
  }
  const_predicate_iterator predicates_end() const {
    return raw_pointer_iterator<PredicateNodesVec::const_iterator>(
        PredicateNodes.end());
  }
  iterator_range<predicate_iterator> predicates() {
    return make_range(predicates_begin(), predicates_end());
  }
  iterator_range<const_predicate_iterator> predicates() const {
    return make_range(predicates_begin(), predicates_end());
  }

  template <class... Args> GIMatchDagInstr *addInstrNode(Args &&... args) {
    auto Obj =
        std::make_unique<GIMatchDagInstr>(*this, std::forward<Args>(args)...);
    auto ObjRaw = Obj.get();
    InstrNodes.push_back(std::move(Obj));
    return ObjRaw;
  }

  template <class T, class... Args>
  T *addPredicateNode(Args &&... args) {
    auto Obj = std::make_unique<T>(getContext(), std::forward<Args>(args)...);
    auto ObjRaw = Obj.get();
    PredicateNodes.push_back(std::move(Obj));
    return ObjRaw;
  }

  template <class... Args> GIMatchDagEdge *addEdge(Args &&... args) {
    auto Obj = std::make_unique<GIMatchDagEdge>(std::forward<Args>(args)...);
    auto ObjRaw = Obj.get();
    Edges.push_back(std::move(Obj));
    return ObjRaw;
  }

  template <class... Args>
  GIMatchDagPredicateDependencyEdge *addPredicateDependency(Args &&... args) {
    auto Obj = std::make_unique<GIMatchDagPredicateDependencyEdge>(
        std::forward<Args>(args)...);
    auto ObjRaw = Obj.get();
    PredicateDependencies.push_back(std::move(Obj));
    return ObjRaw;
  }

  size_t getInstrNodeIdx(instr_node_iterator I) {
    return std::distance(instr_nodes_begin(), I);
  }
  size_t getInstrNodeIdx(const_instr_node_iterator I) const {
    return std::distance(instr_nodes_begin(), I);
  }
  size_t getNumInstrNodes() const { return InstrNodes.size(); }
  size_t getNumEdges() const { return Edges.size(); }
  size_t getNumPredicates() const { return PredicateNodes.size(); }

  void setHasPostMatchPredicate(bool V) { HasPostMatchPredicate = V; }
  bool hasPostMatchPredicate() const { return HasPostMatchPredicate; }

  void addMatchRoot(GIMatchDagInstr *N) { MatchRoots.push_back(N); }

  LLVM_DUMP_METHOD void print(raw_ostream &OS) const;

#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
  LLVM_DUMP_METHOD void dump() const { print(errs()); }
#endif // if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)

  void writeDOTGraph(raw_ostream &OS, StringRef ID) const;
};

raw_ostream &operator<<(raw_ostream &OS, const GIMatchDag &G);

} // end namespace llvm

#endif // ifndef LLVM_UTILS_TABLEGEN_GIMATCHDAG_H