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