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