1 //===-- R600ClauseMergePass - Merge consecutive CF_ALU -------------------===//
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 /// R600EmitClauseMarker pass emits CFAlu instruction in a conservative manner.
11 /// This pass is merging consecutive CFAlus where applicable.
12 /// It needs to be called after IfCvt for best results.
13 //===----------------------------------------------------------------------===//
14
15 #include "MCTargetDesc/R600MCTargetDesc.h"
16 #include "R600.h"
17 #include "R600Subtarget.h"
18 #include "llvm/CodeGen/MachineFunctionPass.h"
19
20 using namespace llvm;
21
22 #define DEBUG_TYPE "r600mergeclause"
23
24 namespace {
25
isCFAlu(const MachineInstr & MI)26 static bool isCFAlu(const MachineInstr &MI) {
27 switch (MI.getOpcode()) {
28 case R600::CF_ALU:
29 case R600::CF_ALU_PUSH_BEFORE:
30 return true;
31 default:
32 return false;
33 }
34 }
35
36 class R600ClauseMergePass : public MachineFunctionPass {
37
38 private:
39 const R600InstrInfo *TII;
40
41 unsigned getCFAluSize(const MachineInstr &MI) const;
42 bool isCFAluEnabled(const MachineInstr &MI) const;
43
44 /// IfCvt pass can generate "disabled" ALU clause marker that need to be
45 /// removed and their content affected to the previous alu clause.
46 /// This function parse instructions after CFAlu until it find a disabled
47 /// CFAlu and merge the content, or an enabled CFAlu.
48 void cleanPotentialDisabledCFAlu(MachineInstr &CFAlu) const;
49
50 /// Check whether LatrCFAlu can be merged into RootCFAlu and do it if
51 /// it is the case.
52 bool mergeIfPossible(MachineInstr &RootCFAlu,
53 const MachineInstr &LatrCFAlu) const;
54
55 public:
56 static char ID;
57
R600ClauseMergePass()58 R600ClauseMergePass() : MachineFunctionPass(ID) { }
59
60 bool runOnMachineFunction(MachineFunction &MF) override;
61
62 StringRef getPassName() const override;
63 };
64
65 } // end anonymous namespace
66
67 INITIALIZE_PASS_BEGIN(R600ClauseMergePass, DEBUG_TYPE,
68 "R600 Clause Merge", false, false)
69 INITIALIZE_PASS_END(R600ClauseMergePass, DEBUG_TYPE,
70 "R600 Clause Merge", false, false)
71
72 char R600ClauseMergePass::ID = 0;
73
74 char &llvm::R600ClauseMergePassID = R600ClauseMergePass::ID;
75
getCFAluSize(const MachineInstr & MI) const76 unsigned R600ClauseMergePass::getCFAluSize(const MachineInstr &MI) const {
77 assert(isCFAlu(MI));
78 return MI
79 .getOperand(TII->getOperandIdx(MI.getOpcode(), R600::OpName::COUNT))
80 .getImm();
81 }
82
isCFAluEnabled(const MachineInstr & MI) const83 bool R600ClauseMergePass::isCFAluEnabled(const MachineInstr &MI) const {
84 assert(isCFAlu(MI));
85 return MI
86 .getOperand(TII->getOperandIdx(MI.getOpcode(), R600::OpName::Enabled))
87 .getImm();
88 }
89
cleanPotentialDisabledCFAlu(MachineInstr & CFAlu) const90 void R600ClauseMergePass::cleanPotentialDisabledCFAlu(
91 MachineInstr &CFAlu) const {
92 int CntIdx = TII->getOperandIdx(R600::CF_ALU, R600::OpName::COUNT);
93 MachineBasicBlock::iterator I = CFAlu, E = CFAlu.getParent()->end();
94 I++;
95 do {
96 while (I != E && !isCFAlu(*I))
97 I++;
98 if (I == E)
99 return;
100 MachineInstr &MI = *I++;
101 if (isCFAluEnabled(MI))
102 break;
103 CFAlu.getOperand(CntIdx).setImm(getCFAluSize(CFAlu) + getCFAluSize(MI));
104 MI.eraseFromParent();
105 } while (I != E);
106 }
107
mergeIfPossible(MachineInstr & RootCFAlu,const MachineInstr & LatrCFAlu) const108 bool R600ClauseMergePass::mergeIfPossible(MachineInstr &RootCFAlu,
109 const MachineInstr &LatrCFAlu) const {
110 assert(isCFAlu(RootCFAlu) && isCFAlu(LatrCFAlu));
111 int CntIdx = TII->getOperandIdx(R600::CF_ALU, R600::OpName::COUNT);
112 unsigned RootInstCount = getCFAluSize(RootCFAlu),
113 LaterInstCount = getCFAluSize(LatrCFAlu);
114 unsigned CumuledInsts = RootInstCount + LaterInstCount;
115 if (CumuledInsts >= TII->getMaxAlusPerClause()) {
116 LLVM_DEBUG(dbgs() << "Excess inst counts\n");
117 return false;
118 }
119 if (RootCFAlu.getOpcode() == R600::CF_ALU_PUSH_BEFORE)
120 return false;
121 // Is KCache Bank 0 compatible ?
122 int Mode0Idx =
123 TII->getOperandIdx(R600::CF_ALU, R600::OpName::KCACHE_MODE0);
124 int KBank0Idx =
125 TII->getOperandIdx(R600::CF_ALU, R600::OpName::KCACHE_BANK0);
126 int KBank0LineIdx =
127 TII->getOperandIdx(R600::CF_ALU, R600::OpName::KCACHE_ADDR0);
128 if (LatrCFAlu.getOperand(Mode0Idx).getImm() &&
129 RootCFAlu.getOperand(Mode0Idx).getImm() &&
130 (LatrCFAlu.getOperand(KBank0Idx).getImm() !=
131 RootCFAlu.getOperand(KBank0Idx).getImm() ||
132 LatrCFAlu.getOperand(KBank0LineIdx).getImm() !=
133 RootCFAlu.getOperand(KBank0LineIdx).getImm())) {
134 LLVM_DEBUG(dbgs() << "Wrong KC0\n");
135 return false;
136 }
137 // Is KCache Bank 1 compatible ?
138 int Mode1Idx =
139 TII->getOperandIdx(R600::CF_ALU, R600::OpName::KCACHE_MODE1);
140 int KBank1Idx =
141 TII->getOperandIdx(R600::CF_ALU, R600::OpName::KCACHE_BANK1);
142 int KBank1LineIdx =
143 TII->getOperandIdx(R600::CF_ALU, R600::OpName::KCACHE_ADDR1);
144 if (LatrCFAlu.getOperand(Mode1Idx).getImm() &&
145 RootCFAlu.getOperand(Mode1Idx).getImm() &&
146 (LatrCFAlu.getOperand(KBank1Idx).getImm() !=
147 RootCFAlu.getOperand(KBank1Idx).getImm() ||
148 LatrCFAlu.getOperand(KBank1LineIdx).getImm() !=
149 RootCFAlu.getOperand(KBank1LineIdx).getImm())) {
150 LLVM_DEBUG(dbgs() << "Wrong KC0\n");
151 return false;
152 }
153 if (LatrCFAlu.getOperand(Mode0Idx).getImm()) {
154 RootCFAlu.getOperand(Mode0Idx).setImm(
155 LatrCFAlu.getOperand(Mode0Idx).getImm());
156 RootCFAlu.getOperand(KBank0Idx).setImm(
157 LatrCFAlu.getOperand(KBank0Idx).getImm());
158 RootCFAlu.getOperand(KBank0LineIdx)
159 .setImm(LatrCFAlu.getOperand(KBank0LineIdx).getImm());
160 }
161 if (LatrCFAlu.getOperand(Mode1Idx).getImm()) {
162 RootCFAlu.getOperand(Mode1Idx).setImm(
163 LatrCFAlu.getOperand(Mode1Idx).getImm());
164 RootCFAlu.getOperand(KBank1Idx).setImm(
165 LatrCFAlu.getOperand(KBank1Idx).getImm());
166 RootCFAlu.getOperand(KBank1LineIdx)
167 .setImm(LatrCFAlu.getOperand(KBank1LineIdx).getImm());
168 }
169 RootCFAlu.getOperand(CntIdx).setImm(CumuledInsts);
170 RootCFAlu.setDesc(TII->get(LatrCFAlu.getOpcode()));
171 return true;
172 }
173
runOnMachineFunction(MachineFunction & MF)174 bool R600ClauseMergePass::runOnMachineFunction(MachineFunction &MF) {
175 if (skipFunction(MF.getFunction()))
176 return false;
177
178 const R600Subtarget &ST = MF.getSubtarget<R600Subtarget>();
179 TII = ST.getInstrInfo();
180
181 for (MachineBasicBlock &MBB : MF) {
182 MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end();
183 MachineBasicBlock::iterator LatestCFAlu = E;
184 while (I != E) {
185 MachineInstr &MI = *I++;
186 if ((!TII->canBeConsideredALU(MI) && !isCFAlu(MI)) ||
187 TII->mustBeLastInClause(MI.getOpcode()))
188 LatestCFAlu = E;
189 if (!isCFAlu(MI))
190 continue;
191 cleanPotentialDisabledCFAlu(MI);
192
193 if (LatestCFAlu != E && mergeIfPossible(*LatestCFAlu, MI)) {
194 MI.eraseFromParent();
195 } else {
196 assert(MI.getOperand(8).getImm() && "CF ALU instruction disabled");
197 LatestCFAlu = MI;
198 }
199 }
200 }
201 return false;
202 }
203
getPassName() const204 StringRef R600ClauseMergePass::getPassName() const {
205 return "R600 Merge Clause Markers Pass";
206 }
207
createR600ClauseMergePass()208 llvm::FunctionPass *llvm::createR600ClauseMergePass() {
209 return new R600ClauseMergePass();
210 }
211