Homogenize branch instruction arguments.

Branch instruction arguments were defined and used inconsistently across
different instructions, in both the spec and the implementation.  In
particular, conditional and unconditional branch instructions were using
different syntax in the implementation.  This led to the IR we produce not
being accepted by the parser. Update the printer to use common syntax: `(`
list-of-SSA-uses `:` list-of-types `)`.  The motivation for choosing this
syntax as opposed to the one in the spec, `(` list-of-SSA-uses `)` `:`
list-of-types is double-fold.  First, it is tricky to differentiate the label
of the false branch from the type while parsing conditional branches (which is
what apparently motivated the implementation to diverge from the spec in the
first place).  Second, the ongoing convergence between terminator instructions
and other operations prompts for consistency between their operand list syntax.
After this change, the only remaining difference between the two is the use of
parentheses.  Update the comment of the parser that did not correspond to the
code.  Remove the unused isParenthesized argument from parseSSAUseAndTypeList.

Update the spec accordingly.  Note that the examples in the spec were _not_
using the EBNF defined a couple of lines above them, but were using the current
syntax.  Add a supplementary example of a branch to a basic block with multiple
arguments.

PiperOrigin-RevId: 221162655
This commit is contained in:
Alex Zinenko 2018-11-12 14:58:53 -08:00 committed by jpienaar
parent 5a0d3d0204
commit cab24dc211
4 changed files with 53 additions and 68 deletions

View File

