1 //===- GCNCreateVOPD.cpp - Create VOPD Instructions ----------------------===//
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
7 //===----------------------------------------------------------------------===//
10 /// Combine VALU pairs into VOPD instructions
11 /// Only works on wave32
12 /// Has register requirements, we reject creating VOPD if the requirements are
14 /// shouldCombineVOPD mutator in postRA machine scheduler puts candidate
15 /// instructions for VOPD back-to-back
18 //===----------------------------------------------------------------------===//
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"
35 #define DEBUG_TYPE "gcn-create-vopd"
36 STATISTIC(NumVOPDCreated
, "Number of VOPD Insts Created.");
42 class GCNCreateVOPD
: public MachineFunctionPass
{
44 class VOPDCombineInfo
{
46 VOPDCombineInfo() = default;
47 VOPDCombineInfo(MachineInstr
*First
, MachineInstr
*Second
)
48 : FirstMI(First
), SecondMI(Second
) {}
50 MachineInstr
*FirstMI
;
51 MachineInstr
*SecondMI
;
56 const GCNSubtarget
*ST
= nullptr;
58 GCNCreateVOPD() : MachineFunctionPass(ID
) {}
60 void getAnalysisUsage(AnalysisUsage
&AU
) const override
{
62 MachineFunctionPass::getAnalysisUsage(AU
);
65 StringRef
getPassName() const override
{
66 return "GCN Create VOPD Instructions";
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(SII
->getSubtarget());
77 AMDGPU::getVOPDFull(AMDGPU::getVOPDOpcode(Opc1
),
78 AMDGPU::getVOPDOpcode(Opc2
), EncodingFamily
);
79 assert(NewOpcode
!= -1 &&
80 "Should have previously determined this as a possible VOPD\n");
82 auto VOPDInst
= BuildMI(*FirstMI
->getParent(), FirstMI
,
83 FirstMI
->getDebugLoc(), SII
->get(NewOpcode
))
84 .setMIFlags(FirstMI
->getFlags() | SecondMI
->getFlags());
86 namespace VOPD
= AMDGPU::VOPD
;
87 MachineInstr
*MI
[] = {FirstMI
, SecondMI
};
89 AMDGPU::getVOPDInstInfo(FirstMI
->getDesc(), SecondMI
->getDesc());
91 for (auto CompIdx
: VOPD::COMPONENTS
) {
92 auto MCOprIdx
= InstInfo
[CompIdx
].getIndexOfDstInMCOperands();
93 VOPDInst
.add(MI
[CompIdx
]->getOperand(MCOprIdx
));
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(MI
[CompIdx
]->getOperand(MCOprIdx
));
104 SII
->fixImplicitOperands(*VOPDInst
);
105 for (auto CompIdx
: VOPD::COMPONENTS
)
106 VOPDInst
.copyImplicitOps(*MI
[CompIdx
]);
108 LLVM_DEBUG(dbgs() << "VOPD Fused: " << *VOPDInst
<< " from\tX: "
109 << *CI
.FirstMI
<< "\tY: " << *CI
.SecondMI
<< "\n");
111 for (auto CompIdx
: VOPD::COMPONENTS
)
112 MI
[CompIdx
]->eraseFromParent();
118 bool runOnMachineFunction(MachineFunction
&MF
) override
{
119 if (skipFunction(MF
.getFunction()))
121 ST
= &MF
.getSubtarget
<GCNSubtarget
>();
122 if (!AMDGPU::hasVOPD(*ST
) || !ST
->isWave32())
124 LLVM_DEBUG(dbgs() << "CreateVOPD Pass:\n");
126 const SIInstrInfo
*SII
= ST
->getInstrInfo();
127 bool Changed
= false;
129 SmallVector
<VOPDCombineInfo
> ReplaceCandidates
;
131 for (auto &MBB
: MF
) {
132 auto MII
= MBB
.begin(), E
= MBB
.end();
134 auto *FirstMI
= &*MII
;
135 MII
= next_nodbg(MII
, MBB
.end());
136 if (MII
== MBB
.end())
138 if (FirstMI
->isDebugInstr())
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(Opc2
);
147 if (FirstCanBeVOPD
.X
&& SecondCanBeVOPD
.Y
)
148 CI
= VOPDCombineInfo(FirstMI
, SecondMI
);
149 else if (FirstCanBeVOPD
.Y
&& SecondCanBeVOPD
.X
)
150 CI
= VOPDCombineInfo(SecondMI
, FirstMI
);
153 // checkVOPDRegConstraints cares about program order, but doReplace
154 // cares about X-Y order in the constituted VOPD
155 if (llvm::checkVOPDRegConstraints(*SII
, *FirstMI
, *SecondMI
)) {
156 ReplaceCandidates
.push_back(CI
);
161 for (auto &CI
: ReplaceCandidates
) {
162 Changed
|= doReplace(SII
, CI
);
171 char GCNCreateVOPD::ID
= 0;
173 char &llvm::GCNCreateVOPDID
= GCNCreateVOPD::ID
;
175 INITIALIZE_PASS(GCNCreateVOPD
, DEBUG_TYPE
, "GCN Create VOPD Instructions",