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