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