R600: Add VTX_READ_* and RAT_WRITE_CACHELESS_* when computing cf addr
[oota-llvm.git] / lib / Target / R600 / R600ControlFlowFinalizer.cpp
1 //===-- R600ControlFlowFinalizer.cpp - Finalize Control Flow Inst----------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 /// \file
11 /// This pass compute turns all control flow pseudo instructions into native one
12 /// computing their address on the fly ; it also sets STACK_SIZE info.
13 //===----------------------------------------------------------------------===//
14
15 #define DEBUG_TYPE "r600cf"
16 #include "llvm/Support/Debug.h"
17 #include "llvm/Support/raw_ostream.h"
18
19 #include "AMDGPU.h"
20 #include "R600Defines.h"
21 #include "R600InstrInfo.h"
22 #include "R600MachineFunctionInfo.h"
23 #include "R600RegisterInfo.h"
24 #include "llvm/CodeGen/MachineFunctionPass.h"
25 #include "llvm/CodeGen/MachineInstrBuilder.h"
26 #include "llvm/CodeGen/MachineRegisterInfo.h"
27
28 namespace llvm {
29
30 class R600ControlFlowFinalizer : public MachineFunctionPass {
31
32 private:
33   enum ControlFlowInstruction {
34     CF_TC,
35     CF_CALL_FS,
36     CF_WHILE_LOOP,
37     CF_END_LOOP,
38     CF_LOOP_BREAK,
39     CF_LOOP_CONTINUE,
40     CF_JUMP,
41     CF_ELSE,
42     CF_POP
43   };
44   
45   static char ID;
46   const R600InstrInfo *TII;
47   unsigned MaxFetchInst;
48   const AMDGPUSubtarget &ST;
49
50   bool isFetch(const MachineInstr *MI) const {
51     switch (MI->getOpcode()) {
52     case AMDGPU::TEX_VTX_CONSTBUF:
53     case AMDGPU::TEX_VTX_TEXBUF:
54     case AMDGPU::TEX_LD:
55     case AMDGPU::TEX_GET_TEXTURE_RESINFO:
56     case AMDGPU::TEX_GET_GRADIENTS_H:
57     case AMDGPU::TEX_GET_GRADIENTS_V:
58     case AMDGPU::TEX_SET_GRADIENTS_H:
59     case AMDGPU::TEX_SET_GRADIENTS_V:
60     case AMDGPU::TEX_SAMPLE:
61     case AMDGPU::TEX_SAMPLE_C:
62     case AMDGPU::TEX_SAMPLE_L:
63     case AMDGPU::TEX_SAMPLE_C_L:
64     case AMDGPU::TEX_SAMPLE_LB:
65     case AMDGPU::TEX_SAMPLE_C_LB:
66     case AMDGPU::TEX_SAMPLE_G:
67     case AMDGPU::TEX_SAMPLE_C_G:
68     case AMDGPU::TXD:
69     case AMDGPU::TXD_SHADOW:
70     case AMDGPU::VTX_READ_GLOBAL_8_eg:
71     case AMDGPU::VTX_READ_GLOBAL_32_eg:
72     case AMDGPU::VTX_READ_GLOBAL_128_eg:
73     case AMDGPU::VTX_READ_PARAM_8_eg:
74     case AMDGPU::VTX_READ_PARAM_16_eg:
75     case AMDGPU::VTX_READ_PARAM_32_eg:
76     case AMDGPU::VTX_READ_PARAM_128_eg:
77      return true;
78     default:
79       return false;
80     }
81   }
82
83   bool IsTrivialInst(MachineInstr *MI) const {
84     switch (MI->getOpcode()) {
85     case AMDGPU::KILL:
86     case AMDGPU::RETURN:
87       return true;
88     default:
89       return false;
90     }
91   }
92
93   const MCInstrDesc &getHWInstrDesc(ControlFlowInstruction CFI) const {
94     if (ST.device()->getGeneration() <= AMDGPUDeviceInfo::HD4XXX) {
95       switch (CFI) {
96       case CF_TC:
97         return TII->get(AMDGPU::CF_TC_R600);
98       case CF_CALL_FS:
99         return TII->get(AMDGPU::CF_CALL_FS_R600);
100       case CF_WHILE_LOOP:
101         return TII->get(AMDGPU::WHILE_LOOP_R600);
102       case CF_END_LOOP:
103         return TII->get(AMDGPU::END_LOOP_R600);
104       case CF_LOOP_BREAK:
105         return TII->get(AMDGPU::LOOP_BREAK_R600);
106       case CF_LOOP_CONTINUE:
107         return TII->get(AMDGPU::CF_CONTINUE_R600);
108       case CF_JUMP:
109         return TII->get(AMDGPU::CF_JUMP_R600);
110       case CF_ELSE:
111         return TII->get(AMDGPU::CF_ELSE_R600);
112       case CF_POP:
113         return TII->get(AMDGPU::POP_R600);
114       }
115     } else {
116       switch (CFI) {
117       case CF_TC:
118         return TII->get(AMDGPU::CF_TC_EG);
119       case CF_CALL_FS:
120         return TII->get(AMDGPU::CF_CALL_FS_EG);
121       case CF_WHILE_LOOP:
122         return TII->get(AMDGPU::WHILE_LOOP_EG);
123       case CF_END_LOOP:
124         return TII->get(AMDGPU::END_LOOP_EG);
125       case CF_LOOP_BREAK:
126         return TII->get(AMDGPU::LOOP_BREAK_EG);
127       case CF_LOOP_CONTINUE:
128         return TII->get(AMDGPU::CF_CONTINUE_EG);
129       case CF_JUMP:
130         return TII->get(AMDGPU::CF_JUMP_EG);
131       case CF_ELSE:
132         return TII->get(AMDGPU::CF_ELSE_EG);
133       case CF_POP:
134         return TII->get(AMDGPU::POP_EG);
135       }
136     }
137   }
138
139   MachineBasicBlock::iterator
140   MakeFetchClause(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
141       unsigned CfAddress) const {
142     MachineBasicBlock::iterator ClauseHead = I;
143     unsigned AluInstCount = 0;
144     for (MachineBasicBlock::iterator E = MBB.end(); I != E; ++I) {
145       if (IsTrivialInst(I))
146         continue;
147       if (!isFetch(I))
148         break;
149       AluInstCount ++;
150       if (AluInstCount > MaxFetchInst)
151         break;
152     }
153     BuildMI(MBB, ClauseHead, MBB.findDebugLoc(ClauseHead),
154         getHWInstrDesc(CF_TC))
155         .addImm(CfAddress) // ADDR
156         .addImm(AluInstCount); // COUNT
157     return I;
158   }
159   void CounterPropagateAddr(MachineInstr *MI, unsigned Addr) const {
160     MI->getOperand(0).setImm(Addr + MI->getOperand(0).getImm());
161   }
162   void CounterPropagateAddr(std::set<MachineInstr *> MIs, unsigned Addr)
163       const {
164     for (std::set<MachineInstr *>::iterator It = MIs.begin(), E = MIs.end();
165         It != E; ++It) {
166       MachineInstr *MI = *It;
167       CounterPropagateAddr(MI, Addr);
168     }
169   }
170
171 public:
172   R600ControlFlowFinalizer(TargetMachine &tm) : MachineFunctionPass(ID),
173     TII (static_cast<const R600InstrInfo *>(tm.getInstrInfo())),
174     ST(tm.getSubtarget<AMDGPUSubtarget>()) {
175       const AMDGPUSubtarget &ST = tm.getSubtarget<AMDGPUSubtarget>();
176       if (ST.device()->getGeneration() <= AMDGPUDeviceInfo::HD4XXX)
177         MaxFetchInst = 8;
178       else
179         MaxFetchInst = 16;
180   }
181
182   virtual bool runOnMachineFunction(MachineFunction &MF) {
183     unsigned MaxStack = 0;
184     unsigned CurrentStack = 0;
185     for (MachineFunction::iterator MB = MF.begin(), ME = MF.end(); MB != ME;
186         ++MB) {
187       MachineBasicBlock &MBB = *MB;
188       unsigned CfCount = 0;
189       std::vector<std::pair<unsigned, std::set<MachineInstr *> > > LoopStack;
190       std::vector<MachineInstr * > IfThenElseStack;
191       R600MachineFunctionInfo *MFI = MF.getInfo<R600MachineFunctionInfo>();
192       if (MFI->ShaderType == 1) {
193         BuildMI(MBB, MBB.begin(), MBB.findDebugLoc(MBB.begin()),
194             getHWInstrDesc(CF_CALL_FS));
195         CfCount++;
196       }
197       for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end();
198           I != E;) {
199         if (isFetch(I)) {
200           DEBUG(dbgs() << CfCount << ":"; I->dump(););
201           I = MakeFetchClause(MBB, I, 0);
202           CfCount++;
203           continue;
204         }
205
206         MachineBasicBlock::iterator MI = I;
207         I++;
208         switch (MI->getOpcode()) {
209         case AMDGPU::CF_ALU_PUSH_BEFORE:
210           CurrentStack++;
211           MaxStack = std::max(MaxStack, CurrentStack);
212         case AMDGPU::CF_ALU:
213         case AMDGPU::EG_ExportBuf:
214         case AMDGPU::EG_ExportSwz:
215         case AMDGPU::R600_ExportBuf:
216         case AMDGPU::R600_ExportSwz:
217         case AMDGPU::RAT_WRITE_CACHELESS_32_eg:
218         case AMDGPU::RAT_WRITE_CACHELESS_128_eg:
219           DEBUG(dbgs() << CfCount << ":"; MI->dump(););
220           CfCount++;
221           break;
222         case AMDGPU::WHILELOOP: {
223           CurrentStack++;
224           MaxStack = std::max(MaxStack, CurrentStack);
225           MachineInstr *MIb = BuildMI(MBB, MI, MBB.findDebugLoc(MI),
226               getHWInstrDesc(CF_WHILE_LOOP))
227               .addImm(1);
228           std::pair<unsigned, std::set<MachineInstr *> > Pair(CfCount,
229               std::set<MachineInstr *>());
230           Pair.second.insert(MIb);
231           LoopStack.push_back(Pair);
232           MI->eraseFromParent();
233           CfCount++;
234           break;
235         }
236         case AMDGPU::ENDLOOP: {
237           CurrentStack--;
238           std::pair<unsigned, std::set<MachineInstr *> > Pair =
239               LoopStack.back();
240           LoopStack.pop_back();
241           CounterPropagateAddr(Pair.second, CfCount);
242           BuildMI(MBB, MI, MBB.findDebugLoc(MI), getHWInstrDesc(CF_END_LOOP))
243               .addImm(Pair.first + 1);
244           MI->eraseFromParent();
245           CfCount++;
246           break;
247         }
248         case AMDGPU::IF_PREDICATE_SET: {
249           MachineInstr *MIb = BuildMI(MBB, MI, MBB.findDebugLoc(MI),
250               getHWInstrDesc(CF_JUMP))
251               .addImm(0)
252               .addImm(0);
253           IfThenElseStack.push_back(MIb);
254           DEBUG(dbgs() << CfCount << ":"; MIb->dump(););
255           MI->eraseFromParent();
256           CfCount++;
257           break;
258         }
259         case AMDGPU::ELSE: {
260           MachineInstr * JumpInst = IfThenElseStack.back();
261           IfThenElseStack.pop_back();
262           CounterPropagateAddr(JumpInst, CfCount);
263           MachineInstr *MIb = BuildMI(MBB, MI, MBB.findDebugLoc(MI),
264               getHWInstrDesc(CF_ELSE))
265               .addImm(0)
266               .addImm(1);
267           DEBUG(dbgs() << CfCount << ":"; MIb->dump(););
268           IfThenElseStack.push_back(MIb);
269           MI->eraseFromParent();
270           CfCount++;
271           break;
272         }
273         case AMDGPU::ENDIF: {
274           CurrentStack--;
275           MachineInstr *IfOrElseInst = IfThenElseStack.back();
276           IfThenElseStack.pop_back();
277           CounterPropagateAddr(IfOrElseInst, CfCount + 1);
278           MachineInstr *MIb = BuildMI(MBB, MI, MBB.findDebugLoc(MI),
279               getHWInstrDesc(CF_POP))
280               .addImm(CfCount + 1)
281               .addImm(1);
282           DEBUG(dbgs() << CfCount << ":"; MIb->dump(););
283           MI->eraseFromParent();
284           CfCount++;
285           break;
286         }
287         case AMDGPU::PREDICATED_BREAK: {
288           CurrentStack--;
289           CfCount += 3;
290           BuildMI(MBB, MI, MBB.findDebugLoc(MI), getHWInstrDesc(CF_JUMP))
291               .addImm(CfCount)
292               .addImm(1);
293           MachineInstr *MIb = BuildMI(MBB, MI, MBB.findDebugLoc(MI),
294               getHWInstrDesc(CF_LOOP_BREAK))
295               .addImm(0);
296           BuildMI(MBB, MI, MBB.findDebugLoc(MI), getHWInstrDesc(CF_POP))
297               .addImm(CfCount)
298               .addImm(1);
299           LoopStack.back().second.insert(MIb);
300           MI->eraseFromParent();
301           break;
302         }
303         case AMDGPU::CONTINUE: {
304           MachineInstr *MIb = BuildMI(MBB, MI, MBB.findDebugLoc(MI),
305               getHWInstrDesc(CF_LOOP_CONTINUE))
306               .addImm(0);
307           LoopStack.back().second.insert(MIb);
308           MI->eraseFromParent();
309           CfCount++;
310           break;
311         }
312         default:
313           break;
314         }
315       }
316       BuildMI(MBB, MBB.begin(), MBB.findDebugLoc(MBB.begin()),
317           TII->get(AMDGPU::STACK_SIZE))
318           .addImm(MaxStack);
319     }
320
321     return false;
322   }
323
324   const char *getPassName() const {
325     return "R600 Control Flow Finalizer Pass";
326   }
327 };
328
329 char R600ControlFlowFinalizer::ID = 0;
330
331 }
332
333
334 llvm::FunctionPass *llvm::createR600ControlFlowFinalizer(TargetMachine &TM) {
335   return new R600ControlFlowFinalizer(TM);
336 }
337