1 // RUN: mlir-opt %s -inline='default-pipeline=''' | FileCheck %s
2 // RUN: mlir-opt %s --mlir-disable-threading -inline='default-pipeline=''' | FileCheck %s
3 // RUN: mlir-opt %s -inline='default-pipeline=''' -mlir-print-debuginfo -mlir-print-local-scope | FileCheck %s --check-prefix INLINE-LOC
4 // RUN: mlir-opt %s -inline | FileCheck %s --check-prefix INLINE_SIMPLIFY
5 // RUN: mlir-opt %s -inline='op-pipelines=func.func(canonicalize,cse)' | FileCheck %s --check-prefix INLINE_SIMPLIFY
7 // Inline a function that takes an argument.
8 func.func @func_with_arg(%c : i32) -> i32 {
9 %b = arith.addi %c, %c : i32
13 // CHECK-LABEL: func @inline_with_arg
14 func.func @inline_with_arg(%arg0 : i32) -> i32 {
15 // CHECK-NEXT: arith.addi
18 %0 = call @func_with_arg(%arg0) : (i32) -> i32
22 // Inline a function that has multiple return operations.
23 func.func @func_with_multi_return(%a : i1) -> (i32) {
24 cf.cond_br %a, ^bb1, ^bb2
27 %const_0 = arith.constant 0 : i32
31 %const_55 = arith.constant 55 : i32
32 return %const_55 : i32
35 // CHECK-LABEL: func @inline_with_multi_return() -> i32
36 func.func @inline_with_multi_return() -> i32 {
37 // CHECK-NEXT: [[VAL_7:%.*]] = arith.constant false
38 // CHECK-NEXT: cf.cond_br [[VAL_7]], ^bb1, ^bb2
40 // CHECK-NEXT: [[VAL_8:%.*]] = arith.constant 0 : i32
41 // CHECK-NEXT: cf.br ^bb3([[VAL_8]] : i32)
43 // CHECK-NEXT: [[VAL_9:%.*]] = arith.constant 55 : i32
44 // CHECK-NEXT: cf.br ^bb3([[VAL_9]] : i32)
45 // CHECK: ^bb3([[VAL_10:%.*]]: i32):
46 // CHECK-NEXT: return [[VAL_10]] : i32
48 %false = arith.constant false
49 %x = call @func_with_multi_return(%false) : (i1) -> i32
53 // Check that location information is updated for inlined instructions.
54 func.func @func_with_locations(%c : i32) -> i32 {
55 %b = arith.addi %c, %c : i32 loc("mysource.cc":10:8)
56 return %b : i32 loc("mysource.cc":11:2)
59 // INLINE-LOC-LABEL: func @inline_with_locations
60 func.func @inline_with_locations(%arg0 : i32) -> i32 {
61 // INLINE-LOC-NEXT: arith.addi %{{.*}}, %{{.*}} : i32 loc(callsite("mysource.cc":10:8 at "mysource.cc":55:14))
62 // INLINE-LOC-NEXT: return
64 %0 = call @func_with_locations(%arg0) : (i32) -> i32 loc("mysource.cc":55:14)
69 // Check that external function declarations are not inlined.
70 func.func private @func_external()
72 // CHECK-LABEL: func @no_inline_external
73 func.func @no_inline_external() {
74 // CHECK-NEXT: call @func_external()
75 call @func_external() : () -> ()
79 // Check that multiple levels of calls will be inlined.
80 func.func @multilevel_func_a() {
83 func.func @multilevel_func_b() {
84 call @multilevel_func_a() : () -> ()
88 // CHECK-LABEL: func @inline_multilevel
89 func.func @inline_multilevel() {
91 %fn = "test.functional_region_op"() ({
92 call @multilevel_func_b() : () -> ()
93 "test.return"() : () -> ()
96 call_indirect %fn() : () -> ()
100 // Check that recursive calls are not inlined.
101 // CHECK-LABEL: func @no_inline_recursive
102 func.func @no_inline_recursive() {
103 // CHECK: test.functional_region_op
104 // CHECK-NOT: test.functional_region_op
105 %fn = "test.functional_region_op"() ({
106 call @no_inline_recursive() : () -> ()
107 "test.return"() : () -> ()
108 }) : () -> (() -> ())
112 // Check that we can convert types for inputs and results as necessary.
113 func.func @convert_callee_fn(%arg : i32) -> i32 {
116 func.func @convert_callee_fn_multi_arg(%a : i32, %b : i32) -> () {
119 func.func @convert_callee_fn_multi_res() -> (i32, i32) {
120 %res = arith.constant 0 : i32
121 return %res, %res : i32, i32
124 // CHECK-LABEL: func @inline_convert_call
125 func.func @inline_convert_call() -> i16 {
126 // CHECK: %[[INPUT:.*]] = arith.constant
127 %test_input = arith.constant 0 : i16
129 // CHECK: %[[CAST_INPUT:.*]] = "test.cast"(%[[INPUT]]) : (i16) -> i32
130 // CHECK: %[[CAST_RESULT:.*]] = "test.cast"(%[[CAST_INPUT]]) : (i32) -> i16
131 // CHECK-NEXT: return %[[CAST_RESULT]]
132 %res = "test.conversion_call_op"(%test_input) { callee=@convert_callee_fn } : (i16) -> (i16)
136 func.func @convert_callee_fn_multiblock() -> i32 {
139 %0 = arith.constant 0 : i32
143 // CHECK-LABEL: func @inline_convert_result_multiblock
144 func.func @inline_convert_result_multiblock() -> i16 {
145 // CHECK: cf.br ^bb1 {inlined_conversion}
147 // CHECK: %[[C:.+]] = arith.constant {inlined_conversion} 0 : i32
148 // CHECK: cf.br ^bb2(%[[C]] : i32)
149 // CHECK: ^bb2(%[[BBARG:.+]]: i32):
150 // CHECK: %[[CAST_RESULT:.+]] = "test.cast"(%[[BBARG]]) : (i32) -> i16
151 // CHECK: return %[[CAST_RESULT]] : i16
153 %res = "test.conversion_call_op"() { callee=@convert_callee_fn_multiblock } : () -> (i16)
157 // CHECK-LABEL: func @no_inline_convert_call
158 func.func @no_inline_convert_call() {
159 // CHECK: "test.conversion_call_op"
160 %test_input_i16 = arith.constant 0 : i16
161 %test_input_i64 = arith.constant 0 : i64
162 "test.conversion_call_op"(%test_input_i16, %test_input_i64) { callee=@convert_callee_fn_multi_arg } : (i16, i64) -> ()
164 // CHECK: "test.conversion_call_op"
165 %res_2:2 = "test.conversion_call_op"() { callee=@convert_callee_fn_multi_res } : () -> (i16, i64)
169 // Check that we properly simplify when inlining.
170 func.func @simplify_return_constant() -> i32 {
171 %res = arith.constant 0 : i32
175 func.func @simplify_return_reference() -> (() -> i32) {
176 %res = constant @simplify_return_constant : () -> i32
177 return %res : () -> i32
180 // INLINE_SIMPLIFY-LABEL: func @inline_simplify
181 func.func @inline_simplify() -> i32 {
182 // INLINE_SIMPLIFY-NEXT: %[[CST:.*]] = arith.constant 0 : i32
183 // INLINE_SIMPLIFY-NEXT: return %[[CST]]
184 %fn = call @simplify_return_reference() : () -> (() -> i32)
185 %res = call_indirect %fn() : () -> i32
189 // CHECK-LABEL: func @no_inline_invalid_call
190 func.func @no_inline_invalid_call() -> i32 {
191 %res = "test.conversion_call_op"() { callee=@convert_callee_fn_multiblock, noinline } : () -> (i32)
195 func.func @gpu_alloc() -> memref<1024xf32> {
196 %m = gpu.alloc [] () : memref<1024xf32>
197 return %m : memref<1024xf32>
200 // CHECK-LABEL: func @inline_gpu_ops
201 func.func @inline_gpu_ops() -> memref<1024xf32> {
202 // CHECK-NEXT: gpu.alloc
203 %m = call @gpu_alloc() : () -> memref<1024xf32>
204 return %m : memref<1024xf32>
207 // Test block arguments location propagation.
208 // Use two call-sites to force cloning.
209 func.func @func_with_block_args_location(%arg0 : i32) {
210 cf.br ^bb1(%arg0 : i32)
211 ^bb1(%x : i32 loc("foo")):
212 "test.foo" (%x) : (i32) -> () loc("bar")
216 // INLINE-LOC-LABEL: func @func_with_block_args_location_callee1
218 // INLINE-LOC: ^bb{{[0-9]+}}(%{{.*}}: i32 loc(callsite("foo" at "bar"))
219 func.func @func_with_block_args_location_callee1(%arg0 : i32) {
220 call @func_with_block_args_location(%arg0) : (i32) -> () loc("bar")
224 // CHECK-LABEL: func @func_with_block_args_location_callee2
225 func.func @func_with_block_args_location_callee2(%arg0 : i32) {
226 call @func_with_block_args_location(%arg0) : (i32) -> ()
230 func.func @func_with_multiple_blocks(%arg0 : i32) {
231 cf.br ^bb1(%arg0 : i32)
233 "test.foo" (%x) : (i32) -> () loc("bar")
237 // CHECK-LABEL: func @func_with_multiple_blocks_callee1
238 func.func @func_with_multiple_blocks_callee1(%arg0 : i32) {
240 // Call cannot be inlined because "test.dummy" may not support unstructured
241 // control flow in its body.
242 // CHECK: call @func_with_multiple_blocks
243 call @func_with_multiple_blocks(%arg0) : (i32) -> ()
244 "test.terminator"() : () -> ()
249 // CHECK-LABEL: func @func_with_multiple_blocks_callee2
250 func.func @func_with_multiple_blocks_callee2(%arg0 : i32, %c : i1) {
251 %0 = scf.while (%arg1 = %arg0) : (i32) -> (i32) {
252 // Call cannot be inlined because scf.while does not support unstructured
253 // control flow in its body.
254 // CHECK: call @func_with_multiple_blocks
255 func.call @func_with_multiple_blocks(%arg0) : (i32) -> ()
256 scf.condition(%c) %arg1 : i32
259 scf.yield %arg1 : i32
264 // Check that we can handle argument and result attributes.
265 test.conversion_func_op @handle_attr_callee_fn_multi_arg(%arg0 : i16, %arg1 : i16 {"test.handle_argument"}) -> (i16 {"test.handle_result"}, i16) {
266 %0 = arith.addi %arg0, %arg1 : i16
267 %1 = arith.subi %arg0, %arg1 : i16
268 "test.return"(%0, %1) : (i16, i16) -> ()
270 test.conversion_func_op @handle_attr_callee_fn(%arg0 : i32 {"test.handle_argument"}) -> (i32 {"test.handle_result"}) {
271 "test.return"(%arg0) : (i32) -> ()
274 // CHECK-LABEL: func @inline_handle_attr_call
275 // CHECK-SAME: %[[ARG0:[a-zA-Z0-9]+]]
276 // CHECK-SAME: %[[ARG1:[a-zA-Z0-9]+]]
277 func.func @inline_handle_attr_call(%arg0 : i16, %arg1 : i16) -> (i16, i16) {
279 // CHECK: %[[CHANGE_INPUT:.*]] = "test.type_changer"(%[[ARG1]]) : (i16) -> i16
280 // CHECK: %[[SUM:.*]] = arith.addi %[[ARG0]], %[[CHANGE_INPUT]]
281 // CHECK: %[[DIFF:.*]] = arith.subi %[[ARG0]], %[[CHANGE_INPUT]]
282 // CHECK: %[[CHANGE_RESULT:.*]] = "test.type_changer"(%[[SUM]]) : (i16) -> i16
283 // CHECK-NEXT: return %[[CHANGE_RESULT]], %[[DIFF]]
284 %res0, %res1 = "test.conversion_call_op"(%arg0, %arg1) { callee=@handle_attr_callee_fn_multi_arg } : (i16, i16) -> (i16, i16)
285 return %res0, %res1 : i16, i16
288 // CHECK-LABEL: func @inline_convert_and_handle_attr_call
289 // CHECK-SAME: %[[ARG0:[a-zA-Z0-9]+]]
290 func.func @inline_convert_and_handle_attr_call(%arg0 : i16) -> (i16) {
292 // CHECK: %[[CAST_INPUT:.*]] = "test.cast"(%[[ARG0]]) : (i16) -> i32
293 // CHECK: %[[CHANGE_INPUT:.*]] = "test.type_changer"(%[[CAST_INPUT]]) : (i32) -> i32
294 // CHECK: %[[CHANGE_RESULT:.*]] = "test.type_changer"(%[[CHANGE_INPUT]]) : (i32) -> i32
295 // CHECK: %[[CAST_RESULT:.*]] = "test.cast"(%[[CHANGE_RESULT]]) : (i32) -> i16
296 // CHECK: return %[[CAST_RESULT]]
297 %res = "test.conversion_call_op"(%arg0) { callee=@handle_attr_callee_fn } : (i16) -> (i16)
301 // Check a function with complex ops is inlined.
302 func.func @double_square_complex(%cplx: complex<f32>) -> complex<f32> {
303 %double = complex.add %cplx, %cplx : complex<f32>
304 %square = complex.mul %double, %double : complex<f32>
305 return %square : complex<f32>
308 // CHECK-LABEL: func @inline_with_complex_ops
309 func.func @inline_with_complex_ops() -> complex<f32> {
310 %c1 = arith.constant 1.0 : f32
311 %c2 = arith.constant 2.0 : f32
312 %c = complex.create %c1, %c2 : complex<f32>
314 // CHECK: complex.add
315 // CHECK: complex.mul
317 %r = call @double_square_complex(%c) : (complex<f32>) -> (complex<f32>)
318 return %r : complex<f32>