1*753f127fSDimitry Andric //===- GCNCreateVOPD.cpp - Create VOPD Instructions ----------------------===// 2*753f127fSDimitry Andric // 3*753f127fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*753f127fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*753f127fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*753f127fSDimitry Andric // 7*753f127fSDimitry Andric //===----------------------------------------------------------------------===// 8*753f127fSDimitry Andric // 9*753f127fSDimitry Andric /// \file 10*753f127fSDimitry Andric /// Combine VALU pairs into VOPD instructions 11*753f127fSDimitry Andric /// Only works on wave32 12*753f127fSDimitry Andric /// Has register requirements, we reject creating VOPD if the requirements are 13*753f127fSDimitry Andric /// not met. 14*753f127fSDimitry Andric /// shouldCombineVOPD mutator in postRA machine scheduler puts candidate 15*753f127fSDimitry Andric /// instructions for VOPD back-to-back 16*753f127fSDimitry Andric /// 17*753f127fSDimitry Andric // 18*753f127fSDimitry Andric //===----------------------------------------------------------------------===// 19*753f127fSDimitry Andric 20*753f127fSDimitry Andric #include "AMDGPU.h" 21*753f127fSDimitry Andric #include "GCNSubtarget.h" 22*753f127fSDimitry Andric #include "GCNVOPDUtils.h" 23*753f127fSDimitry Andric #include "MCTargetDesc/AMDGPUMCTargetDesc.h" 24*753f127fSDimitry Andric #include "SIInstrInfo.h" 25*753f127fSDimitry Andric #include "Utils/AMDGPUBaseInfo.h" 26*753f127fSDimitry Andric #include "llvm/ADT/SmallVector.h" 27*753f127fSDimitry Andric #include "llvm/ADT/Statistic.h" 28*753f127fSDimitry Andric #include "llvm/ADT/StringMap.h" 29*753f127fSDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h" 30*753f127fSDimitry Andric #include "llvm/CodeGen/MachineInstr.h" 31*753f127fSDimitry Andric #include "llvm/CodeGen/MachineOperand.h" 32*753f127fSDimitry Andric #include "llvm/Support/Casting.h" 33*753f127fSDimitry Andric #include "llvm/Support/Debug.h" 34*753f127fSDimitry Andric #include <utility> 35*753f127fSDimitry Andric 36*753f127fSDimitry Andric #define DEBUG_TYPE "gcn-create-vopd" 37*753f127fSDimitry Andric STATISTIC(NumVOPDCreated, "Number of VOPD Insts Created."); 38*753f127fSDimitry Andric 39*753f127fSDimitry Andric using namespace llvm; 40*753f127fSDimitry Andric 41*753f127fSDimitry Andric namespace { 42*753f127fSDimitry Andric 43*753f127fSDimitry Andric class GCNCreateVOPD : public MachineFunctionPass { 44*753f127fSDimitry Andric private: 45*753f127fSDimitry Andric public: 46*753f127fSDimitry Andric static char ID; 47*753f127fSDimitry Andric const GCNSubtarget *ST = nullptr; 48*753f127fSDimitry Andric 49*753f127fSDimitry Andric GCNCreateVOPD() : MachineFunctionPass(ID) {} 50*753f127fSDimitry Andric 51*753f127fSDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 52*753f127fSDimitry Andric AU.setPreservesCFG(); 53*753f127fSDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 54*753f127fSDimitry Andric } 55*753f127fSDimitry Andric 56*753f127fSDimitry Andric StringRef getPassName() const override { 57*753f127fSDimitry Andric return "GCN Create VOPD Instructions"; 58*753f127fSDimitry Andric } 59*753f127fSDimitry Andric 60*753f127fSDimitry Andric bool doReplace(const SIInstrInfo *SII, 61*753f127fSDimitry Andric std::pair<MachineInstr *, MachineInstr *> &Pair) { 62*753f127fSDimitry Andric auto *FirstMI = Pair.first; 63*753f127fSDimitry Andric auto *SecondMI = Pair.second; 64*753f127fSDimitry Andric unsigned Opc1 = FirstMI->getOpcode(); 65*753f127fSDimitry Andric unsigned Opc2 = SecondMI->getOpcode(); 66*753f127fSDimitry Andric int NewOpcode = AMDGPU::getVOPDFull(AMDGPU::getVOPDOpcode(Opc1), 67*753f127fSDimitry Andric AMDGPU::getVOPDOpcode(Opc2)); 68*753f127fSDimitry Andric assert(NewOpcode != -1 && 69*753f127fSDimitry Andric "Should have previously determined this as a possible VOPD\n"); 70*753f127fSDimitry Andric 71*753f127fSDimitry Andric auto VOPDInst = BuildMI(*FirstMI->getParent(), FirstMI, 72*753f127fSDimitry Andric FirstMI->getDebugLoc(), SII->get(NewOpcode)) 73*753f127fSDimitry Andric .setMIFlags(FirstMI->getFlags() | SecondMI->getFlags()); 74*753f127fSDimitry Andric VOPDInst.add(FirstMI->getOperand(0)) 75*753f127fSDimitry Andric .add(SecondMI->getOperand(0)) 76*753f127fSDimitry Andric .add(FirstMI->getOperand(1)); 77*753f127fSDimitry Andric 78*753f127fSDimitry Andric switch (Opc1) { 79*753f127fSDimitry Andric case AMDGPU::V_MOV_B32_e32: 80*753f127fSDimitry Andric break; 81*753f127fSDimitry Andric case AMDGPU::V_FMAMK_F32: 82*753f127fSDimitry Andric case AMDGPU::V_FMAAK_F32: 83*753f127fSDimitry Andric VOPDInst.add(FirstMI->getOperand(2)); 84*753f127fSDimitry Andric VOPDInst.add(FirstMI->getOperand(3)); 85*753f127fSDimitry Andric break; 86*753f127fSDimitry Andric default: 87*753f127fSDimitry Andric VOPDInst.add(FirstMI->getOperand(2)); 88*753f127fSDimitry Andric break; 89*753f127fSDimitry Andric } 90*753f127fSDimitry Andric 91*753f127fSDimitry Andric VOPDInst.add(SecondMI->getOperand(1)); 92*753f127fSDimitry Andric 93*753f127fSDimitry Andric switch (Opc2) { 94*753f127fSDimitry Andric case AMDGPU::V_MOV_B32_e32: 95*753f127fSDimitry Andric break; 96*753f127fSDimitry Andric case AMDGPU::V_FMAMK_F32: 97*753f127fSDimitry Andric case AMDGPU::V_FMAAK_F32: 98*753f127fSDimitry Andric VOPDInst.add(SecondMI->getOperand(2)); 99*753f127fSDimitry Andric VOPDInst.add(SecondMI->getOperand(3)); 100*753f127fSDimitry Andric break; 101*753f127fSDimitry Andric default: 102*753f127fSDimitry Andric VOPDInst.add(SecondMI->getOperand(2)); 103*753f127fSDimitry Andric break; 104*753f127fSDimitry Andric } 105*753f127fSDimitry Andric 106*753f127fSDimitry Andric VOPDInst.copyImplicitOps(*FirstMI); 107*753f127fSDimitry Andric VOPDInst.copyImplicitOps(*SecondMI); 108*753f127fSDimitry Andric 109*753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "VOPD Fused: " << *VOPDInst << " from\tX: " 110*753f127fSDimitry Andric << *Pair.first << "\tY: " << *Pair.second << "\n"); 111*753f127fSDimitry Andric FirstMI->eraseFromParent(); 112*753f127fSDimitry Andric SecondMI->eraseFromParent(); 113*753f127fSDimitry Andric ++NumVOPDCreated; 114*753f127fSDimitry Andric return true; 115*753f127fSDimitry Andric } 116*753f127fSDimitry Andric 117*753f127fSDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override { 118*753f127fSDimitry Andric if (skipFunction(MF.getFunction())) 119*753f127fSDimitry Andric return false; 120*753f127fSDimitry Andric ST = &MF.getSubtarget<GCNSubtarget>(); 121*753f127fSDimitry Andric if (!AMDGPU::hasVOPD(*ST) || !ST->isWave32()) 122*753f127fSDimitry Andric return false; 123*753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "CreateVOPD Pass:\n"); 124*753f127fSDimitry Andric 125*753f127fSDimitry Andric const SIInstrInfo *SII = ST->getInstrInfo(); 126*753f127fSDimitry Andric bool Changed = false; 127*753f127fSDimitry Andric 128*753f127fSDimitry Andric SmallVector<std::pair<MachineInstr *, MachineInstr *>> ReplaceCandidates; 129*753f127fSDimitry Andric 130*753f127fSDimitry Andric for (auto &MBB : MF) { 131*753f127fSDimitry Andric auto MII = MBB.begin(), E = MBB.end(); 132*753f127fSDimitry Andric while (MII != E) { 133*753f127fSDimitry Andric auto *FirstMI = &*MII; 134*753f127fSDimitry Andric MII = next_nodbg(MII, MBB.end()); 135*753f127fSDimitry Andric if (MII == MBB.end()) 136*753f127fSDimitry Andric break; 137*753f127fSDimitry Andric if (FirstMI->isDebugInstr()) 138*753f127fSDimitry Andric continue; 139*753f127fSDimitry Andric auto *SecondMI = &*MII; 140*753f127fSDimitry Andric unsigned Opc = FirstMI->getOpcode(); 141*753f127fSDimitry Andric unsigned Opc2 = SecondMI->getOpcode(); 142*753f127fSDimitry Andric llvm::AMDGPU::CanBeVOPD FirstCanBeVOPD = AMDGPU::getCanBeVOPD(Opc); 143*753f127fSDimitry Andric llvm::AMDGPU::CanBeVOPD SecondCanBeVOPD = AMDGPU::getCanBeVOPD(Opc2); 144*753f127fSDimitry Andric std::pair<MachineInstr *, MachineInstr *> Pair; 145*753f127fSDimitry Andric 146*753f127fSDimitry Andric if (FirstCanBeVOPD.X && SecondCanBeVOPD.Y) 147*753f127fSDimitry Andric Pair = {FirstMI, SecondMI}; 148*753f127fSDimitry Andric else if (FirstCanBeVOPD.Y && SecondCanBeVOPD.X) 149*753f127fSDimitry Andric Pair = {SecondMI, FirstMI}; 150*753f127fSDimitry Andric else 151*753f127fSDimitry Andric continue; 152*753f127fSDimitry Andric // checkVOPDRegConstraints cares about program order, but doReplace 153*753f127fSDimitry Andric // cares about X-Y order in the constituted VOPD 154*753f127fSDimitry Andric if (llvm::checkVOPDRegConstraints(*SII, *FirstMI, *SecondMI)) { 155*753f127fSDimitry Andric ReplaceCandidates.push_back(Pair); 156*753f127fSDimitry Andric ++MII; 157*753f127fSDimitry Andric } 158*753f127fSDimitry Andric } 159*753f127fSDimitry Andric } 160*753f127fSDimitry Andric for (auto &Pair : ReplaceCandidates) { 161*753f127fSDimitry Andric Changed |= doReplace(SII, Pair); 162*753f127fSDimitry Andric } 163*753f127fSDimitry Andric 164*753f127fSDimitry Andric return Changed; 165*753f127fSDimitry Andric } 166*753f127fSDimitry Andric }; 167*753f127fSDimitry Andric 168*753f127fSDimitry Andric } // namespace 169*753f127fSDimitry Andric 170*753f127fSDimitry Andric char GCNCreateVOPD::ID = 0; 171*753f127fSDimitry Andric 172*753f127fSDimitry Andric char &llvm::GCNCreateVOPDID = GCNCreateVOPD::ID; 173*753f127fSDimitry Andric 174*753f127fSDimitry Andric INITIALIZE_PASS(GCNCreateVOPD, DEBUG_TYPE, "GCN Create VOPD Instructions", 175*753f127fSDimitry Andric false, false) 176