Skip to content

Commit 9eb436f

Browse files
committed
[mlir][DeclarativeParser] Add support for formatting the successors of an operation.
This revision add support for formatting successor variables in a similar way to operands, attributes, etc. Differential Revision: https://reviews.llvm.org/D74789
1 parent b1de971 commit 9eb436f

File tree

15 files changed

+228
-149
lines changed

15 files changed

+228
-149
lines changed

mlir/docs/OpDefinitions.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,10 @@ The available directives are as follows:
625625

626626
- Represents all of the results of an operation.
627627

628+
* `successors`
629+
630+
- Represents all of the successors of an operation.
631+
628632
* `type` ( input )
629633

630634
- Represents the type of the given input.
@@ -641,8 +645,8 @@ The following are the set of valid punctuation:
641645
#### Variables
642646

643647
A variable is an entity that has been registered on the operation itself, i.e.
644-
an argument(attribute or operand), result, etc. In the `CallOp` example above,
645-
the variables would be `$callee` and `$args`.
648+
an argument(attribute or operand), result, successor, etc. In the `CallOp`
649+
example above, the variables would be `$callee` and `$args`.
646650

647651
Attribute variables are printed with their respective value type, unless that
648652
value type is buildable. In those cases, the type of the attribute is elided.

mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -455,15 +455,12 @@ def LLVM_SelectOp
455455
// Terminators.
456456
def LLVM_BrOp : LLVM_TerminatorOp<"br", []> {
457457
let successors = (successor AnySuccessor:$dest);
458-
let parser = [{ return parseBrOp(parser, result); }];
459-
let printer = [{ printBrOp(p, *this); }];
458+
let assemblyFormat = "$dest attr-dict";
460459
}
461460
def LLVM_CondBrOp : LLVM_TerminatorOp<"cond_br", []> {
462461
let arguments = (ins LLVMI1:$condition);
463462
let successors = (successor AnySuccessor:$trueDest, AnySuccessor:$falseDest);
464-
465-
let parser = [{ return parseCondBrOp(parser, result); }];
466-
let printer = [{ printCondBrOp(p, *this); }];
463+
let assemblyFormat = "$condition `,` successors attr-dict";
467464
}
468465
def LLVM_ReturnOp : LLVM_TerminatorOp<"return", []>,
469466
Arguments<(ins Variadic<LLVM_Type>:$args)> {

mlir/include/mlir/Dialect/SPIRV/SPIRVControlFlowOps.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ def SPV_BranchOp : SPV_Op<"Branch", [InFunctionScope, Terminator]> {
6969
}];
7070

7171
let autogenSerialization = 0;
72+
73+
let assemblyFormat = "successors attr-dict";
7274
}
7375

7476
// -----

mlir/include/mlir/Dialect/StandardOps/IR/Ops.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ def BranchOp : Std_Op<"br", [Terminator]> {
250250
}];
251251

252252
let hasCanonicalizer = 1;
253+
let assemblyFormat = "$dest attr-dict";
253254
}
254255

255256
def CallOp : Std_Op<"call", [CallOpInterface]> {
@@ -602,6 +603,7 @@ def CondBranchOp : Std_Op<"cond_br", [Terminator]> {
602603
}];
603604

604605
let hasCanonicalizer = 1;
606+
let assemblyFormat = "$condition `,` successors attr-dict";
605607
}
606608

607609
def ConstantOp : Std_Op<"constant",

