1*ec043967SThomas Symalla //=== lib/CodeGen/GlobalISel/AMDGPUPostLegalizerCombiner.cpp 2*ec043967SThomas Symalla //---------------===// 3fee41517SMatt Arsenault // 4fee41517SMatt Arsenault // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5fee41517SMatt Arsenault // See https://llvm.org/LICENSE.txt for license information. 6fee41517SMatt Arsenault // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7fee41517SMatt Arsenault // 8fee41517SMatt Arsenault //===----------------------------------------------------------------------===// 9fee41517SMatt Arsenault // 10fee41517SMatt Arsenault // This pass does combining of machine instructions at the generic MI level, 11fee41517SMatt Arsenault // after the legalizer. 12fee41517SMatt Arsenault // 13fee41517SMatt Arsenault //===----------------------------------------------------------------------===// 14fee41517SMatt Arsenault 15*ec043967SThomas Symalla <<<<<<< HEAD 166a87e9b0Sdfukalov #include "AMDGPU.h" 17fee41517SMatt Arsenault #include "AMDGPULegalizerInfo.h" 18560d7e04Sdfukalov #include "GCNSubtarget.h" 19*ec043967SThomas Symalla ======= 20*ec043967SThomas Symalla #include "AMDGPULegalizerInfo.h" 21*ec043967SThomas Symalla #include "AMDGPUTargetMachine.h" 22*ec043967SThomas Symalla >>>>>>> clang-format 23560d7e04Sdfukalov #include "MCTargetDesc/AMDGPUMCTargetDesc.h" 24fee41517SMatt Arsenault #include "llvm/CodeGen/GlobalISel/Combiner.h" 25fee41517SMatt Arsenault #include "llvm/CodeGen/GlobalISel/CombinerHelper.h" 26fee41517SMatt Arsenault #include "llvm/CodeGen/GlobalISel/CombinerInfo.h" 27fee41517SMatt Arsenault #include "llvm/CodeGen/GlobalISel/GISelKnownBits.h" 28fee41517SMatt Arsenault #include "llvm/CodeGen/GlobalISel/MIPatternMatch.h" 29fee41517SMatt Arsenault #include "llvm/CodeGen/MachineDominators.h" 30fee41517SMatt Arsenault #include "llvm/CodeGen/TargetPassConfig.h" 31*ec043967SThomas Symalla <<<<<<< HEAD 326a87e9b0Sdfukalov #include "llvm/Target/TargetMachine.h" 33*ec043967SThomas Symalla ======= 34*ec043967SThomas Symalla #include "llvm/Support/Debug.h" 35*ec043967SThomas Symalla >>>>>>> clang-format 36fee41517SMatt Arsenault 37fee41517SMatt Arsenault #define DEBUG_TYPE "amdgpu-postlegalizer-combiner" 38fee41517SMatt Arsenault 39fee41517SMatt Arsenault using namespace llvm; 40fee41517SMatt Arsenault using namespace MIPatternMatch; 41fee41517SMatt Arsenault 420031418dSPetar Avramovic class AMDGPUPostLegalizerCombinerHelper { 430031418dSPetar Avramovic protected: 440031418dSPetar Avramovic MachineIRBuilder &B; 450031418dSPetar Avramovic MachineFunction &MF; 460031418dSPetar Avramovic MachineRegisterInfo &MRI; 470031418dSPetar Avramovic CombinerHelper &Helper; 480031418dSPetar Avramovic 490031418dSPetar Avramovic public: 500031418dSPetar Avramovic AMDGPUPostLegalizerCombinerHelper(MachineIRBuilder &B, CombinerHelper &Helper) 510031418dSPetar Avramovic : B(B), MF(B.getMF()), MRI(*B.getMRI()), Helper(Helper){}; 520031418dSPetar Avramovic 53fee41517SMatt Arsenault struct FMinFMaxLegacyInfo { 54fee41517SMatt Arsenault Register LHS; 55fee41517SMatt Arsenault Register RHS; 56fee41517SMatt Arsenault Register True; 57fee41517SMatt Arsenault Register False; 58fee41517SMatt Arsenault CmpInst::Predicate Pred; 59fee41517SMatt Arsenault }; 60fee41517SMatt Arsenault 61fee41517SMatt Arsenault // TODO: Make sure fmin_legacy/fmax_legacy don't canonicalize 620031418dSPetar Avramovic bool matchFMinFMaxLegacy(MachineInstr &MI, FMinFMaxLegacyInfo &Info); 630031418dSPetar Avramovic void applySelectFCmpToFMinToFMaxLegacy(MachineInstr &MI, 640031418dSPetar Avramovic const FMinFMaxLegacyInfo &Info); 650031418dSPetar Avramovic 660031418dSPetar Avramovic bool matchUCharToFloat(MachineInstr &MI); 670031418dSPetar Avramovic void applyUCharToFloat(MachineInstr &MI); 680031418dSPetar Avramovic 690031418dSPetar Avramovic // FIXME: Should be able to have 2 separate matchdatas rather than custom 700031418dSPetar Avramovic // struct boilerplate. 710031418dSPetar Avramovic struct CvtF32UByteMatchInfo { 720031418dSPetar Avramovic Register CvtVal; 730031418dSPetar Avramovic unsigned ShiftOffset; 740031418dSPetar Avramovic }; 750031418dSPetar Avramovic 760031418dSPetar Avramovic bool matchCvtF32UByteN(MachineInstr &MI, CvtF32UByteMatchInfo &MatchInfo); 770031418dSPetar Avramovic void applyCvtF32UByteN(MachineInstr &MI, 780031418dSPetar Avramovic const CvtF32UByteMatchInfo &MatchInfo); 7962af0305SThomas Symalla 8062af0305SThomas Symalla struct ClampI64ToI16MatchInfo { 8162af0305SThomas Symalla int64_t Cmp1; 8262af0305SThomas Symalla int64_t Cmp2; 8362af0305SThomas Symalla Register Origin; 8462af0305SThomas Symalla }; 8562af0305SThomas Symalla 8662af0305SThomas Symalla bool matchClampI64ToI16(MachineInstr &MI, MachineRegisterInfo &MRI, 8762af0305SThomas Symalla MachineFunction &MF, 8862af0305SThomas Symalla ClampI64ToI16MatchInfo &MatchInfo); 8962af0305SThomas Symalla 9062af0305SThomas Symalla void applyClampI64ToI16(MachineInstr &MI, 9162af0305SThomas Symalla const ClampI64ToI16MatchInfo &MatchInfo); 920031418dSPetar Avramovic }; 930031418dSPetar Avramovic 940031418dSPetar Avramovic bool AMDGPUPostLegalizerCombinerHelper::matchFMinFMaxLegacy( 950031418dSPetar Avramovic MachineInstr &MI, FMinFMaxLegacyInfo &Info) { 96fee41517SMatt Arsenault // FIXME: Combines should have subtarget predicates, and we shouldn't need 97fee41517SMatt Arsenault // this here. 98fee41517SMatt Arsenault if (!MF.getSubtarget<GCNSubtarget>().hasFminFmaxLegacy()) 99fee41517SMatt Arsenault return false; 100fee41517SMatt Arsenault 101fee41517SMatt Arsenault // FIXME: Type predicate on pattern 102fee41517SMatt Arsenault if (MRI.getType(MI.getOperand(0).getReg()) != LLT::scalar(32)) 103fee41517SMatt Arsenault return false; 104fee41517SMatt Arsenault 105fee41517SMatt Arsenault Register Cond = MI.getOperand(1).getReg(); 106fee41517SMatt Arsenault if (!MRI.hasOneNonDBGUse(Cond) || 107fee41517SMatt Arsenault !mi_match(Cond, MRI, 108fee41517SMatt Arsenault m_GFCmp(m_Pred(Info.Pred), m_Reg(Info.LHS), m_Reg(Info.RHS)))) 109fee41517SMatt Arsenault return false; 110fee41517SMatt Arsenault 111fee41517SMatt Arsenault Info.True = MI.getOperand(2).getReg(); 112fee41517SMatt Arsenault Info.False = MI.getOperand(3).getReg(); 113fee41517SMatt Arsenault 114fee41517SMatt Arsenault if (!(Info.LHS == Info.True && Info.RHS == Info.False) && 115fee41517SMatt Arsenault !(Info.LHS == Info.False && Info.RHS == Info.True)) 116fee41517SMatt Arsenault return false; 117fee41517SMatt Arsenault 118fee41517SMatt Arsenault switch (Info.Pred) { 119fee41517SMatt Arsenault case CmpInst::FCMP_FALSE: 120fee41517SMatt Arsenault case CmpInst::FCMP_OEQ: 121fee41517SMatt Arsenault case CmpInst::FCMP_ONE: 122fee41517SMatt Arsenault case CmpInst::FCMP_ORD: 123fee41517SMatt Arsenault case CmpInst::FCMP_UNO: 124fee41517SMatt Arsenault case CmpInst::FCMP_UEQ: 125fee41517SMatt Arsenault case CmpInst::FCMP_UNE: 126fee41517SMatt Arsenault case CmpInst::FCMP_TRUE: 127fee41517SMatt Arsenault return false; 128fee41517SMatt Arsenault default: 129fee41517SMatt Arsenault return true; 130fee41517SMatt Arsenault } 131fee41517SMatt Arsenault } 132fee41517SMatt Arsenault 1330031418dSPetar Avramovic void AMDGPUPostLegalizerCombinerHelper::applySelectFCmpToFMinToFMaxLegacy( 1340031418dSPetar Avramovic MachineInstr &MI, const FMinFMaxLegacyInfo &Info) { 1350031418dSPetar Avramovic B.setInstrAndDebugLoc(MI); 1360031418dSPetar Avramovic auto buildNewInst = [&MI, this](unsigned Opc, Register X, Register Y) { 1370031418dSPetar Avramovic B.buildInstr(Opc, {MI.getOperand(0)}, {X, Y}, MI.getFlags()); 138fee41517SMatt Arsenault }; 139fee41517SMatt Arsenault 140fee41517SMatt Arsenault switch (Info.Pred) { 141fee41517SMatt Arsenault case CmpInst::FCMP_ULT: 142fee41517SMatt Arsenault case CmpInst::FCMP_ULE: 143fee41517SMatt Arsenault if (Info.LHS == Info.True) 144fee41517SMatt Arsenault buildNewInst(AMDGPU::G_AMDGPU_FMIN_LEGACY, Info.RHS, Info.LHS); 145fee41517SMatt Arsenault else 146fee41517SMatt Arsenault buildNewInst(AMDGPU::G_AMDGPU_FMAX_LEGACY, Info.LHS, Info.RHS); 147fee41517SMatt Arsenault break; 148fee41517SMatt Arsenault case CmpInst::FCMP_OLE: 149fee41517SMatt Arsenault case CmpInst::FCMP_OLT: { 150fee41517SMatt Arsenault // We need to permute the operands to get the correct NaN behavior. The 151fee41517SMatt Arsenault // selected operand is the second one based on the failing compare with NaN, 152fee41517SMatt Arsenault // so permute it based on the compare type the hardware uses. 153fee41517SMatt Arsenault if (Info.LHS == Info.True) 154fee41517SMatt Arsenault buildNewInst(AMDGPU::G_AMDGPU_FMIN_LEGACY, Info.LHS, Info.RHS); 155fee41517SMatt Arsenault else 156fee41517SMatt Arsenault buildNewInst(AMDGPU::G_AMDGPU_FMAX_LEGACY, Info.RHS, Info.LHS); 157fee41517SMatt Arsenault break; 158fee41517SMatt Arsenault } 159fee41517SMatt Arsenault case CmpInst::FCMP_UGE: 160fee41517SMatt Arsenault case CmpInst::FCMP_UGT: { 161fee41517SMatt Arsenault if (Info.LHS == Info.True) 162fee41517SMatt Arsenault buildNewInst(AMDGPU::G_AMDGPU_FMAX_LEGACY, Info.RHS, Info.LHS); 163fee41517SMatt Arsenault else 164fee41517SMatt Arsenault buildNewInst(AMDGPU::G_AMDGPU_FMIN_LEGACY, Info.LHS, Info.RHS); 165fee41517SMatt Arsenault break; 166fee41517SMatt Arsenault } 167fee41517SMatt Arsenault case CmpInst::FCMP_OGT: 168fee41517SMatt Arsenault case CmpInst::FCMP_OGE: { 169fee41517SMatt Arsenault if (Info.LHS == Info.True) 170fee41517SMatt Arsenault buildNewInst(AMDGPU::G_AMDGPU_FMAX_LEGACY, Info.LHS, Info.RHS); 171fee41517SMatt Arsenault else 172fee41517SMatt Arsenault buildNewInst(AMDGPU::G_AMDGPU_FMIN_LEGACY, Info.RHS, Info.LHS); 173fee41517SMatt Arsenault break; 174fee41517SMatt Arsenault } 175fee41517SMatt Arsenault default: 176fee41517SMatt Arsenault llvm_unreachable("predicate should not have matched"); 177fee41517SMatt Arsenault } 178fee41517SMatt Arsenault 179fee41517SMatt Arsenault MI.eraseFromParent(); 180fee41517SMatt Arsenault } 181fee41517SMatt Arsenault 1820031418dSPetar Avramovic bool AMDGPUPostLegalizerCombinerHelper::matchUCharToFloat(MachineInstr &MI) { 183b27d255eSMatt Arsenault Register DstReg = MI.getOperand(0).getReg(); 184b27d255eSMatt Arsenault 185b27d255eSMatt Arsenault // TODO: We could try to match extracting the higher bytes, which would be 186b27d255eSMatt Arsenault // easier if i8 vectors weren't promoted to i32 vectors, particularly after 187b27d255eSMatt Arsenault // types are legalized. v4i8 -> v4f32 is probably the only case to worry 188b27d255eSMatt Arsenault // about in practice. 189b27d255eSMatt Arsenault LLT Ty = MRI.getType(DstReg); 190b27d255eSMatt Arsenault if (Ty == LLT::scalar(32) || Ty == LLT::scalar(16)) { 191db777eaeSMatt Arsenault Register SrcReg = MI.getOperand(1).getReg(); 192db777eaeSMatt Arsenault unsigned SrcSize = MRI.getType(SrcReg).getSizeInBits(); 193db777eaeSMatt Arsenault assert(SrcSize == 16 || SrcSize == 32 || SrcSize == 64); 194db777eaeSMatt Arsenault const APInt Mask = APInt::getHighBitsSet(SrcSize, SrcSize - 8); 195db777eaeSMatt Arsenault return Helper.getKnownBits()->maskedValueIsZero(SrcReg, Mask); 196b27d255eSMatt Arsenault } 197b27d255eSMatt Arsenault 198b27d255eSMatt Arsenault return false; 199b27d255eSMatt Arsenault } 200b27d255eSMatt Arsenault 2010031418dSPetar Avramovic void AMDGPUPostLegalizerCombinerHelper::applyUCharToFloat(MachineInstr &MI) { 2020031418dSPetar Avramovic B.setInstrAndDebugLoc(MI); 203b27d255eSMatt Arsenault 204b27d255eSMatt Arsenault const LLT S32 = LLT::scalar(32); 205b27d255eSMatt Arsenault 206b27d255eSMatt Arsenault Register DstReg = MI.getOperand(0).getReg(); 207db777eaeSMatt Arsenault Register SrcReg = MI.getOperand(1).getReg(); 2080031418dSPetar Avramovic LLT Ty = MRI.getType(DstReg); 2090031418dSPetar Avramovic LLT SrcTy = MRI.getType(SrcReg); 210db777eaeSMatt Arsenault if (SrcTy != S32) 211db777eaeSMatt Arsenault SrcReg = B.buildAnyExtOrTrunc(S32, SrcReg).getReg(0); 212b27d255eSMatt Arsenault 213b27d255eSMatt Arsenault if (Ty == S32) { 214*ec043967SThomas Symalla B.buildInstr(AMDGPU::G_AMDGPU_CVT_F32_UBYTE0, {DstReg}, {SrcReg}, 215*ec043967SThomas Symalla MI.getFlags()); 216b27d255eSMatt Arsenault } else { 217*ec043967SThomas Symalla auto Cvt0 = B.buildInstr(AMDGPU::G_AMDGPU_CVT_F32_UBYTE0, {S32}, {SrcReg}, 218*ec043967SThomas Symalla MI.getFlags()); 219b27d255eSMatt Arsenault B.buildFPTrunc(DstReg, Cvt0, MI.getFlags()); 220b27d255eSMatt Arsenault } 221b27d255eSMatt Arsenault 222b27d255eSMatt Arsenault MI.eraseFromParent(); 223b27d255eSMatt Arsenault } 224fee41517SMatt Arsenault 2250031418dSPetar Avramovic bool AMDGPUPostLegalizerCombinerHelper::matchCvtF32UByteN( 2260031418dSPetar Avramovic MachineInstr &MI, CvtF32UByteMatchInfo &MatchInfo) { 2270ba40d4cSMatt Arsenault Register SrcReg = MI.getOperand(1).getReg(); 2280ba40d4cSMatt Arsenault 2290ba40d4cSMatt Arsenault // Look through G_ZEXT. 2300ba40d4cSMatt Arsenault mi_match(SrcReg, MRI, m_GZExt(m_Reg(SrcReg))); 2310ba40d4cSMatt Arsenault 2320ba40d4cSMatt Arsenault Register Src0; 2330ba40d4cSMatt Arsenault int64_t ShiftAmt; 2340ba40d4cSMatt Arsenault bool IsShr = mi_match(SrcReg, MRI, m_GLShr(m_Reg(Src0), m_ICst(ShiftAmt))); 2350ba40d4cSMatt Arsenault if (IsShr || mi_match(SrcReg, MRI, m_GShl(m_Reg(Src0), m_ICst(ShiftAmt)))) { 2360ba40d4cSMatt Arsenault const unsigned Offset = MI.getOpcode() - AMDGPU::G_AMDGPU_CVT_F32_UBYTE0; 2370ba40d4cSMatt Arsenault 2380ba40d4cSMatt Arsenault unsigned ShiftOffset = 8 * Offset; 2390ba40d4cSMatt Arsenault if (IsShr) 2400ba40d4cSMatt Arsenault ShiftOffset += ShiftAmt; 2410ba40d4cSMatt Arsenault else 2420ba40d4cSMatt Arsenault ShiftOffset -= ShiftAmt; 2430ba40d4cSMatt Arsenault 2440ba40d4cSMatt Arsenault MatchInfo.CvtVal = Src0; 2450ba40d4cSMatt Arsenault MatchInfo.ShiftOffset = ShiftOffset; 2460ba40d4cSMatt Arsenault return ShiftOffset < 32 && ShiftOffset >= 8 && (ShiftOffset % 8) == 0; 2470ba40d4cSMatt Arsenault } 2480ba40d4cSMatt Arsenault 2490ba40d4cSMatt Arsenault // TODO: Simplify demanded bits. 2500ba40d4cSMatt Arsenault return false; 2510ba40d4cSMatt Arsenault } 2520ba40d4cSMatt Arsenault 2530031418dSPetar Avramovic void AMDGPUPostLegalizerCombinerHelper::applyCvtF32UByteN( 2540031418dSPetar Avramovic MachineInstr &MI, const CvtF32UByteMatchInfo &MatchInfo) { 2550031418dSPetar Avramovic B.setInstrAndDebugLoc(MI); 2560ba40d4cSMatt Arsenault unsigned NewOpc = AMDGPU::G_AMDGPU_CVT_F32_UBYTE0 + MatchInfo.ShiftOffset / 8; 2570ba40d4cSMatt Arsenault 2580ba40d4cSMatt Arsenault const LLT S32 = LLT::scalar(32); 2590ba40d4cSMatt Arsenault Register CvtSrc = MatchInfo.CvtVal; 2600031418dSPetar Avramovic LLT SrcTy = MRI.getType(MatchInfo.CvtVal); 2610ba40d4cSMatt Arsenault if (SrcTy != S32) { 2620ba40d4cSMatt Arsenault assert(SrcTy.isScalar() && SrcTy.getSizeInBits() >= 8); 2630ba40d4cSMatt Arsenault CvtSrc = B.buildAnyExt(S32, CvtSrc).getReg(0); 2640ba40d4cSMatt Arsenault } 2650ba40d4cSMatt Arsenault 2660ba40d4cSMatt Arsenault assert(MI.getOpcode() != NewOpc); 2670ba40d4cSMatt Arsenault B.buildInstr(NewOpc, {MI.getOperand(0)}, {CvtSrc}, MI.getFlags()); 2680ba40d4cSMatt Arsenault MI.eraseFromParent(); 2690ba40d4cSMatt Arsenault } 2700ba40d4cSMatt Arsenault 271*ec043967SThomas Symalla bool AMDGPUPostLegalizerCombinerHelper::matchClampI64ToI16( 272*ec043967SThomas Symalla MachineInstr &MI, MachineRegisterInfo &MRI, MachineFunction &MF, 27362af0305SThomas Symalla ClampI64ToI16MatchInfo &MatchInfo) { 27462af0305SThomas Symalla assert(MI.getOpcode() == TargetOpcode::G_TRUNC && "Invalid instruction!"); 27562af0305SThomas Symalla const LLT SrcType = MRI.getType(MI.getOperand(1).getReg()); 27662af0305SThomas Symalla if (SrcType != LLT::scalar(64)) 27762af0305SThomas Symalla return false; 27862af0305SThomas Symalla 27962af0305SThomas Symalla MachineIRBuilder B(MI); 28062af0305SThomas Symalla 28162af0305SThomas Symalla LLVM_DEBUG(dbgs() << "Matching Clamp i64 to i16"); 28262af0305SThomas Symalla 28362af0305SThomas Symalla if (mi_match(MI.getOperand(1).getReg(), MRI, 284*ec043967SThomas Symalla m_MaxMin(m_ICst(MatchInfo.Cmp1), m_ICst(MatchInfo.Cmp2), 28562af0305SThomas Symalla m_Reg(MatchInfo.Origin)))) { 28662af0305SThomas Symalla const auto Cmp1 = static_cast<int64_t>(MatchInfo.Cmp1); 28762af0305SThomas Symalla const auto Cmp2 = static_cast<int64_t>(MatchInfo.Cmp2); 28862af0305SThomas Symalla 289*ec043967SThomas Symalla const int64_t Min = 290*ec043967SThomas Symalla static_cast<int64_t>(std::numeric_limits<int16_t>::min()); 291*ec043967SThomas Symalla const int64_t Max = 292*ec043967SThomas Symalla static_cast<int64_t>(std::numeric_limits<int16_t>::max()); 29362af0305SThomas Symalla 29462af0305SThomas Symalla // are we really trying to clamp against short boundaries? 29562af0305SThomas Symalla return ((Cmp2 >= Cmp1 && Cmp1 >= Min && Cmp2 <= Max) || 29662af0305SThomas Symalla (Cmp1 >= Cmp2 && Cmp1 <= Max && Cmp2 >= Min)); 29762af0305SThomas Symalla } 29862af0305SThomas Symalla 29962af0305SThomas Symalla return false; 30062af0305SThomas Symalla } 30162af0305SThomas Symalla 302*ec043967SThomas Symalla void AMDGPUPostLegalizerCombinerHelper::applyClampI64ToI16( 303*ec043967SThomas Symalla MachineInstr &MI, const ClampI64ToI16MatchInfo &MatchInfo) { 30462af0305SThomas Symalla LLVM_DEBUG(dbgs() << "Combining MI"); 30562af0305SThomas Symalla 30662af0305SThomas Symalla MachineIRBuilder B(MI); 30762af0305SThomas Symalla MachineRegisterInfo &MRI = MI.getParent()->getParent()->getRegInfo(); 30862af0305SThomas Symalla 30962af0305SThomas Symalla Register Src = MatchInfo.Origin; 31062af0305SThomas Symalla assert(MRI.getType(Src) == LLT::scalar(64)); 31162af0305SThomas Symalla const LLT S32 = LLT::scalar(32); 31262af0305SThomas Symalla 31362af0305SThomas Symalla auto Unmerge = B.buildUnmerge(S32, Src); 31462af0305SThomas Symalla Register Hi32 = Unmerge->getOperand(0).getReg(); 31562af0305SThomas Symalla Register Lo32 = Unmerge->getOperand(1).getReg(); 31662af0305SThomas Symalla MRI.setRegClass(Hi32, &AMDGPU::VGPR_32RegClass); 31762af0305SThomas Symalla MRI.setRegClass(Lo32, &AMDGPU::VGPR_32RegClass); 31862af0305SThomas Symalla 31962af0305SThomas Symalla constexpr unsigned int CvtOpcode = AMDGPU::V_CVT_PK_I16_I32_e64; 32062af0305SThomas Symalla assert(MI.getOpcode() != CvtOpcode); 32162af0305SThomas Symalla 32262af0305SThomas Symalla Register CvtDst = MRI.createGenericVirtualRegister(S32); 32362af0305SThomas Symalla MRI.setRegClass(CvtDst, &AMDGPU::VGPR_32RegClass); 32462af0305SThomas Symalla 32562af0305SThomas Symalla auto CvtPk = B.buildInstr(CvtOpcode); 32662af0305SThomas Symalla CvtPk.addDef(CvtDst); 32762af0305SThomas Symalla CvtPk.addReg(Hi32); 32862af0305SThomas Symalla CvtPk.addReg(Lo32); 32962af0305SThomas Symalla CvtPk.setMIFlags(MI.getFlags()); 33062af0305SThomas Symalla 33162af0305SThomas Symalla auto min = std::min(MatchInfo.Cmp1, MatchInfo.Cmp2); 33262af0305SThomas Symalla auto max = std::max(MatchInfo.Cmp1, MatchInfo.Cmp2); 33362af0305SThomas Symalla 33462af0305SThomas Symalla Register MinBoundaryDst = MRI.createGenericVirtualRegister(S32); 33562af0305SThomas Symalla MRI.setRegClass(MinBoundaryDst, &AMDGPU::VGPR_32RegClass); 33662af0305SThomas Symalla B.buildConstant(MinBoundaryDst, min); 33762af0305SThomas Symalla 33862af0305SThomas Symalla Register MaxBoundaryDst = MRI.createGenericVirtualRegister(S32); 33962af0305SThomas Symalla MRI.setRegClass(MaxBoundaryDst, &AMDGPU::VGPR_32RegClass); 34062af0305SThomas Symalla B.buildConstant(MaxBoundaryDst, max); 34162af0305SThomas Symalla 34262af0305SThomas Symalla Register MedDst = MRI.createGenericVirtualRegister(S32); 34362af0305SThomas Symalla MRI.setRegClass(MedDst, &AMDGPU::VGPR_32RegClass); 34462af0305SThomas Symalla 34562af0305SThomas Symalla auto Med = B.buildInstr(AMDGPU::V_MED3_I32); 34662af0305SThomas Symalla Med.addDef(MedDst); 34762af0305SThomas Symalla Med.addReg(MinBoundaryDst); 34862af0305SThomas Symalla Med.addReg(CvtDst); 34962af0305SThomas Symalla Med.addReg(MaxBoundaryDst); 35062af0305SThomas Symalla Med.setMIFlags(MI.getFlags()); 35162af0305SThomas Symalla 35262af0305SThomas Symalla B.buildCopy(MI.getOperand(0).getReg(), MedDst); 35362af0305SThomas Symalla 35462af0305SThomas Symalla MI.eraseFromParent(); 35562af0305SThomas Symalla } 35662af0305SThomas Symalla 3570031418dSPetar Avramovic class AMDGPUPostLegalizerCombinerHelperState { 3580031418dSPetar Avramovic protected: 3590031418dSPetar Avramovic CombinerHelper &Helper; 3600031418dSPetar Avramovic AMDGPUPostLegalizerCombinerHelper &PostLegalizerHelper; 3610031418dSPetar Avramovic 3620031418dSPetar Avramovic public: 3630031418dSPetar Avramovic AMDGPUPostLegalizerCombinerHelperState( 3640031418dSPetar Avramovic CombinerHelper &Helper, 3650031418dSPetar Avramovic AMDGPUPostLegalizerCombinerHelper &PostLegalizerHelper) 3660031418dSPetar Avramovic : Helper(Helper), PostLegalizerHelper(PostLegalizerHelper) {} 3670031418dSPetar Avramovic }; 3680031418dSPetar Avramovic 369fee41517SMatt Arsenault #define AMDGPUPOSTLEGALIZERCOMBINERHELPER_GENCOMBINERHELPER_DEPS 370fee41517SMatt Arsenault #include "AMDGPUGenPostLegalizeGICombiner.inc" 371fee41517SMatt Arsenault #undef AMDGPUPOSTLEGALIZERCOMBINERHELPER_GENCOMBINERHELPER_DEPS 372fee41517SMatt Arsenault 373fee41517SMatt Arsenault namespace { 374fee41517SMatt Arsenault #define AMDGPUPOSTLEGALIZERCOMBINERHELPER_GENCOMBINERHELPER_H 375fee41517SMatt Arsenault #include "AMDGPUGenPostLegalizeGICombiner.inc" 376fee41517SMatt Arsenault #undef AMDGPUPOSTLEGALIZERCOMBINERHELPER_GENCOMBINERHELPER_H 377fee41517SMatt Arsenault 37816bcd545SMatt Arsenault class AMDGPUPostLegalizerCombinerInfo final : public CombinerInfo { 379fee41517SMatt Arsenault GISelKnownBits *KB; 380fee41517SMatt Arsenault MachineDominatorTree *MDT; 381fee41517SMatt Arsenault 382fee41517SMatt Arsenault public: 383e35ba099SDaniel Sanders AMDGPUGenPostLegalizerCombinerHelperRuleConfig GeneratedRuleCfg; 384fee41517SMatt Arsenault 385fee41517SMatt Arsenault AMDGPUPostLegalizerCombinerInfo(bool EnableOpt, bool OptSize, bool MinSize, 386fee41517SMatt Arsenault const AMDGPULegalizerInfo *LI, 387fee41517SMatt Arsenault GISelKnownBits *KB, MachineDominatorTree *MDT) 388fee41517SMatt Arsenault : CombinerInfo(/*AllowIllegalOps*/ false, /*ShouldLegalizeIllegal*/ true, 389fee41517SMatt Arsenault /*LegalizerInfo*/ LI, EnableOpt, OptSize, MinSize), 390fee41517SMatt Arsenault KB(KB), MDT(MDT) { 391e35ba099SDaniel Sanders if (!GeneratedRuleCfg.parseCommandLineOption()) 392fee41517SMatt Arsenault report_fatal_error("Invalid rule identifier"); 393fee41517SMatt Arsenault } 394fee41517SMatt Arsenault 395d15723efSMatt Arsenault bool combine(GISelChangeObserver &Observer, MachineInstr &MI, 396fee41517SMatt Arsenault MachineIRBuilder &B) const override; 397fee41517SMatt Arsenault }; 398fee41517SMatt Arsenault 399fee41517SMatt Arsenault bool AMDGPUPostLegalizerCombinerInfo::combine(GISelChangeObserver &Observer, 400fee41517SMatt Arsenault MachineInstr &MI, 401fee41517SMatt Arsenault MachineIRBuilder &B) const { 40266ffa0e9SMatt Arsenault CombinerHelper Helper(Observer, B, KB, MDT, LInfo); 4030031418dSPetar Avramovic AMDGPUPostLegalizerCombinerHelper PostLegalizerHelper(B, Helper); 4040031418dSPetar Avramovic AMDGPUGenPostLegalizerCombinerHelper Generated(GeneratedRuleCfg, Helper, 4050031418dSPetar Avramovic PostLegalizerHelper); 406fee41517SMatt Arsenault 4070031418dSPetar Avramovic if (Generated.tryCombineAll(Observer, MI, B)) 408fee41517SMatt Arsenault return true; 409fee41517SMatt Arsenault 410fee41517SMatt Arsenault switch (MI.getOpcode()) { 411fee41517SMatt Arsenault case TargetOpcode::G_SHL: 412fee41517SMatt Arsenault case TargetOpcode::G_LSHR: 413fee41517SMatt Arsenault case TargetOpcode::G_ASHR: 414fee41517SMatt Arsenault // On some subtargets, 64-bit shift is a quarter rate instruction. In the 415fee41517SMatt Arsenault // common case, splitting this into a move and a 32-bit shift is faster and 416fee41517SMatt Arsenault // the same code size. 417fee41517SMatt Arsenault return Helper.tryCombineShiftToUnmerge(MI, 32); 418fee41517SMatt Arsenault } 419fee41517SMatt Arsenault 420fee41517SMatt Arsenault return false; 421fee41517SMatt Arsenault } 422fee41517SMatt Arsenault 423fee41517SMatt Arsenault #define AMDGPUPOSTLEGALIZERCOMBINERHELPER_GENCOMBINERHELPER_CPP 424fee41517SMatt Arsenault #include "AMDGPUGenPostLegalizeGICombiner.inc" 425fee41517SMatt Arsenault #undef AMDGPUPOSTLEGALIZERCOMBINERHELPER_GENCOMBINERHELPER_CPP 426fee41517SMatt Arsenault 427fee41517SMatt Arsenault // Pass boilerplate 428fee41517SMatt Arsenault // ================ 429fee41517SMatt Arsenault 430fee41517SMatt Arsenault class AMDGPUPostLegalizerCombiner : public MachineFunctionPass { 431fee41517SMatt Arsenault public: 432fee41517SMatt Arsenault static char ID; 433fee41517SMatt Arsenault 434fee41517SMatt Arsenault AMDGPUPostLegalizerCombiner(bool IsOptNone = false); 435fee41517SMatt Arsenault 436fee41517SMatt Arsenault StringRef getPassName() const override { 437fee41517SMatt Arsenault return "AMDGPUPostLegalizerCombiner"; 438fee41517SMatt Arsenault } 439fee41517SMatt Arsenault 440fee41517SMatt Arsenault bool runOnMachineFunction(MachineFunction &MF) override; 441fee41517SMatt Arsenault 442fee41517SMatt Arsenault void getAnalysisUsage(AnalysisUsage &AU) const override; 443*ec043967SThomas Symalla 444fee41517SMatt Arsenault private: 445fee41517SMatt Arsenault bool IsOptNone; 446fee41517SMatt Arsenault }; 447fee41517SMatt Arsenault } // end anonymous namespace 448fee41517SMatt Arsenault 449fee41517SMatt Arsenault void AMDGPUPostLegalizerCombiner::getAnalysisUsage(AnalysisUsage &AU) const { 450fee41517SMatt Arsenault AU.addRequired<TargetPassConfig>(); 451fee41517SMatt Arsenault AU.setPreservesCFG(); 452fee41517SMatt Arsenault getSelectionDAGFallbackAnalysisUsage(AU); 453fee41517SMatt Arsenault AU.addRequired<GISelKnownBitsAnalysis>(); 454fee41517SMatt Arsenault AU.addPreserved<GISelKnownBitsAnalysis>(); 455fee41517SMatt Arsenault if (!IsOptNone) { 456fee41517SMatt Arsenault AU.addRequired<MachineDominatorTree>(); 457fee41517SMatt Arsenault AU.addPreserved<MachineDominatorTree>(); 458fee41517SMatt Arsenault } 459fee41517SMatt Arsenault MachineFunctionPass::getAnalysisUsage(AU); 460fee41517SMatt Arsenault } 461fee41517SMatt Arsenault 462fee41517SMatt Arsenault AMDGPUPostLegalizerCombiner::AMDGPUPostLegalizerCombiner(bool IsOptNone) 463fee41517SMatt Arsenault : MachineFunctionPass(ID), IsOptNone(IsOptNone) { 464fee41517SMatt Arsenault initializeAMDGPUPostLegalizerCombinerPass(*PassRegistry::getPassRegistry()); 465fee41517SMatt Arsenault } 466fee41517SMatt Arsenault 467fee41517SMatt Arsenault bool AMDGPUPostLegalizerCombiner::runOnMachineFunction(MachineFunction &MF) { 468fee41517SMatt Arsenault if (MF.getProperties().hasProperty( 469fee41517SMatt Arsenault MachineFunctionProperties::Property::FailedISel)) 470fee41517SMatt Arsenault return false; 471fee41517SMatt Arsenault auto *TPC = &getAnalysis<TargetPassConfig>(); 472fee41517SMatt Arsenault const Function &F = MF.getFunction(); 473fee41517SMatt Arsenault bool EnableOpt = 474fee41517SMatt Arsenault MF.getTarget().getOptLevel() != CodeGenOpt::None && !skipFunction(F); 475fee41517SMatt Arsenault 476fee41517SMatt Arsenault const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>(); 477*ec043967SThomas Symalla const AMDGPULegalizerInfo *LI = 478*ec043967SThomas Symalla static_cast<const AMDGPULegalizerInfo *>(ST.getLegalizerInfo()); 479fee41517SMatt Arsenault 480fee41517SMatt Arsenault GISelKnownBits *KB = &getAnalysis<GISelKnownBitsAnalysis>().get(MF); 481fee41517SMatt Arsenault MachineDominatorTree *MDT = 482fee41517SMatt Arsenault IsOptNone ? nullptr : &getAnalysis<MachineDominatorTree>(); 483fee41517SMatt Arsenault AMDGPUPostLegalizerCombinerInfo PCInfo(EnableOpt, F.hasOptSize(), 484fee41517SMatt Arsenault F.hasMinSize(), LI, KB, MDT); 485fee41517SMatt Arsenault Combiner C(PCInfo, TPC); 486fee41517SMatt Arsenault return C.combineMachineInstrs(MF, /*CSEInfo*/ nullptr); 487fee41517SMatt Arsenault } 488fee41517SMatt Arsenault 489fee41517SMatt Arsenault char AMDGPUPostLegalizerCombiner::ID = 0; 490fee41517SMatt Arsenault INITIALIZE_PASS_BEGIN(AMDGPUPostLegalizerCombiner, DEBUG_TYPE, 491*ec043967SThomas Symalla "Combine AMDGPU machine instrs after legalization", false, 492*ec043967SThomas Symalla false) 493fee41517SMatt Arsenault INITIALIZE_PASS_DEPENDENCY(TargetPassConfig) 494fee41517SMatt Arsenault INITIALIZE_PASS_DEPENDENCY(GISelKnownBitsAnalysis) 495fee41517SMatt Arsenault INITIALIZE_PASS_END(AMDGPUPostLegalizerCombiner, DEBUG_TYPE, 496fee41517SMatt Arsenault "Combine AMDGPU machine instrs after legalization", false, 497fee41517SMatt Arsenault false) 498fee41517SMatt Arsenault 499fee41517SMatt Arsenault namespace llvm { 500fee41517SMatt Arsenault FunctionPass *createAMDGPUPostLegalizeCombiner(bool IsOptNone) { 501fee41517SMatt Arsenault return new AMDGPUPostLegalizerCombiner(IsOptNone); 502fee41517SMatt Arsenault } 503fee41517SMatt Arsenault } // end namespace llvm 504