1 | //===- GCNCreateVOPD.cpp - Create VOPD Instructions ----------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | /// \file |
10 | /// Combine VALU pairs into VOPD instructions |
11 | /// Only works on wave32 |
12 | /// Has register requirements, we reject creating VOPD if the requirements are |
13 | /// not met. |
14 | /// shouldCombineVOPD mutator in postRA machine scheduler puts candidate |
15 | /// instructions for VOPD back-to-back |
16 | /// |
17 | // |
18 | //===----------------------------------------------------------------------===// |
19 | |
20 | #include "AMDGPU.h" |
21 | #include "GCNSubtarget.h" |
22 | #include "GCNVOPDUtils.h" |
23 | #include "MCTargetDesc/AMDGPUMCTargetDesc.h" |
24 | #include "SIInstrInfo.h" |
25 | #include "Utils/AMDGPUBaseInfo.h" |
26 | #include "llvm/ADT/SmallVector.h" |
27 | #include "llvm/ADT/Statistic.h" |
28 | #include "llvm/CodeGen/MachineBasicBlock.h" |
29 | #include "llvm/CodeGen/MachineInstr.h" |
30 | #include "llvm/CodeGen/MachineOperand.h" |
31 | #include "llvm/Support/Casting.h" |
32 | #include "llvm/Support/Debug.h" |
33 | #include <utility> |
34 | |
35 | #define DEBUG_TYPE "gcn-create-vopd" |
36 | STATISTIC(NumVOPDCreated, "Number of VOPD Insts Created." ); |
37 | |
38 | using namespace llvm; |
39 | |
40 | namespace { |
41 | |
42 | class GCNCreateVOPD : public MachineFunctionPass { |
43 | private: |
44 | class VOPDCombineInfo { |
45 | public: |
46 | VOPDCombineInfo() = default; |
47 | VOPDCombineInfo(MachineInstr *First, MachineInstr *Second) |
48 | : FirstMI(First), SecondMI(Second) {} |
49 | |
50 | MachineInstr *FirstMI; |
51 | MachineInstr *SecondMI; |
52 | }; |
53 | |
54 | public: |
55 | static char ID; |
56 | const GCNSubtarget *ST = nullptr; |
57 | |
58 | GCNCreateVOPD() : MachineFunctionPass(ID) {} |
59 | |
60 | void getAnalysisUsage(AnalysisUsage &AU) const override { |
61 | AU.setPreservesCFG(); |
62 | MachineFunctionPass::getAnalysisUsage(AU); |
63 | } |
64 | |
65 | StringRef getPassName() const override { |
66 | return "GCN Create VOPD Instructions" ; |
67 | } |
68 | |
69 | bool doReplace(const SIInstrInfo *SII, VOPDCombineInfo &CI) { |
70 | auto *FirstMI = CI.FirstMI; |
71 | auto *SecondMI = CI.SecondMI; |
72 | unsigned Opc1 = FirstMI->getOpcode(); |
73 | unsigned Opc2 = SecondMI->getOpcode(); |
74 | unsigned EncodingFamily = |
75 | AMDGPU::getVOPDEncodingFamily(ST: SII->getSubtarget()); |
76 | int NewOpcode = |
77 | AMDGPU::getVOPDFull(OpX: AMDGPU::getVOPDOpcode(Opc: Opc1), |
78 | OpY: AMDGPU::getVOPDOpcode(Opc: Opc2), EncodingFamily); |
79 | assert(NewOpcode != -1 && |
80 | "Should have previously determined this as a possible VOPD\n" ); |
81 | |
82 | auto VOPDInst = BuildMI(BB&: *FirstMI->getParent(), I: FirstMI, |
83 | MIMD: FirstMI->getDebugLoc(), MCID: SII->get(Opcode: NewOpcode)) |
84 | .setMIFlags(FirstMI->getFlags() | SecondMI->getFlags()); |
85 | |
86 | namespace VOPD = AMDGPU::VOPD; |
87 | MachineInstr *MI[] = {FirstMI, SecondMI}; |
88 | auto InstInfo = |
89 | AMDGPU::getVOPDInstInfo(OpX: FirstMI->getDesc(), OpY: SecondMI->getDesc()); |
90 | |
91 | for (auto CompIdx : VOPD::COMPONENTS) { |
92 | auto MCOprIdx = InstInfo[CompIdx].getIndexOfDstInMCOperands(); |
93 | VOPDInst.add(MO: MI[CompIdx]->getOperand(i: MCOprIdx)); |
94 | } |
95 | |
96 | for (auto CompIdx : VOPD::COMPONENTS) { |
97 | auto CompSrcOprNum = InstInfo[CompIdx].getCompSrcOperandsNum(); |
98 | for (unsigned CompSrcIdx = 0; CompSrcIdx < CompSrcOprNum; ++CompSrcIdx) { |
99 | auto MCOprIdx = InstInfo[CompIdx].getIndexOfSrcInMCOperands(CompSrcIdx); |
100 | VOPDInst.add(MO: MI[CompIdx]->getOperand(i: MCOprIdx)); |
101 | } |
102 | } |
103 | |
104 | SII->fixImplicitOperands(MI&: *VOPDInst); |
105 | for (auto CompIdx : VOPD::COMPONENTS) |
106 | VOPDInst.copyImplicitOps(OtherMI: *MI[CompIdx]); |
107 | |
108 | LLVM_DEBUG(dbgs() << "VOPD Fused: " << *VOPDInst << " from\tX: " |
109 | << *CI.FirstMI << "\tY: " << *CI.SecondMI << "\n" ); |
110 | |
111 | for (auto CompIdx : VOPD::COMPONENTS) |
112 | MI[CompIdx]->eraseFromParent(); |
113 | |
114 | ++NumVOPDCreated; |
115 | return true; |
116 | } |
117 | |
118 | bool runOnMachineFunction(MachineFunction &MF) override { |
119 | if (skipFunction(F: MF.getFunction())) |
120 | return false; |
121 | ST = &MF.getSubtarget<GCNSubtarget>(); |
122 | if (!AMDGPU::hasVOPD(STI: *ST) || !ST->isWave32()) |
123 | return false; |
124 | LLVM_DEBUG(dbgs() << "CreateVOPD Pass:\n" ); |
125 | |
126 | const SIInstrInfo *SII = ST->getInstrInfo(); |
127 | bool Changed = false; |
128 | |
129 | SmallVector<VOPDCombineInfo> ReplaceCandidates; |
130 | |
131 | for (auto &MBB : MF) { |
132 | auto MII = MBB.begin(), E = MBB.end(); |
133 | while (MII != E) { |
134 | auto *FirstMI = &*MII; |
135 | MII = next_nodbg(It: MII, End: MBB.end()); |
136 | if (MII == MBB.end()) |
137 | break; |
138 | if (FirstMI->isDebugInstr()) |
139 | continue; |
140 | auto *SecondMI = &*MII; |
141 | unsigned Opc = FirstMI->getOpcode(); |
142 | unsigned Opc2 = SecondMI->getOpcode(); |
143 | llvm::AMDGPU::CanBeVOPD FirstCanBeVOPD = AMDGPU::getCanBeVOPD(Opc); |
144 | llvm::AMDGPU::CanBeVOPD SecondCanBeVOPD = AMDGPU::getCanBeVOPD(Opc: Opc2); |
145 | VOPDCombineInfo CI; |
146 | |
147 | if (FirstCanBeVOPD.X && SecondCanBeVOPD.Y) |
148 | CI = VOPDCombineInfo(FirstMI, SecondMI); |
149 | else if (FirstCanBeVOPD.Y && SecondCanBeVOPD.X) |
150 | CI = VOPDCombineInfo(SecondMI, FirstMI); |
151 | else |
152 | continue; |
153 | // checkVOPDRegConstraints cares about program order, but doReplace |
154 | // cares about X-Y order in the constituted VOPD |
155 | if (llvm::checkVOPDRegConstraints(TII: *SII, FirstMI: *FirstMI, SecondMI: *SecondMI)) { |
156 | ReplaceCandidates.push_back(Elt: CI); |
157 | ++MII; |
158 | } |
159 | } |
160 | } |
161 | for (auto &CI : ReplaceCandidates) { |
162 | Changed |= doReplace(SII, CI); |
163 | } |
164 | |
165 | return Changed; |
166 | } |
167 | }; |
168 | |
169 | } // namespace |
170 | |
171 | char GCNCreateVOPD::ID = 0; |
172 | |
173 | char &llvm::GCNCreateVOPDID = GCNCreateVOPD::ID; |
174 | |
175 | INITIALIZE_PASS(GCNCreateVOPD, DEBUG_TYPE, "GCN Create VOPD Instructions" , |
176 | false, false) |
177 | |