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