LLVM 24.0.0git
NVPTXISelLowering.cpp
Go to the documentation of this file.
1//===-- NVPTXISelLowering.cpp - NVPTX DAG Lowering Implementation ---------===//
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 the interfaces that NVPTX uses to lower LLVM code into a
10// selection DAG.
11//
12//===----------------------------------------------------------------------===//
13
14#include "NVPTXISelLowering.h"
16#include "NVPTX.h"
19#include "NVPTXSubtarget.h"
20#include "NVPTXTargetMachine.h"
22#include "NVPTXUtilities.h"
23#include "NVVMProperties.h"
24#include "llvm/ADT/APFloat.h"
25#include "llvm/ADT/APInt.h"
26#include "llvm/ADT/STLExtras.h"
28#include "llvm/ADT/StringRef.h"
42#include "llvm/IR/Argument.h"
43#include "llvm/IR/Attributes.h"
44#include "llvm/IR/Constants.h"
45#include "llvm/IR/DataLayout.h"
48#include "llvm/IR/FPEnv.h"
49#include "llvm/IR/Function.h"
50#include "llvm/IR/GlobalValue.h"
51#include "llvm/IR/IRBuilder.h"
52#include "llvm/IR/Instruction.h"
54#include "llvm/IR/IntrinsicsNVPTX.h"
55#include "llvm/IR/LLVMContext.h"
56#include "llvm/IR/Module.h"
58#include "llvm/IR/Type.h"
59#include "llvm/IR/Value.h"
60#include "llvm/MC/MCContext.h"
61#include "llvm/MC/MCSymbol.h"
72#include <algorithm>
73#include <cassert>
74#include <cmath>
75#include <cstdint>
76#include <iterator>
77#include <optional>
78#include <tuple>
79#include <utility>
80#include <vector>
81
82#define DEBUG_TYPE "nvptx-lower"
83
84using namespace llvm;
85
87 "nvptx-sched4reg",
88 cl::desc("NVPTX Specific: schedule for register pressue"), cl::init(false));
89
91 "nvptx-fma-level", cl::Hidden,
92 cl::desc("NVPTX Specific: FMA contraction (0: don't do it"
93 " 1: do it 2: do it aggressively"),
94 cl::init(2));
95
97 "nvptx-prec-divf32", cl::Hidden,
99 "NVPTX Specific: Override the precision of the lowering for f32 fdiv"),
101 clEnumValN(NVPTX::DivPrecisionLevel::Approx, "0", "Use div.approx"),
102 clEnumValN(NVPTX::DivPrecisionLevel::Full, "1", "Use div.full"),
104 "Use IEEE Compliant F32 div.rnd if available (default)"),
106 "Use IEEE Compliant F32 div.rnd if available, no FTZ")),
108
110 "nvptx-prec-sqrtf32", cl::Hidden,
111 cl::desc("NVPTX Specific: 0 use sqrt.approx, 1 use sqrt.rn."),
112 cl::init(true));
113
114// PTX atom.add.f32 has fixed FTZ behavior that may not match the function's
115// (see shouldExpandAtomicRMWInIR), so we'd normally fall back to a CAS loop
116// when they disagree. This option (enabled by default) allows using atom.add
117// anyway, trading correct denormal handling for the speed of the native
118// instruction.
120 "nvptx-allow-ftz-atomics", cl::Hidden,
121 cl::desc("NVPTX Specific: Lower atomicrmw fadd to atom.add even when its "
122 "FTZ behavior does not match the function's denormal mode."),
123 cl::init(true));
124
125/// Whereas CUDA's implementation (see libdevice) uses ex2.approx for exp2(), it
126/// does NOT use lg2.approx for log2, so this is disabled by default.
128 "nvptx-approx-log2f32",
129 cl::desc("NVPTX Specific: whether to use lg2.approx for log2"),
130 cl::init(false));
131
134 const SDNode &N) const {
135 // If nvptx-prec-div32=N is used on the command-line, always honor it
136 if (UsePrecDivF32.getNumOccurrences() > 0)
137 return UsePrecDivF32;
138
139 const SDNodeFlags Flags = N.getFlags();
140 if (Flags.hasApproximateFuncs())
142
144}
145
147 // If nvptx-prec-sqrtf32 is used on the command-line, always honor it
148 if (UsePrecSqrtF32.getNumOccurrences() > 0)
149 return UsePrecSqrtF32;
150
151 if (N) {
152 const SDNodeFlags Flags = N->getFlags();
153 if (Flags.hasApproximateFuncs())
154 return false;
155 }
156
157 return true;
158}
159
164
165static bool IsPTXVectorType(MVT VT) {
166 switch (VT.SimpleTy) {
167 default:
168 return false;
169 case MVT::v2i1:
170 case MVT::v4i1:
171 case MVT::v2i8:
172 case MVT::v4i8:
173 case MVT::v8i8: // <2 x i8x4>
174 case MVT::v16i8: // <4 x i8x4>
175 case MVT::v2i16:
176 case MVT::v4i16:
177 case MVT::v8i16: // <4 x i16x2>
178 case MVT::v2i32:
179 case MVT::v4i32:
180 case MVT::v2i64:
181 case MVT::v2f16:
182 case MVT::v4f16:
183 case MVT::v8f16: // <4 x f16x2>
184 case MVT::v2bf16:
185 case MVT::v4bf16:
186 case MVT::v8bf16: // <4 x bf16x2>
187 case MVT::v2f32:
188 case MVT::v4f32:
189 case MVT::v2f64:
190 case MVT::v4i64:
191 case MVT::v4f64:
192 case MVT::v8i32:
193 case MVT::v8f32:
194 case MVT::v16f16: // <8 x f16x2>
195 case MVT::v16bf16: // <8 x bf16x2>
196 case MVT::v16i16: // <8 x i16x2>
197 case MVT::v32i8: // <8 x i8x4>
198 return true;
199 }
200}
201
202// When legalizing vector loads/stores, this function is called, which does two
203// things:
204// 1. Determines Whether the vector is something we want to custom lower,
205// std::nullopt is returned if we do not want to custom lower it.
206// 2. If we do want to handle it, returns two parameters:
207// - unsigned int NumElts - The number of elements in the final vector
208// - EVT EltVT - The type of the elements in the final vector
209static std::optional<std::pair<unsigned int, MVT>>
211 unsigned AddressSpace) {
212 const bool CanLowerTo256Bit = STI.has256BitVectorLoadStore(AddressSpace);
213
214 if (CanLowerTo256Bit && VectorEVT.isScalarInteger() &&
215 VectorEVT.getSizeInBits() == 256)
216 return {{4, MVT::i64}};
217
218 if (!VectorEVT.isSimple())
219 return std::nullopt;
220 const MVT VectorVT = VectorEVT.getSimpleVT();
221
222 if (!VectorVT.isVector()) {
223 if (VectorVT == MVT::i128 || VectorVT == MVT::f128)
224 return {{2, MVT::i64}};
225 return std::nullopt;
226 }
227
228 const MVT EltVT = VectorVT.getVectorElementType();
229 const unsigned NumElts = VectorVT.getVectorNumElements();
230
231 // The size of the PTX virtual register that holds a packed type.
232 unsigned PackRegSize;
233
234 // We only handle "native" vector sizes for now, e.g. <4 x double> is not
235 // legal. We can (and should) split that into 2 stores of <2 x double> here
236 // but I'm leaving that as a TODO for now.
237 switch (VectorVT.SimpleTy) {
238 default:
239 return std::nullopt;
240
241 case MVT::v4i64:
242 case MVT::v4f64:
243 // This is a "native" vector type iff the address space is global and the
244 // target supports 256-bit loads/stores
245 if (!CanLowerTo256Bit)
246 return std::nullopt;
247 [[fallthrough]];
248 case MVT::v2i8:
249 case MVT::v2i64:
250 case MVT::v2f64:
251 // This is a "native" vector type
252 return std::pair(NumElts, EltVT);
253
254 case MVT::v16f16: // <8 x f16x2>
255 case MVT::v16bf16: // <8 x bf16x2>
256 case MVT::v16i16: // <8 x i16x2>
257 case MVT::v32i8: // <8 x i8x4>
258 // This can be upsized into a "native" vector type iff the address space is
259 // global and the target supports 256-bit loads/stores.
260 if (!CanLowerTo256Bit)
261 return std::nullopt;
262 [[fallthrough]];
263 case MVT::v2i16: // <1 x i16x2>
264 case MVT::v2f16: // <1 x f16x2>
265 case MVT::v2bf16: // <1 x bf16x2>
266 case MVT::v4i8: // <1 x i8x4>
267 case MVT::v4i16: // <2 x i16x2>
268 case MVT::v4f16: // <2 x f16x2>
269 case MVT::v4bf16: // <2 x bf16x2>
270 case MVT::v8i8: // <2 x i8x4>
271 case MVT::v8f16: // <4 x f16x2>
272 case MVT::v8bf16: // <4 x bf16x2>
273 case MVT::v8i16: // <4 x i16x2>
274 case MVT::v16i8: // <4 x i8x4>
275 PackRegSize = 32;
276 break;
277
278 case MVT::v8f32: // <4 x f32x2>
279 case MVT::v8i32: // <4 x i32x2>
280 // This is a "native" vector type iff the address space is global and the
281 // target supports 256-bit loads/stores
282 if (!CanLowerTo256Bit)
283 return std::nullopt;
284 [[fallthrough]];
285 case MVT::v2f32: // <1 x f32x2>
286 case MVT::v4f32: // <2 x f32x2>
287 case MVT::v2i32: // <1 x i32x2>
288 case MVT::v4i32: // <2 x i32x2>
289 if (!STI.hasF32x2Instructions())
290 return std::pair(NumElts, EltVT);
291 PackRegSize = 64;
292 break;
293 }
294
295 // If we reach here, then we can pack 2 or more elements into a single 32-bit
296 // or 64-bit PTX register and treat the vector as a new vector containing
297 // packed elements.
298
299 // Number of elements to pack in one word.
300 const unsigned NPerReg = PackRegSize / EltVT.getSizeInBits();
301
302 return std::pair(NumElts / NPerReg, MVT::getVectorVT(EltVT, NPerReg));
303}
304
305/// ComputePTXValueVTs - For the given Type \p Ty, returns the set of primitive
306/// legal-ish MVTs that compose it. Unlike ComputeValueVTs, this will legalize
307/// the types as required by the calling convention (with special handling for
308/// i8s).
309/// NOTE: This is a band-aid for code that expects ComputeValueVTs to return the
310/// same number of types as the Ins/Outs arrays in LowerFormalArguments,
311/// LowerCall, and LowerReturn.
312static void ComputePTXValueVTs(const TargetLowering &TLI, const DataLayout &DL,
313 LLVMContext &Ctx, CallingConv::ID CallConv,
314 Type *Ty, SmallVectorImpl<EVT> &ValueVTs,
316 uint64_t StartingOffset = 0) {
317 SmallVector<EVT, 16> TempVTs;
318 SmallVector<uint64_t, 16> TempOffsets;
319 ComputeValueVTs(TLI, DL, Ty, TempVTs, /*MemVTs=*/nullptr, &TempOffsets,
320 StartingOffset);
321
322 for (const auto [VT, Off] : zip(TempVTs, TempOffsets)) {
323 MVT RegisterVT = TLI.getRegisterTypeForCallingConv(Ctx, CallConv, VT);
324 unsigned NumRegs = TLI.getNumRegistersForCallingConv(Ctx, CallConv, VT);
325
326 // Since we actually can load/store b8, we need to ensure that we'll use
327 // the original sized type for any i8s or i8 vectors.
328 if (VT.getScalarType() == MVT::i8) {
329 if (RegisterVT == MVT::i16)
330 RegisterVT = MVT::i8;
331 else if (RegisterVT == MVT::v2i16)
332 RegisterVT = MVT::v2i8;
333 else
334 assert(RegisterVT == MVT::v4i8 &&
335 "Expected v4i8, v2i16, or i16 for i8 RegisterVT");
336 }
337
338 // TODO: This is horribly incorrect for cases where the vector elements are
339 // not a multiple of bytes (ex i1) and legal or i8. However, this problem
340 // has existed for as long as NVPTX has and no one has complained, so we'll
341 // leave it for now.
342 for (unsigned I : seq(NumRegs)) {
343 ValueVTs.push_back(RegisterVT);
344 Offsets.push_back(Off + I * RegisterVT.getStoreSize());
345 }
346 }
347}
348
349// We return an EVT that can hold N VTs
350// If the VT is a vector, the resulting EVT is a flat vector with the same
351// element type as VT's element type.
352static EVT getVectorizedVT(EVT VT, unsigned N, LLVMContext &C) {
353 if (N == 1)
354 return VT;
355
356 return VT.isVector() ? EVT::getVectorVT(C, VT.getScalarType(),
357 VT.getVectorNumElements() * N)
358 : EVT::getVectorVT(C, VT, N);
359}
360
362 const SDLoc &dl, SelectionDAG &DAG) {
363 if (V.getValueType() == VT) {
364 assert(I == 0 && "Index must be 0 for scalar value");
365 return V;
366 }
367
368 if (!VT.isVector())
369 return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, VT, V,
370 DAG.getVectorIdxConstant(I, dl));
371
372 return DAG.getNode(
373 ISD::EXTRACT_SUBVECTOR, dl, VT, V,
375}
376
377template <typename T>
378static inline SDValue getBuildVectorizedValue(unsigned N, const SDLoc &dl,
379 SelectionDAG &DAG, T GetElement) {
380 if (N == 1)
381 return GetElement(0);
382
384 for (const unsigned I : llvm::seq(N)) {
385 SDValue Val = GetElement(I);
386 if (Val.getValueType().isVector())
388 else
389 Values.push_back(Val);
390 }
391
392 EVT VT = EVT::getVectorVT(*DAG.getContext(), Values[0].getValueType(),
393 Values.size());
394 return DAG.getBuildVector(VT, dl, Values);
395}
396
397/// PromoteScalarIntegerPTX
398/// Used to make sure the arguments/returns are suitable for passing
399/// and promote them to a larger size if they're not.
400///
401/// The promoted type is placed in \p PromoteVT if the function returns true.
403 if (VT.isScalarInteger()) {
404 switch (PowerOf2Ceil(VT.getFixedSizeInBits())) {
405 default:
407 "Promotion is not suitable for scalars of size larger than 64-bits");
408 case 1:
409 return MVT::i1;
410 case 2:
411 case 4:
412 case 8:
413 return MVT::i8;
414 case 16:
415 return MVT::i16;
416 case 32:
417 return MVT::i32;
418 case 64:
419 return MVT::i64;
420 }
421 }
422 return VT;
423}
424
425// Check whether we can merge loads/stores of some of the pieces of a
426// flattened function parameter or return value into a single vector
427// load/store.
428//
429// The flattened parameter is represented as a list of EVTs and
430// offsets, and the whole structure is aligned to ParamAlignment. This
431// function determines whether we can load/store pieces of the
432// parameter starting at index Idx using a single vectorized op of
433// size AccessSize. If so, it returns the number of param pieces
434// covered by the vector op. Otherwise, it returns 1.
435template <typename T>
437 unsigned Idx, uint32_t AccessSize, const SmallVectorImpl<EVT> &ValueVTs,
438 const SmallVectorImpl<T> &Offsets, Align ParamAlignment) {
439
440 // Can't vectorize if param alignment is not sufficient.
441 if (ParamAlignment < AccessSize)
442 return 1;
443 // Can't vectorize if offset is not aligned.
444 if (Offsets[Idx] & (AccessSize - 1))
445 return 1;
446
447 EVT EltVT = ValueVTs[Idx];
448 unsigned EltSize = EltVT.getStoreSize();
449
450 // Element is too large to vectorize.
451 if (EltSize >= AccessSize)
452 return 1;
453
454 unsigned NumElts = AccessSize / EltSize;
455 // Can't vectorize if AccessBytes if not a multiple of EltSize.
456 if (AccessSize != EltSize * NumElts)
457 return 1;
458
459 // We don't have enough elements to vectorize.
460 if (Idx + NumElts > ValueVTs.size())
461 return 1;
462
463 // PTX ISA can only deal with 2- and 4-element vector ops.
464 if (NumElts != 4 && NumElts != 2)
465 return 1;
466
467 for (unsigned j = Idx + 1; j < Idx + NumElts; ++j) {
468 // Types do not match.
469 if (ValueVTs[j] != EltVT)
470 return 1;
471
472 // Elements are not contiguous.
473 if (Offsets[j] - Offsets[j - 1] != EltSize)
474 return 1;
475 }
476 // OK. We can vectorize ValueVTs[i..i+NumElts)
477 return NumElts;
478}
479
480// Computes whether and how we can vectorize the loads/stores of a
481// flattened function parameter or return value.
482//
483// The flattened parameter is represented as the list of ValueVTs and
484// Offsets, and is aligned to ParamAlignment bytes. We return a vector
485// of the same size as ValueVTs indicating how each piece should be
486// loaded/stored (i.e. as a scalar, or as part of a vector
487// load/store).
488template <typename T>
491 const SmallVectorImpl<T> &Offsets, Align ParamAlignment,
492 bool IsVAArg = false) {
493 // Set vector size to match ValueVTs and mark all elements as
494 // scalars by default.
495
496 if (IsVAArg)
497 return SmallVector<unsigned>(ValueVTs.size(), 1);
498
499 SmallVector<unsigned, 16> VectorInfo;
500
501 const auto GetNumElts = [&](unsigned I) -> unsigned {
502 for (const unsigned AccessSize : {16, 8, 4, 2}) {
503 const unsigned NumElts = canMergeParamLoadStoresStartingAt(
504 I, AccessSize, ValueVTs, Offsets, ParamAlignment);
505 assert((NumElts == 1 || NumElts == 2 || NumElts == 4) &&
506 "Unexpected vectorization size");
507 if (NumElts != 1)
508 return NumElts;
509 }
510 return 1;
511 };
512
513 // Check what we can vectorize using 128/64/32-bit accesses.
514 for (unsigned I = 0, E = ValueVTs.size(); I != E;) {
515 const unsigned NumElts = GetNumElts(I);
516 VectorInfo.push_back(NumElts);
517 I += NumElts;
518 }
519 assert(std::accumulate(VectorInfo.begin(), VectorInfo.end(), 0u) ==
520 ValueVTs.size());
521 return VectorInfo;
522}
523
524// NVPTXTargetLowering Constructor.
526 const NVPTXSubtarget &STI)
527 : TargetLowering(TM, STI), STI(STI), GlobalUniqueCallSite(0) {
528 // always lower memset, memcpy, and memmove intrinsics to load/store
529 // instructions, rather
530 // then generating calls to memset, mempcy or memmove.
534
537
538 // Jump is Expensive. Don't create extra control flow for 'and', 'or'
539 // condition branches.
540 setJumpIsExpensive(true);
541
542 // Wide divides are _very_ slow. Try to reduce the width of the divide if
543 // possible.
544 addBypassSlowDiv(64, 32);
545
546 // By default, use the Source scheduling
547 if (sched4reg)
549 else
551
552 auto setFP16OperationAction = [&](unsigned Op, MVT VT, LegalizeAction Action,
553 LegalizeAction NoF16Action) {
554 bool IsOpSupported = STI.allowFP16Math();
555 switch (Op) {
556 // Several FP16 instructions are available on sm_80 only.
557 case ISD::FMINNUM:
558 case ISD::FMAXNUM:
561 case ISD::FMAXIMUM:
562 case ISD::FMINIMUM:
563 case ISD::FMAXIMUMNUM:
564 case ISD::FMINIMUMNUM:
565 IsOpSupported &= STI.hasFeature(NVPTX::SM80);
566 break;
567 case ISD::FEXP2:
568 case ISD::FTANH:
569 IsOpSupported &=
570 STI.hasFeature(NVPTX::SM75) && STI.hasFeature(NVPTX::PTX70);
571 break;
572 }
573 setOperationAction(Op, VT, IsOpSupported ? Action : NoF16Action);
574 };
575
576 auto setBF16OperationAction = [&](unsigned Op, MVT VT, LegalizeAction Action,
577 LegalizeAction NoBF16Action) {
578 bool IsOpSupported = STI.hasNativeBF16Support(Op);
580 Op, VT, IsOpSupported ? Action : NoBF16Action);
581 };
582
583 auto setI16x2OperationAction = [&](unsigned Op, MVT VT, LegalizeAction Action,
584 LegalizeAction NoI16x2Action) {
585 bool IsOpSupported = false;
586 // instructions are available on sm_90 only
587 switch (Op) {
588 case ISD::ADD:
589 case ISD::SMAX:
590 case ISD::SMIN:
591 case ISD::UMIN:
592 case ISD::UMAX:
593 IsOpSupported =
594 STI.hasFeature(NVPTX::SM90) && STI.hasFeature(NVPTX::PTX80);
595 break;
596 }
597 setOperationAction(Op, VT, IsOpSupported ? Action : NoI16x2Action);
598 };
599
600 addRegisterClass(MVT::i1, &NVPTX::B1RegClass);
601 addRegisterClass(MVT::i16, &NVPTX::B16RegClass);
602 addRegisterClass(MVT::v2i16, &NVPTX::B32RegClass);
603 addRegisterClass(MVT::v4i8, &NVPTX::B32RegClass);
604 addRegisterClass(MVT::i32, &NVPTX::B32RegClass);
605 addRegisterClass(MVT::i64, &NVPTX::B64RegClass);
606 addRegisterClass(MVT::f32, &NVPTX::B32RegClass);
607 addRegisterClass(MVT::f64, &NVPTX::B64RegClass);
608 addRegisterClass(MVT::f16, &NVPTX::B16RegClass);
609 addRegisterClass(MVT::v2f16, &NVPTX::B32RegClass);
610 addRegisterClass(MVT::bf16, &NVPTX::B16RegClass);
611 addRegisterClass(MVT::v2bf16, &NVPTX::B32RegClass);
612
613 if (STI.hasF32x2Instructions()) {
614 addRegisterClass(MVT::v2f32, &NVPTX::B64RegClass);
615 addRegisterClass(MVT::v2i32, &NVPTX::B64RegClass);
616 }
617
618 // Conversion to/from FP16/FP16x2 is always legal.
623
625 if (STI.hasFeature(NVPTX::SM30))
627
628 setFP16OperationAction(ISD::SETCC, MVT::f16, Legal, Promote);
629 setFP16OperationAction(ISD::SETCC, MVT::v2f16, Legal, Expand);
630
631 // Conversion to/from BFP16/BFP16x2 is always legal.
636
637 setBF16OperationAction(ISD::SETCC, MVT::v2bf16, Legal, Expand);
638 setBF16OperationAction(ISD::SETCC, MVT::bf16, Legal, Promote);
639 if (getOperationAction(ISD::SETCC, MVT::bf16) == Promote)
640 AddPromotedToType(ISD::SETCC, MVT::bf16, MVT::f32);
641
642 // Conversion to/from i16/i16x2 is always legal.
647
652
653 // No support for these operations with v2f32/v2i32
654 setOperationAction(ISD::INSERT_VECTOR_ELT, {MVT::v2f32, MVT::v2i32}, Expand);
655 setOperationAction(ISD::VECTOR_SHUFFLE, {MVT::v2f32, MVT::v2i32}, Expand);
656
659 MVT::v2i32, Expand);
660
661 // Need custom lowering in case the index is dynamic.
662 if (STI.hasF32x2Instructions())
663 setOperationAction(ISD::EXTRACT_VECTOR_ELT, {MVT::v2f32, MVT::v2i32},
664 Custom);
665
666 // Custom conversions to/from v2i8.
668
669 // Only logical ops can be done on v4i8/v2i32 directly, others must be done
670 // elementwise.
687 {MVT::v4i8, MVT::v2i32}, Expand);
688
689 // Operations not directly supported by NVPTX.
690 for (MVT VT : {MVT::bf16, MVT::f16, MVT::v2bf16, MVT::v2f16, MVT::f32,
691 MVT::v2f32, MVT::f64, MVT::i1, MVT::i8, MVT::i16, MVT::v2i16,
692 MVT::v4i8, MVT::i32, MVT::v2i32, MVT::i64}) {
695 }
696
697 setOperationAction(ISD::SDIVREM, {MVT::i32, MVT::i64}, Expand);
698 setOperationAction(ISD::UDIVREM, {MVT::i32, MVT::i64}, Expand);
699
700 // We don't want ops like FMINIMUM or UMAX to be lowered to SETCC+VSELECT.
701 setOperationAction(ISD::VSELECT, {MVT::v2f32, MVT::v2i32}, Expand);
702
703 // Some SIGN_EXTEND_INREG can be done using cvt instruction.
704 // For others we will expand to a SHL/SRA pair.
710 setOperationAction(ISD::SIGN_EXTEND_INREG, {MVT::v2i16, MVT::v2i32}, Expand);
711
718
719 if (STI.hasCLMAD())
723
725 {MVT::i8, MVT::i16, MVT::v2i16, MVT::i32, MVT::i64},
726 Expand);
727
728 if (STI.hasHWROT32()) {
731 Custom);
732 }
733
734 setOperationAction(ISD::BR_JT, MVT::Other, STI.hasBrx() ? Legal : Expand);
736
737 // We want to legalize constant related memmove and memcopy
738 // intrinsics.
740
741 // FP extload/truncstore is not legal in PTX. We need to expand all these.
742 for (auto FloatVTs :
744 for (MVT ValVT : FloatVTs) {
745 for (MVT MemVT : FloatVTs) {
746 setLoadExtAction(ISD::EXTLOAD, ValVT, MemVT, Expand);
747 setTruncStoreAction(ValVT, MemVT, Expand);
748 }
749 }
750 }
751
752 // To improve CodeGen we'll legalize any-extend loads to zext loads. This is
753 // how they'll be lowered in ISel anyway, and by doing this a little earlier
754 // we allow for more DAG combine opportunities.
755 for (auto IntVTs :
757 for (MVT ValVT : IntVTs)
758 for (MVT MemVT : IntVTs)
759 if (isTypeLegal(ValVT))
760 setLoadExtAction(ISD::EXTLOAD, ValVT, MemVT, Custom);
761
762 // PTX does not support load / store predicate registers
764 for (MVT VT : MVT::integer_valuetypes()) {
766 Promote);
767 setTruncStoreAction(VT, MVT::i1, Expand);
768 }
769
770 // Disable generations of extload/truncstore for v2i32/v2i16/v2i8. The generic
771 // expansion for these nodes when they are unaligned is incorrect if the
772 // type is a vector.
773 //
774 // TODO: Fix the generic expansion for these nodes found in
775 // TargetLowering::expandUnalignedLoad/Store.
777 MVT::v2i8, Expand);
779 {MVT::v2i8, MVT::v2i16}, Expand);
780 setTruncStoreAction(MVT::v2i16, MVT::v2i8, Expand);
781 setTruncStoreAction(MVT::v2i32, MVT::v2i16, Expand);
782 setTruncStoreAction(MVT::v2i32, MVT::v2i8, Expand);
783
784 // Register custom handling for illegal type loads/stores. We'll try to custom
785 // lower almost all illegal types and logic in the lowering will discard cases
786 // we can't handle.
787 setOperationAction({ISD::LOAD, ISD::STORE}, {MVT::i128, MVT::i256, MVT::f128},
788 Custom);
790 if (!isTypeLegal(VT) && VT.getStoreSizeInBits() <= 256)
792 Custom);
793
794 // Custom legalization for LDU intrinsics.
795 // TODO: The logic to lower these is not very robust and we should rewrite it.
796 // Perhaps LDU should not be represented as an intrinsic at all.
799 if (IsPTXVectorType(VT))
801
805 MVT::i1, Expand);
806
807 // This is legal in NVPTX
812
813 setOperationAction(ISD::DYNAMIC_STACKALLOC, {MVT::i32, MVT::i64}, Custom);
815
816 // TRAP can be lowered to PTX trap
817 setOperationAction(ISD::TRAP, MVT::Other, Legal);
818 // DEBUGTRAP can be lowered to PTX brkpt
820
821 // Support varargs.
826
828 {MVT::i16, MVT::i32, MVT::i64}, Legal);
829 // PTX abs.s is undefined for INT_MIN, so ISD::ABS (which requires
830 // abs(INT_MIN) == INT_MIN) must be expanded. ABS_MIN_POISON matches
831 // PTX abs semantics since INT_MIN input is poison/undefined.
832 setOperationAction(ISD::ABS, {MVT::i16, MVT::i32, MVT::i64}, Expand);
833 setOperationAction(ISD::ABS_MIN_POISON, {MVT::i16, MVT::i32, MVT::i64},
834 Legal);
835
837 Promote);
840
841 setI16x2OperationAction(ISD::ABS_MIN_POISON, MVT::v2i16, Legal, Custom);
842 setI16x2OperationAction(ISD::SMIN, MVT::v2i16, Legal, Custom);
843 setI16x2OperationAction(ISD::SMAX, MVT::v2i16, Legal, Custom);
844 setI16x2OperationAction(ISD::UMIN, MVT::v2i16, Legal, Custom);
845 setI16x2OperationAction(ISD::UMAX, MVT::v2i16, Legal, Custom);
846 setI16x2OperationAction(ISD::CTPOP, MVT::v2i16, Legal, Expand);
847 setI16x2OperationAction(ISD::CTLZ, MVT::v2i16, Legal, Expand);
848
849 setI16x2OperationAction(ISD::ADD, MVT::v2i16, Legal, Custom);
850 setI16x2OperationAction(ISD::SUB, MVT::v2i16, Legal, Custom);
851 setI16x2OperationAction(ISD::MUL, MVT::v2i16, Legal, Custom);
852 setI16x2OperationAction(ISD::SHL, MVT::v2i16, Legal, Custom);
853 setI16x2OperationAction(ISD::SREM, MVT::v2i16, Legal, Custom);
854 setI16x2OperationAction(ISD::UREM, MVT::v2i16, Legal, Custom);
855
856 // Other arithmetic and logic ops are unsupported.
861 MVT::v2i16, Expand);
862
863 // v2i32 is not supported for any arithmetic operations
868 MVT::v2i32, Expand);
869
874 if (STI.hasFeature(NVPTX::PTX43)) {
879 }
880
882 setOperationAction(ISD::CTTZ, {MVT::v2i16, MVT::v2i32}, Expand);
885
886 // PTX does not directly support SELP of i1, so promote to i32 first
888
889 // PTX only exposes separate mul.lo and mul.hi forms. Lower i16 and i32 to
890 // use mul.wide. i64 has no mul.wide, so it expands to MUL and MULHS/MULHU.
891 setOperationAction({ISD::SMUL_LOHI, ISD::UMUL_LOHI}, {MVT::i16, MVT::i32},
892 Custom);
894
895 // We have some custom DAG combine patterns for these nodes
897 ISD::AND,
899 ISD::FADD,
906 ISD::MUL,
908 ISD::SHL,
909 ISD::SREM,
910 ISD::UREM,
914 ISD::LOAD,
919
920 // If the vector operands require register coalescing, scalarize instead
921 if (STI.hasF32x2Instructions())
923
924 // setcc for f16x2 and bf16x2 needs special handling to prevent
925 // legalizer's attempt to scalarize it due to v2i1 not being legal.
926 if (STI.allowFP16Math() || STI.hasBF16Math())
928
929 // Vector reduction operations. These may be turned into shuffle or tree
930 // reductions depending on what instructions are available for each type.
932 MVT EltVT = VT.getVectorElementType();
933 if (EltVT == MVT::f32 || EltVT == MVT::f64) {
938 VT, Custom);
939 }
940 }
941
942 // Promote fp16 arithmetic if fp16 hardware isn't available or the
943 // user passed --nvptx-no-fp16-math. The flag is useful because,
944 // although sm_53+ GPUs have some sort of FP16 support in
945 // hardware, only sm_53 and sm_60 have full implementation. Others
946 // only have token amount of hardware and are likely to run faster
947 // by using fp32 units instead.
948 for (const auto &Op : {ISD::FADD, ISD::FMUL, ISD::FSUB, ISD::FMA}) {
949 setFP16OperationAction(Op, MVT::f16, Legal, Promote);
950 setFP16OperationAction(Op, MVT::v2f16, Legal, Expand);
951 setBF16OperationAction(Op, MVT::v2bf16, Legal, Expand);
952 // bf16 must be promoted to f32.
953 setBF16OperationAction(Op, MVT::bf16, Legal, Promote);
954 if (getOperationAction(Op, MVT::bf16) == Promote)
955 AddPromotedToType(Op, MVT::bf16, MVT::f32);
956 setOperationAction(Op, MVT::v2f32,
957 STI.hasF32x2Instructions() ? Legal : Expand);
958 }
959
960 // On SM80, we select add/mul/sub as fma to avoid promotion to float
961 for (const auto &Op : {ISD::FADD, ISD::FMUL, ISD::FSUB}) {
962 for (const auto &VT : {MVT::bf16, MVT::v2bf16}) {
963 if (!STI.hasNativeBF16Support(Op) && STI.hasNativeBF16Support(ISD::FMA)) {
965 }
966 }
967 }
968
969 // f16/f16x2 neg was introduced in PTX 60, SM_53.
970 const bool IsFP16FP16x2NegAvailable = STI.hasFeature(NVPTX::SM53) &&
971 STI.hasFeature(NVPTX::PTX60) &&
972 STI.allowFP16Math();
973 for (const auto &VT : {MVT::f16, MVT::v2f16})
975 IsFP16FP16x2NegAvailable ? Legal : Expand);
976
977 setBF16OperationAction(ISD::FNEG, MVT::bf16, Legal, Expand);
978 setBF16OperationAction(ISD::FNEG, MVT::v2bf16, Legal, Expand);
979 setOperationAction(ISD::FNEG, MVT::v2f32, Expand);
980 // (would be) Library functions.
981
982 // These map to conversion instructions for scalar FP types.
983 for (const auto &Op : {ISD::FCEIL, ISD::FFLOOR, ISD::FNEARBYINT, ISD::FRINT,
985 setOperationAction(Op, MVT::f16, Legal);
986 setOperationAction(Op, MVT::f32, Legal);
987 setOperationAction(Op, MVT::f64, Legal);
988 setOperationAction(Op, MVT::v2f16, Expand);
989 setOperationAction(Op, MVT::v2bf16, Expand);
990 setOperationAction(Op, MVT::v2f32, Expand);
991 setBF16OperationAction(Op, MVT::bf16, Legal, Promote);
992 if (getOperationAction(Op, MVT::bf16) == Promote)
993 AddPromotedToType(Op, MVT::bf16, MVT::f32);
994 }
995
996 if (!STI.hasFeature(NVPTX::SM80) || !STI.hasFeature(NVPTX::PTX71)) {
998 }
999 if (!STI.hasFeature(NVPTX::SM90)) {
1000 for (MVT VT : {MVT::bf16, MVT::f32, MVT::f64}) {
1003 }
1004 }
1005
1006 // Expand nearest-even rounding and diagnose unsupported conversions.
1007 setOperationAction(ISD::FPTRUNC_ROUND, {MVT::f16, MVT::bf16, MVT::f32},
1008 Custom);
1009
1010 // Expand v2f32 = fp_extend
1012 // Expand v2[b]f16 = fp_round v2f32
1013 setOperationAction(ISD::FP_ROUND, {MVT::v2bf16, MVT::v2f16}, Expand);
1014
1015 // sm_80 only has conversions between f32 and bf16. Custom lower all other
1016 // bf16 conversions.
1017 if (!STI.hasFeature(NVPTX::SM90)) {
1018 for (MVT VT : {MVT::i1, MVT::i16, MVT::i32, MVT::i64}) {
1021 VT, Custom);
1022 }
1025 MVT::bf16, Custom);
1026 }
1027
1031 setOperationAction(ISD::FROUND, MVT::v2bf16, Expand);
1035 AddPromotedToType(ISD::FROUND, MVT::bf16, MVT::f32);
1036
1037 setOperationAction({ISD::LROUND, ISD::LLROUND}, {MVT::f32, MVT::f64}, Expand);
1038
1039 // 'Expand' implements FCOPYSIGN without calling an external library.
1046
1047 // These map to corresponding instructions for f32/f64. f16 must be
1048 // promoted to f32. v2f16 is expanded to f16, which is then promoted
1049 // to f32.
1050 for (const auto &Op : {ISD::FDIV, ISD::FSQRT, ISD::FSIN, ISD::FCOS}) {
1051 setOperationAction(Op, MVT::f16, Promote);
1052 setOperationAction(Op, MVT::f32, Legal);
1053 // Only div/sqrt are legal for f64.
1054 if (Op == ISD::FDIV || Op == ISD::FSQRT) {
1055 setOperationAction(Op, MVT::f64, Legal);
1056 }
1057 setOperationAction(Op, {MVT::v2f16, MVT::v2bf16, MVT::v2f32}, Expand);
1058 setOperationAction(Op, MVT::bf16, Promote);
1059 AddPromotedToType(Op, MVT::bf16, MVT::f32);
1060 }
1061 // Expand remainders at the IR level using ExpandIRInsts.
1062 setOperationAction(ISD::FREM, {MVT::f16, MVT::bf16, MVT::f32, MVT::f64},
1063 Expand);
1064
1065 // FTANH support:
1066 // - f32 (sm_75+, PTX 7.0+)
1067 // - f16/f16x2 (sm_75+, PTX 7.0+)
1068 // - bf16/bf16x2 (sm_90+, PTX 7.8+)
1069 // When f16/bf16 types aren't supported, they are promoted/expanded to f32.
1070 if (STI.hasFeature(NVPTX::SM75) && STI.hasFeature(NVPTX::PTX70))
1072 setOperationAction(ISD::FTANH, MVT::v2f32, Expand);
1073
1074 // Scalar f16/bf16: promote to f32 when not natively supported.
1075 setFP16OperationAction(ISD::FTANH, MVT::f16, Legal, Promote);
1076 setBF16OperationAction(ISD::FTANH, MVT::bf16, Legal, Promote);
1077 if (getOperationAction(ISD::FTANH, MVT::bf16) == Promote)
1078 AddPromotedToType(ISD::FTANH, MVT::bf16, MVT::f32);
1079
1080 // Vector v2f16/v2bf16: expand when not natively supported.
1081 setFP16OperationAction(ISD::FTANH, MVT::v2f16, Legal, Expand);
1082 setBF16OperationAction(ISD::FTANH, MVT::v2bf16, Legal, Expand);
1083
1084 setOperationAction(ISD::FABS, {MVT::f32, MVT::f64}, Legal);
1085 setOperationAction(ISD::FABS, MVT::v2f32, Expand);
1086 if (STI.hasFeature(NVPTX::PTX65)) {
1087 setFP16OperationAction(ISD::FABS, MVT::f16, Legal, Promote);
1088 setFP16OperationAction(ISD::FABS, MVT::v2f16, Legal, Expand);
1089 } else {
1091 setOperationAction(ISD::FABS, MVT::v2f16, Expand);
1092 }
1093 setBF16OperationAction(ISD::FABS, MVT::v2bf16, Legal, Expand);
1094 setBF16OperationAction(ISD::FABS, MVT::bf16, Legal, Promote);
1095 if (getOperationAction(ISD::FABS, MVT::bf16) == Promote)
1096 AddPromotedToType(ISD::FABS, MVT::bf16, MVT::f32);
1097
1098 for (const auto &Op :
1100 setOperationAction(Op, MVT::f32, Legal);
1101 setOperationAction(Op, MVT::f64, Legal);
1102 setFP16OperationAction(Op, MVT::f16, Legal, Promote);
1103 setFP16OperationAction(Op, MVT::v2f16, Legal, Expand);
1104 setBF16OperationAction(Op, MVT::v2bf16, Legal, Expand);
1105 setBF16OperationAction(Op, MVT::bf16, Legal, Promote);
1106 if (getOperationAction(Op, MVT::bf16) == Promote)
1107 AddPromotedToType(Op, MVT::bf16, MVT::f32);
1108 setOperationAction(Op, MVT::v2f32, Expand);
1109 }
1110 bool SupportsF32MinMaxNaN = STI.hasFeature(NVPTX::SM80);
1111 for (const auto &Op : {ISD::FMINIMUM, ISD::FMAXIMUM}) {
1112 setOperationAction(Op, MVT::f32, SupportsF32MinMaxNaN ? Legal : Expand);
1113 setFP16OperationAction(Op, MVT::f16, Legal, Expand);
1114 setFP16OperationAction(Op, MVT::v2f16, Legal, Expand);
1115 setBF16OperationAction(Op, MVT::bf16, Legal, Expand);
1116 setBF16OperationAction(Op, MVT::v2bf16, Legal, Expand);
1117 setOperationAction(Op, MVT::v2f32, Expand);
1118 }
1119
1120 // Custom lowering for inline asm with 128-bit operands
1123
1124 // FEXP2 support:
1125 // - f32
1126 // - f16/f16x2 (sm_70+, PTX 7.0+)
1127 // - bf16/bf16x2 (sm_90+, PTX 7.8+)
1128 // When f16/bf16 types aren't supported, they are promoted/expanded to f32.
1130 setOperationAction(ISD::FEXP2, MVT::v2f32, Expand);
1131 setFP16OperationAction(ISD::FEXP2, MVT::f16, Legal, Promote);
1132 setFP16OperationAction(ISD::FEXP2, MVT::v2f16, Legal, Expand);
1133 setBF16OperationAction(ISD::FEXP2, MVT::bf16, Legal, Promote);
1134 setBF16OperationAction(ISD::FEXP2, MVT::v2bf16, Legal, Expand);
1135
1136 // FLOG2 supports f32 only
1137 // f16/bf16 types aren't supported, but they are promoted/expanded to f32.
1138 if (UseApproxLog2F32) {
1140 setOperationPromotedToType(ISD::FLOG2, MVT::f16, MVT::f32);
1141 setOperationPromotedToType(ISD::FLOG2, MVT::bf16, MVT::f32);
1142 setOperationAction(ISD::FLOG2, {MVT::v2f16, MVT::v2bf16, MVT::v2f32},
1143 Expand);
1144 }
1145
1146 setOperationAction(ISD::ADDRSPACECAST, {MVT::i32, MVT::i64}, Custom);
1147
1148 // atom.b128 is legal in PTX but since we don't represent i128 as a legal
1149 // type, we need to custom lower it.
1151 Custom);
1152
1153 // Now deduce the information based on the above mentioned
1154 // actions
1155 computeRegisterProperties(STI.getRegisterInfo());
1156
1157 // PTX support for 16-bit CAS is emulated. Only use 32+
1158 setMinCmpXchgSizeInBits(STI.getMinCmpXchgSizeInBits());
1159 setMaxAtomicSizeInBitsSupported(STI.hasAtomSwap128() ? 128 : 64);
1162
1163 // Custom lowering for tcgen05.ld vector operands
1165 {MVT::v1i32, MVT::v2i32, MVT::v4i32, MVT::v8i32,
1166 MVT::v16i32, MVT::v32i32, MVT::v64i32, MVT::v128i32,
1167 MVT::v2f32, MVT::v4f32, MVT::v8f32, MVT::v16f32,
1168 MVT::v32f32, MVT::v64f32, MVT::v128f32},
1169 Custom);
1170
1171 // Custom lowering for tcgen05.st vector operands and the st.async
1172 // i128 (.b128) operand. MVT::i8 is needed for the st.async.{sys,gpu} b8
1173 // variant.
1175 {MVT::i8, MVT::v1i32, MVT::v2i32, MVT::v4i32, MVT::v8i32,
1176 MVT::v16i32, MVT::v32i32, MVT::v64i32, MVT::v128i32,
1177 MVT::i128, MVT::Other},
1178 Custom);
1179
1180 // Enable custom lowering for the following:
1181 // * MVT::i128 - clusterlaunchcontrol
1182 // * MVT::i32 - prmt
1183 // * MVT::v4f32 - cvt_rs fp{4/6/8}x4 intrinsics
1184 // * MVT::Other - internal.addrspace.wrap
1186 {MVT::i32, MVT::i128, MVT::v4f32, MVT::Other}, Custom);
1187
1188 // Custom lowering for bswap
1189 setOperationAction(ISD::BSWAP, {MVT::i16, MVT::i32, MVT::i64, MVT::v2i16},
1190 Custom);
1191}
1192
1195 if (!VT.isScalableVector() && VT.getVectorNumElements() != 1 &&
1196 VT.getScalarType() == MVT::i1)
1197 return TypeSplitVector;
1199}
1200
1202 int Enabled, int &ExtraSteps,
1203 bool &UseOneConst,
1204 bool Reciprocal) const {
1207 return SDValue();
1208
1209 if (ExtraSteps == ReciprocalEstimate::Unspecified)
1210 ExtraSteps = 0;
1211
1212 SDLoc DL(Operand);
1213 EVT VT = Operand.getValueType();
1214 bool Ftz = useF32FTZ(DAG.getMachineFunction());
1215
1216 auto MakeIntrinsicCall = [&](Intrinsic::ID IID) {
1217 return DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, VT,
1218 DAG.getConstant(IID, DL, MVT::i32), Operand);
1219 };
1220
1221 // The sqrt and rsqrt refinement processes assume we always start out with an
1222 // approximation of the rsqrt. Therefore, if we're going to do any refinement
1223 // (i.e. ExtraSteps > 0), we must return an rsqrt. But if we're *not* doing
1224 // any refinement, we must return a regular sqrt.
1225 if (Reciprocal || ExtraSteps > 0) {
1226 if (VT == MVT::f32)
1227 return MakeIntrinsicCall(Ftz ? Intrinsic::nvvm_rsqrt_approx_ftz_f
1228 : Intrinsic::nvvm_rsqrt_approx_f);
1229 else if (VT == MVT::f64)
1230 return MakeIntrinsicCall(Intrinsic::nvvm_rsqrt_approx_d);
1231 else
1232 return SDValue();
1233 } else {
1234 if (VT == MVT::f32)
1235 return MakeIntrinsicCall(Ftz ? Intrinsic::nvvm_sqrt_approx_ftz_f
1236 : Intrinsic::nvvm_sqrt_approx_f);
1237 else {
1238 // There's no sqrt.approx.f64 instruction, so we emit
1239 // reciprocal(rsqrt(x)). This is faster than
1240 // select(x == 0, 0, x * rsqrt(x)). (In fact, it's faster than plain
1241 // x * rsqrt(x).)
1242 return DAG.getNode(
1244 DAG.getConstant(Intrinsic::nvvm_rcp_approx_ftz_d, DL, MVT::i32),
1245 MakeIntrinsicCall(Intrinsic::nvvm_rsqrt_approx_d));
1246 }
1247 }
1248}
1249
1251 // Load directly from the source address space of a cast to generic.
1252 unsigned SrcAS = ADDRESS_SPACE_GENERIC;
1253 if (Ptr->getOpcode() == ISD::ADDRSPACECAST) {
1254 const auto *ASC = cast<AddrSpaceCastSDNode>(Ptr);
1255 if (ASC->getDestAddressSpace() == ADDRESS_SPACE_GENERIC) {
1256 Ptr = ASC->getOperand(0);
1257 SrcAS = ASC->getSrcAddressSpace();
1258 }
1259 }
1260
1261 // Preserve the alloca's address space through frame-index inference.
1262 if (const auto *FIN = dyn_cast<FrameIndexSDNode>(Ptr))
1263 if (const AllocaInst *AI =
1265 FIN->getIndex()))
1266 return MachinePointerInfo(AI);
1267
1268 return MachinePointerInfo(SrcAS);
1269}
1270
1272 if (Flags.isSExt())
1273 return ISD::SIGN_EXTEND;
1274 if (Flags.isZExt())
1275 return ISD::ZERO_EXTEND;
1276 return ISD::ANY_EXTEND;
1277}
1278
1280 ISD::ArgFlagsTy Flags, SelectionDAG &DAG,
1281 SDLoc dl) {
1282 const EVT ActualVT = V.getValueType();
1283 assert((ActualVT == ExpectedVT ||
1284 (ExpectedVT.isInteger() && ActualVT.isInteger())) &&
1285 "Non-integer argument type size mismatch");
1286 if (ExpectedVT.bitsGT(ActualVT))
1287 return DAG.getNode(getExtOpcode(Flags), dl, ExpectedVT, V);
1288 if (ExpectedVT.bitsLT(ActualVT))
1289 return DAG.getNode(ISD::TRUNCATE, dl, ExpectedVT, V);
1290
1291 return V;
1292}
1293
1295 return DAG.getNode(NVPTXISD::Symbol, SDLoc(), T, DAG.getMCSymbol(Sym, T));
1296}
1297
1298static SDValue getSymbolNode(SelectionDAG &DAG, const Twine &Name, EVT T) {
1300 return getSymbolNode(DAG, Ctx.getOrCreateSymbol(Name), T);
1301}
1302
1304 SmallVectorImpl<SDValue> &InVals) const {
1305
1306 if (CLI.IsVarArg &&
1307 (!STI.hasFeature(NVPTX::PTX60) || !STI.hasFeature(NVPTX::SM30)))
1309 "Support for variadic functions (unsized array parameter) introduced "
1310 "in PTX ISA version 6.0 and requires target sm_30.");
1311
1312 SelectionDAG &DAG = CLI.DAG;
1313 SDLoc dl = CLI.DL;
1314 const SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins;
1315 SDValue Callee = CLI.Callee;
1316 ArgListTy &Args = CLI.getArgs();
1317 Type *RetTy = CLI.RetTy;
1318 const CallBase *CB = CLI.CB;
1319 const DataLayout &DL = DAG.getDataLayout();
1320 LLVMContext &Ctx = *DAG.getContext();
1321
1322 const auto GetI32 = [&](const unsigned I) {
1323 return DAG.getConstant(I, dl, MVT::i32);
1324 };
1325
1326 const unsigned UniqueCallSite = GlobalUniqueCallSite++;
1327 const SDValue CallChain = CLI.Chain;
1328 const SDValue StartChain =
1329 DAG.getCALLSEQ_START(CallChain, UniqueCallSite, 0, dl);
1330 SDValue DeclareGlue = StartChain.getValue(1);
1331
1332 SmallVector<SDValue, 16> CallPrereqs{StartChain};
1333
1334 const auto MakeDeclareScalarParam = [&](SDValue Symbol, unsigned Size) {
1335 // PTX ABI requires integral types to be at least 32 bits in size. FP16 is
1336 // loaded/stored using i16, so it's handled here as well.
1337 const unsigned SizeBits = promoteScalarArgumentSize(Size * 8);
1338 SDValue Declare =
1339 DAG.getNode(NVPTXISD::DeclareScalarParam, dl, {MVT::Other, MVT::Glue},
1340 {StartChain, Symbol, GetI32(SizeBits), DeclareGlue});
1341 CallPrereqs.push_back(Declare);
1342 DeclareGlue = Declare.getValue(1);
1343 return Declare;
1344 };
1345
1346 const auto MakeDeclareArrayParam = [&](SDValue Symbol, Align Align,
1347 unsigned Size) {
1348 SDValue Declare = DAG.getNode(
1349 NVPTXISD::DeclareArrayParam, dl, {MVT::Other, MVT::Glue},
1350 {StartChain, Symbol, GetI32(Align.value()), GetI32(Size), DeclareGlue});
1351 CallPrereqs.push_back(Declare);
1352 DeclareGlue = Declare.getValue(1);
1353 return Declare;
1354 };
1355
1356 // Variadic arguments.
1357 //
1358 // Normally, for each argument, we declare a param scalar or a param
1359 // byte array in the .param space, and store the argument value to that
1360 // param scalar or array starting at offset 0.
1361 //
1362 // In the case of the first variadic argument, we declare a vararg byte array
1363 // with size 0. The exact size of this array isn't known at this point, so
1364 // it'll be patched later. All the variadic arguments will be stored to this
1365 // array at a certain offset (which gets tracked by 'VAOffset'). The offset is
1366 // initially set to 0, so it can be used for non-variadic arguments (which use
1367 // 0 offset) to simplify the code.
1368 //
1369 // After all vararg is processed, 'VAOffset' holds the size of the
1370 // vararg byte array.
1371 assert((CLI.IsVarArg || CLI.Args.size() <= CLI.NumFixedArgs) &&
1372 "Non-VarArg function with extra arguments");
1373
1374 const unsigned FirstVAArg = CLI.NumFixedArgs; // position of first variadic
1375 unsigned VAOffset = 0; // current offset in the param array
1376
1377 const SDValue VADeclareParam =
1378 CLI.Args.size() > FirstVAArg
1379 ? MakeDeclareArrayParam(
1380 getCallParamSymbolNode(DAG, FirstVAArg, MVT::i32),
1381 Align(STI.getMaxRequiredAlignment()), 0)
1382 : SDValue();
1383
1384 // Args.size() and Outs.size() need not match.
1385 // Outs.size() will be larger
1386 // * if there is an aggregate argument with multiple fields (each field
1387 // showing up separately in Outs)
1388 // * if there is a vector argument with more than typical vector-length
1389 // elements (generally if more than 4) where each vector element is
1390 // individually present in Outs.
1391 // So a different index should be used for indexing into Outs/OutVals.
1392 // See similar issue in LowerFormalArguments.
1393 auto AllOuts = ArrayRef(CLI.Outs);
1394 auto AllOutVals = ArrayRef(CLI.OutVals);
1395 assert(AllOuts.size() == AllOutVals.size() &&
1396 "Outs and OutVals must be the same size");
1397 // Declare the .params or .reg need to pass values
1398 // to the function
1399 for (const auto E : llvm::enumerate(Args)) {
1400 const auto ArgI = E.index();
1401 const auto Arg = E.value();
1402 const auto ArgOuts =
1403 AllOuts.take_while([&](auto O) { return O.OrigArgIndex == ArgI; });
1404 const auto ArgOutVals = AllOutVals.take_front(ArgOuts.size());
1405 AllOuts = AllOuts.drop_front(ArgOuts.size());
1406 AllOutVals = AllOutVals.drop_front(ArgOuts.size());
1407
1408 const bool IsVAArg = (ArgI >= FirstVAArg);
1409 const bool IsByVal = Arg.IsByVal;
1410
1411 const SDValue ParamSymbol =
1412 getCallParamSymbolNode(DAG, IsVAArg ? FirstVAArg : ArgI, MVT::i32);
1413
1414 assert((!IsByVal || Arg.IndirectType) &&
1415 "byval arg must have indirect type");
1416 Type *ETy = (IsByVal ? Arg.IndirectType : Arg.Ty);
1417
1418 const Align ArgAlign = [&]() {
1419 const unsigned ParamIdx = ArgI + AttributeList::FirstArgIndex;
1420 if (IsByVal)
1421 return getDeviceByValParamAlign(CB, ETy, ParamIdx, DL);
1422 return getPTXParamAlign(CB, Arg.Ty, ParamIdx, DL);
1423 }();
1424
1425 const unsigned TySize = DL.getTypeAllocSize(ETy);
1426 assert((!IsByVal || TySize == ArgOuts[0].Flags.getByValSize()) &&
1427 "type size mismatch");
1428
1429 const SDValue ArgDeclare = [&]() {
1430 if (IsVAArg)
1431 return VADeclareParam;
1432
1433 if (IsByVal || shouldPassAsArray(Arg.Ty))
1434 return MakeDeclareArrayParam(ParamSymbol, ArgAlign, TySize);
1435
1436 assert(ArgOuts.size() == 1 && "We must pass only one value as non-array");
1437 assert((ArgOuts[0].VT.isInteger() || ArgOuts[0].VT.isFloatingPoint()) &&
1438 "Only int and float types are supported as non-array arguments");
1439
1440 return MakeDeclareScalarParam(ParamSymbol, TySize);
1441 }();
1442
1443 if (IsByVal) {
1444 assert(ArgOutVals.size() == 1 && "We must pass only one value as byval");
1445 SDValue SrcPtr = ArgOutVals[0];
1446 const MachinePointerInfo SrcPtrInfo = refinePtrAS(SrcPtr, DAG);
1447 // Don't use Flags.getNonZeroByValAlign as this includes the stackalign,
1448 // which does not apply to the source pointer.
1449 const Align BaseSrcAlign = [&]() {
1450 // The align attribute on a byval argument indicates the known alignment
1451 // of the pointer passed to the function.
1452 if (CB)
1453 if (const MaybeAlign A = CB->getParamAlign(ArgI))
1454 return *A;
1455 // Fall back to the default alignment for the type.
1456 // TODO: This might be too aggressive but we haven't had a problem with
1457 // it yet.
1458 return getPTXParamTypeAlign(ETy, DL);
1459 }();
1460
1461 if (IsVAArg)
1462 VAOffset = alignTo(VAOffset, ArgAlign);
1463
1464 SmallVector<EVT, 4> ValueVTs, MemVTs;
1466 ComputeValueVTs(*this, DL, ETy, ValueVTs, &MemVTs, &Offsets);
1467
1468 unsigned J = 0;
1469 const auto VI = VectorizePTXValueVTs(MemVTs, Offsets, ArgAlign, IsVAArg);
1470 for (const unsigned NumElts : VI) {
1471 EVT LoadVT = getVectorizedVT(MemVTs[J], NumElts, Ctx);
1472 Align SrcAlign = commonAlignment(BaseSrcAlign, Offsets[J]);
1473 SDValue SrcAddr = DAG.getObjectPtrOffset(dl, SrcPtr, Offsets[J]);
1474 SDValue SrcLoad =
1475 DAG.getLoad(LoadVT, dl, CallChain, SrcAddr,
1476 SrcPtrInfo.getWithOffset(Offsets[J]), SrcAlign);
1477
1478 TypeSize ParamOffset = Offsets[J].getWithIncrement(VAOffset);
1479 Align ParamAlign = commonAlignment(ArgAlign, ParamOffset);
1480 SDValue ParamAddr =
1481 DAG.getObjectPtrOffset(dl, ParamSymbol, ParamOffset);
1482 SDValue StoreParam = DAG.getStore(
1483 ArgDeclare, dl, SrcLoad, ParamAddr,
1485 CallPrereqs.push_back(StoreParam);
1486
1487 J += NumElts;
1488 }
1489 if (IsVAArg)
1490 VAOffset += TySize;
1491 } else {
1494 ComputePTXValueVTs(*this, DL, Ctx, CLI.CallConv, Arg.Ty, VTs, Offsets,
1495 VAOffset);
1496 assert(VTs.size() == Offsets.size() && "Size mismatch");
1497 assert(VTs.size() == ArgOuts.size() && "Size mismatch");
1498
1499 // PTX Interoperability Guide 3.3(A): [Integer] Values shorter
1500 // than 32-bits are sign extended or zero extended, depending on
1501 // whether they are signed or unsigned types. This case applies
1502 // only to scalar parameters and not to aggregate values.
1503 const bool ExtendIntegerParam =
1504 Arg.Ty->isIntegerTy() && DL.getTypeAllocSizeInBits(Arg.Ty) < 32;
1505
1506 const auto GetStoredValue = [&](const unsigned I) {
1507 SDValue StVal = ArgOutVals[I];
1509 StVal.getValueType() &&
1510 "OutVal type should always be legal");
1511
1512 const EVT VTI = promoteScalarIntegerPTX(VTs[I]);
1513 const EVT StoreVT =
1514 ExtendIntegerParam ? MVT::i32 : (VTI == MVT::i1 ? MVT::i8 : VTI);
1515
1516 return correctParamType(StVal, StoreVT, ArgOuts[I].Flags, DAG, dl);
1517 };
1518
1519 unsigned J = 0;
1520 const auto VI = VectorizePTXValueVTs(VTs, Offsets, ArgAlign, IsVAArg);
1521 for (const unsigned NumElts : VI) {
1522 const EVT EltVT = promoteScalarIntegerPTX(VTs[J]);
1523
1524 unsigned Offset;
1525 if (IsVAArg) {
1526 // TODO: We may need to support vector types that can be passed
1527 // as scalars in variadic arguments.
1528 assert(NumElts == 1 &&
1529 "Vectorization should be disabled for vaargs.");
1530
1531 // Align each part of the variadic argument to their type.
1532 VAOffset = alignTo(VAOffset, DAG.getEVTAlign(EltVT));
1533 Offset = VAOffset;
1534
1535 const EVT TheStoreType = ExtendIntegerParam ? MVT::i32 : EltVT;
1536 VAOffset += DL.getTypeAllocSize(TheStoreType.getTypeForEVT(Ctx));
1537 } else {
1538 assert(VAOffset == 0 && "VAOffset must be 0 for non-VA args");
1539 Offset = Offsets[J];
1540 }
1541
1542 SDValue Ptr =
1543 DAG.getObjectPtrOffset(dl, ParamSymbol, TypeSize::getFixed(Offset));
1544
1545 const MaybeAlign CurrentAlign = ExtendIntegerParam
1546 ? MaybeAlign(std::nullopt)
1547 : commonAlignment(ArgAlign, Offset);
1548
1549 SDValue Val =
1550 getBuildVectorizedValue(NumElts, dl, DAG, [&](unsigned K) {
1551 return GetStoredValue(J + K);
1552 });
1553
1554 SDValue StoreParam = DAG.getStore(
1555 ArgDeclare, dl, Val, Ptr,
1557 CallPrereqs.push_back(StoreParam);
1558
1559 J += NumElts;
1560 }
1561 }
1562 }
1563
1564 // Handle Result
1565 if (!Ins.empty()) {
1566 const SDValue RetSymbol = getSymbolNode(DAG, "retval0", MVT::i32);
1567 const unsigned ResultSize = DL.getTypeAllocSize(RetTy);
1568 if (shouldPassAsArray(RetTy)) {
1569 const Align RetAlign =
1570 getPTXParamAlign(CB, RetTy, AttributeList::ReturnIndex, DL);
1571 MakeDeclareArrayParam(RetSymbol, RetAlign, ResultSize);
1572 } else {
1573 MakeDeclareScalarParam(RetSymbol, ResultSize);
1574 }
1575 }
1576
1577 // Set the size of the vararg param byte array if the callee is a variadic
1578 // function and the variadic part is not empty.
1579 if (VADeclareParam) {
1580 SDValue DeclareParamOps[] = {VADeclareParam.getOperand(0),
1581 VADeclareParam.getOperand(1),
1582 VADeclareParam.getOperand(2), GetI32(VAOffset),
1583 VADeclareParam.getOperand(4)};
1584 DAG.MorphNodeTo(VADeclareParam.getNode(), VADeclareParam.getOpcode(),
1585 VADeclareParam->getVTList(), DeclareParamOps);
1586 }
1587
1588 const auto *Func = dyn_cast<GlobalAddressSDNode>(Callee.getNode());
1589 const auto *CalleeF = Func ? dyn_cast<Function>(Func->getGlobal()) : nullptr;
1590
1591 // If the type of the callsite does not match that of the function, convert
1592 // the callsite to an indirect call.
1593 const bool ConvertToIndirectCall =
1594 CalleeF && CB->getFunctionType() != CalleeF->getFunctionType();
1595
1596 // Both indirect calls and libcalls have nullptr Func. In order to distinguish
1597 // between them we must rely on the call site value which is valid for
1598 // indirect calls but is always null for libcalls.
1599 const bool IsIndirectCall = (!Func && CB) || ConvertToIndirectCall;
1600
1601 if (isa<ExternalSymbolSDNode>(Callee)) {
1602 Function* CalleeFunc = nullptr;
1603
1604 // Try to find the callee in the current module.
1605 Callee = DAG.getSymbolFunctionGlobalAddress(Callee, &CalleeFunc);
1606 assert(CalleeFunc != nullptr && "Libcall callee must be set.");
1607
1608 // Set the "libcall callee" attribute to indicate that the function
1609 // must always have a declaration.
1610 CalleeFunc->addFnAttr("nvptx-libcall-callee", "true");
1611 }
1612
1613 // In the indirect function call case, PTX requires a prototype of the form:
1614 // proto_0 : .callprototype(.param .b32 _) _ (.param .b32 _);
1615 // Where the label is to be used as the last arg of the call instruction.
1616 // We record the call site here and emit all prototypes at the
1617 // start of the function in the AsmPrinter.
1618 SDValue Proto = GetI32(0);
1619 if (IsIndirectCall) {
1620 auto *ProtoSymbol = DAG.getMachineFunction()
1622 ->addCallPrototype(CB, DAG.getMachineFunction());
1623 Proto = DAG.getMCSymbol(ProtoSymbol, MVT::i32);
1624 }
1625
1626 const bool IsUnknownIntrinsic =
1627 CalleeF && CalleeF->isIntrinsic() &&
1628 CalleeF->getIntrinsicID() == Intrinsic::not_intrinsic;
1629 if (IsUnknownIntrinsic) {
1632 "call to unknown intrinsic '" + CalleeF->getName() +
1633 "' cannot be lowered by the NVPTX backend",
1634 dl.getDebugLoc()));
1635 }
1636
1637 const unsigned NumArgs =
1638 std::min<unsigned>(CLI.NumFixedArgs + 1, Args.size());
1639 /// CALL(Chain, IsConvergent, IsIndirectCall/IsUniform, NumReturns,
1640 /// NumParams, Callee, Proto)
1641 const SDValue CallToken = DAG.getTokenFactor(dl, CallPrereqs);
1642 const SDValue Call = DAG.getNode(
1643 NVPTXISD::CALL, dl, MVT::Other,
1644 {CallToken, GetI32(CLI.IsConvergent), GetI32(IsIndirectCall),
1645 GetI32(Ins.empty() ? 0 : 1), GetI32(NumArgs), Callee, Proto});
1646
1647 SmallVector<SDValue, 16> LoadChains{Call};
1648 SmallVector<SDValue, 16> ProxyRegOps;
1649 if (!Ins.empty()) {
1652 ComputePTXValueVTs(*this, DL, Ctx, CLI.CallConv, RetTy, VTs, Offsets);
1653 assert(VTs.size() == Ins.size() && "Bad value decomposition");
1654
1655 const Align RetAlign =
1656 getPTXParamAlign(CB, RetTy, AttributeList::ReturnIndex, DL);
1657 const SDValue RetSymbol = getSymbolNode(DAG, "retval0", MVT::i32);
1658
1659 // PTX Interoperability Guide 3.3(A): [Integer] Values shorter than
1660 // 32-bits are sign extended or zero extended, depending on whether
1661 // they are signed or unsigned types.
1662 const bool ExtendIntegerRetVal =
1663 RetTy->isIntegerTy() && DL.getTypeAllocSizeInBits(RetTy) < 32;
1664
1665 unsigned I = 0;
1666 const auto VI = VectorizePTXValueVTs(VTs, Offsets, RetAlign);
1667 for (const unsigned NumElts : VI) {
1668 const MaybeAlign CurrentAlign =
1669 ExtendIntegerRetVal ? MaybeAlign(std::nullopt)
1670 : commonAlignment(RetAlign, Offsets[I]);
1671
1672 const EVT VTI = promoteScalarIntegerPTX(VTs[I]);
1673 const EVT LoadVT =
1674 ExtendIntegerRetVal ? MVT::i32 : (VTI == MVT::i1 ? MVT::i8 : VTI);
1675 const EVT VecVT = getVectorizedVT(LoadVT, NumElts, Ctx);
1676 SDValue Ptr =
1677 DAG.getObjectPtrOffset(dl, RetSymbol, TypeSize::getFixed(Offsets[I]));
1678
1679 SDValue R = DAG.getLoad(
1680 VecVT, dl, Call, Ptr,
1682
1683 LoadChains.push_back(R.getValue(1));
1684 for (const unsigned J : llvm::seq(NumElts))
1685 ProxyRegOps.push_back(getExtractVectorizedValue(R, J, LoadVT, dl, DAG));
1686 I += NumElts;
1687 }
1688 }
1689
1690 const SDValue EndToken = DAG.getTokenFactor(dl, LoadChains);
1691 const SDValue CallEnd = DAG.getCALLSEQ_END(EndToken, UniqueCallSite,
1692 UniqueCallSite + 1, SDValue(), dl);
1693
1694 // Append ProxyReg instructions to the chain to make sure that `callseq_end`
1695 // will not get lost. Otherwise, during libcalls expansion, the nodes can become
1696 // dangling.
1697 for (const auto [I, Reg] : llvm::enumerate(ProxyRegOps)) {
1698 SDValue Proxy =
1699 DAG.getNode(NVPTXISD::ProxyReg, dl, Reg.getValueType(), {CallEnd, Reg});
1700 SDValue Ret = correctParamType(Proxy, Ins[I].VT, Ins[I].Flags, DAG, dl);
1701 InVals.push_back(Ret);
1702 }
1703
1704 // set IsTailCall to false for now, until we figure out how to express
1705 // tail call optimization in PTX
1706 CLI.IsTailCall = false;
1707 return CallEnd;
1708}
1709
1711 SelectionDAG &DAG) const {
1712
1713 if (!STI.hasFeature(NVPTX::PTX73) || !STI.hasFeature(NVPTX::SM52)) {
1714 const Function &Fn = DAG.getMachineFunction().getFunction();
1715
1717 Fn,
1718 "Support for dynamic alloca introduced in PTX ISA version 7.3 and "
1719 "requires target sm_52.",
1720 SDLoc(Op).getDebugLoc()));
1721 auto Ops = {DAG.getConstant(0, SDLoc(), Op.getValueType()),
1722 Op.getOperand(0)};
1723 return DAG.getMergeValues(Ops, SDLoc());
1724 }
1725
1726 SDLoc DL(Op.getNode());
1727 SDValue Chain = Op.getOperand(0);
1728 SDValue Size = Op.getOperand(1);
1729 uint64_t Align = Op.getConstantOperandVal(2);
1730
1731 // The alignment on a ISD::DYNAMIC_STACKALLOC node may be 0 to indicate that
1732 // the default stack alignment should be used.
1733 if (Align == 0)
1735
1736 // The size for ptx alloca instruction is 64-bit for m64 and 32-bit for m32.
1737 const MVT LocalVT = getPointerTy(DAG.getDataLayout(), ADDRESS_SPACE_LOCAL);
1738
1739 SDValue Alloc =
1740 DAG.getNode(NVPTXISD::DYNAMIC_STACKALLOC, DL, {LocalVT, MVT::Other},
1741 {Chain, DAG.getZExtOrTrunc(Size, DL, LocalVT),
1742 DAG.getTargetConstant(Align, DL, MVT::i32)});
1743
1744 // NVPTXLowerAlloca puts allocas in the local address space, so a local
1745 // pointer is requested here; escapes are explicit addrspacecasts in the IR.
1746 assert(Op.getValueType() == LocalVT && "Unexpected alloca pointer size");
1747
1748 return DAG.getMergeValues({Alloc, SDValue(Alloc.getNode(), 1)}, DL);
1749}
1750
1752 SelectionDAG &DAG) const {
1753 SDLoc DL(Op.getNode());
1754 if (!STI.hasFeature(NVPTX::PTX73) || !STI.hasFeature(NVPTX::SM52)) {
1755 const Function &Fn = DAG.getMachineFunction().getFunction();
1756
1758 Fn,
1759 "Support for stackrestore requires PTX ISA version >= 7.3 and target "
1760 ">= sm_52.",
1761 DL.getDebugLoc()));
1762 return Op.getOperand(0);
1763 }
1764
1765 const MVT LocalVT = getPointerTy(DAG.getDataLayout(), ADDRESS_SPACE_LOCAL);
1766 SDValue Chain = Op.getOperand(0);
1767 SDValue Ptr = Op.getOperand(1);
1768 SDValue ASC = DAG.getAddrSpaceCast(DL, LocalVT, Ptr, ADDRESS_SPACE_GENERIC,
1770 return DAG.getNode(NVPTXISD::STACKRESTORE, DL, MVT::Other, {Chain, ASC});
1771}
1772
1774 SelectionDAG &DAG) const {
1775 SDLoc DL(Op.getNode());
1776 if (!STI.hasFeature(NVPTX::PTX73) || !STI.hasFeature(NVPTX::SM52)) {
1777 const Function &Fn = DAG.getMachineFunction().getFunction();
1778
1780 Fn,
1781 "Support for stacksave requires PTX ISA version >= 7.3 and target >= "
1782 "sm_52.",
1783 DL.getDebugLoc()));
1784 auto Ops = {DAG.getConstant(0, DL, Op.getValueType()), Op.getOperand(0)};
1785 return DAG.getMergeValues(Ops, DL);
1786 }
1787
1788 const MVT LocalVT = getPointerTy(DAG.getDataLayout(), ADDRESS_SPACE_LOCAL);
1789 SDValue Chain = Op.getOperand(0);
1790 SDValue SS =
1791 DAG.getNode(NVPTXISD::STACKSAVE, DL, {LocalVT, MVT::Other}, Chain);
1792 SDValue ASC = DAG.getAddrSpaceCast(
1793 DL, Op.getValueType(), SS, ADDRESS_SPACE_LOCAL, ADDRESS_SPACE_GENERIC);
1794 return DAG.getMergeValues({ASC, SDValue(SS.getNode(), 1)}, DL);
1795}
1796
1797// By default CONCAT_VECTORS is lowered by ExpandVectorBuildThroughStack()
1798// (see LegalizeDAG.cpp). This is slow and uses local memory.
1799// We use extract/insert/build vector just as what LegalizeOp() does in llvm 2.5
1800SDValue
1801NVPTXTargetLowering::LowerCONCAT_VECTORS(SDValue Op, SelectionDAG &DAG) const {
1802 SDNode *Node = Op.getNode();
1803 SDLoc dl(Node);
1805 unsigned NumOperands = Node->getNumOperands();
1806 for (unsigned i = 0; i < NumOperands; ++i) {
1807 SDValue SubOp = Node->getOperand(i);
1808 EVT VVT = SubOp.getNode()->getValueType(0);
1809 EVT EltVT = VVT.getVectorElementType();
1810 unsigned NumSubElem = VVT.getVectorNumElements();
1811 for (unsigned j = 0; j < NumSubElem; ++j) {
1812 Ops.push_back(DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, EltVT, SubOp,
1813 DAG.getIntPtrConstant(j, dl)));
1814 }
1815 }
1816 return DAG.getBuildVector(Node->getValueType(0), dl, Ops);
1817}
1818
1820 SelectionDAG &DAG,
1821 unsigned Mode = NVPTX::PTXPrmtMode::NONE) {
1822 assert(A.getValueType() == MVT::i32 && B.getValueType() == MVT::i32 &&
1823 Selector.getValueType() == MVT::i32 && "PRMT must have i32 operands");
1824 return DAG.getNode(NVPTXISD::PRMT, DL, MVT::i32,
1825 {A, B, Selector, DAG.getConstant(Mode, DL, MVT::i32)});
1826}
1827
1829 SelectionDAG &DAG,
1830 unsigned Mode = NVPTX::PTXPrmtMode::NONE) {
1831 return getPRMT(A, B, DAG.getConstant(Selector, DL, MVT::i32), DL, DAG, Mode);
1832}
1833
1834/// Reduces the elements using the scalar operations provided. The operations
1835/// are sorted descending in number of inputs they take. The flags on the
1836/// original reduction operation will be propagated to each scalar operation.
1837/// Nearby elements are grouped in tree reduction, unlike the shuffle reduction
1838/// used in ExpandReductions and SelectionDAG.
1840 const SmallVector<SDValue> &Elements, EVT EltTy,
1841 ArrayRef<std::pair<unsigned /*NodeType*/, unsigned /*NumInputs*/>> Ops,
1842 const SDLoc &DL, const SDNodeFlags Flags, SelectionDAG &DAG) {
1843 // Build the reduction tree at each level, starting with all the elements.
1844 SmallVector<SDValue> Level = Elements;
1845
1846 unsigned OpIdx = 0;
1847 while (Level.size() > 1) {
1848 // Try to reduce this level using the current operator.
1849 const auto [Op, NumInputs] = Ops[OpIdx];
1850
1851 // Build the next level by partially reducing all elements.
1852 SmallVector<SDValue> ReducedLevel;
1853 unsigned I = 0, E = Level.size();
1854 for (; I + NumInputs <= E; I += NumInputs) {
1855 // Reduce elements in groups of [NumInputs], as much as possible.
1856 ReducedLevel.push_back(DAG.getNode(
1857 Op, DL, EltTy, ArrayRef<SDValue>(Level).slice(I, NumInputs), Flags));
1858 }
1859
1860 if (I < E) {
1861 // Handle leftover elements.
1862
1863 if (ReducedLevel.empty()) {
1864 // We didn't reduce anything at this level. We need to pick a smaller
1865 // operator.
1866 ++OpIdx;
1867 assert(OpIdx < Ops.size() && "no smaller operators for reduction");
1868 continue;
1869 }
1870
1871 // We reduced some things but there's still more left, meaning the
1872 // operator's number of inputs doesn't evenly divide this level size. Move
1873 // these elements to the next level.
1874 for (; I < E; ++I)
1875 ReducedLevel.push_back(Level[I]);
1876 }
1877
1878 // Process the next level.
1879 Level = ReducedLevel;
1880 }
1881
1882 return *Level.begin();
1883}
1884
1885// Get scalar reduction opcode
1886static ISD::NodeType getScalarOpcodeForReduction(unsigned ReductionOpcode) {
1887 switch (ReductionOpcode) {
1889 return ISD::FMAXNUM;
1891 return ISD::FMINNUM;
1893 return ISD::FMAXIMUM;
1895 return ISD::FMINIMUM;
1897 return ISD::FMAXIMUMNUM;
1899 return ISD::FMINIMUMNUM;
1900 default:
1901 llvm_unreachable("unhandled reduction opcode");
1902 }
1903}
1904
1905/// Get 3-input scalar reduction opcode
1906static std::optional<unsigned>
1907getScalar3OpcodeForReduction(unsigned ReductionOpcode) {
1908 switch (ReductionOpcode) {
1911 return NVPTXISD::FMAXNUM3;
1914 return NVPTXISD::FMINNUM3;
1916 return NVPTXISD::FMAXIMUM3;
1918 return NVPTXISD::FMINIMUM3;
1919 default:
1920 return std::nullopt;
1921 }
1922}
1923
1924/// Lower reductions to either a sequence of operations or a tree if
1925/// reassociations are allowed. This method will use larger operations like
1926/// max3/min3 when the target supports them.
1927SDValue NVPTXTargetLowering::LowerVECREDUCE(SDValue Op,
1928 SelectionDAG &DAG) const {
1929 SDLoc DL(Op);
1930 const SDNodeFlags Flags = Op->getFlags();
1931 SDValue Vector = Op.getOperand(0);
1932
1933 const unsigned Opcode = Op->getOpcode();
1934 const EVT EltTy = Vector.getValueType().getVectorElementType();
1935
1936 // Whether we can use 3-input min/max when expanding the reduction.
1937 const bool CanUseMinMax3 =
1938 EltTy == MVT::f32 && STI.hasFeature(NVPTX::SM100) &&
1939 STI.hasFeature(NVPTX::PTX88) &&
1940 (Opcode == ISD::VECREDUCE_FMAX || Opcode == ISD::VECREDUCE_FMIN ||
1941 Opcode == ISD::VECREDUCE_FMAXIMUM || Opcode == ISD::VECREDUCE_FMINIMUM ||
1942 Opcode == ISD::VECREDUCE_FMAXIMUMNUM ||
1943 Opcode == ISD::VECREDUCE_FMINIMUMNUM);
1944
1945 // A list of SDNode opcodes with equivalent semantics, sorted descending by
1946 // number of inputs they take.
1947 SmallVector<std::pair<unsigned /*Op*/, unsigned /*NumIn*/>, 2> ScalarOps;
1948
1949 if (auto Opcode3Elem = getScalar3OpcodeForReduction(Opcode);
1950 CanUseMinMax3 && Opcode3Elem)
1951 ScalarOps.push_back({*Opcode3Elem, 3});
1952 ScalarOps.push_back({getScalarOpcodeForReduction(Opcode), 2});
1953
1955 DAG.ExtractVectorElements(Vector, Elements);
1956
1957 return buildTreeReduction(Elements, EltTy, ScalarOps, DL, Flags, DAG);
1958}
1959
1960SDValue NVPTXTargetLowering::LowerBITCAST(SDValue Op, SelectionDAG &DAG) const {
1961 // Handle bitcasting from v2i8 without hitting the default promotion
1962 // strategy which goes through stack memory.
1963 EVT FromVT = Op->getOperand(0)->getValueType(0);
1964 if (FromVT != MVT::v2i8) {
1965 return Op;
1966 }
1967
1968 // Pack vector elements into i16 and bitcast to final type
1969 SDLoc DL(Op);
1970 SDValue Vec0 = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::i8,
1971 Op->getOperand(0), DAG.getIntPtrConstant(0, DL));
1972 SDValue Vec1 = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::i8,
1973 Op->getOperand(0), DAG.getIntPtrConstant(1, DL));
1974 SDValue Extend0 = DAG.getNode(ISD::ZERO_EXTEND, DL, MVT::i16, Vec0);
1975 SDValue Extend1 = DAG.getNode(ISD::ZERO_EXTEND, DL, MVT::i16, Vec1);
1976 SDValue Const8 = DAG.getConstant(8, DL, MVT::i16);
1977 SDValue AsInt = DAG.getNode(
1978 ISD::OR, DL, MVT::i16,
1979 {Extend0, DAG.getNode(ISD::SHL, DL, MVT::i16, {Extend1, Const8})});
1980 EVT ToVT = Op->getValueType(0);
1981 return DAG.getBitcast(ToVT, AsInt);
1982}
1983
1984// We can init constant f16x2/v2i16/v4i8 with a single .b32 move. Normally it
1985// would get lowered as two constant loads and vector-packing move.
1986// Instead we want just a constant move:
1987// mov.b32 %r2, 0x40003C00
1988SDValue NVPTXTargetLowering::LowerBUILD_VECTOR(SDValue Op,
1989 SelectionDAG &DAG) const {
1990 EVT VT = Op->getValueType(0);
1991 if (!(NVPTX::isPackedVectorTy(VT) && VT.is32BitVector()))
1992 return Op;
1993 SDLoc DL(Op);
1994
1995 if (!llvm::all_of(Op->ops(), [](SDValue Operand) {
1996 return Operand->isUndef() || isa<ConstantSDNode>(Operand) ||
1997 isa<ConstantFPSDNode>(Operand);
1998 })) {
1999 if (VT != MVT::v4i8)
2000 return Op;
2001 // Lower non-const v4i8 vector as byte-wise constructed i32, which allows us
2002 // to optimize calculation of constant parts.
2003 auto GetPRMT = [&](const SDValue Left, const SDValue Right, bool Cast,
2004 uint64_t SelectionValue) -> SDValue {
2005 SDValue L = Left;
2006 SDValue R = Right;
2007 if (Cast) {
2008 L = DAG.getAnyExtOrTrunc(L, DL, MVT::i32);
2009 R = DAG.getAnyExtOrTrunc(R, DL, MVT::i32);
2010 }
2011 return getPRMT(L, R, SelectionValue, DL, DAG);
2012 };
2013 auto PRMT__10 = GetPRMT(Op->getOperand(0), Op->getOperand(1), true, 0x3340);
2014 auto PRMT__32 = GetPRMT(Op->getOperand(2), Op->getOperand(3), true, 0x3340);
2015 auto PRMT3210 = GetPRMT(PRMT__10, PRMT__32, false, 0x5410);
2016 return DAG.getBitcast(VT, PRMT3210);
2017 }
2018
2019 // Get value or the Nth operand as an APInt(32). Undef values treated as 0.
2020 auto GetOperand = [](SDValue Op, int N) -> APInt {
2021 const SDValue &Operand = Op->getOperand(N);
2022 EVT VT = Op->getValueType(0);
2023 if (Operand->isUndef())
2024 return APInt(32, 0);
2025 APInt Value;
2026 if (VT == MVT::v2f16 || VT == MVT::v2bf16)
2027 Value = cast<ConstantFPSDNode>(Operand)->getValueAPF().bitcastToAPInt();
2028 else if (VT == MVT::v2i16 || VT == MVT::v4i8)
2029 Value = Operand->getAsAPIntVal();
2030 else
2031 llvm_unreachable("Unsupported type");
2032 // i8 values are carried around as i16, so we need to zero out upper bits,
2033 // so they do not get in the way of combining individual byte values
2034 if (VT == MVT::v4i8)
2035 Value = Value.trunc(8);
2036 return Value.zext(32);
2037 };
2038
2039 // Construct a 32-bit constant by shifting into place smaller values
2040 // (elements of the vector type VT).
2041 // For example, if VT has 2 elements, then N == 2:
2042 // ShiftAmount = 32 / N = 16
2043 // Value |= Op0 (b16) << 0
2044 // Value |= Op1 (b16) << 16
2045 // If N == 4:
2046 // ShiftAmount = 32 / N = 8
2047 // Value |= Op0 (b8) << 0
2048 // Value |= Op1 (b8) << 8
2049 // Value |= Op2 (b8) << 16
2050 // Value |= Op3 (b8) << 24
2051 // ...etc
2052 APInt Value(32, 0);
2053 const unsigned NumElements = VT.getVectorNumElements();
2054 assert(32 % NumElements == 0 && "must evenly divide bit length");
2055 const unsigned ShiftAmount = 32 / NumElements;
2056 for (unsigned ElementNo : seq(NumElements))
2057 Value |= GetOperand(Op, ElementNo).shl(ElementNo * ShiftAmount);
2058 SDValue Const = DAG.getConstant(Value, DL, MVT::i32);
2059 return DAG.getNode(ISD::BITCAST, DL, Op->getValueType(0), Const);
2060}
2061
2062SDValue NVPTXTargetLowering::LowerEXTRACT_VECTOR_ELT(SDValue Op,
2063 SelectionDAG &DAG) const {
2064 SDValue Index = Op->getOperand(1);
2065 SDValue Vector = Op->getOperand(0);
2066 SDLoc DL(Op);
2067 EVT VectorVT = Vector.getValueType();
2068
2069 if (VectorVT == MVT::v4i8) {
2070 SDValue Selector = DAG.getNode(ISD::OR, DL, MVT::i32,
2071 DAG.getZExtOrTrunc(Index, DL, MVT::i32),
2072 DAG.getConstant(0x7770, DL, MVT::i32));
2073 SDValue PRMT = getPRMT(DAG.getBitcast(MVT::i32, Vector),
2074 DAG.getConstant(0, DL, MVT::i32), Selector, DL, DAG);
2075 SDValue Ext = DAG.getAnyExtOrTrunc(PRMT, DL, Op->getValueType(0));
2076 SDNodeFlags Flags;
2077 Flags.setNoSignedWrap(Ext.getScalarValueSizeInBits() > 8);
2078 Flags.setNoUnsignedWrap(Ext.getScalarValueSizeInBits() >= 8);
2079 Ext->setFlags(Flags);
2080 return Ext;
2081 }
2082
2083 // Constant index will be matched by tablegen.
2084 if (isa<ConstantSDNode>(Index.getNode()))
2085 return Op;
2086
2087 // Extract individual elements and select one of them.
2088 assert(NVPTX::isPackedVectorTy(VectorVT) &&
2089 VectorVT.getVectorNumElements() == 2 && "Unexpected vector type.");
2090 EVT EltVT = VectorVT.getVectorElementType();
2091
2092 SDLoc dl(Op.getNode());
2093 SDValue E0 = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, EltVT, Vector,
2094 DAG.getIntPtrConstant(0, dl));
2095 SDValue E1 = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, EltVT, Vector,
2096 DAG.getIntPtrConstant(1, dl));
2097 return DAG.getSelectCC(dl, Index, DAG.getIntPtrConstant(0, dl), E0, E1,
2099}
2100
2101SDValue NVPTXTargetLowering::LowerINSERT_VECTOR_ELT(SDValue Op,
2102 SelectionDAG &DAG) const {
2103 SDValue Vector = Op->getOperand(0);
2104 EVT VectorVT = Vector.getValueType();
2105
2106 if (VectorVT != MVT::v4i8)
2107 return Op;
2108 SDLoc DL(Op);
2109 SDValue Value = Op->getOperand(1);
2110 if (Value->isUndef())
2111 return Vector;
2112
2113 SDValue Index = Op->getOperand(2);
2114
2115 SDValue BFI =
2116 DAG.getNode(NVPTXISD::BFI, DL, MVT::i32,
2117 {DAG.getZExtOrTrunc(Value, DL, MVT::i32),
2118 DAG.getBitcast(MVT::i32, Vector),
2119 DAG.getNode(ISD::MUL, DL, MVT::i32,
2120 DAG.getZExtOrTrunc(Index, DL, MVT::i32),
2121 DAG.getConstant(8, DL, MVT::i32)),
2122 DAG.getConstant(8, DL, MVT::i32)});
2123 return DAG.getNode(ISD::BITCAST, DL, Op->getValueType(0), BFI);
2124}
2125
2126SDValue NVPTXTargetLowering::LowerVECTOR_SHUFFLE(SDValue Op,
2127 SelectionDAG &DAG) const {
2128 SDValue V1 = Op.getOperand(0);
2129 EVT VectorVT = V1.getValueType();
2130 if (VectorVT != MVT::v4i8 || Op.getValueType() != MVT::v4i8)
2131 return Op;
2132
2133 // Lower shuffle to PRMT instruction.
2134 const ShuffleVectorSDNode *SVN = cast<ShuffleVectorSDNode>(Op.getNode());
2135 SDValue V2 = Op.getOperand(1);
2136 uint32_t Selector = 0;
2137 for (auto I : llvm::enumerate(SVN->getMask())) {
2138 if (I.value() != -1) // -1 is a placeholder for undef.
2139 Selector |= (I.value() << (I.index() * 4));
2140 }
2141
2142 SDLoc DL(Op);
2143 SDValue PRMT = getPRMT(DAG.getBitcast(MVT::i32, V1),
2144 DAG.getBitcast(MVT::i32, V2), Selector, DL, DAG);
2145 return DAG.getBitcast(Op.getValueType(), PRMT);
2146}
2147/// LowerShiftRightParts - Lower SRL_PARTS, SRA_PARTS, which
2148/// 1) returns two i32 values and take a 2 x i32 value to shift plus a shift
2149/// amount, or
2150/// 2) returns two i64 values and take a 2 x i64 value to shift plus a shift
2151/// amount.
2152SDValue NVPTXTargetLowering::LowerShiftRightParts(SDValue Op,
2153 SelectionDAG &DAG) const {
2154 assert(Op.getNumOperands() == 3 && "Not a double-shift!");
2155 assert(Op.getOpcode() == ISD::SRA_PARTS || Op.getOpcode() == ISD::SRL_PARTS);
2156
2157 EVT VT = Op.getValueType();
2158 unsigned VTBits = VT.getSizeInBits();
2159 SDLoc dl(Op);
2160 SDValue ShOpLo = Op.getOperand(0);
2161 SDValue ShOpHi = Op.getOperand(1);
2162 SDValue ShAmt = Op.getOperand(2);
2163 unsigned Opc = (Op.getOpcode() == ISD::SRA_PARTS) ? ISD::SRA : ISD::SRL;
2164
2165 if (VTBits == 32 && STI.hasFeature(NVPTX::SM35)) {
2166 // For 32bit and sm35, we can use the funnel shift 'shf' instruction.
2167 // {dHi, dLo} = {aHi, aLo} >> Amt
2168 // dHi = aHi >> Amt
2169 // dLo = shf.r.clamp aLo, aHi, Amt
2170
2171 SDValue Hi = DAG.getNode(Opc, dl, VT, ShOpHi, ShAmt);
2172 SDValue Lo =
2173 DAG.getNode(NVPTXISD::FSHR_CLAMP, dl, VT, ShOpHi, ShOpLo, ShAmt);
2174
2175 SDValue Ops[2] = { Lo, Hi };
2176 return DAG.getMergeValues(Ops, dl);
2177 } else {
2178 // {dHi, dLo} = {aHi, aLo} >> Amt
2179 // - if (Amt>=size) then
2180 // dLo = aHi >> (Amt-size)
2181 // dHi = aHi >> Amt (this is either all 0 or all 1)
2182 // else
2183 // dLo = (aLo >>logic Amt) | (aHi << (size-Amt))
2184 // dHi = aHi >> Amt
2185
2186 SDValue RevShAmt = DAG.getNode(ISD::SUB, dl, MVT::i32,
2187 DAG.getConstant(VTBits, dl, MVT::i32),
2188 ShAmt);
2189 SDValue Tmp1 = DAG.getNode(ISD::SRL, dl, VT, ShOpLo, ShAmt);
2190 SDValue ExtraShAmt = DAG.getNode(ISD::SUB, dl, MVT::i32, ShAmt,
2191 DAG.getConstant(VTBits, dl, MVT::i32));
2192 SDValue Tmp2 = DAG.getNode(ISD::SHL, dl, VT, ShOpHi, RevShAmt);
2193 SDValue FalseVal = DAG.getNode(ISD::OR, dl, VT, Tmp1, Tmp2);
2194 SDValue TrueVal = DAG.getNode(Opc, dl, VT, ShOpHi, ExtraShAmt);
2195
2196 SDValue Cmp = DAG.getSetCC(dl, MVT::i1, ShAmt,
2197 DAG.getConstant(VTBits, dl, MVT::i32),
2198 ISD::SETGE);
2199 SDValue Hi = DAG.getNode(Opc, dl, VT, ShOpHi, ShAmt);
2200 SDValue Lo = DAG.getNode(ISD::SELECT, dl, VT, Cmp, TrueVal, FalseVal);
2201
2202 SDValue Ops[2] = { Lo, Hi };
2203 return DAG.getMergeValues(Ops, dl);
2204 }
2205}
2206
2207/// LowerShiftLeftParts - Lower SHL_PARTS, which
2208/// 1) returns two i32 values and take a 2 x i32 value to shift plus a shift
2209/// amount, or
2210/// 2) returns two i64 values and take a 2 x i64 value to shift plus a shift
2211/// amount.
2212SDValue NVPTXTargetLowering::LowerShiftLeftParts(SDValue Op,
2213 SelectionDAG &DAG) const {
2214 assert(Op.getNumOperands() == 3 && "Not a double-shift!");
2215 assert(Op.getOpcode() == ISD::SHL_PARTS);
2216
2217 EVT VT = Op.getValueType();
2218 unsigned VTBits = VT.getSizeInBits();
2219 SDLoc dl(Op);
2220 SDValue ShOpLo = Op.getOperand(0);
2221 SDValue ShOpHi = Op.getOperand(1);
2222 SDValue ShAmt = Op.getOperand(2);
2223
2224 if (VTBits == 32 && STI.hasFeature(NVPTX::SM35)) {
2225 // For 32bit and sm35, we can use the funnel shift 'shf' instruction.
2226 // {dHi, dLo} = {aHi, aLo} << Amt
2227 // dHi = shf.l.clamp aLo, aHi, Amt
2228 // dLo = aLo << Amt
2229
2230 SDValue Hi =
2231 DAG.getNode(NVPTXISD::FSHL_CLAMP, dl, VT, ShOpHi, ShOpLo, ShAmt);
2232 SDValue Lo = DAG.getNode(ISD::SHL, dl, VT, ShOpLo, ShAmt);
2233
2234 SDValue Ops[2] = { Lo, Hi };
2235 return DAG.getMergeValues(Ops, dl);
2236 } else {
2237 // {dHi, dLo} = {aHi, aLo} << Amt
2238 // - if (Amt>=size) then
2239 // dLo = aLo << Amt (all 0)
2240 // dLo = aLo << (Amt-size)
2241 // else
2242 // dLo = aLo << Amt
2243 // dHi = (aHi << Amt) | (aLo >> (size-Amt))
2244
2245 SDValue RevShAmt = DAG.getNode(ISD::SUB, dl, MVT::i32,
2246 DAG.getConstant(VTBits, dl, MVT::i32),
2247 ShAmt);
2248 SDValue Tmp1 = DAG.getNode(ISD::SHL, dl, VT, ShOpHi, ShAmt);
2249 SDValue ExtraShAmt = DAG.getNode(ISD::SUB, dl, MVT::i32, ShAmt,
2250 DAG.getConstant(VTBits, dl, MVT::i32));
2251 SDValue Tmp2 = DAG.getNode(ISD::SRL, dl, VT, ShOpLo, RevShAmt);
2252 SDValue FalseVal = DAG.getNode(ISD::OR, dl, VT, Tmp1, Tmp2);
2253 SDValue TrueVal = DAG.getNode(ISD::SHL, dl, VT, ShOpLo, ExtraShAmt);
2254
2255 SDValue Cmp = DAG.getSetCC(dl, MVT::i1, ShAmt,
2256 DAG.getConstant(VTBits, dl, MVT::i32),
2257 ISD::SETGE);
2258 SDValue Lo = DAG.getNode(ISD::SHL, dl, VT, ShOpLo, ShAmt);
2259 SDValue Hi = DAG.getNode(ISD::SELECT, dl, VT, Cmp, TrueVal, FalseVal);
2260
2261 SDValue Ops[2] = { Lo, Hi };
2262 return DAG.getMergeValues(Ops, dl);
2263 }
2264}
2265
2266/// If the types match, convert the generic copysign to the NVPTXISD version,
2267/// otherwise bail ensuring that mismatched cases are properly expaned.
2268SDValue NVPTXTargetLowering::LowerFCOPYSIGN(SDValue Op,
2269 SelectionDAG &DAG) const {
2270 EVT VT = Op.getValueType();
2271 SDLoc DL(Op);
2272
2273 SDValue In1 = Op.getOperand(0);
2274 SDValue In2 = Op.getOperand(1);
2275 EVT SrcVT = In2.getValueType();
2276
2277 if (!SrcVT.bitsEq(VT))
2278 return SDValue();
2279
2280 return DAG.getNode(NVPTXISD::FCOPYSIGN, DL, VT, In1, In2);
2281}
2282
2283SDValue NVPTXTargetLowering::LowerFROUND(SDValue Op, SelectionDAG &DAG) const {
2284 EVT VT = Op.getValueType();
2285
2286 if (VT == MVT::f32)
2287 return LowerFROUND32(Op, DAG);
2288
2289 if (VT == MVT::f64)
2290 return LowerFROUND64(Op, DAG);
2291
2292 llvm_unreachable("unhandled type");
2293}
2294
2295// This is the the rounding method used in CUDA libdevice in C like code:
2296// float roundf(float A)
2297// {
2298// float RoundedA = (float) (int) ( A > 0 ? (A + 0.5f) : (A - 0.5f));
2299// RoundedA = abs(A) > 0x1.0p23 ? A : RoundedA;
2300// return abs(A) < 0.5 ? (float)(int)A : RoundedA;
2301// }
2302SDValue NVPTXTargetLowering::LowerFROUND32(SDValue Op,
2303 SelectionDAG &DAG) const {
2304 SDLoc SL(Op);
2305 SDValue A = Op.getOperand(0);
2306 EVT VT = Op.getValueType();
2307
2308 SDValue AbsA = DAG.getNode(ISD::FABS, SL, VT, A);
2309
2310 // RoundedA = (float) (int) ( A > 0 ? (A + 0.5f) : (A - 0.5f))
2311 SDValue Bitcast = DAG.getNode(ISD::BITCAST, SL, MVT::i32, A);
2312 const unsigned SignBitMask = 0x80000000;
2313 SDValue Sign = DAG.getNode(ISD::AND, SL, MVT::i32, Bitcast,
2314 DAG.getConstant(SignBitMask, SL, MVT::i32));
2315 const unsigned PointFiveInBits = 0x3F000000;
2316 SDValue PointFiveWithSignRaw =
2317 DAG.getNode(ISD::OR, SL, MVT::i32, Sign,
2318 DAG.getConstant(PointFiveInBits, SL, MVT::i32));
2319 SDValue PointFiveWithSign =
2320 DAG.getNode(ISD::BITCAST, SL, VT, PointFiveWithSignRaw);
2321 SDValue AdjustedA = DAG.getNode(ISD::FADD, SL, VT, A, PointFiveWithSign);
2322 SDValue RoundedA = DAG.getNode(ISD::FTRUNC, SL, VT, AdjustedA);
2323
2324 // RoundedA = abs(A) > 0x1.0p23 ? A : RoundedA;
2325 EVT SetCCVT = getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), VT);
2326 SDValue IsLarge =
2327 DAG.getSetCC(SL, SetCCVT, AbsA, DAG.getConstantFP(pow(2.0, 23.0), SL, VT),
2328 ISD::SETOGT);
2329 RoundedA = DAG.getNode(ISD::SELECT, SL, VT, IsLarge, A, RoundedA);
2330
2331 // return abs(A) < 0.5 ? (float)(int)A : RoundedA;
2332 SDValue IsSmall =DAG.getSetCC(SL, SetCCVT, AbsA,
2333 DAG.getConstantFP(0.5, SL, VT), ISD::SETOLT);
2334 SDValue RoundedAForSmallA = DAG.getNode(ISD::FTRUNC, SL, VT, A);
2335 return DAG.getNode(ISD::SELECT, SL, VT, IsSmall, RoundedAForSmallA, RoundedA);
2336}
2337
2338// The implementation of round(double) is similar to that of round(float) in
2339// that they both separate the value range into three regions and use a method
2340// specific to the region to round the values. However, round(double) first
2341// calculates the round of the absolute value and then adds the sign back while
2342// round(float) directly rounds the value with sign.
2343SDValue NVPTXTargetLowering::LowerFROUND64(SDValue Op,
2344 SelectionDAG &DAG) const {
2345 SDLoc SL(Op);
2346 SDValue A = Op.getOperand(0);
2347 EVT VT = Op.getValueType();
2348
2349 SDValue AbsA = DAG.getNode(ISD::FABS, SL, VT, A);
2350
2351 // double RoundedA = (double) (int) (abs(A) + 0.5f);
2352 SDValue AdjustedA = DAG.getNode(ISD::FADD, SL, VT, AbsA,
2353 DAG.getConstantFP(0.5, SL, VT));
2354 SDValue RoundedA = DAG.getNode(ISD::FTRUNC, SL, VT, AdjustedA);
2355
2356 // RoundedA = abs(A) < 0.5 ? (double)0 : RoundedA;
2357 EVT SetCCVT = getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), VT);
2358 SDValue IsSmall =DAG.getSetCC(SL, SetCCVT, AbsA,
2359 DAG.getConstantFP(0.5, SL, VT), ISD::SETOLT);
2360 RoundedA = DAG.getNode(ISD::SELECT, SL, VT, IsSmall,
2361 DAG.getConstantFP(0, SL, VT),
2362 RoundedA);
2363
2364 // Add sign to rounded_A
2365 RoundedA = DAG.getNode(ISD::FCOPYSIGN, SL, VT, RoundedA, A);
2366 DAG.getNode(ISD::FTRUNC, SL, VT, A);
2367
2368 // RoundedA = abs(A) > 0x1.0p52 ? A : RoundedA;
2369 SDValue IsLarge =
2370 DAG.getSetCC(SL, SetCCVT, AbsA, DAG.getConstantFP(pow(2.0, 52.0), SL, VT),
2371 ISD::SETOGT);
2372 return DAG.getNode(ISD::SELECT, SL, VT, IsLarge, A, RoundedA);
2373}
2374
2376 EVT VT = N->getValueType(0);
2377 EVT NVT = MVT::f32;
2378 if (VT.isVector()) {
2379 NVT = EVT::getVectorVT(*DAG.getContext(), NVT, VT.getVectorElementCount());
2380 }
2381 SDLoc DL(N);
2382 SDValue Tmp0 = DAG.getFPExtendOrRound(N->getOperand(0), DL, NVT);
2383 SDValue Tmp1 = DAG.getFPExtendOrRound(N->getOperand(1), DL, NVT);
2384 SDValue Res = DAG.getNode(N->getOpcode(), DL, NVT, Tmp0, Tmp1, N->getFlags());
2385 return DAG.getFPExtendOrRound(Res, DL, VT);
2386}
2387
2388SDValue NVPTXTargetLowering::PromoteBinOpIfF32FTZ(SDValue Op,
2389 SelectionDAG &DAG) const {
2390 if (useF32FTZ(DAG.getMachineFunction())) {
2391 return PromoteBinOpToF32(Op.getNode(), DAG);
2392 }
2393 return Op;
2394}
2395
2396SDValue NVPTXTargetLowering::LowerINT_TO_FP(SDValue Op,
2397 SelectionDAG &DAG) const {
2398 assert(!STI.hasFeature(NVPTX::SM90));
2399
2400 if (Op.getValueType() == MVT::bf16) {
2401 SDLoc Loc(Op);
2402 return DAG.getNode(
2403 ISD::FP_ROUND, Loc, MVT::bf16,
2404 DAG.getNode(Op.getOpcode(), Loc, MVT::f32, Op.getOperand(0)),
2405 DAG.getIntPtrConstant(0, Loc, /*isTarget=*/true));
2406 }
2407
2408 // Everything else is considered legal.
2409 return Op;
2410}
2411
2412SDValue NVPTXTargetLowering::LowerFP_TO_INT(SDValue Op,
2413 SelectionDAG &DAG) const {
2414 assert(!STI.hasFeature(NVPTX::SM90));
2415
2416 if (Op.getOperand(0).getValueType() == MVT::bf16) {
2417 SDLoc Loc(Op);
2418 return DAG.getNode(
2419 Op.getOpcode(), Loc, Op.getValueType(),
2420 DAG.getNode(ISD::FP_EXTEND, Loc, MVT::f32, Op.getOperand(0)));
2421 }
2422
2423 // Everything else is considered legal.
2424 return Op;
2425}
2426
2427SDValue NVPTXTargetLowering::LowerFP_ROUND(SDValue Op,
2428 SelectionDAG &DAG) const {
2429 EVT NarrowVT = Op.getValueType();
2430 SDValue Wide = Op.getOperand(0);
2431 EVT WideVT = Wide.getValueType();
2432 if (NarrowVT.getScalarType() == MVT::bf16) {
2433 const TargetLowering *TLI = STI.getTargetLowering();
2434 if (!STI.hasFeature(NVPTX::SM80)) {
2435 return TLI->expandFP_ROUND(Op.getNode(), DAG);
2436 }
2437 if (!STI.hasFeature(NVPTX::SM90)) {
2438 // sm_80 was the first architecture to support f32 -> bf16.
2439 if (WideVT.getScalarType() == MVT::f32) {
2440 return Op;
2441 }
2442 if (WideVT.getScalarType() == MVT::f64) {
2443 SDLoc Loc(Op);
2444 // Round-inexact-to-odd f64 to f32, then do the final rounding using
2445 // the hardware f32 -> bf16 instruction.
2446 SDValue rod = TLI->expandRoundInexactToOdd(
2447 WideVT.changeElementType(*DAG.getContext(), MVT::f32), Wide, Loc,
2448 DAG);
2449 return DAG.getFPExtendOrRound(rod, Loc, NarrowVT);
2450 }
2451 return TLI->expandFP_ROUND(Op.getNode(), DAG);
2452 }
2453 }
2454
2455 // Everything else is considered legal.
2456 return Op;
2457}
2458
2460 const SDLoc DL(Op);
2461 const EVT VT = Op.getValueType();
2462 const unsigned Opc = Op.getOpcode() == ISD::SMUL_LOHI
2463 ? NVPTXISD::MUL_WIDE_SIGNED
2464 : NVPTXISD::MUL_WIDE_UNSIGNED;
2465
2466 SDValue Wide =
2468 Op.getOperand(0), Op.getOperand(1));
2469 auto [Lo, Hi] = DAG.SplitScalar(Wide, DL, VT, VT);
2470 return DAG.getMergeValues({Lo, Hi}, DL);
2471}
2472
2474 const NVPTXSubtarget &STI) {
2475 EVT SrcVT = Op.getOperand(0).getValueType();
2476 EVT DstVT = Op.getValueType();
2477 auto RM = static_cast<RoundingMode>(Op.getConstantOperandVal(1));
2479 // Reuse the native selection and fallback expansion for ordinary fptrunc.
2480 SDLoc DL(Op);
2481 return DAG.getNode(ISD::FP_ROUND, DL, DstVT, Op.getOperand(0),
2482 DAG.getIntPtrConstant(0, DL, /*isTarget=*/true),
2483 Op.getNode()->getFlags());
2484 }
2485
2486 bool RoundToInfinity =
2488
2489 bool Supported = RM == RoundingMode::TowardZero || RoundToInfinity;
2490 if (DstVT == MVT::bf16) {
2491 if (SrcVT == MVT::f64 || RoundToInfinity)
2492 Supported &= STI.hasFeature(NVPTX::SM90);
2493 else
2494 Supported &= STI.hasFeature(NVPTX::SM80);
2495 }
2496
2497 if (Supported)
2498 return Op;
2499
2502 "unsupported conversion or rounding mode for llvm.fptrunc.round",
2503 SDLoc(Op).getDebugLoc()));
2504 return DAG.getPOISON(DstVT);
2505}
2506
2507SDValue NVPTXTargetLowering::LowerFP_EXTEND(SDValue Op,
2508 SelectionDAG &DAG) const {
2509 SDValue Narrow = Op.getOperand(0);
2510 EVT NarrowVT = Narrow.getValueType();
2511 EVT WideVT = Op.getValueType();
2512 if (NarrowVT.getScalarType() == MVT::bf16) {
2513 if (WideVT.getScalarType() == MVT::f32 &&
2514 (!STI.hasFeature(NVPTX::SM80) || !STI.hasFeature(NVPTX::PTX71))) {
2515 SDLoc Loc(Op);
2516 return DAG.getNode(ISD::BF16_TO_FP, Loc, WideVT, Narrow);
2517 }
2518 if (WideVT.getScalarType() == MVT::f64 && !STI.hasFeature(NVPTX::SM90)) {
2519 EVT F32 = NarrowVT.changeElementType(*DAG.getContext(), MVT::f32);
2520 SDLoc Loc(Op);
2521 if (STI.hasFeature(NVPTX::SM80) && STI.hasFeature(NVPTX::PTX71)) {
2522 Op = DAG.getNode(ISD::FP_EXTEND, Loc, F32, Narrow);
2523 } else {
2524 Op = DAG.getNode(ISD::BF16_TO_FP, Loc, F32, Narrow);
2525 }
2526 return DAG.getNode(ISD::FP_EXTEND, Loc, WideVT, Op);
2527 }
2528 }
2529
2530 // Everything else is considered legal.
2531 return Op;
2532}
2533
2535 SDLoc DL(Op);
2536 if (Op.getValueType() != MVT::v2i16)
2537 return Op;
2538 EVT EltVT = Op.getValueType().getVectorElementType();
2539 SmallVector<SDValue> VecElements;
2540 for (int I = 0, E = Op.getValueType().getVectorNumElements(); I < E; I++) {
2541 SmallVector<SDValue> ScalarArgs;
2542 llvm::transform(Op->ops(), std::back_inserter(ScalarArgs),
2543 [&](const SDUse &O) {
2544 return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, EltVT,
2545 O.get(), DAG.getIntPtrConstant(I, DL));
2546 });
2547 VecElements.push_back(DAG.getNode(Op.getOpcode(), DL, EltVT, ScalarArgs));
2548 }
2549 SDValue V =
2550 DAG.getNode(ISD::BUILD_VECTOR, DL, Op.getValueType(), VecElements);
2551 return V;
2552}
2553
2555 bool hasOffset = false) {
2556 // skip lowering if the vector operand is already legalized
2557 if (!Op->getOperand(hasOffset ? 4 : 3).getValueType().isVector())
2558 return Op;
2559
2560 SDNode *N = Op.getNode();
2561 SDLoc DL(N);
2563
2564 // split the vector argument
2565 for (size_t I = 0; I < N->getNumOperands(); I++) {
2566 SDValue Val = N->getOperand(I);
2567 EVT ValVT = Val.getValueType();
2568 if (ValVT.isVector()) {
2569 EVT EltVT = ValVT.getVectorElementType();
2570 for (unsigned J = 0, NElts = ValVT.getVectorNumElements(); J < NElts; J++)
2571 Ops.push_back(DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, EltVT, Val,
2572 DAG.getIntPtrConstant(J, DL)));
2573 } else
2574 Ops.push_back(Val);
2575 }
2576
2578 SDValue Tcgen05StNode =
2579 DAG.getMemIntrinsicNode(ISD::INTRINSIC_VOID, DL, N->getVTList(), Ops,
2580 MemSD->getMemoryVT(), MemSD->getMemOperand());
2581
2582 return Tcgen05StNode;
2583}
2584
2586 SDLoc DL(Op);
2587 SDValue Src = Op.getOperand(0);
2588 EVT VT = Op.getValueType();
2589
2590 switch (VT.getSimpleVT().SimpleTy) {
2591 case MVT::i16: {
2592 SDValue Extended = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i32, Src);
2593 SDValue Swapped =
2594 getPRMT(Extended, DAG.getConstant(0, DL, MVT::i32), 0x7701, DL, DAG);
2595 return DAG.getNode(ISD::TRUNCATE, DL, MVT::i16, Swapped);
2596 }
2597 case MVT::i32: {
2598 return getPRMT(Src, DAG.getConstant(0, DL, MVT::i32), 0x0123, DL, DAG);
2599 }
2600 case MVT::v2i16: {
2601 SDValue Converted = DAG.getBitcast(MVT::i32, Src);
2602 SDValue Swapped =
2603 getPRMT(Converted, DAG.getConstant(0, DL, MVT::i32), 0x2301, DL, DAG);
2604 return DAG.getNode(ISD::BITCAST, DL, MVT::v2i16, Swapped);
2605 }
2606 case MVT::i64: {
2607 SDValue UnpackSrc =
2608 DAG.getNode(NVPTXISD::UNPACK_VECTOR, DL, {MVT::i32, MVT::i32}, Src);
2609 SDValue SwappedLow =
2610 getPRMT(UnpackSrc.getValue(0), DAG.getConstant(0, DL, MVT::i32), 0x0123,
2611 DL, DAG);
2612 SDValue SwappedHigh =
2613 getPRMT(UnpackSrc.getValue(1), DAG.getConstant(0, DL, MVT::i32), 0x0123,
2614 DL, DAG);
2615 return DAG.getNode(NVPTXISD::BUILD_VECTOR, DL, MVT::i64,
2616 {SwappedHigh, SwappedLow});
2617 }
2618 default:
2619 llvm_unreachable("unsupported type for bswap");
2620 }
2621}
2622
2624 const Function &Fn = DAG.getMachineFunction().getFunction();
2625 SDNode *N = Op.getNode();
2626 SDLoc DL(N);
2627 Intrinsic::ID IntrinsicID = N->getConstantOperandVal(1);
2628 SDValue DestAddr = N->getOperand(2);
2629 SDValue Value = N->getOperand(3);
2630 SDValue MbarAddr = N->getOperand(4);
2631
2632 MVT ValueVT = Value.getSimpleValueType();
2633
2634 if (ValueVT == MVT::i32 || ValueVT == MVT::i64)
2635 return Op;
2636
2637 if (ValueVT == MVT::i128) {
2638 SDValue Cast = DAG.getNode(ISD::BITCAST, DL, MVT::v2i64, Value);
2639 SDValue ValueLo = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::i64, Cast,
2640 DAG.getIntPtrConstant(0, DL));
2641 SDValue ValueHi = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::i64, Cast,
2642 DAG.getIntPtrConstant(1, DL));
2643 SDValue Ops[] = {N->getOperand(0), DestAddr, ValueLo, ValueHi, MbarAddr};
2644 return DAG.getNode(NVPTXISD::ST_ASYNC_MBARRIER_B128, DL, MVT::Other, Ops);
2645 }
2646
2648 Fn,
2649 Twine("unsupported argument type ") + llvm::EVT(ValueVT).getEVTString() +
2650 " for " + llvm::Intrinsic::getName(IntrinsicID) + " intrinsic",
2651 DiagnosticLocation(DL.getDebugLoc())));
2652 return Op.getOperand(0); // Return only the chain
2653}
2654
2656 const Function &Fn = DAG.getMachineFunction().getFunction();
2657 SDNode *N = Op.getNode();
2658 SDLoc DL(N);
2659 Intrinsic::ID IntrinsicID = N->getConstantOperandVal(1);
2660 SDValue DestAddr = N->getOperand(2);
2661 SDValue Value = N->getOperand(3);
2662
2663 MVT ValueVT = Value.getSimpleValueType();
2664
2665 if (ValueVT == MVT::i16 || ValueVT == MVT::i32 || ValueVT == MVT::i64)
2666 return Op;
2667
2668 if (ValueVT == MVT::i8) {
2669 unsigned OpCode;
2670 switch (IntrinsicID) {
2671 case Intrinsic::nvvm_st_async_sys:
2672 OpCode = NVPTXISD::ST_ASYNC_SYS_B8;
2673 break;
2674 case Intrinsic::nvvm_st_async_gpu:
2675 OpCode = NVPTXISD::ST_ASYNC_GPU_B8;
2676 break;
2677 case Intrinsic::nvvm_st_async_mmio_sys:
2678 OpCode = NVPTXISD::ST_ASYNC_MMIO_SYS_B8;
2679 break;
2680 default:
2681 llvm_unreachable("unexpected intrinsic ID for st.async.release");
2682 }
2683
2684 Value = DAG.getNode(ISD::ZERO_EXTEND, DL, MVT::i16, Value);
2685
2686 // The `.mmio` variant has no multimem form and therefore no `isMultimem`
2687 // operand.
2688 if (IntrinsicID == Intrinsic::nvvm_st_async_mmio_sys) {
2689 SDValue Ops[] = {N->getOperand(0), DestAddr, Value};
2690 return DAG.getNode(OpCode, DL, MVT::Other, Ops);
2691 }
2692
2693 SDValue IsMultimem =
2694 DAG.getTargetConstant(N->getConstantOperandVal(4), DL, MVT::i1);
2695 SDValue Ops[] = {N->getOperand(0), DestAddr, Value, IsMultimem};
2696 return DAG.getNode(OpCode, DL, MVT::Other, Ops);
2697 }
2698
2700 Fn,
2701 Twine("unsupported argument type ") + llvm::EVT(ValueVT).getEVTString() +
2702 " for " + llvm::Intrinsic::getName(IntrinsicID) + " intrinsic",
2703 DiagnosticLocation(DL.getDebugLoc())));
2704 return Op.getOperand(0); // Return only the chain
2705}
2706
2707static unsigned getTcgen05MMADisableOutputLane(unsigned IID) {
2708 switch (IID) {
2709 case Intrinsic::nvvm_tcgen05_mma_shared_disable_output_lane_cg1:
2710 return NVPTXISD::TCGEN05_MMA_SHARED_DISABLE_OUTPUT_LANE_CG1;
2711 case Intrinsic::nvvm_tcgen05_mma_shared_disable_output_lane_cg2:
2712 return NVPTXISD::TCGEN05_MMA_SHARED_DISABLE_OUTPUT_LANE_CG2;
2713 case Intrinsic::nvvm_tcgen05_mma_shared_scale_d_disable_output_lane_cg1:
2714 return NVPTXISD::TCGEN05_MMA_SHARED_SCALE_D_DISABLE_OUTPUT_LANE_CG1;
2715 case Intrinsic::nvvm_tcgen05_mma_shared_scale_d_disable_output_lane_cg2:
2716 return NVPTXISD::TCGEN05_MMA_SHARED_SCALE_D_DISABLE_OUTPUT_LANE_CG2;
2717 case Intrinsic::nvvm_tcgen05_mma_tensor_disable_output_lane_cg1:
2718 return NVPTXISD::TCGEN05_MMA_TENSOR_DISABLE_OUTPUT_LANE_CG1;
2719 case Intrinsic::nvvm_tcgen05_mma_tensor_disable_output_lane_cg2:
2720 return NVPTXISD::TCGEN05_MMA_TENSOR_DISABLE_OUTPUT_LANE_CG2;
2721 case Intrinsic::nvvm_tcgen05_mma_tensor_scale_d_disable_output_lane_cg1:
2722 return NVPTXISD::TCGEN05_MMA_TENSOR_SCALE_D_DISABLE_OUTPUT_LANE_CG1;
2723 case Intrinsic::nvvm_tcgen05_mma_tensor_scale_d_disable_output_lane_cg2:
2724 return NVPTXISD::TCGEN05_MMA_TENSOR_SCALE_D_DISABLE_OUTPUT_LANE_CG2;
2725 case Intrinsic::nvvm_tcgen05_mma_tensor_disable_output_lane_cg1_ashift:
2726 return NVPTXISD::TCGEN05_MMA_TENSOR_DISABLE_OUTPUT_LANE_CG1_ASHIFT;
2727 case Intrinsic::nvvm_tcgen05_mma_tensor_disable_output_lane_cg2_ashift:
2728 return NVPTXISD::TCGEN05_MMA_TENSOR_DISABLE_OUTPUT_LANE_CG2_ASHIFT;
2729 case Intrinsic::
2730 nvvm_tcgen05_mma_tensor_scale_d_disable_output_lane_cg1_ashift:
2731 return NVPTXISD::TCGEN05_MMA_TENSOR_SCALE_D_DISABLE_OUTPUT_LANE_CG1_ASHIFT;
2732 case Intrinsic::
2733 nvvm_tcgen05_mma_tensor_scale_d_disable_output_lane_cg2_ashift:
2734 return NVPTXISD::TCGEN05_MMA_TENSOR_SCALE_D_DISABLE_OUTPUT_LANE_CG2_ASHIFT;
2735 case Intrinsic::nvvm_tcgen05_mma_sp_shared_disable_output_lane_cg1:
2736 return NVPTXISD::TCGEN05_MMA_SP_SHARED_DISABLE_OUTPUT_LANE_CG1;
2737 case Intrinsic::nvvm_tcgen05_mma_sp_shared_disable_output_lane_cg2:
2738 return NVPTXISD::TCGEN05_MMA_SP_SHARED_DISABLE_OUTPUT_LANE_CG2;
2739 case Intrinsic::nvvm_tcgen05_mma_sp_shared_scale_d_disable_output_lane_cg1:
2740 return NVPTXISD::TCGEN05_MMA_SP_SHARED_SCALE_D_DISABLE_OUTPUT_LANE_CG1;
2741 case Intrinsic::nvvm_tcgen05_mma_sp_shared_scale_d_disable_output_lane_cg2:
2742 return NVPTXISD::TCGEN05_MMA_SP_SHARED_SCALE_D_DISABLE_OUTPUT_LANE_CG2;
2743 case Intrinsic::nvvm_tcgen05_mma_sp_tensor_disable_output_lane_cg1:
2744 return NVPTXISD::TCGEN05_MMA_SP_TENSOR_DISABLE_OUTPUT_LANE_CG1;
2745 case Intrinsic::nvvm_tcgen05_mma_sp_tensor_disable_output_lane_cg2:
2746 return NVPTXISD::TCGEN05_MMA_SP_TENSOR_DISABLE_OUTPUT_LANE_CG2;
2747 case Intrinsic::nvvm_tcgen05_mma_sp_tensor_disable_output_lane_cg1_ashift:
2748 return NVPTXISD::TCGEN05_MMA_SP_TENSOR_DISABLE_OUTPUT_LANE_CG1_ASHIFT;
2749 case Intrinsic::nvvm_tcgen05_mma_sp_tensor_disable_output_lane_cg2_ashift:
2750 return NVPTXISD::TCGEN05_MMA_SP_TENSOR_DISABLE_OUTPUT_LANE_CG2_ASHIFT;
2751 case Intrinsic::nvvm_tcgen05_mma_sp_tensor_scale_d_disable_output_lane_cg1:
2752 return NVPTXISD::TCGEN05_MMA_SP_TENSOR_SCALE_D_DISABLE_OUTPUT_LANE_CG1;
2753 case Intrinsic::nvvm_tcgen05_mma_sp_tensor_scale_d_disable_output_lane_cg2:
2754 return NVPTXISD::TCGEN05_MMA_SP_TENSOR_SCALE_D_DISABLE_OUTPUT_LANE_CG2;
2755 case Intrinsic::
2756 nvvm_tcgen05_mma_sp_tensor_scale_d_disable_output_lane_cg1_ashift:
2757 return NVPTXISD::
2758 TCGEN05_MMA_SP_TENSOR_SCALE_D_DISABLE_OUTPUT_LANE_CG1_ASHIFT;
2759 case Intrinsic::
2760 nvvm_tcgen05_mma_sp_tensor_scale_d_disable_output_lane_cg2_ashift:
2761 return NVPTXISD::
2762 TCGEN05_MMA_SP_TENSOR_SCALE_D_DISABLE_OUTPUT_LANE_CG2_ASHIFT;
2763 case Intrinsic::
2764 nvvm_tcgen05_mma_shared_f8f6f4_disable_output_lane_cg1_decompress_b:
2765 return NVPTXISD::TCGEN05_MMA_SHARED_DISABLE_OUTPUT_LANE_CG1_DECOMPRESS_B;
2766 case Intrinsic::
2767 nvvm_tcgen05_mma_shared_f8f6f4_disable_output_lane_cg2_decompress_b:
2768 return NVPTXISD::TCGEN05_MMA_SHARED_DISABLE_OUTPUT_LANE_CG2_DECOMPRESS_B;
2769 case Intrinsic::
2770 nvvm_tcgen05_mma_tensor_f8f6f4_disable_output_lane_cg1_decompress_b:
2771 return NVPTXISD::TCGEN05_MMA_TENSOR_DISABLE_OUTPUT_LANE_CG1_DECOMPRESS_B;
2772 case Intrinsic::
2773 nvvm_tcgen05_mma_tensor_f8f6f4_disable_output_lane_cg2_decompress_b:
2774 return NVPTXISD::TCGEN05_MMA_TENSOR_DISABLE_OUTPUT_LANE_CG2_DECOMPRESS_B;
2775 };
2776 llvm_unreachable("unhandled tcgen05.mma.disable_output_lane intrinsic");
2777}
2778
2780 SDNode *N = Op.getNode();
2781 SDLoc DL(N);
2782 unsigned IID = cast<ConstantSDNode>(N->getOperand(1))->getZExtValue();
2783
2785 // split the vector argument
2786 for (size_t I = 0; I < N->getNumOperands(); I++) {
2787 if (I == 1)
2788 continue; // skip IID
2789 SDValue Val = N->getOperand(I);
2790 EVT ValVT = Val.getValueType();
2791 if (ValVT.isVector()) {
2792 EVT EltVT = ValVT.getVectorElementType();
2793 for (unsigned J = 0, NElts = ValVT.getVectorNumElements(); J < NElts; J++)
2794 Ops.push_back(DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, EltVT, Val,
2795 DAG.getIntPtrConstant(J, DL)));
2796 } else
2797 Ops.push_back(Val);
2798 }
2799
2801 SDValue Tcgen05MMANode = DAG.getMemIntrinsicNode(
2802 getTcgen05MMADisableOutputLane(IID), DL, N->getVTList(), Ops,
2803 MemSD->getMemoryVT(), MemSD->getMemOperand());
2804
2805 return Tcgen05MMANode;
2806}
2807
2808// Lower vector return type of tcgen05.ld intrinsics
2809static std::optional<std::pair<SDValue, SDValue>>
2810lowerTcgen05Ld(SDNode *N, SelectionDAG &DAG, bool HasOffset = false) {
2811 SDLoc DL(N);
2812 EVT ResVT = N->getValueType(0);
2813 if (!ResVT.isVector())
2814 return {}; // already legalized.
2815
2816 const unsigned NumElts = ResVT.getVectorNumElements();
2817
2818 // Create the return type of the instructions
2819 SmallVector<EVT, 5> ListVTs;
2820 for (unsigned i = 0; i < NumElts; ++i)
2821 ListVTs.push_back(MVT::i32);
2822
2823 ListVTs.push_back(N->getValueType(1)); // Chain
2824
2825 SDVTList ResVTs = DAG.getVTList(ListVTs);
2826
2827 SmallVector<SDValue, 8> Ops{N->getOperand(0), N->getOperand(1),
2828 N->getOperand(2)};
2829
2830 if (HasOffset) {
2831 Ops.push_back(N->getOperand(3)); // offset
2832 Ops.push_back(N->getOperand(4)); // Pack flag
2833 } else
2834 Ops.push_back(N->getOperand(3)); // Pack flag
2835
2837 SDValue NewNode =
2839 MemSD->getMemoryVT(), MemSD->getMemOperand());
2840
2841 // split the vector result
2842 SmallVector<SDValue, 4> ScalarRes;
2843 for (unsigned i = 0; i < NumElts; ++i) {
2844 SDValue Res = NewNode.getValue(i);
2845 ScalarRes.push_back(Res);
2846 }
2847
2848 SDValue Chain = NewNode.getValue(NumElts);
2849 SDValue BuildVector = DAG.getNode(ISD::BUILD_VECTOR, DL, ResVT, ScalarRes);
2850 return {{BuildVector, Chain}};
2851}
2852
2854 unsigned Val) {
2855 SDNode *N = Op.getNode();
2856 SDLoc DL(N);
2857
2858 const Function &Fn = DAG.getMachineFunction().getFunction();
2859
2860 unsigned AS = 0;
2861 if (auto *MemN = dyn_cast<MemIntrinsicSDNode>(N))
2862 AS = MemN->getAddressSpace();
2863 Type *PtrTy = PointerType::get(*DAG.getContext(), AS);
2865
2867 Fn,
2868 "Intrinsic " +
2869 Intrinsic::getName(N->getConstantOperandVal(1), {PtrTy}, M) +
2870 " with value " + Twine(Val) +
2871 " is not supported on the given target.",
2872 DL.getDebugLoc()));
2873 return Op.getOperand(0);
2874}
2875
2877 SDNode *N = Op.getNode();
2878 SDLoc DL(N);
2879
2880 // immediate argument representing elemtype
2881 unsigned Val = N->getConstantOperandVal(3);
2882
2884 Val))
2885 return reportInvalidTensormapReplaceUsage(Op, DAG, Val);
2886
2887 return Op;
2888}
2889
2891 SDNode *N = Op.getNode();
2892 SDLoc DL(N);
2893
2894 // immediate argument representing swizzle mode
2895 unsigned Val = N->getConstantOperandVal(3);
2896
2898 Val))
2899 return reportInvalidTensormapReplaceUsage(Op, DAG, Val);
2900
2901 return Op;
2902}
2903
2905 SDNode *N = Op.getNode();
2906 SDValue Intrin = N->getOperand(1);
2907
2908 // Get the intrinsic ID
2909 unsigned IntrinNo = cast<ConstantSDNode>(Intrin.getNode())->getZExtValue();
2910 switch (IntrinNo) {
2911 default:
2912 break;
2913 case Intrinsic::nvvm_st_async:
2914 return lowerStAsyncWithMbarrier(Op, DAG);
2915 case Intrinsic::nvvm_st_async_sys:
2916 case Intrinsic::nvvm_st_async_gpu:
2917 case Intrinsic::nvvm_st_async_mmio_sys:
2918 return lowerStAsyncRelease(Op, DAG);
2919
2920 case Intrinsic::nvvm_tcgen05_st_16x64b_x1:
2921 case Intrinsic::nvvm_tcgen05_st_16x64b_x2:
2922 case Intrinsic::nvvm_tcgen05_st_16x64b_x4:
2923 case Intrinsic::nvvm_tcgen05_st_16x64b_x8:
2924 case Intrinsic::nvvm_tcgen05_st_16x64b_x16:
2925 case Intrinsic::nvvm_tcgen05_st_16x64b_x32:
2926 case Intrinsic::nvvm_tcgen05_st_16x64b_x128:
2927 case Intrinsic::nvvm_tcgen05_st_16x128b_x1:
2928 case Intrinsic::nvvm_tcgen05_st_16x128b_x2:
2929 case Intrinsic::nvvm_tcgen05_st_16x128b_x4:
2930 case Intrinsic::nvvm_tcgen05_st_16x128b_x8:
2931 case Intrinsic::nvvm_tcgen05_st_16x128b_x16:
2932 case Intrinsic::nvvm_tcgen05_st_16x128b_x32:
2933 case Intrinsic::nvvm_tcgen05_st_16x128b_x64:
2934 case Intrinsic::nvvm_tcgen05_st_16x256b_x1:
2935 case Intrinsic::nvvm_tcgen05_st_16x256b_x2:
2936 case Intrinsic::nvvm_tcgen05_st_16x256b_x4:
2937 case Intrinsic::nvvm_tcgen05_st_16x256b_x8:
2938 case Intrinsic::nvvm_tcgen05_st_16x256b_x16:
2939 case Intrinsic::nvvm_tcgen05_st_16x256b_x32:
2940 case Intrinsic::nvvm_tcgen05_st_32x32b_x1:
2941 case Intrinsic::nvvm_tcgen05_st_32x32b_x2:
2942 case Intrinsic::nvvm_tcgen05_st_32x32b_x4:
2943 case Intrinsic::nvvm_tcgen05_st_32x32b_x8:
2944 case Intrinsic::nvvm_tcgen05_st_32x32b_x16:
2945 case Intrinsic::nvvm_tcgen05_st_32x32b_x32:
2946 case Intrinsic::nvvm_tcgen05_st_16x64b_x64:
2947 case Intrinsic::nvvm_tcgen05_st_32x32b_x64:
2948 case Intrinsic::nvvm_tcgen05_st_32x32b_x128:
2949 return lowerTcgen05St(Op, DAG);
2950 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x1:
2951 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x2:
2952 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x4:
2953 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x8:
2954 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x16:
2955 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x32:
2956 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x64:
2957 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x128:
2958 return lowerTcgen05St(Op, DAG, /* hasOffset */ true);
2959 case Intrinsic::nvvm_tcgen05_mma_shared_disable_output_lane_cg1:
2960 case Intrinsic::nvvm_tcgen05_mma_shared_disable_output_lane_cg2:
2961 case Intrinsic::nvvm_tcgen05_mma_shared_scale_d_disable_output_lane_cg1:
2962 case Intrinsic::nvvm_tcgen05_mma_shared_scale_d_disable_output_lane_cg2:
2963 case Intrinsic::nvvm_tcgen05_mma_sp_shared_disable_output_lane_cg1:
2964 case Intrinsic::nvvm_tcgen05_mma_sp_shared_disable_output_lane_cg2:
2965 case Intrinsic::nvvm_tcgen05_mma_sp_shared_scale_d_disable_output_lane_cg1:
2966 case Intrinsic::nvvm_tcgen05_mma_sp_shared_scale_d_disable_output_lane_cg2:
2967 case Intrinsic::nvvm_tcgen05_mma_tensor_disable_output_lane_cg1:
2968 case Intrinsic::nvvm_tcgen05_mma_tensor_disable_output_lane_cg2:
2969 case Intrinsic::nvvm_tcgen05_mma_tensor_scale_d_disable_output_lane_cg1:
2970 case Intrinsic::nvvm_tcgen05_mma_tensor_scale_d_disable_output_lane_cg2:
2971 case Intrinsic::nvvm_tcgen05_mma_sp_tensor_disable_output_lane_cg1:
2972 case Intrinsic::nvvm_tcgen05_mma_sp_tensor_disable_output_lane_cg2:
2973 case Intrinsic::nvvm_tcgen05_mma_sp_tensor_scale_d_disable_output_lane_cg1:
2974 case Intrinsic::nvvm_tcgen05_mma_sp_tensor_scale_d_disable_output_lane_cg2:
2975 case Intrinsic::nvvm_tcgen05_mma_tensor_disable_output_lane_cg1_ashift:
2976 case Intrinsic::nvvm_tcgen05_mma_tensor_disable_output_lane_cg2_ashift:
2977 case Intrinsic::
2978 nvvm_tcgen05_mma_tensor_scale_d_disable_output_lane_cg1_ashift:
2979 case Intrinsic::
2980 nvvm_tcgen05_mma_tensor_scale_d_disable_output_lane_cg2_ashift:
2981 case Intrinsic::nvvm_tcgen05_mma_sp_tensor_disable_output_lane_cg1_ashift:
2982 case Intrinsic::nvvm_tcgen05_mma_sp_tensor_disable_output_lane_cg2_ashift:
2983 case Intrinsic::
2984 nvvm_tcgen05_mma_sp_tensor_scale_d_disable_output_lane_cg1_ashift:
2985 case Intrinsic::
2986 nvvm_tcgen05_mma_sp_tensor_scale_d_disable_output_lane_cg2_ashift:
2987 case Intrinsic::
2988 nvvm_tcgen05_mma_shared_f8f6f4_disable_output_lane_cg1_decompress_b:
2989 case Intrinsic::
2990 nvvm_tcgen05_mma_shared_f8f6f4_disable_output_lane_cg2_decompress_b:
2991 case Intrinsic::
2992 nvvm_tcgen05_mma_tensor_f8f6f4_disable_output_lane_cg1_decompress_b:
2993 case Intrinsic::
2994 nvvm_tcgen05_mma_tensor_f8f6f4_disable_output_lane_cg2_decompress_b:
2996 case Intrinsic::nvvm_tensormap_replace_elemtype:
2997 return lowerTensormapReplaceElemtype(Op, DAG);
2998 case Intrinsic::nvvm_tensormap_replace_swizzle_mode:
3000 }
3001 return Op;
3002}
3003
3005 SelectionDAG &DAG) {
3006
3007 SDNode *N = Op.getNode();
3008 if (N->getOperand(1).getValueType() != MVT::i128) {
3009 // return, if the operand is already lowered
3010 return SDValue();
3011 }
3012
3013 unsigned IID =
3014 cast<ConstantSDNode>(N->getOperand(0).getNode())->getZExtValue();
3015 auto Opcode = [&]() {
3016 switch (IID) {
3017 case Intrinsic::nvvm_clusterlaunchcontrol_query_cancel_is_canceled:
3018 return NVPTXISD::CLUSTERLAUNCHCONTROL_QUERY_CANCEL_IS_CANCELED;
3019 case Intrinsic::nvvm_clusterlaunchcontrol_query_cancel_get_first_ctaid_x:
3020 return NVPTXISD::CLUSTERLAUNCHCONTROL_QUERY_CANCEL_GET_FIRST_CTAID_X;
3021 case Intrinsic::nvvm_clusterlaunchcontrol_query_cancel_get_first_ctaid_y:
3022 return NVPTXISD::CLUSTERLAUNCHCONTROL_QUERY_CANCEL_GET_FIRST_CTAID_Y;
3023 case Intrinsic::nvvm_clusterlaunchcontrol_query_cancel_get_first_ctaid_z:
3024 return NVPTXISD::CLUSTERLAUNCHCONTROL_QUERY_CANCEL_GET_FIRST_CTAID_Z;
3025 default:
3026 llvm_unreachable("unsupported/unhandled intrinsic");
3027 }
3028 }();
3029
3030 SDLoc DL(N);
3031 SDValue TryCancelResponse = N->getOperand(1);
3032 SDValue Cast = DAG.getNode(ISD::BITCAST, DL, MVT::v2i64, TryCancelResponse);
3033 SDValue TryCancelResponse0 =
3034 DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::i64, Cast,
3035 DAG.getIntPtrConstant(0, DL));
3036 SDValue TryCancelResponse1 =
3037 DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::i64, Cast,
3038 DAG.getIntPtrConstant(1, DL));
3039
3040 return DAG.getNode(Opcode, DL, N->getVTList(),
3041 {TryCancelResponse0, TryCancelResponse1});
3042}
3043
3045 SDNode *N = Op.getNode();
3046 SDLoc DL(N);
3047 SDValue F32Vec = N->getOperand(1);
3048 SDValue RBits = N->getOperand(2);
3049
3050 unsigned IntrinsicID = N->getConstantOperandVal(0);
3051
3052 // Extract the 4 float elements from the vector
3054 for (unsigned i = 0; i < 4; ++i)
3055 Ops.push_back(DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::f32, F32Vec,
3056 DAG.getIntPtrConstant(i, DL)));
3057
3059
3060 auto [OpCode, RetTy, CvtModeFlag] =
3061 [&]() -> std::tuple<unsigned, MVT::SimpleValueType, uint32_t> {
3062 switch (IntrinsicID) {
3063 case Intrinsic::nvvm_f32x4_to_e4m3x4_rs_relu_satfinite:
3064 return {NVPTXISD::CVT_E4M3X4_F32X4_RS_SF, MVT::v4i8,
3065 CvtMode::RS | CvtMode::RELU_FLAG};
3066 case Intrinsic::nvvm_f32x4_to_e4m3x4_rs_satfinite:
3067 return {NVPTXISD::CVT_E4M3X4_F32X4_RS_SF, MVT::v4i8, CvtMode::RS};
3068 case Intrinsic::nvvm_f32x4_to_e5m2x4_rs_relu_satfinite:
3069 return {NVPTXISD::CVT_E5M2X4_F32X4_RS_SF, MVT::v4i8,
3070 CvtMode::RS | CvtMode::RELU_FLAG};
3071 case Intrinsic::nvvm_f32x4_to_e5m2x4_rs_satfinite:
3072 return {NVPTXISD::CVT_E5M2X4_F32X4_RS_SF, MVT::v4i8, CvtMode::RS};
3073 case Intrinsic::nvvm_f32x4_to_e2m3x4_rs_relu_satfinite:
3074 return {NVPTXISD::CVT_E2M3X4_F32X4_RS_SF, MVT::v4i8,
3075 CvtMode::RS | CvtMode::RELU_FLAG};
3076 case Intrinsic::nvvm_f32x4_to_e2m3x4_rs_satfinite:
3077 return {NVPTXISD::CVT_E2M3X4_F32X4_RS_SF, MVT::v4i8, CvtMode::RS};
3078 case Intrinsic::nvvm_f32x4_to_e3m2x4_rs_relu_satfinite:
3079 return {NVPTXISD::CVT_E3M2X4_F32X4_RS_SF, MVT::v4i8,
3080 CvtMode::RS | CvtMode::RELU_FLAG};
3081 case Intrinsic::nvvm_f32x4_to_e3m2x4_rs_satfinite:
3082 return {NVPTXISD::CVT_E3M2X4_F32X4_RS_SF, MVT::v4i8, CvtMode::RS};
3083 case Intrinsic::nvvm_f32x4_to_e2m1x4_rs_relu_satfinite:
3084 return {NVPTXISD::CVT_E2M1X4_F32X4_RS_SF, MVT::i16,
3085 CvtMode::RS | CvtMode::RELU_FLAG};
3086 case Intrinsic::nvvm_f32x4_to_e2m1x4_rs_satfinite:
3087 return {NVPTXISD::CVT_E2M1X4_F32X4_RS_SF, MVT::i16, CvtMode::RS};
3088 default:
3089 llvm_unreachable("unsupported/unhandled intrinsic");
3090 }
3091 }();
3092
3093 Ops.push_back(RBits);
3094 Ops.push_back(DAG.getConstant(CvtModeFlag, DL, MVT::i32));
3095
3096 return DAG.getNode(OpCode, DL, RetTy, Ops);
3097}
3098
3100 const unsigned Mode = [&]() {
3101 switch (Op->getConstantOperandVal(0)) {
3102 case Intrinsic::nvvm_prmt:
3104 case Intrinsic::nvvm_prmt_b4e:
3106 case Intrinsic::nvvm_prmt_ecl:
3108 case Intrinsic::nvvm_prmt_ecr:
3110 case Intrinsic::nvvm_prmt_f4e:
3112 case Intrinsic::nvvm_prmt_rc16:
3114 case Intrinsic::nvvm_prmt_rc8:
3116 default:
3117 llvm_unreachable("unsupported/unhandled intrinsic");
3118 }
3119 }();
3120 SDLoc DL(Op);
3121 SDValue A = Op->getOperand(1);
3122 SDValue B = Op.getNumOperands() == 4 ? Op.getOperand(2)
3123 : DAG.getConstant(0, DL, MVT::i32);
3124 SDValue Selector = (Op->op_end() - 1)->get();
3125 return getPRMT(A, B, Selector, DL, DAG, Mode);
3126}
3127
3128#define TCGEN05_LD_RED_INTR(SHAPE, NUM, TYPE) \
3129 Intrinsic::nvvm_tcgen05_ld_red_##SHAPE##_x##NUM##_##TYPE
3130
3131#define TCGEN05_LD_RED_INST(SHAPE, NUM, TYPE) \
3132 NVPTXISD::TCGEN05_LD_RED_##SHAPE##_X##NUM##_##TYPE
3133
3134static unsigned getTcgen05LdRedID(Intrinsic::ID IID) {
3135 switch (IID) {
3136 case TCGEN05_LD_RED_INTR(32x32b, 2, f32):
3137 return TCGEN05_LD_RED_INST(32x32b, 2, F32);
3138 case TCGEN05_LD_RED_INTR(32x32b, 4, f32):
3139 return TCGEN05_LD_RED_INST(32x32b, 4, F32);
3140 case TCGEN05_LD_RED_INTR(32x32b, 8, f32):
3141 return TCGEN05_LD_RED_INST(32x32b, 8, F32);
3142 case TCGEN05_LD_RED_INTR(32x32b, 16, f32):
3143 return TCGEN05_LD_RED_INST(32x32b, 16, F32);
3144 case TCGEN05_LD_RED_INTR(32x32b, 32, f32):
3145 return TCGEN05_LD_RED_INST(32x32b, 32, F32);
3146 case TCGEN05_LD_RED_INTR(32x32b, 64, f32):
3147 return TCGEN05_LD_RED_INST(32x32b, 64, F32);
3148 case TCGEN05_LD_RED_INTR(32x32b, 128, f32):
3149 return TCGEN05_LD_RED_INST(32x32b, 128, F32);
3150 case TCGEN05_LD_RED_INTR(16x32bx2, 2, f32):
3151 return TCGEN05_LD_RED_INST(16x32bx2, 2, F32);
3152 case TCGEN05_LD_RED_INTR(16x32bx2, 4, f32):
3153 return TCGEN05_LD_RED_INST(16x32bx2, 4, F32);
3154 case TCGEN05_LD_RED_INTR(16x32bx2, 8, f32):
3155 return TCGEN05_LD_RED_INST(16x32bx2, 8, F32);
3156 case TCGEN05_LD_RED_INTR(16x32bx2, 16, f32):
3157 return TCGEN05_LD_RED_INST(16x32bx2, 16, F32);
3158 case TCGEN05_LD_RED_INTR(16x32bx2, 32, f32):
3159 return TCGEN05_LD_RED_INST(16x32bx2, 32, F32);
3160 case TCGEN05_LD_RED_INTR(16x32bx2, 64, f32):
3161 return TCGEN05_LD_RED_INST(16x32bx2, 64, F32);
3162 case TCGEN05_LD_RED_INTR(16x32bx2, 128, f32):
3163 return TCGEN05_LD_RED_INST(16x32bx2, 128, F32);
3164 case TCGEN05_LD_RED_INTR(32x32b, 2, i32):
3165 return TCGEN05_LD_RED_INST(32x32b, 2, I32);
3166 case TCGEN05_LD_RED_INTR(32x32b, 4, i32):
3167 return TCGEN05_LD_RED_INST(32x32b, 4, I32);
3168 case TCGEN05_LD_RED_INTR(32x32b, 8, i32):
3169 return TCGEN05_LD_RED_INST(32x32b, 8, I32);
3170 case TCGEN05_LD_RED_INTR(32x32b, 16, i32):
3171 return TCGEN05_LD_RED_INST(32x32b, 16, I32);
3172 case TCGEN05_LD_RED_INTR(32x32b, 32, i32):
3173 return TCGEN05_LD_RED_INST(32x32b, 32, I32);
3174 case TCGEN05_LD_RED_INTR(32x32b, 64, i32):
3175 return TCGEN05_LD_RED_INST(32x32b, 64, I32);
3176 case TCGEN05_LD_RED_INTR(32x32b, 128, i32):
3177 return TCGEN05_LD_RED_INST(32x32b, 128, I32);
3178 case TCGEN05_LD_RED_INTR(16x32bx2, 2, i32):
3179 return TCGEN05_LD_RED_INST(16x32bx2, 2, I32);
3180 case TCGEN05_LD_RED_INTR(16x32bx2, 4, i32):
3181 return TCGEN05_LD_RED_INST(16x32bx2, 4, I32);
3182 case TCGEN05_LD_RED_INTR(16x32bx2, 8, i32):
3183 return TCGEN05_LD_RED_INST(16x32bx2, 8, I32);
3184 case TCGEN05_LD_RED_INTR(16x32bx2, 16, i32):
3185 return TCGEN05_LD_RED_INST(16x32bx2, 16, I32);
3186 case TCGEN05_LD_RED_INTR(16x32bx2, 32, i32):
3187 return TCGEN05_LD_RED_INST(16x32bx2, 32, I32);
3188 case TCGEN05_LD_RED_INTR(16x32bx2, 64, i32):
3189 return TCGEN05_LD_RED_INST(16x32bx2, 64, I32);
3190 case TCGEN05_LD_RED_INTR(16x32bx2, 128, i32):
3191 return TCGEN05_LD_RED_INST(16x32bx2, 128, I32);
3192 default:
3193 llvm_unreachable("Invalid tcgen05.ld.red intrinsic ID");
3194 }
3195}
3196
3197// Lower vector return type of tcgen05.ld intrinsics
3198static std::optional<std::tuple<SDValue, SDValue, SDValue>>
3200 SDLoc DL(N);
3201 EVT ResVT = N->getValueType(0);
3202 if (!ResVT.isVector())
3203 return {}; // already legalized.
3204
3205 const unsigned NumElts = ResVT.getVectorNumElements();
3206
3207 // Create the return type of the instructions
3208 // +1 represents the reduction value
3209 SmallVector<EVT, 132> ListVTs{
3210 NumElts + 1,
3211 ResVT.getVectorElementType().isFloatingPoint() ? MVT::f32 : MVT::i32};
3212
3213 ListVTs.push_back(MVT::Other); // Chain
3214
3215 SDVTList ResVTs = DAG.getVTList(ListVTs);
3216
3217 // Prepare the Operands
3218 SmallVector<SDValue, 8> Ops{N->getOperand(0)}; // Chain
3219
3220 // skip IID at index 1
3221 for (unsigned i = 2; i < N->getNumOperands(); i++)
3222 Ops.push_back(N->getOperand(i));
3223
3224 unsigned IID = cast<ConstantSDNode>(N->getOperand(1))->getZExtValue();
3226 SDValue NewNode =
3227 DAG.getMemIntrinsicNode(getTcgen05LdRedID(IID), DL, ResVTs, Ops,
3228 MemSD->getMemoryVT(), MemSD->getMemOperand());
3229
3230 // Split vector result
3231 SmallVector<SDValue, 132> ScalarRes;
3232 for (unsigned i = 0; i < NumElts; ++i) {
3233 SDValue Res = NewNode.getValue(i);
3234 ScalarRes.push_back(Res);
3235 }
3236
3237 SDValue BuildVector = DAG.getNode(ISD::BUILD_VECTOR, DL, ResVT, ScalarRes);
3238 SDValue RedResult = NewNode.getValue(NumElts);
3239 SDValue Chain = NewNode.getValue(NumElts + 1);
3240 return {{BuildVector, RedResult, Chain}};
3241}
3242
3244 switch (Op->getConstantOperandVal(1)) {
3245 default:
3246 return Op;
3247
3248 // These tcgen05 intrinsics return a v2i32, which is legal, so we have to
3249 // lower them through LowerOperation() instead of ReplaceNodeResults().
3250 case Intrinsic::nvvm_tcgen05_ld_16x64b_x2:
3251 case Intrinsic::nvvm_tcgen05_ld_16x128b_x1:
3252 case Intrinsic::nvvm_tcgen05_ld_32x32b_x2:
3253 if (auto Res = lowerTcgen05Ld(Op.getNode(), DAG))
3254 return DAG.getMergeValues({Res->first, Res->second}, SDLoc(Op));
3255 return SDValue();
3256
3257 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x2:
3258 if (auto Res = lowerTcgen05Ld(Op.getNode(), DAG, /*HasOffset=*/true))
3259 return DAG.getMergeValues({Res->first, Res->second}, SDLoc(Op));
3260 return SDValue();
3261
3262 case Intrinsic::nvvm_tcgen05_ld_red_32x32b_x2_f32:
3263 case Intrinsic::nvvm_tcgen05_ld_red_32x32b_x2_i32:
3264 case Intrinsic::nvvm_tcgen05_ld_red_16x32bx2_x2_f32:
3265 case Intrinsic::nvvm_tcgen05_ld_red_16x32bx2_x2_i32:
3266 if (auto Res = lowerTcgen05LdRed(Op.getNode(), DAG))
3267 return DAG.getMergeValues(
3268 {std::get<0>(*Res), std::get<1>(*Res), std::get<2>(*Res)}, SDLoc(Op));
3269 return SDValue();
3270 }
3271}
3272
3273static unsigned getSPNumRegs(EVT VT) {
3274 return divideCeil(VT.getSizeInBits(), 32);
3275}
3276
3278 assert(VT.isVector() && "Expected a vector type");
3279 EVT EltVT = VT.getVectorElementType();
3280 if (EltVT == MVT::i8)
3281 return MVT::v4i8;
3282 if (EltVT == MVT::i16)
3283 return MVT::v2i16;
3284 return EltVT;
3285}
3286
3289 SelectionDAG &DAG) {
3290 for (SDValue Operand : Input) {
3291 EVT VT = Operand.getValueType();
3292 SDLoc DL(Operand);
3293 if (!VT.isVector()) {
3294 Output.push_back(Operand);
3295 continue;
3296 }
3297
3298 // Pack partial .b32 operands at their natural width before extending them
3299 // to avoid redundant cvt/prmt sequences.
3300 if (VT.getSizeInBits() < 32) {
3301 EVT IntVT = EVT::getIntegerVT(*DAG.getContext(), VT.getSizeInBits());
3302 Output.push_back(
3303 DAG.getAnyExtOrTrunc(DAG.getBitcast(IntVT, Operand), DL, MVT::i32));
3304 continue;
3305 }
3306
3307 EVT RegVT = getSPRegType(VT);
3308 if (!RegVT.isVector()) {
3309 DAG.ExtractVectorElements(Operand, Output);
3310 continue;
3311 }
3312
3313 unsigned RegElts = RegVT.getVectorNumElements();
3314 for (unsigned I : llvm::seq(getSPNumRegs(VT)))
3315 Output.push_back(DAG.getBitcast(
3316 MVT::i32, DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, RegVT, Operand,
3317 DAG.getVectorIdxConstant(I * RegElts, DL))));
3318 }
3319}
3320
3322 SelectionDAG &DAG) {
3323 assert(Regs.size() == getSPNumRegs(VT) && VT.getSizeInBits() % 32 == 0 &&
3324 "Incorrect number of SP vector registers");
3325 if (!VT.isVector())
3326 return Regs.front();
3327
3328 EVT RegVT = getSPRegType(VT);
3330 for (SDValue Reg : Regs)
3331 Parts.push_back(DAG.getBitcast(RegVT, Reg));
3332
3333 if (!RegVT.isVector())
3334 return DAG.getBuildVector(VT, DL, Parts);
3335 if (Parts.size() == 1)
3336 return Parts.front();
3337 return DAG.getNode(ISD::CONCAT_VECTORS, DL, VT, Parts);
3338}
3339
3340static unsigned getSPCompressNodeOpcode(unsigned NumResults) {
3341#define SPCOMPRESS_NODE_CASE(NumResults) \
3342 case NumResults: \
3343 return NVPTXISD::SPCOMPRESS_R##NumResults
3344
3345 switch (NumResults) {
3362 default:
3363 llvm_unreachable("Invalid spcompress result count");
3364 }
3365
3366#undef SPCOMPRESS_NODE_CASE
3367}
3368
3369static unsigned getSPDecompressNodeOpcode(unsigned NumResults) {
3370#define SPDECOMPRESS_NODE_CASE(NumResults) \
3371 case NumResults: \
3372 return NVPTXISD::SPDECOMPRESS_R##NumResults
3373
3374 switch (NumResults) {
3383 default:
3384 llvm_unreachable("Invalid spdecompress result count");
3385 }
3386
3387#undef SPDECOMPRESS_NODE_CASE
3388}
3389
3391 SDNode *N = Op.getNode();
3392 SDLoc DL(N);
3393
3394 auto IID = static_cast<Intrinsic::ID>(N->getConstantOperandVal(0));
3395 bool IsCompress = IID == Intrinsic::nvvm_spcompress;
3396 assert((IsCompress || IID == Intrinsic::nvvm_spdecompress) &&
3397 "Unexpected SP intrinsic");
3398
3399 EVT DataVT =
3400 IsCompress ? N->getOperand(1).getValueType() : N->getValueType(0);
3401 EVT CDataVT =
3402 IsCompress ? N->getValueType(1) : N->getOperand(2).getValueType();
3403
3404 unsigned ElemSize = DataVT.getScalarSizeInBits();
3405 unsigned IdxSize = N->getConstantOperandVal(3);
3406 unsigned NumTgt = N->getConstantOperandVal(4);
3407 unsigned NumSrc =
3408 NumTgt * CDataVT.getVectorNumElements() / DataVT.getVectorNumElements();
3409 unsigned RepeatFactor = IsCompress ? getSPNumRegs(DataVT) / 2
3410 : DataVT.getVectorNumElements() / NumTgt;
3411
3413 for (unsigned Qualifier : {ElemSize, IdxSize, RepeatFactor, NumSrc, NumTgt})
3414 Ops.push_back(DAG.getTargetConstant(Qualifier, DL, MVT::i32));
3415 appendSplitSPOperands(N->ops().slice(1, 2), Ops, DAG);
3416
3417 SmallVector<EVT, 16> ResultVTs;
3418 for (const EVT VT : N->values())
3419 ResultVTs.append(getSPNumRegs(VT), MVT::i32);
3420
3421 unsigned Opcode = IsCompress ? getSPCompressNodeOpcode(ResultVTs.size())
3422 : getSPDecompressNodeOpcode(ResultVTs.size());
3423 SDValue Lowered = DAG.getNode(Opcode, DL, ResultVTs, Ops);
3424
3426 unsigned Reg = 0;
3427 for (const EVT VT : N->values()) {
3429 for (unsigned R : llvm::seq(getSPNumRegs(VT)))
3430 Regs.push_back(Lowered.getValue(Reg + R));
3431 Reg += Regs.size();
3432 Retvals.push_back(joinSPRegs(VT, Regs, DL, DAG));
3433 }
3434
3435 return DAG.getMergeValues(Retvals, DL);
3436}
3437
3439 switch (Op->getConstantOperandVal(0)) {
3440 default:
3441 return Op;
3442 case Intrinsic::nvvm_prmt:
3443 case Intrinsic::nvvm_prmt_b4e:
3444 case Intrinsic::nvvm_prmt_ecl:
3445 case Intrinsic::nvvm_prmt_ecr:
3446 case Intrinsic::nvvm_prmt_f4e:
3447 case Intrinsic::nvvm_prmt_rc16:
3448 case Intrinsic::nvvm_prmt_rc8:
3449 return lowerPrmtIntrinsic(Op, DAG);
3450 case Intrinsic::nvvm_clusterlaunchcontrol_query_cancel_is_canceled:
3451 case Intrinsic::nvvm_clusterlaunchcontrol_query_cancel_get_first_ctaid_x:
3452 case Intrinsic::nvvm_clusterlaunchcontrol_query_cancel_get_first_ctaid_y:
3453 case Intrinsic::nvvm_clusterlaunchcontrol_query_cancel_get_first_ctaid_z:
3455 case Intrinsic::nvvm_f32x4_to_e4m3x4_rs_satfinite:
3456 case Intrinsic::nvvm_f32x4_to_e4m3x4_rs_relu_satfinite:
3457 case Intrinsic::nvvm_f32x4_to_e5m2x4_rs_satfinite:
3458 case Intrinsic::nvvm_f32x4_to_e5m2x4_rs_relu_satfinite:
3459 case Intrinsic::nvvm_f32x4_to_e2m3x4_rs_satfinite:
3460 case Intrinsic::nvvm_f32x4_to_e2m3x4_rs_relu_satfinite:
3461 case Intrinsic::nvvm_f32x4_to_e3m2x4_rs_satfinite:
3462 case Intrinsic::nvvm_f32x4_to_e3m2x4_rs_relu_satfinite:
3463 case Intrinsic::nvvm_f32x4_to_e2m1x4_rs_satfinite:
3464 case Intrinsic::nvvm_f32x4_to_e2m1x4_rs_relu_satfinite:
3465 return lowerCvtRSIntrinsics(Op, DAG);
3466
3467 case Intrinsic::nvvm_spcompress:
3468 case Intrinsic::nvvm_spdecompress:
3469 return lowerSPIntrinsic(Op, DAG);
3470 }
3471}
3472
3473// In PTX 64-bit CTLZ and CTPOP are supported, but they return a 32-bit value.
3474// Lower these into a node returning the correct type which is zero-extended
3475// back to the correct size.
3477 SDValue V = Op->getOperand(0);
3478 assert(V.getValueType() == MVT::i64 &&
3479 "Unexpected CTLZ/CTPOP type to legalize");
3480
3481 SDLoc DL(Op);
3482 SDValue CT = DAG.getNode(Op->getOpcode(), DL, MVT::i32, V);
3483 return DAG.getNode(ISD::ZERO_EXTEND, DL, MVT::i64, CT, SDNodeFlags::NonNeg);
3484}
3485
3487 unsigned Opcode, SelectionDAG &DAG) {
3488 assert(A.getValueType() == MVT::i64 && B.getValueType() == MVT::i64);
3489
3490 const auto *AmtConst = dyn_cast<ConstantSDNode>(ShiftAmount);
3491 if (!AmtConst)
3492 return SDValue();
3493 const auto Amt = AmtConst->getZExtValue() & 63;
3494
3495 SDValue UnpackA =
3496 DAG.getNode(NVPTXISD::UNPACK_VECTOR, DL, {MVT::i32, MVT::i32}, A);
3497 SDValue UnpackB =
3498 DAG.getNode(NVPTXISD::UNPACK_VECTOR, DL, {MVT::i32, MVT::i32}, B);
3499
3500 // Arch is Little endiain: 0 = low bits, 1 = high bits
3501 SDValue ALo = UnpackA.getValue(0);
3502 SDValue AHi = UnpackA.getValue(1);
3503 SDValue BLo = UnpackB.getValue(0);
3504 SDValue BHi = UnpackB.getValue(1);
3505
3506 // The bitfeild consists of { AHi : ALo : BHi : BLo }
3507 //
3508 // * FSHL, Amt < 32 - The window will contain { AHi : ALo : BHi }
3509 // * FSHL, Amt >= 32 - The window will contain { ALo : BHi : BLo }
3510 // * FSHR, Amt < 32 - The window will contain { ALo : BHi : BLo }
3511 // * FSHR, Amt >= 32 - The window will contain { AHi : ALo : BHi }
3512 //
3513 // Note that Amt = 0 and Amt = 32 are special cases where 32-bit funnel shifts
3514 // are not needed at all. Amt = 0 is a no-op producing either A or B depending
3515 // on the direction. Amt = 32 can be implemented by a packing and unpacking
3516 // move to select and arrange the 32bit values. For simplicity, these cases
3517 // are not handled here explicitly and instead we rely on DAGCombiner to
3518 // remove the no-op funnel shifts we insert.
3519 auto [High, Mid, Low] = ((Opcode == ISD::FSHL) == (Amt < 32))
3520 ? std::make_tuple(AHi, ALo, BHi)
3521 : std::make_tuple(ALo, BHi, BLo);
3522
3523 SDValue NewAmt = DAG.getConstant(Amt & 31, DL, MVT::i32);
3524 SDValue RHi = DAG.getNode(Opcode, DL, MVT::i32, {High, Mid, NewAmt});
3525 SDValue RLo = DAG.getNode(Opcode, DL, MVT::i32, {Mid, Low, NewAmt});
3526
3527 return DAG.getNode(NVPTXISD::BUILD_VECTOR, DL, MVT::i64, {RLo, RHi});
3528}
3529
3531 return expandFSH64(Op->getOperand(0), Op->getOperand(1), Op->getOperand(2),
3532 SDLoc(Op), Op->getOpcode(), DAG);
3533}
3534
3536 unsigned Opcode = Op->getOpcode() == ISD::ROTL ? ISD::FSHL : ISD::FSHR;
3537 return expandFSH64(Op->getOperand(0), Op->getOperand(0), Op->getOperand(1),
3538 SDLoc(Op), Opcode, DAG);
3539}
3540
3542 assert(Op.getValueType() == MVT::i1 && "Custom lowering enabled only for i1");
3543
3544 SDValue Cond = Op->getOperand(0);
3545 SDValue TrueVal = Op->getOperand(1);
3546 SDValue FalseVal = Op->getOperand(2);
3547 SDLoc DL(Op);
3548
3549 // If both operands are truncated, we push the select through the truncates.
3550 if (TrueVal.getOpcode() == ISD::TRUNCATE &&
3551 FalseVal.getOpcode() == ISD::TRUNCATE) {
3552 TrueVal = TrueVal.getOperand(0);
3553 FalseVal = FalseVal.getOperand(0);
3554
3555 EVT VT = TrueVal.getSimpleValueType().bitsLE(FalseVal.getSimpleValueType())
3556 ? TrueVal.getValueType()
3557 : FalseVal.getValueType();
3558 TrueVal = DAG.getAnyExtOrTrunc(TrueVal, DL, VT);
3559 FalseVal = DAG.getAnyExtOrTrunc(FalseVal, DL, VT);
3560 SDValue Select = DAG.getSelect(DL, VT, Cond, TrueVal, FalseVal);
3561 return DAG.getNode(ISD::TRUNCATE, DL, MVT::i1, Select);
3562 }
3563
3564 // Otherwise, expand the select into a series of logical operations. These
3565 // often can be folded into other operations either by us or ptxas.
3566 TrueVal = DAG.getFreeze(TrueVal);
3567 FalseVal = DAG.getFreeze(FalseVal);
3568 SDValue And1 = DAG.getNode(ISD::AND, DL, MVT::i1, Cond, TrueVal);
3569 SDValue NotCond = DAG.getNOT(DL, Cond, MVT::i1);
3570 SDValue And2 = DAG.getNode(ISD::AND, DL, MVT::i1, NotCond, FalseVal);
3571 SDValue Or = DAG.getNode(ISD::OR, DL, MVT::i1, And1, And2);
3572 return Or;
3573}
3574
3576 SDNode *N = Op.getNode();
3577
3578 SDValue Chain = N->getOperand(0);
3579 SDValue Val = N->getOperand(1);
3580 SDValue BasePtr = N->getOperand(2);
3581 SDValue Offset = N->getOperand(3);
3582 SDValue Mask = N->getOperand(4);
3583
3584 SDLoc DL(N);
3585 EVT ValVT = Val.getValueType();
3586 MemSDNode *MemSD = cast<MemSDNode>(N);
3587 assert(ValVT.isVector() && "Masked vector store must have vector type");
3588 assert(MemSD->getAlign() >= DAG.getEVTAlign(ValVT) &&
3589 "Unexpected alignment for masked store");
3590
3591 unsigned Opcode = 0;
3592 switch (ValVT.getSimpleVT().SimpleTy) {
3593 default:
3594 llvm_unreachable("Unexpected masked vector store type");
3595 case MVT::v4i64:
3596 case MVT::v4f64: {
3597 Opcode = NVPTXISD::StoreV4;
3598 break;
3599 }
3600 case MVT::v8i32:
3601 case MVT::v8f32: {
3602 Opcode = NVPTXISD::StoreV8;
3603 break;
3604 }
3605 }
3606
3608
3609 // Construct the new SDNode. First operand is the chain.
3610 Ops.push_back(Chain);
3611
3612 // The next N operands are the values to store. Encode the mask into the
3613 // values using the sentinel register 0 to represent a masked-off element.
3614 assert(Mask.getValueType().isVector() &&
3615 Mask.getValueType().getVectorElementType() == MVT::i1 &&
3616 "Mask must be a vector of i1");
3617 assert(Mask.getOpcode() == ISD::BUILD_VECTOR &&
3618 "Mask expected to be a BUILD_VECTOR");
3619 assert(Mask.getValueType().getVectorNumElements() ==
3620 ValVT.getVectorNumElements() &&
3621 "Mask size must be the same as the vector size");
3622 for (auto [I, Op] : enumerate(Mask->ops())) {
3623 // Mask elements must be constants.
3624 if (Op.getNode()->getAsZExtVal() == 0) {
3625 // Append a sentinel register 0 to the Ops vector to represent a masked
3626 // off element, this will be handled in tablegen
3628 ValVT.getVectorElementType()));
3629 } else {
3630 // Extract the element from the vector to store
3631 SDValue ExtVal =
3633 Val, DAG.getIntPtrConstant(I, DL));
3634 Ops.push_back(ExtVal);
3635 }
3636 }
3637
3638 // Next, the pointer operand.
3639 Ops.push_back(BasePtr);
3640
3641 // Finally, the offset operand. We expect this to always be undef, and it will
3642 // be ignored in lowering, but to mirror the handling of the other vector
3643 // store instructions we include it in the new SDNode.
3644 assert(Offset.isUndef() && "Offset operand expected to be undef or poison");
3645 Ops.push_back(Offset);
3646
3647 SDValue NewSt =
3648 DAG.getMemIntrinsicNode(Opcode, DL, DAG.getVTList(MVT::Other), Ops,
3649 MemSD->getMemoryVT(), MemSD->getMemOperand());
3650
3651 return NewSt;
3652}
3653
3654SDValue
3656 switch (Op.getOpcode()) {
3657 case ISD::RETURNADDR:
3658 return SDValue();
3659 case ISD::FRAMEADDR:
3660 return SDValue();
3661 case ISD::ADDRSPACECAST:
3662 return LowerADDRSPACECAST(Op, DAG);
3664 return lowerIntrinsicWChain(Op, DAG);
3666 return lowerIntrinsicWOChain(Op, DAG);
3668 return lowerIntrinsicVoid(Op, DAG);
3669 case ISD::BUILD_VECTOR:
3670 return LowerBUILD_VECTOR(Op, DAG);
3671 case ISD::BITCAST:
3672 return LowerBITCAST(Op, DAG);
3674 return Op;
3676 return LowerEXTRACT_VECTOR_ELT(Op, DAG);
3678 return LowerINSERT_VECTOR_ELT(Op, DAG);
3680 return LowerVECTOR_SHUFFLE(Op, DAG);
3682 return LowerCONCAT_VECTORS(Op, DAG);
3689 return LowerVECREDUCE(Op, DAG);
3690 case ISD::STORE:
3691 return LowerSTORE(Op, DAG);
3692 case ISD::MSTORE: {
3693 assert(STI.has256BitVectorLoadStore(
3694 cast<MemSDNode>(Op.getNode())->getAddressSpace()) &&
3695 "Masked store vector not supported on subtarget.");
3696 return lowerMSTORE(Op, DAG);
3697 }
3698 case ISD::LOAD:
3699 return LowerLOAD(Op, DAG);
3700 case ISD::MLOAD:
3701 return LowerMLOAD(Op, DAG);
3702 case ISD::SHL_PARTS:
3703 return LowerShiftLeftParts(Op, DAG);
3704 case ISD::SRA_PARTS:
3705 case ISD::SRL_PARTS:
3706 return LowerShiftRightParts(Op, DAG);
3707 case ISD::SELECT:
3708 return lowerSELECT(Op, DAG);
3709 case ISD::SMUL_LOHI:
3710 case ISD::UMUL_LOHI:
3711 return lowerMUL_LOHI(Op, DAG);
3712 case ISD::FROUND:
3713 return LowerFROUND(Op, DAG);
3714 case ISD::FCOPYSIGN:
3715 return LowerFCOPYSIGN(Op, DAG);
3716 case ISD::SINT_TO_FP:
3717 case ISD::UINT_TO_FP:
3718 return LowerINT_TO_FP(Op, DAG);
3719 case ISD::FP_TO_SINT:
3720 case ISD::FP_TO_UINT:
3721 // fptosi/fptoui to i1 truncate toward zero, so the only defined results
3722 // are {0,-1} (signed) and {0,1} (unsigned); every other input results in
3723 // poison. Thus we can simply lower to `x <= -1.0` or `x >= 1.0`.
3724 if (Op.getValueType() == MVT::i1) {
3725 SDLoc DL(Op);
3726 SDValue X = Op.getOperand(0);
3727 bool IsSigned = Op.getOpcode() == ISD::FP_TO_SINT;
3728 return DAG.getSetCC(
3729 DL, MVT::i1, X,
3730 DAG.getConstantFP(IsSigned ? -1.0 : 1.0, DL, X.getValueType()),
3731 IsSigned ? ISD::SETOLE : ISD::SETOGE);
3732 }
3733 return LowerFP_TO_INT(Op, DAG);
3734 case ISD::FP_ROUND:
3735 return LowerFP_ROUND(Op, DAG);
3736 case ISD::FPTRUNC_ROUND:
3737 return lowerFPTRUNC_ROUND(Op, DAG, STI);
3738 case ISD::FP_EXTEND:
3739 return LowerFP_EXTEND(Op, DAG);
3740 case ISD::VAARG:
3741 return LowerVAARG(Op, DAG);
3742 case ISD::VASTART:
3743 return LowerVASTART(Op, DAG);
3744 case ISD::FSHL:
3745 case ISD::FSHR:
3746 return lowerFSH(Op, DAG);
3747 case ISD::ROTL:
3748 case ISD::ROTR:
3749 return lowerROT(Op, DAG);
3750 case ISD::ABS:
3752 case ISD::SMIN:
3753 case ISD::SMAX:
3754 case ISD::UMIN:
3755 case ISD::UMAX:
3756 case ISD::ADD:
3757 case ISD::SUB:
3758 case ISD::MUL:
3759 case ISD::SHL:
3760 case ISD::SREM:
3761 case ISD::UREM:
3762 return LowerVectorArith(Op, DAG);
3764 return LowerDYNAMIC_STACKALLOC(Op, DAG);
3765 case ISD::STACKRESTORE:
3766 return LowerSTACKRESTORE(Op, DAG);
3767 case ISD::STACKSAVE:
3768 return LowerSTACKSAVE(Op, DAG);
3769 case ISD::CopyToReg:
3770 return LowerCopyToReg_128(Op, DAG);
3771 case ISD::FADD:
3772 case ISD::FSUB:
3773 case ISD::FMUL:
3774 // Used only for bf16 on SM80, where we select fma for non-ftz operation
3775 return PromoteBinOpIfF32FTZ(Op, DAG);
3776 case ISD::CTPOP:
3777 case ISD::CTLZ:
3778 return lowerCTLZCTPOP(Op, DAG);
3779 case ISD::BSWAP:
3780 return lowerBSWAP(Op, DAG);
3781 default:
3782 llvm_unreachable("Custom lowering not defined for operation");
3783 }
3784}
3785
3786// This will prevent AsmPrinter from trying to print the jump tables itself.
3790
3791SDValue NVPTXTargetLowering::LowerADDRSPACECAST(SDValue Op,
3792 SelectionDAG &DAG) const {
3794 unsigned SrcAS = N->getSrcAddressSpace();
3795 unsigned DestAS = N->getDestAddressSpace();
3796 if (SrcAS != llvm::ADDRESS_SPACE_GENERIC &&
3797 DestAS != llvm::ADDRESS_SPACE_GENERIC) {
3798 // Shared and SharedCluster can be converted to each other through generic
3799 // space
3800 if ((SrcAS == llvm::ADDRESS_SPACE_SHARED &&
3803 DestAS == llvm::ADDRESS_SPACE_SHARED)) {
3804 SDLoc DL(Op.getNode());
3805 const MVT GenerictVT =
3807 SDValue GenericConversion = DAG.getAddrSpaceCast(
3808 DL, GenerictVT, Op.getOperand(0), SrcAS, ADDRESS_SPACE_GENERIC);
3809 SDValue SharedClusterConversion =
3810 DAG.getAddrSpaceCast(DL, Op.getValueType(), GenericConversion,
3811 ADDRESS_SPACE_GENERIC, DestAS);
3812 return SharedClusterConversion;
3813 }
3814
3815 return DAG.getUNDEF(Op.getValueType());
3816 }
3817
3818 return Op;
3819}
3820
3821// This function is almost a copy of SelectionDAG::expandVAArg().
3822// The only diff is that this one produces loads from local address space.
3823SDValue NVPTXTargetLowering::LowerVAARG(SDValue Op, SelectionDAG &DAG) const {
3824 const TargetLowering *TLI = STI.getTargetLowering();
3825 SDLoc DL(Op);
3826
3827 SDNode *Node = Op.getNode();
3828 const Value *V = cast<SrcValueSDNode>(Node->getOperand(2))->getValue();
3829 EVT VT = Node->getValueType(0);
3830 auto *Ty = VT.getTypeForEVT(*DAG.getContext());
3831 SDValue Tmp1 = Node->getOperand(0);
3832 SDValue Tmp2 = Node->getOperand(1);
3833 const MaybeAlign MA(Node->getConstantOperandVal(3));
3834
3835 SDValue VAListLoad = DAG.getLoad(TLI->getPointerTy(DAG.getDataLayout()), DL,
3836 Tmp1, Tmp2, MachinePointerInfo(V));
3837 SDValue VAList = VAListLoad;
3838
3839 if (MA && *MA > TLI->getMinStackArgumentAlignment()) {
3840 VAList = DAG.getNode(
3841 ISD::ADD, DL, VAList.getValueType(), VAList,
3842 DAG.getConstant(MA->value() - 1, DL, VAList.getValueType()));
3843
3844 VAList = DAG.getNode(ISD::AND, DL, VAList.getValueType(), VAList,
3845 DAG.getSignedConstant(-(int64_t)MA->value(), DL,
3846 VAList.getValueType()));
3847 }
3848
3849 // Increment the pointer, VAList, to the next vaarg
3850 Tmp1 = DAG.getNode(ISD::ADD, DL, VAList.getValueType(), VAList,
3852 DL, VAList.getValueType()));
3853
3854 // Store the incremented VAList to the legalized pointer
3855 Tmp1 = DAG.getStore(VAListLoad.getValue(1), DL, Tmp1, Tmp2,
3856 MachinePointerInfo(V));
3857
3858 const Value *SrcV = Constant::getNullValue(
3860
3861 // Load the actual argument out of the pointer VAList
3862 return DAG.getLoad(VT, DL, Tmp1, VAList, MachinePointerInfo(SrcV));
3863}
3864
3865SDValue NVPTXTargetLowering::LowerVASTART(SDValue Op, SelectionDAG &DAG) const {
3866 const TargetLowering *TLI = STI.getTargetLowering();
3867 SDLoc DL(Op);
3868 EVT PtrVT = TLI->getPointerTy(DAG.getDataLayout());
3869
3870 // Store the address of unsized array <function>_vararg[] in the ap object.
3871 SDValue VAReg = getParamSymbolNode(DAG, /* vararg */ -1, PtrVT);
3872
3873 const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
3874 return DAG.getStore(Op.getOperand(0), DL, VAReg, Op.getOperand(1),
3875 MachinePointerInfo(SV));
3876}
3877
3878static std::pair<MemSDNode *, uint32_t>
3880 const NVPTXSubtarget &STI) {
3881 SDValue Chain = N->getOperand(0);
3882 SDValue BasePtr = N->getOperand(1);
3883 SDValue Mask = N->getOperand(3);
3884 [[maybe_unused]] SDValue Passthru = N->getOperand(4);
3885
3886 SDLoc DL(N);
3887 EVT ResVT = N->getValueType(0);
3888 assert(ResVT.isVector() && "Masked vector load must have vector type");
3889 // While we only expect poison passthru vectors as an input to the backend,
3890 // when the legalization framework splits a poison vector in half, it creates
3891 // two undef vectors, so we can technically expect those too.
3892 assert((Passthru.getOpcode() == ISD::POISON ||
3893 Passthru.getOpcode() == ISD::UNDEF) &&
3894 "Passthru operand expected to be poison or undef");
3895
3896 // Extract the mask and convert it to a uint32_t representing the used bytes
3897 // of the entire vector load
3898 uint32_t UsedBytesMask = 0;
3899 uint32_t ElementSizeInBits = ResVT.getVectorElementType().getSizeInBits();
3900 assert(ElementSizeInBits % 8 == 0 && "Unexpected element size");
3901 uint32_t ElementSizeInBytes = ElementSizeInBits / 8;
3902 uint32_t ElementMask = (1u << ElementSizeInBytes) - 1u;
3903
3904 for (SDValue Op : reverse(Mask->ops())) {
3905 // We technically only want to do this shift for every
3906 // iteration *but* the first, but in the first iteration UsedBytesMask is 0,
3907 // so this shift is a no-op.
3908 UsedBytesMask <<= ElementSizeInBytes;
3909
3910 // Mask elements must be constants.
3911 if (Op->getAsZExtVal() != 0)
3912 UsedBytesMask |= ElementMask;
3913 }
3914
3915 assert(UsedBytesMask != 0 && UsedBytesMask != UINT32_MAX &&
3916 "Unexpected masked load with elements masked all on or all off");
3917
3918 // Create a new load sd node to be handled normally by ReplaceLoadVector.
3919 MemSDNode *NewLD = cast<MemSDNode>(
3920 DAG.getLoad(ResVT, DL, Chain, BasePtr, N->getMemOperand()).getNode());
3921
3922 // If our subtarget does not support the used bytes mask pragma, "drop" the
3923 // mask by setting it to UINT32_MAX
3924 if (!STI.hasUsedBytesMaskPragma())
3925 UsedBytesMask = UINT32_MAX;
3926
3927 return {NewLD, UsedBytesMask};
3928}
3929
3930/// replaceLoadVector - Convert vector loads into multi-output scalar loads.
3931static std::optional<std::pair<SDValue, SDValue>>
3934 const EVT ResVT = LD->getValueType(0);
3935 const EVT MemVT = LD->getMemoryVT();
3936
3937 // If we're doing sign/zero extension as part of the load, avoid lowering to
3938 // a LoadV node. TODO: consider relaxing this restriction.
3939 if (ResVT != MemVT)
3940 return std::nullopt;
3941
3942 const auto NumEltsAndEltVT =
3943 getVectorLoweringShape(ResVT, STI, LD->getAddressSpace());
3944 if (!NumEltsAndEltVT)
3945 return std::nullopt;
3946 const auto [NumElts, EltVT] = NumEltsAndEltVT.value();
3947
3948 Align Alignment = LD->getAlign();
3949 const auto &TD = DAG.getDataLayout();
3950 Align PrefAlign = TD.getPrefTypeAlign(MemVT.getTypeForEVT(*DAG.getContext()));
3951 if (Alignment < PrefAlign) {
3952 // This load is not sufficiently aligned, so bail out and let this vector
3953 // load be scalarized. Note that we may still be able to emit smaller
3954 // vector loads. For example, if we are loading a <4 x float> with an
3955 // alignment of 8, this check will fail but the legalizer will try again
3956 // with 2 x <2 x float>, which will succeed with an alignment of 8.
3957 return std::nullopt;
3958 }
3959
3960 // If we have a masked load, convert it to a normal load now
3961 std::optional<uint32_t> UsedBytesMask = std::nullopt;
3962 if (LD->getOpcode() == ISD::MLOAD)
3963 std::tie(LD, UsedBytesMask) =
3965
3966 // Since LoadV2 is a target node, we cannot rely on DAG type legalization.
3967 // Therefore, we must ensure the type is legal. For i1 and i8, we set the
3968 // loaded type to i16 and propagate the "real" type as the memory type.
3969 const MVT LoadEltVT = (EltVT.getSizeInBits() < 16) ? MVT::i16 : EltVT;
3970
3971 unsigned Opcode;
3972 switch (NumElts) {
3973 default:
3974 return std::nullopt;
3975 case 2:
3976 Opcode = NVPTXISD::LoadV2;
3977 break;
3978 case 4:
3979 Opcode = NVPTXISD::LoadV4;
3980 break;
3981 case 8:
3982 Opcode = NVPTXISD::LoadV8;
3983 break;
3984 }
3985 auto ListVTs = SmallVector<EVT, 9>(NumElts, LoadEltVT);
3986 ListVTs.push_back(MVT::Other);
3987 SDVTList LdResVTs = DAG.getVTList(ListVTs);
3988
3989 SDLoc DL(LD);
3990
3991 // Copy regular operands
3992 SmallVector<SDValue, 8> OtherOps(LD->ops());
3993
3994 OtherOps.push_back(
3995 DAG.getConstant(UsedBytesMask.value_or(UINT32_MAX), DL, MVT::i32));
3996
3997 // The select routine does not have access to the LoadSDNode instance, so
3998 // pass along the extension information
3999 OtherOps.push_back(
4000 DAG.getIntPtrConstant(cast<LoadSDNode>(LD)->getExtensionType(), DL));
4001
4002 SDValue NewLD = DAG.getMemIntrinsicNode(Opcode, DL, LdResVTs, OtherOps, MemVT,
4003 LD->getMemOperand());
4004
4005 SmallVector<SDValue> ScalarRes;
4006 if (EltVT.isVector()) {
4008 assert(NumElts * EltVT.getVectorNumElements() ==
4009 ResVT.getVectorNumElements());
4010 // Generate EXTRACT_VECTOR_ELTs to split v2[i,f,bf]16/v4i8 subvectors back
4011 // into individual elements.
4012 for (const unsigned I : llvm::seq(NumElts)) {
4013 SDValue SubVector = NewLD.getValue(I);
4014 DAG.ExtractVectorElements(SubVector, ScalarRes);
4015 }
4016 } else {
4017 for (const unsigned I : llvm::seq(NumElts)) {
4018 SDValue Res = NewLD.getValue(I);
4019 if (LoadEltVT != EltVT)
4020 Res = DAG.getNode(ISD::TRUNCATE, DL, EltVT, Res);
4021 ScalarRes.push_back(Res);
4022 }
4023 }
4024
4025 SDValue LoadChain = NewLD.getValue(NumElts);
4026
4027 const MVT BuildVecVT =
4028 MVT::getVectorVT(EltVT.getScalarType(), ScalarRes.size());
4029 SDValue BuildVec = DAG.getBuildVector(BuildVecVT, DL, ScalarRes);
4030 SDValue LoadValue = DAG.getBitcast(ResVT, BuildVec);
4031
4032 return {{LoadValue, LoadChain}};
4033}
4034
4037 const NVPTXSubtarget &STI) {
4038 if (auto Res = replaceLoadVector(N, DAG, STI))
4039 Results.append({Res->first, Res->second});
4040}
4041
4043 const NVPTXSubtarget &STI) {
4044 if (auto Res = replaceLoadVector(N, DAG, STI))
4045 return DAG.getMergeValues({Res->first, Res->second}, SDLoc(N));
4046 return SDValue();
4047}
4048
4049// v = ld i1* addr
4050// =>
4051// v1 = ld i8* addr (-> i16)
4052// v = trunc i16 to i1
4054 SDLoc dl(LD);
4055 assert(LD->getExtensionType() == ISD::NON_EXTLOAD);
4056 assert(LD->getValueType(0) == MVT::i1 && "Custom lowering for i1 load only");
4057 SDValue newLD = DAG.getExtLoad(ISD::ZEXTLOAD, dl, MVT::i16, LD->getChain(),
4058 LD->getBasePtr(), LD->getPointerInfo(),
4059 MVT::i8, LD->getAlign(),
4060 LD->getMemOperand()->getFlags());
4061 SDValue result = DAG.getNode(ISD::TRUNCATE, dl, MVT::i1, newLD);
4062 // The legalizer (the caller) is expecting two values from the legalized
4063 // load, so we build a MergeValues node for it. See ExpandUnalignedLoad()
4064 // in LegalizeDAG.cpp which also uses MergeValues.
4065 return DAG.getMergeValues({result, newLD.getValue(1)}, dl);
4066}
4067
4068SDValue NVPTXTargetLowering::LowerLOAD(SDValue Op, SelectionDAG &DAG) const {
4069 LoadSDNode *LD = cast<LoadSDNode>(Op);
4070
4071 if (Op.getValueType() == MVT::i1)
4072 return lowerLOADi1(LD, DAG);
4073
4074 // To improve CodeGen we'll legalize any-extend loads to zext loads. This is
4075 // how they'll be lowered in ISel anyway, and by doing this a little earlier
4076 // we allow for more DAG combine opportunities.
4077 if (LD->getExtensionType() == ISD::EXTLOAD) {
4078 assert(LD->getValueType(0).isInteger() && LD->getMemoryVT().isInteger() &&
4079 "Unexpected fpext-load");
4080 return DAG.getExtLoad(ISD::ZEXTLOAD, SDLoc(Op), Op.getValueType(),
4081 LD->getChain(), LD->getBasePtr(), LD->getMemoryVT(),
4082 LD->getMemOperand());
4083 }
4084
4085 llvm_unreachable("Unexpected custom lowering for load");
4086}
4087
4088SDValue NVPTXTargetLowering::LowerMLOAD(SDValue Op, SelectionDAG &DAG) const {
4089 // v2f16/v2bf16/v2i16/v4i8 are legal, so we can't rely on legalizer to handle
4090 // masked loads of these types and have to handle them here.
4091 // v2f32 also needs to be handled here if the subtarget has f32x2
4092 // instructions, making it legal.
4093 //
4094 // Note: misaligned masked loads should never reach this point
4095 // because the override of isLegalMaskedLoad in NVPTXTargetTransformInfo.cpp
4096 // will validate alignment. Therefore, we do not need to special case handle
4097 // them here.
4098 EVT VT = Op.getValueType();
4099 if (NVPTX::isPackedVectorTy(VT)) {
4101 cast<MemSDNode>(Op.getNode()), DAG, STI);
4102 MemSDNode *LD = std::get<0>(Result);
4103 uint32_t UsedBytesMask = std::get<1>(Result);
4104
4105 SDLoc DL(LD);
4106
4107 // Copy regular operands
4108 SmallVector<SDValue, 8> OtherOps(LD->ops());
4109
4110 OtherOps.push_back(DAG.getConstant(UsedBytesMask, DL, MVT::i32));
4111
4112 // We currently are not lowering extending loads, but pass the extension
4113 // type anyway as later handling expects it.
4114 OtherOps.push_back(
4115 DAG.getIntPtrConstant(cast<LoadSDNode>(LD)->getExtensionType(), DL));
4116 SDValue NewLD =
4117 DAG.getMemIntrinsicNode(NVPTXISD::MLoad, DL, LD->getVTList(), OtherOps,
4118 LD->getMemoryVT(), LD->getMemOperand());
4119 return NewLD;
4120 }
4121 return SDValue();
4122}
4123
4125 const NVPTXSubtarget &STI) {
4126 MemSDNode *N = cast<MemSDNode>(Op.getNode());
4127 SDValue Val = N->getOperand(1);
4128 SDLoc DL(N);
4129 const EVT ValVT = Val.getValueType();
4130 const EVT MemVT = N->getMemoryVT();
4131
4132 // If we're truncating as part of the store, avoid lowering to a StoreV node.
4133 // TODO: consider relaxing this restriction.
4134 if (ValVT != MemVT)
4135 return SDValue();
4136
4137 const auto NumEltsAndEltVT =
4138 getVectorLoweringShape(ValVT, STI, N->getAddressSpace());
4139 if (!NumEltsAndEltVT)
4140 return SDValue();
4141 const auto [NumElts, EltVT] = NumEltsAndEltVT.value();
4142
4143 const DataLayout &TD = DAG.getDataLayout();
4144
4145 Align Alignment = N->getAlign();
4146 Align PrefAlign = TD.getPrefTypeAlign(ValVT.getTypeForEVT(*DAG.getContext()));
4147 if (Alignment < PrefAlign) {
4148 // This store is not sufficiently aligned, so bail out and let this vector
4149 // store be scalarized. Note that we may still be able to emit smaller
4150 // vector stores. For example, if we are storing a <4 x float> with an
4151 // alignment of 8, this check will fail but the legalizer will try again
4152 // with 2 x <2 x float>, which will succeed with an alignment of 8.
4153 return SDValue();
4154 }
4155
4156 unsigned Opcode;
4157 switch (NumElts) {
4158 default:
4159 return SDValue();
4160 case 2:
4161 Opcode = NVPTXISD::StoreV2;
4162 break;
4163 case 4:
4164 Opcode = NVPTXISD::StoreV4;
4165 break;
4166 case 8:
4167 Opcode = NVPTXISD::StoreV8;
4168 break;
4169 }
4170
4172
4173 // First is the chain
4174 Ops.push_back(N->getOperand(0));
4175
4176 // Then the split values
4177 if (EltVT.isVector()) {
4179 assert(NumElts * EltVT.getVectorNumElements() ==
4180 ValVT.getVectorNumElements());
4181 // Combine individual elements into v2[i,f,bf]16/v4i8 subvectors to be
4182 // stored as b32s
4183 const unsigned NumEltsPerSubVector = EltVT.getVectorNumElements();
4184 for (const unsigned I : llvm::seq(NumElts)) {
4185 SmallVector<SDValue, 4> SubVectorElts;
4186 DAG.ExtractVectorElements(Val, SubVectorElts, I * NumEltsPerSubVector,
4187 NumEltsPerSubVector);
4188 Ops.push_back(DAG.getBuildVector(EltVT, DL, SubVectorElts));
4189 }
4190 } else {
4191 SDValue V = DAG.getBitcast(MVT::getVectorVT(EltVT, NumElts), Val);
4192 for (const unsigned I : llvm::seq(NumElts)) {
4193 SDValue ExtVal = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, EltVT, V,
4194 DAG.getIntPtrConstant(I, DL));
4195
4196 // Since StoreV2 is a target node, we cannot rely on DAG type
4197 // legalization. Therefore, we must ensure the type is legal. For i1 and
4198 // i8, we set the stored type to i16 and propagate the "real" type as the
4199 // memory type.
4200 if (EltVT.getSizeInBits() < 16)
4201 ExtVal = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i16, ExtVal);
4202 Ops.push_back(ExtVal);
4203 }
4204 }
4205
4206 // Then any remaining arguments
4207 Ops.append(N->op_begin() + 2, N->op_end());
4208
4209 SDValue NewSt =
4210 DAG.getMemIntrinsicNode(Opcode, DL, DAG.getVTList(MVT::Other), Ops,
4211 N->getMemoryVT(), N->getMemOperand());
4212
4213 // return DCI.CombineTo(N, NewSt, true);
4214 return NewSt;
4215}
4216
4217SDValue NVPTXTargetLowering::LowerSTORE(SDValue Op, SelectionDAG &DAG) const {
4218 StoreSDNode *Store = cast<StoreSDNode>(Op);
4219 EVT VT = Store->getMemoryVT();
4220
4221 // Leave truncating stores to i1 to the generic legalizer.
4222 if (VT == MVT::i1 && !Store->isTruncatingStore())
4223 return LowerSTOREi1(Op, DAG);
4224
4225 // Lower store of any other vector type, including v2f32 as we want to break
4226 // it apart since this is not a widely-supported type.
4227 return lowerSTOREVector(Op, DAG, STI);
4228}
4229
4230// st i1 v, addr
4231// =>
4232// v1 = zxt v to i16
4233// st.u8 i16, addr
4234SDValue NVPTXTargetLowering::LowerSTOREi1(SDValue Op, SelectionDAG &DAG) const {
4235 SDNode *Node = Op.getNode();
4236 SDLoc dl(Node);
4237 StoreSDNode *ST = cast<StoreSDNode>(Node);
4238 SDValue Tmp1 = ST->getChain();
4239 SDValue Tmp2 = ST->getBasePtr();
4240 SDValue Tmp3 = ST->getValue();
4241 assert(Tmp3.getValueType() == MVT::i1 && "Custom lowering for i1 store only");
4242 Tmp3 = DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::i16, Tmp3);
4243 SDValue Result =
4244 DAG.getTruncStore(Tmp1, dl, Tmp3, Tmp2, ST->getPointerInfo(), MVT::i8,
4245 ST->getAlign(), ST->getMemOperand()->getFlags());
4246 return Result;
4247}
4248
4249SDValue NVPTXTargetLowering::LowerCopyToReg_128(SDValue Op,
4250 SelectionDAG &DAG) const {
4251 // Change the CopyToReg to take in two 64-bit operands instead of a 128-bit
4252 // operand so that it can pass the legalization.
4253
4254 assert(Op.getOperand(1).getValueType() == MVT::i128 &&
4255 "Custom lowering for 128-bit CopyToReg only");
4256
4257 SDNode *Node = Op.getNode();
4258 SDLoc DL(Node);
4259
4260 SDValue Cast = DAG.getBitcast(MVT::v2i64, Op->getOperand(2));
4261 SDValue Lo = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::i64, Cast,
4262 DAG.getIntPtrConstant(0, DL));
4263 SDValue Hi = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::i64, Cast,
4264 DAG.getIntPtrConstant(1, DL));
4265
4267 SmallVector<EVT, 3> ResultsType(Node->values());
4268
4269 NewOps[0] = Op->getOperand(0); // Chain
4270 NewOps[1] = Op->getOperand(1); // Dst Reg
4271 NewOps[2] = Lo; // Lower 64-bit
4272 NewOps[3] = Hi; // Higher 64-bit
4273 if (Op.getNumOperands() == 4)
4274 NewOps[4] = Op->getOperand(3); // Glue if exists
4275
4276 return DAG.getNode(ISD::CopyToReg, DL, ResultsType, NewOps);
4277}
4278
4279unsigned NVPTXTargetLowering::getNumRegisters(
4280 LLVMContext &Context, EVT VT,
4281 std::optional<MVT> RegisterVT = std::nullopt) const {
4282 if (VT == MVT::i128 && RegisterVT == MVT::i128)
4283 return 1;
4284 return TargetLoweringBase::getNumRegisters(Context, VT, RegisterVT);
4285}
4286
4287bool NVPTXTargetLowering::splitValueIntoRegisterParts(
4288 SelectionDAG &DAG, const SDLoc &DL, SDValue Val, SDValue *Parts,
4289 unsigned NumParts, MVT PartVT, std::optional<CallingConv::ID> CC) const {
4290 if (Val.getValueType() == MVT::i128 && NumParts == 1) {
4291 Parts[0] = Val;
4292 return true;
4293 }
4294 return false;
4295}
4296
4297SDValue NVPTXTargetLowering::getParamSymbolNode(SelectionDAG &DAG, int I,
4298 EVT T) const {
4299 const MachineFunction &MF = DAG.getMachineFunction();
4300 return getSymbolNode(
4301 DAG, getParamSymbol(MF.getContext(), &MF.getFunction(), I), T);
4302}
4303
4304SDValue NVPTXTargetLowering::getCallParamSymbolNode(SelectionDAG &DAG, int I,
4305 EVT T) const {
4306 return getSymbolNode(DAG, "param" + Twine(I), T);
4307}
4308
4310 SDValue Chain, CallingConv::ID CallConv, bool isVarArg,
4311 const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &dl,
4312 SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
4313 const DataLayout &DL = DAG.getDataLayout();
4314 LLVMContext &Ctx = *DAG.getContext();
4315
4316 const Function &F = DAG.getMachineFunction().getFunction();
4317 const bool IsKernel = isKernelFunction(F);
4318
4319 const MVT PtrVT = getPointerTy(DL, IsKernel ? ADDRESS_SPACE_ENTRY_PARAM
4321
4322 SDValue Root = DAG.getRoot();
4323 SmallVector<SDValue, 16> OutChains;
4324
4325 // argTypes.size() (or theArgs.size()) and Ins.size() need not match.
4326 // Ins.size() will be larger
4327 // * if there is an aggregate argument with multiple fields (each field
4328 // showing up separately in Ins)
4329 // * if there is a vector argument with more than typical vector-length
4330 // elements (generally if more than 4) where each vector element is
4331 // individually present in Ins.
4332 // So a different index should be used for indexing into Ins.
4333 // See similar issue in LowerCall.
4334
4335 auto AllIns = ArrayRef(Ins);
4336 const auto NonEmptyArgs = make_filter_range(
4337 F.args(), [](const Argument &A) { return !A.getType()->isEmptyTy(); });
4338 for (const auto &[ParamI, Arg] : enumerate(NonEmptyArgs)) {
4339 const unsigned ArgNo = Arg.getArgNo();
4340 const auto ArgIns =
4341 AllIns.take_while([&](auto I) { return I.OrigArgIndex == ArgNo; });
4342 AllIns = AllIns.drop_front(ArgIns.size());
4343
4344 Type *Ty = Arg.getType();
4345 assert(!ArgIns.empty() &&
4346 "Non-empty argument produced no parameter values");
4347
4348 if (Arg.use_empty()) {
4349 // argument is dead
4350 for (const auto &In : ArgIns) {
4351 assert(!In.Used && "Arg.use_empty() is true but Arg is used?");
4352 InVals.push_back(DAG.getUNDEF(In.VT));
4353 }
4354 continue;
4355 }
4356
4357 SDValue ArgSymbol = getParamSymbolNode(DAG, ParamI, PtrVT);
4358
4359 // In the following cases, assign a node order of "i+1"
4360 // to newly created nodes. The SDNodes for params have to
4361 // appear in the same order as their order of appearance
4362 // in the original function. "i+1" holds that order.
4363 if (Arg.hasByValAttr()) {
4364 // Param has ByVal attribute
4365 // Return MoveParam(param symbol).
4366 // Ideally, the param symbol can be returned directly,
4367 // but when SDNode builder decides to use it in a CopyToReg(),
4368 // machine instruction fails because TargetExternalSymbol
4369 // (not lowered) is target dependent, and CopyToReg assumes
4370 // the source is lowered.
4371 assert(ArgIns.size() == 1 && "ByVal argument must be a pointer");
4372 const auto &ByvalIn = ArgIns[0];
4373 assert(getValueType(DL, Ty) == ByvalIn.VT &&
4374 "Ins type did not match function type");
4375
4376 SDValue P;
4377 if (IsKernel) {
4378 assert(Ty->getPointerAddressSpace() == ADDRESS_SPACE_ENTRY_PARAM &&
4379 "Kernel ByVal argument must be lowered to the param address "
4380 "space by NVPTXLowerArgs");
4381 P = ArgSymbol;
4382 P.getNode()->setIROrder(Arg.getArgNo() + 1);
4383 } else {
4384 P = DAG.getNode(NVPTXISD::MoveParam, dl, ArgSymbol.getValueType(),
4385 ArgSymbol);
4386 P.getNode()->setIROrder(Arg.getArgNo() + 1);
4387 P = DAG.getAddrSpaceCast(dl, ByvalIn.VT, P, ADDRESS_SPACE_LOCAL,
4389 }
4390 InVals.push_back(P);
4391 } else {
4394 ComputePTXValueVTs(*this, DL, Ctx, CallConv, Ty, VTs, Offsets);
4395 assert(VTs.size() == ArgIns.size() && "Size mismatch");
4396 assert(VTs.size() == Offsets.size() && "Size mismatch");
4397
4398 const Align ArgAlign = getPTXParamAlign(
4399 &F, Ty, Arg.getArgNo() + AttributeList::FirstArgIndex, DL);
4400
4401 unsigned I = 0;
4402 const auto VI = VectorizePTXValueVTs(VTs, Offsets, ArgAlign);
4403 for (const unsigned NumElts : VI) {
4404 // i1 is loaded/stored as i8
4405 const EVT LoadVT = VTs[I] == MVT::i1 ? MVT::i8 : VTs[I];
4406 const EVT VecVT = getVectorizedVT(LoadVT, NumElts, Ctx);
4407
4408 SDValue VecAddr = DAG.getObjectPtrOffset(
4409 dl, ArgSymbol, TypeSize::getFixed(Offsets[I]));
4410
4411 const Align PartAlign = commonAlignment(ArgAlign, Offsets[I]);
4412 const unsigned AS = IsKernel ? NVPTX::AddressSpace::EntryParam
4414 SDValue P = DAG.getLoad(VecVT, dl, Root, VecAddr,
4415 MachinePointerInfo(AS), PartAlign,
4418 P.getNode()->setIROrder(Arg.getArgNo() + 1);
4419 for (const unsigned J : llvm::seq(NumElts)) {
4420 SDValue Elt = getExtractVectorizedValue(P, J, LoadVT, dl, DAG);
4421
4422 Elt = correctParamType(Elt, ArgIns[I + J].VT, ArgIns[I + J].Flags,
4423 DAG, dl);
4424 InVals.push_back(Elt);
4425 }
4426 I += NumElts;
4427 }
4428 }
4429 }
4430
4431 if (!OutChains.empty())
4432 DAG.setRoot(DAG.getTokenFactor(dl, OutChains));
4433
4434 return Chain;
4435}
4436
4437SDValue
4439 bool isVarArg,
4441 const SmallVectorImpl<SDValue> &OutVals,
4442 const SDLoc &dl, SelectionDAG &DAG) const {
4443 const Function &F = DAG.getMachineFunction().getFunction();
4444 Type *RetTy = F.getReturnType();
4445
4446 if (RetTy->isVoidTy()) {
4447 assert(OutVals.empty() && Outs.empty() && "Return value expected for void");
4448 return DAG.getNode(NVPTXISD::RET_GLUE, dl, MVT::Other, Chain);
4449 }
4450
4451 const DataLayout &DL = DAG.getDataLayout();
4452 LLVMContext &Ctx = *DAG.getContext();
4453
4454 const SDValue RetSymbol = getSymbolNode(DAG, "func_retval0", MVT::i32);
4455 const auto RetAlign =
4456 getPTXParamAlign(&F, RetTy, AttributeList::ReturnIndex, DL);
4457
4458 // PTX Interoperability Guide 3.3(A): [Integer] Values shorter than
4459 // 32-bits are sign extended or zero extended, depending on whether
4460 // they are signed or unsigned types.
4461 const bool ExtendIntegerRetVal =
4462 RetTy->isIntegerTy() && DL.getTypeAllocSizeInBits(RetTy) < 32;
4463
4466 ComputePTXValueVTs(*this, DL, Ctx, CallConv, RetTy, VTs, Offsets);
4467 assert(VTs.size() == OutVals.size() && "Bad return value decomposition");
4468
4469 const auto GetRetVal = [&](unsigned I) -> SDValue {
4470 SDValue RetVal = OutVals[I];
4472 RetVal.getValueType() &&
4473 "OutVal type should always be legal");
4474
4475 const EVT VTI = promoteScalarIntegerPTX(VTs[I]);
4476 const EVT StoreVT =
4477 ExtendIntegerRetVal ? MVT::i32 : (VTI == MVT::i1 ? MVT::i8 : VTI);
4478 return correctParamType(RetVal, StoreVT, Outs[I].Flags, DAG, dl);
4479 };
4480
4481 unsigned I = 0;
4482 const auto VI = VectorizePTXValueVTs(VTs, Offsets, RetAlign);
4483 for (const unsigned NumElts : VI) {
4484 const MaybeAlign CurrentAlign = ExtendIntegerRetVal
4485 ? MaybeAlign(std::nullopt)
4486 : commonAlignment(RetAlign, Offsets[I]);
4487
4489 NumElts, dl, DAG, [&](unsigned K) { return GetRetVal(I + K); });
4490
4491 SDValue Ptr =
4492 DAG.getObjectPtrOffset(dl, RetSymbol, TypeSize::getFixed(Offsets[I]));
4493
4494 Chain = DAG.getStore(Chain, dl, Val, Ptr,
4496 CurrentAlign);
4497
4498 I += NumElts;
4499 }
4500
4501 return DAG.getNode(NVPTXISD::RET_GLUE, dl, MVT::Other, Chain);
4502}
4503
4505 SDValue Op, StringRef Constraint, std::vector<SDValue> &Ops,
4506 SelectionDAG &DAG) const {
4507 if (Constraint.size() > 1)
4508 return;
4510}
4511
4512// llvm.ptx.memcpy.const and llvm.ptx.memmove.const need to be modeled as
4513// TgtMemIntrinsic
4514// because we need the information that is only available in the "Value" type
4515// of destination
4516// pointer. In particular, the address space information.
4519 MachineFunction &MF, unsigned Intrinsic) const {
4520 IntrinsicInfo Info;
4521 switch (Intrinsic) {
4522 default:
4523 return;
4524 case Intrinsic::nvvm_match_all_sync_i32p:
4525 case Intrinsic::nvvm_match_all_sync_i64p:
4526 Info.opc = ISD::INTRINSIC_W_CHAIN;
4527 // memVT is bogus. These intrinsics have IntrInaccessibleMemOnly attribute
4528 // in order to model data exchange with other threads, but perform no real
4529 // memory accesses.
4530 Info.memVT = MVT::i1;
4531
4532 // Our result depends on both our and other thread's arguments.
4534 Infos.push_back(Info);
4535 return;
4536 case Intrinsic::nvvm_wmma_m16n16k16_load_a_f16_col:
4537 case Intrinsic::nvvm_wmma_m16n16k16_load_a_f16_row:
4538 case Intrinsic::nvvm_wmma_m16n16k16_load_a_f16_col_stride:
4539 case Intrinsic::nvvm_wmma_m16n16k16_load_a_f16_row_stride:
4540 case Intrinsic::nvvm_wmma_m16n16k16_load_b_f16_col:
4541 case Intrinsic::nvvm_wmma_m16n16k16_load_b_f16_row:
4542 case Intrinsic::nvvm_wmma_m16n16k16_load_b_f16_col_stride:
4543 case Intrinsic::nvvm_wmma_m16n16k16_load_b_f16_row_stride:
4544 case Intrinsic::nvvm_wmma_m32n8k16_load_a_f16_col:
4545 case Intrinsic::nvvm_wmma_m32n8k16_load_a_f16_row:
4546 case Intrinsic::nvvm_wmma_m32n8k16_load_a_f16_col_stride:
4547 case Intrinsic::nvvm_wmma_m32n8k16_load_a_f16_row_stride:
4548 case Intrinsic::nvvm_wmma_m32n8k16_load_b_f16_col:
4549 case Intrinsic::nvvm_wmma_m32n8k16_load_b_f16_row:
4550 case Intrinsic::nvvm_wmma_m32n8k16_load_b_f16_col_stride:
4551 case Intrinsic::nvvm_wmma_m32n8k16_load_b_f16_row_stride:
4552 case Intrinsic::nvvm_wmma_m8n32k16_load_a_f16_col:
4553 case Intrinsic::nvvm_wmma_m8n32k16_load_a_f16_row:
4554 case Intrinsic::nvvm_wmma_m8n32k16_load_a_f16_col_stride:
4555 case Intrinsic::nvvm_wmma_m8n32k16_load_a_f16_row_stride:
4556 case Intrinsic::nvvm_wmma_m8n32k16_load_b_f16_col:
4557 case Intrinsic::nvvm_wmma_m8n32k16_load_b_f16_row:
4558 case Intrinsic::nvvm_wmma_m8n32k16_load_b_f16_col_stride:
4559 case Intrinsic::nvvm_wmma_m8n32k16_load_b_f16_row_stride: {
4560 Info.opc = ISD::INTRINSIC_W_CHAIN;
4561 Info.memVT = MVT::v8f16;
4562 Info.ptrVal = I.getArgOperand(0);
4563 Info.offset = 0;
4564 Info.flags = MachineMemOperand::MOLoad;
4565 Info.align = Align(16);
4566 Infos.push_back(Info);
4567 return;
4568 }
4569 case Intrinsic::nvvm_wmma_m16n16k16_load_a_s8_col:
4570 case Intrinsic::nvvm_wmma_m16n16k16_load_a_s8_col_stride:
4571 case Intrinsic::nvvm_wmma_m16n16k16_load_a_u8_col_stride:
4572 case Intrinsic::nvvm_wmma_m16n16k16_load_a_u8_col:
4573 case Intrinsic::nvvm_wmma_m16n16k16_load_a_s8_row:
4574 case Intrinsic::nvvm_wmma_m16n16k16_load_a_s8_row_stride:
4575 case Intrinsic::nvvm_wmma_m16n16k16_load_a_u8_row_stride:
4576 case Intrinsic::nvvm_wmma_m16n16k16_load_a_u8_row:
4577 case Intrinsic::nvvm_wmma_m8n32k16_load_a_bf16_col:
4578 case Intrinsic::nvvm_wmma_m8n32k16_load_a_bf16_col_stride:
4579 case Intrinsic::nvvm_wmma_m8n32k16_load_a_bf16_row:
4580 case Intrinsic::nvvm_wmma_m8n32k16_load_a_bf16_row_stride:
4581 case Intrinsic::nvvm_wmma_m16n16k16_load_b_s8_col:
4582 case Intrinsic::nvvm_wmma_m16n16k16_load_b_s8_col_stride:
4583 case Intrinsic::nvvm_wmma_m16n16k16_load_b_u8_col_stride:
4584 case Intrinsic::nvvm_wmma_m16n16k16_load_b_u8_col:
4585 case Intrinsic::nvvm_wmma_m16n16k16_load_b_s8_row:
4586 case Intrinsic::nvvm_wmma_m16n16k16_load_b_s8_row_stride:
4587 case Intrinsic::nvvm_wmma_m16n16k16_load_b_u8_row_stride:
4588 case Intrinsic::nvvm_wmma_m16n16k16_load_b_u8_row:
4589 case Intrinsic::nvvm_wmma_m32n8k16_load_b_bf16_col:
4590 case Intrinsic::nvvm_wmma_m32n8k16_load_b_bf16_col_stride:
4591 case Intrinsic::nvvm_wmma_m32n8k16_load_b_bf16_row:
4592 case Intrinsic::nvvm_wmma_m32n8k16_load_b_bf16_row_stride: {
4593 Info.opc = ISD::INTRINSIC_W_CHAIN;
4594 Info.memVT = MVT::v2i32;
4595 Info.ptrVal = I.getArgOperand(0);
4596 Info.offset = 0;
4597 Info.flags = MachineMemOperand::MOLoad;
4598 Info.align = Align(8);
4599 Infos.push_back(Info);
4600 return;
4601 }
4602
4603 case Intrinsic::nvvm_wmma_m32n8k16_load_a_s8_col:
4604 case Intrinsic::nvvm_wmma_m32n8k16_load_a_s8_col_stride:
4605 case Intrinsic::nvvm_wmma_m32n8k16_load_a_u8_col_stride:
4606 case Intrinsic::nvvm_wmma_m32n8k16_load_a_u8_col:
4607 case Intrinsic::nvvm_wmma_m32n8k16_load_a_s8_row:
4608 case Intrinsic::nvvm_wmma_m32n8k16_load_a_s8_row_stride:
4609 case Intrinsic::nvvm_wmma_m32n8k16_load_a_u8_row_stride:
4610 case Intrinsic::nvvm_wmma_m32n8k16_load_a_u8_row:
4611 case Intrinsic::nvvm_wmma_m16n16k16_load_a_bf16_col:
4612 case Intrinsic::nvvm_wmma_m16n16k16_load_a_bf16_col_stride:
4613 case Intrinsic::nvvm_wmma_m16n16k16_load_a_bf16_row:
4614 case Intrinsic::nvvm_wmma_m16n16k16_load_a_bf16_row_stride:
4615 case Intrinsic::nvvm_wmma_m16n16k8_load_a_tf32_col:
4616 case Intrinsic::nvvm_wmma_m16n16k8_load_a_tf32_col_stride:
4617 case Intrinsic::nvvm_wmma_m16n16k8_load_a_tf32_row:
4618 case Intrinsic::nvvm_wmma_m16n16k8_load_a_tf32_row_stride:
4619
4620 case Intrinsic::nvvm_wmma_m8n32k16_load_b_s8_col:
4621 case Intrinsic::nvvm_wmma_m8n32k16_load_b_s8_col_stride:
4622 case Intrinsic::nvvm_wmma_m8n32k16_load_b_u8_col_stride:
4623 case Intrinsic::nvvm_wmma_m8n32k16_load_b_u8_col:
4624 case Intrinsic::nvvm_wmma_m8n32k16_load_b_s8_row:
4625 case Intrinsic::nvvm_wmma_m8n32k16_load_b_s8_row_stride:
4626 case Intrinsic::nvvm_wmma_m8n32k16_load_b_u8_row_stride:
4627 case Intrinsic::nvvm_wmma_m8n32k16_load_b_u8_row:
4628 case Intrinsic::nvvm_wmma_m16n16k16_load_b_bf16_col:
4629 case Intrinsic::nvvm_wmma_m16n16k16_load_b_bf16_col_stride:
4630 case Intrinsic::nvvm_wmma_m16n16k16_load_b_bf16_row:
4631 case Intrinsic::nvvm_wmma_m16n16k16_load_b_bf16_row_stride:
4632 case Intrinsic::nvvm_wmma_m16n16k8_load_b_tf32_col:
4633 case Intrinsic::nvvm_wmma_m16n16k8_load_b_tf32_col_stride:
4634 case Intrinsic::nvvm_wmma_m16n16k8_load_b_tf32_row:
4635 case Intrinsic::nvvm_wmma_m16n16k8_load_b_tf32_row_stride:
4636 case Intrinsic::nvvm_ldmatrix_sync_aligned_m8n8_x4_b16:
4637 case Intrinsic::nvvm_ldmatrix_sync_aligned_m8n8_x4_trans_b16:
4638 case Intrinsic::nvvm_ldmatrix_sync_aligned_m16n16_x2_trans_b8:
4639 case Intrinsic::nvvm_ldmatrix_sync_aligned_m16n16_x2_trans_b8x16_b4x16_p64:
4640 case Intrinsic::nvvm_ldmatrix_sync_aligned_m16n16_x2_trans_b8x16_b6x16_p32:
4641 case Intrinsic::nvvm_ldmatrix_sync_aligned_m8n16_x4_b8x16_b4x16_p64:
4642 case Intrinsic::nvvm_ldmatrix_sync_aligned_m8n16_x4_b8x16_b6x16_p32:
4643 case Intrinsic::nvvm_ldmatrix_sync_aligned_m8n16_x4_s8_s4: {
4644 Info.opc = ISD::INTRINSIC_W_CHAIN;
4645 Info.memVT = MVT::v4i32;
4646 Info.ptrVal = I.getArgOperand(0);
4647 Info.offset = 0;
4648 Info.flags = MachineMemOperand::MOLoad;
4649 Info.align = Align(16);
4650 Infos.push_back(Info);
4651 return;
4652 }
4653
4654 case Intrinsic::nvvm_wmma_m32n8k16_load_b_s8_col:
4655 case Intrinsic::nvvm_wmma_m32n8k16_load_b_s8_col_stride:
4656 case Intrinsic::nvvm_wmma_m32n8k16_load_b_u8_col_stride:
4657 case Intrinsic::nvvm_wmma_m32n8k16_load_b_u8_col:
4658 case Intrinsic::nvvm_wmma_m32n8k16_load_b_s8_row:
4659 case Intrinsic::nvvm_wmma_m32n8k16_load_b_s8_row_stride:
4660 case Intrinsic::nvvm_wmma_m32n8k16_load_b_u8_row_stride:
4661 case Intrinsic::nvvm_wmma_m32n8k16_load_b_u8_row:
4662
4663 case Intrinsic::nvvm_wmma_m8n32k16_load_a_s8_col:
4664 case Intrinsic::nvvm_wmma_m8n32k16_load_a_s8_col_stride:
4665 case Intrinsic::nvvm_wmma_m8n32k16_load_a_u8_col_stride:
4666 case Intrinsic::nvvm_wmma_m8n32k16_load_a_u8_col:
4667 case Intrinsic::nvvm_wmma_m8n32k16_load_a_s8_row:
4668 case Intrinsic::nvvm_wmma_m8n32k16_load_a_s8_row_stride:
4669 case Intrinsic::nvvm_wmma_m8n32k16_load_a_u8_row_stride:
4670 case Intrinsic::nvvm_wmma_m8n32k16_load_a_u8_row:
4671 case Intrinsic::nvvm_wmma_m8n8k128_load_a_b1_row:
4672 case Intrinsic::nvvm_wmma_m8n8k128_load_a_b1_row_stride:
4673 case Intrinsic::nvvm_wmma_m8n8k128_load_b_b1_col:
4674 case Intrinsic::nvvm_wmma_m8n8k128_load_b_b1_col_stride:
4675 case Intrinsic::nvvm_wmma_m8n8k32_load_a_s4_row:
4676 case Intrinsic::nvvm_wmma_m8n8k32_load_a_s4_row_stride:
4677 case Intrinsic::nvvm_wmma_m8n8k32_load_a_u4_row_stride:
4678 case Intrinsic::nvvm_wmma_m8n8k32_load_a_u4_row:
4679 case Intrinsic::nvvm_wmma_m8n8k32_load_b_s4_col:
4680 case Intrinsic::nvvm_wmma_m8n8k32_load_b_s4_col_stride:
4681 case Intrinsic::nvvm_wmma_m8n8k32_load_b_u4_col_stride:
4682 case Intrinsic::nvvm_wmma_m8n8k32_load_b_u4_col:
4683 case Intrinsic::nvvm_ldmatrix_sync_aligned_m8n8_x1_b16:
4684 case Intrinsic::nvvm_ldmatrix_sync_aligned_m8n8_x1_trans_b16:
4685 case Intrinsic::nvvm_ldmatrix_sync_aligned_m8n16_x1_b8x16_b4x16_p64:
4686 case Intrinsic::nvvm_ldmatrix_sync_aligned_m8n16_x1_b8x16_b6x16_p32:
4687 case Intrinsic::nvvm_ldmatrix_sync_aligned_m8n16_x1_s8_s4: {
4688 Info.opc = ISD::INTRINSIC_W_CHAIN;
4689 Info.memVT = MVT::i32;
4690 Info.ptrVal = I.getArgOperand(0);
4691 Info.offset = 0;
4692 Info.flags = MachineMemOperand::MOLoad;
4693 Info.align = Align(4);
4694 Infos.push_back(Info);
4695 return;
4696 }
4697
4698 case Intrinsic::nvvm_wmma_m16n16k16_load_c_f16_col:
4699 case Intrinsic::nvvm_wmma_m16n16k16_load_c_f16_row:
4700 case Intrinsic::nvvm_wmma_m16n16k16_load_c_f16_col_stride:
4701 case Intrinsic::nvvm_wmma_m16n16k16_load_c_f16_row_stride:
4702 case Intrinsic::nvvm_wmma_m32n8k16_load_c_f16_col:
4703 case Intrinsic::nvvm_wmma_m32n8k16_load_c_f16_row:
4704 case Intrinsic::nvvm_wmma_m32n8k16_load_c_f16_col_stride:
4705 case Intrinsic::nvvm_wmma_m32n8k16_load_c_f16_row_stride:
4706 case Intrinsic::nvvm_wmma_m8n32k16_load_c_f16_col:
4707 case Intrinsic::nvvm_wmma_m8n32k16_load_c_f16_row:
4708 case Intrinsic::nvvm_wmma_m8n32k16_load_c_f16_col_stride:
4709 case Intrinsic::nvvm_wmma_m8n32k16_load_c_f16_row_stride: {
4710 Info.opc = ISD::INTRINSIC_W_CHAIN;
4711 Info.memVT = MVT::v4f16;
4712 Info.ptrVal = I.getArgOperand(0);
4713 Info.offset = 0;
4714 Info.flags = MachineMemOperand::MOLoad;
4715 Info.align = Align(16);
4716 Infos.push_back(Info);
4717 return;
4718 }
4719
4720 case Intrinsic::nvvm_wmma_m16n16k16_load_c_f32_col:
4721 case Intrinsic::nvvm_wmma_m16n16k16_load_c_f32_row:
4722 case Intrinsic::nvvm_wmma_m16n16k16_load_c_f32_col_stride:
4723 case Intrinsic::nvvm_wmma_m16n16k16_load_c_f32_row_stride:
4724 case Intrinsic::nvvm_wmma_m32n8k16_load_c_f32_col:
4725 case Intrinsic::nvvm_wmma_m32n8k16_load_c_f32_row:
4726 case Intrinsic::nvvm_wmma_m32n8k16_load_c_f32_col_stride:
4727 case Intrinsic::nvvm_wmma_m32n8k16_load_c_f32_row_stride:
4728 case Intrinsic::nvvm_wmma_m8n32k16_load_c_f32_col:
4729 case Intrinsic::nvvm_wmma_m8n32k16_load_c_f32_row:
4730 case Intrinsic::nvvm_wmma_m8n32k16_load_c_f32_col_stride:
4731 case Intrinsic::nvvm_wmma_m8n32k16_load_c_f32_row_stride:
4732 case Intrinsic::nvvm_wmma_m16n16k8_load_c_f32_col:
4733 case Intrinsic::nvvm_wmma_m16n16k8_load_c_f32_row:
4734 case Intrinsic::nvvm_wmma_m16n16k8_load_c_f32_col_stride:
4735 case Intrinsic::nvvm_wmma_m16n16k8_load_c_f32_row_stride: {
4736 Info.opc = ISD::INTRINSIC_W_CHAIN;
4737 Info.memVT = MVT::v8f32;
4738 Info.ptrVal = I.getArgOperand(0);
4739 Info.offset = 0;
4740 Info.flags = MachineMemOperand::MOLoad;
4741 Info.align = Align(16);
4742 Infos.push_back(Info);
4743 return;
4744 }
4745
4746 case Intrinsic::nvvm_wmma_m32n8k16_load_a_bf16_col:
4747 case Intrinsic::nvvm_wmma_m32n8k16_load_a_bf16_col_stride:
4748 case Intrinsic::nvvm_wmma_m32n8k16_load_a_bf16_row:
4749 case Intrinsic::nvvm_wmma_m32n8k16_load_a_bf16_row_stride:
4750
4751 case Intrinsic::nvvm_wmma_m8n32k16_load_b_bf16_col:
4752 case Intrinsic::nvvm_wmma_m8n32k16_load_b_bf16_col_stride:
4753 case Intrinsic::nvvm_wmma_m8n32k16_load_b_bf16_row:
4754 case Intrinsic::nvvm_wmma_m8n32k16_load_b_bf16_row_stride:
4755
4756 case Intrinsic::nvvm_wmma_m16n16k16_load_c_s32_col:
4757 case Intrinsic::nvvm_wmma_m16n16k16_load_c_s32_col_stride:
4758 case Intrinsic::nvvm_wmma_m16n16k16_load_c_s32_row:
4759 case Intrinsic::nvvm_wmma_m16n16k16_load_c_s32_row_stride:
4760 case Intrinsic::nvvm_wmma_m32n8k16_load_c_s32_col:
4761 case Intrinsic::nvvm_wmma_m32n8k16_load_c_s32_col_stride:
4762 case Intrinsic::nvvm_wmma_m32n8k16_load_c_s32_row:
4763 case Intrinsic::nvvm_wmma_m32n8k16_load_c_s32_row_stride:
4764 case Intrinsic::nvvm_wmma_m8n32k16_load_c_s32_col:
4765 case Intrinsic::nvvm_wmma_m8n32k16_load_c_s32_col_stride:
4766 case Intrinsic::nvvm_wmma_m8n32k16_load_c_s32_row:
4767 case Intrinsic::nvvm_wmma_m8n32k16_load_c_s32_row_stride: {
4768 Info.opc = ISD::INTRINSIC_W_CHAIN;
4769 Info.memVT = MVT::v8i32;
4770 Info.ptrVal = I.getArgOperand(0);
4771 Info.offset = 0;
4772 Info.flags = MachineMemOperand::MOLoad;
4773 Info.align = Align(16);
4774 Infos.push_back(Info);
4775 return;
4776 }
4777
4778 case Intrinsic::nvvm_wmma_m8n8k128_load_c_s32_col:
4779 case Intrinsic::nvvm_wmma_m8n8k128_load_c_s32_col_stride:
4780 case Intrinsic::nvvm_wmma_m8n8k128_load_c_s32_row:
4781 case Intrinsic::nvvm_wmma_m8n8k128_load_c_s32_row_stride:
4782 case Intrinsic::nvvm_wmma_m8n8k32_load_c_s32_col:
4783 case Intrinsic::nvvm_wmma_m8n8k32_load_c_s32_col_stride:
4784 case Intrinsic::nvvm_wmma_m8n8k32_load_c_s32_row:
4785 case Intrinsic::nvvm_wmma_m8n8k32_load_c_s32_row_stride:
4786 case Intrinsic::nvvm_ldmatrix_sync_aligned_m8n8_x2_b16:
4787 case Intrinsic::nvvm_ldmatrix_sync_aligned_m8n8_x2_trans_b16:
4788 case Intrinsic::nvvm_ldmatrix_sync_aligned_m16n16_x1_trans_b8:
4789 case Intrinsic::nvvm_ldmatrix_sync_aligned_m16n16_x1_trans_b8x16_b4x16_p64:
4790 case Intrinsic::nvvm_ldmatrix_sync_aligned_m16n16_x1_trans_b8x16_b6x16_p32:
4791 case Intrinsic::nvvm_ldmatrix_sync_aligned_m8n16_x2_b8x16_b4x16_p64:
4792 case Intrinsic::nvvm_ldmatrix_sync_aligned_m8n16_x2_b8x16_b6x16_p32:
4793 case Intrinsic::nvvm_ldmatrix_sync_aligned_m8n16_x2_s8_s4: {
4794 Info.opc = ISD::INTRINSIC_W_CHAIN;
4795 Info.memVT = MVT::v2i32;
4796 Info.ptrVal = I.getArgOperand(0);
4797 Info.offset = 0;
4798 Info.flags = MachineMemOperand::MOLoad;
4799 Info.align = Align(8);
4800 Infos.push_back(Info);
4801 return;
4802 }
4803
4804 case Intrinsic::nvvm_wmma_m8n8k4_load_a_f64_col:
4805 case Intrinsic::nvvm_wmma_m8n8k4_load_a_f64_col_stride:
4806 case Intrinsic::nvvm_wmma_m8n8k4_load_a_f64_row:
4807 case Intrinsic::nvvm_wmma_m8n8k4_load_a_f64_row_stride:
4808
4809 case Intrinsic::nvvm_wmma_m8n8k4_load_b_f64_col:
4810 case Intrinsic::nvvm_wmma_m8n8k4_load_b_f64_col_stride:
4811 case Intrinsic::nvvm_wmma_m8n8k4_load_b_f64_row:
4812 case Intrinsic::nvvm_wmma_m8n8k4_load_b_f64_row_stride: {
4813 Info.opc = ISD::INTRINSIC_W_CHAIN;
4814 Info.memVT = MVT::f64;
4815 Info.ptrVal = I.getArgOperand(0);
4816 Info.offset = 0;
4817 Info.flags = MachineMemOperand::MOLoad;
4818 Info.align = Align(8);
4819 Infos.push_back(Info);
4820 return;
4821 }
4822
4823 case Intrinsic::nvvm_wmma_m8n8k4_load_c_f64_col:
4824 case Intrinsic::nvvm_wmma_m8n8k4_load_c_f64_col_stride:
4825 case Intrinsic::nvvm_wmma_m8n8k4_load_c_f64_row:
4826 case Intrinsic::nvvm_wmma_m8n8k4_load_c_f64_row_stride: {
4827 Info.opc = ISD::INTRINSIC_W_CHAIN;
4828 Info.memVT = MVT::v2f64;
4829 Info.ptrVal = I.getArgOperand(0);
4830 Info.offset = 0;
4831 Info.flags = MachineMemOperand::MOLoad;
4832 Info.align = Align(16);
4833 Infos.push_back(Info);
4834 return;
4835 }
4836
4837 case Intrinsic::nvvm_wmma_m16n16k16_store_d_f16_col:
4838 case Intrinsic::nvvm_wmma_m16n16k16_store_d_f16_row:
4839 case Intrinsic::nvvm_wmma_m16n16k16_store_d_f16_col_stride:
4840 case Intrinsic::nvvm_wmma_m16n16k16_store_d_f16_row_stride:
4841 case Intrinsic::nvvm_wmma_m32n8k16_store_d_f16_col:
4842 case Intrinsic::nvvm_wmma_m32n8k16_store_d_f16_row:
4843 case Intrinsic::nvvm_wmma_m32n8k16_store_d_f16_col_stride:
4844 case Intrinsic::nvvm_wmma_m32n8k16_store_d_f16_row_stride:
4845 case Intrinsic::nvvm_wmma_m8n32k16_store_d_f16_col:
4846 case Intrinsic::nvvm_wmma_m8n32k16_store_d_f16_row:
4847 case Intrinsic::nvvm_wmma_m8n32k16_store_d_f16_col_stride:
4848 case Intrinsic::nvvm_wmma_m8n32k16_store_d_f16_row_stride: {
4849 Info.opc = ISD::INTRINSIC_VOID;
4850 Info.memVT = MVT::v4f16;
4851 Info.ptrVal = I.getArgOperand(0);
4852 Info.offset = 0;
4853 Info.flags = MachineMemOperand::MOStore;
4854 Info.align = Align(16);
4855 Infos.push_back(Info);
4856 return;
4857 }
4858
4859 case Intrinsic::nvvm_wmma_m16n16k16_store_d_f32_col:
4860 case Intrinsic::nvvm_wmma_m16n16k16_store_d_f32_row:
4861 case Intrinsic::nvvm_wmma_m16n16k16_store_d_f32_col_stride:
4862 case Intrinsic::nvvm_wmma_m16n16k16_store_d_f32_row_stride:
4863 case Intrinsic::nvvm_wmma_m32n8k16_store_d_f32_col:
4864 case Intrinsic::nvvm_wmma_m32n8k16_store_d_f32_row:
4865 case Intrinsic::nvvm_wmma_m32n8k16_store_d_f32_col_stride:
4866 case Intrinsic::nvvm_wmma_m32n8k16_store_d_f32_row_stride:
4867 case Intrinsic::nvvm_wmma_m8n32k16_store_d_f32_col:
4868 case Intrinsic::nvvm_wmma_m8n32k16_store_d_f32_row:
4869 case Intrinsic::nvvm_wmma_m8n32k16_store_d_f32_col_stride:
4870 case Intrinsic::nvvm_wmma_m8n32k16_store_d_f32_row_stride:
4871 case Intrinsic::nvvm_wmma_m16n16k8_store_d_f32_col:
4872 case Intrinsic::nvvm_wmma_m16n16k8_store_d_f32_row:
4873 case Intrinsic::nvvm_wmma_m16n16k8_store_d_f32_col_stride:
4874 case Intrinsic::nvvm_wmma_m16n16k8_store_d_f32_row_stride: {
4875 Info.opc = ISD::INTRINSIC_VOID;
4876 Info.memVT = MVT::v8f32;
4877 Info.ptrVal = I.getArgOperand(0);
4878 Info.offset = 0;
4879 Info.flags = MachineMemOperand::MOStore;
4880 Info.align = Align(16);
4881 Infos.push_back(Info);
4882 return;
4883 }
4884
4885 case Intrinsic::nvvm_wmma_m16n16k16_store_d_s32_col:
4886 case Intrinsic::nvvm_wmma_m16n16k16_store_d_s32_col_stride:
4887 case Intrinsic::nvvm_wmma_m16n16k16_store_d_s32_row:
4888 case Intrinsic::nvvm_wmma_m16n16k16_store_d_s32_row_stride:
4889 case Intrinsic::nvvm_wmma_m32n8k16_store_d_s32_col:
4890 case Intrinsic::nvvm_wmma_m32n8k16_store_d_s32_col_stride:
4891 case Intrinsic::nvvm_wmma_m32n8k16_store_d_s32_row:
4892 case Intrinsic::nvvm_wmma_m32n8k16_store_d_s32_row_stride:
4893 case Intrinsic::nvvm_wmma_m8n32k16_store_d_s32_col:
4894 case Intrinsic::nvvm_wmma_m8n32k16_store_d_s32_col_stride:
4895 case Intrinsic::nvvm_wmma_m8n32k16_store_d_s32_row:
4896 case Intrinsic::nvvm_wmma_m8n32k16_store_d_s32_row_stride: {
4897 Info.opc = ISD::INTRINSIC_VOID;
4898 Info.memVT = MVT::v8i32;
4899 Info.ptrVal = I.getArgOperand(0);
4900 Info.offset = 0;
4901 Info.flags = MachineMemOperand::MOStore;
4902 Info.align = Align(16);
4903 Infos.push_back(Info);
4904 return;
4905 }
4906
4907 case Intrinsic::nvvm_wmma_m8n8k128_store_d_s32_col:
4908 case Intrinsic::nvvm_wmma_m8n8k128_store_d_s32_col_stride:
4909 case Intrinsic::nvvm_wmma_m8n8k128_store_d_s32_row:
4910 case Intrinsic::nvvm_wmma_m8n8k128_store_d_s32_row_stride:
4911 case Intrinsic::nvvm_wmma_m8n8k32_store_d_s32_col:
4912 case Intrinsic::nvvm_wmma_m8n8k32_store_d_s32_col_stride:
4913 case Intrinsic::nvvm_wmma_m8n8k32_store_d_s32_row:
4914 case Intrinsic::nvvm_wmma_m8n8k32_store_d_s32_row_stride:
4915 case Intrinsic::nvvm_stmatrix_sync_aligned_m8n8_x2_b16:
4916 case Intrinsic::nvvm_stmatrix_sync_aligned_m8n8_x2_trans_b16:
4917 case Intrinsic::nvvm_stmatrix_sync_aligned_m16n8_x2_trans_b8: {
4918 Info.opc = ISD::INTRINSIC_VOID;
4919 Info.memVT = MVT::v2i32;
4920 Info.ptrVal = I.getArgOperand(0);
4921 Info.offset = 0;
4922 Info.flags = MachineMemOperand::MOStore;
4923 Info.align = Align(8);
4924 Infos.push_back(Info);
4925 return;
4926 }
4927
4928 case Intrinsic::nvvm_wmma_m8n8k4_store_d_f64_col:
4929 case Intrinsic::nvvm_wmma_m8n8k4_store_d_f64_col_stride:
4930 case Intrinsic::nvvm_wmma_m8n8k4_store_d_f64_row:
4931 case Intrinsic::nvvm_wmma_m8n8k4_store_d_f64_row_stride: {
4932 Info.opc = ISD::INTRINSIC_VOID;
4933 Info.memVT = MVT::v2f64;
4934 Info.ptrVal = I.getArgOperand(0);
4935 Info.offset = 0;
4936 Info.flags = MachineMemOperand::MOStore;
4937 Info.align = Align(16);
4938 Infos.push_back(Info);
4939 return;
4940 }
4941
4942 case Intrinsic::nvvm_stmatrix_sync_aligned_m8n8_x1_b16:
4943 case Intrinsic::nvvm_stmatrix_sync_aligned_m8n8_x1_trans_b16:
4944 case Intrinsic::nvvm_stmatrix_sync_aligned_m16n8_x1_trans_b8: {
4945 Info.opc = ISD::INTRINSIC_VOID;
4946 Info.memVT = MVT::i32;
4947 Info.ptrVal = I.getArgOperand(0);
4948 Info.offset = 0;
4949 Info.flags = MachineMemOperand::MOStore;
4950 Info.align = Align(4);
4951 Infos.push_back(Info);
4952 return;
4953 }
4954
4955 case Intrinsic::nvvm_stmatrix_sync_aligned_m8n8_x4_b16:
4956 case Intrinsic::nvvm_stmatrix_sync_aligned_m8n8_x4_trans_b16:
4957 case Intrinsic::nvvm_stmatrix_sync_aligned_m16n8_x4_trans_b8: {
4958 Info.opc = ISD::INTRINSIC_VOID;
4959 Info.memVT = MVT::v4i32;
4960 Info.ptrVal = I.getArgOperand(0);
4961 Info.offset = 0;
4962 Info.flags = MachineMemOperand::MOStore;
4963 Info.align = Align(16);
4964 Infos.push_back(Info);
4965 return;
4966 }
4967
4968 case Intrinsic::nvvm_st_bulk: {
4969 Value *Dst = I.getArgOperand(0);
4970 Value *Val = I.getArgOperand(2);
4971 Info.opc = ISD::INTRINSIC_VOID;
4972 Info.memVT = MVT::getVT(Val->getType());
4973 Info.ptrVal = Dst;
4974 Info.offset = 0;
4975 Info.flags = MachineMemOperand::MOStore;
4976 Info.align.reset();
4977 Info.size = MemoryLocation::UnknownSize;
4978 Infos.push_back(Info);
4979 return;
4980 }
4981
4982 case Intrinsic::nvvm_prefetch_tensormap: {
4983 auto &DL = I.getDataLayout();
4984 Info.opc = ISD::INTRINSIC_VOID;
4985 Info.memVT = getPointerTy(DL);
4986 Info.ptrVal = I.getArgOperand(0);
4987 Info.offset = 0;
4988 Info.flags =
4990 Info.align.reset();
4991 Infos.push_back(Info);
4992 return;
4993 }
4994
4995 case Intrinsic::nvvm_prefetch_L1_32B_valid_addr: {
4996 Info.opc = ISD::INTRINSIC_VOID;
4997 Info.memVT = MVT::i8;
4998 Info.ptrVal = I.getArgOperand(0);
4999 Info.offset = 0;
5000 Info.flags = MachineMemOperand::MOLoad;
5001 Info.align = Align(1);
5002 Infos.push_back(Info);
5003 return;
5004 }
5005
5006 case Intrinsic::nvvm_mbarrier_init: {
5007 Info.opc = ISD::INTRINSIC_VOID;
5008 Info.memVT = MVT::i64;
5009 Info.ptrVal = I.getArgOperand(0);
5010 Info.offset = 0;
5011 Info.flags = MachineMemOperand::MOStore;
5012 Info.align = Align(8);
5013 Infos.push_back(Info);
5014 return;
5015 }
5016
5017 case Intrinsic::nvvm_mbarrier_check_layout: {
5018 Info.opc = ISD::INTRINSIC_W_CHAIN;
5019 Info.memVT = MVT::i64;
5020 Info.ptrVal = I.getArgOperand(0);
5021 Info.offset = 0;
5022 Info.flags = MachineMemOperand::MOLoad;
5023 Info.align = Align(8);
5024 Infos.push_back(Info);
5025 return;
5026 }
5027
5028 case Intrinsic::nvvm_tensormap_replace_global_address:
5029 case Intrinsic::nvvm_tensormap_replace_global_stride: {
5030 Info.opc = ISD::INTRINSIC_VOID;
5031 Info.memVT = MVT::i64;
5032 Info.ptrVal = I.getArgOperand(0);
5033 Info.offset = 0;
5034 Info.flags = MachineMemOperand::MOStore;
5035 Info.align.reset();
5036 Infos.push_back(Info);
5037 return;
5038 }
5039
5040 case Intrinsic::nvvm_tensormap_replace_rank:
5041 case Intrinsic::nvvm_tensormap_replace_box_dim:
5042 case Intrinsic::nvvm_tensormap_replace_global_dim:
5043 case Intrinsic::nvvm_tensormap_replace_element_stride:
5044 case Intrinsic::nvvm_tensormap_replace_elemtype:
5045 case Intrinsic::nvvm_tensormap_replace_interleave_layout:
5046 case Intrinsic::nvvm_tensormap_replace_swizzle_mode:
5047 case Intrinsic::nvvm_tensormap_replace_swizzle_atomicity:
5048 case Intrinsic::nvvm_tensormap_replace_fill_mode: {
5049 Info.opc = ISD::INTRINSIC_VOID;
5050 Info.memVT = MVT::i32;
5051 Info.ptrVal = I.getArgOperand(0);
5052 Info.offset = 0;
5053 Info.flags = MachineMemOperand::MOStore;
5054 Info.align.reset();
5055 Infos.push_back(Info);
5056 return;
5057 }
5058
5059 case Intrinsic::nvvm_ldu_global_i:
5060 case Intrinsic::nvvm_ldu_global_f:
5061 case Intrinsic::nvvm_ldu_global_p: {
5062 Info.opc = ISD::INTRINSIC_W_CHAIN;
5063 Info.memVT = getValueType(I.getDataLayout(), I.getType());
5064 Info.ptrVal = I.getArgOperand(0);
5065 Info.offset = 0;
5066 Info.flags = MachineMemOperand::MOLoad;
5067 Info.align = cast<ConstantInt>(I.getArgOperand(1))->getMaybeAlignValue();
5068
5069 Infos.push_back(Info);
5070 return;
5071 }
5072 case Intrinsic::nvvm_tex_1d_v4f32_s32:
5073 case Intrinsic::nvvm_tex_1d_v4f32_f32:
5074 case Intrinsic::nvvm_tex_1d_level_v4f32_f32:
5075 case Intrinsic::nvvm_tex_1d_grad_v4f32_f32:
5076 case Intrinsic::nvvm_tex_1d_array_v4f32_s32:
5077 case Intrinsic::nvvm_tex_1d_array_v4f32_f32:
5078 case Intrinsic::nvvm_tex_1d_array_level_v4f32_f32:
5079 case Intrinsic::nvvm_tex_1d_array_grad_v4f32_f32:
5080 case Intrinsic::nvvm_tex_2d_v4f32_s32:
5081 case Intrinsic::nvvm_tex_2d_v4f32_f32:
5082 case Intrinsic::nvvm_tex_2d_level_v4f32_f32:
5083 case Intrinsic::nvvm_tex_2d_grad_v4f32_f32:
5084 case Intrinsic::nvvm_tex_2d_array_v4f32_s32:
5085 case Intrinsic::nvvm_tex_2d_array_v4f32_f32:
5086 case Intrinsic::nvvm_tex_2d_array_level_v4f32_f32:
5087 case Intrinsic::nvvm_tex_2d_array_grad_v4f32_f32:
5088 case Intrinsic::nvvm_tex_3d_v4f32_s32:
5089 case Intrinsic::nvvm_tex_3d_v4f32_f32:
5090 case Intrinsic::nvvm_tex_3d_level_v4f32_f32:
5091 case Intrinsic::nvvm_tex_3d_grad_v4f32_f32:
5092 case Intrinsic::nvvm_tex_cube_v4f32_f32:
5093 case Intrinsic::nvvm_tex_cube_level_v4f32_f32:
5094 case Intrinsic::nvvm_tex_cube_array_v4f32_f32:
5095 case Intrinsic::nvvm_tex_cube_array_level_v4f32_f32:
5096 case Intrinsic::nvvm_tld4_r_2d_v4f32_f32:
5097 case Intrinsic::nvvm_tld4_g_2d_v4f32_f32:
5098 case Intrinsic::nvvm_tld4_b_2d_v4f32_f32:
5099 case Intrinsic::nvvm_tld4_a_2d_v4f32_f32:
5100 case Intrinsic::nvvm_tex_unified_1d_v4f32_s32:
5101 case Intrinsic::nvvm_tex_unified_1d_v4f32_f32:
5102 case Intrinsic::nvvm_tex_unified_1d_level_v4f32_f32:
5103 case Intrinsic::nvvm_tex_unified_1d_grad_v4f32_f32:
5104 case Intrinsic::nvvm_tex_unified_1d_array_v4f32_s32:
5105 case Intrinsic::nvvm_tex_unified_1d_array_v4f32_f32:
5106 case Intrinsic::nvvm_tex_unified_1d_array_level_v4f32_f32:
5107 case Intrinsic::nvvm_tex_unified_1d_array_grad_v4f32_f32:
5108 case Intrinsic::nvvm_tex_unified_2d_v4f32_s32:
5109 case Intrinsic::nvvm_tex_unified_2d_v4f32_f32:
5110 case Intrinsic::nvvm_tex_unified_2d_level_v4f32_f32:
5111 case Intrinsic::nvvm_tex_unified_2d_grad_v4f32_f32:
5112 case Intrinsic::nvvm_tex_unified_2d_array_v4f32_s32:
5113 case Intrinsic::nvvm_tex_unified_2d_array_v4f32_f32:
5114 case Intrinsic::nvvm_tex_unified_2d_array_level_v4f32_f32:
5115 case Intrinsic::nvvm_tex_unified_2d_array_grad_v4f32_f32:
5116 case Intrinsic::nvvm_tex_unified_3d_v4f32_s32:
5117 case Intrinsic::nvvm_tex_unified_3d_v4f32_f32:
5118 case Intrinsic::nvvm_tex_unified_3d_level_v4f32_f32:
5119 case Intrinsic::nvvm_tex_unified_3d_grad_v4f32_f32:
5120 case Intrinsic::nvvm_tex_unified_cube_v4f32_f32:
5121 case Intrinsic::nvvm_tex_unified_cube_level_v4f32_f32:
5122 case Intrinsic::nvvm_tex_unified_cube_array_v4f32_f32:
5123 case Intrinsic::nvvm_tex_unified_cube_array_level_v4f32_f32:
5124 case Intrinsic::nvvm_tex_unified_cube_grad_v4f32_f32:
5125 case Intrinsic::nvvm_tex_unified_cube_array_grad_v4f32_f32:
5126 case Intrinsic::nvvm_tld4_unified_r_2d_v4f32_f32:
5127 case Intrinsic::nvvm_tld4_unified_g_2d_v4f32_f32:
5128 case Intrinsic::nvvm_tld4_unified_b_2d_v4f32_f32:
5129 case Intrinsic::nvvm_tld4_unified_a_2d_v4f32_f32:
5130 Info.opc = ISD::INTRINSIC_W_CHAIN;
5131 Info.memVT = MVT::v4f32;
5132 Info.ptrVal = nullptr;
5133 Info.offset = 0;
5134 Info.flags = MachineMemOperand::MOLoad;
5135 Info.align = Align(16);
5136 Infos.push_back(Info);
5137 return;
5138
5139 case Intrinsic::nvvm_tex_1d_v4s32_s32:
5140 case Intrinsic::nvvm_tex_1d_v4s32_f32:
5141 case Intrinsic::nvvm_tex_1d_level_v4s32_f32:
5142 case Intrinsic::nvvm_tex_1d_grad_v4s32_f32:
5143 case Intrinsic::nvvm_tex_1d_array_v4s32_s32:
5144 case Intrinsic::nvvm_tex_1d_array_v4s32_f32:
5145 case Intrinsic::nvvm_tex_1d_array_level_v4s32_f32:
5146 case Intrinsic::nvvm_tex_1d_array_grad_v4s32_f32:
5147 case Intrinsic::nvvm_tex_2d_v4s32_s32:
5148 case Intrinsic::nvvm_tex_2d_v4s32_f32:
5149 case Intrinsic::nvvm_tex_2d_level_v4s32_f32:
5150 case Intrinsic::nvvm_tex_2d_grad_v4s32_f32:
5151 case Intrinsic::nvvm_tex_2d_array_v4s32_s32:
5152 case Intrinsic::nvvm_tex_2d_array_v4s32_f32:
5153 case Intrinsic::nvvm_tex_2d_array_level_v4s32_f32:
5154 case Intrinsic::nvvm_tex_2d_array_grad_v4s32_f32:
5155 case Intrinsic::nvvm_tex_3d_v4s32_s32:
5156 case Intrinsic::nvvm_tex_3d_v4s32_f32:
5157 case Intrinsic::nvvm_tex_3d_level_v4s32_f32:
5158 case Intrinsic::nvvm_tex_3d_grad_v4s32_f32:
5159 case Intrinsic::nvvm_tex_cube_v4s32_f32:
5160 case Intrinsic::nvvm_tex_cube_level_v4s32_f32:
5161 case Intrinsic::nvvm_tex_cube_array_v4s32_f32:
5162 case Intrinsic::nvvm_tex_cube_array_level_v4s32_f32:
5163 case Intrinsic::nvvm_tex_cube_v4u32_f32:
5164 case Intrinsic::nvvm_tex_cube_level_v4u32_f32:
5165 case Intrinsic::nvvm_tex_cube_array_v4u32_f32:
5166 case Intrinsic::nvvm_tex_cube_array_level_v4u32_f32:
5167 case Intrinsic::nvvm_tex_1d_v4u32_s32:
5168 case Intrinsic::nvvm_tex_1d_v4u32_f32:
5169 case Intrinsic::nvvm_tex_1d_level_v4u32_f32:
5170 case Intrinsic::nvvm_tex_1d_grad_v4u32_f32:
5171 case Intrinsic::nvvm_tex_1d_array_v4u32_s32:
5172 case Intrinsic::nvvm_tex_1d_array_v4u32_f32:
5173 case Intrinsic::nvvm_tex_1d_array_level_v4u32_f32:
5174 case Intrinsic::nvvm_tex_1d_array_grad_v4u32_f32:
5175 case Intrinsic::nvvm_tex_2d_v4u32_s32:
5176 case Intrinsic::nvvm_tex_2d_v4u32_f32:
5177 case Intrinsic::nvvm_tex_2d_level_v4u32_f32:
5178 case Intrinsic::nvvm_tex_2d_grad_v4u32_f32:
5179 case Intrinsic::nvvm_tex_2d_array_v4u32_s32:
5180 case Intrinsic::nvvm_tex_2d_array_v4u32_f32:
5181 case Intrinsic::nvvm_tex_2d_array_level_v4u32_f32:
5182 case Intrinsic::nvvm_tex_2d_array_grad_v4u32_f32:
5183 case Intrinsic::nvvm_tex_3d_v4u32_s32:
5184 case Intrinsic::nvvm_tex_3d_v4u32_f32:
5185 case Intrinsic::nvvm_tex_3d_level_v4u32_f32:
5186 case Intrinsic::nvvm_tex_3d_grad_v4u32_f32:
5187 case Intrinsic::nvvm_tld4_r_2d_v4s32_f32:
5188 case Intrinsic::nvvm_tld4_g_2d_v4s32_f32:
5189 case Intrinsic::nvvm_tld4_b_2d_v4s32_f32:
5190 case Intrinsic::nvvm_tld4_a_2d_v4s32_f32:
5191 case Intrinsic::nvvm_tld4_r_2d_v4u32_f32:
5192 case Intrinsic::nvvm_tld4_g_2d_v4u32_f32:
5193 case Intrinsic::nvvm_tld4_b_2d_v4u32_f32:
5194 case Intrinsic::nvvm_tld4_a_2d_v4u32_f32:
5195 case Intrinsic::nvvm_tex_unified_1d_v4s32_s32:
5196 case Intrinsic::nvvm_tex_unified_1d_v4s32_f32:
5197 case Intrinsic::nvvm_tex_unified_1d_level_v4s32_f32:
5198 case Intrinsic::nvvm_tex_unified_1d_grad_v4s32_f32:
5199 case Intrinsic::nvvm_tex_unified_1d_array_v4s32_s32:
5200 case Intrinsic::nvvm_tex_unified_1d_array_v4s32_f32:
5201 case Intrinsic::nvvm_tex_unified_1d_array_level_v4s32_f32:
5202 case Intrinsic::nvvm_tex_unified_1d_array_grad_v4s32_f32:
5203 case Intrinsic::nvvm_tex_unified_2d_v4s32_s32:
5204 case Intrinsic::nvvm_tex_unified_2d_v4s32_f32:
5205 case Intrinsic::nvvm_tex_unified_2d_level_v4s32_f32:
5206 case Intrinsic::nvvm_tex_unified_2d_grad_v4s32_f32:
5207 case Intrinsic::nvvm_tex_unified_2d_array_v4s32_s32:
5208 case Intrinsic::nvvm_tex_unified_2d_array_v4s32_f32:
5209 case Intrinsic::nvvm_tex_unified_2d_array_level_v4s32_f32:
5210 case Intrinsic::nvvm_tex_unified_2d_array_grad_v4s32_f32:
5211 case Intrinsic::nvvm_tex_unified_3d_v4s32_s32:
5212 case Intrinsic::nvvm_tex_unified_3d_v4s32_f32:
5213 case Intrinsic::nvvm_tex_unified_3d_level_v4s32_f32:
5214 case Intrinsic::nvvm_tex_unified_3d_grad_v4s32_f32:
5215 case Intrinsic::nvvm_tex_unified_1d_v4u32_s32:
5216 case Intrinsic::nvvm_tex_unified_1d_v4u32_f32:
5217 case Intrinsic::nvvm_tex_unified_1d_level_v4u32_f32:
5218 case Intrinsic::nvvm_tex_unified_1d_grad_v4u32_f32:
5219 case Intrinsic::nvvm_tex_unified_1d_array_v4u32_s32:
5220 case Intrinsic::nvvm_tex_unified_1d_array_v4u32_f32:
5221 case Intrinsic::nvvm_tex_unified_1d_array_level_v4u32_f32:
5222 case Intrinsic::nvvm_tex_unified_1d_array_grad_v4u32_f32:
5223 case Intrinsic::nvvm_tex_unified_2d_v4u32_s32:
5224 case Intrinsic::nvvm_tex_unified_2d_v4u32_f32:
5225 case Intrinsic::nvvm_tex_unified_2d_level_v4u32_f32:
5226 case Intrinsic::nvvm_tex_unified_2d_grad_v4u32_f32:
5227 case Intrinsic::nvvm_tex_unified_2d_array_v4u32_s32:
5228 case Intrinsic::nvvm_tex_unified_2d_array_v4u32_f32:
5229 case Intrinsic::nvvm_tex_unified_2d_array_level_v4u32_f32:
5230 case Intrinsic::nvvm_tex_unified_2d_array_grad_v4u32_f32:
5231 case Intrinsic::nvvm_tex_unified_3d_v4u32_s32:
5232 case Intrinsic::nvvm_tex_unified_3d_v4u32_f32:
5233 case Intrinsic::nvvm_tex_unified_3d_level_v4u32_f32:
5234 case Intrinsic::nvvm_tex_unified_3d_grad_v4u32_f32:
5235 case Intrinsic::nvvm_tex_unified_cube_v4s32_f32:
5236 case Intrinsic::nvvm_tex_unified_cube_level_v4s32_f32:
5237 case Intrinsic::nvvm_tex_unified_cube_array_v4s32_f32:
5238 case Intrinsic::nvvm_tex_unified_cube_array_level_v4s32_f32:
5239 case Intrinsic::nvvm_tex_unified_cube_v4u32_f32:
5240 case Intrinsic::nvvm_tex_unified_cube_level_v4u32_f32:
5241 case Intrinsic::nvvm_tex_unified_cube_array_v4u32_f32:
5242 case Intrinsic::nvvm_tex_unified_cube_array_level_v4u32_f32:
5243 case Intrinsic::nvvm_tex_unified_cube_grad_v4s32_f32:
5244 case Intrinsic::nvvm_tex_unified_cube_grad_v4u32_f32:
5245 case Intrinsic::nvvm_tex_unified_cube_array_grad_v4s32_f32:
5246 case Intrinsic::nvvm_tex_unified_cube_array_grad_v4u32_f32:
5247 case Intrinsic::nvvm_tld4_unified_r_2d_v4s32_f32:
5248 case Intrinsic::nvvm_tld4_unified_g_2d_v4s32_f32:
5249 case Intrinsic::nvvm_tld4_unified_b_2d_v4s32_f32:
5250 case Intrinsic::nvvm_tld4_unified_a_2d_v4s32_f32:
5251 case Intrinsic::nvvm_tld4_unified_r_2d_v4u32_f32:
5252 case Intrinsic::nvvm_tld4_unified_g_2d_v4u32_f32:
5253 case Intrinsic::nvvm_tld4_unified_b_2d_v4u32_f32:
5254 case Intrinsic::nvvm_tld4_unified_a_2d_v4u32_f32:
5255 Info.opc = ISD::INTRINSIC_W_CHAIN;
5256 Info.memVT = MVT::v4i32;
5257 Info.ptrVal = nullptr;
5258 Info.offset = 0;
5259 Info.flags = MachineMemOperand::MOLoad;
5260 Info.align = Align(16);
5261 Infos.push_back(Info);
5262 return;
5263
5264 case Intrinsic::nvvm_suld_1d_i8_clamp:
5265 case Intrinsic::nvvm_suld_1d_v2i8_clamp:
5266 case Intrinsic::nvvm_suld_1d_v4i8_clamp:
5267 case Intrinsic::nvvm_suld_1d_array_i8_clamp:
5268 case Intrinsic::nvvm_suld_1d_array_v2i8_clamp:
5269 case Intrinsic::nvvm_suld_1d_array_v4i8_clamp:
5270 case Intrinsic::nvvm_suld_2d_i8_clamp:
5271 case Intrinsic::nvvm_suld_2d_v2i8_clamp:
5272 case Intrinsic::nvvm_suld_2d_v4i8_clamp:
5273 case Intrinsic::nvvm_suld_2d_array_i8_clamp:
5274 case Intrinsic::nvvm_suld_2d_array_v2i8_clamp:
5275 case Intrinsic::nvvm_suld_2d_array_v4i8_clamp:
5276 case Intrinsic::nvvm_suld_3d_i8_clamp:
5277 case Intrinsic::nvvm_suld_3d_v2i8_clamp:
5278 case Intrinsic::nvvm_suld_3d_v4i8_clamp:
5279 case Intrinsic::nvvm_suld_1d_i8_trap:
5280 case Intrinsic::nvvm_suld_1d_v2i8_trap:
5281 case Intrinsic::nvvm_suld_1d_v4i8_trap:
5282 case Intrinsic::nvvm_suld_1d_array_i8_trap:
5283 case Intrinsic::nvvm_suld_1d_array_v2i8_trap:
5284 case Intrinsic::nvvm_suld_1d_array_v4i8_trap:
5285 case Intrinsic::nvvm_suld_2d_i8_trap:
5286 case Intrinsic::nvvm_suld_2d_v2i8_trap:
5287 case Intrinsic::nvvm_suld_2d_v4i8_trap:
5288 case Intrinsic::nvvm_suld_2d_array_i8_trap:
5289 case Intrinsic::nvvm_suld_2d_array_v2i8_trap:
5290 case Intrinsic::nvvm_suld_2d_array_v4i8_trap:
5291 case Intrinsic::nvvm_suld_3d_i8_trap:
5292 case Intrinsic::nvvm_suld_3d_v2i8_trap:
5293 case Intrinsic::nvvm_suld_3d_v4i8_trap:
5294 case Intrinsic::nvvm_suld_1d_i8_zero:
5295 case Intrinsic::nvvm_suld_1d_v2i8_zero:
5296 case Intrinsic::nvvm_suld_1d_v4i8_zero:
5297 case Intrinsic::nvvm_suld_1d_array_i8_zero:
5298 case Intrinsic::nvvm_suld_1d_array_v2i8_zero:
5299 case Intrinsic::nvvm_suld_1d_array_v4i8_zero:
5300 case Intrinsic::nvvm_suld_2d_i8_zero:
5301 case Intrinsic::nvvm_suld_2d_v2i8_zero:
5302 case Intrinsic::nvvm_suld_2d_v4i8_zero:
5303 case Intrinsic::nvvm_suld_2d_array_i8_zero:
5304 case Intrinsic::nvvm_suld_2d_array_v2i8_zero:
5305 case Intrinsic::nvvm_suld_2d_array_v4i8_zero:
5306 case Intrinsic::nvvm_suld_3d_i8_zero:
5307 case Intrinsic::nvvm_suld_3d_v2i8_zero:
5308 case Intrinsic::nvvm_suld_3d_v4i8_zero:
5309 Info.opc = ISD::INTRINSIC_W_CHAIN;
5310 Info.memVT = MVT::i8;
5311 Info.ptrVal = nullptr;
5312 Info.offset = 0;
5313 Info.flags = MachineMemOperand::MOLoad;
5314 Info.align = Align(16);
5315 Infos.push_back(Info);
5316 return;
5317
5318 case Intrinsic::nvvm_suld_1d_i16_clamp:
5319 case Intrinsic::nvvm_suld_1d_v2i16_clamp:
5320 case Intrinsic::nvvm_suld_1d_v4i16_clamp:
5321 case Intrinsic::nvvm_suld_1d_array_i16_clamp:
5322 case Intrinsic::nvvm_suld_1d_array_v2i16_clamp:
5323 case Intrinsic::nvvm_suld_1d_array_v4i16_clamp:
5324 case Intrinsic::nvvm_suld_2d_i16_clamp:
5325 case Intrinsic::nvvm_suld_2d_v2i16_clamp:
5326 case Intrinsic::nvvm_suld_2d_v4i16_clamp:
5327 case Intrinsic::nvvm_suld_2d_array_i16_clamp:
5328 case Intrinsic::nvvm_suld_2d_array_v2i16_clamp:
5329 case Intrinsic::nvvm_suld_2d_array_v4i16_clamp:
5330 case Intrinsic::nvvm_suld_3d_i16_clamp:
5331 case Intrinsic::nvvm_suld_3d_v2i16_clamp:
5332 case Intrinsic::nvvm_suld_3d_v4i16_clamp:
5333 case Intrinsic::nvvm_suld_1d_i16_trap:
5334 case Intrinsic::nvvm_suld_1d_v2i16_trap:
5335 case Intrinsic::nvvm_suld_1d_v4i16_trap:
5336 case Intrinsic::nvvm_suld_1d_array_i16_trap:
5337 case Intrinsic::nvvm_suld_1d_array_v2i16_trap:
5338 case Intrinsic::nvvm_suld_1d_array_v4i16_trap:
5339 case Intrinsic::nvvm_suld_2d_i16_trap:
5340 case Intrinsic::nvvm_suld_2d_v2i16_trap:
5341 case Intrinsic::nvvm_suld_2d_v4i16_trap:
5342 case Intrinsic::nvvm_suld_2d_array_i16_trap:
5343 case Intrinsic::nvvm_suld_2d_array_v2i16_trap:
5344 case Intrinsic::nvvm_suld_2d_array_v4i16_trap:
5345 case Intrinsic::nvvm_suld_3d_i16_trap:
5346 case Intrinsic::nvvm_suld_3d_v2i16_trap:
5347 case Intrinsic::nvvm_suld_3d_v4i16_trap:
5348 case Intrinsic::nvvm_suld_1d_i16_zero:
5349 case Intrinsic::nvvm_suld_1d_v2i16_zero:
5350 case Intrinsic::nvvm_suld_1d_v4i16_zero:
5351 case Intrinsic::nvvm_suld_1d_array_i16_zero:
5352 case Intrinsic::nvvm_suld_1d_array_v2i16_zero:
5353 case Intrinsic::nvvm_suld_1d_array_v4i16_zero:
5354 case Intrinsic::nvvm_suld_2d_i16_zero:
5355 case Intrinsic::nvvm_suld_2d_v2i16_zero:
5356 case Intrinsic::nvvm_suld_2d_v4i16_zero:
5357 case Intrinsic::nvvm_suld_2d_array_i16_zero:
5358 case Intrinsic::nvvm_suld_2d_array_v2i16_zero:
5359 case Intrinsic::nvvm_suld_2d_array_v4i16_zero:
5360 case Intrinsic::nvvm_suld_3d_i16_zero:
5361 case Intrinsic::nvvm_suld_3d_v2i16_zero:
5362 case Intrinsic::nvvm_suld_3d_v4i16_zero:
5363 Info.opc = ISD::INTRINSIC_W_CHAIN;
5364 Info.memVT = MVT::i16;
5365 Info.ptrVal = nullptr;
5366 Info.offset = 0;
5367 Info.flags = MachineMemOperand::MOLoad;
5368 Info.align = Align(16);
5369 Infos.push_back(Info);
5370 return;
5371
5372 case Intrinsic::nvvm_suld_1d_i32_clamp:
5373 case Intrinsic::nvvm_suld_1d_v2i32_clamp:
5374 case Intrinsic::nvvm_suld_1d_v4i32_clamp:
5375 case Intrinsic::nvvm_suld_1d_array_i32_clamp:
5376 case Intrinsic::nvvm_suld_1d_array_v2i32_clamp:
5377 case Intrinsic::nvvm_suld_1d_array_v4i32_clamp:
5378 case Intrinsic::nvvm_suld_2d_i32_clamp:
5379 case Intrinsic::nvvm_suld_2d_v2i32_clamp:
5380 case Intrinsic::nvvm_suld_2d_v4i32_clamp:
5381 case Intrinsic::nvvm_suld_2d_array_i32_clamp:
5382 case Intrinsic::nvvm_suld_2d_array_v2i32_clamp:
5383 case Intrinsic::nvvm_suld_2d_array_v4i32_clamp:
5384 case Intrinsic::nvvm_suld_3d_i32_clamp:
5385 case Intrinsic::nvvm_suld_3d_v2i32_clamp:
5386 case Intrinsic::nvvm_suld_3d_v4i32_clamp:
5387 case Intrinsic::nvvm_suld_1d_i32_trap:
5388 case Intrinsic::nvvm_suld_1d_v2i32_trap:
5389 case Intrinsic::nvvm_suld_1d_v4i32_trap:
5390 case Intrinsic::nvvm_suld_1d_array_i32_trap:
5391 case Intrinsic::nvvm_suld_1d_array_v2i32_trap:
5392 case Intrinsic::nvvm_suld_1d_array_v4i32_trap:
5393 case Intrinsic::nvvm_suld_2d_i32_trap:
5394 case Intrinsic::nvvm_suld_2d_v2i32_trap:
5395 case Intrinsic::nvvm_suld_2d_v4i32_trap:
5396 case Intrinsic::nvvm_suld_2d_array_i32_trap:
5397 case Intrinsic::nvvm_suld_2d_array_v2i32_trap:
5398 case Intrinsic::nvvm_suld_2d_array_v4i32_trap:
5399 case Intrinsic::nvvm_suld_3d_i32_trap:
5400 case Intrinsic::nvvm_suld_3d_v2i32_trap:
5401 case Intrinsic::nvvm_suld_3d_v4i32_trap:
5402 case Intrinsic::nvvm_suld_1d_i32_zero:
5403 case Intrinsic::nvvm_suld_1d_v2i32_zero:
5404 case Intrinsic::nvvm_suld_1d_v4i32_zero:
5405 case Intrinsic::nvvm_suld_1d_array_i32_zero:
5406 case Intrinsic::nvvm_suld_1d_array_v2i32_zero:
5407 case Intrinsic::nvvm_suld_1d_array_v4i32_zero:
5408 case Intrinsic::nvvm_suld_2d_i32_zero:
5409 case Intrinsic::nvvm_suld_2d_v2i32_zero:
5410 case Intrinsic::nvvm_suld_2d_v4i32_zero:
5411 case Intrinsic::nvvm_suld_2d_array_i32_zero:
5412 case Intrinsic::nvvm_suld_2d_array_v2i32_zero:
5413 case Intrinsic::nvvm_suld_2d_array_v4i32_zero:
5414 case Intrinsic::nvvm_suld_3d_i32_zero:
5415 case Intrinsic::nvvm_suld_3d_v2i32_zero:
5416 case Intrinsic::nvvm_suld_3d_v4i32_zero:
5417 Info.opc = ISD::INTRINSIC_W_CHAIN;
5418 Info.memVT = MVT::i32;
5419 Info.ptrVal = nullptr;
5420 Info.offset = 0;
5421 Info.flags = MachineMemOperand::MOLoad;
5422 Info.align = Align(16);
5423 Infos.push_back(Info);
5424 return;
5425
5426 case Intrinsic::nvvm_suld_1d_i64_clamp:
5427 case Intrinsic::nvvm_suld_1d_v2i64_clamp:
5428 case Intrinsic::nvvm_suld_1d_array_i64_clamp:
5429 case Intrinsic::nvvm_suld_1d_array_v2i64_clamp:
5430 case Intrinsic::nvvm_suld_2d_i64_clamp:
5431 case Intrinsic::nvvm_suld_2d_v2i64_clamp:
5432 case Intrinsic::nvvm_suld_2d_array_i64_clamp:
5433 case Intrinsic::nvvm_suld_2d_array_v2i64_clamp:
5434 case Intrinsic::nvvm_suld_3d_i64_clamp:
5435 case Intrinsic::nvvm_suld_3d_v2i64_clamp:
5436 case Intrinsic::nvvm_suld_1d_i64_trap:
5437 case Intrinsic::nvvm_suld_1d_v2i64_trap:
5438 case Intrinsic::nvvm_suld_1d_array_i64_trap:
5439 case Intrinsic::nvvm_suld_1d_array_v2i64_trap:
5440 case Intrinsic::nvvm_suld_2d_i64_trap:
5441 case Intrinsic::nvvm_suld_2d_v2i64_trap:
5442 case Intrinsic::nvvm_suld_2d_array_i64_trap:
5443 case Intrinsic::nvvm_suld_2d_array_v2i64_trap:
5444 case Intrinsic::nvvm_suld_3d_i64_trap:
5445 case Intrinsic::nvvm_suld_3d_v2i64_trap:
5446 case Intrinsic::nvvm_suld_1d_i64_zero:
5447 case Intrinsic::nvvm_suld_1d_v2i64_zero:
5448 case Intrinsic::nvvm_suld_1d_array_i64_zero:
5449 case Intrinsic::nvvm_suld_1d_array_v2i64_zero:
5450 case Intrinsic::nvvm_suld_2d_i64_zero:
5451 case Intrinsic::nvvm_suld_2d_v2i64_zero:
5452 case Intrinsic::nvvm_suld_2d_array_i64_zero:
5453 case Intrinsic::nvvm_suld_2d_array_v2i64_zero:
5454 case Intrinsic::nvvm_suld_3d_i64_zero:
5455 case Intrinsic::nvvm_suld_3d_v2i64_zero:
5456 Info.opc = ISD::INTRINSIC_W_CHAIN;
5457 Info.memVT = MVT::i64;
5458 Info.ptrVal = nullptr;
5459 Info.offset = 0;
5460 Info.flags = MachineMemOperand::MOLoad;
5461 Info.align = Align(16);
5462 Infos.push_back(Info);
5463 return;
5464
5465 case Intrinsic::nvvm_tcgen05_ld_16x64b_x1:
5466 case Intrinsic::nvvm_tcgen05_ld_32x32b_x1:
5467 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x1: {
5468 Info.opc = ISD::INTRINSIC_W_CHAIN;
5469 Info.memVT = MVT::v1i32;
5470 Info.ptrVal = I.getArgOperand(0);
5471 Info.offset = 0;
5472 Info.flags = MachineMemOperand::MOLoad;
5473 Info.align.reset();
5474 Infos.push_back(Info);
5475 return;
5476 }
5477
5478 case Intrinsic::nvvm_tcgen05_ld_16x64b_x2:
5479 case Intrinsic::nvvm_tcgen05_ld_16x128b_x1:
5480 case Intrinsic::nvvm_tcgen05_ld_32x32b_x2:
5481 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x2:
5482 case Intrinsic::nvvm_tcgen05_ld_red_32x32b_x2_i32:
5483 case Intrinsic::nvvm_tcgen05_ld_red_16x32bx2_x2_i32: {
5484 Info.opc = ISD::INTRINSIC_W_CHAIN;
5485 Info.memVT = MVT::v2i32;
5486 Info.ptrVal = I.getArgOperand(0);
5487 Info.offset = 0;
5488 Info.flags = MachineMemOperand::MOLoad;
5489 Info.align.reset();
5490 Infos.push_back(Info);
5491 return;
5492 }
5493
5494 case Intrinsic::nvvm_tcgen05_ld_red_32x32b_x2_f32:
5495 case Intrinsic::nvvm_tcgen05_ld_red_16x32bx2_x2_f32: {
5496 Info.opc = ISD::INTRINSIC_W_CHAIN;
5497 Info.memVT = MVT::v2f32;
5498 Info.ptrVal = I.getArgOperand(0);
5499 Info.offset = 0;
5500 Info.flags = MachineMemOperand::MOLoad;
5501 Info.align.reset();
5502 Infos.push_back(Info);
5503 return;
5504 }
5505
5506 case Intrinsic::nvvm_tcgen05_ld_16x64b_x4:
5507 case Intrinsic::nvvm_tcgen05_ld_16x128b_x2:
5508 case Intrinsic::nvvm_tcgen05_ld_32x32b_x4:
5509 case Intrinsic::nvvm_tcgen05_ld_16x256b_x1:
5510 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x4:
5511 case Intrinsic::nvvm_tcgen05_ld_red_32x32b_x4_i32:
5512 case Intrinsic::nvvm_tcgen05_ld_red_16x32bx2_x4_i32: {
5513 Info.opc = ISD::INTRINSIC_W_CHAIN;
5514 Info.memVT = MVT::v4i32;
5515 Info.ptrVal = I.getArgOperand(0);
5516 Info.offset = 0;
5517 Info.flags = MachineMemOperand::MOLoad;
5518 Info.align.reset();
5519 Infos.push_back(Info);
5520 return;
5521 }
5522
5523 case Intrinsic::nvvm_tcgen05_ld_red_32x32b_x4_f32:
5524 case Intrinsic::nvvm_tcgen05_ld_red_16x32bx2_x4_f32: {
5525 Info.opc = ISD::INTRINSIC_W_CHAIN;
5526 Info.memVT = MVT::v4f32;
5527 Info.ptrVal = I.getArgOperand(0);
5528 Info.offset = 0;
5529 Info.flags = MachineMemOperand::MOLoad;
5530 Info.align.reset();
5531 Infos.push_back(Info);
5532 return;
5533 }
5534
5535 case Intrinsic::nvvm_tcgen05_ld_16x64b_x8:
5536 case Intrinsic::nvvm_tcgen05_ld_16x128b_x4:
5537 case Intrinsic::nvvm_tcgen05_ld_16x256b_x2:
5538 case Intrinsic::nvvm_tcgen05_ld_32x32b_x8:
5539 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x8:
5540 case Intrinsic::nvvm_tcgen05_ld_red_32x32b_x8_i32:
5541 case Intrinsic::nvvm_tcgen05_ld_red_16x32bx2_x8_i32: {
5542 Info.opc = ISD::INTRINSIC_W_CHAIN;
5543 Info.memVT = MVT::v8i32;
5544 Info.ptrVal = I.getArgOperand(0);
5545 Info.offset = 0;
5546 Info.flags = MachineMemOperand::MOLoad;
5547 Info.align.reset();
5548 Infos.push_back(Info);
5549 return;
5550 }
5551
5552 case Intrinsic::nvvm_tcgen05_ld_red_32x32b_x8_f32:
5553 case Intrinsic::nvvm_tcgen05_ld_red_16x32bx2_x8_f32: {
5554 Info.opc = ISD::INTRINSIC_W_CHAIN;
5555 Info.memVT = MVT::v8f32;
5556 Info.ptrVal = I.getArgOperand(0);
5557 Info.offset = 0;
5558 Info.flags = MachineMemOperand::MOLoad;
5559 Info.align.reset();
5560 Infos.push_back(Info);
5561 return;
5562 }
5563
5564 case Intrinsic::nvvm_tcgen05_ld_16x64b_x16:
5565 case Intrinsic::nvvm_tcgen05_ld_16x128b_x8:
5566 case Intrinsic::nvvm_tcgen05_ld_16x256b_x4:
5567 case Intrinsic::nvvm_tcgen05_ld_32x32b_x16:
5568 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x16:
5569 case Intrinsic::nvvm_tcgen05_ld_red_32x32b_x16_i32:
5570 case Intrinsic::nvvm_tcgen05_ld_red_16x32bx2_x16_i32: {
5571 Info.opc = ISD::INTRINSIC_W_CHAIN;
5572 Info.memVT = MVT::v16i32;
5573 Info.ptrVal = I.getArgOperand(0);
5574 Info.offset = 0;
5575 Info.flags = MachineMemOperand::MOLoad;
5576 Info.align.reset();
5577 Infos.push_back(Info);
5578 return;
5579 }
5580
5581 case Intrinsic::nvvm_tcgen05_ld_red_32x32b_x16_f32:
5582 case Intrinsic::nvvm_tcgen05_ld_red_16x32bx2_x16_f32: {
5583 Info.opc = ISD::INTRINSIC_W_CHAIN;
5584 Info.memVT = MVT::v16f32;
5585 Info.ptrVal = I.getArgOperand(0);
5586 Info.offset = 0;
5587 Info.flags = MachineMemOperand::MOLoad;
5588 Info.align.reset();
5589 Infos.push_back(Info);
5590 return;
5591 }
5592
5593 case Intrinsic::nvvm_tcgen05_ld_16x64b_x32:
5594 case Intrinsic::nvvm_tcgen05_ld_16x128b_x16:
5595 case Intrinsic::nvvm_tcgen05_ld_16x256b_x8:
5596 case Intrinsic::nvvm_tcgen05_ld_32x32b_x32:
5597 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x32:
5598 case Intrinsic::nvvm_tcgen05_ld_red_32x32b_x32_i32:
5599 case Intrinsic::nvvm_tcgen05_ld_red_16x32bx2_x32_i32: {
5600 Info.opc = ISD::INTRINSIC_W_CHAIN;
5601 Info.memVT = MVT::v32i32;
5602 Info.ptrVal = I.getArgOperand(0);
5603 Info.offset = 0;
5604 Info.flags = MachineMemOperand::MOLoad;
5605 Info.align.reset();
5606 Infos.push_back(Info);
5607 return;
5608 }
5609
5610 case Intrinsic::nvvm_tcgen05_ld_red_32x32b_x32_f32:
5611 case Intrinsic::nvvm_tcgen05_ld_red_16x32bx2_x32_f32: {
5612 Info.opc = ISD::INTRINSIC_W_CHAIN;
5613 Info.memVT = MVT::v32f32;
5614 Info.ptrVal = I.getArgOperand(0);
5615 Info.offset = 0;
5616 Info.flags = MachineMemOperand::MOLoad;
5617 Info.align.reset();
5618 Infos.push_back(Info);
5619 return;
5620 }
5621
5622 case Intrinsic::nvvm_tcgen05_ld_16x64b_x64:
5623 case Intrinsic::nvvm_tcgen05_ld_16x128b_x32:
5624 case Intrinsic::nvvm_tcgen05_ld_16x256b_x16:
5625 case Intrinsic::nvvm_tcgen05_ld_32x32b_x64:
5626 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x64:
5627 case Intrinsic::nvvm_tcgen05_ld_red_32x32b_x64_i32:
5628 case Intrinsic::nvvm_tcgen05_ld_red_16x32bx2_x64_i32: {
5629 Info.opc = ISD::INTRINSIC_W_CHAIN;
5630 Info.memVT = MVT::v64i32;
5631 Info.ptrVal = I.getArgOperand(0);
5632 Info.offset = 0;
5633 Info.flags = MachineMemOperand::MOLoad;
5634 Info.align.reset();
5635 Infos.push_back(Info);
5636 return;
5637 }
5638
5639 case Intrinsic::nvvm_tcgen05_ld_red_32x32b_x64_f32:
5640 case Intrinsic::nvvm_tcgen05_ld_red_16x32bx2_x64_f32: {
5641 Info.opc = ISD::INTRINSIC_W_CHAIN;
5642 Info.memVT = MVT::v64f32;
5643 Info.ptrVal = I.getArgOperand(0);
5644 Info.offset = 0;
5645 Info.flags = MachineMemOperand::MOLoad;
5646 Info.align.reset();
5647 Infos.push_back(Info);
5648 return;
5649 }
5650
5651 case Intrinsic::nvvm_tcgen05_ld_16x64b_x128:
5652 case Intrinsic::nvvm_tcgen05_ld_16x128b_x64:
5653 case Intrinsic::nvvm_tcgen05_ld_16x256b_x32:
5654 case Intrinsic::nvvm_tcgen05_ld_32x32b_x128:
5655 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x128:
5656 case Intrinsic::nvvm_tcgen05_ld_red_32x32b_x128_i32:
5657 case Intrinsic::nvvm_tcgen05_ld_red_16x32bx2_x128_i32: {
5658 Info.opc = ISD::INTRINSIC_W_CHAIN;
5659 Info.memVT = MVT::v128i32;
5660 Info.ptrVal = I.getArgOperand(0);
5661 Info.offset = 0;
5662 Info.flags = MachineMemOperand::MOLoad;
5663 Info.align.reset();
5664 Infos.push_back(Info);
5665 return;
5666 }
5667
5668 case Intrinsic::nvvm_tcgen05_ld_red_32x32b_x128_f32:
5669 case Intrinsic::nvvm_tcgen05_ld_red_16x32bx2_x128_f32: {
5670 Info.opc = ISD::INTRINSIC_W_CHAIN;
5671 Info.memVT = MVT::v128f32;
5672 Info.ptrVal = I.getArgOperand(0);
5673 Info.offset = 0;
5674 Info.flags = MachineMemOperand::MOLoad;
5675 Info.align.reset();
5676 Infos.push_back(Info);
5677 return;
5678 }
5679
5680 case Intrinsic::nvvm_tcgen05_st_16x64b_x1:
5681 case Intrinsic::nvvm_tcgen05_st_32x32b_x1:
5682 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x1: {
5683 Info.opc = ISD::INTRINSIC_VOID;
5684 Info.memVT = MVT::v1i32;
5685 Info.ptrVal = I.getArgOperand(0);
5686 Info.offset = 0;
5687 Info.flags = MachineMemOperand::MOStore;
5688 Info.align.reset();
5689 Infos.push_back(Info);
5690 return;
5691 }
5692
5693 case Intrinsic::nvvm_tcgen05_st_16x64b_x2:
5694 case Intrinsic::nvvm_tcgen05_st_16x128b_x1:
5695 case Intrinsic::nvvm_tcgen05_st_32x32b_x2:
5696 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x2: {
5697 Info.opc = ISD::INTRINSIC_VOID;
5698 Info.memVT = MVT::v2i32;
5699 Info.ptrVal = I.getArgOperand(0);
5700 Info.offset = 0;
5701 Info.flags = MachineMemOperand::MOStore;
5702 Info.align.reset();
5703 Infos.push_back(Info);
5704 return;
5705 }
5706
5707 case Intrinsic::nvvm_tcgen05_st_16x64b_x4:
5708 case Intrinsic::nvvm_tcgen05_st_16x128b_x2:
5709 case Intrinsic::nvvm_tcgen05_st_16x256b_x1:
5710 case Intrinsic::nvvm_tcgen05_st_32x32b_x4:
5711 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x4: {
5712 Info.opc = ISD::INTRINSIC_VOID;
5713 Info.memVT = MVT::v4i32;
5714 Info.ptrVal = I.getArgOperand(0);
5715 Info.offset = 0;
5716 Info.flags = MachineMemOperand::MOStore;
5717 Info.align.reset();
5718 Infos.push_back(Info);
5719 return;
5720 }
5721
5722 case Intrinsic::nvvm_tcgen05_st_16x64b_x8:
5723 case Intrinsic::nvvm_tcgen05_st_16x128b_x4:
5724 case Intrinsic::nvvm_tcgen05_st_16x256b_x2:
5725 case Intrinsic::nvvm_tcgen05_st_32x32b_x8:
5726 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x8: {
5727 Info.opc = ISD::INTRINSIC_VOID;
5728 Info.memVT = MVT::v8i32;
5729 Info.ptrVal = I.getArgOperand(0);
5730 Info.offset = 0;
5731 Info.flags = MachineMemOperand::MOStore;
5732 Info.align.reset();
5733 Infos.push_back(Info);
5734 return;
5735 }
5736
5737 case Intrinsic::nvvm_tcgen05_st_16x64b_x16:
5738 case Intrinsic::nvvm_tcgen05_st_16x128b_x8:
5739 case Intrinsic::nvvm_tcgen05_st_16x256b_x4:
5740 case Intrinsic::nvvm_tcgen05_st_32x32b_x16:
5741 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x16: {
5742 Info.opc = ISD::INTRINSIC_VOID;
5743 Info.memVT = MVT::v16i32;
5744 Info.ptrVal = I.getArgOperand(0);
5745 Info.offset = 0;
5746 Info.flags = MachineMemOperand::MOStore;
5747 Info.align.reset();
5748 Infos.push_back(Info);
5749 return;
5750 }
5751
5752 case Intrinsic::nvvm_tcgen05_st_16x64b_x32:
5753 case Intrinsic::nvvm_tcgen05_st_16x128b_x16:
5754 case Intrinsic::nvvm_tcgen05_st_16x256b_x8:
5755 case Intrinsic::nvvm_tcgen05_st_32x32b_x32:
5756 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x32: {
5757 Info.opc = ISD::INTRINSIC_VOID;
5758 Info.memVT = MVT::v32i32;
5759 Info.ptrVal = I.getArgOperand(0);
5760 Info.offset = 0;
5761 Info.flags = MachineMemOperand::MOStore;
5762 Info.align.reset();
5763 Infos.push_back(Info);
5764 return;
5765 }
5766
5767 case Intrinsic::nvvm_tcgen05_st_16x64b_x64:
5768 case Intrinsic::nvvm_tcgen05_st_16x128b_x32:
5769 case Intrinsic::nvvm_tcgen05_st_16x256b_x16:
5770 case Intrinsic::nvvm_tcgen05_st_32x32b_x64:
5771 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x64: {
5772 Info.opc = ISD::INTRINSIC_VOID;
5773 Info.memVT = MVT::v64i32;
5774 Info.ptrVal = I.getArgOperand(0);
5775 Info.offset = 0;
5776 Info.flags = MachineMemOperand::MOStore;
5777 Info.align.reset();
5778 Infos.push_back(Info);
5779 return;
5780 }
5781
5782 case Intrinsic::nvvm_tcgen05_st_16x64b_x128:
5783 case Intrinsic::nvvm_tcgen05_st_16x128b_x64:
5784 case Intrinsic::nvvm_tcgen05_st_16x256b_x32:
5785 case Intrinsic::nvvm_tcgen05_st_32x32b_x128:
5786 case Intrinsic::nvvm_tcgen05_st_16x32bx2_x128: {
5787 Info.opc = ISD::INTRINSIC_VOID;
5788 Info.memVT = MVT::v128i32;
5789 Info.ptrVal = I.getArgOperand(0);
5790 Info.offset = 0;
5791 Info.flags = MachineMemOperand::MOStore;
5792 Info.align.reset();
5793 Infos.push_back(Info);
5794 return;
5795 }
5796 case Intrinsic::
5797 nvvm_tcgen05_mma_shared_f8f6f4_disable_output_lane_cg1_decompress_b:
5798 case Intrinsic::
5799 nvvm_tcgen05_mma_tensor_f8f6f4_disable_output_lane_cg1_decompress_b:
5800 case Intrinsic::nvvm_tcgen05_mma_shared_disable_output_lane_cg1:
5801 case Intrinsic::nvvm_tcgen05_mma_shared_scale_d_disable_output_lane_cg1:
5802 case Intrinsic::nvvm_tcgen05_mma_sp_shared_disable_output_lane_cg1:
5803 case Intrinsic::nvvm_tcgen05_mma_sp_shared_scale_d_disable_output_lane_cg1:
5804 case Intrinsic::nvvm_tcgen05_mma_tensor_disable_output_lane_cg1:
5805 case Intrinsic::nvvm_tcgen05_mma_tensor_scale_d_disable_output_lane_cg1:
5806 case Intrinsic::nvvm_tcgen05_mma_tensor_disable_output_lane_cg1_ashift:
5807 case Intrinsic::
5808 nvvm_tcgen05_mma_tensor_scale_d_disable_output_lane_cg1_ashift:
5809 case Intrinsic::nvvm_tcgen05_mma_sp_tensor_disable_output_lane_cg1:
5810 case Intrinsic::nvvm_tcgen05_mma_sp_tensor_scale_d_disable_output_lane_cg1:
5811 case Intrinsic::nvvm_tcgen05_mma_sp_tensor_disable_output_lane_cg1_ashift:
5812 case Intrinsic::
5813 nvvm_tcgen05_mma_sp_tensor_scale_d_disable_output_lane_cg1_ashift: {
5814 // We are reading and writing back to TMem
5815 Info.opc = ISD::INTRINSIC_VOID;
5816 Info.memVT = MVT::v4i32;
5817 Info.ptrVal = I.getArgOperand(0);
5818 Info.offset = 0;
5820 Info.align = Align(16);
5821 Infos.push_back(Info);
5822 return;
5823 }
5824
5825 case Intrinsic::
5826 nvvm_tcgen05_mma_shared_f8f6f4_disable_output_lane_cg2_decompress_b:
5827 case Intrinsic::
5828 nvvm_tcgen05_mma_tensor_f8f6f4_disable_output_lane_cg2_decompress_b:
5829 case Intrinsic::nvvm_tcgen05_mma_shared_disable_output_lane_cg2:
5830 case Intrinsic::nvvm_tcgen05_mma_shared_scale_d_disable_output_lane_cg2:
5831 case Intrinsic::nvvm_tcgen05_mma_sp_shared_disable_output_lane_cg2:
5832 case Intrinsic::nvvm_tcgen05_mma_sp_shared_scale_d_disable_output_lane_cg2:
5833 case Intrinsic::nvvm_tcgen05_mma_tensor_disable_output_lane_cg2:
5834 case Intrinsic::nvvm_tcgen05_mma_tensor_scale_d_disable_output_lane_cg2:
5835 case Intrinsic::nvvm_tcgen05_mma_sp_tensor_disable_output_lane_cg2:
5836 case Intrinsic::nvvm_tcgen05_mma_sp_tensor_scale_d_disable_output_lane_cg2:
5837 case Intrinsic::nvvm_tcgen05_mma_tensor_disable_output_lane_cg2_ashift:
5838 case Intrinsic::
5839 nvvm_tcgen05_mma_tensor_scale_d_disable_output_lane_cg2_ashift:
5840 case Intrinsic::nvvm_tcgen05_mma_sp_tensor_disable_output_lane_cg2_ashift:
5841 case Intrinsic::
5842 nvvm_tcgen05_mma_sp_tensor_scale_d_disable_output_lane_cg2_ashift: {
5843 // We are reading and writing back to TMem
5844 Info.opc = ISD::INTRINSIC_VOID;
5845 Info.memVT = MVT::v8i32;
5846 Info.ptrVal = I.getArgOperand(0);
5847 Info.offset = 0;
5849 Info.align = Align(16);
5850 Infos.push_back(Info);
5851 return;
5852 }
5853 case Intrinsic::nvvm_tcgen05_alloc_cg1:
5854 case Intrinsic::nvvm_tcgen05_alloc_cg2:
5855 Info.opc = ISD::INTRINSIC_VOID;
5856 Info.memVT = MVT::i32;
5857 Info.ptrVal = I.getArgOperand(0);
5858 Info.offset = 0;
5859 Info.flags = MachineMemOperand::MOStore;
5860 Info.align = Align(4);
5861 Infos.push_back(Info);
5862 return;
5863 }
5864}
5865
5866// Helper for getting a function parameter symbol. Its name is composed from
5867// the function name and the parameter index. Negative index corresponds to the
5868// special parameter (unsized array) used for passing variable arguments.
5870 int Idx) const {
5871 const StringRef FuncName = getTargetMachine().getSymbol(F)->getName();
5872 if (Idx < 0)
5873 return Ctx.getOrCreateSymbol(FuncName + "_vararg");
5874 return Ctx.getOrCreateSymbol(FuncName + "_param_" + Twine(Idx));
5875}
5876
5877/// isLegalAddressingMode - Return true if the addressing mode represented
5878/// by AM is legal for this target, for a load/store of the specified type.
5879/// Used to guide target specific optimizations, like loop strength reduction
5880/// (LoopStrengthReduce.cpp) and memory optimization for address mode
5881/// (CodeGenPrepare.cpp)
5883 const AddrMode &AM, Type *Ty,
5884 unsigned AS, Instruction *I) const {
5885 // AddrMode - This represents an addressing mode of:
5886 // BaseGV + BaseOffs + BaseReg + Scale*ScaleReg
5887 //
5888 // The legal address modes are
5889 // - [avar]
5890 // - [areg]
5891 // - [areg+immoff]
5892 // - [immAddr]
5893
5894 // immoff must fit in a signed 32-bit int
5895 if (!APInt(64, AM.BaseOffs).isSignedIntN(32))
5896 return false;
5897
5898 if (AM.BaseGV)
5899 return !AM.BaseOffs && !AM.HasBaseReg && !AM.Scale;
5900
5901 switch (AM.Scale) {
5902 case 0: // "r", "r+i" or "i" is allowed
5903 break;
5904 case 1:
5905 if (AM.HasBaseReg) // "r+r+i" or "r+r" is not allowed.
5906 return false;
5907 // Otherwise we have r+i.
5908 break;
5909 default:
5910 // No scale > 1 is allowed
5911 return false;
5912 }
5913 return true;
5914}
5915
5916//===----------------------------------------------------------------------===//
5917// NVPTX Inline Assembly Support
5918//===----------------------------------------------------------------------===//
5919
5920/// getConstraintType - Given a constraint letter, return the type of
5921/// constraint it is for this target.
5924 if (Constraint.size() == 1) {
5925 switch (Constraint[0]) {
5926 default:
5927 break;
5928 case 'b':
5929 case 'r':
5930 case 'h':
5931 case 'c':
5932 case 'l':
5933 case 'f':
5934 case 'd':
5935 case 'q':
5936 case '0':
5937 case 'N':
5938 return C_RegisterClass;
5939 }
5940 }
5941 return TargetLowering::getConstraintType(Constraint);
5942}
5943
5944std::pair<unsigned, const TargetRegisterClass *>
5946 StringRef Constraint,
5947 MVT VT) const {
5948 if (Constraint.size() == 1) {
5949 switch (Constraint[0]) {
5950 case 'b':
5951 return std::make_pair(0U, &NVPTX::B1RegClass);
5952 case 'c':
5953 case 'h':
5954 return std::make_pair(0U, &NVPTX::B16RegClass);
5955 case 'r':
5956 case 'f':
5957 return std::make_pair(0U, &NVPTX::B32RegClass);
5958 case 'l':
5959 case 'N':
5960 case 'd':
5961 return std::make_pair(0U, &NVPTX::B64RegClass);
5962 case 'q': {
5963 if (!STI.hasFeature(NVPTX::SM70))
5964 report_fatal_error("Inline asm with 128 bit operands is only "
5965 "supported for sm_70 and higher!");
5966 return std::make_pair(0U, &NVPTX::B128RegClass);
5967 }
5968 }
5969 }
5970 return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);
5971}
5972
5973//===----------------------------------------------------------------------===//
5974// NVPTX DAG Combining
5975//===----------------------------------------------------------------------===//
5976
5978 CodeGenOptLevel OptLevel) const {
5979 // Always honor command-line argument
5980 if (FMAContractLevelOpt.getNumOccurrences() > 0)
5981 return FMAContractLevelOpt > 0;
5982
5983 // Do not contract if we're not optimizing the code.
5984 if (OptLevel == CodeGenOptLevel::None)
5985 return false;
5986
5987 return false;
5988}
5989
5990static bool isConstZero(const SDValue &Operand) {
5991 const auto *Const = dyn_cast<ConstantSDNode>(Operand);
5992 return Const && Const->getZExtValue() == 0;
5993}
5994
5995/// PerformADDCombineWithOperands - Try DAG combinations for an ADD with
5996/// operands N0 and N1. This is a helper for PerformADDCombine that is
5997/// called with the default operands, and if that fails, with commuted
5998/// operands.
5999static SDValue
6002 EVT VT = N0.getValueType();
6003
6004 // Since integer multiply-add costs the same as integer multiply
6005 // but is more costly than integer add, do the fusion only when
6006 // the mul is only used in the add.
6007 // TODO: this may not be true for later architectures, consider relaxing this
6008 if (!N0.getNode()->hasOneUse())
6009 return SDValue();
6010
6011 // fold (add (select cond, 0, (mul a, b)), c)
6012 // -> (select cond, c, (add (mul a, b), c))
6013 //
6014 if (N0.getOpcode() == ISD::SELECT) {
6015 unsigned ZeroOpNum;
6016 if (isConstZero(N0->getOperand(1)))
6017 ZeroOpNum = 1;
6018 else if (isConstZero(N0->getOperand(2)))
6019 ZeroOpNum = 2;
6020 else
6021 return SDValue();
6022
6023 SDValue M = N0->getOperand((ZeroOpNum == 1) ? 2 : 1);
6024 if (M->getOpcode() != ISD::MUL || !M.getNode()->hasOneUse())
6025 return SDValue();
6026
6027 SDLoc DL(N);
6028 SDValue Mul =
6029 DCI.DAG.getNode(ISD::MUL, DL, VT, M->getOperand(0), M->getOperand(1));
6030 SDValue MAD = DCI.DAG.getNode(ISD::ADD, DL, VT, Mul, N1);
6031 return DCI.DAG.getSelect(SDLoc(N), VT, N0->getOperand(0),
6032 ((ZeroOpNum == 1) ? N1 : MAD),
6033 ((ZeroOpNum == 1) ? MAD : N1));
6034 }
6035
6036 return SDValue();
6037}
6038
6039SDValue NVPTXTargetLowering::performFADDCombineWithOperands(
6041 CodeGenOptLevel OptLevel) const {
6042 EVT VT = N0.getValueType();
6043 if (N0.getOpcode() == ISD::FMUL) {
6044 if (!(allowFMA(DCI.DAG.getMachineFunction(), OptLevel) ||
6045 (N->getFlags().hasAllowContract() &&
6046 N0->getFlags().hasAllowContract())))
6047 return SDValue();
6048
6049 // For floating point:
6050 // Do the fusion only when the mul has less than 5 uses and all
6051 // are add.
6052 // The heuristic is that if a use is not an add, then that use
6053 // cannot be fused into fma, therefore mul is still needed anyway.
6054 // If there are more than 4 uses, even if they are all add, fusing
6055 // them will increase register pressue.
6056 //
6057 int numUses = 0;
6058 int nonAddCount = 0;
6059 for (const SDNode *User : N0.getNode()->users()) {
6060 numUses++;
6061 if (User->getOpcode() != ISD::FADD)
6062 ++nonAddCount;
6063 if (numUses >= 5)
6064 return SDValue();
6065 }
6066 if (nonAddCount) {
6067 int orderNo = N->getIROrder();
6068 int orderNo2 = N0.getNode()->getIROrder();
6069 // simple heuristics here for considering potential register
6070 // pressure, the logics here is that the differnce are used
6071 // to measure the distance between def and use, the longer distance
6072 // more likely cause register pressure.
6073 if (orderNo - orderNo2 < 500)
6074 return SDValue();
6075
6076 // Now, check if at least one of the FMUL's operands is live beyond the
6077 // node N, which guarantees that the FMA will not increase register
6078 // pressure at node N.
6079 bool opIsLive = false;
6080 const SDNode *left = N0.getOperand(0).getNode();
6081 const SDNode *right = N0.getOperand(1).getNode();
6082
6083 if (isa<ConstantSDNode>(left) || isa<ConstantSDNode>(right))
6084 opIsLive = true;
6085
6086 if (!opIsLive)
6087 for (const SDNode *User : left->users()) {
6088 int orderNo3 = User->getIROrder();
6089 if (orderNo3 > orderNo) {
6090 opIsLive = true;
6091 break;
6092 }
6093 }
6094
6095 if (!opIsLive)
6096 for (const SDNode *User : right->users()) {
6097 int orderNo3 = User->getIROrder();
6098 if (orderNo3 > orderNo) {
6099 opIsLive = true;
6100 break;
6101 }
6102 }
6103
6104 if (!opIsLive)
6105 return SDValue();
6106 }
6107
6108 return DCI.DAG.getNode(ISD::FMA, SDLoc(N), VT, N0.getOperand(0),
6109 N0.getOperand(1), N1);
6110 }
6111
6112 return SDValue();
6113}
6114
6115/// Fold unpacking movs into a load by increasing the number of return values.
6116///
6117/// ex:
6118/// L: v2f16,ch = load <p>
6119/// a: f16 = extractelt L:0, 0
6120/// b: f16 = extractelt L:0, 1
6121/// use(a, b)
6122///
6123/// ...is turned into...
6124///
6125/// L: f16,f16,ch = LoadV2 <p>
6126/// use(L:0, L:1)
6127static SDValue
6129 // Don't run this optimization before the legalizer
6130 if (!DCI.isAfterLegalizeDAG())
6131 return SDValue();
6132
6133 EVT ElementVT = N->getValueType(0);
6134 // Avoid non-packed types and v4i8
6135 if (!NVPTX::isPackedVectorTy(ElementVT) || ElementVT == MVT::v4i8)
6136 return SDValue();
6137
6138 // Check whether all outputs are either used by an extractelt or are
6139 // glue/chain nodes
6140 if (!all_of(N->uses(), [&](SDUse &U) {
6141 // Skip glue, chain nodes
6142 if (U.getValueType() == MVT::Glue || U.getValueType() == MVT::Other)
6143 return true;
6144 if (U.getUser()->getOpcode() == ISD::EXTRACT_VECTOR_ELT) {
6145 if (N->getOpcode() != ISD::LOAD)
6146 return true;
6147 // Since this is an ISD::LOAD, check all extractelts are used. If
6148 // any are not used, we don't want to defeat another optimization that
6149 // will narrow the load.
6150 //
6151 // For example:
6152 //
6153 // L: v2f16,ch = load <p>
6154 // e0: f16 = extractelt L:0, 0
6155 // e1: f16 = extractelt L:0, 1 <-- unused
6156 // store e0
6157 //
6158 // Can be optimized by DAGCombiner to:
6159 //
6160 // L: f16,ch = load <p>
6161 // store L:0
6162 return !U.getUser()->use_empty();
6163 }
6164
6165 // Otherwise, this use prevents us from splitting a value.
6166 return false;
6167 }))
6168 return SDValue();
6169
6170 auto *LD = cast<MemSDNode>(N);
6171 SDLoc DL(LD);
6172
6173 // the new opcode after we double the number of operands
6174 unsigned Opcode;
6176 unsigned OldNumOutputs; // non-glue, non-chain outputs
6177 switch (LD->getOpcode()) {
6178 case ISD::LOAD:
6179 OldNumOutputs = 1;
6180 // Any packed type is legal, so the legalizer will not have lowered
6181 // ISD::LOAD -> NVPTXISD::Load (unless it's under-aligned). We have to do it
6182 // here.
6183 Opcode = NVPTXISD::LoadV2;
6184 // append a "full" used bytes mask operand right before the extension type
6185 // operand, signifying that all bytes are used.
6186 Operands.push_back(DCI.DAG.getConstant(UINT32_MAX, DL, MVT::i32));
6187 Operands.push_back(DCI.DAG.getIntPtrConstant(
6188 cast<LoadSDNode>(LD)->getExtensionType(), DL));
6189 break;
6190 case NVPTXISD::LoadV2:
6191 OldNumOutputs = 2;
6192 Opcode = NVPTXISD::LoadV4;
6193 break;
6194 case NVPTXISD::LoadV4:
6195 // V8 is only supported for f32/i32. Don't forget, we're not changing the
6196 // load size here. This is already a 256-bit load.
6197 if (ElementVT != MVT::v2f32 && ElementVT != MVT::v2i32)
6198 return SDValue();
6199 OldNumOutputs = 4;
6200 Opcode = NVPTXISD::LoadV8;
6201 break;
6202 case NVPTXISD::LoadV8:
6203 // PTX doesn't support the next doubling of outputs
6204 return SDValue();
6205 }
6206
6207 // the non-glue, non-chain outputs in the new load
6208 const unsigned NewNumOutputs = OldNumOutputs * 2;
6209 SmallVector<EVT> NewVTs(NewNumOutputs, ElementVT.getVectorElementType());
6210 // add remaining chain and glue values
6211 NewVTs.append(LD->value_begin() + OldNumOutputs, LD->value_end());
6212
6213 // Create the new load
6214 SDValue NewLoad = DCI.DAG.getMemIntrinsicNode(
6215 Opcode, DL, DCI.DAG.getVTList(NewVTs), Operands, LD->getMemoryVT(),
6216 LD->getMemOperand());
6217
6218 // Now we use a combination of BUILD_VECTORs and a MERGE_VALUES node to keep
6219 // the outputs the same. These nodes will be optimized away in later
6220 // DAGCombiner iterations.
6222 for (unsigned I : seq(OldNumOutputs))
6223 Results.push_back(DCI.DAG.getBuildVector(
6224 ElementVT, DL, {NewLoad.getValue(I * 2), NewLoad.getValue(I * 2 + 1)}));
6225 // Add remaining chain and glue nodes
6226 for (unsigned I : seq(NewLoad->getNumValues() - NewNumOutputs))
6227 Results.push_back(NewLoad.getValue(NewNumOutputs + I));
6228
6229 return DCI.DAG.getMergeValues(Results, DL);
6230}
6231
6232/// Fold packing movs into a store.
6233///
6234/// ex:
6235/// v1: v2f16 = BUILD_VECTOR a:f16, b:f16
6236/// v2: v2f16 = BUILD_VECTOR c:f16, d:f16
6237/// StoreV2 v1, v2
6238///
6239/// ...is turned into...
6240///
6241/// StoreV4 a, b, c, d
6244 unsigned Front, unsigned Back) {
6245 // We want to run this as late as possible since other optimizations may
6246 // eliminate the BUILD_VECTORs.
6247 if (!DCI.isAfterLegalizeDAG())
6248 return SDValue();
6249
6250 // Get the type of the operands being stored.
6251 EVT ElementVT = N->getOperand(Front).getValueType();
6252
6253 // Avoid non-packed types and v4i8
6254 if (!NVPTX::isPackedVectorTy(ElementVT) || ElementVT == MVT::v4i8)
6255 return SDValue();
6256
6257 auto *ST = cast<MemSDNode>(N);
6258
6259 // The new opcode after we double the number of operands.
6260 unsigned Opcode;
6261 switch (N->getOpcode()) {
6262 case ISD::STORE:
6263 // Any packed type is legal, so the legalizer will not have lowered
6264 // ISD::STORE -> NVPTXISD::Store (unless it's under-aligned). We have to do
6265 // it here.
6266 Opcode = NVPTXISD::StoreV2;
6267 break;
6268 case NVPTXISD::StoreV2:
6269 Opcode = NVPTXISD::StoreV4;
6270 break;
6271 case NVPTXISD::StoreV4:
6272 // V8 is only supported for f32/i32. Don't forget, we're not changing the
6273 // store size here. This is already a 256-bit store.
6274 if (ElementVT != MVT::v2f32 && ElementVT != MVT::v2i32)
6275 return SDValue();
6276 Opcode = NVPTXISD::StoreV8;
6277 break;
6278 case NVPTXISD::StoreV8:
6279 // PTX doesn't support the next doubling of operands
6280 return SDValue();
6281 default:
6282 llvm_unreachable("Unhandled store opcode");
6283 }
6284
6285 // Scan the operands and if they're all BUILD_VECTORs, we'll have gathered
6286 // their elements.
6287 SmallVector<SDValue, 4> Operands(N->ops().take_front(Front));
6288 for (SDValue BV : N->ops().drop_front(Front).drop_back(Back)) {
6289 if (BV.getOpcode() != ISD::BUILD_VECTOR)
6290 return SDValue();
6291
6292 // If the operand has multiple uses, this optimization can increase register
6293 // pressure.
6294 if (!BV.hasOneUse())
6295 return SDValue();
6296
6297 // DAGCombiner visits nodes bottom-up. Check the BUILD_VECTOR operands for
6298 // any signs they may be folded by some other pattern or rule.
6299 for (SDValue Op : BV->ops()) {
6300 // Peek through bitcasts
6301 if (Op.getOpcode() == ISD::BITCAST)
6302 Op = Op.getOperand(0);
6303
6304 // This may be folded into a PRMT.
6305 if (Op.getValueType() == MVT::i16 && Op.getOpcode() == ISD::TRUNCATE &&
6306 Op->getOperand(0).getValueType() == MVT::i32)
6307 return SDValue();
6308
6309 // This may be folded into cvt.bf16x2
6310 if (Op.getOpcode() == ISD::FP_ROUND)
6311 return SDValue();
6312 }
6313 Operands.append({BV.getOperand(0), BV.getOperand(1)});
6314 }
6315 Operands.append(N->op_end() - Back, N->op_end());
6316
6317 // Now we replace the store
6318 return DCI.DAG.getMemIntrinsicNode(Opcode, SDLoc(N), N->getVTList(), Operands,
6319 ST->getMemoryVT(), ST->getMemOperand());
6320}
6321
6323 const NVPTXSubtarget &STI) {
6324
6325 if (DCI.isBeforeLegalize() && N->getOpcode() == ISD::STORE) {
6326 // Here is our chance to custom lower a store with a non-simple type.
6327 // Unfortunately, we can't do this in the legalizer because there is no
6328 // way to setOperationAction for an non-simple type.
6330 if (!ST->getValue().getValueType().isSimple())
6331 return lowerSTOREVector(SDValue(ST, 0), DCI.DAG, STI);
6332 }
6333
6334 return combinePackingMovIntoStore(N, DCI, 1, 2);
6335}
6336
6338 const NVPTXSubtarget &STI) {
6339 if (DCI.isBeforeLegalize() && N->getOpcode() == ISD::LOAD) {
6340 // Here is our chance to custom lower a load with a non-simple type.
6341 // Unfortunately, we can't do this in the legalizer because there is no
6342 // way to setOperationAction for an non-simple type.
6343 if (!N->getValueType(0).isSimple())
6344 return lowerLoadVector(N, DCI.DAG, STI);
6345 }
6346
6347 return combineUnpackingMovIntoLoad(N, DCI);
6348}
6349
6350/// PerformADDCombine - Target-specific dag combine xforms for ISD::ADD.
6351///
6354 CodeGenOptLevel OptLevel) {
6355 if (OptLevel == CodeGenOptLevel::None)
6356 return SDValue();
6357
6358 SDValue N0 = N->getOperand(0);
6359 SDValue N1 = N->getOperand(1);
6360
6361 // Skip non-integer, non-scalar case
6362 EVT VT = N0.getValueType();
6363 if (VT.isVector() || VT != MVT::i32)
6364 return SDValue();
6365
6366 // First try with the default operand order.
6367 if (SDValue Result = PerformADDCombineWithOperands(N, N0, N1, DCI))
6368 return Result;
6369
6370 // If that didn't work, try again with the operands commuted.
6371 return PerformADDCombineWithOperands(N, N1, N0, DCI);
6372}
6373
6374/// Check if a v2f32 BUILD_VECTOR provably packs values from non-adjacent
6375/// register pairs (non-coalescable).
6376static bool isNonCoalescableBuildVector(const SDValue &BV) {
6377 if (BV.getOpcode() != ISD::BUILD_VECTOR || BV.getValueType() != MVT::v2f32)
6378 return false;
6379
6380 SDValue Elt0 = BV.getOperand(0);
6381 SDValue Elt1 = BV.getOperand(1);
6382
6383 bool IsExt0 = Elt0.getOpcode() == ISD::EXTRACT_VECTOR_ELT;
6384 bool IsExt1 = Elt1.getOpcode() == ISD::EXTRACT_VECTOR_ELT;
6385
6386 // If neither element is an EXTRACT_VECTOR_ELT they are free-standing
6387 // scalars and the register allocator can still place them side-by-side.
6388 if (!IsExt0 && !IsExt1)
6389 return false;
6390
6391 // If exactly one element is an EXTRACT_VECTOR_ELT, the other is a scalar
6392 // that cannot generally occupy the adjacent register slot.
6393 if (IsExt0 != IsExt1)
6394 return true;
6395
6396 // At this point both sources are extracting from vectors. If they are from
6397 // different vectors, then the BUILD_VECTOR is non-coalescable.
6398 SDValue Src0 = Elt0.getOperand(0);
6399 SDValue Src1 = Elt1.getOperand(0);
6400 if (Src0 != Src1)
6401 return true;
6402
6403 auto *Idx0 = dyn_cast<ConstantSDNode>(Elt0.getOperand(1));
6404 auto *Idx1 = dyn_cast<ConstantSDNode>(Elt1.getOperand(1));
6405 // If both indices are dynamic they will be lowered to
6406 // loads and the vector will be spilled to local memory. The register
6407 // allocator can easily place the results in adjacent registers.
6408 if (!Idx0 && !Idx1)
6409 return false;
6410
6411 // If one index is dynamic and the other is constant, the value from the
6412 // constant load will result in an additional register to pair with the result
6413 // from the dynamic load. We consider this non-coalescable.
6414 if ((Idx0 && !Idx1) || (!Idx0 && Idx1))
6415 return true;
6416
6417 // Both are constant, adjacent pairs are coalescable
6418 return std::abs(Idx0->getSExtValue() - Idx1->getSExtValue()) != 1;
6419}
6420
6421/// Return true if FMUL v2f32 node \p N may be scalarized to fold each lane's
6422/// product into a scalar FMA.
6423bool NVPTXTargetLowering::mayFoldFMULIntoFMA(SDNode *N, MachineFunction &MF,
6424 CodeGenOptLevel OptLevel) const {
6425 if (N->getOpcode() != ISD::FMUL || N->getValueType(0) != MVT::v2f32)
6426 return false;
6427 const bool GlobalFMA = allowFMA(MF, OptLevel);
6428 if (!N->getFlags().hasAllowContract() && !GlobalFMA)
6429 return false;
6430
6431 const SDNode *FirstFAdd = nullptr;
6432 unsigned NumScalarFAdd = 0;
6433
6434 // Both lanes must feed unique FADDs
6435 for (SDNode *EE : N->users()) {
6436 if (NumScalarFAdd == 2)
6437 return false;
6438
6439 if (EE->getOpcode() != ISD::EXTRACT_VECTOR_ELT || !EE->hasOneUse() ||
6440 !isa<ConstantSDNode>(EE->getOperand(1)))
6441 return false;
6442
6443 const SDNode *const FAdd = *EE->users().begin();
6444 if (FAdd->getOpcode() != ISD::FADD ||
6445 (!GlobalFMA && !FAdd->getFlags().hasAllowContract()))
6446 return false;
6447
6448 if (!FirstFAdd)
6449 FirstFAdd = FAdd;
6450 else if (FAdd == FirstFAdd)
6451 return false;
6452
6453 NumScalarFAdd++;
6454 }
6455
6456 return NumScalarFAdd == 2;
6457}
6458
6459/// Scalarize a v2f32 arithmetic node (FADD, FMUL, FSUB, FMA) when at least
6460/// one operand is a BUILD_VECTOR that repacks values from non-adjacent register
6461/// pairs. Without this combine the BUILD_VECTOR forces allocation of a
6462/// temporary 64-bit register, increasing register pressure.
6463///
6464/// Example - before:
6465/// t0: v2f32,v2f32,ch = LoadV2 ...
6466/// t1: f32 = extract_vector_elt t0, 0
6467/// t2: f32 = extract_vector_elt t0:1, 0
6468/// t3: v2f32 = BUILD_VECTOR t1, t2 ;; non-coalescable repack
6469/// t4: v2f32 = fma t_a, t3, t_c
6470///
6471/// After:
6472/// t0: v2f32,v2f32,ch = LoadV2 ...
6473/// t1: f32 = extract_vector_elt t0, 0
6474/// t2: f32 = extract_vector_elt t0:1, 0
6475/// a0: f32 = extract_vector_elt t_a, 0
6476/// a1: f32 = extract_vector_elt t_a, 1
6477/// c0: f32 = extract_vector_elt t_c, 0
6478/// c1: f32 = extract_vector_elt t_c, 1
6479/// r0: f32 = fma a0, t1, c0
6480/// r1: f32 = fma a1, t2, c1
6481/// t4: v2f32 = BUILD_VECTOR r0, r1
6482///
6483/// Also scalarizes an FMUL when all output lanes feed into scalar FADDs
6484/// to enable scalar FMA combining.
6485SDValue NVPTXTargetLowering::performScalarizeV2F32Op(
6487 CodeGenOptLevel OptLevel) const {
6488 EVT VT = N->getValueType(0);
6489 if (VT != MVT::v2f32)
6490 return SDValue();
6491
6492 if (none_of(N->ops(), isNonCoalescableBuildVector) &&
6493 !mayFoldFMULIntoFMA(N, DCI.DAG.getMachineFunction(), OptLevel))
6494 return SDValue();
6495
6496 SelectionDAG &DAG = DCI.DAG;
6497 SDLoc DL(N);
6498 EVT EltVT = VT.getVectorElementType();
6499 unsigned Opc = N->getOpcode();
6500
6501 // For each operand, get the scalar element at the given index: if the operand
6502 // is a BUILD_VECTOR, grab the element directly; otherwise, emit an
6503 // EXTRACT_VECTOR_ELT.
6504 auto GetElement = [&](SDValue Op, unsigned Index) -> SDValue {
6505 if (Op.getOpcode() == ISD::BUILD_VECTOR)
6506 return Op.getOperand(Index);
6507 return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, EltVT, Op,
6508 DAG.getVectorIdxConstant(Index, DL));
6509 };
6510
6511 // Build scalar operand lists for element 0 and element 1.
6512 SmallVector<SDValue, 3> Ops0, Ops1;
6513 for (const SDValue &Op : N->ops()) {
6514 Ops0.push_back(GetElement(Op, 0));
6515 Ops1.push_back(GetElement(Op, 1));
6516 }
6517
6518 SDValue Res0 = DAG.getNode(Opc, DL, EltVT, Ops0, N->getFlags());
6519 SDValue Res1 = DAG.getNode(Opc, DL, EltVT, Ops1, N->getFlags());
6520
6521 return DAG.getNode(ISD::BUILD_VECTOR, DL, VT, Res0, Res1);
6522}
6523
6524/// Target-specific dag combine xforms for ISD::FADD.
6525SDValue
6526NVPTXTargetLowering::performFADDCombine(SDNode *N,
6528 CodeGenOptLevel OptLevel) const {
6529 if (SDValue Result = performScalarizeV2F32Op(N, DCI, OptLevel))
6530 return Result;
6531
6532 SDValue N0 = N->getOperand(0);
6533 SDValue N1 = N->getOperand(1);
6534
6535 EVT VT = N0.getValueType();
6536 if (VT.isVector() || !(VT == MVT::f32 || VT == MVT::f64))
6537 return SDValue();
6538
6539 // First try with the default operand order.
6540 if (SDValue Result = performFADDCombineWithOperands(N, N0, N1, DCI, OptLevel))
6541 return Result;
6542
6543 // If that didn't work, try again with the operands commuted.
6544 return performFADDCombineWithOperands(N, N1, N0, DCI, OptLevel);
6545}
6546
6547/// Get 3-input version of a 2-input min/max opcode
6548static unsigned getMinMax3Opcode(unsigned MinMax2Opcode) {
6549 switch (MinMax2Opcode) {
6550 case ISD::FMAXNUM:
6551 case ISD::FMAXIMUMNUM:
6552 return NVPTXISD::FMAXNUM3;
6553 case ISD::FMINNUM:
6554 case ISD::FMINIMUMNUM:
6555 return NVPTXISD::FMINNUM3;
6556 case ISD::FMAXIMUM:
6557 return NVPTXISD::FMAXIMUM3;
6558 case ISD::FMINIMUM:
6559 return NVPTXISD::FMINIMUM3;
6560 default:
6561 llvm_unreachable("Invalid 2-input min/max opcode");
6562 }
6563}
6564
6565/// PerformFMinMaxCombine - Combine (fmaxnum (fmaxnum a, b), c) into
6566/// (fmaxnum3 a, b, c). Also covers other llvm min/max intrinsics.
6569 const NVPTXSubtarget &STI) {
6570
6571 // 3-input min/max requires PTX 8.8+ and SM_100+, and only supports f32s
6572 EVT VT = N->getValueType(0);
6573 if (VT != MVT::f32 || !STI.hasFeature(NVPTX::PTX88) ||
6574 !STI.hasFeature(NVPTX::SM100))
6575 return SDValue();
6576
6577 SDValue Op0 = N->getOperand(0);
6578 SDValue Op1 = N->getOperand(1);
6579 unsigned MinMaxOp2 = N->getOpcode();
6580 unsigned MinMaxOp3 = getMinMax3Opcode(MinMaxOp2);
6581
6582 if (Op0.getOpcode() == MinMaxOp2 && Op0.hasOneUse()) {
6583 // (maxnum (maxnum a, b), c) -> (maxnum3 a, b, c)
6584 SDValue A = Op0.getOperand(0);
6585 SDValue B = Op0.getOperand(1);
6586 SDValue C = Op1;
6587 return DCI.DAG.getNode(MinMaxOp3, SDLoc(N), VT, A, B, C, N->getFlags());
6588 } else if (Op1.getOpcode() == MinMaxOp2 && Op1.hasOneUse()) {
6589 // (maxnum a, (maxnum b, c)) -> (maxnum3 a, b, c)
6590 SDValue A = Op0;
6591 SDValue B = Op1.getOperand(0);
6592 SDValue C = Op1.getOperand(1);
6593 return DCI.DAG.getNode(MinMaxOp3, SDLoc(N), VT, A, B, C, N->getFlags());
6594 }
6595 return SDValue();
6596}
6597
6598// sext (mul.iN nsw x, y) => mul.wide.sN x, y
6599// zext (mul.iN nuw x, y) => mul.wide.uN x, y
6600// sext (shl.iN nsw x, const) => mul.wide.sN x, (1 << const)
6601// zext (shl.iN nuw x, const) => mul.wide.uN x, (1 << const)
6604 CodeGenOptLevel OptLevel) {
6605 assert(N->getOpcode() == ISD::SIGN_EXTEND ||
6606 N->getOpcode() == ISD::ZERO_EXTEND);
6607
6608 if (OptLevel == CodeGenOptLevel::None)
6609 return SDValue();
6610
6611 SDValue Op = N->getOperand(0);
6612 if (!Op.hasOneUse())
6613 return SDValue();
6614
6615 EVT ToVT = N->getValueType(0);
6616 EVT FromVT = Op.getValueType();
6617 if (!((ToVT == MVT::i32 && FromVT == MVT::i16) ||
6618 (ToVT == MVT::i64 && FromVT == MVT::i32)))
6619 return SDValue();
6620
6621 bool IsSigned = N->getOpcode() == ISD::SIGN_EXTEND;
6622 if ((IsSigned && !Op->getFlags().hasNoSignedWrap()) ||
6623 (!IsSigned && !Op->getFlags().hasNoUnsignedWrap()))
6624 return SDValue();
6625
6626 SDLoc DL(N);
6627 SDValue LHS = Op.getOperand(0);
6628 SDValue RHS = Op.getOperand(1);
6629 unsigned MulWideOpcode =
6630 IsSigned ? NVPTXISD::MUL_WIDE_SIGNED : NVPTXISD::MUL_WIDE_UNSIGNED;
6631 if (Op.getOpcode() == ISD::MUL) {
6632 return DCI.DAG.getNode(MulWideOpcode, DL, ToVT, LHS, RHS);
6633 } else if (Op.getOpcode() == ISD::SHL && isa<ConstantSDNode>(RHS)) {
6634 const auto ShiftAmt = Op.getConstantOperandVal(1);
6635 const auto MulVal = APInt(FromVT.getSizeInBits(), 1) << ShiftAmt;
6636
6637 // Note that the sext (shl nsw ...) case doesn't work if 1 << const
6638 // overflows to a negative value! The only valid input values in this
6639 // case are 0 and -1 (all other values yield poison because of the nsw),
6640 // and mul.wide.sN would give us the wrong sign for -1. We could use
6641 // mul.wide.uN, but since this is a weird case anyway, we might as well not
6642 // apply this transformation at all.
6643 if (IsSigned && MulVal.isNegative())
6644 return SDValue();
6645
6646 RHS = DCI.DAG.getConstant(MulVal, DL, FromVT);
6647 return DCI.DAG.getNode(MulWideOpcode, DL, ToVT, LHS, RHS);
6648 }
6649
6650 return SDValue();
6651}
6652
6653/// Check whether Op is explicitly extended from at most \p OptSize bits,
6654/// setting \p IsSigned to the signedness of the extension.
6655static bool IsExtendedFromLte(SDValue Op, unsigned OptSize, bool &IsSigned) {
6656 if (Op.getOpcode() == ISD::SIGN_EXTEND ||
6657 Op.getOpcode() == ISD::SIGN_EXTEND_INREG) {
6658 EVT OrigVT = Op.getOperand(0).getValueType();
6659 if (OrigVT.getFixedSizeInBits() <= OptSize) {
6660 IsSigned = true;
6661 return true;
6662 }
6663 } else if (Op.getOpcode() == ISD::ZERO_EXTEND) {
6664 EVT OrigVT = Op.getOperand(0).getValueType();
6665 if (OrigVT.getFixedSizeInBits() <= OptSize) {
6666 IsSigned = false;
6667 return true;
6668 }
6669 }
6670
6671 return false;
6672}
6673
6674/// AreMulWideOperandsDemotable - Checks if the given LHS and RHS operands can
6675/// be demoted to \p OptSize bits without loss of information using the same
6676/// signedness. The signedness of the operands is placed in \p IsSigned.
6678 unsigned OptSize,
6679 const SelectionDAG &DAG,
6680 bool &IsSigned) {
6681 // The native register size is 32 bits, so extending i16 to i32 is often
6682 // cheap, whereas truncating i64 to i32 is free. Use known bits to narrow
6683 // i64 products, and require explicit extensions for i32 products.
6684 if (LHS.getValueType() != MVT::i64) {
6685 if (!IsExtendedFromLte(LHS, OptSize, IsSigned))
6686 return false;
6687
6688 if (auto *CI = dyn_cast<ConstantSDNode>(RHS)) {
6689 const APInt &Val = CI->getAPIntValue();
6690 return IsSigned ? Val.isSignedIntN(OptSize) : Val.isIntN(OptSize);
6691 }
6692
6693 bool RHSSigned;
6694 return IsExtendedFromLte(RHS, OptSize, RHSSigned) && IsSigned == RHSSigned;
6695 }
6696
6697 // Extensions may have been folded into masks, shifts, or other operations.
6698 // Check the values' widths rather than requiring explicit extension nodes.
6699 if (DAG.computeKnownBits(LHS).countMaxActiveBits() <= OptSize &&
6700 DAG.computeKnownBits(RHS).countMaxActiveBits() <= OptSize) {
6701 IsSigned = false;
6702 return true;
6703 }
6704 if (DAG.ComputeMaxSignificantBits(LHS) <= OptSize &&
6705 DAG.ComputeMaxSignificantBits(RHS) <= OptSize) {
6706 IsSigned = true;
6707 return true;
6708 }
6709 return false;
6710}
6711
6712/// TryMULWIDECombine - Attempt to replace a multiply of M bits with a multiply
6713/// of M/2 bits that produces an M-bit result (i.e. mul.wide). This transform
6714/// works on both multiply DAG nodes and SHL DAG nodes with a constant shift
6715/// amount.
6718 EVT MulType = N->getValueType(0);
6719 if (MulType != MVT::i32 && MulType != MVT::i64) {
6720 return SDValue();
6721 }
6722
6723 SDLoc DL(N);
6724 unsigned OptSize = MulType.getSizeInBits() >> 1;
6725 SDValue LHS = N->getOperand(0);
6726 SDValue RHS = N->getOperand(1);
6727
6728 // Canonicalize the multiply so the constant (if any) is on the right
6729 if (N->getOpcode() == ISD::MUL) {
6730 if (isa<ConstantSDNode>(LHS)) {
6731 std::swap(LHS, RHS);
6732 }
6733 }
6734
6735 bool Signed;
6736 // If we have a SHL, determine the actual multiply amount.
6737 if (N->getOpcode() == ISD::SHL) {
6738 // A plain shift is already one instruction. Only fold it when doing so
6739 // can also remove an explicit extension.
6740 if (!IsExtendedFromLte(LHS, OptSize, Signed))
6741 return SDValue();
6742
6744 if (!ShlRHS) {
6745 return SDValue();
6746 }
6747
6748 APInt ShiftAmt = ShlRHS->getAPIntValue();
6749 unsigned BitWidth = MulType.getSizeInBits();
6750 unsigned Limit = Signed ? OptSize - 1 : OptSize;
6751 if (ShiftAmt.sge(0) && ShiftAmt.slt(Limit)) {
6752 APInt MulVal = APInt(BitWidth, 1) << ShiftAmt;
6753 RHS = DCI.DAG.getConstant(MulVal, DL, MulType);
6754 } else {
6755 return SDValue();
6756 }
6757 } else if (!AreMulWideOperandsDemotable(LHS, RHS, OptSize, DCI.DAG, Signed)) {
6758 return SDValue();
6759 }
6760
6761 if (N->getOpcode() == ISD::MUL) {
6762 // Keep matching low/high products together so ptxas can share their
6763 // partial products. Widening only the low product can duplicate work and
6764 // increase register pressure, even when its operands fit the narrow type.
6765 for (unsigned Opc : {ISD::MULHU, ISD::MULHS}) {
6766 if (SDNode *Hi = DCI.DAG.getNodeIfExists(Opc, N->getVTList(), {LHS, RHS}))
6767 if (!Hi->use_empty())
6768 return SDValue();
6769 if (SDNode *Hi = DCI.DAG.getNodeIfExists(Opc, N->getVTList(), {RHS, LHS}))
6770 if (!Hi->use_empty())
6771 return SDValue();
6772 }
6773 }
6774
6775 EVT DemotedVT;
6776 if (MulType == MVT::i32) {
6777 DemotedVT = MVT::i16;
6778 } else {
6779 DemotedVT = MVT::i32;
6780 }
6781
6782 // Truncate the operands to the correct size. Note that these are just for
6783 // type consistency and will (likely) be eliminated in later phases.
6784 SDValue TruncLHS =
6785 DCI.DAG.getNode(ISD::TRUNCATE, DL, DemotedVT, LHS);
6786 SDValue TruncRHS =
6787 DCI.DAG.getNode(ISD::TRUNCATE, DL, DemotedVT, RHS);
6788
6789 unsigned Opc;
6790 if (Signed) {
6791 Opc = NVPTXISD::MUL_WIDE_SIGNED;
6792 } else {
6793 Opc = NVPTXISD::MUL_WIDE_UNSIGNED;
6794 }
6795
6796 return DCI.DAG.getNode(Opc, DL, MulType, TruncLHS, TruncRHS);
6797}
6798
6799static bool isConstOne(const SDValue &Operand) {
6800 const auto *Const = dyn_cast<ConstantSDNode>(Operand);
6801 return Const && Const->getZExtValue() == 1;
6802}
6803
6805 if (Add->getOpcode() != ISD::ADD)
6806 return SDValue();
6807
6808 if (isConstOne(Add->getOperand(0)))
6809 return Add->getOperand(1);
6810
6811 if (isConstOne(Add->getOperand(1)))
6812 return Add->getOperand(0);
6813
6814 return SDValue();
6815}
6816
6819
6821 SDValue Mul = DCI.DAG.getNode(ISD::MUL, DL, VT, X, Y);
6822 return DCI.DAG.getNode(ISD::ADD, DL, VT, Mul, X);
6823 }
6824
6825 return SDValue();
6826}
6827
6829 SDLoc DL,
6831 if (Select->getOpcode() != ISD::SELECT)
6832 return SDValue();
6833
6834 SDValue Cond = Select->getOperand(0);
6835
6836 unsigned ConstOpNo;
6837 if (isConstOne(Select->getOperand(1)))
6838 ConstOpNo = 1;
6839 else if (isConstOne(Select->getOperand(2)))
6840 ConstOpNo = 2;
6841 else
6842 return SDValue();
6843
6844 SDValue Y = Select->getOperand((ConstOpNo == 1) ? 2 : 1);
6845
6846 // Do not combine if the resulting sequence is not obviously profitable.
6848 return SDValue();
6849
6850 SDValue NewMul = DCI.DAG.getNode(ISD::MUL, DL, VT, X, Y);
6851
6852 return DCI.DAG.getNode(ISD::SELECT, DL, VT, Cond,
6853 (ConstOpNo == 1) ? X : NewMul,
6854 (ConstOpNo == 1) ? NewMul : X);
6855}
6856
6857static SDValue
6860
6861 EVT VT = N0.getValueType();
6862 if (VT.isVector())
6863 return SDValue();
6864
6865 if (VT != MVT::i16 && VT != MVT::i32 && VT != MVT::i64)
6866 return SDValue();
6867
6868 SDLoc DL(N);
6869
6870 // (mul x, (add y, 1)) -> (add (mul x, y), x)
6871 if (SDValue Res = combineMADConstOne(N0, N1, VT, DL, DCI))
6872 return Res;
6873 if (SDValue Res = combineMADConstOne(N1, N0, VT, DL, DCI))
6874 return Res;
6875
6876 // (mul x, (select y, 1)) -> (select (mul x, y), x)
6877 if (SDValue Res = combineMulSelectConstOne(N0, N1, VT, DL, DCI))
6878 return Res;
6879 if (SDValue Res = combineMulSelectConstOne(N1, N0, VT, DL, DCI))
6880 return Res;
6881
6882 return SDValue();
6883}
6884
6885/// PerformMULCombine - Runs PTX-specific DAG combine patterns on MUL nodes.
6888 CodeGenOptLevel OptLevel) {
6889 if (OptLevel == CodeGenOptLevel::None)
6890 return SDValue();
6891
6892 if (SDValue Ret = TryMULWIDECombine(N, DCI))
6893 return Ret;
6894
6895 SDValue N0 = N->getOperand(0);
6896 SDValue N1 = N->getOperand(1);
6897 return PerformMULCombineWithOperands(N, N0, N1, DCI);
6898}
6899
6900/// Commute SHL with a bitwise logic operation when doing so exposes a common
6901/// shifted operand. For example:
6902///
6903/// Before:
6904/// N = shl (zext (LogicOp X, C)), ShiftAmount
6905/// OtherShift = shl (zext (OtherLogicOp X, OtherC)), ShiftAmount
6906///
6907/// After:
6908/// ShiftedX = shl (zext X), ShiftAmount
6909/// N = LogicOp ShiftedX, ShiftedC
6910/// OtherShift = OtherLogicOp ShiftedX, ShiftedOtherC
6911///
6912/// ShiftedC = (zext C) << ShiftAmount and ShiftedOtherC =
6913/// (zext OtherC) << ShiftAmount are folded constants. This replaces two
6914/// variable shifts with the single shared ShiftedX. Requiring another matching
6915/// shift avoids disrupting isolated address calculations where a shift may be
6916/// folded into the addressing mode.
6919 using namespace SDPatternMatch;
6920
6921 struct ShiftOfLogicOp {
6922 SDNode *Shift;
6923 SDValue LogicOp;
6924 SDValue X;
6926 unsigned ExtendOpcode;
6927 };
6928
6929 // Match a logic operation, with an optional extension, inside a SHL.
6930 auto matchShiftOfLogicOp =
6931 [&](SDNode *Shift) -> std::optional<ShiftOfLogicOp> {
6932 if (Shift->getOpcode() != ISD::SHL || !Shift->getOperand(0).hasOneUse())
6933 return std::nullopt;
6934 ShiftOfLogicOp Match;
6935 Match.Shift = Shift;
6936 Match.LogicOp = Shift->getOperand(0);
6937 Match.ExtendOpcode = 0;
6938 if (ISD::isExtOpcode(Match.LogicOp.getOpcode())) {
6939 Match.ExtendOpcode = Match.LogicOp.getOpcode();
6940 Match.LogicOp = Match.LogicOp.getOperand(0);
6941 }
6942
6943 if (!sd_match(Match.LogicOp, m_OneUse(m_BitwiseLogic(
6944 m_Value(Match.X),
6945 m_Value(Match.Constant, m_ConstInt())))))
6946 return std::nullopt;
6947
6948 return Match;
6949 };
6950
6951 // Match N as the root shift-of-logic; bail if it does not fit the pattern.
6952 const std::optional<ShiftOfLogicOp> Root = matchShiftOfLogicOp(N);
6953 if (!Root)
6954 return SDValue();
6955
6956 // Only profitable for a constant shift amount: the per-op constant shift then
6957 // folds away instead of becoming an extra variable shift.
6958 if (!isConstOrConstSplat(N->getOperand(1)))
6959 return SDValue();
6960
6961 // Collect candidate shifts that share X. Reached through another user of X,
6962 // the logic result feeds the shift directly or through an optional extend.
6963 SmallVector<SDNode *, 4> CandidateShifts;
6964 for (const SDNode *CandidateLogicOp : Root->X->users()) {
6965 if (CandidateLogicOp == Root->LogicOp.getNode())
6966 continue;
6967 for (SDNode *LogicUser : CandidateLogicOp->users()) {
6968 if (ISD::isExtOpcode(LogicUser->getOpcode())) {
6969 // shl (ext (logic X, C)): step through the extend to find the shift.
6970 for (SDNode *ExtendUser : LogicUser->users())
6971 if (ExtendUser->getOpcode() == ISD::SHL)
6972 CandidateShifts.push_back(ExtendUser);
6973 } else if (LogicUser->getOpcode() == ISD::SHL) {
6974 // shl (logic X, C): the user is already the shift.
6975 CandidateShifts.push_back(LogicUser);
6976 }
6977 }
6978 }
6979
6980 // Verify each candidate against the root's pattern: the same X, extension,
6981 // type, and shift amount.
6982 const EVT VT = N->getValueType(0);
6983 const SDValue ShiftAmount = N->getOperand(1);
6985 for (SDNode *CandidateShift : CandidateShifts) {
6986 const std::optional<ShiftOfLogicOp> Candidate =
6987 matchShiftOfLogicOp(CandidateShift);
6988 if (Candidate && Candidate->X == Root->X &&
6989 Candidate->ExtendOpcode == Root->ExtendOpcode &&
6990 CandidateShift->getValueType(0) == VT &&
6991 CandidateShift->getOperand(1) == ShiftAmount)
6992 Matches.push_back(*Candidate);
6993 }
6994 if (Matches.empty())
6995 return SDValue();
6996
6997 // Build the shared shifted X once, then rewrite the root and every match
6998 // into a logic op over it so the shift is CSE'd.
6999 SelectionDAG &DAG = DCI.DAG;
7000 const SDValue ShiftedX =
7001 DAG.getNode(ISD::SHL, SDLoc(N), VT,
7002 Root->ExtendOpcode
7003 ? DAG.getNode(Root->ExtendOpcode, SDLoc(N), VT, Root->X)
7004 : Root->X,
7005 ShiftAmount);
7006
7007 // Rebuild the logic op from shared ShiftedX and a folded constant shift.
7008 auto buildCommutedLogicOp = [&](const SDValue LogicOp, SDValue C,
7009 const SDLoc &DL) {
7010 if (Root->ExtendOpcode)
7011 C = DAG.getNode(Root->ExtendOpcode, DL, VT, C);
7012 const SDValue ShiftedC = DAG.getNode(ISD::SHL, DL, VT, C, ShiftAmount);
7013 return DAG.getNode(LogicOp.getOpcode(), DL, VT, ShiftedX, ShiftedC,
7014 LogicOp->getFlags());
7015 };
7016
7017 for (const ShiftOfLogicOp &Match : Matches)
7018 DCI.CombineTo(Match.Shift,
7019 buildCommutedLogicOp(Match.LogicOp, Match.Constant,
7020 SDLoc(Match.Shift)));
7021 return buildCommutedLogicOp(Root->LogicOp, Root->Constant, SDLoc(N));
7022}
7023
7024/// PerformSHLCombine - Runs PTX-specific DAG combine patterns on SHL nodes.
7027 CodeGenOptLevel OptLevel) {
7028 if (OptLevel > CodeGenOptLevel::None) {
7029 // Expose a shared shifted operand for CSE before mul.wide folding, which
7030 // would otherwise consume the shift.
7031 if (SDValue Ret = combineShiftOfLogicOp(N, DCI))
7032 return Ret;
7033
7034 // Try mul.wide combining at OptLevel > 0
7035 if (SDValue Ret = TryMULWIDECombine(N, DCI))
7036 return Ret;
7037 }
7038
7039 return SDValue();
7040}
7041
7044 const NVPTXSubtarget &STI) {
7045 EVT CCType = N->getValueType(0);
7046 SDValue A = N->getOperand(0);
7047 SDValue B = N->getOperand(1);
7048
7049 EVT AType = A.getValueType();
7050 if (!(CCType == MVT::v2i1 && (AType == MVT::v2f16 || AType == MVT::v2bf16)))
7051 return SDValue();
7052
7053 if (A.getValueType() == MVT::v2bf16 && !STI.hasFeature(NVPTX::SM90))
7054 return SDValue();
7055
7056 SDLoc DL(N);
7057 // setp.f16x2 returns two scalar predicates, which we need to
7058 // convert back to v2i1. The returned result will be scalarized by
7059 // the legalizer, but the comparison will remain a single vector
7060 // instruction.
7061 SDValue CCNode = DCI.DAG.getNode(
7062 A.getValueType() == MVT::v2f16 ? NVPTXISD::SETP_F16X2
7064 DL, DCI.DAG.getVTList(MVT::i1, MVT::i1), {A, B, N->getOperand(2)});
7065 return DCI.DAG.getNode(ISD::BUILD_VECTOR, DL, CCType, CCNode.getValue(0),
7066 CCNode.getValue(1));
7067}
7068
7071 SDValue Vector = peekThroughFreeze(N->getOperand(0));
7072 SDLoc DL(N);
7073 EVT VectorVT = Vector.getValueType();
7074 if (Vector->getOpcode() == ISD::LOAD && VectorVT.isSimple() &&
7075 IsPTXVectorType(VectorVT.getSimpleVT()))
7076 return SDValue(); // Native vector loads already combine nicely w/
7077 // extract_vector_elt.
7078 // Don't mess with singletons or packed types (v2*32, v2*16, v4i8 and v8i8),
7079 // we already handle them OK.
7080 if (VectorVT.getVectorNumElements() == 1 ||
7081 NVPTX::isPackedVectorTy(VectorVT) || VectorVT == MVT::v8i8)
7082 return SDValue();
7083
7084 // Don't mess with undef values as sra may be simplified to 0, not undef.
7085 if (Vector->isUndef() || ISD::allOperandsUndef(Vector.getNode()))
7086 return SDValue();
7087
7088 uint64_t VectorBits = VectorVT.getSizeInBits();
7089 // We only handle the types we can extract in-register.
7090 if (!(VectorBits == 16 || VectorBits == 32 || VectorBits == 64))
7091 return SDValue();
7092
7093 ConstantSDNode *Index = dyn_cast<ConstantSDNode>(N->getOperand(1));
7094 // Index == 0 is handled by generic DAG combiner.
7095 if (!Index || Index->getZExtValue() == 0)
7096 return SDValue();
7097
7098 MVT IVT = MVT::getIntegerVT(VectorBits);
7099 EVT EltVT = VectorVT.getVectorElementType();
7100 EVT EltIVT = EltVT.changeTypeToInteger();
7101 uint64_t EltBits = EltVT.getScalarSizeInBits();
7102
7103 SDValue Result = DCI.DAG.getNode(
7104 ISD::TRUNCATE, DL, EltIVT,
7105 DCI.DAG.getNode(
7106 ISD::SRA, DL, IVT, DCI.DAG.getNode(ISD::BITCAST, DL, IVT, Vector),
7107 DCI.DAG.getConstant(Index->getZExtValue() * EltBits, DL, IVT)));
7108
7109 // If element has non-integer type, bitcast it back to the expected type.
7110 if (EltVT != EltIVT)
7111 Result = DCI.DAG.getNode(ISD::BITCAST, DL, EltVT, Result);
7112 // Past legalizer, we may need to extent i8 -> i16 to match the register type.
7113 if (EltVT != N->getValueType(0))
7114 Result = DCI.DAG.getNode(ISD::ANY_EXTEND, DL, N->getValueType(0), Result);
7115
7116 return Result;
7117}
7118
7119/// Transform patterns like:
7120/// (select (ugt shift_amt, BitWidth-1), 0, (srl/shl x, shift_amt))
7121/// (select (ult shift_amt, BitWidth), (srl/shl x, shift_amt), 0)
7122/// Into:
7123/// (NVPTXISD::SRL_CLAMP x, shift_amt) or (NVPTXISD::SHL_CLAMP x, shift_amt)
7124///
7125/// These patterns arise from code like `s >= 32 ? 0 : x >> s`. In LLVM,
7126/// over-shifting a value results in poison, but PTX shr/shl instructions clamp
7127/// the shift amount to BitWidth, making the guard redundant.
7128///
7129/// Note: We only handle SRL and SHL, not SRA, because arithmetic right shifts
7130/// can produce 0 or -1 when shift >= BitWidth.
7131/// Note: We don't handle uge or ule. These don't appear because of
7132/// canonicalization.
7135 if (!DCI.isAfterLegalizeDAG())
7136 return SDValue();
7137
7138 using namespace SDPatternMatch;
7139 unsigned BitWidth = N->getValueType(0).getSizeInBits();
7140 SDValue ShiftAmt, ShiftOp;
7141
7142 // Match logical shifts where the shift amount in the guard matches the shift
7143 // amount in the operation.
7144 auto LogicalShift = m_Value(
7145 ShiftOp, m_AnyOf(m_Srl(m_Value(), m_TruncOrSelf(m_Deferred(ShiftAmt))),
7146 m_Shl(m_Value(), m_TruncOrSelf(m_Deferred(ShiftAmt)))));
7147
7148 // shift_amt > BitWidth-1 ? 0 : shift_op
7149 bool MatchedUGT = sd_match(
7150 N, m_Select(m_SpecificSetCC(ISD::SETUGT, m_Value(ShiftAmt),
7152 m_Zero(), LogicalShift));
7153 // shift_amt < BitWidth ? shift_op : 0
7154 bool MatchedULT =
7155 !MatchedUGT &&
7156 sd_match(
7157 N, m_Select(m_SpecificSetCC(ISD::SETULT, m_Value(ShiftAmt),
7159 LogicalShift, m_Zero()));
7160
7161 if (!MatchedUGT && !MatchedULT)
7162 return SDValue();
7163
7164 // In LLVM IR, the shift amount and the value-to-be-shifted are the same
7165 // type, whereas in PTX the shift amount is always i32. Therefore when
7166 // shifting types larger than i32, we can only do this transformation if we
7167 // know that the upper bits of the shift amount are known zero.
7168 SDValue ClampAmt = ShiftOp.getOperand(1);
7169 unsigned ClampAmtBits = ClampAmt.getValueSizeInBits();
7170 if (ShiftAmt.getValueSizeInBits() > ClampAmtBits &&
7171 DCI.DAG.computeKnownBits(ShiftAmt).countMaxActiveBits() > ClampAmtBits)
7172 return SDValue();
7173
7174 // Return a clamp shift operation, which has the same semantics as PTX shift.
7175 unsigned ClampOpc = ShiftOp.getOpcode() == ISD::SRL ? NVPTXISD::SRL_CLAMP
7176 : NVPTXISD::SHL_CLAMP;
7177 return DCI.DAG.getNode(ClampOpc, SDLoc(N), ShiftOp.getValueType(),
7178 ShiftOp.getOperand(0), ClampAmt);
7179}
7180
7183 SDValue VA = N->getOperand(1);
7184 EVT VectorVT = VA.getValueType();
7185 if (VectorVT != MVT::v4i8)
7186 return SDValue();
7187
7188 // We need to split vselect into individual per-element operations Because we
7189 // use BFE/BFI instruction for byte extraction/insertion, we do end up with
7190 // 32-bit values, so we may as well do comparison as i32 to avoid conversions
7191 // to/from i16 normally used for i8 values.
7193 SDLoc DL(N);
7194 SDValue VCond = N->getOperand(0);
7195 SDValue VB = N->getOperand(2);
7196 for (int I = 0; I < 4; ++I) {
7197 SDValue C = DCI.DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::i1, VCond,
7198 DCI.DAG.getConstant(I, DL, MVT::i32));
7199 SDValue EA = DCI.DAG.getAnyExtOrTrunc(
7200 DCI.DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::i8, VA,
7201 DCI.DAG.getConstant(I, DL, MVT::i32)),
7202 DL, MVT::i32);
7203 SDValue EB = DCI.DAG.getAnyExtOrTrunc(
7204 DCI.DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::i8, VB,
7205 DCI.DAG.getConstant(I, DL, MVT::i32)),
7206 DL, MVT::i32);
7207 E.push_back(DCI.DAG.getAnyExtOrTrunc(
7208 DCI.DAG.getNode(ISD::SELECT, DL, MVT::i32, C, EA, EB), DL, MVT::i8));
7209 }
7210 return DCI.DAG.getNode(ISD::BUILD_VECTOR, DL, MVT::v4i8, E);
7211}
7212
7213static SDValue
7215 auto VT = N->getValueType(0);
7216 if (!DCI.isAfterLegalizeDAG() ||
7217 // only process v2*16 types
7218 !(NVPTX::isPackedVectorTy(VT) && VT.is32BitVector() &&
7219 VT.getVectorNumElements() == 2))
7220 return SDValue();
7221
7222 auto Op0 = N->getOperand(0);
7223 auto Op1 = N->getOperand(1);
7224
7225 // Start out by assuming we want to take the lower 2 bytes of each i32
7226 // operand.
7227 uint64_t Op0Bytes = 0x10;
7228 uint64_t Op1Bytes = 0x54;
7229
7230 std::pair<SDValue *, uint64_t *> OpData[2] = {{&Op0, &Op0Bytes},
7231 {&Op1, &Op1Bytes}};
7232
7233 // Check that each operand is an i16, truncated from an i32 operand. We'll
7234 // select individual bytes from those original operands. Optionally, fold in a
7235 // shift right of that original operand.
7236 for (auto &[Op, OpBytes] : OpData) {
7237 // Eat up any bitcast
7238 if (Op->getOpcode() == ISD::BITCAST)
7239 *Op = Op->getOperand(0);
7240
7241 if (!(Op->getValueType() == MVT::i16 && Op->getOpcode() == ISD::TRUNCATE &&
7242 Op->getOperand(0).getValueType() == MVT::i32))
7243 return SDValue();
7244
7245 // If the truncate has multiple uses, this optimization can increase
7246 // register pressure
7247 if (!Op->hasOneUse())
7248 return SDValue();
7249
7250 *Op = Op->getOperand(0);
7251
7252 // Optionally, fold in a shift-right of the original operand and let permute
7253 // pick the two higher bytes of the original value directly.
7254 if (Op->getOpcode() == ISD::SRL && isa<ConstantSDNode>(Op->getOperand(1))) {
7255 if (cast<ConstantSDNode>(Op->getOperand(1))->getZExtValue() == 16) {
7256 // Shift the PRMT byte selector to pick upper bytes from each respective
7257 // value, instead of the lower ones: 0x10 -> 0x32, 0x54 -> 0x76
7258 assert((*OpBytes == 0x10 || *OpBytes == 0x54) &&
7259 "PRMT selector values out of range");
7260 *OpBytes += 0x22;
7261 *Op = Op->getOperand(0);
7262 }
7263 }
7264 }
7265
7266 SDLoc DL(N);
7267 auto &DAG = DCI.DAG;
7268
7269 auto PRMT =
7270 getPRMT(DAG.getBitcast(MVT::i32, Op0), DAG.getBitcast(MVT::i32, Op1),
7271 (Op1Bytes << 8) | Op0Bytes, DL, DAG);
7272 return DAG.getBitcast(VT, PRMT);
7273}
7274
7277 auto *ASCN1 = cast<AddrSpaceCastSDNode>(N);
7278
7279 if (auto *ASCN2 = dyn_cast<AddrSpaceCastSDNode>(ASCN1->getOperand(0))) {
7280 assert(ASCN2->getDestAddressSpace() == ASCN1->getSrcAddressSpace());
7281
7282 // Fold asc[B -> A](asc[A -> B](x)) -> x
7283 if (ASCN1->getDestAddressSpace() == ASCN2->getSrcAddressSpace())
7284 return ASCN2->getOperand(0);
7285 }
7286
7287 return SDValue();
7288}
7289
7290// Given a constant selector value and a prmt mode, return the selector value
7291// normalized to the generic prmt mode. See the PTX ISA documentation for more
7292// details:
7293// https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#data-movement-and-conversion-instructions-prmt
7294static APInt getPRMTSelector(const APInt &Selector, unsigned Mode) {
7295 assert(Selector.getBitWidth() == 32 && "PRMT must have i32 operands");
7296
7298 return Selector;
7299
7300 const unsigned V = Selector.trunc(2).getZExtValue();
7301
7302 const auto GetSelector = [](unsigned S0, unsigned S1, unsigned S2,
7303 unsigned S3) {
7304 return APInt(32, S0 | (S1 << 4) | (S2 << 8) | (S3 << 12));
7305 };
7306
7307 switch (Mode) {
7309 return GetSelector(V, V + 1, V + 2, V + 3);
7311 return GetSelector(V, (V - 1) & 7, (V - 2) & 7, (V - 3) & 7);
7313 return GetSelector(V, V, V, V);
7315 return GetSelector(V, std::max(V, 1U), std::max(V, 2U), 3U);
7317 return GetSelector(0, std::min(V, 1U), std::min(V, 2U), V);
7319 unsigned V1 = (V & 1) << 1;
7320 return GetSelector(V1, V1 + 1, V1, V1 + 1);
7321 }
7322 default:
7323 llvm_unreachable("Invalid PRMT mode");
7324 }
7325}
7326
7327static APInt computePRMT(APInt A, APInt B, APInt Selector, unsigned Mode) {
7328 assert(A.getBitWidth() == 32 && B.getBitWidth() == 32 &&
7329 Selector.getBitWidth() == 32 && "PRMT must have i32 operands");
7330 // {b, a} = {{b7, b6, b5, b4}, {b3, b2, b1, b0}}
7331 APInt BitField = B.concat(A);
7332 APInt SelectorVal = getPRMTSelector(Selector, Mode);
7333 APInt Result(32, 0);
7334 for (unsigned I : llvm::seq(4U)) {
7335 APInt Sel = SelectorVal.extractBits(4, I * 4);
7336 unsigned Idx = Sel.getLoBits(3).getZExtValue();
7337 unsigned Sign = Sel.getHiBits(1).getZExtValue();
7338 APInt Byte = BitField.extractBits(8, Idx * 8);
7339 if (Sign)
7340 Byte = Byte.ashr(8);
7341 Result.insertBits(Byte, I * 8);
7342 }
7343 return Result;
7344}
7345
7347 CodeGenOptLevel OptLevel) {
7348 if (OptLevel == CodeGenOptLevel::None)
7349 return SDValue();
7350
7351 // Constant fold PRMT
7352 if (isa<ConstantSDNode>(N->getOperand(0)) &&
7353 isa<ConstantSDNode>(N->getOperand(1)) &&
7354 isa<ConstantSDNode>(N->getOperand(2)))
7355 return DCI.DAG.getConstant(computePRMT(N->getConstantOperandAPInt(0),
7356 N->getConstantOperandAPInt(1),
7357 N->getConstantOperandAPInt(2),
7358 N->getConstantOperandVal(3)),
7359 SDLoc(N), N->getValueType(0));
7360 return SDValue();
7361}
7362
7363// During call lowering we wrap the return values in a ProxyReg node which
7364// depend on the chain value produced by the completed call. This ensures that
7365// the full call is emitted in cases where libcalls are used to legalize
7366// operations. To improve the functioning of other DAG combines we pull all
7367// operations we can through one of these nodes, ensuring that the ProxyReg
7368// directly wraps a load. That is:
7369//
7370// (ProxyReg (zext (load retval0))) => (zext (ProxyReg (load retval0)))
7371//
7374 switch (R.getOpcode()) {
7375 case ISD::TRUNCATE:
7376 case ISD::ANY_EXTEND:
7377 case ISD::SIGN_EXTEND:
7378 case ISD::ZERO_EXTEND:
7379 case ISD::BITCAST: {
7380 if (SDValue V = sinkProxyReg(R.getOperand(0), Chain, DCI))
7381 return DCI.DAG.getNode(R.getOpcode(), SDLoc(R), R.getValueType(), V);
7382 return SDValue();
7383 }
7384 case ISD::SHL:
7385 case ISD::SRL:
7386 case ISD::SRA:
7387 case ISD::OR: {
7388 if (SDValue A = sinkProxyReg(R.getOperand(0), Chain, DCI))
7389 if (SDValue B = sinkProxyReg(R.getOperand(1), Chain, DCI))
7390 return DCI.DAG.getNode(R.getOpcode(), SDLoc(R), R.getValueType(), A, B);
7391 return SDValue();
7392 }
7393 case ISD::Constant:
7394 return R;
7395 case ISD::LOAD:
7396 case NVPTXISD::LoadV2:
7397 case NVPTXISD::LoadV4: {
7398 return DCI.DAG.getNode(NVPTXISD::ProxyReg, SDLoc(R), R.getValueType(),
7399 {Chain, R});
7400 }
7401 case ISD::BUILD_VECTOR: {
7402 if (DCI.isBeforeLegalize())
7403 return SDValue();
7404
7406 for (auto &Op : R->ops()) {
7407 SDValue V = sinkProxyReg(Op, Chain, DCI);
7408 if (!V)
7409 return SDValue();
7410 Ops.push_back(V);
7411 }
7412 return DCI.DAG.getNode(ISD::BUILD_VECTOR, SDLoc(R), R.getValueType(), Ops);
7413 }
7415 if (DCI.isBeforeLegalize())
7416 return SDValue();
7417
7418 if (SDValue V = sinkProxyReg(R.getOperand(0), Chain, DCI))
7420 R.getValueType(), V, R.getOperand(1));
7421 return SDValue();
7422 }
7423 default:
7424 return SDValue();
7425 }
7426}
7427
7430 const bool IsFTZ = nvvm::FPArithShouldFTZ(IID);
7431 const bool IsSat = nvvm::FPArithIsSaturating(IID);
7432 switch (VT.getScalarType().getSimpleVT().SimpleTy) {
7433 case MVT::f16: {
7434 static constexpr unsigned SubRNOpcodes[2][2] = {
7435 {NVPTXISD::SUB_RN, NVPTXISD::SUB_RN_SAT},
7436 {NVPTXISD::SUB_RN_FTZ, NVPTXISD::SUB_RN_FTZ_SAT}};
7437 return SubRNOpcodes[IsFTZ][IsSat];
7438 }
7439 case MVT::bf16:
7440 return NVPTXISD::SUB_RN;
7441 case MVT::f32: {
7442 // for f32x2 inputs
7443 if (!VT.isVector() || IsSat)
7444 return 0;
7445 static constexpr unsigned SubF32x2Opcodes[4][2] = {
7446 {NVPTXISD::SUB_RZ, NVPTXISD::SUB_RZ_FTZ}, // RZ
7447 {NVPTXISD::SUB_RN, NVPTXISD::SUB_RN_FTZ}, // RN
7448 {NVPTXISD::SUB_RP, NVPTXISD::SUB_RP_FTZ}, // RP
7449 {NVPTXISD::SUB_RM, NVPTXISD::SUB_RM_FTZ}}; // RM
7450 return SubF32x2Opcodes[static_cast<unsigned>(RoundingMode)][IsFTZ];
7451 }
7452 default:
7453 return 0;
7454 }
7455}
7456
7458 Intrinsic::ID AddIntrinsicID,
7460 const EVT VT = N->getValueType(0);
7461 const unsigned Opc = getFAddWithNegOpcode(VT, AddIntrinsicID, RoundingMode);
7462 if (!Opc)
7463 return SDValue();
7464
7465 SDValue Op1 = N->getOperand(1);
7466 SDValue Op2 = N->getOperand(2);
7467
7468 SDValue SubOp1, SubOp2;
7469
7470 if (Op1.getOpcode() == ISD::FNEG) {
7471 SubOp1 = Op2;
7472 SubOp2 = Op1.getOperand(0);
7473 } else if (Op2.getOpcode() == ISD::FNEG) {
7474 SubOp1 = Op1;
7475 SubOp2 = Op2.getOperand(0);
7476 } else {
7477 return SDValue();
7478 }
7479
7480 return DAG.getNode(Opc, SDLoc(N), VT, SubOp1, SubOp2);
7481}
7482
7483// TODO: Remove the type-legality checks here once
7484// https://github.com/llvm/llvm-project/pull/172442 lands, adding support for
7485// explicit type constraints for overloaded intrinsics in tablegen.
7487 unsigned ISDOpcode, Intrinsic::ID IID,
7489 const EVT VT = N->getValueType(0);
7491 return false;
7492
7493 const bool IsRN = RoundingMode == APFloat::rmNearestTiesToEven;
7494 const bool IsFTZ = nvvm::FPArithShouldFTZ(IID);
7495 const bool IsSat = nvvm::FPArithIsSaturating(IID);
7496 switch (VT.getScalarType().getSimpleVT().SimpleTy) {
7497 case MVT::f16:
7498 return IsRN;
7499 case MVT::bf16:
7500 return IsRN && !IsSat && !IsFTZ && STI.hasNativeBF16Support(ISDOpcode);
7501 case MVT::f32:
7502 return !VT.isVector() || (!IsSat && STI.hasF32x2Instructions());
7503 case MVT::f64:
7504 return !VT.isVector() && !IsSat && !IsFTZ;
7505 default:
7506 return false;
7507 }
7508}
7509
7511 Intrinsic::ID IID,
7513 const EVT VT = N->getValueType(0);
7516 Twine(Intrinsic::getBaseName(IID)) + " with rounding mode " +
7517 nvvm::GetRoundingModeName(RoundingMode) + " and operand type " +
7518 VT.getEVTString() + " is not supported on this target",
7519 SDLoc(N).getDebugLoc()));
7520 return DAG.getPOISON(VT);
7521}
7522
7525 const NVPTXSubtarget &STI) {
7526 const Intrinsic::ID IID =
7527 static_cast<Intrinsic::ID>(N->getConstantOperandVal(0));
7528
7529 switch (IID) {
7530 default:
7531 break;
7532 case Intrinsic::nvvm_fadd:
7533 case Intrinsic::nvvm_fadd_ftz:
7534 case Intrinsic::nvvm_fadd_sat:
7535 case Intrinsic::nvvm_fadd_ftz_sat: {
7536 const auto RoundingMode = static_cast<APFloat::roundingMode>(
7537 N->getConstantOperandAPInt(3).getSExtValue());
7538 if (!isSupportedFPArith(N, STI, ISD::FADD, IID, RoundingMode))
7539 return diagnoseUnsupportedFPArith(N, DCI.DAG, IID, RoundingMode);
7540 return combineFAddWithNeg(N, DCI.DAG, IID, RoundingMode);
7541 }
7542 case Intrinsic::nvvm_spcompress:
7543 case Intrinsic::nvvm_spdecompress:
7544 return lowerSPIntrinsic(SDValue(N, 0), DCI.DAG);
7545 case Intrinsic::nvvm_fmul:
7546 case Intrinsic::nvvm_fmul_ftz:
7547 case Intrinsic::nvvm_fmul_sat:
7548 case Intrinsic::nvvm_fmul_ftz_sat: {
7549 const auto RoundingMode = static_cast<APFloat::roundingMode>(
7550 N->getConstantOperandAPInt(3).getSExtValue());
7551 if (!isSupportedFPArith(N, STI, ISD::FMUL, IID, RoundingMode))
7552 return diagnoseUnsupportedFPArith(N, DCI.DAG, IID, RoundingMode);
7553 break;
7554 }
7555 }
7556 return SDValue();
7557}
7558
7561
7562 SDValue Chain = N->getOperand(0);
7563 SDValue Reg = N->getOperand(1);
7564
7565 // If the ProxyReg is not wrapping a load, try to pull the operations through
7566 // the ProxyReg.
7567 if (Reg.getOpcode() != ISD::LOAD) {
7568 if (SDValue V = sinkProxyReg(Reg, Chain, DCI))
7569 return V;
7570 }
7571
7572 return SDValue();
7573}
7574
7575SDValue NVPTXTargetLowering::PerformDAGCombine(SDNode *N,
7576 DAGCombinerInfo &DCI) const {
7578 switch (N->getOpcode()) {
7579 default:
7580 break;
7581 case ISD::ADD:
7582 return PerformADDCombine(N, DCI, OptLevel);
7583 case ISD::ADDRSPACECAST:
7584 return combineADDRSPACECAST(N, DCI);
7585 case ISD::SIGN_EXTEND:
7586 case ISD::ZERO_EXTEND:
7587 return combineSZExtToMulWide(N, DCI, OptLevel);
7588 case ISD::BUILD_VECTOR:
7589 return PerformBUILD_VECTORCombine(N, DCI);
7591 return PerformEXTRACTCombine(N, DCI);
7592 case ISD::FADD:
7593 return performFADDCombine(N, DCI, OptLevel);
7594 case ISD::FMA:
7595 case ISD::FMUL:
7596 case ISD::FSUB:
7597 return performScalarizeV2F32Op(N, DCI, OptLevel);
7598 case ISD::FMAXNUM:
7599 case ISD::FMINNUM:
7600 case ISD::FMAXIMUM:
7601 case ISD::FMINIMUM:
7602 case ISD::FMAXIMUMNUM:
7603 case ISD::FMINIMUMNUM:
7604 return PerformFMinMaxCombine(N, DCI, STI);
7605 case ISD::LOAD:
7606 case NVPTXISD::LoadV2:
7607 case NVPTXISD::LoadV4:
7608 return combineLOAD(N, DCI, STI);
7609 case ISD::MUL:
7610 return PerformMULCombine(N, DCI, OptLevel);
7611 case NVPTXISD::PRMT:
7612 return combinePRMT(N, DCI, OptLevel);
7613 case NVPTXISD::ProxyReg:
7614 return combineProxyReg(N, DCI);
7615 case ISD::SETCC:
7616 return PerformSETCCCombine(N, DCI, STI);
7617 case ISD::SHL:
7618 return PerformSHLCombine(N, DCI, OptLevel);
7619 case ISD::STORE:
7620 case NVPTXISD::StoreV2:
7621 case NVPTXISD::StoreV4:
7622 return combineSTORE(N, DCI, STI);
7623 case ISD::SELECT:
7624 return PerformSELECTShiftCombine(N, DCI);
7625 case ISD::VSELECT:
7626 return PerformVSELECTCombine(N, DCI);
7628 return combineIntrinsicWOChain(N, DCI, STI);
7629 }
7630 return SDValue();
7631}
7632
7635 // Handle bitcasting to v2i8 without hitting the default promotion
7636 // strategy which goes through stack memory.
7637 SDValue Op(Node, 0);
7638 EVT ToVT = Op->getValueType(0);
7639 if (ToVT != MVT::v2i8) {
7640 return;
7641 }
7642
7643 // Bitcast to i16 and unpack elements into a vector
7644 SDLoc DL(Node);
7645 SDValue AsInt = DAG.getBitcast(MVT::i16, Op->getOperand(0));
7646 SDValue Vec0 = DAG.getNode(ISD::TRUNCATE, DL, MVT::i8, AsInt);
7647 SDValue Const8 = DAG.getConstant(8, DL, MVT::i16);
7648 SDValue Vec1 =
7649 DAG.getNode(ISD::TRUNCATE, DL, MVT::i8,
7650 DAG.getNode(ISD::SRL, DL, MVT::i16, {AsInt, Const8}));
7651 Results.push_back(
7652 DAG.getNode(ISD::BUILD_VECTOR, DL, MVT::v2i8, {Vec0, Vec1}));
7653}
7654
7657 SDValue Chain = N->getOperand(0);
7658 SDValue Intrin = N->getOperand(1);
7659 SDLoc DL(N);
7660
7661 // Get the intrinsic ID
7662 unsigned IntrinNo = Intrin.getNode()->getAsZExtVal();
7663 switch (IntrinNo) {
7664 default:
7665 return;
7666 case Intrinsic::nvvm_ldu_global_i:
7667 case Intrinsic::nvvm_ldu_global_f:
7668 case Intrinsic::nvvm_ldu_global_p: {
7669 EVT ResVT = N->getValueType(0);
7670
7671 if (ResVT.isVector()) {
7672 // Vector LDG/LDU
7673
7674 unsigned NumElts = ResVT.getVectorNumElements();
7675 EVT EltVT = ResVT.getVectorElementType();
7676
7677 // Since LDU/LDG are target nodes, we cannot rely on DAG type
7678 // legalization.
7679 // Therefore, we must ensure the type is legal. For i1 and i8, we set the
7680 // loaded type to i16 and propagate the "real" type as the memory type.
7681 bool NeedTrunc = false;
7682 if (EltVT.getSizeInBits() < 16) {
7683 EltVT = MVT::i16;
7684 NeedTrunc = true;
7685 }
7686
7687 unsigned Opcode = 0;
7688 SDVTList LdResVTs;
7689
7690 switch (NumElts) {
7691 default:
7692 return;
7693 case 2:
7694 Opcode = NVPTXISD::LDUV2;
7695 LdResVTs = DAG.getVTList(EltVT, EltVT, MVT::Other);
7696 break;
7697 case 4: {
7698 Opcode = NVPTXISD::LDUV4;
7699 EVT ListVTs[] = { EltVT, EltVT, EltVT, EltVT, MVT::Other };
7700 LdResVTs = DAG.getVTList(ListVTs);
7701 break;
7702 }
7703 }
7704
7705 SmallVector<SDValue, 8> OtherOps;
7706
7707 // Copy regular operands
7708
7709 OtherOps.push_back(Chain); // Chain
7710 // Skip operand 1 (intrinsic ID)
7711 // Others
7712 OtherOps.append(N->op_begin() + 2, N->op_end());
7713
7715
7716 SDValue NewLD = DAG.getMemIntrinsicNode(Opcode, DL, LdResVTs, OtherOps,
7717 MemSD->getMemoryVT(),
7718 MemSD->getMemOperand());
7719
7720 SmallVector<SDValue, 4> ScalarRes;
7721
7722 for (unsigned i = 0; i < NumElts; ++i) {
7723 SDValue Res = NewLD.getValue(i);
7724 if (NeedTrunc)
7725 Res =
7726 DAG.getNode(ISD::TRUNCATE, DL, ResVT.getVectorElementType(), Res);
7727 ScalarRes.push_back(Res);
7728 }
7729
7730 SDValue LoadChain = NewLD.getValue(NumElts);
7731
7732 SDValue BuildVec =
7733 DAG.getBuildVector(ResVT, DL, ScalarRes);
7734
7735 Results.push_back(BuildVec);
7736 Results.push_back(LoadChain);
7737 } else {
7738 // i8 LDG/LDU
7739 assert(ResVT.isSimple() && ResVT.getSimpleVT().SimpleTy == MVT::i8 &&
7740 "Custom handling of non-i8 ldu/ldg?");
7741
7742 // Just copy all operands as-is
7744
7745 // Force output to i16
7746 SDVTList LdResVTs = DAG.getVTList(MVT::i16, MVT::Other);
7747
7749
7750 // We make sure the memory type is i8, which will be used during isel
7751 // to select the proper instruction.
7752 SDValue NewLD =
7754 MVT::i8, MemSD->getMemOperand());
7755
7756 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i8,
7757 NewLD.getValue(0)));
7758 Results.push_back(NewLD.getValue(1));
7759 }
7760 return;
7761 }
7762
7763 case Intrinsic::nvvm_tcgen05_ld_16x64b_x1:
7764 case Intrinsic::nvvm_tcgen05_ld_16x64b_x4:
7765 case Intrinsic::nvvm_tcgen05_ld_16x64b_x8:
7766 case Intrinsic::nvvm_tcgen05_ld_16x64b_x16:
7767 case Intrinsic::nvvm_tcgen05_ld_16x64b_x32:
7768 case Intrinsic::nvvm_tcgen05_ld_16x64b_x64:
7769 case Intrinsic::nvvm_tcgen05_ld_16x64b_x128:
7770 case Intrinsic::nvvm_tcgen05_ld_32x32b_x1:
7771 case Intrinsic::nvvm_tcgen05_ld_32x32b_x4:
7772 case Intrinsic::nvvm_tcgen05_ld_32x32b_x8:
7773 case Intrinsic::nvvm_tcgen05_ld_32x32b_x16:
7774 case Intrinsic::nvvm_tcgen05_ld_32x32b_x32:
7775 case Intrinsic::nvvm_tcgen05_ld_32x32b_x64:
7776 case Intrinsic::nvvm_tcgen05_ld_32x32b_x128:
7777 case Intrinsic::nvvm_tcgen05_ld_16x128b_x2:
7778 case Intrinsic::nvvm_tcgen05_ld_16x128b_x4:
7779 case Intrinsic::nvvm_tcgen05_ld_16x128b_x8:
7780 case Intrinsic::nvvm_tcgen05_ld_16x128b_x16:
7781 case Intrinsic::nvvm_tcgen05_ld_16x128b_x32:
7782 case Intrinsic::nvvm_tcgen05_ld_16x128b_x64:
7783 case Intrinsic::nvvm_tcgen05_ld_16x256b_x1:
7784 case Intrinsic::nvvm_tcgen05_ld_16x256b_x2:
7785 case Intrinsic::nvvm_tcgen05_ld_16x256b_x4:
7786 case Intrinsic::nvvm_tcgen05_ld_16x256b_x8:
7787 case Intrinsic::nvvm_tcgen05_ld_16x256b_x16:
7788 case Intrinsic::nvvm_tcgen05_ld_16x256b_x32:
7789 if (auto Res = lowerTcgen05Ld(N, DAG)) {
7790 Results.push_back(Res->first);
7791 Results.push_back(Res->second);
7792 }
7793 return;
7794
7795 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x1:
7796 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x4:
7797 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x8:
7798 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x16:
7799 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x32:
7800 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x64:
7801 case Intrinsic::nvvm_tcgen05_ld_16x32bx2_x128:
7802 if (auto Res = lowerTcgen05Ld(N, DAG, /*HasOffset=*/true)) {
7803 Results.push_back(Res->first);
7804 Results.push_back(Res->second);
7805 }
7806 return;
7807
7808 case Intrinsic::nvvm_tcgen05_ld_red_32x32b_x8_i32:
7809 case Intrinsic::nvvm_tcgen05_ld_red_32x32b_x8_f32:
7810 case Intrinsic::nvvm_tcgen05_ld_red_32x32b_x64_i32:
7811 case Intrinsic::nvvm_tcgen05_ld_red_32x32b_x64_f32:
7812 case Intrinsic::nvvm_tcgen05_ld_red_32x32b_x4_i32:
7813 case Intrinsic::nvvm_tcgen05_ld_red_32x32b_x4_f32:
7814 case Intrinsic::nvvm_tcgen05_ld_red_32x32b_x32_i32:
7815 case Intrinsic::nvvm_tcgen05_ld_red_32x32b_x32_f32:
7816 case Intrinsic::nvvm_tcgen05_ld_red_32x32b_x16_i32:
7817 case Intrinsic::nvvm_tcgen05_ld_red_32x32b_x16_f32:
7818 case Intrinsic::nvvm_tcgen05_ld_red_32x32b_x128_i32:
7819 case Intrinsic::nvvm_tcgen05_ld_red_32x32b_x128_f32:
7820 case Intrinsic::nvvm_tcgen05_ld_red_16x32bx2_x8_i32:
7821 case Intrinsic::nvvm_tcgen05_ld_red_16x32bx2_x8_f32:
7822 case Intrinsic::nvvm_tcgen05_ld_red_16x32bx2_x64_i32:
7823 case Intrinsic::nvvm_tcgen05_ld_red_16x32bx2_x64_f32:
7824 case Intrinsic::nvvm_tcgen05_ld_red_16x32bx2_x4_i32:
7825 case Intrinsic::nvvm_tcgen05_ld_red_16x32bx2_x4_f32:
7826 case Intrinsic::nvvm_tcgen05_ld_red_16x32bx2_x32_i32:
7827 case Intrinsic::nvvm_tcgen05_ld_red_16x32bx2_x32_f32:
7828 case Intrinsic::nvvm_tcgen05_ld_red_16x32bx2_x16_i32:
7829 case Intrinsic::nvvm_tcgen05_ld_red_16x32bx2_x16_f32:
7830 case Intrinsic::nvvm_tcgen05_ld_red_16x32bx2_x128_i32:
7831 case Intrinsic::nvvm_tcgen05_ld_red_16x32bx2_x128_f32:
7832 if (auto Res = lowerTcgen05LdRed(N, DAG)) {
7833 Results.push_back(std::get<0>(*Res));
7834 Results.push_back(std::get<1>(*Res));
7835 Results.push_back(std::get<2>(*Res));
7836 }
7837 return;
7838 }
7839}
7840
7843 // Change the CopyFromReg to output 2 64-bit results instead of a 128-bit
7844 // result so that it can pass the legalization
7845 SDLoc DL(N);
7846 SDValue Chain = N->getOperand(0);
7847 SDValue Reg = N->getOperand(1);
7848 SDValue Glue = N->getOperand(2);
7849
7850 assert(Reg.getValueType() == MVT::i128 &&
7851 "Custom lowering for CopyFromReg with 128-bit reg only");
7852 SmallVector<EVT, 4> ResultsType = {MVT::i64, MVT::i64, N->getValueType(1),
7853 N->getValueType(2)};
7854 SmallVector<SDValue, 3> NewOps = {Chain, Reg, Glue};
7855
7856 SDValue NewValue = DAG.getNode(ISD::CopyFromReg, DL, ResultsType, NewOps);
7857 SDValue Pair = DAG.getNode(ISD::BUILD_PAIR, DL, MVT::i128,
7858 {NewValue.getValue(0), NewValue.getValue(1)});
7859
7860 Results.push_back(Pair);
7861 Results.push_back(NewValue.getValue(2));
7862 Results.push_back(NewValue.getValue(3));
7863}
7864
7866 const TargetLowering &TLI,
7868 SDValue Chain = N->getOperand(0);
7869 SDValue Reg = N->getOperand(1);
7870
7871 MVT VT = TLI.getRegisterType(*DAG.getContext(), Reg.getValueType());
7872
7873 SDValue NewReg = DAG.getAnyExtOrTrunc(Reg, SDLoc(N), VT);
7874 SDValue NewProxy =
7875 DAG.getNode(NVPTXISD::ProxyReg, SDLoc(N), VT, {Chain, NewReg});
7876 SDValue Res = DAG.getAnyExtOrTrunc(NewProxy, SDLoc(N), N->getValueType(0));
7877
7878 Results.push_back(Res);
7879}
7880
7882 const NVPTXSubtarget &STI,
7884 assert(N->getValueType(0) == MVT::i128 &&
7885 "Custom lowering for atomic128 only supports i128");
7886
7888 SDLoc dl(N);
7889
7890 if (!STI.hasAtomSwap128()) {
7893 "Support for b128 atomics introduced in PTX ISA version 8.3 and "
7894 "requires target sm_90.",
7895 dl.getDebugLoc()));
7896
7897 Results.push_back(DAG.getUNDEF(MVT::i128));
7898 Results.push_back(AN->getOperand(0)); // Chain
7899 return;
7900 }
7901
7903 Ops.push_back(AN->getOperand(0)); // Chain
7904 Ops.push_back(AN->getOperand(1)); // Ptr
7905 for (const auto &Op : AN->ops().drop_front(2)) {
7906 // Low part
7907 Ops.push_back(DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i64, Op,
7908 DAG.getIntPtrConstant(0, dl)));
7909 // High part
7910 Ops.push_back(DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i64, Op,
7911 DAG.getIntPtrConstant(1, dl)));
7912 }
7913 unsigned Opcode = N->getOpcode() == ISD::ATOMIC_SWAP
7916 SDVTList Tys = DAG.getVTList(MVT::i64, MVT::i64, MVT::Other);
7917 SDValue Result = DAG.getMemIntrinsicNode(Opcode, dl, Tys, Ops, MVT::i128,
7918 AN->getMemOperand());
7919 Results.push_back(DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i128,
7920 {Result.getValue(0), Result.getValue(1)}));
7921 Results.push_back(Result.getValue(2));
7922}
7923
7924void NVPTXTargetLowering::ReplaceNodeResults(
7926 switch (N->getOpcode()) {
7927 default:
7928 report_fatal_error("Unhandled custom legalization");
7929 case ISD::BITCAST:
7930 ReplaceBITCAST(N, DAG, Results);
7931 return;
7932 case ISD::LOAD:
7933 case ISD::MLOAD:
7934 replaceLoadVector(N, DAG, Results, STI);
7935 return;
7938 return;
7939 case ISD::CopyFromReg:
7941 return;
7942 case NVPTXISD::ProxyReg:
7943 replaceProxyReg(N, DAG, *this, Results);
7944 return;
7946 case ISD::ATOMIC_SWAP:
7947 replaceAtomicSwap128(N, DAG, STI, Results);
7948 return;
7949 }
7950}
7951
7952/// Returns how NVPTX should expand a scalar atomicrmw.
7954 AtomicRMWInst::BinOp Op, Type *Ty, unsigned AddressSpace, const Function &F,
7955 bool IgnoreDenormalMode, const NVPTXSubtarget &STI) {
7956 using AtomicExpansionKind = TargetLoweringBase::AtomicExpansionKind;
7957 assert(!Ty->isVectorTy() && "Expected a scalar atomicrmw type");
7958
7959 // Try to lower LLVM atomicrmw fadd/fsub to PTX atomic.add. Fsub is first
7960 // expanded to an fadd with a negated operand. This is complicated by the
7961 // weird FTZ behavior PTX atom.add has:
7962 // - atom.add.f32 on global memory flushes denormals
7963 // - atom.add.f32 on shared memory does not flush denormals
7964 // - atom.add.f16 and atomic.add.bf16 never flush denormals
7965 //
7966 // We lower to atom.add only if the function's FTZ behavior matches that of
7967 // atom.add; otherwise, we lower to a CAS loop. But we always allow
7968 // atomic.add.bf16; even though it never flushes denormals, we never flush
7969 // bf16 denormals when doing regular arithmetic, even when FTZ is enabled.
7971 AtomicExpansionKind ExpansionKind = Op == AtomicRMWInst::BinOp::FSub
7972 ? AtomicExpansionKind::Expand
7973 : AtomicExpansionKind::None;
7974
7975 // Both the -nvptx-allow-ftz-atomics option and per-instruction
7976 // !atomic.ignore.denormal.mode say that denormal handling is insignificant
7977 // here, so atom.add may be used even when its FTZ behavior disagrees with
7978 // the function's.
7979 const bool IgnoreFTZMismatch = AllowFTZAtomics || IgnoreDenormalMode;
7980
7981 if (Ty->isFloatTy()) {
7982 const bool FTZ = F.getDenormalMode(APFloat::IEEEsingle()).Output ==
7984 bool UseNative = IgnoreFTZMismatch;
7985 switch (AddressSpace) {
7987 UseNative |= FTZ;
7988 break;
7991 UseNative |= !FTZ;
7992 break;
7993 }
7994 if (UseNative)
7995 return ExpansionKind;
7996 }
7997
7998 if (Ty->isHalfTy()) {
7999 // atom.add.f16 never flushes denormals, so it only agrees with a
8000 // function that is not in FTZ mode for f16.
8001 const bool FTZ = F.getDenormalMode(APFloat::IEEEhalf()).Output ==
8003 if ((!FTZ || IgnoreFTZMismatch) && STI.hasFeature(NVPTX::SM70) &&
8004 STI.hasFeature(NVPTX::PTX63))
8005 return ExpansionKind;
8006 }
8007
8008 if (Ty->isBFloatTy() && STI.hasFeature(NVPTX::SM90))
8009 return ExpansionKind;
8010
8011 if (Ty->isDoubleTy() && STI.hasAtomAddF64())
8012 return ExpansionKind;
8013 }
8014
8015 // PTX's only atomic fp op is `add`; all other ops expand to a CAS loop.
8017 return AtomicExpansionKind::CmpXChg;
8018
8019 assert(Ty->isIntegerTy() && "Expected an integer atomicrmw type");
8020 const unsigned BitWidth = cast<IntegerType>(Ty)->getBitWidth();
8021
8022 switch (Op) {
8023 default:
8024 return AtomicExpansionKind::CmpXChg;
8026 if (BitWidth == 128)
8027 return AtomicExpansionKind::None;
8028 [[fallthrough]];
8031 AtomicExpansionKind ExpansionKind = Op == AtomicRMWInst::BinOp::Sub
8032 ? AtomicExpansionKind::Expand
8033 : AtomicExpansionKind::None;
8034 switch (BitWidth) {
8035 case 8:
8036 case 16:
8037 return AtomicExpansionKind::CmpXChg;
8038 case 32:
8039 case 64:
8040 return ExpansionKind;
8041 case 128:
8042 return AtomicExpansionKind::CmpXChg;
8043 default:
8044 llvm_unreachable("unsupported width encountered");
8045 }
8046 }
8054 switch (BitWidth) {
8055 case 8:
8056 case 16:
8057 return AtomicExpansionKind::CmpXChg;
8058 case 32:
8059 return AtomicExpansionKind::None;
8060 case 64:
8061 if (STI.hasAtomMinMaxAndOrXor())
8062 return AtomicExpansionKind::None;
8063 return AtomicExpansionKind::CmpXChg;
8064 case 128:
8065 return AtomicExpansionKind::CmpXChg;
8066 default:
8067 llvm_unreachable("unsupported width encountered");
8068 }
8071 switch (BitWidth) {
8072 case 32:
8073 return AtomicExpansionKind::None;
8074 case 8:
8075 case 16:
8076 case 64:
8077 case 128:
8078 return AtomicExpansionKind::CmpXChg;
8079 default:
8080 llvm_unreachable("unsupported width encountered");
8081 }
8082 }
8083
8084 return AtomicExpansionKind::CmpXChg;
8085}
8086
8089 const DataLayout &DL = AI->getDataLayout();
8091 const bool IgnoreDenormalMode =
8092 AI->hasMetadata(LLVMContext::MD_atomic_ignore_denormal_mode);
8093
8094 // TODO: once we support native elementwise vector atoms,
8095 // return `AtomicExpansionKind::None` to preserve and lower them.
8096 if (AI->isElementwise()) {
8097 auto *VecTy = cast<FixedVectorType>(AI->getType());
8098 Type *Ty = VecTy->getElementType();
8099
8100 // Collapse <1 x T> elementwise RMWs to scalar RMWs
8101 if (VecTy->getNumElements() == 1)
8103
8104 uint64_t VecBytes = DL.getTypeStoreSize(VecTy).getFixedValue();
8105 uint64_t VecBits = DL.getTypeStoreSizeInBits(VecTy).getFixedValue();
8106
8108 // Split exchanges that are too wide or insufficiently aligned until
8109 // each piece can be lowered atomically.
8110 if (VecBits > getMaxAtomicSizeInBitsSupported() ||
8111 AI->getAlign().value() < VecBytes)
8113
8114 // Expand subword exchanges to a masked cmpxchg loop.
8115 if (VecBits < getMinCmpXchgSizeInBits())
8117
8119 }
8120
8121 // If the scalar lane op is natively supported or expands to one, return
8122 // Expand so halving eventually bottoms out at the scalar base case. The
8123 // latter includes sub and fsub, which expand to add and fadd, respectively.
8125 Op, Ty, AI->getPointerAddressSpace(), *AI->getFunction(),
8126 IgnoreDenormalMode, STI);
8127 if (LaneExpansionKind == AtomicExpansionKind::None ||
8128 LaneExpansionKind == AtomicExpansionKind::Expand)
8130
8131 // If the whole vector fits a single native cmpxchg, emit one wide
8132 // cmpxchg loop at the current width.
8133 if (VecBits <= getMaxAtomicSizeInBitsSupported())
8135
8136 // If the vector is too wide for a single native cmpxchg, halve further to
8137 // emit multiple cmpxchg loops.
8139 }
8140
8141 Type *Ty = AI->getValOperand()->getType();
8142 if (Ty->isVectorTy())
8145 *AI->getFunction(), IgnoreDenormalMode,
8146 STI);
8147}
8148
8149// clang-format off
8150// Atomic load lowering grid, one (LLVM ordering, native support) combination
8151// per line:
8152//
8153// seq_cst, ld.acquire supported: fence seq_cst; load acquire
8154// seq_cst, ld.acquire unsupported: fence seq_cst; load monotonic; fence acquire
8155// acquire, ld.acquire supported: load acquire
8156// acquire, ld.acquire unsupported: load monotonic; fence acquire
8157//
8158// Atomic store lowering grid, in the same form:
8159//
8160// seq_cst, st.release supported: fence seq_cst; store monotonic
8161// seq_cst, st.release unsupported: fence seq_cst; store monotonic
8162// release, st.release supported: store release
8163// release, st.release unsupported: fence release; store monotonic
8164//
8165// Note that ordered fences are only supported on architectures where
8166// acquire/release loads/stores are supported. On lower architectures, all
8167// LLVM fences are lowered "membar". This is correct, because membar provides
8168// all the guarantees of "fence.sc".
8169// Lowering is based on the PTX Atomics ABI:
8170// https://docs.nvidia.com/cuda/ptx-writers-guide-to-interoperability/atomic-abi.html
8171// clang-format on
8172
8174 const Instruction *I) const {
8175 // atomicrmw and cmpxchg instructions not efficiently supported by PTX
8176 // are lowered to CAS emulation loops that preserve their memory order,
8177 // syncscope, and volatile semantics. For PTX, it is more efficient to use
8178 // atom.cas.relaxed.sco instructions within the loop, and fences before and
8179 // after the loop to restore order.
8180 //
8181 // For ordered elementwise atomicrmw, if we expand elementwise, it is also
8182 // more efficient to insert fences around the whole split sequence once and
8183 // downgrade the ordering for the entire sequence, rather than having the
8184 // stronger ordering on every expanded atomicrmw.
8185 //
8186 // On targets with memory-order qualifiers, atomic instructions efficiently
8187 // supported by PTX are lowered to `atom.<op>.<sem>.<scope>` instructions with
8188 // their corresponding memory order and scope. Since PTX does not support
8189 // seq_cst, we emulate it by lowering to a fence.sc followed by an atom
8190 // according to the PTX atomics ABI.
8191 // https://docs.nvidia.com/cuda/ptx-writers-guide-to-interoperability/atomic-abi.html
8192 //
8193 // Atomic loads with a memory order not supported on the SM can be
8194 // inefficiently emulated by appending a `fence.acquire` after a relaxed load.
8195 if (auto *CI = dyn_cast<AtomicCmpXchgInst>(I))
8196 return (cast<IntegerType>(CI->getCompareOperand()->getType())
8197 ->getBitWidth() < STI.getMinCmpXchgSizeInBits()) ||
8198 !STI.hasMemoryOrdering() ||
8199 CI->getMergedOrdering() == AtomicOrdering::SequentiallyConsistent;
8200 if (auto *RI = dyn_cast<AtomicRMWInst>(I)) {
8203 (RI->isElementwise() && Expansion == AtomicExpansionKind::Expand) ||
8204 !STI.hasMemoryOrdering() ||
8205 RI->getOrdering() == AtomicOrdering::SequentiallyConsistent;
8206 }
8207 if (auto *LI = dyn_cast<LoadInst>(I))
8208 return LI->getOrdering() == AtomicOrdering::SequentiallyConsistent ||
8209 (!STI.hasMemoryOrdering() && isAcquireOrStronger(LI->getOrdering()));
8210 if (auto *SI = dyn_cast<StoreInst>(I))
8211 return SI->getOrdering() == AtomicOrdering::SequentiallyConsistent ||
8212 (!STI.hasMemoryOrdering() && isReleaseOrStronger(SI->getOrdering()));
8213 return false;
8214}
8215
8217 const Instruction *I) const {
8218 // Returns the new AtomicOrdering for the original op once AtomicExpandPass
8219 // has split it into leading/trailing fences + the op itself. Per the grids
8220 // above:
8221 // - cmpxchg / atomicrmw at seq_cst (not CAS-emulated): Acquire
8222 // ("fence.sc; atom.<op>.acquire" pattern).
8223 // - load at any ordering when hasMemoryOrdering: Acquire
8224 // ("fence.sc; ld.acquire" for seq_cst; the acquire load is already typed
8225 // on supported targets).
8226 // - everything else (CAS-emulated ops, seq_cst on !hasMemoryOrdering,
8227 // release-or-stronger store on !hasMemoryOrdering, etc.): Monotonic
8228 // (i.e., relaxed) -- the surrounding fences carry the ordering.
8229 //
8230 // If the operation is emulated by a CAS-loop, we lower the instruction to
8231 // atom.<op>.relaxed, since AtomicExpandPass will insert fences for enforcing
8232 // the correct memory ordering around the CAS loop.
8233 //
8234 // When the operation is not emulated, but the memory order is seq_cst,
8235 // we must lower to "fence.sc.<scope>; atom.<op>.acquire.<scope>;" to conform
8236 // to the PTX atomics ABI.
8237 // https://docs.nvidia.com/cuda/ptx-writers-guide-to-interoperability/atomic-abi.html
8238 // For such cases, emitLeadingFence() will separately insert the leading
8239 // "fence.sc.<scope>;". Here, we only set the memory order to acquire.
8240 //
8241 // Otherwise, the operation is not emulated, and the memory order is not
8242 // seq_cst. In this case, the LLVM memory order is natively supported by the
8243 // PTX `atom` instruction, and we just lower to the corresponding
8244 // `atom.<op>.relaxed|acquire|release|acq_rel". For such cases, this function
8245 // will NOT be called.
8246 // prerequisite: shouldInsertFencesForAtomic() should have returned `true` for
8247 // I before its memory order was modified.
8248 if (!STI.hasMemoryOrdering())
8250
8251 if (auto *CI = dyn_cast<AtomicCmpXchgInst>(I);
8252 CI && CI->getMergedOrdering() == AtomicOrdering::SequentiallyConsistent &&
8253 cast<IntegerType>(CI->getCompareOperand()->getType())->getBitWidth() >=
8254 STI.getMinCmpXchgSizeInBits()) {
8256 } else if (auto *RI = dyn_cast<AtomicRMWInst>(I);
8257 RI &&
8258 RI->getOrdering() == AtomicOrdering::SequentiallyConsistent) {
8260 // A non-elementwise `Expand` means we are expanding sub(x) to add(-x).
8261 // The atomic add will have acquire ordering.
8262 if (ExpansionKind == AtomicExpansionKind::None ||
8263 (ExpansionKind == AtomicExpansionKind::Expand && !RI->isElementwise()))
8265 } else if (isa<LoadInst>(I)) {
8267 }
8268
8270}
8271
8273 Instruction *Inst,
8274 AtomicOrdering Ord) const {
8275 // Emits the leading fence per the grids above:
8276 // - cmpxchg / atomicrmw: fence.sc iff Ord == seq_cst, else fence.release
8277 // if Ord is release-or-stronger.
8278 // - load: fence.sc iff Ord == seq_cst.
8279 // - store: same shape as cmpxchg/rmw (fence.sc or fence.release based on
8280 // Ord being seq_cst vs release-or-stronger).
8281 // Returns nullptr if no leading fence is needed for this Inst/Ord.
8282 //
8283 // prerequisite: shouldInsertFencesForAtomic() should have returned `true` for
8284 // `Inst` before its memory order was modified. We cannot enforce this with an
8285 // assert, because AtomicExpandPass will have modified the memory order
8286 // between the initial call to shouldInsertFencesForAtomic() and the call to
8287 // this function.
8288 auto SSID = getAtomicSyncScopeID(Inst);
8289 assert(SSID.has_value() && "Expected an atomic operation");
8290 if (isa<AtomicCmpXchgInst>(Inst) || isa<AtomicRMWInst>(Inst)) {
8291 // Specialize for cmpxchg and atomicrmw
8292 if (isReleaseOrStronger(Ord))
8293 return Builder.CreateFence(Ord == AtomicOrdering::SequentiallyConsistent
8296 SSID.value());
8297 } else if (auto *LI = dyn_cast<LoadInst>(Inst)) {
8298 // volatile operations have sys scope by default
8299 SSID = LI->isVolatile() ? Builder.getContext().getOrInsertSyncScopeID("")
8300 : SSID;
8302 return Builder.CreateFence(AtomicOrdering::SequentiallyConsistent,
8303 SSID.value());
8304 } else if (auto *SI = dyn_cast<StoreInst>(Inst)) {
8305 // volatile operations have sys scope by default
8306 SSID = SI->isVolatile() ? Builder.getContext().getOrInsertSyncScopeID("")
8307 : SSID;
8308 if (isReleaseOrStronger(Ord))
8309 return Builder.CreateFence(Ord == AtomicOrdering::SequentiallyConsistent
8312 SSID.value());
8313 }
8314
8315 return nullptr;
8316}
8317
8319 Instruction *Inst,
8320 AtomicOrdering Ord) const {
8321 // Emits the trailing fence per the grids above:
8322 // - cmpxchg / atomicrmw: fence.acquire iff Ord is acquire-or-stronger AND
8323 // the op is being CAS-emulated (i.e., the inner CAS uses relaxed).
8324 // - load: fence.acquire iff !hasMemoryOrdering (covers both the acquire
8325 // and seq_cst cells of the load grid).
8326 // - store: never (release-side ordering for stores comes from the leading
8327 // fence or the typed `st.release` instruction).
8328 // Returns nullptr if no trailing fence is needed for this Inst/Ord.
8329 //
8330 // prerequisite: shouldInsertFencesForAtomic() should have returned `true` for
8331 // `Inst` before its memory order was modified. See `emitLeadingFence` for why
8332 // this cannot be enforced with an assert. Specialize for cmpxchg and
8333 // atomicrmw
8334 auto *CI = dyn_cast<AtomicCmpXchgInst>(Inst);
8335 auto *RI = dyn_cast<AtomicRMWInst>(Inst);
8336 auto SSID = getAtomicSyncScopeID(Inst);
8337 assert(SSID.has_value() && "Expected an atomic operation");
8338 if (CI || RI) {
8339 bool IsEmulated = !STI.hasMemoryOrdering();
8340 if (CI)
8341 IsEmulated |=
8342 cast<IntegerType>(CI->getCompareOperand()->getType())->getBitWidth() <
8343 STI.getMinCmpXchgSizeInBits();
8344 else {
8346 IsEmulated |=
8348 (RI->isElementwise() && Expansion == AtomicExpansionKind::Expand);
8349 }
8350
8351 if (isAcquireOrStronger(Ord) && IsEmulated)
8352 return Builder.CreateFence(AtomicOrdering::Acquire, SSID.value());
8353
8354 } else if (isa<LoadInst>(Inst) && !STI.hasMemoryOrdering()) {
8355 return Builder.CreateFence(AtomicOrdering::Acquire, SSID.value());
8356 }
8357 return nullptr;
8358}
8359
8360// Rather than default to SINT when both UINT and SINT are custom, we only
8361// change the opcode when UINT is not legal and SINT is. UINT is preferred when
8362// both are custom since unsigned CVT instructions can lead to slightly better
8363// SASS code with fewer instructions.
8365 EVT ToVT) const {
8366 if (isOperationLegal(Op, ToVT))
8367 return Op;
8368 switch (Op) {
8369 case ISD::FP_TO_UINT:
8371 return ISD::FP_TO_SINT;
8372 break;
8376 break;
8377 default:
8378 break;
8379 }
8380 return Op;
8381}
8382
8383// Pin NVPTXTargetObjectFile's vtables to this file.
8385
8390
8392 const SelectionDAG &DAG, unsigned Depth) {
8393 SDValue A = Op.getOperand(0);
8394 SDValue B = Op.getOperand(1);
8395 ConstantSDNode *Selector = dyn_cast<ConstantSDNode>(Op.getOperand(2));
8396 unsigned Mode = Op.getConstantOperandVal(3);
8397
8398 if (!Selector)
8399 return;
8400
8401 KnownBits AKnown = DAG.computeKnownBits(A, Depth);
8402 KnownBits BKnown = DAG.computeKnownBits(B, Depth);
8403
8404 // {b, a} = {{b7, b6, b5, b4}, {b3, b2, b1, b0}}
8405 assert(AKnown.getBitWidth() == 32 && BKnown.getBitWidth() == 32 &&
8406 "PRMT must have i32 operands");
8407 assert(Known.getBitWidth() == 32 && "PRMT must have i32 result");
8408 KnownBits BitField = BKnown.concat(AKnown);
8409
8410 APInt SelectorVal = getPRMTSelector(Selector->getAPIntValue(), Mode);
8411 for (unsigned I : llvm::seq(4)) {
8412 APInt Sel = SelectorVal.extractBits(4, I * 4);
8413 unsigned Idx = Sel.getLoBits(3).getZExtValue();
8414 unsigned Sign = Sel.getHiBits(1).getZExtValue();
8415 KnownBits Byte = BitField.extractBits(8, Idx * 8);
8416 if (Sign)
8417 Byte = KnownBits::ashr(Byte, KnownBits::makeConstant(APInt(8, 7)));
8418 Known.insertBits(Byte, I * 8);
8419 }
8420}
8421
8424
8425 // We can't do anything without knowing the sign bit.
8426 auto ExtType = LD->getConstantOperandVal(LD->getNumOperands() - 1);
8427 if (ExtType == ISD::SEXTLOAD)
8428 return;
8429
8430 // ExtLoading to vector types is weird and may not work well with known bits.
8431 auto DestVT = LD->getValueType(0);
8432 if (DestVT.isVector())
8433 return;
8434
8435 assert(Known.getBitWidth() == DestVT.getSizeInBits());
8436 auto ElementBitWidth = getFromTypeWidthForLoad(LD);
8437 Known.Zero.setHighBits(Known.getBitWidth() - ElementBitWidth);
8438}
8439
8441 const SDValue Op, KnownBits &Known, const APInt &DemandedElts,
8442 const SelectionDAG &DAG, unsigned Depth) const {
8443 Known.resetAll();
8444
8445 switch (Op.getOpcode()) {
8446 case NVPTXISD::MUL_WIDE_SIGNED:
8447 case NVPTXISD::MUL_WIDE_UNSIGNED: {
8448 KnownBits LHS = DAG.computeKnownBits(Op.getOperand(0), Depth + 1);
8449 KnownBits RHS = DAG.computeKnownBits(Op.getOperand(1), Depth + 1);
8450 unsigned BitWidth = Known.getBitWidth();
8451 bool IsSigned = Op.getOpcode() == NVPTXISD::MUL_WIDE_SIGNED;
8452 // Forming mul.wide must not hide bits that let subsequent combines remove
8453 // unused parts of its operands, such as the high bytes of narrow loads.
8454 Known = KnownBits::mul(IsSigned ? LHS.sext(BitWidth) : LHS.zext(BitWidth),
8455 IsSigned ? RHS.sext(BitWidth) : RHS.zext(BitWidth));
8456 break;
8457 }
8458 case NVPTXISD::PRMT:
8460 break;
8461 case NVPTXISD::LoadV2:
8462 case NVPTXISD::LoadV4:
8463 case NVPTXISD::LoadV8:
8465 break;
8466 default:
8467 break;
8468 }
8469}
8470
8471static std::pair<APInt, APInt> getPRMTDemandedBits(const APInt &SelectorVal,
8472 const APInt &DemandedBits) {
8473 APInt DemandedLHS = APInt(32, 0);
8474 APInt DemandedRHS = APInt(32, 0);
8475
8476 for (unsigned I : llvm::seq(4)) {
8477 if (DemandedBits.extractBits(8, I * 8).isZero())
8478 continue;
8479
8480 APInt Sel = SelectorVal.extractBits(4, I * 4);
8481 unsigned Idx = Sel.getLoBits(3).getZExtValue();
8482 unsigned Sign = Sel.getHiBits(1).getZExtValue();
8483
8484 APInt &Src = Idx < 4 ? DemandedLHS : DemandedRHS;
8485 unsigned ByteStart = (Idx % 4) * 8;
8486 if (Sign)
8487 Src.setBit(ByteStart + 7);
8488 else
8489 Src.setBits(ByteStart, ByteStart + 8);
8490 }
8491
8492 return {DemandedLHS, DemandedRHS};
8493}
8494
8495// Replace undef with 0 as this is easier for other optimizations such as
8496// known bits.
8498 if (!Op)
8499 return SDValue();
8500 if (Op.isUndef())
8501 return DAG.getConstant(0, SDLoc(), MVT::i32);
8502 return Op;
8503}
8504
8506 const APInt &DemandedBits,
8507 SelectionDAG &DAG,
8508 const TargetLowering &TLI,
8509 unsigned Depth) {
8510 assert(PRMT.getOpcode() == NVPTXISD::PRMT);
8511 SDValue Op0 = PRMT.getOperand(0);
8512 SDValue Op1 = PRMT.getOperand(1);
8513 auto *SelectorConst = dyn_cast<ConstantSDNode>(PRMT.getOperand(2));
8514 if (!SelectorConst)
8515 return SDValue();
8516
8517 unsigned Mode = PRMT.getConstantOperandVal(3);
8518 const APInt Selector = getPRMTSelector(SelectorConst->getAPIntValue(), Mode);
8519
8520 // Try to simplify the PRMT to one of the inputs if the used bytes are all
8521 // from the same input in the correct order.
8522 const unsigned LeadingBytes = DemandedBits.countLeadingZeros() / 8;
8523 const unsigned SelBits = (4 - LeadingBytes) * 4;
8524 if (Selector.getLoBits(SelBits) == APInt(32, 0x3210).getLoBits(SelBits))
8525 return Op0;
8526 if (Selector.getLoBits(SelBits) == APInt(32, 0x7654).getLoBits(SelBits))
8527 return Op1;
8528
8529 auto [DemandedLHS, DemandedRHS] = getPRMTDemandedBits(Selector, DemandedBits);
8530
8531 // Attempt to avoid multi-use ops if we don't need anything from them.
8532 SDValue DemandedOp0 =
8533 TLI.SimplifyMultipleUseDemandedBits(Op0, DemandedLHS, DAG, Depth + 1);
8534 SDValue DemandedOp1 =
8535 TLI.SimplifyMultipleUseDemandedBits(Op1, DemandedRHS, DAG, Depth + 1);
8536
8537 DemandedOp0 = canonicalizePRMTInput(DemandedOp0, DAG);
8538 DemandedOp1 = canonicalizePRMTInput(DemandedOp1, DAG);
8539 if ((DemandedOp0 && DemandedOp0 != Op0) ||
8540 (DemandedOp1 && DemandedOp1 != Op1)) {
8541 Op0 = DemandedOp0 ? DemandedOp0 : Op0;
8542 Op1 = DemandedOp1 ? DemandedOp1 : Op1;
8543 return getPRMT(Op0, Op1, Selector.getZExtValue(), SDLoc(PRMT), DAG);
8544 }
8545
8546 return SDValue();
8547}
8548
8550 SDValue Op, const APInt &DemandedBits, const APInt &DemandedElts,
8551 KnownBits &Known, TargetLoweringOpt &TLO, unsigned Depth) const {
8552 Known.resetAll();
8553
8554 switch (Op.getOpcode()) {
8555 case NVPTXISD::PRMT:
8557 *this, Depth)) {
8558 TLO.CombineTo(Op, Result);
8559 return true;
8560 }
8561 break;
8562 default:
8563 break;
8564 }
8565
8566 computeKnownBitsForTargetNode(Op, Known, DemandedElts, TLO.DAG, Depth);
8567 return false;
8568}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
uint64_t uint64_t
constexpr LLT S1
constexpr LLT F32
static cl::list< std::string > UseNative("amdgpu-use-native", cl::desc("Comma separated list of functions to replace with native, or all"), cl::CommaSeparated, cl::ValueOptional, cl::Hidden)
AMDGPU Register Bank Select
This file declares a class to represent arbitrary precision floating point values and provide a varie...
This file implements a class to represent arbitrary precision integral constant values and operations...
static SDValue PerformADDCombineWithOperands(SDNode *N, SDValue N0, SDValue N1, TargetLowering::DAGCombinerInfo &DCI, const ARMSubtarget *Subtarget)
PerformADDCombineWithOperands - Try DAG combinations for an ADD with operands N0 and N1.
static SDValue PerformADDCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, const ARMSubtarget *Subtarget)
PerformADDCombine - Target-specific dag combine xforms for ISD::ADD.
static SDValue PerformVSELECTCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, const ARMSubtarget *Subtarget)
static SDValue PerformMULCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, const ARMSubtarget *Subtarget)
static SDValue PerformBUILD_VECTORCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, const ARMSubtarget *Subtarget)
PerformBUILD_VECTORCombine - Target-specific dag combine xforms for ISD::BUILD_VECTOR.
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Function Alias Analysis Results
Atomic ordering constants.
This file contains the simple types necessary to represent the attributes associated with functions a...
#define X(NUM, ENUM, NAME)
Definition ELF.h:857
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
#define clEnumValN(ENUMVAL, FLAGNAME, DESC)
This file contains the declarations for the subclasses of Constant, which represent the different fla...
DXIL Intrinsic Expansion
This file contains the declarations of entities that describe floating point environment and related ...
static bool IsIndirectCall(const MachineInstr *MI)
Module.h This file contains the declarations for the Module class.
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Register Reg
Register const TargetRegisterInfo * TRI
#define T
NVPTX address space definition.
static SDValue reportInvalidTensormapReplaceUsage(SDValue Op, SelectionDAG &DAG, unsigned Val)
static SDValue combineShiftOfLogicOp(SDNode *N, TargetLowering::DAGCombinerInfo &DCI)
Commute SHL with a bitwise logic operation when doing so exposes a common shifted operand.
static SDValue combineADDRSPACECAST(SDNode *N, TargetLowering::DAGCombinerInfo &DCI)
static cl::opt< bool > sched4reg("nvptx-sched4reg", cl::desc("NVPTX Specific: schedule for register pressue"), cl::init(false))
static SDValue lowerTcgen05St(SDValue Op, SelectionDAG &DAG, bool hasOffset=false)
static SDValue PerformEXTRACTCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI)
static cl::opt< NVPTX::DivPrecisionLevel > UsePrecDivF32("nvptx-prec-divf32", cl::Hidden, cl::desc("NVPTX Specific: Override the precision of the lowering for f32 fdiv"), cl::values(clEnumValN(NVPTX::DivPrecisionLevel::Approx, "0", "Use div.approx"), clEnumValN(NVPTX::DivPrecisionLevel::Full, "1", "Use div.full"), clEnumValN(NVPTX::DivPrecisionLevel::IEEE754, "2", "Use IEEE Compliant F32 div.rnd if available (default)"), clEnumValN(NVPTX::DivPrecisionLevel::IEEE754_NoFTZ, "3", "Use IEEE Compliant F32 div.rnd if available, no FTZ")), cl::init(NVPTX::DivPrecisionLevel::IEEE754))
static bool isConstOne(const SDValue &Operand)
static cl::opt< unsigned > FMAContractLevelOpt("nvptx-fma-level", cl::Hidden, cl::desc("NVPTX Specific: FMA contraction (0: don't do it" " 1: do it 2: do it aggressively"), cl::init(2))
static bool IsPTXVectorType(MVT VT)
static SDValue joinSPRegs(EVT VT, ArrayRef< SDValue > Regs, const SDLoc &DL, SelectionDAG &DAG)
static SDValue diagnoseUnsupportedFPArith(SDNode *N, SelectionDAG &DAG, Intrinsic::ID IID, APFloat::roundingMode RoundingMode)
static SDValue PerformSELECTShiftCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI)
Transform patterns like: (select (ugt shift_amt, BitWidth-1), 0, (srl/shl x, shift_amt)) (select (ult...
static SDValue lowerLOADi1(LoadSDNode *LD, SelectionDAG &DAG)
static SDValue lowerIntrinsicVoid(SDValue Op, SelectionDAG &DAG)
static SDValue lowerROT(SDValue Op, SelectionDAG &DAG)
static SDValue PerformFMinMaxCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, const NVPTXSubtarget &STI)
PerformFMinMaxCombine - Combine (fmaxnum (fmaxnum a, b), c) into (fmaxnum3 a, b, c).
static void ComputePTXValueVTs(const TargetLowering &TLI, const DataLayout &DL, LLVMContext &Ctx, CallingConv::ID CallConv, Type *Ty, SmallVectorImpl< EVT > &ValueVTs, SmallVectorImpl< uint64_t > &Offsets, uint64_t StartingOffset=0)
ComputePTXValueVTs - For the given Type Ty, returns the set of primitive legal-ish MVTs that compose ...
static void ReplaceBITCAST(SDNode *Node, SelectionDAG &DAG, SmallVectorImpl< SDValue > &Results)
static void replaceAtomicSwap128(SDNode *N, SelectionDAG &DAG, const NVPTXSubtarget &STI, SmallVectorImpl< SDValue > &Results)
static unsigned getMinMax3Opcode(unsigned MinMax2Opcode)
Get 3-input version of a 2-input min/max opcode.
static bool isSupportedFPArith(SDNode *N, const NVPTXSubtarget &STI, unsigned ISDOpcode, Intrinsic::ID IID, APFloat::roundingMode RoundingMode)
static bool IsExtendedFromLte(SDValue Op, unsigned OptSize, bool &IsSigned)
Check whether Op is explicitly extended from at most OptSize bits, setting IsSigned to the signedness...
static SDValue lowerStAsyncWithMbarrier(SDValue Op, SelectionDAG &DAG)
static SDValue lowerSTOREVector(SDValue Op, SelectionDAG &DAG, const NVPTXSubtarget &STI)
static SDValue lowerLoadVector(SDNode *N, SelectionDAG &DAG, const NVPTXSubtarget &STI)
static void replaceProxyReg(SDNode *N, SelectionDAG &DAG, const TargetLowering &TLI, SmallVectorImpl< SDValue > &Results)
static SDValue lowerStAsyncRelease(SDValue Op, SelectionDAG &DAG)
static void ReplaceCopyFromReg_128(SDNode *N, SelectionDAG &DAG, SmallVectorImpl< SDValue > &Results)
#define TCGEN05_LD_RED_INST(SHAPE, NUM, TYPE)
static SDValue getSymbolNode(SelectionDAG &DAG, MCSymbol *Sym, EVT T)
static SDValue lowerCTLZCTPOP(SDValue Op, SelectionDAG &DAG)
static SDValue combineMADConstOne(SDValue X, SDValue Add, EVT VT, SDLoc DL, TargetLowering::DAGCombinerInfo &DCI)
static unsigned getTcgen05LdRedID(Intrinsic::ID IID)
static SDValue combinePRMT(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, CodeGenOptLevel OptLevel)
static SDValue combinePackingMovIntoStore(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, unsigned Front, unsigned Back)
Fold packing movs into a store.
static bool AreMulWideOperandsDemotable(SDValue LHS, SDValue RHS, unsigned OptSize, const SelectionDAG &DAG, bool &IsSigned)
AreMulWideOperandsDemotable - Checks if the given LHS and RHS operands can be demoted to OptSize bits...
static void ReplaceINTRINSIC_W_CHAIN(SDNode *N, SelectionDAG &DAG, SmallVectorImpl< SDValue > &Results)
static unsigned getSPDecompressNodeOpcode(unsigned NumResults)
static SDValue getBuildVectorizedValue(unsigned N, const SDLoc &dl, SelectionDAG &DAG, T GetElement)
static SDValue getExtractVectorizedValue(SDValue V, unsigned I, EVT VT, const SDLoc &dl, SelectionDAG &DAG)
static TargetLoweringBase::AtomicExpansionKind getScalarAtomicRMWExpansion(AtomicRMWInst::BinOp Op, Type *Ty, unsigned AddressSpace, const Function &F, bool IgnoreDenormalMode, const NVPTXSubtarget &STI)
Returns how NVPTX should expand a scalar atomicrmw.
static SDValue combineSZExtToMulWide(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, CodeGenOptLevel OptLevel)
static unsigned canMergeParamLoadStoresStartingAt(unsigned Idx, uint32_t AccessSize, const SmallVectorImpl< EVT > &ValueVTs, const SmallVectorImpl< T > &Offsets, Align ParamAlignment)
static EVT getVectorizedVT(EVT VT, unsigned N, LLVMContext &C)
#define SPCOMPRESS_NODE_CASE(NumResults)
static SDValue lowerIntrinsicWOChain(SDValue Op, SelectionDAG &DAG)
static void appendSplitSPOperands(ArrayRef< SDUse > Input, SmallVectorImpl< SDValue > &Output, SelectionDAG &DAG)
static std::optional< unsigned > getScalar3OpcodeForReduction(unsigned ReductionOpcode)
Get 3-input scalar reduction opcode.
static SDValue lowerIntrinsicWChain(SDValue Op, SelectionDAG &DAG)
static bool isNonCoalescableBuildVector(const SDValue &BV)
Check if a v2f32 BUILD_VECTOR provably packs values from non-adjacent register pairs (non-coalescable...
static SDValue lowerSPIntrinsic(SDValue Op, SelectionDAG &DAG)
static bool isConstZero(const SDValue &Operand)
static SDValue LowerVectorArith(SDValue Op, SelectionDAG &DAG)
static SDValue LowerTcgen05MMADisableOutputLane(SDValue Op, SelectionDAG &DAG)
static unsigned getTcgen05MMADisableOutputLane(unsigned IID)
static std::pair< APInt, APInt > getPRMTDemandedBits(const APInt &SelectorVal, const APInt &DemandedBits)
static APInt computePRMT(APInt A, APInt B, APInt Selector, unsigned Mode)
static SDValue lowerMUL_LOHI(SDValue Op, SelectionDAG &DAG)
static ISD::NodeType getScalarOpcodeForReduction(unsigned ReductionOpcode)
static EVT getSPRegType(EVT VT)
static SDValue lowerBSWAP(SDValue Op, SelectionDAG &DAG)
static SDValue lowerMSTORE(SDValue Op, SelectionDAG &DAG)
static SDValue PerformMULCombineWithOperands(SDNode *N, SDValue N0, SDValue N1, TargetLowering::DAGCombinerInfo &DCI)
static void computeKnownBitsForPRMT(const SDValue Op, KnownBits &Known, const SelectionDAG &DAG, unsigned Depth)
static SDValue combineUnpackingMovIntoLoad(SDNode *N, TargetLowering::DAGCombinerInfo &DCI)
Fold unpacking movs into a load by increasing the number of return values.
#define TCGEN05_LD_RED_INTR(SHAPE, NUM, TYPE)
static SDValue lowerTensormapReplaceElemtype(SDValue Op, SelectionDAG &DAG)
static SDValue LowerClusterLaunchControlQueryCancel(SDValue Op, SelectionDAG &DAG)
static SDValue PerformSETCCCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, const NVPTXSubtarget &STI)
static std::optional< std::pair< SDValue, SDValue > > lowerTcgen05Ld(SDNode *N, SelectionDAG &DAG, bool HasOffset=false)
static SDValue lowerCvtRSIntrinsics(SDValue Op, SelectionDAG &DAG)
static std::optional< std::pair< SDValue, SDValue > > replaceLoadVector(SDNode *N, SelectionDAG &DAG, const NVPTXSubtarget &STI)
replaceLoadVector - Convert vector loads into multi-output scalar loads.
static SDValue expandFSH64(SDValue A, SDValue B, SDValue ShiftAmount, SDLoc DL, unsigned Opcode, SelectionDAG &DAG)
static cl::opt< bool > AllowFTZAtomics("nvptx-allow-ftz-atomics", cl::Hidden, cl::desc("NVPTX Specific: Lower atomicrmw fadd to atom.add even when its " "FTZ behavior does not match the function's denormal mode."), cl::init(true))
static std::pair< MemSDNode *, uint32_t > convertMLOADToLoadWithUsedBytesMask(MemSDNode *N, SelectionDAG &DAG, const NVPTXSubtarget &STI)
static SDValue TryMULWIDECombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI)
TryMULWIDECombine - Attempt to replace a multiply of M bits with a multiply of M/2 bits that produces...
static SDValue lowerPrmtIntrinsic(SDValue Op, SelectionDAG &DAG)
static SDValue combineMulSelectConstOne(SDValue X, SDValue Select, EVT VT, SDLoc DL, TargetLowering::DAGCombinerInfo &DCI)
static SDValue buildTreeReduction(const SmallVector< SDValue > &Elements, EVT EltTy, ArrayRef< std::pair< unsigned, unsigned > > Ops, const SDLoc &DL, const SDNodeFlags Flags, SelectionDAG &DAG)
Reduces the elements using the scalar operations provided.
static SDValue lowerFPTRUNC_ROUND(SDValue Op, SelectionDAG &DAG, const NVPTXSubtarget &STI)
static SDValue combineProxyReg(SDNode *N, TargetLowering::DAGCombinerInfo &DCI)
static SmallVector< unsigned, 16 > VectorizePTXValueVTs(const SmallVectorImpl< EVT > &ValueVTs, const SmallVectorImpl< T > &Offsets, Align ParamAlignment, bool IsVAArg=false)
static SDValue combineFAddWithNeg(SDNode *N, SelectionDAG &DAG, Intrinsic::ID AddIntrinsicID, APFloat::roundingMode RoundingMode)
static SDValue getPRMT(SDValue A, SDValue B, SDValue Selector, SDLoc DL, SelectionDAG &DAG, unsigned Mode=NVPTX::PTXPrmtMode::NONE)
static SDValue matchMADConstOnePattern(SDValue Add)
static SDValue correctParamType(SDValue V, EVT ExpectedVT, ISD::ArgFlagsTy Flags, SelectionDAG &DAG, SDLoc dl)
static ISD::NodeType getExtOpcode(const ISD::ArgFlagsTy &Flags)
static cl::opt< bool > UsePrecSqrtF32("nvptx-prec-sqrtf32", cl::Hidden, cl::desc("NVPTX Specific: 0 use sqrt.approx, 1 use sqrt.rn."), cl::init(true))
static MachinePointerInfo refinePtrAS(SDValue &Ptr, SelectionDAG &DAG)
static void computeKnownBitsForLoadV(const SDValue Op, KnownBits &Known)
static APInt getPRMTSelector(const APInt &Selector, unsigned Mode)
static unsigned getSPCompressNodeOpcode(unsigned NumResults)
static EVT promoteScalarIntegerPTX(const EVT VT)
PromoteScalarIntegerPTX Used to make sure the arguments/returns are suitable for passing and promote ...
static std::optional< std::tuple< SDValue, SDValue, SDValue > > lowerTcgen05LdRed(SDNode *N, SelectionDAG &DAG)
static SDValue simplifyDemandedBitsForPRMT(SDValue PRMT, const APInt &DemandedBits, SelectionDAG &DAG, const TargetLowering &TLI, unsigned Depth)
static unsigned getSPNumRegs(EVT VT)
static SDValue canonicalizePRMTInput(SDValue Op, SelectionDAG &DAG)
static SDValue sinkProxyReg(SDValue R, SDValue Chain, TargetLowering::DAGCombinerInfo &DCI)
static SDValue lowerFSH(SDValue Op, SelectionDAG &DAG)
static SDValue lowerTensormapReplaceSwizzleMode(SDValue Op, SelectionDAG &DAG)
static SDValue combineIntrinsicWOChain(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, const NVPTXSubtarget &STI)
static SDValue PromoteBinOpToF32(SDNode *N, SelectionDAG &DAG)
static unsigned getFAddWithNegOpcode(EVT VT, Intrinsic::ID IID, APFloat::roundingMode RoundingMode)
static std::optional< std::pair< unsigned int, MVT > > getVectorLoweringShape(EVT VectorEVT, const NVPTXSubtarget &STI, unsigned AddressSpace)
#define SPDECOMPRESS_NODE_CASE(NumResults)
static cl::opt< bool > UseApproxLog2F32("nvptx-approx-log2f32", cl::desc("NVPTX Specific: whether to use lg2.approx for log2"), cl::init(false))
Whereas CUDA's implementation (see libdevice) uses ex2.approx for exp2(), it does NOT use lg2....
static SDValue lowerSELECT(SDValue Op, SelectionDAG &DAG)
static SDValue combineLOAD(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, const NVPTXSubtarget &STI)
static SDValue combineSTORE(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, const NVPTXSubtarget &STI)
static SDValue PerformSHLCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, CodeGenOptLevel OptLevel)
PerformSHLCombine - Runs PTX-specific DAG combine patterns on SHL nodes.
uint64_t High
This file contains the definitions of the enumerations and flags associated with NVVM Intrinsics,...
#define P(N)
const SmallVectorImpl< MachineOperand > & Cond
static cl::opt< RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode > Mode("regalloc-enable-advisor", cl::Hidden, cl::init(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Default), cl::desc("Enable regalloc advisor mode"), cl::values(clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Default, "default", "Default"), clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Release, "release", "precompiled"), clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Development, "development", "for training")))
Contains matchers for matching SelectionDAG nodes and values.
SI Fold Operands
Func MI getDebugLoc()))
This file contains some templates that are useful if you are working with the STL at all.
This file defines the SmallVector class.
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
This file describes how to lower LLVM code to machine code.
Value * RHS
Value * LHS
BinaryOperator * Mul
The Input class is used to parse a yaml document into in-memory structs and vectors.
static const fltSemantics & IEEEsingle()
Definition APFloat.h:304
llvm::RoundingMode roundingMode
IEEE-754R 4.3: Rounding-direction attributes.
Definition APFloat.h:359
static constexpr roundingMode rmNearestTiesToEven
Definition APFloat.h:361
static const fltSemantics & IEEEhalf()
Definition APFloat.h:302
Class for arbitrary precision integers.
Definition APInt.h:78
LLVM_ABI APInt getLoBits(unsigned numBits) const
Compute an APInt containing numBits lowbits from this APInt.
Definition APInt.cpp:641
uint64_t getZExtValue() const
Get zero extended value.
Definition APInt.h:1560
LLVM_ABI APInt getHiBits(unsigned numBits) const
Compute an APInt containing numBits highbits from this APInt.
Definition APInt.cpp:636
LLVM_ABI APInt trunc(unsigned width) const
Truncate to new width.
Definition APInt.cpp:970
void setBit(unsigned BitPosition)
Set the given bit to 1 whose position is given as "bitPosition".
Definition APInt.h:1350
unsigned getBitWidth() const
Return the number of bits in the APInt.
Definition APInt.h:1508
bool isSignedIntN(unsigned N) const
Check if this APInt has an N-bits signed integer value.
Definition APInt.h:431
bool slt(const APInt &RHS) const
Signed less than comparison.
Definition APInt.h:1134
LLVM_ABI APInt extractBits(unsigned numBits, unsigned bitPosition) const
Return an APInt with the extracted bits [bitPosition,bitPosition+numBits).
Definition APInt.cpp:478
bool isIntN(unsigned N) const
Check if this APInt has an N-bits unsigned integer value.
Definition APInt.h:428
bool sge(const APInt &RHS) const
Signed greater or equal comparison.
Definition APInt.h:1241
an instruction to allocate memory on the stack
This class represents an incoming formal argument to a Function.
Definition Argument.h:32
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
const T & front() const
Get the first element.
Definition ArrayRef.h:144
size_t size() const
Get the array size.
Definition ArrayRef.h:141
ArrayRef< T > slice(size_t N, size_t M) const
slice(n, m) - Chop off the first N elements of the array, and keep M elements in the array.
Definition ArrayRef.h:185
an instruction that atomically reads a memory location, combines it with another value,...
bool isElementwise() const
Return true if this RMW has elementwise vector semantics.
Align getAlign() const
Return the alignment of the memory that is being allocated by the instruction.
static bool isFPOperation(BinOp Op)
BinOp
This enumeration lists the possible modifications atomicrmw can make.
@ Add
*p = old + v
@ FAdd
*p = old + v
@ Min
*p = old <signed v ? old : v
@ Sub
*p = old - v
@ And
*p = old & v
@ Xor
*p = old ^ v
@ FSub
*p = old - v
@ UIncWrap
Increment one up to a maximum value.
@ Max
*p = old >signed v ? old : v
@ UMin
*p = old <unsigned v ? old : v
@ UMax
*p = old >unsigned v ? old : v
@ UDecWrap
Decrement one until a minimum value or zero.
BinOp getOperation() const
unsigned getPointerAddressSpace() const
Returns the address space of the pointer operand.
This is an SDNode representing atomic operations.
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
MaybeAlign getParamAlign(unsigned ArgNo) const
Extract the alignment for a call or parameter (0=unknown).
FunctionType * getFunctionType() const
const APInt & getAPIntValue() const
This is an important base class in LLVM.
Definition Constant.h:43
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
A parsed version of the target data layout string in and methods for querying it.
Definition DataLayout.h:64
LLVM_ABI TypeSize getTypeAllocSize(Type *Ty) const
Returns the offset in bytes between successive objects of the specified type, including alignment pad...
LLVM_ABI Align getPrefTypeAlign(Type *Ty) const
Returns the preferred stack/global alignment for the specified type.
Diagnostic information for unsupported feature in backend.
static constexpr ElementCount getFixed(ScalarTy MinVal)
Definition TypeSize.h:306
void addFnAttr(Attribute::AttrKind Kind)
Add function attributes to this function.
Definition Function.cpp:641
Module * getParent()
Get the module that this global value is contained inside of...
Common base class shared among various IRBuilders.
Definition IRBuilder.h:111
bool hasMetadata() const
Return true if this instruction has any metadata attached to it.
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
LLVM_ABI const DataLayout & getDataLayout() const
Get the data layout of the module this instruction belongs to.
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:76
LLVM_ABI void diagnose(const DiagnosticInfo &DI)
Report a message to the currently installed diagnostic handler.
This class is used to represent ISD::LOAD nodes.
Context object for machine code objects.
Definition MCContext.h:83
MCSection * getDataSection() const
static constexpr unsigned NoRegister
Definition MCRegister.h:60
Instances of this class represent a uniqued identifier for a section in the current translation unit.
Definition MCSection.h:580
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition MCSymbol.h:42
StringRef getName() const
getName - Get the symbol name.
Definition MCSymbol.h:188
Machine Value Type.
static auto integer_fixedlen_vector_valuetypes()
SimpleValueType SimpleTy
unsigned getVectorNumElements() const
bool isVector() const
Return true if this is a vector value type.
bool isScalableVector() const
Return true if this is a vector value type where the runtime length is machine dependent.
static LLVM_ABI MVT getVT(Type *Ty, bool HandleUnknown=false)
Return the value type corresponding to the specified type.
static auto integer_valuetypes()
TypeSize getSizeInBits() const
Returns the size of the specified MVT in bits.
static auto fixedlen_vector_valuetypes()
TypeSize getStoreSize() const
Return the number of bytes overwritten by a store of the specified value type.
static MVT getVectorVT(MVT VT, unsigned NumElements)
MVT getVectorElementType() const
static MVT getIntegerVT(unsigned BitWidth)
static auto fp_valuetypes()
MVT getScalarType() const
If this is a vector, return the element type, otherwise return this.
static auto fp_fixedlen_vector_valuetypes()
const AllocaInst * getObjectAllocation(int ObjectIdx) const
Return the underlying Alloca of the specified stack object if it exists.
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
DenormalMode getDenormalMode(const fltSemantics &FPType) const
Returns the denormal handling type for the default rounding mode of the function.
MCContext & getContext() const
Function & getFunction()
Return the LLVM function that this machine code represents.
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
@ EK_Inline
EK_Inline - Jump table entries are emitted inline at their point of use.
@ MODereferenceable
The memory access is dereferenceable (i.e., doesn't trap).
@ MOLoad
The memory access reads data.
@ MOInvariant
The memory access always returns the same value (or traps).
@ MOStore
The memory access writes data.
This SDNode is used for target intrinsics that touch memory and need an associated MachineMemOperand.
This is an abstract virtual class for memory operations.
Align getAlign() 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.
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:68
bool hasTensormapReplaceElemtypeSupport(unsigned ElemType) const
bool hasAtomMinMaxAndOrXor() const
bool hasTensormapReplaceSwizzleModeSupport(unsigned SwizzleMode) const
bool hasAtomAddF64() const
bool hasNativeBF16Support(unsigned Opcode) const
bool hasUsedBytesMaskPragma() const
bool hasAtomSwap128() const
bool hasF32x2Instructions() const
bool has256BitVectorLoadStore(unsigned AS) const
AtomicOrdering atomicOperationOrderAfterFenceSplit(const Instruction *I) const override
ConstraintType getConstraintType(StringRef Constraint) const override
getConstraintType - Given a constraint letter, return the type of constraint it is for this target.
SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override
This callback is invoked for operations that are unsupported by the target, which are registered to u...
bool SimplifyDemandedBitsForTargetNode(SDValue Op, const APInt &DemandedBits, const APInt &DemandedElts, KnownBits &Known, TargetLoweringOpt &TLO, unsigned Depth=0) const override
Attempt to simplify any target nodes based on the demanded bits/elts, returning true on success.
AtomicExpansionKind shouldExpandAtomicRMWInIR(const AtomicRMWInst *AI) const override
Returns how the IR-level AtomicExpand pass should expand the given AtomicRMW, if at all.
NVPTXTargetLowering(const NVPTXTargetMachine &TM, const NVPTXSubtarget &STI)
unsigned getPreferredFPToIntOpcode(unsigned Op, EVT FromVT, EVT ToVT) const override
bool useF32FTZ(const MachineFunction &MF) const
SDValue LowerSTACKSAVE(SDValue Op, SelectionDAG &DAG) const
SDValue getSqrtEstimate(SDValue Operand, SelectionDAG &DAG, int Enabled, int &ExtraSteps, bool &UseOneConst, bool Reciprocal) const override
Hooks for building estimates in place of slower divisions and square roots.
SDValue LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool isVarArg, const SmallVectorImpl< ISD::OutputArg > &Outs, const SmallVectorImpl< SDValue > &OutVals, const SDLoc &dl, SelectionDAG &DAG) const override
This hook must be implemented to lower outgoing return values, described by the Outs array,...
SDValue LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv, bool isVarArg, const SmallVectorImpl< ISD::InputArg > &Ins, const SDLoc &dl, SelectionDAG &DAG, SmallVectorImpl< SDValue > &InVals) const override
This hook must be implemented to lower the incoming (formal) arguments, described by the Ins array,...
MCSymbol * getParamSymbol(MCContext &Ctx, const Function *F, int Idx) const
void LowerAsmOperandForConstraint(SDValue Op, StringRef Constraint, std::vector< SDValue > &Ops, SelectionDAG &DAG) const override
Lower the specified operand into the Ops vector.
SDValue LowerSTACKRESTORE(SDValue Op, SelectionDAG &DAG) const
Instruction * emitTrailingFence(IRBuilderBase &Builder, Instruction *Inst, AtomicOrdering Ord) const override
TargetLoweringBase::LegalizeTypeAction getPreferredVectorAction(MVT VT) const override
Return the preferred vector type legalization action.
NVPTX::DivPrecisionLevel getDivF32Level(const MachineFunction &MF, const SDNode &N) const
bool shouldInsertFencesForAtomic(const Instruction *) const override
Whether AtomicExpandPass should automatically insert fences and reduce ordering for this atomic.
SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const
EVT getSetCCResultType(const DataLayout &DL, LLVMContext &Ctx, EVT VT) const override
Return the ValueType of the result of SETCC operations.
std::pair< unsigned, const TargetRegisterClass * > getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const override
Given a physical register constraint (e.g.
bool isLegalAddressingMode(const DataLayout &DL, const AddrMode &AM, Type *Ty, unsigned AS, Instruction *I=nullptr) const override
isLegalAddressingMode - Return true if the addressing mode represented by AM is legal for this target...
Instruction * emitLeadingFence(IRBuilderBase &Builder, Instruction *Inst, AtomicOrdering Ord) const override
Inserts in the IR a target-specific intrinsic specifying a fence.
void getTgtMemIntrinsic(SmallVectorImpl< IntrinsicInfo > &Infos, const CallBase &I, MachineFunction &MF, unsigned Intrinsic) const override
Given an intrinsic, checks if on the target the intrinsic will need to map to a MemIntrinsicNode (tou...
bool allowFMA(MachineFunction &MF, CodeGenOptLevel OptLevel) const
bool usePrecSqrtF32(const SDNode *N=nullptr) const
unsigned getJumpTableEncoding() const override
Return the entry encoding for a jump table in the current function.
SDValue LowerCall(CallLoweringInfo &CLI, SmallVectorImpl< SDValue > &InVals) const override
This hook must be implemented to lower calls into the specified DAG.
void computeKnownBitsForTargetNode(const SDValue Op, KnownBits &Known, const APInt &DemandedElts, const SelectionDAG &DAG, unsigned Depth=0) const override
Determine which of the bits specified in Mask are known to be either zero or one and return them in t...
MCSection * SelectSectionForGlobal(const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const override
static LLVM_ABI PointerType * get(LLVMContext &C, unsigned AddressSpace)
This constructs an opaque pointer to an object in a numbered address space.
Definition Type.cpp:887
Wrapper class for IR location info (IR ordering and DebugLoc) to be passed into SDNode creation funct...
const DebugLoc & getDebugLoc() const
Represents one node in the SelectionDAG.
ArrayRef< SDUse > ops() const
const APInt & getAsAPIntVal() const
Helper method returns the APInt value of a ConstantSDNode.
unsigned getOpcode() const
Return the SelectionDAG opcode value for this node.
bool hasOneUse() const
Return true if there is exactly one use of this node.
unsigned getIROrder() const
Return the node ordering.
SDNodeFlags getFlags() const
uint64_t getAsZExtVal() const
Helper method returns the zero-extended integer value of a ConstantSDNode.
unsigned getNumValues() const
Return the number of values defined/returned by this operator.
SDVTList getVTList() const
const SDValue & getOperand(unsigned Num) const
bool isUndef() const
Returns true if the node type is UNDEF or POISON.
iterator_range< user_iterator > users()
void setFlags(SDNodeFlags NewFlags)
Represents a use of a SDNode.
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
bool hasOneUse() const
Return true if there is exactly one node using value ResNo of Node, in exactly one operand.
SDValue getValue(unsigned R) const
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
uint64_t getScalarValueSizeInBits() const
uint64_t getConstantOperandVal(unsigned i) const
unsigned getOpcode() const
SectionKind - This is a simple POD value that classifies the properties of a section.
Definition SectionKind.h:22
This is used to represent a portion of an LLVM function in a low-level Data Dependence DAG representa...
LLVM_ABI unsigned ComputeMaxSignificantBits(SDValue Op, unsigned Depth=0) const
Get the upper bound on bit size for this Value Op as a signed integer.
const SDValue & getRoot() const
Return the root tag of the SelectionDAG.
const TargetSubtargetInfo & getSubtarget() const
LLVM_ABI SDValue getMergeValues(ArrayRef< SDValue > Ops, const SDLoc &dl)
Create a MERGE_VALUES node from the given operands.
LLVM_ABI SDVTList getVTList(EVT VT)
Return an SDVTList that represents the list of values specified.
LLVM_ABI void ExtractVectorElements(SDValue Op, SmallVectorImpl< SDValue > &Args, unsigned Start=0, unsigned Count=0, EVT EltVT=EVT())
Append the extracted elements from Start to Count out of the vector Op in Args.
LLVM_ABI SDNode * getNodeIfExists(unsigned Opcode, SDVTList VTList, ArrayRef< SDValue > Ops, const SDNodeFlags Flags, bool AllowCommute=false)
Get the specified node if it's already available, or else return NULL.
LLVM_ABI SDValue getFreeze(SDValue V)
Return a freeze using the SDLoc of the value operand.
LLVM_ABI SDValue getSymbolFunctionGlobalAddress(SDValue Op, Function **TargetFunction=nullptr)
Return a GlobalAddress of the function from the current module with name matching the given ExternalS...
LLVM_ABI SDValue getConstantFP(double Val, const SDLoc &DL, EVT VT, bool isTarget=false)
Create a ConstantFPSDNode wrapping a constant value.
LLVM_ABI SDValue getAddrSpaceCast(const SDLoc &dl, EVT VT, SDValue Ptr, unsigned SrcAS, unsigned DestAS, const SDNodeFlags Flags=SDNodeFlags())
Return an AddrSpaceCastSDNode.
LLVM_ABI SDValue getRegister(Register Reg, EVT VT)
LLVM_ABI SDValue getMemIntrinsicNode(unsigned Opcode, const SDLoc &dl, SDVTList VTList, ArrayRef< SDValue > Ops, EVT MemVT, MachinePointerInfo PtrInfo, Align Alignment, MachineMemOperand::Flags Flags=MachineMemOperand::MOLoad|MachineMemOperand::MOStore, LocationSize Size=LocationSize::precise(0), const AAMDNodes &AAInfo=AAMDNodes())
Creates a MemIntrinsicNode that may produce a result and takes a list of operands.
SDValue getSetCC(const SDLoc &DL, EVT VT, SDValue LHS, SDValue RHS, ISD::CondCode Cond, SDValue Chain=SDValue(), bool IsSignaling=false, SDNodeFlags Flags={})
Helper function to make it easier to build SetCC's if you just have an ISD::CondCode instead of an SD...
LLVM_ABI Align getEVTAlign(EVT MemoryVT) const
Compute the default alignment value for the given type.
LLVM_ABI SDValue getNOT(const SDLoc &DL, SDValue Val, EVT VT)
Create a bitwise NOT operation as (XOR Val, -1).
LLVM_ABI SDNode * MorphNodeTo(SDNode *N, unsigned Opc, SDVTList VTs, ArrayRef< SDValue > Ops)
This mutates the specified node to have the specified return type, opcode, and operands.
SDValue getUNDEF(EVT VT)
Return an UNDEF node. UNDEF does not have a useful SDLoc.
SDValue getCALLSEQ_END(SDValue Chain, SDValue Op1, SDValue Op2, SDValue InGlue, const SDLoc &DL)
Return a new CALLSEQ_END node, which always must have a glue result (to ensure it's not CSE'd).
SDValue getBuildVector(EVT VT, const SDLoc &DL, ArrayRef< SDValue > Ops)
Return an ISD::BUILD_VECTOR node.
LLVM_ABI SDValue getTruncStore(SDValue Chain, const SDLoc &dl, SDValue Val, SDValue Ptr, SDValue Offset, MachinePointerInfo PtrInfo, EVT SVT, Align Alignment, MachineMemOperand::Flags MMOFlags=MachineMemOperand::MONone, const MMOMetadata &Metadata=MMOMetadata())
LLVM_ABI SDValue getBitcast(EVT VT, SDValue V)
Return a bitcast using the SDLoc of the value operand, and casting to the provided type.
SDValue getSelect(const SDLoc &DL, EVT VT, SDValue Cond, SDValue LHS, SDValue RHS, SDNodeFlags Flags=SDNodeFlags())
Helper function to make it easier to build Select's if you just have operands and don't want to check...
const DataLayout & getDataLayout() const
LLVM_ABI SDValue getTokenFactor(const SDLoc &DL, SmallVectorImpl< SDValue > &Vals)
Creates a new TokenFactor containing Vals.
LLVM_ABI SDValue getStore(SDValue Chain, const SDLoc &dl, SDValue Val, SDValue Ptr, MachinePointerInfo PtrInfo, Align Alignment, MachineMemOperand::Flags MMOFlags=MachineMemOperand::MONone, const MMOMetadata &Metadata=MMOMetadata())
Helper function to build ISD::STORE nodes.
LLVM_ABI SDValue getConstant(uint64_t Val, const SDLoc &DL, EVT VT, bool isTarget=false, bool isOpaque=false)
Create a ConstantSDNode wrapping a constant value.
LLVM_ABI SDValue getExtLoad(ISD::LoadExtType ExtType, const SDLoc &dl, EVT VT, SDValue Chain, SDValue Ptr, MachinePointerInfo PtrInfo, EVT MemVT, MaybeAlign Alignment=MaybeAlign(), MachineMemOperand::Flags MMOFlags=MachineMemOperand::MONone, const MMOMetadata &Metadata=MMOMetadata())
LLVM_ABI SDValue getSignedConstant(int64_t Val, const SDLoc &DL, EVT VT, bool isTarget=false, bool isOpaque=false)
SDValue getCALLSEQ_START(SDValue Chain, uint64_t InSize, uint64_t OutSize, const SDLoc &DL)
Return a new CALLSEQ_START node, that starts new call frame, in which InSize bytes are set up inside ...
SDValue getSelectCC(const SDLoc &DL, SDValue LHS, SDValue RHS, SDValue True, SDValue False, ISD::CondCode Cond, SDNodeFlags Flags=SDNodeFlags())
Helper function to make it easier to build SelectCC's if you just have an ISD::CondCode instead of an...
LLVM_ABI SDValue getLoad(EVT VT, const SDLoc &dl, SDValue Chain, SDValue Ptr, MachinePointerInfo PtrInfo, MaybeAlign Alignment=MaybeAlign(), MachineMemOperand::Flags MMOFlags=MachineMemOperand::MONone, const MMOMetadata &Metadata=MMOMetadata())
Loads are not normal binary operators: their result type is not determined by their operands,...
LLVM_ABI SDValue getAnyExtOrTrunc(SDValue Op, const SDLoc &DL, EVT VT)
Convert Op, which must be of integer type, to the integer type VT, by either any-extending or truncat...
LLVM_ABI SDValue getIntPtrConstant(uint64_t Val, const SDLoc &DL, bool isTarget=false)
LLVM_ABI SDValue getNode(unsigned Opcode, const SDLoc &DL, EVT VT, ArrayRef< SDUse > Ops)
Gets or creates the specified node.
LLVM_ABI SDValue getFPExtendOrRound(SDValue Op, const SDLoc &DL, EVT VT)
Convert Op, which must be of float type, to the float type VT, by either extending or rounding (by tr...
SDValue getTargetConstant(uint64_t Val, const SDLoc &DL, EVT VT, bool isOpaque=false)
LLVM_ABI SDValue getVectorIdxConstant(uint64_t Val, const SDLoc &DL, bool isTarget=false)
MachineFunction & getMachineFunction() const
SDValue getPOISON(EVT VT)
Return a POISON node. POISON does not have a useful SDLoc.
LLVM_ABI KnownBits computeKnownBits(SDValue Op, unsigned Depth=0) const
Determine which bits of Op are known to be either zero or one and return them in Known.
LLVM_ABI SDValue getZExtOrTrunc(SDValue Op, const SDLoc &DL, EVT VT)
Convert Op, which must be of integer type, to the integer type VT, by either zero-extending or trunca...
SDValue getObjectPtrOffset(const SDLoc &SL, SDValue Ptr, TypeSize Offset)
Create an add instruction with appropriate flags when used for addressing some offset of an object.
LLVMContext * getContext() const
const SDValue & setRoot(SDValue N)
Set the current root tag of the SelectionDAG.
LLVM_ABI SDValue getMCSymbol(MCSymbol *Sym, EVT VT)
LLVM_ABI std::pair< SDValue, SDValue > SplitScalar(const SDValue &N, const SDLoc &DL, const EVT &LoVT, const EVT &HiVT)
Split the scalar node with EXTRACT_ELEMENT using the provided VTs and return the low/high part.
ArrayRef< int > getMask() const
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
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.
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
constexpr size_t size() const
Get the string size.
Definition StringRef.h:144
Align getStackAlign() const
getStackAlignment - This method returns the number of bytes to which the stack pointer must be aligne...
void setBooleanVectorContents(BooleanContent Ty)
Specify how the target extends the result of a vector boolean value from a vector of i1 to a wider ty...
void setOperationAction(unsigned Op, MVT VT, LegalizeAction Action)
Indicate that the specified operation does not work with the specified type and indicate what to do a...
void setMaxDivRemBitWidthSupported(unsigned SizeInBits)
Set the size in bits of the maximum div/rem the backend supports.
EVT getValueType(const DataLayout &DL, Type *Ty, bool AllowUnknown=false) const
Return the EVT corresponding to this LLVM type.
unsigned MaxStoresPerMemcpyOptSize
Likewise for functions with the OptSize attribute.
const TargetMachine & getTargetMachine() const
virtual unsigned getNumRegistersForCallingConv(LLVMContext &Context, CallingConv::ID CC, EVT VT) const
Certain targets require unusual breakdowns of certain types.
virtual MVT getRegisterTypeForCallingConv(LLVMContext &Context, CallingConv::ID CC, EVT VT) const
Certain combinations of ABIs, Targets and features require that types are legal for some operations a...
void setOperationPromotedToType(unsigned Opc, MVT OrigVT, MVT DestVT)
Convenience method to set an operation to Promote and specify the type in a single call.
LegalizeTypeAction
This enum indicates whether a types are legal for a target, and if not, what action should be used to...
unsigned getMinCmpXchgSizeInBits() const
Returns the size of the smallest cmpxchg or ll/sc instruction the backend supports.
void addBypassSlowDiv(unsigned int SlowBitWidth, unsigned int FastBitWidth)
Tells the code generator which bitwidths to bypass.
MVT getRegisterType(LLVMContext &Context, EVT VT) const
Return the type of registers that this ValueType will eventually require.
void setMaxLargeFPConvertBitWidthSupported(unsigned SizeInBits)
Set the size in bits of the maximum fp to/from int conversion the backend supports.
virtual unsigned getNumRegisters(LLVMContext &Context, EVT VT, std::optional< MVT > RegisterVT=std::nullopt) const
Return the number of registers that this ValueType will eventually require.
void setMaxAtomicSizeInBitsSupported(unsigned SizeInBits)
Set the maximum atomic operation size supported by the backend.
virtual TargetLoweringBase::LegalizeTypeAction getPreferredVectorAction(MVT VT) const
Return the preferred vector type legalization action.
unsigned MaxStoresPerMemsetOptSize
Likewise for functions with the OptSize attribute.
void setBooleanContents(BooleanContent Ty)
Specify how the target extends the result of integer and floating point boolean values from i1 to a w...
unsigned MaxStoresPerMemmove
Specify maximum number of store instructions per memmove call.
void computeRegisterProperties(const TargetRegisterInfo *TRI)
Once all of the register classes are added, this allows us to compute derived properties we expose.
unsigned MaxStoresPerMemmoveOptSize
Likewise for functions with the OptSize attribute.
void addRegisterClass(MVT VT, const TargetRegisterClass *RC)
Add the specified register class as an available regclass for the specified value type.
bool isTypeLegal(EVT VT) const
Return true if the target has native support for the specified value type.
virtual MVT getPointerTy(const DataLayout &DL, uint32_t AS=0) const
Return the pointer type for the given address space, defaults to the pointer type from the data layou...
bool isOperationLegal(unsigned Op, EVT VT) const
Return true if the specified operation is legal on this target.
unsigned MaxStoresPerMemset
Specify maximum number of store instructions per memset call.
@ Bitcast
Build the immediate as a bitcast of an integer constant with the same bits.
void setTruncStoreAction(MVT ValVT, MVT MemVT, LegalizeAction Action)
Indicate that the specified truncating store does not work with the specified type and indicate what ...
unsigned getMaxAtomicSizeInBitsSupported() const
Returns the maximum atomic operation size (in bits) supported by the backend.
void setMinCmpXchgSizeInBits(unsigned SizeInBits)
Sets the minimum cmpxchg or ll/sc size supported by the backend.
void AddPromotedToType(unsigned Opc, MVT OrigVT, MVT DestVT)
If Opc/OrigVT is specified as being promoted, the promotion code defaults to trying a larger integer/...
AtomicExpansionKind
Enum that specifies what an atomic load/AtomicRMWInst is expanded to, if at all.
void setCondCodeAction(ArrayRef< ISD::CondCode > CCs, MVT VT, LegalizeAction Action)
Indicate that the specified condition code is or isn't supported on the target and indicate what to d...
void setTargetDAGCombine(ArrayRef< ISD::NodeType > NTs)
Targets should invoke this method for each target independent node that they want to provide a custom...
Align getMinStackArgumentAlignment() const
Return the minimum stack alignment of an argument.
void setLoadExtAction(unsigned ExtType, MVT ValVT, MVT MemVT, LegalizeAction Action)
Indicate that the specified load with extension does not work with the specified type and indicate wh...
std::vector< ArgListEntry > ArgListTy
unsigned MaxStoresPerMemcpy
Specify maximum number of store instructions per memcpy call.
void setSchedulingPreference(Sched::Preference Pref)
Specify the target scheduling preference.
void setJumpIsExpensive(bool isExpensive=true)
Tells the code generator not to expand logic operations on comparison predicates into separate sequen...
LegalizeAction getOperationAction(unsigned Op, EVT VT) const
Return how this operation should be treated: either it is legal, needs to be promoted to a larger siz...
This class defines information used to lower LLVM code to legal SelectionDAG operators that the targe...
SDValue SimplifyMultipleUseDemandedBits(SDValue Op, const APInt &DemandedBits, const APInt &DemandedElts, SelectionDAG &DAG, unsigned Depth=0) const
More limited version of SimplifyDemandedBits that can be used to "lookthrough" ops that don't contrib...
virtual ConstraintType getConstraintType(StringRef Constraint) const
Given a constraint, return the type of constraint it is for this target.
virtual std::pair< unsigned, const TargetRegisterClass * > getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const
Given a physical register constraint (e.g.
TargetLowering(const TargetLowering &)=delete
SDValue expandRoundInexactToOdd(EVT ResultVT, SDValue Op, const SDLoc &DL, SelectionDAG &DAG) const
Truncate Op to ResultVT.
SDValue expandFP_ROUND(SDNode *Node, SelectionDAG &DAG) const
Expand round(fp) to fp conversion.
virtual void LowerAsmOperandForConstraint(SDValue Op, StringRef Constraint, std::vector< SDValue > &Ops, SelectionDAG &DAG) const
Lower the specified operand into the Ops vector.
Primary interface to the complete machine description for the target machine.
CodeGenOptLevel getOptLevel() const
Returns the optimization level: None, Less, Default, or Aggressive.
MCSymbol * getSymbol(const GlobalValue *GV) const
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
virtual const TargetFrameLowering * getFrameLowering() const
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
static constexpr TypeSize getFixed(ScalarTy ExactSize)
Definition TypeSize.h:344
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
bool isIntegerTy() const
True if this is an instance of IntegerType.
Definition Type.h:252
bool isVoidTy() const
Return true if this is 'void'.
Definition Type.h:141
LLVM Value Representation.
Definition Value.h:75
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:257
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition Value.cpp:315
CallInst * Call
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
LLVM_ABI APInt pow(const APInt &X, int64_t N)
Compute X^N for N>=0.
Definition APInt.cpp:3199
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
NodeType
ISD::NodeType enum - This enum defines the target-independent operators for a SelectionDAG.
Definition ISDOpcodes.h:43
@ SETCC
SetCC operator - This evaluates to a true value iff the condition is true.
Definition ISDOpcodes.h:845
@ STACKRESTORE
STACKRESTORE has two operands, an input chain and a pointer to restore to it returns an output chain.
@ STACKSAVE
STACKSAVE - STACKSAVE has one operand, an input chain.
@ POISON
POISON - A poison node.
Definition ISDOpcodes.h:238
@ MLOAD
Masked load and store - consecutive vector load and store operations with additional mask operand tha...
@ VECREDUCE_FMINIMUMNUM
@ SMUL_LOHI
SMUL_LOHI/UMUL_LOHI - Multiply two integers of type iN, producing a signed/unsigned value of type i[2...
Definition ISDOpcodes.h:277
@ BSWAP
Byte Swap and Counting operators.
Definition ISDOpcodes.h:805
@ VAEND
VAEND, VASTART - VAEND and VASTART have three operands: an input chain, pointer, and a SRCVALUE.
@ ADDC
Carry-setting nodes for multiple precision addition and subtraction.
Definition ISDOpcodes.h:296
@ 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...
@ ANY_EXTEND
ANY_EXTEND - Used for integer types. The high bits are undefined.
Definition ISDOpcodes.h:879
@ 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
@ SINT_TO_FP
[SU]INT_TO_FP - These operators convert integers (whose interpreted sign depends on the first letter)...
Definition ISDOpcodes.h:906
@ CONCAT_VECTORS
CONCAT_VECTORS(VECTOR0, VECTOR1, ...) - Given a number of values of vector type with the same length ...
Definition ISDOpcodes.h:589
@ VECREDUCE_FMAX
FMIN/FMAX nodes can have flags, for NaN/NoNaN variants.
@ FADD
Simple binary floating point operators.
Definition ISDOpcodes.h:420
@ VECREDUCE_FMAXIMUM
FMINIMUM/FMAXIMUM nodes propatate NaNs and signed zeroes using the llvm.minimum and llvm....
@ ABS
ABS - Determine the unsigned absolute value of a signed integer value of the same bitwidth.
Definition ISDOpcodes.h:765
@ SDIVREM
SDIVREM/UDIVREM - Divide two integers and produce both a quotient and remainder result.
Definition ISDOpcodes.h:282
@ FPTRUNC_ROUND
FPTRUNC_ROUND - This corresponds to the fptrunc_round intrinsic.
Definition ISDOpcodes.h:520
@ BITCAST
BITCAST - This operator converts between integer, vector and FP values, as if the value was stored to...
@ BUILD_PAIR
BUILD_PAIR - This is the opposite of EXTRACT_ELEMENT in some ways.
Definition ISDOpcodes.h:256
@ CLMUL
Carry-less multiplication operations.
Definition ISDOpcodes.h:796
@ CTLZ_ZERO_POISON
Definition ISDOpcodes.h:814
@ SIGN_EXTEND
Conversion operators.
Definition ISDOpcodes.h:870
@ READSTEADYCOUNTER
READSTEADYCOUNTER - This corresponds to the readfixedcounter intrinsic.
@ VECREDUCE_FMAXIMUMNUM
FMINIMUMNUM/FMAXIMUMNUM nodes do not propagate NaNs and order signed zeroes using the llvm....
@ FNEG
Perform various unary floating-point operations inspired by libm.
@ BR_CC
BR_CC - Conditional branch.
@ SSUBO
Same for subtraction.
Definition ISDOpcodes.h:355
@ BRIND
BRIND - Indirect branch.
@ BR_JT
BR_JT - Jumptable branch.
@ SSUBSAT
RESULT = [US]SUBSAT(LHS, RHS) - Perform saturation subtraction on 2 integers with the same bit width ...
Definition ISDOpcodes.h:377
@ SELECT
Select(COND, TRUEVAL, FALSEVAL).
Definition ISDOpcodes.h:822
@ UNDEF
UNDEF - An undefined node.
Definition ISDOpcodes.h:235
@ EXTRACT_ELEMENT
EXTRACT_ELEMENT - This is used to get the lower or upper (determined by a Constant,...
Definition ISDOpcodes.h:249
@ VACOPY
VACOPY - VACOPY has 5 operands: an input chain, a destination pointer, a source pointer,...
@ CopyFromReg
CopyFromReg - This node indicates that the input value is a virtual or physical register that is defi...
Definition ISDOpcodes.h:232
@ SADDO
RESULT, BOOL = [SU]ADDO(LHS, RHS) - Overflow-aware nodes for addition.
Definition ISDOpcodes.h:351
@ MULHU
MULHU/MULHS - Multiply high - Multiply two integers of type iN, producing an unsigned/signed value of...
Definition ISDOpcodes.h:714
@ SHL
Shift and rotation operations.
Definition ISDOpcodes.h:787
@ VECTOR_SHUFFLE
VECTOR_SHUFFLE(VEC1, VEC2) - Returns a vector, of the same type as VEC1/VEC2.
Definition ISDOpcodes.h:659
@ EXTRACT_SUBVECTOR
EXTRACT_SUBVECTOR(VECTOR, IDX) - Returns a subvector from VECTOR.
Definition ISDOpcodes.h:619
@ FMINNUM_IEEE
FMINNUM_IEEE/FMAXNUM_IEEE - Same as FMINNUM/FMAXNUM, except that a signaling NaN operand deterministi...
@ 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
@ ZERO_EXTEND
ZERO_EXTEND - Used for integer types, zeroing the new bits.
Definition ISDOpcodes.h:876
@ DEBUGTRAP
DEBUGTRAP - Trap intended to get the attention of a debugger.
@ SELECT_CC
Select with condition operator - This selects between a true value and a false value (ops #2 and #3) ...
Definition ISDOpcodes.h:837
@ ATOMIC_CMP_SWAP
Val, OUTCHAIN = ATOMIC_CMP_SWAP(INCHAIN, ptr, cmp, swap) For double-word atomic operations: ValLo,...
@ FMINNUM
FMINNUM/FMAXNUM - Same semantics as the llvm.minnum/maxnum intrinsics.
@ SSHLSAT
RESULT = [US]SHLSAT(LHS, RHS) - Perform saturation left shift.
Definition ISDOpcodes.h:389
@ SMULO
Same for multiplication.
Definition ISDOpcodes.h:359
@ DYNAMIC_STACKALLOC
DYNAMIC_STACKALLOC - Allocate some number of bytes on the stack aligned to a specified boundary.
@ SIGN_EXTEND_INREG
SIGN_EXTEND_INREG - This operator atomically performs a SHL/SRA pair to sign extend a small value in ...
Definition ISDOpcodes.h:914
@ SMIN
[US]{MIN/MAX} - Binary minimum or maximum of signed or unsigned integers.
Definition ISDOpcodes.h:745
@ FP_EXTEND
X = FP_EXTEND(Y) - Extend a smaller FP type into a larger FP type.
@ VSELECT
Select with a vector condition (op #0) and two vector operands (ops #1 and #2), returning a vector re...
Definition ISDOpcodes.h:831
@ UADDO_CARRY
Carry-using nodes for multiple precision addition and subtraction.
Definition ISDOpcodes.h:331
@ BF16_TO_FP
BF16_TO_FP, FP_TO_BF16 - These operators are used to perform promotions and truncation for bfloat16.
@ FRAMEADDR
FRAMEADDR, RETURNADDR - These nodes represent llvm.frameaddress and llvm.returnaddress on the DAG.
Definition ISDOpcodes.h:112
@ STRICT_FP_TO_UINT
Definition ISDOpcodes.h:483
@ STRICT_FP_TO_SINT
STRICT_FP_TO_[US]INT - Convert a floating point value to a signed or unsigned integer.
Definition ISDOpcodes.h:482
@ FMINIMUM
FMINIMUM/FMAXIMUM - Same semantics as the llvm.minimum/maximum intrinsics.
@ FP_TO_SINT
FP_TO_[US]INT - Convert a floating point value to a signed or unsigned integer.
Definition ISDOpcodes.h:952
@ READCYCLECOUNTER
READCYCLECOUNTER - This corresponds to the readcyclecounter intrinsic.
@ AND
Bitwise operators - logical and, logical or, logical xor.
Definition ISDOpcodes.h:757
@ TRAP
TRAP - Trapping instruction.
@ INTRINSIC_WO_CHAIN
RESULT = INTRINSIC_WO_CHAIN(INTRINSICID, arg1, arg2, ...) This node represents a target intrinsic fun...
Definition ISDOpcodes.h:207
@ ADDE
Carry-using nodes for multiple precision addition and subtraction.
Definition ISDOpcodes.h:306
@ INSERT_VECTOR_ELT
INSERT_VECTOR_ELT(VECTOR, VAL, IDX) - Returns VECTOR with the element at IDX replaced with VAL.
Definition ISDOpcodes.h:570
@ ATOMIC_SWAP
Val, OUTCHAIN = ATOMIC_SWAP(INCHAIN, ptr, amt) Val, OUTCHAIN = ATOMIC_LOAD_[OpName](INCHAIN,...
@ FP_ROUND
X = FP_ROUND(Y, TRUNC) - Rounding 'Y' from a larger floating point type down to the precision of the ...
Definition ISDOpcodes.h:985
@ ADDRSPACECAST
ADDRSPACECAST - This operator converts between pointers of different address spaces.
@ VECREDUCE_FMINIMUM
@ TRUNCATE
TRUNCATE - Completely drop the high bits.
Definition ISDOpcodes.h:882
@ VAARG
VAARG - VAARG has four operands: an input chain, a pointer, a SRCVALUE, and the alignment.
@ SHL_PARTS
SHL_PARTS/SRA_PARTS/SRL_PARTS - These operators are used for expanded integer shift operations.
Definition ISDOpcodes.h:859
@ FCOPYSIGN
FCOPYSIGN(X, Y) - Return the value of X with the sign of Y.
Definition ISDOpcodes.h:539
@ SADDSAT
RESULT = [US]ADDSAT(LHS, RHS) - Perform saturation addition on 2 integers with the same bit width (W)...
Definition ISDOpcodes.h:368
@ FMINIMUMNUM
FMINIMUMNUM/FMAXIMUMNUM - Same semantics as the llvm.minimumnum/maximumnum intrinsics.
@ SADDO_CARRY
Carry-using overflow-aware nodes for multiple precision addition and subtraction.
Definition ISDOpcodes.h:341
@ INTRINSIC_W_CHAIN
RESULT,OUTCHAIN = INTRINSIC_W_CHAIN(INCHAIN, INTRINSICID, arg1, ...) This node represents a target in...
Definition ISDOpcodes.h:215
@ ABS_MIN_POISON
ABS with a poison result for INT_MIN.
Definition ISDOpcodes.h:769
@ BUILD_VECTOR
BUILD_VECTOR(ELT0, ELT1, ELT2, ELT3,...) - Return a fixed-width vector with the specified,...
Definition ISDOpcodes.h:561
bool isExtOpcode(unsigned Opcode)
LLVM_ABI bool allOperandsUndef(const SDNode *N)
Return true if the node has at least one operand and all operands of the specified node are ISD::UNDE...
This namespace contains an enum with a value for every intrinsic/builtin function known by LLVM.
LLVM_ABI StringRef getName(ID id)
Return the LLVM name for an intrinsic, such as "llvm.ppc.altivec.lvx".
LLVM_ABI StringRef getBaseName(ID id)
Return the LLVM name for an intrinsic, without encoded types for overloading, such as "llvm....
OneUse_match< SubPat > m_OneUse(const SubPat &SP)
@ ATOMIC_CMP_SWAP_B128
These nodes are used to lower atomic instructions with i128 type.
@ DeviceParam
Definition NVPTX.h:333
@ EntryParam
Definition NVPTX.h:327
bool isPackedVectorTy(EVT VT)
DivPrecisionLevel
Definition NVPTX.h:464
match_combine_or< CastInst_match< OpTy, TruncInst >, OpTy > m_TruncOrSelf(const OpTy &Op)
specific_intval< false > m_SpecificInt(const APInt &V)
Match a specific integer value or vector with all elements equal to the value.
match_deferred< Value > m_Deferred(Value *const &V)
Like m_Specific(), but works if the specific value to match is determined as part of the same match()...
ThreeOps_match< Cond, LHS, RHS, Instruction::Select > m_Select(const Cond &C, const LHS &L, const RHS &R)
Matches SelectInst.
auto m_Value()
Match an arbitrary value and ignore it.
is_zero< true > m_Zero()
Match any null constant or a vector with all elements equal to 0.
BinaryOp_match< LHS, RHS, Instruction::Shl > m_Shl(const LHS &L, const RHS &R)
BinOpPred_match< LHS, RHS, is_bitwiselogic_op > m_BitwiseLogic(const LHS &L, const RHS &R)
Matches bitwise logic operations.
ValuesClass values(OptsTy... Options)
Helper to build a ValuesClass by forwarding a variable number of arguments as an initializer list to ...
initializer< Ty > init(const Ty &Val)
StringRef GetRoundingModeName(APFloat::roundingMode RM)
bool FPArithIsSaturating(Intrinsic::ID IntrinsicID)
bool FPArithShouldFTZ(Intrinsic::ID IntrinsicID)
@ User
could "use" a pointer
NodeAddr< NodeBase * > Node
Definition RDFGraph.h:381
This is an optimization pass for GlobalISel generic memory operations.
@ Low
Lower the current thread's priority such that it does not affect foreground tasks significantly.
Definition Threading.h:280
@ Offset
Definition DWP.cpp:577
detail::zippy< detail::zip_shortest, T, U, Args... > zip(T &&t, U &&u, Args &&...args)
zip iterator for two or more iteratable types.
Definition STLExtras.h:846
Align getDeviceByValParamAlign(const Function *F, Type *ArgTy, unsigned AttrIdx, const DataLayout &DL)
The .param-space alignment for a byval parameter or call argument: the (possibly promoted) parameter ...
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1755
SDValue peekThroughFreeze(SDValue V)
Return the non-frozen source operand of V if it exists.
RelativeUniformCounterPtr Values
Definition InstrProf.h:91
@ Known
Known to have no common set bits.
LLVM_ABI void ComputeValueVTs(const TargetLowering &TLI, const DataLayout &DL, Type *Ty, SmallVectorImpl< EVT > &ValueVTs, SmallVectorImpl< EVT > *MemVTs=nullptr, SmallVectorImpl< TypeSize > *Offsets=nullptr, TypeSize StartingOffset=TypeSize::getZero())
ComputeValueVTs - Given an LLVM IR type, compute a sequence of EVTs that represent all the individual...
Definition Analysis.cpp:121
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
Definition STLExtras.h:2570
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
@ Store
The extracted value is stored (ExtractElement only).
Align getPTXParamTypeAlign(Type *ArgTy, const DataLayout &DL)
ABI alignment of ArgTy in .param space, capped at the PTX maximum of 128.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
uint64_t PowerOf2Ceil(uint64_t A)
Returns the power of two which is greater than or equal to the given value.
Definition MathExtras.h:380
bool isReleaseOrStronger(AtomicOrdering AO)
OutputIt transform(R &&Range, OutputIt d_first, UnaryFunction F)
Wrapper function around std::transform to apply a function to a range and store the result elsewhere.
Definition STLExtras.h:2042
auto reverse(ContainerTy &&C)
Definition STLExtras.h:408
std::optional< SyncScope::ID > getAtomicSyncScopeID(const Instruction *I)
A helper function that returns an atomic operation's sync scope; returns std::nullopt if it is not an...
bool none_of(R &&Range, UnaryPredicate P)
Provide wrappers to std::none_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1769
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
bool shouldPassAsArray(Type *Ty)
constexpr uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Definition Alignment.h:149
iterator_range< filter_iterator< detail::IterOfRange< RangeT >, PredicateT > > make_filter_range(RangeT &&Range, PredicateT Pred)
Convenience function that takes a range of elements and a predicate, and return a new filter_iterator...
Definition STLExtras.h:552
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
unsigned promoteScalarArgumentSize(unsigned Size)
AtomicOrdering
Atomic ordering for LLVM's memory model.
constexpr T divideCeil(U Numerator, V Denominator)
Returns the integer ceil(Numerator / Denominator).
Definition MathExtras.h:389
@ Add
Sum of integers.
@ FAdd
Sum of floats.
DWARFExpression::Operation Op
RoundingMode
Rounding mode.
@ TowardZero
roundTowardZero.
@ NearestTiesToEven
roundTiesToEven.
@ TowardPositive
roundTowardPositive.
@ TowardNegative
roundTowardNegative.
Align getPTXParamAlign(const Function *F, Type *Ty, unsigned AttrIdx, const DataLayout &DL)
Alignment for a function parameter or return value at AttributeList index AttrIdx (FirstArgIndex + ar...
ArrayRef(const T &OneElt) -> ArrayRef< T >
LLVM_ABI ConstantSDNode * isConstOrConstSplat(SDValue N, bool AllowUndefs=false, bool AllowTruncation=false)
Returns the SDNode if it is a constant splat BuildVector or constant int.
bool isAcquireOrStronger(AtomicOrdering AO)
constexpr unsigned BitWidth
bool isKernelFunction(const Function &F)
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
constexpr auto seq(T Begin, T End)
Iterate over an integral type from Begin up to - but not including - End.
Definition Sequence.h:341
Align commonAlignment(Align A, uint64_t Offset)
Returns the alignment that satisfies both alignments.
Definition Alignment.h:206
unsigned getFromTypeWidthForLoad(const MemSDNode *Mem)
The bit-width of a single element loaded by Mem, i.e.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition BitVector.h:880
#define N
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39
constexpr uint64_t value() const
This is a hole in the type system and should not be abused.
Definition Alignment.h:82
@ PreserveSign
The sign of a flushed-to-zero number is preserved in the sign of 0.
DenormalModeKind Output
Denormal flushing mode for floating point instruction results in the default floating point environme...
Extended Value Type.
Definition ValueTypes.h:35
TypeSize getStoreSize() const
Return the number of bytes overwritten by a store of the specified value type.
Definition ValueTypes.h:418
bool isSimple() const
Test if the given EVT is simple (as opposed to being extended).
Definition ValueTypes.h:145
static EVT getVectorVT(LLVMContext &Context, EVT VT, unsigned NumElements, bool IsScalable=false)
Returns the EVT that represents a vector NumElements in length, where each element is of type VT.
Definition ValueTypes.h:70
EVT changeTypeToInteger() const
Return the type converted to an equivalently sized integer or vector with integer element type.
Definition ValueTypes.h:129
bool bitsGT(EVT VT) const
Return true if this has more bits than VT.
Definition ValueTypes.h:307
bool bitsLT(EVT VT) const
Return true if this has less bits than VT.
Definition ValueTypes.h:323
bool isFloatingPoint() const
Return true if this is a FP or a vector FP type.
Definition ValueTypes.h:155
ElementCount getVectorElementCount() const
Definition ValueTypes.h:373
bool is32BitVector() const
Return true if this is a 32-bit vector type.
Definition ValueTypes.h:220
TypeSize getSizeInBits() const
Return the size of the specified value type in bits.
Definition ValueTypes.h:396
uint64_t getScalarSizeInBits() const
Definition ValueTypes.h:408
MVT getSimpleVT() const
Return the SimpleValueType held in the specified simple EVT.
Definition ValueTypes.h:339
static EVT getIntegerVT(LLVMContext &Context, unsigned BitWidth)
Returns the EVT that represents an integer with the given number of bits.
Definition ValueTypes.h:61
uint64_t getFixedSizeInBits() const
Return the size of the specified fixed width value type in bits.
Definition ValueTypes.h:404
LLVM_ABI std::string getEVTString() const
This function returns value type as a string, e.g. "i32".
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
bool bitsEq(EVT VT) const
Return true if this has the same number of bits as VT.
Definition ValueTypes.h:279
LLVM_ABI Type * getTypeForEVT(LLVMContext &Context) const
This method returns an LLVM type corresponding to the specified EVT.
EVT widenIntegerElementType(LLVMContext &Context) const
Return a VT for an integer element type with doubled bit width.
Definition ValueTypes.h:467
EVT getVectorElementType() const
Given a vector type, return the type of each element.
Definition ValueTypes.h:351
EVT changeElementType(LLVMContext &Context, EVT EltVT) const
Return a VT for a type whose attributes match ourselves with the exception of the element type that i...
Definition ValueTypes.h:121
bool isScalarInteger() const
Return true if this is an integer, but not a vector.
Definition ValueTypes.h:165
unsigned getVectorNumElements() const
Given a vector type, return the number of elements it contains.
Definition ValueTypes.h:359
bool isInteger() const
Return true if this is an integer or a vector integer type.
Definition ValueTypes.h:160
static KnownBits makeConstant(const APInt &C)
Create known bits from a known constant.
Definition KnownBits.h:315
static LLVM_ABI KnownBits ashr(const KnownBits &LHS, const KnownBits &RHS, bool ShAmtNonZero=false, bool Exact=false)
Compute known bits for ashr(LHS, RHS).
KnownBits concat(const KnownBits &Lo) const
Concatenate the bits from Lo onto the bottom of *this.
Definition KnownBits.h:247
unsigned getBitWidth() const
Get the bit width of this value.
Definition KnownBits.h:44
unsigned countMaxActiveBits() const
Returns the maximum number of bits needed to represent all possible unsigned values with these known ...
Definition KnownBits.h:310
static LLVM_ABI KnownBits mul(const KnownBits &LHS, const KnownBits &RHS, bool NoUndefSelfMultiply=false)
Compute known bits resulting from multiplying LHS and RHS.
This class contains a discriminated union of information about pointers in memory operands,...
MachinePointerInfo getWithOffset(int64_t O) const
This struct is a compact representation of a valid (power of two) or undefined (0) alignment.
Definition Alignment.h:111
These are IR-level optimization flags that may be propagated to SDNodes.
bool hasAllowContract() const
This represents a list of ValueType's that has been intern'd by a SelectionDAG.
This represents an addressing mode of: BaseGV + BaseOffs + BaseReg + Scale*ScaleReg + ScalableOffset*...
This structure contains all information that is necessary for lowering calls.
SmallVector< ISD::InputArg, 32 > Ins
SmallVector< ISD::OutputArg, 32 > Outs
Type * RetTy
Same as OrigRetTy, or partially legalized for soft float libcalls.
LLVM_ABI SDValue CombineTo(SDNode *N, ArrayRef< SDValue > To, bool AddTo=true)
A convenience struct that encapsulates a DAG, and two SDValues for returning information from TargetL...