R600: Control Flow support for pre EG gen
[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      return true;
71     default:
72       return false;
73     }
74   }
75
76   bool IsTrivialInst(MachineInstr *MI) const {
77     switch (MI->getOpcode()) {
78     case AMDGPU::KILL:
79     case AMDGPU::RETURN:
80       return true;
81     default:
82       return false;
83     }
84   }
85
86   const MCInstrDesc &getHWInstrDesc(ControlFlowInstruction CFI) const {
87     if (ST.device()->getGeneration() <= AMDGPUDeviceInfo::HD4XXX) {
88       switch (CFI) {
89       case CF_TC:
90         return TII->get(AMDGPU::CF_TC_R600);
91       case CF_CALL_FS:
92         return TII->get(AMDGPU::CF_CALL_FS_R600);
93       case CF_WHILE_LOOP:
94         return TII->get(AMDGPU::WHILE_LOOP_R600);
95       case CF_END_LOOP:
96         return TII->get(AMDGPU::END_LOOP_R600);
97       case CF_LOOP_BREAK:
98         return TII->get(AMDGPU::LOOP_BREAK_R600);
99       case CF_LOOP_CONTINUE:
100         return TII->get(AMDGPU::CF_CONTINUE_R600);
101       case CF_JUMP:
102         return TII->get(AMDGPU::CF_JUMP_R600);
103       case CF_ELSE:
104         return TII->get(AMDGPU::CF_ELSE_R600);
105       case CF_POP:
106         return TII->get(AMDGPU::POP_R600);
107       }
108     } else {
109       switch (CFI) {
110       case CF_TC:
111         return TII->get(AMDGPU::CF_TC_EG);
112       case CF_CALL_FS:
113         return TII->get(AMDGPU::CF_CALL_FS_EG);
114       case CF_WHILE_LOOP:
115         return TII->get(AMDGPU::WHILE_LOOP_EG);
116       case CF_END_LOOP:
117         return TII->get(AMDGPU::END_LOOP_EG);
118       case CF_LOOP_BREAK:
119         return TII->get(AMDGPU::LOOP_BREAK_EG);
120       case CF_LOOP_CONTINUE:
121         return TII->get(AMDGPU::CF_CONTINUE_EG);
122       case CF_JUMP:
123         return TII->get(AMDGPU::CF_JUMP_EG);
124       case CF_ELSE:
125         return TII->get(AMDGPU::CF_ELSE_EG);
126       case CF_POP:
127         return TII->get(AMDGPU::POP_EG);
128       }
129     }
130   }
131
132   MachineBasicBlock::iterator
133   MakeFetchClause(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
134       unsigned CfAddress) const {
135     MachineBasicBlock::iterator ClauseHead = I;
136     unsigned AluInstCount = 0;
137     for (MachineBasicBlock::iterator E = MBB.end(); I != E; ++I) {
138       if (IsTrivialInst(I))
139         continue;
140       if (!isFetch(I))
141         break;
142       AluInstCount ++;
143       if (AluInstCount > MaxFetchInst)
144         break;
145     }
146     BuildMI(MBB, ClauseHead, MBB.findDebugLoc(ClauseHead),
147         getHWInstrDesc(CF_TC))
148         .addImm(CfAddress) // ADDR
149         .addImm(AluInstCount); // COUNT
150     return I;
151   }
152   void CounterPropagateAddr(MachineInstr *MI, unsigned Addr) const {
153     MI->getOperand(0).setImm(Addr + MI->getOperand(0).getImm());
154   }
155   void CounterPropagateAddr(std::set<MachineInstr *> MIs, unsigned Addr)
156       const {
157     for (std::set<MachineInstr *>::iterator It = MIs.begin(), E = MIs.end();
158         It != E; ++It) {
159       MachineInstr *MI = *It;
160       CounterPropagateAddr(MI, Addr);
161     }
162   }
163
164 public:
165   R600ControlFlowFinalizer(TargetMachine &tm) : MachineFunctionPass(ID),
166     TII (static_cast<const R600InstrInfo *>(tm.getInstrInfo())),
167     ST(tm.getSubtarget<AMDGPUSubtarget>()) {
168       const AMDGPUSubtarget &ST = tm.getSubtarget<AMDGPUSubtarget>();
169       if (ST.device()->getGeneration() <= AMDGPUDeviceInfo::HD4XXX)
170         MaxFetchInst = 8;
171       else
172         MaxFetchInst = 16;
173   }
174
175   virtual bool runOnMachineFunction(MachineFunction &MF) {
176     unsigned MaxStack = 0;
177     unsigned CurrentStack = 0;
178     for (MachineFunction::iterator MB = MF.begin(), ME = MF.end(); MB != ME;
179         ++MB) {
180       MachineBasicBlock &MBB = *MB;
181       unsigned CfCount = 0;
182       std::vector<std::pair<unsigned, std::set<MachineInstr *> > > LoopStack;
183       std::vector<MachineInstr * > IfThenElseStack;
184       R600MachineFunctionInfo *MFI = MF.getInfo<R600MachineFunctionInfo>();
185       if (MFI->ShaderType == 1) {
186         BuildMI(MBB, MBB.begin(), MBB.findDebugLoc(MBB.begin()),
187             getHWInstrDesc(CF_CALL_FS));
188         CfCount++;
189       }
190       for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end();
191           I != E;) {
192         if (isFetch(I)) {
193           DEBUG(dbgs() << CfCount << ":"; I->dump(););
194           I = MakeFetchClause(MBB, I, 0);
195           CfCount++;
196           continue;
197         }
198
199         MachineBasicBlock::iterator MI = I;
200         I++;
201         switch (MI->getOpcode()) {
202         case AMDGPU::CF_ALU_PUSH_BEFORE:
203           CurrentStack++;
204           MaxStack = std::max(MaxStack, CurrentStack);
205         case AMDGPU::CF_ALU:
206         case AMDGPU::EG_ExportBuf:
207         case AMDGPU::EG_ExportSwz:
208         case AMDGPU::R600_ExportBuf:
209         case AMDGPU::R600_ExportSwz:
210           DEBUG(dbgs() << CfCount << ":"; MI->dump(););
211           CfCount++;
212           break;
213         case AMDGPU::WHILELOOP: {
214           CurrentStack++;
215           MaxStack = std::max(MaxStack, CurrentStack);
216           MachineInstr *MIb = BuildMI(MBB, MI, MBB.findDebugLoc(MI),
217               getHWInstrDesc(CF_WHILE_LOOP))
218               .addImm(2);
219           std::pair<unsigned, std::set<MachineInstr *> > Pair(CfCount,
220               std::set<MachineInstr *>());
221           Pair.second.insert(MIb);
222           LoopStack.push_back(Pair);
223           MI->eraseFromParent();
224           CfCount++;
225           break;
226         }
227         case AMDGPU::ENDLOOP: {
228           CurrentStack--;
229           std::pair<unsigned, std::set<MachineInstr *> > Pair =
230               LoopStack.back();
231           LoopStack.pop_back();
232           CounterPropagateAddr(Pair.second, CfCount);
233           BuildMI(MBB, MI, MBB.findDebugLoc(MI), getHWInstrDesc(CF_END_LOOP))
234               .addImm(Pair.first + 1);
235           MI->eraseFromParent();
236           CfCount++;
237           break;
238         }
239         case AMDGPU::IF_PREDICATE_SET: {
240           MachineInstr *MIb = BuildMI(MBB, MI, MBB.findDebugLoc(MI),
241               getHWInstrDesc(CF_JUMP))
242               .addImm(0)
243               .addImm(0);
244           IfThenElseStack.push_back(MIb);
245           DEBUG(dbgs() << CfCount << ":"; MIb->dump(););
246           MI->eraseFromParent();
247           CfCount++;
248           break;
249         }
250         case AMDGPU::ELSE: {
251           MachineInstr * JumpInst = IfThenElseStack.back();
252           IfThenElseStack.pop_back();
253           CounterPropagateAddr(JumpInst, CfCount);
254           MachineInstr *MIb = BuildMI(MBB, MI, MBB.findDebugLoc(MI),
255               getHWInstrDesc(CF_ELSE))
256               .addImm(0)
257               .addImm(1);
258           DEBUG(dbgs() << CfCount << ":"; MIb->dump(););
259           IfThenElseStack.push_back(MIb);
260           MI->eraseFromParent();
261           CfCount++;
262           break;
263         }
264         case AMDGPU::ENDIF: {
265           CurrentStack--;
266           MachineInstr *IfOrElseInst = IfThenElseStack.back();
267           IfThenElseStack.pop_back();
268           CounterPropagateAddr(IfOrElseInst, CfCount + 1);
269           MachineInstr *MIb = BuildMI(MBB, MI, MBB.findDebugLoc(MI),
270               getHWInstrDesc(CF_POP))
271               .addImm(CfCount + 1)
272               .addImm(1);
273           DEBUG(dbgs() << CfCount << ":"; MIb->dump(););
274           MI->eraseFromParent();
275           CfCount++;
276           break;
277         }
278         case AMDGPU::PREDICATED_BREAK: {
279           CurrentStack--;
280           CfCount += 3;
281           BuildMI(MBB, MI, MBB.findDebugLoc(MI), getHWInstrDesc(CF_JUMP))
282               .addImm(CfCount)
283               .addImm(1);
284           MachineInstr *MIb = BuildMI(MBB, MI, MBB.findDebugLoc(MI),
285               getHWInstrDesc(CF_LOOP_BREAK))
286               .addImm(0);
287           BuildMI(MBB, MI, MBB.findDebugLoc(MI), getHWInstrDesc(CF_POP))
288               .addImm(CfCount)
289               .addImm(1);
290           LoopStack.back().second.insert(MIb);
291           MI->eraseFromParent();
292           break;
293         }
294         case AMDGPU::CONTINUE: {
295           MachineInstr *MIb = BuildMI(MBB, MI, MBB.findDebugLoc(MI),
296               getHWInstrDesc(CF_LOOP_CONTINUE))
297               .addImm(0);
298           LoopStack.back().second.insert(MIb);
299           MI->eraseFromParent();
300           CfCount++;
301           break;
302         }
303         default:
304           break;
305         }
306       }
307       BuildMI(MBB, MBB.begin(), MBB.findDebugLoc(MBB.begin()),
308           TII->get(AMDGPU::STACK_SIZE))
309           .addImm(MaxStack);
310     }
311
312     return false;
313   }
314
315   const char *getPassName() const {
316     return "R600 Control Flow Finalizer Pass";
317   }
318 };
319
320 char R600ControlFlowFinalizer::ID = 0;
321
322 }
323
324
325 llvm::FunctionPass *llvm::createR600ControlFlowFinalizer(TargetMachine &TM) {
326   return new R600ControlFlowFinalizer(TM);
327 }
328