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