Skip to content

Commit

Permalink
IR: Support parsing numeric block ids, and emit them in textual output.
Browse files Browse the repository at this point in the history
Just as as llvm IR supports explicitly specifying numeric value ids
for instructions, and emits them by default in textual output, now do
the same for blocks.

This is a slightly incompatible change in the textual IR format.

Previously, llvm would parse numeric labels as string names. E.g.
  define void @f() {
    br label %"55"
  55:
    ret void
  }
defined a label *named* "55", even without needing to be quoted, while
the reference required quoting. Now, if you intend a block label which
looks like a value number to be a name, you must quote it in the
definition too (e.g. `"55":`).

Previously, llvm would print nameless blocks only as a comment, and
would omit it if there was no predecessor. This could cause confusion
for readers of the IR, just as unnamed instructions did prior to the
addition of "%5 = " syntax, back in 2008 (PR2480).

Now, it will always print a label for an unnamed block, with the
exception of the entry block. (IMO it may be better to print it for
the entry-block as well. However, that requires updating many more
tests.)

Thus, the following is supported, and is the canonical printing:
  define i32 @f(i32, i32) {
    %3 = add i32 %0, %1
    br label %4

  4:
    ret i32 %3
  }

New test cases covering this behavior are added, and other tests
updated as required.

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

llvm-svn: 356789
  • Loading branch information
