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;
117#define GET_GICOMBINER_CLASS_MEMBERS
118#define AMDGPUSubtarget GCNSubtarget
119#include "AMDGPUGenRegBankGICombiner.inc"
120#undef GET_GICOMBINER_CLASS_MEMBERS
121#undef AMDGPUSubtarget
124#define GET_GICOMBINER_IMPL
125#define AMDGPUSubtarget GCNSubtarget
126#include "AMDGPUGenRegBankGICombiner.inc"
127#undef AMDGPUSubtarget
128#undef GET_GICOMBINER_IMPL
130AMDGPURegBankCombinerImpl::AMDGPURegBankCombinerImpl(
133 const AMDGPURegBankCombinerImplRuleConfig &RuleConfig,
135 :
Combiner(MF, CInfo, &VT, CSEInfo), RuleConfig(RuleConfig), STI(STI),
136 RBI(*STI.getRegBankInfo()),
TRI(*STI.getRegisterInfo()),
137 TII(*STI.getInstrInfo()),
138 Helper(Observer,
B,
false, &VT, MDT, LI),
140#include
"AMDGPUGenRegBankGICombiner.inc"
145bool AMDGPURegBankCombinerImpl::isVgprRegBank(
Register Reg)
const {
150 if (isVgprRegBank(
Reg))
154 for (MachineInstr &Use : MRI.use_instructions(
Reg)) {
156 if (
Use.getOpcode() == AMDGPU::COPY && isVgprRegBank(Def))
162 MRI.setRegBank(VgprReg, RBI.
getRegBank(AMDGPU::VGPRRegBankID));
166AMDGPURegBankCombinerImpl::MinMaxMedOpc
167AMDGPURegBankCombinerImpl::getMinMaxPair(
unsigned Opc)
const {
173 return {AMDGPU::G_SMIN, AMDGPU::G_SMAX, AMDGPU::G_AMDGPU_SMED3};
176 return {AMDGPU::G_UMIN, AMDGPU::G_UMAX, AMDGPU::G_AMDGPU_UMED3};
177 case AMDGPU::G_FMAXNUM:
178 case AMDGPU::G_FMINNUM:
179 return {AMDGPU::G_FMINNUM, AMDGPU::G_FMAXNUM, AMDGPU::G_AMDGPU_FMED3};
180 case AMDGPU::G_FMAXNUM_IEEE:
181 case AMDGPU::G_FMINNUM_IEEE:
182 return {AMDGPU::G_FMINNUM_IEEE, AMDGPU::G_FMAXNUM_IEEE,
183 AMDGPU::G_AMDGPU_FMED3};
187template <
class m_Cst,
typename CstTy>
188bool AMDGPURegBankCombinerImpl::matchMed(MachineInstr &
MI,
189 MachineRegisterInfo &MRI,
191 CstTy &K0, CstTy &K1)
const {
209bool AMDGPURegBankCombinerImpl::matchIntMinMaxToMed3(
210 MachineInstr &
MI, Med3MatchInfo &MatchInfo)
const {
212 if (!isVgprRegBank(Dst))
220 MinMaxMedOpc OpcodeTriple = getMinMaxPair(
MI.getOpcode());
222 std::optional<ValueAndVReg> K0, K1;
224 if (!matchMed<GCstAndRegMatch>(
MI, MRI, OpcodeTriple, Val, K0, K1))
227 if (OpcodeTriple.Med == AMDGPU::G_AMDGPU_SMED3 && K0->Value.sgt(K1->Value))
229 if (OpcodeTriple.Med == AMDGPU::G_AMDGPU_UMED3 && K0->Value.ugt(K1->Value))
232 MatchInfo = {OpcodeTriple.Med, Val, K0->VReg, K1->VReg};
254bool AMDGPURegBankCombinerImpl::matchFPMinMaxToMed3(
255 MachineInstr &
MI, Med3MatchInfo &MatchInfo)
const {
258 if (!isVgprRegBank(Dst))
267 auto OpcodeTriple = getMinMaxPair(
MI.getOpcode());
270 std::optional<FPValueAndVReg> K0, K1;
272 if (!matchMed<GFCstAndRegMatch>(
MI, MRI, OpcodeTriple, Val, K0, K1))
275 if (K0->Value > K1->Value)
285 if ((getIEEE() && isFminnumLike(
MI)) || VT->isKnownNeverNaN(Dst)) {
289 MatchInfo = {OpcodeTriple.Med, Val, K0->VReg, K1->VReg};
297bool AMDGPURegBankCombinerImpl::matchFPMinMaxToClamp(MachineInstr &
MI,
300 if (!isVgprRegBank(
MI.getOperand(0).getReg()))
304 auto OpcodeTriple = getMinMaxPair(
MI.getOpcode());
306 std::optional<FPValueAndVReg> K0, K1;
308 if (!matchMed<GFCstOrSplatGFCstMatch>(
MI, MRI, OpcodeTriple, Val, K0, K1))
311 if (!K0->Value.isPosZero() || !K1->Value.isOne())
318 if ((getIEEE() && getDX10Clamp() && isFminnumLike(
MI) &&
319 VT->isKnownNeverSNaN(Val)) ||
320 VT->isKnownNeverNaN(
MI.getOperand(0).getReg())) {
337bool AMDGPURegBankCombinerImpl::matchFPMed3ToClamp(MachineInstr &
MI,
340 if (!isVgprRegBank(
MI.getOperand(0).getReg()))
349 if (isFCst(Src0) && !isFCst(Src1))
351 if (isFCst(Src1) && !isFCst(Src2))
353 if (isFCst(Src0) && !isFCst(Src1))
360 auto isOp3Zero = [&]() {
362 if (Op3->
getOpcode() == TargetOpcode::G_FCONSTANT)
370 if (VT->isKnownNeverNaN(
MI.getOperand(0).getReg()) ||
371 (getIEEE() && getDX10Clamp() &&
372 (VT->isKnownNeverSNaN(Val) || isOp3Zero()))) {
380void AMDGPURegBankCombinerImpl::applyClamp(MachineInstr &
MI,
382 B.buildInstr(AMDGPU::G_AMDGPU_CLAMP, {
MI.getOperand(0)}, {
Reg},
384 MI.eraseFromParent();
387void AMDGPURegBankCombinerImpl::applyMed3(MachineInstr &
MI,
388 Med3MatchInfo &MatchInfo)
const {
389 B.buildInstr(MatchInfo.Opc, {MI.getOperand(0)},
390 {getAsVgpr(MatchInfo.Val0), getAsVgpr(MatchInfo.Val1),
391 getAsVgpr(MatchInfo.Val2)},
393 MI.eraseFromParent();
396void AMDGPURegBankCombinerImpl::applyCanonicalizeZextShiftAmt(
397 MachineInstr &
MI, MachineInstr &Ext)
const {
398 unsigned ShOpc =
MI.getOpcode();
399 assert(ShOpc == AMDGPU::G_SHL || ShOpc == AMDGPU::G_LSHR ||
400 ShOpc == AMDGPU::G_ASHR);
408 LLT AmtTy = MRI.
getType(AmtReg);
412 auto NewExt =
B.buildAnyExt(ExtAmtTy, AmtReg);
413 auto Mask =
B.buildConstant(
415 auto And =
B.buildAnd(ExtAmtTy, NewExt, Mask);
416 B.buildInstr(ShOpc, {ShDst}, {ShSrc,
And});
421 MI.eraseFromParent();
424bool AMDGPURegBankCombinerImpl::combineD16Load(MachineInstr &
MI)
const {
426 MachineInstr *
Load, *SextLoad;
427 const int64_t CleanLo16 = 0xFFFFFFFFFFFF0000;
428 const int64_t CleanHi16 = 0x000000000000FFFF;
436 if (
Load->getOpcode() == AMDGPU::G_ZEXTLOAD) {
437 const MachineMemOperand *MMO = *
Load->memoperands_begin();
440 return applyD16Load(AMDGPU::G_AMDGPU_LOAD_D16_LO_U8,
MI,
Load, Dst);
442 return applyD16Load(AMDGPU::G_AMDGPU_LOAD_D16_LO,
MI,
Load, Dst);
455 if (SextLoad->
getOpcode() != AMDGPU::G_SEXTLOAD)
462 return applyD16Load(AMDGPU::G_AMDGPU_LOAD_D16_LO_I8,
MI, SextLoad, Dst);
474 if (
Load->getOpcode() == AMDGPU::G_ZEXTLOAD) {
475 const MachineMemOperand *MMO = *
Load->memoperands_begin();
478 return applyD16Load(AMDGPU::G_AMDGPU_LOAD_D16_HI_U8,
MI,
Load, Dst);
480 return applyD16Load(AMDGPU::G_AMDGPU_LOAD_D16_HI,
MI,
Load, Dst);
493 if (SextLoad->
getOpcode() != AMDGPU::G_SEXTLOAD)
500 return applyD16Load(AMDGPU::G_AMDGPU_LOAD_D16_HI_I8,
MI, SextLoad, Dst);
509void AMDGPURegBankCombinerImpl::applyMinMaxToMinMax3(
510 MachineInstr &
MI, MinMaxToMinMax3MatchInfo &MatchInfo)
const {
511 B.buildInstr(MatchInfo.Opc, {MI.getOperand(0)},
512 {MatchInfo.Val0, MatchInfo.Val1, MatchInfo.Val2},
MI.getFlags());
513 MI.eraseFromParent();
519bool AMDGPURegBankCombinerImpl::matchMinMaxToMinMax3(
520 MachineInstr &
MI, MinMaxToMinMax3MatchInfo &MatchInfo)
const {
525 if (!(isVgprRegBank(Dst) && isVgprRegBank(Src1) && isVgprRegBank(Src2))) {
530 unsigned Opc =
MI.getOpcode();
543 unsigned AMDGPUOpc = 0;
546 AMDGPUOpc = AMDGPU::G_AMDGPU_SMAX3;
549 AMDGPUOpc = AMDGPU::G_AMDGPU_SMIN3;
552 AMDGPUOpc = AMDGPU::G_AMDGPU_UMAX3;
555 AMDGPUOpc = AMDGPU::G_AMDGPU_UMIN3;
557 case AMDGPU::G_FMAXNUM:
558 case AMDGPU::G_FMAXNUM_IEEE:
559 AMDGPUOpc = AMDGPU::G_AMDGPU_FMAX3;
561 case AMDGPU::G_FMINNUM:
562 case AMDGPU::G_FMINNUM_IEEE:
563 AMDGPUOpc = AMDGPU::G_AMDGPU_FMIN3;
565 case AMDGPU::G_FMAXIMUM:
566 case AMDGPU::G_FMAXIMUMNUM:
567 AMDGPUOpc = AMDGPU::G_AMDGPU_FMAXIMUM3;
569 case AMDGPU::G_FMINIMUM:
570 case AMDGPU::G_FMINIMUMNUM:
571 AMDGPUOpc = AMDGPU::G_AMDGPU_FMINIMUM3;
577 MatchInfo = {AMDGPUOpc, R0, R1,
R2};
581bool AMDGPURegBankCombinerImpl::applyD16Load(
582 unsigned D16Opc, MachineInstr &DstMI, MachineInstr *SmallLoad,
583 Register SrcReg32ToOverwriteD16)
const {
585 LLT SrcTy = MRI.
getType(SrcReg32ToOverwriteD16);
593 B.buildInstr(D16Opc, {D16Dst},
597 if (D16Dst != DstReg)
598 B.buildBitcast(DstReg, D16Dst);
604SIModeRegisterDefaults AMDGPURegBankCombinerImpl::getMode()
const {
605 return MF.getInfo<SIMachineFunctionInfo>()->getMode();
608bool AMDGPURegBankCombinerImpl::getIEEE()
const {
return getMode().IEEE; }
610bool AMDGPURegBankCombinerImpl::getDX10Clamp()
const {
611 return getMode().DX10Clamp;
614bool AMDGPURegBankCombinerImpl::isFminnumIeee(
const MachineInstr &
MI)
const {
615 return MI.getOpcode() == AMDGPU::G_FMINNUM_IEEE;
618bool AMDGPURegBankCombinerImpl::isFminnum(
const MachineInstr &
MI)
const {
619 return MI.getOpcode() == AMDGPU::G_FMINNUM;
622bool AMDGPURegBankCombinerImpl::isFminnumLike(
const MachineInstr &
MI)
const {
623 return isFminnumIeee(
MI) || isFminnum(
MI);
626bool AMDGPURegBankCombinerImpl::isFCst(MachineInstr *
MI)
const {
627 return MI->getOpcode() == AMDGPU::G_FCONSTANT;
630bool AMDGPURegBankCombinerImpl::isClampZeroToOne(MachineInstr *K0,
631 MachineInstr *K1)
const {
632 if (isFCst(K0) && isFCst(K1)) {
642 function_ref<GISelValueTracking *()> GetVT,
643 function_ref<MachineDominatorTree *()> GetMDT,
645 AMDGPURegBankCombinerImplRuleConfig RuleConfig;
646 if (!RuleConfig.parseCommandLineOption())
654 const auto *LI =
ST.getLegalizerInfo();
656 CombinerInfo CInfo(
false,
true,
657 LI, EnableOpt,
F.hasOptSize(),
F.hasMinSize());
659 CInfo.MaxIterations = 1;
660 CInfo.ObserverLvl = CombinerInfo::ObserverLevel::SinglePass;
663 CInfo.EnableFullDCE =
false;
665 GISelValueTracking *VT = GetVT();
666 MachineDominatorTree *MDT = GetMDT();
667 AMDGPURegBankCombinerImpl Impl(MF, CInfo, *VT,
nullptr,
668 RuleConfig, ST, MDT, LI);
669 return Impl.combineMachineInstrs();
675class AMDGPURegBankCombinerLegacy :
public MachineFunctionPass {
679 AMDGPURegBankCombinerLegacy(
bool IsOptLevelNone =
false)
680 : MachineFunctionPass(
ID), IsOptLevelNone(IsOptLevelNone) {}
682 StringRef getPassName()
const override {
return "AMDGPURegBankCombiner"; }
686 void getAnalysisUsage(AnalysisUsage &AU)
const override;
693void AMDGPURegBankCombinerLegacy::getAnalysisUsage(AnalysisUsage &AU)
const {
696 AU.
addRequired<GISelValueTrackingAnalysisLegacy>();
698 if (!IsOptLevelNone) {
704bool AMDGPURegBankCombinerLegacy::runOnMachineFunction(
MachineFunction &MF) {
712 return &getAnalysis<GISelValueTrackingAnalysisLegacy>().get(MF);
714 [&]() -> MachineDominatorTree * {
715 return IsOptLevelNone ? nullptr
716 : &getAnalysis<MachineDominatorTreeWrapperPass>()
722char AMDGPURegBankCombinerLegacy::ID = 0;
724 "Combine AMDGPU machine instrs after regbankselect",
728 "Combine AMDGPU machine instrs after regbankselect",
false,
732 return new AMDGPURegBankCombinerLegacy(IsOptLevelNone);
736 : IsOptLevelNone(IsOptLevelNone) {}
748 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.
bool shouldSkipOptimizationForOptBisect(IRUnitRef IR)