10b57cec5SDimitry Andric //===-- R600ClauseMergePass - Merge consecutive CF_ALU -------------------===//
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 /// R600EmitClauseMarker pass emits CFAlu instruction in a conservative maneer.
110b57cec5SDimitry Andric /// This pass is merging consecutive CFAlus where applicable.
120b57cec5SDimitry Andric /// It needs to be called after IfCvt for best results.
130b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
140b57cec5SDimitry Andric 
150b57cec5SDimitry Andric #include "AMDGPU.h"
160b57cec5SDimitry Andric #include "MCTargetDesc/AMDGPUMCTargetDesc.h"
17*af732203SDimitry Andric #include "R600Subtarget.h"
180b57cec5SDimitry Andric 
190b57cec5SDimitry Andric using namespace llvm;
200b57cec5SDimitry Andric 
210b57cec5SDimitry Andric #define DEBUG_TYPE "r600mergeclause"
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric namespace {
240b57cec5SDimitry Andric 
isCFAlu(const MachineInstr & MI)250b57cec5SDimitry Andric static bool isCFAlu(const MachineInstr &MI) {
260b57cec5SDimitry Andric   switch (MI.getOpcode()) {
270b57cec5SDimitry Andric   case R600::CF_ALU:
280b57cec5SDimitry Andric   case R600::CF_ALU_PUSH_BEFORE:
290b57cec5SDimitry Andric     return true;
300b57cec5SDimitry Andric   default:
310b57cec5SDimitry Andric     return false;
320b57cec5SDimitry Andric   }
330b57cec5SDimitry Andric }
340b57cec5SDimitry Andric 
350b57cec5SDimitry Andric class R600ClauseMergePass : public MachineFunctionPass {
360b57cec5SDimitry Andric 
370b57cec5SDimitry Andric private:
380b57cec5SDimitry Andric   const R600InstrInfo *TII;
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric   unsigned getCFAluSize(const MachineInstr &MI) const;
410b57cec5SDimitry Andric   bool isCFAluEnabled(const MachineInstr &MI) const;
420b57cec5SDimitry Andric 
430b57cec5SDimitry Andric   /// IfCvt pass can generate "disabled" ALU clause marker that need to be
440b57cec5SDimitry Andric   /// removed and their content affected to the previous alu clause.
450b57cec5SDimitry Andric   /// This function parse instructions after CFAlu until it find a disabled
460b57cec5SDimitry Andric   /// CFAlu and merge the content, or an enabled CFAlu.
470b57cec5SDimitry Andric   void cleanPotentialDisabledCFAlu(MachineInstr &CFAlu) const;
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric   /// Check whether LatrCFAlu can be merged into RootCFAlu and do it if
500b57cec5SDimitry Andric   /// it is the case.
510b57cec5SDimitry Andric   bool mergeIfPossible(MachineInstr &RootCFAlu,
520b57cec5SDimitry Andric                        const MachineInstr &LatrCFAlu) const;
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric public:
550b57cec5SDimitry Andric   static char ID;
560b57cec5SDimitry Andric 
R600ClauseMergePass()570b57cec5SDimitry Andric   R600ClauseMergePass() : MachineFunctionPass(ID) { }
580b57cec5SDimitry Andric 
590b57cec5SDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
600b57cec5SDimitry Andric 
610b57cec5SDimitry Andric   StringRef getPassName() const override;
620b57cec5SDimitry Andric };
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric } // end anonymous namespace
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric INITIALIZE_PASS_BEGIN(R600ClauseMergePass, DEBUG_TYPE,
670b57cec5SDimitry Andric                       "R600 Clause Merge", false, false)
680b57cec5SDimitry Andric INITIALIZE_PASS_END(R600ClauseMergePass, DEBUG_TYPE,
690b57cec5SDimitry Andric                     "R600 Clause Merge", false, false)
700b57cec5SDimitry Andric 
710b57cec5SDimitry Andric char R600ClauseMergePass::ID = 0;
720b57cec5SDimitry Andric 
730b57cec5SDimitry Andric char &llvm::R600ClauseMergePassID = R600ClauseMergePass::ID;
740b57cec5SDimitry Andric 
getCFAluSize(const MachineInstr & MI) const750b57cec5SDimitry Andric unsigned R600ClauseMergePass::getCFAluSize(const MachineInstr &MI) const {
760b57cec5SDimitry Andric   assert(isCFAlu(MI));
770b57cec5SDimitry Andric   return MI
780b57cec5SDimitry Andric       .getOperand(TII->getOperandIdx(MI.getOpcode(), R600::OpName::COUNT))
790b57cec5SDimitry Andric       .getImm();
800b57cec5SDimitry Andric }
810b57cec5SDimitry Andric 
isCFAluEnabled(const MachineInstr & MI) const820b57cec5SDimitry Andric bool R600ClauseMergePass::isCFAluEnabled(const MachineInstr &MI) const {
830b57cec5SDimitry Andric   assert(isCFAlu(MI));
840b57cec5SDimitry Andric   return MI
850b57cec5SDimitry Andric       .getOperand(TII->getOperandIdx(MI.getOpcode(), R600::OpName::Enabled))
860b57cec5SDimitry Andric       .getImm();
870b57cec5SDimitry Andric }
880b57cec5SDimitry Andric 
cleanPotentialDisabledCFAlu(MachineInstr & CFAlu) const890b57cec5SDimitry Andric void R600ClauseMergePass::cleanPotentialDisabledCFAlu(
900b57cec5SDimitry Andric     MachineInstr &CFAlu) const {
910b57cec5SDimitry Andric   int CntIdx = TII->getOperandIdx(R600::CF_ALU, R600::OpName::COUNT);
920b57cec5SDimitry Andric   MachineBasicBlock::iterator I = CFAlu, E = CFAlu.getParent()->end();
930b57cec5SDimitry Andric   I++;
940b57cec5SDimitry Andric   do {
950b57cec5SDimitry Andric     while (I != E && !isCFAlu(*I))
960b57cec5SDimitry Andric       I++;
970b57cec5SDimitry Andric     if (I == E)
980b57cec5SDimitry Andric       return;
990b57cec5SDimitry Andric     MachineInstr &MI = *I++;
1000b57cec5SDimitry Andric     if (isCFAluEnabled(MI))
1010b57cec5SDimitry Andric       break;
1020b57cec5SDimitry Andric     CFAlu.getOperand(CntIdx).setImm(getCFAluSize(CFAlu) + getCFAluSize(MI));
1030b57cec5SDimitry Andric     MI.eraseFromParent();
1040b57cec5SDimitry Andric   } while (I != E);
1050b57cec5SDimitry Andric }
1060b57cec5SDimitry Andric 
mergeIfPossible(MachineInstr & RootCFAlu,const MachineInstr & LatrCFAlu) const1070b57cec5SDimitry Andric bool R600ClauseMergePass::mergeIfPossible(MachineInstr &RootCFAlu,
1080b57cec5SDimitry Andric                                           const MachineInstr &LatrCFAlu) const {
1090b57cec5SDimitry Andric   assert(isCFAlu(RootCFAlu) && isCFAlu(LatrCFAlu));
1100b57cec5SDimitry Andric   int CntIdx = TII->getOperandIdx(R600::CF_ALU, R600::OpName::COUNT);
1110b57cec5SDimitry Andric   unsigned RootInstCount = getCFAluSize(RootCFAlu),
1120b57cec5SDimitry Andric       LaterInstCount = getCFAluSize(LatrCFAlu);
1130b57cec5SDimitry Andric   unsigned CumuledInsts = RootInstCount + LaterInstCount;
1140b57cec5SDimitry Andric   if (CumuledInsts >= TII->getMaxAlusPerClause()) {
1150b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Excess inst counts\n");
1160b57cec5SDimitry Andric     return false;
1170b57cec5SDimitry Andric   }
1180b57cec5SDimitry Andric   if (RootCFAlu.getOpcode() == R600::CF_ALU_PUSH_BEFORE)
1190b57cec5SDimitry Andric     return false;
1200b57cec5SDimitry Andric   // Is KCache Bank 0 compatible ?
1210b57cec5SDimitry Andric   int Mode0Idx =
1220b57cec5SDimitry Andric       TII->getOperandIdx(R600::CF_ALU, R600::OpName::KCACHE_MODE0);
1230b57cec5SDimitry Andric   int KBank0Idx =
1240b57cec5SDimitry Andric       TII->getOperandIdx(R600::CF_ALU, R600::OpName::KCACHE_BANK0);
1250b57cec5SDimitry Andric   int KBank0LineIdx =
1260b57cec5SDimitry Andric       TII->getOperandIdx(R600::CF_ALU, R600::OpName::KCACHE_ADDR0);
1270b57cec5SDimitry Andric   if (LatrCFAlu.getOperand(Mode0Idx).getImm() &&
1280b57cec5SDimitry Andric       RootCFAlu.getOperand(Mode0Idx).getImm() &&
1290b57cec5SDimitry Andric       (LatrCFAlu.getOperand(KBank0Idx).getImm() !=
1300b57cec5SDimitry Andric            RootCFAlu.getOperand(KBank0Idx).getImm() ||
1310b57cec5SDimitry Andric        LatrCFAlu.getOperand(KBank0LineIdx).getImm() !=
1320b57cec5SDimitry Andric            RootCFAlu.getOperand(KBank0LineIdx).getImm())) {
1330b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Wrong KC0\n");
1340b57cec5SDimitry Andric     return false;
1350b57cec5SDimitry Andric   }
1360b57cec5SDimitry Andric   // Is KCache Bank 1 compatible ?
1370b57cec5SDimitry Andric   int Mode1Idx =
1380b57cec5SDimitry Andric       TII->getOperandIdx(R600::CF_ALU, R600::OpName::KCACHE_MODE1);
1390b57cec5SDimitry Andric   int KBank1Idx =
1400b57cec5SDimitry Andric       TII->getOperandIdx(R600::CF_ALU, R600::OpName::KCACHE_BANK1);
1410b57cec5SDimitry Andric   int KBank1LineIdx =
1420b57cec5SDimitry Andric       TII->getOperandIdx(R600::CF_ALU, R600::OpName::KCACHE_ADDR1);
1430b57cec5SDimitry Andric   if (LatrCFAlu.getOperand(Mode1Idx).getImm() &&
1440b57cec5SDimitry Andric       RootCFAlu.getOperand(Mode1Idx).getImm() &&
1450b57cec5SDimitry Andric       (LatrCFAlu.getOperand(KBank1Idx).getImm() !=
1460b57cec5SDimitry Andric            RootCFAlu.getOperand(KBank1Idx).getImm() ||
1470b57cec5SDimitry Andric        LatrCFAlu.getOperand(KBank1LineIdx).getImm() !=
1480b57cec5SDimitry Andric            RootCFAlu.getOperand(KBank1LineIdx).getImm())) {
1490b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Wrong KC0\n");
1500b57cec5SDimitry Andric     return false;
1510b57cec5SDimitry Andric   }
1520b57cec5SDimitry Andric   if (LatrCFAlu.getOperand(Mode0Idx).getImm()) {
1530b57cec5SDimitry Andric     RootCFAlu.getOperand(Mode0Idx).setImm(
1540b57cec5SDimitry Andric         LatrCFAlu.getOperand(Mode0Idx).getImm());
1550b57cec5SDimitry Andric     RootCFAlu.getOperand(KBank0Idx).setImm(
1560b57cec5SDimitry Andric         LatrCFAlu.getOperand(KBank0Idx).getImm());
1570b57cec5SDimitry Andric     RootCFAlu.getOperand(KBank0LineIdx)
1580b57cec5SDimitry Andric         .setImm(LatrCFAlu.getOperand(KBank0LineIdx).getImm());
1590b57cec5SDimitry Andric   }
1600b57cec5SDimitry Andric   if (LatrCFAlu.getOperand(Mode1Idx).getImm()) {
1610b57cec5SDimitry Andric     RootCFAlu.getOperand(Mode1Idx).setImm(
1620b57cec5SDimitry Andric         LatrCFAlu.getOperand(Mode1Idx).getImm());
1630b57cec5SDimitry Andric     RootCFAlu.getOperand(KBank1Idx).setImm(
1640b57cec5SDimitry Andric         LatrCFAlu.getOperand(KBank1Idx).getImm());
1650b57cec5SDimitry Andric     RootCFAlu.getOperand(KBank1LineIdx)
1660b57cec5SDimitry Andric         .setImm(LatrCFAlu.getOperand(KBank1LineIdx).getImm());
1670b57cec5SDimitry Andric   }
1680b57cec5SDimitry Andric   RootCFAlu.getOperand(CntIdx).setImm(CumuledInsts);
1690b57cec5SDimitry Andric   RootCFAlu.setDesc(TII->get(LatrCFAlu.getOpcode()));
1700b57cec5SDimitry Andric   return true;
1710b57cec5SDimitry Andric }
1720b57cec5SDimitry Andric 
runOnMachineFunction(MachineFunction & MF)1730b57cec5SDimitry Andric bool R600ClauseMergePass::runOnMachineFunction(MachineFunction &MF) {
1740b57cec5SDimitry Andric   if (skipFunction(MF.getFunction()))
1750b57cec5SDimitry Andric     return false;
1760b57cec5SDimitry Andric 
1770b57cec5SDimitry Andric   const R600Subtarget &ST = MF.getSubtarget<R600Subtarget>();
1780b57cec5SDimitry Andric   TII = ST.getInstrInfo();
1790b57cec5SDimitry Andric 
1800b57cec5SDimitry Andric   for (MachineFunction::iterator BB = MF.begin(), BB_E = MF.end();
1810b57cec5SDimitry Andric                                                   BB != BB_E; ++BB) {
1820b57cec5SDimitry Andric     MachineBasicBlock &MBB = *BB;
1830b57cec5SDimitry Andric     MachineBasicBlock::iterator I = MBB.begin(),  E = MBB.end();
1840b57cec5SDimitry Andric     MachineBasicBlock::iterator LatestCFAlu = E;
1850b57cec5SDimitry Andric     while (I != E) {
1860b57cec5SDimitry Andric       MachineInstr &MI = *I++;
1870b57cec5SDimitry Andric       if ((!TII->canBeConsideredALU(MI) && !isCFAlu(MI)) ||
1880b57cec5SDimitry Andric           TII->mustBeLastInClause(MI.getOpcode()))
1890b57cec5SDimitry Andric         LatestCFAlu = E;
1900b57cec5SDimitry Andric       if (!isCFAlu(MI))
1910b57cec5SDimitry Andric         continue;
1920b57cec5SDimitry Andric       cleanPotentialDisabledCFAlu(MI);
1930b57cec5SDimitry Andric 
1940b57cec5SDimitry Andric       if (LatestCFAlu != E && mergeIfPossible(*LatestCFAlu, MI)) {
1950b57cec5SDimitry Andric         MI.eraseFromParent();
1960b57cec5SDimitry Andric       } else {
1970b57cec5SDimitry Andric         assert(MI.getOperand(8).getImm() && "CF ALU instruction disabled");
1980b57cec5SDimitry Andric         LatestCFAlu = MI;
1990b57cec5SDimitry Andric       }
2000b57cec5SDimitry Andric     }
2010b57cec5SDimitry Andric   }
2020b57cec5SDimitry Andric   return false;
2030b57cec5SDimitry Andric }
2040b57cec5SDimitry Andric 
getPassName() const2050b57cec5SDimitry Andric StringRef R600ClauseMergePass::getPassName() const {
2060b57cec5SDimitry Andric   return "R600 Merge Clause Markers Pass";
2070b57cec5SDimitry Andric }
2080b57cec5SDimitry Andric 
createR600ClauseMergePass()2090b57cec5SDimitry Andric llvm::FunctionPass *llvm::createR600ClauseMergePass() {
2100b57cec5SDimitry Andric   return new R600ClauseMergePass();
2110b57cec5SDimitry Andric }
212