diff --git a/llvm/include/llvm/Analysis/CFGPrinter.h b/llvm/include/llvm/Analysis/CFGPrinter.h --- a/llvm/include/llvm/Analysis/CFGPrinter.h +++ b/llvm/include/llvm/Analysis/CFGPrinter.h @@ -119,81 +119,96 @@ } }; +template +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 +std::string CompleteNodeLabelString( + const BasicBlockT *Node, + function_ref + HandleBasicBlock, + function_ref + 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 : public DefaultDOTGraphTraits { // Cache for is hidden property - llvm::DenseMap isOnDeoptOrUnreachablePath; + DenseMap 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 + function_ref HandleBasicBlock = [](raw_string_ostream &OS, const BasicBlock &Node) -> void { OS << Node; }, - llvm::function_ref + function_ref 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 --- /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 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 + : public GraphTraits { + 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; + + 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 : 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 + HandleBasicBlock = + [](raw_string_ostream &OS, + const MachineBasicBlock &Node) -> void { OS << Node; }, + function_ref + 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 --- a/llvm/include/llvm/CodeGen/MachinePassRegistry.def +++ b/llvm/include/llvm/CodeGen/MachinePassRegistry.def @@ -159,6 +159,7 @@ 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 --- a/llvm/include/llvm/CodeGen/Passes.h +++ b/llvm/include/llvm/CodeGen/Passes.h @@ -408,6 +408,9 @@ /// 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 --- a/llvm/include/llvm/InitializePasses.h +++ b/llvm/include/llvm/InitializePasses.h @@ -277,6 +277,7 @@ 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 --- a/llvm/lib/CodeGen/CMakeLists.txt +++ b/llvm/lib/CodeGen/CMakeLists.txt @@ -101,6 +101,7 @@ 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 --- a/llvm/lib/CodeGen/CodeGen.cpp +++ b/llvm/lib/CodeGen/CodeGen.cpp @@ -69,6 +69,7 @@ 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 --- /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 `..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 + MCFGFuncName("mcfg-func-name", cl::Hidden, + cl::desc("The name of a function (or its substring)" + " whose CFG is viewed/printed.")); + +static cl::opt MCFGDotFilenamePrefix( + "mcfg-dot-filename-prefix", cl::Hidden, + cl::desc("The prefix used for the Machine CFG dot file names.")); + +static cl::opt + 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 --- /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 --- /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 --- /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