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