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