mlir/include/mlir/IR/OpImplementation.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -578,6 +578,11 @@ class OpAsmParser {
578578
virtual ParseResult
579579
parseSuccessorAndUseList(Block *&dest, SmallVectorImpl<Value> &operands) = 0;
580580

581+
/// Parse an optional operation successor and its operand list.
582+
virtual OptionalParseResult
583+
parseOptionalSuccessorAndUseList(Block *&dest,
584+
SmallVectorImpl<Value> &operands) = 0;
585+
581586
//===--------------------------------------------------------------------===//
582587
// Type Parsing
583588
//===--------------------------------------------------------------------===//

mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp

Lines changed: 0 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -780,69 +780,6 @@ static ParseResult parseInsertValueOp(OpAsmParser &parser,
780780
return success();
781781
}
782782

783-
//===----------------------------------------------------------------------===//
784-
// Printing/parsing for LLVM::BrOp.
785-
//===----------------------------------------------------------------------===//
786-
787-
static void printBrOp(OpAsmPrinter &p, BrOp &op) {
788-
p << op.getOperationName() << ' ';
789-
p.printSuccessorAndUseList(op.getOperation(), 0);
790-
p.printOptionalAttrDict(op.getAttrs());
791-
}
792-
793-
// <operation> ::= `llvm.br` bb-id (`[` ssa-use-and-type-list `]`)?
794-
// attribute-dict?
795-
static ParseResult parseBrOp(OpAsmParser &parser, OperationState &result) {
796-
Block *dest;
797-
SmallVector<Value, 4> operands;
798-
if (parser.parseSuccessorAndUseList(dest, operands) ||
799-
parser.parseOptionalAttrDict(result.attributes))
800-
return failure();
801-
802-
result.addSuccessor(dest, operands);
803-
return success();
804-
}
805-
806-
//===----------------------------------------------------------------------===//
807-
// Printing/parsing for LLVM::CondBrOp.
808-
//===----------------------------------------------------------------------===//
809-
810-
static void printCondBrOp(OpAsmPrinter &p, CondBrOp &op) {
811-
p << op.getOperationName() << ' ' << op.getOperand(0) << ", ";
812-
p.printSuccessorAndUseList(op.getOperation(), 0);
813-
p << ", ";
814-
p.printSuccessorAndUseList(op.getOperation(), 1);
815-
p.printOptionalAttrDict(op.getAttrs());
816-
}
817-
818-
// <operation> ::= `llvm.cond_br` ssa-use `,`
819-
// bb-id (`[` ssa-use-and-type-list `]`)? `,`
820-
// bb-id (`[` ssa-use-and-type-list `]`)? attribute-dict?
821-
static ParseResult parseCondBrOp(OpAsmParser &parser, OperationState &result) {
822-
Block *trueDest;
823-
Block *falseDest;
824-
SmallVector<Value, 4> trueOperands;
825-
SmallVector<Value, 4> falseOperands;
826-
OpAsmParser::OperandType condition;
827-
828-
Builder &builder = parser.getBuilder();
829-
auto *llvmDialect =
830-
builder.getContext()->getRegisteredDialect<LLVM::LLVMDialect>();
831-
auto i1Type = LLVM::LLVMType::getInt1Ty(llvmDialect);
832-
833-
if (parser.parseOperand(condition) || parser.parseComma() ||
834-
parser.parseSuccessorAndUseList(trueDest, trueOperands) ||
835-
parser.parseComma() ||
836-
parser.parseSuccessorAndUseList(falseDest, falseOperands) ||
837-
parser.parseOptionalAttrDict(result.attributes) ||
838-
parser.resolveOperand(condition, i1Type, result.operands))
839-
return failure();
840-
841-
result.addSuccessor(trueDest, trueOperands);
842-
result.addSuccessor(falseDest, falseOperands);
843-
return success();
844-
}
845-
846783
//===----------------------------------------------------------------------===//
847784
// Printing/parsing for LLVM::ReturnOp.
848785
//===----------------------------------------------------------------------===//

mlir/lib/Dialect/SPIRV/SPIRVOps.cpp

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1018,24 +1018,6 @@ void spirv::BitcastOp::getCanonicalizationPatterns(
10181018
results.insert<ConvertChainedBitcast>(context);
10191019
}
10201020

1021-
//===----------------------------------------------------------------------===//
1022-
// spv.BranchOp
1023-
//===----------------------------------------------------------------------===//
1024-
1025-
static ParseResult parseBranchOp(OpAsmParser &parser, OperationState &state) {
1026-
Block *dest;
1027-
SmallVector<Value, 4> destOperands;
1028-
if (parser.parseSuccessorAndUseList(dest, destOperands))
1029-
return failure();
1030-
state.addSuccessor(dest, destOperands);
1031-
return success();
1032-
}
1033-
1034-
static void print(spirv::BranchOp branchOp, OpAsmPrinter &printer) {
1035-
printer << spirv::BranchOp::getOperationName() << ' ';
1036-
printer.printSuccessorAndUseList(branchOp.getOperation(), /*index=*/0);
1037-
}
1038-
10391021
//===----------------------------------------------------------------------===//
10401022
// spv.BranchConditionalOp
10411023
//===----------------------------------------------------------------------===//

mlir/lib/Dialect/StandardOps/IR/Ops.cpp

Lines changed: 0 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -414,20 +414,6 @@ struct SimplifyBrToBlockWithSinglePred : public OpRewritePattern<BranchOp> {
414414
};
415415
} // end anonymous namespace.
416416

