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