1753f127fSDimitry Andric //===- GCNCreateVOPD.cpp - Create VOPD Instructions ----------------------===// 2753f127fSDimitry Andric // 3753f127fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4753f127fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5753f127fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6753f127fSDimitry Andric // 7753f127fSDimitry Andric //===----------------------------------------------------------------------===// 8753f127fSDimitry Andric // 9753f127fSDimitry Andric /// \file 10753f127fSDimitry Andric /// Combine VALU pairs into VOPD instructions 11753f127fSDimitry Andric /// Only works on wave32 12753f127fSDimitry Andric /// Has register requirements, we reject creating VOPD if the requirements are 13753f127fSDimitry Andric /// not met. 14753f127fSDimitry Andric /// shouldCombineVOPD mutator in postRA machine scheduler puts candidate 15753f127fSDimitry Andric /// instructions for VOPD back-to-back 16753f127fSDimitry Andric /// 17753f127fSDimitry Andric // 18753f127fSDimitry Andric //===----------------------------------------------------------------------===// 19753f127fSDimitry Andric 20753f127fSDimitry Andric #include "AMDGPU.h" 21753f127fSDimitry Andric #include "GCNSubtarget.h" 22753f127fSDimitry Andric #include "GCNVOPDUtils.h" 23753f127fSDimitry Andric #include "MCTargetDesc/AMDGPUMCTargetDesc.h" 24753f127fSDimitry Andric #include "SIInstrInfo.h" 25753f127fSDimitry Andric #include "Utils/AMDGPUBaseInfo.h" 26753f127fSDimitry Andric #include "llvm/ADT/SmallVector.h" 27753f127fSDimitry Andric #include "llvm/ADT/Statistic.h" 28753f127fSDimitry Andric #include "llvm/ADT/StringMap.h" 29753f127fSDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h" 30753f127fSDimitry Andric #include "llvm/CodeGen/MachineInstr.h" 31753f127fSDimitry Andric #include "llvm/CodeGen/MachineOperand.h" 32753f127fSDimitry Andric #include "llvm/Support/Casting.h" 33753f127fSDimitry Andric #include "llvm/Support/Debug.h" 34753f127fSDimitry Andric #include <utility> 35753f127fSDimitry Andric 36753f127fSDimitry Andric #define DEBUG_TYPE "gcn-create-vopd" 37753f127fSDimitry Andric STATISTIC(NumVOPDCreated, "Number of VOPD Insts Created."); 38753f127fSDimitry Andric 39753f127fSDimitry Andric using namespace llvm; 40753f127fSDimitry Andric 41753f127fSDimitry Andric namespace { 42753f127fSDimitry Andric 43753f127fSDimitry Andric class GCNCreateVOPD : public MachineFunctionPass { 44753f127fSDimitry Andric private: 45*06c3fb27SDimitry Andric class VOPDCombineInfo { 46*06c3fb27SDimitry Andric public: 47*06c3fb27SDimitry Andric VOPDCombineInfo() {} 48*06c3fb27SDimitry Andric VOPDCombineInfo(MachineInstr *First, MachineInstr *Second) 49*06c3fb27SDimitry Andric : FirstMI(First), SecondMI(Second) {} 50*06c3fb27SDimitry Andric 51*06c3fb27SDimitry Andric MachineInstr *FirstMI; 52*06c3fb27SDimitry Andric MachineInstr *SecondMI; 53*06c3fb27SDimitry Andric }; 54*06c3fb27SDimitry Andric 55753f127fSDimitry Andric public: 56753f127fSDimitry Andric static char ID; 57753f127fSDimitry Andric const GCNSubtarget *ST = nullptr; 58753f127fSDimitry Andric 59753f127fSDimitry Andric GCNCreateVOPD() : MachineFunctionPass(ID) {} 60753f127fSDimitry Andric 61753f127fSDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 62753f127fSDimitry Andric AU.setPreservesCFG(); 63753f127fSDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 64753f127fSDimitry Andric } 65753f127fSDimitry Andric 66753f127fSDimitry Andric StringRef getPassName() const override { 67753f127fSDimitry Andric return "GCN Create VOPD Instructions"; 68753f127fSDimitry Andric } 69753f127fSDimitry Andric 70*06c3fb27SDimitry Andric bool doReplace(const SIInstrInfo *SII, VOPDCombineInfo &CI) { 71*06c3fb27SDimitry Andric auto *FirstMI = CI.FirstMI; 72*06c3fb27SDimitry Andric auto *SecondMI = CI.SecondMI; 73753f127fSDimitry Andric unsigned Opc1 = FirstMI->getOpcode(); 74753f127fSDimitry Andric unsigned Opc2 = SecondMI->getOpcode(); 75753f127fSDimitry Andric int NewOpcode = AMDGPU::getVOPDFull(AMDGPU::getVOPDOpcode(Opc1), 76753f127fSDimitry Andric AMDGPU::getVOPDOpcode(Opc2)); 77753f127fSDimitry Andric assert(NewOpcode != -1 && 78753f127fSDimitry Andric "Should have previously determined this as a possible VOPD\n"); 79753f127fSDimitry Andric 80753f127fSDimitry Andric auto VOPDInst = BuildMI(*FirstMI->getParent(), FirstMI, 81753f127fSDimitry Andric FirstMI->getDebugLoc(), SII->get(NewOpcode)) 82753f127fSDimitry Andric .setMIFlags(FirstMI->getFlags() | SecondMI->getFlags()); 83753f127fSDimitry Andric 84bdd1243dSDimitry Andric namespace VOPD = AMDGPU::VOPD; 85bdd1243dSDimitry Andric MachineInstr *MI[] = {FirstMI, SecondMI}; 86bdd1243dSDimitry Andric auto InstInfo = 87bdd1243dSDimitry Andric AMDGPU::getVOPDInstInfo(FirstMI->getDesc(), SecondMI->getDesc()); 88bdd1243dSDimitry Andric 89bdd1243dSDimitry Andric for (auto CompIdx : VOPD::COMPONENTS) { 90bdd1243dSDimitry Andric auto MCOprIdx = InstInfo[CompIdx].getIndexOfDstInMCOperands(); 91bdd1243dSDimitry Andric VOPDInst.add(MI[CompIdx]->getOperand(MCOprIdx)); 92753f127fSDimitry Andric } 93753f127fSDimitry Andric 94bdd1243dSDimitry Andric for (auto CompIdx : VOPD::COMPONENTS) { 95bdd1243dSDimitry Andric auto CompSrcOprNum = InstInfo[CompIdx].getCompSrcOperandsNum(); 96bdd1243dSDimitry Andric for (unsigned CompSrcIdx = 0; CompSrcIdx < CompSrcOprNum; ++CompSrcIdx) { 97bdd1243dSDimitry Andric auto MCOprIdx = InstInfo[CompIdx].getIndexOfSrcInMCOperands(CompSrcIdx); 98bdd1243dSDimitry Andric VOPDInst.add(MI[CompIdx]->getOperand(MCOprIdx)); 99bdd1243dSDimitry Andric } 100753f127fSDimitry Andric } 101753f127fSDimitry Andric 102bdd1243dSDimitry Andric for (auto CompIdx : VOPD::COMPONENTS) 103bdd1243dSDimitry Andric VOPDInst.copyImplicitOps(*MI[CompIdx]); 104753f127fSDimitry Andric 105753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "VOPD Fused: " << *VOPDInst << " from\tX: " 106*06c3fb27SDimitry Andric << *CI.FirstMI << "\tY: " << *CI.SecondMI << "\n"); 107bdd1243dSDimitry Andric 108bdd1243dSDimitry Andric for (auto CompIdx : VOPD::COMPONENTS) 109bdd1243dSDimitry Andric MI[CompIdx]->eraseFromParent(); 110bdd1243dSDimitry Andric 111753f127fSDimitry Andric ++NumVOPDCreated; 112753f127fSDimitry Andric return true; 113753f127fSDimitry Andric } 114753f127fSDimitry Andric 115753f127fSDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override { 116753f127fSDimitry Andric if (skipFunction(MF.getFunction())) 117753f127fSDimitry Andric return false; 118753f127fSDimitry Andric ST = &MF.getSubtarget<GCNSubtarget>(); 119753f127fSDimitry Andric if (!AMDGPU::hasVOPD(*ST) || !ST->isWave32()) 120753f127fSDimitry Andric return false; 121753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "CreateVOPD Pass:\n"); 122753f127fSDimitry Andric 123753f127fSDimitry Andric const SIInstrInfo *SII = ST->getInstrInfo(); 124753f127fSDimitry Andric bool Changed = false; 125753f127fSDimitry Andric 126*06c3fb27SDimitry Andric SmallVector<VOPDCombineInfo> ReplaceCandidates; 127753f127fSDimitry Andric 128753f127fSDimitry Andric for (auto &MBB : MF) { 129753f127fSDimitry Andric auto MII = MBB.begin(), E = MBB.end(); 130753f127fSDimitry Andric while (MII != E) { 131753f127fSDimitry Andric auto *FirstMI = &*MII; 132753f127fSDimitry Andric MII = next_nodbg(MII, MBB.end()); 133753f127fSDimitry Andric if (MII == MBB.end()) 134753f127fSDimitry Andric break; 135753f127fSDimitry Andric if (FirstMI->isDebugInstr()) 136753f127fSDimitry Andric continue; 137753f127fSDimitry Andric auto *SecondMI = &*MII; 138753f127fSDimitry Andric unsigned Opc = FirstMI->getOpcode(); 139753f127fSDimitry Andric unsigned Opc2 = SecondMI->getOpcode(); 140753f127fSDimitry Andric llvm::AMDGPU::CanBeVOPD FirstCanBeVOPD = AMDGPU::getCanBeVOPD(Opc); 141753f127fSDimitry Andric llvm::AMDGPU::CanBeVOPD SecondCanBeVOPD = AMDGPU::getCanBeVOPD(Opc2); 142*06c3fb27SDimitry Andric VOPDCombineInfo CI; 143753f127fSDimitry Andric 144753f127fSDimitry Andric if (FirstCanBeVOPD.X && SecondCanBeVOPD.Y) 145*06c3fb27SDimitry Andric CI = VOPDCombineInfo(FirstMI, SecondMI); 146753f127fSDimitry Andric else if (FirstCanBeVOPD.Y && SecondCanBeVOPD.X) 147*06c3fb27SDimitry Andric CI = VOPDCombineInfo(SecondMI, FirstMI); 148753f127fSDimitry Andric else 149753f127fSDimitry Andric continue; 150753f127fSDimitry Andric // checkVOPDRegConstraints cares about program order, but doReplace 151753f127fSDimitry Andric // cares about X-Y order in the constituted VOPD 152753f127fSDimitry Andric if (llvm::checkVOPDRegConstraints(*SII, *FirstMI, *SecondMI)) { 153*06c3fb27SDimitry Andric ReplaceCandidates.push_back(CI); 154753f127fSDimitry Andric ++MII; 155753f127fSDimitry Andric } 156753f127fSDimitry Andric } 157753f127fSDimitry Andric } 158*06c3fb27SDimitry Andric for (auto &CI : ReplaceCandidates) { 159*06c3fb27SDimitry Andric Changed |= doReplace(SII, CI); 160753f127fSDimitry Andric } 161753f127fSDimitry Andric 162753f127fSDimitry Andric return Changed; 163753f127fSDimitry Andric } 164753f127fSDimitry Andric }; 165753f127fSDimitry Andric 166753f127fSDimitry Andric } // namespace 167753f127fSDimitry Andric 168753f127fSDimitry Andric char GCNCreateVOPD::ID = 0; 169753f127fSDimitry Andric 170753f127fSDimitry Andric char &llvm::GCNCreateVOPDID = GCNCreateVOPD::ID; 171753f127fSDimitry Andric 172753f127fSDimitry Andric INITIALIZE_PASS(GCNCreateVOPD, DEBUG_TYPE, "GCN Create VOPD Instructions", 173753f127fSDimitry Andric false, false) 174