| //===-- R600ClauseMergePass - Merge consecutive CF_ALU -------------------===// | |
| // | |
| // The LLVM Compiler Infrastructure | |
| // | |
| // This file is distributed under the University of Illinois Open Source | |
| // License. See LICENSE.TXT for details. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| /// \file | |
| /// R600EmitClauseMarker pass emits CFAlu instruction in a conservative maneer. | |
| /// This pass is merging consecutive CFAlus where applicable. | |
| /// It needs to be called after IfCvt for best results. | |
| //===----------------------------------------------------------------------===// | |
| #include "AMDGPU.h" | |
| #include "AMDGPUSubtarget.h" | |
| #include "R600Defines.h" | |
| #include "R600InstrInfo.h" | |
| #include "R600MachineFunctionInfo.h" | |
| #include "R600RegisterInfo.h" | |
| #include "MCTargetDesc/AMDGPUMCTargetDesc.h" | |
| #include "llvm/CodeGen/MachineFunctionPass.h" | |
| #include "llvm/CodeGen/MachineInstrBuilder.h" | |
| #include "llvm/CodeGen/MachineRegisterInfo.h" | |
| #include "llvm/Support/Debug.h" | |
| #include "llvm/Support/raw_ostream.h" | |
| using namespace llvm; | |
| #define DEBUG_TYPE "r600mergeclause" | |
| namespace { | |
| static bool isCFAlu(const MachineInstr &MI) { | |
| switch (MI.getOpcode()) { | |
| case R600::CF_ALU: | |
| case R600::CF_ALU_PUSH_BEFORE: | |
| return true; | |
| default: | |
| return false; | |
| } | |
| } | |
| class R600ClauseMergePass : public MachineFunctionPass { | |
| private: | |
| const R600InstrInfo *TII; | |
| unsigned getCFAluSize(const MachineInstr &MI) const; | |
| bool isCFAluEnabled(const MachineInstr &MI) const; | |
| /// IfCvt pass can generate "disabled" ALU clause marker that need to be | |
| /// removed and their content affected to the previous alu clause. | |
| /// This function parse instructions after CFAlu until it find a disabled | |
| /// CFAlu and merge the content, or an enabled CFAlu. | |
| void cleanPotentialDisabledCFAlu(MachineInstr &CFAlu) const; | |
| /// Check whether LatrCFAlu can be merged into RootCFAlu and do it if | |
| /// it is the case. | |
| bool mergeIfPossible(MachineInstr &RootCFAlu, | |
| const MachineInstr &LatrCFAlu) const; | |
| public: | |
| static char ID; | |
| R600ClauseMergePass() : MachineFunctionPass(ID) { } | |
| bool runOnMachineFunction(MachineFunction &MF) override; | |
| StringRef getPassName() const override; | |
| }; | |
| } // end anonymous namespace | |
| INITIALIZE_PASS_BEGIN(R600ClauseMergePass, DEBUG_TYPE, | |
| "R600 Clause Merge", false, false) | |
| INITIALIZE_PASS_END(R600ClauseMergePass, DEBUG_TYPE, | |
| "R600 Clause Merge", false, false) | |
| char R600ClauseMergePass::ID = 0; | |
| char &llvm::R600ClauseMergePassID = R600ClauseMergePass::ID; | |
| unsigned R600ClauseMergePass::getCFAluSize(const MachineInstr &MI) const { | |
| assert(isCFAlu(MI)); | |
| return MI | |
| .getOperand(TII->getOperandIdx(MI.getOpcode(), R600::OpName::COUNT)) | |
| .getImm(); | |
| } | |
| bool R600ClauseMergePass::isCFAluEnabled(const MachineInstr &MI) const { | |
| assert(isCFAlu(MI)); | |
| return MI | |
| .getOperand(TII->getOperandIdx(MI.getOpcode(), R600::OpName::Enabled)) | |
| .getImm(); | |
| } | |
| void R600ClauseMergePass::cleanPotentialDisabledCFAlu( | |
| MachineInstr &CFAlu) const { | |
| int CntIdx = TII->getOperandIdx(R600::CF_ALU, R600::OpName::COUNT); | |
| MachineBasicBlock::iterator I = CFAlu, E = CFAlu.getParent()->end(); | |
| I++; | |
| do { | |
| while (I != E && !isCFAlu(*I)) | |
| I++; | |
| if (I == E) | |
| return; | |
| MachineInstr &MI = *I++; | |
| if (isCFAluEnabled(MI)) | |
| break; | |
| CFAlu.getOperand(CntIdx).setImm(getCFAluSize(CFAlu) + getCFAluSize(MI)); | |
| MI.eraseFromParent(); | |
| } while (I != E); | |
| } | |
| bool R600ClauseMergePass::mergeIfPossible(MachineInstr &RootCFAlu, | |
| const MachineInstr &LatrCFAlu) const { | |
| assert(isCFAlu(RootCFAlu) && isCFAlu(LatrCFAlu)); | |
| int CntIdx = TII->getOperandIdx(R600::CF_ALU, R600::OpName::COUNT); | |
| unsigned RootInstCount = getCFAluSize(RootCFAlu), | |
| LaterInstCount = getCFAluSize(LatrCFAlu); | |
| unsigned CumuledInsts = RootInstCount + LaterInstCount; | |
| if (CumuledInsts >= TII->getMaxAlusPerClause()) { | |
| LLVM_DEBUG(dbgs() << "Excess inst counts\n"); | |
| return false; | |
| } | |
| if (RootCFAlu.getOpcode() == R600::CF_ALU_PUSH_BEFORE) | |
| return false; | |
| // Is KCache Bank 0 compatible ? | |
| int Mode0Idx = | |
| TII->getOperandIdx(R600::CF_ALU, R600::OpName::KCACHE_MODE0); | |
| int KBank0Idx = | |
| TII->getOperandIdx(R600::CF_ALU, R600::OpName::KCACHE_BANK0); | |
| int KBank0LineIdx = | |
| TII->getOperandIdx(R600::CF_ALU, R600::OpName::KCACHE_ADDR0); | |
| if (LatrCFAlu.getOperand(Mode0Idx).getImm() && | |
| RootCFAlu.getOperand(Mode0Idx).getImm() && | |
| (LatrCFAlu.getOperand(KBank0Idx).getImm() != | |
| RootCFAlu.getOperand(KBank0Idx).getImm() || | |
| LatrCFAlu.getOperand(KBank0LineIdx).getImm() != | |
| RootCFAlu.getOperand(KBank0LineIdx).getImm())) { | |
| LLVM_DEBUG(dbgs() << "Wrong KC0\n"); | |
| return false; | |
| } | |
| // Is KCache Bank 1 compatible ? | |
| int Mode1Idx = | |
| TII->getOperandIdx(R600::CF_ALU, R600::OpName::KCACHE_MODE1); | |
| int KBank1Idx = | |
| TII->getOperandIdx(R600::CF_ALU, R600::OpName::KCACHE_BANK1); | |
| int KBank1LineIdx = | |
| TII->getOperandIdx(R600::CF_ALU, R600::OpName::KCACHE_ADDR1); | |
| if (LatrCFAlu.getOperand(Mode1Idx).getImm() && | |
| RootCFAlu.getOperand(Mode1Idx).getImm() && | |
| (LatrCFAlu.getOperand(KBank1Idx).getImm() != | |
| RootCFAlu.getOperand(KBank1Idx).getImm() || | |
| LatrCFAlu.getOperand(KBank1LineIdx).getImm() != | |
| RootCFAlu.getOperand(KBank1LineIdx).getImm())) { | |
| LLVM_DEBUG(dbgs() << "Wrong KC0\n"); | |
| return false; | |
| } | |
| if (LatrCFAlu.getOperand(Mode0Idx).getImm()) { | |
| RootCFAlu.getOperand(Mode0Idx).setImm( | |
| LatrCFAlu.getOperand(Mode0Idx).getImm()); | |
| RootCFAlu.getOperand(KBank0Idx).setImm( | |
| LatrCFAlu.getOperand(KBank0Idx).getImm()); | |
| RootCFAlu.getOperand(KBank0LineIdx) | |
| .setImm(LatrCFAlu.getOperand(KBank0LineIdx).getImm()); | |
| } | |
| if (LatrCFAlu.getOperand(Mode1Idx).getImm()) { | |
| RootCFAlu.getOperand(Mode1Idx).setImm( | |
| LatrCFAlu.getOperand(Mode1Idx).getImm()); | |
| RootCFAlu.getOperand(KBank1Idx).setImm( | |
| LatrCFAlu.getOperand(KBank1Idx).getImm()); | |
| RootCFAlu.getOperand(KBank1LineIdx) | |
| .setImm(LatrCFAlu.getOperand(KBank1LineIdx).getImm()); | |
| } | |
| RootCFAlu.getOperand(CntIdx).setImm(CumuledInsts); | |
| RootCFAlu.setDesc(TII->get(LatrCFAlu.getOpcode())); | |
| return true; | |
| } | |
| bool R600ClauseMergePass::runOnMachineFunction(MachineFunction &MF) { | |
| if (skipFunction(MF.getFunction())) | |
| return false; | |
| const R600Subtarget &ST = MF.getSubtarget<R600Subtarget>(); | |
| TII = ST.getInstrInfo(); | |
| for (MachineFunction::iterator BB = MF.begin(), BB_E = MF.end(); | |
| BB != BB_E; ++BB) { | |
| MachineBasicBlock &MBB = *BB; | |
| MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); | |
| MachineBasicBlock::iterator LatestCFAlu = E; | |
| while (I != E) { | |
| MachineInstr &MI = *I++; | |
| if ((!TII->canBeConsideredALU(MI) && !isCFAlu(MI)) || | |
| TII->mustBeLastInClause(MI.getOpcode())) | |
| LatestCFAlu = E; | |
| if (!isCFAlu(MI)) | |
| continue; | |
| cleanPotentialDisabledCFAlu(MI); | |
| if (LatestCFAlu != E && mergeIfPossible(*LatestCFAlu, MI)) { | |
| MI.eraseFromParent(); | |
| } else { | |
| assert(MI.getOperand(8).getImm() && "CF ALU instruction disabled"); | |
| LatestCFAlu = MI; | |
| } | |
| } | |
| } | |
| return false; | |
| } | |
| StringRef R600ClauseMergePass::getPassName() const { | |
| return "R600 Merge Clause Markers Pass"; | |
| } | |
| llvm::FunctionPass *llvm::createR600ClauseMergePass() { | |
| return new R600ClauseMergePass(); | |
| } |