2404 lines · plain
1// RUN: mlir-opt -allow-unregistered-dialect %s -split-input-file -canonicalize="test-convergence" | FileCheck %s2// RUN: mlir-opt -allow-unregistered-dialect %s -split-input-file -canonicalize="test-convergence top-down=0" | FileCheck %s --check-prefix=CHECK-BOTTOM-UP3 4// -----5 6// CHECK-DAG: #[[$MAP0:.*]] = affine_map<(d0) -> (d0 - 1)>7// CHECK-DAG: #[[$MAP1:.*]] = affine_map<(d0) -> (d0 + 1)>8 9// CHECK-LABEL: func @compose_affine_maps_1dto2d_no_symbols() {10func.func @compose_affine_maps_1dto2d_no_symbols() {11 %0 = memref.alloc() : memref<4x4xf32>12 13 affine.for %i0 = 0 to 15 {14 // Test load[%x, %x]15 16 %x0 = affine.apply affine_map<(d0) -> (d0 - 1)> (%i0)17 %x1_0 = affine.apply affine_map<(d0, d1) -> (d0)> (%x0, %x0)18 %x1_1 = affine.apply affine_map<(d0, d1) -> (d1)> (%x0, %x0)19 20 // CHECK: %[[I0A:.*]] = affine.apply #[[$MAP0]](%{{.*}})21 // CHECK-NEXT: %[[V0:.*]] = memref.load %{{.*}}[%[[I0A]], %[[I0A]]]22 %v0 = memref.load %0[%x1_0, %x1_1] : memref<4x4xf32>23 24 // Test store[%y, %y]25 %y0 = affine.apply affine_map<(d0) -> (d0 + 1)> (%i0)26 %y1_0 = affine.apply affine_map<(d0, d1) -> (d0)> (%y0, %y0)27 %y1_1 = affine.apply affine_map<(d0, d1) -> (d1)> (%y0, %y0)28 29 // CHECK-NEXT: %[[I1A:.*]] = affine.apply #[[$MAP1]](%{{.*}})30 // CHECK-NEXT: memref.store %[[V0]], %{{.*}}[%[[I1A]], %[[I1A]]]31 memref.store %v0, %0[%y1_0, %y1_1] : memref<4x4xf32>32 33 // Test store[%x, %y]34 %xy_0 = affine.apply affine_map<(d0, d1) -> (d0)> (%x0, %y0)35 %xy_1 = affine.apply affine_map<(d0, d1) -> (d1)> (%x0, %y0)36 37 // CHECK-NEXT: memref.store %[[V0]], %{{.*}}[%[[I0A]], %[[I1A]]]38 memref.store %v0, %0[%xy_0, %xy_1] : memref<4x4xf32>39 40 // Test store[%y, %x]41 %yx_0 = affine.apply affine_map<(d0, d1) -> (d0)> (%y0, %x0)42 %yx_1 = affine.apply affine_map<(d0, d1) -> (d1)> (%y0, %x0)43 // CHECK-NEXT: memref.store %[[V0]], %{{.*}}[%[[I1A]], %[[I0A]]]44 memref.store %v0, %0[%yx_0, %yx_1] : memref<4x4xf32>45 }46 return47}48 49// -----50 51// CHECK-DAG: #[[$MAP4:.*]] = affine_map<(d0) -> (d0 - 4)>52// CHECK-DAG: #[[$MAP7:.*]] = affine_map<(d0) -> (d0 * 2 - 3)>53// CHECK-DAG: #[[$MAP7a:.*]] = affine_map<(d0) -> (d0 * 2 + 1)>54 55// CHECK-LABEL: func @compose_affine_maps_1dto2d_with_symbols() {56func.func @compose_affine_maps_1dto2d_with_symbols() {57 %0 = memref.alloc() : memref<4x4xf32>58 59 affine.for %i0 = 0 to 15 {60 // Test load[%x0, %x0] with symbol %c461 %c4 = arith.constant 4 : index62 %x0 = affine.apply affine_map<(d0)[s0] -> (d0 - s0)> (%i0)[%c4]63 64 // CHECK: %[[I0:.*]] = affine.apply #[[$MAP4]](%{{.*}})65 // CHECK-NEXT: %[[V0:.*]] = memref.load %{{.*}}[%[[I0]], %[[I0]]]66 %v0 = memref.load %0[%x0, %x0] : memref<4x4xf32>67 68 // Test load[%x0, %x1] with symbol %c4 captured by '%x0' map.69 %x1 = affine.apply affine_map<(d0) -> (d0 + 1)> (%i0)70 %y1 = affine.apply affine_map<(d0, d1) -> (d0+d1)> (%x0, %x1)71 // CHECK-NEXT: %[[I1:.*]] = affine.apply #[[$MAP7]](%{{.*}})72 // CHECK-NEXT: memref.store %[[V0]], %{{.*}}[%[[I1]], %[[I1]]]73 memref.store %v0, %0[%y1, %y1] : memref<4x4xf32>74 75 // Test store[%x1, %x0] with symbol %c4 captured by '%x0' map.76 %y2 = affine.apply affine_map<(d0, d1) -> (d0 + d1)> (%x1, %x0)77 // CHECK-NEXT: %[[I2:.*]] = affine.apply #[[$MAP7]](%{{.*}})78 // CHECK-NEXT: memref.store %[[V0]], %{{.*}}[%[[I2]], %[[I2]]]79 memref.store %v0, %0[%y2, %y2] : memref<4x4xf32>80 81 // Test store[%x2, %x0] with symbol %c4 from '%x0' and %c5 from '%x2'82 %c5 = arith.constant 5 : index83 %x2 = affine.apply affine_map<(d0)[s0] -> (d0 + s0)> (%i0)[%c5]84 %y3 = affine.apply affine_map<(d0, d1) -> (d0 + d1)> (%x2, %x0)85 // CHECK: %[[I3:.*]] = affine.apply #[[$MAP7a]](%{{.*}})86 // CHECK-NEXT: memref.store %[[V0]], %{{.*}}[%[[I3]], %[[I3]]]87 memref.store %v0, %0[%y3, %y3] : memref<4x4xf32>88 }89 return90}91 92// -----93 94// CHECK-DAG: #[[$MAP8:.*]] = affine_map<(d0, d1) -> (d1 + (d0 ceildiv 4) * 4 - (d1 floordiv 4) * 4)>95// CHECK-DAG: #[[$MAP8a:.*]] = affine_map<(d0, d1) -> (d1 + (d0 ceildiv 8) * 8 - (d1 floordiv 8) * 8)>96 97// CHECK-LABEL: func @compose_affine_maps_2d_tile98func.func @compose_affine_maps_2d_tile(%0: memref<16x32xf32>, %1: memref<16x32xf32>) {99 %c4 = arith.constant 4 : index100 %c8 = arith.constant 8 : index101 102 affine.for %i0 = 0 to 16 {103 %x0 = affine.apply affine_map<(d0)[s0] -> (d0 ceildiv s0)> (%i0)[%c4]104 affine.for %i1 = 0 to 16 {105 %x1 = affine.apply affine_map<(d0)[s0] -> (d0 ceildiv s0)> (%i1)[%c8]106 affine.for %i2 = 0 to 16 {107 %x2 = affine.apply affine_map<(d0)[s0] -> (d0 mod s0)> (%i2)[%c4]108 affine.for %i3 = 0 to 16 {109 %x3 = affine.apply affine_map<(d0)[s0] -> (d0 mod s0)> (%i3)[%c8]110 111 %x40 = affine.apply affine_map<(d0, d1, d2, d3)[s0, s1] ->112 ((d0 * s0) + d2)> (%x0, %x1, %x2, %x3)[%c4, %c8]113 %x41 = affine.apply affine_map<(d0, d1, d2, d3)[s0, s1] ->114 ((d1 * s1) + d3)> (%x0, %x1, %x2, %x3)[%c4, %c8]115 // CHECK: %[[I0:.*]] = affine.apply #[[$MAP8]](%{{.*}}, %{{.*}})116 // CHECK: %[[I1:.*]] = affine.apply #[[$MAP8a]](%{{.*}}, %{{.*}})117 // CHECK-NEXT: %[[L0:.*]] = memref.load %{{.*}}[%[[I0]], %[[I1]]]118 %v0 = memref.load %0[%x40, %x41] : memref<16x32xf32>119 120 // CHECK-NEXT: memref.store %[[L0]], %{{.*}}[%[[I0]], %[[I1]]]121 memref.store %v0, %1[%x40, %x41] : memref<16x32xf32>122 }123 }124 }125 }126 return127}128 129// -----130 131// CHECK-DAG: #[[$MAP4b:.*]] = affine_map<(d0) -> (d0 - 7)>132// CHECK-DAG: #[[$MAP9:.*]] = affine_map<(d0) -> (d0 + 3)>133// CHECK-DAG: #[[$MAP10:.*]] = affine_map<(d0) -> (d0 * 3)>134// CHECK-DAG: #[[$MAP11:.*]] = affine_map<(d0) -> ((d0 + 3) ceildiv 3)>135// CHECK-DAG: #[[$MAP12:.*]] = affine_map<(d0) -> (d0 * 7 - 49)>136 137// CHECK-LABEL: func @compose_affine_maps_dependent_loads() {138func.func @compose_affine_maps_dependent_loads() {139 %0 = memref.alloc() : memref<16x32xf32>140 %1 = memref.alloc() : memref<16x32xf32>141 142 affine.for %i0 = 0 to 3 {143 affine.for %i1 = 0 to 3 {144 affine.for %i2 = 0 to 3 {145 %c3 = arith.constant 3 : index146 %c7 = arith.constant 7 : index147 148 %x00 = affine.apply affine_map<(d0, d1, d2)[s0, s1] -> (d0 + s0)>149 (%i0, %i1, %i2)[%c3, %c7]150 %x01 = affine.apply affine_map<(d0, d1, d2)[s0, s1] -> (d1 - s1)>151 (%i0, %i1, %i2)[%c3, %c7]152 %x02 = affine.apply affine_map<(d0, d1, d2)[s0, s1] -> (d2 * s0)>153 (%i0, %i1, %i2)[%c3, %c7]154 155 // CHECK: %[[I0:.*]] = affine.apply #[[$MAP9]](%{{.*}})156 // CHECK: %[[I1:.*]] = affine.apply #[[$MAP4b]](%{{.*}})157 // CHECK: %[[I2:.*]] = affine.apply #[[$MAP10]](%{{.*}})158 // CHECK-NEXT: %[[V0:.*]] = memref.load %{{.*}}[%[[I0]], %[[I1]]]159 %v0 = memref.load %0[%x00, %x01] : memref<16x32xf32>160 161 // CHECK-NEXT: memref.store %[[V0]], %{{.*}}[%[[I0]], %[[I2]]]162 memref.store %v0, %0[%x00, %x02] : memref<16x32xf32>163 164 // Swizzle %i0, %i1165 // CHECK-NEXT: memref.store %[[V0]], %{{.*}}[%[[I1]], %[[I0]]]166 memref.store %v0, %0[%x01, %x00] : memref<16x32xf32>167 168 // Swizzle %x00, %x01 and %c3, %c7169 %x10 = affine.apply affine_map<(d0, d1)[s0, s1] -> (d0 * s1)>170 (%x01, %x00)[%c3, %c7]171 %x11 = affine.apply affine_map<(d0, d1)[s0, s1] -> (d1 ceildiv s0)>172 (%x01, %x00)[%c3, %c7]173 174 // CHECK-NEXT: %[[I2A:.*]] = affine.apply #[[$MAP12]](%{{.*}})175 // CHECK-NEXT: %[[I2B:.*]] = affine.apply #[[$MAP11]](%{{.*}})176 // CHECK-NEXT: memref.store %[[V0]], %{{.*}}[%[[I2A]], %[[I2B]]]177 memref.store %v0, %0[%x10, %x11] : memref<16x32xf32>178 }179 }180 }181 return182}183 184// -----185 186// CHECK-DAG: #[[$MAP13A:.*]] = affine_map<(d0) -> ((d0 + 6) ceildiv 8)>187// CHECK-DAG: #[[$MAP13B:.*]] = affine_map<(d0) -> ((d0 * 4 - 4) floordiv 3)>188 189// CHECK-LABEL: func @compose_affine_maps_diamond_dependency190func.func @compose_affine_maps_diamond_dependency(%arg0: f32, %arg1: memref<4x4xf32>) {191 affine.for %i0 = 0 to 15 {192 %a = affine.apply affine_map<(d0) -> (d0 - 1)> (%i0)193 %b = affine.apply affine_map<(d0) -> (d0 + 7)> (%a)194 %c = affine.apply affine_map<(d0) -> (d0 * 4)> (%a)195 %d0 = affine.apply affine_map<(d0, d1) -> (d0 ceildiv 8)> (%b, %c)196 %d1 = affine.apply affine_map<(d0, d1) -> (d1 floordiv 3)> (%b, %c)197 // CHECK: %[[I0:.*]] = affine.apply #[[$MAP13A]](%{{.*}})198 // CHECK: %[[I1:.*]] = affine.apply #[[$MAP13B]](%{{.*}})199 // CHECK-NEXT: memref.store %arg0, %arg1[%[[I0]], %[[I1]]]200 memref.store %arg0, %arg1[%d0, %d1] : memref<4x4xf32>201 }202 203 return204}205 206// -----207 208// CHECK-DAG: #[[$MAP14:.*]] = affine_map<()[s0, s1] -> ((s0 * 4 + s1 * 4) floordiv s0)>209 210// CHECK-LABEL: func @compose_affine_maps_multiple_symbols211func.func @compose_affine_maps_multiple_symbols(%arg0: index, %arg1: index) -> index {212 %a = affine.apply affine_map<(d0)[s0] -> (s0 + d0)> (%arg0)[%arg1]213 %c = affine.apply affine_map<(d0) -> (d0 * 4)> (%a)214 %e = affine.apply affine_map<(d0)[s0] -> (d0 floordiv s0)> (%c)[%arg1]215 // CHECK: [[I0:.*]] = affine.apply #[[$MAP14]]()[%{{.*}}, %{{.*}}]216 return %e : index217}218 219// -----220 221// CHECK-LABEL: func @arg_used_as_dim_and_symbol222func.func @arg_used_as_dim_and_symbol(%arg0: memref<100x100xf32>, %arg1: index, %arg2: f32) -> (memref<100x100xf32, 1>, memref<1xi32>) {223 %c9 = arith.constant 9 : index224 %1 = memref.alloc() : memref<100x100xf32, 1>225 %2 = memref.alloc() : memref<1xi32>226 affine.for %i0 = 0 to 100 {227 affine.for %i1 = 0 to 100 {228 %3 = affine.apply affine_map<(d0, d1)[s0, s1] -> (d1 + s0 + s1)>229 (%i0, %i1)[%arg1, %c9]230 %4 = affine.apply affine_map<(d0, d1, d3) -> (d3 - (d0 + d1))>231 (%arg1, %c9, %3)232 // CHECK: memref.store %arg2, %{{.*}}[%{{.*}}, %{{.*}}]233 memref.store %arg2, %1[%4, %arg1] : memref<100x100xf32, 1>234 }235 }236 return %1, %2 : memref<100x100xf32, 1>, memref<1xi32>237}238 239// -----240 241// CHECK-LABEL: func @trivial_maps242func.func @trivial_maps() {243 // CHECK-NOT: affine.apply244 245 %0 = memref.alloc() : memref<10xf32>246 %c0 = arith.constant 0 : index247 %cst = arith.constant 0.000000e+00 : f32248 affine.for %i1 = 0 to 10 {249 %1 = affine.apply affine_map<()[s0] -> (s0)>()[%c0]250 memref.store %cst, %0[%1] : memref<10xf32>251 %2 = memref.load %0[%c0] : memref<10xf32>252 253 %3 = affine.apply affine_map<()[] -> (0)>()[]254 memref.store %cst, %0[%3] : memref<10xf32>255 memref.store %2, %0[%c0] : memref<10xf32>256 }257 return258}259 260// -----261 262// CHECK-DAG: #[[$MAP15:.*]] = affine_map<()[s0] -> (s0 - 42)>263 264// CHECK-LABEL: func @partial_fold_map265func.func @partial_fold_map(%arg1: index, %arg2: index) -> index {266 // TODO: Constant fold one index into affine.apply267 %c42 = arith.constant 42 : index268 %2 = affine.apply affine_map<(d0, d1) -> (d0 - d1)> (%arg1, %c42)269 // CHECK: [[X:.*]] = affine.apply #[[$MAP15]]()[%{{.*}}]270 return %2 : index271}272 273// -----274 275// CHECK-DAG: #[[$MAP_symbolic_composition_a:.*]] = affine_map<()[s0] -> (s0 * 512)>276 277// CHECK-LABEL: func @symbolic_composition_a(%{{.*}}: index, %{{.*}}: index) -> index {278func.func @symbolic_composition_a(%arg0: index, %arg1: index) -> index {279 %0 = affine.apply affine_map<(d0) -> (d0 * 4)>(%arg0)280 %1 = affine.apply affine_map<()[s0, s1] -> (8 * s0)>()[%0, %arg0]281 %2 = affine.apply affine_map<()[s0, s1] -> (16 * s1)>()[%arg1, %1]282 // CHECK: %{{.*}} = affine.apply #[[$MAP_symbolic_composition_a]]()[%{{.*}}]283 return %2 : index284}285 286// -----287 288// CHECK-DAG: #[[$MAP_symbolic_composition_b:.*]] = affine_map<()[s0] -> (s0 * 4)>289 290// CHECK-LABEL: func @symbolic_composition_b(%arg0: index, %arg1: index, %arg2: index, %arg3: index) -> index {291func.func @symbolic_composition_b(%arg0: index, %arg1: index, %arg2: index, %arg3: index) -> index {292 %0 = affine.apply affine_map<(d0) -> (d0)>(%arg0)293 %1 = affine.apply affine_map<()[s0, s1, s2, s3] -> (s0 + s1 + s2 + s3)>()[%0, %0, %0, %0]294 // CHECK: %{{.*}} = affine.apply #[[$MAP_symbolic_composition_b]]()[%{{.*}}]295 return %1 : index296}297 298// -----299 300// CHECK-DAG: #[[$MAP_symbolic_composition_c:.*]] = affine_map<()[s0, s1] -> (s0 * 3 + s1)>301 302// CHECK-LABEL: func @symbolic_composition_c(%arg0: index, %arg1: index, %arg2: index, %arg3: index) -> index {303func.func @symbolic_composition_c(%arg0: index, %arg1: index, %arg2: index, %arg3: index) -> index {304 %0 = affine.apply affine_map<(d0) -> (d0)>(%arg0)305 %1 = affine.apply affine_map<(d0) -> (d0)>(%arg1)306 %2 = affine.apply affine_map<()[s0, s1, s2, s3] -> (s0 + s1 + s2 + s3)>()[%0, %0, %0, %1]307 // CHECK: %{{.*}} = affine.apply #[[$MAP_symbolic_composition_c]]()[%{{.*}}, %{{.*}}]308 return %2 : index309}310 311// -----312 313// CHECK-DAG: #[[$MAP_symbolic_composition_d:.*]] = affine_map<()[s0, s1] -> (s0 * 3 + s1)>314 315// CHECK-LABEL: func @symbolic_composition_d(316// CHECK-SAME: %[[ARG0:[0-9a-zA-Z]+]]: index317// CHECK-SAME: %[[ARG1:[0-9a-zA-Z]+]]: index318func.func @symbolic_composition_d(%arg0: index, %arg1: index, %arg2: index, %arg3: index) -> index {319 %0 = affine.apply affine_map<(d0) -> (d0)>(%arg0)320 %1 = affine.apply affine_map<()[s0] -> (s0)>()[%arg1]321 %2 = affine.apply affine_map<()[s0, s1, s2, s3] -> (s0 + s1 + s2 + s3)>()[%0, %0, %0, %1]322 // CHECK: %{{.*}} = affine.apply #[[$MAP_symbolic_composition_d]]()[%[[ARG0]], %[[ARG1]]]323 return %2 : index324}325 326// -----327 328// CHECK-DAG: #[[$MAP_mix_dims_and_symbols_b:.*]] = affine_map<()[s0, s1] -> (s0 * 42 + s1 + 6)>329 330// CHECK-LABEL: func @mix_dims_and_symbols_b(%arg0: index, %arg1: index) -> index {331func.func @mix_dims_and_symbols_b(%arg0: index, %arg1: index) -> index {332 %a = affine.apply affine_map<(d0)[s0] -> (d0 - 1 + 42 * s0)> (%arg0)[%arg1]333 %b = affine.apply affine_map<(d0) -> (d0 + 7)> (%a)334 // CHECK: {{.*}} = affine.apply #[[$MAP_mix_dims_and_symbols_b]]()[%{{.*}}, %{{.*}}]335 336 return %b : index337}338 339// -----340 341// CHECK-DAG: #[[$MAP_mix_dims_and_symbols_c:.*]] = affine_map<()[s0, s1] -> (s0 * 168 + s1 * 4 - 4)>342 343// CHECK-LABEL: func @mix_dims_and_symbols_c(%arg0: index, %arg1: index) -> index {344func.func @mix_dims_and_symbols_c(%arg0: index, %arg1: index) -> index {345 %a = affine.apply affine_map<(d0)[s0] -> (d0 - 1 + 42 * s0)> (%arg0)[%arg1]346 %b = affine.apply affine_map<(d0) -> (d0 + 7)> (%a)347 %c = affine.apply affine_map<(d0) -> (d0 * 4)> (%a)348 // CHECK: {{.*}} = affine.apply #[[$MAP_mix_dims_and_symbols_c]]()[%{{.*}}, %{{.*}}]349 return %c : index350}351 352// -----353 354// CHECK-DAG: #[[$MAP_mix_dims_and_symbols_d:.*]] = affine_map<()[s0, s1] -> ((s0 * 42 + s1 + 6) ceildiv 8)>355 356// CHECK-LABEL: func @mix_dims_and_symbols_d(%arg0: index, %arg1: index) -> index {357func.func @mix_dims_and_symbols_d(%arg0: index, %arg1: index) -> index {358 %a = affine.apply affine_map<(d0)[s0] -> (d0 - 1 + 42 * s0)> (%arg0)[%arg1]359 %b = affine.apply affine_map<(d0) -> (d0 + 7)> (%a)360 %c = affine.apply affine_map<(d0) -> (d0 * 4)> (%a)361 %d = affine.apply affine_map<()[s0] -> (s0 ceildiv 8)> ()[%b]362 // CHECK: {{.*}} = affine.apply #[[$MAP_mix_dims_and_symbols_d]]()[%{{.*}}, %{{.*}}]363 return %d : index364}365 366// -----367 368// CHECK-DAG: #[[$MAP_mix_dims_and_symbols_e:.*]] = affine_map<()[s0, s1] -> ((s0 * 168 + s1 * 4 - 4) floordiv 3)>369 370// CHECK-LABEL: func @mix_dims_and_symbols_e(%arg0: index, %arg1: index) -> index {371func.func @mix_dims_and_symbols_e(%arg0: index, %arg1: index) -> index {372 %a = affine.apply affine_map<(d0)[s0] -> (d0 - 1 + 42 * s0)> (%arg0)[%arg1]373 %b = affine.apply affine_map<(d0) -> (d0 + 7)> (%a)374 %c = affine.apply affine_map<(d0) -> (d0 * 4)> (%a)375 %d = affine.apply affine_map<()[s0] -> (s0 ceildiv 8)> ()[%b]376 %e = affine.apply affine_map<(d0) -> (d0 floordiv 3)> (%c)377 // CHECK: {{.*}} = affine.apply #[[$MAP_mix_dims_and_symbols_e]]()[%{{.*}}, %{{.*}}]378 return %e : index379}380 381// -----382 383// CHECK-LABEL: func @mix_dims_and_symbols_f(%arg0: index, %arg1: index) -> index {384func.func @mix_dims_and_symbols_f(%arg0: index, %arg1: index) -> index {385 %a = affine.apply affine_map<(d0)[s0] -> (d0 - 1 + 42 * s0)> (%arg0)[%arg1]386 %b = affine.apply affine_map<(d0) -> (d0 + 7)> (%a)387 %c = affine.apply affine_map<(d0) -> (d0 * 4)> (%a)388 %d = affine.apply affine_map<()[s0] -> (s0 ceildiv 8)> ()[%b]389 %e = affine.apply affine_map<(d0) -> (d0 floordiv 3)> (%c)390 %f = affine.apply affine_map<(d0, d1)[s0, s1] -> (d0 - s1 + d1 - s0)> (%d, %e)[%e, %d]391 // CHECK: {{.*}} = arith.constant 0 : index392 393 return %f : index394}395 396// -----397 398// CHECK-DAG: #[[$MAP_symbolic_composition_b:.*]] = affine_map<()[s0] -> (s0 * 4)>399 400// CHECK-LABEL: func @mix_dims_and_symbols_g(%arg0: index, %arg1: index) -> (index, index, index) {401func.func @mix_dims_and_symbols_g(%M: index, %N: index) -> (index, index, index) {402 %K = affine.apply affine_map<(d0) -> (4*d0)> (%M)403 %res1 = affine.apply affine_map<()[s0, s1] -> (4 * s0)>()[%N, %K]404 %res2 = affine.apply affine_map<()[s0, s1] -> (s1)>()[%N, %K]405 %res3 = affine.apply affine_map<()[s0, s1] -> (1024)>()[%N, %K]406 // CHECK-DAG: {{.*}} = arith.constant 1024 : index407 // CHECK-DAG: {{.*}} = affine.apply #[[$MAP_symbolic_composition_b]]()[%{{.*}}]408 // CHECK-DAG: {{.*}} = affine.apply #[[$MAP_symbolic_composition_b]]()[%{{.*}}]409 return %res1, %res2, %res3 : index, index, index410}411 412// -----413 414// CHECK-DAG: #[[$symbolic_semi_affine:.*]] = affine_map<(d0)[s0] -> (d0 floordiv (s0 + 1))>415 416// CHECK-LABEL: func @symbolic_semi_affine(%arg0: index, %arg1: index, %arg2: memref<?xf32>) {417func.func @symbolic_semi_affine(%M: index, %N: index, %A: memref<?xf32>) {418 %f1 = arith.constant 1.0 : f32419 affine.for %i0 = 1 to 100 {420 %1 = affine.apply affine_map<()[s0] -> (s0 + 1)> ()[%M]421 %2 = affine.apply affine_map<(d0)[s0] -> (d0 floordiv s0)> (%i0)[%1]422 // CHECK-DAG: {{.*}} = affine.apply #[[$symbolic_semi_affine]](%{{.*}})[%{{.*}}]423 memref.store %f1, %A[%2] : memref<?xf32>424 }425 return426}427 428// -----429 430// CHECK: #[[$MAP0:.*]] = affine_map<()[s0] -> (0, s0)>431// CHECK: #[[$MAP1:.*]] = affine_map<()[s0] -> (100, s0)>432 433// CHECK-LABEL: func @constant_fold_bounds(%arg0: index) {434func.func @constant_fold_bounds(%N : index) {435 // CHECK: arith.constant 3 : index436 // CHECK-NEXT: "foo"() : () -> index437 %c9 = arith.constant 9 : index438 %c1 = arith.constant 1 : index439 %c2 = arith.constant 2 : index440 %c3 = affine.apply affine_map<(d0, d1) -> (d0 + d1)> (%c1, %c2)441 %l = "foo"() : () -> index442 443 // CHECK: affine.for %{{.*}} = 5 to 7 {444 affine.for %i = max affine_map<(d0, d1) -> (0, d0 + d1)> (%c2, %c3) to min affine_map<(d0, d1) -> (d0 - 2, 32*d1)> (%c9, %c1) {445 "foo"(%i, %c3) : (index, index) -> ()446 }447 448 // Bound takes a non-constant argument but can still be folded.449 // CHECK: affine.for %{{.*}} = 1 to 7 {450 affine.for %j = max affine_map<(d0) -> (0, 1)> (%N) to min affine_map<(d0, d1) -> (7, 9)> (%N, %l) {451 "foo"(%j, %c3) : (index, index) -> ()452 }453 454 // None of the bounds can be folded.455 // CHECK: affine.for %{{.*}} = max #[[$MAP0]]()[%{{.*}}] to min #[[$MAP1]]()[%{{.*}}] {456 affine.for %k = max affine_map<()[s0] -> (0, s0)> ()[%l] to min affine_map<()[s0] -> (100, s0)> ()[%N] {457 "foo"(%k, %c3) : (index, index) -> ()458 }459 return460}461 462// -----463 464// CHECK-LABEL: func @fold_empty_loops()465func.func @fold_empty_loops() -> index {466 %c0 = arith.constant 0 : index467 affine.for %i = 0 to 10 {468 }469 %res = affine.for %i = 0 to 10 iter_args(%arg = %c0) -> index {470 affine.yield %arg : index471 }472 // CHECK-NEXT: %[[zero:.*]] = arith.constant 0473 // CHECK-NEXT: return %[[zero]]474 return %res : index475}476 477// -----478 479// CHECK-LABEL: func @fold_empty_loop()480func.func @fold_empty_loop() -> (index, index) {481 %c0 = arith.constant 0 : index482 %c1 = arith.constant 1 : index483 %c2 = arith.constant 2 : index484 %res:2 = affine.for %i = 0 to 10 iter_args(%arg0 = %c0, %arg1 = %c1) -> (index, index) {485 affine.yield %c2, %arg1 : index, index486 }487 // CHECK-DAG: %[[one:.*]] = arith.constant 1488 // CHECK-DAG: %[[two:.*]] = arith.constant 2489 // CHECK-NEXT: return %[[two]], %[[one]]490 return %res#0, %res#1 : index, index491}492 493// -----494 495// CHECK-LABEL: func @fold_empty_loops_trip_count_1()496func.func @fold_empty_loops_trip_count_1() -> (index, index, index, index) {497 %c0 = arith.constant 0 : index498 %c1 = arith.constant 1 : index499 %c2 = arith.constant 2 : index500 %res1:2 = affine.for %i = 0 to 1 iter_args(%arg0 = %c2, %arg1 = %c0) -> (index, index) {501 affine.yield %c1, %arg0 : index, index502 }503 %res2:2 = affine.for %i = 0 to 2 step 3 iter_args(%arg0 = %c2, %arg1 = %c0) -> (index, index) {504 affine.yield %arg1, %arg0 : index, index505 }506 // CHECK-DAG: %[[zero:.*]] = arith.constant 0507 // CHECK-DAG: %[[one:.*]] = arith.constant 1508 // CHECK-DAG: %[[two:.*]] = arith.constant 2509 // CHECK-NEXT: return %[[one]], %[[two]], %[[zero]], %[[two]]510 return %res1#0, %res1#1, %res2#0, %res2#1 : index, index, index, index511}512 513// -----514 515// CHECK-LABEL: func @fold_empty_loop_trip_count_0()516func.func @fold_empty_loop_trip_count_0() -> (index, index) {517 %c0 = arith.constant 0 : index518 %c1 = arith.constant 1 : index519 %c2 = arith.constant 2 : index520 %res:2 = affine.for %i = 0 to 0 iter_args(%arg0 = %c2, %arg1 = %c0) -> (index, index) {521 affine.yield %c1, %arg0 : index, index522 }523 // CHECK-DAG: %[[zero:.*]] = arith.constant 0524 // CHECK-DAG: %[[two:.*]] = arith.constant 2525 // CHECK-NEXT: return %[[two]], %[[zero]]526 return %res#0, %res#1 : index, index527}528 529// -----530 531// CHECK-LABEL: func @fold_empty_loop_trip_count_unknown532func.func @fold_empty_loop_trip_count_unknown(%in : index) -> (index, index) {533 %c0 = arith.constant 0 : index534 %c1 = arith.constant 1 : index535 %res:2 = affine.for %i = 0 to %in iter_args(%arg0 = %c0, %arg1 = %c1) -> (index, index) {536 affine.yield %arg0, %arg1 : index, index537 }538 // CHECK-DAG: %[[zero:.*]] = arith.constant 0539 // CHECK-DAG: %[[one:.*]] = arith.constant 1540 // CHECK-NEXT: return %[[zero]], %[[one]]541 return %res#0, %res#1 : index, index542}543 544// -----545 546// CHECK-LABEL: func @empty_loops_not_folded_1547func.func @empty_loops_not_folded_1(%in : index) -> index {548 %c0 = arith.constant 0 : index549 %c1 = arith.constant 1 : index550 // CHECK: affine.for551 %res = affine.for %i = 0 to %in iter_args(%arg = %c0) -> index {552 affine.yield %c1 : index553 }554 return %res : index555}556 557// -----558 559// CHECK-LABEL: func @empty_loops_not_folded_2560func.func @empty_loops_not_folded_2(%in : index) -> (index, index) {561 %c0 = arith.constant 0 : index562 %c1 = arith.constant 1 : index563 // CHECK: affine.for564 %res:2 = affine.for %i = 0 to %in iter_args(%arg0 = %c0, %arg1 = %c1) -> (index, index) {565 affine.yield %arg1, %arg0 : index, index566 }567 return %res#0, %res#1 : index, index568}569 570// -----571 572// CHECK-LABEL: func @empty_loops_not_folded_3573func.func @empty_loops_not_folded_3() -> (index, index) {574 %c0 = arith.constant 0 : index575 %c1 = arith.constant 1 : index576 // CHECK: affine.for577 %res:2 = affine.for %i = 0 to 10 iter_args(%arg0 = %c0, %arg1 = %c1) -> (index, index) {578 affine.yield %arg1, %arg0 : index, index579 }580 return %res#0, %res#1 : index, index581}582 583// -----584 585// CHECK-LABEL: func @zero_iter_loop_not_folded586func.func @zero_iter_loop_not_folded() {587 %A = memref.alloc() : memref<4xf32>588 affine.for %i = 0 to 0 {589 %load = affine.load %A[%i] : memref<4xf32>590 affine.store %load, %A[%i] : memref<4xf32>591 }592 // CHECK: affine.for {{.*}} = 0 to 0 {593 return594}595 596// -----597 598// CHECK-LABEL: func @fold_zero_iter_loops599// CHECK-SAME: %[[ARG:.*]]: index600func.func @fold_zero_iter_loops(%in : index) -> index {601 %c1 = arith.constant 1 : index602 %res = affine.for %i = 0 to 0 iter_args(%loop_arg = %in) -> index {603 %yield = arith.addi %loop_arg, %c1 : index604 affine.yield %yield : index605 }606 // CHECK-NEXT: return %[[ARG]]607 return %res : index608}609 610// -----611 612// CHECK-DAG: #[[$SET:.*]] = affine_set<(d0, d1)[s0] : (d0 >= 0, -d0 + 1022 >= 0, d1 >= 0, -d1 + s0 - 2 >= 0)>613 614// CHECK-LABEL: func @canonicalize_affine_if615// CHECK-SAME: %[[M:[0-9a-zA-Z]*]]: index,616// CHECK-SAME: %[[N:[0-9a-zA-Z]*]]: index)617func.func @canonicalize_affine_if(%M : index, %N : index) {618 %c1022 = arith.constant 1022 : index619 // Drop unused operand %M, propagate %c1022, and promote %N to symbolic.620 affine.for %i = 0 to 1024 {621 affine.for %j = 0 to %N {622 // CHECK: affine.if #[[$SET]](%{{.*}}, %{{.*}})[%[[N]]]623 affine.if affine_set<(d0, d1, d2, d3)[s0] : (d1 >= 0, d0 - d1 >= 0, d2 >= 0, d3 - d2 - 2 >= 0)>624 (%c1022, %i, %j, %N)[%M] {625 "foo"() : () -> ()626 }627 "bar"() : () -> ()628 }629 }630 return631}632 633// -----634 635// CHECK-DAG: #[[$SET:.*]] = affine_set<(d0, d1)[s0] : (d0 - 1 >= 0, d1 - 1 == 0, -d0 + s0 + 10 >= 0)>636 637// CHECK-LABEL: func @canonicalize_affine_if_compose_apply638// CHECK-SAME: %[[N:.*]]: index639func.func @canonicalize_affine_if_compose_apply(%N: index) {640 %M = affine.apply affine_map<()[s0] -> (s0 + 10)> ()[%N]641 // CHECK-NEXT: affine.for %[[I:.*]] =642 affine.for %i = 0 to 1024 {643 // CHECK-NEXT: affine.for %[[J:.*]] =644 affine.for %j = 0 to 100 {645 %j_ = affine.apply affine_map<(d0)[] -> (d0 + 1)> (%j)646 // CHECK-NEXT: affine.if #[[$SET]](%[[I]], %[[J]])[%[[N]]]647 affine.if affine_set<(d0, d1)[s0] : (d0 - 1 >= 0, d1 - 2 == 0, -d0 + s0 >= 0)>(%i, %j_)[%M] {648 "test.foo"() : ()->()649 }650 }651 }652 return653}654 655// -----656 657// CHECK-DAG: #[[$LBMAP:.*]] = affine_map<()[s0] -> (0, s0)>658// CHECK-DAG: #[[$UBMAP:.*]] = affine_map<()[s0] -> (1024, s0 * 2)>659 660// CHECK-LABEL: func @canonicalize_bounds661// CHECK-SAME: %[[M:.*]]: index,662// CHECK-SAME: %[[N:.*]]: index)663func.func @canonicalize_bounds(%M : index, %N : index) {664 %c0 = arith.constant 0 : index665 %c1024 = arith.constant 1024 : index666 // Drop unused operand %N, drop duplicate operand %M, propagate %c1024, and667 // promote %M to a symbolic one.668 // CHECK: affine.for %{{.*}} = 0 to min #[[$UBMAP]]()[%[[M]]]669 affine.for %i = 0 to min affine_map<(d0, d1, d2, d3) -> (d0, d1 + d2)> (%c1024, %M, %M, %N) {670 "foo"() : () -> ()671 }672 // Promote %M to symbolic position.673 // CHECK: affine.for %{{.*}} = 0 to #{{.*}}()[%[[M]]]674 affine.for %i = 0 to affine_map<(d0) -> (4 * d0)> (%M) {675 "foo"() : () -> ()676 }677 // Lower bound canonicalize.678 // CHECK: affine.for %{{.*}} = max #[[$LBMAP]]()[%[[N]]] to %[[M]]679 affine.for %i = max affine_map<(d0, d1) -> (d0, d1)> (%c0, %N) to %M {680 "foo"() : () -> ()681 }682 return683}684 685// -----686 687// Compose maps into affine load and store ops.688 689// CHECK-LABEL: @compose_into_affine_load_store690func.func @compose_into_affine_load_store(%A : memref<1024xf32>, %u : index) {691 // CHECK: affine.for %[[IV:.*]] = 0 to 1024692 affine.for %i = 0 to 1024 {693 // Make sure the unused operand (%u below) gets dropped as well.694 %idx = affine.apply affine_map<(d0, d1) -> (d0 + 1)> (%i, %u)695 %0 = affine.load %A[%idx] : memref<1024xf32>696 affine.store %0, %A[%idx] : memref<1024xf32>697 // CHECK-NEXT: affine.load %{{.*}}[%[[IV]] + 1]698 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%[[IV]] + 1]699 700 // Map remains the same, but operand changes on composition.701 %copy = affine.apply affine_map<(d0) -> (d0)> (%i)702 %1 = affine.load %A[%copy] : memref<1024xf32>703 "prevent.dce"(%1) : (f32) -> ()704 // CHECK-NEXT: affine.load %{{.*}}[%[[IV]]]705 }706 return707}708 709// -----710 711func.func @affine_min(%arg0 : index, %arg1 : index, %arg2 : index) {712 %c511 = arith.constant 511 : index713 %c1 = arith.constant 0 : index714 %0 = affine.min affine_map<(d0)[s0] -> (1000, d0 + 512, s0 + 1)> (%c1)[%c511]715 "op0"(%0) : (index) -> ()716 // CHECK: %[[CST:.*]] = arith.constant 512 : index717 // CHECK-NEXT: "op0"(%[[CST]]) : (index) -> ()718 // CHECK-NEXT: return719 return720}721 722// -----723 724func.func @affine_min(%arg0 : index, %arg1 : index, %arg2 : index) {725 %c3 = arith.constant 3 : index726 %c20 = arith.constant 20 : index727 %0 = affine.min affine_map<(d0)[s0] -> (1000, d0 floordiv 4, (s0 mod 5) + 1)> (%c20)[%c3]728 "op0"(%0) : (index) -> ()729 // CHECK: %[[CST:.*]] = arith.constant 4 : index730 // CHECK-NEXT: "op0"(%[[CST]]) : (index) -> ()731 // CHECK-NEXT: return732 return733}734 735// -----736 737func.func @affine_max(%arg0 : index, %arg1 : index, %arg2 : index) {738 %c511 = arith.constant 511 : index739 %c1 = arith.constant 0 : index740 %0 = affine.max affine_map<(d0)[s0] -> (1000, d0 + 512, s0 + 1)> (%c1)[%c511]741 "op0"(%0) : (index) -> ()742 // CHECK: %[[CST:.*]] = arith.constant 1000 : index743 // CHECK-NEXT: "op0"(%[[CST]]) : (index) -> ()744 // CHECK-NEXT: return745 return746}747 748// -----749 750func.func @affine_max(%arg0 : index, %arg1 : index, %arg2 : index) {751 %c3 = arith.constant 3 : index752 %c20 = arith.constant 20 : index753 %0 = affine.max affine_map<(d0)[s0] -> (1000, d0 floordiv 4, (s0 mod 5) + 1)> (%c20)[%c3]754 "op0"(%0) : (index) -> ()755 // CHECK: %[[CST:.*]] = arith.constant 1000 : index756 // CHECK-NEXT: "op0"(%[[CST]]) : (index) -> ()757 // CHECK-NEXT: return758 return759}760 761// -----762 763// CHECK: #[[$MAP:.*]] = affine_map<(d0, d1) -> (d1 - 2, d0)>764 765func.func @affine_min(%arg0: index) {766 affine.for %i = 0 to %arg0 {767 affine.for %j = 0 to %arg0 {768 %c2 = arith.constant 2 : index769 // CHECK: affine.min #[[$MAP]]770 %0 = affine.min affine_map<(d0,d1,d2)->(d0, d1 - d2)>(%i, %j, %c2)771 "consumer"(%0) : (index) -> ()772 }773 }774 return775}776 777// -----778 779// Reproducer for PR45031. This used to fold into an incorrect map because780// symbols were concatenated in the wrong order during map folding. Map781// composition places the symbols of the original map before those of the map782// it is composed with, e.g. A.compose(B) will first have all symbols of A,783// then all symbols of B.784 785#map1 = affine_map<(d0)[s0, s1] -> (d0 * s0 + s1)>786#map2 = affine_map<(d0)[s0] -> (1024, -d0 + s0)>787 788// CHECK: #[[$MAP:.*]] = affine_map<()[s0, s1] -> (1024, s0 - s1 * 1024)>789 790// CHECK: func @rep(%[[ARG0:.*]]: index, %[[ARG1:.*]]: index)791func.func @rep(%arg0 : index, %arg1 : index) -> index {792 // CHECK-NOT: arith.constant793 %c0 = arith.constant 0 : index794 %c1024 = arith.constant 1024 : index795 // CHECK-NOT: affine.apply796 %0 = affine.apply #map1(%arg0)[%c1024, %c0]797 798 // CHECK: affine.min #[[$MAP]]()[%[[ARG1]], %[[ARG0]]]799 %1 = affine.min #map2(%0)[%arg1]800 return %1 : index801}802 803// -----804 805// CHECK-DAG: #[[ub:.*]] = affine_map<()[s0] -> (s0 + 2)>806 807func.func @drop_duplicate_bounds(%N : index) {808 // affine.for %i = max #lb(%arg0) to min #ub(%arg0)809 affine.for %i = max affine_map<(d0) -> (d0, d0)>(%N) to min affine_map<(d0) -> (d0 + 2, d0 + 2)>(%N) {810 "foo"() : () -> ()811 }812 return813}814 815// -----816 817// Ensure affine.parallel bounds expressions are canonicalized.818 819#map3 = affine_map<(d0) -> (d0 * 5)>820 821// CHECK-LABEL: func @affine_parallel_const_bounds822func.func @affine_parallel_const_bounds() {823 %cst = arith.constant 1.0 : f32824 %c0 = arith.constant 0 : index825 %c4 = arith.constant 4 : index826 %0 = memref.alloc() : memref<4xf32>827 // CHECK: affine.parallel (%{{.*}}) = (0) to (4)828 affine.parallel (%i) = (%c0) to (%c0 + %c4) {829 %1 = affine.apply #map3(%i)830 // CHECK: affine.parallel (%{{.*}}) = (0) to (%{{.*}} * 5)831 affine.parallel (%j) = (%c0) to (%1) {832 affine.store %cst, %0[%j] : memref<4xf32>833 }834 }835 return836}837 838// -----839 840func.func @compose_affine_maps_div_symbol(%A : memref<i64>, %i0 : index, %i1 : index) {841 %0 = affine.apply affine_map<()[s0] -> (2 * s0)> ()[%i0]842 %1 = affine.apply affine_map<()[s0] -> (3 * s0)> ()[%i0]843 %2 = affine.apply affine_map<(d0)[s0, s1] -> (d0 mod s1 + s0 * s1 + s0 * 4)> (%i1)[%0, %1]844 %3 = arith.index_cast %2: index to i64845 memref.store %3, %A[]: memref<i64>846 affine.for %i2 = 0 to 3 {847 %4 = affine.apply affine_map<(d0)[s0, s1] -> (d0 ceildiv s1 + s0 + s0 * 3)> (%i2)[%0, %1]848 %5 = arith.index_cast %4: index to i64849 memref.store %5, %A[]: memref<i64>850 }851 return852}853 854// -----855 856// CHECK: #[[MAP:.+]] = affine_map<()[s0, s1] -> (s0 + s1, s0 * s1)>857 858// CHECK: func @deduplicate_affine_min_expressions859// CHECK-SAME: (%[[I0:.+]]: index, %[[I1:.+]]: index)860func.func @deduplicate_affine_min_expressions(%i0: index, %i1: index) -> index {861 // CHECK: affine.min #[[MAP]]()[%[[I0]], %[[I1]]]862 %0 = affine.min affine_map<()[s0, s1] -> (s0 + s1, s0 * s1, s1 + s0, s0 * s1)> ()[%i0, %i1]863 return %0: index864}865 866// -----867 868// CHECK: #[[MAP:.+]] = affine_map<()[s0, s1] -> (s0 + s1, s0 * s1)>869 870// CHECK: func @deduplicate_affine_max_expressions871// CHECK-SAME: (%[[I0:.+]]: index, %[[I1:.+]]: index)872func.func @deduplicate_affine_max_expressions(%i0: index, %i1: index) -> index {873 // CHECK: affine.max #[[MAP]]()[%[[I0]], %[[I1]]]874 %0 = affine.max affine_map<()[s0, s1] -> (s0 + s1, s0 * s1, s1 + s0, s0 * s1)> ()[%i0, %i1]875 return %0: index876}877 878// -----879 880// CHECK-DAG: #[[MAP0:.+]] = affine_map<()[s0, s1, s2] -> (-s1 + s2, 16, s0 * 3)>881// CHECK-DAG: #[[MAP1:.+]] = affine_map<()[s0, s1, s2] -> (-s0 + s1, -s2 + 5, 16)>882 883// CHECK: func @merge_affine_min_ops884// CHECK-SAME: (%[[I0:.+]]: index, %[[I1:.+]]: index, %[[I2:.+]]: index, %[[I3:.+]]: index)885func.func @merge_affine_min_ops(%i0: index, %i1: index, %i2: index, %i3: index) -> (index, index) {886 %0 = affine.min affine_map<(d0)[s0] -> (16, d0 - s0)> (%i0)[%i1]887 888 // CHECK: affine.min #[[MAP0]]()[%[[I2]], %[[I1]], %[[I0]]]889 %1 = affine.min affine_map<(d0)[s0] -> (3 * s0, d0)> (%0)[%i2] // Use as dim890 // CHECK: affine.min #[[MAP1]]()[%[[I1]], %[[I0]], %[[I3]]]891 %2 = affine.min affine_map<(d0)[s0] -> (s0, 5 - d0)> (%i3)[%0] // Use as symbol892 893 return %1, %2: index, index894}895 896// -----897 898// CHECK: #[[MAP:.+]] = affine_map<()[s0, s1, s2] -> (s2 + 8, s2 * 4, s1 + 16, s1 * 8, s0 + 7)>899 900// CHECK: func @merge_multiple_affine_min_ops901// CHECK-SAME: (%[[I0:.+]]: index, %[[I1:.+]]: index, %[[I2:.+]]: index)902func.func @merge_multiple_affine_min_ops(%i0: index, %i1: index, %i2: index) -> index {903 %0 = affine.min affine_map<()[s0] -> (s0 + 16, s0 * 8)> ()[%i0]904 %1 = affine.min affine_map<()[s0] -> (s0 + 8, s0 * 4)> ()[%i1]905 // CHECK: affine.min #[[MAP]]()[%[[I2]], %[[I0]], %[[I1]]]906 %2 = affine.min affine_map<()[s0, s1, s2] -> (s0, 7 + s1, s2)> ()[%0, %i2, %1]907 return %2: index908}909 910// -----911 912// CHECK-DAG: #[[MAP:.+]] = affine_map<()[s0, s1] -> (s1 + 16, s1 * 8, s0 * 2)>913 914// CHECK: func @merge_multiple_uses_of_affine_min_ops915// CHECK-SAME: (%[[I0:.+]]: index, %[[I1:.+]]: index)916func.func @merge_multiple_uses_of_affine_min_ops(%i0: index, %i1: index) -> index {917 %0 = affine.min affine_map<()[s0] -> (s0 + 16, s0 * 8)> ()[%i0]918 // CHECK: affine.min #[[MAP]]()[%[[I1]], %[[I0]]]919 %2 = affine.min affine_map<()[s0, s1, s2] -> (s0, s1, s2 * 2)> ()[%0, %0, %i1]920 return %2: index921}922 923// -----924 925// CHECK-DAG: #[[MAP0:.+]] = affine_map<()[s0] -> (s0 + 16, s0 * 8)>926// CHECK-DAG: #[[MAP1:.+]] = affine_map<()[s0, s1, s2] -> (s2 + 16, s2 * 8, s1 * 2, s0 + 1)>927 928// CHECK: func @merge_mixed_uses_of_affine_min_ops929// CHECK-SAME: (%[[I0:.+]]: index, %[[I1:.+]]: index)930func.func @merge_mixed_uses_of_affine_min_ops(%i0: index, %i1: index) -> index {931 // CHECK: %[[AFFINE:.+]] = affine.min #[[MAP0]]()[%[[I0]]]932 %0 = affine.min affine_map<()[s0] -> (s0 + 16, s0 * 8)> ()[%i0]933 // %0 is bound to a symbol that is both a standalone expression and a part934 // of other expressions.935 // CHECK: affine.min #[[MAP1]]()[%[[AFFINE]], %[[I1]], %[[I0]]]936 %2 = affine.min affine_map<()[s0, s1, s2] -> (s0, s1 + 1, s2 * 2)> ()[%0, %0, %i1]937 return %2: index938}939 940// -----941 942// CHECK-LABEL: func @dont_merge_affine_min_if_not_single_dim943func.func @dont_merge_affine_min_if_not_single_dim(%i0: index, %i1: index, %i2: index) -> index {944 // CHECK-COUNT-2: affine.min945 %0 = affine.min affine_map<()[s0] -> (s0 + 16, s0 * 8)> ()[%i0]946 %1 = affine.min affine_map<(d0)[s0] -> (s0 + 4, 7 + d0)> (%0)[%i2]947 return %1: index948}949 950// -----951 952// CHECK-LABEL: func @dont_merge_affine_min_if_not_single_sym953func.func @dont_merge_affine_min_if_not_single_sym(%i0: index, %i1: index, %i2: index) -> index {954 // CHECK-COUNT-2: affine.min955 %0 = affine.min affine_map<()[s0] -> (s0 + 16, s0 * 8)> ()[%i0]956 %1 = affine.min affine_map<()[s0, s1] -> (s0 + 4, 7 + s1)> ()[%0, %i2]957 return %1: index958}959 960// -----961 962// CHECK-DAG: #[[MAP0:.+]] = affine_map<()[s0, s1, s2] -> (-s1 + s2, 16, s0 * 3)>963// CHECK-DAG: #[[MAP1:.+]] = affine_map<()[s0, s1, s2] -> (-s0 + s1, -s2 + 5, 16)>964 965// CHECK: func @merge_affine_max_ops966// CHECK-SAME: (%[[I0:.+]]: index, %[[I1:.+]]: index, %[[I2:.+]]: index, %[[I3:.+]]: index)967func.func @merge_affine_max_ops(%i0: index, %i1: index, %i2: index, %i3: index) -> (index, index) {968 %0 = affine.max affine_map<(d0)[s0] -> (16, d0 - s0)> (%i0)[%i1]969 970 // CHECK: affine.max #[[MAP0]]()[%[[I2]], %[[I1]], %[[I0]]]971 %1 = affine.max affine_map<(d0)[s0] -> (3 * s0, d0)> (%0)[%i2] // Use as dim972 // CHECK: affine.max #[[MAP1]]()[%[[I1]], %[[I0]], %[[I3]]]973 %2 = affine.max affine_map<(d0)[s0] -> (s0, 5 - d0)> (%i3)[%0] // Use as symbol974 975 return %1, %2: index, index976}977 978// -----979 980// CHECK: #[[MAP:.+]] = affine_map<()[s0, s1, s2] -> (s2 + 8, s2 * 4, s1 + 16, s1 * 8, s0 + 7)>981 982// CHECK: func @merge_multiple_affine_max_ops983// CHECK-SAME: (%[[I0:.+]]: index, %[[I1:.+]]: index, %[[I2:.+]]: index)984func.func @merge_multiple_affine_max_ops(%i0: index, %i1: index, %i2: index) -> index {985 %0 = affine.max affine_map<()[s0] -> (s0 + 16, s0 * 8)> ()[%i0]986 %1 = affine.max affine_map<()[s0] -> (s0 + 8, s0 * 4)> ()[%i1]987 // CHECK: affine.max #[[MAP]]()[%[[I2]], %[[I0]], %[[I1]]]988 %2 = affine.max affine_map<()[s0, s1, s2] -> (s0, 7 + s1, s2)> ()[%0, %i2, %1]989 return %2: index990}991 992// -----993 994// CHECK-DAG: #[[MAP:.+]] = affine_map<()[s0, s1] -> (s1 + 16, s1 * 8, s0 * 2)>995 996// CHECK: func @merge_multiple_uses_of_affine_max_ops997// CHECK-SAME: (%[[I0:.+]]: index, %[[I1:.+]]: index)998func.func @merge_multiple_uses_of_affine_max_ops(%i0: index, %i1: index) -> index {999 %0 = affine.max affine_map<()[s0] -> (s0 + 16, s0 * 8)> ()[%i0]1000 // CHECK: affine.max #[[MAP]]()[%[[I1]], %[[I0]]]1001 %2 = affine.max affine_map<()[s0, s1, s2] -> (s0, s1, s2 * 2)> ()[%0, %0, %i1]1002 return %2: index1003}1004 1005// -----1006 1007// CHECK-DAG: #[[MAP0:.+]] = affine_map<()[s0] -> (s0 + 16, s0 * 8)>1008// CHECK-DAG: #[[MAP1:.+]] = affine_map<()[s0, s1, s2] -> (s2 + 16, s2 * 8, s1 * 2, s0 + 1)>1009 1010// CHECK: func @merge_mixed_uses_of_affine_max_ops1011// CHECK-SAME: (%[[I0:.+]]: index, %[[I1:.+]]: index)1012func.func @merge_mixed_uses_of_affine_max_ops(%i0: index, %i1: index) -> index {1013 // CHECK: %[[AFFINE:.+]] = affine.max #[[MAP0]]()[%[[I0]]]1014 %0 = affine.max affine_map<()[s0] -> (s0 + 16, s0 * 8)> ()[%i0]1015 // %0 is bound to a symbol that is both a standalone expression and a part1016 // of other expressions.1017 // CHECK: affine.max #[[MAP1]]()[%[[AFFINE]], %[[I1]], %[[I0]]]1018 %2 = affine.max affine_map<()[s0, s1, s2] -> (s0, s1 + 1, s2 * 2)> ()[%0, %0, %i1]1019 return %2: index1020}1021 1022// -----1023 1024// CHECK-LABEL: func @dont_merge_affine_max_if_not_single_dim1025func.func @dont_merge_affine_max_if_not_single_dim(%i0: index, %i1: index, %i2: index) -> index {1026 // CHECK-COUNT-2: affine.max1027 %0 = affine.max affine_map<()[s0] -> (s0 + 16, s0 * 8)> ()[%i0]1028 %1 = affine.max affine_map<(d0)[s0] -> (s0 + 4, 7 + d0)> (%0)[%i2]1029 return %1: index1030}1031 1032// -----1033 1034// CHECK-LABEL: func @dont_merge_affine_max_if_not_single_sym1035func.func @dont_merge_affine_max_if_not_single_sym(%i0: index, %i1: index, %i2: index) -> index {1036 // CHECK-COUNT-2: affine.max1037 %0 = affine.max affine_map<()[s0] -> (s0 + 16, s0 * 8)> ()[%i0]1038 %1 = affine.max affine_map<()[s0, s1] -> (s0 + 4, 7 + s1)> ()[%0, %i2]1039 return %1: index1040}1041 1042// -----1043 1044// Ensure bounding maps of affine.for are composed.1045 1046// CHECK-DAG: #[[$MAP0]] = affine_map<()[s0] -> (s0 - 2)>1047// CHECK-DAG: #[[$MAP1]] = affine_map<()[s0] -> (s0 + 2)>1048 1049// CHECK-LABEL: func @compose_affine_for_bounds1050// CHECK-SAME: %[[N:.*]]: index)1051// CHECK: affine.for %{{.*}} = #[[$MAP0]]()[%[[N]]] to #[[$MAP1]]()[%[[N]]] {1052 1053func.func @compose_affine_for_bounds(%N: index) {1054 %u = affine.apply affine_map<(d0) -> (d0 + 2)>(%N)1055 %l = affine.apply affine_map<(d0) -> (d0 - 2)>(%N)1056 affine.for %i = %l to %u {1057 "foo"() : () -> ()1058 }1059 return1060}1061 1062// -----1063 1064// Compose maps into affine.vector_load / affine.vector_store1065 1066// CHECK-LABEL: func @compose_into_affine_vector_load_vector_store1067// CHECK: affine.for %[[IV:.*]] = 0 to 10241068// CHECK-NEXT: affine.vector_load %{{.*}}[%[[IV]] + 1]1069// CHECK-NEXT: affine.vector_store %{{.*}}, %{{.*}}[%[[IV]] + 1]1070// CHECK-NEXT: affine.vector_load %{{.*}}[%[[IV]]]1071func.func @compose_into_affine_vector_load_vector_store(%A : memref<1024xf32>, %u : index) {1072 affine.for %i = 0 to 1024 {1073 // Make sure the unused operand (%u below) gets dropped as well.1074 %idx = affine.apply affine_map<(d0, d1) -> (d0 + 1)> (%i, %u)1075 %0 = affine.vector_load %A[%idx] : memref<1024xf32>, vector<8xf32>1076 affine.vector_store %0, %A[%idx] : memref<1024xf32>, vector<8xf32>1077 1078 // Map remains the same, but operand changes on composition.1079 %copy = affine.apply affine_map<(d0) -> (d0)> (%i)1080 %1 = affine.vector_load %A[%copy] : memref<1024xf32>, vector<8xf32>1081 "prevent.dce"(%1) : (vector<8xf32>) -> ()1082 }1083 return1084}1085 1086// -----1087 1088// CHECK-LABEL: func @no_fold_of_store1089// CHECK: %[[cst:.+]] = memref.cast %arg1090// CHECK: affine.store %[[cst]]1091func.func @no_fold_of_store(%arg : memref<32xi8>, %holder: memref<memref<?xi8>>) {1092 %0 = memref.cast %arg : memref<32xi8> to memref<?xi8>1093 affine.store %0, %holder[] : memref<memref<?xi8>>1094 return1095}1096 1097// -----1098 1099// CHECK-DAG: #[[$MAP0:.+]] = affine_map<()[s0] -> (s0 + 16)>1100// CHECK-DAG: #[[$MAP1:.+]] = affine_map<()[s0] -> (s0 * 4)>1101 1102// CHECK: func @canonicalize_single_min_max1103// CHECK-SAME: (%[[I0:.+]]: index, %[[I1:.+]]: index)1104func.func @canonicalize_single_min_max(%i0: index, %i1: index) -> (index, index) {1105 // CHECK-NOT: affine.min1106 // CHECK-NEXT: affine.apply #[[$MAP0]]()[%[[I0]]]1107 %0 = affine.min affine_map<()[s0] -> (s0 + 16)> ()[%i0]1108 1109 // CHECK-NOT: affine.max1110 // CHECK-NEXT: affine.apply #[[$MAP1]]()[%[[I1]]]1111 %1 = affine.min affine_map<()[s0] -> (s0 * 4)> ()[%i1]1112 1113 return %0, %1: index, index1114}1115 1116// -----1117 1118// CHECK: #[[$MAP:.+]] = affine_map<()[s0, s1] -> (32, s1 + 16, s0 + s1)>1119 1120// CHECK-LABEL: func @canonicalize_multi_min_max1121// CHECK-SAME: (%[[I0:.+]]: index, %[[I1:.+]]: index)1122func.func @canonicalize_multi_min_max(%i0: index, %i1: index) -> (index, index) {1123 // CHECK-NEXT: affine.min #[[$MAP]]()[%[[I0]], %[[I1]]]1124 %0 = affine.min affine_map<()[s0, s1] -> (s0 + s1, s1 + 16, 32)> ()[%i0, %i1]1125 1126 // CHECK-NEXT: affine.max #[[$MAP]]()[%[[I0]], %[[I1]]]1127 %1 = affine.max affine_map<()[s0, s1] -> (s0 + s1, 32, s1 + 16)> ()[%i0, %i1]1128 1129 return %0, %1: index, index1130}1131 1132// -----1133 1134module {1135 memref.global "private" constant @__constant_1x5x1xf32 : memref<1x5x1xf32> = dense<[[[6.250000e-02], [2.500000e-01], [3.750000e-01], [2.500000e-01], [6.250000e-02]]]>1136 memref.global "private" constant @__constant_32x64xf32 : memref<32x64xf32> = dense<0.000000e+00>1137 // CHECK-LABEL: func @fold_const_init_global_memref1138 func.func @fold_const_init_global_memref() -> (f32, f32) {1139 %m = memref.get_global @__constant_1x5x1xf32 : memref<1x5x1xf32>1140 %v0 = affine.load %m[0, 0, 0] : memref<1x5x1xf32>1141 %v1 = affine.load %m[0, 1, 0] : memref<1x5x1xf32>1142 return %v0, %v1 : f32, f321143 // CHECK-DAG: %[[C0:.*]] = arith.constant 6.250000e-02 : f321144 // CHECK-DAG: %[[C1:.*]] = arith.constant 2.500000e-01 : f321145 // CHECK-NEXT: return %[[C0]], %[[C1]]1146 }1147 1148 // CHECK-LABEL: func @fold_const_splat_global1149 func.func @fold_const_splat_global() -> memref<32x64xf32> {1150 // CHECK-NEXT: %[[CST:.*]] = arith.constant 0.000000e+00 : f321151 %m = memref.get_global @__constant_32x64xf32 : memref<32x64xf32>1152 %s = memref.alloc() : memref<32x64xf32>1153 affine.for %i = 0 to 32 {1154 affine.for %j = 0 to 64 {1155 %v = affine.load %m[%i, %j] : memref<32x64xf32>1156 affine.store %v, %s[%i, %j] : memref<32x64xf32>1157 // CHECK: affine.store %[[CST]], %{{.*}}1158 }1159 }1160 return %s: memref<32x64xf32>1161 }1162}1163 1164// -----1165 1166// Simplification of maps exploiting operand info.1167 1168// CHECK: #[[$MAP_SIMPLER:.*]] = affine_map<(d0, d1) -> (((d0 + d1) mod 458313) floordiv 227)>1169 1170// CHECK-LABEL: func @simplify_with_operands1171func.func @simplify_with_operands(%N: index, %A: memref<?x32xf32>) {1172 // CHECK-NEXT: affine.for %[[I:.*]] = 0 to %{{.*}}1173 affine.for %i = 0 to %N step 32 {1174 // CHECK-NEXT: affine.for %[[II:.*]] = 0 to 321175 affine.for %ii = 0 to 32 {1176 // %ii is less than 32 and %i divides 32.1177 // CHECK: affine.load %{{.*}}[0, 0]1178 %x = affine.load %A[%ii floordiv 32, %i mod 32] : memref<?x32xf32>1179 "test.foo"(%x) : (f32) -> ()1180 1181 // %i is aligned at 32 boundary and %ii < 32.1182 // CHECK: affine.load %{{.*}}[%[[I]] floordiv 32, %[[II]] mod 16]1183 %a = affine.load %A[(%i + %ii) floordiv 32, (%i + %ii) mod 16] : memref<?x32xf32>1184 "test.foo"(%a) : (f32) -> ()1185 // CHECK: affine.load %{{.*}}[%[[I]] floordiv 64, (%[[I]] + %[[II]]) mod 64]1186 %b = affine.load %A[(%i + %ii) floordiv 64, (%i + %ii) mod 64] : memref<?x32xf32>1187 "test.foo"(%b) : (f32) -> ()1188 // CHECK: affine.load %{{.*}}[(%[[I]] + %[[II]]) floordiv 16, %[[II]] mod 16]1189 %c = affine.load %A[(%i + %ii) floordiv 16, (%i + %ii) mod 16] : memref<?x32xf32>1190 "test.foo"(%c) : (f32) -> ()1191 }1192 }1193 1194 // Should not simplify.1195 affine.for %i = -1 to 32 {1196 // CHECK: affine.load %{{.*}}[%{{.*}} floordiv {{.*}}, %{{.*}} mod {{.*}}] :1197 %x = affine.load %A[%i floordiv 32, %i mod 32] : memref<?x32xf32>1198 "test.foo"(%x) : (f32) -> ()1199 }1200 1201 affine.for %arg0 = 0 to %N step 128 {1202 affine.for %arg4 = 0 to 32 step 32 {1203 affine.for %arg5 = 0 to 128 {1204 // CHECK: affine.apply #[[$MAP_SIMPLER]]1205 %x = affine.apply affine_map<(d0, d1, d2) -> (((d0 + d2) mod 458313) floordiv 227 + d1 floordiv 256)>(%arg0, %arg4, %arg5)1206 "test.foo"(%x) : (index) -> ()1207 }1208 }1209 }1210 1211 return1212}1213 1214// CHECK-LABEL: func @simplify_div_mod_with_operands1215func.func @simplify_div_mod_with_operands(%N: index, %A: memref<64xf32>, %unknown: index) {1216 // CHECK: affine.for %[[I:.*]] = 0 to 321217 %cst = arith.constant 1.0 : f321218 affine.for %i = 0 to 32 {1219 // CHECK: affine.store %{{.*}}, %{{.*}}[0]1220 affine.store %cst, %A[%i floordiv 32] : memref<64xf32>1221 // CHECK: affine.store %{{.*}}, %{{.*}}[1]1222 affine.store %cst, %A[(%i + 1) ceildiv 32] : memref<64xf32>1223 // CHECK: affine.store %{{.*}}, %{{.*}}[%[[I]]]1224 affine.store %cst, %A[%i mod 32] : memref<64xf32>1225 // CHECK: affine.store %{{.*}}, %{{.*}}[0]1226 affine.store %cst, %A[2 * %i floordiv 64] : memref<64xf32>1227 // CHECK: affine.store %{{.*}}, %{{.*}}[0]1228 affine.store %cst, %A[(%i mod 16) floordiv 16] : memref<64xf32>1229 1230 // The ones below can't be simplified.1231 affine.store %cst, %A[%i floordiv 16] : memref<64xf32>1232 affine.store %cst, %A[%i mod 16] : memref<64xf32>1233 affine.store %cst, %A[(%i mod 16) floordiv 15] : memref<64xf32>1234 affine.store %cst, %A[%i mod 31] : memref<64xf32>1235 // CHECK: affine.store %{{.*}}, %{{.*}}[%{{.*}} floordiv 16] : memref<64xf32>1236 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}} mod 16] : memref<64xf32>1237 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[(%{{.*}} mod 16) floordiv 15] : memref<64xf32>1238 // CHECK-NEXT: affine.store %{{.*}}, %{{.*}}[%{{.*}} mod 31] : memref<64xf32>1239 }1240 1241 affine.for %i = -8 to 32 {1242 // Can't be simplified.1243 // CHECK: affine.store %{{.*}}, %{{.*}}[%{{.*}} floordiv 32] : memref<64xf32>1244 affine.store %cst, %A[%i floordiv 32] : memref<64xf32>1245 // CHECK: affine.store %{{.*}}, %{{.*}}[%{{.*}} mod 32] : memref<64xf32>1246 affine.store %cst, %A[%i mod 32] : memref<64xf32>1247 // floordiv rounds toward -inf; (%i - 96) floordiv 64 will be -2.1248 // CHECK: affine.store %{{.*}}, %{{.*}}[0] : memref<64xf32>1249 affine.store %cst, %A[2 + (%i - 96) floordiv 64] : memref<64xf32>1250 }1251 1252 // CHECK: affine.for %[[II:.*]] = 8 to 161253 affine.for %i = 8 to 16 {1254 // CHECK: affine.store %{{.*}}, %{{.*}}[1] : memref<64xf32>1255 affine.store %cst, %A[%i floordiv 8] : memref<64xf32>1256 // CHECK: affine.store %{{.*}}, %{{.*}}[2] : memref<64xf32>1257 affine.store %cst, %A[(%i + 1) ceildiv 8] : memref<64xf32>1258 // CHECK: affine.store %{{.*}}, %{{.*}}[%[[II]] mod 8] : memref<64xf32>1259 affine.store %cst, %A[%i mod 8] : memref<64xf32>1260 // CHECK: affine.store %{{.*}}, %{{.*}}[%[[II]]] : memref<64xf32>1261 affine.store %cst, %A[%i mod 32] : memref<64xf32>1262 // Upper bound on the mod 32 expression will be 15.1263 // CHECK: affine.store %{{.*}}, %{{.*}}[0] : memref<64xf32>1264 affine.store %cst, %A[(%i mod 32) floordiv 16] : memref<64xf32>1265 // Lower bound on the mod 16 expression will be 8.1266 // CHECK: affine.store %{{.*}}, %{{.*}}[1] : memref<64xf32>1267 affine.store %cst, %A[(%i mod 16) floordiv 8] : memref<64xf32>1268 // CHECK: affine.store %{{.*}}, %{{.*}}[0] : memref<64xf32>1269 affine.store %cst, %A[(%unknown mod 16) floordiv 16] : memref<64xf32>1270 }1271 return1272}1273 1274// -----1275 1276#map0 = affine_map<(d0) -> (32, d0 * -32 + 32)>1277#map1 = affine_map<(d0) -> (32, d0 * -32 + 64)>1278#map3 = affine_map<(d0) -> (16, d0 * -16 + 32)>1279 1280// CHECK-DAG: #[[$SIMPLE_MAP:.*]] = affine_map<()[s0] -> (3, s0)>1281// CHECK-DAG: #[[$SIMPLE_MAP_MAX:.*]] = affine_map<()[s0] -> (5, s0)>1282// CHECK-DAG: #[[$SIMPLIFIED_MAP:.*]] = affine_map<(d0, d1) -> (-9, d0 * 4 - d1 * 4)>1283// CHECK-DAG: #[[$FLOORDIV:.*]] = affine_map<(d0) -> (d0 floordiv 2)>1284 1285// CHECK-LABEL: func @simplify_min_max_bounds_simple1286func.func @simplify_min_max_bounds_simple(%M: index) {1287 1288 // CHECK-NEXT: affine.for %{{.*}} = 0 to min #[[$SIMPLE_MAP]]1289 affine.for %i = 0 to min affine_map<(d0) -> (3, 5, d0)>(%M) {1290 "test.foo"() : () -> ()1291 }1292 1293 // CHECK: affine.for %{{.*}} = 0 to min #[[$SIMPLE_MAP]]1294 affine.for %i = 0 to min affine_map<(d0) -> (3, 3, d0)>(%M) {1295 "test.foo"() : () -> ()1296 }1297 1298 // CHECK: affine.for %{{.*}} = max #[[$SIMPLE_MAP_MAX]]1299 affine.for %i = max affine_map<(d0) -> (3, 5, d0)>(%M) to 10 {1300 "test.foo"() : () -> ()1301 }1302 1303 // CHECK: affine.for %{{.*}} = max #[[$SIMPLE_MAP_MAX]]1304 affine.for %i = max affine_map<(d0) -> (5, 5, d0)>(%M) to 10 {1305 "test.foo"() : () -> ()1306 }1307 1308 return1309}1310 1311// CHECK-LABEL: func @simplify_bounds_tiled1312func.func @simplify_bounds_tiled() {1313 affine.for %arg5 = 0 to 1 {1314 affine.for %arg6 = 0 to 2 {1315 affine.for %arg8 = 0 to min #map0(%arg5) step 16 {1316 affine.for %arg9 = 0 to min #map1(%arg6) step 16 {1317 affine.for %arg10 = 0 to 2 {1318 affine.for %arg12 = 0 to min #map3(%arg10) step 16 {1319 "test.foo"() : () -> ()1320 }1321 }1322 }1323 }1324 }1325 }1326 // CHECK: affine.for1327 // CHECK-NEXT: affine.for1328 // CHECK-NEXT: affine.for %{{.*}} = 0 to 32 step 161329 // CHECK-NEXT: affine.for %{{.*}} = 0 to 32 step 161330 // CHECK-NEXT: affine.for %{{.*}} = 0 to 21331 // CHECK-NEXT: affine.for %{{.*}} = 0 to 16 step 161332 1333 return1334}1335 1336// CHECK-LABEL: func @simplify_min_max_multi_expr1337func.func @simplify_min_max_multi_expr() {1338 // Lower bound max.1339 // CHECK: affine.for1340 affine.for %i = 0 to 2 {1341 // CHECK: affine.for %{{.*}} = 5 to1342 affine.for %j = max affine_map<(d0) -> (5, 4 * d0)> (%i) to affine_map<(d0) -> (4 * d0 + 3)>(%i) {1343 "test.foo"() : () -> ()1344 }1345 }1346 1347 // Expressions with multiple operands.1348 // CHECK: affine.for1349 affine.for %i = 0 to 2 {1350 // CHECK: affine.for1351 affine.for %j = 0 to 4 {1352 // The first upper bound expression will not be lower than -9. So, it's redundant.1353 // CHECK-NEXT: affine.for %{{.*}} = -10 to -91354 affine.for %k = -10 to min affine_map<(d0, d1) -> (4 * d0 - 3 * d1, -9)>(%i, %j) {1355 "test.foo"() : () -> ()1356 }1357 }1358 }1359 1360 // One expression is redundant but not the others.1361 // CHECK: affine.for1362 affine.for %i = 0 to 2 {1363 // CHECK: affine.for1364 affine.for %j = 0 to 4 {1365 // The first upper bound expression will not be lower than -9. So, it's redundant.1366 // CHECK-NEXT: affine.for %{{.*}} = -10 to min #[[$SIMPLIFIED_MAP]]1367 affine.for %k = -10 to min affine_map<(d0, d1) -> (4 * d0 - 3 * d1, -9, 4 * d0 - 4 * d1)>(%i, %j) {1368 "test.foo"() : () -> ()1369 }1370 }1371 }1372 1373 // CHECK: affine.for %{{.*}} = 0 to 11374 affine.for %i = 0 to 2 {1375 affine.for %j = max affine_map<(d0) -> (d0 floordiv 2, 0)>(%i) to 1 {1376 "test.foo"() : () -> ()1377 }1378 }1379 1380 // The constant bound is redundant here.1381 // CHECK: affine.for %{{.*}} = #[[$FLOORDIV]](%{{.*}} to 101382 affine.for %i = 0 to 8 {1383 affine.for %j = max affine_map<(d0) -> (d0 floordiv 2, 0)>(%i) to 10 {1384 "test.foo"() : () -> ()1385 }1386 }1387 1388 return1389}1390 1391// CHECK-LABEL: func @no_simplify_min_max1392func.func @no_simplify_min_max(%M: index) {1393 // Negative test cases.1394 // CHECK: affine.for1395 affine.for %i = 0 to 4 {1396 // CHECK-NEXT: affine.for %{{.*}} = 0 to min1397 affine.for %j = 0 to min affine_map<(d0) -> (2 * d0, 2)>(%i) {1398 "test.foo"() : () -> ()1399 }1400 // CHECK: affine.for %{{.*}} = 0 to min {{.*}}(%{{.*}})[%{{.*}}]1401 affine.for %j = 0 to min affine_map<(d0)[s0] -> (d0, s0)>(%i)[%M] {1402 "test.foo"() : () -> ()1403 }1404 }1405 1406 return1407}1408 1409// -----1410 1411// CHECK: #[[$map:.*]] = affine_map<()[s0] -> (s0 * ((-s0 + 40961) ceildiv 512))>1412// CHECK-BOTTOM-UP: #[[$map:.*]] = affine_map<()[s0] -> (s0 * ((-s0 + 40961) ceildiv 512))>1413// CHECK-LABEL: func @regression_do_not_perform_invalid_replacements1414// CHECK-BOTTOM-UP-LABEL: func @regression_do_not_perform_invalid_replacements1415func.func @regression_do_not_perform_invalid_replacements(%arg0: index) {1416 // Dim must be promoted to sym before combining both maps.1417 // CHECK: %[[apply:.*]] = affine.apply #[[$map]]()[%{{.*}}]1418 // CHECK-BOTTOM-UP: %[[apply:.*]] = affine.apply #[[$map]]()[%{{.*}}]1419 %0 = affine.apply affine_map<(d0) -> (-d0 + 40961)>(%arg0)1420 %1 = affine.apply affine_map<(d0)[s0] -> (d0 * (s0 ceildiv 512))>(%arg0)[%0]1421 // CHECK: "test.foo"(%[[apply]])1422 // CHECK-BOTTOM-UP: "test.foo"(%[[apply]])1423 "test.foo"(%1) : (index) -> ()1424 return1425}1426 1427// -----1428// CHECK-LABEL: func @min.oneval(%arg0: index)1429func.func @min.oneval(%arg0: index) -> index {1430 %min = affine.min affine_map<()[s0] -> (s0)> ()[%arg0]1431 // CHECK: return %arg0 : index1432 return %min: index1433}1434 1435// -----1436// CHECK-LABEL: func @max.oneval(%arg0: index)1437func.func @max.oneval(%arg0: index) -> index {1438 %max = affine.max affine_map<()[s0] -> (s0)> ()[%arg0]1439 // CHECK: return %arg0 : index1440 return %max: index1441}1442 1443// -----1444 1445// CHECK-LABEL: func @mod_of_mod(1446// CHECK: %[[c0:.*]] = arith.constant 01447// CHECK: return %[[c0]], %[[c0]]1448func.func @mod_of_mod(%lb: index, %ub: index, %step: index) -> (index, index) {1449 // Simplify: (ub - ub % step) % step == 01450 %0 = affine.apply affine_map<()[s0, s1] -> ((s0 - (s0 mod s1)) mod s1)> ()[%ub, %step]1451 // Simplify: (ub - (ub - lb) % step - lb) % step == 01452 %1 = affine.apply affine_map<()[s0, s1, s2] -> ((s0 - ((s0 - s2) mod s1) - s2) mod s1)> ()[%ub, %step, %lb]1453 return %0, %1 : index, index1454}1455 1456// -----1457 1458// CHECK-LABEL: func.func @prefetch_canonicalize1459// CHECK-SAME: ([[PARAM_0_:%.+]]: memref<512xf32>) {1460func.func @prefetch_canonicalize(%arg0: memref<512xf32>) -> () {1461 // CHECK: affine.for [[I_0_:%.+]] = 0 to 8 {1462 affine.for %arg3 = 0 to 8 {1463 %1 = affine.apply affine_map<(d0) -> (d0 * 64)>(%arg3)1464 // CHECK: affine.prefetch [[PARAM_0_]][[[I_0_]] * 64], read, locality<3>, data : memref<512xf32>1465 affine.prefetch %arg0[%1], read, locality<3>, data : memref<512xf32>1466 }1467 return1468}1469 1470// -----1471 1472// CHECK-LABEL: @delinearize_fold_constant1473// CHECK-DAG: %[[C1:.+]] = arith.constant 1 : index1474// CHECK-DAG: %[[C2:.+]] = arith.constant 2 : index1475// CHECK-NOT: affine.delinearize_index1476// CHECK: return %[[C1]], %[[C1]], %[[C2]]1477func.func @delinearize_fold_constant() -> (index, index, index) {1478 %c22 = arith.constant 22 : index1479 %0:3 = affine.delinearize_index %c22 into (2, 3, 5) : index, index, index1480 return %0#0, %0#1, %0#2 : index, index, index1481}1482 1483// -----1484 1485// CHECK-LABEL: @delinearize_fold_negative_constant1486// CHECK-DAG: %[[C_2:.+]] = arith.constant -2 : index1487// CHECK-DAG: %[[C1:.+]] = arith.constant 1 : index1488// CHECK-DAG: %[[C3:.+]] = arith.constant 3 : index1489// CHECK-NOT: affine.delinearize_index1490// CHECK: return %[[C_2]], %[[C1]], %[[C3]]1491func.func @delinearize_fold_negative_constant() -> (index, index, index) {1492 %c_22 = arith.constant -22 : index1493 %0:3 = affine.delinearize_index %c_22 into (2, 3, 5) : index, index, index1494 return %0#0, %0#1, %0#2 : index, index, index1495}1496 1497// -----1498 1499// CHECK-LABEL: @delinearize_fold_negative_constant_no_outer_bound1500// CHECK-DAG: %[[C_2:.+]] = arith.constant -2 : index1501// CHECK-DAG: %[[C1:.+]] = arith.constant 1 : index1502// CHECK-DAG: %[[C3:.+]] = arith.constant 3 : index1503// CHECK-NOT: affine.delinearize_index1504// CHECK: return %[[C_2]], %[[C1]], %[[C3]]1505func.func @delinearize_fold_negative_constant_no_outer_bound() -> (index, index, index) {1506 %c_22 = arith.constant -22 : index1507 %0:3 = affine.delinearize_index %c_22 into (3, 5) : index, index, index1508 return %0#0, %0#1, %0#2 : index, index, index1509}1510 1511// -----1512 1513// CHECK-LABEL: @delinearize_dont_fold_constant_dynamic_basis1514// CHECK-DAG: %[[C22:.+]] = arith.constant 22 : index1515// CHECK: %[[RET:.+]]:3 = affine.delinearize_index %[[C22]]1516// CHECK: return %[[RET]]#0, %[[RET]]#1, %[[RET]]#21517func.func @delinearize_dont_fold_constant_dynamic_basis(%arg0: index) -> (index, index, index) {1518 %c22 = arith.constant 22 : index1519 %0:3 = affine.delinearize_index %c22 into (2, %arg0, 5) : index, index, index1520 return %0#0, %0#1, %0#2 : index, index, index1521}1522 1523// -----1524 1525func.func @drop_unit_basis_in_delinearize(%arg0 : index, %arg1 : index, %arg2 : index) ->1526 (index, index, index, index, index, index) {1527 %c1 = arith.constant 1 : index1528 %0:6 = affine.delinearize_index %arg0 into (1, %arg1, 1, 1, %arg2, %c1)1529 : index, index, index, index, index, index1530 return %0#0, %0#1, %0#2, %0#3, %0#4, %0#5 : index, index, index, index, index, index1531}1532// CHECK-LABEL: func @drop_unit_basis_in_delinearize(1533// CHECK-SAME: %[[ARG0:[a-zA-Z0-9]+]]: index,1534// CHECK-SAME: %[[ARG1:[a-zA-Z0-9]+]]: index,1535// CHECK-SAME: %[[ARG2:[a-zA-Z0-9]+]]: index)1536// CHECK-DAG: %[[C0:.+]] = arith.constant 0 : index1537// CHECK-DAG: %[[DELINEARIZE:.+]]:2 = affine.delinearize_index %[[ARG0]] into (%[[ARG1]], %[[ARG2]])1538// CHECK: return %[[C0]], %[[DELINEARIZE]]#0, %[[C0]], %[[C0]], %[[DELINEARIZE]]#1, %[[C0]]1539 1540// -----1541 1542func.func @drop_unit_basis_in_delinearize_no_outer_bound(%arg0 : index, %arg1 : index, %arg2 : index) ->1543 (index, index, index, index, index, index) {1544 %c1 = arith.constant 1 : index1545 %0:6 = affine.delinearize_index %arg0 into (%arg1, 1, 1, %arg2, %c1)1546 : index, index, index, index, index, index1547 return %0#0, %0#1, %0#2, %0#3, %0#4, %0#5 : index, index, index, index, index, index1548}1549// CHECK-LABEL: func @drop_unit_basis_in_delinearize_no_outer_bound(1550// CHECK-SAME: %[[ARG0:[a-zA-Z0-9]+]]: index,1551// CHECK-SAME: %[[ARG1:[a-zA-Z0-9]+]]: index,1552// CHECK-SAME: %[[ARG2:[a-zA-Z0-9]+]]: index)1553// CHECK-DAG: %[[C0:.+]] = arith.constant 0 : index1554// CHECK-DAG: %[[DELINEARIZE:.+]]:3 = affine.delinearize_index %[[ARG0]] into (%[[ARG1]], %[[ARG2]])1555// CHECK: return %[[DELINEARIZE]]#0, %[[DELINEARIZE]]#1, %[[C0]], %[[C0]], %[[DELINEARIZE]]#2, %[[C0]]1556 1557// -----1558 1559func.func @drop_all_unit_bases(%arg0 : index) -> (index, index) {1560 %0:2 = affine.delinearize_index %arg0 into (1, 1) : index, index1561 return %0#0, %0#1 : index, index1562}1563// CHECK-LABEL: func @drop_all_unit_bases(1564// CHECK-SAME: %[[ARG0:.+]]: index)1565// CHECK-DAG: %[[C0:.+]] = arith.constant 0 : index1566// CHECK-NOT: affine.delinearize_index1567// CHECK: return %[[C0]], %[[C0]]1568 1569// -----1570 1571func.func @drop_all_unit_bases_no_outer_bound(%arg0 : index) -> (index, index, index) {1572 %0:3 = affine.delinearize_index %arg0 into (1, 1) : index, index, index1573 return %0#0, %0#1, %0#2 : index, index, index1574}1575// CHECK-LABEL: func @drop_all_unit_bases_no_outer_bound(1576// CHECK-SAME: %[[ARG0:.+]]: index)1577// CHECK-DAG: %[[C0:.+]] = arith.constant 0 : index1578// CHECK-NOT: affine.delinearize_index1579// CHECK: return %[[ARG0]], %[[C0]], %[[C0]]1580 1581// -----1582 1583func.func @drop_single_loop_delinearize(%arg0 : index, %arg1 : index) -> index {1584 %c0 = arith.constant 0 : index1585 %c1 = arith.constant 1 : index1586 %2 = scf.for %iv = %c0 to %arg1 step %c1 iter_args(%arg2 = %c0) -> index {1587 %0 = affine.delinearize_index %iv into (%arg1) : index1588 %1 = "some_use"(%arg2, %0) : (index, index) -> (index)1589 scf.yield %1 : index1590 }1591 return %2 : index1592}1593// CHECK-LABEL: func @drop_single_loop_delinearize(1594// CHECK-SAME: %[[ARG0:.+]]: index)1595// CHECK: scf.for %[[IV:[a-zA-Z0-9]+]] =1596// CHECK-NOT: affine.delinearize_index1597// CHECK: "some_use"(%{{.+}}, %[[IV]])1598 1599// -----1600 1601// CHECK-LABEL: func @delinearize_non_induction_variable1602// CHECK-NOT: affine.delinearize1603func.func @delinearize_non_induction_variable(%arg0: memref<?xi32>, %i : index, %t0 : index, %t1 : index, %t2 : index) -> index {1604 %1 = affine.apply affine_map<(d0)[s0, s1, s2] -> (d0 + s0 + s1 * 64 + s2 * 128)>(%i)[%t0, %t1, %t2]1605 %2 = affine.delinearize_index %1 into (1024) : index1606 return %2 : index1607}1608 1609// -----1610 1611// CHECK-LABEL: func @delinearize_non_loop_like1612// CHECK-NOT: affine.delinearize1613func.func @delinearize_non_loop_like(%arg0: memref<?xi32>, %i : index) -> index {1614 %2 = affine.delinearize_index %i into (1024) : index1615 return %2 : index1616}1617 1618// -----1619 1620// CHECK-LABEL: func @delinearize_empty_basis1621// CHECK-SAME: (%[[ARG0:.+]]: index)1622// CHECK-NOT: affine.delinearize1623// CHECK: return %[[ARG0]]1624func.func @delinearize_empty_basis(%arg0: index) -> index {1625 %0 = affine.delinearize_index %arg0 into () : index1626 return %0 : index1627}1628 1629// -----1630 1631// CHECK-LABEL: @linearize_fold_constants1632// CHECK-DAG: %[[C22:.+]] = arith.constant 22 : index1633// CHECK-NOT: affine.linearize1634// CHECK: return %[[C22]]1635func.func @linearize_fold_constants() -> index {1636 %c2 = arith.constant 2 : index1637 %c1 = arith.constant 1 : index1638 1639 %ret = affine.linearize_index [%c1, %c1, %c2] by (2, 3, 5) : index1640 return %ret : index1641}1642 1643// -----1644 1645// CHECK-LABEL: @linearize_fold_constants_no_outer_bound1646// CHECK-DAG: %[[C22:.+]] = arith.constant 22 : index1647// CHECK-NOT: affine.linearize1648// CHECK: return %[[C22]]1649func.func @linearize_fold_constants_no_outer_bound() -> index {1650 %c2 = arith.constant 2 : index1651 %c1 = arith.constant 1 : index1652 1653 %ret = affine.linearize_index [%c1, %c1, %c2] by (3, 5) : index1654 return %ret : index1655}1656 1657// -----1658 1659// CHECK-LABEL: @linearize_fold_empty_basis1660// CHECK-SAME: (%[[ARG0:.+]]: index)1661// CHECK-NOT: affine.linearize1662// CHECK: return %[[ARG0]]1663func.func @linearize_fold_empty_basis(%arg0: index) -> index {1664 %ret = affine.linearize_index [%arg0] by () : index1665 return %ret : index1666}1667 1668// -----1669 1670// CHECK-LABEL: @linearize_fold_only_outer_bound1671// CHECK-SAME: (%[[ARG0:.+]]: index)1672// CHECK-NOT: affine.linearize1673// CHECK: return %[[ARG0]]1674func.func @linearize_fold_only_outer_bound(%arg0: index) -> index {1675 %ret = affine.linearize_index [%arg0] by (2) : index1676 return %ret : index1677}1678 1679// -----1680 1681// CHECK-LABEL: @linearize_dont_fold_dynamic_basis1682// CHECK: %[[RET:.+]] = affine.linearize_index1683// CHECK: return %[[RET]]1684func.func @linearize_dont_fold_dynamic_basis(%arg0: index) -> index {1685 %c2 = arith.constant 2 : index1686 %c1 = arith.constant 1 : index1687 1688 %ret = affine.linearize_index [%c1, %c1, %c2] by (2, %arg0, 5) : index1689 return %ret : index1690}1691 1692// -----1693 1694// CHECK-LABEL: func @cancel_delinearize_linearize_disjoint_exact(1695// CHECK-SAME: %[[ARG0:[a-zA-Z0-9]+]]: index,1696// CHECK-SAME: %[[ARG1:[a-zA-Z0-9]+]]: index,1697// CHECK-SAME: %[[ARG2:[a-zA-Z0-9]+]]: index,1698// CHECK-SAME: %[[ARG3:[a-zA-Z0-9]+]]: index,1699// CHECK-SAME: %[[ARG4:[a-zA-Z0-9]+]]: index)1700// CHECK: return %[[ARG0]], %[[ARG1]], %[[ARG2]]1701func.func @cancel_delinearize_linearize_disjoint_exact(%arg0: index, %arg1: index, %arg2: index, %arg3: index, %arg4: index) -> (index, index, index) {1702 %0 = affine.linearize_index disjoint [%arg0, %arg1, %arg2] by (%arg3, 4, %arg4) : index1703 %1:3 = affine.delinearize_index %0 into (%arg3, 4, %arg4)1704 : index, index, index1705 return %1#0, %1#1, %1#2 : index, index, index1706}1707 1708// -----1709 1710// CHECK-LABEL: func @cancel_delinearize_linearize_disjoint_linearize_extra_bound(1711// CHECK-SAME: %[[ARG0:[a-zA-Z0-9]+]]: index,1712// CHECK-SAME: %[[ARG1:[a-zA-Z0-9]+]]: index,1713// CHECK-SAME: %[[ARG2:[a-zA-Z0-9]+]]: index,1714// CHECK-SAME: %[[ARG3:[a-zA-Z0-9]+]]: index,1715// CHECK-SAME: %[[ARG4:[a-zA-Z0-9]+]]: index)1716// CHECK: return %[[ARG0]], %[[ARG1]], %[[ARG2]]1717func.func @cancel_delinearize_linearize_disjoint_linearize_extra_bound(%arg0: index, %arg1: index, %arg2: index, %arg3: index, %arg4: index) -> (index, index, index) {1718 %0 = affine.linearize_index disjoint [%arg0, %arg1, %arg2] by (4, %arg4) : index1719 %1:3 = affine.delinearize_index %0 into (4, %arg4)1720 : index, index, index1721 return %1#0, %1#1, %1#2 : index, index, index1722}1723 1724// -----1725 1726// CHECK-LABEL: func @cancel_delinearize_linearize_disjoint_delinearize_extra_bound(1727// CHECK-SAME: %[[ARG0:[a-zA-Z0-9]+]]: index,1728// CHECK-SAME: %[[ARG1:[a-zA-Z0-9]+]]: index,1729// CHECK-SAME: %[[ARG2:[a-zA-Z0-9]+]]: index,1730// CHECK-SAME: %[[ARG3:[a-zA-Z0-9]+]]: index,1731// CHECK-SAME: %[[ARG4:[a-zA-Z0-9]+]]: index)1732// CHECK: return %[[ARG0]], %[[ARG1]], %[[ARG2]]1733func.func @cancel_delinearize_linearize_disjoint_delinearize_extra_bound(%arg0: index, %arg1: index, %arg2: index, %arg3: index, %arg4: index) -> (index, index, index) {1734 %0 = affine.linearize_index disjoint [%arg0, %arg1, %arg2] by (4, %arg4) : index1735 %1:3 = affine.delinearize_index %0 into (%arg3, 4, %arg4)1736 : index, index, index1737 return %1#0, %1#1, %1#2 : index, index, index1738}1739 1740// -----1741 1742// CHECK-LABEL: func @cancel_delinearize_linearize_disjoint_partial(1743// CHECK-SAME: %[[ARG0:[a-zA-Z0-9]+]]: index,1744// CHECK-SAME: %[[ARG1:[a-zA-Z0-9]+]]: index,1745// CHECK-SAME: %[[ARG2:[a-zA-Z0-9]+]]: index,1746// CHECK-SAME: %[[ARG3:[a-zA-Z0-9]+]]: index,1747// CHECK-SAME: %[[ARG4:[a-zA-Z0-9]+]]: index)1748// CHECK: %[[LIN:.+]] = affine.linearize_index disjoint [%[[ARG0]], %[[ARG1]]] by (%[[ARG3]], 4) : index1749// CHECK: %[[DELIN:.+]]:2 = affine.delinearize_index %[[LIN]] into (8) : index, index1750// CHECK: return %[[DELIN]]#0, %[[DELIN]]#1, %[[ARG2]]1751func.func @cancel_delinearize_linearize_disjoint_partial(%arg0: index, %arg1: index, %arg2: index, %arg3: index, %arg4: index) -> (index, index, index) {1752 %0 = affine.linearize_index disjoint [%arg0, %arg1, %arg2] by (%arg3, 4, %arg4) : index1753 %1:3 = affine.delinearize_index %0 into (8, %arg4)1754 : index, index, index1755 return %1#0, %1#1, %1#2 : index, index, index1756}1757 1758// -----1759 1760// Without `disjoint`, the cancelation isn't guaranteed to be the identity.1761// CHECK-LABEL: func @no_cancel_delinearize_linearize_exact(1762// CHECK-SAME: %[[ARG0:[a-zA-Z0-9]+]]: index,1763// CHECK-SAME: %[[ARG1:[a-zA-Z0-9]+]]: index,1764// CHECK-SAME: %[[ARG2:[a-zA-Z0-9]+]]: index,1765// CHECK-SAME: %[[ARG3:[a-zA-Z0-9]+]]: index,1766// CHECK-SAME: %[[ARG4:[a-zA-Z0-9]+]]: index)1767// CHECK: %[[LIN:.+]] = affine.linearize_index [%[[ARG0]], %[[ARG1]], %[[ARG2]]] by (%[[ARG3]], 4, %[[ARG4]])1768// CHECK: %[[DELIN:.+]]:3 = affine.delinearize_index %[[LIN]] into (%[[ARG3]], 4, %[[ARG4]])1769// CHECK: return %[[DELIN]]#0, %[[DELIN]]#1, %[[DELIN]]#21770func.func @no_cancel_delinearize_linearize_exact(%arg0: index, %arg1: index, %arg2: index, %arg3: index, %arg4: index) -> (index, index, index) {1771 %0 = affine.linearize_index [%arg0, %arg1, %arg2] by (%arg3, 4, %arg4) : index1772 %1:3 = affine.delinearize_index %0 into (%arg3, 4, %arg4)1773 : index, index, index1774 return %1#0, %1#1, %1#2 : index, index, index1775}1776 1777// -----1778 1779// These don't cancel because the delinearize and linearize have a different basis.1780// CHECK-LABEL: func @no_cancel_delinearize_linearize_different_basis(1781// CHECK-SAME: %[[ARG0:[a-zA-Z0-9]+]]: index,1782// CHECK-SAME: %[[ARG1:[a-zA-Z0-9]+]]: index,1783// CHECK-SAME: %[[ARG2:[a-zA-Z0-9]+]]: index,1784// CHECK-SAME: %[[ARG3:[a-zA-Z0-9]+]]: index,1785// CHECK-SAME: %[[ARG4:[a-zA-Z0-9]+]]: index)1786// CHECK: %[[LIN:.+]] = affine.linearize_index [%[[ARG0]], %[[ARG1]], %[[ARG2]]] by (%[[ARG3]], 4, %[[ARG4]])1787// CHECK: %[[DELIN:.+]]:3 = affine.delinearize_index %[[LIN]] into (%[[ARG3]], 8, %[[ARG4]])1788// CHECK: return %[[DELIN]]#0, %[[DELIN]]#1, %[[DELIN]]#21789func.func @no_cancel_delinearize_linearize_different_basis(%arg0: index, %arg1: index, %arg2: index, %arg3: index, %arg4: index) -> (index, index, index) {1790 %0 = affine.linearize_index [%arg0, %arg1, %arg2] by (%arg3, 4, %arg4) : index1791 %1:3 = affine.delinearize_index %0 into (%arg3, 8, %arg4)1792 : index, index, index1793 return %1#0, %1#1, %1#2 : index, index, index1794}1795 1796// -----1797 1798// CHECK-LABEL: func @split_delinearize_spanning_final_part1799// CHECK-SAME: %[[ARG0:[a-zA-Z0-9]+]]: index,1800// CHECK-SAME: %[[ARG1:[a-zA-Z0-9]+]]: index,1801// CHECK-SAME: %[[ARG2:[a-zA-Z0-9]+]]: index)1802// CHECK: %[[LIN:.+]] = affine.linearize_index disjoint [%[[ARG0]], %[[ARG1]]] by (2, 4)1803// CHECK: %[[DELIN1:.+]]:2 = affine.delinearize_index %[[LIN]] into (2)1804// CHECK: %[[DELIN2:.+]]:2 = affine.delinearize_index %[[ARG2]] into (8, 8)1805// CHECK: return %[[DELIN1]]#0, %[[DELIN1]]#1, %[[DELIN2]]#0, %[[DELIN2]]#11806func.func @split_delinearize_spanning_final_part(%arg0: index, %arg1: index, %arg2: index) -> (index, index, index, index) {1807 %0 = affine.linearize_index disjoint [%arg0, %arg1, %arg2] by (2, 4, 64) : index1808 %1:4 = affine.delinearize_index %0 into (2, 8, 8)1809 : index, index, index, index1810 return %1#0, %1#1, %1#2, %1#3 : index, index, index, index1811}1812 1813// -----1814 1815// CHECK-LABEL: func @split_delinearize_spanning_final_part_and_cancel1816// CHECK-SAME: %[[ARG0:[a-zA-Z0-9]+]]: index,1817// CHECK-SAME: %[[ARG1:[a-zA-Z0-9]+]]: index,1818// CHECK-SAME: %[[ARG2:[a-zA-Z0-9]+]]: index)1819// CHECK: %[[DELIN:.+]]:2 = affine.delinearize_index %[[ARG2]] into (8, 8)1820// CHECK: return %[[ARG0]], %[[ARG1]], %[[DELIN]]#0, %[[DELIN]]#11821func.func @split_delinearize_spanning_final_part_and_cancel(%arg0: index, %arg1: index, %arg2: index) -> (index, index, index, index) {1822 %0 = affine.linearize_index disjoint [%arg0, %arg1, %arg2] by (2, 4, 64) : index1823 %1:4 = affine.delinearize_index %0 into (2, 4, 8, 8)1824 : index, index, index, index1825 return %1#0, %1#1, %1#2, %1#3 : index, index, index, index1826}1827 1828// -----1829 1830// The delinearize basis doesn't match the last basis element before1831// overshooting it, don't simplify.1832// CHECK-LABEL: func @dont_split_delinearize_overshooting_target1833// CHECK-SAME: %[[ARG0:[a-zA-Z0-9]+]]: index,1834// CHECK-SAME: %[[ARG1:[a-zA-Z0-9]+]]: index,1835// CHECK-SAME: %[[ARG2:[a-zA-Z0-9]+]]: index)1836// CHECK: %[[LIN:.+]] = affine.linearize_index disjoint [%[[ARG0]], %[[ARG1]], %[[ARG2]]] by (2, 4, 64)1837// CHECK: %[[DELIN:.+]]:4 = affine.delinearize_index %[[LIN]] into (2, 16, 8)1838// CHECK: return %[[DELIN]]#0, %[[DELIN]]#1, %[[DELIN]]#2, %[[DELIN]]#31839func.func @dont_split_delinearize_overshooting_target(%arg0: index, %arg1: index, %arg2: index) -> (index, index, index, index) {1840 %0 = affine.linearize_index disjoint [%arg0, %arg1, %arg2] by (2, 4, 64) : index1841 %1:4 = affine.delinearize_index %0 into (2, 16, 8)1842 : index, index, index, index1843 return %1#0, %1#1, %1#2, %1#3 : index, index, index, index1844}1845 1846// -----1847 1848// The delinearize basis doesn't fully multiply to the final basis element.1849// CHECK-LABEL: func @dont_split_delinearize_undershooting_target1850// CHECK-SAME: %[[ARG0:[a-zA-Z0-9]+]]: index,1851// CHECK-SAME: %[[ARG1:[a-zA-Z0-9]+]]: index)1852// CHECK: %[[LIN:.+]] = affine.linearize_index disjoint [%[[ARG0]], %[[ARG1]]] by (2, 64)1853// CHECK: %[[DELIN:.+]]:3 = affine.delinearize_index %[[LIN]] into (4, 8)1854// CHECK: return %[[DELIN]]#0, %[[DELIN]]#11855func.func @dont_split_delinearize_undershooting_target(%arg0: index, %arg1: index) -> (index, index, index) {1856 %0 = affine.linearize_index disjoint [%arg0, %arg1] by (2, 64) : index1857 %1:3 = affine.delinearize_index %0 into (4, 8)1858 : index, index, index1859 return %1#0, %1#1, %1#2 : index, index, index1860}1861 1862// -----1863 1864// CHECK-LABEL: @linearize_unit_basis_disjoint1865// CHECK-SAME: (%[[arg0:.+]]: index, %[[arg1:.+]]: index, %[[arg2:.+]]: index, %[[arg3:.+]]: index)1866// CHECK: %[[ret:.+]] = affine.linearize_index disjoint [%[[arg0]], %[[arg2]]] by (3, %[[arg3]]) : index1867// CHECK: return %[[ret]]1868func.func @linearize_unit_basis_disjoint(%arg0: index, %arg1: index, %arg2: index, %arg3: index) -> index {1869 %ret = affine.linearize_index disjoint [%arg0, %arg1, %arg2] by (3, 1, %arg3) : index1870 return %ret : index1871}1872 1873// -----1874 1875// CHECK-LABEL: @linearize_unit_basis_disjoint_no_outer_bound1876// CHECK-SAME: (%[[arg0:.+]]: index, %[[arg1:.+]]: index, %[[arg2:.+]]: index, %[[arg3:.+]]: index)1877// CHECK: %[[ret:.+]] = affine.linearize_index disjoint [%[[arg0]], %[[arg2]]] by (%[[arg3]]) : index1878// CHECK: return %[[ret]]1879func.func @linearize_unit_basis_disjoint_no_outer_bound(%arg0: index, %arg1: index, %arg2: index, %arg3: index) -> index {1880 %ret = affine.linearize_index disjoint [%arg0, %arg1, %arg2] by (1, %arg3) : index1881 return %ret : index1882}1883 1884// -----1885 1886// CHECK-LABEL: @linearize_unit_basis_zero1887// CHECK-SAME: (%[[arg0:.+]]: index, %[[arg1:.+]]: index, %[[arg2:.+]]: index)1888// CHECK: %[[ret:.+]] = affine.linearize_index [%[[arg0]], %[[arg1]]] by (3, %[[arg2]]) : index1889// CHECK: return %[[ret]]1890func.func @linearize_unit_basis_zero(%arg0: index, %arg1: index, %arg2: index) -> index {1891 %c0 = arith.constant 0 : index1892 %ret = affine.linearize_index [%arg0, %c0, %arg1] by (3, 1, %arg2) : index1893 return %ret : index1894}1895 1896// -----1897 1898// CHECK-LABEL: @linearize_all_zero_unit_basis1899// CHECK: arith.constant 0 : index1900// CHECK-NOT: affine.linearize_index1901func.func @linearize_all_zero_unit_basis() -> index {1902 %c0 = arith.constant 0 : index1903 %ret = affine.linearize_index [%c0, %c0] by (1, 1) : index1904 return %ret : index1905}1906 1907// -----1908 1909// CHECK-LABEL: @linearize_one_element_basis1910// CHECK-SAME: (%[[arg0:.+]]: index, %[[arg1:.+]]: index)1911// CHECK-NOT: affine.linearize_index1912// CHECK: return %[[arg0]]1913func.func @linearize_one_element_basis(%arg0: index, %arg1: index) -> index {1914 %ret = affine.linearize_index [%arg0] by (%arg1) : index1915 return %ret : index1916}1917 1918// -----1919 1920// CHECK-LABEL: func @cancel_linearize_delinearize_exact(1921// CHECK-SAME: %[[ARG0:[a-zA-Z0-9]+]]: index,1922// CHECK-SAME: %[[ARG1:[a-zA-Z0-9]+]]: index,1923// CHECK-SAME: %[[ARG2:[a-zA-Z0-9]+]]: index)1924// CHECK: return %[[ARG0]]1925func.func @cancel_linearize_delinearize_exact(%arg0: index, %arg1: index, %arg2: index) -> index {1926 %0:3 = affine.delinearize_index %arg0 into (%arg1, 4, %arg2) : index, index, index1927 %1 = affine.linearize_index [%0#0, %0#1, %0#2] by (%arg1, 4, %arg2) : index1928 return %1 : index1929}1930 1931// -----1932 1933// CHECK-LABEL: func @cancel_linearize_delinearize_linearize_extra_bound(1934// CHECK-SAME: %[[ARG0:[a-zA-Z0-9]+]]: index,1935// CHECK-SAME: %[[ARG1:[a-zA-Z0-9]+]]: index,1936// CHECK-SAME: %[[ARG2:[a-zA-Z0-9]+]]: index)1937// CHECK: return %[[ARG0]]1938func.func @cancel_linearize_delinearize_linearize_extra_bound(%arg0: index, %arg1: index, %arg2: index) -> index {1939 %0:3 = affine.delinearize_index %arg0 into (4, %arg2) : index, index, index1940 %1 = affine.linearize_index [%0#0, %0#1, %0#2] by (%arg1, 4, %arg2) : index1941 return %1 : index1942}1943 1944// -----1945 1946// CHECK-LABEL: func @cancel_linearize_delinearize_delinearize_extra_bound(1947// CHECK-SAME: %[[ARG0:[a-zA-Z0-9]+]]: index,1948// CHECK-SAME: %[[ARG1:[a-zA-Z0-9]+]]: index,1949// CHECK-SAME: %[[ARG2:[a-zA-Z0-9]+]]: index)1950// CHECK: return %[[ARG0]]1951func.func @cancel_linearize_delinearize_delinearize_extra_bound(%arg0: index, %arg1: index, %arg2: index) -> index {1952 %0:3 = affine.delinearize_index %arg0 into (%arg1, 4, %arg2) : index, index, index1953 %1 = affine.linearize_index [%0#0, %0#1, %0#2] by (4, %arg2) : index1954 return %1 : index1955}1956 1957// -----1958 1959// CHECK-LABEL: func @cancel_linearize_delinearize_head(1960// CHECK-SAME: %[[ARG0:[a-zA-Z0-9]+]]: index,1961// CHECK-SAME: %[[ARG1:[a-zA-Z0-9]+]]: index)1962// CHECK: %[[DELIN:.+]]:2 = affine.delinearize_index %[[ARG0]] into (12, 8)1963// CHECK: %[[LIN:.+]] = affine.linearize_index [%[[DELIN]]#0, %[[ARG1]]] by (12, 16)1964// CHECK: return %[[LIN]]1965func.func @cancel_linearize_delinearize_head(%arg0: index, %arg1: index) -> index {1966 %0:3 = affine.delinearize_index %arg0 into (3, 4, 8) : index, index, index1967 %1 = affine.linearize_index [%0#0, %0#1, %arg1] by (3, 4, 16) : index1968 return %1 : index1969}1970 1971// -----1972 1973// CHECK-LABEL: func @cancel_linearize_delinearize_head_delinearize_unbounded(1974// CHECK-SAME: %[[ARG0:[a-zA-Z0-9]+]]: index,1975// CHECK-SAME: %[[ARG1:[a-zA-Z0-9]+]]: index)1976// CHECK: %[[DELIN:.+]]:2 = affine.delinearize_index %[[ARG0]] into (12, 8)1977// CHECK: %[[LIN:.+]] = affine.linearize_index [%[[DELIN]]#0, %[[ARG1]]] by (12, 16)1978// CHECK: return %[[LIN]]1979func.func @cancel_linearize_delinearize_head_delinearize_unbounded(%arg0: index, %arg1: index) -> index {1980 %0:3 = affine.delinearize_index %arg0 into (4, 8) : index, index, index1981 %1 = affine.linearize_index [%0#0, %0#1, %arg1] by (3, 4, 16) : index1982 return %1 : index1983}1984 1985// -----1986 1987// CHECK-LABEL: func @cancel_linearize_delinearize_head_linearize_unbounded(1988// CHECK-SAME: %[[ARG0:[a-zA-Z0-9]+]]: index,1989// CHECK-SAME: %[[ARG1:[a-zA-Z0-9]+]]: index)1990// CHECK: %[[DELIN:.+]]:2 = affine.delinearize_index %[[ARG0]] into (8)1991// CHECK: %[[LIN:.+]] = affine.linearize_index [%[[DELIN]]#0, %[[ARG1]]] by (16)1992// CHECK: return %[[LIN]]1993func.func @cancel_linearize_delinearize_head_linearize_unbounded(%arg0: index, %arg1: index) -> index {1994 %0:3 = affine.delinearize_index %arg0 into (3, 4, 8) : index, index, index1995 %1 = affine.linearize_index [%0#0, %0#1, %arg1] by (4, 16) : index1996 return %1 : index1997}1998 1999// -----2000 2001// CHECK-LABEL: func @cancel_linearize_delinearize_head_both_unbounded(2002// CHECK-SAME: %[[ARG0:[a-zA-Z0-9]+]]: index,2003// CHECK-SAME: %[[ARG1:[a-zA-Z0-9]+]]: index)2004// CHECK: %[[DELIN:.+]]:2 = affine.delinearize_index %[[ARG0]] into (8)2005// CHECK: %[[LIN:.+]] = affine.linearize_index [%[[DELIN]]#0, %[[ARG1]]] by (16)2006// CHECK: return %[[LIN]]2007func.func @cancel_linearize_delinearize_head_both_unbounded(%arg0: index, %arg1: index) -> index {2008 %0:3 = affine.delinearize_index %arg0 into (4, 8) : index, index, index2009 %1 = affine.linearize_index [%0#0, %0#1, %arg1] by (4, 16) : index2010 return %1 : index2011}2012 2013// -----2014 2015// CHECK-LABEL: func @cancel_linearize_delinearize_tail(2016// CHECK-SAME: %[[ARG0:[a-zA-Z0-9]+]]: index,2017// CHECK-SAME: %[[ARG1:[a-zA-Z0-9]+]]: index)2018// CHECK: %[[DELIN:.+]]:2 = affine.delinearize_index %[[ARG0]] into (3, 32)2019// CHECK: %[[LIN:.+]] = affine.linearize_index [%[[ARG1]], %[[DELIN]]#1] by (5, 32)2020// CHECK: return %[[LIN]]2021func.func @cancel_linearize_delinearize_tail(%arg0: index, %arg1: index) -> index {2022 %0:3 = affine.delinearize_index %arg0 into (3, 4, 8) : index, index, index2023 %1 = affine.linearize_index [%arg1, %0#1, %0#2] by (5, 4, 8) : index2024 return %1 : index2025}2026 2027// -----2028 2029// CHECK-LABEL: func @cancel_linearize_delinearize_middle_exact(2030// CHECK-SAME: %[[ARG0:[a-zA-Z0-9]+]]: index,2031// CHECK-SAME: %[[ARG1:[a-zA-Z0-9]+]]: index,2032// CHECK-SAME: %[[ARG2:[a-zA-z0-9]+]]: index)2033// CHECK: %[[LIN:.+]] = affine.linearize_index [%[[ARG1]], %[[ARG0]], %[[ARG2]]] by (9, 30, 7)2034// CHECK: return %[[LIN]]2035func.func @cancel_linearize_delinearize_middle_exact(%arg0: index, %arg1: index, %arg2: index) -> index {2036 %0:3 = affine.delinearize_index %arg0 into (2, 3, 5) : index, index, index2037 %1 = affine.linearize_index [%arg1, %0#0, %0#1, %0#2, %arg2] by (9, 2, 3, 5, 7) : index2038 return %1 : index2039}2040 2041// -----2042 2043// CHECK: #[[$MAP:.+]] = affine_map<()[s0, s1] -> ((s0 * s1) * 16)>2044 2045// CHECK-LABEL: func @cancel_linearize_delinearize_middle_exact_dynamic_basis(2046// CHECK-SAME: %[[ARG0:[a-zA-Z0-9]+]]: index,2047// CHECK-SAME: %[[ARG1:[a-zA-Z0-9]+]]: index,2048// CHECK-SAME: %[[ARG2:[a-zA-z0-9]+]]: index)2049// CHECK: %[[C1:.+]] = arith.constant 1 : index2050// CHECK: %[[SIZEPROD:.+]] = affine.apply #[[$MAP]]()[%[[ARG1]], %[[ARG2]]]2051// CHECK: %[[LIN:.+]] = affine.linearize_index [%[[C1]], %[[ARG0]], %[[C1]]] by (3, %[[SIZEPROD]], 4)2052// CHECK: return %[[LIN]]2053func.func @cancel_linearize_delinearize_middle_exact_dynamic_basis(%arg0: index, %arg1: index, %arg2: index) -> index {2054 %c1 = arith.constant 1 : index2055 %0:4 = affine.delinearize_index %arg0 into (2, %arg1, %arg2, 8) : index, index, index, index2056 %1 = affine.linearize_index [%c1, %0#0, %0#1, %0#2, %0#3, %c1] by (3, 2, %arg1, %arg2, 8, 4) : index2057 return %1 : index2058}2059 2060// -----2061 2062// CHECK-LABEL: func @cancel_linearize_delinearize_middle_exact_delinearize_unbounded_disjoint(2063// CHECK-SAME: %[[ARG0:[a-zA-Z0-9]+]]: index,2064// CHECK-SAME: %[[ARG1:[a-zA-Z0-9]+]]: index,2065// CHECK-SAME: %[[ARG2:[a-zA-z0-9]+]]: index)2066// CHECK: %[[LIN:.+]] = affine.linearize_index disjoint [%[[ARG1]], %[[ARG0]], %[[ARG2]]] by (9, 30, 7)2067// CHECK: return %[[LIN]]2068func.func @cancel_linearize_delinearize_middle_exact_delinearize_unbounded_disjoint(%arg0: index, %arg1: index, %arg2: index) -> index {2069 %0:3 = affine.delinearize_index %arg0 into (3, 5) : index, index, index2070 %1 = affine.linearize_index disjoint [%arg1, %0#0, %0#1, %0#2, %arg2] by (9, 2, 3, 5, 7) : index2071 return %1 : index2072}2073 2074// -----2075 2076// Unlike in the test above, the linerize indices aren't asserted to be disjoint, so2077// we can't know if the `2` from the basis is a correct bound.2078// CHECK-LABEL: func @dont_cancel_linearize_delinearize_middle_exact_delinearize_unbounded(2079// CHECK-SAME: %[[ARG0:[a-zA-Z0-9]+]]: index,2080// CHECK-SAME: %[[ARG1:[a-zA-Z0-9]+]]: index,2081// CHECK-SAME: %[[ARG2:[a-zA-z0-9]+]]: index)2082// CHECK: %[[DELIN:.+]]:2 = affine.delinearize_index %[[ARG0]] into (3)2083// CHECK: %[[LIN:.+]] = affine.linearize_index [%[[ARG1]], %[[DELIN]]#0, %[[DELIN]]#1, %[[ARG2]]] by (9, 2, 3, 7)2084// CHECK: return %[[LIN]]2085 2086func.func @dont_cancel_linearize_delinearize_middle_exact_delinearize_unbounded(%arg0: index, %arg1: index, %arg2: index) -> index {2087 %0:2 = affine.delinearize_index %arg0 into (3) : index, index2088 %1 = affine.linearize_index [%arg1, %0#0, %0#1, %arg2] by (9, 2, 3, 7) : index2089 return %1 : index2090}2091 2092// -----2093 2094// The presence of a `disjoint` here tells us that the "unbounded" term on the2095// delinearization can't have been above 2.2096// CHECK-LABEL: func @cancel_linearize_delinearize_middle_delinearize_unbounded_disjoint_implied_bound(2097// CHECK-SAME: %[[ARG0:[a-zA-Z0-9]+]]: index,2098// CHECK-SAME: %[[ARG1:[a-zA-Z0-9]+]]: index,2099// CHECK-SAME: %[[ARG2:[a-zA-z0-9]+]]: index)2100// CHECK: %[[DELIN:.+]]:2 = affine.delinearize_index %[[ARG0]] into (6, 5)2101// CHECK: %[[LIN:.+]] = affine.linearize_index disjoint [%[[ARG1]], %[[DELIN]]#0, %[[ARG2]]] by (9, 6, 7)2102// CHECK: return %[[LIN]]2103func.func @cancel_linearize_delinearize_middle_delinearize_unbounded_disjoint_implied_bound(%arg0: index, %arg1: index, %arg2: index) -> index {2104 %0:3 = affine.delinearize_index %arg0 into (3, 5) : index, index, index2105 %1 = affine.linearize_index disjoint [%arg1, %0#0, %0#1, %arg2] by (9, 2, 3, 7) : index2106 return %1 : index2107}2108 2109// -----2110 2111// CHECK-LABEL: func @cancel_linearize_delinearize_multiple_matches(2112// CHECK-SAME: %[[ARG0:[a-zA-Z0-9]+]]: index,2113// CHECK-SAME: %[[ARG1:[a-zA-Z0-9]+]]: index)2114// CHECK: %[[C0:.+]] = arith.constant 02115// CHECK: %[[DELIN:.+]]:4 = affine.delinearize_index %[[ARG0]] into (4, 16, 4, 64)2116// CHECK: %[[LIN:.+]] = affine.linearize_index [%[[ARG1]], %[[DELIN]]#1, %[[C0]], %[[DELIN]]#3] by (4, 16, 4, 64)2117// CHECK: return %[[LIN]]2118func.func @cancel_linearize_delinearize_multiple_matches(%arg0: index, %arg1: index) -> index {2119 %c0 = arith.constant 0 : index2120 %0:7 = affine.delinearize_index %arg0 into (4, 4, 4, 4, 4, 4, 4) : index, index, index, index, index, index, index2121 %1 = affine.linearize_index [%arg1, %0#1, %0#2, %c0, %0#4, %0#5, %0#6] by (4, 4, 4, 4, 4, 4, 4) : index2122 return %1 : index2123}2124 2125// -----2126 2127// CHECK-LABEL: func @cancel_linearize_delinearize_multiple_delinearizes(2128// CHECK-SAME: %[[ARG0:[a-zA-Z0-9]+]]: index,2129// CHECK-SAME: %[[ARG1:[a-zA-Z0-9]+]]: index)2130// CHECK: %[[LIN:.+]] = affine.linearize_index [%[[ARG0]], %[[ARG1]]] by (32, 32)2131// CHECK: return %[[LIN]]2132func.func @cancel_linearize_delinearize_multiple_delinearizes(%arg0: index, %arg1: index) -> index {2133 %0:2 = affine.delinearize_index %arg0 into (4, 8) : index, index2134 %1:2 = affine.delinearize_index %arg1 into (2, 16) : index, index2135 %2 = affine.linearize_index [%0#0, %0#1, %1#0, %1#1] by (4, 8, 2, 16) : index2136 return %2 : index2137}2138 2139// -----2140 2141// Don't cancel because the values from the delinearize aren't used in order2142// CHECK-LABEL: func @no_cancel_linearize_delinearize_permuted(2143// CHECK-SAME: %[[ARG0:[a-zA-Z0-9]+]]: index,2144// CHECK-SAME: %[[ARG1:[a-zA-Z0-9]+]]: index,2145// CHECK-SAME: %[[ARG2:[a-zA-Z0-9]+]]: index)2146// CHECK: %[[DELIN:.+]]:3 = affine.delinearize_index %[[ARG0]] into (%[[ARG1]], 4, %[[ARG2]])2147// CHECK: %[[LIN:.+]] = affine.linearize_index [%[[DELIN]]#0, %[[DELIN]]#2, %[[DELIN]]#1] by (%[[ARG1]], %[[ARG2]], 4)2148// CHECK: return %[[LIN]]2149func.func @no_cancel_linearize_delinearize_permuted(%arg0: index, %arg1: index, %arg2: index) -> index {2150 %0:3 = affine.delinearize_index %arg0 into (%arg1, 4, %arg2) : index, index, index2151 %1 = affine.linearize_index [%0#0, %0#2, %0#1] by (%arg1, %arg2, 4) : index2152 return %1 : index2153}2154 2155// -----2156 2157// CHECK: #[[$MAP:.+]] = affine_map<()[s0] -> (s0 * 3)>2158// But these cancel because they're a contiguous segment2159// CHECK-LABEL: func @partial_cancel_linearize_delinearize_not_fully_permuted(2160// CHECK-SAME: %[[ARG0:[a-zA-Z0-9]+]]: index,2161// CHECK-SAME: %[[ARG1:[a-zA-Z0-9]+]]: index,2162// CHECK-SAME: %[[ARG2:[a-zA-Z0-9]+]]: index)2163// CHECK: %[[SIZEPROD:.+]] = affine.apply #[[$MAP]]()[%[[ARG2]]]2164// CHECK: %[[DELIN:.+]]:3 = affine.delinearize_index %[[ARG0]] into (%[[ARG1]], 4, %[[SIZEPROD]])2165// CHECK: %[[LIN:.+]] = affine.linearize_index [%[[DELIN]]#0, %[[DELIN]]#2, %[[DELIN]]#1] by (%[[ARG1]], %[[SIZEPROD]], 4)2166// CHECK: return %[[LIN]]2167func.func @partial_cancel_linearize_delinearize_not_fully_permuted(%arg0: index, %arg1: index, %arg2: index) -> index {2168 %0:4 = affine.delinearize_index %arg0 into (%arg1, 4, %arg2, 3) : index, index, index, index2169 %1 = affine.linearize_index [%0#0, %0#2, %0#3, %0#1] by (%arg1, %arg2, 3, 4) : index2170 return %1 : index2171}2172 2173// -----2174 2175// Ensure we don't get SSA errors when creating new `affine.delinearize` operations.2176// CHECK-LABEL: func @cancel_linearize_delinearize_placement2177// CHECK-SAME: (%[[ARG0:.+]]: index)2178// CHECK: %[[C0:.+]] = arith.constant 0 : index2179// CHECK: %[[NEW_DELIN:.+]]:2 = affine.delinearize_index %[[ARG0]] into (8, 32) : index, index2180// CHECK-NEXT: %[[DELIN_PART:.+]]:2 = affine.delinearize_index %[[NEW_DELIN]]#1 into (8, 4) : index, index2181// CHECK-NEXT: %[[L1:.+]] = affine.linearize_index disjoint [%[[DELIN_PART]]#1, %[[NEW_DELIN]]#0, %[[C0]], %[[C0]]] by (4, 8, 4, 8)2182// CHECK-NEXT: %[[L2:.+]] = affine.linearize_index disjoint [%[[NEW_DELIN]]#1, %[[C0]], %[[C0]]] by (32, 8, 4)2183// CHECK-NEXT: %[[L3:.+]] = affine.linearize_index disjoint [%[[DELIN_PART]]#0, %[[NEW_DELIN]]#0, %[[C0]], %[[C0]]] by (8, 8, 4, 4)2184// CHECK-NEXT: return %[[L1]], %[[L2]], %[[L3]]2185func.func @cancel_linearize_delinearize_placement(%arg0: index) -> (index, index, index) {2186 %c0 = arith.constant 0 : index2187 %0:3 = affine.delinearize_index %arg0 into (8, 8, 4) : index, index, index2188 %1 = affine.linearize_index disjoint [%0#2, %0#0, %c0, %c0] by (4, 8, 4, 8) : index2189 %2 = affine.linearize_index disjoint [%0#1, %0#2, %c0, %c0] by (8, 4, 8, 4) : index2190 %3 = affine.linearize_index disjoint [%0#1, %0#0, %c0, %c0] by (8, 8, 4, 4) : index2191 return %1, %2, %3 : index, index, index2192}2193 2194// -----2195 2196// Won't cancel because the linearize and delinearize are using a different basis2197// CHECK-LABEL: func @no_cancel_linearize_delinearize_different_basis(2198// CHECK-SAME: %[[ARG0:[a-zA-Z0-9]+]]: index,2199// CHECK-SAME: %[[ARG1:[a-zA-Z0-9]+]]: index,2200// CHECK-SAME: %[[ARG2:[a-zA-Z0-9]+]]: index)2201// CHECK: %[[DELIN:.+]]:3 = affine.delinearize_index %[[ARG0]] into (%[[ARG1]], 4, %[[ARG2]])2202// CHECK: %[[LIN:.+]] = affine.linearize_index [%[[DELIN]]#0, %[[DELIN]]#1, %[[DELIN]]#2] by (%[[ARG1]], 8, %[[ARG2]])2203// CHECK: return %[[LIN]]2204func.func @no_cancel_linearize_delinearize_different_basis(%arg0: index, %arg1: index, %arg2: index) -> index {2205 %0:3 = affine.delinearize_index %arg0 into (%arg1, 4, %arg2) : index, index, index2206 %1 = affine.linearize_index [%0#0, %0#1, %0#2] by (%arg1, 8, %arg2) : index2207 return %1 : index2208}2209 2210// -----2211 2212// CHECK-LABEL: func @affine_leading_zero(2213// CHECK-SAME: %[[ARG0:[a-zA-Z0-9]+]]: index,2214// CHECK-SAME: %[[ARG1:[a-zA-Z0-9]+]]: index)2215// CHECK: %[[RET:.+]] = affine.linearize_index [%[[ARG0]], %[[ARG1]]] by (3, 5)2216// CHECK: return %[[RET]]2217func.func @affine_leading_zero(%arg0: index, %arg1: index) -> index {2218 %c0 = arith.constant 0 : index2219 %ret = affine.linearize_index [%c0, %arg0, %arg1] by (2, 3, 5) : index2220 return %ret : index2221}2222 2223// -----2224 2225// CHECK-LABEL: func @affine_leading_zero_no_outer_bound(2226// CHECK-SAME: %[[ARG0:[a-zA-Z0-9]+]]: index,2227// CHECK-SAME: %[[ARG1:[a-zA-Z0-9]+]]: index)2228// CHECK: %[[RET:.+]] = affine.linearize_index [%[[ARG0]], %[[ARG1]]] by (3, 5)2229// CHECK: return %[[RET]]2230func.func @affine_leading_zero_no_outer_bound(%arg0: index, %arg1: index) -> index {2231 %c0 = arith.constant 0 : index2232 %ret = affine.linearize_index [%c0, %arg0, %arg1] by (3, 5) : index2233 return %ret : index2234}2235 2236// -----2237 2238// CHECK-LABEL: func @delin_apply_cancel_exact2239// CHECK-SAME: (%[[ARG0:.+]]: index, %[[ARG1:.+]]: memref<?xindex>)2240// CHECK-COUNT-6: memref.store %[[ARG0]], %[[ARG1]][%[[ARG0]]]2241// CHECK-NOT: memref.store2242// CHECK: return2243func.func @delin_apply_cancel_exact(%arg0: index, %arg1: memref<?xindex>) {2244 %a:3 = affine.delinearize_index %arg0 into (4, 5) : index, index, index2245 %b:3 = affine.delinearize_index %arg0 into (3, 4, 5) : index, index, index2246 %c:2 = affine.delinearize_index %arg0 into (20) : index, index2247 2248 %t1 = affine.apply affine_map<()[s0, s1, s2] -> (s0 + s1 * 5 + s2 * 20)>()[%a#2, %a#1, %a#0]2249 memref.store %t1, %arg1[%t1] : memref<?xindex>2250 2251 %t2 = affine.apply affine_map<()[s0, s1, s2] -> (s0 + s2 * 20 + s1 * 5)>()[%a#2, %a#1, %a#0]2252 memref.store %t2, %arg1[%t2] : memref<?xindex>2253 2254 %t3 = affine.apply affine_map<()[s0, s1, s2] -> (s1 * 20 + s2 * 5 + s0)>()[%a#2, %a#0, %a#1]2255 memref.store %t3, %arg1[%t3] : memref<?xindex>2256 2257 %t4 = affine.apply affine_map<()[s0, s1, s2] -> (s0 + s1 * 5 + s2 * 20)>()[%b#2, %b#1, %b#0]2258 memref.store %t4, %arg1[%t4] : memref<?xindex>2259 2260 %t5 = affine.apply affine_map<()[s0, s1] -> (s0 + s1 * 20)>()[%c#1, %c#0]2261 memref.store %t5, %arg1[%t5] : memref<?xindex>2262 2263 %t6 = affine.apply affine_map<()[s0, s1] -> (s1 * 20 + s0)>()[%c#1, %c#0]2264 memref.store %t6, %arg1[%t5] : memref<?xindex>2265 2266 return2267}2268 2269// -----2270 2271// CHECK-LABEL: func @delin_apply_cancel_exact_dim2272// CHECK: affine.for %[[arg1:.+]] = 0 to 2562273// CHECK: memref.store %[[arg1]]2274// CHECK: return2275func.func @delin_apply_cancel_exact_dim(%arg0: memref<?xindex>) {2276 affine.for %arg1 = 0 to 256 {2277 %a:3 = affine.delinearize_index %arg1 into (2, 2, 64) : index, index, index2278 %i = affine.apply affine_map<(d0, d1, d2) -> (d0 + d1 * 128 + d2 * 64)>(%a#2, %a#0, %a#1)2279 memref.store %i, %arg0[%i] : memref<?xindex>2280 }2281 return2282}2283 2284// -----2285 2286// CHECK-DAG: #[[$MAP:.+]] = affine_map<()[s0] -> (s0 + 512)>2287// CHECK-LABEL: func @delin_apply_cancel_const_term2288// CHECK-SAME: (%[[ARG0:.+]]: index, %[[ARG1:.+]]: memref<?xindex>)2289// CHECK: affine.apply #[[$MAP]]()[%[[ARG0]]]2290// CHECK: return2291func.func @delin_apply_cancel_const_term(%arg0: index, %arg1: memref<?xindex>) {2292 %a:3 = affine.delinearize_index %arg0 into (2, 2, 64) : index, index, index2293 2294 %t1 = affine.apply affine_map<()[s0, s1, s2] -> (s0 + s1 * 128 + s2 * 64 + 512)>()[%a#2, %a#0, %a#1]2295 memref.store %t1, %arg1[%t1] : memref<?xindex>2296 2297 return2298}2299 2300// -----2301 2302// CHECK-DAG: #[[$MAP:.+]] = affine_map<()[s0, s1] -> (s0 + s1 + 512)>2303// CHECK-LABEL: func @delin_apply_cancel_var_term2304// CHECK-SAME: (%[[ARG0:.+]]: index, %[[ARG1:.+]]: memref<?xindex>, %[[ARG2:.+]]: index)2305// CHECK: affine.apply #[[$MAP]]()[%[[ARG2]], %[[ARG0]]]2306// CHECK: return2307func.func @delin_apply_cancel_var_term(%arg0: index, %arg1: memref<?xindex>, %arg2: index) {2308 %a:3 = affine.delinearize_index %arg0 into (2, 2, 64) : index, index, index2309 2310 %t1 = affine.apply affine_map<()[s0, s1, s2, s3] -> (s0 + s1 * 128 + s2 * 64 + s3 + 512)>()[%a#2, %a#0, %a#1, %arg2]2311 memref.store %t1, %arg1[%t1] : memref<?xindex>2312 2313 return2314}2315 2316// -----2317 2318// CHECK-DAG: #[[$MAP:.+]] = affine_map<()[s0] -> (s0 * 2 + s0 ceildiv 4)>2319// CHECK-LABEL: func @delin_apply_cancel_nested_exprs2320// CHECK-SAME: (%[[ARG0:.+]]: index, %[[ARG1:.+]]: memref<?xindex>)2321// CHECK: affine.apply #[[$MAP]]()[%[[ARG0]]]2322// CHECK: return2323func.func @delin_apply_cancel_nested_exprs(%arg0: index, %arg1: memref<?xindex>) {2324 %a:2 = affine.delinearize_index %arg0 into (20) : index, index2325 2326 %t1 = affine.apply affine_map<()[s0, s1] -> ((s0 + s1 * 20) ceildiv 4 + (s1 * 20 + s0) * 2)>()[%a#1, %a#0]2327 memref.store %t1, %arg1[%t1] : memref<?xindex>2328 2329 return2330}2331 2332// -----2333 2334// CHECK-DAG: #[[$MAP:.+]] = affine_map<()[s0, s1] -> (s0 + s1)>2335// CHECK-LABEL: func @delin_apply_cancel_preserve_rotation2336// CHECK-SAME: (%[[ARG0:.+]]: index, %[[ARG1:.+]]: memref<?xindex>)2337// CHECK: %[[A:.+]]:2 = affine.delinearize_index %[[ARG0]] into (20)2338// CHECK: affine.apply #[[$MAP]]()[%[[A]]#1, %[[ARG0]]]2339// CHECK: return2340func.func @delin_apply_cancel_preserve_rotation(%arg0: index, %arg1: memref<?xindex>) {2341 %a:2 = affine.delinearize_index %arg0 into (20) : index, index2342 2343 %t1 = affine.apply affine_map<()[s0, s1] -> (s0 + s1 * 20 + s0)>()[%a#1, %a#0]2344 memref.store %t1, %arg1[%t1] : memref<?xindex>2345 2346 return2347}2348 2349// -----2350 2351// CHECK-DAG: #[[$MAP:.+]] = affine_map<()[s0, s1] -> (s0 + s1 * 5)>2352// CHECK-LABEL: func @delin_apply_dont_cancel_partial2353// CHECK-SAME: (%[[ARG0:.+]]: index, %[[ARG1:.+]]: memref<?xindex>)2354// CHECK: %[[A:.+]]:3 = affine.delinearize_index %[[ARG0]] into (3, 4, 5)2355// CHECK: affine.apply #[[$MAP]]()[%[[A]]#2, %[[A]]#1]2356// CHECK: return2357func.func @delin_apply_dont_cancel_partial(%arg0: index, %arg1: memref<?xindex>) {2358 %a:3 = affine.delinearize_index %arg0 into (3, 4, 5) : index, index, index2359 2360 %t1 = affine.apply affine_map<()[s0, s1] -> (s0 + s1 * 5)>()[%a#2, %a#1]2361 memref.store %t1, %arg1[%t1] : memref<?xindex>2362 2363 return2364}2365 2366// -----2367 2368// CHECK-LABEL: @cst_value_to_cst_attr_basis_delinearize_index2369// CHECK-SAME: (%[[ARG0:.*]]: index)2370// CHECK: %[[RET:.*]]:3 = affine.delinearize_index %[[ARG0]] into (3, 4, 2) : index, index2371// CHECK: return %[[RET]]#0, %[[RET]]#1, %[[RET]]#2 : index, index, index2372func.func @cst_value_to_cst_attr_basis_delinearize_index(%arg0 : index) ->2373 (index, index, index) {2374 %c4 = arith.constant 4 : index2375 %c3 = arith.constant 3 : index2376 %c2 = arith.constant 2 : index2377 %0:3 = affine.delinearize_index %arg0 into (%c3, %c4, %c2)2378 : index, index, index2379 return %0#0, %0#1, %0#2 : index, index, index2380}2381 2382// -----2383 2384// CHECK-LABEL: @cst_value_to_cst_attr_basis_linearize_index2385// CHECK-SAME: (%[[ARG0:.*]]: index, %[[ARG1:.*]]: index, %[[ARG2:.*]]: index)2386// CHECK: %[[RET:.*]] = affine.linearize_index disjoint [%[[ARG0]], %[[ARG1]], %[[ARG2]]] by (2, 3, 4) : index2387// CHECK: return %[[RET]] : index2388func.func @cst_value_to_cst_attr_basis_linearize_index(%arg0 : index, %arg1 : index, %arg2 : index) ->2389 (index) {2390 %c4 = arith.constant 4 : index2391 %c2 = arith.constant 2 : index2392 %0 = affine.linearize_index disjoint [%arg0, %arg1, %arg2] by (%c2, 3, %c4) : index2393 return %0 : index2394}2395 2396// CHECK-LABEL: func @for_empty_body_folder_iv_yield2397func.func @for_empty_body_folder_iv_yield() -> index {2398 %c18 = arith.constant 18 : index2399 %10 = affine.for %arg3 = 0 to 114 iter_args(%arg4 = %c18) -> (index) {2400 affine.yield %arg3 : index2401 }2402 return %10 : index2403}2404