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