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