30#include "llvm/IR/IntrinsicsNVPTX.h"
42#define DEBUG_TYPE "nvptx-isel"
43#define PASS_NAME "NVPTX DAG->DAG Pattern Instruction Selection"
47 cl::desc(
"Enable reciprocal sqrt optimization"));
54 cl::desc(
"Enable MAD wide optimization"));
59 NVPTXScopes() =
default;
66 LLVMContext *Context =
nullptr;
70 const NVPTXTargetMachine &TM;
72 NVPTX::DivPrecisionLevel getDivF32Level(
const SDNode *
N)
const;
73 bool usePrecSqrtF32(
const SDNode *
N)
const;
74 bool useF32FTZ()
const;
75 bool allowFMA()
const;
76 bool doRsqrtOpt()
const;
77 bool doMADWideOpt()
const;
82 NVPTXDAGToDAGISel() =
delete;
84 explicit NVPTXDAGToDAGISel(NVPTXTargetMachine &tm,
CodeGenOptLevel OptLevel);
86 bool runOnMachineFunction(MachineFunction &MF)
override;
87 const NVPTXSubtarget *Subtarget =
nullptr;
89 bool SelectInlineAsmMemoryOperand(
const SDValue &
Op,
91 std::vector<SDValue> &OutOps)
override;
95#include "NVPTXGenDAGISel.inc"
97 void Select(SDNode *
N)
override;
98 bool tryIntrinsicChain(SDNode *
N);
99 bool tryIntrinsicVoid(SDNode *
N);
100 void SelectTexSurfHandle(SDNode *
N);
101 bool tryLoad(SDNode *
N);
102 bool tryLoadVector(SDNode *
N);
103 bool tryLDU(SDNode *
N);
104 bool tryLDG(MemSDNode *
N);
105 bool tryStore(SDNode *
N);
106 bool tryStoreVector(SDNode *
N);
107 bool tryFence(SDNode *
N);
108 bool tryBFE(SDNode *
N);
109 bool tryBF16ArithToFMA(SDNode *
N);
110 bool tryConstantFP(SDNode *
N);
111 bool SelectSETP_F16X2(SDNode *
N);
112 bool SelectSETP_BF16X2(SDNode *
N);
113 bool tryUNPACK_VECTOR(SDNode *
N);
114 bool tryEXTRACT_VECTOR_ELEMENT(SDNode *
N);
115 void SelectV2I64toI128(SDNode *
N);
116 void SelectI128toV2I64(SDNode *
N);
117 void SelectCpAsyncBulkTensorReduceCommon(SDNode *
N,
unsigned RedOp,
118 bool IsIm2Col =
false);
119 void SelectTcgen05Ld(SDNode *
N,
bool hasOffset =
false);
120 void SelectTcgen05St(SDNode *
N,
bool hasOffset =
false);
121 void selectAtomicSwap128(SDNode *
N);
123 inline SDValue getI32Imm(
unsigned Imm,
const SDLoc &
DL) {
124 return CurDAG->getTargetConstant(Imm,
DL, MVT::i32);
126 NVPTX::Ordering getMemOrder(
const MemSDNode *
N)
const;
127 NVPTX::Scope getAtomicScope(
const MemSDNode *
N)
const;
130 SDValue getPTXCmpMode(
const CondCodeSDNode &CondCode);
137 std::pair<NVPTX::Ordering, NVPTX::Scope>
138 insertMemoryInstructionFence(SDLoc
DL,
SDValue &Chain, MemSDNode *
N);
139 NVPTX::Scope getOperationScope(MemSDNode *
N, NVPTX::Ordering O)
const;
142 static NVPTX::AddressSpace getAddrSpace(
const MemSDNode *
N);
148 explicit NVPTXDAGToDAGISelLegacy(NVPTXTargetMachine &tm,
158 return new NVPTXDAGToDAGISelLegacy(TM, OptLevel);
164 ID,
std::make_unique<NVPTXDAGToDAGISel>(tm, OptLevel)) {}
166char NVPTXDAGToDAGISelLegacy::ID = 0;
180NVPTX::DivPrecisionLevel
181NVPTXDAGToDAGISel::getDivF32Level(
const SDNode *
N)
const {
185bool NVPTXDAGToDAGISel::usePrecSqrtF32(
const SDNode *
N)
const {
189bool NVPTXDAGToDAGISel::useF32FTZ()
const {
193bool NVPTXDAGToDAGISel::allowFMA()
const {
198bool NVPTXDAGToDAGISel::doRsqrtOpt()
const {
return EnableRsqrtOpt; }
200bool NVPTXDAGToDAGISel::doMADWideOpt()
const {
return EnableMADWide; }
204void NVPTXDAGToDAGISel::Select(SDNode *
N) {
206 if (
N->isMachineOpcode()) {
211 switch (
N->getOpcode()) {
231 if (tryEXTRACT_VECTOR_ELEMENT(
N))
238 SelectSETP_BF16X2(
N);
243 if (tryLoadVector(
N))
254 if (tryStoreVector(
N))
258 if (tryIntrinsicChain(
N))
262 if (tryIntrinsicVoid(
N))
273 if (
N->getOperand(1).getValueType() == MVT::i128) {
274 SelectV2I64toI128(
N);
280 if (
N->getOperand(1).getValueType() == MVT::i128) {
281 SelectI128toV2I64(
N);
288 selectAtomicSwap128(
N);
293 if (tryBF16ArithToFMA(
N))
302#define TCGEN05_LD_OPCODE(SHAPE, NUM) \
303 (enablePack ? NVPTX::TCGEN05_LD_##SHAPE##_##NUM##_PACK \
304 : NVPTX::TCGEN05_LD_##SHAPE##_##NUM)
308 case Intrinsic::nvvm_tcgen05_ld_16x64b_x1:
310 case Intrinsic::nvvm_tcgen05_ld_16x64b_x2:
312 case Intrinsic::nvvm_tcgen05_ld_16x64b_x4:
314 case Intrinsic::nvvm_tcgen05_ld_16x64b_x8:
316 case Intrinsic::nvvm_tcgen05_ld_16x64b_x16:
318 case Intrinsic::nvvm_tcgen05_ld_16x64b_x32:
320 case Intrinsic::nvvm_tcgen05_ld_16x64b_x64:
322 case Intrinsic::nvvm_tcgen05_ld_16x64b_x128:
324 case Intrinsic::nvvm_tcgen05_ld_16x128b_x1:
326 case Intrinsic::nvvm_tcgen05_ld_16x128b_x2:
328 case Intrinsic::nvvm_tcgen05_ld_16x128b_x4:
330 case Intrinsic::nvvm_tcgen05_ld_16x128b_x8:
332 case Intrinsic::nvvm_tcgen05_ld_16x128b_x16:
334 case Intrinsic::nvvm_tcgen05_ld_16x128b_x32:
336 case Intrinsic::nvvm_tcgen05_ld_16x128b_x64:
338 case Intrinsic::nvvm_tcgen05_ld_16x256b_x1:
340 case Intrinsic::nvvm_tcgen05_ld_16x256b_x2:
342 case Intrinsic::nvvm_tcgen05_ld_16x256b_x4:
344 case Intrinsic::nvvm_tcgen05_ld_16x256b_x8:
346 case Intrinsic::nvvm_tcgen05_ld_16x256b_x16:
348 case Intrinsic::nvvm_tcgen05_ld_16x256b_x32:
350 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x1:
352 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x2:
354 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x4:
356 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x8:
358 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x16:
360 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x32:
362 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x64:
364 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x128:
366 case Intrinsic::nvvm_tcgen05_ld_32x32b_x1:
368 case Intrinsic::nvvm_tcgen05_ld_32x32b_x2:
370 case Intrinsic::nvvm_tcgen05_ld_32x32b_x4:
372 case Intrinsic::nvvm_tcgen05_ld_32x32b_x8:
374 case Intrinsic::nvvm_tcgen05_ld_32x32b_x16:
376 case Intrinsic::nvvm_tcgen05_ld_32x32b_x32:
378 case Intrinsic::nvvm_tcgen05_ld_32x32b_x64:
380 case Intrinsic::nvvm_tcgen05_ld_32x32b_x128:
386void NVPTXDAGToDAGISel::SelectTcgen05Ld(SDNode *
N,
bool hasOffset) {
389 "tcgen05.ld is not supported on this architecture variant");
396 auto OffsetNode = CurDAG->getTargetConstant(
398 ReplaceNode(
N, CurDAG->getMachineNode(
400 {N->getOperand(2), OffsetNode, N->getOperand(0)}));
403 ReplaceNode(
N, CurDAG->getMachineNode(
405 {N->getOperand(2), N->getOperand(0)}));
409bool NVPTXDAGToDAGISel::tryIntrinsicChain(SDNode *
N) {
410 unsigned IID =
N->getConstantOperandVal(1);
414 case Intrinsic::nvvm_ldu_global_f:
415 case Intrinsic::nvvm_ldu_global_i:
416 case Intrinsic::nvvm_ldu_global_p:
419 case Intrinsic::nvvm_tcgen05_ld_16x64b_x1:
420 case Intrinsic::nvvm_tcgen05_ld_16x64b_x2:
421 case Intrinsic::nvvm_tcgen05_ld_16x64b_x4:
422 case Intrinsic::nvvm_tcgen05_ld_16x64b_x8:
423 case Intrinsic::nvvm_tcgen05_ld_16x64b_x16:
424 case Intrinsic::nvvm_tcgen05_ld_16x64b_x32:
425 case Intrinsic::nvvm_tcgen05_ld_16x64b_x64:
426 case Intrinsic::nvvm_tcgen05_ld_16x64b_x128:
427 case Intrinsic::nvvm_tcgen05_ld_16x128b_x1:
428 case Intrinsic::nvvm_tcgen05_ld_16x128b_x2:
429 case Intrinsic::nvvm_tcgen05_ld_16x128b_x4:
430 case Intrinsic::nvvm_tcgen05_ld_16x128b_x16:
431 case Intrinsic::nvvm_tcgen05_ld_16x128b_x32:
432 case Intrinsic::nvvm_tcgen05_ld_16x128b_x64:
433 case Intrinsic::nvvm_tcgen05_ld_16x256b_x1:
434 case Intrinsic::nvvm_tcgen05_ld_16x128b_x8:
435 case Intrinsic::nvvm_tcgen05_ld_16x256b_x2:
436 case Intrinsic::nvvm_tcgen05_ld_16x256b_x4:
437 case Intrinsic::nvvm_tcgen05_ld_16x256b_x8:
438 case Intrinsic::nvvm_tcgen05_ld_16x256b_x16:
439 case Intrinsic::nvvm_tcgen05_ld_16x256b_x32:
440 case Intrinsic::nvvm_tcgen05_ld_32x32b_x1:
441 case Intrinsic::nvvm_tcgen05_ld_32x32b_x2:
442 case Intrinsic::nvvm_tcgen05_ld_32x32b_x4:
443 case Intrinsic::nvvm_tcgen05_ld_32x32b_x8:
444 case Intrinsic::nvvm_tcgen05_ld_32x32b_x16:
445 case Intrinsic::nvvm_tcgen05_ld_32x32b_x32:
446 case Intrinsic::nvvm_tcgen05_ld_32x32b_x64:
447 case Intrinsic::nvvm_tcgen05_ld_32x32b_x128: {
452 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x1:
453 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x2:
454 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x4:
455 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x8:
456 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x16:
457 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x32:
458 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x64:
459 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x128: {
460 SelectTcgen05Ld(
N,
true);
468SDValue NVPTXDAGToDAGISel::getPTXCmpMode(
const CondCodeSDNode &CondCode) {
495 return CmpMode::NotANumber;
510 return CurDAG->getTargetConstant(PTXCmpMode, SDLoc(), MVT::i32);
513bool NVPTXDAGToDAGISel::SelectSETP_F16X2(SDNode *
N) {
516 SDNode *SetP = CurDAG->getMachineNode(
517 NVPTX::SETP_f16x2rr,
DL, MVT::i1, MVT::i1,
518 {
N->getOperand(0),
N->getOperand(1), PTXCmpMode,
519 CurDAG->getTargetConstant(useF32FTZ() ? 1 : 0,
DL, MVT::i1)});
520 ReplaceNode(
N, SetP);
524bool NVPTXDAGToDAGISel::SelectSETP_BF16X2(SDNode *
N) {
528 CurDAG->getMachineNode(NVPTX::SETP_bf16x2rr,
DL, MVT::i1, MVT::i1,
529 {
N->getOperand(0),
N->getOperand(1), PTXCmpMode});
530 ReplaceNode(
N, SetP);
534bool NVPTXDAGToDAGISel::tryUNPACK_VECTOR(SDNode *
N) {
536 MVT EltVT =
N->getSimpleValueType(0);
539 CurDAG->getMachineNode(NVPTX::I64toV2I32, SDLoc(
N), EltVT, EltVT,
Vector);
547bool NVPTXDAGToDAGISel::tryEXTRACT_VECTOR_ELEMENT(SDNode *
N) {
550 MVT VT =
Vector.getSimpleValueType();
556 Opcode = NVPTX::I32toV2I16;
558 Opcode = NVPTX::I64toV2I32;
564 for (
auto *U :
Vector.getNode()->users()) {
567 if (
U->getOperand(0) !=
Vector)
569 if (
const ConstantSDNode *IdxConst =
571 if (IdxConst->getZExtValue() == 0)
573 else if (IdxConst->getZExtValue() == 1)
589 CurDAG->getMachineNode(Opcode, SDLoc(
N), EltVT, EltVT,
Vector);
590 for (
auto *Node : E0)
592 for (
auto *Node : E1)
598NVPTX::AddressSpace NVPTXDAGToDAGISel::getAddrSpace(
const MemSDNode *
N) {
600 static_cast<NVPTX::AddressSpace
>(
N->getMemOperand()->getAddrSpace());
602 case NVPTX::AddressSpace::Generic:
603 case NVPTX::AddressSpace::Global:
604 case NVPTX::AddressSpace::Shared:
605 case NVPTX::AddressSpace::Const:
606 case NVPTX::AddressSpace::Local:
607 case NVPTX::AddressSpace::SharedCluster:
608 case NVPTX::AddressSpace::EntryParam:
609 case NVPTX::AddressSpace::DeviceParam:
615NVPTX::Ordering NVPTXDAGToDAGISel::getMemOrder(
const MemSDNode *
N)
const {
618 return NVPTX::Ordering::NotAtomic;
621 case AtomicOrdering::NotAtomic:
622 return NVPTX::Ordering::NotAtomic;
623 case AtomicOrdering::Unordered:
624 case AtomicOrdering::Monotonic:
625 return NVPTX::Ordering::Relaxed;
626 case AtomicOrdering::Acquire:
627 return NVPTX::Ordering::Acquire;
628 case AtomicOrdering::Release:
629 return NVPTX::Ordering::Release;
630 case AtomicOrdering::AcquireRelease:
631 return NVPTX::Ordering::AcquireRelease;
632 case AtomicOrdering::SequentiallyConsistent:
633 return NVPTX::Ordering::SequentiallyConsistent;
645NVPTX::Scope NVPTXDAGToDAGISel::getAtomicScope(
const MemSDNode *
N)
const {
647 return NVPTX::Scope::DefaultDevice;
653struct OperationOrderings {
654 NVPTX::Ordering InstructionOrdering, FenceOrdering;
655 OperationOrderings(NVPTX::Ordering IO = NVPTX::Ordering::NotAtomic,
656 NVPTX::Ordering FO = NVPTX::Ordering::NotAtomic)
657 : InstructionOrdering(IO), FenceOrdering(FO) {}
660static OperationOrderings
661getOperationOrderings(MemSDNode *
N,
const NVPTXSubtarget *Subtarget) {
663 auto CodeAddrSpace = NVPTXDAGToDAGISel::getAddrSpace(
N);
751 if (CodeAddrSpace == NVPTX::AddressSpace::Local ||
752 CodeAddrSpace == NVPTX::AddressSpace::Const ||
753 CodeAddrSpace == NVPTX::AddressSpace::EntryParam ||
754 CodeAddrSpace == NVPTX::AddressSpace::DeviceParam) {
755 return NVPTX::Ordering::NotAtomic;
760 if (!(Ordering == AtomicOrdering::NotAtomic ||
761 Ordering == AtomicOrdering::Unordered ||
762 Ordering == AtomicOrdering::Monotonic) &&
763 !HasMemoryOrdering) {
765 formatv(
"PTX does not support \"atomic\" for orderings different than"
766 "\"NotAtomic\" or \"Monotonic\" for sm_60 or older, but order "
778 bool AddrGenericOrGlobalOrShared =
779 (CodeAddrSpace == NVPTX::AddressSpace::Generic ||
780 CodeAddrSpace == NVPTX::AddressSpace::Global ||
781 CodeAddrSpace == NVPTX::AddressSpace::Shared ||
782 CodeAddrSpace == NVPTX::AddressSpace::SharedCluster);
783 if (!AddrGenericOrGlobalOrShared)
784 return NVPTX::Ordering::NotAtomic;
786 bool UseRelaxedMMIO =
787 HasRelaxedMMIO && CodeAddrSpace == NVPTX::AddressSpace::Global;
790 case AtomicOrdering::NotAtomic:
791 return N->isVolatile() ? NVPTX::Ordering::Volatile
792 : NVPTX::Ordering::NotAtomic;
793 case AtomicOrdering::Unordered:
796 case AtomicOrdering::Monotonic:
798 return UseRelaxedMMIO ? NVPTX::Ordering::RelaxedMMIO
799 : NVPTX::Ordering::Volatile;
801 return HasMemoryOrdering ? NVPTX::Ordering::Relaxed
802 : NVPTX::Ordering::Volatile;
805 case AtomicOrdering::Acquire:
808 formatv(
"PTX only supports Acquire Ordering on reads: {}",
809 N->getOperationName()));
810 return NVPTX::Ordering::Acquire;
811 case AtomicOrdering::Release:
814 formatv(
"PTX only supports Release Ordering on writes: {}",
815 N->getOperationName()));
816 return NVPTX::Ordering::Release;
817 case AtomicOrdering::AcquireRelease: {
819 formatv(
"NVPTX does not support AcquireRelease Ordering on "
821 "yet and PTX does not support it on loads or stores: {}",
822 N->getOperationName()));
824 case AtomicOrdering::SequentiallyConsistent: {
832 NVPTX::Ordering InstrOrder;
834 InstrOrder = NVPTX::Ordering::Acquire;
835 else if (
N->writeMem())
836 InstrOrder = NVPTX::Ordering::Release;
839 formatv(
"NVPTX does not support SequentiallyConsistent Ordering on "
840 "read-modify-writes yet: {}",
841 N->getOperationName()));
842 return OperationOrderings(InstrOrder,
843 NVPTX::Ordering::SequentiallyConsistent);
847 formatv(
"NVPTX backend does not support AtomicOrdering \"{}\" yet.",
853NVPTX::Scope NVPTXDAGToDAGISel::getOperationScope(MemSDNode *
N,
854 NVPTX::Ordering O)
const {
856 case NVPTX::Ordering::NotAtomic:
857 case NVPTX::Ordering::Volatile:
859 return NVPTX::Scope::Thread;
860 case NVPTX::Ordering::RelaxedMMIO:
864 return NVPTX::Scope::System;
865 case NVPTX::Ordering::Relaxed:
866 case NVPTX::Ordering::Acquire:
867 case NVPTX::Ordering::Release:
868 case NVPTX::Ordering::AcquireRelease:
869 case NVPTX::Ordering::SequentiallyConsistent:
870 auto S = Scopes[
N->getSyncScopeID()];
875 return N->isVolatile() ? NVPTX::Scope::System : S;
893 if (!
T->hasSplitAcquireAndReleaseFences() &&
901 return T->hasMemoryOrdering() ? NVPTX::atomic_thread_fence_acquire_sys
902 : NVPTX::INT_MEMBAR_SYS;
904 return T->hasMemoryOrdering() ? NVPTX::atomic_thread_fence_acquire_cta
905 : NVPTX::INT_MEMBAR_CTA;
907 return NVPTX::atomic_thread_fence_acquire_cluster;
909 return T->hasMemoryOrdering() ? NVPTX::atomic_thread_fence_acquire_gpu
910 : NVPTX::INT_MEMBAR_GL;
914 formatv(
"Unsupported scope \"{}\" for acquire/release/acq_rel fence.",
921 return T->hasMemoryOrdering() ? NVPTX::atomic_thread_fence_release_sys
922 : NVPTX::INT_MEMBAR_SYS;
924 return T->hasMemoryOrdering() ? NVPTX::atomic_thread_fence_release_cta
925 : NVPTX::INT_MEMBAR_CTA;
927 return NVPTX::atomic_thread_fence_release_cluster;
929 return T->hasMemoryOrdering() ? NVPTX::atomic_thread_fence_release_gpu
930 : NVPTX::INT_MEMBAR_GL;
934 formatv(
"Unsupported scope \"{}\" for acquire/release/acq_rel fence.",
941 return T->hasMemoryOrdering() ? NVPTX::atomic_thread_fence_acq_rel_sys
942 : NVPTX::INT_MEMBAR_SYS;
944 return T->hasMemoryOrdering() ? NVPTX::atomic_thread_fence_acq_rel_cta
945 : NVPTX::INT_MEMBAR_CTA;
947 return NVPTX::atomic_thread_fence_acq_rel_cluster;
949 return T->hasMemoryOrdering() ? NVPTX::atomic_thread_fence_acq_rel_gpu
950 : NVPTX::INT_MEMBAR_GL;
954 formatv(
"Unsupported scope \"{}\" for acquire/release/acq_rel fence.",
962 return T->hasMemoryOrdering() ? NVPTX::atomic_thread_fence_seq_cst_sys
963 : NVPTX::INT_MEMBAR_SYS;
965 return T->hasMemoryOrdering() ? NVPTX::atomic_thread_fence_seq_cst_cta
966 : NVPTX::INT_MEMBAR_CTA;
968 return NVPTX::atomic_thread_fence_seq_cst_cluster;
970 return T->hasMemoryOrdering() ? NVPTX::atomic_thread_fence_seq_cst_gpu
971 : NVPTX::INT_MEMBAR_GL;
984 formatv(
"Unsupported \"{}\" ordering and \"{}\" scope for fence.",
985 OrderingToString(O), ScopeToString(S)));
993std::pair<NVPTX::Ordering, NVPTX::Scope>
994NVPTXDAGToDAGISel::insertMemoryInstructionFence(SDLoc
DL,
SDValue &Chain,
996 auto [InstructionOrdering, FenceOrdering] =
997 getOperationOrderings(
N, Subtarget);
998 auto Scope = getOperationScope(
N, InstructionOrdering);
1004 if (Scope == NVPTX::Scope::Thread &&
1005 InstructionOrdering != NVPTX::Ordering::NotAtomic &&
1006 InstructionOrdering != NVPTX::Ordering::Volatile)
1007 return {NVPTX::Ordering::NotAtomic,
Scope};
1010 switch (NVPTX::Ordering(FenceOrdering)) {
1011 case NVPTX::Ordering::NotAtomic:
1013 case NVPTX::Ordering::SequentiallyConsistent: {
1015 Chain =
SDValue(CurDAG->getMachineNode(
Op,
DL, MVT::Other, Chain), 0);
1020 formatv(
"Unexpected fence ordering: \"{}\".",
1023 return {InstructionOrdering,
Scope};
1028static std::optional<unsigned>
1030 std::optional<unsigned> Opcode_i32,
1031 std::optional<unsigned> Opcode_i64) {
1050 return std::nullopt;
1055 return V.getOpcode() ==
ISD::ADD ||
1056 (V->getOpcode() ==
ISD::OR && V->getFlags().hasDisjoint());
1061 N =
N.getOperand(0);
1071 GA->getValueType(0), GA->getOffset(),
1072 GA->getTargetFlags());
1075 ES->getTargetFlags());
1084 APInt AccumulatedOffset(64u, 0);
1090 const APInt CI = CN->getAPIntValue().
sext(64);
1091 if (!(CI + AccumulatedOffset).isSignedIntN(32))
1094 AccumulatedOffset += CI;
1120bool NVPTXDAGToDAGISel::tryLoad(SDNode *
N) {
1122 assert(
LD->readMem() &&
"Expected load");
1126 if (PlainLoad && PlainLoad->
isIndexed())
1130 const auto CodeAddrSpace = getAddrSpace(LD);
1136 const auto [
Ordering,
Scope] = insertMemoryInstructionFence(
DL, Chain, LD);
1138 const unsigned FromTypeWidth =
LD->getMemoryVT().getSizeInBits();
1146 uint32_t UsedBytesMask;
1147 switch (
N->getOpcode()) {
1150 UsedBytesMask = UINT32_MAX;
1153 UsedBytesMask =
N->getConstantOperandVal(3);
1160 FromTypeWidth <= 128 &&
"Invalid width for load");
1165 getI32Imm(Scope,
DL),
1166 getI32Imm(CodeAddrSpace,
DL),
1167 getI32Imm(FromType,
DL),
1168 getI32Imm(FromTypeWidth,
DL),
1169 getI32Imm(UsedBytesMask,
DL),
1175 const std::optional<unsigned> Opcode =
1176 pickOpcodeForVT(TargetVT, NVPTX::LD_i16, NVPTX::LD_i32, NVPTX::LD_i64);
1180 SDNode *NVPTXLD = CurDAG->getMachineNode(*Opcode,
DL,
LD->getVTList(),
Ops);
1184 MachineMemOperand *MemRef =
LD->getMemOperand();
1187 ReplaceNode(LD, NVPTXLD);
1192 switch (
N->getOpcode()) {
1204bool NVPTXDAGToDAGISel::tryLoadVector(SDNode *
N) {
1208 const auto CodeAddrSpace = getAddrSpace(LD);
1212 const MVT EltVT =
LD->getSimpleValueType(0);
1215 const auto [
Ordering,
Scope] = insertMemoryInstructionFence(
DL, Chain, LD);
1225 const unsigned ExtensionType =
N->getConstantOperandVal(4);
1228 : NVPTX::PTXLdStInstCode::
Untyped;
1231 const uint32_t UsedBytesMask =
N->getConstantOperandVal(3);
1237 getI32Imm(Scope,
DL),
1238 getI32Imm(CodeAddrSpace,
DL),
1239 getI32Imm(FromType,
DL),
1240 getI32Imm(FromTypeWidth,
DL),
1241 getI32Imm(UsedBytesMask,
DL),
1246 std::optional<unsigned> Opcode;
1247 switch (
N->getOpcode()) {
1252 NVPTX::LDV_i32_v2, NVPTX::LDV_i64_v2);
1256 NVPTX::LDV_i32_v4, NVPTX::LDV_i64_v4);
1260 NVPTX::LDV_i32_v8, {});
1266 SDNode *NVPTXLD = CurDAG->getMachineNode(*Opcode,
DL,
LD->getVTList(),
Ops);
1268 MachineMemOperand *MemRef =
LD->getMemOperand();
1271 ReplaceNode(LD, NVPTXLD);
1275bool NVPTXDAGToDAGISel::tryLDG(MemSDNode *LD) {
1278 unsigned ExtensionType;
1279 uint32_t UsedBytesMask;
1281 ExtensionType =
Load->getExtensionType();
1282 UsedBytesMask = UINT32_MAX;
1284 ExtensionType =
LD->getConstantOperandVal(4);
1285 UsedBytesMask =
LD->getConstantOperandVal(3);
1289 : NVPTX::PTXLdStInstCode::
Untyped;
1293 assert(!(
LD->getSimpleValueType(0).isVector() &&
1298 getI32Imm(FromTypeWidth,
DL),
1299 getI32Imm(UsedBytesMask,
DL),
1305 std::optional<unsigned> Opcode;
1306 switch (
LD->getOpcode()) {
1311 NVPTX::LD_GLOBAL_NC_i32, NVPTX::LD_GLOBAL_NC_i64);
1314 Opcode =
pickOpcodeForVT(TargetVT, std::nullopt, NVPTX::LD_GLOBAL_NC_i32,
1315 NVPTX::LD_GLOBAL_NC_i64);
1320 NVPTX::LD_GLOBAL_NC_v2i32, NVPTX::LD_GLOBAL_NC_v2i64);
1325 NVPTX::LD_GLOBAL_NC_v4i32, NVPTX::LD_GLOBAL_NC_v4i64);
1329 NVPTX::LD_GLOBAL_NC_v8i32, {});
1335 SDNode *NVPTXLDG = CurDAG->getMachineNode(*Opcode,
DL,
LD->getVTList(),
Ops);
1337 ReplaceNode(LD, NVPTXLDG);
1341bool NVPTXDAGToDAGISel::tryLDU(SDNode *
N) {
1356 std::optional<unsigned> Opcode;
1357 switch (
N->getOpcode()) {
1362 NVPTX::LDU_GLOBAL_i32, NVPTX::LDU_GLOBAL_i64);
1366 NVPTX::LDU_GLOBAL_v2i32, NVPTX::LDU_GLOBAL_v2i64);
1370 NVPTX::LDU_GLOBAL_v4i32, {});
1376 SDNode *NVPTXLDU = CurDAG->getMachineNode(*Opcode,
DL,
LD->getVTList(),
Ops);
1378 ReplaceNode(LD, NVPTXLDU);
1382bool NVPTXDAGToDAGISel::tryStore(SDNode *
N) {
1384 assert(
ST->writeMem() &&
"Expected store");
1387 assert((PlainStore || AtomicStore) &&
"Expected store");
1390 if (PlainStore && PlainStore->
isIndexed())
1394 const auto CodeAddrSpace = getAddrSpace(ST);
1398 const auto [
Ordering,
Scope] = insertMemoryInstructionFence(
DL, Chain, ST);
1401 const unsigned ToTypeWidth =
ST->getMemoryVT().getSizeInBits();
1407 "Invalid width for store");
1411 getI32Imm(Ordering,
DL),
1412 getI32Imm(Scope,
DL),
1413 getI32Imm(CodeAddrSpace,
DL),
1414 getI32Imm(ToTypeWidth,
DL),
1419 const std::optional<unsigned> Opcode =
1421 NVPTX::ST_i32, NVPTX::ST_i64);
1425 SDNode *NVPTXST = CurDAG->getMachineNode(*Opcode,
DL, MVT::Other,
Ops);
1430 MachineMemOperand *MemRef =
ST->getMemOperand();
1432 ReplaceNode(ST, NVPTXST);
1436bool NVPTXDAGToDAGISel::tryStoreVector(SDNode *
N) {
1438 const unsigned TotalWidth =
ST->getMemoryVT().getSizeInBits();
1441 const auto CodeAddrSpace = getAddrSpace(ST);
1442 if (CodeAddrSpace == NVPTX::AddressSpace::Const) {
1449 const auto [
Ordering,
Scope] = insertMemoryInstructionFence(
DL, Chain, ST);
1454 for (
auto &V :
ST->ops().slice(1, NumElts))
1455 Ops.push_back(selectPossiblyImm(V));
1457 const unsigned ToTypeWidth = TotalWidth / NumElts;
1460 TotalWidth <= 256 &&
"Invalid width for store");
1463 Ops.append({getI32Imm(Ordering,
DL), getI32Imm(Scope,
DL),
1464 getI32Imm(CodeAddrSpace,
DL), getI32Imm(ToTypeWidth,
DL),
Base,
1468 ST->getOperand(1).getSimpleValueType().SimpleTy;
1469 std::optional<unsigned> Opcode;
1470 switch (
ST->getOpcode()) {
1490 SDNode *NVPTXST = CurDAG->getMachineNode(*Opcode,
DL, MVT::Other,
Ops);
1492 MachineMemOperand *MemRef =
ST->getMemOperand();
1495 ReplaceNode(ST, NVPTXST);
1501bool NVPTXDAGToDAGISel::tryBFE(SDNode *
N) {
1508 bool IsSigned =
false;
1524 uint64_t MaskVal =
Mask->getZExtValue();
1534 Len = CurDAG->getTargetConstant(NumBits,
DL, MVT::i32);
1538 Val =
LHS.getNode()->getOperand(0);
1539 Start =
LHS.getNode()->getOperand(1);
1545 int64_t GoodBits =
Start.getValueSizeInBits() - StartVal;
1546 if (NumBits > GoodBits) {
1552 Start = CurDAG->getTargetConstant(StartVal,
DL, MVT::i32);
1604 NumBits = NumZeros + NumOnes - ShiftAmt;
1610 if (ShiftAmt < NumZeros) {
1617 Start = CurDAG->getTargetConstant(ShiftAmt,
DL, MVT::i32);
1618 Len = CurDAG->getTargetConstant(NumBits,
DL, MVT::i32);
1634 Val =
LHS->getOperand(0);
1653 if (OuterShiftAmt < InnerShiftAmt) {
1664 Start = CurDAG->getTargetConstant(OuterShiftAmt - InnerShiftAmt,
DL,
1689 Opc = NVPTX::BFE_S32rii;
1691 Opc = NVPTX::BFE_U32rii;
1695 Opc = NVPTX::BFE_S64rii;
1697 Opc = NVPTX::BFE_U64rii;
1708 ReplaceNode(
N, CurDAG->getMachineNode(
Opc,
DL,
N->getVTList(),
Ops));
1713bool NVPTXDAGToDAGISel::tryBF16ArithToFMA(SDNode *
N) {
1714 EVT VT =
SDValue(
N, 0).getValueType();
1732 APF.convert(APFloat::BFloat(), APFloat::rmNearestTiesToEven, &LosesInfo);
1735 auto API = APF.bitcastToAPInt();
1736 API = API.concat(API);
1737 auto Const = CurDAG->getTargetConstant(API,
DL, MVT::i32);
1738 return SDValue(CurDAG->getMachineNode(NVPTX::MOV_B32_i,
DL, VT, Const),
1741 auto Const = CurDAG->getTargetConstantFP(APF,
DL, VT);
1742 return SDValue(CurDAG->getMachineNode(NVPTX::MOV_BF16_i,
DL, VT, Const), 0);
1745 switch (
N->getOpcode()) {
1748 Operands = {N0, GetConstant(1.0), N1};
1752 Operands = {N1, GetConstant(-1.0), N0};
1757 Operands = {N0, N1, GetConstant(-0.0)};
1763 int Opcode = IsVec ? NVPTX::FMA_BF16x2rrr : NVPTX::FMA_BF16rrr;
1764 MachineSDNode *
FMA = CurDAG->getMachineNode(Opcode,
DL, VT, Operands);
1765 ReplaceNode(
N, FMA);
1771 V =
V.getOperand(0);
1774 return CurDAG->getTargetConstant(CN->getAPIntValue(), SDLoc(V),
1777 return CurDAG->getTargetConstantFP(CN->getValueAPF(), SDLoc(V),
1784bool NVPTXDAGToDAGISel::SelectInlineAsmMemoryOperand(
1786 std::vector<SDValue> &OutOps) {
1787 switch (ConstraintID) {
1790 case InlineAsm::ConstraintCode::m: {
1792 OutOps.push_back(
Base);
1793 OutOps.push_back(
Offset);
1800void NVPTXDAGToDAGISel::SelectV2I64toI128(SDNode *
N) {
1816 CurDAG->getMachineNode(NVPTX::V2I64toI128,
DL, MVT::i128, {
Lo,
Hi});
1819 NewOps[0] =
N->getOperand(0);
1822 if (
N->getNumOperands() == 5)
1823 NewOps[3] =
N->getOperand(4);
1826 ReplaceNode(
N, NewValue.
getNode());
1829void NVPTXDAGToDAGISel::SelectI128toV2I64(SDNode *
N) {
1846 SDNode *Mov = CurDAG->getMachineNode(
1847 NVPTX::I128toV2I64,
DL,
1851 ReplaceNode(
N, Mov);
1854bool NVPTXDAGToDAGISel::tryFence(SDNode *
N) {
1857 auto Scope = Scopes[
N->getConstantOperandVal(2)];
1862 if (Scope == NVPTX::Scope::Thread) {
1863 CurDAG->ReplaceAllUsesOfValueWith(
SDValue(
N, 0),
N->getOperand(0));
1864 CurDAG->RemoveDeadNode(
N);
1869 NVPTX::Ordering(
N->getConstantOperandVal(1)), Scope, Subtarget);
1871 SDNode *FenceNode = CurDAG->getMachineNode(FenceOp,
DL, MVT::Other, Chain);
1872 ReplaceNode(
N, FenceNode);
1876NVPTXScopes::NVPTXScopes(LLVMContext &
C) :
Context(&
C) {
1887 "NVPTXScopes::operator[]");
1889 auto S = Scopes.find(ID);
1890 if (S == Scopes.end()) {
1891 auto scopeName =
Context->getSyncScopeName(ID);
1892 assert(scopeName.has_value() &&
"Scope name must exist.");
1896 for (
const auto &Entry : Scopes) {
1902 formatv(
"NVPTX backend does not support syncscope \"{0}\" (ID={1}).\n"
1903 "Supported syncscopes are: {2}.",
1904 scopeName.value(),
int(ID),
1910bool NVPTXScopes::empty()
const {
return Scopes.size() == 0; }
1912#define CP_ASYNC_BULK_TENSOR_OPCODE(dir, dim, mode, is_s32, suffix) \
1914 ? NVPTX::CP_ASYNC_BULK_TENSOR_##dir##_##dim##_SHARED32_##mode##suffix \
1915 : NVPTX::CP_ASYNC_BULK_TENSOR_##dir##_##dim##_##mode##suffix)
1917#define GET_CP_ASYNC_BULK_TENSOR_OPCODE_S2G_RED(dim, mode, is_ch, is_s32) \
1918 (is_ch ? (CP_ASYNC_BULK_TENSOR_OPCODE(RED, dim, mode, is_s32, _CH)) \
1919 : (CP_ASYNC_BULK_TENSOR_OPCODE(RED, dim, mode, is_s32, )))
1938 "GetCpAsyncBulkTensorS2GReductionOpcode.");
1959 "GetCpAsyncBulkTensorS2GReductionOpcode.");
1964void NVPTXDAGToDAGISel::SelectCpAsyncBulkTensorReduceCommon(SDNode *
N,
1971 size_t NumOps =
N->getNumOperands();
1972 size_t NumDims =
NumOps - 6;
1973 bool IsCacheHint =
N->getConstantOperandVal(
NumOps - 1) == 1;
1974 size_t NumArgs = NumDims + (IsCacheHint ? 3 : 2);
1978 Ops.push_back(getI32Imm(RedOp,
DL));
1979 Ops.push_back(
N->getOperand(0));
1984 NumDims, IsShared32, IsCacheHint, IsIm2Col);
1985 ReplaceNode(
N, CurDAG->getMachineNode(Opcode,
DL,
N->getVTList(),
Ops));
1988#define TCGEN05_ST_OPCODE(SHAPE, NUM) \
1989 (enableUnpack ? NVPTX::TCGEN05_ST_##SHAPE##_##NUM##_UNPACK \
1990 : NVPTX::TCGEN05_ST_##SHAPE##_##NUM)
1994 case Intrinsic::nvvm_tcgen05_st_16x64b_x1:
1996 case Intrinsic::nvvm_tcgen05_st_16x64b_x2:
1998 case Intrinsic::nvvm_tcgen05_st_16x64b_x4:
2000 case Intrinsic::nvvm_tcgen05_st_16x64b_x8:
2002 case Intrinsic::nvvm_tcgen05_st_16x64b_x16:
2004 case Intrinsic::nvvm_tcgen05_st_16x64b_x32:
2006 case Intrinsic::nvvm_tcgen05_st_16x64b_x64:
2008 case Intrinsic::nvvm_tcgen05_st_16x64b_x128:
2010 case Intrinsic::nvvm_tcgen05_st_16x128b_x1:
2012 case Intrinsic::nvvm_tcgen05_st_16x128b_x2:
2014 case Intrinsic::nvvm_tcgen05_st_16x128b_x4:
2016 case Intrinsic::nvvm_tcgen05_st_16x128b_x8:
2018 case Intrinsic::nvvm_tcgen05_st_16x128b_x16:
2020 case Intrinsic::nvvm_tcgen05_st_16x128b_x32:
2022 case Intrinsic::nvvm_tcgen05_st_16x128b_x64:
2024 case Intrinsic::nvvm_tcgen05_st_16x256b_x1:
2026 case Intrinsic::nvvm_tcgen05_st_16x256b_x2:
2028 case Intrinsic::nvvm_tcgen05_st_16x256b_x4:
2030 case Intrinsic::nvvm_tcgen05_st_16x256b_x8:
2032 case Intrinsic::nvvm_tcgen05_st_16x256b_x16:
2034 case Intrinsic::nvvm_tcgen05_st_16x256b_x32:
2036 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x1:
2038 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x2:
2040 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x4:
2042 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x8:
2044 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x16:
2046 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x32:
2048 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x64:
2050 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x128:
2052 case Intrinsic::nvvm_tcgen05_st_32x32b_x1:
2054 case Intrinsic::nvvm_tcgen05_st_32x32b_x2:
2056 case Intrinsic::nvvm_tcgen05_st_32x32b_x4:
2058 case Intrinsic::nvvm_tcgen05_st_32x32b_x8:
2060 case Intrinsic::nvvm_tcgen05_st_32x32b_x16:
2062 case Intrinsic::nvvm_tcgen05_st_32x32b_x32:
2064 case Intrinsic::nvvm_tcgen05_st_32x32b_x64:
2066 case Intrinsic::nvvm_tcgen05_st_32x32b_x128:
2072void NVPTXDAGToDAGISel::SelectTcgen05St(SDNode *
N,
bool hasOffset) {
2075 "tcgen05.st is not supported on this architecture variant");
2085 Operands.
push_back(CurDAG->getTargetConstant(
2089 for (
unsigned I = hasOffset ? 4 : 3;
I < (
N->getNumOperands() - 1);
I++)
2098 DL,
N->getVTList(), Operands));
2101bool NVPTXDAGToDAGISel::tryIntrinsicVoid(SDNode *
N) {
2102 unsigned IID =
N->getConstantOperandVal(1);
2104 auto CastTy = [](TMARedTy
Op) {
return static_cast<unsigned>(
Op); };
2108 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_add_tile_1d:
2109 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_add_tile_2d:
2110 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_add_tile_3d:
2111 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_add_tile_4d:
2112 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_add_tile_5d:
2113 SelectCpAsyncBulkTensorReduceCommon(
N, CastTy(TMARedTy::ADD));
2115 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_add_im2col_3d:
2116 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_add_im2col_4d:
2117 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_add_im2col_5d:
2118 SelectCpAsyncBulkTensorReduceCommon(
N, CastTy(TMARedTy::ADD),
2121 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_min_tile_1d:
2122 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_min_tile_2d:
2123 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_min_tile_3d:
2124 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_min_tile_4d:
2125 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_min_tile_5d:
2126 SelectCpAsyncBulkTensorReduceCommon(
N, CastTy(TMARedTy::MIN));
2128 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_min_im2col_3d:
2129 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_min_im2col_4d:
2130 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_min_im2col_5d:
2131 SelectCpAsyncBulkTensorReduceCommon(
N, CastTy(TMARedTy::MIN),
2134 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_max_tile_1d:
2135 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_max_tile_2d:
2136 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_max_tile_3d:
2137 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_max_tile_4d:
2138 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_max_tile_5d:
2139 SelectCpAsyncBulkTensorReduceCommon(
N, CastTy(TMARedTy::MAX));
2141 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_max_im2col_3d:
2142 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_max_im2col_4d:
2143 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_max_im2col_5d:
2144 SelectCpAsyncBulkTensorReduceCommon(
N, CastTy(TMARedTy::MAX),
2147 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_inc_tile_1d:
2148 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_inc_tile_2d:
2149 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_inc_tile_3d:
2150 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_inc_tile_4d:
2151 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_inc_tile_5d:
2152 SelectCpAsyncBulkTensorReduceCommon(
N, CastTy(TMARedTy::INC));
2154 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_inc_im2col_3d:
2155 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_inc_im2col_4d:
2156 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_inc_im2col_5d:
2157 SelectCpAsyncBulkTensorReduceCommon(
N, CastTy(TMARedTy::INC),
2160 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_dec_tile_1d:
2161 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_dec_tile_2d:
2162 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_dec_tile_3d:
2163 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_dec_tile_4d:
2164 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_dec_tile_5d:
2165 SelectCpAsyncBulkTensorReduceCommon(
N, CastTy(TMARedTy::DEC));
2167 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_dec_im2col_3d:
2168 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_dec_im2col_4d:
2169 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_dec_im2col_5d:
2170 SelectCpAsyncBulkTensorReduceCommon(
N, CastTy(TMARedTy::DEC),
2173 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_and_tile_1d:
2174 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_and_tile_2d:
2175 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_and_tile_3d:
2176 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_and_tile_4d:
2177 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_and_tile_5d:
2178 SelectCpAsyncBulkTensorReduceCommon(
N, CastTy(TMARedTy::AND));
2180 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_and_im2col_3d:
2181 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_and_im2col_4d:
2182 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_and_im2col_5d:
2183 SelectCpAsyncBulkTensorReduceCommon(
N, CastTy(TMARedTy::AND),
2186 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_or_tile_1d:
2187 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_or_tile_2d:
2188 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_or_tile_3d:
2189 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_or_tile_4d:
2190 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_or_tile_5d:
2191 SelectCpAsyncBulkTensorReduceCommon(
N, CastTy(TMARedTy::OR));
2193 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_or_im2col_3d:
2194 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_or_im2col_4d:
2195 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_or_im2col_5d:
2196 SelectCpAsyncBulkTensorReduceCommon(
N, CastTy(TMARedTy::OR),
2199 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_xor_tile_1d:
2200 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_xor_tile_2d:
2201 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_xor_tile_3d:
2202 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_xor_tile_4d:
2203 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_xor_tile_5d:
2204 SelectCpAsyncBulkTensorReduceCommon(
N, CastTy(TMARedTy::XOR));
2206 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_xor_im2col_3d:
2207 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_xor_im2col_4d:
2208 case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_xor_im2col_5d:
2209 SelectCpAsyncBulkTensorReduceCommon(
N, CastTy(TMARedTy::XOR),
2213 case Intrinsic::nvvm_tcgen05_st_16x64b_x1:
2214 case Intrinsic::nvvm_tcgen05_st_16x64b_x2:
2215 case Intrinsic::nvvm_tcgen05_st_16x64b_x4:
2216 case Intrinsic::nvvm_tcgen05_st_16x64b_x8:
2217 case Intrinsic::nvvm_tcgen05_st_16x64b_x16:
2218 case Intrinsic::nvvm_tcgen05_st_16x64b_x32:
2219 case Intrinsic::nvvm_tcgen05_st_16x64b_x64:
2220 case Intrinsic::nvvm_tcgen05_st_16x64b_x128:
2221 case Intrinsic::nvvm_tcgen05_st_32x32b_x1:
2222 case Intrinsic::nvvm_tcgen05_st_32x32b_x2:
2223 case Intrinsic::nvvm_tcgen05_st_32x32b_x4:
2224 case Intrinsic::nvvm_tcgen05_st_32x32b_x8:
2225 case Intrinsic::nvvm_tcgen05_st_32x32b_x16:
2226 case Intrinsic::nvvm_tcgen05_st_32x32b_x32:
2227 case Intrinsic::nvvm_tcgen05_st_32x32b_x64:
2228 case Intrinsic::nvvm_tcgen05_st_32x32b_x128:
2229 case Intrinsic::nvvm_tcgen05_st_16x128b_x1:
2230 case Intrinsic::nvvm_tcgen05_st_16x128b_x2:
2231 case Intrinsic::nvvm_tcgen05_st_16x128b_x4:
2232 case Intrinsic::nvvm_tcgen05_st_16x128b_x8:
2233 case Intrinsic::nvvm_tcgen05_st_16x128b_x16:
2234 case Intrinsic::nvvm_tcgen05_st_16x128b_x32:
2235 case Intrinsic::nvvm_tcgen05_st_16x128b_x64:
2236 case Intrinsic::nvvm_tcgen05_st_16x256b_x1:
2237 case Intrinsic::nvvm_tcgen05_st_16x256b_x2:
2238 case Intrinsic::nvvm_tcgen05_st_16x256b_x4:
2239 case Intrinsic::nvvm_tcgen05_st_16x256b_x8:
2240 case Intrinsic::nvvm_tcgen05_st_16x256b_x16:
2241 case Intrinsic::nvvm_tcgen05_st_16x256b_x32: {
2246 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x1:
2247 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x2:
2248 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x4:
2249 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x8:
2250 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x16:
2251 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x32:
2252 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x64:
2253 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x128: {
2254 SelectTcgen05St(
N,
true);
2260void NVPTXDAGToDAGISel::selectAtomicSwap128(SDNode *
N) {
2267 Ops.append(
N->op_begin() + 2,
N->op_end());
2269 getI32Imm(getMemOrder(AN), dl),
2270 getI32Imm(getAtomicScope(AN), dl),
2271 getI32Imm(getAddrSpace(AN), dl),
2278 ? NVPTX::ATOM_EXCH_B128
2279 : NVPTX::ATOM_CAS_B128;
2281 auto *ATOM = CurDAG->getMachineNode(Opcode, dl,
N->getVTList(),
Ops);
2284 ReplaceNode(
N, ATOM);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
AMDGPU Register Bank Select
This file implements a class to represent arbitrary precision integral constant values and operations...
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Atomic ordering constants.
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
const size_t AbstractManglingParser< Derived, Alloc >::NumOps
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
This file implements a map that provides insertion order iteration.
static NVPTX::Scope resolveScope(NVPTX::Scope S, const NVPTXSubtarget *T)
static unsigned getStoreVectorNumElts(SDNode *N)
static bool isAddLike(const SDValue V)
static SDValue selectBaseADDR(SDValue N, SelectionDAG *DAG)
static SDValue accumulateOffset(SDValue &Addr, SDLoc DL, SelectionDAG *DAG)
static unsigned getTcgen05StOpcode(unsigned IID, bool enableUnpack)
static std::optional< unsigned > pickOpcodeForVT(MVT::SimpleValueType VT, std::optional< unsigned > Opcode_i16, std::optional< unsigned > Opcode_i32, std::optional< unsigned > Opcode_i64)
static cl::opt< bool > EnableMADWide("nvptx-mad-wide-opt", cl::init(false), cl::Hidden, cl::desc("Enable MAD wide optimization"))
static unsigned GetCpAsyncBulkTensorS2GReductionOpcode(size_t Dim, bool IsShared32, bool IsCacheHint, bool IsIm2Col)
#define TCGEN05_LD_OPCODE(SHAPE, NUM)
static SDValue stripAssertAlign(SDValue N)
static cl::opt< bool > EnableRsqrtOpt("nvptx-rsqrt-approx-opt", cl::init(true), cl::Hidden, cl::desc("Enable reciprocal sqrt optimization"))
static unsigned int getFenceOp(NVPTX::Ordering O, NVPTX::Scope S, NVPTXSubtarget const *T)
#define GET_CP_ASYNC_BULK_TENSOR_OPCODE_S2G_RED(dim, mode, is_ch, is_s32)
#define TCGEN05_ST_OPCODE(SHAPE, NUM)
static std::pair< SDValue, SDValue > selectADDR(SDValue Addr, SelectionDAG *DAG)
static unsigned getTcgen05LdOpcode(unsigned IID, bool enablePack)
static bool canLowerToLDG(const MemSDNode &N, const NVPTXSubtarget &Subtarget, NVPTX::AddressSpace CodeAddrSpace)
This file contains the definitions of the enumerations and flags associated with NVVM Intrinsics,...
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Class for arbitrary precision integers.
LLVM_ABI APInt sext(unsigned width) const
Sign extend to a new width.
int64_t getSExtValue() const
Get sign extended value.
const SDValue & getVal() const
uint64_t getZExtValue() const
FunctionPass class - This class is used to implement most global optimizations.
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
This is an important class for using LLVM in a threaded context.
bool isIndexed() const
Return true if this is a pre/post inc/dec load/store.
ISD::LoadExtType getExtensionType() const
Return whether this is a plain node, or one of the varieties of value-extending loads.
unsigned getVectorNumElements() const
bool isVector() const
Return true if this is a vector value type.
bool is32BitVector() const
Return true if this is a 32-bit vector type.
MVT getVectorElementType() const
bool is64BitVector() const
Return true if this is a 64-bit vector type.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
Function & getFunction()
Return the LLVM function that this machine code represents.
This is an abstract virtual class for memory operations.
MachineMemOperand * getMemOperand() const
Return the unique MachineMemOperand object describing the memory reference performed by operation.
bool hasTcgen05InstSupport() const
bool hasNativeBF16Support(unsigned Opcode) const
const NVPTXTargetLowering * getTargetLowering() const override
bool hasRelaxedMMIO() const
bool hasAtomScope() const
bool hasMemoryOrdering() const
bool useF32FTZ(const MachineFunction &MF) const
NVPTX::DivPrecisionLevel getDivF32Level(const MachineFunction &MF, const SDNode &N) const
bool allowFMA(MachineFunction &MF, CodeGenOptLevel OptLevel) const
bool usePrecSqrtF32(const SDNode *N=nullptr) const
const NVPTXSubtarget * getSubtargetImpl(const Function &) const override
Virtual method implemented by subclasses that returns a reference to that target's TargetSubtargetInf...
Wrapper class for IR location info (IR ordering and DebugLoc) to be passed into SDNode creation funct...
Represents one node in the SelectionDAG.
const SDValue & getOperand(unsigned Num) const
Unlike LLVM values, Selection DAG nodes may return multiple values as the result of a computation.
SDNode * getNode() const
get the SDNode which holds the desired result
EVT getValueType() const
Return the ValueType of the referenced return value.
TypeSize getValueSizeInBits() const
Returns the size of the value in bits.
const SDValue & getOperand(unsigned i) const
SelectionDAGISel - This is the common base class used for SelectionDAG-based pattern-matching instruc...
virtual bool runOnMachineFunction(MachineFunction &mf)
This is used to represent a portion of an LLVM function in a low-level Data Dependence DAG representa...
SDValue getTargetGlobalAddress(const GlobalValue *GV, const SDLoc &DL, EVT VT, int64_t offset=0, unsigned TargetFlags=0)
SDValue getTargetFrameIndex(int FI, EVT VT)
SDValue getSignedTargetConstant(int64_t Val, const SDLoc &DL, EVT VT, bool isOpaque=false)
LLVM_ABI SDValue getTargetExternalSymbol(const char *Sym, EVT VT, unsigned TargetFlags=0)
void push_back(const T &Elt)
const SDValue & getValue() const
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
@ ATOMIC_STORE
OUTCHAIN = ATOMIC_STORE(INCHAIN, val, ptr) This corresponds to "store atomic" instruction.
@ ADD
Simple integer binary arithmetic operators.
@ LOAD
LOAD and STORE have token chains as their first operand, then the same operands as an LLVM load/store...
@ FMA
FMA - Perform a * b + c with no intermediate rounding step.
@ INTRINSIC_VOID
OUTCHAIN = INTRINSIC_VOID(INCHAIN, INTRINSICID, arg1, arg2, ...) This node represents a target intrin...
@ FADD
Simple binary floating point operators.
@ ATOMIC_FENCE
OUTCHAIN = ATOMIC_FENCE(INCHAIN, ordering, scope) This corresponds to the fence instruction.
@ BITCAST
BITCAST - This operator converts between integer, vector and FP values, as if the value was stored to...
@ ATOMIC_LOAD
Val, OUTCHAIN = ATOMIC_LOAD(INCHAIN, ptr) This corresponds to "load atomic" instruction.
@ AssertAlign
AssertAlign - These nodes record if a register contains a value that has a known alignment and the tr...
@ CopyFromReg
CopyFromReg - This node indicates that the input value is a virtual or physical register that is defi...
@ SHL
Shift and rotation operations.
@ EXTRACT_VECTOR_ELT
EXTRACT_VECTOR_ELT(VECTOR, IDX) - Returns a single element from VECTOR identified by the (potentially...
@ CopyToReg
CopyToReg - This node has three operands: a chain, a register number to set to this value,...
@ AND
Bitwise operators - logical and, logical or, logical xor.
@ INTRINSIC_W_CHAIN
RESULT,OUTCHAIN = INTRINSIC_W_CHAIN(INCHAIN, INTRINSICID, arg1, ...) This node represents a target in...
CondCode
ISD::CondCode enum - These are ordered carefully to make the bitfields below work out,...
@ ATOMIC_CMP_SWAP_B128
These nodes are used to lower atomic instructions with i128 type.
std::string OrderingToString(Ordering Order)
initializer< Ty > init(const Ty &Val)
Scope
Defines the scope in which this symbol should be visible: Default – Visible in the public interface o...
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
int countr_one(T Value)
Count the number of ones from the least significant bit to the first zero bit.
@ Load
The value being inserted comes from a load (InsertElement only).
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
FunctionPass * createNVPTXISelDag(NVPTXTargetMachine &TM, llvm::CodeGenOptLevel OptLevel)
createNVPTXISelDag - This pass converts a legalized DAG into a NVPTX-specific DAG,...
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
int countr_zero(T Val)
Count number of 0's from the least significant bit to the most stopping at the first 1.
constexpr bool isShiftedMask_64(uint64_t Value)
Return true if the argument contains a non-empty sequence of ones with the remainder zero (64 bit ver...
const char * toIRString(AtomicOrdering ao)
String used by LLVM IR to represent atomic ordering.
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
constexpr bool isMask_64(uint64_t Value)
Return true if the argument is a non-empty sequence of ones starting at the least significant bit wit...
CodeGenOptLevel
Code generation optimization level.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
AtomicOrdering
Atomic ordering for LLVM's memory model.
DWARFExpression::Operation Op
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
unsigned getFromTypeWidthForLoad(const MemSDNode *Mem)
The bit-width of a single element loaded by Mem, i.e.
LLVM_ABI void reportFatalUsageError(Error Err)
Report a fatal error that does not indicate a bug in LLVM.
Implement std::hash so that hash_code can be used in STL containers.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
bool isVector() const
Return true if this is a vector value type.
EVT getScalarType() const
If this is a vector type, return the element type, otherwise return this.
unsigned getVectorNumElements() const
Given a vector type, return the number of elements it contains.
A MapVector that performs no allocations if smaller than a certain size.