LLVM 24.0.0git
AMDGPULegalizerInfo.cpp
Go to the documentation of this file.
1//===- AMDGPULegalizerInfo.cpp -----------------------------------*- C++ -*-==//
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/// \file
9/// This file implements the targeting of the Machinelegalizer class for
10/// AMDGPU.
11/// \todo This should be generated by TableGen.
12//===----------------------------------------------------------------------===//
13
14#include "AMDGPULegalizerInfo.h"
15
16#include "AMDGPU.h"
18#include "AMDGPUInstrInfo.h"
19#include "AMDGPUMemoryUtils.h"
20#include "AMDGPUTargetMachine.h"
21#include "SIInstrInfo.h"
23#include "SIRegisterInfo.h"
25#include "llvm/ADT/ScopeExit.h"
36#include "llvm/IR/IntrinsicsAMDGPU.h"
37#include "llvm/IR/IntrinsicsR600.h"
38
39#define DEBUG_TYPE "amdgpu-legalinfo"
40
41using namespace llvm;
42using namespace LegalizeActions;
43using namespace LegalizeMutations;
44using namespace LegalityPredicates;
45using namespace MIPatternMatch;
46
47// Hack until load/store selection patterns support any tuple of legal types.
49 "amdgpu-global-isel-new-legality",
50 cl::desc("Use GlobalISel desired legality, rather than try to use"
51 "rules compatible with selection patterns"),
52 cl::init(false),
54
55static constexpr unsigned MaxRegisterSize = 1024;
56
57// Round the number of elements to the next power of two elements
59 unsigned NElts = Ty.getNumElements();
60 unsigned Pow2NElts = 1 << Log2_32_Ceil(NElts);
61 return Ty.changeElementCount(ElementCount::getFixed(Pow2NElts));
62}
63
64// Round the number of bits to the next power of two bits
66 unsigned Bits = Ty.getSizeInBits();
67 unsigned Pow2Bits = 1 << Log2_32_Ceil(Bits);
68 return LLT::scalar(Pow2Bits);
69}
70
71/// \returns true if this is an odd sized vector which should widen by adding an
72/// additional element. This is mostly to handle <3 x s16> -> <4 x s16>. This
73/// excludes s1 vectors, which should always be scalarized.
74static LegalityPredicate isSmallOddVector(unsigned TypeIdx) {
75 return [=](const LegalityQuery &Query) {
76 const LLT Ty = Query.Types[TypeIdx];
77 if (!Ty.isVector())
78 return false;
79
80 const LLT EltTy = Ty.getElementType();
81 const unsigned EltSize = EltTy.getSizeInBits();
82 return Ty.getNumElements() % 2 != 0 &&
83 EltSize > 1 && EltSize < 32 &&
84 Ty.getSizeInBits() % 32 != 0;
85 };
86}
87
88static LegalityPredicate sizeIsMultipleOf32(unsigned TypeIdx) {
89 return [=](const LegalityQuery &Query) {
90 const LLT Ty = Query.Types[TypeIdx];
91 return Ty.getSizeInBits() % 32 == 0;
92 };
93}
94
95static LegalityPredicate isWideVec16(unsigned TypeIdx) {
96 return [=](const LegalityQuery &Query) {
97 const LLT Ty = Query.Types[TypeIdx];
98 const LLT EltTy = Ty.getScalarType();
99 return EltTy.getSizeInBits() == 16 && Ty.getNumElements() > 2;
100 };
101}
102
103static LegalizeMutation oneMoreElement(unsigned TypeIdx) {
104 return [=](const LegalityQuery &Query) {
105 const LLT Ty = Query.Types[TypeIdx];
106 const LLT EltTy = Ty.getElementType();
107 return std::pair(TypeIdx,
108 LLT::fixed_vector(Ty.getNumElements() + 1, EltTy));
109 };
110}
111
113 return [=](const LegalityQuery &Query) {
114 const LLT Ty = Query.Types[TypeIdx];
115 const LLT EltTy = Ty.getElementType();
116 unsigned Size = Ty.getSizeInBits();
117 unsigned Pieces = (Size + 63) / 64;
118 unsigned NewNumElts = (Ty.getNumElements() + 1) / Pieces;
119 return std::pair(TypeIdx, LLT::scalarOrVector(
120 ElementCount::getFixed(NewNumElts), EltTy));
121 };
122}
123
124// Increase the number of vector elements to reach the next multiple of 32-bit
125// type.
126static LegalizeMutation moreEltsToNext32Bit(unsigned TypeIdx) {
127 return [=](const LegalityQuery &Query) {
128 const LLT Ty = Query.Types[TypeIdx];
129
130 const LLT EltTy = Ty.getElementType();
131 const int Size = Ty.getSizeInBits();
132 const int EltSize = EltTy.getSizeInBits();
133 const int NextMul32 = (Size + 31) / 32;
134
135 assert(EltSize < 32);
136
137 const int NewNumElts = (32 * NextMul32 + EltSize - 1) / EltSize;
138 return std::pair(TypeIdx, LLT::fixed_vector(NewNumElts, EltTy));
139 };
140}
141
142// Retrieves the scalar type that's the same size as the mem desc
144 return [=](const LegalityQuery &Query) {
145 unsigned MemSize = Query.MMODescrs[0].MemoryTy.getSizeInBits();
146 return std::make_pair(TypeIdx, LLT::integer(MemSize));
147 };
148}
149
150// Increase the number of vector elements to reach the next legal RegClass.
152 return [=](const LegalityQuery &Query) {
153 const LLT Ty = Query.Types[TypeIdx];
154 const unsigned NumElts = Ty.getNumElements();
155 const unsigned EltSize = Ty.getElementType().getSizeInBits();
156 const unsigned MaxNumElts = MaxRegisterSize / EltSize;
157
158 assert(EltSize == 32 || EltSize == 64);
159 assert(Ty.getSizeInBits() < MaxRegisterSize);
160
161 unsigned NewNumElts;
162 // Find the nearest legal RegClass that is larger than the current type.
163 for (NewNumElts = NumElts; NewNumElts < MaxNumElts; ++NewNumElts) {
164 if (SIRegisterInfo::getSGPRClassForBitWidth(NewNumElts * EltSize))
165 break;
166 }
167 return std::pair(TypeIdx,
168 LLT::fixed_vector(NewNumElts, Ty.getElementType()));
169 };
170}
171
173 if (!Ty.isVector())
174 return LLT::scalar(128);
175 const ElementCount NumElems = Ty.getElementCount();
176 return LLT::vector(NumElems, LLT::scalar(128));
177}
178
180 if (!Ty.isVector())
181 return LLT::fixed_vector(4, LLT::integer(32));
182 const unsigned NumElems = Ty.getElementCount().getFixedValue();
183 return LLT::fixed_vector(NumElems * 4, LLT::integer(32));
184}
185
187 const unsigned Size = Ty.getSizeInBits();
188
189 if (Size <= 32) {
190 // <2 x i8> -> i16
191 // <4 x i8> -> i32
192 return LLT::integer(Size);
193 }
194
195 return LLT::fixed_vector(Size / 32, LLT::integer(32));
196}
197
198static LegalizeMutation bitcastToRegisterType(unsigned TypeIdx) {
199 return [=](const LegalityQuery &Query) {
200 const LLT Ty = Query.Types[TypeIdx];
201 return std::pair(TypeIdx, getBitcastRegisterType(Ty));
202 };
203}
204
206 return [=](const LegalityQuery &Query) {
207 const LLT Ty = Query.Types[TypeIdx];
208 unsigned Size = Ty.getSizeInBits();
209 assert(Size % 32 == 0);
210 return std::pair(TypeIdx,
212 LLT::integer(32)));
213 };
214}
215
216static LegalityPredicate vectorSmallerThan(unsigned TypeIdx, unsigned Size) {
217 return [=](const LegalityQuery &Query) {
218 const LLT QueryTy = Query.Types[TypeIdx];
219 return QueryTy.isVector() && QueryTy.getSizeInBits() < Size;
220 };
221}
222
223static LegalityPredicate vectorWiderThan(unsigned TypeIdx, unsigned Size) {
224 return [=](const LegalityQuery &Query) {
225 const LLT QueryTy = Query.Types[TypeIdx];
226 return QueryTy.isVector() && QueryTy.getSizeInBits() > Size;
227 };
228}
229
230static LegalityPredicate numElementsNotEven(unsigned TypeIdx) {
231 return [=](const LegalityQuery &Query) {
232 const LLT QueryTy = Query.Types[TypeIdx];
233 return QueryTy.isVector() && QueryTy.getNumElements() % 2 != 0;
234 };
235}
236
237static bool isRegisterSize(const GCNSubtarget &ST, unsigned Size) {
238 return ((ST.useRealTrue16Insts() && Size == 16) || Size % 32 == 0) &&
240}
241
243 const int EltSize = EltTy.getSizeInBits();
244 return EltSize == 16 || EltSize % 32 == 0;
245}
246
247static bool isRegisterVectorType(LLT Ty) {
248 const int EltSize = Ty.getElementType().getSizeInBits();
249 return EltSize == 32 || EltSize == 64 ||
250 (EltSize == 16 && Ty.getNumElements() % 2 == 0) ||
251 EltSize == 128 || EltSize == 256;
252}
253
254// TODO: replace all uses of isRegisterType with isRegisterClassType
255static bool isRegisterType(const GCNSubtarget &ST, LLT Ty) {
256 if (!isRegisterSize(ST, Ty.getSizeInBits()))
257 return false;
258
259 if (Ty.isVector())
260 return isRegisterVectorType(Ty);
261
262 return true;
263}
264
265// Any combination of 32 or 64-bit elements up the maximum register size, and
266// multiples of v2s16.
268 unsigned TypeIdx) {
269 return [=, &ST](const LegalityQuery &Query) {
270 return isRegisterType(ST, Query.Types[TypeIdx]);
271 };
272}
273
274// RegisterType that doesn't have a corresponding RegClass.
275// TODO: Once `isRegisterType` is replaced with `isRegisterClassType` this
276// should be removed.
278 unsigned TypeIdx) {
279 return [=, &ST](const LegalityQuery &Query) {
280 LLT Ty = Query.Types[TypeIdx];
281 return isRegisterType(ST, Ty) &&
282 !SIRegisterInfo::getSGPRClassForBitWidth(Ty.getSizeInBits());
283 };
284}
285
286static LegalityPredicate elementTypeIsLegal(unsigned TypeIdx) {
287 return [=](const LegalityQuery &Query) {
288 const LLT QueryTy = Query.Types[TypeIdx];
289 if (!QueryTy.isVector())
290 return false;
291 const LLT EltTy = QueryTy.getElementType();
292 return EltTy == LLT::scalar(16) || EltTy.getSizeInBits() >= 32;
293 };
294}
295
296constexpr LLT F16 = LLT::float16();
297constexpr LLT BF16 = LLT::bfloat16();
298constexpr LLT F32 = LLT::float32();
299constexpr LLT F64 = LLT::float64();
304
305constexpr LLT S1 = LLT::scalar(1);
306constexpr LLT S8 = LLT::scalar(8);
307constexpr LLT S16 = LLT::scalar(16);
308constexpr LLT S32 = LLT::scalar(32);
309constexpr LLT S64 = LLT::scalar(64);
310constexpr LLT S96 = LLT::scalar(96);
311constexpr LLT S128 = LLT::scalar(128);
312constexpr LLT S160 = LLT::scalar(160);
313constexpr LLT S192 = LLT::scalar(192);
314constexpr LLT S224 = LLT::scalar(224);
315constexpr LLT S256 = LLT::scalar(256);
316constexpr LLT S512 = LLT::scalar(512);
317constexpr LLT S1024 = LLT::scalar(1024);
319
320constexpr LLT V2S8 = LLT::fixed_vector(2, 8);
321constexpr LLT V2S16 = LLT::fixed_vector(2, 16);
322constexpr LLT V4S16 = LLT::fixed_vector(4, 16);
323constexpr LLT V6S16 = LLT::fixed_vector(6, 16);
324constexpr LLT V8S16 = LLT::fixed_vector(8, 16);
325constexpr LLT V10S16 = LLT::fixed_vector(10, 16);
326constexpr LLT V12S16 = LLT::fixed_vector(12, 16);
327constexpr LLT V16S16 = LLT::fixed_vector(16, 16);
328
329constexpr LLT V2S32 = LLT::fixed_vector(2, 32);
330constexpr LLT V3S32 = LLT::fixed_vector(3, 32);
331constexpr LLT V4S32 = LLT::fixed_vector(4, 32);
332constexpr LLT V5S32 = LLT::fixed_vector(5, 32);
333constexpr LLT V6S32 = LLT::fixed_vector(6, 32);
334constexpr LLT V7S32 = LLT::fixed_vector(7, 32);
335constexpr LLT V8S32 = LLT::fixed_vector(8, 32);
336constexpr LLT V9S32 = LLT::fixed_vector(9, 32);
337constexpr LLT V10S32 = LLT::fixed_vector(10, 32);
338constexpr LLT V11S32 = LLT::fixed_vector(11, 32);
339constexpr LLT V12S32 = LLT::fixed_vector(12, 32);
340constexpr LLT V16S32 = LLT::fixed_vector(16, 32);
341constexpr LLT V32S32 = LLT::fixed_vector(32, 32);
342
343constexpr LLT V2S64 = LLT::fixed_vector(2, 64);
344constexpr LLT V3S64 = LLT::fixed_vector(3, 64);
345constexpr LLT V4S64 = LLT::fixed_vector(4, 64);
346constexpr LLT V5S64 = LLT::fixed_vector(5, 64);
347constexpr LLT V6S64 = LLT::fixed_vector(6, 64);
348constexpr LLT V7S64 = LLT::fixed_vector(7, 64);
349constexpr LLT V8S64 = LLT::fixed_vector(8, 64);
350constexpr LLT V16S64 = LLT::fixed_vector(16, 64);
351
352constexpr LLT V2S128 = LLT::fixed_vector(2, 128);
353constexpr LLT V4S128 = LLT::fixed_vector(4, 128);
354
355constexpr std::initializer_list<LLT> AllScalarTypes = {
357
358constexpr std::initializer_list<LLT> AllS16Vectors{
360
361constexpr std::initializer_list<LLT> AllS32Vectors = {
364
365constexpr std::initializer_list<LLT> AllS64Vectors = {
367
373
374// Checks whether a type is in the list of legal register types.
375static bool isRegisterClassType(const GCNSubtarget &ST, LLT Ty) {
376 if (Ty.isPointerOrPointerVector())
377 Ty = Ty.changeElementType(LLT::scalar(Ty.getScalarSizeInBits()));
378
381 (ST.useRealTrue16Insts() && Ty == S16) ||
383}
384
386 unsigned TypeIdx) {
387 return [&ST, TypeIdx](const LegalityQuery &Query) {
388 return isRegisterClassType(ST, Query.Types[TypeIdx]);
389 };
390}
391
392// If we have a truncating store or an extending load with a data size larger
393// than 32-bits, we need to reduce to a 32-bit type.
395 return [=](const LegalityQuery &Query) {
396 const LLT Ty = Query.Types[TypeIdx];
397 return !Ty.isVector() && Ty.getSizeInBits() > 32 &&
398 Query.MMODescrs[0].MemoryTy.getSizeInBits() < Ty.getSizeInBits();
399 };
400}
401
402// If we have a truncating store or an extending load with a data size larger
403// than 32-bits and mem location is a power of 2
405 return [=](const LegalityQuery &Query) {
406 unsigned MemSize = Query.MMODescrs[0].MemoryTy.getSizeInBits();
407 return isWideScalarExtLoadTruncStore(TypeIdx)(Query) &&
408 isPowerOf2_64(MemSize);
409 };
410}
411
412// TODO: Should load to s16 be legal? Most loads extend to 32-bits, but we
413// handle some operations by just promoting the register during
414// selection. There are also d16 loads on GFX9+ which preserve the high bits.
415static unsigned maxSizeForAddrSpace(const GCNSubtarget &ST, unsigned AS,
416 bool IsLoad, bool IsAtomic) {
417 switch (AS) {
419 // FIXME: Private element size.
420 return ST.hasFlatScratchEnabled() ? 128 : 32;
422 return ST.useDS128() ? 128 : 64;
427 // Treat constant and global as identical. SMRD loads are sometimes usable for
428 // global loads (ideally constant address space should be eliminated)
429 // depending on the context. Legality cannot be context dependent, but
430 // RegBankSelect can split the load as necessary depending on the pointer
431 // register bank/uniformity and if the memory is invariant or not written in a
432 // kernel.
433 return IsLoad ? 512 : 128;
434 default:
435 // FIXME: Flat addresses may contextually need to be split to 32-bit parts
436 // if they may alias scratch depending on the subtarget. This needs to be
437 // moved to custom handling to use addressMayBeAccessedAsPrivate
438 return ST.hasMultiDwordFlatScratchAddressing() || IsAtomic ? 128 : 32;
439 }
440}
441
442static bool isLoadStoreSizeLegal(const GCNSubtarget &ST,
443 const LegalityQuery &Query) {
444 const LLT Ty = Query.Types[0];
445
446 // Handle G_LOAD, G_ZEXTLOAD, G_SEXTLOAD
447 const bool IsLoad = Query.Opcode != AMDGPU::G_STORE;
448
449 unsigned RegSize = Ty.getSizeInBits();
450 uint64_t MemSize = Query.MMODescrs[0].MemoryTy.getSizeInBits();
451 uint64_t AlignBits = Query.MMODescrs[0].AlignInBits;
452 unsigned AS = Query.Types[1].getAddressSpace();
453
454 // All of these need to be custom lowered to cast the pointer operand.
456 return false;
457
458 // Do not handle extending vector loads.
459 if (Ty.isVector() && MemSize != RegSize)
460 return false;
461
462 // TODO: We should be able to widen loads if the alignment is high enough, but
463 // we also need to modify the memory access size.
464#if 0
465 // Accept widening loads based on alignment.
466 if (IsLoad && MemSize < Size)
467 MemSize = std::max(MemSize, Align);
468#endif
469
470 // Only 1-byte and 2-byte to 32-bit extloads are valid.
471 if (MemSize != RegSize && RegSize != 32)
472 return false;
473
474 if (MemSize > maxSizeForAddrSpace(ST, AS, IsLoad,
475 Query.MMODescrs[0].Ordering !=
477 return false;
478
479 switch (MemSize) {
480 case 8:
481 case 16:
482 case 32:
483 case 64:
484 case 128:
485 break;
486 case 96:
487 if (!ST.hasDwordx3LoadStores())
488 return false;
489 break;
490 case 256:
491 case 512:
492 // These may contextually need to be broken down.
493 break;
494 default:
495 return false;
496 }
497
498 assert(RegSize >= MemSize);
499
500 if (AlignBits < MemSize) {
501 const SITargetLowering *TLI = ST.getTargetLowering();
502 if (!TLI->allowsMisalignedMemoryAccessesImpl(MemSize, AS,
503 Align(AlignBits / 8)))
504 return false;
505 }
506
507 return true;
508}
509
510// The newer buffer intrinsic forms take their resource arguments as
511// pointers in address space 8, aka s128 values. However, in order to not break
512// SelectionDAG, the underlying operations have to continue to take v4i32
513// arguments. Therefore, we convert resource pointers - or vectors of them
514// to integer values here.
515static bool hasBufferRsrcWorkaround(const LLT Ty) {
516 if (Ty.isPointer() && Ty.getAddressSpace() == AMDGPUAS::BUFFER_RESOURCE)
517 return true;
518 if (Ty.isVector()) {
519 const LLT ElemTy = Ty.getElementType();
520 return hasBufferRsrcWorkaround(ElemTy);
521 }
522 return false;
523}
524
525// The current selector can't handle <6 x s16>, <8 x s16>, s96, s128 etc, so
526// workaround this. Eventually it should ignore the type for loads and only care
527// about the size. Return true in cases where we will workaround this for now by
528// bitcasting.
529static bool loadStoreBitcastWorkaround(const LLT Ty) {
531 return false;
532
533 const unsigned Size = Ty.getSizeInBits();
534 if (Ty.isPointerVector())
535 return true;
536 if (Size <= 64)
537 return false;
538 // Address space 8 pointers get their own workaround.
540 return false;
541 if (!Ty.isVector())
542 return true;
543
544 unsigned EltSize = Ty.getScalarSizeInBits();
545 return EltSize != 32 && EltSize != 64;
546}
547
548static bool isLoadStoreLegal(const GCNSubtarget &ST, const LegalityQuery &Query) {
549 const LLT Ty = Query.Types[0];
550 return isRegisterType(ST, Ty) && isLoadStoreSizeLegal(ST, Query) &&
552}
553
554/// Return true if a load or store of the type should be lowered with a bitcast
555/// to a different type.
556static bool shouldBitcastLoadStoreType(const GCNSubtarget &ST, const LLT Ty,
557 const LLT MemTy) {
558 const unsigned MemSizeInBits = MemTy.getSizeInBits();
559 const unsigned Size = Ty.getSizeInBits();
560 if (Size != MemSizeInBits)
561 return Size <= 32 && Ty.isVector();
562
564 return true;
565
566 // Don't try to handle bitcasting vector ext loads for now.
567 return Ty.isVector() && (!MemTy.isVector() || MemTy == Ty) &&
568 (Size <= 32 || isRegisterSize(ST, Size)) &&
569 !isRegisterVectorElementType(Ty.getElementType());
570}
571
572/// Return true if we should legalize a load by widening an odd sized memory
573/// access up to the alignment. Note this case when the memory access itself
574/// changes, not the size of the result register.
575static bool shouldWidenLoad(const GCNSubtarget &ST, LLT MemoryTy,
576 uint64_t AlignInBits, unsigned AddrSpace,
577 unsigned Opcode) {
578 unsigned SizeInBits = MemoryTy.getSizeInBits();
579 // We don't want to widen cases that are naturally legal.
580 if (isPowerOf2_32(SizeInBits))
581 return false;
582
583 // If we have 96-bit memory operations, we shouldn't touch them. Note we may
584 // end up widening these for a scalar load during RegBankSelect, if we don't
585 // have 96-bit scalar loads.
586 if (SizeInBits == 96 && ST.hasDwordx3LoadStores())
587 return false;
588
589 if (SizeInBits >= maxSizeForAddrSpace(ST, AddrSpace, Opcode, false))
590 return false;
591
592 // A load is known dereferenceable up to the alignment, so it's legal to widen
593 // to it.
594 //
595 // TODO: Could check dereferenceable for less aligned cases.
596 unsigned RoundedSize = NextPowerOf2(SizeInBits);
597 if (AlignInBits < RoundedSize)
598 return false;
599
600 // Do not widen if it would introduce a slow unaligned load.
601 const SITargetLowering *TLI = ST.getTargetLowering();
602 unsigned Fast = 0;
604 RoundedSize, AddrSpace, Align(AlignInBits / 8),
606 Fast;
607}
608
609static bool shouldWidenLoad(const GCNSubtarget &ST, const LegalityQuery &Query,
610 unsigned Opcode) {
611 if (Query.MMODescrs[0].Ordering != AtomicOrdering::NotAtomic)
612 return false;
613
614 return shouldWidenLoad(ST, Query.MMODescrs[0].MemoryTy,
615 Query.MMODescrs[0].AlignInBits,
616 Query.Types[1].getAddressSpace(), Opcode);
617}
618
619/// Mutates IR (typicaly a load instruction) to use a <4 x s32> as the initial
620/// type of the operand `idx` and then to transform it to a `p8` via bitcasts
621/// and inttoptr. In addition, handle vectors of p8. Returns the new type.
623 MachineRegisterInfo &MRI, unsigned Idx) {
624 MachineOperand &MO = MI.getOperand(Idx);
625
626 const LLT PointerTy = MRI.getType(MO.getReg());
627
628 // Paranoidly prevent us from doing this multiple times.
630 return PointerTy;
631
632 const LLT ScalarTy = getBufferRsrcScalarType(PointerTy);
633 const LLT VectorTy = getBufferRsrcRegisterType(PointerTy);
634 if (!PointerTy.isVector()) {
635 // Happy path: (4 x s32) -> (s32, s32, s32, s32) -> (p8)
636 const unsigned NumParts = PointerTy.getSizeInBits() / 32;
637 const LLT I32 = LLT::integer(32);
638
639 Register VectorReg = MRI.createGenericVirtualRegister(VectorTy);
640 std::array<Register, 4> VectorElems;
641 B.setInsertPt(B.getMBB(), ++B.getInsertPt());
642 for (unsigned I = 0; I < NumParts; ++I)
643 VectorElems[I] =
644 B.buildExtractVectorElementConstant(I32, VectorReg, I).getReg(0);
645 B.buildMergeValues(MO, VectorElems);
646 MO.setReg(VectorReg);
647 return VectorTy;
648 }
649 Register BitcastReg = MRI.createGenericVirtualRegister(VectorTy);
650 B.setInsertPt(B.getMBB(), ++B.getInsertPt());
651 auto Scalar = B.buildBitcast(ScalarTy, BitcastReg);
652 B.buildIntToPtr(MO, Scalar);
653 MO.setReg(BitcastReg);
654
655 return VectorTy;
656}
657
658/// Cast a buffer resource (an address space 8 pointer) into a 4xi32, which is
659/// the form in which the value must be in order to be passed to the low-level
660/// representations used for MUBUF/MTBUF intrinsics. This is a hack, which is
661/// needed in order to account for the fact that we can't define a register
662/// class for s128 without breaking SelectionDAG.
664 MachineRegisterInfo &MRI = *B.getMRI();
665 const LLT PointerTy = MRI.getType(Pointer);
666 const LLT ScalarTy = getBufferRsrcScalarType(PointerTy);
667 const LLT VectorTy = getBufferRsrcRegisterType(PointerTy);
668
669 if (!PointerTy.isVector()) {
670 // Special case: p8 -> (s32, s32, s32, s32) -> (4xs32)
671 SmallVector<Register, 4> PointerParts;
672 const unsigned NumParts = PointerTy.getSizeInBits() / 32;
673 auto Unmerged = B.buildUnmerge(LLT::integer(32), Pointer);
674 for (unsigned I = 0; I < NumParts; ++I)
675 PointerParts.push_back(Unmerged.getReg(I));
676 return B.buildBuildVector(VectorTy, PointerParts).getReg(0);
677 }
678 Register Scalar = B.buildPtrToInt(ScalarTy, Pointer).getReg(0);
679 return B.buildBitcast(VectorTy, Scalar).getReg(0);
680}
681
683 unsigned Idx) {
684 MachineOperand &MO = MI.getOperand(Idx);
685
686 const LLT PointerTy = B.getMRI()->getType(MO.getReg());
687 // Paranoidly prevent us from doing this multiple times.
689 return;
691}
692
694 const GCNTargetMachine &TM)
695 : ST(ST_) {
696 using namespace TargetOpcode;
697
698 auto GetAddrSpacePtr = [&TM](unsigned AS) {
699 return LLT::pointer(AS, TM.getPointerSizeInBits(AS));
700 };
701
702 const LLT GlobalPtr = GetAddrSpacePtr(AMDGPUAS::GLOBAL_ADDRESS);
703 const LLT ConstantPtr = GetAddrSpacePtr(AMDGPUAS::CONSTANT_ADDRESS);
704 const LLT Constant32Ptr = GetAddrSpacePtr(AMDGPUAS::CONSTANT_ADDRESS_32BIT);
705 const LLT LocalPtr = GetAddrSpacePtr(AMDGPUAS::LOCAL_ADDRESS);
706 const LLT RegionPtr = GetAddrSpacePtr(AMDGPUAS::REGION_ADDRESS);
707 const LLT FlatPtr = GetAddrSpacePtr(AMDGPUAS::FLAT_ADDRESS);
708 const LLT PrivatePtr = GetAddrSpacePtr(AMDGPUAS::PRIVATE_ADDRESS);
709 const LLT BufferFatPtr = GetAddrSpacePtr(AMDGPUAS::BUFFER_FAT_POINTER);
710 const LLT RsrcPtr = GetAddrSpacePtr(AMDGPUAS::BUFFER_RESOURCE);
711 const LLT BufferStridedPtr =
712 GetAddrSpacePtr(AMDGPUAS::BUFFER_STRIDED_POINTER);
713
714 const LLT CodePtr = FlatPtr;
715
716 const std::initializer_list<LLT> AddrSpaces64 = {
717 GlobalPtr, ConstantPtr, FlatPtr
718 };
719
720 const std::initializer_list<LLT> AddrSpaces32 = {
721 LocalPtr, PrivatePtr, Constant32Ptr, RegionPtr
722 };
723
724 const std::initializer_list<LLT> AddrSpaces128 = {RsrcPtr};
725
726 const std::initializer_list<LLT> FPTypesBase = {F32, F64};
727 const std::initializer_list<LLT> FPTypes16 = {F32, F64, F16};
728 const std::initializer_list<LLT> FPTypesPK16 = {F32, F64, F16, V2F16};
729 const std::initializer_list<LLT> FPTypesPK16_64 = {F32, F64, F16, V2F16,
730 V2F64};
731
732 const LLT MinExtendedFPTy = ST.has16BitInsts() ? F16 : F32;
733 const LLT I1 = LLT::integer(1);
734 const LLT I16 = LLT::integer(16);
735 const LLT I32 = LLT::integer(32);
736 const LLT I64 = LLT::integer(64);
737 const LLT V2I16 = LLT::fixed_vector(2, I16);
738
740
741 // s1 for VCC branches, s32 for SCC branches.
743
744 // TODO: All multiples of 32, vectors of pointers, all v2s16 pairs, more
745 // elements for v3s16
748 .legalFor(AllS32Vectors)
750 .legalFor(AddrSpaces64)
751 .legalFor(AddrSpaces32)
752 .legalFor(AddrSpaces128)
753 .legalIf(isPointer(0))
754 .clampScalar(0, S16, S256)
756 .clampMaxNumElements(0, S32, 16)
758 .scalarize(0);
759
760 if (ST.hasVOP3PInsts() && ST.hasAddNoCarryInsts() && ST.hasIntClamp()) {
761 // Full set of gfx9 features.
762 if (ST.hasAnyPackedU64Ops()) {
763 getActionDefinitionsBuilder({G_ADD, G_SUB})
764 .legalFor({S64, S32, S16, V2S16, V2S64})
765 .clampMaxNumElementsStrict(0, S16, 2)
767 .scalarize(0)
768 .minScalar(0, S16)
770 .maxScalar(0, S32);
771 } else if (ST.hasScalarAddSub64()) {
772 getActionDefinitionsBuilder({G_ADD, G_SUB})
773 .legalFor({S64, S32, S16, V2S16})
774 .clampMaxNumElementsStrict(0, S16, 2)
775 .scalarize(0)
776 .minScalar(0, S16)
778 .maxScalar(0, S32);
779 } else {
780 getActionDefinitionsBuilder({G_ADD, G_SUB})
781 .legalFor({S32, S16, V2S16})
782 .clampMaxNumElementsStrict(0, S16, 2)
783 .scalarize(0)
784 .minScalar(0, S16)
786 .maxScalar(0, S32);
787 }
788
789 if (ST.hasScalarSMulU64()) {
791 .legalFor({S64, S32, S16, V2S16})
792 .clampMaxNumElementsStrict(0, S16, 2)
793 .scalarize(0)
794 .minScalar(0, S16)
796 .custom();
797 } else {
799 .legalFor({S32, S16, V2S16})
800 .clampMaxNumElementsStrict(0, S16, 2)
801 .scalarize(0)
802 .minScalar(0, S16)
804 .custom();
805 }
806 assert(ST.hasMad64_32());
807
808 getActionDefinitionsBuilder({G_UADDSAT, G_USUBSAT, G_SADDSAT, G_SSUBSAT})
809 .legalFor({S32, S16, V2S16}) // Clamp modifier
810 .minScalarOrElt(0, S16)
812 .scalarize(0)
814 .lower();
815 } else if (ST.has16BitInsts()) {
816 getActionDefinitionsBuilder({G_ADD, G_SUB})
817 .legalFor({S32, S16})
818 .minScalar(0, S16)
820 .maxScalar(0, S32)
821 .scalarize(0);
822
824 .legalFor({S32, S16})
825 .scalarize(0)
826 .minScalar(0, S16)
828 .custom();
829 assert(ST.hasMad64_32());
830
831 // Technically the saturating operations require clamp bit support, but this
832 // was introduced at the same time as 16-bit operations.
833 getActionDefinitionsBuilder({G_UADDSAT, G_USUBSAT})
834 .legalFor({S32, S16}) // Clamp modifier
835 .minScalar(0, S16)
836 .scalarize(0)
838 .lower();
839
840 // We're just lowering this, but it helps get a better result to try to
841 // coerce to the desired type first.
842 getActionDefinitionsBuilder({G_SADDSAT, G_SSUBSAT})
843 .minScalar(0, S16)
844 .scalarize(0)
845 .lower();
846 } else {
847 getActionDefinitionsBuilder({G_ADD, G_SUB})
848 .legalFor({S32})
849 .widenScalarToNextMultipleOf(0, 32)
850 .clampScalar(0, S32, S32)
851 .scalarize(0);
852
853 auto &Mul = getActionDefinitionsBuilder(G_MUL)
854 .legalFor({S32})
855 .scalarize(0)
856 .minScalar(0, S32)
858
859 if (ST.hasMad64_32())
860 Mul.custom();
861 else
862 Mul.maxScalar(0, S32);
863
864 if (ST.hasIntClamp()) {
865 getActionDefinitionsBuilder({G_UADDSAT, G_USUBSAT})
866 .legalFor({S32}) // Clamp modifier.
867 .scalarize(0)
869 .lower();
870 } else {
871 // Clamp bit support was added in VI, along with 16-bit operations.
872 getActionDefinitionsBuilder({G_UADDSAT, G_USUBSAT})
873 .minScalar(0, S32)
874 .scalarize(0)
875 .lower();
876 }
877
878 // FIXME: DAG expansion gets better results. The widening uses the smaller
879 // range values and goes for the min/max lowering directly.
880 getActionDefinitionsBuilder({G_SADDSAT, G_SSUBSAT})
881 .minScalar(0, S32)
882 .scalarize(0)
883 .lower();
884 }
885
887 {G_SDIV, G_UDIV, G_SREM, G_UREM, G_SDIVREM, G_UDIVREM})
888 .customFor({S32, S64})
889 .clampScalar(0, S32, S64)
891 .scalarize(0);
892
893 auto &Mulh = getActionDefinitionsBuilder({G_UMULH, G_SMULH})
894 .legalFor({S32})
895 .maxScalar(0, S32);
896
897 if (ST.hasVOP3PInsts()) {
898 Mulh
899 .clampMaxNumElements(0, S8, 2)
900 .lowerFor({V2S8});
901 }
902
903 Mulh
904 .scalarize(0)
905 .lower();
906
907 // Report legal for any types we can handle anywhere. For the cases only legal
908 // on the SALU, RegBankSelect will be able to re-legalize.
909 getActionDefinitionsBuilder({G_AND, G_OR, G_XOR})
910 .legalFor({S32, S1, S64, V2S32, S16, V2S16, V4S16})
911 .clampScalar(0, S32, S64)
917 .scalarize(0);
918
920 {G_UADDO, G_USUBO, G_UADDE, G_SADDE, G_USUBE, G_SSUBE})
921 .legalFor({{S32, S1}, {S32, S32}})
922 .clampScalar(0, S32, S32)
923 .scalarize(0);
924
926 // Don't worry about the size constraint.
928 .widenScalarIf(all(typeInSet(0, {I16, F16, BF16}), isScalar(1)),
929 changeTo(0, LLT::integer(32)))
930 .widenScalarIf(all(isScalar(0), typeInSet(1, {I16, F16, BF16})),
931 changeTo(1, LLT::integer(32)))
932 .lower();
933
935 .legalFor({S1, S32, S64, S16, GlobalPtr,
936 LocalPtr, ConstantPtr, PrivatePtr, FlatPtr })
937 .legalIf(isPointer(0))
938 .clampScalar(0, S32, S64)
940
942
943 getActionDefinitionsBuilder({G_IMPLICIT_DEF, G_FREEZE})
944 .legalIf(isRegisterClassType(ST, 0))
945 // s1 and s16 are special cases because they have legal operations on
946 // them, but don't really occupy registers in the normal way.
947 .legalFor({S1, S16})
948 .clampNumElements(0, V16S32, V32S32)
952 .clampMaxNumElements(0, S32, 16);
953
954 getActionDefinitionsBuilder(G_FRAME_INDEX).legalFor({PrivatePtr});
955
956 // If the amount is divergent, we have to do a wave reduction to get the
957 // maximum value, so this is expanded during RegBankSelect.
958 getActionDefinitionsBuilder(G_DYN_STACKALLOC)
959 .legalFor({{PrivatePtr, S32}});
960
961 getActionDefinitionsBuilder(G_STACKSAVE)
962 .customFor({PrivatePtr});
963 getActionDefinitionsBuilder(G_STACKRESTORE)
964 .legalFor({PrivatePtr});
965
966 getActionDefinitionsBuilder({G_GET_FPENV, G_SET_FPENV}).customFor({S64});
967
968 getActionDefinitionsBuilder({G_GET_ROUNDING, G_SET_ROUNDING}).legalFor({S32});
969
970 getActionDefinitionsBuilder(G_GLOBAL_VALUE)
971 .customIf(typeIsNot(0, PrivatePtr));
972
973 getActionDefinitionsBuilder(G_BLOCK_ADDR).legalFor({CodePtr});
974
975 auto &FPOpActions =
976 getActionDefinitionsBuilder({G_FADD, G_FMUL, G_FMA}).legalFor({F32, F64});
977 auto &FCanonicalizeActions =
978 getActionDefinitionsBuilder(G_FCANONICALIZE).legalFor({F32, F64});
979 auto &StrictFPOpActions =
980 getActionDefinitionsBuilder({G_STRICT_FADD, G_STRICT_FMUL, G_STRICT_FMA})
981 .legalFor({F32, F64});
982 auto &TrigActions =
983 getActionDefinitionsBuilder({G_FSIN, G_FCOS}).customFor({F32, F64});
984 auto &FDIVActions = getActionDefinitionsBuilder(G_FDIV).customFor({F32, F64});
985
986 if (ST.has16BitInsts()) {
987 if (ST.hasVOP3PInsts()) {
988 FPOpActions.legalFor({F16, V2F16});
989 FCanonicalizeActions.legalFor({F16, V2F16});
990 StrictFPOpActions.legalFor({F16, V2F16});
991 } else {
992 FPOpActions.legalFor({F16});
993 FCanonicalizeActions.legalFor({F16});
994 StrictFPOpActions.legalFor({F16});
995 }
996
997 TrigActions.customFor({F16});
998 FDIVActions.customFor({F16});
999 }
1000
1001 FPOpActions.widenScalarFor({BF16}, changeElementTo(0, F32));
1002 FCanonicalizeActions.widenScalarFor({BF16}, changeElementTo(0, F32));
1003
1004 if (ST.hasAnyPackedFP32Ops()) {
1005 FPOpActions.legalFor({V2F32});
1006 FCanonicalizeActions.legalFor({V2F32});
1007 StrictFPOpActions.legalFor({V2F32});
1008 FPOpActions.clampMaxNumElementsStrict(0, F32, 2);
1009 FCanonicalizeActions.clampMaxNumElementsStrict(0, F32, 2);
1010 StrictFPOpActions.clampMaxNumElementsStrict(0, F32, 2);
1011 }
1012
1013 if (ST.hasAnyPackedFP64Ops()) {
1014 FPOpActions.legalFor({V2F64});
1015 FCanonicalizeActions.legalFor({V2F64});
1016 StrictFPOpActions.legalFor({V2F64});
1017 FPOpActions.clampMaxNumElementsStrict(0, F64, 2);
1018 FCanonicalizeActions.clampMaxNumElementsStrict(0, F64, 2);
1019 StrictFPOpActions.clampMaxNumElementsStrict(0, F64, 2);
1020 }
1021
1022 auto &MinNumMaxNumIeee =
1023 getActionDefinitionsBuilder({G_FMINNUM_IEEE, G_FMAXNUM_IEEE});
1024
1025 if (ST.hasVOP3PInsts()) {
1026 MinNumMaxNumIeee.legalFor(FPTypesPK16)
1027 .moreElementsIf(isSmallOddVector(0), oneMoreElement(0))
1028 .clampMaxNumElements(0, F16, 2)
1029 .scalarize(0);
1030 } else if (ST.has16BitInsts()) {
1031 MinNumMaxNumIeee.legalFor(FPTypes16).scalarize(0);
1032 } else {
1033 MinNumMaxNumIeee.legalFor(FPTypesBase).scalarize(0);
1034 }
1035
1036 auto &MinNumMaxNum = getActionDefinitionsBuilder(
1037 {G_FMINNUM, G_FMAXNUM, G_FMINIMUMNUM, G_FMAXIMUMNUM});
1038
1039 if (ST.hasAnyPackedFP64Ops()) {
1040 MinNumMaxNum.customFor(FPTypesPK16_64)
1041 .moreElementsIf(isSmallOddVector(0), oneMoreElement(0))
1042 .clampMaxNumElements(0, F16, 2)
1043 .clampMaxNumElements(0, F64, 2)
1044 .scalarize(0);
1045 } else if (ST.hasVOP3PInsts()) {
1046 MinNumMaxNum.customFor(FPTypesPK16)
1047 .moreElementsIf(isSmallOddVector(0), oneMoreElement(0))
1048 .clampMaxNumElements(0, F16, 2)
1049 .scalarize(0);
1050 } else if (ST.has16BitInsts()) {
1051 MinNumMaxNum.customFor(FPTypes16).scalarize(0);
1052 } else {
1053 MinNumMaxNum.customFor(FPTypesBase).scalarize(0);
1054 }
1055
1056 if (!ST.has16BitInsts()) {
1057 MinNumMaxNumIeee.minScalar(0, F32);
1058 MinNumMaxNum.minScalar(0, F32);
1059 }
1060
1061 if (ST.hasVOP3PInsts()) {
1062 FPOpActions.clampMaxNumElementsStrict(0, F16, 2);
1063 FCanonicalizeActions.clampMaxNumElementsStrict(0, F16, 2);
1064 StrictFPOpActions.clampMaxNumElementsStrict(0, F16, 2);
1065 }
1066
1067 FPOpActions.scalarize(0);
1068 FCanonicalizeActions.scalarize(0);
1069 StrictFPOpActions.scalarize(0);
1070 TrigActions.scalarize(0);
1071 FDIVActions.scalarize(0);
1072 if (!ST.has16BitInsts()) {
1073 FPOpActions.widenScalarFor({F16}, changeElementTo(0, F32));
1074 FCanonicalizeActions.widenScalarFor({F16}, changeElementTo(0, F32));
1075 StrictFPOpActions.widenScalarFor({F16}, changeElementTo(0, F32));
1076 TrigActions.widenScalarFor({F16}, changeElementTo(0, F32));
1077 FDIVActions.widenScalarFor({F16}, changeElementTo(0, F32));
1078 }
1079
1080 auto &FNegAbs = getActionDefinitionsBuilder({G_FNEG, G_FABS});
1081 FNegAbs.legalFor(FPTypesPK16)
1082 .legalFor({BF16, V2BF16})
1083 .legalFor(ST.hasAnyPackedFP32Ops(), {V2F32})
1086 if (ST.hasAnyPackedFP32Ops())
1087 FNegAbs.clampMaxNumElementsStrict(0, F32, 2);
1088 FNegAbs.scalarize(0);
1089
1090 if (ST.has16BitInsts()) {
1092 .legalFor({F16})
1093 .legalFor(ST.hasBF16TransInsts(), {BF16})
1094 .customFor({F32, F64})
1095 .scalarize(0)
1097 .unsupported();
1099 .legalFor({F32, F64, F16})
1100 .scalarize(0);
1101
1102 getActionDefinitionsBuilder({G_FLDEXP, G_STRICT_FLDEXP})
1103 .legalFor({{F32, I32}, {F64, I32}, {F16, I16}})
1104 .scalarize(0)
1105 .maxScalarIf(typeIs(0, F16), 1, I16)
1106 .clampScalar(1, I32, I32)
1107 .lower();
1108
1110 .customFor({{F32, I32}, {F64, I32}, {F16, I16}, {F16, I32}})
1111 .scalarize(0)
1112 .lower();
1113
1115 .lowerFor({F16, F32, F64})
1116 .scalarize(0)
1117 .lower();
1118 } else {
1120 .customFor({F32, F64, F16})
1121 .scalarize(0)
1123 .unsupported();
1124
1125 if (ST.hasFractBug()) {
1127 .customFor({F64})
1128 .legalFor({F32, F64})
1129 .scalarize(0)
1130 .minScalar(0, F32);
1131 } else {
1133 .legalFor({F32, F64})
1134 .scalarize(0)
1135 .minScalar(0, F32);
1136 }
1137
1138 getActionDefinitionsBuilder({G_FLDEXP, G_STRICT_FLDEXP})
1139 .legalFor({{F32, I32}, {F64, I32}})
1140 .scalarize(0)
1141 .minScalar(0, F32)
1142 .clampScalar(1, I32, I32)
1143 .lower();
1144
1146 .customFor({{F32, I32}, {F64, I32}})
1147 .scalarize(0)
1148 .minScalar(0, F32)
1149 .clampScalar(1, I32, I32)
1150 .lower();
1151
1153 .lowerFor({F32, F64})
1154 .scalarize(0)
1155 .lower();
1156 }
1157
1158 auto &FPTruncActions = getActionDefinitionsBuilder(G_FPTRUNC);
1159 if (ST.hasCvtPkF16F32Inst()) {
1160 FPTruncActions.legalFor({{F32, F64}, {F16, F32}, {V2F16, V2F32}})
1161 .clampMaxNumElements(0, F16, 2);
1162 } else {
1163 FPTruncActions.legalFor({{F32, F64}, {F16, F32}});
1164 }
1165 FPTruncActions.lowerFor({{BF16, F32}, {BF16, F64}, {F16, F64}}).scalarize(0);
1166
1168 .legalFor({{F64, F32}, {F32, F16}})
1169 .narrowScalarFor({{F64, F16}}, changeElementSizeTo(0, F32))
1170 .lowerFor({{F32, BF16}, {F64, BF16}})
1171 .scalarize(0);
1172
1173 auto &FSubActions = getActionDefinitionsBuilder({G_FSUB, G_STRICT_FSUB});
1174 if (ST.has16BitInsts()) {
1175 FSubActions
1176 // Use actual fsub instruction
1177 .legalFor({F32, F16})
1178 // Must use fadd + fneg
1179 .lowerFor({F64, V2F16});
1180 } else {
1181 FSubActions
1182 // Use actual fsub instruction
1183 .legalFor({F32})
1184 // Must use fadd + fneg
1185 .lowerFor({F64, F16, V2F16});
1186 }
1187
1188 if (ST.hasAnyPackedFP32Ops())
1189 FSubActions.lowerFor({V2F32}).clampMaxNumElements(0, F32, 2);
1190
1191 FSubActions.clampMaxNumElements(0, F16, 2).scalarize(0).clampScalar(0, F32,
1192 F64);
1193
1194 // Whether this is legal depends on the floating point mode for the function.
1195 auto &FMad = getActionDefinitionsBuilder(G_FMAD);
1196 if (ST.hasMadF16() && ST.hasMadMacF32Insts())
1197 FMad.customFor({F32, F16});
1198 else if (ST.hasMadMacF32Insts())
1199 FMad.customFor({F32});
1200 else if (ST.hasMadF16())
1201 FMad.customFor({F16});
1202 FMad.scalarize(0)
1203 .lower();
1204
1205 auto &FRem = getActionDefinitionsBuilder(G_FREM);
1206 if (ST.has16BitInsts()) {
1207 FRem.customFor({F16, F32, F64});
1208 } else {
1209 FRem.minScalar(0, F32).customFor({F32, F64});
1210 }
1211 FRem.scalarize(0);
1212
1213 // TODO: Do we need to clamp maximum bitwidth?
1215 .legalIf(isScalar(0))
1216 .legalFor({{V2S16, V2S32}})
1217 .clampMaxNumElements(0, S16, 2)
1218 // Avoid scalarizing in cases that should be truly illegal. In unresolvable
1219 // situations (like an invalid implicit use), we don't want to infinite loop
1220 // in the legalizer.
1222 .alwaysLegal();
1223
1224 getActionDefinitionsBuilder({G_SEXT, G_ZEXT, G_ANYEXT})
1225 .legalFor({{S64, S32}, {S32, S16}, {S64, S16},
1226 {S32, S1}, {S64, S1}, {S16, S1}})
1227 .scalarize(0)
1228 .clampScalar(0, S32, S64)
1229 .widenScalarToNextPow2(1, 32);
1230
1231 // TODO: Split s1->s64 during regbankselect for VALU.
1232 auto &IToFP = getActionDefinitionsBuilder({G_SITOFP, G_UITOFP})
1233 .legalFor({{F32, I32}, {F64, I32}})
1234 .widenScalarFor({{F16, I32}}, changeElementSizeTo(0, F32))
1235 .lowerIf(typeIs(1, I1))
1236 .customFor({{F32, I64}, {F64, I64}});
1237 if (ST.has16BitInsts())
1238 IToFP.legalFor({{F16, I16}});
1239 IToFP.clampScalar(1, I32, I64)
1240 .minScalar(0, F32)
1241 .scalarize(0)
1243
1244 auto &FPToI = getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI})
1245 .legalFor({{I32, F32}, {I32, F64}})
1246 .customFor({{I64, F32}, {I64, F64}})
1247 .widenScalarFor({{I32, F16}}, changeElementSizeTo(1, F32))
1248 .narrowScalarFor({{I64, F16}}, changeElementSizeTo(0, I32));
1249 if (ST.has16BitInsts())
1250 FPToI.legalFor({{I16, F16}});
1251 else
1252 FPToI.minScalar(1, F32);
1253
1254 FPToI.minScalar(0, I32).widenScalarToNextPow2(0, 32).scalarize(0).lower();
1255
1256 // clang-format off
1257 auto &FPToISat = getActionDefinitionsBuilder({G_FPTOSI_SAT, G_FPTOUI_SAT})
1258 .legalFor({{I32, F32}, {I32, F64}, {I16, F32}})
1259 .legalFor(ST.has16BitInsts(), {{I16, F16}})
1260 .legalFor(ST.hasVCvtPkIU16F32(), {{V2I16, V2F32}})
1261 .narrowScalarFor({{I64, F16}}, changeElementSizeTo(0, I32));
1262
1263 // If available, widen width <16 to i16, intead of i32 so v_cvt_i16/u16_f16 can be used.
1264 if (ST.has16BitInsts())
1265 FPToISat.minScalarIf(typeIs(1, F16), 0, I16);
1266
1267 if (ST.hasVCvtPkIU16F32())
1268 FPToISat.clampMaxNumElements(0, I16, 2);
1269
1270 FPToISat.minScalar(1, F32);
1271 FPToISat.minScalar(0, I32)
1272 .widenScalarToNextPow2(0, 32)
1273 .scalarize(0)
1274 .lower();
1275 // clang-format on
1276
1277 getActionDefinitionsBuilder({G_LROUND, G_LLROUND})
1278 .clampScalar(0, I16, I64)
1279 .scalarize(0)
1280 .lower();
1281
1282 getActionDefinitionsBuilder(G_INTRINSIC_FPTRUNC_ROUND)
1283 .legalFor({F16, F32})
1284 .scalarize(0)
1285 .lower();
1286
1287 // Lower G_FNEARBYINT and G_FRINT into G_INTRINSIC_ROUNDEVEN
1288 getActionDefinitionsBuilder({G_INTRINSIC_ROUND, G_FRINT, G_FNEARBYINT})
1289 .scalarize(0)
1290 .lower();
1291
1292 getActionDefinitionsBuilder({G_INTRINSIC_LRINT, G_INTRINSIC_LLRINT})
1293 .clampScalar(0, I16, I64)
1294 .scalarize(0)
1295 .lower();
1296
1297 auto &RoundingActions = getActionDefinitionsBuilder(
1298 {G_INTRINSIC_TRUNC, G_FCEIL, G_INTRINSIC_ROUNDEVEN});
1299 if (ST.has16BitInsts())
1300 RoundingActions.legalFor({F16, F32, F64});
1301 else if (ST.getGeneration() >= AMDGPUSubtarget::SEA_ISLANDS)
1302 RoundingActions.legalFor({F32, F64});
1303 else
1304 RoundingActions.legalFor({F32}).customFor({F64});
1305
1306 RoundingActions.scalarize(0);
1307 if (!ST.has16BitInsts())
1308 RoundingActions.minScalar(0, F32);
1309
1310 getActionDefinitionsBuilder(G_PTR_ADD)
1311 .unsupportedFor({BufferFatPtr, BufferStridedPtr, RsrcPtr})
1312 .legalIf(all(isPointer(0), sameSize(0, 1)))
1313 .scalarize(0)
1314 .scalarSameSizeAs(1, 0);
1315
1316 getActionDefinitionsBuilder(G_PTRMASK)
1317 .legalIf(all(sameSize(0, 1), typeInSet(1, {S64, S32})))
1318 .scalarSameSizeAs(1, 0)
1319 .scalarize(0);
1320
1321 auto &CmpBuilder =
1322 getActionDefinitionsBuilder(G_ICMP)
1323 // The compare output type differs based on the register bank of the output,
1324 // so make both s1 and s32 legal.
1325 //
1326 // Scalar compares producing output in scc will be promoted to s32, as that
1327 // is the allocatable register type that will be needed for the copy from
1328 // scc. This will be promoted during RegBankSelect, and we assume something
1329 // before that won't try to use s32 result types.
1330 //
1331 // Vector compares producing an output in vcc/SGPR will use s1 in VCC reg
1332 // bank.
1334 {S1}, {S32, S64, GlobalPtr, LocalPtr, ConstantPtr, PrivatePtr, FlatPtr})
1335 .legalForCartesianProduct(
1336 {S32}, {S32, S64, GlobalPtr, LocalPtr, ConstantPtr, PrivatePtr, FlatPtr});
1337 if (ST.has16BitInsts()) {
1338 CmpBuilder.legalFor({{S1, S16}});
1339 }
1340
1341 CmpBuilder
1343 .clampScalar(1, S32, S64)
1344 .scalarize(0)
1345 .legalIf(all(typeInSet(0, {S1, S32}), isPointer(1)));
1346
1347 getActionDefinitionsBuilder({G_SCMP, G_UCMP}).lower();
1348
1349 auto &FCmpBuilder =
1350 getActionDefinitionsBuilder(G_FCMP).legalForCartesianProduct(
1351 {I1}, ST.has16BitInsts() ? FPTypes16 : FPTypesBase);
1352
1353 if (ST.hasSALUFloatInsts())
1354 FCmpBuilder.legalForCartesianProduct({I32}, {F16, F32});
1355
1356 FCmpBuilder.widenScalarToNextPow2(1).minScalar(1, F32).scalarize(0);
1357
1358 // FIXME: fpow has a selection pattern that should move to custom lowering.
1359 auto &ExpOps = getActionDefinitionsBuilder(G_FPOW);
1360 if (ST.has16BitInsts())
1361 ExpOps.customFor({{F32}, {F16}});
1362 else
1363 ExpOps.customFor({F32});
1364 ExpOps.clampScalar(0, MinExtendedFPTy, F32).scalarize(0);
1365
1366 getActionDefinitionsBuilder(G_FPOWI)
1367 .clampScalar(0, MinExtendedFPTy, F32)
1368 .lower();
1369
1370 getActionDefinitionsBuilder(G_FLOG2)
1371 .legalFor(ST.has16BitInsts(), {F16})
1372 .legalFor(ST.hasBF16TransInsts(), {BF16})
1373 .customFor({F32, F16})
1374 .scalarize(0)
1375 .widenScalarFor({BF16}, changeElementTo(0, F32))
1376 .lower();
1377
1378 getActionDefinitionsBuilder(G_FEXP2)
1379 .legalFor(ST.has16BitInsts(), {F16})
1380 .legalFor(ST.hasBF16TransInsts(), {BF16})
1381 .customFor({F32, F64, F16})
1382 .scalarize(0)
1383 .widenScalarFor({BF16}, changeElementTo(0, F32))
1384 .lower();
1385
1386 getActionDefinitionsBuilder({G_FLOG, G_FLOG10})
1387 .customFor({F16, F32})
1388 .scalarize(0);
1389
1390 getActionDefinitionsBuilder({G_FEXP, G_FEXP10})
1391 .customFor({F16, F32, F64})
1392 .scalarize(0);
1393
1394 // The 64-bit versions produce 32-bit results, but only on the SALU.
1395 getActionDefinitionsBuilder(G_CTPOP)
1396 .legalFor({{S32, S32}, {S32, S64}})
1397 .clampScalar(0, S32, S32)
1398 .widenScalarToNextPow2(1, 32)
1399 .clampScalar(1, S32, S64)
1400 .scalarize(0)
1401 .widenScalarToNextPow2(0, 32);
1402
1403 // If no 16 bit instr is available, lower into different instructions.
1404 if (ST.has16BitInsts())
1405 getActionDefinitionsBuilder(G_IS_FPCLASS)
1406 .legalForCartesianProduct({I1}, FPTypes16)
1407 .widenScalarToNextPow2(1)
1408 .scalarize(0)
1409 .lower();
1410 else
1411 getActionDefinitionsBuilder(G_IS_FPCLASS)
1412 .legalForCartesianProduct({I1}, FPTypesBase)
1413 .lowerFor({I1, F16})
1414 .widenScalarToNextPow2(1)
1415 .scalarize(0)
1416 .lower();
1417
1418 // The hardware instructions return a different result on 0 than the generic
1419 // instructions expect. The hardware produces -1, but these produce the
1420 // bitwidth.
1421 getActionDefinitionsBuilder({G_CTLZ, G_CTTZ})
1422 .scalarize(0)
1423 .clampScalar(0, S32, S32)
1424 .clampScalar(1, S32, S64)
1425 .widenScalarToNextPow2(0, 32)
1426 .widenScalarToNextPow2(1, 32)
1427 .custom();
1428
1429 // The 64-bit versions produce 32-bit results, but only on the SALU.
1430 getActionDefinitionsBuilder(G_CTLZ_ZERO_POISON)
1431 .legalFor({{S32, S32}, {S32, S64}})
1432 .customIf(scalarNarrowerThan(1, 32))
1433 .clampScalar(0, S32, S32)
1434 .clampScalar(1, S32, S64)
1435 .scalarize(0)
1436 .widenScalarToNextPow2(0, 32)
1437 .widenScalarToNextPow2(1, 32);
1438
1439 getActionDefinitionsBuilder(G_CTTZ_ZERO_POISON)
1440 .legalFor({{S32, S32}, {S32, S64}})
1441 .clampScalar(0, S32, S32)
1442 .clampScalar(1, S32, S64)
1443 .scalarize(0)
1444 .widenScalarToNextPow2(0, 32)
1445 .widenScalarToNextPow2(1, 32);
1446
1447 getActionDefinitionsBuilder(G_CTLS)
1448 .customFor({{S32, S32}})
1449 .scalarize(0)
1450 .clampScalar(0, S32, S32)
1451 .clampScalar(1, S32, S32);
1452
1453 // S64 is only legal on SALU, and needs to be broken into 32-bit elements in
1454 // RegBankSelect.
1455 getActionDefinitionsBuilder(G_BITREVERSE)
1456 .legalFor({S32, S64})
1457 .clampScalar(0, S32, S64)
1458 .scalarize(0)
1459 .widenScalarToNextPow2(0);
1460
1461 if (ST.has16BitInsts()) {
1462 getActionDefinitionsBuilder(G_BSWAP)
1463 .legalFor({S16, S32, V2S16})
1464 .clampMaxNumElementsStrict(0, S16, 2)
1465 // FIXME: Fixing non-power-of-2 before clamp is workaround for
1466 // narrowScalar limitation.
1467 .widenScalarToNextPow2(0)
1468 .clampScalar(0, S16, S32)
1469 .scalarize(0);
1470
1471 if (ST.hasVOP3PInsts()) {
1472 getActionDefinitionsBuilder(G_ABS)
1473 .legalFor({S32, S16, V2S16})
1474 .clampMaxNumElements(0, S16, 2)
1475 .minScalar(0, S16)
1476 .widenScalarToNextPow2(0)
1477 .scalarize(0)
1478 .lower();
1479 if (ST.useMinMaxI64Insts()) {
1480 getActionDefinitionsBuilder({G_SMIN, G_SMAX, G_UMIN, G_UMAX})
1481 .legalFor({S32, S16, S64, V2S16})
1482 .clampMaxNumElements(0, S16, 2)
1483 .minScalar(0, S16)
1484 .widenScalarToNextPow2(0)
1485 .scalarize(0)
1486 .lower();
1487 } else {
1488 getActionDefinitionsBuilder({G_SMIN, G_SMAX, G_UMIN, G_UMAX})
1489 .legalFor({S32, S16, V2S16})
1490 .clampMaxNumElements(0, S16, 2)
1491 .minScalar(0, S16)
1492 .widenScalarToNextPow2(0)
1493 .scalarize(0)
1494 .lower();
1495 }
1496 } else {
1497 getActionDefinitionsBuilder({G_SMIN, G_SMAX, G_UMIN, G_UMAX, G_ABS})
1498 .legalFor({S32, S16})
1499 .widenScalarToNextPow2(0)
1500 .minScalar(0, S16)
1501 .scalarize(0)
1502 .lower();
1503 }
1504 } else {
1505 // TODO: Should have same legality without v_perm_b32
1506 getActionDefinitionsBuilder(G_BSWAP)
1507 .legalFor({S32})
1508 .lowerIf(scalarNarrowerThan(0, 32))
1509 // FIXME: Fixing non-power-of-2 before clamp is workaround for
1510 // narrowScalar limitation.
1511 .widenScalarToNextPow2(0)
1512 .maxScalar(0, S32)
1513 .scalarize(0)
1514 .lower();
1515
1516 getActionDefinitionsBuilder({G_SMIN, G_SMAX, G_UMIN, G_UMAX, G_ABS})
1517 .legalFor({S32})
1518 .minScalar(0, S32)
1519 .widenScalarToNextPow2(0)
1520 .scalarize(0)
1521 .lower();
1522 }
1523
1524 getActionDefinitionsBuilder(G_INTTOPTR)
1525 // List the common cases
1526 .legalForCartesianProduct(AddrSpaces64, {S64})
1527 .legalForCartesianProduct(AddrSpaces32, {S32})
1528 .scalarize(0)
1529 // Accept any address space as long as the size matches
1530 .legalIf(sameSize(0, 1))
1531 .widenScalarIf(smallerThan(1, 0),
1532 [](const LegalityQuery &Query) {
1533 return std::pair(
1534 1, LLT::scalar(Query.Types[0].getSizeInBits()));
1535 })
1536 .narrowScalarIf(largerThan(1, 0), [](const LegalityQuery &Query) {
1537 return std::pair(1, LLT::scalar(Query.Types[0].getSizeInBits()));
1538 });
1539
1540 getActionDefinitionsBuilder(G_PTRTOINT)
1541 // List the common cases
1542 .legalForCartesianProduct(AddrSpaces64, {S64})
1543 .legalForCartesianProduct(AddrSpaces32, {S32})
1544 .scalarize(0)
1545 // Accept any address space as long as the size matches
1546 .legalIf(sameSize(0, 1))
1547 .widenScalarIf(smallerThan(0, 1),
1548 [](const LegalityQuery &Query) {
1549 return std::pair(
1550 0, LLT::scalar(Query.Types[1].getSizeInBits()));
1551 })
1552 .narrowScalarIf(largerThan(0, 1), [](const LegalityQuery &Query) {
1553 return std::pair(0, LLT::scalar(Query.Types[1].getSizeInBits()));
1554 });
1555
1556 getActionDefinitionsBuilder(G_ADDRSPACE_CAST)
1557 .scalarize(0)
1558 .custom();
1559
1560 const auto needToSplitMemOp = [=](const LegalityQuery &Query,
1561 bool IsLoad) -> bool {
1562 const LLT DstTy = Query.Types[0];
1563
1564 // Split vector extloads.
1565 unsigned MemSize = Query.MMODescrs[0].MemoryTy.getSizeInBits();
1566
1567 if (DstTy.isVector() && DstTy.getSizeInBits() > MemSize)
1568 return true;
1569
1570 const LLT PtrTy = Query.Types[1];
1571 unsigned AS = PtrTy.getAddressSpace();
1572 if (MemSize > maxSizeForAddrSpace(ST, AS, IsLoad,
1573 Query.MMODescrs[0].Ordering !=
1575 return true;
1576
1577 // Catch weird sized loads that don't evenly divide into the access sizes
1578 // TODO: May be able to widen depending on alignment etc.
1579 unsigned NumRegs = (MemSize + 31) / 32;
1580 if (NumRegs == 3) {
1581 if (!ST.hasDwordx3LoadStores())
1582 return true;
1583 } else {
1584 // If the alignment allows, these should have been widened.
1585 if (!isPowerOf2_32(NumRegs))
1586 return true;
1587 }
1588
1589 return false;
1590 };
1591
1592 unsigned GlobalAlign32 = ST.hasUnalignedBufferAccessEnabled() ? 0 : 32;
1593 unsigned GlobalAlign16 = ST.hasUnalignedBufferAccessEnabled() ? 0 : 16;
1594 unsigned GlobalAlign8 = ST.hasUnalignedBufferAccessEnabled() ? 0 : 8;
1595
1596 // TODO: Refine based on subtargets which support unaligned access or 128-bit
1597 // LDS
1598 // TODO: Unsupported flat for SI.
1599
1600 for (unsigned Op : {G_LOAD, G_STORE}) {
1601 const bool IsStore = Op == G_STORE;
1602
1603 auto &Actions = getActionDefinitionsBuilder(Op);
1604 // Explicitly list some common cases.
1605 // TODO: Does this help compile time at all?
1606 Actions.legalForTypesWithMemDesc({{S32, GlobalPtr, S32, GlobalAlign32},
1607 {V2S32, GlobalPtr, V2S32, GlobalAlign32},
1608 {V4S32, GlobalPtr, V4S32, GlobalAlign32},
1609 {S64, GlobalPtr, S64, GlobalAlign32},
1610 {V2S64, GlobalPtr, V2S64, GlobalAlign32},
1611 {V2S16, GlobalPtr, V2S16, GlobalAlign32},
1612 {S32, GlobalPtr, S8, GlobalAlign8},
1613 {S32, GlobalPtr, S16, GlobalAlign16},
1614
1615 {S32, LocalPtr, S32, 32},
1616 {S64, LocalPtr, S64, 32},
1617 {V2S32, LocalPtr, V2S32, 32},
1618 {S32, LocalPtr, S8, 8},
1619 {S32, LocalPtr, S16, 16},
1620 {V2S16, LocalPtr, S32, 32},
1621
1622 {S32, PrivatePtr, S32, 32},
1623 {S32, PrivatePtr, S8, 8},
1624 {S32, PrivatePtr, S16, 16},
1625 {V2S16, PrivatePtr, S32, 32},
1626
1627 {S32, ConstantPtr, S32, GlobalAlign32},
1628 {V2S32, ConstantPtr, V2S32, GlobalAlign32},
1629 {V4S32, ConstantPtr, V4S32, GlobalAlign32},
1630 {S64, ConstantPtr, S64, GlobalAlign32},
1631 {V2S32, ConstantPtr, V2S32, GlobalAlign32}});
1632
1633 Actions.legalForTypesWithMemDesc(ST.useRealTrue16Insts(), /* Pred */
1634 {{S16, GlobalPtr, S8, GlobalAlign8},
1635 {S16, GlobalPtr, S16, GlobalAlign16},
1636 {S16, LocalPtr, S8, 8},
1637 {S16, LocalPtr, S16, 16},
1638 {S16, PrivatePtr, S8, 8},
1639 {S16, PrivatePtr, S16, 16}});
1640
1641 Actions.legalIf(
1642 [=](const LegalityQuery &Query) -> bool {
1643 return isLoadStoreLegal(ST, Query);
1644 });
1645
1646 // The custom pointers (fat pointers, buffer resources) don't work with load
1647 // and store at this level. Fat pointers should have been lowered to
1648 // intrinsics before the translation to MIR.
1649 Actions.unsupportedIf(
1650 typeInSet(1, {BufferFatPtr, BufferStridedPtr, RsrcPtr}));
1651
1652 // Address space 8 pointers are handled by a 4xs32 load, bitcast, and
1653 // ptrtoint. This is needed to account for the fact that we can't have i128
1654 // as a register class for SelectionDAG reasons.
1655 Actions.customIf([=](const LegalityQuery &Query) -> bool {
1656 return hasBufferRsrcWorkaround(Query.Types[0]);
1657 });
1658
1659 // Constant 32-bit is handled by addrspacecasting the 32-bit pointer to
1660 // 64-bits.
1661 //
1662 // TODO: Should generalize bitcast action into coerce, which will also cover
1663 // inserting addrspacecasts.
1664 Actions.customIf(typeIs(1, Constant32Ptr));
1665
1666 // Turn any illegal element vectors into something easier to deal
1667 // with. These will ultimately produce 32-bit scalar shifts to extract the
1668 // parts anyway.
1669 //
1670 // For odd 16-bit element vectors, prefer to split those into pieces with
1671 // 16-bit vector parts.
1672 Actions.bitcastIf(
1673 [=](const LegalityQuery &Query) -> bool {
1674 return shouldBitcastLoadStoreType(ST, Query.Types[0],
1675 Query.MMODescrs[0].MemoryTy);
1676 }, bitcastToRegisterType(0));
1677
1678 if (!IsStore) {
1679 // Widen suitably aligned loads by loading extra bytes. The standard
1680 // legalization actions can't properly express widening memory operands.
1681 Actions.customIf([=](const LegalityQuery &Query) -> bool {
1682 return shouldWidenLoad(ST, Query, G_LOAD);
1683 });
1684 }
1685
1686 // FIXME: load/store narrowing should be moved to lower action
1687 Actions
1688 .narrowScalarIf(
1689 [=](const LegalityQuery &Query) -> bool {
1690 return !Query.Types[0].isVector() &&
1691 needToSplitMemOp(Query, Op == G_LOAD);
1692 },
1693 [=](const LegalityQuery &Query) -> std::pair<unsigned, LLT> {
1694 const LLT DstTy = Query.Types[0];
1695 const LLT PtrTy = Query.Types[1];
1696
1697 const unsigned DstSize = DstTy.getSizeInBits();
1698 unsigned MemSize = Query.MMODescrs[0].MemoryTy.getSizeInBits();
1699
1700 // Split extloads.
1701 if (DstSize > MemSize)
1702 return std::pair(0, LLT::scalar(MemSize));
1703
1704 unsigned MaxSize = maxSizeForAddrSpace(
1705 ST, PtrTy.getAddressSpace(), Op == G_LOAD,
1706 Query.MMODescrs[0].Ordering != AtomicOrdering::NotAtomic);
1707 if (MemSize > MaxSize)
1708 return std::pair(0, LLT::scalar(MaxSize));
1709
1710 uint64_t Align = Query.MMODescrs[0].AlignInBits;
1711 return std::pair(0, LLT::scalar(Align));
1712 })
1713 .fewerElementsIf(
1714 [=](const LegalityQuery &Query) -> bool {
1715 return Query.Types[0].isVector() &&
1716 needToSplitMemOp(Query, Op == G_LOAD);
1717 },
1718 [=](const LegalityQuery &Query) -> std::pair<unsigned, LLT> {
1719 const LLT DstTy = Query.Types[0];
1720 const LLT PtrTy = Query.Types[1];
1721
1722 LLT EltTy = DstTy.getElementType();
1723 unsigned MaxSize = maxSizeForAddrSpace(
1724 ST, PtrTy.getAddressSpace(), Op == G_LOAD,
1725 Query.MMODescrs[0].Ordering != AtomicOrdering::NotAtomic);
1726
1727 // FIXME: Handle widened to power of 2 results better. This ends
1728 // up scalarizing.
1729 // FIXME: 3 element stores scalarized on SI
1730
1731 // Split if it's too large for the address space.
1732 unsigned MemSize = Query.MMODescrs[0].MemoryTy.getSizeInBits();
1733 if (MemSize > MaxSize) {
1734 unsigned NumElts = DstTy.getNumElements();
1735 unsigned EltSize = EltTy.getSizeInBits();
1736
1737 if (MaxSize % EltSize == 0) {
1738 return std::pair(
1740 ElementCount::getFixed(MaxSize / EltSize), EltTy));
1741 }
1742
1743 unsigned NumPieces = MemSize / MaxSize;
1744
1745 // FIXME: Refine when odd breakdowns handled
1746 // The scalars will need to be re-legalized.
1747 if (NumPieces == 1 || NumPieces >= NumElts ||
1748 NumElts % NumPieces != 0)
1749 return std::pair(0, EltTy);
1750
1751 return std::pair(0,
1752 LLT::fixed_vector(NumElts / NumPieces, EltTy));
1753 }
1754
1755 // FIXME: We could probably handle weird extending loads better.
1756 if (DstTy.getSizeInBits() > MemSize)
1757 return std::pair(0, EltTy);
1758
1759 unsigned EltSize = EltTy.getSizeInBits();
1760 unsigned DstSize = DstTy.getSizeInBits();
1761 if (!isPowerOf2_32(DstSize)) {
1762 // We're probably decomposing an odd sized store. Try to split
1763 // to the widest type. TODO: Account for alignment. As-is it
1764 // should be OK, since the new parts will be further legalized.
1765 unsigned FloorSize = llvm::bit_floor(DstSize);
1766 return std::pair(
1768 ElementCount::getFixed(FloorSize / EltSize), EltTy));
1769 }
1770
1771 // May need relegalization for the scalars.
1772 return std::pair(0, EltTy);
1773 })
1774 .widenScalarIf(scalarNarrowerThan(0, 32), changeTo(0, LLT::integer(32)))
1775 .narrowScalarIf(isTruncStoreToSizePowerOf2(0),
1777 .widenScalarToNextPow2(0)
1778 .moreElementsIf(vectorSmallerThan(0, 32), moreEltsToNext32Bit(0))
1779 .lower();
1780 }
1781
1782 // FIXME: Unaligned accesses not lowered.
1783 auto &ExtLoads =
1784 getActionDefinitionsBuilder({G_SEXTLOAD, G_ZEXTLOAD})
1785 .legalForTypesWithMemDesc({{S32, GlobalPtr, S8, 8},
1786 {S32, GlobalPtr, S16, 2 * 8},
1787 {S32, LocalPtr, S8, 8},
1788 {S32, LocalPtr, S16, 16},
1789 {S32, PrivatePtr, S8, 8},
1790 {S32, PrivatePtr, S16, 16},
1791 {S32, ConstantPtr, S8, 8},
1792 {S32, ConstantPtr, S16, 2 * 8}})
1793 .legalForTypesWithMemDesc(ST.useRealTrue16Insts(),
1794 {{S16, GlobalPtr, S8, GlobalAlign8},
1795 {S16, LocalPtr, S8, GlobalAlign8},
1796 {S16, PrivatePtr, S8, GlobalAlign8},
1797 {S16, ConstantPtr, S8, GlobalAlign8}})
1798 .legalIf([=](const LegalityQuery &Query) -> bool {
1799 return isLoadStoreLegal(ST, Query);
1800 });
1801
1802 if (ST.hasFlatAddressSpace()) {
1803 ExtLoads.legalForTypesWithMemDesc(
1804 {{S32, FlatPtr, S8, 8}, {S32, FlatPtr, S16, 16}});
1805
1806 ExtLoads.legalForTypesWithMemDesc(ST.useRealTrue16Insts(),
1807 {{S16, FlatPtr, S8, GlobalAlign8}});
1808 }
1809
1810 // Constant 32-bit is handled by addrspacecasting the 32-bit pointer to
1811 // 64-bits.
1812 //
1813 // TODO: Should generalize bitcast action into coerce, which will also cover
1814 // inserting addrspacecasts.
1815 ExtLoads.customIf(typeIs(1, Constant32Ptr));
1816
1817 ExtLoads.narrowScalarIf(
1818 [](const LegalityQuery &Query) {
1819 LLT MemTy = Query.MMODescrs[0].MemoryTy;
1820 return MemTy.isScalar() && MemTy.getSizeInBits() > 32 &&
1821 Query.Types[0].getSizeInBits() > MemTy.getSizeInBits();
1822 }, // For large MemSize, narrowscalar to MemSize (load MemSize + ext)
1824 ExtLoads.clampScalar(0, S32, S32)
1825 .widenScalarToNextPow2(0)
1826 .lower();
1827
1828 auto &Atomics = getActionDefinitionsBuilder(
1829 {G_ATOMICRMW_XCHG, G_ATOMICRMW_ADD, G_ATOMICRMW_SUB,
1830 G_ATOMICRMW_AND, G_ATOMICRMW_OR, G_ATOMICRMW_XOR,
1831 G_ATOMICRMW_MAX, G_ATOMICRMW_MIN, G_ATOMICRMW_UMAX,
1832 G_ATOMICRMW_UMIN, G_ATOMICRMW_UINC_WRAP, G_ATOMICRMW_UDEC_WRAP})
1833 .legalFor({{S32, GlobalPtr}, {S32, LocalPtr},
1834 {S64, GlobalPtr}, {S64, LocalPtr},
1835 {S32, RegionPtr}, {S64, RegionPtr}});
1836 if (ST.hasFlatAddressSpace()) {
1837 Atomics.legalFor({{S32, FlatPtr}, {S64, FlatPtr}});
1838 }
1839
1840 auto &Atomics32 =
1841 getActionDefinitionsBuilder({G_ATOMICRMW_USUB_COND, G_ATOMICRMW_USUB_SAT})
1842 .legalFor({{S32, GlobalPtr}, {S32, LocalPtr}, {S32, RegionPtr}});
1843 if (ST.hasFlatAddressSpace()) {
1844 Atomics32.legalFor({{S32, FlatPtr}});
1845 }
1846
1847 // TODO: v2bf16 operations, and fat buffer pointer support.
1848 auto &Atomic = getActionDefinitionsBuilder(G_ATOMICRMW_FADD);
1849 if (ST.hasLDSFPAtomicAddF32()) {
1850 Atomic.legalFor({{F32, LocalPtr}, {F32, RegionPtr}});
1851 if (ST.hasLdsAtomicAddF64())
1852 Atomic.legalFor({{F64, LocalPtr}});
1853 if (ST.hasAtomicDsPkAdd16Insts())
1854 Atomic.legalFor({{V2F16, LocalPtr}, {V2BF16, LocalPtr}});
1855 }
1856 if (ST.hasAtomicFaddInsts())
1857 Atomic.legalFor({{F32, GlobalPtr}});
1858 if (ST.hasFlatAtomicFaddF32Inst())
1859 Atomic.legalFor({{F32, FlatPtr}});
1860
1861 if (ST.hasGFX90AInsts() || ST.hasGFX1250Insts()) {
1862 // These are legal with some caveats, and should have undergone expansion in
1863 // the IR in most situations
1864 // TODO: Move atomic expansion into legalizer
1865 Atomic.legalFor({{F32, GlobalPtr}, {F64, GlobalPtr}, {F64, FlatPtr}});
1866 }
1867
1868 if (ST.hasAtomicBufferGlobalPkAddF16NoRtnInsts() ||
1869 ST.hasAtomicBufferGlobalPkAddF16Insts())
1870 Atomic.legalFor({{V2F16, GlobalPtr}, {V2F16, BufferFatPtr}});
1871 if (ST.hasAtomicGlobalPkAddBF16Inst())
1872 Atomic.legalFor({{V2BF16, GlobalPtr}});
1873 if (ST.hasAtomicFlatPkAdd16Insts())
1874 Atomic.legalFor({{V2F16, FlatPtr}, {V2BF16, FlatPtr}});
1875
1876
1877 // Most of the legalization work here is done by AtomicExpand. We could
1878 // probably use a simpler legality rule that just assumes anything is OK.
1879 auto &AtomicFMinFMax =
1880 getActionDefinitionsBuilder({G_ATOMICRMW_FMIN, G_ATOMICRMW_FMAX})
1881 .legalFor({{F32, LocalPtr}, {F64, LocalPtr}});
1882
1883 if (ST.hasAtomicFMinFMaxF32GlobalInsts())
1884 AtomicFMinFMax.legalFor({{F32, GlobalPtr},{F32, BufferFatPtr}});
1885 if (ST.hasAtomicFMinFMaxF64GlobalInsts())
1886 AtomicFMinFMax.legalFor({{F64, GlobalPtr}, {F64, BufferFatPtr}});
1887 if (ST.hasAtomicFMinFMaxF32FlatInsts())
1888 AtomicFMinFMax.legalFor({F32, FlatPtr});
1889 if (ST.hasAtomicFMinFMaxF64FlatInsts())
1890 AtomicFMinFMax.legalFor({F64, FlatPtr});
1891
1892 // BUFFER/FLAT_ATOMIC_CMP_SWAP on GCN GPUs needs input marshalling, and output
1893 // demarshalling
1894 getActionDefinitionsBuilder(G_ATOMIC_CMPXCHG)
1895 .customFor({{S32, GlobalPtr}, {S64, GlobalPtr},
1896 {S32, FlatPtr}, {S64, FlatPtr}})
1897 .legalFor({{S32, LocalPtr}, {S64, LocalPtr},
1898 {S32, RegionPtr}, {S64, RegionPtr}});
1899 // TODO: Pointer types, any 32-bit or 64-bit vector
1900
1901 // Condition should be s32 for scalar, s1 for vector.
1902 getActionDefinitionsBuilder(G_SELECT)
1903 .legalForCartesianProduct({S32, S64, S16, V2S32, V2S16, V4S16, GlobalPtr,
1904 LocalPtr, FlatPtr, PrivatePtr,
1905 LLT::fixed_vector(2, LocalPtr),
1906 LLT::fixed_vector(2, PrivatePtr)},
1907 {S1, S32})
1908 .clampScalar(0, S16, S64)
1909 .scalarize(1)
1910 .moreElementsIf(isSmallOddVector(0), oneMoreElement(0))
1911 .fewerElementsIf(numElementsNotEven(0), scalarize(0))
1912 .clampMaxNumElements(0, S32, 2)
1913 .clampMaxNumElements(0, LocalPtr, 2)
1914 .clampMaxNumElements(0, PrivatePtr, 2)
1915 .scalarize(0)
1916 .widenScalarToNextPow2(0)
1917 .legalIf(all(isPointer(0), typeInSet(1, {S1, S32})));
1918
1919 // TODO: Only the low 4/5/6 bits of the shift amount are observed, so we can
1920 // be more flexible with the shift amount type.
1921 auto &Shifts = getActionDefinitionsBuilder({G_SHL, G_LSHR, G_ASHR})
1922 .legalFor({{S32, S32}, {S64, S32}});
1923 if (ST.has16BitInsts()) {
1924 if (ST.hasVOP3PInsts()) {
1925 Shifts.legalFor({{S16, S16}, {V2S16, V2S16}})
1926 .clampMaxNumElements(0, S16, 2);
1927 } else
1928 Shifts.legalFor({{S16, S16}});
1929
1930 // TODO: Support 16-bit shift amounts for all types
1931 Shifts.widenScalarIf(
1932 [=](const LegalityQuery &Query) {
1933 // Use 16-bit shift amounts for any 16-bit shift. Otherwise we want a
1934 // 32-bit amount.
1935 const LLT ValTy = Query.Types[0];
1936 const LLT AmountTy = Query.Types[1];
1937 return ValTy.isScalar() && ValTy.getSizeInBits() <= 16 &&
1938 AmountTy.getSizeInBits() < 16;
1939 },
1941 Shifts.maxScalarIf(typeIs(0, S16), 1, S16);
1942 Shifts.clampScalar(1, S32, S32);
1943 Shifts.widenScalarToNextPow2(0, 16);
1944 Shifts.clampScalar(0, S16, S64);
1945
1946 getActionDefinitionsBuilder({G_SSHLSAT, G_USHLSAT})
1947 .minScalar(0, S16)
1948 .scalarize(0)
1949 .lower();
1950 } else {
1951 // Make sure we legalize the shift amount type first, as the general
1952 // expansion for the shifted type will produce much worse code if it hasn't
1953 // been truncated already.
1954 Shifts.clampScalar(1, S32, S32);
1955 Shifts.widenScalarToNextPow2(0, 32);
1956 Shifts.clampScalar(0, S32, S64);
1957
1958 getActionDefinitionsBuilder({G_SSHLSAT, G_USHLSAT})
1959 .minScalar(0, S32)
1960 .scalarize(0)
1961 .lower();
1962 }
1963 Shifts.scalarize(0);
1964
1965 for (unsigned Op : {G_EXTRACT_VECTOR_ELT, G_INSERT_VECTOR_ELT}) {
1966 unsigned VecTypeIdx = Op == G_EXTRACT_VECTOR_ELT ? 1 : 0;
1967 unsigned EltTypeIdx = Op == G_EXTRACT_VECTOR_ELT ? 0 : 1;
1968 unsigned IdxTypeIdx = 2;
1969
1970 getActionDefinitionsBuilder(Op)
1971 .customIf([=](const LegalityQuery &Query) {
1972 const LLT EltTy = Query.Types[EltTypeIdx];
1973 const LLT VecTy = Query.Types[VecTypeIdx];
1974 const LLT IdxTy = Query.Types[IdxTypeIdx];
1975 const unsigned EltSize = EltTy.getSizeInBits();
1976 const bool isLegalVecType =
1978 // Address space 8 pointers are 128-bit wide values, but the logic
1979 // below will try to bitcast them to 2N x s64, which will fail.
1980 // Therefore, as an intermediate step, wrap extracts/insertions from a
1981 // ptrtoint-ing the vector and scalar arguments (or inttoptring the
1982 // extraction result) in order to produce a vector operation that can
1983 // be handled by the logic below.
1984 if (EltTy.isPointer() && EltSize > 64)
1985 return true;
1986 return (EltSize == 32 || EltSize == 64) &&
1987 VecTy.getSizeInBits() % 32 == 0 &&
1988 VecTy.getSizeInBits() <= MaxRegisterSize &&
1989 IdxTy.getSizeInBits() == 32 &&
1990 isLegalVecType;
1991 })
1992 .bitcastIf(all(sizeIsMultipleOf32(VecTypeIdx),
1993 scalarOrEltNarrowerThan(VecTypeIdx, 32)),
1994 bitcastToVectorElement32(VecTypeIdx))
1995 //.bitcastIf(vectorSmallerThan(1, 32), bitcastToScalar(1))
1996 .bitcastIf(all(sizeIsMultipleOf32(VecTypeIdx),
1997 scalarOrEltWiderThan(VecTypeIdx, 64)),
1998 [=](const LegalityQuery &Query) {
1999 // For > 64-bit element types, try to turn this into a
2000 // 64-bit element vector since we may be able to do better
2001 // indexing if this is scalar. If not, fall back to 32.
2002 const LLT EltTy = Query.Types[EltTypeIdx];
2003 const LLT VecTy = Query.Types[VecTypeIdx];
2004 const unsigned DstEltSize = EltTy.getSizeInBits();
2005 const unsigned VecSize = VecTy.getSizeInBits();
2006
2007 const unsigned TargetEltSize =
2008 DstEltSize % 64 == 0 ? 64 : 32;
2009 return std::pair(VecTypeIdx,
2010 LLT::fixed_vector(VecSize / TargetEltSize,
2011 TargetEltSize));
2012 })
2013 .clampScalar(EltTypeIdx, S32, S64)
2014 .clampScalar(VecTypeIdx, S32, S64)
2015 .clampScalar(IdxTypeIdx, S32, S32)
2016 .clampMaxNumElements(VecTypeIdx, S32, 32)
2017 // TODO: Clamp elements for 64-bit vectors?
2018 .moreElementsIf(isIllegalRegisterType(ST, VecTypeIdx),
2020 // It should only be necessary with variable indexes.
2021 // As a last resort, lower to the stack
2022 .lower();
2023 }
2024
2025 getActionDefinitionsBuilder(G_EXTRACT_VECTOR_ELT)
2026 .unsupportedIf([=](const LegalityQuery &Query) {
2027 const LLT &EltTy = Query.Types[1].getElementType();
2028 return Query.Types[0] != EltTy;
2029 });
2030
2031 for (unsigned Op : {G_EXTRACT, G_INSERT}) {
2032 unsigned BigTyIdx = Op == G_EXTRACT ? 1 : 0;
2033 unsigned LitTyIdx = Op == G_EXTRACT ? 0 : 1;
2034 getActionDefinitionsBuilder(Op)
2035 .widenScalarIf(
2036 [=](const LegalityQuery &Query) {
2037 const LLT BigTy = Query.Types[BigTyIdx];
2038 return (BigTy.getScalarSizeInBits() < 16);
2039 },
2041 .widenScalarIf(
2042 [=](const LegalityQuery &Query) {
2043 const LLT LitTy = Query.Types[LitTyIdx];
2044 return (LitTy.getScalarSizeInBits() < 16);
2045 },
2047 .moreElementsIf(isSmallOddVector(BigTyIdx), oneMoreElement(BigTyIdx))
2048 .widenScalarToNextPow2(BigTyIdx, 32)
2049 .customIf([=](const LegalityQuery &Query) {
2050 // Generic lower operates on the full-width value, producing
2051 // shift+trunc/mask sequences. For simple cases where extract/insert
2052 // values are 32-bit aligned, we can instead unmerge/merge and work on
2053 // the 32-bit components. However, we can't check the offset here so
2054 // custom lower function will have to call generic lowering if offset
2055 // is not 32-bit aligned.
2056 const LLT BigTy = Query.Types[BigTyIdx];
2057 const LLT LitTy = Query.Types[LitTyIdx];
2058 return !BigTy.isVector() && BigTy.getSizeInBits() % 32 == 0 &&
2059 LitTy.getSizeInBits() % 32 == 0;
2060 })
2061 .lower();
2062 }
2063
2064 auto &BuildVector =
2065 getActionDefinitionsBuilder(G_BUILD_VECTOR)
2066 .legalForCartesianProduct(AllS32Vectors, {S32})
2067 .legalForCartesianProduct(AllS64Vectors, {S64})
2068 .clampNumElements(0, V16S32, V32S32)
2069 .clampNumElements(0, V2S64, V16S64)
2070 .fewerElementsIf(isWideVec16(0),
2072 .moreElementsIf(isIllegalRegisterType(ST, 0),
2074
2075 if (ST.hasScalarPackInsts()) {
2076 BuildVector
2077 // FIXME: Should probably widen s1 vectors straight to s32
2078 .minScalarOrElt(0, S16)
2079 .minScalar(1, S16);
2080
2081 getActionDefinitionsBuilder(G_BUILD_VECTOR_TRUNC)
2082 .legalFor({V2S16, S32})
2083 .lower();
2084 } else {
2085 BuildVector.customFor({V2S16, S16});
2086 BuildVector.minScalarOrElt(0, S32);
2087
2088 getActionDefinitionsBuilder(G_BUILD_VECTOR_TRUNC)
2089 .customFor({V2S16, S32})
2090 .lower();
2091 }
2092
2093 BuildVector.legalIf(isRegisterType(ST, 0));
2094
2095 // FIXME: Clamp maximum size
2096 getActionDefinitionsBuilder(G_CONCAT_VECTORS)
2097 .legalIf(all(isRegisterType(ST, 0), isRegisterType(ST, 1)))
2098 .clampMaxNumElements(0, S32, 32)
2099 .clampMaxNumElements(1, S16, 2) // TODO: Make 4?
2100 .clampMaxNumElements(0, S16, 64);
2101
2102 getActionDefinitionsBuilder(G_SHUFFLE_VECTOR).lower();
2103
2104 // Merge/Unmerge
2105 for (unsigned Op : {G_MERGE_VALUES, G_UNMERGE_VALUES}) {
2106 unsigned BigTyIdx = Op == G_MERGE_VALUES ? 0 : 1;
2107 unsigned LitTyIdx = Op == G_MERGE_VALUES ? 1 : 0;
2108
2109 auto notValidElt = [=](const LegalityQuery &Query, unsigned TypeIdx) {
2110 const LLT Ty = Query.Types[TypeIdx];
2111 if (Ty.isVector()) {
2112 const LLT &EltTy = Ty.getElementType();
2113 if (EltTy.getSizeInBits() < 8 || EltTy.getSizeInBits() > 512)
2114 return true;
2116 return true;
2117 }
2118 return false;
2119 };
2120
2121 auto &Builder =
2122 getActionDefinitionsBuilder(Op)
2123 .legalIf(all(isRegisterType(ST, 0), isRegisterType(ST, 1)))
2124 .lowerFor({{S16, V2S16}})
2125 .lowerIf([=](const LegalityQuery &Query) {
2126 const LLT BigTy = Query.Types[BigTyIdx];
2127 return BigTy.getSizeInBits() == 32;
2128 })
2129 // Try to widen to s16 first for small types.
2130 // TODO: Only do this on targets with legal s16 shifts
2131 .minScalarOrEltIf(scalarNarrowerThan(LitTyIdx, 16), LitTyIdx, S16)
2132 .widenScalarToNextPow2(LitTyIdx, /*Min*/ 16)
2133 .moreElementsIf(isSmallOddVector(BigTyIdx),
2134 oneMoreElement(BigTyIdx))
2135 .fewerElementsIf(all(typeIs(0, S16), vectorWiderThan(1, 32),
2136 elementTypeIs(1, S16)),
2138 // Clamp the little scalar to s8-s256 and make it a power of 2. It's
2139 // not worth considering the multiples of 64 since 2*192 and 2*384
2140 // are not valid.
2141 .clampScalar(LitTyIdx, S32, S512)
2142 .widenScalarToNextPow2(LitTyIdx, /*Min*/ 32)
2143 // Break up vectors with weird elements into scalars
2144 .fewerElementsIf(
2145 [=](const LegalityQuery &Query) {
2146 return notValidElt(Query, LitTyIdx);
2147 },
2148 scalarize(0))
2149 .fewerElementsIf(
2150 [=](const LegalityQuery &Query) {
2151 return notValidElt(Query, BigTyIdx);
2152 },
2153 scalarize(1))
2154 .clampScalar(BigTyIdx, S32, MaxScalar);
2155
2156 if (Op == G_MERGE_VALUES) {
2157 Builder.widenScalarIf(
2158 // TODO: Use 16-bit shifts if legal for 8-bit values?
2159 [=](const LegalityQuery &Query) {
2160 const LLT Ty = Query.Types[LitTyIdx];
2161 return Ty.getSizeInBits() < 32;
2162 },
2163 changeElementSizeTo(LitTyIdx, S32));
2164 }
2165
2166 Builder.widenScalarIf(
2167 [=](const LegalityQuery &Query) {
2168 const LLT Ty = Query.Types[BigTyIdx];
2169 return Ty.getSizeInBits() % 16 != 0;
2170 },
2171 [=](const LegalityQuery &Query) {
2172 // Pick the next power of 2, or a multiple of 64 over 128.
2173 // Whichever is smaller.
2174 const LLT &Ty = Query.Types[BigTyIdx];
2175 unsigned NewSizeInBits = 1 << Log2_32_Ceil(Ty.getSizeInBits() + 1);
2176 if (NewSizeInBits >= 256) {
2177 unsigned RoundedTo = alignTo<64>(Ty.getSizeInBits() + 1);
2178 if (RoundedTo < NewSizeInBits)
2179 NewSizeInBits = RoundedTo;
2180 }
2181 return std::pair(BigTyIdx, LLT::scalar(NewSizeInBits));
2182 })
2183 // Any vectors left are the wrong size. Scalarize them.
2184 .scalarize(0)
2185 .scalarize(1);
2186 }
2187
2188 // S64 is only legal on SALU, and needs to be broken into 32-bit elements in
2189 // RegBankSelect.
2190 auto &SextInReg = getActionDefinitionsBuilder(G_SEXT_INREG)
2191 .legalFor({{S32}, {S64}})
2192 .clampScalar(0, S32, S64);
2193
2194 if (ST.hasVOP3PInsts()) {
2195 SextInReg.lowerFor({{V2S16}})
2196 // Prefer to reduce vector widths for 16-bit vectors before lowering, to
2197 // get more vector shift opportunities, since we'll get those when
2198 // expanded.
2199 .clampMaxNumElementsStrict(0, S16, 2);
2200 } else if (ST.has16BitInsts()) {
2201 SextInReg.lowerFor({{S32}, {S64}, {S16}});
2202 } else {
2203 // Prefer to promote to s32 before lowering if we don't have 16-bit
2204 // shifts. This avoid a lot of intermediate truncate and extend operations.
2205 SextInReg.lowerFor({{S32}, {S64}});
2206 }
2207
2208 SextInReg
2209 .scalarize(0)
2210 .clampScalar(0, S32, S64)
2211 .lower();
2212
2213 getActionDefinitionsBuilder({G_ROTR, G_ROTL})
2214 .scalarize(0)
2215 .lower();
2216
2217 auto &FSHRActionDefs = getActionDefinitionsBuilder(G_FSHR);
2218 FSHRActionDefs.legalFor({{S32, S32}})
2219 .clampMaxNumElementsStrict(0, S16, 2);
2220 if (ST.hasVOP3PInsts())
2221 FSHRActionDefs.lowerFor({{V2S16, V2S16}});
2222 FSHRActionDefs.scalarize(0).lower();
2223
2224 if (ST.hasVOP3PInsts()) {
2225 getActionDefinitionsBuilder(G_FSHL)
2226 .lowerFor({{V2S16, V2S16}})
2227 .clampMaxNumElementsStrict(0, S16, 2)
2228 .scalarize(0)
2229 .lower();
2230 } else {
2231 getActionDefinitionsBuilder(G_FSHL)
2232 .scalarize(0)
2233 .lower();
2234 }
2235
2236 getActionDefinitionsBuilder(G_READCYCLECOUNTER)
2237 .legalFor({S64});
2238
2239 getActionDefinitionsBuilder(G_READSTEADYCOUNTER).legalFor({S64});
2240
2241 getActionDefinitionsBuilder(G_FENCE)
2242 .alwaysLegal();
2243
2244 getActionDefinitionsBuilder({G_SMULO, G_UMULO})
2245 .scalarize(0)
2246 .minScalar(0, S32)
2247 .lower();
2248
2249 getActionDefinitionsBuilder({G_SBFX, G_UBFX})
2250 .legalFor({{S32, S32}, {S64, S32}})
2251 .clampScalar(1, S32, S32)
2252 .clampScalar(0, S32, S64)
2253 .widenScalarToNextPow2(0)
2254 .scalarize(0);
2255
2256 getActionDefinitionsBuilder(
2257 {// TODO: Verify V_BFI_B32 is generated from expanded bit ops
2258 G_FCOPYSIGN,
2259
2260 G_ATOMIC_CMPXCHG_WITH_SUCCESS, G_ATOMICRMW_NAND, G_ATOMICRMW_FSUB,
2261 G_READ_REGISTER, G_WRITE_REGISTER,
2262
2263 G_SADDO, G_SSUBO})
2264 .lower();
2265
2266 if (ST.hasIEEEMinimumMaximumInsts()) {
2267 getActionDefinitionsBuilder({G_FMINIMUM, G_FMAXIMUM})
2268 .legalFor(FPTypesPK16)
2269 .clampMaxNumElements(0, F16, 2)
2270 .scalarize(0);
2271 } else if (ST.hasVOP3PInsts()) {
2272 getActionDefinitionsBuilder({G_FMINIMUM, G_FMAXIMUM})
2273 .lowerFor({V2F16})
2274 .clampMaxNumElementsStrict(0, F16, 2)
2275 .scalarize(0)
2276 .lower();
2277 } else {
2278 getActionDefinitionsBuilder({G_FMINIMUM, G_FMAXIMUM})
2279 .scalarize(0)
2280 .clampScalar(0, F32, F64)
2281 .lower();
2282 }
2283
2284 getActionDefinitionsBuilder(
2285 {G_MEMCPY, G_MEMCPY_INLINE, G_MEMMOVE, G_MEMSET, G_MEMSET_INLINE})
2286 .lower();
2287
2288 getActionDefinitionsBuilder({G_TRAP, G_DEBUGTRAP}).custom();
2289
2290 getActionDefinitionsBuilder({G_VASTART, G_VAARG, G_BRJT, G_JUMP_TABLE,
2291 G_INDEXED_LOAD, G_INDEXED_SEXTLOAD,
2292 G_INDEXED_ZEXTLOAD, G_INDEXED_STORE})
2293 .unsupported();
2294
2295 getActionDefinitionsBuilder(G_PREFETCH).alwaysLegal();
2296
2297 getActionDefinitionsBuilder(
2298 {G_VECREDUCE_SMIN, G_VECREDUCE_SMAX, G_VECREDUCE_UMIN, G_VECREDUCE_UMAX,
2299 G_VECREDUCE_ADD, G_VECREDUCE_MUL, G_VECREDUCE_FMUL, G_VECREDUCE_FMIN,
2300 G_VECREDUCE_FMAX, G_VECREDUCE_FMINIMUM, G_VECREDUCE_FMAXIMUM,
2301 G_VECREDUCE_OR, G_VECREDUCE_AND, G_VECREDUCE_XOR})
2302 .legalFor(AllVectors)
2303 .scalarize(1)
2304 .lower();
2305
2306 getActionDefinitionsBuilder({G_INTRINSIC, G_INTRINSIC_W_SIDE_EFFECTS,
2307 G_INTRINSIC_CONVERGENT,
2308 G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS})
2309 .alwaysLegal();
2310
2311 verify(*ST.getInstrInfo());
2312}
2313
2316 LostDebugLocObserver &LocObserver) const {
2317 MachineIRBuilder &B = Helper.MIRBuilder;
2318 MachineRegisterInfo &MRI = *B.getMRI();
2319
2320 switch (MI.getOpcode()) {
2321 case TargetOpcode::G_ADDRSPACE_CAST:
2322 return legalizeAddrSpaceCast(MI, MRI, B);
2323 case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
2324 return legalizeFroundeven(MI, MRI, B);
2325 case TargetOpcode::G_FCEIL:
2326 return legalizeFceil(MI, MRI, B);
2327 case TargetOpcode::G_FREM:
2328 return legalizeFrem(MI, MRI, B);
2329 case TargetOpcode::G_INTRINSIC_TRUNC:
2330 return legalizeIntrinsicTrunc(MI, MRI, B);
2331 case TargetOpcode::G_SITOFP:
2332 return legalizeITOFP(MI, MRI, B, true);
2333 case TargetOpcode::G_UITOFP:
2334 return legalizeITOFP(MI, MRI, B, false);
2335 case TargetOpcode::G_FPTOSI:
2336 return legalizeFPTOI(MI, MRI, B, true);
2337 case TargetOpcode::G_FPTOUI:
2338 return legalizeFPTOI(MI, MRI, B, false);
2339 case TargetOpcode::G_FMINNUM:
2340 case TargetOpcode::G_FMAXNUM:
2341 case TargetOpcode::G_FMINIMUMNUM:
2342 case TargetOpcode::G_FMAXIMUMNUM:
2343 return legalizeMinNumMaxNum(Helper, MI);
2344 case TargetOpcode::G_EXTRACT:
2345 return legalizeExtract(Helper, MI);
2346 case TargetOpcode::G_INSERT:
2347 return legalizeInsert(Helper, MI);
2348 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
2349 return legalizeExtractVectorElt(MI, MRI, B);
2350 case TargetOpcode::G_INSERT_VECTOR_ELT:
2351 return legalizeInsertVectorElt(MI, MRI, B);
2352 case TargetOpcode::G_FSIN:
2353 case TargetOpcode::G_FCOS:
2354 return legalizeSinCos(MI, MRI, B);
2355 case TargetOpcode::G_GLOBAL_VALUE:
2356 return legalizeGlobalValue(MI, MRI, B);
2357 case TargetOpcode::G_LOAD:
2358 case TargetOpcode::G_SEXTLOAD:
2359 case TargetOpcode::G_ZEXTLOAD:
2360 return legalizeLoad(Helper, MI);
2361 case TargetOpcode::G_STORE:
2362 return legalizeStore(Helper, MI);
2363 case TargetOpcode::G_FMAD:
2364 return legalizeFMad(MI, MRI, B);
2365 case TargetOpcode::G_FDIV:
2366 return legalizeFDIV(MI, MRI, B);
2367 case TargetOpcode::G_FFREXP:
2368 return legalizeFFREXP(MI, MRI, B);
2369 case TargetOpcode::G_FSQRT:
2370 return legalizeFSQRT(MI, MRI, B);
2371 case TargetOpcode::G_UDIV:
2372 case TargetOpcode::G_UREM:
2373 case TargetOpcode::G_UDIVREM:
2374 return legalizeUnsignedDIV_REM(MI, MRI, B);
2375 case TargetOpcode::G_SDIV:
2376 case TargetOpcode::G_SREM:
2377 case TargetOpcode::G_SDIVREM:
2378 return legalizeSignedDIV_REM(MI, MRI, B);
2379 case TargetOpcode::G_ATOMIC_CMPXCHG:
2380 return legalizeAtomicCmpXChg(MI, MRI, B);
2381 case TargetOpcode::G_FLOG2:
2382 return legalizeFlog2(MI, B);
2383 case TargetOpcode::G_FLOG:
2384 case TargetOpcode::G_FLOG10:
2385 return legalizeFlogCommon(MI, B);
2386 case TargetOpcode::G_FEXP2:
2387 return legalizeFExp2(MI, B);
2388 case TargetOpcode::G_FEXP:
2389 case TargetOpcode::G_FEXP10:
2390 return legalizeFExp(MI, B);
2391 case TargetOpcode::G_FPOW:
2392 return legalizeFPow(MI, B);
2393 case TargetOpcode::G_FFLOOR:
2394 return legalizeFFloor(MI, MRI, B);
2395 case TargetOpcode::G_BUILD_VECTOR:
2396 case TargetOpcode::G_BUILD_VECTOR_TRUNC:
2397 return legalizeBuildVector(MI, MRI, B);
2398 case TargetOpcode::G_MUL:
2399 return legalizeMul(Helper, MI);
2400 case TargetOpcode::G_CTLZ:
2401 case TargetOpcode::G_CTTZ:
2402 return legalizeCTLZ_CTTZ(MI, MRI, B);
2403 case TargetOpcode::G_CTLS:
2404 return legalizeCTLS(MI, MRI, B);
2405 case TargetOpcode::G_CTLZ_ZERO_POISON:
2406 return legalizeCTLZ_ZERO_POISON(MI, MRI, B);
2407 case TargetOpcode::G_STACKSAVE:
2408 return legalizeStackSave(MI, B);
2409 case TargetOpcode::G_GET_FPENV:
2410 return legalizeGetFPEnv(MI, MRI, B);
2411 case TargetOpcode::G_SET_FPENV:
2412 return legalizeSetFPEnv(MI, MRI, B);
2413 case TargetOpcode::G_TRAP:
2414 return legalizeTrap(MI, MRI, B);
2415 case TargetOpcode::G_DEBUGTRAP:
2416 return legalizeDebugTrap(MI, MRI, B);
2417 default:
2418 return false;
2419 }
2420
2421 llvm_unreachable("expected switch to return");
2422}
2423
2425 unsigned AS,
2427 MachineIRBuilder &B) const {
2428 MachineFunction &MF = B.getMF();
2429 const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
2430 const LLT I32 = LLT::integer(32);
2431 const LLT I64 = LLT::integer(64);
2432
2434
2435 if (ST.hasApertureRegs()) {
2436 // Note: this register is somewhat broken. When used as a 32-bit operand,
2437 // it only returns zeroes. The real value is in the upper 32 bits.
2438 // Thus, we must emit extract the high 32 bits.
2439 const unsigned ApertureRegNo = (AS == AMDGPUAS::LOCAL_ADDRESS)
2440 ? AMDGPU::SRC_SHARED_BASE
2441 : AMDGPU::SRC_PRIVATE_BASE;
2442 assert((ApertureRegNo != AMDGPU::SRC_PRIVATE_BASE ||
2443 !ST.hasGloballyAddressableScratch()) &&
2444 "Cannot use src_private_base with globally addressable scratch!");
2446 MRI.setRegClass(Dst, &AMDGPU::SReg_64RegClass);
2447 B.buildCopy({Dst}, {Register(ApertureRegNo)});
2448 return B.buildUnmerge(I32, Dst).getReg(1);
2449 }
2450
2453 // For code object version 5, private_base and shared_base are passed through
2454 // implicit kernargs.
2458
2462 uint64_t Offset =
2463 ST.getTargetLowering()->getImplicitParameterOffset(B.getMF(), Param);
2464
2465 Register KernargPtrReg = MRI.createGenericVirtualRegister(
2467
2468 if (!loadInputValue(KernargPtrReg, B,
2470 return Register();
2471
2473 PtrInfo.getWithOffset(Offset),
2477
2478 // Pointer address
2479 B.buildObjectPtrOffset(LoadAddr, KernargPtrReg,
2480 B.buildConstant(LLT::integer(64), Offset).getReg(0));
2481 // Load address
2482 return B.buildLoad(I32, LoadAddr, *MMO).getReg(0);
2483 }
2484
2487
2489 return Register();
2490
2491 // TODO: Use custom PseudoSourceValue
2493
2494 // Offset into amd_queue_t for group_segment_aperture_base_hi /
2495 // private_segment_aperture_base_hi.
2496 uint32_t StructOffset = (AS == AMDGPUAS::LOCAL_ADDRESS) ? 0x40 : 0x44;
2497
2499 PtrInfo,
2502 LLT::integer(32), commonAlignment(Align(64), StructOffset));
2503
2504 B.buildObjectPtrOffset(
2505 LoadAddr, QueuePtr,
2506 B.buildConstant(LLT::integer(64), StructOffset).getReg(0));
2507 return B.buildLoad(I32, LoadAddr, *MMO).getReg(0);
2508}
2509
2510/// Return true if the value is a known valid address, such that a null check is
2511/// not necessary.
2513 const AMDGPUTargetMachine &TM, unsigned AddrSpace) {
2514 MachineInstr *Def = MRI.getVRegDef(Val);
2515 switch (Def->getOpcode()) {
2516 case AMDGPU::G_FRAME_INDEX:
2517 case AMDGPU::G_GLOBAL_VALUE:
2518 case AMDGPU::G_BLOCK_ADDR:
2519 return true;
2520 case AMDGPU::G_CONSTANT: {
2521 const ConstantInt *CI = Def->getOperand(1).getCImm();
2522 return CI->getSExtValue() != AMDGPU::getNullPointerValue(AddrSpace);
2523 }
2524 default:
2525 return false;
2526 }
2527
2528 return false;
2529}
2530
2533 MachineIRBuilder &B) const {
2534 MachineFunction &MF = B.getMF();
2535
2536 // MI can either be a G_ADDRSPACE_CAST or a
2537 // G_INTRINSIC @llvm.amdgcn.addrspacecast.nonnull
2538 assert(MI.getOpcode() == TargetOpcode::G_ADDRSPACE_CAST ||
2539 (isa<GIntrinsic>(MI) && cast<GIntrinsic>(MI).getIntrinsicID() ==
2540 Intrinsic::amdgcn_addrspacecast_nonnull));
2541
2542 const LLT I32 = LLT::integer(32);
2543 const LLT I64 = LLT::integer(64);
2544 Register Dst = MI.getOperand(0).getReg();
2545 Register Src = isa<GIntrinsic>(MI) ? MI.getOperand(2).getReg()
2546 : MI.getOperand(1).getReg();
2547 LLT DstTy = MRI.getType(Dst);
2548 LLT SrcTy = MRI.getType(Src);
2549 unsigned DestAS = DstTy.getAddressSpace();
2550 unsigned SrcAS = SrcTy.getAddressSpace();
2551
2552 // TODO: Avoid reloading from the queue ptr for each cast, or at least each
2553 // vector element.
2554 assert(!DstTy.isVector());
2555
2556 const AMDGPUTargetMachine &TM
2557 = static_cast<const AMDGPUTargetMachine &>(MF.getTarget());
2558
2559 if (TM.isNoopAddrSpaceCast(SrcAS, DestAS)) {
2560 MI.setDesc(B.getTII().get(TargetOpcode::G_BITCAST));
2561 return true;
2562 }
2563
2564 if (SrcAS == AMDGPUAS::FLAT_ADDRESS &&
2565 (DestAS == AMDGPUAS::LOCAL_ADDRESS ||
2566 DestAS == AMDGPUAS::PRIVATE_ADDRESS)) {
2567 auto castFlatToLocalOrPrivate = [&](const DstOp &Dst) -> Register {
2568 if (DestAS == AMDGPUAS::PRIVATE_ADDRESS &&
2569 ST.hasGloballyAddressableScratch()) {
2570 // flat -> private with globally addressable scratch: subtract
2571 // src_flat_scratch_base_lo.
2572 Register SrcLo = B.buildExtract(I32, Src, 0).getReg(0);
2573 Register FlatScratchBaseLo =
2574 B.buildInstr(AMDGPU::S_MOV_B32, {I32},
2575 {Register(AMDGPU::SRC_FLAT_SCRATCH_BASE_LO)})
2576 .getReg(0);
2577 MRI.setRegClass(FlatScratchBaseLo, &AMDGPU::SReg_32RegClass);
2578 Register Sub = B.buildSub(I32, SrcLo, FlatScratchBaseLo).getReg(0);
2579 return B.buildIntToPtr(Dst, Sub).getReg(0);
2580 }
2581
2582 // Extract low 32-bits of the pointer.
2583 return B.buildExtract(Dst, Src, 0).getReg(0);
2584 };
2585
2586 // For llvm.amdgcn.addrspacecast.nonnull we can always assume non-null, for
2587 // G_ADDRSPACE_CAST we need to guess.
2588 if (isa<GIntrinsic>(MI) || isKnownNonNull(Src, MRI, TM, SrcAS)) {
2589 castFlatToLocalOrPrivate(Dst);
2590 MI.eraseFromParent();
2591 return true;
2592 }
2593
2594 unsigned NullVal = AMDGPU::getNullPointerValue(DestAS);
2595
2596 auto SegmentNull = B.buildConstant(DstTy, NullVal);
2597 auto FlatNull = B.buildConstant(SrcTy, 0);
2598
2599 // Extract low 32-bits of the pointer.
2600 auto PtrLo32 = castFlatToLocalOrPrivate(DstTy);
2601
2602 auto CmpRes =
2603 B.buildICmp(CmpInst::ICMP_NE, LLT::scalar(1), Src, FlatNull.getReg(0));
2604 B.buildSelect(Dst, CmpRes, PtrLo32, SegmentNull.getReg(0));
2605
2606 MI.eraseFromParent();
2607 return true;
2608 }
2609
2610 if (DestAS == AMDGPUAS::FLAT_ADDRESS &&
2611 (SrcAS == AMDGPUAS::LOCAL_ADDRESS ||
2612 SrcAS == AMDGPUAS::PRIVATE_ADDRESS)) {
2613 auto castLocalOrPrivateToFlat = [&](const DstOp &Dst) -> Register {
2614 // Coerce the type of the low half of the result so we can use
2615 // merge_values.
2616 Register SrcAsInt = B.buildPtrToInt(I32, Src).getReg(0);
2617
2618 if (SrcAS == AMDGPUAS::PRIVATE_ADDRESS &&
2619 ST.hasGloballyAddressableScratch()) {
2620 // For wave32: Addr = (TID[4:0] << 52) + FLAT_SCRATCH_BASE + privateAddr
2621 // For wave64: Addr = (TID[5:0] << 51) + FLAT_SCRATCH_BASE + privateAddr
2622 Register AllOnes = B.buildConstant(I32, -1).getReg(0);
2623 Register ThreadID = B.buildConstant(I32, 0).getReg(0);
2624 ThreadID = B.buildIntrinsic(Intrinsic::amdgcn_mbcnt_lo, {I32})
2625 .addUse(AllOnes)
2626 .addUse(ThreadID)
2627 .getReg(0);
2628 if (ST.isWave64()) {
2629 ThreadID = B.buildIntrinsic(Intrinsic::amdgcn_mbcnt_hi, {I32})
2630 .addUse(AllOnes)
2631 .addUse(ThreadID)
2632 .getReg(0);
2633 }
2634 Register ShAmt =
2635 B.buildConstant(I32, 57 - 32 - ST.getWavefrontSizeLog2()).getReg(0);
2636 Register SrcHi = B.buildShl(I32, ThreadID, ShAmt).getReg(0);
2637 Register CvtPtr =
2638 B.buildMergeLikeInstr(DstTy, {SrcAsInt, SrcHi}).getReg(0);
2639 // Accessing src_flat_scratch_base_lo as a 64-bit operand gives the full
2640 // 64-bit hi:lo value.
2641 Register FlatScratchBase =
2642 B.buildInstr(AMDGPU::S_MOV_B64, {I64},
2643 {Register(AMDGPU::SRC_FLAT_SCRATCH_BASE)})
2644 .getReg(0);
2645 MRI.setRegClass(FlatScratchBase, &AMDGPU::SReg_64RegClass);
2646 return B.buildPtrAdd(Dst, CvtPtr, FlatScratchBase).getReg(0);
2647 }
2648
2649 Register ApertureReg = getSegmentAperture(SrcAS, MRI, B);
2650 if (!ApertureReg.isValid())
2651 return false;
2652
2653 // TODO: Should we allow mismatched types but matching sizes in merges to
2654 // avoid the ptrtoint?
2655 return B.buildMergeLikeInstr(Dst, {SrcAsInt, ApertureReg}).getReg(0);
2656 };
2657
2658 // For llvm.amdgcn.addrspacecast.nonnull we can always assume non-null, for
2659 // G_ADDRSPACE_CAST we need to guess.
2660 if (isa<GIntrinsic>(MI) || isKnownNonNull(Src, MRI, TM, SrcAS)) {
2661 castLocalOrPrivateToFlat(Dst);
2662 MI.eraseFromParent();
2663 return true;
2664 }
2665
2666 Register BuildPtr = castLocalOrPrivateToFlat(DstTy);
2667
2668 auto SegmentNull =
2669 B.buildConstant(SrcTy, AMDGPU::getNullPointerValue(SrcAS));
2670 auto FlatNull = B.buildConstant(DstTy, AMDGPU::getNullPointerValue(DestAS));
2671
2672 auto CmpRes = B.buildICmp(CmpInst::ICMP_NE, LLT::scalar(1), Src,
2673 SegmentNull.getReg(0));
2674
2675 B.buildSelect(Dst, CmpRes, BuildPtr, FlatNull);
2676
2677 MI.eraseFromParent();
2678 return true;
2679 }
2680
2681 if (DestAS == AMDGPUAS::CONSTANT_ADDRESS_32BIT &&
2682 SrcTy.getSizeInBits() == 64) {
2683 // Truncate.
2684 B.buildExtract(Dst, Src, 0);
2685 MI.eraseFromParent();
2686 return true;
2687 }
2688
2689 if (SrcAS == AMDGPUAS::CONSTANT_ADDRESS_32BIT &&
2690 DstTy.getSizeInBits() == 64) {
2692 uint32_t AddrHiVal = Info->get32BitAddressHighBits();
2693 auto PtrLo = B.buildPtrToInt(I32, Src);
2694 if (AddrHiVal == 0) {
2695 auto Zext = B.buildZExt(I64, PtrLo);
2696 B.buildIntToPtr(Dst, Zext);
2697 } else {
2698 auto HighAddr = B.buildConstant(I32, AddrHiVal);
2699 B.buildMergeLikeInstr(Dst, {PtrLo, HighAddr});
2700 }
2701
2702 MI.eraseFromParent();
2703 return true;
2704 }
2705
2706 // Invalid casts are poison.
2707 // TODO: Should return poison
2708 B.buildUndef(Dst);
2709 MI.eraseFromParent();
2710 return true;
2711}
2712
2715 MachineIRBuilder &B) const {
2716 Register Src = MI.getOperand(1).getReg();
2717 LLT Ty = MRI.getType(Src);
2718 assert(Ty.isScalar() && Ty.getSizeInBits() == 64);
2719
2720 APFloat C1Val(APFloat::IEEEdouble(), "0x1.0p+52");
2721 APFloat C2Val(APFloat::IEEEdouble(), "0x1.fffffffffffffp+51");
2722
2723 auto C1 = B.buildFConstant(Ty, C1Val);
2724 auto CopySign = B.buildFCopysign(Ty, C1, Src);
2725
2726 // TODO: Should this propagate fast-math-flags?
2727 auto Tmp1 = B.buildFAdd(Ty, Src, CopySign);
2728 auto Tmp2 = B.buildFSub(Ty, Tmp1, CopySign);
2729
2730 auto C2 = B.buildFConstant(Ty, C2Val);
2731 auto Fabs = B.buildFAbs(Ty, Src);
2732
2733 auto Cond = B.buildFCmp(CmpInst::FCMP_OGT, LLT::scalar(1), Fabs, C2);
2734 B.buildSelect(MI.getOperand(0).getReg(), Cond, Src, Tmp2);
2735 MI.eraseFromParent();
2736 return true;
2737}
2738
2741 MachineIRBuilder &B) const {
2742
2743 const LLT S1 = LLT::scalar(1);
2744
2745 Register Src = MI.getOperand(1).getReg();
2746 assert(MRI.getType(Src) == F64);
2747
2748 // result = trunc(src)
2749 // if (src > 0.0 && src != result)
2750 // result += 1.0
2751
2752 auto Trunc = B.buildIntrinsicTrunc(F64, Src);
2753
2754 const auto Zero = B.buildFConstant(F64, 0.0);
2755 const auto One = B.buildFConstant(F64, 1.0);
2756 auto Lt0 = B.buildFCmp(CmpInst::FCMP_OGT, S1, Src, Zero);
2757 auto NeTrunc = B.buildFCmp(CmpInst::FCMP_ONE, S1, Src, Trunc);
2758 auto And = B.buildAnd(S1, Lt0, NeTrunc);
2759 auto Add = B.buildSelect(F64, And, One, Zero);
2760
2761 // TODO: Should this propagate fast-math-flags?
2762 B.buildFAdd(MI.getOperand(0).getReg(), Trunc, Add);
2763 MI.eraseFromParent();
2764 return true;
2765}
2766
2769 MachineIRBuilder &B) const {
2770 Register DstReg = MI.getOperand(0).getReg();
2771 Register Src0Reg = MI.getOperand(1).getReg();
2772 Register Src1Reg = MI.getOperand(2).getReg();
2773 auto Flags = MI.getFlags();
2774 LLT Ty = MRI.getType(DstReg);
2775
2776 auto Div = B.buildFDiv(Ty, Src0Reg, Src1Reg, Flags);
2777 auto Trunc = B.buildIntrinsicTrunc(Ty, Div, Flags);
2778 auto Neg = B.buildFNeg(Ty, Trunc, Flags);
2779 B.buildFMA(DstReg, Neg, Src1Reg, Src0Reg, Flags);
2780 MI.eraseFromParent();
2781 return true;
2782}
2783
2786 const unsigned FractBits = 52;
2787 const unsigned ExpBits = 11;
2788 LLT I32 = LLT::integer(32);
2789
2790 auto Const0 = B.buildConstant(I32, FractBits - 32);
2791 auto Const1 = B.buildConstant(I32, ExpBits);
2792
2793 auto ExpPart = B.buildIntrinsic(Intrinsic::amdgcn_ubfe, {I32})
2794 .addUse(Hi)
2795 .addUse(Const0.getReg(0))
2796 .addUse(Const1.getReg(0));
2797
2798 return B.buildSub(I32, ExpPart, B.buildConstant(I32, 1023));
2799}
2800
2803 MachineIRBuilder &B) const {
2804 const LLT S1 = LLT::scalar(1);
2805 const LLT I32 = LLT::integer(32);
2806 const LLT I64 = LLT::integer(64);
2807
2808 Register Src = MI.getOperand(1).getReg();
2809 assert(MRI.getType(Src) == F64);
2810
2811 auto SrcInt = B.buildBitcast(I64, Src);
2812
2813 // TODO: Should this use extract since the low half is unused?
2814 auto Unmerge = B.buildUnmerge({I32, I32}, SrcInt);
2815 Register Hi = Unmerge.getReg(1);
2816
2817 // Extract the upper half, since this is where we will find the sign and
2818 // exponent.
2819 auto Exp = extractF64Exponent(Hi, B);
2820
2821 const unsigned FractBits = 52;
2822
2823 // Extract the sign bit.
2824 const auto SignBitMask = B.buildConstant(I32, UINT32_C(1) << 31);
2825 auto SignBit = B.buildAnd(I32, Hi, SignBitMask);
2826
2827 const auto FractMask = B.buildConstant(I64, (UINT64_C(1) << FractBits) - 1);
2828
2829 const auto Zero32 = B.buildConstant(I32, 0);
2830
2831 // Extend back to 64-bits.
2832 auto SignBit64 = B.buildMergeLikeInstr(I64, {Zero32, SignBit});
2833
2834 auto Shr = B.buildAShr(I64, FractMask, Exp);
2835 auto Not = B.buildNot(I64, Shr);
2836 auto Tmp0 = B.buildAnd(I64, SrcInt, Not);
2837 auto FiftyOne = B.buildConstant(I32, FractBits - 1);
2838
2839 auto ExpLt0 = B.buildICmp(CmpInst::ICMP_SLT, S1, Exp, Zero32);
2840 auto ExpGt51 = B.buildICmp(CmpInst::ICMP_SGT, S1, Exp, FiftyOne);
2841
2842 auto Tmp1 = B.buildSelect(I64, ExpLt0, SignBit64, Tmp0);
2843 auto Res = B.buildSelect(I64, ExpGt51, SrcInt, Tmp1);
2844 B.buildBitcast(MI.getOperand(0).getReg(), Res);
2845 MI.eraseFromParent();
2846 return true;
2847}
2848
2851 MachineIRBuilder &B, bool Signed) const {
2852
2853 Register Dst = MI.getOperand(0).getReg();
2854 Register Src = MI.getOperand(1).getReg();
2855
2856 const LLT I64 = LLT::integer(64);
2857 const LLT I32 = LLT::integer(32);
2858
2859 assert(MRI.getType(Src) == I64);
2860
2861 auto Unmerge = B.buildUnmerge({I32, I32}, Src);
2862 auto ThirtyTwo = B.buildConstant(I32, 32);
2863
2864 if (MRI.getType(Dst) == F64) {
2865 auto CvtHi = Signed ? B.buildSITOFP(F64, Unmerge.getReg(1))
2866 : B.buildUITOFP(F64, Unmerge.getReg(1));
2867
2868 auto CvtLo = B.buildUITOFP(F64, Unmerge.getReg(0));
2869 auto LdExp = B.buildFLdexp(F64, CvtHi, ThirtyTwo);
2870
2871 // TODO: Should this propagate fast-math-flags?
2872 B.buildFAdd(Dst, LdExp, CvtLo);
2873 MI.eraseFromParent();
2874 return true;
2875 }
2876
2877 assert(MRI.getType(Dst) == F32);
2878
2879 auto One = B.buildConstant(I32, 1);
2880
2881 MachineInstrBuilder ShAmt;
2882 if (Signed) {
2883 auto ThirtyOne = B.buildConstant(I32, 31);
2884 auto X = B.buildXor(I32, Unmerge.getReg(0), Unmerge.getReg(1));
2885 auto OppositeSign = B.buildAShr(I32, X, ThirtyOne);
2886 auto MaxShAmt = B.buildAdd(I32, ThirtyTwo, OppositeSign);
2887 auto LS = B.buildIntrinsic(Intrinsic::amdgcn_sffbh, {I32})
2888 .addUse(Unmerge.getReg(1));
2889 auto LS2 = B.buildSub(I32, LS, One);
2890 ShAmt = B.buildUMin(I32, LS2, MaxShAmt);
2891 } else
2892 ShAmt = B.buildCTLZ(I32, Unmerge.getReg(1));
2893 auto Norm = B.buildShl(I64, Src, ShAmt);
2894 auto Unmerge2 = B.buildUnmerge({I32, I32}, Norm);
2895 auto Adjust = B.buildUMin(I32, One, Unmerge2.getReg(0));
2896 auto Norm2 = B.buildOr(I32, Unmerge2.getReg(1), Adjust);
2897 auto FVal = Signed ? B.buildSITOFP(F32, Norm2) : B.buildUITOFP(F32, Norm2);
2898 auto Scale = B.buildSub(I32, ThirtyTwo, ShAmt);
2899 B.buildFLdexp(Dst, FVal, Scale);
2900 MI.eraseFromParent();
2901 return true;
2902}
2903
2904// TODO: Copied from DAG implementation. Verify logic and document how this
2905// actually works.
2909 bool Signed) const {
2910
2911 Register Dst = MI.getOperand(0).getReg();
2912 Register Src = MI.getOperand(1).getReg();
2913
2914 const LLT I64 = LLT::integer(64);
2915 const LLT I32 = LLT::integer(32);
2916
2917 const LLT SrcLT = MRI.getType(Src);
2918 assert((SrcLT == F32 || SrcLT == F64) && MRI.getType(Dst) == I64);
2919
2920 unsigned Flags = MI.getFlags();
2921
2922 // The basic idea of converting a floating point number into a pair of 32-bit
2923 // integers is illustrated as follows:
2924 //
2925 // tf := trunc(val);
2926 // hif := floor(tf * 2^-32);
2927 // lof := tf - hif * 2^32; // lof is always positive due to floor.
2928 // hi := fptoi(hif);
2929 // lo := fptoi(lof);
2930 //
2931 auto Trunc = B.buildIntrinsicTrunc(SrcLT, Src, Flags);
2933 if (Signed && SrcLT == F32) {
2934 // However, a 32-bit floating point number has only 23 bits mantissa and
2935 // it's not enough to hold all the significant bits of `lof` if val is
2936 // negative. To avoid the loss of precision, We need to take the absolute
2937 // value after truncating and flip the result back based on the original
2938 // signedness.
2939 auto SrcInt = B.buildBitcast(I32, Src);
2940 Sign = B.buildAShr(I32, SrcInt, B.buildConstant(I32, 31));
2941 Trunc = B.buildFAbs(F32, Trunc, Flags);
2942 }
2943 MachineInstrBuilder K0, K1;
2944 if (SrcLT == F64) {
2945 K0 = B.buildFConstant(
2946 F64, llvm::bit_cast<double>(UINT64_C(/*2^-32*/ 0x3df0000000000000)));
2947 K1 = B.buildFConstant(
2948 F64, llvm::bit_cast<double>(UINT64_C(/*-2^32*/ 0xc1f0000000000000)));
2949 } else {
2950 K0 = B.buildFConstant(
2951 F32, llvm::bit_cast<float>(UINT32_C(/*2^-32*/ 0x2f800000)));
2952 K1 = B.buildFConstant(
2953 F32, llvm::bit_cast<float>(UINT32_C(/*-2^32*/ 0xcf800000)));
2954 }
2955
2956 auto Mul = B.buildFMul(SrcLT, Trunc, K0, Flags);
2957 auto FloorMul = B.buildFFloor(SrcLT, Mul, Flags);
2958 auto Fma = B.buildFMA(SrcLT, FloorMul, K1, Trunc, Flags);
2959
2960 auto Hi = (Signed && SrcLT == F64) ? B.buildFPTOSI(I32, FloorMul)
2961 : B.buildFPTOUI(I32, FloorMul);
2962 auto Lo = B.buildFPTOUI(I32, Fma);
2963
2964 if (Signed && SrcLT == F32) {
2965 // Flip the result based on the signedness, which is either all 0s or 1s.
2966 Sign = B.buildMergeLikeInstr(I64, {Sign, Sign});
2967 // r := xor({lo, hi}, sign) - sign;
2968 B.buildSub(Dst, B.buildXor(I64, B.buildMergeLikeInstr(I64, {Lo, Hi}), Sign),
2969 Sign);
2970 } else
2971 B.buildMergeLikeInstr(Dst, {Lo, Hi});
2972 MI.eraseFromParent();
2973
2974 return true;
2975}
2976
2978 MachineInstr &MI) const {
2979 MachineFunction &MF = Helper.MIRBuilder.getMF();
2981
2982 // With ieee_mode disabled, the instructions have the correct behavior.
2983 if (!MFI->getMode().IEEE)
2984 return true;
2985
2987}
2988
2990 MachineInstr &MI) const {
2991 MachineIRBuilder &B = Helper.MIRBuilder;
2992 MachineRegisterInfo &MRI = *B.getMRI();
2993 Register DstReg = MI.getOperand(0).getReg();
2994 Register SrcReg = MI.getOperand(1).getReg();
2995 uint64_t Offset = MI.getOperand(2).getImm();
2996
2997 // Fall back to generic lowering for offset 0 (trivial trunc) and
2998 // non-32-bit-aligned cases which require shift+trunc sequences
2999 // that generic code handles correctly.
3000 if (Offset == 0 || Offset % 32 != 0)
3001 return Helper.lowerExtract(MI) == LegalizerHelper::Legalized;
3002
3003 const LLT DstTy = MRI.getType(DstReg);
3004 unsigned StartIdx = Offset / 32;
3005 unsigned DstCount = DstTy.getSizeInBits() / 32;
3006 auto Unmerge = B.buildUnmerge(LLT::integer(32), SrcReg);
3007
3008 if (DstCount == 1) {
3009 if (DstTy.isPointer())
3010 B.buildIntToPtr(DstReg, Unmerge.getReg(StartIdx));
3011 else
3012 MRI.replaceRegWith(DstReg, Unmerge.getReg(StartIdx));
3013 } else {
3014 SmallVector<Register, 8> MergeVec;
3015 for (unsigned I = 0; I < DstCount; ++I)
3016 MergeVec.push_back(Unmerge.getReg(StartIdx + I));
3017 B.buildMergeLikeInstr(DstReg, MergeVec);
3018 }
3019
3020 MI.eraseFromParent();
3021 return true;
3022}
3023
3025 MachineInstr &MI) const {
3026 MachineIRBuilder &B = Helper.MIRBuilder;
3027 MachineRegisterInfo &MRI = *B.getMRI();
3028 Register DstReg = MI.getOperand(0).getReg();
3029 Register SrcReg = MI.getOperand(1).getReg();
3030 Register InsertSrc = MI.getOperand(2).getReg();
3031 uint64_t Offset = MI.getOperand(3).getImm();
3032
3033 unsigned DstSize = MRI.getType(DstReg).getSizeInBits();
3034 const LLT InsertTy = MRI.getType(InsertSrc);
3035 unsigned InsertSize = InsertTy.getSizeInBits();
3036
3037 // Fall back to generic lowering for non-32-bit-aligned cases which
3038 // require shift+mask sequences that generic code handles correctly.
3039 if (Offset % 32 != 0 || DstSize % 32 != 0 || InsertSize % 32 != 0)
3040 return Helper.lowerInsert(MI) == LegalizerHelper::Legalized;
3041
3042 const LLT I32 = LLT::integer(32);
3043 unsigned DstCount = DstSize / 32;
3044 unsigned InsertCount = InsertSize / 32;
3045 unsigned StartIdx = Offset / 32;
3046
3047 auto SrcUnmerge = B.buildUnmerge(I32, SrcReg);
3048
3049 SmallVector<Register, 8> MergeVec;
3050 for (unsigned I = 0; I < StartIdx; ++I)
3051 MergeVec.push_back(SrcUnmerge.getReg(I));
3052
3053 if (InsertCount == 1) {
3054 // Merge-like instructions require same source types. Convert pointer
3055 // to scalar when inserting a pointer value into a scalar.
3056 if (InsertTy.isPointer())
3057 InsertSrc = B.buildPtrToInt(I32, InsertSrc).getReg(0);
3058 MergeVec.push_back(InsertSrc);
3059 } else {
3060 auto InsertUnmerge = B.buildUnmerge(I32, InsertSrc);
3061 for (unsigned I = 0; I < InsertCount; ++I)
3062 MergeVec.push_back(InsertUnmerge.getReg(I));
3063 }
3064
3065 for (unsigned I = StartIdx + InsertCount; I < DstCount; ++I)
3066 MergeVec.push_back(SrcUnmerge.getReg(I));
3067
3068 B.buildMergeLikeInstr(DstReg, MergeVec);
3069
3070 MI.eraseFromParent();
3071 return true;
3072}
3073
3076 MachineIRBuilder &B) const {
3077 // TODO: Should move some of this into LegalizerHelper.
3078
3079 // TODO: Promote dynamic indexing of i16/f16 to i32/f32
3080
3081 Register Dst = MI.getOperand(0).getReg();
3082 Register Vec = MI.getOperand(1).getReg();
3083
3084 LLT VecTy = MRI.getType(Vec);
3085 LLT EltTy = VecTy.getElementType();
3086 assert(EltTy == MRI.getType(Dst));
3087
3088 // Other legalization maps vector<? x [type bigger than 64 bits]> via bitcasts
3089 // but we can't go directly to that logic becasue you can't bitcast a vector
3090 // of pointers to a vector of integers. Therefore, introduce an intermediate
3091 // vector of integers using ptrtoint (and inttoptr on the output) in order to
3092 // drive the legalization forward.
3093 if (EltTy.isPointer() && EltTy.getSizeInBits() > 64) {
3094 LLT IntTy = LLT::integer(EltTy.getSizeInBits());
3095 LLT IntVecTy = VecTy.changeElementType(IntTy);
3096
3097 auto IntVec = B.buildPtrToInt(IntVecTy, Vec);
3098 auto IntElt = B.buildExtractVectorElement(IntTy, IntVec, MI.getOperand(2));
3099 B.buildIntToPtr(Dst, IntElt);
3100
3101 MI.eraseFromParent();
3102 return true;
3103 }
3104
3105 // FIXME: Artifact combiner probably should have replaced the truncated
3106 // constant before this, so we shouldn't need
3107 // getIConstantVRegValWithLookThrough.
3108 std::optional<ValueAndVReg> MaybeIdxVal =
3109 getIConstantVRegValWithLookThrough(MI.getOperand(2).getReg(), MRI);
3110 if (!MaybeIdxVal) // Dynamic case will be selected to register indexing.
3111 return true;
3112 const uint64_t IdxVal = MaybeIdxVal->Value.getZExtValue();
3113
3114 if (IdxVal < VecTy.getNumElements()) {
3115 auto Unmerge = B.buildUnmerge(EltTy, Vec);
3116 B.buildCopy(Dst, Unmerge.getReg(IdxVal));
3117 } else {
3118 B.buildUndef(Dst);
3119 }
3120
3121 MI.eraseFromParent();
3122 return true;
3123}
3124
3127 MachineIRBuilder &B) const {
3128 // TODO: Should move some of this into LegalizerHelper.
3129
3130 // TODO: Promote dynamic indexing of i16/f16 to i32/f32
3131
3132 Register Dst = MI.getOperand(0).getReg();
3133 Register Vec = MI.getOperand(1).getReg();
3134 Register Ins = MI.getOperand(2).getReg();
3135
3136 LLT VecTy = MRI.getType(Vec);
3137 LLT EltTy = VecTy.getElementType();
3138 assert(EltTy == MRI.getType(Ins));
3139
3140 // Other legalization maps vector<? x [type bigger than 64 bits]> via bitcasts
3141 // but we can't go directly to that logic becasue you can't bitcast a vector
3142 // of pointers to a vector of integers. Therefore, make the pointer vector
3143 // into an equivalent vector of integers with ptrtoint, insert the ptrtoint'd
3144 // new value, and then inttoptr the result vector back. This will then allow
3145 // the rest of legalization to take over.
3146 if (EltTy.isPointer() && EltTy.getSizeInBits() > 64) {
3147 LLT IntTy = LLT::integer(EltTy.getSizeInBits());
3148 LLT IntVecTy = VecTy.changeElementType(IntTy);
3149
3150 auto IntVecSource = B.buildPtrToInt(IntVecTy, Vec);
3151 auto IntIns = B.buildPtrToInt(IntTy, Ins);
3152 auto IntVecDest = B.buildInsertVectorElement(IntVecTy, IntVecSource, IntIns,
3153 MI.getOperand(3));
3154 B.buildIntToPtr(Dst, IntVecDest);
3155 MI.eraseFromParent();
3156 return true;
3157 }
3158
3159 // FIXME: Artifact combiner probably should have replaced the truncated
3160 // constant before this, so we shouldn't need
3161 // getIConstantVRegValWithLookThrough.
3162 std::optional<ValueAndVReg> MaybeIdxVal =
3163 getIConstantVRegValWithLookThrough(MI.getOperand(3).getReg(), MRI);
3164 if (!MaybeIdxVal) // Dynamic case will be selected to register indexing.
3165 return true;
3166
3167 const uint64_t IdxVal = MaybeIdxVal->Value.getZExtValue();
3168
3169 unsigned NumElts = VecTy.getNumElements();
3170 if (IdxVal < NumElts) {
3172 for (unsigned i = 0; i < NumElts; ++i)
3173 SrcRegs.push_back(MRI.createGenericVirtualRegister(EltTy));
3174 B.buildUnmerge(SrcRegs, Vec);
3175
3176 SrcRegs[IdxVal] = MI.getOperand(2).getReg();
3177 B.buildMergeLikeInstr(Dst, SrcRegs);
3178 } else {
3179 B.buildUndef(Dst);
3180 }
3181
3182 MI.eraseFromParent();
3183 return true;
3184}
3185
3188 MachineIRBuilder &B) const {
3189
3190 Register DstReg = MI.getOperand(0).getReg();
3191 Register SrcReg = MI.getOperand(1).getReg();
3192 LLT Ty = MRI.getType(DstReg);
3193 unsigned Flags = MI.getFlags();
3194
3195 Register TrigVal;
3196 auto OneOver2Pi = B.buildFConstant(Ty, 0.5 * numbers::inv_pi);
3197 if (ST.hasTrigReducedRange()) {
3198 auto MulVal = B.buildFMul(Ty, SrcReg, OneOver2Pi, Flags);
3199 TrigVal = B.buildIntrinsic(Intrinsic::amdgcn_fract, {Ty})
3200 .addUse(MulVal.getReg(0))
3201 .setMIFlags(Flags)
3202 .getReg(0);
3203 } else
3204 TrigVal = B.buildFMul(Ty, SrcReg, OneOver2Pi, Flags).getReg(0);
3205
3206 Intrinsic::ID TrigIntrin = MI.getOpcode() == AMDGPU::G_FSIN ?
3207 Intrinsic::amdgcn_sin : Intrinsic::amdgcn_cos;
3208 B.buildIntrinsic(TrigIntrin, ArrayRef<Register>(DstReg))
3209 .addUse(TrigVal)
3210 .setMIFlags(Flags);
3211 MI.eraseFromParent();
3212 return true;
3213}
3214
3217 const GlobalValue *GV,
3218 int64_t Offset,
3219 unsigned GAFlags) const {
3220 assert(isInt<32>(Offset + 4) && "32-bit offset is expected!");
3221 // In order to support pc-relative addressing, SI_PC_ADD_REL_OFFSET is lowered
3222 // to the following code sequence:
3223 //
3224 // For constant address space:
3225 // s_getpc_b64 s[0:1]
3226 // s_add_u32 s0, s0, $symbol
3227 // s_addc_u32 s1, s1, 0
3228 //
3229 // s_getpc_b64 returns the address of the s_add_u32 instruction and then
3230 // a fixup or relocation is emitted to replace $symbol with a literal
3231 // constant, which is a pc-relative offset from the encoding of the $symbol
3232 // operand to the global variable.
3233 //
3234 // For global address space:
3235 // s_getpc_b64 s[0:1]
3236 // s_add_u32 s0, s0, $symbol@{gotpc}rel32@lo
3237 // s_addc_u32 s1, s1, $symbol@{gotpc}rel32@hi
3238 //
3239 // s_getpc_b64 returns the address of the s_add_u32 instruction and then
3240 // fixups or relocations are emitted to replace $symbol@*@lo and
3241 // $symbol@*@hi with lower 32 bits and higher 32 bits of a literal constant,
3242 // which is a 64-bit pc-relative offset from the encoding of the $symbol
3243 // operand to the global variable.
3244
3246
3247 Register PCReg = PtrTy.getSizeInBits() != 32 ? DstReg :
3248 B.getMRI()->createGenericVirtualRegister(ConstPtrTy);
3249
3250 if (ST.has64BitLiterals()) {
3251 assert(GAFlags != SIInstrInfo::MO_NONE);
3252
3254 B.buildInstr(AMDGPU::SI_PC_ADD_REL_OFFSET64).addDef(PCReg);
3255 MIB.addGlobalAddress(GV, Offset, GAFlags + 2);
3256 } else {
3258 B.buildInstr(AMDGPU::SI_PC_ADD_REL_OFFSET).addDef(PCReg);
3259
3260 MIB.addGlobalAddress(GV, Offset, GAFlags);
3261 if (GAFlags == SIInstrInfo::MO_NONE)
3262 MIB.addImm(0);
3263 else
3264 MIB.addGlobalAddress(GV, Offset, GAFlags + 1);
3265 }
3266
3267 if (!B.getMRI()->getRegClassOrNull(PCReg))
3268 B.getMRI()->setRegClass(PCReg, &AMDGPU::SReg_64RegClass);
3269
3270 if (PtrTy.getSizeInBits() == 32)
3271 B.buildExtract(DstReg, PCReg, 0);
3272 return true;
3273}
3274
3275// Emit a ABS32_LO / ABS32_HI relocation stub.
3277 Register DstReg, LLT PtrTy, MachineIRBuilder &B, const GlobalValue *GV,
3278 MachineRegisterInfo &MRI) const {
3279 bool RequiresHighHalf = PtrTy.getSizeInBits() != 32;
3280
3281 if (RequiresHighHalf && ST.has64BitLiterals()) {
3282 if (!MRI.getRegClassOrNull(DstReg))
3283 MRI.setRegClass(DstReg, &AMDGPU::SReg_64RegClass);
3284 B.buildInstr(AMDGPU::S_MOV_B64)
3285 .addDef(DstReg)
3286 .addGlobalAddress(GV, 0, SIInstrInfo::MO_ABS64);
3287 return;
3288 }
3289
3290 LLT I32 = LLT::integer(32);
3291
3292 // Use the destination directly, if and only if we store the lower address
3293 // part only and we don't have a register class being set.
3294 Register AddrLo = !RequiresHighHalf && !MRI.getRegClassOrNull(DstReg)
3295 ? DstReg
3297
3298 if (!MRI.getRegClassOrNull(AddrLo))
3299 MRI.setRegClass(AddrLo, &AMDGPU::SReg_32RegClass);
3300
3301 // Write the lower half.
3302 B.buildInstr(AMDGPU::S_MOV_B32)
3303 .addDef(AddrLo)
3304 .addGlobalAddress(GV, 0, SIInstrInfo::MO_ABS32_LO);
3305
3306 // If required, write the upper half as well.
3307 if (RequiresHighHalf) {
3308 assert(PtrTy.getSizeInBits() == 64 &&
3309 "Must provide a 64-bit pointer type!");
3310
3311 Register AddrHi = MRI.createGenericVirtualRegister(I32);
3312 MRI.setRegClass(AddrHi, &AMDGPU::SReg_32RegClass);
3313
3314 B.buildInstr(AMDGPU::S_MOV_B32)
3315 .addDef(AddrHi)
3316 .addGlobalAddress(GV, 0, SIInstrInfo::MO_ABS32_HI);
3317
3318 // Use the destination directly, if and only if we don't have a register
3319 // class being set.
3320 Register AddrDst = !MRI.getRegClassOrNull(DstReg)
3321 ? DstReg
3323
3324 if (!MRI.getRegClassOrNull(AddrDst))
3325 MRI.setRegClass(AddrDst, &AMDGPU::SReg_64RegClass);
3326
3327 B.buildMergeValues(AddrDst, {AddrLo, AddrHi});
3328
3329 // If we created a new register for the destination, cast the result into
3330 // the final output.
3331 if (AddrDst != DstReg)
3332 B.buildCast(DstReg, AddrDst);
3333 } else if (AddrLo != DstReg) {
3334 // If we created a new register for the destination, cast the result into
3335 // the final output.
3336 B.buildCast(DstReg, AddrLo);
3337 }
3338}
3339
3342 MachineIRBuilder &B) const {
3343 Register DstReg = MI.getOperand(0).getReg();
3344 LLT Ty = MRI.getType(DstReg);
3345 unsigned AS = Ty.getAddressSpace();
3346
3347 const GlobalValue *GV = MI.getOperand(1).getGlobal();
3348 MachineFunction &MF = B.getMF();
3350
3352 if (!MFI->isModuleEntryFunction() &&
3353 GV->getName() != "llvm.amdgcn.module.lds" &&
3355 const Function &Fn = MF.getFunction();
3357 Fn, "local memory global used by non-kernel function",
3358 MI.getDebugLoc(), DS_Warning));
3359
3360 // We currently don't have a way to correctly allocate LDS objects that
3361 // aren't directly associated with a kernel. We do force inlining of
3362 // functions that use local objects. However, if these dead functions are
3363 // not eliminated, we don't want a compile time error. Just emit a warning
3364 // and a trap, since there should be no callable path here.
3365 B.buildTrap();
3366 B.buildUndef(DstReg);
3367 MI.eraseFromParent();
3368 return true;
3369 }
3370
3371 // TODO: We could emit code to handle the initialization somewhere.
3372 // We ignore the initializer for now and legalize it to allow selection.
3373 // The initializer will anyway get errored out during assembly emission.
3374 const SITargetLowering *TLI = ST.getTargetLowering();
3375 if (!TLI->shouldUseLDSConstAddress(GV)) {
3376 MI.getOperand(1).setTargetFlags(SIInstrInfo::MO_ABS32_LO);
3377 return true; // Leave in place;
3378 }
3379
3380 const GlobalVariable &GVar = *cast<GlobalVariable>(GV);
3381 if (AS == AMDGPUAS::LOCAL_ADDRESS && GV->hasExternalLinkage()) {
3382 // HIP uses an unsized array `extern __shared__ T s[]` or similar
3383 // zero-sized type in other languages to declare the dynamic shared
3384 // memory which size is not known at the compile time. They will be
3385 // allocated by the runtime and placed directly after the static
3386 // allocated ones. They all share the same offset.
3387 if (GVar.getGlobalSize(GVar.getDataLayout()) == 0) {
3388 // Adjust alignment for that dynamic shared memory array.
3389 MFI->setDynLDSAlign(MF.getFunction(), GVar);
3390 LLT I32 = LLT::integer(32);
3391 auto Sz = B.buildIntrinsic(Intrinsic::amdgcn_groupstaticsize, {I32});
3392 B.buildIntToPtr(DstReg, Sz);
3393 MI.eraseFromParent();
3394 return true;
3395 }
3396 }
3397
3398 B.buildConstant(DstReg, MFI->allocateLDSGlobal(B.getDataLayout(), GVar));
3399 MI.eraseFromParent();
3400 return true;
3401 }
3402
3403 if (ST.isAmdPalOS() || ST.isMesa3DOS()) {
3404 buildAbsGlobalAddress(DstReg, Ty, B, GV, MRI);
3405 MI.eraseFromParent();
3406 return true;
3407 }
3408
3409 const SITargetLowering *TLI = ST.getTargetLowering();
3410
3411 if (TLI->shouldEmitFixup(GV)) {
3412 buildPCRelGlobalAddress(DstReg, Ty, B, GV, 0);
3413 MI.eraseFromParent();
3414 return true;
3415 }
3416
3417 if (TLI->shouldEmitPCReloc(GV)) {
3418 buildPCRelGlobalAddress(DstReg, Ty, B, GV, 0, SIInstrInfo::MO_REL32);
3419 MI.eraseFromParent();
3420 return true;
3421 }
3422
3424 Register GOTAddr = MRI.createGenericVirtualRegister(PtrTy);
3425
3426 LLT LoadTy = Ty.getSizeInBits() == 32 ? PtrTy : Ty;
3431 LoadTy, Align(8));
3432
3433 buildPCRelGlobalAddress(GOTAddr, PtrTy, B, GV, 0, SIInstrInfo::MO_GOTPCREL32);
3434
3435 if (Ty.getSizeInBits() == 32) {
3436 // Truncate if this is a 32-bit constant address.
3437 auto Load = B.buildLoad(PtrTy, GOTAddr, *GOTMMO);
3438 B.buildExtract(DstReg, Load, 0);
3439 } else
3440 B.buildLoad(DstReg, GOTAddr, *GOTMMO);
3441
3442 MI.eraseFromParent();
3443 return true;
3444}
3445
3447 if (Ty.isVector())
3448 return Ty.changeElementCount(
3449 ElementCount::getFixed(PowerOf2Ceil(Ty.getNumElements())));
3450 return Ty.changeElementSize(PowerOf2Ceil(Ty.getSizeInBits()));
3451}
3452
3454 MachineInstr &MI) const {
3455 MachineIRBuilder &B = Helper.MIRBuilder;
3456 MachineRegisterInfo &MRI = *B.getMRI();
3457 GISelChangeObserver &Observer = Helper.Observer;
3458
3459 Register PtrReg = MI.getOperand(1).getReg();
3460 LLT PtrTy = MRI.getType(PtrReg);
3461 unsigned AddrSpace = PtrTy.getAddressSpace();
3462
3463 if (AddrSpace == AMDGPUAS::CONSTANT_ADDRESS_32BIT) {
3465 auto Cast = B.buildAddrSpaceCast(ConstPtr, PtrReg);
3466 Observer.changingInstr(MI);
3467 MI.getOperand(1).setReg(Cast.getReg(0));
3468 Observer.changedInstr(MI);
3469 return true;
3470 }
3471
3472 if (MI.getOpcode() != AMDGPU::G_LOAD)
3473 return false;
3474
3475 Register ValReg = MI.getOperand(0).getReg();
3476 LLT ValTy = MRI.getType(ValReg);
3477
3478 if (hasBufferRsrcWorkaround(ValTy)) {
3479 Observer.changingInstr(MI);
3480 castBufferRsrcFromV4I32(MI, B, MRI, 0);
3481 Observer.changedInstr(MI);
3482 return true;
3483 }
3484
3485 MachineMemOperand *MMO = *MI.memoperands_begin();
3486 const unsigned ValSize = ValTy.getSizeInBits();
3487 const LLT MemTy = MMO->getMemoryType();
3488 const Align MemAlign = MMO->getAlign();
3489 const unsigned MemSize = MemTy.getSizeInBits();
3490 const uint64_t AlignInBits = 8 * MemAlign.value();
3491
3492 // Widen non-power-of-2 loads to the alignment if needed
3493 if (shouldWidenLoad(ST, MemTy, AlignInBits, AddrSpace, MI.getOpcode())) {
3494 const unsigned WideMemSize = PowerOf2Ceil(MemSize);
3495
3496 // This was already the correct extending load result type, so just adjust
3497 // the memory type.
3498 if (WideMemSize == ValSize) {
3499 MachineFunction &MF = B.getMF();
3500
3501 MachineMemOperand *WideMMO =
3502 MF.getMachineMemOperand(MMO, 0, WideMemSize / 8);
3503 Observer.changingInstr(MI);
3504 MI.setMemRefs(MF, {WideMMO});
3505 Observer.changedInstr(MI);
3506 return true;
3507 }
3508
3509 // Don't bother handling edge case that should probably never be produced.
3510 if (ValSize > WideMemSize)
3511 return false;
3512
3513 LLT WideTy = widenToNextPowerOf2(ValTy);
3514
3515 Register WideLoad;
3516 if (!WideTy.isVector()) {
3517 WideLoad = B.buildLoadFromOffset(WideTy, PtrReg, *MMO, 0).getReg(0);
3518 B.buildTrunc(ValReg, WideLoad).getReg(0);
3519 } else {
3520 // Extract the subvector.
3521
3522 if (isRegisterType(ST, ValTy)) {
3523 // If this a case where G_EXTRACT is legal, use it.
3524 // (e.g. <3 x i32> -> <4 x i32>)
3525 WideLoad = B.buildLoadFromOffset(WideTy, PtrReg, *MMO, 0).getReg(0);
3526 B.buildExtract(ValReg, WideLoad, 0);
3527 } else {
3528 // For cases where the widened type isn't a nice register value, unmerge
3529 // from a widened register (e.g. <3 x i16> -> <4 x i16>)
3530 WideLoad = B.buildLoadFromOffset(WideTy, PtrReg, *MMO, 0).getReg(0);
3531 B.buildDeleteTrailingVectorElements(ValReg, WideLoad);
3532 }
3533 }
3534
3535 MI.eraseFromParent();
3536 return true;
3537 }
3538
3539 return false;
3540}
3541
3543 MachineInstr &MI) const {
3544 MachineIRBuilder &B = Helper.MIRBuilder;
3545 MachineRegisterInfo &MRI = *B.getMRI();
3546 GISelChangeObserver &Observer = Helper.Observer;
3547
3548 Register DataReg = MI.getOperand(0).getReg();
3549 LLT DataTy = MRI.getType(DataReg);
3550
3551 if (hasBufferRsrcWorkaround(DataTy)) {
3552 Observer.changingInstr(MI);
3554 Observer.changedInstr(MI);
3555 return true;
3556 }
3557 return false;
3558}
3559
3562 MachineIRBuilder &B) const {
3563 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
3564 assert(Ty.isScalar());
3565
3566 MachineFunction &MF = B.getMF();
3568
3569 // TODO: Always legal with future ftz flag.
3570 // TODO: Type is expected to be LLT::float32()/LLT::float16()
3571 // FIXME: Do we need just output?
3572 if (Ty == F32 &&
3574 return true;
3575 if (Ty == F16 &&
3577 return true;
3578
3579 MachineIRBuilder HelperBuilder(MI);
3580 GISelObserverWrapper DummyObserver;
3581 LegalizerHelper Helper(MF, DummyObserver, HelperBuilder);
3582 return Helper.lowerFMad(MI) == LegalizerHelper::Legalized;
3583}
3584
3587 Register DstReg = MI.getOperand(0).getReg();
3588 Register PtrReg = MI.getOperand(1).getReg();
3589 Register CmpVal = MI.getOperand(2).getReg();
3590 Register NewVal = MI.getOperand(3).getReg();
3591
3593 "this should not have been custom lowered");
3594
3595 LLT ValTy = MRI.getType(CmpVal);
3596 LLT VecTy = LLT::fixed_vector(2, ValTy);
3597
3598 Register PackedVal = B.buildBuildVector(VecTy, { NewVal, CmpVal }).getReg(0);
3599
3600 B.buildInstr(AMDGPU::G_AMDGPU_ATOMIC_CMPXCHG)
3601 .addDef(DstReg)
3602 .addUse(PtrReg)
3603 .addUse(PackedVal)
3604 .setMemRefs(MI.memoperands());
3605
3606 MI.eraseFromParent();
3607 return true;
3608}
3609
3610/// Return true if it's known that \p Src can never be an f32 denormal value.
3612 Register Src) {
3613 const MachineInstr *DefMI = MRI.getVRegDef(Src);
3614 switch (DefMI->getOpcode()) {
3615 case TargetOpcode::G_INTRINSIC: {
3617 case Intrinsic::amdgcn_frexp_mant:
3618 case Intrinsic::amdgcn_log:
3619 case Intrinsic::amdgcn_log_clamp:
3620 case Intrinsic::amdgcn_exp2:
3621 case Intrinsic::amdgcn_sqrt:
3622 return true;
3623 default:
3624 break;
3625 }
3626
3627 break;
3628 }
3629 case TargetOpcode::G_FSQRT:
3630 return true;
3631 case TargetOpcode::G_FFREXP: {
3632 if (DefMI->getOperand(0).getReg() == Src)
3633 return true;
3634 break;
3635 }
3636 case TargetOpcode::G_FPEXT: {
3637 return MRI.getType(DefMI->getOperand(1).getReg()) == F16;
3638 }
3639 default:
3640 return false;
3641 }
3642
3643 return false;
3644}
3645
3646static bool allowApproxFunc(const MachineFunction &MF, unsigned Flags) {
3647 return Flags & MachineInstr::FmAfn;
3648}
3649
3651 unsigned Flags) {
3652 return !valueIsKnownNeverF32Denorm(MF.getRegInfo(), Src) &&
3655}
3656
3657std::pair<Register, Register>
3659 unsigned Flags) const {
3660 if (!needsDenormHandlingF32(B.getMF(), Src, Flags))
3661 return {};
3662
3663 auto SmallestNormal = B.buildFConstant(
3665 auto IsLtSmallestNormal =
3666 B.buildFCmp(CmpInst::FCMP_OLT, LLT::scalar(1), Src, SmallestNormal);
3667
3668 auto Scale32 = B.buildFConstant(F32, 0x1.0p+32);
3669 auto One = B.buildFConstant(F32, 1.0);
3670 auto ScaleFactor =
3671 B.buildSelect(F32, IsLtSmallestNormal, Scale32, One, Flags);
3672 auto ScaledInput = B.buildFMul(F32, Src, ScaleFactor, Flags);
3673
3674 return {ScaledInput.getReg(0), IsLtSmallestNormal.getReg(0)};
3675}
3676
3678 MachineIRBuilder &B) const {
3679 // v_log_f32 is good enough for OpenCL, except it doesn't handle denormals.
3680 // If we have to handle denormals, scale up the input and adjust the result.
3681
3682 // scaled = x * (is_denormal ? 0x1.0p+32 : 1.0)
3683 // log2 = amdgpu_log2 - (is_denormal ? 32.0 : 0.0)
3684
3685 Register Dst = MI.getOperand(0).getReg();
3686 Register Src = MI.getOperand(1).getReg();
3687 LLT Ty = B.getMRI()->getType(Dst);
3688 unsigned Flags = MI.getFlags();
3689
3690 if (Ty == F16) {
3691 // Nothing in half is a denormal when promoted to f32.
3692 auto Ext = B.buildFPExt(F32, Src, Flags);
3693 auto Log2 = B.buildIntrinsic(Intrinsic::amdgcn_log, {F32})
3694 .addUse(Ext.getReg(0))
3695 .setMIFlags(Flags);
3696 B.buildFPTrunc(Dst, Log2, Flags);
3697 MI.eraseFromParent();
3698 return true;
3699 }
3700
3701 assert(Ty == F32);
3702
3703 auto [ScaledInput, IsLtSmallestNormal] = getScaledLogInput(B, Src, Flags);
3704 if (!ScaledInput) {
3705 B.buildIntrinsic(Intrinsic::amdgcn_log, {MI.getOperand(0)})
3706 .addUse(Src)
3707 .setMIFlags(Flags);
3708 MI.eraseFromParent();
3709 return true;
3710 }
3711
3712 auto Log2 = B.buildIntrinsic(Intrinsic::amdgcn_log, {Ty})
3713 .addUse(ScaledInput)
3714 .setMIFlags(Flags);
3715
3716 auto ThirtyTwo = B.buildFConstant(Ty, 32.0);
3717 auto Zero = B.buildFConstant(Ty, 0.0);
3718 auto ResultOffset =
3719 B.buildSelect(Ty, IsLtSmallestNormal, ThirtyTwo, Zero, Flags);
3720 B.buildFSub(Dst, Log2, ResultOffset, Flags);
3721
3722 MI.eraseFromParent();
3723 return true;
3724}
3725
3727 Register Z, unsigned Flags) {
3728 auto FMul = B.buildFMul(Ty, X, Y, Flags);
3729 return B.buildFAdd(Ty, FMul, Z, Flags).getReg(0);
3730}
3731
3733 MachineIRBuilder &B) const {
3734 const bool IsLog10 = MI.getOpcode() == TargetOpcode::G_FLOG10;
3735 assert(IsLog10 || MI.getOpcode() == TargetOpcode::G_FLOG);
3736
3737 MachineRegisterInfo &MRI = *B.getMRI();
3738 Register Dst = MI.getOperand(0).getReg();
3739 Register X = MI.getOperand(1).getReg();
3740 unsigned Flags = MI.getFlags();
3741 const LLT Ty = MRI.getType(X);
3742
3743 if (Ty == F16 || MI.getFlag(MachineInstr::FmAfn)) {
3744 // TODO: The direct f16 path is 1.79 ulp for f16. This should be used
3745 // depending on !fpmath metadata.
3746 bool PromoteToF32 =
3747 Ty == F16 && (!MI.getFlag(MachineInstr::FmAfn) || !ST.has16BitInsts());
3748 if (PromoteToF32) {
3750 auto PromoteSrc = B.buildFPExt(F32, X, Flags);
3751 legalizeFlogUnsafe(B, LogVal, PromoteSrc.getReg(0), IsLog10, Flags);
3752 B.buildFPTrunc(Dst, LogVal, Flags);
3753 } else {
3754 legalizeFlogUnsafe(B, Dst, X, IsLog10, Flags);
3755 }
3756
3757 MI.eraseFromParent();
3758 return true;
3759 }
3760
3761 auto [ScaledInput, IsScaled] = getScaledLogInput(B, X, Flags);
3762 if (ScaledInput)
3763 X = ScaledInput;
3764
3765 auto Y =
3766 B.buildIntrinsic(Intrinsic::amdgcn_log, {Ty}).addUse(X).setMIFlags(Flags);
3767
3768 Register R;
3769 if (ST.hasFastFMAF32()) {
3770 // c+cc are ln(2)/ln(10) to more than 49 bits
3771 const float c_log10 = 0x1.344134p-2f;
3772 const float cc_log10 = 0x1.09f79ep-26f;
3773
3774 // c + cc is ln(2) to more than 49 bits
3775 const float c_log = 0x1.62e42ep-1f;
3776 const float cc_log = 0x1.efa39ep-25f;
3777
3778 auto C = B.buildFConstant(Ty, IsLog10 ? c_log10 : c_log);
3779 auto CC = B.buildFConstant(Ty, IsLog10 ? cc_log10 : cc_log);
3780 // This adds correction terms for which contraction may lead to an increase
3781 // in the error of the approximation, so disable it.
3782 auto NewFlags = Flags & ~(MachineInstr::FmContract);
3783 R = B.buildFMul(Ty, Y, C, NewFlags).getReg(0);
3784 auto NegR = B.buildFNeg(Ty, R, NewFlags);
3785 auto FMA0 = B.buildFMA(Ty, Y, C, NegR, NewFlags);
3786 auto FMA1 = B.buildFMA(Ty, Y, CC, FMA0, NewFlags);
3787 R = B.buildFAdd(Ty, R, FMA1, NewFlags).getReg(0);
3788 } else {
3789 // ch+ct is ln(2)/ln(10) to more than 36 bits
3790 const float ch_log10 = 0x1.344000p-2f;
3791 const float ct_log10 = 0x1.3509f6p-18f;
3792
3793 // ch + ct is ln(2) to more than 36 bits
3794 const float ch_log = 0x1.62e000p-1f;
3795 const float ct_log = 0x1.0bfbe8p-15f;
3796
3797 auto CH = B.buildFConstant(Ty, IsLog10 ? ch_log10 : ch_log);
3798 auto CT = B.buildFConstant(Ty, IsLog10 ? ct_log10 : ct_log);
3799
3800 const LLT I32 = LLT::integer(32);
3801 auto YInt = B.buildBitcast(I32, Y);
3802 auto MaskConst = B.buildConstant(I32, 0xfffff000);
3803 auto YH = B.buildBitcast(Ty, B.buildAnd(I32, YInt, MaskConst));
3804 auto YT = B.buildFSub(Ty, Y, YH, Flags);
3805 // This adds correction terms for which contraction may lead to an increase
3806 // in the error of the approximation, so disable it.
3807 auto NewFlags = Flags & ~(MachineInstr::FmContract);
3808 auto YTCT = B.buildFMul(Ty, YT, CT, NewFlags);
3809
3810 Register Mad0 =
3811 getMad(B, Ty, YH.getReg(0), CT.getReg(0), YTCT.getReg(0), NewFlags);
3812 Register Mad1 = getMad(B, Ty, YT.getReg(0), CH.getReg(0), Mad0, NewFlags);
3813 R = getMad(B, Ty, YH.getReg(0), CH.getReg(0), Mad1, NewFlags);
3814 }
3815
3816 const bool IsFiniteOnly =
3818
3819 if (!IsFiniteOnly) {
3820 // Expand isfinite(x) => fabs(x) < inf
3821 auto Inf = B.buildFConstant(Ty, APFloat::getInf(APFloat::IEEEsingle()));
3822 auto Fabs = B.buildFAbs(Ty, Y);
3823 auto IsFinite =
3824 B.buildFCmp(CmpInst::FCMP_OLT, LLT::scalar(1), Fabs, Inf, Flags);
3825 R = B.buildSelect(Ty, IsFinite, R, Y, Flags).getReg(0);
3826 }
3827
3828 if (ScaledInput) {
3829 auto Zero = B.buildFConstant(Ty, 0.0);
3830 auto ShiftK =
3831 B.buildFConstant(Ty, IsLog10 ? 0x1.344136p+3f : 0x1.62e430p+4f);
3832 auto Shift = B.buildSelect(Ty, IsScaled, ShiftK, Zero, Flags);
3833 B.buildFSub(Dst, R, Shift, Flags);
3834 } else {
3835 B.buildCopy(Dst, R);
3836 }
3837
3838 MI.eraseFromParent();
3839 return true;
3840}
3841
3843 Register Src, bool IsLog10,
3844 unsigned Flags) const {
3845 const double Log2BaseInverted =
3847
3848 LLT Ty = B.getMRI()->getType(Dst);
3849
3850 if (Ty == F32) {
3851 auto [ScaledInput, IsScaled] = getScaledLogInput(B, Src, Flags);
3852 if (ScaledInput) {
3853 auto LogSrc = B.buildIntrinsic(Intrinsic::amdgcn_log, {Ty})
3854 .addUse(ScaledInput)
3855 .setMIFlags(Flags);
3856 auto ScaledResultOffset = B.buildFConstant(Ty, -32.0 * Log2BaseInverted);
3857 auto Zero = B.buildFConstant(Ty, 0.0);
3858 auto ResultOffset =
3859 B.buildSelect(Ty, IsScaled, ScaledResultOffset, Zero, Flags);
3860 auto Log2Inv = B.buildFConstant(Ty, Log2BaseInverted);
3861
3862 if (ST.hasFastFMAF32())
3863 B.buildFMA(Dst, LogSrc, Log2Inv, ResultOffset, Flags);
3864 else {
3865 auto Mul = B.buildFMul(Ty, LogSrc, Log2Inv, Flags);
3866 B.buildFAdd(Dst, Mul, ResultOffset, Flags);
3867 }
3868
3869 return true;
3870 }
3871 }
3872
3873 auto Log2Operand = Ty == F16 ? B.buildFLog2(Ty, Src, Flags)
3874 : B.buildIntrinsic(Intrinsic::amdgcn_log, {Ty})
3875 .addUse(Src)
3876 .setMIFlags(Flags);
3877 auto Log2BaseInvertedOperand = B.buildFConstant(Ty, Log2BaseInverted);
3878 B.buildFMul(Dst, Log2Operand, Log2BaseInvertedOperand, Flags);
3879 return true;
3880}
3881
3883 MachineIRBuilder &B) const {
3884 // v_exp_f32 is good enough for OpenCL, except it doesn't handle denormals.
3885 // If we have to handle denormals, scale up the input and adjust the result.
3886
3887 Register Dst = MI.getOperand(0).getReg();
3888 Register Src = MI.getOperand(1).getReg();
3889 unsigned Flags = MI.getFlags();
3890 LLT Ty = B.getMRI()->getType(Dst);
3891
3892 if (Ty == F64)
3893 return legalizeFEXPF64(MI, B);
3894
3895 if (Ty == F16) {
3896 // Nothing in half is a denormal when promoted to f32.
3897 auto Ext = B.buildFPExt(F32, Src, Flags);
3898 auto Log2 = B.buildIntrinsic(Intrinsic::amdgcn_exp2, {F32})
3899 .addUse(Ext.getReg(0))
3900 .setMIFlags(Flags);
3901 B.buildFPTrunc(Dst, Log2, Flags);
3902 MI.eraseFromParent();
3903 return true;
3904 }
3905
3906 assert(Ty == F32);
3907
3908 if (!needsDenormHandlingF32(B.getMF(), Src, Flags)) {
3909 B.buildIntrinsic(Intrinsic::amdgcn_exp2, ArrayRef<Register>{Dst})
3910 .addUse(Src)
3911 .setMIFlags(Flags);
3912 MI.eraseFromParent();
3913 return true;
3914 }
3915
3916 // bool needs_scaling = x < -0x1.f80000p+6f;
3917 // v_exp_f32(x + (s ? 0x1.0p+6f : 0.0f)) * (s ? 0x1.0p-64f : 1.0f);
3918
3919 // -nextafter(128.0, -1)
3920 auto RangeCheckConst = B.buildFConstant(Ty, -0x1.f80000p+6f);
3921 auto NeedsScaling = B.buildFCmp(CmpInst::FCMP_OLT, LLT::scalar(1), Src,
3922 RangeCheckConst, Flags);
3923
3924 auto SixtyFour = B.buildFConstant(Ty, 0x1.0p+6f);
3925 auto Zero = B.buildFConstant(Ty, 0.0);
3926 auto AddOffset = B.buildSelect(F32, NeedsScaling, SixtyFour, Zero, Flags);
3927 auto AddInput = B.buildFAdd(F32, Src, AddOffset, Flags);
3928
3929 auto Exp2 = B.buildIntrinsic(Intrinsic::amdgcn_exp2, {Ty})
3930 .addUse(AddInput.getReg(0))
3931 .setMIFlags(Flags);
3932
3933 auto TwoExpNeg64 = B.buildFConstant(Ty, 0x1.0p-64f);
3934 auto One = B.buildFConstant(Ty, 1.0);
3935 auto ResultScale = B.buildSelect(F32, NeedsScaling, TwoExpNeg64, One, Flags);
3936 B.buildFMul(Dst, Exp2, ResultScale, Flags);
3937 MI.eraseFromParent();
3938 return true;
3939}
3940
3942 const SrcOp &Src, unsigned Flags) {
3943 LLT Ty = Dst.getLLTTy(*B.getMRI());
3944
3945 if (Ty == F32) {
3946 return B.buildIntrinsic(Intrinsic::amdgcn_exp2, {Dst})
3947 .addUse(Src.getReg())
3948 .setMIFlags(Flags);
3949 }
3950 return B.buildFExp2(Dst, Src, Flags);
3951}
3952
3954 Register Dst, Register X,
3955 unsigned Flags,
3956 bool IsExp10) const {
3957 LLT Ty = B.getMRI()->getType(X);
3958
3959 // exp(x) -> exp2(M_LOG2E_F * x);
3960 // exp10(x) -> exp2(log2(10) * x);
3961 auto Const = B.buildFConstant(Ty, IsExp10 ? 0x1.a934f0p+1f : numbers::log2e);
3962 auto Mul = B.buildFMul(Ty, X, Const, Flags);
3963 buildExp(B, Dst, Mul, Flags);
3964 return true;
3965}
3966
3968 Register X, unsigned Flags) const {
3969 LLT Ty = B.getMRI()->getType(Dst);
3970
3971 if (Ty != F32 || !needsDenormHandlingF32(B.getMF(), X, Flags)) {
3972 return legalizeFExpUnsafeImpl(B, Dst, X, Flags, /*IsExp10=*/false);
3973 }
3974
3975 auto Threshold = B.buildFConstant(Ty, -0x1.5d58a0p+6f);
3976 auto NeedsScaling =
3977 B.buildFCmp(CmpInst::FCMP_OLT, LLT::scalar(1), X, Threshold, Flags);
3978 auto ScaleOffset = B.buildFConstant(Ty, 0x1.0p+6f);
3979 auto ScaledX = B.buildFAdd(Ty, X, ScaleOffset, Flags);
3980 auto AdjustedX = B.buildSelect(Ty, NeedsScaling, ScaledX, X, Flags);
3981
3982 auto Log2E = B.buildFConstant(Ty, numbers::log2e);
3983 auto ExpInput = B.buildFMul(Ty, AdjustedX, Log2E, Flags);
3984
3985 auto Exp2 = B.buildIntrinsic(Intrinsic::amdgcn_exp2, {Ty})
3986 .addUse(ExpInput.getReg(0))
3987 .setMIFlags(Flags);
3988
3989 auto ResultScaleFactor = B.buildFConstant(Ty, 0x1.969d48p-93f);
3990 auto AdjustedResult = B.buildFMul(Ty, Exp2, ResultScaleFactor, Flags);
3991 B.buildSelect(Dst, NeedsScaling, AdjustedResult, Exp2, Flags);
3992 return true;
3993}
3994
3996 Register Dst, Register X,
3997 unsigned Flags) const {
3998 LLT Ty = B.getMRI()->getType(Dst);
3999
4000 if (Ty != F32 || !needsDenormHandlingF32(B.getMF(), X, Flags)) {
4001 // exp2(x * 0x1.a92000p+1f) * exp2(x * 0x1.4f0978p-11f);
4002 auto K0 = B.buildFConstant(Ty, 0x1.a92000p+1f);
4003 auto K1 = B.buildFConstant(Ty, 0x1.4f0978p-11f);
4004
4005 auto Mul1 = B.buildFMul(Ty, X, K1, Flags);
4006 auto Exp2_1 = buildExp(B, Ty, Mul1, Flags);
4007 auto Mul0 = B.buildFMul(Ty, X, K0, Flags);
4008 auto Exp2_0 = buildExp(B, Ty, Mul0, Flags);
4009 B.buildFMul(Dst, Exp2_0, Exp2_1, Flags);
4010 return true;
4011 }
4012
4013 // bool s = x < -0x1.2f7030p+5f;
4014 // x += s ? 0x1.0p+5f : 0.0f;
4015 // exp10 = exp2(x * 0x1.a92000p+1f) *
4016 // exp2(x * 0x1.4f0978p-11f) *
4017 // (s ? 0x1.9f623ep-107f : 1.0f);
4018
4019 auto Threshold = B.buildFConstant(Ty, -0x1.2f7030p+5f);
4020 auto NeedsScaling =
4021 B.buildFCmp(CmpInst::FCMP_OLT, LLT::scalar(1), X, Threshold);
4022
4023 auto ScaleOffset = B.buildFConstant(Ty, 0x1.0p+5f);
4024 auto ScaledX = B.buildFAdd(Ty, X, ScaleOffset, Flags);
4025 auto AdjustedX = B.buildSelect(Ty, NeedsScaling, ScaledX, X);
4026
4027 auto K0 = B.buildFConstant(Ty, 0x1.a92000p+1f);
4028 auto K1 = B.buildFConstant(Ty, 0x1.4f0978p-11f);
4029
4030 auto Mul1 = B.buildFMul(Ty, AdjustedX, K1, Flags);
4031 auto Exp2_1 = buildExp(B, Ty, Mul1, Flags);
4032 auto Mul0 = B.buildFMul(Ty, AdjustedX, K0, Flags);
4033 auto Exp2_0 = buildExp(B, Ty, Mul0, Flags);
4034
4035 auto MulExps = B.buildFMul(Ty, Exp2_0, Exp2_1, Flags);
4036 auto ResultScaleFactor = B.buildFConstant(Ty, 0x1.9f623ep-107f);
4037 auto AdjustedResult = B.buildFMul(Ty, MulExps, ResultScaleFactor, Flags);
4038
4039 B.buildSelect(Dst, NeedsScaling, AdjustedResult, MulExps);
4040 return true;
4041}
4042
4043// This expansion gives a result slightly better than 1ulp.
4045 MachineIRBuilder &B) const {
4046
4047 Register X = MI.getOperand(1).getReg();
4048 LLT I32 = LLT::integer(32);
4049 LLT S1 = LLT::scalar(1);
4050
4051 // TODO: Check if reassoc is safe. There is an output change in exp2 and
4052 // exp10, which slightly increases ulp.
4053 unsigned Flags = MI.getFlags() & ~MachineInstr::FmReassoc;
4054
4055 Register Dn, F, T;
4056
4057 if (MI.getOpcode() == TargetOpcode::G_FEXP2) {
4058 // Dn = rint(X)
4059 Dn = B.buildFRint(F64, X, Flags).getReg(0);
4060 // F = X - Dn
4061 F = B.buildFSub(F64, X, Dn, Flags).getReg(0);
4062 // T = F*C1 + F*C2
4063 auto C1 = B.buildFConstant(F64, APFloat(0x1.62e42fefa39efp-1));
4064 auto C2 = B.buildFConstant(F64, APFloat(0x1.abc9e3b39803fp-56));
4065 auto Mul2 = B.buildFMul(F64, F, C2, Flags).getReg(0);
4066 T = B.buildFMA(F64, F, C1, Mul2, Flags).getReg(0);
4067
4068 } else if (MI.getOpcode() == TargetOpcode::G_FEXP10) {
4069 auto C1 = B.buildFConstant(F64, APFloat(0x1.a934f0979a371p+1));
4070 auto Mul = B.buildFMul(F64, X, C1, Flags).getReg(0);
4071 Dn = B.buildFRint(F64, Mul, Flags).getReg(0);
4072
4073 auto NegDn = B.buildFNeg(F64, Dn, Flags).getReg(0);
4074 auto C2 = B.buildFConstant(F64, APFloat(-0x1.9dc1da994fd21p-59));
4075 auto C3 = B.buildFConstant(F64, APFloat(0x1.34413509f79ffp-2));
4076 auto Inner = B.buildFMA(F64, NegDn, C3, X, Flags).getReg(0);
4077 F = B.buildFMA(F64, NegDn, C2, Inner, Flags).getReg(0);
4078
4079 auto C4 = B.buildFConstant(F64, APFloat(0x1.26bb1bbb55516p+1));
4080 auto C5 = B.buildFConstant(F64, APFloat(-0x1.f48ad494ea3e9p-53));
4081 auto MulF = B.buildFMul(F64, F, C5, Flags).getReg(0);
4082 T = B.buildFMA(F64, F, C4, MulF, Flags).getReg(0);
4083
4084 } else { // G_FEXP
4085 auto C1 = B.buildFConstant(F64, APFloat(0x1.71547652b82fep+0));
4086 auto Mul = B.buildFMul(F64, X, C1, Flags).getReg(0);
4087 Dn = B.buildFRint(F64, Mul, Flags).getReg(0);
4088
4089 auto NegDn = B.buildFNeg(F64, Dn, Flags).getReg(0);
4090 auto C2 = B.buildFConstant(F64, APFloat(0x1.abc9e3b39803fp-56));
4091 auto C3 = B.buildFConstant(F64, APFloat(0x1.62e42fefa39efp-1));
4092 auto Inner = B.buildFMA(F64, NegDn, C3, X, Flags).getReg(0);
4093 T = B.buildFMA(F64, NegDn, C2, Inner, Flags).getReg(0);
4094 }
4095
4096 // Polynomial chain for P
4097 auto P = B.buildFConstant(F64, 0x1.ade156a5dcb37p-26);
4098 P = B.buildFMA(F64, T, P, B.buildFConstant(F64, 0x1.28af3fca7ab0cp-22),
4099 Flags);
4100 P = B.buildFMA(F64, T, P, B.buildFConstant(F64, 0x1.71dee623fde64p-19),
4101 Flags);
4102 P = B.buildFMA(F64, T, P, B.buildFConstant(F64, 0x1.a01997c89e6b0p-16),
4103 Flags);
4104 P = B.buildFMA(F64, T, P, B.buildFConstant(F64, 0x1.a01a014761f6ep-13),
4105 Flags);
4106 P = B.buildFMA(F64, T, P, B.buildFConstant(F64, 0x1.6c16c1852b7b0p-10),
4107 Flags);
4108 P = B.buildFMA(F64, T, P, B.buildFConstant(F64, 0x1.1111111122322p-7), Flags);
4109 P = B.buildFMA(F64, T, P, B.buildFConstant(F64, 0x1.55555555502a1p-5), Flags);
4110 P = B.buildFMA(F64, T, P, B.buildFConstant(F64, 0x1.5555555555511p-3), Flags);
4111 P = B.buildFMA(F64, T, P, B.buildFConstant(F64, 0x1.000000000000bp-1), Flags);
4112
4113 auto One = B.buildFConstant(F64, 1.0);
4114 P = B.buildFMA(F64, T, P, One, Flags);
4115 P = B.buildFMA(F64, T, P, One, Flags);
4116
4117 // Z = FLDEXP(P, (int)Dn)
4118 auto DnInt = B.buildFPTOSI(I32, Dn);
4119 auto Z = B.buildFLdexp(F64, P, DnInt, Flags);
4120
4121 if (!(Flags & MachineInstr::FmNoInfs)) {
4122 // Overflow guard: if X <= 1024.0 then Z else +inf
4123 auto CondHi = B.buildFCmp(CmpInst::FCMP_ULE, S1, X,
4124 B.buildFConstant(F64, APFloat(1024.0)));
4125 auto PInf = B.buildFConstant(F64, APFloat::getInf(APFloat::IEEEdouble()));
4126 Z = B.buildSelect(F64, CondHi, Z, PInf, Flags);
4127 }
4128
4129 // Underflow guard: if X >= -1075.0 then Z else 0.0
4130 auto CondLo = B.buildFCmp(CmpInst::FCMP_UGE, S1, X,
4131 B.buildFConstant(F64, APFloat(-1075.0)));
4132 auto Zero = B.buildFConstant(F64, APFloat(0.0));
4133 B.buildSelect(MI.getOperand(0).getReg(), CondLo, Z, Zero, Flags);
4134
4135 MI.eraseFromParent();
4136 return true;
4137}
4138
4140 MachineIRBuilder &B) const {
4141 Register Dst = MI.getOperand(0).getReg();
4142 Register X = MI.getOperand(1).getReg();
4143 const unsigned Flags = MI.getFlags();
4144 MachineFunction &MF = B.getMF();
4145 MachineRegisterInfo &MRI = *B.getMRI();
4146 LLT Ty = MRI.getType(Dst);
4147
4148 if (Ty == F64)
4149 return legalizeFEXPF64(MI, B);
4150
4151 const bool IsExp10 = MI.getOpcode() == TargetOpcode::G_FEXP10;
4152
4153 if (Ty == F16) {
4154 // v_exp_f16 (fmul x, log2e)
4155 if (allowApproxFunc(MF, Flags)) {
4156 // TODO: Does this really require fast?
4157 IsExp10 ? legalizeFExp10Unsafe(B, Dst, X, Flags)
4158 : legalizeFExpUnsafe(B, Dst, X, Flags);
4159 MI.eraseFromParent();
4160 return true;
4161 }
4162
4163 // Nothing in half is a denormal when promoted to f32.
4164 //
4165 // exp(f16 x) ->
4166 // fptrunc (v_exp_f32 (fmul (fpext x), log2e))
4167 //
4168 // exp10(f16 x) ->
4169 // fptrunc (v_exp_f32 (fmul (fpext x), log2(10)))
4170 auto Ext = B.buildFPExt(F32, X, Flags);
4172 legalizeFExpUnsafeImpl(B, Lowered, Ext.getReg(0), Flags, IsExp10);
4173 B.buildFPTrunc(Dst, Lowered, Flags);
4174 MI.eraseFromParent();
4175 return true;
4176 }
4177
4178 assert(Ty == F32);
4179
4180 // TODO: Interpret allowApproxFunc as ignoring DAZ. This is currently copying
4181 // library behavior. Also, is known-not-daz source sufficient?
4182 if (allowApproxFunc(MF, Flags)) {
4183 IsExp10 ? legalizeFExp10Unsafe(B, Dst, X, Flags)
4184 : legalizeFExpUnsafe(B, Dst, X, Flags);
4185 MI.eraseFromParent();
4186 return true;
4187 }
4188
4189 // Algorithm:
4190 //
4191 // e^x = 2^(x/ln(2)) = 2^(x*(64/ln(2))/64)
4192 //
4193 // x*(64/ln(2)) = n + f, |f| <= 0.5, n is integer
4194 // n = 64*m + j, 0 <= j < 64
4195 //
4196 // e^x = 2^((64*m + j + f)/64)
4197 // = (2^m) * (2^(j/64)) * 2^(f/64)
4198 // = (2^m) * (2^(j/64)) * e^(f*(ln(2)/64))
4199 //
4200 // f = x*(64/ln(2)) - n
4201 // r = f*(ln(2)/64) = x - n*(ln(2)/64)
4202 //
4203 // e^x = (2^m) * (2^(j/64)) * e^r
4204 //
4205 // (2^(j/64)) is precomputed
4206 //
4207 // e^r = 1 + r + (r^2)/2! + (r^3)/3! + (r^4)/4! + (r^5)/5!
4208 // e^r = 1 + q
4209 //
4210 // q = r + (r^2)/2! + (r^3)/3! + (r^4)/4! + (r^5)/5!
4211 //
4212 // e^x = (2^m) * ( (2^(j/64)) + q*(2^(j/64)) )
4213 const unsigned FlagsNoContract = Flags & ~MachineInstr::FmContract;
4214 Register PH, PL;
4215
4216 if (ST.hasFastFMAF32()) {
4217 const float c_exp = numbers::log2ef;
4218 const float cc_exp = 0x1.4ae0bep-26f; // c+cc are 49 bits
4219 const float c_exp10 = 0x1.a934f0p+1f;
4220 const float cc_exp10 = 0x1.2f346ep-24f;
4221
4222 auto C = B.buildFConstant(Ty, IsExp10 ? c_exp10 : c_exp);
4223 PH = B.buildFMul(Ty, X, C, Flags).getReg(0);
4224 auto NegPH = B.buildFNeg(Ty, PH, Flags);
4225 auto FMA0 = B.buildFMA(Ty, X, C, NegPH, Flags);
4226
4227 auto CC = B.buildFConstant(Ty, IsExp10 ? cc_exp10 : cc_exp);
4228 PL = B.buildFMA(Ty, X, CC, FMA0, Flags).getReg(0);
4229 } else {
4230 const float ch_exp = 0x1.714000p+0f;
4231 const float cl_exp = 0x1.47652ap-12f; // ch + cl are 36 bits
4232
4233 const float ch_exp10 = 0x1.a92000p+1f;
4234 const float cl_exp10 = 0x1.4f0978p-11f;
4235
4236 const LLT I32 = LLT::integer(32);
4237 auto XInt = B.buildBitcast(I32, X);
4238 auto MaskConst = B.buildConstant(I32, 0xfffff000);
4239 auto XH = B.buildBitcast(Ty, B.buildAnd(I32, XInt, MaskConst));
4240 auto XL = B.buildFSub(Ty, X, XH, Flags);
4241
4242 auto CH = B.buildFConstant(Ty, IsExp10 ? ch_exp10 : ch_exp);
4243 PH = B.buildFMul(Ty, XH, CH, Flags).getReg(0);
4244
4245 auto CL = B.buildFConstant(Ty, IsExp10 ? cl_exp10 : cl_exp);
4246 auto XLCL = B.buildFMul(Ty, XL, CL, Flags);
4247
4248 Register Mad0 =
4249 getMad(B, Ty, XL.getReg(0), CH.getReg(0), XLCL.getReg(0), Flags);
4250 PL = getMad(B, Ty, XH.getReg(0), CL.getReg(0), Mad0, Flags);
4251 }
4252
4253 auto E = B.buildIntrinsicRoundeven(Ty, PH, Flags);
4254
4255 // It is unsafe to contract this fsub into the PH multiply.
4256 auto PHSubE = B.buildFSub(Ty, PH, E, FlagsNoContract);
4257 auto A = B.buildFAdd(Ty, PHSubE, PL, Flags);
4258 const LLT I32 = LLT::integer(32);
4259 auto IntE = B.buildFPTOSI(I32, E);
4260
4261 auto Exp2 = B.buildIntrinsic(Intrinsic::amdgcn_exp2, {Ty})
4262 .addUse(A.getReg(0))
4263 .setMIFlags(Flags);
4264 auto R = B.buildFLdexp(Ty, Exp2, IntE, Flags);
4265
4266 auto UnderflowCheckConst =
4267 B.buildFConstant(Ty, IsExp10 ? -0x1.66d3e8p+5f : -0x1.9d1da0p+6f);
4268 auto Zero = B.buildFConstant(Ty, 0.0);
4269 auto Underflow =
4270 B.buildFCmp(CmpInst::FCMP_OLT, LLT::scalar(1), X, UnderflowCheckConst);
4271
4272 R = B.buildSelect(Ty, Underflow, Zero, R);
4273
4274 if (!(Flags & MachineInstr::FmNoInfs)) {
4275 auto OverflowCheckConst =
4276 B.buildFConstant(Ty, IsExp10 ? 0x1.344136p+5f : 0x1.62e430p+6f);
4277
4278 auto Overflow =
4279 B.buildFCmp(CmpInst::FCMP_OGT, LLT::scalar(1), X, OverflowCheckConst);
4280 auto Inf = B.buildFConstant(Ty, APFloat::getInf(APFloat::IEEEsingle()));
4281 R = B.buildSelect(Ty, Overflow, Inf, R, Flags);
4282 }
4283
4284 B.buildCopy(Dst, R);
4285 MI.eraseFromParent();
4286 return true;
4287}
4288
4290 MachineIRBuilder &B) const {
4291 Register Dst = MI.getOperand(0).getReg();
4292 Register Src0 = MI.getOperand(1).getReg();
4293 Register Src1 = MI.getOperand(2).getReg();
4294 unsigned Flags = MI.getFlags();
4295 LLT Ty = B.getMRI()->getType(Dst);
4296
4297 if (Ty == F32) {
4298 auto Log = B.buildFLog2(F32, Src0, Flags);
4299 auto Mul = B.buildIntrinsic(Intrinsic::amdgcn_fmul_legacy, {F32})
4300 .addUse(Log.getReg(0))
4301 .addUse(Src1)
4302 .setMIFlags(Flags);
4303 B.buildFExp2(Dst, Mul, Flags);
4304 } else if (Ty == F16) {
4305 // There's no f16 fmul_legacy, so we need to convert for it.
4306 auto Log = B.buildFLog2(F16, Src0, Flags);
4307 auto Ext0 = B.buildFPExt(F32, Log, Flags);
4308 auto Ext1 = B.buildFPExt(F32, Src1, Flags);
4309 auto Mul = B.buildIntrinsic(Intrinsic::amdgcn_fmul_legacy, {F32})
4310 .addUse(Ext0.getReg(0))
4311 .addUse(Ext1.getReg(0))
4312 .setMIFlags(Flags);
4313 // The f32 product is finite whenever the original fpow was, but it can
4314 // still be outside the f16 range. Drop ninf from the truncation and from
4315 // the exp2, since neither can assume a finite value here.
4316 unsigned FlagsNoNInf = Flags & ~MachineInstr::FmNoInfs;
4317 B.buildFExp2(Dst, B.buildFPTrunc(F16, Mul, FlagsNoNInf), FlagsNoNInf);
4318 } else
4319 return false;
4320
4321 MI.eraseFromParent();
4322 return true;
4323}
4324
4325// Find a source register, ignoring any possible source modifiers.
4327 Register ModSrc = OrigSrc;
4328 if (MachineInstr *SrcFNeg = getOpcodeDef(AMDGPU::G_FNEG, ModSrc, MRI)) {
4329 ModSrc = SrcFNeg->getOperand(1).getReg();
4330 if (MachineInstr *SrcFAbs = getOpcodeDef(AMDGPU::G_FABS, ModSrc, MRI))
4331 ModSrc = SrcFAbs->getOperand(1).getReg();
4332 } else if (MachineInstr *SrcFAbs = getOpcodeDef(AMDGPU::G_FABS, ModSrc, MRI))
4333 ModSrc = SrcFAbs->getOperand(1).getReg();
4334 return ModSrc;
4335}
4336
4339 MachineIRBuilder &B) const {
4340
4341 const LLT S1 = LLT::scalar(1);
4342 Register Dst = MI.getOperand(0).getReg();
4343 Register OrigSrc = MI.getOperand(1).getReg();
4344 unsigned Flags = MI.getFlags();
4345 assert(ST.hasFractBug() && MRI.getType(Dst) == F64 &&
4346 "this should not have been custom lowered");
4347
4348 // V_FRACT is buggy on SI, so the F32 version is never used and (x-floor(x))
4349 // is used instead. However, SI doesn't have V_FLOOR_F64, so the most
4350 // efficient way to implement it is using V_FRACT_F64. The workaround for the
4351 // V_FRACT bug is:
4352 // fract(x) = isnan(x) ? x : min(V_FRACT(x), 0.99999999999999999)
4353 //
4354 // Convert floor(x) to (x - fract(x))
4355
4356 auto Fract = B.buildIntrinsic(Intrinsic::amdgcn_fract, {F64})
4357 .addUse(OrigSrc)
4358 .setMIFlags(Flags);
4359
4360 // Give source modifier matching some assistance before obscuring a foldable
4361 // pattern.
4362
4363 // TODO: We can avoid the neg on the fract? The input sign to fract
4364 // shouldn't matter?
4365 Register ModSrc = stripAnySourceMods(OrigSrc, MRI);
4366
4367 auto Const =
4368 B.buildFConstant(F64, llvm::bit_cast<double>(0x3fefffffffffffff));
4369
4371
4372 // We don't need to concern ourselves with the snan handling difference, so
4373 // use the one which will directly select.
4374 const SIMachineFunctionInfo *MFI = B.getMF().getInfo<SIMachineFunctionInfo>();
4375 if (MFI->getMode().IEEE)
4376 B.buildFMinNumIEEE(Min, Fract, Const, Flags);
4377 else
4378 B.buildFMinNum(Min, Fract, Const, Flags);
4379
4380 Register CorrectedFract = Min;
4381 if (!MI.getFlag(MachineInstr::FmNoNans)) {
4382 auto IsNan = B.buildFCmp(CmpInst::FCMP_ORD, S1, ModSrc, ModSrc, Flags);
4383 CorrectedFract = B.buildSelect(F64, IsNan, ModSrc, Min, Flags).getReg(0);
4384 }
4385
4386 auto NegFract = B.buildFNeg(F64, CorrectedFract, Flags);
4387 B.buildFAdd(Dst, OrigSrc, NegFract, Flags);
4388
4389 MI.eraseFromParent();
4390 return true;
4391}
4392
4393// Turn an illegal packed v2i16/v2f16 build vector into bit operations.
4394// TODO: This should probably be a bitcast action in LegalizerHelper.
4397 Register Dst = MI.getOperand(0).getReg();
4398 const LLT I32 = LLT::integer(32);
4399 const LLT I16 = LLT::integer(16);
4400 assert(MRI.getType(Dst).isVector() &&
4401 MRI.getType(Dst).getNumElements() == 2 &&
4402 MRI.getType(Dst).getScalarSizeInBits() == 16);
4403
4404 Register Src0 = MI.getOperand(1).getReg();
4405 Register Src1 = MI.getOperand(2).getReg();
4406
4407 if (MI.getOpcode() == AMDGPU::G_BUILD_VECTOR_TRUNC) {
4408 assert(MRI.getType(Src0) == I32);
4409 Src0 = B.buildTrunc(I16, MI.getOperand(1).getReg()).getReg(0);
4410 Src1 = B.buildTrunc(I16, MI.getOperand(2).getReg()).getReg(0);
4411 }
4412
4413 auto Merge = B.buildMergeLikeInstr(I32, {Src0, Src1});
4414 B.buildBitcast(Dst, Merge);
4415
4416 MI.eraseFromParent();
4417 return true;
4418}
4419
4420// Build a big integer multiply or multiply-add using MAD_64_32 instructions.
4421//
4422// Source and accumulation registers must all be 32-bits.
4423//
4424// TODO: When the multiply is uniform, we should produce a code sequence
4425// that is better suited to instruction selection on the SALU. Instead of
4426// the outer loop going over parts of the result, the outer loop should go
4427// over parts of one of the factors. This should result in instruction
4428// selection that makes full use of S_ADDC_U32 instructions.
4431 ArrayRef<Register> Src0,
4432 ArrayRef<Register> Src1,
4433 bool UsePartialMad64_32,
4434 bool SeparateOddAlignedProducts) const {
4435 // Use (possibly empty) vectors of S1 registers to represent the set of
4436 // carries from one pair of positions to the next.
4437 using Carry = SmallVector<Register, 2>;
4438
4439 MachineIRBuilder &B = Helper.MIRBuilder;
4440 GISelValueTracking &VT = *Helper.getValueTracking();
4441
4442 const LLT S1 = LLT::scalar(1);
4443 const LLT I32 = LLT::integer(32);
4444 const LLT I64 = LLT::integer(64);
4445
4446 Register Zero32;
4447 Register Zero64;
4448
4449 auto getZero32 = [&]() -> Register {
4450 if (!Zero32)
4451 Zero32 = B.buildConstant(I32, 0).getReg(0);
4452 return Zero32;
4453 };
4454 auto getZero64 = [&]() -> Register {
4455 if (!Zero64)
4456 Zero64 = B.buildConstant(I64, 0).getReg(0);
4457 return Zero64;
4458 };
4459
4460 SmallVector<bool, 2> Src0KnownZeros, Src1KnownZeros;
4461 for (unsigned i = 0; i < Src0.size(); ++i) {
4462 Src0KnownZeros.push_back(VT.getKnownBits(Src0[i]).isZero());
4463 Src1KnownZeros.push_back(VT.getKnownBits(Src1[i]).isZero());
4464 }
4465
4466 // Merge the given carries into the 32-bit LocalAccum, which is modified
4467 // in-place.
4468 //
4469 // Returns the carry-out, which is a single S1 register or null.
4470 auto mergeCarry =
4471 [&](Register &LocalAccum, const Carry &CarryIn) -> Register {
4472 if (CarryIn.empty())
4473 return Register();
4474
4475 bool HaveCarryOut = true;
4476 Register CarryAccum;
4477 if (CarryIn.size() == 1) {
4478 if (!LocalAccum) {
4479 LocalAccum = B.buildZExt(I32, CarryIn[0]).getReg(0);
4480 return Register();
4481 }
4482
4483 CarryAccum = getZero32();
4484 } else {
4485 CarryAccum = B.buildZExt(I32, CarryIn[0]).getReg(0);
4486 for (unsigned i = 1; i + 1 < CarryIn.size(); ++i) {
4487 CarryAccum =
4488 B.buildUAdde(I32, S1, CarryAccum, getZero32(), CarryIn[i])
4489 .getReg(0);
4490 }
4491
4492 if (!LocalAccum) {
4493 LocalAccum = getZero32();
4494 HaveCarryOut = false;
4495 }
4496 }
4497
4498 auto Add =
4499 B.buildUAdde(I32, S1, CarryAccum, LocalAccum, CarryIn.back());
4500 LocalAccum = Add.getReg(0);
4501 return HaveCarryOut ? Add.getReg(1) : Register();
4502 };
4503
4504 // Build a multiply-add chain to compute
4505 //
4506 // LocalAccum + (partial products at DstIndex)
4507 // + (opportunistic subset of CarryIn)
4508 //
4509 // LocalAccum is an array of one or two 32-bit registers that are updated
4510 // in-place. The incoming registers may be null.
4511 //
4512 // In some edge cases, carry-ins can be consumed "for free". In that case,
4513 // the consumed carry bits are removed from CarryIn in-place.
4514 auto buildMadChain =
4515 [&](MutableArrayRef<Register> LocalAccum, unsigned DstIndex, Carry &CarryIn)
4516 -> Carry {
4517 assert((DstIndex + 1 < Accum.size() && LocalAccum.size() == 2) ||
4518 (DstIndex + 1 >= Accum.size() && LocalAccum.size() == 1));
4519
4520 Carry CarryOut;
4521 unsigned j0 = 0;
4522
4523 // Use plain 32-bit multiplication for the most significant part of the
4524 // result by default.
4525 if (LocalAccum.size() == 1 &&
4526 (!UsePartialMad64_32 || !CarryIn.empty())) {
4527 do {
4528 // Skip multiplication if one of the operands is 0
4529 unsigned j1 = DstIndex - j0;
4530 if (Src0KnownZeros[j0] || Src1KnownZeros[j1]) {
4531 ++j0;
4532 continue;
4533 }
4534 auto Mul = B.buildMul(I32, Src0[j0], Src1[j1]);
4535 if (!LocalAccum[0] || VT.getKnownBits(LocalAccum[0]).isZero()) {
4536 LocalAccum[0] = Mul.getReg(0);
4537 } else {
4538 if (CarryIn.empty()) {
4539 LocalAccum[0] = B.buildAdd(I32, LocalAccum[0], Mul).getReg(0);
4540 } else {
4541 LocalAccum[0] =
4542 B.buildUAdde(I32, S1, LocalAccum[0], Mul, CarryIn.back())
4543 .getReg(0);
4544 CarryIn.pop_back();
4545 }
4546 }
4547 ++j0;
4548 } while (j0 <= DstIndex && (!UsePartialMad64_32 || !CarryIn.empty()));
4549 }
4550
4551 // Build full 64-bit multiplies.
4552 if (j0 <= DstIndex) {
4553 bool HaveSmallAccum = false;
4554 Register Tmp;
4555
4556 if (LocalAccum[0]) {
4557 if (LocalAccum.size() == 1) {
4558 Tmp = B.buildAnyExt(I64, LocalAccum[0]).getReg(0);
4559 HaveSmallAccum = true;
4560 } else if (LocalAccum[1]) {
4561 Tmp = B.buildMergeLikeInstr(I64, LocalAccum).getReg(0);
4562 HaveSmallAccum = false;
4563 } else {
4564 Tmp = B.buildZExt(I64, LocalAccum[0]).getReg(0);
4565 HaveSmallAccum = true;
4566 }
4567 } else {
4568 assert(LocalAccum.size() == 1 || !LocalAccum[1]);
4569 Tmp = getZero64();
4570 HaveSmallAccum = true;
4571 }
4572
4573 do {
4574 unsigned j1 = DstIndex - j0;
4575 if (Src0KnownZeros[j0] || Src1KnownZeros[j1]) {
4576 ++j0;
4577 continue;
4578 }
4579 auto Mad = B.buildInstr(AMDGPU::G_AMDGPU_MAD_U64_U32, {I64, S1},
4580 {Src0[j0], Src1[j1], Tmp});
4581 Tmp = Mad.getReg(0);
4582 if (!HaveSmallAccum)
4583 CarryOut.push_back(Mad.getReg(1));
4584 HaveSmallAccum = false;
4585
4586 ++j0;
4587 } while (j0 <= DstIndex);
4588
4589 auto Unmerge = B.buildUnmerge(I32, Tmp);
4590 LocalAccum[0] = Unmerge.getReg(0);
4591 if (LocalAccum.size() > 1)
4592 LocalAccum[1] = Unmerge.getReg(1);
4593 }
4594
4595 // Every partial product contributing to this destination index was
4596 // skipped because an operand half is known zero, so nothing has been
4597 // accumulated and the result is zero.
4598 if (!LocalAccum[0])
4599 LocalAccum[0] = getZero32();
4600
4601 // A second element is only ever requested when the full 64-bit multiply
4602 // block above runs, which always writes it.
4603 assert((LocalAccum.size() == 1 || LocalAccum[1]) &&
4604 "Uninitialized accumulator part");
4605
4606 return CarryOut;
4607 };
4608
4609 // Outer multiply loop, iterating over destination parts from least
4610 // significant to most significant parts.
4611 //
4612 // The columns of the following diagram correspond to the destination parts
4613 // affected by one iteration of the outer loop (ignoring boundary
4614 // conditions).
4615 //
4616 // Dest index relative to 2 * i: 1 0 -1
4617 // ------
4618 // Carries from previous iteration: e o
4619 // Even-aligned partial product sum: E E .
4620 // Odd-aligned partial product sum: O O
4621 //
4622 // 'o' is OddCarry, 'e' is EvenCarry.
4623 // EE and OO are computed from partial products via buildMadChain and use
4624 // accumulation where possible and appropriate.
4625 //
4626 Register SeparateOddCarry;
4627 Carry EvenCarry;
4628 Carry OddCarry;
4629
4630 for (unsigned i = 0; i <= Accum.size() / 2; ++i) {
4631 Carry OddCarryIn = std::move(OddCarry);
4632 Carry EvenCarryIn = std::move(EvenCarry);
4633 OddCarry.clear();
4634 EvenCarry.clear();
4635
4636 // Partial products at offset 2 * i.
4637 if (2 * i < Accum.size()) {
4638 auto LocalAccum = Accum.drop_front(2 * i).take_front(2);
4639 EvenCarry = buildMadChain(LocalAccum, 2 * i, EvenCarryIn);
4640 }
4641
4642 // Partial products at offset 2 * i - 1.
4643 if (i > 0) {
4644 if (!SeparateOddAlignedProducts) {
4645 auto LocalAccum = Accum.drop_front(2 * i - 1).take_front(2);
4646 OddCarry = buildMadChain(LocalAccum, 2 * i - 1, OddCarryIn);
4647 } else {
4648 bool IsHighest = 2 * i >= Accum.size();
4649 Register SeparateOddOut[2];
4650 auto LocalAccum = MutableArrayRef(SeparateOddOut)
4651 .take_front(IsHighest ? 1 : 2);
4652 OddCarry = buildMadChain(LocalAccum, 2 * i - 1, OddCarryIn);
4653
4655
4656 if (i == 1) {
4657 if (!IsHighest)
4658 Lo = B.buildUAddo(I32, S1, Accum[2 * i - 1], SeparateOddOut[0]);
4659 else
4660 Lo = B.buildAdd(I32, Accum[2 * i - 1], SeparateOddOut[0]);
4661 } else {
4662 Lo = B.buildUAdde(I32, S1, Accum[2 * i - 1], SeparateOddOut[0],
4663 SeparateOddCarry);
4664 }
4665 Accum[2 * i - 1] = Lo->getOperand(0).getReg();
4666
4667 if (!IsHighest) {
4668 auto Hi = B.buildUAdde(I32, S1, Accum[2 * i], SeparateOddOut[1],
4669 Lo->getOperand(1).getReg());
4670 Accum[2 * i] = Hi.getReg(0);
4671 SeparateOddCarry = Hi.getReg(1);
4672 }
4673 }
4674 }
4675
4676 // Add in the carries from the previous iteration
4677 if (i > 0) {
4678 if (Register CarryOut = mergeCarry(Accum[2 * i - 1], OddCarryIn))
4679 EvenCarryIn.push_back(CarryOut);
4680
4681 if (2 * i < Accum.size()) {
4682 if (Register CarryOut = mergeCarry(Accum[2 * i], EvenCarryIn))
4683 OddCarry.push_back(CarryOut);
4684 }
4685 }
4686 }
4687}
4688
4689// Custom narrowing of wide multiplies using wide multiply-add instructions.
4690//
4691// TODO: If the multiply is followed by an addition, we should attempt to
4692// integrate it to make better use of V_MAD_U64_U32's multiply-add capabilities.
4694 MachineInstr &MI) const {
4695 assert(ST.hasMad64_32());
4696 assert(MI.getOpcode() == TargetOpcode::G_MUL);
4697
4698 MachineIRBuilder &B = Helper.MIRBuilder;
4699 MachineRegisterInfo &MRI = *B.getMRI();
4700
4701 Register DstReg = MI.getOperand(0).getReg();
4702 Register Src0 = MI.getOperand(1).getReg();
4703 Register Src1 = MI.getOperand(2).getReg();
4704
4705 LLT Ty = MRI.getType(DstReg);
4706 assert(Ty.isScalar());
4707
4708 unsigned Size = Ty.getSizeInBits();
4709 if (ST.useVMulU64Inst() && Size == 64)
4710 return true;
4711
4712 unsigned NumParts = Size / 32;
4713 assert((Size % 32) == 0);
4714 assert(NumParts >= 2);
4715
4716 // Whether to use MAD_64_32 for partial products whose high half is
4717 // discarded. This avoids some ADD instructions but risks false dependency
4718 // stalls on some subtargets in some cases.
4719 const bool UsePartialMad64_32 = ST.getGeneration() < AMDGPUSubtarget::GFX10;
4720
4721 // Whether to compute odd-aligned partial products separately. This is
4722 // advisable on subtargets where the accumulator of MAD_64_32 must be placed
4723 // in an even-aligned VGPR.
4724 const bool SeparateOddAlignedProducts = ST.hasFullRate64Ops();
4725
4726 LLT I32 = LLT::integer(32);
4727 SmallVector<Register, 2> Src0Parts, Src1Parts;
4728 for (unsigned i = 0; i < NumParts; ++i) {
4729 Src0Parts.push_back(MRI.createGenericVirtualRegister(I32));
4730 Src1Parts.push_back(MRI.createGenericVirtualRegister(I32));
4731 }
4732 B.buildUnmerge(Src0Parts, Src0);
4733 B.buildUnmerge(Src1Parts, Src1);
4734
4735 SmallVector<Register, 2> AccumRegs(NumParts);
4736 buildMultiply(Helper, AccumRegs, Src0Parts, Src1Parts, UsePartialMad64_32,
4737 SeparateOddAlignedProducts);
4738
4739 B.buildMergeLikeInstr(DstReg, AccumRegs);
4740 MI.eraseFromParent();
4741 return true;
4742}
4743
4744// Legalize ctlz/cttz to ffbh/ffbl instead of the default legalization to
4745// ctlz/cttz_zero_poison. This allows us to fix up the result for the zero input
4746// case with a single min instruction instead of a compare+select.
4749 MachineIRBuilder &B) const {
4750 Register Dst = MI.getOperand(0).getReg();
4751 Register Src = MI.getOperand(1).getReg();
4752 LLT DstTy = MRI.getType(Dst);
4753 LLT SrcTy = MRI.getType(Src);
4754
4755 unsigned NewOpc = MI.getOpcode() == AMDGPU::G_CTLZ
4756 ? AMDGPU::G_AMDGPU_FFBH_U32
4757 : AMDGPU::G_AMDGPU_FFBL_B32;
4758 auto Tmp = B.buildInstr(NewOpc, {DstTy}, {Src});
4759 B.buildUMin(Dst, Tmp, B.buildConstant(DstTy, SrcTy.getSizeInBits()));
4760
4761 MI.eraseFromParent();
4762 return true;
4763}
4764
4767 MachineIRBuilder &B) const {
4768 Register Dst = MI.getOperand(0).getReg();
4769 Register Src = MI.getOperand(1).getReg();
4770 LLT SrcTy = MRI.getType(Src);
4771 TypeSize NumBits = SrcTy.getSizeInBits();
4772
4773 assert(NumBits < 32u);
4774
4775 const LLT I32 = LLT::integer(32);
4776 auto ShiftAmt = B.buildConstant(I32, 32u - NumBits);
4777 auto Extend = B.buildAnyExt(I32, {Src}).getReg(0u);
4778 auto Shift = B.buildShl(I32, Extend, ShiftAmt);
4779 auto Ctlz = B.buildInstr(AMDGPU::G_AMDGPU_FFBH_U32, {I32}, {Shift});
4780 B.buildTrunc(Dst, Ctlz);
4781 MI.eraseFromParent();
4782 return true;
4783}
4784
4787 MachineIRBuilder &B) const {
4788 Register Dst = MI.getOperand(0).getReg();
4789 Register Src = MI.getOperand(1).getReg();
4790 LLT SrcTy = MRI.getType(Src);
4791 const LLT I32 = LLT::integer(32);
4792 assert(SrcTy == I32 && "legalizeCTLS only supports i32");
4793 unsigned BitWidth = SrcTy.getSizeInBits();
4794
4795 auto Sffbh = B.buildIntrinsic(Intrinsic::amdgcn_sffbh, {I32}).addUse(Src);
4796 auto Clamped = B.buildUMin(I32, Sffbh, B.buildConstant(I32, BitWidth));
4797 B.buildSub(Dst, Clamped, B.buildConstant(I32, 1));
4798 MI.eraseFromParent();
4799 return true;
4800}
4801
4802// Check that this is a G_XOR x, -1
4803static bool isNot(const MachineRegisterInfo &MRI, const MachineInstr &MI) {
4804 if (MI.getOpcode() != TargetOpcode::G_XOR)
4805 return false;
4806 auto ConstVal = getIConstantVRegSExtVal(MI.getOperand(2).getReg(), MRI);
4807 return ConstVal == -1;
4808}
4809
4810// Return the use branch instruction, otherwise null if the usage is invalid.
4811static MachineInstr *
4813 MachineBasicBlock *&UncondBrTarget, bool &Negated) {
4814 Register CondDef = MI.getOperand(0).getReg();
4815 if (!MRI.hasOneNonDBGUse(CondDef))
4816 return nullptr;
4817
4818 MachineBasicBlock *Parent = MI.getParent();
4819 MachineInstr *UseMI = &*MRI.use_instr_nodbg_begin(CondDef);
4820
4821 if (isNot(MRI, *UseMI)) {
4822 Register NegatedCond = UseMI->getOperand(0).getReg();
4823 if (!MRI.hasOneNonDBGUse(NegatedCond))
4824 return nullptr;
4825
4826 // We're deleting the def of this value, so we need to remove it.
4827 eraseInstr(*UseMI, MRI);
4828
4829 UseMI = &*MRI.use_instr_nodbg_begin(NegatedCond);
4830 Negated = true;
4831 }
4832
4833 if (UseMI->getParent() != Parent || UseMI->getOpcode() != AMDGPU::G_BRCOND)
4834 return nullptr;
4835
4836 // Make sure the cond br is followed by a G_BR, or is the last instruction.
4837 MachineBasicBlock::iterator Next = std::next(UseMI->getIterator());
4838 if (Next == Parent->end()) {
4839 MachineFunction::iterator NextMBB = std::next(Parent->getIterator());
4840 if (NextMBB == Parent->getParent()->end()) // Illegal intrinsic use.
4841 return nullptr;
4842 UncondBrTarget = &*NextMBB;
4843 } else {
4844 if (Next->getOpcode() != AMDGPU::G_BR)
4845 return nullptr;
4846 Br = &*Next;
4847 UncondBrTarget = Br->getOperand(0).getMBB();
4848 }
4849
4850 return UseMI;
4851}
4852
4855 const ArgDescriptor *Arg,
4856 const TargetRegisterClass *ArgRC,
4857 LLT ArgTy) const {
4858 MCRegister SrcReg = Arg->getRegister();
4859 assert(SrcReg.isPhysical() && "Physical register expected");
4860 assert(DstReg.isVirtual() && "Virtual register expected");
4861
4862 Register LiveIn = getFunctionLiveInPhysReg(B.getMF(), B.getTII(), SrcReg,
4863 *ArgRC, B.getDebugLoc(), ArgTy);
4864 if (Arg->isMasked()) {
4865 // TODO: Should we try to emit this once in the entry block?
4866 const LLT I32 = LLT::integer(32);
4867 const unsigned Mask = Arg->getMask();
4868 const unsigned Shift = llvm::countr_zero<unsigned>(Mask);
4869
4870 Register AndMaskSrc = LiveIn;
4871
4872 // TODO: Avoid clearing the high bits if we know workitem id y/z are always
4873 // 0.
4874 if (Shift != 0) {
4875 auto ShiftAmt = B.buildConstant(I32, Shift);
4876 AndMaskSrc = B.buildLShr(I32, LiveIn, ShiftAmt).getReg(0);
4877 }
4878
4879 B.buildAnd(DstReg, AndMaskSrc, B.buildConstant(I32, Mask >> Shift));
4880 } else {
4881 B.buildCopy(DstReg, LiveIn);
4882 }
4883}
4884
4889 AMDGPUFunctionArgInfo::PreloadedValue ClusterWorkGroupIdPV) const {
4890 Register DstReg = MI.getOperand(0).getReg();
4891 if (!ST.hasClusters()) {
4892 if (!loadInputValue(DstReg, B, WorkGroupIdPV))
4893 return false;
4894 MI.eraseFromParent();
4895 return true;
4896 }
4897
4898 // Clusters are supported. Return the global position in the grid. If clusters
4899 // are enabled, WorkGroupIdPV returns the cluster ID not the workgroup ID.
4900
4901 // WorkGroupIdXYZ = ClusterId == 0 ?
4902 // ClusterIdXYZ :
4903 // ClusterIdXYZ * (ClusterMaxIdXYZ + 1) + ClusterWorkGroupIdXYZ
4904 MachineRegisterInfo &MRI = *B.getMRI();
4905 const LLT I32 = LLT::integer(32);
4906 Register ClusterIdXYZ = MRI.createGenericVirtualRegister(I32);
4907 Register ClusterMaxIdXYZ = MRI.createGenericVirtualRegister(I32);
4908 Register ClusterWorkGroupIdXYZ = MRI.createGenericVirtualRegister(I32);
4909 if (!loadInputValue(ClusterIdXYZ, B, WorkGroupIdPV) ||
4910 !loadInputValue(ClusterWorkGroupIdXYZ, B, ClusterWorkGroupIdPV) ||
4911 !loadInputValue(ClusterMaxIdXYZ, B, ClusterMaxIdPV))
4912 return false;
4913
4914 auto One = B.buildConstant(I32, 1);
4915 auto ClusterSizeXYZ = B.buildAdd(I32, ClusterMaxIdXYZ, One);
4916 auto GlobalIdXYZ = B.buildAdd(I32, ClusterWorkGroupIdXYZ,
4917 B.buildMul(I32, ClusterIdXYZ, ClusterSizeXYZ));
4918
4919 const SIMachineFunctionInfo *MFI = B.getMF().getInfo<SIMachineFunctionInfo>();
4920
4921 switch (MFI->getClusterDims().getKind()) {
4924 B.buildCopy(DstReg, GlobalIdXYZ);
4925 MI.eraseFromParent();
4926 return true;
4927 }
4929 B.buildCopy(DstReg, ClusterIdXYZ);
4930 MI.eraseFromParent();
4931 return true;
4932 }
4934 using namespace AMDGPU::Hwreg;
4935 unsigned ClusterIdField = HwregEncoding::encode(ID_IB_STS2, 6, 4);
4936 Register ClusterId = MRI.createGenericVirtualRegister(I32);
4937 MRI.setRegClass(ClusterId, &AMDGPU::SReg_32RegClass);
4938 B.buildInstr(AMDGPU::S_GETREG_B32_const)
4939 .addDef(ClusterId)
4940 .addImm(ClusterIdField);
4941 auto Zero = B.buildConstant(I32, 0);
4942 auto NoClusters =
4943 B.buildICmp(CmpInst::ICMP_EQ, LLT::scalar(1), ClusterId, Zero);
4944 B.buildSelect(DstReg, NoClusters, ClusterIdXYZ, GlobalIdXYZ);
4945 MI.eraseFromParent();
4946 return true;
4947 }
4948 }
4949
4950 llvm_unreachable("nothing should reach here");
4951}
4952
4954 Register DstReg, MachineIRBuilder &B,
4956 const SIMachineFunctionInfo *MFI = B.getMF().getInfo<SIMachineFunctionInfo>();
4957 const ArgDescriptor *Arg = nullptr;
4958 const TargetRegisterClass *ArgRC = nullptr;
4959 LLT ArgTy;
4960
4961 CallingConv::ID CC = B.getMF().getFunction().getCallingConv();
4962 const ArgDescriptor WorkGroupIDX =
4963 ArgDescriptor::createRegister(AMDGPU::TTMP9);
4964 // If GridZ is not programmed in an entry function then the hardware will set
4965 // it to all zeros, so there is no need to mask the GridY value in the low
4966 // order bits.
4967 const ArgDescriptor WorkGroupIDY = ArgDescriptor::createRegister(
4968 AMDGPU::TTMP7,
4969 AMDGPU::isEntryFunctionCC(CC) && !MFI->hasWorkGroupIDZ() ? ~0u : 0xFFFFu);
4970 const ArgDescriptor WorkGroupIDZ =
4971 ArgDescriptor::createRegister(AMDGPU::TTMP7, 0xFFFF0000u);
4972 const ArgDescriptor ClusterWorkGroupIDX =
4973 ArgDescriptor::createRegister(AMDGPU::TTMP6, 0x0000000Fu);
4974 const ArgDescriptor ClusterWorkGroupIDY =
4975 ArgDescriptor::createRegister(AMDGPU::TTMP6, 0x000000F0u);
4976 const ArgDescriptor ClusterWorkGroupIDZ =
4977 ArgDescriptor::createRegister(AMDGPU::TTMP6, 0x00000F00u);
4978 const ArgDescriptor ClusterWorkGroupMaxIDX =
4979 ArgDescriptor::createRegister(AMDGPU::TTMP6, 0x0000F000u);
4980 const ArgDescriptor ClusterWorkGroupMaxIDY =
4981 ArgDescriptor::createRegister(AMDGPU::TTMP6, 0x000F0000u);
4982 const ArgDescriptor ClusterWorkGroupMaxIDZ =
4983 ArgDescriptor::createRegister(AMDGPU::TTMP6, 0x00F00000u);
4984 const ArgDescriptor ClusterWorkGroupMaxFlatID =
4985 ArgDescriptor::createRegister(AMDGPU::TTMP6, 0x0F000000u);
4986
4987 auto LoadConstant = [&](unsigned N) {
4988 B.buildConstant(DstReg, N);
4989 return true;
4990 };
4991
4992 if (ST.hasArchitectedSGPRs() &&
4994 AMDGPU::ClusterDimsAttr ClusterDims = MFI->getClusterDims();
4995 bool HasFixedDims = ClusterDims.isFixedDims();
4996
4997 switch (ArgType) {
4999 Arg = &WorkGroupIDX;
5000 ArgRC = &AMDGPU::SReg_32RegClass;
5001 ArgTy = LLT::integer(32);
5002 break;
5004 Arg = &WorkGroupIDY;
5005 ArgRC = &AMDGPU::SReg_32RegClass;
5006 ArgTy = LLT::integer(32);
5007 break;
5009 Arg = &WorkGroupIDZ;
5010 ArgRC = &AMDGPU::SReg_32RegClass;
5011 ArgTy = LLT::integer(32);
5012 break;
5014 if (HasFixedDims && ClusterDims.getDims()[0] == 1)
5015 return LoadConstant(0);
5016 Arg = &ClusterWorkGroupIDX;
5017 ArgRC = &AMDGPU::SReg_32RegClass;
5018 ArgTy = LLT::integer(32);
5019 break;
5021 if (HasFixedDims && ClusterDims.getDims()[1] == 1)
5022 return LoadConstant(0);
5023 Arg = &ClusterWorkGroupIDY;
5024 ArgRC = &AMDGPU::SReg_32RegClass;
5025 ArgTy = LLT::integer(32);
5026 break;
5028 if (HasFixedDims && ClusterDims.getDims()[2] == 1)
5029 return LoadConstant(0);
5030 Arg = &ClusterWorkGroupIDZ;
5031 ArgRC = &AMDGPU::SReg_32RegClass;
5032 ArgTy = LLT::integer(32);
5033 break;
5035 if (HasFixedDims)
5036 return LoadConstant(ClusterDims.getDims()[0] - 1);
5037 Arg = &ClusterWorkGroupMaxIDX;
5038 ArgRC = &AMDGPU::SReg_32RegClass;
5039 ArgTy = LLT::integer(32);
5040 break;
5042 if (HasFixedDims)
5043 return LoadConstant(ClusterDims.getDims()[1] - 1);
5044 Arg = &ClusterWorkGroupMaxIDY;
5045 ArgRC = &AMDGPU::SReg_32RegClass;
5046 ArgTy = LLT::integer(32);
5047 break;
5049 if (HasFixedDims)
5050 return LoadConstant(ClusterDims.getDims()[2] - 1);
5051 Arg = &ClusterWorkGroupMaxIDZ;
5052 ArgRC = &AMDGPU::SReg_32RegClass;
5053 ArgTy = LLT::integer(32);
5054 break;
5056 Arg = &ClusterWorkGroupMaxFlatID;
5057 ArgRC = &AMDGPU::SReg_32RegClass;
5058 ArgTy = LLT::integer(32);
5059 break;
5060 default:
5061 break;
5062 }
5063 }
5064
5065 if (!Arg)
5066 std::tie(Arg, ArgRC, ArgTy) = MFI->getPreloadedValue(ArgType);
5067
5068 if (!Arg) {
5070 // The intrinsic may appear when we have a 0 sized kernarg segment, in
5071 // which case the pointer argument may be missing and we use null.
5072 return LoadConstant(0);
5073 }
5074
5075 // It's undefined behavior if a function marked with the amdgpu-no-*
5076 // attributes uses the corresponding intrinsic.
5077 B.buildUndef(DstReg);
5078 return true;
5079 }
5080
5081 if (!Arg->isRegister() || !Arg->getRegister().isValid())
5082 return false; // TODO: Handle these
5083 buildLoadInputValue(DstReg, B, Arg, ArgRC, ArgTy);
5084 return true;
5085}
5086
5090 if (!loadInputValue(MI.getOperand(0).getReg(), B, ArgType))
5091 return false;
5092
5093 MI.eraseFromParent();
5094 return true;
5095}
5096
5098 int64_t C) {
5099 B.buildConstant(MI.getOperand(0).getReg(), C);
5100 MI.eraseFromParent();
5101 return true;
5102}
5103
5106 unsigned Dim, AMDGPUFunctionArgInfo::PreloadedValue ArgType) const {
5107 unsigned MaxID = ST.getMaxWorkitemID(B.getMF().getFunction(), Dim);
5108 if (MaxID == 0)
5109 return replaceWithConstant(B, MI, 0);
5110
5111 const SIMachineFunctionInfo *MFI = B.getMF().getInfo<SIMachineFunctionInfo>();
5112 const ArgDescriptor *Arg;
5113 const TargetRegisterClass *ArgRC;
5114 LLT ArgTy;
5115 std::tie(Arg, ArgRC, ArgTy) = MFI->getPreloadedValue(ArgType);
5116
5117 Register DstReg = MI.getOperand(0).getReg();
5118 if (!Arg) {
5119 // It's undefined behavior if a function marked with the amdgpu-no-*
5120 // attributes uses the corresponding intrinsic.
5121 B.buildUndef(DstReg);
5122 MI.eraseFromParent();
5123 return true;
5124 }
5125
5126 if (Arg->isMasked()) {
5127 // Don't bother inserting AssertZext for packed IDs since we're emitting the
5128 // masking operations anyway.
5129 //
5130 // TODO: We could assert the top bit is 0 for the source copy.
5131 if (!loadInputValue(DstReg, B, ArgType))
5132 return false;
5133 } else {
5135 if (!loadInputValue(TmpReg, B, ArgType))
5136 return false;
5137 B.buildAssertZExt(DstReg, TmpReg, llvm::bit_width(MaxID));
5138 }
5139
5140 MI.eraseFromParent();
5141 return true;
5142}
5143
5146 // This isn't really a constant pool but close enough.
5149 return PtrInfo;
5150}
5151
5153 int64_t Offset) const {
5155 Register KernArgReg = B.getMRI()->createGenericVirtualRegister(PtrTy);
5156
5157 // TODO: If we passed in the base kernel offset we could have a better
5158 // alignment than 4, but we don't really need it.
5159 if (!loadInputValue(KernArgReg, B,
5161 llvm_unreachable("failed to find kernarg segment ptr");
5162
5163 auto COffset = B.buildConstant(LLT::integer(64), Offset);
5164 return B.buildObjectPtrOffset(PtrTy, KernArgReg, COffset).getReg(0);
5165}
5166
5167/// Legalize a value that's loaded from kernel arguments. This is only used by
5168/// legacy intrinsics.
5171 uint64_t Offset,
5172 Align Alignment) const {
5173 Register DstReg = MI.getOperand(0).getReg();
5174
5175 assert(B.getMRI()->getType(DstReg) == LLT::integer(32) &&
5176 "unexpected kernarg parameter type");
5177
5180 B.buildLoad(DstReg, Ptr, PtrInfo.getWithOffset(Offset), Align(4),
5183 MI.eraseFromParent();
5184 return true;
5185}
5186
5189 MachineIRBuilder &B) const {
5190 Register Dst = MI.getOperand(0).getReg();
5191 LLT DstTy = MRI.getType(Dst);
5192
5193 if (DstTy == F16)
5194 return legalizeFDIV16(MI, MRI, B);
5195 if (DstTy == F32)
5196 return legalizeFDIV32(MI, MRI, B);
5197 if (DstTy == F64)
5198 return legalizeFDIV64(MI, MRI, B);
5199
5200 return false;
5201}
5202
5204 Register DstDivReg,
5205 Register DstRemReg,
5206 Register X,
5207 Register Y) const {
5208 const LLT S1 = LLT::scalar(1);
5209 const LLT I32 = LLT::integer(32);
5210
5211 // See AMDGPUCodeGenPrepare::expandDivRem32 for a description of the
5212 // algorithm used here.
5213
5214 // Initial estimate of inv(y).
5215 auto FloatY = B.buildUITOFP(F32, Y);
5216 auto RcpIFlag = B.buildInstr(AMDGPU::G_AMDGPU_RCP_IFLAG, {F32}, {FloatY});
5217 auto Scale = B.buildFConstant(F32, llvm::bit_cast<float>(0x4f7ffffe));
5218 auto ScaledY = B.buildFMul(F32, RcpIFlag, Scale);
5219 auto Z = B.buildFPTOUI(I32, ScaledY);
5220
5221 // One round of UNR.
5222 auto NegY = B.buildSub(I32, B.buildConstant(I32, 0), Y);
5223 auto NegYZ = B.buildMul(I32, NegY, Z);
5224 Z = B.buildAdd(I32, Z, B.buildUMulH(I32, Z, NegYZ));
5225
5226 // Quotient/remainder estimate.
5227 auto Q = B.buildUMulH(I32, X, Z);
5228 auto R = B.buildSub(I32, X, B.buildMul(I32, Q, Y));
5229
5230 // First quotient/remainder refinement.
5231 auto One = B.buildConstant(I32, 1);
5232 auto Cond = B.buildICmp(CmpInst::ICMP_UGE, S1, R, Y);
5233 if (DstDivReg)
5234 Q = B.buildSelect(I32, Cond, B.buildAdd(I32, Q, One), Q);
5235 R = B.buildSelect(I32, Cond, B.buildSub(I32, R, Y), R);
5236
5237 // Second quotient/remainder refinement.
5238 Cond = B.buildICmp(CmpInst::ICMP_UGE, S1, R, Y);
5239 if (DstDivReg)
5240 B.buildSelect(DstDivReg, Cond, B.buildAdd(I32, Q, One), Q);
5241
5242 if (DstRemReg)
5243 B.buildSelect(DstRemReg, Cond, B.buildSub(I32, R, Y), R);
5244}
5245
5246// Build integer reciprocal sequence around V_RCP_IFLAG_F32
5247//
5248// Return lo, hi of result
5249//
5250// %cvt.lo = G_UITOFP Val.lo
5251// %cvt.hi = G_UITOFP Val.hi
5252// %mad = G_FMAD %cvt.hi, 2**32, %cvt.lo
5253// %rcp = G_AMDGPU_RCP_IFLAG %mad
5254// %mul1 = G_FMUL %rcp, 0x5f7ffffc
5255// %mul2 = G_FMUL %mul1, 2**(-32)
5256// %trunc = G_INTRINSIC_TRUNC %mul2
5257// %mad2 = G_FMAD %trunc, -(2**32), %mul1
5258// return {G_FPTOUI %mad2, G_FPTOUI %trunc}
5259static std::pair<Register, Register> emitReciprocalU64(MachineIRBuilder &B,
5260 Register Val) {
5261 const LLT I32 = LLT::integer(32);
5262 auto Unmerge = B.buildUnmerge(I32, Val);
5263
5264 auto CvtLo = B.buildUITOFP(F32, Unmerge.getReg(0));
5265 auto CvtHi = B.buildUITOFP(F32, Unmerge.getReg(1));
5266
5267 auto Mad = B.buildFMAD(
5268 F32, CvtHi, // 2**32
5269 B.buildFConstant(F32, llvm::bit_cast<float>(0x4f800000)), CvtLo);
5270
5271 auto Rcp = B.buildInstr(AMDGPU::G_AMDGPU_RCP_IFLAG, {F32}, {Mad});
5272 auto Mul1 = B.buildFMul(
5273 F32, Rcp, B.buildFConstant(F32, llvm::bit_cast<float>(0x5f7ffffc)));
5274
5275 // 2**(-32)
5276 auto Mul2 = B.buildFMul(
5277 F32, Mul1, B.buildFConstant(F32, llvm::bit_cast<float>(0x2f800000)));
5278 auto Trunc = B.buildIntrinsicTrunc(F32, Mul2);
5279
5280 // -(2**32)
5281 auto Mad2 = B.buildFMAD(
5282 F32, Trunc, B.buildFConstant(F32, llvm::bit_cast<float>(0xcf800000)),
5283 Mul1);
5284
5285 auto ResultLo = B.buildFPTOUI(I32, Mad2);
5286 auto ResultHi = B.buildFPTOUI(I32, Trunc);
5287
5288 return {ResultLo.getReg(0), ResultHi.getReg(0)};
5289}
5290
5292 Register DstDivReg,
5293 Register DstRemReg,
5294 Register Numer,
5295 Register Denom) const {
5296 const LLT I32 = LLT::integer(32);
5297 const LLT I64 = LLT::integer(64);
5298 const LLT S1 = LLT::scalar(1);
5299 Register RcpLo, RcpHi;
5300
5301 std::tie(RcpLo, RcpHi) = emitReciprocalU64(B, Denom);
5302
5303 auto Rcp = B.buildMergeLikeInstr(I64, {RcpLo, RcpHi});
5304
5305 auto Zero64 = B.buildConstant(I64, 0);
5306 auto NegDenom = B.buildSub(I64, Zero64, Denom);
5307
5308 auto MulLo1 = B.buildMul(I64, NegDenom, Rcp);
5309 auto MulHi1 = B.buildUMulH(I64, Rcp, MulLo1);
5310
5311 auto UnmergeMulHi1 = B.buildUnmerge(I32, MulHi1);
5312 Register MulHi1_Lo = UnmergeMulHi1.getReg(0);
5313 Register MulHi1_Hi = UnmergeMulHi1.getReg(1);
5314
5315 auto Add1_Lo = B.buildUAddo(I32, S1, RcpLo, MulHi1_Lo);
5316 auto Add1_Hi = B.buildUAdde(I32, S1, RcpHi, MulHi1_Hi, Add1_Lo.getReg(1));
5317 auto Add1 = B.buildMergeLikeInstr(I64, {Add1_Lo, Add1_Hi});
5318
5319 auto MulLo2 = B.buildMul(I64, NegDenom, Add1);
5320 auto MulHi2 = B.buildUMulH(I64, Add1, MulLo2);
5321 auto UnmergeMulHi2 = B.buildUnmerge(I32, MulHi2);
5322 Register MulHi2_Lo = UnmergeMulHi2.getReg(0);
5323 Register MulHi2_Hi = UnmergeMulHi2.getReg(1);
5324
5325 auto Zero32 = B.buildConstant(I32, 0);
5326 auto Add2_Lo = B.buildUAddo(I32, S1, Add1_Lo, MulHi2_Lo);
5327 auto Add2_Hi = B.buildUAdde(I32, S1, Add1_Hi, MulHi2_Hi, Add2_Lo.getReg(1));
5328 auto Add2 = B.buildMergeLikeInstr(I64, {Add2_Lo, Add2_Hi});
5329
5330 auto UnmergeNumer = B.buildUnmerge(I32, Numer);
5331 Register NumerLo = UnmergeNumer.getReg(0);
5332 Register NumerHi = UnmergeNumer.getReg(1);
5333
5334 auto MulHi3 = B.buildUMulH(I64, Numer, Add2);
5335 auto Mul3 = B.buildMul(I64, Denom, MulHi3);
5336 auto UnmergeMul3 = B.buildUnmerge(I32, Mul3);
5337 Register Mul3_Lo = UnmergeMul3.getReg(0);
5338 Register Mul3_Hi = UnmergeMul3.getReg(1);
5339 auto Sub1_Lo = B.buildUSubo(I32, S1, NumerLo, Mul3_Lo);
5340 auto Sub1_Hi = B.buildUSube(I32, S1, NumerHi, Mul3_Hi, Sub1_Lo.getReg(1));
5341 auto Sub1_Mi = B.buildSub(I32, NumerHi, Mul3_Hi);
5342 auto Sub1 = B.buildMergeLikeInstr(I64, {Sub1_Lo, Sub1_Hi});
5343
5344 auto UnmergeDenom = B.buildUnmerge(I32, Denom);
5345 Register DenomLo = UnmergeDenom.getReg(0);
5346 Register DenomHi = UnmergeDenom.getReg(1);
5347
5348 auto CmpHi = B.buildICmp(CmpInst::ICMP_UGE, S1, Sub1_Hi, DenomHi);
5349 auto C1 = B.buildSExt(I32, CmpHi);
5350
5351 auto CmpLo = B.buildICmp(CmpInst::ICMP_UGE, S1, Sub1_Lo, DenomLo);
5352 auto C2 = B.buildSExt(I32, CmpLo);
5353
5354 auto CmpEq = B.buildICmp(CmpInst::ICMP_EQ, S1, Sub1_Hi, DenomHi);
5355 auto C3 = B.buildSelect(I32, CmpEq, C2, C1);
5356
5357 // TODO: Here and below portions of the code can be enclosed into if/endif.
5358 // Currently control flow is unconditional and we have 4 selects after
5359 // potential endif to substitute PHIs.
5360
5361 // if C3 != 0 ...
5362 auto Sub2_Lo = B.buildUSubo(I32, S1, Sub1_Lo, DenomLo);
5363 auto Sub2_Mi = B.buildUSube(I32, S1, Sub1_Mi, DenomHi, Sub1_Lo.getReg(1));
5364 auto Sub2_Hi = B.buildUSube(I32, S1, Sub2_Mi, Zero32, Sub2_Lo.getReg(1));
5365 auto Sub2 = B.buildMergeLikeInstr(I64, {Sub2_Lo, Sub2_Hi});
5366
5367 auto One64 = B.buildConstant(I64, 1);
5368 auto Add3 = B.buildAdd(I64, MulHi3, One64);
5369
5370 auto C4 =
5371 B.buildSExt(I32, B.buildICmp(CmpInst::ICMP_UGE, S1, Sub2_Hi, DenomHi));
5372 auto C5 =
5373 B.buildSExt(I32, B.buildICmp(CmpInst::ICMP_UGE, S1, Sub2_Lo, DenomLo));
5374 auto C6 = B.buildSelect(
5375 I32, B.buildICmp(CmpInst::ICMP_EQ, S1, Sub2_Hi, DenomHi), C5, C4);
5376
5377 // if (C6 != 0)
5378 auto Add4 = B.buildAdd(I64, Add3, One64);
5379 auto Sub3_Lo = B.buildUSubo(I32, S1, Sub2_Lo, DenomLo);
5380
5381 auto Sub3_Mi = B.buildUSube(I32, S1, Sub2_Mi, DenomHi, Sub2_Lo.getReg(1));
5382 auto Sub3_Hi = B.buildUSube(I32, S1, Sub3_Mi, Zero32, Sub3_Lo.getReg(1));
5383 auto Sub3 = B.buildMergeLikeInstr(I64, {Sub3_Lo, Sub3_Hi});
5384
5385 // endif C6
5386 // endif C3
5387
5388 if (DstDivReg) {
5389 auto Sel1 = B.buildSelect(
5390 I64, B.buildICmp(CmpInst::ICMP_NE, S1, C6, Zero32), Add4, Add3);
5391 B.buildSelect(DstDivReg, B.buildICmp(CmpInst::ICMP_NE, S1, C3, Zero32),
5392 Sel1, MulHi3);
5393 }
5394
5395 if (DstRemReg) {
5396 auto Sel2 = B.buildSelect(
5397 I64, B.buildICmp(CmpInst::ICMP_NE, S1, C6, Zero32), Sub3, Sub2);
5398 B.buildSelect(DstRemReg, B.buildICmp(CmpInst::ICMP_NE, S1, C3, Zero32),
5399 Sel2, Sub1);
5400 }
5401}
5402
5405 MachineIRBuilder &B) const {
5406 Register DstDivReg, DstRemReg;
5407 switch (MI.getOpcode()) {
5408 default:
5409 llvm_unreachable("Unexpected opcode!");
5410 case AMDGPU::G_UDIV: {
5411 DstDivReg = MI.getOperand(0).getReg();
5412 break;
5413 }
5414 case AMDGPU::G_UREM: {
5415 DstRemReg = MI.getOperand(0).getReg();
5416 break;
5417 }
5418 case AMDGPU::G_UDIVREM: {
5419 DstDivReg = MI.getOperand(0).getReg();
5420 DstRemReg = MI.getOperand(1).getReg();
5421 break;
5422 }
5423 }
5424
5425 const LLT I64 = LLT::integer(64);
5426 const LLT I32 = LLT::integer(32);
5427 const unsigned FirstSrcOpIdx = MI.getNumExplicitDefs();
5428 Register Num = MI.getOperand(FirstSrcOpIdx).getReg();
5429 Register Den = MI.getOperand(FirstSrcOpIdx + 1).getReg();
5430 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
5431
5432 if (Ty == I32)
5433 legalizeUnsignedDIV_REM32Impl(B, DstDivReg, DstRemReg, Num, Den);
5434 else if (Ty == I64)
5435 legalizeUnsignedDIV_REM64Impl(B, DstDivReg, DstRemReg, Num, Den);
5436 else
5437 return false;
5438
5439 MI.eraseFromParent();
5440 return true;
5441}
5442
5445 MachineIRBuilder &B) const {
5446 const LLT I64 = LLT::integer(64);
5447 const LLT I32 = LLT::integer(32);
5448
5449 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
5450 if (Ty != I32 && Ty != I64)
5451 return false;
5452
5453 const unsigned FirstSrcOpIdx = MI.getNumExplicitDefs();
5454 Register LHS = MI.getOperand(FirstSrcOpIdx).getReg();
5455 Register RHS = MI.getOperand(FirstSrcOpIdx + 1).getReg();
5456
5457 auto SignBitOffset = B.buildConstant(I32, Ty.getSizeInBits() - 1);
5458 auto LHSign = B.buildAShr(Ty, LHS, SignBitOffset);
5459 auto RHSign = B.buildAShr(Ty, RHS, SignBitOffset);
5460
5461 LHS = B.buildAdd(Ty, LHS, LHSign).getReg(0);
5462 RHS = B.buildAdd(Ty, RHS, RHSign).getReg(0);
5463
5464 LHS = B.buildXor(Ty, LHS, LHSign).getReg(0);
5465 RHS = B.buildXor(Ty, RHS, RHSign).getReg(0);
5466
5467 Register DstDivReg, DstRemReg, TmpDivReg, TmpRemReg;
5468 switch (MI.getOpcode()) {
5469 default:
5470 llvm_unreachable("Unexpected opcode!");
5471 case AMDGPU::G_SDIV: {
5472 DstDivReg = MI.getOperand(0).getReg();
5473 TmpDivReg = MRI.createGenericVirtualRegister(Ty);
5474 break;
5475 }
5476 case AMDGPU::G_SREM: {
5477 DstRemReg = MI.getOperand(0).getReg();
5478 TmpRemReg = MRI.createGenericVirtualRegister(Ty);
5479 break;
5480 }
5481 case AMDGPU::G_SDIVREM: {
5482 DstDivReg = MI.getOperand(0).getReg();
5483 DstRemReg = MI.getOperand(1).getReg();
5484 TmpDivReg = MRI.createGenericVirtualRegister(Ty);
5485 TmpRemReg = MRI.createGenericVirtualRegister(Ty);
5486 break;
5487 }
5488 }
5489
5490 if (Ty == I32)
5491 legalizeUnsignedDIV_REM32Impl(B, TmpDivReg, TmpRemReg, LHS, RHS);
5492 else
5493 legalizeUnsignedDIV_REM64Impl(B, TmpDivReg, TmpRemReg, LHS, RHS);
5494
5495 if (DstDivReg) {
5496 auto Sign = B.buildXor(Ty, LHSign, RHSign).getReg(0);
5497 auto SignXor = B.buildXor(Ty, TmpDivReg, Sign).getReg(0);
5498 B.buildSub(DstDivReg, SignXor, Sign);
5499 }
5500
5501 if (DstRemReg) {
5502 auto Sign = LHSign.getReg(0); // Remainder sign is the same as LHS
5503 auto SignXor = B.buildXor(Ty, TmpRemReg, Sign).getReg(0);
5504 B.buildSub(DstRemReg, SignXor, Sign);
5505 }
5506
5507 MI.eraseFromParent();
5508 return true;
5509}
5510
5513 MachineIRBuilder &B) const {
5514 Register Res = MI.getOperand(0).getReg();
5515 Register LHS = MI.getOperand(1).getReg();
5516 Register RHS = MI.getOperand(2).getReg();
5517 uint16_t Flags = MI.getFlags();
5518 LLT ResTy = MRI.getType(Res);
5519
5520 bool AllowInaccurateRcp = MI.getFlag(MachineInstr::FmAfn);
5521
5522 if (const auto *CLHS = getConstantFPVRegVal(LHS, MRI)) {
5523 if (!AllowInaccurateRcp && ResTy != F16)
5524 return false;
5525
5526 // v_rcp_f32 and v_rsq_f32 do not support denormals, and according to
5527 // the CI documentation has a worst case error of 1 ulp.
5528 // OpenCL requires <= 2.5 ulp for 1.0 / x, so it should always be OK to
5529 // use it as long as we aren't trying to use denormals.
5530 //
5531 // v_rcp_f16 and v_rsq_f16 DO support denormals and 0.51ulp.
5532
5533 // 1 / x -> RCP(x)
5534 if (CLHS->isOne()) {
5535 B.buildIntrinsic(Intrinsic::amdgcn_rcp, Res)
5536 .addUse(RHS)
5537 .setMIFlags(Flags);
5538
5539 MI.eraseFromParent();
5540 return true;
5541 }
5542
5543 // -1 / x -> RCP( FNEG(x) )
5544 if (CLHS->isMinusOne()) {
5545 auto FNeg = B.buildFNeg(ResTy, RHS, Flags);
5546 B.buildIntrinsic(Intrinsic::amdgcn_rcp, Res)
5547 .addUse(FNeg.getReg(0))
5548 .setMIFlags(Flags);
5549
5550 MI.eraseFromParent();
5551 return true;
5552 }
5553 }
5554
5555 // For f16 require afn or arcp.
5556 // For f32 require afn.
5557 if (!AllowInaccurateRcp &&
5558 (ResTy != F16 || !MI.getFlag(MachineInstr::FmArcp)))
5559 return false;
5560
5561 // x / y -> x * (1.0 / y)
5562 auto RCP = B.buildIntrinsic(Intrinsic::amdgcn_rcp, {ResTy})
5563 .addUse(RHS)
5564 .setMIFlags(Flags);
5565 B.buildFMul(Res, LHS, RCP, Flags);
5566
5567 MI.eraseFromParent();
5568 return true;
5569}
5570
5573 MachineIRBuilder &B) const {
5574 Register Res = MI.getOperand(0).getReg();
5575 Register X = MI.getOperand(1).getReg();
5576 Register Y = MI.getOperand(2).getReg();
5577 uint16_t Flags = MI.getFlags();
5578 LLT ResTy = MRI.getType(Res);
5579
5580 bool AllowInaccurateRcp = MI.getFlag(MachineInstr::FmAfn);
5581
5582 if (!AllowInaccurateRcp)
5583 return false;
5584
5585 const ConstantFP *CLHS = getConstantFPVRegVal(X, MRI);
5586 bool IsNegRcp = CLHS && CLHS->isMinusOne();
5587
5588 // Pull out the negation so it folds for free into the source modifiers.
5589 if (IsNegRcp)
5590 X = B.buildFConstant(ResTy, 1.0).getReg(0);
5591
5592 Register NegY = IsNegRcp ? Y : B.buildFNeg(ResTy, Y).getReg(0);
5593 auto One = B.buildFConstant(ResTy, 1.0);
5594
5595 auto R = B.buildIntrinsic(Intrinsic::amdgcn_rcp, {ResTy})
5596 .addUse(Y)
5597 .setMIFlags(Flags);
5598 if (IsNegRcp)
5599 R = B.buildFNeg(ResTy, R);
5600
5601 auto Tmp0 = B.buildFMA(ResTy, NegY, R, One);
5602 R = B.buildFMA(ResTy, Tmp0, R, R);
5603
5604 auto Tmp1 = B.buildFMA(ResTy, NegY, R, One);
5605 R = B.buildFMA(ResTy, Tmp1, R, R);
5606
5607 // Skip the last 2 correction terms for reciprocal.
5608 if (IsNegRcp || (CLHS && CLHS->isOne())) {
5609 B.buildCopy(Res, R);
5610 MI.eraseFromParent();
5611 return true;
5612 }
5613
5614 auto Ret = B.buildFMul(ResTy, X, R);
5615 auto Tmp2 = B.buildFMA(ResTy, NegY, Ret, X);
5616
5617 B.buildFMA(Res, Tmp2, R, Ret);
5618 MI.eraseFromParent();
5619 return true;
5620}
5621
5624 MachineIRBuilder &B) const {
5625 if (legalizeFastUnsafeFDIV(MI, MRI, B))
5626 return true;
5627
5628 Register Res = MI.getOperand(0).getReg();
5629 Register LHS = MI.getOperand(1).getReg();
5630 Register RHS = MI.getOperand(2).getReg();
5631
5632 uint16_t Flags = MI.getFlags();
5633
5634 LLT I32 = LLT::integer(32);
5635
5636 // a32.u = opx(V_CVT_F32_F16, a.u); // CVT to F32
5637 // b32.u = opx(V_CVT_F32_F16, b.u); // CVT to F32
5638 // r32.u = opx(V_RCP_F32, b32.u); // rcp = 1 / d
5639 // q32.u = opx(V_MUL_F32, a32.u, r32.u); // q = n * rcp
5640 // e32.u = opx(V_MAD_F32, (b32.u^_neg32), q32.u, a32.u); // err = -d * q + n
5641 // q32.u = opx(V_MAD_F32, e32.u, r32.u, q32.u); // q = n * rcp
5642 // e32.u = opx(V_MAD_F32, (b32.u^_neg32), q32.u, a32.u); // err = -d * q + n
5643 // tmp.u = opx(V_MUL_F32, e32.u, r32.u);
5644 // tmp.u = opx(V_AND_B32, tmp.u, 0xff800000)
5645 // q32.u = opx(V_ADD_F32, tmp.u, q32.u);
5646 // q16.u = opx(V_CVT_F16_F32, q32.u);
5647 // q16.u = opx(V_DIV_FIXUP_F16, q16.u, b.u, a.u); // q = touchup(q, d, n)
5648
5649 auto LHSExt = B.buildFPExt(F32, LHS, Flags);
5650 auto RHSExt = B.buildFPExt(F32, RHS, Flags);
5651 auto NegRHSExt = B.buildFNeg(F32, RHSExt);
5652 auto Rcp = B.buildIntrinsic(Intrinsic::amdgcn_rcp, {F32})
5653 .addUse(RHSExt.getReg(0))
5654 .setMIFlags(Flags);
5655 auto Quot = B.buildFMul(F32, LHSExt, Rcp, Flags);
5657 if (ST.hasMadMacF32Insts()) {
5658 Err = B.buildFMAD(F32, NegRHSExt, Quot, LHSExt, Flags);
5659 Quot = B.buildFMAD(F32, Err, Rcp, Quot, Flags);
5660 Err = B.buildFMAD(F32, NegRHSExt, Quot, LHSExt, Flags);
5661 } else {
5662 Err = B.buildFMA(F32, NegRHSExt, Quot, LHSExt, Flags);
5663 Quot = B.buildFMA(F32, Err, Rcp, Quot, Flags);
5664 Err = B.buildFMA(F32, NegRHSExt, Quot, LHSExt, Flags);
5665 }
5666 auto Tmp = B.buildFMul(F32, Err, Rcp, Flags);
5667 auto TmpInt = B.buildBitcast(I32, Tmp);
5668 auto MaskedInt = B.buildAnd(I32, TmpInt, B.buildConstant(I32, 0xff800000));
5669 auto Masked = B.buildBitcast(F32, MaskedInt);
5670 Quot = B.buildFAdd(F32, Masked, Quot, Flags);
5671 auto RDst = B.buildFPTrunc(F16, Quot, Flags);
5672 B.buildIntrinsic(Intrinsic::amdgcn_div_fixup, Res)
5673 .addUse(RDst.getReg(0))
5674 .addUse(RHS)
5675 .addUse(LHS)
5676 .setMIFlags(Flags);
5677
5678 MI.eraseFromParent();
5679 return true;
5680}
5681
5682static constexpr unsigned SPDenormModeBitField =
5684
5685// Enable or disable FP32 denorm mode. When 'Enable' is true, emit instructions
5686// to enable denorm mode. When 'Enable' is false, disable denorm mode.
5688 const GCNSubtarget &ST,
5690 // Set SP denorm mode to this value.
5691 unsigned SPDenormMode =
5692 Enable ? FP_DENORM_FLUSH_NONE : Mode.fpDenormModeSPValue();
5693
5694 if (ST.hasDenormModeInst()) {
5695 // Preserve default FP64FP16 denorm mode while updating FP32 mode.
5696 uint32_t DPDenormModeDefault = Mode.fpDenormModeDPValue();
5697
5698 uint32_t NewDenormModeValue = SPDenormMode | (DPDenormModeDefault << 2);
5699 B.buildInstr(AMDGPU::S_DENORM_MODE)
5700 .addImm(NewDenormModeValue);
5701
5702 } else {
5703 B.buildInstr(AMDGPU::S_SETREG_IMM32_B32)
5704 .addImm(SPDenormMode)
5705 .addImm(SPDenormModeBitField);
5706 }
5707}
5708
5711 MachineIRBuilder &B) const {
5712 if (legalizeFastUnsafeFDIV(MI, MRI, B))
5713 return true;
5714
5715 Register Res = MI.getOperand(0).getReg();
5716 Register LHS = MI.getOperand(1).getReg();
5717 Register RHS = MI.getOperand(2).getReg();
5718 const SIMachineFunctionInfo *MFI = B.getMF().getInfo<SIMachineFunctionInfo>();
5719 SIModeRegisterDefaults Mode = MFI->getMode();
5720
5721 uint16_t Flags = MI.getFlags();
5722
5723 LLT S1 = LLT::scalar(1);
5724
5725 auto One = B.buildFConstant(F32, 1.0f);
5726
5727 auto DenominatorScaled =
5728 B.buildIntrinsic(Intrinsic::amdgcn_div_scale, {F32, S1})
5729 .addUse(LHS)
5730 .addUse(RHS)
5731 .addImm(0)
5732 .setMIFlags(Flags);
5733 auto NumeratorScaled =
5734 B.buildIntrinsic(Intrinsic::amdgcn_div_scale, {F32, S1})
5735 .addUse(LHS)
5736 .addUse(RHS)
5737 .addImm(1)
5738 .setMIFlags(Flags);
5739
5740 auto ApproxRcp = B.buildIntrinsic(Intrinsic::amdgcn_rcp, {F32})
5741 .addUse(DenominatorScaled.getReg(0))
5742 .setMIFlags(Flags);
5743 auto NegDivScale0 = B.buildFNeg(F32, DenominatorScaled, Flags);
5744
5745 const bool PreservesDenormals = Mode.FP32Denormals == DenormalMode::getIEEE();
5746 const bool HasDynamicDenormals =
5747 (Mode.FP32Denormals.Input == DenormalMode::Dynamic) ||
5748 (Mode.FP32Denormals.Output == DenormalMode::Dynamic);
5749
5750 Register SavedSPDenormMode;
5751 if (!PreservesDenormals) {
5752 if (HasDynamicDenormals) {
5753 SavedSPDenormMode = MRI.createVirtualRegister(&AMDGPU::SReg_32RegClass);
5754 B.buildInstr(AMDGPU::S_GETREG_B32)
5755 .addDef(SavedSPDenormMode)
5756 .addImm(SPDenormModeBitField);
5757 }
5758 toggleSPDenormMode(true, B, ST, Mode);
5759 }
5760
5761 auto Fma0 = B.buildFMA(F32, NegDivScale0, ApproxRcp, One, Flags);
5762 auto Fma1 = B.buildFMA(F32, Fma0, ApproxRcp, ApproxRcp, Flags);
5763 auto Mul = B.buildFMul(F32, NumeratorScaled, Fma1, Flags);
5764 auto Fma2 = B.buildFMA(F32, NegDivScale0, Mul, NumeratorScaled, Flags);
5765 auto Fma3 = B.buildFMA(F32, Fma2, Fma1, Mul, Flags);
5766 auto Fma4 = B.buildFMA(F32, NegDivScale0, Fma3, NumeratorScaled, Flags);
5767
5768 if (!PreservesDenormals) {
5769 if (HasDynamicDenormals) {
5770 assert(SavedSPDenormMode);
5771 B.buildInstr(AMDGPU::S_SETREG_B32)
5772 .addReg(SavedSPDenormMode)
5773 .addImm(SPDenormModeBitField);
5774 } else
5775 toggleSPDenormMode(false, B, ST, Mode);
5776 }
5777
5778 auto Fmas = B.buildIntrinsic(Intrinsic::amdgcn_div_fmas, {F32})
5779 .addUse(Fma4.getReg(0))
5780 .addUse(Fma1.getReg(0))
5781 .addUse(Fma3.getReg(0))
5782 .addUse(NumeratorScaled.getReg(1))
5783 .setMIFlags(Flags);
5784
5785 B.buildIntrinsic(Intrinsic::amdgcn_div_fixup, Res)
5786 .addUse(Fmas.getReg(0))
5787 .addUse(RHS)
5788 .addUse(LHS)
5789 .setMIFlags(Flags);
5790
5791 MI.eraseFromParent();
5792 return true;
5793}
5794
5797 MachineIRBuilder &B) const {
5798 if (legalizeFastUnsafeFDIV64(MI, MRI, B))
5799 return true;
5800
5801 Register Res = MI.getOperand(0).getReg();
5802 Register LHS = MI.getOperand(1).getReg();
5803 Register RHS = MI.getOperand(2).getReg();
5804
5805 uint16_t Flags = MI.getFlags();
5806
5807 LLT S1 = LLT::scalar(1);
5808
5809 auto One = B.buildFConstant(F64, 1.0);
5810
5811 auto DivScale0 = B.buildIntrinsic(Intrinsic::amdgcn_div_scale, {F64, S1})
5812 .addUse(LHS)
5813 .addUse(RHS)
5814 .addImm(0)
5815 .setMIFlags(Flags);
5816
5817 auto NegDivScale0 = B.buildFNeg(F64, DivScale0.getReg(0), Flags);
5818
5819 auto Rcp = B.buildIntrinsic(Intrinsic::amdgcn_rcp, {F64})
5820 .addUse(DivScale0.getReg(0))
5821 .setMIFlags(Flags);
5822
5823 auto Fma0 = B.buildFMA(F64, NegDivScale0, Rcp, One, Flags);
5824 auto Fma1 = B.buildFMA(F64, Rcp, Fma0, Rcp, Flags);
5825 auto Fma2 = B.buildFMA(F64, NegDivScale0, Fma1, One, Flags);
5826
5827 auto DivScale1 = B.buildIntrinsic(Intrinsic::amdgcn_div_scale, {F64, S1})
5828 .addUse(LHS)
5829 .addUse(RHS)
5830 .addImm(1)
5831 .setMIFlags(Flags);
5832
5833 auto Fma3 = B.buildFMA(F64, Fma1, Fma2, Fma1, Flags);
5834 auto Mul = B.buildFMul(F64, DivScale1.getReg(0), Fma3, Flags);
5835 auto Fma4 = B.buildFMA(F64, NegDivScale0, Mul, DivScale1.getReg(0), Flags);
5836
5837 Register Scale;
5838 if (!ST.hasUsableDivScaleConditionOutput()) {
5839 // Workaround a hardware bug on SI where the condition output from div_scale
5840 // is not usable.
5841
5842 LLT I32 = LLT::integer(32);
5843 LLT I64 = LLT::integer(64);
5844
5845 auto NumUnmerge = B.buildUnmerge(I32, B.buildBitcast(I64, LHS));
5846 auto DenUnmerge = B.buildUnmerge(I32, B.buildBitcast(I64, RHS));
5847 auto Scale0Unmerge = B.buildUnmerge(I32, B.buildBitcast(I64, DivScale0));
5848 auto Scale1Unmerge = B.buildUnmerge(I32, B.buildBitcast(I64, DivScale1));
5849
5850 auto CmpNum = B.buildICmp(ICmpInst::ICMP_EQ, S1, NumUnmerge.getReg(1),
5851 Scale1Unmerge.getReg(1));
5852 auto CmpDen = B.buildICmp(ICmpInst::ICMP_EQ, S1, DenUnmerge.getReg(1),
5853 Scale0Unmerge.getReg(1));
5854 Scale = B.buildXor(S1, CmpNum, CmpDen).getReg(0);
5855 } else {
5856 Scale = DivScale1.getReg(1);
5857 }
5858
5859 auto Fmas = B.buildIntrinsic(Intrinsic::amdgcn_div_fmas, {F64})
5860 .addUse(Fma4.getReg(0))
5861 .addUse(Fma3.getReg(0))
5862 .addUse(Mul.getReg(0))
5863 .addUse(Scale)
5864 .setMIFlags(Flags);
5865
5866 B.buildIntrinsic(Intrinsic::amdgcn_div_fixup, ArrayRef(Res))
5867 .addUse(Fmas.getReg(0))
5868 .addUse(RHS)
5869 .addUse(LHS)
5870 .setMIFlags(Flags);
5871
5872 MI.eraseFromParent();
5873 return true;
5874}
5875
5878 MachineIRBuilder &B) const {
5879 Register Res0 = MI.getOperand(0).getReg();
5880 Register Res1 = MI.getOperand(1).getReg();
5881 Register Val = MI.getOperand(2).getReg();
5882 uint16_t Flags = MI.getFlags();
5883
5884 LLT Ty = MRI.getType(Res0);
5885 LLT InstrExpTy = Ty == F16 ? LLT::integer(16) : LLT::integer(32);
5886
5887 auto Mant = B.buildIntrinsic(Intrinsic::amdgcn_frexp_mant, {Ty})
5888 .addUse(Val)
5889 .setMIFlags(Flags);
5890 auto Exp = B.buildIntrinsic(Intrinsic::amdgcn_frexp_exp, {InstrExpTy})
5891 .addUse(Val)
5892 .setMIFlags(Flags);
5893
5894 if (ST.hasFractBug()) {
5895 auto Fabs = B.buildFAbs(Ty, Val);
5896 auto Inf = B.buildFConstant(Ty, APFloat::getInf(getFltSemanticForLLT(Ty)));
5897 auto IsFinite =
5898 B.buildFCmp(CmpInst::FCMP_OLT, LLT::scalar(1), Fabs, Inf, Flags);
5899 auto Zero = B.buildConstant(InstrExpTy, 0);
5900 Exp = B.buildSelect(InstrExpTy, IsFinite, Exp, Zero);
5901 Mant = B.buildSelect(Ty, IsFinite, Mant, Val);
5902 }
5903
5904 B.buildCopy(Res0, Mant);
5905 B.buildSExtOrTrunc(Res1, Exp);
5906
5907 MI.eraseFromParent();
5908 return true;
5909}
5910
5913 MachineIRBuilder &B) const {
5914 Register Res = MI.getOperand(0).getReg();
5915 Register LHS = MI.getOperand(2).getReg();
5916 Register RHS = MI.getOperand(3).getReg();
5917 uint16_t Flags = MI.getFlags();
5918
5919 LLT S1 = LLT::scalar(1);
5920
5921 auto Abs = B.buildFAbs(F32, RHS, Flags);
5922 const APFloat C0Val(1.0f);
5923
5924 auto C0 = B.buildFConstant(F32, 0x1p+96f);
5925 auto C1 = B.buildFConstant(F32, 0x1p-32f);
5926 auto C2 = B.buildFConstant(F32, 1.0f);
5927
5928 auto CmpRes = B.buildFCmp(CmpInst::FCMP_OGT, S1, Abs, C0, Flags);
5929 auto Sel = B.buildSelect(F32, CmpRes, C1, C2, Flags);
5930
5931 auto Mul0 = B.buildFMul(F32, RHS, Sel, Flags);
5932
5933 auto RCP = B.buildIntrinsic(Intrinsic::amdgcn_rcp, {F32})
5934 .addUse(Mul0.getReg(0))
5935 .setMIFlags(Flags);
5936
5937 auto Mul1 = B.buildFMul(F32, LHS, RCP, Flags);
5938
5939 B.buildFMul(Res, Sel, Mul1, Flags);
5940
5941 MI.eraseFromParent();
5942 return true;
5943}
5944
5947 MachineIRBuilder &B) const {
5948 // Bypass the correct expansion a standard promotion through G_FSQRT would
5949 // get. The f32 op is accurate enough for the f16 cas.
5950 unsigned Flags = MI.getFlags();
5951 assert(!ST.has16BitInsts());
5952 auto Ext = B.buildFPExt(F32, MI.getOperand(1), Flags);
5953 auto Log2 = B.buildIntrinsic(Intrinsic::amdgcn_sqrt, {F32})
5954 .addUse(Ext.getReg(0))
5955 .setMIFlags(Flags);
5956 B.buildFPTrunc(MI.getOperand(0), Log2, Flags);
5957 MI.eraseFromParent();
5958 return true;
5959}
5960
5963 MachineIRBuilder &B) const {
5964 MachineFunction &MF = B.getMF();
5965 Register Dst = MI.getOperand(0).getReg();
5966 Register X = MI.getOperand(1).getReg();
5967 const unsigned Flags = MI.getFlags();
5968 const LLT I1 = LLT::integer(1);
5969 const LLT I32 = LLT::integer(32);
5970
5971 if (allowApproxFunc(MF, Flags)) {
5972 B.buildIntrinsic(Intrinsic::amdgcn_sqrt, ArrayRef<Register>({Dst}))
5973 .addUse(X)
5974 .setMIFlags(Flags);
5975 MI.eraseFromParent();
5976 return true;
5977 }
5978
5979 auto ScaleThreshold = B.buildFConstant(F32, 0x1.0p-96f);
5980 auto NeedScale = B.buildFCmp(CmpInst::FCMP_OGT, I1, ScaleThreshold, X, Flags);
5981 auto ScaleUpFactor = B.buildFConstant(F32, 0x1.0p+32f);
5982 auto ScaledX = B.buildFMul(F32, X, ScaleUpFactor, Flags);
5983 auto SqrtX = B.buildSelect(F32, NeedScale, ScaledX, X, Flags);
5984
5986 if (needsDenormHandlingF32(MF, X, Flags)) {
5987 B.buildIntrinsic(Intrinsic::amdgcn_sqrt, ArrayRef<Register>({SqrtS}))
5988 .addUse(SqrtX.getReg(0))
5989 .setMIFlags(Flags);
5990
5991 auto SqrtSInt = B.buildBitcast(I32, SqrtS);
5992 auto NegOne = B.buildConstant(I32, -1);
5993 auto SqrtSNextDown = B.buildBitcast(F32, B.buildAdd(I32, SqrtSInt, NegOne));
5994
5995 auto NegSqrtSNextDown = B.buildFNeg(F32, SqrtSNextDown, Flags);
5996 auto SqrtVP = B.buildFMA(F32, NegSqrtSNextDown, SqrtS, SqrtX, Flags);
5997
5998 auto PosOne = B.buildConstant(I32, 1);
5999 auto SqrtSNextUp = B.buildBitcast(F32, B.buildAdd(I32, SqrtSInt, PosOne));
6000
6001 auto NegSqrtSNextUp = B.buildFNeg(F32, SqrtSNextUp, Flags);
6002 auto SqrtVS = B.buildFMA(F32, NegSqrtSNextUp, SqrtS, SqrtX, Flags);
6003
6004 auto Zero = B.buildFConstant(F32, 0.0f);
6005 auto SqrtVPLE0 = B.buildFCmp(CmpInst::FCMP_OLE, I1, SqrtVP, Zero, Flags);
6006
6007 SqrtS =
6008 B.buildSelect(F32, SqrtVPLE0, SqrtSNextDown, SqrtS, Flags).getReg(0);
6009
6010 auto SqrtVPVSGT0 = B.buildFCmp(CmpInst::FCMP_OGT, I1, SqrtVS, Zero, Flags);
6011 SqrtS =
6012 B.buildSelect(F32, SqrtVPVSGT0, SqrtSNextUp, SqrtS, Flags).getReg(0);
6013 } else {
6014 auto SqrtR =
6015 B.buildIntrinsic(Intrinsic::amdgcn_rsq, {F32}).addReg(SqrtX.getReg(0));
6016 B.buildFMul(SqrtS, SqrtX, SqrtR, Flags);
6017
6018 auto Half = B.buildFConstant(F32, 0.5f);
6019 auto SqrtH = B.buildFMul(F32, SqrtR, Half, Flags);
6020 auto NegSqrtH = B.buildFNeg(F32, SqrtH, Flags);
6021 auto SqrtE = B.buildFMA(F32, NegSqrtH, SqrtS, Half, Flags);
6022 SqrtH = B.buildFMA(F32, SqrtH, SqrtE, SqrtH, Flags);
6023 SqrtS = B.buildFMA(F32, SqrtS, SqrtE, SqrtS, Flags).getReg(0);
6024 auto NegSqrtS = B.buildFNeg(F32, SqrtS, Flags);
6025 auto SqrtD = B.buildFMA(F32, NegSqrtS, SqrtS, SqrtX, Flags);
6026 SqrtS = B.buildFMA(F32, SqrtD, SqrtH, SqrtS, Flags).getReg(0);
6027 }
6028
6029 auto ScaleDownFactor = B.buildFConstant(F32, 0x1.0p-16f);
6030
6031 auto ScaledDown = B.buildFMul(F32, SqrtS, ScaleDownFactor, Flags);
6032
6033 SqrtS = B.buildSelect(F32, NeedScale, ScaledDown, SqrtS, Flags).getReg(0);
6034
6035 auto IsZeroOrInf = B.buildIsFPClass(I1, SqrtX, fcZero | fcPosInf);
6036 B.buildSelect(Dst, IsZeroOrInf, SqrtX, SqrtS, Flags);
6037
6038 MI.eraseFromParent();
6039 return true;
6040}
6041
6044 MachineIRBuilder &B) const {
6045 // For double type, the SQRT and RSQ instructions don't have required
6046 // precision, we apply Goldschmidt's algorithm to improve the result:
6047 //
6048 // y0 = rsq(x)
6049 // g0 = x * y0
6050 // h0 = 0.5 * y0
6051 //
6052 // r0 = 0.5 - h0 * g0
6053 // g1 = g0 * r0 + g0
6054 // h1 = h0 * r0 + h0
6055 //
6056 // r1 = 0.5 - h1 * g1 => d0 = x - g1 * g1
6057 // g2 = g1 * r1 + g1 g2 = d0 * h1 + g1
6058 // h2 = h1 * r1 + h1
6059 //
6060 // r2 = 0.5 - h2 * g2 => d1 = x - g2 * g2
6061 // g3 = g2 * r2 + g2 g3 = d1 * h1 + g2
6062 //
6063 // sqrt(x) = g3
6064
6065 const LLT I1 = LLT::integer(1);
6066 const LLT I32 = LLT::integer(32);
6067
6068 Register Dst = MI.getOperand(0).getReg();
6069 assert(MRI.getType(Dst) == F64 && "only expect to lower f64 sqrt");
6070
6071 Register X = MI.getOperand(1).getReg();
6072 unsigned Flags = MI.getFlags();
6073
6074 Register SqrtX = X;
6075 Register Scaling, ZeroInt;
6076 if (!MI.getFlag(MachineInstr::FmAfn)) {
6077 auto ScaleConstant = B.buildFConstant(F64, 0x1.0p-767);
6078
6079 ZeroInt = B.buildConstant(I32, 0).getReg(0);
6080 Scaling = B.buildFCmp(FCmpInst::FCMP_OLT, I1, X, ScaleConstant).getReg(0);
6081
6082 // Scale up input if it is too small.
6083 auto ScaleUpFactor = B.buildConstant(I32, 256);
6084 auto ScaleUp = B.buildSelect(I32, Scaling, ScaleUpFactor, ZeroInt);
6085 SqrtX = B.buildFLdexp(F64, X, ScaleUp, Flags).getReg(0);
6086 }
6087
6088 auto SqrtY = B.buildIntrinsic(Intrinsic::amdgcn_rsq, {F64}).addReg(SqrtX);
6089
6090 auto Half = B.buildFConstant(F64, 0.5);
6091 auto SqrtH0 = B.buildFMul(F64, SqrtY, Half);
6092 auto SqrtS0 = B.buildFMul(F64, SqrtX, SqrtY);
6093
6094 auto NegSqrtH0 = B.buildFNeg(F64, SqrtH0);
6095 auto SqrtR0 = B.buildFMA(F64, NegSqrtH0, SqrtS0, Half);
6096
6097 auto SqrtS1 = B.buildFMA(F64, SqrtS0, SqrtR0, SqrtS0);
6098 auto SqrtH1 = B.buildFMA(F64, SqrtH0, SqrtR0, SqrtH0);
6099
6100 auto NegSqrtS1 = B.buildFNeg(F64, SqrtS1);
6101 auto SqrtD0 = B.buildFMA(F64, NegSqrtS1, SqrtS1, SqrtX);
6102
6103 auto SqrtS2 = B.buildFMA(F64, SqrtD0, SqrtH1, SqrtS1);
6104
6105 Register SqrtRet = SqrtS2.getReg(0);
6106 if (!MI.getFlag(MachineInstr::FmAfn)) {
6107 auto NegSqrtS2 = B.buildFNeg(F64, SqrtS2);
6108 auto SqrtD1 = B.buildFMA(F64, NegSqrtS2, SqrtS2, SqrtX);
6109 auto SqrtD2 = B.buildFMA(F64, SqrtD1, SqrtH1, SqrtS2);
6110
6111 // Scale down the result.
6112 auto ScaleDownFactor = B.buildConstant(I32, -128);
6113 auto ScaleDown = B.buildSelect(I32, Scaling, ScaleDownFactor, ZeroInt);
6114 SqrtRet = B.buildFLdexp(F64, SqrtD2, ScaleDown, Flags).getReg(0);
6115 }
6116
6117 Register IsZeroOrInf;
6118 if (MI.getFlag(MachineInstr::FmNoInfs)) {
6119 auto ZeroFP = B.buildFConstant(F64, 0.0);
6120 IsZeroOrInf = B.buildFCmp(FCmpInst::FCMP_OEQ, I1, SqrtX, ZeroFP).getReg(0);
6121 } else {
6122 IsZeroOrInf = B.buildIsFPClass(I1, SqrtX, fcZero | fcPosInf).getReg(0);
6123 }
6124
6125 // TODO: Check for DAZ and expand to subnormals
6126
6127 // If x is +INF, +0, or -0, use its original value
6128 B.buildSelect(Dst, IsZeroOrInf, SqrtX, SqrtRet, Flags);
6129
6130 MI.eraseFromParent();
6131 return true;
6132}
6133
6136 MachineIRBuilder &B) const {
6137 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
6138 if (Ty == F32)
6139 return legalizeFSQRTF32(MI, MRI, B);
6140 if (Ty == F64)
6141 return legalizeFSQRTF64(MI, MRI, B);
6142 if (Ty == F16)
6143 return legalizeFSQRTF16(MI, MRI, B);
6144 return false;
6145}
6146
6147// Expand llvm.amdgcn.rsq.clamp on targets that don't support the instruction.
6148// FIXME: Why do we handle this one but not other removed instructions?
6149//
6150// Reciprocal square root. The clamp prevents infinite results, clamping
6151// infinities to max_float. D.f = 1.0 / sqrt(S0.f), result clamped to
6152// +-max_float.
6155 MachineIRBuilder &B) const {
6156 if (ST.getGeneration() < AMDGPUSubtarget::VOLCANIC_ISLANDS)
6157 return true;
6158
6159 Register Dst = MI.getOperand(0).getReg();
6160 Register Src = MI.getOperand(2).getReg();
6161 auto Flags = MI.getFlags();
6162
6163 LLT Ty = MRI.getType(Dst);
6164
6165 const fltSemantics *FltSemantics;
6166 if (Ty == F32)
6167 FltSemantics = &APFloat::IEEEsingle();
6168 else if (Ty == F64)
6169 FltSemantics = &APFloat::IEEEdouble();
6170 else
6171 return false;
6172
6173 auto Rsq = B.buildIntrinsic(Intrinsic::amdgcn_rsq, {Ty})
6174 .addUse(Src)
6175 .setMIFlags(Flags);
6176
6177 // We don't need to concern ourselves with the snan handling difference, since
6178 // the rsq quieted (or not) so use the one which will directly select.
6179 const SIMachineFunctionInfo *MFI = B.getMF().getInfo<SIMachineFunctionInfo>();
6180 const bool UseIEEE = MFI->getMode().IEEE;
6181
6182 auto MaxFlt = B.buildFConstant(Ty, APFloat::getLargest(*FltSemantics));
6183 auto ClampMax = UseIEEE ? B.buildFMinNumIEEE(Ty, Rsq, MaxFlt, Flags) :
6184 B.buildFMinNum(Ty, Rsq, MaxFlt, Flags);
6185
6186 auto MinFlt = B.buildFConstant(Ty, APFloat::getLargest(*FltSemantics, true));
6187
6188 if (UseIEEE)
6189 B.buildFMaxNumIEEE(Dst, ClampMax, MinFlt, Flags);
6190 else
6191 B.buildFMaxNum(Dst, ClampMax, MinFlt, Flags);
6192 MI.eraseFromParent();
6193 return true;
6194}
6195
6196// TODO: Fix pointer type handling
6199 Intrinsic::ID IID) const {
6200
6201 MachineIRBuilder &B = Helper.MIRBuilder;
6202 MachineRegisterInfo &MRI = *B.getMRI();
6203
6204 bool IsPermLane16 = IID == Intrinsic::amdgcn_permlane16 ||
6205 IID == Intrinsic::amdgcn_permlanex16;
6206 bool IsSetInactive = IID == Intrinsic::amdgcn_set_inactive ||
6207 IID == Intrinsic::amdgcn_set_inactive_chain_arg;
6208 bool IsPermlaneShuffle = IID == Intrinsic::amdgcn_permlane_bcast ||
6209 IID == Intrinsic::amdgcn_permlane_up ||
6210 IID == Intrinsic::amdgcn_permlane_down ||
6211 IID == Intrinsic::amdgcn_permlane_xor;
6212
6213 auto createLaneOp = [&IID, &B, &MI](Register Src0, Register Src1,
6214 Register Src2, LLT VT) -> Register {
6215 auto LaneOp = B.buildIntrinsic(IID, {VT}).addUse(Src0);
6216 switch (IID) {
6217 case Intrinsic::amdgcn_readfirstlane:
6218 case Intrinsic::amdgcn_permlane64:
6219 return LaneOp.getReg(0);
6220 case Intrinsic::amdgcn_readlane:
6221 case Intrinsic::amdgcn_set_inactive:
6222 case Intrinsic::amdgcn_set_inactive_chain_arg:
6223 return LaneOp.addUse(Src1).getReg(0);
6224 case Intrinsic::amdgcn_writelane:
6225 case Intrinsic::amdgcn_permlane_bcast:
6226 case Intrinsic::amdgcn_permlane_up:
6227 case Intrinsic::amdgcn_permlane_down:
6228 case Intrinsic::amdgcn_permlane_xor:
6229 return LaneOp.addUse(Src1).addUse(Src2).getReg(0);
6230 case Intrinsic::amdgcn_permlane16:
6231 case Intrinsic::amdgcn_permlanex16: {
6232 Register Src3 = MI.getOperand(5).getReg();
6233 int64_t Src4 = MI.getOperand(6).getImm();
6234 int64_t Src5 = MI.getOperand(7).getImm();
6235 return LaneOp.addUse(Src1)
6236 .addUse(Src2)
6237 .addUse(Src3)
6238 .addImm(Src4)
6239 .addImm(Src5)
6240 .getReg(0);
6241 }
6242 case Intrinsic::amdgcn_mov_dpp8:
6243 return LaneOp.addImm(MI.getOperand(3).getImm()).getReg(0);
6244 case Intrinsic::amdgcn_update_dpp:
6245 return LaneOp.addUse(Src1)
6246 .addImm(MI.getOperand(4).getImm())
6247 .addImm(MI.getOperand(5).getImm())
6248 .addImm(MI.getOperand(6).getImm())
6249 .addImm(MI.getOperand(7).getImm())
6250 .getReg(0);
6251 default:
6252 llvm_unreachable("unhandled lane op");
6253 }
6254 };
6255
6256 Register DstReg = MI.getOperand(0).getReg();
6257 Register Src0 = MI.getOperand(2).getReg();
6258 Register Src1, Src2;
6259 if (IID == Intrinsic::amdgcn_readlane || IID == Intrinsic::amdgcn_writelane ||
6260 IID == Intrinsic::amdgcn_update_dpp || IsSetInactive || IsPermLane16 ||
6261 IsPermlaneShuffle) {
6262 Src1 = MI.getOperand(3).getReg();
6263 if (IID == Intrinsic::amdgcn_writelane || IsPermLane16 ||
6264 IsPermlaneShuffle) {
6265 Src2 = MI.getOperand(4).getReg();
6266 }
6267 }
6268
6269 LLT Ty = MRI.getType(DstReg);
6270 unsigned Size = Ty.getSizeInBits();
6271
6272 unsigned SplitSize = 32;
6273 if (IID == Intrinsic::amdgcn_update_dpp && (Size % 64 == 0) &&
6274 ST.hasDPALU_DPP() &&
6275 AMDGPU::isLegalDPALU_DPPControl(ST, MI.getOperand(4).getImm()))
6276 SplitSize = 64;
6277
6278 if (Size == SplitSize) {
6279 // Already legal
6280 return true;
6281 }
6282
6283 const LLT I32 = LLT::integer(32);
6284
6285 bool IsFloat = Ty.getScalarType().isFloat();
6286
6287 LLT IntTy = IsFloat ? LLT::integer(Size) : Ty;
6288 if (IsFloat) {
6289 Src0 = B.buildBitcast(IntTy, Src0).getReg(0);
6290 if (Src1 && MRI.getType(Src1).getScalarType().isFloat())
6291 Src1 = B.buildBitcast(IntTy, Src1).getReg(0);
6292 if (Src2 && MRI.getType(Src2).getScalarType().isFloat())
6293 Src2 = B.buildBitcast(IntTy, Src2).getReg(0);
6294 }
6295
6296 if (Size < 32) {
6297 Src0 = B.buildAnyExt(I32, Src0).getReg(0);
6298
6299 if (IID == Intrinsic::amdgcn_update_dpp || IsSetInactive || IsPermLane16)
6300 Src1 = B.buildAnyExt(I32, Src1).getReg(0);
6301
6302 if (IID == Intrinsic::amdgcn_writelane)
6303 Src2 = B.buildAnyExt(I32, Src2).getReg(0);
6304
6305 Register LaneOpDst = createLaneOp(Src0, Src1, Src2, I32);
6306 if (IsFloat)
6307 B.buildBitcast(DstReg, B.buildTrunc(IntTy, LaneOpDst));
6308 else
6309 B.buildTrunc(DstReg, LaneOpDst);
6310 MI.eraseFromParent();
6311 return true;
6312 }
6313
6314 if (Size % SplitSize != 0)
6315 return false;
6316
6317 LLT PartialResTy = LLT::integer(SplitSize);
6318 bool NeedsBitcast = false;
6319 if (IntTy.isVector()) {
6320 LLT EltTy = IntTy.getElementType();
6321 unsigned EltSize = EltTy.getSizeInBits();
6322 if (EltSize == SplitSize) {
6323 PartialResTy = EltTy;
6324 } else if (EltSize == 16 || EltSize == 32) {
6325 unsigned NElem = SplitSize / EltSize;
6326 PartialResTy = IntTy.changeElementCount(ElementCount::getFixed(NElem));
6327 } else {
6328 NeedsBitcast = true;
6329 }
6330 }
6331
6332 SmallVector<Register, 4> PartialRes;
6333 unsigned NumParts = Size / SplitSize;
6334 MachineInstrBuilder Src0Parts = B.buildUnmerge(PartialResTy, Src0);
6335 MachineInstrBuilder Src1Parts, Src2Parts;
6336
6337 if (IID == Intrinsic::amdgcn_update_dpp || IsSetInactive || IsPermLane16)
6338 Src1Parts = B.buildUnmerge(PartialResTy, Src1);
6339
6340 if (IID == Intrinsic::amdgcn_writelane)
6341 Src2Parts = B.buildUnmerge(PartialResTy, Src2);
6342
6343 for (unsigned i = 0; i < NumParts; ++i) {
6344 Src0 = Src0Parts.getReg(i);
6345
6346 if (IID == Intrinsic::amdgcn_update_dpp || IsSetInactive || IsPermLane16)
6347 Src1 = Src1Parts.getReg(i);
6348
6349 if (IID == Intrinsic::amdgcn_writelane)
6350 Src2 = Src2Parts.getReg(i);
6351
6352 PartialRes.push_back(createLaneOp(Src0, Src1, Src2, PartialResTy));
6353 }
6354
6355 if (NeedsBitcast || IsFloat)
6356 B.buildBitcast(
6357 DstReg,
6358 B.buildMergeLikeInstr(LLT::integer(IntTy.getSizeInBits()), PartialRes));
6359 else
6360 B.buildMergeLikeInstr(DstReg, PartialRes);
6361
6362 MI.eraseFromParent();
6363 return true;
6364}
6365
6368 MachineIRBuilder &B) const {
6369 uint64_t Offset =
6370 ST.getTargetLowering()->getImplicitParameterOffset(
6372 LLT DstTy = MRI.getType(DstReg);
6373 LLT IdxTy = LLT::integer(DstTy.getSizeInBits());
6374
6375 Register KernargPtrReg = MRI.createGenericVirtualRegister(DstTy);
6376 if (!loadInputValue(KernargPtrReg, B,
6378 return false;
6379
6380 B.buildObjectPtrOffset(DstReg, KernargPtrReg,
6381 B.buildConstant(IdxTy, Offset).getReg(0));
6382 return true;
6383}
6384
6385/// To create a buffer resource from a 64-bit pointer, mask off the upper 32
6386/// bits of the pointer and replace them with the stride argument, then
6387/// merge_values everything together. In the common case of a raw buffer (the
6388/// stride component is 0), we can just AND off the upper half.
6391 Register Result = MI.getOperand(0).getReg();
6392 Register Pointer = MI.getOperand(2).getReg();
6393 Register Stride = MI.getOperand(3).getReg();
6394 Register NumRecords = MI.getOperand(4).getReg();
6395 Register Flags = MI.getOperand(5).getReg();
6396
6397 LLT I32 = LLT::integer(32);
6398 LLT I64 = LLT::integer(64);
6399
6400 B.setInsertPt(B.getMBB(), ++B.getInsertPt());
6401
6402 auto ExtStride = B.buildAnyExt(I32, Stride);
6403
6404 if (ST.getBufferResourceNumRecordsWidth() == 45) {
6405 NumRecords = B.buildZExtOrTrunc(I64, NumRecords).getReg(0);
6406 NumRecords =
6407 B.buildAnd(I64, NumRecords, B.buildConstant(I64, (1ULL << 45) - 1))
6408 .getReg(0);
6409 Register Zero = B.buildConstant(I32, 0).getReg(0);
6410 // Build the lower 64-bit value, which has a 57-bit base and the lower 7-bit
6411 // num_records.
6412 LLT PtrIntTy = LLT::integer(MRI.getType(Pointer).getSizeInBits());
6413 auto PointerInt = B.buildPtrToInt(PtrIntTy, Pointer);
6414 auto ExtPointer = B.buildAnyExtOrTrunc(I64, PointerInt);
6415 auto NumRecordsLHS = B.buildShl(I64, NumRecords, B.buildConstant(I32, 57));
6416 Register LowHalf = B.buildOr(I64, ExtPointer, NumRecordsLHS).getReg(0);
6417
6418 // Build the higher 64-bit value, which has the higher 38-bit num_records,
6419 // 6-bit zero (omit), 16-bit stride and scale and 4-bit flag.
6420 auto NumRecordsRHS = B.buildLShr(I64, NumRecords, B.buildConstant(I32, 7));
6421 auto ShiftedStride = B.buildShl(I32, ExtStride, B.buildConstant(I32, 12));
6422 auto ExtShiftedStride =
6423 B.buildMergeValues(I64, {Zero, ShiftedStride.getReg(0)});
6424 auto ShiftedFlags = B.buildShl(I32, Flags, B.buildConstant(I32, 28));
6425 auto ExtShiftedFlags =
6426 B.buildMergeValues(I64, {Zero, ShiftedFlags.getReg(0)});
6427 auto CombinedFields = B.buildOr(I64, NumRecordsRHS, ExtShiftedStride);
6428 Register HighHalf =
6429 B.buildOr(I64, CombinedFields, ExtShiftedFlags).getReg(0);
6430 B.buildMergeValues(Result, {LowHalf, HighHalf});
6431 } else {
6432 NumRecords = B.buildZExtOrTrunc(I32, NumRecords).getReg(0);
6433 auto Unmerge = B.buildUnmerge(I32, Pointer);
6434 auto LowHalf = Unmerge.getReg(0);
6435 auto HighHalf = Unmerge.getReg(1);
6436
6437 auto AndMask = B.buildConstant(I32, 0x0000ffff);
6438 auto Masked = B.buildAnd(I32, HighHalf, AndMask);
6439 auto ShiftConst = B.buildConstant(I32, 16);
6440 auto ShiftedStride = B.buildShl(I32, ExtStride, ShiftConst);
6441 auto NewHighHalf = B.buildOr(I32, Masked, ShiftedStride);
6442 Register NewHighHalfReg = NewHighHalf.getReg(0);
6443 B.buildMergeValues(Result, {LowHalf, NewHighHalfReg, NumRecords, Flags});
6444 }
6445
6446 MI.eraseFromParent();
6447 return true;
6448}
6449
6452 MachineIRBuilder &B) const {
6453 const SIMachineFunctionInfo *MFI = B.getMF().getInfo<SIMachineFunctionInfo>();
6454 if (!MFI->isEntryFunction()) {
6455 return legalizePreloadedArgIntrin(MI, MRI, B,
6457 }
6458
6459 Register DstReg = MI.getOperand(0).getReg();
6460 if (!getImplicitArgPtr(DstReg, MRI, B))
6461 return false;
6462
6463 MI.eraseFromParent();
6464 return true;
6465}
6466
6469 MachineIRBuilder &B) const {
6470 Function &F = B.getMF().getFunction();
6471 std::optional<uint32_t> KnownSize =
6473 if (KnownSize.has_value())
6474 B.buildConstant(DstReg, *KnownSize);
6475 return false;
6476}
6477
6480 MachineIRBuilder &B) const {
6481
6482 const SIMachineFunctionInfo *MFI = B.getMF().getInfo<SIMachineFunctionInfo>();
6483 if (!MFI->isEntryFunction()) {
6484 return legalizePreloadedArgIntrin(MI, MRI, B,
6486 }
6487
6488 Register DstReg = MI.getOperand(0).getReg();
6489 if (!getLDSKernelId(DstReg, MRI, B))
6490 return false;
6491
6492 MI.eraseFromParent();
6493 return true;
6494}
6495
6499 unsigned AddrSpace) const {
6500 const LLT I32 = LLT::integer(32);
6501 auto Unmerge = B.buildUnmerge(I32, MI.getOperand(2).getReg());
6502 Register Hi32 = Unmerge.getReg(1);
6503
6504 if (AddrSpace == AMDGPUAS::PRIVATE_ADDRESS &&
6505 ST.hasGloballyAddressableScratch()) {
6506 Register FlatScratchBaseHi =
6507 B.buildInstr(AMDGPU::S_MOV_B32, {I32},
6508 {Register(AMDGPU::SRC_FLAT_SCRATCH_BASE_HI)})
6509 .getReg(0);
6510 MRI.setRegClass(FlatScratchBaseHi, &AMDGPU::SReg_32RegClass);
6511 // Test bits 63..58 against the aperture address.
6512 Register XOR = B.buildXor(I32, Hi32, FlatScratchBaseHi).getReg(0);
6513 B.buildICmp(ICmpInst::ICMP_ULT, MI.getOperand(0), XOR,
6514 B.buildConstant(I32, 1u << 26));
6515 } else {
6516 Register ApertureReg = getSegmentAperture(AddrSpace, MRI, B);
6517 B.buildICmp(ICmpInst::ICMP_EQ, MI.getOperand(0), Hi32, ApertureReg);
6518 }
6519 MI.eraseFromParent();
6520 return true;
6521}
6522
6523// The raw.(t)buffer and struct.(t)buffer intrinsics have two offset args:
6524// offset (the offset that is included in bounds checking and swizzling, to be
6525// split between the instruction's voffset and immoffset fields) and soffset
6526// (the offset that is excluded from bounds checking and swizzling, to go in
6527// the instruction's soffset field). This function takes the first kind of
6528// offset and figures out how to split it between voffset and immoffset.
6529std::pair<Register, unsigned>
6531 Register OrigOffset) const {
6532 const unsigned MaxImm = SIInstrInfo::getMaxMUBUFImmOffset(ST);
6533 Register BaseReg;
6534 unsigned ImmOffset;
6535 const LLT I32 = LLT::integer(32);
6536 MachineRegisterInfo &MRI = *B.getMRI();
6537
6538 // On GFX1250+, voffset and immoffset are zero-extended from 32 bits before
6539 // being added, so we can only safely match a 32-bit addition with no unsigned
6540 // overflow.
6541 bool CheckNUW = ST.hasGFX1250Insts();
6542 std::tie(BaseReg, ImmOffset) = AMDGPU::getBaseWithConstantOffset(
6543 MRI, OrigOffset, /*KnownBits=*/nullptr, CheckNUW);
6544
6545 // If BaseReg is a pointer, convert it to int.
6546 if (MRI.getType(BaseReg).isPointer())
6547 BaseReg = B.buildPtrToInt(MRI.getType(OrigOffset), BaseReg).getReg(0);
6548
6549 // If the immediate value is too big for the immoffset field, put only bits
6550 // that would normally fit in the immoffset field. The remaining value that
6551 // is copied/added for the voffset field is a large power of 2, and it
6552 // stands more chance of being CSEd with the copy/add for another similar
6553 // load/store.
6554 // However, do not do that rounding down if that is a negative
6555 // number, as it appears to be illegal to have a negative offset in the
6556 // vgpr, even if adding the immediate offset makes it positive.
6557 unsigned Overflow = ImmOffset & ~MaxImm;
6558 ImmOffset -= Overflow;
6559 if ((int32_t)Overflow < 0) {
6560 Overflow += ImmOffset;
6561 ImmOffset = 0;
6562 }
6563
6564 if (Overflow != 0) {
6565 if (!BaseReg) {
6566 BaseReg = B.buildConstant(I32, Overflow).getReg(0);
6567 } else {
6568 auto OverflowVal = B.buildConstant(I32, Overflow);
6569 BaseReg = B.buildAdd(I32, BaseReg, OverflowVal).getReg(0);
6570 }
6571 }
6572
6573 if (!BaseReg)
6574 BaseReg = B.buildConstant(I32, 0).getReg(0);
6575
6576 return std::pair(BaseReg, ImmOffset);
6577}
6578
6579/// Handle register layout difference for f16 images for some subtargets.
6582 Register Reg,
6583 bool ImageStore) const {
6584 const LLT I16 = LLT::integer(16);
6585 const LLT I32 = LLT::integer(32);
6586 LLT StoreVT = MRI.getType(Reg);
6587 assert(StoreVT.isVector() && StoreVT.getElementType().getSizeInBits() == 16);
6588
6589 LLT I16Vec = StoreVT.changeElementType(I16);
6590 Register RegI16 =
6591 StoreVT == I16Vec ? Reg : B.buildBitcast(I16Vec, Reg).getReg(0);
6592
6593 if (ST.hasUnpackedD16VMem()) {
6594 auto Unmerge = B.buildUnmerge(I16, RegI16);
6595
6596 SmallVector<Register, 4> WideRegs;
6597 for (int I = 0, E = Unmerge->getNumOperands() - 1; I != E; ++I)
6598 WideRegs.push_back(B.buildAnyExt(I32, Unmerge.getReg(I)).getReg(0));
6599
6600 int NumElts = StoreVT.getNumElements();
6601
6602 return B.buildBuildVector(LLT::fixed_vector(NumElts, I32), WideRegs)
6603 .getReg(0);
6604 }
6605
6606 if (ImageStore && ST.hasImageStoreD16Bug()) {
6607 if (StoreVT.getNumElements() == 2) {
6608 SmallVector<Register, 4> PackedRegs;
6609 Reg = B.buildBitcast(I32, RegI16).getReg(0);
6610 PackedRegs.push_back(Reg);
6611 PackedRegs.resize(2, B.buildUndef(I32).getReg(0));
6612 return B.buildBuildVector(LLT::fixed_vector(2, I32), PackedRegs)
6613 .getReg(0);
6614 }
6615
6616 if (StoreVT.getNumElements() == 3) {
6617 SmallVector<Register, 4> PackedRegs;
6618 auto Unmerge = B.buildUnmerge(I16, RegI16);
6619 for (int I = 0, E = Unmerge->getNumOperands() - 1; I != E; ++I)
6620 PackedRegs.push_back(Unmerge.getReg(I));
6621 PackedRegs.resize(6, B.buildUndef(I16).getReg(0));
6622 Reg = B.buildBuildVector(LLT::fixed_vector(6, I16), PackedRegs).getReg(0);
6623 return B.buildBitcast(LLT::fixed_vector(3, I32), Reg).getReg(0);
6624 }
6625
6626 if (StoreVT.getNumElements() == 4) {
6627 SmallVector<Register, 4> PackedRegs;
6628 Reg = B.buildBitcast(LLT::fixed_vector(2, I32), RegI16).getReg(0);
6629 auto Unmerge = B.buildUnmerge(I32, Reg);
6630 for (int I = 0, E = Unmerge->getNumOperands() - 1; I != E; ++I)
6631 PackedRegs.push_back(Unmerge.getReg(I));
6632 PackedRegs.resize(4, B.buildUndef(I32).getReg(0));
6633 return B.buildBuildVector(LLT::fixed_vector(4, I32), PackedRegs)
6634 .getReg(0);
6635 }
6636
6637 llvm_unreachable("invalid data type");
6638 }
6639
6640 if (StoreVT.isVector() && StoreVT.getNumElements() == 3 &&
6641 StoreVT.getElementType().getSizeInBits() == 16) {
6642 Reg = B.buildPadVectorWithUndefElements(
6643 LLT::fixed_vector(4, StoreVT.getElementType()), Reg)
6644 .getReg(0);
6645 }
6646 return Reg;
6647}
6648
6650 Register VData, LLT MemTy,
6651 bool IsFormat) const {
6652 MachineRegisterInfo *MRI = B.getMRI();
6653 LLT Ty = MRI->getType(VData);
6654
6655 // Fixup buffer resources themselves needing to be v4i128.
6657 return castBufferRsrcToV4I32(VData, B);
6658
6659 if (shouldBitcastLoadStoreType(ST, Ty, MemTy)) {
6660 Ty = getBitcastRegisterType(Ty);
6661 VData = B.buildBitcast(Ty, VData).getReg(0);
6662 }
6663 // Fixup illegal register types for i8 stores.
6664 if (Ty == LLT::integer(8) || Ty == LLT::integer(16) || Ty == F16) {
6665 Register AnyExt = B.buildAnyExt(LLT::integer(32), VData).getReg(0);
6666 return AnyExt;
6667 }
6668
6669 if (Ty.isVector()) {
6670 if (Ty.getElementType().getSizeInBits() == 16 && Ty.getNumElements() <= 4) {
6671 if (IsFormat)
6672 return handleD16VData(B, *MRI, VData);
6673 }
6674 }
6675
6676 return VData;
6677}
6678
6680 LegalizerHelper &Helper,
6681 bool IsTyped,
6682 bool IsFormat) const {
6683 MachineIRBuilder &B = Helper.MIRBuilder;
6684 MachineRegisterInfo &MRI = *B.getMRI();
6685
6686 Register VData = MI.getOperand(1).getReg();
6687 LLT Ty = MRI.getType(VData);
6688 LLT EltTy = Ty.getScalarType();
6689 const bool IsD16 = IsFormat && (EltTy.getSizeInBits() == 16);
6690 const LLT I32 = LLT::integer(32);
6691
6692 MachineMemOperand *MMO = *MI.memoperands_begin();
6693 const int MemSize = MMO->getSize().getValue();
6694 LLT MemTy = MMO->getMemoryType();
6695
6696 if (IsFormat && !IsTyped && !IsD16 && MemTy.getSizeInBits() < 32) {
6697 const Function &Fn = B.getMF().getFunction();
6699 Fn, "unsupported sub-dword format buffer store", MI.getDebugLoc()));
6700 MI.eraseFromParent();
6701 return true;
6702 }
6703
6704 VData = fixStoreSourceType(B, VData, MemTy, IsFormat);
6705
6707 Register RSrc = MI.getOperand(2).getReg();
6708
6709 unsigned ImmOffset;
6710
6711 // The typed intrinsics add an immediate after the registers.
6712 const unsigned NumVIndexOps = IsTyped ? 8 : 7;
6713
6714 // The struct intrinsic variants add one additional operand over raw.
6715 const bool HasVIndex = MI.getNumOperands() == NumVIndexOps;
6716 Register VIndex;
6717 int OpOffset = 0;
6718 if (HasVIndex) {
6719 VIndex = MI.getOperand(3).getReg();
6720 OpOffset = 1;
6721 } else {
6722 VIndex = B.buildConstant(I32, 0).getReg(0);
6723 }
6724
6725 Register VOffset = MI.getOperand(3 + OpOffset).getReg();
6726 Register SOffset = MI.getOperand(4 + OpOffset).getReg();
6727
6728 unsigned Format = 0;
6729 if (IsTyped) {
6730 Format = MI.getOperand(5 + OpOffset).getImm();
6731 ++OpOffset;
6732 }
6733
6734 unsigned AuxiliaryData = MI.getOperand(5 + OpOffset).getImm();
6735
6736 std::tie(VOffset, ImmOffset) = splitBufferOffsets(B, VOffset);
6737
6738 unsigned Opc;
6739 if (IsTyped) {
6740 Opc = IsD16 ? AMDGPU::G_AMDGPU_TBUFFER_STORE_FORMAT_D16 :
6741 AMDGPU::G_AMDGPU_TBUFFER_STORE_FORMAT;
6742 } else if (IsFormat) {
6743 Opc = IsD16 ? AMDGPU::G_AMDGPU_BUFFER_STORE_FORMAT_D16 :
6744 AMDGPU::G_AMDGPU_BUFFER_STORE_FORMAT;
6745 } else {
6746 switch (MemSize) {
6747 case 1:
6748 Opc = AMDGPU::G_AMDGPU_BUFFER_STORE_BYTE;
6749 break;
6750 case 2:
6751 Opc = AMDGPU::G_AMDGPU_BUFFER_STORE_SHORT;
6752 break;
6753 default:
6754 Opc = AMDGPU::G_AMDGPU_BUFFER_STORE;
6755 break;
6756 }
6757 }
6758
6759 auto MIB = B.buildInstr(Opc)
6760 .addUse(VData) // vdata
6761 .addUse(RSrc) // rsrc
6762 .addUse(VIndex) // vindex
6763 .addUse(VOffset) // voffset
6764 .addUse(SOffset) // soffset
6765 .addImm(ImmOffset); // offset(imm)
6766
6767 if (IsTyped)
6768 MIB.addImm(Format);
6769
6770 MIB.addImm(AuxiliaryData) // cachepolicy, swizzled buffer(imm)
6771 .addImm(HasVIndex ? -1 : 0) // idxen(imm)
6772 .addMemOperand(MMO);
6773
6774 MI.eraseFromParent();
6775 return true;
6776}
6777
6778static void buildBufferLoad(unsigned Opc, Register LoadDstReg, Register RSrc,
6779 Register VIndex, Register VOffset, Register SOffset,
6780 unsigned ImmOffset, unsigned Format,
6781 unsigned AuxiliaryData, MachineMemOperand *MMO,
6782 bool IsTyped, bool HasVIndex, MachineIRBuilder &B) {
6783 auto MIB = B.buildInstr(Opc)
6784 .addDef(LoadDstReg) // vdata
6785 .addUse(RSrc) // rsrc
6786 .addUse(VIndex) // vindex
6787 .addUse(VOffset) // voffset
6788 .addUse(SOffset) // soffset
6789 .addImm(ImmOffset); // offset(imm)
6790
6791 if (IsTyped)
6792 MIB.addImm(Format);
6793
6794 MIB.addImm(AuxiliaryData) // cachepolicy, swizzled buffer(imm)
6795 .addImm(HasVIndex ? -1 : 0) // idxen(imm)
6796 .addMemOperand(MMO);
6797}
6798
6800 LegalizerHelper &Helper,
6801 bool IsFormat,
6802 bool IsTyped) const {
6803 MachineIRBuilder &B = Helper.MIRBuilder;
6804 MachineRegisterInfo &MRI = *B.getMRI();
6805 GISelChangeObserver &Observer = Helper.Observer;
6806
6807 // FIXME: Verifier should enforce 1 MMO for these intrinsics.
6808 MachineMemOperand *MMO = *MI.memoperands_begin();
6809 const LLT MemTy = MMO->getMemoryType();
6810 const LLT I32 = LLT::integer(32);
6811
6812 Register Dst = MI.getOperand(0).getReg();
6813
6814 Register StatusDst;
6815 int OpOffset = 0;
6816 assert(MI.getNumExplicitDefs() == 1 || MI.getNumExplicitDefs() == 2);
6817 bool IsTFE = MI.getNumExplicitDefs() == 2;
6818 if (IsTFE) {
6819 StatusDst = MI.getOperand(1).getReg();
6820 ++OpOffset;
6821 }
6822
6823 castBufferRsrcArgToV4I32(MI, B, 2 + OpOffset);
6824 Register RSrc = MI.getOperand(2 + OpOffset).getReg();
6825
6826 // The typed intrinsics add an immediate after the registers.
6827 const unsigned NumVIndexOps = IsTyped ? 8 : 7;
6828
6829 // The struct intrinsic variants add one additional operand over raw.
6830 const bool HasVIndex = MI.getNumOperands() == NumVIndexOps + OpOffset;
6831 Register VIndex;
6832 if (HasVIndex) {
6833 VIndex = MI.getOperand(3 + OpOffset).getReg();
6834 ++OpOffset;
6835 } else {
6836 VIndex = B.buildConstant(I32, 0).getReg(0);
6837 }
6838
6839 Register VOffset = MI.getOperand(3 + OpOffset).getReg();
6840 Register SOffset = MI.getOperand(4 + OpOffset).getReg();
6841
6842 unsigned Format = 0;
6843 if (IsTyped) {
6844 Format = MI.getOperand(5 + OpOffset).getImm();
6845 ++OpOffset;
6846 }
6847
6848 unsigned AuxiliaryData = MI.getOperand(5 + OpOffset).getImm();
6849 unsigned ImmOffset;
6850
6851 LLT Ty = MRI.getType(Dst);
6852 // Make addrspace 8 pointers loads into 4xi32 loads here, so the rest of the
6853 // logic doesn't have to handle that case.
6854 if (hasBufferRsrcWorkaround(Ty)) {
6855 Observer.changingInstr(MI);
6856 Ty = castBufferRsrcFromV4I32(MI, B, MRI, 0);
6857 Observer.changedInstr(MI);
6858 Dst = MI.getOperand(0).getReg();
6859 B.setInsertPt(B.getMBB(), MI);
6860 }
6861 if (shouldBitcastLoadStoreType(ST, Ty, MemTy)) {
6862 Ty = getBitcastRegisterType(Ty);
6863 Observer.changingInstr(MI);
6864 Helper.bitcastDst(MI, Ty, 0);
6865 Observer.changedInstr(MI);
6866 Dst = MI.getOperand(0).getReg();
6867 B.setInsertPt(B.getMBB(), MI);
6868 }
6869
6870 LLT EltTy = Ty.getScalarType();
6871 const bool IsD16 = IsFormat && (EltTy.getSizeInBits() == 16);
6872 const bool Unpacked = ST.hasUnpackedD16VMem();
6873
6874 if (IsFormat && !IsTyped && !IsD16 && MemTy.getSizeInBits() < 32) {
6875 const Function &Fn = B.getMF().getFunction();
6877 Fn, "unsupported sub-dword format buffer load", MI.getDebugLoc()));
6878 B.buildUndef(Dst);
6879 if (IsTFE)
6880 B.buildUndef(StatusDst);
6881 MI.eraseFromParent();
6882 return true;
6883 }
6884
6885 std::tie(VOffset, ImmOffset) = splitBufferOffsets(B, VOffset);
6886
6887 unsigned Opc;
6888
6889 // TODO: Support TFE for typed and narrow loads.
6890 if (IsTyped) {
6891 if (IsTFE)
6892 return false;
6893 Opc = IsD16 ? AMDGPU::G_AMDGPU_TBUFFER_LOAD_FORMAT_D16 :
6894 AMDGPU::G_AMDGPU_TBUFFER_LOAD_FORMAT;
6895 } else if (IsFormat) {
6896 if (IsD16) {
6897 if (IsTFE)
6898 return false;
6899 Opc = AMDGPU::G_AMDGPU_BUFFER_LOAD_FORMAT_D16;
6900 } else {
6901 Opc = IsTFE ? AMDGPU::G_AMDGPU_BUFFER_LOAD_FORMAT_TFE
6902 : AMDGPU::G_AMDGPU_BUFFER_LOAD_FORMAT;
6903 }
6904 } else {
6905 switch (MemTy.getSizeInBits()) {
6906 case 8:
6907 Opc = IsTFE ? AMDGPU::G_AMDGPU_BUFFER_LOAD_UBYTE_TFE
6908 : AMDGPU::G_AMDGPU_BUFFER_LOAD_UBYTE;
6909 break;
6910 case 16:
6911 Opc = IsTFE ? AMDGPU::G_AMDGPU_BUFFER_LOAD_USHORT_TFE
6912 : AMDGPU::G_AMDGPU_BUFFER_LOAD_USHORT;
6913 break;
6914 default:
6915 Opc = IsTFE ? AMDGPU::G_AMDGPU_BUFFER_LOAD_TFE
6916 : AMDGPU::G_AMDGPU_BUFFER_LOAD;
6917 break;
6918 }
6919 }
6920
6921 if (IsTFE) {
6922 unsigned NumValueDWords = divideCeil(Ty.getSizeInBits(), 32);
6923 unsigned NumLoadDWords = NumValueDWords + 1;
6924 LLT LoadTy = LLT::fixed_vector(NumLoadDWords, I32);
6925 Register LoadDstReg = B.getMRI()->createGenericVirtualRegister(LoadTy);
6926 buildBufferLoad(Opc, LoadDstReg, RSrc, VIndex, VOffset, SOffset, ImmOffset,
6927 Format, AuxiliaryData, MMO, IsTyped, HasVIndex, B);
6928 bool IsFloat = Ty.getScalarType().isFloat();
6929 LLT DstIntTy =
6930 IsFloat ? Ty.changeElementType(LLT::integer(EltTy.getSizeInBits()))
6931 : Ty;
6932 Register DstInt =
6933 IsFloat ? B.getMRI()->createGenericVirtualRegister(DstIntTy) : Dst;
6934 if (MemTy.getSizeInBits() < 32) {
6935 Register ExtDst = B.getMRI()->createGenericVirtualRegister(I32);
6936 B.buildUnmerge({ExtDst, StatusDst}, LoadDstReg);
6937 B.buildTrunc(DstInt, ExtDst);
6938 } else if (NumValueDWords == 1) {
6939 B.buildUnmerge({DstInt, StatusDst}, LoadDstReg);
6940 } else {
6941 SmallVector<Register, 5> LoadElts;
6942 for (unsigned I = 0; I != NumValueDWords; ++I)
6943 LoadElts.push_back(B.getMRI()->createGenericVirtualRegister(I32));
6944 LoadElts.push_back(StatusDst);
6945 B.buildUnmerge(LoadElts, LoadDstReg);
6946 LoadElts.truncate(NumValueDWords);
6947 B.buildMergeLikeInstr(DstInt, LoadElts);
6948 }
6949 if (DstInt != Dst)
6950 B.buildBitcast(Dst, DstInt);
6951 } else if ((!IsD16 && MemTy.getSizeInBits() < 32) ||
6952 (IsD16 && !Ty.isVector())) {
6953 Register LoadDstReg = B.getMRI()->createGenericVirtualRegister(I32);
6954 buildBufferLoad(Opc, LoadDstReg, RSrc, VIndex, VOffset, SOffset, ImmOffset,
6955 Format, AuxiliaryData, MMO, IsTyped, HasVIndex, B);
6956 B.setInsertPt(B.getMBB(), ++B.getInsertPt());
6957 B.buildTrunc(Dst, LoadDstReg);
6958 } else if (Unpacked && IsD16 && Ty.isVector()) {
6959 LLT UnpackedTy = LLT::fixed_vector(Ty.getNumElements(), LLT::integer(32));
6960 Register LoadDstReg = B.getMRI()->createGenericVirtualRegister(UnpackedTy);
6961 buildBufferLoad(Opc, LoadDstReg, RSrc, VIndex, VOffset, SOffset, ImmOffset,
6962 Format, AuxiliaryData, MMO, IsTyped, HasVIndex, B);
6963 B.setInsertPt(B.getMBB(), ++B.getInsertPt());
6964 // FIXME: G_TRUNC should work, but legalization currently fails
6965 auto Unmerge = B.buildUnmerge(I32, LoadDstReg);
6967 for (unsigned I = 0, N = Unmerge->getNumOperands() - 1; I != N; ++I)
6968 Repack.push_back(B.buildTrunc(EltTy, Unmerge.getReg(I)).getReg(0));
6969 B.buildMergeLikeInstr(Dst, Repack);
6970 } else {
6971 buildBufferLoad(Opc, Dst, RSrc, VIndex, VOffset, SOffset, ImmOffset, Format,
6972 AuxiliaryData, MMO, IsTyped, HasVIndex, B);
6973 }
6974
6975 MI.eraseFromParent();
6976 return true;
6977}
6978
6979static unsigned getBufferAtomicPseudo(Intrinsic::ID IntrID) {
6980 switch (IntrID) {
6981 case Intrinsic::amdgcn_raw_buffer_atomic_swap:
6982 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_swap:
6983 case Intrinsic::amdgcn_struct_buffer_atomic_swap:
6984 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_swap:
6985 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_SWAP;
6986 case Intrinsic::amdgcn_raw_buffer_atomic_add:
6987 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_add:
6988 case Intrinsic::amdgcn_struct_buffer_atomic_add:
6989 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_add:
6990 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_ADD;
6991 case Intrinsic::amdgcn_raw_buffer_atomic_sub:
6992 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_sub:
6993 case Intrinsic::amdgcn_struct_buffer_atomic_sub:
6994 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_sub:
6995 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_SUB;
6996 case Intrinsic::amdgcn_raw_buffer_atomic_smin:
6997 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_smin:
6998 case Intrinsic::amdgcn_struct_buffer_atomic_smin:
6999 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_smin:
7000 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_SMIN;
7001 case Intrinsic::amdgcn_raw_buffer_atomic_umin:
7002 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_umin:
7003 case Intrinsic::amdgcn_struct_buffer_atomic_umin:
7004 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_umin:
7005 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_UMIN;
7006 case Intrinsic::amdgcn_raw_buffer_atomic_smax:
7007 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_smax:
7008 case Intrinsic::amdgcn_struct_buffer_atomic_smax:
7009 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_smax:
7010 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_SMAX;
7011 case Intrinsic::amdgcn_raw_buffer_atomic_umax:
7012 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_umax:
7013 case Intrinsic::amdgcn_struct_buffer_atomic_umax:
7014 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_umax:
7015 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_UMAX;
7016 case Intrinsic::amdgcn_raw_buffer_atomic_and:
7017 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_and:
7018 case Intrinsic::amdgcn_struct_buffer_atomic_and:
7019 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_and:
7020 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_AND;
7021 case Intrinsic::amdgcn_raw_buffer_atomic_or:
7022 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_or:
7023 case Intrinsic::amdgcn_struct_buffer_atomic_or:
7024 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_or:
7025 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_OR;
7026 case Intrinsic::amdgcn_raw_buffer_atomic_xor:
7027 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_xor:
7028 case Intrinsic::amdgcn_struct_buffer_atomic_xor:
7029 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_xor:
7030 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_XOR;
7031 case Intrinsic::amdgcn_raw_buffer_atomic_inc:
7032 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_inc:
7033 case Intrinsic::amdgcn_struct_buffer_atomic_inc:
7034 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_inc:
7035 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_INC;
7036 case Intrinsic::amdgcn_raw_buffer_atomic_dec:
7037 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_dec:
7038 case Intrinsic::amdgcn_struct_buffer_atomic_dec:
7039 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_dec:
7040 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_DEC;
7041 case Intrinsic::amdgcn_raw_buffer_atomic_cmpswap:
7042 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_cmpswap:
7043 case Intrinsic::amdgcn_struct_buffer_atomic_cmpswap:
7044 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_cmpswap:
7045 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_CMPSWAP;
7046 case Intrinsic::amdgcn_raw_buffer_atomic_fadd:
7047 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_fadd:
7048 case Intrinsic::amdgcn_struct_buffer_atomic_fadd:
7049 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_fadd:
7050 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_FADD;
7051 case Intrinsic::amdgcn_raw_buffer_atomic_fmin:
7052 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_fmin:
7053 case Intrinsic::amdgcn_struct_buffer_atomic_fmin:
7054 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_fmin:
7055 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_FMIN;
7056 case Intrinsic::amdgcn_raw_buffer_atomic_fmax:
7057 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_fmax:
7058 case Intrinsic::amdgcn_struct_buffer_atomic_fmax:
7059 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_fmax:
7060 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_FMAX;
7061 case Intrinsic::amdgcn_raw_buffer_atomic_sub_clamp_u32:
7062 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_sub_clamp_u32:
7063 case Intrinsic::amdgcn_struct_buffer_atomic_sub_clamp_u32:
7064 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_sub_clamp_u32:
7065 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_SUB_CLAMP_U32;
7066 case Intrinsic::amdgcn_raw_buffer_atomic_cond_sub_u32:
7067 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_cond_sub_u32:
7068 case Intrinsic::amdgcn_struct_buffer_atomic_cond_sub_u32:
7069 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_cond_sub_u32:
7070 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_COND_SUB_U32;
7071 default:
7072 llvm_unreachable("unhandled atomic opcode");
7073 }
7074}
7075
7078 Intrinsic::ID IID) const {
7079 const bool IsCmpSwap =
7080 IID == Intrinsic::amdgcn_raw_buffer_atomic_cmpswap ||
7081 IID == Intrinsic::amdgcn_struct_buffer_atomic_cmpswap ||
7082 IID == Intrinsic::amdgcn_raw_ptr_buffer_atomic_cmpswap ||
7083 IID == Intrinsic::amdgcn_struct_ptr_buffer_atomic_cmpswap;
7084
7085 Register Dst = MI.getOperand(0).getReg();
7086 // Since we don't have 128-bit atomics, we don't need to handle the case of
7087 // p8 argmunents to the atomic itself
7088 Register VData = MI.getOperand(2).getReg();
7089
7090 Register CmpVal;
7091 int OpOffset = 0;
7092
7093 if (IsCmpSwap) {
7094 CmpVal = MI.getOperand(3).getReg();
7095 ++OpOffset;
7096 }
7097
7098 castBufferRsrcArgToV4I32(MI, B, 3 + OpOffset);
7099 Register RSrc = MI.getOperand(3 + OpOffset).getReg();
7100 const unsigned NumVIndexOps = IsCmpSwap ? 9 : 8;
7101
7102 // The struct intrinsic variants add one additional operand over raw.
7103 const bool HasVIndex = MI.getNumOperands() == NumVIndexOps;
7104 Register VIndex;
7105 if (HasVIndex) {
7106 VIndex = MI.getOperand(4 + OpOffset).getReg();
7107 ++OpOffset;
7108 } else {
7109 VIndex = B.buildConstant(LLT::integer(32), 0).getReg(0);
7110 }
7111
7112 Register VOffset = MI.getOperand(4 + OpOffset).getReg();
7113 Register SOffset = MI.getOperand(5 + OpOffset).getReg();
7114 unsigned AuxiliaryData = MI.getOperand(6 + OpOffset).getImm();
7115
7116 MachineMemOperand *MMO = *MI.memoperands_begin();
7117
7118 unsigned ImmOffset;
7119 std::tie(VOffset, ImmOffset) = splitBufferOffsets(B, VOffset);
7120
7121 auto MIB = B.buildInstr(getBufferAtomicPseudo(IID))
7122 .addDef(Dst)
7123 .addUse(VData); // vdata
7124
7125 if (IsCmpSwap)
7126 MIB.addReg(CmpVal);
7127
7128 MIB.addUse(RSrc) // rsrc
7129 .addUse(VIndex) // vindex
7130 .addUse(VOffset) // voffset
7131 .addUse(SOffset) // soffset
7132 .addImm(ImmOffset) // offset(imm)
7133 .addImm(AuxiliaryData) // cachepolicy, swizzled buffer(imm)
7134 .addImm(HasVIndex ? -1 : 0) // idxen(imm)
7135 .addMemOperand(MMO);
7136
7137 MI.eraseFromParent();
7138 return true;
7139}
7140
7141/// Turn a set of f16 typed registers in \p AddrRegs into a dword sized
7142/// vector with f16 typed elements.
7144 SmallVectorImpl<Register> &PackedAddrs,
7145 unsigned ArgOffset,
7147 bool IsA16, bool IsG16) {
7148 auto EndIdx = Intr->VAddrEnd;
7149
7150 for (unsigned I = Intr->VAddrStart; I < EndIdx; I++) {
7151 MachineOperand &SrcOp = MI.getOperand(ArgOffset + I);
7152 if (!SrcOp.isReg())
7153 continue; // _L to _LZ may have eliminated this.
7154
7155 Register AddrReg = SrcOp.getReg();
7156
7157 if ((I < Intr->GradientStart) ||
7158 (I >= Intr->GradientStart && I < Intr->CoordStart && !IsG16) ||
7159 (I >= Intr->CoordStart && !IsA16)) {
7160 if ((I < Intr->GradientStart) && IsA16 &&
7161 (B.getMRI()->getType(AddrReg) == F16)) {
7162 assert(I == Intr->BiasIndex && "Got unexpected 16-bit extra argument");
7163 // Special handling of bias when A16 is on. Bias is of type half but
7164 // occupies full 32-bit.
7165 PackedAddrs.push_back(
7166 B.buildBuildVector(V2F16, {AddrReg, B.buildUndef(F16).getReg(0)})
7167 .getReg(0));
7168 } else {
7169 assert((!IsA16 || Intr->NumBiasArgs == 0 || I != Intr->BiasIndex) &&
7170 "Bias needs to be converted to 16 bit in A16 mode");
7171 // Handle any gradient or coordinate operands that should not be packed
7172 AddrReg = B.buildBitcast(V2F16, AddrReg).getReg(0);
7173 PackedAddrs.push_back(AddrReg);
7174 }
7175 } else {
7176 const LLT EltTy = B.getMRI()->getType(AddrReg);
7177 const LLT V2EltTy = LLT::fixed_vector(2, EltTy);
7178 // Dz/dh, dz/dv and the last odd coord are packed with undef. Also, in 1D,
7179 // derivatives dx/dh and dx/dv are packed with undef.
7180 if (((I + 1) >= EndIdx) ||
7181 ((Intr->NumGradients / 2) % 2 == 1 &&
7182 (I == static_cast<unsigned>(Intr->GradientStart +
7183 (Intr->NumGradients / 2) - 1) ||
7184 I == static_cast<unsigned>(Intr->GradientStart +
7185 Intr->NumGradients - 1))) ||
7186 // Check for _L to _LZ optimization
7187 !MI.getOperand(ArgOffset + I + 1).isReg()) {
7188 PackedAddrs.push_back(
7189 B.buildBuildVector(V2EltTy,
7190 {AddrReg, B.buildUndef(EltTy).getReg(0)})
7191 .getReg(0));
7192 } else {
7193 PackedAddrs.push_back(
7194 B.buildBuildVector(
7195 V2EltTy, {AddrReg, MI.getOperand(ArgOffset + I + 1).getReg()})
7196 .getReg(0));
7197 ++I;
7198 }
7199 }
7200 }
7201}
7202
7203/// Convert from separate vaddr components to a single vector address register,
7204/// and replace the remaining operands with $noreg.
7206 int DimIdx, int NumVAddrs) {
7207 SmallVector<Register, 8> AddrRegs;
7208 for (int I = 0; I != NumVAddrs; ++I) {
7209 MachineOperand &SrcOp = MI.getOperand(DimIdx + I);
7210 if (SrcOp.isReg()) {
7212 LLT I32 = LLT::integer(32);
7213 assert(B.getMRI()->getType(Reg).getSizeInBits() == 32);
7214 if (B.getMRI()->getType(Reg) != I32)
7215 Reg = B.buildBitcast(I32, Reg).getReg(0);
7216 AddrRegs.push_back(Reg);
7217 }
7218 }
7219
7220 int NumAddrRegs = AddrRegs.size();
7221 if (NumAddrRegs != 1) {
7222 LLT EltTy = B.getMRI()->getType(AddrRegs[0]);
7223 auto VAddr =
7224 B.buildBuildVector(LLT::fixed_vector(NumAddrRegs, EltTy), AddrRegs);
7225 MI.getOperand(DimIdx).setReg(VAddr.getReg(0));
7226 }
7227
7228 for (int I = 1; I != NumVAddrs; ++I) {
7229 MachineOperand &SrcOp = MI.getOperand(DimIdx + I);
7230 if (SrcOp.isReg())
7231 MI.getOperand(DimIdx + I).setReg(AMDGPU::NoRegister);
7232 }
7233}
7234
7235/// Rewrite image intrinsics to use register layouts expected by the subtarget.
7236///
7237/// Depending on the subtarget, load/store with 16-bit element data need to be
7238/// rewritten to use the low half of 32-bit registers, or directly use a packed
7239/// layout. 16-bit addresses should also sometimes be packed into 32-bit
7240/// registers.
7241///
7242/// We don't want to directly select image instructions just yet, but also want
7243/// to exposes all register repacking to the legalizer/combiners. We also don't
7244/// want a selected instruction entering RegBankSelect. In order to avoid
7245/// defining a multitude of intermediate image instructions, directly hack on
7246/// the intrinsic's arguments. In cases like a16 addresses, this requires
7247/// padding now unnecessary arguments with $noreg.
7250 const AMDGPU::ImageDimIntrinsicInfo *Intr) const {
7251
7252 const MachineFunction &MF = *MI.getMF();
7253 const unsigned NumDefs = MI.getNumExplicitDefs();
7254 const unsigned ArgOffset = NumDefs + 1;
7255 bool IsTFE = NumDefs == 2;
7256 // We are only processing the operands of d16 image operations on subtargets
7257 // that use the unpacked register layout, or need to repack the TFE result.
7258
7259 // TODO: Do we need to guard against already legalized intrinsics?
7260 const AMDGPU::MIMGBaseOpcodeInfo *BaseOpcode =
7262
7263 MachineRegisterInfo *MRI = B.getMRI();
7264 const LLT I32 = LLT::integer(32);
7265 const LLT I16 = LLT::integer(16);
7266 const LLT V2I16 = LLT::fixed_vector(2, I16);
7267
7268 unsigned DMask = 0;
7269 Register VData;
7270 LLT Ty;
7271
7272 if (!BaseOpcode->NoReturn || BaseOpcode->Store) {
7273 VData = MI.getOperand(NumDefs == 0 ? 1 : 0).getReg();
7274 Ty = MRI->getType(VData);
7275 }
7276
7277 const bool IsAtomicPacked16Bit =
7278 (BaseOpcode->BaseOpcode == AMDGPU::IMAGE_ATOMIC_PK_ADD_F16 ||
7279 BaseOpcode->BaseOpcode == AMDGPU::IMAGE_ATOMIC_PK_ADD_BF16);
7280
7281 // Check for 16 bit addresses and pack if true.
7282 LLT GradTy =
7283 MRI->getType(MI.getOperand(ArgOffset + Intr->GradientStart).getReg());
7284 LLT AddrTy =
7285 MRI->getType(MI.getOperand(ArgOffset + Intr->CoordStart).getReg());
7286 const bool GradTyIs16 = GradTy == I16 || GradTy == F16;
7287 const bool AddrTyIs16 = AddrTy == I16 || AddrTy == F16;
7288 const bool DataTyIs16 =
7289 Ty.getScalarType() == I16 || Ty.getScalarType() == F16;
7290 const bool IsG16 =
7291 ST.hasG16() ? (BaseOpcode->Gradients && GradTyIs16) : GradTyIs16;
7292 const bool IsA16 = AddrTyIs16;
7293 const bool IsD16 = !IsAtomicPacked16Bit && DataTyIs16;
7294
7295 int DMaskLanes = 0;
7296 if (!BaseOpcode->Atomic) {
7297 DMask = MI.getOperand(ArgOffset + Intr->DMaskIndex).getImm();
7298 if (BaseOpcode->Gather4) {
7299 DMaskLanes = 4;
7300 } else if (DMask != 0) {
7301 DMaskLanes = llvm::popcount(DMask);
7302 } else if (!IsTFE && !BaseOpcode->Store) {
7303 // If dmask is 0, this is a no-op load. This can be eliminated.
7304 B.buildUndef(MI.getOperand(0));
7305 MI.eraseFromParent();
7306 return true;
7307 }
7308 }
7309
7310 Observer.changingInstr(MI);
7311 scope_exit ChangedInstr([&] { Observer.changedInstr(MI); });
7312
7313 const unsigned StoreOpcode = IsD16 ? AMDGPU::G_AMDGPU_INTRIN_IMAGE_STORE_D16
7314 : AMDGPU::G_AMDGPU_INTRIN_IMAGE_STORE;
7315 const unsigned LoadOpcode = IsD16 ? AMDGPU::G_AMDGPU_INTRIN_IMAGE_LOAD_D16
7316 : AMDGPU::G_AMDGPU_INTRIN_IMAGE_LOAD;
7317 unsigned NewOpcode = LoadOpcode;
7318 if (BaseOpcode->Store)
7319 NewOpcode = StoreOpcode;
7320 else if (BaseOpcode->NoReturn)
7321 NewOpcode = AMDGPU::G_AMDGPU_INTRIN_IMAGE_LOAD_NORET;
7322
7323 // Track that we legalized this
7324 MI.setDesc(B.getTII().get(NewOpcode));
7325
7326 // Expecting to get an error flag since TFC is on - and dmask is 0 Force
7327 // dmask to be at least 1 otherwise the instruction will fail
7328 if (IsTFE && DMask == 0) {
7329 DMask = 0x1;
7330 DMaskLanes = 1;
7331 MI.getOperand(ArgOffset + Intr->DMaskIndex).setImm(DMask);
7332 }
7333
7334 if (BaseOpcode->Atomic) {
7335 Register VData0 = MI.getOperand(2).getReg();
7336 LLT Ty = MRI->getType(VData0);
7337
7338 // TODO: Allow atomic swap and bit ops for v2f16/v4f16
7339 if (Ty.isVector() && !IsAtomicPacked16Bit)
7340 return false;
7341
7342 if (BaseOpcode->AtomicX2) {
7343 Register VData1 = MI.getOperand(3).getReg();
7344 // The two values are packed in one register.
7345 LLT PackedTy = LLT::fixed_vector(2, Ty);
7346 auto Concat = B.buildBuildVector(PackedTy, {VData0, VData1});
7347 MI.getOperand(2).setReg(Concat.getReg(0));
7348 MI.getOperand(3).setReg(AMDGPU::NoRegister);
7349 }
7350 }
7351
7352 unsigned CorrectedNumVAddrs = Intr->NumVAddrs;
7353
7354 // Rewrite the addressing register layout before doing anything else.
7355 if (BaseOpcode->Gradients && !ST.hasG16() && (IsA16 != IsG16)) {
7356 // 16 bit gradients are supported, but are tied to the A16 control
7357 // so both gradients and addresses must be 16 bit
7358 return false;
7359 }
7360
7361 if (IsA16 && !ST.hasA16()) {
7362 // A16 not supported
7363 return false;
7364 }
7365
7366 const unsigned NSAMaxSize = ST.getNSAMaxSize(BaseOpcode->Sampler);
7367 const unsigned HasPartialNSA = ST.hasPartialNSAEncoding();
7368
7369 if (IsA16 || IsG16) {
7370 // Even if NumVAddrs == 1 we should pack it into a 32-bit value, because the
7371 // instructions expect VGPR_32
7372 SmallVector<Register, 4> PackedRegs;
7373
7374 packImage16bitOpsToDwords(B, MI, PackedRegs, ArgOffset, Intr, IsA16, IsG16);
7375
7376 // See also below in the non-a16 branch
7377 const bool UseNSA = ST.hasNSAEncoding() &&
7378 PackedRegs.size() >= ST.getNSAThreshold(MF) &&
7379 (PackedRegs.size() <= NSAMaxSize || HasPartialNSA);
7380 const bool UsePartialNSA =
7381 UseNSA && HasPartialNSA && PackedRegs.size() > NSAMaxSize;
7382
7383 if (UsePartialNSA) {
7384 // Pack registers that would go over NSAMaxSize into last VAddr register
7385 LLT PackedAddrTy =
7386 LLT::fixed_vector(2 * (PackedRegs.size() - NSAMaxSize + 1), F16);
7387 auto Concat = B.buildConcatVectors(
7388 PackedAddrTy, ArrayRef(PackedRegs).slice(NSAMaxSize - 1));
7389 PackedRegs[NSAMaxSize - 1] = Concat.getReg(0);
7390 PackedRegs.resize(NSAMaxSize);
7391 } else if (!UseNSA && PackedRegs.size() > 1) {
7392 LLT PackedAddrTy = LLT::fixed_vector(2 * PackedRegs.size(), F16);
7393 auto Concat = B.buildConcatVectors(PackedAddrTy, PackedRegs);
7394 PackedRegs[0] = Concat.getReg(0);
7395 PackedRegs.resize(1);
7396 }
7397
7398 const unsigned NumPacked = PackedRegs.size();
7399 for (unsigned I = Intr->VAddrStart; I < Intr->VAddrEnd; I++) {
7400 MachineOperand &SrcOp = MI.getOperand(ArgOffset + I);
7401 if (!SrcOp.isReg()) {
7402 assert(SrcOp.isImm() && SrcOp.getImm() == 0);
7403 continue;
7404 }
7405
7406 assert(SrcOp.getReg() != AMDGPU::NoRegister);
7407
7408 if (I - Intr->VAddrStart < NumPacked)
7409 SrcOp.setReg(PackedRegs[I - Intr->VAddrStart]);
7410 else
7411 SrcOp.setReg(AMDGPU::NoRegister);
7412 }
7413 } else {
7414 // If the register allocator cannot place the address registers contiguously
7415 // without introducing moves, then using the non-sequential address encoding
7416 // is always preferable, since it saves VALU instructions and is usually a
7417 // wash in terms of code size or even better.
7418 //
7419 // However, we currently have no way of hinting to the register allocator
7420 // that MIMG addresses should be placed contiguously when it is possible to
7421 // do so, so force non-NSA for the common 2-address case as a heuristic.
7422 //
7423 // SIShrinkInstructions will convert NSA encodings to non-NSA after register
7424 // allocation when possible.
7425 //
7426 // Partial NSA is allowed on GFX11+ where the final register is a contiguous
7427 // set of the remaining addresses.
7428 const bool UseNSA = ST.hasNSAEncoding() &&
7429 CorrectedNumVAddrs >= ST.getNSAThreshold(MF) &&
7430 (CorrectedNumVAddrs <= NSAMaxSize || HasPartialNSA);
7431 const bool UsePartialNSA =
7432 UseNSA && HasPartialNSA && CorrectedNumVAddrs > NSAMaxSize;
7433
7434 if (UsePartialNSA) {
7436 ArgOffset + Intr->VAddrStart + NSAMaxSize - 1,
7437 Intr->NumVAddrs - NSAMaxSize + 1);
7438 } else if (!UseNSA && Intr->NumVAddrs > 1) {
7439 convertImageAddrToPacked(B, MI, ArgOffset + Intr->VAddrStart,
7440 Intr->NumVAddrs);
7441 }
7442 }
7443
7444 int Flags = 0;
7445 if (IsA16)
7446 Flags |= 1;
7447 if (IsG16)
7448 Flags |= 2;
7449 MI.addOperand(MachineOperand::CreateImm(Flags));
7450
7451 if (BaseOpcode->NoReturn) { // No TFE for stores?
7452 // TODO: Handle dmask trim
7453 if (!Ty.isVector() || !IsD16)
7454 return true;
7455
7456 Register RepackedReg = handleD16VData(B, *MRI, VData, true);
7457 if (RepackedReg != VData) {
7458 MI.getOperand(1).setReg(RepackedReg);
7459 }
7460
7461 return true;
7462 }
7463
7464 Register DstReg = MI.getOperand(0).getReg();
7465 const LLT EltTy = Ty.getScalarType();
7466 const int NumElts = Ty.isVector() ? Ty.getNumElements() : 1;
7467
7468 // Confirm that the return type is large enough for the dmask specified
7469 if (NumElts < DMaskLanes)
7470 return false;
7471
7472 if (NumElts > 4 || DMaskLanes > 4)
7473 return false;
7474
7475 // Image atomic instructions are using DMask to specify how many bits
7476 // input/output data will have. 32-bits (i32, f32, v2f16) or 64-bits (i64,
7477 // f64, v4f16).
7478 // DMaskLanes for image atomic has default value '0'.
7479 // We must be sure that atomic variants (especially packed) will not be
7480 // truncated from v2f16 or v4f16 to f16 type.
7481 //
7482 // ChangeElementCount will be needed for image load where Ty is always scalar.
7483 const unsigned AdjustedNumElts = DMaskLanes == 0 ? 1 : DMaskLanes;
7484 const LLT AdjustedTy =
7485 DMaskLanes == 0
7486 ? Ty
7487 : Ty.changeElementCount(ElementCount::getFixed(AdjustedNumElts));
7488
7489 // The raw dword aligned data component of the load. The only legal cases
7490 // where this matters should be when using the packed D16 format, for
7491 // f16 -> <2 x f16>, and <3 x f16> -> <4 x f16>,
7492 LLT RoundedTy;
7493
7494 // I32 vector to cover all data, plus TFE result element.
7495 LLT TFETy;
7496
7497 // Register type to use for each loaded component. Will be I32 or V2I16.
7498 LLT RegTy;
7499
7500 if (IsD16 && ST.hasUnpackedD16VMem()) {
7501 RoundedTy =
7502 LLT::scalarOrVector(ElementCount::getFixed(AdjustedNumElts), I32);
7503 TFETy = LLT::fixed_vector(AdjustedNumElts + 1, I32);
7504 RegTy = I32;
7505 } else {
7506 unsigned EltSize = EltTy.getSizeInBits();
7507 unsigned RoundedElts = (AdjustedTy.getSizeInBits() + 31) / 32;
7508 unsigned RoundedSize = 32 * RoundedElts;
7509 RoundedTy = LLT::scalarOrVector(
7510 ElementCount::getFixed(RoundedSize / EltSize), EltTy);
7511 TFETy = LLT::fixed_vector(RoundedSize / 32 + 1, I32);
7512 RegTy = !IsTFE && EltSize == 16 ? V2I16 : I32;
7513 }
7514
7515 // The return type does not need adjustment.
7516 // TODO: Should we change f16 case to i32 or <2 x f16>?
7517 if (!IsTFE && (RoundedTy == Ty || !Ty.isVector()))
7518 return true;
7519
7520 Register Dst1Reg;
7521
7522 // Insert after the instruction.
7523 B.setInsertPt(*MI.getParent(), ++MI.getIterator());
7524
7525 // TODO: For TFE with d16, if we used a TFE type that was a multiple of <2 x
7526 // f16> instead of i32, we would only need 1 bitcast instead of multiple.
7527 const LLT LoadResultTy = IsTFE ? TFETy : RoundedTy;
7528 const int ResultNumRegs = LoadResultTy.getSizeInBits() / 32;
7529
7530 Register NewResultReg = MRI->createGenericVirtualRegister(LoadResultTy);
7531
7532 MI.getOperand(0).setReg(NewResultReg);
7533
7534 // In the IR, TFE is supposed to be used with a 2 element struct return
7535 // type. The instruction really returns these two values in one contiguous
7536 // register, with one additional dword beyond the loaded data. Rewrite the
7537 // return type to use a single register result.
7538
7539 if (IsTFE) {
7540 Dst1Reg = MI.getOperand(1).getReg();
7541 if (MRI->getType(Dst1Reg) != I32)
7542 return false;
7543
7544 // TODO: Make sure the TFE operand bit is set.
7545 MI.removeOperand(1);
7546
7547 // Handle the easy case that requires no repack instructions.
7548 if (!Ty.isVector() && Ty.getSizeInBits() == 32) {
7549 auto Unmerge = B.buildUnmerge({I32, I32}, NewResultReg);
7550 B.buildBitcast(DstReg, Unmerge.getReg(0));
7551 B.buildCopy(Dst1Reg, Unmerge.getReg(1));
7552 return true;
7553 }
7554 }
7555
7556 // Now figure out how to copy the new result register back into the old
7557 // result.
7558 SmallVector<Register, 5> ResultRegs(ResultNumRegs, Dst1Reg);
7559
7560 const int NumDataRegs = IsTFE ? ResultNumRegs - 1 : ResultNumRegs;
7561
7562 if (ResultNumRegs == 1) {
7563 assert(!IsTFE);
7564 ResultRegs[0] = NewResultReg;
7565 } else {
7566 // We have to repack into a new vector of some kind.
7567 for (int I = 0; I != NumDataRegs; ++I)
7568 ResultRegs[I] = MRI->createGenericVirtualRegister(RegTy);
7569 B.buildUnmerge(ResultRegs, NewResultReg);
7570
7571 // Drop the final TFE element to get the data part. The TFE result is
7572 // directly written to the right place already.
7573 if (IsTFE)
7574 ResultRegs.resize(NumDataRegs);
7575 }
7576
7577 // For an f16 scalar result, we form an i32 result with a truncate regardless
7578 // of packed vs. unpacked.
7579 if (IsD16 && !Ty.isVector()) {
7580 B.buildTrunc(DstReg, ResultRegs[0]);
7581 return true;
7582 }
7583
7584 // Avoid a build/concat_vector of 1 entry.
7585 if ((Ty == V2I16 || Ty == V2F16) && NumDataRegs == 1 &&
7586 !ST.hasUnpackedD16VMem()) {
7587 B.buildBitcast(DstReg, ResultRegs[0]);
7588 return true;
7589 }
7590
7591 assert(Ty.isVector());
7592
7593 if (IsD16) {
7594 // For packed D16 results with TFE enabled, all the data components are
7595 // I32. Cast back to the expected type.
7596 //
7597 // TODO: We don't really need to use load i32 elements. We would only need
7598 // one cast for the TFE result if a multiple of v2f16 was used.
7599 if (RegTy != V2I16 && !ST.hasUnpackedD16VMem()) {
7600 for (Register &Reg : ResultRegs)
7601 Reg = B.buildBitcast(V2I16, Reg).getReg(0);
7602 } else if (ST.hasUnpackedD16VMem()) {
7603 for (Register &Reg : ResultRegs)
7604 Reg = B.buildTrunc(I16, Reg).getReg(0);
7605 }
7606 }
7607
7608 auto padWithUndef = [&](LLT Ty, int NumElts) {
7609 if (NumElts == 0)
7610 return;
7611 Register Undef = B.buildUndef(Ty).getReg(0);
7612 for (int I = 0; I != NumElts; ++I)
7613 ResultRegs.push_back(Undef);
7614 };
7615
7616 // Pad out any elements eliminated due to the dmask.
7617 LLT ResTy = MRI->getType(ResultRegs[0]);
7618 if (!ResTy.isVector()) {
7619 padWithUndef(ResTy, NumElts - ResultRegs.size());
7620 B.buildBuildVector(DstReg, ResultRegs);
7621 return true;
7622 }
7623
7624 assert(!ST.hasUnpackedD16VMem() && (ResTy == V2I16 || ResTy == V2F16));
7625 const int RegsToCover = (Ty.getSizeInBits() + 31) / 32;
7626
7627 // Deal with the one annoying legal case.
7628 const LLT V3I16 = LLT::fixed_vector(3, I16);
7629 const LLT V3F16 = LLT::fixed_vector(3, F16);
7630 if (Ty == V3I16 || Ty == V3F16) {
7631 if (IsTFE) {
7632 if (ResultRegs.size() == 1) {
7633 NewResultReg = ResultRegs[0];
7634 } else if (ResultRegs.size() == 2) {
7635 LLT V4I16 = LLT::fixed_vector(4, I16);
7636 NewResultReg = B.buildConcatVectors(V4I16, ResultRegs).getReg(0);
7637 } else {
7638 return false;
7639 }
7640 }
7641
7642 LLT DstTy = MRI->getType(DstReg);
7643 LLT NewResTy = MRI->getType(NewResultReg);
7644 LLT ResEltTy = NewResTy.getElementType();
7645 Register ResizeDst = DstTy.getElementType() == ResEltTy
7646 ? DstReg
7648 DstTy.changeElementType(ResEltTy));
7649
7650 if (DstTy.getNumElements() < NewResTy.getNumElements()) {
7651 B.buildDeleteTrailingVectorElements(ResizeDst, NewResultReg);
7652 } else {
7653 B.buildPadVectorWithUndefElements(ResizeDst, NewResultReg);
7654 }
7655 if (ResizeDst != DstReg)
7656 B.buildBitcast(DstReg, ResizeDst);
7657 return true;
7658 }
7659
7660 padWithUndef(ResTy, RegsToCover - ResultRegs.size());
7661 B.buildConcatVectors(DstReg, ResultRegs);
7662 return true;
7663}
7664
7666 MachineInstr &MI) const {
7667 MachineIRBuilder &B = Helper.MIRBuilder;
7668 GISelChangeObserver &Observer = Helper.Observer;
7669
7670 Register OrigDst = MI.getOperand(0).getReg();
7671 Register Dst;
7672 LLT Ty = B.getMRI()->getType(OrigDst);
7673 unsigned Size = Ty.getSizeInBits();
7674 MachineFunction &MF = B.getMF();
7675 bool HasMMO = !MI.memoperands_empty();
7676 unsigned Opc = 0;
7677 if (Size < 32 && ST.hasScalarSubwordLoads()) {
7678 assert(Size == 8 || Size == 16);
7679 Opc = Size == 8 ? AMDGPU::G_AMDGPU_S_BUFFER_LOAD_UBYTE
7680 : AMDGPU::G_AMDGPU_S_BUFFER_LOAD_USHORT;
7681 // The 8-bit and 16-bit scalar buffer load instructions have 32-bit
7682 // destination register.
7683 Dst = B.getMRI()->createGenericVirtualRegister(LLT::integer(32));
7684 } else {
7685 Opc = AMDGPU::G_AMDGPU_S_BUFFER_LOAD;
7686 Dst = OrigDst;
7687 }
7688
7689 Observer.changingInstr(MI);
7690
7691 // Handle needing to s.buffer.load() a p8 value.
7692 if (hasBufferRsrcWorkaround(Ty)) {
7693 Ty = castBufferRsrcFromV4I32(MI, B, *B.getMRI(), 0);
7694 B.setInsertPt(B.getMBB(), MI);
7695 }
7697 Ty = getBitcastRegisterType(Ty);
7698 Helper.bitcastDst(MI, Ty, 0);
7699 B.setInsertPt(B.getMBB(), MI);
7700 }
7701
7702 MI.setDesc(B.getTII().get(Opc));
7703 MI.removeOperand(1);
7705
7706 if (!HasMMO) {
7707 // Legacy intrinsic that doesn't take a pointer and so can't already have an
7708 // MMO.
7709 const unsigned MemSize = (Size + 7) / 8;
7710 const Align MemAlign = B.getDataLayout().getABITypeAlign(
7716 MemSize, MemAlign);
7717 MI.addMemOperand(MF, MMO);
7718 }
7719 if (Dst != OrigDst) {
7720 MI.getOperand(0).setReg(Dst);
7721 B.setInsertPt(B.getMBB(), ++B.getInsertPt());
7722 B.buildTrunc(OrigDst, Dst);
7723 }
7724
7725 // If we don't have 96-bit result scalar loads, widening to 128-bit should
7726 // always be legal. We may need to restore this to a 96-bit result if it turns
7727 // out this needs to be converted to a vector load during RegBankSelect.
7728 if (!isPowerOf2_32(Size) && (Size != 96 || !ST.hasScalarDwordx3Loads())) {
7729 if (Ty.isVector())
7731 else
7732 Helper.widenScalarDst(MI, getPow2ScalarType(Ty), 0);
7733 }
7734
7735 Observer.changedInstr(MI);
7736 return true;
7737}
7738
7740 MachineInstr &MI) const {
7741 MachineIRBuilder &B = Helper.MIRBuilder;
7742 GISelChangeObserver &Observer = Helper.Observer;
7743 Observer.changingInstr(MI);
7744 MI.setDesc(B.getTII().get(AMDGPU::G_AMDGPU_S_BUFFER_PREFETCH));
7745 MI.removeOperand(0); // Remove intrinsic ID
7747 Observer.changedInstr(MI);
7748 return true;
7749}
7750
7751// TODO: Move to selection
7754 MachineIRBuilder &B) const {
7755 if (!ST.hasTrapHandler() ||
7756 ST.getTrapHandlerAbi() != GCNSubtarget::TrapHandlerAbi::AMDHSA)
7757 return legalizeTrapEndpgm(MI, MRI, B);
7758
7759 return ST.supportsGetDoorbellID() ?
7761}
7762
7765 const DebugLoc &DL = MI.getDebugLoc();
7766 MachineBasicBlock &BB = B.getMBB();
7767 MachineFunction *MF = BB.getParent();
7768
7769 if (BB.succ_empty() && std::next(MI.getIterator()) == BB.end()) {
7770 BuildMI(BB, BB.end(), DL, B.getTII().get(AMDGPU::S_ENDPGM))
7771 .addImm(0);
7772 MI.eraseFromParent();
7773 return true;
7774 }
7775
7776 // We need a block split to make the real endpgm a terminator. We also don't
7777 // want to break phis in successor blocks, so we can't just delete to the
7778 // end of the block.
7779 BB.splitAt(MI, false /*UpdateLiveIns*/);
7781 MF->push_back(TrapBB);
7782 BuildMI(*TrapBB, TrapBB->end(), DL, B.getTII().get(AMDGPU::S_ENDPGM))
7783 .addImm(0);
7784 BuildMI(BB, &MI, DL, B.getTII().get(AMDGPU::S_CBRANCH_EXECNZ))
7785 .addMBB(TrapBB);
7786
7787 BB.addSuccessor(TrapBB);
7788 MI.eraseFromParent();
7789 return true;
7790}
7791
7794 MachineFunction &MF = B.getMF();
7795 const LLT I64 = LLT::integer(64);
7796
7797 Register SGPR01(AMDGPU::SGPR0_SGPR1);
7798 // For code object version 5, queue_ptr is passed through implicit kernarg.
7803 uint64_t Offset =
7804 ST.getTargetLowering()->getImplicitParameterOffset(B.getMF(), Param);
7805
7806 Register KernargPtrReg = MRI.createGenericVirtualRegister(
7808
7809 if (!loadInputValue(KernargPtrReg, B,
7811 return false;
7812
7813 // TODO: can we be smarter about machine pointer info?
7816 PtrInfo.getWithOffset(Offset),
7820
7821 // Pointer address
7824 B.buildObjectPtrOffset(LoadAddr, KernargPtrReg,
7825 B.buildConstant(LLT::integer(64), Offset).getReg(0));
7826 // Load address
7827 Register Temp = B.buildLoad(I64, LoadAddr, *MMO).getReg(0);
7828 B.buildCopy(SGPR01, Temp);
7829 B.buildInstr(AMDGPU::S_TRAP)
7830 .addImm(static_cast<unsigned>(GCNSubtarget::TrapID::LLVMAMDHSATrap))
7831 .addReg(SGPR01, RegState::Implicit);
7832 MI.eraseFromParent();
7833 return true;
7834 }
7835
7836 // Pass queue pointer to trap handler as input, and insert trap instruction
7837 // Reference: https://llvm.org/docs/AMDGPUUsage.html#trap-handler-abi
7838 Register LiveIn =
7841 return false;
7842
7843 B.buildCopy(SGPR01, LiveIn);
7844 B.buildInstr(AMDGPU::S_TRAP)
7845 .addImm(static_cast<unsigned>(GCNSubtarget::TrapID::LLVMAMDHSATrap))
7846 .addReg(SGPR01, RegState::Implicit);
7847
7848 MI.eraseFromParent();
7849 return true;
7850}
7851
7854 MachineIRBuilder &B) const {
7855 // We need to simulate the 's_trap 2' instruction on targets that run in
7856 // PRIV=1 (where it is treated as a nop).
7857 if (ST.hasPrivEnabledTrap2NopBug()) {
7858 ST.getInstrInfo()->insertSimulatedTrap(MRI, B.getMBB(), MI,
7859 MI.getDebugLoc());
7860 MI.eraseFromParent();
7861 return true;
7862 }
7863
7864 B.buildInstr(AMDGPU::S_TRAP)
7865 .addImm(static_cast<unsigned>(GCNSubtarget::TrapID::LLVMAMDHSATrap));
7866 MI.eraseFromParent();
7867 return true;
7868}
7869
7872 MachineIRBuilder &B) const {
7873 // Is non-HSA path or trap-handler disabled? Then, report a warning
7874 // accordingly
7875 if (!ST.hasTrapHandler() ||
7876 ST.getTrapHandlerAbi() != GCNSubtarget::TrapHandlerAbi::AMDHSA) {
7877 Function &Fn = B.getMF().getFunction();
7879 Fn, "debugtrap handler not supported", MI.getDebugLoc(), DS_Warning));
7880 } else {
7881 // Insert debug-trap instruction
7882 B.buildInstr(AMDGPU::S_TRAP)
7883 .addImm(static_cast<unsigned>(GCNSubtarget::TrapID::LLVMAMDHSADebugTrap));
7884 }
7885
7886 MI.eraseFromParent();
7887 return true;
7888}
7889
7891 MachineInstr &MI, MachineIRBuilder &B) const {
7892 MachineRegisterInfo &MRI = *B.getMRI();
7893 const LLT I16 = LLT::integer(16);
7894 const LLT I32 = LLT::integer(32);
7895 const LLT V2I16 = LLT::fixed_vector(2, I16);
7896 const LLT V3I32 = LLT::fixed_vector(3, I32);
7897 const LLT V3I16 = LLT::fixed_vector(3, I16);
7898
7899 Register DstReg = MI.getOperand(0).getReg();
7900 Register NodePtr = MI.getOperand(2).getReg();
7901 Register RayExtent = MI.getOperand(3).getReg();
7902 Register RayOrigin = MI.getOperand(4).getReg();
7903 Register RayDir = MI.getOperand(5).getReg();
7904 Register RayInvDir = MI.getOperand(6).getReg();
7905 Register TDescr = MI.getOperand(7).getReg();
7906
7907 RayExtent = B.buildBitcast(I32, RayExtent).getReg(0);
7908
7909 const bool IsGFX11 = AMDGPU::isGFX11(ST);
7910 const bool IsGFX11Plus = AMDGPU::isGFX11Plus(ST);
7911 const bool IsGFX12Plus = AMDGPU::isGFX12Plus(ST);
7912 const bool IsA16 = MRI.getType(RayDir).getElementType().getSizeInBits() == 16;
7913 const bool Is64 = MRI.getType(NodePtr).getSizeInBits() == 64;
7914 const unsigned NumVDataDwords = 4;
7915 const unsigned NumVAddrDwords = IsA16 ? (Is64 ? 9 : 8) : (Is64 ? 12 : 11);
7916 const unsigned NumVAddrs = IsGFX11Plus ? (IsA16 ? 4 : 5) : NumVAddrDwords;
7917 const bool UseNSA =
7918 IsGFX12Plus || (ST.hasNSAEncoding() && NumVAddrs <= ST.getNSAMaxSize());
7919
7920 const unsigned BaseOpcodes[2][2] = {
7921 {AMDGPU::IMAGE_BVH_INTERSECT_RAY, AMDGPU::IMAGE_BVH_INTERSECT_RAY_a16},
7922 {AMDGPU::IMAGE_BVH64_INTERSECT_RAY,
7923 AMDGPU::IMAGE_BVH64_INTERSECT_RAY_a16}};
7924 int Opcode;
7925 if (UseNSA) {
7926 Opcode = AMDGPU::getMIMGOpcode(BaseOpcodes[Is64][IsA16],
7927 IsGFX12Plus ? AMDGPU::MIMGEncGfx12
7928 : IsGFX11 ? AMDGPU::MIMGEncGfx11NSA
7929 : AMDGPU::MIMGEncGfx10NSA,
7930 NumVDataDwords, NumVAddrDwords);
7931 } else {
7932 assert(!IsGFX12Plus);
7933 Opcode = AMDGPU::getMIMGOpcode(BaseOpcodes[Is64][IsA16],
7934 IsGFX11 ? AMDGPU::MIMGEncGfx11Default
7935 : AMDGPU::MIMGEncGfx10Default,
7936 NumVDataDwords, NumVAddrDwords);
7937 }
7938 assert(Opcode != -1);
7939
7941 if (UseNSA && IsGFX11Plus) {
7942 auto packLanes = [&Ops, &I32, &V3I32, &B](Register Src) {
7943 auto SrcInt = B.buildBitcast(V3I32, Src);
7944 auto Unmerge = B.buildUnmerge({I32, I32, I32}, SrcInt);
7945 auto Merged = B.buildMergeLikeInstr(
7946 V3I32, {Unmerge.getReg(0), Unmerge.getReg(1), Unmerge.getReg(2)});
7947 Ops.push_back(Merged.getReg(0));
7948 };
7949
7950 Ops.push_back(NodePtr);
7951 Ops.push_back(RayExtent);
7952 packLanes(RayOrigin);
7953
7954 if (IsA16) {
7955 auto UnmergeRayDir =
7956 B.buildUnmerge({I16, I16, I16}, B.buildBitcast(V3I16, RayDir));
7957 auto UnmergeRayInvDir =
7958 B.buildUnmerge({I16, I16, I16}, B.buildBitcast(V3I16, RayInvDir));
7959 auto MergedDir = B.buildMergeLikeInstr(
7960 V3I32,
7961 {B.buildBitcast(
7962 I32, B.buildMergeLikeInstr(V2I16, {UnmergeRayInvDir.getReg(0),
7963 UnmergeRayDir.getReg(0)}))
7964 .getReg(0),
7965 B.buildBitcast(
7966 I32, B.buildMergeLikeInstr(V2I16, {UnmergeRayInvDir.getReg(1),
7967 UnmergeRayDir.getReg(1)}))
7968 .getReg(0),
7969 B.buildBitcast(
7970 I32, B.buildMergeLikeInstr(V2I16, {UnmergeRayInvDir.getReg(2),
7971 UnmergeRayDir.getReg(2)}))
7972 .getReg(0)});
7973 Ops.push_back(MergedDir.getReg(0));
7974 } else {
7975 packLanes(RayDir);
7976 packLanes(RayInvDir);
7977 }
7978 } else {
7979 if (Is64) {
7980 auto Unmerge = B.buildUnmerge({I32, I32}, NodePtr);
7981 Ops.push_back(Unmerge.getReg(0));
7982 Ops.push_back(Unmerge.getReg(1));
7983 } else {
7984 Ops.push_back(NodePtr);
7985 }
7986 Ops.push_back(RayExtent);
7987
7988 auto packLanes = [&Ops, &I32, &V3I32, &B](Register Src) {
7989 auto SrcInt = B.buildBitcast(V3I32, Src);
7990 auto Unmerge = B.buildUnmerge({I32, I32, I32}, SrcInt);
7991 Ops.push_back(Unmerge.getReg(0));
7992 Ops.push_back(Unmerge.getReg(1));
7993 Ops.push_back(Unmerge.getReg(2));
7994 };
7995
7996 packLanes(RayOrigin);
7997 if (IsA16) {
7998 auto UnmergeRayDir =
7999 B.buildUnmerge({I16, I16, I16}, B.buildBitcast(V3I16, RayDir));
8000 auto UnmergeRayInvDir =
8001 B.buildUnmerge({I16, I16, I16}, B.buildBitcast(V3I16, RayInvDir));
8005 B.buildMergeLikeInstr(R1,
8006 {UnmergeRayDir.getReg(0), UnmergeRayDir.getReg(1)});
8007 B.buildMergeLikeInstr(
8008 R2, {UnmergeRayDir.getReg(2), UnmergeRayInvDir.getReg(0)});
8009 B.buildMergeLikeInstr(
8010 R3, {UnmergeRayInvDir.getReg(1), UnmergeRayInvDir.getReg(2)});
8011 Ops.push_back(R1);
8012 Ops.push_back(R2);
8013 Ops.push_back(R3);
8014 } else {
8015 packLanes(RayDir);
8016 packLanes(RayInvDir);
8017 }
8018 }
8019
8020 if (!UseNSA) {
8021 // Build a single vector containing all the operands so far prepared.
8022 LLT OpTy = LLT::fixed_vector(Ops.size(), I32);
8023 Register MergedOps = B.buildMergeLikeInstr(OpTy, Ops).getReg(0);
8024 Ops.clear();
8025 Ops.push_back(MergedOps);
8026 }
8027
8028 auto MIB = B.buildInstr(AMDGPU::G_AMDGPU_BVH_INTERSECT_RAY)
8029 .addDef(DstReg)
8030 .addImm(Opcode);
8031
8032 for (Register R : Ops) {
8033 MIB.addUse(R);
8034 }
8035
8036 MIB.addUse(TDescr)
8037 .addImm(IsA16 ? 1 : 0)
8038 .cloneMemRefs(MI);
8039
8040 MI.eraseFromParent();
8041 return true;
8042}
8043
8045 MachineInstr &MI, MachineIRBuilder &B) const {
8046 const LLT I32 = LLT::integer(32);
8047 const LLT V2I32 = LLT::fixed_vector(2, I32);
8048
8049 Register DstReg = MI.getOperand(0).getReg();
8050 Register DstOrigin = MI.getOperand(1).getReg();
8051 Register DstDir = MI.getOperand(2).getReg();
8052 Register NodePtr = MI.getOperand(4).getReg();
8053 Register RayExtent = MI.getOperand(5).getReg();
8054 Register InstanceMask = MI.getOperand(6).getReg();
8055 Register RayOrigin = MI.getOperand(7).getReg();
8056 Register RayDir = MI.getOperand(8).getReg();
8057 Register Offsets = MI.getOperand(9).getReg();
8058 Register TDescr = MI.getOperand(10).getReg();
8059
8060 bool IsBVH8 = cast<GIntrinsic>(MI).getIntrinsicID() ==
8061 Intrinsic::amdgcn_image_bvh8_intersect_ray;
8062 const unsigned NumVDataDwords = 10;
8063 const unsigned NumVAddrDwords = IsBVH8 ? 11 : 12;
8064 int Opcode = AMDGPU::getMIMGOpcode(
8065 IsBVH8 ? AMDGPU::IMAGE_BVH8_INTERSECT_RAY
8066 : AMDGPU::IMAGE_BVH_DUAL_INTERSECT_RAY,
8067 AMDGPU::MIMGEncGfx12, NumVDataDwords, NumVAddrDwords);
8068 assert(Opcode != -1);
8069
8070 auto RayExtentInstanceMaskVec =
8071 B.buildMergeLikeInstr(V2I32, {B.buildBitcast(I32, RayExtent),
8072 B.buildAnyExt(I32, InstanceMask)});
8073
8074 B.buildInstr(IsBVH8 ? AMDGPU::G_AMDGPU_BVH8_INTERSECT_RAY
8075 : AMDGPU::G_AMDGPU_BVH_DUAL_INTERSECT_RAY)
8076 .addDef(DstReg)
8077 .addDef(DstOrigin)
8078 .addDef(DstDir)
8079 .addImm(Opcode)
8080 .addUse(NodePtr)
8081 .addUse(RayExtentInstanceMaskVec.getReg(0))
8082 .addUse(RayOrigin)
8083 .addUse(RayDir)
8084 .addUse(Offsets)
8085 .addUse(TDescr)
8086 .cloneMemRefs(MI);
8087
8088 MI.eraseFromParent();
8089 return true;
8090}
8091
8093 MachineIRBuilder &B) const {
8094 const SITargetLowering *TLI = ST.getTargetLowering();
8096 Register DstReg = MI.getOperand(0).getReg();
8097 B.buildInstr(AMDGPU::G_AMDGPU_WAVE_ADDRESS, {DstReg}, {StackPtr});
8098 MI.eraseFromParent();
8099 return true;
8100}
8101
8103 MachineIRBuilder &B) const {
8104 // With architected SGPRs, waveIDinGroup is in TTMP8[29:25].
8105 if (!ST.hasArchitectedSGPRs())
8106 return false;
8107 LLT I32 = LLT::integer(32);
8108 Register DstReg = MI.getOperand(0).getReg();
8109 auto TTMP8 = B.buildCopy(I32, Register(AMDGPU::TTMP8));
8110 auto LSB = B.buildConstant(I32, 25);
8111 auto Width = B.buildConstant(I32, 5);
8112 B.buildUbfx(DstReg, TTMP8, LSB, Width);
8113 MI.eraseFromParent();
8114 return true;
8115}
8116
8119 AMDGPU::Hwreg::Id HwReg,
8120 unsigned LowBit,
8121 unsigned Width) const {
8122 MachineRegisterInfo &MRI = *B.getMRI();
8123 Register DstReg = MI.getOperand(0).getReg();
8124 if (!MRI.getRegClassOrNull(DstReg))
8125 MRI.setRegClass(DstReg, &AMDGPU::SReg_32RegClass);
8126 B.buildInstr(AMDGPU::S_GETREG_B32_const)
8127 .addDef(DstReg)
8128 .addImm(AMDGPU::Hwreg::HwregEncoding::encode(HwReg, LowBit, Width));
8129 MI.eraseFromParent();
8130 return true;
8131}
8132
8133static constexpr unsigned FPEnvModeBitField =
8135
8136static constexpr unsigned FPEnvTrapBitField =
8138
8141 MachineIRBuilder &B) const {
8142 const LLT I32 = LLT::integer(32);
8143 const LLT I64 = LLT::integer(64);
8144 Register Src = MI.getOperand(0).getReg();
8145 if (MRI.getType(Src) != I64)
8146 return false;
8147
8148 auto ModeReg =
8149 B.buildIntrinsic(Intrinsic::amdgcn_s_getreg, {I32},
8150 /*HasSideEffects=*/true, /*isConvergent=*/false)
8151 .addImm(FPEnvModeBitField);
8152 auto TrapReg =
8153 B.buildIntrinsic(Intrinsic::amdgcn_s_getreg, {I32},
8154 /*HasSideEffects=*/true, /*isConvergent=*/false)
8155 .addImm(FPEnvTrapBitField);
8156 B.buildMergeLikeInstr(Src, {ModeReg, TrapReg});
8157 MI.eraseFromParent();
8158 return true;
8159}
8160
8163 MachineIRBuilder &B) const {
8164 const LLT I32 = LLT::integer(32);
8165 const LLT I64 = LLT::integer(64);
8166 Register Src = MI.getOperand(0).getReg();
8167 if (MRI.getType(Src) != I64)
8168 return false;
8169
8170 auto Unmerge = B.buildUnmerge({I32, I32}, MI.getOperand(0));
8171 B.buildIntrinsic(Intrinsic::amdgcn_s_setreg, ArrayRef<DstOp>(),
8172 /*HasSideEffects=*/true, /*isConvergent=*/false)
8173 .addImm(static_cast<int16_t>(FPEnvModeBitField))
8174 .addReg(Unmerge.getReg(0));
8175 B.buildIntrinsic(Intrinsic::amdgcn_s_setreg, ArrayRef<DstOp>(),
8176 /*HasSideEffects=*/true, /*isConvergent=*/false)
8177 .addImm(static_cast<int16_t>(FPEnvTrapBitField))
8178 .addReg(Unmerge.getReg(1));
8179 MI.eraseFromParent();
8180 return true;
8181}
8182
8184 MachineInstr &MI) const {
8185 MachineIRBuilder &B = Helper.MIRBuilder;
8186 MachineRegisterInfo &MRI = *B.getMRI();
8187
8188 // Replace the use G_BRCOND with the exec manipulate and branch pseudos.
8189 auto IntrID = cast<GIntrinsic>(MI).getIntrinsicID();
8190 switch (IntrID) {
8191 case Intrinsic::sponentry:
8192 if (B.getMF().getInfo<SIMachineFunctionInfo>()->isBottomOfStack()) {
8193 // FIXME: The imported pattern checks for i32 instead of p5; if we fix
8194 // that we can remove this cast.
8195 const LLT I32 = LLT::integer(32);
8196 Register TmpReg = MRI.createGenericVirtualRegister(I32);
8197 B.buildInstr(AMDGPU::G_AMDGPU_SPONENTRY).addDef(TmpReg);
8198
8199 Register DstReg = MI.getOperand(0).getReg();
8200 B.buildIntToPtr(DstReg, TmpReg);
8201 MI.eraseFromParent();
8202 } else {
8203 int FI = B.getMF().getFrameInfo().CreateFixedObject(
8204 1, 0, /*IsImmutable=*/false);
8205 B.buildFrameIndex(MI.getOperand(0), FI);
8206 MI.eraseFromParent();
8207 }
8208 return true;
8209 case Intrinsic::amdgcn_if:
8210 case Intrinsic::amdgcn_else: {
8211 MachineInstr *Br = nullptr;
8212 MachineBasicBlock *UncondBrTarget = nullptr;
8213 bool Negated = false;
8214 if (MachineInstr *BrCond =
8215 verifyCFIntrinsic(MI, MRI, Br, UncondBrTarget, Negated)) {
8216 const SIRegisterInfo *TRI
8217 = static_cast<const SIRegisterInfo *>(MRI.getTargetRegisterInfo());
8218
8219 Register Def = MI.getOperand(1).getReg();
8220 Register Use = MI.getOperand(3).getReg();
8221
8222 MachineBasicBlock *CondBrTarget = BrCond->getOperand(1).getMBB();
8223
8224 if (Negated)
8225 std::swap(CondBrTarget, UncondBrTarget);
8226
8227 B.setInsertPt(B.getMBB(), BrCond->getIterator());
8228 if (IntrID == Intrinsic::amdgcn_if) {
8229 B.buildInstr(AMDGPU::SI_IF)
8230 .addDef(Def)
8231 .addUse(Use)
8232 .addMBB(UncondBrTarget);
8233 } else {
8234 B.buildInstr(AMDGPU::SI_ELSE)
8235 .addDef(Def)
8236 .addUse(Use)
8237 .addMBB(UncondBrTarget);
8238 }
8239
8240 if (Br) {
8241 Br->getOperand(0).setMBB(CondBrTarget);
8242 } else {
8243 // The IRTranslator skips inserting the G_BR for fallthrough cases, but
8244 // since we're swapping branch targets it needs to be reinserted.
8245 // FIXME: IRTranslator should probably not do this
8246 B.buildBr(*CondBrTarget);
8247 }
8248
8249 MRI.setRegClass(Def, TRI->getWaveMaskRegClass());
8250 MRI.setRegClass(Use, TRI->getWaveMaskRegClass());
8251 MI.eraseFromParent();
8252 BrCond->eraseFromParent();
8253 return true;
8254 }
8255
8256 return false;
8257 }
8258 case Intrinsic::amdgcn_loop: {
8259 MachineInstr *Br = nullptr;
8260 MachineBasicBlock *UncondBrTarget = nullptr;
8261 bool Negated = false;
8262 if (MachineInstr *BrCond =
8263 verifyCFIntrinsic(MI, MRI, Br, UncondBrTarget, Negated)) {
8264 const SIRegisterInfo *TRI
8265 = static_cast<const SIRegisterInfo *>(MRI.getTargetRegisterInfo());
8266
8267 MachineBasicBlock *CondBrTarget = BrCond->getOperand(1).getMBB();
8268 Register Reg = MI.getOperand(2).getReg();
8269
8270 if (Negated)
8271 std::swap(CondBrTarget, UncondBrTarget);
8272
8273 B.setInsertPt(B.getMBB(), BrCond->getIterator());
8274 B.buildInstr(AMDGPU::SI_LOOP)
8275 .addUse(Reg)
8276 .addMBB(UncondBrTarget);
8277
8278 if (Br)
8279 Br->getOperand(0).setMBB(CondBrTarget);
8280 else
8281 B.buildBr(*CondBrTarget);
8282
8283 MI.eraseFromParent();
8284 BrCond->eraseFromParent();
8285 MRI.setRegClass(Reg, TRI->getWaveMaskRegClass());
8286 return true;
8287 }
8288
8289 return false;
8290 }
8291 case Intrinsic::amdgcn_wave_reduce_min:
8292 case Intrinsic::amdgcn_wave_reduce_umin:
8293 case Intrinsic::amdgcn_wave_reduce_fmin:
8294 case Intrinsic::amdgcn_wave_reduce_max:
8295 case Intrinsic::amdgcn_wave_reduce_umax:
8296 case Intrinsic::amdgcn_wave_reduce_fmax:
8297 case Intrinsic::amdgcn_wave_reduce_add:
8298 case Intrinsic::amdgcn_wave_reduce_fadd:
8299 case Intrinsic::amdgcn_wave_reduce_sub:
8300 case Intrinsic::amdgcn_wave_reduce_fsub:
8301 case Intrinsic::amdgcn_wave_reduce_and:
8302 case Intrinsic::amdgcn_wave_reduce_or:
8303 case Intrinsic::amdgcn_wave_reduce_xor: {
8304 Register SrcReg = MI.getOperand(2).getReg();
8305 if (MRI.getType(SrcReg).getSizeInBits() != 16)
8306 return true;
8307 Register DstReg = MI.getOperand(0).getReg();
8308 bool IsFPOp = IntrID == Intrinsic::amdgcn_wave_reduce_fmin ||
8309 IntrID == Intrinsic::amdgcn_wave_reduce_fmax ||
8310 IntrID == Intrinsic::amdgcn_wave_reduce_fadd ||
8311 IntrID == Intrinsic::amdgcn_wave_reduce_fsub;
8312 bool NeedsSignExt = IntrID == Intrinsic::amdgcn_wave_reduce_min ||
8313 IntrID == Intrinsic::amdgcn_wave_reduce_max ||
8314 IntrID == Intrinsic::amdgcn_wave_reduce_add ||
8315 IntrID == Intrinsic::amdgcn_wave_reduce_sub;
8316 auto Ext = IsFPOp ? B.buildFPExt(F32, SrcReg)
8317 : NeedsSignExt ? B.buildSExt(LLT::integer(32), SrcReg)
8318 : B.buildZExt(LLT::integer(32), SrcReg);
8319 auto NewDst =
8320 MRI.createGenericVirtualRegister(IsFPOp ? F32 : LLT::integer(32));
8321 B.buildIntrinsic(IntrID, ArrayRef<Register>{NewDst},
8322 /*hasSideEffects=*/false, /*isConvergent=*/true)
8323 .addUse(Ext.getReg(0))
8324 .addImm(MI.getOperand(3).getImm()); // strategy
8325 if (IsFPOp)
8326 B.buildFPTrunc(DstReg, NewDst);
8327 else
8328 B.buildTrunc(DstReg, NewDst);
8329 MI.eraseFromParent();
8330 return true;
8331 }
8332 case Intrinsic::amdgcn_addrspacecast_nonnull:
8333 return legalizeAddrSpaceCast(MI, MRI, B);
8334 case Intrinsic::amdgcn_make_buffer_rsrc:
8335 return legalizePointerAsRsrcIntrin(MI, MRI, B);
8336 case Intrinsic::amdgcn_kernarg_segment_ptr:
8337 if (!AMDGPU::isKernel(B.getMF().getFunction())) {
8338 // This only makes sense to call in a kernel, so just lower to null.
8339 B.buildConstant(MI.getOperand(0).getReg(), 0);
8340 MI.eraseFromParent();
8341 return true;
8342 }
8343
8346 case Intrinsic::amdgcn_implicitarg_ptr:
8347 return legalizeImplicitArgPtr(MI, MRI, B);
8348 case Intrinsic::amdgcn_workitem_id_x:
8349 return legalizeWorkitemIDIntrinsic(MI, MRI, B, 0,
8351 case Intrinsic::amdgcn_workitem_id_y:
8352 return legalizeWorkitemIDIntrinsic(MI, MRI, B, 1,
8354 case Intrinsic::amdgcn_workitem_id_z:
8355 return legalizeWorkitemIDIntrinsic(MI, MRI, B, 2,
8357 case Intrinsic::amdgcn_workgroup_id_x:
8358 return legalizeWorkGroupId(
8362 case Intrinsic::amdgcn_workgroup_id_y:
8363 return legalizeWorkGroupId(
8367 case Intrinsic::amdgcn_workgroup_id_z:
8368 return legalizeWorkGroupId(
8372 case Intrinsic::amdgcn_cluster_id_x:
8373 return ST.hasClusters() &&
8376 case Intrinsic::amdgcn_cluster_id_y:
8377 return ST.hasClusters() &&
8380 case Intrinsic::amdgcn_cluster_id_z:
8381 return ST.hasClusters() &&
8384 case Intrinsic::amdgcn_cluster_workgroup_id_x:
8385 return ST.hasClusters() &&
8388 case Intrinsic::amdgcn_cluster_workgroup_id_y:
8389 return ST.hasClusters() &&
8392 case Intrinsic::amdgcn_cluster_workgroup_id_z:
8393 return ST.hasClusters() &&
8396 case Intrinsic::amdgcn_cluster_workgroup_flat_id:
8397 return ST.hasClusters() &&
8399 case Intrinsic::amdgcn_cluster_workgroup_max_id_x:
8400 return ST.hasClusters() &&
8403 case Intrinsic::amdgcn_cluster_workgroup_max_id_y:
8404 return ST.hasClusters() &&
8407 case Intrinsic::amdgcn_cluster_workgroup_max_id_z:
8408 return ST.hasClusters() &&
8411 case Intrinsic::amdgcn_cluster_workgroup_max_flat_id:
8412 return ST.hasClusters() &&
8414 MI, MRI, B,
8416 case Intrinsic::amdgcn_wave_id:
8417 return legalizeWaveID(MI, B);
8418 case Intrinsic::amdgcn_lds_kernel_id:
8419 return legalizePreloadedArgIntrin(MI, MRI, B,
8421 case Intrinsic::amdgcn_dispatch_ptr:
8422 return legalizePreloadedArgIntrin(MI, MRI, B,
8424 case Intrinsic::amdgcn_queue_ptr:
8425 return legalizePreloadedArgIntrin(MI, MRI, B,
8427 case Intrinsic::amdgcn_implicit_buffer_ptr:
8430 case Intrinsic::amdgcn_dispatch_id:
8431 return legalizePreloadedArgIntrin(MI, MRI, B,
8433 case Intrinsic::r600_read_ngroups_x:
8434 // TODO: Emit error for hsa
8437 case Intrinsic::r600_read_ngroups_y:
8440 case Intrinsic::r600_read_ngroups_z:
8443 case Intrinsic::r600_read_local_size_x:
8444 // TODO: Could insert G_ASSERT_ZEXT from i16
8446 case Intrinsic::r600_read_local_size_y:
8447 // TODO: Could insert G_ASSERT_ZEXT from i16
8449 // TODO: Could insert G_ASSERT_ZEXT from i16
8450 case Intrinsic::r600_read_local_size_z:
8453 case Intrinsic::amdgcn_fdiv_fast:
8454 return legalizeFDIVFastIntrin(MI, MRI, B);
8455 case Intrinsic::amdgcn_is_shared:
8457 case Intrinsic::amdgcn_is_private:
8459 case Intrinsic::amdgcn_wavefrontsize: {
8460 B.buildConstant(MI.getOperand(0), ST.getWavefrontSize());
8461 MI.eraseFromParent();
8462 return true;
8463 }
8464 case Intrinsic::amdgcn_s_buffer_load:
8465 case Intrinsic::amdgcn_ptr_s_buffer_load:
8466 return legalizeSBufferLoad(Helper, MI);
8467 case Intrinsic::amdgcn_raw_buffer_store:
8468 case Intrinsic::amdgcn_raw_ptr_buffer_store:
8469 case Intrinsic::amdgcn_struct_buffer_store:
8470 case Intrinsic::amdgcn_struct_ptr_buffer_store:
8471 return legalizeBufferStore(MI, Helper, false, false);
8472 case Intrinsic::amdgcn_raw_buffer_store_format:
8473 case Intrinsic::amdgcn_raw_ptr_buffer_store_format:
8474 case Intrinsic::amdgcn_struct_buffer_store_format:
8475 case Intrinsic::amdgcn_struct_ptr_buffer_store_format:
8476 return legalizeBufferStore(MI, Helper, false, true);
8477 case Intrinsic::amdgcn_raw_tbuffer_store:
8478 case Intrinsic::amdgcn_raw_ptr_tbuffer_store:
8479 case Intrinsic::amdgcn_struct_tbuffer_store:
8480 case Intrinsic::amdgcn_struct_ptr_tbuffer_store:
8481 return legalizeBufferStore(MI, Helper, true, true);
8482 case Intrinsic::amdgcn_raw_buffer_load:
8483 case Intrinsic::amdgcn_raw_ptr_buffer_load:
8484 case Intrinsic::amdgcn_raw_atomic_buffer_load:
8485 case Intrinsic::amdgcn_raw_ptr_atomic_buffer_load:
8486 case Intrinsic::amdgcn_struct_buffer_load:
8487 case Intrinsic::amdgcn_struct_ptr_buffer_load:
8488 case Intrinsic::amdgcn_struct_atomic_buffer_load:
8489 case Intrinsic::amdgcn_struct_ptr_atomic_buffer_load:
8490 return legalizeBufferLoad(MI, Helper, false, false);
8491 case Intrinsic::amdgcn_raw_buffer_load_format:
8492 case Intrinsic::amdgcn_raw_ptr_buffer_load_format:
8493 case Intrinsic::amdgcn_struct_buffer_load_format:
8494 case Intrinsic::amdgcn_struct_ptr_buffer_load_format:
8495 return legalizeBufferLoad(MI, Helper, true, false);
8496 case Intrinsic::amdgcn_raw_tbuffer_load:
8497 case Intrinsic::amdgcn_raw_ptr_tbuffer_load:
8498 case Intrinsic::amdgcn_struct_tbuffer_load:
8499 case Intrinsic::amdgcn_struct_ptr_tbuffer_load:
8500 return legalizeBufferLoad(MI, Helper, true, true);
8501 case Intrinsic::amdgcn_raw_buffer_atomic_swap:
8502 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_swap:
8503 case Intrinsic::amdgcn_struct_buffer_atomic_swap:
8504 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_swap:
8505 case Intrinsic::amdgcn_raw_buffer_atomic_add:
8506 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_add:
8507 case Intrinsic::amdgcn_struct_buffer_atomic_add:
8508 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_add:
8509 case Intrinsic::amdgcn_raw_buffer_atomic_sub:
8510 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_sub:
8511 case Intrinsic::amdgcn_struct_buffer_atomic_sub:
8512 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_sub:
8513 case Intrinsic::amdgcn_raw_buffer_atomic_smin:
8514 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_smin:
8515 case Intrinsic::amdgcn_struct_buffer_atomic_smin:
8516 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_smin:
8517 case Intrinsic::amdgcn_raw_buffer_atomic_umin:
8518 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_umin:
8519 case Intrinsic::amdgcn_struct_buffer_atomic_umin:
8520 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_umin:
8521 case Intrinsic::amdgcn_raw_buffer_atomic_smax:
8522 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_smax:
8523 case Intrinsic::amdgcn_struct_buffer_atomic_smax:
8524 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_smax:
8525 case Intrinsic::amdgcn_raw_buffer_atomic_umax:
8526 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_umax:
8527 case Intrinsic::amdgcn_struct_buffer_atomic_umax:
8528 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_umax:
8529 case Intrinsic::amdgcn_raw_buffer_atomic_and:
8530 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_and:
8531 case Intrinsic::amdgcn_struct_buffer_atomic_and:
8532 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_and:
8533 case Intrinsic::amdgcn_raw_buffer_atomic_or:
8534 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_or:
8535 case Intrinsic::amdgcn_struct_buffer_atomic_or:
8536 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_or:
8537 case Intrinsic::amdgcn_raw_buffer_atomic_xor:
8538 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_xor:
8539 case Intrinsic::amdgcn_struct_buffer_atomic_xor:
8540 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_xor:
8541 case Intrinsic::amdgcn_raw_buffer_atomic_inc:
8542 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_inc:
8543 case Intrinsic::amdgcn_struct_buffer_atomic_inc:
8544 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_inc:
8545 case Intrinsic::amdgcn_raw_buffer_atomic_dec:
8546 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_dec:
8547 case Intrinsic::amdgcn_struct_buffer_atomic_dec:
8548 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_dec:
8549 case Intrinsic::amdgcn_raw_buffer_atomic_cmpswap:
8550 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_cmpswap:
8551 case Intrinsic::amdgcn_struct_buffer_atomic_cmpswap:
8552 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_cmpswap:
8553 case Intrinsic::amdgcn_raw_buffer_atomic_fmin:
8554 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_fmin:
8555 case Intrinsic::amdgcn_struct_buffer_atomic_fmin:
8556 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_fmin:
8557 case Intrinsic::amdgcn_raw_buffer_atomic_fmax:
8558 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_fmax:
8559 case Intrinsic::amdgcn_struct_buffer_atomic_fmax:
8560 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_fmax:
8561 case Intrinsic::amdgcn_raw_buffer_atomic_sub_clamp_u32:
8562 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_sub_clamp_u32:
8563 case Intrinsic::amdgcn_struct_buffer_atomic_sub_clamp_u32:
8564 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_sub_clamp_u32:
8565 case Intrinsic::amdgcn_raw_buffer_atomic_cond_sub_u32:
8566 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_cond_sub_u32:
8567 case Intrinsic::amdgcn_struct_buffer_atomic_cond_sub_u32:
8568 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_cond_sub_u32:
8569 case Intrinsic::amdgcn_raw_buffer_atomic_fadd:
8570 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_fadd:
8571 case Intrinsic::amdgcn_struct_buffer_atomic_fadd:
8572 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_fadd:
8573 return legalizeBufferAtomic(MI, B, IntrID);
8574 case Intrinsic::amdgcn_rsq_clamp:
8575 return legalizeRsqClampIntrinsic(MI, MRI, B);
8576 case Intrinsic::amdgcn_image_bvh_intersect_ray:
8578 case Intrinsic::amdgcn_image_bvh_dual_intersect_ray:
8579 case Intrinsic::amdgcn_image_bvh8_intersect_ray:
8581 case Intrinsic::amdgcn_swmmac_f32_16x16x128_fp8_fp8:
8582 case Intrinsic::amdgcn_swmmac_f32_16x16x128_fp8_bf8:
8583 case Intrinsic::amdgcn_swmmac_f32_16x16x128_bf8_fp8:
8584 case Intrinsic::amdgcn_swmmac_f32_16x16x128_bf8_bf8:
8585 case Intrinsic::amdgcn_swmmac_f16_16x16x128_fp8_fp8:
8586 case Intrinsic::amdgcn_swmmac_f16_16x16x128_fp8_bf8:
8587 case Intrinsic::amdgcn_swmmac_f16_16x16x128_bf8_fp8:
8588 case Intrinsic::amdgcn_swmmac_f16_16x16x128_bf8_bf8: {
8589 Register Index = MI.getOperand(5).getReg();
8590 LLT I64 = LLT::integer(64);
8591 LLT IndexArgTy = MRI.getType(Index);
8592 if (IndexArgTy != I64) {
8593 auto NewIndex = IndexArgTy.isVector() ? B.buildBitcast(I64, Index)
8594 : B.buildAnyExt(I64, Index);
8595 MI.getOperand(5).setReg(NewIndex.getReg(0));
8596 }
8597 return true;
8598 }
8599 case Intrinsic::amdgcn_swmmac_f16_16x16x32_f16:
8600 case Intrinsic::amdgcn_swmmac_bf16_16x16x32_bf16:
8601 case Intrinsic::amdgcn_swmmac_f32_16x16x32_bf16:
8602 case Intrinsic::amdgcn_swmmac_f32_16x16x32_f16:
8603 case Intrinsic::amdgcn_swmmac_f32_16x16x32_fp8_fp8:
8604 case Intrinsic::amdgcn_swmmac_f32_16x16x32_fp8_bf8:
8605 case Intrinsic::amdgcn_swmmac_f32_16x16x32_bf8_fp8:
8606 case Intrinsic::amdgcn_swmmac_f32_16x16x32_bf8_bf8: {
8607 Register Index = MI.getOperand(5).getReg();
8608 LLT I32 = LLT::integer(32);
8609 if (MRI.getType(Index) != I32)
8610 MI.getOperand(5).setReg(B.buildAnyExt(I32, Index).getReg(0));
8611 return true;
8612 }
8613 case Intrinsic::amdgcn_swmmac_f16_16x16x64_f16:
8614 case Intrinsic::amdgcn_swmmac_bf16_16x16x64_bf16:
8615 case Intrinsic::amdgcn_swmmac_f32_16x16x64_bf16:
8616 case Intrinsic::amdgcn_swmmac_bf16f32_16x16x64_bf16:
8617 case Intrinsic::amdgcn_swmmac_f32_16x16x64_f16:
8618 case Intrinsic::amdgcn_swmmac_i32_16x16x128_iu8:
8619 case Intrinsic::amdgcn_swmmac_i32_16x16x32_iu4:
8620 case Intrinsic::amdgcn_swmmac_i32_16x16x32_iu8:
8621 case Intrinsic::amdgcn_swmmac_i32_16x16x64_iu4: {
8622 Register Index = MI.getOperand(7).getReg();
8623 LLT IdxTy = IntrID == Intrinsic::amdgcn_swmmac_i32_16x16x128_iu8
8624 ? LLT::integer(64)
8625 : LLT::integer(32);
8626 LLT IndexArgTy = MRI.getType(Index);
8627 if (IndexArgTy != IdxTy) {
8628 auto NewIndex = IndexArgTy.isVector() ? B.buildBitcast(IdxTy, Index)
8629 : B.buildAnyExt(IdxTy, Index);
8630 MI.getOperand(7).setReg(NewIndex.getReg(0));
8631 }
8632 return true;
8633 }
8634
8635 case Intrinsic::amdgcn_fmed3: {
8636 GISelChangeObserver &Observer = Helper.Observer;
8637
8638 // FIXME: This is to workaround the inability of tablegen match combiners to
8639 // match intrinsics in patterns.
8640 Observer.changingInstr(MI);
8641 MI.setDesc(B.getTII().get(AMDGPU::G_AMDGPU_FMED3));
8642 MI.removeOperand(1);
8643 Observer.changedInstr(MI);
8644 return true;
8645 }
8646 case Intrinsic::amdgcn_readlane:
8647 case Intrinsic::amdgcn_writelane:
8648 case Intrinsic::amdgcn_readfirstlane:
8649 case Intrinsic::amdgcn_permlane16:
8650 case Intrinsic::amdgcn_permlanex16:
8651 case Intrinsic::amdgcn_permlane64:
8652 case Intrinsic::amdgcn_set_inactive:
8653 case Intrinsic::amdgcn_set_inactive_chain_arg:
8654 case Intrinsic::amdgcn_mov_dpp8:
8655 case Intrinsic::amdgcn_update_dpp:
8656 case Intrinsic::amdgcn_permlane_bcast:
8657 case Intrinsic::amdgcn_permlane_up:
8658 case Intrinsic::amdgcn_permlane_down:
8659 case Intrinsic::amdgcn_permlane_xor:
8660 return legalizeLaneOp(Helper, MI, IntrID);
8661 case Intrinsic::amdgcn_s_buffer_prefetch_data:
8662 return legalizeSBufferPrefetch(Helper, MI);
8663 case Intrinsic::amdgcn_dead: {
8664 // TODO: Use poison instead of undef
8665 for (const MachineOperand &Def : MI.defs())
8666 B.buildUndef(Def);
8667 MI.eraseFromParent();
8668 return true;
8669 }
8670 case Intrinsic::amdgcn_cooperative_atomic_load_32x4B:
8671 case Intrinsic::amdgcn_cooperative_atomic_load_16x8B:
8672 case Intrinsic::amdgcn_cooperative_atomic_load_8x16B:
8673 assert(MI.hasOneMemOperand() && "Expected IRTranslator to set MemOp!");
8674 B.buildLoad(MI.getOperand(0), MI.getOperand(2), **MI.memoperands_begin());
8675 MI.eraseFromParent();
8676 return true;
8677 case Intrinsic::amdgcn_cooperative_atomic_store_32x4B:
8678 case Intrinsic::amdgcn_cooperative_atomic_store_16x8B:
8679 case Intrinsic::amdgcn_cooperative_atomic_store_8x16B:
8680 assert(MI.hasOneMemOperand() && "Expected IRTranslator to set MemOp!");
8681 B.buildStore(MI.getOperand(2), MI.getOperand(1), **MI.memoperands_begin());
8682 MI.eraseFromParent();
8683 return true;
8684 case Intrinsic::amdgcn_av_load_b128:
8685 case Intrinsic::amdgcn_av_store_b128: {
8686 assert(MI.hasOneMemOperand() && "Expected IRTranslator to set MemOp!");
8687 if (IntrID == Intrinsic::amdgcn_av_load_b128)
8688 B.buildLoad(MI.getOperand(0), MI.getOperand(2), **MI.memoperands_begin());
8689 else
8690 B.buildStore(MI.getOperand(2), MI.getOperand(1),
8691 **MI.memoperands_begin());
8692 MI.eraseFromParent();
8693 return true;
8694 }
8695 case Intrinsic::amdgcn_flat_load_monitor_b32:
8696 case Intrinsic::amdgcn_flat_load_monitor_b64:
8697 case Intrinsic::amdgcn_flat_load_monitor_b128:
8698 assert(MI.hasOneMemOperand() && "Expected IRTranslator to set MemOp!");
8699 B.buildInstr(AMDGPU::G_AMDGPU_FLAT_LOAD_MONITOR)
8700 .add(MI.getOperand(0))
8701 .add(MI.getOperand(2))
8702 .addMemOperand(*MI.memoperands_begin());
8703 MI.eraseFromParent();
8704 return true;
8705 case Intrinsic::amdgcn_global_load_monitor_b32:
8706 case Intrinsic::amdgcn_global_load_monitor_b64:
8707 case Intrinsic::amdgcn_global_load_monitor_b128:
8708 assert(MI.hasOneMemOperand() && "Expected IRTranslator to set MemOp!");
8709 B.buildInstr(AMDGPU::G_AMDGPU_GLOBAL_LOAD_MONITOR)
8710 .add(MI.getOperand(0))
8711 .add(MI.getOperand(2))
8712 .addMemOperand(*MI.memoperands_begin());
8713 MI.eraseFromParent();
8714 return true;
8715 default: {
8716 if (const AMDGPU::ImageDimIntrinsicInfo *ImageDimIntr =
8718 return legalizeImageIntrinsic(MI, B, Helper.Observer, ImageDimIntr);
8719 return true;
8720 }
8721 }
8722
8723 return true;
8724}
MachineInstrBuilder & UseMI
MachineInstrBuilder MachineInstrBuilder & DefMI
static unsigned getIntrinsicID(const SDNode *N)
unsigned RegSize
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
unsigned uint64_t
static SDValue extractF64Exponent(SDValue Hi, const SDLoc &SL, SelectionDAG &DAG)
static SDValue getMad(SelectionDAG &DAG, const SDLoc &SL, EVT VT, SDValue X, SDValue Y, SDValue C, SDNodeFlags Flags=SDNodeFlags())
static bool valueIsKnownNeverF32Denorm(SDValue Src)
Return true if it's known that Src can never be an f32 denormal value.
Contains the definition of a TargetInstrInfo class that is common to all AMD GPUs.
static void packImage16bitOpsToDwords(MachineIRBuilder &B, MachineInstr &MI, SmallVectorImpl< Register > &PackedAddrs, unsigned ArgOffset, const AMDGPU::ImageDimIntrinsicInfo *Intr, bool IsA16, bool IsG16)
Turn a set of f16 typed registers in AddrRegs into a dword sized vector with f16 typed elements.
static unsigned getBufferAtomicPseudo(Intrinsic::ID IntrID)
static LLT getBufferRsrcScalarType(const LLT Ty)
static LegalityPredicate isIllegalRegisterType(const GCNSubtarget &ST, unsigned TypeIdx)
static cl::opt< bool > EnableNewLegality("amdgpu-global-isel-new-legality", cl::desc("Use GlobalISel desired legality, rather than try to use" "rules compatible with selection patterns"), cl::init(false), cl::ReallyHidden)
constexpr LLT F16
static MachineInstrBuilder buildExp(MachineIRBuilder &B, const DstOp &Dst, const SrcOp &Src, unsigned Flags)
static bool needsDenormHandlingF32(const MachineFunction &MF, Register Src, unsigned Flags)
constexpr std::initializer_list< LLT > AllVectors
static LegalizeMutation bitcastToVectorElement32(unsigned TypeIdx)
static LegalityPredicate isSmallOddVector(unsigned TypeIdx)
static LegalizeMutation oneMoreElement(unsigned TypeIdx)
constexpr LLT F64
static LegalityPredicate vectorSmallerThan(unsigned TypeIdx, unsigned Size)
constexpr LLT V2S8
static bool allowApproxFunc(const MachineFunction &MF, unsigned Flags)
constexpr LLT V4S128
constexpr LLT S16
constexpr LLT S1
constexpr LLT V2F32
static bool shouldBitcastLoadStoreType(const GCNSubtarget &ST, const LLT Ty, const LLT MemTy)
Return true if a load or store of the type should be lowered with a bitcast to a different type.
constexpr LLT S1024
static constexpr unsigned FPEnvModeBitField
constexpr LLT V7S64
static LegalizeMutation getScalarTypeFromMemDesc(unsigned TypeIdx)
static LegalityPredicate vectorWiderThan(unsigned TypeIdx, unsigned Size)
static bool shouldWidenLoad(const GCNSubtarget &ST, LLT MemoryTy, uint64_t AlignInBits, unsigned AddrSpace, unsigned Opcode)
Return true if we should legalize a load by widening an odd sized memory access up to the alignment.
static bool isRegisterVectorElementType(LLT EltTy)
static LegalizeMutation fewerEltsToSize64Vector(unsigned TypeIdx)
static LegalityPredicate isWideVec16(unsigned TypeIdx)
constexpr std::initializer_list< LLT > AllScalarTypes
static LegalityPredicate isTruncStoreToSizePowerOf2(unsigned TypeIdx)
constexpr LLT V2S16
constexpr LLT V8S16
constexpr LLT V9S32
constexpr std::initializer_list< LLT > AllS32Vectors
constexpr LLT S224
static LegalizeMutation moreElementsToNextExistingRegClass(unsigned TypeIdx)
constexpr LLT S512
constexpr LLT MaxScalar
static Register castBufferRsrcToV4I32(Register Pointer, MachineIRBuilder &B)
Cast a buffer resource (an address space 8 pointer) into a 4xi32, which is the form in which the valu...
constexpr LLT V11S32
static bool isRegisterClassType(const GCNSubtarget &ST, LLT Ty)
constexpr LLT V6S64
constexpr LLT V2S64
static std::pair< Register, Register > emitReciprocalU64(MachineIRBuilder &B, Register Val)
static LLT getBitcastRegisterType(const LLT Ty)
static LLT getBufferRsrcRegisterType(const LLT Ty)
constexpr LLT S32
constexpr LLT V2F16
static LegalizeMutation bitcastToRegisterType(unsigned TypeIdx)
static Register stripAnySourceMods(Register OrigSrc, MachineRegisterInfo &MRI)
constexpr LLT V8S32
constexpr LLT V2BF16
constexpr LLT S192
static LLT castBufferRsrcFromV4I32(MachineInstr &MI, MachineIRBuilder &B, MachineRegisterInfo &MRI, unsigned Idx)
Mutates IR (typicaly a load instruction) to use a <4 x s32> as the initial type of the operand idx an...
static bool replaceWithConstant(MachineIRBuilder &B, MachineInstr &MI, int64_t C)
static constexpr unsigned SPDenormModeBitField
constexpr LLT F32
static unsigned maxSizeForAddrSpace(const GCNSubtarget &ST, unsigned AS, bool IsLoad, bool IsAtomic)
constexpr LLT V6S32
static bool isLoadStoreSizeLegal(const GCNSubtarget &ST, const LegalityQuery &Query)
constexpr LLT S160
static MachineInstr * verifyCFIntrinsic(MachineInstr &MI, MachineRegisterInfo &MRI, MachineInstr *&Br, MachineBasicBlock *&UncondBrTarget, bool &Negated)
constexpr LLT V4S16
constexpr LLT V2S128
constexpr LLT V10S16
static LegalityPredicate numElementsNotEven(unsigned TypeIdx)
constexpr LLT V4S32
constexpr LLT V3S32
constexpr LLT V6S16
constexpr std::initializer_list< LLT > AllS64Vectors
constexpr LLT S256
constexpr LLT V2F64
static void castBufferRsrcArgToV4I32(MachineInstr &MI, MachineIRBuilder &B, unsigned Idx)
constexpr LLT V4S64
static constexpr unsigned FPEnvTrapBitField
constexpr LLT V10S32
constexpr LLT V16S32
static constexpr unsigned MaxRegisterSize
constexpr LLT V7S32
constexpr LLT S96
constexpr LLT V12S16
constexpr LLT V16S64
constexpr LLT BF16
static bool isRegisterSize(const GCNSubtarget &ST, unsigned Size)
static LegalityPredicate isWideScalarExtLoadTruncStore(unsigned TypeIdx)
static bool hasBufferRsrcWorkaround(const LLT Ty)
constexpr LLT V32S32
static void toggleSPDenormMode(bool Enable, MachineIRBuilder &B, const GCNSubtarget &ST, SIModeRegisterDefaults Mode)
constexpr LLT S64
constexpr std::initializer_list< LLT > AllS16Vectors
static bool loadStoreBitcastWorkaround(const LLT Ty)
static LLT widenToNextPowerOf2(LLT Ty)
static bool isNot(const MachineRegisterInfo &MRI, const MachineInstr &MI)
constexpr LLT V16S16
static void convertImageAddrToPacked(MachineIRBuilder &B, MachineInstr &MI, int DimIdx, int NumVAddrs)
Convert from separate vaddr components to a single vector address register, and replace the remaining...
static bool isLoadStoreLegal(const GCNSubtarget &ST, const LegalityQuery &Query)
static LegalizeMutation moreEltsToNext32Bit(unsigned TypeIdx)
constexpr LLT V5S32
constexpr LLT V5S64
constexpr LLT V3S64
static LLT getPow2VectorType(LLT Ty)
static void buildBufferLoad(unsigned Opc, Register LoadDstReg, Register RSrc, Register VIndex, Register VOffset, Register SOffset, unsigned ImmOffset, unsigned Format, unsigned AuxiliaryData, MachineMemOperand *MMO, bool IsTyped, bool HasVIndex, MachineIRBuilder &B)
constexpr LLT V8S64
static LLT getPow2ScalarType(LLT Ty)
static LegalityPredicate elementTypeIsLegal(unsigned TypeIdx)
constexpr LLT V2S32
static bool isRegisterVectorType(LLT Ty)
constexpr LLT V12S32
constexpr LLT S128
static LegalityPredicate sizeIsMultipleOf32(unsigned TypeIdx)
constexpr LLT S8
static bool isRegisterType(const GCNSubtarget &ST, LLT Ty)
static bool isKnownNonNull(Register Val, MachineRegisterInfo &MRI, const AMDGPUTargetMachine &TM, unsigned AddrSpace)
Return true if the value is a known valid address, such that a null check is not necessary.
This file declares the targeting of the Machinelegalizer class for AMDGPU.
The AMDGPU TargetMachine interface definition for hw codegen targets.
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
#define X(NUM, ENUM, NAME)
Definition ELF.h:857
static Error unsupported(const char *Str, const Triple &T)
Definition MachO.cpp:77
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< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
@ Enable
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
IRTranslator LLVM IR MI
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
Interface for Targets to specify which operations they can successfully select and how the others sho...
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Contains matchers for matching SSA Machine Instructions.
This file declares the MachineIRBuilder class.
Register Reg
Register const TargetRegisterInfo * TRI
#define R2(n)
Promote Memory to Register
Definition Mem2Reg.cpp:110
#define T
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
#define P(N)
ppc ctr loops verify
R600 Clause Merge
const SmallVectorImpl< MachineOperand > & Cond
static cl::opt< RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode > Mode("regalloc-enable-advisor", cl::Hidden, cl::init(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Default), cl::desc("Enable regalloc advisor mode"), cl::values(clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Default, "default", "Default"), clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Release, "release", "precompiled"), clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Development, "development", "for training")))
#define CH(x, y, z)
Definition SHA256.cpp:34
#define FP_DENORM_FLUSH_NONE
Definition SIDefines.h:1503
Interface definition for SIInstrInfo.
Interface definition for SIRegisterInfo.
This file defines the scope_exit class, which executes user-defined cleanup logic at scope exit.
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
static constexpr int Concat[]
bool legalizeConstHwRegRead(MachineInstr &MI, MachineIRBuilder &B, AMDGPU::Hwreg::Id HwReg, unsigned LowBit, unsigned Width) const
void buildMultiply(LegalizerHelper &Helper, MutableArrayRef< Register > Accum, ArrayRef< Register > Src0, ArrayRef< Register > Src1, bool UsePartialMad64_32, bool SeparateOddAlignedProducts) const
bool legalizeGlobalValue(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
bool legalizeFSQRTF16(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
bool legalizeIntrinsicTrunc(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
bool legalizeInsert(LegalizerHelper &Helper, MachineInstr &MI) const
std::pair< Register, unsigned > splitBufferOffsets(MachineIRBuilder &B, Register OrigOffset) const
bool legalizeBVHIntersectRayIntrinsic(MachineInstr &MI, MachineIRBuilder &B) const
bool legalizeIsAddrSpace(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B, unsigned AddrSpace) const
bool legalizeUnsignedDIV_REM(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
bool legalizeFSQRTF32(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
bool legalizeCTLZ_ZERO_POISON(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
bool legalizeAtomicCmpXChg(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
bool legalizeTrapHsa(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
bool legalizeBufferStore(MachineInstr &MI, LegalizerHelper &Helper, bool IsTyped, bool IsFormat) const
bool legalizeMul(LegalizerHelper &Helper, MachineInstr &MI) const
bool legalizeFFREXP(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
Register getSegmentAperture(unsigned AddrSpace, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
bool legalizeFDIV64(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
bool legalizePointerAsRsrcIntrin(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
To create a buffer resource from a 64-bit pointer, mask off the upper 32 bits of the pointer and repl...
bool legalizeFlogCommon(MachineInstr &MI, MachineIRBuilder &B) const
bool getLDSKernelId(Register DstReg, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
bool legalizeFExp2(MachineInstr &MI, MachineIRBuilder &B) const
bool legalizeTrap(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
bool legalizeBufferAtomic(MachineInstr &MI, MachineIRBuilder &B, Intrinsic::ID IID) const
void legalizeUnsignedDIV_REM32Impl(MachineIRBuilder &B, Register DstDivReg, Register DstRemReg, Register Num, Register Den) const
Register handleD16VData(MachineIRBuilder &B, MachineRegisterInfo &MRI, Register Reg, bool ImageStore=false) const
Handle register layout difference for f16 images for some subtargets.
bool legalizeCTLZ_CTTZ(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
bool legalizeBuildVector(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
bool legalizeFFloor(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
AMDGPULegalizerInfo(const GCNSubtarget &ST, const GCNTargetMachine &TM)
bool legalizeFDIV32(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
bool legalizeFMad(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
bool legalizeFDIV(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
bool legalizeSBufferPrefetch(LegalizerHelper &Helper, MachineInstr &MI) const
bool legalizeFExp10Unsafe(MachineIRBuilder &B, Register Dst, Register Src, unsigned Flags) const
bool legalizeFExp(MachineInstr &MI, MachineIRBuilder &B) const
bool legalizeIntrinsic(LegalizerHelper &Helper, MachineInstr &MI) const override
bool legalizeFrem(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
bool legalizePreloadedArgIntrin(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B, AMDGPUFunctionArgInfo::PreloadedValue ArgType) const
bool legalizeStore(LegalizerHelper &Helper, MachineInstr &MI) const
bool legalizeCustom(LegalizerHelper &Helper, MachineInstr &MI, LostDebugLocObserver &LocObserver) const override
Called for instructions with the Custom LegalizationAction.
bool buildPCRelGlobalAddress(Register DstReg, LLT PtrTy, MachineIRBuilder &B, const GlobalValue *GV, int64_t Offset, unsigned GAFlags=SIInstrInfo::MO_NONE) const
MachinePointerInfo getKernargSegmentPtrInfo(MachineFunction &MF) const
bool legalizeFDIV16(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
bool legalizeRsqClampIntrinsic(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
bool legalizeFExpUnsafeImpl(MachineIRBuilder &B, Register Dst, Register Src, unsigned Flags, bool IsExp10) const
std::pair< Register, Register > getScaledLogInput(MachineIRBuilder &B, Register Src, unsigned Flags) const
bool legalizeFDIVFastIntrin(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
bool loadInputValue(Register DstReg, MachineIRBuilder &B, AMDGPUFunctionArgInfo::PreloadedValue ArgType) const
bool legalizeBVHDualOrBVH8IntersectRayIntrinsic(MachineInstr &MI, MachineIRBuilder &B) const
bool legalizeInsertVectorElt(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
bool legalizeFExpUnsafe(MachineIRBuilder &B, Register Dst, Register Src, unsigned Flags) const
bool legalizeFEXPF64(MachineInstr &MI, MachineIRBuilder &B) const
bool legalizeAddrSpaceCast(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
bool legalizeExtract(LegalizerHelper &Helper, MachineInstr &MI) const
bool legalizeBufferLoad(MachineInstr &MI, LegalizerHelper &Helper, bool IsFormat, bool IsTyped) const
bool legalizeImplicitArgPtr(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
bool legalizeMinNumMaxNum(LegalizerHelper &Helper, MachineInstr &MI) const
void legalizeUnsignedDIV_REM64Impl(MachineIRBuilder &B, Register DstDivReg, Register DstRemReg, Register Num, Register Den) const
bool legalizeDebugTrap(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
bool legalizeFastUnsafeFDIV(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
bool legalizeSinCos(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
bool legalizeCTLS(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
bool legalizeWaveID(MachineInstr &MI, MachineIRBuilder &B) const
bool legalizeFroundeven(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
bool legalizeLDSKernelId(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
bool legalizeWorkGroupId(MachineInstr &MI, MachineIRBuilder &B, AMDGPUFunctionArgInfo::PreloadedValue ClusterIdPV, AMDGPUFunctionArgInfo::PreloadedValue ClusterMaxIdPV, AMDGPUFunctionArgInfo::PreloadedValue ClusterWorkGroupIdPV) const
bool legalizeSignedDIV_REM(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
bool legalizeITOFP(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B, bool Signed) const
bool legalizeFPow(MachineInstr &MI, MachineIRBuilder &B) const
bool legalizeFastUnsafeFDIV64(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
bool legalizeFPTOI(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B, bool Signed) const
bool legalizeStackSave(MachineInstr &MI, MachineIRBuilder &B) const
bool legalizeFlogUnsafe(MachineIRBuilder &B, Register Dst, Register Src, bool IsLog10, unsigned Flags) const
bool legalizeKernargMemParameter(MachineInstr &MI, MachineIRBuilder &B, uint64_t Offset, Align Alignment=Align(4)) const
Legalize a value that's loaded from kernel arguments.
bool legalizeImageIntrinsic(MachineInstr &MI, MachineIRBuilder &B, GISelChangeObserver &Observer, const AMDGPU::ImageDimIntrinsicInfo *ImageDimIntr) const
Rewrite image intrinsics to use register layouts expected by the subtarget.
void buildAbsGlobalAddress(Register DstReg, LLT PtrTy, MachineIRBuilder &B, const GlobalValue *GV, MachineRegisterInfo &MRI) const
bool legalizeGetFPEnv(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
bool getImplicitArgPtr(Register DstReg, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
bool legalizeFSQRT(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
Register getKernargParameterPtr(MachineIRBuilder &B, int64_t Offset) const
bool legalizeSBufferLoad(LegalizerHelper &Helper, MachineInstr &MI) const
bool legalizeFceil(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
bool legalizeFSQRTF64(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
bool legalizeExtractVectorElt(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
bool legalizeLoad(LegalizerHelper &Helper, MachineInstr &MI) const
Register fixStoreSourceType(MachineIRBuilder &B, Register VData, LLT MemTy, bool IsFormat) const
bool legalizeLaneOp(LegalizerHelper &Helper, MachineInstr &MI, Intrinsic::ID IID) const
bool legalizeSetFPEnv(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
bool legalizeWorkitemIDIntrinsic(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B, unsigned Dim, AMDGPUFunctionArgInfo::PreloadedValue ArgType) const
void buildLoadInputValue(Register DstReg, MachineIRBuilder &B, const ArgDescriptor *Arg, const TargetRegisterClass *ArgRC, LLT ArgTy) const
bool legalizeTrapHsaQueuePtr(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
bool legalizeFlog2(MachineInstr &MI, MachineIRBuilder &B) const
bool legalizeTrapEndpgm(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const
static std::optional< uint32_t > getLDSKernelIdMetadata(const Function &F)
void setDynLDSAlign(const Function &F, const GlobalVariable &GV)
unsigned allocateLDSGlobal(const DataLayout &DL, const GlobalVariable &GV)
bool isNoopAddrSpaceCast(unsigned SrcAS, unsigned DestAS) const override
Returns true if a cast between SrcAS and DestAS is a noop.
const std::array< unsigned, 3 > & getDims() const
static const fltSemantics & IEEEsingle()
Definition APFloat.h:304
static const fltSemantics & IEEEdouble()
Definition APFloat.h:305
static APFloat getSmallestNormalized(const fltSemantics &Sem, bool Negative=false)
Returns the smallest (by magnitude) normalized finite number in the given semantics.
Definition APFloat.h:1262
static APFloat getLargest(const fltSemantics &Sem, bool Negative=false)
Returns the largest finite number in the given semantics.
Definition APFloat.h:1242
static APFloat getInf(const fltSemantics &Sem, bool Negative=false)
Factory for Positive and Negative Infinity.
Definition APFloat.h:1202
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
size_t size() const
Get the array size.
Definition ArrayRef.h:141
@ FCMP_OEQ
0 0 0 1 True if ordered and equal
Definition InstrTypes.h:743
@ ICMP_SLT
signed less than
Definition InstrTypes.h:769
@ FCMP_OLT
0 1 0 0 True if ordered and less than
Definition InstrTypes.h:746
@ FCMP_ULE
1 1 0 1 True if unordered, less than, or equal
Definition InstrTypes.h:755
@ FCMP_OGT
0 0 1 0 True if ordered and greater than
Definition InstrTypes.h:744
@ ICMP_UGE
unsigned greater or equal
Definition InstrTypes.h:764
@ ICMP_SGT
signed greater than
Definition InstrTypes.h:767
@ FCMP_ONE
0 1 1 0 True if ordered and operands are unequal
Definition InstrTypes.h:748
@ ICMP_ULT
unsigned less than
Definition InstrTypes.h:765
@ FCMP_OLE
0 1 0 1 True if ordered and less than or equal
Definition InstrTypes.h:747
@ FCMP_ORD
0 1 1 1 True if ordered (no nans)
Definition InstrTypes.h:749
@ ICMP_NE
not equal
Definition InstrTypes.h:762
@ FCMP_UGE
1 0 1 1 True if unordered, greater than, or equal
Definition InstrTypes.h:753
ConstantFP - Floating Point Values [float, double].
Definition Constants.h:420
bool isMinusOne() const
Returns true if this value is exactly -1.0.
Definition Constants.h:488
bool isOne() const
Returns true if this value is exactly +1.0.
Definition Constants.h:485
This is the shared class of boolean and integer constants.
Definition Constants.h:87
int64_t getSExtValue() const
Return the constant as a 64-bit integer value after it has been sign extended as appropriate for the ...
Definition Constants.h:174
A debug info location.
Definition DebugLoc.h:126
Diagnostic information for unsupported feature in backend.
static constexpr ElementCount getFixed(ScalarTy MinVal)
Definition TypeSize.h:309
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition Function.cpp:356
Abstract class that contains various methods for clients to notify about changes.
virtual void changingInstr(MachineInstr &MI)=0
This instruction is about to be mutated in some way.
virtual void changedInstr(MachineInstr &MI)=0
This instruction was mutated in some way.
Simple wrapper observer that takes several observers, and calls each one for each event.
KnownBits getKnownBits(Register R)
bool hasExternalLinkage() const
Module * getParent()
Get the module that this global value is contained inside of...
LLVM_ABI const DataLayout & getDataLayout() const
Get the data layout of the module this global belongs to.
Definition Globals.cpp:205
LLVM_ABI uint64_t getGlobalSize(const DataLayout &DL) const
Get the size of this global variable in bytes.
Definition Globals.cpp:640
static constexpr LLT float64()
Get a 64-bit IEEE double value.
LLT changeElementCount(ElementCount EC) const
Return a vector or scalar with the same element type and the new element count.
constexpr unsigned getScalarSizeInBits() const
constexpr bool isScalar() const
constexpr LLT changeElementType(LLT NewEltTy) const
If this type is a vector, return a vector with the same number of elements but the new element type.
static constexpr LLT vector(ElementCount EC, unsigned ScalarSizeInBits)
Get a low-level vector of some number of elements and element width.
LLT getScalarType() const
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
constexpr uint16_t getNumElements() const
Returns the number of elements in a vector LLT.
constexpr bool isFloat() const
constexpr bool isVector() const
static constexpr LLT pointer(unsigned AddressSpace, unsigned SizeInBits)
Get a low-level pointer in the given address space.
constexpr TypeSize getSizeInBits() const
Returns the total size of the type. Must only be called on sized types.
constexpr bool isPointer() const
static constexpr LLT float16()
Get a 16-bit IEEE half value.
constexpr unsigned getAddressSpace() const
static constexpr LLT fixed_vector(unsigned NumElements, unsigned ScalarSizeInBits)
Get a low-level fixed-width vector of some number of elements and element width.
static LLT integer(unsigned SizeInBits)
static constexpr LLT bfloat16()
LLT getElementType() const
Returns the vector's element type. Only valid for vector types.
static constexpr LLT scalarOrVector(ElementCount EC, LLT ScalarTy)
static constexpr LLT float32()
Get a 32-bit IEEE float value.
LLT changeElementSize(unsigned NewEltSize) const
If this type is a vector, return a vector with the same number of elements but the new element size.
LLVM_ABI void diagnose(const DiagnosticInfo &DI)
Report a message to the currently installed diagnostic handler.
LegalizeRuleSet & minScalar(unsigned TypeIdx, const LLT Ty)
Ensure the scalar is at least as wide as Ty.
LegalizeRuleSet & legalFor(std::initializer_list< LLT > Types)
The instruction is legal when type index 0 is any type in the given list.
LegalizeRuleSet & scalarSameSizeAs(unsigned TypeIdx, unsigned SameSizeIdx)
Change the type TypeIdx to have the same scalar size as type SameSizeIdx.
LegalizeRuleSet & fewerElementsIf(LegalityPredicate Predicate, LegalizeMutation Mutation)
Remove elements to reach the type selected by the mutation if the predicate is true.
LegalizeRuleSet & clampScalarOrElt(unsigned TypeIdx, const LLT MinTy, const LLT MaxTy)
Limit the range of scalar sizes to MinTy and MaxTy.
LegalizeRuleSet & maxScalar(unsigned TypeIdx, const LLT Ty)
Ensure the scalar is at most as wide as Ty.
LegalizeRuleSet & minScalarOrElt(unsigned TypeIdx, const LLT Ty)
Ensure the scalar or element is at least as wide as Ty.
LegalizeRuleSet & clampMaxNumElements(unsigned TypeIdx, const LLT EltTy, unsigned MaxElements)
Limit the number of elements in EltTy vectors to at most MaxElements.
LegalizeRuleSet & unsupportedFor(std::initializer_list< LLT > Types)
LegalizeRuleSet & widenScalarFor(std::initializer_list< LLT > Types, LegalizeMutation Mutation)
Widen the scalar, specified in mutation, when type index 0 is any type in the given list.
LegalizeRuleSet & lower()
The instruction is lowered.
LegalizeRuleSet & moreElementsIf(LegalityPredicate Predicate, LegalizeMutation Mutation)
Add more elements to reach the type selected by the mutation if the predicate is true.
LegalizeRuleSet & lowerFor(std::initializer_list< LLT > Types)
The instruction is lowered when type index 0 is any type in the given list.
LegalizeRuleSet & clampScalar(unsigned TypeIdx, const LLT MinTy, const LLT MaxTy)
Limit the range of scalar sizes to MinTy and MaxTy.
LegalizeRuleSet & custom()
Unconditionally custom lower.
LegalizeRuleSet & clampMaxNumElementsStrict(unsigned TypeIdx, const LLT EltTy, unsigned NumElts)
Express EltTy vectors strictly using vectors with NumElts elements (or scalars when NumElts equals 1)...
LegalizeRuleSet & widenScalarIf(LegalityPredicate Predicate, LegalizeMutation Mutation)
Widen the scalar to the one selected by the mutation if the predicate is true.
LegalizeRuleSet & alwaysLegal()
LegalizeRuleSet & maxScalarIf(LegalityPredicate Predicate, unsigned TypeIdx, const LLT Ty)
Conditionally limit the maximum size of the scalar.
LegalizeRuleSet & customIf(LegalityPredicate Predicate)
LegalizeRuleSet & widenScalarToNextPow2(unsigned TypeIdx, unsigned MinSize=0)
Widen the scalar to the next power of two that is at least MinSize.
LegalizeRuleSet & scalarize(unsigned TypeIdx)
LegalizeRuleSet & legalForCartesianProduct(std::initializer_list< LLT > Types)
The instruction is legal when type indexes 0 and 1 are both in the given list.
LegalizeRuleSet & minScalarIf(LegalityPredicate Predicate, unsigned TypeIdx, const LLT Ty)
Ensure the scalar is at least as wide as Ty if condition is met.
LegalizeRuleSet & legalIf(LegalityPredicate Predicate)
The instruction is legal if predicate is true.
LegalizeRuleSet & customFor(std::initializer_list< LLT > Types)
LegalizeRuleSet & widenScalarToNextMultipleOf(unsigned TypeIdx, unsigned Size)
Widen the scalar to the next multiple of Size.
LLVM_ABI LegalizeResult lowerFMinNumMaxNum(MachineInstr &MI)
LLVM_ABI void moreElementsVectorDst(MachineInstr &MI, LLT MoreTy, unsigned OpIdx)
Legalize a single operand OpIdx of the machine instruction MI as a Def by performing it with addition...
LLVM_ABI LegalizeResult lowerInsert(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerExtract(MachineInstr &MI)
GISelValueTracking * getValueTracking() const
@ Legalized
Instruction has been legalized and the MachineFunction changed.
GISelChangeObserver & Observer
To keep track of changes made by the LegalizerHelper.
LLVM_ABI void bitcastDst(MachineInstr &MI, LLT CastTy, unsigned OpIdx)
Legalize a single operand OpIdx of the machine instruction MI as a def by inserting a G_BITCAST from ...
LLVM_ABI LegalizeResult lowerFMad(MachineInstr &MI)
MachineIRBuilder & MIRBuilder
Expose MIRBuilder so clients can set their own RecordInsertInstruction functions.
LLVM_ABI void widenScalarDst(MachineInstr &MI, LLT WideTy, unsigned OpIdx=0, unsigned TruncOpcode=TargetOpcode::G_TRUNC)
Legalize a single operand OpIdx of the machine instruction MI as a Def by extending the operand's typ...
LegalizeRuleSet & getActionDefinitionsBuilder(unsigned Opcode)
Get the action definition builder for the given opcode.
TypeSize getValue() const
Wrapper class representing physical registers. Should be passed by value.
Definition MCRegister.h:41
constexpr bool isPhysical() const
Return true if the specified register number is in the physical register namespace.
Definition MCRegister.h:72
LLVM_ABI void addSuccessor(MachineBasicBlock *Succ, BranchProbability Prob=BranchProbability::getUnknown())
Add Succ as a successor of this MachineBasicBlock.
LLVM_ABI MachineBasicBlock * splitAt(MachineInstr &SplitInst, bool UpdateLiveIns=true, LiveIntervals *LIS=nullptr)
Split a basic block into 2 pieces at SplitPoint.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineInstrBundleIterator< MachineInstr > iterator
PseudoSourceValueManager & getPSVManager() const
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
DenormalMode getDenormalMode(const fltSemantics &FPType) const
Returns the denormal handling type for the default rounding mode of the function.
void push_back(MachineBasicBlock *MBB)
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
BasicBlockListType::iterator iterator
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags F, LLT MemTy, Align BaseAlignment, const MMOMetadata &Metadata=MMOMetadata(), SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
MachineBasicBlock * CreateMachineBasicBlock(const BasicBlock *BB=nullptr, std::optional< UniqueBBID > BBID=std::nullopt)
CreateMachineInstr - Allocate a new MachineInstr.
const TargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
Helper class to build MachineInstr.
MachineFunction & getMF()
Getter for the function we currently build.
Register getReg(unsigned Idx) const
Get the register for the operand index.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addGlobalAddress(const GlobalValue *GV, int64_t Offset=0, unsigned TargetFlags=0) const
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
Representation of each machine instruction.
const MachineOperand & getOperand(unsigned i) const
A description of a memory reference used in the backend.
LocationSize getSize() const
Return the size in bytes of the memory reference.
LLT getMemoryType() const
Return the memory type of the memory reference.
@ 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).
LLVM_ABI Align getAlign() const
Return the minimum known alignment in bytes of the actual memory reference.
MachineOperand class - Representation of each machine instruction operand.
MachineBasicBlock * getMBB() const
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
void setMBB(MachineBasicBlock *MBB)
static MachineOperand CreateImm(int64_t Val)
Register getReg() const
getReg - Returns the register number.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI bool hasOneNonDBGUse(Register RegNo) const
hasOneNonDBGUse - Return true if there is exactly one non-Debug use of the specified register.
LLVM_ABI LLVM_READONLY MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
LLT getType(Register Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register.
use_instr_nodbg_iterator use_instr_nodbg_begin(Register RegNo) const
LLVM_ABI void setRegClass(Register Reg, const TargetRegisterClass *RC)
setRegClass - Set the register class of the specified virtual register.
LLVM_ABI Register createGenericVirtualRegister(LLT Ty, StringRef Name="")
Create and return a new generic virtual register with low-level type Ty.
const TargetRegisterClass * getRegClassOrNull(Register Reg) const
Return the register class of Reg, or null if Reg has not been assigned a register class yet.
const TargetRegisterInfo * getTargetRegisterInfo() const
LLVM_ABI void replaceRegWith(Register FromReg, Register ToReg)
replaceRegWith - Replace all instances of FromReg with ToReg in the machine function.
Represent a mutable reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:294
MutableArrayRef< T > drop_front(size_t N=1) const
Drop the first N elements of the array.
Definition ArrayRef.h:383
LLVM_ABI const PseudoSourceValue * getConstantPool()
Return a pseudo source value referencing the constant pool.
Wrapper class representing virtual and physical registers.
Definition Register.h:20
constexpr bool isValid() const
Definition Register.h:112
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
Definition Register.h:79
static unsigned getMaxMUBUFImmOffset(const GCNSubtarget &ST)
This class keeps track of the SPI_SP_INPUT_ADDR config register, which tells the hardware which inter...
AMDGPU::ClusterDimsAttr getClusterDims() const
SIModeRegisterDefaults getMode() const
std::tuple< const ArgDescriptor *, const TargetRegisterClass *, LLT > getPreloadedValue(AMDGPUFunctionArgInfo::PreloadedValue Value) const
static LLVM_READONLY const TargetRegisterClass * getSGPRClassForBitWidth(unsigned BitWidth)
bool allowsMisalignedMemoryAccessesImpl(unsigned Size, unsigned AddrSpace, Align Alignment, MachineMemOperand::Flags Flags=MachineMemOperand::MONone, unsigned *IsFast=nullptr) const
bool shouldEmitFixup(const GlobalValue *GV) const
bool shouldUseLDSConstAddress(const GlobalValue *GV) const
bool shouldEmitPCReloc(const GlobalValue *GV) const
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void truncate(size_type N)
Like resize, but requires that N is less than size().
void resize(size_type N)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
int64_t getImm() const
Register getReg() const
Register getStackPointerRegisterToSaveRestore() const
If a physical register, this specifies the register that llvm.savestack/llvm.restorestack should save...
unsigned getPointerSizeInBits(unsigned AS) const
A Use represents the edge between a Value definition and its users.
Definition Use.h:35
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition Value.cpp:319
self_iterator getIterator()
Definition ilist_node.h:123
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ CONSTANT_ADDRESS_32BIT
Address space for 32-bit constant memory.
@ BUFFER_STRIDED_POINTER
Address space for 192-bit fat buffer pointers with an additional index.
@ REGION_ADDRESS
Address space for region memory. (GDS)
@ LOCAL_ADDRESS
Address space for local memory.
@ CONSTANT_ADDRESS
Address space for constant memory (VTX2).
@ FLAT_ADDRESS
Address space for flat memory.
@ GLOBAL_ADDRESS
Address space for global memory (RAT0, VTX0).
@ BUFFER_FAT_POINTER
Address space for 160-bit buffer fat pointers.
@ PRIVATE_ADDRESS
Address space for private memory.
@ BUFFER_RESOURCE
Address space for 128-bit buffer resources.
int getMIMGOpcode(unsigned BaseOpcode, unsigned MIMGEncoding, unsigned VDataDwords, unsigned VAddrDwords)
bool isFlatGlobalAddrSpace(unsigned AS)
bool isGFX12Plus(const MCSubtargetInfo &STI)
constexpr int64_t getNullPointerValue(unsigned AS)
Get the null pointer value for the given address space.
bool isGFX11(const MCSubtargetInfo &STI)
LLVM_READNONE bool isLegalDPALU_DPPControl(const MCSubtargetInfo &ST, unsigned DC)
unsigned getAMDHSACodeObjectVersion(const Module &M)
LLVM_READNONE constexpr bool isKernel(CallingConv::ID CC)
LLVM_READNONE constexpr bool isEntryFunctionCC(CallingConv::ID CC)
LLVM_READNONE constexpr bool isCompute(CallingConv::ID CC)
TargetExtType * isNamedBarrier(const GlobalVariable &GV)
bool isGFX11Plus(const MCSubtargetInfo &STI)
LLVM_READONLY const MIMGBaseOpcodeInfo * getMIMGBaseOpcodeInfo(unsigned BaseOpcode)
std::pair< Register, unsigned > getBaseWithConstantOffset(MachineRegisterInfo &MRI, Register Reg, GISelValueTracking *ValueTracking=nullptr, bool CheckNUW=false)
Returns base register and constant offset.
const ImageDimIntrinsicInfo * getImageDimIntrinsicInfo(unsigned Intr)
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
@ AMDGPU_Gfx
Used for AMD graphics targets.
LLVM_ABI LegalityPredicate scalarOrEltWiderThan(unsigned TypeIdx, unsigned Size)
True iff the specified type index is a scalar or a vector with an element type that's wider than the ...
LLVM_ABI LegalityPredicate isScalar(unsigned TypeIdx)
True iff the specified type index is a scalar.
LLVM_ABI LegalityPredicate isPointer(unsigned TypeIdx)
True iff the specified type index is a pointer (with any address space).
LLVM_ABI LegalityPredicate typeInSet(unsigned TypeIdx, std::initializer_list< LLT > TypesInit)
True iff the given type index is one of the specified types.
LLVM_ABI LegalityPredicate smallerThan(unsigned TypeIdx0, unsigned TypeIdx1)
True iff the first type index has a smaller total bit size than second type index.
LLVM_ABI LegalityPredicate largerThan(unsigned TypeIdx0, unsigned TypeIdx1)
True iff the first type index has a larger total bit size than second type index.
LLVM_ABI LegalityPredicate elementTypeIs(unsigned TypeIdx, LLT EltTy)
True if the type index is a vector with element type EltTy.
LLVM_ABI LegalityPredicate sameSize(unsigned TypeIdx0, unsigned TypeIdx1)
True iff the specified type indices are both the same bit size.
LLVM_ABI LegalityPredicate scalarOrEltNarrowerThan(unsigned TypeIdx, unsigned Size)
True iff the specified type index is a scalar or vector with an element type that's narrower than the...
LegalityPredicate typeIsNot(unsigned TypeIdx, LLT Type)
True iff the given type index is not the specified type.
Predicate all(Predicate P0, Predicate P1)
True iff P0 and P1 are true.
LLVM_ABI LegalityPredicate typeIs(unsigned TypeIdx, LLT TypesInit)
True iff the given type index is the specified type.
LLVM_ABI LegalityPredicate scalarNarrowerThan(unsigned TypeIdx, unsigned Size)
True iff the specified type index is a scalar that's narrower than the given size.
LLVM_ABI LegalizeMutation changeElementCountTo(unsigned TypeIdx, unsigned FromTypeIdx)
Keep the same scalar or element type as TypeIdx, but take the number of elements from FromTypeIdx.
LLVM_ABI LegalizeMutation scalarize(unsigned TypeIdx)
Break up the vector type for the given type index into the element type.
LLVM_ABI LegalizeMutation changeElementTo(unsigned TypeIdx, unsigned FromTypeIdx)
Keep the same scalar or element type as the given type index.
LLVM_ABI LegalizeMutation widenScalarOrEltToNextPow2(unsigned TypeIdx, unsigned Min=0)
Widen the scalar type or vector element type for the given type index to the next power of 2.
LLVM_ABI LegalizeMutation changeTo(unsigned TypeIdx, LLT Ty)
Select this specific type for the given type index.
LLVM_ABI LegalizeMutation changeElementSizeTo(unsigned TypeIdx, unsigned FromTypeIdx)
Change the scalar size or element size to have the same scalar size as type index FromIndex.
Invariant opcodes: All instruction sets have these as their low opcodes.
initializer< Ty > init(const Ty &Val)
constexpr double inv_pi
constexpr double ln2
constexpr double ln10
constexpr float log2ef
Definition MathExtras.h:52
constexpr double log2e
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI Register getFunctionLiveInPhysReg(MachineFunction &MF, const TargetInstrInfo &TII, MCRegister PhysReg, const TargetRegisterClass &RC, const DebugLoc &DL, LLT RegTy=LLT())
Return a virtual register corresponding to the incoming argument register PhysReg.
Definition Utils.cpp:848
unsigned Log2_32_Ceil(uint32_t Value)
Return the ceil log base 2 of the specified value, 32 if the value is zero.
Definition MathExtras.h:339
@ Offset
Definition DWP.cpp:577
LLVM_ABI Type * getTypeForLLT(LLT Ty, LLVMContext &C)
Get the type back from LLT.
Definition Utils.cpp:1972
LLVM_ABI MachineInstr * getOpcodeDef(unsigned Opcode, Register Reg, const MachineRegisterInfo &MRI)
See if Reg is defined by an single def instruction that is Opcode.
Definition Utils.cpp:656
LLVM_ABI const ConstantFP * getConstantFPVRegVal(Register VReg, const MachineRegisterInfo &MRI)
Definition Utils.cpp:464
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
constexpr bool isInt(int64_t x)
Checks if an integer fits into the given bit width.
Definition MathExtras.h:166
@ Implicit
Not emitted register (e.g. carry, or temporary result).
@ Undef
Value of the register doesn't matter.
LLVM_ABI const llvm::fltSemantics & getFltSemanticForLLT(LLT Ty)
Get the appropriate floating point arithmetic semantic based on the bit size of the given scalar LLT.
@ Load
The value being inserted comes from a load (InsertElement only).
std::function< std::pair< unsigned, LLT >(const LegalityQuery &)> LegalizeMutation
int bit_width(T Value)
Returns the number of bits needed to represent Value if Value is nonzero.
Definition bit.h:325
void * PointerTy
constexpr bool isPowerOf2_64(uint64_t Value)
Return true if the argument is a power of two > 0 (64 bit edition.)
Definition MathExtras.h:285
constexpr int popcount(T Value) noexcept
Count the number of set bits in a value.
Definition bit.h:156
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
LLVM_ABI std::optional< int64_t > getIConstantVRegSExtVal(Register VReg, const MachineRegisterInfo &MRI)
If VReg is defined by a G_CONSTANT fits in int64_t returns it.
Definition Utils.cpp:317
int countr_zero(T Val)
Count number of 0's from the least significant bit to the most stopping at the first 1.
Definition bit.h:204
constexpr bool has_single_bit(T Value) noexcept
Definition bit.h:149
std::function< bool(const LegalityQuery &)> LegalityPredicate
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
Definition MathExtras.h:280
constexpr uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Definition Alignment.h:144
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
MutableArrayRef(T &OneElt) -> MutableArrayRef< T >
constexpr T divideCeil(U Numerator, V Denominator)
Returns the integer ceil(Numerator / Denominator).
Definition MathExtras.h:389
To bit_cast(const From &from) noexcept
Definition bit.h:90
@ Mul
Product of integers.
@ FMul
Product of floats.
@ Sub
Subtraction of integers.
@ Add
Sum of integers.
@ Fast
Assign the register banks as fast as possible (default).
DWARFExpression::Operation Op
ArrayRef(const T &OneElt) -> ArrayRef< T >
constexpr unsigned BitWidth
LLVM_ABI void eraseInstr(MachineInstr &MI, MachineRegisterInfo &MRI, LostDebugLocObserver *LocObserver=nullptr)
Definition Utils.cpp:1670
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
LLVM_ABI std::optional< ValueAndVReg > getIConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_CONSTANT returns its...
Definition Utils.cpp:436
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition STLExtras.h:1947
Align commonAlignment(Align A, uint64_t Offset)
Returns the alignment that satisfies both alignments.
Definition Alignment.h:201
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Next
Definition InstrProf.h:147
unsigned Log2(Align A)
Returns the log2 of the alignment.
Definition Alignment.h:197
T bit_floor(T Value)
Returns the largest integral power of two no greater than Value if Value is nonzero.
Definition bit.h:347
constexpr uint64_t NextPowerOf2(uint64_t A)
Returns the next power of two (in 64-bits) that is strictly greater than A.
Definition MathExtras.h:368
MCRegisterClass TargetRegisterClass
Definition FastISel.h:58
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition BitVector.h:880
#define N
static constexpr uint64_t encode(Fields... Values)
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:77
MCRegister getRegister() const
static ArgDescriptor createRegister(Register Reg, unsigned Mask=~0u)
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.
@ Dynamic
Denormals have unknown treatment.
static constexpr DenormalMode getPreserveSign()
static constexpr DenormalMode getIEEE()
bool isZero() const
Returns true if value is all zero.
Definition KnownBits.h:78
The LegalityQuery object bundles together all the information that's needed to decide whether a given...
ArrayRef< MemDesc > MMODescrs
Operations which require memory can use this to place requirements on the memory type for each MMO.
ArrayRef< LLT > Types
Matching combinators.
This class contains a discriminated union of information about pointers in memory operands,...
MachinePointerInfo getWithOffset(int64_t O) const
static LLVM_ABI MachinePointerInfo getGOT(MachineFunction &MF)
Return a MachinePointerInfo record that refers to a GOT entry.
DenormalMode FP64FP16Denormals
If this is set, neither input or output denormals are flushed for both f64 and f16/v2f16 instructions...
bool IEEE
Floating point opcodes that support exception flag gathering quiet and propagate signaling NaN inputs...
DenormalMode FP32Denormals
If this is set, neither input or output denormals are flushed for most f32 instructions.