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