xref: /llvm-project/flang/test/Fir/array-value-copy.fir (revision c628e9eb5e959c043103eb0c760c796d1396e50f)
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.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
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.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>
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.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>
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.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>
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:           %[[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>
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:           %[[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>
131// CHECK:         }
132// Free temporary array.
133// CHECK:         fir.freemem %[[TEMP]] : !fir.heap<!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.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>
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>
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>>
215
216// -----
217
218// Test fir.array_modify conversion with no overlap.
219func.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
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.func 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.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
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.func 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:             %[[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>
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:             %[[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>
310// CHECK:           }
311// Free the temporary array.
312// CHECK:           fir.freemem %[[TEMP]] : !fir.heap<!fir.array<100xf32>>
313// CHECK:           return
314// CHECK:         }
315
316// -----
317
318// Test array of types with no overlap
319func.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>
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.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>
394  }
395  fir.array_merge_store %2, %8 to %arr0 : !fir.array<10xi32>, !fir.array<10xi32>, !fir.box<!fir.array<10xi32>>
396  return
397}
398
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>
409// CHECK:         }
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>
419// CHECK:         }
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>
426// CHECK:         }
427// Free temporary array.
428// CHECK:         fir.freemem %[[TEMP]] : !fir.heap<!fir.array<10xi32>>
429
430// -----
431
432// Test simple fir.array_update with Fortran.offsets attribute.
433func.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>
441  return
442}
443
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>
449
450// -----
451
452// Test fir.array_fetch on derived type members in an array of derived types.
453func.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
476  }
477  %5 = fir.convert %4 : (index) -> i32
478  fir.store %5 to %1 : !fir.ref<i32>
479  return
480}
481
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>
491
492// -----
493
494// Test simple fir.array_load/fir.array_update conversion without copy-in/copy-out with a `fir.box`
495func.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>
503  return
504}
505
506// -----
507
508// Test array operation with conditional update.
509
510func.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>
519  } else {
520    %r = fir.array_update %2, %f, %c1 : (!fir.array<100xf32>, f32, index) -> !fir.array<100xf32>
521    fir.result %r : !fir.array<100xf32>
522  }
523  fir.array_merge_store %2, %arg2 to %arg0 : !fir.array<100xf32>, !fir.array<100xf32>, !fir.ref<!fir.array<100xf32>>
524  return
525}
526
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>
532// CHECK:         } else {
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>
536// CHECK:    }
537