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 MIB.setOperandDead(3); // $scc
3316 }
3317
3318 if (PtrTy.getSizeInBits() == 32)
3319 B.buildExtract(DstReg, PCReg, 0);
3320 else
3321 B.buildCopy(DstReg, PCReg);
3322 return true;
3323}
3324
3325// Emit a ABS32_LO / ABS32_HI relocation stub.
3327 Register DstReg, LLT PtrTy, MachineIRBuilder &B, const GlobalValue *GV,
3328 MachineRegisterInfo &MRI) const {
3329 bool RequiresHighHalf = PtrTy.getSizeInBits() != 32;
3330
3331 if (RequiresHighHalf && ST.has64BitLiterals()) {
3332 Register Addr =
3333 MRI.createVirtualRegister({&AMDGPU::SReg_64RegClass, PtrTy});
3334 B.buildInstr(AMDGPU::S_MOV_B64)
3335 .addDef(Addr)
3336 .addGlobalAddress(GV, 0, SIInstrInfo::MO_ABS64);
3337 B.buildCopy(DstReg, Addr);
3338 return;
3339 }
3340
3341 LLT I32 = LLT::integer(32);
3342 Register AddrLo = MRI.createVirtualRegister({&AMDGPU::SReg_32RegClass, I32});
3343
3344 // Write the lower half.
3345 B.buildInstr(AMDGPU::S_MOV_B32)
3346 .addDef(AddrLo)
3347 .addGlobalAddress(GV, 0, SIInstrInfo::MO_ABS32_LO);
3348
3349 // If required, write the upper half as well.
3350 if (RequiresHighHalf) {
3351 assert(PtrTy.getSizeInBits() == 64 &&
3352 "Must provide a 64-bit pointer type!");
3353
3354 Register AddrHi =
3355 MRI.createVirtualRegister({&AMDGPU::SReg_32RegClass, I32});
3356
3357 B.buildInstr(AMDGPU::S_MOV_B32)
3358 .addDef(AddrHi)
3359 .addGlobalAddress(GV, 0, SIInstrInfo::MO_ABS32_HI);
3360
3361 Register AddrDst =
3362 MRI.createVirtualRegister({&AMDGPU::SReg_64RegClass, LLT::integer(64)});
3363
3364 B.buildMergeValues(AddrDst, {AddrLo, AddrHi});
3365 B.buildCast(DstReg, AddrDst);
3366 } else {
3367 B.buildCast(DstReg, AddrLo);
3368 }
3369}
3370
3373 MachineIRBuilder &B) const {
3374 Register DstReg = MI.getOperand(0).getReg();
3375 LLT Ty = MRI.getType(DstReg);
3376 unsigned AS = Ty.getAddressSpace();
3377
3378 const GlobalValue *GV = MI.getOperand(1).getGlobal();
3379 MachineFunction &MF = B.getMF();
3381
3382 if (AS == AMDGPUAS::BARRIER) {
3383 const GlobalVariable *GVar = cast<GlobalVariable>(GV);
3384 if (!AMDGPU::isNamedBarrier(*GVar)) {
3385 const Function &Fn = MF.getFunction();
3387 Fn, "unsupported use of BARRIER address space", MI.getDebugLoc(),
3388 DS_Error));
3389 B.buildUndef(DstReg);
3390 MI.eraseFromParent();
3391 return true;
3392 }
3393
3394 B.buildConstant(DstReg,
3395 MFI->allocateBarrierGlobal(B.getDataLayout(), *GVar));
3396 MI.eraseFromParent();
3397 return true;
3398 }
3399
3401 if (!MFI->isModuleEntryFunction() &&
3402 GV->getName() != "llvm.amdgcn.module.lds") {
3403 const Function &Fn = MF.getFunction();
3405 Fn, "local memory global used by non-kernel function",
3406 MI.getDebugLoc(), DS_Warning));
3407
3408 // We currently don't have a way to correctly allocate LDS objects that
3409 // aren't directly associated with a kernel. We do force inlining of
3410 // functions that use local objects. However, if these dead functions are
3411 // not eliminated, we don't want a compile time error. Just emit a warning
3412 // and a trap, since there should be no callable path here.
3413 B.buildTrap();
3414 B.buildUndef(DstReg);
3415 MI.eraseFromParent();
3416 return true;
3417 }
3418
3419 // TODO: We could emit code to handle the initialization somewhere.
3420 // We ignore the initializer for now and legalize it to allow selection.
3421 // The initializer will anyway get errored out during assembly emission.
3422 const SITargetLowering *TLI = ST.getTargetLowering();
3423 if (!TLI->shouldUseLDSConstAddress(GV)) {
3424 MI.getOperand(1).setTargetFlags(SIInstrInfo::MO_ABS32_LO);
3425 return true; // Leave in place;
3426 }
3427
3428 const GlobalVariable &GVar = *cast<GlobalVariable>(GV);
3429 if (AS == AMDGPUAS::LOCAL_ADDRESS && GV->hasExternalLinkage()) {
3430 // HIP uses an unsized array `extern __shared__ T s[]` or similar
3431 // zero-sized type in other languages to declare the dynamic shared
3432 // memory which size is not known at the compile time. They will be
3433 // allocated by the runtime and placed directly after the static
3434 // allocated ones. They all share the same offset.
3435 if (GVar.getGlobalSize(GVar.getDataLayout()) == 0) {
3436 // Adjust alignment for that dynamic shared memory array.
3437 MFI->setDynLDSAlign(MF.getFunction(), GVar);
3438 LLT I32 = LLT::integer(32);
3439 auto Sz = B.buildIntrinsic(Intrinsic::amdgcn_groupstaticsize, {I32});
3440 B.buildIntToPtr(DstReg, Sz);
3441 MI.eraseFromParent();
3442 return true;
3443 }
3444 }
3445
3446 B.buildConstant(DstReg, MFI->allocateLDSGlobal(B.getDataLayout(), GVar));
3447 MI.eraseFromParent();
3448 return true;
3449 }
3450
3451 if (ST.isAmdPalOS() || ST.isMesa3DOS()) {
3452 buildAbsGlobalAddress(DstReg, Ty, B, GV, MRI);
3453 MI.eraseFromParent();
3454 return true;
3455 }
3456
3457 const SITargetLowering *TLI = ST.getTargetLowering();
3458
3459 if (TLI->shouldEmitFixup(GV)) {
3460 buildPCRelGlobalAddress(DstReg, Ty, B, GV, 0);
3461 MI.eraseFromParent();
3462 return true;
3463 }
3464
3465 if (TLI->shouldEmitPCReloc(GV)) {
3466 buildPCRelGlobalAddress(DstReg, Ty, B, GV, 0, SIInstrInfo::MO_REL32);
3467 MI.eraseFromParent();
3468 return true;
3469 }
3470
3472 Register GOTAddr = MRI.createGenericVirtualRegister(PtrTy);
3473
3474 LLT LoadTy = Ty.getSizeInBits() == 32 ? PtrTy : Ty;
3479 LoadTy, Align(8));
3480
3481 buildPCRelGlobalAddress(GOTAddr, PtrTy, B, GV, 0, SIInstrInfo::MO_GOTPCREL32);
3482
3483 if (Ty.getSizeInBits() == 32) {
3484 // Truncate if this is a 32-bit constant address.
3485 auto Load = B.buildLoad(PtrTy, GOTAddr, *GOTMMO);
3486 B.buildExtract(DstReg, Load, 0);
3487 } else
3488 B.buildLoad(DstReg, GOTAddr, *GOTMMO);
3489
3490 MI.eraseFromParent();
3491 return true;
3492}
3493
3495 if (Ty.isVector())
3496 return Ty.changeElementCount(
3497 ElementCount::getFixed(PowerOf2Ceil(Ty.getNumElements())));
3498 return Ty.changeElementSize(PowerOf2Ceil(Ty.getSizeInBits()));
3499}
3500
3502 MachineInstr &MI) const {
3503 MachineIRBuilder &B = Helper.MIRBuilder;
3504 MachineRegisterInfo &MRI = *B.getMRI();
3505 GISelChangeObserver &Observer = Helper.Observer;
3506
3507 Register PtrReg = MI.getOperand(1).getReg();
3508 LLT PtrTy = MRI.getType(PtrReg);
3509 unsigned AddrSpace = PtrTy.getAddressSpace();
3510
3511 if (AddrSpace == AMDGPUAS::CONSTANT_ADDRESS_32BIT) {
3513 auto Cast = B.buildAddrSpaceCast(ConstPtr, PtrReg);
3514 Observer.changingInstr(MI);
3515 MI.getOperand(1).setReg(Cast.getReg(0));
3516 Observer.changedInstr(MI);
3517 return true;
3518 }
3519
3520 if (MI.getOpcode() != AMDGPU::G_LOAD)
3521 return false;
3522
3523 Register ValReg = MI.getOperand(0).getReg();
3524 LLT ValTy = MRI.getType(ValReg);
3525
3526 if (hasBufferRsrcWorkaround(ValTy)) {
3527 Observer.changingInstr(MI);
3528 castBufferRsrcFromV4I32(MI, B, MRI, 0);
3529 Observer.changedInstr(MI);
3530 return true;
3531 }
3532
3533 MachineMemOperand *MMO = *MI.memoperands_begin();
3534 const unsigned ValSize = ValTy.getSizeInBits();
3535 const LLT MemTy = MMO->getMemoryType();
3536 const Align MemAlign = MMO->getAlign();
3537 const unsigned MemSize = MemTy.getSizeInBits();
3538 const uint64_t AlignInBits = 8 * MemAlign.value();
3539
3540 // Widen non-power-of-2 loads to the alignment if needed
3541 if (shouldWidenLoad(ST, MemTy, AlignInBits, AddrSpace, MI.getOpcode())) {
3542 const unsigned WideMemSize = PowerOf2Ceil(MemSize);
3543
3544 // This was already the correct extending load result type, so just adjust
3545 // the memory type.
3546 if (WideMemSize == ValSize) {
3547 MachineFunction &MF = B.getMF();
3548
3549 MachineMemOperand *WideMMO =
3550 MF.getMachineMemOperand(MMO, 0, WideMemSize / 8);
3551 Observer.changingInstr(MI);
3552 MI.setMemRefs(MF, {WideMMO});
3553 Observer.changedInstr(MI);
3554 return true;
3555 }
3556
3557 // Don't bother handling edge case that should probably never be produced.
3558 if (ValSize > WideMemSize)
3559 return false;
3560
3561 LLT WideTy = widenToNextPowerOf2(ValTy);
3562
3563 Register WideLoad;
3564 if (!WideTy.isVector()) {
3565 WideLoad = B.buildLoadFromOffset(WideTy, PtrReg, *MMO, 0).getReg(0);
3566 B.buildTrunc(ValReg, WideLoad).getReg(0);
3567 } else {
3568 // Extract the subvector.
3569
3570 if (isRegisterType(ST, ValTy)) {
3571 // If this a case where G_EXTRACT is legal, use it.
3572 // (e.g. <3 x i32> -> <4 x i32>)
3573 WideLoad = B.buildLoadFromOffset(WideTy, PtrReg, *MMO, 0).getReg(0);
3574 B.buildExtract(ValReg, WideLoad, 0);
3575 } else {
3576 // For cases where the widened type isn't a nice register value, unmerge
3577 // from a widened register (e.g. <3 x i16> -> <4 x i16>)
3578 WideLoad = B.buildLoadFromOffset(WideTy, PtrReg, *MMO, 0).getReg(0);
3579 B.buildDeleteTrailingVectorElements(ValReg, WideLoad);
3580 }
3581 }
3582
3583 MI.eraseFromParent();
3584 return true;
3585 }
3586
3587 return false;
3588}
3589
3591 MachineInstr &MI) const {
3592 MachineIRBuilder &B = Helper.MIRBuilder;
3593 MachineRegisterInfo &MRI = *B.getMRI();
3594 GISelChangeObserver &Observer = Helper.Observer;
3595
3596 Register DataReg = MI.getOperand(0).getReg();
3597 LLT DataTy = MRI.getType(DataReg);
3598
3599 if (hasBufferRsrcWorkaround(DataTy)) {
3600 Observer.changingInstr(MI);
3602 Observer.changedInstr(MI);
3603 return true;
3604 }
3605 return false;
3606}
3607
3610 MachineIRBuilder &B) const {
3611 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
3612 assert(Ty.isScalar());
3613
3614 MachineFunction &MF = B.getMF();
3616
3617 // TODO: Always legal with future ftz flag.
3618 // TODO: Type is expected to be LLT::float32()/LLT::float16()
3619 // FIXME: Do we need just output?
3620 if (Ty == F32 &&
3622 return true;
3623 if (Ty == F16 &&
3625 return true;
3626
3627 MachineIRBuilder HelperBuilder(MI);
3628 GISelObserverWrapper DummyObserver;
3629 LegalizerHelper Helper(MF, DummyObserver, HelperBuilder);
3630 return Helper.lowerFMad(MI) == LegalizerHelper::Legalized;
3631}
3632
3635 Register DstReg = MI.getOperand(0).getReg();
3636 Register PtrReg = MI.getOperand(1).getReg();
3637 Register CmpVal = MI.getOperand(2).getReg();
3638 Register NewVal = MI.getOperand(3).getReg();
3639
3641 "this should not have been custom lowered");
3642
3643 LLT ValTy = MRI.getType(CmpVal);
3644 LLT VecTy = LLT::fixed_vector(2, ValTy);
3645
3646 Register PackedVal = B.buildBuildVector(VecTy, { NewVal, CmpVal }).getReg(0);
3647
3648 B.buildInstr(AMDGPU::G_AMDGPU_ATOMIC_CMPXCHG)
3649 .addDef(DstReg)
3650 .addUse(PtrReg)
3651 .addUse(PackedVal)
3652 .setMemRefs(MI.memoperands());
3653
3654 MI.eraseFromParent();
3655 return true;
3656}
3657
3658/// Return true if it's known that \p Src can never be an f32 denormal value.
3660 Register Src) {
3661 const MachineInstr *DefMI = MRI.getVRegDef(Src);
3662 switch (DefMI->getOpcode()) {
3663 case TargetOpcode::G_INTRINSIC: {
3665 case Intrinsic::amdgcn_frexp_mant:
3666 case Intrinsic::amdgcn_log:
3667 case Intrinsic::amdgcn_log_clamp:
3668 case Intrinsic::amdgcn_exp2:
3669 case Intrinsic::amdgcn_sqrt:
3670 return true;
3671 default:
3672 break;
3673 }
3674
3675 break;
3676 }
3677 case TargetOpcode::G_FSQRT:
3678 return true;
3679 case TargetOpcode::G_FFREXP: {
3680 if (DefMI->getOperand(0).getReg() == Src)
3681 return true;
3682 break;
3683 }
3684 case TargetOpcode::G_FPEXT: {
3685 return MRI.getType(DefMI->getOperand(1).getReg()) == F16;
3686 }
3687 default:
3688 return false;
3689 }
3690
3691 return false;
3692}
3693
3694static bool allowApproxFunc(const MachineFunction &MF, unsigned Flags) {
3695 return Flags & MachineInstr::FmAfn;
3696}
3697
3699 unsigned Flags) {
3700 return !valueIsKnownNeverF32Denorm(MF.getRegInfo(), Src) &&
3703}
3704
3705std::pair<Register, Register>
3707 unsigned Flags) const {
3708 if (!needsDenormHandlingF32(B.getMF(), Src, Flags))
3709 return {};
3710
3711 auto SmallestNormal = B.buildFConstant(
3713 auto IsLtSmallestNormal =
3714 B.buildFCmp(CmpInst::FCMP_OLT, LLT::scalar(1), Src, SmallestNormal);
3715
3716 auto Scale32 = B.buildFConstant(F32, 0x1.0p+32);
3717 auto One = B.buildFConstant(F32, 1.0);
3718 auto ScaleFactor =
3719 B.buildSelect(F32, IsLtSmallestNormal, Scale32, One, Flags);
3720 auto ScaledInput = B.buildFMul(F32, Src, ScaleFactor, Flags);
3721
3722 return {ScaledInput.getReg(0), IsLtSmallestNormal.getReg(0)};
3723}
3724
3726 MachineIRBuilder &B) const {
3727 // v_log_f32 is good enough for OpenCL, except it doesn't handle denormals.
3728 // If we have to handle denormals, scale up the input and adjust the result.
3729
3730 // scaled = x * (is_denormal ? 0x1.0p+32 : 1.0)
3731 // log2 = amdgpu_log2 - (is_denormal ? 32.0 : 0.0)
3732
3733 Register Dst = MI.getOperand(0).getReg();
3734 Register Src = MI.getOperand(1).getReg();
3735 LLT Ty = B.getMRI()->getType(Dst);
3736 unsigned Flags = MI.getFlags();
3737
3738 if (Ty == F16) {
3739 // Nothing in half is a denormal when promoted to f32.
3740 auto Ext = B.buildFPExt(F32, Src, Flags);
3741 auto Log2 = B.buildIntrinsic(Intrinsic::amdgcn_log, {F32})
3742 .addUse(Ext.getReg(0))
3743 .setMIFlags(Flags);
3744 B.buildFPTrunc(Dst, Log2, Flags);
3745 MI.eraseFromParent();
3746 return true;
3747 }
3748
3749 assert(Ty == F32);
3750
3751 auto [ScaledInput, IsLtSmallestNormal] = getScaledLogInput(B, Src, Flags);
3752 if (!ScaledInput) {
3753 B.buildIntrinsic(Intrinsic::amdgcn_log, {MI.getOperand(0)})
3754 .addUse(Src)
3755 .setMIFlags(Flags);
3756 MI.eraseFromParent();
3757 return true;
3758 }
3759
3760 auto Log2 = B.buildIntrinsic(Intrinsic::amdgcn_log, {Ty})
3761 .addUse(ScaledInput)
3762 .setMIFlags(Flags);
3763
3764 auto ThirtyTwo = B.buildFConstant(Ty, 32.0);
3765 auto Zero = B.buildFConstant(Ty, 0.0);
3766 auto ResultOffset =
3767 B.buildSelect(Ty, IsLtSmallestNormal, ThirtyTwo, Zero, Flags);
3768 B.buildFSub(Dst, Log2, ResultOffset, Flags);
3769
3770 MI.eraseFromParent();
3771 return true;
3772}
3773
3775 Register Z, unsigned Flags) {
3776 auto FMul = B.buildFMul(Ty, X, Y, Flags);
3777 return B.buildFAdd(Ty, FMul, Z, Flags).getReg(0);
3778}
3779
3781 MachineIRBuilder &B) const {
3782 const bool IsLog10 = MI.getOpcode() == TargetOpcode::G_FLOG10;
3783 assert(IsLog10 || MI.getOpcode() == TargetOpcode::G_FLOG);
3784
3785 MachineRegisterInfo &MRI = *B.getMRI();
3786 Register Dst = MI.getOperand(0).getReg();
3787 Register X = MI.getOperand(1).getReg();
3788 unsigned Flags = MI.getFlags();
3789 const LLT Ty = MRI.getType(X);
3790
3791 if (Ty == F16 || MI.getFlag(MachineInstr::FmAfn)) {
3792 // TODO: The direct f16 path is 1.79 ulp for f16. This should be used
3793 // depending on !fpmath metadata.
3794 bool PromoteToF32 =
3795 Ty == F16 && (!MI.getFlag(MachineInstr::FmAfn) || !ST.has16BitInsts());
3796 if (PromoteToF32) {
3798 auto PromoteSrc = B.buildFPExt(F32, X, Flags);
3799 legalizeFlogUnsafe(B, LogVal, PromoteSrc.getReg(0), IsLog10, Flags);
3800 B.buildFPTrunc(Dst, LogVal, Flags);
3801 } else {
3802 legalizeFlogUnsafe(B, Dst, X, IsLog10, Flags);
3803 }
3804
3805 MI.eraseFromParent();
3806 return true;
3807 }
3808
3809 auto [ScaledInput, IsScaled] = getScaledLogInput(B, X, Flags);
3810 if (ScaledInput)
3811 X = ScaledInput;
3812
3813 auto Y =
3814 B.buildIntrinsic(Intrinsic::amdgcn_log, {Ty}).addUse(X).setMIFlags(Flags);
3815
3816 Register R;
3817 if (ST.hasFastFMAF32()) {
3818 // c+cc are ln(2)/ln(10) to more than 49 bits
3819 const float c_log10 = 0x1.344134p-2f;
3820 const float cc_log10 = 0x1.09f79ep-26f;
3821
3822 // c + cc is ln(2) to more than 49 bits
3823 const float c_log = 0x1.62e42ep-1f;
3824 const float cc_log = 0x1.efa39ep-25f;
3825
3826 auto C = B.buildFConstant(Ty, IsLog10 ? c_log10 : c_log);
3827 auto CC = B.buildFConstant(Ty, IsLog10 ? cc_log10 : cc_log);
3828 // This adds correction terms for which contraction may lead to an increase
3829 // in the error of the approximation, so disable it.
3830 auto NewFlags = Flags & ~(MachineInstr::FmContract);
3831 R = B.buildFMul(Ty, Y, C, NewFlags).getReg(0);
3832 auto NegR = B.buildFNeg(Ty, R, NewFlags);
3833 auto FMA0 = B.buildFMA(Ty, Y, C, NegR, NewFlags);
3834 auto FMA1 = B.buildFMA(Ty, Y, CC, FMA0, NewFlags);
3835 R = B.buildFAdd(Ty, R, FMA1, NewFlags).getReg(0);
3836 } else {
3837 // ch+ct is ln(2)/ln(10) to more than 36 bits
3838 const float ch_log10 = 0x1.344000p-2f;
3839 const float ct_log10 = 0x1.3509f6p-18f;
3840
3841 // ch + ct is ln(2) to more than 36 bits
3842 const float ch_log = 0x1.62e000p-1f;
3843 const float ct_log = 0x1.0bfbe8p-15f;
3844
3845 auto CH = B.buildFConstant(Ty, IsLog10 ? ch_log10 : ch_log);
3846 auto CT = B.buildFConstant(Ty, IsLog10 ? ct_log10 : ct_log);
3847
3848 const LLT I32 = LLT::integer(32);
3849 auto YInt = B.buildBitcast(I32, Y);
3850 auto MaskConst = B.buildConstant(I32, 0xfffff000);
3851 auto YH = B.buildBitcast(Ty, B.buildAnd(I32, YInt, MaskConst));
3852 auto YT = B.buildFSub(Ty, Y, YH, Flags);
3853 // This adds correction terms for which contraction may lead to an increase
3854 // in the error of the approximation, so disable it.
3855 auto NewFlags = Flags & ~(MachineInstr::FmContract);
3856 auto YTCT = B.buildFMul(Ty, YT, CT, NewFlags);
3857
3858 Register Mad0 =
3859 getMad(B, Ty, YH.getReg(0), CT.getReg(0), YTCT.getReg(0), NewFlags);
3860 Register Mad1 = getMad(B, Ty, YT.getReg(0), CH.getReg(0), Mad0, NewFlags);
3861 R = getMad(B, Ty, YH.getReg(0), CH.getReg(0), Mad1, NewFlags);
3862 }
3863
3864 const bool IsFiniteOnly =
3866
3867 if (!IsFiniteOnly) {
3868 // Expand isfinite(x) => fabs(x) < inf
3869 auto Inf = B.buildFConstant(Ty, APFloat::getInf(APFloat::IEEEsingle()));
3870 auto Fabs = B.buildFAbs(Ty, Y);
3871 auto IsFinite =
3872 B.buildFCmp(CmpInst::FCMP_OLT, LLT::scalar(1), Fabs, Inf, Flags);
3873 R = B.buildSelect(Ty, IsFinite, R, Y, Flags).getReg(0);
3874 }
3875
3876 if (ScaledInput) {
3877 auto Zero = B.buildFConstant(Ty, 0.0);
3878 auto ShiftK =
3879 B.buildFConstant(Ty, IsLog10 ? 0x1.344136p+3f : 0x1.62e430p+4f);
3880 auto Shift = B.buildSelect(Ty, IsScaled, ShiftK, Zero, Flags);
3881 B.buildFSub(Dst, R, Shift, Flags);
3882 } else {
3883 B.buildCopy(Dst, R);
3884 }
3885
3886 MI.eraseFromParent();
3887 return true;
3888}
3889
3891 Register Src, bool IsLog10,
3892 unsigned Flags) const {
3893 const double Log2BaseInverted =
3895
3896 LLT Ty = B.getMRI()->getType(Dst);
3897
3898 if (Ty == F32) {
3899 auto [ScaledInput, IsScaled] = getScaledLogInput(B, Src, Flags);
3900 if (ScaledInput) {
3901 auto LogSrc = B.buildIntrinsic(Intrinsic::amdgcn_log, {Ty})
3902 .addUse(ScaledInput)
3903 .setMIFlags(Flags);
3904 auto ScaledResultOffset = B.buildFConstant(Ty, -32.0 * Log2BaseInverted);
3905 auto Zero = B.buildFConstant(Ty, 0.0);
3906 auto ResultOffset =
3907 B.buildSelect(Ty, IsScaled, ScaledResultOffset, Zero, Flags);
3908 auto Log2Inv = B.buildFConstant(Ty, Log2BaseInverted);
3909
3910 if (ST.hasFastFMAF32())
3911 B.buildFMA(Dst, LogSrc, Log2Inv, ResultOffset, Flags);
3912 else {
3913 auto Mul = B.buildFMul(Ty, LogSrc, Log2Inv, Flags);
3914 B.buildFAdd(Dst, Mul, ResultOffset, Flags);
3915 }
3916
3917 return true;
3918 }
3919 }
3920
3921 auto Log2Operand = Ty == F16 ? B.buildFLog2(Ty, Src, Flags)
3922 : B.buildIntrinsic(Intrinsic::amdgcn_log, {Ty})
3923 .addUse(Src)
3924 .setMIFlags(Flags);
3925 auto Log2BaseInvertedOperand = B.buildFConstant(Ty, Log2BaseInverted);
3926 B.buildFMul(Dst, Log2Operand, Log2BaseInvertedOperand, Flags);
3927 return true;
3928}
3929
3931 MachineIRBuilder &B) const {
3932 // v_exp_f32 is good enough for OpenCL, except it doesn't handle denormals.
3933 // If we have to handle denormals, scale up the input and adjust the result.
3934
3935 Register Dst = MI.getOperand(0).getReg();
3936 Register Src = MI.getOperand(1).getReg();
3937 unsigned Flags = MI.getFlags();
3938 LLT Ty = B.getMRI()->getType(Dst);
3939
3940 if (Ty == F64)
3941 return legalizeFEXPF64(MI, B);
3942
3943 if (Ty == F16) {
3944 // Nothing in half is a denormal when promoted to f32.
3945 auto Ext = B.buildFPExt(F32, Src, Flags);
3946 auto Log2 = B.buildIntrinsic(Intrinsic::amdgcn_exp2, {F32})
3947 .addUse(Ext.getReg(0))
3948 .setMIFlags(Flags);
3949 B.buildFPTrunc(Dst, Log2, Flags);
3950 MI.eraseFromParent();
3951 return true;
3952 }
3953
3954 assert(Ty == F32);
3955
3956 if (!needsDenormHandlingF32(B.getMF(), Src, Flags)) {
3957 B.buildIntrinsic(Intrinsic::amdgcn_exp2, ArrayRef<Register>{Dst})
3958 .addUse(Src)
3959 .setMIFlags(Flags);
3960 MI.eraseFromParent();
3961 return true;
3962 }
3963
3964 // bool needs_scaling = x < -0x1.f80000p+6f;
3965 // v_exp_f32(x + (s ? 0x1.0p+6f : 0.0f)) * (s ? 0x1.0p-64f : 1.0f);
3966
3967 // -nextafter(128.0, -1)
3968 auto RangeCheckConst = B.buildFConstant(Ty, -0x1.f80000p+6f);
3969 auto NeedsScaling = B.buildFCmp(CmpInst::FCMP_OLT, LLT::scalar(1), Src,
3970 RangeCheckConst, Flags);
3971
3972 auto SixtyFour = B.buildFConstant(Ty, 0x1.0p+6f);
3973 auto Zero = B.buildFConstant(Ty, 0.0);
3974 auto AddOffset = B.buildSelect(F32, NeedsScaling, SixtyFour, Zero, Flags);
3975 auto AddInput = B.buildFAdd(F32, Src, AddOffset, Flags);
3976
3977 auto Exp2 = B.buildIntrinsic(Intrinsic::amdgcn_exp2, {Ty})
3978 .addUse(AddInput.getReg(0))
3979 .setMIFlags(Flags);
3980
3981 auto TwoExpNeg64 = B.buildFConstant(Ty, 0x1.0p-64f);
3982 auto One = B.buildFConstant(Ty, 1.0);
3983 auto ResultScale = B.buildSelect(F32, NeedsScaling, TwoExpNeg64, One, Flags);
3984 B.buildFMul(Dst, Exp2, ResultScale, Flags);
3985 MI.eraseFromParent();
3986 return true;
3987}
3988
3990 const SrcOp &Src, unsigned Flags) {
3991 LLT Ty = Dst.getLLTTy(*B.getMRI());
3992
3993 if (Ty == F32) {
3994 return B.buildIntrinsic(Intrinsic::amdgcn_exp2, {Dst})
3995 .addUse(Src.getReg())
3996 .setMIFlags(Flags);
3997 }
3998 return B.buildFExp2(Dst, Src, Flags);
3999}
4000
4002 Register Dst, Register X,
4003 unsigned Flags,
4004 bool IsExp10) const {
4005 LLT Ty = B.getMRI()->getType(X);
4006
4007 // exp(x) -> exp2(M_LOG2E_F * x);
4008 // exp10(x) -> exp2(log2(10) * x);
4009 auto Const = B.buildFConstant(Ty, IsExp10 ? 0x1.a934f0p+1f : numbers::log2e);
4010 auto Mul = B.buildFMul(Ty, X, Const, Flags);
4011 buildExp(B, Dst, Mul, Flags);
4012 return true;
4013}
4014
4016 Register X, unsigned Flags) const {
4017 LLT Ty = B.getMRI()->getType(Dst);
4018
4019 if (Ty != F32 || !needsDenormHandlingF32(B.getMF(), X, Flags)) {
4020 return legalizeFExpUnsafeImpl(B, Dst, X, Flags, /*IsExp10=*/false);
4021 }
4022
4023 auto Threshold = B.buildFConstant(Ty, -0x1.5d58a0p+6f);
4024 auto NeedsScaling =
4025 B.buildFCmp(CmpInst::FCMP_OLT, LLT::scalar(1), X, Threshold, Flags);
4026 auto ScaleOffset = B.buildFConstant(Ty, 0x1.0p+6f);
4027 auto ScaledX = B.buildFAdd(Ty, X, ScaleOffset, Flags);
4028 auto AdjustedX = B.buildSelect(Ty, NeedsScaling, ScaledX, X, Flags);
4029
4030 auto Log2E = B.buildFConstant(Ty, numbers::log2e);
4031 auto ExpInput = B.buildFMul(Ty, AdjustedX, Log2E, Flags);
4032
4033 auto Exp2 = B.buildIntrinsic(Intrinsic::amdgcn_exp2, {Ty})
4034 .addUse(ExpInput.getReg(0))
4035 .setMIFlags(Flags);
4036
4037 auto ResultScaleFactor = B.buildFConstant(Ty, 0x1.969d48p-93f);
4038 auto AdjustedResult = B.buildFMul(Ty, Exp2, ResultScaleFactor, Flags);
4039 B.buildSelect(Dst, NeedsScaling, AdjustedResult, Exp2, Flags);
4040 return true;
4041}
4042
4044 Register Dst, Register X,
4045 unsigned Flags) const {
4046 LLT Ty = B.getMRI()->getType(Dst);
4047
4048 if (Ty != F32 || !needsDenormHandlingF32(B.getMF(), X, Flags)) {
4049 // exp2(x * 0x1.a92000p+1f) * exp2(x * 0x1.4f0978p-11f);
4050 auto K0 = B.buildFConstant(Ty, 0x1.a92000p+1f);
4051 auto K1 = B.buildFConstant(Ty, 0x1.4f0978p-11f);
4052
4053 auto Mul1 = B.buildFMul(Ty, X, K1, Flags);
4054 auto Exp2_1 = buildExp(B, Ty, Mul1, Flags);
4055 auto Mul0 = B.buildFMul(Ty, X, K0, Flags);
4056 auto Exp2_0 = buildExp(B, Ty, Mul0, Flags);
4057 B.buildFMul(Dst, Exp2_0, Exp2_1, Flags);
4058 return true;
4059 }
4060
4061 // bool s = x < -0x1.2f7030p+5f;
4062 // x += s ? 0x1.0p+5f : 0.0f;
4063 // exp10 = exp2(x * 0x1.a92000p+1f) *
4064 // exp2(x * 0x1.4f0978p-11f) *
4065 // (s ? 0x1.9f623ep-107f : 1.0f);
4066
4067 auto Threshold = B.buildFConstant(Ty, -0x1.2f7030p+5f);
4068 auto NeedsScaling =
4069 B.buildFCmp(CmpInst::FCMP_OLT, LLT::scalar(1), X, Threshold);
4070
4071 auto ScaleOffset = B.buildFConstant(Ty, 0x1.0p+5f);
4072 auto ScaledX = B.buildFAdd(Ty, X, ScaleOffset, Flags);
4073 auto AdjustedX = B.buildSelect(Ty, NeedsScaling, ScaledX, X);
4074
4075 auto K0 = B.buildFConstant(Ty, 0x1.a92000p+1f);
4076 auto K1 = B.buildFConstant(Ty, 0x1.4f0978p-11f);
4077
4078 auto Mul1 = B.buildFMul(Ty, AdjustedX, K1, Flags);
4079 auto Exp2_1 = buildExp(B, Ty, Mul1, Flags);
4080 auto Mul0 = B.buildFMul(Ty, AdjustedX, K0, Flags);
4081 auto Exp2_0 = buildExp(B, Ty, Mul0, Flags);
4082
4083 auto MulExps = B.buildFMul(Ty, Exp2_0, Exp2_1, Flags);
4084 auto ResultScaleFactor = B.buildFConstant(Ty, 0x1.9f623ep-107f);
4085 auto AdjustedResult = B.buildFMul(Ty, MulExps, ResultScaleFactor, Flags);
4086
4087 B.buildSelect(Dst, NeedsScaling, AdjustedResult, MulExps);
4088 return true;
4089}
4090
4091// This expansion gives a result slightly better than 1ulp.
4093 MachineIRBuilder &B) const {
4094
4095 Register X = MI.getOperand(1).getReg();
4096 LLT I32 = LLT::integer(32);
4097 LLT S1 = LLT::scalar(1);
4098
4099 // TODO: Check if reassoc is safe. There is an output change in exp2 and
4100 // exp10, which slightly increases ulp.
4101 unsigned Flags = MI.getFlags() & ~MachineInstr::FmReassoc;
4102
4103 Register Dn, F, T;
4104
4105 if (MI.getOpcode() == TargetOpcode::G_FEXP2) {
4106 // Dn = rint(X)
4107 Dn = B.buildFRint(F64, X, Flags).getReg(0);
4108 // F = X - Dn
4109 F = B.buildFSub(F64, X, Dn, Flags).getReg(0);
4110 // T = F*C1 + F*C2
4111 auto C1 = B.buildFConstant(F64, APFloat(0x1.62e42fefa39efp-1));
4112 auto C2 = B.buildFConstant(F64, APFloat(0x1.abc9e3b39803fp-56));
4113 auto Mul2 = B.buildFMul(F64, F, C2, Flags).getReg(0);
4114 T = B.buildFMA(F64, F, C1, Mul2, Flags).getReg(0);
4115
4116 } else if (MI.getOpcode() == TargetOpcode::G_FEXP10) {
4117 auto C1 = B.buildFConstant(F64, APFloat(0x1.a934f0979a371p+1));
4118 auto Mul = B.buildFMul(F64, X, C1, Flags).getReg(0);
4119 Dn = B.buildFRint(F64, Mul, Flags).getReg(0);
4120
4121 auto NegDn = B.buildFNeg(F64, Dn, Flags).getReg(0);
4122 auto C2 = B.buildFConstant(F64, APFloat(-0x1.9dc1da994fd21p-59));
4123 auto C3 = B.buildFConstant(F64, APFloat(0x1.34413509f79ffp-2));
4124 auto Inner = B.buildFMA(F64, NegDn, C3, X, Flags).getReg(0);
4125 F = B.buildFMA(F64, NegDn, C2, Inner, Flags).getReg(0);
4126
4127 auto C4 = B.buildFConstant(F64, APFloat(0x1.26bb1bbb55516p+1));
4128 auto C5 = B.buildFConstant(F64, APFloat(-0x1.f48ad494ea3e9p-53));
4129 auto MulF = B.buildFMul(F64, F, C5, Flags).getReg(0);
4130 T = B.buildFMA(F64, F, C4, MulF, Flags).getReg(0);
4131
4132 } else { // G_FEXP
4133 auto C1 = B.buildFConstant(F64, APFloat(0x1.71547652b82fep+0));
4134 auto Mul = B.buildFMul(F64, X, C1, Flags).getReg(0);
4135 Dn = B.buildFRint(F64, Mul, Flags).getReg(0);
4136
4137 auto NegDn = B.buildFNeg(F64, Dn, Flags).getReg(0);
4138 auto C2 = B.buildFConstant(F64, APFloat(0x1.abc9e3b39803fp-56));
4139 auto C3 = B.buildFConstant(F64, APFloat(0x1.62e42fefa39efp-1));
4140 auto Inner = B.buildFMA(F64, NegDn, C3, X, Flags).getReg(0);
4141 T = B.buildFMA(F64, NegDn, C2, Inner, Flags).getReg(0);
4142 }
4143
4144 // Polynomial chain for P
4145 auto P = B.buildFConstant(F64, 0x1.ade156a5dcb37p-26);
4146 P = B.buildFMA(F64, T, P, B.buildFConstant(F64, 0x1.28af3fca7ab0cp-22),
4147 Flags);
4148 P = B.buildFMA(F64, T, P, B.buildFConstant(F64, 0x1.71dee623fde64p-19),
4149 Flags);
4150 P = B.buildFMA(F64, T, P, B.buildFConstant(F64, 0x1.a01997c89e6b0p-16),
4151 Flags);
4152 P = B.buildFMA(F64, T, P, B.buildFConstant(F64, 0x1.a01a014761f6ep-13),
4153 Flags);
4154 P = B.buildFMA(F64, T, P, B.buildFConstant(F64, 0x1.6c16c1852b7b0p-10),
4155 Flags);
4156 P = B.buildFMA(F64, T, P, B.buildFConstant(F64, 0x1.1111111122322p-7), Flags);
4157 P = B.buildFMA(F64, T, P, B.buildFConstant(F64, 0x1.55555555502a1p-5), Flags);
4158 P = B.buildFMA(F64, T, P, B.buildFConstant(F64, 0x1.5555555555511p-3), Flags);
4159 P = B.buildFMA(F64, T, P, B.buildFConstant(F64, 0x1.000000000000bp-1), Flags);
4160
4161 auto One = B.buildFConstant(F64, 1.0);
4162 P = B.buildFMA(F64, T, P, One, Flags);
4163 P = B.buildFMA(F64, T, P, One, Flags);
4164
4165 // Z = FLDEXP(P, (int)Dn)
4166 auto DnInt = B.buildFPTOSI(I32, Dn);
4167 auto Z = B.buildFLdexp(F64, P, DnInt, Flags);
4168
4169 if (!(Flags & MachineInstr::FmNoInfs)) {
4170 // Overflow guard: if X <= 1024.0 then Z else +inf
4171 auto CondHi = B.buildFCmp(CmpInst::FCMP_ULE, S1, X,
4172 B.buildFConstant(F64, APFloat(1024.0)));
4173 auto PInf = B.buildFConstant(F64, APFloat::getInf(APFloat::IEEEdouble()));
4174 Z = B.buildSelect(F64, CondHi, Z, PInf, Flags);
4175 }
4176
4177 // Underflow guard: if X >= -1075.0 then Z else 0.0
4178 auto CondLo = B.buildFCmp(CmpInst::FCMP_UGE, S1, X,
4179 B.buildFConstant(F64, APFloat(-1075.0)));
4180 auto Zero = B.buildFConstant(F64, APFloat(0.0));
4181 B.buildSelect(MI.getOperand(0).getReg(), CondLo, Z, Zero, Flags);
4182
4183 MI.eraseFromParent();
4184 return true;
4185}
4186
4188 MachineIRBuilder &B) const {
4189 Register Dst = MI.getOperand(0).getReg();
4190 Register X = MI.getOperand(1).getReg();
4191 const unsigned Flags = MI.getFlags();
4192 MachineFunction &MF = B.getMF();
4193 MachineRegisterInfo &MRI = *B.getMRI();
4194 LLT Ty = MRI.getType(Dst);
4195
4196 if (Ty == F64)
4197 return legalizeFEXPF64(MI, B);
4198
4199 const bool IsExp10 = MI.getOpcode() == TargetOpcode::G_FEXP10;
4200
4201 if (Ty == F16) {
4202 // v_exp_f16 (fmul x, log2e)
4203 if (allowApproxFunc(MF, Flags)) {
4204 // TODO: Does this really require fast?
4205 IsExp10 ? legalizeFExp10Unsafe(B, Dst, X, Flags)
4206 : legalizeFExpUnsafe(B, Dst, X, Flags);
4207 MI.eraseFromParent();
4208 return true;
4209 }
4210
4211 // Nothing in half is a denormal when promoted to f32.
4212 //
4213 // exp(f16 x) ->
4214 // fptrunc (v_exp_f32 (fmul (fpext x), log2e))
4215 //
4216 // exp10(f16 x) ->
4217 // fptrunc (v_exp_f32 (fmul (fpext x), log2(10)))
4218 auto Ext = B.buildFPExt(F32, X, Flags);
4220 legalizeFExpUnsafeImpl(B, Lowered, Ext.getReg(0), Flags, IsExp10);
4221 B.buildFPTrunc(Dst, Lowered, Flags);
4222 MI.eraseFromParent();
4223 return true;
4224 }
4225
4226 assert(Ty == F32);
4227
4228 // TODO: Interpret allowApproxFunc as ignoring DAZ. This is currently copying
4229 // library behavior. Also, is known-not-daz source sufficient?
4230 if (allowApproxFunc(MF, Flags)) {
4231 IsExp10 ? legalizeFExp10Unsafe(B, Dst, X, Flags)
4232 : legalizeFExpUnsafe(B, Dst, X, Flags);
4233 MI.eraseFromParent();
4234 return true;
4235 }
4236
4237 // Algorithm:
4238 //
4239 // e^x = 2^(x/ln(2)) = 2^(x*(64/ln(2))/64)
4240 //
4241 // x*(64/ln(2)) = n + f, |f| <= 0.5, n is integer
4242 // n = 64*m + j, 0 <= j < 64
4243 //
4244 // e^x = 2^((64*m + j + f)/64)
4245 // = (2^m) * (2^(j/64)) * 2^(f/64)
4246 // = (2^m) * (2^(j/64)) * e^(f*(ln(2)/64))
4247 //
4248 // f = x*(64/ln(2)) - n
4249 // r = f*(ln(2)/64) = x - n*(ln(2)/64)
4250 //
4251 // e^x = (2^m) * (2^(j/64)) * e^r
4252 //
4253 // (2^(j/64)) is precomputed
4254 //
4255 // e^r = 1 + r + (r^2)/2! + (r^3)/3! + (r^4)/4! + (r^5)/5!
4256 // e^r = 1 + q
4257 //
4258 // q = r + (r^2)/2! + (r^3)/3! + (r^4)/4! + (r^5)/5!
4259 //
4260 // e^x = (2^m) * ( (2^(j/64)) + q*(2^(j/64)) )
4261 const unsigned FlagsNoContract = Flags & ~MachineInstr::FmContract;
4262 Register PH, PL;
4263
4264 if (ST.hasFastFMAF32()) {
4265 const float c_exp = numbers::log2ef;
4266 const float cc_exp = 0x1.4ae0bep-26f; // c+cc are 49 bits
4267 const float c_exp10 = 0x1.a934f0p+1f;
4268 const float cc_exp10 = 0x1.2f346ep-24f;
4269
4270 auto C = B.buildFConstant(Ty, IsExp10 ? c_exp10 : c_exp);
4271 PH = B.buildFMul(Ty, X, C, Flags).getReg(0);
4272 auto NegPH = B.buildFNeg(Ty, PH, Flags);
4273 auto FMA0 = B.buildFMA(Ty, X, C, NegPH, Flags);
4274
4275 auto CC = B.buildFConstant(Ty, IsExp10 ? cc_exp10 : cc_exp);
4276 PL = B.buildFMA(Ty, X, CC, FMA0, Flags).getReg(0);
4277 } else {
4278 const float ch_exp = 0x1.714000p+0f;
4279 const float cl_exp = 0x1.47652ap-12f; // ch + cl are 36 bits
4280
4281 const float ch_exp10 = 0x1.a92000p+1f;
4282 const float cl_exp10 = 0x1.4f0978p-11f;
4283
4284 const LLT I32 = LLT::integer(32);
4285 auto XInt = B.buildBitcast(I32, X);
4286 auto MaskConst = B.buildConstant(I32, 0xfffff000);
4287 auto XH = B.buildBitcast(Ty, B.buildAnd(I32, XInt, MaskConst));
4288 auto XL = B.buildFSub(Ty, X, XH, Flags);
4289
4290 auto CH = B.buildFConstant(Ty, IsExp10 ? ch_exp10 : ch_exp);
4291 PH = B.buildFMul(Ty, XH, CH, Flags).getReg(0);
4292
4293 auto CL = B.buildFConstant(Ty, IsExp10 ? cl_exp10 : cl_exp);
4294 auto XLCL = B.buildFMul(Ty, XL, CL, Flags);
4295
4296 Register Mad0 =
4297 getMad(B, Ty, XL.getReg(0), CH.getReg(0), XLCL.getReg(0), Flags);
4298 PL = getMad(B, Ty, XH.getReg(0), CL.getReg(0), Mad0, Flags);
4299 }
4300
4301 auto E = B.buildIntrinsicRoundeven(Ty, PH, Flags);
4302
4303 // It is unsafe to contract this fsub into the PH multiply.
4304 auto PHSubE = B.buildFSub(Ty, PH, E, FlagsNoContract);
4305 auto A = B.buildFAdd(Ty, PHSubE, PL, Flags);
4306 const LLT I32 = LLT::integer(32);
4307 auto IntE = B.buildFPTOSI(I32, E);
4308
4309 auto Exp2 = B.buildIntrinsic(Intrinsic::amdgcn_exp2, {Ty})
4310 .addUse(A.getReg(0))
4311 .setMIFlags(Flags);
4312 auto R = B.buildFLdexp(Ty, Exp2, IntE, Flags);
4313
4314 auto UnderflowCheckConst =
4315 B.buildFConstant(Ty, IsExp10 ? -0x1.66d3e8p+5f : -0x1.9d1da0p+6f);
4316 auto Zero = B.buildFConstant(Ty, 0.0);
4317 auto Underflow =
4318 B.buildFCmp(CmpInst::FCMP_OLT, LLT::scalar(1), X, UnderflowCheckConst);
4319
4320 R = B.buildSelect(Ty, Underflow, Zero, R);
4321
4322 if (!(Flags & MachineInstr::FmNoInfs)) {
4323 auto OverflowCheckConst =
4324 B.buildFConstant(Ty, IsExp10 ? 0x1.344136p+5f : 0x1.62e430p+6f);
4325
4326 auto Overflow =
4327 B.buildFCmp(CmpInst::FCMP_OGT, LLT::scalar(1), X, OverflowCheckConst);
4328 auto Inf = B.buildFConstant(Ty, APFloat::getInf(APFloat::IEEEsingle()));
4329 R = B.buildSelect(Ty, Overflow, Inf, R, Flags);
4330 }
4331
4332 B.buildCopy(Dst, R);
4333 MI.eraseFromParent();
4334 return true;
4335}
4336
4337// Keep in sync with AMDGPUTargetLowering::lowerFPOW, which documents this.
4339 MachineInstr &MI) const {
4340 MachineIRBuilder &B = Helper.MIRBuilder;
4341 Register Dst = MI.getOperand(0).getReg();
4342 Register X = MI.getOperand(1).getReg();
4343 Register Y = MI.getOperand(2).getReg();
4344 unsigned Flags = MI.getFlags();
4345 assert(B.getMRI()->getType(Dst) == F32);
4346
4347 // log2(0) is -inf, which exp2 turns back into a finite result, so the core
4348 // goes infinite for inputs a ninf fpow still asserts about, like pow(0, 2).
4349 unsigned CoreFlags = Flags & ~MachineInstr::FmNoInfs;
4350
4351 // Fast expansion: ignores denormals, NaN for a negative base.
4352 if (allowApproxFunc(B.getMF(), Flags)) {
4353 auto Log = B.buildIntrinsic(Intrinsic::amdgcn_log, {F32})
4354 .addUse(X)
4355 .setMIFlags(CoreFlags);
4356 auto Mul = B.buildIntrinsic(Intrinsic::amdgcn_fmul_legacy, {F32})
4357 .addUse(Y)
4358 .addUse(Log.getReg(0))
4359 .setMIFlags(CoreFlags);
4360 buildExp(B, Dst, Mul.getReg(0), CoreFlags);
4361 MI.eraseFromParent();
4362 return true;
4363 }
4364
4365 auto Abs = B.buildFAbs(F32, X, Flags);
4366 auto Log = B.buildFLog2(F32, Abs, CoreFlags);
4367 auto Mul = B.buildIntrinsic(Intrinsic::amdgcn_fmul_legacy, {F32})
4368 .addUse(Y)
4369 .addUse(Log.getReg(0))
4370 .setMIFlags(CoreFlags);
4371
4372 // A base that is never negative needs neither the sign fixup nor the NaN.
4373 if (Helper.getValueTracking()
4374 ->computeKnownFPClass(X, Flags, fcNegative, 0)
4375 .signBitIsZeroOrNaN()) {
4376 B.buildFExp2(Dst, Mul, CoreFlags);
4377 MI.eraseFromParent();
4378 return true;
4379 }
4380
4381 Register R = B.buildFExp2(F32, Mul, CoreFlags).getReg(0);
4382
4383 auto YTrunc = B.buildIntrinsicTrunc(F32, Y);
4384 auto YIsInt = B.buildFCmp(CmpInst::FCMP_OEQ, S1, YTrunc, Y);
4385 auto YHalf = B.buildFMul(F32, Y, B.buildFConstant(F32, 0.5));
4386 auto YHalfTrunc = B.buildIntrinsicTrunc(F32, YHalf);
4387 auto YIsOdd = B.buildAnd(
4388 S1, YIsInt, B.buildFCmp(CmpInst::FCMP_ONE, S1, YHalfTrunc, YHalf));
4389
4390 // pow(-x, odd y) = -pow(x, y). Selecting the copysign lets even y fold it.
4391 auto Neg = B.buildFCopysign(F32, R, X);
4392 if (Flags & MachineInstr::FmNoNans) {
4393 B.buildSelect(Dst, YIsOdd, Neg, R);
4394 MI.eraseFromParent();
4395 return true;
4396 }
4397 R = B.buildSelect(F32, YIsOdd, Neg, R).getReg(0);
4398
4399 // A negative finite base to a non-integral power is NaN. -inf is excluded:
4400 // the core already gives pow(+inf, y). So are subnormals when flushed.
4401 FPClassTest NegFiniteMask = fcNegNormal;
4402 if (!B.getMF().getDenormalMode(APFloat::IEEEsingle()).inputsAreZero())
4403 NegFiniteMask |= fcNegSubnormal;
4404 auto XNegFinite = B.buildIsFPClass(S1, X, NegFiniteMask);
4405 // Not an ONE compare: pow(-1, NaN) needs the NaN-true behavior of !OEQ.
4406 auto NegNonInt = B.buildAnd(S1, XNegFinite, B.buildNot(S1, YIsInt));
4407 auto NaN = B.buildFConstant(F32, APFloat::getQNaN(APFloat::IEEEsingle()));
4408 B.buildSelect(Dst, NegNonInt, NaN, R);
4409
4410 MI.eraseFromParent();
4411 return true;
4412}
4413
4414// Find a source register, ignoring any possible source modifiers.
4416 Register ModSrc = OrigSrc;
4417 if (MachineInstr *SrcFNeg = getOpcodeDef(AMDGPU::G_FNEG, ModSrc, MRI)) {
4418 ModSrc = SrcFNeg->getOperand(1).getReg();
4419 if (MachineInstr *SrcFAbs = getOpcodeDef(AMDGPU::G_FABS, ModSrc, MRI))
4420 ModSrc = SrcFAbs->getOperand(1).getReg();
4421 } else if (MachineInstr *SrcFAbs = getOpcodeDef(AMDGPU::G_FABS, ModSrc, MRI))
4422 ModSrc = SrcFAbs->getOperand(1).getReg();
4423 return ModSrc;
4424}
4425
4428 MachineIRBuilder &B) const {
4429
4430 const LLT S1 = LLT::scalar(1);
4431 Register Dst = MI.getOperand(0).getReg();
4432 Register OrigSrc = MI.getOperand(1).getReg();
4433 unsigned Flags = MI.getFlags();
4434 assert(ST.hasFractBug() && MRI.getType(Dst) == F64 &&
4435 "this should not have been custom lowered");
4436
4437 // V_FRACT is buggy on SI, so the F32 version is never used and (x-floor(x))
4438 // is used instead. However, SI doesn't have V_FLOOR_F64, so the most
4439 // efficient way to implement it is using V_FRACT_F64. The workaround for the
4440 // V_FRACT bug is:
4441 // fract(x) = isnan(x) ? x : min(V_FRACT(x), 0.99999999999999999)
4442 //
4443 // Convert floor(x) to (x - fract(x))
4444
4445 auto Fract = B.buildIntrinsic(Intrinsic::amdgcn_fract, {F64})
4446 .addUse(OrigSrc)
4447 .setMIFlags(Flags);
4448
4449 // Give source modifier matching some assistance before obscuring a foldable
4450 // pattern.
4451
4452 // TODO: We can avoid the neg on the fract? The input sign to fract
4453 // shouldn't matter?
4454 Register ModSrc = stripAnySourceMods(OrigSrc, MRI);
4455
4456 auto Const =
4457 B.buildFConstant(F64, llvm::bit_cast<double>(0x3fefffffffffffff));
4458
4460
4461 // We don't need to concern ourselves with the snan handling difference, so
4462 // use the one which will directly select.
4463 const SIMachineFunctionInfo *MFI = B.getMF().getInfo<SIMachineFunctionInfo>();
4464 if (MFI->getMode().IEEE)
4465 B.buildFMinNumIEEE(Min, Fract, Const, Flags);
4466 else
4467 B.buildFMinNum(Min, Fract, Const, Flags);
4468
4469 Register CorrectedFract = Min;
4470 if (!MI.getFlag(MachineInstr::FmNoNans)) {
4471 auto IsNan = B.buildFCmp(CmpInst::FCMP_ORD, S1, ModSrc, ModSrc, Flags);
4472 CorrectedFract = B.buildSelect(F64, IsNan, ModSrc, Min, Flags).getReg(0);
4473 }
4474
4475 auto NegFract = B.buildFNeg(F64, CorrectedFract, Flags);
4476 B.buildFAdd(Dst, OrigSrc, NegFract, Flags);
4477
4478 MI.eraseFromParent();
4479 return true;
4480}
4481
4482// Turn an illegal packed v2i16/v2f16 build vector into bit operations.
4483// TODO: This should probably be a bitcast action in LegalizerHelper.
4486 Register Dst = MI.getOperand(0).getReg();
4487 const LLT I32 = LLT::integer(32);
4488 const LLT I16 = LLT::integer(16);
4489 assert(MRI.getType(Dst).isVector() &&
4490 MRI.getType(Dst).getNumElements() == 2 &&
4491 MRI.getType(Dst).getScalarSizeInBits() == 16);
4492
4493 Register Src0 = MI.getOperand(1).getReg();
4494 Register Src1 = MI.getOperand(2).getReg();
4495
4496 if (MI.getOpcode() == AMDGPU::G_BUILD_VECTOR_TRUNC) {
4497 assert(MRI.getType(Src0) == I32);
4498 Src0 = B.buildTrunc(I16, MI.getOperand(1).getReg()).getReg(0);
4499 Src1 = B.buildTrunc(I16, MI.getOperand(2).getReg()).getReg(0);
4500 }
4501
4502 auto Merge = B.buildMergeLikeInstr(I32, {Src0, Src1});
4503 B.buildBitcast(Dst, Merge);
4504
4505 MI.eraseFromParent();
4506 return true;
4507}
4508
4509// Build a big integer multiply or multiply-add using MAD_64_32 instructions.
4510//
4511// Source and accumulation registers must all be 32-bits.
4512//
4513// TODO: When the multiply is uniform, we should produce a code sequence
4514// that is better suited to instruction selection on the SALU. Instead of
4515// the outer loop going over parts of the result, the outer loop should go
4516// over parts of one of the factors. This should result in instruction
4517// selection that makes full use of S_ADDC_U32 instructions.
4520 ArrayRef<Register> Src0,
4521 ArrayRef<Register> Src1,
4522 bool UsePartialMad64_32,
4523 bool SeparateOddAlignedProducts) const {
4524 // Use (possibly empty) vectors of S1 registers to represent the set of
4525 // carries from one pair of positions to the next.
4526 using Carry = SmallVector<Register, 2>;
4527
4528 MachineIRBuilder &B = Helper.MIRBuilder;
4529 GISelValueTracking &VT = *Helper.getValueTracking();
4530
4531 const LLT S1 = LLT::scalar(1);
4532 const LLT I32 = LLT::integer(32);
4533 const LLT I64 = LLT::integer(64);
4534
4535 Register Zero32;
4536 Register Zero64;
4537
4538 auto getZero32 = [&]() -> Register {
4539 if (!Zero32)
4540 Zero32 = B.buildConstant(I32, 0).getReg(0);
4541 return Zero32;
4542 };
4543 auto getZero64 = [&]() -> Register {
4544 if (!Zero64)
4545 Zero64 = B.buildConstant(I64, 0).getReg(0);
4546 return Zero64;
4547 };
4548
4549 SmallVector<bool, 2> Src0KnownZeros, Src1KnownZeros;
4550 for (unsigned i = 0; i < Src0.size(); ++i) {
4551 Src0KnownZeros.push_back(VT.getKnownBits(Src0[i]).isZero());
4552 Src1KnownZeros.push_back(VT.getKnownBits(Src1[i]).isZero());
4553 }
4554
4555 // Merge the given carries into the 32-bit LocalAccum, which is modified
4556 // in-place.
4557 //
4558 // Returns the carry-out, which is a single S1 register or null.
4559 auto mergeCarry =
4560 [&](Register &LocalAccum, const Carry &CarryIn) -> Register {
4561 if (CarryIn.empty())
4562 return Register();
4563
4564 bool HaveCarryOut = true;
4565 Register CarryAccum;
4566 if (CarryIn.size() == 1) {
4567 if (!LocalAccum) {
4568 LocalAccum = B.buildZExt(I32, CarryIn[0]).getReg(0);
4569 return Register();
4570 }
4571
4572 CarryAccum = getZero32();
4573 } else {
4574 CarryAccum = B.buildZExt(I32, CarryIn[0]).getReg(0);
4575 for (unsigned i = 1; i + 1 < CarryIn.size(); ++i) {
4576 CarryAccum =
4577 B.buildUAdde(I32, S1, CarryAccum, getZero32(), CarryIn[i])
4578 .getReg(0);
4579 }
4580
4581 if (!LocalAccum) {
4582 LocalAccum = getZero32();
4583 HaveCarryOut = false;
4584 }
4585 }
4586
4587 auto Add =
4588 B.buildUAdde(I32, S1, CarryAccum, LocalAccum, CarryIn.back());
4589 LocalAccum = Add.getReg(0);
4590 return HaveCarryOut ? Add.getReg(1) : Register();
4591 };
4592
4593 // Build a multiply-add chain to compute
4594 //
4595 // LocalAccum + (partial products at DstIndex)
4596 // + (opportunistic subset of CarryIn)
4597 //
4598 // LocalAccum is an array of one or two 32-bit registers that are updated
4599 // in-place. The incoming registers may be null.
4600 //
4601 // In some edge cases, carry-ins can be consumed "for free". In that case,
4602 // the consumed carry bits are removed from CarryIn in-place.
4603 auto buildMadChain =
4604 [&](MutableArrayRef<Register> LocalAccum, unsigned DstIndex, Carry &CarryIn)
4605 -> Carry {
4606 assert((DstIndex + 1 < Accum.size() && LocalAccum.size() == 2) ||
4607 (DstIndex + 1 >= Accum.size() && LocalAccum.size() == 1));
4608
4609 Carry CarryOut;
4610 unsigned j0 = 0;
4611
4612 // Use plain 32-bit multiplication for the most significant part of the
4613 // result by default.
4614 if (LocalAccum.size() == 1 &&
4615 (!UsePartialMad64_32 || !CarryIn.empty())) {
4616 do {
4617 // Skip multiplication if one of the operands is 0
4618 unsigned j1 = DstIndex - j0;
4619 if (Src0KnownZeros[j0] || Src1KnownZeros[j1]) {
4620 ++j0;
4621 continue;
4622 }
4623 auto Mul = B.buildMul(I32, Src0[j0], Src1[j1]);
4624 if (!LocalAccum[0] || VT.getKnownBits(LocalAccum[0]).isZero()) {
4625 LocalAccum[0] = Mul.getReg(0);
4626 } else {
4627 if (CarryIn.empty()) {
4628 LocalAccum[0] = B.buildAdd(I32, LocalAccum[0], Mul).getReg(0);
4629 } else {
4630 LocalAccum[0] =
4631 B.buildUAdde(I32, S1, LocalAccum[0], Mul, CarryIn.back())
4632 .getReg(0);
4633 CarryIn.pop_back();
4634 }
4635 }
4636 ++j0;
4637 } while (j0 <= DstIndex && (!UsePartialMad64_32 || !CarryIn.empty()));
4638 }
4639
4640 // Build full 64-bit multiplies.
4641 if (j0 <= DstIndex) {
4642 bool HaveSmallAccum = false;
4643 Register Tmp;
4644
4645 if (LocalAccum[0]) {
4646 if (LocalAccum.size() == 1) {
4647 Tmp = B.buildAnyExt(I64, LocalAccum[0]).getReg(0);
4648 HaveSmallAccum = true;
4649 } else if (LocalAccum[1]) {
4650 Tmp = B.buildMergeLikeInstr(I64, LocalAccum).getReg(0);
4651 HaveSmallAccum = false;
4652 } else {
4653 Tmp = B.buildZExt(I64, LocalAccum[0]).getReg(0);
4654 HaveSmallAccum = true;
4655 }
4656 } else {
4657 assert(LocalAccum.size() == 1 || !LocalAccum[1]);
4658 Tmp = getZero64();
4659 HaveSmallAccum = true;
4660 }
4661
4662 do {
4663 unsigned j1 = DstIndex - j0;
4664 if (Src0KnownZeros[j0] || Src1KnownZeros[j1]) {
4665 ++j0;
4666 continue;
4667 }
4668 auto Mad = B.buildInstr(AMDGPU::G_AMDGPU_MAD_U64_U32, {I64, S1},
4669 {Src0[j0], Src1[j1], Tmp});
4670 Tmp = Mad.getReg(0);
4671 if (!HaveSmallAccum)
4672 CarryOut.push_back(Mad.getReg(1));
4673 HaveSmallAccum = false;
4674
4675 ++j0;
4676 } while (j0 <= DstIndex);
4677
4678 auto Unmerge = B.buildUnmerge(I32, Tmp);
4679 LocalAccum[0] = Unmerge.getReg(0);
4680 if (LocalAccum.size() > 1)
4681 LocalAccum[1] = Unmerge.getReg(1);
4682 }
4683
4684 // Every partial product contributing to this destination index was
4685 // skipped because an operand half is known zero, so nothing has been
4686 // accumulated and the result is zero.
4687 if (!LocalAccum[0])
4688 LocalAccum[0] = getZero32();
4689
4690 // A second element is only ever requested when the full 64-bit multiply
4691 // block above runs, which always writes it.
4692 assert((LocalAccum.size() == 1 || LocalAccum[1]) &&
4693 "Uninitialized accumulator part");
4694
4695 return CarryOut;
4696 };
4697
4698 // Outer multiply loop, iterating over destination parts from least
4699 // significant to most significant parts.
4700 //
4701 // The columns of the following diagram correspond to the destination parts
4702 // affected by one iteration of the outer loop (ignoring boundary
4703 // conditions).
4704 //
4705 // Dest index relative to 2 * i: 1 0 -1
4706 // ------
4707 // Carries from previous iteration: e o
4708 // Even-aligned partial product sum: E E .
4709 // Odd-aligned partial product sum: O O
4710 //
4711 // 'o' is OddCarry, 'e' is EvenCarry.
4712 // EE and OO are computed from partial products via buildMadChain and use
4713 // accumulation where possible and appropriate.
4714 //
4715 Register SeparateOddCarry;
4716 Carry EvenCarry;
4717 Carry OddCarry;
4718
4719 for (unsigned i = 0; i <= Accum.size() / 2; ++i) {
4720 Carry OddCarryIn = std::move(OddCarry);
4721 Carry EvenCarryIn = std::move(EvenCarry);
4722 OddCarry.clear();
4723 EvenCarry.clear();
4724
4725 // Partial products at offset 2 * i.
4726 if (2 * i < Accum.size()) {
4727 auto LocalAccum = Accum.drop_front(2 * i).take_front(2);
4728 EvenCarry = buildMadChain(LocalAccum, 2 * i, EvenCarryIn);
4729 }
4730
4731 // Partial products at offset 2 * i - 1.
4732 if (i > 0) {
4733 if (!SeparateOddAlignedProducts) {
4734 auto LocalAccum = Accum.drop_front(2 * i - 1).take_front(2);
4735 OddCarry = buildMadChain(LocalAccum, 2 * i - 1, OddCarryIn);
4736 } else {
4737 bool IsHighest = 2 * i >= Accum.size();
4738 Register SeparateOddOut[2];
4739 auto LocalAccum = MutableArrayRef(SeparateOddOut)
4740 .take_front(IsHighest ? 1 : 2);
4741 OddCarry = buildMadChain(LocalAccum, 2 * i - 1, OddCarryIn);
4742
4744
4745 if (i == 1) {
4746 if (!IsHighest)
4747 Lo = B.buildUAddo(I32, S1, Accum[2 * i - 1], SeparateOddOut[0]);
4748 else
4749 Lo = B.buildAdd(I32, Accum[2 * i - 1], SeparateOddOut[0]);
4750 } else {
4751 Lo = B.buildUAdde(I32, S1, Accum[2 * i - 1], SeparateOddOut[0],
4752 SeparateOddCarry);
4753 }
4754 Accum[2 * i - 1] = Lo->getOperand(0).getReg();
4755
4756 if (!IsHighest) {
4757 auto Hi = B.buildUAdde(I32, S1, Accum[2 * i], SeparateOddOut[1],
4758 Lo->getOperand(1).getReg());
4759 Accum[2 * i] = Hi.getReg(0);
4760 SeparateOddCarry = Hi.getReg(1);
4761 }
4762 }
4763 }
4764
4765 // Add in the carries from the previous iteration
4766 if (i > 0) {
4767 if (Register CarryOut = mergeCarry(Accum[2 * i - 1], OddCarryIn))
4768 EvenCarryIn.push_back(CarryOut);
4769
4770 if (2 * i < Accum.size()) {
4771 if (Register CarryOut = mergeCarry(Accum[2 * i], EvenCarryIn))
4772 OddCarry.push_back(CarryOut);
4773 }
4774 }
4775 }
4776}
4777
4778// Custom narrowing of wide multiplies using wide multiply-add instructions.
4779//
4780// TODO: If the multiply is followed by an addition, we should attempt to
4781// integrate it to make better use of V_MAD_U64_U32's multiply-add capabilities.
4783 MachineInstr &MI) const {
4784 assert(ST.hasMad64_32());
4785 assert(MI.getOpcode() == TargetOpcode::G_MUL);
4786
4787 MachineIRBuilder &B = Helper.MIRBuilder;
4788 MachineRegisterInfo &MRI = *B.getMRI();
4789
4790 Register DstReg = MI.getOperand(0).getReg();
4791 Register Src0 = MI.getOperand(1).getReg();
4792 Register Src1 = MI.getOperand(2).getReg();
4793
4794 LLT Ty = MRI.getType(DstReg);
4795 assert(Ty.isScalar());
4796
4797 unsigned Size = Ty.getSizeInBits();
4798 if (ST.useVMulU64Inst() && Size == 64)
4799 return true;
4800
4801 unsigned NumParts = Size / 32;
4802 assert((Size % 32) == 0);
4803 assert(NumParts >= 2);
4804
4805 // Whether to use MAD_64_32 for partial products whose high half is
4806 // discarded. This avoids some ADD instructions but risks false dependency
4807 // stalls on some subtargets in some cases.
4808 const bool UsePartialMad64_32 = ST.getGeneration() < AMDGPUSubtarget::GFX10;
4809
4810 // Whether to compute odd-aligned partial products separately. This is
4811 // advisable on subtargets where the accumulator of MAD_64_32 must be placed
4812 // in an even-aligned VGPR.
4813 const bool SeparateOddAlignedProducts = ST.hasFullRate64Ops();
4814
4815 LLT I32 = LLT::integer(32);
4816 SmallVector<Register, 2> Src0Parts, Src1Parts;
4817 for (unsigned i = 0; i < NumParts; ++i) {
4818 Src0Parts.push_back(MRI.createGenericVirtualRegister(I32));
4819 Src1Parts.push_back(MRI.createGenericVirtualRegister(I32));
4820 }
4821 B.buildUnmerge(Src0Parts, Src0);
4822 B.buildUnmerge(Src1Parts, Src1);
4823
4824 SmallVector<Register, 2> AccumRegs(NumParts);
4825 buildMultiply(Helper, AccumRegs, Src0Parts, Src1Parts, UsePartialMad64_32,
4826 SeparateOddAlignedProducts);
4827
4828 B.buildMergeLikeInstr(DstReg, AccumRegs);
4829 MI.eraseFromParent();
4830 return true;
4831}
4832
4833// Legalize ctlz/cttz to ffbh/ffbl instead of the default legalization to
4834// ctlz/cttz_zero_poison. This allows us to fix up the result for the zero input
4835// case with a single min instruction instead of a compare+select.
4838 MachineIRBuilder &B) const {
4839 Register Dst = MI.getOperand(0).getReg();
4840 Register Src = MI.getOperand(1).getReg();
4841 LLT DstTy = MRI.getType(Dst);
4842 LLT SrcTy = MRI.getType(Src);
4843
4844 unsigned NewOpc = MI.getOpcode() == AMDGPU::G_CTLZ
4845 ? AMDGPU::G_AMDGPU_FFBH_U32
4846 : AMDGPU::G_AMDGPU_FFBL_B32;
4847 auto Tmp = B.buildInstr(NewOpc, {DstTy}, {Src});
4848 B.buildUMin(Dst, Tmp, B.buildConstant(DstTy, SrcTy.getSizeInBits()));
4849
4850 MI.eraseFromParent();
4851 return true;
4852}
4853
4856 MachineIRBuilder &B) const {
4857 Register Dst = MI.getOperand(0).getReg();
4858 Register Src = MI.getOperand(1).getReg();
4859 LLT SrcTy = MRI.getType(Src);
4860 TypeSize NumBits = SrcTy.getSizeInBits();
4861
4862 assert(NumBits < 32u);
4863
4864 const LLT I32 = LLT::integer(32);
4865 auto ShiftAmt = B.buildConstant(I32, 32u - NumBits);
4866 auto Extend = B.buildAnyExt(I32, {Src}).getReg(0u);
4867 auto Shift = B.buildShl(I32, Extend, ShiftAmt);
4868 auto Ctlz = B.buildInstr(AMDGPU::G_AMDGPU_FFBH_U32, {I32}, {Shift});
4869 B.buildTrunc(Dst, Ctlz);
4870 MI.eraseFromParent();
4871 return true;
4872}
4873
4876 MachineIRBuilder &B) const {
4877 Register Dst = MI.getOperand(0).getReg();
4878 Register Src = MI.getOperand(1).getReg();
4879 LLT SrcTy = MRI.getType(Src);
4880 const LLT I32 = LLT::integer(32);
4881 assert(SrcTy == I32 && "legalizeCTLS only supports i32");
4882 unsigned BitWidth = SrcTy.getSizeInBits();
4883
4884 auto Sffbh = B.buildIntrinsic(Intrinsic::amdgcn_sffbh, {I32}).addUse(Src);
4885 auto Clamped = B.buildUMin(I32, Sffbh, B.buildConstant(I32, BitWidth));
4886 B.buildSub(Dst, Clamped, B.buildConstant(I32, 1));
4887 MI.eraseFromParent();
4888 return true;
4889}
4890
4891// Check that this is a G_XOR x, -1
4892static bool isNot(const MachineRegisterInfo &MRI, const MachineInstr &MI) {
4893 if (MI.getOpcode() != TargetOpcode::G_XOR)
4894 return false;
4895 auto ConstVal = getIConstantVRegSExtVal(MI.getOperand(2).getReg(), MRI);
4896 return ConstVal == -1;
4897}
4898
4899// Return the use branch instruction, otherwise null if the usage is invalid.
4900static MachineInstr *
4902 MachineBasicBlock *&UncondBrTarget, bool &Negated) {
4903 Register CondDef = MI.getOperand(0).getReg();
4904 if (!MRI.hasOneNonDBGUse(CondDef))
4905 return nullptr;
4906
4907 MachineBasicBlock *Parent = MI.getParent();
4908 MachineInstr *UseMI = &*MRI.use_instr_nodbg_begin(CondDef);
4909
4910 if (isNot(MRI, *UseMI)) {
4911 Register NegatedCond = UseMI->getOperand(0).getReg();
4912 if (!MRI.hasOneNonDBGUse(NegatedCond))
4913 return nullptr;
4914
4915 // We're deleting the def of this value, so we need to remove it.
4916 eraseInstr(*UseMI, MRI);
4917
4918 UseMI = &*MRI.use_instr_nodbg_begin(NegatedCond);
4919 Negated = true;
4920 }
4921
4922 if (UseMI->getParent() != Parent || UseMI->getOpcode() != AMDGPU::G_BRCOND)
4923 return nullptr;
4924
4925 // Make sure the cond br is followed by a G_BR, or is the last instruction.
4926 MachineBasicBlock::iterator Next = std::next(UseMI->getIterator());
4927 if (Next == Parent->end()) {
4928 MachineFunction::iterator NextMBB = std::next(Parent->getIterator());
4929 if (NextMBB == Parent->getParent()->end()) // Illegal intrinsic use.
4930 return nullptr;
4931 UncondBrTarget = &*NextMBB;
4932 } else {
4933 if (Next->getOpcode() != AMDGPU::G_BR)
4934 return nullptr;
4935 Br = &*Next;
4936 UncondBrTarget = Br->getOperand(0).getMBB();
4937 }
4938
4939 return UseMI;
4940}
4941
4944 const ArgDescriptor *Arg,
4945 const TargetRegisterClass *ArgRC,
4946 LLT ArgTy) const {
4947 MCRegister SrcReg = Arg->getRegister();
4948 assert(SrcReg.isPhysical() && "Physical register expected");
4949 assert(DstReg.isVirtual() && "Virtual register expected");
4950
4951 Register LiveIn = getFunctionLiveInPhysReg(B.getMF(), B.getTII(), SrcReg,
4952 *ArgRC, B.getDebugLoc(), ArgTy);
4953 if (Arg->isMasked()) {
4954 // TODO: Should we try to emit this once in the entry block?
4955 const LLT I32 = LLT::integer(32);
4956 const unsigned Mask = Arg->getMask();
4957 const unsigned Shift = llvm::countr_zero<unsigned>(Mask);
4958
4959 Register AndMaskSrc = LiveIn;
4960
4961 // TODO: Avoid clearing the high bits if we know workitem id y/z are always
4962 // 0.
4963 if (Shift != 0) {
4964 auto ShiftAmt = B.buildConstant(I32, Shift);
4965 AndMaskSrc = B.buildLShr(I32, LiveIn, ShiftAmt).getReg(0);
4966 }
4967
4968 B.buildAnd(DstReg, AndMaskSrc, B.buildConstant(I32, Mask >> Shift));
4969 } else {
4970 B.buildCopy(DstReg, LiveIn);
4971 }
4972}
4973
4978 AMDGPUFunctionArgInfo::PreloadedValue ClusterWorkGroupIdPV) const {
4979 Register DstReg = MI.getOperand(0).getReg();
4980 if (!ST.hasClusters()) {
4981 if (!loadInputValue(DstReg, B, WorkGroupIdPV))
4982 return false;
4983 MI.eraseFromParent();
4984 return true;
4985 }
4986
4987 // Clusters are supported. Return the global position in the grid. If clusters
4988 // are enabled, WorkGroupIdPV returns the cluster ID not the workgroup ID.
4989
4990 // WorkGroupIdXYZ = ClusterId == 0 ?
4991 // ClusterIdXYZ :
4992 // ClusterIdXYZ * (ClusterMaxIdXYZ + 1) + ClusterWorkGroupIdXYZ
4993 MachineRegisterInfo &MRI = *B.getMRI();
4994 const LLT I32 = LLT::integer(32);
4995 Register ClusterIdXYZ = MRI.createGenericVirtualRegister(I32);
4996 Register ClusterMaxIdXYZ = MRI.createGenericVirtualRegister(I32);
4997 Register ClusterWorkGroupIdXYZ = MRI.createGenericVirtualRegister(I32);
4998 if (!loadInputValue(ClusterIdXYZ, B, WorkGroupIdPV) ||
4999 !loadInputValue(ClusterWorkGroupIdXYZ, B, ClusterWorkGroupIdPV) ||
5000 !loadInputValue(ClusterMaxIdXYZ, B, ClusterMaxIdPV))
5001 return false;
5002
5003 auto One = B.buildConstant(I32, 1);
5004 auto ClusterSizeXYZ = B.buildAdd(I32, ClusterMaxIdXYZ, One);
5005 auto GlobalIdXYZ = B.buildAdd(I32, ClusterWorkGroupIdXYZ,
5006 B.buildMul(I32, ClusterIdXYZ, ClusterSizeXYZ));
5007
5008 const SIMachineFunctionInfo *MFI = B.getMF().getInfo<SIMachineFunctionInfo>();
5009
5010 switch (MFI->getClusterDims().getKind()) {
5013 B.buildCopy(DstReg, GlobalIdXYZ);
5014 MI.eraseFromParent();
5015 return true;
5016 }
5018 B.buildCopy(DstReg, ClusterIdXYZ);
5019 MI.eraseFromParent();
5020 return true;
5021 }
5023 using namespace AMDGPU::Hwreg;
5024 unsigned ClusterIdField = HwregEncoding::encode(ID_IB_STS2, 6, 4);
5025 Register ClusterId = MRI.createGenericVirtualRegister(I32);
5026 MRI.setRegClass(ClusterId, &AMDGPU::SReg_32RegClass);
5027 B.buildInstr(AMDGPU::S_GETREG_B32_const)
5028 .addDef(ClusterId)
5029 .addImm(ClusterIdField);
5030 auto Zero = B.buildConstant(I32, 0);
5031 auto NoClusters =
5032 B.buildICmp(CmpInst::ICMP_EQ, LLT::scalar(1), ClusterId, Zero);
5033 B.buildSelect(DstReg, NoClusters, ClusterIdXYZ, GlobalIdXYZ);
5034 MI.eraseFromParent();
5035 return true;
5036 }
5037 }
5038
5039 llvm_unreachable("nothing should reach here");
5040}
5041
5043 Register DstReg, MachineIRBuilder &B,
5045 const SIMachineFunctionInfo *MFI = B.getMF().getInfo<SIMachineFunctionInfo>();
5046 const ArgDescriptor *Arg = nullptr;
5047 const TargetRegisterClass *ArgRC = nullptr;
5048 LLT ArgTy;
5049
5050 CallingConv::ID CC = B.getMF().getFunction().getCallingConv();
5051 const ArgDescriptor WorkGroupIDX =
5052 ArgDescriptor::createRegister(AMDGPU::TTMP9);
5053 // If GridZ is not programmed in an entry function then the hardware will set
5054 // it to all zeros, so there is no need to mask the GridY value in the low
5055 // order bits.
5056 const ArgDescriptor WorkGroupIDY = ArgDescriptor::createRegister(
5057 AMDGPU::TTMP7,
5058 AMDGPU::isEntryFunctionCC(CC) && !MFI->hasWorkGroupIDZ() ? ~0u : 0xFFFFu);
5059 const ArgDescriptor WorkGroupIDZ =
5060 ArgDescriptor::createRegister(AMDGPU::TTMP7, 0xFFFF0000u);
5061 const ArgDescriptor ClusterWorkGroupIDX =
5062 ArgDescriptor::createRegister(AMDGPU::TTMP6, 0x0000000Fu);
5063 const ArgDescriptor ClusterWorkGroupIDY =
5064 ArgDescriptor::createRegister(AMDGPU::TTMP6, 0x000000F0u);
5065 const ArgDescriptor ClusterWorkGroupIDZ =
5066 ArgDescriptor::createRegister(AMDGPU::TTMP6, 0x00000F00u);
5067 const ArgDescriptor ClusterWorkGroupMaxIDX =
5068 ArgDescriptor::createRegister(AMDGPU::TTMP6, 0x0000F000u);
5069 const ArgDescriptor ClusterWorkGroupMaxIDY =
5070 ArgDescriptor::createRegister(AMDGPU::TTMP6, 0x000F0000u);
5071 const ArgDescriptor ClusterWorkGroupMaxIDZ =
5072 ArgDescriptor::createRegister(AMDGPU::TTMP6, 0x00F00000u);
5073 const ArgDescriptor ClusterWorkGroupMaxFlatID =
5074 ArgDescriptor::createRegister(AMDGPU::TTMP6, 0x0F000000u);
5075
5076 auto LoadConstant = [&](unsigned N) {
5077 B.buildConstant(DstReg, N);
5078 return true;
5079 };
5080
5081 if (ST.hasArchitectedSGPRs() &&
5083 AMDGPU::ClusterDimsAttr ClusterDims = MFI->getClusterDims();
5084 bool HasFixedDims = ClusterDims.isFixedDims();
5085
5086 switch (ArgType) {
5088 Arg = &WorkGroupIDX;
5089 ArgRC = &AMDGPU::SReg_32RegClass;
5090 ArgTy = LLT::integer(32);
5091 break;
5093 Arg = &WorkGroupIDY;
5094 ArgRC = &AMDGPU::SReg_32RegClass;
5095 ArgTy = LLT::integer(32);
5096 break;
5098 Arg = &WorkGroupIDZ;
5099 ArgRC = &AMDGPU::SReg_32RegClass;
5100 ArgTy = LLT::integer(32);
5101 break;
5103 if (HasFixedDims && ClusterDims.getDims()[0] == 1)
5104 return LoadConstant(0);
5105 Arg = &ClusterWorkGroupIDX;
5106 ArgRC = &AMDGPU::SReg_32RegClass;
5107 ArgTy = LLT::integer(32);
5108 break;
5110 if (HasFixedDims && ClusterDims.getDims()[1] == 1)
5111 return LoadConstant(0);
5112 Arg = &ClusterWorkGroupIDY;
5113 ArgRC = &AMDGPU::SReg_32RegClass;
5114 ArgTy = LLT::integer(32);
5115 break;
5117 if (HasFixedDims && ClusterDims.getDims()[2] == 1)
5118 return LoadConstant(0);
5119 Arg = &ClusterWorkGroupIDZ;
5120 ArgRC = &AMDGPU::SReg_32RegClass;
5121 ArgTy = LLT::integer(32);
5122 break;
5124 if (HasFixedDims)
5125 return LoadConstant(ClusterDims.getDims()[0] - 1);
5126 Arg = &ClusterWorkGroupMaxIDX;
5127 ArgRC = &AMDGPU::SReg_32RegClass;
5128 ArgTy = LLT::integer(32);
5129 break;
5131 if (HasFixedDims)
5132 return LoadConstant(ClusterDims.getDims()[1] - 1);
5133 Arg = &ClusterWorkGroupMaxIDY;
5134 ArgRC = &AMDGPU::SReg_32RegClass;
5135 ArgTy = LLT::integer(32);
5136 break;
5138 if (HasFixedDims)
5139 return LoadConstant(ClusterDims.getDims()[2] - 1);
5140 Arg = &ClusterWorkGroupMaxIDZ;
5141 ArgRC = &AMDGPU::SReg_32RegClass;
5142 ArgTy = LLT::integer(32);
5143 break;
5145 Arg = &ClusterWorkGroupMaxFlatID;
5146 ArgRC = &AMDGPU::SReg_32RegClass;
5147 ArgTy = LLT::integer(32);
5148 break;
5149 default:
5150 break;
5151 }
5152 }
5153
5154 if (!Arg)
5155 std::tie(Arg, ArgRC, ArgTy) = MFI->getPreloadedValue(ArgType);
5156
5157 if (!Arg) {
5159 // The intrinsic may appear when we have a 0 sized kernarg segment, in
5160 // which case the pointer argument may be missing and we use null.
5161 return LoadConstant(0);
5162 }
5163
5164 // It's undefined behavior if a function marked with the amdgpu-no-*
5165 // attributes uses the corresponding intrinsic.
5166 B.buildUndef(DstReg);
5167 return true;
5168 }
5169
5170 if (!Arg->isRegister() || !Arg->getRegister().isValid())
5171 return false; // TODO: Handle these
5172 buildLoadInputValue(DstReg, B, Arg, ArgRC, ArgTy);
5173 return true;
5174}
5175
5179 if (!loadInputValue(MI.getOperand(0).getReg(), B, ArgType))
5180 return false;
5181
5182 MI.eraseFromParent();
5183 return true;
5184}
5185
5187 int64_t C) {
5188 B.buildConstant(MI.getOperand(0).getReg(), C);
5189 MI.eraseFromParent();
5190 return true;
5191}
5192
5195 unsigned Dim, AMDGPUFunctionArgInfo::PreloadedValue ArgType) const {
5196 unsigned MaxID = ST.getMaxWorkitemID(B.getMF().getFunction(), Dim);
5197 if (MaxID == 0)
5198 return replaceWithConstant(B, MI, 0);
5199
5200 const SIMachineFunctionInfo *MFI = B.getMF().getInfo<SIMachineFunctionInfo>();
5201 const ArgDescriptor *Arg;
5202 const TargetRegisterClass *ArgRC;
5203 LLT ArgTy;
5204 std::tie(Arg, ArgRC, ArgTy) = MFI->getPreloadedValue(ArgType);
5205
5206 Register DstReg = MI.getOperand(0).getReg();
5207 if (!Arg) {
5208 // It's undefined behavior if a function marked with the amdgpu-no-*
5209 // attributes uses the corresponding intrinsic.
5210 B.buildUndef(DstReg);
5211 MI.eraseFromParent();
5212 return true;
5213 }
5214
5215 if (Arg->isMasked()) {
5216 // Don't bother inserting AssertZext for packed IDs since we're emitting the
5217 // masking operations anyway.
5218 //
5219 // TODO: We could assert the top bit is 0 for the source copy.
5220 if (!loadInputValue(DstReg, B, ArgType))
5221 return false;
5222 } else {
5224 if (!loadInputValue(TmpReg, B, ArgType))
5225 return false;
5226 B.buildAssertZExt(DstReg, TmpReg, llvm::bit_width(MaxID));
5227 }
5228
5229 MI.eraseFromParent();
5230 return true;
5231}
5232
5235 // This isn't really a constant pool but close enough.
5238 return PtrInfo;
5239}
5240
5242 int64_t Offset) const {
5244 Register KernArgReg = B.getMRI()->createGenericVirtualRegister(PtrTy);
5245
5246 // TODO: If we passed in the base kernel offset we could have a better
5247 // alignment than 4, but we don't really need it.
5248 if (!loadInputValue(KernArgReg, B,
5250 llvm_unreachable("failed to find kernarg segment ptr");
5251
5252 auto COffset = B.buildConstant(LLT::integer(64), Offset);
5253 return B.buildObjectPtrOffset(PtrTy, KernArgReg, COffset).getReg(0);
5254}
5255
5256/// Legalize a value that's loaded from kernel arguments. This is only used by
5257/// legacy intrinsics.
5260 uint64_t Offset,
5261 Align Alignment) const {
5262 Register DstReg = MI.getOperand(0).getReg();
5263
5264 assert(B.getMRI()->getType(DstReg) == LLT::integer(32) &&
5265 "unexpected kernarg parameter type");
5266
5269 B.buildLoad(DstReg, Ptr, PtrInfo.getWithOffset(Offset), Align(4),
5272 MI.eraseFromParent();
5273 return true;
5274}
5275
5278 MachineIRBuilder &B) const {
5279 Register Dst = MI.getOperand(0).getReg();
5280 LLT DstTy = MRI.getType(Dst);
5281
5282 if (DstTy == F16)
5283 return legalizeFDIV16(MI, MRI, B);
5284 if (DstTy == F32)
5285 return legalizeFDIV32(MI, MRI, B);
5286 if (DstTy == F64)
5287 return legalizeFDIV64(MI, MRI, B);
5288
5289 return false;
5290}
5291
5293 Register DstDivReg,
5294 Register DstRemReg,
5295 Register X,
5296 Register Y) const {
5297 const LLT S1 = LLT::scalar(1);
5298 const LLT I32 = LLT::integer(32);
5299
5300 // See AMDGPUCodeGenPrepare::expandDivRem32 for a description of the
5301 // algorithm used here.
5302
5303 // Initial estimate of inv(y).
5304 auto FloatY = B.buildUITOFP(F32, Y);
5305 auto RcpIFlag = B.buildInstr(AMDGPU::G_AMDGPU_RCP_IFLAG, {F32}, {FloatY});
5306 auto Scale = B.buildFConstant(F32, llvm::bit_cast<float>(0x4f7ffffe));
5307 auto ScaledY = B.buildFMul(F32, RcpIFlag, Scale);
5308 auto Z = B.buildFPTOUI(I32, ScaledY);
5309
5310 // One round of UNR.
5311 auto NegY = B.buildSub(I32, B.buildConstant(I32, 0), Y);
5312 auto NegYZ = B.buildMul(I32, NegY, Z);
5313 Z = B.buildAdd(I32, Z, B.buildUMulH(I32, Z, NegYZ));
5314
5315 // Quotient/remainder estimate.
5316 auto Q = B.buildUMulH(I32, X, Z);
5317 auto R = B.buildSub(I32, X, B.buildMul(I32, Q, Y));
5318
5319 // First quotient/remainder refinement.
5320 auto One = B.buildConstant(I32, 1);
5321 auto Cond = B.buildICmp(CmpInst::ICMP_UGE, S1, R, Y);
5322 if (DstDivReg)
5323 Q = B.buildSelect(I32, Cond, B.buildAdd(I32, Q, One), Q);
5324 R = B.buildSelect(I32, Cond, B.buildSub(I32, R, Y), R);
5325
5326 // Second quotient/remainder refinement.
5327 Cond = B.buildICmp(CmpInst::ICMP_UGE, S1, R, Y);
5328 if (DstDivReg)
5329 B.buildSelect(DstDivReg, Cond, B.buildAdd(I32, Q, One), Q);
5330
5331 if (DstRemReg)
5332 B.buildSelect(DstRemReg, Cond, B.buildSub(I32, R, Y), R);
5333}
5334
5335// Build integer reciprocal sequence around V_RCP_IFLAG_F32
5336//
5337// Return lo, hi of result
5338//
5339// %cvt.lo = G_UITOFP Val.lo
5340// %cvt.hi = G_UITOFP Val.hi
5341// %mad = G_FMAD %cvt.hi, 2**32, %cvt.lo
5342// %rcp = G_AMDGPU_RCP_IFLAG %mad
5343// %mul1 = G_FMUL %rcp, 0x5f7ffffc
5344// %mul2 = G_FMUL %mul1, 2**(-32)
5345// %trunc = G_INTRINSIC_TRUNC %mul2
5346// %mad2 = G_FMAD %trunc, -(2**32), %mul1
5347// return {G_FPTOUI %mad2, G_FPTOUI %trunc}
5348static std::pair<Register, Register> emitReciprocalU64(MachineIRBuilder &B,
5349 Register Val) {
5350 const LLT I32 = LLT::integer(32);
5351 auto Unmerge = B.buildUnmerge(I32, Val);
5352
5353 auto CvtLo = B.buildUITOFP(F32, Unmerge.getReg(0));
5354 auto CvtHi = B.buildUITOFP(F32, Unmerge.getReg(1));
5355
5356 auto Mad = B.buildFMAD(
5357 F32, CvtHi, // 2**32
5358 B.buildFConstant(F32, llvm::bit_cast<float>(0x4f800000)), CvtLo);
5359
5360 auto Rcp = B.buildInstr(AMDGPU::G_AMDGPU_RCP_IFLAG, {F32}, {Mad});
5361 auto Mul1 = B.buildFMul(
5362 F32, Rcp, B.buildFConstant(F32, llvm::bit_cast<float>(0x5f7ffffc)));
5363
5364 // 2**(-32)
5365 auto Mul2 = B.buildFMul(
5366 F32, Mul1, B.buildFConstant(F32, llvm::bit_cast<float>(0x2f800000)));
5367 auto Trunc = B.buildIntrinsicTrunc(F32, Mul2);
5368
5369 // -(2**32)
5370 auto Mad2 = B.buildFMAD(
5371 F32, Trunc, B.buildFConstant(F32, llvm::bit_cast<float>(0xcf800000)),
5372 Mul1);
5373
5374 auto ResultLo = B.buildFPTOUI(I32, Mad2);
5375 auto ResultHi = B.buildFPTOUI(I32, Trunc);
5376
5377 return {ResultLo.getReg(0), ResultHi.getReg(0)};
5378}
5379
5381 Register DstDivReg,
5382 Register DstRemReg,
5383 Register Numer,
5384 Register Denom) const {
5385 const LLT I32 = LLT::integer(32);
5386 const LLT I64 = LLT::integer(64);
5387 const LLT S1 = LLT::scalar(1);
5388 Register RcpLo, RcpHi;
5389
5390 std::tie(RcpLo, RcpHi) = emitReciprocalU64(B, Denom);
5391
5392 auto Rcp = B.buildMergeLikeInstr(I64, {RcpLo, RcpHi});
5393
5394 auto Zero64 = B.buildConstant(I64, 0);
5395 auto NegDenom = B.buildSub(I64, Zero64, Denom);
5396
5397 auto MulLo1 = B.buildMul(I64, NegDenom, Rcp);
5398 auto MulHi1 = B.buildUMulH(I64, Rcp, MulLo1);
5399
5400 auto UnmergeMulHi1 = B.buildUnmerge(I32, MulHi1);
5401 Register MulHi1_Lo = UnmergeMulHi1.getReg(0);
5402 Register MulHi1_Hi = UnmergeMulHi1.getReg(1);
5403
5404 auto Add1_Lo = B.buildUAddo(I32, S1, RcpLo, MulHi1_Lo);
5405 auto Add1_Hi = B.buildUAdde(I32, S1, RcpHi, MulHi1_Hi, Add1_Lo.getReg(1));
5406 auto Add1 = B.buildMergeLikeInstr(I64, {Add1_Lo, Add1_Hi});
5407
5408 auto MulLo2 = B.buildMul(I64, NegDenom, Add1);
5409 auto MulHi2 = B.buildUMulH(I64, Add1, MulLo2);
5410 auto UnmergeMulHi2 = B.buildUnmerge(I32, MulHi2);
5411 Register MulHi2_Lo = UnmergeMulHi2.getReg(0);
5412 Register MulHi2_Hi = UnmergeMulHi2.getReg(1);
5413
5414 auto Zero32 = B.buildConstant(I32, 0);
5415 auto Add2_Lo = B.buildUAddo(I32, S1, Add1_Lo, MulHi2_Lo);
5416 auto Add2_Hi = B.buildUAdde(I32, S1, Add1_Hi, MulHi2_Hi, Add2_Lo.getReg(1));
5417 auto Add2 = B.buildMergeLikeInstr(I64, {Add2_Lo, Add2_Hi});
5418
5419 auto UnmergeNumer = B.buildUnmerge(I32, Numer);
5420 Register NumerLo = UnmergeNumer.getReg(0);
5421 Register NumerHi = UnmergeNumer.getReg(1);
5422
5423 auto MulHi3 = B.buildUMulH(I64, Numer, Add2);
5424 auto Mul3 = B.buildMul(I64, Denom, MulHi3);
5425 auto UnmergeMul3 = B.buildUnmerge(I32, Mul3);
5426 Register Mul3_Lo = UnmergeMul3.getReg(0);
5427 Register Mul3_Hi = UnmergeMul3.getReg(1);
5428 auto Sub1_Lo = B.buildUSubo(I32, S1, NumerLo, Mul3_Lo);
5429 auto Sub1_Hi = B.buildUSube(I32, S1, NumerHi, Mul3_Hi, Sub1_Lo.getReg(1));
5430 auto Sub1_Mi = B.buildSub(I32, NumerHi, Mul3_Hi);
5431 auto Sub1 = B.buildMergeLikeInstr(I64, {Sub1_Lo, Sub1_Hi});
5432
5433 auto UnmergeDenom = B.buildUnmerge(I32, Denom);
5434 Register DenomLo = UnmergeDenom.getReg(0);
5435 Register DenomHi = UnmergeDenom.getReg(1);
5436
5437 auto CmpHi = B.buildICmp(CmpInst::ICMP_UGE, S1, Sub1_Hi, DenomHi);
5438 auto C1 = B.buildSExt(I32, CmpHi);
5439
5440 auto CmpLo = B.buildICmp(CmpInst::ICMP_UGE, S1, Sub1_Lo, DenomLo);
5441 auto C2 = B.buildSExt(I32, CmpLo);
5442
5443 auto CmpEq = B.buildICmp(CmpInst::ICMP_EQ, S1, Sub1_Hi, DenomHi);
5444 auto C3 = B.buildSelect(I32, CmpEq, C2, C1);
5445
5446 // TODO: Here and below portions of the code can be enclosed into if/endif.
5447 // Currently control flow is unconditional and we have 4 selects after
5448 // potential endif to substitute PHIs.
5449
5450 // if C3 != 0 ...
5451 auto Sub2_Lo = B.buildUSubo(I32, S1, Sub1_Lo, DenomLo);
5452 auto Sub2_Mi = B.buildUSube(I32, S1, Sub1_Mi, DenomHi, Sub1_Lo.getReg(1));
5453 auto Sub2_Hi = B.buildUSube(I32, S1, Sub2_Mi, Zero32, Sub2_Lo.getReg(1));
5454 auto Sub2 = B.buildMergeLikeInstr(I64, {Sub2_Lo, Sub2_Hi});
5455
5456 auto One64 = B.buildConstant(I64, 1);
5457 auto Add3 = B.buildAdd(I64, MulHi3, One64);
5458
5459 auto C4 =
5460 B.buildSExt(I32, B.buildICmp(CmpInst::ICMP_UGE, S1, Sub2_Hi, DenomHi));
5461 auto C5 =
5462 B.buildSExt(I32, B.buildICmp(CmpInst::ICMP_UGE, S1, Sub2_Lo, DenomLo));
5463 auto C6 = B.buildSelect(
5464 I32, B.buildICmp(CmpInst::ICMP_EQ, S1, Sub2_Hi, DenomHi), C5, C4);
5465
5466 // if (C6 != 0)
5467 auto Add4 = B.buildAdd(I64, Add3, One64);
5468 auto Sub3_Lo = B.buildUSubo(I32, S1, Sub2_Lo, DenomLo);
5469
5470 auto Sub3_Mi = B.buildUSube(I32, S1, Sub2_Mi, DenomHi, Sub2_Lo.getReg(1));
5471 auto Sub3_Hi = B.buildUSube(I32, S1, Sub3_Mi, Zero32, Sub3_Lo.getReg(1));
5472 auto Sub3 = B.buildMergeLikeInstr(I64, {Sub3_Lo, Sub3_Hi});
5473
5474 // endif C6
5475 // endif C3
5476
5477 if (DstDivReg) {
5478 auto Sel1 = B.buildSelect(
5479 I64, B.buildICmp(CmpInst::ICMP_NE, S1, C6, Zero32), Add4, Add3);
5480 B.buildSelect(DstDivReg, B.buildICmp(CmpInst::ICMP_NE, S1, C3, Zero32),
5481 Sel1, MulHi3);
5482 }
5483
5484 if (DstRemReg) {
5485 auto Sel2 = B.buildSelect(
5486 I64, B.buildICmp(CmpInst::ICMP_NE, S1, C6, Zero32), Sub3, Sub2);
5487 B.buildSelect(DstRemReg, B.buildICmp(CmpInst::ICMP_NE, S1, C3, Zero32),
5488 Sel2, Sub1);
5489 }
5490}
5491
5494 MachineIRBuilder &B) const {
5495 Register DstDivReg, DstRemReg;
5496 switch (MI.getOpcode()) {
5497 default:
5498 llvm_unreachable("Unexpected opcode!");
5499 case AMDGPU::G_UDIV: {
5500 DstDivReg = MI.getOperand(0).getReg();
5501 break;
5502 }
5503 case AMDGPU::G_UREM: {
5504 DstRemReg = MI.getOperand(0).getReg();
5505 break;
5506 }
5507 case AMDGPU::G_UDIVREM: {
5508 DstDivReg = MI.getOperand(0).getReg();
5509 DstRemReg = MI.getOperand(1).getReg();
5510 break;
5511 }
5512 }
5513
5514 const LLT I64 = LLT::integer(64);
5515 const LLT I32 = LLT::integer(32);
5516 const unsigned FirstSrcOpIdx = MI.getNumExplicitDefs();
5517 Register Num = MI.getOperand(FirstSrcOpIdx).getReg();
5518 Register Den = MI.getOperand(FirstSrcOpIdx + 1).getReg();
5519 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
5520
5521 if (Ty == I32)
5522 legalizeUnsignedDIV_REM32Impl(B, DstDivReg, DstRemReg, Num, Den);
5523 else if (Ty == I64)
5524 legalizeUnsignedDIV_REM64Impl(B, DstDivReg, DstRemReg, Num, Den);
5525 else
5526 return false;
5527
5528 MI.eraseFromParent();
5529 return true;
5530}
5531
5534 MachineIRBuilder &B) const {
5535 const LLT I64 = LLT::integer(64);
5536 const LLT I32 = LLT::integer(32);
5537
5538 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
5539 if (Ty != I32 && Ty != I64)
5540 return false;
5541
5542 const unsigned FirstSrcOpIdx = MI.getNumExplicitDefs();
5543 Register LHS = MI.getOperand(FirstSrcOpIdx).getReg();
5544 Register RHS = MI.getOperand(FirstSrcOpIdx + 1).getReg();
5545
5546 auto SignBitOffset = B.buildConstant(I32, Ty.getSizeInBits() - 1);
5547 auto LHSign = B.buildAShr(Ty, LHS, SignBitOffset);
5548 auto RHSign = B.buildAShr(Ty, RHS, SignBitOffset);
5549
5550 LHS = B.buildAdd(Ty, LHS, LHSign).getReg(0);
5551 RHS = B.buildAdd(Ty, RHS, RHSign).getReg(0);
5552
5553 LHS = B.buildXor(Ty, LHS, LHSign).getReg(0);
5554 RHS = B.buildXor(Ty, RHS, RHSign).getReg(0);
5555
5556 Register DstDivReg, DstRemReg, TmpDivReg, TmpRemReg;
5557 switch (MI.getOpcode()) {
5558 default:
5559 llvm_unreachable("Unexpected opcode!");
5560 case AMDGPU::G_SDIV: {
5561 DstDivReg = MI.getOperand(0).getReg();
5562 TmpDivReg = MRI.createGenericVirtualRegister(Ty);
5563 break;
5564 }
5565 case AMDGPU::G_SREM: {
5566 DstRemReg = MI.getOperand(0).getReg();
5567 TmpRemReg = MRI.createGenericVirtualRegister(Ty);
5568 break;
5569 }
5570 case AMDGPU::G_SDIVREM: {
5571 DstDivReg = MI.getOperand(0).getReg();
5572 DstRemReg = MI.getOperand(1).getReg();
5573 TmpDivReg = MRI.createGenericVirtualRegister(Ty);
5574 TmpRemReg = MRI.createGenericVirtualRegister(Ty);
5575 break;
5576 }
5577 }
5578
5579 if (Ty == I32)
5580 legalizeUnsignedDIV_REM32Impl(B, TmpDivReg, TmpRemReg, LHS, RHS);
5581 else
5582 legalizeUnsignedDIV_REM64Impl(B, TmpDivReg, TmpRemReg, LHS, RHS);
5583
5584 if (DstDivReg) {
5585 auto Sign = B.buildXor(Ty, LHSign, RHSign).getReg(0);
5586 auto SignXor = B.buildXor(Ty, TmpDivReg, Sign).getReg(0);
5587 B.buildSub(DstDivReg, SignXor, Sign);
5588 }
5589
5590 if (DstRemReg) {
5591 auto Sign = LHSign.getReg(0); // Remainder sign is the same as LHS
5592 auto SignXor = B.buildXor(Ty, TmpRemReg, Sign).getReg(0);
5593 B.buildSub(DstRemReg, SignXor, Sign);
5594 }
5595
5596 MI.eraseFromParent();
5597 return true;
5598}
5599
5602 MachineIRBuilder &B) const {
5603 Register Res = MI.getOperand(0).getReg();
5604 Register LHS = MI.getOperand(1).getReg();
5605 Register RHS = MI.getOperand(2).getReg();
5606 uint16_t Flags = MI.getFlags();
5607 LLT ResTy = MRI.getType(Res);
5608
5609 bool AllowInaccurateRcp = MI.getFlag(MachineInstr::FmAfn);
5610
5611 if (const auto *CLHS = getConstantFPVRegVal(LHS, MRI)) {
5612 if (!AllowInaccurateRcp && ResTy != F16)
5613 return false;
5614
5615 // v_rcp_f32 and v_rsq_f32 do not support denormals, and according to
5616 // the CI documentation has a worst case error of 1 ulp.
5617 // OpenCL requires <= 2.5 ulp for 1.0 / x, so it should always be OK to
5618 // use it as long as we aren't trying to use denormals.
5619 //
5620 // v_rcp_f16 and v_rsq_f16 DO support denormals and 0.51ulp.
5621
5622 // 1 / x -> RCP(x)
5623 if (CLHS->isOne()) {
5624 B.buildIntrinsic(Intrinsic::amdgcn_rcp, Res)
5625 .addUse(RHS)
5626 .setMIFlags(Flags);
5627
5628 MI.eraseFromParent();
5629 return true;
5630 }
5631
5632 // -1 / x -> RCP( FNEG(x) )
5633 if (CLHS->isMinusOne()) {
5634 auto FNeg = B.buildFNeg(ResTy, RHS, Flags);
5635 B.buildIntrinsic(Intrinsic::amdgcn_rcp, Res)
5636 .addUse(FNeg.getReg(0))
5637 .setMIFlags(Flags);
5638
5639 MI.eraseFromParent();
5640 return true;
5641 }
5642 }
5643
5644 // For f16 require afn or arcp.
5645 // For f32 require afn.
5646 if (!AllowInaccurateRcp &&
5647 (ResTy != F16 || !MI.getFlag(MachineInstr::FmArcp)))
5648 return false;
5649
5650 // x / y -> x * (1.0 / y)
5651 auto RCP = B.buildIntrinsic(Intrinsic::amdgcn_rcp, {ResTy})
5652 .addUse(RHS)
5653 .setMIFlags(Flags);
5654 B.buildFMul(Res, LHS, RCP, Flags);
5655
5656 MI.eraseFromParent();
5657 return true;
5658}
5659
5662 MachineIRBuilder &B) const {
5663 Register Res = MI.getOperand(0).getReg();
5664 Register X = MI.getOperand(1).getReg();
5665 Register Y = MI.getOperand(2).getReg();
5666 uint16_t Flags = MI.getFlags();
5667 LLT ResTy = MRI.getType(Res);
5668
5669 bool AllowInaccurateRcp = MI.getFlag(MachineInstr::FmAfn);
5670
5671 if (!AllowInaccurateRcp)
5672 return false;
5673
5674 const ConstantFP *CLHS = getConstantFPVRegVal(X, MRI);
5675 bool IsNegRcp = CLHS && CLHS->isMinusOne();
5676
5677 // Pull out the negation so it folds for free into the source modifiers.
5678 if (IsNegRcp)
5679 X = B.buildFConstant(ResTy, 1.0).getReg(0);
5680
5681 Register NegY = IsNegRcp ? Y : B.buildFNeg(ResTy, Y).getReg(0);
5682 auto One = B.buildFConstant(ResTy, 1.0);
5683
5684 auto R = B.buildIntrinsic(Intrinsic::amdgcn_rcp, {ResTy})
5685 .addUse(Y)
5686 .setMIFlags(Flags);
5687 if (IsNegRcp)
5688 R = B.buildFNeg(ResTy, R);
5689
5690 auto Tmp0 = B.buildFMA(ResTy, NegY, R, One);
5691 R = B.buildFMA(ResTy, Tmp0, R, R);
5692
5693 auto Tmp1 = B.buildFMA(ResTy, NegY, R, One);
5694 R = B.buildFMA(ResTy, Tmp1, R, R);
5695
5696 // Skip the last 2 correction terms for reciprocal.
5697 if (IsNegRcp || (CLHS && CLHS->isOne())) {
5698 B.buildCopy(Res, R);
5699 MI.eraseFromParent();
5700 return true;
5701 }
5702
5703 auto Ret = B.buildFMul(ResTy, X, R);
5704 auto Tmp2 = B.buildFMA(ResTy, NegY, Ret, X);
5705
5706 B.buildFMA(Res, Tmp2, R, Ret);
5707 MI.eraseFromParent();
5708 return true;
5709}
5710
5713 MachineIRBuilder &B) const {
5714 if (legalizeFastUnsafeFDIV(MI, MRI, B))
5715 return true;
5716
5717 Register Res = MI.getOperand(0).getReg();
5718 Register LHS = MI.getOperand(1).getReg();
5719 Register RHS = MI.getOperand(2).getReg();
5720
5721 uint16_t Flags = MI.getFlags();
5722
5723 LLT I32 = LLT::integer(32);
5724
5725 // a32.u = opx(V_CVT_F32_F16, a.u); // CVT to F32
5726 // b32.u = opx(V_CVT_F32_F16, b.u); // CVT to F32
5727 // r32.u = opx(V_RCP_F32, b32.u); // rcp = 1 / d
5728 // q32.u = opx(V_MUL_F32, a32.u, r32.u); // q = n * rcp
5729 // e32.u = opx(V_MAD_F32, (b32.u^_neg32), q32.u, a32.u); // err = -d * q + n
5730 // q32.u = opx(V_MAD_F32, e32.u, r32.u, q32.u); // q = n * rcp
5731 // e32.u = opx(V_MAD_F32, (b32.u^_neg32), q32.u, a32.u); // err = -d * q + n
5732 // tmp.u = opx(V_MUL_F32, e32.u, r32.u);
5733 // tmp.u = opx(V_AND_B32, tmp.u, 0xff800000)
5734 // q32.u = opx(V_ADD_F32, tmp.u, q32.u);
5735 // q16.u = opx(V_CVT_F16_F32, q32.u);
5736 // q16.u = opx(V_DIV_FIXUP_F16, q16.u, b.u, a.u); // q = touchup(q, d, n)
5737
5738 auto LHSExt = B.buildFPExt(F32, LHS, Flags);
5739 auto RHSExt = B.buildFPExt(F32, RHS, Flags);
5740 auto NegRHSExt = B.buildFNeg(F32, RHSExt);
5741 auto Rcp = B.buildIntrinsic(Intrinsic::amdgcn_rcp, {F32})
5742 .addUse(RHSExt.getReg(0))
5743 .setMIFlags(Flags);
5744 auto Quot = B.buildFMul(F32, LHSExt, Rcp, Flags);
5746 if (ST.hasMadMacF32Insts()) {
5747 Err = B.buildFMAD(F32, NegRHSExt, Quot, LHSExt, Flags);
5748 Quot = B.buildFMAD(F32, Err, Rcp, Quot, Flags);
5749 Err = B.buildFMAD(F32, NegRHSExt, Quot, LHSExt, Flags);
5750 } else {
5751 Err = B.buildFMA(F32, NegRHSExt, Quot, LHSExt, Flags);
5752 Quot = B.buildFMA(F32, Err, Rcp, Quot, Flags);
5753 Err = B.buildFMA(F32, NegRHSExt, Quot, LHSExt, Flags);
5754 }
5755 auto Tmp = B.buildFMul(F32, Err, Rcp, Flags);
5756 auto TmpInt = B.buildBitcast(I32, Tmp);
5757 auto MaskedInt = B.buildAnd(I32, TmpInt, B.buildConstant(I32, 0xff800000));
5758 auto Masked = B.buildBitcast(F32, MaskedInt);
5759 Quot = B.buildFAdd(F32, Masked, Quot, Flags);
5760 auto RDst = B.buildFPTrunc(F16, Quot, Flags);
5761 B.buildIntrinsic(Intrinsic::amdgcn_div_fixup, Res)
5762 .addUse(RDst.getReg(0))
5763 .addUse(RHS)
5764 .addUse(LHS)
5765 .setMIFlags(Flags);
5766
5767 MI.eraseFromParent();
5768 return true;
5769}
5770
5771static constexpr unsigned SPDenormModeBitField =
5773
5774// Enable or disable FP32 denorm mode. When 'Enable' is true, emit instructions
5775// to enable denorm mode. When 'Enable' is false, disable denorm mode.
5777 const GCNSubtarget &ST,
5779 // Set SP denorm mode to this value.
5780 unsigned SPDenormMode =
5781 Enable ? FP_DENORM_FLUSH_NONE : Mode.fpDenormModeSPValue();
5782
5783 if (ST.hasDenormModeInst()) {
5784 // Preserve default FP64FP16 denorm mode while updating FP32 mode.
5785 uint32_t DPDenormModeDefault = Mode.fpDenormModeDPValue();
5786
5787 uint32_t NewDenormModeValue = SPDenormMode | (DPDenormModeDefault << 2);
5788 B.buildInstr(AMDGPU::S_DENORM_MODE)
5789 .addImm(NewDenormModeValue);
5790
5791 } else {
5792 B.buildInstr(AMDGPU::S_SETREG_IMM32_B32)
5793 .addImm(SPDenormMode)
5794 .addImm(SPDenormModeBitField);
5795 }
5796}
5797
5800 MachineIRBuilder &B) const {
5801 if (legalizeFastUnsafeFDIV(MI, MRI, B))
5802 return true;
5803
5804 Register Res = MI.getOperand(0).getReg();
5805 Register LHS = MI.getOperand(1).getReg();
5806 Register RHS = MI.getOperand(2).getReg();
5807 const SIMachineFunctionInfo *MFI = B.getMF().getInfo<SIMachineFunctionInfo>();
5808 SIModeRegisterDefaults Mode = MFI->getMode();
5809
5810 uint16_t Flags = MI.getFlags();
5811
5812 LLT S1 = LLT::scalar(1);
5813
5814 auto One = B.buildFConstant(F32, 1.0f);
5815
5816 auto DenominatorScaled =
5817 B.buildIntrinsic(Intrinsic::amdgcn_div_scale, {F32, S1})
5818 .addUse(LHS)
5819 .addUse(RHS)
5820 .addImm(0)
5821 .setMIFlags(Flags);
5822 auto NumeratorScaled =
5823 B.buildIntrinsic(Intrinsic::amdgcn_div_scale, {F32, S1})
5824 .addUse(LHS)
5825 .addUse(RHS)
5826 .addImm(1)
5827 .setMIFlags(Flags);
5828
5829 auto ApproxRcp = B.buildIntrinsic(Intrinsic::amdgcn_rcp, {F32})
5830 .addUse(DenominatorScaled.getReg(0))
5831 .setMIFlags(Flags);
5832 auto NegDivScale0 = B.buildFNeg(F32, DenominatorScaled, Flags);
5833
5834 const bool PreservesDenormals = Mode.FP32Denormals == DenormalMode::getIEEE();
5835 const bool HasDynamicDenormals =
5836 (Mode.FP32Denormals.Input == DenormalMode::Dynamic) ||
5837 (Mode.FP32Denormals.Output == DenormalMode::Dynamic);
5838
5839 Register SavedSPDenormMode;
5840 if (!PreservesDenormals) {
5841 if (HasDynamicDenormals) {
5842 SavedSPDenormMode = MRI.createVirtualRegister(&AMDGPU::SReg_32RegClass);
5843 B.buildInstr(AMDGPU::S_GETREG_B32)
5844 .addDef(SavedSPDenormMode)
5845 .addImm(SPDenormModeBitField);
5846 }
5847 toggleSPDenormMode(true, B, ST, Mode);
5848 }
5849
5850 auto Fma0 = B.buildFMA(F32, NegDivScale0, ApproxRcp, One, Flags);
5851 auto Fma1 = B.buildFMA(F32, Fma0, ApproxRcp, ApproxRcp, Flags);
5852 auto Mul = B.buildFMul(F32, NumeratorScaled, Fma1, Flags);
5853 auto Fma2 = B.buildFMA(F32, NegDivScale0, Mul, NumeratorScaled, Flags);
5854 auto Fma3 = B.buildFMA(F32, Fma2, Fma1, Mul, Flags);
5855 auto Fma4 = B.buildFMA(F32, NegDivScale0, Fma3, NumeratorScaled, Flags);
5856
5857 if (!PreservesDenormals) {
5858 if (HasDynamicDenormals) {
5859 assert(SavedSPDenormMode);
5860 B.buildInstr(AMDGPU::S_SETREG_B32)
5861 .addReg(SavedSPDenormMode)
5862 .addImm(SPDenormModeBitField);
5863 } else
5864 toggleSPDenormMode(false, B, ST, Mode);
5865 }
5866
5867 auto Fmas = B.buildIntrinsic(Intrinsic::amdgcn_div_fmas, {F32})
5868 .addUse(Fma4.getReg(0))
5869 .addUse(Fma1.getReg(0))
5870 .addUse(Fma3.getReg(0))
5871 .addUse(NumeratorScaled.getReg(1))
5872 .setMIFlags(Flags);
5873
5874 B.buildIntrinsic(Intrinsic::amdgcn_div_fixup, Res)
5875 .addUse(Fmas.getReg(0))
5876 .addUse(RHS)
5877 .addUse(LHS)
5878 .setMIFlags(Flags);
5879
5880 MI.eraseFromParent();
5881 return true;
5882}
5883
5886 MachineIRBuilder &B) const {
5887 if (legalizeFastUnsafeFDIV64(MI, MRI, B))
5888 return true;
5889
5890 Register Res = MI.getOperand(0).getReg();
5891 Register LHS = MI.getOperand(1).getReg();
5892 Register RHS = MI.getOperand(2).getReg();
5893
5894 uint16_t Flags = MI.getFlags();
5895
5896 LLT S1 = LLT::scalar(1);
5897
5898 auto One = B.buildFConstant(F64, 1.0);
5899
5900 auto DivScale0 = B.buildIntrinsic(Intrinsic::amdgcn_div_scale, {F64, S1})
5901 .addUse(LHS)
5902 .addUse(RHS)
5903 .addImm(0)
5904 .setMIFlags(Flags);
5905
5906 auto NegDivScale0 = B.buildFNeg(F64, DivScale0.getReg(0), Flags);
5907
5908 auto Rcp = B.buildIntrinsic(Intrinsic::amdgcn_rcp, {F64})
5909 .addUse(DivScale0.getReg(0))
5910 .setMIFlags(Flags);
5911
5912 auto Fma0 = B.buildFMA(F64, NegDivScale0, Rcp, One, Flags);
5913 auto Fma1 = B.buildFMA(F64, Rcp, Fma0, Rcp, Flags);
5914 auto Fma2 = B.buildFMA(F64, NegDivScale0, Fma1, One, Flags);
5915
5916 auto DivScale1 = B.buildIntrinsic(Intrinsic::amdgcn_div_scale, {F64, S1})
5917 .addUse(LHS)
5918 .addUse(RHS)
5919 .addImm(1)
5920 .setMIFlags(Flags);
5921
5922 auto Fma3 = B.buildFMA(F64, Fma1, Fma2, Fma1, Flags);
5923 auto Mul = B.buildFMul(F64, DivScale1.getReg(0), Fma3, Flags);
5924 auto Fma4 = B.buildFMA(F64, NegDivScale0, Mul, DivScale1.getReg(0), Flags);
5925
5926 Register Scale;
5927 if (!ST.hasUsableDivScaleConditionOutput()) {
5928 // Workaround a hardware bug on SI where the condition output from div_scale
5929 // is not usable.
5930
5931 LLT I32 = LLT::integer(32);
5932 LLT I64 = LLT::integer(64);
5933
5934 auto NumUnmerge = B.buildUnmerge(I32, B.buildBitcast(I64, LHS));
5935 auto DenUnmerge = B.buildUnmerge(I32, B.buildBitcast(I64, RHS));
5936 auto Scale0Unmerge = B.buildUnmerge(I32, B.buildBitcast(I64, DivScale0));
5937 auto Scale1Unmerge = B.buildUnmerge(I32, B.buildBitcast(I64, DivScale1));
5938
5939 auto CmpNum = B.buildICmp(ICmpInst::ICMP_EQ, S1, NumUnmerge.getReg(1),
5940 Scale1Unmerge.getReg(1));
5941 auto CmpDen = B.buildICmp(ICmpInst::ICMP_EQ, S1, DenUnmerge.getReg(1),
5942 Scale0Unmerge.getReg(1));
5943 Scale = B.buildXor(S1, CmpNum, CmpDen).getReg(0);
5944 } else {
5945 Scale = DivScale1.getReg(1);
5946 }
5947
5948 auto Fmas = B.buildIntrinsic(Intrinsic::amdgcn_div_fmas, {F64})
5949 .addUse(Fma4.getReg(0))
5950 .addUse(Fma3.getReg(0))
5951 .addUse(Mul.getReg(0))
5952 .addUse(Scale)
5953 .setMIFlags(Flags);
5954
5955 B.buildIntrinsic(Intrinsic::amdgcn_div_fixup, ArrayRef(Res))
5956 .addUse(Fmas.getReg(0))
5957 .addUse(RHS)
5958 .addUse(LHS)
5959 .setMIFlags(Flags);
5960
5961 MI.eraseFromParent();
5962 return true;
5963}
5964
5967 MachineIRBuilder &B) const {
5968 Register Res0 = MI.getOperand(0).getReg();
5969 Register Res1 = MI.getOperand(1).getReg();
5970 Register Val = MI.getOperand(2).getReg();
5971 uint16_t Flags = MI.getFlags();
5972
5973 LLT Ty = MRI.getType(Res0);
5974 LLT InstrExpTy = Ty == F16 ? LLT::integer(16) : LLT::integer(32);
5975
5976 auto Mant = B.buildIntrinsic(Intrinsic::amdgcn_frexp_mant, {Ty})
5977 .addUse(Val)
5978 .setMIFlags(Flags);
5979 auto Exp = B.buildIntrinsic(Intrinsic::amdgcn_frexp_exp, {InstrExpTy})
5980 .addUse(Val)
5981 .setMIFlags(Flags);
5982
5983 if (ST.hasFractBug()) {
5984 auto Fabs = B.buildFAbs(Ty, Val);
5985 auto Inf = B.buildFConstant(Ty, APFloat::getInf(getFltSemanticForLLT(Ty)));
5986 auto IsFinite =
5987 B.buildFCmp(CmpInst::FCMP_OLT, LLT::scalar(1), Fabs, Inf, Flags);
5988 auto Zero = B.buildConstant(InstrExpTy, 0);
5989 Exp = B.buildSelect(InstrExpTy, IsFinite, Exp, Zero);
5990 Mant = B.buildSelect(Ty, IsFinite, Mant, Val);
5991 }
5992
5993 B.buildCopy(Res0, Mant);
5994 B.buildSExtOrTrunc(Res1, Exp);
5995
5996 MI.eraseFromParent();
5997 return true;
5998}
5999
6002 MachineIRBuilder &B) const {
6003 Register Res = MI.getOperand(0).getReg();
6004 Register LHS = MI.getOperand(2).getReg();
6005 Register RHS = MI.getOperand(3).getReg();
6006 uint16_t Flags = MI.getFlags();
6007
6008 LLT S1 = LLT::scalar(1);
6009
6010 auto Abs = B.buildFAbs(F32, RHS, Flags);
6011 const APFloat C0Val(1.0f);
6012
6013 auto C0 = B.buildFConstant(F32, 0x1p+96f);
6014 auto C1 = B.buildFConstant(F32, 0x1p-32f);
6015 auto C2 = B.buildFConstant(F32, 1.0f);
6016
6017 auto CmpRes = B.buildFCmp(CmpInst::FCMP_OGT, S1, Abs, C0, Flags);
6018 auto Sel = B.buildSelect(F32, CmpRes, C1, C2, Flags);
6019
6020 auto Mul0 = B.buildFMul(F32, RHS, Sel, Flags);
6021
6022 auto RCP = B.buildIntrinsic(Intrinsic::amdgcn_rcp, {F32})
6023 .addUse(Mul0.getReg(0))
6024 .setMIFlags(Flags);
6025
6026 auto Mul1 = B.buildFMul(F32, LHS, RCP, Flags);
6027
6028 B.buildFMul(Res, Sel, Mul1, Flags);
6029
6030 MI.eraseFromParent();
6031 return true;
6032}
6033
6036 MachineIRBuilder &B) const {
6037 // Bypass the correct expansion a standard promotion through G_FSQRT would
6038 // get. The f32 op is accurate enough for the f16 cas.
6039 unsigned Flags = MI.getFlags();
6040 assert(!ST.has16BitInsts());
6041 auto Ext = B.buildFPExt(F32, MI.getOperand(1), Flags);
6042 auto Log2 = B.buildIntrinsic(Intrinsic::amdgcn_sqrt, {F32})
6043 .addUse(Ext.getReg(0))
6044 .setMIFlags(Flags);
6045 B.buildFPTrunc(MI.getOperand(0), Log2, Flags);
6046 MI.eraseFromParent();
6047 return true;
6048}
6049
6052 MachineIRBuilder &B) const {
6053 MachineFunction &MF = B.getMF();
6054 Register Dst = MI.getOperand(0).getReg();
6055 Register X = MI.getOperand(1).getReg();
6056 const unsigned Flags = MI.getFlags();
6057 const LLT I1 = LLT::integer(1);
6058 const LLT I32 = LLT::integer(32);
6059
6060 if (allowApproxFunc(MF, Flags)) {
6061 B.buildIntrinsic(Intrinsic::amdgcn_sqrt, ArrayRef<Register>({Dst}))
6062 .addUse(X)
6063 .setMIFlags(Flags);
6064 MI.eraseFromParent();
6065 return true;
6066 }
6067
6068 auto ScaleThreshold = B.buildFConstant(F32, 0x1.0p-96f);
6069 auto NeedScale = B.buildFCmp(CmpInst::FCMP_OGT, I1, ScaleThreshold, X, Flags);
6070 auto ScaleUpFactor = B.buildFConstant(F32, 0x1.0p+32f);
6071 auto ScaledX = B.buildFMul(F32, X, ScaleUpFactor, Flags);
6072 auto SqrtX = B.buildSelect(F32, NeedScale, ScaledX, X, Flags);
6073
6075 if (needsDenormHandlingF32(MF, X, Flags)) {
6076 B.buildIntrinsic(Intrinsic::amdgcn_sqrt, ArrayRef<Register>({SqrtS}))
6077 .addUse(SqrtX.getReg(0))
6078 .setMIFlags(Flags);
6079
6080 auto SqrtSInt = B.buildBitcast(I32, SqrtS);
6081 auto NegOne = B.buildConstant(I32, -1);
6082 auto SqrtSNextDown = B.buildBitcast(F32, B.buildAdd(I32, SqrtSInt, NegOne));
6083
6084 auto NegSqrtSNextDown = B.buildFNeg(F32, SqrtSNextDown, Flags);
6085 auto SqrtVP = B.buildFMA(F32, NegSqrtSNextDown, SqrtS, SqrtX, Flags);
6086
6087 auto PosOne = B.buildConstant(I32, 1);
6088 auto SqrtSNextUp = B.buildBitcast(F32, B.buildAdd(I32, SqrtSInt, PosOne));
6089
6090 auto NegSqrtSNextUp = B.buildFNeg(F32, SqrtSNextUp, Flags);
6091 auto SqrtVS = B.buildFMA(F32, NegSqrtSNextUp, SqrtS, SqrtX, Flags);
6092
6093 auto Zero = B.buildFConstant(F32, 0.0f);
6094 auto SqrtVPLE0 = B.buildFCmp(CmpInst::FCMP_OLE, I1, SqrtVP, Zero, Flags);
6095
6096 SqrtS =
6097 B.buildSelect(F32, SqrtVPLE0, SqrtSNextDown, SqrtS, Flags).getReg(0);
6098
6099 auto SqrtVPVSGT0 = B.buildFCmp(CmpInst::FCMP_OGT, I1, SqrtVS, Zero, Flags);
6100 SqrtS =
6101 B.buildSelect(F32, SqrtVPVSGT0, SqrtSNextUp, SqrtS, Flags).getReg(0);
6102 } else {
6103 auto SqrtR =
6104 B.buildIntrinsic(Intrinsic::amdgcn_rsq, {F32}).addReg(SqrtX.getReg(0));
6105 B.buildFMul(SqrtS, SqrtX, SqrtR, Flags);
6106
6107 auto Half = B.buildFConstant(F32, 0.5f);
6108 auto SqrtH = B.buildFMul(F32, SqrtR, Half, Flags);
6109 auto NegSqrtH = B.buildFNeg(F32, SqrtH, Flags);
6110 auto SqrtE = B.buildFMA(F32, NegSqrtH, SqrtS, Half, Flags);
6111 SqrtH = B.buildFMA(F32, SqrtH, SqrtE, SqrtH, Flags);
6112 SqrtS = B.buildFMA(F32, SqrtS, SqrtE, SqrtS, Flags).getReg(0);
6113 auto NegSqrtS = B.buildFNeg(F32, SqrtS, Flags);
6114 auto SqrtD = B.buildFMA(F32, NegSqrtS, SqrtS, SqrtX, Flags);
6115 SqrtS = B.buildFMA(F32, SqrtD, SqrtH, SqrtS, Flags).getReg(0);
6116 }
6117
6118 auto ScaleDownFactor = B.buildFConstant(F32, 0x1.0p-16f);
6119
6120 auto ScaledDown = B.buildFMul(F32, SqrtS, ScaleDownFactor, Flags);
6121
6122 SqrtS = B.buildSelect(F32, NeedScale, ScaledDown, SqrtS, Flags).getReg(0);
6123
6124 auto IsZeroOrInf = B.buildIsFPClass(I1, SqrtX, fcZero | fcPosInf);
6125 B.buildSelect(Dst, IsZeroOrInf, SqrtX, SqrtS, Flags);
6126
6127 MI.eraseFromParent();
6128 return true;
6129}
6130
6133 MachineIRBuilder &B) const {
6134 // For double type, the SQRT and RSQ instructions don't have required
6135 // precision, we apply Goldschmidt's algorithm to improve the result:
6136 //
6137 // y0 = rsq(x)
6138 // g0 = x * y0
6139 // h0 = 0.5 * y0
6140 //
6141 // r0 = 0.5 - h0 * g0
6142 // g1 = g0 * r0 + g0
6143 // h1 = h0 * r0 + h0
6144 //
6145 // r1 = 0.5 - h1 * g1 => d0 = x - g1 * g1
6146 // g2 = g1 * r1 + g1 g2 = d0 * h1 + g1
6147 // h2 = h1 * r1 + h1
6148 //
6149 // r2 = 0.5 - h2 * g2 => d1 = x - g2 * g2
6150 // g3 = g2 * r2 + g2 g3 = d1 * h1 + g2
6151 //
6152 // sqrt(x) = g3
6153
6154 const LLT I1 = LLT::integer(1);
6155 const LLT I32 = LLT::integer(32);
6156
6157 Register Dst = MI.getOperand(0).getReg();
6158 assert(MRI.getType(Dst) == F64 && "only expect to lower f64 sqrt");
6159
6160 Register X = MI.getOperand(1).getReg();
6161 unsigned Flags = MI.getFlags();
6162
6163 Register SqrtX = X;
6164 Register Scaling, ZeroInt;
6165 if (!MI.getFlag(MachineInstr::FmAfn)) {
6166 auto ScaleConstant = B.buildFConstant(F64, 0x1.0p-767);
6167
6168 ZeroInt = B.buildConstant(I32, 0).getReg(0);
6169 Scaling = B.buildFCmp(FCmpInst::FCMP_OLT, I1, X, ScaleConstant).getReg(0);
6170
6171 // Scale up input if it is too small.
6172 auto ScaleUpFactor = B.buildConstant(I32, 256);
6173 auto ScaleUp = B.buildSelect(I32, Scaling, ScaleUpFactor, ZeroInt);
6174 SqrtX = B.buildFLdexp(F64, X, ScaleUp, Flags).getReg(0);
6175 }
6176
6177 auto SqrtY = B.buildIntrinsic(Intrinsic::amdgcn_rsq, {F64}).addReg(SqrtX);
6178
6179 auto Half = B.buildFConstant(F64, 0.5);
6180 auto SqrtH0 = B.buildFMul(F64, SqrtY, Half);
6181 auto SqrtS0 = B.buildFMul(F64, SqrtX, SqrtY);
6182
6183 auto NegSqrtH0 = B.buildFNeg(F64, SqrtH0);
6184 auto SqrtR0 = B.buildFMA(F64, NegSqrtH0, SqrtS0, Half);
6185
6186 auto SqrtS1 = B.buildFMA(F64, SqrtS0, SqrtR0, SqrtS0);
6187 auto SqrtH1 = B.buildFMA(F64, SqrtH0, SqrtR0, SqrtH0);
6188
6189 auto NegSqrtS1 = B.buildFNeg(F64, SqrtS1);
6190 auto SqrtD0 = B.buildFMA(F64, NegSqrtS1, SqrtS1, SqrtX);
6191
6192 auto SqrtS2 = B.buildFMA(F64, SqrtD0, SqrtH1, SqrtS1);
6193
6194 Register SqrtRet = SqrtS2.getReg(0);
6195 if (!MI.getFlag(MachineInstr::FmAfn)) {
6196 auto NegSqrtS2 = B.buildFNeg(F64, SqrtS2);
6197 auto SqrtD1 = B.buildFMA(F64, NegSqrtS2, SqrtS2, SqrtX);
6198 auto SqrtD2 = B.buildFMA(F64, SqrtD1, SqrtH1, SqrtS2);
6199
6200 // Scale down the result.
6201 auto ScaleDownFactor = B.buildConstant(I32, -128);
6202 auto ScaleDown = B.buildSelect(I32, Scaling, ScaleDownFactor, ZeroInt);
6203 SqrtRet = B.buildFLdexp(F64, SqrtD2, ScaleDown, Flags).getReg(0);
6204 }
6205
6206 Register IsZeroOrInf;
6207 if (MI.getFlag(MachineInstr::FmNoInfs)) {
6208 auto ZeroFP = B.buildFConstant(F64, 0.0);
6209 IsZeroOrInf = B.buildFCmp(FCmpInst::FCMP_OEQ, I1, SqrtX, ZeroFP).getReg(0);
6210 } else {
6211 IsZeroOrInf = B.buildIsFPClass(I1, SqrtX, fcZero | fcPosInf).getReg(0);
6212 }
6213
6214 // TODO: Check for DAZ and expand to subnormals
6215
6216 // If x is +INF, +0, or -0, use its original value
6217 B.buildSelect(Dst, IsZeroOrInf, SqrtX, SqrtRet, Flags);
6218
6219 MI.eraseFromParent();
6220 return true;
6221}
6222
6225 MachineIRBuilder &B) const {
6226 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
6227 if (Ty == F32)
6228 return legalizeFSQRTF32(MI, MRI, B);
6229 if (Ty == F64)
6230 return legalizeFSQRTF64(MI, MRI, B);
6231 if (Ty == F16)
6232 return legalizeFSQRTF16(MI, MRI, B);
6233 return false;
6234}
6235
6236// Expand llvm.amdgcn.rsq.clamp on targets that don't support the instruction.
6237// FIXME: Why do we handle this one but not other removed instructions?
6238//
6239// Reciprocal square root. The clamp prevents infinite results, clamping
6240// infinities to max_float. D.f = 1.0 / sqrt(S0.f), result clamped to
6241// +-max_float.
6244 MachineIRBuilder &B) const {
6245 if (ST.getGeneration() < AMDGPUSubtarget::VOLCANIC_ISLANDS)
6246 return true;
6247
6248 Register Dst = MI.getOperand(0).getReg();
6249 Register Src = MI.getOperand(2).getReg();
6250 auto Flags = MI.getFlags();
6251
6252 LLT Ty = MRI.getType(Dst);
6253
6254 const fltSemantics *FltSemantics;
6255 if (Ty == F32)
6256 FltSemantics = &APFloat::IEEEsingle();
6257 else if (Ty == F64)
6258 FltSemantics = &APFloat::IEEEdouble();
6259 else
6260 return false;
6261
6262 auto Rsq = B.buildIntrinsic(Intrinsic::amdgcn_rsq, {Ty})
6263 .addUse(Src)
6264 .setMIFlags(Flags);
6265
6266 // We don't need to concern ourselves with the snan handling difference, since
6267 // the rsq quieted (or not) so use the one which will directly select.
6268 const SIMachineFunctionInfo *MFI = B.getMF().getInfo<SIMachineFunctionInfo>();
6269 const bool UseIEEE = MFI->getMode().IEEE;
6270
6271 auto MaxFlt = B.buildFConstant(Ty, APFloat::getLargest(*FltSemantics));
6272 auto ClampMax = UseIEEE ? B.buildFMinNumIEEE(Ty, Rsq, MaxFlt, Flags) :
6273 B.buildFMinNum(Ty, Rsq, MaxFlt, Flags);
6274
6275 auto MinFlt = B.buildFConstant(Ty, APFloat::getLargest(*FltSemantics, true));
6276
6277 if (UseIEEE)
6278 B.buildFMaxNumIEEE(Dst, ClampMax, MinFlt, Flags);
6279 else
6280 B.buildFMaxNum(Dst, ClampMax, MinFlt, Flags);
6281 MI.eraseFromParent();
6282 return true;
6283}
6284
6285// TODO: Fix pointer type handling
6288 Intrinsic::ID IID) const {
6289
6290 MachineIRBuilder &B = Helper.MIRBuilder;
6291 MachineRegisterInfo &MRI = *B.getMRI();
6292
6293 bool IsPermLane16 = IID == Intrinsic::amdgcn_permlane16 ||
6294 IID == Intrinsic::amdgcn_permlanex16;
6295 bool IsSetInactive = IID == Intrinsic::amdgcn_set_inactive ||
6296 IID == Intrinsic::amdgcn_set_inactive_chain_arg;
6297 bool IsPermlaneShuffle = IID == Intrinsic::amdgcn_permlane_bcast ||
6298 IID == Intrinsic::amdgcn_permlane_up ||
6299 IID == Intrinsic::amdgcn_permlane_down ||
6300 IID == Intrinsic::amdgcn_permlane_xor;
6301
6302 auto createLaneOp = [&IID, &B, &MI](Register Src0, Register Src1,
6303 Register Src2, LLT VT) -> Register {
6304 auto LaneOp = B.buildIntrinsic(IID, {VT}).addUse(Src0);
6305 switch (IID) {
6306 case Intrinsic::amdgcn_readfirstlane:
6307 case Intrinsic::amdgcn_permlane64:
6308 return LaneOp.getReg(0);
6309 case Intrinsic::amdgcn_readlane:
6310 case Intrinsic::amdgcn_set_inactive:
6311 case Intrinsic::amdgcn_set_inactive_chain_arg:
6312 return LaneOp.addUse(Src1).getReg(0);
6313 case Intrinsic::amdgcn_writelane:
6314 case Intrinsic::amdgcn_permlane_bcast:
6315 case Intrinsic::amdgcn_permlane_up:
6316 case Intrinsic::amdgcn_permlane_down:
6317 case Intrinsic::amdgcn_permlane_xor:
6318 return LaneOp.addUse(Src1).addUse(Src2).getReg(0);
6319 case Intrinsic::amdgcn_permlane16:
6320 case Intrinsic::amdgcn_permlanex16: {
6321 Register Src3 = MI.getOperand(5).getReg();
6322 int64_t Src4 = MI.getOperand(6).getImm();
6323 int64_t Src5 = MI.getOperand(7).getImm();
6324 return LaneOp.addUse(Src1)
6325 .addUse(Src2)
6326 .addUse(Src3)
6327 .addImm(Src4)
6328 .addImm(Src5)
6329 .getReg(0);
6330 }
6331 case Intrinsic::amdgcn_mov_dpp8:
6332 return LaneOp.addImm(MI.getOperand(3).getImm()).getReg(0);
6333 case Intrinsic::amdgcn_update_dpp:
6334 return LaneOp.addUse(Src1)
6335 .addImm(MI.getOperand(4).getImm())
6336 .addImm(MI.getOperand(5).getImm())
6337 .addImm(MI.getOperand(6).getImm())
6338 .addImm(MI.getOperand(7).getImm())
6339 .getReg(0);
6340 default:
6341 llvm_unreachable("unhandled lane op");
6342 }
6343 };
6344
6345 Register DstReg = MI.getOperand(0).getReg();
6346 Register Src0 = MI.getOperand(2).getReg();
6347 Register Src1, Src2;
6348 if (IID == Intrinsic::amdgcn_readlane || IID == Intrinsic::amdgcn_writelane ||
6349 IID == Intrinsic::amdgcn_update_dpp || IsSetInactive || IsPermLane16 ||
6350 IsPermlaneShuffle) {
6351 Src1 = MI.getOperand(3).getReg();
6352 if (IID == Intrinsic::amdgcn_writelane || IsPermLane16 ||
6353 IsPermlaneShuffle) {
6354 Src2 = MI.getOperand(4).getReg();
6355 }
6356 }
6357
6358 LLT Ty = MRI.getType(DstReg);
6359 unsigned Size = Ty.getSizeInBits();
6360
6361 unsigned SplitSize = 32;
6362 if (IID == Intrinsic::amdgcn_update_dpp && (Size % 64 == 0) &&
6363 ST.hasDPALU_DPP() &&
6364 AMDGPU::isLegalDPALU_DPPControl(ST, MI.getOperand(4).getImm()))
6365 SplitSize = 64;
6366
6367 if (Size == SplitSize) {
6368 // Already legal
6369 return true;
6370 }
6371
6372 const LLT I32 = LLT::integer(32);
6373
6374 bool IsFloat = Ty.getScalarType().isFloat();
6375
6376 LLT IntTy = IsFloat ? LLT::integer(Size) : Ty;
6377 if (IsFloat) {
6378 Src0 = B.buildBitcast(IntTy, Src0).getReg(0);
6379 if (Src1 && MRI.getType(Src1).getScalarType().isFloat())
6380 Src1 = B.buildBitcast(IntTy, Src1).getReg(0);
6381 if (Src2 && MRI.getType(Src2).getScalarType().isFloat())
6382 Src2 = B.buildBitcast(IntTy, Src2).getReg(0);
6383 }
6384
6385 if (Size < 32) {
6386 Src0 = B.buildAnyExt(I32, Src0).getReg(0);
6387
6388 if (IID == Intrinsic::amdgcn_update_dpp || IsSetInactive || IsPermLane16)
6389 Src1 = B.buildAnyExt(I32, Src1).getReg(0);
6390
6391 if (IID == Intrinsic::amdgcn_writelane)
6392 Src2 = B.buildAnyExt(I32, Src2).getReg(0);
6393
6394 Register LaneOpDst = createLaneOp(Src0, Src1, Src2, I32);
6395 if (IsFloat)
6396 B.buildBitcast(DstReg, B.buildTrunc(IntTy, LaneOpDst));
6397 else
6398 B.buildTrunc(DstReg, LaneOpDst);
6399 MI.eraseFromParent();
6400 return true;
6401 }
6402
6403 if (Size % SplitSize != 0)
6404 return false;
6405
6406 LLT PartialResTy = LLT::integer(SplitSize);
6407 bool NeedsBitcast = false;
6408 if (IntTy.isVector()) {
6409 LLT EltTy = IntTy.getElementType();
6410 unsigned EltSize = EltTy.getSizeInBits();
6411 if (EltSize == SplitSize) {
6412 PartialResTy = EltTy;
6413 } else if (EltSize == 16 || EltSize == 32) {
6414 unsigned NElem = SplitSize / EltSize;
6415 PartialResTy = IntTy.changeElementCount(ElementCount::getFixed(NElem));
6416 } else {
6417 NeedsBitcast = true;
6418 }
6419 }
6420
6421 SmallVector<Register, 4> PartialRes;
6422 unsigned NumParts = Size / SplitSize;
6423 MachineInstrBuilder Src0Parts = B.buildUnmerge(PartialResTy, Src0);
6424 MachineInstrBuilder Src1Parts, Src2Parts;
6425
6426 if (IID == Intrinsic::amdgcn_update_dpp || IsSetInactive || IsPermLane16)
6427 Src1Parts = B.buildUnmerge(PartialResTy, Src1);
6428
6429 if (IID == Intrinsic::amdgcn_writelane)
6430 Src2Parts = B.buildUnmerge(PartialResTy, Src2);
6431
6432 for (unsigned i = 0; i < NumParts; ++i) {
6433 Src0 = Src0Parts.getReg(i);
6434
6435 if (IID == Intrinsic::amdgcn_update_dpp || IsSetInactive || IsPermLane16)
6436 Src1 = Src1Parts.getReg(i);
6437
6438 if (IID == Intrinsic::amdgcn_writelane)
6439 Src2 = Src2Parts.getReg(i);
6440
6441 PartialRes.push_back(createLaneOp(Src0, Src1, Src2, PartialResTy));
6442 }
6443
6444 if (NeedsBitcast || IsFloat)
6445 B.buildBitcast(
6446 DstReg,
6447 B.buildMergeLikeInstr(LLT::integer(IntTy.getSizeInBits()), PartialRes));
6448 else
6449 B.buildMergeLikeInstr(DstReg, PartialRes);
6450
6451 MI.eraseFromParent();
6452 return true;
6453}
6454
6457 MachineIRBuilder &B) const {
6458 uint64_t Offset =
6459 ST.getTargetLowering()->getImplicitParameterOffset(
6461 LLT DstTy = MRI.getType(DstReg);
6462 LLT IdxTy = LLT::integer(DstTy.getSizeInBits());
6463
6464 Register KernargPtrReg = MRI.createGenericVirtualRegister(DstTy);
6465 if (!loadInputValue(KernargPtrReg, B,
6467 return false;
6468
6469 B.buildObjectPtrOffset(DstReg, KernargPtrReg,
6470 B.buildConstant(IdxTy, Offset).getReg(0));
6471 return true;
6472}
6473
6474/// To create a buffer resource from a 64-bit pointer, mask off the upper 32
6475/// bits of the pointer and replace them with the stride argument, then
6476/// merge_values everything together. In the common case of a raw buffer (the
6477/// stride component is 0), we can just AND off the upper half.
6480 Register Result = MI.getOperand(0).getReg();
6481 Register Pointer = MI.getOperand(2).getReg();
6482 Register Stride = MI.getOperand(3).getReg();
6483 Register NumRecords = MI.getOperand(4).getReg();
6484 Register Flags = MI.getOperand(5).getReg();
6485
6486 LLT I32 = LLT::integer(32);
6487 LLT I64 = LLT::integer(64);
6488
6489 B.setInsertPt(B.getMBB(), ++B.getInsertPt());
6490
6491 auto ExtStride = B.buildAnyExt(I32, Stride);
6492
6493 if (ST.getBufferResourceNumRecordsWidth() == 45) {
6494 NumRecords = B.buildZExtOrTrunc(I64, NumRecords).getReg(0);
6495 NumRecords =
6496 B.buildAnd(I64, NumRecords, B.buildConstant(I64, (1ULL << 45) - 1))
6497 .getReg(0);
6498 Register Zero = B.buildConstant(I32, 0).getReg(0);
6499 // Build the lower 64-bit value, which has a 57-bit base and the lower 7-bit
6500 // num_records.
6501 LLT PtrIntTy = LLT::integer(MRI.getType(Pointer).getSizeInBits());
6502 auto PointerInt = B.buildPtrToInt(PtrIntTy, Pointer);
6503 auto ExtPointer = B.buildAnyExtOrTrunc(I64, PointerInt);
6504 auto NumRecordsLHS = B.buildShl(I64, NumRecords, B.buildConstant(I32, 57));
6505 Register LowHalf = B.buildOr(I64, ExtPointer, NumRecordsLHS).getReg(0);
6506
6507 // Build the higher 64-bit value, which has the higher 38-bit num_records,
6508 // 6-bit zero (omit), 16-bit stride and scale and 4-bit flag.
6509 auto NumRecordsRHS = B.buildLShr(I64, NumRecords, B.buildConstant(I32, 7));
6510 auto ShiftedStride = B.buildShl(I32, ExtStride, B.buildConstant(I32, 12));
6511 auto ExtShiftedStride =
6512 B.buildMergeValues(I64, {Zero, ShiftedStride.getReg(0)});
6513 auto ShiftedFlags = B.buildShl(I32, Flags, B.buildConstant(I32, 28));
6514 auto ExtShiftedFlags =
6515 B.buildMergeValues(I64, {Zero, ShiftedFlags.getReg(0)});
6516 auto CombinedFields = B.buildOr(I64, NumRecordsRHS, ExtShiftedStride);
6517 Register HighHalf =
6518 B.buildOr(I64, CombinedFields, ExtShiftedFlags).getReg(0);
6519 B.buildMergeValues(Result, {LowHalf, HighHalf});
6520 } else {
6521 NumRecords = B.buildZExtOrTrunc(I32, NumRecords).getReg(0);
6522 auto Unmerge = B.buildUnmerge(I32, Pointer);
6523 auto LowHalf = Unmerge.getReg(0);
6524 auto HighHalf = Unmerge.getReg(1);
6525
6526 auto AndMask = B.buildConstant(I32, 0x0000ffff);
6527 auto Masked = B.buildAnd(I32, HighHalf, AndMask);
6528 auto ShiftConst = B.buildConstant(I32, 16);
6529 auto ShiftedStride = B.buildShl(I32, ExtStride, ShiftConst);
6530 auto NewHighHalf = B.buildOr(I32, Masked, ShiftedStride);
6531 Register NewHighHalfReg = NewHighHalf.getReg(0);
6532 B.buildMergeValues(Result, {LowHalf, NewHighHalfReg, NumRecords, Flags});
6533 }
6534
6535 MI.eraseFromParent();
6536 return true;
6537}
6538
6541 MachineIRBuilder &B) const {
6542 const SIMachineFunctionInfo *MFI = B.getMF().getInfo<SIMachineFunctionInfo>();
6543 if (!MFI->isEntryFunction()) {
6544 return legalizePreloadedArgIntrin(MI, MRI, B,
6546 }
6547
6548 Register DstReg = MI.getOperand(0).getReg();
6549 if (!getImplicitArgPtr(DstReg, MRI, B))
6550 return false;
6551
6552 MI.eraseFromParent();
6553 return true;
6554}
6555
6559 unsigned AddrSpace) const {
6560 const LLT I32 = LLT::integer(32);
6561 auto Unmerge = B.buildUnmerge(I32, MI.getOperand(2).getReg());
6562 Register Hi32 = Unmerge.getReg(1);
6563
6564 if (AddrSpace == AMDGPUAS::PRIVATE_ADDRESS &&
6565 ST.hasGloballyAddressableScratch()) {
6566 Register FlatScratchBaseHi =
6567 B.buildInstr(AMDGPU::S_MOV_B32, {I32},
6568 {Register(AMDGPU::SRC_FLAT_SCRATCH_BASE_HI)})
6569 .getReg(0);
6570 MRI.setRegClass(FlatScratchBaseHi, &AMDGPU::SReg_32RegClass);
6571 // Test bits 63..58 against the aperture address.
6572 Register XOR = B.buildXor(I32, Hi32, FlatScratchBaseHi).getReg(0);
6573 B.buildICmp(ICmpInst::ICMP_ULT, MI.getOperand(0), XOR,
6574 B.buildConstant(I32, 1u << 26));
6575 } else {
6576 Register ApertureReg = getSegmentAperture(AddrSpace, MRI, B);
6577 B.buildICmp(ICmpInst::ICMP_EQ, MI.getOperand(0), Hi32, ApertureReg);
6578 }
6579 MI.eraseFromParent();
6580 return true;
6581}
6582
6583// The raw.(t)buffer and struct.(t)buffer intrinsics have two offset args:
6584// offset (the offset that is included in bounds checking and swizzling, to be
6585// split between the instruction's voffset and immoffset fields) and soffset
6586// (the offset that is excluded from bounds checking and swizzling, to go in
6587// the instruction's soffset field). This function takes the first kind of
6588// offset and figures out how to split it between voffset and immoffset.
6589std::pair<Register, unsigned>
6591 Register OrigOffset) const {
6592 const unsigned MaxImm = SIInstrInfo::getMaxMUBUFImmOffset(ST);
6593 Register BaseReg;
6594 unsigned ImmOffset;
6595 const LLT I32 = LLT::integer(32);
6596 MachineRegisterInfo &MRI = *B.getMRI();
6597
6598 // On GFX1250+, voffset and immoffset are zero-extended from 32 bits before
6599 // being added, so we can only safely match a 32-bit addition with no unsigned
6600 // overflow.
6601 bool CheckNUW = ST.hasGFX1250Insts();
6602 std::tie(BaseReg, ImmOffset) = AMDGPU::getBaseWithConstantOffset(
6603 MRI, OrigOffset, /*KnownBits=*/nullptr, CheckNUW);
6604
6605 // If BaseReg is a pointer, convert it to int.
6606 if (MRI.getType(BaseReg).isPointer())
6607 BaseReg = B.buildPtrToInt(MRI.getType(OrigOffset), BaseReg).getReg(0);
6608
6609 // If the immediate value is too big for the immoffset field, put only bits
6610 // that would normally fit in the immoffset field. The remaining value that
6611 // is copied/added for the voffset field is a large power of 2, and it
6612 // stands more chance of being CSEd with the copy/add for another similar
6613 // load/store.
6614 // However, do not do that rounding down if that is a negative
6615 // number, as it appears to be illegal to have a negative offset in the
6616 // vgpr, even if adding the immediate offset makes it positive.
6617 unsigned Overflow = ImmOffset & ~MaxImm;
6618 ImmOffset -= Overflow;
6619 if ((int32_t)Overflow < 0) {
6620 Overflow += ImmOffset;
6621 ImmOffset = 0;
6622 }
6623
6624 if (Overflow != 0) {
6625 if (!BaseReg) {
6626 BaseReg = B.buildConstant(I32, Overflow).getReg(0);
6627 } else {
6628 auto OverflowVal = B.buildConstant(I32, Overflow);
6629 BaseReg = B.buildAdd(I32, BaseReg, OverflowVal).getReg(0);
6630 }
6631 }
6632
6633 if (!BaseReg)
6634 BaseReg = B.buildConstant(I32, 0).getReg(0);
6635
6636 return std::pair(BaseReg, ImmOffset);
6637}
6638
6639/// Handle register layout difference for f16 images for some subtargets.
6642 Register Reg,
6643 bool ImageStore) const {
6644 const LLT I16 = LLT::integer(16);
6645 const LLT I32 = LLT::integer(32);
6646 LLT StoreVT = MRI.getType(Reg);
6647 assert(StoreVT.isVector() && StoreVT.getElementType().getSizeInBits() == 16);
6648
6649 LLT I16Vec = StoreVT.changeElementType(I16);
6650 Register RegI16 =
6651 StoreVT == I16Vec ? Reg : B.buildBitcast(I16Vec, Reg).getReg(0);
6652
6653 if (ST.hasUnpackedD16VMem()) {
6654 auto Unmerge = B.buildUnmerge(I16, RegI16);
6655
6656 SmallVector<Register, 4> WideRegs;
6657 for (int I = 0, E = Unmerge->getNumOperands() - 1; I != E; ++I)
6658 WideRegs.push_back(B.buildAnyExt(I32, Unmerge.getReg(I)).getReg(0));
6659
6660 int NumElts = StoreVT.getNumElements();
6661
6662 return B.buildBuildVector(LLT::fixed_vector(NumElts, I32), WideRegs)
6663 .getReg(0);
6664 }
6665
6666 if (ImageStore && ST.hasImageStoreD16Bug()) {
6667 if (StoreVT.getNumElements() == 2) {
6668 SmallVector<Register, 4> PackedRegs;
6669 Reg = B.buildBitcast(I32, RegI16).getReg(0);
6670 PackedRegs.push_back(Reg);
6671 PackedRegs.resize(2, B.buildUndef(I32).getReg(0));
6672 return B.buildBuildVector(LLT::fixed_vector(2, I32), PackedRegs)
6673 .getReg(0);
6674 }
6675
6676 if (StoreVT.getNumElements() == 3) {
6677 SmallVector<Register, 4> PackedRegs;
6678 auto Unmerge = B.buildUnmerge(I16, RegI16);
6679 for (int I = 0, E = Unmerge->getNumOperands() - 1; I != E; ++I)
6680 PackedRegs.push_back(Unmerge.getReg(I));
6681 PackedRegs.resize(6, B.buildUndef(I16).getReg(0));
6682 Reg = B.buildBuildVector(LLT::fixed_vector(6, I16), PackedRegs).getReg(0);
6683 return B.buildBitcast(LLT::fixed_vector(3, I32), Reg).getReg(0);
6684 }
6685
6686 if (StoreVT.getNumElements() == 4) {
6687 SmallVector<Register, 4> PackedRegs;
6688 Reg = B.buildBitcast(LLT::fixed_vector(2, I32), RegI16).getReg(0);
6689 auto Unmerge = B.buildUnmerge(I32, Reg);
6690 for (int I = 0, E = Unmerge->getNumOperands() - 1; I != E; ++I)
6691 PackedRegs.push_back(Unmerge.getReg(I));
6692 PackedRegs.resize(4, B.buildUndef(I32).getReg(0));
6693 return B.buildBuildVector(LLT::fixed_vector(4, I32), PackedRegs)
6694 .getReg(0);
6695 }
6696
6697 llvm_unreachable("invalid data type");
6698 }
6699
6700 if (StoreVT.isVector() && StoreVT.getNumElements() == 3 &&
6701 StoreVT.getElementType().getSizeInBits() == 16) {
6702 Reg = B.buildPadVectorWithUndefElements(
6703 LLT::fixed_vector(4, StoreVT.getElementType()), Reg)
6704 .getReg(0);
6705 }
6706 return Reg;
6707}
6708
6710 Register VData, LLT MemTy,
6711 bool IsFormat) const {
6712 MachineRegisterInfo *MRI = B.getMRI();
6713 LLT Ty = MRI->getType(VData);
6714
6715 // Fixup buffer resources themselves needing to be v4i128.
6717 return castBufferRsrcToV4I32(VData, B);
6718
6719 if (shouldBitcastLoadStoreType(ST, Ty, MemTy)) {
6720 Ty = getBitcastRegisterType(Ty);
6721 VData = B.buildBitcast(Ty, VData).getReg(0);
6722 }
6723 if (Ty.isFloat(16)) {
6724 Ty = LLT::integer(16);
6725 VData = B.buildBitcast(Ty, VData).getReg(0);
6726 }
6727
6728 // Fixup illegal register types for i8 stores.
6729 if (Ty == LLT::integer(8) || Ty == LLT::integer(16))
6730 return B.buildAnyExt(LLT::integer(32), VData).getReg(0);
6731
6732 if (Ty.isVector()) {
6733 if (Ty.getElementType().getSizeInBits() == 16 && Ty.getNumElements() <= 4) {
6734 if (IsFormat)
6735 return handleD16VData(B, *MRI, VData);
6736 }
6737 }
6738
6739 return VData;
6740}
6741
6743 LegalizerHelper &Helper,
6744 bool IsTyped,
6745 bool IsFormat) const {
6746 MachineIRBuilder &B = Helper.MIRBuilder;
6747 MachineRegisterInfo &MRI = *B.getMRI();
6748
6749 Register VData = MI.getOperand(1).getReg();
6750 LLT Ty = MRI.getType(VData);
6751 LLT EltTy = Ty.getScalarType();
6752 const bool IsD16 = IsFormat && (EltTy.getSizeInBits() == 16);
6753 const LLT I32 = LLT::integer(32);
6754
6755 MachineMemOperand *MMO = *MI.memoperands_begin();
6756 const int MemSize = MMO->getSize().getValue();
6757 LLT MemTy = MMO->getMemoryType();
6758
6759 if (IsFormat && !IsTyped && !IsD16 && MemTy.getSizeInBits() < 32) {
6760 const Function &Fn = B.getMF().getFunction();
6762 Fn, "unsupported sub-dword format buffer store", MI.getDebugLoc()));
6763 MI.eraseFromParent();
6764 return true;
6765 }
6766
6767 VData = fixStoreSourceType(B, VData, MemTy, IsFormat);
6768
6770 Register RSrc = MI.getOperand(2).getReg();
6771
6772 unsigned ImmOffset;
6773
6774 // The typed intrinsics add an immediate after the registers.
6775 const unsigned NumVIndexOps = IsTyped ? 8 : 7;
6776
6777 // The struct intrinsic variants add one additional operand over raw.
6778 const bool HasVIndex = MI.getNumOperands() == NumVIndexOps;
6779 Register VIndex;
6780 int OpOffset = 0;
6781 if (HasVIndex) {
6782 VIndex = MI.getOperand(3).getReg();
6783 OpOffset = 1;
6784 } else {
6785 VIndex = B.buildConstant(I32, 0).getReg(0);
6786 }
6787
6788 Register VOffset = MI.getOperand(3 + OpOffset).getReg();
6789 Register SOffset = MI.getOperand(4 + OpOffset).getReg();
6790
6791 unsigned Format = 0;
6792 if (IsTyped) {
6793 Format = MI.getOperand(5 + OpOffset).getImm();
6794 ++OpOffset;
6795 }
6796
6797 unsigned AuxiliaryData = MI.getOperand(5 + OpOffset).getImm();
6798
6799 std::tie(VOffset, ImmOffset) = splitBufferOffsets(B, VOffset);
6800
6801 unsigned Opc;
6802 if (IsTyped) {
6803 Opc = IsD16 ? AMDGPU::G_AMDGPU_TBUFFER_STORE_FORMAT_D16 :
6804 AMDGPU::G_AMDGPU_TBUFFER_STORE_FORMAT;
6805 } else if (IsFormat) {
6806 Opc = IsD16 ? AMDGPU::G_AMDGPU_BUFFER_STORE_FORMAT_D16 :
6807 AMDGPU::G_AMDGPU_BUFFER_STORE_FORMAT;
6808 } else {
6809 switch (MemSize) {
6810 case 1:
6811 Opc = AMDGPU::G_AMDGPU_BUFFER_STORE_BYTE;
6812 break;
6813 case 2:
6814 Opc = AMDGPU::G_AMDGPU_BUFFER_STORE_SHORT;
6815 break;
6816 default:
6817 Opc = AMDGPU::G_AMDGPU_BUFFER_STORE;
6818 break;
6819 }
6820 }
6821
6822 auto MIB = B.buildInstr(Opc)
6823 .addUse(VData) // vdata
6824 .addUse(RSrc) // rsrc
6825 .addUse(VIndex) // vindex
6826 .addUse(VOffset) // voffset
6827 .addUse(SOffset) // soffset
6828 .addImm(ImmOffset); // offset(imm)
6829
6830 if (IsTyped)
6831 MIB.addImm(Format);
6832
6833 MIB.addImm(AuxiliaryData) // cachepolicy, swizzled buffer(imm)
6834 .addImm(HasVIndex ? -1 : 0) // idxen(imm)
6835 .addMemOperand(MMO);
6836
6837 MI.eraseFromParent();
6838 return true;
6839}
6840
6841static void buildBufferLoad(unsigned Opc, Register LoadDstReg, Register RSrc,
6842 Register VIndex, Register VOffset, Register SOffset,
6843 unsigned ImmOffset, unsigned Format,
6844 unsigned AuxiliaryData, MachineMemOperand *MMO,
6845 bool IsTyped, bool HasVIndex, MachineIRBuilder &B) {
6846 auto MIB = B.buildInstr(Opc)
6847 .addDef(LoadDstReg) // vdata
6848 .addUse(RSrc) // rsrc
6849 .addUse(VIndex) // vindex
6850 .addUse(VOffset) // voffset
6851 .addUse(SOffset) // soffset
6852 .addImm(ImmOffset); // offset(imm)
6853
6854 if (IsTyped)
6855 MIB.addImm(Format);
6856
6857 MIB.addImm(AuxiliaryData) // cachepolicy, swizzled buffer(imm)
6858 .addImm(HasVIndex ? -1 : 0) // idxen(imm)
6859 .addMemOperand(MMO);
6860}
6861
6862static void buildTFEBufferLoad(unsigned Opc, ArrayRef<Register> ValueDsts,
6863 Register StatusDst, Register RSrc,
6864 Register VIndex, Register VOffset,
6865 Register SOffset, unsigned ImmOffset,
6866 unsigned Format, unsigned AuxiliaryData,
6867 MachineMemOperand *MMO, bool IsTyped,
6868 bool HasVIndex, MachineIRBuilder &B) {
6869 LLT LoadTy = LLT::fixed_vector(ValueDsts.size() + 1, LLT::integer(32));
6870 Register LoadDstReg = B.getMRI()->createGenericVirtualRegister(LoadTy);
6871 buildBufferLoad(Opc, LoadDstReg, RSrc, VIndex, VOffset, SOffset, ImmOffset,
6872 Format, AuxiliaryData, MMO, IsTyped, HasVIndex, B);
6873 SmallVector<Register, 5> Unmerge(ValueDsts);
6874 Unmerge.push_back(StatusDst);
6875 B.buildUnmerge(Unmerge, LoadDstReg);
6876}
6877
6879 LegalizerHelper &Helper,
6880 bool IsFormat,
6881 bool IsTyped) const {
6882 MachineIRBuilder &B = Helper.MIRBuilder;
6883 MachineRegisterInfo &MRI = *B.getMRI();
6884 GISelChangeObserver &Observer = Helper.Observer;
6885
6886 // FIXME: Verifier should enforce 1 MMO for these intrinsics.
6887 MachineMemOperand *MMO = *MI.memoperands_begin();
6888 const LLT MemTy = MMO->getMemoryType();
6889 const LLT I32 = LLT::integer(32);
6890
6891 Register Dst = MI.getOperand(0).getReg();
6892
6893 Register StatusDst;
6894 int OpOffset = 0;
6895 assert(MI.getNumExplicitDefs() == 1 || MI.getNumExplicitDefs() == 2);
6896 bool IsTFE = MI.getNumExplicitDefs() == 2;
6897 if (IsTFE) {
6898 StatusDst = MI.getOperand(1).getReg();
6899 ++OpOffset;
6900 }
6901
6902 castBufferRsrcArgToV4I32(MI, B, 2 + OpOffset);
6903 Register RSrc = MI.getOperand(2 + OpOffset).getReg();
6904
6905 // The typed intrinsics add an immediate after the registers.
6906 const unsigned NumVIndexOps = IsTyped ? 8 : 7;
6907
6908 // The struct intrinsic variants add one additional operand over raw.
6909 const bool HasVIndex = MI.getNumOperands() == NumVIndexOps + OpOffset;
6910 Register VIndex;
6911 if (HasVIndex) {
6912 VIndex = MI.getOperand(3 + OpOffset).getReg();
6913 ++OpOffset;
6914 } else {
6915 VIndex = B.buildConstant(I32, 0).getReg(0);
6916 }
6917
6918 Register VOffset = MI.getOperand(3 + OpOffset).getReg();
6919 Register SOffset = MI.getOperand(4 + OpOffset).getReg();
6920
6921 unsigned Format = 0;
6922 if (IsTyped) {
6923 Format = MI.getOperand(5 + OpOffset).getImm();
6924 ++OpOffset;
6925 }
6926
6927 unsigned AuxiliaryData = MI.getOperand(5 + OpOffset).getImm();
6928 unsigned ImmOffset;
6929
6930 LLT Ty = MRI.getType(Dst);
6931 // Make addrspace 8 pointers loads into 4xi32 loads here, so the rest of the
6932 // logic doesn't have to handle that case.
6933 if (hasBufferRsrcWorkaround(Ty)) {
6934 Observer.changingInstr(MI);
6935 Ty = castBufferRsrcFromV4I32(MI, B, MRI, 0);
6936 Observer.changedInstr(MI);
6937 Dst = MI.getOperand(0).getReg();
6938 B.setInsertPt(B.getMBB(), MI);
6939 }
6940 if (shouldBitcastLoadStoreType(ST, Ty, MemTy)) {
6941 Ty = getBitcastRegisterType(Ty);
6942 Observer.changingInstr(MI);
6943 Helper.bitcastDst(MI, Ty, 0);
6944 Observer.changedInstr(MI);
6945 Dst = MI.getOperand(0).getReg();
6946 B.setInsertPt(B.getMBB(), MI);
6947 }
6948
6949 LLT EltTy = Ty.getScalarType();
6950 const bool IsD16 = IsFormat && (EltTy.getSizeInBits() == 16);
6951 const bool Unpacked = ST.hasUnpackedD16VMem();
6952
6953 if (IsFormat && !IsTyped && !IsD16 && MemTy.getSizeInBits() < 32) {
6954 const Function &Fn = B.getMF().getFunction();
6956 Fn, "unsupported sub-dword format buffer load", MI.getDebugLoc()));
6957 B.buildUndef(Dst);
6958 if (IsTFE)
6959 B.buildUndef(StatusDst);
6960 MI.eraseFromParent();
6961 return true;
6962 }
6963
6964 if (!IsTyped && IsD16 && IsTFE && !ST.hasBufferTFEFormatD16()) {
6965 const Function &Fn = B.getMF().getFunction();
6967 Fn, "TFE D16 format buffer load is not supported on this GPU",
6968 MI.getDebugLoc()));
6969 B.buildUndef(Dst);
6970 B.buildUndef(StatusDst);
6971 MI.eraseFromParent();
6972 return true;
6973 }
6974
6975 std::tie(VOffset, ImmOffset) = splitBufferOffsets(B, VOffset);
6976
6977 unsigned Opc;
6978
6979 // TODO: Support TFE for typed and narrow loads.
6980 if (IsTyped) {
6981 if (IsTFE)
6982 return false;
6983 Opc = IsD16 ? AMDGPU::G_AMDGPU_TBUFFER_LOAD_FORMAT_D16 :
6984 AMDGPU::G_AMDGPU_TBUFFER_LOAD_FORMAT;
6985 } else if (IsFormat) {
6986 if (IsD16) {
6987 Opc = IsTFE ? AMDGPU::G_AMDGPU_BUFFER_LOAD_FORMAT_D16_TFE
6988 : AMDGPU::G_AMDGPU_BUFFER_LOAD_FORMAT_D16;
6989 } else {
6990 Opc = IsTFE ? AMDGPU::G_AMDGPU_BUFFER_LOAD_FORMAT_TFE
6991 : AMDGPU::G_AMDGPU_BUFFER_LOAD_FORMAT;
6992 }
6993 } else {
6994 switch (MemTy.getSizeInBits()) {
6995 case 8:
6996 Opc = IsTFE ? AMDGPU::G_AMDGPU_BUFFER_LOAD_UBYTE_TFE
6997 : AMDGPU::G_AMDGPU_BUFFER_LOAD_UBYTE;
6998 break;
6999 case 16:
7000 Opc = IsTFE ? AMDGPU::G_AMDGPU_BUFFER_LOAD_USHORT_TFE
7001 : AMDGPU::G_AMDGPU_BUFFER_LOAD_USHORT;
7002 break;
7003 default:
7004 Opc = IsTFE ? AMDGPU::G_AMDGPU_BUFFER_LOAD_TFE
7005 : AMDGPU::G_AMDGPU_BUFFER_LOAD;
7006 break;
7007 }
7008 }
7009
7010 if (IsTFE && IsD16 && Ty.isVector()) {
7011 // Value dwords need not cover Ty exactly: v3i16 needs 2 dwords for 48 bits.
7012 const unsigned NumElts = Ty.getNumElements();
7013 const unsigned NumValueDWords = Unpacked ? NumElts : divideCeil(NumElts, 2);
7014
7015 SmallVector<Register, 4> ValueDWords;
7016 for (unsigned I = 0; I != NumValueDWords; ++I)
7017 ValueDWords.push_back(MRI.createGenericVirtualRegister(I32));
7018 buildTFEBufferLoad(Opc, ValueDWords, StatusDst, RSrc, VIndex, VOffset,
7019 SOffset, ImmOffset, Format, AuxiliaryData, MMO, IsTyped,
7020 HasVIndex, B);
7021
7022 if (Unpacked) {
7023 for (Register &R : ValueDWords)
7024 R = B.buildTrunc(EltTy, R).getReg(0);
7025 B.buildMergeLikeInstr(Dst, ValueDWords);
7026 } else {
7027 Register Merged =
7028 NumValueDWords == 1
7029 ? ValueDWords[0]
7030 : B.buildMergeLikeInstr(LLT::fixed_vector(NumValueDWords, I32),
7031 ValueDWords)
7032 .getReg(0);
7033 LLT PackedTy = LLT::fixed_vector(NumValueDWords * 2, EltTy);
7034 if (PackedTy == Ty) {
7035 B.buildBitcast(Dst, Merged);
7036 } else {
7037 Register Packed = B.buildBitcast(PackedTy, Merged).getReg(0);
7038 B.buildDeleteTrailingVectorElements(Dst, Packed);
7039 }
7040 }
7041 } else if (IsTFE) {
7042 const unsigned NumValueDWords = divideCeil(Ty.getSizeInBits(), 32);
7043 Register DstInt =
7044 EltTy.isFloat() ? MRI.createGenericVirtualRegister(Ty.changeElementType(
7045 LLT::integer(EltTy.getSizeInBits())))
7046 : Dst;
7047 if (MemTy.getSizeInBits() < 32) {
7048 Register ExtDst = MRI.createGenericVirtualRegister(I32);
7049 buildTFEBufferLoad(Opc, ExtDst, StatusDst, RSrc, VIndex, VOffset, SOffset,
7050 ImmOffset, Format, AuxiliaryData, MMO, IsTyped,
7051 HasVIndex, B);
7052 B.buildTrunc(DstInt, ExtDst);
7053 } else if (NumValueDWords == 1) {
7054 buildTFEBufferLoad(Opc, DstInt, StatusDst, RSrc, VIndex, VOffset, SOffset,
7055 ImmOffset, Format, AuxiliaryData, MMO, IsTyped,
7056 HasVIndex, B);
7057 } else {
7058 SmallVector<Register, 4> ValueDWords;
7059 for (unsigned I = 0; I != NumValueDWords; ++I)
7060 ValueDWords.push_back(MRI.createGenericVirtualRegister(I32));
7061 buildTFEBufferLoad(Opc, ValueDWords, StatusDst, RSrc, VIndex, VOffset,
7062 SOffset, ImmOffset, Format, AuxiliaryData, MMO,
7063 IsTyped, HasVIndex, B);
7064 B.buildMergeLikeInstr(DstInt, ValueDWords);
7065 }
7066 if (DstInt != Dst)
7067 B.buildBitcast(Dst, DstInt);
7068 } else if ((!IsD16 && MemTy.getSizeInBits() < 32) ||
7069 (IsD16 && !Ty.isVector())) {
7070 Register LoadDstReg = B.getMRI()->createGenericVirtualRegister(I32);
7071 buildBufferLoad(Opc, LoadDstReg, RSrc, VIndex, VOffset, SOffset, ImmOffset,
7072 Format, AuxiliaryData, MMO, IsTyped, HasVIndex, B);
7073 B.setInsertPt(B.getMBB(), ++B.getInsertPt());
7074 B.buildTrunc(Dst, LoadDstReg);
7075 } else if (Unpacked && IsD16 && Ty.isVector()) {
7076 LLT UnpackedTy = LLT::fixed_vector(Ty.getNumElements(), LLT::integer(32));
7077 Register LoadDstReg = B.getMRI()->createGenericVirtualRegister(UnpackedTy);
7078 buildBufferLoad(Opc, LoadDstReg, RSrc, VIndex, VOffset, SOffset, ImmOffset,
7079 Format, AuxiliaryData, MMO, IsTyped, HasVIndex, B);
7080 B.setInsertPt(B.getMBB(), ++B.getInsertPt());
7081 // FIXME: G_TRUNC should work, but legalization currently fails
7082 auto Unmerge = B.buildUnmerge(I32, LoadDstReg);
7084 for (unsigned I = 0, N = Unmerge->getNumOperands() - 1; I != N; ++I)
7085 Repack.push_back(B.buildTrunc(EltTy, Unmerge.getReg(I)).getReg(0));
7086 B.buildMergeLikeInstr(Dst, Repack);
7087 } else {
7088 buildBufferLoad(Opc, Dst, RSrc, VIndex, VOffset, SOffset, ImmOffset, Format,
7089 AuxiliaryData, MMO, IsTyped, HasVIndex, B);
7090 }
7091
7092 MI.eraseFromParent();
7093 return true;
7094}
7095
7096static unsigned getBufferAtomicPseudo(Intrinsic::ID IntrID) {
7097 switch (IntrID) {
7098 case Intrinsic::amdgcn_raw_buffer_atomic_swap:
7099 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_swap:
7100 case Intrinsic::amdgcn_struct_buffer_atomic_swap:
7101 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_swap:
7102 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_SWAP;
7103 case Intrinsic::amdgcn_raw_buffer_atomic_add:
7104 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_add:
7105 case Intrinsic::amdgcn_struct_buffer_atomic_add:
7106 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_add:
7107 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_ADD;
7108 case Intrinsic::amdgcn_raw_buffer_atomic_sub:
7109 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_sub:
7110 case Intrinsic::amdgcn_struct_buffer_atomic_sub:
7111 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_sub:
7112 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_SUB;
7113 case Intrinsic::amdgcn_raw_buffer_atomic_smin:
7114 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_smin:
7115 case Intrinsic::amdgcn_struct_buffer_atomic_smin:
7116 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_smin:
7117 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_SMIN;
7118 case Intrinsic::amdgcn_raw_buffer_atomic_umin:
7119 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_umin:
7120 case Intrinsic::amdgcn_struct_buffer_atomic_umin:
7121 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_umin:
7122 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_UMIN;
7123 case Intrinsic::amdgcn_raw_buffer_atomic_smax:
7124 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_smax:
7125 case Intrinsic::amdgcn_struct_buffer_atomic_smax:
7126 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_smax:
7127 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_SMAX;
7128 case Intrinsic::amdgcn_raw_buffer_atomic_umax:
7129 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_umax:
7130 case Intrinsic::amdgcn_struct_buffer_atomic_umax:
7131 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_umax:
7132 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_UMAX;
7133 case Intrinsic::amdgcn_raw_buffer_atomic_and:
7134 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_and:
7135 case Intrinsic::amdgcn_struct_buffer_atomic_and:
7136 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_and:
7137 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_AND;
7138 case Intrinsic::amdgcn_raw_buffer_atomic_or:
7139 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_or:
7140 case Intrinsic::amdgcn_struct_buffer_atomic_or:
7141 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_or:
7142 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_OR;
7143 case Intrinsic::amdgcn_raw_buffer_atomic_xor:
7144 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_xor:
7145 case Intrinsic::amdgcn_struct_buffer_atomic_xor:
7146 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_xor:
7147 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_XOR;
7148 case Intrinsic::amdgcn_raw_buffer_atomic_inc:
7149 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_inc:
7150 case Intrinsic::amdgcn_struct_buffer_atomic_inc:
7151 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_inc:
7152 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_INC;
7153 case Intrinsic::amdgcn_raw_buffer_atomic_dec:
7154 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_dec:
7155 case Intrinsic::amdgcn_struct_buffer_atomic_dec:
7156 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_dec:
7157 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_DEC;
7158 case Intrinsic::amdgcn_raw_buffer_atomic_cmpswap:
7159 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_cmpswap:
7160 case Intrinsic::amdgcn_struct_buffer_atomic_cmpswap:
7161 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_cmpswap:
7162 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_CMPSWAP;
7163 case Intrinsic::amdgcn_raw_buffer_atomic_fadd:
7164 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_fadd:
7165 case Intrinsic::amdgcn_struct_buffer_atomic_fadd:
7166 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_fadd:
7167 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_FADD;
7168 case Intrinsic::amdgcn_raw_buffer_atomic_fmin:
7169 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_fmin:
7170 case Intrinsic::amdgcn_struct_buffer_atomic_fmin:
7171 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_fmin:
7172 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_FMIN;
7173 case Intrinsic::amdgcn_raw_buffer_atomic_fmax:
7174 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_fmax:
7175 case Intrinsic::amdgcn_struct_buffer_atomic_fmax:
7176 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_fmax:
7177 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_FMAX;
7178 case Intrinsic::amdgcn_raw_buffer_atomic_sub_clamp_u32:
7179 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_sub_clamp_u32:
7180 case Intrinsic::amdgcn_struct_buffer_atomic_sub_clamp_u32:
7181 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_sub_clamp_u32:
7182 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_SUB_CLAMP_U32;
7183 case Intrinsic::amdgcn_raw_buffer_atomic_cond_sub_u32:
7184 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_cond_sub_u32:
7185 case Intrinsic::amdgcn_struct_buffer_atomic_cond_sub_u32:
7186 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_cond_sub_u32:
7187 return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_COND_SUB_U32;
7188 default:
7189 llvm_unreachable("unhandled atomic opcode");
7190 }
7191}
7192
7195 Intrinsic::ID IID) const {
7196 const bool IsCmpSwap =
7197 IID == Intrinsic::amdgcn_raw_buffer_atomic_cmpswap ||
7198 IID == Intrinsic::amdgcn_struct_buffer_atomic_cmpswap ||
7199 IID == Intrinsic::amdgcn_raw_ptr_buffer_atomic_cmpswap ||
7200 IID == Intrinsic::amdgcn_struct_ptr_buffer_atomic_cmpswap;
7201
7202 Register Dst = MI.getOperand(0).getReg();
7203 // Since we don't have 128-bit atomics, we don't need to handle the case of
7204 // p8 argmunents to the atomic itself
7205 Register VData = MI.getOperand(2).getReg();
7206
7207 Register CmpVal;
7208 int OpOffset = 0;
7209
7210 if (IsCmpSwap) {
7211 CmpVal = MI.getOperand(3).getReg();
7212 ++OpOffset;
7213 }
7214
7215 castBufferRsrcArgToV4I32(MI, B, 3 + OpOffset);
7216 Register RSrc = MI.getOperand(3 + OpOffset).getReg();
7217 const unsigned NumVIndexOps = IsCmpSwap ? 9 : 8;
7218
7219 // The struct intrinsic variants add one additional operand over raw.
7220 const bool HasVIndex = MI.getNumOperands() == NumVIndexOps;
7221 Register VIndex;
7222 if (HasVIndex) {
7223 VIndex = MI.getOperand(4 + OpOffset).getReg();
7224 ++OpOffset;
7225 } else {
7226 VIndex = B.buildConstant(LLT::integer(32), 0).getReg(0);
7227 }
7228
7229 Register VOffset = MI.getOperand(4 + OpOffset).getReg();
7230 Register SOffset = MI.getOperand(5 + OpOffset).getReg();
7231 unsigned AuxiliaryData = MI.getOperand(6 + OpOffset).getImm();
7232
7233 MachineMemOperand *MMO = *MI.memoperands_begin();
7234
7235 unsigned ImmOffset;
7236 std::tie(VOffset, ImmOffset) = splitBufferOffsets(B, VOffset);
7237
7238 auto MIB = B.buildInstr(getBufferAtomicPseudo(IID))
7239 .addDef(Dst)
7240 .addUse(VData); // vdata
7241
7242 if (IsCmpSwap)
7243 MIB.addReg(CmpVal);
7244
7245 MIB.addUse(RSrc) // rsrc
7246 .addUse(VIndex) // vindex
7247 .addUse(VOffset) // voffset
7248 .addUse(SOffset) // soffset
7249 .addImm(ImmOffset) // offset(imm)
7250 .addImm(AuxiliaryData) // cachepolicy, swizzled buffer(imm)
7251 .addImm(HasVIndex ? -1 : 0) // idxen(imm)
7252 .addMemOperand(MMO);
7253
7254 MI.eraseFromParent();
7255 return true;
7256}
7257
7258/// Turn a set of f16 typed registers in \p AddrRegs into a dword sized
7259/// vector with f16 typed elements.
7261 SmallVectorImpl<Register> &PackedAddrs,
7262 unsigned ArgOffset,
7264 bool IsA16, bool IsG16) {
7265 auto EndIdx = Intr->VAddrEnd;
7266
7267 for (unsigned I = Intr->VAddrStart; I < EndIdx; I++) {
7268 MachineOperand &SrcOp = MI.getOperand(ArgOffset + I);
7269 if (!SrcOp.isReg())
7270 continue; // _L to _LZ may have eliminated this.
7271
7272 Register AddrReg = SrcOp.getReg();
7273
7274 if ((I < Intr->GradientStart) ||
7275 (I >= Intr->GradientStart && I < Intr->CoordStart && !IsG16) ||
7276 (I >= Intr->CoordStart && !IsA16)) {
7277 if ((I < Intr->GradientStart) && IsA16 &&
7278 (B.getMRI()->getType(AddrReg) == F16)) {
7279 assert(I == Intr->BiasIndex && "Got unexpected 16-bit extra argument");
7280 // Special handling of bias when A16 is on. Bias is of type half but
7281 // occupies full 32-bit.
7282 PackedAddrs.push_back(
7283 B.buildBuildVector(V2F16, {AddrReg, B.buildUndef(F16).getReg(0)})
7284 .getReg(0));
7285 } else {
7286 assert((!IsA16 || Intr->NumBiasArgs == 0 || I != Intr->BiasIndex) &&
7287 "Bias needs to be converted to 16 bit in A16 mode");
7288 // Handle any gradient or coordinate operands that should not be packed
7289 AddrReg = B.buildBitcast(V2F16, AddrReg).getReg(0);
7290 PackedAddrs.push_back(AddrReg);
7291 }
7292 } else {
7293 const LLT EltTy = B.getMRI()->getType(AddrReg);
7294 const LLT V2EltTy = LLT::fixed_vector(2, EltTy);
7295 // Dz/dh, dz/dv and the last odd coord are packed with undef. Also, in 1D,
7296 // derivatives dx/dh and dx/dv are packed with undef.
7297 if (((I + 1) >= EndIdx) ||
7298 ((Intr->NumGradients / 2) % 2 == 1 &&
7299 (I == static_cast<unsigned>(Intr->GradientStart +
7300 (Intr->NumGradients / 2) - 1) ||
7301 I == static_cast<unsigned>(Intr->GradientStart +
7302 Intr->NumGradients - 1))) ||
7303 // Check for _L to _LZ optimization
7304 !MI.getOperand(ArgOffset + I + 1).isReg()) {
7305 PackedAddrs.push_back(
7306 B.buildBuildVector(V2EltTy,
7307 {AddrReg, B.buildUndef(EltTy).getReg(0)})
7308 .getReg(0));
7309 } else {
7310 PackedAddrs.push_back(
7311 B.buildBuildVector(
7312 V2EltTy, {AddrReg, MI.getOperand(ArgOffset + I + 1).getReg()})
7313 .getReg(0));
7314 ++I;
7315 }
7316 }
7317 }
7318}
7319
7320/// Convert from separate vaddr components to a single vector address register,
7321/// and replace the remaining operands with $noreg.
7323 int DimIdx, int NumVAddrs) {
7324 SmallVector<Register, 8> AddrRegs;
7325 for (int I = 0; I != NumVAddrs; ++I) {
7326 MachineOperand &SrcOp = MI.getOperand(DimIdx + I);
7327 if (SrcOp.isReg()) {
7329 LLT I32 = LLT::integer(32);
7330 assert(B.getMRI()->getType(Reg).getSizeInBits() == 32);
7331 if (B.getMRI()->getType(Reg) != I32)
7332 Reg = B.buildBitcast(I32, Reg).getReg(0);
7333 AddrRegs.push_back(Reg);
7334 }
7335 }
7336
7337 int NumAddrRegs = AddrRegs.size();
7338 if (NumAddrRegs != 1) {
7339 LLT EltTy = B.getMRI()->getType(AddrRegs[0]);
7340 auto VAddr =
7341 B.buildBuildVector(LLT::fixed_vector(NumAddrRegs, EltTy), AddrRegs);
7342 MI.getOperand(DimIdx).setReg(VAddr.getReg(0));
7343 }
7344
7345 for (int I = 1; I != NumVAddrs; ++I) {
7346 MachineOperand &SrcOp = MI.getOperand(DimIdx + I);
7347 if (SrcOp.isReg())
7348 MI.getOperand(DimIdx + I).setReg(AMDGPU::NoRegister);
7349 }
7350}
7351
7352/// Rewrite image intrinsics to use register layouts expected by the subtarget.
7353///
7354/// Depending on the subtarget, load/store with 16-bit element data need to be
7355/// rewritten to use the low half of 32-bit registers, or directly use a packed
7356/// layout. 16-bit addresses should also sometimes be packed into 32-bit
7357/// registers.
7358///
7359/// We don't want to directly select image instructions just yet, but also want
7360/// to exposes all register repacking to the legalizer/combiners. We also don't
7361/// want a selected instruction entering RegBankSelect. In order to avoid
7362/// defining a multitude of intermediate image instructions, directly hack on
7363/// the intrinsic's arguments. In cases like a16 addresses, this requires
7364/// padding now unnecessary arguments with $noreg.
7367 const AMDGPU::ImageDimIntrinsicInfo *Intr) const {
7368
7369 const MachineFunction &MF = *MI.getMF();
7370 const unsigned NumDefs = MI.getNumExplicitDefs();
7371 const unsigned ArgOffset = NumDefs + 1;
7372 bool IsTFE = NumDefs == 2;
7373 // We are only processing the operands of d16 image operations on subtargets
7374 // that use the unpacked register layout, or need to repack the TFE result.
7375
7376 // TODO: Do we need to guard against already legalized intrinsics?
7377 const AMDGPU::MIMGBaseOpcodeInfo *BaseOpcode =
7379
7380 MachineRegisterInfo *MRI = B.getMRI();
7381 const LLT I32 = LLT::integer(32);
7382 const LLT I16 = LLT::integer(16);
7383 const LLT V2I16 = LLT::fixed_vector(2, I16);
7384
7385 unsigned DMask = 0;
7386 Register VData;
7387 LLT Ty;
7388
7389 if (!BaseOpcode->NoReturn || BaseOpcode->Store) {
7390 VData = MI.getOperand(NumDefs == 0 ? 1 : 0).getReg();
7391 Ty = MRI->getType(VData);
7392 }
7393
7394 const bool IsAtomicPacked16Bit =
7395 (BaseOpcode->BaseOpcode == AMDGPU::IMAGE_ATOMIC_PK_ADD_F16 ||
7396 BaseOpcode->BaseOpcode == AMDGPU::IMAGE_ATOMIC_PK_ADD_BF16);
7397
7398 // Check for 16 bit addresses and pack if true.
7399 LLT GradTy =
7400 MRI->getType(MI.getOperand(ArgOffset + Intr->GradientStart).getReg());
7401 LLT AddrTy =
7402 MRI->getType(MI.getOperand(ArgOffset + Intr->CoordStart).getReg());
7403 const bool GradTyIs16 = GradTy == I16 || GradTy == F16;
7404 const bool AddrTyIs16 = AddrTy == I16 || AddrTy == F16;
7405 const bool DataTyIs16 =
7406 Ty.getScalarType() == I16 || Ty.getScalarType() == F16;
7407 const bool IsG16 =
7408 ST.hasG16() ? (BaseOpcode->Gradients && GradTyIs16) : GradTyIs16;
7409 const bool IsA16 = AddrTyIs16;
7410 const bool IsD16 = !IsAtomicPacked16Bit && DataTyIs16;
7411
7412 int DMaskLanes = 0;
7413 if (!BaseOpcode->Atomic) {
7414 DMask = MI.getOperand(ArgOffset + Intr->DMaskIndex).getImm();
7415 if (BaseOpcode->Gather4) {
7416 DMaskLanes = 4;
7417 } else if (DMask != 0) {
7418 DMaskLanes = llvm::popcount(DMask);
7419 } else if (!IsTFE && !BaseOpcode->Store) {
7420 // If dmask is 0, this is a no-op load. This can be eliminated.
7421 B.buildUndef(MI.getOperand(0));
7422 MI.eraseFromParent();
7423 return true;
7424 }
7425 }
7426
7427 Observer.changingInstr(MI);
7428 scope_exit ChangedInstr([&] { Observer.changedInstr(MI); });
7429
7430 const unsigned StoreOpcode = IsD16 ? AMDGPU::G_AMDGPU_INTRIN_IMAGE_STORE_D16
7431 : AMDGPU::G_AMDGPU_INTRIN_IMAGE_STORE;
7432 const unsigned LoadOpcode = IsD16 ? AMDGPU::G_AMDGPU_INTRIN_IMAGE_LOAD_D16
7433 : AMDGPU::G_AMDGPU_INTRIN_IMAGE_LOAD;
7434 unsigned NewOpcode = LoadOpcode;
7435 if (BaseOpcode->Store)
7436 NewOpcode = StoreOpcode;
7437 else if (BaseOpcode->NoReturn)
7438 NewOpcode = AMDGPU::G_AMDGPU_INTRIN_IMAGE_LOAD_NORET;
7439
7440 // Track that we legalized this
7441 MI.setDesc(B.getTII().get(NewOpcode));
7442
7443 // Expecting to get an error flag since TFC is on - and dmask is 0 Force
7444 // dmask to be at least 1 otherwise the instruction will fail
7445 if (IsTFE && DMask == 0) {
7446 DMask = 0x1;
7447 DMaskLanes = 1;
7448 MI.getOperand(ArgOffset + Intr->DMaskIndex).setImm(DMask);
7449 }
7450
7451 if (BaseOpcode->Atomic) {
7452 Register VData0 = MI.getOperand(2).getReg();
7453 LLT Ty = MRI->getType(VData0);
7454
7455 // TODO: Allow atomic swap and bit ops for v2f16/v4f16
7456 if (Ty.isVector() && !IsAtomicPacked16Bit)
7457 return false;
7458
7459 if (BaseOpcode->AtomicX2) {
7460 Register VData1 = MI.getOperand(3).getReg();
7461 // The two values are packed in one register.
7462 LLT PackedTy = LLT::fixed_vector(2, Ty);
7463 auto Concat = B.buildBuildVector(PackedTy, {VData0, VData1});
7464 MI.getOperand(2).setReg(Concat.getReg(0));
7465 MI.getOperand(3).setReg(AMDGPU::NoRegister);
7466 }
7467 }
7468
7469 unsigned CorrectedNumVAddrs = Intr->NumVAddrs;
7470
7471 // Rewrite the addressing register layout before doing anything else.
7472 if (BaseOpcode->Gradients && !ST.hasG16() && (IsA16 != IsG16)) {
7473 // 16 bit gradients are supported, but are tied to the A16 control
7474 // so both gradients and addresses must be 16 bit
7475 return false;
7476 }
7477
7478 if (IsA16 && !ST.hasA16()) {
7479 // A16 not supported
7480 return false;
7481 }
7482
7483 const unsigned NSAMaxSize = ST.getNSAMaxSize(BaseOpcode->Sampler);
7484 const unsigned HasPartialNSA = ST.hasPartialNSAEncoding();
7485
7486 if (IsA16 || IsG16) {
7487 // Even if NumVAddrs == 1 we should pack it into a 32-bit value, because the
7488 // instructions expect VGPR_32
7489 SmallVector<Register, 4> PackedRegs;
7490
7491 packImage16bitOpsToDwords(B, MI, PackedRegs, ArgOffset, Intr, IsA16, IsG16);
7492
7493 // See also below in the non-a16 branch
7494 const bool UseNSA = ST.hasNSAEncoding() &&
7495 PackedRegs.size() >= ST.getNSAThreshold(MF) &&
7496 (PackedRegs.size() <= NSAMaxSize || HasPartialNSA);
7497 const bool UsePartialNSA =
7498 UseNSA && HasPartialNSA && PackedRegs.size() > NSAMaxSize;
7499
7500 if (UsePartialNSA) {
7501 // Pack registers that would go over NSAMaxSize into last VAddr register
7502 LLT PackedAddrTy =
7503 LLT::fixed_vector(2 * (PackedRegs.size() - NSAMaxSize + 1), F16);
7504 auto Concat = B.buildConcatVectors(
7505 PackedAddrTy, ArrayRef(PackedRegs).slice(NSAMaxSize - 1));
7506 PackedRegs[NSAMaxSize - 1] = Concat.getReg(0);
7507 PackedRegs.resize(NSAMaxSize);
7508 } else if (!UseNSA && PackedRegs.size() > 1) {
7509 LLT PackedAddrTy = LLT::fixed_vector(2 * PackedRegs.size(), F16);
7510 auto Concat = B.buildConcatVectors(PackedAddrTy, PackedRegs);
7511 PackedRegs[0] = Concat.getReg(0);
7512 PackedRegs.resize(1);
7513 }
7514
7515 const unsigned NumPacked = PackedRegs.size();
7516 for (unsigned I = Intr->VAddrStart; I < Intr->VAddrEnd; I++) {
7517 MachineOperand &SrcOp = MI.getOperand(ArgOffset + I);
7518 if (!SrcOp.isReg()) {
7519 assert(SrcOp.isImm() && SrcOp.getImm() == 0);
7520 continue;
7521 }
7522
7523 assert(SrcOp.getReg() != AMDGPU::NoRegister);
7524
7525 if (I - Intr->VAddrStart < NumPacked)
7526 SrcOp.setReg(PackedRegs[I - Intr->VAddrStart]);
7527 else
7528 SrcOp.setReg(AMDGPU::NoRegister);
7529 }
7530 } else {
7531 // If the register allocator cannot place the address registers contiguously
7532 // without introducing moves, then using the non-sequential address encoding
7533 // is always preferable, since it saves VALU instructions and is usually a
7534 // wash in terms of code size or even better.
7535 //
7536 // However, we currently have no way of hinting to the register allocator
7537 // that MIMG addresses should be placed contiguously when it is possible to
7538 // do so, so force non-NSA for the common 2-address case as a heuristic.
7539 //
7540 // SIShrinkInstructions will convert NSA encodings to non-NSA after register
7541 // allocation when possible.
7542 //
7543 // Partial NSA is allowed on GFX11+ where the final register is a contiguous
7544 // set of the remaining addresses.
7545 const bool UseNSA = ST.hasNSAEncoding() &&
7546 CorrectedNumVAddrs >= ST.getNSAThreshold(MF) &&
7547 (CorrectedNumVAddrs <= NSAMaxSize || HasPartialNSA);
7548 const bool UsePartialNSA =
7549 UseNSA && HasPartialNSA && CorrectedNumVAddrs > NSAMaxSize;
7550
7551 if (UsePartialNSA) {
7553 ArgOffset + Intr->VAddrStart + NSAMaxSize - 1,
7554 Intr->NumVAddrs - NSAMaxSize + 1);
7555 } else if (!UseNSA && Intr->NumVAddrs > 1) {
7556 convertImageAddrToPacked(B, MI, ArgOffset + Intr->VAddrStart,
7557 Intr->NumVAddrs);
7558 }
7559 }
7560
7561 int Flags = 0;
7562 if (IsA16)
7563 Flags |= 1;
7564 if (IsG16)
7565 Flags |= 2;
7566 MI.addOperand(MachineOperand::CreateImm(Flags));
7567
7568 if (BaseOpcode->NoReturn) { // No TFE for stores?
7569 // TODO: Handle dmask trim
7570 if (!Ty.isVector() || !IsD16)
7571 return true;
7572
7573 Register RepackedReg = handleD16VData(B, *MRI, VData, true);
7574 if (RepackedReg != VData) {
7575 MI.getOperand(1).setReg(RepackedReg);
7576 }
7577
7578 return true;
7579 }
7580
7581 Register DstReg = MI.getOperand(0).getReg();
7582 const LLT EltTy = Ty.getScalarType();
7583 const int NumElts = Ty.isVector() ? Ty.getNumElements() : 1;
7584
7585 // Confirm that the return type is large enough for the dmask specified
7586 if (NumElts < DMaskLanes)
7587 return false;
7588
7589 if (NumElts > 4 || DMaskLanes > 4)
7590 return false;
7591
7592 // Image atomic instructions are using DMask to specify how many bits
7593 // input/output data will have. 32-bits (i32, f32, v2f16) or 64-bits (i64,
7594 // f64, v4f16).
7595 // DMaskLanes for image atomic has default value '0'.
7596 // We must be sure that atomic variants (especially packed) will not be
7597 // truncated from v2f16 or v4f16 to f16 type.
7598 //
7599 // ChangeElementCount will be needed for image load where Ty is always scalar.
7600 const unsigned AdjustedNumElts = DMaskLanes == 0 ? 1 : DMaskLanes;
7601 const LLT AdjustedTy =
7602 DMaskLanes == 0
7603 ? Ty
7604 : Ty.changeElementCount(ElementCount::getFixed(AdjustedNumElts));
7605
7606 // The raw dword aligned data component of the load. The only legal cases
7607 // where this matters should be when using the packed D16 format, for
7608 // f16 -> <2 x f16>, and <3 x f16> -> <4 x f16>,
7609 LLT RoundedTy;
7610
7611 // I32 vector to cover all data, plus TFE result element.
7612 LLT TFETy;
7613
7614 // Register type to use for each loaded component. Will be I32 or V2I16.
7615 LLT RegTy;
7616
7617 if (IsD16 && ST.hasUnpackedD16VMem()) {
7618 RoundedTy =
7619 LLT::scalarOrVector(ElementCount::getFixed(AdjustedNumElts), I32);
7620 TFETy = LLT::fixed_vector(AdjustedNumElts + 1, I32);
7621 RegTy = I32;
7622 } else {
7623 unsigned EltSize = EltTy.getSizeInBits();
7624 unsigned RoundedElts = (AdjustedTy.getSizeInBits() + 31) / 32;
7625 unsigned RoundedSize = 32 * RoundedElts;
7626 RoundedTy = LLT::scalarOrVector(
7627 ElementCount::getFixed(RoundedSize / EltSize), EltTy);
7628 TFETy = LLT::fixed_vector(RoundedSize / 32 + 1, I32);
7629 RegTy = !IsTFE && EltSize == 16 ? V2I16 : I32;
7630 }
7631
7632 // The return type does not need adjustment.
7633 // TODO: Should we change f16 case to i32 or <2 x f16>?
7634 if (!IsTFE && (RoundedTy == Ty || !Ty.isVector()))
7635 return true;
7636
7637 Register Dst1Reg;
7638
7639 // Insert after the instruction.
7640 B.setInsertPt(*MI.getParent(), ++MI.getIterator());
7641
7642 // TODO: For TFE with d16, if we used a TFE type that was a multiple of <2 x
7643 // f16> instead of i32, we would only need 1 bitcast instead of multiple.
7644 const LLT LoadResultTy = IsTFE ? TFETy : RoundedTy;
7645 const int ResultNumRegs = LoadResultTy.getSizeInBits() / 32;
7646
7647 Register NewResultReg = MRI->createGenericVirtualRegister(LoadResultTy);
7648
7649 MI.getOperand(0).setReg(NewResultReg);
7650
7651 // In the IR, TFE is supposed to be used with a 2 element struct return
7652 // type. The instruction really returns these two values in one contiguous
7653 // register, with one additional dword beyond the loaded data. Rewrite the
7654 // return type to use a single register result.
7655
7656 if (IsTFE) {
7657 Dst1Reg = MI.getOperand(1).getReg();
7658 if (MRI->getType(Dst1Reg) != I32)
7659 return false;
7660
7661 // TODO: Make sure the TFE operand bit is set.
7662 MI.removeOperand(1);
7663
7664 // Handle the easy case that requires no repack instructions.
7665 if (!Ty.isVector() && Ty.getSizeInBits() == 32) {
7666 auto Unmerge = B.buildUnmerge({I32, I32}, NewResultReg);
7667 B.buildBitcast(DstReg, Unmerge.getReg(0));
7668 B.buildCopy(Dst1Reg, Unmerge.getReg(1));
7669 return true;
7670 }
7671 }
7672
7673 // Now figure out how to copy the new result register back into the old
7674 // result.
7675 SmallVector<Register, 5> ResultRegs(ResultNumRegs, Dst1Reg);
7676
7677 const int NumDataRegs = IsTFE ? ResultNumRegs - 1 : ResultNumRegs;
7678
7679 if (ResultNumRegs == 1) {
7680 assert(!IsTFE);
7681 ResultRegs[0] = NewResultReg;
7682 } else {
7683 // We have to repack into a new vector of some kind.
7684 for (int I = 0; I != NumDataRegs; ++I)
7685 ResultRegs[I] = MRI->createGenericVirtualRegister(RegTy);
7686 B.buildUnmerge(ResultRegs, NewResultReg);
7687
7688 // Drop the final TFE element to get the data part. The TFE result is
7689 // directly written to the right place already.
7690 if (IsTFE)
7691 ResultRegs.resize(NumDataRegs);
7692 }
7693
7694 // For an f16 scalar result, we form an i32 result with a truncate regardless
7695 // of packed vs. unpacked.
7696 if (IsD16 && !Ty.isVector()) {
7697 B.buildTrunc(DstReg, ResultRegs[0]);
7698 return true;
7699 }
7700
7701 // Avoid a build/concat_vector of 1 entry.
7702 if ((Ty == V2I16 || Ty == V2F16) && NumDataRegs == 1 &&
7703 !ST.hasUnpackedD16VMem()) {
7704 B.buildBitcast(DstReg, ResultRegs[0]);
7705 return true;
7706 }
7707
7708 assert(Ty.isVector());
7709
7710 if (IsD16) {
7711 // For packed D16 results with TFE enabled, all the data components are
7712 // I32. Cast back to the expected type.
7713 //
7714 // TODO: We don't really need to use load i32 elements. We would only need
7715 // one cast for the TFE result if a multiple of v2f16 was used.
7716 if (RegTy != V2I16 && !ST.hasUnpackedD16VMem()) {
7717 for (Register &Reg : ResultRegs)
7718 Reg = B.buildBitcast(V2I16, Reg).getReg(0);
7719 } else if (ST.hasUnpackedD16VMem()) {
7720 for (Register &Reg : ResultRegs)
7721 Reg = B.buildTrunc(I16, Reg).getReg(0);
7722 }
7723 }
7724
7725 auto padWithUndef = [&](LLT Ty, int NumElts) {
7726 if (NumElts == 0)
7727 return;
7728 Register Undef = B.buildUndef(Ty).getReg(0);
7729 for (int I = 0; I != NumElts; ++I)
7730 ResultRegs.push_back(Undef);
7731 };
7732
7733 // Pad out any elements eliminated due to the dmask.
7734 LLT ResTy = MRI->getType(ResultRegs[0]);
7735 if (!ResTy.isVector()) {
7736 padWithUndef(ResTy, NumElts - ResultRegs.size());
7737 B.buildBuildVector(DstReg, ResultRegs);
7738 return true;
7739 }
7740
7741 assert(!ST.hasUnpackedD16VMem() && (ResTy == V2I16 || ResTy == V2F16));
7742 const int RegsToCover = (Ty.getSizeInBits() + 31) / 32;
7743
7744 // Deal with the one annoying legal case.
7745 const LLT V3I16 = LLT::fixed_vector(3, I16);
7746 const LLT V3F16 = LLT::fixed_vector(3, F16);
7747 if (Ty == V3I16 || Ty == V3F16) {
7748 if (IsTFE) {
7749 if (ResultRegs.size() == 1) {
7750 NewResultReg = ResultRegs[0];
7751 } else if (ResultRegs.size() == 2) {
7752 LLT V4I16 = LLT::fixed_vector(4, I16);
7753 NewResultReg = B.buildConcatVectors(V4I16, ResultRegs).getReg(0);
7754 } else {
7755 return false;
7756 }
7757 }
7758
7759 LLT DstTy = MRI->getType(DstReg);
7760 LLT NewResTy = MRI->getType(NewResultReg);
7761 LLT ResEltTy = NewResTy.getElementType();
7762 Register ResizeDst = DstTy.getElementType() == ResEltTy
7763 ? DstReg
7765 DstTy.changeElementType(ResEltTy));
7766
7767 if (DstTy.getNumElements() < NewResTy.getNumElements()) {
7768 B.buildDeleteTrailingVectorElements(ResizeDst, NewResultReg);
7769 } else {
7770 B.buildPadVectorWithUndefElements(ResizeDst, NewResultReg);
7771 }
7772 if (ResizeDst != DstReg)
7773 B.buildBitcast(DstReg, ResizeDst);
7774 return true;
7775 }
7776
7777 padWithUndef(ResTy, RegsToCover - ResultRegs.size());
7778 B.buildConcatVectors(DstReg, ResultRegs);
7779 return true;
7780}
7781
7783 MachineInstr &MI) const {
7784 MachineIRBuilder &B = Helper.MIRBuilder;
7785 GISelChangeObserver &Observer = Helper.Observer;
7786
7787 Register OrigDst = MI.getOperand(0).getReg();
7788 Register Dst;
7789 LLT Ty = B.getMRI()->getType(OrigDst);
7790 unsigned Size = Ty.getSizeInBits();
7791 MachineFunction &MF = B.getMF();
7792 bool HasMMO = !MI.memoperands_empty();
7793
7794 // S_BUFFER_LOAD only produces values that fill whole SGPRs, apart from the
7795 // subword loads below. Those truncate from an s32 result, so they need a
7796 // scalar destination.
7797 bool IsSubwordLoad = Ty.isScalar() && Size < 32 && ST.hasScalarSubwordLoads();
7798 if (Size % 32 != 0 && !IsSubwordLoad) {
7799 const Function &Fn = MF.getFunction();
7801 Fn, "unsupported s_buffer_load result type", MI.getDebugLoc()));
7802 B.buildUndef(OrigDst);
7803 MI.eraseFromParent();
7804 return true;
7805 }
7806
7807 unsigned Opc = 0;
7808 if (IsSubwordLoad) {
7809 assert(Size == 8 || Size == 16);
7810 Opc = Size == 8 ? AMDGPU::G_AMDGPU_S_BUFFER_LOAD_UBYTE
7811 : AMDGPU::G_AMDGPU_S_BUFFER_LOAD_USHORT;
7812 // The 8-bit and 16-bit scalar buffer load instructions have 32-bit
7813 // destination register.
7814 Dst = B.getMRI()->createGenericVirtualRegister(LLT::integer(32));
7815 } else {
7816 Opc = AMDGPU::G_AMDGPU_S_BUFFER_LOAD;
7817 Dst = OrigDst;
7818 }
7819
7820 Observer.changingInstr(MI);
7821
7822 // Handle needing to s.buffer.load() a p8 value.
7823 if (hasBufferRsrcWorkaround(Ty)) {
7824 Ty = castBufferRsrcFromV4I32(MI, B, *B.getMRI(), 0);
7825 B.setInsertPt(B.getMBB(), MI);
7826 }
7828 Ty = getBitcastRegisterType(Ty);
7829 Helper.bitcastDst(MI, Ty, 0);
7830 B.setInsertPt(B.getMBB(), MI);
7831 }
7832
7833 MI.setDesc(B.getTII().get(Opc));
7834 MI.removeOperand(1);
7836
7837 if (!HasMMO) {
7838 // Legacy intrinsic that doesn't take a pointer and so can't already have an
7839 // MMO.
7840 const unsigned MemSize = (Size + 7) / 8;
7841 const Align MemAlign = B.getDataLayout().getABITypeAlign(
7847 MemSize, MemAlign);
7848 MI.addMemOperand(MF, MMO);
7849 }
7850 if (Dst != OrigDst) {
7851 MI.getOperand(0).setReg(Dst);
7852 B.setInsertPt(B.getMBB(), ++B.getInsertPt());
7853 B.buildTrunc(OrigDst, Dst);
7854 }
7855
7856 // If we don't have 96-bit result scalar loads, widening to 128-bit should
7857 // always be legal. We may need to restore this to a 96-bit result if it turns
7858 // out this needs to be converted to a vector load during RegBankSelect.
7859 if (!isPowerOf2_32(Size) && (Size != 96 || !ST.hasScalarDwordx3Loads())) {
7860 if (Ty.isVector())
7862 else
7863 Helper.widenScalarDst(MI, getPow2ScalarType(Ty), 0);
7864 }
7865
7866 Observer.changedInstr(MI);
7867 return true;
7868}
7869
7871 MachineInstr &MI) const {
7872 MachineIRBuilder &B = Helper.MIRBuilder;
7873 GISelChangeObserver &Observer = Helper.Observer;
7874 Observer.changingInstr(MI);
7875 MI.setDesc(B.getTII().get(AMDGPU::G_AMDGPU_S_BUFFER_PREFETCH));
7876 MI.removeOperand(0); // Remove intrinsic ID
7878 Observer.changedInstr(MI);
7879 return true;
7880}
7881
7882// TODO: Move to selection
7884 MachineInstr &MI) const {
7885 MachineIRBuilder &B = Helper.MIRBuilder;
7886 MachineRegisterInfo &MRI = *B.getMRI();
7887 if (!ST.hasTrapHandler() ||
7888 ST.getTrapHandlerAbi() != GCNSubtarget::TrapHandlerAbi::AMDHSA)
7889 return legalizeTrapEndpgm(Helper, MI);
7890
7891 return ST.supportsGetDoorbellID() ?
7893}
7894
7896 MachineInstr &MI) const {
7897 MachineIRBuilder &B = Helper.MIRBuilder;
7898 GISelChangeObserver &Observer = Helper.Observer;
7899 const DebugLoc &DL = MI.getDebugLoc();
7900 MachineBasicBlock &BB = B.getMBB();
7901 MachineFunction *MF = BB.getParent();
7902
7903 if (BB.succ_empty() && std::next(MI.getIterator()) == BB.end()) {
7904 BuildMI(BB, BB.end(), DL, B.getTII().get(AMDGPU::S_ENDPGM))
7905 .addImm(0);
7906 MI.eraseFromParent();
7907 return true;
7908 }
7909
7910 // We need a block split to make the real endpgm a terminator. We also don't
7911 // want to break phis in successor blocks, so we can't just delete to the
7912 // end of the block.
7913 // An instruction's parent block is part of its CSE profile, so notify
7914 // observers about the instructions moved by the split.
7916 MachineBasicBlock::iterator SplitPoint(&MI);
7917 ++SplitPoint;
7918 for (auto I = SplitPoint, E = BB.end(); I != E; ++I) {
7919 Observer.changingInstr(*I);
7920 MovedInstrs.push_back(&*I);
7921 }
7922 BB.splitAt(MI, false /*UpdateLiveIns*/);
7923 for (MachineInstr *MovedMI : MovedInstrs)
7924 Observer.changedInstr(*MovedMI);
7926 MF->push_back(TrapBB);
7927 BuildMI(*TrapBB, TrapBB->end(), DL, B.getTII().get(AMDGPU::S_ENDPGM))
7928 .addImm(0);
7929 BuildMI(BB, &MI, DL, B.getTII().get(AMDGPU::S_CBRANCH_EXECNZ))
7930 .addMBB(TrapBB);
7931
7932 BB.addSuccessor(TrapBB);
7933 MI.eraseFromParent();
7934 return true;
7935}
7936
7939 MachineFunction &MF = B.getMF();
7940 const LLT I64 = LLT::integer(64);
7941
7942 Register SGPR01(AMDGPU::SGPR0_SGPR1);
7943 // For code object version 5, queue_ptr is passed through implicit kernarg.
7948 uint64_t Offset =
7949 ST.getTargetLowering()->getImplicitParameterOffset(B.getMF(), Param);
7950
7951 Register KernargPtrReg = MRI.createGenericVirtualRegister(
7953
7954 if (!loadInputValue(KernargPtrReg, B,
7956 return false;
7957
7958 // TODO: can we be smarter about machine pointer info?
7961 PtrInfo.getWithOffset(Offset),
7965
7966 // Pointer address
7969 B.buildObjectPtrOffset(LoadAddr, KernargPtrReg,
7970 B.buildConstant(LLT::integer(64), Offset).getReg(0));
7971 // Load address
7972 Register Temp = B.buildLoad(I64, LoadAddr, *MMO).getReg(0);
7973 B.buildCopy(SGPR01, Temp);
7974 B.buildInstr(AMDGPU::S_TRAP)
7975 .addImm(static_cast<unsigned>(GCNSubtarget::TrapID::LLVMAMDHSATrap))
7976 .addReg(SGPR01, RegState::Implicit);
7977 MI.eraseFromParent();
7978 return true;
7979 }
7980
7981 // Pass queue pointer to trap handler as input, and insert trap instruction
7982 // Reference: https://llvm.org/docs/AMDGPUUsage.html#trap-handler-abi
7983 Register LiveIn =
7986 return false;
7987
7988 B.buildCopy(SGPR01, LiveIn);
7989 B.buildInstr(AMDGPU::S_TRAP)
7990 .addImm(static_cast<unsigned>(GCNSubtarget::TrapID::LLVMAMDHSATrap))
7991 .addReg(SGPR01, RegState::Implicit);
7992
7993 MI.eraseFromParent();
7994 return true;
7995}
7996
7999 MachineIRBuilder &B) const {
8000 // We need to simulate the 's_trap 2' instruction on targets that run in
8001 // PRIV=1 (where it is treated as a nop).
8002 if (ST.hasPrivEnabledTrap2NopBug()) {
8003 ST.getInstrInfo()->insertSimulatedTrap(MRI, B.getMBB(), MI,
8004 MI.getDebugLoc());
8005 MI.eraseFromParent();
8006 return true;
8007 }
8008
8009 B.buildInstr(AMDGPU::S_TRAP)
8010 .addImm(static_cast<unsigned>(GCNSubtarget::TrapID::LLVMAMDHSATrap));
8011 MI.eraseFromParent();
8012 return true;
8013}
8014
8017 MachineIRBuilder &B) const {
8018 // Is non-HSA path or trap-handler disabled? Then, report a warning
8019 // accordingly
8020 if (!ST.hasTrapHandler() ||
8021 ST.getTrapHandlerAbi() != GCNSubtarget::TrapHandlerAbi::AMDHSA) {
8022 Function &Fn = B.getMF().getFunction();
8024 Fn, "debugtrap handler not supported", MI.getDebugLoc(), DS_Warning));
8025 } else {
8026 // Insert debug-trap instruction
8027 B.buildInstr(AMDGPU::S_TRAP)
8028 .addImm(static_cast<unsigned>(GCNSubtarget::TrapID::LLVMAMDHSADebugTrap));
8029 }
8030
8031 MI.eraseFromParent();
8032 return true;
8033}
8034
8036 MachineInstr &MI, MachineIRBuilder &B) const {
8037 MachineRegisterInfo &MRI = *B.getMRI();
8038 const LLT I16 = LLT::integer(16);
8039 const LLT I32 = LLT::integer(32);
8040 const LLT V2I16 = LLT::fixed_vector(2, I16);
8041 const LLT V3I32 = LLT::fixed_vector(3, I32);
8042 const LLT V3I16 = LLT::fixed_vector(3, I16);
8043
8044 Register DstReg = MI.getOperand(0).getReg();
8045 Register NodePtr = MI.getOperand(2).getReg();
8046 Register RayExtent = MI.getOperand(3).getReg();
8047 Register RayOrigin = MI.getOperand(4).getReg();
8048 Register RayDir = MI.getOperand(5).getReg();
8049 Register RayInvDir = MI.getOperand(6).getReg();
8050 Register TDescr = MI.getOperand(7).getReg();
8051
8052 RayExtent = B.buildBitcast(I32, RayExtent).getReg(0);
8053
8054 const bool IsGFX11 = AMDGPU::isGFX11(ST);
8055 const bool IsGFX11Plus = AMDGPU::isGFX11Plus(ST);
8056 const bool IsGFX12Plus = AMDGPU::isGFX12Plus(ST);
8057 const bool IsA16 = MRI.getType(RayDir).getElementType().getSizeInBits() == 16;
8058 const bool Is64 = MRI.getType(NodePtr).getSizeInBits() == 64;
8059 const unsigned NumVDataDwords = 4;
8060 const unsigned NumVAddrDwords = IsA16 ? (Is64 ? 9 : 8) : (Is64 ? 12 : 11);
8061 const unsigned NumVAddrs = IsGFX11Plus ? (IsA16 ? 4 : 5) : NumVAddrDwords;
8062 const bool UseNSA =
8063 IsGFX12Plus || (ST.hasNSAEncoding() && NumVAddrs <= ST.getNSAMaxSize());
8064
8065 const unsigned BaseOpcodes[2][2] = {
8066 {AMDGPU::IMAGE_BVH_INTERSECT_RAY, AMDGPU::IMAGE_BVH_INTERSECT_RAY_a16},
8067 {AMDGPU::IMAGE_BVH64_INTERSECT_RAY,
8068 AMDGPU::IMAGE_BVH64_INTERSECT_RAY_a16}};
8069 int Opcode;
8070 if (UseNSA) {
8071 Opcode = AMDGPU::getMIMGOpcode(BaseOpcodes[Is64][IsA16],
8072 IsGFX12Plus ? AMDGPU::MIMGEncGfx12
8073 : IsGFX11 ? AMDGPU::MIMGEncGfx11NSA
8074 : AMDGPU::MIMGEncGfx10NSA,
8075 NumVDataDwords, NumVAddrDwords);
8076 } else {
8077 assert(!IsGFX12Plus);
8078 Opcode = AMDGPU::getMIMGOpcode(BaseOpcodes[Is64][IsA16],
8079 IsGFX11 ? AMDGPU::MIMGEncGfx11Default
8080 : AMDGPU::MIMGEncGfx10Default,
8081 NumVDataDwords, NumVAddrDwords);
8082 }
8083 assert(Opcode != -1);
8084
8086 if (UseNSA && IsGFX11Plus) {
8087 auto packLanes = [&Ops, &I32, &V3I32, &B](Register Src) {
8088 auto SrcInt = B.buildBitcast(V3I32, Src);
8089 auto Unmerge = B.buildUnmerge({I32, I32, I32}, SrcInt);
8090 auto Merged = B.buildMergeLikeInstr(
8091 V3I32, {Unmerge.getReg(0), Unmerge.getReg(1), Unmerge.getReg(2)});
8092 Ops.push_back(Merged.getReg(0));
8093 };
8094
8095 Ops.push_back(NodePtr);
8096 Ops.push_back(RayExtent);
8097 packLanes(RayOrigin);
8098
8099 if (IsA16) {
8100 auto UnmergeRayDir =
8101 B.buildUnmerge({I16, I16, I16}, B.buildBitcast(V3I16, RayDir));
8102 auto UnmergeRayInvDir =
8103 B.buildUnmerge({I16, I16, I16}, B.buildBitcast(V3I16, RayInvDir));
8104 auto MergedDir = B.buildMergeLikeInstr(
8105 V3I32,
8106 {B.buildBitcast(
8107 I32, B.buildMergeLikeInstr(V2I16, {UnmergeRayInvDir.getReg(0),
8108 UnmergeRayDir.getReg(0)}))
8109 .getReg(0),
8110 B.buildBitcast(
8111 I32, B.buildMergeLikeInstr(V2I16, {UnmergeRayInvDir.getReg(1),
8112 UnmergeRayDir.getReg(1)}))
8113 .getReg(0),
8114 B.buildBitcast(
8115 I32, B.buildMergeLikeInstr(V2I16, {UnmergeRayInvDir.getReg(2),
8116 UnmergeRayDir.getReg(2)}))
8117 .getReg(0)});
8118 Ops.push_back(MergedDir.getReg(0));
8119 } else {
8120 packLanes(RayDir);
8121 packLanes(RayInvDir);
8122 }
8123 } else {
8124 if (Is64) {
8125 auto Unmerge = B.buildUnmerge({I32, I32}, NodePtr);
8126 Ops.push_back(Unmerge.getReg(0));
8127 Ops.push_back(Unmerge.getReg(1));
8128 } else {
8129 Ops.push_back(NodePtr);
8130 }
8131 Ops.push_back(RayExtent);
8132
8133 auto packLanes = [&Ops, &I32, &V3I32, &B](Register Src) {
8134 auto SrcInt = B.buildBitcast(V3I32, Src);
8135 auto Unmerge = B.buildUnmerge({I32, I32, I32}, SrcInt);
8136 Ops.push_back(Unmerge.getReg(0));
8137 Ops.push_back(Unmerge.getReg(1));
8138 Ops.push_back(Unmerge.getReg(2));
8139 };
8140
8141 packLanes(RayOrigin);
8142 if (IsA16) {
8143 auto UnmergeRayDir =
8144 B.buildUnmerge({I16, I16, I16}, B.buildBitcast(V3I16, RayDir));
8145 auto UnmergeRayInvDir =
8146 B.buildUnmerge({I16, I16, I16}, B.buildBitcast(V3I16, RayInvDir));
8150 B.buildMergeLikeInstr(R1,
8151 {UnmergeRayDir.getReg(0), UnmergeRayDir.getReg(1)});
8152 B.buildMergeLikeInstr(
8153 R2, {UnmergeRayDir.getReg(2), UnmergeRayInvDir.getReg(0)});
8154 B.buildMergeLikeInstr(
8155 R3, {UnmergeRayInvDir.getReg(1), UnmergeRayInvDir.getReg(2)});
8156 Ops.push_back(R1);
8157 Ops.push_back(R2);
8158 Ops.push_back(R3);
8159 } else {
8160 packLanes(RayDir);
8161 packLanes(RayInvDir);
8162 }
8163 }
8164
8165 if (!UseNSA) {
8166 // Build a single vector containing all the operands so far prepared.
8167 LLT OpTy = LLT::fixed_vector(Ops.size(), I32);
8168 Register MergedOps = B.buildMergeLikeInstr(OpTy, Ops).getReg(0);
8169 Ops.clear();
8170 Ops.push_back(MergedOps);
8171 }
8172
8173 auto MIB = B.buildInstr(AMDGPU::G_AMDGPU_BVH_INTERSECT_RAY)
8174 .addDef(DstReg)
8175 .addImm(Opcode);
8176
8177 for (Register R : Ops) {
8178 MIB.addUse(R);
8179 }
8180
8181 MIB.addUse(TDescr)
8182 .addImm(IsA16 ? 1 : 0)
8183 .cloneMemRefs(MI);
8184
8185 MI.eraseFromParent();
8186 return true;
8187}
8188
8190 MachineInstr &MI, MachineIRBuilder &B) const {
8191 const LLT I32 = LLT::integer(32);
8192 const LLT V2I32 = LLT::fixed_vector(2, I32);
8193
8194 Register DstReg = MI.getOperand(0).getReg();
8195 Register DstOrigin = MI.getOperand(1).getReg();
8196 Register DstDir = MI.getOperand(2).getReg();
8197 Register NodePtr = MI.getOperand(4).getReg();
8198 Register RayExtent = MI.getOperand(5).getReg();
8199 Register InstanceMask = MI.getOperand(6).getReg();
8200 Register RayOrigin = MI.getOperand(7).getReg();
8201 Register RayDir = MI.getOperand(8).getReg();
8202 Register Offsets = MI.getOperand(9).getReg();
8203 Register TDescr = MI.getOperand(10).getReg();
8204
8205 bool IsBVH8 = cast<GIntrinsic>(MI).getIntrinsicID() ==
8206 Intrinsic::amdgcn_image_bvh8_intersect_ray;
8207 const unsigned NumVDataDwords = 10;
8208 const unsigned NumVAddrDwords = IsBVH8 ? 11 : 12;
8209 int Opcode = AMDGPU::getMIMGOpcode(
8210 IsBVH8 ? AMDGPU::IMAGE_BVH8_INTERSECT_RAY
8211 : AMDGPU::IMAGE_BVH_DUAL_INTERSECT_RAY,
8212 AMDGPU::MIMGEncGfx12, NumVDataDwords, NumVAddrDwords);
8213 assert(Opcode != -1);
8214
8215 auto RayExtentInstanceMaskVec =
8216 B.buildMergeLikeInstr(V2I32, {B.buildBitcast(I32, RayExtent),
8217 B.buildAnyExt(I32, InstanceMask)});
8218
8219 B.buildInstr(IsBVH8 ? AMDGPU::G_AMDGPU_BVH8_INTERSECT_RAY
8220 : AMDGPU::G_AMDGPU_BVH_DUAL_INTERSECT_RAY)
8221 .addDef(DstReg)
8222 .addDef(DstOrigin)
8223 .addDef(DstDir)
8224 .addImm(Opcode)
8225 .addUse(NodePtr)
8226 .addUse(RayExtentInstanceMaskVec.getReg(0))
8227 .addUse(RayOrigin)
8228 .addUse(RayDir)
8229 .addUse(Offsets)
8230 .addUse(TDescr)
8231 .cloneMemRefs(MI);
8232
8233 MI.eraseFromParent();
8234 return true;
8235}
8236
8238 MachineIRBuilder &B) const {
8239 const SITargetLowering *TLI = ST.getTargetLowering();
8241 Register DstReg = MI.getOperand(0).getReg();
8242 B.buildInstr(AMDGPU::G_AMDGPU_WAVE_ADDRESS, {DstReg}, {StackPtr});
8243 MI.eraseFromParent();
8244 return true;
8245}
8246
8248 MachineIRBuilder &B) const {
8249 // With architected SGPRs, waveIDinGroup is in TTMP8[29:25].
8250 if (!ST.hasArchitectedSGPRs())
8251 return false;
8252 LLT I32 = LLT::integer(32);
8253 Register DstReg = MI.getOperand(0).getReg();
8254 auto TTMP8 = B.buildCopy(I32, Register(AMDGPU::TTMP8));
8255 auto LSB = B.buildConstant(I32, 25);
8256 auto Width = B.buildConstant(I32, 5);
8257 B.buildUbfx(DstReg, TTMP8, LSB, Width);
8258 MI.eraseFromParent();
8259 return true;
8260}
8261
8264 AMDGPU::Hwreg::Id HwReg,
8265 unsigned LowBit,
8266 unsigned Width) const {
8267 MachineRegisterInfo &MRI = *B.getMRI();
8268 Register DstReg = MI.getOperand(0).getReg();
8269 Register Result = MRI.createVirtualRegister(
8270 {&AMDGPU::SReg_32RegClass, MRI.getType(DstReg)});
8271 B.buildInstr(AMDGPU::S_GETREG_B32_const)
8272 .addDef(Result)
8273 .addImm(AMDGPU::Hwreg::HwregEncoding::encode(HwReg, LowBit, Width));
8274 B.buildCopy(DstReg, Result);
8275 MI.eraseFromParent();
8276 return true;
8277}
8278
8279static constexpr unsigned FPEnvModeBitField =
8281
8282static constexpr unsigned FPEnvTrapBitField =
8284
8287 MachineIRBuilder &B) const {
8288 const LLT I32 = LLT::integer(32);
8289 const LLT I64 = LLT::integer(64);
8290 Register Src = MI.getOperand(0).getReg();
8291 if (MRI.getType(Src) != I64)
8292 return false;
8293
8294 auto ModeReg =
8295 B.buildIntrinsic(Intrinsic::amdgcn_s_getreg, {I32},
8296 /*HasSideEffects=*/true, /*isConvergent=*/false)
8297 .addImm(FPEnvModeBitField);
8298 auto TrapReg =
8299 B.buildIntrinsic(Intrinsic::amdgcn_s_getreg, {I32},
8300 /*HasSideEffects=*/true, /*isConvergent=*/false)
8301 .addImm(FPEnvTrapBitField);
8302 B.buildMergeLikeInstr(Src, {ModeReg, TrapReg});
8303 MI.eraseFromParent();
8304 return true;
8305}
8306
8309 MachineIRBuilder &B) const {
8310 const LLT I32 = LLT::integer(32);
8311 const LLT I64 = LLT::integer(64);
8312 Register Src = MI.getOperand(0).getReg();
8313 if (MRI.getType(Src) != I64)
8314 return false;
8315
8316 auto Unmerge = B.buildUnmerge({I32, I32}, MI.getOperand(0));
8317 B.buildIntrinsic(Intrinsic::amdgcn_s_setreg, ArrayRef<DstOp>(),
8318 /*HasSideEffects=*/true, /*isConvergent=*/false)
8319 .addImm(static_cast<int16_t>(FPEnvModeBitField))
8320 .addReg(Unmerge.getReg(0));
8321 B.buildIntrinsic(Intrinsic::amdgcn_s_setreg, ArrayRef<DstOp>(),
8322 /*HasSideEffects=*/true, /*isConvergent=*/false)
8323 .addImm(static_cast<int16_t>(FPEnvTrapBitField))
8324 .addReg(Unmerge.getReg(1));
8325 MI.eraseFromParent();
8326 return true;
8327}
8328
8330 MachineInstr &MI) const {
8331 MachineIRBuilder &B = Helper.MIRBuilder;
8332 MachineRegisterInfo &MRI = *B.getMRI();
8333
8334 // Replace the use G_BRCOND with the exec manipulate and branch pseudos.
8335 auto IntrID = cast<GIntrinsic>(MI).getIntrinsicID();
8336 switch (IntrID) {
8337 case Intrinsic::sponentry:
8338 if (B.getMF().getInfo<SIMachineFunctionInfo>()->isBottomOfStack()) {
8339 // FIXME: The imported pattern checks for i32 instead of p5; if we fix
8340 // that we can remove this cast.
8341 const LLT I32 = LLT::integer(32);
8342 Register TmpReg = MRI.createGenericVirtualRegister(I32);
8343 B.buildInstr(AMDGPU::G_AMDGPU_SPONENTRY).addDef(TmpReg);
8344
8345 Register DstReg = MI.getOperand(0).getReg();
8346 B.buildIntToPtr(DstReg, TmpReg);
8347 MI.eraseFromParent();
8348 } else {
8349 int FI = B.getMF().getFrameInfo().CreateFixedObject(
8350 1, 0, /*IsImmutable=*/false);
8351 B.buildFrameIndex(MI.getOperand(0), FI);
8352 MI.eraseFromParent();
8353 }
8354 return true;
8355 case Intrinsic::amdgcn_if:
8356 case Intrinsic::amdgcn_else: {
8357 MachineInstr *Br = nullptr;
8358 MachineBasicBlock *UncondBrTarget = nullptr;
8359 bool Negated = false;
8360 if (MachineInstr *BrCond =
8361 verifyCFIntrinsic(MI, MRI, Br, UncondBrTarget, Negated)) {
8362 const SIRegisterInfo *TRI
8363 = static_cast<const SIRegisterInfo *>(MRI.getTargetRegisterInfo());
8364
8365 Register Def = MI.getOperand(1).getReg();
8366 Register Use = MI.getOperand(3).getReg();
8367 const TargetRegisterClass *WaveMaskRC = TRI->getWaveMaskRegClass();
8368 Register NewDef =
8369 MRI.createVirtualRegister({WaveMaskRC, MRI.getType(Def)});
8370 Register NewUse =
8371 MRI.createVirtualRegister({WaveMaskRC, MRI.getType(Use)});
8372
8373 MachineBasicBlock *CondBrTarget = BrCond->getOperand(1).getMBB();
8374
8375 if (Negated)
8376 std::swap(CondBrTarget, UncondBrTarget);
8377
8378 B.setInsertPt(B.getMBB(), BrCond->getIterator());
8379 B.buildCopy(NewUse, Use);
8380 if (IntrID == Intrinsic::amdgcn_if) {
8381 B.buildInstr(AMDGPU::SI_IF)
8382 .addDef(NewDef)
8383 .addUse(NewUse)
8384 .addMBB(UncondBrTarget)
8385 .setOperandDead(4); // implicit-def $scc
8386 } else {
8387 B.buildInstr(AMDGPU::SI_ELSE)
8388 .addDef(NewDef)
8389 .addUse(NewUse)
8390 .addMBB(UncondBrTarget)
8391 .setOperandDead(4); // implicit-def $scc
8392 }
8393
8394 if (Br) {
8395 Br->getOperand(0).setMBB(CondBrTarget);
8396 } else {
8397 // The IRTranslator skips inserting the G_BR for fallthrough cases, but
8398 // since we're swapping branch targets it needs to be reinserted.
8399 // FIXME: IRTranslator should probably not do this
8400 B.buildBr(*CondBrTarget);
8401 }
8402
8403 MI.eraseFromParent();
8404 BrCond->eraseFromParent();
8405 // SI_IF and SI_ELSE are terminators, so replace uses of Def rather than
8406 // defining Def with a following copy.
8407 Helper.Observer.changingAllUsesOfReg(MRI, Def);
8408 MRI.replaceRegWith(Def, NewDef);
8410 return true;
8411 }
8412
8413 return false;
8414 }
8415 case Intrinsic::amdgcn_loop: {
8416 MachineInstr *Br = nullptr;
8417 MachineBasicBlock *UncondBrTarget = nullptr;
8418 bool Negated = false;
8419 if (MachineInstr *BrCond =
8420 verifyCFIntrinsic(MI, MRI, Br, UncondBrTarget, Negated)) {
8421 const SIRegisterInfo *TRI
8422 = static_cast<const SIRegisterInfo *>(MRI.getTargetRegisterInfo());
8423
8424 MachineBasicBlock *CondBrTarget = BrCond->getOperand(1).getMBB();
8425 Register Reg = MI.getOperand(2).getReg();
8426 Register NewReg = MRI.createVirtualRegister(
8427 {TRI->getWaveMaskRegClass(), MRI.getType(Reg)});
8428
8429 if (Negated)
8430 std::swap(CondBrTarget, UncondBrTarget);
8431
8432 B.setInsertPt(B.getMBB(), BrCond->getIterator());
8433 B.buildCopy(NewReg, Reg);
8434 B.buildInstr(AMDGPU::SI_LOOP)
8435 .addUse(NewReg)
8436 .addMBB(UncondBrTarget)
8437 .setOperandDead(3); // implicit-def $scc
8438
8439 if (Br)
8440 Br->getOperand(0).setMBB(CondBrTarget);
8441 else
8442 B.buildBr(*CondBrTarget);
8443
8444 MI.eraseFromParent();
8445 BrCond->eraseFromParent();
8446 return true;
8447 }
8448
8449 return false;
8450 }
8451 case Intrinsic::amdgcn_wave_reduce_min:
8452 case Intrinsic::amdgcn_wave_reduce_umin:
8453 case Intrinsic::amdgcn_wave_reduce_fmin:
8454 case Intrinsic::amdgcn_wave_reduce_max:
8455 case Intrinsic::amdgcn_wave_reduce_umax:
8456 case Intrinsic::amdgcn_wave_reduce_fmax:
8457 case Intrinsic::amdgcn_wave_reduce_add:
8458 case Intrinsic::amdgcn_wave_reduce_fadd:
8459 case Intrinsic::amdgcn_wave_reduce_sub:
8460 case Intrinsic::amdgcn_wave_reduce_fsub:
8461 case Intrinsic::amdgcn_wave_reduce_and:
8462 case Intrinsic::amdgcn_wave_reduce_or:
8463 case Intrinsic::amdgcn_wave_reduce_xor: {
8464 Register SrcReg = MI.getOperand(2).getReg();
8465 if (MRI.getType(SrcReg).getSizeInBits() != 16)
8466 return true;
8467 Register DstReg = MI.getOperand(0).getReg();
8468 bool IsFPOp = IntrID == Intrinsic::amdgcn_wave_reduce_fmin ||
8469 IntrID == Intrinsic::amdgcn_wave_reduce_fmax ||
8470 IntrID == Intrinsic::amdgcn_wave_reduce_fadd ||
8471 IntrID == Intrinsic::amdgcn_wave_reduce_fsub;
8472 bool NeedsSignExt = IntrID == Intrinsic::amdgcn_wave_reduce_min ||
8473 IntrID == Intrinsic::amdgcn_wave_reduce_max ||
8474 IntrID == Intrinsic::amdgcn_wave_reduce_add ||
8475 IntrID == Intrinsic::amdgcn_wave_reduce_sub;
8476 auto Ext = IsFPOp ? B.buildFPExt(F32, SrcReg)
8477 : NeedsSignExt ? B.buildSExt(LLT::integer(32), SrcReg)
8478 : B.buildZExt(LLT::integer(32), SrcReg);
8479 auto NewDst =
8480 MRI.createGenericVirtualRegister(IsFPOp ? F32 : LLT::integer(32));
8481 B.buildIntrinsic(IntrID, ArrayRef<Register>{NewDst},
8482 /*hasSideEffects=*/false, /*isConvergent=*/true)
8483 .addUse(Ext.getReg(0))
8484 .addImm(MI.getOperand(3).getImm()); // strategy
8485 if (IsFPOp)
8486 B.buildFPTrunc(DstReg, NewDst);
8487 else
8488 B.buildTrunc(DstReg, NewDst);
8489 MI.eraseFromParent();
8490 return true;
8491 }
8492 case Intrinsic::amdgcn_make_buffer_rsrc:
8493 return legalizePointerAsRsrcIntrin(MI, MRI, B);
8494 case Intrinsic::amdgcn_kernarg_segment_ptr:
8495 if (!AMDGPU::isKernel(B.getMF().getFunction())) {
8496 // This only makes sense to call in a kernel, so just lower to null.
8497 B.buildConstant(MI.getOperand(0).getReg(), 0);
8498 MI.eraseFromParent();
8499 return true;
8500 }
8501
8504 case Intrinsic::amdgcn_implicitarg_ptr:
8505 return legalizeImplicitArgPtr(MI, MRI, B);
8506 case Intrinsic::amdgcn_workitem_id_x:
8507 return legalizeWorkitemIDIntrinsic(MI, MRI, B, 0,
8509 case Intrinsic::amdgcn_workitem_id_y:
8510 return legalizeWorkitemIDIntrinsic(MI, MRI, B, 1,
8512 case Intrinsic::amdgcn_workitem_id_z:
8513 return legalizeWorkitemIDIntrinsic(MI, MRI, B, 2,
8515 case Intrinsic::amdgcn_workgroup_id_x:
8516 return legalizeWorkGroupId(
8520 case Intrinsic::amdgcn_workgroup_id_y:
8521 return legalizeWorkGroupId(
8525 case Intrinsic::amdgcn_workgroup_id_z:
8526 return legalizeWorkGroupId(
8530 case Intrinsic::amdgcn_cluster_id_x:
8531 return ST.hasClusters() &&
8534 case Intrinsic::amdgcn_cluster_id_y:
8535 return ST.hasClusters() &&
8538 case Intrinsic::amdgcn_cluster_id_z:
8539 return ST.hasClusters() &&
8542 case Intrinsic::amdgcn_cluster_workgroup_id_x:
8543 return ST.hasClusters() &&
8546 case Intrinsic::amdgcn_cluster_workgroup_id_y:
8547 return ST.hasClusters() &&
8550 case Intrinsic::amdgcn_cluster_workgroup_id_z:
8551 return ST.hasClusters() &&
8554 case Intrinsic::amdgcn_cluster_workgroup_flat_id:
8555 return ST.hasClusters() &&
8557 case Intrinsic::amdgcn_cluster_workgroup_max_id_x:
8558 return ST.hasClusters() &&
8561 case Intrinsic::amdgcn_cluster_workgroup_max_id_y:
8562 return ST.hasClusters() &&
8565 case Intrinsic::amdgcn_cluster_workgroup_max_id_z:
8566 return ST.hasClusters() &&
8569 case Intrinsic::amdgcn_cluster_workgroup_max_flat_id:
8570 return ST.hasClusters() &&
8572 MI, MRI, B,
8574 case Intrinsic::amdgcn_wave_id:
8575 return legalizeWaveID(MI, B);
8576 case Intrinsic::amdgcn_lds_kernel_id:
8577 return legalizePreloadedArgIntrin(MI, MRI, B,
8579 case Intrinsic::amdgcn_dispatch_ptr:
8580 return legalizePreloadedArgIntrin(MI, MRI, B,
8582 case Intrinsic::amdgcn_queue_ptr:
8583 return legalizePreloadedArgIntrin(MI, MRI, B,
8585 case Intrinsic::amdgcn_implicit_buffer_ptr:
8588 case Intrinsic::amdgcn_dispatch_id:
8589 return legalizePreloadedArgIntrin(MI, MRI, B,
8591 case Intrinsic::r600_read_ngroups_x:
8592 // TODO: Emit error for hsa
8595 case Intrinsic::r600_read_ngroups_y:
8598 case Intrinsic::r600_read_ngroups_z:
8601 case Intrinsic::r600_read_local_size_x:
8602 // TODO: Could insert G_ASSERT_ZEXT from i16
8604 case Intrinsic::r600_read_local_size_y:
8605 // TODO: Could insert G_ASSERT_ZEXT from i16
8607 // TODO: Could insert G_ASSERT_ZEXT from i16
8608 case Intrinsic::r600_read_local_size_z:
8611 case Intrinsic::amdgcn_fdiv_fast:
8612 return legalizeFDIVFastIntrin(MI, MRI, B);
8613 case Intrinsic::amdgcn_is_shared:
8615 case Intrinsic::amdgcn_is_private:
8617 case Intrinsic::amdgcn_wavefrontsize: {
8618 B.buildConstant(MI.getOperand(0), ST.getWavefrontSize());
8619 MI.eraseFromParent();
8620 return true;
8621 }
8622 case Intrinsic::amdgcn_s_buffer_load:
8623 case Intrinsic::amdgcn_ptr_s_buffer_load:
8624 return legalizeSBufferLoad(Helper, MI);
8625 case Intrinsic::amdgcn_raw_buffer_store:
8626 case Intrinsic::amdgcn_raw_ptr_buffer_store:
8627 case Intrinsic::amdgcn_struct_buffer_store:
8628 case Intrinsic::amdgcn_struct_ptr_buffer_store:
8629 return legalizeBufferStore(MI, Helper, false, false);
8630 case Intrinsic::amdgcn_raw_buffer_store_format:
8631 case Intrinsic::amdgcn_raw_ptr_buffer_store_format:
8632 case Intrinsic::amdgcn_struct_buffer_store_format:
8633 case Intrinsic::amdgcn_struct_ptr_buffer_store_format:
8634 return legalizeBufferStore(MI, Helper, false, true);
8635 case Intrinsic::amdgcn_raw_tbuffer_store:
8636 case Intrinsic::amdgcn_raw_ptr_tbuffer_store:
8637 case Intrinsic::amdgcn_struct_tbuffer_store:
8638 case Intrinsic::amdgcn_struct_ptr_tbuffer_store:
8639 return legalizeBufferStore(MI, Helper, true, true);
8640 case Intrinsic::amdgcn_raw_buffer_load:
8641 case Intrinsic::amdgcn_raw_ptr_buffer_load:
8642 case Intrinsic::amdgcn_raw_atomic_buffer_load:
8643 case Intrinsic::amdgcn_raw_ptr_atomic_buffer_load:
8644 case Intrinsic::amdgcn_struct_buffer_load:
8645 case Intrinsic::amdgcn_struct_ptr_buffer_load:
8646 case Intrinsic::amdgcn_struct_atomic_buffer_load:
8647 case Intrinsic::amdgcn_struct_ptr_atomic_buffer_load:
8648 return legalizeBufferLoad(MI, Helper, false, false);
8649 case Intrinsic::amdgcn_raw_buffer_load_format:
8650 case Intrinsic::amdgcn_raw_ptr_buffer_load_format:
8651 case Intrinsic::amdgcn_struct_buffer_load_format:
8652 case Intrinsic::amdgcn_struct_ptr_buffer_load_format:
8653 return legalizeBufferLoad(MI, Helper, true, false);
8654 case Intrinsic::amdgcn_raw_tbuffer_load:
8655 case Intrinsic::amdgcn_raw_ptr_tbuffer_load:
8656 case Intrinsic::amdgcn_struct_tbuffer_load:
8657 case Intrinsic::amdgcn_struct_ptr_tbuffer_load:
8658 return legalizeBufferLoad(MI, Helper, true, true);
8659 case Intrinsic::amdgcn_raw_buffer_atomic_swap:
8660 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_swap:
8661 case Intrinsic::amdgcn_struct_buffer_atomic_swap:
8662 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_swap:
8663 case Intrinsic::amdgcn_raw_buffer_atomic_add:
8664 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_add:
8665 case Intrinsic::amdgcn_struct_buffer_atomic_add:
8666 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_add:
8667 case Intrinsic::amdgcn_raw_buffer_atomic_sub:
8668 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_sub:
8669 case Intrinsic::amdgcn_struct_buffer_atomic_sub:
8670 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_sub:
8671 case Intrinsic::amdgcn_raw_buffer_atomic_smin:
8672 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_smin:
8673 case Intrinsic::amdgcn_struct_buffer_atomic_smin:
8674 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_smin:
8675 case Intrinsic::amdgcn_raw_buffer_atomic_umin:
8676 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_umin:
8677 case Intrinsic::amdgcn_struct_buffer_atomic_umin:
8678 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_umin:
8679 case Intrinsic::amdgcn_raw_buffer_atomic_smax:
8680 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_smax:
8681 case Intrinsic::amdgcn_struct_buffer_atomic_smax:
8682 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_smax:
8683 case Intrinsic::amdgcn_raw_buffer_atomic_umax:
8684 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_umax:
8685 case Intrinsic::amdgcn_struct_buffer_atomic_umax:
8686 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_umax:
8687 case Intrinsic::amdgcn_raw_buffer_atomic_and:
8688 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_and:
8689 case Intrinsic::amdgcn_struct_buffer_atomic_and:
8690 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_and:
8691 case Intrinsic::amdgcn_raw_buffer_atomic_or:
8692 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_or:
8693 case Intrinsic::amdgcn_struct_buffer_atomic_or:
8694 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_or:
8695 case Intrinsic::amdgcn_raw_buffer_atomic_xor:
8696 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_xor:
8697 case Intrinsic::amdgcn_struct_buffer_atomic_xor:
8698 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_xor:
8699 case Intrinsic::amdgcn_raw_buffer_atomic_inc:
8700 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_inc:
8701 case Intrinsic::amdgcn_struct_buffer_atomic_inc:
8702 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_inc:
8703 case Intrinsic::amdgcn_raw_buffer_atomic_dec:
8704 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_dec:
8705 case Intrinsic::amdgcn_struct_buffer_atomic_dec:
8706 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_dec:
8707 case Intrinsic::amdgcn_raw_buffer_atomic_cmpswap:
8708 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_cmpswap:
8709 case Intrinsic::amdgcn_struct_buffer_atomic_cmpswap:
8710 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_cmpswap:
8711 case Intrinsic::amdgcn_raw_buffer_atomic_fmin:
8712 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_fmin:
8713 case Intrinsic::amdgcn_struct_buffer_atomic_fmin:
8714 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_fmin:
8715 case Intrinsic::amdgcn_raw_buffer_atomic_fmax:
8716 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_fmax:
8717 case Intrinsic::amdgcn_struct_buffer_atomic_fmax:
8718 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_fmax:
8719 case Intrinsic::amdgcn_raw_buffer_atomic_sub_clamp_u32:
8720 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_sub_clamp_u32:
8721 case Intrinsic::amdgcn_struct_buffer_atomic_sub_clamp_u32:
8722 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_sub_clamp_u32:
8723 case Intrinsic::amdgcn_raw_buffer_atomic_cond_sub_u32:
8724 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_cond_sub_u32:
8725 case Intrinsic::amdgcn_struct_buffer_atomic_cond_sub_u32:
8726 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_cond_sub_u32:
8727 case Intrinsic::amdgcn_raw_buffer_atomic_fadd:
8728 case Intrinsic::amdgcn_raw_ptr_buffer_atomic_fadd:
8729 case Intrinsic::amdgcn_struct_buffer_atomic_fadd:
8730 case Intrinsic::amdgcn_struct_ptr_buffer_atomic_fadd:
8731 return legalizeBufferAtomic(MI, B, IntrID);
8732 case Intrinsic::amdgcn_rsq_clamp:
8733 return legalizeRsqClampIntrinsic(MI, MRI, B);
8734 case Intrinsic::amdgcn_image_bvh_intersect_ray:
8736 case Intrinsic::amdgcn_image_bvh_dual_intersect_ray:
8737 case Intrinsic::amdgcn_image_bvh8_intersect_ray:
8739 case Intrinsic::amdgcn_swmmac_f32_16x16x128_fp8_fp8:
8740 case Intrinsic::amdgcn_swmmac_f32_16x16x128_fp8_bf8:
8741 case Intrinsic::amdgcn_swmmac_f32_16x16x128_bf8_fp8:
8742 case Intrinsic::amdgcn_swmmac_f32_16x16x128_bf8_bf8:
8743 case Intrinsic::amdgcn_swmmac_f16_16x16x128_fp8_fp8:
8744 case Intrinsic::amdgcn_swmmac_f16_16x16x128_fp8_bf8:
8745 case Intrinsic::amdgcn_swmmac_f16_16x16x128_bf8_fp8:
8746 case Intrinsic::amdgcn_swmmac_f16_16x16x128_bf8_bf8: {
8747 Register Index = MI.getOperand(5).getReg();
8748 LLT I64 = LLT::integer(64);
8749 LLT IndexArgTy = MRI.getType(Index);
8750 if (IndexArgTy != I64) {
8751 auto NewIndex = IndexArgTy.isVector() ? B.buildBitcast(I64, Index)
8752 : B.buildAnyExt(I64, Index);
8753 MI.getOperand(5).setReg(NewIndex.getReg(0));
8754 }
8755 return true;
8756 }
8757 case Intrinsic::amdgcn_swmmac_f16_16x16x32_f16:
8758 case Intrinsic::amdgcn_swmmac_bf16_16x16x32_bf16:
8759 case Intrinsic::amdgcn_swmmac_f32_16x16x32_bf16:
8760 case Intrinsic::amdgcn_swmmac_f32_16x16x32_f16:
8761 case Intrinsic::amdgcn_swmmac_f32_16x16x32_fp8_fp8:
8762 case Intrinsic::amdgcn_swmmac_f32_16x16x32_fp8_bf8:
8763 case Intrinsic::amdgcn_swmmac_f32_16x16x32_bf8_fp8:
8764 case Intrinsic::amdgcn_swmmac_f32_16x16x32_bf8_bf8: {
8765 Register Index = MI.getOperand(5).getReg();
8766 LLT I32 = LLT::integer(32);
8767 if (MRI.getType(Index) != I32)
8768 MI.getOperand(5).setReg(B.buildAnyExt(I32, Index).getReg(0));
8769 return true;
8770 }
8771 case Intrinsic::amdgcn_swmmac_f16_16x16x64_f16:
8772 case Intrinsic::amdgcn_swmmac_bf16_16x16x64_bf16:
8773 case Intrinsic::amdgcn_swmmac_f32_16x16x64_bf16:
8774 case Intrinsic::amdgcn_swmmac_bf16f32_16x16x64_bf16:
8775 case Intrinsic::amdgcn_swmmac_f32_16x16x64_f16:
8776 case Intrinsic::amdgcn_swmmac_i32_16x16x128_iu8:
8777 case Intrinsic::amdgcn_swmmac_i32_16x16x32_iu4:
8778 case Intrinsic::amdgcn_swmmac_i32_16x16x32_iu8:
8779 case Intrinsic::amdgcn_swmmac_i32_16x16x64_iu4: {
8780 Register Index = MI.getOperand(7).getReg();
8781 LLT IdxTy = IntrID == Intrinsic::amdgcn_swmmac_i32_16x16x128_iu8
8782 ? LLT::integer(64)
8783 : LLT::integer(32);
8784 LLT IndexArgTy = MRI.getType(Index);
8785 if (IndexArgTy != IdxTy) {
8786 auto NewIndex = IndexArgTy.isVector() ? B.buildBitcast(IdxTy, Index)
8787 : B.buildAnyExt(IdxTy, Index);
8788 MI.getOperand(7).setReg(NewIndex.getReg(0));
8789 }
8790 return true;
8791 }
8792
8793 case Intrinsic::amdgcn_fmed3: {
8794 GISelChangeObserver &Observer = Helper.Observer;
8795
8796 // FIXME: This is to workaround the inability of tablegen match combiners to
8797 // match intrinsics in patterns.
8798 Observer.changingInstr(MI);
8799 MI.setDesc(B.getTII().get(AMDGPU::G_AMDGPU_FMED3));
8800 MI.removeOperand(1);
8801 Observer.changedInstr(MI);
8802 return true;
8803 }
8804 case Intrinsic::amdgcn_readlane:
8805 case Intrinsic::amdgcn_writelane:
8806 case Intrinsic::amdgcn_readfirstlane:
8807 case Intrinsic::amdgcn_permlane16:
8808 case Intrinsic::amdgcn_permlanex16:
8809 case Intrinsic::amdgcn_permlane64:
8810 case Intrinsic::amdgcn_set_inactive:
8811 case Intrinsic::amdgcn_set_inactive_chain_arg:
8812 case Intrinsic::amdgcn_mov_dpp8:
8813 case Intrinsic::amdgcn_update_dpp:
8814 case Intrinsic::amdgcn_permlane_bcast:
8815 case Intrinsic::amdgcn_permlane_up:
8816 case Intrinsic::amdgcn_permlane_down:
8817 case Intrinsic::amdgcn_permlane_xor:
8818 return legalizeLaneOp(Helper, MI, IntrID);
8819 case Intrinsic::amdgcn_s_buffer_prefetch_data:
8820 return legalizeSBufferPrefetch(Helper, MI);
8821 case Intrinsic::amdgcn_dead: {
8822 // TODO: Use poison instead of undef
8823 for (const MachineOperand &Def : MI.defs())
8824 B.buildUndef(Def);
8825 MI.eraseFromParent();
8826 return true;
8827 }
8828 case Intrinsic::amdgcn_cooperative_atomic_load_32x4B:
8829 case Intrinsic::amdgcn_cooperative_atomic_load_16x8B:
8830 case Intrinsic::amdgcn_cooperative_atomic_load_8x16B:
8831 assert(MI.hasOneMemOperand() && "Expected IRTranslator to set MemOp!");
8832 B.buildLoad(MI.getOperand(0), MI.getOperand(2), **MI.memoperands_begin());
8833 MI.eraseFromParent();
8834 return true;
8835 case Intrinsic::amdgcn_cooperative_atomic_store_32x4B:
8836 case Intrinsic::amdgcn_cooperative_atomic_store_16x8B:
8837 case Intrinsic::amdgcn_cooperative_atomic_store_8x16B:
8838 assert(MI.hasOneMemOperand() && "Expected IRTranslator to set MemOp!");
8839 B.buildStore(MI.getOperand(2), MI.getOperand(1), **MI.memoperands_begin());
8840 MI.eraseFromParent();
8841 return true;
8842 case Intrinsic::amdgcn_av_load_b128:
8843 case Intrinsic::amdgcn_av_store_b128: {
8844 assert(MI.hasOneMemOperand() && "Expected IRTranslator to set MemOp!");
8845 if (IntrID == Intrinsic::amdgcn_av_load_b128)
8846 B.buildLoad(MI.getOperand(0), MI.getOperand(2), **MI.memoperands_begin());
8847 else
8848 B.buildStore(MI.getOperand(2), MI.getOperand(1),
8849 **MI.memoperands_begin());
8850 MI.eraseFromParent();
8851 return true;
8852 }
8853 case Intrinsic::amdgcn_flat_load_monitor_b32:
8854 case Intrinsic::amdgcn_flat_load_monitor_b64:
8855 case Intrinsic::amdgcn_flat_load_monitor_b128:
8856 assert(MI.hasOneMemOperand() && "Expected IRTranslator to set MemOp!");
8857 B.buildInstr(AMDGPU::G_AMDGPU_FLAT_LOAD_MONITOR)
8858 .add(MI.getOperand(0))
8859 .add(MI.getOperand(2))
8860 .addMemOperand(*MI.memoperands_begin());
8861 MI.eraseFromParent();
8862 return true;
8863 case Intrinsic::amdgcn_global_load_monitor_b32:
8864 case Intrinsic::amdgcn_global_load_monitor_b64:
8865 case Intrinsic::amdgcn_global_load_monitor_b128:
8866 assert(MI.hasOneMemOperand() && "Expected IRTranslator to set MemOp!");
8867 B.buildInstr(AMDGPU::G_AMDGPU_GLOBAL_LOAD_MONITOR)
8868 .add(MI.getOperand(0))
8869 .add(MI.getOperand(2))
8870 .addMemOperand(*MI.memoperands_begin());
8871 MI.eraseFromParent();
8872 return true;
8873 default: {
8874 if (const AMDGPU::ImageDimIntrinsicInfo *ImageDimIntr =
8876 return legalizeImageIntrinsic(MI, B, Helper.Observer, ImageDimIntr);
8877 return true;
8878 }
8879 }
8880
8881 return true;
8882}
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 & setOperandDead(unsigned OpIdx) const
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addGlobalAddress(const GlobalValue *GV, int64_t Offset=0, unsigned TargetFlags=0) const
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
Representation of each machine instruction.
const MachineOperand & getOperand(unsigned i) const
A description of a memory reference used in the backend.
LocationSize getSize() const
Return the size in bytes of the memory reference.
LLT getMemoryType() const
Return the memory type of the memory reference.
@ MODereferenceable
The memory access is dereferenceable (i.e., doesn't trap).
@ MOLoad
The memory access reads data.
@ MOInvariant
The memory access always returns the same value (or traps).
LLVM_ABI Align getAlign() const
Return the minimum known alignment in bytes of the actual memory reference.
MachineOperand class - Representation of each machine instruction operand.
MachineBasicBlock * getMBB() const
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
void setMBB(MachineBasicBlock *MBB)
static MachineOperand CreateImm(int64_t Val)
Register getReg() const
getReg - Returns the register number.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI 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:149
MutableArrayRef(T &OneElt) -> MutableArrayRef< T >
constexpr T divideCeil(U Numerator, V Denominator)
Returns the integer ceil(Numerator / Denominator).
Definition MathExtras.h:389
To bit_cast(const From &from) noexcept
Definition bit.h:90
@ Mul
Product of integers.
@ FMul
Product of floats.
@ Sub
Subtraction of integers.
@ Add
Sum of integers.
@ Fast
Assign the register banks as fast as possible (default).
DWARFExpression::Operation Op
ArrayRef(const T &OneElt) -> ArrayRef< T >
constexpr unsigned BitWidth
LLVM_ABI void eraseInstr(MachineInstr &MI, MachineRegisterInfo &MRI, LostDebugLocObserver *LocObserver=nullptr)
Definition Utils.cpp: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:206
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Next
Definition InstrProf.h:147
unsigned Log2(Align A)
Returns the log2 of the alignment.
Definition Alignment.h:202
T bit_floor(T Value)
Returns the largest integral power of two no greater than Value if Value is nonzero.
Definition bit.h:347
constexpr uint64_t NextPowerOf2(uint64_t A)
Returns the next power of two (in 64-bits) that is strictly greater than A.
Definition MathExtras.h:368
MCRegisterClass TargetRegisterClass
Definition FastISel.h:58
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition BitVector.h: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:82
MCRegister getRegister() const
static ArgDescriptor createRegister(Register Reg, unsigned Mask=~0u)
DenormalModeKind Input
Denormal treatment kind for floating point instruction inputs in the default floating-point environme...
@ PreserveSign
The sign of a flushed-to-zero number is preserved in the sign of 0.
@ Dynamic
Denormals have unknown treatment.
static constexpr DenormalMode getPreserveSign()
static constexpr DenormalMode getIEEE()
bool isZero() const
Returns true if value is all zero.
Definition KnownBits.h:78
The LegalityQuery object bundles together all the information that's needed to decide whether a given...
ArrayRef< MemDesc > MMODescrs
Operations which require memory can use this to place requirements on the memory type for each MMO.
ArrayRef< LLT > Types
Matching combinators.
This class contains a discriminated union of information about pointers in memory operands,...
MachinePointerInfo getWithOffset(int64_t O) const
static LLVM_ABI MachinePointerInfo getGOT(MachineFunction &MF)
Return a MachinePointerInfo record that refers to a GOT entry.
DenormalMode FP64FP16Denormals
If this is set, neither input or output denormals are flushed for both f64 and f16/v2f16 instructions...
bool IEEE
Floating point opcodes that support exception flag gathering quiet and propagate signaling NaN inputs...
DenormalMode FP32Denormals
If this is set, neither input or output denormals are flushed for most f32 instructions.