1// RUN: mlir-opt %s -test-memref-bound-check -split-input-file -verify-diagnostics | FileCheck %s 2 3// ----- 4 5// CHECK-LABEL: func @test() { 6func.func @test() { 7 %zero = arith.constant 0 : index 8 %minusone = arith.constant -1 : index 9 %sym = arith.constant 111 : index 10 11 %A = memref.alloc() : memref<9 x 9 x i32> 12 %B = memref.alloc() : memref<111 x i32> 13 14 affine.for %i = -1 to 10 { 15 affine.for %j = -1 to 10 { 16 %idx0 = affine.apply affine_map<(d0, d1) -> (d0)>(%i, %j) 17 %idx1 = affine.apply affine_map<(d0, d1) -> (d1)>(%i, %j) 18 // Out of bound access. 19 %x = affine.load %A[%idx0, %idx1] : memref<9 x 9 x i32> 20 // expected-error@-1 {{'affine.load' op memref out of upper bound access along dimension #1}} 21 // expected-error@-2 {{'affine.load' op memref out of lower bound access along dimension #1}} 22 // expected-error@-3 {{'affine.load' op memref out of upper bound access along dimension #2}} 23 // expected-error@-4 {{'affine.load' op memref out of lower bound access along dimension #2}} 24 // This will access 0 to 110 - hence an overflow. 25 %idy = affine.apply affine_map<(d0, d1) -> (10*d0 - d1 + 19)>(%i, %j) 26 %y = affine.load %B[%idy] : memref<111 x i32> 27 } 28 } 29 30 affine.for %k = 0 to 10 { 31 // In bound. 32 %u = affine.load %B[%zero] : memref<111 x i32> 33 // Out of bounds. 34 %v = affine.load %B[%sym] : memref<111 x i32> // expected-error {{'affine.load' op memref out of upper bound access along dimension #1}} 35 // Out of bounds. 36 affine.store %v, %B[%minusone] : memref<111 x i32> // expected-error {{'affine.store' op memref out of lower bound access along dimension #1}} 37 } 38 return 39} 40 41// CHECK-LABEL: func @test_mod_floordiv_ceildiv 42func.func @test_mod_floordiv_ceildiv() { 43 %zero = arith.constant 0 : index 44 %A = memref.alloc() : memref<128 x 64 x 64 x i32> 45 46 affine.for %i = 0 to 256 { 47 affine.for %j = 0 to 256 { 48 %idx0 = affine.apply affine_map<(d0, d1, d2) -> (d0 mod 128 + 1)>(%i, %j, %j) 49 %idx1 = affine.apply affine_map<(d0, d1, d2) -> (d1 floordiv 4 + 1)>(%i, %j, %j) 50 %idx2 = affine.apply affine_map<(d0, d1, d2) -> (d2 ceildiv 4)>(%i, %j, %j) 51 %x = affine.load %A[%idx0, %idx1, %idx2] : memref<128 x 64 x 64 x i32> 52 // expected-error@-1 {{'affine.load' op memref out of upper bound access along dimension #1}} 53 // expected-error@-2 {{'affine.load' op memref out of upper bound access along dimension #2}} 54 // expected-error@-3 {{'affine.load' op memref out of upper bound access along dimension #3}} 55 %idy0 = affine.apply affine_map<(d0, d1, d2) -> (d0 mod 128)>(%i, %j, %j) 56 %idy1 = affine.apply affine_map<(d0, d1, d2) -> (d1 floordiv 4)>(%i, %j, %j) 57 %idy2 = affine.apply affine_map<(d0, d1, d2) -> (d2 ceildiv 4 - 1)>(%i, %j, %j) 58 affine.store %x, %A[%idy0, %idy1, %idy2] : memref<128 x 64 x 64 x i32> // expected-error {{'affine.store' op memref out of lower bound access along dimension #3}} 59 } // CHECK: } 60 } // CHECK: } 61 return 62} 63 64// CHECK-LABEL: func @test_no_out_of_bounds() 65func.func @test_no_out_of_bounds() { 66 %zero = arith.constant 0 : index 67 %A = memref.alloc() : memref<257 x 256 x i32> 68 %C = memref.alloc() : memref<257 x i32> 69 %B = memref.alloc() : memref<1 x i32> 70 71 affine.for %i = 0 to 256 { 72 affine.for %j = 0 to 256 { 73 // All of these accesses are in bound; check that no errors are emitted. 74 // CHECK: %{{.*}} = affine.apply {{#map.*}}(%{{.*}}, %{{.*}}) 75 // CHECK-NEXT: %{{.*}} = affine.load %{{.*}}[%{{.*}}, %{{.*}}] : memref<257x256xi32> 76 // CHECK-NEXT: %{{.*}} = affine.apply {{#map.*}}(%{{.*}}, %{{.*}}) 77 // CHECK-NEXT: %{{.*}} = affine.load %{{.*}}[%{{.*}}] : memref<1xi32> 78 %idx0 = affine.apply affine_map<(d0, d1) -> ( 64 * (d0 ceildiv 64))>(%i, %j) 79 // Without GCDTightenInequalities(), the upper bound on the region 80 // accessed along first memref dimension would have come out as d0 <= 318 81 // (instead of d0 <= 256), and led to a false positive out of bounds. 82 %x = affine.load %A[%idx0, %zero] : memref<257 x 256 x i32> 83 %idy = affine.apply affine_map<(d0, d1) -> (d0 floordiv 256)>(%i, %i) 84 %y = affine.load %B[%idy] : memref<1 x i32> 85 } // CHECK-NEXT: } 86 } 87 return 88} 89 90// CHECK-LABEL: func @mod_div 91func.func @mod_div() { 92 %zero = arith.constant 0 : index 93 %A = memref.alloc() : memref<128 x 64 x 64 x i32> 94 95 affine.for %i = 0 to 256 { 96 affine.for %j = 0 to 256 { 97 %idx0 = affine.apply affine_map<(d0, d1, d2) -> (d0 mod 128 + 1)>(%i, %j, %j) 98 %idx1 = affine.apply affine_map<(d0, d1, d2) -> (d1 floordiv 4 + 1)>(%i, %j, %j) 99 %idx2 = affine.apply affine_map<(d0, d1, d2) -> (d2 ceildiv 4)>(%i, %j, %j) 100 %x = affine.load %A[%idx0, %idx1, %idx2] : memref<128 x 64 x 64 x i32> 101 // expected-error@-1 {{'affine.load' op memref out of upper bound access along dimension #1}} 102 // expected-error@-2 {{'affine.load' op memref out of upper bound access along dimension #2}} 103 // expected-error@-3 {{'affine.load' op memref out of upper bound access along dimension #3}} 104 %idy0 = affine.apply affine_map<(d0, d1, d2) -> (d0 mod 128)>(%i, %j, %j) 105 %idy1 = affine.apply affine_map<(d0, d1, d2) -> (d1 floordiv 4)>(%i, %j, %j) 106 %idy2 = affine.apply affine_map<(d0, d1, d2) -> (d2 ceildiv 4 - 1)>(%i, %j, %j) 107 affine.store %x, %A[%idy0, %idy1, %idy2] : memref<128 x 64 x 64 x i32> // expected-error {{'affine.store' op memref out of lower bound access along dimension #3}} 108 } 109 } 110 return 111} 112 113// Tests with nested mod's and floordiv's. 114// CHECK-LABEL: func @mod_floordiv_nested() { 115func.func @mod_floordiv_nested() { 116 %A = memref.alloc() : memref<256 x 256 x i32> 117 affine.for %i = 0 to 256 { 118 affine.for %j = 0 to 256 { 119 %idx0 = affine.apply affine_map<(d0, d1) -> ((d0 mod 1024) floordiv 4)>(%i, %j) 120 %idx1 = affine.apply affine_map<(d0, d1) -> ((((d1 mod 128) mod 32) ceildiv 4) * 32)>(%i, %j) 121 affine.load %A[%idx0, %idx1] : memref<256 x 256 x i32> // expected-error {{'affine.load' op memref out of upper bound access along dimension #2}} 122 } 123 } 124 return 125} 126 127// CHECK-LABEL: func @test_semi_affine_bailout 128func.func @test_semi_affine_bailout(%N : index) { 129 %B = memref.alloc() : memref<10 x i32> 130 affine.for %i = 0 to 10 { 131 %idx = affine.apply affine_map<(d0)[s0] -> (d0 * s0)>(%i)[%N] 132 %y = affine.load %B[%idx] : memref<10 x i32> 133 // expected-error@-1 {{getMemRefRegion: compose affine map failed}} 134 } 135 return 136} 137 138// CHECK-LABEL: func @multi_mod_floordiv 139func.func @multi_mod_floordiv() { 140 %A = memref.alloc() : memref<2x2xi32> 141 affine.for %ii = 0 to 64 { 142 %idx0 = affine.apply affine_map<(d0) -> ((d0 mod 147456) floordiv 1152)> (%ii) 143 %idx1 = affine.apply affine_map<(d0) -> (((d0 mod 147456) mod 1152) floordiv 384)> (%ii) 144 %v = affine.load %A[%idx0, %idx1] : memref<2x2xi32> 145 } 146 return 147} 148 149// CHECK-LABEL: func @delinearize_mod_floordiv 150func.func @delinearize_mod_floordiv() { 151 %c0 = arith.constant 0 : index 152 %in = memref.alloc() : memref<2x2x3x3x16x1xi32> 153 %out = memref.alloc() : memref<64x9xi32> 154 155 // Reshape '%in' into '%out'. 156 affine.for %ii = 0 to 64 { 157 affine.for %jj = 0 to 9 { 158 %a0 = affine.apply affine_map<(d0, d1) -> (d0 * (9 * 1024) + d1 * 128)> (%ii, %jj) 159 %a10 = affine.apply affine_map<(d0) -> 160 (d0 floordiv (2 * 3 * 3 * 128 * 128))> (%a0) 161 %a11 = affine.apply affine_map<(d0) -> 162 ((d0 mod 294912) floordiv (3 * 3 * 128 * 128))> (%a0) 163 %a12 = affine.apply affine_map<(d0) -> 164 ((((d0 mod 294912) mod 147456) floordiv 1152) floordiv 8)> (%a0) 165 %a13 = affine.apply affine_map<(d0) -> 166 ((((d0 mod 294912) mod 147456) mod 1152) floordiv 384)> (%a0) 167 %a14 = affine.apply affine_map<(d0) -> 168 (((((d0 mod 294912) mod 147456) mod 1152) mod 384) floordiv 128)> (%a0) 169 %a15 = affine.apply affine_map<(d0) -> 170 ((((((d0 mod 294912) mod 147456) mod 1152) mod 384) mod 128) 171 floordiv 128)> (%a0) 172 %v0 = affine.load %in[%a10, %a11, %a13, %a14, %a12, %a15] 173 : memref<2x2x3x3x16x1xi32> 174 } 175 } 176 return 177} 178 179// CHECK-LABEL: func @zero_d_memref 180func.func @zero_d_memref(%arg0: memref<i32>) { 181 %c0 = arith.constant 0 : i32 182 // A 0-d memref always has in-bound accesses! 183 affine.store %c0, %arg0[] : memref<i32> 184 return 185} 186 187// CHECK-LABEL: func @out_of_bounds 188func.func @out_of_bounds() { 189 %in = memref.alloc() : memref<1xi32> 190 %c9 = arith.constant 9 : i32 191 192 affine.for %i0 = 10 to 11 { 193 %idy = affine.apply affine_map<(d0) -> (100 * d0 floordiv 1000)> (%i0) 194 affine.store %c9, %in[%idy] : memref<1xi32> // expected-error {{'affine.store' op memref out of upper bound access along dimension #1}} 195 } 196 return 197} 198 199// ----- 200 201// This test case accesses within bounds. Without removal of a certain type of 202// trivially redundant constraints (those differing only in their constant 203// term), the number of constraints here explodes, and this would return out of 204// bounds errors conservatively due to IntegerRelation::kExplosionFactor. 205#map3 = affine_map<(d0, d1) -> ((d0 * 72 + d1) floordiv 2304 + ((((d0 * 72 + d1) mod 2304) mod 1152) mod 9) floordiv 3)> 206#map4 = affine_map<(d0, d1) -> ((d0 * 72 + d1) mod 2304 - (((d0 * 72 + d1) mod 2304) floordiv 1152) * 1151 - ((((d0 * 72 + d1) mod 2304) mod 1152) floordiv 9) * 9 - (((((d0 * 72 + d1) mod 2304) mod 1152) mod 9) floordiv 3) * 3)> 207#map5 = affine_map<(d0, d1) -> (((((d0 * 72 + d1) mod 2304) mod 1152) floordiv 9) floordiv 8)> 208// CHECK-LABEL: func @test_complex_mod_floordiv 209func.func @test_complex_mod_floordiv(%arg0: memref<4x4x16x1xf32>) { 210 %c0 = arith.constant 0 : index 211 %0 = memref.alloc() : memref<1x2x3x3x16x1xf32> 212 affine.for %i0 = 0 to 64 { 213 affine.for %i1 = 0 to 9 { 214 %2 = affine.apply #map3(%i0, %i1) 215 %3 = affine.apply #map4(%i0, %i1) 216 %4 = affine.apply #map5(%i0, %i1) 217 %5 = affine.load %arg0[%2, %c0, %4, %c0] : memref<4x4x16x1xf32> 218 } 219 } 220 return 221} 222 223// ----- 224 225// The first load is within bounds, but not the second one. 226#map0 = affine_map<(d0) -> (d0 mod 4)> 227#map1 = affine_map<(d0) -> (d0 mod 4 + 4)> 228 229// CHECK-LABEL: func @test_mod_bound 230func.func @test_mod_bound() { 231 %0 = memref.alloc() : memref<7 x f32> 232 %1 = memref.alloc() : memref<6 x f32> 233 affine.for %i0 = 0 to 4096 { 234 affine.for %i1 = #map0(%i0) to #map1(%i0) { 235 affine.load %0[%i1] : memref<7 x f32> 236 affine.load %1[%i1] : memref<6 x f32> 237 // expected-error@-1 {{'affine.load' op memref out of upper bound access along dimension #1}} 238 } 239 } 240 return 241} 242 243// ----- 244 245#map0 = affine_map<(d0) -> (d0 floordiv 4)> 246#map1 = affine_map<(d0) -> (d0 floordiv 4 + 4)> 247#map2 = affine_map<(d0) -> (4 * (d0 floordiv 4) + d0 mod 4)> 248 249// CHECK-LABEL: func @test_floordiv_bound 250func.func @test_floordiv_bound() { 251 %0 = memref.alloc() : memref<1027 x f32> 252 %1 = memref.alloc() : memref<1026 x f32> 253 %2 = memref.alloc() : memref<4096 x f32> 254 %N = arith.constant 2048 : index 255 affine.for %i0 = 0 to 4096 { 256 affine.for %i1 = #map0(%i0) to #map1(%i0) { 257 affine.load %0[%i1] : memref<1027 x f32> 258 affine.load %1[%i1] : memref<1026 x f32> 259 // expected-error@-1 {{'affine.load' op memref out of upper bound access along dimension #1}} 260 } 261 affine.for %i2 = 0 to #map2(%N) { 262 // Within bounds. 263 %v = affine.load %2[%i2] : memref<4096 x f32> 264 } 265 } 266 return 267} 268 269// ----- 270 271// This should not give an out of bounds error. The result of the affine.apply 272// is composed into the bound map during analysis. 273 274#map_lb = affine_map<(d0) -> (d0)> 275#map_ub = affine_map<(d0) -> (d0 + 4)> 276 277// CHECK-LABEL: func @non_composed_bound_operand 278func.func @non_composed_bound_operand(%arg0: memref<1024xf32>) { 279 affine.for %i0 = 4 to 1028 step 4 { 280 %i1 = affine.apply affine_map<(d0) -> (d0 - 4)> (%i0) 281 affine.for %i2 = #map_lb(%i1) to #map_ub(%i1) { 282 %0 = affine.load %arg0[%i2] : memref<1024xf32> 283 } 284 } 285 return 286} 287 288// CHECK-LABEL: func @zero_d_memref 289func.func @zero_d_memref() { 290 %Z = memref.alloc() : memref<f32> 291 affine.for %i = 0 to 100 { 292 affine.load %Z[] : memref<f32> 293 } 294 return 295} 296 297// CHECK-LABEL: func @affine_parallel 298func.func @affine_parallel(%M: memref<2048x2048xf64>) { 299 affine.parallel (%i) = (0) to (3000) { 300 affine.for %j = 0 to 2048 { 301 affine.load %M[%i, %j] : memref<2048x2048xf64> 302 // expected-error@above {{'affine.load' op memref out of upper bound access along dimension #1}} 303 } 304 } 305 return 306} 307