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