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