xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/AMDGPU/GCNCreateVOPD.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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