25#include "llvm/ADT/STLExtras.h"
26#include "llvm/ADT/StringSwitch.h"
41 .Case(
"AOp", spirv::CooperativeMatrixUseKHR::MatrixA)
42 .Case(
"BOp", spirv::CooperativeMatrixUseKHR::MatrixB)
43 .Default(spirv::CooperativeMatrixUseKHR::MatrixAcc);
51 auto matrixType = dyn_cast<gpu::MMAMatrixType>(type.getElementType());
58 dyn_cast_or_null<spirv::StorageClassAttr>(type.getMemorySpace());
60 storageClass.getValue() != spirv::StorageClass::Function ||
61 !type.hasStaticShape() || !type.getLayout().isIdentity() ||
62 type.getNumElements() <= 0 ||
63 type.getNumElements() > std::numeric_limits<unsigned>::max())
67 static_cast<unsigned>(type.getNumElements()));
77 gpu::SubgroupMmaElementwiseOp op,
Type coopType,
79 assert((isa<spirv::CooperativeMatrixType>(coopType)));
81 switch (op.getOpType()) {
82 case gpu::MMAElementwiseOp::ADDF:
83 builder.replaceOpWithNewOp<spirv::FAddOp>(op, coopType, operands);
85 case gpu::MMAElementwiseOp::ADDI:
86 builder.replaceOpWithNewOp<spirv::IAddOp>(op, coopType, operands);
88 case gpu::MMAElementwiseOp::SUBF:
89 builder.replaceOpWithNewOp<spirv::FSubOp>(op, coopType, operands);
91 case gpu::MMAElementwiseOp::SUBI:
92 builder.replaceOpWithNewOp<spirv::ISubOp>(op, coopType, operands);
94 case gpu::MMAElementwiseOp::MULF:
95 builder.replaceOpWithNewOp<spirv::FMulOp>(op, coopType, operands);
97 case gpu::MMAElementwiseOp::DIVF:
98 builder.replaceOpWithNewOp<spirv::FDivOp>(op, coopType, operands);
100 case gpu::MMAElementwiseOp::DIVS:
101 builder.replaceOpWithNewOp<spirv::SDivOp>(op, coopType, operands);
103 case gpu::MMAElementwiseOp::DIVU:
104 builder.replaceOpWithNewOp<spirv::UDivOp>(op, coopType, operands);
106 case gpu::MMAElementwiseOp::NEGATEF:
107 builder.replaceOpWithNewOp<spirv::FNegateOp>(op, coopType, operands);
109 case gpu::MMAElementwiseOp::NEGATES:
110 builder.replaceOpWithNewOp<spirv::SNegateOp>(op, coopType, operands);
112 case gpu::MMAElementwiseOp::EXTF:
113 case gpu::MMAElementwiseOp::TRUNCF:
114 builder.replaceOpWithNewOp<spirv::FConvertOp>(op, coopType, operands);
123 assert(!operands.empty());
124 if (!llvm::all_equal(
125 llvm::map_range(operands, [](
Value v) {
return v.
getType(); })))
128 return isa<spirv::CooperativeMatrixType>(operands.front().
getType());
133 return elementType && elementType.isSigned();
136static spirv::CooperativeMatrixOperandsKHR
141 using Operands = spirv::CooperativeMatrixOperandsKHR;
143 Operands operands = Operands::None;
145 operands |= Operands::ASigned;
147 operands |= Operands::BSigned;
149 operands |= Operands::CSigned;
151 operands |= Operands::ResultSigned;
158struct WmmaConstantOpToSPIRVLowering final
159 : OpConversionPattern<gpu::SubgroupMmaConstantMatrixOp> {
163 matchAndRewrite(gpu::SubgroupMmaConstantMatrixOp op, OpAdaptor adaptor,
164 ConversionPatternRewriter &rewriter)
const override {
165 Value cst = llvm::getSingleElement(adaptor.getOperands());
166 auto coopType = getTypeConverter()->convertType(op.getType());
168 return rewriter.notifyMatchFailure(op,
"type conversion failed");
170 rewriter.replaceOpWithNewOp<spirv::CompositeConstructOp>(op, coopType, cst);
177struct WmmaExtractOpToSPIRVLowering final
178 : OpConversionPattern<gpu::SubgroupMmaExtractThreadLocalOp> {
182 matchAndRewrite(gpu::SubgroupMmaExtractThreadLocalOp op, OpAdaptor adaptor,
183 ConversionPatternRewriter &rewriter)
const override {
184 Value matrix = adaptor.getMatrix();
186 getTypeConverter()->convertType<spirv::CooperativeMatrixType>(
189 return rewriter.notifyMatchFailure(op,
"type conversion failed");
191 SmallVector<int32_t> intValues;
192 for (Value val : op.getIndices()) {
193 if (
auto constOp = val.getDefiningOp<arith::ConstantIndexOp>()) {
194 intValues.push_back(
static_cast<int32_t
>(constOp.value()));
196 return rewriter.notifyMatchFailure(op,
"indices must be constants");
200 Type elementType = coopType.getElementType();
201 rewriter.replaceOpWithNewOp<spirv::CompositeExtractOp>(
202 op, elementType, matrix, rewriter.getI32ArrayAttr(intValues));
209struct WmmaInsertOpToSPIRVLowering final
210 : OpConversionPattern<gpu::SubgroupMmaInsertThreadLocalOp> {
214 matchAndRewrite(gpu::SubgroupMmaInsertThreadLocalOp op, OpAdaptor adaptor,
215 ConversionPatternRewriter &rewriter)
const override {
216 Value value = adaptor.getValue();
217 Value matrix = adaptor.getMatrix();
218 auto coopType = getTypeConverter()->convertType(matrix.getType());
220 return rewriter.notifyMatchFailure(op,
"type conversion failed");
222 SmallVector<int32_t> intValues;
223 for (Value val : op.getIndices()) {
224 if (
auto constOp = val.getDefiningOp<arith::ConstantIndexOp>()) {
225 intValues.push_back(
static_cast<int32_t
>(constOp.value()));
227 return rewriter.notifyMatchFailure(op,
"indices must be constants");
231 rewriter.replaceOpWithNewOp<spirv::CompositeInsertOp>(
232 op, coopType, value, matrix, rewriter.getI32ArrayAttr(intValues));
239struct WmmaElementwiseOpToSPIRVDefaultLowering final
240 : OpConversionPattern<gpu::SubgroupMmaElementwiseOp> {
244 matchAndRewrite(gpu::SubgroupMmaElementwiseOp op, OpAdaptor adaptor,
245 ConversionPatternRewriter &rewriter)
const override {
248 return rewriter.notifyMatchFailure(op,
249 "not all operands are coop matrices");
252 auto coopType = getTypeConverter()->convertType(op.getType());
254 return rewriter.notifyMatchFailure(op,
"type conversion failed");
263struct WmmaElementwiseOpToSPIRVScalarMulLowering final
264 : OpConversionPattern<gpu::SubgroupMmaElementwiseOp> {
268 matchAndRewrite(gpu::SubgroupMmaElementwiseOp op, OpAdaptor adaptor,
269 ConversionPatternRewriter &rewriter)
const override {
270 if (adaptor.getOperands().size() != 2)
275 return rewriter.notifyMatchFailure(op,
276 "not all operands are coop matrices");
279 if (op.getOpType() != gpu::MMAElementwiseOp::MULF)
284 Value
lhs = op.getOperands().front();
285 Value
rhs = op.getOperands().back();
286 Value splat =
nullptr;
287 Value matrix =
nullptr;
288 if (
lhs.getDefiningOp<gpu::SubgroupMmaConstantMatrixOp>()) {
289 splat = adaptor.getOperands().front();
290 matrix = adaptor.getOperands().back();
291 }
else if (
rhs.getDefiningOp<gpu::SubgroupMmaConstantMatrixOp>()) {
292 matrix = adaptor.getOperands().front();
293 splat = adaptor.getOperands().back();
295 if (!splat || !matrix)
296 return rewriter.notifyMatchFailure(op,
"no splat operand");
300 auto cc = splat.getDefiningOp<spirv::CompositeConstructOp>();
302 return rewriter.notifyMatchFailure(op,
303 "splat is not a composite construct");
306 scalar = llvm::getSingleElement(cc.getConstituents());
308 auto coopType = getTypeConverter()->convertType(op.getType());
310 return rewriter.notifyMatchFailure(op,
"type conversion failed");
311 rewriter.replaceOpWithNewOp<spirv::MatrixTimesScalarOp>(
327struct WmmaLoadOpToSPIRVLowering final
328 : OpConversionPattern<gpu::SubgroupMmaLoadMatrixOp> {
332 matchAndRewrite(gpu::SubgroupMmaLoadMatrixOp op, OpAdaptor adaptor,
333 ConversionPatternRewriter &rewriter)
const override {
334 const auto &typeConverter = *getTypeConverter<SPIRVTypeConverter>();
337 auto retType = cast<gpu::MMAMatrixType>(op.getRes().getType());
338 MemRefType memrefType = op.getSrcMemref().getType();
341 adaptor.getIndices(), loc, rewriter);
346 return rewriter.notifyMatchFailure(op,
"type conversion failed");
348 int64_t stride = op.getLeadDimension().getSExtValue();
349 IntegerType i32Type = rewriter.getI32Type();
350 auto strideValue = spirv::ConstantOp::create(
351 rewriter, loc, i32Type, IntegerAttr::get(i32Type, stride));
353 bool isColMajor = op.getTranspose().value_or(
false);
354 auto layout = isColMajor ? spirv::CooperativeMatrixLayoutKHR::ColumnMajor
355 : spirv::CooperativeMatrixLayoutKHR::RowMajor;
357 rewriter.replaceOpWithNewOp<spirv::KHRCooperativeMatrixLoadOp>(
358 op, coopType, bufferPtr, strideValue, layout);
365struct WmmaStoreOpToSPIRVLowering final
366 : OpConversionPattern<gpu::SubgroupMmaStoreMatrixOp> {
370 matchAndRewrite(gpu::SubgroupMmaStoreMatrixOp op, OpAdaptor adaptor,
371 ConversionPatternRewriter &rewriter)
const override {
372 const auto &typeConverter = *getTypeConverter<SPIRVTypeConverter>();
375 auto memrefType = cast<MemRefType>(op.getDstMemref().getType());
378 adaptor.getIndices(), loc, rewriter);
380 int64_t stride = op.getLeadDimension().getSExtValue();
381 IntegerType i32Type = rewriter.getI32Type();
382 auto strideValue = spirv::ConstantOp::create(
383 rewriter, loc, i32Type, IntegerAttr::get(i32Type, stride));
385 bool isColMajor = op.getTranspose().value_or(
false);
386 auto layout = isColMajor ? spirv::CooperativeMatrixLayoutKHR::ColumnMajor
387 : spirv::CooperativeMatrixLayoutKHR::RowMajor;
389 rewriter.replaceOpWithNewOp<spirv::KHRCooperativeMatrixStoreOp>(
390 op, bufferPtr, adaptor.getSrc(), strideValue, layout);
397struct WmmaMmaOpToSPIRVLowering final
398 : OpConversionPattern<gpu::SubgroupMmaComputeOp> {
402 matchAndRewrite(gpu::SubgroupMmaComputeOp subgroupMmaComputeOp,
404 ConversionPatternRewriter &rewriter)
const override {
406 dyn_cast<spirv::CooperativeMatrixType>(adaptor.getOpA().getType());
408 dyn_cast<spirv::CooperativeMatrixType>(adaptor.getOpB().getType());
410 dyn_cast<spirv::CooperativeMatrixType>(adaptor.getOpC().getType());
413 subgroupMmaComputeOp.getResult().
getType());
414 if (!aType || !bType || !cType || !resultType)
415 return rewriter.notifyMatchFailure(subgroupMmaComputeOp,
416 "type conversion failed");
418 using Operands = spirv::CooperativeMatrixOperandsKHR;
421 spirv::CooperativeMatrixOperandsKHRAttr operandsAttr;
422 if (operands != Operands::None)
423 operandsAttr = spirv::CooperativeMatrixOperandsKHRAttr::get(
424 rewriter.getContext(), operands);
426 rewriter.replaceOpWithNewOp<spirv::KHRCooperativeMatrixMulAddOp>(
427 subgroupMmaComputeOp, adaptor.getOpA(), adaptor.getOpB(),
428 adaptor.getOpC(), operandsAttr);
439 using namespace mlir;
441 patterns.
add<khr::WmmaLoadOpToSPIRVLowering, khr::WmmaMmaOpToSPIRVLowering,
442 khr::WmmaStoreOpToSPIRVLowering, WmmaConstantOpToSPIRVLowering,
443 WmmaExtractOpToSPIRVLowering, WmmaInsertOpToSPIRVLowering,
444 WmmaElementwiseOpToSPIRVDefaultLowering>(converter, context);
446 patterns.
add<WmmaElementwiseOpToSPIRVScalarMulLowering>(converter, context,
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
MLIRContext is the top-level object for a collection of MLIR operations.
MLIRContext * getContext() const
RewritePatternSet & add(ConstructorArg &&arg, ConstructorArgs &&...args)
Add an instance of each of the pattern types 'Ts' to the pattern list with the given arguments.
Type conversion from builtin types to SPIR-V types for shader interface.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
This class provides an abstraction over the different types of ranges over Values.
type_range getType() const
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Type getType() const
Return the type of this value.
MMAMatrix represents a matrix held by a subgroup for matrix-matrix multiply accumulate operations.
ArrayRef< int64_t > getShape() const
Get shape of the matrix.
Type getElementType() const
Get elementType of a single element.
StringRef getOperand() const
The general form of operation this type supports is given by the equation C += A*B.
static ArrayType get(Type elementType, unsigned elementCount)
static CooperativeMatrixType get(Type elementType, uint32_t rows, uint32_t columns, Scope scope, CooperativeMatrixUseKHR use)
Type getElementType() const
static PointerType get(Type pointeeType, StorageClass storageClass)
Value getElementPtr(const SPIRVTypeConverter &typeConverter, MemRefType baseType, Value basePtr, ValueRange indices, Location loc, OpBuilder &builder)
Performs the index computation to get to the element at indices of the memory pointed to by basePtr,...
Include the generated interface declarations.
static std::optional< Type > convertMemrefOfMMAMatrixType(MemRefType type)
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
static bool createElementwiseOp(ConversionPatternRewriter &builder, gpu::SubgroupMmaElementwiseOp op, Type coopType, ValueRange operands)
Creates a SPIR-V op to replace the given GPU subgroup mma elementwise op when the elementwise op dire...
void populateGpuWMMAToSPIRVCoopMatrixKHRConversionPatterns(const SPIRVTypeConverter &typeConverter, RewritePatternSet &patterns)
Collect a set of patterns to convert WMMA ops from GPU dialect to SPIRV, using the KHR Cooperative Ma...
static spirv::CooperativeMatrixType convertMMAMatrixType(gpu::MMAMatrixType type)
static spirv::CooperativeMatrixOperandsKHR getSignedCoopMatrixOperands(spirv::CooperativeMatrixType aType, spirv::CooperativeMatrixType bType, spirv::CooperativeMatrixType cType, spirv::CooperativeMatrixType resultType)
bool allOperandsHaveSameCoopMatrixType(ValueRange operands)
void populateMMAToSPIRVCoopMatrixTypeConversion(SPIRVTypeConverter &typeConverter)
Adds MMAMatrixType conversions to SPIR-V cooperative matrix KHR type conversion to the type converter...
static bool hasSignedIntegerElementType(spirv::CooperativeMatrixType type)