Change syntax of regions in the generic form of operations

The generic form of operations currently supports optional regions to be
    located after the operation type.  As we are going to add a type to each
    region in a leading position in the region syntax, similarly to functions, it
    becomes ambiguous to have regions immediately after the operation type.  Put
    regions between operands the optional list of successors in the generic
    operation syntax and wrap them in parentheses.  The effect on the exisitng IR
    syntax is minimal since only three operations (`affine.for`, `affine.if` and
    `gpu.kernel`) currently use regions.

--

PiperOrigin-RevId: 246787087
This commit is contained in:
Alex Zinenko 2019-05-06 01:40:13 -07:00 committed by Mehdi Amini
parent e2e89f5c83
commit d3380a504f
10 changed files with 120 additions and 97 deletions

View File

@ -69,12 +69,14 @@ class EdscTest(unittest.TestCase):
x = i + j x = i + j
code = str(fun) code = str(fun)
# TODO(zinenko,ntv): use FileCheck for these tests # TODO(zinenko,ntv): use FileCheck for these tests
self.assertIn(' "affine.for"() ( {\n', code)
self.assertIn( self.assertIn(
' "affine.for"() {lower_bound: () -> (0), step: 1 : index, upper_bound: () -> (42)} : () -> () {\n', "{lower_bound: () -> (0), step: 1 : index, upper_bound: () -> (42)}",
code) code)
self.assertIn(" ^bb1(%i0: index):", code) self.assertIn(" ^bb1(%i0: index):", code)
self.assertIn(' "affine.for"(%c42, %2) ( {\n', code)
self.assertIn( self.assertIn(
' "affine.for"(%c42, %2) {lower_bound: (d0) -> (d0), step: 2 : index, upper_bound: (d0) -> (d0)} : (index, index) -> () {\n', "{lower_bound: (d0) -> (d0), step: 2 : index, upper_bound: (d0) -> (d0)} : (index, index) -> ()",
code) code)
self.assertIn(" ^bb2(%i1: index):", code) self.assertIn(" ^bb2(%i1: index):", code)
self.assertIn( self.assertIn(
@ -89,21 +91,13 @@ class EdscTest(unittest.TestCase):
i + j + k + l i + j + k + l
code = str(fun) code = str(fun)
self.assertIn( self.assertIn(' "affine.for"() ( {\n', code)
' "affine.for"() {lower_bound: () -> (0), step: 1 : index, upper_bound: () -> (5)} : () -> () {\n',
code)
self.assertIn(" ^bb1(%i0: index):", code) self.assertIn(" ^bb1(%i0: index):", code)
self.assertIn( self.assertIn(' "affine.for"() ( {\n', code)
' "affine.for"() {lower_bound: () -> (1), step: 3 : index, upper_bound: () -> (15)} : () -> () {\n',
code)
self.assertIn(" ^bb2(%i1: index):", code) self.assertIn(" ^bb2(%i1: index):", code)
self.assertIn( self.assertIn(' "affine.for"() ( {\n', code)
' "affine.for"() {lower_bound: () -> (2), step: 5 : index, upper_bound: () -> (25)} : () -> () {\n',
code)
self.assertIn(" ^bb3(%i2: index):", code) self.assertIn(" ^bb3(%i2: index):", code)
self.assertIn( self.assertIn(' "affine.for"() ( {\n', code)
' "affine.for"() {lower_bound: () -> (3), step: 7 : index, upper_bound: () -> (35)} : () -> () {\n',
code)
self.assertIn(" ^bb4(%i3: index):", code) self.assertIn(" ^bb4(%i3: index):", code)
self.assertIn( self.assertIn(
' %2 = "affine.apply"(%i0, %i1, %i2, %i3) {map: (d0, d1, d2, d3) -> (d0 + d1 + d2 + d3)} : (index, index, index, index) -> index', ' %2 = "affine.apply"(%i0, %i1, %i2, %i3) {map: (d0, d1, d2, d3) -> (d0 + d1 + d2 + d3)} : (index, index, index, index) -> index',
@ -367,11 +361,13 @@ class EdscTest(unittest.TestCase):
E.ret([fun.arg(0)]) E.ret([fun.arg(0)])
code = str(fun) code = str(fun)
self.assertIn('"affine.for"()', code)
self.assertIn( self.assertIn(
'"affine.for"() {lower_bound: () -> (0), step: 1 : index, upper_bound: () -> (10)}', "{lower_bound: () -> (0), step: 1 : index, upper_bound: () -> (10)}",
code) code)
self.assertIn('"affine.for"()', code)
self.assertIn( self.assertIn(
'"affine.for"() {lower_bound: () -> (0), step: 1 : index, upper_bound: () -> (42)}', "{lower_bound: () -> (0), step: 1 : index, upper_bound: () -> (42)}",
code) code)
self.assertIn("%0 = load %arg0[%i0, %i1] : memref<10x42xf32>", code) self.assertIn("%0 = load %arg0[%i0, %i1] : memref<10x42xf32>", code)
self.assertIn("%1 = addf %0, %cst : f32", code) self.assertIn("%1 = addf %0, %cst : f32", code)
@ -392,8 +388,9 @@ class EdscTest(unittest.TestCase):
E.ret([]) E.ret([])
code = str(fun) code = str(fun)
self.assertIn('"affine.for"()', code)
self.assertIn( self.assertIn(
'"affine.for"() {lower_bound: () -> (0), step: 1 : index, upper_bound: () -> (32)} : () -> ()', "{lower_bound: () -> (0), step: 1 : index, upper_bound: () -> (32)} : () -> ()",
code) code)
self.assertIn("%0 = load %arg0[%i0, %i2] : memref<32x32xf32>", code) self.assertIn("%0 = load %arg0[%i0, %i2] : memref<32x32xf32>", code)
self.assertIn("%1 = load %arg1[%i2, %i1] : memref<32x32xf32>", code) self.assertIn("%1 = load %arg1[%i2, %i1] : memref<32x32xf32>", code)

View File

@ -1413,9 +1413,11 @@ Syntax:
``` {.ebnf} ``` {.ebnf}
operation ::= op-result? string-literal `(` ssa-use-list? `)` operation ::= op-result? string-literal `(` ssa-use-list? `)`
(`[` successor-list `]`)? attribute-dict? `:` function-type (`[` successor-list `]`)? (`(` region-list `)`)?
attribute-dict? `:` function-type
op-result ::= ssa-id ((`:` integer-literal) | (`,` ssa-id)*) `=` op-result ::= ssa-id ((`:` integer-literal) | (`,` ssa-id)*) `=`
successor-list ::= successor (`,` successor)* successor-list ::= successor (`,` successor)*
region-list ::= region (`,` region)*
``` ```
MLIR represents computations within functions with a uniform concept called MLIR represents computations within functions with a uniform concept called
@ -1428,7 +1430,8 @@ operations), and have application-specific semantics. For example, MLIR supports
The internal representation of an operation is simple: an operation is The internal representation of an operation is simple: an operation is
identified by a unique string (e.g. `dim`, `tf.Conv2d`, `x86.repmovsb`, identified by a unique string (e.g. `dim`, `tf.Conv2d`, `x86.repmovsb`,
`ppc.eieio`, etc), can return zero or more results, take zero or more SSA `ppc.eieio`, etc), can return zero or more results, take zero or more SSA
operands, and may have zero or more attributes. When parsed or printed in the operands, may have zero or more attributes, may have zero or more successors,
and zero or more enclosed [regions](#regions). When parsed or printed in the
_generic assembly form_, these are all printed literally, and a function type is _generic assembly form_, these are all printed literally, and a function type is
used to indicate the types of the results and operands. used to indicate the types of the results and operands.

View File

@ -1582,6 +1582,16 @@ void FunctionPrinter::printGenericOp(Operation *op) {
os << ']'; os << ']';
} }
// Print regions.
if (op->getNumRegions() != 0) {
os << " (";
interleaveComma(op->getRegions(), [&](Region &region) {
printRegion(region, /*printEntryBlockArgs=*/true,
/*printBlockTerminators=*/true);
});
os << ')';
}
auto attrs = op->getAttrs(); auto attrs = op->getAttrs();
printOptionalAttrDict(attrs); printOptionalAttrDict(attrs);
@ -1600,11 +1610,6 @@ void FunctionPrinter::printGenericOp(Operation *op) {
[&](Value *result) { printType(result->getType()); }); [&](Value *result) { printType(result->getType()); });
os << ')'; os << ')';
} }
// Print any trailing regions.
for (auto &region : op->getRegions())
printRegion(region, /*printEntryBlockArgs=*/true,
/*printBlockTerminators=*/true);
} }
void FunctionPrinter::printSuccessorAndUseList(Operation *term, void FunctionPrinter::printSuccessorAndUseList(Operation *term,

View File

@ -3083,6 +3083,20 @@ Operation *FunctionParser::parseGenericOperation() {
return nullptr; return nullptr;
} }
// Parse the region list.
CleanupOpStateRegions guard{result};
if (consumeIf(Token::l_paren)) {
do {
// Create temporary regions with function as parent.
result.regions.emplace_back(new Region(function));
if (parseOperationRegion(*result.regions.back(),
/*entryArguments*/ {}))
return nullptr;
} while (consumeIf(Token::comma));
if (parseToken(Token::r_paren, "expected ')' to end region list"))
return nullptr;
}
if (getToken().is(Token::l_brace)) { if (getToken().is(Token::l_brace)) {
if (parseAttributeDict(result.attributes)) if (parseAttributeDict(result.attributes))
return nullptr; return nullptr;
@ -3125,16 +3139,6 @@ Operation *FunctionParser::parseGenericOperation() {
result.addSuccessor(successor, operands); result.addSuccessor(successor, operands);
} }
// Parse the optional regions for this operation.
CleanupOpStateRegions guard{result};
while (getToken().is(Token::l_brace)) {
// Create temporary regions with function as parent.
result.regions.emplace_back(new Region(function));
if (parseOperationRegion(*result.regions.back(),
/*entryArguments=*/llvm::None))
return nullptr;
}
return builder.createOperation(result); return builder.createOperation(result);
} }