jyknight committed Mar 22, 2019
1 parent 5e381fb commit c0e6b8a
Show file tree
Hide file tree
Showing 38 changed files with 368 additions and 282 deletions.
4 changes: 2 additions & 2 deletions clang/test/CodeGenCXX/discard-name-values.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ bool test(bool pred) {
// CHECK: br i1 %pred, label %if.then, label %if.end

if (pred) {
// DISCARDVALUE: ; <label>:2:
// DISCARDVALUE: 2:
// DISCARDVALUE-NEXT: tail call void @branch()
// DISCARDVALUE-NEXT: br label %3

Expand All @@ -20,7 +20,7 @@ bool test(bool pred) {
branch();
}

// DISCARDVALUE: ; <label>:3:
// DISCARDVALUE: 3:
// DISCARDVALUE-NEXT: ret i1 %0

// CHECK: if.end:
Expand Down
2 changes: 1 addition & 1 deletion llgo/test/irgen/imports.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ var X interface{}
// CHECK-NEXT: %[[N:.*]] = load i1, i1* @"init$guard"
// CHECK-NEXT: br i1 %[[N]], label %{{.*}}, label %[[L:.*]]

// CHECK: ; <label>:[[L]]
// CHECK: [[L]]:
// CHECK-NEXT: call void @__go_register_gc_roots
// CHECK-NEXT: store i1 true, i1* @"init$guard"
// CHECK-NEXT: call void @fmt..import(i8* undef)
Expand Down
12 changes: 7 additions & 5 deletions llvm/docs/LangRef.rst
Original file line number Diff line number Diff line change
Expand Up @@ -741,11 +741,13 @@ A function definition contains a list of basic blocks, forming the CFG (Control
Flow Graph) for the function. Each basic block may optionally start with a label
(giving the basic block a symbol table entry), contains a list of instructions,
and ends with a :ref:`terminator <terminators>` instruction (such as a branch or
function return). If an explicit label is not provided, a block is assigned an
implicit numbered label, using the next value from the same counter as used for
unnamed temporaries (:ref:`see above<identifiers>`). For example, if a function
entry block does not have an explicit label, it will be assigned label "%0",
then the first unnamed temporary in that block will be "%1", etc.
function return). If an explicit label name is not provided, a block is assigned
an implicit numbered label, using the next value from the same counter as used
for unnamed temporaries (:ref:`see above<identifiers>`). For example, if a
function entry block does not have an explicit label, it will be assigned label
"%0", then the first unnamed temporary in that block will be "%1", etc. If a
numeric label is explicitly specified, it must match the numeric label that
would be used implicitly.

The first basic block in a function is special in two ways: it is
immediately executed on entrance to the function, and it is not allowed
Expand Down
12 changes: 11 additions & 1 deletion llvm/lib/AsmParser/LLLexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1048,7 +1048,17 @@ lltok::Kind LLLexer::LexDigitOrNegative() {
for (; isdigit(static_cast<unsigned char>(CurPtr[0])); ++CurPtr)
/*empty*/;

// Check to see if this really is a label afterall, e.g. "-1:".
// Check if this is a fully-numeric label:
if (isdigit(TokStart[0]) && CurPtr[0] == ':') {
uint64_t Val = atoull(TokStart, CurPtr);
++CurPtr; // Skip the colon.
if ((unsigned)Val != Val)
Error("invalid value number (too large)!");
UIntVal = unsigned(Val);
return lltok::LabelID;
}

// Check to see if this really is a string label, e.g. "-1:".
if (isLabelChar(CurPtr[0]) || CurPtr[0] == ':') {
if (const char *End = isLabelTail(CurPtr)) {
StrVal.assign(TokStart, End-1);
Expand Down
33 changes: 25 additions & 8 deletions llvm/lib/AsmParser/LLParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2926,13 +2926,27 @@ BasicBlock *LLParser::PerFunctionState::GetBB(unsigned ID, LocTy Loc) {
/// unnamed. If there is an error, this returns null otherwise it returns
/// the block being defined.
BasicBlock *LLParser::PerFunctionState::DefineBB(const std::string &Name,
LocTy Loc) {
int NameID, LocTy Loc) {
BasicBlock *BB;
if (Name.empty())
if (Name.empty()) {
if (NameID != -1 && unsigned(NameID) != NumberedVals.size()) {
P.Error(Loc, "label expected to be numbered '" +
Twine(NumberedVals.size()) + "'");
return nullptr;
}
BB = GetBB(NumberedVals.size(), Loc);
else
if (!BB) {
P.Error(Loc, "unable to create block numbered '" +
Twine(NumberedVals.size()) + "'");
return nullptr;
}
} else {
BB = GetBB(Name, Loc);
if (!BB) return nullptr; // Already diagnosed error.
if (!BB) {
P.Error(Loc, "unable to create block named '" + Name + "'");
return nullptr;
}
}

// Move the block to the end of the function. Forward ref'd blocks are
// inserted wherever they happen to be referenced.
Expand Down Expand Up @@ -5489,20 +5503,23 @@ bool LLParser::ParseFunctionBody(Function &Fn) {
}

/// ParseBasicBlock
/// ::= LabelStr? Instruction*
/// ::= (LabelStr|LabelID)? Instruction*
bool LLParser::ParseBasicBlock(PerFunctionState &PFS) {
// If this basic block starts out with a name, remember it.
std::string Name;
int NameID = -1;
LocTy NameLoc = Lex.getLoc();
if (Lex.getKind() == lltok::LabelStr) {
Name = Lex.getStrVal();
Lex.Lex();
} else if (Lex.getKind() == lltok::LabelID) {
NameID = Lex.getUIntVal();
Lex.Lex();
}

BasicBlock *BB = PFS.DefineBB(Name, NameLoc);
BasicBlock *BB = PFS.DefineBB(Name, NameID, NameLoc);
if (!BB)
return Error(NameLoc,
"unable to create block named '" + Name + "'");
return true;

std::string NameStr;

Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/AsmParser/LLParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ namespace llvm {
/// DefineBB - Define the specified basic block, which is either named or
/// unnamed. If there is an error, this returns null otherwise it returns
/// the block being defined.
BasicBlock *DefineBB(const std::string &Name, LocTy Loc);
BasicBlock *DefineBB(const std::string &Name, int NameID, LocTy Loc);

bool resolveForwardRefBlockAddresses();
};
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/AsmParser/LLToken.h
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,7 @@ enum Kind {
kw_varFlags,

// Unsigned Valued tokens (UIntVal).
LabelID, // 42:
GlobalID, // @42
LocalVarID, // %42
AttrGrpID, // #42
Expand Down
9 changes: 5 additions & 4 deletions llvm/lib/IR/AsmWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3482,23 +3482,24 @@ void AssemblyWriter::printArgument(const Argument *Arg, AttributeSet Attrs) {

/// printBasicBlock - This member is called for each basic block in a method.
void AssemblyWriter::printBasicBlock(const BasicBlock *BB) {
bool IsEntryBlock = BB == &BB->getParent()->getEntryBlock();
if (BB->hasName()) { // Print out the label if it exists...
Out << "\n";
PrintLLVMName(Out, BB->getName(), LabelPrefix);
Out << ':';
} else if (!BB->use_empty()) { // Don't print block # of no uses...
Out << "\n; <label>:";
} else if (!IsEntryBlock) {
Out << "\n";
int Slot = Machine.getLocalSlot(BB);
if (Slot != -1)
Out << Slot << ":";
else
Out << "<badref>";
Out << "<badref>:";
}

if (!BB->getParent()) {
Out.PadToColumn(50);
Out << "; Error: Block without parent!";
} else if (BB != &BB->getParent()->getEntryBlock()) { // Not the entry block?
} else if (!IsEntryBlock) {
// Output predecessors for the block.
Out.PadToColumn(50);
Out << ";";
Expand Down
58 changes: 29 additions & 29 deletions llvm/test/Analysis/DominanceFrontier/new_pm_test.ll
Original file line number Diff line number Diff line change
Expand Up @@ -3,48 +3,48 @@

define void @a_linear_impl_fig_1() nounwind {
0:
br label %"1"
br label %1
1:
br label %"2"
br label %2
2:
br label %"3"
br label %3
3:
br i1 1, label %"13", label %"4"
br i1 1, label %12, label %4
4:
br i1 1, label %"5", label %"1"
br i1 1, label %5, label %1
5:
br i1 1, label %"8", label %"6"
br i1 1, label %8, label %6
6:
br i1 1, label %"7", label %"4"
br i1 1, label %7, label %4
7:
ret void
8:
br i1 1, label %"9", label %"1"
br i1 1, label %9, label %1
9:
br label %"10"
br label %10
10:
br i1 1, label %"12", label %"11"
br i1 1, label %13, label %11
11:
br i1 1, label %"9", label %"8"
13:
br i1 1, label %"2", label %"1"
br i1 1, label %9, label %8
12:
switch i32 0, label %"1" [ i32 0, label %"9"
i32 1, label %"8"]
br i1 1, label %2, label %1
13:
switch i32 0, label %1 [ i32 0, label %9
i32 1, label %8]
}

; CHECK: DominanceFrontier for function: a_linear_impl_fig_1
; CHECK-DAG: DomFrontier for BB %"0" is:
; CHECK-DAG: DomFrontier for BB %"11" is: %"{{[8|9]}}" %"{{[8|9]}}"
; CHECK-DAG: DomFrontier for BB %"1" is: %"1"
; CHECK-DAG: DomFrontier for BB %"2" is: %"{{[1|2]}}" %"{{[1|2]}}"
; CHECK-DAG: DomFrontier for BB %"3" is: %"{{[1|2]}}" %"{{[1|2]}}"
; CHECK-DAG: DomFrontier for BB %"13" is: %"{{[1|2]}}" %"{{[1|2]}}"
; CHECK-DAG: DomFrontier for BB %"4" is: %"{{[1|4]}}" %"{{[1|4]}}"
; CHECK-DAG: DomFrontier for BB %"5" is: %"{{[1|4]}}" %"{{[1|4]}}"
; CHECK-DAG: DomFrontier for BB %"8" is: %"{{[1|8]}}" %"{{[1|8]}}"
; CHECK-DAG: DomFrontier for BB %"6" is: %"4"
; CHECK-DAG: DomFrontier for BB %"7" is:
; CHECK-DAG: DomFrontier for BB %"9" is: %"{{[1|8|9]}}" %"{{[1|8|9]}}" %"{{[1|8|9]}}"
; CHECK-DAG: DomFrontier for BB %"10" is: %"{{[1|8|9]}}" %"{{[1|8|9]}}" %"{{[1|8|9]}}"
; CHECK-DAG: DomFrontier for BB %"12" is: %"{{[1|8|9]}}" %"{{[1|8|9]}}" %"{{[1|8|9]}}"
; CHECK-DAG: DomFrontier for BB %0 is:
; CHECK-DAG: DomFrontier for BB %11 is: %{{[8|9]}} %{{[8|9]}}
; CHECK-DAG: DomFrontier for BB %1 is: %1
; CHECK-DAG: DomFrontier for BB %2 is: %{{[1|2]}} %{{[1|2]}}
; CHECK-DAG: DomFrontier for BB %3 is: %{{[1|2]}} %{{[1|2]}}
; CHECK-DAG: DomFrontier for BB %12 is: %{{[1|2]}} %{{[1|2]}}
; CHECK-DAG: DomFrontier for BB %4 is: %{{[1|4]}} %{{[1|4]}}
; CHECK-DAG: DomFrontier for BB %5 is: %{{[1|4]}} %{{[1|4]}}
; CHECK-DAG: DomFrontier for BB %8 is: %{{[1|8]}} %{{[1|8]}}
; CHECK-DAG: DomFrontier for BB %6 is: %4
; CHECK-DAG: DomFrontier for BB %7 is:
; CHECK-DAG: DomFrontier for BB %9 is: %{{[1|8|9]}} %{{[1|8|9]}} %{{[1|8|9]}}
; CHECK-DAG: DomFrontier for BB %10 is: %{{[1|8|9]}} %{{[1|8|9]}} %{{[1|8|9]}}
; CHECK-DAG: DomFrontier for BB %13 is: %{{[1|8|9]}} %{{[1|8|9]}} %{{[1|8|9]}}
12 changes: 6 additions & 6 deletions llvm/test/Analysis/RegionInfo/cond_loop.ll
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,18 @@
; RUN: opt < %s -passes='print<regions>' 2>&1 | FileCheck %s

define void @normal_condition() nounwind {
5:
"5":
br label %"0"

0:
"0":
br label %"1"
1:
"1":
br i1 1, label %"2", label %"3"
2:
"2":
ret void
3:
"3":
br i1 1, label %"1", label %"4"
4:
"4":
br label %"0"
}

Expand Down
8 changes: 4 additions & 4 deletions llvm/test/Analysis/RegionInfo/condition_forward_edge.ll
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@
; RUN: opt < %s -passes='print<regions>' 2>&1 | FileCheck %s

define void @normal_condition() nounwind {
0:
"0":
br label %"1"
1:
"1":
br i1 1, label %"2", label %"3"
2:
"2":
br label %"3"
3:
"3":
ret void
}
; CHECK-NOT: =>
Expand Down
10 changes: 5 additions & 5 deletions llvm/test/Analysis/RegionInfo/condition_same_exit.ll
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@
; RUN: opt < %s -passes='print<regions>' 2>&1 | FileCheck %s

define void @normal_condition() nounwind {
0:
"0":
br i1 1, label %"1", label %"4"

1:
"1":
br i1 1, label %"2", label %"3"
2:
"2":
br label %"4"
3:
"3":
br label %"4"
4:
"4":
ret void
}
; CHECK-NOT: =>
Expand Down
10 changes: 5 additions & 5 deletions llvm/test/Analysis/RegionInfo/condition_simple.ll
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@
; RUN: opt < %s -passes='print<regions>' 2>&1 | FileCheck %s

define void @normal_condition() nounwind {
0:
"0":
br label %"1"
1:
"1":
br i1 1, label %"2", label %"3"
2:
"2":
br label %"4"
3:
"3":
br label %"4"
4:
"4":
ret void
}

Expand Down
10 changes: 5 additions & 5 deletions llvm/test/Analysis/RegionInfo/infinite_loop.ll
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@

define void @normal_condition() nounwind {
0:
br label %"1"
br label %1
1:
br i1 1, label %"2", label %"3"
br i1 1, label %2, label %3
2:
br label %"2"
br label %2
3:
br label %"4"
br label %4
4:
ret void
}
; CHECK-NOT: =>
; CHECK: [0] 0 => <Function Return>
; STAT: 1 region - The # of regions
; STAT: 1 region - The # of regions
18 changes: 9 additions & 9 deletions llvm/test/Analysis/RegionInfo/infinite_loop_2.ll
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,23 @@
; RUN: opt -regions -print-region-style=rn -analyze < %s 2>&1 | FileCheck -check-prefix=RNIT %s

define void @normal_condition() nounwind {
0:
"0":
br label %"1"
1:
"1":
br i1 1, label %"2", label %"3"
2:
"2":
br label %"5"
5:
"5":
br i1 1, label %"11", label %"12"
11:
"11":
br label %"6"
12:
"12":
br label %"6"
6:
"6":
br label %"2"
3:
"3":
br label %"4"
4:
"4":
ret void
}
; CHECK-NOT: =>
Expand Down
Loading

0 comments on commit c0e6b8a

Please sign in to comment.