1fee41517SMatt Arsenault //=== lib/CodeGen/GlobalISel/AMDGPUPostLegalizerCombiner.cpp ---------------===// 2fee41517SMatt Arsenault // 3fee41517SMatt Arsenault // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4fee41517SMatt Arsenault // See https://llvm.org/LICENSE.txt for license information. 5fee41517SMatt Arsenault // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6fee41517SMatt Arsenault // 7fee41517SMatt Arsenault //===----------------------------------------------------------------------===// 8fee41517SMatt Arsenault // 9fee41517SMatt Arsenault // This pass does combining of machine instructions at the generic MI level, 10fee41517SMatt Arsenault // after the legalizer. 11fee41517SMatt Arsenault // 12fee41517SMatt Arsenault //===----------------------------------------------------------------------===// 13fee41517SMatt Arsenault 146a87e9b0Sdfukalov #include "AMDGPU.h" 15fee41517SMatt Arsenault #include "AMDGPULegalizerInfo.h" 16560d7e04Sdfukalov #include "GCNSubtarget.h" 17560d7e04Sdfukalov #include "MCTargetDesc/AMDGPUMCTargetDesc.h" 18fee41517SMatt Arsenault #include "llvm/CodeGen/GlobalISel/Combiner.h" 19fee41517SMatt Arsenault #include "llvm/CodeGen/GlobalISel/CombinerHelper.h" 20fee41517SMatt Arsenault #include "llvm/CodeGen/GlobalISel/CombinerInfo.h" 21fee41517SMatt Arsenault #include "llvm/CodeGen/GlobalISel/GISelKnownBits.h" 22fee41517SMatt Arsenault #include "llvm/CodeGen/GlobalISel/MIPatternMatch.h" 23fee41517SMatt Arsenault #include "llvm/CodeGen/MachineDominators.h" 24fee41517SMatt Arsenault #include "llvm/CodeGen/TargetPassConfig.h" 256a87e9b0Sdfukalov #include "llvm/Target/TargetMachine.h" 26fee41517SMatt Arsenault 27fee41517SMatt Arsenault #define DEBUG_TYPE "amdgpu-postlegalizer-combiner" 28fee41517SMatt Arsenault 29fee41517SMatt Arsenault using namespace llvm; 30fee41517SMatt Arsenault using namespace MIPatternMatch; 31fee41517SMatt Arsenault 320031418dSPetar Avramovic class AMDGPUPostLegalizerCombinerHelper { 330031418dSPetar Avramovic protected: 340031418dSPetar Avramovic MachineIRBuilder &B; 350031418dSPetar Avramovic MachineFunction &MF; 360031418dSPetar Avramovic MachineRegisterInfo &MRI; 370031418dSPetar Avramovic CombinerHelper &Helper; 380031418dSPetar Avramovic 390031418dSPetar Avramovic public: 400031418dSPetar Avramovic AMDGPUPostLegalizerCombinerHelper(MachineIRBuilder &B, CombinerHelper &Helper) 410031418dSPetar Avramovic : B(B), MF(B.getMF()), MRI(*B.getMRI()), Helper(Helper){}; 420031418dSPetar Avramovic 43fee41517SMatt Arsenault struct FMinFMaxLegacyInfo { 44fee41517SMatt Arsenault Register LHS; 45fee41517SMatt Arsenault Register RHS; 46fee41517SMatt Arsenault Register True; 47fee41517SMatt Arsenault Register False; 48fee41517SMatt Arsenault CmpInst::Predicate Pred; 49fee41517SMatt Arsenault }; 50fee41517SMatt Arsenault 51fee41517SMatt Arsenault // TODO: Make sure fmin_legacy/fmax_legacy don't canonicalize 520031418dSPetar Avramovic bool matchFMinFMaxLegacy(MachineInstr &MI, FMinFMaxLegacyInfo &Info); 530031418dSPetar Avramovic void applySelectFCmpToFMinToFMaxLegacy(MachineInstr &MI, 540031418dSPetar Avramovic const FMinFMaxLegacyInfo &Info); 550031418dSPetar Avramovic 560031418dSPetar Avramovic bool matchUCharToFloat(MachineInstr &MI); 570031418dSPetar Avramovic void applyUCharToFloat(MachineInstr &MI); 580031418dSPetar Avramovic 590031418dSPetar Avramovic // FIXME: Should be able to have 2 separate matchdatas rather than custom 600031418dSPetar Avramovic // struct boilerplate. 610031418dSPetar Avramovic struct CvtF32UByteMatchInfo { 620031418dSPetar Avramovic Register CvtVal; 630031418dSPetar Avramovic unsigned ShiftOffset; 640031418dSPetar Avramovic }; 650031418dSPetar Avramovic 660031418dSPetar Avramovic bool matchCvtF32UByteN(MachineInstr &MI, CvtF32UByteMatchInfo &MatchInfo); 670031418dSPetar Avramovic void applyCvtF32UByteN(MachineInstr &MI, 680031418dSPetar Avramovic const CvtF32UByteMatchInfo &MatchInfo); 69*62af0305SThomas Symalla 70*62af0305SThomas Symalla struct ClampI64ToI16MatchInfo { 71*62af0305SThomas Symalla int64_t Cmp1; 72*62af0305SThomas Symalla int64_t Cmp2; 73*62af0305SThomas Symalla Register Origin; 74*62af0305SThomas Symalla }; 75*62af0305SThomas Symalla 76*62af0305SThomas Symalla bool matchClampI64ToI16(MachineInstr &MI, MachineRegisterInfo &MRI, 77*62af0305SThomas Symalla MachineFunction &MF, 78*62af0305SThomas Symalla ClampI64ToI16MatchInfo &MatchInfo); 79*62af0305SThomas Symalla 80*62af0305SThomas Symalla void applyClampI64ToI16(MachineInstr &MI, 81*62af0305SThomas Symalla const ClampI64ToI16MatchInfo &MatchInfo); 820031418dSPetar Avramovic }; 830031418dSPetar Avramovic 840031418dSPetar Avramovic bool AMDGPUPostLegalizerCombinerHelper::matchFMinFMaxLegacy( 850031418dSPetar Avramovic MachineInstr &MI, FMinFMaxLegacyInfo &Info) { 86fee41517SMatt Arsenault // FIXME: Combines should have subtarget predicates, and we shouldn't need 87fee41517SMatt Arsenault // this here. 88fee41517SMatt Arsenault if (!MF.getSubtarget<GCNSubtarget>().hasFminFmaxLegacy()) 89fee41517SMatt Arsenault return false; 90fee41517SMatt Arsenault 91fee41517SMatt Arsenault // FIXME: Type predicate on pattern 92fee41517SMatt Arsenault if (MRI.getType(MI.getOperand(0).getReg()) != LLT::scalar(32)) 93fee41517SMatt Arsenault return false; 94fee41517SMatt Arsenault 95fee41517SMatt Arsenault Register Cond = MI.getOperand(1).getReg(); 96fee41517SMatt Arsenault if (!MRI.hasOneNonDBGUse(Cond) || 97fee41517SMatt Arsenault !mi_match(Cond, MRI, 98fee41517SMatt Arsenault m_GFCmp(m_Pred(Info.Pred), m_Reg(Info.LHS), m_Reg(Info.RHS)))) 99fee41517SMatt Arsenault return false; 100fee41517SMatt Arsenault 101fee41517SMatt Arsenault Info.True = MI.getOperand(2).getReg(); 102fee41517SMatt Arsenault Info.False = MI.getOperand(3).getReg(); 103fee41517SMatt Arsenault 104fee41517SMatt Arsenault if (!(Info.LHS == Info.True && Info.RHS == Info.False) && 105fee41517SMatt Arsenault !(Info.LHS == Info.False && Info.RHS == Info.True)) 106fee41517SMatt Arsenault return false; 107fee41517SMatt Arsenault 108fee41517SMatt Arsenault switch (Info.Pred) { 109fee41517SMatt Arsenault case CmpInst::FCMP_FALSE: 110fee41517SMatt Arsenault case CmpInst::FCMP_OEQ: 111fee41517SMatt Arsenault case CmpInst::FCMP_ONE: 112fee41517SMatt Arsenault case CmpInst::FCMP_ORD: 113fee41517SMatt Arsenault case CmpInst::FCMP_UNO: 114fee41517SMatt Arsenault case CmpInst::FCMP_UEQ: 115fee41517SMatt Arsenault case CmpInst::FCMP_UNE: 116fee41517SMatt Arsenault case CmpInst::FCMP_TRUE: 117fee41517SMatt Arsenault return false; 118fee41517SMatt Arsenault default: 119fee41517SMatt Arsenault return true; 120fee41517SMatt Arsenault } 121fee41517SMatt Arsenault } 122fee41517SMatt Arsenault 1230031418dSPetar Avramovic void AMDGPUPostLegalizerCombinerHelper::applySelectFCmpToFMinToFMaxLegacy( 1240031418dSPetar Avramovic MachineInstr &MI, const FMinFMaxLegacyInfo &Info) { 1250031418dSPetar Avramovic B.setInstrAndDebugLoc(MI); 1260031418dSPetar Avramovic auto buildNewInst = [&MI, this](unsigned Opc, Register X, Register Y) { 1270031418dSPetar Avramovic B.buildInstr(Opc, {MI.getOperand(0)}, {X, Y}, MI.getFlags()); 128fee41517SMatt Arsenault }; 129fee41517SMatt Arsenault 130fee41517SMatt Arsenault switch (Info.Pred) { 131fee41517SMatt Arsenault case CmpInst::FCMP_ULT: 132fee41517SMatt Arsenault case CmpInst::FCMP_ULE: 133fee41517SMatt Arsenault if (Info.LHS == Info.True) 134fee41517SMatt Arsenault buildNewInst(AMDGPU::G_AMDGPU_FMIN_LEGACY, Info.RHS, Info.LHS); 135fee41517SMatt Arsenault else 136fee41517SMatt Arsenault buildNewInst(AMDGPU::G_AMDGPU_FMAX_LEGACY, Info.LHS, Info.RHS); 137fee41517SMatt Arsenault break; 138fee41517SMatt Arsenault case CmpInst::FCMP_OLE: 139fee41517SMatt Arsenault case CmpInst::FCMP_OLT: { 140fee41517SMatt Arsenault // We need to permute the operands to get the correct NaN behavior. The 141fee41517SMatt Arsenault // selected operand is the second one based on the failing compare with NaN, 142fee41517SMatt Arsenault // so permute it based on the compare type the hardware uses. 143fee41517SMatt Arsenault if (Info.LHS == Info.True) 144fee41517SMatt Arsenault buildNewInst(AMDGPU::G_AMDGPU_FMIN_LEGACY, Info.LHS, Info.RHS); 145fee41517SMatt Arsenault else 146fee41517SMatt Arsenault buildNewInst(AMDGPU::G_AMDGPU_FMAX_LEGACY, Info.RHS, Info.LHS); 147fee41517SMatt Arsenault break; 148fee41517SMatt Arsenault } 149fee41517SMatt Arsenault case CmpInst::FCMP_UGE: 150fee41517SMatt Arsenault case CmpInst::FCMP_UGT: { 151fee41517SMatt Arsenault if (Info.LHS == Info.True) 152fee41517SMatt Arsenault buildNewInst(AMDGPU::G_AMDGPU_FMAX_LEGACY, Info.RHS, Info.LHS); 153fee41517SMatt Arsenault else 154fee41517SMatt Arsenault buildNewInst(AMDGPU::G_AMDGPU_FMIN_LEGACY, Info.LHS, Info.RHS); 155fee41517SMatt Arsenault break; 156fee41517SMatt Arsenault } 157fee41517SMatt Arsenault case CmpInst::FCMP_OGT: 158fee41517SMatt Arsenault case CmpInst::FCMP_OGE: { 159fee41517SMatt Arsenault if (Info.LHS == Info.True) 160fee41517SMatt Arsenault buildNewInst(AMDGPU::G_AMDGPU_FMAX_LEGACY, Info.LHS, Info.RHS); 161fee41517SMatt Arsenault else 162fee41517SMatt Arsenault buildNewInst(AMDGPU::G_AMDGPU_FMIN_LEGACY, Info.RHS, Info.LHS); 163fee41517SMatt Arsenault break; 164fee41517SMatt Arsenault } 165fee41517SMatt Arsenault default: 166fee41517SMatt Arsenault llvm_unreachable("predicate should not have matched"); 167fee41517SMatt Arsenault } 168fee41517SMatt Arsenault 169fee41517SMatt Arsenault MI.eraseFromParent(); 170fee41517SMatt Arsenault } 171fee41517SMatt Arsenault 1720031418dSPetar Avramovic bool AMDGPUPostLegalizerCombinerHelper::matchUCharToFloat(MachineInstr &MI) { 173b27d255eSMatt Arsenault Register DstReg = MI.getOperand(0).getReg(); 174b27d255eSMatt Arsenault 175b27d255eSMatt Arsenault // TODO: We could try to match extracting the higher bytes, which would be 176b27d255eSMatt Arsenault // easier if i8 vectors weren't promoted to i32 vectors, particularly after 177b27d255eSMatt Arsenault // types are legalized. v4i8 -> v4f32 is probably the only case to worry 178b27d255eSMatt Arsenault // about in practice. 179b27d255eSMatt Arsenault LLT Ty = MRI.getType(DstReg); 180b27d255eSMatt Arsenault if (Ty == LLT::scalar(32) || Ty == LLT::scalar(16)) { 181db777eaeSMatt Arsenault Register SrcReg = MI.getOperand(1).getReg(); 182db777eaeSMatt Arsenault unsigned SrcSize = MRI.getType(SrcReg).getSizeInBits(); 183db777eaeSMatt Arsenault assert(SrcSize == 16 || SrcSize == 32 || SrcSize == 64); 184db777eaeSMatt Arsenault const APInt Mask = APInt::getHighBitsSet(SrcSize, SrcSize - 8); 185db777eaeSMatt Arsenault return Helper.getKnownBits()->maskedValueIsZero(SrcReg, Mask); 186b27d255eSMatt Arsenault } 187b27d255eSMatt Arsenault 188b27d255eSMatt Arsenault return false; 189b27d255eSMatt Arsenault } 190b27d255eSMatt Arsenault 1910031418dSPetar Avramovic void AMDGPUPostLegalizerCombinerHelper::applyUCharToFloat(MachineInstr &MI) { 1920031418dSPetar Avramovic B.setInstrAndDebugLoc(MI); 193b27d255eSMatt Arsenault 194b27d255eSMatt Arsenault const LLT S32 = LLT::scalar(32); 195b27d255eSMatt Arsenault 196b27d255eSMatt Arsenault Register DstReg = MI.getOperand(0).getReg(); 197db777eaeSMatt Arsenault Register SrcReg = MI.getOperand(1).getReg(); 1980031418dSPetar Avramovic LLT Ty = MRI.getType(DstReg); 1990031418dSPetar Avramovic LLT SrcTy = MRI.getType(SrcReg); 200db777eaeSMatt Arsenault if (SrcTy != S32) 201db777eaeSMatt Arsenault SrcReg = B.buildAnyExtOrTrunc(S32, SrcReg).getReg(0); 202b27d255eSMatt Arsenault 203b27d255eSMatt Arsenault if (Ty == S32) { 204b27d255eSMatt Arsenault B.buildInstr(AMDGPU::G_AMDGPU_CVT_F32_UBYTE0, {DstReg}, 205db777eaeSMatt Arsenault {SrcReg}, MI.getFlags()); 206b27d255eSMatt Arsenault } else { 207b27d255eSMatt Arsenault auto Cvt0 = B.buildInstr(AMDGPU::G_AMDGPU_CVT_F32_UBYTE0, {S32}, 208db777eaeSMatt Arsenault {SrcReg}, MI.getFlags()); 209b27d255eSMatt Arsenault B.buildFPTrunc(DstReg, Cvt0, MI.getFlags()); 210b27d255eSMatt Arsenault } 211b27d255eSMatt Arsenault 212b27d255eSMatt Arsenault MI.eraseFromParent(); 213b27d255eSMatt Arsenault } 214fee41517SMatt Arsenault 2150031418dSPetar Avramovic bool AMDGPUPostLegalizerCombinerHelper::matchCvtF32UByteN( 2160031418dSPetar Avramovic MachineInstr &MI, CvtF32UByteMatchInfo &MatchInfo) { 2170ba40d4cSMatt Arsenault Register SrcReg = MI.getOperand(1).getReg(); 2180ba40d4cSMatt Arsenault 2190ba40d4cSMatt Arsenault // Look through G_ZEXT. 2200ba40d4cSMatt Arsenault mi_match(SrcReg, MRI, m_GZExt(m_Reg(SrcReg))); 2210ba40d4cSMatt Arsenault 2220ba40d4cSMatt Arsenault Register Src0; 2230ba40d4cSMatt Arsenault int64_t ShiftAmt; 2240ba40d4cSMatt Arsenault bool IsShr = mi_match(SrcReg, MRI, m_GLShr(m_Reg(Src0), m_ICst(ShiftAmt))); 2250ba40d4cSMatt Arsenault if (IsShr || mi_match(SrcReg, MRI, m_GShl(m_Reg(Src0), m_ICst(ShiftAmt)))) { 2260ba40d4cSMatt Arsenault const unsigned Offset = MI.getOpcode() - AMDGPU::G_AMDGPU_CVT_F32_UBYTE0; 2270ba40d4cSMatt Arsenault 2280ba40d4cSMatt Arsenault unsigned ShiftOffset = 8 * Offset; 2290ba40d4cSMatt Arsenault if (IsShr) 2300ba40d4cSMatt Arsenault ShiftOffset += ShiftAmt; 2310ba40d4cSMatt Arsenault else 2320ba40d4cSMatt Arsenault ShiftOffset -= ShiftAmt; 2330ba40d4cSMatt Arsenault 2340ba40d4cSMatt Arsenault MatchInfo.CvtVal = Src0; 2350ba40d4cSMatt Arsenault MatchInfo.ShiftOffset = ShiftOffset; 2360ba40d4cSMatt Arsenault return ShiftOffset < 32 && ShiftOffset >= 8 && (ShiftOffset % 8) == 0; 2370ba40d4cSMatt Arsenault } 2380ba40d4cSMatt Arsenault 2390ba40d4cSMatt Arsenault // TODO: Simplify demanded bits. 2400ba40d4cSMatt Arsenault return false; 2410ba40d4cSMatt Arsenault } 2420ba40d4cSMatt Arsenault 2430031418dSPetar Avramovic void AMDGPUPostLegalizerCombinerHelper::applyCvtF32UByteN( 2440031418dSPetar Avramovic MachineInstr &MI, const CvtF32UByteMatchInfo &MatchInfo) { 2450031418dSPetar Avramovic B.setInstrAndDebugLoc(MI); 2460ba40d4cSMatt Arsenault unsigned NewOpc = AMDGPU::G_AMDGPU_CVT_F32_UBYTE0 + MatchInfo.ShiftOffset / 8; 2470ba40d4cSMatt Arsenault 2480ba40d4cSMatt Arsenault const LLT S32 = LLT::scalar(32); 2490ba40d4cSMatt Arsenault Register CvtSrc = MatchInfo.CvtVal; 2500031418dSPetar Avramovic LLT SrcTy = MRI.getType(MatchInfo.CvtVal); 2510ba40d4cSMatt Arsenault if (SrcTy != S32) { 2520ba40d4cSMatt Arsenault assert(SrcTy.isScalar() && SrcTy.getSizeInBits() >= 8); 2530ba40d4cSMatt Arsenault CvtSrc = B.buildAnyExt(S32, CvtSrc).getReg(0); 2540ba40d4cSMatt Arsenault } 2550ba40d4cSMatt Arsenault 2560ba40d4cSMatt Arsenault assert(MI.getOpcode() != NewOpc); 2570ba40d4cSMatt Arsenault B.buildInstr(NewOpc, {MI.getOperand(0)}, {CvtSrc}, MI.getFlags()); 2580ba40d4cSMatt Arsenault MI.eraseFromParent(); 2590ba40d4cSMatt Arsenault } 2600ba40d4cSMatt Arsenault 261*62af0305SThomas Symalla bool AMDGPUPostLegalizerCombinerHelper::matchClampI64ToI16(MachineInstr &MI, MachineRegisterInfo &MRI, 262*62af0305SThomas Symalla MachineFunction &MF, 263*62af0305SThomas Symalla ClampI64ToI16MatchInfo &MatchInfo) { 264*62af0305SThomas Symalla assert(MI.getOpcode() == TargetOpcode::G_TRUNC && "Invalid instruction!"); 265*62af0305SThomas Symalla const LLT SrcType = MRI.getType(MI.getOperand(1).getReg()); 266*62af0305SThomas Symalla if (SrcType != LLT::scalar(64)) 267*62af0305SThomas Symalla return false; 268*62af0305SThomas Symalla 269*62af0305SThomas Symalla MachineIRBuilder B(MI); 270*62af0305SThomas Symalla 271*62af0305SThomas Symalla LLVM_DEBUG(dbgs() << "Matching Clamp i64 to i16"); 272*62af0305SThomas Symalla 273*62af0305SThomas Symalla if (mi_match(MI.getOperand(1).getReg(), MRI, 274*62af0305SThomas Symalla m_MaxMin(m_ICst(MatchInfo.Cmp1), 275*62af0305SThomas Symalla m_ICst(MatchInfo.Cmp2), 276*62af0305SThomas Symalla m_Reg(MatchInfo.Origin)))) { 277*62af0305SThomas Symalla const auto Cmp1 = static_cast<int64_t>(MatchInfo.Cmp1); 278*62af0305SThomas Symalla const auto Cmp2 = static_cast<int64_t>(MatchInfo.Cmp2); 279*62af0305SThomas Symalla 280*62af0305SThomas Symalla const int64_t Min = static_cast<int64_t>(std::numeric_limits<int16_t>::min()); 281*62af0305SThomas Symalla const int64_t Max = static_cast<int64_t>(std::numeric_limits<int16_t>::max()); 282*62af0305SThomas Symalla 283*62af0305SThomas Symalla // are we really trying to clamp against short boundaries? 284*62af0305SThomas Symalla return ((Cmp2 >= Cmp1 && Cmp1 >= Min && Cmp2 <= Max) || 285*62af0305SThomas Symalla (Cmp1 >= Cmp2 && Cmp1 <= Max && Cmp2 >= Min)); 286*62af0305SThomas Symalla } 287*62af0305SThomas Symalla 288*62af0305SThomas Symalla return false; 289*62af0305SThomas Symalla } 290*62af0305SThomas Symalla 291*62af0305SThomas Symalla void AMDGPUPostLegalizerCombinerHelper::applyClampI64ToI16(MachineInstr &MI, 292*62af0305SThomas Symalla const ClampI64ToI16MatchInfo &MatchInfo) { 293*62af0305SThomas Symalla LLVM_DEBUG(dbgs() << "Combining MI"); 294*62af0305SThomas Symalla 295*62af0305SThomas Symalla MachineIRBuilder B(MI); 296*62af0305SThomas Symalla MachineRegisterInfo &MRI = MI.getParent()->getParent()->getRegInfo(); 297*62af0305SThomas Symalla 298*62af0305SThomas Symalla Register Src = MatchInfo.Origin; 299*62af0305SThomas Symalla assert(MRI.getType(Src) == LLT::scalar(64)); 300*62af0305SThomas Symalla const LLT S32 = LLT::scalar(32); 301*62af0305SThomas Symalla 302*62af0305SThomas Symalla auto Unmerge = B.buildUnmerge(S32, Src); 303*62af0305SThomas Symalla Register Hi32 = Unmerge->getOperand(0).getReg(); 304*62af0305SThomas Symalla Register Lo32 = Unmerge->getOperand(1).getReg(); 305*62af0305SThomas Symalla MRI.setRegClass(Hi32, &AMDGPU::VGPR_32RegClass); 306*62af0305SThomas Symalla MRI.setRegClass(Lo32, &AMDGPU::VGPR_32RegClass); 307*62af0305SThomas Symalla 308*62af0305SThomas Symalla constexpr unsigned int CvtOpcode = AMDGPU::V_CVT_PK_I16_I32_e64; 309*62af0305SThomas Symalla assert(MI.getOpcode() != CvtOpcode); 310*62af0305SThomas Symalla 311*62af0305SThomas Symalla Register CvtDst = MRI.createGenericVirtualRegister(S32); 312*62af0305SThomas Symalla MRI.setRegClass(CvtDst, &AMDGPU::VGPR_32RegClass); 313*62af0305SThomas Symalla 314*62af0305SThomas Symalla auto CvtPk = B.buildInstr(CvtOpcode); 315*62af0305SThomas Symalla CvtPk.addDef(CvtDst); 316*62af0305SThomas Symalla CvtPk.addReg(Hi32); 317*62af0305SThomas Symalla CvtPk.addReg(Lo32); 318*62af0305SThomas Symalla CvtPk.setMIFlags(MI.getFlags()); 319*62af0305SThomas Symalla 320*62af0305SThomas Symalla auto min = std::min(MatchInfo.Cmp1, MatchInfo.Cmp2); 321*62af0305SThomas Symalla auto max = std::max(MatchInfo.Cmp1, MatchInfo.Cmp2); 322*62af0305SThomas Symalla 323*62af0305SThomas Symalla Register MinBoundaryDst = MRI.createGenericVirtualRegister(S32); 324*62af0305SThomas Symalla MRI.setRegClass(MinBoundaryDst, &AMDGPU::VGPR_32RegClass); 325*62af0305SThomas Symalla B.buildConstant(MinBoundaryDst, min); 326*62af0305SThomas Symalla 327*62af0305SThomas Symalla Register MaxBoundaryDst = MRI.createGenericVirtualRegister(S32); 328*62af0305SThomas Symalla MRI.setRegClass(MaxBoundaryDst, &AMDGPU::VGPR_32RegClass); 329*62af0305SThomas Symalla B.buildConstant(MaxBoundaryDst, max); 330*62af0305SThomas Symalla 331*62af0305SThomas Symalla Register MedDst = MRI.createGenericVirtualRegister(S32); 332*62af0305SThomas Symalla MRI.setRegClass(MedDst, &AMDGPU::VGPR_32RegClass); 333*62af0305SThomas Symalla 334*62af0305SThomas Symalla auto Med = B.buildInstr(AMDGPU::V_MED3_I32); 335*62af0305SThomas Symalla Med.addDef(MedDst); 336*62af0305SThomas Symalla Med.addReg(MinBoundaryDst); 337*62af0305SThomas Symalla Med.addReg(CvtDst); 338*62af0305SThomas Symalla Med.addReg(MaxBoundaryDst); 339*62af0305SThomas Symalla Med.setMIFlags(MI.getFlags()); 340*62af0305SThomas Symalla 341*62af0305SThomas Symalla B.buildCopy(MI.getOperand(0).getReg(), MedDst); 342*62af0305SThomas Symalla 343*62af0305SThomas Symalla MI.eraseFromParent(); 344*62af0305SThomas Symalla } 345*62af0305SThomas Symalla 3460031418dSPetar Avramovic class AMDGPUPostLegalizerCombinerHelperState { 3470031418dSPetar Avramovic protected: 3480031418dSPetar Avramovic CombinerHelper &Helper; 3490031418dSPetar Avramovic AMDGPUPostLegalizerCombinerHelper &PostLegalizerHelper; 3500031418dSPetar Avramovic 3510031418dSPetar Avramovic public: 3520031418dSPetar Avramovic AMDGPUPostLegalizerCombinerHelperState( 3530031418dSPetar Avramovic CombinerHelper &Helper, 3540031418dSPetar Avramovic AMDGPUPostLegalizerCombinerHelper &PostLegalizerHelper) 3550031418dSPetar Avramovic : Helper(Helper), PostLegalizerHelper(PostLegalizerHelper) {} 3560031418dSPetar Avramovic }; 3570031418dSPetar Avramovic 358fee41517SMatt Arsenault #define AMDGPUPOSTLEGALIZERCOMBINERHELPER_GENCOMBINERHELPER_DEPS 359fee41517SMatt Arsenault #include "AMDGPUGenPostLegalizeGICombiner.inc" 360fee41517SMatt Arsenault #undef AMDGPUPOSTLEGALIZERCOMBINERHELPER_GENCOMBINERHELPER_DEPS 361fee41517SMatt Arsenault 362fee41517SMatt Arsenault namespace { 363fee41517SMatt Arsenault #define AMDGPUPOSTLEGALIZERCOMBINERHELPER_GENCOMBINERHELPER_H 364fee41517SMatt Arsenault #include "AMDGPUGenPostLegalizeGICombiner.inc" 365fee41517SMatt Arsenault #undef AMDGPUPOSTLEGALIZERCOMBINERHELPER_GENCOMBINERHELPER_H 366fee41517SMatt Arsenault 36716bcd545SMatt Arsenault class AMDGPUPostLegalizerCombinerInfo final : public CombinerInfo { 368fee41517SMatt Arsenault GISelKnownBits *KB; 369fee41517SMatt Arsenault MachineDominatorTree *MDT; 370fee41517SMatt Arsenault 371fee41517SMatt Arsenault public: 372e35ba099SDaniel Sanders AMDGPUGenPostLegalizerCombinerHelperRuleConfig GeneratedRuleCfg; 373fee41517SMatt Arsenault 374fee41517SMatt Arsenault AMDGPUPostLegalizerCombinerInfo(bool EnableOpt, bool OptSize, bool MinSize, 375fee41517SMatt Arsenault const AMDGPULegalizerInfo *LI, 376fee41517SMatt Arsenault GISelKnownBits *KB, MachineDominatorTree *MDT) 377fee41517SMatt Arsenault : CombinerInfo(/*AllowIllegalOps*/ false, /*ShouldLegalizeIllegal*/ true, 378fee41517SMatt Arsenault /*LegalizerInfo*/ LI, EnableOpt, OptSize, MinSize), 379fee41517SMatt Arsenault KB(KB), MDT(MDT) { 380e35ba099SDaniel Sanders if (!GeneratedRuleCfg.parseCommandLineOption()) 381fee41517SMatt Arsenault report_fatal_error("Invalid rule identifier"); 382fee41517SMatt Arsenault } 383fee41517SMatt Arsenault 384d15723efSMatt Arsenault bool combine(GISelChangeObserver &Observer, MachineInstr &MI, 385fee41517SMatt Arsenault MachineIRBuilder &B) const override; 386fee41517SMatt Arsenault }; 387fee41517SMatt Arsenault 388fee41517SMatt Arsenault bool AMDGPUPostLegalizerCombinerInfo::combine(GISelChangeObserver &Observer, 389fee41517SMatt Arsenault MachineInstr &MI, 390fee41517SMatt Arsenault MachineIRBuilder &B) const { 39166ffa0e9SMatt Arsenault CombinerHelper Helper(Observer, B, KB, MDT, LInfo); 3920031418dSPetar Avramovic AMDGPUPostLegalizerCombinerHelper PostLegalizerHelper(B, Helper); 3930031418dSPetar Avramovic AMDGPUGenPostLegalizerCombinerHelper Generated(GeneratedRuleCfg, Helper, 3940031418dSPetar Avramovic PostLegalizerHelper); 395fee41517SMatt Arsenault 3960031418dSPetar Avramovic if (Generated.tryCombineAll(Observer, MI, B)) 397fee41517SMatt Arsenault return true; 398fee41517SMatt Arsenault 399fee41517SMatt Arsenault switch (MI.getOpcode()) { 400fee41517SMatt Arsenault case TargetOpcode::G_SHL: 401fee41517SMatt Arsenault case TargetOpcode::G_LSHR: 402fee41517SMatt Arsenault case TargetOpcode::G_ASHR: 403fee41517SMatt Arsenault // On some subtargets, 64-bit shift is a quarter rate instruction. In the 404fee41517SMatt Arsenault // common case, splitting this into a move and a 32-bit shift is faster and 405fee41517SMatt Arsenault // the same code size. 406fee41517SMatt Arsenault return Helper.tryCombineShiftToUnmerge(MI, 32); 407fee41517SMatt Arsenault } 408fee41517SMatt Arsenault 409fee41517SMatt Arsenault return false; 410fee41517SMatt Arsenault } 411fee41517SMatt Arsenault 412fee41517SMatt Arsenault #define AMDGPUPOSTLEGALIZERCOMBINERHELPER_GENCOMBINERHELPER_CPP 413fee41517SMatt Arsenault #include "AMDGPUGenPostLegalizeGICombiner.inc" 414fee41517SMatt Arsenault #undef AMDGPUPOSTLEGALIZERCOMBINERHELPER_GENCOMBINERHELPER_CPP 415fee41517SMatt Arsenault 416fee41517SMatt Arsenault // Pass boilerplate 417fee41517SMatt Arsenault // ================ 418fee41517SMatt Arsenault 419fee41517SMatt Arsenault class AMDGPUPostLegalizerCombiner : public MachineFunctionPass { 420fee41517SMatt Arsenault public: 421fee41517SMatt Arsenault static char ID; 422fee41517SMatt Arsenault 423fee41517SMatt Arsenault AMDGPUPostLegalizerCombiner(bool IsOptNone = false); 424fee41517SMatt Arsenault 425fee41517SMatt Arsenault StringRef getPassName() const override { 426fee41517SMatt Arsenault return "AMDGPUPostLegalizerCombiner"; 427fee41517SMatt Arsenault } 428fee41517SMatt Arsenault 429fee41517SMatt Arsenault bool runOnMachineFunction(MachineFunction &MF) override; 430fee41517SMatt Arsenault 431fee41517SMatt Arsenault void getAnalysisUsage(AnalysisUsage &AU) const override; 432fee41517SMatt Arsenault private: 433fee41517SMatt Arsenault bool IsOptNone; 434fee41517SMatt Arsenault }; 435fee41517SMatt Arsenault } // end anonymous namespace 436fee41517SMatt Arsenault 437fee41517SMatt Arsenault void AMDGPUPostLegalizerCombiner::getAnalysisUsage(AnalysisUsage &AU) const { 438fee41517SMatt Arsenault AU.addRequired<TargetPassConfig>(); 439fee41517SMatt Arsenault AU.setPreservesCFG(); 440fee41517SMatt Arsenault getSelectionDAGFallbackAnalysisUsage(AU); 441fee41517SMatt Arsenault AU.addRequired<GISelKnownBitsAnalysis>(); 442fee41517SMatt Arsenault AU.addPreserved<GISelKnownBitsAnalysis>(); 443fee41517SMatt Arsenault if (!IsOptNone) { 444fee41517SMatt Arsenault AU.addRequired<MachineDominatorTree>(); 445fee41517SMatt Arsenault AU.addPreserved<MachineDominatorTree>(); 446fee41517SMatt Arsenault } 447fee41517SMatt Arsenault MachineFunctionPass::getAnalysisUsage(AU); 448fee41517SMatt Arsenault } 449fee41517SMatt Arsenault 450fee41517SMatt Arsenault AMDGPUPostLegalizerCombiner::AMDGPUPostLegalizerCombiner(bool IsOptNone) 451fee41517SMatt Arsenault : MachineFunctionPass(ID), IsOptNone(IsOptNone) { 452fee41517SMatt Arsenault initializeAMDGPUPostLegalizerCombinerPass(*PassRegistry::getPassRegistry()); 453fee41517SMatt Arsenault } 454fee41517SMatt Arsenault 455fee41517SMatt Arsenault bool AMDGPUPostLegalizerCombiner::runOnMachineFunction(MachineFunction &MF) { 456fee41517SMatt Arsenault if (MF.getProperties().hasProperty( 457fee41517SMatt Arsenault MachineFunctionProperties::Property::FailedISel)) 458fee41517SMatt Arsenault return false; 459fee41517SMatt Arsenault auto *TPC = &getAnalysis<TargetPassConfig>(); 460fee41517SMatt Arsenault const Function &F = MF.getFunction(); 461fee41517SMatt Arsenault bool EnableOpt = 462fee41517SMatt Arsenault MF.getTarget().getOptLevel() != CodeGenOpt::None && !skipFunction(F); 463fee41517SMatt Arsenault 464fee41517SMatt Arsenault const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>(); 465fee41517SMatt Arsenault const AMDGPULegalizerInfo *LI 466fee41517SMatt Arsenault = static_cast<const AMDGPULegalizerInfo *>(ST.getLegalizerInfo()); 467fee41517SMatt Arsenault 468fee41517SMatt Arsenault GISelKnownBits *KB = &getAnalysis<GISelKnownBitsAnalysis>().get(MF); 469fee41517SMatt Arsenault MachineDominatorTree *MDT = 470fee41517SMatt Arsenault IsOptNone ? nullptr : &getAnalysis<MachineDominatorTree>(); 471fee41517SMatt Arsenault AMDGPUPostLegalizerCombinerInfo PCInfo(EnableOpt, F.hasOptSize(), 472fee41517SMatt Arsenault F.hasMinSize(), LI, KB, MDT); 473fee41517SMatt Arsenault Combiner C(PCInfo, TPC); 474fee41517SMatt Arsenault return C.combineMachineInstrs(MF, /*CSEInfo*/ nullptr); 475fee41517SMatt Arsenault } 476fee41517SMatt Arsenault 477fee41517SMatt Arsenault char AMDGPUPostLegalizerCombiner::ID = 0; 478fee41517SMatt Arsenault INITIALIZE_PASS_BEGIN(AMDGPUPostLegalizerCombiner, DEBUG_TYPE, 479fee41517SMatt Arsenault "Combine AMDGPU machine instrs after legalization", 480fee41517SMatt Arsenault false, false) 481fee41517SMatt Arsenault INITIALIZE_PASS_DEPENDENCY(TargetPassConfig) 482fee41517SMatt Arsenault INITIALIZE_PASS_DEPENDENCY(GISelKnownBitsAnalysis) 483fee41517SMatt Arsenault INITIALIZE_PASS_END(AMDGPUPostLegalizerCombiner, DEBUG_TYPE, 484fee41517SMatt Arsenault "Combine AMDGPU machine instrs after legalization", false, 485fee41517SMatt Arsenault false) 486fee41517SMatt Arsenault 487fee41517SMatt Arsenault namespace llvm { 488fee41517SMatt Arsenault FunctionPass *createAMDGPUPostLegalizeCombiner(bool IsOptNone) { 489fee41517SMatt Arsenault return new AMDGPUPostLegalizerCombiner(IsOptNone); 490fee41517SMatt Arsenault } 491fee41517SMatt Arsenault } // end namespace llvm 492