View File

@ -11,7 +11,7 @@ func @empty() {
// GENERIC: "affine.for"() // GENERIC: "affine.for"()
// GENERIC-NEXT: ^bb1(%i0: index): // GENERIC-NEXT: ^bb1(%i0: index):
// GENERIC-NEXT: "affine.terminator"() : () -> () // GENERIC-NEXT: "affine.terminator"() : () -> ()
// GENERIC-NEXT: } // GENERIC-NEXT: })
affine.for %i = 0 to 10 { affine.for %i = 0 to 10 {
} {some_attr: true} } {some_attr: true}
@ -20,8 +20,8 @@ func @empty() {
// //
// GENERIC: "affine.if"() // GENERIC: "affine.if"()
// GENERIC-NEXT: "affine.terminator"() : () -> () // GENERIC-NEXT: "affine.terminator"() : () -> ()
// GENERIC-NEXT: } { // GENERIC-NEXT: }, {
// GENERIC-NEXT: } // GENERIC-NEXT: })
affine.if () : () () { affine.if () : () () {
} {some_attr: true} } {some_attr: true}
@ -30,10 +30,10 @@ func @empty() {
// //
// GENERIC: "affine.if"() // GENERIC: "affine.if"()
// GENERIC-NEXT: "affine.terminator"() : () -> () // GENERIC-NEXT: "affine.terminator"() : () -> ()
// GENERIC-NEXT: } { // GENERIC-NEXT: }, {
// GENERIC-NEXT: "foo"() : () -> () // GENERIC-NEXT: "foo"() : () -> ()
// GENERIC-NEXT: "affine.terminator"() : () -> () // GENERIC-NEXT: "affine.terminator"() : () -> ()
// GENERIC-NEXT: } // GENERIC-NEXT: })
affine.if () : () () { affine.if () : () () {
} else { } else {
"foo"() : () -> () "foo"() : () -> ()
@ -49,10 +49,10 @@ func @affine_terminator() {
// CHECK: affine.for %i // CHECK: affine.for %i
// CHECK-NEXT: } // CHECK-NEXT: }
// //
// GENERIC: "affine.for"() {lower_bound: #map0, step: 1 : index, upper_bound: #map1} : () -> () { // GENERIC: "affine.for"() ( {
// GENERIC-NEXT: ^bb1(%i0: index): // no predecessors // GENERIC-NEXT: ^bb1(%i0: index): // no predecessors
// GENERIC-NEXT: "affine.terminator"() : () -> () // GENERIC-NEXT: "affine.terminator"() : () -> ()
// GENERIC-NEXT: } // GENERIC-NEXT: }) {lower_bound: #map0, step: 1 : index, upper_bound: #map1} : () -> ()
affine.for %i = 0 to 10 { affine.for %i = 0 to 10 {
"affine.terminator"() : () -> () "affine.terminator"() : () -> ()
} }

View File

@ -2,10 +2,9 @@
func @not_enough_sizes(%sz : index) { func @not_enough_sizes(%sz : index) {
// expected-error@+1 {{expected 6 or more operands}} // expected-error@+1 {{expected 6 or more operands}}
"gpu.launch"(%sz, %sz, %sz, %sz, %sz) "gpu.launch"(%sz, %sz, %sz, %sz, %sz) ({
: (index, index, index, index, index) -> () {
return return
} }) : (index, index, index, index, index) -> ()
return return
} }
@ -13,12 +12,11 @@ func @not_enough_sizes(%sz : index) {
func @no_region_attrs(%sz : index) { func @no_region_attrs(%sz : index) {
// expected-error@+1 {{unexpected number of region arguments}} // expected-error@+1 {{unexpected number of region arguments}}
"gpu.launch"(%sz, %sz, %sz, %sz, %sz, %sz) "gpu.launch"(%sz, %sz, %sz, %sz, %sz, %sz) ({
: (index, index, index, index, index, index) -> () {
^bb1(%bx: index, %by: index, %bz: index, ^bb1(%bx: index, %by: index, %bz: index,
%tx: index, %ty: index, %tz: index): %tx: index, %ty: index, %tz: index):
return return
} }) : (index, index, index, index, index, index) -> ()
return return
} }
@ -26,8 +24,7 @@ func @no_region_attrs(%sz : index) {
func @isolation_arg(%sz : index) { func @isolation_arg(%sz : index) {
// expected-note@+1 {{required by region isolation constraints}} // expected-note@+1 {{required by region isolation constraints}}
"gpu.launch"(%sz, %sz, %sz, %sz, %sz, %sz) "gpu.launch"(%sz, %sz, %sz, %sz, %sz, %sz) ({
: (index, index, index, index, index, index) -> () {
^bb1(%bx: index, %by: index, %bz: index, ^bb1(%bx: index, %by: index, %bz: index,
%tx: index, %ty: index, %tz: index, %tx: index, %ty: index, %tz: index,
%szbx: index, %szby: index, %szbz: index, %szbx: index, %szby: index, %szbz: index,
@ -35,7 +32,7 @@ func @isolation_arg(%sz : index) {
// expected-error@+1 {{using value defined outside the region}} // expected-error@+1 {{using value defined outside the region}}
"use"(%sz) : (index) -> () "use"(%sz) : (index) -> ()
return return
} }) : (index, index, index, index, index, index) -> ()
return return
} }
@ -44,8 +41,7 @@ func @isolation_arg(%sz : index) {
func @isolation_op(%sz : index) { func @isolation_op(%sz : index) {
%val = "produce"() : () -> (index) %val = "produce"() : () -> (index)
// expected-note@+1 {{required by region isolation constraints}} // expected-note@+1 {{required by region isolation constraints}}
"gpu.launch"(%sz, %sz, %sz, %sz, %sz, %sz) "gpu.launch"(%sz, %sz, %sz, %sz, %sz, %sz) ({
: (index, index, index, index, index, index) -> () {
^bb1(%bx: index, %by: index, %bz: index, ^bb1(%bx: index, %by: index, %bz: index,
%tx: index, %ty: index, %tz: index, %tx: index, %ty: index, %tz: index,
%szbx: index, %szby: index, %szbz: index, %szbx: index, %szby: index, %szbz: index,
@ -53,7 +49,7 @@ func @isolation_op(%sz : index) {
// expected-error@+1 {{using value defined outside the region}} // expected-error@+1 {{using value defined outside the region}}
"use"(%val) : (index) -> () "use"(%val) : (index) -> ()
return return
} }) : (index, index, index, index, index, index) -> ()
return return
} }
@ -61,18 +57,17 @@ func @isolation_op(%sz : index) {
func @nested_isolation(%sz : index) { func @nested_isolation(%sz : index) {
// expected-note@+1 {{required by region isolation constraints}} // expected-note@+1 {{required by region isolation constraints}}
"gpu.launch"(%sz, %sz, %sz, %sz, %sz, %sz) "gpu.launch"(%sz, %sz, %sz, %sz, %sz, %sz) ({
: (index, index, index, index, index, index) -> () {
^bb1(%bx: index, %by: index, %bz: index, ^bb1(%bx: index, %by: index, %bz: index,
%tx: index, %ty: index, %tz: index, %tx: index, %ty: index, %tz: index,
%szbx: index, %szby: index, %szbz: index, %szbx: index, %szby: index, %szbz: index,
%sztx: index, %szty: index, %sztz: index): %sztx: index, %szty: index, %sztz: index):
"region"() : () -> () { "region"() ({
"region"() : () -> () { "region"() ({
// expected-error@+1 {{using value defined outside the region}} // expected-error@+1 {{using value defined outside the region}}
"use"(%sz) : (index) -> () "use"(%sz) : (index) -> ()
} }) : () -> ()
} }) : () -> ()
} }) : (index, index, index, index, index, index) -> ()
return return
} }

View File

@ -2,39 +2,41 @@
// CHECK-LABEL:func @no_args(%arg0: index) // CHECK-LABEL:func @no_args(%arg0: index)
func @no_args(%sz : index) { func @no_args(%sz : index) {
// CHECK: "gpu.launch"(%arg0, %arg0, %arg0, %arg0, %arg0, %arg0) : (index, index, index, index, index, index) -> () { // CHECK: "gpu.launch"(%arg0, %arg0, %arg0, %arg0, %arg0, %arg0)
"gpu.launch"(%sz, %sz, %sz, %sz, %sz, %sz) // CHECK-SAME: {
: (index, index, index, index, index, index) -> () { "gpu.launch"(%sz, %sz, %sz, %sz, %sz, %sz) ({
^bb1(%bx: index, %by: index, %bz: index, ^bb1(%bx: index, %by: index, %bz: index,
%tx: index, %ty: index, %tz: index, %tx: index, %ty: index, %tz: index,
%szbx: index, %szby: index, %szbz: index, %szbx: index, %szby: index, %szbz: index,
%sztx: index, %szty: index, %sztz: index): %sztx: index, %szty: index, %sztz: index):
return return
} // CHECK: (index, index, index, index, index, index) -> ()
}) : (index, index, index, index, index, index) -> ()
return return
} }
// CHECK-LABEL:func @args(%arg0: index, %arg1: index, %arg2: f32, %arg3: memref<?xf32, 1>) { // CHECK-LABEL:func @args(%arg0: index, %arg1: index, %arg2: f32, %arg3: memref<?xf32, 1>) {
func @args(%blk : index, %thrd : index, %float : f32, %data : memref<?xf32,1>) { func @args(%blk : index, %thrd : index, %float : f32, %data : memref<?xf32,1>) {
// CHECK: "gpu.launch"(%arg0, %arg0, %arg0, %arg1, %arg1, %arg1, %arg2, %arg3) : (index, index, index, index, index, index, f32, memref<?xf32, 1>) -> () { // CHECK: "gpu.launch"(%arg0, %arg0, %arg0, %arg1, %arg1, %arg1, %arg2, %arg3)
"gpu.launch"(%blk, %blk, %blk, %thrd, %thrd, %thrd, %float, %data) // CHECK-SAME: {
: (index, index, index, index, index, index, f32, memref<?xf32,1>) -> () { "gpu.launch"(%blk, %blk, %blk, %thrd, %thrd, %thrd, %float, %data) ({
^bb1(%bx: index, %by: index, %bz: index, ^bb1(%bx: index, %by: index, %bz: index,
%tx: index, %ty: index, %tz: index, %tx: index, %ty: index, %tz: index,
%szbx: index, %szby: index, %szbz: index, %szbx: index, %szby: index, %szbz: index,
%sztx: index, %szty: index, %sztz: index, %sztx: index, %szty: index, %sztz: index,
%data0: f32, %data1: memref<?xf32,1>): %data0: f32, %data1: memref<?xf32,1>):
return return
} // CHECK: (index, index, index, index, index, index, f32, memref<?xf32, 1>) -> ()
}) : (index, index, index, index, index, index, f32, memref<?xf32,1>) -> ()
return return
} }
// It is possible to use values passed into the region as arguments. // It is possible to use values passed into the region as arguments.
// CHECK-LABEL: func @passing_values // CHECK-LABEL: func @passing_values
func @passing_values(%blk : index, %thrd : index, %float : f32, %data : memref<?xf32,1>) { func @passing_values(%blk : index, %thrd : index, %float : f32, %data : memref<?xf32,1>) {
// CHECK: "gpu.launch"(%arg0, %arg0, %arg0, %arg1, %arg1, %arg1, %arg2, %arg3) : (index, index, index, index, index, index, f32, memref<?xf32, 1>) -> () { // CHECK: "gpu.launch"(%arg0, %arg0, %arg0, %arg1, %arg1, %arg1, %arg2, %arg3)
"gpu.launch"(%blk, %blk, %blk, %thrd, %thrd, %thrd, %float, %data) // CHECK-SAME: {
: (index, index, index, index, index, index, f32, memref<?xf32,1>) -> () { "gpu.launch"(%blk, %blk, %blk, %thrd, %thrd, %thrd, %float, %data) ({
// CHECK: ^bb1(%i0: index, %i1: index, %i2: index, %i3: index, %i4: index, %i5: index, %i6: index, %i7: index, %i8: index, %i9: index, %i10: index, %i11: index, %i12: f32, %i13: memref<?xf32, 1>) // CHECK: ^bb1(%i0: index, %i1: index, %i2: index, %i3: index, %i4: index, %i5: index, %i6: index, %i7: index, %i8: index, %i9: index, %i10: index, %i11: index, %i12: f32, %i13: memref<?xf32, 1>)
^bb1(%bx: index, %by: index, %bz: index, ^bb1(%bx: index, %by: index, %bz: index,
%tx: index, %ty: index, %tz: index, %tx: index, %ty: index, %tz: index,
@ -44,7 +46,7 @@ func @passing_values(%blk : index, %thrd : index, %float : f32, %data : memref<?
// CHECK: "use"(%i12) // CHECK: "use"(%i12)
"use"(%data0): (f32) -> () "use"(%data0): (f32) -> ()
return return
} }) : (index, index, index, index, index, index, f32, memref<?xf32,1>) -> ()
return return
} }
@ -52,20 +54,19 @@ func @passing_values(%blk : index, %thrd : index, %float : f32, %data : memref<?
// cross kernel launch region boundaries. // cross kernel launch region boundaries.
// CHECK-LABEL: func @nested_isolation // CHECK-LABEL: func @nested_isolation
func @nested_isolation(%sz : index) { func @nested_isolation(%sz : index) {
"gpu.launch"(%sz, %sz, %sz, %sz, %sz, %sz) "gpu.launch"(%sz, %sz, %sz, %sz, %sz, %sz) ({
: (index, index, index, index, index, index) -> () {
^bb1(%bx: index, %by: index, %bz: index, ^bb1(%bx: index, %by: index, %bz: index,
%tx: index, %ty: index, %tz: index, %tx: index, %ty: index, %tz: index,
%szbx: index, %szby: index, %szbz: index, %szbx: index, %szby: index, %szbz: index,
%sztx: index, %szty: index, %sztz: index): %sztx: index, %szty: index, %sztz: index):
"region"() : () -> () { "region"() ({
// CHECK: %0 = "produce"() // CHECK: %0 = "produce"()
%val = "produce"() : () -> (index) %val = "produce"() : () -> (index)
"region"() : () -> () { "region"() ({
// CHECK: "use"(%0) // CHECK: "use"(%0)
"use"(%val) : (index) -> () "use"(%val) : (index) -> ()
} }) : () -> ()
} }) : () -> ()
} }) : (index, index, index, index, index, index) -> ()
return return
} }

View File

@ -882,7 +882,7 @@ func @negative_in_tensor_size() -> tensor<1x-1xi32>
// ----- // -----
func @invalid_nested_dominance() { func @invalid_nested_dominance() {
"foo.region"() : () -> () { "foo.region"() ({
// expected-error @+1 {{operand #0 does not dominate this use}} // expected-error @+1 {{operand #0 does not dominate this use}}
"foo.use" (%1) : (i32) -> () "foo.use" (%1) : (i32) -> ()
br ^bb2 br ^bb2
@ -891,7 +891,7 @@ func @invalid_nested_dominance() {
// expected-note @+1 {{operand defined here}} // expected-note @+1 {{operand defined here}}
%1 = constant 0 : i32 %1 = constant 0 : i32
"foo.yield" () : () -> () "foo.yield" () : () -> ()
} }) : () -> ()
return return
} }
@ -925,13 +925,13 @@ func @invalid_tuple_missing_greater(tuple<i32)
// Should not crash because of deletion order here. // Should not crash because of deletion order here.
func @invalid_region_dominance() { func @invalid_region_dominance() {
"foo.use" (%1) : (i32) -> () "foo.use" (%1) : (i32) -> ()
"foo.region"() : () -> () { "foo.region"() ({
%1 = constant 0 : i32 // This value is used outside of the region. %1 = constant 0 : i32 // This value is used outside of the region.
"foo.yield" () : () -> () "foo.yield" () : () -> ()
} { }, {
// expected-error @+1 {{expected operation name in quotes}} // expected-error @+1 {{expected operation name in quotes}}
%2 = constant 1 i32 // Syntax error causes region deletion. %2 = constant 1 i32 // Syntax error causes region deletion.
} }) : () -> ()
return return
} }
@ -942,13 +942,13 @@ func @invalid_region_block() {
"foo.branch"()[^bb2] : () -> () // Attempt to jump into the region. "foo.branch"()[^bb2] : () -> () // Attempt to jump into the region.
^bb1: ^bb1:
"foo.region"() : () -> () { "foo.region"() ({
^bb2: ^bb2:
"foo.yield"() : () -> () "foo.yield"() : () -> ()
} { }, {
// expected-error @+1 {{expected operation name in quotes}} // expected-error @+1 {{expected operation name in quotes}}
%2 = constant 1 i32 // Syntax error causes region deletion. %2 = constant 1 i32 // Syntax error causes region deletion.
} }) : () -> ()
} }
// ----- // -----
@ -956,20 +956,27 @@ func @invalid_region_block() {
// Should not crash because of deletion order here. // Should not crash because of deletion order here.
func @invalid_region_dominance() { func @invalid_region_dominance() {
"foo.use" (%1) : (i32) -> () "foo.use" (%1) : (i32) -> ()
"foo.region"() : () -> () { "foo.region"() ({
"foo.region"() : () -> () { "foo.region"() ({
%1 = constant 0 : i32 // This value is used outside of the region. %1 = constant 0 : i32 // This value is used outside of the region.
"foo.yield" () : () -> () "foo.yield" () : () -> ()
} }) : () -> ()
} { }, {
// expected-error @+1 {{expected operation name in quotes}} // expected-error @+1 {{expected operation name in quotes}}
%2 = constant 1 i32 // Syntax error causes region deletion. %2 = constant 1 i32 // Syntax error causes region deletion.
} }) : () -> ()
return return
} }
// ----- // -----
func @unfinished_region_list() {
// expected-error@+1 {{expected ')' to end region list}}
"region"() ({},{},{} : () -> ()
}
// -----
func @multi_result_missing_count() { func @multi_result_missing_count() {
// expected-error@+1 {{expected integer number of results}} // expected-error@+1 {{expected integer number of results}}
%0: = "foo" () : () -> (i32, i32) %0: = "foo" () : () -> (i32, i32)

View File

@ -800,16 +800,27 @@ func @verbose_if(%N: index) {
%c = constant 200 : index %c = constant 200 : index
// CHECK: affine.if #set{{.*}}(%c200)[%arg0, %c200] { // CHECK: affine.if #set{{.*}}(%c200)[%arg0, %c200] {
"affine.if"(%c, %N, %c) { condition: #set0 } : (index, index, index) -> () { "affine.if"(%c, %N, %c) ({
// CHECK-NEXT: "add" // CHECK-NEXT: "add"
%y = "add"(%c, %N) : (index, index) -> index %y = "add"(%c, %N) : (index, index) -> index
"affine.terminator"() : () -> () "affine.terminator"() : () -> ()
// CHECK-NEXT: } else { // CHECK-NEXT: } else {
} { // The else region. }, { // The else region.
// CHECK-NEXT: "add" // CHECK-NEXT: "add"
%z = "add"(%c, %c) : (index, index) -> index %z = "add"(%c, %c) : (index, index) -> index
"affine.terminator"() : () -> () "affine.terminator"() : () -> ()
} })
{ condition: #set0 } : (index, index, index) -> ()
return
}
// CHECK-LABEL: func @terminator_with_regions
func @terminator_with_regions() {
// Combine successors and regions in the same operation.
// CHECK: "region"()[^bb1] ( {
// CHECK: }) : () -> ()
"region"()[^bb2] ({}) : () -> ()
^bb2:
return return
} }

View File

@ -193,7 +193,7 @@ func @up_propagate() -> i32 {
// CHECK-LABEL: func @up_propagate_region // CHECK-LABEL: func @up_propagate_region
func @up_propagate_region() -> i32 { func @up_propagate_region() -> i32 {
// CHECK-NEXT: %0 = "foo.region" // CHECK-NEXT: %0 = "foo.region"
%0 = "foo.region"() : () -> (i32) { %0 = "foo.region"() ({
// CHECK-NEXT: %c0_i32 = constant 0 : i32 // CHECK-NEXT: %c0_i32 = constant 0 : i32
// CHECK-NEXT: %true = constant 1 : i1 // CHECK-NEXT: %true = constant 1 : i1
// CHECK-NEXT: cond_br // CHECK-NEXT: cond_br
@ -217,6 +217,6 @@ func @up_propagate_region() -> i32 {
%c1_i32_0 = constant 1 : i32 %c1_i32_0 = constant 1 : i32
%2 = addi %arg, %c1_i32_0 : i32 %2 = addi %arg, %c1_i32_0 : i32
"foo.yield" (%2) : (i32) -> () "foo.yield" (%2) : (i32) -> ()
} }) : () -> (i32)
return %0 : i32 return %0 : i32
} }