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());
136 return elementType && !elementType.isUnsigned();
139static spirv::CooperativeMatrixOperandsKHR
144 using Operands = spirv::CooperativeMatrixOperandsKHR;
146 Operands operands = Operands::None;
148 operands |= Operands::ASigned;
150 operands |= Operands::BSigned;
152 operands |= Operands::CSigned;
154 operands |= Operands::ResultSigned;
161struct WmmaConstantOpToSPIRVLowering final
162 : OpConversionPattern<gpu::SubgroupMmaConstantMatrixOp> {
166 matchAndRewrite(gpu::SubgroupMmaConstantMatrixOp op, OpAdaptor adaptor,
167 ConversionPatternRewriter &rewriter)
const override {
168 Value cst = llvm::getSingleElement(adaptor.getOperands());
169 auto coopType = getTypeConverter()->convertType(op.getType());
171 return rewriter.notifyMatchFailure(op,
"type conversion failed");
173 rewriter.replaceOpWithNewOp<spirv::CompositeConstructOp>(op, coopType, cst);
180struct WmmaExtractOpToSPIRVLowering final
181 : OpConversionPattern<gpu::SubgroupMmaExtractThreadLocalOp> {
185 matchAndRewrite(gpu::SubgroupMmaExtractThreadLocalOp op, OpAdaptor adaptor,
186 ConversionPatternRewriter &rewriter)
const override {
187 Value matrix = adaptor.getMatrix();
189 getTypeConverter()->convertType<spirv::CooperativeMatrixType>(
192 return rewriter.notifyMatchFailure(op,
"type conversion failed");
194 SmallVector<int32_t> intValues;
195 for (Value val : op.getIndices()) {
196 if (
auto constOp = val.getDefiningOp<arith::ConstantIndexOp>()) {
197 intValues.push_back(
static_cast<int32_t
>(constOp.value()));
199 return rewriter.notifyMatchFailure(op,
"indices must be constants");
203 Type elementType = coopType.getElementType();
204 rewriter.replaceOpWithNewOp<spirv::CompositeExtractOp>(
205 op, elementType, matrix, rewriter.getI32ArrayAttr(intValues));
212struct WmmaInsertOpToSPIRVLowering final
213 : OpConversionPattern<gpu::SubgroupMmaInsertThreadLocalOp> {
217 matchAndRewrite(gpu::SubgroupMmaInsertThreadLocalOp op, OpAdaptor adaptor,
218 ConversionPatternRewriter &rewriter)
const override {
219 Value value = adaptor.getValue();
220 Value matrix = adaptor.getMatrix();
221 auto coopType = getTypeConverter()->convertType(matrix.getType());
223 return rewriter.notifyMatchFailure(op,
"type conversion failed");
225 SmallVector<int32_t> intValues;
226 for (Value val : op.getIndices()) {
227 if (
auto constOp = val.getDefiningOp<arith::ConstantIndexOp>()) {
228 intValues.push_back(
static_cast<int32_t
>(constOp.value()));
230 return rewriter.notifyMatchFailure(op,
"indices must be constants");
234 rewriter.replaceOpWithNewOp<spirv::CompositeInsertOp>(
235 op, coopType, value, matrix, rewriter.getI32ArrayAttr(intValues));
242struct WmmaElementwiseOpToSPIRVDefaultLowering final
243 : OpConversionPattern<gpu::SubgroupMmaElementwiseOp> {
247 matchAndRewrite(gpu::SubgroupMmaElementwiseOp op, OpAdaptor adaptor,
248 ConversionPatternRewriter &rewriter)
const override {
251 return rewriter.notifyMatchFailure(op,
252 "not all operands are coop matrices");
255 auto coopType = getTypeConverter()->convertType(op.getType());
257 return rewriter.notifyMatchFailure(op,
"type conversion failed");
266struct WmmaElementwiseOpToSPIRVScalarMulLowering final
267 : OpConversionPattern<gpu::SubgroupMmaElementwiseOp> {
271 matchAndRewrite(gpu::SubgroupMmaElementwiseOp op, OpAdaptor adaptor,
272 ConversionPatternRewriter &rewriter)
const override {
273 if (adaptor.getOperands().size() != 2)
278 return rewriter.notifyMatchFailure(op,
279 "not all operands are coop matrices");
282 if (op.getOpType() != gpu::MMAElementwiseOp::MULF)
287 Value
lhs = op.getOperands().front();
288 Value
rhs = op.getOperands().back();
289 Value splat =
nullptr;
290 Value matrix =
nullptr;
291 if (
lhs.getDefiningOp<gpu::SubgroupMmaConstantMatrixOp>()) {
292 splat = adaptor.getOperands().front();
293 matrix = adaptor.getOperands().back();
294 }
else if (
rhs.getDefiningOp<gpu::SubgroupMmaConstantMatrixOp>()) {
295 matrix = adaptor.getOperands().front();
296 splat = adaptor.getOperands().back();
298 if (!splat || !matrix)
299 return rewriter.notifyMatchFailure(op,
"no splat operand");
303 auto cc = splat.getDefiningOp<spirv::CompositeConstructOp>();
305 return rewriter.notifyMatchFailure(op,
306 "splat is not a composite construct");
309 scalar = llvm::getSingleElement(cc.getConstituents());
311 auto coopType = getTypeConverter()->convertType(op.getType());
313 return rewriter.notifyMatchFailure(op,
"type conversion failed");
314 rewriter.replaceOpWithNewOp<spirv::MatrixTimesScalarOp>(
327struct MemoryRequirements {
328 spirv::MemoryAccessAttr memoryAccess;
329 IntegerAttr alignment;
335 auto ptrType = cast<spirv::PointerType>(accessedPtr.
getType());
336 if (ptrType.getStorageClass() != spirv::StorageClass::PhysicalStorageBuffer)
340 std::optional<int64_t> sizeInBytes;
341 Type pointeeType = ptrType.getPointeeType();
342 if (
auto scalarType = dyn_cast<spirv::ScalarType>(pointeeType)) {
343 sizeInBytes = scalarType.getSizeInBytes();
344 }
else if (
auto vecType = dyn_cast<VectorType>(pointeeType)) {
345 if (
auto scalarElem = dyn_cast<spirv::ScalarType>(vecType.getElementType()))
346 if (
auto elemSize = scalarElem.getSizeInBytes())
347 sizeInBytes = *elemSize * vecType.getNumElements();
354 return {spirv::MemoryAccessAttr::get(ctx, spirv::MemoryAccess::Aligned),
355 IntegerAttr::get(IntegerType::get(ctx, 32), *sizeInBytes)};
360struct WmmaLoadOpToSPIRVLowering final
361 : OpConversionPattern<gpu::SubgroupMmaLoadMatrixOp> {
365 matchAndRewrite(gpu::SubgroupMmaLoadMatrixOp op, OpAdaptor adaptor,
366 ConversionPatternRewriter &rewriter)
const override {
367 const auto &typeConverter = *getTypeConverter<SPIRVTypeConverter>();
370 auto retType = cast<gpu::MMAMatrixType>(op.getRes().getType());
371 MemRefType memrefType = op.getSrcMemref().getType();
374 adaptor.getIndices(), loc, rewriter);
379 return rewriter.notifyMatchFailure(op,
"type conversion failed");
381 int64_t stride = op.getLeadDimension().getSExtValue();
382 IntegerType i32Type = rewriter.getI32Type();
383 auto strideValue = spirv::ConstantOp::create(
384 rewriter, loc, i32Type, IntegerAttr::get(i32Type, stride));
386 bool isColMajor = op.getTranspose().value_or(
false);
387 auto layout = isColMajor ? spirv::CooperativeMatrixLayoutKHR::ColumnMajor
388 : spirv::CooperativeMatrixLayoutKHR::RowMajor;
391 rewriter.replaceOpWithNewOp<spirv::KHRCooperativeMatrixLoadOp>(
392 op, coopType, bufferPtr, layout, strideValue, memReq.memoryAccess,
400struct WmmaStoreOpToSPIRVLowering final
401 : OpConversionPattern<gpu::SubgroupMmaStoreMatrixOp> {
405 matchAndRewrite(gpu::SubgroupMmaStoreMatrixOp op, OpAdaptor adaptor,
406 ConversionPatternRewriter &rewriter)
const override {
407 const auto &typeConverter = *getTypeConverter<SPIRVTypeConverter>();
410 auto memrefType = cast<MemRefType>(op.getDstMemref().getType());
413 adaptor.getIndices(), loc, rewriter);
415 int64_t stride = op.getLeadDimension().getSExtValue();
416 IntegerType i32Type = rewriter.getI32Type();
417 auto strideValue = spirv::ConstantOp::create(
418 rewriter, loc, i32Type, IntegerAttr::get(i32Type, stride));
420 bool isColMajor = op.getTranspose().value_or(
false);
421 auto layout = isColMajor ? spirv::CooperativeMatrixLayoutKHR::ColumnMajor
422 : spirv::CooperativeMatrixLayoutKHR::RowMajor;
425 rewriter.replaceOpWithNewOp<spirv::KHRCooperativeMatrixStoreOp>(
426 op, bufferPtr, adaptor.getSrc(), layout, strideValue,
427 memReq.memoryAccess, memReq.alignment);
434struct WmmaMmaOpToSPIRVLowering final
435 : OpConversionPattern<gpu::SubgroupMmaComputeOp> {
439 matchAndRewrite(gpu::SubgroupMmaComputeOp subgroupMmaComputeOp,
441 ConversionPatternRewriter &rewriter)
const override {
443 dyn_cast<spirv::CooperativeMatrixType>(adaptor.getOpA().getType());
445 dyn_cast<spirv::CooperativeMatrixType>(adaptor.getOpB().getType());
447 dyn_cast<spirv::CooperativeMatrixType>(adaptor.getOpC().getType());
450 subgroupMmaComputeOp.getResult().
getType());
451 if (!aType || !bType || !cType || !resultType)
452 return rewriter.notifyMatchFailure(subgroupMmaComputeOp,
453 "type conversion failed");
455 using Operands = spirv::CooperativeMatrixOperandsKHR;
458 spirv::CooperativeMatrixOperandsKHRAttr operandsAttr;
459 if (operands != Operands::None)
460 operandsAttr = spirv::CooperativeMatrixOperandsKHRAttr::get(
461 rewriter.getContext(), operands);
463 rewriter.replaceOpWithNewOp<spirv::KHRCooperativeMatrixMulAddOp>(
464 subgroupMmaComputeOp, adaptor.getOpA(), adaptor.getOpB(),
465 adaptor.getOpC(), operandsAttr);
476 using namespace mlir;
478 patterns.
add<khr::WmmaLoadOpToSPIRVLowering, khr::WmmaMmaOpToSPIRVLowering,
479 khr::WmmaStoreOpToSPIRVLowering, WmmaConstantOpToSPIRVLowering,
480 WmmaExtractOpToSPIRVLowering, WmmaInsertOpToSPIRVLowering,
481 WmmaElementwiseOpToSPIRVDefaultLowering>(converter, context);
483 patterns.
add<WmmaElementwiseOpToSPIRVScalarMulLowering>(converter, context,
static FailureOr< MemoryRequirements > calculateMemoryRequirements(Value accessedPtr, bool isNontemporal, uint64_t preferredAlignment)
Given an accessed SPIR-V pointer, calculates its alignment requirements, if any.
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...
MLIRContext * getContext() const
Utility to get the associated MLIRContext that this value is defined in.
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)
static bool hasSignedGpuMmaIntegerSemantics(spirv::CooperativeMatrixType 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...