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"
30
31#define GET_GICOMBINER_DEPS
32#include "AMDGPUGenPreLegalizeGICombiner.inc"
33#undef GET_GICOMBINER_DEPS
34
35#define DEBUG_TYPE "amdgpu-regbank-combiner"
36
37using namespace llvm;
38using namespace MIPatternMatch;
39
40namespace {
41#define GET_GICOMBINER_TYPES
42#include "AMDGPUGenRegBankGICombiner.inc"
43#undef GET_GICOMBINER_TYPES
44
45class AMDGPURegBankCombinerImpl : public Combiner {
46protected:
47 const AMDGPURegBankCombinerImplRuleConfig &RuleConfig;
48 const GCNSubtarget &STI;
49 const RegisterBankInfo &RBI;
51 const SIInstrInfo &TII;
52 const CombinerHelper Helper;
53
54public:
55 AMDGPURegBankCombinerImpl(
57 GISelCSEInfo *CSEInfo,
58 const AMDGPURegBankCombinerImplRuleConfig &RuleConfig,
59 const GCNSubtarget &STI, MachineDominatorTree *MDT,
60 const LegalizerInfo *LI);
61
62 static const char *getName() { return "AMDGPURegBankCombinerImpl"; }
63
64 bool tryCombineAll(MachineInstr &I) const override;
65
66 bool isVgprRegBank(Register Reg) const;
67 Register getAsVgpr(Register Reg) const;
68
69 struct MinMaxMedOpc {
70 unsigned Min, Max, Med;
71 };
72
73 struct Med3MatchInfo {
74 unsigned Opc;
75 Register Val0, Val1, Val2;
76 };
77
78 struct MinMaxToMinMax3MatchInfo {
79 unsigned Opc;
80 Register Val0, Val1, Val2;
81 };
82
83 MinMaxMedOpc getMinMaxPair(unsigned Opc) const;
84
85 template <class m_Cst, typename CstTy>
86 bool matchMed(MachineInstr &MI, MachineRegisterInfo &MRI, MinMaxMedOpc MMMOpc,
87 Register &Val, CstTy &K0, CstTy &K1) const;
88
89 bool matchIntMinMaxToMed3(MachineInstr &MI, Med3MatchInfo &MatchInfo) const;
90 bool matchFPMinMaxToMed3(MachineInstr &MI, Med3MatchInfo &MatchInfo) const;
91 bool matchFPMinMaxToClamp(MachineInstr &MI, Register &Reg) const;
92 bool matchFPMed3ToClamp(MachineInstr &MI, Register &Reg) const;
93 void applyMed3(MachineInstr &MI, Med3MatchInfo &MatchInfo) const;
94 void applyClamp(MachineInstr &MI, Register &Reg) const;
95
96 void applyCanonicalizeZextShiftAmt(MachineInstr &MI, MachineInstr &Ext) const;
97
98 bool combineD16Load(MachineInstr &MI) const;
99 bool applyD16Load(unsigned D16Opc, MachineInstr &DstMI,
100 MachineInstr *SmallLoad, Register ToOverwriteD16) const;
101
102 bool matchMinMaxToMinMax3(MachineInstr &MI,
103 MinMaxToMinMax3MatchInfo &MatchInfo) const;
104 void applyMinMaxToMinMax3(MachineInstr &MI,
105 MinMaxToMinMax3MatchInfo &MatchInfo) const;
106
107private:
108 SIModeRegisterDefaults getMode() const;
109 bool getIEEE() const;
110 bool getDX10Clamp() const;
111 bool isFminnumIeee(const MachineInstr &MI) const;
112 bool isFCst(MachineInstr *MI) const;
113 bool isClampZeroToOne(MachineInstr *K0, MachineInstr *K1) const;
114
115#define GET_GICOMBINER_CLASS_MEMBERS
116#define AMDGPUSubtarget GCNSubtarget
117#include "AMDGPUGenRegBankGICombiner.inc"
118#undef GET_GICOMBINER_CLASS_MEMBERS
119#undef AMDGPUSubtarget
120};
121
122#define GET_GICOMBINER_IMPL
123#define AMDGPUSubtarget GCNSubtarget
124#include "AMDGPUGenRegBankGICombiner.inc"
125#undef AMDGPUSubtarget
126#undef GET_GICOMBINER_IMPL
127
128AMDGPURegBankCombinerImpl::AMDGPURegBankCombinerImpl(
130 GISelCSEInfo *CSEInfo,
131 const AMDGPURegBankCombinerImplRuleConfig &RuleConfig,
132 const GCNSubtarget &STI, MachineDominatorTree *MDT, const LegalizerInfo *LI)
133 : Combiner(MF, CInfo, &VT, CSEInfo), RuleConfig(RuleConfig), STI(STI),
134 RBI(*STI.getRegBankInfo()), TRI(*STI.getRegisterInfo()),
135 TII(*STI.getInstrInfo()),
136 Helper(Observer, B, /*IsPreLegalize*/ false, &VT, MDT, LI),
138#include "AMDGPUGenRegBankGICombiner.inc"
140{
141}
142
143bool AMDGPURegBankCombinerImpl::isVgprRegBank(Register Reg) const {
144 return RBI.getRegBank(Reg, MRI, TRI)->getID() == AMDGPU::VGPRRegBankID;
145}
146
147Register AMDGPURegBankCombinerImpl::getAsVgpr(Register Reg) const {
148 if (isVgprRegBank(Reg))
149 return Reg;
150
151 // Search for existing copy of Reg to vgpr.
152 for (MachineInstr &Use : MRI.use_instructions(Reg)) {
153 Register Def = Use.getOperand(0).getReg();
154 if (Use.getOpcode() == AMDGPU::COPY && isVgprRegBank(Def))
155 return Def;
156 }
157
158 // Copy Reg to vgpr.
159 Register VgprReg = B.buildCopy(MRI.getType(Reg), Reg).getReg(0);
160 MRI.setRegBank(VgprReg, RBI.getRegBank(AMDGPU::VGPRRegBankID));
161 return VgprReg;
162}
163
164AMDGPURegBankCombinerImpl::MinMaxMedOpc
165AMDGPURegBankCombinerImpl::getMinMaxPair(unsigned Opc) const {
166 switch (Opc) {
167 default:
168 llvm_unreachable("Unsupported opcode");
169 case AMDGPU::G_SMAX:
170 case AMDGPU::G_SMIN:
171 return {AMDGPU::G_SMIN, AMDGPU::G_SMAX, AMDGPU::G_AMDGPU_SMED3};
172 case AMDGPU::G_UMAX:
173 case AMDGPU::G_UMIN:
174 return {AMDGPU::G_UMIN, AMDGPU::G_UMAX, AMDGPU::G_AMDGPU_UMED3};
175 case AMDGPU::G_FMAXNUM:
176 case AMDGPU::G_FMINNUM:
177 return {AMDGPU::G_FMINNUM, AMDGPU::G_FMAXNUM, AMDGPU::G_AMDGPU_FMED3};
178 case AMDGPU::G_FMAXNUM_IEEE:
179 case AMDGPU::G_FMINNUM_IEEE:
180 return {AMDGPU::G_FMINNUM_IEEE, AMDGPU::G_FMAXNUM_IEEE,
181 AMDGPU::G_AMDGPU_FMED3};
182 }
183}
184
185template <class m_Cst, typename CstTy>
186bool AMDGPURegBankCombinerImpl::matchMed(MachineInstr &MI,
187 MachineRegisterInfo &MRI,
188 MinMaxMedOpc MMMOpc, Register &Val,
189 CstTy &K0, CstTy &K1) const {
190 // 4 operand commutes of: min(max(Val, K0), K1).
191 // Find K1 from outer instr: min(max(...), K1) or min(K1, max(...)).
192 // Find K0 and Val from inner instr: max(K0, Val) or max(Val, K0).
193 // 4 operand commutes of: max(min(Val, K1), K0).
194 // Find K0 from outer instr: max(min(...), K0) or max(K0, min(...)).
195 // Find K1 and Val from inner instr: min(K1, Val) or min(Val, K1).
196 return mi_match(
197 MI, MRI,
198 m_any_of(
200 MMMOpc.Min, m_CommutativeBinOp(MMMOpc.Max, m_Reg(Val), m_Cst(K0)),
201 m_Cst(K1)),
203 MMMOpc.Max, m_CommutativeBinOp(MMMOpc.Min, m_Reg(Val), m_Cst(K1)),
204 m_Cst(K0))));
205}
206
207bool AMDGPURegBankCombinerImpl::matchIntMinMaxToMed3(
208 MachineInstr &MI, Med3MatchInfo &MatchInfo) const {
209 Register Dst = MI.getOperand(0).getReg();
210 if (!isVgprRegBank(Dst))
211 return false;
212
213 // med3 for i16 is only available on gfx9+, and not available for v2i16.
214 LLT Ty = MRI.getType(Dst);
215 if ((Ty != LLT::scalar(16) || !STI.hasMed3_16()) && Ty != LLT::scalar(32))
216 return false;
217
218 MinMaxMedOpc OpcodeTriple = getMinMaxPair(MI.getOpcode());
219 Register Val;
220 std::optional<ValueAndVReg> K0, K1;
221 // Match min(max(Val, K0), K1) or max(min(Val, K1), K0). Then see if K0 <= K1.
222 if (!matchMed<GCstAndRegMatch>(MI, MRI, OpcodeTriple, Val, K0, K1))
223 return false;
224
225 if (OpcodeTriple.Med == AMDGPU::G_AMDGPU_SMED3 && K0->Value.sgt(K1->Value))
226 return false;
227 if (OpcodeTriple.Med == AMDGPU::G_AMDGPU_UMED3 && K0->Value.ugt(K1->Value))
228 return false;
229
230 MatchInfo = {OpcodeTriple.Med, Val, K0->VReg, K1->VReg};
231 return true;
232}
233
234// fmed3(NaN, K0, K1) = min(min(NaN, K0), K1)
235// ieee = true : min/max(SNaN, K) = QNaN, min/max(QNaN, K) = K
236// ieee = false : min/max(NaN, K) = K
237// clamp(NaN) = dx10_clamp ? 0.0 : NaN
238// Consider values of min(max(Val, K0), K1) and max(min(Val, K1), K0) as input.
239// Other operand commutes (see matchMed) give same result since min and max are
240// commutative.
241
242// Try to replace fp min(max(Val, K0), K1) or max(min(Val, K1), K0), KO<=K1
243// with fmed3(Val, K0, K1) or clamp(Val). Clamp requires K0 = 0.0 and K1 = 1.0.
244// Val = SNaN only for ieee = true
245// fmed3(SNaN, K0, K1) = min(min(SNaN, K0), K1) = min(QNaN, K1) = K1
246// min(max(SNaN, K0), K1) = min(QNaN, K1) = K1
247// max(min(SNaN, K1), K0) = max(K1, K0) = K1
248// Val = NaN,ieee = false or Val = QNaN,ieee = true
249// fmed3(NaN, K0, K1) = min(min(NaN, K0), K1) = min(K0, K1) = K0
250// min(max(NaN, K0), K1) = min(K0, K1) = K0 (can clamp when dx10_clamp = true)
251// max(min(NaN, K1), K0) = max(K1, K0) = K1 != K0
252bool AMDGPURegBankCombinerImpl::matchFPMinMaxToMed3(
253 MachineInstr &MI, Med3MatchInfo &MatchInfo) const {
254 Register Dst = MI.getOperand(0).getReg();
255 // Perform combine only when the destination is a VGPR.
256 if (!isVgprRegBank(Dst))
257 return false;
258
259 LLT Ty = MRI.getType(Dst);
260
261 // med3 for f16 is only available on gfx9+, and not available for v2f16.
262 if ((Ty != LLT::scalar(16) || !STI.hasMed3_16()) && Ty != LLT::scalar(32))
263 return false;
264
265 auto OpcodeTriple = getMinMaxPair(MI.getOpcode());
266
267 Register Val;
268 std::optional<FPValueAndVReg> K0, K1;
269 // Match min(max(Val, K0), K1) or max(min(Val, K1), K0). Then see if K0 <= K1.
270 if (!matchMed<GFCstAndRegMatch>(MI, MRI, OpcodeTriple, Val, K0, K1))
271 return false;
272
273 if (K0->Value > K1->Value)
274 return false;
275
276 // For IEEE=false perform combine only when it's safe to assume that there are
277 // no NaN inputs. Most often MI is marked with nnan fast math flag.
278 // For IEEE=true consider NaN inputs. fmed3(NaN, K0, K1) is equivalent to
279 // min(min(NaN, K0), K1). Safe to fold for min(max(Val, K0), K1) since inner
280 // nodes(max/min) have same behavior when one input is NaN and other isn't.
281 // Don't consider max(min(SNaN, K1), K0) since there is no isKnownNeverQNaN,
282 // also post-legalizer inputs to min/max are fcanonicalized (never SNaN).
283 if ((getIEEE() && isFminnumIeee(MI)) || VT->isKnownNeverNaN(Dst)) {
284 // Don't fold single use constant that can't be inlined.
285 if ((!MRI.hasOneNonDBGUse(K0->VReg) || TII.isInlineConstant(K0->Value)) &&
286 (!MRI.hasOneNonDBGUse(K1->VReg) || TII.isInlineConstant(K1->Value))) {
287 MatchInfo = {OpcodeTriple.Med, Val, K0->VReg, K1->VReg};
288 return true;
289 }
290 }
291
292 return false;
293}
294
295bool AMDGPURegBankCombinerImpl::matchFPMinMaxToClamp(MachineInstr &MI,
296 Register &Reg) const {
297 // Perform combine only when the destination is a VGPR.
298 if (!isVgprRegBank(MI.getOperand(0).getReg()))
299 return false;
300
301 // Clamp is available on all types after regbankselect (f16, f32, f64, v2f16).
302 auto OpcodeTriple = getMinMaxPair(MI.getOpcode());
303 Register Val;
304 std::optional<FPValueAndVReg> K0, K1;
305 // Match min(max(Val, K0), K1) or max(min(Val, K1), K0).
306 if (!matchMed<GFCstOrSplatGFCstMatch>(MI, MRI, OpcodeTriple, Val, K0, K1))
307 return false;
308
309 if (!K0->Value.isPosZero() || !K1->Value.isOne())
310 return false;
311
312 // For IEEE=false perform combine only when it's safe to assume that there are
313 // no NaN inputs. Most often MI is marked with nnan fast math flag.
314 // For IEEE=true consider NaN inputs. Only min(max(QNaN, 0.0), 1.0) evaluates
315 // to 0.0 requires dx10_clamp = true.
316 if ((getIEEE() && getDX10Clamp() && isFminnumIeee(MI) &&
317 VT->isKnownNeverSNaN(Val)) ||
318 VT->isKnownNeverNaN(MI.getOperand(0).getReg())) {
319 Reg = Val;
320 return true;
321 }
322
323 return false;
324}
325
326// Replacing fmed3(NaN, 0.0, 1.0) with clamp. Requires dx10_clamp = true.
327// Val = SNaN only for ieee = true. It is important which operand is NaN.
328// min(min(SNaN, 0.0), 1.0) = min(QNaN, 1.0) = 1.0
329// min(min(SNaN, 1.0), 0.0) = min(QNaN, 0.0) = 0.0
330// min(min(0.0, 1.0), SNaN) = min(0.0, SNaN) = QNaN
331// Val = NaN,ieee = false or Val = QNaN,ieee = true
332// min(min(NaN, 0.0), 1.0) = min(0.0, 1.0) = 0.0
333// min(min(NaN, 1.0), 0.0) = min(1.0, 0.0) = 0.0
334// min(min(0.0, 1.0), NaN) = min(0.0, NaN) = 0.0
335bool AMDGPURegBankCombinerImpl::matchFPMed3ToClamp(MachineInstr &MI,
336 Register &Reg) const {
337 // Perform combine only when the destination is a VGPR.
338 if (!isVgprRegBank(MI.getOperand(0).getReg()))
339 return false;
340
341 // In llvm-ir, clamp is often represented as an intrinsic call to
342 // @llvm.amdgcn.fmed3.f32(%Val, 0.0, 1.0). Check for other operand orders.
343 MachineInstr *Src0 = getDefIgnoringCopies(MI.getOperand(1).getReg(), MRI);
344 MachineInstr *Src1 = getDefIgnoringCopies(MI.getOperand(2).getReg(), MRI);
345 MachineInstr *Src2 = getDefIgnoringCopies(MI.getOperand(3).getReg(), MRI);
346
347 if (isFCst(Src0) && !isFCst(Src1))
348 std::swap(Src0, Src1);
349 if (isFCst(Src1) && !isFCst(Src2))
350 std::swap(Src1, Src2);
351 if (isFCst(Src0) && !isFCst(Src1))
352 std::swap(Src0, Src1);
353 if (!isClampZeroToOne(Src1, Src2))
354 return false;
355
356 Register Val = Src0->getOperand(0).getReg();
357
358 auto isOp3Zero = [&]() {
359 MachineInstr *Op3 = getDefIgnoringCopies(MI.getOperand(3).getReg(), MRI);
360 if (Op3->getOpcode() == TargetOpcode::G_FCONSTANT)
361 return Op3->getOperand(1).getFPImm()->isPosZero();
362 return false;
363 };
364 // For IEEE=false perform combine only when it's safe to assume that there are
365 // no NaN inputs. Most often MI is marked with nnan fast math flag.
366 // For IEEE=true consider NaN inputs. Requires dx10_clamp = true. Safe to fold
367 // when Val could be QNaN. If Val can also be SNaN third input should be 0.0.
368 if (VT->isKnownNeverNaN(MI.getOperand(0).getReg()) ||
369 (getIEEE() && getDX10Clamp() &&
370 (VT->isKnownNeverSNaN(Val) || isOp3Zero()))) {
371 Reg = Val;
372 return true;
373 }
374
375 return false;
376}
377
378void AMDGPURegBankCombinerImpl::applyClamp(MachineInstr &MI,
379 Register &Reg) const {
380 B.buildInstr(AMDGPU::G_AMDGPU_CLAMP, {MI.getOperand(0)}, {Reg},
381 MI.getFlags());
382 MI.eraseFromParent();
383}
384
385void AMDGPURegBankCombinerImpl::applyMed3(MachineInstr &MI,
386 Med3MatchInfo &MatchInfo) const {
387 B.buildInstr(MatchInfo.Opc, {MI.getOperand(0)},
388 {getAsVgpr(MatchInfo.Val0), getAsVgpr(MatchInfo.Val1),
389 getAsVgpr(MatchInfo.Val2)},
390 MI.getFlags());
391 MI.eraseFromParent();
392}
393
394void AMDGPURegBankCombinerImpl::applyCanonicalizeZextShiftAmt(
395 MachineInstr &MI, MachineInstr &Ext) const {
396 unsigned ShOpc = MI.getOpcode();
397 assert(ShOpc == AMDGPU::G_SHL || ShOpc == AMDGPU::G_LSHR ||
398 ShOpc == AMDGPU::G_ASHR);
399 assert(Ext.getOpcode() == AMDGPU::G_ZEXT);
400
401 Register AmtReg = Ext.getOperand(1).getReg();
402 Register ShDst = MI.getOperand(0).getReg();
403 Register ShSrc = MI.getOperand(1).getReg();
404
405 LLT ExtAmtTy = MRI.getType(Ext.getOperand(0).getReg());
406 LLT AmtTy = MRI.getType(AmtReg);
407
408 auto &RB = *MRI.getRegBank(AmtReg);
409
410 auto NewExt = B.buildAnyExt(ExtAmtTy, AmtReg);
411 auto Mask = B.buildConstant(
413 auto And = B.buildAnd(ExtAmtTy, NewExt, Mask);
414 B.buildInstr(ShOpc, {ShDst}, {ShSrc, And});
415
416 MRI.setRegBank(NewExt.getReg(0), RB);
417 MRI.setRegBank(Mask.getReg(0), RB);
418 MRI.setRegBank(And.getReg(0), RB);
419 MI.eraseFromParent();
420}
421
422bool AMDGPURegBankCombinerImpl::combineD16Load(MachineInstr &MI) const {
423 Register Dst;
424 MachineInstr *Load, *SextLoad;
425 const int64_t CleanLo16 = 0xFFFFFFFFFFFF0000;
426 const int64_t CleanHi16 = 0x000000000000FFFF;
427
428 // Load lo
429 if (mi_match(MI.getOperand(1).getReg(), MRI,
431 m_Copy(m_SpecificICst(CleanLo16))),
432 m_MInstr(Load)))) {
433
434 if (Load->getOpcode() == AMDGPU::G_ZEXTLOAD) {
435 const MachineMemOperand *MMO = *Load->memoperands_begin();
436 unsigned LoadSize = MMO->getSizeInBits().getValue();
437 if (LoadSize == 8)
438 return applyD16Load(AMDGPU::G_AMDGPU_LOAD_D16_LO_U8, MI, Load, Dst);
439 if (LoadSize == 16)
440 return applyD16Load(AMDGPU::G_AMDGPU_LOAD_D16_LO, MI, Load, Dst);
441 return false;
442 }
443
444 // s32 Load_lo16 holds SextLoad i8, Load_hi16 is zero.
445 // fake16: and (sextload i8 -> s32), 0xFFFF
446 // true16: zext (sextload i8 -> s16) -> s32
447 if (mi_match(
448 Load, MRI,
449 m_GAnd(m_MInstr(SextLoad), m_Copy(m_SpecificICst(CleanHi16)))) ||
450 mi_match(Load, MRI,
452 m_MInstr(SextLoad))))) {
453 if (SextLoad->getOpcode() != AMDGPU::G_SEXTLOAD)
454 return false;
455
456 const MachineMemOperand *MMO = *SextLoad->memoperands_begin();
457 if (MMO->getSizeInBits().getValue() != 8)
458 return false;
459
460 return applyD16Load(AMDGPU::G_AMDGPU_LOAD_D16_LO_I8, MI, SextLoad, Dst);
461 }
462
463 return false;
464 }
465
466 // Load hi
467 if (mi_match(MI.getOperand(1).getReg(), MRI,
469 m_Copy(m_SpecificICst(CleanHi16))),
471
472 if (Load->getOpcode() == AMDGPU::G_ZEXTLOAD) {
473 const MachineMemOperand *MMO = *Load->memoperands_begin();
474 unsigned LoadSize = MMO->getSizeInBits().getValue();
475 if (LoadSize == 8)
476 return applyD16Load(AMDGPU::G_AMDGPU_LOAD_D16_HI_U8, MI, Load, Dst);
477 if (LoadSize == 16)
478 return applyD16Load(AMDGPU::G_AMDGPU_LOAD_D16_HI, MI, Load, Dst);
479 return false;
480 }
481
482 // s32 Load_lo16 holds SextLoad i8, Load_hi16 is zero.
483 // fake16: and (sextload i8 -> s32), 0xFFFF
484 // true16: zext (sextload i8 -> s16) -> s32
485 if (mi_match(
486 Load, MRI,
487 m_GAnd(m_MInstr(SextLoad), m_Copy(m_SpecificICst(CleanHi16)))) ||
488 mi_match(Load, MRI,
490 m_MInstr(SextLoad))))) {
491 if (SextLoad->getOpcode() != AMDGPU::G_SEXTLOAD)
492 return false;
493
494 const MachineMemOperand *MMO = *SextLoad->memoperands_begin();
495 if (MMO->getSizeInBits().getValue() != 8)
496 return false;
497
498 return applyD16Load(AMDGPU::G_AMDGPU_LOAD_D16_HI_I8, MI, SextLoad, Dst);
499 }
500
501 return false;
502 }
503
504 return false;
505}
506
507void AMDGPURegBankCombinerImpl::applyMinMaxToMinMax3(
508 MachineInstr &MI, MinMaxToMinMax3MatchInfo &MatchInfo) const {
509 B.buildInstr(MatchInfo.Opc, {MI.getOperand(0)},
510 {MatchInfo.Val0, MatchInfo.Val1, MatchInfo.Val2}, MI.getFlags());
511 MI.eraseFromParent();
512 return;
513}
514
515// min(min(a, b), c) == min(a, min(b, c)) == min3(a, b, c)
516// supported scalar type: S32 S16 U32 U16 F32 F16
517bool AMDGPURegBankCombinerImpl::matchMinMaxToMinMax3(
518 MachineInstr &MI, MinMaxToMinMax3MatchInfo &MatchInfo) const {
519 Register Dst = MI.getOperand(0).getReg();
520 Register Src1 = MI.getOperand(1).getReg();
521 Register Src2 = MI.getOperand(2).getReg();
522 // If the register is SGPR, don't optimize it.
523 if (!(isVgprRegBank(Dst) && isVgprRegBank(Src1) && isVgprRegBank(Src2))) {
524 return false;
525 }
526
527 LLT Ty = MRI.getType(Dst);
528 unsigned Opc = MI.getOpcode();
529 if (!(Ty == LLT::scalar(32) ||
530 (Ty == LLT::scalar(16) && STI.hasMin3Max3_16())))
531 return false;
532
533 Register R0, R1, R2;
534 if (!mi_match(MI, MRI,
537 m_Reg(R2)))) {
538 return false;
539 }
540
541 unsigned AMDGPUOpc = 0;
542 switch (Opc) {
543 case AMDGPU::G_SMAX:
544 AMDGPUOpc = AMDGPU::G_AMDGPU_SMAX3;
545 break;
546 case AMDGPU::G_SMIN:
547 AMDGPUOpc = AMDGPU::G_AMDGPU_SMIN3;
548 break;
549 case AMDGPU::G_UMAX:
550 AMDGPUOpc = AMDGPU::G_AMDGPU_UMAX3;
551 break;
552 case AMDGPU::G_UMIN:
553 AMDGPUOpc = AMDGPU::G_AMDGPU_UMIN3;
554 break;
555 case AMDGPU::G_FMAXNUM:
556 case AMDGPU::G_FMAXNUM_IEEE:
557 AMDGPUOpc = AMDGPU::G_AMDGPU_FMAX3;
558 break;
559 case AMDGPU::G_FMINNUM:
560 case AMDGPU::G_FMINNUM_IEEE:
561 AMDGPUOpc = AMDGPU::G_AMDGPU_FMIN3;
562 break;
563 case AMDGPU::G_FMAXIMUM:
564 case AMDGPU::G_FMAXIMUMNUM:
565 AMDGPUOpc = AMDGPU::G_AMDGPU_FMAXIMUM3;
566 break;
567 case AMDGPU::G_FMINIMUM:
568 case AMDGPU::G_FMINIMUMNUM:
569 AMDGPUOpc = AMDGPU::G_AMDGPU_FMINIMUM3;
570 break;
571 default:
572 return false;
573 }
574
575 MatchInfo = {AMDGPUOpc, R0, R1, R2};
576 return true;
577}
578
579bool AMDGPURegBankCombinerImpl::applyD16Load(
580 unsigned D16Opc, MachineInstr &DstMI, MachineInstr *SmallLoad,
581 Register SrcReg32ToOverwriteD16) const {
582 Register DstReg = DstMI.getOperand(0).getReg();
583 LLT SrcTy = MRI.getType(SrcReg32ToOverwriteD16);
584
585 // Dst and Src for D16 load need to have same type.
586 Register D16Dst =
587 SrcTy == MRI.getType(DstReg)
588 ? DstReg
589 : MRI.createVirtualRegister({MRI.getRegBank(DstReg), SrcTy});
590
591 B.buildInstr(D16Opc, {D16Dst},
592 {SmallLoad->getOperand(1).getReg(), SrcReg32ToOverwriteD16})
593 .setMemRefs(SmallLoad->memoperands());
594
595 if (D16Dst != DstReg)
596 B.buildBitcast(DstReg, D16Dst);
597
598 DstMI.eraseFromParent();
599 return true;
600}
601
602SIModeRegisterDefaults AMDGPURegBankCombinerImpl::getMode() const {
603 return MF.getInfo<SIMachineFunctionInfo>()->getMode();
604}
605
606bool AMDGPURegBankCombinerImpl::getIEEE() const { return getMode().IEEE; }
607
608bool AMDGPURegBankCombinerImpl::getDX10Clamp() const {
609 return getMode().DX10Clamp;
610}
611
612bool AMDGPURegBankCombinerImpl::isFminnumIeee(const MachineInstr &MI) const {
613 return MI.getOpcode() == AMDGPU::G_FMINNUM_IEEE;
614}
615
616bool AMDGPURegBankCombinerImpl::isFCst(MachineInstr *MI) const {
617 return MI->getOpcode() == AMDGPU::G_FCONSTANT;
618}
619
620bool AMDGPURegBankCombinerImpl::isClampZeroToOne(MachineInstr *K0,
621 MachineInstr *K1) const {
622 if (isFCst(K0) && isFCst(K1)) {
623 const ConstantFP *KO_FPImm = K0->getOperand(1).getFPImm();
624 const ConstantFP *K1_FPImm = K1->getOperand(1).getFPImm();
625 return (KO_FPImm->isPosZero() && K1_FPImm->isOne()) ||
626 (KO_FPImm->isOne() && K1_FPImm->isPosZero());
627 }
628 return false;
629}
630
631static bool runCombiner(MachineFunction &MF,
632 function_ref<GISelValueTracking *()> GetVT,
633 function_ref<MachineDominatorTree *()> GetMDT,
634 bool EnableOpt) {
635 AMDGPURegBankCombinerImplRuleConfig RuleConfig;
636 if (!RuleConfig.parseCommandLineOption())
637 reportFatalUsageError("Invalid rule identifier");
638
639 if (MF.getProperties().hasFailedISel())
640 return false;
641
642 const Function &F = MF.getFunction();
643 const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
644 const auto *LI = ST.getLegalizerInfo();
645
646 CombinerInfo CInfo(/*AllowIllegalOps=*/false, /*ShouldLegalizeIllegal=*/true,
647 LI, EnableOpt, F.hasOptSize(), F.hasMinSize());
648 // Disable fixed-point iteration to reduce compile-time
649 CInfo.MaxIterations = 1;
650 CInfo.ObserverLvl = CombinerInfo::ObserverLevel::SinglePass;
651 // RegBankSelect seems not to leave dead instructions, so a full DCE pass is
652 // unnecessary.
653 CInfo.EnableFullDCE = false;
654
655 GISelValueTracking *VT = GetVT();
656 MachineDominatorTree *MDT = GetMDT();
657 AMDGPURegBankCombinerImpl Impl(MF, CInfo, *VT, /*CSEInfo=*/nullptr,
658 RuleConfig, ST, MDT, LI);
659 return Impl.combineMachineInstrs();
660}
661
662// Pass boilerplate
663// ================
664
665class AMDGPURegBankCombinerLegacy : public MachineFunctionPass {
666public:
667 static char ID;
668
669 AMDGPURegBankCombinerLegacy(bool IsOptLevelNone = false)
670 : MachineFunctionPass(ID), IsOptLevelNone(IsOptLevelNone) {}
671
672 StringRef getPassName() const override { return "AMDGPURegBankCombiner"; }
673
674 bool runOnMachineFunction(MachineFunction &MF) override;
675
676 void getAnalysisUsage(AnalysisUsage &AU) const override;
677
678private:
679 bool IsOptLevelNone;
680};
681} // end anonymous namespace
682
683void AMDGPURegBankCombinerLegacy::getAnalysisUsage(AnalysisUsage &AU) const {
684 AU.setPreservesCFG();
686 AU.addRequired<GISelValueTrackingAnalysisLegacy>();
687 AU.addPreserved<GISelValueTrackingAnalysisLegacy>();
688 if (!IsOptLevelNone) {
689 AU.addRequired<MachineDominatorTreeWrapperPass>();
690 }
692}
693
694bool AMDGPURegBankCombinerLegacy::runOnMachineFunction(MachineFunction &MF) {
695 const Function &F = MF.getFunction();
696 bool EnableOpt =
697 MF.getTarget().getOptLevel() != CodeGenOptLevel::None && !skipFunction(F);
698
699 return runCombiner(
700 MF,
701 [&]() {
702 return &getAnalysis<GISelValueTrackingAnalysisLegacy>().get(MF);
703 },
704 [&]() -> MachineDominatorTree * {
705 return IsOptLevelNone ? nullptr
706 : &getAnalysis<MachineDominatorTreeWrapperPass>()
707 .getDomTree();
708 },
709 EnableOpt);
710}
711
712char AMDGPURegBankCombinerLegacy::ID = 0;
713INITIALIZE_PASS_BEGIN(AMDGPURegBankCombinerLegacy, DEBUG_TYPE,
714 "Combine AMDGPU machine instrs after regbankselect",
715 false, false)
717INITIALIZE_PASS_END(AMDGPURegBankCombinerLegacy, DEBUG_TYPE,
718 "Combine AMDGPU machine instrs after regbankselect", false,
719 false)
720
722 return new AMDGPURegBankCombinerLegacy(IsOptLevelNone);
723}
724
726 : IsOptLevelNone(IsOptLevelNone) {}
727
731 const Function &F = MF.getFunction();
732 bool EnableOpt =
733 MF.getTarget().getOptLevel() != CodeGenOptLevel::None && !F.hasOptNone();
734
735 if (!runCombiner(
736 MF, [&]() { return &MFAM.getResult<GISelValueTrackingAnalysis>(MF); },
737 [&]() -> MachineDominatorTree * {
738 return IsOptLevelNone
739 ? nullptr
741 },
742 EnableOpt))
743 return PreservedAnalyses::all();
744
748 return PA;
749}
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.
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.
AMDGPURegBankCombinerPass(bool IsOptLevelNone=false)
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
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:278
Represents analyses that only rely on functions' control flow.
Definition Analysis.h:73
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
Analysis pass which computes a MachineDominatorTree.
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.
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
Definition Analysis.h:151
PreservedAnalyses & preserve()
Mark an analysis as preserved.
Definition Analysis.h:132
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 * createAMDGPURegBankCombinerLegacy(bool IsOptLevelNone)
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
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 PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
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
LLVM_ABI void reportFatalUsageError(Error Err)
Report a fatal error that does not indicate a bug in LLVM.
Definition Error.cpp:177
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition BitVector.h:880