29#include "llvm/ADT/STLExtras.h"
30#include "llvm/ADT/TypeSwitch.h"
31#include "llvm/Support/AMDGPUAddrSpace.h"
32#include "llvm/Support/Casting.h"
33#include "llvm/Support/ErrorHandling.h"
34#include "llvm/Support/MathExtras.h"
39#define GEN_PASS_DEF_CONVERTAMDGPUTOROCDLPASS
40#include "mlir/Conversion/Passes.h.inc"
49 IntegerType destTy = rewriter.getIntegerType(width);
51 auto valTy = cast<IntegerType>(val.
getType());
54 return valTy.getWidth() > width
55 ?
Value(LLVM::TruncOp::create(rewriter, loc, destTy, val))
56 :
Value(LLVM::ZExtOp::create(rewriter, loc, destTy, val));
67 return LLVM::ConstantOp::create(rewriter, loc, rewriter.getI32Type(), value);
78 return LLVM::ConstantOp::create(rewriter, loc, rewriter.getI64Type(), value);
85 IntegerType i32 = rewriter.getI32Type();
87 for (
auto [i, increment, stride] : llvm::enumerate(
indices, strides)) {
90 ShapedType::isDynamic(stride)
92 memRefDescriptor.
stride(rewriter, loc, i))
93 : LLVM::ConstantOp::create(rewriter, loc, i32, stride);
94 increment = LLVM::MulOp::create(rewriter, loc, increment, strideValue);
106 MemRefType memrefType,
109 unsigned numRecordsWidth,
bool boundsCheck) {
110 if (numRecordsWidth > 32 && !boundsCheck)
112 if (memrefType.hasStaticShape() &&
113 !llvm::any_of(strides, ShapedType::isDynamic)) {
114 int64_t size = memrefType.getRank() == 0 ? 1 : 0;
116 for (uint32_t i = 0, e = memrefType.getRank(); i < e; ++i)
117 size = std::max(
shape[i] * strides[i], size);
118 size = size * elementByteWidth;
122 for (uint32_t i = 0, e = memrefType.getRank(); i < e; ++i) {
123 Value size = memrefDescriptor.
size(rewriter, loc, i);
124 Value stride = memrefDescriptor.
stride(rewriter, loc, i);
125 Value maxThisDim = LLVM::MulOp::create(rewriter, loc, size, stride);
127 ? LLVM::UMaxOp::create(rewriter, loc, maxIndex, maxThisDim)
132 return LLVM::MulOp::create(rewriter, loc, maxIndexI64, byteWidthConst);
138 unsigned numRecordsWidth,
139 Value cacheSwizzleStride =
nullptr,
140 unsigned addressSpace = 8) {
144 Type i16 = rewriter.getI16Type();
146 if (
target.has(llvm::AMDGPU::FEAT_GFX940_INSTS) && cacheSwizzleStride) {
147 Value cacheStrideZext =
148 LLVM::ZExtOp::create(rewriter, loc, i16, cacheSwizzleStride);
149 Value swizzleBit = LLVM::ConstantOp::create(
150 rewriter, loc, i16, rewriter.getI16IntegerAttr(1 << 14));
151 stride = LLVM::OrOp::create(rewriter, loc, cacheStrideZext, swizzleBit,
154 stride = LLVM::ConstantOp::create(rewriter, loc, i16,
155 rewriter.getI16IntegerAttr(0));
159 if (
target.has(llvm::AMDGPU::FEAT_GFX1250_INSTS)) {
184 flags |= (7 << 12) | (4 << 15);
185 if (
target.has(llvm::AMDGPU::FEAT_GFX10_INSTS)) {
187 uint32_t oob = boundsCheck ? 3 : 2;
188 flags |= (oob << 28);
194 LLVM::LLVMPointerType::get(rewriter.getContext(), addressSpace);
195 Value resource = rewriter.createOrFold<ROCDL::MakeBufferRsrcOp>(
196 loc, rsrcType, basePointer, stride, numRecords, flagsConst);
201struct FatRawBufferCastLowering
203 FatRawBufferCastLowering(
const LLVMTypeConverter &converter,
204 const ROCDL::TargetInfo &target)
205 : ConvertOpToLLVMPattern<FatRawBufferCastOp>(converter), target(target) {}
207 ROCDL::TargetInfo target;
210 matchAndRewrite(FatRawBufferCastOp op, FatRawBufferCastOpAdaptor adaptor,
211 ConversionPatternRewriter &rewriter)
const override {
212 Location loc = op.getLoc();
213 Value memRef = adaptor.getSource();
214 Value unconvertedMemref = op.getSource();
215 MemRefType memrefType = cast<MemRefType>(unconvertedMemref.
getType());
216 MemRefDescriptor descriptor(memRef);
218 DataLayout dataLayout = DataLayout::closest(op);
219 int64_t elementByteWidth =
222 int64_t unusedOffset = 0;
223 SmallVector<int64_t, 5> strideVals;
224 if (
failed(memrefType.getStridesAndOffset(strideVals, unusedOffset)))
225 return op.emitOpError(
"Can't lower non-stride-offset memrefs");
227 std::optional<unsigned> numRecordsWidth =
228 target.getBufferResourceNumRecordsWidth();
229 if (!numRecordsWidth)
230 return op.emitOpError(
231 "buffer resource num_records width is unknown for this target");
233 Value numRecords = adaptor.getValidBytes();
235 numRecords =
getNumRecords(rewriter, loc, memrefType, descriptor,
236 strideVals, elementByteWidth, *numRecordsWidth,
237 adaptor.getBoundsCheck());
240 adaptor.getResetOffset()
241 ? descriptor.bufferPtr(rewriter, loc, *getTypeConverter(),
243 : descriptor.alignedPtr(rewriter, loc);
246 adaptor.getResetOffset()
248 : descriptor.offset(rewriter, loc);
250 bool hasSizes = memrefType.getRank() > 0;
253 Value sizes = hasSizes
254 ? LLVM::ExtractValueOp::create(rewriter, loc, descriptor,
258 hasSizes ? LLVM::ExtractValueOp::create(rewriter, loc, descriptor,
263 rewriter, loc, basePointer, numRecords, adaptor.getBoundsCheck(),
264 target, *numRecordsWidth, adaptor.getCacheSwizzleStride(),
267 Value
result = MemRefDescriptor::poison(
269 getTypeConverter()->convertType(op.getResult().getType()));
271 result = LLVM::InsertValueOp::create(rewriter, loc,
result, fatPtr, pos);
272 result = LLVM::InsertValueOp::create(rewriter, loc,
result, fatPtr,
274 result = LLVM::InsertValueOp::create(rewriter, loc,
result, offset,
277 result = LLVM::InsertValueOp::create(rewriter, loc,
result, sizes,
279 result = LLVM::InsertValueOp::create(rewriter, loc,
result, strides,
282 rewriter.replaceOp(op,
result);
288template <
typename GpuOp,
typename Intrinsic>
290 RawBufferOpLowering(
const LLVMTypeConverter &converter,
291 const ROCDL::TargetInfo &target)
292 : ConvertOpToLLVMPattern<GpuOp>(converter), target(target) {}
294 ROCDL::TargetInfo target;
295 static constexpr uint32_t maxVectorOpWidth = 128;
298 matchAndRewrite(GpuOp gpuOp,
typename GpuOp::Adaptor adaptor,
299 ConversionPatternRewriter &rewriter)
const override {
300 Location loc = gpuOp.getLoc();
301 Value memref = adaptor.getMemref();
302 Value unconvertedMemref = gpuOp.getMemref();
303 MemRefType memrefType = cast<MemRefType>(unconvertedMemref.
getType());
305 if (!target.has(llvm::AMDGPU::FEAT_GFX9_INSTS))
306 return gpuOp.emitOpError(
"raw buffer ops require GCN or higher");
308 Value storeData = adaptor.getODSOperands(0)[0];
309 if (storeData == memref)
313 wantedDataType = storeData.
getType();
315 wantedDataType = gpuOp.getODSResults(0)[0].getType();
317 Value atomicCmpData = Value();
320 Value maybeCmpData = adaptor.getODSOperands(1)[0];
321 if (maybeCmpData != memref)
322 atomicCmpData = maybeCmpData;
325 Type llvmWantedDataType = this->typeConverter->convertType(wantedDataType);
327 Type i32 = rewriter.getI32Type();
330 DataLayout dataLayout = DataLayout::closest(gpuOp);
331 int64_t elementByteWidth =
340 Type llvmBufferValType = llvmWantedDataType;
342 if (
auto floatType = dyn_cast<FloatType>(wantedDataType))
343 llvmBufferValType = this->getTypeConverter()->convertType(
344 rewriter.getIntegerType(floatType.getWidth()));
346 if (
auto dataVector = dyn_cast<VectorType>(wantedDataType)) {
347 uint32_t vecLen = dataVector.getNumElements();
350 uint32_t totalBits = elemBits * vecLen;
352 isa_and_present<RawBufferAtomicFaddOp>(*gpuOp) && vecLen == 2;
353 if (totalBits > maxVectorOpWidth)
354 return gpuOp.emitOpError(
355 "Total width of loads or stores must be no more than " +
356 Twine(maxVectorOpWidth) +
" bits, but we call for " +
358 " bits. This should've been caught in validation");
359 if (!usePackedFp16 && elemBits < 32) {
360 if (totalBits > 32) {
361 if (totalBits % 32 != 0)
362 return gpuOp.emitOpError(
"Load or store of more than 32-bits that "
363 "doesn't fit into words. Can't happen\n");
364 llvmBufferValType = this->typeConverter->convertType(
365 VectorType::get(totalBits / 32, i32));
367 llvmBufferValType = this->typeConverter->convertType(
368 rewriter.getIntegerType(totalBits));
372 if (
auto vecType = dyn_cast<VectorType>(llvmBufferValType)) {
375 if (vecType.getNumElements() == 1)
376 llvmBufferValType = vecType.getElementType();
379 SmallVector<Value, 6> args;
381 if (llvmBufferValType != llvmWantedDataType) {
382 Value castForStore = LLVM::BitcastOp::create(
383 rewriter, loc, llvmBufferValType, storeData);
384 args.push_back(castForStore);
386 args.push_back(storeData);
391 if (llvmBufferValType != llvmWantedDataType) {
392 Value castForCmp = LLVM::BitcastOp::create(
393 rewriter, loc, llvmBufferValType, atomicCmpData);
394 args.push_back(castForCmp);
396 args.push_back(atomicCmpData);
402 SmallVector<int64_t, 5> strides;
403 if (
failed(memrefType.getStridesAndOffset(strides, offset)))
404 return gpuOp.emitOpError(
"Can't lower non-stride-offset memrefs");
406 MemRefDescriptor memrefDescriptor(memref);
408 Value ptr = memrefDescriptor.bufferPtr(
409 rewriter, loc, *this->getTypeConverter(), memrefType);
410 std::optional<unsigned> numRecordsWidth =
411 target.getBufferResourceNumRecordsWidth();
412 if (!numRecordsWidth)
413 return gpuOp.emitOpError(
414 "buffer resource num_records width is unknown for this target");
417 rewriter, loc, memrefType, memrefDescriptor, strides, elementByteWidth,
418 *numRecordsWidth, adaptor.getBoundsCheck());
420 makeBufferRsrc(rewriter, loc, ptr, numRecords, adaptor.getBoundsCheck(),
421 target, *numRecordsWidth);
422 args.push_back(resource);
426 adaptor.getIndices(), strides);
427 if (std::optional<int32_t> indexOffset = adaptor.getIndexOffset();
428 indexOffset && *indexOffset > 0) {
430 voffset = voffset ? LLVM::AddOp::create(rewriter, loc, voffset,
434 voffset = LLVM::MulOp::create(rewriter, loc, voffset, byteWidthConst);
435 args.push_back(voffset);
438 Value sgprOffset = adaptor.getSgprOffset();
441 sgprOffset = LLVM::MulOp::create(rewriter, loc, sgprOffset, byteWidthConst);
442 args.push_back(sgprOffset);
444 llvm::SmallVector<Type, 1> resultTypes(gpuOp->getNumResults(),
446 typename Intrinsic::Properties properties{};
447 properties.aux = rewriter.getI32IntegerAttr(0);
449 Intrinsic::create(rewriter, loc, resultTypes, args, properties);
452 if (llvmBufferValType != llvmWantedDataType) {
453 replacement = LLVM::BitcastOp::create(rewriter, loc, llvmWantedDataType,
458 rewriter.eraseOp(gpuOp);
476 unsigned vmcnt,
unsigned expcnt,
480 if (!
target.has(llvm::AMDGPU::FEAT_GFX9_INSTS)) {
481 vmcnt = std::min(15u, vmcnt);
482 expcnt = std::min(7u, expcnt);
483 lgkmcnt = std::min(15u, lgkmcnt);
484 return vmcnt | (expcnt << 4) | (lgkmcnt << 8);
486 if (
target.isGeneration(9)) {
487 vmcnt = std::min(63u, vmcnt);
488 expcnt = std::min(7u, expcnt);
489 lgkmcnt = std::min(15u, lgkmcnt);
490 unsigned lowBits = vmcnt & 0xF;
491 unsigned highBits = (vmcnt >> 4) << 14;
492 unsigned otherCnts = (expcnt << 4) | (lgkmcnt << 8);
493 return lowBits | highBits | otherCnts;
495 if (
target.isGeneration(10)) {
496 vmcnt = std::min(63u, vmcnt);
497 expcnt = std::min(7u, expcnt);
498 lgkmcnt = std::min(63u, lgkmcnt);
499 unsigned lowBits = vmcnt & 0xF;
500 unsigned highBits = (vmcnt >> 4) << 14;
501 unsigned otherCnts = (expcnt << 4) | (lgkmcnt << 8);
502 return lowBits | highBits | otherCnts;
504 if (
target.isGeneration(11)) {
505 vmcnt = std::min(63u, vmcnt);
506 expcnt = std::min(7u, expcnt);
507 lgkmcnt = std::min(63u, lgkmcnt);
508 return (vmcnt << 10) | expcnt | (lgkmcnt << 4);
513struct MemoryCounterWaitOpLowering
515 MemoryCounterWaitOpLowering(
const LLVMTypeConverter &converter,
516 const ROCDL::TargetInfo &target)
517 : ConvertOpToLLVMPattern<MemoryCounterWaitOp>(converter), target(target) {
520 ROCDL::TargetInfo target;
523 matchAndRewrite(MemoryCounterWaitOp op, OpAdaptor adaptor,
524 ConversionPatternRewriter &rewriter)
const override {
525 if (target.has(llvm::AMDGPU::FEAT_GFX12_INSTS)) {
526 Location loc = op.getLoc();
527 if (std::optional<int> ds = adaptor.getDs())
528 ROCDL::WaitDscntOp::create(rewriter, loc, *ds);
530 if (std::optional<int>
load = adaptor.getLoad())
531 ROCDL::WaitLoadcntOp::create(rewriter, loc, *
load);
533 if (std::optional<int> store = adaptor.getStore())
534 ROCDL::WaitStorecntOp::create(rewriter, loc, *store);
536 if (std::optional<int> exp = adaptor.getExp())
537 ROCDL::WaitExpcntOp::create(rewriter, loc, *exp);
539 if (std::optional<int> tensor = adaptor.getTensor())
540 ROCDL::WaitTensorcntOp::create(rewriter, loc, *tensor);
542 rewriter.eraseOp(op);
546 if (adaptor.getTensor())
547 return op.emitOpError(
"unsupported chipset");
549 auto getVal = [](Attribute attr) ->
unsigned {
551 return cast<IntegerAttr>(attr).getInt();
556 unsigned ds = getVal(adaptor.getDsAttr());
557 unsigned exp = getVal(adaptor.getExpAttr());
559 unsigned vmcnt = 1024;
561 Attribute store = adaptor.getStoreAttr();
563 vmcnt = getVal(
load) + getVal(store);
567 vmcnt = getVal(store);
570 FailureOr<unsigned> waitcnt = encodeWaitcnt(
target, vmcnt, exp, ds);
572 return op.emitOpError(
"unsupported chipset");
574 rewriter.replaceOpWithNewOp<ROCDL::SWaitcntOp>(op, *waitcnt);
587 matchAndRewrite(LDSBarrierOp op, LDSBarrierOp::Adaptor adaptor,
588 ConversionPatternRewriter &rewriter)
const override {
590 bool hasSplitBarriers =
target.has(llvm::AMDGPU::FEAT_GFX12_INSTS);
596 bool requiresInlineAsm =
597 !hasSplitBarriers && !
target.has(llvm::AMDGPU::FEAT_BACK_OFF_BARRIER);
600 rewriter.getAttr<LLVM::MMRATagAttr>(
"amdgpu-synchronize-as",
"local");
609 StringRef scope =
"workgroup";
611 auto relFence = LLVM::FenceOp::create(rewriter, loc,
612 LLVM::AtomicOrdering::release, scope);
613 relFence->setDiscardableAttr(LLVM::LLVMDialect::getMmraAttrName(), mmra);
614 if (requiresInlineAsm) {
615 auto asmDialectAttr = LLVM::AsmDialectAttr::get(rewriter.getContext(),
616 LLVM::AsmDialect::AD_ATT);
617 const char *asmStr =
";;;WARNING: BREAKS DEBUG WATCHES\ns_barrier";
618 const char *constraints =
"";
619 LLVM::InlineAsmOp::create(
622 asmStr, constraints,
true,
623 false, LLVM::TailCallKind::None,
627 }
else if (!hasSplitBarriers) {
628 ROCDL::SBarrierOp::create(rewriter, loc);
630 ROCDL::BarrierSignalOp::create(rewriter, loc, -1);
631 ROCDL::BarrierWaitOp::create(rewriter, loc, -1);
634 auto acqFence = LLVM::FenceOp::create(rewriter, loc,
635 LLVM::AtomicOrdering::acquire, scope);
636 acqFence->setDiscardableAttr(LLVM::LLVMDialect::getMmraAttrName(), mmra);
637 rewriter.replaceOp(op, acqFence);
643 SchedBarrierOpLowering(
const LLVMTypeConverter &converter,
644 const ROCDL::TargetInfo &target)
645 : ConvertOpToLLVMPattern<SchedBarrierOp>(converter), target(target) {}
647 ROCDL::TargetInfo target;
650 matchAndRewrite(SchedBarrierOp op, SchedBarrierOp::Adaptor adaptor,
651 ConversionPatternRewriter &rewriter)
const override {
652 rewriter.replaceOpWithNewOp<ROCDL::SchedBarrier>(op, op.getOptsAttr());
676 bool allowBf16 =
true) {
678 if (
auto vectorType = dyn_cast<VectorType>(inputType)) {
679 if (vectorType.getElementType().isBF16() && !allowBf16)
680 return LLVM::BitcastOp::create(
681 rewriter, loc, vectorType.clone(rewriter.getI16Type()), input);
682 if (vectorType.getElementType().isInteger(8) &&
683 vectorType.getNumElements() <= 8)
684 return LLVM::BitcastOp::create(
686 rewriter.getIntegerType(vectorType.getNumElements() * 8), input);
687 if (isa<IntegerType>(vectorType.getElementType()) &&
688 vectorType.getElementTypeBitWidth() <= 8) {
689 int64_t numWords = llvm::divideCeil(
690 vectorType.getNumElements() * vectorType.getElementTypeBitWidth(),
692 return LLVM::BitcastOp::create(
693 rewriter, loc, VectorType::get(numWords, rewriter.getI32Type()),
703 bool allowBf16 =
true) {
705 auto vectorType = cast<VectorType>(inputType);
707 if (vectorType.getElementType().isBF16() && !allowBf16)
708 return LLVM::BitcastOp::create(
709 rewriter, loc, vectorType.clone(rewriter.getI16Type()), input);
711 if (isa<IntegerType>(vectorType.getElementType()) &&
712 vectorType.getElementTypeBitWidth() <= 8) {
713 int64_t numWords = llvm::divideCeil(
714 vectorType.getNumElements() * vectorType.getElementTypeBitWidth(), 32);
715 Type castType = (numWords > 1)
716 ?
Type{VectorType::get(numWords, rewriter.getI32Type())}
717 : rewriter.getI32Type();
718 return LLVM::BitcastOp::create(rewriter, loc, castType, input);
736 .Case([&](IntegerType) {
738 return LLVM::ZExtOp::create(rewriter, loc, rewriter.getI32Type(),
741 .Case([&](VectorType vectorType) {
743 int64_t numElements = vectorType.getNumElements();
744 assert((numElements == 4 || numElements == 8) &&
745 "scale operand must be a vector of length 4 or 8");
746 IntegerType outputType =
747 (numElements == 4) ? rewriter.getI32Type() : rewriter.getI64Type();
748 return LLVM::BitcastOp::create(rewriter, loc, outputType, input);
750 .DefaultUnreachable(
"unexpected input type for scale operand");
754static std::optional<ROCDL::WMMAMatrixScaleFormat>
757 .Case([](Float8E8M0FNUType) {
return ROCDL::WMMAMatrixScaleFormat::e8; })
758 .Case([](Float8E4M3FNType) {
return ROCDL::WMMAMatrixScaleFormat::e4m3; })
759 .Default(std::nullopt);
764static std::optional<StringRef>
766 if (m == 16 && n == 16 && k == 128)
768 ? ROCDL::wmma_scale16_f32_16x16x128_f8f6f4::getOperationName()
769 : ROCDL::wmma_scale_f32_16x16x128_f8f6f4::getOperationName();
771 if (m == 32 && n == 16 && k == 128)
772 return isScale16 ? ROCDL::wmma_scale16_f32_32x16x128_f4::getOperationName()
773 : ROCDL::wmma_scale_f32_32x16x128_f4::getOperationName();
787 ConversionPatternRewriter &rewriter,
Location loc,
792 auto vectorType = dyn_cast<VectorType>(inputType);
794 operands.push_back(llvmInput);
797 Type elemType = vectorType.getElementType();
799 operands.push_back(llvmInput);
806 auto mlirInputType = cast<VectorType>(mlirInput.
getType());
807 bool isInputInteger = mlirInputType.getElementType().isInteger();
808 if (isInputInteger) {
810 bool localIsUnsigned = isUnsigned;
812 localIsUnsigned =
true;
814 localIsUnsigned =
false;
817 NamedAttribute(attrName, rewriter.getBoolAttr(!localIsUnsigned)));
822 Type i32 = rewriter.getI32Type();
823 Type intrinsicInType = numBits <= 32
824 ? (
Type)rewriter.getIntegerType(numBits)
825 : (
Type)VectorType::get(numBits / 32, i32);
826 auto llvmIntrinsicInType = typeConverter->convertType(intrinsicInType);
827 Value castInput = rewriter.createOrFold<LLVM::BitcastOp>(
828 loc, llvmIntrinsicInType, llvmInput);
833 castInput = LLVM::ZExtOp::create(rewriter, loc, i32, castInput);
834 operands.push_back(castInput);
847 Value output, int32_t subwordOffset,
851 auto vectorType = dyn_cast<VectorType>(inputType);
852 Type elemType = vectorType.getElementType();
853 operands.push_back(output);
866 return (
target.hasFnuzFp8() && isa<Float8E5M2FNUZType>(type)) ||
867 (
target.hasOcpFp8() && isa<Float8E5M2Type>(type));
874 return (
target.hasFnuzFp8() && isa<Float8E4M3FNUZType>(type)) ||
875 (
target.hasOcpFp8() && isa<Float8E4M3FNType>(type));
881static std::optional<StringRef>
883 uint32_t m = mfma.getM(), n = mfma.getN(), k = mfma.getK(),
884 b = mfma.getBlocks();
889 if (mfma.getReducePrecision() &&
890 target.has(llvm::AMDGPU::FEAT_XF32_INSTS)) {
891 if (m == 32 && n == 32 && k == 4 &&
b == 1)
892 return ROCDL::mfma_f32_32x32x4_xf32::getOperationName();
893 if (m == 16 && n == 16 && k == 8 &&
b == 1)
894 return ROCDL::mfma_f32_16x16x8_xf32::getOperationName();
896 if (m == 32 && n == 32 && k == 1 &&
b == 2)
897 return ROCDL::mfma_f32_32x32x1f32::getOperationName();
898 if (m == 16 && n == 16 && k == 1 &&
b == 4)
899 return ROCDL::mfma_f32_16x16x1f32::getOperationName();
900 if (m == 4 && n == 4 && k == 1 &&
b == 16)
901 return ROCDL::mfma_f32_4x4x1f32::getOperationName();
902 if (m == 32 && n == 32 && k == 2 &&
b == 1)
903 return ROCDL::mfma_f32_32x32x2f32::getOperationName();
904 if (m == 16 && n == 16 && k == 4 &&
b == 1)
905 return ROCDL::mfma_f32_16x16x4f32::getOperationName();
909 if (
target.has(llvm::AMDGPU::FEAT_GFX950_INSTS)) {
910 if (m == 32 && n == 32 && k == 16 &&
b == 1)
911 return ROCDL::mfma_f32_32x32x16_f16::getOperationName();
912 if (m == 16 && n == 16 && k == 32 &&
b == 1)
913 return ROCDL::mfma_f32_16x16x32_f16::getOperationName();
915 if (m == 32 && n == 32 && k == 4 &&
b == 2)
916 return ROCDL::mfma_f32_32x32x4f16::getOperationName();
917 if (m == 16 && n == 16 && k == 4 &&
b == 4)
918 return ROCDL::mfma_f32_16x16x4f16::getOperationName();
919 if (m == 4 && n == 4 && k == 4 &&
b == 16)
920 return ROCDL::mfma_f32_4x4x4f16::getOperationName();
921 if (m == 32 && n == 32 && k == 8 &&
b == 1)
922 return ROCDL::mfma_f32_32x32x8f16::getOperationName();
923 if (m == 16 && n == 16 && k == 16 &&
b == 1)
924 return ROCDL::mfma_f32_16x16x16f16::getOperationName();
928 if (
target.has(llvm::AMDGPU::FEAT_GFX950_INSTS)) {
929 if (m == 32 && n == 32 && k == 16 &&
b == 1)
930 return ROCDL::mfma_f32_32x32x16_bf16::getOperationName();
931 if (m == 16 && n == 16 && k == 32 &&
b == 1)
932 return ROCDL::mfma_f32_16x16x32_bf16::getOperationName();
934 if (
target.has(llvm::AMDGPU::FEAT_GFX90A_INSTS)) {
935 if (m == 32 && n == 32 && k == 4 &&
b == 2)
936 return ROCDL::mfma_f32_32x32x4bf16_1k::getOperationName();
937 if (m == 16 && n == 16 && k == 4 &&
b == 4)
938 return ROCDL::mfma_f32_16x16x4bf16_1k::getOperationName();
939 if (m == 4 && n == 4 && k == 4 &&
b == 16)
940 return ROCDL::mfma_f32_4x4x4bf16_1k::getOperationName();
941 if (m == 32 && n == 32 && k == 8 &&
b == 1)
942 return ROCDL::mfma_f32_32x32x8bf16_1k::getOperationName();
943 if (m == 16 && n == 16 && k == 16 &&
b == 1)
944 return ROCDL::mfma_f32_16x16x16bf16_1k::getOperationName();
946 if (m == 32 && n == 32 && k == 2 &&
b == 2)
947 return ROCDL::mfma_f32_32x32x2bf16::getOperationName();
948 if (m == 16 && n == 16 && k == 2 &&
b == 4)
949 return ROCDL::mfma_f32_16x16x2bf16::getOperationName();
950 if (m == 4 && n == 4 && k == 2 &&
b == 16)
951 return ROCDL::mfma_f32_4x4x2bf16::getOperationName();
952 if (m == 32 && n == 32 && k == 4 &&
b == 1)
953 return ROCDL::mfma_f32_32x32x4bf16::getOperationName();
954 if (m == 16 && n == 16 && k == 8 &&
b == 1)
955 return ROCDL::mfma_f32_16x16x8bf16::getOperationName();
959 if (
target.has(llvm::AMDGPU::FEAT_GFX950_INSTS)) {
960 if (m == 32 && n == 32 && k == 32 &&
b == 1)
961 return ROCDL::mfma_i32_32x32x32_i8::getOperationName();
962 if (m == 16 && n == 16 && k == 64 &&
b == 1)
963 return ROCDL::mfma_i32_16x16x64_i8::getOperationName();
965 if (m == 32 && n == 32 && k == 4 &&
b == 2)
966 return ROCDL::mfma_i32_32x32x4i8::getOperationName();
967 if (m == 16 && n == 16 && k == 4 &&
b == 4)
968 return ROCDL::mfma_i32_16x16x4i8::getOperationName();
969 if (m == 4 && n == 4 && k == 4 &&
b == 16)
970 return ROCDL::mfma_i32_4x4x4i8::getOperationName();
971 if (m == 32 && n == 32 && k == 8 &&
b == 1)
972 return ROCDL::mfma_i32_32x32x8i8::getOperationName();
973 if (m == 16 && n == 16 && k == 16 &&
b == 1)
974 return ROCDL::mfma_i32_16x16x16i8::getOperationName();
975 if (m == 32 && n == 32 && k == 16 &&
b == 1 &&
976 target.has(llvm::AMDGPU::FEAT_GFX940_INSTS))
977 return ROCDL::mfma_i32_32x32x16_i8::getOperationName();
978 if (m == 16 && n == 16 && k == 32 &&
b == 1 &&
979 target.has(llvm::AMDGPU::FEAT_GFX940_INSTS))
980 return ROCDL::mfma_i32_16x16x32_i8::getOperationName();
984 target.has(llvm::AMDGPU::FEAT_GFX90A_INSTS)) {
985 if (m == 16 && n == 16 && k == 4 &&
b == 1)
986 return ROCDL::mfma_f64_16x16x4f64::getOperationName();
987 if (m == 4 && n == 4 && k == 4 &&
b == 4)
988 return ROCDL::mfma_f64_4x4x4f64::getOperationName();
995 cast<VectorType>(mfma.getSourceB().getType()).getElementType();
996 if (m == 16 && n == 16 && k == 32 &&
b == 1) {
998 return ROCDL::mfma_f32_16x16x32_bf8_bf8::getOperationName();
1000 return ROCDL::mfma_f32_16x16x32_bf8_fp8::getOperationName();
1002 if (m == 32 && n == 32 && k == 16 &&
b == 1) {
1004 return ROCDL::mfma_f32_32x32x16_bf8_bf8::getOperationName();
1006 return ROCDL::mfma_f32_32x32x16_bf8_fp8::getOperationName();
1012 cast<VectorType>(mfma.getSourceB().getType()).getElementType();
1013 if (m == 16 && n == 16 && k == 32 &&
b == 1) {
1015 return ROCDL::mfma_f32_16x16x32_fp8_bf8::getOperationName();
1017 return ROCDL::mfma_f32_16x16x32_fp8_fp8::getOperationName();
1019 if (m == 32 && n == 32 && k == 16 &&
b == 1) {
1021 return ROCDL::mfma_f32_32x32x16_fp8_bf8::getOperationName();
1023 return ROCDL::mfma_f32_32x32x16_fp8_fp8::getOperationName();
1027 return std::nullopt;
1030static std::optional<ROCDL::MatrixFormat>
1034 .Case([](Float8E4M3FNType) {
return ROCDL::MatrixFormat::fp8_e4m3; })
1035 .Case([](Float8E5M2Type) {
return ROCDL::MatrixFormat::fp8_e5m2; })
1036 .Case([](Float6E2M3FNType) {
return ROCDL::MatrixFormat::fp6_e2m3; })
1037 .Case([](Float6E3M2FNType) {
return ROCDL::MatrixFormat::fp6_e3m2; })
1038 .Case([](Float4E2M1FNType) {
return ROCDL::MatrixFormat::fp4_e2m1; })
1039 .Default(std::nullopt);
1050 std::tuple<StringRef, ROCDL::MatrixFormat, ROCDL::MatrixFormat>;
1052static std::optional<ScaledMFMAIntrinsic>
1054 uint32_t n, uint32_t k, uint32_t
b,
1060 if (!
target.has(llvm::AMDGPU::FEAT_GFX950_INSTS))
1061 return std::nullopt;
1062 if (!isa<Float32Type>(destType))
1063 return std::nullopt;
1065 std::optional<ROCDL::MatrixFormat> aTypeCode =
1067 std::optional<ROCDL::MatrixFormat> bTypeCode =
1069 if (!aTypeCode || !bTypeCode)
1070 return std::nullopt;
1072 if (m == 32 && n == 32 && k == 64 &&
b == 1)
1073 return std::tuple{ROCDL::mfma_scale_f32_32x32x64_f8f6f4::getOperationName(),
1074 *aTypeCode, *bTypeCode};
1075 if (m == 16 && n == 16 && k == 128 &&
b == 1)
1077 ROCDL::mfma_scale_f32_16x16x128_f8f6f4::getOperationName(), *aTypeCode,
1080 return std::nullopt;
1083static std::optional<ScaledMFMAIntrinsic>
1086 mfma.getSourceA().getType(), mfma.getSourceB().getType(),
1087 mfma.getDestC().getType(), mfma.getM(), mfma.getN(), mfma.getK(),
1088 mfma.getBlocks(),
target);
1091static std::optional<ScaledMFMAIntrinsic>
1094 smfma.getSourceB().getType(),
1095 smfma.getDestC().getType(), smfma.getM(),
1096 smfma.getN(), smfma.getK(), 1u,
target);
1101static std::optional<StringRef>
1103 Type elemDestType, uint32_t k,
bool isRDNA3) {
1104 using fp8 = Float8E4M3FNType;
1105 using bf8 = Float8E5M2Type;
1110 if (elemSourceType.
isF16() && elemDestType.
isF32())
1111 return ROCDL::wmma_f32_16x16x16_f16::getOperationName();
1112 if (elemSourceType.
isBF16() && elemDestType.
isF32())
1113 return ROCDL::wmma_f32_16x16x16_bf16::getOperationName();
1114 if (elemSourceType.
isF16() && elemDestType.
isF16())
1115 return ROCDL::wmma_f16_16x16x16_f16::getOperationName();
1117 return ROCDL::wmma_bf16_16x16x16_bf16::getOperationName();
1119 return ROCDL::wmma_i32_16x16x16_iu8::getOperationName();
1124 return ROCDL::wmma_i32_16x16x16_iu4::getOperationName();
1125 return std::nullopt;
1129 if (isa<fp8>(elemSourceType) && isa<fp8>(elemBSourceType) &&
1130 elemDestType.
isF32())
1131 return ROCDL::wmma_f32_16x16x16_fp8_fp8::getOperationName();
1132 if (isa<fp8>(elemSourceType) && isa<bf8>(elemBSourceType) &&
1133 elemDestType.
isF32())
1134 return ROCDL::wmma_f32_16x16x16_fp8_bf8::getOperationName();
1135 if (isa<bf8>(elemSourceType) && isa<bf8>(elemBSourceType) &&
1136 elemDestType.
isF32())
1137 return ROCDL::wmma_f32_16x16x16_bf8_bf8::getOperationName();
1138 if (isa<bf8>(elemSourceType) && isa<fp8>(elemBSourceType) &&
1139 elemDestType.
isF32())
1140 return ROCDL::wmma_f32_16x16x16_bf8_fp8::getOperationName();
1142 return ROCDL::wmma_i32_16x16x16_iu4::getOperationName();
1144 return std::nullopt;
1148 if (k == 32 && !isRDNA3) {
1150 return ROCDL::wmma_i32_16x16x32_iu4::getOperationName();
1153 return std::nullopt;
1159 Type elemBSourceType,
1162 using fp8 = Float8E4M3FNType;
1163 using bf8 = Float8E5M2Type;
1166 if (elemSourceType.
isF32() && elemDestType.
isF32())
1167 return ROCDL::wmma_f32_16x16x4_f32::getOperationName();
1169 return std::nullopt;
1173 if (elemSourceType.
isF16() && elemDestType.
isF32())
1174 return ROCDL::wmma_f32_16x16x32_f16::getOperationName();
1175 if (elemSourceType.
isBF16() && elemDestType.
isF32())
1176 return ROCDL::wmma_f32_16x16x32_bf16::getOperationName();
1177 if (elemSourceType.
isF16() && elemDestType.
isF16())
1178 return ROCDL::wmma_f16_16x16x32_f16::getOperationName();
1180 return ROCDL::wmma_bf16_16x16x32_bf16::getOperationName();
1182 return std::nullopt;
1186 if (isa<fp8>(elemSourceType) && isa<fp8>(elemBSourceType)) {
1187 if (elemDestType.
isF32())
1188 return ROCDL::wmma_f32_16x16x64_fp8_fp8::getOperationName();
1189 if (elemDestType.
isF16())
1190 return ROCDL::wmma_f16_16x16x64_fp8_fp8::getOperationName();
1192 if (isa<fp8>(elemSourceType) && isa<bf8>(elemBSourceType)) {
1193 if (elemDestType.
isF32())
1194 return ROCDL::wmma_f32_16x16x64_fp8_bf8::getOperationName();
1195 if (elemDestType.
isF16())
1196 return ROCDL::wmma_f16_16x16x64_fp8_bf8::getOperationName();
1198 if (isa<bf8>(elemSourceType) && isa<bf8>(elemBSourceType)) {
1199 if (elemDestType.
isF32())
1200 return ROCDL::wmma_f32_16x16x64_bf8_bf8::getOperationName();
1201 if (elemDestType.
isF16())
1202 return ROCDL::wmma_f16_16x16x64_bf8_bf8::getOperationName();
1204 if (isa<bf8>(elemSourceType) && isa<fp8>(elemBSourceType)) {
1205 if (elemDestType.
isF32())
1206 return ROCDL::wmma_f32_16x16x64_bf8_fp8::getOperationName();
1207 if (elemDestType.
isF16())
1208 return ROCDL::wmma_f16_16x16x64_bf8_fp8::getOperationName();
1211 return ROCDL::wmma_i32_16x16x64_iu8::getOperationName();
1213 return std::nullopt;
1217 if (isa<fp8>(elemSourceType) && isa<fp8>(elemBSourceType)) {
1218 if (elemDestType.
isF32())
1219 return ROCDL::wmma_f32_16x16x128_fp8_fp8::getOperationName();
1220 if (elemDestType.
isF16())
1221 return ROCDL::wmma_f16_16x16x128_fp8_fp8::getOperationName();
1223 if (isa<fp8>(elemSourceType) && isa<bf8>(elemBSourceType)) {
1224 if (elemDestType.
isF32())
1225 return ROCDL::wmma_f32_16x16x128_fp8_bf8::getOperationName();
1226 if (elemDestType.
isF16())
1227 return ROCDL::wmma_f16_16x16x128_fp8_bf8::getOperationName();
1229 if (isa<bf8>(elemSourceType) && isa<bf8>(elemBSourceType)) {
1230 if (elemDestType.
isF32())
1231 return ROCDL::wmma_f32_16x16x128_bf8_bf8::getOperationName();
1232 if (elemDestType.
isF16())
1233 return ROCDL::wmma_f16_16x16x128_bf8_bf8::getOperationName();
1235 if (isa<bf8>(elemSourceType) && isa<fp8>(elemBSourceType)) {
1236 if (elemDestType.
isF32())
1237 return ROCDL::wmma_f32_16x16x128_bf8_fp8::getOperationName();
1238 if (elemDestType.
isF16())
1239 return ROCDL::wmma_f16_16x16x128_bf8_fp8::getOperationName();
1242 return std::nullopt;
1245 return std::nullopt;
1251static std::optional<StringRef>
1253 bool isGfx950 =
target.has(llvm::AMDGPU::FEAT_GFX950_INSTS);
1257 uint32_t m = op.getM(), n = op.getN(), k = op.getK();
1262 if (m == 16 && n == 16 && k == 32) {
1264 return ROCDL::smfmac_f32_16x16x32_f16::getOperationName();
1266 return ROCDL::smfmac_f32_16x16x32_bf16::getOperationName();
1269 if (m == 16 && n == 16 && k == 64) {
1272 return ROCDL::smfmac_f32_16x16x64_f16::getOperationName();
1274 return ROCDL::smfmac_f32_16x16x64_bf16::getOperationName();
1278 return ROCDL::smfmac_i32_16x16x64_i8::getOperationName();
1279 if (isFp8(sourceAElem) && isFp8(sourceBElem) && destElem.
isF32())
1280 return ROCDL::smfmac_f32_16x16x64_fp8_fp8::getOperationName();
1281 if (isFp8(sourceAElem) && isBf8(sourceBElem) && destElem.
isF32())
1282 return ROCDL::smfmac_f32_16x16x64_fp8_bf8::getOperationName();
1283 if (isBf8(sourceAElem) && isFp8(sourceBElem) && destElem.
isF32())
1284 return ROCDL::smfmac_f32_16x16x64_bf8_fp8::getOperationName();
1285 if (isBf8(sourceAElem) && isBf8(sourceBElem) && destElem.
isF32())
1286 return ROCDL::smfmac_f32_16x16x64_bf8_bf8::getOperationName();
1289 if (m == 16 && n == 16 && k == 128 && isGfx950) {
1292 return ROCDL::smfmac_i32_16x16x128_i8::getOperationName();
1293 if (isFp8(sourceAElem) && isFp8(sourceBElem) && destElem.
isF32())
1294 return ROCDL::smfmac_f32_16x16x128_fp8_fp8::getOperationName();
1295 if (isFp8(sourceAElem) && isBf8(sourceBElem) && destElem.
isF32())
1296 return ROCDL::smfmac_f32_16x16x128_fp8_bf8::getOperationName();
1297 if (isBf8(sourceAElem) && isFp8(sourceBElem) && destElem.
isF32())
1298 return ROCDL::smfmac_f32_16x16x128_bf8_fp8::getOperationName();
1299 if (isBf8(sourceAElem) && isBf8(sourceBElem) && destElem.
isF32())
1300 return ROCDL::smfmac_f32_16x16x128_bf8_bf8::getOperationName();
1303 if (m == 32 && n == 32 && k == 16) {
1305 return ROCDL::smfmac_f32_32x32x16_f16::getOperationName();
1307 return ROCDL::smfmac_f32_32x32x16_bf16::getOperationName();
1310 if (m == 32 && n == 32 && k == 32) {
1313 return ROCDL::smfmac_f32_32x32x32_f16::getOperationName();
1315 return ROCDL::smfmac_f32_32x32x32_bf16::getOperationName();
1319 return ROCDL::smfmac_i32_32x32x32_i8::getOperationName();
1320 if (isFp8(sourceAElem) && isFp8(sourceBElem) && destElem.
isF32())
1321 return ROCDL::smfmac_f32_32x32x32_fp8_fp8::getOperationName();
1322 if (isFp8(sourceAElem) && isBf8(sourceBElem) && destElem.
isF32())
1323 return ROCDL::smfmac_f32_32x32x32_fp8_bf8::getOperationName();
1324 if (isBf8(sourceAElem) && isFp8(sourceBElem) && destElem.
isF32())
1325 return ROCDL::smfmac_f32_32x32x32_bf8_fp8::getOperationName();
1326 if (isBf8(sourceAElem) && isBf8(sourceBElem) && destElem.
isF32())
1327 return ROCDL::smfmac_f32_32x32x32_bf8_bf8::getOperationName();
1330 if (m == 32 && n == 32 && k == 64 && isGfx950) {
1333 return ROCDL::smfmac_i32_32x32x64_i8::getOperationName();
1334 if (isFp8(sourceAElem) && isFp8(sourceBElem) && destElem.
isF32())
1335 return ROCDL::smfmac_f32_32x32x64_fp8_fp8::getOperationName();
1336 if (isFp8(sourceAElem) && isBf8(sourceBElem) && destElem.
isF32())
1337 return ROCDL::smfmac_f32_32x32x64_fp8_bf8::getOperationName();
1338 if (isBf8(sourceAElem) && isFp8(sourceBElem) && destElem.
isF32())
1339 return ROCDL::smfmac_f32_32x32x64_bf8_fp8::getOperationName();
1340 if (isBf8(sourceAElem) && isBf8(sourceBElem) && destElem.
isF32())
1341 return ROCDL::smfmac_f32_32x32x64_bf8_bf8::getOperationName();
1344 return std::nullopt;
1350static std::optional<StringRef>
1352 auto sourceVectorType = cast<VectorType>(wmma.getSourceA().getType());
1353 auto sourceBVectorType = cast<VectorType>(wmma.getSourceB().getType());
1354 auto destVectorType = cast<VectorType>(wmma.getDestC().getType());
1355 Type elemSourceType = sourceVectorType.getElementType();
1356 Type elemBSourceType = sourceBVectorType.getElementType();
1357 Type elemDestType = destVectorType.getElementType();
1359 const uint32_t k = wmma.getK();
1360 const bool isRDNA3 =
target.isGeneration(11);
1361 const bool isRDNA4 =
1362 target.isGeneration(12) && !
target.has(llvm::AMDGPU::FEAT_GFX1250_INSTS);
1365 if (isRDNA3 || isRDNA4)
1370 if (
target.has(llvm::AMDGPU::FEAT_GFX1250_INSTS))
1374 return std::nullopt;
1387static std::optional<SparseWMMAOpInfo>
1393 uint32_t m = swmmac.getM(), n = swmmac.getN(), k = swmmac.getK();
1395 if ((m != 16) || (n != 16))
1396 return std::nullopt;
1398 const bool isRDNA4 =
1399 target.isGeneration(12) && !
target.has(llvm::AMDGPU::FEAT_GFX1250_INSTS);
1404 ROCDL::swmmac_f32_16x16x32_f16::getOperationName(),
false,
false,
1408 ROCDL::swmmac_f32_16x16x32_bf16::getOperationName(),
false,
false,
1412 ROCDL::swmmac_f16_16x16x32_f16::getOperationName(),
false,
false,
1416 ROCDL::swmmac_bf16_16x16x32_bf16::getOperationName(),
false,
false,
1421 ROCDL::swmmac_i32_16x16x32_iu8::getOperationName(),
true,
false,
1426 ROCDL::swmmac_i32_16x16x32_iu4::getOperationName(),
true,
false,
1431 ROCDL::swmmac_f32_16x16x32_fp8_fp8::getOperationName(),
false,
1436 ROCDL::swmmac_f32_16x16x32_fp8_bf8::getOperationName(),
false,
1441 ROCDL::swmmac_f32_16x16x32_bf8_fp8::getOperationName(),
false,
1445 ROCDL::swmmac_f32_16x16x32_bf8_bf8::getOperationName(),
false,
1452 ROCDL::swmmac_i32_16x16x64_iu4::getOperationName(),
true,
false,
1457 const bool isGFX1250 =
target.has(llvm::AMDGPU::FEAT_GFX1250_INSTS);
1458 const bool isWavesize64 = swmmac.getWave64();
1459 if (isGFX1250 && !isWavesize64) {
1463 ROCDL::swmmac_f32_16x16x64_f16::getOperationName(),
true,
true,
1467 ROCDL::swmmac_f32_16x16x64_bf16::getOperationName(),
true,
true,
1471 ROCDL::swmmac_f16_16x16x64_f16::getOperationName(),
true,
true,
1475 ROCDL::swmmac_bf16_16x16x64_bf16::getOperationName(),
true,
true,
1482 ROCDL::swmmac_f32_16x16x128_fp8_fp8::getOperationName(),
false,
1487 ROCDL::swmmac_f32_16x16x128_fp8_bf8::getOperationName(),
false,
1492 ROCDL::swmmac_f32_16x16x128_bf8_fp8::getOperationName(),
false,
1496 ROCDL::swmmac_f32_16x16x128_bf8_bf8::getOperationName(),
false,
1501 ROCDL::swmmac_f16_16x16x128_fp8_fp8::getOperationName(),
false,
1506 ROCDL::swmmac_f16_16x16x128_fp8_bf8::getOperationName(),
false,
1511 ROCDL::swmmac_f16_16x16x128_bf8_fp8::getOperationName(),
false,
1515 ROCDL::swmmac_f16_16x16x128_bf8_bf8::getOperationName(),
false,
1520 ROCDL::swmmac_f16_16x16x128_bf8_bf8::getOperationName(),
false,
1525 ROCDL::swmmac_i32_16x16x128_iu8::getOperationName(),
true,
true,
1530 return std::nullopt;
1535 MFMAOpLowering(
const LLVMTypeConverter &converter,
1536 const ROCDL::TargetInfo &target)
1537 : ConvertOpToLLVMPattern<MFMAOp>(converter), target(target) {}
1539 ROCDL::TargetInfo target;
1542 matchAndRewrite(MFMAOp op, MFMAOpAdaptor adaptor,
1543 ConversionPatternRewriter &rewriter)
const override {
1544 Location loc = op.getLoc();
1546 Type outType = typeConverter->convertType(op.getDestD().getType());
1547 Type intrinsicOutType = outType;
1548 if (
auto outVecType = dyn_cast<VectorType>(outType))
1549 if (outVecType.getElementType().isBF16())
1550 intrinsicOutType = outVecType.clone(rewriter.getI16Type());
1552 if (!target.has(llvm::AMDGPU::FEAT_MAI_INSTS))
1553 return op->emitOpError(
"MFMA only supported on gfx908+");
1554 uint32_t getBlgpField =
static_cast<uint32_t
>(op.getBlgp());
1555 if (op.getNegateA() || op.getNegateB() || op.getNegateC()) {
1556 if (!target.has(llvm::AMDGPU::FEAT_GFX940_INSTS))
1557 return op.emitOpError(
"negation unsupported on older than gfx942");
1559 op.getNegateA() | (op.getNegateB() << 1) | (op.getNegateC() << 2);
1562 std::optional<ScaledMFMAIntrinsic> maybeScaledIntrinsic =
1564 if (!maybeIntrinsic.has_value() && !maybeScaledIntrinsic.has_value())
1565 return op.emitOpError(
"no intrinsic matching MFMA size on given chipset");
1568 !maybeIntrinsic.has_value() && maybeScaledIntrinsic.has_value();
1570 (adaptor.getAbid() > 0 || getBlgpField > 0 || op.getCbsz() > 0)) {
1571 return op.emitOpError(
1572 "non-default abid, blgp, and cbsz aren't supported on MFMAs that can "
1573 "be scaled as those fields are used for type information");
1576 StringRef intrinsicName =
1577 isScaled ? std::get<0>(*maybeScaledIntrinsic) : *maybeIntrinsic;
1580 bool allowBf16 = [&]() {
1581 if (!target.has(llvm::AMDGPU::FEAT_GFX950_INSTS))
1585 return intrinsicName.contains(
"16x16x32.bf16") ||
1586 intrinsicName.contains(
"32x32x16.bf16");
1588 OperationState loweredOp(loc, intrinsicName);
1589 loweredOp.addTypes(intrinsicOutType);
1591 rewriter, loc, adaptor.getSourceA(), allowBf16),
1593 rewriter, loc, adaptor.getSourceB(), allowBf16),
1594 adaptor.getDestC()});
1597 auto [_scaledName, aTypeCode, bTypeCode] = *maybeScaledIntrinsic;
1598 loweredOp.addOperands({zero, zero});
1599 loweredOp.addAttributes(
1601 ROCDL::MatrixFormatAttr::get(rewriter.getContext(), aTypeCode)},
1603 ROCDL::MatrixFormatAttr::get(rewriter.getContext(), bTypeCode)},
1604 {
"opselA", rewriter.getI32IntegerAttr(0)},
1605 {
"opselB", rewriter.getI32IntegerAttr(0)}});
1607 Attribute blgpAttr =
1609 ? Attribute(ROCDL::MFMANegModifierAttr::get(
1610 rewriter.getContext(),
1611 static_cast<ROCDL::MFMANegModifier
>(getBlgpField)))
1612 : Attribute(ROCDL::MFMAPermBAttr::
get(
1614 static_cast<ROCDL::MFMAPermB>(getBlgpField)));
1615 loweredOp.addAttributes(
1616 {{
"cbsz", rewriter.getI32IntegerAttr(op.getCbsz())},
1617 {
"abid", rewriter.getI32IntegerAttr(op.getAbid())},
1618 {
"blgp", blgpAttr}});
1620 Value lowered = rewriter.create(loweredOp)->getResult(0);
1621 if (outType != intrinsicOutType)
1622 lowered = LLVM::BitcastOp::create(rewriter, loc, outType, lowered);
1623 rewriter.replaceOp(op, lowered);
1629 ScaledMFMAOpLowering(
const LLVMTypeConverter &converter,
1630 const ROCDL::TargetInfo &target)
1631 : ConvertOpToLLVMPattern(converter), target(target) {}
1633 ROCDL::TargetInfo target;
1636 matchAndRewrite(ScaledMFMAOp op, ScaledMFMAOpAdaptor adaptor,
1637 ConversionPatternRewriter &rewriter)
const override {
1638 Location loc = op.getLoc();
1639 Type intrinsicOutType = typeConverter->convertType(op.getDestD().getType());
1641 if (!target.has(llvm::AMDGPU::FEAT_GFX950_INSTS))
1642 return op->emitOpError(
"scaled MFMA only supported on gfx908+");
1643 std::optional<ScaledMFMAIntrinsic> maybeScaledIntrinsic =
1645 if (!maybeScaledIntrinsic.has_value())
1646 return op.emitOpError(
1647 "no intrinsic matching scaled MFMA size on given chipset");
1649 auto [intrinsicName, aTypeCode, bTypeCode] = *maybeScaledIntrinsic;
1650 OperationState loweredOp(loc, intrinsicName);
1651 loweredOp.addTypes(intrinsicOutType);
1652 loweredOp.addOperands(
1655 adaptor.getDestC()});
1656 loweredOp.addOperands(
1661 loweredOp.addAttributes(
1663 ROCDL::MatrixFormatAttr::get(rewriter.getContext(), aTypeCode)},
1665 ROCDL::MatrixFormatAttr::get(rewriter.getContext(), bTypeCode)},
1666 {
"opselA", rewriter.getI32IntegerAttr(adaptor.getScalesIdxA())},
1667 {
"opselB", rewriter.getI32IntegerAttr(adaptor.getScalesIdxB())}});
1669 Value lowered = rewriter.create(loweredOp)->getResult(0);
1670 rewriter.replaceOp(op, lowered);
1676 SparseMFMAOpLowering(
const LLVMTypeConverter &converter,
1677 const ROCDL::TargetInfo &target)
1678 : ConvertOpToLLVMPattern<SparseMFMAOp>(converter), target(target) {}
1680 ROCDL::TargetInfo target;
1683 matchAndRewrite(SparseMFMAOp op, SparseMFMAOpAdaptor adaptor,
1684 ConversionPatternRewriter &rewriter)
const override {
1685 Location loc = op.getLoc();
1687 typeConverter->convertType<VectorType>(op.getDestC().
getType());
1689 return rewriter.notifyMatchFailure(op,
"type conversion failed");
1692 if (!target.has(llvm::AMDGPU::FEAT_GFX940_INSTS))
1693 return op->emitOpError(
"sparse MFMA (smfmac) only supported on gfx942+");
1696 if (!maybeIntrinsic.has_value())
1697 return op.emitOpError(
1698 "no intrinsic matching sparse MFMA on the given chipset");
1701 ROCDL::smfmac_f32_16x16x32_bf16::getOperationName() ||
1703 ROCDL::smfmac_f32_32x32x16_bf16::getOperationName());
1705 (target.has(llvm::AMDGPU::FEAT_GFX950_INSTS)) && !isGfx942BF16;
1711 Value c = adaptor.getDestC();
1715 Value sparseIdx = adaptor.getSparseIdx();
1716 Type i32Type = rewriter.getI32Type();
1717 if (sparseIdx.
getType() != i32Type)
1718 sparseIdx = LLVM::BitcastOp::create(rewriter, loc, i32Type, sparseIdx);
1720 OperationState loweredOp(loc, maybeIntrinsic.value());
1721 loweredOp.addTypes(outType);
1722 loweredOp.addOperands({a,
b, c, sparseIdx});
1723 loweredOp.addAttributes(
1724 {{
"cbsz", rewriter.getI32IntegerAttr(op.getCbsz())},
1725 {
"abid", rewriter.getI32IntegerAttr(op.getAbid())}});
1726 Value lowered = rewriter.create(loweredOp)->getResult(0);
1727 rewriter.replaceOp(op, lowered);
1733 WMMAOpLowering(
const LLVMTypeConverter &converter,
1734 const ROCDL::TargetInfo &target)
1735 : ConvertOpToLLVMPattern<WMMAOp>(converter), target(target) {}
1737 ROCDL::TargetInfo target;
1740 matchAndRewrite(WMMAOp op, WMMAOpAdaptor adaptor,
1741 ConversionPatternRewriter &rewriter)
const override {
1742 Location loc = op.getLoc();
1744 typeConverter->convertType<VectorType>(op.getDestD().
getType());
1746 return rewriter.notifyMatchFailure(op,
"type conversion failed");
1748 if (!target.isGeneration(11) && !target.isGeneration(12))
1749 return op->emitOpError(
"WMMA only supported on gfx11 and gfx12");
1751 bool isGFX1250 = target.has(llvm::AMDGPU::FEAT_GFX1250_INSTS);
1756 auto aType = cast<VectorType>(adaptor.getSourceA().getType());
1757 auto bType = cast<VectorType>(adaptor.getSourceB().getType());
1758 auto destCType = cast<VectorType>(adaptor.getDestC().getType());
1759 bool castAToI16 = aType.getElementType().isBF16() && !isGFX1250;
1760 bool castBToI16 = bType.getElementType().isBF16() && !isGFX1250;
1761 bool castDestCToI16 = destCType.getElementType().isBF16() && !isGFX1250;
1762 bool castOutToI16 = outType.getElementType().
isBF16() && !isGFX1250;
1763 VectorType rawOutType = outType;
1765 rawOutType = outType.clone(rewriter.getI16Type());
1766 Value a = adaptor.getSourceA();
1768 a = LLVM::BitcastOp::create(rewriter, loc,
1769 aType.clone(rewriter.getI16Type()), a);
1770 Value
b = adaptor.getSourceB();
1772 b = LLVM::BitcastOp::create(rewriter, loc,
1773 bType.clone(rewriter.getI16Type()),
b);
1774 Value destC = adaptor.getDestC();
1776 destC = LLVM::BitcastOp::create(
1777 rewriter, loc, destCType.clone(rewriter.getI16Type()), destC);
1781 if (!maybeIntrinsic.has_value())
1782 return op.emitOpError(
"no intrinsic matching WMMA on the given chipset");
1784 if (target.has(llvm::AMDGPU::FEAT_GFX12_INSTS) &&
1785 op.getSubwordOffset() != 0)
1786 return op.emitOpError(
"subwordOffset not supported on gfx12+");
1788 SmallVector<Value, 4> operands;
1789 SmallVector<NamedAttribute, 4> attrs;
1791 op.getSourceA(), operands, attrs,
"signA");
1793 op.getSourceB(), operands, attrs,
"signB");
1795 op.getSubwordOffset(), op.getClamp(), operands,
1798 OperationState loweredOp(loc, *maybeIntrinsic);
1799 loweredOp.addTypes(rawOutType);
1800 loweredOp.addOperands(operands);
1801 loweredOp.addAttributes(attrs);
1802 Operation *lowered = rewriter.create(loweredOp);
1804 Operation *maybeCastBack = lowered;
1805 if (rawOutType != outType)
1806 maybeCastBack = LLVM::BitcastOp::create(rewriter, loc, outType,
1808 rewriter.replaceOp(op, maybeCastBack->
getResults());
1814enum class DotFamily {
1823static std::optional<std::pair<StringRef, DotFamily>>
1825 Type aElem = cast<VectorType>(op.getSourceA().getType()).getElementType();
1826 Type bElem = cast<VectorType>(op.getSourceB().getType()).getElementType();
1827 Type dest = op.getDestC().getType();
1828 bool uA = op.getUnsignedA();
1829 bool uB = op.getUnsignedB();
1833 if (dest.
isF32() &&
target.has(llvm::AMDGPU::FEAT_DOT10_INSTS))
1834 return {{ROCDL::fdot2::getOperationName(), DotFamily::Clamp}};
1835 if (dest.
isF16() &&
target.has(llvm::AMDGPU::FEAT_DOT9_INSTS))
1836 return {{ROCDL::fdot2_f16_f16::getOperationName(), DotFamily::NoClamp}};
1837 return std::nullopt;
1842 if (dest.
isF32() &&
target.has(llvm::AMDGPU::FEAT_DOT12_INSTS))
1843 return {{ROCDL::fdot2_f32_bf16::getOperationName(), DotFamily::Clamp}};
1844 if (dest.
isBF16() &&
target.has(llvm::AMDGPU::FEAT_DOT9_INSTS))
1845 return {{ROCDL::fdot2_bf16_bf16::getOperationName(), DotFamily::NoClamp}};
1846 return std::nullopt;
1850 if (isa<IntegerType>(aElem) && isa<IntegerType>(bElem) &&
1852 bool mixedSign = (uA != uB);
1856 if (!
target.has(llvm::AMDGPU::FEAT_DOT8_INSTS))
1857 return std::nullopt;
1859 switch (elemWidth) {
1861 name = ROCDL::sudot4::getOperationName();
1864 name = ROCDL::sudot8::getOperationName();
1867 return std::nullopt;
1869 return {{name, DotFamily::Sudot}};
1873 bool supported =
false;
1874 switch (elemWidth) {
1876 supported =
target.has(llvm::AMDGPU::FEAT_DOT2_INSTS);
1877 name = uA ? ROCDL::udot2::getOperationName()
1878 :
ROCDL::sdot2::getOperationName();
1881 supported = uA ?
target.has(llvm::AMDGPU::FEAT_DOT7_INSTS)
1882 :
target.has(llvm::AMDGPU::FEAT_DOT1_INSTS) ||
1883 target.has(llvm::AMDGPU::FEAT_DOT8_INSTS);
1884 name = uA ? ROCDL::udot4::getOperationName()
1885 : ROCDL::sdot4::getOperationName();
1888 supported = uA ?
target.has(llvm::AMDGPU::FEAT_DOT7_INSTS)
1889 :
target.has(llvm::AMDGPU::FEAT_DOT1_INSTS) ||
1890 target.has(llvm::AMDGPU::FEAT_DOT8_INSTS);
1891 name = uA ? ROCDL::udot8::getOperationName()
1892 : ROCDL::sdot8::getOperationName();
1895 return std::nullopt;
1898 return std::nullopt;
1899 return {{name, DotFamily::Clamp}};
1903 bool aIsFp8 = isa<Float8E4M3FNType>(aElem);
1904 bool aIsBf8 = isa<Float8E5M2Type>(aElem);
1905 bool bIsFp8 = isa<Float8E4M3FNType>(bElem);
1906 bool bIsBf8 = isa<Float8E5M2Type>(bElem);
1907 if ((aIsFp8 || aIsBf8) && (bIsFp8 || bIsBf8) && dest.
isF32()) {
1908 if (!
target.has(llvm::AMDGPU::FEAT_DOT11_INSTS))
1909 return std::nullopt;
1911 if (aIsFp8 && bIsFp8)
1912 name = ROCDL::dot4_f32_fp8_fp8::getOperationName();
1913 else if (aIsFp8 && bIsBf8)
1914 name = ROCDL::dot4_f32_fp8_bf8::getOperationName();
1915 else if (aIsBf8 && bIsFp8)
1916 name = ROCDL::dot4_f32_bf8_fp8::getOperationName();
1918 name = ROCDL::dot4_f32_bf8_bf8::getOperationName();
1919 return {{name, DotFamily::NoClamp}};
1922 return std::nullopt;
1926 DotOpLowering(
const LLVMTypeConverter &converter,
1927 const ROCDL::TargetInfo &target)
1928 : ConvertOpToLLVMPattern<DotOp>(converter), target(target) {}
1930 ROCDL::TargetInfo target;
1933 matchAndRewrite(DotOp op, DotOpAdaptor adaptor,
1934 ConversionPatternRewriter &rewriter)
const override {
1935 Location loc = op.getLoc();
1937 std::optional<std::pair<StringRef, DotFamily>> maybeIntrinsic =
1938 dotOpToIntrinsic(op, target);
1939 if (!maybeIntrinsic)
1940 return op.emitOpError(
"no intrinsic matching dot on the given chipset: ")
1941 << op.getSourceA().getType() <<
" * " << op.getSourceB().getType()
1942 <<
" + " << op.getDestC().getType();
1944 auto [intrinsicName, family] = maybeIntrinsic.value();
1948 Value c = adaptor.getDestC();
1950 SmallVector<NamedAttribute, 3> attrs;
1951 if (family == DotFamily::Sudot) {
1952 attrs.push_back(rewriter.getNamedAttr(
1953 "signA", rewriter.getBoolAttr(!op.getUnsignedA())));
1954 attrs.push_back(rewriter.getNamedAttr(
1955 "signB", rewriter.getBoolAttr(!op.getUnsignedB())));
1958 if (family != DotFamily::NoClamp && op.getClamp())
1960 rewriter.getNamedAttr(
"clamp", rewriter.getBoolAttr(
true)));
1962 Type resultType = typeConverter->convertType(op.getDestD().getType());
1964 OperationState loweredOp(loc, intrinsicName);
1965 loweredOp.addTypes(resultType);
1966 loweredOp.addOperands({a,
b, c});
1967 loweredOp.addAttributes(attrs);
1968 Operation *lowered = rewriter.create(loweredOp);
1969 rewriter.replaceOp(op, lowered->
getResults());
1975 SparseWMMAOpLowering(
const LLVMTypeConverter &converter,
1976 const ROCDL::TargetInfo &target)
1977 : ConvertOpToLLVMPattern<SparseWMMAOp>(converter), target(target) {}
1979 ROCDL::TargetInfo target;
1982 matchAndRewrite(SparseWMMAOp op, SparseWMMAOpAdaptor adaptor,
1983 ConversionPatternRewriter &rewriter)
const override {
1984 Location loc = op.getLoc();
1986 typeConverter->convertType<VectorType>(op.getDestD().
getType());
1988 return rewriter.notifyMatchFailure(op,
"type conversion failed");
1990 std::optional<SparseWMMAOpInfo> maybeIntrinsic =
1993 if (!maybeIntrinsic.has_value())
1994 return op.emitOpError(
1995 "no intrinsic matching Sparse WMMA on the given chipset");
1996 SparseWMMAOpInfo intrinsic = maybeIntrinsic.value();
1998 SmallVector<NamedAttribute> attrs;
2000 if ((op.getUnsignedA() || op.getUnsignedB()) && !intrinsic.
useSign)
2001 return op->emitOpError(
"intrinsic doesn't support unsign");
2003 if (
auto attr = op.getUnsignedAAttr())
2004 attrs.push_back({
"signA", attr});
2005 if (
auto attr = op.getUnsignedBAttr())
2006 attrs.push_back({
"signB", attr});
2009 if ((op.getReuseA() || op.getReuseB()) && !intrinsic.
useReuse)
2010 return op->emitOpError(
"intrinsic doesn't support reuse");
2012 if (
auto attr = op.getReuseAAttr())
2013 attrs.push_back({
"reuseA", attr});
2014 if (
auto attr = op.getReuseBAttr())
2015 attrs.push_back({
"reuseB", attr});
2018 if (op.getClamp() && !intrinsic.
useClamp)
2019 return op->emitOpError(
"intrinsic doesn't support clamp");
2020 if (intrinsic.
useClamp && op.getClampAttr())
2021 attrs.push_back({
"clamp", op.getClampAttr()});
2023 const bool isGFX1250orHigher = target.has(llvm::AMDGPU::FEAT_GFX1250_INSTS);
2028 Value c = adaptor.getDestC();
2029 VectorType rawOutType = outType;
2030 if (!isGFX1250orHigher) {
2032 rawOutType = cast<VectorType>(c.
getType());
2036 Value sparseIdx = LLVM::BitcastOp::create(
2037 rewriter, loc, rewriter.getI32Type(), adaptor.getSparseIdx());
2039 OperationState loweredOp(loc, intrinsic.
name);
2040 loweredOp.addTypes(rawOutType);
2041 loweredOp.addOperands({a,
b, c, sparseIdx});
2042 loweredOp.addAttributes(attrs);
2043 Operation *lowered = rewriter.create(loweredOp);
2045 Operation *maybeCastBack = lowered;
2046 if (rawOutType != outType)
2047 maybeCastBack = LLVM::BitcastOp::create(rewriter, loc, outType,
2049 rewriter.replaceOp(op, maybeCastBack->
getResults());
2056 ScaledWMMAOpLowering(
const LLVMTypeConverter &converter,
2057 const ROCDL::TargetInfo &target)
2058 : ConvertOpToLLVMPattern<ScaledWMMAOp>(converter), target(target) {}
2060 ROCDL::TargetInfo target;
2063 matchAndRewrite(ScaledWMMAOp op, ScaledWMMAOpAdaptor adaptor,
2064 ConversionPatternRewriter &rewriter)
const override {
2065 Location loc = op.getLoc();
2067 typeConverter->convertType<VectorType>(op.getDestD().
getType());
2069 return rewriter.notifyMatchFailure(op,
"type conversion failed");
2071 if (!target.has(llvm::AMDGPU::FEAT_GFX1250_INSTS))
2072 return op->emitOpError(
"WMMA scale only supported on gfx1250+");
2074 int64_t m = op.getM();
2075 int64_t n = op.getN();
2076 int64_t k = op.getK();
2081 std::optional<ROCDL::MatrixFormat> aFmtCode =
2083 std::optional<ROCDL::MatrixFormat> bFmtCode =
2086 if (!aFmtCode || !bFmtCode)
2087 return op.emitOpError(
"unsupported element types for scaled_wmma");
2090 auto scaleAVecType = cast<VectorType>(op.getScaleA().getType());
2091 auto scaleBVecType = cast<VectorType>(op.getScaleB().getType());
2093 if (scaleAVecType.getNumElements() != scaleBVecType.getNumElements())
2094 return op.emitOpError(
"scaleA and scaleB must have equal vector length");
2097 Type scaleAElemType = scaleAVecType.getElementType();
2098 Type scaleBElemType = scaleBVecType.getElementType();
2100 std::optional<ROCDL::WMMAMatrixScaleFormat> scaleAFmt =
2102 std::optional<ROCDL::WMMAMatrixScaleFormat> scaleBFmt =
2105 if (!scaleAFmt || !scaleBFmt)
2106 return op.emitOpError(
"unsupported scale element types");
2109 bool isScale16 = (scaleAVecType.getNumElements() == 8);
2110 std::optional<StringRef> intrinsicName =
2113 return op.emitOpError(
"unsupported scaled_wmma dimensions: ")
2114 << m <<
"x" << n <<
"x" << k;
2116 SmallVector<NamedAttribute, 8> attrs;
2119 bool is32x16 = (m == 32 && n == 16 && k == 128);
2121 attrs.emplace_back(
"fmtA", ROCDL::MatrixFormatAttr::get(
2122 rewriter.getContext(), *aFmtCode));
2123 attrs.emplace_back(
"fmtB", ROCDL::MatrixFormatAttr::get(
2124 rewriter.getContext(), *bFmtCode));
2129 "modC", ROCDL::WMMACModifierAttr::get(rewriter.getContext(),
2130 ROCDL::WMMACModifier::none));
2134 attrs.emplace_back(
"scaleAType", ROCDL::WMMAMatrixScaleAttr::get(
2135 rewriter.getContext(),
2136 static_cast<ROCDL::WMMAMatrixScale
>(
2137 op.getAFirstScaleLane() / 16)));
2138 attrs.emplace_back(
"fmtScaleA", ROCDL::WMMAMatrixScaleFormatAttr::get(
2139 rewriter.getContext(), *scaleAFmt));
2140 attrs.emplace_back(
"scaleBType", ROCDL::WMMAMatrixScaleAttr::get(
2141 rewriter.getContext(),
2142 static_cast<ROCDL::WMMAMatrixScale
>(
2143 op.getBFirstScaleLane() / 16)));
2144 attrs.emplace_back(
"fmtScaleB", ROCDL::WMMAMatrixScaleFormatAttr::get(
2145 rewriter.getContext(), *scaleBFmt));
2148 attrs.emplace_back(
"reuseA", rewriter.getBoolAttr(
false));
2149 attrs.emplace_back(
"reuseB", rewriter.getBoolAttr(
false));
2162 OperationState loweredOp(loc, *intrinsicName);
2163 loweredOp.addTypes(outType);
2164 loweredOp.addOperands(
2165 {sourceA, sourceB, adaptor.getDestC(), packedScaleA, packedScaleB});
2166 loweredOp.addAttributes(attrs);
2168 Operation *lowered = rewriter.create(loweredOp);
2169 rewriter.replaceOp(op, lowered->
getResults());
2175struct TransposeLoadOpLowering
2177 TransposeLoadOpLowering(
const LLVMTypeConverter &converter,
2178 const ROCDL::TargetInfo &target)
2179 : ConvertOpToLLVMPattern<TransposeLoadOp>(converter), target(target) {}
2181 ROCDL::TargetInfo target;
2184 matchAndRewrite(TransposeLoadOp op, TransposeLoadOpAdaptor adaptor,
2185 ConversionPatternRewriter &rewriter)
const override {
2186 if (!target.has(llvm::AMDGPU::FEAT_GFX950_INSTS) &&
2187 !target.has(llvm::AMDGPU::FEAT_GFX1250_INSTS))
2188 return op.emitOpError(
2189 "transpose_load is only supported on gfx950 and gfx1250+");
2191 Location loc = op.getLoc();
2192 auto srcMemRefType = cast<MemRefType>(op.getSrc().getType());
2196 size_t srcElementSize =
2197 srcMemRefType.getElementType().getIntOrFloatBitWidth();
2198 if (srcElementSize < 8)
2199 return op.emitOpError(
"Expect source memref to have at least 8 bits "
2200 "element size, got ")
2203 auto resultType = cast<VectorType>(op.getResult().getType());
2206 (adaptor.getSrcIndices()));
2208 size_t numElements = resultType.getNumElements();
2209 size_t elementTypeSize =
2212 Type llvmResultType = typeConverter->convertType(resultType);
2215 Type rocdlResultType =
2216 elementTypeSize < 16
2217 ? VectorType::get((numElements * elementTypeSize) / 32,
2218 rewriter.getIntegerType(32))
2221 auto emitNumElementsError = [&](
size_t expected, StringRef chipsetName) {
2222 return op.emitOpError()
2223 << elementTypeSize <<
"-bit transpose_load requires " << expected
2224 <<
" elements on " << chipsetName;
2228 if (target.has(llvm::AMDGPU::FEAT_GFX1250_INSTS)) {
2229 switch (elementTypeSize) {
2231 if (numElements != 16)
2232 return emitNumElementsError(16,
"gfx1250+");
2234 ROCDL::DsLoadTr4_B64::create(rewriter, loc, rocdlResultType, srcPtr,
2241 if (numElements != 16)
2242 return emitNumElementsError(16,
"gfx1250+");
2244 ROCDL::DsLoadTr6_B96::create(rewriter, loc, rocdlResultType, srcPtr,
2251 if (numElements != 8)
2252 return emitNumElementsError(8,
"gfx1250+");
2254 ROCDL::DsLoadTr8_B64::create(rewriter, loc, rocdlResultType, srcPtr,
2261 if (numElements != 8)
2262 return emitNumElementsError(8,
"gfx1250+");
2263 intrinsic = ROCDL::DsLoadTr16_B128::create(
2264 rewriter, loc, rocdlResultType, srcPtr,
2270 return op.emitOpError(
"Unsupported element size for transpose load");
2273 switch (elementTypeSize) {
2275 if (numElements != 16)
2276 return emitNumElementsError(16,
"gfx950");
2277 intrinsic = ROCDL::ds_read_tr4_b64::create(
2278 rewriter, loc, rocdlResultType, srcPtr,
2284 if (numElements != 16)
2285 return emitNumElementsError(16,
"gfx950");
2286 intrinsic = ROCDL::ds_read_tr6_b96::create(
2287 rewriter, loc, rocdlResultType, srcPtr,
2293 if (numElements != 8)
2294 return emitNumElementsError(8,
"gfx950");
2295 intrinsic = ROCDL::ds_read_tr8_b64::create(
2296 rewriter, loc, rocdlResultType, srcPtr,
2302 if (numElements != 4)
2303 return emitNumElementsError(4,
"gfx950");
2304 intrinsic = ROCDL::ds_read_tr16_b64::create(
2305 rewriter, loc, rocdlResultType, srcPtr,
2311 return op.emitOpError(
"Unsupported element size for transpose load");
2315 assert(intrinsic &&
"expected ROCDL transpose load intrinsic");
2316 if (intrinsic.
getType() == llvmResultType) {
2317 rewriter.replaceOp(op, intrinsic);
2320 rewriter.replaceOpWithNewOp<LLVM::BitcastOp>(op, llvmResultType, intrinsic);
2325struct GlobalTransposeLoadOpLowering
2327 GlobalTransposeLoadOpLowering(
const LLVMTypeConverter &converter,
2328 const ROCDL::TargetInfo &target)
2329 : ConvertOpToLLVMPattern<GlobalTransposeLoadOp>(converter),
2332 ROCDL::TargetInfo target;
2335 matchAndRewrite(GlobalTransposeLoadOp op,
2336 GlobalTransposeLoadOpAdaptor adaptor,
2337 ConversionPatternRewriter &rewriter)
const override {
2338 if (!target.has(llvm::AMDGPU::FEAT_GFX12_INSTS))
2339 return op.emitOpError(
2340 "global_transpose_load is only supported on gfx1200+");
2342 Location loc = op.getLoc();
2343 auto srcMemRefType = cast<MemRefType>(op.getSrc().getType());
2344 auto resultType = cast<VectorType>(op.getResult().getType());
2347 rewriter, loc, srcMemRefType, adaptor.getSrc(), adaptor.getSrcIndices(),
2348 LLVM::GEPNoWrapFlags::inbounds | LLVM::GEPNoWrapFlags::nuw);
2350 size_t numElements = resultType.getNumElements();
2351 size_t elementTypeSize =
2356 Type rocdlResultType =
2357 elementTypeSize < 16
2358 ? VectorType::get((numElements * elementTypeSize) / 32,
2359 rewriter.getIntegerType(32))
2360 : typeConverter->convertType(resultType);
2361 Type llvmResultType = typeConverter->convertType(resultType);
2363 switch (elementTypeSize) {
2365 assert(numElements == 16);
2366 if (!target.has(llvm::AMDGPU::FEAT_GFX1250_INSTS))
2367 return op.emitOpError(
"4-bit global_transpose_load requires gfx1250+");
2368 auto rocdlOp = ROCDL::GlobalLoadTr4_B64::create(
2371 rewriter.replaceOpWithNewOp<LLVM::BitcastOp>(op, llvmResultType, rocdlOp);
2375 assert(numElements == 16);
2376 if (!target.has(llvm::AMDGPU::FEAT_GFX1250_INSTS))
2377 return op.emitOpError(
"6-bit global_transpose_load requires gfx1250+");
2378 auto rocdlOp = ROCDL::GlobalLoadTr6_B96::create(
2381 rewriter.replaceOpWithNewOp<LLVM::BitcastOp>(op, llvmResultType, rocdlOp);
2385 assert(numElements == 8);
2386 auto rocdlOp = ROCDL::GlobalLoadTr8_B64::create(
2389 rewriter.replaceOpWithNewOp<LLVM::BitcastOp>(op, llvmResultType, rocdlOp);
2393 assert(numElements == 8);
2394 rewriter.replaceOpWithNewOp<ROCDL::GlobalLoadTr8_B128>(
2399 return op.emitOpError(
2400 "unsupported element size for global transpose load");
2407 GatherToLDSOpLowering(
const LLVMTypeConverter &converter,
2408 const ROCDL::TargetInfo &target)
2409 : ConvertOpToLLVMPattern<GatherToLDSOp>(converter), target(target) {}
2411 ROCDL::TargetInfo target;
2414 matchAndRewrite(GatherToLDSOp op, GatherToLDSOpAdaptor adaptor,
2415 ConversionPatternRewriter &rewriter)
const override {
2416 if (!target.has(llvm::AMDGPU::FEAT_VMEM_TO_LDS_LOAD_INSTS))
2417 return op.emitOpError(
"pre-gfx9 and post-gfx10 not supported");
2419 Location loc = op.getLoc();
2421 auto srcMemRefType = cast<MemRefType>(op.getSrc().getType());
2422 auto dstMemRefType = cast<MemRefType>(op.getDst().getType());
2427 Type transferType = op.getTransferType();
2428 int loadWidth = [&]() ->
int {
2429 if (
auto transferVectorType = dyn_cast<VectorType>(transferType)) {
2430 return (transferVectorType.getNumElements() *
2431 transferVectorType.getElementTypeBitWidth()) /
2438 if (!llvm::is_contained({1, 2, 4, 12, 16}, loadWidth))
2439 return op.emitOpError(
"chipset unsupported element size");
2441 if (!target.has(llvm::AMDGPU::FEAT_GFX950_INSTS) &&
2442 llvm::is_contained({12, 16}, loadWidth))
2443 return op.emitOpError(
"Gather to LDS instructions with 12-byte and "
2444 "16-byte load widths are only supported on gfx950");
2448 (adaptor.getSrcIndices()));
2451 (adaptor.getDstIndices()));
2453 if (op.getAsync()) {
2454 rewriter.replaceOpWithNewOp<ROCDL::LoadAsyncToLDSOp>(
2455 op, srcPtr, dstPtr, rewriter.getI32IntegerAttr(loadWidth),
2456 rewriter.getI32IntegerAttr(0),
2460 rewriter.replaceOpWithNewOp<ROCDL::LoadToLDSOp>(
2461 op, srcPtr, dstPtr, rewriter.getI32IntegerAttr(loadWidth),
2462 rewriter.getI32IntegerAttr(0),
2471struct GlobalLoadAsyncToLDSOpLowering
2473 GlobalLoadAsyncToLDSOpLowering(
const LLVMTypeConverter &converter,
2474 const ROCDL::TargetInfo &target)
2475 : ConvertOpToLLVMPattern<GlobalLoadAsyncToLDSOp>(converter),
2478 ROCDL::TargetInfo target;
2481 matchAndRewrite(GlobalLoadAsyncToLDSOp op,
2482 GlobalLoadAsyncToLDSOpAdaptor adaptor,
2483 ConversionPatternRewriter &rewriter)
const override {
2484 if (!target.has(llvm::AMDGPU::FEAT_GFX1250_INSTS))
2485 return op.emitOpError(
2486 "global_load_async_to_lds is only supported on gfx1250+");
2488 Location loc = op.getLoc();
2489 auto srcMemRefType = cast<MemRefType>(op.getSrc().getType());
2490 auto dstMemRefType = cast<MemRefType>(op.getDst().getType());
2492 Type transferType = op.getTransferType();
2494 isa<VectorType>(transferType)
2495 ? cast<VectorType>(transferType).getNumElements() *
2496 cast<VectorType>(transferType).getElementTypeBitWidth()
2501 adaptor.getSrcIndices());
2504 adaptor.getDstIndices());
2507 Value mask = adaptor.getMask();
2508 int64_t nullptrVal =
2509 llvm::AMDGPU::getNullPointerValue(llvm::AMDGPUAS::LOCAL_ADDRESS);
2513 LLVM::IntToPtrOp::create(rewriter, loc, dstPtr.
getType(), nullInt);
2514 dstPtr = LLVM::SelectOp::create(rewriter, loc, mask, dstPtr, nullPtr);
2517 auto offset = rewriter.getI32IntegerAttr(0);
2518 Attribute aux = rewriter.getI32IntegerAttr(0);
2520 switch (transferBits) {
2522 rewriter.replaceOpWithNewOp<ROCDL::GlobalLoadAsyncToLDSB8Op>(
2527 rewriter.replaceOpWithNewOp<ROCDL::GlobalLoadAsyncToLDSB32Op>(
2532 rewriter.replaceOpWithNewOp<ROCDL::GlobalLoadAsyncToLDSB64Op>(
2537 rewriter.replaceOpWithNewOp<ROCDL::GlobalLoadAsyncToLDSB128Op>(
2542 return op.emitOpError(
"unsupported transfer width");
2549struct ExtPackedFp8OpLowering final
2551 ExtPackedFp8OpLowering(
const LLVMTypeConverter &converter,
2552 const ROCDL::TargetInfo &
target)
2553 : ConvertOpToLLVMPattern<amdgpu::ExtPackedFp8Op>(converter),
2555 ROCDL::TargetInfo
target;
2558 matchAndRewrite(ExtPackedFp8Op op, ExtPackedFp8OpAdaptor adaptor,
2559 ConversionPatternRewriter &rewriter)
const override;
2562struct ScaledExtPackedMatrixOpLowering final
2564 ScaledExtPackedMatrixOpLowering(
const LLVMTypeConverter &converter,
2565 const ROCDL::TargetInfo &
target)
2566 : ConvertOpToLLVMPattern<amdgpu::ScaledExtPackedMatrixOp>(converter),
2568 ROCDL::TargetInfo
target;
2571 matchAndRewrite(ScaledExtPackedMatrixOp op,
2572 ScaledExtPackedMatrixOpAdaptor adaptor,
2573 ConversionPatternRewriter &rewriter)
const override;
2576struct PackedTrunc2xFp8OpLowering final
2578 PackedTrunc2xFp8OpLowering(
const LLVMTypeConverter &converter,
2579 const ROCDL::TargetInfo &
target)
2580 : ConvertOpToLLVMPattern<amdgpu::PackedTrunc2xFp8Op>(converter),
2582 ROCDL::TargetInfo
target;
2585 matchAndRewrite(PackedTrunc2xFp8Op op, PackedTrunc2xFp8OpAdaptor adaptor,
2586 ConversionPatternRewriter &rewriter)
const override;
2589struct PackedStochRoundFp8OpLowering final
2591 PackedStochRoundFp8OpLowering(
const LLVMTypeConverter &converter,
2592 const ROCDL::TargetInfo &
target)
2593 : ConvertOpToLLVMPattern<amdgpu::PackedStochRoundFp8Op>(converter),
2595 ROCDL::TargetInfo
target;
2598 matchAndRewrite(PackedStochRoundFp8Op op,
2599 PackedStochRoundFp8OpAdaptor adaptor,
2600 ConversionPatternRewriter &rewriter)
const override;
2603struct ScaledExtPackedOpLowering final
2605 ScaledExtPackedOpLowering(
const LLVMTypeConverter &converter,
2606 const ROCDL::TargetInfo &
target)
2607 : ConvertOpToLLVMPattern<amdgpu::ScaledExtPackedOp>(converter),
2609 ROCDL::TargetInfo
target;
2612 matchAndRewrite(ScaledExtPackedOp op, ScaledExtPackedOpAdaptor adaptor,
2613 ConversionPatternRewriter &rewriter)
const override;
2616struct PackedScaledTruncOpLowering final
2618 PackedScaledTruncOpLowering(
const LLVMTypeConverter &converter,
2619 const ROCDL::TargetInfo &
target)
2620 : ConvertOpToLLVMPattern<amdgpu::PackedScaledTruncOp>(converter),
2622 ROCDL::TargetInfo
target;
2625 matchAndRewrite(PackedScaledTruncOp op, PackedScaledTruncOpAdaptor adaptor,
2626 ConversionPatternRewriter &rewriter)
const override;
2631LogicalResult ExtPackedFp8OpLowering::matchAndRewrite(
2632 ExtPackedFp8Op op, ExtPackedFp8OpAdaptor adaptor,
2633 ConversionPatternRewriter &rewriter)
const {
2634 Location loc = op.getLoc();
2635 if (!target.has(llvm::AMDGPU::FEAT_FP8_CONVERSION_INSTS))
2636 return rewriter.notifyMatchFailure(
2637 loc,
"Fp8 conversion instructions are not available on target "
2638 "architecture and their emulation is not implemented");
2640 getTypeConverter()->convertType(VectorType::get(4, rewriter.getI8Type()));
2641 Type i32 = getTypeConverter()->convertType(rewriter.getI32Type());
2642 Type f32 = getTypeConverter()->convertType(op.getResult().getType());
2644 Value source = adaptor.getSource();
2645 auto sourceVecType = dyn_cast<VectorType>(op.getSource().getType());
2646 auto resultVecType = dyn_cast<VectorType>(op.getResult().getType());
2649 if (!sourceVecType || sourceVecType.getNumElements() < 4) {
2650 Value longVec = LLVM::UndefOp::create(rewriter, loc, v4i8);
2651 if (!sourceVecType) {
2652 longVec = LLVM::InsertElementOp::create(
2655 for (int32_t i = 0, e = sourceVecType.getNumElements(); i < e; ++i) {
2657 Value elem = LLVM::ExtractElementOp::create(rewriter, loc, source, idx);
2659 LLVM::InsertElementOp::create(rewriter, loc, longVec, elem, idx);
2664 Value i32Source = LLVM::BitcastOp::create(rewriter, loc, i32, source);
2665 if (resultVecType) {
2667 rewriter.replaceOpWithNewOp<ROCDL::CvtPkF32Bf8Op>(op, f32, i32Source,
2670 rewriter.replaceOpWithNewOp<ROCDL::CvtPkF32Fp8Op>(op, f32, i32Source,
2675 rewriter.replaceOpWithNewOp<ROCDL::CvtF32Bf8Op>(op, f32, i32Source,
2678 rewriter.replaceOpWithNewOp<ROCDL::CvtF32Fp8Op>(op, f32, i32Source,
2685int32_t getScaleSel(int32_t blockSize,
unsigned bitWidth, int32_t scaleWaveHalf,
2686 int32_t firstScaleByte) {
2692 assert(llvm::is_contained({16, 32}, blockSize));
2693 assert(llvm::is_contained({4u, 6u, 8u}, bitWidth));
2695 const bool isFp8 = bitWidth == 8;
2696 const bool isBlock16 = blockSize == 16;
2699 int32_t bit0 = isBlock16;
2700 assert(llvm::is_contained({0, 1, 2}, firstScaleByte));
2701 int32_t bit1 = (firstScaleByte == 2) << 1;
2702 assert(llvm::is_contained({0, 1}, scaleWaveHalf));
2703 int32_t bit2 = scaleWaveHalf << 2;
2704 return bit2 | bit1 | bit0;
2707 int32_t bit0 = isBlock16;
2709 assert(llvm::is_contained({0, 1, 2, 3}, firstScaleByte));
2710 int32_t bits2and1 = firstScaleByte << 1;
2711 assert(llvm::is_contained({0, 1}, scaleWaveHalf));
2712 int32_t bit3 = scaleWaveHalf << 3;
2713 int32_t bits = bit3 | bits2and1 | bit0;
2715 assert(!llvm::is_contained(
2716 {0b0011, 0b0101, 0b0111, 0b1000, 0b1001, 0b1011, 0b1111}, bits));
2720static std::optional<StringRef>
2721scaledExtPacked816ToIntrinsic(Type srcElemType, Type destElemType) {
2722 using fp4 = Float4E2M1FNType;
2723 using fp8 = Float8E4M3FNType;
2724 using bf8 = Float8E5M2Type;
2725 using fp6 = Float6E2M3FNType;
2726 using bf6 = Float6E3M2FNType;
2727 if (isa<fp4>(srcElemType)) {
2728 if (destElemType.
isF16())
2729 return ROCDL::CvtPkScalePk8F16Fp4Op::getOperationName();
2730 if (destElemType.
isBF16())
2731 return ROCDL::CvtPkScalePk8Bf16Fp4Op::getOperationName();
2732 if (destElemType.
isF32())
2733 return ROCDL::CvtPkScalePk8F32Fp4Op::getOperationName();
2734 return std::nullopt;
2736 if (isa<fp8>(srcElemType)) {
2737 if (destElemType.
isF16())
2738 return ROCDL::CvtPkScalePk8F16Fp8Op::getOperationName();
2739 if (destElemType.
isBF16())
2740 return ROCDL::CvtPkScalePk8Bf16Fp8Op::getOperationName();
2741 if (destElemType.
isF32())
2742 return ROCDL::CvtPkScalePk8F32Fp8Op::getOperationName();
2743 return std::nullopt;
2745 if (isa<bf8>(srcElemType)) {
2746 if (destElemType.
isF16())
2747 return ROCDL::CvtPkScalePk8F16Bf8Op::getOperationName();
2748 if (destElemType.
isBF16())
2749 return ROCDL::CvtPkScalePk8Bf16Bf8Op::getOperationName();
2750 if (destElemType.
isF32())
2751 return ROCDL::CvtPkScalePk8F32Bf8Op::getOperationName();
2752 return std::nullopt;
2754 if (isa<fp6>(srcElemType)) {
2755 if (destElemType.
isF16())
2756 return ROCDL::CvtPkScalePk16F16Fp6Op::getOperationName();
2757 if (destElemType.
isBF16())
2758 return ROCDL::CvtPkScalePk16Bf16Fp6Op::getOperationName();
2759 if (destElemType.
isF32())
2760 return ROCDL::CvtPkScalePk16F32Fp6Op::getOperationName();
2761 return std::nullopt;
2763 if (isa<bf6>(srcElemType)) {
2764 if (destElemType.
isF16())
2765 return ROCDL::CvtPkScalePk16F16Bf6Op::getOperationName();
2766 if (destElemType.
isBF16())
2767 return ROCDL::CvtPkScalePk16Bf16Bf6Op::getOperationName();
2768 if (destElemType.
isF32())
2769 return ROCDL::CvtPkScalePk16F32Bf6Op::getOperationName();
2770 return std::nullopt;
2772 llvm_unreachable(
"invalid combination of element types for packed conversion "
2776LogicalResult ScaledExtPackedMatrixOpLowering::matchAndRewrite(
2777 ScaledExtPackedMatrixOp op, ScaledExtPackedMatrixOpAdaptor adaptor,
2778 ConversionPatternRewriter &rewriter)
const {
2779 using fp4 = Float4E2M1FNType;
2780 using fp8 = Float8E4M3FNType;
2781 using bf8 = Float8E5M2Type;
2782 using fp6 = Float6E2M3FNType;
2783 using bf6 = Float6E3M2FNType;
2784 Location loc = op.getLoc();
2785 if (!target.has(llvm::AMDGPU::FEAT_GFX1250_INSTS)) {
2786 return rewriter.notifyMatchFailure(
2788 "Scaled fp packed conversion instructions are not available on target "
2789 "architecture and their emulation is not implemented");
2793 int32_t scaleWaveHalf = op.getFirstScaleLane() / 16;
2794 int32_t firstScaleByte = op.getFirstScaleByte();
2795 int32_t blockSize = op.getBlockSize();
2796 auto sourceType = cast<VectorType>(op.getSource().getType());
2797 auto srcElemType = cast<FloatType>(sourceType.getElementType());
2798 unsigned bitWidth = srcElemType.getWidth();
2800 auto targetType = cast<VectorType>(op.getResult().getType());
2801 auto destElemType = cast<FloatType>(targetType.getElementType());
2803 IntegerType i32 = rewriter.getI32Type();
2804 Value source = adaptor.getSource();
2805 Type llvmResultType = typeConverter->convertType(op.getResult().getType());
2806 Type packedType =
nullptr;
2807 if (isa<fp4>(srcElemType)) {
2809 packedType = getTypeConverter()->convertType(packedType);
2810 }
else if (isa<fp8, bf8>(srcElemType)) {
2811 packedType = VectorType::get(2, i32);
2812 packedType = getTypeConverter()->convertType(packedType);
2813 }
else if (isa<fp6, bf6>(srcElemType)) {
2814 packedType = VectorType::get(3, i32);
2815 packedType = getTypeConverter()->convertType(packedType);
2817 llvm_unreachable(
"invalid element type for packed scaled ext");
2820 if (!packedType || !llvmResultType) {
2821 return rewriter.notifyMatchFailure(op,
"type conversion failed");
2824 std::optional<StringRef> maybeIntrinsic =
2825 scaledExtPacked816ToIntrinsic(srcElemType, destElemType);
2826 if (!maybeIntrinsic.has_value())
2827 return op.emitOpError(
2828 "no intrinsic matching packed scaled conversion on the given chipset");
2831 getScaleSel(blockSize, bitWidth, scaleWaveHalf, firstScaleByte);
2833 LLVM::BitcastOp::create(rewriter, loc, i32, adaptor.getScale());
2834 Value castedSource =
2835 LLVM::BitcastOp::create(rewriter, loc, packedType, source);
2837 OperationState loweredOp(loc, *maybeIntrinsic);
2838 loweredOp.addTypes({llvmResultType});
2839 loweredOp.addOperands({castedSource, castedScale});
2841 SmallVector<NamedAttribute, 1> attrs;
2843 NamedAttribute(
"scaleSel", rewriter.getI32IntegerAttr(scaleSel)));
2845 loweredOp.addAttributes(attrs);
2846 Operation *lowered = rewriter.create(loweredOp);
2847 rewriter.replaceOp(op, lowered);
2852LogicalResult ScaledExtPackedOpLowering::matchAndRewrite(
2853 ScaledExtPackedOp op, ScaledExtPackedOpAdaptor adaptor,
2854 ConversionPatternRewriter &rewriter)
const {
2855 Location loc = op.getLoc();
2856 if (!target.has(llvm::AMDGPU::FEAT_GFX950_INSTS))
2857 return rewriter.notifyMatchFailure(
2858 loc,
"Scaled fp conversion instructions are not available on target "
2859 "architecture and their emulation is not implemented");
2860 Type i32 = getTypeConverter()->convertType(rewriter.getI32Type());
2862 Value source = adaptor.getSource();
2863 Value scale = adaptor.getScale();
2865 VectorType sourceVecType = cast<VectorType>(op.getSource().getType());
2866 Type sourceElemType = sourceVecType.getElementType();
2867 VectorType destVecType = cast<VectorType>(op.getResult().getType());
2868 Type destElemType = destVecType.getElementType();
2870 VectorType packedVecType;
2871 if (isa<Float8E5M2Type, Float8E4M3FNType>(sourceElemType)) {
2872 VectorType v4i8 = VectorType::get(4, rewriter.getI8Type());
2873 packedVecType = cast<VectorType>(getTypeConverter()->convertType(v4i8));
2874 }
else if (isa<Float4E2M1FNType>(sourceElemType)) {
2875 VectorType v8i4 = VectorType::get(8, rewriter.getI4Type());
2876 packedVecType = cast<VectorType>(getTypeConverter()->convertType(v8i4));
2878 llvm_unreachable(
"invalid element type for scaled ext");
2882 if (sourceVecType.getNumElements() < packedVecType.getNumElements()) {
2883 Value longVec = LLVM::ZeroOp::create(rewriter, loc, packedVecType);
2884 if (!sourceVecType) {
2885 longVec = LLVM::InsertElementOp::create(
2888 for (int32_t i = 0, e = sourceVecType.getNumElements(); i < e; ++i) {
2890 Value elem = LLVM::ExtractElementOp::create(rewriter, loc, source, idx);
2892 LLVM::InsertElementOp::create(rewriter, loc, longVec, elem, idx);
2897 Value i32Source = LLVM::BitcastOp::create(rewriter, loc, i32, source);
2899 if (isa<Float8E5M2Type>(sourceElemType) && destElemType.
isF32())
2900 rewriter.replaceOpWithNewOp<ROCDL::CvtScaleF32PkF32Bf8Op>(
2901 op, destVecType, i32Source, scale, op.getIndex());
2902 else if (isa<Float8E5M2Type>(sourceElemType) && destElemType.
isF16())
2903 rewriter.replaceOpWithNewOp<ROCDL::CvtScaleF32PkF16Bf8Op>(
2904 op, destVecType, i32Source, scale, op.getIndex());
2905 else if (isa<Float8E5M2Type>(sourceElemType) && destElemType.
isBF16())
2906 rewriter.replaceOpWithNewOp<ROCDL::CvtScaleF32PkBf16Bf8Op>(
2907 op, destVecType, i32Source, scale, op.getIndex());
2908 else if (isa<Float8E4M3FNType>(sourceElemType) && destElemType.
isF32())
2909 rewriter.replaceOpWithNewOp<ROCDL::CvtScaleF32PkF32Fp8Op>(
2910 op, destVecType, i32Source, scale, op.getIndex());
2911 else if (isa<Float8E4M3FNType>(sourceElemType) && destElemType.
isF16())
2912 rewriter.replaceOpWithNewOp<ROCDL::CvtScaleF32PkF16Fp8Op>(
2913 op, destVecType, i32Source, scale, op.getIndex());
2914 else if (isa<Float8E4M3FNType>(sourceElemType) && destElemType.
isBF16())
2915 rewriter.replaceOpWithNewOp<ROCDL::CvtScaleF32PkBf16Fp8Op>(
2916 op, destVecType, i32Source, scale, op.getIndex());
2917 else if (isa<Float4E2M1FNType>(sourceElemType) && destElemType.
isF32())
2918 rewriter.replaceOpWithNewOp<ROCDL::CvtScaleF32PkF32Fp4Op>(
2919 op, destVecType, i32Source, scale, op.getIndex());
2920 else if (isa<Float4E2M1FNType>(sourceElemType) && destElemType.
isF16())
2921 rewriter.replaceOpWithNewOp<ROCDL::CvtScaleF32PkF16Fp4Op>(
2922 op, destVecType, i32Source, scale, op.getIndex());
2923 else if (isa<Float4E2M1FNType>(sourceElemType) && destElemType.
isBF16())
2924 rewriter.replaceOpWithNewOp<ROCDL::CvtScaleF32PkBf16Fp4Op>(
2925 op, destVecType, i32Source, scale, op.getIndex());
2932LogicalResult PackedScaledTruncOpLowering::matchAndRewrite(
2933 PackedScaledTruncOp op, PackedScaledTruncOpAdaptor adaptor,
2934 ConversionPatternRewriter &rewriter)
const {
2935 Location loc = op.getLoc();
2936 if (!target.has(llvm::AMDGPU::FEAT_GFX950_INSTS))
2937 return rewriter.notifyMatchFailure(
2938 loc,
"Scaled fp conversion instructions are not available on target "
2939 "architecture and their emulation is not implemented");
2940 Type v2i16 = getTypeConverter()->convertType(
2941 VectorType::get(2, rewriter.getI16Type()));
2942 Type i32 = getTypeConverter()->convertType(rewriter.getI32Type());
2944 Type resultType = op.getResult().getType();
2946 VectorType sourceVecType = cast<VectorType>(op.getSource().getType());
2947 Type sourceElemType = sourceVecType.getElementType();
2949 Type intResultType = isa<Float4E2M1FNType>(resultElemType) ? i32 : v2i16;
2951 Value source = adaptor.getSource();
2952 Value scale = adaptor.getScale();
2953 Value existing = adaptor.getExisting();
2955 existing = LLVM::BitcastOp::create(rewriter, loc, intResultType, existing);
2957 existing = LLVM::ZeroOp::create(rewriter, loc, intResultType);
2959 if (sourceVecType.getNumElements() < 2) {
2961 Value elem0 = LLVM::ExtractElementOp::create(rewriter, loc, source, c0);
2962 VectorType v2 = VectorType::get(2, sourceElemType);
2963 source = LLVM::ZeroOp::create(rewriter, loc, v2);
2964 source = LLVM::InsertElementOp::create(rewriter, loc, source, elem0, c0);
2967 Value sourceA, sourceB;
2968 if (sourceElemType.
isF32()) {
2971 sourceA = LLVM::ExtractElementOp::create(rewriter, loc, source, c0);
2972 sourceB = LLVM::ExtractElementOp::create(rewriter, loc, source, c1);
2976 if (sourceElemType.
isF32() && isa<Float8E5M2Type>(resultElemType))
2977 result = ROCDL::CvtScaleF32PkBf8F32Op::create(rewriter, loc, intResultType,
2978 existing, sourceA, sourceB,
2979 scale, op.getIndex());
2980 else if (sourceElemType.
isF16() && isa<Float8E5M2Type>(resultElemType))
2981 result = ROCDL::CvtScaleF32PkBf8F16Op::create(
2982 rewriter, loc, intResultType, existing, source, scale, op.getIndex());
2983 else if (sourceElemType.
isBF16() && isa<Float8E5M2Type>(resultElemType))
2984 result = ROCDL::CvtScaleF32PkBf8Bf16Op::create(
2985 rewriter, loc, intResultType, existing, source, scale, op.getIndex());
2986 else if (sourceElemType.
isF32() && isa<Float8E4M3FNType>(resultElemType))
2987 result = ROCDL::CvtScaleF32PkFp8F32Op::create(rewriter, loc, intResultType,
2988 existing, sourceA, sourceB,
2989 scale, op.getIndex());
2990 else if (sourceElemType.
isF16() && isa<Float8E4M3FNType>(resultElemType))
2991 result = ROCDL::CvtScaleF32PkFp8F16Op::create(
2992 rewriter, loc, intResultType, existing, source, scale, op.getIndex());
2993 else if (sourceElemType.
isBF16() && isa<Float8E4M3FNType>(resultElemType))
2994 result = ROCDL::CvtScaleF32PkFp8Bf16Op::create(
2995 rewriter, loc, intResultType, existing, source, scale, op.getIndex());
2996 else if (sourceElemType.
isF32() && isa<Float4E2M1FNType>(resultElemType))
2997 result = ROCDL::CvtScaleF32PkFp4F32Op::create(rewriter, loc, intResultType,
2998 existing, sourceA, sourceB,
2999 scale, op.getIndex());
3000 else if (sourceElemType.
isF16() && isa<Float4E2M1FNType>(resultElemType))
3001 result = ROCDL::CvtScaleF32PkFp4F16Op::create(
3002 rewriter, loc, intResultType, existing, source, scale, op.getIndex());
3003 else if (sourceElemType.
isBF16() && isa<Float4E2M1FNType>(resultElemType))
3004 result = ROCDL::CvtScaleF32PkFp4Bf16Op::create(
3005 rewriter, loc, intResultType, existing, source, scale, op.getIndex());
3009 result = rewriter.replaceOpWithNewOp<LLVM::BitcastOp>(
3010 op, getTypeConverter()->convertType(resultType),
result);
3014LogicalResult PackedTrunc2xFp8OpLowering::matchAndRewrite(
3015 PackedTrunc2xFp8Op op, PackedTrunc2xFp8OpAdaptor adaptor,
3016 ConversionPatternRewriter &rewriter)
const {
3017 Location loc = op.getLoc();
3018 if (!target.has(llvm::AMDGPU::FEAT_FP8_CONVERSION_INSTS))
3019 return rewriter.notifyMatchFailure(
3020 loc,
"Fp8 conversion instructions are not available on target "
3021 "architecture and their emulation is not implemented");
3022 Type i32 = getTypeConverter()->convertType(rewriter.getI32Type());
3024 Type resultType = op.getResult().getType();
3027 Value sourceA = adaptor.getSourceA();
3028 Value sourceB = adaptor.getSourceB();
3030 sourceB = LLVM::UndefOp::create(rewriter, loc, sourceA.
getType());
3031 Value existing = adaptor.getExisting();
3033 existing = LLVM::BitcastOp::create(rewriter, loc, i32, existing);
3035 existing = LLVM::UndefOp::create(rewriter, loc, i32);
3039 result = ROCDL::CvtPkBf8F32Op::create(rewriter, loc, i32, sourceA, sourceB,
3040 existing, op.getWordIndex());
3042 result = ROCDL::CvtPkFp8F32Op::create(rewriter, loc, i32, sourceA, sourceB,
3043 existing, op.getWordIndex());
3045 return op.emitOpError(
3046 "no truncation to result type available on given chipset");
3048 result = rewriter.replaceOpWithNewOp<LLVM::BitcastOp>(
3049 op, getTypeConverter()->convertType(resultType),
result);
3053LogicalResult PackedStochRoundFp8OpLowering::matchAndRewrite(
3054 PackedStochRoundFp8Op op, PackedStochRoundFp8OpAdaptor adaptor,
3055 ConversionPatternRewriter &rewriter)
const {
3056 Location loc = op.getLoc();
3057 if (!target.has(llvm::AMDGPU::FEAT_FP8_CONVERSION_INSTS))
3058 return rewriter.notifyMatchFailure(
3059 loc,
"Fp8 conversion instructions are not available on target "
3060 "architecture and their emulation is not implemented");
3061 Type i32 = getTypeConverter()->convertType(rewriter.getI32Type());
3063 Type resultType = op.getResult().getType();
3066 Value source = adaptor.getSource();
3067 Value stoch = adaptor.getStochiasticParam();
3068 Value existing = adaptor.getExisting();
3070 existing = LLVM::BitcastOp::create(rewriter, loc, i32, existing);
3072 existing = LLVM::UndefOp::create(rewriter, loc, i32);
3076 result = ROCDL::CvtSrBf8F32Op::create(rewriter, loc, i32, source, stoch,
3077 existing, op.getStoreIndex());
3079 result = ROCDL::CvtSrFp8F32Op::create(rewriter, loc, i32, source, stoch,
3080 existing, op.getStoreIndex());
3082 return op.emitOpError(
3083 "no stochastic rounding to result type available on given chipset");
3085 result = rewriter.replaceOpWithNewOp<LLVM::BitcastOp>(
3086 op, getTypeConverter()->convertType(resultType),
result);
3092struct AMDGPUDPPLowering :
public ConvertOpToLLVMPattern<DPPOp> {
3093 AMDGPUDPPLowering(
const LLVMTypeConverter &converter,
3094 const ROCDL::TargetInfo &
target)
3095 : ConvertOpToLLVMPattern<DPPOp>(converter),
target(
target) {}
3096 ROCDL::TargetInfo
target;
3099 matchAndRewrite(DPPOp DppOp, DPPOp::Adaptor adaptor,
3100 ConversionPatternRewriter &rewriter)
const override {
3103 Location loc = DppOp.getLoc();
3104 Value src = adaptor.getSrc();
3105 Value old = adaptor.getOld();
3108 Type llvmType =
nullptr;
3110 llvmType = rewriter.getI32Type();
3111 }
else if (isa<FloatType>(srcType)) {
3113 ? rewriter.getF32Type()
3114 : rewriter.getF64Type();
3115 }
else if (isa<IntegerType>(srcType)) {
3117 ? rewriter.getI32Type()
3118 : rewriter.getI64Type();
3120 auto llvmSrcIntType = typeConverter->convertType(
3124 auto convertOperand = [&](Value operand, Type operandType) {
3125 if (operandType.getIntOrFloatBitWidth() <= 16) {
3126 if (llvm::isa<FloatType>(operandType)) {
3128 LLVM::BitcastOp::create(rewriter, loc, llvmSrcIntType, operand);
3130 auto llvmVecType = typeConverter->convertType(mlir::VectorType::get(
3131 32 / operandType.getIntOrFloatBitWidth(), llvmSrcIntType));
3132 Value undefVec = LLVM::UndefOp::create(rewriter, loc, llvmVecType);
3134 LLVM::InsertElementOp::create(rewriter, loc, undefVec, operand,
3136 operand = LLVM::BitcastOp::create(rewriter, loc, llvmType, operand);
3141 src = convertOperand(src, srcType);
3142 old = convertOperand(old, oldType);
3145 enum DppCtrl :
unsigned {
3154 ROW_HALF_MIRROR = 0x141,
3159 auto kind = DppOp.getKind();
3160 auto permArgument = DppOp.getPermArgument();
3161 uint32_t DppCtrl = 0;
3165 case DPPPerm::quad_perm: {
3166 auto quadPermAttr = cast<ArrayAttr>(*permArgument);
3168 for (
auto elem : quadPermAttr.getAsRange<IntegerAttr>()) {
3169 uint32_t num = elem.getInt();
3170 DppCtrl |= num << (i * 2);
3175 case DPPPerm::row_shl: {
3176 auto intAttr = cast<IntegerAttr>(*permArgument);
3177 DppCtrl = intAttr.getInt() + DppCtrl::ROW_SHL0;
3180 case DPPPerm::row_shr: {
3181 auto intAttr = cast<IntegerAttr>(*permArgument);
3182 DppCtrl = intAttr.getInt() + DppCtrl::ROW_SHR0;
3185 case DPPPerm::row_ror: {
3186 auto intAttr = cast<IntegerAttr>(*permArgument);
3187 DppCtrl = intAttr.getInt() + DppCtrl::ROW_ROR0;
3190 case DPPPerm::wave_shl:
3191 DppCtrl = DppCtrl::WAVE_SHL1;
3193 case DPPPerm::wave_shr:
3194 DppCtrl = DppCtrl::WAVE_SHR1;
3196 case DPPPerm::wave_rol:
3197 DppCtrl = DppCtrl::WAVE_ROL1;
3199 case DPPPerm::wave_ror:
3200 DppCtrl = DppCtrl::WAVE_ROR1;
3202 case DPPPerm::row_mirror:
3203 DppCtrl = DppCtrl::ROW_MIRROR;
3205 case DPPPerm::row_half_mirror:
3206 DppCtrl = DppCtrl::ROW_HALF_MIRROR;
3208 case DPPPerm::row_bcast_15:
3209 DppCtrl = DppCtrl::BCAST15;
3211 case DPPPerm::row_bcast_31:
3212 DppCtrl = DppCtrl::BCAST31;
3218 auto rowMask = DppOp.getRowMask();
3219 auto bankMask = DppOp.getBankMask();
3220 bool boundCtrl = DppOp.getBoundCtrl();
3224 ROCDL::DPPUpdateOp::create(rewriter, loc, llvmType, old, src, DppCtrl,
3225 rowMask, bankMask, boundCtrl);
3227 Value
result = dppMovOp.getRes();
3229 result = LLVM::TruncOp::create(rewriter, loc, llvmSrcIntType,
result);
3230 if (!llvm::isa<IntegerType>(srcType)) {
3231 result = LLVM::BitcastOp::create(rewriter, loc, srcType,
result);
3242struct AMDGPUSwizzleBitModeLowering
3243 :
public ConvertOpToLLVMPattern<SwizzleBitModeOp> {
3247 matchAndRewrite(SwizzleBitModeOp op, OpAdaptor adaptor,
3248 ConversionPatternRewriter &rewriter)
const override {
3249 Location loc = op.getLoc();
3250 Type i32 = rewriter.getI32Type();
3251 Value src = adaptor.getSrc();
3252 SmallVector<Value> decomposed;
3254 return rewriter.notifyMatchFailure(op,
3255 "failed to decompose value to i32");
3256 unsigned andMask = op.getAndMask();
3257 unsigned orMask = op.getOrMask();
3258 unsigned xorMask = op.getXorMask();
3262 unsigned mask = andMask | (orMask << 5) | (xorMask << 10);
3264 SmallVector<Value> swizzled;
3265 for (Value v : decomposed) {
3267 ROCDL::DsSwizzleOp::create(rewriter, loc, v.getType(), v, maskValue);
3268 swizzled.emplace_back(res);
3272 rewriter.replaceOp(op,
result);
3277struct AMDGPUPermlaneLowering :
public ConvertOpToLLVMPattern<PermlaneSwapOp> {
3280 AMDGPUPermlaneLowering(
const LLVMTypeConverter &converter,
3281 const ROCDL::TargetInfo &
target)
3282 : ConvertOpToLLVMPattern<PermlaneSwapOp>(converter),
target(
target) {}
3283 ROCDL::TargetInfo
target;
3286 matchAndRewrite(PermlaneSwapOp op, OpAdaptor adaptor,
3287 ConversionPatternRewriter &rewriter)
const override {
3288 unsigned rowLength = op.getRowLength();
3289 bool supported = rowLength == 16
3290 ?
target.has(llvm::AMDGPU::FEAT_PERMLANE16_SWAP)
3291 :
target.has(llvm::AMDGPU::FEAT_PERMLANE32_SWAP);
3293 return op->emitOpError(
"permlane_swap of row length ")
3294 << rowLength <<
" is not supported on " <<
target.getArchName();
3296 Location loc = op.getLoc();
3297 Type i32 = rewriter.getI32Type();
3298 Value src = adaptor.getSrc();
3299 bool fi = op.getFetchInactive();
3300 bool boundctrl = op.getBoundCtrl();
3302 SmallVector<Value> decomposed;
3304 return rewriter.notifyMatchFailure(op,
3305 "failed to decompose value to i32");
3307 SmallVector<Value> permuted;
3308 for (Value v : decomposed) {
3310 Type i32pair = LLVM::LLVMStructType::getLiteral(
3311 rewriter.getContext(), {v.getType(), v.getType()});
3313 if (rowLength == 16)
3314 res = ROCDL::Permlane16SwapOp::create(rewriter, loc, i32pair, v, v, fi,
3316 else if (rowLength == 32)
3317 res = ROCDL::Permlane32SwapOp::create(rewriter, loc, i32pair, v, v, fi,
3320 llvm_unreachable(
"unsupported row length");
3322 Value vdst0 = LLVM::ExtractValueOp::create(rewriter, loc, res, {0});
3323 Value vdst1 = LLVM::ExtractValueOp::create(rewriter, loc, res, {1});
3325 Value isEqual = LLVM::ICmpOp::create(rewriter, loc,
3326 LLVM::ICmpPredicate::eq, vdst0, v);
3331 LLVM::SelectOp::create(rewriter, loc, isEqual, vdst1, vdst0);
3332 permuted.emplace_back(vdstNew);
3336 rewriter.replaceOp(op,
result);
3341struct AMDGPUPermlaneVarLowering
3342 :
public ConvertOpToLLVMPattern<PermlaneVarOp> {
3345 AMDGPUPermlaneVarLowering(
const LLVMTypeConverter &converter,
3346 const ROCDL::TargetInfo &
target)
3347 : ConvertOpToLLVMPattern<PermlaneVarOp>(converter),
target(
target) {}
3348 ROCDL::TargetInfo
target;
3351 matchAndRewrite(PermlaneVarOp op, OpAdaptor adaptor,
3352 ConversionPatternRewriter &rewriter)
const override {
3353 if (!
target.has(llvm::AMDGPU::FEAT_GFX12_INSTS))
3354 return op->emitOpError(
"permlane_var is only supported on GFX12+");
3356 Location loc = op.getLoc();
3357 Type i32 = rewriter.getI32Type();
3358 Value src = adaptor.getSrc();
3359 Value selector = adaptor.getSelector();
3360 bool cross = op.getCross();
3361 bool fi = op.getFetchInactive();
3362 bool boundCtrl = op.getBoundCtrl();
3364 SmallVector<Value> decomposed;
3366 return rewriter.notifyMatchFailure(op,
3367 "failed to decompose value to i32");
3369 SmallVector<Value> permuted;
3370 for (Value v : decomposed) {
3373 res = ROCDL::PermlaneX16VarOp::create(rewriter, loc, i32, v, v,
3374 selector, fi, boundCtrl);
3376 res = ROCDL::Permlane16VarOp::create(rewriter, loc, i32, v, v, selector,
3378 permuted.emplace_back(res);
3382 rewriter.replaceOp(op,
result);
3395constexpr int32_t kDsBarrierPendingCountBitWidth = 29;
3396constexpr int32_t kDsBarrierPhasePos = kDsBarrierPendingCountBitWidth;
3397constexpr int32_t kDsBarrierInitCountPos = 32;
3398constexpr int32_t kDsBarrierPendingCountMask =
3399 (1 << kDsBarrierPendingCountBitWidth) - 1;
3401struct DsBarrierInitOpLowering
3402 :
public ConvertOpToLLVMPattern<DsBarrierInitOp> {
3403 ROCDL::TargetInfo
target;
3405 DsBarrierInitOpLowering(
const LLVMTypeConverter &converter,
3406 const ROCDL::TargetInfo &
target)
3407 : ConvertOpToLLVMPattern<DsBarrierInitOp>(converter),
target(
target) {}
3410 matchAndRewrite(DsBarrierInitOp op, OpAdaptor adaptor,
3411 ConversionPatternRewriter &rewriter)
const override {
3412 if (!
target.has(llvm::AMDGPU::FEAT_GFX1250_INSTS))
3413 return op->emitOpError(
"only supported on gfx1250+");
3415 Location loc = op.getLoc();
3416 Type i64 = rewriter.getI64Type();
3418 MemRefType memrefType = cast<MemRefType>(op.getBase().getType());
3420 adaptor.getBase(), adaptor.getIndices());
3427 LLVM::SubOp::create(rewriter, loc, adaptor.getParticipants(),
3434 Value maskedCount32 =
3435 LLVM::AndOp::create(rewriter, loc, initCount, countMask);
3436 Value maskedCount = LLVM::ZExtOp::create(rewriter, loc, i64, maskedCount32);
3438 Value initCountShifted = LLVM::ShlOp::create(
3439 rewriter, loc, maskedCount,
3441 Value barrierState =
3442 LLVM::OrOp::create(rewriter, loc, initCountShifted, maskedCount);
3444 LLVM::StoreOp::create(
3445 rewriter, loc, barrierState, ptr, 8,
false,
3447 false, LLVM::AtomicOrdering::release,
3450 rewriter.eraseOp(op);
3455struct DsBarrierPollStateOpLowering
3456 :
public ConvertOpToLLVMPattern<DsBarrierPollStateOp> {
3457 ROCDL::TargetInfo
target;
3459 DsBarrierPollStateOpLowering(
const LLVMTypeConverter &converter,
3460 const ROCDL::TargetInfo &
target)
3461 : ConvertOpToLLVMPattern<DsBarrierPollStateOp>(converter),
3465 matchAndRewrite(DsBarrierPollStateOp op, OpAdaptor adaptor,
3466 ConversionPatternRewriter &rewriter)
const override {
3467 if (!
target.has(llvm::AMDGPU::FEAT_GFX1250_INSTS))
3468 return op->emitOpError(
"only supported on gfx1250+");
3470 Location loc = op.getLoc();
3471 Type i64 = rewriter.getI64Type();
3473 MemRefType memrefType = cast<MemRefType>(op.getBase().getType());
3475 adaptor.getBase(), adaptor.getIndices());
3479 rewriter.replaceOpWithNewOp<LLVM::LoadOp>(
3480 op, i64, ptr, 8,
false,
3483 LLVM::AtomicOrdering::acquire,
3489struct DsAsyncBarrierArriveOpLowering
3490 :
public ConvertOpToLLVMPattern<DsAsyncBarrierArriveOp> {
3491 ROCDL::TargetInfo
target;
3493 DsAsyncBarrierArriveOpLowering(
const LLVMTypeConverter &converter,
3494 const ROCDL::TargetInfo &
target)
3495 : ConvertOpToLLVMPattern<DsAsyncBarrierArriveOp>(converter),
3499 matchAndRewrite(DsAsyncBarrierArriveOp op, OpAdaptor adaptor,
3500 ConversionPatternRewriter &rewriter)
const override {
3501 if (!
target.has(llvm::AMDGPU::FEAT_GFX1250_INSTS))
3502 return op->emitOpError(
"only supported on gfx1250+");
3504 Location loc = op.getLoc();
3506 MemRefType memrefType = cast<MemRefType>(op.getBase().getType());
3508 adaptor.getBase(), adaptor.getIndices());
3510 rewriter.replaceOpWithNewOp<ROCDL::DsAtomicAsyncBarrierArriveOp>(
3511 op, ptr,
nullptr,
nullptr,
3517struct DsBarrierArriveOpLowering
3518 :
public ConvertOpToLLVMPattern<DsBarrierArriveOp> {
3519 ROCDL::TargetInfo
target;
3521 DsBarrierArriveOpLowering(
const LLVMTypeConverter &converter,
3522 const ROCDL::TargetInfo &
target)
3523 : ConvertOpToLLVMPattern<DsBarrierArriveOp>(converter),
target(
target) {}
3526 matchAndRewrite(DsBarrierArriveOp op, OpAdaptor adaptor,
3527 ConversionPatternRewriter &rewriter)
const override {
3528 if (!
target.has(llvm::AMDGPU::FEAT_GFX1250_INSTS))
3529 return op->emitOpError(
"only supported on gfx1250+");
3531 Location loc = op.getLoc();
3532 Type i64 = rewriter.getI64Type();
3534 MemRefType memrefType = cast<MemRefType>(op.getBase().getType());
3536 adaptor.getBase(), adaptor.getIndices());
3538 rewriter.replaceOpWithNewOp<ROCDL::DsAtomicBarrierArriveRtnOp>(
3539 op, i64, ptr, adaptor.getCount(),
nullptr,
3545struct DsBarrierStatePhaseOpLowering
3546 :
public ConvertOpToLLVMPattern<DsBarrierStatePhaseOp> {
3550 matchAndRewrite(DsBarrierStatePhaseOp op, OpAdaptor adaptor,
3551 ConversionPatternRewriter &rewriter)
const override {
3552 Location loc = op.getLoc();
3553 Type i32 = rewriter.getI32Type();
3555 Value state = adaptor.getState();
3557 Value noInitCount = LLVM::TruncOp::create(rewriter, loc, i32, state);
3558 Value phase = LLVM::LShrOp::create(
3559 rewriter, loc, noInitCount,
3562 rewriter.replaceOp(op, phase);
3567struct DsBarrierStatePendingCountOpLowering
3568 :
public ConvertOpToLLVMPattern<DsBarrierStatePendingCountOp> {
3572 matchAndRewrite(DsBarrierStatePendingCountOp op, OpAdaptor adaptor,
3573 ConversionPatternRewriter &rewriter)
const override {
3574 Location loc = op.getLoc();
3575 Type i32 = rewriter.getI32Type();
3577 Value state = adaptor.getState();
3579 Value noInitCount = LLVM::TruncOp::create(rewriter, loc, i32, state);
3580 Value pendingCount = LLVM::AndOp::create(
3581 rewriter, loc, noInitCount,
3583 static_cast<uint32_t
>(kDsBarrierPendingCountMask)));
3585 rewriter.replaceOp(op, pendingCount);
3590struct DsBarrierStateInitCountOpLowering
3591 :
public ConvertOpToLLVMPattern<DsBarrierStateInitCountOp> {
3595 matchAndRewrite(DsBarrierStateInitCountOp op, OpAdaptor adaptor,
3596 ConversionPatternRewriter &rewriter)
const override {
3597 Location loc = op.getLoc();
3598 Type i32 = rewriter.getI32Type();
3600 Value state = adaptor.getState();
3602 Value initCountI64 = LLVM::LShrOp::create(
3603 rewriter, loc, state,
3605 Value initCount = LLVM::TruncOp::create(rewriter, loc, i32, initCountI64);
3607 rewriter.replaceOp(op, initCount);
3612struct DsBarrierStatePhaseParityLowering
3613 :
public ConvertOpToLLVMPattern<DsBarrierStatePhaseParity> {
3617 matchAndRewrite(DsBarrierStatePhaseParity op, OpAdaptor adaptor,
3618 ConversionPatternRewriter &rewriter)
const override {
3619 Location loc = op.getLoc();
3620 Type i1 = rewriter.getI1Type();
3622 Value state = adaptor.getState();
3625 LLVM::TruncOp::create(rewriter, loc, rewriter.getI32Type(), state);
3626 Value phase = LLVM::LShrOp::create(
3627 rewriter, loc, noInitCount,
3629 Value parity = LLVM::TruncOp::create(rewriter, loc, i1, phase);
3631 rewriter.replaceOp(op, parity);
3640static Value setValueAtOffset(ConversionPatternRewriter &rewriter, Location loc,
3641 Value accumulator, Value value, int64_t shift) {
3646 value = LLVM::ShlOp::create(rewriter, loc, value, shiftAmount);
3652 constexpr bool isDisjoint =
true;
3653 return LLVM::OrOp::create(rewriter, loc, accumulator, value, isDisjoint);
3656template <
typename BaseOp>
3657struct AMDGPUMakeDmaBaseLowering :
public ConvertOpToLLVMPattern<BaseOp> {
3658 using ConvertOpToLLVMPattern<BaseOp>::ConvertOpToLLVMPattern;
3661 AMDGPUMakeDmaBaseLowering(
const LLVMTypeConverter &converter,
3662 const ROCDL::TargetInfo &
target)
3663 : ConvertOpToLLVMPattern<BaseOp>(converter),
target(
target) {}
3664 ROCDL::TargetInfo
target;
3667 matchAndRewrite(BaseOp op, Adaptor adaptor,
3668 ConversionPatternRewriter &rewriter)
const override {
3669 if (!
target.has(llvm::AMDGPU::FEAT_GFX1250_INSTS))
3670 return op->emitOpError(
"make_dma_base is only supported on gfx1250");
3672 Location loc = op.getLoc();
3674 constexpr int32_t constlen = 4;
3675 Value consts[constlen];
3676 for (int64_t i = 0; i < constlen; ++i)
3679 constexpr int32_t sgprslen = constlen;
3680 Value sgprs[sgprslen];
3681 for (int64_t i = 0; i < sgprslen; ++i) {
3682 sgprs[i] = consts[0];
3685 sgprs[0] = consts[1];
3687 if constexpr (BaseOp::isGather()) {
3688 sgprs[0] = setValueAtOffset(rewriter, loc, sgprs[0], consts[1], 30);
3690 auto type = cast<TDMGatherBaseType>(op.getResult().getType());
3691 Type indexType = type.getIndexType();
3693 assert(llvm::is_contained({16u, 32u}, indexSize) &&
3694 "expected index_size to be 16 or 32");
3695 unsigned idx = (indexSize / 16) - 1;
3698 sgprs[0] = setValueAtOffset(rewriter, loc, sgprs[0], consts[1], 31);
3701 ValueRange ldsIndices = adaptor.getLdsIndices();
3702 Value lds = adaptor.getLds();
3703 auto ldsMemRefType = cast<MemRefType>(op.getLds().getType());
3706 rewriter, loc, ldsMemRefType, lds, ldsIndices);
3708 ValueRange globalIndices = adaptor.getGlobalIndices();
3709 Value global = adaptor.getGlobal();
3710 auto globalMemRefType = cast<MemRefType>(op.getGlobal().getType());
3713 rewriter, loc, globalMemRefType, global, globalIndices);
3715 Type i32 = rewriter.getI32Type();
3716 Type i64 = rewriter.getI64Type();
3718 sgprs[1] = LLVM::PtrToIntOp::create(rewriter, loc, i32, ldsPtr);
3719 Value castForGlobalAddr =
3720 LLVM::PtrToIntOp::create(rewriter, loc, i64, globalPtr);
3722 sgprs[2] = LLVM::TruncOp::create(rewriter, loc, i32, castForGlobalAddr);
3724 Value shift = LLVM::LShrOp::create(rewriter, loc, castForGlobalAddr,
3727 Value highHalf = LLVM::TruncOp::create(rewriter, loc, i32, shift);
3730 highHalf = LLVM::AndOp::create(rewriter, loc, highHalf, mask);
3732 sgprs[3] = setValueAtOffset(rewriter, loc, highHalf, consts[2], 30);
3734 Type v4i32 = this->typeConverter->convertType(VectorType::get(4, i32));
3735 assert(v4i32 &&
"expected type conversion to succeed");
3736 Value
result = LLVM::PoisonOp::create(rewriter, loc, v4i32);
3738 for (
auto [sgpr, constant] : llvm::zip_equal(sgprs, consts))
3740 LLVM::InsertElementOp::create(rewriter, loc,
result, sgpr, constant);
3742 rewriter.replaceOp(op,
result);
3747template <
typename DescriptorOp>
3748struct AMDGPULowerDescriptor :
public ConvertOpToLLVMPattern<DescriptorOp> {
3749 using ConvertOpToLLVMPattern<DescriptorOp>::ConvertOpToLLVMPattern;
3752 AMDGPULowerDescriptor(
const LLVMTypeConverter &converter,
3753 const ROCDL::TargetInfo &
target)
3754 : ConvertOpToLLVMPattern<DescriptorOp>(converter),
target(
target) {}
3755 ROCDL::TargetInfo
target;
3757 Value getDGroup0(OpAdaptor &adaptor)
const {
return adaptor.getBase(); }
3759 Value setWorkgroupMask(DescriptorOp op, OpAdaptor &adaptor,
3760 ConversionPatternRewriter &rewriter, Location loc,
3761 Value sgpr0)
const {
3762 Value mask = op.getWorkgroupMask();
3766 Type i16 = rewriter.getI16Type();
3767 mask = LLVM::BitcastOp::create(rewriter, loc, i16, mask);
3768 Type i32 = rewriter.getI32Type();
3769 Value extendedMask = LLVM::ZExtOp::create(rewriter, loc, i32, mask);
3770 return setValueAtOffset(rewriter, loc, sgpr0, extendedMask, 0);
3773 Value setDataSize(DescriptorOp op, OpAdaptor &adaptor,
3774 ConversionPatternRewriter &rewriter, Location loc,
3775 Value sgpr0, ArrayRef<Value> consts)
const {
3776 unsigned elementTypeWidthInBits = op.getElementTypeWidth();
3777 assert(llvm::is_contained({8u, 16u, 32u, 64u}, elementTypeWidthInBits) &&
3778 "expected type width to be 8, 16, 32, or 64.");
3779 int64_t idx = llvm::Log2_32(elementTypeWidthInBits / 8);
3780 Value size = consts[idx];
3781 return setValueAtOffset(rewriter, loc, sgpr0, size, 16);
3784 Value setAtomicBarrier(DescriptorOp op, OpAdaptor &adaptor,
3785 ConversionPatternRewriter &rewriter, Location loc,
3786 Value sgpr0, ArrayRef<Value> consts)
const {
3787 if (!adaptor.getAtomicBarrierAddress())
3790 return setValueAtOffset(rewriter, loc, sgpr0, consts[1], 18);
3793 Value setIterateEnable(DescriptorOp op, OpAdaptor &adaptor,
3794 ConversionPatternRewriter &rewriter, Location loc,
3795 Value sgpr0, ArrayRef<Value> consts)
const {
3796 if (!adaptor.getGlobalIncrement())
3801 return setValueAtOffset(rewriter, loc, sgpr0, consts[1], 19);
3804 Value setPadEnable(DescriptorOp op, OpAdaptor &adaptor,
3805 ConversionPatternRewriter &rewriter, Location loc,
3806 Value sgpr0, ArrayRef<Value> consts)
const {
3807 if (!op.getPadAmount())
3810 return setValueAtOffset(rewriter, loc, sgpr0, consts[1], 20);
3813 Value setEarlyTimeout(DescriptorOp op, OpAdaptor &adaptor,
3814 ConversionPatternRewriter &rewriter, Location loc,
3815 Value sgpr0, ArrayRef<Value> consts)
const {
3816 if (!op.getWorkgroupMask())
3819 return setValueAtOffset(rewriter, loc, sgpr0, consts[1], 21);
3822 Value setPadInterval(DescriptorOp op, OpAdaptor &adaptor,
3823 ConversionPatternRewriter &rewriter, Location loc,
3824 Value sgpr0, ArrayRef<Value> consts)
const {
3825 if (!op.getPadAmount())
3834 IntegerType i32 = rewriter.getI32Type();
3835 Value padInterval = adaptor.getPadInterval();
3836 padInterval = LLVM::CountTrailingZerosOp::create(rewriter, loc, i32,
3837 padInterval,
false);
3838 padInterval = LLVM::SubOp::create(rewriter, loc, padInterval, consts[1]);
3840 return setValueAtOffset(rewriter, loc, sgpr0, padInterval, 22);
3843 Value setPadAmount(DescriptorOp op, OpAdaptor &adaptor,
3844 ConversionPatternRewriter &rewriter, Location loc,
3845 Value sgpr0, ArrayRef<Value> consts)
const {
3846 if (!op.getPadAmount())
3855 Value padAmount = adaptor.getPadAmount();
3856 padAmount = LLVM::SubOp::create(rewriter, loc, padAmount, consts[1]);
3858 return setValueAtOffset(rewriter, loc, sgpr0, padAmount, 25);
3861 Value setAtomicBarrierAddress(DescriptorOp op, OpAdaptor &adaptor,
3862 ConversionPatternRewriter &rewriter,
3863 Location loc, Value sgpr1,
3864 ArrayRef<Value> consts)
const {
3865 if (!adaptor.getAtomicBarrierAddress())
3868 Value atomicBarrierAddress = adaptor.getAtomicBarrierAddress();
3869 auto barrierAddressTy =
3870 cast<MemRefType>(op.getAtomicBarrierAddress().getType());
3871 ValueRange atomicBarrierIndices = adaptor.getAtomicBarrierIndices();
3873 rewriter, loc, barrierAddressTy, atomicBarrierAddress,
3874 atomicBarrierIndices);
3875 IntegerType i32 = rewriter.getI32Type();
3881 atomicBarrierAddress =
3882 LLVM::PtrToIntOp::create(rewriter, loc, i32, atomicBarrierAddress);
3883 atomicBarrierAddress =
3884 LLVM::LShrOp::create(rewriter, loc, atomicBarrierAddress, consts[3]);
3886 atomicBarrierAddress =
3887 LLVM::AndOp::create(rewriter, loc, atomicBarrierAddress, mask);
3888 return setValueAtOffset(rewriter, loc, sgpr1, atomicBarrierAddress, 32);
3891 std::pair<Value, Value> setTensorDimX(DescriptorOp op, OpAdaptor &adaptor,
3892 ConversionPatternRewriter &rewriter,
3893 Location loc, Value sgpr1, Value sgpr2,
3894 ArrayRef<Value> consts, uint64_t dimX,
3895 uint32_t offset)
const {
3896 ArrayRef<int64_t> globalStaticSizes = adaptor.getGlobalStaticSizes();
3897 ValueRange globalDynamicSizes = adaptor.getGlobalDynamicSizes();
3898 SmallVector<OpFoldResult> mixedGlobalSizes =
3900 if (mixedGlobalSizes.size() <= dimX)
3901 return {sgpr1, sgpr2};
3903 OpFoldResult tensorDimXOpFoldResult = *(mixedGlobalSizes.rbegin() + dimX);
3910 if (
auto attr = dyn_cast<Attribute>(tensorDimXOpFoldResult)) {
3914 IntegerType i32 = rewriter.getI32Type();
3915 tensorDimX = cast<Value>(tensorDimXOpFoldResult);
3916 tensorDimX = LLVM::TruncOp::create(rewriter, loc, i32, tensorDimX);
3919 sgpr1 = setValueAtOffset(rewriter, loc, sgpr1, tensorDimX, offset);
3922 Value tensorDimXHigh = LLVM::LShrOp::create(rewriter, loc, tensorDimX, c16);
3923 sgpr2 = setValueAtOffset(rewriter, loc, sgpr2, tensorDimXHigh, offset + 16);
3924 return {sgpr1, sgpr2};
3927 std::pair<Value, Value> setTensorDim0(DescriptorOp op, OpAdaptor &adaptor,
3928 ConversionPatternRewriter &rewriter,
3929 Location loc, Value sgpr1, Value sgpr2,
3930 ArrayRef<Value> consts)
const {
3931 return setTensorDimX(op, adaptor, rewriter, loc, sgpr1, sgpr2, consts, 0,
3935 std::pair<Value, Value> setTensorDim1(DescriptorOp op, OpAdaptor &adaptor,
3936 ConversionPatternRewriter &rewriter,
3937 Location loc, Value sgpr2, Value sgpr3,
3938 ArrayRef<Value> consts)
const {
3939 return setTensorDimX(op, adaptor, rewriter, loc, sgpr2, sgpr3, consts, 1,
3943 Value setTileDimX(DescriptorOp op, OpAdaptor &adaptor,
3944 ConversionPatternRewriter &rewriter, Location loc,
3945 Value sgpr, ArrayRef<Value> consts,
size_t dimX,
3946 int64_t offset)
const {
3947 ArrayRef<int64_t> sharedStaticSizes = adaptor.getSharedStaticSizes();
3948 ValueRange sharedDynamicSizes = adaptor.getSharedDynamicSizes();
3949 SmallVector<OpFoldResult> mixedSharedSizes =
3951 if (mixedSharedSizes.size() <= dimX)
3954 OpFoldResult tileDimXOpFoldResult = *(mixedSharedSizes.rbegin() + dimX);
3963 if (
auto attr = dyn_cast<Attribute>(tileDimXOpFoldResult)) {
3967 IntegerType i32 = rewriter.getI32Type();
3968 tileDimX = cast<Value>(tileDimXOpFoldResult);
3969 tileDimX = LLVM::TruncOp::create(rewriter, loc, i32, tileDimX);
3972 return setValueAtOffset(rewriter, loc, sgpr, tileDimX, offset);
3975 Value setTileDim0(DescriptorOp op, OpAdaptor &adaptor,
3976 ConversionPatternRewriter &rewriter, Location loc,
3977 Value sgpr3, ArrayRef<Value> consts)
const {
3978 return setTileDimX(op, adaptor, rewriter, loc, sgpr3, consts, 0, 112);
3981 Value setTileDim1(DescriptorOp op, OpAdaptor &adaptor,
3982 ConversionPatternRewriter &rewriter, Location loc,
3983 Value sgpr4, ArrayRef<Value> consts)
const {
3984 return setTileDimX(op, adaptor, rewriter, loc, sgpr4, consts, 1, 128);
3987 Value setValidIndices(DescriptorOp op, OpAdaptor &adaptor,
3988 ConversionPatternRewriter &rewriter, Location loc,
3989 Value sgpr4, ArrayRef<Value> consts)
const {
3990 auto type = cast<VectorType>(op.getIndices().getType());
3991 ArrayRef<int64_t> shape = type.getShape();
3992 assert(shape.size() == 1 &&
"expected shape to be of rank 1.");
3993 unsigned length = shape.back();
3994 assert(0 < length && length <= 16 &&
"expected length to be at most 16.");
3996 return setValueAtOffset(rewriter, loc, sgpr4, value, 128);
3999 Value setTileDim1OrValidIndices(DescriptorOp op, OpAdaptor &adaptor,
4000 ConversionPatternRewriter &rewriter,
4001 Location loc, Value sgpr4,
4002 ArrayRef<Value> consts)
const {
4003 if constexpr (DescriptorOp::isGather())
4004 return setValidIndices(op, adaptor, rewriter, loc, sgpr4, consts);
4005 return setTileDim1(op, adaptor, rewriter, loc, sgpr4, consts);
4008 Value setTileDim2(DescriptorOp op, OpAdaptor &adaptor,
4009 ConversionPatternRewriter &rewriter, Location loc,
4010 Value sgpr4, ArrayRef<Value> consts)
const {
4012 if constexpr (DescriptorOp::isGather())
4014 return setTileDimX(op, adaptor, rewriter, loc, sgpr4, consts, 2, 144);
4017 std::pair<Value, Value>
4018 setTensorDimXStride(DescriptorOp op, OpAdaptor &adaptor,
4019 ConversionPatternRewriter &rewriter, Location loc,
4020 Value sgprY, Value sgprZ, ArrayRef<Value> consts,
4021 size_t dimX, int64_t offset)
const {
4022 ArrayRef<int64_t> globalStaticStrides = adaptor.getGlobalStaticStrides();
4023 ValueRange globalDynamicStrides = adaptor.getGlobalDynamicStrides();
4024 SmallVector<OpFoldResult> mixedGlobalStrides =
4025 getMixedValues(globalStaticStrides, globalDynamicStrides, rewriter);
4027 if (mixedGlobalStrides.size() <= (dimX + 1))
4028 return {sgprY, sgprZ};
4030 OpFoldResult tensorDimXStrideOpFoldResult =
4031 *(mixedGlobalStrides.rbegin() + dimX + 1);
4036 Value tensorDimXStride;
4037 if (
auto attr = dyn_cast<Attribute>(tensorDimXStrideOpFoldResult))
4041 tensorDimXStride = cast<Value>(tensorDimXStrideOpFoldResult);
4043 constexpr int64_t first48bits = (1ll << 48) - 1;
4046 LLVM::AndOp::create(rewriter, loc, mask, tensorDimXStride);
4047 IntegerType i32 = rewriter.getI32Type();
4048 Value tensorDimXStrideLow =
4049 LLVM::TruncOp::create(rewriter, loc, i32, tensorDimXStride);
4050 sgprY = setValueAtOffset(rewriter, loc, sgprY, tensorDimXStrideLow, offset);
4052 int64_t shift = (offset % 32) == 0 ? 32 : offset % 32;
4054 Value tensorDimXStrideHigh =
4055 LLVM::LShrOp::create(rewriter, loc, tensorDimXStride, shiftVal);
4056 tensorDimXStrideHigh =
4057 LLVM::TruncOp::create(rewriter, loc, i32, tensorDimXStrideHigh);
4058 sgprZ = setValueAtOffset(rewriter, loc, sgprZ, tensorDimXStrideHigh,
4060 return {sgprY, sgprZ};
4063 std::pair<Value, Value>
4064 setTensorDim0Stride(DescriptorOp op, OpAdaptor &adaptor,
4065 ConversionPatternRewriter &rewriter, Location loc,
4066 Value sgpr5, Value sgpr6, ArrayRef<Value> consts)
const {
4067 return setTensorDimXStride(op, adaptor, rewriter, loc, sgpr5, sgpr6, consts,
4071 std::pair<Value, Value>
4072 setTensorDim1Stride(DescriptorOp op, OpAdaptor &adaptor,
4073 ConversionPatternRewriter &rewriter, Location loc,
4074 Value sgpr5, Value sgpr6, ArrayRef<Value> consts)
const {
4076 if constexpr (DescriptorOp::isGather())
4077 return {sgpr5, sgpr6};
4078 return setTensorDimXStride(op, adaptor, rewriter, loc, sgpr5, sgpr6, consts,
4082 Value getDGroup1(DescriptorOp op, OpAdaptor &adaptor,
4083 ConversionPatternRewriter &rewriter, Location loc,
4084 ArrayRef<Value> consts)
const {
4086 for (int64_t i = 0; i < 8; ++i) {
4087 sgprs[i] = consts[0];
4090 sgprs[0] = setWorkgroupMask(op, adaptor, rewriter, loc, sgprs[0]);
4091 sgprs[0] = setDataSize(op, adaptor, rewriter, loc, sgprs[0], consts);
4092 sgprs[0] = setAtomicBarrier(op, adaptor, rewriter, loc, sgprs[0], consts);
4093 sgprs[0] = setIterateEnable(op, adaptor, rewriter, loc, sgprs[0], consts);
4094 sgprs[0] = setPadEnable(op, adaptor, rewriter, loc, sgprs[0], consts);
4095 sgprs[0] = setEarlyTimeout(op, adaptor, rewriter, loc, sgprs[0], consts);
4096 sgprs[0] = setPadInterval(op, adaptor, rewriter, loc, sgprs[0], consts);
4097 sgprs[0] = setPadAmount(op, adaptor, rewriter, loc, sgprs[0], consts);
4100 setAtomicBarrierAddress(op, adaptor, rewriter, loc, sgprs[1], consts);
4101 std::tie(sgprs[1], sgprs[2]) =
4102 setTensorDim0(op, adaptor, rewriter, loc, sgprs[1], sgprs[2], consts);
4103 std::tie(sgprs[2], sgprs[3]) =
4104 setTensorDim1(op, adaptor, rewriter, loc, sgprs[2], sgprs[3], consts);
4106 sgprs[3] = setTileDim0(op, adaptor, rewriter, loc, sgprs[3], consts);
4108 setTileDim1OrValidIndices(op, adaptor, rewriter, loc, sgprs[4], consts);
4109 sgprs[4] = setTileDim2(op, adaptor, rewriter, loc, sgprs[4], consts);
4110 std::tie(sgprs[5], sgprs[6]) = setTensorDim0Stride(
4111 op, adaptor, rewriter, loc, sgprs[5], sgprs[6], consts);
4112 std::tie(sgprs[6], sgprs[7]) = setTensorDim1Stride(
4113 op, adaptor, rewriter, loc, sgprs[6], sgprs[7], consts);
4115 IntegerType i32 = rewriter.getI32Type();
4116 Type v8i32 = this->typeConverter->convertType(VectorType::get(8, i32));
4117 assert(v8i32 &&
"expected type conversion to succeed");
4118 Value dgroup1 = LLVM::PoisonOp::create(rewriter, loc, v8i32);
4120 for (
auto [sgpr, constant] : llvm::zip_equal(sgprs, consts)) {
4122 LLVM::InsertElementOp::create(rewriter, loc, dgroup1, sgpr, constant);
4128 Value setTensorDimX(DescriptorOp op, OpAdaptor &adaptor,
4129 ConversionPatternRewriter &rewriter, Location loc,
4130 Value sgpr0, ArrayRef<Value> consts, int64_t dimX,
4131 int64_t offset)
const {
4132 ArrayRef<int64_t> globalStaticSizes = adaptor.getGlobalStaticSizes();
4133 ValueRange globalDynamicSizes = adaptor.getGlobalDynamicSizes();
4134 SmallVector<OpFoldResult> mixedGlobalSizes =
4136 if (mixedGlobalSizes.size() <=
static_cast<unsigned long>(dimX))
4139 OpFoldResult tensorDimXOpFoldResult = *(mixedGlobalSizes.rbegin() + dimX);
4141 if (
auto attr = dyn_cast<Attribute>(tensorDimXOpFoldResult)) {
4145 IntegerType i32 = rewriter.getI32Type();
4146 tensorDimX = cast<Value>(tensorDimXOpFoldResult);
4147 tensorDimX = LLVM::TruncOp::create(rewriter, loc, i32, tensorDimX);
4150 return setValueAtOffset(rewriter, loc, sgpr0, tensorDimX, offset);
4153 Value setTensorDim2(DescriptorOp op, OpAdaptor &adaptor,
4154 ConversionPatternRewriter &rewriter, Location loc,
4155 Value sgpr0, ArrayRef<Value> consts)
const {
4156 return setTensorDimX(op, adaptor, rewriter, loc, sgpr0, consts, 2, 0);
4159 Value truncateAndSetValueAtOffset(ConversionPatternRewriter &rewriter,
4160 Location loc, Value accumulator,
4161 Value value, int64_t shift)
const {
4163 IntegerType i32 = rewriter.getI32Type();
4164 value = LLVM::TruncOp::create(rewriter, loc, i32, value);
4165 return setValueAtOffset(rewriter, loc, accumulator, value, shift);
4168 Value setLDSAddrIncrement(DescriptorOp op, OpAdaptor &adaptor,
4169 ConversionPatternRewriter &rewriter, Location loc,
4170 Value sgpr1, ArrayRef<Value> consts,
4171 int64_t offset)
const {
4172 Value ldsAddrIncrement = adaptor.getLdsIncrement();
4173 return setValueAtOffset(rewriter, loc, sgpr1, ldsAddrIncrement, offset);
4176 std::pair<Value, Value>
4177 setGlobalAddrIncrement(DescriptorOp op, OpAdaptor &adaptor,
4178 ConversionPatternRewriter &rewriter, Location loc,
4179 Value sgpr2, Value sgpr3, ArrayRef<Value> consts,
4180 int64_t offset)
const {
4181 Value globalAddrIncrement = adaptor.getGlobalIncrement();
4182 sgpr2 = truncateAndSetValueAtOffset(rewriter, loc, sgpr2,
4183 globalAddrIncrement, offset);
4185 globalAddrIncrement =
4186 LLVM::LShrOp::create(rewriter, loc, globalAddrIncrement, shift);
4187 constexpr int64_t first16BitsHigh = (1ll << 16) - 1;
4188 sgpr3 = truncateAndSetValueAtOffset(rewriter, loc, sgpr3,
4189 globalAddrIncrement, offset + 32);
4191 sgpr3 = LLVM::AndOp::create(rewriter, loc, sgpr3, mask);
4192 return {sgpr2, sgpr3};
4195 Value setTensorDim3OrLDSAddrIncrement(DescriptorOp op, OpAdaptor &adaptor,
4196 ConversionPatternRewriter &rewriter,
4197 Location loc, Value sgpr1,
4198 ArrayRef<Value> consts)
const {
4199 Value ldsIncrement = op.getLdsIncrement();
4200 constexpr int64_t dim = 3;
4201 constexpr int64_t offset = 32;
4203 return setTensorDimX(op, adaptor, rewriter, loc, sgpr1, consts, dim,
4205 return setLDSAddrIncrement(op, adaptor, rewriter, loc, sgpr1, consts,
4209 std::pair<Value, Value> setTensorDim2StrideOrGlobalAddrIncrement(
4210 DescriptorOp op, OpAdaptor &adaptor, ConversionPatternRewriter &rewriter,
4211 Location loc, Value sgpr2, Value sgpr3, ArrayRef<Value> consts)
const {
4212 Value globalIncrement = op.getGlobalIncrement();
4213 constexpr int32_t dim = 2;
4214 constexpr int32_t offset = 64;
4215 if (!globalIncrement)
4216 return setTensorDimXStride(op, adaptor, rewriter, loc, sgpr2, sgpr3,
4217 consts, dim, offset);
4218 return setGlobalAddrIncrement(op, adaptor, rewriter, loc, sgpr2, sgpr3,
4222 Value setIterateCount(DescriptorOp op, OpAdaptor &adaptor,
4223 ConversionPatternRewriter &rewriter, Location loc,
4224 Value sgpr3, ArrayRef<Value> consts,
4225 int32_t offset)
const {
4226 Value iterationCount = adaptor.getIterationCount();
4227 IntegerType i32 = rewriter.getI32Type();
4234 iterationCount = LLVM::TruncOp::create(rewriter, loc, i32, iterationCount);
4236 LLVM::SubOp::create(rewriter, loc, iterationCount, consts[1]);
4237 return setValueAtOffset(rewriter, loc, sgpr3, iterationCount, offset);
4240 Value setTileDim3OrIterateCount(DescriptorOp op, OpAdaptor &adaptor,
4241 ConversionPatternRewriter &rewriter,
4242 Location loc, Value sgpr3,
4243 ArrayRef<Value> consts)
const {
4244 Value iterateCount = op.getIterationCount();
4245 constexpr int32_t dim = 2;
4246 constexpr int32_t offset = 112;
4248 return setTileDimX(op, adaptor, rewriter, loc, sgpr3, consts, dim,
4251 return setIterateCount(op, adaptor, rewriter, loc, sgpr3, consts, offset);
4254 Value getDGroup2(DescriptorOp op, OpAdaptor &adaptor,
4255 ConversionPatternRewriter &rewriter, Location loc,
4256 ArrayRef<Value> consts)
const {
4257 if constexpr (DescriptorOp::isGather())
4258 return getDGroup2Gather(op, adaptor, rewriter, loc, consts);
4259 return getDGroup2NonGather(op, adaptor, rewriter, loc, consts);
4262 Value getDGroup2NonGather(DescriptorOp op, OpAdaptor &adaptor,
4263 ConversionPatternRewriter &rewriter, Location loc,
4264 ArrayRef<Value> consts)
const {
4265 IntegerType i32 = rewriter.getI32Type();
4266 Type v4i32 = this->typeConverter->convertType(VectorType::get(4, i32));
4267 assert(v4i32 &&
"expected type conversion to succeed.");
4269 bool onlyNeedsTwoDescriptors = !op.getLdsIncrement() && op.getRank() <= 2;
4270 if (onlyNeedsTwoDescriptors)
4271 return LLVM::ZeroOp::create(rewriter, loc, v4i32);
4273 constexpr int64_t sgprlen = 4;
4274 Value sgprs[sgprlen];
4275 for (
int i = 0; i < sgprlen; ++i)
4276 sgprs[i] = consts[0];
4278 sgprs[0] = setTensorDim2(op, adaptor, rewriter, loc, sgprs[0], consts);
4279 sgprs[1] = setTensorDim3OrLDSAddrIncrement(op, adaptor, rewriter, loc,
4281 std::tie(sgprs[2], sgprs[3]) = setTensorDim2StrideOrGlobalAddrIncrement(
4282 op, adaptor, rewriter, loc, sgprs[2], sgprs[3], consts);
4284 setTileDim3OrIterateCount(op, adaptor, rewriter, loc, sgprs[3], consts);
4286 Value dgroup2 = LLVM::PoisonOp::create(rewriter, loc, v4i32);
4287 for (
auto [sgpr, constant] : llvm::zip(sgprs, consts))
4289 LLVM::InsertElementOp::create(rewriter, loc, dgroup2, sgpr, constant);
4294 Value getGatherIndices(DescriptorOp op, OpAdaptor &adaptor,
4295 ConversionPatternRewriter &rewriter, Location loc,
4296 ArrayRef<Value> consts,
bool firstHalf)
const {
4297 IntegerType i32 = rewriter.getI32Type();
4298 Type v4i32 = this->typeConverter->convertType(VectorType::get(4, i32));
4299 assert(v4i32 &&
"expected type conversion to succeed.");
4301 Value
indices = adaptor.getIndices();
4302 auto vectorType = cast<VectorType>(
indices.getType());
4303 unsigned length = vectorType.getShape().back();
4304 Type elementType = vectorType.getElementType();
4305 unsigned maxLength = elementType == i32 ? 4 : 8;
4306 int32_t offset = firstHalf ? 0 : maxLength;
4307 unsigned discountedLength =
4308 std::max(
static_cast<int32_t
>(length - offset), 0);
4310 unsigned targetSize = std::min(maxLength, discountedLength);
4312 SmallVector<Value> indicesVector;
4313 for (
unsigned i = offset; i < targetSize + offset; ++i) {
4315 if (i < consts.size())
4319 Value elem = LLVM::ExtractElementOp::create(rewriter, loc,
indices, idx);
4320 indicesVector.push_back(elem);
4323 SmallVector<Value> indicesI32Vector;
4324 if (elementType == i32) {
4325 indicesI32Vector = std::move(indicesVector);
4327 for (
unsigned i = 0; i < targetSize; ++i) {
4328 Value index = indicesVector[i];
4329 indicesI32Vector.push_back(
4330 LLVM::ZExtOp::create(rewriter, loc, i32, index));
4332 if ((targetSize % 2) != 0)
4334 indicesI32Vector.push_back(consts[0]);
4337 SmallVector<Value> indicesToInsert;
4338 if (elementType == i32) {
4339 indicesToInsert = std::move(indicesI32Vector);
4341 unsigned size = indicesI32Vector.size() / 2;
4342 for (
unsigned i = 0; i < size; ++i) {
4343 Value first = indicesI32Vector[2 * i];
4344 Value second = indicesI32Vector[2 * i + 1];
4345 Value joined = setValueAtOffset(rewriter, loc, first, second, 16);
4346 indicesToInsert.push_back(joined);
4350 Value dgroup = LLVM::PoisonOp::create(rewriter, loc, v4i32);
4351 for (
auto [sgpr, constant] : llvm::zip_first(indicesToInsert, consts))
4353 LLVM::InsertElementOp::create(rewriter, loc, dgroup, sgpr, constant);
4358 Value getDGroup2Gather(DescriptorOp op, OpAdaptor &adaptor,
4359 ConversionPatternRewriter &rewriter, Location loc,
4360 ArrayRef<Value> consts)
const {
4361 return getGatherIndices(op, adaptor, rewriter, loc, consts,
true);
4364 std::pair<Value, Value>
4365 setTensorDim3Stride(DescriptorOp op, OpAdaptor &adaptor,
4366 ConversionPatternRewriter &rewriter, Location loc,
4367 Value sgpr0, Value sgpr1, ArrayRef<Value> consts)
const {
4368 constexpr int32_t dim = 3;
4369 constexpr int32_t offset = 0;
4370 return setTensorDimXStride(op, adaptor, rewriter, loc, sgpr0, sgpr1, consts,
4374 std::pair<Value, Value> setTensorDim4(DescriptorOp op, OpAdaptor &adaptor,
4375 ConversionPatternRewriter &rewriter,
4376 Location loc, Value sgpr1, Value sgpr2,
4377 ArrayRef<Value> consts)
const {
4378 constexpr int32_t dim = 4;
4379 constexpr int32_t offset = 48;
4380 return setTensorDimX(op, adaptor, rewriter, loc, sgpr1, sgpr2, consts, dim,
4384 Value setTileDim4(DescriptorOp op, OpAdaptor &adaptor,
4385 ConversionPatternRewriter &rewriter, Location loc,
4386 Value sgpr2, ArrayRef<Value> consts)
const {
4387 constexpr int32_t dim = 4;
4388 constexpr int32_t offset = 80;
4389 return setTileDimX(op, adaptor, rewriter, loc, sgpr2, consts, dim, offset);
4392 Value getDGroup3(DescriptorOp op, OpAdaptor &adaptor,
4393 ConversionPatternRewriter &rewriter, Location loc,
4394 ArrayRef<Value> consts)
const {
4395 if constexpr (DescriptorOp::isGather())
4396 return getDGroup3Gather(op, adaptor, rewriter, loc, consts);
4397 return getDGroup3NonGather(op, adaptor, rewriter, loc, consts);
4400 Value getDGroup3NonGather(DescriptorOp op, OpAdaptor &adaptor,
4401 ConversionPatternRewriter &rewriter, Location loc,
4402 ArrayRef<Value> consts)
const {
4403 IntegerType i32 = rewriter.getI32Type();
4404 Type v4i32 = this->typeConverter->convertType(VectorType::get(4, i32));
4405 assert(v4i32 &&
"expected type conversion to succeed.");
4406 bool onlyNeedsTwoDescriptors = !op.getLdsIncrement() && op.getRank() <= 2;
4407 if (onlyNeedsTwoDescriptors)
4408 return LLVM::ZeroOp::create(rewriter, loc, v4i32);
4410 constexpr int32_t sgprlen = 4;
4411 Value sgprs[sgprlen];
4412 for (
int i = 0; i < sgprlen; ++i)
4413 sgprs[i] = consts[0];
4415 std::tie(sgprs[0], sgprs[1]) = setTensorDim3Stride(
4416 op, adaptor, rewriter, loc, sgprs[0], sgprs[1], consts);
4417 std::tie(sgprs[1], sgprs[2]) =
4418 setTensorDim4(op, adaptor, rewriter, loc, sgprs[1], sgprs[2], consts);
4419 sgprs[2] = setTileDim4(op, adaptor, rewriter, loc, sgprs[2], consts);
4421 Value dgroup3 = LLVM::PoisonOp::create(rewriter, loc, v4i32);
4422 for (
auto [sgpr, constant] : llvm::zip(sgprs, consts))
4424 LLVM::InsertElementOp::create(rewriter, loc, dgroup3, sgpr, constant);
4429 Value getDGroup3Gather(DescriptorOp op, OpAdaptor &adaptor,
4430 ConversionPatternRewriter &rewriter, Location loc,
4431 ArrayRef<Value> consts)
const {
4432 return getGatherIndices(op, adaptor, rewriter, loc, consts,
false);
4436 matchAndRewrite(DescriptorOp op, OpAdaptor adaptor,
4437 ConversionPatternRewriter &rewriter)
const override {
4438 if (!
target.has(llvm::AMDGPU::FEAT_GFX1250_INSTS))
4439 return op->emitOpError(
4440 "make_dma_descriptor is only supported on gfx1250");
4442 Location loc = op.getLoc();
4444 SmallVector<Value> consts;
4445 for (int64_t i = 0; i < 8; ++i)
4448 Value dgroup0 = this->getDGroup0(adaptor);
4449 Value dgroup1 = this->getDGroup1(op, adaptor, rewriter, loc, consts);
4450 Value dgroup2 = this->getDGroup2(op, adaptor, rewriter, loc, consts);
4451 Value dgroup3 = this->getDGroup3(op, adaptor, rewriter, loc, consts);
4452 SmallVector<Value> results = {dgroup0, dgroup1, dgroup2, dgroup3};
4453 rewriter.replaceOpWithMultiple(op, {results});
4458template <
typename SourceOp,
typename TargetOp>
4459struct AMDGPUTensorLoadStoreOpLowering
4460 :
public ConvertOpToLLVMPattern<SourceOp> {
4461 using ConvertOpToLLVMPattern<SourceOp>::ConvertOpToLLVMPattern;
4463 AMDGPUTensorLoadStoreOpLowering(
const LLVMTypeConverter &converter,
4464 const ROCDL::TargetInfo &
target)
4465 : ConvertOpToLLVMPattern<SourceOp>(converter),
target(
target) {}
4466 ROCDL::TargetInfo
target;
4469 matchAndRewrite(SourceOp op, Adaptor adaptor,
4470 ConversionPatternRewriter &rewriter)
const override {
4471 if (!
target.has(llvm::AMDGPU::FEAT_GFX1250_INSTS))
4472 return op->emitOpError(
"is only supported on gfx1250");
4477 auto v8i32 = VectorType::get(8, rewriter.getI32Type());
4478 Value dgroup4 = LLVM::ZeroOp::create(rewriter, op.getLoc(), v8i32);
4479 Attribute cachePolicy = rewriter.getI32IntegerAttr(0);
4480 rewriter.replaceOpWithNewOp<TargetOp>(op, desc[0], desc[1], desc[2],
4481 desc[3], dgroup4, cachePolicy,
4489struct GlobalPrefetchOpLowering
4490 :
public ConvertOpToLLVMPattern<GlobalPrefetchOp> {
4491 GlobalPrefetchOpLowering(
const LLVMTypeConverter &converter,
4492 const ROCDL::TargetInfo &
target)
4493 : ConvertOpToLLVMPattern<GlobalPrefetchOp>(converter),
target(
target) {}
4496 matchAndRewrite(GlobalPrefetchOp op, GlobalPrefetchOpAdaptor adaptor,
4497 ConversionPatternRewriter &rewriter)
const override {
4498 if (!
target.has(llvm::AMDGPU::FEAT_GFX1250_INSTS))
4499 return op->emitOpError(
"is only supported on gfx1250+");
4501 const bool isSpeculative = op.getSpeculative();
4503 op.getTemporalHint(), op.getCacheScope(), isSpeculative);
4506 Attribute cachePolicy = ROCDL::Gfx12CachePolicyAttr::get(
4507 rewriter.getContext(),
4508 static_cast<ROCDL::Gfx12CachePolicy
>(immArgValue));
4511 Value memRef = adaptor.getSrc();
4512 MemRefDescriptor descriptor(memRef);
4513 MemRefType memRefType = op.getSrc().getType();
4514 Location loc = op->getLoc();
4515 auto inboundsFlags = isSpeculative ? LLVM::GEPNoWrapFlags::none
4516 : LLVM::GEPNoWrapFlags::inbounds |
4517 LLVM::GEPNoWrapFlags::nuw;
4519 rewriter, loc, memRefType, descriptor,
indices, inboundsFlags);
4521 rewriter.replaceOpWithNewOp<ROCDL::GlobalPrefetchOp>(
4522 op, prefetchPtr, cachePolicy, mlir::ArrayAttr{}, mlir::ArrayAttr{},
4528 ROCDL::TargetInfo
target;
4531struct ConvertAMDGPUToROCDLPass
4532 :
public impl::ConvertAMDGPUToROCDLPassBase<ConvertAMDGPUToROCDLPass> {
4535 void runOnOperation()
override {
4539 0, [&] {
return emitError(UnknownLoc::get(ctx)); });
4541 return signalPassFailure();
4543 RewritePatternSet patterns(ctx);
4544 LLVMTypeConverter converter(ctx);
4549 target.addIllegalDialect<::mlir::amdgpu::AMDGPUDialect>();
4550 target.addLegalDialect<::mlir::LLVM::LLVMDialect>();
4551 target.addLegalDialect<::mlir::ROCDL::ROCDLDialect>();
4552 if (
failed(applyPartialConversion(getOperation(),
target,
4553 std::move(patterns))))
4554 signalPassFailure();
4562 typeConverter, [](gpu::AddressSpace space) {
4564 case gpu::AddressSpace::Global:
4565 return ROCDL::ROCDLDialect::kGlobalMemoryAddressSpace;
4566 case gpu::AddressSpace::Workgroup:
4567 return ROCDL::ROCDLDialect::kSharedMemoryAddressSpace;
4568 case gpu::AddressSpace::Private:
4569 return ROCDL::ROCDLDialect::kPrivateMemoryAddressSpace;
4570 case gpu::AddressSpace::Constant:
4571 return ROCDL::ROCDLDialect::kConstantMemoryAddressSpace;
4573 llvm_unreachable(
"unknown address space enum value");
4576 return LLVM::LLVMPointerType::get(
4577 type.getContext(), ROCDL::ROCDLDialect::kBarrierAddressSpace);
4583 typeConverter.addTypeAttributeConversion(
4585 -> TypeConverter::AttributeConversionResult {
4587 Type i64 = IntegerType::get(ctx, 64);
4588 switch (as.getValue()) {
4589 case amdgpu::AddressSpace::FatRawBuffer:
4590 return IntegerAttr::get(i64, 7);
4591 case amdgpu::AddressSpace::BufferRsrc:
4592 return IntegerAttr::get(i64, 8);
4593 case amdgpu::AddressSpace::FatStructuredBuffer:
4594 return IntegerAttr::get(i64, 9);
4596 return TypeConverter::AttributeConversionResult::abort();
4598 typeConverter.addConversion([&](DsBarrierStateType type) ->
Type {
4599 return IntegerType::get(type.
getContext(), 64);
4601 typeConverter.addConversion([&](TDMBaseType type) ->
Type {
4603 return typeConverter.convertType(VectorType::get(4, i32));
4605 typeConverter.addConversion([&](TDMGatherBaseType type) ->
Type {
4607 return typeConverter.convertType(VectorType::get(4, i32));
4609 typeConverter.addConversion(
4610 [&](TDMDescriptorType type,
4613 Type v4i32 = typeConverter.convertType(VectorType::get(4, i32));
4614 Type v8i32 = typeConverter.convertType(VectorType::get(8, i32));
4615 llvm::append_values(
result, v4i32, v8i32, v4i32, v4i32);
4625 if (inputs.size() != 1)
4628 if (!isa<TDMDescriptorType>(inputs[0].
getType()))
4631 auto cast = UnrealizedConversionCastOp::create(builder, loc, types, inputs);
4632 return cast.getResults();
4635 typeConverter.addTargetMaterialization(addUnrealizedCast);
4643 .
add<FatRawBufferCastLowering,
4644 RawBufferOpLowering<RawBufferLoadOp, ROCDL::RawPtrBufferLoadOp>,
4645 RawBufferOpLowering<RawBufferStoreOp, ROCDL::RawPtrBufferStoreOp>,
4646 RawBufferOpLowering<RawBufferAtomicFaddOp,
4647 ROCDL::RawPtrBufferAtomicFaddOp>,
4648 RawBufferOpLowering<RawBufferAtomicFmaxOp,
4649 ROCDL::RawPtrBufferAtomicFmaxOp>,
4650 RawBufferOpLowering<RawBufferAtomicSmaxOp,
4651 ROCDL::RawPtrBufferAtomicSmaxOp>,
4652 RawBufferOpLowering<RawBufferAtomicUminOp,
4653 ROCDL::RawPtrBufferAtomicUminOp>,
4654 RawBufferOpLowering<RawBufferAtomicCmpswapOp,
4655 ROCDL::RawPtrBufferAtomicCmpSwap>,
4656 AMDGPUDPPLowering, MemoryCounterWaitOpLowering, LDSBarrierOpLowering,
4657 SchedBarrierOpLowering, MFMAOpLowering, ScaledMFMAOpLowering,
4658 SparseMFMAOpLowering, WMMAOpLowering, ScaledWMMAOpLowering,
4659 SparseWMMAOpLowering, DotOpLowering, ExtPackedFp8OpLowering,
4660 ScaledExtPackedMatrixOpLowering, ScaledExtPackedOpLowering,
4661 PackedScaledTruncOpLowering, PackedTrunc2xFp8OpLowering,
4662 PackedStochRoundFp8OpLowering, GatherToLDSOpLowering,
4663 GlobalLoadAsyncToLDSOpLowering, TransposeLoadOpLowering,
4664 GlobalTransposeLoadOpLowering, AMDGPUPermlaneLowering,
4665 AMDGPUPermlaneVarLowering, AMDGPUMakeDmaBaseLowering<MakeDmaBaseOp>,
4666 AMDGPUMakeDmaBaseLowering<MakeGatherDmaBaseOp>,
4667 AMDGPULowerDescriptor<MakeDmaDescriptorOp>,
4668 AMDGPULowerDescriptor<MakeGatherDmaDescriptorOp>,
4669 AMDGPUTensorLoadStoreOpLowering<TensorLoadToLDSOp,
4670 ROCDL::TensorLoadToLDSOp>,
4671 AMDGPUTensorLoadStoreOpLowering<TensorStoreFromLDSOp,
4672 ROCDL::TensorStoreFromLDSOp>,
4673 DsBarrierInitOpLowering, DsBarrierPollStateOpLowering,
4674 DsAsyncBarrierArriveOpLowering, DsBarrierArriveOpLowering,
4675 GlobalPrefetchOpLowering>(converter,
target);
4676 patterns.
add<AMDGPUSwizzleBitModeLowering, DsBarrierStatePhaseOpLowering,
4677 DsBarrierStatePendingCountOpLowering,
4678 DsBarrierStateInitCountOpLowering,
4679 DsBarrierStatePhaseParityLowering>(converter);
static std::optional< StringRef > wmmaOpToIntrinsicRDNA(Type elemSourceType, Type elemBSourceType, Type elemDestType, uint32_t k, bool isRDNA3)
Returns the rocdl intrinsic corresponding to a WMMA operation wmma for RDNA3/4 architectures.
static std::optional< StringRef > wmmaOpToIntrinsic(WMMAOp wmma, const ROCDL::TargetInfo &target)
Returns the rocdl intrinsic corresponding to a WMMA operation wmma if one exists.
static bool typeIsExpectedFp8ForTarget(const ROCDL::TargetInfo &target, Type type)
Return true if type is the E4M3FN variant of an 8-bit float that is supported by the _fp8 instruction...
static Value convertUnsignedToInt(ConversionPatternRewriter &rewriter, Location loc, Value val, unsigned width)
Zero-extend or truncate the unsigned number val to width bits.
static void wmmaPushInputOperand(ConversionPatternRewriter &rewriter, Location loc, const TypeConverter *typeConverter, bool isUnsigned, Value llvmInput, Value mlirInput, SmallVectorImpl< Value > &operands, SmallVectorImpl< NamedAttribute > &attrs, StringRef attrName)
Push an input operand.
static Value castScaleOperand(ConversionPatternRewriter &rewriter, Location loc, Value input)
Converts the scaled MFMA/WMMA operands, scalesA and scalesB, from MLIR AMDGPU dialect convention to R...
static std::optional< StringRef > getScaledWmmaIntrinsicName(int64_t m, int64_t n, int64_t k, bool isScale16)
Determines the ROCDL intrinsic name for scaled WMMA based on dimensions and scale block size (16 or 3...
static void wmmaPushOutputOperand(ConversionPatternRewriter &rewriter, Location loc, const TypeConverter *typeConverter, Value output, int32_t subwordOffset, bool clamp, SmallVectorImpl< Value > &operands, SmallVectorImpl< NamedAttribute > &attrs)
Push the output operand.
static std::optional< StringRef > smfmacOpToIntrinsic(SparseMFMAOp op, const ROCDL::TargetInfo &target)
Returns the rocdl intrinsic corresponding to a SparseMFMA (smfmac) operation if one exists.
static Value createI64Constant(ConversionPatternRewriter &rewriter, Location loc, int64_t value)
static Value getNumRecords(ConversionPatternRewriter &rewriter, Location loc, MemRefType memrefType, MemRefDescriptor &memrefDescriptor, ArrayRef< int64_t > strides, int64_t elementByteWidth, unsigned numRecordsWidth, bool boundsCheck)
Compute the contents of the num_records field for a given memref descriptor - that is,...
static std::optional< StringRef > wmmaOpToIntrinsicGfx1250(Type elemSourceType, Type elemBSourceType, Type elemDestType, uint32_t k)
Return the rocdl intrinsic corresponding to a WMMA operation wmma for the gfx1250 architecture.
static Value packSmallFloatVectorOperand(ConversionPatternRewriter &rewriter, Location loc, Value input, bool allowBf16=true)
Pack small float vector operands (fp4/fp6/fp8/bf16) into the format expected by scaled matrix multipl...
static bool typeIsExpectedBf8ForTarget(const ROCDL::TargetInfo &target, Type type)
Return true if type is the E5M2 variant of an 8-bit float that is supported by the _bf8 instructions ...
static std::optional< ROCDL::WMMAMatrixScaleFormat > getWmmaScaleFormat(Type elemType)
Maps f8 scale element types to WMMA scale format codes.
static Value convertPackedVectorOperand(ConversionPatternRewriter &rewriter, Location loc, Value input, bool allowBf16=true)
Converts packed vector operands to the expected ROCDL types.
static Value getLinearIndexI32(ConversionPatternRewriter &rewriter, Location loc, MemRefDescriptor &memRefDescriptor, ValueRange indices, ArrayRef< int64_t > strides)
Returns the linear index used to access an element in the memref.
static Value convertUnsignedToI32(ConversionPatternRewriter &rewriter, Location loc, Value val)
Convert an unsigned number val to i32.
static std::optional< StringRef > mfmaOpToIntrinsic(MFMAOp mfma, const ROCDL::TargetInfo &target)
Return the rocdl intrinsic corresponding to a MFMA operation mfma if one exists.
static Value createI32Constant(ConversionPatternRewriter &rewriter, Location loc, int32_t value)
static std::optional< ROCDL::MatrixFormat > smallFloatTypeToMatrixFormat(Type mlirElemType)
static std::optional< SparseWMMAOpInfo > sparseWMMAOpToIntrinsic(SparseWMMAOp swmmac, const ROCDL::TargetInfo &target)
std::tuple< StringRef, ROCDL::MatrixFormat, ROCDL::MatrixFormat > ScaledMFMAIntrinsic
If there is a scaled MFMA instruction for the input element types aType and bType,...
static std::optional< ScaledMFMAIntrinsic > mfmaOpToScaledIntrinsic(Type aType, Type bType, Type destType, uint32_t m, uint32_t n, uint32_t k, uint32_t b, const ROCDL::TargetInfo &target)
static Value convertUnsignedToI64(ConversionPatternRewriter &rewriter, Location loc, Value val)
Convert an unsigned number val to i64.
static Value makeBufferRsrc(ConversionPatternRewriter &rewriter, Location loc, Value basePointer, Value numRecords, bool boundsCheck, const ROCDL::TargetInfo &target, unsigned numRecordsWidth, Value cacheSwizzleStride=nullptr, unsigned addressSpace=8)
*if copies could not be generated due to yet unimplemented cases *copyInPlacementStart and copyOutPlacementStart in copyPlacementBlock *specify the insertion points where the incoming copies and outgoing should be the output argument nBegin is set to its * replacement(set to `begin` if no invalidation happens). Since outgoing *copies could have been inserted at `end`
static constexpr unsigned kSizePosInMemRefDescriptor
static constexpr unsigned kStridePosInMemRefDescriptor
static constexpr unsigned kOffsetPosInMemRefDescriptor
static constexpr unsigned kAllocatedPtrPosInMemRefDescriptor
static constexpr unsigned kAlignedPtrPosInMemRefDescriptor
static Value clamp(ImplicitLocOpBuilder &builder, Value value, Value lowerBound, Value upperBound)
Attributes are known-constant values of operations.
This class provides a shared interface for ranked and unranked memref types.
Utility class for operation conversions targeting the LLVM dialect that match exactly one source oper...
ConvertOpToLLVMPattern(const LLVMTypeConverter &typeConverter, PatternBenefit benefit=1)
typename SourceOp::template GenericAdaptor< ArrayRef< ValueRange > > OneToNOpAdaptor
typename SourceOp::Adaptor OpAdaptor
Value getStridedElementPtr(ConversionPatternRewriter &rewriter, Location loc, MemRefType type, Value memRefDesc, ValueRange indices, LLVM::GEPNoWrapFlags noWrapFlags=LLVM::GEPNoWrapFlags::none) const
Convenience wrapper for the corresponding helper utility.
llvm::TypeSize getTypeSizeInBits(Type t) const
Returns the size in bits of the given type in the current scope.
Conversion from types to the LLVM IR dialect.
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.
Helper class to produce LLVM dialect operations extracting or inserting elements of a MemRef descript...
Value stride(OpBuilder &builder, Location loc, unsigned pos)
Builds IR extracting the pos-th size from the descriptor.
Value size(OpBuilder &builder, Location loc, unsigned pos)
Builds IR extracting the pos-th size from the descriptor.
NamedAttribute represents a combination of a name and an Attribute value.
This class helps build Operations.
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
result_range getResults()
unsigned getNumResults()
Return the number of results held by this operation.
Describes the AMDGPU target a lowering is producing code for: the triple's subarch (which identifies ...
static FailureOr< TargetInfo > get(StringRef arch, unsigned waveSize=0, function_ref< InFlightDiagnostic()> emitError=nullptr)
Resolves a target description.
RewritePatternSet & add(ConstructorArg &&arg, ConstructorArgs &&...args)
Add an instance of each of the pattern types 'Ts' to the pattern list with the given arguments.
This class provides an abstraction over the various different ranges of value types.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
MLIRContext * getContext() const
Return the MLIRContext in which this type was uniqued.
bool isSignedInteger() const
Return true if this is a signed integer type (with the specified width).
bool isUnsignedInteger() const
Return true if this is an unsigned integer type (with the specified width).
bool isInteger() const
Return true if this is an integer type (with the specified width).
unsigned getIntOrFloatBitWidth() const
Return the bit width of an integer or a float type, assert failure on other types.
This class provides an abstraction over the different types of ranges over Values.
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.
Value getStridedElementPtr(OpBuilder &builder, Location loc, const LLVMTypeConverter &converter, MemRefType type, Value memRefDesc, ValueRange indices, LLVM::GEPNoWrapFlags noWrapFlags=LLVM::GEPNoWrapFlags::none)
Performs the index computation to get to the element at indices of the memory pointed to by memRefDes...
LogicalResult decomposeValue(OpBuilder &builder, Location loc, Value src, Type dstType, SmallVectorImpl< Value > &result, bool permitVariablySizedScalars=false)
Decomposes a src value into a set of values of type dstType through series of bitcasts and vector ops...
Value createIndexAttrConstant(OpBuilder &builder, Location loc, Type resultType, int64_t value)
Creates an llvm.mlir.constant producing value as resultType, which is expected to be the converted in...
Value composeValue(OpBuilder &builder, Location loc, ValueRange src, Type dstType)
Composes a set of src values into a single value of type dstType through series of bitcasts and vecto...
StringRef resolveArchOption(StringRef arch, StringRef deprecatedAlias)
Returns the target architecture that a pass should parse, given its arch option and the value of the ...
int32_t getGlobalPrefetchLLVMEncoding(amdgpu::LoadTemporalHint hint, amdgpu::Scope scope, bool isSpeculative)
void populateCommonGPUTypeAndAttributeConversions(TypeConverter &typeConverter)
Remap common GPU memory spaces (Workgroup, Private, etc) to LLVM address spaces.
Include the generated interface declarations.
bool matchPattern(Value value, const Pattern &pattern)
Entry point for matching a pattern over a Value.
SmallVector< OpFoldResult > getMixedValues(ArrayRef< int64_t > staticValues, ValueRange dynamicValues, MLIRContext *context)
Return a vector of OpFoldResults with the same size a staticValues, but all elements for which Shaped...
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
detail::constant_int_predicate_matcher m_Zero()
Matches a constant scalar / vector splat / tensor splat integer zero.
Type getElementTypeOrSelf(Type type)
Return the element type or return the type itself.
void populateAMDGPUToROCDLConversionPatterns(LLVMTypeConverter &converter, RewritePatternSet &patterns, const ROCDL::TargetInfo &target)
Note: This function will also add conversions for the AMDGPU-specific address spaces and types,...
void populateGpuMemorySpaceAttributeConversions(TypeConverter &typeConverter, const MemorySpaceMapping &mapping)
Populates memory space attribute conversion rules for lowering gpu.address_space to integer values.
llvm::TypeSwitch< T, ResultT > TypeSwitch
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
void populateAMDGPUTypeAndAttributeConversions(TypeConverter &typeConverter)
Remap AMDGPU memory spaces to LLVM address spaces by mapping amdgpu::AddressSpace::fat_raw_buffer to ...
Returns the rocdl intrinsic corresponding to a SparseWMMA operation swmmac if one exists.