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