19#include "llvm/ADT/StringExtras.h"
20#include "llvm/ADT/iterator_range.h"
21#include "llvm/IR/IRBuilder.h"
22#include "llvm/IR/IntrinsicsNVPTX.h"
23#include "llvm/Support/FormatVariadic.h"
24#include "llvm/Support/NVVMAttributes.h"
31#define REDUX_F32_ID_IMPL(op, abs, hasNaN) \
32 hasNaN ? llvm::Intrinsic::nvvm_redux_sync_f##op##abs##_NaN \
33 : llvm::Intrinsic::nvvm_redux_sync_f##op##abs
35#define GET_REDUX_F32_ID(op, hasAbs, hasNaN) \
36 hasAbs ? REDUX_F32_ID_IMPL(op, _abs, hasNaN) : REDUX_F32_ID_IMPL(op, , hasNaN)
39 NVVM::ReductionKind kind,
40 bool hasAbs,
bool hasNaN) {
42 case NVVM::ReductionKind::ADD:
43 return llvm::Intrinsic::nvvm_redux_sync_add;
44 case NVVM::ReductionKind::UMAX:
45 return llvm::Intrinsic::nvvm_redux_sync_umax;
46 case NVVM::ReductionKind::UMIN:
47 return llvm::Intrinsic::nvvm_redux_sync_umin;
48 case NVVM::ReductionKind::AND:
49 return llvm::Intrinsic::nvvm_redux_sync_and;
50 case NVVM::ReductionKind::OR:
51 return llvm::Intrinsic::nvvm_redux_sync_or;
52 case NVVM::ReductionKind::XOR:
53 return llvm::Intrinsic::nvvm_redux_sync_xor;
54 case NVVM::ReductionKind::MAX:
55 return llvm::Intrinsic::nvvm_redux_sync_max;
56 case NVVM::ReductionKind::MIN:
57 return llvm::Intrinsic::nvvm_redux_sync_min;
58 case NVVM::ReductionKind::FMIN:
60 case NVVM::ReductionKind::FMAX:
63 llvm_unreachable(
"unknown reduction kind");
71 resultType = cast<llvm::StructType>(resultType)->getElementType(0);
73 case NVVM::ShflKind::bfly:
74 return resultType->isFloatTy()
75 ? llvm::Intrinsic::nvvm_shfl_sync_bfly_f32p
76 : llvm::Intrinsic::nvvm_shfl_sync_bfly_i32p;
77 case NVVM::ShflKind::up:
78 return resultType->isFloatTy() ? llvm::Intrinsic::nvvm_shfl_sync_up_f32p
79 : llvm::Intrinsic::nvvm_shfl_sync_up_i32p;
80 case NVVM::ShflKind::down:
81 return resultType->isFloatTy()
82 ? llvm::Intrinsic::nvvm_shfl_sync_down_f32p
83 : llvm::Intrinsic::nvvm_shfl_sync_down_i32p;
84 case NVVM::ShflKind::idx:
85 return resultType->isFloatTy() ? llvm::Intrinsic::nvvm_shfl_sync_idx_f32p
86 : llvm::Intrinsic::nvvm_shfl_sync_idx_i32p;
90 case NVVM::ShflKind::bfly:
91 return resultType->isFloatTy() ? llvm::Intrinsic::nvvm_shfl_sync_bfly_f32
92 : llvm::Intrinsic::nvvm_shfl_sync_bfly_i32;
93 case NVVM::ShflKind::up:
94 return resultType->isFloatTy() ? llvm::Intrinsic::nvvm_shfl_sync_up_f32
95 : llvm::Intrinsic::nvvm_shfl_sync_up_i32;
96 case NVVM::ShflKind::down:
97 return resultType->isFloatTy() ? llvm::Intrinsic::nvvm_shfl_sync_down_f32
98 : llvm::Intrinsic::nvvm_shfl_sync_down_i32;
99 case NVVM::ShflKind::idx:
100 return resultType->isFloatTy() ? llvm::Intrinsic::nvvm_shfl_sync_idx_f32
101 : llvm::Intrinsic::nvvm_shfl_sync_idx_i32;
104 llvm_unreachable(
"unknown shuffle kind");
108 NVVM::MatchSyncKind kind) {
110 case NVVM::MatchSyncKind::any:
111 return valType.
isInteger(32) ? llvm::Intrinsic::nvvm_match_any_sync_i32
112 : llvm::Intrinsic::nvvm_match_any_sync_i64;
113 case NVVM::MatchSyncKind::all:
117 return valType.
isInteger(32) ? llvm::Intrinsic::nvvm_match_all_sync_i32p
118 : llvm::Intrinsic::nvvm_match_all_sync_i64p;
120 llvm_unreachable(
"unsupported match sync kind");
125 case NVVM::VoteSyncKind::any:
126 return llvm::Intrinsic::nvvm_vote_any_sync;
127 case NVVM::VoteSyncKind::all:
128 return llvm::Intrinsic::nvvm_vote_all_sync;
129 case NVVM::VoteSyncKind::ballot:
130 return llvm::Intrinsic::nvvm_vote_ballot_sync;
131 case NVVM::VoteSyncKind::uni:
132 return llvm::Intrinsic::nvvm_vote_uni_sync;
134 llvm_unreachable(
"unsupported vote kind");
137static llvm::Intrinsic::ID
139 NVVM::LdStMatrixShapeAttr
shape,
140 NVVM::LdStMatrixEltType eltType) {
144 return (layout == NVVM::MMALayout::row)
145 ? llvm::Intrinsic::nvvm_ldmatrix_sync_aligned_m8n8_x1_b16
147 nvvm_ldmatrix_sync_aligned_m8n8_x1_trans_b16;
149 return (layout == NVVM::MMALayout::row)
150 ? llvm::Intrinsic::nvvm_ldmatrix_sync_aligned_m8n8_x2_b16
152 nvvm_ldmatrix_sync_aligned_m8n8_x2_trans_b16;
154 return (layout == NVVM::MMALayout::row)
155 ? llvm::Intrinsic::nvvm_ldmatrix_sync_aligned_m8n8_x4_b16
157 nvvm_ldmatrix_sync_aligned_m8n8_x4_trans_b16;
159 }
else if (
shape.getM() == 8 &&
shape.getN() == 16) {
160 if (eltType == NVVM::LdStMatrixEltType::B8X16_B6X16_P32) {
163 return llvm::Intrinsic::
164 nvvm_ldmatrix_sync_aligned_m8n16_x1_b8x16_b6x16_p32;
166 return llvm::Intrinsic::
167 nvvm_ldmatrix_sync_aligned_m8n16_x2_b8x16_b6x16_p32;
169 return llvm::Intrinsic::
170 nvvm_ldmatrix_sync_aligned_m8n16_x4_b8x16_b6x16_p32;
172 }
else if (eltType == NVVM::LdStMatrixEltType::B8X16_B4X16_P64) {
175 return llvm::Intrinsic::
176 nvvm_ldmatrix_sync_aligned_m8n16_x1_b8x16_b4x16_p64;
178 return llvm::Intrinsic::
179 nvvm_ldmatrix_sync_aligned_m8n16_x2_b8x16_b4x16_p64;
181 return llvm::Intrinsic::
182 nvvm_ldmatrix_sync_aligned_m8n16_x4_b8x16_b4x16_p64;
185 }
else if (
shape.getM() == 16 &&
shape.getN() == 16) {
186 if (eltType == NVVM::LdStMatrixEltType::B8) {
189 return llvm::Intrinsic::nvvm_ldmatrix_sync_aligned_m16n16_x1_trans_b8;
191 return llvm::Intrinsic::nvvm_ldmatrix_sync_aligned_m16n16_x2_trans_b8;
193 }
else if (eltType == NVVM::LdStMatrixEltType::B8X16_B6X16_P32) {
196 return llvm::Intrinsic::
197 nvvm_ldmatrix_sync_aligned_m16n16_x1_trans_b8x16_b6x16_p32;
199 return llvm::Intrinsic::
200 nvvm_ldmatrix_sync_aligned_m16n16_x2_trans_b8x16_b6x16_p32;
202 }
else if (eltType == NVVM::LdStMatrixEltType::B8X16_B4X16_P64) {
205 return llvm::Intrinsic::
206 nvvm_ldmatrix_sync_aligned_m16n16_x1_trans_b8x16_b4x16_p64;
208 return llvm::Intrinsic::
209 nvvm_ldmatrix_sync_aligned_m16n16_x2_trans_b8x16_b4x16_p64;
213 llvm_unreachable(
"unknown ldmatrix kind");
217static llvm::Intrinsic::ID
219 NVVM::LdStMatrixShapeAttr
shape,
220 NVVM::LdStMatrixEltType eltType) {
224 return (layout == NVVM::MMALayout::row)
225 ? llvm::Intrinsic::nvvm_stmatrix_sync_aligned_m8n8_x1_b16
227 nvvm_stmatrix_sync_aligned_m8n8_x1_trans_b16;
229 return (layout == NVVM::MMALayout::row)
230 ? llvm::Intrinsic::nvvm_stmatrix_sync_aligned_m8n8_x2_b16
232 nvvm_stmatrix_sync_aligned_m8n8_x2_trans_b16;
234 return (layout == NVVM::MMALayout::row)
235 ? llvm::Intrinsic::nvvm_stmatrix_sync_aligned_m8n8_x4_b16
237 nvvm_stmatrix_sync_aligned_m8n8_x4_trans_b16;
239 }
else if (
shape.getM() == 16 &&
shape.getN() == 8) {
242 return llvm::Intrinsic::nvvm_stmatrix_sync_aligned_m16n8_x1_trans_b8;
244 return llvm::Intrinsic::nvvm_stmatrix_sync_aligned_m16n8_x2_trans_b8;
246 return llvm::Intrinsic::nvvm_stmatrix_sync_aligned_m16n8_x4_trans_b8;
249 llvm_unreachable(
"unknown stmatrix kind");
253static llvm::Intrinsic::ID
256 static_cast<unsigned>(NVVM::NVVMMemorySpace::Shared);
258 : llvm::Intrinsic::nvvm_st_bulk;
262 NVVM::ProxyKind toProxy,
263 NVVM::MemScopeKind scope,
265 if (fromProxy == NVVM::ProxyKind::GENERIC &&
266 toProxy == NVVM::ProxyKind::TENSORMAP) {
268 case NVVM::MemScopeKind::CTA: {
270 return llvm::Intrinsic::nvvm_fence_proxy_tensormap_generic_release_cta;
271 return llvm::Intrinsic::nvvm_fence_proxy_tensormap_generic_acquire_cta;
273 case NVVM::MemScopeKind::CLUSTER: {
275 return llvm::Intrinsic::
276 nvvm_fence_proxy_tensormap_generic_release_cluster;
277 return llvm::Intrinsic::
278 nvvm_fence_proxy_tensormap_generic_acquire_cluster;
280 case NVVM::MemScopeKind::GPU: {
282 return llvm::Intrinsic::nvvm_fence_proxy_tensormap_generic_release_gpu;
283 return llvm::Intrinsic::nvvm_fence_proxy_tensormap_generic_acquire_gpu;
285 case NVVM::MemScopeKind::SYS: {
287 return llvm::Intrinsic::nvvm_fence_proxy_tensormap_generic_release_sys;
288 return llvm::Intrinsic::nvvm_fence_proxy_tensormap_generic_acquire_sys;
291 llvm_unreachable(
"Unknown scope for uni-directional fence.proxy operation");
293 llvm_unreachable(
"Unsupported proxy kinds");
298 case NVVM::MemScopeKind::CTA:
299 return llvm::Intrinsic::nvvm_membar_cta;
300 case NVVM::MemScopeKind::CLUSTER:
301 return llvm::Intrinsic::nvvm_fence_sc_cluster;
302 case NVVM::MemScopeKind::GPU:
303 return llvm::Intrinsic::nvvm_membar_gl;
304 case NVVM::MemScopeKind::SYS:
305 return llvm::Intrinsic::nvvm_membar_sys;
307 llvm_unreachable(
"Unknown scope for memory barrier");
310#define TCGEN05LD(SHAPE, NUM) llvm::Intrinsic::nvvm_tcgen05_ld_##SHAPE##_##NUM
312static llvm::Intrinsic::ID
314 llvm::Intrinsic::ID Shape16x64b[] = {
320 llvm::Intrinsic::ID Shape16x128b[] = {
326 llvm::Intrinsic::ID Shape16x256b[] = {
331 llvm::Intrinsic::ID Shape16x32bx2[] = {
338 llvm::Intrinsic::ID Shape32x32b[] = {
346 unsigned Idx = std::log2(num);
349 case NVVM::Tcgen05LdStShape::SHAPE_16X64B:
350 return Shape16x64b[Idx];
351 case NVVM::Tcgen05LdStShape::SHAPE_16X128B:
352 return Shape16x128b[Idx - 1];
353 case NVVM::Tcgen05LdStShape::SHAPE_16X256B:
354 return Shape16x256b[Idx - 2];
355 case NVVM::Tcgen05LdStShape::SHAPE_32X32B:
356 return Shape32x32b[Idx];
357 case NVVM::Tcgen05LdStShape::SHAPE_16X32BX2:
358 return Shape16x32bx2[Idx];
360 llvm_unreachable(
"unhandled tcgen05.ld lowering");
363#define TCGEN05ST(SHAPE, NUM) llvm::Intrinsic::nvvm_tcgen05_st_##SHAPE##_##NUM
365static llvm::Intrinsic::ID
367 llvm::Intrinsic::ID Shape16x64b[] = {
373 llvm::Intrinsic::ID Shape16x128b[] = {
379 llvm::Intrinsic::ID Shape16x256b[] = {
384 llvm::Intrinsic::ID Shape16x32bx2[] = {
391 llvm::Intrinsic::ID Shape32x32b[] = {
399 unsigned Idx = std::log2(num);
402 case NVVM::Tcgen05LdStShape::SHAPE_16X64B:
403 return Shape16x64b[Idx];
404 case NVVM::Tcgen05LdStShape::SHAPE_16X128B:
405 return Shape16x128b[Idx - 1];
406 case NVVM::Tcgen05LdStShape::SHAPE_16X256B:
407 return Shape16x256b[Idx - 2];
408 case NVVM::Tcgen05LdStShape::SHAPE_32X32B:
409 return Shape32x32b[Idx];
410 case NVVM::Tcgen05LdStShape::SHAPE_16X32BX2:
411 return Shape16x32bx2[Idx];
413 llvm_unreachable(
"unhandled tcgen05.st lowering");
417 return order == NVVM::MemOrderKind::ACQUIRE
419 nvvm_fence_acquire_sync_restrict_space_cluster_scope_cluster
421 nvvm_fence_release_sync_restrict_space_cta_scope_cluster;
424static llvm::Intrinsic::ID
427 case NVVM::ProxyKind::alias:
428 return llvm::Intrinsic::nvvm_fence_proxy_alias;
429 case NVVM::ProxyKind::async:
430 return llvm::Intrinsic::nvvm_fence_proxy_async;
431 case NVVM::ProxyKind::async_global:
432 return llvm::Intrinsic::nvvm_fence_proxy_async_global;
433 case NVVM::ProxyKind::async_shared:
434 return *space == NVVM::SharedSpace::shared_cta
435 ? llvm::Intrinsic::nvvm_fence_proxy_async_shared_cta
436 : llvm::Intrinsic::nvvm_fence_proxy_async_shared_cluster;
438 llvm_unreachable(
"unsupported proxy kind");
442static llvm::Intrinsic::ID
444 return order == NVVM::MemOrderKind::ACQUIRE
446 nvvm_fence_proxy_async_generic_acquire_sync_restrict_space_cluster_scope_cluster
448 nvvm_fence_proxy_async_generic_release_sync_restrict_space_cta_scope_cluster;
457 llvm::Intrinsic::ID IID, llvm::Type *opTypeLLVM,
459 llvm::Type *retType) {
460 if (opTypeLLVM->isVectorTy() && (opTypeLLVM->getScalarType()->isFloatTy() ||
461 opTypeLLVM->getScalarType()->isDoubleTy())) {
462 llvm::Value *
result = llvm::PoisonValue::get(
463 llvm::FixedVectorType::get(opTypeLLVM->getScalarType(), 2));
464 for (
int64_t i = 0; i < 2; ++i) {
466 for (llvm::Value *op : operands)
467 scalarArgs.push_back(
468 builder.CreateExtractElement(op, builder.getInt32(i)));
470 result = builder.CreateInsertElement(
result, res, builder.getInt32(i));
478void NVVM::AddFOp::lowerAddFToLLVMIR(llvm::Value *argLHS, llvm::Value *argRHS,
479 Value res, NVVM::FPRoundingMode rndMode,
480 NVVM::SaturationMode satMode,
bool isFTZ,
482 llvm::IRBuilderBase &builder) {
483 llvm::Type *opTypeLLVM = argLHS->getType();
484 bool isVectorOp = opTypeLLVM->isVectorTy();
485 bool isSat = satMode != NVVM::SaturationMode::NONE;
489 static constexpr llvm::Intrinsic::ID f16IDs[] = {
490 llvm::Intrinsic::nvvm_add_rn_sat_f16,
491 llvm::Intrinsic::nvvm_add_rn_ftz_sat_f16,
492 llvm::Intrinsic::nvvm_add_rn_sat_v2f16,
493 llvm::Intrinsic::nvvm_add_rn_ftz_sat_v2f16,
496 static constexpr llvm::Intrinsic::ID f32IDs[] = {
497 llvm::Intrinsic::nvvm_add_rn_f,
498 llvm::Intrinsic::nvvm_add_rn_f,
499 llvm::Intrinsic::nvvm_add_rm_f,
500 llvm::Intrinsic::nvvm_add_rp_f,
501 llvm::Intrinsic::nvvm_add_rz_f,
502 llvm::Intrinsic::nvvm_add_rn_sat_f,
503 llvm::Intrinsic::nvvm_add_rn_sat_f,
504 llvm::Intrinsic::nvvm_add_rm_sat_f,
505 llvm::Intrinsic::nvvm_add_rp_sat_f,
506 llvm::Intrinsic::nvvm_add_rz_sat_f,
507 llvm::Intrinsic::nvvm_add_rn_ftz_f,
508 llvm::Intrinsic::nvvm_add_rn_ftz_f,
509 llvm::Intrinsic::nvvm_add_rm_ftz_f,
510 llvm::Intrinsic::nvvm_add_rp_ftz_f,
511 llvm::Intrinsic::nvvm_add_rz_ftz_f,
512 llvm::Intrinsic::nvvm_add_rn_ftz_sat_f,
513 llvm::Intrinsic::nvvm_add_rn_ftz_sat_f,
514 llvm::Intrinsic::nvvm_add_rm_ftz_sat_f,
515 llvm::Intrinsic::nvvm_add_rp_ftz_sat_f,
516 llvm::Intrinsic::nvvm_add_rz_ftz_sat_f,
519 static constexpr llvm::Intrinsic::ID f64IDs[] = {
520 llvm::Intrinsic::nvvm_add_rn_d,
521 llvm::Intrinsic::nvvm_add_rn_d, llvm::Intrinsic::nvvm_add_rm_d,
522 llvm::Intrinsic::nvvm_add_rp_d, llvm::Intrinsic::nvvm_add_rz_d};
524 auto addIntrinsic = [&](llvm::Intrinsic::ID IID) -> llvm::Value * {
526 {argLHS, argRHS}, opTypeLLVM);
532 if (opTypeLLVM->getScalarType()->isHalfTy()) {
535 unsigned index = (isVectorOp << 1) | isFTZ;
538 result = builder.CreateFAdd(argLHS, argRHS);
545 if (opTypeLLVM->getScalarType()->isBFloatTy()) {
546 mt.
mapValue(res, builder.CreateFAdd(argLHS, argRHS));
551 if (opTypeLLVM->getScalarType()->isDoubleTy()) {
552 unsigned index =
static_cast<unsigned>(rndMode);
558 const unsigned numRndModes = 5;
559 if (opTypeLLVM->getScalarType()->isFloatTy()) {
561 ((isFTZ << 1) | isSat) * numRndModes + static_cast<unsigned>(rndMode);
568 llvm::IRBuilderBase &builder) {
569 auto thisOp = cast<NVVM::FmaOp>(op);
570 mlir::NVVM::FPRoundingMode rndMode = thisOp.getRnd();
571 unsigned rndIndex =
static_cast<unsigned>(rndMode) - 1;
572 mlir::NVVM::SaturationMode satMode = thisOp.getSat();
573 bool isFTZ = thisOp.getFtz();
574 bool isRelu = thisOp.getRelu();
575 bool isSat = satMode == NVVM::SaturationMode::SAT;
576 bool isOOB = thisOp.getOob();
578 mlir::Type opType = thisOp.getRes().getType();
580 bool isVectorFma = opTypeLLVM->isVectorTy();
586 static constexpr llvm::Intrinsic::ID f16IDs[] = {
587 llvm::Intrinsic::nvvm_fma_rn_f16,
588 llvm::Intrinsic::nvvm_fma_rn_f16x2,
589 llvm::Intrinsic::nvvm_fma_rn_ftz_f16,
590 llvm::Intrinsic::nvvm_fma_rn_ftz_f16x2,
591 llvm::Intrinsic::nvvm_fma_rn_sat_f16,
592 llvm::Intrinsic::nvvm_fma_rn_sat_f16x2,
593 llvm::Intrinsic::nvvm_fma_rn_ftz_sat_f16,
594 llvm::Intrinsic::nvvm_fma_rn_ftz_sat_f16x2,
595 llvm::Intrinsic::nvvm_fma_rn_relu_f16,
596 llvm::Intrinsic::nvvm_fma_rn_relu_f16x2,
597 llvm::Intrinsic::nvvm_fma_rn_ftz_relu_f16,
598 llvm::Intrinsic::nvvm_fma_rn_ftz_relu_f16x2};
600 static constexpr llvm::Intrinsic::ID bf16IDs[] = {
601 llvm::Intrinsic::nvvm_fma_rn_bf16, llvm::Intrinsic::nvvm_fma_rn_bf16x2,
602 llvm::Intrinsic::nvvm_fma_rn_relu_bf16,
603 llvm::Intrinsic::nvvm_fma_rn_relu_bf16x2};
605 static constexpr llvm::Intrinsic::ID f32IDs[] = {
606 llvm::Intrinsic::nvvm_fma_rn_f,
607 llvm::Intrinsic::nvvm_fma_rm_f,
608 llvm::Intrinsic::nvvm_fma_rp_f,
609 llvm::Intrinsic::nvvm_fma_rz_f,
610 llvm::Intrinsic::nvvm_fma_rn_sat_f,
611 llvm::Intrinsic::nvvm_fma_rm_sat_f,
612 llvm::Intrinsic::nvvm_fma_rp_sat_f,
613 llvm::Intrinsic::nvvm_fma_rz_sat_f,
614 llvm::Intrinsic::nvvm_fma_rn_ftz_f,
615 llvm::Intrinsic::nvvm_fma_rm_ftz_f,
616 llvm::Intrinsic::nvvm_fma_rp_ftz_f,
617 llvm::Intrinsic::nvvm_fma_rz_ftz_f,
618 llvm::Intrinsic::nvvm_fma_rn_ftz_sat_f,
619 llvm::Intrinsic::nvvm_fma_rm_ftz_sat_f,
620 llvm::Intrinsic::nvvm_fma_rp_ftz_sat_f,
621 llvm::Intrinsic::nvvm_fma_rz_ftz_sat_f,
624 static constexpr llvm::Intrinsic::ID f64IDs[] = {
625 llvm::Intrinsic::nvvm_fma_rn_d, llvm::Intrinsic::nvvm_fma_rm_d,
626 llvm::Intrinsic::nvvm_fma_rp_d, llvm::Intrinsic::nvvm_fma_rz_d};
628 auto fmaIntrinsic = [&](llvm::Intrinsic::ID IID,
629 llvm::Type *retType) -> llvm::Value * {
631 builder, IID, opTypeLLVM, {argA, argB, argC}, retType);
635 if (opTypeLLVM->getScalarType()->isHalfTy()) {
638 result = fmaIntrinsic(isRelu ? llvm::Intrinsic::nvvm_fma_rn_oob_relu
639 : llvm::Intrinsic::nvvm_fma_rn_oob,
643 (isRelu << 3) | (isSat << 2) | (isFTZ << 1) |
652 if (opTypeLLVM->getScalarType()->isBFloatTy()) {
655 result = fmaIntrinsic(isRelu ? llvm::Intrinsic::nvvm_fma_rn_oob_relu
656 : llvm::Intrinsic::nvvm_fma_rn_oob,
659 unsigned index = (isRelu << 1) | isVectorFma;
667 if (opTypeLLVM->getScalarType()->isDoubleTy()) {
669 fmaIntrinsic(f64IDs[rndIndex], opTypeLLVM->getScalarType()));
674 const unsigned numRndModes = 4;
675 if (opTypeLLVM->getScalarType()->isFloatTy()) {
676 unsigned index = ((isFTZ << 1) | isSat) * numRndModes + rndIndex;
678 fmaIntrinsic(f32IDs[
index], opTypeLLVM->getScalarType()));
686class NVVMDialectLLVMIRTranslationInterface
687 :
public LLVMTranslationDialectInterface {
689 using LLVMTranslationDialectInterface::LLVMTranslationDialectInterface;
694 convertOperation(Operation *op, llvm::IRBuilderBase &builder,
695 LLVM::ModuleTranslation &moduleTranslation)
const final {
699 if (!builder.GetInsertBlock())
701 "cannot be translated to LLVM IR without an active insertion "
702 "point; make sure the op is inside a function");
703 Operation &opInst = *op;
704#include "mlir/Dialect/LLVMIR/NVVMConversions.inc"
712 amendOperation(Operation *op, ArrayRef<llvm::Instruction *> instructions,
713 NamedAttribute attribute,
714 LLVM::ModuleTranslation &moduleTranslation)
const final {
715 if (
auto globalOp = dyn_cast<LLVM::GlobalOp>(op)) {
716 if (attribute.getName() == NVVM::NVVMDialect::getManagedAttrName()) {
717 auto *gv = cast<llvm::GlobalVariable>(
718 moduleTranslation.lookupGlobal(globalOp));
719 llvm::Module *m = gv->getParent();
720 llvm::LLVMContext &ctx = m->getContext();
721 llvm::NamedMDNode *md = m->getOrInsertNamedMetadata(
"nvvm.annotations");
722 md->addOperand(llvm::MDNode::get(
723 ctx, {llvm::ConstantAsMetadata::get(gv),
724 llvm::MDString::get(ctx,
"managed"),
725 llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
726 llvm::Type::getInt32Ty(ctx), 1))}));
731 auto func = dyn_cast<LLVM::LLVMFuncOp>(op);
734 llvm::Function *llvmFunc = moduleTranslation.lookupFunction(func.getName());
736 if (attribute.getName() == NVVM::NVVMDialect::getMaxntidAttrName()) {
737 if (!isa<DenseI32ArrayAttr>(attribute.getValue()))
739 auto values = cast<DenseI32ArrayAttr>(attribute.getValue());
740 const std::string attr = llvm::formatv(
741 "{0:$[,]}", llvm::make_range(values.asArrayRef().begin(),
742 values.asArrayRef().end()));
743 llvmFunc->addFnAttr(llvm::NVVMAttr::MaxNTID, attr);
744 }
else if (attribute.getName() == NVVM::NVVMDialect::getReqntidAttrName()) {
745 if (!isa<DenseI32ArrayAttr>(attribute.getValue()))
747 auto values = cast<DenseI32ArrayAttr>(attribute.getValue());
748 const std::string attr = llvm::formatv(
749 "{0:$[,]}", llvm::make_range(values.asArrayRef().begin(),
750 values.asArrayRef().end()));
751 llvmFunc->addFnAttr(llvm::NVVMAttr::ReqNTID, attr);
752 }
else if (attribute.getName() ==
753 NVVM::NVVMDialect::getClusterDimAttrName()) {
754 if (!isa<DenseI32ArrayAttr>(attribute.getValue()))
756 auto values = cast<DenseI32ArrayAttr>(attribute.getValue());
757 const std::string attr = llvm::formatv(
758 "{0:$[,]}", llvm::make_range(values.asArrayRef().begin(),
759 values.asArrayRef().end()));
760 llvmFunc->addFnAttr(llvm::NVVMAttr::ClusterDim, attr);
761 }
else if (attribute.getName() ==
762 NVVM::NVVMDialect::getClusterMaxBlocksAttrName()) {
763 auto value = dyn_cast<IntegerAttr>(attribute.getValue());
764 llvmFunc->addFnAttr(llvm::NVVMAttr::MaxClusterRank,
765 llvm::utostr(value.getInt()));
766 }
else if (attribute.getName() ==
767 NVVM::NVVMDialect::getMinctasmAttrName()) {
768 auto value = dyn_cast<IntegerAttr>(attribute.getValue());
769 llvmFunc->addFnAttr(llvm::NVVMAttr::MinCTASm,
770 llvm::utostr(value.getInt()));
771 }
else if (attribute.getName() == NVVM::NVVMDialect::getMaxnregAttrName()) {
772 auto value = dyn_cast<IntegerAttr>(attribute.getValue());
773 llvmFunc->addFnAttr(llvm::NVVMAttr::MaxNReg,
774 llvm::utostr(value.getInt()));
775 }
else if (attribute.getName() ==
776 NVVM::NVVMDialect::getKernelFuncAttrName()) {
777 llvmFunc->setCallingConv(llvm::CallingConv::PTX_Kernel);
778 }
else if (attribute.getName() ==
779 NVVM::NVVMDialect::getBlocksAreClustersAttrName()) {
780 llvmFunc->addFnAttr(llvm::NVVMAttr::BlocksAreClusters);
788 LLVM::ModuleTranslation &moduleTranslation)
const final {
790 llvm::LLVMContext &llvmContext = moduleTranslation.getLLVMContext();
791 llvm::Function *llvmFunc =
792 moduleTranslation.lookupFunction(funcOp.getName());
794 if (attribute.getName() == NVVM::NVVMDialect::getGridConstantAttrName()) {
795 llvmFunc->addParamAttr(
797 llvm::Attribute::get(llvmContext, llvm::NVVMAttr::GridConstant));
805 registry.
insert<NVVM::NVVMDialect>();
807 dialect->addInterfaces<NVVMDialectLLVMIRTranslationInterface>();
static LogicalResult convertParameterAttr(llvm::AttrBuilder &attrBuilder, llvm::Attribute::AttrKind llvmKind, NamedAttribute namedAttr, ModuleTranslation &moduleTranslation, Location loc)
static llvm::Intrinsic::ID getLdMatrixIntrinsicId(NVVM::MMALayout layout, int32_t num, NVVM::LdStMatrixShapeAttr shape, NVVM::LdStMatrixEltType eltType)
static llvm::Intrinsic::ID getFenceProxyID(NVVM::ProxyKind kind, std::optional< NVVM::SharedSpace > space)
#define GET_REDUX_F32_ID(op, hasAbs, hasNaN)
static llvm::Intrinsic::ID getStMatrixIntrinsicId(NVVM::MMALayout layout, int32_t num, NVVM::LdStMatrixShapeAttr shape, NVVM::LdStMatrixEltType eltType)
Return the intrinsic ID associated with stmatrix for the given paramters.
static llvm::Intrinsic::ID getTcgen05StIntrinsicID(mlir::NVVM::Tcgen05LdStShape shape, uint32_t num)
static llvm::Intrinsic::ID getTcgen05LdIntrinsicID(mlir::NVVM::Tcgen05LdStShape shape, uint32_t num)
static unsigned getMembarIntrinsicID(NVVM::MemScopeKind scope)
static unsigned getUnidirectionalFenceProxyID(NVVM::ProxyKind fromProxy, NVVM::ProxyKind toProxy, NVVM::MemScopeKind scope, bool isRelease)
llvm::CallInst * createIntrinsicCall(llvm::IRBuilderBase &builder, llvm::Intrinsic::ID intrinsic, ArrayRef< llvm::Value * > args={}, ArrayRef< llvm::Type * > tys={})
Creates a call to an LLVM IR intrinsic function with the given arguments.
static llvm::Intrinsic::ID getFenceProxySyncRestrictID(NVVM::MemOrderKind order)
#define TCGEN05ST(SHAPE, NUM)
static llvm::Intrinsic::ID getReduxIntrinsicId(llvm::Type *resultType, NVVM::ReductionKind kind, bool hasAbs, bool hasNaN)
static llvm::Value * createScalarizedIntrinsicCall(llvm::IRBuilderBase &builder, llvm::Intrinsic::ID IID, llvm::Type *opTypeLLVM, ArrayRef< llvm::Value * > operands, llvm::Type *retType)
#define TCGEN05LD(SHAPE, NUM)
static llvm::Intrinsic::ID getFenceSyncRestrictID(NVVM::MemOrderKind order)
static llvm::Intrinsic::ID getShflIntrinsicId(llvm::Type *resultType, NVVM::ShflKind kind, bool withPredicate)
static llvm::Intrinsic::ID getVoteSyncIntrinsicId(NVVM::VoteSyncKind kind)
static llvm::Intrinsic::ID getMatchSyncIntrinsicId(Type valType, NVVM::MatchSyncKind kind)
static llvm::Intrinsic::ID getStBulkIntrinsicId(LLVM::LLVMPointerType addrType)
Return the intrinsic ID associated with st.bulk for the given address type.
static Value max(ImplicitLocOpBuilder &builder, Value value, Value bound)
static Value min(ImplicitLocOpBuilder &builder, Value value, Value bound)
static bool isSharedMemory(MemRefType type)
Return true if this is a shared memory memref type.
The DialectRegistry maps a dialect namespace to a constructor for the matching dialect.
bool addExtension(TypeID extensionID, std::unique_ptr< DialectExtensionBase > extension)
Add the given extension to the registry.
Implementation class for module translation.
llvm::Value * lookupValue(Value value) const
Finds an LLVM IR value corresponding to the given MLIR value.
llvm::Type * convertType(Type type)
Converts the type from MLIR LLVM dialect to LLVM.
void mapValue(Value mlir, llvm::Value *llvm)
Stores the mapping between an MLIR value and its LLVM IR counterpart.
MLIRContext is the top-level object for a collection of MLIR operations.
void appendDialectRegistry(const DialectRegistry ®istry)
Append the contents of the given dialect registry to the registry associated with this context.
Operation is the basic unit of execution within MLIR.
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
bool isInteger() const
Return true if this is an integer type (with the specified width).
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
llvm::CallInst * createIntrinsicCall(llvm::IRBuilderBase &builder, llvm::Intrinsic::ID intrinsic, ArrayRef< llvm::Value * > args={}, ArrayRef< llvm::Type * > tys={})
Creates a call to an LLVM IR intrinsic function with the given arguments.
Include the generated interface declarations.
void registerNVVMDialectTranslation(DialectRegistry ®istry)
Register the NVVM dialect and the translation from it to the LLVM IR in the given registry;.