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