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