brintos

brintos / llvm-project-archived public Read only

0
0
Text · 41.8 KiB · ed36855 Raw
1019 lines · plain
1// RUN: mlir-opt %s -one-shot-bufferize="allow-return-allocs-from-loops bufferize-function-boundaries test-analysis-only" -split-input-file | FileCheck %s --check-prefixes=CHECK,PARALLEL-CHECK2// RUN: mlir-opt %s -one-shot-bufferize="allow-return-allocs-from-loops bufferize-function-boundaries test-analysis-only check-parallel-regions=false" -split-input-file | FileCheck %s --check-prefixes=CHECK,NO-PARALLEL-CHECK3 4// Run fuzzer with different seeds.5// RUN: mlir-opt %s -one-shot-bufferize="allow-return-allocs-from-loops bufferize-function-boundaries test-analysis-only analysis-heuristic=fuzzer analysis-fuzzer-seed=23" -split-input-file -o /dev/null6// RUN: mlir-opt %s -one-shot-bufferize="allow-return-allocs-from-loops bufferize-function-boundaries test-analysis-only analysis-heuristic=fuzzer analysis-fuzzer-seed=59" -split-input-file -o /dev/null7// RUN: mlir-opt %s -one-shot-bufferize="allow-return-allocs-from-loops bufferize-function-boundaries test-analysis-only analysis-heuristic=fuzzer analysis-fuzzer-seed=91" -split-input-file -o /dev/null8 9// CHECK-LABEL: func @scf_for_yield_only10func.func @scf_for_yield_only(11    %A : tensor<?xf32> {bufferization.writable = false},12    %B : tensor<?xf32> {bufferization.writable = true},13    %lb : index,14    %ub : index,15    %step : index)16  -> (tensor<?xf32>, tensor<?xf32>)17{18  //      CHECK: scf.for19  // CHECK-NEXT: scf.yield20  // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}21  //      CHECK: } {__inplace_operands_attr__ = ["none", "none", "none", "false"]}22  %r0 = scf.for %i = %lb to %ub step %step iter_args(%t = %A) -> (tensor<?xf32>) {23    scf.yield %t : tensor<?xf32>24  }25 26  //      CHECK: scf.for27  // CHECK-NEXT: scf.yield28  // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}29  //      CHECK: } {__inplace_operands_attr__ = ["none", "none", "none", "true"]}30  %r1 = scf.for %i = %lb to %ub step %step iter_args(%t = %B) -> (tensor<?xf32>) {31    scf.yield %t : tensor<?xf32>32  }33 34  //      CHECK: return35  // CHECK-SAME: __equivalent_func_args__ = [-1, 1]36  return %r0, %r1: tensor<?xf32>, tensor<?xf32>37}38 39// -----40 41// CHECK-LABEL: func @scf_for_with_tensor.insert_slice42func.func @scf_for_with_tensor.insert_slice(43    %A : tensor<?xf32> {bufferization.writable = false},44    %B : tensor<?xf32> {bufferization.writable = true},45    %C : tensor<4xf32> {bufferization.writable = false},46    %lb : index,47    %ub : index,48    %step : index)49  -> (tensor<?xf32>, tensor<?xf32>)50{51  //      CHECK: scf.for52  // scf.for bbArgs are always inplaceable seen from ops inside the body:53  //   1. Either the matching tensor is not inplaceable and an alloc occurs54  //      which makes bbArg inplaceable.55  //   2. Or it is already inplaceable and so is bbArg.56  // CHECK-NEXT:   tensor.insert_slice57  // CHECK-SAME:     {__inplace_operands_attr__ = ["true", "true"]}58  // CHECK-NEXT:   tensor.insert_slice59  // CHECK-SAME:     {__inplace_operands_attr__ = ["true", "true"]}60  // CHECK-NEXT:   scf.yield {__inplace_operands_attr__ = ["true", "true"]}61  // CHECK-NEXT: } {__inplace_operands_attr__ = ["none", "none", "none", "false", "true"]}62  %r0:2 = scf.for %i = %lb to %ub step %step iter_args(%tA = %A, %tB = %B)63      -> (tensor<?xf32>, tensor<?xf32>)64  {65    %ttA = tensor.insert_slice %C into %tA[0][4][1] : tensor<4xf32> into tensor<?xf32>66    %ttB = tensor.insert_slice %C into %tB[0][4][1] : tensor<4xf32> into tensor<?xf32>67    scf.yield %ttA, %ttB : tensor<?xf32>, tensor<?xf32>68  }69 70  //      CHECK: return71  // CHECK-SAME: __equivalent_func_args__ = [-1, 1]72  return %r0#0, %r0#1: tensor<?xf32>, tensor<?xf32>73}74 75// -----76 77func.func private @some_use(tensor<?xf32>) -> ()78 79// CHECK-LABEL: func @scf_for_deps80func.func @scf_for_deps(81    %A : tensor<?xf32> {bufferization.writable = true},82    %B : tensor<?xf32> {bufferization.writable = true},83    %lb : index,84    %ub : index,85    %step : index)86  -> (tensor<?xf32>)87{88  // %r0 must be out of place because one use of %t in the subsequent production89  // of %r1 is read.90  //      CHECK: scf.for91  // CHECK-NEXT: call92  // CHECK-SAME: {__inplace_operands_attr__ = ["false"]}93  // CHECK-NEXT: scf.yield94  // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}95  //      CHECK: } {__inplace_operands_attr__ = ["none", "none", "none", "false"]}96  %r0 = scf.for %i = %lb to %ub step %step iter_args(%t = %A) -> (tensor<?xf32>) {97    func.call @some_use(%t) : (tensor<?xf32>) -> ()98    scf.yield %t : tensor<?xf32>99  }100 101  // %r1 bufferizes inplace fine.102  //      CHECK: scf.for103  // CHECK-NEXT: call104  // CHECK-SAME: {__inplace_operands_attr__ = ["false"]}105  // CHECK-NEXT: scf.yield106  // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}107  //      CHECK: } {__inplace_operands_attr__ = ["none", "none", "none", "true"]}108  %r1 = scf.for %i = %lb to %ub step %step iter_args(%t = %A) -> (tensor<?xf32>) {109    func.call @some_use(%t) : (tensor<?xf32>) -> ()110    scf.yield %t : tensor<?xf32>111  }112 113  //      CHECK: return114  // CHECK-SAME: __equivalent_func_args__ = [0]115  return %r1: tensor<?xf32>116}117 118// -----119 120#accesses = [121  affine_map<(i) -> (i)>122]123#trait = {124  indexing_maps = #accesses,125  iterator_types = ["parallel"]126}127 128// CHECK-LABEL: func @reading_scf_for129func.func @reading_scf_for(%t1: tensor<?xf32> {bufferization.writable = true},130                           %s: index, %v: vector<5xf32>) -> (tensor<?xf32>, vector<5xf32>) {131 132  %c0 = arith.constant 0 : index133  %c1 = arith.constant 1 : index134  %cst = arith.constant 0.0 : f32135 136  // Write to %t1.137  // CHECK:      vector.transfer_write138  // CHECK-SAME: __inplace_operands_attr__ = ["none", "false", "none"]139  %t3 = vector.transfer_write %v, %t1[%s] : vector<5xf32>, tensor<?xf32>140 141  // Read the old value of %t1 inside the loop via an alias.142  // CHECK: scf.for {{.*}} {143  %r, %v3 = scf.for %i = %c0 to %s step %c1 iter_args(%t2 = %t1, %v0 = %v) -> (tensor<?xf32>, vector<5xf32>) {144    // CHECK:      tensor.extract_slice145    // CHECK-SAME: __inplace_operands_attr__ = ["true", "none", "none"]146    %e = tensor.extract_slice %t2[%s][%s][1] : tensor<?xf32> to tensor<?xf32>147 148    // Read from %t1 via alias %e.149    %v2 = vector.transfer_read %e[%s], %cst : tensor<?xf32>, vector<5xf32>150    scf.yield %t2, %v2 : tensor<?xf32>, vector<5xf32>151  }152  // CHECK: } {__inplace_operands_attr__ = ["none", "none", "none", "true", "none"]}153 154  // Use %t3 in some way without reading it, so that it does not get DCE'd.155  // CHECK:      linalg.generic156  // CHECK-SAME: __inplace_operands_attr__ = ["true"]157  %o = linalg.generic #trait outs (%t3 : tensor<?xf32>) {158      ^bb(%0: f32) :159        linalg.yield %cst : f32160    } -> (tensor<?xf32>)161 162  return %o, %v3 : tensor<?xf32>, vector<5xf32>163}164 165// -----166 167#accesses = [168  affine_map<(i) -> (i)>169]170#trait = {171  indexing_maps = #accesses,172  iterator_types = ["parallel"]173}174 175// CHECK-LABEL: func @non_reading_scf_for176func.func @non_reading_scf_for(%t1: tensor<?xf32> {bufferization.writable = true},177                               %s: index, %v: vector<5xf32>) -> (tensor<?xf32>, vector<5xf32>) {178 179  %c0 = arith.constant 0 : index180  %c1 = arith.constant 1 : index181  %c10 = arith.constant 10 : index182  %cst = arith.constant 0.0 : f32183 184  // Write to %t1.185  // CHECK:      vector.transfer_write186  // CHECK-SAME: __inplace_operands_attr__ = ["none", "true", "none"]187  %t3 = vector.transfer_write %v, %t1[%s] : vector<5xf32>, tensor<?xf32>188 189  // This loop does not read from %t1. It only writes to it.190  // CHECK:      scf.for191  %r, %v3 = scf.for %i = %c0 to %c10 step %c1 iter_args(%t2 = %t1, %v0 = %v) -> (tensor<?xf32>, vector<5xf32>) {192    // Write to %t1 via %t2. (Overwrite %t3.)193    // CHECK:      linalg.generic194    // CHECK-SAME: __inplace_operands_attr__ = ["true"]195    %o2 = linalg.generic #trait outs (%t2 : tensor<?xf32>) {196        ^bb(%0: f32) :197          linalg.yield %cst : f32198      } -> (tensor<?xf32>)199 200    // Read overwritten value. This is not a read of %t1.201    %v2 = vector.transfer_read %o2[%s], %cst : tensor<?xf32>, vector<5xf32>202    scf.yield %o2, %v2 : tensor<?xf32>, vector<5xf32>203  }204 205  // Use %t3 in some way without reading it, so that it does not get DCE'd.206  // CHECK:      linalg.generic207  // CHECK-SAME: __inplace_operands_attr__ = ["true"]208  %o = linalg.generic #trait outs (%t3 : tensor<?xf32>) {209      ^bb(%0: f32) :210        linalg.yield %cst : f32211    } -> (tensor<?xf32>)212 213  //      CHECK: return214  // CHECK-SAME: __equivalent_func_args__ = [0, -1]215  return %o, %v3 : tensor<?xf32>, vector<5xf32>216}217 218// -----219 220//===----------------------------------------------------------------------===//221// scf.if cases222//===----------------------------------------------------------------------===//223 224// This example passes analysis, but it fails when bufferizing.225// CHECK-LABEL: func @scf_if_inplace1226func.func @scf_if_inplace1(%t1: tensor<?xf32> {bufferization.writable = true},227                           %t2: tensor<?xf32> {bufferization.writable = true},228                           %cond: i1) -> tensor<?xf32> {229  %r = scf.if %cond -> (tensor<?xf32>) {230    // CHECK:      scf.yield231    // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}232    scf.yield %t1 : tensor<?xf32>233  } else {234    // CHECK:      scf.yield235    // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}236    scf.yield %t2 : tensor<?xf32>237  }238  return %r : tensor<?xf32>239}240 241// -----242 243// CHECK-LABEL: func @scf_if_inplace2244func.func @scf_if_inplace2(%t1: tensor<?xf32> {bufferization.writable = true},245                           %v: vector<5xf32>, %idx: index,246                           %cond: i1) -> tensor<?xf32> {247  %r = scf.if %cond -> (tensor<?xf32>) {248    // CHECK:      scf.yield249    // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}250    scf.yield %t1 : tensor<?xf32>251  } else {252    //      CHECK: vector.transfer_write253    // CHECK-SAME: {__inplace_operands_attr__ = ["none", "true", "none"]254    %t2 = vector.transfer_write %v, %t1[%idx] : vector<5xf32>, tensor<?xf32>255    scf.yield %t2 : tensor<?xf32>256  }257  //      CHECK: return258  // CHECK-SAME: __equivalent_func_args__ = [0]259  return %r : tensor<?xf32>260}261 262// -----263 264// CHECK-LABEL: func @scf_if_inplace3265func.func @scf_if_inplace3(%t1: tensor<?xf32> {bufferization.writable = true},266                           %v1: vector<5xf32>, %v2: vector<5xf32>, %idx: index,267                           %cond: i1) -> tensor<?xf32> {268  //      CHECK: tensor.extract_slice269  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "none", "none"]270  %e = tensor.extract_slice %t1[%idx][%idx][1] : tensor<?xf32> to tensor<?xf32>271  %r = scf.if %cond -> (tensor<?xf32>) {272    //      CHECK: vector.transfer_write273    // CHECK-SAME: {__inplace_operands_attr__ = ["none", "true", "none"]274    %t2 = vector.transfer_write %v1, %e[%idx] : vector<5xf32>, tensor<?xf32>275    //      CHECK: scf.yield276    // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}277    scf.yield %t2 : tensor<?xf32>278  } else {279    // Writing the same tensor through an alias. This is OK.280    //      CHECK: vector.transfer_write281    // CHECK-SAME: {__inplace_operands_attr__ = ["none", "true", "none"]282    %t3 = vector.transfer_write %v2, %t1[%idx] : vector<5xf32>, tensor<?xf32>283    //      CHECK: scf.yield284    // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}285    scf.yield %t3 : tensor<?xf32>286  }287  return %r : tensor<?xf32>288}289 290// -----291 292// CHECK-LABEL: func @scf_if_in_place4293func.func @scf_if_in_place4(%t1: tensor<?xf32> {bufferization.writable = true},294                            %v: vector<5xf32>, %idx: index,295                            %cond: i1, %cond2: i1) -> (tensor<?xf32>, vector<10xf32>) {296  %cst = arith.constant 0.0 : f32297  %r = scf.if %cond -> (tensor<?xf32>) {298    //      CHECK: scf.yield299    // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}300    scf.yield %t1 : tensor<?xf32>301  } else {302    //      CHECK: vector.transfer_write303    // CHECK-SAME: {__inplace_operands_attr__ = ["none", "true", "none"]304    %t2 = vector.transfer_write %v, %t1[%idx] : vector<5xf32>, tensor<?xf32>305    //      CHECK: scf.yield306    // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}307    scf.yield %t2 : tensor<?xf32>308  }309  %r_alias = scf.if %cond2 -> (tensor<?xf32>) {310    // Reading %r is OK. No conflict.311    //      CHECK: scf.yield312    // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}313    scf.yield %r : tensor<?xf32>314  } else {315    //      CHECK: scf.yield316    // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}317    scf.yield %r : tensor<?xf32>318  }319  %v2 = vector.transfer_read %r_alias[%idx], %cst : tensor<?xf32>, vector<10xf32>320 321  //      CHECK: return322  // CHECK-SAME: __equivalent_func_args__ = [0, -1]323  return %r_alias, %v2 : tensor<?xf32>, vector<10xf32>324}325 326// -----327 328// CHECK-LABEL: func @scf_if_inplace5329func.func @scf_if_inplace5(%t1: tensor<?xf32> {bufferization.writable = true},330                           %idx: index, %cond: i1) -> tensor<?xf32> {331  %r = scf.if %cond -> (tensor<?xf32>) {332    //      CHECK: tensor.extract_slice333    // CHECK-SAME: {__inplace_operands_attr__ = ["true", "none", "none"]334    %e = tensor.extract_slice %t1[%idx][%idx][1] : tensor<?xf32> to tensor<?xf32>335    //      CHECK: scf.yield336    // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}337    scf.yield %e : tensor<?xf32>338  } else {339    //      CHECK: tensor.extract_slice340    // CHECK-SAME: {__inplace_operands_attr__ = ["true", "none", "none"]341    %f = tensor.extract_slice %t1[%idx][%idx][1] : tensor<?xf32> to tensor<?xf32>342    //      CHECK: scf.yield343    // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}344    scf.yield %f : tensor<?xf32>345  }346 347  // Inserting into an equivalent tensor at the same offset. This bufferizes348  // inplace.349  //      CHECK: tensor.insert_slice350  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "true", "none", "none"]351  %r2 = tensor.insert_slice %r into %t1[%idx][%idx][1] : tensor<?xf32> into tensor<?xf32>352 353  //      CHECK: return354  // CHECK-SAME: __equivalent_func_args__ = [0]355  return %r2 : tensor<?xf32>356}357 358// -----359 360// CHECK-LABEL: func @scf_if_inplace6361func.func @scf_if_inplace6(%t1: tensor<?xf32> {bufferization.writable = true},362                           %v1: vector<5xf32>, %v2: vector<5xf32>,363                           %v3: vector<5xf32>, %idx: index,364                           %cond: i1, %cond2: i1) -> tensor<?xf32> {365  // Test nested scf.if ops.366  %r = scf.if %cond -> (tensor<?xf32>) {367    %t2 = scf.if %cond2 -> (tensor<?xf32>) {368      //      CHECK: vector.transfer_write369      // CHECK-SAME: {__inplace_operands_attr__ = ["none", "true", "none"]370      %t3 = vector.transfer_write %v1, %t1[%idx] : vector<5xf32>, tensor<?xf32>371      //      CHECK: scf.yield372      // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}373      scf.yield %t3 : tensor<?xf32>374    } else {375      //      CHECK: vector.transfer_write376      // CHECK-SAME: {__inplace_operands_attr__ = ["none", "true", "none"]377      %t4 = vector.transfer_write %v3, %t1[%idx] : vector<5xf32>, tensor<?xf32>378      //      CHECK: scf.yield379      // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}380      scf.yield %t4 : tensor<?xf32>381    }382    //      CHECK: scf.yield383    // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}384    scf.yield %t2 : tensor<?xf32>385  } else {386    //      CHECK: vector.transfer_write387    // CHECK-SAME: {__inplace_operands_attr__ = ["none", "true", "none"]388    %t3 = vector.transfer_write %v2, %t1[%idx] : vector<5xf32>, tensor<?xf32>389    //      CHECK: scf.yield390    // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}391    scf.yield %t3 : tensor<?xf32>392  }393 394  //      CHECK: return395  // CHECK-SAME: __equivalent_func_args__ = [0]396  return %r : tensor<?xf32>397}398 399// -----400 401// CHECK-LABEL: func @scf_if_inplace7402func.func @scf_if_inplace7(%t1: tensor<?xf32> {bufferization.writable = true},403                           %v1: vector<5xf32>, %v2: vector<5xf32>, %idx: index,404                           %idx2: index, %cond: i1) -> (tensor<?xf32>, vector<5xf32>) {405  %cst = arith.constant 0.0 : f32406  %r, %v_r2 = scf.if %cond -> (tensor<?xf32>, vector<5xf32>) {407    //      CHECK: vector.transfer_write408    // CHECK-SAME: {__inplace_operands_attr__ = ["none", "true", "none"]409    %t2 = vector.transfer_write %v1, %t1[%idx] : vector<5xf32>, tensor<?xf32>410    //      CHECK: scf.yield411    // CHECK-SAME: {__inplace_operands_attr__ = ["true", "none"]}412    scf.yield %t2, %v1 : tensor<?xf32>, vector<5xf32>413  } else {414    // Writing the same tensor through an alias.415    //      CHECK: vector.transfer_write416    // CHECK-SAME: {__inplace_operands_attr__ = ["none", "false", "none"]417    %t3 = vector.transfer_write %v2, %t1[%idx] : vector<5xf32>, tensor<?xf32>418    // Read the original value of %t1. This requires the write in this branch419    // to be out-of-place. But the write in the other branch can still be420    // inplace.421    %v_r = vector.transfer_read %t1[%idx2], %cst : tensor<?xf32>, vector<5xf32>422    //      CHECK: scf.yield423    // CHECK-SAME: {__inplace_operands_attr__ = ["true", "none"]}424    scf.yield %t3, %v_r : tensor<?xf32>, vector<5xf32>425  }426  return %r, %v_r2 : tensor<?xf32>, vector<5xf32>427}428 429// -----430 431// CHECK-LABEL: func @scf_if_out_of_place1a432func.func @scf_if_out_of_place1a(%t1: tensor<?xf32> {bufferization.writable = true},433                                 %idx: index, %idx2: index,434                                 %cond: i1) -> tensor<?xf32> {435  %r = scf.if %cond -> (tensor<?xf32>) {436    //      CHECK: tensor.extract_slice437    // CHECK-SAME: {__inplace_operands_attr__ = ["true", "none", "none"]438    %e = tensor.extract_slice %t1[%idx][%idx][1] : tensor<?xf32> to tensor<?xf32>439    //      CHECK: scf.yield440    // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}441    scf.yield %e : tensor<?xf32>442  } else {443    //      CHECK: scf.yield444    // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}445    scf.yield %t1 : tensor<?xf32>446  }447 448  // Reading from and writing to the same tensor via different args. This is a449  // conflict.450  //      CHECK: tensor.insert_slice451  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "false", "none", "none"]452  %r2 = tensor.insert_slice %r into %t1[%idx2][%idx2][1] : tensor<?xf32> into tensor<?xf32>453  return %r2 : tensor<?xf32>454}455 456// -----457 458// CHECK-LABEL: func @scf_if_out_of_place1b459func.func @scf_if_out_of_place1b(%t1: tensor<?xf32> {bufferization.writable = true},460                                 %idx: index, %idx2: index, %idx3: index,461                                 %cond: i1) -> tensor<?xf32> {462  %r = scf.if %cond -> (tensor<?xf32>) {463    //      CHECK: tensor.extract_slice464    // CHECK-SAME: {__inplace_operands_attr__ = ["false", "none", "none"]465    %e = tensor.extract_slice %t1[%idx][%idx][1] : tensor<?xf32> to tensor<?xf32>466    //      CHECK: scf.yield467    // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}468    scf.yield %e : tensor<?xf32>469  } else {470    //      CHECK: tensor.extract_slice471    // CHECK-SAME: {__inplace_operands_attr__ = ["false", "none", "none"]472    %f = tensor.extract_slice %t1[%idx2][%idx2][1] : tensor<?xf32> to tensor<?xf32>473    //      CHECK: scf.yield474    // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}475    scf.yield %f : tensor<?xf32>476  }477 478  // Reading from and writing to the same tensor via different args. This is a479  // conflict. In contrast to scf_if_out_of_place1a, the fact that %r aliases480  // with %t1 is only detected when analyzing the tensor.extract_slices. That's481  // why the tensor.insert_slice is inplace and the two extract_slices are482  // out-of-place.483  //      CHECK: tensor.insert_slice484  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "true", "none", "none"]485  %r2 = tensor.insert_slice %r into %t1[%idx3][%idx3][1] : tensor<?xf32> into tensor<?xf32>486 487  //      CHECK: return488  // CHECK-SAME: __equivalent_func_args__ = [0]489  return %r2 : tensor<?xf32>490}491 492// -----493 494// CHECK-LABEL: func @scf_if_out_of_place1c495func.func @scf_if_out_of_place1c(%t1: tensor<?xf32> {bufferization.writable = true},496                                 %idx: index, %idx2: index, %cond: i1) -> tensor<?xf32> {497  %r = scf.if %cond -> (tensor<?xf32>) {498    //      CHECK: tensor.extract_slice499    // CHECK-SAME: {__inplace_operands_attr__ = ["false", "none", "none"]500    %e = tensor.extract_slice %t1[%idx][%idx][1] : tensor<?xf32> to tensor<?xf32>501    //      CHECK: scf.yield502    // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}503    scf.yield %e : tensor<?xf32>504  } else {505    // TODO: This one could bufferize inplace, but the analysis is too restrictive.506    //      CHECK: tensor.extract_slice507    // CHECK-SAME: {__inplace_operands_attr__ = ["false", "none", "none"]508    %f = tensor.extract_slice %t1[%idx2][%idx2][1] : tensor<?xf32> to tensor<?xf32>509    //      CHECK: scf.yield510    // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}511    scf.yield %f : tensor<?xf32>512  }513 514  //      CHECK: tensor.insert_slice515  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "true", "none", "none"]516  %r2 = tensor.insert_slice %r into %t1[%idx2][%idx2][1] : tensor<?xf32> into tensor<?xf32>517 518  //      CHECK: return519  // CHECK-SAME: __equivalent_func_args__ = [0]520  return %r2 : tensor<?xf32>521}522 523// -----524 525// CHECK-LABEL: func @scf_if_out_of_place2526func.func @scf_if_out_of_place2(%t1: tensor<?xf32> {bufferization.writable = true},527                                %v: vector<5xf32>, %idx: index,528                                %cond: i1) -> (tensor<?xf32>, vector<10xf32>) {529  %cst = arith.constant 0.0 : f32530  %r = scf.if %cond -> (tensor<?xf32>) {531    scf.yield %t1 : tensor<?xf32>532  } else {533    //      CHECK: vector.transfer_write534    // CHECK-SAME: {__inplace_operands_attr__ = ["none", "false", "none"]535    %t2 = vector.transfer_write %v, %t1[%idx] : vector<5xf32>, tensor<?xf32>536    //      CHECK: scf.yield537    // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}538    scf.yield %t2 : tensor<?xf32>539  }540 541  // Read the old value of %t1. Forces the transfer_write to bufferize542  // out-of-place.543  %v2 = vector.transfer_read %t1[%idx], %cst : tensor<?xf32>, vector<10xf32>544  return %r, %v2 : tensor<?xf32>, vector<10xf32>545}546 547// -----548 549// CHECK-LABEL: func @scf_if_out_of_place3550func.func @scf_if_out_of_place3(%t1: tensor<?xf32> {bufferization.writable = true},551                                %v: vector<5xf32>, %idx: index,552                                %cond: i1, %cond2: i1) -> (tensor<?xf32>, vector<10xf32>) {553  %cst = arith.constant 0.0 : f32554  %r = scf.if %cond -> (tensor<?xf32>) {555    scf.yield %t1 : tensor<?xf32>556  } else {557    //      CHECK: vector.transfer_write558    // CHECK-SAME: {__inplace_operands_attr__ = ["none", "false", "none"]559    %t2 = vector.transfer_write %v, %t1[%idx] : vector<5xf32>, tensor<?xf32>560    //      CHECK: scf.yield561    // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}562    scf.yield %t2 : tensor<?xf32>563  }564  %t1_alias = scf.if %cond2 -> (tensor<?xf32>) {565    // scf.yield bufferizes to a read. That is a conflict in this example.566    //      CHECK: scf.yield567    // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}568    scf.yield %t1 : tensor<?xf32>569  } else {570    //      CHECK: scf.yield571    // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}572    scf.yield %t1 : tensor<?xf32>573  }574  %v2 = vector.transfer_read %t1_alias[%idx], %cst : tensor<?xf32>, vector<10xf32>575  return %r, %v2 : tensor<?xf32>, vector<10xf32>576}577 578// -----579 580// CHECK-LABEL: func @write_to_same_tensor_in_loop_in_place(581func.func @write_to_same_tensor_in_loop_in_place(582    %A : tensor<?xf32> {bufferization.writable = true},583    %lb : index, %ub : index, %step : index, %sz: index)584  -> (tensor<?xf32>)585{586  // CHECK: scf.for {{.*}} {587  %r0 = scf.for %i = %lb to %ub step %step iter_args(%t = %A) -> (tensor<?xf32>) {588    %B = bufferization.alloc_tensor(%sz) : tensor<?xf32>589    %i2 = arith.index_cast %i : index to i32590    %i3 = arith.sitofp %i2 : i32 to f32591    // The tensor.insert is in-place because the %B is defined inside the loop.592    //      CHECK: tensor.insert593    // CHECK-SAME:   {__inplace_operands_attr__ = ["none", "true", "none"]}594    %B2 = tensor.insert %i3 into %B[%i] : tensor<?xf32>595    //      CHECK: tensor.insert_slice596    // CHECK-SAME:   {__inplace_operands_attr__ = ["true", "true", "none", "none"]}597    %A2 = tensor.insert_slice %B2 into %t[%i][%sz][1] : tensor<?xf32> into tensor<?xf32>598    scf.yield %A2 : tensor<?xf32>599  }600  // CHECK: } {__inplace_operands_attr__ = ["none", "none", "none", "true"]}601 602  return %r0 : tensor<?xf32>603}604 605// -----606 607// This is a regression test. Everything can bufferize in-place because %7 and608// %arg1 are in the same repetitive region.609 610// CHECK-LABEL: func @same_enclosing_repetitive_region611func.func @same_enclosing_repetitive_region(%2: tensor<320xf32>,612                                            %3: tensor<320x10240xf32>)613  -> tensor<320xf32>614{615  %c0 = arith.constant 0 : index616  %cst = arith.constant -0.000000e+00 : f32617  %c320 = arith.constant 320 : index618  %4 = scf.forall (%arg0) in (%c320) shared_outs(%arg1 = %2) -> (tensor<320xf32>) {619    // CHECK: tensor.extract_slice {{.*}} {__inplace_operands_attr__ = ["true", "none"]}620    %5 = tensor.extract_slice %3[%arg0, 0] [1, 10240] [1, 1]  : tensor<320x10240xf32> to tensor<1x10240xf32>621    // CHECK: tensor.extract_slice {{.*}} {__inplace_operands_attr__ = ["true", "none"]}622    %6 = tensor.extract_slice %arg1[%arg0] [1] [1] : tensor<320xf32> to tensor<1xf32>623    // CHECK: linalg.fill {__inplace_operands_attr__ = ["none", "true"]}624    %7 = linalg.fill ins(%cst : f32) outs(%6 : tensor<1xf32>) -> tensor<1xf32>625    // CHECK: linalg.fill {__inplace_operands_attr__ = ["none", "true"]}626    %8 = linalg.fill ins(%cst : f32) outs(%7 : tensor<1xf32>) -> tensor<1xf32>627 628    scf.forall.in_parallel {629      // CHECK: tensor.parallel_insert_slice {{.*}} {__inplace_operands_attr__ = ["true", "true", "none"]}630      tensor.parallel_insert_slice %8 into %arg1[%arg0] [1] [1] : tensor<1xf32> into tensor<320xf32>631    }632  }633  return %4 : tensor<320xf32>634}635 636// -----637 638// CHECK-LABEL: different_repetitive_region_via_alias639func.func @different_repetitive_region_via_alias(%arg0: tensor<4xf32>,640                                                 %arg1: tensor<4xf32>,641                                                 %arg2: index,642                                                 %arg3: index,643                                                 %arg4: index)644  -> (tensor<4xf32>)645{646  %cst = arith.constant 0.000000e+00 : f32647  %cst2 = arith.constant 1.000000e+00 : f32648  %0 = bufferization.alloc_tensor() : tensor<4xf32>649 650  // CHECK: linalg.fill {__inplace_operands_attr__ = ["none", "false"]}651  %1 = linalg.fill ins(%cst : f32) outs(%0 : tensor<4xf32>) -> tensor<4xf32>652 653  %2 = scf.for %arg5 = %arg2 to %arg3 step %arg4 iter_args(%arg6 = %arg1) -> (tensor<4xf32>) {654    // CHECK: tensor.extract {{.*}} {__inplace_operands_attr__ = ["true", "none"]}655    %4 = tensor.extract %1[%arg4] : tensor<4xf32>656    vector.print %4 : f32657    // CHECK: linalg.fill {__inplace_operands_attr__ = ["none", "true"]}658    %5 = linalg.fill ins(%cst2 : f32) outs(%0 : tensor<4xf32>) -> tensor<4xf32>659    scf.yield %5 : tensor<4xf32>660  }661 662  return %2 : tensor<4xf32>663}664 665// -----666 667// CHECK-LABEL: no_raw_conflict_after_repetitive_use668func.func @no_raw_conflict_after_repetitive_use(%arg0: tensor<4xf32>,669                                                %arg1: tensor<4xf32>,670                                                %arg2: index,671                                                %arg3: index,672                                                %arg4: index)673  -> (tensor<4xf32>, tensor<4xf32>)674{675  %cst = arith.constant 0.000000e+00 : f32676  %cst2 = arith.constant 1.000000e+00 : f32677  %cst3 = arith.constant 2.000000e+00 : f32678  %0 = bufferization.alloc_tensor() : tensor<4xf32>679 680  // CHECK: linalg.fill {__inplace_operands_attr__ = ["none", "true"]}681  %1 = linalg.fill ins(%cst : f32) outs(%0 : tensor<4xf32>) -> tensor<4xf32>682 683  %2 = scf.for %arg5 = %arg2 to %arg3 step %arg4 iter_args(%arg6 = %arg1) -> (tensor<4xf32>) {684    // CHECK: tensor.extract {{.*}} {__inplace_operands_attr__ = ["true", "none"]}685    %4 = tensor.extract %1[%arg4] : tensor<4xf32>686    vector.print %4 : f32687    // CHECK: linalg.fill {__inplace_operands_attr__ = ["none", "false"]}688    %5 = linalg.fill ins(%cst2 : f32) outs(%1 : tensor<4xf32>) -> tensor<4xf32>689    scf.yield %5 : tensor<4xf32>690  }691 692  // The following is *not* a RaW conflict.693  // CHECK: tensor.extract {{.*}} {__inplace_operands_attr__ = ["true", "none"]}694  %6 = tensor.extract %1[%arg4] : tensor<4xf32>695  vector.print %6 : f32696  // CHECK: linalg.fill {__inplace_operands_attr__ = ["none", "true"]}697  %7 = linalg.fill ins(%cst3 : f32) outs(%1 : tensor<4xf32>) -> tensor<4xf32>698 699  return %2, %7 : tensor<4xf32>, tensor<4xf32>700}701 702// -----703 704// CHECK-LABEL: func @read_of_bbarg_in_repetitive_region(705func.func @read_of_bbarg_in_repetitive_region(706    %t: tensor<10xf32>, %a: index, %b: index, %c: index, %cst: f32) {707  // CHECK: scf.for708  scf.for %iv = %a to %b step %c {709    // Must bufferize out-of-place because definition of read is in a different710    // repetitive region.711    // CHECK: tensor.extract_slice {{.*}} {__inplace_operands_attr__ = ["true"]}712    %2 = tensor.extract_slice %t[0][4][1] : tensor<10xf32> to tensor<4xf32>713    %3 = tensor.extract %2[%a] : tensor<4xf32>714    vector.print %3 : f32715    // CHECK: tensor.insert {{.*}} {__inplace_operands_attr__ = ["none", "false", "none"]}716    %4 = tensor.insert %cst into %2[%a] : tensor<4xf32>717    %5 = tensor.extract %4[%a] : tensor<4xf32>718    vector.print %5 : f32719  }720  return721}722 723// -----724 725// CHECK-LABEL: func @read_definition_in_same_repetitive_region_as_write(726func.func @read_definition_in_same_repetitive_region_as_write(727    %t: tensor<10xf32>, %a: index, %b: index, %c: index, %cst: f32) {728  // CHECK: tensor.insert {{.*}} {__inplace_operands_attr__ = ["none", "true", "none"]}729  %1 = tensor.insert %cst into %t[%a] : tensor<10xf32>730  // CHECK: scf.for731  scf.for %iv = %a to %b step %c {732    // Can bufferize in-place.733    // CHECK: tensor.extract_slice {{.*}} {__inplace_operands_attr__ = ["true"]}734    %2 = tensor.extract_slice %1[0][4][1] : tensor<10xf32> to tensor<4xf32>735    %3 = tensor.extract %2[%a] : tensor<4xf32>736    vector.print %3 : f32737  }738  return739}740 741// -----742 743// CHECK-LABEL: func @read_definition_in_same_repetitive_region_as_conflicting_write(744func.func @read_definition_in_same_repetitive_region_as_conflicting_write(745    %t: tensor<10xf32>, %a: index, %b: index, %c: index, %cst: f32) {746  // Cannot bufferize in-place according to normal op dominance rules.747  // CHECK: tensor.insert {{.*}} {__inplace_operands_attr__ = ["none", "false", "none"]}748  %1 = tensor.insert %cst into %t[%a] : tensor<10xf32>749  // CHECK: scf.for750  scf.for %iv = %a to %b step %c {751    // CHECK: tensor.extract_slice {{.*}} {__inplace_operands_attr__ = ["true"]}752    %2 = tensor.extract_slice %t[0][4][1] : tensor<10xf32> to tensor<4xf32>753    %3 = tensor.extract %2[%a] : tensor<4xf32>754    vector.print %3 : f32755  }756  return757}758 759// -----760 761// CHECK: func @write_value_in_repetitive_region(762func.func @write_value_in_repetitive_region(763    %t: tensor<10xf32>, %a: index, %b: index, %c: index, %cst: f32) {764  %0 = tensor.extract %t[%a] : tensor<10xf32>765  vector.print %0 : f32766 767  scf.for %iv = %a to %b step %c {768    // No further read of %0, so this can bufferize in-place.769    // CHECK: tensor.extract_slice {{.*}} {__inplace_operands_attr__ = ["true"]}770    %2 = tensor.extract_slice %t[0][4][1] : tensor<10xf32> to tensor<4xf32>771    // CHECK: linalg.fill {__inplace_operands_attr__ = ["none", "true"]}772    %filled = linalg.fill ins(%cst : f32) outs(%2 : tensor<4xf32>) -> tensor<4xf32>773    %3 = tensor.extract %filled[%a] : tensor<4xf32>774    vector.print %3 : f32775  }776  return777}778 779// -----780 781// CHECK-LABEL: func @nesting_op_repetitive_regions(782func.func @nesting_op_repetitive_regions(783    %t: tensor<10xf32>, %a: index, %b: index, %c: index, %cst: f32) {784  // Cannot bufferize in-place according to normal op dominance rules.785  // CHECK: tensor.insert {{.*}} {__inplace_operands_attr__ = ["none", "false", "none"]}786  %1 = tensor.insert %cst into %t[%a] : tensor<10xf32>787  // CHECK: scf.for788  scf.for %iv1 = %a to %b step %c {789    // CHECK: scf.for790    scf.for %iv2 = %a to %b step %c {791      // CHECK: scf.for792      scf.for %iv3 = %a to %b step %c {793        // CHECK: tensor.extract_slice {{.*}} {__inplace_operands_attr__ = ["true"]}794        %2 = tensor.extract_slice %t[0][4][1] : tensor<10xf32> to tensor<4xf32>795        %3 = tensor.extract %2[%a] : tensor<4xf32>796        vector.print %3 : f32797      }798    }799  }800  return801}802 803// -----804 805// CHECK-LABEL: func @parallel_region()806func.func @parallel_region() -> tensor<320xf32>807{808  %alloc0 = bufferization.alloc_tensor() : tensor<320xf32>809  %alloc1 = bufferization.alloc_tensor() : tensor<1xf32>810  %c320 = arith.constant 320 : index811  // CHECK: scf.forall812  %0 = scf.forall (%arg0) in (%c320) shared_outs(%arg1 = %alloc0) -> (tensor<320xf32>) {813    %val = "test.foo"() : () -> (f32)814    // linalg.fill must bufferize out-of-place because every thread needs a815    // private copy of %alloc1. If not accounting for parallel regions, the fill816    // can bufferize in place.817    // PARALLEL-CHECK:    linalg.fill {__inplace_operands_attr__ = ["none", "false"]}818    // NO-PARALLEL-CHECK: linalg.fill {__inplace_operands_attr__ = ["none", "true"]}819    %fill = linalg.fill ins(%val : f32) outs(%alloc1 : tensor<1xf32>) -> tensor<1xf32>820    scf.forall.in_parallel {821      // CHECK: tensor.parallel_insert_slice {{.*}} {__inplace_operands_attr__ = ["true", "true", "none"]}822      tensor.parallel_insert_slice %fill into %arg1[%arg0] [1] [1] : tensor<1xf32> into tensor<320xf32>823    }824  }825  // CHECK: } {__inplace_operands_attr__ = ["none", "true"]}826  return %0 : tensor<320xf32>827}828 829// -----830 831// CHECK-LABEL: func @parallel_region_mixed_def(832func.func @parallel_region_mixed_def(%c: i1) -> tensor<320xf32>833{834  %alloc0 = bufferization.alloc_tensor() : tensor<320xf32>835  %alloc1 = bufferization.alloc_tensor() : tensor<1xf32>836  %c320 = arith.constant 320 : index837  // CHECK: scf.forall838  %0 = scf.forall (%arg0) in (%c320) shared_outs(%arg1 = %alloc0) -> (tensor<320xf32>) {839    %alloc2 = bufferization.alloc_tensor() : tensor<1xf32>840    %selected = scf.if %c -> tensor<1xf32> {841      scf.yield %alloc1 : tensor<1xf32>842    } else {843      scf.yield %alloc2 : tensor<1xf32>844    }845    %val = "test.foo"() : () -> (f32)846    // linalg.fill must bufferize out-of-place because every thread needs a847    // private copy of %alloc1. If not accounting for parallel regions, the fill848    // can bufferize in place.849    // PARALLEL-CHECK: linalg.fill {__inplace_operands_attr__ = ["none", "false"]}850    // NO-PARALLEL-CHECK: linalg.fill {__inplace_operands_attr__ = ["none", "true"]}851    %fill = linalg.fill ins(%val : f32) outs(%selected : tensor<1xf32>) -> tensor<1xf32>852    scf.forall.in_parallel {853      // CHECK: tensor.parallel_insert_slice {{.*}} {__inplace_operands_attr__ = ["true", "true", "none"]}854      tensor.parallel_insert_slice %fill into %arg1[%arg0] [1] [1] : tensor<1xf32> into tensor<320xf32>855    }856  }857  // CHECK: } {__inplace_operands_attr__ = ["none", "true"]}858  return %0 : tensor<320xf32>859}860 861// -----862 863// CHECK-LABEL: func @parallel_region_two_writes(864func.func @parallel_region_two_writes(%f: f32) -> tensor<320xf32>865{866  %alloc0 = bufferization.alloc_tensor() : tensor<320xf32>867  %alloc1 = bufferization.alloc_tensor() : tensor<1xf32>868  %c320 = arith.constant 320 : index869  %c0 = arith.constant 0 : index870  // CHECK: scf.forall871  %0 = scf.forall (%arg0) in (%c320) shared_outs(%arg1 = %alloc0) -> (tensor<320xf32>) {872    %val = "test.foo"() : () -> (f32)873    // linalg.fill must bufferize out-of-place because every thread needs a874    // private copy of %alloc1. If not accounting for parallel regions, the fill875    // can bufferize in place.876    // PARALLEL-CHECK: linalg.fill {__inplace_operands_attr__ = ["none", "false"]}877    // NO-PARALLEL-CHECK: linalg.fill {__inplace_operands_attr__ = ["none", "true"]}878    %fill = linalg.fill ins(%val : f32) outs(%alloc1 : tensor<1xf32>) -> tensor<1xf32>879    // CHECK: tensor.insert880    // CHECK-SAME: __inplace_operands_attr__ = ["none", "true", "none"]881    %inserted = tensor.insert %f into %fill[%c0] : tensor<1xf32>882 883    scf.forall.in_parallel {884      // CHECK: tensor.parallel_insert_slice {{.*}} {__inplace_operands_attr__ = ["true", "true", "none"]}885      tensor.parallel_insert_slice %inserted into %arg1[%arg0] [1] [1] : tensor<1xf32> into tensor<320xf32>886    }887  }888  // CHECK: } {__inplace_operands_attr__ = ["none", "true"]}889  return %0 : tensor<320xf32>890}891 892// -----893 894// CHECK-LABEL: func @parallel_region_no_read()895func.func @parallel_region_no_read()896{897  %alloc0 = bufferization.alloc_tensor() : tensor<320xf32>898  %alloc1 = bufferization.alloc_tensor() : tensor<1xf32>899  %c320 = arith.constant 320 : index900  // CHECK: scf.forall901  scf.forall (%arg0) in (%c320) {902    %val = "test.foo"() : () -> (f32)903    // linalg.fill can bufferize in-place because no alias of %alloc1 is read.904    // CHECK: linalg.fill {__inplace_operands_attr__ = ["none", "true"]}905    %fill = linalg.fill ins(%val : f32) outs(%alloc1 : tensor<1xf32>) -> tensor<1xf32>906    scf.forall.in_parallel {907    }908  }909  return910}911 912// -----913 914// CHECK-LABEL: func @in_order_multiple_parallel_writes915func.func @in_order_multiple_parallel_writes(%2: tensor<320xf32> {bufferization.writable = true},916                                            %3: tensor<320xf32> {bufferization.writable = true})917  -> (tensor<320xf32>, tensor<320xf32>)918{919  %c0 = arith.constant 0 : index920  %cst = arith.constant -0.000000e+00 : f32921  %c320 = arith.constant 320 : index922  %4:2 = scf.forall (%arg0) in (%c320) shared_outs(%arg1 = %2, %arg2 = %3) -> (tensor<320xf32>, tensor<320xf32>) {923    // CHECK: tensor.extract_slice {{.*}} {__inplace_operands_attr__ = ["true", "none"]}924    %6 = tensor.extract_slice %arg1[%arg0] [1] [1] : tensor<320xf32> to tensor<1xf32>925    // CHECK: tensor.extract_slice {{.*}} {__inplace_operands_attr__ = ["true", "none"]}926    %7 = tensor.extract_slice %arg2[%arg0] [1] [1] : tensor<320xf32> to tensor<1xf32>927    // CHECK: linalg.fill {__inplace_operands_attr__ = ["none", "true"]}928    %8 = linalg.fill ins(%cst : f32) outs(%7 : tensor<1xf32>) -> tensor<1xf32>929 930    // CHECK: tensor.parallel_insert_slice {{.*}} {__inplace_operands_attr__ = ["true", "true", "none"]}931    // CHECK: tensor.parallel_insert_slice {{.*}} {__inplace_operands_attr__ = ["true", "true", "none"]}932    scf.forall.in_parallel {933      tensor.parallel_insert_slice %6 into %arg2[%arg0] [1] [1] : tensor<1xf32> into tensor<320xf32>934      tensor.parallel_insert_slice %8 into %arg1[%arg0] [1] [1] : tensor<1xf32> into tensor<320xf32>935    }936  }937  return %4#0, %4#1 : tensor<320xf32>, tensor<320xf32>938}939 940// -----941 942// CHECK-LABEL: func @out_of_order_parallel_write943func.func @out_of_order_parallel_write(%2: tensor<320xf32> {bufferization.writable = true},944                                       %3: tensor<320xf32> {bufferization.writable = true})945  -> (tensor<320xf32>, tensor<320xf32>)946{947  %c0 = arith.constant 0 : index948  %cst = arith.constant -0.000000e+00 : f32949  %c320 = arith.constant 320 : index950  %4:2 = scf.forall (%arg0) in (%c320) shared_outs(%arg1 = %2, %arg2 = %3) -> (tensor<320xf32>, tensor<320xf32>) {951    // The extract_slice cannot operate in place because it is used after the952    // first write.953    // CHECK: tensor.extract_slice {{.*}} {__inplace_operands_attr__ = ["true", "none"]}954    %6 = tensor.extract_slice %arg1[%arg0] [1] [1] : tensor<320xf32> to tensor<1xf32>955 956    // Additionally the fill aliases the thread local slice.957    // CHECK: linalg.fill {__inplace_operands_attr__ = ["none", "false"]}958    %7 = linalg.fill ins(%cst : f32) outs(%6 : tensor<1xf32>) -> tensor<1xf32>959 960    scf.forall.in_parallel {961      // CHECK: tensor.parallel_insert_slice {{.*}} {__inplace_operands_attr__ = ["true", "true", "none"]}962      tensor.parallel_insert_slice %7 into %arg1[%arg0] [1] [1] : tensor<1xf32> into tensor<320xf32>963      // CHECK: tensor.parallel_insert_slice {{.*}} {__inplace_operands_attr__ = ["true", "true", "none"]}964      tensor.parallel_insert_slice %6 into %arg2[%arg0] [1] [1] : tensor<1xf32> into tensor<320xf32>965    }966  }967  return %4#0, %4#1 : tensor<320xf32>, tensor<320xf32>968}969 970// -----971 972// CHECK-LABEL: func @out_of_order_parallel_write973func.func @out_of_order_parallel_write_multiple_reads(%2: tensor<320xf32> {bufferization.writable = true},974                                                      %3: tensor<320xf32> {bufferization.writable = true})975  -> (tensor<320xf32>, tensor<320xf32>)976{977  %c0 = arith.constant 0 : index978  %cst = arith.constant -0.000000e+00 : f32979  %c320 = arith.constant 320 : index980  %4:2 = scf.forall (%arg0) in (%c320) shared_outs(%arg1 = %2, %arg2 = %3) -> (tensor<320xf32>, tensor<320xf32>) {981    // CHECK: tensor.extract_slice {{.*}} {__inplace_operands_attr__ = ["false", "none"]}982    %6 = tensor.extract_slice %arg1[%arg0] [1] [1] : tensor<320xf32> to tensor<1xf32>983    // CHECK: linalg.fill {__inplace_operands_attr__ = ["none", "true"]}984    %7 = linalg.fill ins(%cst : f32) outs(%6 : tensor<1xf32>) -> tensor<1xf32>985 986    %reverse = arith.subi %c320, %arg0 : index987    // CHECK: tensor.extract_slice {{.*}} {__inplace_operands_attr__ = ["true", "none"]}988    %8 = tensor.extract_slice %arg1[%reverse] [1] [1] : tensor<320xf32> to tensor<1xf32>989    scf.forall.in_parallel {990      // Also cannot operate in place due to subsequent conflicting reads.991      // CHECK: tensor.parallel_insert_slice {{.*}} {__inplace_operands_attr__ = ["true", "true", "none"]}992      tensor.parallel_insert_slice %7 into %arg1[%arg0] [1] [1] : tensor<1xf32> into tensor<320xf32>993      // CHECK: tensor.parallel_insert_slice {{.*}} {__inplace_operands_attr__ = ["true", "true", "none"]}994      tensor.parallel_insert_slice %8 into %arg2[%reverse] [1] [1] : tensor<1xf32> into tensor<320xf32>995    }996  }997  return %4#0, %4#1 : tensor<320xf32>, tensor<320xf32>998}999// -----1000 1001// CHECK-LABEL: func @in_order_multiple_parallel_writes1002func.func @in_order_multiple_parallel_writes(%2: tensor<320xf32> {bufferization.writable = true})1003  -> (tensor<320xf32>)1004{1005  %c0 = arith.constant 0 : index1006  %cst = arith.constant -0.000000e+00 : f321007  %c320 = arith.constant 320 : index1008  %4 = scf.forall (%arg0) in (%c320) shared_outs(%arg1 = %2) -> (tensor<320xf32>) {1009    // CHECK: tensor.extract_slice {{.*}} {__inplace_operands_attr__ = ["true", "none"]}1010    %6 = tensor.extract_slice %arg1[%arg0] [1] [1] : tensor<320xf32> to tensor<1xf32>1011    %reverse = arith.subi %c320, %arg0 : index1012    // CHECK: tensor.parallel_insert_slice {{.*}} {__inplace_operands_attr__ = ["true", "true", "none"]}1013    scf.forall.in_parallel {1014      tensor.parallel_insert_slice %6 into %arg1[%reverse] [1] [1] : tensor<1xf32> into tensor<320xf32>1015    }1016  }1017  return %4 : tensor<320xf32>1018} 1019