1// Test rewrite of functions that return fir.array<>, fir.type<>, fir.box<> to 2// functions that take an additional argument for the result. 3 4// RUN: fir-opt %s --abstract-result-opt | FileCheck %s 5// RUN: fir-opt %s --abstract-result-opt=abstract-result-as-box | FileCheck %s --check-prefix=CHECK-BOX 6 7// ----------------------- Test declaration rewrite ---------------------------- 8 9// CHECK-LABEL: func private @arrayfunc(!fir.ref<!fir.array<?xf32>>, i32) 10// CHECK-BOX-LABEL: func private @arrayfunc(!fir.box<!fir.array<?xf32>>, i32) 11func private @arrayfunc(i32) -> !fir.array<?xf32> 12 13// CHECK-LABEL: func private @derivedfunc(!fir.ref<!fir.type<t{x:f32}>>, f32) 14// CHECK-BOX-LABEL: func private @derivedfunc(!fir.box<!fir.type<t{x:f32}>>, f32) 15func private @derivedfunc(f32) -> !fir.type<t{x:f32}> 16 17// CHECK-LABEL: func private @boxfunc(!fir.ref<!fir.box<!fir.heap<f64>>>, i64) 18// CHECK-BOX-LABEL: func private @boxfunc(!fir.ref<!fir.box<!fir.heap<f64>>>, i64) 19func private @boxfunc(i64) -> !fir.box<!fir.heap<f64>> 20 21 22// ------------------------ Test callee rewrite -------------------------------- 23 24// CHECK-LABEL: func private @arrayfunc_callee( 25// CHECK-SAME: %[[buffer:.*]]: !fir.ref<!fir.array<?xf32>>, %[[n:.*]]: index) { 26// CHECK-BOX-LABEL: func private @arrayfunc_callee( 27// CHECK-BOX-SAME: %[[box:.*]]: !fir.box<!fir.array<?xf32>>, %[[n:.*]]: index) { 28func private @arrayfunc_callee(%n : index) -> !fir.array<?xf32> { 29 %buffer = fir.alloca !fir.array<?xf32>, %n 30 // Do something with result (res(4) = 42.) 31 %c4 = constant 4 : i64 32 %coor = fir.coordinate_of %buffer, %c4 : (!fir.ref<!fir.array<?xf32>>, i64) -> !fir.ref<f32> 33 %cst = constant 4.200000e+01 : f32 34 fir.store %cst to %coor : !fir.ref<f32> 35 %res = fir.load %buffer : !fir.ref<!fir.array<?xf32>> 36 return %res : !fir.array<?xf32> 37 38 // CHECK-DAG: %[[coor:.*]] = fir.coordinate_of %[[buffer]], %{{.*}} : (!fir.ref<!fir.array<?xf32>>, i64) -> !fir.ref<f32> 39 // CHECK-DAG: fir.store %{{.*}} to %[[coor]] : !fir.ref<f32> 40 // CHECK: return 41 42 // CHECK-BOX: %[[buffer:.*]] = fir.box_addr %[[box]] : (!fir.box<!fir.array<?xf32>>) -> !fir.ref<!fir.array<?xf32>> 43 // CHECK-BOX-DAG: %[[coor:.*]] = fir.coordinate_of %[[buffer]], %{{.*}} : (!fir.ref<!fir.array<?xf32>>, i64) -> !fir.ref<f32> 44 // CHECK-BOX-DAG: fir.store %{{.*}} to %[[coor]] : !fir.ref<f32> 45 // CHECK-BOX: return 46} 47 48 49// CHECK-LABEL: func @derivedfunc_callee( 50// CHECK-SAME: %[[buffer:.*]]: !fir.ref<!fir.type<t{x:f32}>>, %[[v:.*]]: f32) { 51// CHECK-BOX-LABEL: func @derivedfunc_callee( 52// CHECK-BOX-SAME: %[[box:.*]]: !fir.box<!fir.type<t{x:f32}>>, %[[v:.*]]: f32) { 53func @derivedfunc_callee(%v: f32) -> !fir.type<t{x:f32}> { 54 %buffer = fir.alloca !fir.type<t{x:f32}> 55 %0 = fir.field_index x, !fir.type<t{x:f32}> 56 %1 = fir.coordinate_of %buffer, %0 : (!fir.ref<!fir.type<t{x:f32}>>, !fir.field) -> !fir.ref<f32> 57 fir.store %v to %1 : !fir.ref<f32> 58 %res = fir.load %buffer : !fir.ref<!fir.type<t{x:f32}>> 59 return %res : !fir.type<t{x:f32}> 60 61 // CHECK: %[[coor:.*]] = fir.coordinate_of %[[buffer]], %{{.*}} : (!fir.ref<!fir.type<t{x:f32}>>, !fir.field) -> !fir.ref<f32> 62 // CHECK: fir.store %[[v]] to %[[coor]] : !fir.ref<f32> 63 // CHECK: return 64 65 // CHECK-BOX: %[[buffer:.*]] = fir.box_addr %[[box]] : (!fir.box<!fir.type<t{x:f32}>>) -> !fir.ref<!fir.type<t{x:f32}>> 66 // CHECK-BOX: %[[coor:.*]] = fir.coordinate_of %[[buffer]], %{{.*}} : (!fir.ref<!fir.type<t{x:f32}>>, !fir.field) -> !fir.ref<f32> 67 // CHECK-BOX: fir.store %[[v]] to %[[coor]] : !fir.ref<f32> 68 // CHECK-BOX: return 69} 70 71// CHECK-LABEL: func @boxfunc_callee( 72// CHECK-SAME: %[[buffer:.*]]: !fir.ref<!fir.box<!fir.heap<f64>>>) { 73// CHECK-BOX-LABEL: func @boxfunc_callee( 74// CHECK-BOX-SAME: %[[buffer:.*]]: !fir.ref<!fir.box<!fir.heap<f64>>>) { 75func @boxfunc_callee() -> !fir.box<!fir.heap<f64>> { 76 %alloc = fir.allocmem f64 77 %res = fir.embox %alloc : (!fir.heap<f64>) -> !fir.box<!fir.heap<f64>> 78 return %res : !fir.box<!fir.heap<f64>> 79 // CHECK: %[[box:.*]] = fir.embox %{{.*}} : (!fir.heap<f64>) -> !fir.box<!fir.heap<f64>> 80 // CHECK: fir.store %[[box]] to %[[buffer]] : !fir.ref<!fir.box<!fir.heap<f64>>> 81 // CHECK: return 82 83 // CHECK-BOX: %[[box:.*]] = fir.embox %{{.*}} : (!fir.heap<f64>) -> !fir.box<!fir.heap<f64>> 84 // CHECK-BOX: fir.store %[[box]] to %[[buffer]] : !fir.ref<!fir.box<!fir.heap<f64>>> 85 // CHECK-BOX: return 86} 87 88// ------------------------ Test caller rewrite -------------------------------- 89 90// CHECK-LABEL: func @call_arrayfunc() { 91// CHECK-BOX-LABEL: func @call_arrayfunc() { 92func @call_arrayfunc() { 93 %c100 = constant 100 : index 94 %buffer = fir.alloca !fir.array<?xf32>, %c100 95 %shape = fir.shape %c100 : (index) -> !fir.shape<1> 96 %res = fir.call @arrayfunc_callee(%c100) : (index) -> !fir.array<?xf32> 97 fir.save_result %res to %buffer(%shape) : !fir.array<?xf32>, !fir.ref<!fir.array<?xf32>>, !fir.shape<1> 98 return 99 100 // CHECK: %[[c100:.*]] = constant 100 : index 101 // CHECK: %[[buffer:.*]] = fir.alloca !fir.array<?xf32>, %[[c100]] 102 // CHECK: fir.call @arrayfunc_callee(%[[buffer]], %[[c100]]) : (!fir.ref<!fir.array<?xf32>>, index) -> () 103 // CHECK-NOT: fir.save_result 104 105 // CHECK-BOX: %[[c100:.*]] = constant 100 : index 106 // CHECK-BOX: %[[buffer:.*]] = fir.alloca !fir.array<?xf32>, %[[c100]] 107 // CHECK-BOX: %[[shape:.*]] = fir.shape %[[c100]] : (index) -> !fir.shape<1> 108 // CHECK-BOX: %[[box:.*]] = fir.embox %[[buffer]](%[[shape]]) : (!fir.ref<!fir.array<?xf32>>, !fir.shape<1>) -> !fir.box<!fir.array<?xf32>> 109 // CHECK-BOX: fir.call @arrayfunc_callee(%[[box]], %[[c100]]) : (!fir.box<!fir.array<?xf32>>, index) -> () 110 // CHECK-BOX-NOT: fir.save_result 111} 112 113// CHECK-LABEL: func @call_derivedfunc() { 114// CHECK-BOX-LABEL: func @call_derivedfunc() { 115func @call_derivedfunc() { 116 %buffer = fir.alloca !fir.type<t{x:f32}> 117 %cst = constant 4.200000e+01 : f32 118 %res = fir.call @derivedfunc_callee(%cst) : (f32) -> !fir.type<t{x:f32}> 119 fir.save_result %res to %buffer : !fir.type<t{x:f32}>, !fir.ref<!fir.type<t{x:f32}>> 120 return 121 // CHECK: %[[buffer:.*]] = fir.alloca !fir.type<t{x:f32}> 122 // CHECK: %[[cst:.*]] = constant {{.*}} : f32 123 // CHECK: fir.call @derivedfunc_callee(%[[buffer]], %[[cst]]) : (!fir.ref<!fir.type<t{x:f32}>>, f32) -> () 124 // CHECK-NOT: fir.save_result 125 126 // CHECK-BOX: %[[buffer:.*]] = fir.alloca !fir.type<t{x:f32}> 127 // CHECK-BOX: %[[cst:.*]] = constant {{.*}} : f32 128 // CHECK-BOX: %[[box:.*]] = fir.embox %[[buffer]] : (!fir.ref<!fir.type<t{x:f32}>>) -> !fir.box<!fir.type<t{x:f32}>> 129 // CHECK-BOX: fir.call @derivedfunc_callee(%[[box]], %[[cst]]) : (!fir.box<!fir.type<t{x:f32}>>, f32) -> () 130 // CHECK-BOX-NOT: fir.save_result 131} 132 133func private @derived_lparams_func() -> !fir.type<t2(l1:i32,l2:i32){x:f32}> 134 135// CHECK-LABEL: func @call_derived_lparams_func( 136// CHECK-SAME: %[[buffer:.*]]: !fir.ref<!fir.type<t2(l1:i32,l2:i32){x:f32}>> 137// CHECK-BOX-LABEL: func @call_derived_lparams_func( 138// CHECK-BOX-SAME: %[[buffer:.*]]: !fir.ref<!fir.type<t2(l1:i32,l2:i32){x:f32}>> 139func @call_derived_lparams_func(%buffer: !fir.ref<!fir.type<t2(l1:i32,l2:i32){x:f32}>>) { 140 %l1 = constant 3 : i32 141 %l2 = constant 5 : i32 142 %res = fir.call @derived_lparams_func() : () -> !fir.type<t2(l1:i32,l2:i32){x:f32}> 143 fir.save_result %res to %buffer typeparams %l1, %l2 : !fir.type<t2(l1:i32,l2:i32){x:f32}>, !fir.ref<!fir.type<t2(l1:i32,l2:i32){x:f32}>>, i32, i32 144 return 145 146 // CHECK: %[[l1:.*]] = constant 3 : i32 147 // CHECK: %[[l2:.*]] = constant 5 : i32 148 // CHECK: fir.call @derived_lparams_func(%[[buffer]]) : (!fir.ref<!fir.type<t2(l1:i32,l2:i32){x:f32}>>) -> () 149 // CHECK-NOT: fir.save_result 150 151 // CHECK-BOX: %[[l1:.*]] = constant 3 : i32 152 // CHECK-BOX: %[[l2:.*]] = constant 5 : i32 153 // CHECK-BOX: %[[box:.*]] = fir.embox %[[buffer]] typeparams %[[l1]], %[[l2]] : (!fir.ref<!fir.type<t2(l1:i32,l2:i32){x:f32}>>, i32, i32) -> !fir.box<!fir.type<t2(l1:i32,l2:i32){x:f32}>> 154 // CHECK-BOX: fir.call @derived_lparams_func(%[[box]]) : (!fir.box<!fir.type<t2(l1:i32,l2:i32){x:f32}>>) -> () 155 // CHECK-BOX-NOT: fir.save_result 156} 157 158// CHECK-LABEL: func @call_boxfunc() { 159// CHECK-BOX-LABEL: func @call_boxfunc() { 160func @call_boxfunc() { 161 %buffer = fir.alloca !fir.box<!fir.heap<f64>> 162 %res = fir.call @boxfunc_callee() : () -> !fir.box<!fir.heap<f64>> 163 fir.save_result %res to %buffer: !fir.box<!fir.heap<f64>>, !fir.ref<!fir.box<!fir.heap<f64>>> 164 return 165 166 // CHECK: %[[buffer:.*]] = fir.alloca !fir.box<!fir.heap<f64>> 167 // CHECK: fir.call @boxfunc_callee(%[[buffer]]) : (!fir.ref<!fir.box<!fir.heap<f64>>>) -> () 168 // CHECK-NOT: fir.save_result 169 170 // CHECK-BOX: %[[buffer:.*]] = fir.alloca !fir.box<!fir.heap<f64>> 171 // CHECK-BOX: fir.call @boxfunc_callee(%[[buffer]]) : (!fir.ref<!fir.box<!fir.heap<f64>>>) -> () 172 // CHECK-BOX-NOT: fir.save_result 173} 174 175func private @chararrayfunc(index, index) -> !fir.array<?x!fir.char<1,?>> 176 177// CHECK-LABEL: func @call_chararrayfunc() { 178// CHECK-BOX-LABEL: func @call_chararrayfunc() { 179func @call_chararrayfunc() { 180 %c100 = constant 100 : index 181 %c50 = constant 50 : index 182 %buffer = fir.alloca !fir.array<?x!fir.char<1,?>>(%c100 : index), %c50 183 %shape = fir.shape %c100 : (index) -> !fir.shape<1> 184 %res = fir.call @chararrayfunc(%c100, %c50) : (index, index) -> !fir.array<?x!fir.char<1,?>> 185 fir.save_result %res to %buffer(%shape) typeparams %c50 : !fir.array<?x!fir.char<1,?>>, !fir.ref<!fir.array<?x!fir.char<1,?>>>, !fir.shape<1>, index 186 return 187 188 // CHECK: %[[c100:.*]] = constant 100 : index 189 // CHECK: %[[c50:.*]] = constant 50 : index 190 // CHECK: %[[buffer:.*]] = fir.alloca !fir.array<?x!fir.char<1,?>>(%[[c100]] : index), %[[c50]] 191 // CHECK: fir.call @chararrayfunc(%[[buffer]], %[[c100]], %[[c50]]) : (!fir.ref<!fir.array<?x!fir.char<1,?>>>, index, index) -> () 192 // CHECK-NOT: fir.save_result 193 194 // CHECK-BOX: %[[c100:.*]] = constant 100 : index 195 // CHECK-BOX: %[[c50:.*]] = constant 50 : index 196 // CHECK-BOX: %[[buffer:.*]] = fir.alloca !fir.array<?x!fir.char<1,?>>(%[[c100]] : index), %[[c50]] 197 // CHECK-BOX: %[[shape:.*]] = fir.shape %[[c100]] : (index) -> !fir.shape<1> 198 // CHECK-BOX: %[[box:.*]] = fir.embox %[[buffer]](%[[shape]]) typeparams %[[c50]] : (!fir.ref<!fir.array<?x!fir.char<1,?>>>, !fir.shape<1>, index) -> !fir.box<!fir.array<?x!fir.char<1,?>>> 199 // CHECK-BOX: fir.call @chararrayfunc(%[[box]], %[[c100]], %[[c50]]) : (!fir.box<!fir.array<?x!fir.char<1,?>>>, index, index) -> () 200 // CHECK-BOX-NOT: fir.save_result 201} 202 203// ------------------------ Test fir.address_of rewrite ------------------------ 204 205func private @takesfuncarray((i32) -> !fir.array<?xf32>) 206 207// CHECK-LABEL: func @test_address_of() { 208// CHECK-BOX-LABEL: func @test_address_of() { 209func @test_address_of() { 210 %0 = fir.address_of(@arrayfunc) : (i32) -> !fir.array<?xf32> 211 fir.call @takesfuncarray(%0) : ((i32) -> !fir.array<?xf32>) -> () 212 return 213 214 // CHECK: %[[addrOf:.*]] = fir.address_of(@arrayfunc) : (!fir.ref<!fir.array<?xf32>>, i32) -> () 215 // CHECK: %[[conv:.*]] = fir.convert %[[addrOf]] : ((!fir.ref<!fir.array<?xf32>>, i32) -> ()) -> ((i32) -> !fir.array<?xf32>) 216 // CHECK: fir.call @takesfuncarray(%[[conv]]) : ((i32) -> !fir.array<?xf32>) -> () 217 218 // CHECK-BOX: %[[addrOf:.*]] = fir.address_of(@arrayfunc) : (!fir.box<!fir.array<?xf32>>, i32) -> () 219 // CHECK-BOX: %[[conv:.*]] = fir.convert %[[addrOf]] : ((!fir.box<!fir.array<?xf32>>, i32) -> ()) -> ((i32) -> !fir.array<?xf32>) 220 // CHECK-BOX: fir.call @takesfuncarray(%[[conv]]) : ((i32) -> !fir.array<?xf32>) -> () 221 222} 223 224// ----------------------- Test indirect calls rewrite ------------------------ 225 226// CHECK-LABEL: func @test_indirect_calls( 227// CHECK-SAME: %[[arg0:.*]]: () -> ()) { 228// CHECK-BOX-LABEL: func @test_indirect_calls( 229// CHECK-BOX-SAME: %[[arg0:.*]]: () -> ()) { 230func @test_indirect_calls(%arg0: () -> ()) { 231 %c100 = constant 100 : index 232 %buffer = fir.alloca !fir.array<?xf32>, %c100 233 %shape = fir.shape %c100 : (index) -> !fir.shape<1> 234 %0 = fir.convert %arg0 : (() -> ()) -> ((index) -> !fir.array<?xf32>) 235 %res = fir.call %0(%c100) : (index) -> !fir.array<?xf32> 236 fir.save_result %res to %buffer(%shape) : !fir.array<?xf32>, !fir.ref<!fir.array<?xf32>>, !fir.shape<1> 237 return 238 239 // CHECK: %[[c100:.*]] = constant 100 : index 240 // CHECK: %[[buffer:.*]] = fir.alloca !fir.array<?xf32>, %[[c100]] 241 // CHECK: %[[shape:.*]] = fir.shape %[[c100]] : (index) -> !fir.shape<1> 242 // CHECK: %[[original_conv:.*]] = fir.convert %[[arg0]] : (() -> ()) -> ((index) -> !fir.array<?xf32>) 243 // CHECK: %[[conv:.*]] = fir.convert %[[original_conv]] : ((index) -> !fir.array<?xf32>) -> ((!fir.ref<!fir.array<?xf32>>, index) -> ()) 244 // CHECK: fir.call %[[conv]](%[[buffer]], %c100) : (!fir.ref<!fir.array<?xf32>>, index) -> () 245 // CHECK-NOT: fir.save_result 246 247 // CHECK-BOX: %[[c100:.*]] = constant 100 : index 248 // CHECK-BOX: %[[buffer:.*]] = fir.alloca !fir.array<?xf32>, %[[c100]] 249 // CHECK-BOX: %[[shape:.*]] = fir.shape %[[c100]] : (index) -> !fir.shape<1> 250 // CHECK-BOX: %[[original_conv:.*]] = fir.convert %[[arg0]] : (() -> ()) -> ((index) -> !fir.array<?xf32>) 251 // CHECK-BOX: %[[box:.*]] = fir.embox %[[buffer]](%[[shape]]) : (!fir.ref<!fir.array<?xf32>>, !fir.shape<1>) -> !fir.box<!fir.array<?xf32>> 252 // CHECK-BOX: %[[conv:.*]] = fir.convert %[[original_conv]] : ((index) -> !fir.array<?xf32>) -> ((!fir.box<!fir.array<?xf32>>, index) -> ()) 253 // CHECK-BOX: fir.call %[[conv]](%[[box]], %c100) : (!fir.box<!fir.array<?xf32>>, index) -> () 254 // CHECK-BOX-NOT: fir.save_result 255} 256