Skip to content

Commit 1477e98

Browse files
authored
[TritonArithToLinalg] Lower batched matmul from tt.dot to linalg.batch_matmul (#35)
**Problem:** Triton uses the same tt.dot() operation for both matmul and batched matmul: for 3D operands, the first dimension is a batch dimension and tt.dot performs a batched matrix product. The current lowering did not account for this and always emitted linalg.matmul, which only supports 2D operands. Running triton-shared-opt --triton-arith-to-linalg on a 3D tt.dot therefore failed with: ``` error: 'linalg.matmul' op expected operand #0 rank (3) to match the result rank of indexing_map (2) ``` **Solution:** `MatmulConverter` now inspects the rank of the result tensor and emits `linalg.batch_matmul` for rank-3 operands (and linalg.matmul for rank-2, as before). Rank > 3 is not supported and now fails the pattern instead of producing an invalid op. **Testing:** Adds a lit test (batched_matmul.mlir) covering the 3D case.
1 parent bce5578 commit 1477e98

2 files changed

Lines changed: 41 additions & 3 deletions

File tree

include/triton-shared/Conversion/TritonArithToLinalg/ConversionPatterns.hpp

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1099,9 +1099,19 @@ struct MatmulConverter : public OpConversionPattern<triton::DotOp> {
10991099
ValueRange{init})
11001100
.result();
11011101

1102-
auto res = linalg::MatmulOp::create(rewriter, loc, ValueRange{opa, opb},
1103-
ValueRange{zeroes})
1104-
.getResult(0);
1102+
auto rank = dstType.getRank();
1103+
Value res;
1104+
if (rank > 3) {
1105+
return failure();
1106+
} else if (rank == 3) {
1107+
res = linalg::BatchMatmulOp::create(rewriter, loc, ValueRange{opa, opb},
1108+
ValueRange{zeroes})
1109+
.getResult(0);
1110+
} else {
1111+
res = linalg::MatmulOp::create(rewriter, loc, ValueRange{opa, opb},
1112+
ValueRange{zeroes})
1113+
.getResult(0);
1114+
}
11051115

11061116
if (!skipC) {
11071117
if (integers) {
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// RUN: triton-shared-opt --triton-arith-to-linalg %s | FileCheck %s
2+
3+
module {
4+
tt.func @kernel(
5+
%arg0: tensor<32x64x128x!tt.ptr<f16>>, %arg1: tensor<32x128x256x!tt.ptr<f16>>, %arg2: tensor<32x64x256x!tt.ptr<f32>>, %arg3: tensor<32x64x256x!tt.ptr<f32>>
6+
)
7+
{
8+
%0 = tt.load %arg0: tensor<32x64x128x!tt.ptr<f16>>
9+
%1 = tt.load %arg1: tensor<32x128x256x!tt.ptr<f16>>
10+
%2 = tt.load %arg2: tensor<32x64x256x!tt.ptr<f32>>
11+
%3 = tt.dot %0, %1, %2 : tensor<32x64x128xf16> * tensor<32x128x256xf16> -> tensor<32x64x256xf32>
12+
tt.store %arg3, %3 : tensor<32x64x256x!tt.ptr<f32>>
13+
tt.return
14+
}
15+
}
16+
17+
// CHECK-LABEL: func.func @kernel(
18+
// CHECK-SAME: %[[ARG0:.*]]: tensor<32x64x128x!tt.ptr<f16>>, %[[ARG1:.*]]: tensor<32x128x256x!tt.ptr<f16>>, %[[ARG2:.*]]: tensor<32x64x256x!tt.ptr<f32>>, %[[ARG3:.*]]: tensor<32x64x256x!tt.ptr<f32>>,
19+
// CHECK: %[[LOAD_A:.*]] = tt.load %[[ARG0]] : tensor<32x64x128x!tt.ptr<f16>>
20+
// CHECK: %[[LOAD_B:.*]] = tt.load %[[ARG1]] : tensor<32x128x256x!tt.ptr<f16>>
21+
// CHECK: %[[LOAD_C:.*]] = tt.load %[[ARG2]] : tensor<32x64x256x!tt.ptr<f32>>
22+
// CHECK: %[[EMPTY:.*]] = tensor.empty() : tensor<32x64x256xf32>
23+
// CHECK: %[[FILL:.*]] = linalg.fill {{.*}} outs(%[[EMPTY]] : tensor<32x64x256xf32>) -> tensor<32x64x256xf32>
24+
// CHECK: %[[BATCH_MATMUL:.*]] = linalg.batch_matmul ins(%[[LOAD_A]], %[[LOAD_B]] : tensor<32x64x128xf16>, tensor<32x128x256xf16>) outs(%[[FILL]] : tensor<32x64x256xf32>) -> tensor<32x64x256xf32>
25+
// CHECK: %[[RESULT:.*]] = linalg.generic
26+
// CHECK-SAME: ins(%[[LOAD_C]], %[[BATCH_MATMUL]] : tensor<32x64x256xf32>, tensor<32x64x256xf32>)
27+
// CHECK: tt.store %[[ARG3]], %[[RESULT]] : tensor<32x64x256x!tt.ptr<f32>>
28+
// CHECK: return

0 commit comments

Comments
 (0)