Bug fix for multi-line labels in CFG dot graph

After D154102 multi-line labels would get split incorrectly.
When CFG is generated for a function with basic block name longer
than 80 lines, then the header separator will be placed after the
line break for the label name instead of after the whole label name.
The fix is simple by just moving the insert of | character before the
line splitting happens.

Differential Revision: https://reviews.llvm.org/D159207
This commit is contained in:
Marek Sedláček
2023-09-05 19:03:59 -07:00
committed by Artur Pilipenko
parent 976dbae246
commit ebf01690d9
6 changed files with 35 additions and 19 deletions

View File

@@ -153,6 +153,8 @@ std::string CompleteNodeLabelString(
if (OutStr[0] == '%') {
OutStr.erase(OutStr.begin());
}
// Place | after BB name to separate it into header
OutStr.insert(OutStr.find_first_of('\n') + 1, "\\|");
unsigned ColNum = 0;
unsigned LastSpace = 0;
@@ -178,8 +180,6 @@ std::string CompleteNodeLabelString(
if (OutStr[i] == ' ')
LastSpace = i;
}
// Replace \l after BB name with | to separate it into header
OutStr.replace(OutStr.find_first_of('\\') + 1, 1, "|");
return OutStr;
}

View File

@@ -12,7 +12,7 @@ body: |
# 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:| $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}"];
# MCFG: Node{{[0-9A-Za-z]*}} [shape=record,label="{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: |

View File

@@ -5,22 +5,22 @@
# 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:| 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: Node{{[0-9A-Za-z]*}} [shape=record,label="{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:|\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]*}} [shape=record,label="{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:|\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]*}} [shape=record,label="{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:|\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]*}} [shape=record,label="{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:|\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]*}} [shape=record,label="{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:|\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]*}} [shape=record,label="{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:|\l\l S_ENDPGM 0\l}"];
# MCFG-NEXT: Node{{[0-9A-Za-z]*}} [shape=record,label="{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"

View File

@@ -0,0 +1,16 @@
; RUN: opt < %s -passes=dot-cfg -cfg-dot-filename-prefix=cfg 2>/dev/null > /dev/null
; RUN: FileCheck %s -input-file=cfg.foo.dot --check-prefix=CHECK
define void @foo(ptr %A, ptr %B) {
a_very_long_label_that_should_take_over_eight_symbols_and_span_2_lines_in_cfg_dot_graph:
; CHECK: label="{a_very_long_label_that_should_take_over_eight_symbols_and_span_2_lines_in_cfg_do\l...t_graph:\l| store i32 1, ptr %A, align 4\l store i32 2, ptr %B, align 4\l br label %short_label\l}"
store i32 1, ptr %A
store i32 2, ptr %B
br label %short_label
short_label:
; CHECK: label="{short_label:\l| br label\l... %an_even_longer_multiline_label_that_will_span_muliple_lines_Lorem_ipsum_dolor\l..._sit_amet_consectetur_adipiscing_elit_sed_do_eiusmod_tempor_incididunt_ut_labor\l...e_et_dolore_magna_aliqua\l}"
br label %an_even_longer_multiline_label_that_will_span_muliple_lines_Lorem_ipsum_dolor_sit_amet_consectetur_adipiscing_elit_sed_do_eiusmod_tempor_incididunt_ut_labore_et_dolore_magna_aliqua
an_even_longer_multiline_label_that_will_span_muliple_lines_Lorem_ipsum_dolor_sit_amet_consectetur_adipiscing_elit_sed_do_eiusmod_tempor_incididunt_ut_labore_et_dolore_magna_aliqua:
; CHECK: label="{an_even_longer_multiline_label_that_will_span_muliple_lines_Lorem_ipsum_dolor_si\l...t_amet_consectetur_adipiscing_elit_sed_do_eiusmod_tempor_incididunt_ut_labore_e\l...t_dolore_magna_aliqua:\l| ret void\l}"
ret void
}

View File

@@ -14,18 +14,18 @@ declare i8 @llvm.experimental.deoptimize.i8(...)
define i8 @callee(ptr %c) alwaysinline {
%c0 = load volatile i1, ptr %c
br i1 %c0, label %lleft, label %lright
; NO-FLAGS: label="{lleft:| %v0 = call i8 (...) @llvm.experimental.deoptimize.i8(i32 1) [ \"deopt\"(i32 1)\l... ]\l ret i8 %v0\l}"
; DEOPT-NOT: label="{lleft:| %v0 = call i8 (...) @llvm.experimental.deoptimize.i8(i32 1) [ \"deopt\"(i32 1)\l... ]\l ret i8 %v0\l}"
; UNREACH: label="{lleft:| %v0 = call i8 (...) @llvm.experimental.deoptimize.i8(i32 1) [ \"deopt\"(i32 1)\l... ]\l ret i8 %v0\l}"
; BOTH-FLAGS-NOT: label="{lleft:| %v0 = call i8 (...) @llvm.experimental.deoptimize.i8(i32 1) [ \"deopt\"(i32 1)\l... ]\l ret i8 %v0\l}"
; NO-FLAGS: label="{lleft:\l| %v0 = call i8 (...) @llvm.experimental.deoptimize.i8(i32 1) [ \"deopt\"(i32\l... 1) ]\l ret i8 %v0\l}"
; DEOPT-NOT: label="{lleft:\l| %v0 = call i8 (...) @llvm.experimental.deoptimize.i8(i32 1) [ \"deopt\"(i32\l... 1) ]\l ret i8 %v0\l}"
; UNREACH: label="{lleft:\l| %v0 = call i8 (...) @llvm.experimental.deoptimize.i8(i32 1) [ \"deopt\"(i32\l... 1) ]\l ret i8 %v0\l}"
; BOTH-FLAGS-NOT: label="{lleft:\l| %v0 = call i8 (...) @llvm.experimental.deoptimize.i8(i32 1) [ \"deopt\"(i32\l... 1) ]\l ret i8 %v0\l}"
lleft:
%v0 = call i8(...) @llvm.experimental.deoptimize.i8(i32 1) [ "deopt"(i32 1) ]
ret i8 %v0
; NO-FLAGS: label="{lright:| unreachable\l}"
; DEOPT: label="{lright:| unreachable\l}"
; UNREACH-NOT: label="{lright:| unreachable\l}"
; BOTH-FLAGS-NOT: label="{lright:| unreachable\l}"
; NO-FLAGS: label="{lright:\l| unreachable\l}"
; DEOPT: label="{lright:\l| unreachable\l}"
; UNREACH-NOT: label="{lright:\l| unreachable\l}"
; BOTH-FLAGS-NOT: label="{lright:\l| unreachable\l}"
lright:
unreachable
}

View File

@@ -15,7 +15,7 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
define void @func_npm(i32 %n, i32 %m, ptr noalias nonnull %A) {
; CHECK: digraph "Scop Graph for 'func_npm' function"
; CHECK-NEXT: label="Scop Graph for 'func_npm' function"
; CHECK: Node0x[[EntryID:.*]] [shape=record,label="{entry:| br label %outer.for\l}"];
; CHECK: Node0x[[EntryID:.*]] [shape=record,label="{entry:\l| br label %outer.for\l}"];
; CHECK-NEXT: Node0x[[EntryID]] -> Node0x[[OUTER_FOR_ID:.*]];
; CHECK-NEXT: Node0x[[OUTER_FOR_ID]] [shape=record,label="{outer.for:
; CHECK-NEXT: Node0x[[OUTER_FOR_ID]] -> Node0x[[INNER_FOR_ID:.*]];