LLVM 24.0.0git
NVPTXISelDAGToDAG.cpp
Go to the documentation of this file.
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-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines an instruction selector for the NVPTX target.
10//
11//===----------------------------------------------------------------------===//
12
14#include "NVPTX.h"
15#include "NVPTXISelLowering.h"
17#include "NVPTXTargetMachine.h"
18#include "NVPTXUtilities.h"
19#include "llvm/ADT/APInt.h"
20#include "llvm/ADT/MapVector.h"
22#include "llvm/ADT/Twine.h"
28#include "llvm/IR/Constants.h"
30#include "llvm/IR/InlineAsm.h"
32#include "llvm/IR/Intrinsics.h"
33#include "llvm/IR/IntrinsicsNVPTX.h"
34#include "llvm/IR/LLVMContext.h"
35#include "llvm/IR/Metadata.h"
43#include <optional>
44
45using namespace llvm;
46
47#define DEBUG_TYPE "nvptx-isel"
48#define PASS_NAME "NVPTX DAG->DAG Pattern Instruction Selection"
49
50static cl::opt<bool>
51 EnableRsqrtOpt("nvptx-rsqrt-approx-opt", cl::init(true), cl::Hidden,
52 cl::desc("Enable reciprocal sqrt optimization"));
53
54// FIXME: This is a WAR to recover lost performance from #155024.
55// We still need to investigate the regression and find a more permanent
56// solution.
57static cl::opt<bool> EnableMADWide("nvptx-mad-wide-opt", cl::init(false),
59 cl::desc("Enable MAD wide optimization"));
60
61namespace {
62
63struct NVPTXScopes {
64 NVPTXScopes() = default;
65 NVPTXScopes(LLVMContext &C, const Triple &T);
66 NVPTX::Scope operator[](SyncScope::ID ID) const;
67 bool empty() const;
68
69private:
71 LLVMContext *Context = nullptr;
72};
73
74enum class NVPTXMemCacheHintInstruction { Ld, St, Atom };
75
76struct NVPTXMemCacheHintAccess {
77 NVPTXMemCacheHintInstruction Instruction;
78 NVPTX::AddressSpace AddrSpace;
79 unsigned NumElts;
80 unsigned EltWidth;
81 bool IsVolatile;
82};
83
84struct NVPTXMemCacheHintOperands {
85 SDValue EvictionAndPrefetchHint;
86 SDValue CachePolicyReg;
87};
88
89class NVPTXDAGToDAGISel : public SelectionDAGISel {
90 const NVPTXTargetMachine &TM;
91
92 NVPTX::DivPrecisionLevel getDivF32Level(const SDNode *N) const;
93 bool usePrecSqrtF32(const SDNode *N) const;
94 bool useF32FTZ() const;
95 bool allowFMA() const;
96 bool doRsqrtOpt() const;
97 bool doMADWideOpt() const;
98
99 NVPTXScopes Scopes{};
100
101public:
102 NVPTXDAGToDAGISel() = delete;
103
104 explicit NVPTXDAGToDAGISel(NVPTXTargetMachine &tm, CodeGenOptLevel OptLevel);
105
106 bool runOnMachineFunction(MachineFunction &MF) override;
107 const NVPTXSubtarget *Subtarget = nullptr;
108
109 bool SelectInlineAsmMemoryOperand(const SDValue &Op,
110 InlineAsm::ConstraintCode ConstraintID,
111 std::vector<SDValue> &OutOps) override;
112
113private:
114// Include the pieces autogenerated from the target description.
115#include "NVPTXGenDAGISel.inc"
116
117 void Select(SDNode *N) override;
118 bool tryIntrinsicChain(SDNode *N);
119 bool tryIntrinsicVoid(SDNode *N);
120 bool tryLoad(SDNode *N);
121 bool tryLoadVector(SDNode *N);
122 bool tryLDU(SDNode *N);
123 bool tryLDG(MemSDNode *N);
124 bool tryStore(SDNode *N);
125 bool tryStoreVector(SDNode *N);
126 bool tryFence(SDNode *N);
127 bool tryBFE(SDNode *N);
128 bool tryBF16ArithToFMA(SDNode *N);
129 bool SelectSETP_F16X2(SDNode *N);
130 bool SelectSETP_BF16X2(SDNode *N);
131 bool tryUNPACK_VECTOR(SDNode *N);
132 bool tryEXTRACT_VECTOR_ELEMENT(SDNode *N);
133 void PostprocessISelDAG() override;
134 void SelectV2I64toI128(SDNode *N);
135 void SelectI128toV2I64(SDNode *N);
136 void SelectTcgen05Ld(SDNode *N, bool hasOffset = false);
137 void SelectTcgen05St(SDNode *N, bool hasOffset = false);
138 void selectAtomicSwap128(SDNode *N);
139
140 inline SDValue getI32Imm(unsigned Imm, const SDLoc &DL) {
141 return CurDAG->getTargetConstant(Imm, DL, MVT::i32);
142 }
143 NVPTX::Ordering getMemOrder(const MemSDNode *N) const;
144 NVPTX::Scope getAtomicScope(const MemSDNode *N) const;
145
146 bool SelectADDR(SDValue Addr, SDValue &Base, SDValue &Offset);
147 bool SelectFAbs(SDValue N, SDValue &Src);
148 SDValue getPTXCmpMode(const CondCodeSDNode &CondCode);
149 SDValue selectPossiblyImm(SDValue V);
150
151 // Returns the encoded eviction/prefetch hint and cache policy register for a
152 // memory operation. Hints unsupported by the subtarget or address space are
153 // dropped. If L2::cache_hint is active, returns the hint with
154 // L2CacheHintBit set and a register containing the 64-bit cache policy
155 // value. Otherwise returns NOREG for the policy operand.
156 NVPTXMemCacheHintOperands
157 getMemCacheHintOperands(const MemSDNode *N, NVPTXMemCacheHintAccess Access,
158 const SDLoc &DL, bool EmitDiagnostics = true);
159
160 // Returns the Memory Order and Scope that the PTX memory instruction should
161 // use.
162 std::pair<NVPTX::Ordering, NVPTX::Scope>
163 getMemInstOrderingScope(MemSDNode *N);
164
165 NVPTX::Scope getOperationScope(MemSDNode *N, NVPTX::Ordering O) const;
166
167public:
168 static NVPTX::AddressSpace getAddrSpace(const MemSDNode *N);
169};
170
171class NVPTXDAGToDAGISelLegacy : public SelectionDAGISelLegacy {
172public:
173 static char ID;
174 explicit NVPTXDAGToDAGISelLegacy(NVPTXTargetMachine &tm,
175 CodeGenOptLevel OptLevel);
176};
177
178} // end anonymous namespace
179
180/// createNVPTXISelDag - This pass converts a legalized DAG into a
181/// NVPTX-specific DAG, ready for instruction scheduling.
183 llvm::CodeGenOptLevel OptLevel) {
184 return new NVPTXDAGToDAGISelLegacy(TM, OptLevel);
185}
186
187NVPTXDAGToDAGISelLegacy::NVPTXDAGToDAGISelLegacy(NVPTXTargetMachine &tm,
188 CodeGenOptLevel OptLevel)
190 ID, std::make_unique<NVPTXDAGToDAGISel>(tm, OptLevel)) {}
191
192char NVPTXDAGToDAGISelLegacy::ID = 0;
193
194INITIALIZE_PASS(NVPTXDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false)
195
197 CodeGenOptLevel OptLevel)
198 : SelectionDAGISelPass(std::make_unique<NVPTXDAGToDAGISel>(TM, OptLevel)) {}
199
200NVPTXDAGToDAGISel::NVPTXDAGToDAGISel(NVPTXTargetMachine &tm,
201 CodeGenOptLevel OptLevel)
202 : SelectionDAGISel(tm, OptLevel), TM(tm) {}
203
204bool NVPTXDAGToDAGISel::runOnMachineFunction(MachineFunction &MF) {
205 Subtarget = &MF.getSubtarget<NVPTXSubtarget>();
206 Scopes = NVPTXScopes(MF.getFunction().getContext(),
209}
210
212NVPTXDAGToDAGISel::getDivF32Level(const SDNode *N) const {
213 return Subtarget->getTargetLowering()->getDivF32Level(*MF, *N);
214}
215
216bool NVPTXDAGToDAGISel::usePrecSqrtF32(const SDNode *N) const {
217 return Subtarget->getTargetLowering()->usePrecSqrtF32(N);
218}
219
220bool NVPTXDAGToDAGISel::useF32FTZ() const {
221 return Subtarget->getTargetLowering()->useF32FTZ(*MF);
222}
223
224bool NVPTXDAGToDAGISel::allowFMA() const {
225 const NVPTXTargetLowering *TL = Subtarget->getTargetLowering();
226 return TL->allowFMA(*MF, OptLevel);
227}
228
229bool NVPTXDAGToDAGISel::doRsqrtOpt() const { return EnableRsqrtOpt; }
230
231bool NVPTXDAGToDAGISel::doMADWideOpt() const { return EnableMADWide; }
232
233/// Select - Select instructions not customized! Used for
234/// expanded, promoted and normal instructions.
235void NVPTXDAGToDAGISel::Select(SDNode *N) {
236
237 if (N->isMachineOpcode()) {
238 N->setNodeId(-1);
239 return; // Already selected.
240 }
241
242 switch (N->getOpcode()) {
243 case ISD::LOAD:
244 case ISD::ATOMIC_LOAD:
245 case NVPTXISD::MLoad:
246 if (tryLoad(N))
247 return;
248 break;
249 case ISD::STORE:
251 if (tryStore(N))
252 return;
253 break;
255 if (tryFence(N))
256 return;
257 break;
259 tryUNPACK_VECTOR(N);
260 return;
262 if (tryEXTRACT_VECTOR_ELEMENT(N))
263 return;
264 break;
266 SelectSETP_F16X2(N);
267 return;
269 SelectSETP_BF16X2(N);
270 return;
271 case NVPTXISD::LoadV2:
272 case NVPTXISD::LoadV4:
273 case NVPTXISD::LoadV8:
274 if (tryLoadVector(N))
275 return;
276 break;
277 case NVPTXISD::LDUV2:
278 case NVPTXISD::LDUV4:
279 if (tryLDU(N))
280 return;
281 break;
285 if (tryStoreVector(N))
286 return;
287 break;
289 if (tryIntrinsicChain(N))
290 return;
291 break;
293 if (tryIntrinsicVoid(N))
294 return;
295 break;
296 case ISD::AND:
297 case ISD::SRA:
298 case ISD::SRL:
299 // Try to select BFE
300 if (tryBFE(N))
301 return;
302 break;
303 case ISD::CopyToReg: {
304 if (N->getOperand(1).getValueType() == MVT::i128) {
305 SelectV2I64toI128(N);
306 return;
307 }
308 break;
309 }
310 case ISD::CopyFromReg: {
311 if (N->getOperand(1).getValueType() == MVT::i128) {
312 SelectI128toV2I64(N);
313 return;
314 }
315 break;
316 }
319 selectAtomicSwap128(N);
320 return;
321 case ISD::FADD:
322 case ISD::FMUL:
323 case ISD::FSUB:
324 if (tryBF16ArithToFMA(N))
325 return;
326 break;
327 default:
328 break;
329 }
330 SelectCode(N);
331}
332
333#define TCGEN05_LD_OPCODE(SHAPE, NUM) \
334 (enablePack ? NVPTX::TCGEN05_LD_##SHAPE##_##NUM##_PACK \
335 : NVPTX::TCGEN05_LD_##SHAPE##_##NUM)
336
337static unsigned getTcgen05LdOpcode(unsigned IID, bool enablePack) {
338 switch (IID) {
339 case Intrinsic::nvvm_tcgen05_ld_16x64b_x1:
340 return TCGEN05_LD_OPCODE(16x64b, x1);
341 case Intrinsic::nvvm_tcgen05_ld_16x64b_x2:
342 return TCGEN05_LD_OPCODE(16x64b, x2);
343 case Intrinsic::nvvm_tcgen05_ld_16x64b_x4:
344 return TCGEN05_LD_OPCODE(16x64b, x4);
345 case Intrinsic::nvvm_tcgen05_ld_16x64b_x8:
346 return TCGEN05_LD_OPCODE(16x64b, x8);
347 case Intrinsic::nvvm_tcgen05_ld_16x64b_x16:
348 return TCGEN05_LD_OPCODE(16x64b, x16);
349 case Intrinsic::nvvm_tcgen05_ld_16x64b_x32:
350 return TCGEN05_LD_OPCODE(16x64b, x32);
351 case Intrinsic::nvvm_tcgen05_ld_16x64b_x64:
352 return TCGEN05_LD_OPCODE(16x64b, x64);
353 case Intrinsic::nvvm_tcgen05_ld_16x64b_x128:
354 return TCGEN05_LD_OPCODE(16x64b, x128);
355 case Intrinsic::nvvm_tcgen05_ld_16x128b_x1:
356 return TCGEN05_LD_OPCODE(16x128b, x1);
357 case Intrinsic::nvvm_tcgen05_ld_16x128b_x2:
358 return TCGEN05_LD_OPCODE(16x128b, x2);
359 case Intrinsic::nvvm_tcgen05_ld_16x128b_x4:
360 return TCGEN05_LD_OPCODE(16x128b, x4);
361 case Intrinsic::nvvm_tcgen05_ld_16x128b_x8:
362 return TCGEN05_LD_OPCODE(16x128b, x8);
363 case Intrinsic::nvvm_tcgen05_ld_16x128b_x16:
364 return TCGEN05_LD_OPCODE(16x128b, x16);
365 case Intrinsic::nvvm_tcgen05_ld_16x128b_x32:
366 return TCGEN05_LD_OPCODE(16x128b, x32);
367 case Intrinsic::nvvm_tcgen05_ld_16x128b_x64:
368 return TCGEN05_LD_OPCODE(16x128b, x64);
369 case Intrinsic::nvvm_tcgen05_ld_16x256b_x1:
370 return TCGEN05_LD_OPCODE(16x256b, x1);
371 case Intrinsic::nvvm_tcgen05_ld_16x256b_x2:
372 return TCGEN05_LD_OPCODE(16x256b, x2);
373 case Intrinsic::nvvm_tcgen05_ld_16x256b_x4:
374 return TCGEN05_LD_OPCODE(16x256b, x4);
375 case Intrinsic::nvvm_tcgen05_ld_16x256b_x8:
376 return TCGEN05_LD_OPCODE(16x256b, x8);
377 case Intrinsic::nvvm_tcgen05_ld_16x256b_x16:
378 return TCGEN05_LD_OPCODE(16x256b, x16);
379 case Intrinsic::nvvm_tcgen05_ld_16x256b_x32:
380 return TCGEN05_LD_OPCODE(16x256b, x32);
381 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x1:
382 return TCGEN05_LD_OPCODE(16x32bx2, x1);
383 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x2:
384 return TCGEN05_LD_OPCODE(16x32bx2, x2);
385 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x4:
386 return TCGEN05_LD_OPCODE(16x32bx2, x4);
387 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x8:
388 return TCGEN05_LD_OPCODE(16x32bx2, x8);
389 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x16:
390 return TCGEN05_LD_OPCODE(16x32bx2, x16);
391 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x32:
392 return TCGEN05_LD_OPCODE(16x32bx2, x32);
393 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x64:
394 return TCGEN05_LD_OPCODE(16x32bx2, x64);
395 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x128:
396 return TCGEN05_LD_OPCODE(16x32bx2, x128);
397 case Intrinsic::nvvm_tcgen05_ld_32x32b_x1:
398 return TCGEN05_LD_OPCODE(32x32b, x1);
399 case Intrinsic::nvvm_tcgen05_ld_32x32b_x2:
400 return TCGEN05_LD_OPCODE(32x32b, x2);
401 case Intrinsic::nvvm_tcgen05_ld_32x32b_x4:
402 return TCGEN05_LD_OPCODE(32x32b, x4);
403 case Intrinsic::nvvm_tcgen05_ld_32x32b_x8:
404 return TCGEN05_LD_OPCODE(32x32b, x8);
405 case Intrinsic::nvvm_tcgen05_ld_32x32b_x16:
406 return TCGEN05_LD_OPCODE(32x32b, x16);
407 case Intrinsic::nvvm_tcgen05_ld_32x32b_x32:
408 return TCGEN05_LD_OPCODE(32x32b, x32);
409 case Intrinsic::nvvm_tcgen05_ld_32x32b_x64:
410 return TCGEN05_LD_OPCODE(32x32b, x64);
411 case Intrinsic::nvvm_tcgen05_ld_32x32b_x128:
412 return TCGEN05_LD_OPCODE(32x32b, x128);
413 }
414 llvm_unreachable("unhandled tcgen05.ld lowering");
415}
416
417void NVPTXDAGToDAGISel::SelectTcgen05Ld(SDNode *N, bool hasOffset) {
418 if (!Subtarget->hasTcgen05InstSupport())
420 "tcgen05.ld is not supported on this architecture variant");
421
422 SDLoc DL(N);
423 unsigned IID = cast<ConstantSDNode>(N->getOperand(1))->getZExtValue();
424
425 if (hasOffset) {
426 bool enablePack = cast<ConstantSDNode>(N->getOperand(4))->getZExtValue();
427 auto OffsetNode = CurDAG->getTargetConstant(
428 cast<ConstantSDNode>(N->getOperand(3))->getZExtValue(), DL, MVT::i32);
429 ReplaceNode(N, CurDAG->getMachineNode(
430 getTcgen05LdOpcode(IID, enablePack), DL, N->getVTList(),
431 {N->getOperand(2), OffsetNode, N->getOperand(0)}));
432 } else {
433 bool enablePack = cast<ConstantSDNode>(N->getOperand(3))->getZExtValue();
434 ReplaceNode(N, CurDAG->getMachineNode(
435 getTcgen05LdOpcode(IID, enablePack), DL, N->getVTList(),
436 {N->getOperand(2), N->getOperand(0)}));
437 }
438}
439
440bool NVPTXDAGToDAGISel::tryIntrinsicChain(SDNode *N) {
441 unsigned IID = N->getConstantOperandVal(1);
442 switch (IID) {
443 default:
444 return false;
445 case Intrinsic::nvvm_ldu_global_f:
446 case Intrinsic::nvvm_ldu_global_i:
447 case Intrinsic::nvvm_ldu_global_p:
448 return tryLDU(N);
449
450 case Intrinsic::nvvm_tcgen05_ld_16x64b_x1:
451 case Intrinsic::nvvm_tcgen05_ld_16x64b_x2:
452 case Intrinsic::nvvm_tcgen05_ld_16x64b_x4:
453 case Intrinsic::nvvm_tcgen05_ld_16x64b_x8:
454 case Intrinsic::nvvm_tcgen05_ld_16x64b_x16:
455 case Intrinsic::nvvm_tcgen05_ld_16x64b_x32:
456 case Intrinsic::nvvm_tcgen05_ld_16x64b_x64:
457 case Intrinsic::nvvm_tcgen05_ld_16x64b_x128:
458 case Intrinsic::nvvm_tcgen05_ld_16x128b_x1:
459 case Intrinsic::nvvm_tcgen05_ld_16x128b_x2:
460 case Intrinsic::nvvm_tcgen05_ld_16x128b_x4:
461 case Intrinsic::nvvm_tcgen05_ld_16x128b_x16:
462 case Intrinsic::nvvm_tcgen05_ld_16x128b_x32:
463 case Intrinsic::nvvm_tcgen05_ld_16x128b_x64:
464 case Intrinsic::nvvm_tcgen05_ld_16x256b_x1:
465 case Intrinsic::nvvm_tcgen05_ld_16x128b_x8:
466 case Intrinsic::nvvm_tcgen05_ld_16x256b_x2:
467 case Intrinsic::nvvm_tcgen05_ld_16x256b_x4:
468 case Intrinsic::nvvm_tcgen05_ld_16x256b_x8:
469 case Intrinsic::nvvm_tcgen05_ld_16x256b_x16:
470 case Intrinsic::nvvm_tcgen05_ld_16x256b_x32:
471 case Intrinsic::nvvm_tcgen05_ld_32x32b_x1:
472 case Intrinsic::nvvm_tcgen05_ld_32x32b_x2:
473 case Intrinsic::nvvm_tcgen05_ld_32x32b_x4:
474 case Intrinsic::nvvm_tcgen05_ld_32x32b_x8:
475 case Intrinsic::nvvm_tcgen05_ld_32x32b_x16:
476 case Intrinsic::nvvm_tcgen05_ld_32x32b_x32:
477 case Intrinsic::nvvm_tcgen05_ld_32x32b_x64:
478 case Intrinsic::nvvm_tcgen05_ld_32x32b_x128: {
479 SelectTcgen05Ld(N);
480 return true;
481 }
482
483 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x1:
484 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x2:
485 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x4:
486 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x8:
487 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x16:
488 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x32:
489 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x64:
490 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x128: {
491 SelectTcgen05Ld(N, /* hasOffset */ true);
492 return true;
493 }
494 }
495}
496
497// Map ISD:CONDCODE value to appropriate CmpMode expected by
498// NVPTXInstPrinter::printCmpMode()
499SDValue NVPTXDAGToDAGISel::getPTXCmpMode(const CondCodeSDNode &CondCode) {
501 const unsigned PTXCmpMode = [](ISD::CondCode CC) {
502 switch (CC) {
503 default:
504 llvm_unreachable("Unexpected condition code.");
505 case ISD::SETOEQ:
506 case ISD::SETEQ:
507 return CmpMode::EQ;
508 case ISD::SETOGT:
509 case ISD::SETGT:
510 return CmpMode::GT;
511 case ISD::SETOGE:
512 case ISD::SETGE:
513 return CmpMode::GE;
514 case ISD::SETOLT:
515 case ISD::SETLT:
516 return CmpMode::LT;
517 case ISD::SETOLE:
518 case ISD::SETLE:
519 return CmpMode::LE;
520 case ISD::SETONE:
521 case ISD::SETNE:
522 return CmpMode::NE;
523 case ISD::SETO:
524 return CmpMode::NUM;
525 case ISD::SETUO:
526 return CmpMode::NotANumber;
527 case ISD::SETUEQ:
528 return CmpMode::EQU;
529 case ISD::SETUGT:
530 return CmpMode::GTU;
531 case ISD::SETUGE:
532 return CmpMode::GEU;
533 case ISD::SETULT:
534 return CmpMode::LTU;
535 case ISD::SETULE:
536 return CmpMode::LEU;
537 case ISD::SETUNE:
538 return CmpMode::NEU;
539 }
540 }(CondCode.get());
541 return CurDAG->getTargetConstant(PTXCmpMode, SDLoc(), MVT::i32);
542}
543
544bool NVPTXDAGToDAGISel::SelectSETP_F16X2(SDNode *N) {
545 SDValue PTXCmpMode = getPTXCmpMode(*cast<CondCodeSDNode>(N->getOperand(2)));
546 SDLoc DL(N);
547 SDNode *SetP = CurDAG->getMachineNode(
548 NVPTX::SETP_f16x2, DL, MVT::i1, MVT::i1,
549 {N->getOperand(0), N->getOperand(1), PTXCmpMode,
550 CurDAG->getTargetConstant(useF32FTZ() ? 1 : 0, DL, MVT::i1)});
551 ReplaceNode(N, SetP);
552 return true;
553}
554
555bool NVPTXDAGToDAGISel::SelectSETP_BF16X2(SDNode *N) {
556 SDValue PTXCmpMode = getPTXCmpMode(*cast<CondCodeSDNode>(N->getOperand(2)));
557 SDLoc DL(N);
558 SDNode *SetP =
559 CurDAG->getMachineNode(NVPTX::SETP_bf16x2, DL, MVT::i1, MVT::i1,
560 {N->getOperand(0), N->getOperand(1), PTXCmpMode});
561 ReplaceNode(N, SetP);
562 return true;
563}
564
565bool NVPTXDAGToDAGISel::tryUNPACK_VECTOR(SDNode *N) {
566 SDValue Vector = N->getOperand(0);
567 MVT EltVT = N->getSimpleValueType(0);
568
569 MachineSDNode *N2 =
570 CurDAG->getMachineNode(NVPTX::I64toV2I32, SDLoc(N), EltVT, EltVT, Vector);
571
572 ReplaceNode(N, N2);
573 return true;
574}
575
576// Find all instances of extract_vector_elt that use this v2f16 vector
577// and coalesce them into a scattering move instruction.
578bool NVPTXDAGToDAGISel::tryEXTRACT_VECTOR_ELEMENT(SDNode *N) {
579 SDValue Vector = N->getOperand(0);
580
581 MVT VT = Vector.getSimpleValueType();
582 if (!(NVPTX::isPackedVectorTy(VT) && VT.getVectorNumElements() == 2))
583 return false;
584
585 unsigned Opcode;
586 if (VT.is32BitVector())
587 Opcode = NVPTX::I32toV2I16;
588 else if (VT.is64BitVector())
589 Opcode = NVPTX::I64toV2I32;
590 else
591 llvm_unreachable("Unhandled packed type");
592
593 // Find and record all uses of this vector that extract element 0 or 1.
595 for (auto *U : Vector.getNode()->users()) {
596 if (U->getOpcode() != ISD::EXTRACT_VECTOR_ELT)
597 continue;
598 if (U->getOperand(0) != Vector)
599 continue;
600 if (const ConstantSDNode *IdxConst =
601 dyn_cast<ConstantSDNode>(U->getOperand(1))) {
602 if (IdxConst->getZExtValue() == 0)
603 E0.push_back(U);
604 else if (IdxConst->getZExtValue() == 1)
605 E1.push_back(U);
606 else
607 llvm_unreachable("Invalid vector index.");
608 }
609 }
610
611 // There's no point scattering f16x2 if we only ever access one
612 // element of it.
613 if (E0.empty() || E1.empty())
614 return false;
615
616 // Merge (EltTy extractelt(V, 0), EltTy extractelt(V,1))
617 // into EltTy,EltTy Split[EltTy]x2(V)
618 MVT EltVT = VT.getVectorElementType();
619 SDNode *ScatterOp =
620 CurDAG->getMachineNode(Opcode, SDLoc(N), EltVT, EltVT, Vector);
621 for (auto *Node : E0)
622 ReplaceUses(SDValue(Node, 0), SDValue(ScatterOp, 0));
623 for (auto *Node : E1)
624 ReplaceUses(SDValue(Node, 0), SDValue(ScatterOp, 1));
625
626 return true;
627}
628
629static std::optional<unsigned> getI16ExtractIndex(const SDNode *N) {
630 if (!N->isMachineOpcode() || N->use_empty())
631 return std::nullopt;
632 switch (N->getMachineOpcode()) {
633 default:
634 return std::nullopt;
635 case NVPTX::CVT_u16_u32:
636 if (N->getConstantOperandVal(1) != NVPTX::PTXCvtMode::NONE)
637 return std::nullopt;
638 [[fallthrough]];
639 case NVPTX::I32toI16L:
640 case NVPTX::I32toI16L_Sink:
641 return 0;
642 case NVPTX::I32toI16H:
643 case NVPTX::I32toI16H_Sink:
644 return 1;
645 }
646}
647
648// Merge scalar truncations and individual vector extracts after selection, when
649// bitcasts no longer hide that they extract the same 16-bit halves.
650static void mergeI16Unpacks(SelectionDAG &DAG) {
651 auto Position = DAG.allnodes_begin();
652 // Replacing extracts can CSE downstream nodes, including the next node.
654 DAG, [&](SDNode *Deleted, SDNode *) {
656 ++Position;
657 });
658
659 bool Changed = false;
660 while (Position != DAG.allnodes_end()) {
661 SDNode *N = &*Position++;
662 if (!getI16ExtractIndex(N))
663 continue;
664 SDValue Word = N->getOperand(0);
665 SmallVector<SDValue, 2> Halves[2];
666 for (SDNode *User : Word->users()) {
667 std::optional<unsigned> Index = getI16ExtractIndex(User);
668 if (Index && User->getOperand(0) == Word)
669 Halves[*Index].emplace_back(User, 0);
670 }
671 if (Halves[0].empty() || Halves[1].empty())
672 continue;
673
674 SDNode *Scatter = DAG.getMachineNode(NVPTX::I32toV2I16, SDLoc(N), MVT::i16,
675 MVT::i16, Word);
676 for (unsigned Index : {0u, 1u})
677 for (SDValue V : Halves[Index])
678 DAG.ReplaceAllUsesOfValueWith(V, SDValue(Scatter, Index));
679 Changed = true;
680 }
681 if (Changed)
682 DAG.RemoveDeadNodes();
683}
684
685void NVPTXDAGToDAGISel::PostprocessISelDAG() { mergeI16Unpacks(*CurDAG); }
686
687NVPTX::AddressSpace NVPTXDAGToDAGISel::getAddrSpace(const MemSDNode *N) {
688 auto AS =
689 static_cast<NVPTX::AddressSpace>(N->getMemOperand()->getAddrSpace());
690 switch (AS) {
699 return AS;
700 }
701 llvm_unreachable("Unexpected address space");
702}
703
704NVPTX::Ordering NVPTXDAGToDAGISel::getMemOrder(const MemSDNode *N) const {
705 // No "sem" orderings for SM/PTX versions which do not support memory ordering
706 if (!Subtarget->hasMemoryOrdering())
708 auto Ordering = N->getMergedOrdering();
709 switch (Ordering) {
723 }
724 llvm_unreachable("Invalid atomic ordering");
725}
726
727// Clusters contain exactly 1 block on targets without cluster support.
729 if (S == NVPTX::Scope::Cluster && !T->hasClusters())
730 return NVPTX::Scope::Block;
731 return S;
732}
733
734NVPTX::Scope NVPTXDAGToDAGISel::getAtomicScope(const MemSDNode *N) const {
735 NVPTX::Scope Scope = resolveScope(Scopes[N->getSyncScopeID()], Subtarget);
736 if (!Subtarget->hasAtomScope()) {
737 if (Scope == NVPTX::Scope::System)
738 CurDAG->getContext()->diagnose(DiagnosticInfoUnsupported(
739 CurDAG->getMachineFunction().getFunction(),
740 "NVPTX system scope atomics require sm_60 or later",
741 N->getDebugLoc()));
743 }
744 return Scope;
745}
746
747namespace {
748
749static NVPTX::Ordering getInstructionOrdering(MemSDNode *N,
750 const NVPTXSubtarget *Subtarget) {
751 AtomicOrdering Ordering = N->getSuccessOrdering();
752 auto CodeAddrSpace = NVPTXDAGToDAGISel::getAddrSpace(N);
753
754 bool HasMemoryOrdering = Subtarget->hasMemoryOrdering();
755 bool HasRelaxedMMIO = Subtarget->hasRelaxedMMIO();
756
757 // clang-format off
758
759 // Lowering for Load/Store Operations (note: AcquireRelease Loads or Stores error).
760 // Note: uses of Relaxed in the Atomic column of this table refer
761 // to LLVM AtomicOrdering::Monotonic.
762 //
763 // | Atomic | Volatile | Statespace | PTX sm_60- | PTX sm_70+ |
764 // |---------|----------|--------------------|------------|------------------------------|
765 // | No | No | All | plain | .weak |
766 // | No | Yes | Generic,Shared, | .volatile | .volatile |
767 // | | | Global [0] | | |
768 // | No | Yes | Local (PTX 9.0-) | plain [1] | .weak [1] |
769 // | No | Yes | Local (PTX 9.1+) | .volatile | .volatile |
770 // | No | Yes | Const,Param | plain [1] | .weak [1] |
771 // | Unorder | Yes/No | All | == Relaxed | == Relaxed |
772 // | Relaxed | No | Generic,Shared, | .volatile | <atomic sem> |
773 // | | | Global [0] | | |
774 // | Other | No | Generic,Shared, | Error [2] | <atomic sem> |
775 // | | | Global [0] | | |
776 // | Yes | No | Local,Const,Param | plain [1] | .weak [1] |
777 // | Relaxed | Yes | Generic,Shared [0] | .volatile | .volatile |
778 // | Relaxed | Yes | Global [0] | .volatile | .mmio.relaxed.sys (PTX 8.2+) |
779 // | | | | | or .volatile (PTX 8.1-) |
780 // | Yes | Yes | Local (PTX 9.0-) | plain [1] | .weak [1] |
781 // | Yes | Yes | Local (PTX 9.1+) | .volatile | .volatile |
782 // | Relaxed | Yes | Const,Param | plain [1] | .weak [1] |
783 // | Other | Yes | Generic, Shared, | Error [2] | <atomic sem> [3] |
784 // | | | / Global [0] | | |
785
786 // Lowering of CUDA C++ SequentiallyConsistent Operations and Fences to PTX
787 // by following the ABI proven sound in:
788 // Lustig et al, A Formal Analysis of the NVIDIA PTX Memory Consistency Model, ASPLOS’19.
789 // https://dl.acm.org/doi/pdf/10.1145/3297858.3304043
790 //
791 // | CUDA C++ Atomic Operation or Atomic Fence | PTX Atomic Operation or Fence |
792 // |------------------------------------------------------|-------------------------------|
793 // | cuda::atomic_thread_fence | fence.sc.<scope>; |
794 // | (memory_order_seq_cst, cuda::thread_scope_<scope>) | |
795 // |------------------------------------------------------|-------------------------------|
796 // | cuda::atomic_load | fence.sc.<scope>; |
797 // | (memory_order_seq_cst, cuda::thread_scope_<scope>) | ld.acquire.<scope>; |
798 // |------------------------------------------------------|-------------------------------|
799 // | cuda::atomic_store | fence.sc.<scope>; |
800 // | (memory_order_seq_cst, cuda::thread_scope_<scope>) | st.release.<scope>; |
801 // |------------------------------------------------------|-------------------------------|
802 // | cuda::atomic_fetch_<op> | fence.sc.<scope>; |
803 // | (memory_order_seq_cst, cuda::thread_scope_<scope>) | atom.acq_rel.<scope>; |
804
805 // clang-format on
806
807 // [0]: volatile and atomics are only supported on global or shared
808 // memory locations, accessed via generic/shared/global pointers.
809 // PTX 9.1 adds volatile support on local ld/st.
810 // MMIO is only supported on global memory locations,
811 // accessed via generic/global pointers.
812 // TODO: Implement MMIO access via generic pointer to global.
813 // Currently implemented for global pointers only.
814
815 // [1]: Lowering volatile/atomic operations to non-volatile/non-atomic
816 // PTX instructions fails to preserve their C++ side-effects.
817 //
818 // Example (https://github.com/llvm/llvm-project/issues/62057):
819 //
820 // void example() {
821 // std::atomic<bool> True = true;
822 // while (True.load(std::memory_order_relaxed));
823 // }
824 //
825 // A C++ program that calls "example" is well-defined: the infinite loop
826 // performs an atomic operation. By lowering volatile/atomics to
827 // "weak" memory operations, we are transforming the above into:
828 //
829 // void undefined_behavior() {
830 // bool True = true;
831 // while (True);
832 // }
833 //
834 // which exhibits undefined behavior in both C++ and PTX.
835 //
836 // Calling "example" in CUDA C++ compiled for sm_60- exhibits undefined
837 // behavior due to lack of Independent Forward Progress. Lowering these
838 // to weak memory operations in sm_60- is therefore fine.
839 //
840 // TODO: Where direct volatile or atomic operations are unsupported,
841 // preserve the side-effect using the weak memory instruction and
842 // another instruction, such as a dead dummy volatile load.
843
844 if (CodeAddrSpace == NVPTX::AddressSpace::Local) {
845 // Local memory is private to a thread. Drop atomic ordering but preserve
846 // volatile accesses where supported.
847 return Subtarget->hasLocalVolatile() && N->isVolatile()
850 }
851
852 if (CodeAddrSpace == NVPTX::AddressSpace::Const ||
853 CodeAddrSpace == NVPTX::AddressSpace::EntryParam ||
854 CodeAddrSpace == NVPTX::AddressSpace::DeviceParam) {
856 }
857
858 // [2]: Atomics with Ordering different than Unordered or Relaxed are not
859 // supported on sm_60 and older; this includes volatile atomics.
860 if (!(Ordering == AtomicOrdering::NotAtomic ||
861 Ordering == AtomicOrdering::Unordered ||
862 Ordering == AtomicOrdering::Monotonic) &&
863 !HasMemoryOrdering) {
865 formatv("PTX does not support \"atomic\" for orderings different than"
866 "\"NotAtomic\" or \"Monotonic\" for sm_60 or older, but order "
867 "is: \"{}\".",
868 toIRString(Ordering)));
869 }
870
871 // [3]: TODO: these should eventually use .mmio<.atomic sem>; for now we drop
872 // the volatile semantics and preserve the atomic ones.
873
874 // Apart from local volatile accesses handled above, PTX atomics and volatile
875 // operations are only available in generic, global, or shared memory.
876 bool AddrSupportsVolatileOrAtomic =
877 (CodeAddrSpace == NVPTX::AddressSpace::Generic ||
878 CodeAddrSpace == NVPTX::AddressSpace::Global ||
879 CodeAddrSpace == NVPTX::AddressSpace::Shared ||
880 CodeAddrSpace == NVPTX::AddressSpace::SharedCluster);
881 if (!AddrSupportsVolatileOrAtomic)
883
884 bool UseRelaxedMMIO =
885 HasRelaxedMMIO && CodeAddrSpace == NVPTX::AddressSpace::Global;
886
887 switch (Ordering) {
889 return N->isVolatile() ? NVPTX::Ordering::Volatile
892 // We lower unordered in the exact same way as 'monotonic' to respect
893 // LLVM IR atomicity requirements.
895 if (N->isVolatile())
896 return UseRelaxedMMIO ? NVPTX::Ordering::RelaxedMMIO
898 else
899 return HasMemoryOrdering ? NVPTX::Ordering::Relaxed
901 // case AtomicOrdering::Consume: // If LLVM ever provides this, lower it to
902 // Acquire.
904 if (!N->readMem())
906 formatv("PTX only supports Acquire Ordering on reads: {}",
907 N->getOperationName()));
910 if (!N->writeMem())
912 formatv("PTX only supports Release Ordering on writes: {}",
913 N->getOperationName()));
917 formatv("NVPTX does not support AcquireRelease Ordering on "
918 "read-modify-write "
919 "yet and PTX does not support it on loads or stores: {}",
920 N->getOperationName()));
921 }
923 // LLVM-IR SequentiallyConsistent atomics map to a two-instruction PTX
924 // sequence including a "fence.sc.sco" and the memory instruction with an
925 // Ordering that differs from "sc": acq, rel, or acq_rel, depending on
926 // whether the memory operation is a read, write, or read-modify-write.
927 //
928 // This sets the ordering of the fence to SequentiallyConsistent, and
929 // sets the corresponding ordering for the instruction.
930 llvm_unreachable("seq_cst ordering should not reach this point, "
931 "is emulated in AtomicExpandPass");
932 }
933 }
935 formatv("NVPTX backend does not support AtomicOrdering \"{}\" yet.",
936 toIRString(Ordering)));
937}
938
939} // namespace
940
941NVPTX::Scope NVPTXDAGToDAGISel::getOperationScope(MemSDNode *N,
942 NVPTX::Ordering O) const {
943 switch (O) {
945 case NVPTX::Ordering::Volatile: // Non-atomic volatile operations
946 // NVPTX uses Thread scope as the scope of non-atomic operations.
949 // RelaxedMMIO operations are always system scope.
950 // If a RelaxedMMIO order was generated from an atomic volatile operation
951 // with a smaller thread scope, we bump it here to system scope.
958 auto S = Scopes[N->getSyncScopeID()];
959
960 S = resolveScope(S, Subtarget);
961
962 // If operation is volatile, then its scope is system.
963 return N->isVolatile() ? NVPTX::Scope::System : S;
964 }
965 llvm_unreachable("unhandled ordering");
966}
967
968static bool canLowerToLDG(const MemSDNode &N, const NVPTXSubtarget &Subtarget,
969 NVPTX::AddressSpace CodeAddrSpace) {
970 // We use ldg (i.e. ld.global.nc) for invariant loads from the global address
971 // space.
972 return Subtarget.hasLDG() && CodeAddrSpace == NVPTX::AddressSpace::Global &&
973 N.isInvariant();
974}
975
976static unsigned int getFenceOp(NVPTX::Ordering O, NVPTX::Scope S,
977 NVPTXSubtarget const *T) {
978 S = resolveScope(S, T);
979
980 // Fall back to .acq_rel if .acquire, .release is not supported.
981 if (!T->hasSplitAcquireAndReleaseFences() &&
984
985 switch (O) {
987 switch (S) {
989 return T->hasMemoryOrdering() ? NVPTX::atomic_thread_fence_acquire_sys
990 : NVPTX::INT_MEMBAR_SYS;
992 return T->hasMemoryOrdering() ? NVPTX::atomic_thread_fence_acquire_cta
993 : NVPTX::INT_MEMBAR_CTA;
995 return NVPTX::atomic_thread_fence_acquire_cluster;
997 return T->hasMemoryOrdering() ? NVPTX::atomic_thread_fence_acquire_gpu
998 : NVPTX::INT_MEMBAR_GL;
1002 formatv("Unsupported scope \"{}\" for acquire/release/acq_rel fence.",
1003 ScopeToString(S)));
1004 }
1005 break;
1007 switch (S) {
1009 return T->hasMemoryOrdering() ? NVPTX::atomic_thread_fence_release_sys
1010 : NVPTX::INT_MEMBAR_SYS;
1012 return T->hasMemoryOrdering() ? NVPTX::atomic_thread_fence_release_cta
1013 : NVPTX::INT_MEMBAR_CTA;
1015 return NVPTX::atomic_thread_fence_release_cluster;
1017 return T->hasMemoryOrdering() ? NVPTX::atomic_thread_fence_release_gpu
1018 : NVPTX::INT_MEMBAR_GL;
1022 formatv("Unsupported scope \"{}\" for acquire/release/acq_rel fence.",
1023 ScopeToString(S)));
1024 }
1025 break;
1027 switch (S) {
1029 return T->hasMemoryOrdering() ? NVPTX::atomic_thread_fence_acq_rel_sys
1030 : NVPTX::INT_MEMBAR_SYS;
1032 return T->hasMemoryOrdering() ? NVPTX::atomic_thread_fence_acq_rel_cta
1033 : NVPTX::INT_MEMBAR_CTA;
1035 return NVPTX::atomic_thread_fence_acq_rel_cluster;
1037 return T->hasMemoryOrdering() ? NVPTX::atomic_thread_fence_acq_rel_gpu
1038 : NVPTX::INT_MEMBAR_GL;
1042 formatv("Unsupported scope \"{}\" for acquire/release/acq_rel fence.",
1043 ScopeToString(S)));
1044 }
1045 break;
1046 }
1048 switch (S) {
1050 return T->hasMemoryOrdering() ? NVPTX::atomic_thread_fence_seq_cst_sys
1051 : NVPTX::INT_MEMBAR_SYS;
1053 return T->hasMemoryOrdering() ? NVPTX::atomic_thread_fence_seq_cst_cta
1054 : NVPTX::INT_MEMBAR_CTA;
1056 return NVPTX::atomic_thread_fence_seq_cst_cluster;
1058 return T->hasMemoryOrdering() ? NVPTX::atomic_thread_fence_seq_cst_gpu
1059 : NVPTX::INT_MEMBAR_GL;
1062 report_fatal_error(formatv("Unsupported scope \"{}\" for seq_cst fence.",
1063 ScopeToString(S)));
1064 }
1065 break;
1066 }
1072 formatv("Unsupported \"{}\" ordering and \"{}\" scope for fence.",
1073 OrderingToString(O), ScopeToString(S)));
1074 }
1075 llvm_unreachable("unhandled ordering");
1076}
1077
1078// Returns Memory Order and Scope of a memory instruction.
1079std::pair<NVPTX::Ordering, NVPTX::Scope>
1080NVPTXDAGToDAGISel::getMemInstOrderingScope(MemSDNode *N) {
1081 auto InstructionOrdering = getInstructionOrdering(N, Subtarget);
1082 auto Scope = getOperationScope(N, InstructionOrdering);
1083
1084 // Singlethread scope has no inter-thread synchronization requirements, so
1085 // the atomic operation is lowered as plain and the fence is skipped.
1086 // NotAtomic and Volatile operations naturally have Thread scope and must
1087 // preserve their ordering.
1088 if (Scope == NVPTX::Scope::Thread &&
1092
1093 return {InstructionOrdering, Scope};
1094}
1095
1096// Helper function template to reduce amount of boilerplate code for
1097// opcode selection.
1098static std::optional<unsigned>
1099pickOpcodeForVT(MVT::SimpleValueType VT, std::optional<unsigned> Opcode_i16,
1100 std::optional<unsigned> Opcode_i32,
1101 std::optional<unsigned> Opcode_i64) {
1102 switch (VT) {
1103 case MVT::f16:
1104 case MVT::i16:
1105 case MVT::bf16:
1106 return Opcode_i16;
1107 case MVT::v2f16:
1108 case MVT::v2bf16:
1109 case MVT::v2i16:
1110 case MVT::v4i8:
1111 case MVT::i32:
1112 case MVT::f32:
1113 return Opcode_i32;
1114 case MVT::v2f32:
1115 case MVT::v2i32:
1116 case MVT::i64:
1117 case MVT::f64:
1118 return Opcode_i64;
1119 default:
1120 return std::nullopt;
1121 }
1122}
1123
1124static inline bool isAddLike(const SDValue V) {
1125 return V.getOpcode() == ISD::ADD ||
1126 (V->getOpcode() == ISD::OR && V->getFlags().hasDisjoint());
1127}
1128
1130 if (N.getOpcode() == ISD::AssertAlign)
1131 N = N.getOperand(0);
1132 return N;
1133}
1134
1135// selectBaseADDR - Match a dag node which will serve as the base address for an
1136// ADDR operand pair.
1138 N = stripAssertAlign(N);
1139 if (const auto *GA = dyn_cast<GlobalAddressSDNode>(N))
1140 return DAG->getTargetGlobalAddress(GA->getGlobal(), SDLoc(N),
1141 GA->getValueType(0), GA->getOffset(),
1142 GA->getTargetFlags());
1143 if (const auto *ES = dyn_cast<ExternalSymbolSDNode>(N))
1144 return DAG->getTargetExternalSymbol(ES->getSymbol(), ES->getValueType(0),
1145 ES->getTargetFlags());
1146 if (const auto *FIN = dyn_cast<FrameIndexSDNode>(N))
1147 return DAG->getTargetFrameIndex(FIN->getIndex(), FIN->getValueType(0));
1148 if (N.getOpcode() == NVPTXISD::Symbol)
1149 return N.getOperand(0);
1150
1151 return N;
1152}
1153
1155 Addr = stripAssertAlign(Addr);
1156 APInt AccumulatedOffset(64u, 0);
1157 while (isAddLike(Addr)) {
1158 const auto *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1));
1159 if (!CN)
1160 break;
1161
1162 const APInt CI = CN->getAPIntValue().sext(64);
1163 if (!(CI + AccumulatedOffset).isSignedIntN(32))
1164 break;
1165
1166 AccumulatedOffset += CI;
1167 Addr = stripAssertAlign(Addr->getOperand(0));
1168 }
1169 return DAG->getSignedTargetConstant(AccumulatedOffset.getSExtValue(), DL,
1170 MVT::i32);
1171}
1172
1173static std::pair<SDValue, SDValue> selectADDR(SDValue Addr, SelectionDAG *DAG) {
1174 SDValue Offset = accumulateOffset(Addr, SDLoc(Addr), DAG);
1175 SDValue Base = selectBaseADDR(Addr, DAG);
1176 return {Base, Offset};
1177}
1178
1179// Select a pair of operands which represent a valid PTX address, this could be
1180// one of the following things:
1181// - [var] - Offset is simply set to 0
1182// - [reg] - Offset is simply set to 0
1183// - [reg+immOff]
1184// - [var+immOff]
1185// Note that immOff must fit into a 32-bit signed integer.
1186bool NVPTXDAGToDAGISel::SelectADDR(SDValue Addr, SDValue &Base,
1187 SDValue &Offset) {
1188 std::tie(Base, Offset) = selectADDR(Addr, CurDAG);
1189 return true;
1190}
1191
1193 Ctx.diagnose(DiagnosticInfoGeneric(
1194 Twine("invalid NVPTX !mem.cache_hint metadata: ") + Msg, DS_Warning));
1195}
1196
1197static std::optional<NVPTX::L1Eviction> parseL1Eviction(StringRef Str) {
1199 .Case("normal", NVPTX::L1Eviction::Normal)
1200 .Case("unchanged", NVPTX::L1Eviction::Unchanged)
1203 .Case("no_allocate", NVPTX::L1Eviction::NoAllocate)
1204 .Default(std::nullopt);
1205}
1206
1207static std::optional<NVPTX::L2Eviction> parseL2Eviction(StringRef Str) {
1209 .Case("normal", NVPTX::L2Eviction::Normal)
1212 .Default(std::nullopt);
1213}
1214
1215static std::optional<NVPTX::L2Prefetch> parseL2Prefetch(StringRef Str) {
1217 .Case("64B", NVPTX::L2Prefetch::Bytes64)
1220 .Default(std::nullopt);
1221}
1222
1223template <typename T>
1224static std::optional<T> parseMemCacheHintStringValue(
1225 LLVMContext &Ctx, StringRef Key, const Metadata *Value,
1226 std::optional<T> (*Parse)(StringRef), bool EmitDiagnostics) {
1227 const auto *Val = dyn_cast<MDString>(Value);
1228 if (!Val) {
1229 if (EmitDiagnostics)
1231 Twine("'") + Key + "' expects a string value");
1232 return std::nullopt;
1233 }
1234
1235 StringRef ValStr = Val->getString();
1236 auto Parsed = Parse(ValStr);
1237 if (!Parsed && EmitDiagnostics)
1238 emitInvalidMemCacheHint(Ctx, Twine("unknown value '") + ValStr + "' for '" +
1239 Key + "'");
1240 return Parsed;
1241}
1242
1244 return AddrSpace == NVPTX::AddressSpace::Global ||
1245 AddrSpace == NVPTX::AddressSpace::Generic;
1246}
1247
1248static bool isLdOrSt(NVPTXMemCacheHintAccess Access) {
1249 return Access.Instruction == NVPTXMemCacheHintInstruction::Ld ||
1250 Access.Instruction == NVPTXMemCacheHintInstruction::St;
1251}
1252
1253static bool isL1EvictionSupported(const NVPTXSubtarget &Subtarget,
1254 NVPTX::L1Eviction Eviction,
1255 NVPTXMemCacheHintAccess Access) {
1256 if (Eviction == NVPTX::L1Eviction::Normal)
1257 return true;
1258
1259 return isLdOrSt(Access) && !Access.IsVolatile &&
1260 Subtarget.hasL1EvictionHint();
1261}
1262
1263static bool isL2PrefetchSupported(const NVPTXSubtarget &Subtarget,
1265 NVPTXMemCacheHintAccess Access) {
1266 switch (Prefetch) {
1268 return true;
1270 return Access.Instruction == NVPTXMemCacheHintInstruction::Ld &&
1271 isGlobalOrGeneric(Access.AddrSpace) && Subtarget.hasL2Prefetch64B();
1273 return Access.Instruction == NVPTXMemCacheHintInstruction::Ld &&
1274 isGlobalOrGeneric(Access.AddrSpace) && Subtarget.hasL2Prefetch128B();
1276 return Access.Instruction == NVPTXMemCacheHintInstruction::Ld &&
1277 isGlobalOrGeneric(Access.AddrSpace) && Subtarget.hasL2Prefetch256B();
1278 }
1279 llvm_unreachable("Unexpected L2 prefetch hint");
1280}
1281
1282static bool isL2EvictionSupported(const NVPTXSubtarget &Subtarget,
1283 NVPTX::L2Eviction Eviction,
1284 NVPTXMemCacheHintAccess Access) {
1285 if (Eviction == NVPTX::L2Eviction::Normal)
1286 return true;
1287
1288 return isLdOrSt(Access) && !Access.IsVolatile &&
1289 Subtarget.hasL2EvictionHint() && isGlobalOrGeneric(Access.AddrSpace) &&
1290 ((Access.NumElts == 8 && Access.EltWidth == 32) ||
1291 (Access.NumElts == 4 && Access.EltWidth == 64));
1292}
1293
1294static bool isCachePolicySupported(const NVPTXSubtarget &Subtarget,
1295 NVPTXMemCacheHintAccess Access) {
1296 return !Access.IsVolatile && isGlobalOrGeneric(Access.AddrSpace) &&
1297 Subtarget.hasL2CacheHint();
1298}
1299
1300NVPTXMemCacheHintOperands NVPTXDAGToDAGISel::getMemCacheHintOperands(
1301 const MemSDNode *N, NVPTXMemCacheHintAccess Access, const SDLoc &DL,
1302 bool EmitDiagnostics) {
1303 LLVMContext &Ctx = *CurDAG->getContext();
1304 const MDNode *Node = N->getMemCacheHint();
1305 SDValue PolicyReg = CurDAG->getRegister(NVPTX::NoRegister, MVT::i64);
1306 if (!Node)
1307 return {getI32Imm(0, DL), PolicyReg};
1308 if (Node->getNumOperands() == 0) {
1309 if (EmitDiagnostics)
1310 emitInvalidMemCacheHint(Ctx, "empty hint node");
1311 return {getI32Imm(0, DL), PolicyReg};
1312 }
1313
1317 std::optional<uint64_t> CachePolicy;
1318
1319 for (unsigned I = 0; I + 1 < Node->getNumOperands(); I += 2) {
1320 const auto *Key = cast<MDString>(Node->getOperand(I));
1321 StringRef KeyStr = Key->getString();
1322 const Metadata *Value = Node->getOperand(I + 1).get();
1323
1324 if (KeyStr == "nvvm.l1_eviction") {
1325 auto ParsedL1 = parseMemCacheHintStringValue(
1326 Ctx, KeyStr, Value, parseL1Eviction, EmitDiagnostics);
1327 if (ParsedL1 && isL1EvictionSupported(*Subtarget, *ParsedL1, Access))
1328 L1 = *ParsedL1;
1329 continue;
1330 }
1331
1332 if (KeyStr == "nvvm.l2_eviction") {
1333 auto ParsedL2 = parseMemCacheHintStringValue(
1334 Ctx, KeyStr, Value, parseL2Eviction, EmitDiagnostics);
1335 if (ParsedL2 && isL2EvictionSupported(*Subtarget, *ParsedL2, Access))
1336 L2 = *ParsedL2;
1337 continue;
1338 }
1339
1340 if (KeyStr == "nvvm.l2_prefetch_size") {
1341 auto ParsedPrefetch = parseMemCacheHintStringValue(
1342 Ctx, KeyStr, Value, parseL2Prefetch, EmitDiagnostics);
1343 if (ParsedPrefetch &&
1344 isL2PrefetchSupported(*Subtarget, *ParsedPrefetch, Access))
1345 Prefetch = *ParsedPrefetch;
1346 continue;
1347 }
1348
1349 if (KeyStr == "nvvm.l2_cache_hint") {
1350 const auto *ValCI = mdconst::dyn_extract<ConstantInt>(Value);
1351 if (!ValCI) {
1352 if (EmitDiagnostics)
1354 Ctx, "'nvvm.l2_cache_hint' expects an integer value");
1355 } else if (isCachePolicySupported(*Subtarget, Access)) {
1356 CachePolicy = ValCI->getZExtValue();
1357 }
1358 continue;
1359 }
1360
1361 if (EmitDiagnostics)
1362 emitInvalidMemCacheHint(Ctx, Twine("unknown key '") + KeyStr + "'");
1363 }
1364
1365 unsigned EvictionAndPrefetchHint =
1367 if (CachePolicy) {
1368 SDValue PolicyConst = CurDAG->getTargetConstant(*CachePolicy, DL, MVT::i64);
1369 PolicyReg = SDValue(
1370 CurDAG->getMachineNode(NVPTX::MOV_B64_i, DL, MVT::i64, PolicyConst), 0);
1371 Bitfield::set<NVPTX::L2CacheHintBit>(EvictionAndPrefetchHint, true);
1372 }
1373
1374 return {getI32Imm(EvictionAndPrefetchHint, DL), PolicyReg};
1375}
1376
1377bool NVPTXDAGToDAGISel::tryLoad(SDNode *N) {
1379 assert(LD->readMem() && "Expected load");
1380
1381 // do not support pre/post inc/dec
1382 const LoadSDNode *PlainLoad = dyn_cast<LoadSDNode>(LD);
1383 if (PlainLoad && PlainLoad->isIndexed())
1384 return false;
1385
1386 // Address Space Setting
1387 const auto CodeAddrSpace = getAddrSpace(LD);
1388 if (canLowerToLDG(*LD, *Subtarget, CodeAddrSpace))
1389 return tryLDG(LD);
1390
1391 SDLoc DL(LD);
1392 SDValue Chain = N->getOperand(0);
1393 const auto [Ordering, Scope] = getMemInstOrderingScope(LD);
1394
1395 const unsigned FromTypeWidth = LD->getMemoryVT().getSizeInBits();
1396
1397 // Vector Setting
1398 const unsigned FromType =
1399 (PlainLoad && (PlainLoad->getExtensionType() == ISD::SEXTLOAD))
1402
1403 uint32_t UsedBytesMask;
1404 switch (N->getOpcode()) {
1405 case ISD::LOAD:
1406 case ISD::ATOMIC_LOAD:
1407 UsedBytesMask = UINT32_MAX;
1408 break;
1409 case NVPTXISD::MLoad:
1410 UsedBytesMask = N->getConstantOperandVal(3);
1411 break;
1412 default:
1413 llvm_unreachable("Unexpected opcode");
1414 }
1415
1416 assert(isPowerOf2_32(FromTypeWidth) && FromTypeWidth >= 8 &&
1417 FromTypeWidth <= 128 && "Invalid width for load");
1418
1419 const auto [Base, Offset] = selectADDR(N->getOperand(1), CurDAG);
1420 const auto [EvictionAndPrefetchHint, PolicyReg] = getMemCacheHintOperands(
1421 LD,
1422 {NVPTXMemCacheHintInstruction::Ld, CodeAddrSpace,
1423 /*NumElts=*/1, /*EltWidth=*/FromTypeWidth, LD->isVolatile()},
1424 DL);
1425
1426 // Create the machine instruction DAG
1427 SDValue Ops[] = {getI32Imm(Ordering, DL),
1428 getI32Imm(Scope, DL),
1429 getI32Imm(CodeAddrSpace, DL),
1430 getI32Imm(FromType, DL),
1431 getI32Imm(FromTypeWidth, DL),
1432 getI32Imm(UsedBytesMask, DL),
1433 Base,
1434 Offset,
1435 EvictionAndPrefetchHint,
1436 PolicyReg,
1437 Chain};
1438
1439 const MVT::SimpleValueType TargetVT = LD->getSimpleValueType(0).SimpleTy;
1440 const std::optional<unsigned> Opcode =
1441 pickOpcodeForVT(TargetVT, NVPTX::LD_i16, NVPTX::LD_i32, NVPTX::LD_i64);
1442 if (!Opcode)
1443 return false;
1444
1445 SDNode *NVPTXLD = CurDAG->getMachineNode(*Opcode, DL, LD->getVTList(), Ops);
1446 if (!NVPTXLD)
1447 return false;
1448
1449 MachineMemOperand *MemRef = LD->getMemOperand();
1450 CurDAG->setNodeMemRefs(cast<MachineSDNode>(NVPTXLD), {MemRef});
1451
1452 ReplaceNode(LD, NVPTXLD);
1453 return true;
1454}
1455
1456static unsigned getStoreVectorNumElts(SDNode *N) {
1457 switch (N->getOpcode()) {
1458 case NVPTXISD::StoreV2:
1459 return 2;
1460 case NVPTXISD::StoreV4:
1461 return 4;
1462 case NVPTXISD::StoreV8:
1463 return 8;
1464 default:
1465 llvm_unreachable("Unexpected opcode");
1466 }
1467}
1468
1469bool NVPTXDAGToDAGISel::tryLoadVector(SDNode *N) {
1471
1472 // Address Space Setting
1473 const auto CodeAddrSpace = getAddrSpace(LD);
1474 if (canLowerToLDG(*LD, *Subtarget, CodeAddrSpace))
1475 return tryLDG(LD);
1476
1477 const MVT EltVT = LD->getSimpleValueType(0);
1478 SDLoc DL(LD);
1479 SDValue Chain = LD->getChain();
1480 const auto [Ordering, Scope] = getMemInstOrderingScope(LD);
1481
1482 // Type Setting: fromType + fromTypeWidth
1483 //
1484 // Sign : ISD::SEXTLOAD
1485 // Unsign : ISD::ZEXTLOAD, ISD::NON_EXTLOAD or ISD::EXTLOAD and the
1486 // type is integer
1487 // Float : ISD::NON_EXTLOAD or ISD::EXTLOAD and the type is float
1488 // Read at least 8 bits (predicates are stored as 8-bit values)
1489 // Get the original LoadSDNode::getExtensionType() value
1490 const unsigned ExtensionType = N->getConstantOperandVal(4);
1491 const unsigned FromType = (ExtensionType == ISD::SEXTLOAD)
1493 : NVPTX::PTXLdStInstCode::Untyped;
1494
1495 const unsigned FromTypeWidth = getFromTypeWidthForLoad(LD);
1496 const uint32_t UsedBytesMask = N->getConstantOperandVal(3);
1497
1498 assert(!(EltVT.isVector() && ExtensionType != ISD::NON_EXTLOAD));
1499
1500 const auto [EvictionAndPrefetchHint, PolicyReg] =
1501 getMemCacheHintOperands(LD,
1502 {NVPTXMemCacheHintInstruction::Ld, CodeAddrSpace,
1503 /*NumElts=*/LD->getNumValues() - 1,
1504 /*EltWidth=*/FromTypeWidth, LD->isVolatile()},
1505 DL);
1506 const auto [Base, Offset] = selectADDR(N->getOperand(1), CurDAG);
1507 SDValue Ops[] = {getI32Imm(Ordering, DL),
1508 getI32Imm(Scope, DL),
1509 getI32Imm(CodeAddrSpace, DL),
1510 getI32Imm(FromType, DL),
1511 getI32Imm(FromTypeWidth, DL),
1512 getI32Imm(UsedBytesMask, DL),
1513 Base,
1514 Offset,
1515 EvictionAndPrefetchHint,
1516 PolicyReg,
1517 Chain};
1518
1519 std::optional<unsigned> Opcode;
1520 switch (N->getOpcode()) {
1521 default:
1522 llvm_unreachable("Unexpected opcode");
1523 case NVPTXISD::LoadV2:
1524 Opcode = pickOpcodeForVT(EltVT.SimpleTy, NVPTX::LDV_i16_v2,
1525 NVPTX::LDV_i32_v2, NVPTX::LDV_i64_v2);
1526 break;
1527 case NVPTXISD::LoadV4:
1528 Opcode = pickOpcodeForVT(EltVT.SimpleTy, NVPTX::LDV_i16_v4,
1529 NVPTX::LDV_i32_v4, NVPTX::LDV_i64_v4);
1530 break;
1531 case NVPTXISD::LoadV8:
1532 Opcode = pickOpcodeForVT(EltVT.SimpleTy, {/* no v8i16 */},
1533 NVPTX::LDV_i32_v8, {/* no v8i64 */});
1534 break;
1535 }
1536 if (!Opcode)
1537 return false;
1538
1539 SDNode *NVPTXLD = CurDAG->getMachineNode(*Opcode, DL, LD->getVTList(), Ops);
1540
1541 MachineMemOperand *MemRef = LD->getMemOperand();
1542 CurDAG->setNodeMemRefs(cast<MachineSDNode>(NVPTXLD), {MemRef});
1543
1544 ReplaceNode(LD, NVPTXLD);
1545 return true;
1546}
1547
1548bool NVPTXDAGToDAGISel::tryLDG(MemSDNode *LD) {
1549 SDLoc DL(LD);
1550
1551 unsigned ExtensionType;
1552 uint32_t UsedBytesMask;
1553 if (const auto *Load = dyn_cast<LoadSDNode>(LD)) {
1554 ExtensionType = Load->getExtensionType();
1555 UsedBytesMask = UINT32_MAX;
1556 } else {
1557 ExtensionType = LD->getConstantOperandVal(4);
1558 UsedBytesMask = LD->getConstantOperandVal(3);
1559 }
1560 const unsigned FromType = (ExtensionType == ISD::SEXTLOAD)
1562 : NVPTX::PTXLdStInstCode::Untyped;
1563
1564 const unsigned FromTypeWidth = getFromTypeWidthForLoad(LD);
1565
1566 assert(!(LD->getSimpleValueType(0).isVector() &&
1567 ExtensionType != ISD::NON_EXTLOAD));
1568
1569 const auto [Base, Offset] = selectADDR(LD->getOperand(1), CurDAG);
1570 const auto [EvictionAndPrefetchHint, PolicyReg] = getMemCacheHintOperands(
1571 LD,
1572 {NVPTXMemCacheHintInstruction::Ld, NVPTX::AddressSpace::Global,
1573 LD->getNumValues() - 1, FromTypeWidth, LD->isVolatile()},
1574 DL);
1575 SDValue Ops[] = {getI32Imm(FromType, DL),
1576 getI32Imm(FromTypeWidth, DL),
1577 getI32Imm(UsedBytesMask, DL),
1578 Base,
1579 Offset,
1580 EvictionAndPrefetchHint,
1581 PolicyReg,
1582 LD->getChain()};
1583
1584 const MVT::SimpleValueType TargetVT = LD->getSimpleValueType(0).SimpleTy;
1585 std::optional<unsigned> Opcode;
1586 switch (LD->getOpcode()) {
1587 default:
1588 llvm_unreachable("Unexpected opcode");
1589 case ISD::LOAD:
1590 Opcode = pickOpcodeForVT(TargetVT, NVPTX::LD_GLOBAL_NC_i16,
1591 NVPTX::LD_GLOBAL_NC_i32, NVPTX::LD_GLOBAL_NC_i64);
1592 break;
1593 case NVPTXISD::MLoad:
1594 Opcode = pickOpcodeForVT(TargetVT, std::nullopt, NVPTX::LD_GLOBAL_NC_i32,
1595 NVPTX::LD_GLOBAL_NC_i64);
1596 break;
1597 case NVPTXISD::LoadV2:
1598 Opcode =
1599 pickOpcodeForVT(TargetVT, NVPTX::LD_GLOBAL_NC_v2i16,
1600 NVPTX::LD_GLOBAL_NC_v2i32, NVPTX::LD_GLOBAL_NC_v2i64);
1601 break;
1602 case NVPTXISD::LoadV4:
1603 Opcode =
1604 pickOpcodeForVT(TargetVT, NVPTX::LD_GLOBAL_NC_v4i16,
1605 NVPTX::LD_GLOBAL_NC_v4i32, NVPTX::LD_GLOBAL_NC_v4i64);
1606 break;
1607 case NVPTXISD::LoadV8:
1608 Opcode = pickOpcodeForVT(TargetVT, {/* no v8i16 */},
1609 NVPTX::LD_GLOBAL_NC_v8i32, {/* no v8i64 */});
1610 break;
1611 }
1612 if (!Opcode)
1613 return false;
1614
1615 SDNode *NVPTXLDG = CurDAG->getMachineNode(*Opcode, DL, LD->getVTList(), Ops);
1616
1617 ReplaceNode(LD, NVPTXLDG);
1618 return true;
1619}
1620
1621bool NVPTXDAGToDAGISel::tryLDU(SDNode *N) {
1622 auto *LD = cast<MemSDNode>(N);
1623
1624 SDLoc DL(N);
1625 const unsigned FromTypeWidth = getFromTypeWidthForLoad(LD);
1626 const MVT::SimpleValueType TargetVT = LD->getSimpleValueType(0).SimpleTy;
1627
1628 // If this is an LDU intrinsic, the address is the third operand. If its an
1629 // LDU SD node (from custom vector handling), then its the second operand
1630 SDValue Addr =
1631 LD->getOperand(LD->getOpcode() == ISD::INTRINSIC_W_CHAIN ? 2 : 1);
1632
1633 const auto [Base, Offset] = selectADDR(Addr, CurDAG);
1634 SDValue Ops[] = {getI32Imm(FromTypeWidth, DL), Base, Offset, LD->getChain()};
1635
1636 std::optional<unsigned> Opcode;
1637 switch (N->getOpcode()) {
1638 default:
1639 llvm_unreachable("Unexpected opcode");
1641 Opcode = pickOpcodeForVT(TargetVT, NVPTX::LDU_GLOBAL_i16,
1642 NVPTX::LDU_GLOBAL_i32, NVPTX::LDU_GLOBAL_i64);
1643 break;
1644 case NVPTXISD::LDUV2:
1645 Opcode = pickOpcodeForVT(TargetVT, NVPTX::LDU_GLOBAL_v2i16,
1646 NVPTX::LDU_GLOBAL_v2i32, NVPTX::LDU_GLOBAL_v2i64);
1647 break;
1648 case NVPTXISD::LDUV4:
1649 Opcode = pickOpcodeForVT(TargetVT, NVPTX::LDU_GLOBAL_v4i16,
1650 NVPTX::LDU_GLOBAL_v4i32, {/* no v4i64 */});
1651 break;
1652 }
1653 if (!Opcode)
1654 return false;
1655
1656 SDNode *NVPTXLDU = CurDAG->getMachineNode(*Opcode, DL, LD->getVTList(), Ops);
1657
1658 ReplaceNode(LD, NVPTXLDU);
1659 return true;
1660}
1661
1662bool NVPTXDAGToDAGISel::tryStore(SDNode *N) {
1664 assert(ST->writeMem() && "Expected store");
1665 StoreSDNode *PlainStore = dyn_cast<StoreSDNode>(ST);
1666 AtomicSDNode *AtomicStore = dyn_cast<AtomicSDNode>(ST);
1667 assert((PlainStore || AtomicStore) && "Expected store");
1668
1669 // do not support pre/post inc/dec
1670 if (PlainStore && PlainStore->isIndexed())
1671 return false;
1672
1673 // Address Space Setting
1674 const auto CodeAddrSpace = getAddrSpace(ST);
1675
1676 SDLoc DL(ST);
1677 SDValue Chain = ST->getChain();
1678 const auto [Ordering, Scope] = getMemInstOrderingScope(ST);
1679
1680 // Vector Setting
1681 const unsigned ToTypeWidth = ST->getMemoryVT().getSizeInBits();
1682
1683 // Create the machine instruction DAG
1684 SDValue Value = PlainStore ? PlainStore->getValue() : AtomicStore->getVal();
1685
1686 assert(isPowerOf2_32(ToTypeWidth) && ToTypeWidth >= 8 && ToTypeWidth <= 128 &&
1687 "Invalid width for store");
1688
1689 const auto [Base, Offset] = selectADDR(ST->getBasePtr(), CurDAG);
1690
1691 // Extract eviction/prefetch hint and cache policy register.
1692 const auto [EvictionAndPrefetchHint, PolicyReg] = getMemCacheHintOperands(
1693 ST,
1694 {NVPTXMemCacheHintInstruction::St, CodeAddrSpace,
1695 /*NumElts=*/1, /*EltWidth=*/ToTypeWidth, ST->isVolatile()},
1696 DL);
1697
1698 SDValue Ops[] = {selectPossiblyImm(Value),
1699 getI32Imm(Ordering, DL),
1700 getI32Imm(Scope, DL),
1701 getI32Imm(CodeAddrSpace, DL),
1702 getI32Imm(ToTypeWidth, DL),
1703 Base,
1704 Offset,
1705 EvictionAndPrefetchHint,
1706 PolicyReg,
1707 Chain};
1708
1709 const std::optional<unsigned> Opcode =
1710 pickOpcodeForVT(Value.getSimpleValueType().SimpleTy, NVPTX::ST_i16,
1711 NVPTX::ST_i32, NVPTX::ST_i64);
1712 if (!Opcode)
1713 return false;
1714
1715 SDNode *NVPTXST = CurDAG->getMachineNode(*Opcode, DL, MVT::Other, Ops);
1716
1717 if (!NVPTXST)
1718 return false;
1719
1720 MachineMemOperand *MemRef = ST->getMemOperand();
1721 CurDAG->setNodeMemRefs(cast<MachineSDNode>(NVPTXST), {MemRef});
1722 ReplaceNode(ST, NVPTXST);
1723 return true;
1724}
1725
1726bool NVPTXDAGToDAGISel::tryStoreVector(SDNode *N) {
1728 const unsigned TotalWidth = ST->getMemoryVT().getSizeInBits();
1729
1730 // Address Space Setting
1731 const auto CodeAddrSpace = getAddrSpace(ST);
1732 if (CodeAddrSpace == NVPTX::AddressSpace::Const) {
1733 report_fatal_error("Cannot store to pointer that points to constant "
1734 "memory space");
1735 }
1736
1737 SDLoc DL(ST);
1738 SDValue Chain = ST->getChain();
1739 const auto [Ordering, Scope] = getMemInstOrderingScope(ST);
1740
1741 const unsigned NumElts = getStoreVectorNumElts(ST);
1742
1744 for (auto &V : ST->ops().slice(1, NumElts))
1745 Ops.push_back(selectPossiblyImm(V));
1746 SDValue Addr = N->getOperand(NumElts + 1);
1747 const unsigned ToTypeWidth = TotalWidth / NumElts;
1748
1749 assert(isPowerOf2_32(ToTypeWidth) && ToTypeWidth >= 8 && ToTypeWidth <= 128 &&
1750 TotalWidth <= 256 && "Invalid width for store");
1751
1752 // Extract eviction/prefetch hint and cache policy register.
1753 const auto [EvictionAndPrefetchHint, PolicyReg] = getMemCacheHintOperands(
1754 ST,
1755 {NVPTXMemCacheHintInstruction::St, CodeAddrSpace,
1756 /*NumElts=*/NumElts, /*EltWidth=*/ToTypeWidth, ST->isVolatile()},
1757 DL);
1758
1759 const auto [Base, Offset] = selectADDR(Addr, CurDAG);
1760 Ops.append({getI32Imm(Ordering, DL), getI32Imm(Scope, DL),
1761 getI32Imm(CodeAddrSpace, DL), getI32Imm(ToTypeWidth, DL), Base,
1762 Offset, EvictionAndPrefetchHint, PolicyReg, Chain});
1763
1764 const MVT::SimpleValueType EltVT =
1765 ST->getOperand(1).getSimpleValueType().SimpleTy;
1766 std::optional<unsigned> Opcode;
1767 switch (ST->getOpcode()) {
1768 default:
1769 return false;
1770 case NVPTXISD::StoreV2:
1771 Opcode = pickOpcodeForVT(EltVT, NVPTX::STV_i16_v2, NVPTX::STV_i32_v2,
1772 NVPTX::STV_i64_v2);
1773 break;
1774 case NVPTXISD::StoreV4:
1775 Opcode = pickOpcodeForVT(EltVT, NVPTX::STV_i16_v4, NVPTX::STV_i32_v4,
1776 NVPTX::STV_i64_v4);
1777 break;
1778 case NVPTXISD::StoreV8:
1779 Opcode = pickOpcodeForVT(EltVT, {/* no v8i16 */}, NVPTX::STV_i32_v8,
1780 {/* no v8i64 */});
1781 break;
1782 }
1783
1784 if (!Opcode)
1785 return false;
1786
1787 SDNode *NVPTXST = CurDAG->getMachineNode(*Opcode, DL, MVT::Other, Ops);
1788
1789 MachineMemOperand *MemRef = ST->getMemOperand();
1790 CurDAG->setNodeMemRefs(cast<MachineSDNode>(NVPTXST), {MemRef});
1791
1792 ReplaceNode(ST, NVPTXST);
1793 return true;
1794}
1795
1796/// SelectBFE - Look for instruction sequences that can be made more efficient
1797/// by using the 'bfe' (bit-field extract) PTX instruction
1798bool NVPTXDAGToDAGISel::tryBFE(SDNode *N) {
1799 // BFE is not a native instruction starting with sm_70. Let ptxas see the
1800 // original operations so it can optimize them for the target architecture.
1801 if (Subtarget->hasFeature(NVPTX::SM70))
1802 return false;
1803
1804 SDLoc DL(N);
1805 SDValue LHS = N->getOperand(0);
1806 SDValue RHS = N->getOperand(1);
1807 SDValue Len;
1808 SDValue Start;
1809 SDValue Val;
1810 bool IsSigned = false;
1811
1812 if (N->getOpcode() == ISD::AND) {
1813 // Canonicalize the operands
1814 // We want 'and %val, %mask'
1816 std::swap(LHS, RHS);
1817 }
1818
1820 if (!Mask) {
1821 // We need a constant mask on the RHS of the AND
1822 return false;
1823 }
1824
1825 // Extract the mask bits
1826 uint64_t MaskVal = Mask->getZExtValue();
1827 if (!isMask_64(MaskVal)) {
1828 // We *could* handle shifted masks here, but doing so would require an
1829 // 'and' operation to fix up the low-order bits so we would trade
1830 // shr+and for bfe+and, which has the same throughput
1831 return false;
1832 }
1833
1834 // How many bits are in our mask?
1835 int64_t NumBits = countr_one(MaskVal);
1836 Len = CurDAG->getTargetConstant(NumBits, DL, MVT::i32);
1837
1838 if (LHS.getOpcode() == ISD::SRL || LHS.getOpcode() == ISD::SRA) {
1839 // We have a 'srl/and' pair, extract the effective start bit and length
1840 Val = LHS.getNode()->getOperand(0);
1841 Start = LHS.getNode()->getOperand(1);
1842 ConstantSDNode *StartConst = dyn_cast<ConstantSDNode>(Start);
1843 if (StartConst) {
1844 uint64_t StartVal = StartConst->getZExtValue();
1845 // How many "good" bits do we have left? "good" is defined here as bits
1846 // that exist in the original value, not shifted in.
1847 int64_t GoodBits = Val.getValueSizeInBits() - StartVal;
1848 if (NumBits > GoodBits) {
1849 // Do not handle the case where bits have been shifted in. In theory
1850 // we could handle this, but the cost is likely higher than just
1851 // emitting the srl/and pair.
1852 return false;
1853 }
1854 Start = CurDAG->getTargetConstant(StartVal, DL, MVT::i32);
1855 } else {
1856 // Do not handle the case where the shift amount (can be zero if no srl
1857 // was found) is not constant. We could handle this case, but it would
1858 // require run-time logic that would be more expensive than just
1859 // emitting the srl/and pair.
1860 return false;
1861 }
1862 } else {
1863 // Do not handle the case where the LHS of the and is not a shift. While
1864 // it would be trivial to handle this case, it would just transform
1865 // 'and' -> 'bfe', but 'and' has higher-throughput.
1866 return false;
1867 }
1868 } else if (N->getOpcode() == ISD::SRL || N->getOpcode() == ISD::SRA) {
1869 if (LHS->getOpcode() == ISD::AND) {
1871 if (!ShiftCnst) {
1872 // Shift amount must be constant
1873 return false;
1874 }
1875
1876 uint64_t ShiftAmt = ShiftCnst->getZExtValue();
1877
1878 SDValue AndLHS = LHS->getOperand(0);
1879 SDValue AndRHS = LHS->getOperand(1);
1880
1881 // Canonicalize the AND to have the mask on the RHS
1882 if (isa<ConstantSDNode>(AndLHS)) {
1883 std::swap(AndLHS, AndRHS);
1884 }
1885
1886 ConstantSDNode *MaskCnst = dyn_cast<ConstantSDNode>(AndRHS);
1887 if (!MaskCnst) {
1888 // Mask must be constant
1889 return false;
1890 }
1891
1892 uint64_t MaskVal = MaskCnst->getZExtValue();
1893 uint64_t NumZeros;
1894 uint64_t NumBits;
1895 if (isMask_64(MaskVal)) {
1896 NumZeros = 0;
1897 // The number of bits in the result bitfield will be the number of
1898 // trailing ones (the AND) minus the number of bits we shift off
1899 NumBits = llvm::countr_one(MaskVal) - ShiftAmt;
1900 } else if (isShiftedMask_64(MaskVal)) {
1901 NumZeros = llvm::countr_zero(MaskVal);
1902 unsigned NumOnes = llvm::countr_one(MaskVal >> NumZeros);
1903 // The number of bits in the result bitfield will be the number of
1904 // trailing zeros plus the number of set bits in the mask minus the
1905 // number of bits we shift off
1906 NumBits = NumZeros + NumOnes - ShiftAmt;
1907 } else {
1908 // This is not a mask we can handle
1909 return false;
1910 }
1911
1912 if (ShiftAmt < NumZeros) {
1913 // Handling this case would require extra logic that would make this
1914 // transformation non-profitable
1915 return false;
1916 }
1917
1918 Val = AndLHS;
1919 Start = CurDAG->getTargetConstant(ShiftAmt, DL, MVT::i32);
1920 Len = CurDAG->getTargetConstant(NumBits, DL, MVT::i32);
1921
1922 // If pre-shift AND includes the sign bit in the bitfield, we must use
1923 // signed BFE to replicate that bit during bitfield extraction. If the
1924 // sign bit is not part of the mask, unsigned BFE will zero out upper bits
1925 // of the result
1926 if (N->getOpcode() == ISD::SRA)
1927 IsSigned = (ShiftAmt + NumBits) == Val.getValueSizeInBits();
1928 } else if (LHS->getOpcode() == ISD::SHL) {
1929 // Here, we have a pattern like:
1930 //
1931 // (sra (shl val, NN), MM)
1932 // or
1933 // (srl (shl val, NN), MM)
1934 //
1935 // If MM >= NN, we can efficiently optimize this with bfe
1936 Val = LHS->getOperand(0);
1937
1938 SDValue ShlRHS = LHS->getOperand(1);
1939 ConstantSDNode *ShlCnst = dyn_cast<ConstantSDNode>(ShlRHS);
1940 if (!ShlCnst) {
1941 // Shift amount must be constant
1942 return false;
1943 }
1944 uint64_t InnerShiftAmt = ShlCnst->getZExtValue();
1945
1946 SDValue ShrRHS = RHS;
1947 ConstantSDNode *ShrCnst = dyn_cast<ConstantSDNode>(ShrRHS);
1948 if (!ShrCnst) {
1949 // Shift amount must be constant
1950 return false;
1951 }
1952 uint64_t OuterShiftAmt = ShrCnst->getZExtValue();
1953
1954 // To avoid extra codegen and be profitable, we need Outer >= Inner
1955 if (OuterShiftAmt < InnerShiftAmt) {
1956 return false;
1957 }
1958
1959 // If the outer shift is more than the type size, we have no bitfield to
1960 // extract (since we also check that the inner shift is <= the outer shift
1961 // then this also implies that the inner shift is < the type size)
1962 if (OuterShiftAmt >= Val.getValueSizeInBits()) {
1963 return false;
1964 }
1965
1966 Start = CurDAG->getTargetConstant(OuterShiftAmt - InnerShiftAmt, DL,
1967 MVT::i32);
1968 Len = CurDAG->getTargetConstant(Val.getValueSizeInBits() - OuterShiftAmt,
1969 DL, MVT::i32);
1970
1971 if (N->getOpcode() == ISD::SRA) {
1972 // If we have a arithmetic right shift, we need to use the signed bfe
1973 // variant
1974 IsSigned = true;
1975 }
1976 } else {
1977 // No can do...
1978 return false;
1979 }
1980 } else {
1981 // No can do...
1982 return false;
1983 }
1984 // Only 32-bit BFE has a native SASS implementation.
1985 if (Val.getValueType() != MVT::i32)
1986 return false;
1987
1988 unsigned Opc = IsSigned ? NVPTX::BFE_S32 : NVPTX::BFE_U32;
1989
1990 SDValue Ops[] = {selectPossiblyImm(Val), Start, Len};
1991
1992 ReplaceNode(N, CurDAG->getMachineNode(Opc, DL, N->getVTList(), Ops));
1993 return true;
1994}
1995
1996// Select bf16/bf16v2 FADD, FSUB, FMUL as fma on targets with only fma
1997bool NVPTXDAGToDAGISel::tryBF16ArithToFMA(SDNode *N) {
1998 EVT VT = SDValue(N, 0).getValueType();
1999 if (VT.getScalarType() != MVT::bf16)
2000 return false;
2001
2002 const NVPTXSubtarget *STI = TM.getSubtargetImpl();
2003 if (STI->hasNativeBF16Support(N->getOpcode()))
2004 return false;
2005
2006 const bool IsVec = VT.isVector();
2007 assert(!IsVec || VT.getVectorNumElements() == 2);
2008 SDLoc DL(N);
2009 SDValue N0 = N->getOperand(0);
2010 SDValue N1 = N->getOperand(1);
2012 auto GetConstant = [&](float Value) -> SDValue {
2013 // BF16 immediates must be legalized to integer register values
2014 APFloat APF(Value);
2015 bool LosesInfo;
2016 APF.convert(APFloat::BFloat(), APFloat::rmNearestTiesToEven, &LosesInfo);
2017 assert(!LosesInfo);
2018 if (IsVec) {
2019 auto API = APF.bitcastToAPInt();
2020 API = API.concat(API);
2021 auto Const = CurDAG->getTargetConstant(API, DL, MVT::i32);
2022 return SDValue(CurDAG->getMachineNode(NVPTX::MOV_B32_i, DL, VT, Const),
2023 0);
2024 }
2025 auto Const = CurDAG->getTargetConstantFP(APF, DL, VT);
2026 return SDValue(CurDAG->getMachineNode(NVPTX::MOV_BF16_i, DL, VT, Const), 0);
2027 };
2028
2029 switch (N->getOpcode()) {
2030 case ISD::FADD:
2031 // add(a, b) -> fma(a, 1.0, b)
2032 Operands = {N0, GetConstant(1.0), N1};
2033 break;
2034 case ISD::FSUB:
2035 // sub(a, b) -> fma(b, -1.0, a)
2036 Operands = {N1, GetConstant(-1.0), N0};
2037 break;
2038 case ISD::FMUL:
2039 // mul(a, b) -> fma(a, b, -0.0)
2040 // NOTE: The identity is -0, not 0, because -0 + 0 == 0 for floats
2041 Operands = {N0, N1, GetConstant(-0.0)};
2042 break;
2043 default:
2044 llvm_unreachable("Unexpected opcode");
2045 };
2046
2047 int Opcode = IsVec ? NVPTX::FMA_BF16x2 : NVPTX::FMA_BF16;
2048 MachineSDNode *FMA = CurDAG->getMachineNode(Opcode, DL, VT, Operands);
2049 ReplaceNode(N, FMA);
2050 return true;
2051}
2052
2053// The min/max .abs modifier also accepts operands already known to have no
2054// negative values (not even -0). NaN signs are immaterial to these
2055// instructions.
2056bool NVPTXDAGToDAGISel::SelectFAbs(SDValue N, SDValue &Src) {
2057 if (N.getOpcode() == ISD::FABS)
2058 Src = N.getOperand(0);
2059 else if (CurDAG->computeKnownFPClass(N, fcNegative).signBitIsZeroOrNaN())
2060 Src = N;
2061 else
2062 return false;
2063 Src = selectPossiblyImm(Src);
2064 return true;
2065}
2066
2067SDValue NVPTXDAGToDAGISel::selectPossiblyImm(SDValue V) {
2068 if (V.getOpcode() == ISD::BITCAST)
2069 V = V.getOperand(0);
2070
2071 if (auto *CN = dyn_cast<ConstantSDNode>(V))
2072 return CurDAG->getTargetConstant(CN->getAPIntValue(), SDLoc(V),
2073 V.getValueType());
2074 if (auto *CN = dyn_cast<ConstantFPSDNode>(V))
2075 return CurDAG->getTargetConstantFP(CN->getValueAPF(), SDLoc(V),
2076 V.getValueType());
2077 return V;
2078}
2079
2080/// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
2081/// inline asm expressions.
2082bool NVPTXDAGToDAGISel::SelectInlineAsmMemoryOperand(
2083 const SDValue &Op, InlineAsm::ConstraintCode ConstraintID,
2084 std::vector<SDValue> &OutOps) {
2085 switch (ConstraintID) {
2086 default:
2087 return true;
2088 case InlineAsm::ConstraintCode::m: { // memory
2089 const auto [Base, Offset] = selectADDR(Op, CurDAG);
2090 OutOps.push_back(Base);
2091 OutOps.push_back(Offset);
2092 return false;
2093 }
2094 }
2095 return true;
2096}
2097
2098void NVPTXDAGToDAGISel::SelectV2I64toI128(SDNode *N) {
2099 // Lower a CopyToReg with two 64-bit inputs
2100 // Dst:i128, lo:i64, hi:i64
2101 //
2102 // CopyToReg Dst, lo, hi;
2103 //
2104 // ==>
2105 //
2106 // tmp = V2I64toI128 {lo, hi};
2107 // CopyToReg Dst, tmp;
2108 SDValue Dst = N->getOperand(1);
2109 SDValue Lo = selectPossiblyImm(N->getOperand(2));
2110 SDValue Hi = selectPossiblyImm(N->getOperand(3));
2111
2112 SDLoc DL(N);
2113 SDNode *Mov =
2114 CurDAG->getMachineNode(NVPTX::V2I64toI128, DL, MVT::i128, {Lo, Hi});
2115
2116 SmallVector<SDValue, 4> NewOps(N->getNumOperands() - 1);
2117 NewOps[0] = N->getOperand(0);
2118 NewOps[1] = Dst;
2119 NewOps[2] = SDValue(Mov, 0);
2120 if (N->getNumOperands() == 5)
2121 NewOps[3] = N->getOperand(4);
2122 SDValue NewValue = CurDAG->getNode(ISD::CopyToReg, DL, SmallVector<EVT>(N->values()), NewOps);
2123
2124 ReplaceNode(N, NewValue.getNode());
2125}
2126
2127void NVPTXDAGToDAGISel::SelectI128toV2I64(SDNode *N) {
2128 // Lower CopyFromReg from a 128-bit regs to two 64-bit regs
2129 // Dst:i128, Src:i128
2130 //
2131 // {lo, hi} = CopyFromReg Src
2132 //
2133 // ==>
2134 //
2135 // {lo, hi} = I128toV2I64 Src
2136 //
2137 SDValue Ch = N->getOperand(0);
2138 SDValue Src = N->getOperand(1);
2139 SDValue Glue = N->getOperand(2);
2140 SDLoc DL(N);
2141
2142 // Add Glue and Ch to the operands and results to avoid break the execution
2143 // order
2144 SDNode *Mov = CurDAG->getMachineNode(
2145 NVPTX::I128toV2I64, DL,
2146 {MVT::i64, MVT::i64, Ch.getValueType(), Glue.getValueType()},
2147 {Src, Ch, Glue});
2148
2149 ReplaceNode(N, Mov);
2150}
2151
2152bool NVPTXDAGToDAGISel::tryFence(SDNode *N) {
2153 SDLoc DL(N);
2154 assert(N->getOpcode() == ISD::ATOMIC_FENCE);
2155 auto Scope = Scopes[N->getConstantOperandVal(2)];
2156
2157 // Singlethread fences have no inter-thread synchronization requirements.
2158 // Note: std::atomic_signal_fence lowers to singlethread LLVM IR fences;
2159 // this intentionally drops these before emitting PTX.
2160 if (Scope == NVPTX::Scope::Thread) {
2161 CurDAG->ReplaceAllUsesOfValueWith(SDValue(N, 0), N->getOperand(0));
2162 CurDAG->RemoveDeadNode(N);
2163 return true;
2164 }
2165
2166 unsigned int FenceOp = getFenceOp(
2167 NVPTX::Ordering(N->getConstantOperandVal(1)), Scope, Subtarget);
2168 SDValue Chain = N->getOperand(0);
2169 SDNode *FenceNode = CurDAG->getMachineNode(FenceOp, DL, MVT::Other, Chain);
2170 ReplaceNode(N, FenceNode);
2171 return true;
2172}
2173
2174NVPTXScopes::NVPTXScopes(LLVMContext &C, const Triple &T) : Context(&C) {
2175 auto ScopeID = [&](AtomicScope Scope) {
2176 return C.getOrInsertSyncScopeID(*getAtomicScopeIRString(T, Scope));
2177 };
2183}
2184
2185NVPTX::Scope NVPTXScopes::operator[](SyncScope::ID ID) const {
2186 if (Scopes.empty())
2187 llvm_unreachable("NVPTX Scopes must be initialized before calling "
2188 "NVPTXScopes::operator[]");
2189
2190 auto S = Scopes.find(ID);
2191 if (S == Scopes.end()) {
2192 auto scopeName = Context->getSyncScopeName(ID);
2193 assert(scopeName.has_value() && "Scope name must exist.");
2194
2195 // Build list of supported syncscopes programmatically
2196 SmallVector<StringRef> supportedScopes;
2197 for (const auto &Entry : Scopes) {
2198 if (auto name = Context->getSyncScopeName(Entry.first))
2199 supportedScopes.push_back(name->empty() ? "<empty string>" : *name);
2200 }
2201
2203 formatv("NVPTX backend does not support syncscope \"{0}\" (ID={1}).\n"
2204 "Supported syncscopes are: {2}.",
2205 scopeName.value(), int(ID),
2206 make_range(supportedScopes.begin(), supportedScopes.end())));
2207 }
2208 return S->second;
2209}
2210
2211bool NVPTXScopes::empty() const { return Scopes.size() == 0; }
2212
2213#define TCGEN05_ST_OPCODE(SHAPE, NUM) \
2214 (enableUnpack ? NVPTX::TCGEN05_ST_##SHAPE##_##NUM##_UNPACK \
2215 : NVPTX::TCGEN05_ST_##SHAPE##_##NUM)
2216
2217static unsigned getTcgen05StOpcode(unsigned IID, bool enableUnpack) {
2218 switch (IID) {
2219 case Intrinsic::nvvm_tcgen05_st_16x64b_x1:
2220 return TCGEN05_ST_OPCODE(16x64b, x1);
2221 case Intrinsic::nvvm_tcgen05_st_16x64b_x2:
2222 return TCGEN05_ST_OPCODE(16x64b, x2);
2223 case Intrinsic::nvvm_tcgen05_st_16x64b_x4:
2224 return TCGEN05_ST_OPCODE(16x64b, x4);
2225 case Intrinsic::nvvm_tcgen05_st_16x64b_x8:
2226 return TCGEN05_ST_OPCODE(16x64b, x8);
2227 case Intrinsic::nvvm_tcgen05_st_16x64b_x16:
2228 return TCGEN05_ST_OPCODE(16x64b, x16);
2229 case Intrinsic::nvvm_tcgen05_st_16x64b_x32:
2230 return TCGEN05_ST_OPCODE(16x64b, x32);
2231 case Intrinsic::nvvm_tcgen05_st_16x64b_x64:
2232 return TCGEN05_ST_OPCODE(16x64b, x64);
2233 case Intrinsic::nvvm_tcgen05_st_16x64b_x128:
2234 return TCGEN05_ST_OPCODE(16x64b, x128);
2235 case Intrinsic::nvvm_tcgen05_st_16x128b_x1:
2236 return TCGEN05_ST_OPCODE(16x128b, x1);
2237 case Intrinsic::nvvm_tcgen05_st_16x128b_x2:
2238 return TCGEN05_ST_OPCODE(16x128b, x2);
2239 case Intrinsic::nvvm_tcgen05_st_16x128b_x4:
2240 return TCGEN05_ST_OPCODE(16x128b, x4);
2241 case Intrinsic::nvvm_tcgen05_st_16x128b_x8:
2242 return TCGEN05_ST_OPCODE(16x128b, x8);
2243 case Intrinsic::nvvm_tcgen05_st_16x128b_x16:
2244 return TCGEN05_ST_OPCODE(16x128b, x16);
2245 case Intrinsic::nvvm_tcgen05_st_16x128b_x32:
2246 return TCGEN05_ST_OPCODE(16x128b, x32);
2247 case Intrinsic::nvvm_tcgen05_st_16x128b_x64:
2248 return TCGEN05_ST_OPCODE(16x128b, x64);
2249 case Intrinsic::nvvm_tcgen05_st_16x256b_x1:
2250 return TCGEN05_ST_OPCODE(16x256b, x1);
2251 case Intrinsic::nvvm_tcgen05_st_16x256b_x2:
2252 return TCGEN05_ST_OPCODE(16x256b, x2);
2253 case Intrinsic::nvvm_tcgen05_st_16x256b_x4:
2254 return TCGEN05_ST_OPCODE(16x256b, x4);
2255 case Intrinsic::nvvm_tcgen05_st_16x256b_x8:
2256 return TCGEN05_ST_OPCODE(16x256b, x8);
2257 case Intrinsic::nvvm_tcgen05_st_16x256b_x16:
2258 return TCGEN05_ST_OPCODE(16x256b, x16);
2259 case Intrinsic::nvvm_tcgen05_st_16x256b_x32:
2260 return TCGEN05_ST_OPCODE(16x256b, x32);
2261 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x1:
2262 return TCGEN05_ST_OPCODE(16x32bx2, x1);
2263 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x2:
2264 return TCGEN05_ST_OPCODE(16x32bx2, x2);
2265 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x4:
2266 return TCGEN05_ST_OPCODE(16x32bx2, x4);
2267 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x8:
2268 return TCGEN05_ST_OPCODE(16x32bx2, x8);
2269 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x16:
2270 return TCGEN05_ST_OPCODE(16x32bx2, x16);
2271 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x32:
2272 return TCGEN05_ST_OPCODE(16x32bx2, x32);
2273 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x64:
2274 return TCGEN05_ST_OPCODE(16x32bx2, x64);
2275 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x128:
2276 return TCGEN05_ST_OPCODE(16x32bx2, x128);
2277 case Intrinsic::nvvm_tcgen05_st_32x32b_x1:
2278 return TCGEN05_ST_OPCODE(32x32b, x1);
2279 case Intrinsic::nvvm_tcgen05_st_32x32b_x2:
2280 return TCGEN05_ST_OPCODE(32x32b, x2);
2281 case Intrinsic::nvvm_tcgen05_st_32x32b_x4:
2282 return TCGEN05_ST_OPCODE(32x32b, x4);
2283 case Intrinsic::nvvm_tcgen05_st_32x32b_x8:
2284 return TCGEN05_ST_OPCODE(32x32b, x8);
2285 case Intrinsic::nvvm_tcgen05_st_32x32b_x16:
2286 return TCGEN05_ST_OPCODE(32x32b, x16);
2287 case Intrinsic::nvvm_tcgen05_st_32x32b_x32:
2288 return TCGEN05_ST_OPCODE(32x32b, x32);
2289 case Intrinsic::nvvm_tcgen05_st_32x32b_x64:
2290 return TCGEN05_ST_OPCODE(32x32b, x64);
2291 case Intrinsic::nvvm_tcgen05_st_32x32b_x128:
2292 return TCGEN05_ST_OPCODE(32x32b, x128);
2293 }
2294 llvm_unreachable("unhandled tcgen05.st lowering");
2295}
2296
2297void NVPTXDAGToDAGISel::SelectTcgen05St(SDNode *N, bool hasOffset) {
2298 if (!Subtarget->hasTcgen05InstSupport())
2300 "tcgen05.st is not supported on this architecture variant");
2301
2302 SDLoc DL(N);
2303 unsigned IID = cast<ConstantSDNode>(N->getOperand(1))->getZExtValue();
2304
2306 N->getOperand(2) // taddr
2307 };
2308
2309 if (hasOffset)
2310 Operands.push_back(CurDAG->getTargetConstant(
2311 cast<ConstantSDNode>(N->getOperand(3))->getZExtValue(), DL,
2312 MVT::i32)); // Offset
2313
2314 for (unsigned I = hasOffset ? 4 : 3; I < (N->getNumOperands() - 1); I++)
2315 Operands.push_back(N->getOperand(I));
2316
2317 bool enableUnpack =
2318 cast<ConstantSDNode>(N->getOperand(N->getNumOperands() - 1))
2319 ->getZExtValue();
2320
2321 Operands.push_back(N->getOperand(0)); // Chain
2322 ReplaceNode(N, CurDAG->getMachineNode(getTcgen05StOpcode(IID, enableUnpack),
2323 DL, N->getVTList(), Operands));
2324}
2325
2326bool NVPTXDAGToDAGISel::tryIntrinsicVoid(SDNode *N) {
2327 unsigned IID = N->getConstantOperandVal(1);
2328 switch (IID) {
2329 default:
2330 return false;
2331 case Intrinsic::nvvm_tcgen05_st_16x64b_x1:
2332 case Intrinsic::nvvm_tcgen05_st_16x64b_x2:
2333 case Intrinsic::nvvm_tcgen05_st_16x64b_x4:
2334 case Intrinsic::nvvm_tcgen05_st_16x64b_x8:
2335 case Intrinsic::nvvm_tcgen05_st_16x64b_x16:
2336 case Intrinsic::nvvm_tcgen05_st_16x64b_x32:
2337 case Intrinsic::nvvm_tcgen05_st_16x64b_x64:
2338 case Intrinsic::nvvm_tcgen05_st_16x64b_x128:
2339 case Intrinsic::nvvm_tcgen05_st_32x32b_x1:
2340 case Intrinsic::nvvm_tcgen05_st_32x32b_x2:
2341 case Intrinsic::nvvm_tcgen05_st_32x32b_x4:
2342 case Intrinsic::nvvm_tcgen05_st_32x32b_x8:
2343 case Intrinsic::nvvm_tcgen05_st_32x32b_x16:
2344 case Intrinsic::nvvm_tcgen05_st_32x32b_x32:
2345 case Intrinsic::nvvm_tcgen05_st_32x32b_x64:
2346 case Intrinsic::nvvm_tcgen05_st_32x32b_x128:
2347 case Intrinsic::nvvm_tcgen05_st_16x128b_x1:
2348 case Intrinsic::nvvm_tcgen05_st_16x128b_x2:
2349 case Intrinsic::nvvm_tcgen05_st_16x128b_x4:
2350 case Intrinsic::nvvm_tcgen05_st_16x128b_x8:
2351 case Intrinsic::nvvm_tcgen05_st_16x128b_x16:
2352 case Intrinsic::nvvm_tcgen05_st_16x128b_x32:
2353 case Intrinsic::nvvm_tcgen05_st_16x128b_x64:
2354 case Intrinsic::nvvm_tcgen05_st_16x256b_x1:
2355 case Intrinsic::nvvm_tcgen05_st_16x256b_x2:
2356 case Intrinsic::nvvm_tcgen05_st_16x256b_x4:
2357 case Intrinsic::nvvm_tcgen05_st_16x256b_x8:
2358 case Intrinsic::nvvm_tcgen05_st_16x256b_x16:
2359 case Intrinsic::nvvm_tcgen05_st_16x256b_x32: {
2360 SelectTcgen05St(N);
2361 return true;
2362 }
2363
2364 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x1:
2365 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x2:
2366 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x4:
2367 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x8:
2368 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x16:
2369 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x32:
2370 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x64:
2371 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x128: {
2372 SelectTcgen05St(N, /* hasOffset */ true);
2373 return true;
2374 }
2375 }
2376}
2377
2378void NVPTXDAGToDAGISel::selectAtomicSwap128(SDNode *N) {
2379 MemSDNode *AN = cast<MemSDNode>(N);
2380 SDLoc dl(N);
2381
2382 const SDValue Chain = N->getOperand(0);
2383 const auto [Base, Offset] = selectADDR(N->getOperand(1), CurDAG);
2385 for (const SDValue &Operand : drop_begin(N->op_values(), 2))
2386 Ops.push_back(selectPossiblyImm(Operand));
2387 Ops.append({getI32Imm(getMemOrder(AN), dl), getI32Imm(getAtomicScope(AN), dl),
2388 getI32Imm(getAddrSpace(AN), dl)});
2389
2390 if (N->getOpcode() == NVPTXISD::ATOMIC_SWAP_B128) {
2391 unsigned EltWidth = AN->getMemoryVT().getFixedSizeInBits();
2392 NVPTXMemCacheHintAccess Access{NVPTXMemCacheHintInstruction::Atom,
2393 getAddrSpace(AN),
2394 /*NumElts=*/1, EltWidth, AN->isVolatile()};
2395 const auto [EvictionAndPrefetchHint, CachePolicyReg] =
2396 getMemCacheHintOperands(AN, Access, dl);
2397 Ops.push_back(EvictionAndPrefetchHint);
2398 Ops.push_back(CachePolicyReg);
2399 }
2400
2401 Ops.push_back(Chain);
2402
2403 assert(N->getOpcode() == NVPTXISD::ATOMIC_CMP_SWAP_B128 ||
2404 N->getOpcode() == NVPTXISD::ATOMIC_SWAP_B128);
2405 unsigned Opcode = N->getOpcode() == NVPTXISD::ATOMIC_SWAP_B128
2406 ? NVPTX::ATOM_EXCH_B128
2407 : NVPTX::ATOM_CAS_B128;
2408
2409 auto *ATOM = CurDAG->getMachineNode(Opcode, dl, N->getVTList(), Ops);
2410 CurDAG->setNodeMemRefs(ATOM, AN->getMemOperand());
2411
2412 ReplaceNode(N, ATOM);
2413}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
uint64_t uint64_t
uint64_t Imm
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")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
DXIL Resource Access
#define DEBUG_TYPE
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
loop data Loop Data Prefetch
#define I(x, y, z)
Definition MD5.cpp:57
This file implements a map that provides insertion order iteration.
This file contains the declarations for metadata subclasses.
#define T
static NVPTX::Scope resolveScope(NVPTX::Scope S, const NVPTXSubtarget *T)
static unsigned getStoreVectorNumElts(SDNode *N)
static bool isAddLike(const SDValue V)
static std::optional< NVPTX::L2Eviction > parseL2Eviction(StringRef Str)
static SDValue selectBaseADDR(SDValue N, SelectionDAG *DAG)
static std::optional< NVPTX::L2Prefetch > parseL2Prefetch(StringRef Str)
static std::optional< NVPTX::L1Eviction > parseL1Eviction(StringRef Str)
static std::optional< unsigned > getI16ExtractIndex(const SDNode *N)
static void mergeI16Unpacks(SelectionDAG &DAG)
static SDValue accumulateOffset(SDValue &Addr, SDLoc DL, SelectionDAG *DAG)
static bool isGlobalOrGeneric(NVPTX::AddressSpace AddrSpace)
static bool isL2PrefetchSupported(const NVPTXSubtarget &Subtarget, NVPTX::L2Prefetch Prefetch, NVPTXMemCacheHintAccess Access)
static bool isLdOrSt(NVPTXMemCacheHintAccess Access)
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"))
#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 void emitInvalidMemCacheHint(LLVMContext &Ctx, const Twine &Msg)
static unsigned int getFenceOp(NVPTX::Ordering O, NVPTX::Scope S, NVPTXSubtarget const *T)
static std::optional< T > parseMemCacheHintStringValue(LLVMContext &Ctx, StringRef Key, const Metadata *Value, std::optional< T >(*Parse)(StringRef), bool EmitDiagnostics)
static bool isL2EvictionSupported(const NVPTXSubtarget &Subtarget, NVPTX::L2Eviction Eviction, NVPTXMemCacheHintAccess Access)
#define TCGEN05_ST_OPCODE(SHAPE, NUM)
static bool isL1EvictionSupported(const NVPTXSubtarget &Subtarget, NVPTX::L1Eviction Eviction, NVPTXMemCacheHintAccess Access)
static bool isCachePolicySupported(const NVPTXSubtarget &Subtarget, NVPTXMemCacheHintAccess Access)
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)
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
SI Fold Operands
const char * Msg
static const char * name
This file implements the StringSwitch template, which mimics a switch() statement whose cases are str...
#define PASS_NAME
Value * RHS
Value * LHS
static const fltSemantics & BFloat()
Definition APFloat.h:303
static constexpr roundingMode rmNearestTiesToEven
Definition APFloat.h:361
Class for arbitrary precision integers.
Definition APInt.h:78
LLVM_ABI APInt sext(unsigned width) const
Sign extend to a new width.
Definition APInt.cpp:1030
int64_t getSExtValue() const
Get sign extended value.
Definition APInt.h:1582
This is an SDNode representing atomic operations.
const SDValue & getVal() const
uint64_t getZExtValue() const
Diagnostic information for unsupported feature in backend.
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:312
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition Function.cpp:352
Record instruction ordering so we can query their relative positions within a function.
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:76
bool isIndexed() const
Return true if this is a pre/post inc/dec load/store.
This class is used to represent ISD::LOAD nodes.
ISD::LoadExtType getExtensionType() const
Return whether this is a plain node, or one of the varieties of value-extending loads.
Metadata node.
Definition Metadata.h:1081
Machine Value Type.
SimpleValueType SimpleTy
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.
const TargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
A description of a memory reference used in the backend.
An SDNode that represents everything that will be needed to construct a MachineInstr.
This is an abstract virtual class for memory operations.
bool isVolatile() const
MachineMemOperand * getMemOperand() const
Return the unique MachineMemOperand object describing the memory reference performed by operation.
EVT getMemoryVT() const
Return the type of the in-memory value.
Root of the metadata hierarchy.
Definition Metadata.h:64
NVPTXISelDAGToDAGPass(NVPTXTargetMachine &TM, CodeGenOptLevel OptLevel)
bool hasL2Prefetch256B() const
bool hasL2EvictionHint() const
bool hasTcgen05InstSupport() const
bool hasL2Prefetch64B() const
bool hasL2Prefetch128B() const
bool hasNativeBF16Support(unsigned Opcode) const
bool hasL1EvictionHint() const
bool hasRelaxedMMIO() const
bool hasL2CacheHint() const
bool hasLocalVolatile() const
bool hasMemoryOrdering() const
bool allowFMA(MachineFunction &MF, CodeGenOptLevel OptLevel) const
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
SelectionDAGISelPass(std::unique_ptr< SelectionDAGISel > Selector)
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)
LLVM_ABI MachineSDNode * getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT)
These are used for target selectors to create a new node with specified return type(s),...
allnodes_const_iterator allnodes_begin() const
allnodes_const_iterator allnodes_end() const
SDValue getTargetFrameIndex(int FI, EVT VT)
SDValue getSignedTargetConstant(int64_t Val, const SDLoc &DL, EVT VT, bool isOpaque=false)
LLVM_ABI void RemoveDeadNodes()
This method deletes all unreachable nodes in the SelectionDAG.
LLVM_ABI void ReplaceAllUsesOfValueWith(SDValue From, SDValue To)
Replace any uses of From with To, leaving uses of other values produced by From.getNode() alone.
LLVM_ABI SDValue getTargetExternalSymbol(const char *Sym, EVT VT, unsigned TargetFlags=0)
ilist< SDNode >::iterator allnodes_iterator
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
This class is used to represent ISD::STORE nodes.
const SDValue & getValue() const
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
A switch()-like statement whose cases are string literals.
StringSwitch & Case(StringLiteral S, T Value)
const Triple & getTargetTriple() const
Triple - Helper class for working with autoconf configuration names.
Definition Triple.h:48
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
Value * getOperand(unsigned i) const
Definition User.h:207
LLVM Value Representation.
Definition Value.h:75
Changed
#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.
@ Entry
Definition COFF.h:862
@ ATOMIC_STORE
OUTCHAIN = ATOMIC_STORE(INCHAIN, val, ptr) This corresponds to "store atomic" instruction.
@ ADD
Simple integer binary arithmetic operators.
Definition ISDOpcodes.h:266
@ 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.
Definition ISDOpcodes.h:523
@ INTRINSIC_VOID
OUTCHAIN = INTRINSIC_VOID(INCHAIN, INTRINSICID, arg1, arg2, ...) This node represents a target intrin...
Definition ISDOpcodes.h:222
@ FADD
Simple binary floating point operators.
Definition ISDOpcodes.h:420
@ 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...
Definition ISDOpcodes.h:71
@ CopyFromReg
CopyFromReg - This node indicates that the input value is a virtual or physical register that is defi...
Definition ISDOpcodes.h:232
@ SHL
Shift and rotation operations.
Definition ISDOpcodes.h:787
@ EXTRACT_VECTOR_ELT
EXTRACT_VECTOR_ELT(VECTOR, IDX) - Returns a single element from VECTOR identified by the (potentially...
Definition ISDOpcodes.h:581
@ CopyToReg
CopyToReg - This node has three operands: a chain, a register number to set to this value,...
Definition ISDOpcodes.h:226
@ AND
Bitwise operators - logical and, logical or, logical xor.
Definition ISDOpcodes.h:757
@ INTRINSIC_W_CHAIN
RESULT,OUTCHAIN = INTRINSIC_W_CHAIN(INCHAIN, INTRINSICID, arg1, ...) This node represents a target in...
Definition ISDOpcodes.h:215
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.
@ DeviceParam
Definition NVPTX.h:333
@ SharedCluster
Definition NVPTX.h:326
@ EntryParam
Definition NVPTX.h:327
unsigned encodeEvictionAndPrefetchHint(L1Eviction L1, L2Eviction L2, L2Prefetch P)
Definition NVPTX.h:378
bool isPackedVectorTy(EVT VT)
DivPrecisionLevel
Definition NVPTX.h:464
@ DefaultDevice
Definition NVPTX.h:315
@ RelaxedMMIO
Definition NVPTX.h:305
@ AcquireRelease
Definition NVPTX.h:301
@ NotAtomic
Definition NVPTX.h:294
@ SequentiallyConsistent
Definition NVPTX.h:302
initializer< Ty > init(const Ty &Val)
std::enable_if_t< detail::IsValidPointer< X, Y >::value, X * > dyn_extract(Y &&MD)
Extract a Value from Metadata, if any.
Definition Metadata.h:707
NodeAddr< NodeBase * > Node
Definition RDFGraph.h:381
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition STLExtras.h:316
@ Offset
Definition DWP.cpp:577
AtomicScope
Target-neutral memory synchronization scopes.
Definition AtomicScope.h:23
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
int countr_one(T Value)
Count the number of ones from the least significant bit to the first zero bit.
Definition bit.h:315
@ 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,...
int countr_zero(T Val)
Count number of 0's from the least significant bit to the most stopping at the first 1.
Definition bit.h:204
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...
Definition MathExtras.h:274
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.
Definition MathExtras.h:280
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
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...
Definition MathExtras.h:262
CodeGenOptLevel
Code generation optimization level.
Definition CodeGen.h:227
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...
Definition Casting.h:547
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
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.
Definition Casting.h:559
std::optional< StringRef > getAtomicScopeIRString(const Triple &T, AtomicScope S, bool IsSingleAddressSpace=false)
Returns the LLVM IR syncscope string that T uses to spell S.
Definition AtomicScope.h:34
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.
Definition Error.cpp:177
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:878
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition BitVector.h:880
#define N
A record for a potential prefetch made during the initial scan of the loop.
static void set(StorageType &Packed, typename Bitfield::Type Value)
Sets the typed value in the provided Packed value.
Definition Bitfields.h:223
Extended Value Type.
Definition ValueTypes.h:35
uint64_t getFixedSizeInBits() const
Return the size of the specified fixed width value type in bits.
Definition ValueTypes.h:404
bool isVector() const
Return true if this is a vector value type.
Definition ValueTypes.h:176
EVT getScalarType() const
If this is a vector type, return the element type, otherwise return this.
Definition ValueTypes.h:346
unsigned getVectorNumElements() const
Given a vector type, return the number of elements it contains.
Definition ValueTypes.h:359
A MapVector that performs no allocations if smaller than a certain size.
Definition MapVector.h:342