12cab237bSDimitry Andric //===- R600ControlFlowFinalizer.cpp - Finalize Control Flow Inst ----------===//
28f0fd8f6SDimitry Andric //
38f0fd8f6SDimitry Andric //                     The LLVM Compiler Infrastructure
48f0fd8f6SDimitry Andric //
58f0fd8f6SDimitry Andric // This file is distributed under the University of Illinois Open Source
68f0fd8f6SDimitry Andric // License. See LICENSE.TXT for details.
78f0fd8f6SDimitry Andric //
88f0fd8f6SDimitry Andric //===----------------------------------------------------------------------===//
98f0fd8f6SDimitry Andric //
108f0fd8f6SDimitry Andric /// \file
118f0fd8f6SDimitry Andric /// This pass compute turns all control flow pseudo instructions into native one
128f0fd8f6SDimitry Andric /// computing their address on the fly; it also sets STACK_SIZE info.
132cab237bSDimitry Andric //
148f0fd8f6SDimitry Andric //===----------------------------------------------------------------------===//
158f0fd8f6SDimitry Andric 
168f0fd8f6SDimitry Andric #include "AMDGPU.h"
178f0fd8f6SDimitry Andric #include "AMDGPUSubtarget.h"
188f0fd8f6SDimitry Andric #include "R600Defines.h"
198f0fd8f6SDimitry Andric #include "R600InstrInfo.h"
208f0fd8f6SDimitry Andric #include "R600MachineFunctionInfo.h"
218f0fd8f6SDimitry Andric #include "R600RegisterInfo.h"
22*4ba319b5SDimitry Andric #include "MCTargetDesc/AMDGPUMCTargetDesc.h"
237a7e6055SDimitry Andric #include "llvm/ADT/STLExtras.h"
24db17bf38SDimitry Andric #include "llvm/ADT/SmallVector.h"
257a7e6055SDimitry Andric #include "llvm/ADT/StringRef.h"
267a7e6055SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h"
277a7e6055SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
288f0fd8f6SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
297a7e6055SDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
308f0fd8f6SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
317a7e6055SDimitry Andric #include "llvm/CodeGen/MachineOperand.h"
327a7e6055SDimitry Andric #include "llvm/IR/CallingConv.h"
337a7e6055SDimitry Andric #include "llvm/IR/DebugLoc.h"
342cab237bSDimitry Andric #include "llvm/IR/Function.h"
352cab237bSDimitry Andric #include "llvm/Pass.h"
362cab237bSDimitry Andric #include "llvm/Support/Compiler.h"
37db17bf38SDimitry Andric #include "llvm/Support/Debug.h"
387a7e6055SDimitry Andric #include "llvm/Support/MathExtras.h"
398f0fd8f6SDimitry Andric #include "llvm/Support/raw_ostream.h"
407a7e6055SDimitry Andric #include <algorithm>
417a7e6055SDimitry Andric #include <cassert>
427a7e6055SDimitry Andric #include <cstdint>
437a7e6055SDimitry Andric #include <set>
447a7e6055SDimitry Andric #include <utility>
457a7e6055SDimitry Andric #include <vector>
468f0fd8f6SDimitry Andric 
478f0fd8f6SDimitry Andric using namespace llvm;
488f0fd8f6SDimitry Andric 
498f0fd8f6SDimitry Andric #define DEBUG_TYPE "r600cf"
508f0fd8f6SDimitry Andric 
518f0fd8f6SDimitry Andric namespace {
528f0fd8f6SDimitry Andric 
538f0fd8f6SDimitry Andric struct CFStack {
548f0fd8f6SDimitry Andric   enum StackItem {
558f0fd8f6SDimitry Andric     ENTRY = 0,
568f0fd8f6SDimitry Andric     SUB_ENTRY = 1,
578f0fd8f6SDimitry Andric     FIRST_NON_WQM_PUSH = 2,
588f0fd8f6SDimitry Andric     FIRST_NON_WQM_PUSH_W_FULL_ENTRY = 3
598f0fd8f6SDimitry Andric   };
608f0fd8f6SDimitry Andric 
613ca95b02SDimitry Andric   const R600Subtarget *ST;
628f0fd8f6SDimitry Andric   std::vector<StackItem> BranchStack;
638f0fd8f6SDimitry Andric   std::vector<StackItem> LoopStack;
648f0fd8f6SDimitry Andric   unsigned MaxStackSize;
657a7e6055SDimitry Andric   unsigned CurrentEntries = 0;
667a7e6055SDimitry Andric   unsigned CurrentSubEntries = 0;
678f0fd8f6SDimitry Andric 
CFStack__anonf80183fd0111::CFStack683ca95b02SDimitry Andric   CFStack(const R600Subtarget *st, CallingConv::ID cc) : ST(st),
698f0fd8f6SDimitry Andric       // We need to reserve a stack entry for CALL_FS in vertex shaders.
707a7e6055SDimitry Andric       MaxStackSize(cc == CallingConv::AMDGPU_VS ? 1 : 0) {}
718f0fd8f6SDimitry Andric 
728f0fd8f6SDimitry Andric   unsigned getLoopDepth();
738f0fd8f6SDimitry Andric   bool branchStackContains(CFStack::StackItem);
748f0fd8f6SDimitry Andric   bool requiresWorkAroundForInst(unsigned Opcode);
758f0fd8f6SDimitry Andric   unsigned getSubEntrySize(CFStack::StackItem Item);
768f0fd8f6SDimitry Andric   void updateMaxStackSize();
778f0fd8f6SDimitry Andric   void pushBranch(unsigned Opcode, bool isWQM = false);
788f0fd8f6SDimitry Andric   void pushLoop();
798f0fd8f6SDimitry Andric   void popBranch();
808f0fd8f6SDimitry Andric   void popLoop();
818f0fd8f6SDimitry Andric };
828f0fd8f6SDimitry Andric 
getLoopDepth()838f0fd8f6SDimitry Andric unsigned CFStack::getLoopDepth() {
848f0fd8f6SDimitry Andric   return LoopStack.size();
858f0fd8f6SDimitry Andric }
868f0fd8f6SDimitry Andric 
branchStackContains(CFStack::StackItem Item)878f0fd8f6SDimitry Andric bool CFStack::branchStackContains(CFStack::StackItem Item) {
888f0fd8f6SDimitry Andric   for (std::vector<CFStack::StackItem>::const_iterator I = BranchStack.begin(),
898f0fd8f6SDimitry Andric        E = BranchStack.end(); I != E; ++I) {
908f0fd8f6SDimitry Andric     if (*I == Item)
918f0fd8f6SDimitry Andric       return true;
928f0fd8f6SDimitry Andric   }
938f0fd8f6SDimitry Andric   return false;
948f0fd8f6SDimitry Andric }
958f0fd8f6SDimitry Andric 
requiresWorkAroundForInst(unsigned Opcode)968f0fd8f6SDimitry Andric bool CFStack::requiresWorkAroundForInst(unsigned Opcode) {
97*4ba319b5SDimitry Andric   if (Opcode == R600::CF_ALU_PUSH_BEFORE && ST->hasCaymanISA() &&
988f0fd8f6SDimitry Andric       getLoopDepth() > 1)
998f0fd8f6SDimitry Andric     return true;
1008f0fd8f6SDimitry Andric 
1018f0fd8f6SDimitry Andric   if (!ST->hasCFAluBug())
1028f0fd8f6SDimitry Andric     return false;
1038f0fd8f6SDimitry Andric 
1048f0fd8f6SDimitry Andric   switch(Opcode) {
1058f0fd8f6SDimitry Andric   default: return false;
106*4ba319b5SDimitry Andric   case R600::CF_ALU_PUSH_BEFORE:
107*4ba319b5SDimitry Andric   case R600::CF_ALU_ELSE_AFTER:
108*4ba319b5SDimitry Andric   case R600::CF_ALU_BREAK:
109*4ba319b5SDimitry Andric   case R600::CF_ALU_CONTINUE:
1108f0fd8f6SDimitry Andric     if (CurrentSubEntries == 0)
1118f0fd8f6SDimitry Andric       return false;
1128f0fd8f6SDimitry Andric     if (ST->getWavefrontSize() == 64) {
1138f0fd8f6SDimitry Andric       // We are being conservative here.  We only require this work-around if
1148f0fd8f6SDimitry Andric       // CurrentSubEntries > 3 &&
1158f0fd8f6SDimitry Andric       // (CurrentSubEntries % 4 == 3 || CurrentSubEntries % 4 == 0)
1168f0fd8f6SDimitry Andric       //
1178f0fd8f6SDimitry Andric       // We have to be conservative, because we don't know for certain that
1188f0fd8f6SDimitry Andric       // our stack allocation algorithm for Evergreen/NI is correct.  Applying this
1198f0fd8f6SDimitry Andric       // work-around when CurrentSubEntries > 3 allows us to over-allocate stack
1208f0fd8f6SDimitry Andric       // resources without any problems.
1218f0fd8f6SDimitry Andric       return CurrentSubEntries > 3;
1228f0fd8f6SDimitry Andric     } else {
1238f0fd8f6SDimitry Andric       assert(ST->getWavefrontSize() == 32);
1248f0fd8f6SDimitry Andric       // We are being conservative here.  We only require the work-around if
1258f0fd8f6SDimitry Andric       // CurrentSubEntries > 7 &&
1268f0fd8f6SDimitry Andric       // (CurrentSubEntries % 8 == 7 || CurrentSubEntries % 8 == 0)
1278f0fd8f6SDimitry Andric       // See the comment on the wavefront size == 64 case for why we are
1288f0fd8f6SDimitry Andric       // being conservative.
1298f0fd8f6SDimitry Andric       return CurrentSubEntries > 7;
1308f0fd8f6SDimitry Andric     }
1318f0fd8f6SDimitry Andric   }
1328f0fd8f6SDimitry Andric }
1338f0fd8f6SDimitry Andric 
getSubEntrySize(CFStack::StackItem Item)1348f0fd8f6SDimitry Andric unsigned CFStack::getSubEntrySize(CFStack::StackItem Item) {
1358f0fd8f6SDimitry Andric   switch(Item) {
1368f0fd8f6SDimitry Andric   default:
1378f0fd8f6SDimitry Andric     return 0;
1388f0fd8f6SDimitry Andric   case CFStack::FIRST_NON_WQM_PUSH:
1398f0fd8f6SDimitry Andric   assert(!ST->hasCaymanISA());
140*4ba319b5SDimitry Andric   if (ST->getGeneration() <= AMDGPUSubtarget::R700) {
1418f0fd8f6SDimitry Andric     // +1 For the push operation.
1428f0fd8f6SDimitry Andric     // +2 Extra space required.
1438f0fd8f6SDimitry Andric     return 3;
1448f0fd8f6SDimitry Andric   } else {
1458f0fd8f6SDimitry Andric     // Some documentation says that this is not necessary on Evergreen,
1468f0fd8f6SDimitry Andric     // but experimentation has show that we need to allocate 1 extra
1478f0fd8f6SDimitry Andric     // sub-entry for the first non-WQM push.
1488f0fd8f6SDimitry Andric     // +1 For the push operation.
1498f0fd8f6SDimitry Andric     // +1 Extra space required.
1508f0fd8f6SDimitry Andric     return 2;
1518f0fd8f6SDimitry Andric   }
1528f0fd8f6SDimitry Andric   case CFStack::FIRST_NON_WQM_PUSH_W_FULL_ENTRY:
153*4ba319b5SDimitry Andric     assert(ST->getGeneration() >= AMDGPUSubtarget::EVERGREEN);
1548f0fd8f6SDimitry Andric     // +1 For the push operation.
1558f0fd8f6SDimitry Andric     // +1 Extra space required.
1568f0fd8f6SDimitry Andric     return 2;
1578f0fd8f6SDimitry Andric   case CFStack::SUB_ENTRY:
1588f0fd8f6SDimitry Andric     return 1;
1598f0fd8f6SDimitry Andric   }
1608f0fd8f6SDimitry Andric }
1618f0fd8f6SDimitry Andric 
updateMaxStackSize()1628f0fd8f6SDimitry Andric void CFStack::updateMaxStackSize() {
1633ca95b02SDimitry Andric   unsigned CurrentStackSize =
1643ca95b02SDimitry Andric       CurrentEntries + (alignTo(CurrentSubEntries, 4) / 4);
1658f0fd8f6SDimitry Andric   MaxStackSize = std::max(CurrentStackSize, MaxStackSize);
1668f0fd8f6SDimitry Andric }
1678f0fd8f6SDimitry Andric 
pushBranch(unsigned Opcode,bool isWQM)1688f0fd8f6SDimitry Andric void CFStack::pushBranch(unsigned Opcode, bool isWQM) {
1698f0fd8f6SDimitry Andric   CFStack::StackItem Item = CFStack::ENTRY;
1708f0fd8f6SDimitry Andric   switch(Opcode) {
171*4ba319b5SDimitry Andric   case R600::CF_PUSH_EG:
172*4ba319b5SDimitry Andric   case R600::CF_ALU_PUSH_BEFORE:
1738f0fd8f6SDimitry Andric     if (!isWQM) {
1748f0fd8f6SDimitry Andric       if (!ST->hasCaymanISA() &&
1758f0fd8f6SDimitry Andric           !branchStackContains(CFStack::FIRST_NON_WQM_PUSH))
1768f0fd8f6SDimitry Andric         Item = CFStack::FIRST_NON_WQM_PUSH;  // May not be required on Evergreen/NI
1778f0fd8f6SDimitry Andric                                              // See comment in
1788f0fd8f6SDimitry Andric                                              // CFStack::getSubEntrySize()
1798f0fd8f6SDimitry Andric       else if (CurrentEntries > 0 &&
180*4ba319b5SDimitry Andric                ST->getGeneration() > AMDGPUSubtarget::EVERGREEN &&
1818f0fd8f6SDimitry Andric                !ST->hasCaymanISA() &&
1828f0fd8f6SDimitry Andric                !branchStackContains(CFStack::FIRST_NON_WQM_PUSH_W_FULL_ENTRY))
1838f0fd8f6SDimitry Andric         Item = CFStack::FIRST_NON_WQM_PUSH_W_FULL_ENTRY;
1848f0fd8f6SDimitry Andric       else
1858f0fd8f6SDimitry Andric         Item = CFStack::SUB_ENTRY;
1868f0fd8f6SDimitry Andric     } else
1878f0fd8f6SDimitry Andric       Item = CFStack::ENTRY;
1888f0fd8f6SDimitry Andric     break;
1898f0fd8f6SDimitry Andric   }
1908f0fd8f6SDimitry Andric   BranchStack.push_back(Item);
1918f0fd8f6SDimitry Andric   if (Item == CFStack::ENTRY)
1928f0fd8f6SDimitry Andric     CurrentEntries++;
1938f0fd8f6SDimitry Andric   else
1948f0fd8f6SDimitry Andric     CurrentSubEntries += getSubEntrySize(Item);
1958f0fd8f6SDimitry Andric   updateMaxStackSize();
1968f0fd8f6SDimitry Andric }
1978f0fd8f6SDimitry Andric 
pushLoop()1988f0fd8f6SDimitry Andric void CFStack::pushLoop() {
1998f0fd8f6SDimitry Andric   LoopStack.push_back(CFStack::ENTRY);
2008f0fd8f6SDimitry Andric   CurrentEntries++;
2018f0fd8f6SDimitry Andric   updateMaxStackSize();
2028f0fd8f6SDimitry Andric }
2038f0fd8f6SDimitry Andric 
popBranch()2048f0fd8f6SDimitry Andric void CFStack::popBranch() {
2058f0fd8f6SDimitry Andric   CFStack::StackItem Top = BranchStack.back();
2068f0fd8f6SDimitry Andric   if (Top == CFStack::ENTRY)
2078f0fd8f6SDimitry Andric     CurrentEntries--;
2088f0fd8f6SDimitry Andric   else
2098f0fd8f6SDimitry Andric     CurrentSubEntries-= getSubEntrySize(Top);
2108f0fd8f6SDimitry Andric   BranchStack.pop_back();
2118f0fd8f6SDimitry Andric }
2128f0fd8f6SDimitry Andric 
popLoop()2138f0fd8f6SDimitry Andric void CFStack::popLoop() {
2148f0fd8f6SDimitry Andric   CurrentEntries--;
2158f0fd8f6SDimitry Andric   LoopStack.pop_back();
2168f0fd8f6SDimitry Andric }
2178f0fd8f6SDimitry Andric 
2188f0fd8f6SDimitry Andric class R600ControlFlowFinalizer : public MachineFunctionPass {
2198f0fd8f6SDimitry Andric private:
2202cab237bSDimitry Andric   using ClauseFile = std::pair<MachineInstr *, std::vector<MachineInstr *>>;
2218f0fd8f6SDimitry Andric 
2228f0fd8f6SDimitry Andric   enum ControlFlowInstruction {
2238f0fd8f6SDimitry Andric     CF_TC,
2248f0fd8f6SDimitry Andric     CF_VC,
2258f0fd8f6SDimitry Andric     CF_CALL_FS,
2268f0fd8f6SDimitry Andric     CF_WHILE_LOOP,
2278f0fd8f6SDimitry Andric     CF_END_LOOP,
2288f0fd8f6SDimitry Andric     CF_LOOP_BREAK,
2298f0fd8f6SDimitry Andric     CF_LOOP_CONTINUE,
2308f0fd8f6SDimitry Andric     CF_JUMP,
2318f0fd8f6SDimitry Andric     CF_ELSE,
2328f0fd8f6SDimitry Andric     CF_POP,
2338f0fd8f6SDimitry Andric     CF_END
2348f0fd8f6SDimitry Andric   };
2358f0fd8f6SDimitry Andric 
2367a7e6055SDimitry Andric   const R600InstrInfo *TII = nullptr;
2377a7e6055SDimitry Andric   const R600RegisterInfo *TRI = nullptr;
2388f0fd8f6SDimitry Andric   unsigned MaxFetchInst;
2397a7e6055SDimitry Andric   const R600Subtarget *ST = nullptr;
2408f0fd8f6SDimitry Andric 
IsTrivialInst(MachineInstr & MI) const2413ca95b02SDimitry Andric   bool IsTrivialInst(MachineInstr &MI) const {
2423ca95b02SDimitry Andric     switch (MI.getOpcode()) {
243*4ba319b5SDimitry Andric     case R600::KILL:
244*4ba319b5SDimitry Andric     case R600::RETURN:
2458f0fd8f6SDimitry Andric       return true;
2468f0fd8f6SDimitry Andric     default:
2478f0fd8f6SDimitry Andric       return false;
2488f0fd8f6SDimitry Andric     }
2498f0fd8f6SDimitry Andric   }
2508f0fd8f6SDimitry Andric 
getHWInstrDesc(ControlFlowInstruction CFI) const2518f0fd8f6SDimitry Andric   const MCInstrDesc &getHWInstrDesc(ControlFlowInstruction CFI) const {
2528f0fd8f6SDimitry Andric     unsigned Opcode = 0;
253*4ba319b5SDimitry Andric     bool isEg = (ST->getGeneration() >= AMDGPUSubtarget::EVERGREEN);
2548f0fd8f6SDimitry Andric     switch (CFI) {
2558f0fd8f6SDimitry Andric     case CF_TC:
256*4ba319b5SDimitry Andric       Opcode = isEg ? R600::CF_TC_EG : R600::CF_TC_R600;
2578f0fd8f6SDimitry Andric       break;
2588f0fd8f6SDimitry Andric     case CF_VC:
259*4ba319b5SDimitry Andric       Opcode = isEg ? R600::CF_VC_EG : R600::CF_VC_R600;
2608f0fd8f6SDimitry Andric       break;
2618f0fd8f6SDimitry Andric     case CF_CALL_FS:
262*4ba319b5SDimitry Andric       Opcode = isEg ? R600::CF_CALL_FS_EG : R600::CF_CALL_FS_R600;
2638f0fd8f6SDimitry Andric       break;
2648f0fd8f6SDimitry Andric     case CF_WHILE_LOOP:
265*4ba319b5SDimitry Andric       Opcode = isEg ? R600::WHILE_LOOP_EG : R600::WHILE_LOOP_R600;
2668f0fd8f6SDimitry Andric       break;
2678f0fd8f6SDimitry Andric     case CF_END_LOOP:
268*4ba319b5SDimitry Andric       Opcode = isEg ? R600::END_LOOP_EG : R600::END_LOOP_R600;
2698f0fd8f6SDimitry Andric       break;
2708f0fd8f6SDimitry Andric     case CF_LOOP_BREAK:
271*4ba319b5SDimitry Andric       Opcode = isEg ? R600::LOOP_BREAK_EG : R600::LOOP_BREAK_R600;
2728f0fd8f6SDimitry Andric       break;
2738f0fd8f6SDimitry Andric     case CF_LOOP_CONTINUE:
274*4ba319b5SDimitry Andric       Opcode = isEg ? R600::CF_CONTINUE_EG : R600::CF_CONTINUE_R600;
2758f0fd8f6SDimitry Andric       break;
2768f0fd8f6SDimitry Andric     case CF_JUMP:
277*4ba319b5SDimitry Andric       Opcode = isEg ? R600::CF_JUMP_EG : R600::CF_JUMP_R600;
2788f0fd8f6SDimitry Andric       break;
2798f0fd8f6SDimitry Andric     case CF_ELSE:
280*4ba319b5SDimitry Andric       Opcode = isEg ? R600::CF_ELSE_EG : R600::CF_ELSE_R600;
2818f0fd8f6SDimitry Andric       break;
2828f0fd8f6SDimitry Andric     case CF_POP:
283*4ba319b5SDimitry Andric       Opcode = isEg ? R600::POP_EG : R600::POP_R600;
2848f0fd8f6SDimitry Andric       break;
2858f0fd8f6SDimitry Andric     case CF_END:
2868f0fd8f6SDimitry Andric       if (ST->hasCaymanISA()) {
287*4ba319b5SDimitry Andric         Opcode = R600::CF_END_CM;
2888f0fd8f6SDimitry Andric         break;
2898f0fd8f6SDimitry Andric       }
290*4ba319b5SDimitry Andric       Opcode = isEg ? R600::CF_END_EG : R600::CF_END_R600;
2918f0fd8f6SDimitry Andric       break;
2928f0fd8f6SDimitry Andric     }
2938f0fd8f6SDimitry Andric     assert (Opcode && "No opcode selected");
2948f0fd8f6SDimitry Andric     return TII->get(Opcode);
2958f0fd8f6SDimitry Andric   }
2968f0fd8f6SDimitry Andric 
isCompatibleWithClause(const MachineInstr & MI,std::set<unsigned> & DstRegs) const2973ca95b02SDimitry Andric   bool isCompatibleWithClause(const MachineInstr &MI,
2988f0fd8f6SDimitry Andric                               std::set<unsigned> &DstRegs) const {
2998f0fd8f6SDimitry Andric     unsigned DstMI, SrcMI;
3003ca95b02SDimitry Andric     for (MachineInstr::const_mop_iterator I = MI.operands_begin(),
3013ca95b02SDimitry Andric                                           E = MI.operands_end();
3023ca95b02SDimitry Andric          I != E; ++I) {
3038f0fd8f6SDimitry Andric       const MachineOperand &MO = *I;
3048f0fd8f6SDimitry Andric       if (!MO.isReg())
3058f0fd8f6SDimitry Andric         continue;
3068f0fd8f6SDimitry Andric       if (MO.isDef()) {
3078f0fd8f6SDimitry Andric         unsigned Reg = MO.getReg();
308*4ba319b5SDimitry Andric         if (R600::R600_Reg128RegClass.contains(Reg))
3098f0fd8f6SDimitry Andric           DstMI = Reg;
3108f0fd8f6SDimitry Andric         else
3118f0fd8f6SDimitry Andric           DstMI = TRI->getMatchingSuperReg(Reg,
312*4ba319b5SDimitry Andric               AMDGPURegisterInfo::getSubRegFromChannel(TRI->getHWRegChan(Reg)),
313*4ba319b5SDimitry Andric               &R600::R600_Reg128RegClass);
3148f0fd8f6SDimitry Andric       }
3158f0fd8f6SDimitry Andric       if (MO.isUse()) {
3168f0fd8f6SDimitry Andric         unsigned Reg = MO.getReg();
317*4ba319b5SDimitry Andric         if (R600::R600_Reg128RegClass.contains(Reg))
3188f0fd8f6SDimitry Andric           SrcMI = Reg;
3198f0fd8f6SDimitry Andric         else
3208f0fd8f6SDimitry Andric           SrcMI = TRI->getMatchingSuperReg(Reg,
321*4ba319b5SDimitry Andric               AMDGPURegisterInfo::getSubRegFromChannel(TRI->getHWRegChan(Reg)),
322*4ba319b5SDimitry Andric               &R600::R600_Reg128RegClass);
3238f0fd8f6SDimitry Andric       }
3248f0fd8f6SDimitry Andric     }
3258f0fd8f6SDimitry Andric     if ((DstRegs.find(SrcMI) == DstRegs.end())) {
3268f0fd8f6SDimitry Andric       DstRegs.insert(DstMI);
3278f0fd8f6SDimitry Andric       return true;
3288f0fd8f6SDimitry Andric     } else
3298f0fd8f6SDimitry Andric       return false;
3308f0fd8f6SDimitry Andric   }
3318f0fd8f6SDimitry Andric 
3328f0fd8f6SDimitry Andric   ClauseFile
MakeFetchClause(MachineBasicBlock & MBB,MachineBasicBlock::iterator & I) const3338f0fd8f6SDimitry Andric   MakeFetchClause(MachineBasicBlock &MBB, MachineBasicBlock::iterator &I)
3348f0fd8f6SDimitry Andric       const {
3358f0fd8f6SDimitry Andric     MachineBasicBlock::iterator ClauseHead = I;
3368f0fd8f6SDimitry Andric     std::vector<MachineInstr *> ClauseContent;
3378f0fd8f6SDimitry Andric     unsigned AluInstCount = 0;
3383ca95b02SDimitry Andric     bool IsTex = TII->usesTextureCache(*ClauseHead);
3398f0fd8f6SDimitry Andric     std::set<unsigned> DstRegs;
3408f0fd8f6SDimitry Andric     for (MachineBasicBlock::iterator E = MBB.end(); I != E; ++I) {
3413ca95b02SDimitry Andric       if (IsTrivialInst(*I))
3428f0fd8f6SDimitry Andric         continue;
3438f0fd8f6SDimitry Andric       if (AluInstCount >= MaxFetchInst)
3448f0fd8f6SDimitry Andric         break;
3453ca95b02SDimitry Andric       if ((IsTex && !TII->usesTextureCache(*I)) ||
3463ca95b02SDimitry Andric           (!IsTex && !TII->usesVertexCache(*I)))
3478f0fd8f6SDimitry Andric         break;
3483ca95b02SDimitry Andric       if (!isCompatibleWithClause(*I, DstRegs))
3498f0fd8f6SDimitry Andric         break;
3508f0fd8f6SDimitry Andric       AluInstCount ++;
3513ca95b02SDimitry Andric       ClauseContent.push_back(&*I);
3528f0fd8f6SDimitry Andric     }
3538f0fd8f6SDimitry Andric     MachineInstr *MIb = BuildMI(MBB, ClauseHead, MBB.findDebugLoc(ClauseHead),
3548f0fd8f6SDimitry Andric         getHWInstrDesc(IsTex?CF_TC:CF_VC))
3558f0fd8f6SDimitry Andric         .addImm(0) // ADDR
3568f0fd8f6SDimitry Andric         .addImm(AluInstCount - 1); // COUNT
3578f0fd8f6SDimitry Andric     return ClauseFile(MIb, std::move(ClauseContent));
3588f0fd8f6SDimitry Andric   }
3598f0fd8f6SDimitry Andric 
getLiteral(MachineInstr & MI,std::vector<MachineOperand * > & Lits) const3603ca95b02SDimitry Andric   void getLiteral(MachineInstr &MI, std::vector<MachineOperand *> &Lits) const {
3618f0fd8f6SDimitry Andric     static const unsigned LiteralRegs[] = {
362*4ba319b5SDimitry Andric       R600::ALU_LITERAL_X,
363*4ba319b5SDimitry Andric       R600::ALU_LITERAL_Y,
364*4ba319b5SDimitry Andric       R600::ALU_LITERAL_Z,
365*4ba319b5SDimitry Andric       R600::ALU_LITERAL_W
3668f0fd8f6SDimitry Andric     };
3678f0fd8f6SDimitry Andric     const SmallVector<std::pair<MachineOperand *, int64_t>, 3> Srcs =
3688f0fd8f6SDimitry Andric         TII->getSrcs(MI);
3693ca95b02SDimitry Andric     for (const auto &Src:Srcs) {
370*4ba319b5SDimitry Andric       if (Src.first->getReg() != R600::ALU_LITERAL_X)
3718f0fd8f6SDimitry Andric         continue;
3723ca95b02SDimitry Andric       int64_t Imm = Src.second;
3733ca95b02SDimitry Andric       std::vector<MachineOperand *>::iterator It =
3747a7e6055SDimitry Andric           llvm::find_if(Lits, [&](MachineOperand *val) {
375d88c1a5aSDimitry Andric             return val->isImm() && (val->getImm() == Imm);
376d88c1a5aSDimitry Andric           });
3773ca95b02SDimitry Andric 
3783ca95b02SDimitry Andric       // Get corresponding Operand
3793ca95b02SDimitry Andric       MachineOperand &Operand = MI.getOperand(
380*4ba319b5SDimitry Andric           TII->getOperandIdx(MI.getOpcode(), R600::OpName::literal));
3813ca95b02SDimitry Andric 
3828f0fd8f6SDimitry Andric       if (It != Lits.end()) {
3833ca95b02SDimitry Andric         // Reuse existing literal reg
3848f0fd8f6SDimitry Andric         unsigned Index = It - Lits.begin();
3853ca95b02SDimitry Andric         Src.first->setReg(LiteralRegs[Index]);
3868f0fd8f6SDimitry Andric       } else {
3873ca95b02SDimitry Andric         // Allocate new literal reg
3888f0fd8f6SDimitry Andric         assert(Lits.size() < 4 && "Too many literals in Instruction Group");
3893ca95b02SDimitry Andric         Src.first->setReg(LiteralRegs[Lits.size()]);
3903ca95b02SDimitry Andric         Lits.push_back(&Operand);
3918f0fd8f6SDimitry Andric       }
3928f0fd8f6SDimitry Andric     }
3938f0fd8f6SDimitry Andric   }
3948f0fd8f6SDimitry Andric 
insertLiterals(MachineBasicBlock::iterator InsertPos,const std::vector<unsigned> & Literals) const3958f0fd8f6SDimitry Andric   MachineBasicBlock::iterator insertLiterals(
3968f0fd8f6SDimitry Andric       MachineBasicBlock::iterator InsertPos,
3978f0fd8f6SDimitry Andric       const std::vector<unsigned> &Literals) const {
3988f0fd8f6SDimitry Andric     MachineBasicBlock *MBB = InsertPos->getParent();
3998f0fd8f6SDimitry Andric     for (unsigned i = 0, e = Literals.size(); i < e; i+=2) {
4008f0fd8f6SDimitry Andric       unsigned LiteralPair0 = Literals[i];
4018f0fd8f6SDimitry Andric       unsigned LiteralPair1 = (i + 1 < e)?Literals[i + 1]:0;
4028f0fd8f6SDimitry Andric       InsertPos = BuildMI(MBB, InsertPos->getDebugLoc(),
403*4ba319b5SDimitry Andric           TII->get(R600::LITERALS))
4048f0fd8f6SDimitry Andric           .addImm(LiteralPair0)
4058f0fd8f6SDimitry Andric           .addImm(LiteralPair1);
4068f0fd8f6SDimitry Andric     }
4078f0fd8f6SDimitry Andric     return InsertPos;
4088f0fd8f6SDimitry Andric   }
4098f0fd8f6SDimitry Andric 
4108f0fd8f6SDimitry Andric   ClauseFile
MakeALUClause(MachineBasicBlock & MBB,MachineBasicBlock::iterator & I) const4118f0fd8f6SDimitry Andric   MakeALUClause(MachineBasicBlock &MBB, MachineBasicBlock::iterator &I)
4128f0fd8f6SDimitry Andric       const {
4133ca95b02SDimitry Andric     MachineInstr &ClauseHead = *I;
4148f0fd8f6SDimitry Andric     std::vector<MachineInstr *> ClauseContent;
4158f0fd8f6SDimitry Andric     I++;
4168f0fd8f6SDimitry Andric     for (MachineBasicBlock::instr_iterator E = MBB.instr_end(); I != E;) {
4173ca95b02SDimitry Andric       if (IsTrivialInst(*I)) {
4188f0fd8f6SDimitry Andric         ++I;
4198f0fd8f6SDimitry Andric         continue;
4208f0fd8f6SDimitry Andric       }
4218f0fd8f6SDimitry Andric       if (!I->isBundle() && !TII->isALUInstr(I->getOpcode()))
4228f0fd8f6SDimitry Andric         break;
4233ca95b02SDimitry Andric       std::vector<MachineOperand *>Literals;
4248f0fd8f6SDimitry Andric       if (I->isBundle()) {
4253ca95b02SDimitry Andric         MachineInstr &DeleteMI = *I;
4268f0fd8f6SDimitry Andric         MachineBasicBlock::instr_iterator BI = I.getInstrIterator();
4278f0fd8f6SDimitry Andric         while (++BI != E && BI->isBundledWithPred()) {
4288f0fd8f6SDimitry Andric           BI->unbundleFromPred();
4293ca95b02SDimitry Andric           for (MachineOperand &MO : BI->operands()) {
4308f0fd8f6SDimitry Andric             if (MO.isReg() && MO.isInternalRead())
4318f0fd8f6SDimitry Andric               MO.setIsInternalRead(false);
4328f0fd8f6SDimitry Andric           }
4333ca95b02SDimitry Andric           getLiteral(*BI, Literals);
4347d523365SDimitry Andric           ClauseContent.push_back(&*BI);
4358f0fd8f6SDimitry Andric         }
4368f0fd8f6SDimitry Andric         I = BI;
4373ca95b02SDimitry Andric         DeleteMI.eraseFromParent();
4388f0fd8f6SDimitry Andric       } else {
4393ca95b02SDimitry Andric         getLiteral(*I, Literals);
4403ca95b02SDimitry Andric         ClauseContent.push_back(&*I);
4418f0fd8f6SDimitry Andric         I++;
4428f0fd8f6SDimitry Andric       }
4438f0fd8f6SDimitry Andric       for (unsigned i = 0, e = Literals.size(); i < e; i += 2) {
4443ca95b02SDimitry Andric         MachineInstrBuilder MILit = BuildMI(MBB, I, I->getDebugLoc(),
445*4ba319b5SDimitry Andric             TII->get(R600::LITERALS));
4463ca95b02SDimitry Andric         if (Literals[i]->isImm()) {
4473ca95b02SDimitry Andric             MILit.addImm(Literals[i]->getImm());
4483ca95b02SDimitry Andric         } else {
4493ca95b02SDimitry Andric             MILit.addGlobalAddress(Literals[i]->getGlobal(),
4503ca95b02SDimitry Andric                                    Literals[i]->getOffset());
4513ca95b02SDimitry Andric         }
4523ca95b02SDimitry Andric         if (i + 1 < e) {
4533ca95b02SDimitry Andric           if (Literals[i + 1]->isImm()) {
4543ca95b02SDimitry Andric             MILit.addImm(Literals[i + 1]->getImm());
4553ca95b02SDimitry Andric           } else {
4563ca95b02SDimitry Andric             MILit.addGlobalAddress(Literals[i + 1]->getGlobal(),
4573ca95b02SDimitry Andric                                    Literals[i + 1]->getOffset());
4583ca95b02SDimitry Andric           }
4593ca95b02SDimitry Andric         } else
4603ca95b02SDimitry Andric           MILit.addImm(0);
4618f0fd8f6SDimitry Andric         ClauseContent.push_back(MILit);
4628f0fd8f6SDimitry Andric       }
4638f0fd8f6SDimitry Andric     }
4648f0fd8f6SDimitry Andric     assert(ClauseContent.size() < 128 && "ALU clause is too big");
4653ca95b02SDimitry Andric     ClauseHead.getOperand(7).setImm(ClauseContent.size() - 1);
4663ca95b02SDimitry Andric     return ClauseFile(&ClauseHead, std::move(ClauseContent));
4678f0fd8f6SDimitry Andric   }
4688f0fd8f6SDimitry Andric 
EmitFetchClause(MachineBasicBlock::iterator InsertPos,const DebugLoc & DL,ClauseFile & Clause,unsigned & CfCount)469d88c1a5aSDimitry Andric   void EmitFetchClause(MachineBasicBlock::iterator InsertPos,
470d88c1a5aSDimitry Andric                        const DebugLoc &DL, ClauseFile &Clause,
4718f0fd8f6SDimitry Andric                        unsigned &CfCount) {
4723ca95b02SDimitry Andric     CounterPropagateAddr(*Clause.first, CfCount);
4738f0fd8f6SDimitry Andric     MachineBasicBlock *BB = Clause.first->getParent();
474*4ba319b5SDimitry Andric     BuildMI(BB, DL, TII->get(R600::FETCH_CLAUSE)).addImm(CfCount);
4758f0fd8f6SDimitry Andric     for (unsigned i = 0, e = Clause.second.size(); i < e; ++i) {
4768f0fd8f6SDimitry Andric       BB->splice(InsertPos, BB, Clause.second[i]);
4778f0fd8f6SDimitry Andric     }
4788f0fd8f6SDimitry Andric     CfCount += 2 * Clause.second.size();
4798f0fd8f6SDimitry Andric   }
4808f0fd8f6SDimitry Andric 
EmitALUClause(MachineBasicBlock::iterator InsertPos,const DebugLoc & DL,ClauseFile & Clause,unsigned & CfCount)481d88c1a5aSDimitry Andric   void EmitALUClause(MachineBasicBlock::iterator InsertPos, const DebugLoc &DL,
482d88c1a5aSDimitry Andric                      ClauseFile &Clause, unsigned &CfCount) {
4838f0fd8f6SDimitry Andric     Clause.first->getOperand(0).setImm(0);
4843ca95b02SDimitry Andric     CounterPropagateAddr(*Clause.first, CfCount);
4858f0fd8f6SDimitry Andric     MachineBasicBlock *BB = Clause.first->getParent();
486*4ba319b5SDimitry Andric     BuildMI(BB, DL, TII->get(R600::ALU_CLAUSE)).addImm(CfCount);
4878f0fd8f6SDimitry Andric     for (unsigned i = 0, e = Clause.second.size(); i < e; ++i) {
4888f0fd8f6SDimitry Andric       BB->splice(InsertPos, BB, Clause.second[i]);
4898f0fd8f6SDimitry Andric     }
4908f0fd8f6SDimitry Andric     CfCount += Clause.second.size();
4918f0fd8f6SDimitry Andric   }
4928f0fd8f6SDimitry Andric 
CounterPropagateAddr(MachineInstr & MI,unsigned Addr) const4933ca95b02SDimitry Andric   void CounterPropagateAddr(MachineInstr &MI, unsigned Addr) const {
4943ca95b02SDimitry Andric     MI.getOperand(0).setImm(Addr + MI.getOperand(0).getImm());
4958f0fd8f6SDimitry Andric   }
CounterPropagateAddr(const std::set<MachineInstr * > & MIs,unsigned Addr) const4968f0fd8f6SDimitry Andric   void CounterPropagateAddr(const std::set<MachineInstr *> &MIs,
4978f0fd8f6SDimitry Andric                             unsigned Addr) const {
4988f0fd8f6SDimitry Andric     for (MachineInstr *MI : MIs) {
4993ca95b02SDimitry Andric       CounterPropagateAddr(*MI, Addr);
5008f0fd8f6SDimitry Andric     }
5018f0fd8f6SDimitry Andric   }
5028f0fd8f6SDimitry Andric 
5038f0fd8f6SDimitry Andric public:
5042cab237bSDimitry Andric   static char ID;
5052cab237bSDimitry Andric 
R600ControlFlowFinalizer()506d8866befSDimitry Andric   R600ControlFlowFinalizer() : MachineFunctionPass(ID) {}
5078f0fd8f6SDimitry Andric 
runOnMachineFunction(MachineFunction & MF)5088f0fd8f6SDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override {
5093ca95b02SDimitry Andric     ST = &MF.getSubtarget<R600Subtarget>();
5108f0fd8f6SDimitry Andric     MaxFetchInst = ST->getTexVTXClauseSize();
5113ca95b02SDimitry Andric     TII = ST->getInstrInfo();
5123ca95b02SDimitry Andric     TRI = ST->getRegisterInfo();
5133ca95b02SDimitry Andric 
5148f0fd8f6SDimitry Andric     R600MachineFunctionInfo *MFI = MF.getInfo<R600MachineFunctionInfo>();
5158f0fd8f6SDimitry Andric 
5162cab237bSDimitry Andric     CFStack CFStack(ST, MF.getFunction().getCallingConv());
5178f0fd8f6SDimitry Andric     for (MachineFunction::iterator MB = MF.begin(), ME = MF.end(); MB != ME;
5188f0fd8f6SDimitry Andric         ++MB) {
5198f0fd8f6SDimitry Andric       MachineBasicBlock &MBB = *MB;
5208f0fd8f6SDimitry Andric       unsigned CfCount = 0;
5218f0fd8f6SDimitry Andric       std::vector<std::pair<unsigned, std::set<MachineInstr *>>> LoopStack;
5228f0fd8f6SDimitry Andric       std::vector<MachineInstr * > IfThenElseStack;
5232cab237bSDimitry Andric       if (MF.getFunction().getCallingConv() == CallingConv::AMDGPU_VS) {
5248f0fd8f6SDimitry Andric         BuildMI(MBB, MBB.begin(), MBB.findDebugLoc(MBB.begin()),
5258f0fd8f6SDimitry Andric             getHWInstrDesc(CF_CALL_FS));
5268f0fd8f6SDimitry Andric         CfCount++;
5278f0fd8f6SDimitry Andric       }
5288f0fd8f6SDimitry Andric       std::vector<ClauseFile> FetchClauses, AluClauses;
5298f0fd8f6SDimitry Andric       std::vector<MachineInstr *> LastAlu(1);
5308f0fd8f6SDimitry Andric       std::vector<MachineInstr *> ToPopAfter;
5318f0fd8f6SDimitry Andric 
5328f0fd8f6SDimitry Andric       for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end();
5338f0fd8f6SDimitry Andric           I != E;) {
5343ca95b02SDimitry Andric         if (TII->usesTextureCache(*I) || TII->usesVertexCache(*I)) {
535*4ba319b5SDimitry Andric           LLVM_DEBUG(dbgs() << CfCount << ":"; I->dump(););
5368f0fd8f6SDimitry Andric           FetchClauses.push_back(MakeFetchClause(MBB, I));
5378f0fd8f6SDimitry Andric           CfCount++;
5388f0fd8f6SDimitry Andric           LastAlu.back() = nullptr;
5398f0fd8f6SDimitry Andric           continue;
5408f0fd8f6SDimitry Andric         }
5418f0fd8f6SDimitry Andric 
5428f0fd8f6SDimitry Andric         MachineBasicBlock::iterator MI = I;
543*4ba319b5SDimitry Andric         if (MI->getOpcode() != R600::ENDIF)
5448f0fd8f6SDimitry Andric           LastAlu.back() = nullptr;
545*4ba319b5SDimitry Andric         if (MI->getOpcode() == R600::CF_ALU)
5463ca95b02SDimitry Andric           LastAlu.back() = &*MI;
5478f0fd8f6SDimitry Andric         I++;
5488f0fd8f6SDimitry Andric         bool RequiresWorkAround =
5498f0fd8f6SDimitry Andric             CFStack.requiresWorkAroundForInst(MI->getOpcode());
5508f0fd8f6SDimitry Andric         switch (MI->getOpcode()) {
551*4ba319b5SDimitry Andric         case R600::CF_ALU_PUSH_BEFORE:
5528f0fd8f6SDimitry Andric           if (RequiresWorkAround) {
553*4ba319b5SDimitry Andric             LLVM_DEBUG(dbgs()
554*4ba319b5SDimitry Andric                        << "Applying bug work-around for ALU_PUSH_BEFORE\n");
555*4ba319b5SDimitry Andric             BuildMI(MBB, MI, MBB.findDebugLoc(MI), TII->get(R600::CF_PUSH_EG))
5568f0fd8f6SDimitry Andric                 .addImm(CfCount + 1)
5578f0fd8f6SDimitry Andric                 .addImm(1);
558*4ba319b5SDimitry Andric             MI->setDesc(TII->get(R600::CF_ALU));
5598f0fd8f6SDimitry Andric             CfCount++;
560*4ba319b5SDimitry Andric             CFStack.pushBranch(R600::CF_PUSH_EG);
5618f0fd8f6SDimitry Andric           } else
562*4ba319b5SDimitry Andric             CFStack.pushBranch(R600::CF_ALU_PUSH_BEFORE);
563c4394386SDimitry Andric           LLVM_FALLTHROUGH;
564*4ba319b5SDimitry Andric         case R600::CF_ALU:
5658f0fd8f6SDimitry Andric           I = MI;
5668f0fd8f6SDimitry Andric           AluClauses.push_back(MakeALUClause(MBB, I));
567*4ba319b5SDimitry Andric           LLVM_DEBUG(dbgs() << CfCount << ":"; MI->dump(););
5688f0fd8f6SDimitry Andric           CfCount++;
5698f0fd8f6SDimitry Andric           break;
570*4ba319b5SDimitry Andric         case R600::WHILELOOP: {
5718f0fd8f6SDimitry Andric           CFStack.pushLoop();
5728f0fd8f6SDimitry Andric           MachineInstr *MIb = BuildMI(MBB, MI, MBB.findDebugLoc(MI),
5738f0fd8f6SDimitry Andric               getHWInstrDesc(CF_WHILE_LOOP))
5748f0fd8f6SDimitry Andric               .addImm(1);
5758f0fd8f6SDimitry Andric           std::pair<unsigned, std::set<MachineInstr *>> Pair(CfCount,
5768f0fd8f6SDimitry Andric               std::set<MachineInstr *>());
5778f0fd8f6SDimitry Andric           Pair.second.insert(MIb);
5788f0fd8f6SDimitry Andric           LoopStack.push_back(std::move(Pair));
5798f0fd8f6SDimitry Andric           MI->eraseFromParent();
5808f0fd8f6SDimitry Andric           CfCount++;
5818f0fd8f6SDimitry Andric           break;
5828f0fd8f6SDimitry Andric         }
583*4ba319b5SDimitry Andric         case R600::ENDLOOP: {
5848f0fd8f6SDimitry Andric           CFStack.popLoop();
5858f0fd8f6SDimitry Andric           std::pair<unsigned, std::set<MachineInstr *>> Pair =
5868f0fd8f6SDimitry Andric               std::move(LoopStack.back());
5878f0fd8f6SDimitry Andric           LoopStack.pop_back();
5888f0fd8f6SDimitry Andric           CounterPropagateAddr(Pair.second, CfCount);
5898f0fd8f6SDimitry Andric           BuildMI(MBB, MI, MBB.findDebugLoc(MI), getHWInstrDesc(CF_END_LOOP))
5908f0fd8f6SDimitry Andric               .addImm(Pair.first + 1);
5918f0fd8f6SDimitry Andric           MI->eraseFromParent();
5928f0fd8f6SDimitry Andric           CfCount++;
5938f0fd8f6SDimitry Andric           break;
5948f0fd8f6SDimitry Andric         }
595*4ba319b5SDimitry Andric         case R600::IF_PREDICATE_SET: {
5968f0fd8f6SDimitry Andric           LastAlu.push_back(nullptr);
5978f0fd8f6SDimitry Andric           MachineInstr *MIb = BuildMI(MBB, MI, MBB.findDebugLoc(MI),
5988f0fd8f6SDimitry Andric               getHWInstrDesc(CF_JUMP))
5998f0fd8f6SDimitry Andric               .addImm(0)
6008f0fd8f6SDimitry Andric               .addImm(0);
6018f0fd8f6SDimitry Andric           IfThenElseStack.push_back(MIb);
602*4ba319b5SDimitry Andric           LLVM_DEBUG(dbgs() << CfCount << ":"; MIb->dump(););
6038f0fd8f6SDimitry Andric           MI->eraseFromParent();
6048f0fd8f6SDimitry Andric           CfCount++;
6058f0fd8f6SDimitry Andric           break;
6068f0fd8f6SDimitry Andric         }
607*4ba319b5SDimitry Andric         case R600::ELSE: {
6088f0fd8f6SDimitry Andric           MachineInstr * JumpInst = IfThenElseStack.back();
6098f0fd8f6SDimitry Andric           IfThenElseStack.pop_back();
6103ca95b02SDimitry Andric           CounterPropagateAddr(*JumpInst, CfCount);
6118f0fd8f6SDimitry Andric           MachineInstr *MIb = BuildMI(MBB, MI, MBB.findDebugLoc(MI),
6128f0fd8f6SDimitry Andric               getHWInstrDesc(CF_ELSE))
6138f0fd8f6SDimitry Andric               .addImm(0)
6148f0fd8f6SDimitry Andric               .addImm(0);
615*4ba319b5SDimitry Andric           LLVM_DEBUG(dbgs() << CfCount << ":"; MIb->dump(););
6168f0fd8f6SDimitry Andric           IfThenElseStack.push_back(MIb);
6178f0fd8f6SDimitry Andric           MI->eraseFromParent();
6188f0fd8f6SDimitry Andric           CfCount++;
6198f0fd8f6SDimitry Andric           break;
6208f0fd8f6SDimitry Andric         }
621*4ba319b5SDimitry Andric         case R600::ENDIF: {
6228f0fd8f6SDimitry Andric           CFStack.popBranch();
6238f0fd8f6SDimitry Andric           if (LastAlu.back()) {
6248f0fd8f6SDimitry Andric             ToPopAfter.push_back(LastAlu.back());
6258f0fd8f6SDimitry Andric           } else {
6268f0fd8f6SDimitry Andric             MachineInstr *MIb = BuildMI(MBB, MI, MBB.findDebugLoc(MI),
6278f0fd8f6SDimitry Andric                 getHWInstrDesc(CF_POP))
6288f0fd8f6SDimitry Andric                 .addImm(CfCount + 1)
6298f0fd8f6SDimitry Andric                 .addImm(1);
6308f0fd8f6SDimitry Andric             (void)MIb;
631*4ba319b5SDimitry Andric             LLVM_DEBUG(dbgs() << CfCount << ":"; MIb->dump(););
6328f0fd8f6SDimitry Andric             CfCount++;
6338f0fd8f6SDimitry Andric           }
6348f0fd8f6SDimitry Andric 
6358f0fd8f6SDimitry Andric           MachineInstr *IfOrElseInst = IfThenElseStack.back();
6368f0fd8f6SDimitry Andric           IfThenElseStack.pop_back();
6373ca95b02SDimitry Andric           CounterPropagateAddr(*IfOrElseInst, CfCount);
6388f0fd8f6SDimitry Andric           IfOrElseInst->getOperand(1).setImm(1);
6398f0fd8f6SDimitry Andric           LastAlu.pop_back();
6408f0fd8f6SDimitry Andric           MI->eraseFromParent();
6418f0fd8f6SDimitry Andric           break;
6428f0fd8f6SDimitry Andric         }
643*4ba319b5SDimitry Andric         case R600::BREAK: {
6448f0fd8f6SDimitry Andric           CfCount ++;
6458f0fd8f6SDimitry Andric           MachineInstr *MIb = BuildMI(MBB, MI, MBB.findDebugLoc(MI),
6468f0fd8f6SDimitry Andric               getHWInstrDesc(CF_LOOP_BREAK))
6478f0fd8f6SDimitry Andric               .addImm(0);
6488f0fd8f6SDimitry Andric           LoopStack.back().second.insert(MIb);
6498f0fd8f6SDimitry Andric           MI->eraseFromParent();
6508f0fd8f6SDimitry Andric           break;
6518f0fd8f6SDimitry Andric         }
652*4ba319b5SDimitry Andric         case R600::CONTINUE: {
6538f0fd8f6SDimitry Andric           MachineInstr *MIb = BuildMI(MBB, MI, MBB.findDebugLoc(MI),
6548f0fd8f6SDimitry Andric               getHWInstrDesc(CF_LOOP_CONTINUE))
6558f0fd8f6SDimitry Andric               .addImm(0);
6568f0fd8f6SDimitry Andric           LoopStack.back().second.insert(MIb);
6578f0fd8f6SDimitry Andric           MI->eraseFromParent();
6588f0fd8f6SDimitry Andric           CfCount++;
6598f0fd8f6SDimitry Andric           break;
6608f0fd8f6SDimitry Andric         }
661*4ba319b5SDimitry Andric         case R600::RETURN: {
662d88c1a5aSDimitry Andric           DebugLoc DL = MBB.findDebugLoc(MI);
663d88c1a5aSDimitry Andric           BuildMI(MBB, MI, DL, getHWInstrDesc(CF_END));
6648f0fd8f6SDimitry Andric           CfCount++;
6658f0fd8f6SDimitry Andric           if (CfCount % 2) {
666*4ba319b5SDimitry Andric             BuildMI(MBB, I, DL, TII->get(R600::PAD));
6678f0fd8f6SDimitry Andric             CfCount++;
6688f0fd8f6SDimitry Andric           }
6693ca95b02SDimitry Andric           MI->eraseFromParent();
6708f0fd8f6SDimitry Andric           for (unsigned i = 0, e = FetchClauses.size(); i < e; i++)
671d88c1a5aSDimitry Andric             EmitFetchClause(I, DL, FetchClauses[i], CfCount);
6728f0fd8f6SDimitry Andric           for (unsigned i = 0, e = AluClauses.size(); i < e; i++)
673d88c1a5aSDimitry Andric             EmitALUClause(I, DL, AluClauses[i], CfCount);
6743ca95b02SDimitry Andric           break;
6758f0fd8f6SDimitry Andric         }
6768f0fd8f6SDimitry Andric         default:
6778f0fd8f6SDimitry Andric           if (TII->isExport(MI->getOpcode())) {
678*4ba319b5SDimitry Andric             LLVM_DEBUG(dbgs() << CfCount << ":"; MI->dump(););
6798f0fd8f6SDimitry Andric             CfCount++;
6808f0fd8f6SDimitry Andric           }
6818f0fd8f6SDimitry Andric           break;
6828f0fd8f6SDimitry Andric         }
6838f0fd8f6SDimitry Andric       }
6848f0fd8f6SDimitry Andric       for (unsigned i = 0, e = ToPopAfter.size(); i < e; ++i) {
6858f0fd8f6SDimitry Andric         MachineInstr *Alu = ToPopAfter[i];
6868f0fd8f6SDimitry Andric         BuildMI(MBB, Alu, MBB.findDebugLoc((MachineBasicBlock::iterator)Alu),
687*4ba319b5SDimitry Andric             TII->get(R600::CF_ALU_POP_AFTER))
6888f0fd8f6SDimitry Andric             .addImm(Alu->getOperand(0).getImm())
6898f0fd8f6SDimitry Andric             .addImm(Alu->getOperand(1).getImm())
6908f0fd8f6SDimitry Andric             .addImm(Alu->getOperand(2).getImm())
6918f0fd8f6SDimitry Andric             .addImm(Alu->getOperand(3).getImm())
6928f0fd8f6SDimitry Andric             .addImm(Alu->getOperand(4).getImm())
6938f0fd8f6SDimitry Andric             .addImm(Alu->getOperand(5).getImm())
6948f0fd8f6SDimitry Andric             .addImm(Alu->getOperand(6).getImm())
6958f0fd8f6SDimitry Andric             .addImm(Alu->getOperand(7).getImm())
6968f0fd8f6SDimitry Andric             .addImm(Alu->getOperand(8).getImm());
6978f0fd8f6SDimitry Andric         Alu->eraseFromParent();
6988f0fd8f6SDimitry Andric       }
699d88c1a5aSDimitry Andric       MFI->CFStackSize = CFStack.MaxStackSize;
7008f0fd8f6SDimitry Andric     }
7018f0fd8f6SDimitry Andric 
7028f0fd8f6SDimitry Andric     return false;
7038f0fd8f6SDimitry Andric   }
7048f0fd8f6SDimitry Andric 
getPassName() const705d88c1a5aSDimitry Andric   StringRef getPassName() const override {
7068f0fd8f6SDimitry Andric     return "R600 Control Flow Finalizer Pass";
7078f0fd8f6SDimitry Andric   }
7088f0fd8f6SDimitry Andric };
7098f0fd8f6SDimitry Andric 
7102cab237bSDimitry Andric } // end anonymous namespace
7112cab237bSDimitry Andric 
7122cab237bSDimitry Andric INITIALIZE_PASS_BEGIN(R600ControlFlowFinalizer, DEBUG_TYPE,
7132cab237bSDimitry Andric                      "R600 Control Flow Finalizer", false, false)
7142cab237bSDimitry Andric INITIALIZE_PASS_END(R600ControlFlowFinalizer, DEBUG_TYPE,
7152cab237bSDimitry Andric                     "R600 Control Flow Finalizer", false, false)
7162cab237bSDimitry Andric 
7178f0fd8f6SDimitry Andric char R600ControlFlowFinalizer::ID = 0;
7188f0fd8f6SDimitry Andric 
7192cab237bSDimitry Andric char &llvm::R600ControlFlowFinalizerID = R600ControlFlowFinalizer::ID;
7208f0fd8f6SDimitry Andric 
createR600ControlFlowFinalizer()721d8866befSDimitry Andric FunctionPass *llvm::createR600ControlFlowFinalizer() {
722d8866befSDimitry Andric   return new R600ControlFlowFinalizer();
7238f0fd8f6SDimitry Andric }
724