diff --git a/mlir/include/mlir/Dialect/SCF/IR/SCFOps.td b/mlir/include/mlir/Dialect/SCF/IR/SCFOps.td --- a/mlir/include/mlir/Dialect/SCF/IR/SCFOps.td +++ b/mlir/include/mlir/Dialect/SCF/IR/SCFOps.td @@ -976,7 +976,7 @@ def WhileOp : SCF_Op<"while", [DeclareOpInterfaceMethods, - RecursiveMemoryEffects]> { + RecursiveMemoryEffects, SingleBlock]> { let summary = "a generic 'while' loop"; let description = [{ This operation represents a generic "while"/"do-while" loop that keeps diff --git a/mlir/test/Dialect/SCF/invalid.mlir b/mlir/test/Dialect/SCF/invalid.mlir --- a/mlir/test/Dialect/SCF/invalid.mlir +++ b/mlir/test/Dialect/SCF/invalid.mlir @@ -478,11 +478,25 @@ // ----- func.func @while_empty_block() { - // expected-error@+1 {{expects the 'before' region to terminate with 'scf.condition'}} + // expected-error @below {{expects a non-empty block}} + scf.while : () -> () { + ^bb0: + } do { + ^bb0: + } +} + +// ----- + +func.func @while_invalid_terminator() { + // expected-error @below {{expects the 'before' region to terminate with 'scf.condition'}} scf.while : () -> () { - ^bb0: + ^bb0: + // expected-note @below{{terminator here}} + "test.foo"() : () -> () } do { - ^bb0: + ^bb0: + "test.bar"() : () -> () } } diff --git a/mlir/test/Transforms/inlining.mlir b/mlir/test/Transforms/inlining.mlir --- a/mlir/test/Transforms/inlining.mlir +++ b/mlir/test/Transforms/inlining.mlir @@ -227,18 +227,40 @@ return } -// CHECK-LABEL: func @func_with_block_args_location_callee3 -func.func @func_with_block_args_location_callee3(%arg0 : i32) { +func.func @func_with_multiple_blocks(%arg0 : i32) { + cf.br ^bb1(%arg0 : i32) +^bb1(%x : i32): + "test.foo" (%x) : (i32) -> () loc("bar") + return +} + +// CHECK-LABEL: func @func_with_multiple_blocks_callee1 +func.func @func_with_multiple_blocks_callee1(%arg0 : i32) { "test.dummy_op"() ({ // Call cannot be inlined because "test.dummy" may not support unstructured // control flow in its body. - // CHECK: call @func_with_block_args_location - call @func_with_block_args_location(%arg0) : (i32) -> () + // CHECK: call @func_with_multiple_blocks + call @func_with_multiple_blocks(%arg0) : (i32) -> () "test.terminator"() : () -> () }) : () -> () return } +// CHECK-LABEL: func @func_with_multiple_blocks_callee2 +func.func @func_with_multiple_blocks_callee2(%arg0 : i32, %c : i1) { + %0 = scf.while (%arg1 = %arg0) : (i32) -> (i32) { + // Call cannot be inlined because scf.while does not support unstructured + // control flow in its body. + // CHECK: call @func_with_multiple_blocks + func.call @func_with_multiple_blocks(%arg0) : (i32) -> () + scf.condition(%c) %arg1 : i32 + } do { + ^bb0(%arg1: i32): + scf.yield %arg1 : i32 + } + return +} + // Check that we can handle argument and result attributes. test.conversion_func_op @handle_attr_callee_fn_multi_arg(%arg0 : i16, %arg1 : i16 {"test.handle_argument"}) -> (i16 {"test.handle_result"}, i16) { %0 = arith.addi %arg0, %arg1 : i16