@ -975,8 +975,13 @@ bb2:
br bb3(%b: i64) // Branch passes %b as the argument
// bb3 receives an argument, named %c, from predecessors
// and passes it on to bb4 twice.
bb3(%c: i64):
return %c : i64
br bb4(%c, %c : i64, i64)
bb4(%d : i64, %e : i64):
%0 = addi %d, %e : i64
return %0 : i64
}
```
@ -1004,7 +1009,7 @@ Syntax:
``` {.ebnf}
terminator-stmt ::= `br` bb-id branch-use-list?
branch-use-list ::= `(` ssa-use-list `)` `:` type-list-no-parens
branch-use-list ::= `(` ssa-use-list `:` type-list-no-parens `)`
```
The `br` terminator statement represents an unconditional jump to a target basic
@ -1039,7 +1044,7 @@ instruction that targets the same basic block:
cfgfunc @select(%a : i32, %b :i32, %flag : i1) -> i32 {
bb0:
// Both targets are the same, operands differ
cond_br %flag : i1, bb1 (%a : i32), bb1 (%b : i32)
cond_br %flag, bb1 (%a : i32), bb1 (%b : i32)
bb1 (%x : i32) :
return %x : i32

View File

@ -35,6 +35,7 @@
#include "mlir/Support/STLExtras.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSet.h"
@ -1180,6 +1181,8 @@ private:
DenseMap<const BasicBlock *, unsigned> basicBlockIDs;
void numberValuesInBlock(const BasicBlock *block);
template <typename Range> void printBranchOperands(const Range &range);
};
} // end anonymous namespace
@ -1290,19 +1293,28 @@ void CFGFunctionPrinter::print(const OperationInst *inst) {
printOperation(inst);
}
// Print the operands from "container" to "os", followed by a colon and their
// respective types, everything in parentheses. Do nothing if the container is
// empty.
template <typename Range>
void CFGFunctionPrinter::printBranchOperands(const Range &range) {
if (llvm::empty(range))
return;
os << '(';
interleaveComma(range,
[this](const CFGValue *operand) { printValueID(operand); });
os << " : ";
interleaveComma(range, [this](const CFGValue *operand) {
printType(operand->getType());
});
os << ')';
}
void CFGFunctionPrinter::print(const BranchInst *inst) {
os << "br ";
printBBName(inst->getDest());
if (inst->getNumOperands() != 0) {
os << '(';
interleaveComma(inst->getOperands(),
[&](const CFGValue *operand) { printValueID(operand); });
os << ") : ";
interleaveComma(inst->getOperands(), [&](const CFGValue *operand) {
printType(operand->getType());
});
}
printBranchOperands(inst->getOperands());
}
void CFGFunctionPrinter::print(const CondBranchInst *inst) {
@ -1311,29 +1323,11 @@ void CFGFunctionPrinter::print(const CondBranchInst *inst) {
os << ", ";
printBBName(inst->getTrueDest());
if (inst->getNumTrueOperands() != 0) {
os << '(';
interleaveComma(inst->getTrueOperands(),
[&](const CFGValue *operand) { printValueID(operand); });
os << " : ";
interleaveComma(inst->getTrueOperands(), [&](const CFGValue *operand) {
printType(operand->getType());
});
os << ")";
}
printBranchOperands(inst->getTrueOperands());
os << ", ";
printBBName(inst->getFalseDest());
if (inst->getNumFalseOperands() != 0) {
os << '(';
interleaveComma(inst->getFalseOperands(),
[&](const CFGValue *operand) { printValueID(operand); });
os << " : ";
interleaveComma(inst->getFalseOperands(), [&](const CFGValue *operand) {
printType(operand->getType());
});
os << ")";
}
printBranchOperands(inst->getFalseOperands());
}
void CFGFunctionPrinter::print(const ReturnInst *inst) {

View File

@ -1844,8 +1844,7 @@ public:
template <typename ValueTy>
ParseResult
parseOptionalSSAUseAndTypeList(SmallVectorImpl<ValueTy *> &results,
bool isParenthesized);
parseOptionalSSAUseAndTypeList(SmallVectorImpl<ValueTy *> &results);
// Operations
ParseResult parseOperation(const CreateOperationFunction &createOpFunc);
@ -2060,31 +2059,18 @@ ResultType FunctionParser::parseSSADefOrUseAndType(
}
/// Parse a (possibly empty) list of SSA operands, followed by a colon, then
/// followed by a type list. If hasParens is true, then the operands are
/// surrounded by parens.
/// followed by a type list.
///
/// ssa-use-and-type-list[parens]
/// ::= `(` ssa-use-list `)` ':' type-list-no-parens
///
/// ssa-use-and-type-list[!parens]
/// ssa-use-and-type-list
/// ::= ssa-use-list ':' type-list-no-parens
///
template <typename ValueTy>
ParseResult FunctionParser::parseOptionalSSAUseAndTypeList(
SmallVectorImpl<ValueTy *> &results, bool isParenthesized) {
// If we are in the parenthesized form and no paren exists, then we succeed
// with an empty list.
if (isParenthesized && !consumeIf(Token::l_paren))
return ParseSuccess;
SmallVectorImpl<ValueTy *> &results) {
SmallVector<SSAUseInfo, 4> valueIDs;
if (parseOptionalSSAUseList(valueIDs))
return ParseFailure;
if (isParenthesized && !consumeIf(Token::r_paren))
return emitError("expected ')' in operand list");
// If there were no operands, then there is no colon or type lists.
if (valueIDs.empty())
return ParseSuccess;
@ -2650,7 +2636,7 @@ ParseResult CFGFunctionParser::parseBranchBlockAndUseList(
// Handle optional arguments.
if (consumeIf(Token::l_paren) &&
(parseOptionalSSAUseAndTypeList(values, /*isParenthesized=*/false) ||
(parseOptionalSSAUseAndTypeList(values) ||
parseToken(Token::r_paren, "expected ')' to close argument list"))) {
return ParseFailure;
}
@ -2661,7 +2647,7 @@ ParseResult CFGFunctionParser::parseBranchBlockAndUseList(
/// Parse the terminator instruction for a basic block.
///
/// terminator-stmt ::= `br` bb-id branch-use-list?
/// branch-use-list ::= `(` ssa-use-list `)` ':' type-list-no-parens
/// branch-use-list ::= `(` ssa-use-list ':' type-list-no-parens `)`
/// terminator-stmt ::=
/// `cond_br` ssa-use `,` bb-id branch-use-list? `,` bb-id
/// branch-use-list?
@ -2679,7 +2665,7 @@ TerminatorInst *CFGFunctionParser::parseTerminator() {
// Parse any operands.
SmallVector<CFGValue *, 8> operands;
if (parseOptionalSSAUseAndTypeList(operands, /*isParenthesized=*/false))
if (parseOptionalSSAUseAndTypeList(operands))
return nullptr;
return builder.createReturn(getEncodedSourceLocation(loc), operands);
}

View File

@ -15,7 +15,7 @@ extfunc @body(index) -> ()
// CHECK-NEXT: bb1: // pred: bb0
// CHECK-NEXT: %c1 = constant 1 : index
// CHECK-NEXT: %c42 = constant 42 : index
// CHECK-NEXT: br bb2(%c1) : index
// CHECK-NEXT: br bb2(%c1 : index)
// CHECK-NEXT: bb2(%0: index): // 2 preds: bb1, bb3
// CHECK-NEXT: %1 = cmpi "slt", %0, %c42 : index
// CHECK-NEXT: cond_br %1, bb3, bb4
@ -23,7 +23,7 @@ extfunc @body(index) -> ()
// CHECK-NEXT: call @body(%0) : (index) -> ()
// CHECK-NEXT: %c1_0 = constant 1 : index
// CHECK-NEXT: %2 = addi %0, %c1_0 : index
// CHECK-NEXT: br bb2(%2) : index
// CHECK-NEXT: br bb2(%2 : index)
// CHECK-NEXT: bb4: // pred: bb2
// CHECK-NEXT: return
// CHECK-NEXT: }
@ -78,7 +78,7 @@ extfunc @other(index, i32) -> (i32)
// CHECK-NEXT: bb1: // pred: bb0
// CHECK-NEXT: %c0 = constant 0 : index
// CHECK-NEXT: %c42 = constant 42 : index
// CHECK-NEXT: br bb2(%c0) : index
// CHECK-NEXT: br bb2(%c0 : index)
// CHECK-NEXT: bb2(%0: index): // 2 preds: bb1, bb3
// CHECK-NEXT: %1 = cmpi "slt", %0, %c42 : index
// CHECK-NEXT: cond_br %1, bb3, bb4
@ -89,7 +89,7 @@ extfunc @other(index, i32) -> (i32)
// CHECK-NEXT: %5 = call @other(%2, %arg1) : (index, i32) -> i32
// CHECK-NEXT: %c1 = constant 1 : index
// CHECK-NEXT: %6 = addi %0, %c1 : index
// CHECK-NEXT: br bb2(%6) : index
// CHECK-NEXT: br bb2(%6 : index)
// CHECK-NEXT: bb4: // pred: bb2
// CHECK-NEXT: %c0_0 = constant 0 : index
// CHECK-NEXT: %7 = call @other(%c0_0, %c0_i32) : (index, i32) -> i32
@ -120,7 +120,7 @@ extfunc @post(index) -> ()
// CHECK-NEXT: bb1: // pred: bb0
// CHECK-NEXT: %c0 = constant 0 : index
// CHECK-NEXT: %c42 = constant 42 : index
// CHECK-NEXT: br bb2(%c0) : index
// CHECK-NEXT: br bb2(%c0 : index)
// CHECK-NEXT: bb2(%0: index): // 2 preds: bb1, bb7
// CHECK-NEXT: %1 = cmpi "slt", %0, %c42 : index
// CHECK-NEXT: cond_br %1, bb3, bb8
@ -130,7 +130,7 @@ extfunc @post(index) -> ()
// CHECK-NEXT: bb4: // pred: bb3
// CHECK-NEXT: %c7 = constant 7 : index
// CHECK-NEXT: %c56 = constant 56 : index
// CHECK-NEXT: br bb5(%c7) : index
// CHECK-NEXT: br bb5(%c7 : index)
// CHECK-NEXT: bb5(%2: index): // 2 preds: bb4, bb6
// CHECK-NEXT: %3 = cmpi "slt", %2, %c56 : index
// CHECK-NEXT: cond_br %3, bb6, bb7
@ -138,12 +138,12 @@ extfunc @post(index) -> ()
// CHECK-NEXT: call @body2(%0, %2) : (index, index) -> ()
// CHECK-NEXT: %c2 = constant 2 : index
// CHECK-NEXT: %4 = addi %2, %c2 : index
// CHECK-NEXT: br bb5(%4) : index
// CHECK-NEXT: br bb5(%4 : index)
// CHECK-NEXT: bb7: // pred: bb5
// CHECK-NEXT: call @post(%0) : (index) -> ()
// CHECK-NEXT: %c1 = constant 1 : index
// CHECK-NEXT: %5 = addi %0, %c1 : index
// CHECK-NEXT: br bb2(%5) : index
// CHECK-NEXT: br bb2(%5 : index)
// CHECK-NEXT: bb8: // pred: bb2
// CHECK-NEXT: return
// CHECK-NEXT: }
@ -169,7 +169,7 @@ extfunc @body3(index, index) -> ()
// CHECK-NEXT: bb1: // pred: bb0
// CHECK-NEXT: %c0 = constant 0 : index
// CHECK-NEXT: %c42 = constant 42 : index
// CHECK-NEXT: br bb2(%c0) : index
// CHECK-NEXT: br bb2(%c0 : index)
// CHECK-NEXT: bb2(%0: index): // 2 preds: bb1, bb11
// CHECK-NEXT: %1 = cmpi "slt", %0, %c42 : index
// CHECK-NEXT: cond_br %1, bb3, bb12
@ -179,7 +179,7 @@ extfunc @body3(index, index) -> ()
// CHECK-NEXT: bb4: // pred: bb3
// CHECK-NEXT: %c7 = constant 7 : index
// CHECK-NEXT: %c56 = constant 56 : index
// CHECK-NEXT: br bb5(%c7) : index
// CHECK-NEXT: br bb5(%c7 : index)
// CHECK-NEXT: bb5(%2: index): // 2 preds: bb4, bb6
// CHECK-NEXT: %3 = cmpi "slt", %2, %c56 : index
// CHECK-NEXT: cond_br %3, bb6, bb7
@ -187,14 +187,14 @@ extfunc @body3(index, index) -> ()
// CHECK-NEXT: call @body2(%0, %2) : (index, index) -> ()
// CHECK-NEXT: %c2 = constant 2 : index
// CHECK-NEXT: %4 = addi %2, %c2 : index
// CHECK-NEXT: br bb5(%4) : index
// CHECK-NEXT: br bb5(%4 : index)
// CHECK-NEXT: bb7: // pred: bb5
// CHECK-NEXT: call @mid(%0) : (index) -> ()
// CHECK-NEXT: br bb8
// CHECK-NEXT: bb8: // pred: bb7
// CHECK-NEXT: %c18 = constant 18 : index
// CHECK-NEXT: %c37 = constant 37 : index
// CHECK-NEXT: br bb9(%c18) : index
// CHECK-NEXT: br bb9(%c18 : index)
// CHECK-NEXT: bb9(%5: index): // 2 preds: bb8, bb10
// CHECK-NEXT: %6 = cmpi "slt", %5, %c37 : index
// CHECK-NEXT: cond_br %6, bb10, bb11
@ -202,12 +202,12 @@ extfunc @body3(index, index) -> ()
// CHECK-NEXT: call @body3(%0, %5) : (index, index) -> ()
// CHECK-NEXT: %c3 = constant 3 : index
// CHECK-NEXT: %7 = addi %5, %c3 : index
// CHECK-NEXT: br bb9(%7) : index
// CHECK-NEXT: br bb9(%7 : index)
// CHECK-NEXT: bb11: // pred: bb9
// CHECK-NEXT: call @post(%0) : (index) -> ()
// CHECK-NEXT: %c1 = constant 1 : index
// CHECK-NEXT: %8 = addi %0, %c1 : index
// CHECK-NEXT: br bb2(%8) : index
// CHECK-NEXT: br bb2(%8 : index)
// CHECK-NEXT: bb12: // pred: bb2
// CHECK-NEXT: return
// CHECK-NEXT: }