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