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/CodeGen/MachineBasicBlock.h" 29753f127fSDimitry Andric #include "llvm/CodeGen/MachineInstr.h" 30753f127fSDimitry Andric #include "llvm/CodeGen/MachineOperand.h" 31753f127fSDimitry Andric #include "llvm/Support/Casting.h" 32753f127fSDimitry Andric #include "llvm/Support/Debug.h" 33753f127fSDimitry Andric #include <utility> 34753f127fSDimitry Andric 35753f127fSDimitry Andric #define DEBUG_TYPE "gcn-create-vopd" 36753f127fSDimitry Andric STATISTIC(NumVOPDCreated, "Number of VOPD Insts Created."); 37753f127fSDimitry Andric 38753f127fSDimitry Andric using namespace llvm; 39753f127fSDimitry Andric 40753f127fSDimitry Andric namespace { 41753f127fSDimitry Andric 42753f127fSDimitry Andric class GCNCreateVOPD : public MachineFunctionPass { 43753f127fSDimitry Andric private: 4406c3fb27SDimitry Andric class VOPDCombineInfo { 4506c3fb27SDimitry Andric public: 46*0fca6ea1SDimitry Andric VOPDCombineInfo() = default; 4706c3fb27SDimitry Andric VOPDCombineInfo(MachineInstr *First, MachineInstr *Second) 4806c3fb27SDimitry Andric : FirstMI(First), SecondMI(Second) {} 4906c3fb27SDimitry Andric 5006c3fb27SDimitry Andric MachineInstr *FirstMI; 5106c3fb27SDimitry Andric MachineInstr *SecondMI; 5206c3fb27SDimitry Andric }; 5306c3fb27SDimitry Andric 54753f127fSDimitry Andric public: 55753f127fSDimitry Andric static char ID; 56753f127fSDimitry Andric const GCNSubtarget *ST = nullptr; 57753f127fSDimitry Andric 58753f127fSDimitry Andric GCNCreateVOPD() : MachineFunctionPass(ID) {} 59753f127fSDimitry Andric 60753f127fSDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 61753f127fSDimitry Andric AU.setPreservesCFG(); 62753f127fSDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 63753f127fSDimitry Andric } 64753f127fSDimitry Andric 65753f127fSDimitry Andric StringRef getPassName() const override { 66753f127fSDimitry Andric return "GCN Create VOPD Instructions"; 67753f127fSDimitry Andric } 68753f127fSDimitry Andric 6906c3fb27SDimitry Andric bool doReplace(const SIInstrInfo *SII, VOPDCombineInfo &CI) { 7006c3fb27SDimitry Andric auto *FirstMI = CI.FirstMI; 7106c3fb27SDimitry Andric auto *SecondMI = CI.SecondMI; 72753f127fSDimitry Andric unsigned Opc1 = FirstMI->getOpcode(); 73753f127fSDimitry Andric unsigned Opc2 = SecondMI->getOpcode(); 745f757f3fSDimitry Andric unsigned EncodingFamily = 755f757f3fSDimitry Andric AMDGPU::getVOPDEncodingFamily(SII->getSubtarget()); 765f757f3fSDimitry Andric int NewOpcode = 775f757f3fSDimitry Andric AMDGPU::getVOPDFull(AMDGPU::getVOPDOpcode(Opc1), 785f757f3fSDimitry Andric AMDGPU::getVOPDOpcode(Opc2), EncodingFamily); 79753f127fSDimitry Andric assert(NewOpcode != -1 && 80753f127fSDimitry Andric "Should have previously determined this as a possible VOPD\n"); 81753f127fSDimitry Andric 82753f127fSDimitry Andric auto VOPDInst = BuildMI(*FirstMI->getParent(), FirstMI, 83753f127fSDimitry Andric FirstMI->getDebugLoc(), SII->get(NewOpcode)) 84753f127fSDimitry Andric .setMIFlags(FirstMI->getFlags() | SecondMI->getFlags()); 85753f127fSDimitry Andric 86bdd1243dSDimitry Andric namespace VOPD = AMDGPU::VOPD; 87bdd1243dSDimitry Andric MachineInstr *MI[] = {FirstMI, SecondMI}; 88bdd1243dSDimitry Andric auto InstInfo = 89bdd1243dSDimitry Andric AMDGPU::getVOPDInstInfo(FirstMI->getDesc(), SecondMI->getDesc()); 90bdd1243dSDimitry Andric 91bdd1243dSDimitry Andric for (auto CompIdx : VOPD::COMPONENTS) { 92bdd1243dSDimitry Andric auto MCOprIdx = InstInfo[CompIdx].getIndexOfDstInMCOperands(); 93bdd1243dSDimitry Andric VOPDInst.add(MI[CompIdx]->getOperand(MCOprIdx)); 94753f127fSDimitry Andric } 95753f127fSDimitry Andric 96bdd1243dSDimitry Andric for (auto CompIdx : VOPD::COMPONENTS) { 97bdd1243dSDimitry Andric auto CompSrcOprNum = InstInfo[CompIdx].getCompSrcOperandsNum(); 98bdd1243dSDimitry Andric for (unsigned CompSrcIdx = 0; CompSrcIdx < CompSrcOprNum; ++CompSrcIdx) { 99bdd1243dSDimitry Andric auto MCOprIdx = InstInfo[CompIdx].getIndexOfSrcInMCOperands(CompSrcIdx); 100bdd1243dSDimitry Andric VOPDInst.add(MI[CompIdx]->getOperand(MCOprIdx)); 101bdd1243dSDimitry Andric } 102753f127fSDimitry Andric } 103753f127fSDimitry Andric 104*0fca6ea1SDimitry Andric SII->fixImplicitOperands(*VOPDInst); 105bdd1243dSDimitry Andric for (auto CompIdx : VOPD::COMPONENTS) 106bdd1243dSDimitry Andric VOPDInst.copyImplicitOps(*MI[CompIdx]); 107753f127fSDimitry Andric 108753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "VOPD Fused: " << *VOPDInst << " from\tX: " 10906c3fb27SDimitry Andric << *CI.FirstMI << "\tY: " << *CI.SecondMI << "\n"); 110bdd1243dSDimitry Andric 111bdd1243dSDimitry Andric for (auto CompIdx : VOPD::COMPONENTS) 112bdd1243dSDimitry Andric MI[CompIdx]->eraseFromParent(); 113bdd1243dSDimitry Andric 114753f127fSDimitry Andric ++NumVOPDCreated; 115753f127fSDimitry Andric return true; 116753f127fSDimitry Andric } 117753f127fSDimitry Andric 118753f127fSDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override { 119753f127fSDimitry Andric if (skipFunction(MF.getFunction())) 120753f127fSDimitry Andric return false; 121753f127fSDimitry Andric ST = &MF.getSubtarget<GCNSubtarget>(); 122753f127fSDimitry Andric if (!AMDGPU::hasVOPD(*ST) || !ST->isWave32()) 123753f127fSDimitry Andric return false; 124753f127fSDimitry Andric LLVM_DEBUG(dbgs() << "CreateVOPD Pass:\n"); 125753f127fSDimitry Andric 126753f127fSDimitry Andric const SIInstrInfo *SII = ST->getInstrInfo(); 127753f127fSDimitry Andric bool Changed = false; 128753f127fSDimitry Andric 12906c3fb27SDimitry Andric SmallVector<VOPDCombineInfo> ReplaceCandidates; 130753f127fSDimitry Andric 131753f127fSDimitry Andric for (auto &MBB : MF) { 132753f127fSDimitry Andric auto MII = MBB.begin(), E = MBB.end(); 133753f127fSDimitry Andric while (MII != E) { 134753f127fSDimitry Andric auto *FirstMI = &*MII; 135753f127fSDimitry Andric MII = next_nodbg(MII, MBB.end()); 136753f127fSDimitry Andric if (MII == MBB.end()) 137753f127fSDimitry Andric break; 138753f127fSDimitry Andric if (FirstMI->isDebugInstr()) 139753f127fSDimitry Andric continue; 140753f127fSDimitry Andric auto *SecondMI = &*MII; 141753f127fSDimitry Andric unsigned Opc = FirstMI->getOpcode(); 142753f127fSDimitry Andric unsigned Opc2 = SecondMI->getOpcode(); 143753f127fSDimitry Andric llvm::AMDGPU::CanBeVOPD FirstCanBeVOPD = AMDGPU::getCanBeVOPD(Opc); 144753f127fSDimitry Andric llvm::AMDGPU::CanBeVOPD SecondCanBeVOPD = AMDGPU::getCanBeVOPD(Opc2); 14506c3fb27SDimitry Andric VOPDCombineInfo CI; 146753f127fSDimitry Andric 147753f127fSDimitry Andric if (FirstCanBeVOPD.X && SecondCanBeVOPD.Y) 14806c3fb27SDimitry Andric CI = VOPDCombineInfo(FirstMI, SecondMI); 149753f127fSDimitry Andric else if (FirstCanBeVOPD.Y && SecondCanBeVOPD.X) 15006c3fb27SDimitry Andric CI = VOPDCombineInfo(SecondMI, FirstMI); 151753f127fSDimitry Andric else 152753f127fSDimitry Andric continue; 153753f127fSDimitry Andric // checkVOPDRegConstraints cares about program order, but doReplace 154753f127fSDimitry Andric // cares about X-Y order in the constituted VOPD 155753f127fSDimitry Andric if (llvm::checkVOPDRegConstraints(*SII, *FirstMI, *SecondMI)) { 15606c3fb27SDimitry Andric ReplaceCandidates.push_back(CI); 157753f127fSDimitry Andric ++MII; 158753f127fSDimitry Andric } 159753f127fSDimitry Andric } 160753f127fSDimitry Andric } 16106c3fb27SDimitry Andric for (auto &CI : ReplaceCandidates) { 16206c3fb27SDimitry Andric Changed |= doReplace(SII, CI); 163753f127fSDimitry Andric } 164753f127fSDimitry Andric 165753f127fSDimitry Andric return Changed; 166753f127fSDimitry Andric } 167753f127fSDimitry Andric }; 168753f127fSDimitry Andric 169753f127fSDimitry Andric } // namespace 170753f127fSDimitry Andric 171753f127fSDimitry Andric char GCNCreateVOPD::ID = 0; 172753f127fSDimitry Andric 173753f127fSDimitry Andric char &llvm::GCNCreateVOPDID = GCNCreateVOPD::ID; 174753f127fSDimitry Andric 175753f127fSDimitry Andric INITIALIZE_PASS(GCNCreateVOPD, DEBUG_TYPE, "GCN Create VOPD Instructions", 176753f127fSDimitry Andric false, false) 177