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