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