31#define GET_GICOMBINER_DEPS
32#include "AMDGPUGenPreLegalizeGICombiner.inc"
33#undef GET_GICOMBINER_DEPS
35#define DEBUG_TYPE "amdgpu-regbank-combiner"
41#define GET_GICOMBINER_TYPES
42#include "AMDGPUGenRegBankGICombiner.inc"
43#undef GET_GICOMBINER_TYPES
45class AMDGPURegBankCombinerImpl :
public Combiner {
47 const AMDGPURegBankCombinerImplRuleConfig &RuleConfig;
55 AMDGPURegBankCombinerImpl(
58 const AMDGPURegBankCombinerImplRuleConfig &RuleConfig,
62 static const char *
getName() {
return "AMDGPURegBankCombinerImpl"; }
70 unsigned Min, Max, Med;
73 struct Med3MatchInfo {
78 struct MinMaxToMinMax3MatchInfo {
83 MinMaxMedOpc getMinMaxPair(
unsigned Opc)
const;
85 template <
class m_Cst,
typename CstTy>
87 Register &Val, CstTy &K0, CstTy &K1)
const;
89 bool matchIntMinMaxToMed3(
MachineInstr &
MI, Med3MatchInfo &MatchInfo)
const;
90 bool matchFPMinMaxToMed3(
MachineInstr &
MI, Med3MatchInfo &MatchInfo)
const;
103 MinMaxToMinMax3MatchInfo &MatchInfo)
const;
105 MinMaxToMinMax3MatchInfo &MatchInfo)
const;
109 bool getIEEE()
const;
110 bool getDX10Clamp()
const;
115#define GET_GICOMBINER_CLASS_MEMBERS
116#define AMDGPUSubtarget GCNSubtarget
117#include "AMDGPUGenRegBankGICombiner.inc"
118#undef GET_GICOMBINER_CLASS_MEMBERS
119#undef AMDGPUSubtarget
122#define GET_GICOMBINER_IMPL
123#define AMDGPUSubtarget GCNSubtarget
124#include "AMDGPUGenRegBankGICombiner.inc"
125#undef AMDGPUSubtarget
126#undef GET_GICOMBINER_IMPL
128AMDGPURegBankCombinerImpl::AMDGPURegBankCombinerImpl(
131 const AMDGPURegBankCombinerImplRuleConfig &RuleConfig,
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,
false, &VT, MDT, LI),
138#include
"AMDGPUGenRegBankGICombiner.inc"
143bool AMDGPURegBankCombinerImpl::isVgprRegBank(
Register Reg)
const {
148 if (isVgprRegBank(
Reg))
152 for (MachineInstr &Use : MRI.use_instructions(
Reg)) {
154 if (
Use.getOpcode() == AMDGPU::COPY && isVgprRegBank(Def))
160 MRI.setRegBank(VgprReg, RBI.
getRegBank(AMDGPU::VGPRRegBankID));
164AMDGPURegBankCombinerImpl::MinMaxMedOpc
165AMDGPURegBankCombinerImpl::getMinMaxPair(
unsigned Opc)
const {
171 return {AMDGPU::G_SMIN, AMDGPU::G_SMAX, AMDGPU::G_AMDGPU_SMED3};
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};
185template <
class m_Cst,
typename CstTy>
186bool AMDGPURegBankCombinerImpl::matchMed(MachineInstr &
MI,
187 MachineRegisterInfo &MRI,
189 CstTy &K0, CstTy &K1)
const {
207bool AMDGPURegBankCombinerImpl::matchIntMinMaxToMed3(
208 MachineInstr &
MI, Med3MatchInfo &MatchInfo)
const {
210 if (!isVgprRegBank(Dst))
218 MinMaxMedOpc OpcodeTriple = getMinMaxPair(
MI.getOpcode());
220 std::optional<ValueAndVReg> K0, K1;
222 if (!matchMed<GCstAndRegMatch>(
MI, MRI, OpcodeTriple, Val, K0, K1))
225 if (OpcodeTriple.Med == AMDGPU::G_AMDGPU_SMED3 && K0->Value.sgt(K1->Value))
227 if (OpcodeTriple.Med == AMDGPU::G_AMDGPU_UMED3 && K0->Value.ugt(K1->Value))
230 MatchInfo = {OpcodeTriple.Med, Val, K0->VReg, K1->VReg};
252bool AMDGPURegBankCombinerImpl::matchFPMinMaxToMed3(
253 MachineInstr &
MI, Med3MatchInfo &MatchInfo)
const {
256 if (!isVgprRegBank(Dst))
265 auto OpcodeTriple = getMinMaxPair(
MI.getOpcode());
268 std::optional<FPValueAndVReg> K0, K1;
270 if (!matchMed<GFCstAndRegMatch>(
MI, MRI, OpcodeTriple, Val, K0, K1))
273 if (K0->Value > K1->Value)
283 if ((getIEEE() && isFminnumIeee(
MI)) || VT->isKnownNeverNaN(Dst)) {
287 MatchInfo = {OpcodeTriple.Med, Val, K0->VReg, K1->VReg};
295bool AMDGPURegBankCombinerImpl::matchFPMinMaxToClamp(MachineInstr &
MI,
298 if (!isVgprRegBank(
MI.getOperand(0).getReg()))
302 auto OpcodeTriple = getMinMaxPair(
MI.getOpcode());
304 std::optional<FPValueAndVReg> K0, K1;
306 if (!matchMed<GFCstOrSplatGFCstMatch>(
MI, MRI, OpcodeTriple, Val, K0, K1))
309 if (!K0->Value.isPosZero() || !K1->Value.isOne())
316 if ((getIEEE() && getDX10Clamp() && isFminnumIeee(
MI) &&
317 VT->isKnownNeverSNaN(Val)) ||
318 VT->isKnownNeverNaN(
MI.getOperand(0).getReg())) {
335bool AMDGPURegBankCombinerImpl::matchFPMed3ToClamp(MachineInstr &
MI,
338 if (!isVgprRegBank(
MI.getOperand(0).getReg()))
347 if (isFCst(Src0) && !isFCst(Src1))
349 if (isFCst(Src1) && !isFCst(Src2))
351 if (isFCst(Src0) && !isFCst(Src1))
358 auto isOp3Zero = [&]() {
360 if (Op3->
getOpcode() == TargetOpcode::G_FCONSTANT)
368 if (VT->isKnownNeverNaN(
MI.getOperand(0).getReg()) ||
369 (getIEEE() && getDX10Clamp() &&
370 (VT->isKnownNeverSNaN(Val) || isOp3Zero()))) {
378void AMDGPURegBankCombinerImpl::applyClamp(MachineInstr &
MI,
380 B.buildInstr(AMDGPU::G_AMDGPU_CLAMP, {
MI.getOperand(0)}, {
Reg},
382 MI.eraseFromParent();
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)},
391 MI.eraseFromParent();
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);
406 LLT AmtTy = MRI.
getType(AmtReg);
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});
419 MI.eraseFromParent();
422bool AMDGPURegBankCombinerImpl::combineD16Load(MachineInstr &
MI)
const {
424 MachineInstr *
Load, *SextLoad;
425 const int64_t CleanLo16 = 0xFFFFFFFFFFFF0000;
426 const int64_t CleanHi16 = 0x000000000000FFFF;
434 if (
Load->getOpcode() == AMDGPU::G_ZEXTLOAD) {
435 const MachineMemOperand *MMO = *
Load->memoperands_begin();
438 return applyD16Load(AMDGPU::G_AMDGPU_LOAD_D16_LO_U8,
MI,
Load, Dst);
440 return applyD16Load(AMDGPU::G_AMDGPU_LOAD_D16_LO,
MI,
Load, Dst);
453 if (SextLoad->
getOpcode() != AMDGPU::G_SEXTLOAD)
460 return applyD16Load(AMDGPU::G_AMDGPU_LOAD_D16_LO_I8,
MI, SextLoad, Dst);
472 if (
Load->getOpcode() == AMDGPU::G_ZEXTLOAD) {
473 const MachineMemOperand *MMO = *
Load->memoperands_begin();
476 return applyD16Load(AMDGPU::G_AMDGPU_LOAD_D16_HI_U8,
MI,
Load, Dst);
478 return applyD16Load(AMDGPU::G_AMDGPU_LOAD_D16_HI,
MI,
Load, Dst);
491 if (SextLoad->
getOpcode() != AMDGPU::G_SEXTLOAD)
498 return applyD16Load(AMDGPU::G_AMDGPU_LOAD_D16_HI_I8,
MI, SextLoad, Dst);
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();
517bool AMDGPURegBankCombinerImpl::matchMinMaxToMinMax3(
518 MachineInstr &
MI, MinMaxToMinMax3MatchInfo &MatchInfo)
const {
523 if (!(isVgprRegBank(Dst) && isVgprRegBank(Src1) && isVgprRegBank(Src2))) {
528 unsigned Opc =
MI.getOpcode();
541 unsigned AMDGPUOpc = 0;
544 AMDGPUOpc = AMDGPU::G_AMDGPU_SMAX3;
547 AMDGPUOpc = AMDGPU::G_AMDGPU_SMIN3;
550 AMDGPUOpc = AMDGPU::G_AMDGPU_UMAX3;
553 AMDGPUOpc = AMDGPU::G_AMDGPU_UMIN3;
555 case AMDGPU::G_FMAXNUM:
556 case AMDGPU::G_FMAXNUM_IEEE:
557 AMDGPUOpc = AMDGPU::G_AMDGPU_FMAX3;
559 case AMDGPU::G_FMINNUM:
560 case AMDGPU::G_FMINNUM_IEEE:
561 AMDGPUOpc = AMDGPU::G_AMDGPU_FMIN3;
563 case AMDGPU::G_FMAXIMUM:
564 case AMDGPU::G_FMAXIMUMNUM:
565 AMDGPUOpc = AMDGPU::G_AMDGPU_FMAXIMUM3;
567 case AMDGPU::G_FMINIMUM:
568 case AMDGPU::G_FMINIMUMNUM:
569 AMDGPUOpc = AMDGPU::G_AMDGPU_FMINIMUM3;
575 MatchInfo = {AMDGPUOpc, R0, R1,
R2};
579bool AMDGPURegBankCombinerImpl::applyD16Load(
580 unsigned D16Opc, MachineInstr &DstMI, MachineInstr *SmallLoad,
581 Register SrcReg32ToOverwriteD16)
const {
583 LLT SrcTy = MRI.
getType(SrcReg32ToOverwriteD16);
591 B.buildInstr(D16Opc, {D16Dst},
595 if (D16Dst != DstReg)
596 B.buildBitcast(DstReg, D16Dst);
602SIModeRegisterDefaults AMDGPURegBankCombinerImpl::getMode()
const {
603 return MF.getInfo<SIMachineFunctionInfo>()->getMode();
606bool AMDGPURegBankCombinerImpl::getIEEE()
const {
return getMode().IEEE; }
608bool AMDGPURegBankCombinerImpl::getDX10Clamp()
const {
609 return getMode().DX10Clamp;
612bool AMDGPURegBankCombinerImpl::isFminnumIeee(
const MachineInstr &
MI)
const {
613 return MI.getOpcode() == AMDGPU::G_FMINNUM_IEEE;
616bool AMDGPURegBankCombinerImpl::isFCst(MachineInstr *
MI)
const {
617 return MI->getOpcode() == AMDGPU::G_FCONSTANT;
620bool AMDGPURegBankCombinerImpl::isClampZeroToOne(MachineInstr *K0,
621 MachineInstr *K1)
const {
622 if (isFCst(K0) && isFCst(K1)) {
632 function_ref<GISelValueTracking *()> GetVT,
633 function_ref<MachineDominatorTree *()> GetMDT,
635 AMDGPURegBankCombinerImplRuleConfig RuleConfig;
636 if (!RuleConfig.parseCommandLineOption())
644 const auto *LI =
ST.getLegalizerInfo();
646 CombinerInfo CInfo(
false,
true,
647 LI, EnableOpt,
F.hasOptSize(),
F.hasMinSize());
649 CInfo.MaxIterations = 1;
650 CInfo.ObserverLvl = CombinerInfo::ObserverLevel::SinglePass;
653 CInfo.EnableFullDCE =
false;
655 GISelValueTracking *VT = GetVT();
656 MachineDominatorTree *MDT = GetMDT();
657 AMDGPURegBankCombinerImpl Impl(MF, CInfo, *VT,
nullptr,
658 RuleConfig, ST, MDT, LI);
659 return Impl.combineMachineInstrs();
665class AMDGPURegBankCombinerLegacy :
public MachineFunctionPass {
669 AMDGPURegBankCombinerLegacy(
bool IsOptLevelNone =
false)
670 : MachineFunctionPass(
ID), IsOptLevelNone(IsOptLevelNone) {}
672 StringRef getPassName()
const override {
return "AMDGPURegBankCombiner"; }
676 void getAnalysisUsage(AnalysisUsage &AU)
const override;
683void AMDGPURegBankCombinerLegacy::getAnalysisUsage(AnalysisUsage &AU)
const {
686 AU.
addRequired<GISelValueTrackingAnalysisLegacy>();
688 if (!IsOptLevelNone) {
694bool AMDGPURegBankCombinerLegacy::runOnMachineFunction(
MachineFunction &MF) {
702 return &getAnalysis<GISelValueTrackingAnalysisLegacy>().get(MF);
704 [&]() -> MachineDominatorTree * {
705 return IsOptLevelNone ? nullptr
706 : &getAnalysis<MachineDominatorTreeWrapperPass>()
712char AMDGPURegBankCombinerLegacy::ID = 0;
714 "Combine AMDGPU machine instrs after regbankselect",
718 "Combine AMDGPU machine instrs after regbankselect",
false,
722 return new AMDGPURegBankCombinerLegacy(IsOptLevelNone);
726 : IsOptLevelNone(IsOptLevelNone) {}
738 return IsOptLevelNone
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.
const HexagonInstrInfo * TII
Contains matchers for matching SSA Machine Instructions.
Register const TargetRegisterInfo * TRI
Promote Memory to Register
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
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:
Represents analyses that only rely on functions' control flow.
bool isPosZero() const
Return true if the value is positive zero.
bool isOne() const
Returns true if this value is exactly +1.0.
FunctionPass class - This class is used to implement most global optimizations.
bool hasMin3Max3_16() const
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.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
PreservedAnalyses & preserve()
Mark an analysis as preserved.
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.
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
NodeAddr< UseNode * > Use
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.
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.
@ 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.
LLVM_ABI void reportFatalUsageError(Error Err)
Report a fatal error that does not indicate a bug in LLVM.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.