[llvm] 32a8260 - -dot-machine-cfg for printing MachineFunction to a dot file

Christudasan Devadasan via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 22 00:19:56 PDT 2022


Author: Christudasan Devadasan
Date: 2022-09-22T12:48:33+05:30
New Revision: 32a8260ccc8bc87134df6417c6deb0f4172bc4bf

URL: https://github.com/llvm/llvm-project/commit/32a8260ccc8bc87134df6417c6deb0f4172bc4bf
DIFF: https://github.com/llvm/llvm-project/commit/32a8260ccc8bc87134df6417c6deb0f4172bc4bf.diff

LOG: -dot-machine-cfg for printing MachineFunction to a dot file

This pass allows a user to dump a MIR function to a dot file
and view it as a graph. It is targeted to provide a similar
functionality as -dot-cfg pass on LLVM-IR. As of now the pass
also support below flags:
-dot-mcfg-only [optional][won't print instructions in the
graph just block name]
-mcfg-dot-filename-prefix [optional][prefix to add to output dot file]
-mcfg-func-name [optional] [specify function name or it's
substring, handy if mir file contains multiple functions and
you need to see graph of just one]

More flags and details can be introduced as per the requirements
in future. This pass is inspired from -dot-cfg IR pass and APIs
are written in almost identical format.

Patch by Yashwant Singh <Yashwant.Singh at amd.com> (yassingh)

Reviewed By: arsenm

Differential Revision: https://reviews.llvm.org/D133709

Added: 
    llvm/include/llvm/CodeGen/MachineCFGPrinter.h
    llvm/lib/CodeGen/MachineCFGPrinter.cpp
    llvm/test/Analysis/DotMachineCFG/AMDGPU/functions.mir
    llvm/test/Analysis/DotMachineCFG/AMDGPU/irreducible.mir
    llvm/test/Analysis/DotMachineCFG/AMDGPU/lit.local.cfg

Modified: 
    llvm/include/llvm/Analysis/CFGPrinter.h
    llvm/include/llvm/CodeGen/MachinePassRegistry.def
    llvm/include/llvm/CodeGen/Passes.h
    llvm/include/llvm/InitializePasses.h
    llvm/lib/CodeGen/CMakeLists.txt
    llvm/lib/CodeGen/CodeGen.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Analysis/CFGPrinter.h b/llvm/include/llvm/Analysis/CFGPrinter.h
index 768cda59c57de..5def897839a4c 100644
--- a/llvm/include/llvm/Analysis/CFGPrinter.h
+++ b/llvm/include/llvm/Analysis/CFGPrinter.h
@@ -119,81 +119,96 @@ struct GraphTraits<DOTFuncInfo *> : public GraphTraits<const BasicBlock *> {
   }
 };
 
