Skip to content

Commit ca7817b

Browse files
committed
Add D2S decomp to tosa
1 parent 9a91701 commit ca7817b

2 files changed

Lines changed: 111 additions & 1 deletion

File tree

lib/Conversion/XTenNNToTosa.cpp

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,15 @@ Value getZeroShift(PatternRewriter &rewriter, Location loc) {
7575
rewriter.create<tosa::ConstOp>(loc, shiftValueType, shiftValueAttr);
7676
return shiftValue;
7777
}
78+
79+
Value createTosaI32Const(PatternRewriter &rewriter, Location loc,
80+
ArrayRef<int32_t> values) {
81+
auto type = RankedTensorType::get({static_cast<int64_t>(values.size())},
82+
rewriter.getI32Type());
83+
return rewriter
84+
.create<tosa::ConstOp>(loc, type, DenseIntElementsAttr::get(type, values))
85+
.getResult();
86+
}
7887
} // namespace
7988

8089
class QuantizeOp : public OpRewritePattern<amd::xten_nn::QuantizeOp> {
@@ -203,6 +212,74 @@ class DequantizeOp : public OpRewritePattern<amd::xten_nn::DequantizeOp> {
203212
}
204213
};
205214

215+
class DepthToSpaceOp : public OpRewritePattern<amd::xten_nn::DepthToSpaceOp> {
216+
public:
217+
using OpRewritePattern::OpRewritePattern;
218+
219+
LogicalResult matchAndRewrite(amd::xten_nn::DepthToSpaceOp op,
220+
PatternRewriter &rewriter) const override {
221+
auto inputType = cast<RankedTensorType>(op.getX().getType());
222+
auto resultType = cast<RankedTensorType>(op.getY().getType());
223+
if (!inputType.hasStaticShape() || !resultType.hasStaticShape())
224+
return rewriter.notifyMatchFailure(
225+
op, "depth_to_space lowering requires static shapes");
226+
227+
const int64_t blockSize = op.getBlocksize();
228+
229+
ArrayRef<int64_t> inputShape = inputType.getShape();
230+
const int64_t channels = inputShape[1];
231+
const int64_t blockSizeSquared = blockSize * blockSize;
232+
assert(blockSizeSquared > 0 && "blocksize must be positive");
233+
assert(channels % blockSizeSquared == 0 &&
234+
"input channel dimension must be divisible by blocksize squared");
235+
236+
const int64_t outputChannels = channels / blockSizeSquared;
237+
SmallVector<int64_t> reshapeShape;
238+
SmallVector<int64_t> transposedShape{inputShape[0], outputChannels,
239+
inputShape[2], blockSize,
240+
inputShape[3], blockSize};
241+
SmallVector<int32_t> permutation;
242+
243+
switch (op.getMode()) {
244+
case 1:
245+
// DCR: [N, BS, BS, C', H, W] -> [N, C', H, BS, W, BS].
246+
reshapeShape = {inputShape[0], blockSize, blockSize,
247+
outputChannels, inputShape[2], inputShape[3]};
248+
permutation = {0, 3, 4, 1, 5, 2};
249+
break;
250+
case 2:
251+
// CRD: [N, C', BS, BS, H, W] -> [N, C', H, BS, W, BS].
252+
reshapeShape = {inputShape[0], outputChannels, blockSize,
253+
blockSize, inputShape[2], inputShape[3]};
254+
permutation = {0, 1, 4, 2, 5, 3};
255+
break;
256+
default:
257+
return rewriter.notifyMatchFailure(op, "unsupported depth_to_space mode");
258+
}
259+
260+
auto reshapedType =
261+
RankedTensorType::get(reshapeShape, inputType.getElementType());
262+
Value reshaped = rewriter
263+
.create<tosa::ReshapeOp>(
264+
op.getLoc(), reshapedType, op.getX(),
265+
rewriter.getDenseI64ArrayAttr(reshapeShape))
266+
.getResult();
267+
268+
auto transposedType =
269+
RankedTensorType::get(transposedShape, inputType.getElementType());
270+
Value perm = createTosaI32Const(rewriter, op.getLoc(), permutation);
271+
Value transposed = rewriter
272+
.create<tosa::TransposeOp>(
273+
op.getLoc(), transposedType, reshaped, perm)
274+
.getResult();
275+
276+
rewriter.replaceOpWithNewOp<tosa::ReshapeOp>(
277+
op, resultType, transposed,
278+
rewriter.getDenseI64ArrayAttr(resultType.getShape()));
279+
return success();
280+
}
281+
};
282+
206283
class XTenNNToTosaPass
207284
: public xilinx::xten::XTenNNToTosaBase<XTenNNToTosaPass> {
208285
public:
@@ -211,7 +288,7 @@ class XTenNNToTosaPass
211288
MLIRContext *context = module.getContext();
212289
RewritePatternSet patterns(context);
213290

214-
patterns.insert<QuantizeOp, DequantizeOp>(context);
291+
patterns.insert<QuantizeOp, DequantizeOp, DepthToSpaceOp>(context);
215292
// We insert a clamp to enforce non-standard TOSA dataypes. E.g. i6 signed
216293
// integer range described with an i8 value. However, in the case we use i8
217294
// and clamp to values of i8 (i.e. si8) then the clamp can be optimized away
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// (c) Copyright 2026 Advanced Micro Devices, Inc. All Rights reserved.
2+
3+
// RUN: aten-opt %s --xten-nn-to-tosa --split-input-file | FileCheck %s
4+
5+
func.func @depth_to_space_crd(%arg0: tensor<1x16x8x8xf32>) -> tensor<1x4x16x16xf32> {
6+
%0 = xten_nn.depth_to_space %arg0 {blocksize = 2 : i64, mode = 2 : i64} : (tensor<1x16x8x8xf32>) -> tensor<1x4x16x16xf32>
7+
return %0 : tensor<1x4x16x16xf32>
8+
}
9+
10+
// CHECK-LABEL: func.func @depth_to_space_crd
11+
// CHECK-SAME: ([[ARG0:%.+]]: tensor<1x16x8x8xf32>) -> tensor<1x4x16x16xf32>
12+
// CHECK-DAG: [[PERM:%.+]] = "tosa.const"() <{value = dense<[0, 1, 4, 2, 5, 3]> : tensor<6xi32>}> : () -> tensor<6xi32>
13+
// CHECK-DAG: [[RESHAPED:%.+]] = tosa.reshape [[ARG0]] {new_shape = array<i64: 1, 4, 2, 2, 8, 8>} : (tensor<1x16x8x8xf32>) -> tensor<1x4x2x2x8x8xf32>
14+
// CHECK: [[TRANSPOSED:%.+]] = tosa.transpose [[RESHAPED]], [[PERM]] : (tensor<1x4x2x2x8x8xf32>, tensor<6xi32>) -> tensor<1x4x8x2x8x2xf32>
15+
// CHECK: [[RESULT:%.+]] = tosa.reshape [[TRANSPOSED]] {new_shape = array<i64: 1, 4, 16, 16>} : (tensor<1x4x8x2x8x2xf32>) -> tensor<1x4x16x16xf32>
16+
// CHECK: return [[RESULT]] : tensor<1x4x16x16xf32>
17+
// CHECK-NOT: xten_nn.depth_to_space
18+
19+
// -----
20+
21+
func.func @depth_to_space_dcr(%arg0: tensor<1x16x8x8xbf16>) -> tensor<1x4x16x16xbf16> {
22+
%0 = xten_nn.depth_to_space %arg0 {blocksize = 2 : i64, mode = 1 : i64} : (tensor<1x16x8x8xbf16>) -> tensor<1x4x16x16xbf16>
23+
return %0 : tensor<1x4x16x16xbf16>
24+
}
25+
26+
// CHECK-LABEL: func.func @depth_to_space_dcr
27+
// CHECK-SAME: ([[ARG0:%.+]]: tensor<1x16x8x8xbf16>) -> tensor<1x4x16x16xbf16>
28+
// CHECK-DAG: [[PERM:%.+]] = "tosa.const"() <{value = dense<[0, 3, 4, 1, 5, 2]> : tensor<6xi32>}> : () -> tensor<6xi32>
29+
// CHECK-DAG: [[RESHAPED:%.+]] = tosa.reshape [[ARG0]] {new_shape = array<i64: 1, 2, 2, 4, 8, 8>} : (tensor<1x16x8x8xbf16>) -> tensor<1x2x2x4x8x8xbf16>
30+
// CHECK: [[TRANSPOSED:%.+]] = tosa.transpose [[RESHAPED]], [[PERM]] : (tensor<1x2x2x4x8x8xbf16>, tensor<6xi32>) -> tensor<1x4x8x2x8x2xbf16>
31+
// CHECK: [[RESULT:%.+]] = tosa.reshape [[TRANSPOSED]] {new_shape = array<i64: 1, 4, 16, 16>} : (tensor<1x4x8x2x8x2xbf16>) -> tensor<1x4x16x16xbf16>
32+
// CHECK: return [[RESULT]] : tensor<1x4x16x16xbf16>
33+
// CHECK-NOT: xten_nn.depth_to_space

0 commit comments

Comments
 (0)