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 %s
5
6// Test `pointer(:) = array(:)`
7// TODO: array should have target attribute.
8// CHECK-LABEL: func @maybe_overlap
9// CHECK: %[[ALLOC:.*]] = fir.allocmem !fir.array<100xf32>
10// CHECK: fir.do_loop
11// CHECK: fir.do_loop
12// CHECK: fir.do_loop
13// CHECK: fir.freemem %[[ALLOC]] : !fir.heap<!fir.array<100xf32>>
14func.func @maybe_overlap(%arg0: !fir.ptr<!fir.array<100xf32>>, %arg1: !fir.ref<!fir.array<100xf32>>) {
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(:) = pointer(:)`
35// CHECK-LABEL: func @no_overlap
36// CHECK-NOT: fir.allocmem
37// CHECK:     fir.do_loop
38// CHECK:       fir.array_coor
39// CHECK:       fir.array_coor
40// CHECK:       fir.store
41func.func @no_overlap(%arg0: !fir.ptr<!fir.array<100xf32>>, %arg1: !fir.ref<!fir.array<100xf32>>) {
42  %c100 = arith.constant 100 : index
43  %c99 = arith.constant 99 : index
44  %c1 = arith.constant 1 : index
45  %c0 = arith.constant 0 : index
46  %0 = fir.alloca f32
47  %1 = fir.shape %c100 : (index) -> !fir.shape<1>
48  %2 = fir.array_load %arg0(%1) : (!fir.ptr<!fir.array<100xf32>>, !fir.shape<1>) -> !fir.array<100xf32>
49  %3 = fir.do_loop %arg2 = %c0 to %c99 step %c1 unordered iter_args(%arg3 = %2) -> (!fir.array<100xf32>) {
50    %4 = fir.array_fetch %2, %arg2 : (!fir.array<100xf32>, index) -> f32
51    %5 = fir.array_update %arg3, %4, %arg2 : (!fir.array<100xf32>, f32, index) -> !fir.array<100xf32>
52    fir.result %5 : !fir.array<100xf32>
53  }
54  fir.array_merge_store %2, %3 to %arg0 : !fir.array<100xf32>, !fir.array<100xf32>, !fir.ptr<!fir.array<100xf32>>
55  return
56}
57
58// -----
59
60// Test `array(:) = pointer(:)`
61// TODO: array should have target attribute.
62// CHECK-LABEL: func @maybe_overlap_2
63// CHECK: %[[ALLOC:.*]] = fir.allocmem !fir.array<100xf32>
64// CHECK: fir.do_loop
65// CHECK: fir.do_loop
66// CHECK: fir.do_loop
67// CHECK: fir.freemem %[[ALLOC]] : !fir.heap<!fir.array<100xf32>>
68func.func @maybe_overlap_2(%arg0: !fir.ptr<!fir.array<100xf32>>, %arg1: !fir.ref<!fir.array<100xf32>>) {
69  %c100 = arith.constant 100 : index
70  %c99 = arith.constant 99 : index
71  %c1 = arith.constant 1 : index
72  %c0 = arith.constant 0 : index
73  %0 = fir.alloca f32
74  %1 = fir.shape %c100 : (index) -> !fir.shape<1>
75  %2 = fir.array_load %arg0(%1) : (!fir.ptr<!fir.array<100xf32>>, !fir.shape<1>) -> !fir.array<100xf32>
76  %3 = fir.array_load %arg1(%1) : (!fir.ref<!fir.array<100xf32>>, !fir.shape<1>) -> !fir.array<100xf32>
77  %4 = fir.do_loop %arg2 = %c0 to %c99 step %c1 unordered iter_args(%arg3 = %3) -> (!fir.array<100xf32>) {
78    %5 = fir.array_fetch %2, %arg2 : (!fir.array<100xf32>, index) -> f32
79    %6 = fir.array_update %arg3, %5, %arg2 : (!fir.array<100xf32>, f32, index) -> !fir.array<100xf32>
80    fir.result %6 : !fir.array<100xf32>
81  }
82  fir.array_merge_store %3, %4 to %arg1 : !fir.array<100xf32>, !fir.array<100xf32>, !fir.ref<!fir.array<100xf32>>
83  return
84}
85
86// -----
87
88// Test `pointer1(:) = pointer2(:)`
89// CHECK-LABEL: func @maybe_overlap_3
90// CHECK: %[[ALLOC:.*]] = fir.allocmem !fir.array<100xf32>
91// CHECK: fir.do_loop
92// CHECK: fir.do_loop
93// CHECK: fir.do_loop
94// CHECK: fir.freemem %[[ALLOC]] : !fir.heap<!fir.array<100xf32>>
95func.func @maybe_overlap_3(%arg0: !fir.ptr<!fir.array<100xf32>>, %arg1: !fir.ptr<!fir.array<100xf32>>) {
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.ptr<!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.ptr<!fir.array<100xf32>>
110  return
111}
112
113// -----
114
115// Test derived_target(:)%i = integer_pointer(:)
116// The integer pointer may be aliasing the derived target component.
117// CHECK-LABEL: func @derived_whose_component_may_be_aliased
118// CHECK: %[[ALLOC:.*]] = fir.allocmem !fir.array<4x!fir.type<some_type{i:i32}>>
119// CHECK-COUNT-3: fir.do_loop
120// CHECK: fir.freemem %[[ALLOC]] : !fir.heap<!fir.array<4x!fir.type<some_type{i:i32}>>>
121func.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>>>>) {
122  %c4 = arith.constant 4 : index
123  %0 = fir.field_index i, !fir.type<some_type{i:i32}>
124  %c1 = arith.constant 1 : index
125  %1 = fir.slice %c1, %c4, %c1 path %0 : (index, index, index, !fir.field) -> !fir.slice<1>
126  %2 = fir.array_load %arg0 [%1] : (!fir.box<!fir.array<4x!fir.type<some_type{i:i32}>>>, !fir.slice<1>) -> !fir.array<4xi32>
127  %3 = fir.load %arg1 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
128  %c0 = arith.constant 0 : index
129  %4:3 = fir.box_dims %3, %c0 : (!fir.box<!fir.ptr<!fir.array<?xi32>>>, index) -> (index, index, index)
130  %5 = fir.shift %4#0 : (index) -> !fir.shift<1>
131  %6 = fir.array_load %3(%5) : (!fir.box<!fir.ptr<!fir.array<?xi32>>>, !fir.shift<1>) -> !fir.array<?xi32>
132  %7 = arith.subi %c4, %c1 : index
133  %8 = fir.do_loop %arg2 = %c0 to %7 step %c1 unordered iter_args(%arg3 = %2) -> (!fir.array<4xi32>) {
134    %9 = fir.array_fetch %6, %arg2 : (!fir.array<?xi32>, index) -> i32
135    %10 = fir.array_update %arg3, %9, %arg2 : (!fir.array<4xi32>, i32, index) -> !fir.array<4xi32>
136    fir.result %10 : !fir.array<4xi32>
137  }
138  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>
139  return
140}
141
142// -----
143
144// Test real_target = complex_target(:)%re
145// The real pointer may be aliasing the complex real part.
146// CHECK-LABEL: func @complex_real_aliasing
147// CHECK: %[[ALLOC:.*]] = fir.allocmem !fir.array<?xf32>
148// CHECK-COUNT-3: fir.do_loop
149// CHECK: fir.freemem %[[ALLOC]] : !fir.heap<!fir.array<?xf32>>
150func.func @complex_real_aliasing(%arg0: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>, %arg1: !fir.ref<!fir.array<4x!fir.complex<4>>> {fir.target}) {
151  %c4 = arith.constant 4 : index
152  %0 = fir.load %arg0 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>
153  %c0 = arith.constant 0 : index
154  %1:3 = fir.box_dims %0, %c0 : (!fir.box<!fir.ptr<!fir.array<?xf32>>>, index) -> (index, index, index)
155  %2 = fir.shift %1#0 : (index) -> !fir.shift<1>
156  %3 = fir.array_load %0(%2) : (!fir.box<!fir.ptr<!fir.array<?xf32>>>, !fir.shift<1>) -> !fir.array<?xf32>
157  %c0_i32 = arith.constant 0 : i32
158  %4 = fir.shape %c4 : (index) -> !fir.shape<1>
159  %c1 = arith.constant 1 : index
160  %5 = fir.slice %c1, %c4, %c1 path %c0_i32 : (index, index, index, i32) -> !fir.slice<1>
161  %6 = fir.array_load %arg1(%4) [%5] : (!fir.ref<!fir.array<4x!fir.complex<4>>>, !fir.shape<1>, !fir.slice<1>) -> !fir.array<4xf32>
162  %7 = arith.subi %c4, %c1 : index
163  %8 = fir.do_loop %arg2 = %c0 to %7 step %c1 unordered iter_args(%arg3 = %3) -> (!fir.array<?xf32>) {
164    %9 = fir.array_fetch %6, %arg2 : (!fir.array<4xf32>, index) -> f32
165    %10 = fir.array_update %arg3, %9, %arg2 : (!fir.array<?xf32>, f32, index) -> !fir.array<?xf32>
166    fir.result %10 : !fir.array<?xf32>
167  }
168  fir.array_merge_store %3, %8 to %0 : !fir.array<?xf32>, !fir.array<?xf32>, !fir.box<!fir.ptr<!fir.array<?xf32>>>
169  return
170}
171