xref: /llvm-project/flang/test/Fir/array-copies-pointers.fir (revision c4204c0b29a6721267b1bcbaeedd7b1118e42396)
1// Test array-copy-value pass (copy elision) with array assignment
2// involving Fortran pointers. Focus in only on wether copy ellision
3// is made or not.
4// RUN: fir-opt %s --array-value-copy -split-input-file | FileCheck --check-prefixes=ALL,NOOPT %s
5// RUN: fir-opt %s --array-value-copy="optimize-conflicts=true" -split-input-file | FileCheck --check-prefixes=ALL,OPT %s
6
7// Test `pointer(:) = array(:)`
8// ALL-LABEL: func @maybe_overlap
9// ALL: %[[ALLOC:.*]] = fir.allocmem !fir.array<100xf32>
10// ALL: fir.do_loop
11// ALL: fir.do_loop
12// ALL: fir.do_loop
13// ALL: fir.freemem %[[ALLOC]] : !fir.heap<!fir.array<100xf32>>
14func.func @maybe_overlap(%arg0: !fir.ptr<!fir.array<100xf32>>, %arg1 : !fir.ref<!fir.array<100xf32>> {fir.target}) {
15  %c100 = arith.constant 100 : index
16  %c99 = arith.constant 99 : index
17  %c1 = arith.constant 1 : index
18  %c0 = arith.constant 0 : index
19  %0 = fir.alloca f32
20  %1 = fir.shape %c100 : (index) -> !fir.shape<1>
21  %2 = fir.array_load %arg0(%1) : (!fir.ptr<!fir.array<100xf32>>, !fir.shape<1>) -> !fir.array<100xf32>
22  %3 = fir.array_load %arg1(%1) : (!fir.ref<!fir.array<100xf32>>, !fir.shape<1>) -> !fir.array<100xf32>
23  %4 = fir.do_loop %arg2 = %c0 to %c99 step %c1 unordered iter_args(%arg3 = %2) -> (!fir.array<100xf32>) {
24    %5 = fir.array_fetch %3, %arg2 : (!fir.array<100xf32>, index) -> f32
25    %6 = fir.array_update %arg3, %5, %arg2 : (!fir.array<100xf32>, f32, index) -> !fir.array<100xf32>
26    fir.result %6 : !fir.array<100xf32>
27  }
28  fir.array_merge_store %2, %4 to %arg0 : !fir.array<100xf32>, !fir.array<100xf32>, !fir.ptr<!fir.array<100xf32>>
29  return
30}
31
32// -----
33
34// Test `pointer(:) = array(:)`
35// ALL-LABEL: func @no_overlap1
36// OPT-NOT: fir.allocmem
37// NOOPT: %[[ALLOC:.*]] = fir.allocmem !fir.array<100xf32>
38// NOOPT: fir.do_loop
39// NOOPT: fir.do_loop
40// NOOPT: fir.do_loop
41// NOOPT: fir.freemem %[[ALLOC]] : !fir.heap<!fir.array<100xf32>>
42func.func @no_overlap1(%arg0: !fir.ptr<!fir.array<100xf32>>, %arg1 : !fir.ref<!fir.array<100xf32>>) {
43  %c100 = arith.constant 100 : index
44  %c99 = arith.constant 99 : index
45  %c1 = arith.constant 1 : index
46  %c0 = arith.constant 0 : index
47  %0 = fir.alloca f32
48  %1 = fir.shape %c100 : (index) -> !fir.shape<1>
49  %2 = fir.array_load %arg0(%1) : (!fir.ptr<!fir.array<100xf32>>, !fir.shape<1>) -> !fir.array<100xf32>
50  %3 = fir.array_load %arg1(%1) : (!fir.ref<!fir.array<100xf32>>, !fir.shape<1>) -> !fir.array<100xf32>
51  %4 = fir.do_loop %arg2 = %c0 to %c99 step %c1 unordered iter_args(%arg3 = %2) -> (!fir.array<100xf32>) {
52    %5 = fir.array_fetch %3, %arg2 : (!fir.array<100xf32>, index) -> f32
53    %6 = fir.array_update %arg3, %5, %arg2 : (!fir.array<100xf32>, f32, index) -> !fir.array<100xf32>
54    fir.result %6 : !fir.array<100xf32>
55  }
56  fir.array_merge_store %2, %4 to %arg0 : !fir.array<100xf32>, !fir.array<100xf32>, !fir.ptr<!fir.array<100xf32>>
57  return
58}
59
60// -----
61
62// Test `pointer(:) = pointer(:)`
63// ALL-LABEL: func @no_overlap
64// ALL-NOT: fir.allocmem
65// ALL:     fir.do_loop
66// ALL:       fir.array_coor
67// ALL:       fir.array_coor
68// ALL:       fir.store
69func.func @no_overlap(%arg0: !fir.ptr<!fir.array<100xf32>>, %arg1: !fir.ref<!fir.array<100xf32>>) {
70  %c100 = arith.constant 100 : index
71  %c99 = arith.constant 99 : index
72  %c1 = arith.constant 1 : index
73  %c0 = arith.constant 0 : index
74  %0 = fir.alloca f32
75  %1 = fir.shape %c100 : (index) -> !fir.shape<1>
76  %2 = fir.array_load %arg0(%1) : (!fir.ptr<!fir.array<100xf32>>, !fir.shape<1>) -> !fir.array<100xf32>
77  %3 = fir.do_loop %arg2 = %c0 to %c99 step %c1 unordered iter_args(%arg3 = %2) -> (!fir.array<100xf32>) {
78    %4 = fir.array_fetch %2, %arg2 : (!fir.array<100xf32>, index) -> f32
79    %5 = fir.array_update %arg3, %4, %arg2 : (!fir.array<100xf32>, f32, index) -> !fir.array<100xf32>
80    fir.result %5 : !fir.array<100xf32>
81  }
82  fir.array_merge_store %2, %3 to %arg0 : !fir.array<100xf32>, !fir.array<100xf32>, !fir.ptr<!fir.array<100xf32>>
83  return
84}
85
86// -----
87
88// Test `array(:) = pointer(:)`
89// ALL-LABEL: func @maybe_overlap_2
90// ALL: %[[ALLOC:.*]] = fir.allocmem !fir.array<100xf32>
91// ALL: fir.do_loop
92// ALL: fir.do_loop
93// ALL: fir.do_loop
94// ALL: fir.freemem %[[ALLOC]] : !fir.heap<!fir.array<100xf32>>
95func.func @maybe_overlap_2(%arg0: !fir.ptr<!fir.array<100xf32>>, %arg1: !fir.ref<!fir.array<100xf32>> {fir.target}) {
96  %c100 = arith.constant 100 : index
97  %c99 = arith.constant 99 : index
98  %c1 = arith.constant 1 : index
99  %c0 = arith.constant 0 : index
100  %0 = fir.alloca f32
101  %1 = fir.shape %c100 : (index) -> !fir.shape<1>
102  %2 = fir.array_load %arg0(%1) : (!fir.ptr<!fir.array<100xf32>>, !fir.shape<1>) -> !fir.array<100xf32>
103  %3 = fir.array_load %arg1(%1) : (!fir.ref<!fir.array<100xf32>>, !fir.shape<1>) -> !fir.array<100xf32>
104  %4 = fir.do_loop %arg2 = %c0 to %c99 step %c1 unordered iter_args(%arg3 = %3) -> (!fir.array<100xf32>) {
105    %5 = fir.array_fetch %2, %arg2 : (!fir.array<100xf32>, index) -> f32
106    %6 = fir.array_update %arg3, %5, %arg2 : (!fir.array<100xf32>, f32, index) -> !fir.array<100xf32>
107    fir.result %6 : !fir.array<100xf32>
108  }
109  fir.array_merge_store %3, %4 to %arg1 : !fir.array<100xf32>, !fir.array<100xf32>, !fir.ref<!fir.array<100xf32>>
110  return
111}
112
113// -----
114
115// Test `array(:) = pointer(:)`
116// ALL-LABEL: func @no_overlap_2
117// OPT-NOT: fir.allocmem
118// NOOPT: %[[ALLOC:.*]] = fir.allocmem !fir.array<100xf32>
119// NOOPT: fir.do_loop
120// NOOPT: fir.do_loop
121// NOOPT: fir.do_loop
122// NOOPT: fir.freemem %[[ALLOC]] : !fir.heap<!fir.array<100xf32>>
123func.func @no_overlap_2(%arg0: !fir.ptr<!fir.array<100xf32>>, %arg1: !fir.ref<!fir.array<100xf32>>) {
124  %c100 = arith.constant 100 : index
125  %c99 = arith.constant 99 : index
126  %c1 = arith.constant 1 : index
127  %c0 = arith.constant 0 : index
128  %0 = fir.alloca f32
129  %1 = fir.shape %c100 : (index) -> !fir.shape<1>
130  %2 = fir.array_load %arg0(%1) : (!fir.ptr<!fir.array<100xf32>>, !fir.shape<1>) -> !fir.array<100xf32>
131  %3 = fir.array_load %arg1(%1) : (!fir.ref<!fir.array<100xf32>>, !fir.shape<1>) -> !fir.array<100xf32>
132  %4 = fir.do_loop %arg2 = %c0 to %c99 step %c1 unordered iter_args(%arg3 = %3) -> (!fir.array<100xf32>) {
133    %5 = fir.array_fetch %2, %arg2 : (!fir.array<100xf32>, index) -> f32
134    %6 = fir.array_update %arg3, %5, %arg2 : (!fir.array<100xf32>, f32, index) -> !fir.array<100xf32>
135    fir.result %6 : !fir.array<100xf32>
136  }
137  fir.array_merge_store %3, %4 to %arg1 : !fir.array<100xf32>, !fir.array<100xf32>, !fir.ref<!fir.array<100xf32>>
138  return
139}
140
141// -----
142
143// Test `pointer1(:) = pointer2(:)`
144// ALL-LABEL: func @maybe_overlap_3
145// ALL: %[[ALLOC:.*]] = fir.allocmem !fir.array<100xf32>
146// ALL: fir.do_loop
147// ALL: fir.do_loop
148// ALL: fir.do_loop
149// ALL: fir.freemem %[[ALLOC]] : !fir.heap<!fir.array<100xf32>>
150func.func @maybe_overlap_3(%arg0: !fir.ptr<!fir.array<100xf32>>, %arg1: !fir.ptr<!fir.array<100xf32>>) {
151  %c100 = arith.constant 100 : index
152  %c99 = arith.constant 99 : index
153  %c1 = arith.constant 1 : index
154  %c0 = arith.constant 0 : index
155  %0 = fir.alloca f32
156  %1 = fir.shape %c100 : (index) -> !fir.shape<1>
157  %2 = fir.array_load %arg0(%1) : (!fir.ptr<!fir.array<100xf32>>, !fir.shape<1>) -> !fir.array<100xf32>
158  %3 = fir.array_load %arg1(%1) : (!fir.ptr<!fir.array<100xf32>>, !fir.shape<1>) -> !fir.array<100xf32>
159  %4 = fir.do_loop %arg2 = %c0 to %c99 step %c1 unordered iter_args(%arg3 = %3) -> (!fir.array<100xf32>) {
160    %5 = fir.array_fetch %2, %arg2 : (!fir.array<100xf32>, index) -> f32
161    %6 = fir.array_update %arg3, %5, %arg2 : (!fir.array<100xf32>, f32, index) -> !fir.array<100xf32>
162    fir.result %6 : !fir.array<100xf32>
163  }
164  fir.array_merge_store %3, %4 to %arg1 : !fir.array<100xf32>, !fir.array<100xf32>, !fir.ptr<!fir.array<100xf32>>
165  return
166}
167
168// -----
169
170// Test derived_target(:)%i = integer_pointer(:)
171// The integer pointer may be aliasing the derived target component.
172// ALL-LABEL: func @derived_whose_component_may_be_aliased
173// ALL: %[[ALLOC:.*]] = fir.allocmem !fir.array<4x!fir.type<some_type{i:i32}>>
174// ALL-COUNT-3: fir.do_loop
175// ALL: fir.freemem %[[ALLOC]] : !fir.heap<!fir.array<4x!fir.type<some_type{i:i32}>>>
176func.func @derived_whose_component_may_be_aliased(%arg0: !fir.box<!fir.array<4x!fir.type<some_type{i:i32}>>> {fir.target}, %arg1: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>) {
177  %c4 = arith.constant 4 : index
178  %0 = fir.field_index i, !fir.type<some_type{i:i32}>
179  %c1 = arith.constant 1 : index
180  %1 = fir.slice %c1, %c4, %c1 path %0 : (index, index, index, !fir.field) -> !fir.slice<1>
181  %2 = fir.array_load %arg0 [%1] : (!fir.box<!fir.array<4x!fir.type<some_type{i:i32}>>>, !fir.slice<1>) -> !fir.array<4xi32>
182  %3 = fir.load %arg1 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
183  %c0 = arith.constant 0 : index
184  %4:3 = fir.box_dims %3, %c0 : (!fir.box<!fir.ptr<!fir.array<?xi32>>>, index) -> (index, index, index)
185  %5 = fir.shift %4#0 : (index) -> !fir.shift<1>
186  %6 = fir.array_load %3(%5) : (!fir.box<!fir.ptr<!fir.array<?xi32>>>, !fir.shift<1>) -> !fir.array<?xi32>
187  %7 = arith.subi %c4, %c1 : index
188  %8 = fir.do_loop %arg2 = %c0 to %7 step %c1 unordered iter_args(%arg3 = %2) -> (!fir.array<4xi32>) {
189    %9 = fir.array_fetch %6, %arg2 : (!fir.array<?xi32>, index) -> i32
190    %10 = fir.array_update %arg3, %9, %arg2 : (!fir.array<4xi32>, i32, index) -> !fir.array<4xi32>
191    fir.result %10 : !fir.array<4xi32>
192  }
193  fir.array_merge_store %2, %8 to %arg0[%1] : !fir.array<4xi32>, !fir.array<4xi32>, !fir.box<!fir.array<4x!fir.type<some_type{i:i32}>>>, !fir.slice<1>
194  return
195}
196
197// -----
198
199// Test real_target = complex_target(:)%re
200// The real pointer may be aliasing the complex real part.
201// ALL-LABEL: func @complex_real_aliasing
202// ALL: %[[ALLOC:.*]] = fir.allocmem !fir.array<?xf32>
203// ALL-COUNT-3: fir.do_loop
204// ALL: fir.freemem %[[ALLOC]] : !fir.heap<!fir.array<?xf32>>
205func.func @complex_real_aliasing(%arg0: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>, %arg1: !fir.ref<!fir.array<4xcomplex<f32>>> {fir.target}) {
206  %c4 = arith.constant 4 : index
207  %0 = fir.load %arg0 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>
208  %c0 = arith.constant 0 : index
209  %1:3 = fir.box_dims %0, %c0 : (!fir.box<!fir.ptr<!fir.array<?xf32>>>, index) -> (index, index, index)
210  %2 = fir.shift %1#0 : (index) -> !fir.shift<1>
211  %3 = fir.array_load %0(%2) : (!fir.box<!fir.ptr<!fir.array<?xf32>>>, !fir.shift<1>) -> !fir.array<?xf32>
212  %c0_i32 = arith.constant 0 : i32
213  %4 = fir.shape %c4 : (index) -> !fir.shape<1>
214  %c1 = arith.constant 1 : index
215  %5 = fir.slice %c1, %c4, %c1 path %c0_i32 : (index, index, index, i32) -> !fir.slice<1>
216  %6 = fir.array_load %arg1(%4) [%5] : (!fir.ref<!fir.array<4xcomplex<f32>>>, !fir.shape<1>, !fir.slice<1>) -> !fir.array<4xf32>
217  %7 = arith.subi %c4, %c1 : index
218  %8 = fir.do_loop %arg2 = %c0 to %7 step %c1 unordered iter_args(%arg3 = %3) -> (!fir.array<?xf32>) {
219    %9 = fir.array_fetch %6, %arg2 : (!fir.array<4xf32>, index) -> f32
220    %10 = fir.array_update %arg3, %9, %arg2 : (!fir.array<?xf32>, f32, index) -> !fir.array<?xf32>
221    fir.result %10 : !fir.array<?xf32>
222  }
223  fir.array_merge_store %3, %8 to %0 : !fir.array<?xf32>, !fir.array<?xf32>, !fir.box<!fir.ptr<!fir.array<?xf32>>>
224  return
225}
226
227// -----
228
229// Test `array(:) = pointer(:)`
230// ALL-LABEL: func @maybe_overlap_3
231// ALL: %[[ALLOC:.*]] = fir.allocmem !fir.array<100xf32>
232// ALL: fir.do_loop
233// ALL: fir.do_loop
234// ALL: fir.do_loop
235// ALL: fir.freemem %[[ALLOC]] : !fir.heap<!fir.array<100xf32>>
236fir.global @_QMdataEglob target : !fir.array<100xf32> {
237  %0 = fir.undefined !fir.array<100xf32>
238  fir.has_value %0 : !fir.array<100xf32>
239}
240
241func.func @maybe_overlap_3(%arg0: !fir.ptr<!fir.array<100xf32>>, %arg1: !fir.ref<!fir.array<100xf32>> {fir.target}) {
242  %c100 = arith.constant 100 : index
243  %c99 = arith.constant 99 : index
244  %c1 = arith.constant 1 : index
245  %c0 = arith.constant 0 : index
246  %0 = fir.address_of(@_QMdataEglob) : !fir.ref<!fir.array<100xf32>>
247  %1 = fir.shape %c100 : (index) -> !fir.shape<1>
248  %2 = fir.array_load %arg0(%1) : (!fir.ptr<!fir.array<100xf32>>, !fir.shape<1>) -> !fir.array<100xf32>
249  %3 = fir.array_load %0(%1) : (!fir.ref<!fir.array<100xf32>>, !fir.shape<1>) -> !fir.array<100xf32>
250  %4 = fir.do_loop %arg2 = %c0 to %c99 step %c1 unordered iter_args(%arg3 = %3) -> (!fir.array<100xf32>) {
251    %5 = fir.array_fetch %2, %arg2 : (!fir.array<100xf32>, index) -> f32
252    %6 = fir.array_update %arg3, %5, %arg2 : (!fir.array<100xf32>, f32, index) -> !fir.array<100xf32>
253    fir.result %6 : !fir.array<100xf32>
254  }
255  fir.array_merge_store %3, %4 to %0 : !fir.array<100xf32>, !fir.array<100xf32>, !fir.ref<!fir.array<100xf32>>
256  return
257}
258
259// -----
260
261// Test `array(:) = pointer(:)`
262// ALL-LABEL: func @no_overlap_3
263// OPT-NOT: fir.allocmem
264// NOOPT: %[[ALLOC:.*]] = fir.allocmem !fir.array<100xf32>
265// NOOPT: fir.do_loop
266// NOOPT: fir.do_loop
267// NOOPT: fir.do_loop
268// NOOPT: fir.freemem %[[ALLOC]] : !fir.heap<!fir.array<100xf32>>
269fir.global @_QMdataEglob : !fir.array<100xf32> {
270  %0 = fir.undefined !fir.array<100xf32>
271  fir.has_value %0 : !fir.array<100xf32>
272}
273
274func.func @no_overlap_3(%arg0: !fir.ptr<!fir.array<100xf32>>, %arg1: !fir.ref<!fir.array<100xf32>> {fir.target}) {
275  %c100 = arith.constant 100 : index
276  %c99 = arith.constant 99 : index
277  %c1 = arith.constant 1 : index
278  %c0 = arith.constant 0 : index
279  %0 = fir.address_of(@_QMdataEglob) : !fir.ref<!fir.array<100xf32>>
280  %1 = fir.shape %c100 : (index) -> !fir.shape<1>
281  %2 = fir.array_load %arg0(%1) : (!fir.ptr<!fir.array<100xf32>>, !fir.shape<1>) -> !fir.array<100xf32>
282  %3 = fir.array_load %0(%1) : (!fir.ref<!fir.array<100xf32>>, !fir.shape<1>) -> !fir.array<100xf32>
283  %4 = fir.do_loop %arg2 = %c0 to %c99 step %c1 unordered iter_args(%arg3 = %3) -> (!fir.array<100xf32>) {
284    %5 = fir.array_fetch %2, %arg2 : (!fir.array<100xf32>, index) -> f32
285    %6 = fir.array_update %arg3, %5, %arg2 : (!fir.array<100xf32>, f32, index) -> !fir.array<100xf32>
286    fir.result %6 : !fir.array<100xf32>
287  }
288  fir.array_merge_store %3, %4 to %0 : !fir.array<100xf32>, !fir.array<100xf32>, !fir.ref<!fir.array<100xf32>>
289  return
290}
291