LLVM 24.0.0git
AMDGPURegBankCombiner.cpp
Go to the documentation of this file.
1//=== lib/CodeGen/GlobalISel/AMDGPURegBankCombiner.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//
9// This pass does combining of machine instructions at the generic MI level,
10// after register banks are known.
11//
12//===----------------------------------------------------------------------===//
13
14#include "AMDGPU.h"
15#include "AMDGPULegalizerInfo.h"
17#include "GCNSubtarget.h"
29
30#define GET_GICOMBINER_DEPS
31#include "AMDGPUGenPreLegalizeGICombiner.inc"
32#undef GET_GICOMBINER_DEPS
33
34#define DEBUG_TYPE "amdgpu-regbank-combiner"
35
36using namespace llvm;
37using namespace MIPatternMatch;
38
39namespace {
40#define GET_GICOMBINER_TYPES
41#include "AMDGPUGenRegBankGICombiner.inc"
42#undef GET_GICOMBINER_TYPES
43
44class AMDGPURegBankCombinerImpl : public Combiner {
45protected:
46 const AMDGPURegBankCombinerImplRuleConfig &RuleConfig;
47 const GCNSubtarget &STI;
48 const RegisterBankInfo &RBI;
50 const SIInstrInfo &TII;
51 const CombinerHelper Helper;
52
53public:
54 AMDGPURegBankCombinerImpl(
56 GISelCSEInfo *CSEInfo,
57 const AMDGPURegBankCombinerImplRuleConfig &RuleConfig,
58 const GCNSubtarget &STI, MachineDominatorTree *MDT,
59 const LegalizerInfo *LI);
60
61 static const char *getName() { return "AMDGPURegBankCombinerImpl"; }
62
63 bool tryCombineAll(MachineInstr &I) const override;
64
65 bool isVgprRegBank(Register Reg) const;
66 Register getAsVgpr(Register Reg) const;
67
68 struct MinMaxMedOpc {
69 unsigned Min, Max, Med;
70 };
71
72 struct Med3MatchInfo {
73 unsigned Opc;
74 Register Val0, Val1, Val2;
75 };
76
77 struct MinMaxToMinMax3MatchInfo {
78 unsigned Opc;
79 Register Val0, Val1, Val2;
80 };
81
82 MinMaxMedOpc getMinMaxPair(unsigned Opc) const;
83
84 template <class m_Cst, typename CstTy>
85 bool matchMed(MachineInstr &MI, MachineRegisterInfo &MRI, MinMaxMedOpc MMMOpc,
86 Register &Val, CstTy &K0, CstTy &K1) const;
87
88 bool matchIntMinMaxToMed3(MachineInstr &MI, Med3MatchInfo &MatchInfo) const;
89 bool matchFPMinMaxToMed3(MachineInstr &MI, Med3MatchInfo &MatchInfo) const;
90 bool matchFPMinMaxToClamp(MachineInstr &MI, Register &Reg) const;
91 bool matchFPMed3ToClamp(MachineInstr &MI, Register &Reg) const;
92 void applyMed3(MachineInstr &MI, Med3MatchInfo &MatchInfo) const;
93 void applyClamp(MachineInstr &MI, Register &Reg) const;
94
95 void applyCanonicalizeZextShiftAmt(MachineInstr &MI, MachineInstr &Ext) const;
96
97 bool combineD16Load(MachineInstr &MI) const;
98 bool applyD16Load(unsigned D16Opc, MachineInstr &DstMI,
99 MachineInstr *SmallLoad, Register ToOverwriteD16) const;
100
101 bool matchMinMaxToMinMax3(MachineInstr &MI,
102 MinMaxToMinMax3MatchInfo &MatchInfo) const;
103 void applyMinMaxToMinMax3(MachineInstr &MI,
104 MinMaxToMinMax3MatchInfo &MatchInfo) const;
105
106private:
107 SIModeRegisterDefaults getMode() const;
108 bool getIEEE() const;
109 bool getDX10Clamp() const;
110 bool isFminnumIeee(const MachineInstr &MI) const;
111 bool isFCst(MachineInstr *MI) const;
112 bool isClampZeroToOne(MachineInstr *K0, MachineInstr *K1) const;
113
114#define GET_GICOMBINER_CLASS_MEMBERS
115#define AMDGPUSubtarget GCNSubtarget
116#include "AMDGPUGenRegBankGICombiner.inc"
117#undef GET_GICOMBINER_CLASS_MEMBERS
118#undef AMDGPUSubtarget
119};
120
121#define GET_GICOMBINER_IMPL
122#define AMDGPUSubtarget GCNSubtarget
123#include "AMDGPUGenRegBankGICombiner.inc"
124#undef AMDGPUSubtarget
125#undef GET_GICOMBINER_IMPL
126
127AMDGPURegBankCombinerImpl::AMDGPURegBankCombinerImpl(
129 GISelCSEInfo *CSEInfo,
130 const AMDGPURegBankCombinerImplRuleConfig &RuleConfig,
131 const GCNSubtarget &STI, MachineDominatorTree *MDT, const LegalizerInfo *LI)
132 : Combiner(MF, CInfo, &VT, CSEInfo), RuleConfig(RuleConfig), STI(STI),
133 RBI(*STI.getRegBankInfo()), TRI(*STI.getRegisterInfo()),
134 TII(*STI.getInstrInfo()),
135 Helper(Observer, B, /*IsPreLegalize*/ false, &VT, MDT, LI),
137#include "AMDGPUGenRegBankGICombiner.inc"
139{
140}
141
142bool AMDGPURegBankCombinerImpl::isVgprRegBank(Register Reg) const {
143 return RBI.getRegBank(Reg, MRI, TRI)->getID() == AMDGPU::VGPRRegBankID;
144}
145
146Register AMDGPURegBankCombinerImpl::getAsVgpr(Register Reg) const {
147 if (isVgprRegBank(Reg))
148 return Reg;
149
150 // Search for existing copy of Reg to vgpr.
151 for (MachineInstr &Use : MRI.use_instructions(Reg)) {
152 Register Def = Use.getOperand(0).getReg();
153 if (Use.getOpcode() == AMDGPU::COPY && isVgprRegBank(Def))
154 return Def;
155 }
156
157 // Copy Reg to vgpr.
158 Register VgprReg = B.buildCopy(MRI.getType(Reg), Reg).getReg(0);
159 MRI.setRegBank(VgprReg, RBI.getRegBank(AMDGPU::VGPRRegBankID));
160 return VgprReg;
161}
162
163AMDGPURegBankCombinerImpl::MinMaxMedOpc
164AMDGPURegBankCombinerImpl::getMinMaxPair(unsigned Opc) const {
165 switch (Opc) {
166 default:
167 llvm_unreachable("Unsupported opcode");
168 case AMDGPU::G_SMAX:
169 case AMDGPU::G_SMIN:
170 return {AMDGPU::G_SMIN, AMDGPU::G_SMAX, AMDGPU::G_AMDGPU_SMED3};
171 case AMDGPU::G_UMAX:
172 case AMDGPU::G_UMIN:
173 return {AMDGPU::G_UMIN, AMDGPU::G_UMAX, AMDGPU::G_AMDGPU_UMED3};
174 case AMDGPU::G_FMAXNUM:
175 case AMDGPU::G_FMINNUM:
176 return {AMDGPU::G_FMINNUM, AMDGPU::G_FMAXNUM, AMDGPU::G_AMDGPU_FMED3};
177 case AMDGPU::G_FMAXNUM_IEEE:
178 case AMDGPU::G_FMINNUM_IEEE:
179 return {AMDGPU::G_FMINNUM_IEEE, AMDGPU::G_FMAXNUM_IEEE,
180 AMDGPU::G_AMDGPU_FMED3};
181 }
182}
183
184template <class m_Cst, typename CstTy>
185bool AMDGPURegBankCombinerImpl::matchMed(MachineInstr &MI,
186 MachineRegisterInfo &MRI,
187 MinMaxMedOpc MMMOpc, Register &Val,
188 CstTy &K0, CstTy &K1) const {
189 // 4 operand commutes of: min(max(Val, K0), K1).
190 // Find K1 from outer instr: min(max(...), K1) or min(K1, max(...)).
191 // Find K0 and Val from inner instr: max(K0, Val) or max(Val, K0).
192 // 4 operand commutes of: max(min(Val, K1), K0).
193 // Find K0 from outer instr: max(min(...), K0) or max(K0, min(...)).
194 // Find K1 and Val from inner instr: min(K1, Val) or min(Val, K1).
195 return mi_match(
196 MI, MRI,
197 m_any_of(
199 MMMOpc.Min, m_CommutativeBinOp(MMMOpc.Max, m_Reg(Val), m_Cst(K0)),
200 m_Cst(K1)),
202 MMMOpc.Max, m_CommutativeBinOp(MMMOpc.Min, m_Reg(Val), m_Cst(K1)),
203 m_Cst(K0))));
204}
205
206bool AMDGPURegBankCombinerImpl::matchIntMinMaxToMed3(
207 MachineInstr &MI, Med3MatchInfo &MatchInfo) const {
208 Register Dst = MI.getOperand(0).getReg();
209 if (!isVgprRegBank(Dst))
210 return false;
211
212 // med3 for i16 is only available on gfx9+, and not available for v2i16.
213 LLT Ty = MRI.getType(Dst);
214 if ((Ty != LLT::scalar(16) || !STI.hasMed3_16()) && Ty != LLT::scalar(32))
215 return false;
216
217 MinMaxMedOpc OpcodeTriple = getMinMaxPair(MI.getOpcode());
218 Register Val;
219 std::optional<ValueAndVReg> K0, K1;
220 // Match min(max(Val, K0), K1) or max(min(Val, K1), K0). Then see if K0 <= K1.
221 if (!matchMed<GCstAndRegMatch>(MI, MRI, OpcodeTriple, Val, K0, K1))
222 return false;
223
224 if (OpcodeTriple.Med == AMDGPU::G_AMDGPU_SMED3 && K0->Value.sgt(K1->Value))
225 return false;
226 if (OpcodeTriple.Med == AMDGPU::G_AMDGPU_UMED3 && K0->Value.ugt(K1->Value))
227 return false;
228
229 MatchInfo = {OpcodeTriple.Med, Val, K0->VReg, K1->VReg};
230 return true;
231}
232
233// fmed3(NaN, K0, K1) = min(min(NaN, K0), K1)
234// ieee = true : min/max(SNaN, K) = QNaN, min/max(QNaN, K) = K
235// ieee = false : min/max(NaN, K) = K
236// clamp(NaN) = dx10_clamp ? 0.0 : NaN
237// Consider values of min(max(Val, K0), K1) and max(min(Val, K1), K0) as input.
238// Other operand commutes (see matchMed) give same result since min and max are
239// commutative.
240
241// Try to replace fp min(max(Val, K0), K1) or max(min(Val, K1), K0), KO<=K1
242// with fmed3(Val, K0, K1) or clamp(Val). Clamp requires K0 = 0.0 and K1 = 1.0.
243// Val = SNaN only for ieee = true
244// fmed3(SNaN, K0, K1) = min(min(SNaN, K0), K1) = min(QNaN, K1) = K1
245// min(max(SNaN, K0), K1) = min(QNaN, K1) = K1
246// max(min(SNaN, K1), K0) = max(K1, K0) = K1
247// Val = NaN,ieee = false or Val = QNaN,ieee = true
248// fmed3(NaN, K0, K1) = min(min(NaN, K0), K1) = min(K0, K1) = K0
249// min(max(NaN, K0), K1) = min(K0, K1) = K0 (can clamp when dx10_clamp = true)
250// max(min(NaN, K1), K0) = max(K1, K0) = K1 != K0
251bool AMDGPURegBankCombinerImpl::matchFPMinMaxToMed3(
252 MachineInstr &MI, Med3MatchInfo &MatchInfo) const {
253 Register Dst = MI.getOperand(0).getReg();
254 // Perform combine only when the destination is a VGPR.
255 if (!isVgprRegBank(Dst))
256 return false;
257
258 LLT Ty = MRI.getType(Dst);
259
260 // med3 for f16 is only available on gfx9+, and not available for v2f16.
261 if ((Ty != LLT::scalar(16) || !STI.hasMed3_16()) && Ty != LLT::scalar(32))
262 return false;
263
264 auto OpcodeTriple = getMinMaxPair(MI.getOpcode());
265
266 Register Val;
267 std::optional<FPValueAndVReg> K0, K1;
268 // Match min(max(Val, K0), K1) or max(min(Val, K1), K0). Then see if K0 <= K1.
269 if (!matchMed<GFCstAndRegMatch>(MI, MRI, OpcodeTriple, Val, K0, K1))
270 return false;
271
272 if (K0->Value > K1->Value)
273 return false;
274
275 // For IEEE=false perform combine only when it's safe to assume that there are
276 // no NaN inputs. Most often MI is marked with nnan fast math flag.
277 // For IEEE=true consider NaN inputs. fmed3(NaN, K0, K1) is equivalent to
278 // min(min(NaN, K0), K1). Safe to fold for min(max(Val, K0), K1) since inner
279 // nodes(max/min) have same behavior when one input is NaN and other isn't.
280 // Don't consider max(min(SNaN, K1), K0) since there is no isKnownNeverQNaN,
281 // also post-legalizer inputs to min/max are fcanonicalized (never SNaN).
282 if ((getIEEE() && isFminnumIeee(MI)) || VT->isKnownNeverNaN(Dst)) {
283 // Don't fold single use constant that can't be inlined.
284 if ((!MRI.hasOneNonDBGUse(K0->VReg) || TII.isInlineConstant(K0->Value)) &&
285 (!MRI.hasOneNonDBGUse(K1->VReg) || TII.isInlineConstant(K1->Value))) {
286 MatchInfo = {OpcodeTriple.Med, Val, K0->VReg, K1->VReg};
287 return true;
288 }
289 }
290
291 return false;
292}
293
294bool AMDGPURegBankCombinerImpl::matchFPMinMaxToClamp(MachineInstr &MI,
295 Register &Reg) const {
296 // Perform combine only when the destination is a VGPR.
297 if (!isVgprRegBank(MI.getOperand(0).getReg()))
298 return false;
299
300 // Clamp is available on all types after regbankselect (f16, f32, f64, v2f16).
301 auto OpcodeTriple = getMinMaxPair(MI.getOpcode());
302 Register Val;
303 std::optional<FPValueAndVReg> K0, K1;
304 // Match min(max(Val, K0), K1) or max(min(Val, K1), K0).
305 if (!matchMed<GFCstOrSplatGFCstMatch>(MI, MRI, OpcodeTriple, Val, K0, K1))
306 return false;
307
308 if (!K0->Value.isPosZero() || !K1->Value.isOne())
309 return false;
310
311 // For IEEE=false perform combine only when it's safe to assume that there are
312 // no NaN inputs. Most often MI is marked with nnan fast math flag.
313 // For IEEE=true consider NaN inputs. Only min(max(QNaN, 0.0), 1.0) evaluates
314 // to 0.0 requires dx10_clamp = true.
315 if ((getIEEE() && getDX10Clamp() && isFminnumIeee(MI) &&
316 VT->isKnownNeverSNaN(Val)) ||
317 VT->isKnownNeverNaN(MI.getOperand(0).getReg())) {
318 Reg = Val;
319 return true;
320 }
321
322 return false;
323}
324
325// Replacing fmed3(NaN, 0.0, 1.0) with clamp. Requires dx10_clamp = true.
326// Val = SNaN only for ieee = true. It is important which operand is NaN.
327// min(min(SNaN, 0.0), 1.0) = min(QNaN, 1.0) = 1.0
328// min(min(SNaN, 1.0), 0.0) = min(QNaN, 0.0) = 0.0
329// min(min(0.0, 1.0), SNaN) = min(0.0, SNaN) = QNaN
330// Val = NaN,ieee = false or Val = QNaN,ieee = true
331// min(min(NaN, 0.0), 1.0) = min(0.0, 1.0) = 0.0
332// min(min(NaN, 1.0), 0.0) = min(1.0, 0.0) = 0.0
333// min(min(0.0, 1.0), NaN) = min(0.0, NaN) = 0.0
334bool AMDGPURegBankCombinerImpl::matchFPMed3ToClamp(MachineInstr &MI,
335 Register &Reg) const {
336 // Perform combine only when the destination is a VGPR.
337 if (!isVgprRegBank(MI.getOperand(0).getReg()))
338 return false;
339
340 // In llvm-ir, clamp is often represented as an intrinsic call to
341 // @llvm.amdgcn.fmed3.f32(%Val, 0.0, 1.0). Check for other operand orders.
342 MachineInstr *Src0 = getDefIgnoringCopies(MI.getOperand(1).getReg(), MRI);
343 MachineInstr *Src1 = getDefIgnoringCopies(MI.getOperand(2).getReg(), MRI);
344 MachineInstr *Src2 = getDefIgnoringCopies(MI.getOperand(3).getReg(), MRI);
345
346 if (isFCst(Src0) && !isFCst(Src1))
347 std::swap(Src0, Src1);
348 if (isFCst(Src1) && !isFCst(Src2))
349 std::swap(Src1, Src2);
350 if (isFCst(Src0) && !isFCst(Src1))
351 std::swap(Src0, Src1);
352 if (!isClampZeroToOne(Src1, Src2))
353 return false;
354
355 Register Val = Src0->getOperand(0).getReg();
356
357 auto isOp3Zero = [&]() {
358 MachineInstr *Op3 = getDefIgnoringCopies(MI.getOperand(3).getReg(), MRI);
359 if (Op3->getOpcode() == TargetOpcode::G_FCONSTANT)
360 return Op3->getOperand(1).getFPImm()->isPosZero();
361 return false;
362 };
363 // For IEEE=false perform combine only when it's safe to assume that there are
364 // no NaN inputs. Most often MI is marked with nnan fast math flag.
365 // For IEEE=true consider NaN inputs. Requires dx10_clamp = true. Safe to fold
366 // when Val could be QNaN. If Val can also be SNaN third input should be 0.0.
367 if (VT->isKnownNeverNaN(MI.getOperand(0).getReg()) ||
368 (getIEEE() && getDX10Clamp() &&
369 (VT->isKnownNeverSNaN(Val) || isOp3Zero()))) {
370 Reg = Val;
371 return true;
372 }
373
374 return false;
375}
376
377void AMDGPURegBankCombinerImpl::applyClamp(MachineInstr &MI,
378 Register &Reg) const {
379 B.buildInstr(AMDGPU::G_AMDGPU_CLAMP, {MI.getOperand(0)}, {Reg},
380 MI.getFlags());
381 MI.eraseFromParent();
382}
383
384void AMDGPURegBankCombinerImpl::applyMed3(MachineInstr &MI,
385 Med3MatchInfo &MatchInfo) const {
386 B.buildInstr(MatchInfo.Opc, {MI.getOperand(0)},
387 {getAsVgpr(MatchInfo.Val0), getAsVgpr(MatchInfo.Val1),
388 getAsVgpr(MatchInfo.Val2)},
389 MI.getFlags());
390 MI.eraseFromParent();
391}
392
393void AMDGPURegBankCombinerImpl::applyCanonicalizeZextShiftAmt(
394 MachineInstr &MI, MachineInstr &Ext) const {
395 unsigned ShOpc = MI.getOpcode();
396 assert(ShOpc == AMDGPU::G_SHL || ShOpc == AMDGPU::G_LSHR ||
397 ShOpc == AMDGPU::G_ASHR);
398 assert(Ext.getOpcode() == AMDGPU::G_ZEXT);
399
400 Register AmtReg = Ext.getOperand(1).getReg();
401 Register ShDst = MI.getOperand(0).getReg();
402 Register ShSrc = MI.getOperand(1).getReg();
403
404 LLT ExtAmtTy = MRI.getType(Ext.getOperand(0).getReg());
405 LLT AmtTy = MRI.getType(AmtReg);
406
407 auto &RB = *MRI.getRegBank(AmtReg);
408
409 auto NewExt = B.buildAnyExt(ExtAmtTy, AmtReg);
410 auto Mask = B.buildConstant(
412 auto And = B.buildAnd(ExtAmtTy, NewExt, Mask);
413 B.buildInstr(ShOpc, {ShDst}, {ShSrc, And});
414
415 MRI.setRegBank(NewExt.getReg(0), RB);
416 MRI.setRegBank(Mask.getReg(0), RB);
417 MRI.setRegBank(And.getReg(0), RB);
418 MI.eraseFromParent();
419}
420
421bool AMDGPURegBankCombinerImpl::combineD16Load(MachineInstr &MI) const {
422 Register Dst;
423 MachineInstr *Load, *SextLoad;
424 const int64_t CleanLo16 = 0xFFFFFFFFFFFF0000;
425 const int64_t CleanHi16 = 0x000000000000FFFF;
426
427 // Load lo
428 if (mi_match(MI.getOperand(1).getReg(), MRI,
430 m_Copy(m_SpecificICst(CleanLo16))),
431 m_MInstr(Load)))) {
432
433 if (Load->getOpcode() == AMDGPU::G_ZEXTLOAD) {
434 const MachineMemOperand *MMO = *Load->memoperands_begin();
435 unsigned LoadSize = MMO->getSizeInBits().getValue();
436 if (LoadSize == 8)
437 return applyD16Load(AMDGPU::G_AMDGPU_LOAD_D16_LO_U8, MI, Load, Dst);
438 if (LoadSize == 16)
439 return applyD16Load(AMDGPU::G_AMDGPU_LOAD_D16_LO, MI, Load, Dst);
440 return false;
441 }
442
443 // s32 Load_lo16 holds SextLoad i8, Load_hi16 is zero.
444 // fake16: and (sextload i8 -> s32), 0xFFFF
445 // true16: zext (sextload i8 -> s16) -> s32
446 if (mi_match(
447 Load, MRI,
448 m_GAnd(m_MInstr(SextLoad), m_Copy(m_SpecificICst(CleanHi16)))) ||
449 mi_match(Load, MRI,
451 m_MInstr(SextLoad))))) {
452 if (SextLoad->getOpcode() != AMDGPU::G_SEXTLOAD)
453 return false;
454
455 const MachineMemOperand *MMO = *SextLoad->memoperands_begin();
456 if (MMO->getSizeInBits().getValue() != 8)
457 return false;
458
459 return applyD16Load(AMDGPU::G_AMDGPU_LOAD_D16_LO_I8, MI, SextLoad, Dst);
460 }
461
462 return false;
463 }
464
465 // Load hi
466 if (mi_match(MI.getOperand(1).getReg(), MRI,
468 m_Copy(m_SpecificICst(CleanHi16))),
470
471 if (Load->getOpcode() == AMDGPU::G_ZEXTLOAD) {
472 const MachineMemOperand *MMO = *Load->memoperands_begin();
473 unsigned LoadSize = MMO->getSizeInBits().getValue();
474 if (LoadSize == 8)
475 return applyD16Load(AMDGPU::G_AMDGPU_LOAD_D16_HI_U8, MI, Load, Dst);
476 if (LoadSize == 16)
477 return applyD16Load(AMDGPU::G_AMDGPU_LOAD_D16_HI, MI, Load, Dst);
478 return false;
479 }
480
481 // s32 Load_lo16 holds SextLoad i8, Load_hi16 is zero.
482 // fake16: and (sextload i8 -> s32), 0xFFFF
483 // true16: zext (sextload i8 -> s16) -> s32
484 if (mi_match(
485 Load, MRI,
486 m_GAnd(m_MInstr(SextLoad), m_Copy(m_SpecificICst(CleanHi16)))) ||
487 mi_match(Load, MRI,
489 m_MInstr(SextLoad))))) {
490 if (SextLoad->getOpcode() != AMDGPU::G_SEXTLOAD)
491 return false;
492
493 const MachineMemOperand *MMO = *SextLoad->memoperands_begin();
494 if (MMO->getSizeInBits().getValue() != 8)
495 return false;
496
497 return applyD16Load(AMDGPU::G_AMDGPU_LOAD_D16_HI_I8, MI, SextLoad, Dst);
498 }
499
500 return false;
501 }
502
503 return false;
504}
505
506void AMDGPURegBankCombinerImpl::applyMinMaxToMinMax3(
507 MachineInstr &MI, MinMaxToMinMax3MatchInfo &MatchInfo) const {
508 B.buildInstr(MatchInfo.Opc, {MI.getOperand(0)},
509 {MatchInfo.Val0, MatchInfo.Val1, MatchInfo.Val2}, MI.getFlags());
510 MI.eraseFromParent();
511 return;
512}
513
514// min(min(a, b), c) == min(a, min(b, c)) == min3(a, b, c)
515// supported scalar type: S32 S16 U32 U16 F32 F16
516bool AMDGPURegBankCombinerImpl::matchMinMaxToMinMax3(
517 MachineInstr &MI, MinMaxToMinMax3MatchInfo &MatchInfo) const {
518 Register Dst = MI.getOperand(0).getReg();
519 Register Src1 = MI.getOperand(1).getReg();
520 Register Src2 = MI.getOperand(2).getReg();
521 // If the register is SGPR, don't optimize it.
522 if (!(isVgprRegBank(Dst) && isVgprRegBank(Src1) && isVgprRegBank(Src2))) {
523 return false;
524 }
525
526 LLT Ty = MRI.getType(Dst);
527 unsigned Opc = MI.getOpcode();
528 if (!(Ty == LLT::scalar(32) ||
529 (Ty == LLT::scalar(16) && STI.hasMin3Max3_16())))
530 return false;
531
532 Register R0, R1, R2;
533 if (!mi_match(MI, MRI,
536 m_Reg(R2)))) {
537 return false;
538 }
539
540 unsigned AMDGPUOpc = 0;
541 switch (Opc) {
542 case AMDGPU::G_SMAX:
543 AMDGPUOpc = AMDGPU::G_AMDGPU_SMAX3;
544 break;
545 case AMDGPU::G_SMIN:
546 AMDGPUOpc = AMDGPU::G_AMDGPU_SMIN3;
547 break;
548 case AMDGPU::G_UMAX:
549 AMDGPUOpc = AMDGPU::G_AMDGPU_UMAX3;
550 break;
551 case AMDGPU::G_UMIN:
552 AMDGPUOpc = AMDGPU::G_AMDGPU_UMIN3;
553 break;
554 case AMDGPU::G_FMAXNUM:
555 case AMDGPU::G_FMAXNUM_IEEE:
556 AMDGPUOpc = AMDGPU::G_AMDGPU_FMAX3;
557 break;
558 case AMDGPU::G_FMINNUM:
559 case AMDGPU::G_FMINNUM_IEEE:
560 AMDGPUOpc = AMDGPU::G_AMDGPU_FMIN3;
561 break;
562 case AMDGPU::G_FMAXIMUM:
563 case AMDGPU::G_FMAXIMUMNUM:
564 AMDGPUOpc = AMDGPU::G_AMDGPU_FMAXIMUM3;
565 break;
566 case AMDGPU::G_FMINIMUM:
567 case AMDGPU::G_FMINIMUMNUM:
568 AMDGPUOpc = AMDGPU::G_AMDGPU_FMINIMUM3;
569 break;
570 default:
571 return false;
572 }
573
574 MatchInfo = {AMDGPUOpc, R0, R1, R2};
575 return true;
576}
577
578bool AMDGPURegBankCombinerImpl::applyD16Load(
579 unsigned D16Opc, MachineInstr &DstMI, MachineInstr *SmallLoad,
580 Register SrcReg32ToOverwriteD16) const {
581 Register DstReg = DstMI.getOperand(0).getReg();
582 LLT SrcTy = MRI.getType(SrcReg32ToOverwriteD16);
583
584 // Dst and Src for D16 load need to have same type.
585 Register D16Dst =
586 SrcTy == MRI.getType(DstReg)
587 ? DstReg
588 : MRI.createVirtualRegister({MRI.getRegBank(DstReg), SrcTy});
589
590 B.buildInstr(D16Opc, {D16Dst},
591 {SmallLoad->getOperand(1).getReg(), SrcReg32ToOverwriteD16})
592 .setMemRefs(SmallLoad->memoperands());
593
594 if (D16Dst != DstReg)
595 B.buildBitcast(DstReg, D16Dst);
596
597 DstMI.eraseFromParent();
598 return true;
599}
600
601SIModeRegisterDefaults AMDGPURegBankCombinerImpl::getMode() const {
602 return MF.getInfo<SIMachineFunctionInfo>()->getMode();
603}
604
605bool AMDGPURegBankCombinerImpl::getIEEE() const { return getMode().IEEE; }
606
607bool AMDGPURegBankCombinerImpl::getDX10Clamp() const {
608 return getMode().DX10Clamp;
609}
610
611bool AMDGPURegBankCombinerImpl::isFminnumIeee(const MachineInstr &MI) const {
612 return MI.getOpcode() == AMDGPU::G_FMINNUM_IEEE;
613}
614
615bool AMDGPURegBankCombinerImpl::isFCst(MachineInstr *MI) const {
616 return MI->getOpcode() == AMDGPU::G_FCONSTANT;
617}
618
619bool AMDGPURegBankCombinerImpl::isClampZeroToOne(MachineInstr *K0,
620 MachineInstr *K1) const {
621 if (isFCst(K0) && isFCst(K1)) {
622 const ConstantFP *KO_FPImm = K0->getOperand(1).getFPImm();
623 const ConstantFP *K1_FPImm = K1->getOperand(1).getFPImm();
624 return (KO_FPImm->isPosZero() && K1_FPImm->isOne()) ||
625 (KO_FPImm->isOne() && K1_FPImm->isPosZero());
626 }
627 return false;
628}
629
630// Pass boilerplate
631// ================
632
633class AMDGPURegBankCombiner : public MachineFunctionPass {
634public:
635 static char ID;
636
637 AMDGPURegBankCombiner(bool IsOptNone = false);
638
639 StringRef getPassName() const override { return "AMDGPURegBankCombiner"; }
640
641 bool runOnMachineFunction(MachineFunction &MF) override;
642
643 void getAnalysisUsage(AnalysisUsage &AU) const override;
644
645private:
646 bool IsOptNone;
647 AMDGPURegBankCombinerImplRuleConfig RuleConfig;
648};
649} // end anonymous namespace
650
651void AMDGPURegBankCombiner::getAnalysisUsage(AnalysisUsage &AU) const {
652 AU.setPreservesCFG();
654 AU.addRequired<GISelValueTrackingAnalysisLegacy>();
655 AU.addPreserved<GISelValueTrackingAnalysisLegacy>();
656 if (!IsOptNone) {
657 AU.addRequired<MachineDominatorTreeWrapperPass>();
658 }
660}
661
662AMDGPURegBankCombiner::AMDGPURegBankCombiner(bool IsOptNone)
663 : MachineFunctionPass(ID), IsOptNone(IsOptNone) {
664 if (!RuleConfig.parseCommandLineOption())
665 report_fatal_error("Invalid rule identifier");
666}
667
668bool AMDGPURegBankCombiner::runOnMachineFunction(MachineFunction &MF) {
669 if (MF.getProperties().hasFailedISel())
670 return false;
671 const Function &F = MF.getFunction();
672 bool EnableOpt =
673 MF.getTarget().getOptLevel() != CodeGenOptLevel::None && !skipFunction(F);
674
677 &getAnalysis<GISelValueTrackingAnalysisLegacy>().get(MF);
678
679 const auto *LI = ST.getLegalizerInfo();
681 IsOptNone ? nullptr
682 : &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
683
684 CombinerInfo CInfo(/*AllowIllegalOps*/ false, /*ShouldLegalizeIllegal*/ true,
685 LI, EnableOpt, F.hasOptSize(), F.hasMinSize());
686 // Disable fixed-point iteration to reduce compile-time
687 CInfo.MaxIterations = 1;
688 CInfo.ObserverLvl = CombinerInfo::ObserverLevel::SinglePass;
689 // RegBankSelect seems not to leave dead instructions, so a full DCE pass is
690 // unnecessary.
691 CInfo.EnableFullDCE = false;
692 AMDGPURegBankCombinerImpl Impl(MF, CInfo, *VT, /*CSEInfo*/ nullptr,
693 RuleConfig, ST, MDT, LI);
694 return Impl.combineMachineInstrs();
695}
696
697char AMDGPURegBankCombiner::ID = 0;
698INITIALIZE_PASS_BEGIN(AMDGPURegBankCombiner, DEBUG_TYPE,
699 "Combine AMDGPU machine instrs after regbankselect",
700 false, false)
702INITIALIZE_PASS_END(AMDGPURegBankCombiner, DEBUG_TYPE,
703 "Combine AMDGPU machine instrs after regbankselect", false,
704 false)
705
707 return new AMDGPURegBankCombiner(IsOptNone);
708}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
#define GET_GICOMBINER_CONSTRUCTOR_INITS
This file declares the targeting of the Machinelegalizer class for AMDGPU.
Provides AMDGPU specific target descriptions.
This file declares the targeting of the RegisterBankInfo class for AMDGPU.
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This contains common combine transformations that may be used in a combine pass,or by the target else...
Option class for Targets to specify which operations are combined how and when.
This contains the base class for all Combiners generated by TableGen.
AMD GCN specific subclass of TargetSubtarget.
Provides analysis for querying information about KnownBits during GISel passes.
#define DEBUG_TYPE
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Contains matchers for matching SSA Machine Instructions.
Register Reg
Register const TargetRegisterInfo * TRI
#define R2(n)
Promote Memory to Register
Definition Mem2Reg.cpp:110
#define INITIALIZE_PASS_DEPENDENCY(depName)
Definition PassSupport.h:42
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition PassSupport.h:44
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Definition PassSupport.h:39
static StringRef getName(Value *V)
static bool isClampZeroToOne(SDValue A, SDValue B)
Target-Independent Code Generator Pass Configuration Options pass.
AnalysisUsage & addRequired()
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
Definition Pass.cpp:275
Combiner implementation.
Definition Combiner.h:33
bool isPosZero() const
Return true if the value is positive zero.
Definition Constants.h:470
bool isOne() const
Returns true if this value is exactly +1.0.
Definition Constants.h:485
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:314
bool hasMin3Max3_16() const
bool hasMed3_16() const
The CSE Analysis object.
Definition CSEInfo.h:72
To use KnownBitsInfo analysis in a pass, KnownBitsInfo &Info = getAnalysis<GISelValueTrackingInfoAnal...
constexpr unsigned getScalarSizeInBits() const
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
TypeSize getValue() const
DominatorTree Class - Concrete subclass of DominatorTreeBase that is used to compute a normal dominat...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
Function & getFunction()
Return the LLVM function that this machine code represents.
const MachineFunctionProperties & getProperties() const
Get the function properties.
const TargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
mmo_iterator memoperands_begin() const
Access to memory operands of the instruction.
ArrayRef< MachineMemOperand * > memoperands() const
Access to memory operands of the instruction.
const MachineOperand & getOperand(unsigned i) const
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
LocationSize getSizeInBits() const
Return the size in bits of the memory reference.
Register getReg() const
getReg - Returns the register number.
const ConstantFP * getFPImm() const
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI bool hasOneNonDBGUse(Register RegNo) const
hasOneNonDBGUse - Return true if there is exactly one non-Debug use of the specified register.
const RegisterBank * getRegBank(Register Reg) const
Return the register bank of Reg.
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
LLT getType(Register Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register.
LLVM_ABI void setRegBank(Register Reg, const RegisterBank &RegBank)
Set the register bank to RegBank for Reg.
Holds all the information related to register banks.
const RegisterBank & getRegBank(unsigned ID)
Get the register bank identified by ID.
unsigned getID() const
Get the identifier of this register bank.
Wrapper class representing virtual and physical registers.
Definition Register.h:20
CodeGenOptLevel getOptLevel() const
Returns the optimization level: None, Less, Default, or Aggressive.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
operand_type_match m_Reg()
SpecificConstantMatch m_SpecificICst(const APInt &RequestedValue)
Matches a constant equal to RequestedValue.
UnaryOp_match< SrcTy, TargetOpcode::COPY > m_Copy(SrcTy &&Src)
UnaryOp_match< SrcTy, TargetOpcode::G_ZEXT > m_GZExt(const SrcTy &Src)
BinaryOp_match< LHS, RHS, TargetOpcode::G_OR, true > m_GOr(const LHS &L, const RHS &R)
OneNonDBGUse_match< SubPat > m_OneNonDBGUse(const SubPat &SP)
CheckType m_SpecificType(LLT Ty)
BinaryOpc_match< LHS, RHS, true > m_CommutativeBinOp(unsigned Opcode, const LHS &L, const RHS &R)
bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SHL, false > m_GShl(const LHS &L, const RHS &R)
Or< Preds... > m_any_of(Preds &&... preds)
BinaryOp_match< LHS, RHS, TargetOpcode::G_AND, true > m_GAnd(const LHS &L, const RHS &R)
UnaryOp_match< SrcTy, TargetOpcode::G_BITCAST > m_GBitcast(const SrcTy &Src)
bind_ty< MachineInstr * > m_MInstr(MachineInstr *&MI)
And< Preds... > m_all_of(Preds &&... preds)
auto m_BinOp()
Match an arbitrary binary operation and ignore it.
NodeAddr< DefNode * > Def
Definition RDFGraph.h:384
NodeAddr< UseNode * > Use
Definition RDFGraph.h:385
This is an optimization pass for GlobalISel generic memory operations.
@ Load
The value being inserted comes from a load (InsertElement only).
FunctionPass * createAMDGPURegBankCombiner(bool IsOptNone)
LLVM_ABI MachineInstr * getDefIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, folding away any trivial copies.
Definition Utils.cpp:497
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
LLVM_ABI void getSelectionDAGFallbackAnalysisUsage(AnalysisUsage &AU)
Modify analysis usage so it preserves passes required for the SelectionDAG fallback.
Definition Utils.cpp:1137
@ And
Bitwise or logical AND of integers.
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
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition BitVector.h:880
@ SinglePass
Enables Observer-based DCE and additional heuristics that retry combining defined and used instructio...