523 lines · plain
1// RUN: mlir-opt %s -split-input-file -test-linalg-transform-patterns=test-erase-unused-operands-and-results | FileCheck %s2// RUN: mlir-opt %s -split-input-file -test-linalg-transform-patterns=test-erase-unnecessary-inputs | FileCheck %s --check-prefix=CHECK-INPUT3 4// CHECK-LABEL: func @remove_deadargs_generic_basic5// CHECK-SAME: (%[[ARG0:.*]]: tensor<?xf32>) -> tensor<?xf32> {6// CHECK: %[[GENERIC_OP:.*]] = linalg.generic7// CHECK-SAME: ins(%[[ARG0]] : tensor<?xf32>)8// CHECK-SAME: outs({{.*}} : tensor<?xf32>) {9#map0 = affine_map<(d0) -> (d0)>10func.func @remove_deadargs_generic_basic(%arg0: tensor<?xf32>) -> (tensor<?xf32>) {11 %c0 = arith.constant 0 : index12 %cst = arith.constant 7.0 : f3213 %0 = tensor.dim %arg0, %c0 : tensor<?xf32>14 %1 = tensor.empty(%0) : tensor<?xf32>15 %2 = tensor.empty(%0) : tensor<?xf32>16 %3 = linalg.generic {indexing_maps = [#map0, #map0, #map0], iterator_types=["parallel"]} ins(%arg0, %1 : tensor<?xf32>, tensor<?xf32>) outs (%2:tensor<?xf32>) {17 ^bb0(%arg1: f32, %arg2: f32, %arg3: f32):18 %4 = arith.addf %arg1, %cst : f3219 linalg.yield %4 : f3220 } -> tensor<?xf32>21 return %3 : tensor<?xf32>22}23 24// -----25 26// CHECK-LABEL: func @remove_deadargs_generic_mixedaccess27// CHECK: %[[GENERIC_OP:.*]] = linalg.generic28// CHECK-NOT: ins29// CHECK-SAME: outs({{.*}} : tensor<?x?xf32>) {30#map0 = affine_map<(d0, d1) -> (d0, d1)>31#map1 = affine_map<(d0, d1) -> (d1, d0)>32func.func @remove_deadargs_generic_mixedaccess(%arg0: tensor<?x?xf32>) -> (tensor<?x?xf32>) {33 %c0 = arith.constant 0 : index34 %c1 = arith.constant 0 : index35 %cst1 = arith.constant 7.0 : f3236 %cst2 = arith.constant 6.0 : f3237 %0 = tensor.dim %arg0, %c0 : tensor<?x?xf32>38 %1 = tensor.dim %arg0, %c1 : tensor<?x?xf32>39 %2 = tensor.empty(%0, %1) : tensor<?x?xf32>40 %3 = tensor.empty(%1, %0) : tensor<?x?xf32>41 %4 = tensor.empty(%0, %1) : tensor<?x?xf32>42 %5 = linalg.generic {indexing_maps = [#map0, #map1, #map0], iterator_types=["parallel","parallel"]} ins(%2, %3 : tensor<?x?xf32>, tensor<?x?xf32>) outs (%4:tensor<?x?xf32>) {43 ^bb0(%arg1: f32, %arg2: f32, %arg3: f32):44 %6 = arith.divf %cst1, %cst2 : f3245 linalg.yield %6 : f3246 } -> tensor<?x?xf32>47 return %5 : tensor<?x?xf32>48}49 50// -----51 52// Test case: Most basic case. Adding a vector to itself.53 54#map = affine_map<(d0) -> (d0)>55 56// CHECK: #[[$MAP:.*]] = affine_map<(d0) -> (d0)>57// CHECK-LABEL: @basic58func.func @basic(%arg0: tensor<?xf32>) -> tensor<?xf32> {59 // CHECK: linalg.generic{{.*}}[#[[$MAP]], #[[$MAP]]]60 // CHECK: attrs = {someattr}61 // CHECK: ^bb0(%[[BBARG:.*]]: f32, %{{.*}}: f32):62 // CHECK: arith.addf %[[BBARG]], %[[BBARG]]63 %0 = linalg.generic {indexing_maps = [#map, #map, #map], iterator_types = ["parallel"]}64 ins(%arg0, %arg0 : tensor<?xf32>, tensor<?xf32>)65 outs(%arg0 : tensor<?xf32>) attrs = {someattr} {66 ^bb0(%arg1: f32, %arg2: f32, %arg3: f32):67 %1 = arith.addf %arg1, %arg2 : f3268 linalg.yield %1 : f3269 } -> tensor<?xf32>70 return %0 : tensor<?xf32>71}72 73// -----74 75// Test case: Different indexing maps mean that args are not redundant, despite76// being the same Value.77 78#map0 = affine_map<(d0, d1) -> (d0, d1)>79#map1 = affine_map<(d0, d1) -> (d1, d0)>80 81// CHECK-DAG: #[[$MAP0:.*]] = affine_map<(d0, d1) -> (d0, d1)>82// CHECK-DAG: #[[$MAP1:.*]] = affine_map<(d0, d1) -> (d1, d0)>83// CHECK-LABEL: @distinct_affine_maps84func.func @distinct_affine_maps(%arg0: tensor<?x?xf32>) -> tensor<?x?xf32> {85 // CHECK: linalg.generic{{.*}}[#[[$MAP0]], #[[$MAP1]], #[[$MAP0]]]86 %0 = linalg.generic {indexing_maps = [#map0, #map1, #map0], iterator_types = ["parallel", "parallel"]}87 ins(%arg0, %arg0 : tensor<?x?xf32>, tensor<?x?xf32>)88 outs(%arg0 : tensor<?x?xf32>) {89 ^bb0(%arg1: f32, %arg2: f32, %arg3: f32):90 %1 = arith.addf %arg1, %arg2 : f3291 linalg.yield %1 : f3292 } -> tensor<?x?xf32>93 return %0 : tensor<?x?xf32>94}95 96// -----97 98// Test case: Check rewriting mechanics for mixed redundant and99// non-redundant args.100 101#map0 = affine_map<(d0, d1) -> (d0, d1)>102#map1 = affine_map<(d0, d1) -> (d1, d0)>103 104// CHECK-DAG: #[[$MAP0:.*]] = affine_map<(d0, d1) -> (d0, d1)>105// CHECK-DAG: #[[$MAP1:.*]] = affine_map<(d0, d1) -> (d1, d0)>106// CHECK-LABEL: @mixed_redundant_non_redundant107func.func @mixed_redundant_non_redundant(%arg0: tensor<?x?xf32>) -> tensor<?x?xf32> {108 // CHECK: linalg.generic{{.*}}[#[[$MAP0]], #[[$MAP1]], #[[$MAP0]]]109 // CHECK: ^bb0(%[[BBARG0:.*]]: f32, %[[BBARG1:.*]]: f32, %{{[a-zA-Z0-9]+}}: f32):110 // CHECK: "test.elementwise_mappable"(%[[BBARG0]], %[[BBARG1]], %[[BBARG0]])111 %0 = linalg.generic {indexing_maps = [#map0, #map1, #map0, #map0], iterator_types = ["parallel", "parallel"]}112 ins(%arg0, %arg0, %arg0 : tensor<?x?xf32>, tensor<?x?xf32>, tensor<?x?xf32>)113 outs(%arg0 : tensor<?x?xf32>) {114 ^bb0(%arg1: f32, %arg2: f32, %arg3: f32, %arg4: f32):115 %1 = "test.elementwise_mappable"(%arg1, %arg2, %arg3) : (f32, f32, f32) -> f32116 linalg.yield %1 : f32117 } -> tensor<?x?xf32>118 return %0 : tensor<?x?xf32>119}120 121// -----122 123// Test case: Check rewriting mechanics for multiple different redundant args.124 125#map = affine_map<(d0) -> (d0)>126 127// CHECK: #[[$MAP:.*]] = affine_map<(d0) -> (d0)>128// CHECK-LABEL: @multiple_different_redundant_args129func.func @multiple_different_redundant_args(%arg0: tensor<?xf32>, %arg1: tensor<?xf32>) -> tensor<?xf32> {130 // CHECK: linalg.generic{{.*}}[#[[$MAP]], #[[$MAP]], #[[$MAP]]]131 // CHECK: ^bb0(%[[BBARG0:.*]]: f32, %[[BBARG1:.*]]: f32, %{{[a-zA-Z0-9]+}}: f32):132 // CHECK: "test.elementwise_mappable"(%[[BBARG0]], %[[BBARG1]], %[[BBARG0]], %[[BBARG1]])133 %0 = linalg.generic {indexing_maps = [#map, #map, #map, #map, #map], iterator_types = ["parallel"]}134 ins(%arg0, %arg1, %arg0, %arg1 : tensor<?xf32>, tensor<?xf32>, tensor<?xf32>, tensor<?xf32>)135 outs(%arg0 : tensor<?xf32>) {136 ^bb0(%arg2: f32, %arg3: f32, %arg4: f32, %arg5: f32, %arg6: f32):137 %1 = "test.elementwise_mappable"(%arg2, %arg3, %arg4, %arg5) : (f32, f32, f32, f32) -> f32138 linalg.yield %1 : f32139 } -> tensor<?xf32>140 return %0 : tensor<?xf32>141}142 143// -----144 145// Drop dead result.146 147#map0 = affine_map<(d0, d1, d2) -> (d0, d1, d2)>148#map1 = affine_map<(d0, d1, d2) -> (d0, d2, d1)>149#map2 = affine_map<(d0, d1, d2) -> (d1, d2, d0)>150#map3 = affine_map<(d0, d1, d2) -> (d1, d0, d2)>151#map4 = affine_map<(d0, d1, d2) -> (d2, d0, d1)>152func.func @drop_dead_results(%arg0 : tensor<?x?x?xf32>) -> (tensor<?x?x?xf32>, tensor<?x?x?xf32>) {153 %0:4 = linalg.generic {154 indexing_maps = [#map0, #map1, #map2, #map3, #map4],155 iterator_types = ["parallel", "parallel", "parallel"]}156 ins(%arg0 : tensor<?x?x?xf32>)157 outs(%arg0, %arg0, %arg0, %arg0158 : tensor<?x?x?xf32>, tensor<?x?x?xf32>, tensor<?x?x?xf32>, tensor<?x?x?xf32>) {159 ^bb0(%b0 : f32, %b1 : f32, %b2 : f32, %b3 : f32, %b4 : f32) :160 %1 = arith.addf %b0, %b0: f32161 linalg.yield %1, %1, %1, %1 : f32, f32, f32, f32162 } -> (tensor<?x?x?xf32>, tensor<?x?x?xf32>, tensor<?x?x?xf32>, tensor<?x?x?xf32>)163 return %0#0, %0#2 : tensor<?x?x?xf32>, tensor<?x?x?xf32>164}165// CHECK-DAG: #[[MAP0:.+]] = affine_map<(d0, d1, d2) -> (d0, d1, d2)>166// CHECK-DAG: #[[MAP1:.+]] = affine_map<(d0, d1, d2) -> (d0, d2, d1)>167// CHECK-DAG: #[[MAP2:.+]] = affine_map<(d0, d1, d2) -> (d1, d0, d2)>168// CHECK: func @drop_dead_results(169// CHECK-SAME: %[[ARG0:.+]]: tensor<?x?x?xf32>)170// CHECK: %[[GENERIC:.+]]:2 = linalg.generic171// CHECK-SAME: indexing_maps = [#[[MAP0]], #[[MAP1]], #[[MAP2]]]172// CHECK-SAME: outs(%[[ARG0]], %[[ARG0]] :173// CHECK: return %[[GENERIC]]#0, %[[GENERIC]]#1174 175// -----176 177// Current argmax lowering to `linalg.generic`. Cannot drop the178// first return even though it isnt used since it has an internal179// use.180#map0 = affine_map<(d0) -> (d0)>181#map1 = affine_map<(d0) -> ()>182func.func @argmax_lowering(%arg0 : tensor<?xf32>) -> tensor<i32> {183 %init0 = tensor.empty() : tensor<f32>184 %init1 = tensor.empty() : tensor<i32>185 %0:2 = linalg.generic {186 indexing_maps = [#map0, #map1, #map1],187 iterator_types = ["reduction"]}188 ins(%arg0 : tensor<?xf32>)189 outs(%init0, %init1 : tensor<f32>, tensor<i32>) {190 ^bb0(%b0: f32, %b1: f32, %b2: i32):191 %8 = linalg.index 0 : index192 %9 = arith.index_cast %8 : index to i32193 %10 = arith.cmpf oge, %b0, %b1 : f32194 %11 = arith.select %10, %b0, %b1 : f32195 %12 = arith.cmpf oeq, %b0, %b1 : f32196 %13 = arith.minsi %9, %b2 : i32197 %14 = arith.select %10, %9, %b2 : i32198 %15 = arith.select %12, %13, %14 : i32199 linalg.yield %11, %15 : f32, i32200 } -> (tensor<f32>, tensor<i32>)201 return %0#1 : tensor<i32>202}203// CHECK: func @argmax_lowering(204// CHECK-SAME: %[[ARG0:.+]]: tensor<?xf32>205// CHECK-DAG: %[[INIT0:.+]] = tensor.empty() : tensor<f32>206// CHECK-DAG: %[[INIT1:.+]] = tensor.empty() : tensor<i32>207// CHECK: %[[GENERIC:.+]]:2 = linalg.generic208// CHECK-SAME: outs(%[[INIT0]], %[[INIT1]] :209// CHECK: return %[[GENERIC]]#1210 211// -----212 213// Do not remove operand needed for loop dim.214func.func @loop_dim_operand(%arg0 : tensor<?xf32>) -> tensor<i32> {215 %cst = arith.constant 0 : i32216 %init = tensor.empty() : tensor<i32>217 %fill = linalg.fill ins(%cst : i32) outs(%init : tensor<i32>) -> tensor<i32>218 %0 = linalg.generic {219 indexing_maps = [affine_map<(d0) -> (d0)>, affine_map<(d0) -> ()>],220 iterator_types = ["reduction"]}221 ins(%arg0 : tensor<?xf32>) outs(%fill : tensor<i32>) {222 ^bb0(%b0: f32, %b1: i32):223 %1 = linalg.index 0 : index224 %2 = arith.index_cast %1 : index to i32225 %3 = arith.addi %b1, %2 : i32226 linalg.yield %3 : i32227 } -> tensor<i32>228 return %0 : tensor<i32>229}230// CHECK: func @loop_dim_operand(231// CHECK-SAME: %[[ARG0:.+]]: tensor<?xf32>232// CHECK: linalg.generic233// CHECK-SAME: ins(%[[ARG0]] :234 235// -----236 237// Do not remove outs operand needed for loop bound computation.238func.func @loop_dim_outs_operand(%arg0 : index) -> tensor<i32> {239 %cst = arith.constant 0 : i32240 %init1 = tensor.empty(%arg0) : tensor<?xi32>241 %init = tensor.empty() : tensor<i32>242 %fill = linalg.fill ins(%cst : i32) outs(%init : tensor<i32>) -> tensor<i32>243 %0:2 = linalg.generic {244 indexing_maps = [affine_map<(d0) -> (d0)>, affine_map<(d0) -> ()>],245 iterator_types = ["parallel"]}246 outs(%init1, %fill : tensor<?xi32>, tensor<i32>) {247 ^bb0(%b0: i32, %b1: i32):248 %1 = linalg.index 0 : index249 %2 = arith.index_cast %1 : index to i32250 %3 = arith.addi %b1, %2 : i32251 linalg.yield %2, %3 : i32, i32252 } -> (tensor<?xi32>, tensor<i32>)253 return %0#1 : tensor<i32>254}255// CHECK: func @loop_dim_outs_operand(256// CHECK-SAME: %[[ARG0:.+]]: index257// CHECK: %[[INIT:.+]] = tensor.empty(%[[ARG0]])258// CHECK: linalg.generic259// CHECK-SAME: outs(%[[INIT]]260 261// -----262 263#map0 = affine_map<(d0, d1) -> (d0, d1)>264#map1 = affine_map<(d0, d1) -> (d1, d0)>265#map2 = affine_map<(d0, d1) -> (d0)>266#map3 = affine_map<(d0, d1) -> (d1)>267func.func @multiple_redundant_args(%arg0 : tensor<?x?xi32>, %arg1 : tensor<?xi32>,268 %arg2 : tensor<?xi32>, %arg3 : tensor<?x?xi32>, %arg4 : tensor<?xi32>) -> tensor<?xi32> {269 %0 = linalg.generic {270 indexing_maps = [#map3, #map0, #map0, #map2, #map1, #map1, #map2],271 iterator_types = ["parallel", "reduction"]}272 ins(%arg4, %arg0, %arg0, %arg1, %arg3, %arg3273 : tensor<?xi32>, tensor<?x?xi32>, tensor<?x?xi32>, tensor<?xi32>, tensor<?x?xi32>, tensor<?x?xi32>)274 outs(%arg2 : tensor<?xi32>) {275 ^bb0(%b0 : i32, %b1 : i32, %b2 : i32, %b3 : i32, %b4 : i32, %b5 : i32, %b6 : i32):276 %1 = arith.addi %b0, %b1 : i32277 %2 = arith.addi %1, %b2 : i32278 %3 = arith.addi %2, %b3 : i32279 %4 = arith.addi %3, %b4 : i32280 %5 = arith.addi %4, %b5 : i32281 %6 = arith.addi %5, %b6 : i32282 linalg.yield %6 : i32283 } -> tensor<?xi32>284 return %0 : tensor<?xi32>285}286// CHECK-DAG: #[[MAP0:.+]] = affine_map<(d0, d1) -> (d1)>287// CHECK-DAG: #[[MAP1:.+]] = affine_map<(d0, d1) -> (d0, d1)>288// CHECK-DAG: #[[MAP2:.+]] = affine_map<(d0, d1) -> (d0)>289// CHECK-DAG: #[[MAP3:.+]] = affine_map<(d0, d1) -> (d1, d0)>290// CHECK: func @multiple_redundant_args(291// CHECK-SAME: %[[ARG0:[a-zA-Z0-9_]+]]: tensor<?x?xi32>292// CHECK-SAME: %[[ARG1:[a-zA-Z0-9_]+]]: tensor<?xi32>293// CHECK-SAME: %[[ARG2:[a-zA-Z0-9_]+]]: tensor<?xi32>294// CHECK-SAME: %[[ARG3:[a-zA-Z0-9_]+]]: tensor<?x?xi32>295// CHECK-SAME: %[[ARG4:[a-zA-Z0-9_]+]]: tensor<?xi32>)296// CHECK: %[[RETURN:.+]] = linalg.generic297// CHECK-SAME: indexing_maps = [#[[MAP0]], #[[MAP1]], #[[MAP2]], #[[MAP3]], #[[MAP2]]]298// CHECK-SAME: iterator_types = ["parallel", "reduction"]299// CHECK-SAME: ins(%[[ARG4]], %[[ARG0]], %[[ARG1]], %[[ARG3]] :300// CHECK-SAME: outs(%[[ARG2]] :301// CHECK: ^{{.+}}(%[[B0:[a-zA-Z0-9]+]]: i32302// CHECK-SAME: %[[B1:[a-zA-Z0-9_]+]]: i32303// CHECK-SAME: %[[B2:[a-zA-Z0-9_]+]]: i32304// CHECK-SAME: %[[B3:[a-zA-Z0-9_]+]]: i32305// CHECK-SAME: %[[B4:[a-zA-Z0-9_]+]]: i32)306// CHECK: %[[T0:.+]] = arith.addi %[[B0]], %[[B1]]307// CHECK: %[[T1:.+]] = arith.addi %[[T0]], %[[B1]]308// CHECK: %[[T2:.+]] = arith.addi %[[T1]], %[[B2]]309// CHECK: %[[T3:.+]] = arith.addi %[[T2]], %[[B3]]310// CHECK: %[[T4:.+]] = arith.addi %[[T3]], %[[B3]]311// CHECK: %[[T5:.+]] = arith.addi %[[T4]], %[[B4]]312// CHECK: linalg.yield %[[T5]]313// CHECK: return %[[RETURN]]314 315// -----316 317// Drop redundant results.318 319#map = affine_map<(d0, d1) -> (d0, d1)>320func.func @drop_redundant_results(321 %arg0 : tensor<?x?xf32>) -> (tensor<?x?xf32>, tensor<?x?xf32>) {322 %0:2 = linalg.generic {323 indexing_maps = [#map, #map, #map],324 iterator_types = ["parallel", "parallel"]}325 ins(%arg0 : tensor<?x?xf32>)326 outs(%arg0, %arg0 : tensor<?x?xf32>, tensor<?x?xf32>) {327 ^bb0(%b0 : f32, %b1 : f32, %b2 : f32):328 %1 = arith.addf %b0, %b0 : f32329 linalg.yield %1, %1 : f32, f32330 } -> (tensor<?x?xf32>, tensor<?x?xf32>)331 return %0#0, %0#1 : tensor<?x?xf32>, tensor<?x?xf32>332}333// CHECK: func @drop_redundant_results334// CHECK-SAME: %[[ARG0:.+]]: tensor<?x?xf32>335// CHECK: %[[GENERIC:.+]] = linalg.generic336// CHECK-SAME: outs(%[[ARG0]] :337// CHECK: return %[[GENERIC]]338 339// -----340 341// Drop dead result with different tensors.342 343#map0 = affine_map<(d0, d1, d2) -> (d0, d1, d2)>344#map1 = affine_map<(d0, d1, d2) -> (d0, d2, d1)>345#map2 = affine_map<(d0, d1, d2) -> (d1, d2, d0)>346#map3 = affine_map<(d0, d1, d2) -> (d1, d0, d2)>347#map4 = affine_map<(d0, d1, d2) -> (d2, d0, d1)>348func.func @drop_dead_results_with_different_tensors(%arg0 : tensor<?x?x?xf32>) -> (tensor<?x?x?xf32>, tensor<?x?x?xf32>) {349 %c0 = arith.constant 0 : index350 %d0 = tensor.dim %arg0, %c0 : tensor<?x?x?xf32>351 %c1 = arith.constant 1 : index352 %d1 = tensor.dim %arg0, %c1 : tensor<?x?x?xf32>353 %c2 = arith.constant 2 : index354 %d2 = tensor.dim %arg0, %c2 : tensor<?x?x?xf32>355 %init0 = tensor.empty(%d0, %d1, %d2) : tensor<?x?x?xf32>356 %0:4 = linalg.generic {357 indexing_maps = [#map0, #map1, #map2, #map3, #map4],358 iterator_types = ["parallel", "parallel", "parallel"]}359 ins(%arg0 : tensor<?x?x?xf32>)360 outs(%arg0, %arg0, %init0, %init0361 : tensor<?x?x?xf32>, tensor<?x?x?xf32>, tensor<?x?x?xf32>, tensor<?x?x?xf32>) {362 ^bb0(%b0 : f32, %b1 : f32, %b2 : f32, %b3 : f32, %b4 : f32) :363 linalg.yield %b0, %b0, %b3, %b4 : f32, f32, f32, f32364 } -> (tensor<?x?x?xf32>, tensor<?x?x?xf32>, tensor<?x?x?xf32>, tensor<?x?x?xf32>)365 return %0#0, %0#1 : tensor<?x?x?xf32>, tensor<?x?x?xf32>366}367 368// CHECK-DAG: #[[MAP0:.+]] = affine_map<(d0, d1, d2) -> (d0, d1, d2)>369// CHECK-DAG: #[[MAP1:.+]] = affine_map<(d0, d1, d2) -> (d0, d2, d1)>370// CHECK-DAG: #[[MAP2:.+]] = affine_map<(d0, d1, d2) -> (d1, d2, d0)>371// CHECK: func @drop_dead_results_with_different_tensors(372// CHECK-SAME: %[[ARG0:.+]]: tensor<?x?x?xf32>)373// CHECK: %[[GENERIC:.+]]:2 = linalg.generic374// CHECK-SAME: indexing_maps = [#[[MAP0]], #[[MAP1]], #[[MAP2]]]375// CHECK-SAME: outs(%[[ARG0]], %[[ARG0]] :376// CHECK: return %[[GENERIC]]#0, %[[GENERIC]]#1377 378// -----379 380// Drop dead result with unused cycles.381 382#map0 = affine_map<(d0, d1, d2) -> (d0, d1, d2)>383#map1 = affine_map<(d0, d1, d2) -> (d0, d2, d1)>384#map2 = affine_map<(d0, d1, d2) -> (d1, d2, d0)>385#map3 = affine_map<(d0, d1, d2) -> (d1, d0, d2)>386#map4 = affine_map<(d0, d1, d2) -> (d2, d0, d1)>387func.func @drop_dead_results_with_unused_cycles(%arg0 : tensor<?x?x?xf32>) -> (tensor<?x?x?xf32>, tensor<?x?x?xf32>) {388 %c0 = arith.constant 0 : index389 %d0 = tensor.dim %arg0, %c0 : tensor<?x?x?xf32>390 %c1 = arith.constant 1 : index391 %d1 = tensor.dim %arg0, %c1 : tensor<?x?x?xf32>392 %c2 = arith.constant 2 : index393 %d2 = tensor.dim %arg0, %c2 : tensor<?x?x?xf32>394 %init0 = tensor.empty(%d0, %d1, %d2) : tensor<?x?x?xf32>395 %0:4 = linalg.generic {396 indexing_maps = [#map0, #map1, #map2, #map3, #map4],397 iterator_types = ["parallel", "parallel", "parallel"]}398 ins(%arg0 : tensor<?x?x?xf32>)399 outs(%arg0, %arg0, %init0, %init0400 : tensor<?x?x?xf32>, tensor<?x?x?xf32>, tensor<?x?x?xf32>, tensor<?x?x?xf32>) {401 ^bb0(%b0 : f32, %b1 : f32, %b2 : f32, %b3 : f32, %b4 : f32) :402 %1 = arith.addf %b0, %b0: f32403 %2 = arith.addf %b0, %b3: f32404 %3 = arith.addf %b0, %b4: f32405 linalg.yield %1, %1, %2, %3 : f32, f32, f32, f32406 } -> (tensor<?x?x?xf32>, tensor<?x?x?xf32>, tensor<?x?x?xf32>, tensor<?x?x?xf32>)407 return %0#0, %0#1 : tensor<?x?x?xf32>, tensor<?x?x?xf32>408}409 410// CHECK-DAG: #[[MAP0:.+]] = affine_map<(d0, d1, d2) -> (d0, d1, d2)>411// CHECK-DAG: #[[MAP1:.+]] = affine_map<(d0, d1, d2) -> (d0, d2, d1)>412// CHECK-DAG: #[[MAP2:.+]] = affine_map<(d0, d1, d2) -> (d1, d2, d0)>413// CHECK: func @drop_dead_results_with_unused_cycles(414// CHECK-SAME: %[[ARG0:.+]]: tensor<?x?x?xf32>)415// CHECK: %[[GENERIC:.+]]:2 = linalg.generic416// CHECK-SAME: indexing_maps = [#[[MAP0]], #[[MAP1]], #[[MAP2]]]417// CHECK-SAME: outs(%[[ARG0]], %[[ARG0]] :418// CHECK: return %[[GENERIC]]#0, %[[GENERIC]]#1419 420// -----421 422// Drop only the results not used by others.423 424#map0 = affine_map<(d0, d1, d2) -> (d0, d1, d2)>425#map1 = affine_map<(d0, d1, d2) -> (d0, d2, d1)>426#map2 = affine_map<(d0, d1, d2) -> (d1, d2, d0)>427#map3 = affine_map<(d0, d1, d2) -> (d1, d0, d2)>428func.func @drop_only_the_results_not_used_by_others(%arg0 : tensor<?x?x?xf32>) -> (tensor<?x?x?xf32>) {429 %c0 = arith.constant 0 : index430 %d0 = tensor.dim %arg0, %c0 : tensor<?x?x?xf32>431 %c1 = arith.constant 1 : index432 %d1 = tensor.dim %arg0, %c1 : tensor<?x?x?xf32>433 %c2 = arith.constant 2 : index434 %d2 = tensor.dim %arg0, %c2 : tensor<?x?x?xf32>435 %init0 = tensor.empty(%d0, %d1, %d2) : tensor<?x?x?xf32>436 %0:3 = linalg.generic {437 indexing_maps = [#map0, #map1, #map2, #map3],438 iterator_types = ["parallel", "parallel", "parallel"]}439 ins(%arg0 : tensor<?x?x?xf32>)440 outs(%arg0, %init0, %init0441 : tensor<?x?x?xf32>, tensor<?x?x?xf32>, tensor<?x?x?xf32>) {442 ^bb0(%b0 : f32, %b1 : f32, %b2 : f32, %b3 : f32) :443 linalg.yield %b2, %b1, %b3 : f32, f32, f32444 } -> (tensor<?x?x?xf32>, tensor<?x?x?xf32>, tensor<?x?x?xf32>)445 return %0#0 : tensor<?x?x?xf32>446}447 448// CHECK-DAG: #[[MAP1:.+]] = affine_map<(d0, d1, d2) -> (d0, d2, d1)>449// CHECK-DAG: #[[MAP2:.+]] = affine_map<(d0, d1, d2) -> (d1, d2, d0)>450// CHECK: func @drop_only_the_results_not_used_by_others(451// CHECK-SAME: %[[ARG0:.+]]: tensor<?x?x?xf32>)452// CHECK: %[[INIT:.+]] = tensor.empty453// CHECK: %[[GENERIC:.+]]:2 = linalg.generic454// CHECK-SAME: indexing_maps = [#[[MAP1]], #[[MAP2]]]455// CHECK-SAME: outs(%[[ARG0]], %[[INIT]] :456// CHECK: return %[[GENERIC]]#0457 458// -----459 460// Drop only the cycles not used by others.461 462#map0 = affine_map<(d0, d1, d2) -> (d0, d1, d2)>463#map1 = affine_map<(d0, d1, d2) -> (d0, d2, d1)>464#map2 = affine_map<(d0, d1, d2) -> (d1, d2, d0)>465#map3 = affine_map<(d0, d1, d2) -> (d1, d0, d2)>466func.func @drop_only_the_cycles_not_used_by_others(%arg0 : tensor<?x?x?xf32>) -> (tensor<?x?x?xf32>) {467 %c0 = arith.constant 0 : index468 %d0 = tensor.dim %arg0, %c0 : tensor<?x?x?xf32>469 %c1 = arith.constant 1 : index470 %d1 = tensor.dim %arg0, %c1 : tensor<?x?x?xf32>471 %c2 = arith.constant 2 : index472 %d2 = tensor.dim %arg0, %c2 : tensor<?x?x?xf32>473 %init0 = tensor.empty(%d0, %d1, %d2) : tensor<?x?x?xf32>474 %0:3 = linalg.generic {475 indexing_maps = [#map0, #map1, #map2, #map3],476 iterator_types = ["parallel", "parallel", "parallel"]}477 ins(%arg0 : tensor<?x?x?xf32>)478 outs(%arg0, %init0, %init0479 : tensor<?x?x?xf32>, tensor<?x?x?xf32>, tensor<?x?x?xf32>) {480 ^bb0(%b0 : f32, %b1 : f32, %b2 : f32, %b3 : f32) :481 %1 = arith.addf %b1, %b2: f32482 %2 = arith.addf %b1, %b3 : f32483 linalg.yield %1, %b1, %2 : f32, f32, f32484 } -> (tensor<?x?x?xf32>, tensor<?x?x?xf32>, tensor<?x?x?xf32>)485 return %0#0 : tensor<?x?x?xf32>486}487 488// CHECK-DAG: #[[MAP1:.+]] = affine_map<(d0, d1, d2) -> (d0, d2, d1)>489// CHECK-DAG: #[[MAP2:.+]] = affine_map<(d0, d1, d2) -> (d1, d2, d0)>490// CHECK: func @drop_only_the_cycles_not_used_by_others(491// CHECK-SAME: %[[ARG0:.+]]: tensor<?x?x?xf32>)492// CHECK: %[[INIT:.+]] = tensor.empty493// CHECK: %[[GENERIC:.+]]:2 = linalg.generic494// CHECK-SAME: indexing_maps = [#[[MAP1]], #[[MAP2]]]495// CHECK-SAME: outs(%[[ARG0]], %[[INIT]] :496// CHECK: return %[[GENERIC]]#0497 498 499// -----500 501// CHECK-INPUT-LABEL: func @remove_unnecessary_input(502// CHECK-INPUT-SAME: %[[a:.*]]: tensor<?xf32>, %[[b:.*]]: tensor<?xf32>503#map = affine_map<(d0) -> (d0)>504func.func @remove_unnecessary_input(%a: tensor<?xf32>, %b: tensor<?xf32>)505 -> tensor<?xf32>506{507 // CHECK-INPUT: %[[result:.*]] = linalg.generic {indexing_maps = [#{{.*}}, #{{.*}}], iterator_types = ["parallel"]}508 // CHECK-INPUT-SAME: ins(%[[a]] : tensor<?xf32>) outs(%[[b]] : tensor<?xf32>) {509 // CHECK-INPUT: ^bb0(%[[in:.*]]: f32, %[[out:.*]]: f32):510 // CHECK-INPUT: %[[add:.*]] = arith.addf %[[in]], %[[out]]511 // CHECK-INPUT: linalg.yield %[[add]]512 // CHECK-INPUT: } -> tensor<?xf32>513 // CHECK-INPUT: return %[[result]]514 %0 = linalg.generic515 {indexing_maps = [#map, #map, #map], iterator_types = ["parallel"]}516 ins(%a, %b : tensor<?xf32>, tensor<?xf32>) outs(%b : tensor<?xf32>) {517 ^bb0(%in: f32, %in_2: f32, %out: f32):518 %16 = arith.addf %in, %in_2 : f32519 linalg.yield %16 : f32520 } -> tensor<?xf32>521 return %0 : tensor<?xf32>522}523