// RUN: mlir-opt %s -canonicalize -split-input-file | FileCheck %s // CHECK-LABEL: func @memref_cast( func @memref_cast(%a: index, %b: index) -> memref { %c0 = constant 0 : index %c1 = constant 1 : index %c8 = constant 8 : index %c16 = constant 16 : index %1 = alloc (%b) : memref %2 = view %1[%c0][] : memref to memref<16x16xf32> %3 = memref_cast %2 : memref<16x16xf32> to memref %r0 = linalg.range %c0:%c8:%c1 : !linalg.range // CHECK: linalg.slice {{.*}} : memref<16x16xf32>, !linalg.range, !linalg.range, memref %4 = linalg.slice %3[%r0, %r0] : memref, !linalg.range, !linalg.range, memref // CHECK: linalg.matmul ins({{.*}}memref<16x16xf32>, memref<16x16xf32>) outs({{.*}}memref<16x16xf32>) linalg.matmul ins(%3, %3: memref, memref) outs(%3: memref) return %4: memref } // ----- func @collapsing_tensor_reshapes(%arg0 : tensor) -> tensor { %0 = linalg.tensor_reshape %arg0 [affine_map<(d0, d1, d2, d3, d4) -> (d0, d1)>, affine_map<(d0, d1, d2, d3, d4) -> (d2)>, affine_map<(d0, d1, d2, d3, d4) -> (d3, d4)>] : tensor into tensor %1 = linalg.tensor_reshape %0 [affine_map<(d0, d1, d2) -> (d0, d1)>, affine_map<(d0, d1, d2) -> (d2)>] : tensor into tensor return %1 : tensor } // CHECK-DAG: #[[$MAP0:.*]] = affine_map<(d0, d1, d2, d3, d4) -> (d0, d1, d2)> // CHECK-DAG: #[[$MAP1:.*]] = affine_map<(d0, d1, d2, d3, d4) -> (d3, d4)> // CHECK-LABEL: collapsing_tensor_reshapes // CHECK: linalg.tensor_reshape %{{.*}} [#[[$MAP0]], #[[$MAP1]]] // CHECK-NOT: linalg.tensor_reshape // ----- // ----- func @collapsing_tensor_reshapes_to_zero_dim(%arg0 : tensor<1x1x1xf32>) -> tensor { %0 = linalg.tensor_reshape %arg0 [affine_map<(d0, d1, d2) -> (d0, d1, d2)>] : tensor<1x1x1xf32> into tensor<1xf32> %1 = linalg.tensor_reshape %0 [] : tensor<1xf32> into tensor return %1 : tensor } // CHECK-LABEL: collapsing_tensor_reshapes_to_zero // CHECK: linalg.tensor_reshape %{{.*}} [] // CHECK-SAME: tensor<1x1x1xf32> into tensor // ----- func @collapsing_memref_reshapes_to_zero_dim(%arg0 : memref<1x1x1xf32>) -> memref { %0 = linalg.reshape %arg0 [affine_map<(d0, d1, d2) -> (d0, d1, d2)>] : memref<1x1x1xf32> into memref<1xf32> %1 = linalg.reshape %0 [] : memref<1xf32> into memref return %1 : memref } // CHECK-LABEL: collapsing_memref_reshapes_to_zero // CHECK: linalg.reshape %{{.*}} [] // CHECK-SAME: memref<1x1x1xf32> into memref // ----- func @expanding_tensor_reshapes(%arg0 : tensor) -> tensor { %0 = linalg.tensor_reshape %arg0 [affine_map<(d0, d1, d2) -> (d0, d1)>, affine_map<(d0, d1, d2) -> (d2)>] : tensor into tensor %1 = linalg.tensor_reshape %0 [affine_map<(d0, d1, d2, d3, d4) -> (d0, d1)>, affine_map<(d0, d1, d2, d3, d4) -> (d2)>, affine_map<(d0, d1, d2, d3, d4) -> (d3, d4)>] : tensor into tensor return %1 : tensor } // CHECK-DAG: #[[$MAP0:.*]] = affine_map<(d0, d1, d2, d3, d4) -> (d0, d1, d2)> // CHECK-DAG: #[[$MAP1:.*]] = affine_map<(d0, d1, d2, d3, d4) -> (d3, d4)> // CHECK-LABEL: expanding_tensor_reshapes // CHECK: linalg.tensor_reshape %{{.*}} [#[[$MAP0]], #[[$MAP1]]] // CHECK-NOT: linalg.tensor_reshape // ----- func @collapsing_memref_reshapes(%arg0 : memref) -> memref { %0 = linalg.reshape %arg0 [affine_map<(d0, d1, d2, d3, d4) -> (d0, d1)>, affine_map<(d0, d1, d2, d3, d4) -> (d2)>, affine_map<(d0, d1, d2, d3, d4) -> (d3, d4)>] : memref into memref %1 = linalg.reshape %0 [affine_map<(d0, d1, d2) -> (d0, d1)>, affine_map<(d0, d1, d2) -> (d2)>] : memref into memref return %1 : memref } // CHECK-DAG: #[[$MAP0:.*]] = affine_map<(d0, d1, d2, d3, d4) -> (d0, d1, d2)> // CHECK-DAG: #[[$MAP1:.*]] = affine_map<(d0, d1, d2, d3, d4) -> (d3, d4)> // CHECK-LABEL: collapsing_memref_reshapes // CHECK: linalg.reshape %{{.*}} [#[[$MAP0]], #[[$MAP1]]] // CHECK-NOT: linalg.reshape // ----- func @expanding_memref_reshapes(%arg0 : memref) -> memref { %0 = linalg.reshape %arg0 [affine_map<(d0, d1, d2) -> (d0, d1)>, affine_map<(d0, d1, d2) -> (d2)>] : memref into memref %1 = linalg.reshape %0 [affine_map<(d0, d1, d2, d3, d4) -> (d0, d1)>, affine_map<(d0, d1, d2, d3, d4) -> (d2)>, affine_map<(d0, d1, d2, d3, d4) -> (d3, d4)>] : memref into memref return %1 : memref } // CHECK-DAG: #[[$MAP0:.*]] = affine_map<(d0, d1, d2, d3, d4) -> (d0, d1, d2)> // CHECK-DAG: #[[$MAP1:.*]] = affine_map<(d0, d1, d2, d3, d4) -> (d3, d4)> // CHECK-LABEL: expanding_memref_reshapes // CHECK: linalg.reshape %{{.*}} [#[[$MAP0]], #[[$MAP1]]] // CHECK-NOT: linalg.reshape // ----- func @expanding_tensor_reshapes_to_zero_dim(%arg0 : tensor) -> tensor<1x1x1xf32> { %0 = linalg.tensor_reshape %arg0 [] : tensor into tensor<1xf32> %1 = linalg.tensor_reshape %0 [affine_map<(d0, d1, d2) -> (d0, d1, d2)>] : tensor<1xf32> into tensor<1x1x1xf32> return %1 : tensor<1x1x1xf32> } // CHECK-LABEL: expanding_tensor_reshapes_to_zero // CHECK: linalg.tensor_reshape %{{.*}} [] // CHECK-SAME: tensor into tensor<1x1x1xf32> // ----- func @expanding_memref_reshapes_to_zero_dim(%arg0 : memref) -> memref<1x1x1xf32> { %0 = linalg.reshape %arg0 [] : memref into memref<1xf32> %1 = linalg.reshape %0 [affine_map<(d0, d1, d2) -> (d0, d1, d2)>] : memref<1xf32> into memref<1x1x1xf32> return %1 : memref<1x1x1xf32> } // CHECK-LABEL: expanding_memref_reshapes_to_zero // CHECK: linalg.reshape %{{.*}} [] // CHECK-SAME: memref into memref<1x1x1xf32> // ----- func @fold_tensor_reshape(%arg0 : tensor<12x4xf32>) -> tensor<12x4xf32> { %0 = linalg.tensor_reshape %arg0 [affine_map<(d0, d1, d2) -> (d0, d1)>, affine_map<(d0, d1, d2) -> (d2)>] : tensor<12x4xf32> into tensor<3x4x4xf32> %1 = linalg.tensor_reshape %0 [affine_map<(d0, d1, d2) -> (d0, d1)>, affine_map<(d0, d1, d2) -> (d2)>] : tensor<3x4x4xf32> into tensor<12x4xf32> return %1 : tensor<12x4xf32> } // CHECK-LABEL: @fold_tensor_reshape // CHECK-NOT: linalg.tensor_reshape // ----- func @no_fold_tensor_reshape(%arg0 : tensor) -> tensor { %0 = linalg.tensor_reshape %arg0 [affine_map<(d0, d1, d2) -> (d0, d1)>, affine_map<(d0, d1, d2) -> (d2)>] : tensor into tensor %1 = linalg.tensor_reshape %0 [affine_map<(d0, d1, d2) -> (d0, d1)>, affine_map<(d0, d1, d2) -> (d2)>] : tensor into tensor return %1 : tensor } // CHECK-LABEL: @no_fold_tensor_reshape // CHECK: linalg.tensor_reshape // CHECK: linalg.tensor_reshape // ----- func @fold_memref_reshape(%arg0 : memref<12x4xf32>) -> memref<12x4xf32> { %0 = linalg.reshape %arg0 [affine_map<(d0, d1, d2) -> (d0, d1)>, affine_map<(d0, d1, d2) -> (d2)>] : memref<12x4xf32> into memref<3x4x4xf32> %1 = linalg.reshape %0 [affine_map<(d0, d1, d2) -> (d0, d1)>, affine_map<(d0, d1, d2) -> (d2)>] : memref<3x4x4xf32> into memref<12x4xf32> return %1 : memref<12x4xf32> } // CHECK-LABEL: @fold_memref_reshape // CHECK-NOT: linalg.reshape // ----- func @no_fold_memref_reshape(%arg0 : memref) -> memref { %0 = linalg.reshape %arg0 [affine_map<(d0, d1, d2) -> (d0, d1)>, affine_map<(d0, d1, d2) -> (d2)>] : memref into memref %1 = linalg.reshape %0 [affine_map<(d0, d1, d2) -> (d0, d1)>, affine_map<(d0, d1, d2) -> (d2)>] : memref into memref return %1 : memref } // CHECK-LABEL: @no_fold_memref_reshape // CHECK: linalg.reshape // CHECK: linalg.reshape // ----- #accesses = [ affine_map<(i) -> (i)>, affine_map<(i) -> (i)> ] #trait = { indexing_maps = #accesses, iterator_types = ["parallel"] } func @dce_zero_memref(%arg0 : memref<0xf32>, %arg1: tensor<0xf32>) -> tensor<0xf32> { // memref<0x32> is expected to be dce'ed linalg.copy(%arg0, %arg0): memref<0xf32>, memref<0xf32> // tensor<0xf32> cannot be dce'ed %1 = linalg.generic #trait ins(%arg1 : tensor<0xf32>) { ^bb(%0: f32) : linalg.yield %0 : f32 } -> tensor<0xf32> return %1: tensor<0xf32> } // CHECK-LABEL: @dce_zero_memref // CHECK-NOT: linalg.copy // CHECK-NEXT: linalg.generic // ----- func @reshape_splat_constant_int32() -> tensor<2x4x2xi32> { %c0 = constant dense<42> : tensor<2x8xi32> %0 = linalg.tensor_reshape %c0 [affine_map<(d0, d1, d2) -> (d0)>, affine_map<(d0, d1, d2) -> (d1, d2)>] : tensor<2x8xi32> into tensor<2x4x2xi32> return %0 : tensor<2x4x2xi32> } // CHECK-LABEL: @reshape_splat_constant_int32 // CHECK: %[[CST:.*]] = constant dense<{{.*}}> : tensor<2x4x2xi32> // CHECK-NOT: linalg.tensor_reshape // CHECK: return %[[CST]] func @reshape_splat_constant_int16() -> tensor<2x4x2xi16> { %c0 = constant dense<42> : tensor<2x8xi16> %0 = linalg.tensor_reshape %c0 [affine_map<(d0, d1, d2) -> (d0)>, affine_map<(d0, d1, d2) -> (d1, d2)>] : tensor<2x8xi16> into tensor<2x4x2xi16> return %0 : tensor<2x4x2xi16> } // CHECK-LABEL: @reshape_splat_constant_int16 // CHECK: %[[CST:.*]] = constant dense<{{.*}}> : tensor<2x4x2xi16> // CHECK-NOT: linalg.tensor_reshape // CHECK: return %[[CST]] func @reshape_splat_constant_float32() -> tensor<2x4x2xf32> { %c0 = constant dense<42.0> : tensor<2x8xf32> %0 = linalg.tensor_reshape %c0 [affine_map<(d0, d1, d2) -> (d0)>, affine_map<(d0, d1, d2) -> (d1, d2)>] : tensor<2x8xf32> into tensor<2x4x2xf32> return %0 : tensor<2x4x2xf32> } // CHECK-LABEL: @reshape_splat_constant_float32 // CHECK: %[[CST:.*]] = constant dense<{{.*}}> : tensor<2x4x2xf32> // CHECK-NOT: linalg.tensor_reshape // CHECK: return %[[CST]] func @reshape_splat_constant_float64() -> tensor<2x4x2xf64> { %c0 = constant dense<42.0> : tensor<2x8xf64> %0 = linalg.tensor_reshape %c0 [affine_map<(d0, d1, d2) -> (d0)>, affine_map<(d0, d1, d2) -> (d1, d2)>] : tensor<2x8xf64> into tensor<2x4x2xf64> return %0 : tensor<2x4x2xf64> } // CHECK-LABEL: @reshape_splat_constant_float64 // CHECK: %[[CST:.*]] = constant dense<{{.*}}> : tensor<2x4x2xf64> // CHECK-NOT: linalg.tensor_reshape // CHECK: return %[[CST]] // ----- // CHECK-LABEL: func @tensor_cast( func @tensor_cast(%a : tensor<3x4xf32>, %b : tensor<4x?xf32>, %c : tensor<3x?xf32>) -> tensor<3x?xf32> { %ta = tensor_cast %a : tensor<3x4xf32> to tensor %tb = tensor_cast %b : tensor<4x?xf32> to tensor %tc = tensor_cast %c : tensor<3x?xf32> to tensor // CHECK: linalg.matmul ins({{.*}}tensor<3x4xf32>, tensor<4x?xf32>) // CHECK-SAME: init({{.*}}tensor<3x?xf32>) -> tensor<3x?xf32> %0 = linalg.matmul ins(%ta, %tb: tensor, tensor) init(%tc: tensor) -> tensor %1 = tensor_cast %0 : tensor to tensor<3x?xf32> return %1: tensor<3x?xf32> } // ----- // CHECK-LABEL: func @linalg_effects( // CHECK-SAME: %[[A:[a-z0-9]*]]: tensor // CHECK-SAME: %[[B:[a-z0-9]*]]: memref // CHECK-SAME: %[[C:[a-z0-9]*]]: tensor func @linalg_effects(%a : tensor, %b : memref, %c : tensor) { // CHECK-NOT: %{{.*}} = linalg.matmul %t = linalg.matmul ins(%a, %b : tensor, memref) init(%c : tensor) -> tensor // CHECK-NOT: %{{.*}} = linalg.matmul linalg.matmul ins(%a, %c : tensor, tensor) outs(%b : memref) return }