1// Test for the array-value-copy-pass
2// RUN: fir-opt --split-input-file --array-value-copy %s | FileCheck %s
3
4// Test simple fir.array_load/fir.array_fetch conversion to fir.array_coor
5func @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
11  return
12}
13
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>
26
27// -----
28
29// Test simple fir.array_load/fir.array_update conversion without copy-in/copy-out
30func @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>
38  return
39}
40
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>
48
49// -----
50
51// Test simple fir.array_load/fir.array_update conversion without copy-in/copy-out
52func @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>
60  fir.if %cond {
61    %av2 = fir.array_update %av1, %f, %c1, %c1 : (!fir.array<?x?xf32>, f32, index, index) -> !fir.array<?x?xf32>
62  } else {
63    %av2 = fir.array_update %av1, %g, %c1, %c1 : (!fir.array<?x?xf32>, f32, index, index) -> !fir.array<?x?xf32>
64  }
65  return
66}
67
68// -----
69
70// Test fir.array_load/fir.array_fetch/fir.array_update conversion with
71// an introduced copy-in/copy-out.
72//
73// This test corresponds to a simplified FIR version of the following Fortran
74// code.
75// ```
76//   integer :: i(10)
77//   i = i(10:1:-1)
78//  end
79// ```
80
81func @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>
99  }
100  fir.array_merge_store %2, %8 to %arr0 : !fir.array<10xi32>, !fir.array<10xi32>, !fir.ref<!fir.array<10xi32>>
101  return
102}
103
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:           %[[LOAD0:.*]] = fir.load %[[COOR0]] : !fir.ref<i32>
112// CHECK:           %[[COOR1:.*]] = fir.array_coor %[[TEMP]](%{{.*}}) %{{.*}} : (!fir.heap<!fir.array<10xi32>>, !fir.shape<1>, index) -> !fir.ref<i32>
113// CHECK:           fir.store %[[LOAD0]] to %[[COOR1]] : !fir.ref<i32>
114// CHECK:         }
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>
124// CHECK:         }
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:           %[[LOAD0:.*]] = fir.load %[[COOR0:.*]] : !fir.ref<i32>
129// CHECK:           %[[COOR1:.*]] = fir.array_coor %[[ARR0]](%{{.*}}) %{{.*}} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>, index) -> !fir.ref<i32>
130// CHECK:           fir.store %[[LOAD0]] to %[[COOR1]] : !fir.ref<i32>
131// CHECK:         }
132// Free temporary array.
133// CHECK:         fir.freemem %[[TEMP]] : <!fir.array<10xi32>>
134
135// -----
136
137// Test fir.array_load/fir.array_fetch/fir.array_update conversion with
138// an introduced copy-in/copy-out on a multidimensional array.
139
140func @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>
168    }
169    fir.result %13 : !fir.array<10x5xi32>
170  }
171  fir.array_merge_store %2, %12 to %0 : !fir.array<10x5xi32>, !fir.array<10x5xi32>, !fir.ref<!fir.array<10x5xi32>>
172  return
173}
174
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>, %c10, %c5
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:             %[[LOAD0:.*]] = fir.load %[[COOR0]] : !fir.ref<i32>
190// CHECK:             %[[COOR1:.*]] = fir.array_coor %[[TEMP]](%{{.*}}) %{{.*}}, %{{.*}} : (!fir.heap<!fir.array<10x5xi32>>, !fir.shape<2>, index, index) -> !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:             %[[LOAD0:.*]] = fir.load %[[COOR0]] : !fir.ref<i32>
212// CHECK:             %[[COOR1:.*]] = fir.array_coor %[[ARR0]](%{{.*}}) %{{.*}}, %{{.*}} : (!fir.ref<!fir.array<10x5xi32>>, !fir.shape<2>, index, index) -> !fir.ref<i32>
213// CHECK:             fir.store %[[LOAD0]] to %[[COOR1]] : !fir.ref<i32>
214// CHECK:         fir.freemem %[[TEMP]] : <!fir.array<10x5xi32>>
215
216// -----
217
218// Test fir.array_modify conversion with no overlap.
219func @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
224  %0 = fir.alloca f32
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>
234  }
235  fir.array_merge_store %2, %4 to %arg0 : !fir.array<100xf32>, !fir.array<100xf32>, !fir.ref<!fir.array<100xf32>>
236  return
237}
238
239func private @user_defined_assignment(!fir.ref<f32>, !fir.ref<f32>)
240
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>) -> ()
253
254// -----
255
256// Test fir.array_modify conversion with an overlap.
257// Test user_defined_assignment(arg0(:), arg0(100:1:-1))
258func @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
264  %0 = fir.alloca f32
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>
275  }
276  fir.array_merge_store %2, %5 to %arg0 : !fir.array<100xf32>, !fir.array<100xf32>, !fir.ref<!fir.array<100xf32>>
277  return
278}
279
280func private @user_defined_assignment(!fir.ref<f32>, !fir.ref<f32>)
281
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:             %[[LOAD0:.*]] = fir.load %[[COOR0]] : !fir.ref<f32>
291// CHECK:             %[[COOR1:.*]] = fir.array_coor %[[TEMP]](%{{.*}}) %{{.*}} : (!fir.heap<!fir.array<100xf32>>, !fir.shape<1>, index) -> !fir.ref<f32>
292// CHECK:             fir.store %[[LOAD0]] to %[[COOR1]] : !fir.ref<f32>
293// CHECK:           }
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>) -> ()
303// CHECK:           }
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:             %[[LOAD0:.*]] = fir.load %[[COOR0]] : !fir.ref<f32>
308// CHECK:             %[[COOR1:.*]] = fir.array_coor %[[ARR0]](%{{.*}}) %{{.*}} : (!fir.ref<!fir.array<100xf32>>, !fir.shape<1>, index) -> !fir.ref<f32>
309// CHECK:             fir.store %[[LOAD0]] to %[[COOR1]] : !fir.ref<f32>
310// CHECK:           }
311// Free the temporary array.
312// CHECK:           fir.freemem %[[TEMP]] : <!fir.array<100xf32>>
313// CHECK:           return
314// CHECK:         }
315
316// -----
317
318// Test array of types with no overlap
319func @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>
354    }
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
358  }
359  %5 = fir.convert %4 : (index) -> i32
360  fir.store %5 to %0 : !fir.ref<i32>
361  return
362}
363
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
371
372// -----
373
374// Test fir.array_load/boxed array
375func @conversion_with_temporary_boxed_array(%arr0 : !fir.box<!fir.array<10xi32>>) {
376  %c10 = arith.constant 10 : index
377  %1 = fir.shape %c10 : (index) -> !fir.shape<1>
378  %2 = fir.array_load %arr0(%1) : (!fir.box<!fir.array<10xi32>>, !fir.shape<1>) -> !fir.array<10xi32>
379  %c10_i64 = arith.constant 10 : i64
380  %3 = fir.convert %c10_i64 : (i64) -> index
381  %c1_i64 = arith.constant 1 : i64
382  %c-1_i64 = arith.constant -1 : i64
383  %4 = fir.shape %c10 : (index) -> !fir.shape<1>
384  %5 = fir.slice %c10_i64, %c1_i64, %c-1_i64 : (i64, i64, i64) -> !fir.slice<1>
385  %6 = fir.array_load %arr0(%4) [%5] : (!fir.box<!fir.array<10xi32>>, !fir.shape<1>, !fir.slice<1>) -> !fir.array<10xi32>
386  %c1 = arith.constant 1 : index
387  %c0 = arith.constant 0 : index
388  %7 = arith.subi %3, %c1 : index
389  %8 = fir.do_loop %arg0 = %c0 to %7 step %c1 unordered iter_args(%arg1 = %2) -> (!fir.array<10xi32>) {
390    %9 = fir.array_fetch %6, %arg0 : (!fir.array<10xi32>, index) -> i32
391    %10 = fir.array_update %arg1, %9, %arg0 : (!fir.array<10xi32>, i32, index) -> !fir.array<10xi32>
392    fir.result %10 : !fir.array<10xi32>
393  }
394  fir.array_merge_store %2, %8 to %arr0 : !fir.array<10xi32>, !fir.array<10xi32>, !fir.box<!fir.array<10xi32>>
395  return
396}
397
398// CHECK-LABEL: func @conversion_with_temporary_boxed_array(
399// CHECK-SAME:                                              %[[ARR0:.*]]: !fir.box<!fir.array<10xi32>>)
400// Allocation of temporary array.
401// CHECK:         %[[TEMP:.*]] = fir.allocmem !fir.array<10xi32>, %{{.*}}
402// Copy of original array to temp.
403// CHECK:         fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} {
404// CHECK:           %[[COOR0:.*]] = fir.array_coor %[[ARR0]](%{{.*}}) %{{.*}} : (!fir.box<!fir.array<10xi32>>, !fir.shape<1>, index) -> !fir.ref<i32>
405// CHECK:           %[[LOAD0:.*]] = fir.load %[[COOR0]] : !fir.ref<i32>
406// CHECK:           %[[COOR1:.*]] = fir.array_coor %[[TEMP]](%{{.*}}) %{{.*}} : (!fir.heap<!fir.array<10xi32>>, !fir.shape<1>, index) -> !fir.ref<i32>
407// CHECK:           fir.store %[[LOAD0]] to %[[COOR1]] : !fir.ref<i32>
408// CHECK:         }
409// Perform the assignment i = i(10:1:-1) using the temporary array.
410// CHECK:         %{{.*}} = fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} unordered iter_args(%{{.*}} = %{{.*}}) -> (!fir.array<10xi32>) {
411// CHECK-NOT:       %{{.*}} = fir.array_fetch
412// CHECK-NOT:       %{{.*}} = fir.update
413// CHECK:           %[[COOR0:.*]] = fir.array_coor %[[ARR0]](%{{.*}}) [%{{.*}}] %{{.*}} : (!fir.box<!fir.array<10xi32>>, !fir.shape<1>, !fir.slice<1>, index) -> !fir.ref<i32>
414// CHECK:           %[[LOAD0:.*]] = fir.load %[[COOR0]] : !fir.ref<i32>
415// CHECK:           %[[COOR1:.*]] = fir.array_coor %[[TEMP]](%{{.*}}) %{{.*}} : (!fir.heap<!fir.array<10xi32>>, !fir.shape<1>, index) -> !fir.ref<i32>
416// CHECK:           fir.store %[[LOAD0]] to %[[COOR1]] : !fir.ref<i32>
417// CHECK:           fir.result %{{.*}} : !fir.array<10xi32>
418// CHECK:         }
419// Copy the result back to the original array.
420// CHECK:         fir.do_loop %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} {
421// CHECK:           %[[COOR0:.*]] = fir.array_coor %[[TEMP]](%{{.*}}) %{{.*}} : (!fir.heap<!fir.array<10xi32>>, !fir.shape<1>, index) -> !fir.ref<i32>
422// CHECK:           %[[LOAD0:.*]] = fir.load %[[COOR0:.*]] : !fir.ref<i32>
423// CHECK:           %[[COOR1:.*]] = fir.array_coor %[[ARR0]](%{{.*}}) %{{.*}} : (!fir.box<!fir.array<10xi32>>, !fir.shape<1>, index) -> !fir.ref<i32>
424// CHECK:           fir.store %[[LOAD0]] to %[[COOR1]] : !fir.ref<i32>
425// CHECK:         }
426// Free temporary array.
427// CHECK:         fir.freemem %[[TEMP]] : <!fir.array<10xi32>>
428
429// -----
430
431// Test simple fir.array_update with Fortran.offsets attribute.
432func @array_update_conversion(%arr1 : !fir.box<!fir.array<?x?xf32>>, %m: index, %n: index) {
433  %c10 = arith.constant 10 : index
434  %c20 = arith.constant 20 : index
435  %c1 = arith.constant 1 : index
436  %f = arith.constant 2.0 : f32
437  %s = fir.shape %m, %n : (index, index) -> !fir.shape<2>
438  %av1 = fir.array_load %arr1(%s) : (!fir.box<!fir.array<?x?xf32>>, !fir.shape<2>) -> !fir.array<?x?xf32>
439  %av2 = fir.array_update %av1, %f, %c1, %c1 {Fortran.offsets} : (!fir.array<?x?xf32>, f32, index, index) -> !fir.array<?x?xf32>
440  return
441}
442
443// CHECK-LABEL: func @array_update_conversion
444// CHECK-NOT:     fir.array_update
445// CHECK-NOT:     %{{.*}} = arith.addi %{{.*}}, %{{.*}} : index
446// CHECK:         %[[ARRAY_COOR:.*]] = fir.array_coor{{.*}}-> !fir.ref<f32>
447// CHECK:         fir.store %{{.*}} to %[[ARRAY_COOR]] : !fir.ref<f32>
448
449// -----
450
451// Test fir.array_fetch on derived type members in an array of derived types.
452func @array_fetch_derived_type(%0 : !fir.ref<!fir.array<10x!fir.type<_QTu{mt:!fir.type<_QTt{mem:i32}>}>>>) {
453  %1 = fir.alloca i32 {bindc_name = "i", uniq_name = "_QEi"}
454  %c1_i32 = arith.constant 1 : i32
455  %2 = fir.convert %c1_i32 : (i32) -> index
456  %c10_i32 = arith.constant 10 : i32
457  %3 = fir.convert %c10_i32 : (i32) -> index
458  %c1 = arith.constant 1 : index
459  %shape = fir.shape %2 : (index) -> !fir.shape<1>
460  %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}>}>>
461  %4 = fir.do_loop %arg0 = %2 to %3 step %c1 -> index {
462    %6 = fir.convert %arg0 : (index) -> i32
463    fir.store %6 to %1 : !fir.ref<i32>
464    %c1_i32_0 = arith.constant 1 : i32
465    %7 = fir.load %1 : !fir.ref<i32>
466    %8 = fir.convert %7 : (i32) -> i64
467    %c1_i64 = arith.constant 1 : i64
468    %9 = arith.subi %8, %c1_i64 : i64
469    %11 = fir.field_index mt, !fir.type<_QTu{mt:!fir.type<_QTt{mem:i32}>}>
470    %12 = fir.field_index mem, !fir.type<_QTt{mem:i32}>
471    %idx = fir.convert %9 : (i64) -> index
472    %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
473    %14 = arith.addi %arg0, %c1 : index
474    fir.result %14 : index
475  }
476  %5 = fir.convert %4 : (index) -> i32
477  fir.store %5 to %1 : !fir.ref<i32>
478  return
479}
480
481// CHECK-LABEL: func @array_fetch_derived_type(
482// CHECK-SAME:                                 %[[ARR0:.*]]: !fir.ref<!fir.array<10x!fir.type<_QTu{mt:!fir.type<_QTt{mem:i32}>}>>>) {
483// CHECK:         %{{.*}} = fir.do_loop
484// CHECK:           %[[FIELD_MT:.*]] = fir.field_index mt, !fir.type<_QTu{mt:!fir.type<_QTt{mem:i32}>}>
485// CHECK:           %[[FIELD_MEM:.*]] = fir.field_index mem, !fir.type<_QTt{mem:i32}>
486// CHECK-NOT:       %{{.*}} = fir.array_fetch
487// 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}>}>>
488// 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>
489// CHECK:           %{{.*}} = fir.load %[[COOR_OF]] : !fir.ref<i32>
490
491// -----
492
493// Test simple fir.array_load/fir.array_update conversion without copy-in/copy-out with a `fir.box`
494func @array_update_conversion(%arr1 : !fir.box<!fir.array<?x?xf32>>, %m: index, %n: index) {
495  %c10 = arith.constant 10 : index
496  %c20 = arith.constant 20 : index
497  %c1 = arith.constant 1 : index
498  %f = arith.constant 2.0 : f32
499  %s = fir.shape %m, %n : (index, index) -> !fir.shape<2>
500  %av1 = fir.array_load %arr1(%s) : (!fir.box<!fir.array<?x?xf32>>, !fir.shape<2>) -> !fir.array<?x?xf32>
501  %av2 = fir.array_update %av1, %f, %c1, %c1 : (!fir.array<?x?xf32>, f32, index, index) -> !fir.array<?x?xf32>
502  return
503}
504
505// -----
506
507// Test array operation with conditional update.
508
509func @array_operation_with_cond_update(%arg0: !fir.ref<!fir.array<100xf32>>, %cond1: i1) {
510  %c100 = arith.constant 100 : index
511  %c1 = arith.constant 1 : index
512  %c-1 = arith.constant -1 : index
513  %f = arith.constant 2.0 : f32
514  %1 = fir.shape %c100 : (index) -> !fir.shape<1>
515  %2 = fir.array_load %arg0(%1) : (!fir.ref<!fir.array<100xf32>>, !fir.shape<1>) -> !fir.array<100xf32>
516  %arg2 = fir.if %cond1 -> !fir.array<100xf32> {
517    fir.result %2 : !fir.array<100xf32>
518  } else {
519    %r = fir.array_update %2, %f, %c1 : (!fir.array<100xf32>, f32, index) -> !fir.array<100xf32>
520    fir.result %r : !fir.array<100xf32>
521  }
522  fir.array_merge_store %2, %arg2 to %arg0 : !fir.array<100xf32>, !fir.array<100xf32>, !fir.ref<!fir.array<100xf32>>
523  return
524}
525
526// CHECK-LABEL: func @array_operation_with_cond_update(
527// CHECK-SAME:                                         %[[ARG0:.*]]: !fir.ref<!fir.array<100xf32>>, %[[COND:.*]]: i1) {
528// CHECK:         %[[ARRAY_LOAD:.*]] = fir.undefined !fir.array<100xf32>
529// CHECK:         %[[IF_RES:.*]] = fir.if %[[COND]] -> (!fir.array<100xf32>) {
530// CHECK:           fir.result %[[ARRAY_LOAD]] : !fir.array<100xf32>
531// CHECK:         } else {
532// CHECK:           %[[UPDATE0:.*]] = fir.array_coor %[[ARG0]](%{{.*}}) %{{.*}} : (!fir.ref<!fir.array<100xf32>>, !fir.shape<1>, index) -> !fir.ref<f32>
533// CHECK:           fir.store %{{.*}} to %{{.*}} : !fir.ref<f32>
534// CHECK:           fir.result %[[ARRAY_LOAD]] : !fir.array<100xf32>
535// CHECK:    }
536