static OpFoldResult foldReshapeOp(ReshapeOpTy reshapeOp,
ArrayRef<Attribute> operands) {
// Fold producer-consumer reshape ops that where the operand type of the
- // producer is same as the return type of the consumer. This can only be
- // verified if the shapes in question are static.
+ // producer is same as the return type of the consumer.
ReshapeOpTy reshapeSrcOp =
reshapeOp.src().template getDefiningOp<ReshapeOpTy>();
- if (reshapeSrcOp && reshapeSrcOp.getSrcType().hasStaticShape() &&
- reshapeOp.getResultType().hasStaticShape() &&
- reshapeSrcOp.getSrcType() == reshapeOp.getResultType())
+ if (reshapeSrcOp && reshapeSrcOp.getSrcType() == reshapeOp.getResultType())
return reshapeSrcOp.src();
// Reshape of a constant can be replaced with a new constant.
if (auto elements = operands.front().dyn_cast_or_null<DenseElementsAttr>()) {
Value mlir::linalg::ReshapeOp::getViewSource() { return src(); }
+/// Verify that shapes of the reshaped types using following rules
+/// 1) if a dimension in the collapsed type is static, then the corresponding
+/// dimensions in the expanded shape should be
+/// a) static
+/// b) the product should be same as the collaped shape.
+/// 2) if a dimension in the collaped type is dynamic, one and only one of the
+/// corresponding dimensions in the expanded type should be dynamic. This
+/// rule is only needed with reshape operations that are expanding.
+template <typename OpTy>
+static LogicalResult verifyReshapeLikeShapes(OpTy op, ShapedType collapsedType,
+ ShapedType expandedType,
+ bool isExpandingReshape) {
+ ArrayRef<int64_t> collapsedShape = collapsedType.getShape();
+ ArrayRef<int64_t> expandedShape = expandedType.getShape();
+ unsigned expandedDimStart = 0;
+ for (auto map : llvm::enumerate(op.getReassociationMaps())) {
+ Optional<int64_t> dynamicDims;
+ int64_t linearizedStaticShape = 1;
+ for (auto dim : llvm::enumerate(expandedShape.slice(
+ expandedDimStart, map.value().getNumResults()))) {
+ if (ShapedType::isDynamic(dim.value())) {
+ if (isExpandingReshape && dynamicDims) {
+ return op->emitOpError("invalid to have a single dimension (")
+ << map.index() << ") expanded into multiple dynamic dims ("
+ << expandedDimStart + dynamicDims.getValue() << ","
+ << expandedDimStart + dim.index() << ")";
+ }
+ dynamicDims = dim.index();
+ } else {
+ linearizedStaticShape *= dim.value();
+ }
+ }
+ if (dynamicDims) {
+ if (!ShapedType::isDynamic(collapsedShape[map.index()])) {
+ return op->emitOpError("expected dimension ")
+ << map.index()
+ << " of collapsed type to be dynamic since one or more of the "
+ "corresponding dimensions in the expanded type is dynamic";
+ }
+ } else {
+ if (collapsedShape[map.index()] != linearizedStaticShape) {
+ return op->emitOpError("expected dimension ")
+ << map.index() << " of collapsed type to be static value of "
+ << linearizedStaticShape << " ";
+ }
+ }
+ expandedDimStart += map.value().getNumResults();
+ }
+ return success();
+}
+
// Common verifier for reshape-like types. Fills `expandedType` and
// `collapsedType` with the proper `src` or `result` type.
template <typename Op, typename T>
if (!isReassociationValid(maps, &invalidIdx))
return op.emitOpError("expected reassociation map #")
<< invalidIdx << " to be valid and contiguous";
- return success();
+ return verifyReshapeLikeShapes(op, collapsedType, expandedType, !isCollapse);
}
static LogicalResult verify(ReshapeOp op) {
if (failed(verifyReshapeLikeTypes(op, expandedType, collapsedType)))
return failure();
auto maps = getAffineMaps(op.reassociation());
- // TODO: expanding a ? with a non-constant is under-specified. Error
- // out.
RankedTensorType expectedType =
computeTensorReshapeCollapsedType(expandedType, maps);
if (collapsedType != expectedType)
// -----
-// -----
-
func @collapsing_tensor_reshapes_to_zero_dim(%arg0 : tensor<1x1x1xf32>)
-> tensor<f32> {
%0 = linalg.tensor_reshape %arg0 [affine_map<(d0, d1, d2) -> (d0, d1, d2)>] :
// -----
-func @expanding_tensor_reshapes(%arg0 : tensor<?x?xf32>) -> tensor<?x?x?x?x?xf32>
+func @expanding_tensor_reshapes(%arg0 : tensor<?x?xf32>) -> tensor<?x6x4x?x5xf32>
{
%0 = linalg.tensor_reshape %arg0
[affine_map<(d0, d1, d2) -> (d0, d1)>,
affine_map<(d0, d1, d2) -> (d2)>] :
- tensor<?x?xf32> into tensor<?x?x?xf32>
+ tensor<?x?xf32> into tensor<?x4x?xf32>
%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<?x?x?xf32> into tensor<?x?x?x?x?xf32>
- return %1 : tensor<?x?x?x?x?xf32>
+ tensor<?x4x?xf32> into tensor<?x6x4x?x5xf32>
+ return %1 : tensor<?x6x4x?x5xf32>
}
// 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)>
// -----
-func @expanding_memref_reshapes(%arg0 : memref<?x?xf32>) -> memref<?x?x?x?x?xf32>
+func @expanding_memref_reshapes(%arg0 : memref<?x?xf32>) -> memref<?x6x4x5x?xf32>
{
%0 = linalg.reshape %arg0
[affine_map<(d0, d1, d2) -> (d0, d1)>,
affine_map<(d0, d1, d2) -> (d2)>] :
- memref<?x?xf32> into memref<?x?x?xf32>
+ memref<?x?xf32> into memref<?x4x?xf32>
%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<?x?x?xf32> into memref<?x?x?x?x?xf32>
- return %1 : memref<?x?x?x?x?xf32>
+ memref<?x4x?xf32> into memref<?x6x4x5x?xf32>
+ return %1 : memref<?x6x4x5x?xf32>
}
// 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)>
// -----
-func @no_fold_tensor_reshape(%arg0 : tensor<?x?xf32>) -> tensor<?x?xf32>
+func @fold_tensor_reshape_dynamic(%arg0 : tensor<?x?xf32>) -> tensor<?x?xf32>
{
%0 = linalg.tensor_reshape %arg0
[affine_map<(d0, d1, d2) -> (d0, d1)>,
affine_map<(d0, d1, d2) -> (d2)>] :
- tensor<?x?xf32> into tensor<?x?x?xf32>
+ tensor<?x?xf32> into tensor<?x4x?xf32>
%1 = linalg.tensor_reshape %0
[affine_map<(d0, d1, d2) -> (d0, d1)>,
affine_map<(d0, d1, d2) -> (d2)>] :
- tensor<?x?x?xf32> into tensor<?x?xf32>
+ tensor<?x4x?xf32> into tensor<?x?xf32>
return %1 : tensor<?x?xf32>
}
-// CHECK-LABEL: @no_fold_tensor_reshape
-// CHECK: linalg.tensor_reshape
-// CHECK: linalg.tensor_reshape
+// CHECK-LABEL: @fold_tensor_reshape_dynamic
+// CHECK-NOT: linalg.tensor_reshape
// -----
// -----
-func @no_fold_memref_reshape(%arg0 : memref<?x?xf32>) -> memref<?x?xf32>
+func @fold_memref_reshape_dynamic(%arg0 : memref<?x?xf32>) -> memref<?x?xf32>
{
%0 = linalg.reshape %arg0
[affine_map<(d0, d1, d2) -> (d0, d1)>,
affine_map<(d0, d1, d2) -> (d2)>] :
- memref<?x?xf32> into memref<?x?x?xf32>
+ memref<?x?xf32> into memref<?x4x?xf32>
%1 = linalg.reshape %0
[affine_map<(d0, d1, d2) -> (d0, d1)>,
affine_map<(d0, d1, d2) -> (d2)>] :
- memref<?x?x?xf32> into memref<?x?xf32>
+ memref<?x4x?xf32> into memref<?x?xf32>
return %1 : memref<?x?xf32>
}
-// CHECK-LABEL: @no_fold_memref_reshape
-// CHECK: linalg.reshape
-// CHECK: linalg.reshape
+// CHECK-LABEL: @fold_memref_reshape_dynamic
+// CHECK-NOT: linalg.reshape
// -----
-> tensor<?xf32>
return
}
+
+
+// -----
+
+func @init_tensor_err(%arg0 : index, %arg1 : index)
+{
+ // expected-error @+1 {{specified type 'tensor<4x?x?x5xf32>' does not match the inferred type 'tensor<4x5x?x?xf32>'}}
+ %1 = linalg.init_tensor [4, 5, %arg0, %arg1] : tensor<4x?x?x5xf32>
+ return
+}
+
+// -----
+
+func @init_tensor_err(%arg0 : index)
+{
+ // expected-error @+1 {{expected 4 sizes values}}
+ %1 = linalg.init_tensor [4, 5, %arg0] : tensor<4x?x?x5xf32>
+ return
+}
+
+// -----
+
+func @init_tensor_err(%arg0 : index)
+{
+ // expected-error @+1 {{expected 2 dynamic sizes values}}
+ %1 = "linalg.init_tensor"(%arg0) {static_sizes = [4, -1, -1, 5]} : (index) -> tensor<4x?x?x5xf32>
+ return
+}
+
+// -----
+
+func @illegal_expanding_reshape_dynamic_tensor
+ (%arg0: tensor<?x?x?xf32>) -> tensor<?x?x?x4x?xf32>
+{
+ // expected-error @+1 {{invalid to have a single dimension (2) expanded into multiple dynamic dims (2,4)}}
+ %0 = linalg.tensor_reshape %arg0
+ [affine_map<(d0, d1, d2, d3, d4) -> (d0)>,
+ affine_map<(d0, d1, d2, d3, d4) -> (d1)>,
+ affine_map<(d0, d1, d2, d3, d4) -> (d2, d3, d4)>] :
+ tensor<?x?x?xf32> into tensor<?x?x?x4x?xf32>
+ return %0 : tensor<?x?x?x4x?xf32>
+}
+
+// -----
+
+func @illegal_expanding_reshape_dynamic_memref
+ (%arg0: memref<?x?x?xf32>) -> memref<?x?x?x4x?xf32>
+{
+ // expected-error @+1 {{invalid to have a single dimension (2) expanded into multiple dynamic dims (2,4)}}
+ %0 = linalg.reshape %arg0
+ [affine_map<(d0, d1, d2, d3, d4) -> (d0)>,
+ affine_map<(d0, d1, d2, d3, d4) -> (d1)>,
+ affine_map<(d0, d1, d2, d3, d4) -> (d2, d3, d4)>] :
+ memref<?x?x?xf32> into memref<?x?x?x4x?xf32>
+ return %0 : memref<?x?x?x4x?xf32>
+}
+
+// -----
+
+func @illegal_expanding_reshape_static_tensor
+ (%arg0: tensor<2x3x20xf32>) -> tensor<2x3x2x4x5xf32>
+{
+ // expected-error @+1 {{expected dimension 2 of collapsed type to be static value of 40}}
+ %0 = linalg.tensor_reshape %arg0
+ [affine_map<(d0, d1, d2, d3, d4) -> (d0)>,
+ affine_map<(d0, d1, d2, d3, d4) -> (d1)>,
+ affine_map<(d0, d1, d2, d3, d4) -> (d2, d3, d4)>] :
+ tensor<2x3x20xf32> into tensor<2x3x2x4x5xf32>
+ return %0 : tensor<2x3x2x4x5xf32>
+}
+
+// -----
+
+func @illegal_collapsing_reshape_static_tensor
+ (%arg0: tensor<2x3x2x4x5xf32>) -> tensor<2x3x20xf32>
+{
+ // expected-error @+1 {{expected dimension 2 of collapsed type to be static value of 40}}
+ %0 = linalg.tensor_reshape %arg0
+ [affine_map<(d0, d1, d2, d3, d4) -> (d0)>,
+ affine_map<(d0, d1, d2, d3, d4) -> (d1)>,
+ affine_map<(d0, d1, d2, d3, d4) -> (d2, d3, d4)>] :
+ tensor<2x3x2x4x5xf32> into tensor<2x3x20xf32>
+ return %0 : tensor<2x3x20xf32>
+}
+
+// -----
+
+func @illegal_expanding_reshape_static_memref
+ (%arg0: memref<2x3x20xf32>) -> memref<2x3x2x4x5xf32>
+{
+ // expected-error @+1 {{expected dimension 2 of collapsed type to be static value of 40}}
+ %0 = linalg.reshape %arg0
+ [affine_map<(d0, d1, d2, d3, d4) -> (d0)>,
+ affine_map<(d0, d1, d2, d3, d4) -> (d1)>,
+ affine_map<(d0, d1, d2, d3, d4) -> (d2, d3, d4)>] :
+ memref<2x3x20xf32> into memref<2x3x2x4x5xf32>
+ return %0 : memref<2x3x2x4x5xf32>
+}
+
+// -----
+
+func @illegal_collapsing_reshape_static_memref
+ (%arg0: memref<2x3x2x4x5xf32>) -> memref<2x3x20xf32>
+{
+ // expected-error @+1 {{expected dimension 2 of collapsed type to be static value of 40}}
+ %0 = linalg.reshape %arg0
+ [affine_map<(d0, d1, d2, d3, d4) -> (d0)>,
+ affine_map<(d0, d1, d2, d3, d4) -> (d1)>,
+ affine_map<(d0, d1, d2, d3, d4) -> (d2, d3, d4)>] :
+ memref<2x3x2x4x5xf32> into memref<2x3x20xf32>
+ return %0 : memref<2x3x20xf32>
+}
+
+// -----
+
+func @illegal_collapsing_reshape_mixed_tensor(%arg0 : tensor<?x?xf32>) -> tensor<?x4x5xf32>
+{
+ // expected-error @+1 {{expected dimension 1 of collapsed type to be static value of 5}}
+ %0 = linalg.tensor_reshape %arg0
+ [affine_map<(d0, d1, d2) -> (d0, d1)>,
+ affine_map<(d0, d1, d2) -> (d2)>] :
+ tensor<?x?xf32> into tensor<?x4x5xf32>
+ return %0 : tensor<?x4x5xf32>
+}
+
+// -----
+
+func @illegal_collapsing_reshape_mixed_tensor_2(%arg0 : tensor<?x?xf32>) -> tensor<?x4x5xf32>
+{
+ // expected-error @+1 {{expected dimension 1 of collapsed type to be static value of 20}}
+ %0 = linalg.tensor_reshape %arg0
+ [affine_map<(d0, d1, d2) -> (d0)>,
+ affine_map<(d0, d1, d2) -> (d1, d2)>] :
+ tensor<?x?xf32> into tensor<?x4x5xf32>
+ return %0 : tensor<?x4x5xf32>
+}
+
+// -----
+
+func @illegal_expanding_reshape_mixed_tensor(%arg0 : tensor<?x4x5xf32>) -> tensor<?x?xf32>
+{
+ // expected-error @+1 {{expected dimension 1 of collapsed type to be static value of 5}}
+ %0 = linalg.tensor_reshape %arg0
+ [affine_map<(d0, d1, d2) -> (d0, d1)>,
+ affine_map<(d0, d1, d2) -> (d2)>] :
+ tensor<?x4x5xf32> into tensor<?x?xf32>
+ return %0 : tensor<?x?xf32>
+}
+
+// -----
+
+func @illegal_expanding_reshape_mixed_tensor_2(%arg0 : tensor<?x4x5xf32>) -> tensor<?x?xf32>
+{
+ // expected-error @+1 {{expected dimension 1 of collapsed type to be static value of 20}}
+ %0 = linalg.tensor_reshape %arg0
+ [affine_map<(d0, d1, d2) -> (d0)>,
+ affine_map<(d0, d1, d2) -> (d1, d2)>] :
+ tensor<?x4x5xf32> into tensor<?x?xf32>
+ return %0 : tensor<?x?xf32>
+}
+
+// -----
+
+func @illegal_collapsing_reshape_mixed_memref(%arg0 : memref<?x?xf32>) -> memref<?x4x5xf32>
+{
+ // expected-error @+1 {{expected dimension 1 of collapsed type to be static value of 5}}
+ %0 = linalg.reshape %arg0
+ [affine_map<(d0, d1, d2) -> (d0, d1)>,
+ affine_map<(d0, d1, d2) -> (d2)>] :
+ memref<?x?xf32> into memref<?x4x5xf32>
+ return %0 : memref<?x4x5xf32>
+}
+
+// -----
+
+func @illegal_collapsing_reshape_mixed_memref_2(%arg0 : memref<?x?xf32>) -> memref<?x4x5xf32>
+{
+ // expected-error @+1 {{expected dimension 1 of collapsed type to be static value of 20}}
+ %0 = linalg.reshape %arg0
+ [affine_map<(d0, d1, d2) -> (d0)>,
+ affine_map<(d0, d1, d2) -> (d1, d2)>] :
+ memref<?x?xf32> into memref<?x4x5xf32>
+ return %0 : memref<?x4x5xf32>
+}
+
+// -----
+
+func @illegal_expanding_reshape_mixed_memref(%arg0 : memref<?x4x5xf32>) -> memref<?x?xf32>
+{
+ // expected-error @+1 {{expected dimension 1 of collapsed type to be static value of 5}}
+ %0 = linalg.reshape %arg0
+ [affine_map<(d0, d1, d2) -> (d0, d1)>,
+ affine_map<(d0, d1, d2) -> (d2)>] :
+ memref<?x4x5xf32> into memref<?x?xf32>
+ return %0 : memref<?x?xf32>
+}
+
+// -----
+
+func @illegal_expanding_reshape_mixed_memref_2(%arg0 : memref<?x4x5xf32>) -> memref<?x?xf32>
+{
+ // expected-error @+1 {{expected dimension 1 of collapsed type to be static value of 20}}
+ %0 = linalg.reshape %arg0
+ [affine_map<(d0, d1, d2) -> (d0)>,
+ affine_map<(d0, d1, d2) -> (d1, d2)>] :
+ memref<?x4x5xf32> into memref<?x?xf32>
+ return %0 : memref<?x?xf32>
+}
-// RUN: mlir-opt -split-input-file -verify-diagnostics %s | FileCheck %s
+// RUN: mlir-opt -split-input-file %s | FileCheck %s
// TODO: Re-enable LLVM lowering test after IndexedGenericOp is lowered.
//
memref<?x?x?xf32> into memref<?x?xf32>
%r0 = linalg.reshape %0 [affine_map<(i, j, k) -> (i, j)>,
affine_map<(i, j, k) -> (k)>] :
- memref<?x?xf32> into memref<?x?x?xf32>
+ memref<?x?xf32> into memref<?x4x?xf32>
%1 = linalg.reshape %arg1 [affine_map<(i, j, k) -> (i, j)>,
affine_map<(i, j, k) -> (k)>] :
memref<?x?x?xf32, offset : 0, strides : [?, ?, 1]> into
%r1 = linalg.reshape %1 [affine_map<(i, j, k) -> (i, j)>,
affine_map<(i, j, k) -> (k)>] :
memref<?x?xf32, offset : 0, strides : [?, 1]> into
- memref<?x?x?xf32, offset : 0, strides : [?, ?, 1]>
+ memref<?x4x?xf32, offset : 0, strides : [?, ?, 1]>
%2 = linalg.reshape %arg2 [affine_map<(i, j, k) -> (i, j)>,
affine_map<(i, j, k) -> (k)>] :
memref<?x?x?xf32, offset : ?, strides : [?, ?, 1]> into
%r2 = linalg.reshape %2 [affine_map<(i, j, k) -> (i, j)>,
affine_map<(i, j, k) -> (k)>] :
memref<?x?xf32, offset : ?, strides : [?, 1]> into
- memref<?x?x?xf32, offset : ?, strides : [?, ?, 1]>
+ memref<?x4x?xf32, offset : ?, strides : [?, ?, 1]>
return
}
// CHECK: linalg.reshape {{.*}} [#[[$reshapeD01]], #[[$reshapeD2]]]
// CHECK-SAME: memref<?x?x?xf32> into memref<?x?xf32>
// CHECK: linalg.reshape {{.*}} [#[[$reshapeD01]], #[[$reshapeD2]]]
-// CHECK-SAME: memref<?x?xf32> into memref<?x?x?xf32>
+// CHECK-SAME: memref<?x?xf32> into memref<?x4x?xf32>
// CHECK: linalg.reshape {{.*}} [#[[$reshapeD01]], #[[$reshapeD2]]]
// CHECK-SAME: memref<?x?x?xf32, #[[$strided3DOFF0]]> into memref<?x?xf32, #[[$strided2DOFF0]]>
// CHECK: linalg.reshape {{.*}} [#[[$reshapeD01]], #[[$reshapeD2]]]
-// CHECK-SAME: memref<?x?xf32, #[[$strided2DOFF0]]> into memref<?x?x?xf32, #[[$strided3DOFF0]]>
+// CHECK-SAME: memref<?x?xf32, #[[$strided2DOFF0]]> into memref<?x4x?xf32, #[[$strided3DOFF0]]>
// CHECK: linalg.reshape {{.*}} [#[[$reshapeD01]], #[[$reshapeD2]]]
// CHECK-SAME: memref<?x?x?xf32, #[[$strided3D]]> into memref<?x?xf32, #[[$strided2D]]>
// CHECK: linalg.reshape {{.*}} [#[[$reshapeD01]], #[[$reshapeD2]]]
-// CHECK-SAME: memref<?x?xf32, #[[$strided2D]]> into memref<?x?x?xf32, #[[$strided3D]]>
+// CHECK-SAME: memref<?x?xf32, #[[$strided2D]]> into memref<?x4x?xf32, #[[$strided3D]]>
func @named_ops(%a3: memref<?x?x?xf32>, %b3: memref<?x?x?xf32>, %c3: memref<?x?x?xf32>,
%ta3: tensor<?x?x?xf32>, %tb3: tensor<?x?x?xf32>, %tc3: tensor<?x?x?xf32>)
// -----
-func @init_tensor_err(%arg0 : index, %arg1 : index)
+func @legal_collapsing_reshape_dynamic_tensor
+ (%arg0: tensor<?x?x?x4x?xf32>) -> tensor<?x?x?xf32>
{
- // expected-error @+1 {{specified type 'tensor<4x?x?x5xf32>' does not match the inferred type 'tensor<4x5x?x?xf32>'}}
- %1 = linalg.init_tensor [4, 5, %arg0, %arg1] : tensor<4x?x?x5xf32>
- return
-}
-
-// -----
-
-func @init_tensor_err(%arg0 : index)
-{
- // expected-error @+1 {{expected 4 sizes values}}
- %1 = linalg.init_tensor [4, 5, %arg0] : tensor<4x?x?x5xf32>
- return
+ %0 = linalg.tensor_reshape %arg0
+ [affine_map<(d0, d1, d2, d3, d4) -> (d0)>,
+ affine_map<(d0, d1, d2, d3, d4) -> (d1)>,
+ affine_map<(d0, d1, d2, d3, d4) -> (d2, d3, d4)>] :
+ tensor<?x?x?x4x?xf32> into tensor<?x?x?xf32>
+ return %0 : tensor<?x?x?xf32>
}
+// CHECK-DAG: #[[MAP0:.+]] = affine_map<(d0, d1, d2, d3, d4) -> (d0)>
+// CHECK-DAG: #[[MAP1:.+]] = affine_map<(d0, d1, d2, d3, d4) -> (d1)>
+// CHECK-DAG: #[[MAP2:.+]] = affine_map<(d0, d1, d2, d3, d4) -> (d2, d3, d4)>
+// CHECK: func @legal_collapsing_reshape_dynamic_tensor
+// CHECK: linalg.tensor_reshape %{{.+}} [#[[MAP0]], #[[MAP1]], #[[MAP2]]]
// -----
-func @init_tensor_err(%arg0 : index)
+func @legal_collapsing_reshape_dynamic_memref
+ (%arg0: memref<?x?x?x4x?xf32>) -> memref<?x?x?xf32>
{
- // expected-error @+1 {{expected 2 dynamic sizes values}}
- %1 = "linalg.init_tensor"(%arg0) {static_sizes = [4, -1, -1, 5]} : (index) -> tensor<4x?x?x5xf32>
- return
-}
+ %0 = linalg.reshape %arg0
+ [affine_map<(d0, d1, d2, d3, d4) -> (d0)>,
+ affine_map<(d0, d1, d2, d3, d4) -> (d1)>,
+ affine_map<(d0, d1, d2, d3, d4) -> (d2, d3, d4)>] :
+ memref<?x?x?x4x?xf32> into memref<?x?x?xf32>
+ return %0 : memref<?x?x?xf32>
+}
+// CHECK-DAG: #[[MAP0:.+]] = affine_map<(d0, d1, d2, d3, d4) -> (d0)>
+// CHECK-DAG: #[[MAP1:.+]] = affine_map<(d0, d1, d2, d3, d4) -> (d1)>
+// CHECK-DAG: #[[MAP2:.+]] = affine_map<(d0, d1, d2, d3, d4) -> (d2, d3, d4)>
+// CHECK: func @legal_collapsing_reshape_dynamic_memref
+// CHECK: linalg.reshape %{{.+}} [#[[MAP0]], #[[MAP1]], #[[MAP2]]]