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 B.buildFExp2(Dst, B.buildFPTrunc(F16, Mul), Flags);
4314 } else
4315 return false;
4316
4317 MI.eraseFromParent();
4318 return true;
4319}
4320
4321// Find a source register, ignoring any possible source modifiers.
4323 Register ModSrc = OrigSrc;
4324 if (MachineInstr *SrcFNeg = getOpcodeDef(AMDGPU::G_FNEG, ModSrc, MRI)) {
4325 ModSrc = SrcFNeg->getOperand(1).getReg();
4326 if (MachineInstr *SrcFAbs = getOpcodeDef(AMDGPU::G_FABS, ModSrc, MRI))
4327 ModSrc = SrcFAbs->getOperand(1).getReg();
4328 } else if (MachineInstr *SrcFAbs = getOpcodeDef(AMDGPU::G_FABS, ModSrc, MRI))
4329 ModSrc = SrcFAbs->getOperand(1).getReg();
4330 return ModSrc;
4331}
4332
4335 MachineIRBuilder &B) const {
4336
4337 const LLT S1 = LLT::scalar(1);
4338 Register Dst = MI.getOperand(0).getReg();
4339 Register OrigSrc = MI.getOperand(1).getReg();
4340 unsigned Flags = MI.getFlags();
4341 assert(ST.hasFractBug() && MRI.getType(Dst) == F64 &&
4342 "this should not have been custom lowered");
4343
4344 // V_FRACT is buggy on SI, so the F32 version is never used and (x-floor(x))
4345 // is used instead. However, SI doesn't have V_FLOOR_F64, so the most
4346 // efficient way to implement it is using V_FRACT_F64. The workaround for the
4347 // V_FRACT bug is:
4348 // fract(x) = isnan(x) ? x : min(V_FRACT(x), 0.99999999999999999)
4349 //
4350 // Convert floor(x) to (x - fract(x))
4351
4352 auto Fract = B.buildIntrinsic(Intrinsic::amdgcn_fract, {F64})
4353 .addUse(OrigSrc)
4354 .setMIFlags(Flags);
4355
4356 // Give source modifier matching some assistance before obscuring a foldable
4357 // pattern.
4358
4359 // TODO: We can avoid the neg on the fract? The input sign to fract
4360 // shouldn't matter?
4361 Register ModSrc = stripAnySourceMods(OrigSrc, MRI);
4362
4363 auto Const =
4364 B.buildFConstant(F64, llvm::bit_cast<double>(0x3fefffffffffffff));
4365
4367
4368 // We don't need to concern ourselves with the snan handling difference, so
4369 // use the one which will directly select.
4370 const SIMachineFunctionInfo *MFI = B.getMF().getInfo<SIMachineFunctionInfo>();
4371 if (MFI->getMode().IEEE)
4372 B.buildFMinNumIEEE(Min, Fract, Const, Flags);
4373 else
4374 B.buildFMinNum(Min, Fract, Const, Flags);
4375
4376 Register CorrectedFract = Min;
4377 if (!MI.getFlag(MachineInstr::FmNoNans)) {
4378 auto IsNan = B.buildFCmp(CmpInst::FCMP_ORD, S1, ModSrc, ModSrc, Flags);
4379 CorrectedFract = B.buildSelect(F64, IsNan, ModSrc, Min, Flags).getReg(0);
4380 }
4381
4382 auto NegFract = B.buildFNeg(F64, CorrectedFract, Flags);
4383 B.buildFAdd(Dst, OrigSrc, NegFract, Flags);
4384
4385 MI.eraseFromParent();
4386 return true;
4387}
4388
4389// Turn an illegal packed v2i16/v2f16 build vector into bit operations.
4390// TODO: This should probably be a bitcast action in LegalizerHelper.
4393 Register Dst = MI.getOperand(0).getReg();
4394 const LLT I32 = LLT::integer(32);
4395 const LLT I16 = LLT::integer(16);
4396 assert(MRI.getType(Dst).isVector() &&
4397 MRI.getType(Dst).getNumElements() == 2 &&
4398 MRI.getType(Dst).getScalarSizeInBits() == 16);
4399
4400 Register Src0 = MI.getOperand(1).getReg();
4401 Register Src1 = MI.getOperand(2).getReg();
4402
4403 if (MI.getOpcode() == AMDGPU::G_BUILD_VECTOR_TRUNC) {
4404 assert(MRI.getType(Src0) == I32);
4405 Src0 = B.buildTrunc(I16, MI.getOperand(1).getReg()).getReg(0);
4406 Src1 = B.buildTrunc(I16, MI.getOperand(2).getReg()).getReg(0);
4407 }
4408
4409 auto Merge = B.buildMergeLikeInstr(I32, {Src0, Src1});
4410 B.buildBitcast(Dst, Merge);
4411
4412 MI.eraseFromParent();
4413 return true;
4414}
4415
4416// Build a big integer multiply or multiply-add using MAD_64_32 instructions.
4417//
4418// Source and accumulation registers must all be 32-bits.
4419//
4420// TODO: When the multiply is uniform, we should produce a code sequence
4421// that is better suited to instruction selection on the SALU. Instead of
4422// the outer loop going over parts of the result, the outer loop should go
4423// over parts of one of the factors. This should result in instruction
4424// selection that makes full use of S_ADDC_U32 instructions.
4427 ArrayRef<Register> Src0,
4428 ArrayRef<Register> Src1,
4429 bool UsePartialMad64_32,
4430 bool SeparateOddAlignedProducts) const {
4431 // Use (possibly empty) vectors of S1 registers to represent the set of
4432 // carries from one pair of positions to the next.
4433 using Carry = SmallVector<Register, 2>;
4434
4435 MachineIRBuilder &B = Helper.MIRBuilder;
4436 GISelValueTracking &VT = *Helper.getValueTracking();
4437
4438 const LLT S1 = LLT::scalar(1);
4439 const LLT I32 = LLT::integer(32);
4440 const LLT I64 = LLT::integer(64);
4441
4442 Register Zero32;
4443 Register Zero64;
4444
4445 auto getZero32 = [&]() -> Register {
4446 if (!Zero32)
4447 Zero32 = B.buildConstant(I32, 0).getReg(0);
4448 return Zero32;
4449 };
4450 auto getZero64 = [&]() -> Register {
4451 if (!Zero64)
4452 Zero64 = B.buildConstant(I64, 0).getReg(0);
4453 return Zero64;
4454 };
4455
4456 SmallVector<bool, 2> Src0KnownZeros, Src1KnownZeros;
4457 for (unsigned i = 0; i < Src0.size(); ++i) {
4458 Src0KnownZeros.push_back(VT.getKnownBits(Src0[i]).isZero());
4459 Src1KnownZeros.push_back(VT.getKnownBits(Src1[i]).isZero());
4460 }
4461
4462 // Merge the given carries into the 32-bit LocalAccum, which is modified
4463 // in-place.
4464 //
4465 // Returns the carry-out, which is a single S1 register or null.
4466 auto mergeCarry =
4467 [&](Register &LocalAccum, const Carry &CarryIn) -> Register {
4468 if (CarryIn.empty())
4469 return Register();
4470
4471 bool HaveCarryOut = true;
4472 Register CarryAccum;
4473 if (CarryIn.size() == 1) {
4474 if (!LocalAccum) {
4475 LocalAccum = B.buildZExt(I32, CarryIn[0]).getReg(0);
4476 return Register();
4477 }
4478
4479 CarryAccum = getZero32();
4480 } else {
4481 CarryAccum = B.buildZExt(I32, CarryIn[0]).getReg(0);
4482 for (unsigned i = 1; i + 1 < CarryIn.size(); ++i) {
4483 CarryAccum =
4484 B.buildUAdde(I32, S1, CarryAccum, getZero32(), CarryIn[i])
4485 .getReg(0);
4486 }
4487
4488 if (!LocalAccum) {
4489 LocalAccum = getZero32();
4490 HaveCarryOut = false;
4491 }
4492 }
4493
4494 auto Add =
4495 B.buildUAdde(I32, S1, CarryAccum, LocalAccum, CarryIn.back());
4496 LocalAccum = Add.getReg(0);
4497 return HaveCarryOut ? Add.getReg(1) : Register();
4498 };
4499
4500 // Build a multiply-add chain to compute
4501 //
4502 // LocalAccum + (partial products at DstIndex)
4503 // + (opportunistic subset of CarryIn)
4504 //
4505 // LocalAccum is an array of one or two 32-bit registers that are updated
4506 // in-place. The incoming registers may be null.
4507 //
4508 // In some edge cases, carry-ins can be consumed "for free". In that case,
4509 // the consumed carry bits are removed from CarryIn in-place.
4510 auto buildMadChain =
4511 [&](MutableArrayRef<Register> LocalAccum, unsigned DstIndex, Carry &CarryIn)
4512 -> Carry {
4513 assert((DstIndex + 1 < Accum.size() && LocalAccum.size() == 2) ||
4514 (DstIndex + 1 >= Accum.size() && LocalAccum.size() == 1));
4515
4516 Carry CarryOut;
4517 unsigned j0 = 0;
4518
4519 // Use plain 32-bit multiplication for the most significant part of the
4520 // result by default.
4521 if (LocalAccum.size() == 1 &&
4522 (!UsePartialMad64_32 || !CarryIn.empty())) {
4523 do {
4524 // Skip multiplication if one of the operands is 0
4525 unsigned j1 = DstIndex - j0;
4526 if (Src0KnownZeros[j0] || Src1KnownZeros[j1]) {
4527 ++j0;
4528 continue;
4529 }
4530 auto Mul = B.buildMul(I32, Src0[j0], Src1[j1]);
4531 if (!LocalAccum[0] || VT.getKnownBits(LocalAccum[0]).isZero()) {
4532 LocalAccum[0] = Mul.getReg(0);
4533 } else {
4534 if (CarryIn.empty()) {
4535 LocalAccum[0] = B.buildAdd(I32, LocalAccum[0], Mul).getReg(0);
4536 } else {
4537 LocalAccum[0] =
4538 B.buildUAdde(I32, S1, LocalAccum[0], Mul, CarryIn.back())
4539 .getReg(0);
4540 CarryIn.pop_back();
4541 }
4542 }
4543 ++j0;
4544 } while (j0 <= DstIndex && (!UsePartialMad64_32 || !CarryIn.empty()));
4545 }
4546
4547 // Build full 64-bit multiplies.
4548 if (j0 <= DstIndex) {
4549 bool HaveSmallAccum = false;
4550 Register Tmp;
4551
4552 if (LocalAccum[0]) {
4553 if (LocalAccum.size() == 1) {
4554 Tmp = B.buildAnyExt(I64, LocalAccum[0]).getReg(0);
4555 HaveSmallAccum = true;
4556 } else if (LocalAccum[1]) {
4557 Tmp = B.buildMergeLikeInstr(I64, LocalAccum).getReg(0);
4558 HaveSmallAccum = false;
4559 } else {
4560 Tmp = B.buildZExt(I64, LocalAccum[0]).getReg(0);
4561 HaveSmallAccum = true;
4562 }
4563 } else {
4564 assert(LocalAccum.size() == 1 || !LocalAccum[1]);
4565 Tmp = getZero64();
4566 HaveSmallAccum = true;
4567 }
4568
4569 do {
4570 unsigned j1 = DstIndex - j0;
4571 if (Src0KnownZeros[j0] || Src1KnownZeros[j1]) {
4572 ++j0;
4573 continue;
4574 }
4575 auto Mad = B.buildInstr(AMDGPU::G_AMDGPU_MAD_U64_U32, {I64, S1},
4576 {Src0[j0], Src1[j1], Tmp});
4577 Tmp = Mad.getReg(0);
4578 if (!HaveSmallAccum)
4579 CarryOut.push_back(Mad.getReg(1));
4580 HaveSmallAccum = false;
4581
4582 ++j0;
4583 } while (j0 <= DstIndex);
4584
4585 auto Unmerge = B.buildUnmerge(I32, Tmp);
4586 LocalAccum[0] = Unmerge.getReg(0);
4587 if (LocalAccum.size() > 1)
4588 LocalAccum[1] = Unmerge.getReg(1);
4589 }
4590
4591 // Every partial product contributing to this destination index was
4592 // skipped because an operand half is known zero, so nothing has been
4593 // accumulated and the result is zero.
4594 if (!LocalAccum[0])
4595 LocalAccum[0] = getZero32();
4596
4597 // A second element is only ever requested when the full 64-bit multiply
4598 // block above runs, which always writes it.
4599 assert((LocalAccum.size() == 1 || LocalAccum[1]) &&
4600 "Uninitialized accumulator part");
4601
4602 return CarryOut;
4603 };
4604
4605 // Outer multiply loop, iterating over destination parts from least
4606 // significant to most significant parts.
4607 //
4608 // The columns of the following diagram correspond to the destination parts
4609 // affected by one iteration of the outer loop (ignoring boundary
4610 // conditions).
4611 //
4612 // Dest index relative to 2 * i: 1 0 -1
4613 // ------
4614 // Carries from previous iteration: e o
4615 // Even-aligned partial product sum: E E .
4616 // Odd-aligned partial product sum: O O
4617 //
4618 // 'o' is OddCarry, 'e' is EvenCarry.
4619 // EE and OO are computed from partial products via buildMadChain and use
4620 // accumulation where possible and appropriate.
4621 //
4622 Register SeparateOddCarry;
4623 Carry EvenCarry;
4624 Carry OddCarry;
4625
4626 for (unsigned i = 0; i <= Accum.size() / 2; ++i) {
4627 Carry OddCarryIn = std::move(OddCarry);
4628 Carry EvenCarryIn = std::move(EvenCarry);
4629 OddCarry.clear();
4630 EvenCarry.clear();
4631
4632 // Partial products at offset 2 * i.
4633 if (2 * i < Accum.size()) {
4634 auto LocalAccum = Accum.drop_front(2 * i).take_front(2);
4635 EvenCarry = buildMadChain(LocalAccum, 2 * i, EvenCarryIn);
4636 }
4637
4638 // Partial products at offset 2 * i - 1.
4639 if (i > 0) {
4640 if (!SeparateOddAlignedProducts) {
4641 auto LocalAccum = Accum.drop_front(2 * i - 1).take_front(2);
4642 OddCarry = buildMadChain(LocalAccum, 2 * i - 1, OddCarryIn);
4643 } else {
4644 bool IsHighest = 2 * i >= Accum.size();
4645 Register SeparateOddOut[2];
4646 auto LocalAccum = MutableArrayRef(SeparateOddOut)
4647 .take_front(IsHighest ? 1 : 2);
4648 OddCarry = buildMadChain(LocalAccum, 2 * i - 1, OddCarryIn);
4649
4651
4652 if (i == 1) {
4653 if (!IsHighest)
4654 Lo = B.buildUAddo(I32, S1, Accum[2 * i - 1], SeparateOddOut[0]);
4655 else
4656 Lo = B.buildAdd(I32, Accum[2 * i - 1], SeparateOddOut[0]);
4657 } else {
4658 Lo = B.buildUAdde(I32, S1, Accum[2 * i - 1], SeparateOddOut[0],
4659 SeparateOddCarry);
4660 }
4661 Accum[2 * i - 1] = Lo->getOperand(0).getReg();
4662
4663 if (!IsHighest) {
4664 auto Hi = B.buildUAdde(I32, S1, Accum[2 * i], SeparateOddOut[1],
4665 Lo->getOperand(1).getReg());
4666 Accum[2 * i] = Hi.getReg(0);
4667 SeparateOddCarry = Hi.getReg(1);
4668 }
4669 }
4670 }
4671
4672 // Add in the carries from the previous iteration
4673 if (i > 0) {
4674 if (Register CarryOut = mergeCarry(Accum[2 * i - 1], OddCarryIn))
4675 EvenCarryIn.push_back(CarryOut);
4676
4677 if (2 * i < Accum.size()) {
4678 if (Register CarryOut = mergeCarry(Accum[2 * i], EvenCarryIn))
4679 OddCarry.push_back(CarryOut);
4680 }
4681 }
4682 }
4683}
4684
4685// Custom narrowing of wide multiplies using wide multiply-add instructions.
4686//
4687// TODO: If the multiply is followed by an addition, we should attempt to
4688// integrate it to make better use of V_MAD_U64_U32's multiply-add capabilities.
4690 MachineInstr &MI) const {
4691 assert(ST.hasMad64_32());
4692 assert(MI.getOpcode() == TargetOpcode::G_MUL);
4693
4694 MachineIRBuilder &B = Helper.MIRBuilder;
4695 MachineRegisterInfo &MRI = *B.getMRI();
4696
4697 Register DstReg = MI.getOperand(0).getReg();
4698 Register Src0 = MI.getOperand(1).getReg();
4699 Register Src1 = MI.getOperand(2).getReg();
4700
4701 LLT Ty = MRI.getType(DstReg);
4702 assert(Ty.isScalar());
4703
4704 unsigned Size = Ty.getSizeInBits();
4705 if (ST.useVMulU64Inst() && Size == 64)
4706 return true;
4707
4708 unsigned NumParts = Size / 32;
4709 assert((Size % 32) == 0);
4710 assert(NumParts >= 2);
4711
4712 // Whether to use MAD_64_32 for partial products whose high half is
4713 // discarded. This avoids some ADD instructions but risks false dependency
4714 // stalls on some subtargets in some cases.
4715 const bool UsePartialMad64_32 = ST.getGeneration() < AMDGPUSubtarget::GFX10;
4716
4717 // Whether to compute odd-aligned partial products separately. This is
4718 // advisable on subtargets where the accumulator of MAD_64_32 must be placed
4719 // in an even-aligned VGPR.
4720 const bool SeparateOddAlignedProducts = ST.hasFullRate64Ops();
4721
4722 LLT I32 = LLT::integer(32);
4723 SmallVector<Register, 2> Src0Parts, Src1Parts;
4724 for (unsigned i = 0; i < NumParts; ++i) {
4725 Src0Parts.push_back(MRI.createGenericVirtualRegister(I32));
4726 Src1Parts.push_back(MRI.createGenericVirtualRegister(I32));
4727 }
4728 B.buildUnmerge(Src0Parts, Src0);
4729 B.buildUnmerge(Src1Parts, Src1);
4730
4731 SmallVector<Register, 2> AccumRegs(NumParts);
4732 buildMultiply(Helper, AccumRegs, Src0Parts, Src1Parts, UsePartialMad64_32,
4733 SeparateOddAlignedProducts);
4734
4735 B.buildMergeLikeInstr(DstReg, AccumRegs);
4736 MI.eraseFromParent();
4737 return true;
4738}
4739
4740// Legalize ctlz/cttz to ffbh/ffbl instead of the default legalization to
4741// ctlz/cttz_zero_poison. This allows us to fix up the result for the zero input
4742// case with a single min instruction instead of a compare+select.
4745 MachineIRBuilder &B) const {
4746 Register Dst = MI.getOperand(0).getReg();
4747 Register Src = MI.getOperand(1).getReg();
4748 LLT DstTy = MRI.getType(Dst);
4749 LLT SrcTy = MRI.getType(Src);
4750
4751 unsigned NewOpc = MI.getOpcode() == AMDGPU::G_CTLZ
4752 ? AMDGPU::G_AMDGPU_FFBH_U32
4753 : AMDGPU::G_AMDGPU_FFBL_B32;
4754 auto Tmp = B.buildInstr(NewOpc, {DstTy}, {Src});
4755 B.buildUMin(Dst, Tmp, B.buildConstant(DstTy, SrcTy.getSizeInBits()));
4756
4757 MI.eraseFromParent();
4758 return true;
4759}
4760
4763 MachineIRBuilder &B) const {
4764 Register Dst = MI.getOperand(0).getReg();
4765 Register Src = MI.getOperand(1).getReg();
4766 LLT SrcTy = MRI.getType(Src);
4767 TypeSize NumBits = SrcTy.getSizeInBits();
4768
4769 assert(NumBits < 32u);
4770
4771 const LLT I32 = LLT::integer(32);
4772 auto ShiftAmt = B.buildConstant(I32, 32u - NumBits);
4773 auto Extend = B.buildAnyExt(I32, {Src}).getReg(0u);
4774 auto Shift = B.buildShl(I32, Extend, ShiftAmt);
4775 auto Ctlz = B.buildInstr(AMDGPU::G_AMDGPU_FFBH_U32, {I32}, {Shift});
4776 B.buildTrunc(Dst, Ctlz);
4777 MI.eraseFromParent();
4778 return true;
4779}
4780
4783 MachineIRBuilder &B) const {
4784 Register Dst = MI.getOperand(0).getReg();
4785 Register Src = MI.getOperand(1).getReg();
4786 LLT SrcTy = MRI.getType(Src);
4787 const LLT I32 = LLT::integer(32);
4788 assert(SrcTy == I32 && "legalizeCTLS only supports i32");
4789 unsigned BitWidth = SrcTy.getSizeInBits();
4790
4791 auto Sffbh = B.buildIntrinsic(Intrinsic::amdgcn_sffbh, {I32}).addUse(Src);
4792 auto Clamped = B.buildUMin(I32, Sffbh, B.buildConstant(I32, BitWidth));
4793 B.buildSub(Dst, Clamped, B.buildConstant(I32, 1));
4794 MI.eraseFromParent();
4795 return true;
4796}
4797
4798// Check that this is a G_XOR x, -1
4799static bool isNot(const MachineRegisterInfo &MRI, const MachineInstr &MI) {
4800 if (MI.getOpcode() != TargetOpcode::G_XOR)
4801 return false;
4802 auto ConstVal = getIConstantVRegSExtVal(MI.getOperand(2).getReg(), MRI);
4803 return ConstVal == -1;
4804}
4805
4806// Return the use branch instruction, otherwise null if the usage is invalid.
4807static MachineInstr *
4809 MachineBasicBlock *&UncondBrTarget, bool &Negated) {
4810 Register CondDef = MI.getOperand(0).getReg();
4811 if (!MRI.hasOneNonDBGUse(CondDef))
4812 return nullptr;
4813
4814 MachineBasicBlock *Parent = MI.getParent();
4815 MachineInstr *UseMI = &*MRI.use_instr_nodbg_begin(CondDef);
4816
4817 if (isNot(MRI, *UseMI)) {
4818 Register NegatedCond = UseMI->getOperand(0).getReg();
4819 if (!MRI.hasOneNonDBGUse(NegatedCond))
4820 return nullptr;
4821
4822 // We're deleting the def of this value, so we need to remove it.
4823 eraseInstr(*UseMI, MRI);
4824
4825 UseMI = &*MRI.use_instr_nodbg_begin(NegatedCond);
4826 Negated = true;
4827 }
4828
4829 if (UseMI->getParent() != Parent || UseMI->getOpcode() != AMDGPU::G_BRCOND)
4830 return nullptr;
4831
4832 // Make sure the cond br is followed by a G_BR, or is the last instruction.
4833 MachineBasicBlock::iterator Next = std::next(UseMI->getIterator());
4834 if (Next == Parent->end()) {
4835 MachineFunction::iterator NextMBB = std::next(Parent->getIterator());
4836 if (NextMBB == Parent->getParent()->end()) // Illegal intrinsic use.
4837 return nullptr;
4838 UncondBrTarget = &*NextMBB;
4839 } else {
4840 if (Next->getOpcode() != AMDGPU::G_BR)
4841 return nullptr;
4842 Br = &*Next;
4843 UncondBrTarget = Br->getOperand(0).getMBB();
4844 }
4845
4846 return UseMI;
4847}
4848
4851 const ArgDescriptor *Arg,
4852 const TargetRegisterClass *ArgRC,
4853 LLT ArgTy) const {
4854 MCRegister SrcReg = Arg->getRegister();
4855 assert(SrcReg.isPhysical() && "Physical register expected");
4856 assert(DstReg.isVirtual() && "Virtual register expected");
4857
4858 Register LiveIn = getFunctionLiveInPhysReg(B.getMF(), B.getTII(), SrcReg,
4859 *ArgRC, B.getDebugLoc(), ArgTy);
4860 if (Arg->isMasked()) {
4861 // TODO: Should we try to emit this once in the entry block?
4862 const LLT I32 = LLT::integer(32);
4863 const unsigned Mask = Arg->getMask();
4864 const unsigned Shift = llvm::countr_zero<unsigned>(Mask);
4865
4866 Register AndMaskSrc = LiveIn;
4867
4868 // TODO: Avoid clearing the high bits if we know workitem id y/z are always
4869 // 0.
4870 if (Shift != 0) {
4871 auto ShiftAmt = B.buildConstant(I32, Shift);
4872 AndMaskSrc = B.buildLShr(I32, LiveIn, ShiftAmt).getReg(0);
4873 }
4874
4875 B.buildAnd(DstReg, AndMaskSrc, B.buildConstant(I32, Mask >> Shift));
4876 } else {
4877 B.buildCopy(DstReg, LiveIn);
4878 }
4879}
4880
4885 AMDGPUFunctionArgInfo::PreloadedValue ClusterWorkGroupIdPV) const {
4886 Register DstReg = MI.getOperand(0).getReg();
4887 if (!ST.hasClusters()) {
4888 if (!loadInputValue(DstReg, B, WorkGroupIdPV))
4889 return false;
4890 MI.eraseFromParent();
4891 return true;
4892 }
4893
4894 // Clusters are supported. Return the global position in the grid. If clusters
4895 // are enabled, WorkGroupIdPV returns the cluster ID not the workgroup ID.
4896
4897 // WorkGroupIdXYZ = ClusterId == 0 ?
4898 // ClusterIdXYZ :
4899 // ClusterIdXYZ * (ClusterMaxIdXYZ + 1) + ClusterWorkGroupIdXYZ
4900 MachineRegisterInfo &MRI = *B.getMRI();
4901 const LLT I32 = LLT::integer(32);
4902 Register ClusterIdXYZ = MRI.createGenericVirtualRegister(I32);
4903 Register ClusterMaxIdXYZ = MRI.createGenericVirtualRegister(I32);
4904 Register ClusterWorkGroupIdXYZ = MRI.createGenericVirtualRegister(I32);
4905 if (!loadInputValue(ClusterIdXYZ, B, WorkGroupIdPV) ||
4906 !loadInputValue(ClusterWorkGroupIdXYZ, B, ClusterWorkGroupIdPV) ||
4907 !loadInputValue(ClusterMaxIdXYZ, B, ClusterMaxIdPV))
4908 return false;
4909
4910 auto One = B.buildConstant(I32, 1);
4911 auto ClusterSizeXYZ = B.buildAdd(I32, ClusterMaxIdXYZ, One);
4912 auto GlobalIdXYZ = B.buildAdd(I32, ClusterWorkGroupIdXYZ,
4913 B.buildMul(I32, ClusterIdXYZ, ClusterSizeXYZ));
4914
4915 const SIMachineFunctionInfo *MFI = B.getMF().getInfo<SIMachineFunctionInfo>();
4916
4917 switch (MFI->getClusterDims().getKind()) {
4920 B.buildCopy(DstReg, GlobalIdXYZ);
4921 MI.eraseFromParent();
4922 return true;
4923 }
4925 B.buildCopy(DstReg, ClusterIdXYZ);
4926 MI.eraseFromParent();
4927 return true;
4928 }
4930 using namespace AMDGPU::Hwreg;
4931 unsigned ClusterIdField = HwregEncoding::encode(ID_IB_STS2, 6, 4);
4932 Register ClusterId = MRI.createGenericVirtualRegister(I32);
4933 MRI.setRegClass(ClusterId, &AMDGPU::SReg_32RegClass);
4934 B.buildInstr(AMDGPU::S_GETREG_B32_const)
4935 .addDef(ClusterId)
4936 .addImm(ClusterIdField);
4937 auto Zero = B.buildConstant(I32, 0);
4938 auto NoClusters =
4939 B.buildICmp(CmpInst::ICMP_EQ, LLT::scalar(1), ClusterId, Zero);
4940 B.buildSelect(DstReg, NoClusters, ClusterIdXYZ, GlobalIdXYZ);
4941 MI.eraseFromParent();
4942 return true;
4943 }
4944 }
4945
4946 llvm_unreachable("nothing should reach here");
4947}
4948
4950 Register DstReg, MachineIRBuilder &B,
4952 const SIMachineFunctionInfo *MFI = B.getMF().getInfo<SIMachineFunctionInfo>();
4953 const ArgDescriptor *Arg = nullptr;
4954 const TargetRegisterClass *ArgRC = nullptr;
4955 LLT ArgTy;
4956
4957 CallingConv::ID CC = B.getMF().getFunction().getCallingConv();
4958 const ArgDescriptor WorkGroupIDX =
4959 ArgDescriptor::createRegister(AMDGPU::TTMP9);
4960 // If GridZ is not programmed in an entry function then the hardware will set
4961 // it to all zeros, so there is no need to mask the GridY value in the low
4962 // order bits.
4963 const ArgDescriptor WorkGroupIDY = ArgDescriptor::createRegister(
4964 AMDGPU::TTMP7,
4965 AMDGPU::isEntryFunctionCC(CC) && !MFI->hasWorkGroupIDZ() ? ~0u : 0xFFFFu);
4966 const ArgDescriptor WorkGroupIDZ =
4967 ArgDescriptor::createRegister(AMDGPU::TTMP7, 0xFFFF0000u);
4968 const ArgDescriptor ClusterWorkGroupIDX =
4969 ArgDescriptor::createRegister(AMDGPU::TTMP6, 0x0000000Fu);
4970 const ArgDescriptor ClusterWorkGroupIDY =
4971 ArgDescriptor::createRegister(AMDGPU::TTMP6, 0x000000F0u);
4972 const ArgDescriptor ClusterWorkGroupIDZ =
4973 ArgDescriptor::createRegister(AMDGPU::TTMP6, 0x00000F00u);
4974 const ArgDescriptor ClusterWorkGroupMaxIDX =
4975 ArgDescriptor::createRegister(AMDGPU::TTMP6, 0x0000F000u);
4976 const ArgDescriptor ClusterWorkGroupMaxIDY =
4977 ArgDescriptor::createRegister(AMDGPU::TTMP6, 0x000F0000u);
4978 const ArgDescriptor ClusterWorkGroupMaxIDZ =
4979 ArgDescriptor::createRegister(AMDGPU::TTMP6, 0x00F00000u);
4980 const ArgDescriptor ClusterWorkGroupMaxFlatID =
4981 ArgDescriptor::createRegister(AMDGPU::TTMP6, 0x0F000000u);
4982
4983 auto LoadConstant = [&](unsigned N) {
4984 B.buildConstant(DstReg, N);
4985 return true;
4986 };
4987
4988 if (ST.hasArchitectedSGPRs() &&
4990 AMDGPU::ClusterDimsAttr ClusterDims = MFI->getClusterDims();
4991 bool HasFixedDims = ClusterDims.isFixedDims();
4992
4993 switch (ArgType) {
4995 Arg = &WorkGroupIDX;
4996 ArgRC = &AMDGPU::SReg_32RegClass;
4997 ArgTy = LLT::integer(32);
4998 break;
5000 Arg = &WorkGroupIDY;
5001 ArgRC = &AMDGPU::SReg_32RegClass;
5002 ArgTy = LLT::integer(32);
5003 break;
5005 Arg = &WorkGroupIDZ;
5006 ArgRC = &AMDGPU::SReg_32RegClass;
5007 ArgTy = LLT::integer(32);
5008 break;
5010 if (HasFixedDims && ClusterDims.getDims()[0] == 1)
5011 return LoadConstant(0);
5012 Arg = &ClusterWorkGroupIDX;
5013 ArgRC = &AMDGPU::SReg_32RegClass;
5014 ArgTy = LLT::integer(32);
5015 break;
5017 if (HasFixedDims && ClusterDims.getDims()[1] == 1)
5018 return LoadConstant(0);
5019 Arg = &ClusterWorkGroupIDY;
5020 ArgRC = &AMDGPU::SReg_32RegClass;
5021 ArgTy = LLT::integer(32);
5022 break;
5024 if (HasFixedDims && ClusterDims.getDims()[2] == 1)
5025 return LoadConstant(0);
5026 Arg = &ClusterWorkGroupIDZ;
5027 ArgRC = &AMDGPU::SReg_32RegClass;
5028 ArgTy = LLT::integer(32);
5029 break;
5031 if (HasFixedDims)
5032 return LoadConstant(ClusterDims.getDims()[0] - 1);
5033 Arg = &ClusterWorkGroupMaxIDX;
5034 ArgRC = &AMDGPU::SReg_32RegClass;
5035 ArgTy = LLT::integer(32);
5036 break;
5038 if (HasFixedDims)
5039 return LoadConstant(ClusterDims.getDims()[1] - 1);
5040 Arg = &ClusterWorkGroupMaxIDY;
5041 ArgRC = &AMDGPU::SReg_32RegClass;
5042 ArgTy = LLT::integer(32);
5043 break;
5045 if (HasFixedDims)
5046 return LoadConstant(ClusterDims.getDims()[2] - 1);
5047 Arg = &ClusterWorkGroupMaxIDZ;
5048 ArgRC = &AMDGPU::SReg_32RegClass;
5049 ArgTy = LLT::integer(32);
5050 break;
5052 Arg = &ClusterWorkGroupMaxFlatID;
5053 ArgRC = &AMDGPU::SReg_32RegClass;
5054 ArgTy = LLT::integer(32);
5055 break;
5056 default:
5057 break;
5058 }
5059 }
5060
5061 if (!Arg)
5062 std::tie(Arg, ArgRC, ArgTy) = MFI->getPreloadedValue(ArgType);
5063
5064 if (!Arg) {
5066 // The intrinsic may appear when we have a 0 sized kernarg segment, in
5067 // which case the pointer argument may be missing and we use null.
5068 return LoadConstant(0);
5069 }
5070
5071 // It's undefined behavior if a function marked with the amdgpu-no-*
5072 // attributes uses the corresponding intrinsic.
5073 B.buildUndef(DstReg);
5074 return true;
5075 }
5076
5077 if (!Arg->isRegister() || !Arg->getRegister().isValid())
5078 return false; // TODO: Handle these
5079 buildLoadInputValue(DstReg, B, Arg, ArgRC, ArgTy);
5080 return true;
5081}
5082
5086 if (!loadInputValue(MI.getOperand(0).getReg(), B, ArgType))
5087 return false;
5088
5089 MI.eraseFromParent();
5090 return true;
5091}
5092
5094 int64_t C) {
5095 B.buildConstant(MI.getOperand(0).getReg(), C);
5096 MI.eraseFromParent();
5097 return true;
5098}
5099
5102 unsigned Dim, AMDGPUFunctionArgInfo::PreloadedValue ArgType) const {
5103 unsigned MaxID = ST.getMaxWorkitemID(B.getMF().getFunction(), Dim);
5104 if (MaxID == 0)
5105 return replaceWithConstant(B, MI, 0);
5106
5107 const SIMachineFunctionInfo *MFI = B.getMF().getInfo<SIMachineFunctionInfo>();
5108 const ArgDescriptor *Arg;
5109 const TargetRegisterClass *ArgRC;
5110 LLT ArgTy;
5111 std::tie(Arg, ArgRC, ArgTy) = MFI->getPreloadedValue(ArgType);
5112
5113 Register DstReg = MI.getOperand(0).getReg();
5114 if (!Arg) {
5115 // It's undefined behavior if a function marked with the amdgpu-no-*
5116 // attributes uses the corresponding intrinsic.
5117 B.buildUndef(DstReg);
5118 MI.eraseFromParent();
5119 return true;
5120 }
5121
5122 if (Arg->isMasked()) {
5123 // Don't bother inserting AssertZext for packed IDs since we're emitting the
5124 // masking operations anyway.
5125 //
5126 // TODO: We could assert the top bit is 0 for the source copy.
5127 if (!loadInputValue(DstReg, B, ArgType))
5128 return false;
5129 } else {
5131 if (!loadInputValue(TmpReg, B, ArgType))
5132 return false;
5133 B.buildAssertZExt(DstReg, TmpReg, llvm::bit_width(MaxID));
5134 }
5135
5136 MI.eraseFromParent();
5137 return true;
5138}
5139
5142 // This isn't really a constant pool but close enough.
5145 return PtrInfo;
5146}
5147
5149 int64_t Offset) const {
5151 Register KernArgReg = B.getMRI()->createGenericVirtualRegister(PtrTy);
5152
5153 // TODO: If we passed in the base kernel offset we could have a better
5154 // alignment than 4, but we don't really need it.
5155 if (!loadInputValue(KernArgReg, B,
5157 llvm_unreachable("failed to find kernarg segment ptr");
5158
5159 auto COffset = B.buildConstant(LLT::integer(64), Offset);
5160 return B.buildObjectPtrOffset(PtrTy, KernArgReg, COffset).getReg(0);
5161}
5162
5163/// Legalize a value that's loaded from kernel arguments. This is only used by
5164/// legacy intrinsics.
5167 uint64_t Offset,
5168 Align Alignment) const {
5169 Register DstReg = MI.getOperand(0).getReg();
5170
5171 assert(B.getMRI()->getType(DstReg) == LLT::integer(32) &&
5172 "unexpected kernarg parameter type");
5173
5176 B.buildLoad(DstReg, Ptr, PtrInfo.getWithOffset(Offset), Align(4),
5179 MI.eraseFromParent();
5180 return true;
5181}
5182
5185 MachineIRBuilder &B) const {
5186 Register Dst = MI.getOperand(0).getReg();
5187 LLT DstTy = MRI.getType(Dst);
5188
5189 if (DstTy == F16)
5190 return legalizeFDIV16(MI, MRI, B);
5191 if (DstTy == F32)
5192 return legalizeFDIV32(MI, MRI, B);
5193 if (DstTy == F64)
5194 return legalizeFDIV64(MI, MRI, B);
5195
5196 return false;
5197}
5198
5200 Register DstDivReg,
5201 Register DstRemReg,
5202 Register X,
5203 Register Y) const {
5204 const LLT S1 = LLT::scalar(1);
5205 const LLT I32 = LLT::integer(32);
5206
5207 // See AMDGPUCodeGenPrepare::expandDivRem32 for a description of the
5208 // algorithm used here.
5209
5210 // Initial estimate of inv(y).
5211 auto FloatY = B.buildUITOFP(F32, Y);
5212 auto RcpIFlag = B.buildInstr(AMDGPU::G_AMDGPU_RCP_IFLAG, {F32}, {FloatY});
5213 auto Scale = B.buildFConstant(F32, llvm::bit_cast<float>(0x4f7ffffe));
5214 auto ScaledY = B.buildFMul(F32, RcpIFlag, Scale);
5215 auto Z = B.buildFPTOUI(I32, ScaledY);
5216
5217 // One round of UNR.
5218 auto NegY = B.buildSub(I32, B.buildConstant(I32, 0), Y);
5219 auto NegYZ = B.buildMul(I32, NegY, Z);
5220 Z = B.buildAdd(I32, Z, B.buildUMulH(I32, Z, NegYZ));
5221
5222 // Quotient/remainder estimate.
5223 auto Q = B.buildUMulH(I32, X, Z);
5224 auto R = B.buildSub(I32, X, B.buildMul(I32, Q, Y));
5225
5226 // First quotient/remainder refinement.
5227 auto One = B.buildConstant(I32, 1);
5228 auto Cond = B.buildICmp(CmpInst::ICMP_UGE, S1, R, Y);
5229 if (DstDivReg)
5230 Q = B.buildSelect(I32, Cond, B.buildAdd(I32, Q, One), Q);
5231 R = B.buildSelect(I32, Cond, B.buildSub(I32, R, Y), R);
5232
5233 // Second quotient/remainder refinement.
5234 Cond = B.buildICmp(CmpInst::ICMP_UGE, S1, R, Y);
5235 if (DstDivReg)
5236 B.buildSelect(DstDivReg, Cond, B.buildAdd(I32, Q, One), Q);
5237
5238 if (DstRemReg)
5239 B.buildSelect(DstRemReg, Cond, B.buildSub(I32, R, Y), R);
5240}
5241
5242// Build integer reciprocal sequence around V_RCP_IFLAG_F32
5243//
5244// Return lo, hi of result
5245//
5246// %cvt.lo = G_UITOFP Val.lo
5247// %cvt.hi = G_UITOFP Val.hi
5248// %mad = G_FMAD %cvt.hi, 2**32, %cvt.lo
5249// %rcp = G_AMDGPU_RCP_IFLAG %mad
5250// %mul1 = G_FMUL %rcp, 0x5f7ffffc
5251// %mul2 = G_FMUL %mul1, 2**(-32)
5252// %trunc = G_INTRINSIC_TRUNC %mul2
5253// %mad2 = G_FMAD %trunc, -(2**32), %mul1
5254// return {G_FPTOUI %mad2, G_FPTOUI %trunc}
5255static std::pair<Register, Register> emitReciprocalU64(MachineIRBuilder &B,
5256 Register Val) {
5257 const LLT I32 = LLT::integer(32);
5258 auto Unmerge = B.buildUnmerge(I32, Val);
5259
5260 auto CvtLo = B.buildUITOFP(F32, Unmerge.getReg(0));
5261 auto CvtHi = B.buildUITOFP(F32, Unmerge.getReg(1));
5262
5263 auto Mad = B.buildFMAD(
5264 F32, CvtHi, // 2**32
5265 B.buildFConstant(F32, llvm::bit_cast<float>(0x4f800000)), CvtLo);
5266
5267 auto Rcp = B.buildInstr(AMDGPU::G_AMDGPU_RCP_IFLAG, {F32}, {Mad});
5268 auto Mul1 = B.buildFMul(
5269 F32, Rcp, B.buildFConstant(F32, llvm::bit_cast<float>(0x5f7ffffc)));
5270
5271 // 2**(-32)
5272 auto Mul2 = B.buildFMul(
5273 F32, Mul1, B.buildFConstant(F32, llvm::bit_cast<float>(0x2f800000)));
5274 auto Trunc = B.buildIntrinsicTrunc(F32, Mul2);
5275
5276 // -(2**32)
5277 auto Mad2 = B.buildFMAD(
5278 F32, Trunc, B.buildFConstant(F32, llvm::bit_cast<float>(0xcf800000)),
5279 Mul1);
5280
5281 auto ResultLo = B.buildFPTOUI(I32, Mad2);
5282 auto ResultHi = B.buildFPTOUI(I32, Trunc);
5283
5284 return {ResultLo.getReg(0), ResultHi.getReg(0)};
5285}
5286
5288 Register DstDivReg,
5289 Register DstRemReg,
5290 Register Numer,
5291 Register Denom) const {
5292 const LLT I32 = LLT::integer(32);
5293 const LLT I64 = LLT::integer(64);
5294 const LLT S1 = LLT::scalar(1);
5295 Register RcpLo, RcpHi;
5296
5297 std::tie(RcpLo, RcpHi) = emitReciprocalU64(B, Denom);
5298
5299 auto Rcp = B.buildMergeLikeInstr(I64, {RcpLo, RcpHi});
5300
5301 auto Zero64 = B.buildConstant(I64, 0);
5302 auto NegDenom = B.buildSub(I64, Zero64, Denom);
5303
5304 auto MulLo1 = B.buildMul(I64, NegDenom, Rcp);
5305 auto MulHi1 = B.buildUMulH(I64, Rcp, MulLo1);
5306
5307 auto UnmergeMulHi1 = B.buildUnmerge(I32, MulHi1);
5308 Register MulHi1_Lo = UnmergeMulHi1.getReg(0);
5309 Register MulHi1_Hi = UnmergeMulHi1.getReg(1);
5310
5311 auto Add1_Lo = B.buildUAddo(I32, S1, RcpLo, MulHi1_Lo);
5312 auto Add1_Hi = B.buildUAdde(I32, S1, RcpHi, MulHi1_Hi, Add1_Lo.getReg(1));
5313 auto Add1 = B.buildMergeLikeInstr(I64, {Add1_Lo, Add1_Hi});
5314
5315 auto MulLo2 = B.buildMul(I64, NegDenom, Add1);
5316 auto MulHi2 = B.buildUMulH(I64, Add1, MulLo2);
5317 auto UnmergeMulHi2 = B.buildUnmerge(I32, MulHi2);
5318 Register MulHi2_Lo = UnmergeMulHi2.getReg(0);
5319 Register MulHi2_Hi = UnmergeMulHi2.getReg(1);
5320
5321 auto Zero32 = B.buildConstant(I32, 0);
5322 auto Add2_Lo = B.buildUAddo(I32, S1, Add1_Lo, MulHi2_Lo);
5323 auto Add2_Hi = B.buildUAdde(I32, S1, Add1_Hi, MulHi2_Hi, Add2_Lo.getReg(1));
5324 auto Add2 = B.buildMergeLikeInstr(I64, {Add2_Lo, Add2_Hi});
5325
5326 auto UnmergeNumer = B.buildUnmerge(I32, Numer);
5327 Register NumerLo = UnmergeNumer.getReg(0);
5328 Register NumerHi = UnmergeNumer.getReg(1);
5329
5330 auto MulHi3 = B.buildUMulH(I64, Numer, Add2);
5331 auto Mul3 = B.buildMul(I64, Denom, MulHi3);
5332 auto UnmergeMul3 = B.buildUnmerge(I32, Mul3);
5333 Register Mul3_Lo = UnmergeMul3.getReg(0);
5334 Register Mul3_Hi = UnmergeMul3.getReg(1);
5335 auto Sub1_Lo = B.buildUSubo(I32, S1, NumerLo, Mul3_Lo);
5336 auto Sub1_Hi = B.buildUSube(I32, S1, NumerHi, Mul3_Hi, Sub1_Lo.getReg(1));
5337 auto Sub1_Mi = B.buildSub(I32, NumerHi, Mul3_Hi);
5338 auto Sub1 = B.buildMergeLikeInstr(I64, {Sub1_Lo, Sub1_Hi});
5339
5340 auto UnmergeDenom = B.buildUnmerge(I32, Denom);
5341 Register DenomLo = UnmergeDenom.getReg(0);
5342 Register DenomHi = UnmergeDenom.getReg(1);
5343
5344 auto CmpHi = B.buildICmp(CmpInst::ICMP_UGE, S1, Sub1_Hi, DenomHi);
5345 auto C1 = B.buildSExt(I32, CmpHi);
5346
5347 auto CmpLo = B.buildICmp(CmpInst::ICMP_UGE, S1, Sub1_Lo, DenomLo);
5348 auto C2 = B.buildSExt(I32, CmpLo);
5349
5350 auto CmpEq = B.buildICmp(CmpInst::ICMP_EQ, S1, Sub1_Hi, DenomHi);
5351 auto C3 = B.buildSelect(I32, CmpEq, C2, C1);
5352
5353 // TODO: Here and below portions of the code can be enclosed into if/endif.
5354 // Currently control flow is unconditional and we have 4 selects after
5355 // potential endif to substitute PHIs.
5356
5357 // if C3 != 0 ...
5358 auto Sub2_Lo = B.buildUSubo(I32, S1, Sub1_Lo, DenomLo);
5359 auto Sub2_Mi = B.buildUSube(I32, S1, Sub1_Mi, DenomHi, Sub1_Lo.getReg(1));
5360 auto Sub2_Hi = B.buildUSube(I32, S1, Sub2_Mi, Zero32, Sub2_Lo.getReg(1));
5361 auto Sub2 = B.buildMergeLikeInstr(I64, {Sub2_Lo, Sub2_Hi});
5362
5363 auto One64 = B.buildConstant(I64, 1);
5364 auto Add3 = B.buildAdd(I64, MulHi3, One64);
5365
5366 auto C4 =
5367 B.buildSExt(I32, B.buildICmp(CmpInst::ICMP_UGE, S1, Sub2_Hi, DenomHi));
5368 auto C5 =
5369 B.buildSExt(I32, B.buildICmp(CmpInst::ICMP_UGE, S1, Sub2_Lo, DenomLo));
5370 auto C6 = B.buildSelect(
5371 I32, B.buildICmp(CmpInst::ICMP_EQ, S1, Sub2_Hi, DenomHi), C5, C4);
5372
5373 // if (C6 != 0)
5374 auto Add4 = B.buildAdd(I64, Add3, One64);
5375 auto Sub3_Lo = B.buildUSubo(I32, S1, Sub2_Lo, DenomLo);
5376
5377 auto Sub3_Mi = B.buildUSube(I32, S1, Sub2_Mi, DenomHi, Sub2_Lo.getReg(1));
5378 auto Sub3_Hi = B.buildUSube(I32, S1, Sub3_Mi, Zero32, Sub3_Lo.getReg(1));
5379 auto Sub3 = B.buildMergeLikeInstr(I64, {Sub3_Lo, Sub3_Hi});
5380
5381 // endif C6
5382 // endif C3
5383
5384 if (DstDivReg) {
5385 auto Sel1 = B.buildSelect(
5386 I64, B.buildICmp(CmpInst::ICMP_NE, S1, C6, Zero32), Add4, Add3);
5387 B.buildSelect(DstDivReg, B.buildICmp(CmpInst::ICMP_NE, S1, C3, Zero32),
5388 Sel1, MulHi3);
5389 }
5390
5391 if (DstRemReg) {
5392 auto Sel2 = B.buildSelect(
5393 I64, B.buildICmp(CmpInst::ICMP_NE, S1, C6, Zero32), Sub3, Sub2);
5394 B.buildSelect(DstRemReg, B.buildICmp(CmpInst::ICMP_NE, S1, C3, Zero32),
5395 Sel2, Sub1);
5396 }
5397}
5398
5401 MachineIRBuilder &B) const {
5402 Register DstDivReg, DstRemReg;
5403 switch (MI.getOpcode()) {
5404 default:
5405 llvm_unreachable("Unexpected opcode!");
5406 case AMDGPU::G_UDIV: {
5407 DstDivReg = MI.getOperand(0).getReg();
5408 break;
5409 }
5410 case AMDGPU::G_UREM: {
5411 DstRemReg = MI.getOperand(0).getReg();
5412 break;
5413 }
5414 case AMDGPU::G_UDIVREM: {
5415 DstDivReg = MI.getOperand(0).getReg();
5416 DstRemReg = MI.getOperand(1).getReg();
5417 break;
5418 }
5419 }
5420
5421 const LLT I64 = LLT::integer(64);
5422 const LLT I32 = LLT::integer(32);
5423 const unsigned FirstSrcOpIdx = MI.getNumExplicitDefs();
5424 Register Num = MI.getOperand(FirstSrcOpIdx).getReg();
5425 Register Den = MI.getOperand(FirstSrcOpIdx + 1).getReg();
5426 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
5427
5428 if (Ty == I32)
5429 legalizeUnsignedDIV_REM32Impl(B, DstDivReg, DstRemReg, Num, Den);
5430 else if (Ty == I64)
5431 legalizeUnsignedDIV_REM64Impl(B, DstDivReg, DstRemReg, Num, Den);
5432 else
5433 return false;
5434
5435 MI.eraseFromParent();
5436 return true;
5437}
5438
5441 MachineIRBuilder &B) const {
5442 const LLT I64 = LLT::integer(64);
5443 const LLT I32 = LLT::integer(32);
5444
5445 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
5446 if (Ty != I32 && Ty != I64)
5447 return false;
5448
5449 const unsigned FirstSrcOpIdx = MI.getNumExplicitDefs();
5450 Register LHS = MI.getOperand(FirstSrcOpIdx).getReg();
5451 Register RHS = MI.getOperand(FirstSrcOpIdx + 1).getReg();
5452
5453 auto SignBitOffset = B.buildConstant(I32, Ty.getSizeInBits() - 1);
5454 auto LHSign = B.buildAShr(Ty, LHS, SignBitOffset);
5455 auto RHSign = B.buildAShr(Ty, RHS, SignBitOffset);
5456
5457 LHS = B.buildAdd(Ty, LHS, LHSign).getReg(0);
5458 RHS = B.buildAdd(Ty, RHS, RHSign).getReg(0);
5459
5460 LHS = B.buildXor(Ty, LHS, LHSign).getReg(0);
5461 RHS = B.buildXor(Ty, RHS, RHSign).getReg(0);
5462
5463 Register DstDivReg, DstRemReg, TmpDivReg, TmpRemReg;
5464 switch (MI.getOpcode()) {
5465 default:
5466 llvm_unreachable("Unexpected opcode!");
5467 case AMDGPU::G_SDIV: {
5468 DstDivReg = MI.getOperand(0).getReg();
5469 TmpDivReg = MRI.createGenericVirtualRegister(Ty);
5470 break;
5471 }
5472 case AMDGPU::G_SREM: {
5473 DstRemReg = MI.getOperand(0).getReg();
5474 TmpRemReg = MRI.createGenericVirtualRegister(Ty);
5475 break;
5476 }
5477 case AMDGPU::G_SDIVREM: {
5478 DstDivReg = MI.getOperand(0).getReg();
5479 DstRemReg = MI.getOperand(1).getReg();
5480 TmpDivReg = MRI.createGenericVirtualRegister(Ty);
5481 TmpRemReg = MRI.createGenericVirtualRegister(Ty);
5482 break;
5483 }
5484 }
5485
5486 if (Ty == I32)
5487 legalizeUnsignedDIV_REM32Impl(B, TmpDivReg, TmpRemReg, LHS, RHS);
5488 else
5489 legalizeUnsignedDIV_REM64Impl(B, TmpDivReg, TmpRemReg, LHS, RHS);
5490
5491 if (DstDivReg) {
5492 auto Sign = B.buildXor(Ty, LHSign, RHSign).getReg(0);
5493 auto SignXor = B.buildXor(Ty, TmpDivReg, Sign).getReg(0);
5494 B.buildSub(DstDivReg, SignXor, Sign);
5495 }
5496
5497 if (DstRemReg) {
5498 auto Sign = LHSign.getReg(0); // Remainder sign is the same as LHS
5499 auto SignXor = B.buildXor(Ty, TmpRemReg, Sign).getReg(0);
5500 B.buildSub(DstRemReg, SignXor, Sign);
5501 }
5502
5503 MI.eraseFromParent();
5504 return true;
5505}
5506
5509 MachineIRBuilder &B) const {
5510 Register Res = MI.getOperand(0).getReg();
5511 Register LHS = MI.getOperand(1).getReg();
5512 Register RHS = MI.getOperand(2).getReg();
5513 uint16_t Flags = MI.getFlags();
5514 LLT ResTy = MRI.getType(Res);
5515
5516 bool AllowInaccurateRcp = MI.getFlag(MachineInstr::FmAfn);
5517
5518 if (const auto *CLHS = getConstantFPVRegVal(LHS, MRI)) {
5519 if (!AllowInaccurateRcp && ResTy != F16)
5520 return false;
5521
5522 // v_rcp_f32 and v_rsq_f32 do not support denormals, and according to
5523 // the CI documentation has a worst case error of 1 ulp.
5524 // OpenCL requires <= 2.5 ulp for 1.0 / x, so it should always be OK to
5525 // use it as long as we aren't trying to use denormals.
5526 //
5527 // v_rcp_f16 and v_rsq_f16 DO support denormals and 0.51ulp.
5528
5529 // 1 / x -> RCP(x)
5530 if (CLHS->isOne()) {
5531 B.buildIntrinsic(Intrinsic::amdgcn_rcp, Res)
5532 .addUse(RHS)
5533 .setMIFlags(Flags);
5534
5535 MI.eraseFromParent();
5536 return true;
5537 }
5538
5539 // -1 / x -> RCP( FNEG(x) )
5540 if (CLHS->isMinusOne()) {
5541 auto FNeg = B.buildFNeg(ResTy, RHS, Flags);
5542 B.buildIntrinsic(Intrinsic::amdgcn_rcp, Res)
5543 .addUse(FNeg.getReg(0))
5544 .setMIFlags(Flags);
5545
5546 MI.eraseFromParent();
5547 return true;
5548 }
5549 }
5550
5551 // For f16 require afn or arcp.
5552 // For f32 require afn.
5553 if (!AllowInaccurateRcp &&
5554 (ResTy != F16 || !MI.getFlag(MachineInstr::FmArcp)))
5555 return false;
5556
5557 // x / y -> x * (1.0 / y)
5558 auto RCP = B.buildIntrinsic(Intrinsic::amdgcn_rcp, {ResTy})
5559 .addUse(RHS)
5560 .setMIFlags(Flags);
5561 B.buildFMul(Res, LHS, RCP, Flags);
5562
5563 MI.eraseFromParent();
5564 return true;
5565}
5566
5569 MachineIRBuilder &B) const {
5570 Register Res = MI.getOperand(0).getReg();
5571 Register X = MI.getOperand(1).getReg();
5572 Register Y = MI.getOperand(2).getReg();
5573 uint16_t Flags = MI.getFlags();
5574 LLT ResTy = MRI.getType(Res);
5575
5576 bool AllowInaccurateRcp = MI.getFlag(MachineInstr::FmAfn);
5577
5578 if (!AllowInaccurateRcp)
5579 return false;
5580
5581 const ConstantFP *CLHS = getConstantFPVRegVal(X, MRI);
5582 bool IsNegRcp = CLHS && CLHS->isMinusOne();
5583
5584 // Pull out the negation so it folds for free into the source modifiers.
5585 if (IsNegRcp)
5586 X = B.buildFConstant(ResTy, 1.0).getReg(0);
5587
5588 Register NegY = IsNegRcp ? Y : B.buildFNeg(ResTy, Y).getReg(0);
5589 auto One = B.buildFConstant(ResTy, 1.0);
5590
5591 auto R = B.buildIntrinsic(Intrinsic::amdgcn_rcp, {ResTy})
5592 .addUse(Y)
5593 .setMIFlags(Flags);
5594 if (IsNegRcp)
5595 R = B.buildFNeg(ResTy, R);
5596
5597 auto Tmp0 = B.buildFMA(ResTy, NegY, R, One);
5598 R = B.buildFMA(ResTy, Tmp0, R, R);
5599
5600 auto Tmp1 = B.buildFMA(ResTy, NegY, R, One);
5601 R = B.buildFMA(ResTy, Tmp1, R, R);
5602
5603 // Skip the last 2 correction terms for reciprocal.
5604 if (IsNegRcp || (CLHS && CLHS->isOne())) {
5605 B.buildCopy(Res, R);
5606 MI.eraseFromParent();
5607 return true;
5608 }
5609
5610 auto Ret = B.buildFMul(ResTy, X, R);
5611 auto Tmp2 = B.buildFMA(ResTy, NegY, Ret, X);
5612
5613 B.buildFMA(Res, Tmp2, R, Ret);
5614 MI.eraseFromParent();
5615 return true;
5616}
5617
5620 MachineIRBuilder &B) const {
5621 if (legalizeFastUnsafeFDIV(MI, MRI, B))
5622 return true;
5623
5624 Register Res = MI.getOperand(0).getReg();
5625 Register LHS = MI.getOperand(1).getReg();
5626 Register RHS = MI.getOperand(2).getReg();
5627
5628 uint16_t Flags = MI.getFlags();
5629
5630 LLT I32 = LLT::integer(32);
5631
5632 // a32.u = opx(V_CVT_F32_F16, a.u); // CVT to F32
5633 // b32.u = opx(V_CVT_F32_F16, b.u); // CVT to F32
5634 // r32.u = opx(V_RCP_F32, b32.u); // rcp = 1 / d
5635 // q32.u = opx(V_MUL_F32, a32.u, r32.u); // q = n * rcp
5636 // e32.u = opx(V_MAD_F32, (b32.u^_neg32), q32.u, a32.u); // err = -d * q + n
5637 // q32.u = opx(V_MAD_F32, e32.u, r32.u, q32.u); // q = n * rcp
5638 // e32.u = opx(V_MAD_F32, (b32.u^_neg32), q32.u, a32.u); // err = -d * q + n
5639 // tmp.u = opx(V_MUL_F32, e32.u, r32.u);
5640 // tmp.u = opx(V_AND_B32, tmp.u, 0xff800000)
5641 // q32.u = opx(V_ADD_F32, tmp.u, q32.u);
5642 // q16.u = opx(V_CVT_F16_F32, q32.u);
5643 // q16.u = opx(V_DIV_FIXUP_F16, q16.u, b.u, a.u); // q = touchup(q, d, n)
5644
5645 auto LHSExt = B.buildFPExt(F32, LHS, Flags);
5646 auto RHSExt = B.buildFPExt(F32, RHS, Flags);
5647 auto NegRHSExt = B.buildFNeg(F32, RHSExt);
5648 auto Rcp = B.buildIntrinsic(Intrinsic::amdgcn_rcp, {F32})
5649 .addUse(RHSExt.getReg(0))
5650 .setMIFlags(Flags);
5651 auto Quot = B.buildFMul(F32, LHSExt, Rcp, Flags);
5653 if (ST.hasMadMacF32Insts()) {
5654 Err = B.buildFMAD(F32, NegRHSExt, Quot, LHSExt, Flags);
5655 Quot = B.buildFMAD(F32, Err, Rcp, Quot, Flags);
5656 Err = B.buildFMAD(F32, NegRHSExt, Quot, LHSExt, Flags);
5657 } else {
5658 Err = B.buildFMA(F32, NegRHSExt, Quot, LHSExt, Flags);
5659 Quot = B.buildFMA(F32, Err, Rcp, Quot, Flags);
5660 Err = B.buildFMA(F32, NegRHSExt, Quot, LHSExt, Flags);
5661 }
5662 auto Tmp = B.buildFMul(F32, Err, Rcp, Flags);
5663 auto TmpInt = B.buildBitcast(I32, Tmp);
5664 auto MaskedInt = B.buildAnd(I32, TmpInt, B.buildConstant(I32, 0xff800000));
5665 auto Masked = B.buildBitcast(F32, MaskedInt);
5666 Quot = B.buildFAdd(F32, Masked, Quot, Flags);
5667 auto RDst = B.buildFPTrunc(F16, Quot, Flags);
5668 B.buildIntrinsic(Intrinsic::amdgcn_div_fixup, Res)
5669 .addUse(RDst.getReg(0))
5670 .addUse(RHS)
5671 .addUse(LHS)
5672 .setMIFlags(Flags);
5673
5674 MI.eraseFromParent();
5675 return true;
5676}
5677
5678static constexpr unsigned SPDenormModeBitField =
5680
5681// Enable or disable FP32 denorm mode. When 'Enable' is true, emit instructions
5682// to enable denorm mode. When 'Enable' is false, disable denorm mode.
5684 const GCNSubtarget &ST,
5686 // Set SP denorm mode to this value.
5687 unsigned SPDenormMode =
5688 Enable ? FP_DENORM_FLUSH_NONE : Mode.fpDenormModeSPValue();
5689
5690 if (ST.hasDenormModeInst()) {
5691 // Preserve default FP64FP16 denorm mode while updating FP32 mode.
5692 uint32_t DPDenormModeDefault = Mode.fpDenormModeDPValue();
5693
5694 uint32_t NewDenormModeValue = SPDenormMode | (DPDenormModeDefault << 2);
5695 B.buildInstr(AMDGPU::S_DENORM_MODE)
5696 .addImm(NewDenormModeValue);
5697
5698 } else {
5699 B.buildInstr(AMDGPU::S_SETREG_IMM32_B32)
5700 .addImm(SPDenormMode)
5701 .addImm(SPDenormModeBitField);
5702 }
5703}
5704
5707 MachineIRBuilder &B) const {
5708 if (legalizeFastUnsafeFDIV(MI, MRI, B))
5709 return true;
5710
5711 Register Res = MI.getOperand(0).getReg();
5712 Register LHS = MI.getOperand(1).getReg();
5713 Register RHS = MI.getOperand(2).getReg();
5714 const SIMachineFunctionInfo *MFI = B.getMF().getInfo<SIMachineFunctionInfo>();
5715 SIModeRegisterDefaults Mode = MFI->getMode();
5716
5717 uint16_t Flags = MI.getFlags();
5718
5719 LLT S1 = LLT::scalar(1);
5720
5721 auto One = B.buildFConstant(F32, 1.0f);
5722
5723 auto DenominatorScaled =
5724 B.buildIntrinsic(Intrinsic::amdgcn_div_scale, {F32, S1})
5725 .addUse(LHS)
5726 .addUse(RHS)
5727 .addImm(0)
5728 .setMIFlags(Flags);
5729 auto NumeratorScaled =
5730 B.buildIntrinsic(Intrinsic::amdgcn_div_scale, {F32, S1})
5731 .addUse(LHS)
5732 .addUse(RHS)
5733 .addImm(1)
5734 .setMIFlags(Flags);
5735
5736 auto ApproxRcp = B.buildIntrinsic(Intrinsic::amdgcn_rcp, {F32})
5737 .addUse(DenominatorScaled.getReg(0))
5738 .setMIFlags(Flags);
5739 auto NegDivScale0 = B.buildFNeg(F32, DenominatorScaled, Flags);
5740
5741 const bool PreservesDenormals = Mode.FP32Denormals == DenormalMode::getIEEE();
5742 const bool HasDynamicDenormals =
5743 (Mode.FP32Denormals.Input == DenormalMode::Dynamic) ||
5744 (Mode.FP32Denormals.Output == DenormalMode::Dynamic);
5745
5746 Register SavedSPDenormMode;
5747 if (!PreservesDenormals) {
5748 if (HasDynamicDenormals) {
5749 SavedSPDenormMode = MRI.createVirtualRegister(&AMDGPU::SReg_32RegClass);
5750 B.buildInstr(AMDGPU::S_GETREG_B32)
5751 .addDef(SavedSPDenormMode)
5752 .addImm(SPDenormModeBitField);
5753 }
5754 toggleSPDenormMode(true, B, ST, Mode);
5755 }
5756
5757 auto Fma0 = B.buildFMA(F32, NegDivScale0, ApproxRcp, One, Flags);
5758 auto Fma1 = B.buildFMA(F32, Fma0, ApproxRcp, ApproxRcp, Flags);
5759 auto Mul = B.buildFMul(F32, NumeratorScaled, Fma1, Flags);
5760 auto Fma2 = B.buildFMA(F32, NegDivScale0, Mul, NumeratorScaled, Flags);
5761 auto Fma3 = B.buildFMA(F32, Fma2, Fma1, Mul, Flags);
5762 auto Fma4 = B.buildFMA(F32, NegDivScale0, Fma3, NumeratorScaled, Flags);
5763
5764 if (!PreservesDenormals) {
5765 if (HasDynamicDenormals) {
5766 assert(SavedSPDenormMode);
5767 B.buildInstr(AMDGPU::S_SETREG_B32)
5768 .addReg(SavedSPDenormMode)
5769 .addImm(SPDenormModeBitField);
5770 } else
5771 toggleSPDenormMode(false, B, ST, Mode);
5772 }
5773
5774 auto Fmas = B.buildIntrinsic(Intrinsic::amdgcn_div_fmas, {F32})
5775 .addUse(Fma4.getReg(0))
5776 .addUse(Fma1.getReg(0))
5777 .addUse(Fma3.getReg(0))
5778 .addUse(NumeratorScaled.getReg(1))
5779 .setMIFlags(Flags);
5780
5781 B.buildIntrinsic(Intrinsic::amdgcn_div_fixup, Res)
5782 .addUse(Fmas.getReg(0))
5783 .addUse(RHS)
5784 .addUse(LHS)
5785 .setMIFlags(Flags);
5786
5787 MI.eraseFromParent();
5788 return true;
5789}
5790
5793 MachineIRBuilder &B) const {
5794 if (legalizeFastUnsafeFDIV64(MI, MRI, B))
5795 return true;
5796
5797 Register Res = MI.getOperand(0).getReg();
5798 Register LHS = MI.getOperand(1).getReg();
5799 Register RHS = MI.getOperand(2).getReg();
5800
5801 uint16_t Flags = MI.getFlags();
5802
5803 LLT S1 = LLT::scalar(1);
5804
5805 auto One = B.buildFConstant(F64, 1.0);
5806
5807 auto DivScale0 = B.buildIntrinsic(Intrinsic::amdgcn_div_scale, {F64, S1})
5808 .addUse(LHS)
5809 .addUse(RHS)
5810 .addImm(0)
5811 .setMIFlags(Flags);
5812
5813 auto NegDivScale0 = B.buildFNeg(F64, DivScale0.getReg(0), Flags);
5814
5815 auto Rcp = B.buildIntrinsic(Intrinsic::amdgcn_rcp, {F64})
5816 .addUse(DivScale0.getReg(0))
5817 .setMIFlags(Flags);
5818
5819 auto Fma0 = B.buildFMA(F64, NegDivScale0, Rcp, One, Flags);
5820 auto Fma1 = B.buildFMA(F64, Rcp, Fma0, Rcp, Flags);
5821 auto Fma2 = B.buildFMA(F64, NegDivScale0, Fma1, One, Flags);
5822
5823 auto DivScale1 = B.buildIntrinsic(Intrinsic::amdgcn_div_scale, {F64, S1})
5824 .addUse(LHS)
5825 .addUse(RHS)
5826 .addImm(1)
5827 .setMIFlags(Flags);
5828
5829 auto Fma3 = B.buildFMA(F64, Fma1, Fma2, Fma1, Flags);
5830 auto Mul = B.buildFMul(F64, DivScale1.getReg(0), Fma3, Flags);
5831 auto Fma4 = B.buildFMA(F64, NegDivScale0, Mul, DivScale1.getReg(0), Flags);
5832
5833 Register Scale;
5834 if (!ST.hasUsableDivScaleConditionOutput()) {
5835 // Workaround a hardware bug on SI where the condition output from div_scale
5836 // is not usable.
5837
5838 LLT I32 = LLT::integer(32);
5839 LLT I64 = LLT::integer(64);
5840
5841 auto NumUnmerge = B.buildUnmerge(I32, B.buildBitcast(I64, LHS));
5842 auto DenUnmerge = B.buildUnmerge(I32, B.buildBitcast(I64, RHS));
5843 auto Scale0Unmerge = B.buildUnmerge(I32, B.buildBitcast(I64, DivScale0));
5844 auto Scale1Unmerge = B.buildUnmerge(I32, B.buildBitcast(I64, DivScale1));
5845
5846 auto CmpNum = B.buildICmp(ICmpInst::ICMP_EQ, S1, NumUnmerge.getReg(1),
5847 Scale1Unmerge.getReg(1));
5848 auto CmpDen = B.buildICmp(ICmpInst::ICMP_EQ, S1, DenUnmerge.getReg(1),
5849 Scale0Unmerge.getReg(1));
5850 Scale = B.buildXor(S1, CmpNum, CmpDen).getReg(0);
5851 } else {
5852 Scale = DivScale1.getReg(1);
5853 }
5854
5855 auto Fmas = B.buildIntrinsic(Intrinsic::amdgcn_div_fmas, {F64})
5856 .addUse(Fma4.getReg(0))
5857 .addUse(Fma3.getReg(0))
5858 .addUse(Mul.getReg(0))
5859 .addUse(Scale)
5860 .setMIFlags(Flags);
5861
5862 B.buildIntrinsic(Intrinsic::amdgcn_div_fixup, ArrayRef(Res))
5863 .addUse(Fmas.getReg(0))
5864 .addUse(RHS)
5865 .addUse(LHS)
5866 .setMIFlags(Flags);
5867
5868 MI.eraseFromParent();
5869 return true;
5870}
5871
5874 MachineIRBuilder &B) const {
5875 Register Res0 = MI.getOperand(0).getReg();
5876 Register Res1 = MI.getOperand(1).getReg();
5877 Register Val = MI.getOperand(2).getReg();
5878 uint16_t Flags = MI.getFlags();
5879
5880 LLT Ty = MRI.getType(Res0);
5881 LLT InstrExpTy = Ty == F16 ? LLT::integer(16) : LLT::integer(32);
5882
5883 auto Mant = B.buildIntrinsic(Intrinsic::amdgcn_frexp_mant, {Ty})
5884 .addUse(Val)
5885 .setMIFlags(Flags);
5886 auto Exp = B.buildIntrinsic(Intrinsic::amdgcn_frexp_exp, {InstrExpTy})
5887 .addUse(Val)
5888 .setMIFlags(Flags);
5889
5890 if (ST.hasFractBug()) {
5891 auto Fabs = B.buildFAbs(Ty, Val);
5892 auto Inf = B.buildFConstant(Ty, APFloat::getInf(getFltSemanticForLLT(Ty)));
5893 auto IsFinite =
5894 B.buildFCmp(CmpInst::FCMP_OLT, LLT::scalar(1), Fabs, Inf, Flags);
5895 auto Zero = B.buildConstant(InstrExpTy, 0);
5896 Exp = B.buildSelect(InstrExpTy, IsFinite, Exp, Zero);
5897 Mant = B.buildSelect(Ty, IsFinite, Mant, Val);
5898 }
5899
5900 B.buildCopy(Res0, Mant);
5901 B.buildSExtOrTrunc(Res1, Exp);
5902
5903 MI.eraseFromParent();
5904 return true;
5905}
5906
5909 MachineIRBuilder &B) const {
5910 Register Res = MI.getOperand(0).getReg();
5911 Register LHS = MI.getOperand(2).getReg();
5912 Register RHS = MI.getOperand(3).getReg();
5913 uint16_t Flags = MI.getFlags();
5914
5915 LLT S1 = LLT::scalar(1);
5916
5917 auto Abs = B.buildFAbs(F32, RHS, Flags);
5918 const APFloat C0Val(1.0f);
5919
5920 auto C0 = B.buildFConstant(F32, 0x1p+96f);
5921 auto C1 = B.buildFConstant(F32, 0x1p-32f);
5922 auto C2 = B.buildFConstant(F32, 1.0f);
5923
5924 auto CmpRes = B.buildFCmp(CmpInst::FCMP_OGT, S1, Abs, C0, Flags);
5925 auto Sel = B.buildSelect(F32, CmpRes, C1, C2, Flags);
5926
5927 auto Mul0 = B.buildFMul(F32, RHS, Sel, Flags);
5928
5929 auto RCP = B.buildIntrinsic(Intrinsic::amdgcn_rcp, {F32})
5930 .addUse(Mul0.getReg(0))
5931 .setMIFlags(Flags);
5932
5933 auto Mul1 = B.buildFMul(F32, LHS, RCP, Flags);
5934
5935 B.buildFMul(Res, Sel, Mul1, Flags);
5936
5937 MI.eraseFromParent();
5938 return true;
5939}
5940
5943 MachineIRBuilder &B) const {
5944 // Bypass the correct expansion a standard promotion through G_FSQRT would
5945 // get. The f32 op is accurate enough for the f16 cas.
5946 unsigned Flags = MI.getFlags();
5947 assert(!ST.has16BitInsts());
5948 auto Ext = B.buildFPExt(F32, MI.getOperand(1), Flags);
5949 auto Log2 = B.buildIntrinsic(Intrinsic::amdgcn_sqrt, {F32})
5950 .addUse(Ext.getReg(0))
5951 .setMIFlags(Flags);
5952 B.buildFPTrunc(MI.getOperand(0), Log2, Flags);
5953 MI.eraseFromParent();
5954 return true;
5955}
5956
5959 MachineIRBuilder &B) const {
5960 MachineFunction &MF = B.getMF();
5961 Register Dst = MI.getOperand(0).getReg();
5962 Register X = MI.getOperand(1).getReg();
5963 const unsigned Flags = MI.getFlags();
5964 const LLT I1 = LLT::integer(1);
5965 const LLT I32 = LLT::integer(32);
5966
5967 if (allowApproxFunc(MF, Flags)) {
5968 B.buildIntrinsic(Intrinsic::amdgcn_sqrt, ArrayRef<Register>({Dst}))
5969 .addUse(X)
5970 .setMIFlags(Flags);
5971 MI.eraseFromParent();
5972 return true;
5973 }
5974
5975 auto ScaleThreshold = B.buildFConstant(F32, 0x1.0p-96f);
5976 auto NeedScale = B.buildFCmp(CmpInst::FCMP_OGT, I1, ScaleThreshold, X, Flags);
5977 auto ScaleUpFactor = B.buildFConstant(F32, 0x1.0p+32f);
5978 auto ScaledX = B.buildFMul(F32, X, ScaleUpFactor, Flags);
5979 auto SqrtX = B.buildSelect(F32, NeedScale, ScaledX, X, Flags);
5980
5982 if (needsDenormHandlingF32(MF, X, Flags)) {
5983 B.buildIntrinsic(Intrinsic::amdgcn_sqrt, ArrayRef<Register>({SqrtS}))
5984 .addUse(SqrtX.getReg(0))
5985 .setMIFlags(Flags);
5986
5987 auto SqrtSInt = B.buildBitcast(I32, SqrtS);
5988 auto NegOne = B.buildConstant(I32, -1);
5989 auto SqrtSNextDown = B.buildBitcast(F32, B.buildAdd(I32, SqrtSInt, NegOne));
5990
5991 auto NegSqrtSNextDown = B.buildFNeg(F32, SqrtSNextDown, Flags);
5992 auto SqrtVP = B.buildFMA(F32, NegSqrtSNextDown, SqrtS, SqrtX, Flags);
5993
5994 auto PosOne = B.buildConstant(I32, 1);
5995 auto SqrtSNextUp = B.buildBitcast(F32, B.buildAdd(I32, SqrtSInt, PosOne));
5996
5997 auto NegSqrtSNextUp = B.buildFNeg(F32, SqrtSNextUp, Flags);
5998 auto SqrtVS = B.buildFMA(F32, NegSqrtSNextUp, SqrtS, SqrtX, Flags);
5999
6000 auto Zero = B.buildFConstant(F32, 0.0f);
6001 auto SqrtVPLE0 = B.buildFCmp(CmpInst::FCMP_OLE, I1, SqrtVP, Zero, Flags);
6002
6003 SqrtS =
6004 B.buildSelect(F32, SqrtVPLE0, SqrtSNextDown, SqrtS, Flags).getReg(0);
6005
6006 auto SqrtVPVSGT0 = B.buildFCmp(CmpInst::FCMP_OGT, I1, SqrtVS, Zero, Flags);
6007 SqrtS =
6008 B.buildSelect(F32, SqrtVPVSGT0, SqrtSNextUp, SqrtS, Flags).getReg(0);
6009 } else {
6010 auto SqrtR =
6011 B.buildIntrinsic(Intrinsic::amdgcn_rsq, {F32}).addReg(SqrtX.getReg(0));
6012 B.buildFMul(SqrtS, SqrtX, SqrtR, Flags);
6013
6014 auto Half = B.buildFConstant(F32, 0.5f);
6015 auto SqrtH = B.buildFMul(F32, SqrtR, Half, Flags);
6016 auto NegSqrtH = B.buildFNeg(F32, SqrtH, Flags);
6017 auto SqrtE = B.buildFMA(F32, NegSqrtH, SqrtS, Half, Flags);
6018 SqrtH = B.buildFMA(F32, SqrtH, SqrtE, SqrtH, Flags);
6019 SqrtS = B.buildFMA(F32, SqrtS, SqrtE, SqrtS, Flags).getReg(0);
6020 auto NegSqrtS = B.buildFNeg(F32, SqrtS, Flags);
6021 auto SqrtD = B.buildFMA(F32, NegSqrtS, SqrtS, SqrtX, Flags);
6022 SqrtS = B.buildFMA(F32, SqrtD, SqrtH, SqrtS, Flags).getReg(0);
6023 }
6024
6025 auto ScaleDownFactor = B.buildFConstant(F32, 0x1.0p-16f);
6026
6027 auto ScaledDown = B.buildFMul(F32, SqrtS, ScaleDownFactor, Flags);
6028
6029 SqrtS = B.buildSelect(F32, NeedScale, ScaledDown, SqrtS, Flags).getReg(0);
6030
6031 auto IsZeroOrInf = B.buildIsFPClass(I1, SqrtX, fcZero | fcPosInf);
6032 B.buildSelect(Dst, IsZeroOrInf, SqrtX, SqrtS, Flags);
6033
6034 MI.eraseFromParent();
6035 return true;
6036}
6037
6040 MachineIRBuilder &B) const {
6041 // For double type, the SQRT and RSQ instructions don't have required
6042 // precision, we apply Goldschmidt's algorithm to improve the result:
6043 //
6044 // y0 = rsq(x)
6045 // g0 = x * y0
6046 // h0 = 0.5 * y0
6047 //
6048 // r0 = 0.5 - h0 * g0
6049 // g1 = g0 * r0 + g0
6050 // h1 = h0 * r0 + h0
6051 //
6052 // r1 = 0.5 - h1 * g1 => d0 = x - g1 * g1
6053 // g2 = g1 * r1 + g1 g2 = d0 * h1 + g1
6054 // h2 = h1 * r1 + h1
6055 //
6056 // r2 = 0.5 - h2 * g2 => d1 = x - g2 * g2
6057 // g3 = g2 * r2 + g2 g3 = d1 * h1 + g2
6058 //
6059 // sqrt(x) = g3
6060
6061 const LLT I1 = LLT::integer(1);
6062 const LLT I32 = LLT::integer(32);
6063
6064 Register Dst = MI.getOperand(0).getReg();
6065 assert(MRI.getType(Dst) == F64 && "only expect to lower f64 sqrt");
6066
6067 Register X = MI.getOperand(1).getReg();
6068 unsigned Flags = MI.getFlags();
6069
6070 Register SqrtX = X;
6071 Register Scaling, ZeroInt;
6072 if (!MI.getFlag(MachineInstr::FmAfn)) {
6073 auto ScaleConstant = B.buildFConstant(F64, 0x1.0p-767);
6074
6075 ZeroInt = B.buildConstant(I32, 0).getReg(0);
6076 Scaling = B.buildFCmp(FCmpInst::FCMP_OLT, I1, X, ScaleConstant).getReg(0);
6077
6078 // Scale up input if it is too small.
6079 auto ScaleUpFactor = B.buildConstant(I32, 256);
6080 auto ScaleUp = B.buildSelect(I32, Scaling, ScaleUpFactor, ZeroInt);
6081 SqrtX = B.buildFLdexp(F64, X, ScaleUp, Flags).getReg(0);
6082 }
6083
6084 auto SqrtY = B.buildIntrinsic(Intrinsic::amdgcn_rsq, {F64}).addReg(SqrtX);
6085
6086 auto Half = B.buildFConstant(F64, 0.5);
6087 auto SqrtH0 = B.buildFMul(F64, SqrtY, Half);
6088 auto SqrtS0 = B.buildFMul(F64, SqrtX, SqrtY);
6089
6090 auto NegSqrtH0 = B.buildFNeg(F64, SqrtH0);
6091 auto SqrtR0 = B.buildFMA(F64, NegSqrtH0, SqrtS0, Half);
6092
6093 auto SqrtS1 = B.buildFMA(F64, SqrtS0, SqrtR0, SqrtS0);
6094 auto SqrtH1 = B.buildFMA(F64, SqrtH0, SqrtR0, SqrtH0);
6095
6096 auto NegSqrtS1 = B.buildFNeg(F64, SqrtS1);
6097 auto SqrtD0 = B.buildFMA(F64, NegSqrtS1, SqrtS1, SqrtX);
6098
6099 auto SqrtS2 = B.buildFMA(F64, SqrtD0, SqrtH1, SqrtS1);
6100
6101 Register SqrtRet = SqrtS2.getReg(0);
6102 if (!MI.getFlag(MachineInstr::FmAfn)) {
6103 auto NegSqrtS2 = B.buildFNeg(F64, SqrtS2);
6104 auto SqrtD1 = B.buildFMA(F64, NegSqrtS2, SqrtS2, SqrtX);
6105 auto SqrtD2 = B.buildFMA(F64, SqrtD1, SqrtH1, SqrtS2);
6106
6107 // Scale down the result.
6108 auto ScaleDownFactor = B.buildConstant(I32, -128);
6109 auto ScaleDown = B.buildSelect(I32, Scaling, ScaleDownFactor, ZeroInt);
6110 SqrtRet = B.buildFLdexp(F64, SqrtD2, ScaleDown, Flags).getReg(0);
6111 }
6112
6113 Register IsZeroOrInf;
6114 if (MI.getFlag(MachineInstr::FmNoInfs)) {
6115 auto ZeroFP = B.buildFConstant(F64, 0.0);
6116 IsZeroOrInf = B.buildFCmp(FCmpInst::FCMP_OEQ, I1, SqrtX, ZeroFP).getReg(0);
6117 } else {
6118 IsZeroOrInf = B.buildIsFPClass(I1, SqrtX, fcZero | fcPosInf).getReg(0);
6119 }
6120
6121 // TODO: Check for DAZ and expand to subnormals
6122
6123 // If x is +INF, +0, or -0, use its original value
6124 B.buildSelect(Dst, IsZeroOrInf, SqrtX, SqrtRet, Flags);
6125
6126 MI.eraseFromParent();
6127 return true;
6128}
6129
6132 MachineIRBuilder &B) const {
6133 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
6134 if (Ty == F32)
6135 return legalizeFSQRTF32(MI, MRI, B);
6136 if (Ty == F64)
6137 return legalizeFSQRTF64(MI, MRI, B);
6138 if (Ty == F16)
6139 return legalizeFSQRTF16(MI, MRI, B);
6140 return false;
6141}
6142
6143// Expand llvm.amdgcn.rsq.clamp on targets that don't support the instruction.
6144// FIXME: Why do we handle this one but not other removed instructions?
6145//
6146// Reciprocal square root. The clamp prevents infinite results, clamping
6147// infinities to max_float. D.f = 1.0 / sqrt(S0.f), result clamped to
6148// +-max_float.
6151 MachineIRBuilder &B) const {
6152 if (ST.getGeneration() < AMDGPUSubtarget::VOLCANIC_ISLANDS)
6153 return true;
6154
6155 Register Dst = MI.getOperand(0).getReg();
6156 Register Src = MI.getOperand(2).getReg();
6157 auto Flags = MI.getFlags();
6158
6159 LLT Ty = MRI.getType(Dst);
6160
6161 const fltSemantics *FltSemantics;
6162 if (Ty == F32)
6163 FltSemantics = &APFloat::IEEEsingle();
6164 else if (Ty == F64)
6165 FltSemantics = &APFloat::IEEEdouble();
6166 else
6167 return false;
6168
6169 auto Rsq = B.buildIntrinsic(Intrinsic::amdgcn_rsq, {Ty})
6170 .addUse(Src)
6171 .setMIFlags(Flags);
6172
6173 // We don't need to concern ourselves with the snan handling difference, since
6174 // the rsq quieted (or not) so use the one which will directly select.
6175 const SIMachineFunctionInfo *MFI = B.getMF().getInfo<SIMachineFunctionInfo>();
6176 const bool UseIEEE = MFI->getMode().IEEE;
6177
6178 auto MaxFlt = B.buildFConstant(Ty, APFloat::getLargest(*FltSemantics));
6179 auto ClampMax = UseIEEE ? B.buildFMinNumIEEE(Ty, Rsq, MaxFlt, Flags) :
6180 B.buildFMinNum(Ty, Rsq, MaxFlt, Flags);
6181
6182 auto MinFlt = B.buildFConstant(Ty, APFloat::getLargest(*FltSemantics, true));
6183
6184 if (UseIEEE)
6185 B.buildFMaxNumIEEE(Dst, ClampMax, MinFlt, Flags);
6186 else
6187 B.buildFMaxNum(Dst, ClampMax, MinFlt, Flags);
6188 MI.eraseFromParent();
6189 return true;
6190}
6191
6192// TODO: Fix pointer type handling
6195 Intrinsic::ID IID) const {
6196
6197 MachineIRBuilder &B = Helper.MIRBuilder;
6198 MachineRegisterInfo &MRI = *B.getMRI();
6199
6200 bool IsPermLane16 = IID == Intrinsic::amdgcn_permlane16 ||
6201 IID == Intrinsic::amdgcn_permlanex16;
6202 bool IsSetInactive = IID == Intrinsic::amdgcn_set_inactive ||
6203 IID == Intrinsic::amdgcn_set_inactive_chain_arg;
6204 bool IsPermlaneShuffle = IID == Intrinsic::amdgcn_permlane_bcast ||
6205 IID == Intrinsic::amdgcn_permlane_up ||
6206 IID == Intrinsic::amdgcn_permlane_down ||
6207 IID == Intrinsic::amdgcn_permlane_xor;
6208
6209 auto createLaneOp = [&IID, &B, &MI](Register Src0, Register Src1,
6210 Register Src2, LLT VT) -> Register {
6211 auto LaneOp = B.buildIntrinsic(IID, {VT}).addUse(Src0);
6212 switch (IID) {
6213 case Intrinsic::amdgcn_readfirstlane:
6214 case Intrinsic::amdgcn_permlane64:
6215 return LaneOp.getReg(0);
6216 case Intrinsic::amdgcn_readlane:
6217 case Intrinsic::amdgcn_set_inactive:
6218 case Intrinsic::amdgcn_set_inactive_chain_arg:
6219 return LaneOp.addUse(Src1).getReg(0);
6220 case Intrinsic::amdgcn_writelane:
6221 case Intrinsic::amdgcn_permlane_bcast:
6222 case Intrinsic::amdgcn_permlane_up:
6223 case Intrinsic::amdgcn_permlane_down:
6224 case Intrinsic::amdgcn_permlane_xor:
6225 return LaneOp.addUse(Src1).addUse(Src2).getReg(0);
6226 case Intrinsic::amdgcn_permlane16:
6227 case Intrinsic::amdgcn_permlanex16: {
6228 Register Src3 = MI.getOperand(5).getReg();
6229 int64_t Src4 = MI.getOperand(6).getImm();
6230 int64_t Src5 = MI.getOperand(7).getImm();
6231 return LaneOp.addUse(Src1)
6232 .addUse(Src2)
6233 .addUse(Src3)
6234 .addImm(Src4)
6235 .addImm(Src5)
6236 .getReg(0);
6237 }
6238 case Intrinsic::amdgcn_mov_dpp8:
6239 return LaneOp.addImm(MI.getOperand(3).getImm()).getReg(0);
6240 case Intrinsic::amdgcn_update_dpp:
6241 return LaneOp.addUse(Src1)
6242 .addImm(MI.getOperand(4).getImm())
6243 .addImm(MI.getOperand(5).getImm())
6244 .addImm(MI.getOperand(6).getImm())
6245 .addImm(MI.getOperand(7).getImm())
6246 .getReg(0);
6247 default:
6248 llvm_unreachable("unhandled lane op");
6249 }
6250 };
6251
6252 Register DstReg = MI.getOperand(0).getReg();
6253 Register Src0 = MI.getOperand(2).getReg();
6254 Register Src1, Src2;
6255 if (IID == Intrinsic::amdgcn_readlane || IID == Intrinsic::amdgcn_writelane ||
6256 IID == Intrinsic::amdgcn_update_dpp || IsSetInactive || IsPermLane16 ||
6257 IsPermlaneShuffle) {
6258 Src1 = MI.getOperand(3).getReg();
6259 if (IID == Intrinsic::amdgcn_writelane || IsPermLane16 ||
6260 IsPermlaneShuffle) {
6261 Src2 = MI.getOperand(4).getReg();
6262 }
6263 }
6264
6265 LLT Ty = MRI.getType(DstReg);
6266 unsigned Size = Ty.getSizeInBits();
6267
6268 unsigned SplitSize = 32;
6269 if (IID == Intrinsic::amdgcn_update_dpp && (Size % 64 == 0) &&
6270 ST.hasDPALU_DPP() &&
6271 AMDGPU::isLegalDPALU_DPPControl(ST, MI.getOperand(4).getImm()))
6272 SplitSize = 64;
6273
6274 if (Size == SplitSize) {
6275 // Already legal
6276 return true;
6277 }
6278
6279 const LLT I32 = LLT::integer(32);
6280
6281 bool IsFloat = Ty.getScalarType().isFloat();
6282
6283 LLT IntTy = IsFloat ? LLT::integer(Size) : Ty;
6284 if (IsFloat) {
6285 Src0 = B.buildBitcast(IntTy, Src0).getReg(0);
6286 if (Src1 && MRI.getType(Src1).getScalarType().isFloat())
6287 Src1 = B.buildBitcast(IntTy, Src1).getReg(0);
6288 if (Src2 && MRI.getType(Src2).getScalarType().isFloat())
6289 Src2 = B.buildBitcast(IntTy, Src2).getReg(0);
6290 }
6291
6292 if (Size < 32) {
6293 Src0 = B.buildAnyExt(I32, Src0).getReg(0);
6294
6295 if (IID == Intrinsic::amdgcn_update_dpp || IsSetInactive || IsPermLane16)
6296 Src1 = B.buildAnyExt(I32, Src1).getReg(0);
6297
6298 if (IID == Intrinsic::amdgcn_writelane)
6299 Src2 = B.buildAnyExt(I32, Src2).getReg(0);
6300
6301 Register LaneOpDst = createLaneOp(Src0, Src1, Src2, I32);
6302 if (IsFloat)
6303 B.buildBitcast(DstReg, B.buildTrunc(IntTy, LaneOpDst));
6304 else
6305 B.buildTrunc(DstReg, LaneOpDst);
6306 MI.eraseFromParent();
6307 return true;
6308 }
6309
6310 if (Size % SplitSize != 0)
6311 return false;
6312
6313 LLT PartialResTy = LLT::integer(SplitSize);
6314 bool NeedsBitcast = false;
6315 if (IntTy.isVector()) {
6316 LLT EltTy = IntTy.getElementType();
6317 unsigned EltSize = EltTy.getSizeInBits();
6318 if (EltSize == SplitSize) {
6319 PartialResTy = EltTy;
6320 } else if (EltSize == 16 || EltSize == 32) {
6321 unsigned NElem = SplitSize / EltSize;
6322 PartialResTy = IntTy.changeElementCount(ElementCount::getFixed(NElem));
6323 } else {
6324 NeedsBitcast = true;
6325 }
6326 }
6327
6328 SmallVector<Register, 4> PartialRes;
6329 unsigned NumParts = Size / SplitSize;
6330 MachineInstrBuilder Src0Parts = B.buildUnmerge(PartialResTy, Src0);
6331 MachineInstrBuilder Src1Parts, Src2Parts;
6332
6333 if (IID == Intrinsic::amdgcn_update_dpp || IsSetInactive || IsPermLane16)
6334 Src1Parts = B.buildUnmerge(PartialResTy, Src1);
6335
6336 if (IID == Intrinsic::amdgcn_writelane)
6337 Src2Parts = B.buildUnmerge(PartialResTy, Src2);
6338
6339 for (unsigned i = 0; i < NumParts; ++i) {
6340 Src0 = Src0Parts.getReg(i);
6341
6342 if (IID == Intrinsic::amdgcn_update_dpp || IsSetInactive || IsPermLane16)
6343 Src1 = Src1Parts.getReg(i);
6344
6345 if (IID == Intrinsic::amdgcn_writelane)
6346 Src2 = Src2Parts.getReg(i);
6347
6348 PartialRes.push_back(createLaneOp(Src0, Src1, Src2, PartialResTy));
6349 }
6350
6351 if (NeedsBitcast || IsFloat)
6352 B.buildBitcast(
6353 DstReg,
6354 B.buildMergeLikeInstr(LLT::integer(IntTy.getSizeInBits()), PartialRes));
6355 else
6356 B.buildMergeLikeInstr(DstReg, PartialRes);
6357
6358 MI.eraseFromParent();
6359 return true;
6360}
6361
6364 MachineIRBuilder &B) const {
6365 uint64_t Offset =
6366 ST.getTargetLowering()->getImplicitParameterOffset(
6368 LLT DstTy = MRI.getType(DstReg);
6369 LLT IdxTy = LLT::integer(DstTy.getSizeInBits());
6370
6371 Register KernargPtrReg = MRI.createGenericVirtualRegister(DstTy);
6372 if (!loadInputValue(KernargPtrReg, B,
6374 return false;
6375
6376 B.buildObjectPtrOffset(DstReg, KernargPtrReg,
6377 B.buildConstant(IdxTy, Offset).getReg(0));
6378 return true;
6379}
6380
6381/// To create a buffer resource from a 64-bit pointer, mask off the upper 32
6382/// bits of the pointer and replace them with the stride argument, then
6383/// merge_values everything together. In the common case of a raw buffer (the
6384/// stride component is 0), we can just AND off the upper half.
6387 Register Result = MI.getOperand(0).getReg();
6388 Register Pointer = MI.getOperand(2).getReg();
6389 Register Stride = MI.getOperand(3).getReg();
6390 Register NumRecords = MI.getOperand(4).getReg();
6391 Register Flags = MI.getOperand(5).getReg();
6392
6393 LLT I32 = LLT::integer(32);
6394 LLT I64 = LLT::integer(64);
6395
6396 B.setInsertPt(B.getMBB(), ++B.getInsertPt());
6397
6398 auto ExtStride = B.buildAnyExt(I32, Stride);
6399
6400 if (ST.getBufferResourceNumRecordsWidth() == 45) {
6401 NumRecords = B.buildZExtOrTrunc(I64, NumRecords).getReg(0);
6402 NumRecords =
6403 B.buildAnd(I64, NumRecords, B.buildConstant(I64, (1ULL << 45) - 1))
6404 .getReg(0);
6405 Register Zero = B.buildConstant(I32, 0).getReg(0);
6406 // Build the lower 64-bit value, which has a 57-bit base and the lower 7-bit
6407 // num_records.
6408 LLT PtrIntTy = LLT::integer(MRI.getType(Pointer).getSizeInBits());
6409 auto PointerInt = B.buildPtrToInt(PtrIntTy, Pointer);
6410 auto ExtPointer = B.buildAnyExtOrTrunc(I64, PointerInt);
6411 auto NumRecordsLHS = B.buildShl(I64, NumRecords, B.buildConstant(I32, 57));
6412 Register LowHalf = B.buildOr(I64, ExtPointer, NumRecordsLHS).getReg(0);
6413
6414 // Build the higher 64-bit value, which has the higher 38-bit num_records,
6415 // 6-bit zero (omit), 16-bit stride and scale and 4-bit flag.
6416 auto NumRecordsRHS = B.buildLShr(I64, NumRecords, B.buildConstant(I32, 7));
6417 auto ShiftedStride = B.buildShl(I32, ExtStride, B.buildConstant(I32, 12));
6418 auto ExtShiftedStride =
6419 B.buildMergeValues(I64, {Zero, ShiftedStride.getReg(0)});
6420 auto ShiftedFlags = B.buildShl(I32, Flags, B.buildConstant(I32, 28));
6421 auto ExtShiftedFlags =
6422 B.buildMergeValues(I64, {Zero, ShiftedFlags.getReg(0)});
6423 auto CombinedFields = B.buildOr(I64, NumRecordsRHS, ExtShiftedStride);
6424 Register HighHalf =
6425 B.buildOr(I64, CombinedFields, ExtShiftedFlags).getReg(0);
6426 B.buildMergeValues(Result, {LowHalf, HighHalf});
6427 } else {
6428 NumRecords = B.buildZExtOrTrunc(I32, NumRecords).getReg(0);
6429 auto Unmerge = B.buildUnmerge(I32, Pointer);
6430 auto LowHalf = Unmerge.getReg(0);
6431 auto HighHalf = Unmerge.getReg(1);
6432
6433 auto AndMask = B.buildConstant(I32, 0x0000ffff);
6434 auto Masked = B.buildAnd(I32, HighHalf, AndMask);
6435 auto ShiftConst = B.buildConstant(I32, 16);
6436 auto ShiftedStride = B.buildShl(I32, ExtStride, ShiftConst);
6437 auto NewHighHalf = B.buildOr(I32, Masked, ShiftedStride);
6438 Register NewHighHalfReg = NewHighHalf.getReg(0);
6439 B.buildMergeValues(Result, {LowHalf, NewHighHalfReg, NumRecords, Flags});
6440 }
6441
6442 MI.eraseFromParent();
6443 return true;
6444}
6445
6448 MachineIRBuilder &B) const {
6449 const SIMachineFunctionInfo *MFI = B.getMF().getInfo<SIMachineFunctionInfo>();
6450 if (!MFI->isEntryFunction()) {
6451 return legalizePreloadedArgIntrin(MI, MRI, B,
6453 }
6454
6455 Register DstReg = MI.getOperand(0).getReg();
6456 if (!getImplicitArgPtr(DstReg, MRI, B))
6457 return false;
6458
6459 MI.eraseFromParent();
6460 return true;
6461}
6462
6465 MachineIRBuilder &B) const {
6466 Function &F = B.getMF().getFunction();
6467 std::optional<uint32_t> KnownSize =
6469 if (KnownSize.has_value())
6470 B.buildConstant(DstReg, *KnownSize);
6471 return false;
6472}
6473
6476 MachineIRBuilder &B) const {
6477
6478 const SIMachineFunctionInfo *MFI = B.getMF().getInfo<SIMachineFunctionInfo>();
6479 if (!MFI->isEntryFunction()) {
6480 return legalizePreloadedArgIntrin(MI, MRI, B,
6482 }
6483
6484 Register DstReg = MI.getOperand(0).getReg();
6485 if (!getLDSKernelId(DstReg, MRI, B))
6486 return false;
6487
6488 MI.eraseFromParent();
6489 return true;
6490}
6491
6495 unsigned AddrSpace) const {
6496 const LLT I32 = LLT::integer(32);
6497 auto Unmerge = B.buildUnmerge(I32, MI.getOperand(2).getReg());
6498 Register Hi32 = Unmerge.getReg(1);
6499
6500 if (AddrSpace == AMDGPUAS::PRIVATE_ADDRESS &&
6501 ST.hasGloballyAddressableScratch()) {
6502 Register FlatScratchBaseHi =
6503 B.buildInstr(AMDGPU::S_MOV_B32, {I32},
6504 {Register(AMDGPU::SRC_FLAT_SCRATCH_BASE_HI)})
6505 .getReg(0);
6506 MRI.setRegClass(FlatScratchBaseHi, &AMDGPU::SReg_32RegClass);
6507 // Test bits 63..58 against the aperture address.
6508 Register XOR = B.buildXor(I32, Hi32, FlatScratchBaseHi).getReg(0);
6509 B.buildICmp(ICmpInst::ICMP_ULT, MI.getOperand(0), XOR,
6510 B.buildConstant(I32, 1u << 26));
6511 } else {
6512 Register ApertureReg = getSegmentAperture(AddrSpace, MRI, B);
6513 B.buildICmp(ICmpInst::ICMP_EQ, MI.getOperand(0), Hi32, ApertureReg);
6514 }
6515 MI.eraseFromParent();
6516 return true;
6517}
6518
6519// The raw.(t)buffer and struct.(t)buffer intrinsics have two offset args:
6520// offset (the offset that is included in bounds checking and swizzling, to be
6521// split between the instruction's voffset and immoffset fields) and soffset
6522// (the offset that is excluded from bounds checking and swizzling, to go in
6523// the instruction's soffset field). This function takes the first kind of
6524// offset and figures out how to split it between voffset and immoffset.
6525std::pair<Register, unsigned>
6527 Register OrigOffset) const {
6528 const unsigned MaxImm = SIInstrInfo::getMaxMUBUFImmOffset(ST);
6529 Register BaseReg;
6530 unsigned ImmOffset;
6531 const LLT I32 = LLT::integer(32);
6532 MachineRegisterInfo &MRI = *B.getMRI();
6533
6534 // On GFX1250+, voffset and immoffset are zero-extended from 32 bits before
6535 // being added, so we can only safely match a 32-bit addition with no unsigned
6536 // overflow.
6537 bool CheckNUW = ST.hasGFX1250Insts();
6538 std::tie(BaseReg, ImmOffset) = AMDGPU::getBaseWithConstantOffset(
6539 MRI, OrigOffset, /*KnownBits=*/nullptr, CheckNUW);
6540
6541 // If BaseReg is a pointer, convert it to int.
6542 if (MRI.getType(BaseReg).isPointer())
6543 BaseReg = B.buildPtrToInt(MRI.getType(OrigOffset), BaseReg).getReg(0);
6544
6545 // If the immediate value is too big for the immoffset field, put only bits
6546 // that would normally fit in the immoffset field. The remaining value that
6547 // is copied/added for the voffset field is a large power of 2, and it
6548 // stands more chance of being CSEd with the copy/add for another similar
6549 // load/store.
6550 // However, do not do that rounding down if that is a negative
6551 // number, as it appears to be illegal to have a negative offset in the
6552 // vgpr, even if adding the immediate offset makes it positive.
6553 unsigned Overflow = ImmOffset & ~MaxImm;
6554 ImmOffset -= Overflow;
6555 if ((int32_t)Overflow < 0) {
6556 Overflow += ImmOffset;
6557 ImmOffset = 0;
6558 }
6559
6560 if (Overflow != 0) {
6561 if (!BaseReg) {
6562 BaseReg = B.buildConstant(I32, Overflow).getReg(0);
6563 } else {
6564 auto OverflowVal = B.buildConstant(I32, Overflow);
6565 BaseReg = B.buildAdd(I32, BaseReg, OverflowVal).getReg(0);
6566 }
6567 }
6568
6569 if (!BaseReg)
6570 BaseReg = B.buildConstant(I32, 0).getReg(0);
6571
6572 return std::pair(BaseReg, ImmOffset);
6573}
6574
6575/// Handle register layout difference for f16 images for some subtargets.
6578 Register Reg,
6579 bool ImageStore) const {
6580 const LLT I16 = LLT::integer(16);
6581 const LLT I32 = LLT::integer(32);
6582 LLT StoreVT = MRI.getType(Reg);
6583 assert(StoreVT.isVector() && StoreVT.getElementType().getSizeInBits() == 16);
6584
6585 LLT I16Vec = StoreVT.changeElementType(I16);
6586 Register RegI16 =
6587 StoreVT == I16Vec ? Reg : B.buildBitcast(I16Vec, Reg).getReg(0);
6588
6589 if (ST.hasUnpackedD16VMem()) {
6590 auto Unmerge = B.buildUnmerge(I16, RegI16);
6591
6592 SmallVector<Register, 4> WideRegs;
6593 for (int I = 0, E = Unmerge->getNumOperands() - 1; I != E; ++I)
6594 WideRegs.push_back(B.buildAnyExt(I32, Unmerge.getReg(I)).getReg(0));
6595
6596 int NumElts = StoreVT.getNumElements();
6597
6598 return B.buildBuildVector(LLT::fixed_vector(NumElts, I32), WideRegs)
6599 .getReg(0);
6600 }
6601
6602 if (ImageStore && ST.hasImageStoreD16Bug()) {
6603 if (StoreVT.getNumElements() == 2) {
6604 SmallVector<Register, 4> PackedRegs;
6605 Reg = B.buildBitcast(I32, RegI16).getReg(0);
6606 PackedRegs.push_back(Reg);
6607 PackedRegs.resize(2, B.buildUndef(I32).getReg(0));
6608 return B.buildBuildVector(LLT::fixed_vector(2, I32), PackedRegs)
6609 .getReg(0);
6610 }
6611
6612 if (StoreVT.getNumElements() == 3) {
6613 SmallVector<Register, 4> PackedRegs;
6614 auto Unmerge = B.buildUnmerge(I16, RegI16);
6615 for (int I = 0, E = Unmerge->getNumOperands() - 1; I != E; ++I)
6616 PackedRegs.push_back(Unmerge.getReg(I));
6617 PackedRegs.resize(6, B.buildUndef(I16).getReg(0));
6618 Reg = B.buildBuildVector(LLT::fixed_vector(6, I16), PackedRegs).getReg(0);
6619 return B.buildBitcast(LLT::fixed_vector(3, I32), Reg).getReg(0);
6620 }
6621
6622 if (StoreVT.getNumElements() == 4) {
6623 SmallVector<Register, 4> PackedRegs;
6624 Reg = B.buildBitcast(LLT::fixed_vector(2, I32), RegI16).getReg(0);
6625 auto Unmerge = B.buildUnmerge(I32, Reg);
6626 for (int I = 0, E = Unmerge->getNumOperands() - 1; I != E; ++I)
6627 PackedRegs.push_back(Unmerge.getReg(I));
6628 PackedRegs.resize(4, B.buildUndef(I32).getReg(0));
6629 return B.buildBuildVector(LLT::fixed_vector(4, I32), PackedRegs)
6630 .getReg(0);
6631 }
6632
6633 llvm_unreachable("invalid data type");
6634 }
6635
6636 if (StoreVT.isVector() && StoreVT.getNumElements() == 3 &&
6637 StoreVT.getElementType().getSizeInBits() == 16) {
6638 Reg = B.buildPadVectorWithUndefElements(
6639 LLT::fixed_vector(4, StoreVT.getElementType()), Reg)
6640 .getReg(0);
6641 }
6642 return Reg;
6643}
6644
6646 Register VData, LLT MemTy,
6647 bool IsFormat) const {
6648 MachineRegisterInfo *MRI = B.getMRI();
6649 LLT Ty = MRI->getType(VData);
6650
6651 // Fixup buffer resources themselves needing to be v4i128.
6653 return castBufferRsrcToV4I32(VData, B);
6654
6655 if (shouldBitcastLoadStoreType(ST, Ty, MemTy)) {
6656 Ty = getBitcastRegisterType(Ty);
6657 VData = B.buildBitcast(Ty, VData).getReg(0);
6658 }
6659 // Fixup illegal register types for i8 stores.
6660 if (Ty == LLT::integer(8) || Ty == LLT::integer(16) || Ty == F16) {
6661 Register AnyExt = B.buildAnyExt(LLT::integer(32), VData).getReg(0);
6662 return AnyExt;
6663 }
6664
6665 if (Ty.isVector()) {
6666 if (Ty.getElementType().getSizeInBits() == 16 && Ty.getNumElements() <= 4) {
6667 if (IsFormat)
6668 return handleD16VData(B, *MRI, VData);
6669 }
6670 }
6671
6672 return VData;
6673}
6674
6676 LegalizerHelper &Helper,
6677 bool IsTyped,
6678 bool IsFormat) const {
6679 MachineIRBuilder &B = Helper.MIRBuilder;
6680 MachineRegisterInfo &MRI = *B.getMRI();
6681
6682 Register VData = MI.getOperand(1).getReg();
6683 LLT Ty = MRI.getType(VData);
6684 LLT EltTy = Ty.getScalarType();
6685 const bool IsD16 = IsFormat && (EltTy.getSizeInBits() == 16);
6686 const LLT I32 = LLT::integer(32);
6687
6688 MachineMemOperand *MMO = *MI.memoperands_begin();
6689 const int MemSize = MMO->getSize().getValue();
6690 LLT MemTy = MMO->getMemoryType();
6691
6692 if (IsFormat && !IsTyped && !IsD16 && MemTy.getSizeInBits() < 32) {
6693 const Function &Fn = B.getMF().getFunction();
6695 Fn, "unsupported sub-dword format buffer store", MI.getDebugLoc()));
6696 MI.eraseFromParent();
6697 return true;
6698 }
6699
6700 VData = fixStoreSourceType(B, VData, MemTy, IsFormat);
6701
6703 Register RSrc = MI.getOperand(2).getReg();
6704
6705 unsigned ImmOffset;
6706
6707 // The typed intrinsics add an immediate after the registers.
6708 const unsigned NumVIndexOps = IsTyped ? 8 : 7;
6709
6710 // The struct intrinsic variants add one additional operand over raw.
6711 const bool HasVIndex = MI.getNumOperands() == NumVIndexOps;
6712 Register VIndex;
6713 int OpOffset = 0;
6714 if (HasVIndex) {
6715 VIndex = MI.getOperand(3).getReg();
6716 OpOffset = 1;
6717 } else {
6718 VIndex = B.buildConstant(I32, 0).getReg(0);
6719 }
6720
6721 Register VOffset = MI.getOperand(3 + OpOffset).getReg();
6722 Register SOffset = MI.getOperand(4 + OpOffset).getReg();
6723
6724 unsigned Format = 0;
6725 if (IsTyped) {
6726 Format = MI.getOperand(5 + OpOffset).getImm();
6727 ++OpOffset;
6728 }
6729
6730 unsigned AuxiliaryData = MI.getOperand(5 + OpOffset).getImm();
6731
6732 std::tie(VOffset, ImmOffset) = splitBufferOffsets(B, VOffset);
6733
6734 unsigned Opc;
6735 if (IsTyped) {
6736 Opc = IsD16 ? AMDGPU::G_AMDGPU_TBUFFER_STORE_FORMAT_D16 :
6737 AMDGPU::G_AMDGPU_TBUFFER_STORE_FORMAT;
6738 } else if (IsFormat) {
6739 Opc = IsD16 ? AMDGPU::G_AMDGPU_BUFFER_STORE_FORMAT_D16 :
6740 AMDGPU::G_AMDGPU_BUFFER_STORE_FORMAT;
6741 } else {
6742 switch (MemSize) {
6743 case 1:
6744 Opc = AMDGPU::G_AMDGPU_BUFFER_STORE_BYTE;
6745 break;
6746 case 2:
6747 Opc = AMDGPU::G_AMDGPU_BUFFER_STORE_SHORT;
6748 break;
6749 default:
6750 Opc = AMDGPU::G_AMDGPU_BUFFER_STORE;
6751 break;
6752 }
6753 }
6754
6755 auto MIB = B.buildInstr(Opc)
6756 .addUse(VData) // vdata
6757 .addUse(RSrc) // rsrc
6758 .addUse(VIndex) // vindex
6759 .addUse(VOffset) // voffset
6760 .addUse(SOffset) // soffset
6761 .addImm(ImmOffset); // offset(imm)
6762
6763 if (IsTyped)
6764 MIB.addImm(Format);
6765
6766 MIB.addImm(AuxiliaryData) // cachepolicy, swizzled buffer(imm)
6767 .addImm(HasVIndex ? -1 : 0) // idxen(imm)
6768 .addMemOperand(MMO);
6769
6770 MI.eraseFromParent();
6771 return true;
6772}
6773
6774static void buildBufferLoad(unsigned Opc, Register LoadDstReg, Register RSrc,
6775 Register VIndex, Register VOffset, Register SOffset,
6776 unsigned ImmOffset, unsigned Format,
6777 unsigned AuxiliaryData, MachineMemOperand *MMO,
6778 bool IsTyped, bool HasVIndex, MachineIRBuilder &B) {
6779 auto MIB = B.buildInstr(Opc)
6780 .addDef(LoadDstReg) // vdata
6781 .addUse(RSrc) // rsrc
6782 .addUse(VIndex) // vindex
6783 .addUse(VOffset) // voffset
6784 .addUse(SOffset) // soffset
6785 .addImm(ImmOffset); // offset(imm)
6786
6787 if (IsTyped)
6788 MIB.addImm(Format);
6789
6790 MIB.addImm(AuxiliaryData) // cachepolicy, swizzled buffer(imm)
6791 .addImm(HasVIndex ? -1 : 0) // idxen(imm)
6792 .addMemOperand(MMO);
6793}
6794
6796 LegalizerHelper &Helper,
6797 bool IsFormat,
6798 bool IsTyped) const {
6799 MachineIRBuilder &B = Helper.MIRBuilder;
6800 MachineRegisterInfo &MRI = *B.getMRI();
6801 GISelChangeObserver &Observer = Helper.Observer;
6802
6803 // FIXME: Verifier should enforce 1 MMO for these intrinsics.
6804 MachineMemOperand *MMO = *MI.memoperands_begin();
6805 const LLT MemTy = MMO->getMemoryType();
6806 const LLT I32 = LLT::integer(32);
6807
6808 Register Dst = MI.getOperand(0).getReg();
6809
6810 Register StatusDst;
6811 int OpOffset = 0;
6812 assert(MI.getNumExplicitDefs() == 1 || MI.getNumExplicitDefs() == 2);
6813 bool IsTFE = MI.getNumExplicitDefs() == 2;
6814 if (IsTFE) {
6815 StatusDst = MI.getOperand(1).getReg();
6816 ++OpOffset;
6817 }
6818
6819 castBufferRsrcArgToV4I32(MI, B, 2 + OpOffset);
6820 Register RSrc = MI.getOperand(2 + OpOffset).getReg();
6821
6822 // The typed intrinsics add an immediate after the registers.
6823 const unsigned NumVIndexOps = IsTyped ? 8 : 7;
6824
6825 // The struct intrinsic variants add one additional operand over raw.
6826 const bool HasVIndex = MI.getNumOperands() == NumVIndexOps + OpOffset;
6827 Register VIndex;
6828 if (HasVIndex) {
6829 VIndex = MI.getOperand(3 + OpOffset).getReg();
6830 ++OpOffset;
6831 } else {
6832 VIndex = B.buildConstant(I32, 0).getReg(0);
6833 }
6834
6835 Register VOffset = MI.getOperand(3 + OpOffset).getReg();
6836 Register SOffset = MI.getOperand(4 + OpOffset).getReg();
6837
6838 unsigned Format = 0;
6839 if (IsTyped) {
6840 Format = MI.getOperand(5 + OpOffset).getImm();
6841 ++OpOffset;
6842 }
6843
6844 unsigned AuxiliaryData = MI.getOperand(5 + OpOffset).getImm();
6845 unsigned ImmOffset;
6846
6847 LLT Ty = MRI.getType(Dst);
6848 // Make addrspace 8 pointers loads into 4xi32 loads here, so the rest of the
6849 // logic doesn't have to handle that case.
6850 if (hasBufferRsrcWorkaround(Ty)) {
6851 Observer.changingInstr(MI);
6852 Ty = castBufferRsrcFromV4I32(MI, B, MRI, 0);
6853 Observer.changedInstr(MI);
6854 Dst = MI.getOperand(0).getReg();
6855 B.setInsertPt(B.getMBB(), MI);
6856 }
6857 if (shouldBitcastLoadStoreType(ST, Ty, MemTy)) {
6858 Ty = getBitcastRegisterType(Ty);
6859 Observer.changingInstr(MI);
6860 Helper.bitcastDst(MI, Ty, 0);
6861 Observer.changedInstr(MI);
6862 Dst = MI.getOperand(0).getReg();
6863 B.setInsertPt(B.getMBB(), MI);
6864 }
6865
6866 LLT EltTy = Ty.getScalarType();
6867 const bool IsD16 = IsFormat && (EltTy.getSizeInBits() == 16);
6868 const bool Unpacked = ST.hasUnpackedD16VMem();
6869
6870 if (IsFormat && !IsTyped && !IsD16 && MemTy.getSizeInBits() < 32) {
6871 const Function &Fn = B.getMF().getFunction();
6873 Fn, "unsupported sub-dword format buffer load", MI.getDebugLoc()));
6874 B.buildUndef(Dst);
6875 if (IsTFE)
6876 B.buildUndef(StatusDst);
6877 MI.eraseFromParent();
6878 return true;
6879 }
6880
6881 std::tie(VOffset, ImmOffset) = splitBufferOffsets(B, VOffset);
6882
6883 unsigned Opc;
6884
6885 // TODO: Support TFE for typed and narrow loads.
6886 if (IsTyped) {
6887 if (IsTFE)
6888 return false;
6889 Opc = IsD16 ? AMDGPU::G_AMDGPU_TBUFFER_LOAD_FORMAT_D16 :
6890 AMDGPU::G_AMDGPU_TBUFFER_LOAD_FORMAT;
6891 } else if (IsFormat) {
6892 if (IsD16) {
6893 if (IsTFE)
6894 return false;
6895 Opc = AMDGPU::G_AMDGPU_BUFFER_LOAD_FORMAT_D16;
6896 } else {
6897 Opc = IsTFE ? AMDGPU::G_AMDGPU_BUFFER_LOAD_FORMAT_TFE
6898 : AMDGPU::G_AMDGPU_BUFFER_LOAD_FORMAT;
6899 }
6900 } else {
6901 switch (MemTy.getSizeInBits()) {
6902 case 8:
6903 Opc = IsTFE ? AMDGPU::G_AMDGPU_BUFFER_LOAD_UBYTE_TFE
6904 : AMDGPU::G_AMDGPU_BUFFER_LOAD_UBYTE;
6905 break;
6906 case 16:
6907 Opc = IsTFE ? AMDGPU::G_AMDGPU_BUFFER_LOAD_USHORT_TFE
6908 : AMDGPU::G_AMDGPU_BUFFER_LOAD_USHORT;
6909 break;
6910 default:
6911 Opc = IsTFE ? AMDGPU::G_AMDGPU_BUFFER_LOAD_TFE
6912 : AMDGPU::G_AMDGPU_BUFFER_LOAD;
6913 break;
6914 }
6915 }
6916
6917 if (IsTFE) {
6918 unsigned NumValueDWords = divideCeil(Ty.getSizeInBits(), 32);
6919 unsigned NumLoadDWords = NumValueDWords + 1;
6920 LLT LoadTy = LLT::fixed_vector(NumLoadDWords, I32);
6921 Register LoadDstReg = B.getMRI()->createGenericVirtualRegister(LoadTy);
6922 buildBufferLoad(Opc, LoadDstReg, RSrc, VIndex, VOffset, SOffset, ImmOffset,
6923 Format, AuxiliaryData, MMO, IsTyped, HasVIndex, B);
6924 bool IsFloat = Ty.getScalarType().isFloat();
6925 LLT DstIntTy =
6926 IsFloat ? Ty.changeElementType(LLT::integer(EltTy.getSizeInBits()))
6927 : Ty;
6928 Register DstInt =
6929 IsFloat ? B.getMRI()->createGenericVirtualRegister(DstIntTy) : Dst;
6930 if (MemTy.getSizeInBits() < 32) {
6931 Register ExtDst = B.getMRI()->createGenericVirtualRegister(I32);
6932 B.buildUnmerge({ExtDst, StatusDst}, LoadDstReg);
6933 B.buildTrunc(DstInt, ExtDst);
6934 } else if (NumValueDWords == 1) {
6935 B.buildUnmerge({DstInt, StatusDst}, LoadDstReg);
6936 } else {
6937 SmallVector<Register, 5> LoadElts;
6938 for (unsigned I = 0; I != NumValueDWords; ++I)
6939 LoadElts.push_back(B.getMRI()->createGenericVirtualRegister(I32));
6940 LoadElts.push_back(StatusDst);
6941 B.buildUnmerge(LoadElts, LoadDstReg);
6942 LoadElts.truncate(NumValueDWords);
6943 B.buildMergeLikeInstr(DstInt, LoadElts);
6944 }
6945 if (DstInt != Dst)
6946 B.buildBitcast(Dst, DstInt);
6947 } else if ((!IsD16 && MemTy.getSizeInBits() < 32) ||
6948 (IsD16 && !Ty.isVector())) {
6949 Register LoadDstReg = B.getMRI()->createGenericVirtualRegister(I32);
6950 buildBufferLoad(Opc, LoadDstReg, RSrc, VIndex, VOffset, SOffset, ImmOffset,
6951 Format, AuxiliaryData, MMO, IsTyped, HasVIndex, B);
6952 B.setInsertPt(B.getMBB(), ++B.getInsertPt());
6953 B.buildTrunc(Dst, LoadDstReg);
6954 } else if (Unpacked && IsD16 && Ty.isVector()) {
6955 LLT UnpackedTy = LLT::fixed_vector(Ty.getNumElements(), LLT::integer(32));
6956 Register LoadDstReg = B.getMRI()->createGenericVirtualRegister(UnpackedTy);
6957 buildBufferLoad(Opc, LoadDstReg, RSrc, VIndex, VOffset, SOffset, ImmOffset,
6958 Format, AuxiliaryData, MMO, IsTyped, HasVIndex, B);
6959 B.setInsertPt(B.getMBB(), ++B.getInsertPt());
6960 // FIXME: G_TRUNC should work, but legalization currently fails
6961 auto Unmerge = B.buildUnmerge(I32, LoadDstReg);
6963 for (unsigned I = 0, N = Unmerge->getNumOperands() - 1; I != N; ++I)
6964 Repack.push_back(B.buildTrunc(EltTy, Unmerge.getReg(I)).getReg(0));
6965 B.buildMergeLikeInstr(Dst, Repack);
6966 } else {
6967 buildBufferLoad(Opc, Dst, RSrc, VIndex, VOffset, SOffset, ImmOffset, Format,
6968 AuxiliaryData, MMO, IsTyped, HasVIndex, B);
6969 }
6970
6971 MI.eraseFromParent();
6972 return true;
6973}
6974
6975static unsigned getBufferAtomicPseudo(Intrinsic::ID IntrID) {
6976 switch (IntrID) {
6977 case Intrinsic::amdgcn_raw_buffer_atomic_swap:
6978 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_swap:
6979 case Intrinsic::amdgcn_struct_buffer_atomic_swap:
6980 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_swap:
6981 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_SWAP;
6982 case Intrinsic::amdgcn_raw_buffer_atomic_add:
6983 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_add:
6984 case Intrinsic::amdgcn_struct_buffer_atomic_add:
6985 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_add:
6986 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_ADD;
6987 case Intrinsic::amdgcn_raw_buffer_atomic_sub:
6988 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_sub:
6989 case Intrinsic::amdgcn_struct_buffer_atomic_sub:
6990 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_sub:
6991 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_SUB;
6992 case Intrinsic::amdgcn_raw_buffer_atomic_smin:
6993 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_smin:
6994 case Intrinsic::amdgcn_struct_buffer_atomic_smin:
6995 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_smin:
6996 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_SMIN;
6997 case Intrinsic::amdgcn_raw_buffer_atomic_umin:
6998 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_umin:
6999 case Intrinsic::amdgcn_struct_buffer_atomic_umin:
7000 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_umin:
7001 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_UMIN;
7002 case Intrinsic::amdgcn_raw_buffer_atomic_smax:
7003 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_smax:
7004 case Intrinsic::amdgcn_struct_buffer_atomic_smax:
7005 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_smax:
7006 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_SMAX;
7007 case Intrinsic::amdgcn_raw_buffer_atomic_umax:
7008 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_umax:
7009 case Intrinsic::amdgcn_struct_buffer_atomic_umax:
7010 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_umax:
7011 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_UMAX;
7012 case Intrinsic::amdgcn_raw_buffer_atomic_and:
7013 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_and:
7014 case Intrinsic::amdgcn_struct_buffer_atomic_and:
7015 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_and:
7016 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_AND;
7017 case Intrinsic::amdgcn_raw_buffer_atomic_or:
7018 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_or:
7019 case Intrinsic::amdgcn_struct_buffer_atomic_or:
7020 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_or:
7021 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_OR;
7022 case Intrinsic::amdgcn_raw_buffer_atomic_xor:
7023 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_xor:
7024 case Intrinsic::amdgcn_struct_buffer_atomic_xor:
7025 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_xor:
7026 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_XOR;
7027 case Intrinsic::amdgcn_raw_buffer_atomic_inc:
7028 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_inc:
7029 case Intrinsic::amdgcn_struct_buffer_atomic_inc:
7030 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_inc:
7031 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_INC;
7032 case Intrinsic::amdgcn_raw_buffer_atomic_dec:
7033 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_dec:
7034 case Intrinsic::amdgcn_struct_buffer_atomic_dec:
7035 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_dec:
7036 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_DEC;
7037 case Intrinsic::amdgcn_raw_buffer_atomic_cmpswap:
7038 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_cmpswap:
7039 case Intrinsic::amdgcn_struct_buffer_atomic_cmpswap:
7040 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_cmpswap:
7041 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_CMPSWAP;
7042 case Intrinsic::amdgcn_raw_buffer_atomic_fadd:
7043 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_fadd:
7044 case Intrinsic::amdgcn_struct_buffer_atomic_fadd:
7045 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_fadd:
7046 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_FADD;
7047 case Intrinsic::amdgcn_raw_buffer_atomic_fmin:
7048 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_fmin:
7049 case Intrinsic::amdgcn_struct_buffer_atomic_fmin:
7050 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_fmin:
7051 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_FMIN;
7052 case Intrinsic::amdgcn_raw_buffer_atomic_fmax:
7053 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_fmax:
7054 case Intrinsic::amdgcn_struct_buffer_atomic_fmax:
7055 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_fmax:
7056 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_FMAX;
7057 case Intrinsic::amdgcn_raw_buffer_atomic_sub_clamp_u32:
7058 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_sub_clamp_u32:
7059 case Intrinsic::amdgcn_struct_buffer_atomic_sub_clamp_u32:
7060 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_sub_clamp_u32:
7061 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_SUB_CLAMP_U32;
7062 case Intrinsic::amdgcn_raw_buffer_atomic_cond_sub_u32:
7063 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_cond_sub_u32:
7064 case Intrinsic::amdgcn_struct_buffer_atomic_cond_sub_u32:
7065 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_cond_sub_u32:
7066 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_COND_SUB_U32;
7067 default:
7068 llvm_unreachable("unhandled atomic opcode");
7069 }
7070}
7071
7074 Intrinsic::ID IID) const {
7075 const bool IsCmpSwap =
7076 IID == Intrinsic::amdgcn_raw_buffer_atomic_cmpswap ||
7077 IID == Intrinsic::amdgcn_struct_buffer_atomic_cmpswap ||
7078 IID == Intrinsic::amdgcn_raw_ptr_buffer_atomic_cmpswap ||
7079 IID == Intrinsic::amdgcn_struct_ptr_buffer_atomic_cmpswap;
7080
7081 Register Dst = MI.getOperand(0).getReg();
7082 // Since we don't have 128-bit atomics, we don't need to handle the case of
7083 // p8 argmunents to the atomic itself
7084 Register VData = MI.getOperand(2).getReg();
7085
7086 Register CmpVal;
7087 int OpOffset = 0;
7088
7089 if (IsCmpSwap) {
7090 CmpVal = MI.getOperand(3).getReg();
7091 ++OpOffset;
7092 }
7093
7094 castBufferRsrcArgToV4I32(MI, B, 3 + OpOffset);
7095 Register RSrc = MI.getOperand(3 + OpOffset).getReg();
7096 const unsigned NumVIndexOps = IsCmpSwap ? 9 : 8;
7097
7098 // The struct intrinsic variants add one additional operand over raw.
7099 const bool HasVIndex = MI.getNumOperands() == NumVIndexOps;
7100 Register VIndex;
7101 if (HasVIndex) {
7102 VIndex = MI.getOperand(4 + OpOffset).getReg();
7103 ++OpOffset;
7104 } else {
7105 VIndex = B.buildConstant(LLT::integer(32), 0).getReg(0);
7106 }
7107
7108 Register VOffset = MI.getOperand(4 + OpOffset).getReg();
7109 Register SOffset = MI.getOperand(5 + OpOffset).getReg();
7110 unsigned AuxiliaryData = MI.getOperand(6 + OpOffset).getImm();
7111
7112 MachineMemOperand *MMO = *MI.memoperands_begin();
7113
7114 unsigned ImmOffset;
7115 std::tie(VOffset, ImmOffset) = splitBufferOffsets(B, VOffset);
7116
7117 auto MIB = B.buildInstr(getBufferAtomicPseudo(IID))
7118 .addDef(Dst)
7119 .addUse(VData); // vdata
7120
7121 if (IsCmpSwap)
7122 MIB.addReg(CmpVal);
7123
7124 MIB.addUse(RSrc) // rsrc
7125 .addUse(VIndex) // vindex
7126 .addUse(VOffset) // voffset
7127 .addUse(SOffset) // soffset
7128 .addImm(ImmOffset) // offset(imm)
7129 .addImm(AuxiliaryData) // cachepolicy, swizzled buffer(imm)
7130 .addImm(HasVIndex ? -1 : 0) // idxen(imm)
7131 .addMemOperand(MMO);
7132
7133 MI.eraseFromParent();
7134 return true;
7135}
7136
7137/// Turn a set of f16 typed registers in \p AddrRegs into a dword sized
7138/// vector with f16 typed elements.
7140 SmallVectorImpl<Register> &PackedAddrs,
7141 unsigned ArgOffset,
7143 bool IsA16, bool IsG16) {
7144 auto EndIdx = Intr->VAddrEnd;
7145
7146 for (unsigned I = Intr->VAddrStart; I < EndIdx; I++) {
7147 MachineOperand &SrcOp = MI.getOperand(ArgOffset + I);
7148 if (!SrcOp.isReg())
7149 continue; // _L to _LZ may have eliminated this.
7150
7151 Register AddrReg = SrcOp.getReg();
7152
7153 if ((I < Intr->GradientStart) ||
7154 (I >= Intr->GradientStart && I < Intr->CoordStart && !IsG16) ||
7155 (I >= Intr->CoordStart && !IsA16)) {
7156 if ((I < Intr->GradientStart) && IsA16 &&
7157 (B.getMRI()->getType(AddrReg) == F16)) {
7158 assert(I == Intr->BiasIndex && "Got unexpected 16-bit extra argument");
7159 // Special handling of bias when A16 is on. Bias is of type half but
7160 // occupies full 32-bit.
7161 PackedAddrs.push_back(
7162 B.buildBuildVector(V2F16, {AddrReg, B.buildUndef(F16).getReg(0)})
7163 .getReg(0));
7164 } else {
7165 assert((!IsA16 || Intr->NumBiasArgs == 0 || I != Intr->BiasIndex) &&
7166 "Bias needs to be converted to 16 bit in A16 mode");
7167 // Handle any gradient or coordinate operands that should not be packed
7168 AddrReg = B.buildBitcast(V2F16, AddrReg).getReg(0);
7169 PackedAddrs.push_back(AddrReg);
7170 }
7171 } else {
7172 const LLT EltTy = B.getMRI()->getType(AddrReg);
7173 const LLT V2EltTy = LLT::fixed_vector(2, EltTy);
7174 // Dz/dh, dz/dv and the last odd coord are packed with undef. Also, in 1D,
7175 // derivatives dx/dh and dx/dv are packed with undef.
7176 if (((I + 1) >= EndIdx) ||
7177 ((Intr->NumGradients / 2) % 2 == 1 &&
7178 (I == static_cast<unsigned>(Intr->GradientStart +
7179 (Intr->NumGradients / 2) - 1) ||
7180 I == static_cast<unsigned>(Intr->GradientStart +
7181 Intr->NumGradients - 1))) ||
7182 // Check for _L to _LZ optimization
7183 !MI.getOperand(ArgOffset + I + 1).isReg()) {
7184 PackedAddrs.push_back(
7185 B.buildBuildVector(V2EltTy,
7186 {AddrReg, B.buildUndef(EltTy).getReg(0)})
7187 .getReg(0));
7188 } else {
7189 PackedAddrs.push_back(
7190 B.buildBuildVector(
7191 V2EltTy, {AddrReg, MI.getOperand(ArgOffset + I + 1).getReg()})
7192 .getReg(0));
7193 ++I;
7194 }
7195 }
7196 }
7197}
7198
7199/// Convert from separate vaddr components to a single vector address register,
7200/// and replace the remaining operands with $noreg.
7202 int DimIdx, int NumVAddrs) {
7203 SmallVector<Register, 8> AddrRegs;
7204 for (int I = 0; I != NumVAddrs; ++I) {
7205 MachineOperand &SrcOp = MI.getOperand(DimIdx + I);
7206 if (SrcOp.isReg()) {
7208 LLT I32 = LLT::integer(32);
7209 assert(B.getMRI()->getType(Reg).getSizeInBits() == 32);
7210 if (B.getMRI()->getType(Reg) != I32)
7211 Reg = B.buildBitcast(I32, Reg).getReg(0);
7212 AddrRegs.push_back(Reg);
7213 }
7214 }
7215
7216 int NumAddrRegs = AddrRegs.size();
7217 if (NumAddrRegs != 1) {
7218 LLT EltTy = B.getMRI()->getType(AddrRegs[0]);
7219 auto VAddr =
7220 B.buildBuildVector(LLT::fixed_vector(NumAddrRegs, EltTy), AddrRegs);
7221 MI.getOperand(DimIdx).setReg(VAddr.getReg(0));
7222 }
7223
7224 for (int I = 1; I != NumVAddrs; ++I) {
7225 MachineOperand &SrcOp = MI.getOperand(DimIdx + I);
7226 if (SrcOp.isReg())
7227 MI.getOperand(DimIdx + I).setReg(AMDGPU::NoRegister);
7228 }
7229}
7230
7231/// Rewrite image intrinsics to use register layouts expected by the subtarget.
7232///
7233/// Depending on the subtarget, load/store with 16-bit element data need to be
7234/// rewritten to use the low half of 32-bit registers, or directly use a packed
7235/// layout. 16-bit addresses should also sometimes be packed into 32-bit
7236/// registers.
7237///
7238/// We don't want to directly select image instructions just yet, but also want
7239/// to exposes all register repacking to the legalizer/combiners. We also don't
7240/// want a selected instruction entering RegBankSelect. In order to avoid
7241/// defining a multitude of intermediate image instructions, directly hack on
7242/// the intrinsic's arguments. In cases like a16 addresses, this requires
7243/// padding now unnecessary arguments with $noreg.
7246 const AMDGPU::ImageDimIntrinsicInfo *Intr) const {
7247
7248 const MachineFunction &MF = *MI.getMF();
7249 const unsigned NumDefs = MI.getNumExplicitDefs();
7250 const unsigned ArgOffset = NumDefs + 1;
7251 bool IsTFE = NumDefs == 2;
7252 // We are only processing the operands of d16 image operations on subtargets
7253 // that use the unpacked register layout, or need to repack the TFE result.
7254
7255 // TODO: Do we need to guard against already legalized intrinsics?
7256 const AMDGPU::MIMGBaseOpcodeInfo *BaseOpcode =
7258
7259 MachineRegisterInfo *MRI = B.getMRI();
7260 const LLT I32 = LLT::integer(32);
7261 const LLT I16 = LLT::integer(16);
7262 const LLT V2I16 = LLT::fixed_vector(2, I16);
7263
7264 unsigned DMask = 0;
7265 Register VData;
7266 LLT Ty;
7267
7268 if (!BaseOpcode->NoReturn || BaseOpcode->Store) {
7269 VData = MI.getOperand(NumDefs == 0 ? 1 : 0).getReg();
7270 Ty = MRI->getType(VData);
7271 }
7272
7273 const bool IsAtomicPacked16Bit =
7274 (BaseOpcode->BaseOpcode == AMDGPU::IMAGE_ATOMIC_PK_ADD_F16 ||
7275 BaseOpcode->BaseOpcode == AMDGPU::IMAGE_ATOMIC_PK_ADD_BF16);
7276
7277 // Check for 16 bit addresses and pack if true.
7278 LLT GradTy =
7279 MRI->getType(MI.getOperand(ArgOffset + Intr->GradientStart).getReg());
7280 LLT AddrTy =
7281 MRI->getType(MI.getOperand(ArgOffset + Intr->CoordStart).getReg());
7282 const bool GradTyIs16 = GradTy == I16 || GradTy == F16;
7283 const bool AddrTyIs16 = AddrTy == I16 || AddrTy == F16;
7284 const bool DataTyIs16 =
7285 Ty.getScalarType() == I16 || Ty.getScalarType() == F16;
7286 const bool IsG16 =
7287 ST.hasG16() ? (BaseOpcode->Gradients && GradTyIs16) : GradTyIs16;
7288 const bool IsA16 = AddrTyIs16;
7289 const bool IsD16 = !IsAtomicPacked16Bit && DataTyIs16;
7290
7291 int DMaskLanes = 0;
7292 if (!BaseOpcode->Atomic) {
7293 DMask = MI.getOperand(ArgOffset + Intr->DMaskIndex).getImm();
7294 if (BaseOpcode->Gather4) {
7295 DMaskLanes = 4;
7296 } else if (DMask != 0) {
7297 DMaskLanes = llvm::popcount(DMask);
7298 } else if (!IsTFE && !BaseOpcode->Store) {
7299 // If dmask is 0, this is a no-op load. This can be eliminated.
7300 B.buildUndef(MI.getOperand(0));
7301 MI.eraseFromParent();
7302 return true;
7303 }
7304 }
7305
7306 Observer.changingInstr(MI);
7307 scope_exit ChangedInstr([&] { Observer.changedInstr(MI); });
7308
7309 const unsigned StoreOpcode = IsD16 ? AMDGPU::G_AMDGPU_INTRIN_IMAGE_STORE_D16
7310 : AMDGPU::G_AMDGPU_INTRIN_IMAGE_STORE;
7311 const unsigned LoadOpcode = IsD16 ? AMDGPU::G_AMDGPU_INTRIN_IMAGE_LOAD_D16
7312 : AMDGPU::G_AMDGPU_INTRIN_IMAGE_LOAD;
7313 unsigned NewOpcode = LoadOpcode;
7314 if (BaseOpcode->Store)
7315 NewOpcode = StoreOpcode;
7316 else if (BaseOpcode->NoReturn)
7317 NewOpcode = AMDGPU::G_AMDGPU_INTRIN_IMAGE_LOAD_NORET;
7318
7319 // Track that we legalized this
7320 MI.setDesc(B.getTII().get(NewOpcode));
7321
7322 // Expecting to get an error flag since TFC is on - and dmask is 0 Force
7323 // dmask to be at least 1 otherwise the instruction will fail
7324 if (IsTFE && DMask == 0) {
7325 DMask = 0x1;
7326 DMaskLanes = 1;
7327 MI.getOperand(ArgOffset + Intr->DMaskIndex).setImm(DMask);
7328 }
7329
7330 if (BaseOpcode->Atomic) {
7331 Register VData0 = MI.getOperand(2).getReg();
7332 LLT Ty = MRI->getType(VData0);
7333
7334 // TODO: Allow atomic swap and bit ops for v2f16/v4f16
7335 if (Ty.isVector() && !IsAtomicPacked16Bit)
7336 return false;
7337
7338 if (BaseOpcode->AtomicX2) {
7339 Register VData1 = MI.getOperand(3).getReg();
7340 // The two values are packed in one register.
7341 LLT PackedTy = LLT::fixed_vector(2, Ty);
7342 auto Concat = B.buildBuildVector(PackedTy, {VData0, VData1});
7343 MI.getOperand(2).setReg(Concat.getReg(0));
7344 MI.getOperand(3).setReg(AMDGPU::NoRegister);
7345 }
7346 }
7347
7348 unsigned CorrectedNumVAddrs = Intr->NumVAddrs;
7349
7350 // Rewrite the addressing register layout before doing anything else.
7351 if (BaseOpcode->Gradients && !ST.hasG16() && (IsA16 != IsG16)) {
7352 // 16 bit gradients are supported, but are tied to the A16 control
7353 // so both gradients and addresses must be 16 bit
7354 return false;
7355 }
7356
7357 if (IsA16 && !ST.hasA16()) {
7358 // A16 not supported
7359 return false;
7360 }
7361
7362 const unsigned NSAMaxSize = ST.getNSAMaxSize(BaseOpcode->Sampler);
7363 const unsigned HasPartialNSA = ST.hasPartialNSAEncoding();
7364
7365 if (IsA16 || IsG16) {
7366 // Even if NumVAddrs == 1 we should pack it into a 32-bit value, because the
7367 // instructions expect VGPR_32
7368 SmallVector<Register, 4> PackedRegs;
7369
7370 packImage16bitOpsToDwords(B, MI, PackedRegs, ArgOffset, Intr, IsA16, IsG16);
7371
7372 // See also below in the non-a16 branch
7373 const bool UseNSA = ST.hasNSAEncoding() &&
7374 PackedRegs.size() >= ST.getNSAThreshold(MF) &&
7375 (PackedRegs.size() <= NSAMaxSize || HasPartialNSA);
7376 const bool UsePartialNSA =
7377 UseNSA && HasPartialNSA && PackedRegs.size() > NSAMaxSize;
7378
7379 if (UsePartialNSA) {
7380 // Pack registers that would go over NSAMaxSize into last VAddr register
7381 LLT PackedAddrTy =
7382 LLT::fixed_vector(2 * (PackedRegs.size() - NSAMaxSize + 1), F16);
7383 auto Concat = B.buildConcatVectors(
7384 PackedAddrTy, ArrayRef(PackedRegs).slice(NSAMaxSize - 1));
7385 PackedRegs[NSAMaxSize - 1] = Concat.getReg(0);
7386 PackedRegs.resize(NSAMaxSize);
7387 } else if (!UseNSA && PackedRegs.size() > 1) {
7388 LLT PackedAddrTy = LLT::fixed_vector(2 * PackedRegs.size(), F16);
7389 auto Concat = B.buildConcatVectors(PackedAddrTy, PackedRegs);
7390 PackedRegs[0] = Concat.getReg(0);
7391 PackedRegs.resize(1);
7392 }
7393
7394 const unsigned NumPacked = PackedRegs.size();
7395 for (unsigned I = Intr->VAddrStart; I < Intr->VAddrEnd; I++) {
7396 MachineOperand &SrcOp = MI.getOperand(ArgOffset + I);
7397 if (!SrcOp.isReg()) {
7398 assert(SrcOp.isImm() && SrcOp.getImm() == 0);
7399 continue;
7400 }
7401
7402 assert(SrcOp.getReg() != AMDGPU::NoRegister);
7403
7404 if (I - Intr->VAddrStart < NumPacked)
7405 SrcOp.setReg(PackedRegs[I - Intr->VAddrStart]);
7406 else
7407 SrcOp.setReg(AMDGPU::NoRegister);
7408 }
7409 } else {
7410 // If the register allocator cannot place the address registers contiguously
7411 // without introducing moves, then using the non-sequential address encoding
7412 // is always preferable, since it saves VALU instructions and is usually a
7413 // wash in terms of code size or even better.
7414 //
7415 // However, we currently have no way of hinting to the register allocator
7416 // that MIMG addresses should be placed contiguously when it is possible to
7417 // do so, so force non-NSA for the common 2-address case as a heuristic.
7418 //
7419 // SIShrinkInstructions will convert NSA encodings to non-NSA after register
7420 // allocation when possible.
7421 //
7422 // Partial NSA is allowed on GFX11+ where the final register is a contiguous
7423 // set of the remaining addresses.
7424 const bool UseNSA = ST.hasNSAEncoding() &&
7425 CorrectedNumVAddrs >= ST.getNSAThreshold(MF) &&
7426 (CorrectedNumVAddrs <= NSAMaxSize || HasPartialNSA);
7427 const bool UsePartialNSA =
7428 UseNSA && HasPartialNSA && CorrectedNumVAddrs > NSAMaxSize;
7429
7430 if (UsePartialNSA) {
7432 ArgOffset + Intr->VAddrStart + NSAMaxSize - 1,
7433 Intr->NumVAddrs - NSAMaxSize + 1);
7434 } else if (!UseNSA && Intr->NumVAddrs > 1) {
7435 convertImageAddrToPacked(B, MI, ArgOffset + Intr->VAddrStart,
7436 Intr->NumVAddrs);
7437 }
7438 }
7439
7440 int Flags = 0;
7441 if (IsA16)
7442 Flags |= 1;
7443 if (IsG16)
7444 Flags |= 2;
7445 MI.addOperand(MachineOperand::CreateImm(Flags));
7446
7447 if (BaseOpcode->NoReturn) { // No TFE for stores?
7448 // TODO: Handle dmask trim
7449 if (!Ty.isVector() || !IsD16)
7450 return true;
7451
7452 Register RepackedReg = handleD16VData(B, *MRI, VData, true);
7453 if (RepackedReg != VData) {
7454 MI.getOperand(1).setReg(RepackedReg);
7455 }
7456
7457 return true;
7458 }
7459
7460 Register DstReg = MI.getOperand(0).getReg();
7461 const LLT EltTy = Ty.getScalarType();
7462 const int NumElts = Ty.isVector() ? Ty.getNumElements() : 1;
7463
7464 // Confirm that the return type is large enough for the dmask specified
7465 if (NumElts < DMaskLanes)
7466 return false;
7467
7468 if (NumElts > 4 || DMaskLanes > 4)
7469 return false;
7470
7471 // Image atomic instructions are using DMask to specify how many bits
7472 // input/output data will have. 32-bits (i32, f32, v2f16) or 64-bits (i64,
7473 // f64, v4f16).
7474 // DMaskLanes for image atomic has default value '0'.
7475 // We must be sure that atomic variants (especially packed) will not be
7476 // truncated from v2f16 or v4f16 to f16 type.
7477 //
7478 // ChangeElementCount will be needed for image load where Ty is always scalar.
7479 const unsigned AdjustedNumElts = DMaskLanes == 0 ? 1 : DMaskLanes;
7480 const LLT AdjustedTy =
7481 DMaskLanes == 0
7482 ? Ty
7483 : Ty.changeElementCount(ElementCount::getFixed(AdjustedNumElts));
7484
7485 // The raw dword aligned data component of the load. The only legal cases
7486 // where this matters should be when using the packed D16 format, for
7487 // f16 -> <2 x f16>, and <3 x f16> -> <4 x f16>,
7488 LLT RoundedTy;
7489
7490 // I32 vector to cover all data, plus TFE result element.
7491 LLT TFETy;
7492
7493 // Register type to use for each loaded component. Will be I32 or V2I16.
7494 LLT RegTy;
7495
7496 if (IsD16 && ST.hasUnpackedD16VMem()) {
7497 RoundedTy =
7498 LLT::scalarOrVector(ElementCount::getFixed(AdjustedNumElts), I32);
7499 TFETy = LLT::fixed_vector(AdjustedNumElts + 1, I32);
7500 RegTy = I32;
7501 } else {
7502 unsigned EltSize = EltTy.getSizeInBits();
7503 unsigned RoundedElts = (AdjustedTy.getSizeInBits() + 31) / 32;
7504 unsigned RoundedSize = 32 * RoundedElts;
7505 RoundedTy = LLT::scalarOrVector(
7506 ElementCount::getFixed(RoundedSize / EltSize), EltTy);
7507 TFETy = LLT::fixed_vector(RoundedSize / 32 + 1, I32);
7508 RegTy = !IsTFE && EltSize == 16 ? V2I16 : I32;
7509 }
7510
7511 // The return type does not need adjustment.
7512 // TODO: Should we change f16 case to i32 or <2 x f16>?
7513 if (!IsTFE && (RoundedTy == Ty || !Ty.isVector()))
7514 return true;
7515
7516 Register Dst1Reg;
7517
7518 // Insert after the instruction.
7519 B.setInsertPt(*MI.getParent(), ++MI.getIterator());
7520
7521 // TODO: For TFE with d16, if we used a TFE type that was a multiple of <2 x
7522 // f16> instead of i32, we would only need 1 bitcast instead of multiple.
7523 const LLT LoadResultTy = IsTFE ? TFETy : RoundedTy;
7524 const int ResultNumRegs = LoadResultTy.getSizeInBits() / 32;
7525
7526 Register NewResultReg = MRI->createGenericVirtualRegister(LoadResultTy);
7527
7528 MI.getOperand(0).setReg(NewResultReg);
7529
7530 // In the IR, TFE is supposed to be used with a 2 element struct return
7531 // type. The instruction really returns these two values in one contiguous
7532 // register, with one additional dword beyond the loaded data. Rewrite the
7533 // return type to use a single register result.
7534
7535 if (IsTFE) {
7536 Dst1Reg = MI.getOperand(1).getReg();
7537 if (MRI->getType(Dst1Reg) != I32)
7538 return false;
7539
7540 // TODO: Make sure the TFE operand bit is set.
7541 MI.removeOperand(1);
7542
7543 // Handle the easy case that requires no repack instructions.
7544 if (!Ty.isVector() && Ty.getSizeInBits() == 32) {
7545 auto Unmerge = B.buildUnmerge({I32, I32}, NewResultReg);
7546 B.buildBitcast(DstReg, Unmerge.getReg(0));
7547 B.buildCopy(Dst1Reg, Unmerge.getReg(1));
7548 return true;
7549 }
7550 }
7551
7552 // Now figure out how to copy the new result register back into the old
7553 // result.
7554 SmallVector<Register, 5> ResultRegs(ResultNumRegs, Dst1Reg);
7555
7556 const int NumDataRegs = IsTFE ? ResultNumRegs - 1 : ResultNumRegs;
7557
7558 if (ResultNumRegs == 1) {
7559 assert(!IsTFE);
7560 ResultRegs[0] = NewResultReg;
7561 } else {
7562 // We have to repack into a new vector of some kind.
7563 for (int I = 0; I != NumDataRegs; ++I)
7564 ResultRegs[I] = MRI->createGenericVirtualRegister(RegTy);
7565 B.buildUnmerge(ResultRegs, NewResultReg);
7566
7567 // Drop the final TFE element to get the data part. The TFE result is
7568 // directly written to the right place already.
7569 if (IsTFE)
7570 ResultRegs.resize(NumDataRegs);
7571 }
7572
7573 // For an f16 scalar result, we form an i32 result with a truncate regardless
7574 // of packed vs. unpacked.
7575 if (IsD16 && !Ty.isVector()) {
7576 B.buildTrunc(DstReg, ResultRegs[0]);
7577 return true;
7578 }
7579
7580 // Avoid a build/concat_vector of 1 entry.
7581 if ((Ty == V2I16 || Ty == V2F16) && NumDataRegs == 1 &&
7582 !ST.hasUnpackedD16VMem()) {
7583 B.buildBitcast(DstReg, ResultRegs[0]);
7584 return true;
7585 }
7586
7587 assert(Ty.isVector());
7588
7589 if (IsD16) {
7590 // For packed D16 results with TFE enabled, all the data components are
7591 // I32. Cast back to the expected type.
7592 //
7593 // TODO: We don't really need to use load i32 elements. We would only need
7594 // one cast for the TFE result if a multiple of v2f16 was used.
7595 if (RegTy != V2I16 && !ST.hasUnpackedD16VMem()) {
7596 for (Register &Reg : ResultRegs)
7597 Reg = B.buildBitcast(V2I16, Reg).getReg(0);
7598 } else if (ST.hasUnpackedD16VMem()) {
7599 for (Register &Reg : ResultRegs)
7600 Reg = B.buildTrunc(I16, Reg).getReg(0);
7601 }
7602 }
7603
7604 auto padWithUndef = [&](LLT Ty, int NumElts) {
7605 if (NumElts == 0)
7606 return;
7607 Register Undef = B.buildUndef(Ty).getReg(0);
7608 for (int I = 0; I != NumElts; ++I)
7609 ResultRegs.push_back(Undef);
7610 };
7611
7612 // Pad out any elements eliminated due to the dmask.
7613 LLT ResTy = MRI->getType(ResultRegs[0]);
7614 if (!ResTy.isVector()) {
7615 padWithUndef(ResTy, NumElts - ResultRegs.size());
7616 B.buildBuildVector(DstReg, ResultRegs);
7617 return true;
7618 }
7619
7620 assert(!ST.hasUnpackedD16VMem() && (ResTy == V2I16 || ResTy == V2F16));
7621 const int RegsToCover = (Ty.getSizeInBits() + 31) / 32;
7622
7623 // Deal with the one annoying legal case.
7624 const LLT V3I16 = LLT::fixed_vector(3, I16);
7625 const LLT V3F16 = LLT::fixed_vector(3, F16);
7626 if (Ty == V3I16 || Ty == V3F16) {
7627 if (IsTFE) {
7628 if (ResultRegs.size() == 1) {
7629 NewResultReg = ResultRegs[0];
7630 } else if (ResultRegs.size() == 2) {
7631 LLT V4I16 = LLT::fixed_vector(4, I16);
7632 NewResultReg = B.buildConcatVectors(V4I16, ResultRegs).getReg(0);
7633 } else {
7634 return false;
7635 }
7636 }
7637
7638 LLT DstTy = MRI->getType(DstReg);
7639 LLT NewResTy = MRI->getType(NewResultReg);
7640 LLT ResEltTy = NewResTy.getElementType();
7641 Register ResizeDst = DstTy.getElementType() == ResEltTy
7642 ? DstReg
7644 DstTy.changeElementType(ResEltTy));
7645
7646 if (DstTy.getNumElements() < NewResTy.getNumElements()) {
7647 B.buildDeleteTrailingVectorElements(ResizeDst, NewResultReg);
7648 } else {
7649 B.buildPadVectorWithUndefElements(ResizeDst, NewResultReg);
7650 }
7651 if (ResizeDst != DstReg)
7652 B.buildBitcast(DstReg, ResizeDst);
7653 return true;
7654 }
7655
7656 padWithUndef(ResTy, RegsToCover - ResultRegs.size());
7657 B.buildConcatVectors(DstReg, ResultRegs);
7658 return true;
7659}
7660
7662 MachineInstr &MI) const {
7663 MachineIRBuilder &B = Helper.MIRBuilder;
7664 GISelChangeObserver &Observer = Helper.Observer;
7665
7666 Register OrigDst = MI.getOperand(0).getReg();
7667 Register Dst;
7668 LLT Ty = B.getMRI()->getType(OrigDst);
7669 unsigned Size = Ty.getSizeInBits();
7670 MachineFunction &MF = B.getMF();
7671 bool HasMMO = !MI.memoperands_empty();
7672 unsigned Opc = 0;
7673 if (Size < 32 && ST.hasScalarSubwordLoads()) {
7674 assert(Size == 8 || Size == 16);
7675 Opc = Size == 8 ? AMDGPU::G_AMDGPU_S_BUFFER_LOAD_UBYTE
7676 : AMDGPU::G_AMDGPU_S_BUFFER_LOAD_USHORT;
7677 // The 8-bit and 16-bit scalar buffer load instructions have 32-bit
7678 // destination register.
7679 Dst = B.getMRI()->createGenericVirtualRegister(LLT::integer(32));
7680 } else {
7681 Opc = AMDGPU::G_AMDGPU_S_BUFFER_LOAD;
7682 Dst = OrigDst;
7683 }
7684
7685 Observer.changingInstr(MI);
7686
7687 // Handle needing to s.buffer.load() a p8 value.
7688 if (hasBufferRsrcWorkaround(Ty)) {
7689 Ty = castBufferRsrcFromV4I32(MI, B, *B.getMRI(), 0);
7690 B.setInsertPt(B.getMBB(), MI);
7691 }
7693 Ty = getBitcastRegisterType(Ty);
7694 Helper.bitcastDst(MI, Ty, 0);
7695 B.setInsertPt(B.getMBB(), MI);
7696 }
7697
7698 MI.setDesc(B.getTII().get(Opc));
7699 MI.removeOperand(1);
7701
7702 if (!HasMMO) {
7703 // Legacy intrinsic that doesn't take a pointer and so can't already have an
7704 // MMO.
7705 const unsigned MemSize = (Size + 7) / 8;
7706 const Align MemAlign = B.getDataLayout().getABITypeAlign(
7712 MemSize, MemAlign);
7713 MI.addMemOperand(MF, MMO);
7714 }
7715 if (Dst != OrigDst) {
7716 MI.getOperand(0).setReg(Dst);
7717 B.setInsertPt(B.getMBB(), ++B.getInsertPt());
7718 B.buildTrunc(OrigDst, Dst);
7719 }
7720
7721 // If we don't have 96-bit result scalar loads, widening to 128-bit should
7722 // always be legal. We may need to restore this to a 96-bit result if it turns
7723 // out this needs to be converted to a vector load during RegBankSelect.
7724 if (!isPowerOf2_32(Size) && (Size != 96 || !ST.hasScalarDwordx3Loads())) {
7725 if (Ty.isVector())
7727 else
7728 Helper.widenScalarDst(MI, getPow2ScalarType(Ty), 0);
7729 }
7730
7731 Observer.changedInstr(MI);
7732 return true;
7733}
7734
7736 MachineInstr &MI) const {
7737 MachineIRBuilder &B = Helper.MIRBuilder;
7738 GISelChangeObserver &Observer = Helper.Observer;
7739 Observer.changingInstr(MI);
7740 MI.setDesc(B.getTII().get(AMDGPU::G_AMDGPU_S_BUFFER_PREFETCH));
7741 MI.removeOperand(0); // Remove intrinsic ID
7743 Observer.changedInstr(MI);
7744 return true;
7745}
7746
7747// TODO: Move to selection
7750 MachineIRBuilder &B) const {
7751 if (!ST.hasTrapHandler() ||
7752 ST.getTrapHandlerAbi() != GCNSubtarget::TrapHandlerAbi::AMDHSA)
7753 return legalizeTrapEndpgm(MI, MRI, B);
7754
7755 return ST.supportsGetDoorbellID() ?
7757}
7758
7761 const DebugLoc &DL = MI.getDebugLoc();
7762 MachineBasicBlock &BB = B.getMBB();
7763 MachineFunction *MF = BB.getParent();
7764
7765 if (BB.succ_empty() && std::next(MI.getIterator()) == BB.end()) {
7766 BuildMI(BB, BB.end(), DL, B.getTII().get(AMDGPU::S_ENDPGM))
7767 .addImm(0);
7768 MI.eraseFromParent();
7769 return true;
7770 }
7771
7772 // We need a block split to make the real endpgm a terminator. We also don't
7773 // want to break phis in successor blocks, so we can't just delete to the
7774 // end of the block.
7775 BB.splitAt(MI, false /*UpdateLiveIns*/);
7777 MF->push_back(TrapBB);
7778 BuildMI(*TrapBB, TrapBB->end(), DL, B.getTII().get(AMDGPU::S_ENDPGM))
7779 .addImm(0);
7780 BuildMI(BB, &MI, DL, B.getTII().get(AMDGPU::S_CBRANCH_EXECNZ))
7781 .addMBB(TrapBB);
7782
7783 BB.addSuccessor(TrapBB);
7784 MI.eraseFromParent();
7785 return true;
7786}
7787
7790 MachineFunction &MF = B.getMF();
7791 const LLT I64 = LLT::integer(64);
7792
7793 Register SGPR01(AMDGPU::SGPR0_SGPR1);
7794 // For code object version 5, queue_ptr is passed through implicit kernarg.
7799 uint64_t Offset =
7800 ST.getTargetLowering()->getImplicitParameterOffset(B.getMF(), Param);
7801
7802 Register KernargPtrReg = MRI.createGenericVirtualRegister(
7804
7805 if (!loadInputValue(KernargPtrReg, B,
7807 return false;
7808
7809 // TODO: can we be smarter about machine pointer info?
7812 PtrInfo.getWithOffset(Offset),
7816
7817 // Pointer address
7820 B.buildObjectPtrOffset(LoadAddr, KernargPtrReg,
7821 B.buildConstant(LLT::integer(64), Offset).getReg(0));
7822 // Load address
7823 Register Temp = B.buildLoad(I64, LoadAddr, *MMO).getReg(0);
7824 B.buildCopy(SGPR01, Temp);
7825 B.buildInstr(AMDGPU::S_TRAP)
7826 .addImm(static_cast<unsigned>(GCNSubtarget::TrapID::LLVMAMDHSATrap))
7827 .addReg(SGPR01, RegState::Implicit);
7828 MI.eraseFromParent();
7829 return true;
7830 }
7831
7832 // Pass queue pointer to trap handler as input, and insert trap instruction
7833 // Reference: https://llvm.org/docs/AMDGPUUsage.html#trap-handler-abi
7834 Register LiveIn =
7837 return false;
7838
7839 B.buildCopy(SGPR01, LiveIn);
7840 B.buildInstr(AMDGPU::S_TRAP)
7841 .addImm(static_cast<unsigned>(GCNSubtarget::TrapID::LLVMAMDHSATrap))
7842 .addReg(SGPR01, RegState::Implicit);
7843
7844 MI.eraseFromParent();
7845 return true;
7846}
7847
7850 MachineIRBuilder &B) const {
7851 // We need to simulate the 's_trap 2' instruction on targets that run in
7852 // PRIV=1 (where it is treated as a nop).
7853 if (ST.hasPrivEnabledTrap2NopBug()) {
7854 ST.getInstrInfo()->insertSimulatedTrap(MRI, B.getMBB(), MI,
7855 MI.getDebugLoc());
7856 MI.eraseFromParent();
7857 return true;
7858 }
7859
7860 B.buildInstr(AMDGPU::S_TRAP)
7861 .addImm(static_cast<unsigned>(GCNSubtarget::TrapID::LLVMAMDHSATrap));
7862 MI.eraseFromParent();
7863 return true;
7864}
7865
7868 MachineIRBuilder &B) const {
7869 // Is non-HSA path or trap-handler disabled? Then, report a warning
7870 // accordingly
7871 if (!ST.hasTrapHandler() ||
7872 ST.getTrapHandlerAbi() != GCNSubtarget::TrapHandlerAbi::AMDHSA) {
7873 Function &Fn = B.getMF().getFunction();
7875 Fn, "debugtrap handler not supported", MI.getDebugLoc(), DS_Warning));
7876 } else {
7877 // Insert debug-trap instruction
7878 B.buildInstr(AMDGPU::S_TRAP)
7879 .addImm(static_cast<unsigned>(GCNSubtarget::TrapID::LLVMAMDHSADebugTrap));
7880 }
7881
7882 MI.eraseFromParent();
7883 return true;
7884}
7885
7887 MachineInstr &MI, MachineIRBuilder &B) const {
7888 MachineRegisterInfo &MRI = *B.getMRI();
7889 const LLT I16 = LLT::integer(16);
7890 const LLT I32 = LLT::integer(32);
7891 const LLT V2I16 = LLT::fixed_vector(2, I16);
7892 const LLT V3I32 = LLT::fixed_vector(3, I32);
7893 const LLT V3I16 = LLT::fixed_vector(3, I16);
7894
7895 Register DstReg = MI.getOperand(0).getReg();
7896 Register NodePtr = MI.getOperand(2).getReg();
7897 Register RayExtent = MI.getOperand(3).getReg();
7898 Register RayOrigin = MI.getOperand(4).getReg();
7899 Register RayDir = MI.getOperand(5).getReg();
7900 Register RayInvDir = MI.getOperand(6).getReg();
7901 Register TDescr = MI.getOperand(7).getReg();
7902
7903 RayExtent = B.buildBitcast(I32, RayExtent).getReg(0);
7904
7905 const bool IsGFX11 = AMDGPU::isGFX11(ST);
7906 const bool IsGFX11Plus = AMDGPU::isGFX11Plus(ST);
7907 const bool IsGFX12Plus = AMDGPU::isGFX12Plus(ST);
7908 const bool IsA16 = MRI.getType(RayDir).getElementType().getSizeInBits() == 16;
7909 const bool Is64 = MRI.getType(NodePtr).getSizeInBits() == 64;
7910 const unsigned NumVDataDwords = 4;
7911 const unsigned NumVAddrDwords = IsA16 ? (Is64 ? 9 : 8) : (Is64 ? 12 : 11);
7912 const unsigned NumVAddrs = IsGFX11Plus ? (IsA16 ? 4 : 5) : NumVAddrDwords;
7913 const bool UseNSA =
7914 IsGFX12Plus || (ST.hasNSAEncoding() && NumVAddrs <= ST.getNSAMaxSize());
7915
7916 const unsigned BaseOpcodes[2][2] = {
7917 {AMDGPU::IMAGE_BVH_INTERSECT_RAY, AMDGPU::IMAGE_BVH_INTERSECT_RAY_a16},
7918 {AMDGPU::IMAGE_BVH64_INTERSECT_RAY,
7919 AMDGPU::IMAGE_BVH64_INTERSECT_RAY_a16}};
7920 int Opcode;
7921 if (UseNSA) {
7922 Opcode = AMDGPU::getMIMGOpcode(BaseOpcodes[Is64][IsA16],
7923 IsGFX12Plus ? AMDGPU::MIMGEncGfx12
7924 : IsGFX11 ? AMDGPU::MIMGEncGfx11NSA
7925 : AMDGPU::MIMGEncGfx10NSA,
7926 NumVDataDwords, NumVAddrDwords);
7927 } else {
7928 assert(!IsGFX12Plus);
7929 Opcode = AMDGPU::getMIMGOpcode(BaseOpcodes[Is64][IsA16],
7930 IsGFX11 ? AMDGPU::MIMGEncGfx11Default
7931 : AMDGPU::MIMGEncGfx10Default,
7932 NumVDataDwords, NumVAddrDwords);
7933 }
7934 assert(Opcode != -1);
7935
7937 if (UseNSA && IsGFX11Plus) {
7938 auto packLanes = [&Ops, &I32, &V3I32, &B](Register Src) {
7939 auto SrcInt = B.buildBitcast(V3I32, Src);
7940 auto Unmerge = B.buildUnmerge({I32, I32, I32}, SrcInt);
7941 auto Merged = B.buildMergeLikeInstr(
7942 V3I32, {Unmerge.getReg(0), Unmerge.getReg(1), Unmerge.getReg(2)});
7943 Ops.push_back(Merged.getReg(0));
7944 };
7945
7946 Ops.push_back(NodePtr);
7947 Ops.push_back(RayExtent);
7948 packLanes(RayOrigin);
7949
7950 if (IsA16) {
7951 auto UnmergeRayDir =
7952 B.buildUnmerge({I16, I16, I16}, B.buildBitcast(V3I16, RayDir));
7953 auto UnmergeRayInvDir =
7954 B.buildUnmerge({I16, I16, I16}, B.buildBitcast(V3I16, RayInvDir));
7955 auto MergedDir = B.buildMergeLikeInstr(
7956 V3I32,
7957 {B.buildBitcast(
7958 I32, B.buildMergeLikeInstr(V2I16, {UnmergeRayInvDir.getReg(0),
7959 UnmergeRayDir.getReg(0)}))
7960 .getReg(0),
7961 B.buildBitcast(
7962 I32, B.buildMergeLikeInstr(V2I16, {UnmergeRayInvDir.getReg(1),
7963 UnmergeRayDir.getReg(1)}))
7964 .getReg(0),
7965 B.buildBitcast(
7966 I32, B.buildMergeLikeInstr(V2I16, {UnmergeRayInvDir.getReg(2),
7967 UnmergeRayDir.getReg(2)}))
7968 .getReg(0)});
7969 Ops.push_back(MergedDir.getReg(0));
7970 } else {
7971 packLanes(RayDir);
7972 packLanes(RayInvDir);
7973 }
7974 } else {
7975 if (Is64) {
7976 auto Unmerge = B.buildUnmerge({I32, I32}, NodePtr);
7977 Ops.push_back(Unmerge.getReg(0));
7978 Ops.push_back(Unmerge.getReg(1));
7979 } else {
7980 Ops.push_back(NodePtr);
7981 }
7982 Ops.push_back(RayExtent);
7983
7984 auto packLanes = [&Ops, &I32, &V3I32, &B](Register Src) {
7985 auto SrcInt = B.buildBitcast(V3I32, Src);
7986 auto Unmerge = B.buildUnmerge({I32, I32, I32}, SrcInt);
7987 Ops.push_back(Unmerge.getReg(0));
7988 Ops.push_back(Unmerge.getReg(1));
7989 Ops.push_back(Unmerge.getReg(2));
7990 };
7991
7992 packLanes(RayOrigin);
7993 if (IsA16) {
7994 auto UnmergeRayDir =
7995 B.buildUnmerge({I16, I16, I16}, B.buildBitcast(V3I16, RayDir));
7996 auto UnmergeRayInvDir =
7997 B.buildUnmerge({I16, I16, I16}, B.buildBitcast(V3I16, RayInvDir));
8001 B.buildMergeLikeInstr(R1,
8002 {UnmergeRayDir.getReg(0), UnmergeRayDir.getReg(1)});
8003 B.buildMergeLikeInstr(
8004 R2, {UnmergeRayDir.getReg(2), UnmergeRayInvDir.getReg(0)});
8005 B.buildMergeLikeInstr(
8006 R3, {UnmergeRayInvDir.getReg(1), UnmergeRayInvDir.getReg(2)});
8007 Ops.push_back(R1);
8008 Ops.push_back(R2);
8009 Ops.push_back(R3);
8010 } else {
8011 packLanes(RayDir);
8012 packLanes(RayInvDir);
8013 }
8014 }
8015
8016 if (!UseNSA) {
8017 // Build a single vector containing all the operands so far prepared.
8018 LLT OpTy = LLT::fixed_vector(Ops.size(), I32);
8019 Register MergedOps = B.buildMergeLikeInstr(OpTy, Ops).getReg(0);
8020 Ops.clear();
8021 Ops.push_back(MergedOps);
8022 }
8023
8024 auto MIB = B.buildInstr(AMDGPU::G_AMDGPU_BVH_INTERSECT_RAY)
8025 .addDef(DstReg)
8026 .addImm(Opcode);
8027
8028 for (Register R : Ops) {
8029 MIB.addUse(R);
8030 }
8031
8032 MIB.addUse(TDescr)
8033 .addImm(IsA16 ? 1 : 0)
8034 .cloneMemRefs(MI);
8035
8036 MI.eraseFromParent();
8037 return true;
8038}
8039
8041 MachineInstr &MI, MachineIRBuilder &B) const {
8042 const LLT I32 = LLT::integer(32);
8043 const LLT V2I32 = LLT::fixed_vector(2, I32);
8044
8045 Register DstReg = MI.getOperand(0).getReg();
8046 Register DstOrigin = MI.getOperand(1).getReg();
8047 Register DstDir = MI.getOperand(2).getReg();
8048 Register NodePtr = MI.getOperand(4).getReg();
8049 Register RayExtent = MI.getOperand(5).getReg();
8050 Register InstanceMask = MI.getOperand(6).getReg();
8051 Register RayOrigin = MI.getOperand(7).getReg();
8052 Register RayDir = MI.getOperand(8).getReg();
8053 Register Offsets = MI.getOperand(9).getReg();
8054 Register TDescr = MI.getOperand(10).getReg();
8055
8056 bool IsBVH8 = cast<GIntrinsic>(MI).getIntrinsicID() ==
8057 Intrinsic::amdgcn_image_bvh8_intersect_ray;
8058 const unsigned NumVDataDwords = 10;
8059 const unsigned NumVAddrDwords = IsBVH8 ? 11 : 12;
8060 int Opcode = AMDGPU::getMIMGOpcode(
8061 IsBVH8 ? AMDGPU::IMAGE_BVH8_INTERSECT_RAY
8062 : AMDGPU::IMAGE_BVH_DUAL_INTERSECT_RAY,
8063 AMDGPU::MIMGEncGfx12, NumVDataDwords, NumVAddrDwords);
8064 assert(Opcode != -1);
8065
8066 auto RayExtentInstanceMaskVec =
8067 B.buildMergeLikeInstr(V2I32, {B.buildBitcast(I32, RayExtent),
8068 B.buildAnyExt(I32, InstanceMask)});
8069
8070 B.buildInstr(IsBVH8 ? AMDGPU::G_AMDGPU_BVH8_INTERSECT_RAY
8071 : AMDGPU::G_AMDGPU_BVH_DUAL_INTERSECT_RAY)
8072 .addDef(DstReg)
8073 .addDef(DstOrigin)
8074 .addDef(DstDir)
8075 .addImm(Opcode)
8076 .addUse(NodePtr)
8077 .addUse(RayExtentInstanceMaskVec.getReg(0))
8078 .addUse(RayOrigin)
8079 .addUse(RayDir)
8080 .addUse(Offsets)
8081 .addUse(TDescr)
8082 .cloneMemRefs(MI);
8083
8084 MI.eraseFromParent();
8085 return true;
8086}
8087
8089 MachineIRBuilder &B) const {
8090 const SITargetLowering *TLI = ST.getTargetLowering();
8092 Register DstReg = MI.getOperand(0).getReg();
8093 B.buildInstr(AMDGPU::G_AMDGPU_WAVE_ADDRESS, {DstReg}, {StackPtr});
8094 MI.eraseFromParent();
8095 return true;
8096}
8097
8099 MachineIRBuilder &B) const {
8100 // With architected SGPRs, waveIDinGroup is in TTMP8[29:25].
8101 if (!ST.hasArchitectedSGPRs())
8102 return false;
8103 LLT I32 = LLT::integer(32);
8104 Register DstReg = MI.getOperand(0).getReg();
8105 auto TTMP8 = B.buildCopy(I32, Register(AMDGPU::TTMP8));
8106 auto LSB = B.buildConstant(I32, 25);
8107 auto Width = B.buildConstant(I32, 5);
8108 B.buildUbfx(DstReg, TTMP8, LSB, Width);
8109 MI.eraseFromParent();
8110 return true;
8111}
8112
8115 AMDGPU::Hwreg::Id HwReg,
8116 unsigned LowBit,
8117 unsigned Width) const {
8118 MachineRegisterInfo &MRI = *B.getMRI();
8119 Register DstReg = MI.getOperand(0).getReg();
8120 if (!MRI.getRegClassOrNull(DstReg))
8121 MRI.setRegClass(DstReg, &AMDGPU::SReg_32RegClass);
8122 B.buildInstr(AMDGPU::S_GETREG_B32_const)
8123 .addDef(DstReg)
8124 .addImm(AMDGPU::Hwreg::HwregEncoding::encode(HwReg, LowBit, Width));
8125 MI.eraseFromParent();
8126 return true;
8127}
8128
8129static constexpr unsigned FPEnvModeBitField =
8131
8132static constexpr unsigned FPEnvTrapBitField =
8134
8137 MachineIRBuilder &B) const {
8138 const LLT I32 = LLT::integer(32);
8139 const LLT I64 = LLT::integer(64);
8140 Register Src = MI.getOperand(0).getReg();
8141 if (MRI.getType(Src) != I64)
8142 return false;
8143
8144 auto ModeReg =
8145 B.buildIntrinsic(Intrinsic::amdgcn_s_getreg, {I32},
8146 /*HasSideEffects=*/true, /*isConvergent=*/false)
8147 .addImm(FPEnvModeBitField);
8148 auto TrapReg =
8149 B.buildIntrinsic(Intrinsic::amdgcn_s_getreg, {I32},
8150 /*HasSideEffects=*/true, /*isConvergent=*/false)
8151 .addImm(FPEnvTrapBitField);
8152 B.buildMergeLikeInstr(Src, {ModeReg, TrapReg});
8153 MI.eraseFromParent();
8154 return true;
8155}
8156
8159 MachineIRBuilder &B) const {
8160 const LLT I32 = LLT::integer(32);
8161 const LLT I64 = LLT::integer(64);
8162 Register Src = MI.getOperand(0).getReg();
8163 if (MRI.getType(Src) != I64)
8164 return false;
8165
8166 auto Unmerge = B.buildUnmerge({I32, I32}, MI.getOperand(0));
8167 B.buildIntrinsic(Intrinsic::amdgcn_s_setreg, ArrayRef<DstOp>(),
8168 /*HasSideEffects=*/true, /*isConvergent=*/false)
8169 .addImm(static_cast<int16_t>(FPEnvModeBitField))
8170 .addReg(Unmerge.getReg(0));
8171 B.buildIntrinsic(Intrinsic::amdgcn_s_setreg, ArrayRef<DstOp>(),
8172 /*HasSideEffects=*/true, /*isConvergent=*/false)
8173 .addImm(static_cast<int16_t>(FPEnvTrapBitField))
8174 .addReg(Unmerge.getReg(1));
8175 MI.eraseFromParent();
8176 return true;
8177}
8178
8180 MachineInstr &MI) const {
8181 MachineIRBuilder &B = Helper.MIRBuilder;
8182 MachineRegisterInfo &MRI = *B.getMRI();
8183
8184 // Replace the use G_BRCOND with the exec manipulate and branch pseudos.
8185 auto IntrID = cast<GIntrinsic>(MI).getIntrinsicID();
8186 switch (IntrID) {
8187 case Intrinsic::sponentry:
8188 if (B.getMF().getInfo<SIMachineFunctionInfo>()->isBottomOfStack()) {
8189 // FIXME: The imported pattern checks for i32 instead of p5; if we fix
8190 // that we can remove this cast.
8191 const LLT I32 = LLT::integer(32);
8192 Register TmpReg = MRI.createGenericVirtualRegister(I32);
8193 B.buildInstr(AMDGPU::G_AMDGPU_SPONENTRY).addDef(TmpReg);
8194
8195 Register DstReg = MI.getOperand(0).getReg();
8196 B.buildIntToPtr(DstReg, TmpReg);
8197 MI.eraseFromParent();
8198 } else {
8199 int FI = B.getMF().getFrameInfo().CreateFixedObject(
8200 1, 0, /*IsImmutable=*/false);
8201 B.buildFrameIndex(MI.getOperand(0), FI);
8202 MI.eraseFromParent();
8203 }
8204 return true;
8205 case Intrinsic::amdgcn_if:
8206 case Intrinsic::amdgcn_else: {
8207 MachineInstr *Br = nullptr;
8208 MachineBasicBlock *UncondBrTarget = nullptr;
8209 bool Negated = false;
8210 if (MachineInstr *BrCond =
8211 verifyCFIntrinsic(MI, MRI, Br, UncondBrTarget, Negated)) {
8212 const SIRegisterInfo *TRI
8213 = static_cast<const SIRegisterInfo *>(MRI.getTargetRegisterInfo());
8214
8215 Register Def = MI.getOperand(1).getReg();
8216 Register Use = MI.getOperand(3).getReg();
8217
8218 MachineBasicBlock *CondBrTarget = BrCond->getOperand(1).getMBB();
8219
8220 if (Negated)
8221 std::swap(CondBrTarget, UncondBrTarget);
8222
8223 B.setInsertPt(B.getMBB(), BrCond->getIterator());
8224 if (IntrID == Intrinsic::amdgcn_if) {
8225 B.buildInstr(AMDGPU::SI_IF)
8226 .addDef(Def)
8227 .addUse(Use)
8228 .addMBB(UncondBrTarget);
8229 } else {
8230 B.buildInstr(AMDGPU::SI_ELSE)
8231 .addDef(Def)
8232 .addUse(Use)
8233 .addMBB(UncondBrTarget);
8234 }
8235
8236 if (Br) {
8237 Br->getOperand(0).setMBB(CondBrTarget);
8238 } else {
8239 // The IRTranslator skips inserting the G_BR for fallthrough cases, but
8240 // since we're swapping branch targets it needs to be reinserted.
8241 // FIXME: IRTranslator should probably not do this
8242 B.buildBr(*CondBrTarget);
8243 }
8244
8245 MRI.setRegClass(Def, TRI->getWaveMaskRegClass());
8246 MRI.setRegClass(Use, TRI->getWaveMaskRegClass());
8247 MI.eraseFromParent();
8248 BrCond->eraseFromParent();
8249 return true;
8250 }
8251
8252 return false;
8253 }
8254 case Intrinsic::amdgcn_loop: {
8255 MachineInstr *Br = nullptr;
8256 MachineBasicBlock *UncondBrTarget = nullptr;
8257 bool Negated = false;
8258 if (MachineInstr *BrCond =
8259 verifyCFIntrinsic(MI, MRI, Br, UncondBrTarget, Negated)) {
8260 const SIRegisterInfo *TRI
8261 = static_cast<const SIRegisterInfo *>(MRI.getTargetRegisterInfo());
8262
8263 MachineBasicBlock *CondBrTarget = BrCond->getOperand(1).getMBB();
8264 Register Reg = MI.getOperand(2).getReg();
8265
8266 if (Negated)
8267 std::swap(CondBrTarget, UncondBrTarget);
8268
8269 B.setInsertPt(B.getMBB(), BrCond->getIterator());
8270 B.buildInstr(AMDGPU::SI_LOOP)
8271 .addUse(Reg)
8272 .addMBB(UncondBrTarget);
8273
8274 if (Br)
8275 Br->getOperand(0).setMBB(CondBrTarget);
8276 else
8277 B.buildBr(*CondBrTarget);
8278
8279 MI.eraseFromParent();
8280 BrCond->eraseFromParent();
8281 MRI.setRegClass(Reg, TRI->getWaveMaskRegClass());
8282 return true;
8283 }
8284
8285 return false;
8286 }
8287 case Intrinsic::amdgcn_wave_reduce_min:
8288 case Intrinsic::amdgcn_wave_reduce_umin:
8289 case Intrinsic::amdgcn_wave_reduce_fmin:
8290 case Intrinsic::amdgcn_wave_reduce_max:
8291 case Intrinsic::amdgcn_wave_reduce_umax:
8292 case Intrinsic::amdgcn_wave_reduce_fmax:
8293 case Intrinsic::amdgcn_wave_reduce_add:
8294 case Intrinsic::amdgcn_wave_reduce_fadd:
8295 case Intrinsic::amdgcn_wave_reduce_sub:
8296 case Intrinsic::amdgcn_wave_reduce_fsub:
8297 case Intrinsic::amdgcn_wave_reduce_and:
8298 case Intrinsic::amdgcn_wave_reduce_or:
8299 case Intrinsic::amdgcn_wave_reduce_xor: {
8300 Register SrcReg = MI.getOperand(2).getReg();
8301 if (MRI.getType(SrcReg).getSizeInBits() != 16)
8302 return true;
8303 Register DstReg = MI.getOperand(0).getReg();
8304 bool IsFPOp = IntrID == Intrinsic::amdgcn_wave_reduce_fmin ||
8305 IntrID == Intrinsic::amdgcn_wave_reduce_fmax ||
8306 IntrID == Intrinsic::amdgcn_wave_reduce_fadd ||
8307 IntrID == Intrinsic::amdgcn_wave_reduce_fsub;
8308 bool NeedsSignExt = IntrID == Intrinsic::amdgcn_wave_reduce_min ||
8309 IntrID == Intrinsic::amdgcn_wave_reduce_max ||
8310 IntrID == Intrinsic::amdgcn_wave_reduce_add ||
8311 IntrID == Intrinsic::amdgcn_wave_reduce_sub;
8312 auto Ext = IsFPOp ? B.buildFPExt(F32, SrcReg)
8313 : NeedsSignExt ? B.buildSExt(LLT::integer(32), SrcReg)
8314 : B.buildZExt(LLT::integer(32), SrcReg);
8315 auto NewDst =
8316 MRI.createGenericVirtualRegister(IsFPOp ? F32 : LLT::integer(32));
8317 B.buildIntrinsic(IntrID, ArrayRef<Register>{NewDst},
8318 /*hasSideEffects=*/false, /*isConvergent=*/true)
8319 .addUse(Ext.getReg(0))
8320 .addImm(MI.getOperand(3).getImm()); // strategy
8321 if (IsFPOp)
8322 B.buildFPTrunc(DstReg, NewDst);
8323 else
8324 B.buildTrunc(DstReg, NewDst);
8325 MI.eraseFromParent();
8326 return true;
8327 }
8328 case Intrinsic::amdgcn_addrspacecast_nonnull:
8329 return legalizeAddrSpaceCast(MI, MRI, B);
8330 case Intrinsic::amdgcn_make_buffer_rsrc:
8331 return legalizePointerAsRsrcIntrin(MI, MRI, B);
8332 case Intrinsic::amdgcn_kernarg_segment_ptr:
8333 if (!AMDGPU::isKernel(B.getMF().getFunction())) {
8334 // This only makes sense to call in a kernel, so just lower to null.
8335 B.buildConstant(MI.getOperand(0).getReg(), 0);
8336 MI.eraseFromParent();
8337 return true;
8338 }
8339
8342 case Intrinsic::amdgcn_implicitarg_ptr:
8343 return legalizeImplicitArgPtr(MI, MRI, B);
8344 case Intrinsic::amdgcn_workitem_id_x:
8345 return legalizeWorkitemIDIntrinsic(MI, MRI, B, 0,
8347 case Intrinsic::amdgcn_workitem_id_y:
8348 return legalizeWorkitemIDIntrinsic(MI, MRI, B, 1,
8350 case Intrinsic::amdgcn_workitem_id_z:
8351 return legalizeWorkitemIDIntrinsic(MI, MRI, B, 2,
8353 case Intrinsic::amdgcn_workgroup_id_x:
8354 return legalizeWorkGroupId(
8358 case Intrinsic::amdgcn_workgroup_id_y:
8359 return legalizeWorkGroupId(
8363 case Intrinsic::amdgcn_workgroup_id_z:
8364 return legalizeWorkGroupId(
8368 case Intrinsic::amdgcn_cluster_id_x:
8369 return ST.hasClusters() &&
8372 case Intrinsic::amdgcn_cluster_id_y:
8373 return ST.hasClusters() &&
8376 case Intrinsic::amdgcn_cluster_id_z:
8377 return ST.hasClusters() &&
8380 case Intrinsic::amdgcn_cluster_workgroup_id_x:
8381 return ST.hasClusters() &&
8384 case Intrinsic::amdgcn_cluster_workgroup_id_y:
8385 return ST.hasClusters() &&
8388 case Intrinsic::amdgcn_cluster_workgroup_id_z:
8389 return ST.hasClusters() &&
8392 case Intrinsic::amdgcn_cluster_workgroup_flat_id:
8393 return ST.hasClusters() &&
8395 case Intrinsic::amdgcn_cluster_workgroup_max_id_x:
8396 return ST.hasClusters() &&
8399 case Intrinsic::amdgcn_cluster_workgroup_max_id_y:
8400 return ST.hasClusters() &&
8403 case Intrinsic::amdgcn_cluster_workgroup_max_id_z:
8404 return ST.hasClusters() &&
8407 case Intrinsic::amdgcn_cluster_workgroup_max_flat_id:
8408 return ST.hasClusters() &&
8410 MI, MRI, B,
8412 case Intrinsic::amdgcn_wave_id:
8413 return legalizeWaveID(MI, B);
8414 case Intrinsic::amdgcn_lds_kernel_id:
8415 return legalizePreloadedArgIntrin(MI, MRI, B,
8417 case Intrinsic::amdgcn_dispatch_ptr:
8418 return legalizePreloadedArgIntrin(MI, MRI, B,
8420 case Intrinsic::amdgcn_queue_ptr:
8421 return legalizePreloadedArgIntrin(MI, MRI, B,
8423 case Intrinsic::amdgcn_implicit_buffer_ptr:
8426 case Intrinsic::amdgcn_dispatch_id:
8427 return legalizePreloadedArgIntrin(MI, MRI, B,
8429 case Intrinsic::r600_read_ngroups_x:
8430 // TODO: Emit error for hsa
8433 case Intrinsic::r600_read_ngroups_y:
8436 case Intrinsic::r600_read_ngroups_z:
8439 case Intrinsic::r600_read_local_size_x:
8440 // TODO: Could insert G_ASSERT_ZEXT from i16
8442 case Intrinsic::r600_read_local_size_y:
8443 // TODO: Could insert G_ASSERT_ZEXT from i16
8445 // TODO: Could insert G_ASSERT_ZEXT from i16
8446 case Intrinsic::r600_read_local_size_z:
8449 case Intrinsic::amdgcn_fdiv_fast:
8450 return legalizeFDIVFastIntrin(MI, MRI, B);
8451 case Intrinsic::amdgcn_is_shared:
8453 case Intrinsic::amdgcn_is_private:
8455 case Intrinsic::amdgcn_wavefrontsize: {
8456 B.buildConstant(MI.getOperand(0), ST.getWavefrontSize());
8457 MI.eraseFromParent();
8458 return true;
8459 }
8460 case Intrinsic::amdgcn_s_buffer_load:
8461 case Intrinsic::amdgcn_ptr_s_buffer_load:
8462 return legalizeSBufferLoad(Helper, MI);
8463 case Intrinsic::amdgcn_raw_buffer_store:
8464 case Intrinsic::amdgcn_raw_ptr_buffer_store:
8465 case Intrinsic::amdgcn_struct_buffer_store:
8466 case Intrinsic::amdgcn_struct_ptr_buffer_store:
8467 return legalizeBufferStore(MI, Helper, false, false);
8468 case Intrinsic::amdgcn_raw_buffer_store_format:
8469 case Intrinsic::amdgcn_raw_ptr_buffer_store_format:
8470 case Intrinsic::amdgcn_struct_buffer_store_format:
8471 case Intrinsic::amdgcn_struct_ptr_buffer_store_format:
8472 return legalizeBufferStore(MI, Helper, false, true);
8473 case Intrinsic::amdgcn_raw_tbuffer_store:
8474 case Intrinsic::amdgcn_raw_ptr_tbuffer_store:
8475 case Intrinsic::amdgcn_struct_tbuffer_store:
8476 case Intrinsic::amdgcn_struct_ptr_tbuffer_store:
8477 return legalizeBufferStore(MI, Helper, true, true);
8478 case Intrinsic::amdgcn_raw_buffer_load:
8479 case Intrinsic::amdgcn_raw_ptr_buffer_load:
8480 case Intrinsic::amdgcn_raw_atomic_buffer_load:
8481 case Intrinsic::amdgcn_raw_ptr_atomic_buffer_load:
8482 case Intrinsic::amdgcn_struct_buffer_load:
8483 case Intrinsic::amdgcn_struct_ptr_buffer_load:
8484 case Intrinsic::amdgcn_struct_atomic_buffer_load:
8485 case Intrinsic::amdgcn_struct_ptr_atomic_buffer_load:
8486 return legalizeBufferLoad(MI, Helper, false, false);
8487 case Intrinsic::amdgcn_raw_buffer_load_format:
8488 case Intrinsic::amdgcn_raw_ptr_buffer_load_format:
8489 case Intrinsic::amdgcn_struct_buffer_load_format:
8490 case Intrinsic::amdgcn_struct_ptr_buffer_load_format:
8491 return legalizeBufferLoad(MI, Helper, true, false);
8492 case Intrinsic::amdgcn_raw_tbuffer_load:
8493 case Intrinsic::amdgcn_raw_ptr_tbuffer_load:
8494 case Intrinsic::amdgcn_struct_tbuffer_load:
8495 case Intrinsic::amdgcn_struct_ptr_tbuffer_load:
8496 return legalizeBufferLoad(MI, Helper, true, true);
8497 case Intrinsic::amdgcn_raw_buffer_atomic_swap:
8498 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_swap:
8499 case Intrinsic::amdgcn_struct_buffer_atomic_swap:
8500 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_swap:
8501 case Intrinsic::amdgcn_raw_buffer_atomic_add:
8502 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_add:
8503 case Intrinsic::amdgcn_struct_buffer_atomic_add:
8504 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_add:
8505 case Intrinsic::amdgcn_raw_buffer_atomic_sub:
8506 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_sub:
8507 case Intrinsic::amdgcn_struct_buffer_atomic_sub:
8508 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_sub:
8509 case Intrinsic::amdgcn_raw_buffer_atomic_smin:
8510 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_smin:
8511 case Intrinsic::amdgcn_struct_buffer_atomic_smin:
8512 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_smin:
8513 case Intrinsic::amdgcn_raw_buffer_atomic_umin:
8514 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_umin:
8515 case Intrinsic::amdgcn_struct_buffer_atomic_umin:
8516 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_umin:
8517 case Intrinsic::amdgcn_raw_buffer_atomic_smax:
8518 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_smax:
8519 case Intrinsic::amdgcn_struct_buffer_atomic_smax:
8520 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_smax:
8521 case Intrinsic::amdgcn_raw_buffer_atomic_umax:
8522 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_umax:
8523 case Intrinsic::amdgcn_struct_buffer_atomic_umax:
8524 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_umax:
8525 case Intrinsic::amdgcn_raw_buffer_atomic_and:
8526 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_and:
8527 case Intrinsic::amdgcn_struct_buffer_atomic_and:
8528 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_and:
8529 case Intrinsic::amdgcn_raw_buffer_atomic_or:
8530 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_or:
8531 case Intrinsic::amdgcn_struct_buffer_atomic_or:
8532 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_or:
8533 case Intrinsic::amdgcn_raw_buffer_atomic_xor:
8534 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_xor:
8535 case Intrinsic::amdgcn_struct_buffer_atomic_xor:
8536 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_xor:
8537 case Intrinsic::amdgcn_raw_buffer_atomic_inc:
8538 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_inc:
8539 case Intrinsic::amdgcn_struct_buffer_atomic_inc:
8540 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_inc:
8541 case Intrinsic::amdgcn_raw_buffer_atomic_dec:
8542 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_dec:
8543 case Intrinsic::amdgcn_struct_buffer_atomic_dec:
8544 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_dec:
8545 case Intrinsic::amdgcn_raw_buffer_atomic_cmpswap:
8546 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_cmpswap:
8547 case Intrinsic::amdgcn_struct_buffer_atomic_cmpswap:
8548 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_cmpswap:
8549 case Intrinsic::amdgcn_raw_buffer_atomic_fmin:
8550 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_fmin:
8551 case Intrinsic::amdgcn_struct_buffer_atomic_fmin:
8552 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_fmin:
8553 case Intrinsic::amdgcn_raw_buffer_atomic_fmax:
8554 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_fmax:
8555 case Intrinsic::amdgcn_struct_buffer_atomic_fmax:
8556 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_fmax:
8557 case Intrinsic::amdgcn_raw_buffer_atomic_sub_clamp_u32:
8558 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_sub_clamp_u32:
8559 case Intrinsic::amdgcn_struct_buffer_atomic_sub_clamp_u32:
8560 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_sub_clamp_u32:
8561 case Intrinsic::amdgcn_raw_buffer_atomic_cond_sub_u32:
8562 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_cond_sub_u32:
8563 case Intrinsic::amdgcn_struct_buffer_atomic_cond_sub_u32:
8564 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_cond_sub_u32:
8565 case Intrinsic::amdgcn_raw_buffer_atomic_fadd:
8566 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_fadd:
8567 case Intrinsic::amdgcn_struct_buffer_atomic_fadd:
8568 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_fadd:
8569 return legalizeBufferAtomic(MI, B, IntrID);
8570 case Intrinsic::amdgcn_rsq_clamp:
8571 return legalizeRsqClampIntrinsic(MI, MRI, B);
8572 case Intrinsic::amdgcn_image_bvh_intersect_ray:
8574 case Intrinsic::amdgcn_image_bvh_dual_intersect_ray:
8575 case Intrinsic::amdgcn_image_bvh8_intersect_ray:
8577 case Intrinsic::amdgcn_swmmac_f32_16x16x128_fp8_fp8:
8578 case Intrinsic::amdgcn_swmmac_f32_16x16x128_fp8_bf8:
8579 case Intrinsic::amdgcn_swmmac_f32_16x16x128_bf8_fp8:
8580 case Intrinsic::amdgcn_swmmac_f32_16x16x128_bf8_bf8:
8581 case Intrinsic::amdgcn_swmmac_f16_16x16x128_fp8_fp8:
8582 case Intrinsic::amdgcn_swmmac_f16_16x16x128_fp8_bf8:
8583 case Intrinsic::amdgcn_swmmac_f16_16x16x128_bf8_fp8:
8584 case Intrinsic::amdgcn_swmmac_f16_16x16x128_bf8_bf8: {
8585 Register Index = MI.getOperand(5).getReg();
8586 LLT I64 = LLT::integer(64);
8587 LLT IndexArgTy = MRI.getType(Index);
8588 if (IndexArgTy != I64) {
8589 auto NewIndex = IndexArgTy.isVector() ? B.buildBitcast(I64, Index)
8590 : B.buildAnyExt(I64, Index);
8591 MI.getOperand(5).setReg(NewIndex.getReg(0));
8592 }
8593 return true;
8594 }
8595 case Intrinsic::amdgcn_swmmac_f16_16x16x32_f16:
8596 case Intrinsic::amdgcn_swmmac_bf16_16x16x32_bf16:
8597 case Intrinsic::amdgcn_swmmac_f32_16x16x32_bf16:
8598 case Intrinsic::amdgcn_swmmac_f32_16x16x32_f16:
8599 case Intrinsic::amdgcn_swmmac_f32_16x16x32_fp8_fp8:
8600 case Intrinsic::amdgcn_swmmac_f32_16x16x32_fp8_bf8:
8601 case Intrinsic::amdgcn_swmmac_f32_16x16x32_bf8_fp8:
8602 case Intrinsic::amdgcn_swmmac_f32_16x16x32_bf8_bf8: {
8603 Register Index = MI.getOperand(5).getReg();
8604 LLT I32 = LLT::integer(32);
8605 if (MRI.getType(Index) != I32)
8606 MI.getOperand(5).setReg(B.buildAnyExt(I32, Index).getReg(0));
8607 return true;
8608 }
8609 case Intrinsic::amdgcn_swmmac_f16_16x16x64_f16:
8610 case Intrinsic::amdgcn_swmmac_bf16_16x16x64_bf16:
8611 case Intrinsic::amdgcn_swmmac_f32_16x16x64_bf16:
8612 case Intrinsic::amdgcn_swmmac_bf16f32_16x16x64_bf16:
8613 case Intrinsic::amdgcn_swmmac_f32_16x16x64_f16:
8614 case Intrinsic::amdgcn_swmmac_i32_16x16x128_iu8:
8615 case Intrinsic::amdgcn_swmmac_i32_16x16x32_iu4:
8616 case Intrinsic::amdgcn_swmmac_i32_16x16x32_iu8:
8617 case Intrinsic::amdgcn_swmmac_i32_16x16x64_iu4: {
8618 Register Index = MI.getOperand(7).getReg();
8619 LLT IdxTy = IntrID == Intrinsic::amdgcn_swmmac_i32_16x16x128_iu8
8620 ? LLT::integer(64)
8621 : LLT::integer(32);
8622 LLT IndexArgTy = MRI.getType(Index);
8623 if (IndexArgTy != IdxTy) {
8624 auto NewIndex = IndexArgTy.isVector() ? B.buildBitcast(IdxTy, Index)
8625 : B.buildAnyExt(IdxTy, Index);
8626 MI.getOperand(7).setReg(NewIndex.getReg(0));
8627 }
8628 return true;
8629 }
8630
8631 case Intrinsic::amdgcn_fmed3: {
8632 GISelChangeObserver &Observer = Helper.Observer;
8633
8634 // FIXME: This is to workaround the inability of tablegen match combiners to
8635 // match intrinsics in patterns.
8636 Observer.changingInstr(MI);
8637 MI.setDesc(B.getTII().get(AMDGPU::G_AMDGPU_FMED3));
8638 MI.removeOperand(1);
8639 Observer.changedInstr(MI);
8640 return true;
8641 }
8642 case Intrinsic::amdgcn_readlane:
8643 case Intrinsic::amdgcn_writelane:
8644 case Intrinsic::amdgcn_readfirstlane:
8645 case Intrinsic::amdgcn_permlane16:
8646 case Intrinsic::amdgcn_permlanex16:
8647 case Intrinsic::amdgcn_permlane64:
8648 case Intrinsic::amdgcn_set_inactive:
8649 case Intrinsic::amdgcn_set_inactive_chain_arg:
8650 case Intrinsic::amdgcn_mov_dpp8:
8651 case Intrinsic::amdgcn_update_dpp:
8652 case Intrinsic::amdgcn_permlane_bcast:
8653 case Intrinsic::amdgcn_permlane_up:
8654 case Intrinsic::amdgcn_permlane_down:
8655 case Intrinsic::amdgcn_permlane_xor:
8656 return legalizeLaneOp(Helper, MI, IntrID);
8657 case Intrinsic::amdgcn_s_buffer_prefetch_data:
8658 return legalizeSBufferPrefetch(Helper, MI);
8659 case Intrinsic::amdgcn_dead: {
8660 // TODO: Use poison instead of undef
8661 for (const MachineOperand &Def : MI.defs())
8662 B.buildUndef(Def);
8663 MI.eraseFromParent();
8664 return true;
8665 }
8666 case Intrinsic::amdgcn_cooperative_atomic_load_32x4B:
8667 case Intrinsic::amdgcn_cooperative_atomic_load_16x8B:
8668 case Intrinsic::amdgcn_cooperative_atomic_load_8x16B:
8669 assert(MI.hasOneMemOperand() && "Expected IRTranslator to set MemOp!");
8670 B.buildLoad(MI.getOperand(0), MI.getOperand(2), **MI.memoperands_begin());
8671 MI.eraseFromParent();
8672 return true;
8673 case Intrinsic::amdgcn_cooperative_atomic_store_32x4B:
8674 case Intrinsic::amdgcn_cooperative_atomic_store_16x8B:
8675 case Intrinsic::amdgcn_cooperative_atomic_store_8x16B:
8676 assert(MI.hasOneMemOperand() && "Expected IRTranslator to set MemOp!");
8677 B.buildStore(MI.getOperand(2), MI.getOperand(1), **MI.memoperands_begin());
8678 MI.eraseFromParent();
8679 return true;
8680 case Intrinsic::amdgcn_av_load_b128:
8681 case Intrinsic::amdgcn_av_store_b128: {
8682 assert(MI.hasOneMemOperand() && "Expected IRTranslator to set MemOp!");
8683 if (IntrID == Intrinsic::amdgcn_av_load_b128)
8684 B.buildLoad(MI.getOperand(0), MI.getOperand(2), **MI.memoperands_begin());
8685 else
8686 B.buildStore(MI.getOperand(2), MI.getOperand(1),
8687 **MI.memoperands_begin());
8688 MI.eraseFromParent();
8689 return true;
8690 }
8691 case Intrinsic::amdgcn_flat_load_monitor_b32:
8692 case Intrinsic::amdgcn_flat_load_monitor_b64:
8693 case Intrinsic::amdgcn_flat_load_monitor_b128:
8694 assert(MI.hasOneMemOperand() && "Expected IRTranslator to set MemOp!");
8695 B.buildInstr(AMDGPU::G_AMDGPU_FLAT_LOAD_MONITOR)
8696 .add(MI.getOperand(0))
8697 .add(MI.getOperand(2))
8698 .addMemOperand(*MI.memoperands_begin());
8699 MI.eraseFromParent();
8700 return true;
8701 case Intrinsic::amdgcn_global_load_monitor_b32:
8702 case Intrinsic::amdgcn_global_load_monitor_b64:
8703 case Intrinsic::amdgcn_global_load_monitor_b128:
8704 assert(MI.hasOneMemOperand() && "Expected IRTranslator to set MemOp!");
8705 B.buildInstr(AMDGPU::G_AMDGPU_GLOBAL_LOAD_MONITOR)
8706 .add(MI.getOperand(0))
8707 .add(MI.getOperand(2))
8708 .addMemOperand(*MI.memoperands_begin());
8709 MI.eraseFromParent();
8710 return true;
8711 default: {
8712 if (const AMDGPU::ImageDimIntrinsicInfo *ImageDimIntr =
8714 return legalizeImageIntrinsic(MI, B, Helper.Observer, ImageDimIntr);
8715 return true;
8716 }
8717 }
8718
8719 return true;
8720}
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.