1// RUN: mlir-opt %s -inline="disable-simplify" | FileCheck %s
2// RUN: mlir-opt %s -inline="disable-simplify" -mlir-print-debuginfo | FileCheck %s --check-prefix INLINE-LOC
3// RUN: mlir-opt %s -inline | FileCheck %s --check-prefix INLINE_SIMPLIFY
4
5// Inline a function that takes an argument.
6func @func_with_arg(%c : i32) -> i32 {
7  %b = addi %c, %c : i32
8  return %b : i32
9}
10
11// CHECK-LABEL: func @inline_with_arg
12func @inline_with_arg(%arg0 : i32) -> i32 {
13  // CHECK-NEXT: addi
14  // CHECK-NEXT: return
15
16  %0 = call @func_with_arg(%arg0) : (i32) -> i32
17  return %0 : i32
18}
19
20// Inline a function that has multiple return operations.
21func @func_with_multi_return(%a : i1) -> (i32) {
22  cond_br %a, ^bb1, ^bb2
23
24^bb1:
25  %const_0 = constant 0 : i32
26  return %const_0 : i32
27
28^bb2:
29  %const_55 = constant 55 : i32
30  return %const_55 : i32
31}
32
33// CHECK-LABEL: func @inline_with_multi_return() -> i32
34func @inline_with_multi_return() -> i32 {
35// CHECK-NEXT:    [[VAL_7:%.*]] = constant 0 : i1
36// CHECK-NEXT:    cond_br [[VAL_7]], ^bb1, ^bb2
37// CHECK:       ^bb1:
38// CHECK-NEXT:    [[VAL_8:%.*]] = constant 0 : i32
39// CHECK-NEXT:    br ^bb3([[VAL_8]] : i32)
40// CHECK:       ^bb2:
41// CHECK-NEXT:    [[VAL_9:%.*]] = constant 55 : i32
42// CHECK-NEXT:    br ^bb3([[VAL_9]] : i32)
43// CHECK:       ^bb3([[VAL_10:%.*]]: i32):
44// CHECK-NEXT:    return [[VAL_10]] : i32
45
46  %false = constant 0 : i1
47  %x = call @func_with_multi_return(%false) : (i1) -> i32
48  return %x : i32
49}
50
51// Check that location information is updated for inlined instructions.
52func @func_with_locations(%c : i32) -> i32 {
53  %b = addi %c, %c : i32 loc("mysource.cc":10:8)
54  return %b : i32 loc("mysource.cc":11:2)
55}
56
57// INLINE-LOC-LABEL: func @inline_with_locations
58func @inline_with_locations(%arg0 : i32) -> i32 {
59  // INLINE-LOC-NEXT: addi %{{.*}}, %{{.*}} : i32 loc(callsite("mysource.cc":10:8 at "mysource.cc":55:14))
60  // INLINE-LOC-NEXT: return
61
62  %0 = call @func_with_locations(%arg0) : (i32) -> i32 loc("mysource.cc":55:14)
63  return %0 : i32
64}
65
66
67// Check that external functions are not inlined.
68func @func_external()
69
70// CHECK-LABEL: func @no_inline_external
71func @no_inline_external() {
72  // CHECK-NEXT: call @func_external()
73  call @func_external() : () -> ()
74  return
75}
76
77// Check that multiple levels of calls will be inlined.
78func @multilevel_func_a() {
79  return
80}
81func @multilevel_func_b() {
82  call @multilevel_func_a() : () -> ()
83  return
84}
85
86// CHECK-LABEL: func @inline_multilevel
87func @inline_multilevel() {
88  // CHECK-NOT: call
89  %fn = "test.functional_region_op"() ({
90    call @multilevel_func_b() : () -> ()
91    "test.return"() : () -> ()
92  }) : () -> (() -> ())
93
94  call_indirect %fn() : () -> ()
95  return
96}
97
98// Check that recursive calls are not inlined.
99// CHECK-LABEL: func @no_inline_recursive
100func @no_inline_recursive() {
101  // CHECK: test.functional_region_op
102  // CHECK-NOT: test.functional_region_op
103  %fn = "test.functional_region_op"() ({
104    call @no_inline_recursive() : () -> ()
105    "test.return"() : () -> ()
106  }) : () -> (() -> ())
107  return
108}
109
110// Check that we can convert types for inputs and results as necessary.
111func @convert_callee_fn(%arg : i32) -> i32 {
112  return %arg : i32
113}
114func @convert_callee_fn_multi_arg(%a : i32, %b : i32) -> () {
115  return
116}
117func @convert_callee_fn_multi_res() -> (i32, i32) {
118  %res = constant 0 : i32
119  return %res, %res : i32, i32
120}
121
122// CHECK-LABEL: func @inline_convert_call
123func @inline_convert_call() -> i16 {
124  // CHECK: %[[INPUT:.*]] = constant
125  %test_input = constant 0 : i16
126
127  // CHECK: %[[CAST_INPUT:.*]] = "test.cast"(%[[INPUT]]) : (i16) -> i32
128  // CHECK: %[[CAST_RESULT:.*]] = "test.cast"(%[[CAST_INPUT]]) : (i32) -> i16
129  // CHECK-NEXT: return %[[CAST_RESULT]]
130  %res = "test.conversion_call_op"(%test_input) { callee=@convert_callee_fn } : (i16) -> (i16)
131  return %res : i16
132}
133
134// CHECK-LABEL: func @no_inline_convert_call
135func @no_inline_convert_call() {
136  // CHECK: "test.conversion_call_op"
137  %test_input_i16 = constant 0 : i16
138  %test_input_i64 = constant 0 : i64
139  "test.conversion_call_op"(%test_input_i16, %test_input_i64) { callee=@convert_callee_fn_multi_arg } : (i16, i64) -> ()
140
141  // CHECK: "test.conversion_call_op"
142  %res_2:2 = "test.conversion_call_op"() { callee=@convert_callee_fn_multi_res } : () -> (i16, i64)
143  return
144}
145
146// Check that we properly simplify when inlining.
147func @simplify_return_constant() -> i32 {
148  %res = constant 0 : i32
149  return %res : i32
150}
151
152func @simplify_return_reference() -> (() -> i32) {
153  %res = constant @simplify_return_constant : () -> i32
154  return %res : () -> i32
155}
156
157// INLINE_SIMPLIFY-LABEL: func @inline_simplify
158func @inline_simplify() -> i32 {
159  // INLINE_SIMPLIFY-NEXT: %[[CST:.*]] = constant 0 : i32
160  // INLINE_SIMPLIFY-NEXT: return %[[CST]]
161  %fn = call @simplify_return_reference() : () -> (() -> i32)
162  %res = call_indirect %fn() : () -> i32
163  return %res : i32
164}
165