xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/AMDGPU/AMDGPUCombinerHelper.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
1349cc55cSDimitry Andric //=== lib/CodeGen/GlobalISel/AMDGPUCombinerHelper.cpp ---------------------===//
2349cc55cSDimitry Andric //
3349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6349cc55cSDimitry Andric //
7349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
8349cc55cSDimitry Andric 
9349cc55cSDimitry Andric #include "AMDGPUCombinerHelper.h"
10349cc55cSDimitry Andric #include "GCNSubtarget.h"
11349cc55cSDimitry Andric #include "MCTargetDesc/AMDGPUMCTargetDesc.h"
12349cc55cSDimitry Andric #include "llvm/CodeGen/GlobalISel/MIPatternMatch.h"
13349cc55cSDimitry Andric #include "llvm/IR/IntrinsicsAMDGPU.h"
14349cc55cSDimitry Andric #include "llvm/Target/TargetMachine.h"
15349cc55cSDimitry Andric 
16349cc55cSDimitry Andric using namespace llvm;
17349cc55cSDimitry Andric using namespace MIPatternMatch;
18349cc55cSDimitry Andric 
19349cc55cSDimitry Andric LLVM_READNONE
20349cc55cSDimitry Andric static bool fnegFoldsIntoMI(const MachineInstr &MI) {
21349cc55cSDimitry Andric   switch (MI.getOpcode()) {
22349cc55cSDimitry Andric   case AMDGPU::G_FADD:
23349cc55cSDimitry Andric   case AMDGPU::G_FSUB:
24349cc55cSDimitry Andric   case AMDGPU::G_FMUL:
25349cc55cSDimitry Andric   case AMDGPU::G_FMA:
26349cc55cSDimitry Andric   case AMDGPU::G_FMAD:
27349cc55cSDimitry Andric   case AMDGPU::G_FMINNUM:
28349cc55cSDimitry Andric   case AMDGPU::G_FMAXNUM:
29349cc55cSDimitry Andric   case AMDGPU::G_FMINNUM_IEEE:
30349cc55cSDimitry Andric   case AMDGPU::G_FMAXNUM_IEEE:
31349cc55cSDimitry Andric   case AMDGPU::G_FSIN:
32349cc55cSDimitry Andric   case AMDGPU::G_FPEXT:
33349cc55cSDimitry Andric   case AMDGPU::G_INTRINSIC_TRUNC:
34349cc55cSDimitry Andric   case AMDGPU::G_FPTRUNC:
35349cc55cSDimitry Andric   case AMDGPU::G_FRINT:
36349cc55cSDimitry Andric   case AMDGPU::G_FNEARBYINT:
37349cc55cSDimitry Andric   case AMDGPU::G_INTRINSIC_ROUND:
38349cc55cSDimitry Andric   case AMDGPU::G_INTRINSIC_ROUNDEVEN:
39349cc55cSDimitry Andric   case AMDGPU::G_FCANONICALIZE:
40349cc55cSDimitry Andric   case AMDGPU::G_AMDGPU_RCP_IFLAG:
41349cc55cSDimitry Andric   case AMDGPU::G_AMDGPU_FMIN_LEGACY:
42349cc55cSDimitry Andric   case AMDGPU::G_AMDGPU_FMAX_LEGACY:
43349cc55cSDimitry Andric     return true;
44349cc55cSDimitry Andric   case AMDGPU::G_INTRINSIC: {
45349cc55cSDimitry Andric     unsigned IntrinsicID = MI.getIntrinsicID();
46349cc55cSDimitry Andric     switch (IntrinsicID) {
47349cc55cSDimitry Andric     case Intrinsic::amdgcn_rcp:
48349cc55cSDimitry Andric     case Intrinsic::amdgcn_rcp_legacy:
49349cc55cSDimitry Andric     case Intrinsic::amdgcn_sin:
50349cc55cSDimitry Andric     case Intrinsic::amdgcn_fmul_legacy:
51349cc55cSDimitry Andric     case Intrinsic::amdgcn_fmed3:
52349cc55cSDimitry Andric     case Intrinsic::amdgcn_fma_legacy:
53349cc55cSDimitry Andric       return true;
54349cc55cSDimitry Andric     default:
55349cc55cSDimitry Andric       return false;
56349cc55cSDimitry Andric     }
57349cc55cSDimitry Andric   }
58349cc55cSDimitry Andric   default:
59349cc55cSDimitry Andric     return false;
60349cc55cSDimitry Andric   }
61349cc55cSDimitry Andric }
62349cc55cSDimitry Andric 
63349cc55cSDimitry Andric /// \p returns true if the operation will definitely need to use a 64-bit
64349cc55cSDimitry Andric /// encoding, and thus will use a VOP3 encoding regardless of the source
65349cc55cSDimitry Andric /// modifiers.
66349cc55cSDimitry Andric LLVM_READONLY
67349cc55cSDimitry Andric static bool opMustUseVOP3Encoding(const MachineInstr &MI,
68349cc55cSDimitry Andric                                   const MachineRegisterInfo &MRI) {
69349cc55cSDimitry Andric   return MI.getNumOperands() >
70349cc55cSDimitry Andric              (MI.getOpcode() == AMDGPU::G_INTRINSIC ? 4u : 3u) ||
71349cc55cSDimitry Andric          MRI.getType(MI.getOperand(0).getReg()).getScalarSizeInBits() == 64;
72349cc55cSDimitry Andric }
73349cc55cSDimitry Andric 
74349cc55cSDimitry Andric // Most FP instructions support source modifiers.
75349cc55cSDimitry Andric LLVM_READONLY
76349cc55cSDimitry Andric static bool hasSourceMods(const MachineInstr &MI) {
77349cc55cSDimitry Andric   if (!MI.memoperands().empty())
78349cc55cSDimitry Andric     return false;
79349cc55cSDimitry Andric 
80349cc55cSDimitry Andric   switch (MI.getOpcode()) {
81349cc55cSDimitry Andric   case AMDGPU::COPY:
82349cc55cSDimitry Andric   case AMDGPU::G_SELECT:
83349cc55cSDimitry Andric   case AMDGPU::G_FDIV:
84349cc55cSDimitry Andric   case AMDGPU::G_FREM:
85349cc55cSDimitry Andric   case TargetOpcode::INLINEASM:
86349cc55cSDimitry Andric   case TargetOpcode::INLINEASM_BR:
87349cc55cSDimitry Andric   case AMDGPU::G_INTRINSIC_W_SIDE_EFFECTS:
88349cc55cSDimitry Andric   case AMDGPU::G_BITCAST:
89349cc55cSDimitry Andric   case AMDGPU::G_ANYEXT:
90349cc55cSDimitry Andric   case AMDGPU::G_BUILD_VECTOR:
91349cc55cSDimitry Andric   case AMDGPU::G_BUILD_VECTOR_TRUNC:
92349cc55cSDimitry Andric   case AMDGPU::G_PHI:
93349cc55cSDimitry Andric     return false;
94349cc55cSDimitry Andric   case AMDGPU::G_INTRINSIC: {
95349cc55cSDimitry Andric     unsigned IntrinsicID = MI.getIntrinsicID();
96349cc55cSDimitry Andric     switch (IntrinsicID) {
97349cc55cSDimitry Andric     case Intrinsic::amdgcn_interp_p1:
98349cc55cSDimitry Andric     case Intrinsic::amdgcn_interp_p2:
99349cc55cSDimitry Andric     case Intrinsic::amdgcn_interp_mov:
100349cc55cSDimitry Andric     case Intrinsic::amdgcn_interp_p1_f16:
101349cc55cSDimitry Andric     case Intrinsic::amdgcn_interp_p2_f16:
102349cc55cSDimitry Andric     case Intrinsic::amdgcn_div_scale:
103349cc55cSDimitry Andric       return false;
104349cc55cSDimitry Andric     default:
105349cc55cSDimitry Andric       return true;
106349cc55cSDimitry Andric     }
107349cc55cSDimitry Andric   }
108349cc55cSDimitry Andric   default:
109349cc55cSDimitry Andric     return true;
110349cc55cSDimitry Andric   }
111349cc55cSDimitry Andric }
112349cc55cSDimitry Andric 
113349cc55cSDimitry Andric static bool allUsesHaveSourceMods(MachineInstr &MI, MachineRegisterInfo &MRI,
114349cc55cSDimitry Andric                                   unsigned CostThreshold = 4) {
115349cc55cSDimitry Andric   // Some users (such as 3-operand FMA/MAD) must use a VOP3 encoding, and thus
116349cc55cSDimitry Andric   // it is truly free to use a source modifier in all cases. If there are
117349cc55cSDimitry Andric   // multiple users but for each one will necessitate using VOP3, there will be
118349cc55cSDimitry Andric   // a code size increase. Try to avoid increasing code size unless we know it
119349cc55cSDimitry Andric   // will save on the instruction count.
120349cc55cSDimitry Andric   unsigned NumMayIncreaseSize = 0;
121349cc55cSDimitry Andric   Register Dst = MI.getOperand(0).getReg();
122349cc55cSDimitry Andric   for (const MachineInstr &Use : MRI.use_nodbg_instructions(Dst)) {
123349cc55cSDimitry Andric     if (!hasSourceMods(Use))
124349cc55cSDimitry Andric       return false;
125349cc55cSDimitry Andric 
126349cc55cSDimitry Andric     if (!opMustUseVOP3Encoding(Use, MRI)) {
127349cc55cSDimitry Andric       if (++NumMayIncreaseSize > CostThreshold)
128349cc55cSDimitry Andric         return false;
129349cc55cSDimitry Andric     }
130349cc55cSDimitry Andric   }
131349cc55cSDimitry Andric   return true;
132349cc55cSDimitry Andric }
133349cc55cSDimitry Andric 
134349cc55cSDimitry Andric static bool mayIgnoreSignedZero(MachineInstr &MI) {
135349cc55cSDimitry Andric   const TargetOptions &Options = MI.getMF()->getTarget().Options;
136349cc55cSDimitry Andric   return Options.NoSignedZerosFPMath || MI.getFlag(MachineInstr::MIFlag::FmNsz);
137349cc55cSDimitry Andric }
138349cc55cSDimitry Andric 
139349cc55cSDimitry Andric static bool isInv2Pi(const APFloat &APF) {
140349cc55cSDimitry Andric   static const APFloat KF16(APFloat::IEEEhalf(), APInt(16, 0x3118));
141349cc55cSDimitry Andric   static const APFloat KF32(APFloat::IEEEsingle(), APInt(32, 0x3e22f983));
142349cc55cSDimitry Andric   static const APFloat KF64(APFloat::IEEEdouble(),
143349cc55cSDimitry Andric                             APInt(64, 0x3fc45f306dc9c882));
144349cc55cSDimitry Andric 
145349cc55cSDimitry Andric   return APF.bitwiseIsEqual(KF16) || APF.bitwiseIsEqual(KF32) ||
146349cc55cSDimitry Andric          APF.bitwiseIsEqual(KF64);
147349cc55cSDimitry Andric }
148349cc55cSDimitry Andric 
149349cc55cSDimitry Andric // 0 and 1.0 / (0.5 * pi) do not have inline immmediates, so there is an
150349cc55cSDimitry Andric // additional cost to negate them.
151349cc55cSDimitry Andric static bool isConstantCostlierToNegate(MachineInstr &MI, Register Reg,
152349cc55cSDimitry Andric                                        MachineRegisterInfo &MRI) {
153*bdd1243dSDimitry Andric   std::optional<FPValueAndVReg> FPValReg;
154349cc55cSDimitry Andric   if (mi_match(Reg, MRI, m_GFCstOrSplat(FPValReg))) {
155349cc55cSDimitry Andric     if (FPValReg->Value.isZero() && !FPValReg->Value.isNegative())
156349cc55cSDimitry Andric       return true;
157349cc55cSDimitry Andric 
158349cc55cSDimitry Andric     const GCNSubtarget &ST = MI.getMF()->getSubtarget<GCNSubtarget>();
159349cc55cSDimitry Andric     if (ST.hasInv2PiInlineImm() && isInv2Pi(FPValReg->Value))
160349cc55cSDimitry Andric       return true;
161349cc55cSDimitry Andric   }
162349cc55cSDimitry Andric   return false;
163349cc55cSDimitry Andric }
164349cc55cSDimitry Andric 
165349cc55cSDimitry Andric static unsigned inverseMinMax(unsigned Opc) {
166349cc55cSDimitry Andric   switch (Opc) {
167349cc55cSDimitry Andric   case AMDGPU::G_FMAXNUM:
168349cc55cSDimitry Andric     return AMDGPU::G_FMINNUM;
169349cc55cSDimitry Andric   case AMDGPU::G_FMINNUM:
170349cc55cSDimitry Andric     return AMDGPU::G_FMAXNUM;
171349cc55cSDimitry Andric   case AMDGPU::G_FMAXNUM_IEEE:
172349cc55cSDimitry Andric     return AMDGPU::G_FMINNUM_IEEE;
173349cc55cSDimitry Andric   case AMDGPU::G_FMINNUM_IEEE:
174349cc55cSDimitry Andric     return AMDGPU::G_FMAXNUM_IEEE;
175349cc55cSDimitry Andric   case AMDGPU::G_AMDGPU_FMAX_LEGACY:
176349cc55cSDimitry Andric     return AMDGPU::G_AMDGPU_FMIN_LEGACY;
177349cc55cSDimitry Andric   case AMDGPU::G_AMDGPU_FMIN_LEGACY:
178349cc55cSDimitry Andric     return AMDGPU::G_AMDGPU_FMAX_LEGACY;
179349cc55cSDimitry Andric   default:
180349cc55cSDimitry Andric     llvm_unreachable("invalid min/max opcode");
181349cc55cSDimitry Andric   }
182349cc55cSDimitry Andric }
183349cc55cSDimitry Andric 
184349cc55cSDimitry Andric bool AMDGPUCombinerHelper::matchFoldableFneg(MachineInstr &MI,
185349cc55cSDimitry Andric                                              MachineInstr *&MatchInfo) {
186349cc55cSDimitry Andric   Register Src = MI.getOperand(1).getReg();
187349cc55cSDimitry Andric   MatchInfo = MRI.getVRegDef(Src);
188349cc55cSDimitry Andric 
189349cc55cSDimitry Andric   // If the input has multiple uses and we can either fold the negate down, or
190349cc55cSDimitry Andric   // the other uses cannot, give up. This both prevents unprofitable
191349cc55cSDimitry Andric   // transformations and infinite loops: we won't repeatedly try to fold around
192349cc55cSDimitry Andric   // a negate that has no 'good' form.
193349cc55cSDimitry Andric   if (MRI.hasOneNonDBGUse(Src)) {
194349cc55cSDimitry Andric     if (allUsesHaveSourceMods(MI, MRI, 0))
195349cc55cSDimitry Andric       return false;
196349cc55cSDimitry Andric   } else {
197349cc55cSDimitry Andric     if (fnegFoldsIntoMI(*MatchInfo) &&
198349cc55cSDimitry Andric         (allUsesHaveSourceMods(MI, MRI) ||
199349cc55cSDimitry Andric          !allUsesHaveSourceMods(*MatchInfo, MRI)))
200349cc55cSDimitry Andric       return false;
201349cc55cSDimitry Andric   }
202349cc55cSDimitry Andric 
203349cc55cSDimitry Andric   switch (MatchInfo->getOpcode()) {
204349cc55cSDimitry Andric   case AMDGPU::G_FMINNUM:
205349cc55cSDimitry Andric   case AMDGPU::G_FMAXNUM:
206349cc55cSDimitry Andric   case AMDGPU::G_FMINNUM_IEEE:
207349cc55cSDimitry Andric   case AMDGPU::G_FMAXNUM_IEEE:
208349cc55cSDimitry Andric   case AMDGPU::G_AMDGPU_FMIN_LEGACY:
209349cc55cSDimitry Andric   case AMDGPU::G_AMDGPU_FMAX_LEGACY:
210349cc55cSDimitry Andric     // 0 doesn't have a negated inline immediate.
211349cc55cSDimitry Andric     return !isConstantCostlierToNegate(*MatchInfo,
212349cc55cSDimitry Andric                                        MatchInfo->getOperand(2).getReg(), MRI);
213349cc55cSDimitry Andric   case AMDGPU::G_FADD:
214349cc55cSDimitry Andric   case AMDGPU::G_FSUB:
215349cc55cSDimitry Andric   case AMDGPU::G_FMA:
216349cc55cSDimitry Andric   case AMDGPU::G_FMAD:
217349cc55cSDimitry Andric     return mayIgnoreSignedZero(*MatchInfo);
218349cc55cSDimitry Andric   case AMDGPU::G_FMUL:
219349cc55cSDimitry Andric   case AMDGPU::G_FPEXT:
220349cc55cSDimitry Andric   case AMDGPU::G_INTRINSIC_TRUNC:
221349cc55cSDimitry Andric   case AMDGPU::G_FPTRUNC:
222349cc55cSDimitry Andric   case AMDGPU::G_FRINT:
223349cc55cSDimitry Andric   case AMDGPU::G_FNEARBYINT:
224349cc55cSDimitry Andric   case AMDGPU::G_INTRINSIC_ROUND:
225349cc55cSDimitry Andric   case AMDGPU::G_INTRINSIC_ROUNDEVEN:
226349cc55cSDimitry Andric   case AMDGPU::G_FSIN:
227349cc55cSDimitry Andric   case AMDGPU::G_FCANONICALIZE:
228349cc55cSDimitry Andric   case AMDGPU::G_AMDGPU_RCP_IFLAG:
229349cc55cSDimitry Andric     return true;
230349cc55cSDimitry Andric   case AMDGPU::G_INTRINSIC: {
231349cc55cSDimitry Andric     unsigned IntrinsicID = MatchInfo->getIntrinsicID();
232349cc55cSDimitry Andric     switch (IntrinsicID) {
233349cc55cSDimitry Andric     case Intrinsic::amdgcn_rcp:
234349cc55cSDimitry Andric     case Intrinsic::amdgcn_rcp_legacy:
235349cc55cSDimitry Andric     case Intrinsic::amdgcn_sin:
236349cc55cSDimitry Andric     case Intrinsic::amdgcn_fmul_legacy:
237349cc55cSDimitry Andric     case Intrinsic::amdgcn_fmed3:
238349cc55cSDimitry Andric       return true;
239349cc55cSDimitry Andric     case Intrinsic::amdgcn_fma_legacy:
240349cc55cSDimitry Andric       return mayIgnoreSignedZero(*MatchInfo);
241349cc55cSDimitry Andric     default:
242349cc55cSDimitry Andric       return false;
243349cc55cSDimitry Andric     }
244349cc55cSDimitry Andric   }
245349cc55cSDimitry Andric   default:
246349cc55cSDimitry Andric     return false;
247349cc55cSDimitry Andric   }
248349cc55cSDimitry Andric }
249349cc55cSDimitry Andric 
250349cc55cSDimitry Andric void AMDGPUCombinerHelper::applyFoldableFneg(MachineInstr &MI,
251349cc55cSDimitry Andric                                              MachineInstr *&MatchInfo) {
252349cc55cSDimitry Andric   // Transform:
253349cc55cSDimitry Andric   // %A = inst %Op1, ...
254349cc55cSDimitry Andric   // %B = fneg %A
255349cc55cSDimitry Andric   //
256349cc55cSDimitry Andric   // into:
257349cc55cSDimitry Andric   //
258349cc55cSDimitry Andric   // (if %A has one use, specifically fneg above)
259349cc55cSDimitry Andric   // %B = inst (maybe fneg %Op1), ...
260349cc55cSDimitry Andric   //
261349cc55cSDimitry Andric   // (if %A has multiple uses)
262349cc55cSDimitry Andric   // %B = inst (maybe fneg %Op1), ...
263349cc55cSDimitry Andric   // %A = fneg %B
264349cc55cSDimitry Andric 
265349cc55cSDimitry Andric   // Replace register in operand with a register holding negated value.
266349cc55cSDimitry Andric   auto NegateOperand = [&](MachineOperand &Op) {
267349cc55cSDimitry Andric     Register Reg = Op.getReg();
268349cc55cSDimitry Andric     if (!mi_match(Reg, MRI, m_GFNeg(m_Reg(Reg))))
269349cc55cSDimitry Andric       Reg = Builder.buildFNeg(MRI.getType(Reg), Reg).getReg(0);
270349cc55cSDimitry Andric     replaceRegOpWith(MRI, Op, Reg);
271349cc55cSDimitry Andric   };
272349cc55cSDimitry Andric 
273349cc55cSDimitry Andric   // Replace either register in operands with a register holding negated value.
274349cc55cSDimitry Andric   auto NegateEitherOperand = [&](MachineOperand &X, MachineOperand &Y) {
275349cc55cSDimitry Andric     Register XReg = X.getReg();
276349cc55cSDimitry Andric     Register YReg = Y.getReg();
277349cc55cSDimitry Andric     if (mi_match(XReg, MRI, m_GFNeg(m_Reg(XReg))))
278349cc55cSDimitry Andric       replaceRegOpWith(MRI, X, XReg);
279349cc55cSDimitry Andric     else if (mi_match(YReg, MRI, m_GFNeg(m_Reg(YReg))))
280349cc55cSDimitry Andric       replaceRegOpWith(MRI, Y, YReg);
281349cc55cSDimitry Andric     else {
282349cc55cSDimitry Andric       YReg = Builder.buildFNeg(MRI.getType(YReg), YReg).getReg(0);
283349cc55cSDimitry Andric       replaceRegOpWith(MRI, Y, YReg);
284349cc55cSDimitry Andric     }
285349cc55cSDimitry Andric   };
286349cc55cSDimitry Andric 
287349cc55cSDimitry Andric   Builder.setInstrAndDebugLoc(*MatchInfo);
288349cc55cSDimitry Andric 
289349cc55cSDimitry Andric   // Negate appropriate operands so that resulting value of MatchInfo is
290349cc55cSDimitry Andric   // negated.
291349cc55cSDimitry Andric   switch (MatchInfo->getOpcode()) {
292349cc55cSDimitry Andric   case AMDGPU::G_FADD:
293349cc55cSDimitry Andric   case AMDGPU::G_FSUB:
294349cc55cSDimitry Andric     NegateOperand(MatchInfo->getOperand(1));
295349cc55cSDimitry Andric     NegateOperand(MatchInfo->getOperand(2));
296349cc55cSDimitry Andric     break;
297349cc55cSDimitry Andric   case AMDGPU::G_FMUL:
298349cc55cSDimitry Andric     NegateEitherOperand(MatchInfo->getOperand(1), MatchInfo->getOperand(2));
299349cc55cSDimitry Andric     break;
300349cc55cSDimitry Andric   case AMDGPU::G_FMINNUM:
301349cc55cSDimitry Andric   case AMDGPU::G_FMAXNUM:
302349cc55cSDimitry Andric   case AMDGPU::G_FMINNUM_IEEE:
303349cc55cSDimitry Andric   case AMDGPU::G_FMAXNUM_IEEE:
304349cc55cSDimitry Andric   case AMDGPU::G_AMDGPU_FMIN_LEGACY:
305349cc55cSDimitry Andric   case AMDGPU::G_AMDGPU_FMAX_LEGACY: {
306349cc55cSDimitry Andric     NegateOperand(MatchInfo->getOperand(1));
307349cc55cSDimitry Andric     NegateOperand(MatchInfo->getOperand(2));
308349cc55cSDimitry Andric     unsigned Opposite = inverseMinMax(MatchInfo->getOpcode());
309349cc55cSDimitry Andric     replaceOpcodeWith(*MatchInfo, Opposite);
310349cc55cSDimitry Andric     break;
311349cc55cSDimitry Andric   }
312349cc55cSDimitry Andric   case AMDGPU::G_FMA:
313349cc55cSDimitry Andric   case AMDGPU::G_FMAD:
314349cc55cSDimitry Andric     NegateEitherOperand(MatchInfo->getOperand(1), MatchInfo->getOperand(2));
315349cc55cSDimitry Andric     NegateOperand(MatchInfo->getOperand(3));
316349cc55cSDimitry Andric     break;
317349cc55cSDimitry Andric   case AMDGPU::G_FPEXT:
318349cc55cSDimitry Andric   case AMDGPU::G_INTRINSIC_TRUNC:
319349cc55cSDimitry Andric   case AMDGPU::G_FRINT:
320349cc55cSDimitry Andric   case AMDGPU::G_FNEARBYINT:
321349cc55cSDimitry Andric   case AMDGPU::G_INTRINSIC_ROUND:
322349cc55cSDimitry Andric   case AMDGPU::G_INTRINSIC_ROUNDEVEN:
323349cc55cSDimitry Andric   case AMDGPU::G_FSIN:
324349cc55cSDimitry Andric   case AMDGPU::G_FCANONICALIZE:
325349cc55cSDimitry Andric   case AMDGPU::G_AMDGPU_RCP_IFLAG:
326349cc55cSDimitry Andric   case AMDGPU::G_FPTRUNC:
327349cc55cSDimitry Andric     NegateOperand(MatchInfo->getOperand(1));
328349cc55cSDimitry Andric     break;
329349cc55cSDimitry Andric   case AMDGPU::G_INTRINSIC: {
330349cc55cSDimitry Andric     unsigned IntrinsicID = MatchInfo->getIntrinsicID();
331349cc55cSDimitry Andric     switch (IntrinsicID) {
332349cc55cSDimitry Andric     case Intrinsic::amdgcn_rcp:
333349cc55cSDimitry Andric     case Intrinsic::amdgcn_rcp_legacy:
334349cc55cSDimitry Andric     case Intrinsic::amdgcn_sin:
335349cc55cSDimitry Andric       NegateOperand(MatchInfo->getOperand(2));
336349cc55cSDimitry Andric       break;
337349cc55cSDimitry Andric     case Intrinsic::amdgcn_fmul_legacy:
338349cc55cSDimitry Andric       NegateEitherOperand(MatchInfo->getOperand(2), MatchInfo->getOperand(3));
339349cc55cSDimitry Andric       break;
340349cc55cSDimitry Andric     case Intrinsic::amdgcn_fmed3:
341349cc55cSDimitry Andric       NegateOperand(MatchInfo->getOperand(2));
342349cc55cSDimitry Andric       NegateOperand(MatchInfo->getOperand(3));
343349cc55cSDimitry Andric       NegateOperand(MatchInfo->getOperand(4));
344349cc55cSDimitry Andric       break;
345349cc55cSDimitry Andric     case Intrinsic::amdgcn_fma_legacy:
346349cc55cSDimitry Andric       NegateEitherOperand(MatchInfo->getOperand(2), MatchInfo->getOperand(3));
347349cc55cSDimitry Andric       NegateOperand(MatchInfo->getOperand(4));
348349cc55cSDimitry Andric       break;
349349cc55cSDimitry Andric     default:
350349cc55cSDimitry Andric       llvm_unreachable("folding fneg not supported for this intrinsic");
351349cc55cSDimitry Andric     }
352349cc55cSDimitry Andric     break;
353349cc55cSDimitry Andric   }
354349cc55cSDimitry Andric   default:
355349cc55cSDimitry Andric     llvm_unreachable("folding fneg not supported for this instruction");
356349cc55cSDimitry Andric   }
357349cc55cSDimitry Andric 
358349cc55cSDimitry Andric   Register Dst = MI.getOperand(0).getReg();
359349cc55cSDimitry Andric   Register MatchInfoDst = MatchInfo->getOperand(0).getReg();
360349cc55cSDimitry Andric 
361349cc55cSDimitry Andric   if (MRI.hasOneNonDBGUse(MatchInfoDst)) {
362349cc55cSDimitry Andric     // MatchInfo now has negated value so use that instead of old Dst.
363349cc55cSDimitry Andric     replaceRegWith(MRI, Dst, MatchInfoDst);
364349cc55cSDimitry Andric   } else {
365349cc55cSDimitry Andric     // We want to swap all uses of Dst with uses of MatchInfoDst and vice versa
366349cc55cSDimitry Andric     // but replaceRegWith will replace defs as well. It is easier to replace one
367349cc55cSDimitry Andric     // def with a new register.
368349cc55cSDimitry Andric     LLT Type = MRI.getType(Dst);
369349cc55cSDimitry Andric     Register NegatedMatchInfo = MRI.createGenericVirtualRegister(Type);
370349cc55cSDimitry Andric     replaceRegOpWith(MRI, MatchInfo->getOperand(0), NegatedMatchInfo);
371349cc55cSDimitry Andric 
372349cc55cSDimitry Andric     // MatchInfo now has negated value so use that instead of old Dst.
373349cc55cSDimitry Andric     replaceRegWith(MRI, Dst, NegatedMatchInfo);
374349cc55cSDimitry Andric 
375349cc55cSDimitry Andric     // Recreate non negated value for other uses of old MatchInfoDst
37681ad6265SDimitry Andric     auto NextInst = ++MatchInfo->getIterator();
37781ad6265SDimitry Andric     Builder.setInstrAndDebugLoc(*NextInst);
378349cc55cSDimitry Andric     Builder.buildFNeg(MatchInfoDst, NegatedMatchInfo, MI.getFlags());
379349cc55cSDimitry Andric   }
380349cc55cSDimitry Andric 
381349cc55cSDimitry Andric   MI.eraseFromParent();
382349cc55cSDimitry Andric }
383