1356843Sdim//===- GIMatchDag.cpp - A DAG representation of a pattern to be matched ---===//
2356843Sdim//
3356843Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4356843Sdim// See https://llvm.org/LICENSE.txt for license information.
5356843Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6356843Sdim//
7356843Sdim//===----------------------------------------------------------------------===//
8356843Sdim
9356843Sdim#include "GIMatchDag.h"
10356843Sdim
11356843Sdim#include "llvm/Support/Format.h"
12356843Sdim#include "llvm/TableGen/Record.h"
13356843Sdim#include "../CodeGenInstruction.h"
14356843Sdim
15356843Sdimusing namespace llvm;
16356843Sdim
17356843Sdimvoid GIMatchDag::writeDOTGraph(raw_ostream &OS, StringRef ID) const {
18356843Sdim  const auto writePorts = [&](StringRef Prefix,
19356843Sdim                              const GIMatchDagOperandList &Operands) {
20356843Sdim    StringRef Separator = "";
21356843Sdim    OS << "{";
22356843Sdim    for (const auto &Op : enumerate(Operands)) {
23356843Sdim      OS << Separator << "<" << Prefix << format("%d", Op.index()) << ">"
24356843Sdim         << "#" << Op.index() << " $" << Op.value().getName();
25356843Sdim      Separator = "|";
26356843Sdim    }
27356843Sdim    OS << "}";
28356843Sdim  };
29356843Sdim
30356843Sdim  OS << "digraph \"" << ID << "\" {\n"
31356843Sdim     << "  rankdir=\"BT\"\n";
32356843Sdim  for (const auto &N : InstrNodes) {
33356843Sdim    OS << "  " << format("Node%p", &*N) << " [shape=record,label=\"{";
34356843Sdim    writePorts("s", N->getOperandInfo());
35356843Sdim    OS << "|" << N->getName();
36356843Sdim    if (N->getOpcodeAnnotation())
37356843Sdim      OS << "|" << N->getOpcodeAnnotation()->TheDef->getName();
38356843Sdim    if (N->isMatchRoot())
39356843Sdim      OS << "|Match starts here";
40356843Sdim    OS << "|";
41356843Sdim    SmallVector<std::pair<unsigned, StringRef>, 8> ToPrint;
42356843Sdim    for (const auto &Assignment : N->user_assigned_operand_names())
43356843Sdim      ToPrint.emplace_back(Assignment.first, Assignment.second);
44356843Sdim    llvm::sort(ToPrint.begin(), ToPrint.end());
45356843Sdim    StringRef Separator = "";
46356843Sdim    for (const auto &Assignment : ToPrint) {
47356843Sdim      OS << Separator << "$" << Assignment.second << "=getOperand("
48356843Sdim         << Assignment.first << ")";
49356843Sdim      Separator = ", ";
50356843Sdim    }
51356843Sdim    OS << format("|%p|", &N);
52356843Sdim    writePorts("d", N->getOperandInfo());
53356843Sdim    OS << "}\"";
54356843Sdim    if (N->isMatchRoot())
55356843Sdim      OS << ",color=red";
56356843Sdim    OS << "]\n";
57356843Sdim  }
58356843Sdim
59356843Sdim  for (const auto &E : Edges) {
60356843Sdim    const char *FromFmt = "Node%p:s%d:n";
61356843Sdim    const char *ToFmt = "Node%p:d%d:s";
62356843Sdim    if (E->getFromMO()->isDef() && !E->getToMO()->isDef())
63356843Sdim      std::swap(FromFmt, ToFmt);
64356843Sdim    auto From = format(FromFmt, E->getFromMI(), E->getFromMO()->getIdx());
65356843Sdim    auto To = format(ToFmt, E->getToMI(), E->getToMO()->getIdx());
66356843Sdim    if (E->getFromMO()->isDef() && !E->getToMO()->isDef())
67356843Sdim      std::swap(From, To);
68356843Sdim
69356843Sdim    OS << "  " << From << " -> " << To << " [label=\"$" << E->getName();
70356843Sdim    if (E->getFromMO()->isDef() == E->getToMO()->isDef())
71356843Sdim      OS << " INVALID EDGE!";
72356843Sdim    OS << "\"";
73356843Sdim    if (E->getFromMO()->isDef() == E->getToMO()->isDef())
74356843Sdim      OS << ",color=red";
75356843Sdim    else if (E->getFromMO()->isDef() && !E->getToMO()->isDef())
76356843Sdim      OS << ",dir=back,arrowtail=crow";
77356843Sdim    OS << "]\n";
78356843Sdim  }
79356843Sdim
80356843Sdim  for (const auto &N : PredicateNodes) {
81356843Sdim    OS << "  " << format("Pred%p", &*N) << " [shape=record,label=\"{";
82356843Sdim    writePorts("s", N->getOperandInfo());
83356843Sdim    OS << "|" << N->getName() << "|";
84356843Sdim    N->printDescription(OS);
85356843Sdim    OS << format("|%p|", &N);
86356843Sdim    writePorts("d", N->getOperandInfo());
87356843Sdim    OS << "}\",style=dotted]\n";
88356843Sdim  }
89356843Sdim
90356843Sdim  for (const auto &E : PredicateDependencies) {
91356843Sdim    const char *FromMIFmt = "Node%p:e";
92356843Sdim    const char *FromMOFmt = "Node%p:s%d:n";
93356843Sdim    const char *ToFmt = "Pred%p:d%d:s";
94356843Sdim    auto To = format(ToFmt, E->getPredicate(), E->getPredicateOp()->getIdx());
95356843Sdim    auto Style = "[style=dotted]";
96356843Sdim    if (E->getRequiredMO()) {
97356843Sdim      auto From =
98356843Sdim          format(FromMOFmt, E->getRequiredMI(), E->getRequiredMO()->getIdx());
99356843Sdim      OS << "  " << From << " -> " << To << " " << Style << "\n";
100356843Sdim      continue;
101356843Sdim    }
102356843Sdim    auto From = format(FromMIFmt, E->getRequiredMI());
103356843Sdim    OS << "  " << From << " -> " << To << " " << Style << "\n";
104356843Sdim  }
105356843Sdim
106356843Sdim  OS << "}\n";
107356843Sdim}
108356843Sdim
109356843SdimLLVM_DUMP_METHOD void GIMatchDag::print(raw_ostream &OS) const {
110356843Sdim  OS << "matchdag {\n";
111356843Sdim  for (const auto &N : InstrNodes) {
112356843Sdim    OS << "  ";
113356843Sdim    N->print(OS);
114356843Sdim    OS << "\n";
115356843Sdim  }
116356843Sdim  for (const auto &E : Edges) {
117356843Sdim    OS << "  ";
118356843Sdim    E->print(OS);
119356843Sdim    OS << "\n";
120356843Sdim  }
121356843Sdim
122356843Sdim  for (const auto &P : PredicateNodes) {
123356843Sdim    OS << "  ";
124356843Sdim    P->print(OS);
125356843Sdim    OS << "\n";
126356843Sdim  }
127356843Sdim  for (const auto &D : PredicateDependencies) {
128356843Sdim    OS << "  ";
129356843Sdim    D->print(OS);
130356843Sdim    OS << "\n";
131356843Sdim  }
132356843Sdim  OS << "}\n";
133356843Sdim}
134356843Sdim
135356843Sdimraw_ostream &llvm::operator<<(raw_ostream &OS, const GIMatchDag &G) {
136356843Sdim  G.print(OS);
137356843Sdim  return OS;
138356843Sdim}
139