brintos

brintos / llvm-project-archived public Read only

0
0
Text · 59.9 KiB · c947407 Raw
1428 lines · plain
1// RUN: mlir-opt %s -one-shot-bufferize="bufferize-function-boundaries test-analysis-only" -split-input-file | FileCheck %s2// RUN: mlir-opt %s -one-shot-bufferize="bufferize-function-boundaries test-analysis-only dump-alias-sets" -split-input-file | FileCheck %s --check-prefix=CHECK-ALIAS3 4// Run fuzzer with different seeds.5// RUN: mlir-opt %s -one-shot-bufferize="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="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="bufferize-function-boundaries test-analysis-only analysis-heuristic=fuzzer analysis-fuzzer-seed=91" -split-input-file -o /dev/null8 9// Try different heuristics. Not checking the result, just make sure that we do10// not crash.11// RUN: mlir-opt %s -one-shot-bufferize="bufferize-function-boundaries test-analysis-only analysis-heuristic=bottom-up-from-terminators" -split-input-file -o /dev/null12// RUN: mlir-opt %s -one-shot-bufferize="bufferize-function-boundaries test-analysis-only analysis-heuristic=top-down" -split-input-file -o /dev/null13 14// TODO: Extract op-specific test cases and move them to their respective15// dialects.16 17//===----------------------------------------------------------------------===//18// Simple cases19//===----------------------------------------------------------------------===//20 21// -----22 23// CHECK-LABEL: func @extract_slice_fun(24func.func @extract_slice_fun(%A : tensor<?xf32> {bufferization.writable = false},25//  CHECK-SAME:              bufferization.access = "read"26                             %B : tensor<?xf32> {bufferization.writable = true})27//  CHECK-SAME:              bufferization.access = "read"28  -> (tensor<4xf32>, tensor<8xf32>)29{30  // tensor.extract_slice is not used in a write, it is not compelled to31  // bufferize out of place. Let callers decide whether they want to create32  // aliasing subviews at all call sites or whether they allocate.33  // This is true irrespective of whether the function argument is inplaceable.34  //     CHECK: tensor.extract_slice35  // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}36  %r0 = tensor.extract_slice %A[0][4][1] : tensor<?xf32> to tensor<4xf32>37 38  //     CHECK: tensor.extract_slice39  // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}40  %r1 = tensor.extract_slice %B[0][8][1] : tensor<?xf32> to tensor<8xf32>41 42  return %r0, %r1: tensor<4xf32>, tensor<8xf32>43}44 45// -----46 47// CHECK-LABEL: func @insert_slice_fun(48func.func @insert_slice_fun(%A : tensor<?xf32> {bufferization.writable = false},49//  CHECK-SAME:             bufferization.access = "read"50                            %B : tensor<?xf32> {bufferization.writable = true},51//  CHECK-SAME:             bufferization.access = "read-write"52                            %C : tensor<4xf32> {bufferization.writable = false})53//  CHECK-SAME:             bufferization.access = "read"54  -> (tensor<?xf32>, tensor<?xf32>)55{56  // must bufferize out of place.57  //      CHECK: tensor.insert_slice58  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "false"]}59  %r0 = tensor.insert_slice %C into %A[0][4][1] : tensor<4xf32> into tensor<?xf32>60 61  // bufferizes inplace.62  //      CHECK: tensor.insert_slice63  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "true"]}64  %r1 = tensor.insert_slice %C into %B[0][4][1] : tensor<4xf32> into tensor<?xf32>65 66  //      CHECK: return67  // CHECK-SAME: __equivalent_func_args__ = [-1, 1]68  return %r0, %r1: tensor<?xf32>, tensor<?xf32>69}70 71// -----72 73// CHECK-LABEL: func @conflict_on_B(74func.func @conflict_on_B(%A : tensor<4x4xf32> {bufferization.writable = true},75//  CHECK-SAME:          bufferization.access = "read"76                         %B : tensor<4x4xf32> {bufferization.writable = true})77//  CHECK-SAME:          bufferization.access = "read-write"78  -> (tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>)79{80  // matmul output operand interferes with input operand.81  //     CHECK: linalg.matmul82  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "true", "false"]}83  %C = linalg.matmul  ins(%A, %B: tensor<4x4xf32>, tensor<4x4xf32>)84                     outs(%B: tensor<4x4xf32>)85    -> tensor<4x4xf32>86 87  // matmul output operand interferes with input operand.88  //     CHECK: linalg.matmul89  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "true", "false"]}90  %D = linalg.matmul  ins(%B, %A: tensor<4x4xf32>, tensor<4x4xf32>)91                     outs(%B: tensor<4x4xf32>)92    -> tensor<4x4xf32>93 94  // matmul output operand does not interferes with input operand.95  //     CHECK: linalg.matmul96  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "true", "true"]}97  %E = linalg.matmul  ins(%A, %A: tensor<4x4xf32>, tensor<4x4xf32>)98                     outs(%B: tensor<4x4xf32>)99    -> tensor<4x4xf32>100 101  //      CHECK: return102  // CHECK-SAME: __equivalent_func_args__ = [-1, -1, 1]103  return %C, %D, %E: tensor<4x4xf32>, tensor<4x4xf32>, tensor<4x4xf32>104}105 106//===----------------------------------------------------------------------===//107// Length-1 producer-consumer cases.108//===----------------------------------------------------------------------===//109 110// -----111 112// CHECK-LABEL: func @extract_slice_extract_slice(113func.func @extract_slice_extract_slice(114    %A : tensor<?xf32> {bufferization.writable = true},115//  CHECK-SAME:         bufferization.access = "read"116    %B : tensor<?xf32> {bufferization.writable = false})117//  CHECK-SAME:         bufferization.access = "read"118  -> (tensor<2xf32>, tensor<2xf32>)119{120  // tensor.extract_slice is not used in a write, it is not compelled to121  // bufferize out of place. Let callers decide whether they want to create122  // aliasing subviews at all call sites or whether they allocate.123  // This is true irrespective of whether the function argument is inplaceable.124  // CHECK: {__inplace_operands_attr__ = ["true"]}125  %r0 = tensor.extract_slice %A[0][4][1] : tensor<?xf32> to tensor<4xf32>126 127  // CHECK: {__inplace_operands_attr__ = ["true"]}128  %r1 = tensor.extract_slice %r0[0][2][1] : tensor<4xf32> to tensor<2xf32>129 130  // CHECK: {__inplace_operands_attr__ = ["true"]}131  %r2 = tensor.extract_slice %B[0][4][1] : tensor<?xf32> to tensor<4xf32>132 133  // CHECK: {__inplace_operands_attr__ = ["true"]}134  %r3 = tensor.extract_slice %r2[0][2][1] : tensor<4xf32> to tensor<2xf32>135 136  return %r1, %r3: tensor<2xf32>, tensor<2xf32>137}138 139// -----140 141// CHECK-LABEL: func @insert_slice_insert_slice(142func.func @insert_slice_insert_slice(143    %A : tensor<?xf32> {bufferization.writable = true},144//  CHECK-SAME:         bufferization.access = "read-write"145    %A2 : tensor<4xf32> {bufferization.writable = true},146//  CHECK-SAME:          bufferization.access = "read-write"147    %A3 : tensor<2xf32> {bufferization.writable = true},148//  CHECK-SAME:          bufferization.access = "read"149    %B : tensor<?xf32> {bufferization.writable = false},150//  CHECK-SAME:         bufferization.access = "read"151    %B2 : tensor<4xf32> {bufferization.writable = false},152//  CHECK-SAME:          bufferization.access = "read"153    %B3 : tensor<2xf32> {bufferization.writable = false})154//  CHECK-SAME:          bufferization.access = "read"155  -> (tensor<?xf32>, tensor<?xf32>)156{157  // CHECK: {__inplace_operands_attr__ = ["true", "true"]}158  %r0 = tensor.insert_slice %A3 into %A2[0][2][1] : tensor<2xf32> into tensor<4xf32>159 160  // CHECK: {__inplace_operands_attr__ = ["true", "true"]}161  %r1 = tensor.insert_slice %r0 into %A[0][4][1] : tensor<4xf32> into tensor<?xf32>162 163  // CHECK: {__inplace_operands_attr__ = ["true", "false"]}164  %r2 = tensor.insert_slice %B3 into %B2[0][2][1] : tensor<2xf32> into tensor<4xf32>165 166  // CHECK: {__inplace_operands_attr__ = ["true", "false"]}167  %r3 = tensor.insert_slice %r2 into %B[0][4][1] : tensor<4xf32> into tensor<?xf32>168 169  //      CHECK: return170  // CHECK-SAME: __equivalent_func_args__ = [0, -1]171  return %r1, %r3: tensor<?xf32>, tensor<?xf32>172}173 174// -----175 176// CHECK-LABEL: func @extract_slice_nonmatching_insert_slice177func.func @extract_slice_nonmatching_insert_slice(178    %A : tensor<?xf32> {bufferization.writable = true},179    %B : tensor<?xf32> {bufferization.writable = false},180    %idx: index)181  -> (tensor<?xf32>, tensor<?xf32>)182{183  // %r1 bufferizes inplace because %A is inplaceable.184  // %r0 is an overlapping tensor.extract_slice that does not match, it must be185  // out of place.186  //      CHECK: tensor.extract_slice187  // CHECK-SAME: {__inplace_operands_attr__ = ["false"]}188  %r0 = tensor.extract_slice %A[0][4][1] : tensor<?xf32> to tensor<4xf32>189 190  // %r1 can bufferize inplace fine.191  //      CHECK: tensor.insert_slice192  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "true", "none"]}193  %r1 = tensor.insert_slice %r0 into %A[%idx][4][1] : tensor<4xf32> into tensor<?xf32>194 195  // %r3 does bufferizes inplace because %B is not inplaceable.196  // %r0 is an overlapping tensor.extract_slice that does not match, but does197  // not alias with the buffer coming from %r3 so it can actually bufferize198  // inplace.199  //      CHECK: tensor.extract_slice200  // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}201  %r2 = tensor.extract_slice %B[0][4][1] : tensor<?xf32> to tensor<4xf32>202 203  // %r3 cannot bufferize inplace since %B is not inplaceable.204  //      CHECK: tensor.insert_slice205  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "false", "none"]}206  %r3 = tensor.insert_slice %r2 into %B[%idx][4][1] : tensor<4xf32> into tensor<?xf32>207 208  //      CHECK: return209  // CHECK-SAME: __equivalent_func_args__ = [0, -1]210  return %r1, %r3: tensor<?xf32>, tensor<?xf32>211}212 213// -----214 215// CHECK-LABEL: func @extract_slice_matching_insert_slice216func.func @extract_slice_matching_insert_slice(217    %A : tensor<?xf32> {bufferization.writable = true},218    %B : tensor<?xf32> {bufferization.writable = false})219  -> (tensor<?xf32>, tensor<?xf32>)220{221  // %r1 bufferizes inplace because %A is inplaceable.222  // %r0 is a tensor.extract_slice that matches, it can also be bufferized223  // inplace.224  //      CHECK: tensor.extract_slice225  // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}226  %r0 = tensor.extract_slice %A[0][4][1] : tensor<?xf32> to tensor<4xf32>227 228  //      CHECK: tensor.insert_slice229  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "true"]}230  %r1 = tensor.insert_slice %r0 into %A[0][4][1] : tensor<4xf32> into tensor<?xf32>231 232  // %r2 is a tensor.extract_slice that matches %r3, it can be bufferized233  // inplace.234  //      CHECK: tensor.extract_slice235  // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}236  %r2 = tensor.extract_slice %B[0][4][1] : tensor<?xf32> to tensor<4xf32>237 238  // tensor.insert_slice cannot bufferize inplace.239  // This should have been captured by a canonicalization pattern and it would240  // be unproductive to have special logic in bufferization to encode matching241  // insert_slice(extract_slice(A), A).242  //      CHECK: tensor.insert_slice243  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "false"]}244  %r3 = tensor.insert_slice %r2 into %B[0][4][1] : tensor<4xf32> into tensor<?xf32>245 246  //      CHECK: return247  // CHECK-SAME: __equivalent_func_args__ = [0, -1]248  return %r1, %r3: tensor<?xf32>, tensor<?xf32>249}250 251// -----252 253// CHECK-LABEL: @read_of_matching_insert_slice_source254func.func @read_of_matching_insert_slice_source(255    %A : tensor<?xf32> {bufferization.writable = true},256    %idx : index,257    %idx2 : index)258  -> (tensor<?xf32>, vector<5xf32>)259{260  %cst = arith.constant 0.0 : f32261  %cst2 = arith.constant 1.0 : f32262 263  //      CHECK: tensor.extract_slice264  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "none", "none"]}265  %0 = tensor.extract_slice %A[%idx][%idx][1] : tensor<?xf32> to tensor<?xf32>266 267  //      CHECK: linalg.fill268  // CHECK-SAME: {__inplace_operands_attr__ = ["none", "true"]}269  %1 = linalg.fill ins(%cst : f32) outs(%0 : tensor<?xf32>) -> tensor<?xf32>270 271  //      CHECK: tensor.insert_slice272  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "true", "none", "none"]}273  %2 = tensor.insert_slice %1 into %A[%idx][%idx][1] : tensor<?xf32> into tensor<?xf32>274 275  %3 = vector.transfer_read %1[%idx2], %cst2 : tensor<?xf32>, vector<5xf32>276 277  //      CHECK: return278  // CHECK-SAME: __equivalent_func_args__ = [0, -1]279  return %2, %3 : tensor<?xf32>, vector<5xf32>280}281 282// -----283 284// CHECK-LABEL: @read_of_matching_insert_slice_source_interleaved285func.func @read_of_matching_insert_slice_source_interleaved(286    %A : tensor<?xf32> {bufferization.writable = true},287    %idx : index,288    %idx2 : index,289    %idx3 : index)290  -> (tensor<?xf32>, vector<5xf32>)291{292  %cst = arith.constant 0.0 : f32293  %cst2 = arith.constant 1.0 : f32294 295  //      CHECK: tensor.extract_slice296  // CHECK-SAME: {__inplace_operands_attr__ = ["false", "none", "none"]}297  %0 = tensor.extract_slice %A[%idx][%idx][1] : tensor<?xf32> to tensor<?xf32>298 299  //      CHECK: linalg.fill300  // CHECK-SAME: {__inplace_operands_attr__ = ["none", "true"]}301  %1 = linalg.fill ins(%cst : f32) outs(%0 : tensor<?xf32>) -> tensor<?xf32>302 303  //      CHECK: tensor.insert_slice304  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "true", "none", "none"]}305  %2 = tensor.insert_slice %1 into %A[%idx][%idx][1] : tensor<?xf32> into tensor<?xf32>306 307  //      CHECK: tensor.extract_slice308  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "none", "none"]}309  %4 = tensor.extract_slice %2[%idx3][%idx3][1] : tensor<?xf32> to tensor<?xf32>310 311  //      CHECK: linalg.fill312  // CHECK-SAME: {__inplace_operands_attr__ = ["none", "true"]}313  %5 = linalg.fill ins(%cst : f32) outs(%4 : tensor<?xf32>) -> tensor<?xf32>314 315  %3 = vector.transfer_read %1[%idx2], %cst2 : tensor<?xf32>, vector<5xf32>316 317  //      CHECK: tensor.insert_slice318  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "true", "none", "none"]}319  %6 = tensor.insert_slice %5 into %2[%idx3][%idx3][1] : tensor<?xf32> into tensor<?xf32>320 321  //      CHECK: return322  // CHECK-SAME: __equivalent_func_args__ = [0, -1]323  return %6, %3 : tensor<?xf32>, vector<5xf32>324}325 326// -----327 328// CHECK-LABEL: func @extract_slice_linalg_readonly_use329func.func @extract_slice_linalg_readonly_use(330    %A : tensor<?x?xf32> {bufferization.writable = false},331    %B : tensor<4x4xf32> {bufferization.writable = false},332    %C : tensor<4x4xf32> {bufferization.writable = true})333  ->  (tensor<4x4xf32>, tensor<4x4xf32>)334{335  // tensor.extract_slice is only used as a read, no interference irrespective336  // of user's inplace status.337  //     CHECK: tensor.extract_slice338  // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}339  %sA = tensor.extract_slice %A[0, 0][4, 4][1, 1] : tensor<?x?xf32> to tensor<4x4xf32>340 341  // matmul output operand is not inplaceable at the function boundary.342  //     CHECK: linalg.matmul343  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "true", "false"]}344  %D = linalg.matmul  ins(%sA, %B: tensor<4x4xf32>, tensor<4x4xf32>)345                     outs(%B: tensor<4x4xf32>)346    -> tensor<4x4xf32>347 348  // matmul output operand is inplaceable at the function boundary.349  //     CHECK: linalg.matmul350  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "true", "true"]}351  %E = linalg.matmul  ins(%sA, %B: tensor<4x4xf32>, tensor<4x4xf32>)352                     outs(%C: tensor<4x4xf32>)353    -> tensor<4x4xf32>354 355  //      CHECK: return356  // CHECK-SAME: __equivalent_func_args__ = [-1, 2]357  return %D, %E: tensor<4x4xf32>, tensor<4x4xf32>358}359 360// -----361 362// CHECK-LABEL: func @extract_slice_to_linalg_write_use363func.func @extract_slice_to_linalg_write_use(364    %A : tensor<4x4xf32> {bufferization.writable = false},365    %B : tensor<?x?xf32> {bufferization.writable = false},366    %C : tensor<?x?xf32> {bufferization.writable = true})367  ->  (tensor<4x4xf32>, tensor<4x4xf32>)368{369  // Step 4. %sB forward propagates to a write in %D but it is not inplace.370  // So this is only ever read and can bufferize inplace.371  //     CHECK: tensor.extract_slice372  // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}373  %sB = tensor.extract_slice %B[0, 0][4, 4][1, 1] : tensor<?x?xf32> to tensor<4x4xf32>374 375  // Step 3. %sB has a read interference in %E, it does not bufferize inplace.376  //     CHECK: linalg.matmul377  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "true", "false"]}378  %D = linalg.matmul  ins(%B, %C: tensor<?x?xf32>, tensor<?x?xf32>)379                     outs(%sB: tensor<4x4xf32>)380    -> tensor<4x4xf32>381 382  // Step 2. %sC forward propagates to an inplace write in %E.383  // %sC backward propagates to %C which is inplaceable.384  // As a consequence this is bufferized inplace.385  //     CHECK: tensor.extract_slice386  // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}387  %sC = tensor.extract_slice %C[0, 0][4, 4][1, 1] : tensor<?x?xf32> to tensor<4x4xf32>388 389  // Step 1. %sC backprops to the tensor.extract_slice producer which is not390  // considered an interference. This bufferizes inplace.391  //     CHECK: linalg.matmul392  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "true", "true"]}393  %E = linalg.matmul  ins(%A, %sB: tensor<4x4xf32>, tensor<4x4xf32>)394                     outs(%sC: tensor<4x4xf32>)395    -> tensor<4x4xf32>396 397  return %D, %E: tensor<4x4xf32>, tensor<4x4xf32>398}399 400// -----401 402// CHECK-LABEL: func @insert_slice_double_extract_slice403func.func @insert_slice_double_extract_slice(404    %s1: index,405    %s2: index,406    %s3: index,407    %s4: index,408    %A: tensor<8x6xf32> {bufferization.writable = false},409    %B: tensor<6x6xf32> {bufferization.writable = false},410    %C: tensor<30x20xf32> {bufferization.writable = true})411  -> tensor<30x20xf32>412{413  //      CHECK: tensor.extract_slice414  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "none", "none", "none", "none"]}415  %15 = tensor.extract_slice %C[%s3, %s4] [%s1, %s2] [1, 1] : tensor<30x20xf32> to tensor<?x?xf32>416 417  //      CHECK: linalg.matmul418  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "true", "true"]}419  %18 = linalg.matmul ins(%A, %B : tensor<8x6xf32>, tensor<6x6xf32>) outs(%15 : tensor<?x?xf32>) -> tensor<?x?xf32>420 421  //      CHECK: tensor.extract_slice422  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "none", "none"]}423  %19 = tensor.extract_slice %18[0, 0] [%s1, %s2] [1, 1] : tensor<?x?xf32> to tensor<?x?xf32>424 425  //      CHECK: tensor.insert_slice426  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "true", "none", "none", "none", "none"]}427  %20 = tensor.insert_slice %19 into %C[%s3, %s4] [%s1, %s2] [1, 1] : tensor<?x?xf32> into tensor<30x20xf32>428 429  //      CHECK: return430  // CHECK-SAME: __equivalent_func_args__ = [6]431  return %20 : tensor<30x20xf32>432}433 434//===----------------------------------------------------------------------===//435// Transitive cases436//===----------------------------------------------------------------------===//437 438// -----439 440// CHECK-LABEL: func @extract_slice_to_linalg_write_use441func.func @extract_slice_to_linalg_write_use(442    %A : tensor<4x4xf32> {bufferization.writable = false},443    %B : tensor<?x?xf32> {bufferization.writable = false},444    %C : tensor<?x?xf32> {bufferization.writable = true})445  ->  (tensor<4x4xf32>, tensor<4x4xf32>)446{447  // Step 4. %sB forward propagates to an inplace write in %D.448  // %sB backward propagates to %B which is not inplaceable.449  // As a consequence this is bufferized out of place.450  //     CHECK: tensor.extract_slice451  // CHECK-SAME: {__inplace_operands_attr__ = ["false"]}452  %sB = tensor.extract_slice %B[0, 0][4, 4][1, 1] : tensor<?x?xf32> to tensor<4x4xf32>453 454  // Step 3. %sB backprops to the tensor.extract_slice producer which is not455  // considered an interference. This bufferizes inplace.456  //     CHECK: linalg.matmul457  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "true", "true"]}458  %D = linalg.matmul  ins(%B, %C: tensor<?x?xf32>, tensor<?x?xf32>)459                     outs(%sB: tensor<4x4xf32>)460    -> tensor<4x4xf32>461 462  // Step 2. %sC forward propagates to an inplace write in %E.463  // %sC backward propagates to %C which is inplaceable.464  // As a consequence this is bufferized inplace.465  //     CHECK: tensor.extract_slice466  // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}467  %sC = tensor.extract_slice %C[0, 0][4, 4][1, 1] : tensor<?x?xf32> to tensor<4x4xf32>468 469  // Step 1. %sC backprops to the tensor.extract_slice producer which is not470  // considered an interference. This bufferizes inplace.471  //     CHECK: linalg.matmul472  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "true", "true"]}473  %E = linalg.matmul  ins(%A, %A: tensor<4x4xf32>, tensor<4x4xf32>)474                     outs(%sC: tensor<4x4xf32>)475    -> tensor<4x4xf32>476 477  return %D, %E: tensor<4x4xf32>, tensor<4x4xf32>478}479 480// -----481 482// CHECK-LABEL: func @nested_extract_slice_and_insert483func.func @nested_extract_slice_and_insert(484    %A : tensor<?x?xf32> {bufferization.writable = false},485    %B : tensor<?x?xf32> {bufferization.writable = true},486    %C : tensor<?x?xf32> {bufferization.writable = true},487    %idx : index,488    %sz1 : index,489    %sz2 : index)490  ->  (tensor<?x?xf32>, tensor<?x?xf32>, tensor<?x?xf32>)491{492  %f0 = arith.constant 0.0 : f32493 494  // 2-level matching tensor.extract_slice / tensor.insert_slice into non495  // inplaceable %A.496  //   - %rA is not inplaceable because %A is not inplaceable at function boundary.497  //   - once %rA is deemed not inplaceable, nothing prevent %rsA to be inplaceable498  //   - this propagates to %FA and %ssA being inplaceable.499  //   - %sA would then bufferize to an inplace write (i.e. %FA) but %A is not500  //     inplaceable and so %sA is not inplaceable.501  //     CHECK: tensor.extract_slice502  // CHECK-SAME: {__inplace_operands_attr__ = ["false", "none", "none"]}503  // CHECK-NEXT: tensor.extract_slice504  // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}505  // CHECK-NEXT: fill506  // CHECK-SAME: {__inplace_operands_attr__ = ["none", "true"]}507  // CHECK-NEXT: tensor.insert_slice508  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "true"]}509  // CHECK-NEXT: tensor.insert_slice510  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "false", "none", "none"]}511  %sA = tensor.extract_slice %A[0, 0][%idx, %idx][1, 1] : tensor<?x?xf32> to tensor<?x?xf32>512  %ssA = tensor.extract_slice %sA[0, 0][4, 4][1, 1] : tensor<?x?xf32> to tensor<4x4xf32>513  %FA = linalg.fill ins(%f0 : f32) outs(%ssA : tensor<4x4xf32>) -> tensor<4x4xf32>514  %rsA = tensor.insert_slice %FA into %sA[0, 0][4, 4][1, 1] : tensor<4x4xf32> into tensor<?x?xf32>515  %rA = tensor.insert_slice %rsA into %A[0, 0][%idx, %idx][1, 1] : tensor<?x?xf32> into tensor<?x?xf32>516 517  // 3-level matching tensor.extract_slice / tensor.insert_slice into518  // inplaceable %B.519  // CHECK-NEXT: tensor.extract_slice520  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "none", "none"]}521  // CHECK-NEXT: tensor.extract_slice522  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "none"]}523  // CHECK-NEXT: tensor.extract_slice524  // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}525  // CHECK-NEXT: fill526  // CHECK-SAME: {__inplace_operands_attr__ = ["none", "true"]}527  // CHECK-NEXT: tensor.insert_slice528  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "true"]}529  // CHECK-NEXT: tensor.insert_slice530  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "true", "none"]}531  // CHECK-NEXT: tensor.insert_slice532  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "true", "none", "none"]}533  %sB = tensor.extract_slice %B[0, 0][%idx, %idx][1, 1] : tensor<?x?xf32> to tensor<?x?xf32>534  %ssB = tensor.extract_slice %sB[0, 0][4, %idx][1, 1] : tensor<?x?xf32> to tensor<4x?xf32>535  %sssB = tensor.extract_slice %ssB[0, 0][4, 4][1, 1] : tensor<4x?xf32> to tensor<4x4xf32>536  %FB = linalg.fill ins(%f0 : f32) outs(%sssB : tensor<4x4xf32>) -> tensor<4x4xf32>537  %rssB = tensor.insert_slice %FB into %ssB[0, 0][4, 4][1, 1] : tensor<4x4xf32> into tensor<4x?xf32>538  %rsB = tensor.insert_slice %rssB into %sB[0, 0][4, %idx][1, 1] : tensor<4x?xf32> into tensor<?x?xf32>539  %rB = tensor.insert_slice %rsB into %B[0, 0][%idx, %idx][1, 1] : tensor<?x?xf32> into tensor<?x?xf32>540 541  // 2-level matching tensor.extract_slice / tensor.insert_slice into542  // inplaceable %C with a twist.543  // Throw a wrench in the system: %rsC production sizes do not match %ssC.544  // CHECK-NEXT: tensor.extract_slice545  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "none", "none"]}546  // The tensor.insert_slice that would be candidate for matching does not actually547  // match. That tensor.insert_slice can still be bufferized inplace nonetheless548  // but this tensor.extract_slice, which bufferizes to an inplace write, cannot.549  // CHECK-NEXT: tensor.extract_slice550  // CHECK-SAME: {__inplace_operands_attr__ = ["false", "none"]}551  // CHECK-NEXT: fill552  // CHECK-SAME: {__inplace_operands_attr__ = ["none", "true"]}553  // CHECK-NEXT: tensor.insert_slice554  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "true", "none"]}555  // CHECK-NEXT: tensor.insert_slice556  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "true", "none", "none"]}557  %sC = tensor.extract_slice %C[0, 0][%idx, %idx][1, 1] : tensor<?x?xf32> to tensor<?x?xf32>558  %ssC = tensor.extract_slice %sC[0, 0][%sz1, 4][1, 1] : tensor<?x?xf32> to tensor<?x4xf32>559  %FC = linalg.fill ins(%f0 : f32) outs(%ssC : tensor<?x4xf32>) -> tensor<?x4xf32>560  %rsC = tensor.insert_slice %FC into %sC[0, 0][%sz2, 4][1, 1] : tensor<?x4xf32> into tensor<?x?xf32>561  %rC = tensor.insert_slice %rsC into %C[0, 0][%idx, %idx][1, 1] : tensor<?x?xf32> into tensor<?x?xf32>562 563  //      CHECK: return564  // CHECK-SAME: __equivalent_func_args__ = [-1, 1, 2]565  return %rA, %rB, %rC: tensor<?x?xf32>, tensor<?x?xf32>, tensor<?x?xf32>566}567 568// -----569 570//===----------------------------------------------------------------------===//571// Cross function boundary cases.572//===----------------------------------------------------------------------===//573 574func.func private @foo(tensor<64xf32>)575 576// CHECK-LABEL: dependence_through_call577func.func @dependence_through_call(%I : tensor<64xf32> {bufferization.writable = true}) {578  %f1 = arith.constant 1.000000e+00 : f32579  %f2 = arith.constant 2.000000e+00 : f32580 581  // 2. %B already bufferizes inplace, %A would alias and have a different582  // value. The calls to `foo` are determined to read conservatively, so %A583  // cannot bufferize inplace.584  //     CHECK: fill585  // CHECK-SAME: {__inplace_operands_attr__ = ["none", "false"]}586  %A = linalg.fill ins(%f1 : f32) outs(%I : tensor<64xf32>) -> tensor<64xf32>587 588  // 1. Bufferizes inplace: no alias to %A is yet possible.589  //     CHECK: fill590  // CHECK-SAME: {__inplace_operands_attr__ = ["none", "true"]}591  %B = linalg.fill ins(%f2 : f32) outs(%I : tensor<64xf32>) -> tensor<64xf32>592 593  call @foo(%A) : (tensor<64xf32>) -> ()594  call @foo(%B) : (tensor<64xf32>) -> ()595 596  return597}598 599// -----600 601func.func private @foo(tensor<64xf32>)602 603func.func private @bar(%A : tensor<64xf32>) {604  call @foo(%A) : (tensor<64xf32>) -> ()605  return606}607 608func.func @read_dependence_through_scf_and_call(609    %I : tensor<64xf32> {bufferization.writable = true},610    %I2 : tensor<64xf32> {bufferization.writable = true}) {611  %c0 = arith.constant 0 : index612  %c1 = arith.constant 1 : index613  %c10 = arith.constant 10 : index614  %f1 = arith.constant 1.000000e+00 : f32615  %f2 = arith.constant 2.000000e+00 : f32616 617  // 5. %B bufferizes inplace, %A would alias and have a different value.618  // The calls to `foo` are determined to read conservatively, so %A cannot619  // bufferize inplace.620  //     CHECK: fill621  // CHECK-SAME: {__inplace_operands_attr__ = ["none", "false"]}622  %A = linalg.fill ins(%f1 : f32) outs(%I : tensor<64xf32>) -> tensor<64xf32>623 624  // 4. Bufferizes inplace: no alias to %A is yet possible.625  //     CHECK: fill626  // CHECK-SAME: {__inplace_operands_attr__ = ["none", "true"]}627  %B = linalg.fill ins(%f2 : f32) outs(%I : tensor<64xf32>) -> tensor<64xf32>628 629  // 3. Does not read or write, bufferizes inplace.630  //      CHECK: scf.for631  // CHECK-NEXT: scf.yield632  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "true"]}633  //      CHECK: } {__inplace_operands_attr__ = ["none", "none", "none", "true", "true"]}634  %r:2 = scf.for %i = %c0 to %c10 step %c1 iter_args(%0 = %A, %1 = %B)635    -> (tensor<64xf32>, tensor<64xf32>)636  {637    scf.yield %0, %1 : tensor<64xf32>, tensor<64xf32>638  }639  call @foo(%r#0) : (tensor<64xf32>) -> ()640  call @foo(%r#1) : (tensor<64xf32>) -> ()641 642  // 2. %B2 already bufferizes inplace, %A2 would alias and have a different643  // value. The calls to `foo` are determined to read conservatively, so %A2644  // cannot bufferize inplace.645  //     CHECK: fill646  // CHECK-SAME: {__inplace_operands_attr__ = ["none", "false"]}647  %A2 = linalg.fill ins(%f1 : f32) outs(%I2 : tensor<64xf32>) -> tensor<64xf32>648 649  // 1. Bufferizes inplace: no alias to %A2 is yet possible.650  //     CHECK: fill651  // CHECK-SAME: {__inplace_operands_attr__ = ["none", "true"]}652  %B2 = linalg.fill ins(%f2 : f32) outs(%I2 : tensor<64xf32>) -> tensor<64xf32>653 654  call @bar(%A2) : (tensor<64xf32>) -> ()655  call @bar(%B2) : (tensor<64xf32>) -> ()656  return657}658 659// -----660 661//===----------------------------------------------------------------------===//662// Transitive cases through extract_slice.663//===----------------------------------------------------------------------===//664 665// CHECK-LABEL: func @write_into_constant_via_alias666func.func @write_into_constant_via_alias(%v : vector<5xi32>,667                                    %s1 : index, %s2 : index,668                                    %s3 : index) -> tensor<?xi32> {669  %A = arith.constant dense<[1, 2, 3, 4]> : tensor<4xi32>670  //      CHECK: tensor.extract_slice671  // CHECK-SAME: {__inplace_operands_attr__ = ["false", "none", "none"]}672  %b = tensor.extract_slice %A[%s1][%s2][1] : tensor<4xi32> to tensor<?xi32>673  //      CHECK: vector.transfer_write674  // CHECK-SAME: {__inplace_operands_attr__ = ["none", "true", "none"]}675  %r = vector.transfer_write %v, %b[%s3] : vector<5xi32>, tensor<?xi32>676  return %r : tensor<?xi32>677}678 679// -----680 681func.func @matmul_on_tensors(682    %arg0: tensor<518x518xf32> {bufferization.buffer_layout = affine_map<(d0, d1) -> (d0, d1)>, bufferization.writable = false},683    %arg1: tensor<518x518xf32> {bufferization.buffer_layout = affine_map<(d0, d1) -> (d0, d1)>, bufferization.writable = false},684    %arg2: tensor<256x256xf32> {bufferization.buffer_layout = affine_map<(d0, d1) -> (d0, d1)>, bufferization.writable = true})685    -> tensor<256x256xf32>686{687  %c0 = arith.constant 0 : index688  %cst_0 = arith.constant 0.000000e+00 : f32689  %cst_1 = arith.constant 1.000000e+00 : f32690 691  %7 = bufferization.alloc_tensor() : tensor<256x256xf32>692 693  //      CHECK: linalg.fill694  // CHECK-SAME: {__inplace_operands_attr__ = ["none", "false"]}695  //      CHECK: linalg.fill696  // CHECK-SAME: {__inplace_operands_attr__ = ["none", "true"]}697  %8 = linalg.fill ins(%cst_0 : f32) outs(%7 : tensor<256x256xf32>) -> tensor<256x256xf32>698  %11 = linalg.fill ins(%cst_1 : f32) outs(%7 : tensor<256x256xf32>) -> tensor<256x256xf32>699 700  //      CHECK: tensor.extract_slice701  // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}702  //      CHECK: tensor.extract_slice703  // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}704  //      CHECK: linalg.matmul705  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "true", "true"]}706  %sA = tensor.extract_slice %8[0, 0][256, 16][1, 1]: tensor<256x256xf32> to tensor<256x16xf32>707  %sB = tensor.extract_slice %11[0, 0][16, 256][1, 1]: tensor<256x256xf32> to tensor<16x256xf32>708  %r = linalg.matmul709         ins(%sA, %sB : tensor<256x16xf32>, tensor<16x256xf32>)710        outs(%arg2 : tensor<256x256xf32>) -> tensor<256x256xf32>711 712  //      CHECK: return713  // CHECK-SAME: __equivalent_func_args__ = [2]714  return %r : tensor<256x256xf32>715}716 717// -----718 719func.func @matmul_on_tensors(720    %arg0: tensor<518x518xf32> {bufferization.buffer_layout = affine_map<(d0, d1) -> (d0, d1)>, bufferization.writable = false},721    %arg1: tensor<518x518xf32> {bufferization.buffer_layout = affine_map<(d0, d1) -> (d0, d1)>, bufferization.writable = false},722    %arg2: tensor<256x256xf32> {bufferization.buffer_layout = affine_map<(d0, d1) -> (d0, d1)>, bufferization.writable = true})723    -> tensor<256x256xf32>724{725  %c0 = arith.constant 0 : index726  %cst_0 = arith.constant 0.000000e+00 : f32727  %cst_1 = arith.constant 1.000000e+00 : f32728 729  %7 = bufferization.alloc_tensor() : tensor<256x256xf32>730 731  //     CHECK: linalg.fill732  // CHECK-SAME: {__inplace_operands_attr__ = ["none", "false"]}733  //      CHECK: vector.transfer_write734  // CHECK-SAME: {__inplace_operands_attr__ = ["none", "true", "none", "none"]735  %8 = linalg.fill ins(%cst_0 : f32) outs(%7 : tensor<256x256xf32>) -> tensor<256x256xf32>736  %9 = vector.transfer_read %arg0[%c0, %c0], %cst_0 {in_bounds = [false, true]} : tensor<518x518xf32>, vector<256x256xf32>737  %10 = vector.transfer_write %9, %8[%c0, %c0] {in_bounds = [true, true]} : vector<256x256xf32>, tensor<256x256xf32>738 739  //      CHECK: linalg.fill740  // CHECK-SAME: {__inplace_operands_attr__ = ["none", "true"]}741  //      CHECK: vector.transfer_write742  // CHECK-SAME: {__inplace_operands_attr__ = ["none", "true", "none", "none"]743  %11 = linalg.fill ins(%cst_1 : f32) outs(%7 : tensor<256x256xf32>) -> tensor<256x256xf32>744  %12 = vector.transfer_read %arg1[%c0, %c0], %cst_0 {in_bounds = [false, true]} : tensor<518x518xf32>, vector<256x256xf32>745  %13 = vector.transfer_write %12, %11[%c0, %c0] {in_bounds = [true, true]} : vector<256x256xf32>, tensor<256x256xf32>746 747  //      CHECK: tensor.extract_slice748  // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}749  //      CHECK: tensor.extract_slice750  // CHECK-SAME: {__inplace_operands_attr__ = ["true"]}751  //      CHECK: linalg.matmul752  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "true", "true"]}753  %sA = tensor.extract_slice %10[0, 0][256, 16][1, 1]: tensor<256x256xf32> to tensor<256x16xf32>754  %sB = tensor.extract_slice %13[0, 0][16, 256][1, 1]: tensor<256x256xf32> to tensor<16x256xf32>755  %r = linalg.matmul756         ins(%sA, %sB : tensor<256x16xf32>, tensor<16x256xf32>)757        outs(%arg2 : tensor<256x256xf32>) -> tensor<256x256xf32>758 759  //      CHECK: return760  // CHECK-SAME: __equivalent_func_args__ = [2]761  return %r : tensor<256x256xf32>762}763 764// -----765 766//===----------------------------------------------------------------------===//767// Chain of tensor.insert_slice is better traversed in reverse order without768// prioritizing  the tensor.insert_slice ops.769//===----------------------------------------------------------------------===//770 771// CHECK-LABEL: func @insert_slice_chain(772func.func @insert_slice_chain(773    %v1: vector<32x90xf32>,774    %v2: vector<30x90xf32>,775    %arg0: tensor<62x126xf32> {bufferization.buffer_layout = affine_map<(d0, d1) -> (d0, d1)>, bufferization.writable = false},776// CHECK-SAME: bufferization.access = "none"777    %arg1: tensor<126x90xf32> {bufferization.buffer_layout = affine_map<(d0, d1) -> (d0, d1)>, bufferization.writable = false},778// CHECK-SAME: bufferization.access = "none"779    %arg2: tensor<62x90xf32> {bufferization.buffer_layout = affine_map<(d0, d1) -> (d0, d1)>, bufferization.writable = true})780// CHECK-SAME: bufferization.access = "write"781  -> tensor<62x90xf32> attributes {passthrough = [["prefer-vector-width", "512"]], target_cpu = "skylake-avx512"}782{783  %c0 = arith.constant 0 : index784  %cst = arith.constant 0.000000e+00 : f32785 786  //      CHECK: linalg.fill787  // CHECK-SAME: {__inplace_operands_attr__ = ["none", "true"]788  %0 = linalg.fill ins(%cst : f32) outs(%arg2 : tensor<62x90xf32>) -> tensor<62x90xf32>789 790  //      CHECK: tensor.extract_slice791  // CHECK-SAME: {__inplace_operands_attr__ = ["true"]792  %2 = tensor.extract_slice %0[0, 0] [32, 90] [1, 1] : tensor<62x90xf32> to tensor<32x90xf32>793  //      CHECK: vector.transfer_write794  // CHECK-SAME: {__inplace_operands_attr__ = ["none", "true", "none", "none"]795  %7 = vector.transfer_write %v1, %2[%c0, %c0] {in_bounds = [true, true]} : vector<32x90xf32>, tensor<32x90xf32>796  //      CHECK: tensor.insert_slice797  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "true"]798  %8 = tensor.insert_slice %7 into %0[0, 0] [32, 90] [1, 1] : tensor<32x90xf32> into tensor<62x90xf32>799 800  //      CHECK: tensor.extract_slice801  // CHECK-SAME: {__inplace_operands_attr__ = ["true"]802  %10 = tensor.extract_slice %8[32, 0] [30, 90] [1, 1] : tensor<62x90xf32> to tensor<30x90xf32>803  //      CHECK: vector.transfer_write804  // CHECK-SAME: {__inplace_operands_attr__ = ["none", "true", "none", "none"]805  %14 = vector.transfer_write %v2, %10[%c0, %c0] {in_bounds = [true, true]} : vector<30x90xf32>, tensor<30x90xf32>806  //      CHECK: tensor.insert_slice807  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "true"]808  %15 = tensor.insert_slice %14 into %8[32, 0] [30, 90] [1, 1] : tensor<30x90xf32> into tensor<62x90xf32>809 810  //      CHECK: return811  // CHECK-SAME: __equivalent_func_args__ = [4]812  return %15 : tensor<62x90xf32>813}814 815// -----816 817//===----------------------------------------------------------------------===//818// Insert point issue cases.819//===----------------------------------------------------------------------===//820 821// Only test IR validity wrt dominance.822// CHECK-LABEL: func @ip823func.func @ip(%t: tensor<10x20xf32> {bufferization.writable = true},824         %x: index, %y: index, %v: vector<5x6xf32>)825  -> tensor<10x20xf32>826{827  %c0 = arith.constant 0 : index828  %c256 = arith.constant 256 : index829  %c257 = arith.constant 257 : index830  %r = scf.for %arg0 = %c0 to %c257 step %c256 iter_args(%arg1 = %t) -> (tensor<10x20xf32>) {831    %t1 = tensor.extract_slice %arg1[%x, 0] [5, %y] [1, 1] : tensor<10x20xf32> to tensor<5x?xf32>832    %t11 = tensor.extract_slice %t1[0, 0] [5, %y] [1, 1] : tensor<5x?xf32> to tensor<5x?xf32>833    %t2 = vector.transfer_write %v, %t11[%c0, %c0] : vector<5x6xf32>, tensor<5x?xf32>834    %t3 = tensor.insert_slice %t2 into %arg1[%x, 0] [5, %y] [1, 1] : tensor<5x?xf32> into tensor<10x20xf32>835    scf.yield %t3 : tensor<10x20xf32>836  }837 838  //      CHECK: return839  // CHECK-SAME: __equivalent_func_args__ = [0]840 return %r : tensor<10x20xf32>841}842 843// -----844 845#accesses = [846  affine_map<(i) -> (i)>,847  affine_map<(i) -> (i)>,848  affine_map<(i) -> (i)>849]850#trait = {851  indexing_maps = #accesses,852  iterator_types = ["parallel"]853}854 855// CHECK-LABEL: func @linalg_op_same_out_tensors(856func.func @linalg_op_same_out_tensors(857    %t1: tensor<?xf32> {bufferization.writable = true},858// CHECK-SAME:          bufferization.access = "read"859    %t2: tensor<?xf32> {bufferization.writable = true})860// CHECK-SAME:          bufferization.access = "write"861  -> (tensor<?xf32>, tensor<?xf32>){862 863  //      CHECK: linalg.generic864  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "true", "false"]865  %o:2 = linalg.generic #trait ins(%t1 : tensor<?xf32>)866                               outs (%t2, %t2 : tensor<?xf32>, tensor<?xf32>) {867      ^bb(%0: f32, %1: f32, %2 : f32) :868        linalg.yield %0, %0 : f32, f32869    } -> (tensor<?xf32>, tensor<?xf32>)870 871  //      CHECK: return872  // CHECK-SAME: __equivalent_func_args__ = [1, -1]873  return %o#0, %o#1 : tensor<?xf32>, tensor<?xf32>874}875 876// -----877 878#accesses = [879  affine_map<(i) -> (i)>,880  affine_map<(i) -> (i)>,881  affine_map<(i) -> (i)>,882  affine_map<(i) -> (i)>883]884#trait = {885  indexing_maps = #accesses,886  iterator_types = ["parallel"]887}888 889// CHECK-LABEL: func @linalg_op_same_out_tensors_2(890func.func @linalg_op_same_out_tensors_2(891    %t1: tensor<?xf32> {bufferization.writable = true},892// CHECK-SAME:          bufferization.access = "read"893    %t2: tensor<?xf32> {bufferization.writable = true})894// CHECK-SAME:          bufferization.access = "write"895        -> (tensor<?xf32>, tensor<?xf32>, tensor<?xf32>){896 897  //      CHECK: linalg.generic898  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "true", "false", "false"]899  %o:3 = linalg.generic #trait900          ins(%t1 : tensor<?xf32>)901          outs (%t2, %t2, %t2 : tensor<?xf32>, tensor<?xf32>, tensor<?xf32>) {902      ^bb(%0: f32, %1: f32, %2 : f32, %3 : f32) :903        linalg.yield %0, %0, %0 : f32, f32, f32904    } -> (tensor<?xf32>, tensor<?xf32>, tensor<?xf32>)905 906  //      CHECK: return907  // CHECK-SAME: __equivalent_func_args__ = [1, -1, -1]908  return %o#0, %o#1, %o#2 : tensor<?xf32>, tensor<?xf32>, tensor<?xf32>909}910 911// -----912 913// CHECK-LABEL: func @double_insert_slice_into_alias914func.func @double_insert_slice_into_alias(915    %v1: vector<32x90xf32>,916    %v2: vector<30x90xf32>,917    %arg2: tensor<62x90xf32> {bufferization.writable = true},918    %s1: index, %s2: index, %s3: index, %s4: index)919  -> (tensor<62x90xf32>, tensor<?x?xf32>)920{921  %c0 = arith.constant 0 : index922 923  // Cannot bufferize inplace this extract_slice because both operand and result924  // are modified and returned separately.925  //      CHECK: tensor.extract_slice926  // CHECK-SAME: {__inplace_operands_attr__ = ["false", "none", "none", "none", "none"]927  %e = tensor.extract_slice %arg2[%s1, %s2][%s3, %s4][1, 1] : tensor<62x90xf32> to tensor<?x?xf32>928 929  //      CHECK: tensor.extract_slice930  // CHECK-SAME: {__inplace_operands_attr__ = ["true"]931  %2 = tensor.extract_slice %arg2[0, 0] [32, 90] [1, 1] : tensor<62x90xf32> to tensor<32x90xf32>932  //      CHECK: vector.transfer_write933  // CHECK-SAME: {__inplace_operands_attr__ = ["none", "true", "none", "none"]934  %7 = vector.transfer_write %v1, %2[%c0, %c0] {in_bounds = [true, true]} : vector<32x90xf32>, tensor<32x90xf32>935  //      CHECK: tensor.insert_slice936  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "true"]937  %8 = tensor.insert_slice %7 into %arg2[0, 0] [32, 90] [1, 1] : tensor<32x90xf32> into tensor<62x90xf32>938 939  //      CHECK: tensor.extract_slice940  // CHECK-SAME: {__inplace_operands_attr__ = ["true"]941  %10 = tensor.extract_slice %e[32, 0] [30, 90] [1, 1] : tensor<?x?xf32> to tensor<30x90xf32>942  //      CHECK: vector.transfer_write943  // CHECK-SAME: {__inplace_operands_attr__ = ["none", "true", "none", "none"]944  %14 = vector.transfer_write %v2, %10[%c0, %c0] {in_bounds = [true, true]} : vector<30x90xf32>, tensor<30x90xf32>945  //      CHECK: tensor.insert_slice946  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "true"]947  %15 = tensor.insert_slice %14 into %e[32, 0] [30, 90] [1, 1] : tensor<30x90xf32> into tensor<?x?xf32>948 949  //      CHECK: return950  // CHECK-SAME: __equivalent_func_args__ = [2, -1]951  return %8, %15 : tensor<62x90xf32>, tensor<?x?xf32>952}953 954// -----955 956// CHECK-LABEL: func @interleaved_extract_insert_slice_chain_1957func.func @interleaved_extract_insert_slice_chain_1(958    %arg2: tensor<62x90xf32> {bufferization.writable = true})959  -> (tensor<62x90xf32>)960{961  //      CHECK: tensor.extract_slice962  // CHECK-SAME: {__inplace_operands_attr__ = ["true"]963  %2 = tensor.extract_slice %arg2[0, 0] [32, 90] [1, 1] : tensor<62x90xf32> to tensor<32x90xf32>964 965  // TODO: This should bufferize inplace once we have a proper range analysis.966  //      CHECK: tensor.extract_slice967  // CHECK-SAME: {__inplace_operands_attr__ = ["false"]968  %10 = tensor.extract_slice %arg2[32, 0] [30, 90] [1, 1] : tensor<62x90xf32> to tensor<30x90xf32>969 970 971  //      CHECK: tensor.insert_slice972  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "true"]973  %8 = tensor.insert_slice %2 into %arg2[0, 0] [32, 90] [1, 1] : tensor<32x90xf32> into tensor<62x90xf32>974 975 976  //      CHECK: tensor.insert_slice977  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "true"]978  %15 = tensor.insert_slice %10 into %8[32, 0] [30, 90] [1, 1] : tensor<30x90xf32> into tensor<62x90xf32>979 980  //      CHECK: return981  // CHECK-SAME: __equivalent_func_args__ = [0]982  return %15 : tensor<62x90xf32>983}984 985// -----986 987// CHECK-LABEL: func @interleaved_extract_insert_slice_chain_2988func.func @interleaved_extract_insert_slice_chain_2(989    %arg2: tensor<62x90xf32> {bufferization.writable = true})990  -> (tensor<62x90xf32>)991{992  //      CHECK: tensor.extract_slice993  // CHECK-SAME: {__inplace_operands_attr__ = ["true"]994  %2 = tensor.extract_slice %arg2[0, 0] [32, 90] [1, 1] : tensor<62x90xf32> to tensor<32x90xf32>995 996  // The slices are overlapping, so this can never bufferize inplace.997  //      CHECK: tensor.extract_slice998  // CHECK-SAME: {__inplace_operands_attr__ = ["false"]999  %10 = tensor.extract_slice %arg2[31, 0] [30, 90] [1, 1] : tensor<62x90xf32> to tensor<30x90xf32>1000 1001 1002  //      CHECK: tensor.insert_slice1003  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "true"]1004  %8 = tensor.insert_slice %2 into %arg2[0, 0] [32, 90] [1, 1] : tensor<32x90xf32> into tensor<62x90xf32>1005 1006 1007  //      CHECK: tensor.insert_slice1008  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "true"]1009  %15 = tensor.insert_slice %10 into %8[31, 0] [30, 90] [1, 1] : tensor<30x90xf32> into tensor<62x90xf32>1010 1011  //      CHECK: return1012  // CHECK-SAME: __equivalent_func_args__ = [0]1013  return %15 : tensor<62x90xf32>1014}1015 1016// -----1017 1018// CHECK-LABEL: func @extract_once_insert_twice1019func.func @extract_once_insert_twice(1020    %arg2: tensor<62x90xf32> {bufferization.writable = true})1021  -> (tensor<62x90xf32>)1022{1023  //      CHECK: tensor.extract_slice1024  // CHECK-SAME: {__inplace_operands_attr__ = ["false"]1025  %2 = tensor.extract_slice %arg2[0, 0] [32, 90] [1, 1] : tensor<62x90xf32> to tensor<32x90xf32>1026 1027  //      CHECK: tensor.insert_slice1028  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "true"]1029  %8 = tensor.insert_slice %2 into %arg2[0, 0] [32, 90] [1, 1] : tensor<32x90xf32> into tensor<62x90xf32>1030 1031  //      CHECK: tensor.insert_slice1032  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "true"]1033  %15 = tensor.insert_slice %2 into %8[15, 0] [32, 90] [1, 1] : tensor<32x90xf32> into tensor<62x90xf32>1034 1035  //      CHECK: return1036  // CHECK-SAME: __equivalent_func_args__ = [0]1037  return %15 : tensor<62x90xf32>1038}1039 1040// -----1041 1042// CHECK-LABEL: func @some_use1043func.func @some_use(%A : tensor<?xf32> {bufferization.writable = true},1044                    %v : vector<5xf32>) -> (tensor<?xf32>) {1045  %idx = arith.constant 0 : index1046  //      CHECK: vector.transfer_write1047  // CHECK-SAME: {__inplace_operands_attr__ = ["none", "true", "none"]1048  %0 = vector.transfer_write %v, %A[%idx] : vector<5xf32>, tensor<?xf32>1049  return %0 : tensor<?xf32>1050}1051 1052 1053// CHECK-LABEL: func @main_func1054func.func @main_func(%A : tensor<?xf32> {bufferization.writable = true},1055                     %v : vector<5xf32>) -> (tensor<?xf32>) {1056  //      CHECK: call1057  // CHECK-SAME: {__inplace_operands_attr__ = ["true", "none"]1058  %0 = call @some_use(%A, %v) : (tensor<?xf32>, vector<5xf32>) -> (tensor<?xf32>)1059  return %0 : tensor<?xf32>1060}1061 1062// -----1063 1064// CHECK-LABEL: func @to_tensor_op_not_writable1065func.func @to_tensor_op_not_writable(%m: memref<?xf32>, %v:  vector<5xf32>,1066                                     %idx1: index, %idx2: index)1067    -> vector<10xf32> {1068  %0 = bufferization.to_tensor %m restrict : memref<?xf32> to tensor<?xf32>1069 1070  // Write to the tensor. Cannot be inplace due to tensor_load.1071  //      CHECK: vector.transfer_write1072  // CHECK-SAME: {__inplace_operands_attr__ = ["none", "false", "none"]1073  %w = vector.transfer_write %v, %0[%idx1] : vector<5xf32>, tensor<?xf32>1074 1075  // Read from the tensor and return result.1076  %cst = arith.constant 0.0 : f321077  %r = vector.transfer_read %w[%idx2], %cst : tensor<?xf32>, vector<10xf32>1078  return %r : vector<10xf32>1079}1080 1081// -----1082 1083// CHECK-LABEL: func @inner_func1084func.func @inner_func(%t: tensor<?xf32>) -> tensor<?xf32> {1085  //      CHECK: return1086  // CHECK-SAME: __equivalent_func_args__ = [0]1087  return %t : tensor<?xf32>1088}1089 1090func.func @equivalent_func_arg(%c0: index, %c10: index, %c1: index, %t0: tensor<?xf32>) -> tensor<?xf32> {1091  // This test does not check IR. It just asserts there is no failure due to1092  // non-equivalent scf.for yield values.1093  %1 = scf.for %iv = %c0 to %c10 step %c1 iter_args(%t1 = %t0) -> (tensor<?xf32>) {1094    %3 = func.call @inner_func(%t1) : (tensor<?xf32>) -> tensor<?xf32>1095    scf.yield %3 : tensor<?xf32>1096  }1097  return %1: tensor<?xf32>1098}1099 1100// -----1101 1102// CHECK-LABEL: func @inner_func_21103func.func @inner_func_2(%t: tensor<?xf32>) -> tensor<?xf32> {1104  %f = arith.constant 1.0 : f321105  %c0 = arith.constant 0 : index1106  %0 = tensor.insert %f into %t[%c0] : tensor<?xf32>1107  //      CHECK: return1108  // CHECK-SAME: __equivalent_func_args__ = [0]1109  return %0 : tensor<?xf32>1110}1111 1112func.func @equivalent_func_arg_2(%c0: index, %c10: index, %c1: index, %t0: tensor<?xf32>) -> tensor<?xf32> {1113  // This test does not check IR. It just asserts there is no failure due to1114  // non-equivalent scf.for yield values.1115  %1 = scf.for %iv = %c0 to %c10 step %c1 iter_args(%t1 = %t0) -> (tensor<?xf32>) {1116    %3 = func.call @inner_func_2(%t1) : (tensor<?xf32>) -> tensor<?xf32>1117    scf.yield %3 : tensor<?xf32>1118  }1119  return %1: tensor<?xf32>1120}1121 1122// -----1123 1124// CHECK-LABEL: func @write_after_select_read_one1125//  CHECK-SAME:     %[[t1:.*]]: tensor<?xf32> {{.*}}, %[[t2:.*]]: tensor<?xf32>1126func.func @write_after_select_read_one(1127    %t1 : tensor<?xf32> {bufferization.writable = true},1128    %t2 : tensor<?xf32> {bufferization.writable = true},1129    %c : i1)1130  -> (f32, tensor<?xf32>)1131{1132  %cst = arith.constant 0.0 : f321133  %idx = arith.constant 0 : index1134 1135  //      CHECK: arith.select %{{.*}}, %[[t1]], %[[t2]]1136  // CHECK-SAME:   {__inplace_operands_attr__ = ["none", "false", "true"]}1137  %s = arith.select %c, %t1, %t2 : tensor<?xf32>1138  //      CHECK: tensor.insert1139  // CHECK-SAME:   {__inplace_operands_attr__ = ["none", "true", "none"]}1140  %w = tensor.insert %cst into %s[%idx] : tensor<?xf32>1141  //      CHECK: tensor.extract1142  // CHECK-SAME:   {__inplace_operands_attr__ = ["true", "none"]}1143  %f = tensor.extract %t1[%idx] : tensor<?xf32>1144 1145  return %f, %w : f32, tensor<?xf32>1146}1147 1148// -----1149 1150// CHECK-LABEL: func @write_after_select_read_both1151//  CHECK-SAME:     %[[t1:.*]]: tensor<?xf32> {{.*}}, %[[t2:.*]]: tensor<?xf32>1152func.func @write_after_select_read_both(1153    %t1 : tensor<?xf32> {bufferization.writable = true},1154    %t2 : tensor<?xf32> {bufferization.writable = true},1155    %c : i1)1156  -> (f32, f32, tensor<?xf32>)1157{1158  %cst = arith.constant 0.0 : f321159  %idx = arith.constant 0 : index1160 1161  //      CHECK: arith.select %{{.*}}, %[[t1]], %[[t2]]1162  // CHECK-SAME:   {__inplace_operands_attr__ = ["none", "false", "false"]}1163  %s = arith.select %c, %t1, %t2 : tensor<?xf32>1164  //      CHECK: tensor.insert1165  // CHECK-SAME:   {__inplace_operands_attr__ = ["none", "true", "none"]}1166  %w = tensor.insert %cst into %s[%idx] : tensor<?xf32>1167  //      CHECK: tensor.extract1168  // CHECK-SAME:   {__inplace_operands_attr__ = ["true", "none"]}1169  %f = tensor.extract %t1[%idx] : tensor<?xf32>1170  //      CHECK: tensor.extract1171  // CHECK-SAME:   {__inplace_operands_attr__ = ["true", "none"]}1172  %f2 = tensor.extract %t2[%idx] : tensor<?xf32>1173 1174  return %f, %f2, %w : f32, f32, tensor<?xf32>1175}1176 1177// -----1178 1179// CHECK-LABEL: func @write_after_select_no_conflict1180//  CHECK-SAME:     %[[t1:.*]]: tensor<?xf32> {{.*}}, %[[t2:.*]]: tensor<?xf32>1181func.func @write_after_select_no_conflict(1182    %t1 : tensor<?xf32> {bufferization.writable = true},1183    %t2 : tensor<?xf32> {bufferization.writable = true},1184    %c : i1)1185  -> (f32, tensor<?xf32>)1186{1187  %cst = arith.constant 0.0 : f321188  %idx = arith.constant 0 : index1189 1190  //      CHECK: arith.select %{{.*}}, %[[t1]], %[[t2]]1191  // CHECK-SAME:   {__inplace_operands_attr__ = ["none", "true", "true"]}1192  %s = arith.select %c, %t1, %t2 : tensor<?xf32>1193  //      CHECK: tensor.insert1194  // CHECK-SAME:   {__inplace_operands_attr__ = ["none", "true", "none"]}1195  %w = tensor.insert %cst into %s[%idx] : tensor<?xf32>1196  //      CHECK: tensor.extract1197  // CHECK-SAME:   {__inplace_operands_attr__ = ["true", "none"]}1198  %f = tensor.extract %w[%idx] : tensor<?xf32>1199 1200  return %f, %w : f32, tensor<?xf32>1201}1202 1203// -----1204 1205// CHECK-LABEL: func @write_to_same_tensor_in_loop_out_of_place(1206func.func @write_to_same_tensor_in_loop_out_of_place(1207    %A : tensor<?xf32> {bufferization.writable = true},1208    %B : tensor<?xf32> {bufferization.writable = true},1209    %lb : index, %ub : index, %step : index, %sz: index)1210  -> (tensor<?xf32>)1211{1212  // CHECK: scf.for {{.*}} {1213  %r0 = scf.for %i = %lb to %ub step %step iter_args(%t = %A) -> (tensor<?xf32>) {1214    %i2 = arith.index_cast %i : index to i321215    %i3 = arith.sitofp %i2 : i32 to f321216    // The tensor.insert is out-of-place because the %B is written multiple1217    // times inside a loop.1218    //      CHECK: tensor.insert1219    // CHECK-SAME:   {__inplace_operands_attr__ = ["none", "false", "none"]}1220    %B2 = tensor.insert %i3 into %B[%i] : tensor<?xf32>1221    //      CHECK: tensor.insert_slice1222    // CHECK-SAME:   {__inplace_operands_attr__ = ["true", "true", "none", "none"]}1223    %A2 = tensor.insert_slice %B2 into %t[%i][%sz][1] : tensor<?xf32> into tensor<?xf32>1224    scf.yield %A2 : tensor<?xf32>1225  }1226  // CHECK: } {__inplace_operands_attr__ = ["none", "none", "none", "true"]}1227 1228  return %r0 : tensor<?xf32>1229}1230 1231// -----1232 1233// CHECK-LABEL: func @write_to_same_alloc_tensor_in_place(1234func.func @write_to_same_alloc_tensor_in_place(1235    %A : tensor<?xf32> {bufferization.writable = true},1236    %lb : index, %ub : index, %step : index, %sz: index, %sz2: index)1237  -> (tensor<?xf32>)1238{1239  %B = bufferization.alloc_tensor(%sz2) : tensor<?xf32>1240 1241  // CHECK: scf.for {{.*}} {1242  %r0 = scf.for %i = %lb to %ub step %step iter_args(%t = %A) -> (tensor<?xf32>) {1243    %i2 = arith.index_cast %i : index to i321244    %i3 = arith.sitofp %i2 : i32 to f321245    // %B is written multiple times inside a loop, but it is an alloc_tensor.1246    //      CHECK: tensor.insert1247    // CHECK-SAME:   {__inplace_operands_attr__ = ["none", "true", "none"]}1248    %B2 = tensor.insert %i3 into %B[%i] : tensor<?xf32>1249    //      CHECK: tensor.insert_slice1250    // CHECK-SAME:   {__inplace_operands_attr__ = ["true", "true", "none", "none"]}1251    %A2 = tensor.insert_slice %B2 into %t[%i][%sz][1] : tensor<?xf32> into tensor<?xf32>1252    scf.yield %A2 : tensor<?xf32>1253  }1254  // CHECK: } {__inplace_operands_attr__ = ["none", "none", "none", "true"]}1255 1256  return %r0 : tensor<?xf32>1257}1258 1259// -----1260 1261// CHECK-LABEL: func @write_to_same_alloc_tensor_out_of_place(1262func.func @write_to_same_alloc_tensor_out_of_place(1263    %A : tensor<?xf32> {bufferization.writable = true},1264    %lb : index, %ub : index, %step : index, %sz: index, %sz2: index, %f: f32)1265  -> (tensor<?xf32>)1266{1267  %B = bufferization.alloc_tensor(%sz2) : tensor<?xf32>1268  %C = tensor.insert %f into %B[%lb] : tensor<?xf32>1269 1270  // CHECK: scf.for {{.*}} {1271  %r0 = scf.for %i = %lb to %ub step %step iter_args(%t = %A) -> (tensor<?xf32>) {1272    %i2 = arith.index_cast %i : index to i321273    %i3 = arith.sitofp %i2 : i32 to f321274    // %C is written multiple times inside a loop. Even though %C aliases with1275    // an alloc_tensor, out-of-bounds bufferization is necessary because there1276    // is another alias (%C) outside of the loop.1277    //      CHECK: tensor.insert1278    // CHECK-SAME:   {__inplace_operands_attr__ = ["none", "false", "none"]}1279    %B2 = tensor.insert %i3 into %C[%i] : tensor<?xf32>1280    //      CHECK: tensor.insert_slice1281    // CHECK-SAME:   {__inplace_operands_attr__ = ["true", "true", "none", "none"]}1282    %A2 = tensor.insert_slice %B2 into %t[%i][%sz][1] : tensor<?xf32> into tensor<?xf32>1283    scf.yield %A2 : tensor<?xf32>1284  }1285  // CHECK: } {__inplace_operands_attr__ = ["none", "none", "none", "true"]}1286 1287  return %r0 : tensor<?xf32>1288}1289 1290// -----1291 1292// CHECK-LABEL: func.func private @ext_func(tensor<?xf32> {bufferization.access = "read-write"})1293func.func private @ext_func(%t: tensor<?xf32>)1294 1295// CHECK: func.func @private_func_read_write(%{{.*}}: tensor<5xf32> {bufferization.access = "read"})1296func.func @private_func_read_write(%t: tensor<5xf32>) -> f32 {1297  %c0 = arith.constant 0 : index1298  // Bufferizes out-of-place because `ext_func` may modify the buffer.1299  // CHECK: tensor.cast {{.*}} {__inplace_operands_attr__ = ["false"]}1300  %0 = tensor.cast %t : tensor<5xf32> to tensor<?xf32>1301  func.call @ext_func(%0) : (tensor<?xf32>) -> ()1302  %1 = tensor.extract %t[%c0] : tensor<5xf32>1303  return %1 : f321304}1305 1306// -----1307 1308// CHECK-LABEL: func.func private @print_buffer(tensor<*xf32> {bufferization.access = "read"})1309func.func private @print_buffer(%t: tensor<*xf32> {bufferization.access = "read"})1310 1311// CHECK: func.func @private_func_read(%{{.*}}: tensor<5xf32> {bufferization.access = "read"})1312func.func @private_func_read(%t: tensor<5xf32>) -> f32 {1313  %c0 = arith.constant 0 : index1314  // Bufferizes in-place because `print_buffer` is read-only.1315  // CHECK: tensor.cast {{.*}} {__inplace_operands_attr__ = ["true"]}1316  %0 = tensor.cast %t : tensor<5xf32> to tensor<*xf32>1317  // CHECK: call @print_buffer(%cast) {__inplace_operands_attr__ = ["true"]}1318  func.call @print_buffer(%0) : (tensor<*xf32>) -> ()1319  %1 = tensor.extract %t[%c0] : tensor<5xf32>1320  return %1 : f321321}1322 1323// -----1324 1325// CHECK-LABEL: func.func private @ext_func(tensor<?xf32> {bufferization.access = "read-write"}, tensor<?xf32> {bufferization.access = "read-write"})1326func.func private @ext_func(%t1: tensor<?xf32>, %t2: tensor<?xf32>)1327 1328// CHECK: func.func @private_func_two_params_writing(%{{.*}}: tensor<?xf32> {bufferization.access = "read"})1329func.func @private_func_two_params_writing(%t: tensor<?xf32>) {1330  // Both operands bufferize out-of-place because both bufferize to a memory1331  // write.1332  // CHECK: call @ext_func(%{{.*}}, %{{.*}}) {__inplace_operands_attr__ = ["false", "false"]}1333  func.call @ext_func(%t, %t) : (tensor<?xf32>, tensor<?xf32>) -> ()1334  return1335}1336 1337// -----1338 1339// CHECK-LABEL: func.func private @ext_func(tensor<?xf32> {bufferization.access = "read-write"}) -> (tensor<5xf32>, tensor<6xf32>)1340func.func private @ext_func(%t: tensor<?xf32>) -> (tensor<5xf32>, tensor<6xf32>)1341 1342// CHECK: func.func @private_func_aliasing(%{{.*}}: tensor<?xf32> {bufferization.access = "read"})1343func.func @private_func_aliasing(%t: tensor<?xf32>) -> f32 {1344  %c0 = arith.constant 0 : index1345  // Bufferizes out-of-place because either one of the two reuslts may alias1346  // with the argument and one of the results is read afterwards.1347  // CHECK: call @ext_func(%{{.*}}) {__inplace_operands_attr__ = ["false"]} : (tensor<?xf32>) -> (tensor<5xf32>, tensor<6xf32>)1348  %0, %1 = func.call @ext_func(%t) : (tensor<?xf32>) -> (tensor<5xf32>, tensor<6xf32>)1349  %2 = tensor.extract %1[%c0] : tensor<6xf32>1350  return %2 : f321351}1352 1353// -----1354 1355// CHECK-LABEL: func @recursive_function1356func.func @recursive_function(%a: tensor<?xf32>, %b: tensor<?xf32>) -> (tensor<?xf32>, tensor<?xf32>) {1357  // The analysis does not support recursive function calls and is conservative1358  // around them.1359  // CHECK: call @recursive_function1360  // CHECK-SAME: {__inplace_operands_attr__ = ["false", "false"]}1361  %0:2 = call @recursive_function(%a, %b) : (tensor<?xf32>, tensor<?xf32>) -> (tensor<?xf32>, tensor<?xf32>)1362  return %0#0, %0#1 : tensor<?xf32>, tensor<?xf32>1363}1364 1365// -----1366 1367// CHECK-ALIAS-SETS-LABEL: func @multiple_returns(1368func.func @multiple_returns(%c: i1, %t0: tensor<5xf32>, %t1: tensor<5xf32>, %t2: tensor<5xf32>) -> tensor<5xf32> {1369  cf.cond_br %c, ^bb1, ^bb21370^bb1:1371  return %t0 : tensor<5xf32>1372^bb2:1373  return %t1 : tensor<5xf32>1374}1375 1376//       CHECK-ALIAS-SETS: func @caller(1377//  CHECK-ALIAS-SETS-SAME:     %{{.*}}: i1, %[[t0:.*]]: tensor<5xf32> {bufferization.access = "read"}, %[[t1:.*]]: tensor<5xf32> {bufferization.access = "read"}, %[[t2:.*]]: tensor<5xf32> {bufferization.access = "none"})1378func.func @caller(%c: i1, %t0: tensor<5xf32>, %t1: tensor<5xf32>, %t2: tensor<5xf32>) {1379  // Check that alias sets are computed correctly.1380  //      CHECK-ALIAS-SETS: %[[result:.*]] = call @multiple_returns1381  // CHECK-ALIAS-SETS-SAME: {__inplace_operands_attr__ = ["none", "true", "true", "true"],1382  // CHECK-ALIAS-SETS-SAME:  __opresult_alias_set_attr__ = [{{\[}}"%[[result]]", "%[[t0]]", "%[[t1]]"]]}1383  call @multiple_returns(%c, %t0, %t1, %t2) : (i1, tensor<5xf32>, tensor<5xf32>, tensor<5xf32>) -> (tensor<5xf32>)1384  return1385}1386 1387// -----1388 1389// CHECK-ALIAS-SETS-LABEL: func @multiple_equivalent_returns(1390func.func @multiple_equivalent_returns(%c: i1, %t0: tensor<5xf32>, %t1: tensor<5xf32>, %t2: tensor<5xf32>) -> tensor<5xf32> {1391  cf.cond_br %c, ^bb1, ^bb21392^bb1:1393  return %t0 : tensor<5xf32>1394^bb2:1395  return %t0 : tensor<5xf32>1396}1397 1398//       CHECK-ALIAS-SETS: func @caller(1399//  CHECK-ALIAS-SETS-SAME:     %{{.*}}: i1, %[[t0:.*]]: tensor<5xf32> {bufferization.access = "read"}, %[[t1:.*]]: tensor<5xf32> {bufferization.access = "none"}, %[[t2:.*]]: tensor<5xf32> {bufferization.access = "none"})1400func.func @caller(%c: i1, %t0: tensor<5xf32>, %t1: tensor<5xf32>, %t2: tensor<5xf32>) -> tensor<5xf32> {1401  // Check that equivalence sets are computed correctly.1402  //      CHECK-ALIAS-SETS: %[[result:.*]] = call @multiple_equivalent_returns1403  // CHECK-ALIAS-SETS-SAME: {__inplace_operands_attr__ = ["none", "true", "true", "true"],1404  // CHECK-ALIAS-SETS-SAME:  __opresult_alias_set_attr__ = [{{\[}}"%[[result]]", "%[[t0]]"]]}1405  %r = call @multiple_equivalent_returns(%c, %t0, %t1, %t2) : (i1, tensor<5xf32>, tensor<5xf32>, tensor<5xf32>) -> (tensor<5xf32>)1406  // CHECK-ALIAS-SETS-SAME: {__equivalent_func_args__ = [1], __inplace_operands_attr__ = ["true"]} %[[result]] : tensor<5xf32>1407  return %r : tensor<5xf32>1408}1409 1410// -----1411 1412// CHECK-ALIAS-LABEL: func @foo1413func.func @foo(%arg0: tensor<?xf32>) -> tensor<?xf32> {1414  // CHECK-ALIAS: return1415  // CHECK-ALIAS-SAME: __equivalent_func_args__ = [0]1416  return %arg0 : tensor<?xf32>1417}1418 1419// CHECK-ALIAS: func @bar(%[[arg0:.*]]: tensor<?xf32>1420func.func @bar(%arg0: tensor<?xf32>) -> tensor<?xf32> {1421  // CHECK-ALIAS: %[[call:.*]] = call @foo(%[[arg0]])1422  // CHECK-ALIAS-SAME: {__inplace_operands_attr__ = ["true"], __opresult_alias_set_attr__ = [{{\[}}"%[[call]]", "%[[arg0]]"]]}1423  %x = call @foo(%arg0) : (tensor<?xf32>) -> tensor<?xf32>1424  // CHECK-ALIAS: return1425  // CHECK-ALIAS-SAME: __equivalent_func_args__ = [0]1426  return %x : tensor<?xf32>1427}1428