R600: Use .AMDGPU.config section to emit stacksize
[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   unsigned getHWStackSize(unsigned StackSubEntry, bool hasPush) const {
170     switch (ST.device()->getGeneration()) {
171     case AMDGPUDeviceInfo::HD4XXX:
172       if (hasPush)
173         StackSubEntry += 2;
174       break;
175     case AMDGPUDeviceInfo::HD5XXX:
176       if (hasPush)
177         StackSubEntry ++;
178     case AMDGPUDeviceInfo::HD6XXX:
179       StackSubEntry += 2;
180       break;
181     }
182     return (StackSubEntry + 3)/4; // Need ceil value of StackSubEntry/4
183   }
184
185 public:
186   R600ControlFlowFinalizer(TargetMachine &tm) : MachineFunctionPass(ID),
187     TII (static_cast<const R600InstrInfo *>(tm.getInstrInfo())),
188     ST(tm.getSubtarget<AMDGPUSubtarget>()) {
189       const AMDGPUSubtarget &ST = tm.getSubtarget<AMDGPUSubtarget>();
190       if (ST.device()->getGeneration() <= AMDGPUDeviceInfo::HD4XXX)
191         MaxFetchInst = 8;
192       else
193         MaxFetchInst = 16;
194   }
195
196   virtual bool runOnMachineFunction(MachineFunction &MF) {
197     unsigned MaxStack = 0;
198     unsigned CurrentStack = 0;
199     bool hasPush;
200     for (MachineFunction::iterator MB = MF.begin(), ME = MF.end(); MB != ME;
201         ++MB) {
202       MachineBasicBlock &MBB = *MB;
203       unsigned CfCount = 0;
204       std::vector<std::pair<unsigned, std::set<MachineInstr *> > > LoopStack;
205       std::vector<MachineInstr * > IfThenElseStack;
206       R600MachineFunctionInfo *MFI = MF.getInfo<R600MachineFunctionInfo>();
207       if (MFI->ShaderType == 1) {
208         BuildMI(MBB, MBB.begin(), MBB.findDebugLoc(MBB.begin()),
209             getHWInstrDesc(CF_CALL_FS));
210         CfCount++;
211       }
212       for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end();
213           I != E;) {
214         if (isFetch(I)) {
215           DEBUG(dbgs() << CfCount << ":"; I->dump(););
216           I = MakeFetchClause(MBB, I, 0);
217           CfCount++;
218           continue;
219         }
220
221         MachineBasicBlock::iterator MI = I;
222         I++;
223         switch (MI->getOpcode()) {
224         case AMDGPU::CF_ALU_PUSH_BEFORE:
225           CurrentStack++;
226           MaxStack = std::max(MaxStack, CurrentStack);
227           hasPush = true;
228         case AMDGPU::CF_ALU:
229         case AMDGPU::EG_ExportBuf:
230         case AMDGPU::EG_ExportSwz:
231         case AMDGPU::R600_ExportBuf:
232         case AMDGPU::R600_ExportSwz:
233         case AMDGPU::RAT_WRITE_CACHELESS_32_eg:
234         case AMDGPU::RAT_WRITE_CACHELESS_128_eg:
235           DEBUG(dbgs() << CfCount << ":"; MI->dump(););
236           CfCount++;
237           break;
238         case AMDGPU::WHILELOOP: {
239           CurrentStack+=4;
240           MaxStack = std::max(MaxStack, CurrentStack);
241           MachineInstr *MIb = BuildMI(MBB, MI, MBB.findDebugLoc(MI),
242               getHWInstrDesc(CF_WHILE_LOOP))
243               .addImm(1);
244           std::pair<unsigned, std::set<MachineInstr *> > Pair(CfCount,
245               std::set<MachineInstr *>());
246           Pair.second.insert(MIb);
247           LoopStack.push_back(Pair);
248           MI->eraseFromParent();
249           CfCount++;
250           break;
251         }
252         case AMDGPU::ENDLOOP: {
253           CurrentStack-=4;
254           std::pair<unsigned, std::set<MachineInstr *> > Pair =
255               LoopStack.back();
256           LoopStack.pop_back();
257           CounterPropagateAddr(Pair.second, CfCount);
258           BuildMI(MBB, MI, MBB.findDebugLoc(MI), getHWInstrDesc(CF_END_LOOP))
259               .addImm(Pair.first + 1);
260           MI->eraseFromParent();
261           CfCount++;
262           break;
263         }
264         case AMDGPU::IF_PREDICATE_SET: {
265           MachineInstr *MIb = BuildMI(MBB, MI, MBB.findDebugLoc(MI),
266               getHWInstrDesc(CF_JUMP))
267               .addImm(0)
268               .addImm(0);
269           IfThenElseStack.push_back(MIb);
270           DEBUG(dbgs() << CfCount << ":"; MIb->dump(););
271           MI->eraseFromParent();
272           CfCount++;
273           break;
274         }
275         case AMDGPU::ELSE: {
276           MachineInstr * JumpInst = IfThenElseStack.back();
277           IfThenElseStack.pop_back();
278           CounterPropagateAddr(JumpInst, CfCount);
279           MachineInstr *MIb = BuildMI(MBB, MI, MBB.findDebugLoc(MI),
280               getHWInstrDesc(CF_ELSE))
281               .addImm(0)
282               .addImm(1);
283           DEBUG(dbgs() << CfCount << ":"; MIb->dump(););
284           IfThenElseStack.push_back(MIb);
285           MI->eraseFromParent();
286           CfCount++;
287           break;
288         }
289         case AMDGPU::ENDIF: {
290           CurrentStack--;
291           MachineInstr *IfOrElseInst = IfThenElseStack.back();
292           IfThenElseStack.pop_back();
293           CounterPropagateAddr(IfOrElseInst, CfCount + 1);
294           MachineInstr *MIb = BuildMI(MBB, MI, MBB.findDebugLoc(MI),
295               getHWInstrDesc(CF_POP))
296               .addImm(CfCount + 1)
297               .addImm(1);
298           (void)MIb;
299           DEBUG(dbgs() << CfCount << ":"; MIb->dump(););
300           MI->eraseFromParent();
301           CfCount++;
302           break;
303         }
304         case AMDGPU::PREDICATED_BREAK: {
305           CurrentStack--;
306           CfCount += 3;
307           BuildMI(MBB, MI, MBB.findDebugLoc(MI), getHWInstrDesc(CF_JUMP))
308               .addImm(CfCount)
309               .addImm(1);
310           MachineInstr *MIb = BuildMI(MBB, MI, MBB.findDebugLoc(MI),
311               getHWInstrDesc(CF_LOOP_BREAK))
312               .addImm(0);
313           BuildMI(MBB, MI, MBB.findDebugLoc(MI), getHWInstrDesc(CF_POP))
314               .addImm(CfCount)
315               .addImm(1);
316           LoopStack.back().second.insert(MIb);
317           MI->eraseFromParent();
318           break;
319         }
320         case AMDGPU::CONTINUE: {
321           MachineInstr *MIb = BuildMI(MBB, MI, MBB.findDebugLoc(MI),
322               getHWInstrDesc(CF_LOOP_CONTINUE))
323               .addImm(0);
324           LoopStack.back().second.insert(MIb);
325           MI->eraseFromParent();
326           CfCount++;
327           break;
328         }
329         case AMDGPU::RETURN: {
330           BuildMI(MBB, MI, MBB.findDebugLoc(MI), getHWInstrDesc(CF_END));
331           CfCount++;
332           MI->eraseFromParent();
333           if (CfCount % 2) {
334             BuildMI(MBB, I, MBB.findDebugLoc(MI), TII->get(AMDGPU::PAD));
335             CfCount++;
336           }
337         }
338         default:
339           break;
340         }
341       }
342       MFI->StackSize = getHWStackSize(MaxStack, hasPush);
343     }
344
345     return false;
346   }
347
348   const char *getPassName() const {
349     return "R600 Control Flow Finalizer Pass";
350   }
351 };
352
353 char R600ControlFlowFinalizer::ID = 0;
354
355 }
356
357
358 llvm::FunctionPass *llvm::createR600ControlFlowFinalizer(TargetMachine &TM) {
359   return new R600ControlFlowFinalizer(TM);
360 }