xref: /src/contrib/llvm-project/llvm/lib/Target/AMDGPU/R600ControlFlowFinalizer.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1044eb2f6SDimitry Andric //===- R600ControlFlowFinalizer.cpp - Finalize Control Flow Inst ----------===//
24a16efa3SDimitry Andric //
3e6d15924SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e6d15924SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e6d15924SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
64a16efa3SDimitry Andric //
74a16efa3SDimitry Andric //===----------------------------------------------------------------------===//
84a16efa3SDimitry Andric //
94a16efa3SDimitry Andric /// \file
104a16efa3SDimitry Andric /// This pass compute turns all control flow pseudo instructions into native one
114a16efa3SDimitry Andric /// computing their address on the fly; it also sets STACK_SIZE info.
12044eb2f6SDimitry Andric //
134a16efa3SDimitry Andric //===----------------------------------------------------------------------===//
144a16efa3SDimitry Andric 
15c0981da4SDimitry Andric #include "MCTargetDesc/R600MCTargetDesc.h"
16c0981da4SDimitry Andric #include "R600.h"
17b60736ecSDimitry Andric #include "R600MachineFunctionInfo.h"
18b60736ecSDimitry Andric #include "R600Subtarget.h"
19145449b1SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
2071d5a254SDimitry Andric #include <set>
214a16efa3SDimitry Andric 
22f8af5cf6SDimitry Andric using namespace llvm;
23f8af5cf6SDimitry Andric 
245ca98fd9SDimitry Andric #define DEBUG_TYPE "r600cf"
255ca98fd9SDimitry Andric 
26f8af5cf6SDimitry Andric namespace {
274a16efa3SDimitry Andric 
285ca98fd9SDimitry Andric struct CFStack {
295ca98fd9SDimitry Andric   enum StackItem {
305ca98fd9SDimitry Andric     ENTRY = 0,
315ca98fd9SDimitry Andric     SUB_ENTRY = 1,
325ca98fd9SDimitry Andric     FIRST_NON_WQM_PUSH = 2,
335ca98fd9SDimitry Andric     FIRST_NON_WQM_PUSH_W_FULL_ENTRY = 3
345ca98fd9SDimitry Andric   };
355ca98fd9SDimitry Andric 
3601095a5dSDimitry Andric   const R600Subtarget *ST;
375ca98fd9SDimitry Andric   std::vector<StackItem> BranchStack;
385ca98fd9SDimitry Andric   std::vector<StackItem> LoopStack;
395ca98fd9SDimitry Andric   unsigned MaxStackSize;
4071d5a254SDimitry Andric   unsigned CurrentEntries = 0;
4171d5a254SDimitry Andric   unsigned CurrentSubEntries = 0;
425ca98fd9SDimitry Andric 
CFStack__anon8aea2c6d0111::CFStack4301095a5dSDimitry Andric   CFStack(const R600Subtarget *st, CallingConv::ID cc) : ST(st),
445ca98fd9SDimitry Andric       // We need to reserve a stack entry for CALL_FS in vertex shaders.
4571d5a254SDimitry Andric       MaxStackSize(cc == CallingConv::AMDGPU_VS ? 1 : 0) {}
465ca98fd9SDimitry Andric 
475ca98fd9SDimitry Andric   unsigned getLoopDepth();
485ca98fd9SDimitry Andric   bool branchStackContains(CFStack::StackItem);
495ca98fd9SDimitry Andric   bool requiresWorkAroundForInst(unsigned Opcode);
505ca98fd9SDimitry Andric   unsigned getSubEntrySize(CFStack::StackItem Item);
515ca98fd9SDimitry Andric   void updateMaxStackSize();
525ca98fd9SDimitry Andric   void pushBranch(unsigned Opcode, bool isWQM = false);
535ca98fd9SDimitry Andric   void pushLoop();
545ca98fd9SDimitry Andric   void popBranch();
555ca98fd9SDimitry Andric   void popLoop();
565ca98fd9SDimitry Andric };
575ca98fd9SDimitry Andric 
getLoopDepth()585ca98fd9SDimitry Andric unsigned CFStack::getLoopDepth() {
595ca98fd9SDimitry Andric   return LoopStack.size();
605ca98fd9SDimitry Andric }
615ca98fd9SDimitry Andric 
branchStackContains(CFStack::StackItem Item)625ca98fd9SDimitry Andric bool CFStack::branchStackContains(CFStack::StackItem Item) {
63b60736ecSDimitry Andric   return llvm::is_contained(BranchStack, Item);
645ca98fd9SDimitry Andric }
655ca98fd9SDimitry Andric 
requiresWorkAroundForInst(unsigned Opcode)665ca98fd9SDimitry Andric bool CFStack::requiresWorkAroundForInst(unsigned Opcode) {
67eb11fae6SDimitry Andric   if (Opcode == R600::CF_ALU_PUSH_BEFORE && ST->hasCaymanISA() &&
685ca98fd9SDimitry Andric       getLoopDepth() > 1)
695ca98fd9SDimitry Andric     return true;
705ca98fd9SDimitry Andric 
715a5ac124SDimitry Andric   if (!ST->hasCFAluBug())
725ca98fd9SDimitry Andric     return false;
735ca98fd9SDimitry Andric 
745ca98fd9SDimitry Andric   switch(Opcode) {
755ca98fd9SDimitry Andric   default: return false;
76eb11fae6SDimitry Andric   case R600::CF_ALU_PUSH_BEFORE:
77eb11fae6SDimitry Andric   case R600::CF_ALU_ELSE_AFTER:
78eb11fae6SDimitry Andric   case R600::CF_ALU_BREAK:
79eb11fae6SDimitry Andric   case R600::CF_ALU_CONTINUE:
805ca98fd9SDimitry Andric     if (CurrentSubEntries == 0)
815ca98fd9SDimitry Andric       return false;
825a5ac124SDimitry Andric     if (ST->getWavefrontSize() == 64) {
835ca98fd9SDimitry Andric       // We are being conservative here.  We only require this work-around if
845ca98fd9SDimitry Andric       // CurrentSubEntries > 3 &&
855ca98fd9SDimitry Andric       // (CurrentSubEntries % 4 == 3 || CurrentSubEntries % 4 == 0)
865ca98fd9SDimitry Andric       //
875ca98fd9SDimitry Andric       // We have to be conservative, because we don't know for certain that
885ca98fd9SDimitry Andric       // our stack allocation algorithm for Evergreen/NI is correct.  Applying this
895ca98fd9SDimitry Andric       // work-around when CurrentSubEntries > 3 allows us to over-allocate stack
905ca98fd9SDimitry Andric       // resources without any problems.
915ca98fd9SDimitry Andric       return CurrentSubEntries > 3;
92ac9a064cSDimitry Andric     }
935a5ac124SDimitry Andric     assert(ST->getWavefrontSize() == 32);
945ca98fd9SDimitry Andric     // We are being conservative here.  We only require the work-around if
955ca98fd9SDimitry Andric     // CurrentSubEntries > 7 &&
965ca98fd9SDimitry Andric     // (CurrentSubEntries % 8 == 7 || CurrentSubEntries % 8 == 0)
975ca98fd9SDimitry Andric     // See the comment on the wavefront size == 64 case for why we are
985ca98fd9SDimitry Andric     // being conservative.
995ca98fd9SDimitry Andric     return CurrentSubEntries > 7;
1005ca98fd9SDimitry Andric   }
1015ca98fd9SDimitry Andric }
1025ca98fd9SDimitry Andric 
getSubEntrySize(CFStack::StackItem Item)1035ca98fd9SDimitry Andric unsigned CFStack::getSubEntrySize(CFStack::StackItem Item) {
1045ca98fd9SDimitry Andric   switch(Item) {
1055ca98fd9SDimitry Andric   default:
1065ca98fd9SDimitry Andric     return 0;
1075ca98fd9SDimitry Andric   case CFStack::FIRST_NON_WQM_PUSH:
1085a5ac124SDimitry Andric     assert(!ST->hasCaymanISA());
109eb11fae6SDimitry Andric     if (ST->getGeneration() <= AMDGPUSubtarget::R700) {
1105ca98fd9SDimitry Andric       // +1 For the push operation.
1115ca98fd9SDimitry Andric       // +2 Extra space required.
1125ca98fd9SDimitry Andric       return 3;
113ac9a064cSDimitry Andric     }
1145ca98fd9SDimitry Andric     // Some documentation says that this is not necessary on Evergreen,
1155ca98fd9SDimitry Andric     // but experimentation has show that we need to allocate 1 extra
1165ca98fd9SDimitry Andric     // sub-entry for the first non-WQM push.
1175ca98fd9SDimitry Andric     // +1 For the push operation.
1185ca98fd9SDimitry Andric     // +1 Extra space required.
1195ca98fd9SDimitry Andric     return 2;
1205ca98fd9SDimitry Andric   case CFStack::FIRST_NON_WQM_PUSH_W_FULL_ENTRY:
121eb11fae6SDimitry Andric     assert(ST->getGeneration() >= AMDGPUSubtarget::EVERGREEN);
1225ca98fd9SDimitry Andric     // +1 For the push operation.
1235ca98fd9SDimitry Andric     // +1 Extra space required.
1245ca98fd9SDimitry Andric     return 2;
1255ca98fd9SDimitry Andric   case CFStack::SUB_ENTRY:
1265ca98fd9SDimitry Andric     return 1;
1275ca98fd9SDimitry Andric   }
1285ca98fd9SDimitry Andric }
1295ca98fd9SDimitry Andric 
updateMaxStackSize()1305ca98fd9SDimitry Andric void CFStack::updateMaxStackSize() {
131cfca06d7SDimitry Andric   unsigned CurrentStackSize = CurrentEntries + divideCeil(CurrentSubEntries, 4);
1325ca98fd9SDimitry Andric   MaxStackSize = std::max(CurrentStackSize, MaxStackSize);
1335ca98fd9SDimitry Andric }
1345ca98fd9SDimitry Andric 
pushBranch(unsigned Opcode,bool isWQM)1355ca98fd9SDimitry Andric void CFStack::pushBranch(unsigned Opcode, bool isWQM) {
1365ca98fd9SDimitry Andric   CFStack::StackItem Item = CFStack::ENTRY;
1375ca98fd9SDimitry Andric   switch(Opcode) {
138eb11fae6SDimitry Andric   case R600::CF_PUSH_EG:
139eb11fae6SDimitry Andric   case R600::CF_ALU_PUSH_BEFORE:
1405ca98fd9SDimitry Andric     if (!isWQM) {
1415a5ac124SDimitry Andric       if (!ST->hasCaymanISA() &&
1425a5ac124SDimitry Andric           !branchStackContains(CFStack::FIRST_NON_WQM_PUSH))
1435ca98fd9SDimitry Andric         Item = CFStack::FIRST_NON_WQM_PUSH;  // May not be required on Evergreen/NI
1445ca98fd9SDimitry Andric                                              // See comment in
1455ca98fd9SDimitry Andric                                              // CFStack::getSubEntrySize()
1465ca98fd9SDimitry Andric       else if (CurrentEntries > 0 &&
147eb11fae6SDimitry Andric                ST->getGeneration() > AMDGPUSubtarget::EVERGREEN &&
1485a5ac124SDimitry Andric                !ST->hasCaymanISA() &&
1495ca98fd9SDimitry Andric                !branchStackContains(CFStack::FIRST_NON_WQM_PUSH_W_FULL_ENTRY))
1505ca98fd9SDimitry Andric         Item = CFStack::FIRST_NON_WQM_PUSH_W_FULL_ENTRY;
1515ca98fd9SDimitry Andric       else
1525ca98fd9SDimitry Andric         Item = CFStack::SUB_ENTRY;
1535ca98fd9SDimitry Andric     } else
1545ca98fd9SDimitry Andric       Item = CFStack::ENTRY;
1555ca98fd9SDimitry Andric     break;
1565ca98fd9SDimitry Andric   }
1575ca98fd9SDimitry Andric   BranchStack.push_back(Item);
1585ca98fd9SDimitry Andric   if (Item == CFStack::ENTRY)
1595ca98fd9SDimitry Andric     CurrentEntries++;
1605ca98fd9SDimitry Andric   else
1615ca98fd9SDimitry Andric     CurrentSubEntries += getSubEntrySize(Item);
1625ca98fd9SDimitry Andric   updateMaxStackSize();
1635ca98fd9SDimitry Andric }
1645ca98fd9SDimitry Andric 
pushLoop()1655ca98fd9SDimitry Andric void CFStack::pushLoop() {
1665ca98fd9SDimitry Andric   LoopStack.push_back(CFStack::ENTRY);
1675ca98fd9SDimitry Andric   CurrentEntries++;
1685ca98fd9SDimitry Andric   updateMaxStackSize();
1695ca98fd9SDimitry Andric }
1705ca98fd9SDimitry Andric 
popBranch()1715ca98fd9SDimitry Andric void CFStack::popBranch() {
1725ca98fd9SDimitry Andric   CFStack::StackItem Top = BranchStack.back();
1735ca98fd9SDimitry Andric   if (Top == CFStack::ENTRY)
1745ca98fd9SDimitry Andric     CurrentEntries--;
1755ca98fd9SDimitry Andric   else
1765ca98fd9SDimitry Andric     CurrentSubEntries-= getSubEntrySize(Top);
1775ca98fd9SDimitry Andric   BranchStack.pop_back();
1785ca98fd9SDimitry Andric }
1795ca98fd9SDimitry Andric 
popLoop()1805ca98fd9SDimitry Andric void CFStack::popLoop() {
1815ca98fd9SDimitry Andric   CurrentEntries--;
1825ca98fd9SDimitry Andric   LoopStack.pop_back();
1835ca98fd9SDimitry Andric }
1845ca98fd9SDimitry Andric 
1854a16efa3SDimitry Andric class R600ControlFlowFinalizer : public MachineFunctionPass {
1864a16efa3SDimitry Andric private:
187044eb2f6SDimitry Andric   using ClauseFile = std::pair<MachineInstr *, std::vector<MachineInstr *>>;
18859d6cff9SDimitry Andric 
18959d6cff9SDimitry Andric   enum ControlFlowInstruction {
19059d6cff9SDimitry Andric     CF_TC,
19159d6cff9SDimitry Andric     CF_VC,
19259d6cff9SDimitry Andric     CF_CALL_FS,
19359d6cff9SDimitry Andric     CF_WHILE_LOOP,
19459d6cff9SDimitry Andric     CF_END_LOOP,
19559d6cff9SDimitry Andric     CF_LOOP_BREAK,
19659d6cff9SDimitry Andric     CF_LOOP_CONTINUE,
19759d6cff9SDimitry Andric     CF_JUMP,
19859d6cff9SDimitry Andric     CF_ELSE,
19959d6cff9SDimitry Andric     CF_POP,
20059d6cff9SDimitry Andric     CF_END
20159d6cff9SDimitry Andric   };
20259d6cff9SDimitry Andric 
20371d5a254SDimitry Andric   const R600InstrInfo *TII = nullptr;
20471d5a254SDimitry Andric   const R600RegisterInfo *TRI = nullptr;
2054a16efa3SDimitry Andric   unsigned MaxFetchInst;
20671d5a254SDimitry Andric   const R600Subtarget *ST = nullptr;
2074a16efa3SDimitry Andric 
IsTrivialInst(MachineInstr & MI) const20801095a5dSDimitry Andric   bool IsTrivialInst(MachineInstr &MI) const {
20901095a5dSDimitry Andric     switch (MI.getOpcode()) {
210eb11fae6SDimitry Andric     case R600::KILL:
211eb11fae6SDimitry Andric     case R600::RETURN:
2124a16efa3SDimitry Andric       return true;
2134a16efa3SDimitry Andric     default:
2144a16efa3SDimitry Andric       return false;
2154a16efa3SDimitry Andric     }
2164a16efa3SDimitry Andric   }
2174a16efa3SDimitry Andric 
getHWInstrDesc(ControlFlowInstruction CFI) const21859d6cff9SDimitry Andric   const MCInstrDesc &getHWInstrDesc(ControlFlowInstruction CFI) const {
21959d6cff9SDimitry Andric     unsigned Opcode = 0;
220eb11fae6SDimitry Andric     bool isEg = (ST->getGeneration() >= AMDGPUSubtarget::EVERGREEN);
22159d6cff9SDimitry Andric     switch (CFI) {
22259d6cff9SDimitry Andric     case CF_TC:
223eb11fae6SDimitry Andric       Opcode = isEg ? R600::CF_TC_EG : R600::CF_TC_R600;
22459d6cff9SDimitry Andric       break;
22559d6cff9SDimitry Andric     case CF_VC:
226eb11fae6SDimitry Andric       Opcode = isEg ? R600::CF_VC_EG : R600::CF_VC_R600;
22759d6cff9SDimitry Andric       break;
22859d6cff9SDimitry Andric     case CF_CALL_FS:
229eb11fae6SDimitry Andric       Opcode = isEg ? R600::CF_CALL_FS_EG : R600::CF_CALL_FS_R600;
23059d6cff9SDimitry Andric       break;
23159d6cff9SDimitry Andric     case CF_WHILE_LOOP:
232eb11fae6SDimitry Andric       Opcode = isEg ? R600::WHILE_LOOP_EG : R600::WHILE_LOOP_R600;
23359d6cff9SDimitry Andric       break;
23459d6cff9SDimitry Andric     case CF_END_LOOP:
235eb11fae6SDimitry Andric       Opcode = isEg ? R600::END_LOOP_EG : R600::END_LOOP_R600;
23659d6cff9SDimitry Andric       break;
23759d6cff9SDimitry Andric     case CF_LOOP_BREAK:
238eb11fae6SDimitry Andric       Opcode = isEg ? R600::LOOP_BREAK_EG : R600::LOOP_BREAK_R600;
23959d6cff9SDimitry Andric       break;
24059d6cff9SDimitry Andric     case CF_LOOP_CONTINUE:
241eb11fae6SDimitry Andric       Opcode = isEg ? R600::CF_CONTINUE_EG : R600::CF_CONTINUE_R600;
24259d6cff9SDimitry Andric       break;
24359d6cff9SDimitry Andric     case CF_JUMP:
244eb11fae6SDimitry Andric       Opcode = isEg ? R600::CF_JUMP_EG : R600::CF_JUMP_R600;
24559d6cff9SDimitry Andric       break;
24659d6cff9SDimitry Andric     case CF_ELSE:
247eb11fae6SDimitry Andric       Opcode = isEg ? R600::CF_ELSE_EG : R600::CF_ELSE_R600;
24859d6cff9SDimitry Andric       break;
24959d6cff9SDimitry Andric     case CF_POP:
250eb11fae6SDimitry Andric       Opcode = isEg ? R600::POP_EG : R600::POP_R600;
25159d6cff9SDimitry Andric       break;
25259d6cff9SDimitry Andric     case CF_END:
2535a5ac124SDimitry Andric       if (ST->hasCaymanISA()) {
254eb11fae6SDimitry Andric         Opcode = R600::CF_END_CM;
25559d6cff9SDimitry Andric         break;
25659d6cff9SDimitry Andric       }
257eb11fae6SDimitry Andric       Opcode = isEg ? R600::CF_END_EG : R600::CF_END_R600;
25859d6cff9SDimitry Andric       break;
25959d6cff9SDimitry Andric     }
26059d6cff9SDimitry Andric     assert (Opcode && "No opcode selected");
26159d6cff9SDimitry Andric     return TII->get(Opcode);
26259d6cff9SDimitry Andric   }
26359d6cff9SDimitry Andric 
isCompatibleWithClause(const MachineInstr & MI,std::set<unsigned> & DstRegs) const26401095a5dSDimitry Andric   bool isCompatibleWithClause(const MachineInstr &MI,
265f8af5cf6SDimitry Andric                               std::set<unsigned> &DstRegs) const {
26659d6cff9SDimitry Andric     unsigned DstMI, SrcMI;
26701095a5dSDimitry Andric     for (MachineInstr::const_mop_iterator I = MI.operands_begin(),
26801095a5dSDimitry Andric                                           E = MI.operands_end();
26901095a5dSDimitry Andric          I != E; ++I) {
27059d6cff9SDimitry Andric       const MachineOperand &MO = *I;
27159d6cff9SDimitry Andric       if (!MO.isReg())
27259d6cff9SDimitry Andric         continue;
273f8af5cf6SDimitry Andric       if (MO.isDef()) {
2741d5ae102SDimitry Andric         Register Reg = MO.getReg();
275eb11fae6SDimitry Andric         if (R600::R600_Reg128RegClass.contains(Reg))
276f8af5cf6SDimitry Andric           DstMI = Reg;
277f8af5cf6SDimitry Andric         else
278f8af5cf6SDimitry Andric           DstMI = TRI->getMatchingSuperReg(Reg,
279cfca06d7SDimitry Andric               R600RegisterInfo::getSubRegFromChannel(TRI->getHWRegChan(Reg)),
280eb11fae6SDimitry Andric               &R600::R600_Reg128RegClass);
281f8af5cf6SDimitry Andric       }
28259d6cff9SDimitry Andric       if (MO.isUse()) {
2831d5ae102SDimitry Andric         Register Reg = MO.getReg();
284eb11fae6SDimitry Andric         if (R600::R600_Reg128RegClass.contains(Reg))
28559d6cff9SDimitry Andric           SrcMI = Reg;
28659d6cff9SDimitry Andric         else
287f8af5cf6SDimitry Andric           SrcMI = TRI->getMatchingSuperReg(Reg,
288cfca06d7SDimitry Andric               R600RegisterInfo::getSubRegFromChannel(TRI->getHWRegChan(Reg)),
289eb11fae6SDimitry Andric               &R600::R600_Reg128RegClass);
29059d6cff9SDimitry Andric       }
29159d6cff9SDimitry Andric     }
292f8af5cf6SDimitry Andric     if ((DstRegs.find(SrcMI) == DstRegs.end())) {
29359d6cff9SDimitry Andric       DstRegs.insert(DstMI);
29459d6cff9SDimitry Andric       return true;
295ac9a064cSDimitry Andric     }
29659d6cff9SDimitry Andric     return false;
29759d6cff9SDimitry Andric   }
29859d6cff9SDimitry Andric 
29959d6cff9SDimitry Andric   ClauseFile
MakeFetchClause(MachineBasicBlock & MBB,MachineBasicBlock::iterator & I) const30059d6cff9SDimitry Andric   MakeFetchClause(MachineBasicBlock &MBB, MachineBasicBlock::iterator &I)
30159d6cff9SDimitry Andric       const {
3024a16efa3SDimitry Andric     MachineBasicBlock::iterator ClauseHead = I;
30359d6cff9SDimitry Andric     std::vector<MachineInstr *> ClauseContent;
3044a16efa3SDimitry Andric     unsigned AluInstCount = 0;
30501095a5dSDimitry Andric     bool IsTex = TII->usesTextureCache(*ClauseHead);
306f8af5cf6SDimitry Andric     std::set<unsigned> DstRegs;
3074a16efa3SDimitry Andric     for (MachineBasicBlock::iterator E = MBB.end(); I != E; ++I) {
30801095a5dSDimitry Andric       if (IsTrivialInst(*I))
3094a16efa3SDimitry Andric         continue;
310f8af5cf6SDimitry Andric       if (AluInstCount >= MaxFetchInst)
3114a16efa3SDimitry Andric         break;
31201095a5dSDimitry Andric       if ((IsTex && !TII->usesTextureCache(*I)) ||
31301095a5dSDimitry Andric           (!IsTex && !TII->usesVertexCache(*I)))
31459d6cff9SDimitry Andric         break;
31501095a5dSDimitry Andric       if (!isCompatibleWithClause(*I, DstRegs))
31659d6cff9SDimitry Andric         break;
31759d6cff9SDimitry Andric       AluInstCount ++;
31801095a5dSDimitry Andric       ClauseContent.push_back(&*I);
3194a16efa3SDimitry Andric     }
32059d6cff9SDimitry Andric     MachineInstr *MIb = BuildMI(MBB, ClauseHead, MBB.findDebugLoc(ClauseHead),
32159d6cff9SDimitry Andric         getHWInstrDesc(IsTex?CF_TC:CF_VC))
32259d6cff9SDimitry Andric         .addImm(0) // ADDR
32359d6cff9SDimitry Andric         .addImm(AluInstCount - 1); // COUNT
32467c32a98SDimitry Andric     return ClauseFile(MIb, std::move(ClauseContent));
3254a16efa3SDimitry Andric   }
32659d6cff9SDimitry Andric 
getLiteral(MachineInstr & MI,std::vector<MachineOperand * > & Lits) const32701095a5dSDimitry Andric   void getLiteral(MachineInstr &MI, std::vector<MachineOperand *> &Lits) const {
328f8af5cf6SDimitry Andric     static const unsigned LiteralRegs[] = {
329eb11fae6SDimitry Andric       R600::ALU_LITERAL_X,
330eb11fae6SDimitry Andric       R600::ALU_LITERAL_Y,
331eb11fae6SDimitry Andric       R600::ALU_LITERAL_Z,
332eb11fae6SDimitry Andric       R600::ALU_LITERAL_W
33359d6cff9SDimitry Andric     };
334f8af5cf6SDimitry Andric     const SmallVector<std::pair<MachineOperand *, int64_t>, 3> Srcs =
335f8af5cf6SDimitry Andric         TII->getSrcs(MI);
33601095a5dSDimitry Andric     for (const auto &Src:Srcs) {
337eb11fae6SDimitry Andric       if (Src.first->getReg() != R600::ALU_LITERAL_X)
33859d6cff9SDimitry Andric         continue;
33901095a5dSDimitry Andric       int64_t Imm = Src.second;
34001095a5dSDimitry Andric       std::vector<MachineOperand *>::iterator It =
34171d5a254SDimitry Andric           llvm::find_if(Lits, [&](MachineOperand *val) {
342b915e9e0SDimitry Andric             return val->isImm() && (val->getImm() == Imm);
343b915e9e0SDimitry Andric           });
34401095a5dSDimitry Andric 
34501095a5dSDimitry Andric       // Get corresponding Operand
34601095a5dSDimitry Andric       MachineOperand &Operand = MI.getOperand(
347eb11fae6SDimitry Andric           TII->getOperandIdx(MI.getOpcode(), R600::OpName::literal));
34801095a5dSDimitry Andric 
34959d6cff9SDimitry Andric       if (It != Lits.end()) {
35001095a5dSDimitry Andric         // Reuse existing literal reg
35159d6cff9SDimitry Andric         unsigned Index = It - Lits.begin();
35201095a5dSDimitry Andric         Src.first->setReg(LiteralRegs[Index]);
35359d6cff9SDimitry Andric       } else {
35401095a5dSDimitry Andric         // Allocate new literal reg
35559d6cff9SDimitry Andric         assert(Lits.size() < 4 && "Too many literals in Instruction Group");
35601095a5dSDimitry Andric         Src.first->setReg(LiteralRegs[Lits.size()]);
35701095a5dSDimitry Andric         Lits.push_back(&Operand);
35859d6cff9SDimitry Andric       }
35959d6cff9SDimitry Andric     }
36059d6cff9SDimitry Andric   }
36159d6cff9SDimitry Andric 
insertLiterals(MachineBasicBlock::iterator InsertPos,const std::vector<unsigned> & Literals) const36259d6cff9SDimitry Andric   MachineBasicBlock::iterator insertLiterals(
36359d6cff9SDimitry Andric       MachineBasicBlock::iterator InsertPos,
36459d6cff9SDimitry Andric       const std::vector<unsigned> &Literals) const {
36559d6cff9SDimitry Andric     MachineBasicBlock *MBB = InsertPos->getParent();
36659d6cff9SDimitry Andric     for (unsigned i = 0, e = Literals.size(); i < e; i+=2) {
36759d6cff9SDimitry Andric       unsigned LiteralPair0 = Literals[i];
36859d6cff9SDimitry Andric       unsigned LiteralPair1 = (i + 1 < e)?Literals[i + 1]:0;
36959d6cff9SDimitry Andric       InsertPos = BuildMI(MBB, InsertPos->getDebugLoc(),
370eb11fae6SDimitry Andric           TII->get(R600::LITERALS))
37159d6cff9SDimitry Andric           .addImm(LiteralPair0)
37259d6cff9SDimitry Andric           .addImm(LiteralPair1);
37359d6cff9SDimitry Andric     }
37459d6cff9SDimitry Andric     return InsertPos;
37559d6cff9SDimitry Andric   }
37659d6cff9SDimitry Andric 
37759d6cff9SDimitry Andric   ClauseFile
MakeALUClause(MachineBasicBlock & MBB,MachineBasicBlock::iterator & I) const37859d6cff9SDimitry Andric   MakeALUClause(MachineBasicBlock &MBB, MachineBasicBlock::iterator &I)
37959d6cff9SDimitry Andric       const {
38001095a5dSDimitry Andric     MachineInstr &ClauseHead = *I;
38159d6cff9SDimitry Andric     std::vector<MachineInstr *> ClauseContent;
38259d6cff9SDimitry Andric     I++;
38359d6cff9SDimitry Andric     for (MachineBasicBlock::instr_iterator E = MBB.instr_end(); I != E;) {
38401095a5dSDimitry Andric       if (IsTrivialInst(*I)) {
38559d6cff9SDimitry Andric         ++I;
38659d6cff9SDimitry Andric         continue;
38759d6cff9SDimitry Andric       }
38859d6cff9SDimitry Andric       if (!I->isBundle() && !TII->isALUInstr(I->getOpcode()))
38959d6cff9SDimitry Andric         break;
39001095a5dSDimitry Andric       std::vector<MachineOperand *>Literals;
39159d6cff9SDimitry Andric       if (I->isBundle()) {
39201095a5dSDimitry Andric         MachineInstr &DeleteMI = *I;
39359d6cff9SDimitry Andric         MachineBasicBlock::instr_iterator BI = I.getInstrIterator();
39459d6cff9SDimitry Andric         while (++BI != E && BI->isBundledWithPred()) {
39559d6cff9SDimitry Andric           BI->unbundleFromPred();
39601095a5dSDimitry Andric           for (MachineOperand &MO : BI->operands()) {
39759d6cff9SDimitry Andric             if (MO.isReg() && MO.isInternalRead())
39859d6cff9SDimitry Andric               MO.setIsInternalRead(false);
39959d6cff9SDimitry Andric           }
40001095a5dSDimitry Andric           getLiteral(*BI, Literals);
401dd58ef01SDimitry Andric           ClauseContent.push_back(&*BI);
40259d6cff9SDimitry Andric         }
40359d6cff9SDimitry Andric         I = BI;
40401095a5dSDimitry Andric         DeleteMI.eraseFromParent();
40559d6cff9SDimitry Andric       } else {
40601095a5dSDimitry Andric         getLiteral(*I, Literals);
40701095a5dSDimitry Andric         ClauseContent.push_back(&*I);
40859d6cff9SDimitry Andric         I++;
40959d6cff9SDimitry Andric       }
41059d6cff9SDimitry Andric       for (unsigned i = 0, e = Literals.size(); i < e; i += 2) {
41101095a5dSDimitry Andric         MachineInstrBuilder MILit = BuildMI(MBB, I, I->getDebugLoc(),
412eb11fae6SDimitry Andric             TII->get(R600::LITERALS));
41301095a5dSDimitry Andric         if (Literals[i]->isImm()) {
41401095a5dSDimitry Andric             MILit.addImm(Literals[i]->getImm());
41501095a5dSDimitry Andric         } else {
41601095a5dSDimitry Andric             MILit.addGlobalAddress(Literals[i]->getGlobal(),
41701095a5dSDimitry Andric                                    Literals[i]->getOffset());
41801095a5dSDimitry Andric         }
41901095a5dSDimitry Andric         if (i + 1 < e) {
42001095a5dSDimitry Andric           if (Literals[i + 1]->isImm()) {
42101095a5dSDimitry Andric             MILit.addImm(Literals[i + 1]->getImm());
42201095a5dSDimitry Andric           } else {
42301095a5dSDimitry Andric             MILit.addGlobalAddress(Literals[i + 1]->getGlobal(),
42401095a5dSDimitry Andric                                    Literals[i + 1]->getOffset());
42501095a5dSDimitry Andric           }
42601095a5dSDimitry Andric         } else
42701095a5dSDimitry Andric           MILit.addImm(0);
42859d6cff9SDimitry Andric         ClauseContent.push_back(MILit);
42959d6cff9SDimitry Andric       }
43059d6cff9SDimitry Andric     }
431f8af5cf6SDimitry Andric     assert(ClauseContent.size() < 128 && "ALU clause is too big");
43201095a5dSDimitry Andric     ClauseHead.getOperand(7).setImm(ClauseContent.size() - 1);
43301095a5dSDimitry Andric     return ClauseFile(&ClauseHead, std::move(ClauseContent));
43459d6cff9SDimitry Andric   }
43559d6cff9SDimitry Andric 
EmitFetchClause(MachineBasicBlock::iterator InsertPos,const DebugLoc & DL,ClauseFile & Clause,unsigned & CfCount)436b915e9e0SDimitry Andric   void EmitFetchClause(MachineBasicBlock::iterator InsertPos,
437b915e9e0SDimitry Andric                        const DebugLoc &DL, ClauseFile &Clause,
43859d6cff9SDimitry Andric                        unsigned &CfCount) {
43901095a5dSDimitry Andric     CounterPropagateAddr(*Clause.first, CfCount);
44059d6cff9SDimitry Andric     MachineBasicBlock *BB = Clause.first->getParent();
441eb11fae6SDimitry Andric     BuildMI(BB, DL, TII->get(R600::FETCH_CLAUSE)).addImm(CfCount);
44277fc4c14SDimitry Andric     for (MachineInstr *MI : Clause.second)
44377fc4c14SDimitry Andric       BB->splice(InsertPos, BB, MI);
44459d6cff9SDimitry Andric     CfCount += 2 * Clause.second.size();
44559d6cff9SDimitry Andric   }
44659d6cff9SDimitry Andric 
EmitALUClause(MachineBasicBlock::iterator InsertPos,const DebugLoc & DL,ClauseFile & Clause,unsigned & CfCount)447b915e9e0SDimitry Andric   void EmitALUClause(MachineBasicBlock::iterator InsertPos, const DebugLoc &DL,
448b915e9e0SDimitry Andric                      ClauseFile &Clause, unsigned &CfCount) {
449f8af5cf6SDimitry Andric     Clause.first->getOperand(0).setImm(0);
45001095a5dSDimitry Andric     CounterPropagateAddr(*Clause.first, CfCount);
45159d6cff9SDimitry Andric     MachineBasicBlock *BB = Clause.first->getParent();
452eb11fae6SDimitry Andric     BuildMI(BB, DL, TII->get(R600::ALU_CLAUSE)).addImm(CfCount);
45377fc4c14SDimitry Andric     for (MachineInstr *MI : Clause.second)
45477fc4c14SDimitry Andric       BB->splice(InsertPos, BB, MI);
45559d6cff9SDimitry Andric     CfCount += Clause.second.size();
45659d6cff9SDimitry Andric   }
45759d6cff9SDimitry Andric 
CounterPropagateAddr(MachineInstr & MI,unsigned Addr) const45801095a5dSDimitry Andric   void CounterPropagateAddr(MachineInstr &MI, unsigned Addr) const {
45901095a5dSDimitry Andric     MI.getOperand(0).setImm(Addr + MI.getOperand(0).getImm());
4604a16efa3SDimitry Andric   }
CounterPropagateAddr(const std::set<MachineInstr * > & MIs,unsigned Addr) const46167c32a98SDimitry Andric   void CounterPropagateAddr(const std::set<MachineInstr *> &MIs,
46267c32a98SDimitry Andric                             unsigned Addr) const {
46367c32a98SDimitry Andric     for (MachineInstr *MI : MIs) {
46401095a5dSDimitry Andric       CounterPropagateAddr(*MI, Addr);
4654a16efa3SDimitry Andric     }
4664a16efa3SDimitry Andric   }
4674a16efa3SDimitry Andric 
4684a16efa3SDimitry Andric public:
469044eb2f6SDimitry Andric   static char ID;
470044eb2f6SDimitry Andric 
R600ControlFlowFinalizer()471b5630dbaSDimitry Andric   R600ControlFlowFinalizer() : MachineFunctionPass(ID) {}
4724a16efa3SDimitry Andric 
runOnMachineFunction(MachineFunction & MF)4735ca98fd9SDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override {
47401095a5dSDimitry Andric     ST = &MF.getSubtarget<R600Subtarget>();
4755a5ac124SDimitry Andric     MaxFetchInst = ST->getTexVTXClauseSize();
47601095a5dSDimitry Andric     TII = ST->getInstrInfo();
47701095a5dSDimitry Andric     TRI = ST->getRegisterInfo();
47801095a5dSDimitry Andric 
4795ca98fd9SDimitry Andric     R600MachineFunctionInfo *MFI = MF.getInfo<R600MachineFunctionInfo>();
480f8af5cf6SDimitry Andric 
481044eb2f6SDimitry Andric     CFStack CFStack(ST, MF.getFunction().getCallingConv());
4824a16efa3SDimitry Andric     for (MachineFunction::iterator MB = MF.begin(), ME = MF.end(); MB != ME;
4834a16efa3SDimitry Andric         ++MB) {
4844a16efa3SDimitry Andric       MachineBasicBlock &MBB = *MB;
4854a16efa3SDimitry Andric       unsigned CfCount = 0;
4864a16efa3SDimitry Andric       std::vector<std::pair<unsigned, std::set<MachineInstr *>>> LoopStack;
4874a16efa3SDimitry Andric       std::vector<MachineInstr * > IfThenElseStack;
488044eb2f6SDimitry Andric       if (MF.getFunction().getCallingConv() == CallingConv::AMDGPU_VS) {
4894a16efa3SDimitry Andric         BuildMI(MBB, MBB.begin(), MBB.findDebugLoc(MBB.begin()),
49059d6cff9SDimitry Andric             getHWInstrDesc(CF_CALL_FS));
4914a16efa3SDimitry Andric         CfCount++;
4924a16efa3SDimitry Andric       }
49359d6cff9SDimitry Andric       std::vector<ClauseFile> FetchClauses, AluClauses;
494f8af5cf6SDimitry Andric       std::vector<MachineInstr *> LastAlu(1);
495f8af5cf6SDimitry Andric       std::vector<MachineInstr *> ToPopAfter;
496f8af5cf6SDimitry Andric 
4974a16efa3SDimitry Andric       for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end();
4984a16efa3SDimitry Andric           I != E;) {
49901095a5dSDimitry Andric         if (TII->usesTextureCache(*I) || TII->usesVertexCache(*I)) {
500eb11fae6SDimitry Andric           LLVM_DEBUG(dbgs() << CfCount << ":"; I->dump(););
50159d6cff9SDimitry Andric           FetchClauses.push_back(MakeFetchClause(MBB, I));
5024a16efa3SDimitry Andric           CfCount++;
5035ca98fd9SDimitry Andric           LastAlu.back() = nullptr;
5044a16efa3SDimitry Andric           continue;
5054a16efa3SDimitry Andric         }
5064a16efa3SDimitry Andric 
5074a16efa3SDimitry Andric         MachineBasicBlock::iterator MI = I;
508eb11fae6SDimitry Andric         if (MI->getOpcode() != R600::ENDIF)
5095ca98fd9SDimitry Andric           LastAlu.back() = nullptr;
510eb11fae6SDimitry Andric         if (MI->getOpcode() == R600::CF_ALU)
51101095a5dSDimitry Andric           LastAlu.back() = &*MI;
5124a16efa3SDimitry Andric         I++;
5135ca98fd9SDimitry Andric         bool RequiresWorkAround =
5145ca98fd9SDimitry Andric             CFStack.requiresWorkAroundForInst(MI->getOpcode());
5154a16efa3SDimitry Andric         switch (MI->getOpcode()) {
516eb11fae6SDimitry Andric         case R600::CF_ALU_PUSH_BEFORE:
5175ca98fd9SDimitry Andric           if (RequiresWorkAround) {
518eb11fae6SDimitry Andric             LLVM_DEBUG(dbgs()
519eb11fae6SDimitry Andric                        << "Applying bug work-around for ALU_PUSH_BEFORE\n");
520eb11fae6SDimitry Andric             BuildMI(MBB, MI, MBB.findDebugLoc(MI), TII->get(R600::CF_PUSH_EG))
5215ca98fd9SDimitry Andric                 .addImm(CfCount + 1)
5225ca98fd9SDimitry Andric                 .addImm(1);
523eb11fae6SDimitry Andric             MI->setDesc(TII->get(R600::CF_ALU));
5245ca98fd9SDimitry Andric             CfCount++;
525eb11fae6SDimitry Andric             CFStack.pushBranch(R600::CF_PUSH_EG);
5265ca98fd9SDimitry Andric           } else
527eb11fae6SDimitry Andric             CFStack.pushBranch(R600::CF_ALU_PUSH_BEFORE);
528e3b55780SDimitry Andric           [[fallthrough]];
529eb11fae6SDimitry Andric         case R600::CF_ALU:
53059d6cff9SDimitry Andric           I = MI;
53159d6cff9SDimitry Andric           AluClauses.push_back(MakeALUClause(MBB, I));
532eb11fae6SDimitry Andric           LLVM_DEBUG(dbgs() << CfCount << ":"; MI->dump(););
5334a16efa3SDimitry Andric           CfCount++;
5344a16efa3SDimitry Andric           break;
535eb11fae6SDimitry Andric         case R600::WHILELOOP: {
5365ca98fd9SDimitry Andric           CFStack.pushLoop();
5374a16efa3SDimitry Andric           MachineInstr *MIb = BuildMI(MBB, MI, MBB.findDebugLoc(MI),
53859d6cff9SDimitry Andric               getHWInstrDesc(CF_WHILE_LOOP))
53959d6cff9SDimitry Andric               .addImm(1);
5404a16efa3SDimitry Andric           std::pair<unsigned, std::set<MachineInstr *>> Pair(CfCount,
5414a16efa3SDimitry Andric               std::set<MachineInstr *>());
5424a16efa3SDimitry Andric           Pair.second.insert(MIb);
54367c32a98SDimitry Andric           LoopStack.push_back(std::move(Pair));
5444a16efa3SDimitry Andric           MI->eraseFromParent();
5454a16efa3SDimitry Andric           CfCount++;
5464a16efa3SDimitry Andric           break;
5474a16efa3SDimitry Andric         }
548eb11fae6SDimitry Andric         case R600::ENDLOOP: {
5495ca98fd9SDimitry Andric           CFStack.popLoop();
5504a16efa3SDimitry Andric           std::pair<unsigned, std::set<MachineInstr *>> Pair =
55167c32a98SDimitry Andric               std::move(LoopStack.back());
5524a16efa3SDimitry Andric           LoopStack.pop_back();
5534a16efa3SDimitry Andric           CounterPropagateAddr(Pair.second, CfCount);
55459d6cff9SDimitry Andric           BuildMI(MBB, MI, MBB.findDebugLoc(MI), getHWInstrDesc(CF_END_LOOP))
5554a16efa3SDimitry Andric               .addImm(Pair.first + 1);
5564a16efa3SDimitry Andric           MI->eraseFromParent();
5574a16efa3SDimitry Andric           CfCount++;
5584a16efa3SDimitry Andric           break;
5594a16efa3SDimitry Andric         }
560eb11fae6SDimitry Andric         case R600::IF_PREDICATE_SET: {
5615ca98fd9SDimitry Andric           LastAlu.push_back(nullptr);
5624a16efa3SDimitry Andric           MachineInstr *MIb = BuildMI(MBB, MI, MBB.findDebugLoc(MI),
56359d6cff9SDimitry Andric               getHWInstrDesc(CF_JUMP))
5644a16efa3SDimitry Andric               .addImm(0)
5654a16efa3SDimitry Andric               .addImm(0);
5664a16efa3SDimitry Andric           IfThenElseStack.push_back(MIb);
567eb11fae6SDimitry Andric           LLVM_DEBUG(dbgs() << CfCount << ":"; MIb->dump(););
5684a16efa3SDimitry Andric           MI->eraseFromParent();
5694a16efa3SDimitry Andric           CfCount++;
5704a16efa3SDimitry Andric           break;
5714a16efa3SDimitry Andric         }
572eb11fae6SDimitry Andric         case R600::ELSE: {
5734a16efa3SDimitry Andric           MachineInstr * JumpInst = IfThenElseStack.back();
5744a16efa3SDimitry Andric           IfThenElseStack.pop_back();
57501095a5dSDimitry Andric           CounterPropagateAddr(*JumpInst, CfCount);
5764a16efa3SDimitry Andric           MachineInstr *MIb = BuildMI(MBB, MI, MBB.findDebugLoc(MI),
57759d6cff9SDimitry Andric               getHWInstrDesc(CF_ELSE))
5784a16efa3SDimitry Andric               .addImm(0)
579f8af5cf6SDimitry Andric               .addImm(0);
580eb11fae6SDimitry Andric           LLVM_DEBUG(dbgs() << CfCount << ":"; MIb->dump(););
5814a16efa3SDimitry Andric           IfThenElseStack.push_back(MIb);
5824a16efa3SDimitry Andric           MI->eraseFromParent();
5834a16efa3SDimitry Andric           CfCount++;
5844a16efa3SDimitry Andric           break;
5854a16efa3SDimitry Andric         }
586eb11fae6SDimitry Andric         case R600::ENDIF: {
5875ca98fd9SDimitry Andric           CFStack.popBranch();
588f8af5cf6SDimitry Andric           if (LastAlu.back()) {
589f8af5cf6SDimitry Andric             ToPopAfter.push_back(LastAlu.back());
590f8af5cf6SDimitry Andric           } else {
5914a16efa3SDimitry Andric             MachineInstr *MIb = BuildMI(MBB, MI, MBB.findDebugLoc(MI),
59259d6cff9SDimitry Andric                 getHWInstrDesc(CF_POP))
5934a16efa3SDimitry Andric                 .addImm(CfCount + 1)
5944a16efa3SDimitry Andric                 .addImm(1);
59559d6cff9SDimitry Andric             (void)MIb;
596eb11fae6SDimitry Andric             LLVM_DEBUG(dbgs() << CfCount << ":"; MIb->dump(););
5974a16efa3SDimitry Andric             CfCount++;
598f8af5cf6SDimitry Andric           }
599f8af5cf6SDimitry Andric 
600f8af5cf6SDimitry Andric           MachineInstr *IfOrElseInst = IfThenElseStack.back();
601f8af5cf6SDimitry Andric           IfThenElseStack.pop_back();
60201095a5dSDimitry Andric           CounterPropagateAddr(*IfOrElseInst, CfCount);
603f8af5cf6SDimitry Andric           IfOrElseInst->getOperand(1).setImm(1);
604f8af5cf6SDimitry Andric           LastAlu.pop_back();
605f8af5cf6SDimitry Andric           MI->eraseFromParent();
6064a16efa3SDimitry Andric           break;
6074a16efa3SDimitry Andric         }
608eb11fae6SDimitry Andric         case R600::BREAK: {
609f8af5cf6SDimitry Andric           CfCount ++;
6104a16efa3SDimitry Andric           MachineInstr *MIb = BuildMI(MBB, MI, MBB.findDebugLoc(MI),
61159d6cff9SDimitry Andric               getHWInstrDesc(CF_LOOP_BREAK))
6124a16efa3SDimitry Andric               .addImm(0);
6134a16efa3SDimitry Andric           LoopStack.back().second.insert(MIb);
6144a16efa3SDimitry Andric           MI->eraseFromParent();
6154a16efa3SDimitry Andric           break;
6164a16efa3SDimitry Andric         }
617eb11fae6SDimitry Andric         case R600::CONTINUE: {
6184a16efa3SDimitry Andric           MachineInstr *MIb = BuildMI(MBB, MI, MBB.findDebugLoc(MI),
61959d6cff9SDimitry Andric               getHWInstrDesc(CF_LOOP_CONTINUE))
6204a16efa3SDimitry Andric               .addImm(0);
6214a16efa3SDimitry Andric           LoopStack.back().second.insert(MIb);
6224a16efa3SDimitry Andric           MI->eraseFromParent();
6234a16efa3SDimitry Andric           CfCount++;
6244a16efa3SDimitry Andric           break;
6254a16efa3SDimitry Andric         }
626eb11fae6SDimitry Andric         case R600::RETURN: {
627b915e9e0SDimitry Andric           DebugLoc DL = MBB.findDebugLoc(MI);
628b915e9e0SDimitry Andric           BuildMI(MBB, MI, DL, getHWInstrDesc(CF_END));
62959d6cff9SDimitry Andric           CfCount++;
63059d6cff9SDimitry Andric           if (CfCount % 2) {
631eb11fae6SDimitry Andric             BuildMI(MBB, I, DL, TII->get(R600::PAD));
63259d6cff9SDimitry Andric             CfCount++;
63359d6cff9SDimitry Andric           }
63401095a5dSDimitry Andric           MI->eraseFromParent();
63577fc4c14SDimitry Andric           for (ClauseFile &CF : FetchClauses)
63677fc4c14SDimitry Andric             EmitFetchClause(I, DL, CF, CfCount);
63777fc4c14SDimitry Andric           for (ClauseFile &CF : AluClauses)
63877fc4c14SDimitry Andric             EmitALUClause(I, DL, CF, CfCount);
63901095a5dSDimitry Andric           break;
64059d6cff9SDimitry Andric         }
6414a16efa3SDimitry Andric         default:
642f8af5cf6SDimitry Andric           if (TII->isExport(MI->getOpcode())) {
643eb11fae6SDimitry Andric             LLVM_DEBUG(dbgs() << CfCount << ":"; MI->dump(););
644f8af5cf6SDimitry Andric             CfCount++;
645f8af5cf6SDimitry Andric           }
6464a16efa3SDimitry Andric           break;
6474a16efa3SDimitry Andric         }
6484a16efa3SDimitry Andric       }
64977fc4c14SDimitry Andric       for (MachineInstr *Alu : ToPopAfter) {
650f8af5cf6SDimitry Andric         BuildMI(MBB, Alu, MBB.findDebugLoc((MachineBasicBlock::iterator)Alu),
651eb11fae6SDimitry Andric             TII->get(R600::CF_ALU_POP_AFTER))
652f8af5cf6SDimitry Andric             .addImm(Alu->getOperand(0).getImm())
653f8af5cf6SDimitry Andric             .addImm(Alu->getOperand(1).getImm())
654f8af5cf6SDimitry Andric             .addImm(Alu->getOperand(2).getImm())
655f8af5cf6SDimitry Andric             .addImm(Alu->getOperand(3).getImm())
656f8af5cf6SDimitry Andric             .addImm(Alu->getOperand(4).getImm())
657f8af5cf6SDimitry Andric             .addImm(Alu->getOperand(5).getImm())
658f8af5cf6SDimitry Andric             .addImm(Alu->getOperand(6).getImm())
659f8af5cf6SDimitry Andric             .addImm(Alu->getOperand(7).getImm())
660f8af5cf6SDimitry Andric             .addImm(Alu->getOperand(8).getImm());
661f8af5cf6SDimitry Andric         Alu->eraseFromParent();
662f8af5cf6SDimitry Andric       }
663b915e9e0SDimitry Andric       MFI->CFStackSize = CFStack.MaxStackSize;
6644a16efa3SDimitry Andric     }
6654a16efa3SDimitry Andric 
6664a16efa3SDimitry Andric     return false;
6674a16efa3SDimitry Andric   }
6684a16efa3SDimitry Andric 
getPassName() const669b915e9e0SDimitry Andric   StringRef getPassName() const override {
6704a16efa3SDimitry Andric     return "R600 Control Flow Finalizer Pass";
6714a16efa3SDimitry Andric   }
6724a16efa3SDimitry Andric };
6734a16efa3SDimitry Andric 
674044eb2f6SDimitry Andric } // end anonymous namespace
675044eb2f6SDimitry Andric 
676044eb2f6SDimitry Andric INITIALIZE_PASS_BEGIN(R600ControlFlowFinalizer, DEBUG_TYPE,
677044eb2f6SDimitry Andric                      "R600 Control Flow Finalizer", false, false)
678044eb2f6SDimitry Andric INITIALIZE_PASS_END(R600ControlFlowFinalizer, DEBUG_TYPE,
679044eb2f6SDimitry Andric                     "R600 Control Flow Finalizer", false, false)
680044eb2f6SDimitry Andric 
6814a16efa3SDimitry Andric char R600ControlFlowFinalizer::ID = 0;
6824a16efa3SDimitry Andric 
683044eb2f6SDimitry Andric char &llvm::R600ControlFlowFinalizerID = R600ControlFlowFinalizer::ID;
6844a16efa3SDimitry Andric 
createR600ControlFlowFinalizer()685b5630dbaSDimitry Andric FunctionPass *llvm::createR600ControlFlowFinalizer() {
686b5630dbaSDimitry Andric   return new R600ControlFlowFinalizer();
6874a16efa3SDimitry Andric }
688