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