307 lines · plain
1// RUN: mlir-opt %s -test-memref-bound-check -split-input-file -verify-diagnostics | FileCheck %s2 3// -----4 5// CHECK-LABEL: func @test() {6func.func @test() {7 %zero = arith.constant 0 : index8 %minusone = arith.constant -1 : index9 %sym = arith.constant 111 : index10 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 return39}40 41// CHECK-LABEL: func @test_mod_floordiv_ceildiv42func.func @test_mod_floordiv_ceildiv() {43 %zero = arith.constant 0 : index44 %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 return62}63 64// CHECK-LABEL: func @test_no_out_of_bounds()65func.func @test_no_out_of_bounds() {66 %zero = arith.constant 0 : index67 %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 region80 // accessed along first memref dimension would have come out as d0 <= 31881 // (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 return88}89 90// CHECK-LABEL: func @mod_div91func.func @mod_div() {92 %zero = arith.constant 0 : index93 %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 return111}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 return125}126 127// CHECK-LABEL: func @test_semi_affine_bailout128func.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 return136}137 138// CHECK-LABEL: func @multi_mod_floordiv139func.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 return147}148 149// CHECK-LABEL: func @delinearize_mod_floordiv150func.func @delinearize_mod_floordiv() {151 %c0 = arith.constant 0 : index152 %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 return177}178 179// CHECK-LABEL: func @zero_d_memref180func.func @zero_d_memref(%arg0: memref<i32>) {181 %c0 = arith.constant 0 : i32182 // A 0-d memref always has in-bound accesses!183 affine.store %c0, %arg0[] : memref<i32>184 return185}186 187// CHECK-LABEL: func @out_of_bounds188func.func @out_of_bounds() {189 %in = memref.alloc() : memref<1xi32>190 %c9 = arith.constant 9 : i32191 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 return197}198 199// -----200 201// This test case accesses within bounds. Without removal of a certain type of202// trivially redundant constraints (those differing only in their constant203// term), the number of constraints here explodes, and this would return out of204// 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_floordiv209func.func @test_complex_mod_floordiv(%arg0: memref<4x4x16x1xf32>) {210 %c0 = arith.constant 0 : index211 %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 return221}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_bound230func.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 return241}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_bound250func.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 : index255 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 return267}268 269// -----270 271// This should not give an out of bounds error. The result of the affine.apply272// 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_operand278func.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 return286}287 288// CHECK-LABEL: func @zero_d_memref289func.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 return295}296 297// CHECK-LABEL: func @affine_parallel298func.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 return306}307