417-
static ParseResult parseBranchOp(OpAsmParser &parser, OperationState &result) {
418-
Block *dest;
419-
SmallVector<Value, 4> destOperands;
420-
if (parser.parseSuccessorAndUseList(dest, destOperands))
421-
return failure();
422-
result.addSuccessor(dest, destOperands);
423-
return success();
424-
}
425-
426-
static void print(OpAsmPrinter &p, BranchOp op) {
427-
p << "br ";
428-
p.printSuccessorAndUseList(op.getOperation(), 0);
429-
}
430-
431417
Block *BranchOp::getDest() { return getSuccessor(0); }
432418

433419
void BranchOp::setDest(Block *block) { return setSuccessor(block, 0); }
@@ -810,42 +796,6 @@ struct SimplifyConstCondBranchPred : public OpRewritePattern<CondBranchOp> {
810796
};
811797
} // end anonymous namespace.
812798

813-
static ParseResult parseCondBranchOp(OpAsmParser &parser,
814-
OperationState &result) {
815-
SmallVector<Value, 4> destOperands;
816-
Block *dest;
817-
OpAsmParser::OperandType condInfo;
818-
819-
// Parse the condition.
820-
Type int1Ty = parser.getBuilder().getI1Type();
821-
if (parser.parseOperand(condInfo) || parser.parseComma() ||
822-
parser.resolveOperand(condInfo, int1Ty, result.operands)) {
823-
return parser.emitError(parser.getNameLoc(),
824-
"expected condition type was boolean (i1)");
825-
}
826-
827-
// Parse the true successor.
828-
if (parser.parseSuccessorAndUseList(dest, destOperands))
829-
return failure();
830-
result.addSuccessor(dest, destOperands);
831-
832-
// Parse the false successor.
833-
destOperands.clear();
834-
if (parser.parseComma() ||
835-
parser.parseSuccessorAndUseList(dest, destOperands))
836-
return failure();
837-
result.addSuccessor(dest, destOperands);
838-
839-
return success();
840-
}
841-
842-
static void print(OpAsmPrinter &p, CondBranchOp op) {
843-
p << "cond_br " << op.getCondition() << ", ";
844-
p.printSuccessorAndUseList(op.getOperation(), CondBranchOp::trueIndex);
845-
p << ", ";
846-
p.printSuccessorAndUseList(op.getOperation(), CondBranchOp::falseIndex);
847-
}
848-
849799
void CondBranchOp::getCanonicalizationPatterns(
850800
OwningRewritePatternList &results, MLIRContext *context) {
851801
results.insert<SimplifyConstCondBranchPred>(context);

mlir/lib/Parser/Parser.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4423,6 +4423,15 @@ class CustomOpAsmParser : public OpAsmParser {
44234423
return parser.parseSuccessorAndUseList(dest, operands);
44244424
}
44254425

4426+
/// Parse an optional operation successor and its operand list.
4427+
OptionalParseResult
4428+
parseOptionalSuccessorAndUseList(Block *&dest,
4429+
SmallVectorImpl<Value> &operands) override {
4430+
if (parser.getToken().isNot(Token::caret_identifier))
4431+
return llvm::None;
4432+
return parseSuccessorAndUseList(dest, operands);
4433+
}
4434+
44264435
//===--------------------------------------------------------------------===//
44274436
// Type Parsing
44284437
//===--------------------------------------------------------------------===//

mlir/test/Dialect/SPIRV/control-flow-ops.mlir

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ func @branch_argument() -> () {
2424
// -----
2525

2626
func @missing_accessor() -> () {
27+
// expected-error @+1 {{has incorrect number of successors: expected 1 but found 0}}
2728
spv.Branch
28-
// expected-error @+1 {{expected block name}}
2929
}
3030

3131
// -----

mlir/test/IR/invalid.mlir

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,6 @@ func @condbr_notbool() {
402402
^bb0:
403403
%a = "foo"() : () -> i32 // expected-note {{prior use here}}
404404
cond_br %a, ^bb0, ^bb0 // expected-error {{use of value '%a' expects different type than prior uses: 'i1' vs 'i32'}}
405-
// expected-error@-1 {{expected condition type was boolean (i1)}}
406405
}
407406
408407
// -----

mlir/test/lib/TestDialect/TestOps.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1139,4 +1139,9 @@ def FormatOperandEOp : FormatOperandBase<"format_operand_e_op", [{
11391139
$buildable `,` $operand `:` type($buildable) `,` type($operand) attr-dict
11401140
}]>;
11411141

1142+
def FormatSuccessorAOp : TEST_Op<"format_successor_a_op", [Terminator]> {
1143+
let successors = (successor VariadicSuccessor<AnySuccessor>:$targets);
1144+
let assemblyFormat = "$targets attr-dict";
1145+
}
1146+
11421147
#endif // TEST_OPS

mlir/test/mlir-tblgen/op-format-spec.td

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,18 @@ def DirectiveOperandsValid : TestFormat_Op<"operands_valid", [{
9494
// results
9595

9696
// CHECK: error: 'results' directive can not be used as a top-level directive
97-
def DirectiveResultsInvalidA : TestFormat_Op<"operands_invalid_a", [{
97+
def DirectiveResultsInvalidA : TestFormat_Op<"results_invalid_a", [{
9898
results
9999
}]>;
100100

101+
//===----------------------------------------------------------------------===//
102+
// successors
103+
104+
// CHECK: error: 'successors' is only valid as a top-level directive
105+
def DirectiveSuccessorsInvalidA : TestFormat_Op<"successors_invalid_a", [{
106+
type(successors)
107+
}]>;
108+
101109
//===----------------------------------------------------------------------===//
102110
// type
103111

@@ -235,7 +243,7 @@ def OptionalInvalidK : TestFormat_Op<"optional_invalid_k", [{
235243
// Variables
236244
//===----------------------------------------------------------------------===//
237245

238-
// CHECK: error: expected variable to refer to a argument or result
246+
// CHECK: error: expected variable to refer to a argument, result, or successor
239247
def VariableInvalidA : TestFormat_Op<"variable_invalid_a", [{
240248
$unknown_arg attr-dict
241249
}]>;
@@ -255,6 +263,18 @@ def VariableInvalidD : TestFormat_Op<"variable_invalid_d", [{
255263
def VariableInvalidE : TestFormat_Op<"variable_invalid_e", [{
256264
$result attr-dict
257265
}]>, Results<(outs I64:$result)>;
266+
// CHECK: error: successor 'successor' is already bound
267+
def VariableInvalidF : TestFormat_Op<"variable_invalid_f", [{
268+
$successor $successor attr-dict
269+
}]> {
270+
let successors = (successor AnySuccessor:$successor);
271+
}
272+
// CHECK: error: successor 'successor' is already bound
273+
def VariableInvalidG : TestFormat_Op<"variable_invalid_g", [{
274+
successors $successor attr-dict
275+
}]> {
276+
let successors = (successor AnySuccessor:$successor);
277+
}
258278

259279
//===----------------------------------------------------------------------===//
260280
// Coverage Checks

mlir/test/mlir-tblgen/op-format.mlir

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,19 @@ test.format_operand_d_op %i64, %memref : memref<1xf64>
4141

4242
// CHECK: test.format_operand_e_op %[[I64]], %[[MEMREF]] : i64, memref<1xf64>
4343
test.format_operand_e_op %i64, %memref : i64, memref<1xf64>
44+
45+
"foo.successor_test_region"() ( {
46+
^bb0:
47+
// CHECK: test.format_successor_a_op ^bb1 {attr}
48+
test.format_successor_a_op ^bb1 {attr}
49+
50+
^bb1:
51+
// CHECK: test.format_successor_a_op ^bb1, ^bb2 {attr}
52+
test.format_successor_a_op ^bb1, ^bb2 {attr}
53+
54+
^bb2:
55+
// CHECK: test.format_successor_a_op {attr}
56+
test.format_successor_a_op {attr}
57+
58+
}) { arg_names = ["i", "j", "k"] } : () -> ()
59+

0 commit comments

Comments
 (0)