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