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