123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314 |
- //===-- SelectionDAGPrinter.cpp - Implement SelectionDAG::viewGraph() -----===//
- //
- // 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
- //
- //===----------------------------------------------------------------------===//
- //
- // This implements the SelectionDAG::viewGraph method.
- //
- //===----------------------------------------------------------------------===//
- #include "ScheduleDAGSDNodes.h"
- #include "llvm/ADT/DenseSet.h"
- #include "llvm/ADT/StringExtras.h"
- #include "llvm/CodeGen/MachineFunction.h"
- #include "llvm/CodeGen/SelectionDAG.h"
- #include "llvm/Support/Debug.h"
- #include "llvm/Support/GraphWriter.h"
- #include "llvm/Support/raw_ostream.h"
- using namespace llvm;
- #define DEBUG_TYPE "dag-printer"
- namespace llvm {
- template<>
- struct DOTGraphTraits<SelectionDAG*> : public DefaultDOTGraphTraits {
- explicit DOTGraphTraits(bool isSimple=false) :
- DefaultDOTGraphTraits(isSimple) {}
- static bool hasEdgeDestLabels() {
- return true;
- }
- static unsigned numEdgeDestLabels(const void *Node) {
- return ((const SDNode *) Node)->getNumValues();
- }
- static std::string getEdgeDestLabel(const void *Node, unsigned i) {
- return ((const SDNode *) Node)->getValueType(i).getEVTString();
- }
- template<typename EdgeIter>
- static std::string getEdgeSourceLabel(const void *Node, EdgeIter I) {
- return itostr(I - SDNodeIterator::begin((const SDNode *) Node));
- }
- /// edgeTargetsEdgeSource - This method returns true if this outgoing edge
- /// should actually target another edge source, not a node. If this method
- /// is implemented, getEdgeTarget should be implemented.
- template<typename EdgeIter>
- static bool edgeTargetsEdgeSource(const void *Node, EdgeIter I) {
- return true;
- }
- /// getEdgeTarget - If edgeTargetsEdgeSource returns true, this method is
- /// called to determine which outgoing edge of Node is the target of this
- /// edge.
- template<typename EdgeIter>
- static EdgeIter getEdgeTarget(const void *Node, EdgeIter I) {
- SDNode *TargetNode = *I;
- SDNodeIterator NI = SDNodeIterator::begin(TargetNode);
- std::advance(NI, I.getNode()->getOperand(I.getOperand()).getResNo());
- return NI;
- }
- static std::string getGraphName(const SelectionDAG *G) {
- return std::string(G->getMachineFunction().getName());
- }
- static bool renderGraphFromBottomUp() {
- return true;
- }
- static std::string getNodeIdentifierLabel(const SDNode *Node,
- const SelectionDAG *Graph) {
- std::string R;
- raw_string_ostream OS(R);
- #ifndef NDEBUG
- OS << 't' << Node->PersistentId;
- #else
- OS << static_cast<const void *>(Node);
- #endif
- return R;
- }
- /// If you want to override the dot attributes printed for a particular
- /// edge, override this method.
- template<typename EdgeIter>
- static std::string getEdgeAttributes(const void *Node, EdgeIter EI,
- const SelectionDAG *Graph) {
- SDValue Op = EI.getNode()->getOperand(EI.getOperand());
- EVT VT = Op.getValueType();
- if (VT == MVT::Glue)
- return "color=red,style=bold";
- else if (VT == MVT::Other)
- return "color=blue,style=dashed";
- return "";
- }
- static std::string getSimpleNodeLabel(const SDNode *Node,
- const SelectionDAG *G) {
- std::string Result = Node->getOperationName(G);
- {
- raw_string_ostream OS(Result);
- Node->print_details(OS, G);
- }
- return Result;
- }
- std::string getNodeLabel(const SDNode *Node, const SelectionDAG *Graph);
- static std::string getNodeAttributes(const SDNode *N,
- const SelectionDAG *Graph) {
- #ifndef NDEBUG
- const std::string &Attrs = Graph->getGraphAttrs(N);
- if (!Attrs.empty()) {
- if (Attrs.find("shape=") == std::string::npos)
- return std::string("shape=Mrecord,") + Attrs;
- else
- return Attrs;
- }
- #endif
- return "shape=Mrecord";
- }
- static void addCustomGraphFeatures(SelectionDAG *G,
- GraphWriter<SelectionDAG*> &GW) {
- GW.emitSimpleNode(nullptr, "plaintext=circle", "GraphRoot");
- if (G->getRoot().getNode())
- GW.emitEdge(nullptr, -1, G->getRoot().getNode(), G->getRoot().getResNo(),
- "color=blue,style=dashed");
- }
- };
- }
- std::string DOTGraphTraits<SelectionDAG*>::getNodeLabel(const SDNode *Node,
- const SelectionDAG *G) {
- return DOTGraphTraits<SelectionDAG*>::getSimpleNodeLabel(Node, G);
- }
- /// viewGraph - Pop up a ghostview window with the reachable parts of the DAG
- /// rendered using 'dot'.
- ///
- void SelectionDAG::viewGraph(const std::string &Title) {
- // This code is only for debugging!
- #ifndef NDEBUG
- ViewGraph(this, "dag." + getMachineFunction().getName(),
- false, Title);
- #else
- errs() << "SelectionDAG::viewGraph is only available in debug builds on "
- << "systems with Graphviz or gv!\n";
- #endif // NDEBUG
- }
- // This overload is defined out-of-line here instead of just using a
- // default parameter because this is easiest for gdb to call.
- void SelectionDAG::viewGraph() {
- viewGraph("");
- }
- /// Just dump dot graph to a user-provided path and title.
- /// This doesn't open the dot viewer program and
- /// helps visualization when outside debugging session.
- /// FileName expects absolute path. If provided
- /// without any path separators then the file
- /// will be created in the current directory.
- /// Error will be emitted if the path is insane.
- #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
- LLVM_DUMP_METHOD void SelectionDAG::dumpDotGraph(const Twine &FileName,
- const Twine &Title) {
- dumpDotGraphToFile(this, FileName, Title);
- }
- #endif
- /// clearGraphAttrs - Clear all previously defined node graph attributes.
- /// Intended to be used from a debugging tool (eg. gdb).
- void SelectionDAG::clearGraphAttrs() {
- #if LLVM_ENABLE_ABI_BREAKING_CHECKS
- NodeGraphAttrs.clear();
- #else
- errs() << "SelectionDAG::clearGraphAttrs is only available in builds with "
- << "ABI breaking checks enabled on systems with Graphviz or gv!\n";
- #endif
- }
- /// setGraphAttrs - Set graph attributes for a node. (eg. "color=red".)
- ///
- void SelectionDAG::setGraphAttrs(const SDNode *N, const char *Attrs) {
- #if LLVM_ENABLE_ABI_BREAKING_CHECKS
- NodeGraphAttrs[N] = Attrs;
- #else
- errs() << "SelectionDAG::setGraphAttrs is only available in builds with "
- << "ABI breaking checks enabled on systems with Graphviz or gv!\n";
- #endif
- }
- /// getGraphAttrs - Get graph attributes for a node. (eg. "color=red".)
- /// Used from getNodeAttributes.
- std::string SelectionDAG::getGraphAttrs(const SDNode *N) const {
- #if LLVM_ENABLE_ABI_BREAKING_CHECKS
- std::map<const SDNode *, std::string>::const_iterator I =
- NodeGraphAttrs.find(N);
- if (I != NodeGraphAttrs.end())
- return I->second;
- else
- return "";
- #else
- errs() << "SelectionDAG::getGraphAttrs is only available in builds with "
- << "ABI breaking checks enabled on systems with Graphviz or gv!\n";
- return std::string();
- #endif
- }
- /// setGraphColor - Convenience for setting node color attribute.
- ///
- void SelectionDAG::setGraphColor(const SDNode *N, const char *Color) {
- #if LLVM_ENABLE_ABI_BREAKING_CHECKS
- NodeGraphAttrs[N] = std::string("color=") + Color;
- #else
- errs() << "SelectionDAG::setGraphColor is only available in builds with "
- << "ABI breaking checks enabled on systems with Graphviz or gv!\n";
- #endif
- }
- /// setSubgraphColorHelper - Implement setSubgraphColor. Return
- /// whether we truncated the search.
- ///
- bool SelectionDAG::setSubgraphColorHelper(SDNode *N, const char *Color, DenseSet<SDNode *> &visited,
- int level, bool &printed) {
- bool hit_limit = false;
- #ifndef NDEBUG
- if (level >= 20) {
- if (!printed) {
- printed = true;
- LLVM_DEBUG(dbgs() << "setSubgraphColor hit max level\n");
- }
- return true;
- }
- unsigned oldSize = visited.size();
- visited.insert(N);
- if (visited.size() != oldSize) {
- setGraphColor(N, Color);
- for(SDNodeIterator i = SDNodeIterator::begin(N), iend = SDNodeIterator::end(N);
- i != iend;
- ++i) {
- hit_limit = setSubgraphColorHelper(*i, Color, visited, level+1, printed) || hit_limit;
- }
- }
- #else
- errs() << "SelectionDAG::setSubgraphColor is only available in debug builds"
- << " on systems with Graphviz or gv!\n";
- #endif
- return hit_limit;
- }
- /// setSubgraphColor - Convenience for setting subgraph color attribute.
- ///
- void SelectionDAG::setSubgraphColor(SDNode *N, const char *Color) {
- #ifndef NDEBUG
- DenseSet<SDNode *> visited;
- bool printed = false;
- if (setSubgraphColorHelper(N, Color, visited, 0, printed)) {
- // Visually mark that we hit the limit
- if (strcmp(Color, "red") == 0) {
- setSubgraphColorHelper(N, "blue", visited, 0, printed);
- } else if (strcmp(Color, "yellow") == 0) {
- setSubgraphColorHelper(N, "green", visited, 0, printed);
- }
- }
- #else
- errs() << "SelectionDAG::setSubgraphColor is only available in debug builds"
- << " on systems with Graphviz or gv!\n";
- #endif
- }
- std::string ScheduleDAGSDNodes::getGraphNodeLabel(const SUnit *SU) const {
- std::string s;
- raw_string_ostream O(s);
- O << "SU(" << SU->NodeNum << "): ";
- if (SU->getNode()) {
- SmallVector<SDNode *, 4> GluedNodes;
- for (SDNode *N = SU->getNode(); N; N = N->getGluedNode())
- GluedNodes.push_back(N);
- while (!GluedNodes.empty()) {
- O << DOTGraphTraits<SelectionDAG*>
- ::getSimpleNodeLabel(GluedNodes.back(), DAG);
- GluedNodes.pop_back();
- if (!GluedNodes.empty())
- O << "\n ";
- }
- } else {
- O << "CROSS RC COPY";
- }
- return O.str();
- }
- void ScheduleDAGSDNodes::getCustomGraphFeatures(GraphWriter<ScheduleDAG*> &GW) const {
- if (DAG) {
- // Draw a special "GraphRoot" node to indicate the root of the graph.
- GW.emitSimpleNode(nullptr, "plaintext=circle", "GraphRoot");
- const SDNode *N = DAG->getRoot().getNode();
- if (N && N->getNodeId() != -1)
- GW.emitEdge(nullptr, -1, &SUnits[N->getNodeId()], -1,
- "color=blue,style=dashed");
- }
- }
|