+template <typename BasicBlockT>
+std::string SimpleNodeLabelString(const BasicBlockT *Node) {
+  if (!Node->getName().empty())
+    return Node->getName().str();
+
+  std::string Str;
+  raw_string_ostream OS(Str);
+
+  Node->printAsOperand(OS, false);
+  return OS.str();
+}
+
+template <typename BasicBlockT>
+std::string CompleteNodeLabelString(
+    const BasicBlockT *Node,
+    function_ref<void(raw_string_ostream &, const BasicBlockT &)>
+        HandleBasicBlock,
+    function_ref<void(std::string &, unsigned &, unsigned)>
+        HandleComment) {
+
+  enum { MaxColumns = 80 };
+  std::string Str;
+  raw_string_ostream OS(Str);
+
+  if (Node->getName().empty()) {
+    Node->printAsOperand(OS, false);
+    OS << ':';
+  }
+
+  HandleBasicBlock(OS, *Node);
+  std::string OutStr = OS.str();
+  if (OutStr[0] == '\n')
+    OutStr.erase(OutStr.begin());
+
+  unsigned ColNum = 0;
+  unsigned LastSpace = 0;
+  for (unsigned i = 0; i != OutStr.length(); ++i) {
+    if (OutStr[i] == '\n') { // Left justify
+      OutStr[i] = '\\';
+      OutStr.insert(OutStr.begin() + i + 1, 'l');
+      ColNum = 0;
+      LastSpace = 0;
+    } else if (OutStr[i] == ';') {             // Delete comments!
+      unsigned Idx = OutStr.find('\n', i + 1); // Find end of line
+      HandleComment(OutStr, i, Idx);
+    } else if (ColNum == MaxColumns) { // Wrap lines.
+      // Wrap very long names even though we can't find a space.
+      if (!LastSpace)
+        LastSpace = i;
+      OutStr.insert(LastSpace, "\\l...");
+      ColNum = i - LastSpace;
+      LastSpace = 0;
+      i += 3; // The loop will advance 'i' again.
+    } else
+      ++ColNum;
+    if (OutStr[i] == ' ')
+      LastSpace = i;
+  }
+  return OutStr;
+}
+
 template <>
 struct DOTGraphTraits<DOTFuncInfo *> : public DefaultDOTGraphTraits {
 
   // Cache for is hidden property
-  llvm::DenseMap<const BasicBlock *, bool> isOnDeoptOrUnreachablePath;
+  DenseMap<const BasicBlock *, bool> isOnDeoptOrUnreachablePath;
 
   DOTGraphTraits(bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {}
 
+  static void eraseComment(std::string &OutStr, unsigned &I, unsigned Idx) {
+    OutStr.erase(OutStr.begin() + I, OutStr.begin() + Idx);
+    --I;
+  }
+
   static std::string getGraphName(DOTFuncInfo *CFGInfo) {
     return "CFG for '" + CFGInfo->getFunction()->getName().str() + "' function";
   }
 
   static std::string getSimpleNodeLabel(const BasicBlock *Node, DOTFuncInfo *) {
-    if (!Node->getName().empty())
-      return Node->getName().str();
-
-    std::string Str;
-    raw_string_ostream OS(Str);
-
-    Node->printAsOperand(OS, false);
-    return OS.str();
-  }
-
-  static void eraseComment(std::string &OutStr, unsigned &I, unsigned Idx) {
-    OutStr.erase(OutStr.begin() + I, OutStr.begin() + Idx);
-    --I;
+    return SimpleNodeLabelString(Node);
   }
 
   static std::string getCompleteNodeLabel(
       const BasicBlock *Node, DOTFuncInfo *,
-      llvm::function_ref<void(raw_string_ostream &, const BasicBlock &)>
+      function_ref<void(raw_string_ostream &, const BasicBlock &)>
           HandleBasicBlock = [](raw_string_ostream &OS,
                                 const BasicBlock &Node) -> void { OS << Node; },
-      llvm::function_ref<void(std::string &, unsigned &, unsigned)>
+      function_ref<void(std::string &, unsigned &, unsigned)>
           HandleComment = eraseComment) {
-    enum { MaxColumns = 80 };
-    std::string Str;
-    raw_string_ostream OS(Str);
-
-    if (Node->getName().empty()) {
-      Node->printAsOperand(OS, false);
-      OS << ":";
-    }
-
-    HandleBasicBlock(OS, *Node);
-    std::string OutStr = OS.str();
-    if (OutStr[0] == '\n')
-      OutStr.erase(OutStr.begin());
-
-    // Process string output to make it nicer...
-    unsigned ColNum = 0;
-    unsigned LastSpace = 0;
-    for (unsigned i = 0; i != OutStr.length(); ++i) {
-      if (OutStr[i] == '\n') { // Left justify
-        OutStr[i] = '\\';
-        OutStr.insert(OutStr.begin() + i + 1, 'l');
-        ColNum = 0;
-        LastSpace = 0;
-      } else if (OutStr[i] == ';') {             // Delete comments!
-        unsigned Idx = OutStr.find('\n', i + 1); // Find end of line
-        HandleComment(OutStr, i, Idx);
-      } else if (ColNum == MaxColumns) { // Wrap lines.
-        // Wrap very long names even though we can't find a space.
-        if (!LastSpace)
-          LastSpace = i;
-        OutStr.insert(LastSpace, "\\l...");
-        ColNum = i - LastSpace;
-        LastSpace = 0;
-        i += 3; // The loop will advance 'i' again.
-      } else
-        ++ColNum;
-      if (OutStr[i] == ' ')
-        LastSpace = i;
-    }
-    return OutStr;
+    return CompleteNodeLabelString(Node, HandleBasicBlock, HandleComment);
   }
 
   std::string getNodeLabel(const BasicBlock *Node, DOTFuncInfo *CFGInfo) {

diff  --git a/llvm/include/llvm/CodeGen/MachineCFGPrinter.h b/llvm/include/llvm/CodeGen/MachineCFGPrinter.h
new file mode 100644
index 0000000000000..ea3ff5a5c828b
--- /dev/null
+++ b/llvm/include/llvm/CodeGen/MachineCFGPrinter.h
@@ -0,0 +1,92 @@
+//===-- MachineCFGPrinter.h -------------------------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Analysis/CFGPrinter.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineInstr.h"
+#include "llvm/Support/DOTGraphTraits.h"
+
+namespace llvm {
+
+template <class GraphType> struct GraphTraits;
+class DOTMachineFuncInfo {
+private:
+  const MachineFunction *F;
+
+public:
+  DOTMachineFuncInfo(const MachineFunction *F) : F(F) {}
+
+  const MachineFunction *getFunction() const { return this->F; }
+};
+
+template <>
+struct GraphTraits<DOTMachineFuncInfo *>
+    : public GraphTraits<const MachineBasicBlock *> {
+  static NodeRef getEntryNode(DOTMachineFuncInfo *CFGInfo) {
+    return &(CFGInfo->getFunction()->front());
+  }
+
+  // nodes_iterator/begin/end - Allow iteration over all nodes in the graph
+  using nodes_iterator = pointer_iterator<MachineFunction::const_iterator>;
+
+  static nodes_iterator nodes_begin(DOTMachineFuncInfo *CFGInfo) {
+    return nodes_iterator(CFGInfo->getFunction()->begin());
+  }
+
+  static nodes_iterator nodes_end(DOTMachineFuncInfo *CFGInfo) {
+    return nodes_iterator(CFGInfo->getFunction()->end());
+  }
+
+  static size_t size(DOTMachineFuncInfo *CFGInfo) {
+    return CFGInfo->getFunction()->size();
+  }
+};
+
+template <>
+struct DOTGraphTraits<DOTMachineFuncInfo *> : public DefaultDOTGraphTraits {
+
+  DOTGraphTraits(bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {}
+
+  static void eraseComment(std::string &OutStr, unsigned &I, unsigned Idx) {
+    OutStr.erase(OutStr.begin() + I, OutStr.begin() + Idx);
+    --I;
+  }
+
+  static std::string getSimpleNodeLabel(const MachineBasicBlock *Node,
+                                        DOTMachineFuncInfo *) {
+    return SimpleNodeLabelString(Node);
+  }
+
+  static std::string getCompleteNodeLabel(
+      const MachineBasicBlock *Node, DOTMachineFuncInfo *,
+      function_ref<void(raw_string_ostream &, const MachineBasicBlock &)>
+          HandleBasicBlock =
+              [](raw_string_ostream &OS,
+                 const MachineBasicBlock &Node) -> void { OS << Node; },
+      function_ref<void(std::string &, unsigned &, unsigned)>
+          HandleComment = eraseComment) {
+    return CompleteNodeLabelString(Node, HandleBasicBlock, HandleComment);
+  }
+
+  std::string getNodeLabel(const MachineBasicBlock *Node,
+                           DOTMachineFuncInfo *CFGInfo) {
+    if (isSimple())
+      return getSimpleNodeLabel(Node, CFGInfo);
+
+    return getCompleteNodeLabel(Node, CFGInfo);
+  }
+
+  static std::string getGraphName(DOTMachineFuncInfo *CFGInfo) {
+    return "Machine CFG for '" + CFGInfo->getFunction()->getName().str() +
+           "' function";
+  }
+};
+} // namespace llvm

diff  --git a/llvm/include/llvm/CodeGen/MachinePassRegistry.def b/llvm/include/llvm/CodeGen/MachinePassRegistry.def
index 077b71327c04c..617214aaca3c1 100644
--- a/llvm/include/llvm/CodeGen/MachinePassRegistry.def
+++ b/llvm/include/llvm/CodeGen/MachinePassRegistry.def
@@ -159,6 +159,7 @@ DUMMY_MACHINE_FUNCTION_PASS("reg-usage-collector", RegUsageInfoCollectorPass, ()
 DUMMY_MACHINE_FUNCTION_PASS("funclet-layout", FuncletLayoutPass, ())
 DUMMY_MACHINE_FUNCTION_PASS("stackmap-liveness", StackMapLivenessPass, ())
 DUMMY_MACHINE_FUNCTION_PASS("removeredundantdebugvalues", RemoveRedundantDebugValuesPass, ())
+DUMMY_MACHINE_FUNCTION_PASS("dot-machine-cfg", MachineCFGPrinter, ())
 DUMMY_MACHINE_FUNCTION_PASS("livedebugvalues", LiveDebugValuesPass, ())
 DUMMY_MACHINE_FUNCTION_PASS("early-tailduplication", EarlyTailDuplicatePass, ())
 DUMMY_MACHINE_FUNCTION_PASS("opt-phis", OptimizePHIsPass, ())

diff  --git a/llvm/include/llvm/CodeGen/Passes.h b/llvm/include/llvm/CodeGen/Passes.h
index a97fd5cc78c70..2ec803aaa66c5 100644
--- a/llvm/include/llvm/CodeGen/Passes.h
+++ b/llvm/include/llvm/CodeGen/Passes.h
@@ -408,6 +408,9 @@ namespace llvm {
   /// RemoveRedundantDebugValues pass.
   extern char &RemoveRedundantDebugValuesID;
 
+  /// MachineCFGPrinter pass.
+  extern char &MachineCFGPrinterID;
+
   /// LiveDebugValues pass
   extern char &LiveDebugValuesID;
 

diff  --git a/llvm/include/llvm/InitializePasses.h b/llvm/include/llvm/InitializePasses.h
index b7e5a7f88e299..6a5d91661b03c 100644
--- a/llvm/include/llvm/InitializePasses.h
+++ b/llvm/include/llvm/InitializePasses.h
@@ -277,6 +277,7 @@ void initializeMachineBlockFrequencyInfoPass(PassRegistry&);
 void initializeMachineBlockPlacementPass(PassRegistry&);
 void initializeMachineBlockPlacementStatsPass(PassRegistry&);
 void initializeMachineBranchProbabilityInfoPass(PassRegistry&);
+void initializeMachineCFGPrinterPass(PassRegistry &);
 void initializeMachineCSEPass(PassRegistry&);
 void initializeMachineCombinerPass(PassRegistry&);
 void initializeMachineCopyPropagationPass(PassRegistry&);

diff  --git a/llvm/lib/CodeGen/CMakeLists.txt b/llvm/lib/CodeGen/CMakeLists.txt
index 5ed42c7def2d4..604f2c630f853 100644
--- a/llvm/lib/CodeGen/CMakeLists.txt
+++ b/llvm/lib/CodeGen/CMakeLists.txt
@@ -101,6 +101,7 @@ add_llvm_component_library(LLVMCodeGen
   MachineBlockFrequencyInfo.cpp
   MachineBlockPlacement.cpp
   MachineBranchProbabilityInfo.cpp
+  MachineCFGPrinter.cpp
   MachineCombiner.cpp
   MachineCopyPropagation.cpp
   MachineCSE.cpp

diff  --git a/llvm/lib/CodeGen/CodeGen.cpp b/llvm/lib/CodeGen/CodeGen.cpp
index 219032e30cc93..87090ec369934 100644
--- a/llvm/lib/CodeGen/CodeGen.cpp
+++ b/llvm/lib/CodeGen/CodeGen.cpp
@@ -69,6 +69,7 @@ void llvm::initializeCodeGen(PassRegistry &Registry) {
   initializeMachineBlockFrequencyInfoPass(Registry);
   initializeMachineBlockPlacementPass(Registry);
   initializeMachineBlockPlacementStatsPass(Registry);
+  initializeMachineCFGPrinterPass(Registry);
   initializeMachineCSEPass(Registry);
   initializeMachineCombinerPass(Registry);
   initializeMachineCopyPropagationPass(Registry);

diff  --git a/llvm/lib/CodeGen/MachineCFGPrinter.cpp b/llvm/lib/CodeGen/MachineCFGPrinter.cpp
new file mode 100644
index 0000000000000..7bfb817713808
--- /dev/null
+++ b/llvm/lib/CodeGen/MachineCFGPrinter.cpp
@@ -0,0 +1,95 @@
+//===- MachineCFGPrinter.cpp - DOT Printer for Machine Functions ----------===//
+//
+// 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 file defines the `-dot-machine-cfg` analysis pass, which emits
+// Machine Function in DOT format in file titled `<prefix>.<function-name>.dot.
+//===----------------------------------------------------------------------===//
+
+#include "llvm/CodeGen/MachineCFGPrinter.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/TargetSubtargetInfo.h"
+#include "llvm/InitializePasses.h"
+#include "llvm/Pass.h"
+#include "llvm/PassRegistry.h"
+#include "llvm/Support/GraphWriter.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "dot-machine-cfg"
+
+static cl::opt<std::string>
+    MCFGFuncName("mcfg-func-name", cl::Hidden,
+                 cl::desc("The name of a function (or its substring)"
+                          " whose CFG is viewed/printed."));
+
+static cl::opt<std::string> MCFGDotFilenamePrefix(
+    "mcfg-dot-filename-prefix", cl::Hidden,
+    cl::desc("The prefix used for the Machine CFG dot file names."));
+
+static cl::opt<bool>
+    CFGOnly("dot-mcfg-only", cl::init(false), cl::Hidden,
+            cl::desc("Print only the CFG without blocks body"));
+
+static void writeMCFGToDotFile(MachineFunction &MF) {
+  std::string Filename =
+      (MCFGDotFilenamePrefix + "." + MF.getName() + ".dot").str();
+  errs() << "Writing '" << Filename << "'...";
+
+  std::error_code EC;
+  raw_fd_ostream File(Filename, EC, sys::fs::OF_Text);
+
+  DOTMachineFuncInfo MCFGInfo(&MF);
+
+  if (!EC)
+    WriteGraph(File, &MCFGInfo, CFGOnly);
+  else
+    errs() << "  error opening file for writing!";
+  errs() << '\n';
+}
+
+namespace {
+
+class MachineCFGPrinter : public MachineFunctionPass {
+public:
+  static char ID;
+
+  MachineCFGPrinter();
+
+  bool runOnMachineFunction(MachineFunction &MF) override;
+
+  void getAnalysisUsage(AnalysisUsage &AU) const override {
+    AU.setPreservesCFG();
+    MachineFunctionPass::getAnalysisUsage(AU);
+  }
+};
+
+} // namespace
+
+char MachineCFGPrinter::ID = 0;
+
+char &llvm::MachineCFGPrinterID = MachineCFGPrinter::ID;
+
+INITIALIZE_PASS(MachineCFGPrinter, DEBUG_TYPE, "Machine CFG Printer Pass",
+                false, true)
+
+/// Default construct and initialize the pass.
+MachineCFGPrinter::MachineCFGPrinter() : MachineFunctionPass(ID) {
+  initializeMachineCFGPrinterPass(*PassRegistry::getPassRegistry());
+}
+
+bool MachineCFGPrinter::runOnMachineFunction(MachineFunction &MF) {
+  if (!MCFGFuncName.empty() && !MF.getName().contains(MCFGFuncName))
+    return false;
+  errs() << "Writing Machine CFG for function ";
+  errs().write_escaped(MF.getName()) << '\n';
+
+  writeMCFGToDotFile(MF);
+  return false;
+}

diff  --git a/llvm/test/Analysis/DotMachineCFG/AMDGPU/functions.mir b/llvm/test/Analysis/DotMachineCFG/AMDGPU/functions.mir
new file mode 100644
index 0000000000000..51daa8637621b
--- /dev/null
+++ b/llvm/test/Analysis/DotMachineCFG/AMDGPU/functions.mir
@@ -0,0 +1,24 @@
+# RUN: llc -mtriple=amdgcn-- -run-pass=dot-machine-cfg  -mcfg-dot-filename-prefix=%t -mcfg-func-name=func2 -o -  %s 2>&1 > /dev/null
+# RUN: FileCheck %s -input-file=%t.func2.dot --check-prefix=MCFG
+
+# MCFG-NOT: digraph "Machine CFG for 'func1' function"
+name: func1
+body: |
+  bb.0:
+    $sgpr0 = S_LOAD_DWORD_IMM $sgpr10_sgpr11, 0, 0
+    $sgpr1 = S_LOAD_DWORD_IMM $sgpr12_sgpr13, 0, 0
+    S_ENDPGM 0
+...
+
+# MCFG: digraph "Machine CFG for 'func2' function"
+# MCFG-NEXT: label="Machine CFG for 'func2' function"
+# MCFG: Node{{[0-9A-Za-z]*}} [shape=record,label="{%bb.0:bb.0:\l  $sgpr0 = S_LOAD_DWORD_IMM $sgpr12_sgpr13, 0, 0\l  $sgpr1 = S_LOAD_DWORD_IMM $sgpr6_sgpr7, 0, 0\l  $sgpr2 = S_LOAD_DWORD_IMM $sgpr14_sgpr15, 0, 0\l  S_ENDPGM 0\l}"];
+---
+name: func2
+body: |
+  bb.0:
+    $sgpr0 = S_LOAD_DWORD_IMM $sgpr12_sgpr13, 0, 0
+    $sgpr1 = S_LOAD_DWORD_IMM $sgpr6_sgpr7, 0, 0
+    $sgpr2 = S_LOAD_DWORD_IMM $sgpr14_sgpr15, 0, 0
+    S_ENDPGM 0
+...

diff  --git a/llvm/test/Analysis/DotMachineCFG/AMDGPU/irreducible.mir b/llvm/test/Analysis/DotMachineCFG/AMDGPU/irreducible.mir
new file mode 100644
index 0000000000000..e06aac2ab3f5a
--- /dev/null
+++ b/llvm/test/Analysis/DotMachineCFG/AMDGPU/irreducible.mir
@@ -0,0 +1,87 @@
+# RUN: llc -mtriple=amdgcn-- -run-pass=dot-machine-cfg  -mcfg-dot-filename-prefix=%t -o -  %s 2>&1 > /dev/null
+# RUN: FileCheck %s -input-file=%t.irreducible.dot --check-prefix=MCFG
+# RUN: llc -mtriple=amdgcn-- -run-pass=dot-machine-cfg  -mcfg-dot-filename-prefix=%t -dot-mcfg-only -o -  %s 2>&1 > /dev/null
+# RUN: FileCheck %s -input-file=%t.irreducible.dot --check-prefix=MCFG-ONLY
+
+# MCFG: digraph "Machine CFG for 'irreducible' function"
+# MCFG-NEXT: label="Machine CFG for 'irreducible' function"
+# MCFG: Node{{[0-9A-Za-z]*}} [shape=record,label="{%bb.0:bb.0:\l  successors: %bb.1(0x40000000), %bb.2(0x40000000)\l  liveins: $vgpr0, $vgpr1, $vgpr2, $sgpr4_sgpr5, $sgpr6_sgpr7, $sgpr8_sgpr9,\l... $sgpr10_sgpr11, $sgpr14, $sgpr15, $sgpr16\l  %0:sreg_32 = IMPLICIT_DEF\l  %1:vgpr_32 = COPY $vgpr0\l  %2:vgpr_32 = V_MOV_B32_e32 0, implicit $exec\l  S_CMP_EQ_U32 %0:sreg_32, 0, implicit-def $scc\l  S_CBRANCH_SCC1 %bb.1, implicit $scc\l  S_BRANCH %bb.2\l}"];
+# MCFG-NEXT: Node{{[0-9A-Za-z]*}} -> Node{{[0-9A-Za-z]*}};
+# MCFG-NEXT: Node{{[0-9A-Za-z]*}} -> Node{{[0-9A-Za-z]*}};
+# MCFG-NEXT: Node{{[0-9A-Za-z]*}} [shape=record,label="{%bb.1:bb.1:\l\l  successors: %bb.3(0x80000000)\l\l  %3:vgpr_32 = PHI %2:vgpr_32, %bb.0, %4:vgpr_32, %bb.5\l  %5:vgpr_32 = V_ADD_U32_e64 %3:vgpr_32, 1, 0, implicit $exec\l  S_BRANCH %bb.3\l}"];
+# MCFG-NEXT: Node{{[0-9A-Za-z]*}} -> Node{{[0-9A-Za-z]*}};
+# MCFG-NEXT: Node{{[0-9A-Za-z]*}} [shape=record,label="{%bb.2:bb.2:\l\l  successors: %bb.3(0x80000000)\l\l  %6:vgpr_32 = PHI %2:vgpr_32, %bb.0, %4:vgpr_32, %bb.4\l  %7:vgpr_32 = V_ADD_U32_e64 %6:vgpr_32, 2, 0, implicit $exec\l}"];
+# MCFG-NEXT: Node{{[0-9A-Za-z]*}} -> Node{{[0-9A-Za-z]*}};
+# MCFG-NEXT: Node{{[0-9A-Za-z]*}} [shape=record,label="{%bb.3:bb.3:\l\l  successors: %bb.4(0x80000000)\l\l  %4:vgpr_32 = PHI %5:vgpr_32, %bb.1, %7:vgpr_32, %bb.2\l}"];
+# MCFG-NEXT: Node{{[0-9A-Za-z]*}} -> Node{{[0-9A-Za-z]*}};
+# MCFG-NEXT: Node{{[0-9A-Za-z]*}} [shape=record,label="{%bb.4:bb.4:\l\l  successors: %bb.2(0x40000000), %bb.5(0x40000000)\l\l  %8:vgpr_32 = V_AND_B32_e32 3, %1:vgpr_32, implicit $exec\l  %9:sreg_64 = V_CMP_EQ_U32_e64 %8:vgpr_32, 2, implicit $exec\l  %10:sreg_64 = SI_IF killed %9:sreg_64, %bb.2, implicit-def dead $exec,\l... implicit-def dead $scc, implicit $exec\l}"];
+# MCFG-NEXT: Node{{[0-9A-Za-z]*}} -> Node{{[0-9A-Za-z]*}};
+# MCFG-NEXT: Node{{[0-9A-Za-z]*}} -> Node{{[0-9A-Za-z]*}};
+# MCFG-NEXT: Node{{[0-9A-Za-z]*}} [shape=record,label="{%bb.5:bb.5:\l\l  successors: %bb.1(0x40000000), %bb.6(0x40000000)\l\l  %11:sreg_64 = V_CMP_EQ_U32_e64 %8:vgpr_32, 1, implicit $exec\l  %12:sreg_64 = SI_IF killed %11:sreg_64, %bb.1, implicit-def dead $exec,\l... implicit-def dead $scc, implicit $exec\l}"];
+# MCFG-NEXT: Node{{[0-9A-Za-z]*}} -> Node{{[0-9A-Za-z]*}};
+# MCFG-NEXT: Node{{[0-9A-Za-z]*}} -> Node{{[0-9A-Za-z]*}};
+# MCFG-NEXT: Node{{[0-9A-Za-z]*}} [shape=record,label="{%bb.6:bb.6:\l\l\l  S_ENDPGM 0\l}"];
+
+# MCFG-ONLY: digraph "Machine CFG for 'irreducible' function"
+# MCFG-ONLY-NEXT: label="Machine CFG for 'irreducible' function"
+# MCFG-ONLY: Node{{[0-9A-Za-z]*}} [shape=record,label="{%bb.0}"];
+# MCFG-ONLY-NEXT: Node{{[0-9A-Za-z]*}} -> Node{{[0-9A-Za-z]*}};
+# MCFG-ONLY-NEXT: Node{{[0-9A-Za-z]*}} -> Node{{[0-9A-Za-z]*}};
+# MCFG-ONLY-NEXT: Node{{[0-9A-Za-z]*}} [shape=record,label="{%bb.1}"];
+# MCFG-ONLY-NEXT: Node{{[0-9A-Za-z]*}} -> Node{{[0-9A-Za-z]*}};
+# MCFG-ONLY-NEXT: Node{{[0-9A-Za-z]*}} [shape=record,label="{%bb.2}"];
+# MCFG-ONLY-NEXT: Node{{[0-9A-Za-z]*}} -> Node{{[0-9A-Za-z]*}};
+# MCFG-ONLY-NEXT: Node{{[0-9A-Za-z]*}} [shape=record,label="{%bb.3}"];
+# MCFG-ONLY-NEXT: Node{{[0-9A-Za-z]*}} -> Node{{[0-9A-Za-z]*}};
+# MCFG-ONLY-NEXT: Node{{[0-9A-Za-z]*}} [shape=record,label="{%bb.4}"];
+# MCFG-ONLY-NEXT: Node{{[0-9A-Za-z]*}} -> Node{{[0-9A-Za-z]*}};
+# MCFG-ONLY-NEXT: Node{{[0-9A-Za-z]*}} -> Node{{[0-9A-Za-z]*}};
+# MCFG-ONLY-NEXT: Node{{[0-9A-Za-z]*}} [shape=record,label="{%bb.5}"];
+# MCFG-ONLY-NEXT: Node{{[0-9A-Za-z]*}} -> Node{{[0-9A-Za-z]*}};
+# MCFG-ONLY-NEXT: Node{{[0-9A-Za-z]*}} -> Node{{[0-9A-Za-z]*}};
+# MCFG-ONLY-NEXT: Node{{[0-9A-Za-z]*}} [shape=record,label="{%bb.6}"];
+---
+name:            irreducible
+tracksRegLiveness: true
+machineFunctionInfo:
+  isEntryFunction: true
+body:             |
+  bb.0:
+    successors: %bb.1, %bb.2
+    liveins: $vgpr0, $vgpr1, $vgpr2, $sgpr4_sgpr5, $sgpr6_sgpr7, $sgpr8_sgpr9, $sgpr10_sgpr11, $sgpr14, $sgpr15, $sgpr16
+
+    %0:sreg_32 = IMPLICIT_DEF
+    %2:vgpr_32 = COPY $vgpr0
+    %3:vgpr_32 = V_MOV_B32_e32 0, implicit $exec
+    S_CMP_EQ_U32 %0, 0, implicit-def $scc
+    S_CBRANCH_SCC1 %bb.1, implicit $scc
+    S_BRANCH %bb.2
+
+  bb.1:
+    %28:vgpr_32 = PHI %3, %bb.0, %49, %bb.5
+    %29:vgpr_32 = V_ADD_U32_e64 %28, 1, 0, implicit $exec
+    S_BRANCH %bb.3
+
+  bb.2:
+    %38:vgpr_32 = PHI %3, %bb.0, %49, %bb.4
+    %39:vgpr_32 = V_ADD_U32_e64 %38, 2, 0, implicit $exec
+
+  bb.3:
+    %49:vgpr_32 = PHI %29, %bb.1, %39, %bb.2
+
+  bb.4:
+    successors: %bb.2, %bb.5
+
+    %50:vgpr_32 = V_AND_B32_e32 3, %2, implicit $exec
+    %51:sreg_64 = V_CMP_EQ_U32_e64 %50, 2, implicit $exec
+    %52:sreg_64 = SI_IF killed %51:sreg_64, %bb.2, implicit-def dead $exec, implicit-def dead $scc, implicit $exec
+
+  bb.5:
+    successors: %bb.1, %bb.6
+    %61:sreg_64 = V_CMP_EQ_U32_e64 %50, 1, implicit $exec
+    %62:sreg_64 = SI_IF killed %61:sreg_64, %bb.1, implicit-def dead $exec, implicit-def dead $scc, implicit $exec
+
+  bb.6:
+    S_ENDPGM 0
+...
+

diff  --git a/llvm/test/Analysis/DotMachineCFG/AMDGPU/lit.local.cfg b/llvm/test/Analysis/DotMachineCFG/AMDGPU/lit.local.cfg
new file mode 100644
index 0000000000000..2a665f06be72e
--- /dev/null
+++ b/llvm/test/Analysis/DotMachineCFG/AMDGPU/lit.local.cfg
@@ -0,0 +1,2 @@
+if not 'AMDGPU' in config.root.targets:
+    config.unsupported = True


        


More information about the llvm-commits mailing list