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