blob: a8342fc3e3c4d0c3cd18a86288b9edb1dea36150 [file]
// RUN: iree-opt --split-input-file --iree-stablehlo-input-transformation-pipeline %s \
// RUN: | FileCheck %s --implicit-check-not=stablehlo.
// Every dim and every amount differs so a swapped or misplaced fold is caught.
// CHECK-LABEL: @dynamic_pad_constant
// CHECK: tensor.pad %arg0 low[1, 0, 2] high[0, 2, 1]
// CHECK: return %{{.+}} : tensor<3x5x8xf32>
func.func @dynamic_pad_constant(%arg0: tensor<2x3x5xf32>, %arg1: tensor<f32>) -> tensor<3x5x8xf32> {
%low = stablehlo.constant dense<[1, 0, 2]> : tensor<3xi64>
%high = stablehlo.constant dense<[0, 2, 1]> : tensor<3xi64>
%interior = stablehlo.constant dense<0> : tensor<3xi64>
%0 = "stablehlo.dynamic_pad"(%arg0, %arg1, %low, %high, %interior)
: (tensor<2x3x5xf32>, tensor<f32>, tensor<3xi64>, tensor<3xi64>, tensor<3xi64>)
-> tensor<3x5x8xf32>
return %0 : tensor<3x5x8xf32>
}
// -----
// Interior padding becomes the stride of the insert.
// CHECK-LABEL: @dynamic_pad_interior
// CHECK: linalg.fill
// CHECK: tensor.insert_slice %arg0 into %{{.+}}[0, 1, 0] [2, 3, 5] [2, 1, 3]
// CHECK: return %{{.+}} : tensor<4x7x15xf32>
func.func @dynamic_pad_interior(%arg0: tensor<2x3x5xf32>, %arg1: tensor<f32>) -> tensor<4x7x15xf32> {
%low = stablehlo.constant dense<[0, 1, 0]> : tensor<3xi64>
%high = stablehlo.constant dense<[1, 3, 2]> : tensor<3xi64>
%interior = stablehlo.constant dense<[1, 0, 2]> : tensor<3xi64>
%0 = "stablehlo.dynamic_pad"(%arg0, %arg1, %low, %high, %interior)
: (tensor<2x3x5xf32>, tensor<f32>, tensor<3xi64>, tensor<3xi64>, tensor<3xi64>)
-> tensor<4x7x15xf32>
return %0 : tensor<4x7x15xf32>
}
// -----
// Negative low and high amounts crop.
// CHECK-LABEL: @dynamic_pad_negative_edges
// CHECK: tensor.pad %arg0 low[0, 0, 1] high[0, 2, 2]
// CHECK: tensor.extract_slice %{{.+}}[1, 0, 0] [1, 5, 4] [1, 1, 1]
// CHECK: return %{{.+}} : tensor<1x5x4xf32>
func.func @dynamic_pad_negative_edges(%arg0: tensor<2x3x5xf32>, %arg1: tensor<f32>) -> tensor<1x5x4xf32> {
%low = stablehlo.constant dense<[-1, 0, 1]> : tensor<3xi64>
%high = stablehlo.constant dense<[0, 2, -2]> : tensor<3xi64>
%interior = stablehlo.constant dense<0> : tensor<3xi64>
%0 = "stablehlo.dynamic_pad"(%arg0, %arg1, %low, %high, %interior)
: (tensor<2x3x5xf32>, tensor<f32>, tensor<3xi64>, tensor<3xi64>, tensor<3xi64>)
-> tensor<1x5x4xf32>
return %0 : tensor<1x5x4xf32>
}
// -----
// A negative high amount crops after the interior padding is applied.
// CHECK-LABEL: @dynamic_pad_negative_high_interior
// CHECK: tensor.insert_slice %arg0 into %{{.+}}[0, 0, 0] [2, 3, 5] [2, 1, 3]
// CHECK: tensor.extract_slice %{{.+}}[0, 0, 0] [1, 4, 13] [1, 1, 1]
// CHECK: return %{{.+}} : tensor<1x4x13xf32>
func.func @dynamic_pad_negative_high_interior(%arg0: tensor<2x3x5xf32>, %arg1: tensor<f32>) -> tensor<1x4x13xf32> {
%low = stablehlo.constant dense<0> : tensor<3xi64>
%high = stablehlo.constant dense<[-2, 1, 0]> : tensor<3xi64>
%interior = stablehlo.constant dense<[1, 0, 2]> : tensor<3xi64>
%0 = "stablehlo.dynamic_pad"(%arg0, %arg1, %low, %high, %interior)
: (tensor<2x3x5xf32>, tensor<f32>, tensor<3xi64>, tensor<3xi64>, tensor<3xi64>)
-> tensor<1x4x13xf32>
return %0 : tensor<1x4x13xf32>
}
// -----
// Constant amounts on a dynamic operand fold to a pad with a dynamic result.
// CHECK-LABEL: @dynamic_pad_dynamic_operand
// CHECK: tensor.pad %arg0 low[1, 0] high[2, 4]
// CHECK: return %{{.+}} : tensor<?x7xf32>
func.func @dynamic_pad_dynamic_operand(%arg0: tensor<?x3xf32>, %arg1: tensor<f32>) -> tensor<?x7xf32> {
%low = stablehlo.constant dense<[1, 0]> : tensor<2xi64>
%high = stablehlo.constant dense<[2, 4]> : tensor<2xi64>
%interior = stablehlo.constant dense<0> : tensor<2xi64>
%0 = "stablehlo.dynamic_pad"(%arg0, %arg1, %low, %high, %interior)
: (tensor<?x3xf32>, tensor<f32>, tensor<2xi64>, tensor<2xi64>, tensor<2xi64>)
-> tensor<?x7xf32>
return %0 : tensor<?x7xf32>
}
// -----
// The low amounts are a constant only after the concatenate folds.
// CHECK-LABEL: @dynamic_pad_folded_shape
// CHECK: tensor.pad %arg0 low[1, 2] high[0, 3]
// CHECK: return %{{.+}} : tensor<5x10xf32>
func.func @dynamic_pad_folded_shape(%arg0: tensor<4x5xf32>, %arg1: tensor<f32>) -> tensor<5x10xf32> {
%c1 = stablehlo.constant dense<1> : tensor<1xi32>
%c2 = stablehlo.constant dense<2> : tensor<1xi32>
%low = stablehlo.concatenate %c1, %c2, dim = 0 : (tensor<1xi32>, tensor<1xi32>) -> tensor<2xi32>
%high = stablehlo.constant dense<[0, 3]> : tensor<2xi32>
%interior = stablehlo.constant dense<0> : tensor<2xi32>
%0 = "stablehlo.dynamic_pad"(%arg0, %arg1, %low, %high, %interior)
: (tensor<4x5xf32>, tensor<f32>, tensor<2xi32>, tensor<2xi32>, tensor<2xi32>)
-> tensor<5x10xf32>
return %0 : tensor<5x10xf32>
}
// -----
// The amounts are constants only after @low and @high are inlined.
// CHECK-LABEL: @dynamic_pad_after_inline
// CHECK: tensor.pad %arg0 low[1, 0] high[0, 3]
// CHECK: return %{{.+}} : tensor<3x8xf32>
func.func private @low() -> tensor<2xi64> {
%c = stablehlo.constant dense<[1, 0]> : tensor<2xi64>
return %c : tensor<2xi64>
}
func.func private @high() -> tensor<2xi64> {
%c = stablehlo.constant dense<[0, 3]> : tensor<2xi64>
return %c : tensor<2xi64>
}
func.func @dynamic_pad_after_inline(%arg0: tensor<2x5xf32>, %arg1: tensor<f32>) -> tensor<3x8xf32> {
%low = call @low() : () -> tensor<2xi64>
%high = call @high() : () -> tensor<2xi64>
%interior = stablehlo.constant dense<0> : tensor<2xi64>
%0 = "stablehlo.dynamic_pad"(%arg0, %arg1, %low, %high, %interior)
: (tensor<2x5xf32>, tensor<f32>, tensor<2xi64>, tensor<2xi64>, tensor<2xi64>)
-> tensor<3x8xf32>
return %0 : tensor<3x8xf32>
}
// -----
// Start indices are clamped to operand_dim - slice_size: 5 - 1 and 8 - 3.
// CHECK-LABEL: @dynamic_gather_constant
// CHECK-DAG: arith.constant 4 : index
// CHECK-DAG: arith.constant 5 : index
// CHECK: linalg.generic
// CHECK: return %{{.+}} : tensor<2x7x3x2xi32>
func.func @dynamic_gather_constant(%arg0: tensor<5x8x2xi32>,
%arg1: tensor<2x7x2xi64>) -> tensor<2x7x3x2xi32> {
%sizes = stablehlo.constant dense<[1, 3, 2]> : tensor<3xi32>
%0 = "stablehlo.dynamic_gather"(%arg0, %arg1, %sizes) {
dimension_numbers = #stablehlo.gather<offset_dims = [2, 3],
collapsed_slice_dims = [0],
start_index_map = [1, 0],
index_vector_dim = 2>,
indices_are_sorted = false
} : (tensor<5x8x2xi32>, tensor<2x7x2xi64>, tensor<3xi32>) -> tensor<2x7x3x2xi32>
return %0 : tensor<2x7x3x2xi32>
}
// -----
// A zero slice size gives an empty result.
// CHECK-LABEL: @dynamic_gather_zero_slice
// CHECK: %[[EMPTY:.+]] = tensor.empty() : tensor<6x0x2xi32>
// CHECK: return %[[EMPTY]]
func.func @dynamic_gather_zero_slice(%arg0: tensor<5x8x2xi32>,
%arg1: tensor<6x2xi64>) -> tensor<6x0x2xi32> {
%sizes = stablehlo.constant dense<[1, 0, 2]> : tensor<3xi64>
%0 = "stablehlo.dynamic_gather"(%arg0, %arg1, %sizes) {
dimension_numbers = #stablehlo.gather<offset_dims = [1, 2],
collapsed_slice_dims = [0],
start_index_map = [0, 1],
index_vector_dim = 1>,
indices_are_sorted = false
} : (tensor<5x8x2xi32>, tensor<6x2xi64>, tensor<3xi64>) -> tensor<6x0x2xi32>
return %0 : tensor<6x0x2xi32>
}
// -----
// Row i of the padding is [low, high] of spatial dim i.
// CHECK-LABEL: @dynamic_conv_constant
// CHECK: tensor.pad %arg0 low[0, 1, 0, 0] high[0, 2, 1, 0]
// CHECK: linalg.conv_2d_nhwc_hwcf
// CHECK-SAME: ins(%{{.+}}, %{{.+}} : tensor<2x11x7x3xf32>, tensor<3x2x3x4xf32>)
// CHECK: return %{{.+}} : tensor<2x9x6x4xf32>
func.func @dynamic_conv_constant(%arg0: tensor<2x8x6x3xf32>,
%arg1: tensor<3x2x3x4xf32>) -> tensor<2x9x6x4xf32> {
%padding = stablehlo.constant dense<[[1, 2], [0, 1]]> : tensor<2x2xi32>
%0 = "stablehlo.dynamic_conv"(%arg0, %arg1, %padding) {
dimension_numbers = #stablehlo.conv<[b, 0, 1, f]x[0, 1, i, o]->[b, 0, 1, f]>,
feature_group_count = 1 : i64,
batch_group_count = 1 : i64,
window_strides = array<i64: 1, 1>,
lhs_dilation = array<i64: 1, 1>,
rhs_dilation = array<i64: 1, 1>
} : (tensor<2x8x6x3xf32>, tensor<3x2x3x4xf32>, tensor<2x2xi32>) -> tensor<2x9x6x4xf32>
return %0 : tensor<2x9x6x4xf32>
}
// -----
// Negative padding crops the input before the convolution.
// CHECK-LABEL: @dynamic_conv_negative_padding
// CHECK: tensor.extract_slice %{{.+}}[0, 1, 0, 0] [2, 7, 4, 3] [1, 1, 1, 1]
// CHECK: linalg.conv_2d_nhwc_hwcf
// CHECK-SAME: ins(%{{.+}}, %{{.+}} : tensor<2x7x4x3xf32>, tensor<3x2x3x4xf32>)
// CHECK: return %{{.+}} : tensor<2x5x3x4xf32>
func.func @dynamic_conv_negative_padding(%arg0: tensor<2x8x6x3xf32>,
%arg1: tensor<3x2x3x4xf32>) -> tensor<2x5x3x4xf32> {
%padding = stablehlo.constant dense<[[-1, 0], [0, -2]]> : tensor<2x2xi64>
%0 = "stablehlo.dynamic_conv"(%arg0, %arg1, %padding) {
dimension_numbers = #stablehlo.conv<[b, 0, 1, f]x[0, 1, i, o]->[b, 0, 1, f]>,
feature_group_count = 1 : i64,
batch_group_count = 1 : i64,
window_strides = array<i64: 1, 1>,
lhs_dilation = array<i64: 1, 1>,
rhs_dilation = array<i64: 1, 1>
} : (tensor<2x8x6x3xf32>, tensor<3x2x3x4xf32>, tensor<2x2xi64>) -> tensor<2x5x3x4xf32>
return %0 : tensor<2x5x3x4xf32>
}