LLVM 24.0.0git
AMDGPUCombinerHelper.cpp
Go to the documentation of this file.
1//=== lib/CodeGen/GlobalISel/AMDGPUCombinerHelper.cpp ---------------------===//
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
10#include "GCNSubtarget.h"
15#include "llvm/IR/IntrinsicsAMDGPU.h"
17
18using namespace llvm;
19using namespace MIPatternMatch;
20
27
29static bool fnegFoldsIntoMI(const MachineInstr &MI) {
30 switch (MI.getOpcode()) {
31 case AMDGPU::G_FADD:
32 case AMDGPU::G_FSUB:
33 case AMDGPU::G_FMUL:
34 case AMDGPU::G_FMA:
35 case AMDGPU::G_FMAD:
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:
42 case AMDGPU::G_FSIN:
43 case AMDGPU::G_FPEXT:
44 case AMDGPU::G_INTRINSIC_TRUNC:
45 case AMDGPU::G_FPTRUNC:
46 case AMDGPU::G_FRINT:
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:
54 return true;
55 case AMDGPU::G_INTRINSIC: {
56 Intrinsic::ID IntrinsicID = cast<GIntrinsic>(MI).getIntrinsicID();
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:
64 return true;
65 default:
66 return false;
67 }
68 }
69 default:
70 return false;
71 }
72}
73
74/// \p returns true if the operation will definitely need to use a 64-bit
75/// encoding, and thus will use a VOP3 encoding regardless of the source
76/// modifiers.
79 const MachineRegisterInfo &MRI) {
80 return MI.getNumOperands() > (isa<GIntrinsic>(MI) ? 4u : 3u) ||
81 MRI.getType(MI.getOperand(0).getReg()).getScalarSizeInBits() == 64;
82}
83
84// Most FP instructions support source modifiers.
86static bool hasSourceMods(const MachineInstr &MI) {
87 if (!MI.memoperands().empty())
88 return false;
89
90 switch (MI.getOpcode()) {
91 case AMDGPU::COPY:
92 case AMDGPU::G_SELECT:
93 case AMDGPU::G_FDIV:
94 case AMDGPU::G_FREM:
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:
103 case AMDGPU::G_PHI:
104 return false;
105 case AMDGPU::G_INTRINSIC:
106 case AMDGPU::G_INTRINSIC_CONVERGENT: {
107 Intrinsic::ID IntrinsicID = cast<GIntrinsic>(MI).getIntrinsicID();
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:
115 return false;
116 default:
117 return true;
118 }
119 }
120 default:
121 return true;
122 }
123}
124
126 unsigned CostThreshold = 4) {
127 // Some users (such as 3-operand FMA/MAD) must use a VOP3 encoding, and thus
128 // it is truly free to use a source modifier in all cases. If there are
129 // multiple users but for each one will necessitate using VOP3, there will be
130 // a code size increase. Try to avoid increasing code size unless we know it
131 // will save on the instruction count.
132 unsigned NumMayIncreaseSize = 0;
133 Register Dst = MI.getOperand(0).getReg();
134 for (const MachineInstr &Use : MRI.use_nodbg_instructions(Dst)) {
135 if (!hasSourceMods(Use))
136 return false;
137
138 if (!opMustUseVOP3Encoding(Use, MRI)) {
139 if (++NumMayIncreaseSize > CostThreshold)
140 return false;
141 }
142 }
143 return true;
144}
145
147 return MI.getFlag(MachineInstr::MIFlag::FmNsz);
148}
149
150static bool isInv2Pi(const APFloat &APF) {
151 static const APFloat KF16(APFloat::IEEEhalf(), APInt(16, 0x3118));
152 static const APFloat KF32(APFloat::IEEEsingle(), APInt(32, 0x3e22f983));
153 static const APFloat KF64(APFloat::IEEEdouble(),
154 APInt(64, 0x3fc45f306dc9c882));
155
156 return APF.bitwiseIsEqual(KF16) || APF.bitwiseIsEqual(KF32) ||
157 APF.bitwiseIsEqual(KF64);
158}
159
160// 0 and 1.0 / (0.5 * pi) do not have inline immmediates, so there is an
161// additional cost to negate them.
163 MachineRegisterInfo &MRI) {
164 std::optional<FPValueAndVReg> FPValReg;
165 if (mi_match(Reg, MRI, m_GFCstOrSplat(FPValReg))) {
166 if (FPValReg->Value.isZero() && !FPValReg->Value.isNegative())
167 return true;
168
169 const GCNSubtarget &ST = MI.getMF()->getSubtarget<GCNSubtarget>();
170 if (ST.hasInv2PiInlineImm() && isInv2Pi(FPValReg->Value))
171 return true;
172 }
173 return false;
174}
175
177 Register LHS,
178 Register RHS) const {
180 return true;
181 return VT &&
182 (VT->isKnownNeverLogicalZero(LHS) || VT->isKnownNeverLogicalZero(RHS));
183}
184
185static unsigned inverseMinMax(unsigned Opc) {
186 switch (Opc) {
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;
203 default:
204 llvm_unreachable("invalid min/max opcode");
205 }
206}
207
209 MachineInstr *&MatchInfo) const {
210 Register Src = MI.getOperand(1).getReg();
211 MatchInfo = MRI.getVRegDef(Src);
212
213 // If the input has multiple uses and we can either fold the negate down, or
214 // the other uses cannot, give up. This both prevents unprofitable
215 // transformations and infinite loops: we won't repeatedly try to fold around
216 // a negate that has no 'good' form.
217 if (MRI.hasOneNonDBGUse(Src)) {
219 return false;
220 } else {
221 if (fnegFoldsIntoMI(*MatchInfo) &&
223 !allUsesHaveSourceMods(*MatchInfo, MRI)))
224 return false;
225 }
226
227 switch (MatchInfo->getOpcode()) {
228 case AMDGPU::G_AMDGPU_FMIN_LEGACY:
229 case AMDGPU::G_AMDGPU_FMAX_LEGACY:
230 if (isConstantCostlierToNegate(*MatchInfo,
231 MatchInfo->getOperand(2).getReg(), MRI))
232 return false;
233 // Swapping min<->max flips which operand a signed zero tie selects.
234 return canIgnoreLegacyMinMaxTies(*MatchInfo,
235 MatchInfo->getOperand(1).getReg(),
236 MatchInfo->getOperand(2).getReg());
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:
243 // 0 doesn't have a negated inline immediate.
244 return !isConstantCostlierToNegate(*MatchInfo,
245 MatchInfo->getOperand(2).getReg(), MRI);
246 case AMDGPU::G_FADD:
247 case AMDGPU::G_FSUB:
248 case AMDGPU::G_FMA:
249 case AMDGPU::G_FMAD:
250 return mayIgnoreSignedZero(*MatchInfo);
251 case AMDGPU::G_FMUL:
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:
259 case AMDGPU::G_FSIN:
260 case AMDGPU::G_FCANONICALIZE:
261 case AMDGPU::G_AMDGPU_RCP_IFLAG:
262 return true;
263 case AMDGPU::G_INTRINSIC:
264 case AMDGPU::G_INTRINSIC_CONVERGENT: {
265 Intrinsic::ID IntrinsicID = cast<GIntrinsic>(MatchInfo)->getIntrinsicID();
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:
272 return true;
273 case Intrinsic::amdgcn_fma_legacy:
274 return mayIgnoreSignedZero(*MatchInfo);
275 default:
276 return false;
277 }
278 }
279 default:
280 return false;
281 }
282}
283
285 MachineInstr *&MatchInfo) const {
286 // Transform:
287 // %A = inst %Op1, ...
288 // %B = fneg %A
289 //
290 // into:
291 //
292 // (if %A has one use, specifically fneg above)
293 // %B = inst (maybe fneg %Op1), ...
294 //
295 // (if %A has multiple uses)
296 // %B = inst (maybe fneg %Op1), ...
297 // %A = fneg %B
298
299 // Replace register in operand with a register holding negated value.
300 auto NegateOperand = [&](MachineOperand &Op) {
301 Register Reg = Op.getReg();
302 if (!mi_match(Reg, MRI, m_GFNeg(m_Reg(Reg))))
303 Reg = Builder.buildFNeg(MRI.getType(Reg), Reg).getReg(0);
304 replaceRegOpWith(MRI, Op, Reg);
305 };
306
307 // Replace either register in operands with a register holding negated value.
308 auto NegateEitherOperand = [&](MachineOperand &X, MachineOperand &Y) {
309 Register XReg = X.getReg();
310 Register YReg = Y.getReg();
311 if (mi_match(XReg, MRI, m_GFNeg(m_Reg(XReg))))
312 replaceRegOpWith(MRI, X, XReg);
313 else if (mi_match(YReg, MRI, m_GFNeg(m_Reg(YReg))))
314 replaceRegOpWith(MRI, Y, YReg);
315 else {
316 YReg = Builder.buildFNeg(MRI.getType(YReg), YReg).getReg(0);
317 replaceRegOpWith(MRI, Y, YReg);
318 }
319 };
320
321 Builder.setInstrAndDebugLoc(*MatchInfo);
322
323 // Negate appropriate operands so that resulting value of MatchInfo is
324 // negated.
325 switch (MatchInfo->getOpcode()) {
326 case AMDGPU::G_FADD:
327 case AMDGPU::G_FSUB:
328 NegateOperand(MatchInfo->getOperand(1));
329 NegateOperand(MatchInfo->getOperand(2));
330 break;
331 case AMDGPU::G_FMUL:
332 NegateEitherOperand(MatchInfo->getOperand(1), MatchInfo->getOperand(2));
333 break;
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: {
342 NegateOperand(MatchInfo->getOperand(1));
343 NegateOperand(MatchInfo->getOperand(2));
344 unsigned Opposite = inverseMinMax(MatchInfo->getOpcode());
345 replaceOpcodeWith(*MatchInfo, Opposite);
346 break;
347 }
348 case AMDGPU::G_FMA:
349 case AMDGPU::G_FMAD:
350 NegateEitherOperand(MatchInfo->getOperand(1), MatchInfo->getOperand(2));
351 NegateOperand(MatchInfo->getOperand(3));
352 break;
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:
359 case AMDGPU::G_FSIN:
360 case AMDGPU::G_FCANONICALIZE:
361 case AMDGPU::G_AMDGPU_RCP_IFLAG:
362 case AMDGPU::G_FPTRUNC:
363 NegateOperand(MatchInfo->getOperand(1));
364 break;
365 case AMDGPU::G_INTRINSIC:
366 case AMDGPU::G_INTRINSIC_CONVERGENT: {
367 Intrinsic::ID IntrinsicID = cast<GIntrinsic>(MatchInfo)->getIntrinsicID();
368 switch (IntrinsicID) {
369 case Intrinsic::amdgcn_rcp:
370 case Intrinsic::amdgcn_rcp_legacy:
371 case Intrinsic::amdgcn_sin:
372 NegateOperand(MatchInfo->getOperand(2));
373 break;
374 case Intrinsic::amdgcn_fmul_legacy:
375 NegateEitherOperand(MatchInfo->getOperand(2), MatchInfo->getOperand(3));
376 break;
377 case Intrinsic::amdgcn_fmed3:
378 NegateOperand(MatchInfo->getOperand(2));
379 NegateOperand(MatchInfo->getOperand(3));
380 NegateOperand(MatchInfo->getOperand(4));
381 break;
382 case Intrinsic::amdgcn_fma_legacy:
383 NegateEitherOperand(MatchInfo->getOperand(2), MatchInfo->getOperand(3));
384 NegateOperand(MatchInfo->getOperand(4));
385 break;
386 default:
387 llvm_unreachable("folding fneg not supported for this intrinsic");
388 }
389 break;
390 }
391 default:
392 llvm_unreachable("folding fneg not supported for this instruction");
393 }
394
395 Register Dst = MI.getOperand(0).getReg();
396 Register MatchInfoDst = MatchInfo->getOperand(0).getReg();
397
398 if (MRI.hasOneNonDBGUse(MatchInfoDst)) {
399 // MatchInfo now has negated value so use that instead of old Dst.
400 replaceRegWith(MRI, Dst, MatchInfoDst);
401 } else {
402 // We want to swap all uses of Dst with uses of MatchInfoDst and vice versa
403 // but replaceRegWith will replace defs as well. It is easier to replace one
404 // def with a new register.
405 LLT Type = MRI.getType(Dst);
406 Register NegatedMatchInfo = MRI.createGenericVirtualRegister(Type);
407 replaceRegOpWith(MRI, MatchInfo->getOperand(0), NegatedMatchInfo);
408
409 // MatchInfo now has negated value so use that instead of old Dst.
410 replaceRegWith(MRI, Dst, NegatedMatchInfo);
411
412 // Recreate non negated value for other uses of old MatchInfoDst
413 auto NextInst = ++MatchInfo->getIterator();
414 Builder.setInstrAndDebugLoc(*NextInst);
415 Builder.buildFNeg(MatchInfoDst, NegatedMatchInfo, MI.getFlags());
416 }
417
418 MI.eraseFromParent();
419}
420
422 MachineInstr &Fptrunc) const {
423 Register Round = Fptrunc.getOperand(0).getReg();
424 if (!MRI.hasOneNonDBGUse(Round))
425 return false;
426
427 LLT SrcTy = MRI.getType(Fptrunc.getOperand(1).getReg());
428 return isLegalOrBeforeLegalizer({TargetOpcode::G_FABS, {SrcTy}});
429}
430
432 MachineInstr &Fptrunc) const {
433 // fabs (fptrunc x) -> fptrunc (fabs x)
434 Register Dst = Fabs.getOperand(0).getReg();
435 Register Src = Fptrunc.getOperand(1).getReg();
436 Builder.setInstrAndDebugLoc(Fabs);
437 Register Abs =
438 Builder.buildFAbs(MRI.getType(Src), Src, Fabs.getFlags()).getReg(0);
439 Builder.buildFPTrunc(Dst, Abs, Fptrunc.getFlags());
440 Fabs.eraseFromParent();
441}
442
443// TODO: Should return converted value / extension source and avoid introducing
444// intermediate fptruncs in the apply function.
446 Register Reg) {
447 Register SrcReg;
448 if (mi_match(Reg, MRI, m_GFPExt(m_Reg(SrcReg))))
449 return MRI.getType(SrcReg) == LLT::float16();
450
451 const ConstantFP *FPImm;
452 if (mi_match(Reg, MRI, m_GFCst(FPImm))) {
453 APFloat Val = FPImm->getValueAPF();
454 bool LosesInfo = true;
456 return !LosesInfo;
457 }
458
459 return false;
460}
461
463 Register Src0,
464 Register Src1,
465 Register Src2) const {
466 assert(MI.getOpcode() == TargetOpcode::G_FPTRUNC);
467 Register SrcReg = MI.getOperand(1).getReg();
468 if (MRI.getType(MI.getOperand(0).getReg()) != LLT::float16())
469 return false;
470 if (!MRI.hasOneNonDBGUse(SrcReg) || MRI.getType(SrcReg) != LLT::float32())
471 return false;
472
473 return isFPExtFromF16OrConst(MRI, Src0) && isFPExtFromF16OrConst(MRI, Src1) &&
475}
476
478 Register Src0,
479 Register Src1,
480 Register Src2) const {
481 // We expect fptrunc (fpext x) to fold out, and to constant fold any constant
482 // sources.
483 Src0 = Builder.buildFPTrunc(LLT::float16(), Src0).getReg(0);
484 Src1 = Builder.buildFPTrunc(LLT::float16(), Src1).getReg(0);
485 Src2 = Builder.buildFPTrunc(LLT::float16(), Src2).getReg(0);
486
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();
493}
494
497 std::function<void(MachineIRBuilder &)> &MatchInfo) const {
498 assert(MI.getOpcode() == TargetOpcode::G_FMUL);
499 assert(Sel.getOpcode() == TargetOpcode::G_SELECT);
500 assert(MI.getOperand(2).getReg() == Sel.getOperand(0).getReg());
501
502 Register Dst = MI.getOperand(0).getReg();
503 LLT DestTy = MRI.getType(Dst);
504 LLT ScalarDestTy = DestTy.getScalarType();
505
506 // TODO: Expected float type in ScalarDestTy
507 if ((ScalarDestTy != LLT::float64() && ScalarDestTy != LLT::float32() &&
508 ScalarDestTy != LLT::float16()) ||
509 !MRI.hasOneNonDBGUse(Sel.getOperand(0).getReg()))
510 return false;
511
512 Register SelectCondReg = Sel.getOperand(1).getReg();
513 Register SelectTrueReg = Sel.getOperand(2).getReg();
514 Register SelectFalseReg = Sel.getOperand(3).getReg();
515
516 const auto SelectTrueVal =
518 if (!SelectTrueVal)
519 return false;
520 const auto SelectFalseVal =
521 isConstantOrConstantSplatVectorFP(SelectFalseReg, MRI);
522 if (!SelectFalseVal)
523 return false;
524
525 if (SelectTrueVal->isNegative() != SelectFalseVal->isNegative())
526 return false;
527
528 // For f32, only non-inline constants should be transformed.
529 // TODO: Expected float32
530 if (ScalarDestTy == LLT::float32() && TII.isInlineConstant(*SelectTrueVal) &&
531 TII.isInlineConstant(*SelectFalseVal))
532 return false;
533
534 int SelectTrueLog2Val = SelectTrueVal->getExactLog2Abs();
535 if (SelectTrueLog2Val == INT_MIN)
536 return false;
537 int SelectFalseLog2Val = SelectFalseVal->getExactLog2Abs();
538 if (SelectFalseLog2Val == INT_MIN)
539 return false;
540
541 MatchInfo = [=, &MI](MachineIRBuilder &Builder) {
542 LLT IntDestTy = DestTy.changeElementType(LLT::integer(32));
543 auto NewSel = Builder.buildSelect(
544 IntDestTy, SelectCondReg,
545 Builder.buildConstant(IntDestTy, SelectTrueLog2Val),
546 Builder.buildConstant(IntDestTy, SelectFalseLog2Val));
547
548 Register XReg = MI.getOperand(1).getReg();
549 if (SelectTrueVal->isNegative()) {
550 auto NegX =
551 Builder.buildFNeg(DestTy, XReg, MRI.getVRegDef(XReg)->getFlags());
552 Builder.buildFLdexp(Dst, NegX, NewSel, MI.getFlags());
553 } else {
554 Builder.buildFLdexp(Dst, XReg, NewSel, MI.getFlags());
555 }
556 };
557
558 return true;
559}
560
563 if (!Res)
564 return false;
565
566 const uint64_t Val = Res->Value.getZExtValue();
567 unsigned MaskIdx = 0;
568 unsigned MaskLen = 0;
569 if (!isShiftedMask_64(Val, MaskIdx, MaskLen))
570 return false;
571
572 // Check if low 32 bits or high 32 bits are all ones.
573 return MaskLen >= 32 && ((MaskIdx == 0) || (MaskIdx == 64 - MaskLen));
574}
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.
#define X(NUM, ENUM, NAME)
Definition ELF.h:857
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
#define LLVM_READNONE
Definition Compiler.h:323
#define LLVM_READONLY
Definition Compiler.h:330
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...
IRTranslator LLVM IR MI
Interface for Targets to specify which operations they can successfully select and how the others sho...
Contains matchers for matching SSA Machine Instructions.
Register Reg
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()
Definition APFloat.h:304
static const fltSemantics & IEEEdouble()
Definition APFloat.h:305
static constexpr roundingMode rmNearestTiesToEven
Definition APFloat.h:361
static const fltSemantics & IEEEhalf()
Definition APFloat.h:302
LLVM_ABI opStatus convert(const fltSemantics &ToSemantics, roundingMode RM, bool *losesInfo)
Definition APFloat.cpp:6010
bool bitwiseIsEqual(const APFloat &RHS) const
Definition APFloat.h:1548
Class for arbitrary precision integers.
Definition APInt.h:78
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
const LegalizerInfo * LI
MachineDominatorTree * MDT
GISelValueTracking * VT
GISelChangeObserver & Observer
MachineIRBuilder & Builder
ConstantFP - Floating Point Values [float, double].
Definition Constants.h:420
const APFloat & getValueAPF() const
Definition Constants.h:463
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.
Definition Register.h:20
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
A Use represents the edge between a Value definition and its users.
Definition Use.h:35
self_iterator getIterator()
Definition ilist_node.h:123
#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.
Definition Utils.cpp:1529
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...
Definition MathExtras.h:274
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
DWARFExpression::Operation Op
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
LLVM_ABI std::optional< ValueAndVReg > getIConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_CONSTANT returns its...
Definition Utils.cpp:436
static cl::opt< unsigned > CostThreshold("dfa-cost-threshold", cl::desc("Maximum cost accepted for the transformation"), cl::Hidden, cl::init(50))