32#include "llvm/ADT/STLExtras.h"
33#include "llvm/ADT/TypeSwitch.h"
34#include "llvm/IR/IRBuilder.h"
35#include "llvm/IR/NVVMIntrinsicUtils.h"
36#include "llvm/Support/Casting.h"
37#include "llvm/Support/FormatVariadic.h"
38#include "llvm/Support/NVPTXAddrSpace.h"
39#include "llvm/Support/raw_ostream.h"
48#include "mlir/Dialect/LLVMIR/NVVMOpsDialect.cpp.inc"
49#include "mlir/Dialect/LLVMIR/NVVMOpsEnums.cpp.inc"
51static constexpr unsigned notIntrinsic = llvm::Intrinsic::not_intrinsic;
58 auto ptrTy = llvm::cast<LLVM::LLVMPointerType>(
ptr.getType());
59 return ptrTy.getAddressSpace() ==
static_cast<unsigned>(targetAS);
76 NVVMMemorySpace targetAS) {
77 unsigned AS =
static_cast<unsigned>(targetAS);
78 return builder.CreateAddrSpaceCast(
79 ptr, llvm::PointerType::get(builder.getContext(), AS));
83static llvm::nvvm::CTAGroupKind
86 case NVVM::CTAGroupKind::CTA_1:
87 return llvm::nvvm::CTAGroupKind::CG_1;
88 case NVVM::CTAGroupKind::CTA_2:
89 return llvm::nvvm::CTAGroupKind::CG_2;
91 llvm_unreachable(
"unsupported cta_group value");
103 size_t numIm2ColOffsets,
105 if (tensorDims < 1 || tensorDims > 5)
106 return emitError(loc,
"expects coordinates between 1 to 5 dimension");
114 "to use im2col mode, the tensor has to be at least 3-dimensional");
116 if (numIm2ColOffsets && (tensorDims != (numIm2ColOffsets + 2)))
118 loc,
"im2col offsets must be 2 less than number of coordinates");
123LogicalResult CpAsyncBulkTensorSharedCTAToGlobalOp::verify() {
124 TMAStoreMode mode = getMode();
128 if (getPredicate()) {
129 if (mode != TMAStoreMode::TILE)
130 return emitError(
"Inline-ptx lowering supported only for Tile mode.");
131 if (getL2CacheHint())
132 return emitError(
"Inline-ptx lowering unsupported with L2 cache-hint.");
137 case TMAStoreMode::TILE:
139 case TMAStoreMode::IM2COL:
141 case TMAStoreMode::TILE_SCATTER4:
143 return emitError(
"Scatter4 mode expects 5 coordinates");
148LogicalResult CpAsyncOp::verify() {
149 if (getModifier() != LoadCacheModifierKind::CG &&
150 getModifier() != LoadCacheModifierKind::CA)
151 return emitError(
"Only CG and CA cache modifiers are supported.");
152 if (getSize() != 4 && getSize() != 8 && getSize() != 16)
153 return emitError(
"expected byte size to be either 4, 8 or 16.");
154 if (getModifier() == LoadCacheModifierKind::CG && getSize() != 16)
155 return emitError(
"CG cache modifier is only support for 16 bytes copy.");
162 if (tensorDims < 1 || tensorDims > 5)
163 return emitError(loc,
"expects coordinates between 1 to 5 dimension");
165 auto checkTMALoadParams = [&](TMALoadMode mode,
bool isIm2col,
166 size_t expectedIm2colOff) -> LogicalResult {
167 if (isIm2col && (tensorDims < 3))
170 <<
" mode, the tensor has to be at least 3-dimensional";
172 if (numIm2colOff != expectedIm2colOff)
173 return emitError(loc) <<
" im2col offsets expected " << expectedIm2colOff
174 <<
" (provided " << numIm2colOff <<
")";
180 case TMALoadMode::TILE:
181 return checkTMALoadParams(mode,
false, 0);
182 case TMALoadMode::IM2COL:
183 return checkTMALoadParams(mode,
true, tensorDims - 2);
184 case TMALoadMode::IM2COL_W:
185 case TMALoadMode::IM2COL_W_128:
186 return checkTMALoadParams(mode,
true, 2);
187 case TMALoadMode::TILE_GATHER4:
188 return (tensorDims == 5)
189 ? checkTMALoadParams(mode,
false, 0)
190 :
emitError(loc,
"Gather4 mode expects 5 coordinates");
195LogicalResult CpAsyncBulkTensorPrefetchOp::verify() {
197 getMode(), getLoc());
200LogicalResult CpAsyncBulkTensorGlobalToSharedClusterOp::verify() {
201 TMALoadMode mode = getMode();
202 bool isCTAOnly = getIsCTAOnly();
203 if (getPredicate()) {
205 return emitError(
"Predicate is supported only for shared::cluster mode.");
206 if (mode != TMALoadMode::TILE && mode != TMALoadMode::IM2COL)
208 "Predicate is supported only for Tile and Im2col modes.");
210 NVVMMemorySpace expectedAS =
211 isCTAOnly ? NVVMMemorySpace::Shared : NVVMMemorySpace::SharedCluster;
212 unsigned AS = llvm::cast<LLVM::LLVMPointerType>(getDstMem().
getType())
214 if (AS != expectedAS)
217 ?
"Shared::cta destination requires address-space 3."
218 :
"Shared::cluster destination requires address-space 7.");
221 if (getMulticastMask())
222 return emitError(
"Multicast is not supported with shared::cta mode.");
224 return emitError(
"CTAGroup is not supported with shared::cta mode.");
229 getMode(), getLoc());
232LogicalResult CpAsyncBulkTensorReduceOp::verify() {
233 TMAStoreMode mode = getMode();
236 case TMAStoreMode::TILE:
238 case TMAStoreMode::IM2COL:
240 case TMAStoreMode::TILE_SCATTER4:
241 return emitError(
"Scatter mode unsupported for CpAsyncBulkTensorReduceOp");
246LogicalResult CpAsyncBulkGlobalToSharedClusterOp::verify() {
248 if (isSharedCTA && getMulticastMask())
249 return emitError(
"Multicast is not supported with shared::cta mode.");
255 NVVM::MemScopeKind scope,
256 Value retVal =
nullptr) {
257 if (scope != NVVM::MemScopeKind::CTA && scope != NVVM::MemScopeKind::CLUSTER)
258 return op->
emitError(
"mbarrier scope must be either CTA or Cluster");
261 bool hasRetValue =
static_cast<bool>(retVal);
262 if (isSharedCluster && hasRetValue)
264 "mbarrier in shared_cluster space cannot return any value");
269LogicalResult MBarrierArriveOp::verify() {
274LogicalResult MBarrierArriveDropOp::verify() {
279LogicalResult MBarrierArriveExpectTxOp::verify() {
283 if (getPredicate()) {
284 if (getScope() != NVVM::MemScopeKind::CTA)
285 return emitError(
"mbarrier scope must be CTA when using predicate");
288 return emitError(
"mbarrier in shared_cluster space is not supported when "
292 return emitError(
"return-value is not supported when using predicate");
294 if (getRelaxed() ==
true)
295 return emitError(
"mbarrier with relaxed semantics is not supported when "
302LogicalResult MBarrierArriveDropExpectTxOp::verify() {
317 inferredReturnTypes.push_back(IntegerType::get(context, 64));
322MBarrierArriveOp::inferReturnTypes(
MLIRContext *context,
323 std::optional<Location> location,
324 MBarrierArriveOp::Adaptor adaptor,
327 inferredReturnTypes);
330LogicalResult MBarrierArriveDropOp::inferReturnTypes(
331 MLIRContext *context, std::optional<Location> location,
332 MBarrierArriveDropOp::Adaptor adaptor,
335 inferredReturnTypes);
338LogicalResult MBarrierArriveExpectTxOp::inferReturnTypes(
339 MLIRContext *context, std::optional<Location> location,
340 MBarrierArriveExpectTxOp::Adaptor adaptor,
344 if (adaptor.getPredicate())
347 inferredReturnTypes);
350LogicalResult MBarrierArriveDropExpectTxOp::inferReturnTypes(
351 MLIRContext *context, std::optional<Location> location,
352 MBarrierArriveDropExpectTxOp::Adaptor adaptor,
355 inferredReturnTypes);
365 return inferred == actual;
374bool MBarrierArriveExpectTxOp::isCompatibleReturnTypes(
TypeRange l,
378bool MBarrierArriveDropExpectTxOp::isCompatibleReturnTypes(
TypeRange l,
383LogicalResult MBarrierExpectTxOp::verify() {
387LogicalResult MBarrierCompleteTxOp::verify() {
391LogicalResult MBarrierTestWaitOp::verify() {
395LogicalResult MBarrierTryWaitOp::verify() {
399LogicalResult ConvertFloatToTF32Op::verify() {
400 using RndMode = NVVM::FPRoundingMode;
404 return emitError(
"Relu not supported with rna rounding mode.");
411 "Only {rn,rz,rna} rounding modes supported for ConvertFloatToTF32Op.");
416LogicalResult ConvertF32x2ToF6x2Op::verify() {
419 if (!llvm::isa<mlir::Float6E2M3FNType, mlir::Float6E3M2FNType>(getDstTy())) {
421 << mlir::Float6E2M3FNType::get(ctx) <<
" and "
422 << mlir::Float6E3M2FNType::get(ctx)
423 <<
" types are supported for conversions from f32x2 to f6x2.";
428LogicalResult ConvertF32x2ToF8x2Op::verify() {
429 using RndMode = NVVM::FPRoundingMode;
430 using SatMode = NVVM::SaturationMode;
432 bool isRoundingModeRN = getRnd() == RndMode::RN;
433 bool isRoundingModeRZ = getRnd() == RndMode::RZ;
434 bool isRoundingModeRP = getRnd() == RndMode::RP;
435 bool isSatFinite = getSat() == SatMode::SATFINITE;
437 bool hasRelu = getRelu();
442 .Case<mlir::Float8E4M3FNType, mlir::Float8E5M2Type>(
444 if (!isRoundingModeRN) {
445 return emitOpError(
"Only RN rounding mode is supported for "
446 "conversions from f32x2 to ")
447 << mlir::Float8E4M3FNType::get(ctx) <<
" and "
448 << mlir::Float8E5M2Type::get(ctx) <<
" types";
451 return emitOpError(
"Only SATFINITE saturation mode is supported "
454 << mlir::Float8E4M3FNType::get(ctx) <<
" and "
455 << mlir::Float8E5M2Type::get(ctx) <<
" types";
459 .Case<mlir::Float8E8M0FNUType>([&](
mlir::Type) -> LogicalResult {
460 if (!(isRoundingModeRZ || isRoundingModeRP)) {
461 return emitOpError(
"Only RZ and RP rounding modes are supported for "
462 "conversions from f32x2 to ")
463 << mlir::Float8E8M0FNUType::get(ctx) <<
" type";
466 return emitOpError(
"relu not supported for conversions to ")
467 << mlir::Float8E8M0FNUType::get(ctx) <<
" type";
473 << mlir::Float8E4M3FNType::get(ctx) <<
", "
474 << mlir::Float8E5M2Type::get(ctx) <<
", and "
475 << mlir::Float8E8M0FNUType::get(ctx)
477 "supported for conversions from f32x2 to f8x2";
481LogicalResult ConvertF16x2ToF8x2Op::verify() {
484 if (!llvm::isa<mlir::Float8E4M3FNType, mlir::Float8E5M2Type>(getDstTy())) {
486 << mlir::Float8E4M3FNType::get(ctx) <<
" and "
487 << mlir::Float8E5M2Type::get(ctx)
488 <<
" types are supported for conversions from f16x2 to f8x2.";
493LogicalResult ConvertBF16x2ToF8x2Op::verify() {
494 using RndMode = NVVM::FPRoundingMode;
495 using SatMode = NVVM::SaturationMode;
497 bool isRoundingModeRN = getRnd() == RndMode::RN;
498 bool isRoundingModeRZ = getRnd() == RndMode::RZ;
499 bool isRoundingModeRP = getRnd() == RndMode::RP;
500 bool isSatFinite = getSat() == SatMode::SATFINITE;
501 bool hasRelu = getRelu();
506 .Case<mlir::Float8E4M3FNType, mlir::Float8E5M2Type>(
508 if (!isRoundingModeRN)
509 return emitOpError(
"Only RN rounding mode is supported for "
510 "conversions from bf16x2 to ")
511 << mlir::Float8E4M3FNType::get(ctx) <<
" and "
512 << mlir::Float8E5M2Type::get(ctx) <<
" types";
514 return emitOpError(
"Only SATFINITE saturation mode is supported "
515 "for conversions from bf16x2 to ")
516 << mlir::Float8E4M3FNType::get(ctx) <<
" and "
517 << mlir::Float8E5M2Type::get(ctx) <<
" types";
520 .Case<mlir::Float8E8M0FNUType>([&](
mlir::Type) -> LogicalResult {
521 if (!(isRoundingModeRZ || isRoundingModeRP))
522 return emitOpError(
"Only RZ and RP rounding modes are supported for "
523 "conversions from bf16x2 to ")
524 << mlir::Float8E8M0FNUType::get(ctx) <<
" type";
526 return emitOpError(
"relu not supported for conversions to ")
527 << mlir::Float8E8M0FNUType::get(ctx) <<
" type";
531 llvm_unreachable(
"Invalid conversion in ConvertBF16x2ToF8x2Op");
536LogicalResult ConvertF32x2ToF4x2Op::verify() {
539 if (!llvm::isa<mlir::Float4E2M1FNType>(getDstTy()))
541 << mlir::Float4E2M1FNType::get(ctx)
542 <<
" type is supported for conversions from f32x2 to f4x2.";
547LogicalResult ConvertF8x2ToBF16x2Op::verify() {
549 if (llvm::isa<Float8E8M0FNUType>(getSrcType())) {
550 if (getSat() != SaturationMode::NONE)
552 "Only NONE saturation mode is supported for conversions from ")
553 << Float8E8M0FNUType::get(ctx) <<
" type";
554 if (getScaleFactor())
555 return emitOpError(
"scaleFactor not supported for conversions from ")
556 << Float8E8M0FNUType::get(ctx) <<
" type";
558 return emitOpError(
"relu not supported for conversions from ")
559 << Float8E8M0FNUType::get(ctx) <<
" type";
565LogicalResult PermuteOp::verify() {
566 using Mode = NVVM::PermuteMode;
567 bool hasHi =
static_cast<bool>(getHi());
574 return emitError(
"mode '") << getMode() <<
"' requires 'hi' operand.";
582 << getMode() <<
"' does not accept 'hi' operand.";
597 static constexpr FPRoundingMode validRndModes[] = {
598 FPRoundingMode::RN, FPRoundingMode::RZ, FPRoundingMode::RS};
600 if (!llvm::is_contained(validRndModes, rnd)) {
602 "Only RN, RZ, and RS rounding modes are supported for "
603 "conversions from f32x2 to ")
607 if (rnd == FPRoundingMode::RS) {
608 if (!hasRandomBits) {
609 return op->
emitOpError(
"random_bits is required for RS rounding mode.");
614 "random_bits not supported for RN and RZ rounding modes.");
621LogicalResult ConvertF32x2ToF16x2Op::verify() {
623 getRandomBits() ?
true :
false, *
this);
626LogicalResult ConvertF32x2ToBF16x2Op::verify() {
628 getRandomBits() ?
true :
false, *
this);
631LogicalResult ConvertF32x4ToF8x4Op::verify() {
634 if (!llvm::isa<mlir::Float8E4M3FNType, mlir::Float8E5M2Type>(getDstTy()))
636 << mlir::Float8E4M3FNType::get(ctx) <<
" and "
637 << mlir::Float8E5M2Type::get(ctx)
638 <<
" types are supported for conversions from f32x4 to f8x4.";
643LogicalResult ConvertF32x4ToF6x4Op::verify() {
646 if (!llvm::isa<mlir::Float6E2M3FNType, mlir::Float6E3M2FNType>(getDstTy()))
648 << mlir::Float6E2M3FNType::get(ctx) <<
" and "
649 << mlir::Float6E3M2FNType::get(ctx)
650 <<
" types are supported for conversions from f32x4 to f6x4.";
655LogicalResult ConvertF32x4ToF4x4Op::verify() {
658 if (!llvm::isa<mlir::Float4E2M1FNType>(getDstTy()))
659 return emitOpError(
"Only ") << mlir::Float4E2M1FNType::get(ctx)
660 <<
" type is supported for conversions from "
666LogicalResult BulkStoreOp::verify() {
667 if (getInitVal() != 0)
668 return emitOpError(
"only 0 is supported for initVal, got ") << getInitVal();
672LogicalResult PMEventOp::verify() {
673 auto eventId = getEventId();
674 auto maskedEventId = getMaskedEventId();
675 if (!maskedEventId && !eventId) {
676 return emitOpError() <<
"either `id` or `mask` must be set";
679 if (maskedEventId && eventId) {
680 return emitOpError() <<
"`id` and `mask` cannot be set at the same time";
684 if (eventId < 0 || eventId > 15) {
685 return emitOpError() <<
"`id` must be between 0 and 15";
689 return llvm::success();
695std::optional<mlir::NVVM::MMATypes>
696MmaOp::inferOperandMMAType(
Type operandElType,
bool isAccumulator) {
698 VectorType::get(2, Float16Type::get(operandElType.
getContext()));
699 if (operandElType.
isF64())
700 return NVVM::MMATypes::f64;
701 if (operandElType.
isF16() || operandElType == half2Type)
702 return NVVM::MMATypes::f16;
703 if (operandElType.
isF32() && isAccumulator)
704 return NVVM::MMATypes::f32;
705 if (operandElType.
isF32() && !isAccumulator)
706 return NVVM::MMATypes::tf32;
707 if (llvm::isa<IntegerType>(operandElType)) {
709 return NVVM::MMATypes::s32;
713 if (
auto structType = llvm::dyn_cast<LLVM::LLVMStructType>(operandElType)) {
714 if (structType.getBody().empty())
716 return inferOperandMMAType(structType.getBody()[0], isAccumulator);
723 return (type == MMATypes::u4 || type == MMATypes::s4);
727 return (type == MMATypes::u8 || type == MMATypes::s8);
732 type == MMATypes::s32;
735MMATypes MmaOp::accumPtxType() {
736 std::optional<mlir::NVVM::MMATypes> val = inferOperandMMAType(
737 getODSOperands(2).getTypes().front(),
true);
738 assert(val.has_value() &&
"accumulator PTX type should always be inferrable");
742MMATypes MmaOp::resultPtxType() {
743 std::optional<mlir::NVVM::MMATypes> val =
744 inferOperandMMAType(getResult().
getType(),
true);
745 assert(val.has_value() &&
"result PTX type should always be inferrable");
751 struct MMAOperandFragment {
752 StringRef operandName;
753 StringRef ptxTypeAttr;
754 SmallVector<Value, 4> regs;
755 explicit MMAOperandFragment(StringRef name, StringRef ptxTypeName)
756 : operandName(name), ptxTypeAttr(ptxTypeName) {}
759 std::array<MMAOperandFragment, 3> frags{
760 MMAOperandFragment(
"A", getMultiplicandAPtxTypeAttrName()),
761 MMAOperandFragment(
"B", getMultiplicandBPtxTypeAttrName()),
762 MMAOperandFragment(
"C",
"")};
764 mlir::NVVM::MmaOp::getOperandSegmentSizeAttr()};
766 for (
unsigned fragIdx = 0; fragIdx < frags.size(); fragIdx++) {
767 auto &frag = frags[fragIdx];
768 auto varOperandSpec = getODSOperandIndexAndLength(fragIdx);
769 for (
auto operandIdx = varOperandSpec.first;
770 operandIdx < varOperandSpec.first + varOperandSpec.second;
772 frag.regs.push_back(this->getOperand(operandIdx));
773 if (operandIdx == 0) {
774 regTypes.push_back(this->getOperand(operandIdx).
getType());
777 std::optional<MMATypes> inferredType = MmaOp::inferOperandMMAType(
778 regTypes.back(), fragIdx >= 2);
780 ignoreAttrNames.push_back(frag.ptxTypeAttr);
783 auto printMmaOperand = [&](
const MMAOperandFragment &frag) ->
void {
784 p <<
" " << frag.operandName;
790 for (
const auto &frag : frags) {
791 printMmaOperand(frag);
799 frags[1].regs[0].getType(),
800 frags[2].regs[0].getType()},
809 std::optional<MMAIntOverflow> intOverflow,
810 std::optional<std::array<MMATypes, 2>> multiplicandPtxTypes,
811 std::optional<std::array<MMALayout, 2>> multiplicandLayouts) {
813 assert(
shape.size() == 3 &&
"expected shape to have size 3 (m, n, k)");
818 result.addOperands(operandA);
819 result.addOperands(operandB);
820 result.addOperands(operandC);
822 if (multiplicandPtxTypes) {
823 result.addAttribute(
"multiplicandAPtxType",
824 MMATypesAttr::get(ctx, (*multiplicandPtxTypes)[0]));
825 result.addAttribute(
"multiplicandBPtxType",
826 MMATypesAttr::get(ctx, (*multiplicandPtxTypes)[1]));
828 if (
auto res = inferOperandMMAType(operandA[0].
getType(),
false))
829 result.addAttribute(
"multiplicandAPtxType", MMATypesAttr::get(ctx, *res));
830 if (
auto res = inferOperandMMAType(operandB[0].
getType(),
false))
831 result.addAttribute(
"multiplicandBPtxType", MMATypesAttr::get(ctx, *res));
834 if (multiplicandLayouts) {
835 result.addAttribute(
"layoutA",
836 MMALayoutAttr::get(ctx, (*multiplicandLayouts)[0]));
837 result.addAttribute(
"layoutB",
838 MMALayoutAttr::get(ctx, (*multiplicandLayouts)[1]));
840 result.addAttribute(
"layoutA", MMALayoutAttr::get(ctx, MMALayout::row));
841 result.addAttribute(
"layoutB", MMALayoutAttr::get(ctx, MMALayout::col));
844 if (intOverflow.has_value())
845 result.addAttribute(
"intOverflowBehavior",
846 MMAIntOverflowAttr::get(ctx, *intOverflow));
847 if (b1Op.has_value())
848 result.addAttribute(
"b1Op", MMAB1OpAttr::get(ctx, *b1Op));
850 result.addTypes(resultType);
852 MmaOp::getOperandSegmentSizeAttr(),
854 static_cast<int32_t>(operandB.size()),
855 static_cast<int32_t>(operandC.size())}));
863 struct MMAOperandFragment {
864 std::optional<MMATypes> elemtype;
865 SmallVector<OpAsmParser::UnresolvedOperand, 4> regs;
866 SmallVector<Type> regTypes;
870 std::array<MMAOperandFragment, 4> frags;
876 MMAOperandFragment &frag) -> LogicalResult {
906 if (operandTypes.size() != 3)
909 "expected one type for each operand segment but got " +
910 Twine(operandTypes.size()) +
" types");
911 for (
const auto &iter : llvm::enumerate(operandTypes)) {
912 auto &frag = frags[iter.index()];
913 frag.regTypes.resize(frag.regs.size(), iter.value());
917 frag.elemtype = inferOperandMMAType(frag.regTypes[0],
924 frags[3].elemtype = inferOperandMMAType(resultType,
true);
926 std::array<StringRef, 2> names{
"multiplicandAPtxType",
927 "multiplicandBPtxType"};
928 for (
unsigned idx = 0; idx < names.size(); idx++) {
929 const auto &frag = frags[idx];
930 std::optional<NamedAttribute> attr = namedAttributes.
getNamed(names[idx]);
931 if (!frag.elemtype.has_value() && !attr.has_value()) {
934 "attribute " + names[idx] +
935 " is not provided explicitly and cannot be inferred");
937 if (!attr.has_value())
939 names[idx], MMATypesAttr::get(parser.
getContext(), *frag.elemtype));
942 result.addTypes(resultType);
943 if (!namedAttributes.
empty())
944 result.addAttributes(namedAttributes);
945 result.addAttribute(MmaOp::getOperandSegmentSizeAttr(),
947 static_cast<int32_t>(frags[0].regs.size()),
948 static_cast<int32_t>(frags[1].regs.size()),
949 static_cast<int32_t>(frags[2].regs.size()),
954LogicalResult MmaOp::verify() {
956 auto f16Ty = Float16Type::get(context);
957 auto i32Ty = IntegerType::get(context, 32);
958 auto f16x2Ty = VectorType::get(2, f16Ty);
959 auto f32Ty = Float32Type::get(context);
960 auto f16x2x4StructTy = LLVM::LLVMStructType::getLiteral(
961 context, {f16x2Ty, f16x2Ty, f16x2Ty, f16x2Ty});
964 LLVM::LLVMStructType::getLiteral(context, {i32Ty, i32Ty, i32Ty, i32Ty});
967 auto f16x2x2StructTy =
968 LLVM::LLVMStructType::getLiteral(context, {f16x2Ty, f16x2Ty});
970 LLVM::LLVMStructType::getLiteral(context, {f32Ty, f32Ty, f32Ty, f32Ty});
972 LLVM::LLVMStructType::getLiteral(context, {i32Ty, i32Ty});
974 std::array<int64_t, 3> mmaShape{getShapeAttr().getM(), getShapeAttr().getN(),
975 getShapeAttr().getK()};
981 AllowedShapes allowedShapes;
982 AllowedTypes expectedA;
983 AllowedTypes expectedB;
984 AllowedTypes expectedC;
989 if (mmaShape[0] == 16) {
991 Type multiplicandFragType;
992 switch (*getMultiplicandAPtxType()) {
995 multiplicandFragType = i32Ty;
996 expectedResult.push_back(LLVM::LLVMStructType::getLiteral(
997 context, {f32Ty, f32Ty, f32Ty, f32Ty}));
1001 multiplicandFragType = i32Ty;
1002 expectedResult.push_back(LLVM::LLVMStructType::getLiteral(
1003 context, {f32Ty, f32Ty, f32Ty, f32Ty}));
1007 multiplicandFragType = f16x2Ty;
1008 expectedResult.push_back(f16x2x2StructTy);
1009 expectedResult.push_back(f32x4StructTy);
1011 case MMATypes::e4m3:
1012 case MMATypes::e5m2:
1016 multiplicandFragType = i32Ty;
1017 expectedResult.push_back(f16x2x2StructTy);
1018 expectedResult.push_back(f32x4StructTy);
1032 return emitError(
"invalid shape or multiplicand type: ")
1033 << getMultiplicandAPtxType().value();
1037 expectedResult.push_back(s32x4StructTy);
1038 expectedC.emplace_back(4, i32Ty);
1039 multiplicandFragType = i32Ty;
1041 expectedC.emplace_back(2, f16x2Ty);
1042 expectedC.emplace_back(4, f32Ty);
1045 int64_t unitA = (mmaShape[0] / 8) * (mmaShape[2] / kFactor);
1046 int64_t unitB = (mmaShape[1] / 8) * (mmaShape[2] / kFactor);
1047 expectedA.emplace_back(unitA, multiplicandFragType);
1048 expectedB.emplace_back(unitB, multiplicandFragType);
1049 allowedShapes.push_back({16, 8, kFactor});
1050 allowedShapes.push_back({16, 8, kFactor * 2});
1052 if (resultPtxType() != accumPtxType())
1057 if (mmaShape[0] == 8) {
1058 if (*getMultiplicandAPtxType() == MMATypes::f16) {
1059 expectedA.emplace_back(2, f16x2Ty);
1060 expectedB.emplace_back(2, f16x2Ty);
1061 expectedResult.push_back(f16x2x4StructTy);
1062 expectedResult.push_back(f32x8StructTy);
1063 expectedC.emplace_back(4, f16x2Ty);
1064 expectedC.emplace_back(8, f32Ty);
1065 allowedShapes.push_back({8, 8, 4});
1067 if (*getMultiplicandAPtxType() == MMATypes::f64) {
1068 Type f64Ty = Float64Type::get(context);
1069 expectedA.emplace_back(1, f64Ty);
1070 expectedB.emplace_back(1, f64Ty);
1071 expectedC.emplace_back(2, f64Ty);
1072 expectedResult.emplace_back(LLVM::LLVMStructType::getLiteral(
1074 allowedShapes.push_back({8, 8, 4});
1077 expectedA.push_back({i32Ty});
1078 expectedB.push_back({i32Ty});
1079 expectedC.push_back({i32Ty, i32Ty});
1080 expectedResult.push_back(s32x2StructTy);
1082 allowedShapes.push_back({8, 8, 32});
1084 allowedShapes.push_back({8, 8, 16});
1085 if (getMultiplicandAPtxType().value() == MMATypes::b1)
1086 allowedShapes.push_back({8, 8, 128});
1090 std::string errorMessage;
1091 llvm::raw_string_ostream errorStream(errorMessage);
1094 if (expectedA.empty() || expectedB.empty() || expectedC.empty() ||
1095 !llvm::is_contained(allowedShapes, mmaShape)) {
1096 errorStream <<
"unimplemented variant for MMA shape <";
1097 llvm::interleaveComma(mmaShape, errorStream);
1103 std::array<StringRef, 3> operandNames{
"A",
"B",
"C"};
1104 for (
const auto &iter : llvm::enumerate(
1106 auto spec = this->getODSOperandIndexAndLength(iter.index());
1108 operand_type_begin() + spec.first +
1110 bool match = llvm::is_contained(iter.value(), operandTySeg);
1113 errorStream <<
"Could not match types for the "
1114 << operandNames[iter.index()]
1115 <<
" operands; expected one of ";
1116 for (
const auto &x : iter.value()) {
1117 errorStream << x.size() <<
"x" << x[0] <<
" ";
1119 errorStream <<
"but got ";
1120 llvm::interleaveComma(operandTySeg, errorStream);
1126 if (!llvm::any_of(expectedResult, [&](
Type expectedResultType) {
1127 return expectedResultType == getResult().getType();
1130 <<
"Could not match allowed types for the result; expected one of ";
1131 llvm::interleaveComma(expectedResult, errorStream);
1132 errorStream <<
" but got " << getResult().getType();
1137 if (getMultiplicandAPtxType() == MMATypes::b1 && !getB1Op()) {
1138 return emitOpError(
"op requires " + getB1OpAttrName().strref() +
1146 if (!getIntOverflowBehavior())
1148 getIntOverflowBehaviorAttrName().strref() +
1156 (mmaShape[0] == 8 && mmaShape[1] == 8 && mmaShape[2] == 4 &&
1157 getMultiplicandAPtxType() == MMATypes::f16);
1159 if (!isM8N8K4_F16) {
1161 if (getLayoutA() != MMALayout::row || getLayoutB() != MMALayout::col) {
1162 return emitOpError(
"requires layoutA = #nvvm.mma_layout<row> and "
1163 "layoutB = #nvvm.mma_layout<col> for shape <")
1164 << mmaShape[0] <<
", " << mmaShape[1] <<
", " << mmaShape[2]
1165 <<
"> with element types " << *getMultiplicandAPtxType() <<
" and "
1166 << *getMultiplicandBPtxType()
1167 <<
". Only m8n8k4 with f16 supports other layouts.";
1174MMATypes MmaSpOp::accumPtxType() {
1175 std::optional<mlir::NVVM::MMATypes> val = MmaOp::inferOperandMMAType(
1176 getODSOperands(2).getTypes().front(),
true);
1177 assert(val.has_value() &&
"accumulator PTX type should always be inferrable");
1181MMATypes MmaSpOp::resultPtxType() {
1182 std::optional<mlir::NVVM::MMATypes> val =
1183 MmaOp::inferOperandMMAType(getResult().
getType(),
true);
1184 assert(val.has_value() &&
"result PTX type should always be inferrable");
1190 llvm::IRBuilderBase &builder) {
1191 auto thisOp = cast<NVVM::MmaSpOp>(op);
1199 auto intId = MmaSpOp::getIntrinsicID(
1200 thisOp.getShape().getM(), thisOp.getShape().getN(),
1201 thisOp.getShape().getK(), thisOp.getIntOverflowBehavior(),
1202 thisOp.getOrderedMetadata(), thisOp.getKind(),
1203 *thisOp.getMultiplicandAPtxType(), *thisOp.getMultiplicandBPtxType(),
1204 thisOp.accumPtxType(), thisOp.resultPtxType());
1206 return {intId, args};
1211 struct MMAOperandFragment {
1212 StringRef operandName;
1213 StringRef ptxTypeAttr;
1214 SmallVector<Value, 4> regs;
1215 explicit MMAOperandFragment(StringRef name, StringRef ptxTypeName)
1216 : operandName(name), ptxTypeAttr(ptxTypeName) {}
1219 std::array<MMAOperandFragment, 5> frags{
1220 MMAOperandFragment(
"A", getMultiplicandAPtxTypeAttrName()),
1221 MMAOperandFragment(
"B", getMultiplicandBPtxTypeAttrName()),
1222 MMAOperandFragment(
"C",
""), MMAOperandFragment(
"sparseMetadata",
""),
1223 MMAOperandFragment(
"selector",
"")};
1225 mlir::NVVM::MmaSpOp::getOperandSegmentSizeAttr()};
1228 for (
unsigned fragIdx = 0; fragIdx < 3; fragIdx++) {
1229 auto &frag = frags[fragIdx];
1230 auto varOperandSpec = getODSOperandIndexAndLength(fragIdx);
1231 for (
auto operandIdx = varOperandSpec.first;
1232 operandIdx < varOperandSpec.first + varOperandSpec.second;
1234 frag.regs.push_back(this->getOperand(operandIdx));
1235 if (operandIdx == varOperandSpec.first) {
1236 regTypes.push_back(this->getOperand(operandIdx).
getType());
1239 std::optional<MMATypes> inferredType = MmaOp::inferOperandMMAType(
1240 regTypes.back(), fragIdx >= 2);
1242 ignoreAttrNames.push_back(frag.ptxTypeAttr);
1246 frags[3].regs.push_back(getSparseMetadata());
1247 frags[4].regs.push_back(getSparsitySelector());
1249 auto printMmaSpOperand = [&](
const MMAOperandFragment &frag) ->
void {
1250 p <<
" " << frag.operandName;
1256 for (
const auto &frag : frags)
1257 printMmaSpOperand(frag);
1262 for (
int i = 0; i < 3; ++i) {
1267 p <<
") -> " << getResult().getType();
1274 std::optional<MMAIntOverflow> intOverflow,
1275 std::optional<std::array<MMATypes, 2>> multiplicandPtxTypes) {
1277 assert(
shape.size() == 3 &&
"expected shape to have size 3 (m, n, k)");
1282 result.addOperands(operandA);
1283 result.addOperands(operandB);
1284 result.addOperands(operandC);
1285 result.addOperands(sparseMetadata);
1286 result.addOperands(sparsitySelector);
1288 if (multiplicandPtxTypes) {
1289 result.addAttribute(
"multiplicandAPtxType",
1290 MMATypesAttr::get(ctx, (*multiplicandPtxTypes)[0]));
1291 result.addAttribute(
"multiplicandBPtxType",
1292 MMATypesAttr::get(ctx, (*multiplicandPtxTypes)[1]));
1294 if (
auto res = MmaOp::inferOperandMMAType(operandA[0].
getType(),
false))
1295 result.addAttribute(
"multiplicandAPtxType", MMATypesAttr::get(ctx, *res));
1296 if (
auto res = MmaOp::inferOperandMMAType(operandB[0].
getType(),
false))
1297 result.addAttribute(
"multiplicandBPtxType", MMATypesAttr::get(ctx, *res));
1300 if (intOverflow.has_value())
1301 result.addAttribute(
"intOverflowBehavior",
1302 MMAIntOverflowAttr::get(ctx, *intOverflow));
1304 result.addTypes(resultType);
1306 MmaSpOp::getOperandSegmentSizeAttr(),
1308 static_cast<int32_t>(operandB.size()),
1309 static_cast<int32_t>(operandC.size()), 1,
1314 struct MMAOperandFragment {
1315 std::optional<MMATypes> elemtype;
1316 SmallVector<OpAsmParser::UnresolvedOperand, 4> regs;
1317 SmallVector<Type> regTypes;
1321 std::array<MMAOperandFragment, 6> frags;
1326 auto parseMmaSpOperand = [&](StringRef operandName,
1327 MMAOperandFragment &frag) -> LogicalResult {
1338 if (parseMmaSpOperand(
"A", frags[0]).
failed())
1340 if (parseMmaSpOperand(
"B", frags[1]).
failed())
1342 if (parseMmaSpOperand(
"C", frags[2]).
failed())
1344 if (parseMmaSpOperand(
"sparseMetadata", frags[3]).
failed())
1346 if (parseMmaSpOperand(
"selector", frags[4]).
failed())
1362 if (operandTypes.size() != 3)
1365 "expected one type for each operand segment but got " +
1366 Twine(operandTypes.size()) +
" types");
1367 for (
const auto &iter : llvm::enumerate(operandTypes)) {
1368 auto &frag = frags[iter.index()];
1369 frag.regTypes.resize(frag.regs.size(), iter.value());
1374 MmaOp::inferOperandMMAType(frag.regTypes[0],
1382 MmaOp::inferOperandMMAType(resultType,
true);
1397 std::array<StringRef, 2> names{
"multiplicandAPtxType",
1398 "multiplicandBPtxType"};
1399 for (
unsigned idx = 0; idx < names.size(); idx++) {
1400 const auto &frag = frags[idx];
1401 std::optional<NamedAttribute> attr = namedAttributes.
getNamed(names[idx]);
1402 if (!frag.elemtype.has_value() && !attr.has_value()) {
1405 "attribute " + names[idx] +
1406 " is not provided explicitly and cannot be inferred");
1408 if (!attr.has_value())
1410 names[idx], MMATypesAttr::get(parser.
getContext(), *frag.elemtype));
1413 result.addTypes(resultType);
1414 if (!namedAttributes.
empty())
1415 result.addAttributes(namedAttributes);
1416 result.addAttribute(MmaSpOp::getOperandSegmentSizeAttr(),
1418 static_cast<int32_t>(frags[0].regs.size()),
1419 static_cast<int32_t>(frags[1].regs.size()),
1420 static_cast<int32_t>(frags[2].regs.size()),
1427LogicalResult MmaSpOp::verify() {
1429 auto f16Ty = Float16Type::get(context);
1430 auto i32Ty = IntegerType::get(context, 32);
1431 auto f16x2Ty = VectorType::get(2, f16Ty);
1432 auto f32Ty = Float32Type::get(context);
1433 auto f16x2x4StructTy = LLVM::LLVMStructType::getLiteral(
1434 context, {f16x2Ty, f16x2Ty, f16x2Ty, f16x2Ty});
1436 auto s32x4StructTy =
1437 LLVM::LLVMStructType::getLiteral(context, {i32Ty, i32Ty, i32Ty, i32Ty});
1438 auto f32x8StructTy =
1440 auto f16x2x2StructTy =
1441 LLVM::LLVMStructType::getLiteral(context, {f16x2Ty, f16x2Ty});
1442 auto f32x4StructTy =
1443 LLVM::LLVMStructType::getLiteral(context, {f32Ty, f32Ty, f32Ty, f32Ty});
1444 auto s32x2StructTy =
1445 LLVM::LLVMStructType::getLiteral(context, {i32Ty, i32Ty});
1447 std::array<int64_t, 3> mmaShape{getShapeAttr().getM(), getShapeAttr().getN(),
1448 getShapeAttr().getK()};
1454 AllowedShapes allowedShapes;
1455 AllowedTypes expectedA;
1456 AllowedTypes expectedB;
1457 AllowedTypes expectedC;
1462 if (mmaShape[0] == 16) {
1464 Type multiplicandFragType;
1465 switch (*getMultiplicandAPtxType()) {
1466 case MMATypes::tf32:
1468 multiplicandFragType = i32Ty;
1469 expectedResult.push_back(LLVM::LLVMStructType::getLiteral(
1470 context, {f32Ty, f32Ty, f32Ty, f32Ty}));
1472 allowedShapes.push_back({16, 8, 8});
1473 allowedShapes.push_back({16, 8, 16});
1475 case MMATypes::bf16:
1477 multiplicandFragType = i32Ty;
1478 expectedResult.push_back(LLVM::LLVMStructType::getLiteral(
1479 context, {f32Ty, f32Ty, f32Ty, f32Ty}));
1481 allowedShapes.push_back({16, 8, 16});
1482 allowedShapes.push_back({16, 8, 32});
1486 multiplicandFragType = f16x2Ty;
1487 expectedResult.push_back(f16x2x2StructTy);
1488 expectedResult.push_back(f32x4StructTy);
1490 allowedShapes.push_back({16, 8, 16});
1491 allowedShapes.push_back({16, 8, 32});
1497 allowedShapes.push_back({16, 8, 64});
1498 allowedShapes.push_back({16, 8, 128});
1504 allowedShapes.push_back({16, 8, 32});
1505 allowedShapes.push_back({16, 8, 64});
1507 case MMATypes::e4m3:
1508 case MMATypes::e5m2:
1509 case MMATypes::e3m2:
1510 case MMATypes::e2m3:
1511 case MMATypes::e2m1:
1513 multiplicandFragType = i32Ty;
1514 expectedResult.push_back(f16x2x2StructTy);
1515 expectedResult.push_back(f32x4StructTy);
1517 allowedShapes.push_back({16, 8, 64});
1520 return emitError(
"invalid shape or multiplicand type: ")
1521 << getMultiplicandAPtxType().value();
1525 expectedResult.push_back(s32x4StructTy);
1526 expectedC.emplace_back(4, i32Ty);
1527 multiplicandFragType = i32Ty;
1528 }
else if (*getMultiplicandAPtxType() >= MMATypes::e4m3 &&
1529 *getMultiplicandAPtxType() <= MMATypes::e2m1) {
1531 expectedC.emplace_back(2, f16x2Ty);
1532 expectedC.emplace_back(4, f32Ty);
1534 expectedC.emplace_back(2, f16x2Ty);
1535 expectedC.emplace_back(4, f32Ty);
1540 int64_t unitA = (mmaShape[0] / 8) * (mmaShape[2] / kFactor) / 2;
1541 int64_t unitB = (mmaShape[1] / 8) * (mmaShape[2] / kFactor);
1542 expectedA.emplace_back(unitA, multiplicandFragType);
1543 expectedB.emplace_back(unitB, multiplicandFragType);
1545 if (resultPtxType() != accumPtxType())
1550 if (mmaShape[0] == 8) {
1551 if (*getMultiplicandAPtxType() == MMATypes::f16) {
1552 expectedA.emplace_back(2, f16x2Ty);
1553 expectedB.emplace_back(2, f16x2Ty);
1554 expectedResult.push_back(f16x2x4StructTy);
1555 expectedResult.push_back(f32x8StructTy);
1556 expectedC.emplace_back(4, f16x2Ty);
1557 expectedC.emplace_back(8, f32Ty);
1558 allowedShapes.push_back({8, 8, 4});
1560 if (*getMultiplicandAPtxType() == MMATypes::f64) {
1561 Type f64Ty = Float64Type::get(context);
1562 expectedA.emplace_back(1, f64Ty);
1563 expectedB.emplace_back(1, f64Ty);
1564 expectedC.emplace_back(2, f64Ty);
1565 expectedResult.emplace_back(LLVM::LLVMStructType::getLiteral(
1567 allowedShapes.push_back({8, 8, 4});
1570 expectedA.push_back({i32Ty});
1571 expectedB.push_back({i32Ty});
1572 expectedC.push_back({i32Ty, i32Ty});
1573 expectedResult.push_back(s32x2StructTy);
1575 allowedShapes.push_back({8, 8, 32});
1577 allowedShapes.push_back({8, 8, 16});
1581 std::string errorMessage;
1582 llvm::raw_string_ostream errorStream(errorMessage);
1585 if (expectedA.empty() || expectedB.empty() || expectedC.empty() ||
1586 !llvm::is_contained(allowedShapes, mmaShape)) {
1587 errorStream <<
"unimplemented variant for MMA shape <";
1588 llvm::interleaveComma(mmaShape, errorStream);
1594 std::array<StringRef, 3> operandNames{
"A",
"B",
"C"};
1595 for (
const auto &iter : llvm::enumerate(
1597 auto spec = this->getODSOperandIndexAndLength(iter.index());
1599 operand_type_begin() + spec.first +
1601 bool match = llvm::is_contained(iter.value(), operandTySeg);
1604 errorStream <<
"Could not match types for the "
1605 << operandNames[iter.index()]
1606 <<
" operands; expected one of ";
1607 for (
const auto &x : iter.value()) {
1608 errorStream << x.size() <<
"x" << x[0] <<
" ";
1610 errorStream <<
"but got ";
1611 llvm::interleaveComma(operandTySeg, errorStream);
1617 if (!llvm::any_of(expectedResult, [&](
Type expectedResultType) {
1618 return expectedResultType == getResult().getType();
1621 <<
"Could not match allowed types for the result; expected one of ";
1622 llvm::interleaveComma(expectedResult, errorStream);
1623 errorStream <<
" but got " << getResult().getType();
1631 if (!getIntOverflowBehavior())
1633 getIntOverflowBehaviorAttrName().strref() +
1638 if (!getSparseMetadata().
getType().isInteger(32)) {
1639 return emitOpError() <<
"sparse metadata must be i32 type";
1643 if (!getSparsitySelector().
getType().isInteger(32)) {
1644 return emitOpError() <<
"sparsity selector must be i32 type";
1656struct MMAOperandFragment {
1657 StringRef operandName;
1658 StringRef ptxTypeAttr;
1659 SmallVector<Value, 4> regs;
1660 explicit MMAOperandFragment(StringRef name, StringRef ptxTypeName)
1661 : operandName(name), ptxTypeAttr(ptxTypeName) {}
1668 p <<
" " << name <<
"[";
1687template <
typename Op>
1692 for (
unsigned fragIdx = 0; fragIdx < frags.size(); fragIdx++) {
1693 auto &frag = frags[fragIdx];
1694 auto varOperandSpec = op.getODSOperandIndexAndLength(fragIdx);
1695 for (
auto operandIdx = varOperandSpec.first;
1696 operandIdx < varOperandSpec.first + varOperandSpec.second;
1698 frag.regs.push_back(op.getOperand(operandIdx));
1699 if (fragIdx == 0 && operandIdx == varOperandSpec.first) {
1700 regTypes.push_back(op.getOperand(operandIdx).getType());
1704 regTypes.push_back(frag.regs[0].getType());
1706 std::optional<MMATypes> inferredType =
1707 MmaOp::inferOperandMMAType(regTypes.back(),
1710 ignoreAttrNames.push_back(frag.ptxTypeAttr);
1721 auto typeParser = [&]() {
1725 operandTypes.push_back(ty);
1731 if (operandTypes.size() != 3)
1733 "expected exactly 3 types");
1742 if (!attrs.
get(
"multiplicandAPtxType")) {
1743 if (
auto inferredType =
1744 MmaOp::inferOperandMMAType(operandTypes[0],
false)) {
1745 attrs.
set(
"multiplicandAPtxType", MMATypesAttr::get(ctx, *inferredType));
1748 if (!attrs.
get(
"multiplicandBPtxType")) {
1749 if (
auto inferredType =
1750 MmaOp::inferOperandMMAType(operandTypes[1],
false)) {
1751 attrs.
set(
"multiplicandBPtxType", MMATypesAttr::get(ctx, *inferredType));
1757template <
typename OpType>
1760 ScaleVecSize scaleVecSize,
1761 BlockScaleFormat blockScaleFormat,
1762 MMABlockScaleKind kind) {
1764 auto &properties =
result.getOrAddProperties<
typename OpType::Properties>();
1765 properties.setShape(
1767 properties.setScaleVecSize(ScaleVecSizeAttr::get(ctx, scaleVecSize));
1768 properties.setBlockScaleFormat(
1769 BlockScaleFormatAttr::get(ctx, blockScaleFormat));
1770 properties.setKind(MMABlockScaleKindAttr::get(ctx, kind));
1777 std::optional<std::array<MMATypes, 2>> multiplicandPtxTypes) {
1778 if (multiplicandPtxTypes) {
1779 result.addAttribute(
"multiplicandAPtxType",
1780 MMATypesAttr::get(ctx, (*multiplicandPtxTypes)[0]));
1781 result.addAttribute(
"multiplicandBPtxType",
1782 MMATypesAttr::get(ctx, (*multiplicandPtxTypes)[1]));
1784 if (
auto res = MmaOp::inferOperandMMAType(operandA[0].
getType(),
false))
1785 result.addAttribute(
"multiplicandAPtxType", MMATypesAttr::get(ctx, *res));
1786 if (
auto res = MmaOp::inferOperandMMAType(operandB[0].
getType(),
false))
1787 result.addAttribute(
"multiplicandBPtxType", MMATypesAttr::get(ctx, *res));
1792template <
typename OpTy>
1794 return *MmaOp::inferOperandMMAType(
1795 cast<LLVM::LLVMStructType>(op.getRes().getType()).getBody()[0],
1805 std::array<MMAOperandFragment, 3> frags{
1806 MMAOperandFragment(
"A", getMultiplicandAPtxTypeAttrName()),
1807 MMAOperandFragment(
"B", getMultiplicandBPtxTypeAttrName()),
1808 MMAOperandFragment(
"C",
"")};
1810 mlir::NVVM::MmaBlockScaleOp::getOperandSegmentSizeAttr()};
1815 for (
const auto &frag : frags)
1820 {getScaleAData(), getByteIdA(), getThreadIdA()});
1822 {getScaleBData(), getByteIdB(), getThreadIdB()});
1829 frags[1].regs[0].getType(),
1830 frags[2].regs[0].getType()},
1836ParseResult MmaBlockScaleOp::parse(
OpAsmParser &parser,
1838 struct LocalOperandFragment {
1839 std::optional<MMATypes> elemtype;
1840 SmallVector<OpAsmParser::UnresolvedOperand, 4> regs;
1844 std::array<LocalOperandFragment, 3> frags;
1873 for (
const auto &[idx, frag] : llvm::enumerate(frags)) {
1874 frag.elemtype = MmaOp::inferOperandMMAType(operandTypes[idx],
1877 .resolveOperands(frag.regs, operandTypes[idx], parser.
getNameLoc(),
1887 .resolveOperands(scaleAOperands, scaleTypes, parser.
getNameLoc(),
1897 result.addAttributes(namedAttributes);
1901 result.addTypes(resultTypes);
1902 result.addAttribute(MmaBlockScaleOp::getOperandSegmentSizeAttr(),
1904 static_cast<int32_t>(frags[0].regs.size()),
1905 static_cast<int32_t>(frags[1].regs.size()),
1906 static_cast<int32_t>(frags[2].regs.size()),
1917void MmaBlockScaleOp::build(
1922 std::optional<std::array<MMATypes, 2>> multiplicandPtxTypes,
1923 ScaleVecSize scaleVecSize, BlockScaleFormat blockScaleFormat,
1924 MMABlockScaleKind kind) {
1925 assert(
shape.size() == 3 &&
"expected shape to have size 3 (m, n, k)");
1928 blockScaleFormat, kind);
1930 result.addOperands(operandA);
1931 result.addOperands(operandB);
1932 result.addOperands(operandC);
1934 {scaleAData, byteIdA, threadIdA, scaleBData, byteIdB, threadIdB});
1937 multiplicandPtxTypes);
1939 result.addTypes(resultType);
1940 result.addAttribute(MmaBlockScaleOp::getOperandSegmentSizeAttr(),
1942 static_cast<int32_t>(operandA.size()),
1943 static_cast<int32_t>(operandB.size()),
1944 static_cast<int32_t>(operandC.size()),
1956 auto curOp = cast<NVVM::MmaBlockScaleOp>(op);
1960 for (
Value operand : curOp.getOperandA())
1962 for (
Value operand : curOp.getOperandB())
1964 for (
Value operand : curOp.getOperandC())
1968 args.push_back(mt.
lookupValue(curOp.getScaleAData()));
1969 args.push_back(mt.
lookupValue(curOp.getByteIdA()));
1970 args.push_back(mt.
lookupValue(curOp.getThreadIdA()));
1971 args.push_back(mt.
lookupValue(curOp.getScaleBData()));
1972 args.push_back(mt.
lookupValue(curOp.getByteIdB()));
1973 args.push_back(mt.
lookupValue(curOp.getThreadIdB()));
1975 unsigned intId = MmaBlockScaleOp::getIntrinsicID(
1976 curOp.getShape().getM(), curOp.getShape().getN(), curOp.getShape().getK(),
1977 *curOp.getMultiplicandAPtxType(), *curOp.getMultiplicandBPtxType(),
1979 curOp.getBlockScaleFormat(), curOp.getKind());
1981 return {intId, args};
1984LogicalResult MmaBlockScaleOp::verify() {
1990 if (m == 16 && n == 8 && k == 64) {
1991 if (getMultiplicandAPtxType() != NVVM::MMATypes::e2m1 ||
1992 getMultiplicandBPtxType() != NVVM::MMATypes::e2m1)
1994 "unsupported MMATypes attribute for mma.m16n8k64.(mxf4nvf4|mxf4)");
1995 if (getKind() == NVVM::MMABlockScaleKind::MXF4) {
1996 if (getScaleVecSize() != NVVM::ScaleVecSize::X2)
1998 "unsupported ScaleVecSize attribute for mma.m16n8k64.mxf4");
1999 if (getBlockScaleFormat() != NVVM::BlockScaleFormat::UE8M0)
2001 "unsupported BlockScaleFormat attribute for mma.m16n8k64.mxf4");
2002 }
else if (getKind() == NVVM::MMABlockScaleKind::MXF4NVF4) {
2003 if (!((getScaleVecSize() == NVVM::ScaleVecSize::X2 &&
2004 getBlockScaleFormat() == NVVM::BlockScaleFormat::UE8M0) ||
2005 (getScaleVecSize() == NVVM::ScaleVecSize::X4 &&
2006 (getBlockScaleFormat() == NVVM::BlockScaleFormat::UE4M3 ||
2007 getBlockScaleFormat() == NVVM::BlockScaleFormat::UE8M0))))
2009 "attributes for mma.m16n8k64.mxf4nvf4");
2013 }
else if (m == 16 && n == 8 && k == 32) {
2014 if (!(getKind() == NVVM::MMABlockScaleKind::MXF8F6F4 &&
2015 getScaleVecSize() == NVVM::ScaleVecSize::X1 &&
2016 getBlockScaleFormat() == NVVM::BlockScaleFormat::UE8M0))
2018 emitOpError(
"unsupported Kind, ScaleVecSize and BlockScaleFormat "
2019 "attributes for mma.m16n8k32");
2032 std::array<MMAOperandFragment, 3> frags{
2033 MMAOperandFragment(
"A", getMultiplicandAPtxTypeAttrName()),
2034 MMAOperandFragment(
"B", getMultiplicandBPtxTypeAttrName()),
2035 MMAOperandFragment(
"C",
"")};
2037 mlir::NVVM::MmaSpBlockScaleOp::getOperandSegmentSizeAttr()};
2042 for (
const auto &frag : frags)
2051 {getScaleAData(), getByteIdA(), getThreadIdA()});
2053 {getScaleBData(), getByteIdB(), getThreadIdB()});
2060 frags[1].regs[0].getType(),
2061 frags[2].regs[0].getType()},
2067ParseResult MmaSpBlockScaleOp::parse(
OpAsmParser &parser,
2069 struct LocalOperandFragment {
2070 std::optional<MMATypes> elemtype;
2071 SmallVector<OpAsmParser::UnresolvedOperand, 4> regs;
2075 std::array<LocalOperandFragment, 3> frags;
2111 for (
const auto &[idx, frag] : llvm::enumerate(frags)) {
2112 frag.elemtype = MmaOp::inferOperandMMAType(operandTypes[idx],
2115 .resolveOperands(frag.regs, operandTypes[idx], parser.
getNameLoc(),
2124 .resolveOperands(metadataOperands, i32Type, parser.
getNameLoc(),
2137 .resolveOperands(scaleAOperands, scaleTypes, parser.
getNameLoc(),
2147 result.addAttributes(namedAttributes);
2152 if (!
result.attributes.get(
"orderedMetadata"))
2155 result.addTypes(resultTypes);
2156 result.addAttribute(MmaSpBlockScaleOp::getOperandSegmentSizeAttr(),
2158 static_cast<int32_t>(frags[0].regs.size()),
2159 static_cast<int32_t>(frags[1].regs.size()),
2160 static_cast<int32_t>(frags[2].regs.size()),
2173void MmaSpBlockScaleOp::build(
2179 std::optional<std::array<MMATypes, 2>> multiplicandPtxTypes,
2180 ScaleVecSize scaleVecSize, BlockScaleFormat blockScaleFormat,
2181 MMABlockScaleKind kind) {
2182 assert(
shape.size() == 3 &&
"expected shape to have size 3 (m, n, k)");
2185 builder,
result,
shape, scaleVecSize, blockScaleFormat, kind);
2188 result.addOperands(operandA);
2189 result.addOperands(operandB);
2190 result.addOperands(operandC);
2191 result.addOperands({sparseMetadata, sparsitySelector, scaleAData, byteIdA,
2192 threadIdA, scaleBData, byteIdB, threadIdB});
2195 multiplicandPtxTypes);
2197 result.addTypes(resultType);
2198 result.addAttribute(MmaSpBlockScaleOp::getOperandSegmentSizeAttr(),
2200 static_cast<int32_t>(operandA.size()),
2201 static_cast<int32_t>(operandB.size()),
2202 static_cast<int32_t>(operandC.size()),
2216 auto curOp = cast<NVVM::MmaSpBlockScaleOp>(op);
2220 for (
Value operand : curOp.getOperandA())
2222 for (
Value operand : curOp.getOperandB())
2224 for (
Value operand : curOp.getOperandC())
2228 args.push_back(mt.
lookupValue(curOp.getSparseMetadata()));
2229 args.push_back(mt.
lookupValue(curOp.getSparsitySelector()));
2232 args.push_back(mt.
lookupValue(curOp.getScaleAData()));
2233 args.push_back(mt.
lookupValue(curOp.getByteIdA()));
2234 args.push_back(mt.
lookupValue(curOp.getThreadIdA()));
2235 args.push_back(mt.
lookupValue(curOp.getScaleBData()));
2236 args.push_back(mt.
lookupValue(curOp.getByteIdB()));
2237 args.push_back(mt.
lookupValue(curOp.getThreadIdB()));
2239 unsigned intId = MmaSpBlockScaleOp::getIntrinsicID(
2240 curOp.getShape().getM(), curOp.getShape().getN(), curOp.getShape().getK(),
2241 *curOp.getMultiplicandAPtxType(), *curOp.getMultiplicandBPtxType(),
2243 curOp.getBlockScaleFormat(), curOp.getKind());
2245 return {intId, args};
2248LogicalResult MmaSpBlockScaleOp::verify() {
2250 if (!getOrderedMetadata()) {
2251 return emitOpError(
"'orderedMetadata' attribute is mandatory");
2259 if (m == 16 && n == 8 && k == 128) {
2260 if (getMultiplicandAPtxType() != NVVM::MMATypes::e2m1 ||
2261 getMultiplicandBPtxType() != NVVM::MMATypes::e2m1)
2263 "unsupported MMATypes attribute for mma.m16n8k128.(mxf4nvf4|mxf4)");
2264 if (getKind() == NVVM::MMABlockScaleKind::MXF4) {
2265 if (getScaleVecSize() != NVVM::ScaleVecSize::X2)
2267 "unsupported ScaleVecSize attribute for mma.m16n8k128.mxf4");
2268 if (getBlockScaleFormat() != NVVM::BlockScaleFormat::UE8M0)
2270 "unsupported BlockScaleFormat attribute for mma.m16n8k128.mxf4");
2271 }
else if (getKind() == NVVM::MMABlockScaleKind::MXF4NVF4) {
2272 if (!((getScaleVecSize() == NVVM::ScaleVecSize::X2 &&
2273 getBlockScaleFormat() == NVVM::BlockScaleFormat::UE8M0) ||
2274 (getScaleVecSize() == NVVM::ScaleVecSize::X4 &&
2275 (getBlockScaleFormat() == NVVM::BlockScaleFormat::UE4M3 ||
2276 getBlockScaleFormat() == NVVM::BlockScaleFormat::UE8M0))))
2278 "attributes for mma.m16n8k128.mxf4nvf4");
2282 }
else if (m == 16 && n == 8 && k == 64) {
2283 if (!(getKind() == NVVM::MMABlockScaleKind::MXF8F6F4 &&
2284 getScaleVecSize() == NVVM::ScaleVecSize::X1 &&
2285 getBlockScaleFormat() == NVVM::BlockScaleFormat::UE8M0))
2287 emitOpError(
"unsupported Kind, ScaleVecSize and BlockScaleFormat "
2288 "attributes for mma.m16n8k64");
2295LogicalResult ShflOp::verify() {
2296 auto returnStructType = llvm::dyn_cast<LLVM::LLVMStructType>(
getType());
2298 auto verifyTypeError = [&](Twine desc,
Type expectedType,
2299 Type actualType) -> LogicalResult {
2300 return emitOpError(
"expected " + desc +
" to be of type ")
2301 << expectedType <<
" but got " << actualType <<
" instead";
2304 if (returnStructType) {
2305 if (!getReturnValueAndIsValid())
2306 return emitOpError(
"\"return_value_and_is_valid\" attribute must be "
2307 "specified when the return type is a struct type");
2309 if (returnStructType.getBody().size() != 2)
2310 return emitOpError(
"expected return type to be a two-element struct");
2313 auto resultType = returnStruct[0];
2314 if (resultType != getVal().
getType())
2315 return verifyTypeError(
"first element in the returned struct",
2316 getVal().
getType(), resultType);
2318 auto predicateType = returnStruct[1];
2319 if (!predicateType.isInteger(1))
2320 return verifyTypeError(
"second element in the returned struct",
2324 if (getReturnValueAndIsValid())
2325 return emitOpError(
"expected return type to be a two-element struct");
2328 return verifyTypeError(
"return type", getVal().
getType(),
getType());
2334ShflOp::inferReturnTypes(
MLIRContext *context, std::optional<Location> location,
2335 ShflOp::Adaptor adaptor,
2337 Type valType = adaptor.getVal().getType();
2338 if (adaptor.getReturnValueAndIsValid())
2339 inferredReturnTypes.push_back(LLVM::LLVMStructType::getLiteral(
2340 context, {valType, IntegerType::get(context, 1)}));
2342 inferredReturnTypes.push_back(valType);
2347 NVVM::MMAFrag frag,
int nRow,
2350 unsigned numberElements = 0;
2353 Type f16x2 = VectorType::get(2, builder.getF16Type());
2354 if (type == NVVM::MMATypes::f16) {
2355 elementType = f16x2;
2356 if (frag == NVVM::MMAFrag::a || frag == NVVM::MMAFrag::b)
2360 }
else if (type == NVVM::MMATypes::f32) {
2361 elementType = builder.getF32Type();
2363 }
else if (type == NVVM::MMATypes::f64) {
2364 elementType = builder.getF64Type();
2365 if (frag == NVVM::MMAFrag::a || frag == NVVM::MMAFrag::b)
2369 }
else if (type == NVVM::MMATypes::tf32) {
2370 elementType = builder.getI32Type();
2372 }
else if (type == NVVM::MMATypes::s8 || type == NVVM::MMATypes::u8) {
2373 elementType = builder.getI32Type();
2374 int parallelSize = 0;
2375 if (frag == NVVM::MMAFrag::a)
2376 parallelSize = nRow;
2377 if (frag == NVVM::MMAFrag::b)
2378 parallelSize = nCol;
2381 if (parallelSize == 16)
2384 else if (parallelSize == 8)
2386 else if (parallelSize == 32)
2388 }
else if (type == NVVM::MMATypes::s32) {
2389 elementType = builder.getI32Type();
2392 assert(numberElements != 0 && elementType !=
nullptr);
2393 return std::make_pair(elementType, numberElements);
2396static std::pair<mlir::Type, unsigned>
2400 if (frag == NVVM::MMAFrag::a) {
2403 }
else if (frag == NVVM::MMAFrag::b) {
2410 assert(nRow && nCol);
2414LogicalResult NVVM::WMMALoadOp::verify() {
2415 unsigned addressSpace =
2416 llvm::cast<LLVM::LLVMPointerType>(getPtr().
getType()).getAddressSpace();
2417 if (addressSpace != 0 && addressSpace != NVVMMemorySpace::Global &&
2418 addressSpace != NVVMMemorySpace::Shared)
2419 return emitOpError(
"expected source pointer in memory "
2422 if (NVVM::WMMALoadOp::getIntrinsicID(
getM(),
getN(), getK(), getLayout(),
2423 getEltype(), getFrag()) == 0)
2424 return emitOpError() <<
"invalid attribute combination";
2429 if (typeInfo.first == f64Ty && typeInfo.second == 1) {
2431 return emitOpError(
"expected destination type to be f64");
2435 Type dstType = LLVM::LLVMStructType::getLiteral(
2438 return emitOpError(
"expected destination type is a structure of ")
2439 << typeInfo.second <<
" elements of type " << typeInfo.first;
2443LogicalResult NVVM::WMMAStoreOp::verify() {
2444 unsigned addressSpace =
2445 llvm::cast<LLVM::LLVMPointerType>(getPtr().
getType()).getAddressSpace();
2446 if (addressSpace != 0 && addressSpace != NVVMMemorySpace::Global &&
2447 addressSpace != NVVMMemorySpace::Shared)
2448 return emitOpError(
"expected operands to be a source pointer in memory "
2451 if (NVVM::WMMAStoreOp::getIntrinsicID(
getM(),
getN(), getK(), getLayout(),
2453 return emitOpError() <<
"invalid attribute combination";
2456 if (getArgs().size() != typeInfo.second)
2457 return emitOpError() <<
"expected " << typeInfo.second <<
" data operands";
2458 if (llvm::any_of(getArgs(), [&typeInfo](
Value operands) {
2459 return operands.
getType() != typeInfo.first;
2461 return emitOpError() <<
"expected data operands of type " << typeInfo.first;
2465LogicalResult NVVM::WMMAMmaOp::verify() {
2466 if (NVVM::WMMAMmaOp::getIntrinsicID(
getM(),
getN(), getK(), getLayoutA(),
2467 getLayoutB(), getEltypeA(),
2469 return emitOpError() <<
"invalid attribute combination";
2477 arguments.append(typeInfoA.second, typeInfoA.first);
2478 arguments.append(typeInfoB.second, typeInfoB.first);
2479 arguments.append(typeInfoC.second, typeInfoC.first);
2480 unsigned numArgs = arguments.size();
2481 if (getArgs().size() != numArgs)
2482 return emitOpError() <<
"expected " << numArgs <<
" arguments";
2483 for (
unsigned i = 0; i < numArgs; i++) {
2484 if (getArgs()[i].
getType() != arguments[i])
2485 return emitOpError() <<
"expected argument " << i <<
" to be of type "
2488 Type dstType = LLVM::LLVMStructType::getLiteral(
2491 return emitOpError(
"expected destination type is a structure of ")
2492 << typeInfoC.second <<
" elements of type " << typeInfoC.first;
2496LogicalResult NVVM::LdMatrixOp::verify() {
2498 if (m == 8 && n == 8) {
2499 if (num != 1 && num != 2 && num != 4) {
2500 return emitOpError(
"expected num attribute to be 1, 2 or 4 for 8x8 "
2503 if (getEltType() != LdStMatrixEltType::B16) {
2504 return emitOpError(
"expected element type to be b16 for 8x8 matrix");
2506 }
else if (m == 8 && n == 16) {
2507 if (num != 1 && num != 2 && num != 4) {
2508 return emitOpError(
"expected num attribute to be 1, 2 or 4 for 8x16 "
2511 if (getLayout() != MMALayout::row) {
2512 return emitOpError(
"expected layout to be row for 8x16 matrix");
2514 if (getEltType() != LdStMatrixEltType::B8X16_B4X16_P64 &&
2515 getEltType() != LdStMatrixEltType::B8X16_B6X16_P32) {
2516 return emitOpError(
"expected element type to be b8x16.b4x16_p64 or "
2517 "b8x16.b6x16_p32 for 8x16 matrix");
2519 }
else if (m == 16 && n == 16) {
2520 if (num != 1 && num != 2) {
2521 return emitOpError(
"expected num attribute to be 1 or 2 for 16x16 "
2524 if (getLayout() != MMALayout::col) {
2525 return emitOpError(
"expected layout to be col for 16x16 matrix");
2527 if (getEltType() != LdStMatrixEltType::B8 &&
2528 getEltType() != LdStMatrixEltType::B8X16_B4X16_P64 &&
2529 getEltType() != LdStMatrixEltType::B8X16_B6X16_P32) {
2530 return emitOpError(
"expected element type to be b8, b8x16.b4x16_p64 or "
2531 "b8x16.b6x16_p32 for 16x16 matrix");
2534 return emitOpError(
"expected shape to be 8x8, 8x16 or 16x16");
2538 uint32_t numElements = (m == 16 && n == 16 ? num * 2 : num);
2539 if (numElements == 1 &&
getType() != i32)
2540 return emitOpError(
"expected destination type is i32");
2541 if (numElements == 2 || numElements == 4) {
2542 Type dstType = LLVM::LLVMStructType::getLiteral(
2545 return emitOpError(
"expected destination type is a structure of ")
2546 << numElements <<
" elements of type i32";
2552LogicalResult LdMatrixOp::inferReturnTypes(
2553 MLIRContext *context, std::optional<Location> location,
2555 uint32_t num = adaptor.getNum();
2556 uint32_t m = adaptor.getShape().getM();
2557 uint32_t n = adaptor.getShape().getN();
2558 uint32_t numElements = (m == 16 && n == 16) ? num * 2 : num;
2560 Type i32 = IntegerType::get(context, 32);
2561 if (numElements == 1)
2562 inferredReturnTypes.push_back(i32);
2564 inferredReturnTypes.push_back(LLVM::LLVMStructType::getLiteral(
2569LogicalResult NVVM::StMatrixOp::verify() {
2570 int numMatrix = getSources().size();
2571 if (numMatrix != 1 && numMatrix != 2 && numMatrix != 4)
2572 return emitOpError(
"expected num attribute to be 1, 2 or 4");
2575 if (m == 8 && n == 8) {
2576 if (getEltType() != NVVM::LdStMatrixEltType::B16) {
2577 return emitOpError(
"expected element type to be B16 for 8x8 matrix");
2579 }
else if (m == 16 && n == 8) {
2580 if (getEltType() != NVVM::LdStMatrixEltType::B8) {
2581 return emitOpError(
"expected element type to be B8 for 16x8 matrix");
2583 if (getLayout() != NVVM::MMALayout::col) {
2584 return emitOpError(
"expected layout to be col for 16x8 matrix");
2587 return emitOpError(
"expected shape to be 8x8 or 16x8");
2593LogicalResult NVVM::MovMatrixOp::verify() {
2595 if (m != 8 || n != 8)
2597 if (getLayout() != NVVM::MMALayout::col)
2599 if (getEltType() != NVVM::LdStMatrixEltType::B16)
2600 return emitOpError(
"expected element type to be b16");
2605 if (typeA == NVVM::WGMMATypes::tf32)
2607 if (typeA == NVVM::WGMMATypes::f16 || typeA == NVVM::WGMMATypes::bf16)
2609 if (typeA == NVVM::WGMMATypes::s8 || typeA == NVVM::WGMMATypes::u8)
2611 if (typeA == NVVM::WGMMATypes::e4m3 || typeA == NVVM::WGMMATypes::e5m2)
2613 if (typeA == NVVM::WGMMATypes::b1)
2619 NVVM::WGMMATypes typeA,
2620 NVVM::WGMMATypes typeB) {
2622 case NVVM::WGMMATypes::f16:
2623 if ((typeD == NVVM::WGMMATypes::f32 || typeD == NVVM::WGMMATypes::f16) &&
2624 typeB == NVVM::WGMMATypes::f16)
2627 case NVVM::WGMMATypes::tf32:
2628 if (typeD == NVVM::WGMMATypes::f32 && typeB == NVVM::WGMMATypes::tf32)
2631 case NVVM::WGMMATypes::u8:
2632 case NVVM::WGMMATypes::s8:
2633 if (typeD == NVVM::WGMMATypes::s32 &&
2634 (typeB == NVVM::WGMMATypes::u8 || typeB == NVVM::WGMMATypes::s8))
2637 case NVVM::WGMMATypes::b1:
2638 if (typeD == NVVM::WGMMATypes::s32 && typeB == NVVM::WGMMATypes::b1)
2641 case NVVM::WGMMATypes::bf16:
2642 if ((typeD == NVVM::WGMMATypes::f32 || typeD == NVVM::WGMMATypes::f16) &&
2643 typeB == NVVM::WGMMATypes::bf16)
2646 case NVVM::WGMMATypes::e4m3:
2647 case NVVM::WGMMATypes::e5m2:
2648 if ((typeD == NVVM::WGMMATypes::f32 || typeD == NVVM::WGMMATypes::f16) &&
2649 (typeB == NVVM::WGMMATypes::e5m2 || typeB == NVVM::WGMMATypes::e4m3))
2652 case WGMMATypes::f32:
2653 case WGMMATypes::s32:
2654 llvm_unreachable(
"unsupported input types");
2662 72, 80, 88, 96, 104, 112, 120, 128,
2663 136, 144, 152, 160, 168, 176, 184, 192,
2664 200, 208, 216, 224, 232, 240, 248, 256};
2666 80, 96, 112, 128, 144, 160,
2667 176, 192, 208, 224, 240, 256};
2669 case WGMMATypes::f16:
2670 case WGMMATypes::tf32:
2671 case WGMMATypes::bf16:
2672 case WGMMATypes::e4m3:
2673 case WGMMATypes::e5m2:
2674 if (llvm::is_contained(allowedN, sizeN))
2677 case WGMMATypes::u8:
2678 case WGMMATypes::s8:
2679 case WGMMATypes::b1:
2680 if (llvm::is_contained(allowedNshort, sizeN))
2683 case WGMMATypes::f32:
2684 case WGMMATypes::s32:
2685 llvm_unreachable(
"unsupported input types");
2691LogicalResult NVVM::WgmmaMmaAsyncOp::verify() {
2692 Value outValue = getResults();
2693 auto stype = dyn_cast<LLVM::LLVMStructType>(outValue.
getType());
2695 return emitOpError() <<
"expected results to be struct";
2696 int outputSize = stype.getBody().size();
2697 WGMMATypes typeD = getTypeD();
2698 WGMMATypes typeA = getTypeA();
2699 WGMMATypes typeB = getTypeB();
2701 for (
Type t : stype.getBody()) {
2702 if (t != stype.getBody().front())
2704 <<
"all elements in struct must be same type but there is " << t;
2707 if (typeD != WGMMATypes::f32 && typeD != WGMMATypes::f16 &&
2708 typeD != WGMMATypes::s32) {
2709 return emitOpError() <<
"does not support the given output type " << typeD;
2711 if (typeD == WGMMATypes::s32 &&
2712 (getScaleA() == WGMMAScaleIn::neg || getScaleB() == WGMMAScaleIn::neg)) {
2713 return emitOpError() <<
"has s32 output, scaleA and scaleB cannot be neg";
2717 return emitOpError() << typeD <<
" += " << typeA <<
" * " << typeB
2718 <<
", it is not supported.";
2728 return emitOpError() <<
"shape 'k' must be " << allowedK.value()
2729 <<
" for input type " << typeA;
2733 return emitOpError() <<
"has input type " << typeA <<
" n is set to "
2734 <<
getShape().getN() <<
", it is not supported.";
2741 if ((typeA != WGMMATypes::f16 && typeA != WGMMATypes::bf16) &&
2742 (getLayoutA() == mlir::NVVM::MMALayout::col ||
2743 getLayoutB() == mlir::NVVM::MMALayout::row)) {
2745 <<
"given layouts layout_a = " << getLayoutA()
2746 <<
" and layout_b = " << getLayoutB() <<
" for input types " << typeA
2748 <<
" requires transpose. However, this is only supported for: "
2749 << MMATypes::f16 <<
" and " << MMATypes::bf16;
2753 int expectedOutput = 0;
2754 if (typeD == WGMMATypes::f32 || typeD == WGMMATypes::s32)
2755 expectedOutput =
getShape().getN() / 2;
2756 if (typeD == WGMMATypes::f16)
2757 expectedOutput =
getShape().getN() / 4;
2758 if (outputSize != expectedOutput) {
2759 return emitOpError() <<
"results " << expectedOutput
2760 <<
", however output struct has " << outputSize
2764 if (typeD != WGMMATypes::s32 &&
2765 getSatfinite().value_or(NVVM::MMAIntOverflow::wrapped) ==
2766 NVVM::MMAIntOverflow::satfinite) {
2768 <<
" `satfinite` can be only used with s32 accumulator, however "
2769 "the current accumulator is "
2776std::string NVVM::WgmmaMmaAsyncOp::getPtx() {
2779 bool isF16 = getTypeA() == WGMMATypes::f16 || getTypeA() == WGMMATypes::bf16;
2781 StringRef outputTypeName = stringifyWGMMATypes(getTypeD());
2783 int expectedOutputRegisters = 0;
2784 if (getTypeD() == WGMMATypes::f16)
2785 expectedOutputRegisters =
getShape().getN() / 4;
2787 expectedOutputRegisters =
getShape().getN() / 2;
2790 llvm::raw_string_ostream ss(ptx);
2795 << ((expectedOutputRegisters * 2) + 2)
2797 "wgmma.mma_async.sync.aligned.m"
2798 << m <<
"n" << n <<
"k" << k <<
"." << outputTypeName <<
"." << getTypeA()
2799 <<
"." << getTypeB();
2800 if (getSatfinite().value_or(NVVM::MMAIntOverflow::wrapped) ==
2801 NVVM::MMAIntOverflow::satfinite)
2805 for (; regCnt < expectedOutputRegisters; ++regCnt) {
2806 ss <<
"$" << regCnt;
2807 if (regCnt != expectedOutputRegisters - 1)
2813 regCnt = (regCnt * 2);
2814 ss <<
" $" << (regCnt) <<
"," <<
" $" << (regCnt + 1) <<
"," <<
" p";
2815 if (getTypeD() != WGMMATypes::s32) {
2816 ss <<
", $" << (regCnt + 3) <<
", $" << (regCnt + 4);
2820 ss <<
", $" << (regCnt + 5) <<
", $" << (regCnt + 6);
2827bool NVVM::WgmmaMmaAsyncOp::getAsmValues(
2831 bool isF16 = getTypeA() == WGMMATypes::f16 || getTypeA() == WGMMATypes::bf16;
2838 asmValues.push_back({makeConstantI32(rewriter,
static_cast<int>(getScaleD())),
2840 if (getTypeD() != WGMMATypes::s32) {
2841 asmValues.push_back(
2842 {makeConstantI32(rewriter,
2843 getScaleA() == NVVM::WGMMAScaleIn::neg ? -1 : 1),
2845 asmValues.push_back(
2846 {makeConstantI32(rewriter,
2847 getScaleB() == NVVM::WGMMAScaleIn::neg ? -1 : 1),
2851 asmValues.push_back(
2852 {makeConstantI32(rewriter,
static_cast<int>(getLayoutA())),
2854 asmValues.push_back(
2855 {makeConstantI32(rewriter, 1 -
static_cast<int>(getLayoutB())),
2861LogicalResult NVVM::FenceProxyOp::verify() {
2862 if (getKind() == NVVM::ProxyKind::async_shared && !getSpace().has_value()) {
2863 return emitOpError() <<
"async_shared fence requires space attribute";
2865 if (getKind() != NVVM::ProxyKind::async_shared && getSpace().has_value()) {
2866 return emitOpError() <<
"only async_shared fence can have space attribute";
2871LogicalResult NVVM::FenceProxyAcquireOp::verify() {
2872 if (getFromProxy() != NVVM::ProxyKind::GENERIC)
2873 return emitOpError(
"uni-directional proxies only support generic for "
2874 "from_proxy attribute");
2876 if (getToProxy() != NVVM::ProxyKind::TENSORMAP)
2877 return emitOpError(
"uni-directional proxies only support tensormap "
2878 "for to_proxy attribute");
2882LogicalResult NVVM::FenceProxyReleaseOp::verify() {
2883 if (getFromProxy() != NVVM::ProxyKind::GENERIC)
2884 return emitOpError(
"uni-directional proxies only support generic for "
2885 "from_proxy attribute");
2887 if (getToProxy() != NVVM::ProxyKind::TENSORMAP)
2888 return emitOpError(
"uni-directional proxies only support tensormap "
2889 "for to_proxy attribute");
2893LogicalResult NVVM::FenceProxySyncRestrictOp::verify() {
2894 if (getFromProxy() != NVVM::ProxyKind::GENERIC)
2895 return emitOpError(
"only generic is support for from_proxy attribute");
2897 if (getToProxy() != NVVM::ProxyKind::async)
2898 return emitOpError(
"only async is supported for to_proxy attribute");
2902LogicalResult NVVM::SetMaxRegisterOp::verify() {
2903 if (getRegCount() % 8)
2904 return emitOpError(
"new register size must be multiple of 8");
2905 if (getRegCount() < 24 || getRegCount() > 256)
2906 return emitOpError(
"new register size must be in between 24 to 256");
2910LogicalResult NVVM::Tcgen05CpOp::verify() {
2911 auto mc = getMulticast();
2913 using SH = Tcgen05CpShape;
2914 using MC = Tcgen05CpMulticast;
2916 case SH::SHAPE_128x256b:
2917 case SH::SHAPE_128x128b:
2918 case SH::SHAPE_4x256b:
2920 return emitError(
"Invalid multicast type for tcgen05.cp Op");
2922 case SH::SHAPE_64x128b:
2923 if (mc != MC::WARPX2_01_23 && mc != MC::WARPX2_02_13)
2924 return emitError(
"Shape 64x128b requires multicast warpx2_01_23 or "
2925 "warpx2_02_13 for tcgen05.cp Op");
2927 case SH::SHAPE_32x128b:
2928 if (mc != MC::WARPX4)
2930 "Shape 32x128b requires multicast warpx4 for tcgen05.cp Op");
2936LogicalResult NVVM::MatchSyncOp::verify() {
2937 if (getKind() == NVVM::MatchSyncKind::all) {
2938 auto type = llvm::dyn_cast<LLVM::LLVMStructType>(
getType());
2939 if (!type || type.getBody().size() != 2 ||
2940 !type.getBody()[0].isInteger(32) || !type.getBody()[1].isInteger(1)) {
2941 return emitOpError(
"match.sync 'all' returns a two element struct with "
2942 "first element as i32 and second element as i1");
2945 if (!
getType().isInteger(32)) {
2946 return emitOpError(
"match.sync 'any' returns an i32");
2952LogicalResult MatchSyncOp::inferReturnTypes(
2953 MLIRContext *context, std::optional<Location> location,
2955 if (adaptor.getKind() == NVVM::MatchSyncKind::all)
2956 inferredReturnTypes.push_back(LLVM::LLVMStructType::getLiteral(
2958 {IntegerType::get(context, 32), IntegerType::get(context, 1)}));
2960 inferredReturnTypes.push_back(IntegerType::get(context, 32));
2964LogicalResult NVVM::VoteSyncOp::verify() {
2965 if (getKind() == NVVM::VoteSyncKind::ballot) {
2966 if (!
getType().isInteger(32)) {
2967 return emitOpError(
"vote.sync 'ballot' returns an i32");
2970 if (!
getType().isInteger(1)) {
2971 return emitOpError(
"vote.sync 'any', 'all' and 'uni' returns an i1");
2977LogicalResult VoteSyncOp::inferReturnTypes(
2978 MLIRContext *context, std::optional<Location> location,
2980 unsigned width = adaptor.getKind() == NVVM::VoteSyncKind::ballot ? 32 : 1;
2981 inferredReturnTypes.push_back(IntegerType::get(context, width));
2985LogicalResult NVVM::PrefetchOp::verify() {
2986 using MemSpace = NVVM::NVVMMemorySpace;
2987 using CacheLevel = NVVM::PrefetchCacheLevel;
2989 unsigned addressSpace =
2990 llvm::cast<LLVM::LLVMPointerType>(getAddr().
getType()).getAddressSpace();
2991 std::optional<NVVM::CacheEvictionPriority> evictPriority = getEvictPriority();
2992 std::optional<NVVM::PrefetchCacheLevel> cacheLevel = getCacheLevel();
2994 if (getTensormap() && cacheLevel)
2995 return emitOpError(
"cannot specify both tensormap and cache level");
2997 if (getTensormap()) {
2998 if (addressSpace != MemSpace::Generic &&
2999 addressSpace != MemSpace::Constant) {
3001 "prefetch tensormap requires a generic or constant pointer");
3004 if (evictPriority) {
3006 "prefetch tensormap does not support eviction priority");
3009 if (getInParamSpace() && addressSpace != MemSpace::Generic) {
3011 "in_param_space can only be specified for a generic pointer");
3014 }
else if (cacheLevel) {
3015 if (addressSpace != MemSpace::Generic && addressSpace != MemSpace::Global &&
3016 addressSpace != MemSpace::Local) {
3017 return emitOpError(
"prefetch to cache level requires a generic, global, "
3018 "or local pointer");
3022 if (*cacheLevel != CacheLevel::L1) {
3024 "unsupported cache level, the only supported uniform "
3025 "cache level is L1");
3028 if (addressSpace != MemSpace::Generic) {
3030 "prefetch to uniform cache requires a generic pointer");
3034 if (evictPriority) {
3035 if (*cacheLevel != CacheLevel::L2)
3037 "cache eviction priority supported only for cache level L2");
3039 if (addressSpace != MemSpace::Global)
3040 return emitOpError(
"cache eviction priority requires a global pointer");
3042 if (*evictPriority != NVVM::CacheEvictionPriority::EvictNormal &&
3043 *evictPriority != NVVM::CacheEvictionPriority::EvictLast)
3045 "unsupported cache eviction priority, only evict_last and "
3046 "evict_normal are supported");
3050 return emitOpError(
"predicate supported only on prefetch tensormap");
3054 "requires specification of either cache level or tensormap");
3060LogicalResult NVVM::ClusterLaunchControlQueryCancelOp::verify() {
3061 switch (getQueryType()) {
3062 case NVVM::ClusterLaunchControlQueryType::IS_CANCELED:
3064 return emitOpError(
"is_canceled query type returns an i1");
3066 case NVVM::ClusterLaunchControlQueryType::GET_FIRST_CTA_ID_X:
3067 case NVVM::ClusterLaunchControlQueryType::GET_FIRST_CTA_ID_Y:
3068 case NVVM::ClusterLaunchControlQueryType::GET_FIRST_CTA_ID_Z:
3069 if (!
getType().isInteger(32)) {
3070 return emitOpError(
"get_first_cta_id_x, get_first_cta_id_y, "
3071 "get_first_cta_id_z query types return an i32");
3078LogicalResult ClusterLaunchControlQueryCancelOp::inferReturnTypes(
3079 MLIRContext *context, std::optional<Location> location,
3080 ClusterLaunchControlQueryCancelOp::Adaptor adaptor,
3083 adaptor.getQueryType() == NVVM::ClusterLaunchControlQueryType::IS_CANCELED
3086 inferredReturnTypes.push_back(IntegerType::get(context, width));
3090LogicalResult NVVM::ReduxOp::verify() {
3093 if (!reduxType.
isF32()) {
3095 return emitOpError(
"abs attribute is supported only for f32 type");
3097 return emitOpError(
"nan attribute is supported only for f32 type");
3100 NVVM::ReductionKind kind = getKind();
3102 case NVVM::ReductionKind::ADD:
3103 case NVVM::ReductionKind::AND:
3104 case NVVM::ReductionKind::OR:
3105 case NVVM::ReductionKind::XOR:
3106 case NVVM::ReductionKind::MAX:
3107 case NVVM::ReductionKind::MIN:
3108 case NVVM::ReductionKind::UMAX:
3109 case NVVM::ReductionKind::UMIN:
3112 << kind <<
"' reduction kind unsupported with " << reduxType
3113 <<
" type. Only supported type is 'i32'.";
3115 case NVVM::ReductionKind::FMIN:
3116 case NVVM::ReductionKind::FMAX:
3117 if (!reduxType.isF32())
3119 << kind <<
"' reduction kind unsupported with " << reduxType
3120 <<
" type. Only supported type is 'f32'.";
3127LogicalResult NVVM::TensormapReplaceOp::verify() {
3128 auto ord = getOrd();
3129 Value newVal = getNewValue();
3130 auto newValAttr = getNewValueAttr();
3131 auto fieldName = stringifyEnum(getField());
3133 if (ord && !llvm::is_contained({NVVM::TensormapField::BOX_DIM,
3134 NVVM::TensormapField::GLOBAL_DIM,
3135 NVVM::TensormapField::GLOBAL_STRIDE,
3136 NVVM::TensormapField::ELEMENT_STRIDE},
3138 return emitOpError(
"ordinal is not supported for ")
3139 << fieldName <<
" field";
3141 auto invalidNewVal = [&](llvm::Twine type) -> std::string {
3142 return llvm::Twine(
"new_value must be specified and must be an " + type +
3143 " for " + llvm::Twine(fieldName) +
" field")
3147 auto invalidNewValAttr = [&]() -> std::string {
3148 return (llvm::Twine(
3149 "new_value_attr must be specified and must be a valid ") +
3150 llvm::Twine(fieldName) +
" attribute for " + fieldName +
" field")
3154 switch (getField()) {
3155 case NVVM::TensormapField::GLOBAL_ADDRESS:
3159 case NVVM::TensormapField::RANK:
3163 case NVVM::TensormapField::GLOBAL_STRIDE:
3165 return emitOpError(
"ordinal is required for global_stride field");
3169 case NVVM::TensormapField::BOX_DIM:
3170 case NVVM::TensormapField::GLOBAL_DIM:
3171 case NVVM::TensormapField::ELEMENT_STRIDE:
3174 << stringifyEnum(getField()) <<
" field";
3178 case NVVM::TensormapField::ELEMTYPE:
3179 if (!(newValAttr && llvm::isa<TensormapElemtypeAttr>(*newValAttr)))
3182 case NVVM::TensormapField::INTERLEAVE_LAYOUT:
3183 if (!(newValAttr && llvm::isa<TensormapInterleaveLayoutAttr>(*newValAttr)))
3186 case NVVM::TensormapField::SWIZZLE_MODE:
3187 if (!(newValAttr && llvm::isa<TensormapSwizzleModeAttr>(*newValAttr)))
3190 case NVVM::TensormapField::SWIZZLE_ATOMICITY:
3191 if (!(newValAttr && llvm::isa<TensormapSwizzleAtomicityAttr>(*newValAttr)))
3194 case NVVM::TensormapField::FILL_MODE:
3195 if (!(newValAttr && llvm::isa<TensormapFillModeAttr>(*newValAttr)))
3203template <
typename OpType>
3205 mlir::NVVM::FPRoundingMode rndMode = op.getRnd();
3206 mlir::NVVM::SaturationMode satMode = op.getSat();
3207 bool isFTZ = op.getFtz();
3210 mlir::Type opBaseType = isa<VectorType>(opType)
3211 ? cast<VectorType>(opType).getElementType()
3214 if (opBaseType.
isF64() && (satMode != NVVM::SaturationMode::NONE || isFTZ))
3215 return op.emitOpError(
"FTZ and saturation are not supported for "
3216 "additions/subtractions involving f64 type");
3218 if (opBaseType.
isF16() && !(rndMode == NVVM::FPRoundingMode::RN ||
3219 rndMode == NVVM::FPRoundingMode::NONE))
3220 return op.emitOpError(
"only RN rounding mode is supported for f16 and "
3221 "vector<2xf16> additions/subtractions");
3223 if (opBaseType.
isBF16()) {
3224 if (rndMode != NVVM::FPRoundingMode::RN &&
3225 rndMode != NVVM::FPRoundingMode::NONE)
3226 return op.emitOpError(
"only RN rounding mode is supported for bf16 and "
3227 "vector<2xbf16> additions/subtractions");
3228 if (satMode != NVVM::SaturationMode::NONE || isFTZ)
3229 return op.emitOpError(
"FTZ and saturation are not supported for bf16 and "
3230 "vector<2xbf16> additions/subtractions");
3237 if (opBaseType.
isF16() && isFTZ && satMode == NVVM::SaturationMode::NONE)
3238 return op.emitOpError(
"FTZ with no saturation is not supported for f16 and "
3239 "vector<2xf16> additions/subtractions");
3248LogicalResult NVVM::FmaOp::verify() {
3249 auto opType = getRes().getType();
3250 mlir::NVVM::FPRoundingMode rndMode = getRnd();
3251 mlir::NVVM::SaturationMode satMode = getSat();
3252 bool isFTZ = getFtz();
3253 bool isRelu = getRelu();
3254 bool hasOOB = getOob();
3256 auto getBaseFType = [](
Type type) ->
Type {
3257 if (isa<VectorType>(type))
3258 return cast<VectorType>(type).getElementType();
3262 auto opBaseType = getBaseFType(opType);
3264 if (rndMode == NVVM::FPRoundingMode::NONE)
3265 return emitOpError(
"rounding mode must be specified");
3267 if (isRelu && satMode == NVVM::SaturationMode::SAT)
3268 return emitOpError(
"relu and saturation are not supported together");
3270 if (hasOOB && (satMode == NVVM::SaturationMode::SAT || isFTZ))
3271 return emitOpError(
"oob is not supported with saturation or FTZ");
3273 if (!(opBaseType.isF16() || opBaseType.isBF16()) && (isRelu || hasOOB))
3274 return emitOpError(
"relu and oob are only supported for f16 and bf16");
3276 if (opBaseType.isF64() && (satMode != NVVM::SaturationMode::NONE || isFTZ))
3277 return emitOpError(
"FTZ and saturation are not supported for f64 type");
3279 if (opBaseType.isF16() && rndMode != NVVM::FPRoundingMode::RN)
3281 "only RN rounding mode is supported for f16 and vector<2xf16>");
3283 if (opBaseType.isBF16()) {
3284 if (rndMode != NVVM::FPRoundingMode::RN)
3286 "only RN rounding mode is supported for bf16 and vector<2xbf16>");
3287 if (satMode != NVVM::SaturationMode::NONE || isFTZ)
3289 "FTZ and saturation are not supported for bf16 and vector<2xbf16>");
3295LogicalResult NVVM::SqrtOp::verify() {
3296 if (getRnd() == NVVM::FPRoundingMode::NONE)
3297 return emitOpError(
"rounding mode cannot be None");
3299 if (getRes().
getType().isF64() && getFtz())
3300 return emitOpError(
"FTZ is not supported for f64");
3305LogicalResult NVVM::DivFOp::verify() {
3306 bool isApprox = getApprox();
3307 bool isFull = getFull();
3308 bool isF64 = getRes().getType().isF64();
3309 bool isFtz = getFtz();
3310 NVVM::FPRoundingMode rndMode = getRnd();
3312 if (isApprox && isFull)
3313 return emitOpError(
"'approx' and 'full' are mutually exclusive");
3315 if (isApprox || isFull) {
3317 return emitOpError(
"'approx' and 'full' forms are f32-only");
3318 if (rndMode != NVVM::FPRoundingMode::NONE)
3320 "'approx' and 'full' forms do not accept a rounding mode");
3325 if (rndMode == NVVM::FPRoundingMode::NONE)
3326 return emitOpError(
"rounding mode cannot be None for the rounded divide");
3328 return emitOpError(
"FTZ is not supported for f64");
3339 unsigned sizeInBits,
3341 field = builder.CreateZExtOrBitCast(field, builder.getInt32Ty());
3343 unsigned mask = (sizeInBits < 32 ? ((1u << sizeInBits) - 1) : 0xffffffffu);
3344 if (mask != 0xffffffffu)
3345 field = builder.CreateAnd(field, builder.getInt32(mask));
3347 field = builder.CreateZExtOrBitCast(field, builder.getInt64Ty());
3348 field = builder.CreateShl(field, start);
3350 return builder.CreateOr(
result, field);
3353void Tcgen05MmaSmemDescOp::createSmemDescriptor(
Operation &op,
3355 llvm::IRBuilderBase &builder) {
3356 auto thisOp = cast<NVVM::Tcgen05MmaSmemDescOp>(op);
3357 llvm::Value *smemDesc = builder.getInt64(0);
3362 builder, smemDesc, mt.
lookupValue(thisOp.getLeadingDimOffset()), 14, 16);
3364 builder, smemDesc, mt.
lookupValue(thisOp.getStrideDimOffset()), 14, 32);
3370 builder, smemDesc, mt.
lookupValue(thisOp.getLeadingDimMode()), 1, 52);
3374 mt.
mapValue(thisOp.getRes()) = smemDesc;
3381std::string NVVM::MBarrierInitOp::getPtx() {
3383 return isShared ? std::string(
"mbarrier.init.shared.b64 [%0], %1;")
3384 : std::string(
"mbarrier.init.b64 [%0], %1;");
3387std::string NVVM::MBarrierArriveExpectTxOp::getPtx() {
3390 ? std::string(
"mbarrier.arrive.expect_tx.shared.b64 _, [%0], %1;")
3391 : std::string(
"mbarrier.arrive.expect_tx.b64 _, [%0], %1;");
3394std::string NVVM::MBarrierTryWaitParityOp::getPtx() {
3396 llvm::StringRef space = isShared ?
".shared" :
"";
3398 return llvm::formatv(
"{\n\t"
3399 ".reg .pred P1; \n\t"
3401 "mbarrier.try_wait.parity{0}.b64 P1, [%0], %1, %2; \n\t"
3402 "@P1 bra.uni DONE; \n\t"
3403 "bra.uni LAB_WAIT; \n\t"
3420 LLVM::FNegOp::create(rewriter, loc, op.getRhs().getType(), op.getRhs());
3423 op.getRnd(), op.getSat(), op.getFtz());
3442 return aligned ? llvm::Intrinsic::nvvm_barrier_cta_sync_aligned_count
3443 : llvm::Intrinsic::nvvm_barrier_cta_sync_count;
3445 return aligned ? llvm::Intrinsic::nvvm_barrier_cta_sync_aligned_all
3446 : llvm::Intrinsic::nvvm_barrier_cta_sync_all;
3451static llvm::Intrinsic::ID
3454 case NVVM::BarrierReduction::AND:
3455 return aligned ? llvm::Intrinsic::nvvm_barrier_cta_red_and_aligned_all
3456 : llvm::Intrinsic::nvvm_barrier_cta_red_and_all;
3457 case NVVM::BarrierReduction::OR:
3458 return aligned ? llvm::Intrinsic::nvvm_barrier_cta_red_or_aligned_all
3459 : llvm::Intrinsic::nvvm_barrier_cta_red_or_all;
3460 case NVVM::BarrierReduction::POPC:
3461 return aligned ? llvm::Intrinsic::nvvm_barrier_cta_red_popc_aligned_all
3462 : llvm::Intrinsic::nvvm_barrier_cta_red_popc_all;
3464 llvm_unreachable(
"unknown BarrierReduction kind");
3469 auto thisOp = cast<NVVM::BarrierOp>(op);
3470 llvm::Value *barrierId = thisOp.getBarrierId()
3472 : builder.getInt32(0);
3473 bool hasCount =
static_cast<bool>(thisOp.getNumberOfThreads());
3474 llvm::Intrinsic::ID
id =
3478 args.push_back(mt.
lookupValue(thisOp.getNumberOfThreads()));
3479 return {id, std::move(args)};
3484 auto thisOp = cast<NVVM::BarrierArriveOp>(op);
3485 llvm::Value *barrierId = thisOp.getBarrierId()
3487 : builder.getInt32(0);
3488 llvm::Value *numThreads = mt.
lookupValue(thisOp.getNumberOfThreads());
3489 llvm::Intrinsic::ID
id =
3491 ? llvm::Intrinsic::nvvm_barrier_cta_arrive_aligned_count
3492 : llvm::Intrinsic::nvvm_barrier_cta_arrive_count;
3493 return {id, {barrierId, numThreads}};
3498 auto thisOp = cast<NVVM::BarrierReductionOp>(op);
3500 thisOp.getAligned(), thisOp.getReductionOp());
3501 llvm::Value *barrierId = thisOp.getBarrierId()
3503 : builder.getInt32(0);
3506 builder.CreateICmpNE(mt.
lookupValue(thisOp.getReductionPredicate()),
3507 builder.getInt32(0))};
3508 return {id, std::move(args)};
3513 llvm::IRBuilderBase &builder) {
3514 auto thisOp = cast<NVVM::CosOp>(op);
3515 llvm::Intrinsic::ID
id = thisOp.getFtz()
3516 ? llvm::Intrinsic::nvvm_cos_approx_ftz_f
3517 : llvm::Intrinsic::nvvm_cos_approx_f;
3523 llvm::IRBuilderBase &builder) {
3524 auto thisOp = cast<NVVM::SinOp>(op);
3525 llvm::Intrinsic::ID
id = thisOp.getFtz()
3526 ? llvm::Intrinsic::nvvm_sin_approx_ftz_f
3527 : llvm::Intrinsic::nvvm_sin_approx_f;
3533 llvm::IRBuilderBase &builder) {
3534 auto thisOp = cast<NVVM::Log2Op>(op);
3535 llvm::Intrinsic::ID
id = thisOp.getFtz()
3536 ? llvm::Intrinsic::nvvm_lg2_approx_ftz_f
3537 : llvm::Intrinsic::nvvm_lg2_approx_f;
3543 llvm::IRBuilderBase &builder) {
3544 auto thisOp = cast<NVVM::Ex2Op>(op);
3545 llvm::Intrinsic::ID
id = thisOp.getFtz()
3546 ? llvm::Intrinsic::nvvm_ex2_approx_ftz
3547 : llvm::Intrinsic::nvvm_ex2_approx;
3553 llvm::IRBuilderBase &builder) {
3554 auto thisOp = cast<NVVM::RsqrtOp>(op);
3555 Type t = thisOp.getRes().getType();
3556 bool isFtz = thisOp.getFtz();
3558 llvm::Intrinsic::ID
id = [&] {
3560 return isFtz ? llvm::Intrinsic::nvvm_rsqrt_approx_ftz_f
3561 : llvm::Intrinsic::nvvm_rsqrt_approx_f;
3564 return isFtz ? llvm::Intrinsic::nvvm_rsqrt_approx_ftz_d
3565 : llvm::Intrinsic::nvvm_rsqrt_approx_d;
3573 llvm::IRBuilderBase &builder) {
3574 auto thisOp = cast<NVVM::SqrtOp>(op);
3575 Type t = thisOp.getRes().getType();
3576 NVVM::FPRoundingMode rndMode = thisOp.getRnd();
3577 bool isFtz = thisOp.getFtz();
3581 unsigned rndIndex =
static_cast<unsigned>(rndMode) - 1;
3583 static constexpr llvm::Intrinsic::ID f32IDs[] = {
3584 llvm::Intrinsic::nvvm_sqrt_rn_f,
3585 llvm::Intrinsic::nvvm_sqrt_rm_f,
3586 llvm::Intrinsic::nvvm_sqrt_rp_f,
3587 llvm::Intrinsic::nvvm_sqrt_rz_f,
3589 static constexpr llvm::Intrinsic::ID f32FTZIDs[] = {
3590 llvm::Intrinsic::nvvm_sqrt_rn_ftz_f,
3591 llvm::Intrinsic::nvvm_sqrt_rm_ftz_f,
3592 llvm::Intrinsic::nvvm_sqrt_rp_ftz_f,
3593 llvm::Intrinsic::nvvm_sqrt_rz_ftz_f,
3595 static constexpr llvm::Intrinsic::ID f64IDs[] = {
3596 llvm::Intrinsic::nvvm_sqrt_rn_d,
3597 llvm::Intrinsic::nvvm_sqrt_rm_d,
3598 llvm::Intrinsic::nvvm_sqrt_rp_d,
3599 llvm::Intrinsic::nvvm_sqrt_rz_d,
3602 llvm::Intrinsic::ID
id =
3603 t.
isF32() ? (isFtz ? f32FTZIDs[rndIndex] : f32IDs[rndIndex])
3611 llvm::IRBuilderBase &builder) {
3612 auto thisOp = cast<NVVM::SqrtApproxOp>(op);
3613 llvm::Intrinsic::ID
id = thisOp.getFtz()
3614 ? llvm::Intrinsic::nvvm_sqrt_approx_ftz_f
3615 : llvm::Intrinsic::nvvm_sqrt_approx_f;
3621 llvm::IRBuilderBase &builder) {
3622 auto thisOp = cast<NVVM::DivFOp>(op);
3623 bool isFtz = thisOp.getFtz();
3625 llvm::Intrinsic::ID id;
3627 if (thisOp.getApprox()) {
3628 id = isFtz ? llvm::Intrinsic::nvvm_div_approx_ftz_f
3629 : llvm::Intrinsic::nvvm_div_approx_f;
3630 }
else if (thisOp.getFull()) {
3633 id = isFtz ? llvm::Intrinsic::nvvm_div_full_ftz
3634 : llvm::Intrinsic::nvvm_div_full;
3637 unsigned rndIndex =
static_cast<unsigned>(thisOp.getRnd()) - 1;
3639 static constexpr llvm::Intrinsic::ID f32IDs[] = {
3640 llvm::Intrinsic::nvvm_div_rn_f,
3641 llvm::Intrinsic::nvvm_div_rm_f,
3642 llvm::Intrinsic::nvvm_div_rp_f,
3643 llvm::Intrinsic::nvvm_div_rz_f,
3645 static constexpr llvm::Intrinsic::ID f32FTZIDs[] = {
3646 llvm::Intrinsic::nvvm_div_rn_ftz_f,
3647 llvm::Intrinsic::nvvm_div_rm_ftz_f,
3648 llvm::Intrinsic::nvvm_div_rp_ftz_f,
3649 llvm::Intrinsic::nvvm_div_rz_ftz_f,
3651 static constexpr llvm::Intrinsic::ID f64IDs[] = {
3652 llvm::Intrinsic::nvvm_div_rn_d,
3653 llvm::Intrinsic::nvvm_div_rm_d,
3654 llvm::Intrinsic::nvvm_div_rp_d,
3655 llvm::Intrinsic::nvvm_div_rz_d,
3657 Type t = thisOp.getRes().getType();
3658 id = t.
isF32() ? (isFtz ? f32FTZIDs[rndIndex] : f32IDs[rndIndex])
3668 llvm::IRBuilderBase &builder) {
3669 auto thisOp = cast<NVVM::PMEventOp>(op);
3673 llvm::Value *maskVal;
3674 if (
auto eventAttr = thisOp.getEventIdAttr()) {
3675 uint16_t mask =
static_cast<uint16_t
>(1u << eventAttr.getInt());
3676 maskVal = llvm::ConstantInt::get(i16Ty, mask);
3679 llvm::ConstantInt::get(i16Ty, thisOp.getMaskedEventIdAttr().getValue());
3682 return {llvm::Intrinsic::nvvm_pm_event_mask, {maskVal}};
3687 auto thisOp = cast<NVVM::MBarrierInitOp>(op);
3689 llvm::Intrinsic::ID
id = isShared ? llvm::Intrinsic::nvvm_mbarrier_init_shared
3690 : llvm::Intrinsic::nvvm_mbarrier_init;
3695 args.push_back(mt.
lookupValue(thisOp.getCount()));
3697 return {id, std::move(args)};
3702 auto thisOp = cast<NVVM::MBarrierInvalOp>(op);
3704 llvm::Intrinsic::ID
id = isShared
3705 ? llvm::Intrinsic::nvvm_mbarrier_inval_shared
3706 : llvm::Intrinsic::nvvm_mbarrier_inval;
3713 auto thisOp = cast<NVVM::MBarrierExpectTxOp>(op);
3716 bool isClusterScope = thisOp.getScope() == NVVM::MemScopeKind::CLUSTER;
3719 size_t index = ((isClusterScope ? 1 : 0) << 1) | (isClusterSpace ? 1 : 0);
3721 static constexpr llvm::Intrinsic::ID IDs[] = {
3722 llvm::Intrinsic::nvvm_mbarrier_expect_tx_scope_cta_space_cta,
3723 llvm::Intrinsic::nvvm_mbarrier_expect_tx_scope_cta_space_cluster,
3724 llvm::Intrinsic::nvvm_mbarrier_expect_tx_scope_cluster_space_cta,
3725 llvm::Intrinsic::nvvm_mbarrier_expect_tx_scope_cluster_space_cluster};
3730 args.push_back(mt.
lookupValue(thisOp.getTxcount()));
3732 return {IDs[
index], std::move(args)};
3737 auto thisOp = cast<NVVM::MBarrierCompleteTxOp>(op);
3740 bool isClusterScope = thisOp.getScope() == NVVM::MemScopeKind::CLUSTER;
3743 size_t index = ((isClusterScope ? 1 : 0) << 1) | (isClusterSpace ? 1 : 0);
3745 static constexpr llvm::Intrinsic::ID IDs[] = {
3746 llvm::Intrinsic::nvvm_mbarrier_complete_tx_scope_cta_space_cta,
3747 llvm::Intrinsic::nvvm_mbarrier_complete_tx_scope_cta_space_cluster,
3748 llvm::Intrinsic::nvvm_mbarrier_complete_tx_scope_cluster_space_cta,
3749 llvm::Intrinsic::nvvm_mbarrier_complete_tx_scope_cluster_space_cluster};
3754 args.push_back(mt.
lookupValue(thisOp.getTxcount()));
3756 return {IDs[
index], std::move(args)};
3761 auto thisOp = cast<NVVM::MBarrierArriveOp>(op);
3764 bool isClusterScope = thisOp.getScope() == NVVM::MemScopeKind::CLUSTER;
3767 size_t index = ((isClusterScope ? 1 : 0) << 1) | (isClusterSpace ? 1 : 0);
3769 static constexpr llvm::Intrinsic::ID IDs[] = {
3770 llvm::Intrinsic::nvvm_mbarrier_arrive_scope_cta_space_cta,
3771 llvm::Intrinsic::nvvm_mbarrier_arrive_scope_cta_space_cluster,
3772 llvm::Intrinsic::nvvm_mbarrier_arrive_scope_cluster_space_cta,
3773 llvm::Intrinsic::nvvm_mbarrier_arrive_scope_cluster_space_cluster};
3774 static constexpr llvm::Intrinsic::ID relaxedIDs[] = {
3775 llvm::Intrinsic::nvvm_mbarrier_arrive_relaxed_scope_cta_space_cta,
3776 llvm::Intrinsic::nvvm_mbarrier_arrive_relaxed_scope_cta_space_cluster,
3777 llvm::Intrinsic::nvvm_mbarrier_arrive_relaxed_scope_cluster_space_cta,
3779 nvvm_mbarrier_arrive_relaxed_scope_cluster_space_cluster};
3780 auto id = thisOp.getRelaxed() ? relaxedIDs[
index] : IDs[
index];
3784 llvm::Value *mbar = mt.
lookupValue(thisOp.getAddr());
3791 bool hasCount =
static_cast<bool>(thisOp.getCount());
3793 (
id == llvm::Intrinsic::nvvm_mbarrier_arrive_scope_cta_space_cta))
3794 return {llvm::Intrinsic::nvvm_mbarrier_arrive_shared, {mbar}};
3798 llvm::Value *count =
3800 : llvm::ConstantInt::get(llvm::Type::getInt32Ty(ctx), 1);
3801 return {id, {mbar, count}};
3806 auto thisOp = cast<NVVM::MBarrierArriveDropOp>(op);
3809 bool isClusterScope = thisOp.getScope() == NVVM::MemScopeKind::CLUSTER;
3812 size_t index = ((isClusterScope ? 1 : 0) << 1) | (isClusterSpace ? 1 : 0);
3814 static constexpr llvm::Intrinsic::ID IDs[] = {
3815 llvm::Intrinsic::nvvm_mbarrier_arrive_drop_scope_cta_space_cta,
3816 llvm::Intrinsic::nvvm_mbarrier_arrive_drop_scope_cta_space_cluster,
3817 llvm::Intrinsic::nvvm_mbarrier_arrive_drop_scope_cluster_space_cta,
3818 llvm::Intrinsic::nvvm_mbarrier_arrive_drop_scope_cluster_space_cluster};
3819 static constexpr llvm::Intrinsic::ID relaxedIDs[] = {
3820 llvm::Intrinsic::nvvm_mbarrier_arrive_drop_relaxed_scope_cta_space_cta,
3822 nvvm_mbarrier_arrive_drop_relaxed_scope_cta_space_cluster,
3824 nvvm_mbarrier_arrive_drop_relaxed_scope_cluster_space_cta,
3826 nvvm_mbarrier_arrive_drop_relaxed_scope_cluster_space_cluster};
3827 auto id = thisOp.getRelaxed() ? relaxedIDs[
index] : IDs[
index];
3831 llvm::Value *mbar = mt.
lookupValue(thisOp.getAddr());
3837 bool hasCount =
static_cast<bool>(thisOp.getCount());
3838 llvm::Value *count =
3840 : llvm::ConstantInt::get(llvm::Type::getInt32Ty(ctx), 1);
3842 return {id, {mbar, count}};
3845bool MBarrierArriveExpectTxOp::getAsmValues(
3852 for (
auto val : getOperands())
3860 auto thisOp = cast<NVVM::MBarrierArriveExpectTxOp>(op);
3863 bool isClusterScope = thisOp.getScope() == NVVM::MemScopeKind::CLUSTER;
3866 size_t index = ((isClusterScope ? 1 : 0) << 1) | (isClusterSpace ? 1 : 0);
3869 static constexpr llvm::Intrinsic::ID IDs[] = {
3870 llvm::Intrinsic::nvvm_mbarrier_arrive_expect_tx_scope_cta_space_cta,
3871 llvm::Intrinsic::nvvm_mbarrier_arrive_expect_tx_scope_cta_space_cluster,
3872 llvm::Intrinsic::nvvm_mbarrier_arrive_expect_tx_scope_cluster_space_cta,
3873 llvm::Intrinsic::nvvm_mbarrier_arrive_expect_tx_scope_cluster_space_cluster};
3874 static constexpr llvm::Intrinsic::ID relaxedIDs[] = {
3875 llvm::Intrinsic::nvvm_mbarrier_arrive_expect_tx_relaxed_scope_cta_space_cta,
3876 llvm::Intrinsic::nvvm_mbarrier_arrive_expect_tx_relaxed_scope_cta_space_cluster,
3877 llvm::Intrinsic::nvvm_mbarrier_arrive_expect_tx_relaxed_scope_cluster_space_cta,
3878 llvm::Intrinsic::nvvm_mbarrier_arrive_expect_tx_relaxed_scope_cluster_space_cluster};
3880 auto id = thisOp.getRelaxed() ? relaxedIDs[
index] : IDs[
index];
3883 llvm::Value *txcount = mt.
lookupValue(thisOp.getTxcount());
3884 llvm::Value *mbar = mt.
lookupValue(thisOp.getAddr());
3889 return {id, {mbar, txcount}};
3894 auto thisOp = cast<NVVM::MBarrierArriveDropExpectTxOp>(op);
3897 bool isClusterScope = thisOp.getScope() == NVVM::MemScopeKind::CLUSTER;
3900 size_t index = ((isClusterScope ? 1 : 0) << 1) | (isClusterSpace ? 1 : 0);
3903 static constexpr llvm::Intrinsic::ID IDs[] = {
3904 llvm::Intrinsic::nvvm_mbarrier_arrive_drop_expect_tx_scope_cta_space_cta,
3905 llvm::Intrinsic::nvvm_mbarrier_arrive_drop_expect_tx_scope_cta_space_cluster,
3906 llvm::Intrinsic::nvvm_mbarrier_arrive_drop_expect_tx_scope_cluster_space_cta,
3907 llvm::Intrinsic::nvvm_mbarrier_arrive_drop_expect_tx_scope_cluster_space_cluster};
3908 static constexpr llvm::Intrinsic::ID relaxedIDs[] = {
3909 llvm::Intrinsic::nvvm_mbarrier_arrive_drop_expect_tx_relaxed_scope_cta_space_cta,
3910 llvm::Intrinsic::nvvm_mbarrier_arrive_drop_expect_tx_relaxed_scope_cta_space_cluster,
3911 llvm::Intrinsic::nvvm_mbarrier_arrive_drop_expect_tx_relaxed_scope_cluster_space_cta,
3912 llvm::Intrinsic::nvvm_mbarrier_arrive_drop_expect_tx_relaxed_scope_cluster_space_cluster};
3914 auto id = thisOp.getRelaxed() ? relaxedIDs[
index] : IDs[
index];
3917 llvm::Value *txcount = mt.
lookupValue(thisOp.getTxcount());
3918 llvm::Value *mbar = mt.
lookupValue(thisOp.getAddr());
3923 return {id, {mbar, txcount}};
3928 auto thisOp = cast<NVVM::MBarrierArriveNocompleteOp>(op);
3930 llvm::Intrinsic::ID
id =
3931 isShared ? llvm::Intrinsic::nvvm_mbarrier_arrive_noComplete_shared
3932 : llvm::Intrinsic::nvvm_mbarrier_arrive_noComplete;
3936 args.push_back(mt.
lookupValue(thisOp.getCount()));
3938 return {id, std::move(args)};
3943 auto thisOp = cast<NVVM::MBarrierArriveDropNocompleteOp>(op);
3945 llvm::Intrinsic::ID
id =
3946 isShared ? llvm::Intrinsic::nvvm_mbarrier_arrive_drop_noComplete_shared
3947 : llvm::Intrinsic::nvvm_mbarrier_arrive_drop_noComplete;
3951 args.push_back(mt.
lookupValue(thisOp.getCount()));
3953 return {id, std::move(args)};
3958 auto thisOp = cast<NVVM::MBarrierTestWaitOp>(op);
3959 bool isPhaseParity = thisOp.getStateOrPhase().getType().isInteger(32);
3960 bool isClusterScope = thisOp.getScope() == NVVM::MemScopeKind::CLUSTER;
3963 size_t index = ((isClusterScope ? 1 : 0) << 1) | (isPhaseParity ? 1 : 0);
3966 static constexpr llvm::Intrinsic::ID IDs[] = {
3967 llvm::Intrinsic::nvvm_mbarrier_test_wait_scope_cta_space_cta,
3968 llvm::Intrinsic::nvvm_mbarrier_test_wait_parity_scope_cta_space_cta,
3969 llvm::Intrinsic::nvvm_mbarrier_test_wait_scope_cluster_space_cta,
3970 llvm::Intrinsic::nvvm_mbarrier_test_wait_parity_scope_cluster_space_cta};
3971 static constexpr llvm::Intrinsic::ID relaxedIDs[] = {
3972 llvm::Intrinsic::nvvm_mbarrier_test_wait_relaxed_scope_cta_space_cta,
3973 llvm::Intrinsic::nvvm_mbarrier_test_wait_parity_relaxed_scope_cta_space_cta,
3974 llvm::Intrinsic::nvvm_mbarrier_test_wait_relaxed_scope_cluster_space_cta,
3975 llvm::Intrinsic::nvvm_mbarrier_test_wait_parity_relaxed_scope_cluster_space_cta};
3977 auto id = thisOp.getRelaxed() ? relaxedIDs[
index] : IDs[
index];
3980 llvm::Value *mbar = mt.
lookupValue(thisOp.getAddr());
3981 llvm::Value *input = mt.
lookupValue(thisOp.getStateOrPhase());
3986 return {id, {mbar, input}};
3991 auto thisOp = cast<NVVM::MBarrierTryWaitOp>(op);
3992 bool isPhaseParity = thisOp.getStateOrPhase().getType().isInteger(32);
3993 bool isClusterScope = thisOp.getScope() == NVVM::MemScopeKind::CLUSTER;
3994 bool hasTicks =
static_cast<bool>(thisOp.getTicks());
3998 size_t index = ((hasTicks ? 1 : 0) << 2) | ((isClusterScope ? 1 : 0) << 1) |
3999 (isPhaseParity ? 1 : 0);
4002 static constexpr llvm::Intrinsic::ID IDs[] = {
4003 llvm::Intrinsic::nvvm_mbarrier_try_wait_scope_cta_space_cta,
4004 llvm::Intrinsic::nvvm_mbarrier_try_wait_parity_scope_cta_space_cta,
4005 llvm::Intrinsic::nvvm_mbarrier_try_wait_scope_cluster_space_cta,
4006 llvm::Intrinsic::nvvm_mbarrier_try_wait_parity_scope_cluster_space_cta,
4007 llvm::Intrinsic::nvvm_mbarrier_try_wait_tl_scope_cta_space_cta,
4008 llvm::Intrinsic::nvvm_mbarrier_try_wait_parity_tl_scope_cta_space_cta,
4009 llvm::Intrinsic::nvvm_mbarrier_try_wait_tl_scope_cluster_space_cta,
4010 llvm::Intrinsic::nvvm_mbarrier_try_wait_parity_tl_scope_cluster_space_cta};
4011 static constexpr llvm::Intrinsic::ID relaxedIDs[] = {
4012 llvm::Intrinsic::nvvm_mbarrier_try_wait_relaxed_scope_cta_space_cta,
4013 llvm::Intrinsic::nvvm_mbarrier_try_wait_parity_relaxed_scope_cta_space_cta,
4014 llvm::Intrinsic::nvvm_mbarrier_try_wait_relaxed_scope_cluster_space_cta,
4015 llvm::Intrinsic::nvvm_mbarrier_try_wait_parity_relaxed_scope_cluster_space_cta,
4016 llvm::Intrinsic::nvvm_mbarrier_try_wait_tl_relaxed_scope_cta_space_cta,
4017 llvm::Intrinsic::nvvm_mbarrier_try_wait_parity_tl_relaxed_scope_cta_space_cta,
4018 llvm::Intrinsic::nvvm_mbarrier_try_wait_tl_relaxed_scope_cluster_space_cta,
4019 llvm::Intrinsic::nvvm_mbarrier_try_wait_parity_tl_relaxed_scope_cluster_space_cta};
4021 auto id = thisOp.getRelaxed() ? relaxedIDs[
index] : IDs[
index];
4024 llvm::Value *mbar = mt.
lookupValue(thisOp.getAddr());
4031 args.push_back(mbar);
4032 args.push_back(mt.
lookupValue(thisOp.getStateOrPhase()));
4034 args.push_back(mt.
lookupValue(thisOp.getTicks()));
4036 return {id, std::move(args)};
4041 auto thisOp = cast<NVVM::CpAsyncMBarrierArriveOp>(op);
4044 llvm::Intrinsic::ID id;
4045 if (thisOp.getNoinc()) {
4046 id = isShared ? llvm::Intrinsic::nvvm_cp_async_mbarrier_arrive_noinc_shared
4047 : llvm::Intrinsic::nvvm_cp_async_mbarrier_arrive_noinc;
4049 id = isShared ? llvm::Intrinsic::nvvm_cp_async_mbarrier_arrive_shared
4050 : llvm::Intrinsic::nvvm_cp_async_mbarrier_arrive;
4058 llvm::IRBuilderBase &builder) {
4059 auto thisOp = cast<NVVM::MovMatrixOp>(op);
4060 return {llvm::Intrinsic::nvvm_movmatrix_sync_aligned_m8n8_trans_b16,
4064#define CP_ASYNC_ID_IMPL(mod, size, suffix) \
4065 llvm::Intrinsic::nvvm_cp_async_##mod##_shared_global_##size##suffix
4067#define GET_CP_ASYNC_ID(mod, size, has_cpsize) \
4068 has_cpsize ? CP_ASYNC_ID_IMPL(mod, size, _s) : CP_ASYNC_ID_IMPL(mod, size, )
4073 llvm::Intrinsic::ID id;
4075 auto cpAsyncOp = cast<NVVM::CpAsyncOp>(op);
4076 bool hasCpSize =
static_cast<bool>(cpAsyncOp.getCpSize());
4077 switch (cpAsyncOp.getSize()) {
4085 id = (cpAsyncOp.getModifier() == NVVM::LoadCacheModifierKind::CG)
4090 llvm_unreachable(
"Invalid copy size in CpAsyncOp.");
4094 args.push_back(mt.
lookupValue(cpAsyncOp.getDst()));
4095 args.push_back(mt.
lookupValue(cpAsyncOp.getSrc()));
4097 args.push_back(mt.
lookupValue(cpAsyncOp.getCpSize()));
4104 auto thisOp = cast<NVVM::CpAsyncBulkPrefetchOp>(op);
4106 llvm::Intrinsic::ID
id = llvm::Intrinsic::nvvm_cp_async_bulk_prefetch_L2;
4109 args.push_back(mt.
lookupValue(thisOp.getSrcMem()));
4113 const bool hasCacheHint =
static_cast<bool>(cacheHint);
4114 llvm::Value *i64Unused =
4115 llvm::ConstantInt::get(llvm::Type::getInt64Ty(mt.
getLLVMContext()), 0);
4116 args.push_back(hasCacheHint ? mt.
lookupValue(cacheHint) : i64Unused);
4117 args.push_back(builder.getInt1(hasCacheHint));
4119 return {id, std::move(args)};
4124 auto thisOp = cast<NVVM::CpAsyncBulkGlobalToSharedClusterOp>(op);
4128 args.push_back(mt.
lookupValue(thisOp.getDstMem()));
4130 args.push_back(mt.
lookupValue(thisOp.getSrcMem()));
4134 mlir::Value multicastMask = thisOp.getMulticastMask();
4135 const bool hasMulticastMask =
static_cast<bool>(multicastMask);
4138 llvm::Value *i16Unused = llvm::ConstantInt::get(builder.getInt16Ty(), 0);
4139 args.push_back(hasMulticastMask ? mt.
lookupValue(multicastMask)
4145 const bool hasCacheHint =
static_cast<bool>(cacheHint);
4146 llvm::Value *i64Unused = llvm::ConstantInt::get(builder.getInt64Ty(), 0);
4147 args.push_back(hasCacheHint ? mt.
lookupValue(cacheHint) : i64Unused);
4151 args.push_back(builder.getInt1(hasMulticastMask));
4152 args.push_back(builder.getInt1(hasCacheHint));
4154 llvm::Intrinsic::ID
id =
4156 ? llvm::Intrinsic::nvvm_cp_async_bulk_global_to_shared_cta
4157 : llvm::Intrinsic::nvvm_cp_async_bulk_global_to_shared_cluster;
4159 return {id, std::move(args)};
4164 auto thisOp = cast<NVVM::CpAsyncBulkSharedCTAToGlobalOp>(op);
4166 llvm::Intrinsic::ID
id =
4167 llvm::Intrinsic::nvvm_cp_async_bulk_shared_cta_to_global;
4170 args.push_back(mt.
lookupValue(thisOp.getDstMem()));
4171 args.push_back(mt.
lookupValue(thisOp.getSrcMem()));
4175 const bool hasCacheHint =
static_cast<bool>(cacheHint);
4176 llvm::Value *i64Unused =
4177 llvm::ConstantInt::get(llvm::Type::getInt64Ty(mt.
getLLVMContext()), 0);
4178 args.push_back(hasCacheHint ? mt.
lookupValue(cacheHint) : i64Unused);
4179 args.push_back(builder.getInt1(hasCacheHint));
4182 if (
mlir::Value byteMask = thisOp.getByteMask()) {
4184 id = llvm::Intrinsic::nvvm_cp_async_bulk_shared_cta_to_global_bytemask;
4187 return {id, std::move(args)};
4190bool CpAsyncBulkTensorGlobalToSharedClusterOp::getAsmValues(
4197 for (
auto val : getOperands())
4204CpAsyncBulkTensorGlobalToSharedClusterOp::getIntrinsicIDAndArgs(
4206 auto thisOp = cast<NVVM::CpAsyncBulkTensorGlobalToSharedClusterOp>(op);
4207 const bool isCTAOnly = thisOp.getIsCTAOnly();
4211 args.push_back(mt.
lookupValue(thisOp.getDstMem()));
4213 args.push_back(mt.
lookupValue(thisOp.getTmaDescriptor()));
4223 const bool hasMC =
static_cast<bool>(mcMask);
4224 llvm::Value *i16Zero =
4225 llvm::ConstantInt::get(llvm::Type::getInt16Ty(mt.
getLLVMContext()), 0);
4229 const bool hasCacheHint =
static_cast<bool>(cacheHint);
4230 llvm::Value *i64Zero =
4231 llvm::ConstantInt::get(llvm::Type::getInt64Ty(mt.
getLLVMContext()), 0);
4237 thisOp.getGroup() ? (
static_cast<int32_t
>(*thisOp.getGroup()) + 1) : 0;
4239 llvm::ConstantInt::get(llvm::Type::getInt32Ty(mt.
getLLVMContext()), val);
4243 args.push_back(hasMC ? mt.
lookupValue(mcMask) : i16Zero);
4244 args.push_back(hasCacheHint ? mt.
lookupValue(cacheHint) : i64Zero);
4245 args.push_back(builder.getInt1(hasMC));
4246 args.push_back(builder.getInt1(hasCacheHint));
4250 args.push_back(hasCacheHint ? mt.
lookupValue(cacheHint) : i64Zero);
4251 args.push_back(builder.getInt1(hasCacheHint));
4254 constexpr size_t numDims = 5;
4255 constexpr size_t numModes = 5;
4256 using rowTy = std::array<llvm::Intrinsic::ID, numDims + 1>;
4257 using TableTy = std::array<rowTy, numModes>;
4258 static constexpr TableTy IDTable{
4259 {{
notIntrinsic, llvm::Intrinsic::nvvm_cp_async_bulk_tensor_g2s_tile_1d,
4260 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_g2s_tile_2d,
4261 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_g2s_tile_3d,
4262 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_g2s_tile_4d,
4263 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_g2s_tile_5d},
4265 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_g2s_im2col_3d,
4266 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_g2s_im2col_4d,
4267 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_g2s_im2col_5d},
4269 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_g2s_im2col_w_3d,
4270 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_g2s_im2col_w_4d,
4271 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_g2s_im2col_w_5d},
4273 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_g2s_im2col_w_128_3d,
4274 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_g2s_im2col_w_128_4d,
4275 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_g2s_im2col_w_128_5d},
4277 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_g2s_tile_gather4_2d}}};
4279 static constexpr TableTy IDTableCTA{
4281 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_g2s_cta_tile_1d,
4282 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_g2s_cta_tile_2d,
4283 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_g2s_cta_tile_3d,
4284 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_g2s_cta_tile_4d,
4285 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_g2s_cta_tile_5d},
4287 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_g2s_cta_im2col_3d,
4288 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_g2s_cta_im2col_4d,
4289 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_g2s_cta_im2col_5d},
4291 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_g2s_cta_im2col_w_3d,
4292 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_g2s_cta_im2col_w_4d,
4293 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_g2s_cta_im2col_w_5d},
4295 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_g2s_cta_im2col_w_128_3d,
4296 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_g2s_cta_im2col_w_128_4d,
4297 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_g2s_cta_im2col_w_128_5d},
4299 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_g2s_cta_tile_gather4_2d}}};
4302 (getMaxEnumValForTMALoadMode() == std::size(IDTable) - 1) &&
4303 (getMaxEnumValForTMALoadMode() == std::size(IDTableCTA) - 1),
4304 "TMALoadModes must match number of rows in IDTable and IDTableCTA");
4305 size_t mode =
static_cast<size_t>(thisOp.getMode());
4306 size_t dim = thisOp.getCoordinates().size();
4307 auto id = isCTAOnly ? IDTableCTA[mode][dim] : IDTable[mode][dim];
4309 "Invalid intrinsic for CpAsyncBulkTensorGlobalToSharedClusterOp.");
4311 return {id, std::move(args)};
4316 auto thisOp = cast<NVVM::CpAsyncBulkTensorPrefetchOp>(op);
4320 args.push_back(mt.
lookupValue(thisOp.getTmaDescriptor()));
4322 for (
auto v : thisOp.getCoordinates())
4324 for (
auto v : thisOp.getIm2colOffsets())
4328 const bool hasCacheHint =
static_cast<bool>(cacheHint);
4329 llvm::Value *i64Unused =
4330 llvm::ConstantInt::get(llvm::Type::getInt64Ty(mt.
getLLVMContext()), 0);
4331 args.push_back(hasCacheHint ? mt.
lookupValue(cacheHint) : i64Unused);
4332 args.push_back(builder.getInt1(hasCacheHint));
4334 const unsigned NI = llvm::Intrinsic::not_intrinsic;
4335 static constexpr llvm::Intrinsic::ID IDTable[][6] = {
4336 {NI, llvm::Intrinsic::nvvm_cp_async_bulk_tensor_prefetch_tile_1d,
4337 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_prefetch_tile_2d,
4338 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_prefetch_tile_3d,
4339 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_prefetch_tile_4d,
4340 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_prefetch_tile_5d},
4342 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_prefetch_im2col_3d,
4343 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_prefetch_im2col_4d,
4344 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_prefetch_im2col_5d},
4346 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_prefetch_im2col_w_3d,
4347 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_prefetch_im2col_w_4d,
4348 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_prefetch_im2col_w_5d},
4350 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_prefetch_im2col_w_128_3d,
4351 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_prefetch_im2col_w_128_4d,
4352 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_prefetch_im2col_w_128_5d},
4353 {NI, NI, NI, NI, NI,
4354 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_prefetch_tile_gather4_2d}};
4356 static_assert(getMaxEnumValForTMALoadMode() == std::size(IDTable) - 1,
4357 "TMALoadModes must match number of rows in IDTable");
4358 size_t mode =
static_cast<size_t>(thisOp.getMode());
4359 size_t dim = thisOp.getCoordinates().size();
4360 llvm::Intrinsic::ID
id = IDTable[mode][dim];
4361 if (
id == llvm::Intrinsic::not_intrinsic)
4362 llvm_unreachable(
"Invalid intrinsic for CpAsyncBulkTensorPrefetchOp.");
4364 return {id, std::move(args)};
4368CpAsyncBulkTensorSharedCTAToGlobalOp::getIntrinsicIDAndArgs(
4370 auto thisOp = cast<NVVM::CpAsyncBulkTensorSharedCTAToGlobalOp>(op);
4374 args.push_back(mt.
lookupValue(thisOp.getSrcMem()));
4375 args.push_back(mt.
lookupValue(thisOp.getTmaDescriptor()));
4377 for (
auto v : thisOp.getCoordinates())
4381 const bool hasCacheHint =
static_cast<bool>(cacheHint);
4382 llvm::Value *i64Unused =
4383 llvm::ConstantInt::get(llvm::Type::getInt64Ty(mt.
getLLVMContext()), 0);
4384 args.push_back(hasCacheHint ? mt.
lookupValue(cacheHint) : i64Unused);
4385 args.push_back(builder.getInt1(hasCacheHint));
4387 const unsigned NI = llvm::Intrinsic::not_intrinsic;
4388 static constexpr llvm::Intrinsic::ID IDTable[][6] = {
4389 {NI, llvm::Intrinsic::nvvm_cp_async_bulk_tensor_s2g_tile_1d,
4390 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_s2g_tile_2d,
4391 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_s2g_tile_3d,
4392 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_s2g_tile_4d,
4393 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_s2g_tile_5d},
4394 {NI, NI, NI, llvm::Intrinsic::nvvm_cp_async_bulk_tensor_s2g_im2col_3d,
4395 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_s2g_im2col_4d,
4396 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_s2g_im2col_5d},
4397 {NI, NI, NI, NI, NI,
4398 llvm::Intrinsic::nvvm_cp_async_bulk_tensor_s2g_tile_scatter4_2d}};
4400 static_assert(getMaxEnumValForTMAStoreMode() == std::size(IDTable) - 1,
4401 "TMAStoreModes must match number of rows in IDTable");
4402 size_t mode =
static_cast<size_t>(thisOp.getMode());
4403 size_t dim = thisOp.getCoordinates().size();
4404 llvm::Intrinsic::ID
id = IDTable[mode][dim];
4405 if (
id == llvm::Intrinsic::not_intrinsic)
4407 "Invalid intrinsic for CpAsyncBulkTensorSharedCTAToGlobalOp.");
4409 return {id, std::move(args)};
4414 auto thisOp = cast<NVVM::CpAsyncBulkTensorReduceOp>(op);
4417 args.push_back(mt.
lookupValue(thisOp.getSrcMem()));
4418 args.push_back(mt.
lookupValue(thisOp.getTmaDescriptor()));
4419 for (
Value v : thisOp.getCoordinates())
4423 const bool hasCacheHint =
static_cast<bool>(cacheHint);
4424 args.push_back(hasCacheHint ? mt.
lookupValue(cacheHint)
4425 : builder.getInt64(0));
4426 args.push_back(builder.getInt32(
static_cast<uint32_t
>(thisOp.getRedKind())));
4427 args.push_back(builder.getInt1(hasCacheHint));
4429 using namespace llvm::Intrinsic;
4430 const unsigned NI = not_intrinsic;
4431 static constexpr ID IDTable[][6] = {
4432 {NI, nvvm_cp_async_bulk_tensor_reduce_tile_1d,
4433 nvvm_cp_async_bulk_tensor_reduce_tile_2d,
4434 nvvm_cp_async_bulk_tensor_reduce_tile_3d,
4435 nvvm_cp_async_bulk_tensor_reduce_tile_4d,
4436 nvvm_cp_async_bulk_tensor_reduce_tile_5d},
4437 {NI, NI, NI, nvvm_cp_async_bulk_tensor_reduce_im2col_3d,
4438 nvvm_cp_async_bulk_tensor_reduce_im2col_4d,
4439 nvvm_cp_async_bulk_tensor_reduce_im2col_5d}};
4441 size_t mode =
static_cast<size_t>(thisOp.getMode());
4442 size_t dim = thisOp.getCoordinates().size();
4443 assert(mode < std::size(IDTable) &&
4444 "Invalid mode for CpAsyncBulkTensorReduceOp");
4445 assert(dim < std::size(IDTable[mode]) &&
4446 "Invalid dim for CpAsyncBulkTensorReduceOp");
4448 ID intrinsicID = IDTable[mode][dim];
4449 assert(intrinsicID != NI &&
4450 "Invalid intrinsic for CpAsyncBulkTensorReduceOp");
4451 return {intrinsicID, std::move(args)};
4456#define CVT_F2TF32_ID_IMPL(rnd, relu, sf) \
4457 hasRelu ? llvm::Intrinsic::nvvm_f2tf32_##rnd##relu##sf \
4458 : llvm::Intrinsic::nvvm_f2tf32_##rnd##sf
4460#define GET_CVT_F2TF32_ID(rnd, relu, sf) \
4461 hasSatFinite ? CVT_F2TF32_ID_IMPL(rnd, relu, sf) \
4462 : CVT_F2TF32_ID_IMPL(rnd, relu, )
4465ConvertFloatToTF32Op::getIntrinsicID(NVVM::FPRoundingMode rnd,
4466 NVVM::SaturationMode sat,
bool hasRelu) {
4467 using RndMode = NVVM::FPRoundingMode;
4468 bool hasSatFinite = (sat == NVVM::SaturationMode::SATFINITE);
4477 llvm_unreachable(
"Invalid RoundingMode for CvtFloatToTF32Op");
4482ConvertF32x2ToF4x2Op::getIntrinsicIDAndArgs(NVVM::ConvertF32x2ToF4x2Op op,
4484 llvm::IRBuilderBase &builder) {
4489 bool hasRelu = op.getRelu();
4491 llvm::Intrinsic::ID intId =
4492 hasRelu ? llvm::Intrinsic::nvvm_ff_to_e2m1x2_rn_relu_satfinite
4493 : llvm::Intrinsic::nvvm_ff_to_e2m1x2_rn_satfinite;
4495 return {intId, std::move(args)};
4498#define GET_F32x2_TO_F6x2_ID(type, has_relu) \
4499 has_relu ? llvm::Intrinsic::nvvm_ff_to_##type##_rn_relu_satfinite \
4500 : llvm::Intrinsic::nvvm_ff_to_##type##_rn_satfinite
4502llvm::Intrinsic::ID ConvertF32x2ToF6x2Op::getIntrinsicID(
mlir::Type dstTy,
4505 .Case([&](mlir::Float6E2M3FNType) {
4508 .Case([&](mlir::Float6E3M2FNType) {
4512 llvm_unreachable(
"Invalid conversion in ConvertF32x2ToF6x2Op");
4513 return llvm::Intrinsic::not_intrinsic;
4518ConvertF16x2ToF4x2Op::getIntrinsicIDAndArgs(NVVM::ConvertF16x2ToF4x2Op &op,
4520 llvm::IRBuilderBase &builder) {
4522 bool hasRelu = op.getRelu();
4524 llvm::Intrinsic::ID intId = llvm::Intrinsic::not_intrinsic;
4526 if (llvm::isa<mlir::Float4E2M1FNType>(dstTy))
4527 intId = hasRelu ? llvm::Intrinsic::nvvm_f16x2_to_e2m1x2_rn_relu_satfinite
4528 : llvm::Intrinsic::nvvm_f16x2_to_e2m1x2_rn_satfinite;
4533 return {intId, std::move(args)};
4537ConvertBF16x2ToF4x2Op::getIntrinsicIDAndArgs(NVVM::ConvertBF16x2ToF4x2Op &op,
4539 llvm::IRBuilderBase &builder) {
4541 bool hasRelu = op.getRelu();
4543 llvm::Intrinsic::ID intId = llvm::Intrinsic::not_intrinsic;
4545 if (llvm::isa<mlir::Float4E2M1FNType>(dstTy))
4546 intId = hasRelu ? llvm::Intrinsic::nvvm_bf16x2_to_e2m1x2_rn_relu_satfinite
4547 : llvm::Intrinsic::nvvm_bf16x2_to_e2m1x2_rn_satfinite;
4552 return {intId, std::move(args)};
4555llvm::Intrinsic::ID ConvertF16x2ToF6x2Op::getIntrinsicID(
mlir::Type dstTy,
4558 .Case<mlir::Float6E2M3FNType>([&](mlir::Float6E2M3FNType) {
4559 return hasRelu ? llvm::Intrinsic::nvvm_f16x2_to_e2m3x2_rn_relu_satfinite
4560 : llvm::Intrinsic::nvvm_f16x2_to_e2m3x2_rn_satfinite;
4562 .Case<mlir::Float6E3M2FNType>([&](mlir::Float6E3M2FNType) {
4563 return hasRelu ? llvm::Intrinsic::nvvm_f16x2_to_e3m2x2_rn_relu_satfinite
4564 : llvm::Intrinsic::nvvm_f16x2_to_e3m2x2_rn_satfinite;
4567 llvm_unreachable(
"Invalid conversion in ConvertF16x2ToF6x2Op");
4568 return llvm::Intrinsic::not_intrinsic;
4572llvm::Intrinsic::ID ConvertBF16x2ToF6x2Op::getIntrinsicID(
mlir::Type dstTy,
4575 .Case<mlir::Float6E2M3FNType>([&](mlir::Float6E2M3FNType) {
4577 ? llvm::Intrinsic::nvvm_bf16x2_to_e2m3x2_rn_relu_satfinite
4578 : llvm::Intrinsic::nvvm_bf16x2_to_e2m3x2_rn_satfinite;
4580 .Case<mlir::Float6E3M2FNType>([&](mlir::Float6E3M2FNType) {
4582 ? llvm::Intrinsic::nvvm_bf16x2_to_e3m2x2_rn_relu_satfinite
4583 : llvm::Intrinsic::nvvm_bf16x2_to_e3m2x2_rn_satfinite;
4586 llvm_unreachable(
"Invalid conversion in ConvertBF16x2ToF6x2Op");
4587 return llvm::Intrinsic::not_intrinsic;
4591#define GET_F32x2_TO_F8X2_US_ID(rnd, has_satf) \
4592 has_satf ? llvm::Intrinsic::nvvm_ff_to_ue8m0x2_##rnd##_satfinite \
4593 : llvm::Intrinsic::nvvm_ff_to_ue8m0x2_##rnd
4595#define GET_F32x2_TO_F8X2_S_ID(type, has_relu) \
4596 has_relu ? llvm::Intrinsic::nvvm_ff_to_##type##_rn_relu \
4597 : llvm::Intrinsic::nvvm_ff_to_##type##_rn
4600ConvertF32x2ToF8x2Op::getIntrinsicID(
mlir::Type dstTy, NVVM::FPRoundingMode rnd,
4601 NVVM::SaturationMode sat,
bool hasRelu) {
4602 bool hasSatFinite = (sat == NVVM::SaturationMode::SATFINITE);
4603 bool hasRoundingModeRZ = (rnd == NVVM::FPRoundingMode::RZ);
4604 bool hasRoundingModeRP = (rnd == NVVM::FPRoundingMode::RP);
4607 .Case([&](mlir::Float8E4M3FNType) {
4610 .Case([&](mlir::Float8E5M2Type) {
4613 .Case([&](mlir::Float8E8M0FNUType) {
4614 if (hasRoundingModeRZ)
4616 else if (hasRoundingModeRP)
4619 llvm_unreachable(
"Invalid conversion in ConvertF32x2ToF8x2Op");
4622 llvm_unreachable(
"Invalid conversion in ConvertF32x2ToF8x2Op");
4623 return llvm::Intrinsic::not_intrinsic;
4627#define GET_F16x2_TO_F8X2_ID(type, has_relu) \
4628 has_relu ? llvm::Intrinsic::nvvm_f16x2_to_##type##_rn_relu \
4629 : llvm::Intrinsic::nvvm_f16x2_to_##type##_rn
4631llvm::Intrinsic::ID ConvertF16x2ToF8x2Op::getIntrinsicID(
mlir::Type dstTy,
4634 .Case([&](mlir::Float8E4M3FNType) {
4637 .Case([&](mlir::Float8E5M2Type) {
4641 llvm_unreachable(
"Invalid conversion in ConvertF16x2ToF8x2Op");
4642 return llvm::Intrinsic::not_intrinsic;
4647ConvertBF16x2ToF8x2Op::getIntrinsicID(
mlir::Type dstTy,
4648 NVVM::FPRoundingMode rnd,
4649 NVVM::SaturationMode sat,
bool hasRelu) {
4650 bool hasSatFinite = (sat == NVVM::SaturationMode::SATFINITE);
4652 static constexpr llvm::Intrinsic::ID ue8m0x2IDs[] = {
4653 llvm::Intrinsic::nvvm_bf16x2_to_ue8m0x2_rz,
4654 llvm::Intrinsic::nvvm_bf16x2_to_ue8m0x2_rp,
4655 llvm::Intrinsic::nvvm_bf16x2_to_ue8m0x2_rz_satfinite,
4656 llvm::Intrinsic::nvvm_bf16x2_to_ue8m0x2_rp_satfinite,
4660 .Case<mlir::Float8E4M3FNType>([&](mlir::Float8E4M3FNType) {
4662 ? llvm::Intrinsic::nvvm_bf16x2_to_e4m3x2_rn_relu_satfinite
4663 : llvm::Intrinsic::nvvm_bf16x2_to_e4m3x2_rn_satfinite;
4665 .Case<mlir::Float8E5M2Type>([&](mlir::Float8E5M2Type) {
4667 ? llvm::Intrinsic::nvvm_bf16x2_to_e5m2x2_rn_relu_satfinite
4668 : llvm::Intrinsic::nvvm_bf16x2_to_e5m2x2_rn_satfinite;
4670 .Case<mlir::Float8E8M0FNUType>([&](mlir::Float8E8M0FNUType) {
4671 bool hasRoundingModeRP = (rnd == NVVM::FPRoundingMode::RP);
4672 unsigned index = (hasSatFinite << 1) | hasRoundingModeRP;
4673 return ue8m0x2IDs[
index];
4676 llvm_unreachable(
"Invalid conversion in ConvertBF16x2ToF8x2Op");
4677 return llvm::Intrinsic::not_intrinsic;
4683 auto curOp = cast<NVVM::ConvertF8x2ToF16x2Op>(op);
4685 bool hasRelu = curOp.getRelu();
4687 llvm::Intrinsic::ID intId =
4689 .Case([&](Float8E4M3FNType type) {
4690 return hasRelu ? llvm::Intrinsic::nvvm_e4m3x2_to_f16x2_rn_relu
4691 : llvm::Intrinsic::nvvm_e4m3x2_to_f16x2_rn;
4693 .Case([&](Float8E5M2Type type) {
4694 return hasRelu ? llvm::Intrinsic::nvvm_e5m2x2_to_f16x2_rn_relu
4695 : llvm::Intrinsic::nvvm_e5m2x2_to_f16x2_rn;
4698 llvm_unreachable(
"Invalid type for ConvertF8x2ToF16x2Op");
4699 return llvm::Intrinsic::not_intrinsic;
4702 llvm::Value *packedI16 =
4703 builder.CreateBitCast(mt.
lookupValue(curOp.getSrc()),
4704 llvm::Type::getInt16Ty(builder.getContext()));
4706 return {intId, {packedI16}};
4711 auto curOp = cast<NVVM::ConvertF8x2ToBF16x2Op>(op);
4712 bool hasScale =
static_cast<bool>(curOp.getScaleFactor());
4713 bool hasSatfinite = curOp.getSat() == NVVM::SaturationMode::SATFINITE;
4714 bool hasRelu = curOp.getRelu();
4716 static constexpr llvm::Intrinsic::ID E4M3Ids[] = {
4717 llvm::Intrinsic::nvvm_e4m3x2_to_bf16x2_rn_scale_n2_ue8m0,
4718 llvm::Intrinsic::nvvm_e4m3x2_to_bf16x2_rn_relu_scale_n2_ue8m0,
4719 llvm::Intrinsic::nvvm_e4m3x2_to_bf16x2_rn_satfinite_scale_n2_ue8m0,
4720 llvm::Intrinsic::nvvm_e4m3x2_to_bf16x2_rn_relu_satfinite_scale_n2_ue8m0,
4723 static constexpr llvm::Intrinsic::ID E5M2Ids[] = {
4724 llvm::Intrinsic::nvvm_e5m2x2_to_bf16x2_rn_scale_n2_ue8m0,
4725 llvm::Intrinsic::nvvm_e5m2x2_to_bf16x2_rn_relu_scale_n2_ue8m0,
4726 llvm::Intrinsic::nvvm_e5m2x2_to_bf16x2_rn_satfinite_scale_n2_ue8m0,
4727 llvm::Intrinsic::nvvm_e5m2x2_to_bf16x2_rn_relu_satfinite_scale_n2_ue8m0,
4730 llvm::Intrinsic::ID intId =
4732 .Case([&](Float8E8M0FNUType type) {
4733 return llvm::Intrinsic::nvvm_ue8m0x2_to_bf16x2;
4735 .Case([&](Float8E4M3FNType type) {
4736 return E4M3Ids[hasSatfinite << 1 | hasRelu];
4738 .Case([&](Float8E5M2Type type) {
4739 return E5M2Ids[hasSatfinite << 1 | hasRelu];
4742 llvm_unreachable(
"Invalid type for ConvertF8x2ToBF16x2Op");
4743 return llvm::Intrinsic::not_intrinsic;
4745 llvm::Value *packedI16 =
4746 builder.CreateBitCast(mt.
lookupValue(curOp.getSrc()),
4747 llvm::Type::getInt16Ty(builder.getContext()));
4750 args.push_back(packedI16);
4751 if (!isa<Float8E8M0FNUType>(curOp.getSrcType()))
4754 : builder.getInt16(0x7f7f));
4757 return {intId, std::move(args)};
4762 auto curOp = cast<NVVM::ConvertF6x2ToF16x2Op>(op);
4764 bool hasRelu = curOp.getRelu();
4766 llvm::Intrinsic::ID intId =
4768 .Case([&](Float6E2M3FNType type) {
4769 return hasRelu ? llvm::Intrinsic::nvvm_e2m3x2_to_f16x2_rn_relu
4770 : llvm::Intrinsic::nvvm_e2m3x2_to_f16x2_rn;
4772 .Case([&](Float6E3M2FNType type) {
4773 return hasRelu ? llvm::Intrinsic::nvvm_e3m2x2_to_f16x2_rn_relu
4774 : llvm::Intrinsic::nvvm_e3m2x2_to_f16x2_rn;
4777 llvm_unreachable(
"Invalid type for ConvertF6x2ToF16x2Op");
4778 return llvm::Intrinsic::not_intrinsic;
4781 llvm::Value *packedI16 =
4782 builder.CreateBitCast(mt.
lookupValue(curOp.getSrc()),
4783 llvm::Type::getInt16Ty(builder.getContext()));
4785 return {intId, {packedI16}};
4790 auto curOp = cast<NVVM::ConvertF6x2ToBF16x2Op>(op);
4791 bool hasScale =
static_cast<bool>(curOp.getScaleFactor());
4792 bool hasSatfinite = curOp.getSat() == NVVM::SaturationMode::SATFINITE;
4793 bool hasRelu = curOp.getRelu();
4795 static constexpr llvm::Intrinsic::ID E2M3Ids[] = {
4796 llvm::Intrinsic::nvvm_e2m3x2_to_bf16x2_rn_scale_n2_ue8m0,
4797 llvm::Intrinsic::nvvm_e2m3x2_to_bf16x2_rn_relu_scale_n2_ue8m0,
4798 llvm::Intrinsic::nvvm_e2m3x2_to_bf16x2_rn_satfinite_scale_n2_ue8m0,
4799 llvm::Intrinsic::nvvm_e2m3x2_to_bf16x2_rn_relu_satfinite_scale_n2_ue8m0,
4802 static constexpr llvm::Intrinsic::ID E3M2Ids[] = {
4803 llvm::Intrinsic::nvvm_e3m2x2_to_bf16x2_rn_scale_n2_ue8m0,
4804 llvm::Intrinsic::nvvm_e3m2x2_to_bf16x2_rn_relu_scale_n2_ue8m0,
4805 llvm::Intrinsic::nvvm_e3m2x2_to_bf16x2_rn_satfinite_scale_n2_ue8m0,
4806 llvm::Intrinsic::nvvm_e3m2x2_to_bf16x2_rn_relu_satfinite_scale_n2_ue8m0,
4809 unsigned idx = (hasSatfinite << 1) | hasRelu;
4810 llvm::Intrinsic::ID intId =
4812 .Case([&](Float6E2M3FNType type) {
return E2M3Ids[idx]; })
4813 .Case([&](Float6E3M2FNType type) {
return E3M2Ids[idx]; })
4815 llvm_unreachable(
"Invalid type for ConvertF6x2ToBF16x2Op");
4816 return llvm::Intrinsic::not_intrinsic;
4819 llvm::Value *packedI16 =
4820 builder.CreateBitCast(mt.
lookupValue(curOp.getSrc()),
4821 llvm::Type::getInt16Ty(builder.getContext()));
4824 args.push_back(packedI16);
4831 return {intId, std::move(args)};
4836 auto curOp = cast<NVVM::ConvertF4x2ToF16x2Op>(op);
4838 bool hasRelu = curOp.getRelu();
4840 llvm::Intrinsic::ID intId =
4842 .Case([&](Float4E2M1FNType type) {
4843 return hasRelu ? llvm::Intrinsic::nvvm_e2m1x2_to_f16x2_rn_relu
4844 : llvm::Intrinsic::nvvm_e2m1x2_to_f16x2_rn;
4847 llvm_unreachable(
"Invalid type for ConvertF4x2ToF16x2Op");
4848 return llvm::Intrinsic::not_intrinsic;
4851 llvm::Value *extendedI16 =
4852 builder.CreateZExt(mt.
lookupValue(curOp.getSrc()),
4853 llvm::Type::getInt16Ty(builder.getContext()));
4855 return {intId, {extendedI16}};
4860 auto curOp = cast<NVVM::ConvertF4x2ToBF16x2Op>(op);
4861 bool hasScale =
static_cast<bool>(curOp.getScaleFactor());
4862 bool hasSatfinite = curOp.getSat() == NVVM::SaturationMode::SATFINITE;
4863 bool hasRelu = curOp.getRelu();
4865 static constexpr llvm::Intrinsic::ID E2M1Ids[] = {
4866 llvm::Intrinsic::nvvm_e2m1x2_to_bf16x2_rn_scale_n2_ue8m0,
4867 llvm::Intrinsic::nvvm_e2m1x2_to_bf16x2_rn_relu_scale_n2_ue8m0,
4868 llvm::Intrinsic::nvvm_e2m1x2_to_bf16x2_rn_satfinite_scale_n2_ue8m0,
4869 llvm::Intrinsic::nvvm_e2m1x2_to_bf16x2_rn_relu_satfinite_scale_n2_ue8m0,
4872 unsigned idx = (hasSatfinite << 1) | hasRelu;
4873 llvm::Intrinsic::ID intId =
4875 .Case([&](Float4E2M1FNType type) {
return E2M1Ids[idx]; })
4877 llvm_unreachable(
"Invalid type for ConvertF4x2ToBF16x2Op");
4878 return llvm::Intrinsic::not_intrinsic;
4881 llvm::Value *extendedI16 =
4882 builder.CreateZExt(mt.
lookupValue(curOp.getSrc()),
4883 llvm::Type::getInt16Ty(builder.getContext()));
4886 args.push_back(extendedI16);
4893 return {intId, std::move(args)};
4898 auto thisOp = cast<NVVM::ConvertF32x2ToS2F6x2Op>(op);
4899 bool hasRelu = thisOp.getRelu();
4900 bool hasScale =
static_cast<bool>(thisOp.getScaleFactor());
4902 llvm::Intrinsic::ID
id =
4904 ? llvm::Intrinsic::nvvm_ff_to_s2f6x2_rn_relu_satfinite_scale_n2_ue8m0
4905 : llvm::Intrinsic::nvvm_ff_to_s2f6x2_rn_satfinite_scale_n2_ue8m0;
4911 args.push_back(hasScale ? mt.
lookupValue(thisOp.getScaleFactor())
4912 : builder.getInt16(0x7f7f));
4913 return {id, std::move(args)};
4918 auto thisOp = cast<NVVM::ConvertBF16x2ToS2F6x2Op>(op);
4919 bool hasRelu = thisOp.getRelu();
4920 bool hasScale =
static_cast<bool>(thisOp.getScaleFactor());
4922 llvm::Intrinsic::ID
id =
4925 nvvm_bf16x2_to_s2f6x2_rn_relu_satfinite_scale_n2_ue8m0
4926 : llvm::Intrinsic::nvvm_bf16x2_to_s2f6x2_rn_satfinite_scale_n2_ue8m0;
4931 args.push_back(hasScale ? mt.
lookupValue(thisOp.getScaleFactor())
4932 : builder.getInt16(0x7f7f));
4933 return {id, std::move(args)};
4938 auto thisOp = cast<NVVM::ConvertS2F6x2ToBF16x2Op>(op);
4939 bool hasRelu = thisOp.getRelu();
4940 bool hasScale =
static_cast<bool>(thisOp.getScaleFactor());
4941 bool hasSat = thisOp.getSat() == NVVM::SaturationMode::SATFINITE;
4943 static constexpr llvm::Intrinsic::ID ids[] = {
4944 llvm::Intrinsic::nvvm_s2f6x2_to_bf16x2_rn_scale_n2_ue8m0,
4945 llvm::Intrinsic::nvvm_s2f6x2_to_bf16x2_rn_relu_scale_n2_ue8m0,
4946 llvm::Intrinsic::nvvm_s2f6x2_to_bf16x2_rn_satfinite_scale_n2_ue8m0,
4947 llvm::Intrinsic::nvvm_s2f6x2_to_bf16x2_rn_relu_satfinite_scale_n2_ue8m0,
4950 unsigned idx = (hasSat << 1) | hasRelu;
4954 llvm::Value *packedI16 =
4955 builder.CreateBitCast(mt.
lookupValue(thisOp.getSrc()),
4956 llvm::Type::getInt16Ty(builder.getContext()));
4957 args.push_back(packedI16);
4958 args.push_back(hasScale ? mt.
lookupValue(thisOp.getScaleFactor())
4959 : builder.getInt16(0x7f7f));
4961 return {ids[idx], std::move(args)};
4965Tcgen05AllocOp::getIntrinsicIDAndArgs(
Operation &op,
4968 auto curOp = cast<NVVM::Tcgen05AllocOp>(op);
4969 unsigned as = llvm::cast<LLVM::LLVMPointerType>(curOp.getAddr().getType())
4971 bool isShared = as == NVVMMemorySpace::Shared;
4972 bool is2CTAMode = curOp.getGroup() == CTAGroupKind::CTA_2;
4974 llvm::Intrinsic::ID id;
4976 id = is2CTAMode ? llvm::Intrinsic::nvvm_tcgen05_alloc_shared_cg2
4977 : llvm::Intrinsic::nvvm_tcgen05_alloc_shared_cg1;
4979 id = is2CTAMode ? llvm::Intrinsic::nvvm_tcgen05_alloc_cg2
4980 : llvm::Intrinsic::nvvm_tcgen05_alloc_cg1;
4990llvm::Intrinsic::ID Tcgen05DeallocOp::getIntrinsicIDAndArgs(
4993 auto curOp = cast<NVVM::Tcgen05DeallocOp>(op);
4994 auto id = (curOp.getGroup() == CTAGroupKind::CTA_1)
4995 ? llvm::Intrinsic::nvvm_tcgen05_dealloc_cg1
4996 : llvm::Intrinsic::nvvm_tcgen05_dealloc_cg2;
5005#define TCGEN05_COMMIT_IMPL(cg, is_shared, mc) \
5006 is_shared ? llvm::Intrinsic::nvvm_tcgen05_commit##mc##_shared##_##cg \
5007 : llvm::Intrinsic::nvvm_tcgen05_commit##mc##_##cg
5009#define GET_TCGEN05_COMMIT_ID(cta_group, is_shared, has_mc) \
5010 has_mc ? TCGEN05_COMMIT_IMPL(cta_group, is_shared, _mc) \
5011 : TCGEN05_COMMIT_IMPL(cta_group, is_shared, )
5014Tcgen05CommitOp::getIntrinsicIDAndArgs(
Operation &op,
5017 auto curOp = cast<NVVM::Tcgen05CommitOp>(op);
5018 unsigned as = llvm::cast<LLVM::LLVMPointerType>(curOp.getAddr().getType())
5020 bool isShared = as == NVVMMemorySpace::Shared;
5021 bool hasMulticast =
static_cast<bool>(curOp.getMulticastMask());
5022 bool is2CTAMode = curOp.getGroup() == CTAGroupKind::CTA_2;
5024 llvm::Intrinsic::ID
id =
5031 args.push_back(mt.
lookupValue(curOp.getMulticastMask()));
5036#define TCGEN05_CP_IMPL(shape_mc, src_fmt, cg) \
5037 llvm::Intrinsic::nvvm_tcgen05_cp##shape_mc##src_fmt##cg
5039#define TCGEN05_CP_2CTA(shape_mc, src_fmt, is_2cta) \
5040 is_2cta ? TCGEN05_CP_IMPL(shape_mc, src_fmt, _cg2) \
5041 : TCGEN05_CP_IMPL(shape_mc, src_fmt, _cg1)
5043#define GET_TCGEN05_CP_ID(shape_mc, src_fmt, is_2cta) \
5045 if ((src_fmt) == Tcgen05CpSrcFormat::B6x16_P32) \
5046 return TCGEN05_CP_2CTA(shape_mc, _b6x16_p32, is_2cta); \
5047 if ((src_fmt) == Tcgen05CpSrcFormat::B4x16_P64) \
5048 return TCGEN05_CP_2CTA(shape_mc, _b4x16_p64, is_2cta); \
5049 return TCGEN05_CP_2CTA(shape_mc, , is_2cta); \
5053ConvertF32x2ToF16x2Op::getIntrinsicIDAndArgs(NVVM::ConvertF32x2ToF16x2Op &op,
5055 llvm::IRBuilderBase &builder) {
5056 static constexpr llvm::Intrinsic::ID rndRNIds[] = {
5057 llvm::Intrinsic::nvvm_ff2f16x2_rn,
5058 llvm::Intrinsic::nvvm_ff2f16x2_rn_relu,
5059 llvm::Intrinsic::nvvm_ff2f16x2_rn_satfinite,
5060 llvm::Intrinsic::nvvm_ff2f16x2_rn_relu_satfinite,
5062 static constexpr llvm::Intrinsic::ID rndRZIds[] = {
5063 llvm::Intrinsic::nvvm_ff2f16x2_rz,
5064 llvm::Intrinsic::nvvm_ff2f16x2_rz_relu,
5065 llvm::Intrinsic::nvvm_ff2f16x2_rz_satfinite,
5066 llvm::Intrinsic::nvvm_ff2f16x2_rz_relu_satfinite,
5068 static constexpr llvm::Intrinsic::ID rndRSIds[] = {
5069 llvm::Intrinsic::nvvm_ff2f16x2_rs,
5070 llvm::Intrinsic::nvvm_ff2f16x2_rs_relu,
5071 llvm::Intrinsic::nvvm_ff2f16x2_rs_satfinite,
5072 llvm::Intrinsic::nvvm_ff2f16x2_rs_relu_satfinite,
5075 unsigned hasRelu = op.getRelu() ? 1 : 0;
5076 unsigned hasSatFinite =
5077 (op.getSat() == NVVM::SaturationMode::SATFINITE) ? 1 : 0;
5080 unsigned idx = (hasSatFinite << 1) | hasRelu;
5085 if (op.getRandomBits())
5086 args.push_back(mt.
lookupValue(op.getRandomBits()));
5088 switch (op.getRnd()) {
5089 case FPRoundingMode::RN:
5090 return {rndRNIds[idx], std::move(args)};
5091 case FPRoundingMode::RZ:
5092 return {rndRZIds[idx], std::move(args)};
5093 case FPRoundingMode::RS:
5094 return {rndRSIds[idx], std::move(args)};
5096 llvm_unreachable(
"Invalid rounding mode for ConvertF32x2ToF16x2Op");
5101ConvertF32x2ToBF16x2Op::getIntrinsicIDAndArgs(NVVM::ConvertF32x2ToBF16x2Op &op,
5103 llvm::IRBuilderBase &builder) {
5104 static constexpr llvm::Intrinsic::ID rndRNIds[] = {
5105 llvm::Intrinsic::nvvm_ff2bf16x2_rn,
5106 llvm::Intrinsic::nvvm_ff2bf16x2_rn_relu,
5107 llvm::Intrinsic::nvvm_ff2bf16x2_rn_satfinite,
5108 llvm::Intrinsic::nvvm_ff2bf16x2_rn_relu_satfinite,
5110 static constexpr llvm::Intrinsic::ID rndRZIds[] = {
5111 llvm::Intrinsic::nvvm_ff2bf16x2_rz,
5112 llvm::Intrinsic::nvvm_ff2bf16x2_rz_relu,
5113 llvm::Intrinsic::nvvm_ff2bf16x2_rz_satfinite,
5114 llvm::Intrinsic::nvvm_ff2bf16x2_rz_relu_satfinite,
5116 static constexpr llvm::Intrinsic::ID rndRSIds[] = {
5117 llvm::Intrinsic::nvvm_ff2bf16x2_rs,
5118 llvm::Intrinsic::nvvm_ff2bf16x2_rs_relu,
5119 llvm::Intrinsic::nvvm_ff2bf16x2_rs_satfinite,
5120 llvm::Intrinsic::nvvm_ff2bf16x2_rs_relu_satfinite,
5123 unsigned hasRelu = op.getRelu() ? 1 : 0;
5124 unsigned hasSatFinite =
5125 (op.getSat() == NVVM::SaturationMode::SATFINITE) ? 1 : 0;
5128 unsigned idx = (hasSatFinite << 1) | hasRelu;
5133 if (op.getRandomBits())
5134 args.push_back(mt.
lookupValue(op.getRandomBits()));
5136 switch (op.getRnd()) {
5137 case FPRoundingMode::RN:
5138 return {rndRNIds[idx], std::move(args)};
5139 case FPRoundingMode::RZ:
5140 return {rndRZIds[idx], std::move(args)};
5141 case FPRoundingMode::RS:
5142 return {rndRSIds[idx], std::move(args)};
5144 llvm_unreachable(
"Invalid rounding mode for ConvertF32x2ToBF16x2Op");
5148llvm::Intrinsic::ID ConvertF32x4ToF8x4Op::getIntrinsicID() {
5150 bool hasRelu = getRelu();
5153 .Case([&](mlir::Float8E4M3FNType) {
5154 return hasRelu ? llvm::Intrinsic::nvvm_f32x4_to_e4m3x4_rs_relu_satfinite
5155 : llvm::Intrinsic::nvvm_f32x4_to_e4m3x4_rs_satfinite;
5157 .Case([&](mlir::Float8E5M2Type) {
5158 return hasRelu ? llvm::Intrinsic::nvvm_f32x4_to_e5m2x4_rs_relu_satfinite
5159 : llvm::Intrinsic::nvvm_f32x4_to_e5m2x4_rs_satfinite;
5162 llvm_unreachable(
"Invalid F8 type in ConvertF32x4ToF8x4Op");
5163 return llvm::Intrinsic::not_intrinsic;
5167llvm::Intrinsic::ID ConvertF32x4ToF6x4Op::getIntrinsicID() {
5169 bool hasRelu = getRelu();
5172 .Case([&](mlir::Float6E2M3FNType) {
5173 return hasRelu ? llvm::Intrinsic::nvvm_f32x4_to_e2m3x4_rs_relu_satfinite
5174 : llvm::Intrinsic::nvvm_f32x4_to_e2m3x4_rs_satfinite;
5176 .Case([&](mlir::Float6E3M2FNType) {
5177 return hasRelu ? llvm::Intrinsic::nvvm_f32x4_to_e3m2x4_rs_relu_satfinite
5178 : llvm::Intrinsic::nvvm_f32x4_to_e3m2x4_rs_satfinite;
5181 llvm_unreachable(
"Invalid F6 type in ConvertF32x4ToF6x4Op");
5182 return llvm::Intrinsic::not_intrinsic;
5186llvm::Intrinsic::ID ConvertF32x4ToF4x4Op::getIntrinsicID() {
5188 bool hasRelu = getRelu();
5191 .Case([&](mlir::Float4E2M1FNType) {
5192 return hasRelu ? llvm::Intrinsic::nvvm_f32x4_to_e2m1x4_rs_relu_satfinite
5193 : llvm::Intrinsic::nvvm_f32x4_to_e2m1x4_rs_satfinite;
5196 llvm_unreachable(
"Invalid F4 type in ConvertF32x4ToF4x4Op");
5197 return llvm::Intrinsic::not_intrinsic;
5201llvm::Intrinsic::ID Tcgen05CpOp::getIntrinsicID(
Operation &op) {
5202 auto curOp = cast<NVVM::Tcgen05CpOp>(op);
5203 bool is2CTA = curOp.getGroup() == CTAGroupKind::CTA_2;
5204 auto srcFmt = curOp.getSrcFormat();
5205 auto mc = curOp.getMulticast();
5207 switch (curOp.getShape()) {
5208 case Tcgen05CpShape::SHAPE_128x256b:
5210 case Tcgen05CpShape::SHAPE_128x128b:
5212 case Tcgen05CpShape::SHAPE_4x256b:
5214 case Tcgen05CpShape::SHAPE_32x128b:
5216 case Tcgen05CpShape::SHAPE_64x128b:
5217 return (mc == Tcgen05CpMulticast::WARPX2_01_23)
5221 llvm_unreachable(
"Invalid shape in tcgen05 cp Op");
5228 if (
shape == NVVM::Tcgen05LdStShape::SHAPE_16X128B)
5230 if (
shape == NVVM::Tcgen05LdStShape::SHAPE_16X256B)
5235LogicalResult Tcgen05LdOp::verify() {
5237 if (
getShape() == NVVM::Tcgen05LdStShape::SHAPE_16X32BX2 && !getOffset())
5240 if (
getShape() != NVVM::Tcgen05LdStShape::SHAPE_16X32BX2 && getOffset())
5241 result =
emitError(
"offset argument is only supported for shape 16x32bx2");
5243 auto resTy = getRes().getType();
5244 unsigned resLen = isa<VectorType>(resTy)
5245 ? llvm::cast<VectorType>(resTy).getNumElements()
5248 result =
emitError(llvm::formatv(
"invalid result type length {0} for shape "
5249 "{1} in tcgen05.ld Op",
5250 resLen, stringifyEnum(
getShape())));
5255LogicalResult Tcgen05StOp::verify() {
5257 if (
getShape() == NVVM::Tcgen05LdStShape::SHAPE_16X32BX2 && !getOffset())
5260 auto valTy = getVal().getType();
5261 unsigned valLen = isa<VectorType>(valTy)
5262 ? llvm::cast<VectorType>(valTy).getNumElements()
5265 result =
emitError(llvm::formatv(
"invalid input length {0} for shape "
5266 "{1} in tcgen05.st Op",
5267 valLen, stringifyEnum(
getShape())));
5277 if (
auto rangeAttr = op->
getAttrOfType<LLVM::ConstantRangeAttr>(
"range")) {
5278 setResultRanges(
result, {rangeAttr.getLower(), rangeAttr.getUpper(),
5279 rangeAttr.getLower(), rangeAttr.getUpper()});
5289 std::optional<LLVM::ConstantRangeAttr> rangeAttr) {
5293 const llvm::APInt &lower = rangeAttr->getLower();
5294 const llvm::APInt &upper = rangeAttr->getUpper();
5297 if (lower == upper && !lower.isMaxValue() && !lower.isMinValue()) {
5298 unsigned bitWidth = lower.getBitWidth();
5299 llvm::APInt minVal = llvm::APInt::getMinValue(bitWidth);
5300 llvm::APInt maxVal = llvm::APInt::getMaxValue(bitWidth);
5302 "invalid range attribute: Lower == Upper, but they aren't min (")
5303 << llvm::toString(minVal, 10,
false) <<
") or max ("
5304 << llvm::toString(maxVal, 10,
false)
5305 <<
") value! This is an invalid constant range.";
5312 llvm::IRBuilderBase &builder) {
5313 return builder.CreateBitCast(arg,
5314 llvm::Type::getInt32Ty(builder.getContext()));
5319 auto curOp = cast<NVVM::DotAccumulate4WayOp>(op);
5326 bool isASigned = curOp.getAType() == NVVM::DotAccumulateType::SIGNED;
5327 bool isBSigned = curOp.getBType() == NVVM::DotAccumulateType::SIGNED;
5328 unsigned type = (isASigned << 1) | isBSigned;
5329 const llvm::Intrinsic::ID ids[] = {
5330 llvm::Intrinsic::nvvm_idp4a_u_u,
5331 llvm::Intrinsic::nvvm_idp4a_u_s,
5332 llvm::Intrinsic::nvvm_idp4a_s_u,
5333 llvm::Intrinsic::nvvm_idp4a_s_s,
5335 return {ids[type], args};
5340 auto curOp = cast<NVVM::DotAccumulate2WayOp>(op);
5345 args.push_back(builder.getInt1(curOp.getBHi()));
5348 bool isASigned = curOp.getAType() == NVVM::DotAccumulateType::SIGNED;
5349 bool isBSigned = curOp.getBType() == NVVM::DotAccumulateType::SIGNED;
5350 unsigned type = (isASigned << 1) | isBSigned;
5351 const llvm::Intrinsic::ID ids[] = {
5352 llvm::Intrinsic::nvvm_idp2a_u_u,
5353 llvm::Intrinsic::nvvm_idp2a_u_s,
5354 llvm::Intrinsic::nvvm_idp2a_s_u,
5355 llvm::Intrinsic::nvvm_idp2a_s_s,
5357 return {ids[type], args};
5361 llvm::IRBuilderBase &builder) {
5362 return builder.CreateAddrSpaceCast(
5363 addr, builder.getPtrTy(llvm::NVPTXAS::ADDRESS_SPACE_ENTRY_PARAM));
5367PrefetchOp::getIntrinsicIDAndArgs(NVVM::PrefetchOp &op,
5369 llvm::IRBuilderBase &builder) {
5370 using MemSpace = NVVM::NVVMMemorySpace;
5371 using CacheLevel = NVVM::PrefetchCacheLevel;
5373 std::optional<NVVM::PrefetchCacheLevel> cacheLevel = op.getCacheLevel();
5374 std::optional<NVVM::CacheEvictionPriority> evictPriority =
5375 op.getEvictPriority();
5376 unsigned addressSpace =
5377 llvm::cast<LLVM::LLVMPointerType>(op.getAddr().getType())
5385 if (op.getTensormap())
5386 return {llvm::Intrinsic::nvvm_prefetch_tensormap, args};
5388 assert(cacheLevel &&
"expected cache level for non-tensormap prefetch");
5390 if (op.getUniform() && *cacheLevel == CacheLevel::L1)
5391 return {llvm::Intrinsic::nvvm_prefetchu_L1, args};
5393 if (evictPriority && *cacheLevel == CacheLevel::L2) {
5394 switch (*evictPriority) {
5395 case NVVM::CacheEvictionPriority::EvictLast:
5396 return {llvm::Intrinsic::nvvm_prefetch_global_L2_evict_last, args};
5397 case NVVM::CacheEvictionPriority::EvictNormal:
5398 return {llvm::Intrinsic::nvvm_prefetch_global_L2_evict_normal, args};
5400 llvm_unreachable(
"Invalid cache eviction priority");
5404 switch (
static_cast<MemSpace
>(addressSpace)) {
5405 case MemSpace::Generic:
5406 return *cacheLevel == CacheLevel::L1
5408 :
NVVM::
IDArgPair({llvm::Intrinsic::nvvm_prefetch_L2, args});
5409 case MemSpace::Global:
5410 return *cacheLevel == CacheLevel::L1
5412 {llvm::Intrinsic::nvvm_prefetch_global_L1, args})
5414 {llvm::Intrinsic::nvvm_prefetch_global_L2, args});
5415 case MemSpace::Local:
5416 return *cacheLevel == CacheLevel::L1
5418 {llvm::Intrinsic::nvvm_prefetch_local_L1, args})
5420 {llvm::Intrinsic::nvvm_prefetch_local_L2, args});
5422 llvm_unreachable(
"Invalid pointer address space");
5426bool NVVM::InlinePtxOp::getAsmValues(
5430 for (
auto arg : getReadWriteArgs())
5432 for (
auto arg : getResults())
5434 for (
auto arg : getReadOnlyArgs())
5441NVVM::IDArgPair ClusterLaunchControlTryCancelOp::getIntrinsicIDAndArgs(
5443 auto curOp = cast<NVVM::ClusterLaunchControlTryCancelOp>(op);
5445 args.push_back(mt.
lookupValue(curOp.getSmemAddress()));
5446 args.push_back(mt.
lookupValue(curOp.getMbarrier()));
5448 llvm::Intrinsic::ID intrinsicID =
5449 curOp.getMulticast()
5451 nvvm_clusterlaunchcontrol_try_cancel_async_multicast_shared
5452 : llvm::Intrinsic::nvvm_clusterlaunchcontrol_try_cancel_async_shared;
5454 return {intrinsicID, args};
5457NVVM::IDArgPair ClusterLaunchControlQueryCancelOp::getIntrinsicIDAndArgs(
5459 auto curOp = cast<NVVM::ClusterLaunchControlQueryCancelOp>(op);
5461 args.push_back(mt.
lookupValue(curOp.getTryCancelResponse()));
5463 llvm::Intrinsic::ID intrinsicID;
5465 switch (curOp.getQueryType()) {
5466 case NVVM::ClusterLaunchControlQueryType::IS_CANCELED:
5468 llvm::Intrinsic::nvvm_clusterlaunchcontrol_query_cancel_is_canceled;
5470 case NVVM::ClusterLaunchControlQueryType::GET_FIRST_CTA_ID_X:
5471 intrinsicID = llvm::Intrinsic::
5472 nvvm_clusterlaunchcontrol_query_cancel_get_first_ctaid_x;
5474 case NVVM::ClusterLaunchControlQueryType::GET_FIRST_CTA_ID_Y:
5475 intrinsicID = llvm::Intrinsic::
5476 nvvm_clusterlaunchcontrol_query_cancel_get_first_ctaid_y;
5478 case NVVM::ClusterLaunchControlQueryType::GET_FIRST_CTA_ID_Z:
5479 intrinsicID = llvm::Intrinsic::
5480 nvvm_clusterlaunchcontrol_query_cancel_get_first_ctaid_z;
5483 return {intrinsicID, args};
5488 llvm::IRBuilderBase &builder) {
5489 auto thisOp = cast<NVVM::PermuteOp>(op);
5490 NVVM::PermuteMode mode = thisOp.getMode();
5492 static constexpr llvm::Intrinsic::ID IDs[] = {
5493 llvm::Intrinsic::nvvm_prmt, llvm::Intrinsic::nvvm_prmt_f4e,
5494 llvm::Intrinsic::nvvm_prmt_b4e, llvm::Intrinsic::nvvm_prmt_rc8,
5495 llvm::Intrinsic::nvvm_prmt_ecl, llvm::Intrinsic::nvvm_prmt_ecr,
5496 llvm::Intrinsic::nvvm_prmt_rc16};
5498 unsigned modeIndex =
static_cast<unsigned>(mode);
5506 args.push_back(mt.
lookupValue(thisOp.getSelector()));
5508 return {IDs[modeIndex], args};
5513 auto thisOp = cast<NVVM::TensormapReplaceOp>(op);
5517 if (thisOp.getOrd())
5518 args.push_back(builder.getInt32(thisOp.getOrd().value()));
5519 if (thisOp.getNewValue())
5520 args.push_back(mt.
lookupValue(thisOp.getNewValue()));
5521 if (
auto attr = thisOp.getNewValueAttr()) {
5524 .Case<TensormapElemtypeAttr, TensormapInterleaveLayoutAttr,
5525 TensormapSwizzleModeAttr, TensormapSwizzleAtomicityAttr,
5526 TensormapFillModeAttr>([](
auto attr) {
5527 return static_cast<unsigned>(attr.getValue());
5529 .Default([](
auto attr) {
5530 llvm_unreachable(
"Invalid attribute type");
5533 args.push_back(builder.getInt32(val));
5536 static constexpr llvm::Intrinsic::ID IDs[] = {
5537 llvm::Intrinsic::nvvm_tensormap_replace_global_address,
5538 llvm::Intrinsic::nvvm_tensormap_replace_rank,
5539 llvm::Intrinsic::nvvm_tensormap_replace_box_dim,
5540 llvm::Intrinsic::nvvm_tensormap_replace_global_dim,
5541 llvm::Intrinsic::nvvm_tensormap_replace_global_stride,
5542 llvm::Intrinsic::nvvm_tensormap_replace_element_stride,
5543 llvm::Intrinsic::nvvm_tensormap_replace_elemtype,
5544 llvm::Intrinsic::nvvm_tensormap_replace_interleave_layout,
5545 llvm::Intrinsic::nvvm_tensormap_replace_swizzle_mode,
5546 llvm::Intrinsic::nvvm_tensormap_replace_swizzle_atomicity,
5547 llvm::Intrinsic::nvvm_tensormap_replace_fill_mode,
5550 unsigned fieldIndex =
static_cast<unsigned>(thisOp.getField());
5552 return {IDs[fieldIndex], args};
5561 llvm::IRBuilderBase &builder) {
5563 auto thisOp = cast<NVVM::Tcgen05MMAOp>(op);
5566 args.push_back(mt.
lookupValue(thisOp.getMatrixD()));
5569 const bool isATensor = isa<llvm::PointerType>(
A->getType());
5572 args.push_back(mt.
lookupValue(thisOp.getMatrixB()));
5573 args.push_back(mt.
lookupValue(thisOp.getIdesc()));
5574 args.push_back(mt.
lookupValue(thisOp.getEnableInputD()));
5576 using EnableAShiftArray = std::array<llvm::Intrinsic::ID, 2>;
5577 using CtaGroupArray = std::array<EnableAShiftArray, 2>;
5578 using IsATensorArray = std::array<CtaGroupArray, 2>;
5579 using HasScaleInputDArray = std::array<IsATensorArray, 2>;
5580 using HasDisableOutputLaneArray = std::array<HasScaleInputDArray, 2>;
5583 static constexpr HasDisableOutputLaneArray tcgen05MMAIDs = {
5589 {llvm::Intrinsic::nvvm_tcgen05_mma_shared,
notIntrinsic},
5591 {llvm::Intrinsic::nvvm_tcgen05_mma_shared,
notIntrinsic}}},
5595 llvm::Intrinsic::nvvm_tcgen05_mma_tensor,
5596 llvm::Intrinsic::nvvm_tcgen05_mma_tensor_ashift,
5600 llvm::Intrinsic::nvvm_tcgen05_mma_tensor,
5601 llvm::Intrinsic::nvvm_tcgen05_mma_tensor_ashift,
5607 {llvm::Intrinsic::nvvm_tcgen05_mma_shared_scale_d,
notIntrinsic},
5609 {llvm::Intrinsic::nvvm_tcgen05_mma_shared_scale_d,
notIntrinsic}}},
5613 llvm::Intrinsic::nvvm_tcgen05_mma_tensor_scale_d,
5614 llvm::Intrinsic::nvvm_tcgen05_mma_tensor_scale_d_ashift,
5618 llvm::Intrinsic::nvvm_tcgen05_mma_tensor_scale_d,
5619 llvm::Intrinsic::nvvm_tcgen05_mma_tensor_scale_d_ashift,
5625 {llvm::Intrinsic::nvvm_tcgen05_mma_shared_disable_output_lane_cg1,
5628 {llvm::Intrinsic::nvvm_tcgen05_mma_shared_disable_output_lane_cg2,
5633 nvvm_tcgen05_mma_tensor_disable_output_lane_cg1,
5635 nvvm_tcgen05_mma_tensor_disable_output_lane_cg1_ashift,
5640 nvvm_tcgen05_mma_tensor_disable_output_lane_cg2,
5642 nvvm_tcgen05_mma_tensor_disable_output_lane_cg2_ashift,
5648 nvvm_tcgen05_mma_shared_scale_d_disable_output_lane_cg1,
5652 nvvm_tcgen05_mma_shared_scale_d_disable_output_lane_cg2,
5657 nvvm_tcgen05_mma_tensor_scale_d_disable_output_lane_cg1,
5659 nvvm_tcgen05_mma_tensor_scale_d_disable_output_lane_cg1_ashift},
5663 nvvm_tcgen05_mma_tensor_scale_d_disable_output_lane_cg2,
5665 nvvm_tcgen05_mma_tensor_scale_d_disable_output_lane_cg2_ashift,
5668 llvm::Value *ScaleInputD = mt.
lookupValue(thisOp.getScaleInputD());
5669 bool hasScaleInputD = ScaleInputD !=
nullptr;
5671 llvm::Value *DisableOutputLane =
5673 bool hasDisableOutputLane = DisableOutputLane !=
nullptr;
5675 const unsigned ctaGroup =
5678 llvm::Intrinsic::ID ID =
5679 tcgen05MMAIDs[hasDisableOutputLane][hasScaleInputD][isATensor]
5680 [ctaGroup - 1][thisOp.getAShift()];
5682 assert(ID !=
notIntrinsic &&
"Invalid intrinsic for Tcgen05MMAOp.");
5685 args.push_back(ScaleInputD);
5687 if (hasDisableOutputLane)
5688 args.push_back(DisableOutputLane);
5690 args.push_back(builder.getInt32(
static_cast<unsigned>(thisOp.getKind())));
5692 if (!hasDisableOutputLane)
5693 args.push_back(builder.getInt32(ctaGroup));
5696 builder.getInt32(
static_cast<unsigned>(thisOp.getCollectorOp())));
5703 NVVM::CTAGroupKind ctaGroup,
bool hasAShift,
5704 NVVM::Tcgen05MMACollectorOp collectorOp,
Location loc) {
5706 if (disableOutputLane) {
5707 mlir::VectorType disableOutputLaneType =
5708 cast<mlir::VectorType>(disableOutputLane.
getType());
5709 if ((ctaGroup == NVVM::CTAGroupKind::CTA_1 &&
5710 disableOutputLaneType.getNumElements() != 4) ||
5711 (ctaGroup == NVVM::CTAGroupKind::CTA_2 &&
5712 disableOutputLaneType.getNumElements() != 8))
5713 return emitError(loc) <<
"Disable Output Lane of length "
5714 << disableOutputLaneType.getNumElements()
5715 <<
" is incompatible with CtaGroupAttr";
5718 if (hasAShift && !isATensor)
5720 loc,
"A-shift can be applied only when matrix A is in tensor memory");
5722 if (hasAShift ==
true && (collectorOp == Tcgen05MMACollectorOp::FILL ||
5723 collectorOp == Tcgen05MMACollectorOp::USE))
5725 loc,
"Cannot use collector buffer operation fill or use with ashift");
5730LogicalResult Tcgen05MMAOp::verify() {
5732 getDisableOutputLane(), getCtaGroup(), getAShift(),
5733 getCollectorOp(), getLoc());
5743 auto thisOp = cast<NVVM::Tcgen05MMASparseOp>(op);
5746 args.push_back(mt.
lookupValue(thisOp.getMatrixD()));
5749 bool isATensor = isa<llvm::PointerType>(
A->getType());
5752 args.push_back(mt.
lookupValue(thisOp.getMatrixB()));
5753 args.push_back(mt.
lookupValue(thisOp.getIdesc()));
5754 args.push_back(mt.
lookupValue(thisOp.getEnableInputD()));
5755 args.push_back(mt.
lookupValue(thisOp.getSparseMetadata()));
5757 using EnableAShiftArray = std::array<llvm::Intrinsic::ID, 2>;
5758 using CtaGroupArray = std::array<EnableAShiftArray, 2>;
5759 using IsATensorArray = std::array<CtaGroupArray, 2>;
5760 using HasScaleInputDArray = std::array<IsATensorArray, 2>;
5761 using HasDisableOutputLaneArray = std::array<HasScaleInputDArray, 2>;
5764 static constexpr HasDisableOutputLaneArray tcgen05MMASparseIDs = {
5770 {llvm::Intrinsic::nvvm_tcgen05_mma_sp_shared,
notIntrinsic},
5772 {llvm::Intrinsic::nvvm_tcgen05_mma_sp_shared,
notIntrinsic}}},
5776 llvm::Intrinsic::nvvm_tcgen05_mma_sp_tensor,
5777 llvm::Intrinsic::nvvm_tcgen05_mma_sp_tensor_ashift,
5781 llvm::Intrinsic::nvvm_tcgen05_mma_sp_tensor,
5782 llvm::Intrinsic::nvvm_tcgen05_mma_sp_tensor_ashift,
5788 {llvm::Intrinsic::nvvm_tcgen05_mma_sp_shared_scale_d,
5791 {llvm::Intrinsic::nvvm_tcgen05_mma_sp_shared_scale_d,
5796 llvm::Intrinsic::nvvm_tcgen05_mma_sp_tensor_scale_d,
5797 llvm::Intrinsic::nvvm_tcgen05_mma_sp_tensor_scale_d_ashift,
5801 llvm::Intrinsic::nvvm_tcgen05_mma_sp_tensor_scale_d,
5802 llvm::Intrinsic::nvvm_tcgen05_mma_sp_tensor_scale_d_ashift,
5809 nvvm_tcgen05_mma_sp_shared_disable_output_lane_cg1,
5813 nvvm_tcgen05_mma_sp_shared_disable_output_lane_cg2,
5818 nvvm_tcgen05_mma_sp_tensor_disable_output_lane_cg1,
5820 nvvm_tcgen05_mma_sp_tensor_disable_output_lane_cg1_ashift,
5825 nvvm_tcgen05_mma_sp_tensor_disable_output_lane_cg2,
5827 nvvm_tcgen05_mma_sp_tensor_disable_output_lane_cg2_ashift,
5833 nvvm_tcgen05_mma_sp_shared_scale_d_disable_output_lane_cg1,
5837 nvvm_tcgen05_mma_sp_shared_scale_d_disable_output_lane_cg2,
5842 nvvm_tcgen05_mma_sp_tensor_scale_d_disable_output_lane_cg1,
5844 nvvm_tcgen05_mma_sp_tensor_scale_d_disable_output_lane_cg1_ashift},
5848 nvvm_tcgen05_mma_sp_tensor_scale_d_disable_output_lane_cg2,
5850 nvvm_tcgen05_mma_sp_tensor_scale_d_disable_output_lane_cg2_ashift,
5853 llvm::Value *ScaleInputD = mt.
lookupValue(thisOp.getScaleInputD());
5854 bool hasScaleInputD = ScaleInputD !=
nullptr;
5856 llvm::Value *DisableOutputLane =
5858 bool hasDisableOutputLane = DisableOutputLane !=
nullptr;
5863 llvm::Intrinsic::ID ID =
5864 tcgen05MMASparseIDs[hasDisableOutputLane][hasScaleInputD][isATensor]
5865 [ctaGroup - 1][thisOp.getAShift()];
5867 assert(ID !=
notIntrinsic &&
"Invalid intrinsic for Tcgen05MMASparseOp.");
5870 args.push_back(ScaleInputD);
5872 if (hasDisableOutputLane)
5873 args.push_back(DisableOutputLane);
5875 args.push_back(builder.getInt32(
static_cast<unsigned>(thisOp.getKind())));
5877 if (!hasDisableOutputLane)
5878 args.push_back(builder.getInt32(ctaGroup));
5881 builder.getInt32(
static_cast<unsigned>(thisOp.getCollectorOp())));
5886LogicalResult Tcgen05MMASparseOp::verify() {
5888 getDisableOutputLane(), getCtaGroup(), getAShift(),
5889 getCollectorOp(), getLoc());
5899 auto thisOp = cast<NVVM::Tcgen05MMABlockScaleOp>(op);
5902 args.push_back(mt.
lookupValue(thisOp.getMatrixD()));
5905 bool isATensor = isa<llvm::PointerType>(
A->getType());
5908 args.push_back(mt.
lookupValue(thisOp.getMatrixB()));
5909 args.push_back(mt.
lookupValue(thisOp.getIdesc()));
5910 args.push_back(mt.
lookupValue(thisOp.getEnableInputD()));
5911 args.push_back(mt.
lookupValue(thisOp.getScaleA()));
5912 args.push_back(mt.
lookupValue(thisOp.getScaleB()));
5913 args.push_back(builder.getInt32(
5916 builder.getInt32(
static_cast<unsigned>(thisOp.getCollectorOp())));
5918 auto kind = thisOp.getKind();
5919 auto blockScale = thisOp.getBlockScale();
5920 llvm::Intrinsic::ID ID = [&]() {
5921 if (kind == NVVM::Tcgen05MMAKind::MXF8F6F4) {
5922 if (blockScale == NVVM::Tcgen05MMABlockScale::DEFAULT) {
5923 return isATensor ? llvm::Intrinsic::
5924 nvvm_tcgen05_mma_tensor_mxf8f6f4_block_scale
5926 nvvm_tcgen05_mma_shared_mxf8f6f4_block_scale;
5927 }
else if (blockScale == NVVM::Tcgen05MMABlockScale::BLOCK32) {
5930 nvvm_tcgen05_mma_tensor_mxf8f6f4_block_scale_block32
5932 nvvm_tcgen05_mma_shared_mxf8f6f4_block_scale_block32;
5934 }
else if (kind == NVVM::Tcgen05MMAKind::MXF4) {
5935 if (blockScale == NVVM::Tcgen05MMABlockScale::DEFAULT) {
5937 ? llvm::Intrinsic::nvvm_tcgen05_mma_tensor_mxf4_block_scale
5938 : llvm::Intrinsic::nvvm_tcgen05_mma_shared_mxf4_block_scale;
5939 }
else if (blockScale == NVVM::Tcgen05MMABlockScale::BLOCK32) {
5940 return isATensor ? llvm::Intrinsic::
5941 nvvm_tcgen05_mma_tensor_mxf4_block_scale_block32
5943 nvvm_tcgen05_mma_shared_mxf4_block_scale_block32;
5945 }
else if (kind == NVVM::Tcgen05MMAKind::MXF4NVF4) {
5946 if (blockScale == NVVM::Tcgen05MMABlockScale::BLOCK32) {
5949 nvvm_tcgen05_mma_tensor_mxf4nvf4_block_scale_block32
5951 nvvm_tcgen05_mma_shared_mxf4nvf4_block_scale_block32;
5953 }
else if (blockScale == NVVM::Tcgen05MMABlockScale::BLOCK16) {
5956 nvvm_tcgen05_mma_tensor_mxf4nvf4_block_scale_block16
5958 nvvm_tcgen05_mma_shared_mxf4nvf4_block_scale_block16;
5961 llvm_unreachable(
"Invalid tcgen05.mma.block_scale attributes");
5968 NVVM::Tcgen05MMACollectorOp collectorOp, NVVM::Tcgen05MMAKind kind,
5969 NVVM::Tcgen05MMABlockScale blockScale,
Location loc) {
5970 if (blockScale == NVVM::Tcgen05MMABlockScale::DEFAULT &&
5971 kind == NVVM::Tcgen05MMAKind::MXF4NVF4)
5972 return emitError(loc,
"mxf4nvf4 requires block scale attribute");
5974 if (blockScale == NVVM::Tcgen05MMABlockScale::BLOCK16 &&
5975 kind != NVVM::Tcgen05MMAKind::MXF4NVF4)
5977 llvm::formatv(
"{} kind does not support block16 attribute",
5978 stringifyEnum(kind)));
5983LogicalResult Tcgen05MMABlockScaleOp::verify() {
5985 getBlockScale(), getLoc());
5995 auto thisOp = cast<NVVM::Tcgen05MMASparseBlockScaleOp>(op);
5998 args.push_back(mt.
lookupValue(thisOp.getMatrixD()));
6001 bool isATensor = isa<llvm::PointerType>(
A->getType());
6004 args.push_back(mt.
lookupValue(thisOp.getMatrixB()));
6005 args.push_back(mt.
lookupValue(thisOp.getIdesc()));
6006 args.push_back(mt.
lookupValue(thisOp.getEnableInputD()));
6007 args.push_back(mt.
lookupValue(thisOp.getSparseMetadata()));
6008 args.push_back(mt.
lookupValue(thisOp.getScaleA()));
6009 args.push_back(mt.
lookupValue(thisOp.getScaleB()));
6010 args.push_back(builder.getInt32(
6013 builder.getInt32(
static_cast<unsigned>(thisOp.getCollectorOp())));
6015 auto kind = thisOp.getKind();
6016 auto blockScale = thisOp.getBlockScale();
6017 llvm::Intrinsic::ID ID = [&]() {
6018 if (kind == NVVM::Tcgen05MMAKind::MXF8F6F4) {
6019 if (blockScale == NVVM::Tcgen05MMABlockScale::DEFAULT) {
6020 return isATensor ? llvm::Intrinsic::
6021 nvvm_tcgen05_mma_sp_tensor_mxf8f6f4_block_scale
6023 nvvm_tcgen05_mma_sp_shared_mxf8f6f4_block_scale;
6024 }
else if (blockScale == NVVM::Tcgen05MMABlockScale::BLOCK32) {
6027 nvvm_tcgen05_mma_sp_tensor_mxf8f6f4_block_scale_block32
6029 nvvm_tcgen05_mma_sp_shared_mxf8f6f4_block_scale_block32;
6031 }
else if (kind == NVVM::Tcgen05MMAKind::MXF4) {
6032 if (blockScale == NVVM::Tcgen05MMABlockScale::DEFAULT) {
6033 return isATensor ? llvm::Intrinsic::
6034 nvvm_tcgen05_mma_sp_tensor_mxf4_block_scale
6036 nvvm_tcgen05_mma_sp_shared_mxf4_block_scale;
6037 }
else if (blockScale == NVVM::Tcgen05MMABlockScale::BLOCK32) {
6040 nvvm_tcgen05_mma_sp_tensor_mxf4_block_scale_block32
6042 nvvm_tcgen05_mma_sp_shared_mxf4_block_scale_block32;
6044 }
else if (kind == NVVM::Tcgen05MMAKind::MXF4NVF4) {
6045 if (blockScale == NVVM::Tcgen05MMABlockScale::BLOCK32) {
6048 nvvm_tcgen05_mma_sp_tensor_mxf4nvf4_block_scale_block32
6050 nvvm_tcgen05_mma_sp_shared_mxf4nvf4_block_scale_block32;
6052 }
else if (blockScale == NVVM::Tcgen05MMABlockScale::BLOCK16) {
6055 nvvm_tcgen05_mma_sp_tensor_mxf4nvf4_block_scale_block16
6057 nvvm_tcgen05_mma_sp_shared_mxf4nvf4_block_scale_block16;
6060 llvm_unreachable(
"Invalid tcgen05.mma.sp.block_scale attributes");
6066LogicalResult Tcgen05MMASparseBlockScaleOp::verify() {
6068 getBlockScale(), getLoc());
6078 auto thisOp = cast<NVVM::Tcgen05MMAWsOp>(op);
6081 args.push_back(mt.
lookupValue(thisOp.getMatrixD()));
6084 bool isATensor = isa<llvm::PointerType>(
A->getType());
6087 args.push_back(mt.
lookupValue(thisOp.getMatrixB()));
6088 args.push_back(mt.
lookupValue(thisOp.getIdesc()));
6089 args.push_back(mt.
lookupValue(thisOp.getEnableInputD()));
6091 mlir::Value ZeroColMask = thisOp.getZeroColMask();
6095 ID = isATensor ? llvm::Intrinsic::nvvm_tcgen05_mma_ws_tensor_zero_col_mask
6096 : llvm::Intrinsic::nvvm_tcgen05_mma_ws_shared_zero_col_mask;
6098 ID = isATensor ? llvm::Intrinsic::nvvm_tcgen05_mma_ws_tensor
6099 : llvm::Intrinsic::nvvm_tcgen05_mma_ws_shared;
6101 args.push_back(builder.getInt32(
static_cast<unsigned>(thisOp.getKind())));
6103 builder.getInt32(
static_cast<unsigned>(thisOp.getCollectorBBuffer())));
6105 builder.getInt32(
static_cast<unsigned>(thisOp.getCollectorOp())));
6117 auto thisOp = cast<NVVM::Tcgen05MMAWsSparseOp>(op);
6120 args.push_back(mt.
lookupValue(thisOp.getMatrixD()));
6123 bool isATensor = isa<llvm::PointerType>(
A->getType());
6126 args.push_back(mt.
lookupValue(thisOp.getMatrixB()));
6127 args.push_back(mt.
lookupValue(thisOp.getIdesc()));
6128 args.push_back(mt.
lookupValue(thisOp.getEnableInputD()));
6129 args.push_back(mt.
lookupValue(thisOp.getSparseMetadata()));
6131 mlir::Value ZeroColMask = thisOp.getZeroColMask();
6136 ? llvm::Intrinsic::nvvm_tcgen05_mma_ws_sp_tensor_zero_col_mask
6137 : llvm::Intrinsic::nvvm_tcgen05_mma_ws_sp_shared_zero_col_mask;
6139 ID = isATensor ? llvm::Intrinsic::nvvm_tcgen05_mma_ws_sp_tensor
6140 : llvm::Intrinsic::nvvm_tcgen05_mma_ws_sp_shared;
6142 args.push_back(builder.getInt32(
static_cast<unsigned>(thisOp.getKind())));
6144 builder.getInt32(
static_cast<unsigned>(thisOp.getCollectorBBuffer())));
6146 builder.getInt32(
static_cast<unsigned>(thisOp.getCollectorOp())));
6155#define TCGEN05LDRED(SHAPE, NUM, TYPE) \
6156 llvm::Intrinsic::nvvm_tcgen05_ld_red_##SHAPE##_##NUM##_##TYPE
6160 auto thisOp = cast<NVVM::Tcgen05LdRedOp>(op);
6163 mlir::VectorType VecResTy =
6164 cast<mlir::VectorType>(thisOp.getData().getType());
6165 unsigned Num = VecResTy.getNumElements();
6166 bool IsFloat = thisOp.getRedVal().getType().isF32();
6168 llvm::Intrinsic::ID Shape32x32b[][2] = {
6179 llvm::Intrinsic::ID Shape16x32bx2[][2] = {
6190 NVVM::Tcgen05LdStShape
shape = thisOp.getShape();
6191 unsigned ID = [&]() {
6194 unsigned idx = std::log2(Num);
6196 case NVVM::Tcgen05LdStShape::SHAPE_32X32B:
6197 return Shape32x32b[idx][IsFloat];
6198 case NVVM::Tcgen05LdStShape::SHAPE_16X32BX2:
6199 return Shape16x32bx2[idx][IsFloat];
6201 llvm_unreachable(
"unhandled tcgen05.ld lowering");
6207 if (
shape == NVVM::Tcgen05LdStShape::SHAPE_16X32BX2)
6208 args.push_back(mt.
lookupValue(thisOp.getOffset()));
6211 builder.getInt32(thisOp.getOp() == NVVM::ReductionKind::MIN ? 0 : 1));
6214 args.push_back(builder.getInt1(
static_cast<unsigned>(thisOp.getAbs())));
6215 args.push_back(builder.getInt1(
static_cast<unsigned>(thisOp.getNan())));
6220LogicalResult Tcgen05LdRedOp::verify() {
6221 VectorType data = cast<VectorType>(getData().
getType());
6222 Type redVal = getRedVal().getType();
6224 if (data.getElementType() != redVal)
6226 "type of reduction value and element type of vector data should match");
6228 if (getOp() != NVVM::ReductionKind::MIN &&
6229 getOp() != NVVM::ReductionKind::MAX)
6230 return emitError(
"only min and max reduction kinds are supported");
6232 if (redVal.
isInteger() && (getAbs() || getNan())) {
6233 return emitError(
"abs or nan is only applicable for f32 type");
6243struct NVVMInlinerInterface final : DialectInlinerInterface {
6244 using DialectInlinerInterface::DialectInlinerInterface;
6245 bool isLegalToInline(Operation *, Region *,
bool, IRMapping &)
const final {
6252void NVVMDialect::initialize() {
6255#include "mlir/Dialect/LLVMIR/NVVMOps.cpp.inc"
6258#define GET_ATTRDEF_LIST
6259#include "mlir/Dialect/LLVMIR/NVVMOpsAttributes.cpp.inc"
6264 allowUnknownOperations();
6265 addInterfaces<NVVMInlinerInterface>();
6266 declarePromisedInterface<ConvertToLLVMPatternInterface, NVVMDialect>();
6267 declarePromisedInterface<gpu::TargetAttrInterface, NVVMTargetAttr>();
6270LogicalResult NVVMDialect::verifyOperationAttribute(
Operation *op,
6272 StringAttr attrName = attr.
getName();
6274 if (attrName == NVVMDialect::getKernelFuncAttrName()) {
6275 if (!isa<LLVM::LLVMFuncOp>(op)) {
6276 return op->
emitError() <<
"'" << NVVMDialect::getKernelFuncAttrName()
6277 <<
"' attribute attached to unexpected op";
6282 if (attrName == NVVMDialect::getMaxntidAttrName() ||
6283 attrName == NVVMDialect::getReqntidAttrName() ||
6284 attrName == NVVMDialect::getClusterDimAttrName()) {
6285 auto values = llvm::dyn_cast<DenseI32ArrayAttr>(attr.
getValue());
6286 if (!values || values.empty() || values.size() > 3) {
6289 <<
"' attribute must be integer array with maximum 3 index";
6294 if (attrName == NVVMDialect::getMinctasmAttrName() ||
6295 attrName == NVVMDialect::getMaxnregAttrName() ||
6296 attrName == NVVMDialect::getClusterMaxBlocksAttrName()) {
6297 if (!llvm::dyn_cast<IntegerAttr>(attr.
getValue())) {
6299 <<
"'" << attrName <<
"' attribute must be integer constant";
6303 if (attrName == NVVMDialect::getBlocksAreClustersAttrName()) {
6304 if (!op->
hasAttr(NVVMDialect::getReqntidAttrName()) ||
6305 !op->
hasAttr(NVVMDialect::getClusterDimAttrName())) {
6307 <<
"'" << attrName <<
"' attribute must be used along with " <<
"'"
6308 << NVVMDialect::getReqntidAttrName() <<
"' and " <<
"'"
6309 << NVVMDialect::getClusterDimAttrName() <<
"'";
6316LogicalResult NVVMDialect::verifyRegionArgAttribute(
Operation *op,
6317 unsigned regionIndex,
6320 auto funcOp = dyn_cast<FunctionOpInterface>(op);
6324 bool isKernel = op->
hasAttr(NVVMDialect::getKernelFuncAttrName());
6325 StringAttr attrName = argAttr.
getName();
6326 if (attrName == NVVM::NVVMDialect::getGridConstantAttrName()) {
6330 <<
"' attribute must be present only on kernel arguments";
6332 if (!isa<UnitAttr>(argAttr.
getValue()))
6333 return op->
emitError() <<
"'" << attrName <<
"' must be a unit attribute";
6334 if (!funcOp.getArgAttr(argIndex, LLVM::LLVMDialect::getByValAttrName())) {
6337 <<
"' attribute requires the argument to also have attribute '"
6338 << LLVM::LLVMDialect::getByValAttrName() <<
"'";
6349unsigned NVVMMemorySpaceAttr::getAddressSpace()
const {
6350 return static_cast<unsigned>(getValue());
6353bool NVVMMemorySpaceAttr::isValidLoad(
6354 Type type, ptr::AtomicOrdering ordering, std::optional<int64_t> alignment,
6355 const ::mlir::DataLayout *dataLayout,
6361bool NVVMMemorySpaceAttr::isValidStore(
6362 Type type, ptr::AtomicOrdering ordering, std::optional<int64_t> alignment,
6363 const ::mlir::DataLayout *dataLayout,
6369bool NVVMMemorySpaceAttr::isValidAtomicOp(
6370 ptr::AtomicBinOp op,
Type type, ptr::AtomicOrdering ordering,
6371 std::optional<int64_t> alignment, const ::mlir::DataLayout *dataLayout,
6374 assert(
false &&
"unimplemented, see TODO in the source.");
6378bool NVVMMemorySpaceAttr::isValidAtomicXchg(
6379 Type type, ptr::AtomicOrdering successOrdering,
6380 ptr::AtomicOrdering failureOrdering, std::optional<int64_t> alignment,
6381 const ::mlir::DataLayout *dataLayout,
6384 assert(
false &&
"unimplemented, see TODO in the source.");
6388bool NVVMMemorySpaceAttr::isValidAddrSpaceCast(
6392 assert(
false &&
"unimplemented, see TODO in the source.");
6396bool NVVMMemorySpaceAttr::isValidPtrIntCast(
6401 assert(
false &&
"unimplemented, see TODO in the source.");
6410 int optLevel, StringRef triple, StringRef chip,
6411 StringRef features, DictionaryAttr flags,
6413 if (optLevel < 0 || optLevel > 3) {
6414 emitError() <<
"The optimization level must be a number between 0 and 3.";
6417 if (triple.empty()) {
6418 emitError() <<
"The target triple cannot be empty.";
6422 emitError() <<
"The target chip cannot be empty.";
6425 if (files && !llvm::all_of(files, [](::mlir::Attribute attr) {
6426 return mlir::isa_and_nonnull<StringAttr>(attr);
6428 emitError() <<
"All the elements in the `link` array must be strings.";
6434LogicalResult NVVMTargetAttr::verifyTarget(
Operation *gpuModule) {
6435 if (!getVerifyTarget())
6438 auto gpuModuleOp = llvm::dyn_cast<gpu::GPUModuleOp>(gpuModule);
6441 "NVVM target attribute must be attached to a GPU module");
6444 const unsigned targetFullSmVersion =
6448 "Minimum NVVM target SM version is sm_20");
6452 ->
walk([&](Operation *op) {
6453 if (
auto reqOp = llvm::dyn_cast<NVVM::RequiresSMInterface>(op)) {
6454 const NVVMCheckSMVersion requirement =
6455 reqOp.getRequiredMinSMVersion();
6457 op->
emitOpError() <<
"is not supported on " << getChip();
6469#define GET_OP_CLASSES
6470#include "mlir/Dialect/LLVMIR/NVVMOps.cpp.inc"
6472#define GET_ATTRDEF_CLASSES
6473#include "mlir/Dialect/LLVMIR/NVVMOpsAttributes.cpp.inc"
p<< " : "<< getMemRefType()<< ", "<< getType();}static LogicalResult verifyVectorMemoryOp(Operation *op, MemRefType memrefType, VectorType vectorType) { if(memrefType.getElementType() !=vectorType.getElementType()) return op-> emitOpError("requires memref and vector types of the same elemental type")
Given a list of lists of parsed operands, populates uniqueOperands with unique operands.
static bool isLegalToInline(InlinerInterface &interface, Region *src, Region *insertRegion, bool shouldCloneInlinedRegion, IRMapping &valueMapping)
Utility to check that all of the operations within 'src' can be inlined.
#define GET_TCGEN05_CP_ID(shape_mc, src_fmt, is_2cta)
static LogicalResult verifyTMALoadParams(size_t tensorDims, size_t numIm2colOff, TMALoadMode mode, Location loc)
static LogicalResult verifyTcgen05MMAOp(bool isATensor, mlir::Value disableOutputLane, NVVM::CTAGroupKind ctaGroup, bool hasAShift, NVVM::Tcgen05MMACollectorOp collectorOp, Location loc)
static bool isPtrInAddrSpace(mlir::Value ptr, NVVMMemorySpace targetAS)
static bool isCompatibleReturnTypesOptionalResult(TypeRange inferred, TypeRange actual)
For ops with optional results, allow the user to omit the result even when inference would produce on...
static bool isPtrInSharedCTASpace(mlir::Value ptr)
static LogicalResult isAllowedSizeN(int sizeN, NVVM::WGMMATypes typeA)
static llvm::nvvm::CTAGroupKind getNVVMCtaGroupKind(NVVM::CTAGroupKind ctaGroup)
static void addInferredMultiplicandTypes(MLIRContext *ctx, OperationState &result, ValueRange operandA, ValueRange operandB, std::optional< std::array< MMATypes, 2 > > multiplicandPtxTypes)
#define GET_CVT_F2TF32_ID(rnd, relu, sf)
static void addBlockScaleProperties(OpBuilder &builder, OperationState &result, ArrayRef< int64_t > shape, ScaleVecSize scaleVecSize, BlockScaleFormat blockScaleFormat, MMABlockScaleKind kind)
#define GET_F32x2_TO_F8X2_US_ID(rnd, has_satf)
static llvm::Value * getParamCastedAddr(llvm::Value *addr, llvm::IRBuilderBase &builder)
static LogicalResult verifyAddSubFOp(OpType op)
static LogicalResult verifyTcgen05MMABlockScaleOp(NVVM::Tcgen05MMACollectorOp collectorOp, NVVM::Tcgen05MMAKind kind, NVVM::Tcgen05MMABlockScale blockScale, Location loc)
static llvm::Value * packValInto64Bits(llvm::IRBuilderBase &builder, llvm::Value *result, llvm::Value *field, unsigned sizeInBits, unsigned start)
Packs the given field into the result.
static void printOperandList(OpAsmPrinter &p, StringRef name, ArrayRef< Value > operands)
#define GET_F32x2_TO_F6x2_ID(type, has_relu)
static llvm::Value * getAsPackedI32(llvm::Value *arg, llvm::IRBuilderBase &builder)
#define GET_F16x2_TO_F8X2_ID(type, has_relu)
static LogicalResult verifyMBarrierArriveLikeOp(Operation *op, Value addr, NVVM::MemScopeKind scope, Value retVal=nullptr)
static llvm::Value * castPtrToAddrSpace(llvm::IRBuilderBase &builder, llvm::Value *ptr, NVVMMemorySpace targetAS)
static LogicalResult isAllowedWGMMADataType(NVVM::WGMMATypes typeD, NVVM::WGMMATypes typeA, NVVM::WGMMATypes typeB)
static llvm::Intrinsic::ID getBarrierReductionIntrinsic(bool aligned, NVVM::BarrierReduction kind)
Maps the (aligned, kind) pair to the @llvm.nvvm.barrier.cta.red.
static void inferAndSetMultiplicandTypes(MLIRContext *ctx, NamedAttrList &attrs, const SmallVectorImpl< Type > &operandTypes)
static LogicalResult parseMmaOperand(OpAsmParser &parser, StringRef operandName, SmallVectorImpl< OpAsmParser::UnresolvedOperand > ®s)
static std::pair< mlir::Type, unsigned > inferMMATypeFromMNK(NVVM::MMATypes type, NVVM::MMAFrag frag, int m, int n, int k, MLIRContext *context)
static bool isInt8PtxType(MMATypes type)
#define TCGEN05LDRED(SHAPE, NUM, TYPE)
static bool isInt4PtxType(MMATypes type)
static bool isIntegerPtxType(MMATypes type)
#define GET_F32x2_TO_F8X2_S_ID(type, has_relu)
static MMATypes inferPtxTypeFromResult(OpTy op)
static LogicalResult verifyConstantRangeAttr(Operation *op, std::optional< LLVM::ConstantRangeAttr > rangeAttr)
Verify the range attribute satisfies LLVM ConstantRange constructor requirements for NVVM SpecialRang...
static LogicalResult parseMmaTypeSignature(OpAsmParser &parser, SmallVectorImpl< Type > &operandTypes)
static FailureOr< int > getAllowedSizeK(NVVM::WGMMATypes typeA)
static bool isPtrInSharedClusterSpace(mlir::Value ptr)
#define GET_CP_ASYNC_ID(mod, size, has_cpsize)
static unsigned isValidVectorLength(NVVM::Tcgen05LdStShape shape, unsigned vecLen)
#define GET_TCGEN05_COMMIT_ID(cta_group, is_shared, has_mc)
static LogicalResult verifyConvertF32x2ToFP16x2Op(Twine dstType, FPRoundingMode rnd, bool hasRandomBits, Operation *op)
static void nvvmInferResultRanges(Operation *op, Value result, ArrayRef<::mlir::ConstantIntRanges > argRanges, SetIntRangeFn setResultRanges)
Infer the result ranges for the NVVM SpecialRangeableRegisterOp that might have ConstantRangeAttr.
static LogicalResult cpAsyncBulkTensorCommonVerifier(size_t tensorDims, bool isIm2Col, size_t numIm2ColOffsets, Location loc)
static bool isPtrInGenericSpace(mlir::Value ptr)
static void processOperandFragments(Op &op, std::array< MMAOperandFragment, 3 > &frags, SmallVectorImpl< Type > ®Types, SmallVectorImpl< StringRef > &ignoreAttrNames)
static llvm::Intrinsic::ID getBarrierSyncIntrinsic(bool aligned, bool hasCount)
Maps the (aligned, hasCount) pair to the @llvm.nvvm.barrier.cta.sync.
static constexpr unsigned notIntrinsic
static LogicalResult inferMBarrierArriveResultTypes(MLIRContext *context, Value addr, SmallVectorImpl< Type > &inferredReturnTypes)
Only shared_cluster (ptr<7>) produces zero results; all other address spaces (including generic) retu...
static ArrayRef< int64_t > getShape(Type type)
Returns the shape of the given type.
@ OptionalSquare
Square brackets supporting zero or more ops, or nothing.
virtual Builder & getBuilder() const =0
Return a builder which provides useful access to MLIRContext, global objects like types and attribute...
virtual ParseResult parseCommaSeparatedList(Delimiter delimiter, function_ref< ParseResult()> parseElementFn, StringRef contextMessage=StringRef())=0
Parse a list of comma-separated items with an optional delimiter.
virtual ParseResult parseOptionalAttrDict(NamedAttrList &result)=0
Parse a named dictionary into 'result' if it is present.
MLIRContext * getContext() const
virtual ParseResult parseRParen()=0
Parse a ) token.
virtual InFlightDiagnostic emitError(SMLoc loc, const Twine &message={})=0
Emit a diagnostic at the specified location and return failure.
virtual SMLoc getCurrentLocation()=0
Get the location of the next token and store it into the argument.
virtual ParseResult parseColon()=0
Parse a : token.
virtual SMLoc getNameLoc() const =0
Return the location of the original name token.
virtual ParseResult parseArrow()=0
Parse a '->' token.
virtual ParseResult parseLParen()=0
Parse a ( token.
virtual ParseResult parseType(Type &result)=0
Parse a type.
virtual ParseResult parseArrowTypeList(SmallVectorImpl< Type > &result)=0
Parse an arrow followed by a type list.
ParseResult parseTypeList(SmallVectorImpl< Type > &result)
Parse a type list.
ParseResult parseKeyword(StringRef keyword)
Parse a given keyword.
void printArrowTypeList(TypeRange &&types)
This class is a general helper class for creating context-global objects like types,...
DenseI32ArrayAttr getDenseI32ArrayAttr(ArrayRef< int32_t > values)
IntegerType getIntegerType(unsigned width)
MLIRContext * getContext() const
Attr getAttr(Args &&...args)
Get or construct an instance of the attribute Attr with provided arguments.
This class represents a diagnostic that is inflight and set to be reported.
static IntegerValueRange getMaxRange(Value value)
Create a maximal range ([0, uint_max(t)] / [int_min(t), int_max(t)]) range that is used to mark the v...
Implementation class for module translation.
llvm::Value * lookupValue(Value value) const
Finds an LLVM IR value corresponding to the given MLIR value.
void mapValue(Value mlir, llvm::Value *llvm)
Stores the mapping between an MLIR value and its LLVM IR counterpart.
llvm::LLVMContext & getLLVMContext() const
Returns the LLVM context in which the IR is being constructed.
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.
NamedAttrList is array of NamedAttributes that tracks whether it is sorted and does some basic work t...
std::optional< NamedAttribute > getNamed(StringRef name) const
Return the specified named attribute if present, std::nullopt otherwise.
Attribute get(StringAttr name) const
Return the specified attribute if present, null otherwise.
Attribute set(StringAttr name, Attribute value)
If the an attribute exists with the specified name, change it to the new value.
NamedAttribute represents a combination of a name and an Attribute value.
StringAttr getName() const
Return the name of the attribute.
Attribute getValue() const
Return the value of the attribute.
The OpAsmParser has methods for interacting with the asm parser: parsing things from it,...
ParseResult resolveOperands(Operands &&operands, Type type, SmallVectorImpl< Value > &result)
Resolve a list of operands to SSA values, emitting an error on failure, or appending the results to t...
virtual ParseResult parseOperandList(SmallVectorImpl< UnresolvedOperand > &result, Delimiter delimiter=Delimiter::None, bool allowResultNumber=true, int requiredOperandCount=-1)=0
Parse zero or more SSA comma-separated operand references with a specified surrounding delimiter,...
This is a pure-virtual base class that exposes the asmprinter hooks necessary to implement a custom p...
void printOperands(const ContainerType &container)
Print a comma separated list of operands.
virtual void printOptionalAttrDict(ArrayRef< NamedAttribute > attrs, ArrayRef< StringRef > elidedAttrs={})=0
If the specified operation has attributes, print out an attribute dictionary with their values.
This class helps build Operations.
This provides public APIs that all operations should have.
Operation is the basic unit of execution within MLIR.
AttrClass getAttrOfType(StringAttr name)
bool hasAttr(StringAttr name)
Return true if the operation has an attribute with the provided name, false otherwise.
Location getLoc()
The source location the operation was defined or derived from.
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers.
A special type of RewriterBase that coordinates the application of a rewrite pattern on the current I...
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 coordinates the application of a rewrite on a set of IR, providing a way for clients to tr...
OpTy replaceOpWithNewOp(Operation *op, Args &&...args)
Replace the results of the given (original) op with a new op that is created without verification (re...
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 isInteger() const
Return true if this is an integer type (with the specified width).
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.
static WalkResult advance()
static WalkResult interrupt()
bool isValidLoadStoreImpl(Type type, ptr::AtomicOrdering ordering, std::optional< int64_t > alignment, const ::mlir::DataLayout *dataLayout, function_ref< InFlightDiagnostic()> emitError)
Checks whether the given type is an LLVM type that can be loaded or stored.
SmallVector< int64_t, 4 > getCoordinates(ArrayRef< int64_t > basis, unsigned linearIndex)
@ Write
Write register with '=' modifier.
@ ReadWrite
ReadWrite register with '+' modifier.
@ Read
Read register with no modifier.
std::pair< mlir::Type, unsigned > inferMMAType(mlir::NVVM::MMATypes type, mlir::NVVM::MMAFrag frag, int nRow, int nCol, mlir::MLIRContext *context)
Return the element type and number of elements associated with a wmma matrix of given chracteristics.
std::pair< llvm::Intrinsic::ID, llvm::SmallVector< llvm::Value * > > IDArgPair
A pair type of LLVM's Intrinsic ID and args (which are llvm values).
void walk(Operation *op, function_ref< void(Region *)> callback, WalkOrder order)
Walk all of the regions, blocks, or operations nested under (and including) the given operation.
uint64_t getN(LevelType lt)
uint64_t getM(LevelType lt)
Include the generated interface declarations.
llvm::function_ref< void(Value, const ConstantIntRanges &)> SetIntRangeFn
The type of the setResultRanges callback provided to ops implementing InferIntRangeInterface.
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.
llvm::function_ref< Fn > function_ref
LogicalResult matchAndRewrite(SubFOp op, PatternRewriter &rewriter) const override
static bool isMinimumSMVersion(unsigned fullSmVersion)
static unsigned getTargetFullSmVersionFromStr(StringRef smVersionString)
bool isCompatibleWith(const unsigned &targetFullSmVersion) const
OpRewritePattern(MLIRContext *context, PatternBenefit benefit=1, ArrayRef< StringRef > generatedNames={})
This represents an operation in an abstracted form, suitable for use with the builder APIs.