LLVM 23.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
176static unsigned inverseMinMax(unsigned Opc) {
177 switch (Opc) {
178 case AMDGPU::G_FMAXNUM:
179 return AMDGPU::G_FMINNUM;
180 case AMDGPU::G_FMINNUM:
181 return AMDGPU::G_FMAXNUM;
182 case AMDGPU::G_FMAXNUM_IEEE:
183 return AMDGPU::G_FMINNUM_IEEE;
184 case AMDGPU::G_FMINNUM_IEEE:
185 return AMDGPU::G_FMAXNUM_IEEE;
186 case AMDGPU::G_FMAXIMUM:
187 return AMDGPU::G_FMINIMUM;
188 case AMDGPU::G_FMINIMUM:
189 return AMDGPU::G_FMAXIMUM;
190 case AMDGPU::G_AMDGPU_FMAX_LEGACY:
191 return AMDGPU::G_AMDGPU_FMIN_LEGACY;
192 case AMDGPU::G_AMDGPU_FMIN_LEGACY:
193 return AMDGPU::G_AMDGPU_FMAX_LEGACY;
194 default:
195 llvm_unreachable("invalid min/max opcode");
196 }
197}
198
200 MachineInstr *&MatchInfo) const {
201 Register Src = MI.getOperand(1).getReg();
202 MatchInfo = MRI.getVRegDef(Src);
203
204 // If the input has multiple uses and we can either fold the negate down, or
205 // the other uses cannot, give up. This both prevents unprofitable
206 // transformations and infinite loops: we won't repeatedly try to fold around
207 // a negate that has no 'good' form.
208 if (MRI.hasOneNonDBGUse(Src)) {
210 return false;
211 } else {
212 if (fnegFoldsIntoMI(*MatchInfo) &&
214 !allUsesHaveSourceMods(*MatchInfo, MRI)))
215 return false;
216 }
217
218 switch (MatchInfo->getOpcode()) {
219 case AMDGPU::G_FMINNUM:
220 case AMDGPU::G_FMAXNUM:
221 case AMDGPU::G_FMINNUM_IEEE:
222 case AMDGPU::G_FMAXNUM_IEEE:
223 case AMDGPU::G_FMINIMUM:
224 case AMDGPU::G_FMAXIMUM:
225 case AMDGPU::G_AMDGPU_FMIN_LEGACY:
226 case AMDGPU::G_AMDGPU_FMAX_LEGACY:
227 // 0 doesn't have a negated inline immediate.
228 return !isConstantCostlierToNegate(*MatchInfo,
229 MatchInfo->getOperand(2).getReg(), MRI);
230 case AMDGPU::G_FADD:
231 case AMDGPU::G_FSUB:
232 case AMDGPU::G_FMA:
233 case AMDGPU::G_FMAD:
234 return mayIgnoreSignedZero(*MatchInfo);
235 case AMDGPU::G_FMUL:
236 case AMDGPU::G_FPEXT:
237 case AMDGPU::G_INTRINSIC_TRUNC:
238 case AMDGPU::G_FPTRUNC:
239 case AMDGPU::G_FRINT:
240 case AMDGPU::G_FNEARBYINT:
241 case AMDGPU::G_INTRINSIC_ROUND:
242 case AMDGPU::G_INTRINSIC_ROUNDEVEN:
243 case AMDGPU::G_FSIN:
244 case AMDGPU::G_FCANONICALIZE:
245 case AMDGPU::G_AMDGPU_RCP_IFLAG:
246 return true;
247 case AMDGPU::G_INTRINSIC:
248 case AMDGPU::G_INTRINSIC_CONVERGENT: {
249 Intrinsic::ID IntrinsicID = cast<GIntrinsic>(MatchInfo)->getIntrinsicID();
250 switch (IntrinsicID) {
251 case Intrinsic::amdgcn_rcp:
252 case Intrinsic::amdgcn_rcp_legacy:
253 case Intrinsic::amdgcn_sin:
254 case Intrinsic::amdgcn_fmul_legacy:
255 case Intrinsic::amdgcn_fmed3:
256 return true;
257 case Intrinsic::amdgcn_fma_legacy:
258 return mayIgnoreSignedZero(*MatchInfo);
259 default:
260 return false;
261 }
262 }
263 default:
264 return false;
265 }
266}
267
269 MachineInstr *&MatchInfo) const {
270 // Transform:
271 // %A = inst %Op1, ...
272 // %B = fneg %A
273 //
274 // into:
275 //
276 // (if %A has one use, specifically fneg above)
277 // %B = inst (maybe fneg %Op1), ...
278 //
279 // (if %A has multiple uses)
280 // %B = inst (maybe fneg %Op1), ...
281 // %A = fneg %B
282
283 // Replace register in operand with a register holding negated value.
284 auto NegateOperand = [&](MachineOperand &Op) {
285 Register Reg = Op.getReg();
286 if (!mi_match(Reg, MRI, m_GFNeg(m_Reg(Reg))))
287 Reg = Builder.buildFNeg(MRI.getType(Reg), Reg).getReg(0);
288 replaceRegOpWith(MRI, Op, Reg);
289 };
290
291 // Replace either register in operands with a register holding negated value.
292 auto NegateEitherOperand = [&](MachineOperand &X, MachineOperand &Y) {
293 Register XReg = X.getReg();
294 Register YReg = Y.getReg();
295 if (mi_match(XReg, MRI, m_GFNeg(m_Reg(XReg))))
296 replaceRegOpWith(MRI, X, XReg);
297 else if (mi_match(YReg, MRI, m_GFNeg(m_Reg(YReg))))
298 replaceRegOpWith(MRI, Y, YReg);
299 else {
300 YReg = Builder.buildFNeg(MRI.getType(YReg), YReg).getReg(0);
301 replaceRegOpWith(MRI, Y, YReg);
302 }
303 };
304
305 Builder.setInstrAndDebugLoc(*MatchInfo);
306
307 // Negate appropriate operands so that resulting value of MatchInfo is
308 // negated.
309 switch (MatchInfo->getOpcode()) {
310 case AMDGPU::G_FADD:
311 case AMDGPU::G_FSUB:
312 NegateOperand(MatchInfo->getOperand(1));
313 NegateOperand(MatchInfo->getOperand(2));
314 break;
315 case AMDGPU::G_FMUL:
316 NegateEitherOperand(MatchInfo->getOperand(1), MatchInfo->getOperand(2));
317 break;
318 case AMDGPU::G_FMINNUM:
319 case AMDGPU::G_FMAXNUM:
320 case AMDGPU::G_FMINNUM_IEEE:
321 case AMDGPU::G_FMAXNUM_IEEE:
322 case AMDGPU::G_FMINIMUM:
323 case AMDGPU::G_FMAXIMUM:
324 case AMDGPU::G_AMDGPU_FMIN_LEGACY:
325 case AMDGPU::G_AMDGPU_FMAX_LEGACY: {
326 NegateOperand(MatchInfo->getOperand(1));
327 NegateOperand(MatchInfo->getOperand(2));
328 unsigned Opposite = inverseMinMax(MatchInfo->getOpcode());
329 replaceOpcodeWith(*MatchInfo, Opposite);
330 break;
331 }
332 case AMDGPU::G_FMA:
333 case AMDGPU::G_FMAD:
334 NegateEitherOperand(MatchInfo->getOperand(1), MatchInfo->getOperand(2));
335 NegateOperand(MatchInfo->getOperand(3));
336 break;
337 case AMDGPU::G_FPEXT:
338 case AMDGPU::G_INTRINSIC_TRUNC:
339 case AMDGPU::G_FRINT:
340 case AMDGPU::G_FNEARBYINT:
341 case AMDGPU::G_INTRINSIC_ROUND:
342 case AMDGPU::G_INTRINSIC_ROUNDEVEN:
343 case AMDGPU::G_FSIN:
344 case AMDGPU::G_FCANONICALIZE:
345 case AMDGPU::G_AMDGPU_RCP_IFLAG:
346 case AMDGPU::G_FPTRUNC:
347 NegateOperand(MatchInfo->getOperand(1));
348 break;
349 case AMDGPU::G_INTRINSIC:
350 case AMDGPU::G_INTRINSIC_CONVERGENT: {
351 Intrinsic::ID IntrinsicID = cast<GIntrinsic>(MatchInfo)->getIntrinsicID();
352 switch (IntrinsicID) {
353 case Intrinsic::amdgcn_rcp:
354 case Intrinsic::amdgcn_rcp_legacy:
355 case Intrinsic::amdgcn_sin:
356 NegateOperand(MatchInfo->getOperand(2));
357 break;
358 case Intrinsic::amdgcn_fmul_legacy:
359 NegateEitherOperand(MatchInfo->getOperand(2), MatchInfo->getOperand(3));
360 break;
361 case Intrinsic::amdgcn_fmed3:
362 NegateOperand(MatchInfo->getOperand(2));
363 NegateOperand(MatchInfo->getOperand(3));
364 NegateOperand(MatchInfo->getOperand(4));
365 break;
366 case Intrinsic::amdgcn_fma_legacy:
367 NegateEitherOperand(MatchInfo->getOperand(2), MatchInfo->getOperand(3));
368 NegateOperand(MatchInfo->getOperand(4));
369 break;
370 default:
371 llvm_unreachable("folding fneg not supported for this intrinsic");
372 }
373 break;
374 }
375 default:
376 llvm_unreachable("folding fneg not supported for this instruction");
377 }
378
379 Register Dst = MI.getOperand(0).getReg();
380 Register MatchInfoDst = MatchInfo->getOperand(0).getReg();
381
382 if (MRI.hasOneNonDBGUse(MatchInfoDst)) {
383 // MatchInfo now has negated value so use that instead of old Dst.
384 replaceRegWith(MRI, Dst, MatchInfoDst);
385 } else {
386 // We want to swap all uses of Dst with uses of MatchInfoDst and vice versa
387 // but replaceRegWith will replace defs as well. It is easier to replace one
388 // def with a new register.
389 LLT Type = MRI.getType(Dst);
390 Register NegatedMatchInfo = MRI.createGenericVirtualRegister(Type);
391 replaceRegOpWith(MRI, MatchInfo->getOperand(0), NegatedMatchInfo);
392
393 // MatchInfo now has negated value so use that instead of old Dst.
394 replaceRegWith(MRI, Dst, NegatedMatchInfo);
395
396 // Recreate non negated value for other uses of old MatchInfoDst
397 auto NextInst = ++MatchInfo->getIterator();
398 Builder.setInstrAndDebugLoc(*NextInst);
399 Builder.buildFNeg(MatchInfoDst, NegatedMatchInfo, MI.getFlags());
400 }
401
402 MI.eraseFromParent();
403}
404
406 MachineInstr &Fptrunc) const {
407 Register Round = Fptrunc.getOperand(0).getReg();
408 if (!MRI.hasOneNonDBGUse(Round))
409 return false;
410
411 LLT SrcTy = MRI.getType(Fptrunc.getOperand(1).getReg());
412 return isLegalOrBeforeLegalizer({TargetOpcode::G_FABS, {SrcTy}});
413}
414
416 MachineInstr &Fptrunc) const {
417 // fabs (fptrunc x) -> fptrunc (fabs x)
418 Register Dst = Fabs.getOperand(0).getReg();
419 Register Src = Fptrunc.getOperand(1).getReg();
420 Builder.setInstrAndDebugLoc(Fabs);
421 Register Abs =
422 Builder.buildFAbs(MRI.getType(Src), Src, Fabs.getFlags()).getReg(0);
423 Builder.buildFPTrunc(Dst, Abs, Fptrunc.getFlags());
424 Fabs.eraseFromParent();
425}
426
427// TODO: Should return converted value / extension source and avoid introducing
428// intermediate fptruncs in the apply function.
430 Register Reg) {
431 const MachineInstr *Def = MRI.getVRegDef(Reg);
432 if (Def->getOpcode() == TargetOpcode::G_FPEXT) {
433 Register SrcReg = Def->getOperand(1).getReg();
434 return MRI.getType(SrcReg) == LLT::scalar(16);
435 }
436
437 if (Def->getOpcode() == TargetOpcode::G_FCONSTANT) {
438 APFloat Val = Def->getOperand(1).getFPImm()->getValueAPF();
439 bool LosesInfo = true;
441 return !LosesInfo;
442 }
443
444 return false;
445}
446
448 Register Src0,
449 Register Src1,
450 Register Src2) const {
451 assert(MI.getOpcode() == TargetOpcode::G_FPTRUNC);
452 Register SrcReg = MI.getOperand(1).getReg();
453 if (!MRI.hasOneNonDBGUse(SrcReg) || MRI.getType(SrcReg) != LLT::scalar(32))
454 return false;
455
456 return isFPExtFromF16OrConst(MRI, Src0) && isFPExtFromF16OrConst(MRI, Src1) &&
458}
459
461 Register Src0,
462 Register Src1,
463 Register Src2) const {
464 // We expect fptrunc (fpext x) to fold out, and to constant fold any constant
465 // sources.
466 Src0 = Builder.buildFPTrunc(LLT::scalar(16), Src0).getReg(0);
467 Src1 = Builder.buildFPTrunc(LLT::scalar(16), Src1).getReg(0);
468 Src2 = Builder.buildFPTrunc(LLT::scalar(16), Src2).getReg(0);
469
470 LLT Ty = MRI.getType(Src0);
471 auto A1 = Builder.buildFMinNumIEEE(Ty, Src0, Src1);
472 auto B1 = Builder.buildFMaxNumIEEE(Ty, Src0, Src1);
473 auto C1 = Builder.buildFMaxNumIEEE(Ty, A1, Src2);
474 Builder.buildFMinNumIEEE(MI.getOperand(0), B1, C1);
475 MI.eraseFromParent();
476}
477
480 std::function<void(MachineIRBuilder &)> &MatchInfo) const {
481 assert(MI.getOpcode() == TargetOpcode::G_FMUL);
482 assert(Sel.getOpcode() == TargetOpcode::G_SELECT);
483 assert(MI.getOperand(2).getReg() == Sel.getOperand(0).getReg());
484
485 Register Dst = MI.getOperand(0).getReg();
486 LLT DestTy = MRI.getType(Dst);
487 LLT ScalarDestTy = DestTy.getScalarType();
488
489 // TODO: Expected float type in ScalarDestTy
490 if ((ScalarDestTy != LLT::scalar(64) && ScalarDestTy != LLT::scalar(32) &&
491 ScalarDestTy != LLT::scalar(16)) ||
492 !MRI.hasOneNonDBGUse(Sel.getOperand(0).getReg()))
493 return false;
494
495 Register SelectCondReg = Sel.getOperand(1).getReg();
496 MachineInstr *SelectTrue = MRI.getVRegDef(Sel.getOperand(2).getReg());
497 MachineInstr *SelectFalse = MRI.getVRegDef(Sel.getOperand(3).getReg());
498
499 const auto SelectTrueVal =
501 if (!SelectTrueVal)
502 return false;
503 const auto SelectFalseVal =
505 if (!SelectFalseVal)
506 return false;
507
508 if (SelectTrueVal->isNegative() != SelectFalseVal->isNegative())
509 return false;
510
511 // For f32, only non-inline constants should be transformed.
512 // TODO: Expected float32
513 if (ScalarDestTy == LLT::scalar(32) && TII.isInlineConstant(*SelectTrueVal) &&
514 TII.isInlineConstant(*SelectFalseVal))
515 return false;
516
517 int SelectTrueLog2Val = SelectTrueVal->getExactLog2Abs();
518 if (SelectTrueLog2Val == INT_MIN)
519 return false;
520 int SelectFalseLog2Val = SelectFalseVal->getExactLog2Abs();
521 if (SelectFalseLog2Val == INT_MIN)
522 return false;
523
524 MatchInfo = [=, &MI](MachineIRBuilder &Builder) {
525 LLT IntDestTy = DestTy.changeElementType(LLT::scalar(32));
526 auto NewSel = Builder.buildSelect(
527 IntDestTy, SelectCondReg,
528 Builder.buildConstant(IntDestTy, SelectTrueLog2Val),
529 Builder.buildConstant(IntDestTy, SelectFalseLog2Val));
530
531 Register XReg = MI.getOperand(1).getReg();
532 if (SelectTrueVal->isNegative()) {
533 auto NegX =
534 Builder.buildFNeg(DestTy, XReg, MRI.getVRegDef(XReg)->getFlags());
535 Builder.buildFLdexp(Dst, NegX, NewSel, MI.getFlags());
536 } else {
537 Builder.buildFLdexp(Dst, XReg, NewSel, MI.getFlags());
538 }
539 };
540
541 return true;
542}
543
546 if (!Res)
547 return false;
548
549 const uint64_t Val = Res->Value.getZExtValue();
550 unsigned MaskIdx = 0;
551 unsigned MaskLen = 0;
552 if (!isShiftedMask_64(Val, MaskIdx, MaskLen))
553 return false;
554
555 // Check if low 32 bits or high 32 bits are all ones.
556 return MaskLen >= 32 && ((MaskIdx == 0) || (MaskIdx == 64 - MaskLen));
557}
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 mayIgnoreSignedZero(MachineInstr &MI)
static bool isConstantCostlierToNegate(MachineInstr &MI, Register Reg, MachineRegisterInfo &MRI)
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.
Provides AMDGPU specific target descriptions.
#define X(NUM, ENUM, NAME)
Definition ELF.h:856
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
#define LLVM_READNONE
Definition Compiler.h:317
#define LLVM_READONLY
Definition Compiler.h:324
AMD GCN specific subclass of TargetSubtarget.
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
static const fltSemantics & IEEEsingle()
Definition APFloat.h:297
static const fltSemantics & IEEEdouble()
Definition APFloat.h:298
static constexpr roundingMode rmNearestTiesToEven
Definition APFloat.h:345
static const fltSemantics & IEEEhalf()
Definition APFloat.h:295
LLVM_ABI opStatus convert(const fltSemantics &ToSemantics, roundingMode RM, bool *losesInfo)
Definition APFloat.cpp:5920
bool bitwiseIsEqual(const APFloat &RHS) const
Definition APFloat.h:1530
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
Abstract class that contains various methods for clients to notify about changes.
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 scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
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,...
LLVM_ABI MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
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()
bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P)
UnaryOp_match< SrcTy, TargetOpcode::G_FNEG > m_GFNeg(const SrcTy &Src)
GFCstOrSplatGFCstMatch m_GFCstOrSplat(std::optional< FPValueAndVReg > &FPValReg)
This is an optimization pass for GlobalISel generic memory operations.
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:273
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
LLVM_ABI std::optional< APFloat > isConstantOrConstantSplatVectorFP(MachineInstr &MI, const MachineRegisterInfo &MRI)
Determines if MI defines a float constant integer or a splat vector of float constant integers.
Definition Utils.cpp:1543
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))