1 // Test for the array-value-copy pass
2 // RUN: fir-opt --split-input-file --array-value-copy %s | FileCheck %s
4 // Test simple fir.array_load/fir.array_fetch conversion to fir.array_coor
5 func.func @array_fetch_conversion(%arr1 : !fir.ref<!fir.array<?x?xf32>>, %m: index, %n: index) {
6 %c10 = arith.constant 10 : index
7 %c20 = arith.constant 20 : index
8 %s = fir.shape %m, %n : (index, index) -> !fir.shape<2>
9 %av1 = fir.array_load %arr1(%s) : (!fir.ref<!fir.array<?x?xf32>>, !fir.shape<2>) -> !fir.array<?x?xf32>
10 %f = fir.array_fetch %av1, %c10, %c20 : (!fir.array<?x?xf32>, index, index) -> f32
14 // CHECK-LABEL: func @array_fetch_conversion(
15 // CHECK-SAME: %[[ARRAY:.*]]: !fir.ref<!fir.array<?x?xf32>>,
16 // CHECK-SAME: %[[ARG1:.*]]: index,
17 // CHECK-SAME: %[[ARG2:.*]]: index) {
18 // CHECK: %{{.*}} = fir.shape %[[ARG1]], %[[ARG2]] : (index, index) -> !fir.shape<2>
19 // CHECK: %{{.*}} = fir.undefined !fir.array<?x?xf32>
20 // CHECK: %[[VAL_0:.*]] = arith.addi %{{.*}}, %{{.*}} : index
21 // CHECK: %[[VAL_1:.*]] = arith.addi %{{.*}}, %{{.*}} : index
22 // CHECK-NOT: fir.array_load
23 // CHECK-NOT: fir.array_fetch
24 // CHECK: %{{.*}} = fir.array_coor %arg0(%0) %[[VAL_0]], %[[VAL_1]] : (!fir.ref<!fir.array<?x?xf32>>, !fir.shape<2>, index, index) -> !fir.ref<f32>
25 // CHECK: %{{.*}} = fir.load %4 : !fir.ref<f32>
29 // Test simple fir.array_load/fir.array_update conversion without copy-in/copy-out
30 func.func @array_update_conversion(%arr1 : !fir.box<!fir.array<?x?xf32>>, %m: index, %n: index) {
31 %c10 = arith.constant 10 : index
32 %c20 = arith.constant 20 : index
33 %c1 = arith.constant 1 : index
34 %f = arith.constant 2.0 : f32
35 %s = fir.shape %m, %n : (index, index) -> !fir.shape<2>
36 %av1 = fir.array_load %arr1(%s) : (!fir.box<!fir.array<?x?xf32>>, !fir.shape<2>) -> !fir.array<?x?xf32>
37 %av2 = fir.array_update %av1, %f, %c1, %c1 : (!fir.array<?x?xf32>, f32, index, index) -> !fir.array<?x?xf32>
41 // CHECK-LABEL: func @array_update_conversion
42 // CHECK-NOT: fir.array_load
43 // CHECK-NOT: fir.array_update
44 // CHECK: %{{.*}} = arith.addi %{{.*}}, %{{.*}} : index
45 // CHECK: %{{.*}} = arith.addi %{{.*}}, %{{.*}} : index
46 // CHECK: %[[ARRAY_COOR:.*]] = fir.array_coor{{.*}}-> !fir.ref<f32>
47 // CHECK: fir.store %{{.*}} to %[[ARRAY_COOR]] : !fir.ref<f32>
51 // Test simple fir.array_load/fir.array_update conversion without copy-in/copy-out
52 func.func @array_update_conversion(%arr1 : !fir.box<!fir.array<?x?xf32>>, %m: index, %n: index, %cond: i1) {
53 %c10 = arith.constant 10 : index
54 %c20 = arith.constant 20 : index
55 %c1 = arith.constant 1 : index
56 %f = arith.constant 2.0 : f32
57 %g = arith.constant 4.0 : f32
58 %s = fir.shape %m, %n : (index, index) -> !fir.shape<2>
59 %av1 = fir.array_load %arr1(%s) : (!fir.box<!fir.array<?x?xf32>>, !fir.shape<2>) -> !fir.array<?x?xf32>
61 %av2 = fir.array_update %av1, %f, %c1, %c1 : (!fir.array<?x?xf32>, f32, index, index) -> !fir.array<?x?xf32>
63 %av2 = fir.array_update %av1, %g, %c1, %c1 : (!fir.array<?x?xf32>, f32, index, index) -> !fir.array<?x?xf32>
70 // Test fir.array_load/fir.array_fetch/fir.array_update conversion with
71 // an introduced copy-in/copy-out.
73 // This test corresponds to a simplified FIR version of the following Fortran
81 func.func @conversion_with_temporary(%arr0 : !fir.ref<!fir.array<10xi32>>) {
82 %c10 = arith.constant 10 : index
83 %1 = fir.shape %c10 : (index) -> !fir.shape<1>
84 %2 = fir.array_load %arr0(%1) : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> !fir.array<10xi32>
85 %c10_i64 = arith.constant 10 : i64
86 %3 = fir.convert %c10_i64 : (i64) -> index
87 %c1_i64 = arith.constant 1 : i64
88 %c-1_i64 = arith.constant -1 : i64
89 %4 = fir.shape %c10 : (index) -> !fir.shape<1>
90 %5 = fir.slice %c10_i64, %c1_i64, %c-1_i64 : (i64, i64, i64) -> !fir.slice<1>
91 %6 = fir.array_load %arr0(%4) [%5] : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>, !fir.slice<1>) -> !fir.array<10xi32>
92 %c1 = arith.constant 1 : index
93 %c0 = arith.constant 0 : index
94 %7 = arith.subi %3, %c1 : index
95 %8 = fir.do_loop %arg0 = %c0 to %7 step %c1 unordered iter_args(%arg1 = %2) -> (!fir.array<10xi32>) {
96 %9 = fir.array_fetch %6, %arg0 : (!fir.array<10xi32>, index) -> i32
97 %10 = fir.array_update %arg1, %9, %arg0 : (!fir.array<10xi32>, i32, index) -> !fir.array<10xi32>
98 fir.result %10 : !fir.array<10xi32>
100 fir.array_merge_store %2, %8 to %arr0 : !fir.array<10xi32>, !fir.array<10xi32>, !fir.ref<!fir.array<10xi32>>
104 // CHECK-LABEL: func @conversion_with_temporary(
105 // CHECK-SAME: %[[ARR0:.*]]: !fir.ref<!fir.array<10xi32>>)
106 // Allocation of temporary array.
107 // CHECK: %[[TEMP:.*]] = fir.allocmem !fir.array<10xi32>
108 // Copy of original array to temp.
109 // CHECK: fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} {
110 // CHECK: %[[COOR0:.*]] = fir.array_coor %[[ARR0]](%{{.*}}) %{{.*}} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>, index) -> !fir.ref<i32>
111 // CHECK: %[[COOR1:.*]] = fir.array_coor %[[TEMP]](%{{.*}}) %{{.*}} : (!fir.heap<!fir.array<10xi32>>, !fir.shape<1>, index) -> !fir.ref<i32>
112 // CHECK: %[[LOAD0:.*]] = fir.load %[[COOR0]] : !fir.ref<i32>
113 // CHECK: fir.store %[[LOAD0]] to %[[COOR1]] : !fir.ref<i32>
115 // Perform the assignment i = i(10:1:-1) using the temporary array.
116 // CHECK: %{{.*}} = fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} unordered iter_args(%{{.*}} = %{{.*}}) -> (!fir.array<10xi32>) {
117 // CHECK-NOT: %{{.*}} = fir.array_fetch
118 // CHECK-NOT: %{{.*}} = fir.array_update
119 // CHECK: %[[COOR0:.*]] = fir.array_coor %[[ARR0]](%{{.*}}) [%{{.*}}] %{{.*}} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>, !fir.slice<1>, index) -> !fir.ref<i32>
120 // CHECK: %[[LOAD0:.*]] = fir.load %[[COOR0]] : !fir.ref<i32>
121 // CHECK: %[[COOR1:.*]] = fir.array_coor %[[TEMP]](%{{.*}}) %{{.*}} : (!fir.heap<!fir.array<10xi32>>, !fir.shape<1>, index) -> !fir.ref<i32>
122 // CHECK: fir.store %[[LOAD0]] to %[[COOR1]] : !fir.ref<i32>
123 // CHECK: fir.result %{{.*}} : !fir.array<10xi32>
125 // Copy the result back to the original array.
126 // CHECK: fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} {
127 // CHECK: %[[COOR0:.*]] = fir.array_coor %[[TEMP]](%{{.*}}) %{{.*}} : (!fir.heap<!fir.array<10xi32>>, !fir.shape<1>, index) -> !fir.ref<i32>
128 // CHECK: %[[COOR1:.*]] = fir.array_coor %[[ARR0]](%{{.*}}) %{{.*}} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>, index) -> !fir.ref<i32>
129 // CHECK: %[[LOAD0:.*]] = fir.load %[[COOR0:.*]] : !fir.ref<i32>
130 // CHECK: fir.store %[[LOAD0]] to %[[COOR1]] : !fir.ref<i32>
132 // Free temporary array.
133 // CHECK: fir.freemem %[[TEMP]] : !fir.heap<!fir.array<10xi32>>
137 // Test fir.array_load/fir.array_fetch/fir.array_update conversion with
138 // an introduced copy-in/copy-out on a multidimensional array.
140 func.func @conversion_with_temporary_multidim(%0: !fir.ref<!fir.array<10x5xi32>>) {
141 %c10 = arith.constant 10 : index
142 %c5 = arith.constant 5 : index
143 %1 = fir.shape %c10, %c5 : (index, index) -> !fir.shape<2>
144 %2 = fir.array_load %0(%1) : (!fir.ref<!fir.array<10x5xi32>>, !fir.shape<2>) -> !fir.array<10x5xi32>
145 %c10_i64 = arith.constant 10 : i64
146 %3 = fir.convert %c10_i64 : (i64) -> index
147 %c5_i64 = arith.constant 5 : i64
148 %4 = fir.convert %c5_i64 : (i64) -> index
149 %c1 = arith.constant 1 : index
150 %c10_i64_0 = arith.constant 10 : i64
151 %c1_i64 = arith.constant 1 : i64
152 %c-1_i64 = arith.constant -1 : i64
153 %5 = arith.addi %c1, %c5 : index
154 %6 = arith.subi %5, %c1 : index
155 %c1_i64_1 = arith.constant 1 : i64
156 %7 = fir.shape %c10, %c5 : (index, index) -> !fir.shape<2>
157 %8 = fir.slice %c10_i64_0, %c1_i64, %c-1_i64, %c1, %6, %c1_i64_1 : (i64, i64, i64, index, index, i64) -> !fir.slice<2>
158 %9 = fir.array_load %0(%7) [%8] : (!fir.ref<!fir.array<10x5xi32>>, !fir.shape<2>, !fir.slice<2>) -> !fir.array<10x5xi32>
159 %c1_2 = arith.constant 1 : index
160 %c0 = arith.constant 0 : index
161 %10 = arith.subi %3, %c1_2 : index
162 %11 = arith.subi %4, %c1_2 : index
163 %12 = fir.do_loop %arg0 = %c0 to %11 step %c1_2 unordered iter_args(%arg1 = %2) -> (!fir.array<10x5xi32>) {
164 %13 = fir.do_loop %arg2 = %c0 to %10 step %c1_2 unordered iter_args(%arg3 = %arg1) -> (!fir.array<10x5xi32>) {
165 %14 = fir.array_fetch %9, %arg2, %arg0 : (!fir.array<10x5xi32>, index, index) -> i32
166 %15 = fir.array_update %arg3, %14, %arg2, %arg0 : (!fir.array<10x5xi32>, i32, index, index) -> !fir.array<10x5xi32>
167 fir.result %15 : !fir.array<10x5xi32>
169 fir.result %13 : !fir.array<10x5xi32>
171 fir.array_merge_store %2, %12 to %0 : !fir.array<10x5xi32>, !fir.array<10x5xi32>, !fir.ref<!fir.array<10x5xi32>>
175 // CHECK-LABEL: func @conversion_with_temporary_multidim(
176 // CHECK-SAME: %[[ARR0:.*]]: !fir.ref<!fir.array<10x5xi32>>) {
177 // CHECK: %[[CST10:.*]] = arith.constant 10 : index
178 // CHECK: %[[CST5:.*]] = arith.constant 5 : index
179 // CHECK: %[[TEMP:.*]] = fir.allocmem !fir.array<10x5xi32>
180 // CHECK: %[[IDX5:.*]] = fir.convert %[[CST5]] : (index) -> index
181 // CHECK: %[[UB5:.*]] = arith.subi %[[IDX5]], %{{.*}} : index
182 // CHECK: fir.do_loop %[[INDUC0:.*]] = %{{.*}} to %[[UB5]] step %{{.*}} {
183 // CHECK: %[[IDX10:.*]] = fir.convert %[[CST10]] : (index) -> index
184 // CHECK: %[[UB10:.*]] = arith.subi %[[IDX10]], %{{.*}} : index
185 // CHECK: fir.do_loop %[[INDUC1:.*]] = %{{.*}} to %[[UB10]] step %{{.*}} {
186 // CHECK: %[[IDX1:.*]] = arith.addi %[[INDUC1]], %{{.*}} : index
187 // CHECK: %[[IDX2:.*]] = arith.addi %[[INDUC0]], %{{.*}} : index
188 // CHECK: %[[COOR0:.*]] = fir.array_coor %[[ARR0]](%{{.*}}) %[[IDX1:.*]], %[[IDX2:.*]] : (!fir.ref<!fir.array<10x5xi32>>, !fir.shape<2>, index, index) -> !fir.ref<i32>
189 // CHECK: %[[COOR1:.*]] = fir.array_coor %[[TEMP]](%{{.*}}) %{{.*}}, %{{.*}} : (!fir.heap<!fir.array<10x5xi32>>, !fir.shape<2>, index, index) -> !fir.ref<i32>
190 // CHECK: %[[LOAD0:.*]] = fir.load %[[COOR0]] : !fir.ref<i32>
191 // CHECK: fir.store %[[LOAD0]] to %[[COOR1]] : !fir.ref<i32>
192 // CHECK: %{{.*}} = fir.do_loop %[[INDUC0:.*]] = %{{.*}} to %{{.*}} step %{{.*}} unordered iter_args(%{{.*}} = %{{.*}}) -> (!fir.array<10x5xi32>) {
193 // CHECK: %{{.*}} = fir.do_loop %[[INDUC1:.*]] = %{{.*}} to %{{.*}} step %{{.*}} unordered iter_args(%{{.*}} = %{{.*}}) -> (!fir.array<10x5xi32>) {
194 // CHECK: %[[IDX1:.*]] = arith.addi %[[INDUC1]], %{{.*}} : index
195 // CHECK: %[[IDX2:.*]] = arith.addi %[[INDUC0]], %{{.*}} : index
196 // CHECK-NOT: %{{.*}} = fir.array_fetch
197 // CHECK-NOT: %{{.*}} = fir.array_update
198 // CHECK: %[[COOR0:.*]] = fir.array_coor %[[ARR0]](%{{.*}}) [%{{.*}}] %[[IDX1]], %[[IDX2]] : (!fir.ref<!fir.array<10x5xi32>>, !fir.shape<2>, !fir.slice<2>, index, index) -> !fir.ref<i32>
199 // CHECK: %[[LOAD0:.*]] = fir.load %[[COOR0]] : !fir.ref<i32>
200 // CHECK: %[[COOR1:.*]] = fir.array_coor %[[TEMP]](%{{.*}}) %{{.*}}, %{{.*}} : (!fir.heap<!fir.array<10x5xi32>>, !fir.shape<2>, index, index) -> !fir.ref<i32>
201 // CHECK: fir.store %[[LOAD0]] to %[[COOR1]] : !fir.ref<i32>
202 // CHECK: %[[IDX5:.*]] = fir.convert %[[CST5]] : (index) -> index
203 // CHECK: %[[UB5:.*]] = arith.subi %[[IDX5]], %{{.*}} : index
204 // CHECK: fir.do_loop %[[INDUC0:.*]] = %{{.*}} to %[[UB5]] step %{{.*}} {
205 // CHECK: %[[IDX10:.*]] = fir.convert %[[CST10]] : (index) -> index
206 // CHECK: %[[UB10:.*]] = arith.subi %[[IDX10]], %{{.*}} : index
207 // CHECK: fir.do_loop %[[INDUC1:.*]] = %{{.*}} to %[[UB10]] step %{{.*}} {
208 // CHECK: %[[IDX1:.*]] = arith.addi %[[INDUC1]], %{{.*}} : index
209 // CHECK: %[[IDX2:.*]] = arith.addi %[[INDUC0]], %{{.*}} : index
210 // CHECK: %[[COOR0:.*]] = fir.array_coor %[[TEMP]](%{{.*}}) %[[IDX1]], %[[IDX2]] : (!fir.heap<!fir.array<10x5xi32>>, !fir.shape<2>, index, index) -> !fir.ref<i32>
211 // CHECK: %[[COOR1:.*]] = fir.array_coor %[[ARR0]](%{{.*}}) %{{.*}}, %{{.*}} : (!fir.ref<!fir.array<10x5xi32>>, !fir.shape<2>, index, index) -> !fir.ref<i32>
212 // CHECK: %[[LOAD0:.*]] = fir.load %[[COOR0]] : !fir.ref<i32>
213 // CHECK: fir.store %[[LOAD0]] to %[[COOR1]] : !fir.ref<i32>
214 // CHECK: fir.freemem %[[TEMP]] : !fir.heap<!fir.array<10x5xi32>>
218 // Test fir.array_modify conversion with no overlap.
219 func.func @array_modify_no_overlap(%arg0: !fir.ref<!fir.array<100xf32>>, %arg1: !fir.ref<!fir.array<100xf32>>) {
220 %c100 = arith.constant 100 : index
221 %c99 = arith.constant 99 : index
222 %c1 = arith.constant 1 : index
223 %c0 = arith.constant 0 : index
225 %1 = fir.shape %c100 : (index) -> !fir.shape<1>
226 %2 = fir.array_load %arg0(%1) : (!fir.ref<!fir.array<100xf32>>, !fir.shape<1>) -> !fir.array<100xf32>
227 %3 = fir.array_load %arg1(%1) : (!fir.ref<!fir.array<100xf32>>, !fir.shape<1>) -> !fir.array<100xf32>
228 %4 = fir.do_loop %arg2 = %c0 to %c99 step %c1 unordered iter_args(%arg3 = %2) -> (!fir.array<100xf32>) {
229 %5 = fir.array_fetch %3, %arg2 : (!fir.array<100xf32>, index) -> f32
230 %6:2 = fir.array_modify %arg3, %arg2 : (!fir.array<100xf32>, index) -> (!fir.ref<f32>, !fir.array<100xf32>)
231 fir.store %5 to %0 : !fir.ref<f32>
232 fir.call @user_defined_assignment(%6#0, %0) : (!fir.ref<f32>, !fir.ref<f32>) -> ()
233 fir.result %6#1 : !fir.array<100xf32>
235 fir.array_merge_store %2, %4 to %arg0 : !fir.array<100xf32>, !fir.array<100xf32>, !fir.ref<!fir.array<100xf32>>
239 func.func private @user_defined_assignment(!fir.ref<f32>, !fir.ref<f32>)
241 // CHECK-LABEL: func @array_modify_no_overlap(
242 // CHECK-SAME: %[[ARR0:.*]]: !fir.ref<!fir.array<100xf32>>,
243 // CHECK-SAME: %[[ARR1:.*]]: !fir.ref<!fir.array<100xf32>>) {
244 // CHECK: %[[VAR0:.*]] = fir.alloca f32
245 // CHECK-COUNT-1: %{{.*}} = fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} unordered iter_args(%{{.*}} = %{{.*}}) -> (!fir.array<100xf32>) {
246 // CHECK-NOT: %{{.*}} = fir.array_fetch
247 // CHECK-NOT: %{{.*}} = fir.array_modify
248 // CHECK: %[[COOR0:.*]] = fir.array_coor %arg1(%1) %5 : (!fir.ref<!fir.array<100xf32>>, !fir.shape<1>, index) -> !fir.ref<f32>
249 // CHECK: %[[LOAD0:.*]] = fir.load %[[COOR0]] : !fir.ref<f32>
250 // CHECK: %[[COOR1:.*]] = fir.array_coor %[[ARR0]](%{{.*}}) %{{.*}} : (!fir.ref<!fir.array<100xf32>>, !fir.shape<1>, index) -> !fir.ref<f32>
251 // CHECK: fir.store %[[LOAD0]] to %[[VAR0]] : !fir.ref<f32>
252 // CHECK: fir.call @{{.*}}(%[[COOR1]], %[[VAR0]]) : (!fir.ref<f32>, !fir.ref<f32>) -> ()
256 // Test fir.array_modify conversion with an overlap.
257 // Test user_defined_assignment(arg0(:), arg0(100:1:-1))
258 func.func @array_modify_overlap(%arg0: !fir.ref<!fir.array<100xf32>>) {
259 %c100 = arith.constant 100 : index
260 %c99 = arith.constant 99 : index
261 %c1 = arith.constant 1 : index
262 %c-1 = arith.constant -1 : index
263 %c0 = arith.constant 0 : index
265 %1 = fir.shape %c100 : (index) -> !fir.shape<1>
266 %2 = fir.array_load %arg0(%1) : (!fir.ref<!fir.array<100xf32>>, !fir.shape<1>) -> !fir.array<100xf32>
267 %3 = fir.slice %c100, %c1, %c-1 : (index, index, index) -> !fir.slice<1>
268 %4 = fir.array_load %arg0(%1) [%3] : (!fir.ref<!fir.array<100xf32>>, !fir.shape<1>, !fir.slice<1>) -> !fir.array<100xf32>
269 %5 = fir.do_loop %arg1 = %c0 to %c99 step %c1 unordered iter_args(%arg2 = %2) -> (!fir.array<100xf32>) {
270 %6 = fir.array_fetch %4, %arg1 : (!fir.array<100xf32>, index) -> f32
271 %7:2 = fir.array_modify %arg2, %arg1 : (!fir.array<100xf32>, index) -> (!fir.ref<f32>, !fir.array<100xf32>)
272 fir.store %6 to %0 : !fir.ref<f32>
273 fir.call @user_defined_assignment(%7#0, %0) : (!fir.ref<f32>, !fir.ref<f32>) -> ()
274 fir.result %7#1 : !fir.array<100xf32>
276 fir.array_merge_store %2, %5 to %arg0 : !fir.array<100xf32>, !fir.array<100xf32>, !fir.ref<!fir.array<100xf32>>
280 func.func private @user_defined_assignment(!fir.ref<f32>, !fir.ref<f32>)
282 // CHECK-LABEL: func @array_modify_overlap(
283 // CHECK-SAME: %[[ARR0:.*]]: !fir.ref<!fir.array<100xf32>>) {
284 // CHECK: %[[VAR0:.*]] = fir.alloca f32
285 // Allocate the temporary array.
286 // CHECK: %[[TEMP:.*]] = fir.allocmem !fir.array<100xf32>
287 // Copy original array to temp.
288 // CHECK: fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} {
289 // CHECK: %[[COOR0:.*]] = fir.array_coor %[[ARR0]](%{{.*}}) %{{.*}} : (!fir.ref<!fir.array<100xf32>>, !fir.shape<1>, index) -> !fir.ref<f32>
290 // CHECK: %[[COOR1:.*]] = fir.array_coor %[[TEMP]](%{{.*}}) %{{.*}} : (!fir.heap<!fir.array<100xf32>>, !fir.shape<1>, index) -> !fir.ref<f32>
291 // CHECK: %[[LOAD0:.*]] = fir.load %[[COOR0]] : !fir.ref<f32>
292 // CHECK: fir.store %[[LOAD0]] to %[[COOR1]] : !fir.ref<f32>
294 // CHECK: %[[VAL_21:.*]] = fir.undefined !fir.array<100xf32>
295 // CHECK: %[[VAL_23:.*]] = fir.undefined !fir.array<100xf32>
296 // CHECK-NOT: %{{.*}} = fir.array_fetch
297 // CHECK-NOT: %{{.*}} = fir.array_modify
298 // CHECK: %[[COOR0:.*]] = fir.array_coor %[[ARR0]](%{{.*}}) {{\[}}%{{.*}}] %{{.*}} : (!fir.ref<!fir.array<100xf32>>, !fir.shape<1>, !fir.slice<1>, index) -> !fir.ref<f32>
299 // CHECK: %[[LOAD0:.*]] = fir.load %[[COOR0]] : !fir.ref<f32>
300 // CHECK: %[[COOR1:.*]] = fir.array_coor %[[TEMP]](%{{.*}}) %{{.*}} : (!fir.heap<!fir.array<100xf32>>, !fir.shape<1>, index) -> !fir.ref<f32>
301 // CHECK: fir.store %[[LOAD0]] to %[[VAR0]] : !fir.ref<f32>
302 // CHECK: fir.call @user_defined_assignment(%[[COOR1]], %[[VAR0]]) : (!fir.ref<f32>, !fir.ref<f32>) -> ()
304 // Copy back result to original array from temp.
305 // CHECK: fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} {
306 // CHECK: %[[COOR0:.*]] = fir.array_coor %[[TEMP]](%{{.*}}) %{{.*}} : (!fir.heap<!fir.array<100xf32>>, !fir.shape<1>, index) -> !fir.ref<f32>
307 // CHECK: %[[COOR1:.*]] = fir.array_coor %[[ARR0]](%{{.*}}) %{{.*}} : (!fir.ref<!fir.array<100xf32>>, !fir.shape<1>, index) -> !fir.ref<f32>
308 // CHECK: %[[LOAD0:.*]] = fir.load %[[COOR0]] : !fir.ref<f32>
309 // CHECK: fir.store %[[LOAD0]] to %[[COOR1]] : !fir.ref<f32>
311 // Free the temporary array.
312 // CHECK: fir.freemem %[[TEMP]] : !fir.heap<!fir.array<100xf32>>
318 // Test array of types with no overlap
319 func.func @array_of_types() {
320 %0 = fir.alloca i32 {bindc_name = "j", uniq_name = "_QEj"}
321 %1 = fir.address_of(@_QEtypes) : !fir.ref<!fir.array<10x!fir.type<_QTd{i:!fir.array<10xi32>}>>>
322 %c1_i32 = arith.constant 1 : i32
323 %2 = fir.convert %c1_i32 : (i32) -> index
324 %c10_i32 = arith.constant 10 : i32
325 %3 = fir.convert %c10_i32 : (i32) -> index
326 %c1 = arith.constant 1 : index
327 %4 = fir.do_loop %arg0 = %2 to %3 step %c1 -> index {
328 %6 = fir.convert %arg0 : (index) -> i32
329 fir.store %6 to %0 : !fir.ref<i32>
330 %c1_0 = arith.constant 1 : index
331 %7 = fir.load %0 : !fir.ref<i32>
332 %8 = fir.convert %7 : (i32) -> i64
333 %c1_i64 = arith.constant 1 : i64
334 %9 = arith.subi %8, %c1_i64 : i64
335 %10 = fir.coordinate_of %1, %9 : (!fir.ref<!fir.array<10x!fir.type<_QTd{i:!fir.array<10xi32>}>>>, i64) -> !fir.ref<!fir.type<_QTd{i:!fir.array<10xi32>}>>
336 %11 = fir.field_index i, !fir.type<_QTd{i:!fir.array<10xi32>}>
337 %12 = fir.coordinate_of %10, %11 : (!fir.ref<!fir.type<_QTd{i:!fir.array<10xi32>}>>, !fir.field) -> !fir.ref<!fir.array<10xi32>>
338 %c10 = arith.constant 10 : index
339 %13 = arith.addi %c1_0, %c10 : index
340 %14 = arith.subi %13, %c1_0 : index
341 %c1_i64_1 = arith.constant 1 : i64
342 %15 = fir.shape %c10 : (index) -> !fir.shape<1>
343 %16 = fir.slice %c1_0, %14, %c1_i64_1 : (index, index, i64) -> !fir.slice<1>
344 %17 = fir.array_load %12(%15) [%16] : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>, !fir.slice<1>) -> !fir.array<10xi32>
345 %c10_i64 = arith.constant 10 : i64
346 %18 = fir.convert %c10_i64 : (i64) -> index
347 %c0_i32 = arith.constant 0 : i32
348 %c1_2 = arith.constant 1 : index
349 %c0 = arith.constant 0 : index
350 %19 = arith.subi %18, %c1_2 : index
351 %20 = fir.do_loop %arg1 = %c0 to %19 step %c1_2 unordered iter_args(%arg2 = %17) -> (!fir.array<10xi32>) {
352 %22 = fir.array_update %arg2, %c0_i32, %arg1 : (!fir.array<10xi32>, i32, index) -> !fir.array<10xi32>
353 fir.result %22 : !fir.array<10xi32>
355 fir.array_merge_store %17, %20 to %12[%16] : !fir.array<10xi32>, !fir.array<10xi32>, !fir.ref<!fir.array<10xi32>>, !fir.slice<1>
356 %21 = arith.addi %arg0, %c1 : index
357 fir.result %21 : index
359 %5 = fir.convert %4 : (index) -> i32
360 fir.store %5 to %0 : !fir.ref<i32>
364 // CHECK-LABEL: func @array_of_types() {
365 // CHECK: %{{.*}} = fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} -> index {
366 // CHECK: %{{.*}} = fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} unordered iter_args(%arg2 = %17) -> (!fir.array<10xi32>) {
367 // CHECK-NOT: %{{.*}} = fir.array_update
368 // CHECK: %[[COOR0:.*]] = fir.array_coor %{{.*}}(%{{.*}}) [%{{.*}}] %{{.*}} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>, !fir.slice<1>, index) -> !fir.ref<i32>
369 // CHECK: fir.store %{{.*}} to %[[COOR0]] : !fir.ref<i32>
370 // CHECK-NOT: fir.array_merge_store
374 // Test fir.array_load/boxed array
375 func.func @conversion_with_temporary_boxed_array(%arr0 : !fir.box<!fir.array<10xi32>>) {
376 %c10 = arith.constant 10 : index
377 %1:3 = fir.box_dims %arr0, %c10 : (!fir.box<!fir.array<10xi32>>, index) -> (index, index, index)
378 %shift = fir.shift %1#0 : (index) -> !fir.shift<1>
379 %2 = fir.array_load %arr0(%shift) : (!fir.box<!fir.array<10xi32>>, !fir.shift<1>) -> !fir.array<10xi32>
380 %c10_i64 = arith.constant 10 : i64
381 %3 = fir.convert %c10_i64 : (i64) -> index
382 %c1_i64 = arith.constant 1 : i64
383 %c-1_i64 = arith.constant -1 : i64
384 %4 = fir.shape %c10 : (index) -> !fir.shape<1>
385 %5 = fir.slice %c10_i64, %c1_i64, %c-1_i64 : (i64, i64, i64) -> !fir.slice<1>
386 %6 = fir.array_load %arr0(%4) [%5] : (!fir.box<!fir.array<10xi32>>, !fir.shape<1>, !fir.slice<1>) -> !fir.array<10xi32>
387 %c1 = arith.constant 1 : index
388 %c0 = arith.constant 0 : index
389 %7 = arith.subi %3, %c1 : index
390 %8 = fir.do_loop %arg0 = %c0 to %7 step %c1 unordered iter_args(%arg1 = %2) -> (!fir.array<10xi32>) {
391 %9 = fir.array_fetch %6, %arg0 : (!fir.array<10xi32>, index) -> i32
392 %10 = fir.array_update %arg1, %9, %arg0 : (!fir.array<10xi32>, i32, index) -> !fir.array<10xi32>
393 fir.result %10 : !fir.array<10xi32>
395 fir.array_merge_store %2, %8 to %arr0 : !fir.array<10xi32>, !fir.array<10xi32>, !fir.box<!fir.array<10xi32>>
399 // CHECK-LABEL: func @conversion_with_temporary_boxed_array(
400 // CHECK-SAME: %[[ARR0:.*]]: !fir.box<!fir.array<10xi32>>)
401 // Allocation of temporary array.
402 // CHECK: %[[TEMP:.*]] = fir.allocmem !fir.array<10xi32>
403 // Copy of original array to temp.
404 // CHECK: fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} {
405 // CHECK: %[[COOR0:.*]] = fir.array_coor %[[ARR0]](%{{.*}}) %{{.*}} : (!fir.box<!fir.array<10xi32>>, !fir.shapeshift<1>, index) -> !fir.ref<i32>
406 // CHECK: %[[COOR1:.*]] = fir.array_coor %[[TEMP]](%{{.*}}) %{{.*}} : (!fir.heap<!fir.array<10xi32>>, !fir.shapeshift<1>, index) -> !fir.ref<i32>
407 // CHECK: %[[LOAD0:.*]] = fir.load %[[COOR0]] : !fir.ref<i32>
408 // CHECK: fir.store %[[LOAD0]] to %[[COOR1]] : !fir.ref<i32>
410 // Perform the assignment i = i(10:1:-1) using the temporary array.
411 // CHECK: %{{.*}} = fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} unordered iter_args(%{{.*}} = %{{.*}}) -> (!fir.array<10xi32>) {
412 // CHECK-NOT: %{{.*}} = fir.array_fetch
413 // CHECK-NOT: %{{.*}} = fir.update
414 // CHECK: %[[COOR0:.*]] = fir.array_coor %[[ARR0]](%{{.*}}) [%{{.*}}] %{{.*}} : (!fir.box<!fir.array<10xi32>>, !fir.shape<1>, !fir.slice<1>, index) -> !fir.ref<i32>
415 // CHECK: %[[LOAD0:.*]] = fir.load %[[COOR0]] : !fir.ref<i32>
416 // CHECK: %[[COOR1:.*]] = fir.array_coor %[[TEMP]](%{{.*}}) %{{.*}} : (!fir.heap<!fir.array<10xi32>>, !fir.shapeshift<1>, index) -> !fir.ref<i32>
417 // CHECK: fir.store %[[LOAD0]] to %[[COOR1]] : !fir.ref<i32>
418 // CHECK: fir.result %{{.*}} : !fir.array<10xi32>
420 // Copy the result back to the original array.
421 // CHECK: fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} {
422 // CHECK: %[[COOR0:.*]] = fir.array_coor %[[TEMP]](%{{.*}}) %{{.*}} : (!fir.heap<!fir.array<10xi32>>, !fir.shapeshift<1>, index) -> !fir.ref<i32>
423 // CHECK: %[[COOR1:.*]] = fir.array_coor %[[ARR0]](%{{.*}}) %{{.*}} : (!fir.box<!fir.array<10xi32>>, !fir.shapeshift<1>, index) -> !fir.ref<i32>
424 // CHECK: %[[LOAD0:.*]] = fir.load %[[COOR0:.*]] : !fir.ref<i32>
425 // CHECK: fir.store %[[LOAD0]] to %[[COOR1]] : !fir.ref<i32>
427 // Free temporary array.
428 // CHECK: fir.freemem %[[TEMP]] : !fir.heap<!fir.array<10xi32>>
432 // Test simple fir.array_update with Fortran.offsets attribute.
433 func.func @array_update_conversion(%arr1 : !fir.box<!fir.array<?x?xf32>>, %m: index, %n: index) {
434 %c10 = arith.constant 10 : index
435 %c20 = arith.constant 20 : index
436 %c1 = arith.constant 1 : index
437 %f = arith.constant 2.0 : f32
438 %s = fir.shape %m, %n : (index, index) -> !fir.shape<2>
439 %av1 = fir.array_load %arr1(%s) : (!fir.box<!fir.array<?x?xf32>>, !fir.shape<2>) -> !fir.array<?x?xf32>
440 %av2 = fir.array_update %av1, %f, %c1, %c1 {Fortran.offsets} : (!fir.array<?x?xf32>, f32, index, index) -> !fir.array<?x?xf32>
444 // CHECK-LABEL: func @array_update_conversion
445 // CHECK-NOT: fir.array_update
446 // CHECK-NOT: %{{.*}} = arith.addi %{{.*}}, %{{.*}} : index
447 // CHECK: %[[ARRAY_COOR:.*]] = fir.array_coor{{.*}}-> !fir.ref<f32>
448 // CHECK: fir.store %{{.*}} to %[[ARRAY_COOR]] : !fir.ref<f32>
452 // Test fir.array_fetch on derived type members in an array of derived types.
453 func.func @array_fetch_derived_type(%0 : !fir.ref<!fir.array<10x!fir.type<_QTu{mt:!fir.type<_QTt{mem:i32}>}>>>) {
454 %1 = fir.alloca i32 {bindc_name = "i", uniq_name = "_QEi"}
455 %c1_i32 = arith.constant 1 : i32
456 %2 = fir.convert %c1_i32 : (i32) -> index
457 %c10_i32 = arith.constant 10 : i32
458 %3 = fir.convert %c10_i32 : (i32) -> index
459 %c1 = arith.constant 1 : index
460 %shape = fir.shape %2 : (index) -> !fir.shape<1>
461 %arr0 = fir.array_load %0(%shape) : (!fir.ref<!fir.array<10x!fir.type<_QTu{mt:!fir.type<_QTt{mem:i32}>}>>>, !fir.shape<1>) -> !fir.array<10x!fir.type<_QTu{mt:!fir.type<_QTt{mem:i32}>}>>
462 %4 = fir.do_loop %arg0 = %2 to %3 step %c1 -> index {
463 %6 = fir.convert %arg0 : (index) -> i32
464 fir.store %6 to %1 : !fir.ref<i32>
465 %c1_i32_0 = arith.constant 1 : i32
466 %7 = fir.load %1 : !fir.ref<i32>
467 %8 = fir.convert %7 : (i32) -> i64
468 %c1_i64 = arith.constant 1 : i64
469 %9 = arith.subi %8, %c1_i64 : i64
470 %11 = fir.field_index mt, !fir.type<_QTu{mt:!fir.type<_QTt{mem:i32}>}>
471 %12 = fir.field_index mem, !fir.type<_QTt{mem:i32}>
472 %idx = fir.convert %9 : (i64) -> index
473 %res = fir.array_fetch %arr0, %idx, %11, %12 : (!fir.array<10x!fir.type<_QTu{mt:!fir.type<_QTt{mem:i32}>}>>, index, !fir.field, !fir.field) -> i32
474 %14 = arith.addi %arg0, %c1 : index
475 fir.result %14 : index
477 %5 = fir.convert %4 : (index) -> i32
478 fir.store %5 to %1 : !fir.ref<i32>
482 // CHECK-LABEL: func @array_fetch_derived_type(
483 // CHECK-SAME: %[[ARR0:.*]]: !fir.ref<!fir.array<10x!fir.type<_QTu{mt:!fir.type<_QTt{mem:i32}>}>>>) {
484 // CHECK: %{{.*}} = fir.do_loop
485 // CHECK: %[[FIELD_MT:.*]] = fir.field_index mt, !fir.type<_QTu{mt:!fir.type<_QTt{mem:i32}>}>
486 // CHECK: %[[FIELD_MEM:.*]] = fir.field_index mem, !fir.type<_QTt{mem:i32}>
487 // CHECK-NOT: %{{.*}} = fir.array_fetch
488 // CHECK: %[[COOR0:.*]] = fir.array_coor %[[ARR0]](%{{.*}}) %{{.*}} : (!fir.ref<!fir.array<10x!fir.type<_QTu{mt:!fir.type<_QTt{mem:i32}>}>>>, !fir.shape<1>, index) -> !fir.ref<!fir.type<_QTu{mt:!fir.type<_QTt{mem:i32}>}>>
489 // CHECK: %[[COOR_OF:.*]] = fir.coordinate_of %[[COOR0]], %[[FIELD_MT]], %[[FIELD_MEM]] : (!fir.ref<!fir.type<_QTu{mt:!fir.type<_QTt{mem:i32}>}>>, !fir.field, !fir.field) -> !fir.ref<i32>
490 // CHECK: %{{.*}} = fir.load %[[COOR_OF]] : !fir.ref<i32>
494 // Test simple fir.array_load/fir.array_update conversion without copy-in/copy-out with a `fir.box`
495 func.func @array_update_conversion(%arr1 : !fir.box<!fir.array<?x?xf32>>, %m: index, %n: index) {
496 %c10 = arith.constant 10 : index
497 %c20 = arith.constant 20 : index
498 %c1 = arith.constant 1 : index
499 %f = arith.constant 2.0 : f32
500 %s = fir.shape %m, %n : (index, index) -> !fir.shape<2>
501 %av1 = fir.array_load %arr1(%s) : (!fir.box<!fir.array<?x?xf32>>, !fir.shape<2>) -> !fir.array<?x?xf32>
502 %av2 = fir.array_update %av1, %f, %c1, %c1 : (!fir.array<?x?xf32>, f32, index, index) -> !fir.array<?x?xf32>
508 // Test array operation with conditional update.
510 func.func @array_operation_with_cond_update(%arg0: !fir.ref<!fir.array<100xf32>>, %cond1: i1) {
511 %c100 = arith.constant 100 : index
512 %c1 = arith.constant 1 : index
513 %c-1 = arith.constant -1 : index
514 %f = arith.constant 2.0 : f32
515 %1 = fir.shape %c100 : (index) -> !fir.shape<1>
516 %2 = fir.array_load %arg0(%1) : (!fir.ref<!fir.array<100xf32>>, !fir.shape<1>) -> !fir.array<100xf32>
517 %arg2 = fir.if %cond1 -> !fir.array<100xf32> {
518 fir.result %2 : !fir.array<100xf32>
520 %r = fir.array_update %2, %f, %c1 : (!fir.array<100xf32>, f32, index) -> !fir.array<100xf32>
521 fir.result %r : !fir.array<100xf32>
523 fir.array_merge_store %2, %arg2 to %arg0 : !fir.array<100xf32>, !fir.array<100xf32>, !fir.ref<!fir.array<100xf32>>
527 // CHECK-LABEL: func @array_operation_with_cond_update(
528 // CHECK-SAME: %[[ARG0:.*]]: !fir.ref<!fir.array<100xf32>>, %[[COND:.*]]: i1) {
529 // CHECK: %[[ARRAY_LOAD:.*]] = fir.undefined !fir.array<100xf32>
530 // CHECK: %[[IF_RES:.*]] = fir.if %[[COND]] -> (!fir.array<100xf32>) {
531 // CHECK: fir.result %[[ARRAY_LOAD]] : !fir.array<100xf32>
533 // CHECK: %[[UPDATE0:.*]] = fir.array_coor %[[ARG0]](%{{.*}}) %{{.*}} : (!fir.ref<!fir.array<100xf32>>, !fir.shape<1>, index) -> !fir.ref<f32>
534 // CHECK: fir.store %{{.*}} to %{{.*}} : !fir.ref<f32>
535 // CHECK: fir.result %[[ARRAY_LOAD]] : !fir.array<100xf32>