10b57cec5SDimitry Andric //===- R600ControlFlowFinalizer.cpp - Finalize Control Flow Inst ----------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric /// \file 100b57cec5SDimitry Andric /// This pass compute turns all control flow pseudo instructions into native one 110b57cec5SDimitry Andric /// computing their address on the fly; it also sets STACK_SIZE info. 120b57cec5SDimitry Andric // 130b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 140b57cec5SDimitry Andric 150b57cec5SDimitry Andric #include "AMDGPU.h" 160b57cec5SDimitry Andric #include "MCTargetDesc/AMDGPUMCTargetDesc.h" 17*e8d8bef9SDimitry Andric #include "R600MachineFunctionInfo.h" 18*e8d8bef9SDimitry Andric #include "R600Subtarget.h" 190b57cec5SDimitry Andric #include <set> 200b57cec5SDimitry Andric 210b57cec5SDimitry Andric using namespace llvm; 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric #define DEBUG_TYPE "r600cf" 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric namespace { 260b57cec5SDimitry Andric 270b57cec5SDimitry Andric struct CFStack { 280b57cec5SDimitry Andric enum StackItem { 290b57cec5SDimitry Andric ENTRY = 0, 300b57cec5SDimitry Andric SUB_ENTRY = 1, 310b57cec5SDimitry Andric FIRST_NON_WQM_PUSH = 2, 320b57cec5SDimitry Andric FIRST_NON_WQM_PUSH_W_FULL_ENTRY = 3 330b57cec5SDimitry Andric }; 340b57cec5SDimitry Andric 350b57cec5SDimitry Andric const R600Subtarget *ST; 360b57cec5SDimitry Andric std::vector<StackItem> BranchStack; 370b57cec5SDimitry Andric std::vector<StackItem> LoopStack; 380b57cec5SDimitry Andric unsigned MaxStackSize; 390b57cec5SDimitry Andric unsigned CurrentEntries = 0; 400b57cec5SDimitry Andric unsigned CurrentSubEntries = 0; 410b57cec5SDimitry Andric 420b57cec5SDimitry Andric CFStack(const R600Subtarget *st, CallingConv::ID cc) : ST(st), 430b57cec5SDimitry Andric // We need to reserve a stack entry for CALL_FS in vertex shaders. 440b57cec5SDimitry Andric MaxStackSize(cc == CallingConv::AMDGPU_VS ? 1 : 0) {} 450b57cec5SDimitry Andric 460b57cec5SDimitry Andric unsigned getLoopDepth(); 470b57cec5SDimitry Andric bool branchStackContains(CFStack::StackItem); 480b57cec5SDimitry Andric bool requiresWorkAroundForInst(unsigned Opcode); 490b57cec5SDimitry Andric unsigned getSubEntrySize(CFStack::StackItem Item); 500b57cec5SDimitry Andric void updateMaxStackSize(); 510b57cec5SDimitry Andric void pushBranch(unsigned Opcode, bool isWQM = false); 520b57cec5SDimitry Andric void pushLoop(); 530b57cec5SDimitry Andric void popBranch(); 540b57cec5SDimitry Andric void popLoop(); 550b57cec5SDimitry Andric }; 560b57cec5SDimitry Andric 570b57cec5SDimitry Andric unsigned CFStack::getLoopDepth() { 580b57cec5SDimitry Andric return LoopStack.size(); 590b57cec5SDimitry Andric } 600b57cec5SDimitry Andric 610b57cec5SDimitry Andric bool CFStack::branchStackContains(CFStack::StackItem Item) { 62*e8d8bef9SDimitry Andric return llvm::is_contained(BranchStack, Item); 630b57cec5SDimitry Andric } 640b57cec5SDimitry Andric 650b57cec5SDimitry Andric bool CFStack::requiresWorkAroundForInst(unsigned Opcode) { 660b57cec5SDimitry Andric if (Opcode == R600::CF_ALU_PUSH_BEFORE && ST->hasCaymanISA() && 670b57cec5SDimitry Andric getLoopDepth() > 1) 680b57cec5SDimitry Andric return true; 690b57cec5SDimitry Andric 700b57cec5SDimitry Andric if (!ST->hasCFAluBug()) 710b57cec5SDimitry Andric return false; 720b57cec5SDimitry Andric 730b57cec5SDimitry Andric switch(Opcode) { 740b57cec5SDimitry Andric default: return false; 750b57cec5SDimitry Andric case R600::CF_ALU_PUSH_BEFORE: 760b57cec5SDimitry Andric case R600::CF_ALU_ELSE_AFTER: 770b57cec5SDimitry Andric case R600::CF_ALU_BREAK: 780b57cec5SDimitry Andric case R600::CF_ALU_CONTINUE: 790b57cec5SDimitry Andric if (CurrentSubEntries == 0) 800b57cec5SDimitry Andric return false; 810b57cec5SDimitry Andric if (ST->getWavefrontSize() == 64) { 820b57cec5SDimitry Andric // We are being conservative here. We only require this work-around if 830b57cec5SDimitry Andric // CurrentSubEntries > 3 && 840b57cec5SDimitry Andric // (CurrentSubEntries % 4 == 3 || CurrentSubEntries % 4 == 0) 850b57cec5SDimitry Andric // 860b57cec5SDimitry Andric // We have to be conservative, because we don't know for certain that 870b57cec5SDimitry Andric // our stack allocation algorithm for Evergreen/NI is correct. Applying this 880b57cec5SDimitry Andric // work-around when CurrentSubEntries > 3 allows us to over-allocate stack 890b57cec5SDimitry Andric // resources without any problems. 900b57cec5SDimitry Andric return CurrentSubEntries > 3; 910b57cec5SDimitry Andric } else { 920b57cec5SDimitry Andric assert(ST->getWavefrontSize() == 32); 930b57cec5SDimitry Andric // We are being conservative here. We only require the work-around if 940b57cec5SDimitry Andric // CurrentSubEntries > 7 && 950b57cec5SDimitry Andric // (CurrentSubEntries % 8 == 7 || CurrentSubEntries % 8 == 0) 960b57cec5SDimitry Andric // See the comment on the wavefront size == 64 case for why we are 970b57cec5SDimitry Andric // being conservative. 980b57cec5SDimitry Andric return CurrentSubEntries > 7; 990b57cec5SDimitry Andric } 1000b57cec5SDimitry Andric } 1010b57cec5SDimitry Andric } 1020b57cec5SDimitry Andric 1030b57cec5SDimitry Andric unsigned CFStack::getSubEntrySize(CFStack::StackItem Item) { 1040b57cec5SDimitry Andric switch(Item) { 1050b57cec5SDimitry Andric default: 1060b57cec5SDimitry Andric return 0; 1070b57cec5SDimitry Andric case CFStack::FIRST_NON_WQM_PUSH: 1080b57cec5SDimitry Andric assert(!ST->hasCaymanISA()); 1090b57cec5SDimitry Andric if (ST->getGeneration() <= AMDGPUSubtarget::R700) { 1100b57cec5SDimitry Andric // +1 For the push operation. 1110b57cec5SDimitry Andric // +2 Extra space required. 1120b57cec5SDimitry Andric return 3; 1130b57cec5SDimitry Andric } else { 1140b57cec5SDimitry Andric // Some documentation says that this is not necessary on Evergreen, 1150b57cec5SDimitry Andric // but experimentation has show that we need to allocate 1 extra 1160b57cec5SDimitry Andric // sub-entry for the first non-WQM push. 1170b57cec5SDimitry Andric // +1 For the push operation. 1180b57cec5SDimitry Andric // +1 Extra space required. 1190b57cec5SDimitry Andric return 2; 1200b57cec5SDimitry Andric } 1210b57cec5SDimitry Andric case CFStack::FIRST_NON_WQM_PUSH_W_FULL_ENTRY: 1220b57cec5SDimitry Andric assert(ST->getGeneration() >= AMDGPUSubtarget::EVERGREEN); 1230b57cec5SDimitry Andric // +1 For the push operation. 1240b57cec5SDimitry Andric // +1 Extra space required. 1250b57cec5SDimitry Andric return 2; 1260b57cec5SDimitry Andric case CFStack::SUB_ENTRY: 1270b57cec5SDimitry Andric return 1; 1280b57cec5SDimitry Andric } 1290b57cec5SDimitry Andric } 1300b57cec5SDimitry Andric 1310b57cec5SDimitry Andric void CFStack::updateMaxStackSize() { 1325ffd83dbSDimitry Andric unsigned CurrentStackSize = CurrentEntries + divideCeil(CurrentSubEntries, 4); 1330b57cec5SDimitry Andric MaxStackSize = std::max(CurrentStackSize, MaxStackSize); 1340b57cec5SDimitry Andric } 1350b57cec5SDimitry Andric 1360b57cec5SDimitry Andric void CFStack::pushBranch(unsigned Opcode, bool isWQM) { 1370b57cec5SDimitry Andric CFStack::StackItem Item = CFStack::ENTRY; 1380b57cec5SDimitry Andric switch(Opcode) { 1390b57cec5SDimitry Andric case R600::CF_PUSH_EG: 1400b57cec5SDimitry Andric case R600::CF_ALU_PUSH_BEFORE: 1410b57cec5SDimitry Andric if (!isWQM) { 1420b57cec5SDimitry Andric if (!ST->hasCaymanISA() && 1430b57cec5SDimitry Andric !branchStackContains(CFStack::FIRST_NON_WQM_PUSH)) 1440b57cec5SDimitry Andric Item = CFStack::FIRST_NON_WQM_PUSH; // May not be required on Evergreen/NI 1450b57cec5SDimitry Andric // See comment in 1460b57cec5SDimitry Andric // CFStack::getSubEntrySize() 1470b57cec5SDimitry Andric else if (CurrentEntries > 0 && 1480b57cec5SDimitry Andric ST->getGeneration() > AMDGPUSubtarget::EVERGREEN && 1490b57cec5SDimitry Andric !ST->hasCaymanISA() && 1500b57cec5SDimitry Andric !branchStackContains(CFStack::FIRST_NON_WQM_PUSH_W_FULL_ENTRY)) 1510b57cec5SDimitry Andric Item = CFStack::FIRST_NON_WQM_PUSH_W_FULL_ENTRY; 1520b57cec5SDimitry Andric else 1530b57cec5SDimitry Andric Item = CFStack::SUB_ENTRY; 1540b57cec5SDimitry Andric } else 1550b57cec5SDimitry Andric Item = CFStack::ENTRY; 1560b57cec5SDimitry Andric break; 1570b57cec5SDimitry Andric } 1580b57cec5SDimitry Andric BranchStack.push_back(Item); 1590b57cec5SDimitry Andric if (Item == CFStack::ENTRY) 1600b57cec5SDimitry Andric CurrentEntries++; 1610b57cec5SDimitry Andric else 1620b57cec5SDimitry Andric CurrentSubEntries += getSubEntrySize(Item); 1630b57cec5SDimitry Andric updateMaxStackSize(); 1640b57cec5SDimitry Andric } 1650b57cec5SDimitry Andric 1660b57cec5SDimitry Andric void CFStack::pushLoop() { 1670b57cec5SDimitry Andric LoopStack.push_back(CFStack::ENTRY); 1680b57cec5SDimitry Andric CurrentEntries++; 1690b57cec5SDimitry Andric updateMaxStackSize(); 1700b57cec5SDimitry Andric } 1710b57cec5SDimitry Andric 1720b57cec5SDimitry Andric void CFStack::popBranch() { 1730b57cec5SDimitry Andric CFStack::StackItem Top = BranchStack.back(); 1740b57cec5SDimitry Andric if (Top == CFStack::ENTRY) 1750b57cec5SDimitry Andric CurrentEntries--; 1760b57cec5SDimitry Andric else 1770b57cec5SDimitry Andric CurrentSubEntries-= getSubEntrySize(Top); 1780b57cec5SDimitry Andric BranchStack.pop_back(); 1790b57cec5SDimitry Andric } 1800b57cec5SDimitry Andric 1810b57cec5SDimitry Andric void CFStack::popLoop() { 1820b57cec5SDimitry Andric CurrentEntries--; 1830b57cec5SDimitry Andric LoopStack.pop_back(); 1840b57cec5SDimitry Andric } 1850b57cec5SDimitry Andric 1860b57cec5SDimitry Andric class R600ControlFlowFinalizer : public MachineFunctionPass { 1870b57cec5SDimitry Andric private: 1880b57cec5SDimitry Andric using ClauseFile = std::pair<MachineInstr *, std::vector<MachineInstr *>>; 1890b57cec5SDimitry Andric 1900b57cec5SDimitry Andric enum ControlFlowInstruction { 1910b57cec5SDimitry Andric CF_TC, 1920b57cec5SDimitry Andric CF_VC, 1930b57cec5SDimitry Andric CF_CALL_FS, 1940b57cec5SDimitry Andric CF_WHILE_LOOP, 1950b57cec5SDimitry Andric CF_END_LOOP, 1960b57cec5SDimitry Andric CF_LOOP_BREAK, 1970b57cec5SDimitry Andric CF_LOOP_CONTINUE, 1980b57cec5SDimitry Andric CF_JUMP, 1990b57cec5SDimitry Andric CF_ELSE, 2000b57cec5SDimitry Andric CF_POP, 2010b57cec5SDimitry Andric CF_END 2020b57cec5SDimitry Andric }; 2030b57cec5SDimitry Andric 2040b57cec5SDimitry Andric const R600InstrInfo *TII = nullptr; 2050b57cec5SDimitry Andric const R600RegisterInfo *TRI = nullptr; 2060b57cec5SDimitry Andric unsigned MaxFetchInst; 2070b57cec5SDimitry Andric const R600Subtarget *ST = nullptr; 2080b57cec5SDimitry Andric 2090b57cec5SDimitry Andric bool IsTrivialInst(MachineInstr &MI) const { 2100b57cec5SDimitry Andric switch (MI.getOpcode()) { 2110b57cec5SDimitry Andric case R600::KILL: 2120b57cec5SDimitry Andric case R600::RETURN: 2130b57cec5SDimitry Andric return true; 2140b57cec5SDimitry Andric default: 2150b57cec5SDimitry Andric return false; 2160b57cec5SDimitry Andric } 2170b57cec5SDimitry Andric } 2180b57cec5SDimitry Andric 2190b57cec5SDimitry Andric const MCInstrDesc &getHWInstrDesc(ControlFlowInstruction CFI) const { 2200b57cec5SDimitry Andric unsigned Opcode = 0; 2210b57cec5SDimitry Andric bool isEg = (ST->getGeneration() >= AMDGPUSubtarget::EVERGREEN); 2220b57cec5SDimitry Andric switch (CFI) { 2230b57cec5SDimitry Andric case CF_TC: 2240b57cec5SDimitry Andric Opcode = isEg ? R600::CF_TC_EG : R600::CF_TC_R600; 2250b57cec5SDimitry Andric break; 2260b57cec5SDimitry Andric case CF_VC: 2270b57cec5SDimitry Andric Opcode = isEg ? R600::CF_VC_EG : R600::CF_VC_R600; 2280b57cec5SDimitry Andric break; 2290b57cec5SDimitry Andric case CF_CALL_FS: 2300b57cec5SDimitry Andric Opcode = isEg ? R600::CF_CALL_FS_EG : R600::CF_CALL_FS_R600; 2310b57cec5SDimitry Andric break; 2320b57cec5SDimitry Andric case CF_WHILE_LOOP: 2330b57cec5SDimitry Andric Opcode = isEg ? R600::WHILE_LOOP_EG : R600::WHILE_LOOP_R600; 2340b57cec5SDimitry Andric break; 2350b57cec5SDimitry Andric case CF_END_LOOP: 2360b57cec5SDimitry Andric Opcode = isEg ? R600::END_LOOP_EG : R600::END_LOOP_R600; 2370b57cec5SDimitry Andric break; 2380b57cec5SDimitry Andric case CF_LOOP_BREAK: 2390b57cec5SDimitry Andric Opcode = isEg ? R600::LOOP_BREAK_EG : R600::LOOP_BREAK_R600; 2400b57cec5SDimitry Andric break; 2410b57cec5SDimitry Andric case CF_LOOP_CONTINUE: 2420b57cec5SDimitry Andric Opcode = isEg ? R600::CF_CONTINUE_EG : R600::CF_CONTINUE_R600; 2430b57cec5SDimitry Andric break; 2440b57cec5SDimitry Andric case CF_JUMP: 2450b57cec5SDimitry Andric Opcode = isEg ? R600::CF_JUMP_EG : R600::CF_JUMP_R600; 2460b57cec5SDimitry Andric break; 2470b57cec5SDimitry Andric case CF_ELSE: 2480b57cec5SDimitry Andric Opcode = isEg ? R600::CF_ELSE_EG : R600::CF_ELSE_R600; 2490b57cec5SDimitry Andric break; 2500b57cec5SDimitry Andric case CF_POP: 2510b57cec5SDimitry Andric Opcode = isEg ? R600::POP_EG : R600::POP_R600; 2520b57cec5SDimitry Andric break; 2530b57cec5SDimitry Andric case CF_END: 2540b57cec5SDimitry Andric if (ST->hasCaymanISA()) { 2550b57cec5SDimitry Andric Opcode = R600::CF_END_CM; 2560b57cec5SDimitry Andric break; 2570b57cec5SDimitry Andric } 2580b57cec5SDimitry Andric Opcode = isEg ? R600::CF_END_EG : R600::CF_END_R600; 2590b57cec5SDimitry Andric break; 2600b57cec5SDimitry Andric } 2610b57cec5SDimitry Andric assert (Opcode && "No opcode selected"); 2620b57cec5SDimitry Andric return TII->get(Opcode); 2630b57cec5SDimitry Andric } 2640b57cec5SDimitry Andric 2650b57cec5SDimitry Andric bool isCompatibleWithClause(const MachineInstr &MI, 2660b57cec5SDimitry Andric std::set<unsigned> &DstRegs) const { 2670b57cec5SDimitry Andric unsigned DstMI, SrcMI; 2680b57cec5SDimitry Andric for (MachineInstr::const_mop_iterator I = MI.operands_begin(), 2690b57cec5SDimitry Andric E = MI.operands_end(); 2700b57cec5SDimitry Andric I != E; ++I) { 2710b57cec5SDimitry Andric const MachineOperand &MO = *I; 2720b57cec5SDimitry Andric if (!MO.isReg()) 2730b57cec5SDimitry Andric continue; 2740b57cec5SDimitry Andric if (MO.isDef()) { 2758bcb0991SDimitry Andric Register Reg = MO.getReg(); 2760b57cec5SDimitry Andric if (R600::R600_Reg128RegClass.contains(Reg)) 2770b57cec5SDimitry Andric DstMI = Reg; 2780b57cec5SDimitry Andric else 2790b57cec5SDimitry Andric DstMI = TRI->getMatchingSuperReg(Reg, 2805ffd83dbSDimitry Andric R600RegisterInfo::getSubRegFromChannel(TRI->getHWRegChan(Reg)), 2810b57cec5SDimitry Andric &R600::R600_Reg128RegClass); 2820b57cec5SDimitry Andric } 2830b57cec5SDimitry Andric if (MO.isUse()) { 2848bcb0991SDimitry Andric Register Reg = MO.getReg(); 2850b57cec5SDimitry Andric if (R600::R600_Reg128RegClass.contains(Reg)) 2860b57cec5SDimitry Andric SrcMI = Reg; 2870b57cec5SDimitry Andric else 2880b57cec5SDimitry Andric SrcMI = TRI->getMatchingSuperReg(Reg, 2895ffd83dbSDimitry Andric R600RegisterInfo::getSubRegFromChannel(TRI->getHWRegChan(Reg)), 2900b57cec5SDimitry Andric &R600::R600_Reg128RegClass); 2910b57cec5SDimitry Andric } 2920b57cec5SDimitry Andric } 2930b57cec5SDimitry Andric if ((DstRegs.find(SrcMI) == DstRegs.end())) { 2940b57cec5SDimitry Andric DstRegs.insert(DstMI); 2950b57cec5SDimitry Andric return true; 2960b57cec5SDimitry Andric } else 2970b57cec5SDimitry Andric return false; 2980b57cec5SDimitry Andric } 2990b57cec5SDimitry Andric 3000b57cec5SDimitry Andric ClauseFile 3010b57cec5SDimitry Andric MakeFetchClause(MachineBasicBlock &MBB, MachineBasicBlock::iterator &I) 3020b57cec5SDimitry Andric const { 3030b57cec5SDimitry Andric MachineBasicBlock::iterator ClauseHead = I; 3040b57cec5SDimitry Andric std::vector<MachineInstr *> ClauseContent; 3050b57cec5SDimitry Andric unsigned AluInstCount = 0; 3060b57cec5SDimitry Andric bool IsTex = TII->usesTextureCache(*ClauseHead); 3070b57cec5SDimitry Andric std::set<unsigned> DstRegs; 3080b57cec5SDimitry Andric for (MachineBasicBlock::iterator E = MBB.end(); I != E; ++I) { 3090b57cec5SDimitry Andric if (IsTrivialInst(*I)) 3100b57cec5SDimitry Andric continue; 3110b57cec5SDimitry Andric if (AluInstCount >= MaxFetchInst) 3120b57cec5SDimitry Andric break; 3130b57cec5SDimitry Andric if ((IsTex && !TII->usesTextureCache(*I)) || 3140b57cec5SDimitry Andric (!IsTex && !TII->usesVertexCache(*I))) 3150b57cec5SDimitry Andric break; 3160b57cec5SDimitry Andric if (!isCompatibleWithClause(*I, DstRegs)) 3170b57cec5SDimitry Andric break; 3180b57cec5SDimitry Andric AluInstCount ++; 3190b57cec5SDimitry Andric ClauseContent.push_back(&*I); 3200b57cec5SDimitry Andric } 3210b57cec5SDimitry Andric MachineInstr *MIb = BuildMI(MBB, ClauseHead, MBB.findDebugLoc(ClauseHead), 3220b57cec5SDimitry Andric getHWInstrDesc(IsTex?CF_TC:CF_VC)) 3230b57cec5SDimitry Andric .addImm(0) // ADDR 3240b57cec5SDimitry Andric .addImm(AluInstCount - 1); // COUNT 3250b57cec5SDimitry Andric return ClauseFile(MIb, std::move(ClauseContent)); 3260b57cec5SDimitry Andric } 3270b57cec5SDimitry Andric 3280b57cec5SDimitry Andric void getLiteral(MachineInstr &MI, std::vector<MachineOperand *> &Lits) const { 3290b57cec5SDimitry Andric static const unsigned LiteralRegs[] = { 3300b57cec5SDimitry Andric R600::ALU_LITERAL_X, 3310b57cec5SDimitry Andric R600::ALU_LITERAL_Y, 3320b57cec5SDimitry Andric R600::ALU_LITERAL_Z, 3330b57cec5SDimitry Andric R600::ALU_LITERAL_W 3340b57cec5SDimitry Andric }; 3350b57cec5SDimitry Andric const SmallVector<std::pair<MachineOperand *, int64_t>, 3> Srcs = 3360b57cec5SDimitry Andric TII->getSrcs(MI); 3370b57cec5SDimitry Andric for (const auto &Src:Srcs) { 3380b57cec5SDimitry Andric if (Src.first->getReg() != R600::ALU_LITERAL_X) 3390b57cec5SDimitry Andric continue; 3400b57cec5SDimitry Andric int64_t Imm = Src.second; 3410b57cec5SDimitry Andric std::vector<MachineOperand *>::iterator It = 3420b57cec5SDimitry Andric llvm::find_if(Lits, [&](MachineOperand *val) { 3430b57cec5SDimitry Andric return val->isImm() && (val->getImm() == Imm); 3440b57cec5SDimitry Andric }); 3450b57cec5SDimitry Andric 3460b57cec5SDimitry Andric // Get corresponding Operand 3470b57cec5SDimitry Andric MachineOperand &Operand = MI.getOperand( 3480b57cec5SDimitry Andric TII->getOperandIdx(MI.getOpcode(), R600::OpName::literal)); 3490b57cec5SDimitry Andric 3500b57cec5SDimitry Andric if (It != Lits.end()) { 3510b57cec5SDimitry Andric // Reuse existing literal reg 3520b57cec5SDimitry Andric unsigned Index = It - Lits.begin(); 3530b57cec5SDimitry Andric Src.first->setReg(LiteralRegs[Index]); 3540b57cec5SDimitry Andric } else { 3550b57cec5SDimitry Andric // Allocate new literal reg 3560b57cec5SDimitry Andric assert(Lits.size() < 4 && "Too many literals in Instruction Group"); 3570b57cec5SDimitry Andric Src.first->setReg(LiteralRegs[Lits.size()]); 3580b57cec5SDimitry Andric Lits.push_back(&Operand); 3590b57cec5SDimitry Andric } 3600b57cec5SDimitry Andric } 3610b57cec5SDimitry Andric } 3620b57cec5SDimitry Andric 3630b57cec5SDimitry Andric MachineBasicBlock::iterator insertLiterals( 3640b57cec5SDimitry Andric MachineBasicBlock::iterator InsertPos, 3650b57cec5SDimitry Andric const std::vector<unsigned> &Literals) const { 3660b57cec5SDimitry Andric MachineBasicBlock *MBB = InsertPos->getParent(); 3670b57cec5SDimitry Andric for (unsigned i = 0, e = Literals.size(); i < e; i+=2) { 3680b57cec5SDimitry Andric unsigned LiteralPair0 = Literals[i]; 3690b57cec5SDimitry Andric unsigned LiteralPair1 = (i + 1 < e)?Literals[i + 1]:0; 3700b57cec5SDimitry Andric InsertPos = BuildMI(MBB, InsertPos->getDebugLoc(), 3710b57cec5SDimitry Andric TII->get(R600::LITERALS)) 3720b57cec5SDimitry Andric .addImm(LiteralPair0) 3730b57cec5SDimitry Andric .addImm(LiteralPair1); 3740b57cec5SDimitry Andric } 3750b57cec5SDimitry Andric return InsertPos; 3760b57cec5SDimitry Andric } 3770b57cec5SDimitry Andric 3780b57cec5SDimitry Andric ClauseFile 3790b57cec5SDimitry Andric MakeALUClause(MachineBasicBlock &MBB, MachineBasicBlock::iterator &I) 3800b57cec5SDimitry Andric const { 3810b57cec5SDimitry Andric MachineInstr &ClauseHead = *I; 3820b57cec5SDimitry Andric std::vector<MachineInstr *> ClauseContent; 3830b57cec5SDimitry Andric I++; 3840b57cec5SDimitry Andric for (MachineBasicBlock::instr_iterator E = MBB.instr_end(); I != E;) { 3850b57cec5SDimitry Andric if (IsTrivialInst(*I)) { 3860b57cec5SDimitry Andric ++I; 3870b57cec5SDimitry Andric continue; 3880b57cec5SDimitry Andric } 3890b57cec5SDimitry Andric if (!I->isBundle() && !TII->isALUInstr(I->getOpcode())) 3900b57cec5SDimitry Andric break; 3910b57cec5SDimitry Andric std::vector<MachineOperand *>Literals; 3920b57cec5SDimitry Andric if (I->isBundle()) { 3930b57cec5SDimitry Andric MachineInstr &DeleteMI = *I; 3940b57cec5SDimitry Andric MachineBasicBlock::instr_iterator BI = I.getInstrIterator(); 3950b57cec5SDimitry Andric while (++BI != E && BI->isBundledWithPred()) { 3960b57cec5SDimitry Andric BI->unbundleFromPred(); 3970b57cec5SDimitry Andric for (MachineOperand &MO : BI->operands()) { 3980b57cec5SDimitry Andric if (MO.isReg() && MO.isInternalRead()) 3990b57cec5SDimitry Andric MO.setIsInternalRead(false); 4000b57cec5SDimitry Andric } 4010b57cec5SDimitry Andric getLiteral(*BI, Literals); 4020b57cec5SDimitry Andric ClauseContent.push_back(&*BI); 4030b57cec5SDimitry Andric } 4040b57cec5SDimitry Andric I = BI; 4050b57cec5SDimitry Andric DeleteMI.eraseFromParent(); 4060b57cec5SDimitry Andric } else { 4070b57cec5SDimitry Andric getLiteral(*I, Literals); 4080b57cec5SDimitry Andric ClauseContent.push_back(&*I); 4090b57cec5SDimitry Andric I++; 4100b57cec5SDimitry Andric } 4110b57cec5SDimitry Andric for (unsigned i = 0, e = Literals.size(); i < e; i += 2) { 4120b57cec5SDimitry Andric MachineInstrBuilder MILit = BuildMI(MBB, I, I->getDebugLoc(), 4130b57cec5SDimitry Andric TII->get(R600::LITERALS)); 4140b57cec5SDimitry Andric if (Literals[i]->isImm()) { 4150b57cec5SDimitry Andric MILit.addImm(Literals[i]->getImm()); 4160b57cec5SDimitry Andric } else { 4170b57cec5SDimitry Andric MILit.addGlobalAddress(Literals[i]->getGlobal(), 4180b57cec5SDimitry Andric Literals[i]->getOffset()); 4190b57cec5SDimitry Andric } 4200b57cec5SDimitry Andric if (i + 1 < e) { 4210b57cec5SDimitry Andric if (Literals[i + 1]->isImm()) { 4220b57cec5SDimitry Andric MILit.addImm(Literals[i + 1]->getImm()); 4230b57cec5SDimitry Andric } else { 4240b57cec5SDimitry Andric MILit.addGlobalAddress(Literals[i + 1]->getGlobal(), 4250b57cec5SDimitry Andric Literals[i + 1]->getOffset()); 4260b57cec5SDimitry Andric } 4270b57cec5SDimitry Andric } else 4280b57cec5SDimitry Andric MILit.addImm(0); 4290b57cec5SDimitry Andric ClauseContent.push_back(MILit); 4300b57cec5SDimitry Andric } 4310b57cec5SDimitry Andric } 4320b57cec5SDimitry Andric assert(ClauseContent.size() < 128 && "ALU clause is too big"); 4330b57cec5SDimitry Andric ClauseHead.getOperand(7).setImm(ClauseContent.size() - 1); 4340b57cec5SDimitry Andric return ClauseFile(&ClauseHead, std::move(ClauseContent)); 4350b57cec5SDimitry Andric } 4360b57cec5SDimitry Andric 4370b57cec5SDimitry Andric void EmitFetchClause(MachineBasicBlock::iterator InsertPos, 4380b57cec5SDimitry Andric const DebugLoc &DL, ClauseFile &Clause, 4390b57cec5SDimitry Andric unsigned &CfCount) { 4400b57cec5SDimitry Andric CounterPropagateAddr(*Clause.first, CfCount); 4410b57cec5SDimitry Andric MachineBasicBlock *BB = Clause.first->getParent(); 4420b57cec5SDimitry Andric BuildMI(BB, DL, TII->get(R600::FETCH_CLAUSE)).addImm(CfCount); 4430b57cec5SDimitry Andric for (unsigned i = 0, e = Clause.second.size(); i < e; ++i) { 4440b57cec5SDimitry Andric BB->splice(InsertPos, BB, Clause.second[i]); 4450b57cec5SDimitry Andric } 4460b57cec5SDimitry Andric CfCount += 2 * Clause.second.size(); 4470b57cec5SDimitry Andric } 4480b57cec5SDimitry Andric 4490b57cec5SDimitry Andric void EmitALUClause(MachineBasicBlock::iterator InsertPos, const DebugLoc &DL, 4500b57cec5SDimitry Andric ClauseFile &Clause, unsigned &CfCount) { 4510b57cec5SDimitry Andric Clause.first->getOperand(0).setImm(0); 4520b57cec5SDimitry Andric CounterPropagateAddr(*Clause.first, CfCount); 4530b57cec5SDimitry Andric MachineBasicBlock *BB = Clause.first->getParent(); 4540b57cec5SDimitry Andric BuildMI(BB, DL, TII->get(R600::ALU_CLAUSE)).addImm(CfCount); 4550b57cec5SDimitry Andric for (unsigned i = 0, e = Clause.second.size(); i < e; ++i) { 4560b57cec5SDimitry Andric BB->splice(InsertPos, BB, Clause.second[i]); 4570b57cec5SDimitry Andric } 4580b57cec5SDimitry Andric CfCount += Clause.second.size(); 4590b57cec5SDimitry Andric } 4600b57cec5SDimitry Andric 4610b57cec5SDimitry Andric void CounterPropagateAddr(MachineInstr &MI, unsigned Addr) const { 4620b57cec5SDimitry Andric MI.getOperand(0).setImm(Addr + MI.getOperand(0).getImm()); 4630b57cec5SDimitry Andric } 4640b57cec5SDimitry Andric void CounterPropagateAddr(const std::set<MachineInstr *> &MIs, 4650b57cec5SDimitry Andric unsigned Addr) const { 4660b57cec5SDimitry Andric for (MachineInstr *MI : MIs) { 4670b57cec5SDimitry Andric CounterPropagateAddr(*MI, Addr); 4680b57cec5SDimitry Andric } 4690b57cec5SDimitry Andric } 4700b57cec5SDimitry Andric 4710b57cec5SDimitry Andric public: 4720b57cec5SDimitry Andric static char ID; 4730b57cec5SDimitry Andric 4740b57cec5SDimitry Andric R600ControlFlowFinalizer() : MachineFunctionPass(ID) {} 4750b57cec5SDimitry Andric 4760b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override { 4770b57cec5SDimitry Andric ST = &MF.getSubtarget<R600Subtarget>(); 4780b57cec5SDimitry Andric MaxFetchInst = ST->getTexVTXClauseSize(); 4790b57cec5SDimitry Andric TII = ST->getInstrInfo(); 4800b57cec5SDimitry Andric TRI = ST->getRegisterInfo(); 4810b57cec5SDimitry Andric 4820b57cec5SDimitry Andric R600MachineFunctionInfo *MFI = MF.getInfo<R600MachineFunctionInfo>(); 4830b57cec5SDimitry Andric 4840b57cec5SDimitry Andric CFStack CFStack(ST, MF.getFunction().getCallingConv()); 4850b57cec5SDimitry Andric for (MachineFunction::iterator MB = MF.begin(), ME = MF.end(); MB != ME; 4860b57cec5SDimitry Andric ++MB) { 4870b57cec5SDimitry Andric MachineBasicBlock &MBB = *MB; 4880b57cec5SDimitry Andric unsigned CfCount = 0; 4890b57cec5SDimitry Andric std::vector<std::pair<unsigned, std::set<MachineInstr *>>> LoopStack; 4900b57cec5SDimitry Andric std::vector<MachineInstr * > IfThenElseStack; 4910b57cec5SDimitry Andric if (MF.getFunction().getCallingConv() == CallingConv::AMDGPU_VS) { 4920b57cec5SDimitry Andric BuildMI(MBB, MBB.begin(), MBB.findDebugLoc(MBB.begin()), 4930b57cec5SDimitry Andric getHWInstrDesc(CF_CALL_FS)); 4940b57cec5SDimitry Andric CfCount++; 4950b57cec5SDimitry Andric } 4960b57cec5SDimitry Andric std::vector<ClauseFile> FetchClauses, AluClauses; 4970b57cec5SDimitry Andric std::vector<MachineInstr *> LastAlu(1); 4980b57cec5SDimitry Andric std::vector<MachineInstr *> ToPopAfter; 4990b57cec5SDimitry Andric 5000b57cec5SDimitry Andric for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); 5010b57cec5SDimitry Andric I != E;) { 5020b57cec5SDimitry Andric if (TII->usesTextureCache(*I) || TII->usesVertexCache(*I)) { 5030b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << CfCount << ":"; I->dump();); 5040b57cec5SDimitry Andric FetchClauses.push_back(MakeFetchClause(MBB, I)); 5050b57cec5SDimitry Andric CfCount++; 5060b57cec5SDimitry Andric LastAlu.back() = nullptr; 5070b57cec5SDimitry Andric continue; 5080b57cec5SDimitry Andric } 5090b57cec5SDimitry Andric 5100b57cec5SDimitry Andric MachineBasicBlock::iterator MI = I; 5110b57cec5SDimitry Andric if (MI->getOpcode() != R600::ENDIF) 5120b57cec5SDimitry Andric LastAlu.back() = nullptr; 5130b57cec5SDimitry Andric if (MI->getOpcode() == R600::CF_ALU) 5140b57cec5SDimitry Andric LastAlu.back() = &*MI; 5150b57cec5SDimitry Andric I++; 5160b57cec5SDimitry Andric bool RequiresWorkAround = 5170b57cec5SDimitry Andric CFStack.requiresWorkAroundForInst(MI->getOpcode()); 5180b57cec5SDimitry Andric switch (MI->getOpcode()) { 5190b57cec5SDimitry Andric case R600::CF_ALU_PUSH_BEFORE: 5200b57cec5SDimitry Andric if (RequiresWorkAround) { 5210b57cec5SDimitry Andric LLVM_DEBUG(dbgs() 5220b57cec5SDimitry Andric << "Applying bug work-around for ALU_PUSH_BEFORE\n"); 5230b57cec5SDimitry Andric BuildMI(MBB, MI, MBB.findDebugLoc(MI), TII->get(R600::CF_PUSH_EG)) 5240b57cec5SDimitry Andric .addImm(CfCount + 1) 5250b57cec5SDimitry Andric .addImm(1); 5260b57cec5SDimitry Andric MI->setDesc(TII->get(R600::CF_ALU)); 5270b57cec5SDimitry Andric CfCount++; 5280b57cec5SDimitry Andric CFStack.pushBranch(R600::CF_PUSH_EG); 5290b57cec5SDimitry Andric } else 5300b57cec5SDimitry Andric CFStack.pushBranch(R600::CF_ALU_PUSH_BEFORE); 5310b57cec5SDimitry Andric LLVM_FALLTHROUGH; 5320b57cec5SDimitry Andric case R600::CF_ALU: 5330b57cec5SDimitry Andric I = MI; 5340b57cec5SDimitry Andric AluClauses.push_back(MakeALUClause(MBB, I)); 5350b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << CfCount << ":"; MI->dump();); 5360b57cec5SDimitry Andric CfCount++; 5370b57cec5SDimitry Andric break; 5380b57cec5SDimitry Andric case R600::WHILELOOP: { 5390b57cec5SDimitry Andric CFStack.pushLoop(); 5400b57cec5SDimitry Andric MachineInstr *MIb = BuildMI(MBB, MI, MBB.findDebugLoc(MI), 5410b57cec5SDimitry Andric getHWInstrDesc(CF_WHILE_LOOP)) 5420b57cec5SDimitry Andric .addImm(1); 5430b57cec5SDimitry Andric std::pair<unsigned, std::set<MachineInstr *>> Pair(CfCount, 5440b57cec5SDimitry Andric std::set<MachineInstr *>()); 5450b57cec5SDimitry Andric Pair.second.insert(MIb); 5460b57cec5SDimitry Andric LoopStack.push_back(std::move(Pair)); 5470b57cec5SDimitry Andric MI->eraseFromParent(); 5480b57cec5SDimitry Andric CfCount++; 5490b57cec5SDimitry Andric break; 5500b57cec5SDimitry Andric } 5510b57cec5SDimitry Andric case R600::ENDLOOP: { 5520b57cec5SDimitry Andric CFStack.popLoop(); 5530b57cec5SDimitry Andric std::pair<unsigned, std::set<MachineInstr *>> Pair = 5540b57cec5SDimitry Andric std::move(LoopStack.back()); 5550b57cec5SDimitry Andric LoopStack.pop_back(); 5560b57cec5SDimitry Andric CounterPropagateAddr(Pair.second, CfCount); 5570b57cec5SDimitry Andric BuildMI(MBB, MI, MBB.findDebugLoc(MI), getHWInstrDesc(CF_END_LOOP)) 5580b57cec5SDimitry Andric .addImm(Pair.first + 1); 5590b57cec5SDimitry Andric MI->eraseFromParent(); 5600b57cec5SDimitry Andric CfCount++; 5610b57cec5SDimitry Andric break; 5620b57cec5SDimitry Andric } 5630b57cec5SDimitry Andric case R600::IF_PREDICATE_SET: { 5640b57cec5SDimitry Andric LastAlu.push_back(nullptr); 5650b57cec5SDimitry Andric MachineInstr *MIb = BuildMI(MBB, MI, MBB.findDebugLoc(MI), 5660b57cec5SDimitry Andric getHWInstrDesc(CF_JUMP)) 5670b57cec5SDimitry Andric .addImm(0) 5680b57cec5SDimitry Andric .addImm(0); 5690b57cec5SDimitry Andric IfThenElseStack.push_back(MIb); 5700b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << CfCount << ":"; MIb->dump();); 5710b57cec5SDimitry Andric MI->eraseFromParent(); 5720b57cec5SDimitry Andric CfCount++; 5730b57cec5SDimitry Andric break; 5740b57cec5SDimitry Andric } 5750b57cec5SDimitry Andric case R600::ELSE: { 5760b57cec5SDimitry Andric MachineInstr * JumpInst = IfThenElseStack.back(); 5770b57cec5SDimitry Andric IfThenElseStack.pop_back(); 5780b57cec5SDimitry Andric CounterPropagateAddr(*JumpInst, CfCount); 5790b57cec5SDimitry Andric MachineInstr *MIb = BuildMI(MBB, MI, MBB.findDebugLoc(MI), 5800b57cec5SDimitry Andric getHWInstrDesc(CF_ELSE)) 5810b57cec5SDimitry Andric .addImm(0) 5820b57cec5SDimitry Andric .addImm(0); 5830b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << CfCount << ":"; MIb->dump();); 5840b57cec5SDimitry Andric IfThenElseStack.push_back(MIb); 5850b57cec5SDimitry Andric MI->eraseFromParent(); 5860b57cec5SDimitry Andric CfCount++; 5870b57cec5SDimitry Andric break; 5880b57cec5SDimitry Andric } 5890b57cec5SDimitry Andric case R600::ENDIF: { 5900b57cec5SDimitry Andric CFStack.popBranch(); 5910b57cec5SDimitry Andric if (LastAlu.back()) { 5920b57cec5SDimitry Andric ToPopAfter.push_back(LastAlu.back()); 5930b57cec5SDimitry Andric } else { 5940b57cec5SDimitry Andric MachineInstr *MIb = BuildMI(MBB, MI, MBB.findDebugLoc(MI), 5950b57cec5SDimitry Andric getHWInstrDesc(CF_POP)) 5960b57cec5SDimitry Andric .addImm(CfCount + 1) 5970b57cec5SDimitry Andric .addImm(1); 5980b57cec5SDimitry Andric (void)MIb; 5990b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << CfCount << ":"; MIb->dump();); 6000b57cec5SDimitry Andric CfCount++; 6010b57cec5SDimitry Andric } 6020b57cec5SDimitry Andric 6030b57cec5SDimitry Andric MachineInstr *IfOrElseInst = IfThenElseStack.back(); 6040b57cec5SDimitry Andric IfThenElseStack.pop_back(); 6050b57cec5SDimitry Andric CounterPropagateAddr(*IfOrElseInst, CfCount); 6060b57cec5SDimitry Andric IfOrElseInst->getOperand(1).setImm(1); 6070b57cec5SDimitry Andric LastAlu.pop_back(); 6080b57cec5SDimitry Andric MI->eraseFromParent(); 6090b57cec5SDimitry Andric break; 6100b57cec5SDimitry Andric } 6110b57cec5SDimitry Andric case R600::BREAK: { 6120b57cec5SDimitry Andric CfCount ++; 6130b57cec5SDimitry Andric MachineInstr *MIb = BuildMI(MBB, MI, MBB.findDebugLoc(MI), 6140b57cec5SDimitry Andric getHWInstrDesc(CF_LOOP_BREAK)) 6150b57cec5SDimitry Andric .addImm(0); 6160b57cec5SDimitry Andric LoopStack.back().second.insert(MIb); 6170b57cec5SDimitry Andric MI->eraseFromParent(); 6180b57cec5SDimitry Andric break; 6190b57cec5SDimitry Andric } 6200b57cec5SDimitry Andric case R600::CONTINUE: { 6210b57cec5SDimitry Andric MachineInstr *MIb = BuildMI(MBB, MI, MBB.findDebugLoc(MI), 6220b57cec5SDimitry Andric getHWInstrDesc(CF_LOOP_CONTINUE)) 6230b57cec5SDimitry Andric .addImm(0); 6240b57cec5SDimitry Andric LoopStack.back().second.insert(MIb); 6250b57cec5SDimitry Andric MI->eraseFromParent(); 6260b57cec5SDimitry Andric CfCount++; 6270b57cec5SDimitry Andric break; 6280b57cec5SDimitry Andric } 6290b57cec5SDimitry Andric case R600::RETURN: { 6300b57cec5SDimitry Andric DebugLoc DL = MBB.findDebugLoc(MI); 6310b57cec5SDimitry Andric BuildMI(MBB, MI, DL, getHWInstrDesc(CF_END)); 6320b57cec5SDimitry Andric CfCount++; 6330b57cec5SDimitry Andric if (CfCount % 2) { 6340b57cec5SDimitry Andric BuildMI(MBB, I, DL, TII->get(R600::PAD)); 6350b57cec5SDimitry Andric CfCount++; 6360b57cec5SDimitry Andric } 6370b57cec5SDimitry Andric MI->eraseFromParent(); 6380b57cec5SDimitry Andric for (unsigned i = 0, e = FetchClauses.size(); i < e; i++) 6390b57cec5SDimitry Andric EmitFetchClause(I, DL, FetchClauses[i], CfCount); 6400b57cec5SDimitry Andric for (unsigned i = 0, e = AluClauses.size(); i < e; i++) 6410b57cec5SDimitry Andric EmitALUClause(I, DL, AluClauses[i], CfCount); 6420b57cec5SDimitry Andric break; 6430b57cec5SDimitry Andric } 6440b57cec5SDimitry Andric default: 6450b57cec5SDimitry Andric if (TII->isExport(MI->getOpcode())) { 6460b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << CfCount << ":"; MI->dump();); 6470b57cec5SDimitry Andric CfCount++; 6480b57cec5SDimitry Andric } 6490b57cec5SDimitry Andric break; 6500b57cec5SDimitry Andric } 6510b57cec5SDimitry Andric } 6520b57cec5SDimitry Andric for (unsigned i = 0, e = ToPopAfter.size(); i < e; ++i) { 6530b57cec5SDimitry Andric MachineInstr *Alu = ToPopAfter[i]; 6540b57cec5SDimitry Andric BuildMI(MBB, Alu, MBB.findDebugLoc((MachineBasicBlock::iterator)Alu), 6550b57cec5SDimitry Andric TII->get(R600::CF_ALU_POP_AFTER)) 6560b57cec5SDimitry Andric .addImm(Alu->getOperand(0).getImm()) 6570b57cec5SDimitry Andric .addImm(Alu->getOperand(1).getImm()) 6580b57cec5SDimitry Andric .addImm(Alu->getOperand(2).getImm()) 6590b57cec5SDimitry Andric .addImm(Alu->getOperand(3).getImm()) 6600b57cec5SDimitry Andric .addImm(Alu->getOperand(4).getImm()) 6610b57cec5SDimitry Andric .addImm(Alu->getOperand(5).getImm()) 6620b57cec5SDimitry Andric .addImm(Alu->getOperand(6).getImm()) 6630b57cec5SDimitry Andric .addImm(Alu->getOperand(7).getImm()) 6640b57cec5SDimitry Andric .addImm(Alu->getOperand(8).getImm()); 6650b57cec5SDimitry Andric Alu->eraseFromParent(); 6660b57cec5SDimitry Andric } 6670b57cec5SDimitry Andric MFI->CFStackSize = CFStack.MaxStackSize; 6680b57cec5SDimitry Andric } 6690b57cec5SDimitry Andric 6700b57cec5SDimitry Andric return false; 6710b57cec5SDimitry Andric } 6720b57cec5SDimitry Andric 6730b57cec5SDimitry Andric StringRef getPassName() const override { 6740b57cec5SDimitry Andric return "R600 Control Flow Finalizer Pass"; 6750b57cec5SDimitry Andric } 6760b57cec5SDimitry Andric }; 6770b57cec5SDimitry Andric 6780b57cec5SDimitry Andric } // end anonymous namespace 6790b57cec5SDimitry Andric 6800b57cec5SDimitry Andric INITIALIZE_PASS_BEGIN(R600ControlFlowFinalizer, DEBUG_TYPE, 6810b57cec5SDimitry Andric "R600 Control Flow Finalizer", false, false) 6820b57cec5SDimitry Andric INITIALIZE_PASS_END(R600ControlFlowFinalizer, DEBUG_TYPE, 6830b57cec5SDimitry Andric "R600 Control Flow Finalizer", false, false) 6840b57cec5SDimitry Andric 6850b57cec5SDimitry Andric char R600ControlFlowFinalizer::ID = 0; 6860b57cec5SDimitry Andric 6870b57cec5SDimitry Andric char &llvm::R600ControlFlowFinalizerID = R600ControlFlowFinalizer::ID; 6880b57cec5SDimitry Andric 6890b57cec5SDimitry Andric FunctionPass *llvm::createR600ControlFlowFinalizer() { 6900b57cec5SDimitry Andric return new R600ControlFlowFinalizer(); 6910b57cec5SDimitry Andric } 692