brintos

brintos / llvm-project-archived public Read only

0
0
Text · 83.7 KiB · 0e1125a Raw
2276 lines · cpp
1//===-- NVPTXISelDAGToDAG.cpp - A dag to dag inst selector for NVPTX ------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file defines an instruction selector for the NVPTX target.10//11//===----------------------------------------------------------------------===//12 13#include "NVPTXISelDAGToDAG.h"14#include "NVPTX.h"15#include "NVPTXUtilities.h"16#include "llvm/ADT/APInt.h"17#include "llvm/Analysis/ValueTracking.h"18#include "llvm/CodeGen/ISDOpcodes.h"19#include "llvm/CodeGen/SelectionDAG.h"20#include "llvm/CodeGen/SelectionDAGNodes.h"21#include "llvm/IR/GlobalValue.h"22#include "llvm/IR/Instructions.h"23#include "llvm/IR/IntrinsicsNVPTX.h"24#include "llvm/IR/NVVMIntrinsicUtils.h"25#include "llvm/Support/AtomicOrdering.h"26#include "llvm/Support/CommandLine.h"27#include "llvm/Support/ErrorHandling.h"28#include "llvm/Support/FormatVariadic.h"29#include "llvm/Support/MathExtras.h"30#include <optional>31 32using namespace llvm;33 34#define DEBUG_TYPE "nvptx-isel"35#define PASS_NAME "NVPTX DAG->DAG Pattern Instruction Selection"36 37static cl::opt<bool>38    EnableRsqrtOpt("nvptx-rsqrt-approx-opt", cl::init(true), cl::Hidden,39                   cl::desc("Enable reciprocal sqrt optimization"));40 41// FIXME: This is a WAR to recover lost performance from #155024.42// We still need to investigate the regression and find a more permanent43// solution.44static cl::opt<bool> EnableMADWide("nvptx-mad-wide-opt", cl::init(false),45                                   cl::Hidden,46                                   cl::desc("Enable MAD wide optimization"));47 48/// createNVPTXISelDag - This pass converts a legalized DAG into a49/// NVPTX-specific DAG, ready for instruction scheduling.50FunctionPass *llvm::createNVPTXISelDag(NVPTXTargetMachine &TM,51                                       llvm::CodeGenOptLevel OptLevel) {52  return new NVPTXDAGToDAGISelLegacy(TM, OptLevel);53}54 55NVPTXDAGToDAGISelLegacy::NVPTXDAGToDAGISelLegacy(NVPTXTargetMachine &tm,56                                                 CodeGenOptLevel OptLevel)57    : SelectionDAGISelLegacy(58          ID, std::make_unique<NVPTXDAGToDAGISel>(tm, OptLevel)) {}59 60char NVPTXDAGToDAGISelLegacy::ID = 0;61 62INITIALIZE_PASS(NVPTXDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false)63 64NVPTXDAGToDAGISel::NVPTXDAGToDAGISel(NVPTXTargetMachine &tm,65                                     CodeGenOptLevel OptLevel)66    : SelectionDAGISel(tm, OptLevel), TM(tm) {}67 68bool NVPTXDAGToDAGISel::runOnMachineFunction(MachineFunction &MF) {69  Subtarget = &MF.getSubtarget<NVPTXSubtarget>();70  Scopes = NVPTXScopes(MF.getFunction().getContext());71  return SelectionDAGISel::runOnMachineFunction(MF);72}73 74NVPTX::DivPrecisionLevel75NVPTXDAGToDAGISel::getDivF32Level(const SDNode *N) const {76  return Subtarget->getTargetLowering()->getDivF32Level(*MF, *N);77}78 79bool NVPTXDAGToDAGISel::usePrecSqrtF32(const SDNode *N) const {80  return Subtarget->getTargetLowering()->usePrecSqrtF32(N);81}82 83bool NVPTXDAGToDAGISel::useF32FTZ() const {84  return Subtarget->getTargetLowering()->useF32FTZ(*MF);85}86 87bool NVPTXDAGToDAGISel::allowFMA() const {88  const NVPTXTargetLowering *TL = Subtarget->getTargetLowering();89  return TL->allowFMA(*MF, OptLevel);90}91 92bool NVPTXDAGToDAGISel::doRsqrtOpt() const { return EnableRsqrtOpt; }93 94bool NVPTXDAGToDAGISel::doMADWideOpt() const { return EnableMADWide; }95 96/// Select - Select instructions not customized! Used for97/// expanded, promoted and normal instructions.98void NVPTXDAGToDAGISel::Select(SDNode *N) {99 100  if (N->isMachineOpcode()) {101    N->setNodeId(-1);102    return; // Already selected.103  }104 105  switch (N->getOpcode()) {106  case ISD::LOAD:107  case ISD::ATOMIC_LOAD:108  case NVPTXISD::MLoad:109    if (tryLoad(N))110      return;111    break;112  case ISD::STORE:113  case ISD::ATOMIC_STORE:114    if (tryStore(N))115      return;116    break;117  case ISD::ATOMIC_FENCE:118    if (tryFence(N))119      return;120    break;121  case NVPTXISD::UNPACK_VECTOR:122    tryUNPACK_VECTOR(N);123    return;124  case ISD::EXTRACT_VECTOR_ELT:125    if (tryEXTRACT_VECTOR_ELEMENT(N))126      return;127    break;128  case NVPTXISD::SETP_F16X2:129    SelectSETP_F16X2(N);130    return;131  case NVPTXISD::SETP_BF16X2:132    SelectSETP_BF16X2(N);133    return;134  case NVPTXISD::LoadV2:135  case NVPTXISD::LoadV4:136  case NVPTXISD::LoadV8:137    if (tryLoadVector(N))138      return;139    break;140  case NVPTXISD::LDUV2:141  case NVPTXISD::LDUV4:142    if (tryLDU(N))143      return;144    break;145  case NVPTXISD::StoreV2:146  case NVPTXISD::StoreV4:147  case NVPTXISD::StoreV8:148    if (tryStoreVector(N))149      return;150    break;151  case ISD::INTRINSIC_W_CHAIN:152    if (tryIntrinsicChain(N))153      return;154    break;155  case ISD::INTRINSIC_VOID:156    if (tryIntrinsicVoid(N))157      return;158    break;159  case ISD::AND:160  case ISD::SRA:161  case ISD::SRL:162    // Try to select BFE163    if (tryBFE(N))164      return;165    break;166  case ISD::ADDRSPACECAST:167    SelectAddrSpaceCast(N);168    return;169  case ISD::CopyToReg: {170    if (N->getOperand(1).getValueType() == MVT::i128) {171      SelectV2I64toI128(N);172      return;173    }174    break;175  }176  case ISD::CopyFromReg: {177    if (N->getOperand(1).getValueType() == MVT::i128) {178      SelectI128toV2I64(N);179      return;180    }181    break;182  }183  case NVPTXISD::ATOMIC_CMP_SWAP_B128:184  case NVPTXISD::ATOMIC_SWAP_B128:185    selectAtomicSwap128(N);186    return;187  case ISD::FADD:188  case ISD::FMUL:189  case ISD::FSUB:190    if (tryBF16ArithToFMA(N))191      return;192    break;193  default:194    break;195  }196  SelectCode(N);197}198 199#define TCGEN05_LD_OPCODE(SHAPE, NUM)                                          \200  (enablePack ? NVPTX::TCGEN05_LD_##SHAPE##_##NUM##_PACK                       \201              : NVPTX::TCGEN05_LD_##SHAPE##_##NUM)202 203static unsigned getTcgen05LdOpcode(unsigned IID, bool enablePack) {204  switch (IID) {205  case Intrinsic::nvvm_tcgen05_ld_16x64b_x1:206    return TCGEN05_LD_OPCODE(16x64b, x1);207  case Intrinsic::nvvm_tcgen05_ld_16x64b_x2:208    return TCGEN05_LD_OPCODE(16x64b, x2);209  case Intrinsic::nvvm_tcgen05_ld_16x64b_x4:210    return TCGEN05_LD_OPCODE(16x64b, x4);211  case Intrinsic::nvvm_tcgen05_ld_16x64b_x8:212    return TCGEN05_LD_OPCODE(16x64b, x8);213  case Intrinsic::nvvm_tcgen05_ld_16x64b_x16:214    return TCGEN05_LD_OPCODE(16x64b, x16);215  case Intrinsic::nvvm_tcgen05_ld_16x64b_x32:216    return TCGEN05_LD_OPCODE(16x64b, x32);217  case Intrinsic::nvvm_tcgen05_ld_16x64b_x64:218    return TCGEN05_LD_OPCODE(16x64b, x64);219  case Intrinsic::nvvm_tcgen05_ld_16x64b_x128:220    return TCGEN05_LD_OPCODE(16x64b, x128);221  case Intrinsic::nvvm_tcgen05_ld_16x128b_x1:222    return TCGEN05_LD_OPCODE(16x128b, x1);223  case Intrinsic::nvvm_tcgen05_ld_16x128b_x2:224    return TCGEN05_LD_OPCODE(16x128b, x2);225  case Intrinsic::nvvm_tcgen05_ld_16x128b_x4:226    return TCGEN05_LD_OPCODE(16x128b, x4);227  case Intrinsic::nvvm_tcgen05_ld_16x128b_x8:228    return TCGEN05_LD_OPCODE(16x128b, x8);229  case Intrinsic::nvvm_tcgen05_ld_16x128b_x16:230    return TCGEN05_LD_OPCODE(16x128b, x16);231  case Intrinsic::nvvm_tcgen05_ld_16x128b_x32:232    return TCGEN05_LD_OPCODE(16x128b, x32);233  case Intrinsic::nvvm_tcgen05_ld_16x128b_x64:234    return TCGEN05_LD_OPCODE(16x128b, x64);235  case Intrinsic::nvvm_tcgen05_ld_16x256b_x1:236    return TCGEN05_LD_OPCODE(16x256b, x1);237  case Intrinsic::nvvm_tcgen05_ld_16x256b_x2:238    return TCGEN05_LD_OPCODE(16x256b, x2);239  case Intrinsic::nvvm_tcgen05_ld_16x256b_x4:240    return TCGEN05_LD_OPCODE(16x256b, x4);241  case Intrinsic::nvvm_tcgen05_ld_16x256b_x8:242    return TCGEN05_LD_OPCODE(16x256b, x8);243  case Intrinsic::nvvm_tcgen05_ld_16x256b_x16:244    return TCGEN05_LD_OPCODE(16x256b, x16);245  case Intrinsic::nvvm_tcgen05_ld_16x256b_x32:246    return TCGEN05_LD_OPCODE(16x256b, x32);247  case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x1:248    return TCGEN05_LD_OPCODE(16x32bx2, x1);249  case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x2:250    return TCGEN05_LD_OPCODE(16x32bx2, x2);251  case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x4:252    return TCGEN05_LD_OPCODE(16x32bx2, x4);253  case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x8:254    return TCGEN05_LD_OPCODE(16x32bx2, x8);255  case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x16:256    return TCGEN05_LD_OPCODE(16x32bx2, x16);257  case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x32:258    return TCGEN05_LD_OPCODE(16x32bx2, x32);259  case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x64:260    return TCGEN05_LD_OPCODE(16x32bx2, x64);261  case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x128:262    return TCGEN05_LD_OPCODE(16x32bx2, x128);263  case Intrinsic::nvvm_tcgen05_ld_32x32b_x1:264    return TCGEN05_LD_OPCODE(32x32b, x1);265  case Intrinsic::nvvm_tcgen05_ld_32x32b_x2:266    return TCGEN05_LD_OPCODE(32x32b, x2);267  case Intrinsic::nvvm_tcgen05_ld_32x32b_x4:268    return TCGEN05_LD_OPCODE(32x32b, x4);269  case Intrinsic::nvvm_tcgen05_ld_32x32b_x8:270    return TCGEN05_LD_OPCODE(32x32b, x8);271  case Intrinsic::nvvm_tcgen05_ld_32x32b_x16:272    return TCGEN05_LD_OPCODE(32x32b, x16);273  case Intrinsic::nvvm_tcgen05_ld_32x32b_x32:274    return TCGEN05_LD_OPCODE(32x32b, x32);275  case Intrinsic::nvvm_tcgen05_ld_32x32b_x64:276    return TCGEN05_LD_OPCODE(32x32b, x64);277  case Intrinsic::nvvm_tcgen05_ld_32x32b_x128:278    return TCGEN05_LD_OPCODE(32x32b, x128);279  }280  llvm_unreachable("unhandled tcgen05.ld lowering");281}282 283void NVPTXDAGToDAGISel::SelectTcgen05Ld(SDNode *N, bool hasOffset) {284  if (!Subtarget->hasTcgen05InstSupport())285    report_fatal_error(286        "tcgen05.ld is not supported on this architecture variant");287 288  SDLoc DL(N);289  unsigned IID = cast<ConstantSDNode>(N->getOperand(1))->getZExtValue();290 291  if (hasOffset) {292    bool enablePack = cast<ConstantSDNode>(N->getOperand(4))->getZExtValue();293    auto OffsetNode = CurDAG->getTargetConstant(294        cast<ConstantSDNode>(N->getOperand(3))->getZExtValue(), DL, MVT::i32);295    ReplaceNode(N, CurDAG->getMachineNode(296                       getTcgen05LdOpcode(IID, enablePack), DL, N->getVTList(),297                       {N->getOperand(2), OffsetNode, N->getOperand(0)}));298  } else {299    bool enablePack = cast<ConstantSDNode>(N->getOperand(3))->getZExtValue();300    ReplaceNode(N, CurDAG->getMachineNode(301                       getTcgen05LdOpcode(IID, enablePack), DL, N->getVTList(),302                       {N->getOperand(2), N->getOperand(0)}));303  }304}305 306bool NVPTXDAGToDAGISel::tryIntrinsicChain(SDNode *N) {307  unsigned IID = N->getConstantOperandVal(1);308  switch (IID) {309  default:310    return false;311  case Intrinsic::nvvm_ldu_global_f:312  case Intrinsic::nvvm_ldu_global_i:313  case Intrinsic::nvvm_ldu_global_p:314    return tryLDU(N);315 316  case Intrinsic::nvvm_tcgen05_ld_16x64b_x1:317  case Intrinsic::nvvm_tcgen05_ld_16x64b_x2:318  case Intrinsic::nvvm_tcgen05_ld_16x64b_x4:319  case Intrinsic::nvvm_tcgen05_ld_16x64b_x8:320  case Intrinsic::nvvm_tcgen05_ld_16x64b_x16:321  case Intrinsic::nvvm_tcgen05_ld_16x64b_x32:322  case Intrinsic::nvvm_tcgen05_ld_16x64b_x64:323  case Intrinsic::nvvm_tcgen05_ld_16x64b_x128:324  case Intrinsic::nvvm_tcgen05_ld_16x128b_x1:325  case Intrinsic::nvvm_tcgen05_ld_16x128b_x2:326  case Intrinsic::nvvm_tcgen05_ld_16x128b_x4:327  case Intrinsic::nvvm_tcgen05_ld_16x128b_x16:328  case Intrinsic::nvvm_tcgen05_ld_16x128b_x32:329  case Intrinsic::nvvm_tcgen05_ld_16x128b_x64:330  case Intrinsic::nvvm_tcgen05_ld_16x256b_x1:331  case Intrinsic::nvvm_tcgen05_ld_16x128b_x8:332  case Intrinsic::nvvm_tcgen05_ld_16x256b_x2:333  case Intrinsic::nvvm_tcgen05_ld_16x256b_x4:334  case Intrinsic::nvvm_tcgen05_ld_16x256b_x8:335  case Intrinsic::nvvm_tcgen05_ld_16x256b_x16:336  case Intrinsic::nvvm_tcgen05_ld_16x256b_x32:337  case Intrinsic::nvvm_tcgen05_ld_32x32b_x1:338  case Intrinsic::nvvm_tcgen05_ld_32x32b_x2:339  case Intrinsic::nvvm_tcgen05_ld_32x32b_x4:340  case Intrinsic::nvvm_tcgen05_ld_32x32b_x8:341  case Intrinsic::nvvm_tcgen05_ld_32x32b_x16:342  case Intrinsic::nvvm_tcgen05_ld_32x32b_x32:343  case Intrinsic::nvvm_tcgen05_ld_32x32b_x64:344  case Intrinsic::nvvm_tcgen05_ld_32x32b_x128: {345    SelectTcgen05Ld(N);346    return true;347  }348 349  case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x1:350  case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x2:351  case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x4:352  case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x8:353  case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x16:354  case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x32:355  case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x64:356  case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x128: {357    SelectTcgen05Ld(N, /* hasOffset */ true);358    return true;359  }360  }361}362 363// Map ISD:CONDCODE value to appropriate CmpMode expected by364// NVPTXInstPrinter::printCmpMode()365SDValue NVPTXDAGToDAGISel::getPTXCmpMode(const CondCodeSDNode &CondCode) {366  using NVPTX::PTXCmpMode::CmpMode;367  const unsigned PTXCmpMode = [](ISD::CondCode CC) {368    switch (CC) {369    default:370      llvm_unreachable("Unexpected condition code.");371    case ISD::SETOEQ:372    case ISD::SETEQ:373      return CmpMode::EQ;374    case ISD::SETOGT:375    case ISD::SETGT:376      return CmpMode::GT;377    case ISD::SETOGE:378    case ISD::SETGE:379      return CmpMode::GE;380    case ISD::SETOLT:381    case ISD::SETLT:382      return CmpMode::LT;383    case ISD::SETOLE:384    case ISD::SETLE:385      return CmpMode::LE;386    case ISD::SETONE:387    case ISD::SETNE:388      return CmpMode::NE;389    case ISD::SETO:390      return CmpMode::NUM;391    case ISD::SETUO:392      return CmpMode::NotANumber;393    case ISD::SETUEQ:394      return CmpMode::EQU;395    case ISD::SETUGT:396      return CmpMode::GTU;397    case ISD::SETUGE:398      return CmpMode::GEU;399    case ISD::SETULT:400      return CmpMode::LTU;401    case ISD::SETULE:402      return CmpMode::LEU;403    case ISD::SETUNE:404      return CmpMode::NEU;405    }406  }(CondCode.get());407  return CurDAG->getTargetConstant(PTXCmpMode, SDLoc(), MVT::i32);408}409 410bool NVPTXDAGToDAGISel::SelectSETP_F16X2(SDNode *N) {411  SDValue PTXCmpMode = getPTXCmpMode(*cast<CondCodeSDNode>(N->getOperand(2)));412  SDLoc DL(N);413  SDNode *SetP = CurDAG->getMachineNode(414      NVPTX::SETP_f16x2rr, DL, MVT::i1, MVT::i1,415      {N->getOperand(0), N->getOperand(1), PTXCmpMode,416       CurDAG->getTargetConstant(useF32FTZ() ? 1 : 0, DL, MVT::i1)});417  ReplaceNode(N, SetP);418  return true;419}420 421bool NVPTXDAGToDAGISel::SelectSETP_BF16X2(SDNode *N) {422  SDValue PTXCmpMode = getPTXCmpMode(*cast<CondCodeSDNode>(N->getOperand(2)));423  SDLoc DL(N);424  SDNode *SetP = CurDAG->getMachineNode(425      NVPTX::SETP_bf16x2rr, DL, MVT::i1, MVT::i1,426      {N->getOperand(0), N->getOperand(1), PTXCmpMode,427       CurDAG->getTargetConstant(useF32FTZ() ? 1 : 0, DL, MVT::i1)});428  ReplaceNode(N, SetP);429  return true;430}431 432bool NVPTXDAGToDAGISel::tryUNPACK_VECTOR(SDNode *N) {433  SDValue Vector = N->getOperand(0);434  MVT EltVT = N->getSimpleValueType(0);435 436  MachineSDNode *N2 =437      CurDAG->getMachineNode(NVPTX::I64toV2I32, SDLoc(N), EltVT, EltVT, Vector);438 439  ReplaceNode(N, N2);440  return true;441}442 443// Find all instances of extract_vector_elt that use this v2f16 vector444// and coalesce them into a scattering move instruction.445bool NVPTXDAGToDAGISel::tryEXTRACT_VECTOR_ELEMENT(SDNode *N) {446  SDValue Vector = N->getOperand(0);447 448  MVT VT = Vector.getSimpleValueType();449  if (!(NVPTX::isPackedVectorTy(VT) && VT.getVectorNumElements() == 2))450    return false;451 452  unsigned Opcode;453  if (VT.is32BitVector())454    Opcode = NVPTX::I32toV2I16;455  else if (VT.is64BitVector())456    Opcode = NVPTX::I64toV2I32;457  else458    llvm_unreachable("Unhandled packed type");459 460  // Find and record all uses of this vector that extract element 0 or 1.461  SmallVector<SDNode *, 4> E0, E1;462  for (auto *U : Vector.getNode()->users()) {463    if (U->getOpcode() != ISD::EXTRACT_VECTOR_ELT)464      continue;465    if (U->getOperand(0) != Vector)466      continue;467    if (const ConstantSDNode *IdxConst =468            dyn_cast<ConstantSDNode>(U->getOperand(1))) {469      if (IdxConst->getZExtValue() == 0)470        E0.push_back(U);471      else if (IdxConst->getZExtValue() == 1)472        E1.push_back(U);473      else474        llvm_unreachable("Invalid vector index.");475    }476  }477 478  // There's no point scattering f16x2 if we only ever access one479  // element of it.480  if (E0.empty() || E1.empty())481    return false;482 483  // Merge (EltTy extractelt(V, 0), EltTy extractelt(V,1))484  // into EltTy,EltTy Split[EltTy]x2(V)485  MVT EltVT = VT.getVectorElementType();486  SDNode *ScatterOp =487      CurDAG->getMachineNode(Opcode, SDLoc(N), EltVT, EltVT, Vector);488  for (auto *Node : E0)489    ReplaceUses(SDValue(Node, 0), SDValue(ScatterOp, 0));490  for (auto *Node : E1)491    ReplaceUses(SDValue(Node, 0), SDValue(ScatterOp, 1));492 493  return true;494}495 496static std::optional<NVPTX::AddressSpace> convertAS(unsigned AS) {497  switch (AS) {498  case llvm::ADDRESS_SPACE_LOCAL:499    return NVPTX::AddressSpace::Local;500  case llvm::ADDRESS_SPACE_GLOBAL:501    return NVPTX::AddressSpace::Global;502  case llvm::ADDRESS_SPACE_SHARED:503    return NVPTX::AddressSpace::Shared;504  case llvm::ADDRESS_SPACE_SHARED_CLUSTER:505    return NVPTX::AddressSpace::SharedCluster;506  case llvm::ADDRESS_SPACE_GENERIC:507    return NVPTX::AddressSpace::Generic;508  case llvm::ADDRESS_SPACE_PARAM:509    return NVPTX::AddressSpace::Param;510  case llvm::ADDRESS_SPACE_CONST:511    return NVPTX::AddressSpace::Const;512  default:513    return std::nullopt;514  }515}516 517NVPTX::AddressSpace NVPTXDAGToDAGISel::getAddrSpace(const MemSDNode *N) {518  return convertAS(N->getMemOperand()->getAddrSpace())519      .value_or(NVPTX::AddressSpace::Generic);520}521 522NVPTX::Ordering NVPTXDAGToDAGISel::getMemOrder(const MemSDNode *N) const {523  // No "sem" orderings for SM/PTX versions which do not support memory ordering524  if (!Subtarget->hasMemoryOrdering())525    return NVPTX::Ordering::NotAtomic;526  auto Ordering = N->getMergedOrdering();527  switch (Ordering) {528  case AtomicOrdering::NotAtomic:529    return NVPTX::Ordering::NotAtomic;530  case AtomicOrdering::Unordered:531  case AtomicOrdering::Monotonic:532    return NVPTX::Ordering::Relaxed;533  case AtomicOrdering::Acquire:534    return NVPTX::Ordering::Acquire;535  case AtomicOrdering::Release:536    return NVPTX::Ordering::Release;537  case AtomicOrdering::AcquireRelease:538    return NVPTX::Ordering::AcquireRelease;539  case AtomicOrdering::SequentiallyConsistent:540    return NVPTX::Ordering::SequentiallyConsistent;541  }542  llvm_unreachable("Invalid atomic ordering");543}544 545NVPTX::Scope NVPTXDAGToDAGISel::getAtomicScope(const MemSDNode *N) const {546  // No "scope" modifier for SM/PTX versions which do not support scoped atomics547  // Functionally, these atomics are at device scope548  if (!Subtarget->hasAtomScope())549    return NVPTX::Scope::DefaultDevice;550  return Scopes[N->getSyncScopeID()];551}552 553namespace {554 555struct OperationOrderings {556  NVPTX::Ordering InstructionOrdering, FenceOrdering;557  OperationOrderings(NVPTX::Ordering IO = NVPTX::Ordering::NotAtomic,558                     NVPTX::Ordering FO = NVPTX::Ordering::NotAtomic)559      : InstructionOrdering(IO), FenceOrdering(FO) {}560};561 562static OperationOrderings563getOperationOrderings(MemSDNode *N, const NVPTXSubtarget *Subtarget) {564  AtomicOrdering Ordering = N->getSuccessOrdering();565  auto CodeAddrSpace = NVPTXDAGToDAGISel::getAddrSpace(N);566 567  bool HasMemoryOrdering = Subtarget->hasMemoryOrdering();568  bool HasRelaxedMMIO = Subtarget->hasRelaxedMMIO();569 570  // clang-format off571 572  // Lowering for Load/Store Operations (note: AcquireRelease Loads or Stores error).573  // Note: uses of Relaxed in the Atomic column of this table refer574  // to LLVM AtomicOrdering::Monotonic.575  //576  // | Atomic  | Volatile | Statespace         | PTX sm_60- | PTX sm_70+                   |577  // |---------|----------|--------------------|------------|------------------------------|578  // | No      | No       | All                | plain      | .weak                        |579  // | No      | Yes      | Generic,Shared,    | .volatile  | .volatile                    |580  // |         |          | Global [0]         |            |                              |581  // | No      | Yes      | Local,Const,Param  | plain [1]  | .weak [1]                    |582  // | Unorder | Yes/No   | All                | == Relaxed | == Relaxed                   |583  // | Relaxed | No       | Generic,Shared,    | .volatile  | <atomic sem>                 |584  // |         |          | Global [0]         |            |                              |585  // | Other   | No       | Generic,Shared,    | Error [2]  | <atomic sem>                 |586  // |         |          | Global [0]         |            |                              |587  // | Yes     | No       | Local,Const,Param  | plain [1]  | .weak [1]                    |588  // | Relaxed | Yes      | Generic,Shared [0] | .volatile  | .volatile                    |589  // | Relaxed | Yes      | Global [0]         | .volatile  | .mmio.relaxed.sys (PTX 8.2+) |590  // |         |          |                    |            |  or .volatile (PTX 8.1-)     |591  // | Relaxed | Yes      | Local,Const,Param  | plain [1]  | .weak [1]                    |592  // | Other   | Yes      | Generic, Shared,   | Error [2]  | <atomic sem> [3]             |593  // |         |          | / Global [0]       |            |                              |594 595  // Lowering of CUDA C++ SequentiallyConsistent Operations and Fences to PTX596  // by following the ABI proven sound in:597  //   Lustig et al, A Formal Analysis of the NVIDIA PTX Memory Consistency Model, ASPLOS’19.598  //   https://dl.acm.org/doi/pdf/10.1145/3297858.3304043599  //600  // | CUDA C++ Atomic Operation or Atomic Fence            | PTX Atomic Operation or Fence |601  // |------------------------------------------------------|-------------------------------|602  // | cuda::atomic_thread_fence                            | fence.sc.<scope>;             |603  // |   (memory_order_seq_cst, cuda::thread_scope_<scope>) |                               |604  // |------------------------------------------------------|-------------------------------|605  // | cuda::atomic_load                                    | fence.sc.<scope>;             |606  // |   (memory_order_seq_cst, cuda::thread_scope_<scope>) | ld.acquire.<scope>;           |607  // |------------------------------------------------------|-------------------------------|  608  // | cuda::atomic_store                                   | fence.sc.<scope>;             |609  // |   (memory_order_seq_cst, cuda::thread_scope_<scope>) | st.release.<scope>;           |610  // |------------------------------------------------------|-------------------------------|611  // | cuda::atomic_fetch_<op>                              | fence.sc.<scope>;             |612  // |   (memory_order_seq_cst, cuda::thread_scope_<scope>) | atom.acq_rel.<scope>;         |613 614  // clang-format on615 616  // [0]: volatile and atomics are only supported on global or shared617  //      memory locations, accessed via generic/shared/global pointers.618  //      MMIO is only supported on global memory locations,619  //      accessed via generic/global pointers.620  // TODO: Implement MMIO access via generic pointer to global.621  //       Currently implemented for global pointers only.622 623  // [1]: Lowering volatile/atomic operations to non-volatile/non-atomic624  //      PTX instructions fails to preserve their C++ side-effects.625  //626  //      Example (https://github.com/llvm/llvm-project/issues/62057):627  //628  //          void example() {629  //              std::atomic<bool> True = true;630  //              while (True.load(std::memory_order_relaxed));631  //          }632  //633  //      A C++ program that calls "example" is well-defined: the infinite loop634  //      performs an atomic operation. By lowering volatile/atomics to635  //      "weak" memory operations, we are transforming the above into:636  //637  //          void undefined_behavior() {638  //              bool True = true;639  //              while (True);640  //          }641  //642  //      which exhibits undefined behavior in both C++ and PTX.643  //644  //      Calling "example" in CUDA C++ compiled for sm_60- exhibits undefined645  //      behavior due to lack of Independent Forward Progress. Lowering these646  //      to weak memory operations in sm_60- is therefore fine.647  //648  //      TODO: lower atomic and volatile operations to memory locations649  //      in local, const, and param to two PTX instructions in sm_70+:650  //        - the "weak" memory instruction we are currently lowering to, and651  //        - some other instruction that preserves the side-effect, e.g.,652  //          a dead dummy volatile load.653  if (CodeAddrSpace == NVPTX::AddressSpace::Local ||654      CodeAddrSpace == NVPTX::AddressSpace::Const ||655      CodeAddrSpace == NVPTX::AddressSpace::Param) {656    return NVPTX::Ordering::NotAtomic;657  }658 659  // [2]: Atomics with Ordering different than Unordered or Relaxed are not660  //      supported on sm_60 and older; this includes volatile atomics.661  if (!(Ordering == AtomicOrdering::NotAtomic ||662        Ordering == AtomicOrdering::Unordered ||663        Ordering == AtomicOrdering::Monotonic) &&664      !HasMemoryOrdering) {665    report_fatal_error(666        formatv("PTX does not support \"atomic\" for orderings different than"667                "\"NotAtomic\" or \"Monotonic\" for sm_60 or older, but order "668                "is: \"{}\".",669                toIRString(Ordering)));670  }671 672  // [3]: TODO: these should eventually use .mmio<.atomic sem>; for now we drop673  // the volatile semantics and preserve the atomic ones.674 675  // PTX volatile and PTX atomics are not available for statespace that differ676  // from .generic, .global, or .shared. The behavior of PTX volatile and PTX677  // atomics is undefined if the generic address does not refer to a .global or678  // .shared memory location.679  bool AddrGenericOrGlobalOrShared =680      (CodeAddrSpace == NVPTX::AddressSpace::Generic ||681       CodeAddrSpace == NVPTX::AddressSpace::Global ||682       CodeAddrSpace == NVPTX::AddressSpace::Shared ||683       CodeAddrSpace == NVPTX::AddressSpace::SharedCluster);684  if (!AddrGenericOrGlobalOrShared)685    return NVPTX::Ordering::NotAtomic;686 687  bool UseRelaxedMMIO =688      HasRelaxedMMIO && CodeAddrSpace == NVPTX::AddressSpace::Global;689 690  switch (Ordering) {691  case AtomicOrdering::NotAtomic:692    return N->isVolatile() ? NVPTX::Ordering::Volatile693                           : NVPTX::Ordering::NotAtomic;694  case AtomicOrdering::Unordered:695    // We lower unordered in the exact same way as 'monotonic' to respect696    // LLVM IR atomicity requirements.697  case AtomicOrdering::Monotonic:698    if (N->isVolatile())699      return UseRelaxedMMIO ? NVPTX::Ordering::RelaxedMMIO700                            : NVPTX::Ordering::Volatile;701    else702      return HasMemoryOrdering ? NVPTX::Ordering::Relaxed703                               : NVPTX::Ordering::Volatile;704  // case AtomicOrdering::Consume: // If LLVM ever provides this, lower it to705  // Acquire.706  case AtomicOrdering::Acquire:707    if (!N->readMem())708      report_fatal_error(709          formatv("PTX only supports Acquire Ordering on reads: {}",710                  N->getOperationName()));711    return NVPTX::Ordering::Acquire;712  case AtomicOrdering::Release:713    if (!N->writeMem())714      report_fatal_error(715          formatv("PTX only supports Release Ordering on writes: {}",716                  N->getOperationName()));717    return NVPTX::Ordering::Release;718  case AtomicOrdering::AcquireRelease: {719    report_fatal_error(720        formatv("NVPTX does not support AcquireRelease Ordering on "721                "read-modify-write "722                "yet and PTX does not support it on loads or stores: {}",723                N->getOperationName()));724  }725  case AtomicOrdering::SequentiallyConsistent: {726    // LLVM-IR SequentiallyConsistent atomics map to a two-instruction PTX727    // sequence including a "fence.sc.sco" and the memory instruction with an728    // Ordering that differs from "sc": acq, rel, or acq_rel, depending on729    // whether the memory operation is a read, write, or read-modify-write.730    //731    // This sets the ordering of the fence to SequentiallyConsistent, and732    // sets the corresponding ordering for the instruction.733    NVPTX::Ordering InstrOrder;734    if (N->readMem())735      InstrOrder = NVPTX::Ordering::Acquire;736    else if (N->writeMem())737      InstrOrder = NVPTX::Ordering::Release;738    else739      report_fatal_error(740          formatv("NVPTX does not support SequentiallyConsistent Ordering on "741                  "read-modify-writes yet: {}",742                  N->getOperationName()));743    return OperationOrderings(InstrOrder,744                              NVPTX::Ordering::SequentiallyConsistent);745  }746  }747  report_fatal_error(748      formatv("NVPTX backend does not support AtomicOrdering \"{}\" yet.",749              toIRString(Ordering)));750}751 752} // namespace753 754NVPTX::Scope NVPTXDAGToDAGISel::getOperationScope(MemSDNode *N,755                                                  NVPTX::Ordering O) const {756  switch (O) {757  case NVPTX::Ordering::NotAtomic:758  case NVPTX::Ordering::Volatile: // Non-atomic volatile operations759    // NVPTX uses Thread scope as the scope of non-atomic operations.760    return NVPTX::Scope::Thread;761  case NVPTX::Ordering::RelaxedMMIO:762    // RelaxedMMIO operations are always system scope.763    // If a RelaxedMMIO order was generated from an atomic volatile operation764    // with a smaller thread scope, we bump it here to system scope.765    return NVPTX::Scope::System;766  case NVPTX::Ordering::Relaxed:767  case NVPTX::Ordering::Acquire:768  case NVPTX::Ordering::Release:769  case NVPTX::Ordering::AcquireRelease:770  case NVPTX::Ordering::SequentiallyConsistent:771    auto S = Scopes[N->getSyncScopeID()];772 773    // Atomic operations must have a scope greater than thread.774    if (S == NVPTX::Scope::Thread)775      report_fatal_error(776          formatv("Atomics need scope > \"{}\".", ScopeToString(S)));777 778    // If scope is cluster, clusters must be supported.779    if (S == NVPTX::Scope::Cluster)780      Subtarget->failIfClustersUnsupported("cluster scope");781 782    // If operation is volatile, then its scope is system.783    return N->isVolatile() ? NVPTX::Scope::System : S;784  }785  llvm_unreachable("unhandled ordering");786}787 788static bool canLowerToLDG(const MemSDNode &N, const NVPTXSubtarget &Subtarget,789                          NVPTX::AddressSpace CodeAddrSpace) {790  // We use ldg (i.e. ld.global.nc) for invariant loads from the global address791  // space.792  return Subtarget.hasLDG() && CodeAddrSpace == NVPTX::AddressSpace::Global &&793         N.isInvariant();794}795 796static unsigned int getFenceOp(NVPTX::Ordering O, NVPTX::Scope S,797                               NVPTXSubtarget const *T) {798  if (S == NVPTX::Scope::Cluster)799    T->failIfClustersUnsupported(".cluster scope fence");800 801  // Fall back to .acq_rel if .acquire, .release is not supported.802  if (!T->hasSplitAcquireAndReleaseFences() &&803      (O == NVPTX::Ordering::Acquire || O == NVPTX::Ordering::Release))804    O = NVPTX::Ordering::AcquireRelease;805 806  switch (O) {807  case NVPTX::Ordering::Acquire:808    switch (S) {809    case NVPTX::Scope::System:810      return T->hasMemoryOrdering() ? NVPTX::atomic_thread_fence_acquire_sys811                                    : NVPTX::INT_MEMBAR_SYS;812    case NVPTX::Scope::Block:813      return T->hasMemoryOrdering() ? NVPTX::atomic_thread_fence_acquire_cta814                                    : NVPTX::INT_MEMBAR_CTA;815    case NVPTX::Scope::Cluster:816      return NVPTX::atomic_thread_fence_acquire_cluster;817    case NVPTX::Scope::Device:818      return T->hasMemoryOrdering() ? NVPTX::atomic_thread_fence_acquire_gpu819                                    : NVPTX::INT_MEMBAR_GL;820    case NVPTX::Scope::Thread:821    case NVPTX::Scope::DefaultDevice:822      report_fatal_error(823          formatv("Unsupported scope \"{}\" for acquire/release/acq_rel fence.",824                  ScopeToString(S)));825    }826    break;827  case NVPTX::Ordering::Release:828    switch (S) {829    case NVPTX::Scope::System:830      return T->hasMemoryOrdering() ? NVPTX::atomic_thread_fence_release_sys831                                    : NVPTX::INT_MEMBAR_SYS;832    case NVPTX::Scope::Block:833      return T->hasMemoryOrdering() ? NVPTX::atomic_thread_fence_release_cta834                                    : NVPTX::INT_MEMBAR_CTA;835    case NVPTX::Scope::Cluster:836      return NVPTX::atomic_thread_fence_release_cluster;837    case NVPTX::Scope::Device:838      return T->hasMemoryOrdering() ? NVPTX::atomic_thread_fence_release_gpu839                                    : NVPTX::INT_MEMBAR_GL;840    case NVPTX::Scope::Thread:841    case NVPTX::Scope::DefaultDevice:842      report_fatal_error(843          formatv("Unsupported scope \"{}\" for acquire/release/acq_rel fence.",844                  ScopeToString(S)));845    }846    break;847  case NVPTX::Ordering::AcquireRelease: {848    switch (S) {849    case NVPTX::Scope::System:850      return T->hasMemoryOrdering() ? NVPTX::atomic_thread_fence_acq_rel_sys851                                    : NVPTX::INT_MEMBAR_SYS;852    case NVPTX::Scope::Block:853      return T->hasMemoryOrdering() ? NVPTX::atomic_thread_fence_acq_rel_cta854                                    : NVPTX::INT_MEMBAR_CTA;855    case NVPTX::Scope::Cluster:856      return NVPTX::atomic_thread_fence_acq_rel_cluster;857    case NVPTX::Scope::Device:858      return T->hasMemoryOrdering() ? NVPTX::atomic_thread_fence_acq_rel_gpu859                                    : NVPTX::INT_MEMBAR_GL;860    case NVPTX::Scope::Thread:861    case NVPTX::Scope::DefaultDevice:862      report_fatal_error(863          formatv("Unsupported scope \"{}\" for acquire/release/acq_rel fence.",864                  ScopeToString(S)));865    }866    break;867  }868  case NVPTX::Ordering::SequentiallyConsistent: {869    switch (S) {870    case NVPTX::Scope::System:871      return T->hasMemoryOrdering() ? NVPTX::atomic_thread_fence_seq_cst_sys872                                    : NVPTX::INT_MEMBAR_SYS;873    case NVPTX::Scope::Block:874      return T->hasMemoryOrdering() ? NVPTX::atomic_thread_fence_seq_cst_cta875                                    : NVPTX::INT_MEMBAR_CTA;876    case NVPTX::Scope::Cluster:877      return NVPTX::atomic_thread_fence_seq_cst_cluster;878    case NVPTX::Scope::Device:879      return T->hasMemoryOrdering() ? NVPTX::atomic_thread_fence_seq_cst_gpu880                                    : NVPTX::INT_MEMBAR_GL;881    case NVPTX::Scope::Thread:882    case NVPTX::Scope::DefaultDevice:883      report_fatal_error(formatv("Unsupported scope \"{}\" for seq_cst fence.",884                                 ScopeToString(S)));885    }886    break;887  }888  case NVPTX::Ordering::NotAtomic:889  case NVPTX::Ordering::Relaxed:890  case NVPTX::Ordering::Volatile:891  case NVPTX::Ordering::RelaxedMMIO:892    report_fatal_error(893        formatv("Unsupported \"{}\" ordering and \"{}\" scope for fence.",894                OrderingToString(O), ScopeToString(S)));895  }896  llvm_unreachable("unhandled ordering");897}898 899// Returns Memory Order and Scope of a memory instruction, and900// inserts any fence before the instruction that's required to901// implement its memory ordering.902std::pair<NVPTX::Ordering, NVPTX::Scope>903NVPTXDAGToDAGISel::insertMemoryInstructionFence(SDLoc DL, SDValue &Chain,904                                                MemSDNode *N) {905  auto [InstructionOrdering, FenceOrdering] =906      getOperationOrderings(N, Subtarget);907  auto Scope = getOperationScope(N, InstructionOrdering);908 909  // If a fence is required before the operation, insert it:910  switch (NVPTX::Ordering(FenceOrdering)) {911  case NVPTX::Ordering::NotAtomic:912    break;913  case NVPTX::Ordering::SequentiallyConsistent: {914    auto Op = getFenceOp(FenceOrdering, Scope, Subtarget);915    Chain = SDValue(CurDAG->getMachineNode(Op, DL, MVT::Other, Chain), 0);916    break;917  }918  default:919    report_fatal_error(920        formatv("Unexpected fence ordering: \"{}\".",921                OrderingToString(NVPTX::Ordering(FenceOrdering))));922  }923  return {InstructionOrdering, Scope};924}925 926void NVPTXDAGToDAGISel::SelectAddrSpaceCast(SDNode *N) {927  SDValue Src = N->getOperand(0);928  AddrSpaceCastSDNode *CastN = cast<AddrSpaceCastSDNode>(N);929  unsigned SrcAddrSpace = CastN->getSrcAddressSpace();930  unsigned DstAddrSpace = CastN->getDestAddressSpace();931  SDLoc DL(N);932  assert(SrcAddrSpace != DstAddrSpace &&933         "addrspacecast must be between different address spaces");934 935  if (DstAddrSpace == ADDRESS_SPACE_GENERIC) {936    // Specific to generic937 938    if (TM.is64Bit() && TM.getPointerSizeInBits(SrcAddrSpace) == 32) {939      SDValue CvtNone =940          CurDAG->getTargetConstant(NVPTX::PTXCvtMode::NONE, DL, MVT::i32);941      SDNode *Cvt = CurDAG->getMachineNode(NVPTX::CVT_u64_u32, DL, MVT::i64,942                                           Src, CvtNone);943      Src = SDValue(Cvt, 0);944    }945 946    unsigned Opc;947    switch (SrcAddrSpace) {948    default: report_fatal_error("Bad address space in addrspacecast");949    case ADDRESS_SPACE_GLOBAL:950      Opc = TM.is64Bit() ? NVPTX::cvta_global_64 : NVPTX::cvta_global;951      break;952    case ADDRESS_SPACE_SHARED:953      Opc = TM.is64Bit() ? NVPTX::cvta_shared_64 : NVPTX::cvta_shared;954      break;955    case ADDRESS_SPACE_SHARED_CLUSTER:956      if (!TM.is64Bit())957        report_fatal_error(958            "Shared cluster address space is only supported in 64-bit mode");959      Opc = NVPTX::cvta_shared_cluster_64;960      break;961    case ADDRESS_SPACE_CONST:962      Opc = TM.is64Bit() ? NVPTX::cvta_const_64 : NVPTX::cvta_const;963      break;964    case ADDRESS_SPACE_LOCAL:965      Opc = TM.is64Bit() ? NVPTX::cvta_local_64 : NVPTX::cvta_local;966      break;967    case ADDRESS_SPACE_PARAM:968      Opc = TM.is64Bit() ? NVPTX::cvta_param_64 : NVPTX::cvta_param;969      break;970    }971    ReplaceNode(N, CurDAG->getMachineNode(Opc, DL, N->getValueType(0), Src));972    return;973  } else {974    // Generic to specific975    if (SrcAddrSpace != 0)976      report_fatal_error("Cannot cast between two non-generic address spaces");977    unsigned Opc;978    switch (DstAddrSpace) {979    default: report_fatal_error("Bad address space in addrspacecast");980    case ADDRESS_SPACE_GLOBAL:981      Opc = TM.is64Bit() ? NVPTX::cvta_to_global_64 : NVPTX::cvta_to_global;982      break;983    case ADDRESS_SPACE_SHARED:984      Opc = TM.is64Bit() ? NVPTX::cvta_to_shared_64 : NVPTX::cvta_to_shared;985      break;986    case ADDRESS_SPACE_SHARED_CLUSTER:987      if (!TM.is64Bit())988        report_fatal_error(989            "Shared cluster address space is only supported in 64-bit mode");990      Opc = NVPTX::cvta_to_shared_cluster_64;991      break;992    case ADDRESS_SPACE_CONST:993      Opc = TM.is64Bit() ? NVPTX::cvta_to_const_64 : NVPTX::cvta_to_const;994      break;995    case ADDRESS_SPACE_LOCAL:996      Opc = TM.is64Bit() ? NVPTX::cvta_to_local_64 : NVPTX::cvta_to_local;997      break;998    case ADDRESS_SPACE_PARAM:999      Opc = TM.is64Bit() ? NVPTX::cvta_to_param_64 : NVPTX::cvta_to_param;1000      break;1001    }1002 1003    SDNode *CVTA = CurDAG->getMachineNode(Opc, DL, N->getValueType(0), Src);1004    if (TM.is64Bit() && TM.getPointerSizeInBits(DstAddrSpace) == 32) {1005      SDValue CvtNone =1006          CurDAG->getTargetConstant(NVPTX::PTXCvtMode::NONE, DL, MVT::i32);1007      CVTA = CurDAG->getMachineNode(NVPTX::CVT_u32_u64, DL, MVT::i32,1008                                    SDValue(CVTA, 0), CvtNone);1009    }1010 1011    ReplaceNode(N, CVTA);1012    return;1013  }1014}1015 1016// Helper function template to reduce amount of boilerplate code for1017// opcode selection.1018static std::optional<unsigned>1019pickOpcodeForVT(MVT::SimpleValueType VT, std::optional<unsigned> Opcode_i16,1020                std::optional<unsigned> Opcode_i32,1021                std::optional<unsigned> Opcode_i64) {1022  switch (VT) {1023  case MVT::f16:1024  case MVT::i16:1025  case MVT::bf16:1026    return Opcode_i16;1027  case MVT::v2f16:1028  case MVT::v2bf16:1029  case MVT::v2i16:1030  case MVT::v4i8:1031  case MVT::i32:1032  case MVT::f32:1033    return Opcode_i32;1034  case MVT::v2f32:1035  case MVT::v2i32:1036  case MVT::i64:1037  case MVT::f64:1038    return Opcode_i64;1039  default:1040    return std::nullopt;1041  }1042}1043 1044static inline bool isAddLike(const SDValue V) {1045  return V.getOpcode() == ISD::ADD ||1046         (V->getOpcode() == ISD::OR && V->getFlags().hasDisjoint());1047}1048 1049static SDValue stripAssertAlign(SDValue N) {1050  if (N.getOpcode() == ISD::AssertAlign)1051    N = N.getOperand(0);1052  return N;1053}1054 1055// selectBaseADDR - Match a dag node which will serve as the base address for an1056// ADDR operand pair.1057static SDValue selectBaseADDR(SDValue N, SelectionDAG *DAG) {1058  N = stripAssertAlign(N);1059  if (const auto *GA = dyn_cast<GlobalAddressSDNode>(N))1060    return DAG->getTargetGlobalAddress(GA->getGlobal(), SDLoc(N),1061                                       GA->getValueType(0), GA->getOffset(),1062                                       GA->getTargetFlags());1063  if (const auto *ES = dyn_cast<ExternalSymbolSDNode>(N))1064    return DAG->getTargetExternalSymbol(ES->getSymbol(), ES->getValueType(0),1065                                        ES->getTargetFlags());1066  if (const auto *FIN = dyn_cast<FrameIndexSDNode>(N))1067    return DAG->getTargetFrameIndex(FIN->getIndex(), FIN->getValueType(0));1068 1069  return N;1070}1071 1072static SDValue accumulateOffset(SDValue &Addr, SDLoc DL, SelectionDAG *DAG) {1073  Addr = stripAssertAlign(Addr);1074  APInt AccumulatedOffset(64u, 0);1075  while (isAddLike(Addr)) {1076    const auto *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1));1077    if (!CN)1078      break;1079 1080    const APInt CI = CN->getAPIntValue().sext(64);1081    if (!(CI + AccumulatedOffset).isSignedIntN(32))1082      break;1083 1084    AccumulatedOffset += CI;1085    Addr = stripAssertAlign(Addr->getOperand(0));1086  }1087  return DAG->getSignedTargetConstant(AccumulatedOffset.getSExtValue(), DL,1088                                      MVT::i32);1089}1090 1091static std::pair<SDValue, SDValue> selectADDR(SDValue Addr, SelectionDAG *DAG) {1092  SDValue Offset = accumulateOffset(Addr, SDLoc(Addr), DAG);1093  SDValue Base = selectBaseADDR(Addr, DAG);1094  return {Base, Offset};1095}1096 1097// Select a pair of operands which represent a valid PTX address, this could be1098// one of the following things:1099//  - [var] - Offset is simply set to 01100//  - [reg] - Offset is simply set to 01101//  - [reg+immOff]1102//  - [var+immOff]1103// Note that immOff must fit into a 32-bit signed integer.1104bool NVPTXDAGToDAGISel::SelectADDR(SDValue Addr, SDValue &Base,1105                                   SDValue &Offset) {1106  std::tie(Base, Offset) = selectADDR(Addr, CurDAG);1107  return true;1108}1109 1110bool NVPTXDAGToDAGISel::tryLoad(SDNode *N) {1111  MemSDNode *LD = cast<MemSDNode>(N);1112  assert(LD->readMem() && "Expected load");1113 1114  // do not support pre/post inc/dec1115  const LoadSDNode *PlainLoad = dyn_cast<LoadSDNode>(LD);1116  if (PlainLoad && PlainLoad->isIndexed())1117    return false;1118 1119  // Address Space Setting1120  const auto CodeAddrSpace = getAddrSpace(LD);1121  if (canLowerToLDG(*LD, *Subtarget, CodeAddrSpace))1122    return tryLDG(LD);1123 1124  SDLoc DL(LD);1125  SDValue Chain = N->getOperand(0);1126  const auto [Ordering, Scope] = insertMemoryInstructionFence(DL, Chain, LD);1127 1128  const unsigned FromTypeWidth = LD->getMemoryVT().getSizeInBits();1129 1130  // Vector Setting1131  const unsigned FromType =1132      (PlainLoad && (PlainLoad->getExtensionType() == ISD::SEXTLOAD))1133          ? NVPTX::PTXLdStInstCode::Signed1134          : NVPTX::PTXLdStInstCode::Untyped;1135 1136  uint32_t UsedBytesMask;1137  switch (N->getOpcode()) {1138  case ISD::LOAD:1139  case ISD::ATOMIC_LOAD:1140    UsedBytesMask = UINT32_MAX;1141    break;1142  case NVPTXISD::MLoad:1143    UsedBytesMask = N->getConstantOperandVal(3);1144    break;1145  default:1146    llvm_unreachable("Unexpected opcode");1147  }1148 1149  assert(isPowerOf2_32(FromTypeWidth) && FromTypeWidth >= 8 &&1150         FromTypeWidth <= 128 && "Invalid width for load");1151 1152  // Create the machine instruction DAG1153  const auto [Base, Offset] = selectADDR(N->getOperand(1), CurDAG);1154  SDValue Ops[] = {getI32Imm(Ordering, DL),1155                   getI32Imm(Scope, DL),1156                   getI32Imm(CodeAddrSpace, DL),1157                   getI32Imm(FromType, DL),1158                   getI32Imm(FromTypeWidth, DL),1159                   getI32Imm(UsedBytesMask, DL),1160                   Base,1161                   Offset,1162                   Chain};1163 1164  const MVT::SimpleValueType TargetVT = LD->getSimpleValueType(0).SimpleTy;1165  const std::optional<unsigned> Opcode =1166      pickOpcodeForVT(TargetVT, NVPTX::LD_i16, NVPTX::LD_i32, NVPTX::LD_i64);1167  if (!Opcode)1168    return false;1169 1170  SDNode *NVPTXLD = CurDAG->getMachineNode(*Opcode, DL, LD->getVTList(), Ops);1171  if (!NVPTXLD)1172    return false;1173 1174  MachineMemOperand *MemRef = LD->getMemOperand();1175  CurDAG->setNodeMemRefs(cast<MachineSDNode>(NVPTXLD), {MemRef});1176 1177  ReplaceNode(LD, NVPTXLD);1178  return true;1179}1180 1181static unsigned getStoreVectorNumElts(SDNode *N) {1182  switch (N->getOpcode()) {1183  case NVPTXISD::StoreV2:1184    return 2;1185  case NVPTXISD::StoreV4:1186    return 4;1187  case NVPTXISD::StoreV8:1188    return 8;1189  default:1190    llvm_unreachable("Unexpected opcode");1191  }1192}1193 1194bool NVPTXDAGToDAGISel::tryLoadVector(SDNode *N) {1195  MemSDNode *LD = cast<MemSDNode>(N);1196 1197  // Address Space Setting1198  const auto CodeAddrSpace = getAddrSpace(LD);1199  if (canLowerToLDG(*LD, *Subtarget, CodeAddrSpace))1200    return tryLDG(LD);1201 1202  const MVT EltVT = LD->getSimpleValueType(0);1203  SDLoc DL(LD);1204  SDValue Chain = LD->getChain();1205  const auto [Ordering, Scope] = insertMemoryInstructionFence(DL, Chain, LD);1206 1207  // Type Setting: fromType + fromTypeWidth1208  //1209  // Sign   : ISD::SEXTLOAD1210  // Unsign : ISD::ZEXTLOAD, ISD::NON_EXTLOAD or ISD::EXTLOAD and the1211  //          type is integer1212  // Float  : ISD::NON_EXTLOAD or ISD::EXTLOAD and the type is float1213  // Read at least 8 bits (predicates are stored as 8-bit values)1214  // Get the original LoadSDNode::getExtensionType() value1215  const unsigned ExtensionType = N->getConstantOperandVal(4);1216  const unsigned FromType = (ExtensionType == ISD::SEXTLOAD)1217                                ? NVPTX::PTXLdStInstCode::Signed1218                                : NVPTX::PTXLdStInstCode::Untyped;1219 1220  const unsigned FromTypeWidth = getFromTypeWidthForLoad(LD);1221  const uint32_t UsedBytesMask = N->getConstantOperandVal(3);1222 1223  assert(!(EltVT.isVector() && ExtensionType != ISD::NON_EXTLOAD));1224 1225  const auto [Base, Offset] = selectADDR(N->getOperand(1), CurDAG);1226  SDValue Ops[] = {getI32Imm(Ordering, DL),1227                   getI32Imm(Scope, DL),1228                   getI32Imm(CodeAddrSpace, DL),1229                   getI32Imm(FromType, DL),1230                   getI32Imm(FromTypeWidth, DL),1231                   getI32Imm(UsedBytesMask, DL),1232                   Base,1233                   Offset,1234                   Chain};1235 1236  std::optional<unsigned> Opcode;1237  switch (N->getOpcode()) {1238  default:1239    llvm_unreachable("Unexpected opcode");1240  case NVPTXISD::LoadV2:1241    Opcode = pickOpcodeForVT(EltVT.SimpleTy, NVPTX::LDV_i16_v2,1242                             NVPTX::LDV_i32_v2, NVPTX::LDV_i64_v2);1243    break;1244  case NVPTXISD::LoadV4:1245    Opcode = pickOpcodeForVT(EltVT.SimpleTy, NVPTX::LDV_i16_v4,1246                             NVPTX::LDV_i32_v4, NVPTX::LDV_i64_v4);1247    break;1248  case NVPTXISD::LoadV8:1249    Opcode = pickOpcodeForVT(EltVT.SimpleTy, {/* no v8i16 */},1250                             NVPTX::LDV_i32_v8, {/* no v8i64 */});1251    break;1252  }1253  if (!Opcode)1254    return false;1255 1256  SDNode *NVPTXLD = CurDAG->getMachineNode(*Opcode, DL, LD->getVTList(), Ops);1257 1258  MachineMemOperand *MemRef = LD->getMemOperand();1259  CurDAG->setNodeMemRefs(cast<MachineSDNode>(NVPTXLD), {MemRef});1260 1261  ReplaceNode(LD, NVPTXLD);1262  return true;1263}1264 1265bool NVPTXDAGToDAGISel::tryLDG(MemSDNode *LD) {1266  SDLoc DL(LD);1267 1268  unsigned ExtensionType;1269  uint32_t UsedBytesMask;1270  if (const auto *Load = dyn_cast<LoadSDNode>(LD)) {1271    ExtensionType = Load->getExtensionType();1272    UsedBytesMask = UINT32_MAX;1273  } else {1274    ExtensionType = LD->getConstantOperandVal(4);1275    UsedBytesMask = LD->getConstantOperandVal(3);1276  }1277  const unsigned FromType = (ExtensionType == ISD::SEXTLOAD)1278                                ? NVPTX::PTXLdStInstCode::Signed1279                                : NVPTX::PTXLdStInstCode::Untyped;1280 1281  const unsigned FromTypeWidth = getFromTypeWidthForLoad(LD);1282 1283  assert(!(LD->getSimpleValueType(0).isVector() &&1284           ExtensionType != ISD::NON_EXTLOAD));1285 1286  const auto [Base, Offset] = selectADDR(LD->getOperand(1), CurDAG);1287  SDValue Ops[] = {getI32Imm(FromType, DL),1288                   getI32Imm(FromTypeWidth, DL),1289                   getI32Imm(UsedBytesMask, DL),1290                   Base,1291                   Offset,1292                   LD->getChain()};1293 1294  const MVT::SimpleValueType TargetVT = LD->getSimpleValueType(0).SimpleTy;1295  std::optional<unsigned> Opcode;1296  switch (LD->getOpcode()) {1297  default:1298    llvm_unreachable("Unexpected opcode");1299  case ISD::LOAD:1300    Opcode = pickOpcodeForVT(TargetVT, NVPTX::LD_GLOBAL_NC_i16,1301                             NVPTX::LD_GLOBAL_NC_i32, NVPTX::LD_GLOBAL_NC_i64);1302    break;1303  case NVPTXISD::MLoad:1304    Opcode = pickOpcodeForVT(TargetVT, std::nullopt, NVPTX::LD_GLOBAL_NC_i32,1305                             NVPTX::LD_GLOBAL_NC_i64);1306    break;1307  case NVPTXISD::LoadV2:1308    Opcode =1309        pickOpcodeForVT(TargetVT, NVPTX::LD_GLOBAL_NC_v2i16,1310                        NVPTX::LD_GLOBAL_NC_v2i32, NVPTX::LD_GLOBAL_NC_v2i64);1311    break;1312  case NVPTXISD::LoadV4:1313    Opcode =1314        pickOpcodeForVT(TargetVT, NVPTX::LD_GLOBAL_NC_v4i16,1315                        NVPTX::LD_GLOBAL_NC_v4i32, NVPTX::LD_GLOBAL_NC_v4i64);1316    break;1317  case NVPTXISD::LoadV8:1318    Opcode = pickOpcodeForVT(TargetVT, {/* no v8i16 */},1319                             NVPTX::LD_GLOBAL_NC_v8i32, {/* no v8i64 */});1320    break;1321  }1322  if (!Opcode)1323    return false;1324 1325  SDNode *NVPTXLDG = CurDAG->getMachineNode(*Opcode, DL, LD->getVTList(), Ops);1326 1327  ReplaceNode(LD, NVPTXLDG);1328  return true;1329}1330 1331unsigned NVPTXDAGToDAGISel::getFromTypeWidthForLoad(const MemSDNode *Mem) {1332  auto TotalWidth = Mem->getMemoryVT().getSizeInBits();1333  auto NumElts = Mem->getNumValues() - 1;1334  auto ElementBitWidth = TotalWidth / NumElts;1335  assert(isPowerOf2_32(ElementBitWidth) && ElementBitWidth >= 8 &&1336         ElementBitWidth <= 128 && TotalWidth <= 256 &&1337         "Invalid width for load");1338  return ElementBitWidth;1339}1340 1341bool NVPTXDAGToDAGISel::tryLDU(SDNode *N) {1342  auto *LD = cast<MemSDNode>(N);1343 1344  SDLoc DL(N);1345  const unsigned FromTypeWidth = getFromTypeWidthForLoad(LD);1346  const MVT::SimpleValueType TargetVT = LD->getSimpleValueType(0).SimpleTy;1347 1348  // If this is an LDU intrinsic, the address is the third operand. If its an1349  // LDU SD node (from custom vector handling), then its the second operand1350  SDValue Addr =1351      LD->getOperand(LD->getOpcode() == ISD::INTRINSIC_W_CHAIN ? 2 : 1);1352 1353  const auto [Base, Offset] = selectADDR(Addr, CurDAG);1354  SDValue Ops[] = {getI32Imm(FromTypeWidth, DL), Base, Offset, LD->getChain()};1355 1356  std::optional<unsigned> Opcode;1357  switch (N->getOpcode()) {1358  default:1359    llvm_unreachable("Unexpected opcode");1360  case ISD::INTRINSIC_W_CHAIN:1361    Opcode = pickOpcodeForVT(TargetVT, NVPTX::LDU_GLOBAL_i16,1362                             NVPTX::LDU_GLOBAL_i32, NVPTX::LDU_GLOBAL_i64);1363    break;1364  case NVPTXISD::LDUV2:1365    Opcode = pickOpcodeForVT(TargetVT, NVPTX::LDU_GLOBAL_v2i16,1366                             NVPTX::LDU_GLOBAL_v2i32, NVPTX::LDU_GLOBAL_v2i64);1367    break;1368  case NVPTXISD::LDUV4:1369    Opcode = pickOpcodeForVT(TargetVT, NVPTX::LDU_GLOBAL_v4i16,1370                             NVPTX::LDU_GLOBAL_v4i32, {/* no v4i64 */});1371    break;1372  }1373  if (!Opcode)1374    return false;1375 1376  SDNode *NVPTXLDU = CurDAG->getMachineNode(*Opcode, DL, LD->getVTList(), Ops);1377 1378  ReplaceNode(LD, NVPTXLDU);1379  return true;1380}1381 1382bool NVPTXDAGToDAGISel::tryStore(SDNode *N) {1383  MemSDNode *ST = cast<MemSDNode>(N);1384  assert(ST->writeMem() && "Expected store");1385  StoreSDNode *PlainStore = dyn_cast<StoreSDNode>(ST);1386  AtomicSDNode *AtomicStore = dyn_cast<AtomicSDNode>(ST);1387  assert((PlainStore || AtomicStore) && "Expected store");1388 1389  // do not support pre/post inc/dec1390  if (PlainStore && PlainStore->isIndexed())1391    return false;1392 1393  // Address Space Setting1394  const auto CodeAddrSpace = getAddrSpace(ST);1395 1396  SDLoc DL(ST);1397  SDValue Chain = ST->getChain();1398  const auto [Ordering, Scope] = insertMemoryInstructionFence(DL, Chain, ST);1399 1400  // Vector Setting1401  const unsigned ToTypeWidth = ST->getMemoryVT().getSizeInBits();1402 1403  // Create the machine instruction DAG1404  SDValue Value = PlainStore ? PlainStore->getValue() : AtomicStore->getVal();1405 1406  assert(isPowerOf2_32(ToTypeWidth) && ToTypeWidth >= 8 && ToTypeWidth <= 128 &&1407         "Invalid width for store");1408 1409  const auto [Base, Offset] = selectADDR(ST->getBasePtr(), CurDAG);1410  SDValue Ops[] = {selectPossiblyImm(Value),1411                   getI32Imm(Ordering, DL),1412                   getI32Imm(Scope, DL),1413                   getI32Imm(CodeAddrSpace, DL),1414                   getI32Imm(ToTypeWidth, DL),1415                   Base,1416                   Offset,1417                   Chain};1418 1419  const std::optional<unsigned> Opcode =1420      pickOpcodeForVT(Value.getSimpleValueType().SimpleTy, NVPTX::ST_i16,1421                      NVPTX::ST_i32, NVPTX::ST_i64);1422  if (!Opcode)1423    return false;1424 1425  SDNode *NVPTXST = CurDAG->getMachineNode(*Opcode, DL, MVT::Other, Ops);1426 1427  if (!NVPTXST)1428    return false;1429 1430  MachineMemOperand *MemRef = ST->getMemOperand();1431  CurDAG->setNodeMemRefs(cast<MachineSDNode>(NVPTXST), {MemRef});1432  ReplaceNode(ST, NVPTXST);1433  return true;1434}1435 1436bool NVPTXDAGToDAGISel::tryStoreVector(SDNode *N) {1437  MemSDNode *ST = cast<MemSDNode>(N);1438  const unsigned TotalWidth = ST->getMemoryVT().getSizeInBits();1439 1440  // Address Space Setting1441  const auto CodeAddrSpace = getAddrSpace(ST);1442  if (CodeAddrSpace == NVPTX::AddressSpace::Const) {1443    report_fatal_error("Cannot store to pointer that points to constant "1444                       "memory space");1445  }1446 1447  SDLoc DL(ST);1448  SDValue Chain = ST->getChain();1449  const auto [Ordering, Scope] = insertMemoryInstructionFence(DL, Chain, ST);1450 1451  const unsigned NumElts = getStoreVectorNumElts(ST);1452 1453  SmallVector<SDValue, 16> Ops;1454  for (auto &V : ST->ops().slice(1, NumElts))1455    Ops.push_back(selectPossiblyImm(V));1456  SDValue Addr = N->getOperand(NumElts + 1);1457  const unsigned ToTypeWidth = TotalWidth / NumElts;1458 1459  assert(isPowerOf2_32(ToTypeWidth) && ToTypeWidth >= 8 && ToTypeWidth <= 128 &&1460         TotalWidth <= 256 && "Invalid width for store");1461 1462  const auto [Base, Offset] = selectADDR(Addr, CurDAG);1463  Ops.append({getI32Imm(Ordering, DL), getI32Imm(Scope, DL),1464              getI32Imm(CodeAddrSpace, DL), getI32Imm(ToTypeWidth, DL), Base,1465              Offset, Chain});1466 1467  const MVT::SimpleValueType EltVT =1468      ST->getOperand(1).getSimpleValueType().SimpleTy;1469  std::optional<unsigned> Opcode;1470  switch (ST->getOpcode()) {1471  default:1472    return false;1473  case NVPTXISD::StoreV2:1474    Opcode = pickOpcodeForVT(EltVT, NVPTX::STV_i16_v2, NVPTX::STV_i32_v2,1475                             NVPTX::STV_i64_v2);1476    break;1477  case NVPTXISD::StoreV4:1478    Opcode = pickOpcodeForVT(EltVT, NVPTX::STV_i16_v4, NVPTX::STV_i32_v4,1479                             NVPTX::STV_i64_v4);1480    break;1481  case NVPTXISD::StoreV8:1482    Opcode = pickOpcodeForVT(EltVT, {/* no v8i16 */}, NVPTX::STV_i32_v8,1483                             {/* no v8i64 */});1484    break;1485  }1486 1487  if (!Opcode)1488    return false;1489 1490  SDNode *NVPTXST = CurDAG->getMachineNode(*Opcode, DL, MVT::Other, Ops);1491 1492  MachineMemOperand *MemRef = ST->getMemOperand();1493  CurDAG->setNodeMemRefs(cast<MachineSDNode>(NVPTXST), {MemRef});1494 1495  ReplaceNode(ST, NVPTXST);1496  return true;1497}1498 1499/// SelectBFE - Look for instruction sequences that can be made more efficient1500/// by using the 'bfe' (bit-field extract) PTX instruction1501bool NVPTXDAGToDAGISel::tryBFE(SDNode *N) {1502  SDLoc DL(N);1503  SDValue LHS = N->getOperand(0);1504  SDValue RHS = N->getOperand(1);1505  SDValue Len;1506  SDValue Start;1507  SDValue Val;1508  bool IsSigned = false;1509 1510  if (N->getOpcode() == ISD::AND) {1511    // Canonicalize the operands1512    // We want 'and %val, %mask'1513    if (isa<ConstantSDNode>(LHS) && !isa<ConstantSDNode>(RHS)) {1514      std::swap(LHS, RHS);1515    }1516 1517    ConstantSDNode *Mask = dyn_cast<ConstantSDNode>(RHS);1518    if (!Mask) {1519      // We need a constant mask on the RHS of the AND1520      return false;1521    }1522 1523    // Extract the mask bits1524    uint64_t MaskVal = Mask->getZExtValue();1525    if (!isMask_64(MaskVal)) {1526      // We *could* handle shifted masks here, but doing so would require an1527      // 'and' operation to fix up the low-order bits so we would trade1528      // shr+and for bfe+and, which has the same throughput1529      return false;1530    }1531 1532    // How many bits are in our mask?1533    int64_t NumBits = countr_one(MaskVal);1534    Len = CurDAG->getTargetConstant(NumBits, DL, MVT::i32);1535 1536    if (LHS.getOpcode() == ISD::SRL || LHS.getOpcode() == ISD::SRA) {1537      // We have a 'srl/and' pair, extract the effective start bit and length1538      Val = LHS.getNode()->getOperand(0);1539      Start = LHS.getNode()->getOperand(1);1540      ConstantSDNode *StartConst = dyn_cast<ConstantSDNode>(Start);1541      if (StartConst) {1542        uint64_t StartVal = StartConst->getZExtValue();1543        // How many "good" bits do we have left?  "good" is defined here as bits1544        // that exist in the original value, not shifted in.1545        int64_t GoodBits = Start.getValueSizeInBits() - StartVal;1546        if (NumBits > GoodBits) {1547          // Do not handle the case where bits have been shifted in. In theory1548          // we could handle this, but the cost is likely higher than just1549          // emitting the srl/and pair.1550          return false;1551        }1552        Start = CurDAG->getTargetConstant(StartVal, DL, MVT::i32);1553      } else {1554        // Do not handle the case where the shift amount (can be zero if no srl1555        // was found) is not constant. We could handle this case, but it would1556        // require run-time logic that would be more expensive than just1557        // emitting the srl/and pair.1558        return false;1559      }1560    } else {1561      // Do not handle the case where the LHS of the and is not a shift. While1562      // it would be trivial to handle this case, it would just transform1563      // 'and' -> 'bfe', but 'and' has higher-throughput.1564      return false;1565    }1566  } else if (N->getOpcode() == ISD::SRL || N->getOpcode() == ISD::SRA) {1567    if (LHS->getOpcode() == ISD::AND) {1568      ConstantSDNode *ShiftCnst = dyn_cast<ConstantSDNode>(RHS);1569      if (!ShiftCnst) {1570        // Shift amount must be constant1571        return false;1572      }1573 1574      uint64_t ShiftAmt = ShiftCnst->getZExtValue();1575 1576      SDValue AndLHS = LHS->getOperand(0);1577      SDValue AndRHS = LHS->getOperand(1);1578 1579      // Canonicalize the AND to have the mask on the RHS1580      if (isa<ConstantSDNode>(AndLHS)) {1581        std::swap(AndLHS, AndRHS);1582      }1583 1584      ConstantSDNode *MaskCnst = dyn_cast<ConstantSDNode>(AndRHS);1585      if (!MaskCnst) {1586        // Mask must be constant1587        return false;1588      }1589 1590      uint64_t MaskVal = MaskCnst->getZExtValue();1591      uint64_t NumZeros;1592      uint64_t NumBits;1593      if (isMask_64(MaskVal)) {1594        NumZeros = 0;1595        // The number of bits in the result bitfield will be the number of1596        // trailing ones (the AND) minus the number of bits we shift off1597        NumBits = llvm::countr_one(MaskVal) - ShiftAmt;1598      } else if (isShiftedMask_64(MaskVal)) {1599        NumZeros = llvm::countr_zero(MaskVal);1600        unsigned NumOnes = llvm::countr_one(MaskVal >> NumZeros);1601        // The number of bits in the result bitfield will be the number of1602        // trailing zeros plus the number of set bits in the mask minus the1603        // number of bits we shift off1604        NumBits = NumZeros + NumOnes - ShiftAmt;1605      } else {1606        // This is not a mask we can handle1607        return false;1608      }1609 1610      if (ShiftAmt < NumZeros) {1611        // Handling this case would require extra logic that would make this1612        // transformation non-profitable1613        return false;1614      }1615 1616      Val = AndLHS;1617      Start = CurDAG->getTargetConstant(ShiftAmt, DL, MVT::i32);1618      Len = CurDAG->getTargetConstant(NumBits, DL, MVT::i32);1619 1620      // If pre-shift AND includes the sign bit in the bitfield, we must use1621      // signed BFE to replicate that bit during bitfield extraction. If the1622      // sign bit is not part of the mask, unsigned BFE will zero out upper bits1623      // of the result1624      if (N->getOpcode() == ISD::SRA)1625        IsSigned = (ShiftAmt + NumBits) == Val.getValueSizeInBits();1626    } else if (LHS->getOpcode() == ISD::SHL) {1627      // Here, we have a pattern like:1628      //1629      // (sra (shl val, NN), MM)1630      // or1631      // (srl (shl val, NN), MM)1632      //1633      // If MM >= NN, we can efficiently optimize this with bfe1634      Val = LHS->getOperand(0);1635 1636      SDValue ShlRHS = LHS->getOperand(1);1637      ConstantSDNode *ShlCnst = dyn_cast<ConstantSDNode>(ShlRHS);1638      if (!ShlCnst) {1639        // Shift amount must be constant1640        return false;1641      }1642      uint64_t InnerShiftAmt = ShlCnst->getZExtValue();1643 1644      SDValue ShrRHS = RHS;1645      ConstantSDNode *ShrCnst = dyn_cast<ConstantSDNode>(ShrRHS);1646      if (!ShrCnst) {1647        // Shift amount must be constant1648        return false;1649      }1650      uint64_t OuterShiftAmt = ShrCnst->getZExtValue();1651 1652      // To avoid extra codegen and be profitable, we need Outer >= Inner1653      if (OuterShiftAmt < InnerShiftAmt) {1654        return false;1655      }1656 1657      // If the outer shift is more than the type size, we have no bitfield to1658      // extract (since we also check that the inner shift is <= the outer shift1659      // then this also implies that the inner shift is < the type size)1660      if (OuterShiftAmt >= Val.getValueSizeInBits()) {1661        return false;1662      }1663 1664      Start = CurDAG->getTargetConstant(OuterShiftAmt - InnerShiftAmt, DL,1665                                        MVT::i32);1666      Len = CurDAG->getTargetConstant(Val.getValueSizeInBits() - OuterShiftAmt,1667                                      DL, MVT::i32);1668 1669      if (N->getOpcode() == ISD::SRA) {1670        // If we have a arithmetic right shift, we need to use the signed bfe1671        // variant1672        IsSigned = true;1673      }1674    } else {1675      // No can do...1676      return false;1677    }1678  } else {1679    // No can do...1680    return false;1681  }1682 1683 1684  unsigned Opc;1685  // For the BFE operations we form here from "and" and "srl", always use the1686  // unsigned variants.1687  if (Val.getValueType() == MVT::i32) {1688    if (IsSigned) {1689      Opc = NVPTX::BFE_S32rii;1690    } else {1691      Opc = NVPTX::BFE_U32rii;1692    }1693  } else if (Val.getValueType() == MVT::i64) {1694    if (IsSigned) {1695      Opc = NVPTX::BFE_S64rii;1696    } else {1697      Opc = NVPTX::BFE_U64rii;1698    }1699  } else {1700    // We cannot handle this type1701    return false;1702  }1703 1704  SDValue Ops[] = {1705    Val, Start, Len1706  };1707 1708  ReplaceNode(N, CurDAG->getMachineNode(Opc, DL, N->getVTList(), Ops));1709  return true;1710}1711 1712// Select bf16/bf16v2 FADD, FSUB, FMUL as fma on targets with only fma1713bool NVPTXDAGToDAGISel::tryBF16ArithToFMA(SDNode *N) {1714  EVT VT = SDValue(N, 0).getValueType();1715  if (VT.getScalarType() != MVT::bf16)1716    return false;1717 1718  const NVPTXSubtarget *STI = TM.getSubtargetImpl();1719  if (STI->hasNativeBF16Support(N->getOpcode()))1720    return false;1721 1722  const bool IsVec = VT.isVector();1723  assert(!IsVec || VT.getVectorNumElements() == 2);1724  SDLoc DL(N);1725  SDValue N0 = N->getOperand(0);1726  SDValue N1 = N->getOperand(1);1727  SmallVector<SDValue, 3> Operands;1728  auto GetConstant = [&](float Value) -> SDValue {1729    // BF16 immediates must be legalized to integer register values1730    APFloat APF(Value);1731    bool LosesInfo;1732    APF.convert(APFloat::BFloat(), APFloat::rmNearestTiesToEven, &LosesInfo);1733    assert(!LosesInfo);1734    if (IsVec) {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),1739                     0);1740    }1741    auto Const = CurDAG->getTargetConstantFP(APF, DL, VT);1742    return SDValue(CurDAG->getMachineNode(NVPTX::MOV_BF16_i, DL, VT, Const), 0);1743  };1744 1745  switch (N->getOpcode()) {1746  case ISD::FADD:1747    // add(a, b) -> fma(a, 1.0, b)1748    Operands = {N0, GetConstant(1.0), N1};1749    break;1750  case ISD::FSUB:1751    // sub(a, b) -> fma(b, -1.0, a)1752    Operands = {N1, GetConstant(-1.0), N0};1753    break;1754  case ISD::FMUL:1755    // mul(a, b) -> fma(a, b, -0.0)1756    // NOTE: The identity is -0, not 0, because -0 + 0 == 0 for floats1757    Operands = {N0, N1, GetConstant(-0.0)};1758    break;1759  default:1760    llvm_unreachable("Unexpected opcode");1761  };1762 1763  int Opcode = IsVec ? NVPTX::FMA_BF16x2rrr : NVPTX::FMA_BF16rrr;1764  MachineSDNode *FMA = CurDAG->getMachineNode(Opcode, DL, VT, Operands);1765  ReplaceNode(N, FMA);1766  return true;1767}1768 1769SDValue NVPTXDAGToDAGISel::selectPossiblyImm(SDValue V) {1770  if (V.getOpcode() == ISD::BITCAST)1771    V = V.getOperand(0);1772 1773  if (auto *CN = dyn_cast<ConstantSDNode>(V))1774    return CurDAG->getTargetConstant(CN->getAPIntValue(), SDLoc(V),1775                                     V.getValueType());1776  if (auto *CN = dyn_cast<ConstantFPSDNode>(V))1777    return CurDAG->getTargetConstantFP(CN->getValueAPF(), SDLoc(V),1778                                       V.getValueType());1779  return V;1780}1781 1782/// SelectInlineAsmMemoryOperand - Implement addressing mode selection for1783/// inline asm expressions.1784bool NVPTXDAGToDAGISel::SelectInlineAsmMemoryOperand(1785    const SDValue &Op, InlineAsm::ConstraintCode ConstraintID,1786    std::vector<SDValue> &OutOps) {1787  switch (ConstraintID) {1788  default:1789    return true;1790  case InlineAsm::ConstraintCode::m: { // memory1791    const auto [Base, Offset] = selectADDR(Op, CurDAG);1792    OutOps.push_back(Base);1793    OutOps.push_back(Offset);1794    return false;1795  }1796  }1797  return true;1798}1799 1800void NVPTXDAGToDAGISel::SelectV2I64toI128(SDNode *N) {1801  // Lower a CopyToReg with two 64-bit inputs1802  // Dst:i128, lo:i64, hi:i641803  //1804  // CopyToReg Dst, lo, hi;1805  //1806  // ==>1807  //1808  // tmp = V2I64toI128 {lo, hi};1809  // CopyToReg Dst, tmp;1810  SDValue Dst = N->getOperand(1);1811  SDValue Lo = N->getOperand(2);1812  SDValue Hi = N->getOperand(3);1813 1814  SDLoc DL(N);1815  SDNode *Mov =1816      CurDAG->getMachineNode(NVPTX::V2I64toI128, DL, MVT::i128, {Lo, Hi});1817 1818  SmallVector<SDValue, 4> NewOps(N->getNumOperands() - 1);1819  NewOps[0] = N->getOperand(0);1820  NewOps[1] = Dst;1821  NewOps[2] = SDValue(Mov, 0);1822  if (N->getNumOperands() == 5)1823    NewOps[3] = N->getOperand(4);1824  SDValue NewValue = CurDAG->getNode(ISD::CopyToReg, DL, SmallVector<EVT>(N->values()), NewOps);1825 1826  ReplaceNode(N, NewValue.getNode());1827}1828 1829void NVPTXDAGToDAGISel::SelectI128toV2I64(SDNode *N) {1830  // Lower CopyFromReg from a 128-bit regs to two 64-bit regs1831  // Dst:i128, Src:i1281832  //1833  // {lo, hi} = CopyFromReg Src1834  //1835  // ==>1836  //1837  // {lo, hi} = I128toV2I64 Src1838  //1839  SDValue Ch = N->getOperand(0);1840  SDValue Src = N->getOperand(1);1841  SDValue Glue = N->getOperand(2);1842  SDLoc DL(N);1843 1844  // Add Glue and Ch to the operands and results to avoid break the execution1845  // order1846  SDNode *Mov = CurDAG->getMachineNode(1847      NVPTX::I128toV2I64, DL,1848      {MVT::i64, MVT::i64, Ch.getValueType(), Glue.getValueType()},1849      {Src, Ch, Glue});1850 1851  ReplaceNode(N, Mov);1852}1853 1854bool NVPTXDAGToDAGISel::tryFence(SDNode *N) {1855  SDLoc DL(N);1856  assert(N->getOpcode() == ISD::ATOMIC_FENCE);1857  unsigned int FenceOp =1858      getFenceOp(NVPTX::Ordering(N->getConstantOperandVal(1)),1859                 Scopes[N->getConstantOperandVal(2)], Subtarget);1860  SDValue Chain = N->getOperand(0);1861  SDNode *FenceNode = CurDAG->getMachineNode(FenceOp, DL, MVT::Other, Chain);1862  ReplaceNode(N, FenceNode);1863  return true;1864}1865 1866NVPTXScopes::NVPTXScopes(LLVMContext &C) : Context(&C) {1867  Scopes[C.getOrInsertSyncScopeID("singlethread")] = NVPTX::Scope::Thread;1868  Scopes[C.getOrInsertSyncScopeID("")] = NVPTX::Scope::System;1869  Scopes[C.getOrInsertSyncScopeID("block")] = NVPTX::Scope::Block;1870  Scopes[C.getOrInsertSyncScopeID("cluster")] = NVPTX::Scope::Cluster;1871  Scopes[C.getOrInsertSyncScopeID("device")] = NVPTX::Scope::Device;1872}1873 1874NVPTX::Scope NVPTXScopes::operator[](SyncScope::ID ID) const {1875  if (Scopes.empty())1876    llvm_unreachable("NVPTX Scopes must be initialized before calling "1877                     "NVPTXScopes::operator[]");1878 1879  auto S = Scopes.find(ID);1880  if (S == Scopes.end()) {1881    auto scopeName = Context->getSyncScopeName(ID);1882    assert(scopeName.has_value() && "Scope name must exist.");1883 1884    // Build list of supported syncscopes programmatically1885    SmallVector<StringRef> supportedScopes;1886    for (const auto &Entry : Scopes) {1887      if (auto name = Context->getSyncScopeName(Entry.first))1888        supportedScopes.push_back(name->empty() ? "<empty string>" : *name);1889    }1890 1891    reportFatalUsageError(1892        formatv("NVPTX backend does not support syncscope \"{0}\" (ID={1}).\n"1893                "Supported syncscopes are: {2}.",1894                scopeName.value(), int(ID),1895                make_range(supportedScopes.begin(), supportedScopes.end())));1896  }1897  return S->second;1898}1899 1900bool NVPTXScopes::empty() const { return Scopes.size() == 0; }1901 1902#define CP_ASYNC_BULK_TENSOR_OPCODE(dir, dim, mode, is_s32, suffix)            \1903  (is_s32                                                                      \1904       ? NVPTX::CP_ASYNC_BULK_TENSOR_##dir##_##dim##_SHARED32_##mode##suffix   \1905       : NVPTX::CP_ASYNC_BULK_TENSOR_##dir##_##dim##_##mode##suffix)1906 1907#define GET_CP_ASYNC_BULK_TENSOR_OPCODE_S2G_RED(dim, mode, is_ch, is_s32)      \1908  (is_ch ? (CP_ASYNC_BULK_TENSOR_OPCODE(RED, dim, mode, is_s32, _CH))          \1909         : (CP_ASYNC_BULK_TENSOR_OPCODE(RED, dim, mode, is_s32, )))1910 1911static unsigned GetCpAsyncBulkTensorS2GReductionOpcode(size_t Dim,1912                                                       bool IsShared32,1913                                                       bool IsCacheHint,1914                                                       bool IsIm2Col) {1915  if (IsIm2Col) {1916    switch (Dim) {1917    case 3:1918      return GET_CP_ASYNC_BULK_TENSOR_OPCODE_S2G_RED(3D, IM2COL, IsCacheHint,1919                                                     IsShared32);1920    case 4:1921      return GET_CP_ASYNC_BULK_TENSOR_OPCODE_S2G_RED(4D, IM2COL, IsCacheHint,1922                                                     IsShared32);1923    case 5:1924      return GET_CP_ASYNC_BULK_TENSOR_OPCODE_S2G_RED(5D, IM2COL, IsCacheHint,1925                                                     IsShared32);1926    default:1927      llvm_unreachable("Invalid Dimension in im2col mode for "1928                       "GetCpAsyncBulkTensorS2GReductionOpcode.");1929    }1930  } else {1931    switch (Dim) {1932    case 1:1933      return GET_CP_ASYNC_BULK_TENSOR_OPCODE_S2G_RED(1D, TILE, IsCacheHint,1934                                                     IsShared32);1935    case 2:1936      return GET_CP_ASYNC_BULK_TENSOR_OPCODE_S2G_RED(2D, TILE, IsCacheHint,1937                                                     IsShared32);1938    case 3:1939      return GET_CP_ASYNC_BULK_TENSOR_OPCODE_S2G_RED(3D, TILE, IsCacheHint,1940                                                     IsShared32);1941    case 4:1942      return GET_CP_ASYNC_BULK_TENSOR_OPCODE_S2G_RED(4D, TILE, IsCacheHint,1943                                                     IsShared32);1944    case 5:1945      return GET_CP_ASYNC_BULK_TENSOR_OPCODE_S2G_RED(5D, TILE, IsCacheHint,1946                                                     IsShared32);1947    default:1948      llvm_unreachable("Invalid Dimension in tile mode for "1949                       "GetCpAsyncBulkTensorS2GReductionOpcode.");1950    }1951  }1952}1953 1954void NVPTXDAGToDAGISel::SelectCpAsyncBulkTensorReduceCommon(SDNode *N,1955                                                            unsigned RedOp,1956                                                            bool IsIm2Col) {1957  // We have {Chain, Intrinsic-ID} followed by the actual intrisic args:1958  // src, dst, dims{d0...dN}, cache_hint, cache_hint_flag1959  // NumOperands = {Chain, IID} + {Actual intrinsic args}1960  //             = {2}          + {4 + dims}1961  size_t NumOps = N->getNumOperands();1962  size_t NumDims = NumOps - 6;1963  bool IsCacheHint = N->getConstantOperandVal(NumOps - 1) == 1;1964  size_t NumArgs = NumDims + (IsCacheHint ? 3 : 2); // src, dst, cache_hint1965 1966  SDLoc DL(N);1967  SmallVector<SDValue, 12> Ops(N->ops().slice(2, NumArgs));1968  Ops.push_back(getI32Imm(RedOp, DL)); // Reduction Op1969  Ops.push_back(N->getOperand(0));     // Chain operand1970 1971  bool IsShared32 =1972      CurDAG->getDataLayout().getPointerSizeInBits(ADDRESS_SPACE_SHARED) == 32;1973  unsigned Opcode = GetCpAsyncBulkTensorS2GReductionOpcode(1974      NumDims, IsShared32, IsCacheHint, IsIm2Col);1975  ReplaceNode(N, CurDAG->getMachineNode(Opcode, DL, N->getVTList(), Ops));1976}1977 1978#define TCGEN05_ST_OPCODE(SHAPE, NUM)                                          \1979  (enableUnpack ? NVPTX::TCGEN05_ST_##SHAPE##_##NUM##_UNPACK                   \1980                : NVPTX::TCGEN05_ST_##SHAPE##_##NUM)1981 1982static unsigned getTcgen05StOpcode(unsigned IID, bool enableUnpack) {1983  switch (IID) {1984  case Intrinsic::nvvm_tcgen05_st_16x64b_x1:1985    return TCGEN05_ST_OPCODE(16x64b, x1);1986  case Intrinsic::nvvm_tcgen05_st_16x64b_x2:1987    return TCGEN05_ST_OPCODE(16x64b, x2);1988  case Intrinsic::nvvm_tcgen05_st_16x64b_x4:1989    return TCGEN05_ST_OPCODE(16x64b, x4);1990  case Intrinsic::nvvm_tcgen05_st_16x64b_x8:1991    return TCGEN05_ST_OPCODE(16x64b, x8);1992  case Intrinsic::nvvm_tcgen05_st_16x64b_x16:1993    return TCGEN05_ST_OPCODE(16x64b, x16);1994  case Intrinsic::nvvm_tcgen05_st_16x64b_x32:1995    return TCGEN05_ST_OPCODE(16x64b, x32);1996  case Intrinsic::nvvm_tcgen05_st_16x64b_x64:1997    return TCGEN05_ST_OPCODE(16x64b, x64);1998  case Intrinsic::nvvm_tcgen05_st_16x64b_x128:1999    return TCGEN05_ST_OPCODE(16x64b, x128);2000  case Intrinsic::nvvm_tcgen05_st_16x128b_x1:2001    return TCGEN05_ST_OPCODE(16x128b, x1);2002  case Intrinsic::nvvm_tcgen05_st_16x128b_x2:2003    return TCGEN05_ST_OPCODE(16x128b, x2);2004  case Intrinsic::nvvm_tcgen05_st_16x128b_x4:2005    return TCGEN05_ST_OPCODE(16x128b, x4);2006  case Intrinsic::nvvm_tcgen05_st_16x128b_x8:2007    return TCGEN05_ST_OPCODE(16x128b, x8);2008  case Intrinsic::nvvm_tcgen05_st_16x128b_x16:2009    return TCGEN05_ST_OPCODE(16x128b, x16);2010  case Intrinsic::nvvm_tcgen05_st_16x128b_x32:2011    return TCGEN05_ST_OPCODE(16x128b, x32);2012  case Intrinsic::nvvm_tcgen05_st_16x128b_x64:2013    return TCGEN05_ST_OPCODE(16x128b, x64);2014  case Intrinsic::nvvm_tcgen05_st_16x256b_x1:2015    return TCGEN05_ST_OPCODE(16x256b, x1);2016  case Intrinsic::nvvm_tcgen05_st_16x256b_x2:2017    return TCGEN05_ST_OPCODE(16x256b, x2);2018  case Intrinsic::nvvm_tcgen05_st_16x256b_x4:2019    return TCGEN05_ST_OPCODE(16x256b, x4);2020  case Intrinsic::nvvm_tcgen05_st_16x256b_x8:2021    return TCGEN05_ST_OPCODE(16x256b, x8);2022  case Intrinsic::nvvm_tcgen05_st_16x256b_x16:2023    return TCGEN05_ST_OPCODE(16x256b, x16);2024  case Intrinsic::nvvm_tcgen05_st_16x256b_x32:2025    return TCGEN05_ST_OPCODE(16x256b, x32);2026  case Intrinsic::nvvm_tcgen05_st_16x32bx2_x1:2027    return TCGEN05_ST_OPCODE(16x32bx2, x1);2028  case Intrinsic::nvvm_tcgen05_st_16x32bx2_x2:2029    return TCGEN05_ST_OPCODE(16x32bx2, x2);2030  case Intrinsic::nvvm_tcgen05_st_16x32bx2_x4:2031    return TCGEN05_ST_OPCODE(16x32bx2, x4);2032  case Intrinsic::nvvm_tcgen05_st_16x32bx2_x8:2033    return TCGEN05_ST_OPCODE(16x32bx2, x8);2034  case Intrinsic::nvvm_tcgen05_st_16x32bx2_x16:2035    return TCGEN05_ST_OPCODE(16x32bx2, x16);2036  case Intrinsic::nvvm_tcgen05_st_16x32bx2_x32:2037    return TCGEN05_ST_OPCODE(16x32bx2, x32);2038  case Intrinsic::nvvm_tcgen05_st_16x32bx2_x64:2039    return TCGEN05_ST_OPCODE(16x32bx2, x64);2040  case Intrinsic::nvvm_tcgen05_st_16x32bx2_x128:2041    return TCGEN05_ST_OPCODE(16x32bx2, x128);2042  case Intrinsic::nvvm_tcgen05_st_32x32b_x1:2043    return TCGEN05_ST_OPCODE(32x32b, x1);2044  case Intrinsic::nvvm_tcgen05_st_32x32b_x2:2045    return TCGEN05_ST_OPCODE(32x32b, x2);2046  case Intrinsic::nvvm_tcgen05_st_32x32b_x4:2047    return TCGEN05_ST_OPCODE(32x32b, x4);2048  case Intrinsic::nvvm_tcgen05_st_32x32b_x8:2049    return TCGEN05_ST_OPCODE(32x32b, x8);2050  case Intrinsic::nvvm_tcgen05_st_32x32b_x16:2051    return TCGEN05_ST_OPCODE(32x32b, x16);2052  case Intrinsic::nvvm_tcgen05_st_32x32b_x32:2053    return TCGEN05_ST_OPCODE(32x32b, x32);2054  case Intrinsic::nvvm_tcgen05_st_32x32b_x64:2055    return TCGEN05_ST_OPCODE(32x32b, x64);2056  case Intrinsic::nvvm_tcgen05_st_32x32b_x128:2057    return TCGEN05_ST_OPCODE(32x32b, x128);2058  }2059  llvm_unreachable("unhandled tcgen05.st lowering");2060}2061 2062void NVPTXDAGToDAGISel::SelectTcgen05St(SDNode *N, bool hasOffset) {2063  if (!Subtarget->hasTcgen05InstSupport())2064    report_fatal_error(2065        "tcgen05.st is not supported on this architecture variant");2066 2067  SDLoc DL(N);2068  unsigned IID = cast<ConstantSDNode>(N->getOperand(1))->getZExtValue();2069 2070  SmallVector<SDValue, 128> Operands = {2071      N->getOperand(2) // taddr2072  };2073 2074  if (hasOffset)2075    Operands.push_back(CurDAG->getTargetConstant(2076        cast<ConstantSDNode>(N->getOperand(3))->getZExtValue(), DL,2077        MVT::i32)); // Offset2078 2079  for (unsigned I = hasOffset ? 4 : 3; I < (N->getNumOperands() - 1); I++)2080    Operands.push_back(N->getOperand(I));2081 2082  bool enableUnpack =2083      cast<ConstantSDNode>(N->getOperand(N->getNumOperands() - 1))2084          ->getZExtValue();2085 2086  Operands.push_back(N->getOperand(0)); // Chain2087  ReplaceNode(N, CurDAG->getMachineNode(getTcgen05StOpcode(IID, enableUnpack),2088                                        DL, N->getVTList(), Operands));2089}2090 2091bool NVPTXDAGToDAGISel::tryIntrinsicVoid(SDNode *N) {2092  unsigned IID = N->getConstantOperandVal(1);2093  using TMARedTy = llvm::nvvm::TMAReductionOp;2094  auto CastTy = [](TMARedTy Op) { return static_cast<unsigned>(Op); };2095  switch (IID) {2096  default:2097    return false;2098  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_add_tile_1d:2099  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_add_tile_2d:2100  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_add_tile_3d:2101  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_add_tile_4d:2102  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_add_tile_5d:2103    SelectCpAsyncBulkTensorReduceCommon(N, CastTy(TMARedTy::ADD));2104    return true;2105  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_add_im2col_3d:2106  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_add_im2col_4d:2107  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_add_im2col_5d:2108    SelectCpAsyncBulkTensorReduceCommon(N, CastTy(TMARedTy::ADD),2109                                        /*IsIm2Col=*/true);2110    return true;2111  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_min_tile_1d:2112  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_min_tile_2d:2113  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_min_tile_3d:2114  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_min_tile_4d:2115  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_min_tile_5d:2116    SelectCpAsyncBulkTensorReduceCommon(N, CastTy(TMARedTy::MIN));2117    return true;2118  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_min_im2col_3d:2119  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_min_im2col_4d:2120  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_min_im2col_5d:2121    SelectCpAsyncBulkTensorReduceCommon(N, CastTy(TMARedTy::MIN),2122                                        /*IsIm2Col=*/true);2123    return true;2124  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_max_tile_1d:2125  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_max_tile_2d:2126  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_max_tile_3d:2127  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_max_tile_4d:2128  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_max_tile_5d:2129    SelectCpAsyncBulkTensorReduceCommon(N, CastTy(TMARedTy::MAX));2130    return true;2131  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_max_im2col_3d:2132  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_max_im2col_4d:2133  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_max_im2col_5d:2134    SelectCpAsyncBulkTensorReduceCommon(N, CastTy(TMARedTy::MAX),2135                                        /*IsIm2Col=*/true);2136    return true;2137  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_inc_tile_1d:2138  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_inc_tile_2d:2139  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_inc_tile_3d:2140  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_inc_tile_4d:2141  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_inc_tile_5d:2142    SelectCpAsyncBulkTensorReduceCommon(N, CastTy(TMARedTy::INC));2143    return true;2144  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_inc_im2col_3d:2145  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_inc_im2col_4d:2146  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_inc_im2col_5d:2147    SelectCpAsyncBulkTensorReduceCommon(N, CastTy(TMARedTy::INC),2148                                        /*IsIm2Col=*/true);2149    return true;2150  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_dec_tile_1d:2151  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_dec_tile_2d:2152  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_dec_tile_3d:2153  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_dec_tile_4d:2154  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_dec_tile_5d:2155    SelectCpAsyncBulkTensorReduceCommon(N, CastTy(TMARedTy::DEC));2156    return true;2157  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_dec_im2col_3d:2158  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_dec_im2col_4d:2159  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_dec_im2col_5d:2160    SelectCpAsyncBulkTensorReduceCommon(N, CastTy(TMARedTy::DEC),2161                                        /*IsIm2Col=*/true);2162    return true;2163  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_and_tile_1d:2164  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_and_tile_2d:2165  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_and_tile_3d:2166  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_and_tile_4d:2167  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_and_tile_5d:2168    SelectCpAsyncBulkTensorReduceCommon(N, CastTy(TMARedTy::AND));2169    return true;2170  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_and_im2col_3d:2171  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_and_im2col_4d:2172  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_and_im2col_5d:2173    SelectCpAsyncBulkTensorReduceCommon(N, CastTy(TMARedTy::AND),2174                                        /*IsIm2Col=*/true);2175    return true;2176  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_or_tile_1d:2177  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_or_tile_2d:2178  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_or_tile_3d:2179  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_or_tile_4d:2180  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_or_tile_5d:2181    SelectCpAsyncBulkTensorReduceCommon(N, CastTy(TMARedTy::OR));2182    return true;2183  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_or_im2col_3d:2184  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_or_im2col_4d:2185  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_or_im2col_5d:2186    SelectCpAsyncBulkTensorReduceCommon(N, CastTy(TMARedTy::OR),2187                                        /*IsIm2Col=*/true);2188    return true;2189  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_xor_tile_1d:2190  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_xor_tile_2d:2191  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_xor_tile_3d:2192  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_xor_tile_4d:2193  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_xor_tile_5d:2194    SelectCpAsyncBulkTensorReduceCommon(N, CastTy(TMARedTy::XOR));2195    return true;2196  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_xor_im2col_3d:2197  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_xor_im2col_4d:2198  case Intrinsic::nvvm_cp_async_bulk_tensor_reduce_xor_im2col_5d:2199    SelectCpAsyncBulkTensorReduceCommon(N, CastTy(TMARedTy::XOR),2200                                        /*IsIm2Col=*/true);2201    return true;2202 2203  case Intrinsic::nvvm_tcgen05_st_16x64b_x1:2204  case Intrinsic::nvvm_tcgen05_st_16x64b_x2:2205  case Intrinsic::nvvm_tcgen05_st_16x64b_x4:2206  case Intrinsic::nvvm_tcgen05_st_16x64b_x8:2207  case Intrinsic::nvvm_tcgen05_st_16x64b_x16:2208  case Intrinsic::nvvm_tcgen05_st_16x64b_x32:2209  case Intrinsic::nvvm_tcgen05_st_16x64b_x64:2210  case Intrinsic::nvvm_tcgen05_st_16x64b_x128:2211  case Intrinsic::nvvm_tcgen05_st_32x32b_x1:2212  case Intrinsic::nvvm_tcgen05_st_32x32b_x2:2213  case Intrinsic::nvvm_tcgen05_st_32x32b_x4:2214  case Intrinsic::nvvm_tcgen05_st_32x32b_x8:2215  case Intrinsic::nvvm_tcgen05_st_32x32b_x16:2216  case Intrinsic::nvvm_tcgen05_st_32x32b_x32:2217  case Intrinsic::nvvm_tcgen05_st_32x32b_x64:2218  case Intrinsic::nvvm_tcgen05_st_32x32b_x128:2219  case Intrinsic::nvvm_tcgen05_st_16x128b_x1:2220  case Intrinsic::nvvm_tcgen05_st_16x128b_x2:2221  case Intrinsic::nvvm_tcgen05_st_16x128b_x4:2222  case Intrinsic::nvvm_tcgen05_st_16x128b_x8:2223  case Intrinsic::nvvm_tcgen05_st_16x128b_x16:2224  case Intrinsic::nvvm_tcgen05_st_16x128b_x32:2225  case Intrinsic::nvvm_tcgen05_st_16x128b_x64:2226  case Intrinsic::nvvm_tcgen05_st_16x256b_x1:2227  case Intrinsic::nvvm_tcgen05_st_16x256b_x2:2228  case Intrinsic::nvvm_tcgen05_st_16x256b_x4:2229  case Intrinsic::nvvm_tcgen05_st_16x256b_x8:2230  case Intrinsic::nvvm_tcgen05_st_16x256b_x16:2231  case Intrinsic::nvvm_tcgen05_st_16x256b_x32: {2232    SelectTcgen05St(N);2233    return true;2234  }2235 2236  case Intrinsic::nvvm_tcgen05_st_16x32bx2_x1:2237  case Intrinsic::nvvm_tcgen05_st_16x32bx2_x2:2238  case Intrinsic::nvvm_tcgen05_st_16x32bx2_x4:2239  case Intrinsic::nvvm_tcgen05_st_16x32bx2_x8:2240  case Intrinsic::nvvm_tcgen05_st_16x32bx2_x16:2241  case Intrinsic::nvvm_tcgen05_st_16x32bx2_x32:2242  case Intrinsic::nvvm_tcgen05_st_16x32bx2_x64:2243  case Intrinsic::nvvm_tcgen05_st_16x32bx2_x128: {2244    SelectTcgen05St(N, /*  hasOffset */ true);2245    return true;2246  }2247  }2248}2249 2250void NVPTXDAGToDAGISel::selectAtomicSwap128(SDNode *N) {2251  MemSDNode *AN = cast<MemSDNode>(N);2252  SDLoc dl(N);2253 2254  const SDValue Chain = N->getOperand(0);2255  const auto [Base, Offset] = selectADDR(N->getOperand(1), CurDAG);2256  SmallVector<SDValue, 5> Ops{Base, Offset};2257  Ops.append(N->op_begin() + 2, N->op_end());2258  Ops.append({2259      getI32Imm(getMemOrder(AN), dl),2260      getI32Imm(getAtomicScope(AN), dl),2261      getI32Imm(getAddrSpace(AN), dl),2262      Chain,2263  });2264 2265  assert(N->getOpcode() == NVPTXISD::ATOMIC_CMP_SWAP_B128 ||2266         N->getOpcode() == NVPTXISD::ATOMIC_SWAP_B128);2267  unsigned Opcode = N->getOpcode() == NVPTXISD::ATOMIC_SWAP_B1282268                        ? NVPTX::ATOM_EXCH_B1282269                        : NVPTX::ATOM_CAS_B128;2270 2271  auto *ATOM = CurDAG->getMachineNode(Opcode, dl, N->getVTList(), Ops);2272  CurDAG->setNodeMemRefs(ATOM, AN->getMemOperand());2273 2274  ReplaceNode(N, ATOM);2275}2276