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