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