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