LLVM 24.0.0git
AMDGPUInstCombineIntrinsic.cpp
Go to the documentation of this file.
1//===- AMDGPInstCombineIntrinsic.cpp - AMDGPU specific InstCombine pass ---===//
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//
9// \file
10// This file implements a TargetTransformInfo analysis pass specific to the
11// AMDGPU target machine. It uses the target's detailed information to provide
12// more precise answers to certain TTI queries, while letting the target
13// independent and default TTI implementations handle the rest.
14//
15//===----------------------------------------------------------------------===//
16
17#include "AMDGPUInstrInfo.h"
19#include "GCNSubtarget.h"
20#include "SIDefines.h"
22#include "llvm/ADT/STLExtras.h"
25#include "llvm/IR/Constants.h"
26#include "llvm/IR/Dominators.h"
27#include "llvm/IR/IntrinsicsAMDGPU.h"
30#include <optional>
31
32using namespace llvm;
33using namespace llvm::PatternMatch;
34
35#define DEBUG_TYPE "AMDGPUtti"
36
37namespace {
38
39struct AMDGPUImageDMaskIntrinsic {
40 unsigned Intr;
41};
42
43#define GET_AMDGPUImageDMaskIntrinsicTable_IMPL
44#include "AMDGPUGenSearchableTables.inc"
45
46} // end anonymous namespace
47
48// Constant fold llvm.amdgcn.fmed3 intrinsics for standard inputs.
49//
50// A single NaN input is folded to minnum, so we rely on that folding for
51// handling NaNs.
52static APFloat fmed3AMDGCN(const APFloat &Src0, const APFloat &Src1,
53 const APFloat &Src2) {
54 assert(!Src0.isNaN() && !Src1.isNaN() && !Src2.isNaN() &&
55 "nans handled separately");
56 APFloat Max3 = maxnum(maxnum(Src0, Src1), Src2);
57
58 if (Max3.bitwiseIsEqual(Src0))
59 return maxnum(Src1, Src2);
60
61 if (Max3.bitwiseIsEqual(Src1))
62 return maxnum(Src0, Src2);
63
64 return maxnum(Src0, Src1);
65}
66
67// Check if a value can be converted to a 16-bit value without losing precision.
68// The value is expected to be either a float (IsFloat = true) or an unsigned
69// integer (IsFloat = false). When AllowI16SExt is set, a sext from i16 is also
70// accepted: for unsigned addresses sext and zext only differ for a negative
71// i16, which is out of bounds anyway (see caller).
72static bool canSafelyConvertTo16Bit(Value &V, bool IsFloat,
73 bool AllowI16SExt = false) {
74 Type *VTy = V.getType();
75 if (VTy->isHalfTy() || VTy->isIntegerTy(16)) {
76 // The value is already 16-bit, so we don't want to convert to 16-bit again!
77 return false;
78 }
79 if (IsFloat) {
80 if (ConstantFP *ConstFloat = dyn_cast<ConstantFP>(&V)) {
81 // We need to check that if we cast the index down to a half, we do not
82 // lose precision.
83 APFloat FloatValue(ConstFloat->getValueAPF());
84 bool LosesInfo = true;
86 &LosesInfo);
87 return !LosesInfo;
88 }
89 } else {
90 if (ConstantInt *ConstInt = dyn_cast<ConstantInt>(&V)) {
91 // We need to check that if we cast the index down to an i16, we do not
92 // lose precision.
93 APInt IntValue(ConstInt->getValue());
94 return IntValue.getActiveBits() <= 16;
95 }
96 }
97
98 // Coordinates may arrive as extractelement((s|z|fp)ext Vec), Idx. The
99 // widening cast has one use per lane, so it is never sunk into the extract;
100 // strip the extract here so the cast check below is common to scalar and
101 // vector coords.
102 Value *CastCandidate;
103 if (!match(&V, m_ExtractElt(m_Value(CastCandidate), m_Value())))
104 CastCandidate = &V;
105
106 Value *CastSrc;
107 bool IsExt = IsFloat ? match(CastCandidate, m_FPExt(m_Value(CastSrc)))
108 : match(CastCandidate, m_ZExt(m_Value(CastSrc)));
109 if (!IsExt && !IsFloat && AllowI16SExt)
110 IsExt = match(CastCandidate, m_SExt(m_Value(CastSrc)));
111 if (IsExt) {
112 Type *CastSrcTy = CastSrc->getType()->getScalarType();
113 if (CastSrcTy->isHalfTy() || CastSrcTy->isIntegerTy(16))
114 return true;
115 }
116
117 return false;
118}
119
120// Convert a value to 16-bit.
122 Type *VTy = V.getType();
124 return cast<Instruction>(&V)->getOperand(0);
125 // Vector form: extractelement((s|z|fp)ext Vec), Idx -> extractelement(Vec,
126 // Idx), taking the narrow lane directly so the widening cast can be removed.
127 Instruction *VecCast;
128 Value *Idx;
129 if (match(&V, m_ExtractElt(m_Instruction(VecCast), m_Value(Idx))) &&
131 return Builder.CreateExtractElement(VecCast->getOperand(0), Idx);
132 if (VTy->isIntegerTy())
133 return Builder.CreateIntCast(&V, Type::getInt16Ty(V.getContext()), false);
134 if (VTy->isFloatingPointTy())
135 return Builder.CreateFPCast(&V, Type::getHalfTy(V.getContext()));
136
137 llvm_unreachable("Should never be called!");
138}
139
140/// Applies Func(OldIntr.Args, OldIntr.ArgTys), creates intrinsic call with
141/// modified arguments (based on OldIntr) and replaces InstToReplace with
142/// this newly created intrinsic call.
143static std::optional<Instruction *> modifyIntrinsicCall(
144 IntrinsicInst &OldIntr, Instruction &InstToReplace, unsigned NewIntr,
145 InstCombiner &IC,
146 std::function<void(SmallVectorImpl<Value *> &, SmallVectorImpl<Type *> &)>
147 Func) {
148 SmallVector<Type *, 4> OverloadTys;
149 if (!Intrinsic::isSignatureValid(OldIntr.getCalledFunction(), OverloadTys))
150 return std::nullopt;
151
152 SmallVector<Value *, 8> Args(OldIntr.args());
153
154 // Modify arguments and types
155 Func(Args, OverloadTys);
156
157 CallInst *NewCall =
158 IC.Builder.CreateIntrinsicWithoutFolding(NewIntr, OverloadTys, Args);
159 NewCall->takeName(&OldIntr);
160 NewCall->copyMetadata(OldIntr);
161 if (isa<FPMathOperator>(NewCall))
162 NewCall->copyFastMathFlags(&OldIntr);
163 // Copy attributes
164 AttributeList OldAttrList = OldIntr.getAttributes();
165 NewCall->setAttributes(OldAttrList);
166
167 // Erase and replace uses
168 if (!InstToReplace.getType()->isVoidTy())
169 IC.replaceInstUsesWith(InstToReplace, NewCall);
170
171 bool RemoveOldIntr = &OldIntr != &InstToReplace;
172
173 auto *RetValue = IC.eraseInstFromFunction(InstToReplace);
174 if (RemoveOldIntr)
175 IC.eraseInstFromFunction(OldIntr);
176
177 return RetValue;
178}
179
180static std::optional<Instruction *>
182 const AMDGPU::ImageDimIntrinsicInfo *ImageDimIntr,
184 const AMDGPU::MIMGBaseOpcodeInfo *BaseOpcode =
186
187 // Optimize _L to _LZ when _L is zero
188 if (const auto *LZMappingInfo =
190 if (auto *ConstantLod =
191 dyn_cast<ConstantFP>(II.getOperand(ImageDimIntr->LodIndex))) {
192 if (ConstantLod->isZero() || ConstantLod->isNegative()) {
193 const AMDGPU::ImageDimIntrinsicInfo *NewImageDimIntr =
195 ImageDimIntr->Dim);
196 return modifyIntrinsicCall(
197 II, II, NewImageDimIntr->Intr, IC, [&](auto &Args, auto &ArgTys) {
198 Args.erase(Args.begin() + ImageDimIntr->LodIndex);
199 });
200 }
201 }
202 }
203
204 // Optimize _mip away, when 'lod' is zero
205 if (const auto *MIPMappingInfo =
207 if (auto *ConstantMip =
208 dyn_cast<ConstantInt>(II.getOperand(ImageDimIntr->MipIndex))) {
209 if (ConstantMip->isZero()) {
210 const AMDGPU::ImageDimIntrinsicInfo *NewImageDimIntr =
211 AMDGPU::getImageDimIntrinsicByBaseOpcode(MIPMappingInfo->NONMIP,
212 ImageDimIntr->Dim);
213 return modifyIntrinsicCall(
214 II, II, NewImageDimIntr->Intr, IC, [&](auto &Args, auto &ArgTys) {
215 Args.erase(Args.begin() + ImageDimIntr->MipIndex);
216 });
217 }
218 }
219 }
220
221 // Optimize _bias away when 'bias' is zero
222 if (const auto *BiasMappingInfo =
224 if (auto *ConstantBias =
225 dyn_cast<ConstantFP>(II.getOperand(ImageDimIntr->BiasIndex))) {
226 if (ConstantBias->isZero()) {
227 const AMDGPU::ImageDimIntrinsicInfo *NewImageDimIntr =
228 AMDGPU::getImageDimIntrinsicByBaseOpcode(BiasMappingInfo->NoBias,
229 ImageDimIntr->Dim);
230 return modifyIntrinsicCall(
231 II, II, NewImageDimIntr->Intr, IC, [&](auto &Args, auto &ArgTys) {
232 Args.erase(Args.begin() + ImageDimIntr->BiasIndex);
233 ArgTys.erase(ArgTys.begin() + ImageDimIntr->BiasTyArg);
234 });
235 }
236 }
237 }
238
239 // Optimize _offset away when 'offset' is zero
240 if (const auto *OffsetMappingInfo =
242 if (auto *ConstantOffset =
243 dyn_cast<ConstantInt>(II.getOperand(ImageDimIntr->OffsetIndex))) {
244 if (ConstantOffset->isZero()) {
245 const AMDGPU::ImageDimIntrinsicInfo *NewImageDimIntr =
247 OffsetMappingInfo->NoOffset, ImageDimIntr->Dim);
248 return modifyIntrinsicCall(
249 II, II, NewImageDimIntr->Intr, IC, [&](auto &Args, auto &ArgTys) {
250 Args.erase(Args.begin() + ImageDimIntr->OffsetIndex);
251 });
252 }
253 }
254 }
255
256 // Optimize the arrayed dim away when the array slice is zero, since slice 0
257 // is the base layer. Restricted to non-atomic, non-sampled image loads and
258 // stores for now.
259 const AMDGPU::MIMGDimInfo *DimInfo =
260 AMDGPU::getMIMGDimInfo(ImageDimIntr->Dim);
261 if (!BaseOpcode->Atomic && !BaseOpcode->Sampler && BaseOpcode->Coordinates &&
262 DimInfo->NonArrayDim != ImageDimIntr->Dim) {
263 // Address is [coords..., slice, (fragid)] plus an optional mip operand.
264 // The slice is the last coordinate, so index it from CoordStart.
265 unsigned SliceIndex = ImageDimIntr->CoordStart + DimInfo->NumCoords - 1 -
266 (DimInfo->MSAA ? 1 : 0);
267 auto *ConstantSlice = dyn_cast<ConstantInt>(II.getOperand(SliceIndex));
268 if (ConstantSlice && ConstantSlice->isZero()) {
269 if (const AMDGPU::ImageDimIntrinsicInfo *NewImageDimIntr =
271 DimInfo->NonArrayDim)) {
272 return modifyIntrinsicCall(II, II, NewImageDimIntr->Intr, IC,
273 [&](auto &Args, auto &ArgTys) {
274 Args.erase(Args.begin() + SliceIndex);
275 });
276 }
277 }
278 }
279
280 // Try to use D16
281 if (ST->hasD16Images()) {
282 if (BaseOpcode->HasD16) {
283
284 // If the only use of image intrinsic is a fptrunc (with conversion to
285 // half) then both fptrunc and image intrinsic will be replaced with image
286 // intrinsic with D16 flag.
287 if (II.hasOneUse()) {
288 Instruction *User = II.user_back();
289
290 if (User->getOpcode() == Instruction::FPTrunc &&
292
293 return modifyIntrinsicCall(II, *User, ImageDimIntr->Intr, IC,
294 [&](auto &Args, auto &ArgTys) {
295 // Change return type of image intrinsic.
296 // Set it to return type of fptrunc.
297 ArgTys[0] = User->getType();
298 });
299 }
300 }
301
302 // Only perform D16 folding if every user of the image sample is
303 // an ExtractElementInst immediately followed by an FPTrunc to half.
305 ExtractTruncPairs;
306 bool AllHalfExtracts = true;
307
308 for (User *U : II.users()) {
309 auto *Ext = dyn_cast<ExtractElementInst>(U);
310 if (!Ext || !Ext->hasOneUse()) {
311 AllHalfExtracts = false;
312 break;
313 }
314
315 auto *Tr = dyn_cast<FPTruncInst>(*Ext->user_begin());
316 if (!Tr || !Tr->getType()->isHalfTy()) {
317 AllHalfExtracts = false;
318 break;
319 }
320
321 ExtractTruncPairs.emplace_back(Ext, Tr);
322 }
323
324 if (!ExtractTruncPairs.empty() && AllHalfExtracts) {
325 auto *VecTy = cast<VectorType>(II.getType());
326 Type *HalfVecTy =
327 VecTy->getWithNewType(Type::getHalfTy(II.getContext()));
328
329 // Obtain the original image sample intrinsic's signature
330 // and replace its return type with the half-vector for D16 folding
331 SmallVector<Type *, 8> OverloadTys;
332 if (!Intrinsic::isSignatureValid(II.getCalledFunction(), OverloadTys))
333 return std::nullopt;
334
335 OverloadTys[0] = HalfVecTy;
336 Module *M = II.getModule();
338 M, ImageDimIntr->Intr, OverloadTys);
339
340 II.mutateType(HalfVecTy);
341 II.setCalledFunction(HalfDecl);
342
343 IRBuilder<> Builder(*M);
344 for (auto &[Ext, Tr] : ExtractTruncPairs) {
345 Value *Idx = Ext->getIndexOperand();
346
347 Builder.SetInsertPoint(Tr);
348
349 Value *HalfExtract = Builder.CreateExtractElement(&II, Idx);
350 HalfExtract->takeName(Tr);
351
352 Tr->replaceAllUsesWith(HalfExtract);
353 }
354
355 for (auto &[Ext, Tr] : ExtractTruncPairs) {
356 IC.eraseInstFromFunction(*Tr);
357 IC.eraseInstFromFunction(*Ext);
358 }
359
360 return &II;
361 }
362 }
363 }
364
365 // Try to use A16 or G16
366 if (!ST->hasA16() && !ST->hasG16())
367 return std::nullopt;
368
369 // Address is interpreted as float if the instruction has a sampler or as
370 // unsigned int if there is no sampler.
371 bool HasSampler = BaseOpcode->Sampler;
372 bool FloatCoord = false;
373 // true means derivatives can be converted to 16 bit, coordinates not
374 bool OnlyDerivatives = false;
375
376 // Sampler-less addresses are unsigned, so a sext from i16 folds to a16 like a
377 // zext: they only disagree for a negative i16 (>= 0x8000), which is out of
378 // bounds while the max image dimension is <= 0x8000.
379 bool AllowI16SExt = !HasSampler;
380
381 for (unsigned OperandIndex = ImageDimIntr->GradientStart;
382 OperandIndex < ImageDimIntr->VAddrEnd; OperandIndex++) {
383 Value *Coord = II.getOperand(OperandIndex);
384 // If the values are not derived from 16-bit values, we cannot optimize.
385 if (!canSafelyConvertTo16Bit(*Coord, HasSampler, AllowI16SExt)) {
386 if (OperandIndex < ImageDimIntr->CoordStart ||
387 ImageDimIntr->GradientStart == ImageDimIntr->CoordStart) {
388 return std::nullopt;
389 }
390 // All gradients can be converted, so convert only them
391 OnlyDerivatives = true;
392 break;
393 }
394
395 assert(OperandIndex == ImageDimIntr->GradientStart ||
396 FloatCoord == Coord->getType()->isFloatingPointTy());
397 FloatCoord = Coord->getType()->isFloatingPointTy();
398 }
399
400 if (!OnlyDerivatives && !ST->hasA16())
401 OnlyDerivatives = true; // Only supports G16
402
403 // Check if there is a bias parameter and if it can be converted to f16
404 if (!OnlyDerivatives && ImageDimIntr->NumBiasArgs != 0) {
405 Value *Bias = II.getOperand(ImageDimIntr->BiasIndex);
406 assert(HasSampler &&
407 "Only image instructions with a sampler can have a bias");
408 if (!canSafelyConvertTo16Bit(*Bias, HasSampler))
409 OnlyDerivatives = true;
410 }
411
412 if (OnlyDerivatives && (!ST->hasG16() || ImageDimIntr->GradientStart ==
413 ImageDimIntr->CoordStart))
414 return std::nullopt;
415
416 Type *CoordType = FloatCoord ? Type::getHalfTy(II.getContext())
417 : Type::getInt16Ty(II.getContext());
418
419 return modifyIntrinsicCall(
420 II, II, II.getIntrinsicID(), IC, [&](auto &Args, auto &ArgTys) {
421 ArgTys[ImageDimIntr->GradientTyArg] = CoordType;
422 if (!OnlyDerivatives) {
423 ArgTys[ImageDimIntr->CoordTyArg] = CoordType;
424
425 // Change the bias type
426 if (ImageDimIntr->NumBiasArgs != 0)
427 ArgTys[ImageDimIntr->BiasTyArg] = Type::getHalfTy(II.getContext());
428 }
429
430 unsigned EndIndex =
431 OnlyDerivatives ? ImageDimIntr->CoordStart : ImageDimIntr->VAddrEnd;
432 for (unsigned OperandIndex = ImageDimIntr->GradientStart;
433 OperandIndex < EndIndex; OperandIndex++) {
434 Args[OperandIndex] =
435 convertTo16Bit(*II.getOperand(OperandIndex), IC.Builder);
436 }
437
438 // Convert the bias
439 if (!OnlyDerivatives && ImageDimIntr->NumBiasArgs != 0) {
440 Value *Bias = II.getOperand(ImageDimIntr->BiasIndex);
441 Args[ImageDimIntr->BiasIndex] = convertTo16Bit(*Bias, IC.Builder);
442 }
443 });
444}
445
447 const Value *Op0, const Value *Op1,
448 InstCombiner &IC) const {
449 // The legacy behaviour is that multiplying +/-0.0 by anything, even NaN or
450 // infinity, gives +0.0. If we can prove we don't have one of the special
451 // cases then we can use a normal multiply instead.
453 KnownFPClass Known0 =
455 DenormalMode Mode = I.getFunction()->getDenormalMode(APFloat::IEEEsingle());
456
457 // Bail early if Op0 may be zero and nsz is not set -- Op1 cannot help.
458 if (!Known0.isKnownNeverLogicalZero(Mode) && !I.hasNoSignedZeros())
459 return false;
460
461 KnownFPClass Known1 =
463
464 // Simplify if both operands are known non-zero.
465 if (Known0.isKnownNeverLogicalZero(Mode) &&
466 Known1.isKnownNeverLogicalZero(Mode))
467 return true;
468
469 // With nsz, two additional cases allow simplification:
470 // 1. One operand is not zero or infinity or NaN:
471 // Op0 NeverLogicalZero && NeverInfOrNaN, or symmetric for Op1.
472 // 2. Neither operand is infinity or NaN:
473 // Op0 NeverInfOrNaN && Op1 NeverInfOrNaN.
474 // The following condition captures both cases.
475 if (I.hasNoSignedZeros() &&
476 (Known0.isKnownNeverLogicalZero(Mode) || Known1.isKnownNeverInfOrNaN()) &&
477 (Known1.isKnownNeverLogicalZero(Mode) || Known0.isKnownNeverInfOrNaN()))
478 return true;
479
480 return false;
481}
482
483/// Match an fpext from half to float, or a constant we can convert.
485 Value *Src = nullptr;
486 ConstantFP *CFP = nullptr;
487 if (match(Arg, m_OneUse(m_FPExt(m_Value(Src))))) {
488 if (Src->getType()->isHalfTy())
489 return Src;
490 } else if (match(Arg, m_ConstantFP(CFP))) {
491 bool LosesInfo;
492 APFloat Val(CFP->getValueAPF());
494 if (!LosesInfo)
495 return ConstantFP::get(Type::getHalfTy(Arg->getContext()), Val);
496 }
497 return nullptr;
498}
499
500// Trim all zero components from the end of the vector \p UseV and return
501// an appropriate bitset with known elements.
503 Instruction *I) {
504 auto *VTy = cast<FixedVectorType>(UseV->getType());
505 unsigned VWidth = VTy->getNumElements();
506 APInt DemandedElts = APInt::getAllOnes(VWidth);
507
508 for (int i = VWidth - 1; i > 0; --i) {
509 auto *Elt = findScalarElement(UseV, i);
510 if (!Elt)
511 break;
512
513 if (auto *ConstElt = dyn_cast<Constant>(Elt)) {
514 if (!ConstElt->isNullValue() && !isa<UndefValue>(Elt))
515 break;
516 } else {
517 break;
518 }
519
520 DemandedElts.clearBit(i);
521 }
522
523 return DemandedElts;
524}
525
526// Trim elements of the end of the vector \p V, if they are
527// equal to the first element of the vector.
529 auto *VTy = cast<FixedVectorType>(V->getType());
530 unsigned VWidth = VTy->getNumElements();
531 APInt DemandedElts = APInt::getAllOnes(VWidth);
532 Value *FirstComponent = findScalarElement(V, 0);
533
534 SmallVector<int> ShuffleMask;
535 if (auto *SVI = dyn_cast<ShuffleVectorInst>(V))
536 SVI->getShuffleMask(ShuffleMask);
537
538 for (int I = VWidth - 1; I > 0; --I) {
539 if (ShuffleMask.empty()) {
540 auto *Elt = findScalarElement(V, I);
541 if (!Elt || (Elt != FirstComponent && !isa<UndefValue>(Elt)))
542 break;
543 } else {
544 // Detect identical elements in the shufflevector result, even though
545 // findScalarElement cannot tell us what that element is.
546 if (ShuffleMask[I] != ShuffleMask[0] && ShuffleMask[I] != PoisonMaskElem)
547 break;
548 }
549 DemandedElts.clearBit(I);
550 }
551
552 return DemandedElts;
553}
554
557 APInt DemandedElts,
558 int DMaskIdx = -1,
559 bool IsLoad = true);
560
561/// Return true if it's legal to contract llvm.amdgcn.rcp(llvm.sqrt)
562static bool canContractSqrtToRsq(const FPMathOperator *SqrtOp) {
563 return (SqrtOp->getType()->isFloatTy() &&
564 (SqrtOp->hasApproxFunc() || SqrtOp->getFPAccuracy() >= 1.0f)) ||
565 SqrtOp->getType()->isHalfTy();
566}
567
568/// Simplify a lane index operand (e.g. llvm.amdgcn.readlane src1).
569///
570/// The instruction only reads the low 5 bits for wave32, and 6 bits for wave64.
573 unsigned LaneArgIdx) const {
574 unsigned MaskBits = ST->getWavefrontSizeLog2();
575 APInt DemandedMask(32, maskTrailingOnes<unsigned>(MaskBits));
576
577 KnownBits Known(32);
578 if (IC.SimplifyDemandedBits(&II, LaneArgIdx, DemandedMask, Known))
579 return true;
580
581 if (!Known.isConstant())
582 return false;
583
584 // Out of bounds indexes may appear in wave64 code compiled for wave32.
585 // Unlike the DAG version, SimplifyDemandedBits does not change constants, so
586 // manually fix it up.
587
588 Value *LaneArg = II.getArgOperand(LaneArgIdx);
589 Constant *MaskedConst =
590 ConstantInt::get(LaneArg->getType(), Known.getConstant() & DemandedMask);
591 if (MaskedConst != LaneArg) {
592 II.getOperandUse(LaneArgIdx).set(MaskedConst);
593 return true;
594 }
595
596 return false;
597}
598
599/// Simplify the f32 scale operand of a V_CVT_SCALEF32_* conversion, of which
600/// only the exponent field is read.
602 unsigned ScaleArgIdx) {
603 Value *Scale = II.getArgOperand(ScaleArgIdx);
604 Value *StrippedSign = InstCombiner::stripSignOnlyFPOps(Scale);
605 if (StrippedSign != Scale) {
606 IC.replaceOperand(II, ScaleArgIdx, StrippedSign);
607 return true;
608 }
609
610 auto *BC = dyn_cast<BitCastInst>(Scale);
611 if (!BC || !BC->hasOneUse() || !BC->getSrcTy()->isIntegerTy(32))
612 return false;
613
614 KnownBits Known(32);
615 return IC.SimplifyDemandedBits(
617}
618
620 Function &NewCallee, ArrayRef<Value *> Ops) {
622 Old.getOperandBundlesAsDefs(OpBundles);
623
624 CallInst *NewCall = B.CreateCall(&NewCallee, Ops, OpBundles);
625 NewCall->takeName(&Old);
626 return NewCall;
627}
628
629// Return true for sequences of instructions that effectively assign
630// each lane to its thread ID
631static bool isThreadID(const GCNSubtarget &ST, Value *V) {
632 // Case 1:
633 // wave32: mbcnt_lo(-1, 0)
634 // wave64: mbcnt_hi(-1, mbcnt_lo(-1, 0))
640 if (ST.isWave32() && match(V, W32Pred))
641 return true;
642 if (ST.isWave64() && match(V, W64Pred))
643 return true;
644
645 // Case 2:
646 // workitem.id.x & (wavefront size - 1), or bare workitem.id.x when the
647 // workgroup is one wave long or less.
648 auto *I = dyn_cast<Instruction>(V);
649 if (!I || !ST.isWaveSizeKnown())
650 return false;
651
652 const Function &F = *I->getFunction();
653 if (!ST.hasWavefrontsEvenlySplittingXDim(F, /*RequiresUniformYZ=*/true))
654 return false;
655
656 unsigned WaveSize = ST.getWavefrontSize();
658 if (match(V, m_c_And(TidX, m_SpecificInt(WaveSize - 1))))
659 return true;
660
661 return match(V, TidX) && ST.getMaxWorkitemID(F, 0) < WaveSize;
662}
663
666 IntrinsicInst &II) const {
667 const auto IID = II.getIntrinsicID();
668 assert(IID == Intrinsic::amdgcn_readlane ||
669 IID == Intrinsic::amdgcn_readfirstlane ||
670 IID == Intrinsic::amdgcn_permlane64);
671
672 Instruction *OpInst = dyn_cast<Instruction>(II.getOperand(0));
673
674 // Only do this if both instructions are in the same block
675 // (so the exec mask won't change) and the readlane is the only user of its
676 // operand.
677 if (!OpInst || !OpInst->hasOneUser() || OpInst->getParent() != II.getParent())
678 return nullptr;
679
680 const bool IsReadLane = (IID == Intrinsic::amdgcn_readlane);
681
682 // If this is a readlane, check that the second operand is a constant, or is
683 // defined before OpInst so we know it's safe to move this intrinsic higher.
684 Value *LaneID = nullptr;
685 if (IsReadLane) {
686 LaneID = II.getOperand(1);
687
688 // readlane take an extra operand for the lane ID, so we must check if that
689 // LaneID value can be used at the point where we want to move the
690 // intrinsic.
691 if (auto *LaneIDInst = dyn_cast<Instruction>(LaneID)) {
692 if (!IC.getDominatorTree().dominates(LaneIDInst, OpInst))
693 return nullptr;
694 }
695 }
696
697 // Hoist the intrinsic (II) through OpInst.
698 //
699 // (II (OpInst x)) -> (OpInst (II x))
700 const auto DoIt = [&](unsigned OpIdx,
701 Function *NewIntrinsic) -> Instruction * {
702 SmallVector<Value *, 2> Ops{OpInst->getOperand(OpIdx)};
703 if (IsReadLane)
704 Ops.push_back(LaneID);
705
706 // Rewrite the intrinsic call.
707 CallInst *NewII = rewriteCall(IC.Builder, II, *NewIntrinsic, Ops);
708
709 // Rewrite OpInst so it takes the result of the intrinsic now.
710 Instruction &NewOp = *OpInst->clone();
711 NewOp.setOperand(OpIdx, NewII);
712 return &NewOp;
713 };
714
715 // TODO(?): Should we do more with permlane64?
716 if (IID == Intrinsic::amdgcn_permlane64 && !isa<BitCastInst>(OpInst))
717 return nullptr;
718
719 if (isa<UnaryOperator>(OpInst))
720 return DoIt(0, II.getCalledFunction());
721
722 if (isa<CastInst>(OpInst)) {
723 Value *Src = OpInst->getOperand(0);
724 Type *SrcTy = Src->getType();
725 if (!isTypeLegal(SrcTy))
726 return nullptr;
727
728 Function *Remangled =
729 Intrinsic::getOrInsertDeclaration(II.getModule(), IID, {SrcTy});
730 return DoIt(0, Remangled);
731 }
732
733 // We can also hoist through binary operators if the other operand is uniform.
734 if (isa<BinaryOperator>(OpInst)) {
735 // FIXME: If we had access to UniformityInfo here we could just check
736 // if the operand is uniform.
738 return DoIt(1, II.getCalledFunction());
740 return DoIt(0, II.getCalledFunction());
741 }
742
743 return nullptr;
744}
745
746/// Evaluate V as a function of the lane ID and return its value on Lane, or
747/// std::nullopt if V is not a closed-form expression of the lane ID.
748static std::optional<uint64_t> evalLaneExpr(Value *V, unsigned Lane,
749 const GCNSubtarget &ST,
750 const DataLayout &DL,
751 unsigned Depth = 0) {
753 return std::nullopt;
754
755 // Poison/undef in the index expression: bail and let InstCombine fold the
756 // intrinsic the usual way.
757 if (isa<UndefValue>(V))
758 return std::nullopt;
759
760 if (const ConstantInt *CI = dyn_cast<ConstantInt>(V))
761 return CI->getZExtValue();
762
763 if (isThreadID(ST, V))
764 return Lane;
765
767 if (!BO)
768 return std::nullopt;
769
770 std::optional<uint64_t> LHS =
771 evalLaneExpr(BO->getOperand(0), Lane, ST, DL, Depth + 1);
772 if (!LHS)
773 return std::nullopt;
774 std::optional<uint64_t> RHS =
775 evalLaneExpr(BO->getOperand(1), Lane, ST, DL, Depth + 1);
776 if (!RHS)
777 return std::nullopt;
778
779 Type *Ty = BO->getType();
780 Constant *Ops[] = {ConstantInt::get(Ty, *LHS), ConstantInt::get(Ty, *RHS)};
781 auto *CI =
783 return CI ? std::optional<uint64_t>(CI->getZExtValue()) : std::nullopt;
784}
785
786/// Build the per-lane shuffle map by evaluating Index for every lane in the
787/// wave. Returns false if any lane index is non-constant or out of range.
788static bool tryBuildShuffleMap(Value *Index, const GCNSubtarget &ST,
790 const DataLayout &DL) {
791 unsigned WaveSize = ST.getWavefrontSize();
792 Ids.resize(WaveSize);
793 for (unsigned Lane : seq(WaveSize)) {
794 std::optional<uint64_t> Val = evalLaneExpr(Index, Lane, ST, DL);
795 if (!Val || *Val >= WaveSize)
796 return false;
797 Ids[Lane] = static_cast<uint8_t>(*Val);
798 }
799 return true;
800}
801
802/// Lanes are partitioned into groups of Period; each group is a translated
803/// copy of the first: Ids[I] = Ids[I % Period] + (I & ~(Period - 1)).
804template <unsigned Period>
806 static_assert(isPowerOf2_32(Period), "Period must be a power of two");
807 for (size_t I = Period, E = Ids.size(); I < E; ++I)
808 if (Ids[I] != Ids[I % Period] + (I & ~(Period - 1)))
809 return false;
810 return true;
811}
812
813/// Match an N-lane row pattern: each lane in [0, N) reads from a source lane
814/// in the same N-lane row, and the pattern repeats periodically across rows.
815template <unsigned N> static bool isRowPattern(ArrayRef<uint8_t> Ids) {
816 for (unsigned I = 0; I < N; ++I)
817 if (Ids[I] >= N)
818 return false;
819 return hasPeriodicLayout<N>(Ids);
820}
821
822static constexpr auto isQuadPattern = isRowPattern<4>;
823static constexpr auto isHalfRowPattern = isRowPattern<8>;
824static constexpr auto isFullRowPattern = isRowPattern<16>;
825
826/// Match a 4-lane (quad) permutation, encoded as the v_mov_b32_dpp
827/// QUAD_PERM control word: bits[1:0]=Ids[0], [3:2]=Ids[1], [5:4]=Ids[2],
828/// [7:6]=Ids[3].
829static std::optional<unsigned> matchQuadPermPattern(ArrayRef<uint8_t> Ids) {
830 if (!isQuadPattern(Ids))
831 return std::nullopt;
832 return Ids[3] << 6 | Ids[2] << 4 | Ids[1] << 2 | Ids[0];
833}
834
835/// Match an N-lane reversal (mirror) pattern.
836template <unsigned N> static bool matchMirrorPattern(ArrayRef<uint8_t> Ids) {
837 if (!isRowPattern<N>(Ids))
838 return false;
839 for (unsigned J = 0; J < N; ++J)
840 if (Ids[J] != (N - 1) - J)
841 return false;
842 return true;
843}
844
847
848/// Match a 16-lane cyclic rotation; returns the rotation amount in [1, 15].
849static std::optional<unsigned> matchRowRotatePattern(ArrayRef<uint8_t> Ids) {
850 if (Ids[0] == 0 || !isFullRowPattern(Ids))
851 return std::nullopt;
852 for (unsigned J = 1; J < 16; ++J)
853 if (Ids[J] != (Ids[0] + J) % 16)
854 return std::nullopt;
855 return 16u - Ids[0];
856}
857
858/// Match a row-share pattern: all 16 lanes of each row read the same source
859/// lane. Returns the shared source lane index in [0, 16).
860static std::optional<unsigned> matchRowSharePattern(ArrayRef<uint8_t> Ids) {
861 if (!isFullRowPattern(Ids))
862 return std::nullopt;
863 if (!all_equal(Ids.take_front(16)))
864 return std::nullopt;
865 return Ids[0];
866}
867
868/// Match an XOR mask pattern within each 16-lane row: Ids[J] == Mask ^ J,
869/// with Mask in [1, 15].
870static std::optional<unsigned> matchRowXMaskPattern(ArrayRef<uint8_t> Ids) {
871 unsigned Mask = Ids[0];
872 if (Mask == 0 || !isFullRowPattern(Ids))
873 return std::nullopt;
874 for (unsigned J = 0; J < 16; ++J)
875 if (Ids[J] != (Mask ^ J))
876 return std::nullopt;
877 return Mask;
878}
879
880/// Match an 8-lane arbitrary permutation, encoded as the v_mov_b32_dpp8
881/// 24-bit selector (three bits per output lane).
882static std::optional<unsigned> matchHalfRowPermPattern(ArrayRef<uint8_t> Ids) {
883 if (!isHalfRowPattern(Ids))
884 return std::nullopt;
885 unsigned Selector = 0;
886 for (unsigned J = 0; J < 8; ++J)
887 Selector |= Ids[J] << (J * 3);
888 return Selector;
889}
890
891/// Pack a 16-lane permutation into a single 64-bit value: four bits per output
892/// lane, lane J in bits [J*4 + 3 : J*4]. The caller splits it into the low and
893/// high 32-bit selector operands of v_permlane16 / v_permlanex16.
895 uint64_t Sel = 0;
896 for (unsigned J = 0; J < 16; ++J)
897 Sel |= static_cast<uint64_t>(Ids[J] & 0xF) << (J * 4);
898 return Sel;
899}
900
901/// Match a half-wave swap: lane J reads from lane J ^ 32. Only meaningful on
902/// wave64 targets.
904 if (Ids.size() != 64)
905 return false;
906 for (unsigned J = 0; J < 64; ++J)
907 if (Ids[J] != (J ^ 32))
908 return false;
909 return true;
910}
911
912/// Match a cross-row permutation suitable for v_permlanex16: every lane in
913/// the low 16-lane half reads from the high half of its own row, and vice
914/// versa.
916 if (!hasPeriodicLayout<32>(Ids))
917 return false;
918 for (unsigned J = 0; J < 16; ++J) {
919 if (Ids[J] < 16 || Ids[J] >= 32)
920 return false;
921 if (Ids[J + 16] != Ids[J] - 16)
922 return false;
923 }
924 return true;
925}
926
927/// Match a DS_SWIZZLE bitmask-mode permutation:
928/// dst_lane = ((src_lane & AND) | OR) ^ XOR
929/// with each mask being five bits. Returns the encoded swizzle immediate.
930/// The hardware applies the formula independently within each 32-lane group,
931/// so on wave64 the high group must replicate the low one (translated by 32).
932static std::optional<unsigned>
934 if (!hasPeriodicLayout<32>(Ids))
935 return std::nullopt;
936
937 // The formula is per-bit: output bit B depends only on input bit B. Probe
938 // each bit with src=0 and src=(1<<B); if the output bit flipped, AND[B]=1
939 // and XOR[B] carries the constant offset; otherwise it is a constant bit
940 // encoded in OR (with AND[B]=0, XOR[B]=0).
941 unsigned AndMask = 0, OrMask = 0, XorMask = 0;
942 for (unsigned B = 0; B < 5; ++B) {
943 unsigned Bit0 = (Ids[0] >> B) & 1;
944 unsigned Bit1 = (Ids[1ull << B] >> B) & 1;
945 if (Bit0 != Bit1) {
946 AndMask |= 1u << B;
947 XorMask |= Bit0 << B;
948 } else {
949 OrMask |= Bit0 << B;
950 }
951 }
952
953 // The per-bit derivation assumes bit independence; verify the masks
954 // actually reproduce every lane in the 32-lane group.
955 for (unsigned I : seq(32u)) {
956 unsigned Expected = ((I & AndMask) | OrMask) ^ XorMask;
957 if (Ids[I] != Expected)
958 return std::nullopt;
959 }
960
965}
966
967/// Match a GFX9+ DS_SWIZZLE rotate-mode permutation: a cyclic left-rotation
968/// of all 32 lanes within each 32-lane group by a constant N in [0, 31],
969/// i.e. dst_lane = (src_lane + N) % 32. On wave64, hasPeriodicLayout<32>
970/// ensures both 32-lane groups rotate by the same amount.
971static std::optional<unsigned>
973 if (!hasPeriodicLayout<32>(Ids))
974 return std::nullopt;
975
976 // Determine the rotation amount from lane 0: every lane must read from
977 // lane (I + N) % 32 where N = Ids[0] and 0 <= N <= 31.
978 unsigned N = Ids[0];
979 if (N >= 32)
980 return std::nullopt;
981
982 for (unsigned I = 0; I < 32; ++I)
983 if (Ids[I] != (I + N) % 32)
984 return std::nullopt;
985
988}
989
990/// Emit v_mov_b32_dpp with the given control word, row/bank masks 0xF, and
991/// bound_ctrl=1 so out-of-bounds lanes are well-defined and the DPP mov can
992/// be folded into a consuming VALU op by GCNDPPCombine.
993static Value *createUpdateDpp(IRBuilderBase &B, Value *Val, unsigned Ctrl) {
994 Type *Ty = Val->getType();
995 return B.CreateIntrinsic(Intrinsic::amdgcn_update_dpp, {Ty},
996 {PoisonValue::get(Ty), Val, B.getInt32(Ctrl),
997 B.getInt32(0xF), B.getInt32(0xF), B.getTrue()});
998}
999
1000/// Emit v_mov_b32_dpp8 with the given 24-bit lane selector.
1001static Value *createMovDpp8(IRBuilderBase &B, Value *Val, unsigned Selector) {
1002 return B.CreateIntrinsic(Intrinsic::amdgcn_mov_dpp8, {Val->getType()},
1003 {Val, B.getInt32(Selector)});
1004}
1005
1006/// Emit v_permlane16 with the precomputed lane-select halves.
1008 uint32_t Hi) {
1009 Type *Ty = Val->getType();
1010 return B.CreateIntrinsic(Intrinsic::amdgcn_permlane16, {Ty},
1011 {PoisonValue::get(Ty), Val, B.getInt32(Lo),
1012 B.getInt32(Hi), B.getFalse(), B.getFalse()});
1013}
1014
1015/// Emit v_permlanex16 with the precomputed lane-select halves. Each output
1016/// lane reads from the other 16-lane half of the same row.
1018 uint32_t Hi) {
1019 Type *Ty = Val->getType();
1020 return B.CreateIntrinsic(Intrinsic::amdgcn_permlanex16, {Ty},
1021 {PoisonValue::get(Ty), Val, B.getInt32(Lo),
1022 B.getInt32(Hi), B.getFalse(), B.getFalse()});
1023}
1024
1025/// Emit ds_swizzle with the given immediate, bitcasting/converting between
1026/// pointer/float types and i32 as required by the intrinsic signature.
1028 const DataLayout &DL) {
1029 Type *OrigTy = Val->getType();
1030 assert(DL.getTypeSizeInBits(OrigTy) == 32 &&
1031 "ds_swizzle only supports 32-bit operands");
1032 IntegerType *I32Ty = B.getInt32Ty();
1033 Value *Src = Val;
1034 if (OrigTy->isPointerTy())
1035 Src = B.CreatePtrToInt(Src, I32Ty);
1036 else if (OrigTy != I32Ty)
1037 Src = B.CreateBitCast(Src, I32Ty);
1038 Value *Result = B.CreateIntrinsic(Intrinsic::amdgcn_ds_swizzle, {},
1039 {Src, B.getInt32(Offset)});
1040 if (OrigTy->isPointerTy())
1041 return B.CreateIntToPtr(Result, OrigTy);
1042 if (OrigTy != I32Ty)
1043 return B.CreateBitCast(Result, OrigTy);
1044 return Result;
1045}
1046
1047/// Emit v_permlane64 (swap of the two 32-lane halves of a wave64).
1049 return B.CreateIntrinsic(Intrinsic::amdgcn_permlane64, {Val->getType()},
1050 {Val});
1051}
1052
1053/// Given a shuffle map, try to emit the best hardware intrinsic.
1056 const GCNSubtarget &ST,
1057 const DataLayout &DL) {
1058 // Identity shuffle (every lane reads itself) folds to the source value.
1059 if (all_of(enumerate(Ids),
1060 [](const auto &E) { return E.value() == E.index(); }))
1061 return Src;
1062
1063 // Uniform shuffle (all lanes read the same value) is handled by cheaper
1064 // broadcast/readlane intrinsics.
1065 if (all_equal(Ids))
1066 return nullptr;
1067
1068 if (std::optional<unsigned> QP = matchQuadPermPattern(Ids)) {
1069 if (ST.hasDPP())
1070 return createUpdateDpp(B, Src, *QP);
1072 }
1073
1074 if (ST.hasDPP()) {
1079 if (std::optional<unsigned> Amt = matchRowRotatePattern(Ids))
1080 return createUpdateDpp(B, Src, AMDGPU::DPP::ROW_ROR_FIRST + *Amt - 1);
1081 }
1082
1083 // row_share is supported on GFX90A and GFX10+; row_xmask is GFX10+ only.
1084 if (ST.hasDPPRowShare()) {
1085 if (std::optional<unsigned> Lane = matchRowSharePattern(Ids))
1086 return createUpdateDpp(B, Src, AMDGPU::DPP::ROW_SHARE_FIRST + *Lane);
1087 }
1088
1089 if (ST.hasDPP() && ST.hasGFX10Insts()) {
1090 if (std::optional<unsigned> Mask = matchRowXMaskPattern(Ids))
1091 return createUpdateDpp(B, Src, AMDGPU::DPP::ROW_XMASK_FIRST + *Mask);
1092 }
1093
1094 if (ST.hasDPP8()) {
1095 if (std::optional<unsigned> Sel = matchHalfRowPermPattern(Ids))
1096 return createMovDpp8(B, Src, *Sel);
1097 }
1098
1099 if (ST.hasPermlane16Insts()) {
1100 if (isFullRowPattern(Ids)) {
1102 return createPermlane16(B, Src, Lo_32(Sel), Hi_32(Sel));
1103 }
1104 // Cross-row shuffles (e.g. XOR 16..31) — covered by permlanex16.
1105 if (isCrossRowPattern(Ids)) {
1107 return createPermlaneX16(B, Src, Lo_32(Sel), Hi_32(Sel));
1108 }
1109 }
1110
1111 // Generic DS_SWIZZLE bitmask-mode fallback: handles any 32-lane shuffle that
1112 // can be expressed as dst = ((src & AND) | OR) ^ XOR with 5-bit masks. This
1113 // is available on every target that has ds_swizzle.
1114 if (std::optional<unsigned> Imm = matchDsSwizzleBitmaskPattern(Ids))
1115 return createDsSwizzle(B, Src, *Imm, DL);
1116
1117 // DS_SWIZZLE rotate mode (GFX9+): handles cyclic 32-lane rotations that
1118 // bitmask mode cannot express (e.g. +1 mod 32 requires inter-bit carry).
1119 if (ST.hasDsSwizzleRotateMode()) {
1120 if (std::optional<unsigned> Imm = matchDsSwizzleRotatePattern(Ids))
1121 return createDsSwizzle(B, Src, *Imm, DL);
1122 }
1123
1124 if (ST.hasPermLane64() && matchHalfWaveSwapPattern(Ids))
1125 return createPermlane64(B, Src);
1126
1127 return nullptr;
1128}
1129
1130/// Try to fold a wave_shuffle/ds_bpermute whose lane index is a constant
1131/// function of the lane ID into a hardware-specific lane permutation intrinsic.
1132static std::optional<Instruction *>
1134 const GCNSubtarget &ST) {
1135 const DataLayout &DL = IC.getDataLayout();
1136 if (DL.getTypeSizeInBits(II.getType()) != 32)
1137 return std::nullopt;
1138
1139 if (!ST.isWaveSizeKnown())
1140 return std::nullopt;
1141
1142 unsigned WaveSize = ST.getWavefrontSize();
1143 bool IsBpermute = II.getIntrinsicID() == Intrinsic::amdgcn_ds_bpermute;
1144 Value *Src = II.getArgOperand(IsBpermute ? 1 : 0);
1145 Value *Index = II.getArgOperand(IsBpermute ? 0 : 1);
1146
1148 if (IsBpermute) {
1149 Ids.resize(WaveSize);
1150 for (unsigned Lane : seq(WaveSize)) {
1151 std::optional<uint64_t> Val = evalLaneExpr(Index, Lane, ST, DL);
1152 if (!Val || (*Val & 3) || (*Val >> 2) >= WaveSize)
1153 return std::nullopt;
1154 Ids[Lane] = static_cast<uint8_t>(*Val >> 2);
1155 }
1156 } else {
1157 if (!tryBuildShuffleMap(Index, ST, Ids, DL))
1158 return std::nullopt;
1159 }
1160
1161 Value *Result = matchShuffleToHWIntrinsic(IC.Builder, Src, Ids, ST, DL);
1162 if (!Result)
1163 return std::nullopt;
1164
1165 return IC.replaceInstUsesWith(II, Result);
1166}
1167
1168/// Try to fold an addition into the accumulator when saturation is disabled.
1170 unsigned AccIdx,
1171 unsigned ClampIdx,
1172 InstCombiner &IC) {
1173 // Reassociating across a saturating accumulation is not valid.
1174 if (!match(II.getArgOperand(ClampIdx), m_Zero()) || !II.hasOneUse())
1175 return nullptr;
1176
1177 const APInt *Acc = nullptr;
1178 if (!match(II.getArgOperand(AccIdx), m_APInt(Acc)))
1179 return nullptr;
1180
1181 auto *AccumUser = dyn_cast<BinaryOperator>(II.user_back());
1182 if (!AccumUser)
1183 return nullptr;
1184
1185 Value *AccumDelta = nullptr;
1186 if (!match(AccumUser, m_c_Add(m_Specific(&II), m_Value(AccumDelta))))
1187 return nullptr;
1188
1189 Value *NewAcc = nullptr;
1190 const APInt *AccumDeltaC = nullptr;
1191 if (Acc->isZero())
1192 NewAcc = AccumDelta;
1193 else if (match(AccumDelta, m_APInt(AccumDeltaC)))
1194 NewAcc = ConstantInt::get(II.getType(), *Acc + *AccumDeltaC);
1195 else
1196 return nullptr;
1197
1198 Instruction *NewII =
1199 IC.InsertNewInstWith(II.clone(), AccumUser->getIterator());
1200 NewII->setOperand(AccIdx, NewAcc);
1203 IC.replaceInstUsesWith(*AccumUser, NewII);
1204 IC.eraseInstFromFunction(*AccumUser);
1205 return &II;
1206}
1207
1208std::optional<Instruction *>
1210 Intrinsic::ID IID = II.getIntrinsicID();
1211 switch (IID) {
1212 case Intrinsic::amdgcn_implicitarg_ptr: {
1213 if (II.getFunction()->hasFnAttribute("amdgpu-no-implicitarg-ptr"))
1214 return IC.replaceInstUsesWith(II, PoisonValue::get(II.getType()));
1215 uint64_t ImplicitArgBytes = ST->getImplicitArgNumBytes(*II.getFunction());
1216
1217 uint64_t CurrentOrNullBytes =
1218 II.getAttributes().getRetDereferenceableOrNullBytes();
1219 if (CurrentOrNullBytes != 0) {
1220 // Refine "dereferenceable (A) meets dereferenceable_or_null(B)"
1221 // into dereferenceable(max(A, B))
1222 uint64_t NewBytes = std::max(CurrentOrNullBytes, ImplicitArgBytes);
1223 II.addRetAttr(
1224 Attribute::getWithDereferenceableBytes(II.getContext(), NewBytes));
1225 II.removeRetAttr(Attribute::DereferenceableOrNull);
1226 return &II;
1227 }
1228
1229 uint64_t CurrentBytes = II.getAttributes().getRetDereferenceableBytes();
1230 uint64_t NewBytes = std::max(CurrentBytes, ImplicitArgBytes);
1231 if (NewBytes != CurrentBytes) {
1232 II.addRetAttr(
1233 Attribute::getWithDereferenceableBytes(II.getContext(), NewBytes));
1234 return &II;
1235 }
1236
1237 return std::nullopt;
1238 }
1239 case Intrinsic::amdgcn_rcp: {
1240 Value *Src = II.getArgOperand(0);
1241 if (isa<PoisonValue>(Src))
1242 return IC.replaceInstUsesWith(II, Src);
1243
1244 // TODO: Move to ConstantFolding/InstSimplify?
1245 if (isa<UndefValue>(Src)) {
1246 Type *Ty = II.getType();
1247 auto *QNaN = ConstantFP::get(Ty, APFloat::getQNaN(Ty->getFltSemantics()));
1248 return IC.replaceInstUsesWith(II, QNaN);
1249 }
1250
1251 if (II.isStrictFP())
1252 break;
1253
1254 if (const ConstantFP *C = dyn_cast<ConstantFP>(Src)) {
1255 std::optional<APFloat> Val = AMDGPU::evaluateRcp(C->getValueAPF());
1256 if (!Val)
1257 break;
1258
1259 return IC.replaceInstUsesWith(II, ConstantFP::get(II.getContext(), *Val));
1260 }
1261
1262 FastMathFlags FMF = cast<FPMathOperator>(II).getFastMathFlags();
1263 if (!FMF.allowContract())
1264 break;
1265 auto *SrcCI = dyn_cast<IntrinsicInst>(Src);
1266 if (!SrcCI)
1267 break;
1268
1269 auto IID = SrcCI->getIntrinsicID();
1270 // llvm.amdgcn.rcp(llvm.amdgcn.sqrt(x)) -> llvm.amdgcn.rsq(x) if contractable
1271 //
1272 // llvm.amdgcn.rcp(llvm.sqrt(x)) -> llvm.amdgcn.rsq(x) if contractable and
1273 // relaxed.
1274 if (IID == Intrinsic::amdgcn_sqrt || IID == Intrinsic::sqrt) {
1275 const FPMathOperator *SqrtOp = cast<FPMathOperator>(SrcCI);
1276 FastMathFlags InnerFMF = SqrtOp->getFastMathFlags();
1277 if (!InnerFMF.allowContract() || !SrcCI->hasOneUse())
1278 break;
1279
1280 if (IID == Intrinsic::sqrt && !canContractSqrtToRsq(SqrtOp))
1281 break;
1282
1284 SrcCI->getModule(), Intrinsic::amdgcn_rsq, {SrcCI->getType()});
1285
1286 InnerFMF |= FMF;
1287 II.setFastMathFlags(InnerFMF);
1288
1289 II.setCalledFunction(NewDecl);
1290 return IC.replaceOperand(II, 0, SrcCI->getArgOperand(0));
1291 }
1292
1293 break;
1294 }
1295 case Intrinsic::amdgcn_sqrt:
1296 case Intrinsic::amdgcn_rsq:
1297 case Intrinsic::amdgcn_tanh: {
1298 Value *Src = II.getArgOperand(0);
1299 if (isa<PoisonValue>(Src))
1300 return IC.replaceInstUsesWith(II, Src);
1301
1302 // TODO: Move to ConstantFolding/InstSimplify?
1303 if (isa<UndefValue>(Src)) {
1304 Type *Ty = II.getType();
1305 auto *QNaN = ConstantFP::get(Ty, APFloat::getQNaN(Ty->getFltSemantics()));
1306 return IC.replaceInstUsesWith(II, QNaN);
1307 }
1308
1309 // f16 amdgcn.sqrt is identical to regular sqrt.
1310 if (IID == Intrinsic::amdgcn_sqrt && Src->getType()->isHalfTy()) {
1312 II.getModule(), Intrinsic::sqrt, {II.getType()});
1313 II.setCalledFunction(NewDecl);
1314 return &II;
1315 }
1316
1317 break;
1318 }
1319 case Intrinsic::amdgcn_log:
1320 case Intrinsic::amdgcn_exp2: {
1321 const bool IsLog = IID == Intrinsic::amdgcn_log;
1322 const bool IsExp = IID == Intrinsic::amdgcn_exp2;
1323 Value *Src = II.getArgOperand(0);
1324 Type *Ty = II.getType();
1325
1326 if (isa<PoisonValue>(Src))
1327 return IC.replaceInstUsesWith(II, Src);
1328
1329 if (IC.getSimplifyQuery().isUndefValue(Src))
1331
1332 if (ConstantFP *C = dyn_cast<ConstantFP>(Src)) {
1333 if (C->isInfinity()) {
1334 // exp2(+inf) -> +inf
1335 // log2(+inf) -> +inf
1336 if (!C->isNegative())
1337 return IC.replaceInstUsesWith(II, C);
1338
1339 // exp2(-inf) -> 0
1340 if (IsExp && C->isNegative())
1342 }
1343
1344 if (II.isStrictFP())
1345 break;
1346
1347 if (C->isNaN()) {
1348 Constant *Quieted = ConstantFP::get(Ty, C->getValue().makeQuiet());
1349 return IC.replaceInstUsesWith(II, Quieted);
1350 }
1351
1352 // f32 instruction doesn't handle denormals, f16 does.
1353 if (C->isZero() || (C->getValue().isDenormal() && Ty->isFloatTy())) {
1354 Constant *FoldedValue = IsLog ? ConstantFP::getInfinity(Ty, true)
1355 : ConstantFP::get(Ty, 1.0);
1356 return IC.replaceInstUsesWith(II, FoldedValue);
1357 }
1358
1359 if (IsLog && C->isNegative())
1361
1362 // TODO: Full constant folding matching hardware behavior.
1363 }
1364
1365 break;
1366 }
1367 case Intrinsic::amdgcn_frexp_mant:
1368 case Intrinsic::amdgcn_frexp_exp: {
1369 Value *Src = II.getArgOperand(0);
1370 if (const ConstantFP *C = dyn_cast<ConstantFP>(Src)) {
1371 int Exp;
1372 APFloat Significand =
1373 frexp(C->getValueAPF(), Exp, APFloat::rmNearestTiesToEven);
1374
1375 if (IID == Intrinsic::amdgcn_frexp_mant) {
1376 return IC.replaceInstUsesWith(
1377 II, ConstantFP::get(II.getContext(), Significand));
1378 }
1379
1380 // Match instruction special case behavior.
1381 if (Exp == APFloat::IEK_NaN || Exp == APFloat::IEK_Inf)
1382 Exp = 0;
1383
1384 return IC.replaceInstUsesWith(II,
1385 ConstantInt::getSigned(II.getType(), Exp));
1386 }
1387
1388 if (isa<PoisonValue>(Src))
1389 return IC.replaceInstUsesWith(II, PoisonValue::get(II.getType()));
1390
1391 if (isa<UndefValue>(Src)) {
1392 return IC.replaceInstUsesWith(II, UndefValue::get(II.getType()));
1393 }
1394
1395 break;
1396 }
1397 case Intrinsic::amdgcn_class: {
1398 Value *Src0 = II.getArgOperand(0);
1399 Value *Src1 = II.getArgOperand(1);
1400 const ConstantInt *CMask = dyn_cast<ConstantInt>(Src1);
1401 if (CMask) {
1402 II.setCalledOperand(Intrinsic::getOrInsertDeclaration(
1403 II.getModule(), Intrinsic::is_fpclass, Src0->getType()));
1404
1405 // Clamp any excess bits, as they're illegal for the generic intrinsic.
1406 II.setArgOperand(1, ConstantInt::get(Src1->getType(),
1407 CMask->getZExtValue() & fcAllFlags));
1408 return &II;
1409 }
1410
1411 // Propagate poison.
1412 if (isa<PoisonValue>(Src0) || isa<PoisonValue>(Src1))
1413 return IC.replaceInstUsesWith(II, PoisonValue::get(II.getType()));
1414
1415 // llvm.amdgcn.class(_, undef) -> false
1416 if (IC.getSimplifyQuery().isUndefValue(Src1))
1417 return IC.replaceInstUsesWith(II, ConstantInt::get(II.getType(), false));
1418
1419 // llvm.amdgcn.class(undef, mask) -> mask != 0
1420 if (IC.getSimplifyQuery().isUndefValue(Src0)) {
1421 Value *CmpMask = IC.Builder.CreateICmpNE(
1422 Src1, ConstantInt::getNullValue(Src1->getType()));
1423 return IC.replaceInstUsesWith(II, CmpMask);
1424 }
1425 break;
1426 }
1427 case Intrinsic::amdgcn_cvt_pkrtz: {
1428 auto foldFPTruncToF16RTZ = [](Value *Arg) -> Value * {
1429 Type *HalfTy = Type::getHalfTy(Arg->getContext());
1430
1431 if (isa<PoisonValue>(Arg))
1432 return PoisonValue::get(HalfTy);
1433 if (isa<UndefValue>(Arg))
1434 return UndefValue::get(HalfTy);
1435
1436 ConstantFP *CFP = nullptr;
1437 if (match(Arg, m_ConstantFP(CFP))) {
1438 bool LosesInfo;
1439 APFloat Val(CFP->getValueAPF());
1441 return ConstantFP::get(HalfTy, Val);
1442 }
1443
1444 Value *Src = nullptr;
1445 if (match(Arg, m_FPExt(m_Value(Src)))) {
1446 if (Src->getType()->isHalfTy())
1447 return Src;
1448 }
1449
1450 return nullptr;
1451 };
1452
1453 if (Value *Src0 = foldFPTruncToF16RTZ(II.getArgOperand(0))) {
1454 if (Value *Src1 = foldFPTruncToF16RTZ(II.getArgOperand(1))) {
1455 Value *V = PoisonValue::get(II.getType());
1456 V = IC.Builder.CreateInsertElement(V, Src0, (uint64_t)0);
1457 V = IC.Builder.CreateInsertElement(V, Src1, (uint64_t)1);
1458 return IC.replaceInstUsesWith(II, V);
1459 }
1460 }
1461
1462 break;
1463 }
1464 case Intrinsic::amdgcn_cvt_pknorm_i16:
1465 case Intrinsic::amdgcn_cvt_pknorm_u16:
1466 case Intrinsic::amdgcn_cvt_pk_i16:
1467 case Intrinsic::amdgcn_cvt_pk_u16: {
1468 Value *Src0 = II.getArgOperand(0);
1469 Value *Src1 = II.getArgOperand(1);
1470
1471 // TODO: Replace call with scalar operation if only one element is poison.
1472 if (isa<PoisonValue>(Src0) && isa<PoisonValue>(Src1))
1473 return IC.replaceInstUsesWith(II, PoisonValue::get(II.getType()));
1474
1475 if (isa<UndefValue>(Src0) && isa<UndefValue>(Src1)) {
1476 return IC.replaceInstUsesWith(II, UndefValue::get(II.getType()));
1477 }
1478
1479 break;
1480 }
1481 case Intrinsic::amdgcn_cvt_off_f32_i4: {
1482 Value* Arg = II.getArgOperand(0);
1483 Type *Ty = II.getType();
1484
1485 if (isa<PoisonValue>(Arg))
1486 return IC.replaceInstUsesWith(II, PoisonValue::get(Ty));
1487
1488 if(IC.getSimplifyQuery().isUndefValue(Arg))
1490
1491 ConstantInt *CArg = dyn_cast<ConstantInt>(II.getArgOperand(0));
1492 if (!CArg)
1493 break;
1494
1495 // Tabulated 0.0625 * (sext (CArg & 0xf)).
1496 constexpr size_t ResValsSize = 16;
1497 static constexpr float ResVals[ResValsSize] = {
1498 0.0, 0.0625, 0.125, 0.1875, 0.25, 0.3125, 0.375, 0.4375,
1499 -0.5, -0.4375, -0.375, -0.3125, -0.25, -0.1875, -0.125, -0.0625};
1500 Constant *Res =
1501 ConstantFP::get(Ty, ResVals[CArg->getZExtValue() & (ResValsSize - 1)]);
1502 return IC.replaceInstUsesWith(II, Res);
1503 }
1504 case Intrinsic::amdgcn_ubfe:
1505 case Intrinsic::amdgcn_sbfe: {
1506 // Decompose simple cases into standard shifts.
1507 Value *Src = II.getArgOperand(0);
1508 if (isa<UndefValue>(Src)) {
1509 return IC.replaceInstUsesWith(II, Src);
1510 }
1511
1512 uint64_t Width;
1513 Type *Ty = II.getType();
1514 unsigned IntSize = Ty->getIntegerBitWidth();
1515
1516 ConstantInt *CWidth = dyn_cast<ConstantInt>(II.getArgOperand(2));
1517 if (CWidth) {
1518 Width = CWidth->getZExtValue();
1519 if ((Width & (IntSize - 1)) == 0) {
1521 }
1522
1523 // Hardware ignores high bits, so remove those.
1524 if (Width >= IntSize) {
1525 return IC.replaceOperand(
1526 II, 2, ConstantInt::get(CWidth->getType(), Width & (IntSize - 1)));
1527 }
1528 }
1529
1530 uint64_t Offset;
1531 ConstantInt *COffset = dyn_cast<ConstantInt>(II.getArgOperand(1));
1532 if (COffset) {
1533 Offset = COffset->getZExtValue();
1534 if (Offset >= IntSize) {
1535 return IC.replaceOperand(
1536 II, 1,
1537 ConstantInt::get(COffset->getType(), Offset & (IntSize - 1)));
1538 }
1539 }
1540
1541 bool Signed = IID == Intrinsic::amdgcn_sbfe;
1542
1543 if (!CWidth || !COffset)
1544 break;
1545
1546 // The case of Width == 0 is handled above, which makes this transformation
1547 // safe. If Width == 0, then the ashr and lshr instructions become poison
1548 // value since the shift amount would be equal to the bit size.
1549 assert(Width != 0);
1550
1551 // TODO: This allows folding to undef when the hardware has specific
1552 // behavior?
1553 if (Offset + Width < IntSize) {
1554 Value *Shl = IC.Builder.CreateShl(Src, IntSize - Offset - Width);
1555 Value *RightShift = Signed ? IC.Builder.CreateAShr(Shl, IntSize - Width)
1556 : IC.Builder.CreateLShr(Shl, IntSize - Width);
1557 RightShift->takeName(&II);
1558 return IC.replaceInstUsesWith(II, RightShift);
1559 }
1560
1561 Value *RightShift = Signed ? IC.Builder.CreateAShr(Src, Offset)
1562 : IC.Builder.CreateLShr(Src, Offset);
1563
1564 RightShift->takeName(&II);
1565 return IC.replaceInstUsesWith(II, RightShift);
1566 }
1567 case Intrinsic::amdgcn_exp:
1568 case Intrinsic::amdgcn_exp_row:
1569 case Intrinsic::amdgcn_exp_compr: {
1570 ConstantInt *En = cast<ConstantInt>(II.getArgOperand(1));
1571 uint64_t EnBits = En->getZExtValue();
1572 if (EnBits == 0xf)
1573 break; // All inputs enabled.
1574
1575 bool IsCompr = IID == Intrinsic::amdgcn_exp_compr;
1576 bool Changed = false;
1577 for (int I = 0; I < (IsCompr ? 2 : 4); ++I) {
1578 if ((!IsCompr && (EnBits & (1 << I)) == 0) ||
1579 (IsCompr && ((EnBits & (0x3 << (2 * I))) == 0))) {
1580 Value *Src = II.getArgOperand(I + 2);
1581 if (!isa<PoisonValue>(Src)) {
1582 IC.replaceOperand(II, I + 2, PoisonValue::get(Src->getType()));
1583 Changed = true;
1584 }
1585 }
1586 }
1587
1588 if (Changed) {
1589 return &II;
1590 }
1591
1592 break;
1593 }
1594 case Intrinsic::amdgcn_fmed3: {
1595 Value *Src0 = II.getArgOperand(0);
1596 Value *Src1 = II.getArgOperand(1);
1597 Value *Src2 = II.getArgOperand(2);
1598
1599 for (Value *Src : {Src0, Src1, Src2}) {
1600 if (isa<PoisonValue>(Src))
1601 return IC.replaceInstUsesWith(II, Src);
1602 }
1603
1604 if (II.isStrictFP())
1605 break;
1606
1607 // med3 with a nan input acts like
1608 // v_min_f32(v_min_f32(s0, s1), s2)
1609 //
1610 // Signalingness is ignored with ieee=0, so we fold to
1611 // minimumnum/maximumnum. With ieee=1, the v_min_f32 acts like llvm.minnum
1612 // with signaling nan handling. With ieee=0, like llvm.minimumnum except a
1613 // returned signaling nan will not be quieted.
1614
1615 // ieee=1
1616 // s0 snan: s2
1617 // s1 snan: s2
1618 // s2 snan: qnan
1619
1620 // s0 qnan: min(s1, s2)
1621 // s1 qnan: min(s0, s2)
1622 // s2 qnan: min(s0, s1)
1623
1624 // ieee=0
1625 // s0 _nan: min(s1, s2)
1626 // s1 _nan: min(s0, s2)
1627 // s2 _nan: min(s0, s1)
1628
1629 // med3 behavior with infinity
1630 // s0 +inf: max(s1, s2)
1631 // s1 +inf: max(s0, s2)
1632 // s2 +inf: max(s0, s1)
1633 // s0 -inf: min(s1, s2)
1634 // s1 -inf: min(s0, s2)
1635 // s2 -inf: min(s0, s1)
1636
1637 // Checking for NaN before canonicalization provides better fidelity when
1638 // mapping other operations onto fmed3 since the order of operands is
1639 // unchanged.
1640 Value *V = nullptr;
1641 const APFloat *ConstSrc0 = nullptr;
1642 const APFloat *ConstSrc1 = nullptr;
1643 const APFloat *ConstSrc2 = nullptr;
1644
1645 if ((match(Src0, m_APFloat(ConstSrc0)) &&
1646 (ConstSrc0->isNaN() || ConstSrc0->isInfinity())) ||
1647 isa<UndefValue>(Src0)) {
1648 const bool IsPosInfinity = ConstSrc0 && ConstSrc0->isPosInfinity();
1649 switch (fpenvIEEEMode(II)) {
1650 case KnownIEEEMode::On:
1651 // TODO: If Src2 is snan, does it need quieting?
1652 if (ConstSrc0 && ConstSrc0->isNaN() && ConstSrc0->isSignaling())
1653 return IC.replaceInstUsesWith(II, Src2);
1654
1655 V = IsPosInfinity ? IC.Builder.CreateMaxNum(Src1, Src2)
1656 : IC.Builder.CreateMinNum(Src1, Src2);
1657 break;
1658 case KnownIEEEMode::Off:
1659 V = IsPosInfinity ? IC.Builder.CreateMaximumNum(Src1, Src2)
1660 : IC.Builder.CreateMinimumNum(Src1, Src2);
1661 break;
1663 break;
1664 }
1665 } else if ((match(Src1, m_APFloat(ConstSrc1)) &&
1666 (ConstSrc1->isNaN() || ConstSrc1->isInfinity())) ||
1667 isa<UndefValue>(Src1)) {
1668 const bool IsPosInfinity = ConstSrc1 && ConstSrc1->isPosInfinity();
1669 switch (fpenvIEEEMode(II)) {
1670 case KnownIEEEMode::On:
1671 // TODO: If Src2 is snan, does it need quieting?
1672 if (ConstSrc1 && ConstSrc1->isNaN() && ConstSrc1->isSignaling())
1673 return IC.replaceInstUsesWith(II, Src2);
1674
1675 V = IsPosInfinity ? IC.Builder.CreateMaxNum(Src0, Src2)
1676 : IC.Builder.CreateMinNum(Src0, Src2);
1677 break;
1678 case KnownIEEEMode::Off:
1679 V = IsPosInfinity ? IC.Builder.CreateMaximumNum(Src0, Src2)
1680 : IC.Builder.CreateMinimumNum(Src0, Src2);
1681 break;
1683 break;
1684 }
1685 } else if ((match(Src2, m_APFloat(ConstSrc2)) &&
1686 (ConstSrc2->isNaN() || ConstSrc2->isInfinity())) ||
1687 isa<UndefValue>(Src2)) {
1688 switch (fpenvIEEEMode(II)) {
1689 case KnownIEEEMode::On:
1690 if (ConstSrc2 && ConstSrc2->isNaN() && ConstSrc2->isSignaling()) {
1691 auto *Quieted = ConstantFP::get(II.getType(), ConstSrc2->makeQuiet());
1692 return IC.replaceInstUsesWith(II, Quieted);
1693 }
1694
1695 V = (ConstSrc2 && ConstSrc2->isPosInfinity())
1696 ? IC.Builder.CreateMaxNum(Src0, Src1)
1697 : IC.Builder.CreateMinNum(Src0, Src1);
1698 break;
1699 case KnownIEEEMode::Off:
1700 V = (ConstSrc2 && ConstSrc2->isPosInfinity())
1701 ? IC.Builder.CreateMaximumNum(Src0, Src1)
1702 : IC.Builder.CreateMinimumNum(Src0, Src1);
1703 break;
1705 break;
1706 }
1707 }
1708
1709 if (V) {
1710 if (auto *CI = dyn_cast<CallInst>(V)) {
1711 CI->copyFastMathFlags(&II);
1712 CI->takeName(&II);
1713 }
1714 return IC.replaceInstUsesWith(II, V);
1715 }
1716
1717 bool Swap = false;
1718 // Canonicalize constants to RHS operands.
1719 //
1720 // fmed3(c0, x, c1) -> fmed3(x, c0, c1)
1721 if (isa<Constant>(Src0) && !isa<Constant>(Src1)) {
1722 std::swap(Src0, Src1);
1723 Swap = true;
1724 }
1725
1726 if (isa<Constant>(Src1) && !isa<Constant>(Src2)) {
1727 std::swap(Src1, Src2);
1728 Swap = true;
1729 }
1730
1731 if (isa<Constant>(Src0) && !isa<Constant>(Src1)) {
1732 std::swap(Src0, Src1);
1733 Swap = true;
1734 }
1735
1736 if (Swap) {
1737 II.setArgOperand(0, Src0);
1738 II.setArgOperand(1, Src1);
1739 II.setArgOperand(2, Src2);
1740 return &II;
1741 }
1742
1743 if (const ConstantFP *C0 = dyn_cast<ConstantFP>(Src0)) {
1744 if (const ConstantFP *C1 = dyn_cast<ConstantFP>(Src1)) {
1745 if (const ConstantFP *C2 = dyn_cast<ConstantFP>(Src2)) {
1746 APFloat Result = fmed3AMDGCN(C0->getValueAPF(), C1->getValueAPF(),
1747 C2->getValueAPF());
1748 return IC.replaceInstUsesWith(II,
1749 ConstantFP::get(II.getType(), Result));
1750 }
1751 }
1752 }
1753
1754 if (!ST->hasMed3_16())
1755 break;
1756
1757 // Repeat floating-point width reduction done for minnum/maxnum.
1758 // fmed3((fpext X), (fpext Y), (fpext Z)) -> fpext (fmed3(X, Y, Z))
1759 if (Value *X = matchFPExtFromF16(Src0)) {
1760 if (Value *Y = matchFPExtFromF16(Src1)) {
1761 if (Value *Z = matchFPExtFromF16(Src2)) {
1762 Value *NewCall = IC.Builder.CreateIntrinsic(
1763 IID, {X->getType()}, {X, Y, Z}, &II, II.getName());
1764 return new FPExtInst(NewCall, II.getType());
1765 }
1766 }
1767 }
1768
1769 break;
1770 }
1771 case Intrinsic::amdgcn_mbcnt_hi:
1772 // exec_hi is all 0, so this is just a copy.
1773 if (ST->isWave32())
1774 return IC.replaceInstUsesWith(II, II.getArgOperand(1));
1775 [[fallthrough]];
1776 case Intrinsic::amdgcn_mbcnt_lo: {
1777 ConstantRange AccRange =
1778 computeConstantRange(II.getArgOperand(1),
1779 /*ForSigned=*/false, IC.getSimplifyQuery());
1780 if (AccRange.isFullSet())
1781 return nullptr;
1782
1783 // TODO: Can raise lower bound by inspecting first argument.
1784 // Wave64 mbcnt_lo adds at most 32. Otherwise these add at most 31.
1785 unsigned MaxCount =
1786 IID == Intrinsic::amdgcn_mbcnt_lo && ST->isWave64() ? 32 : 31;
1787 ConstantRange MbcntRange(APInt(32, 0), APInt(32, MaxCount + 1));
1788 ConstantRange ComputedRange = AccRange.add(MbcntRange);
1789 if (ComputedRange.isFullSet())
1790 return nullptr;
1791
1792 if (std::optional<ConstantRange> ExistingRange = II.getRange()) {
1793 ComputedRange = ComputedRange.intersectWith(*ExistingRange);
1794 if (ComputedRange == *ExistingRange)
1795 return nullptr;
1796 }
1797
1798 II.addRangeRetAttr(ComputedRange);
1799 return nullptr;
1800 }
1801 case Intrinsic::amdgcn_ballot: {
1802 Value *Arg = II.getArgOperand(0);
1803 if (isa<PoisonValue>(Arg))
1804 return IC.replaceInstUsesWith(II, PoisonValue::get(II.getType()));
1805
1806 if (auto *Src = dyn_cast<ConstantInt>(Arg)) {
1807 if (Src->isZero()) {
1808 // amdgcn.ballot(i1 0) is zero.
1809 return IC.replaceInstUsesWith(II, Constant::getNullValue(II.getType()));
1810 }
1811 }
1812 if (ST->isWave32() && II.getType()->getIntegerBitWidth() == 64) {
1813 // %b64 = call i64 ballot.i64(...)
1814 // =>
1815 // %b32 = call i32 ballot.i32(...)
1816 // %b64 = zext i32 %b32 to i64
1818 IC.Builder.CreateIntrinsic(Intrinsic::amdgcn_ballot,
1819 {IC.Builder.getInt32Ty()},
1820 {II.getArgOperand(0)}),
1821 II.getType());
1822 Call->takeName(&II);
1823 return IC.replaceInstUsesWith(II, Call);
1824 }
1825 break;
1826 }
1827 case Intrinsic::amdgcn_wavefrontsize: {
1828 if (ST->isWaveSizeKnown())
1829 return IC.replaceInstUsesWith(
1830 II, ConstantInt::get(II.getType(), ST->getWavefrontSize()));
1831 break;
1832 }
1833 case Intrinsic::amdgcn_wqm_vote: {
1834 // wqm_vote is identity when the argument is constant.
1835 if (!isa<Constant>(II.getArgOperand(0)))
1836 break;
1837
1838 return IC.replaceInstUsesWith(II, II.getArgOperand(0));
1839 }
1840 case Intrinsic::amdgcn_kill: {
1841 const ConstantInt *C = dyn_cast<ConstantInt>(II.getArgOperand(0));
1842 if (!C || !C->getZExtValue())
1843 break;
1844
1845 // amdgcn.kill(i1 1) is a no-op
1846 return IC.eraseInstFromFunction(II);
1847 }
1848 case Intrinsic::amdgcn_s_sendmsg:
1849 case Intrinsic::amdgcn_s_sendmsghalt: {
1850 // The second operand is copied to m0, but is only actually used for
1851 // certain message types. For message types that are known to not use m0,
1852 // fold it to poison.
1853 using namespace AMDGPU::SendMsg;
1854
1855 Value *M0Val = II.getArgOperand(1);
1856 if (isa<PoisonValue>(M0Val))
1857 break;
1858
1859 auto *MsgImm = cast<ConstantInt>(II.getArgOperand(0));
1860 uint16_t MsgId, OpId, StreamId;
1861 decodeMsg(static_cast<unsigned>(MsgImm->getZExtValue()), MsgId, OpId,
1862 StreamId, *ST);
1863
1864 if (!msgDoesNotUseM0(MsgId, *ST))
1865 break;
1866
1867 // Drop UB-implying attributes since we're replacing with poison.
1868 II.dropUBImplyingAttrsAndMetadata();
1869 IC.replaceOperand(II, 1, PoisonValue::get(M0Val->getType()));
1870 return nullptr;
1871 }
1872 case Intrinsic::amdgcn_update_dpp: {
1873 Value *Old = II.getArgOperand(0);
1874
1875 auto *BC = cast<ConstantInt>(II.getArgOperand(5));
1876 auto *RM = cast<ConstantInt>(II.getArgOperand(3));
1877 auto *BM = cast<ConstantInt>(II.getArgOperand(4));
1878 if (BC->isNullValue() || RM->getZExtValue() != 0xF ||
1879 BM->getZExtValue() != 0xF || isa<PoisonValue>(Old))
1880 break;
1881
1882 // If bound_ctrl = 1, row mask = bank mask = 0xf we can omit old value.
1883 return IC.replaceOperand(II, 0, PoisonValue::get(Old->getType()));
1884 }
1885 case Intrinsic::amdgcn_permlane16:
1886 case Intrinsic::amdgcn_permlane16_var:
1887 case Intrinsic::amdgcn_permlanex16:
1888 case Intrinsic::amdgcn_permlanex16_var: {
1889 // Discard vdst_in if it's not going to be read.
1890 Value *VDstIn = II.getArgOperand(0);
1891 if (isa<PoisonValue>(VDstIn))
1892 break;
1893
1894 // FetchInvalid operand idx.
1895 unsigned int FiIdx = (IID == Intrinsic::amdgcn_permlane16 ||
1896 IID == Intrinsic::amdgcn_permlanex16)
1897 ? 4 /* for permlane16 and permlanex16 */
1898 : 3; /* for permlane16_var and permlanex16_var */
1899
1900 // BoundCtrl operand idx.
1901 // For permlane16 and permlanex16 it should be 5
1902 // For Permlane16_var and permlanex16_var it should be 4
1903 unsigned int BcIdx = FiIdx + 1;
1904
1905 ConstantInt *FetchInvalid = cast<ConstantInt>(II.getArgOperand(FiIdx));
1906 ConstantInt *BoundCtrl = cast<ConstantInt>(II.getArgOperand(BcIdx));
1907 if (!FetchInvalid->getZExtValue() && !BoundCtrl->getZExtValue())
1908 break;
1909
1910 return IC.replaceOperand(II, 0, PoisonValue::get(VDstIn->getType()));
1911 }
1912 case Intrinsic::amdgcn_wave_shuffle:
1913 return tryOptimizeShufflePattern(IC, II, *ST);
1914 case Intrinsic::amdgcn_permlane64:
1915 case Intrinsic::amdgcn_readfirstlane:
1916 case Intrinsic::amdgcn_readlane:
1917 case Intrinsic::amdgcn_ds_bpermute: {
1918 // If the data argument is uniform these intrinsics return it unchanged.
1919 unsigned SrcIdx = IID == Intrinsic::amdgcn_ds_bpermute ? 1 : 0;
1920 const Use &Src = II.getArgOperandUse(SrcIdx);
1922 return IC.replaceInstUsesWith(II, Src.get());
1923
1924 if (IID == Intrinsic::amdgcn_readlane &&
1926 return &II;
1927
1928 // If the lane argument of bpermute is uniform, change it to readlane. This
1929 // generates better code and can enable further optimizations because
1930 // readlane is AlwaysUniform.
1931 if (IID == Intrinsic::amdgcn_ds_bpermute) {
1932 const Use &Lane = II.getArgOperandUse(0);
1933 if (AMDGPU::isTriviallyUniform(Lane)) {
1934 Value *NewLane = IC.Builder.CreateLShr(Lane, 2);
1936 II.getModule(), Intrinsic::amdgcn_readlane, II.getType());
1937 II.setCalledFunction(NewDecl);
1938 II.setOperand(0, Src);
1939 II.setOperand(1, NewLane);
1940 return &II;
1941 }
1942 }
1943
1944 if (IID == Intrinsic::amdgcn_ds_bpermute)
1945 return tryOptimizeShufflePattern(IC, II, *ST);
1946
1948 return Res;
1949
1950 return std::nullopt;
1951 }
1952 case Intrinsic::amdgcn_wave_match_b32: {
1953 const Use &Src0 = II.getArgOperandUse(0);
1954 const Use &Src1 = II.getArgOperandUse(1);
1955 if (Src0.get() == Src1.get() && AMDGPU::isTriviallyUniform(Src0)) {
1957 II.getModule(), Intrinsic::amdgcn_ballot, II.getType());
1958 CallInst *NewCall =
1959 IC.Builder.CreateCall(NewF, {IC.Builder.getInt1(true)});
1960 return IC.replaceInstUsesWith(II, NewCall);
1961 }
1962 break;
1963 }
1964 case Intrinsic::amdgcn_writelane: {
1965 // TODO: Fold bitcast like readlane.
1966 if (simplifyDemandedLaneMaskArg(IC, II, 1))
1967 return &II;
1968 return std::nullopt;
1969 }
1970 case Intrinsic::amdgcn_trig_preop: {
1971 // The intrinsic is declared with name mangling, but currently the
1972 // instruction only exists for f64
1973 if (!II.getType()->isDoubleTy())
1974 break;
1975
1976 Value *Src = II.getArgOperand(0);
1977 Value *Segment = II.getArgOperand(1);
1978 if (isa<PoisonValue>(Src) || isa<PoisonValue>(Segment))
1979 return IC.replaceInstUsesWith(II, PoisonValue::get(II.getType()));
1980
1981 if (isa<UndefValue>(Segment))
1982 return IC.replaceInstUsesWith(II, ConstantFP::getZero(II.getType()));
1983
1984 // Sign bit is not used.
1985 Value *StrippedSign = InstCombiner::stripSignOnlyFPOps(Src);
1986 if (StrippedSign != Src)
1987 return IC.replaceOperand(II, 0, StrippedSign);
1988
1989 if (II.isStrictFP())
1990 break;
1991
1992 const ConstantFP *CSrc = dyn_cast<ConstantFP>(Src);
1993 if (!CSrc && !isa<UndefValue>(Src))
1994 break;
1995
1996 // The instruction ignores special cases, and literally just extracts the
1997 // exponents. Fold undef to nan, and index the table as normal.
1998 APInt FSrcInt = CSrc ? CSrc->getValueAPF().bitcastToAPInt()
1999 : APFloat::getQNaN(II.getType()->getFltSemantics())
2000 .bitcastToAPInt();
2001
2002 const ConstantInt *Cseg = dyn_cast<ConstantInt>(Segment);
2003 if (!Cseg) {
2004 if (isa<UndefValue>(Src))
2005 return IC.replaceInstUsesWith(II, ConstantFP::getZero(II.getType()));
2006 break;
2007 }
2008
2009 unsigned Exponent =
2010 static_cast<unsigned>(FSrcInt.extractBitsAsZExtValue(11, 52));
2011 unsigned SegmentVal =
2012 static_cast<unsigned>(Cseg->getValue().trunc(5).getZExtValue());
2013 unsigned Shift = SegmentVal * 53;
2014 if (Exponent > 1077)
2015 Shift += Exponent - 1077;
2016
2017 // 2.0/PI table.
2018 static const uint32_t TwoByPi[] = {
2019 0xa2f9836e, 0x4e441529, 0xfc2757d1, 0xf534ddc0, 0xdb629599, 0x3c439041,
2020 0xfe5163ab, 0xdebbc561, 0xb7246e3a, 0x424dd2e0, 0x06492eea, 0x09d1921c,
2021 0xfe1deb1c, 0xb129a73e, 0xe88235f5, 0x2ebb4484, 0xe99c7026, 0xb45f7e41,
2022 0x3991d639, 0x835339f4, 0x9c845f8b, 0xbdf9283b, 0x1ff897ff, 0xde05980f,
2023 0xef2f118b, 0x5a0a6d1f, 0x6d367ecf, 0x27cb09b7, 0x4f463f66, 0x9e5fea2d,
2024 0x7527bac7, 0xebe5f17b, 0x3d0739f7, 0x8a5292ea, 0x6bfb5fb1, 0x1f8d5d08,
2025 0x56033046};
2026
2027 // Return 0 for outbound segment (hardware behavior).
2028 unsigned Idx = Shift >> 5;
2029 if (Idx + 2 >= std::size(TwoByPi)) {
2030 APFloat Zero = APFloat::getZero(II.getType()->getFltSemantics());
2031 return IC.replaceInstUsesWith(II, ConstantFP::get(II.getType(), Zero));
2032 }
2033
2034 unsigned BShift = Shift & 0x1f;
2035 uint64_t Thi = Make_64(TwoByPi[Idx], TwoByPi[Idx + 1]);
2036 uint64_t Tlo = Make_64(TwoByPi[Idx + 2], 0);
2037 if (BShift)
2038 Thi = (Thi << BShift) | (Tlo >> (64 - BShift));
2039 Thi = Thi >> 11;
2040 APFloat Result = APFloat((double)Thi);
2041
2042 int Scale = -53 - Shift;
2043 if (Exponent >= 1968)
2044 Scale += 128;
2045
2046 Result = scalbn(Result, Scale, RoundingMode::NearestTiesToEven);
2047 return IC.replaceInstUsesWith(II, ConstantFP::get(Src->getType(), Result));
2048 }
2049 case Intrinsic::amdgcn_sdot2:
2050 case Intrinsic::amdgcn_udot2:
2051 case Intrinsic::amdgcn_sdot4:
2052 case Intrinsic::amdgcn_udot4:
2053 case Intrinsic::amdgcn_sdot8:
2054 case Intrinsic::amdgcn_udot8: {
2055 Value *Src0 = II.getArgOperand(0);
2056 Value *Src1 = II.getArgOperand(1);
2057
2058 // Canonicalize the constant multiplicand to Src1.
2059 if (isa<Constant>(Src0) && !isa<Constant>(Src1)) {
2060 II.setArgOperand(0, Src1);
2061 II.setArgOperand(1, Src0);
2062 return &II;
2063 }
2064
2065 if (match(Src1, m_Zero()))
2066 return IC.replaceInstUsesWith(II, II.getArgOperand(2));
2067
2068 if (Instruction *I = foldAddIntoDotAccumulator(II, 2, 3, IC))
2069 return I;
2070
2071 break;
2072 }
2073 case Intrinsic::amdgcn_sudot4:
2074 case Intrinsic::amdgcn_sudot8: {
2075 Value *Src0 = II.getArgOperand(1);
2076 Value *Src1 = II.getArgOperand(3);
2077
2078 // Canonicalize the constant multiplicand to Src1, moving its sign flag with
2079 // it.
2080 if (isa<Constant>(Src0) && !isa<Constant>(Src1)) {
2081 Value *Sign0 = II.getArgOperand(0);
2082 Value *Sign1 = II.getArgOperand(2);
2083 II.setArgOperand(0, Sign1);
2084 II.setArgOperand(1, Src1);
2085 II.setArgOperand(2, Sign0);
2086 II.setArgOperand(3, Src0);
2087 return &II;
2088 }
2089
2090 if (match(Src1, m_Zero()))
2091 return IC.replaceInstUsesWith(II, II.getArgOperand(4));
2092
2093 if (Instruction *I = foldAddIntoDotAccumulator(II, 4, 5, IC))
2094 return I;
2095
2096 break;
2097 }
2098 case Intrinsic::amdgcn_fmul_legacy: {
2099 Value *Op0 = II.getArgOperand(0);
2100 Value *Op1 = II.getArgOperand(1);
2101
2102 for (Value *Src : {Op0, Op1}) {
2103 if (isa<PoisonValue>(Src))
2104 return IC.replaceInstUsesWith(II, Src);
2105 }
2106
2107 // The legacy behaviour is that multiplying +/-0.0 by anything, even NaN or
2108 // infinity, gives +0.0.
2109 // TODO: Move to InstSimplify?
2110 if (match(Op0, PatternMatch::m_AnyZeroFP()) ||
2112 return IC.replaceInstUsesWith(II, ConstantFP::getZero(II.getType()));
2113
2114 // If we can prove we don't have one of the special cases then we can use a
2115 // normal fmul instruction instead.
2116 if (canSimplifyLegacyMulToMul(II, Op0, Op1, IC)) {
2117 auto *FMul = IC.Builder.CreateFMulFMF(Op0, Op1, &II);
2118 FMul->takeName(&II);
2119 return IC.replaceInstUsesWith(II, FMul);
2120 }
2121 break;
2122 }
2123 case Intrinsic::amdgcn_fma_legacy: {
2124 Value *Op0 = II.getArgOperand(0);
2125 Value *Op1 = II.getArgOperand(1);
2126 Value *Op2 = II.getArgOperand(2);
2127
2128 for (Value *Src : {Op0, Op1, Op2}) {
2129 if (isa<PoisonValue>(Src))
2130 return IC.replaceInstUsesWith(II, Src);
2131 }
2132
2133 // The legacy behaviour is that multiplying +/-0.0 by anything, even NaN or
2134 // infinity, gives +0.0.
2135 // TODO: Move to InstSimplify?
2136 if (match(Op0, PatternMatch::m_AnyZeroFP()) ||
2138 // It's tempting to just return Op2 here, but that would give the wrong
2139 // result if Op2 was -0.0.
2140 auto *Zero = ConstantFP::getZero(II.getType());
2141 auto *FAdd = IC.Builder.CreateFAddFMF(Zero, Op2, &II);
2142 FAdd->takeName(&II);
2143 return IC.replaceInstUsesWith(II, FAdd);
2144 }
2145
2146 // If we can prove we don't have one of the special cases then we can use a
2147 // normal fma instead.
2148 if (canSimplifyLegacyMulToMul(II, Op0, Op1, IC)) {
2149 II.setCalledOperand(Intrinsic::getOrInsertDeclaration(
2150 II.getModule(), Intrinsic::fma, II.getType()));
2151 return &II;
2152 }
2153 break;
2154 }
2155 case Intrinsic::amdgcn_is_shared:
2156 case Intrinsic::amdgcn_is_private: {
2157 Value *Src = II.getArgOperand(0);
2158 if (isa<PoisonValue>(Src))
2159 return IC.replaceInstUsesWith(II, PoisonValue::get(II.getType()));
2160 if (isa<UndefValue>(Src))
2161 return IC.replaceInstUsesWith(II, UndefValue::get(II.getType()));
2162
2163 if (isa<ConstantPointerNull>(II.getArgOperand(0)))
2164 return IC.replaceInstUsesWith(II, ConstantInt::getFalse(II.getType()));
2165 break;
2166 }
2167 case Intrinsic::amdgcn_make_buffer_rsrc: {
2168 Value *Src = II.getArgOperand(0);
2169 if (isa<PoisonValue>(Src))
2170 return IC.replaceInstUsesWith(II, PoisonValue::get(II.getType()));
2171
2172 // Normalize num_records to the correct width.
2173 std::optional<unsigned> Width = ST->getBufferResourceNumRecordsWidth();
2174 if (!Width)
2175 return std::nullopt;
2176 Type *NumRecordsTy = IC.Builder.getIntNTy(*Width);
2177 if (II.getArgOperand(2)->getType() == NumRecordsTy)
2178 return std::nullopt;
2179 SmallVector<Value *, 4> Args(II.args());
2180 Args[2] = IC.Builder.CreateZExtOrTrunc(Args[2], NumRecordsTy);
2182 Intrinsic::amdgcn_make_buffer_rsrc,
2183 {II.getType(), Src->getType(), NumRecordsTy}, Args);
2184 NewCall->copyMetadata(II);
2185 NewCall->setTailCallKind(II.getTailCallKind());
2186 // Copy over all attributes except those on num_records, which may no longer
2187 // be valid.
2188 NewCall->setAttributes(
2189 II.getAttributes().removeParamAttributes(II.getContext(), 2));
2190 NewCall->takeName(&II);
2191 return IC.replaceInstUsesWith(II, NewCall);
2192 }
2193 case Intrinsic::amdgcn_raw_buffer_store_format:
2194 case Intrinsic::amdgcn_raw_ptr_buffer_store_format:
2195 case Intrinsic::amdgcn_struct_buffer_store_format:
2196 case Intrinsic::amdgcn_struct_ptr_buffer_store_format:
2197 case Intrinsic::amdgcn_raw_tbuffer_store:
2198 case Intrinsic::amdgcn_raw_ptr_tbuffer_store:
2199 case Intrinsic::amdgcn_struct_tbuffer_store:
2200 case Intrinsic::amdgcn_struct_ptr_tbuffer_store:
2201 case Intrinsic::amdgcn_image_store_1d:
2202 case Intrinsic::amdgcn_image_store_1darray:
2203 case Intrinsic::amdgcn_image_store_2d:
2204 case Intrinsic::amdgcn_image_store_2darray:
2205 case Intrinsic::amdgcn_image_store_2darraymsaa:
2206 case Intrinsic::amdgcn_image_store_2dmsaa:
2207 case Intrinsic::amdgcn_image_store_3d:
2208 case Intrinsic::amdgcn_image_store_cube:
2209 case Intrinsic::amdgcn_image_store_mip_1d:
2210 case Intrinsic::amdgcn_image_store_mip_1darray:
2211 case Intrinsic::amdgcn_image_store_mip_2d:
2212 case Intrinsic::amdgcn_image_store_mip_2darray:
2213 case Intrinsic::amdgcn_image_store_mip_3d:
2214 case Intrinsic::amdgcn_image_store_mip_cube: {
2215 if (!isa<FixedVectorType>(II.getArgOperand(0)->getType()))
2216 break;
2217
2218 APInt DemandedElts;
2219 if (ST->hasDefaultComponentBroadcast())
2220 DemandedElts = defaultComponentBroadcast(II.getArgOperand(0));
2221 else if (ST->hasDefaultComponentZero())
2222 DemandedElts = trimTrailingZerosInVector(IC, II.getArgOperand(0), &II);
2223 else
2224 break;
2225
2226 int DMaskIdx = getAMDGPUImageDMaskIntrinsic(II.getIntrinsicID()) ? 1 : -1;
2227 if (simplifyAMDGCNMemoryIntrinsicDemanded(IC, II, DemandedElts, DMaskIdx,
2228 false)) {
2229 return IC.eraseInstFromFunction(II);
2230 }
2231
2232 break;
2233 }
2234 case Intrinsic::amdgcn_prng_b32: {
2235 auto *Src = II.getArgOperand(0);
2236 if (isa<UndefValue>(Src)) {
2237 return IC.replaceInstUsesWith(II, Src);
2238 }
2239 return std::nullopt;
2240 }
2241 case Intrinsic::amdgcn_mfma_scale_f32_16x16x128_f8f6f4:
2242 case Intrinsic::amdgcn_mfma_scale_f32_32x32x64_f8f6f4: {
2243 Value *Src0 = II.getArgOperand(0);
2244 Value *Src1 = II.getArgOperand(1);
2245 uint64_t CBSZ = cast<ConstantInt>(II.getArgOperand(3))->getZExtValue();
2246 uint64_t BLGP = cast<ConstantInt>(II.getArgOperand(4))->getZExtValue();
2247 auto *Src0Ty = cast<FixedVectorType>(Src0->getType());
2248 auto *Src1Ty = cast<FixedVectorType>(Src1->getType());
2249
2250 auto getFormatNumRegs = [](uint64_t FormatVal) {
2251 switch (FormatVal) {
2254 return 6u;
2256 return 4u;
2259 return 8u;
2260 default:
2261 llvm_unreachable("invalid format value");
2262 }
2263 };
2264
2265 bool MadeChange = false;
2266 unsigned Src0NumElts = getFormatNumRegs(CBSZ);
2267 unsigned Src1NumElts = getFormatNumRegs(BLGP);
2268
2269 // Depending on the used format, fewer registers are required so shrink the
2270 // vector type.
2271 if (Src0Ty->getNumElements() > Src0NumElts) {
2272 Src0 = IC.Builder.CreateExtractVector(
2273 FixedVectorType::get(Src0Ty->getElementType(), Src0NumElts), Src0,
2274 uint64_t(0));
2275 MadeChange = true;
2276 }
2277
2278 if (Src1Ty->getNumElements() > Src1NumElts) {
2279 Src1 = IC.Builder.CreateExtractVector(
2280 FixedVectorType::get(Src1Ty->getElementType(), Src1NumElts), Src1,
2281 uint64_t(0));
2282 MadeChange = true;
2283 }
2284
2285 if (!MadeChange)
2286 return std::nullopt;
2287
2288 SmallVector<Value *, 10> Args(II.args());
2289 Args[0] = Src0;
2290 Args[1] = Src1;
2291
2292 Value *NewII = IC.Builder.CreateIntrinsic(
2293 IID, {Src0->getType(), Src1->getType()}, Args, &II);
2294 NewII->takeName(&II);
2295 return IC.replaceInstUsesWith(II, NewII);
2296 }
2297 case Intrinsic::amdgcn_wmma_f32_16x16x128_f8f6f4:
2298 case Intrinsic::amdgcn_wmma_scale_f32_16x16x128_f8f6f4:
2299 case Intrinsic::amdgcn_wmma_scale16_f32_16x16x128_f8f6f4: {
2300 Value *Src0 = II.getArgOperand(1);
2301 Value *Src1 = II.getArgOperand(3);
2302 unsigned FmtA = cast<ConstantInt>(II.getArgOperand(0))->getZExtValue();
2303 uint64_t FmtB = cast<ConstantInt>(II.getArgOperand(2))->getZExtValue();
2304 auto *Src0Ty = cast<FixedVectorType>(Src0->getType());
2305 auto *Src1Ty = cast<FixedVectorType>(Src1->getType());
2306
2307 bool MadeChange = false;
2308 unsigned Src0NumElts = AMDGPU::wmmaScaleF8F6F4FormatToNumRegs(FmtA);
2309 unsigned Src1NumElts = AMDGPU::wmmaScaleF8F6F4FormatToNumRegs(FmtB);
2310
2311 // Depending on the used format, fewer registers are required so shrink the
2312 // vector type.
2313 if (Src0Ty->getNumElements() > Src0NumElts) {
2314 Src0 = IC.Builder.CreateExtractVector(
2315 FixedVectorType::get(Src0Ty->getElementType(), Src0NumElts), Src0,
2316 IC.Builder.getInt64(0));
2317 MadeChange = true;
2318 }
2319
2320 if (Src1Ty->getNumElements() > Src1NumElts) {
2321 Src1 = IC.Builder.CreateExtractVector(
2322 FixedVectorType::get(Src1Ty->getElementType(), Src1NumElts), Src1,
2323 IC.Builder.getInt64(0));
2324 MadeChange = true;
2325 }
2326
2327 if (!MadeChange)
2328 return std::nullopt;
2329
2330 SmallVector<Value *, 13> Args(II.args());
2331 Args[1] = Src0;
2332 Args[3] = Src1;
2333
2334 Value *NewII = IC.Builder.CreateIntrinsic(
2335 IID, {II.getArgOperand(5)->getType(), Src0->getType(), Src1->getType()},
2336 Args, &II);
2337 NewII->takeName(&II);
2338 return IC.replaceInstUsesWith(II, NewII);
2339 }
2340 }
2341 if (const AMDGPU::ImageDimIntrinsicInfo *ImageDimIntr =
2342 AMDGPU::getImageDimIntrinsicInfo(II.getIntrinsicID())) {
2343 return simplifyAMDGCNImageIntrinsic(ST, ImageDimIntr, II, IC);
2344 }
2345 if (std::optional<unsigned> ScaleArgIdx =
2347 if (simplifyExponentOnlyScaleArg(IC, II, *ScaleArgIdx))
2348 return &II;
2349 }
2350 return std::nullopt;
2351}
2352
2353/// Implement SimplifyDemandedVectorElts for amdgcn buffer and image intrinsics.
2354///
2355/// The result of simplifying amdgcn image and buffer store intrinsics is updating
2356/// definitions of the intrinsics vector argument, not Uses of the result like
2357/// image and buffer loads.
2358/// Note: This only supports non-TFE/LWE image intrinsic calls; those have
2359/// struct returns.
2362 APInt DemandedElts,
2363 int DMaskIdx, bool IsLoad) {
2364
2365 auto *IIVTy = cast<FixedVectorType>(IsLoad ? II.getType()
2366 : II.getOperand(0)->getType());
2367 unsigned VWidth = IIVTy->getNumElements();
2368 if (VWidth == 1)
2369 return nullptr;
2370 Type *EltTy = IIVTy->getElementType();
2371
2374
2375 // Assume the arguments are unchanged and later override them, if needed.
2376 SmallVector<Value *, 16> Args(II.args());
2377 uint64_t OffsetAdd = 0;
2378
2379 if (DMaskIdx < 0) {
2380 // Buffer case.
2381
2382 const unsigned ActiveBits = DemandedElts.getActiveBits();
2383 const unsigned UnusedComponentsAtFront = DemandedElts.countr_zero();
2384
2385 // Start assuming the prefix of elements is demanded, but possibly clear
2386 // some other bits if there are trailing zeros (unused components at front)
2387 // and update offset.
2388 DemandedElts = (1 << ActiveBits) - 1;
2389
2390 if (UnusedComponentsAtFront > 0) {
2391 static const unsigned InvalidOffsetIdx = 0xf;
2392
2393 unsigned OffsetIdx;
2394 switch (II.getIntrinsicID()) {
2395 case Intrinsic::amdgcn_raw_buffer_load:
2396 case Intrinsic::amdgcn_raw_ptr_buffer_load:
2397 OffsetIdx = 1;
2398 break;
2399 case Intrinsic::amdgcn_s_buffer_load:
2400 case Intrinsic::amdgcn_ptr_s_buffer_load:
2401 // If resulting type is vec3, there is no point in trimming the
2402 // load with updated offset, as the vec3 would most likely be widened to
2403 // vec4 anyway during lowering.
2404 if (ActiveBits == 4 && UnusedComponentsAtFront == 1)
2405 OffsetIdx = InvalidOffsetIdx;
2406 else
2407 OffsetIdx = 1;
2408 break;
2409 case Intrinsic::amdgcn_struct_buffer_load:
2410 case Intrinsic::amdgcn_struct_ptr_buffer_load:
2411 OffsetIdx = 2;
2412 break;
2413 default:
2414 // TODO: handle tbuffer* intrinsics.
2415 OffsetIdx = InvalidOffsetIdx;
2416 break;
2417 }
2418
2419 if (OffsetIdx != InvalidOffsetIdx) {
2420 // Clear demanded bits and update the offset.
2421 DemandedElts &= ~((1 << UnusedComponentsAtFront) - 1);
2422 auto *Offset = Args[OffsetIdx];
2423 uint64_t SingleComponentSizeInBits =
2425 OffsetAdd = UnusedComponentsAtFront * SingleComponentSizeInBits / 8;
2426 auto *OffsetAddVal = ConstantInt::get(Offset->getType(), OffsetAdd);
2427 Args[OffsetIdx] = IC.Builder.CreateAdd(Offset, OffsetAddVal);
2428 }
2429 }
2430 } else {
2431 // Image case.
2432
2433 ConstantInt *DMask = cast<ConstantInt>(Args[DMaskIdx]);
2434 unsigned DMaskVal = DMask->getZExtValue() & 0xf;
2435
2436 // dmask 0 has special semantics, do not simplify.
2437 if (DMaskVal == 0)
2438 return nullptr;
2439
2440 if (!IsLoad && !isMask_32(DMaskVal))
2441 return nullptr;
2442
2443 // Mask off values that are undefined because the dmask doesn't cover them
2444 DemandedElts &= (1 << llvm::popcount(DMaskVal)) - 1;
2445
2446 unsigned NewDMaskVal = 0;
2447 unsigned OrigLdStIdx = 0;
2448 for (unsigned SrcIdx = 0; SrcIdx < 4; ++SrcIdx) {
2449 const unsigned Bit = 1 << SrcIdx;
2450 if (!!(DMaskVal & Bit)) {
2451 if (!!DemandedElts[OrigLdStIdx])
2452 NewDMaskVal |= Bit;
2453 OrigLdStIdx++;
2454 }
2455 }
2456
2457 if (DMaskVal != NewDMaskVal)
2458 Args[DMaskIdx] = ConstantInt::get(DMask->getType(), NewDMaskVal);
2459 }
2460
2461 unsigned NewNumElts = DemandedElts.popcount();
2462 if (!NewNumElts)
2463 return PoisonValue::get(IIVTy);
2464
2465 if (NewNumElts >= VWidth && DemandedElts.isMask()) {
2466 if (DMaskIdx >= 0)
2467 II.setArgOperand(DMaskIdx, Args[DMaskIdx]);
2468 return nullptr;
2469 }
2470
2471 // Validate function argument and return types, extracting overloaded types
2472 // along the way.
2473 SmallVector<Type *, 6> OverloadTys;
2474 if (!Intrinsic::isSignatureValid(II.getCalledFunction(), OverloadTys))
2475 return nullptr;
2476
2477 Type *NewTy =
2478 (NewNumElts == 1) ? EltTy : FixedVectorType::get(EltTy, NewNumElts);
2479 OverloadTys[0] = NewTy;
2480
2481 if (!IsLoad) {
2482 SmallVector<int, 8> EltMask;
2483 for (unsigned OrigStoreIdx = 0; OrigStoreIdx < VWidth; ++OrigStoreIdx)
2484 if (DemandedElts[OrigStoreIdx])
2485 EltMask.push_back(OrigStoreIdx);
2486
2487 if (NewNumElts == 1)
2488 Args[0] = IC.Builder.CreateExtractElement(II.getOperand(0), EltMask[0]);
2489 else
2490 Args[0] = IC.Builder.CreateShuffleVector(II.getOperand(0), EltMask);
2491 }
2492
2494 II.getIntrinsicID(), OverloadTys, Args);
2495 NewCall->takeName(&II);
2496 NewCall->copyMetadata(II);
2497 AttributeList OldAttrList = II.getAttributes();
2498 NewCall->setAttributes(OldAttrList);
2499
2500 if (OffsetAdd != 0) {
2501 unsigned RsrcArg =
2502 AMDGPU::lookupRsrcIntrinsic(II.getIntrinsicID())->RsrcArg;
2503 if (MaybeAlign RsrcAlign = NewCall->getParamAlign(RsrcArg)) {
2504 NewCall->removeParamAttr(RsrcArg, Attribute::Alignment);
2505 NewCall->addParamAttr(
2506 RsrcArg,
2508 commonAlignment(*RsrcAlign, OffsetAdd)));
2509 }
2510 }
2511
2512 if (IsLoad) {
2513 if (NewNumElts == 1) {
2514 return IC.Builder.CreateInsertElement(PoisonValue::get(IIVTy), NewCall,
2515 DemandedElts.countr_zero());
2516 }
2517
2518 SmallVector<int, 8> EltMask;
2519 unsigned NewLoadIdx = 0;
2520 for (unsigned OrigLoadIdx = 0; OrigLoadIdx < VWidth; ++OrigLoadIdx) {
2521 if (!!DemandedElts[OrigLoadIdx])
2522 EltMask.push_back(NewLoadIdx++);
2523 else
2524 EltMask.push_back(NewNumElts);
2525 }
2526
2527 auto *Shuffle = IC.Builder.CreateShuffleVector(NewCall, EltMask);
2528
2529 return Shuffle;
2530 }
2531
2532 return NewCall;
2533}
2534
2536 InstCombiner &IC, IntrinsicInst &II, const APInt &DemandedElts,
2537 APInt &UndefElts) const {
2538 auto *VT = dyn_cast<FixedVectorType>(II.getType());
2539 if (!VT)
2540 return nullptr;
2541
2542 const unsigned FirstElt = DemandedElts.countr_zero();
2543 const unsigned LastElt = DemandedElts.getActiveBits() - 1;
2544 const unsigned MaskLen = LastElt - FirstElt + 1;
2545
2546 unsigned OldNumElts = VT->getNumElements();
2547 if (MaskLen == OldNumElts && MaskLen != 1)
2548 return nullptr;
2549
2550 Type *EltTy = VT->getElementType();
2551 Type *NewVT = MaskLen == 1 ? EltTy : FixedVectorType::get(EltTy, MaskLen);
2552
2553 // Theoretically we should support these intrinsics for any legal type. Avoid
2554 // introducing cases that aren't direct register types like v3i16.
2555 if (!isTypeLegal(NewVT))
2556 return nullptr;
2557
2558 Value *Src = II.getArgOperand(0);
2559
2560 // Make sure convergence tokens are preserved.
2561 // TODO: CreateIntrinsic should allow directly copying bundles
2563 II.getOperandBundlesAsDefs(OpBundles);
2564
2565 Module *M = IC.Builder.getModule();
2566 Function *Remangled =
2567 Intrinsic::getOrInsertDeclaration(M, II.getIntrinsicID(), {NewVT});
2568
2569 if (MaskLen == 1) {
2570 Value *Extract = IC.Builder.CreateExtractElement(Src, FirstElt);
2571
2572 // TODO: Preserve callsite attributes?
2573 CallInst *NewCall = IC.Builder.CreateCall(Remangled, {Extract}, OpBundles);
2574
2575 return IC.Builder.CreateInsertElement(PoisonValue::get(II.getType()),
2576 NewCall, FirstElt);
2577 }
2578
2579 SmallVector<int> ExtractMask(MaskLen, -1);
2580 for (unsigned I = 0; I != MaskLen; ++I) {
2581 if (DemandedElts[FirstElt + I])
2582 ExtractMask[I] = FirstElt + I;
2583 }
2584
2585 Value *Extract = IC.Builder.CreateShuffleVector(Src, ExtractMask);
2586
2587 // TODO: Preserve callsite attributes?
2588 CallInst *NewCall = IC.Builder.CreateCall(Remangled, {Extract}, OpBundles);
2589
2590 SmallVector<int> InsertMask(OldNumElts, -1);
2591 for (unsigned I = 0; I != MaskLen; ++I) {
2592 if (DemandedElts[FirstElt + I])
2593 InsertMask[FirstElt + I] = I;
2594 }
2595
2596 // FIXME: If the call has a convergence bundle, we end up leaving the dead
2597 // call behind.
2598 return IC.Builder.CreateShuffleVector(NewCall, InsertMask);
2599}
2600
2602 InstCombiner &IC, IntrinsicInst &II, APInt DemandedElts, APInt &UndefElts,
2603 APInt &UndefElts2, APInt &UndefElts3,
2604 std::function<void(Instruction *, unsigned, APInt, APInt &)>
2605 SimplifyAndSetOp) const {
2606 switch (II.getIntrinsicID()) {
2607 case Intrinsic::amdgcn_readfirstlane:
2608 SimplifyAndSetOp(&II, 0, DemandedElts, UndefElts);
2609 return simplifyAMDGCNLaneIntrinsicDemanded(IC, II, DemandedElts, UndefElts);
2610 case Intrinsic::amdgcn_raw_buffer_load:
2611 case Intrinsic::amdgcn_raw_ptr_buffer_load:
2612 case Intrinsic::amdgcn_raw_buffer_load_format:
2613 case Intrinsic::amdgcn_raw_ptr_buffer_load_format:
2614 case Intrinsic::amdgcn_raw_tbuffer_load:
2615 case Intrinsic::amdgcn_raw_ptr_tbuffer_load:
2616 case Intrinsic::amdgcn_s_buffer_load:
2617 case Intrinsic::amdgcn_ptr_s_buffer_load:
2618 case Intrinsic::amdgcn_struct_buffer_load:
2619 case Intrinsic::amdgcn_struct_ptr_buffer_load:
2620 case Intrinsic::amdgcn_struct_buffer_load_format:
2621 case Intrinsic::amdgcn_struct_ptr_buffer_load_format:
2622 case Intrinsic::amdgcn_struct_tbuffer_load:
2623 case Intrinsic::amdgcn_struct_ptr_tbuffer_load:
2624 return simplifyAMDGCNMemoryIntrinsicDemanded(IC, II, DemandedElts);
2625 default: {
2626 if (getAMDGPUImageDMaskIntrinsic(II.getIntrinsicID())) {
2627 return simplifyAMDGCNMemoryIntrinsicDemanded(IC, II, DemandedElts, 0);
2628 }
2629 break;
2630 }
2631 }
2632 return std::nullopt;
2633}
for(const MachineOperand &MO :llvm::drop_begin(OldMI.operands(), Desc.getNumOperands()))
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
uint64_t uint64_t
uint64_t Imm
static Value * createPermlane16(IRBuilderBase &B, Value *Val, uint32_t Lo, uint32_t Hi)
Emit v_permlane16 with the precomputed lane-select halves.
static std::optional< unsigned > matchRowSharePattern(ArrayRef< uint8_t > Ids)
Match a row-share pattern: all 16 lanes of each row read the same source lane.
static bool matchMirrorPattern(ArrayRef< uint8_t > Ids)
Match an N-lane reversal (mirror) pattern.
static bool canSafelyConvertTo16Bit(Value &V, bool IsFloat, bool AllowI16SExt=false)
static bool tryBuildShuffleMap(Value *Index, const GCNSubtarget &ST, SmallVectorImpl< uint8_t > &Ids, const DataLayout &DL)
Build the per-lane shuffle map by evaluating Index for every lane in the wave.
static std::optional< unsigned > matchQuadPermPattern(ArrayRef< uint8_t > Ids)
Match a 4-lane (quad) permutation, encoded as the v_mov_b32_dpp QUAD_PERM control word: bits[1:0]=Ids...
static std::optional< unsigned > matchDsSwizzleRotatePattern(ArrayRef< uint8_t > Ids)
Match a GFX9+ DS_SWIZZLE rotate-mode permutation: a cyclic left-rotation of all 32 lanes within each ...
static std::optional< unsigned > matchHalfRowPermPattern(ArrayRef< uint8_t > Ids)
Match an 8-lane arbitrary permutation, encoded as the v_mov_b32_dpp8 24-bit selector (three bits per ...
static std::optional< unsigned > matchRowXMaskPattern(ArrayRef< uint8_t > Ids)
Match an XOR mask pattern within each 16-lane row: Ids[J] == Mask ^ J, with Mask in [1,...
static constexpr auto matchHalfRowMirrorPattern
static Value * createPermlaneX16(IRBuilderBase &B, Value *Val, uint32_t Lo, uint32_t Hi)
Emit v_permlanex16 with the precomputed lane-select halves.
static bool isRowPattern(ArrayRef< uint8_t > Ids)
Match an N-lane row pattern: each lane in [0, N) reads from a source lane in the same N-lane row,...
static bool canContractSqrtToRsq(const FPMathOperator *SqrtOp)
Return true if it's legal to contract llvm.amdgcn.rcp(llvm.sqrt)
static CallInst * rewriteCall(IRBuilderBase &B, CallInst &Old, Function &NewCallee, ArrayRef< Value * > Ops)
static Value * convertTo16Bit(Value &V, InstCombiner::BuilderTy &Builder)
static constexpr auto isFullRowPattern
static constexpr auto isQuadPattern
static APInt trimTrailingZerosInVector(InstCombiner &IC, Value *UseV, Instruction *I)
static uint64_t computePermlane16Masks(ArrayRef< uint8_t > Ids)
Pack a 16-lane permutation into a single 64-bit value: four bits per output lane, lane J in bits [J*4...
static bool matchHalfWaveSwapPattern(ArrayRef< uint8_t > Ids)
Match a half-wave swap: lane J reads from lane J ^ 32.
static bool hasPeriodicLayout(ArrayRef< uint8_t > Ids)
Lanes are partitioned into groups of Period; each group is a translated copy of the first: Ids[I] = I...
static std::optional< uint64_t > evalLaneExpr(Value *V, unsigned Lane, const GCNSubtarget &ST, const DataLayout &DL, unsigned Depth=0)
Evaluate V as a function of the lane ID and return its value on Lane, or std::nullopt if V is not a c...
static std::optional< Instruction * > tryOptimizeShufflePattern(InstCombiner &IC, IntrinsicInst &II, const GCNSubtarget &ST)
Try to fold a wave_shuffle/ds_bpermute whose lane index is a constant function of the lane ID into a ...
static constexpr auto isHalfRowPattern
static APInt defaultComponentBroadcast(Value *V)
static std::optional< unsigned > matchDsSwizzleBitmaskPattern(ArrayRef< uint8_t > Ids)
Match a DS_SWIZZLE bitmask-mode permutation: dst_lane = ((src_lane & AND) | OR) ^ XOR with each mask ...
static Value * createDsSwizzle(IRBuilderBase &B, Value *Val, unsigned Offset, const DataLayout &DL)
Emit ds_swizzle with the given immediate, bitcasting/converting between pointer/float types and i32 a...
static std::optional< Instruction * > modifyIntrinsicCall(IntrinsicInst &OldIntr, Instruction &InstToReplace, unsigned NewIntr, InstCombiner &IC, std::function< void(SmallVectorImpl< Value * > &, SmallVectorImpl< Type * > &)> Func)
Applies Func(OldIntr.Args, OldIntr.ArgTys), creates intrinsic call with modified arguments (based on ...
static Value * matchShuffleToHWIntrinsic(IRBuilderBase &B, Value *Src, ArrayRef< uint8_t > Ids, const GCNSubtarget &ST, const DataLayout &DL)
Given a shuffle map, try to emit the best hardware intrinsic.
static std::optional< unsigned > matchRowRotatePattern(ArrayRef< uint8_t > Ids)
Match a 16-lane cyclic rotation; returns the rotation amount in [1, 15].
static bool isCrossRowPattern(ArrayRef< uint8_t > Ids)
Match a cross-row permutation suitable for v_permlanex16: every lane in the low 16-lane half reads fr...
static bool isThreadID(const GCNSubtarget &ST, Value *V)
static Value * createUpdateDpp(IRBuilderBase &B, Value *Val, unsigned Ctrl)
Emit v_mov_b32_dpp with the given control word, row/bank masks 0xF, and bound_ctrl=1 so out-of-bounds...
static APFloat fmed3AMDGCN(const APFloat &Src0, const APFloat &Src1, const APFloat &Src2)
static Value * simplifyAMDGCNMemoryIntrinsicDemanded(InstCombiner &IC, IntrinsicInst &II, APInt DemandedElts, int DMaskIdx=-1, bool IsLoad=true)
Implement SimplifyDemandedVectorElts for amdgcn buffer and image intrinsics.
static std::optional< Instruction * > simplifyAMDGCNImageIntrinsic(const GCNSubtarget *ST, const AMDGPU::ImageDimIntrinsicInfo *ImageDimIntr, IntrinsicInst &II, InstCombiner &IC)
static Value * createMovDpp8(IRBuilderBase &B, Value *Val, unsigned Selector)
Emit v_mov_b32_dpp8 with the given 24-bit lane selector.
static Instruction * foldAddIntoDotAccumulator(IntrinsicInst &II, unsigned AccIdx, unsigned ClampIdx, InstCombiner &IC)
Try to fold an addition into the accumulator when saturation is disabled.
static Value * matchFPExtFromF16(Value *Arg)
Match an fpext from half to float, or a constant we can convert.
static constexpr auto matchFullRowMirrorPattern
static bool simplifyExponentOnlyScaleArg(InstCombiner &IC, IntrinsicInst &II, unsigned ScaleArgIdx)
Simplify the f32 scale operand of a V_CVT_SCALEF32_* conversion, of which only the exponent field is ...
static Value * createPermlane64(IRBuilderBase &B, Value *Val)
Emit v_permlane64 (swap of the two 32-lane halves of a wave64).
Contains the definition of a TargetInstrInfo class that is common to all AMD GPUs.
This file a TargetTransformInfoImplBase conforming object specific to the AMDGPU target machine.
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
#define X(NUM, ENUM, NAME)
Definition ELF.h:665
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
Utilities for dealing with flags related to floating point properties and mode controls.
AMD GCN specific subclass of TargetSubtarget.
This file provides the interface for the instcombine pass implementation.
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
uint64_t IntrinsicInst * II
if(PassOpts->AAPipeline)
int64_t C1
int64_t C0
MachineInstr *& Lo
This file contains some templates that are useful if you are working with the STL at all.
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
Value * RHS
Value * LHS
static const fltSemantics & IEEEsingle()
Definition APFloat.h:304
static constexpr roundingMode rmTowardZero
Definition APFloat.h:365
static constexpr roundingMode rmNearestTiesToEven
Definition APFloat.h:361
static const fltSemantics & IEEEhalf()
Definition APFloat.h:302
static APFloat getQNaN(const fltSemantics &Sem, bool Negative=false, const APInt *payload=nullptr)
Factory for QNaN values.
Definition APFloat.h:1224
LLVM_ABI opStatus convert(const fltSemantics &ToSemantics, roundingMode RM, bool *losesInfo)
Definition APFloat.cpp:6045
bool bitwiseIsEqual(const APFloat &RHS) const
Definition APFloat.h:1548
bool isPosInfinity() const
Definition APFloat.h:1596
APFloat makeQuiet() const
Assuming this is an IEEE-754 NaN value, quiet its signaling bit.
Definition APFloat.h:1420
bool isNaN() const
Definition APFloat.h:1581
bool isSignaling() const
Definition APFloat.h:1585
APInt bitcastToAPInt() const
Definition APFloat.h:1475
static APFloat getZero(const fltSemantics &Sem, bool Negative=false)
Factory for Positive and Negative Zero.
Definition APFloat.h:1183
bool isInfinity() const
Definition APFloat.h:1580
Class for arbitrary precision integers.
Definition APInt.h:78
static APInt getAllOnes(unsigned numBits)
Return an APInt of a specified width with all bits set.
Definition APInt.h:230
void clearBit(unsigned BitPosition)
Set a given bit to 0.
Definition APInt.h:1426
unsigned popcount() const
Count the number of bits set.
Definition APInt.h:1690
LLVM_ABI uint64_t extractBitsAsZExtValue(unsigned numBits, unsigned bitPosition) const
Definition APInt.cpp:517
unsigned getActiveBits() const
Compute the number of active bits in the value.
Definition APInt.h:1532
bool isZero() const
Determine if this value is zero, i.e. all bits are clear.
Definition APInt.h:376
unsigned countr_zero() const
Count the number of trailing zero bits.
Definition APInt.h:1659
bool isMask(unsigned numBits) const
Definition APInt.h:484
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
ArrayRef< T > take_front(size_t N=1) const
Return a copy of *this with only the first N elements.
Definition ArrayRef.h:218
size_t size() const
Get the array size.
Definition ArrayRef.h:141
static LLVM_ABI Attribute getWithDereferenceableBytes(LLVMContext &Context, uint64_t Bytes)
static LLVM_ABI Attribute getWithAlignment(LLVMContext &Context, Align Alignment)
Return a uniquified Attribute object that has the specific alignment set.
bool isTypeLegal(Type *Ty) const override
LLVM_ABI void getOperandBundlesAsDefs(SmallVectorImpl< OperandBundleDef > &Defs) const
Return the list of operand bundles attached to this instruction as a vector of OperandBundleDefs.
void removeParamAttr(unsigned ArgNo, Attribute::AttrKind Kind)
Removes the attribute from the given argument.
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
MaybeAlign getParamAlign(unsigned ArgNo) const
Extract the alignment for a call or parameter (0=unknown).
void setAttributes(AttributeList A)
Set the attributes for this call.
iterator_range< User::op_iterator > args()
Iteration adapter for range-for loops.
AttributeList getAttributes() const
Return the attributes for this call.
void addParamAttr(unsigned ArgNo, Attribute::AttrKind Kind)
Adds the attribute to the indicated argument.
This class represents a function call, abstracting a target machine's calling convention.
void setTailCallKind(TailCallKind TCK)
ConstantFP - Floating Point Values [float, double].
Definition Constants.h:420
const APFloat & getValueAPF() const
Definition Constants.h:463
static LLVM_ABI ConstantFP * getZero(Type *Ty, bool Negative=false)
static LLVM_ABI ConstantFP * getNaN(Type *Ty, bool Negative=false, uint64_t Payload=0)
static LLVM_ABI ConstantFP * getInfinity(Type *Ty, bool Negative=false)
This is the shared class of boolean and integer constants.
Definition Constants.h:87
static ConstantInt * getSigned(IntegerType *Ty, int64_t V, bool ImplicitTrunc=false)
Return a ConstantInt with the specified value for the specified type.
Definition Constants.h:135
static LLVM_ABI ConstantInt * getFalse(LLVMContext &Context)
uint64_t getZExtValue() const
Return the constant as a 64-bit unsigned integer value after it has been zero extended as appropriate...
Definition Constants.h:168
const APInt & getValue() const
Return the constant as an APInt value reference.
Definition Constants.h:159
This class represents a range of values.
LLVM_ABI ConstantRange add(const ConstantRange &Other) const
Return a new range representing the possible values resulting from an addition of a value in this ran...
LLVM_ABI bool isFullSet() const
Return true if this set contains all of the elements possible for this data-type.
LLVM_ABI ConstantRange intersectWith(const ConstantRange &CR, PreferredRangeType Type=Smallest) const
Return the range that results from the intersection of this range with another range.
This is an important base class in LLVM.
Definition Constant.h:44
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
A parsed version of the target data layout string in and methods for querying it.
Definition DataLayout.h:64
TypeSize getTypeSizeInBits(Type *Ty) const
Size examples:
Definition DataLayout.h:791
LLVM_ABI bool dominates(const BasicBlock *BB, const Use &U) const
Return true if the (end of the) basic block BB dominates the use U.
Tagged union holding either a T or a Error.
Definition Error.h:485
This class represents an extension of floating point types.
Utility class for floating point operations which can have information about relaxed accuracy require...
Definition Operator.h:202
FastMathFlags getFastMathFlags() const
Convenience function for getting all the fast-math flags.
Definition Operator.h:291
bool hasApproxFunc() const
Test if this operation allows approximations of math library functions or intrinsics.
Definition Operator.h:288
LLVM_ABI float getFPAccuracy() const
Get the maximum error permitted by this operation in ULPs.
Convenience struct for specifying and reasoning about fast-math flags.
Definition FMF.h:23
bool allowContract() const
Definition FMF.h:69
static LLVM_ABI FixedVectorType * get(Type *ElementType, unsigned NumElts)
Definition Type.cpp:843
bool simplifyDemandedLaneMaskArg(InstCombiner &IC, IntrinsicInst &II, unsigned LaneAgIdx) const
Simplify a lane index operand (e.g.
std::optional< Instruction * > instCombineIntrinsic(InstCombiner &IC, IntrinsicInst &II) const override
Instruction * hoistLaneIntrinsicThroughOperand(InstCombiner &IC, IntrinsicInst &II) const
std::optional< Value * > simplifyDemandedVectorEltsIntrinsic(InstCombiner &IC, IntrinsicInst &II, APInt DemandedElts, APInt &UndefElts, APInt &UndefElts2, APInt &UndefElts3, std::function< void(Instruction *, unsigned, APInt, APInt &)> SimplifyAndSetOp) const override
KnownIEEEMode fpenvIEEEMode(const Instruction &I) const
Return KnownIEEEMode::On if we know if the use context can assume "amdgpu-ieee"="true" and KnownIEEEM...
Value * simplifyAMDGCNLaneIntrinsicDemanded(InstCombiner &IC, IntrinsicInst &II, const APInt &DemandedElts, APInt &UndefElts) const
bool canSimplifyLegacyMulToMul(const Instruction &I, const Value *Op0, const Value *Op1, InstCombiner &IC) const
Common base class shared among various IRBuilders.
Definition IRBuilder.h:111
ConstantInt * getInt1(bool V)
Get a constant value representing either true or false.
Definition IRBuilder.h:446
LLVM_ABI CallInst * CreateIntrinsicWithoutFolding(Intrinsic::ID ID, ArrayRef< Type * > OverloadTypes, ArrayRef< Value * > Args, FMFSource FMFSource={}, const Twine &Name="", ArrayRef< OperandBundleDef > OpBundles={})
Create a call to intrinsic ID with Args, mangled using OverloadTypes.
Value * CreateInsertElement(Type *VecTy, Value *NewElt, Value *Idx, const Twine &Name="")
Definition IRBuilder.h:2745
Value * CreateExtractElement(Value *Vec, Value *Idx, const Twine &Name="")
Definition IRBuilder.h:2733
IntegerType * getIntNTy(unsigned N)
Fetch the type representing an N-bit integer.
Definition IRBuilder.h:541
Value * CreateZExtOrTrunc(Value *V, Type *DestTy, const Twine &Name="")
Create a ZExt or Trunc from the integer value V to DestTy.
Definition IRBuilder.h:2215
Value * CreateLShr(Value *LHS, Value *RHS, const Twine &Name="", bool isExact=false)
Definition IRBuilder.h:1534
Value * CreateExtractVector(Type *DstType, Value *SrcVec, Value *Idx, const Twine &Name="")
Create a call to the vector.extract intrinsic.
Definition IRBuilder.h:1114
Module * getModule() const
Get the module.
Definition IRBuilder.h:190
Value * CreateICmpNE(Value *LHS, Value *RHS, const Twine &Name="")
Definition IRBuilder.h:2462
ConstantInt * getInt64(uint64_t C)
Get a constant 64-bit value.
Definition IRBuilder.h:476
Value * CreateMaxNum(Value *LHS, Value *RHS, FMFSource FMFSource={}, const Twine &Name="")
Create call to the maxnum intrinsic.
Definition IRBuilder.h:1045
Value * CreateShl(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
Definition IRBuilder.h:1513
Value * CreateZExt(Value *V, Type *DestTy, const Twine &Name="", bool IsNonNeg=false)
Definition IRBuilder.h:2197
Value * CreateShuffleVector(Value *V1, Value *V2, Value *Mask, const Twine &Name="")
Definition IRBuilder.h:2767
LLVM_ABI Value * CreateIntrinsic(Intrinsic::ID ID, ArrayRef< Type * > OverloadTypes, ArrayRef< Value * > Args, FMFSource FMFSource={}, const Twine &Name="", ArrayRef< OperandBundleDef > OpBundles={}, function_ref< void(CallInst *)> SetFn=[](CallInst *) {})
Variant to create a possibly constant-folded intrinsic.
Value * CreateMaximumNum(Value *LHS, Value *RHS, const Twine &Name="")
Create call to the maximum intrinsic.
Definition IRBuilder.h:1073
Value * CreateMinNum(Value *LHS, Value *RHS, FMFSource FMFSource={}, const Twine &Name="")
Create call to the minnum intrinsic.
Definition IRBuilder.h:1033
Value * CreateAdd(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
Definition IRBuilder.h:1424
CallInst * CreateCall(FunctionType *FTy, Value *Callee, ArrayRef< Value * > Args={}, const Twine &Name="", MDNode *FPMathTag=nullptr)
Definition IRBuilder.h:2637
void SetInsertPoint(BasicBlock *TheBB)
This specifies that created instructions should be appended to the end of the specified block.
Definition IRBuilder.h:197
Value * CreateFAddFMF(Value *L, Value *R, FMFSource FMFSource, const Twine &Name="", MDNode *FPMD=nullptr)
Definition IRBuilder.h:1643
Value * CreateMinimumNum(Value *LHS, Value *RHS, const Twine &Name="")
Create call to the minimumnum intrinsic.
Definition IRBuilder.h:1067
Value * CreateAShr(Value *LHS, Value *RHS, const Twine &Name="", bool isExact=false)
Definition IRBuilder.h:1553
Value * CreateFMulFMF(Value *L, Value *R, FMFSource FMFSource, const Twine &Name="", MDNode *FPMD=nullptr)
Definition IRBuilder.h:1681
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition IRBuilder.h:2987
The core instruction combiner logic.
const DataLayout & getDataLayout() const
virtual Instruction * eraseInstFromFunction(Instruction &I)=0
Combiner aware instruction erasure.
DominatorTree & getDominatorTree() const
Instruction * replaceInstUsesWith(Instruction &I, Value *V)
A combiner-aware RAUW-like routine.
Instruction * InsertNewInstWith(Instruction *New, BasicBlock::iterator Old)
Same as InsertNewInstBefore, but also sets the debug loc.
virtual bool SimplifyDemandedBits(Instruction *I, unsigned OpNo, const APInt &DemandedMask, KnownBits &Known, const SimplifyQuery &Q, unsigned Depth=0)=0
IRBuilder< TargetFolder, IRBuilderInstCombineInserter > BuilderTy
An IRBuilder that automatically inserts new instructions into the worklist.
static Value * stripSignOnlyFPOps(Value *Val)
Ignore all operations which only change the sign of a value, returning the underlying magnitude value...
Instruction * replaceOperand(Instruction &I, unsigned OpNum, Value *V)
Replace operand of instruction and add old operand to the worklist.
const SimplifyQuery & getSimplifyQuery() const
LLVM_ABI void dropUBImplyingAttrsAndMetadata(ArrayRef< unsigned > Keep={})
Drop any attributes or metadata that can cause immediate undefined behavior.
LLVM_ABI Instruction * clone() const
Create a copy of 'this' instruction that is identical in all ways except the following:
LLVM_ABI void copyFastMathFlags(FastMathFlags FMF)
Convenience function for transferring all fast-math flag values to this instruction,...
void dropPoisonGeneratingAnnotations()
Drops flags, attributes and metadata that may generate poison.
LLVM_ABI void copyMetadata(const Instruction &SrcInst, ArrayRef< unsigned > WL=ArrayRef< unsigned >())
Copy metadata from SrcInst to this instruction.
Class to represent integer types.
A wrapper class for inspecting calls to intrinsic functions.
bool isKnownNeverInfOrNaN() const
Return true if it's known this can never be an infinity or nan.
LLVM_ABI bool isKnownNeverLogicalZero(DenormalMode Mode) const
Return true if it's known this can never be interpreted as a zero.
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:68
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
reference emplace_back(ArgTypes &&... Args)
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.
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
bool isPointerTy() const
True if this is an instance of PointerType.
Definition Type.h:277
bool isFloatTy() const
Return true if this is 'float', a 32-bit IEEE fp type.
Definition Type.h:155
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
Definition Type.h:363
static LLVM_ABI IntegerType * getInt16Ty(LLVMContext &C)
Definition Type.cpp:298
bool isHalfTy() const
Return true if this is 'half', a 16-bit IEEE fp type.
Definition Type.h:144
LLVM_ABI Type * getWithNewType(Type *EltTy) const
Given vector type, change the element type, whilst keeping the old number of elements.
bool isFloatingPointTy() const
Return true if this is one of the floating-point types.
Definition Type.h:186
bool isIntegerTy() const
True if this is an instance of IntegerType.
Definition Type.h:252
static LLVM_ABI Type * getHalfTy(LLVMContext &C)
Definition Type.cpp:274
bool isVoidTy() const
Return true if this is 'void'.
Definition Type.h:141
static LLVM_ABI UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
A Use represents the edge between a Value definition and its users.
Definition Use.h:35
const Use & getOperandUse(unsigned i) const
Definition User.h:220
void setOperand(unsigned i, Value *Val)
Definition User.h:212
Value * getOperand(unsigned i) const
Definition User.h:207
LLVM Value Representation.
Definition Value.h:75
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:257
LLVM_ABI bool hasOneUser() const
Return true if there is exactly one user of this value.
Definition Value.cpp:158
LLVMContext & getContext() const
All values hold a context through their type.
Definition Value.h:260
LLVM_ABI void takeName(Value *V)
Transfer the name from V to this value.
Definition Value.cpp:395
constexpr ScalarTy getFixedValue() const
Definition TypeSize.h:201
const ParentTy * getParent() const
Definition ilist_node.h:34
CallInst * Call
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
APInt getExponentOnlyScaleDemandedBits()
LLVM_READONLY const MIMGOffsetMappingInfo * getMIMGOffsetMappingInfo(unsigned Offset)
uint8_t wmmaScaleF8F6F4FormatToNumRegs(unsigned Fmt)
const ImageDimIntrinsicInfo * getImageDimIntrinsicByBaseOpcode(unsigned BaseOpcode, unsigned Dim)
std::optional< unsigned > getExponentOnlyScaleArgIdx(unsigned IntrID)
LLVM_READONLY const MIMGMIPMappingInfo * getMIMGMIPMappingInfo(unsigned MIP)
bool isTriviallyUniform(const Value *V, const Instruction *CtxI)
Return true if we can easily prove that V is uniform at CtxI.
LLVM_READONLY const MIMGBiasMappingInfo * getMIMGBiasMappingInfo(unsigned Bias)
std::optional< APFloat > evaluateRcp(const APFloat &Val)
Evaluate the constant-folded result of v_rcp for Val, accounting for the hardware's denormal flushing...
LLVM_READONLY const MIMGLZMappingInfo * getMIMGLZMappingInfo(unsigned L)
LLVM_READONLY const MIMGDimInfo * getMIMGDimInfo(unsigned DimEnum)
LLVM_READONLY const MIMGBaseOpcodeInfo * getMIMGBaseOpcodeInfo(unsigned BaseOpcode)
const ImageDimIntrinsicInfo * getImageDimIntrinsicInfo(unsigned Intr)
const RsrcIntrinsic * lookupRsrcIntrinsic(unsigned Intr)
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > OverloadTys={})
Look up the Function declaration of the intrinsic id in the Module M.
LLVM_ABI bool isSignatureValid(Intrinsic::ID ID, FunctionType *FT, SmallVectorImpl< Type * > &OverloadTys, raw_ostream &OS=nulls())
Returns true if FT is a valid function type for intrinsic ID.
OneUse_match< SubPat > m_OneUse(const SubPat &SP)
ap_match< APInt > m_APInt(const APInt *&Res)
Match a ConstantInt or splatted ConstantVector, binding the specified pointer to the contained APInt.
BinaryOp_match< LHS, RHS, Instruction::And, true > m_c_And(const LHS &L, const RHS &R)
Matches an And with LHS and RHS in either order.
specific_intval< false > m_SpecificInt(const APInt &V)
Match a specific integer value or vector with all elements equal to the value.
bool match(Val *V, const Pattern &P)
match_bind< Instruction > m_Instruction(Instruction *&I)
Match an instruction, capturing it if we match.
cstfp_pred_ty< is_any_zero_fp > m_AnyZeroFP()
Match a floating-point negative zero or positive zero.
specificval_ty m_Specific(const Value *V)
Match if we have a specific specified value.
ap_match< APFloat > m_APFloat(const APFloat *&Res)
Match a ConstantFP or splatted ConstantVector, binding the specified pointer to the contained APFloat...
TwoOps_match< Val_t, Idx_t, Instruction::ExtractElement > m_ExtractElt(const Val_t &Val, const Idx_t &Idx)
Matches ExtractElementInst.
auto m_Value()
Match an arbitrary value and ignore it.
CastInst_match< OpTy, FPExtInst > m_FPExt(const OpTy &Op)
CastInst_match< OpTy, ZExtInst > m_ZExt(const OpTy &Op)
Matches ZExt.
is_zero< true > m_Zero()
Match any null constant or a vector with all elements equal to 0.
BinaryOp_match< LHS, RHS, Instruction::Add, true > m_c_Add(const LHS &L, const RHS &R)
Matches a Add with LHS and RHS in either order.
auto m_Intrinsic(const Ts &...Ops)
Match intrinsic calls like this: m_Intrinsic<Intrinsic::fabs>(m_Value(X))
auto m_ConstantFP()
Match an arbitrary ConstantFP and ignore it.
CastInst_match< OpTy, SExtInst > m_SExt(const OpTy &Op)
Matches SExt.
auto m_ConstantInt()
Match an arbitrary ConstantInt and ignore it.
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:577
LLVM_ABI KnownFPClass computeKnownFPClass(const Value *V, const APInt &DemandedElts, FPClassTest InterestedClasses, const SimplifyQuery &SQ, unsigned Depth=0)
Determine which floating-point classes are valid for V, and return them in KnownFPClass bit sets.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1755
@ Known
Known to have no common set bits.
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
Definition STLExtras.h:2570
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
constexpr bool isMask_32(uint32_t Value)
Return true if the argument is a non-empty sequence of ones starting at the least significant bit wit...
Definition MathExtras.h:256
constexpr int popcount(T Value) noexcept
Count the number of set bits in a value.
Definition bit.h:156
APFloat frexp(const APFloat &X, int &Exp, APFloat::roundingMode RM)
Equivalent of C standard library function.
Definition APFloat.h:1728
auto dyn_cast_or_null(const Y &Val)
Definition Casting.h:753
LLVM_READONLY APFloat maxnum(const APFloat &A, const APFloat &B)
Implements IEEE-754 2008 maxNum semantics.
Definition APFloat.h:1771
constexpr unsigned MaxAnalysisRecursionDepth
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
Definition MathExtras.h:280
APFloat scalbn(APFloat X, int Exp, APFloat::roundingMode RM)
Returns: X * 2^Exp for integral exponents.
Definition APFloat.h:1716
constexpr uint32_t Hi_32(uint64_t Value)
Return the high 32 bits of a 64 bit value.
Definition MathExtras.h:151
constexpr uint32_t Lo_32(uint64_t Value)
Return the low 32 bits of a 64 bit value.
Definition MathExtras.h:156
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
constexpr int PoisonMaskElem
@ FMul
Product of floats.
@ FAdd
Sum of floats.
LLVM_ABI Value * findScalarElement(Value *V, unsigned EltNo)
Given a vector and an element number, see if the scalar value is already around as a register,...
@ NearestTiesToEven
roundTiesToEven.
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
constexpr auto seq(T Begin, T End)
Iterate over an integral type from Begin up to - but not including - End.
Definition Sequence.h:341
Align commonAlignment(Align A, uint64_t Offset)
Returns the alignment that satisfies both alignments.
Definition Alignment.h:206
bool all_equal(std::initializer_list< T > Values)
Returns true if all Values in the initializer lists are equal or the list.
Definition STLExtras.h:2182
constexpr T maskTrailingOnes(unsigned N)
Create a bitmask with the N right-most bits set to 1, and all other bits set to 0.
Definition MathExtras.h:78
LLVM_ABI Constant * ConstantFoldInstOperands(const Instruction *I, ArrayRef< Constant * > Ops, const DataLayout &DL, const TargetLibraryInfo *TLI=nullptr, bool AllowNonDeterministic=true)
ConstantFoldInstOperands - Attempt to constant fold an instruction with the specified operands.
constexpr uint64_t Make_64(uint32_t High, uint32_t Low)
Make a 64-bit integer from a high / low pair of 32-bit integers.
Definition MathExtras.h:161
LLVM_ABI ConstantRange computeConstantRange(const Value *V, bool ForSigned, const SimplifyQuery &SQ, unsigned Depth=0)
Determine the possible constant range of an integer or vector of integer value.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition BitVector.h:881
#define N
Represent subnormal handling kind for floating point instruction inputs and outputs.
This struct is a compact representation of a valid (power of two) or undefined (0) alignment.
Definition Alignment.h:111
SimplifyQuery getWithInstruction(const Instruction *I) const
LLVM_ABI bool isUndefValue(Value *V) const
If CanUseUndef is true, returns whether V is undef.