15#include "llvm/IR/IntrinsicsAMDGPU.h"
26 TII(*
STI.getInstrInfo()) {}
30 switch (
MI.getOpcode()) {
36 case AMDGPU::G_FMINNUM:
37 case AMDGPU::G_FMAXNUM:
38 case AMDGPU::G_FMINNUM_IEEE:
39 case AMDGPU::G_FMAXNUM_IEEE:
40 case AMDGPU::G_FMINIMUM:
41 case AMDGPU::G_FMAXIMUM:
44 case AMDGPU::G_INTRINSIC_TRUNC:
45 case AMDGPU::G_FPTRUNC:
47 case AMDGPU::G_FNEARBYINT:
48 case AMDGPU::G_INTRINSIC_ROUND:
49 case AMDGPU::G_INTRINSIC_ROUNDEVEN:
50 case AMDGPU::G_FCANONICALIZE:
51 case AMDGPU::G_AMDGPU_RCP_IFLAG:
52 case AMDGPU::G_AMDGPU_FMIN_LEGACY:
53 case AMDGPU::G_AMDGPU_FMAX_LEGACY:
55 case AMDGPU::G_INTRINSIC: {
57 switch (IntrinsicID) {
58 case Intrinsic::amdgcn_rcp:
59 case Intrinsic::amdgcn_rcp_legacy:
60 case Intrinsic::amdgcn_sin:
61 case Intrinsic::amdgcn_fmul_legacy:
62 case Intrinsic::amdgcn_fmed3:
63 case Intrinsic::amdgcn_fma_legacy:
87 if (!
MI.memoperands().empty())
90 switch (
MI.getOpcode()) {
92 case AMDGPU::G_SELECT:
95 case TargetOpcode::INLINEASM:
96 case TargetOpcode::INLINEASM_BR:
97 case AMDGPU::G_INTRINSIC_W_SIDE_EFFECTS:
98 case AMDGPU::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS:
99 case AMDGPU::G_BITCAST:
100 case AMDGPU::G_ANYEXT:
101 case AMDGPU::G_BUILD_VECTOR:
102 case AMDGPU::G_BUILD_VECTOR_TRUNC:
105 case AMDGPU::G_INTRINSIC:
106 case AMDGPU::G_INTRINSIC_CONVERGENT: {
108 switch (IntrinsicID) {
109 case Intrinsic::amdgcn_interp_p1:
110 case Intrinsic::amdgcn_interp_p2:
111 case Intrinsic::amdgcn_interp_mov:
112 case Intrinsic::amdgcn_interp_p1_f16:
113 case Intrinsic::amdgcn_interp_p2_f16:
114 case Intrinsic::amdgcn_div_scale:
132 unsigned NumMayIncreaseSize = 0;
154 APInt(64, 0x3fc45f306dc9c882));
164 std::optional<FPValueAndVReg> FPValReg;
166 if (FPValReg->Value.isZero() && !FPValReg->Value.isNegative())
170 if (ST.hasInv2PiInlineImm() &&
isInv2Pi(FPValReg->Value))
182 (
VT->isKnownNeverLogicalZero(LHS) ||
VT->isKnownNeverLogicalZero(RHS));
187 case AMDGPU::G_FMAXNUM:
188 return AMDGPU::G_FMINNUM;
189 case AMDGPU::G_FMINNUM:
190 return AMDGPU::G_FMAXNUM;
191 case AMDGPU::G_FMAXNUM_IEEE:
192 return AMDGPU::G_FMINNUM_IEEE;
193 case AMDGPU::G_FMINNUM_IEEE:
194 return AMDGPU::G_FMAXNUM_IEEE;
195 case AMDGPU::G_FMAXIMUM:
196 return AMDGPU::G_FMINIMUM;
197 case AMDGPU::G_FMINIMUM:
198 return AMDGPU::G_FMAXIMUM;
199 case AMDGPU::G_AMDGPU_FMAX_LEGACY:
200 return AMDGPU::G_AMDGPU_FMIN_LEGACY;
201 case AMDGPU::G_AMDGPU_FMIN_LEGACY:
202 return AMDGPU::G_AMDGPU_FMAX_LEGACY;
211 MatchInfo =
MRI.getVRegDef(Src);
217 if (
MRI.hasOneNonDBGUse(Src)) {
228 case AMDGPU::G_AMDGPU_FMIN_LEGACY:
229 case AMDGPU::G_AMDGPU_FMAX_LEGACY:
237 case AMDGPU::G_FMINNUM:
238 case AMDGPU::G_FMAXNUM:
239 case AMDGPU::G_FMINNUM_IEEE:
240 case AMDGPU::G_FMAXNUM_IEEE:
241 case AMDGPU::G_FMINIMUM:
242 case AMDGPU::G_FMAXIMUM:
252 case AMDGPU::G_FPEXT:
253 case AMDGPU::G_INTRINSIC_TRUNC:
254 case AMDGPU::G_FPTRUNC:
255 case AMDGPU::G_FRINT:
256 case AMDGPU::G_FNEARBYINT:
257 case AMDGPU::G_INTRINSIC_ROUND:
258 case AMDGPU::G_INTRINSIC_ROUNDEVEN:
260 case AMDGPU::G_FCANONICALIZE:
261 case AMDGPU::G_AMDGPU_RCP_IFLAG:
263 case AMDGPU::G_INTRINSIC:
264 case AMDGPU::G_INTRINSIC_CONVERGENT: {
266 switch (IntrinsicID) {
267 case Intrinsic::amdgcn_rcp:
268 case Intrinsic::amdgcn_rcp_legacy:
269 case Intrinsic::amdgcn_sin:
270 case Intrinsic::amdgcn_fmul_legacy:
271 case Intrinsic::amdgcn_fmed3:
273 case Intrinsic::amdgcn_fma_legacy:
303 Reg =
Builder.buildFNeg(
MRI.getType(Reg), Reg).getReg(0);
316 YReg =
Builder.buildFNeg(
MRI.getType(YReg), YReg).getReg(0);
321 Builder.setInstrAndDebugLoc(*MatchInfo);
334 case AMDGPU::G_FMINNUM:
335 case AMDGPU::G_FMAXNUM:
336 case AMDGPU::G_FMINNUM_IEEE:
337 case AMDGPU::G_FMAXNUM_IEEE:
338 case AMDGPU::G_FMINIMUM:
339 case AMDGPU::G_FMAXIMUM:
340 case AMDGPU::G_AMDGPU_FMIN_LEGACY:
341 case AMDGPU::G_AMDGPU_FMAX_LEGACY: {
353 case AMDGPU::G_FPEXT:
354 case AMDGPU::G_INTRINSIC_TRUNC:
355 case AMDGPU::G_FRINT:
356 case AMDGPU::G_FNEARBYINT:
357 case AMDGPU::G_INTRINSIC_ROUND:
358 case AMDGPU::G_INTRINSIC_ROUNDEVEN:
360 case AMDGPU::G_FCANONICALIZE:
361 case AMDGPU::G_AMDGPU_RCP_IFLAG:
362 case AMDGPU::G_FPTRUNC:
365 case AMDGPU::G_INTRINSIC:
366 case AMDGPU::G_INTRINSIC_CONVERGENT: {
368 switch (IntrinsicID) {
369 case Intrinsic::amdgcn_rcp:
370 case Intrinsic::amdgcn_rcp_legacy:
371 case Intrinsic::amdgcn_sin:
374 case Intrinsic::amdgcn_fmul_legacy:
377 case Intrinsic::amdgcn_fmed3:
382 case Intrinsic::amdgcn_fma_legacy:
398 if (
MRI.hasOneNonDBGUse(MatchInfoDst)) {
414 Builder.setInstrAndDebugLoc(*NextInst);
415 Builder.buildFNeg(MatchInfoDst, NegatedMatchInfo,
MI.getFlags());
418 MI.eraseFromParent();
424 if (!
MRI.hasOneNonDBGUse(Round))
436 Builder.setInstrAndDebugLoc(Fabs);
454 bool LosesInfo =
true;
466 assert(
MI.getOpcode() == TargetOpcode::G_FPTRUNC);
487 LLT Ty =
MRI.getType(Src0);
488 auto A1 =
Builder.buildFMinNumIEEE(Ty, Src0, Src1);
489 auto B1 =
Builder.buildFMaxNumIEEE(Ty, Src0, Src1);
490 auto C1 =
Builder.buildFMaxNumIEEE(Ty, A1, Src2);
491 Builder.buildFMinNumIEEE(
MI.getOperand(0), B1, C1);
492 MI.eraseFromParent();
498 assert(
MI.getOpcode() == TargetOpcode::G_FMUL);
503 LLT DestTy =
MRI.getType(Dst);
516 const auto SelectTrueVal =
520 const auto SelectFalseVal =
525 if (SelectTrueVal->isNegative() != SelectFalseVal->isNegative())
530 if (ScalarDestTy ==
LLT::float32() &&
TII.isInlineConstant(*SelectTrueVal) &&
531 TII.isInlineConstant(*SelectFalseVal))
534 int SelectTrueLog2Val = SelectTrueVal->getExactLog2Abs();
535 if (SelectTrueLog2Val == INT_MIN)
537 int SelectFalseLog2Val = SelectFalseVal->getExactLog2Abs();
538 if (SelectFalseLog2Val == INT_MIN)
543 auto NewSel =
Builder.buildSelect(
544 IntDestTy, SelectCondReg,
545 Builder.buildConstant(IntDestTy, SelectTrueLog2Val),
546 Builder.buildConstant(IntDestTy, SelectFalseLog2Val));
549 if (SelectTrueVal->isNegative()) {
551 Builder.buildFNeg(DestTy, XReg,
MRI.getVRegDef(XReg)->getFlags());
552 Builder.buildFLdexp(Dst, NegX, NewSel,
MI.getFlags());
554 Builder.buildFLdexp(Dst, XReg, NewSel,
MI.getFlags());
566 const uint64_t Val = Res->Value.getZExtValue();
567 unsigned MaskIdx = 0;
568 unsigned MaskLen = 0;
573 return MaskLen >= 32 && ((MaskIdx == 0) || (MaskIdx == 64 - MaskLen));
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static LLVM_READONLY bool hasSourceMods(const MachineInstr &MI)
static bool isInv2Pi(const APFloat &APF)
static bool isFPExtFromF16OrConst(const MachineRegisterInfo &MRI, Register Reg)
static bool isConstantCostlierToNegate(MachineInstr &MI, Register Reg, MachineRegisterInfo &MRI)
static bool mayIgnoreSignedZero(const MachineInstr &MI)
static bool allUsesHaveSourceMods(MachineInstr &MI, MachineRegisterInfo &MRI, unsigned CostThreshold=4)
static LLVM_READONLY bool opMustUseVOP3Encoding(const MachineInstr &MI, const MachineRegisterInfo &MRI)
returns true if the operation will definitely need to use a 64-bit encoding, and thus will use a VOP3...
static unsigned inverseMinMax(unsigned Opc)
static LLVM_READNONE bool fnegFoldsIntoMI(const MachineInstr &MI)
This contains common combine transformations that may be used in a combine pass.
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
AMD GCN specific subclass of TargetSubtarget.
Provides analysis for querying information about KnownBits during GISel passes.
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
Interface for Targets to specify which operations they can successfully select and how the others sho...
Contains matchers for matching SSA Machine Instructions.
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
bool matchFoldFAbsFptrunc(MachineInstr &Fabs, MachineInstr &Fptrunc) const
AMDGPUCombinerHelper(GISelChangeObserver &Observer, MachineIRBuilder &B, bool IsPreLegalize, GISelValueTracking *VT, MachineDominatorTree *MDT, const LegalizerInfo *LI, const GCNSubtarget &STI)
bool matchConstantIs32BitMask(Register Reg) const
bool matchCombineFmulWithSelectToFldexp(MachineInstr &MI, MachineInstr &Sel, std::function< void(MachineIRBuilder &)> &MatchInfo) const
LLVM_ABI CombinerHelper(GISelChangeObserver &Observer, MachineIRBuilder &B, bool IsPreLegalize, GISelValueTracking *VT=nullptr, MachineDominatorTree *MDT=nullptr, const LegalizerInfo *LI=nullptr)
bool matchExpandPromotedF16FMed3(MachineInstr &MI, Register Src0, Register Src1, Register Src2) const
void applyFoldableFneg(MachineInstr &MI, MachineInstr *&MatchInfo) const
bool matchFoldableFneg(MachineInstr &MI, MachineInstr *&MatchInfo) const
void applyFoldFAbsFptrunc(MachineInstr &Fabs, MachineInstr &Fptrunc) const
void applyExpandPromotedF16FMed3(MachineInstr &MI, Register Src0, Register Src1, Register Src2) const
bool canIgnoreLegacyMinMaxTies(const MachineInstr &MI, Register LHS, Register RHS) const
fmin_legacy/fmax_legacy select s1 on NaN, and on a +0.0/-0.0 tie (s1 for min, s0 for max).
static const fltSemantics & IEEEsingle()
static const fltSemantics & IEEEdouble()
static constexpr roundingMode rmNearestTiesToEven
static const fltSemantics & IEEEhalf()
LLVM_ABI opStatus convert(const fltSemantics &ToSemantics, roundingMode RM, bool *losesInfo)
bool bitwiseIsEqual(const APFloat &RHS) const
Class for arbitrary precision integers.
LLVM_ABI void replaceRegWith(MachineRegisterInfo &MRI, Register FromReg, Register ToReg) const
MachineRegisterInfo::replaceRegWith() and inform the observer of the changes.
LLVM_ABI void replaceRegOpWith(MachineRegisterInfo &MRI, MachineOperand &FromRegOp, Register ToReg) const
Replace a single register operand with a new register and inform the observer of the changes.
LLVM_ABI void replaceOpcodeWith(MachineInstr &FromMI, unsigned ToOpcode) const
Replace the opcode in instruction with a new opcode and inform the observer of the changes.
MachineRegisterInfo & MRI
LLVM_ABI bool isLegalOrBeforeLegalizer(const LegalityQuery &Query) const
MachineDominatorTree * MDT
GISelChangeObserver & Observer
MachineIRBuilder & Builder
ConstantFP - Floating Point Values [float, double].
const APFloat & getValueAPF() const
Abstract class that contains various methods for clients to notify about changes.
static constexpr LLT float64()
Get a 64-bit IEEE double value.
constexpr unsigned getScalarSizeInBits() const
constexpr LLT changeElementType(LLT NewEltTy) const
If this type is a vector, return a vector with the same number of elements but the new element type.
LLT getScalarType() const
static constexpr LLT float16()
Get a 16-bit IEEE half value.
static LLT integer(unsigned SizeInBits)
static constexpr LLT float32()
Get a 32-bit IEEE float value.
DominatorTree Class - Concrete subclass of DominatorTreeBase that is used to compute a normal dominat...
Helper class to build MachineInstr.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineOperand & getOperand(unsigned i) const
uint32_t getFlags() const
Return the MI flags bitvector.
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
MachineOperand class - Representation of each machine instruction operand.
Register getReg() const
getReg - Returns the register number.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLT getType(Register Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register.
iterator_range< use_instr_nodbg_iterator > use_nodbg_instructions(Register Reg) const
Wrapper class representing virtual and physical registers.
The instances of the Type class are immutable: once they are created, they are never changed.
A Use represents the edge between a Value definition and its users.
self_iterator getIterator()
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
operand_type_match m_Reg()
UnaryOp_match< SrcTy, TargetOpcode::G_FPEXT > m_GFPExt(const SrcTy &Src)
bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P)
UnaryOp_match< SrcTy, TargetOpcode::G_FNEG > m_GFNeg(const SrcTy &Src)
GFCstAndRegMatch m_GFCst(std::optional< FPValueAndVReg > &FPValReg)
GFCstOrSplatGFCstMatch m_GFCstOrSplat(std::optional< FPValueAndVReg > &FPValReg)
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI std::optional< APFloat > isConstantOrConstantSplatVectorFP(Register Def, const MachineRegisterInfo &MRI)
Determines if Def defines a float constant integer or a splat vector of float constant integers.
constexpr bool isShiftedMask_64(uint64_t Value)
Return true if the argument contains a non-empty sequence of ones with the remainder zero (64 bit ver...
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...
DWARFExpression::Operation Op
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
LLVM_ABI std::optional< ValueAndVReg > getIConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_CONSTANT returns its...
static cl::opt< unsigned > CostThreshold("dfa-cost-threshold", cl::desc("Maximum cost accepted for the transformation"), cl::Hidden, cl::init(50))