145bb48eaSTom Stellard //===-- R600ClauseMergePass - Merge consecutive CF_ALU -------------------===//
245bb48eaSTom Stellard //
345bb48eaSTom Stellard //                     The LLVM Compiler Infrastructure
445bb48eaSTom Stellard //
545bb48eaSTom Stellard // This file is distributed under the University of Illinois Open Source
645bb48eaSTom Stellard // License. See LICENSE.TXT for details.
745bb48eaSTom Stellard //
845bb48eaSTom Stellard //===----------------------------------------------------------------------===//
945bb48eaSTom Stellard //
1045bb48eaSTom Stellard /// \file
1145bb48eaSTom Stellard /// R600EmitClauseMarker pass emits CFAlu instruction in a conservative maneer.
1245bb48eaSTom Stellard /// This pass is merging consecutive CFAlus where applicable.
1345bb48eaSTom Stellard /// It needs to be called after IfCvt for best results.
1445bb48eaSTom Stellard //===----------------------------------------------------------------------===//
1545bb48eaSTom Stellard 
1645bb48eaSTom Stellard #include "AMDGPU.h"
1745bb48eaSTom Stellard #include "AMDGPUSubtarget.h"
1845bb48eaSTom Stellard #include "R600Defines.h"
1945bb48eaSTom Stellard #include "R600InstrInfo.h"
2045bb48eaSTom Stellard #include "R600MachineFunctionInfo.h"
2145bb48eaSTom Stellard #include "R600RegisterInfo.h"
2245bb48eaSTom Stellard #include "llvm/CodeGen/MachineFunctionPass.h"
2345bb48eaSTom Stellard #include "llvm/CodeGen/MachineInstrBuilder.h"
2445bb48eaSTom Stellard #include "llvm/CodeGen/MachineRegisterInfo.h"
2545bb48eaSTom Stellard #include "llvm/Support/Debug.h"
2645bb48eaSTom Stellard #include "llvm/Support/raw_ostream.h"
2745bb48eaSTom Stellard 
2845bb48eaSTom Stellard using namespace llvm;
2945bb48eaSTom Stellard 
3045bb48eaSTom Stellard #define DEBUG_TYPE "r600mergeclause"
3145bb48eaSTom Stellard 
3245bb48eaSTom Stellard namespace {
3345bb48eaSTom Stellard 
344d295118SDuncan P. N. Exon Smith static bool isCFAlu(const MachineInstr &MI) {
354d295118SDuncan P. N. Exon Smith   switch (MI.getOpcode()) {
3645bb48eaSTom Stellard   case AMDGPU::CF_ALU:
3745bb48eaSTom Stellard   case AMDGPU::CF_ALU_PUSH_BEFORE:
3845bb48eaSTom Stellard     return true;
3945bb48eaSTom Stellard   default:
4045bb48eaSTom Stellard     return false;
4145bb48eaSTom Stellard   }
4245bb48eaSTom Stellard }
4345bb48eaSTom Stellard 
4445bb48eaSTom Stellard class R600ClauseMergePass : public MachineFunctionPass {
4545bb48eaSTom Stellard 
4645bb48eaSTom Stellard private:
4745bb48eaSTom Stellard   const R600InstrInfo *TII;
4845bb48eaSTom Stellard 
494d295118SDuncan P. N. Exon Smith   unsigned getCFAluSize(const MachineInstr &MI) const;
504d295118SDuncan P. N. Exon Smith   bool isCFAluEnabled(const MachineInstr &MI) const;
5145bb48eaSTom Stellard 
5245bb48eaSTom Stellard   /// IfCvt pass can generate "disabled" ALU clause marker that need to be
5345bb48eaSTom Stellard   /// removed and their content affected to the previous alu clause.
5445bb48eaSTom Stellard   /// This function parse instructions after CFAlu until it find a disabled
5545bb48eaSTom Stellard   /// CFAlu and merge the content, or an enabled CFAlu.
564d295118SDuncan P. N. Exon Smith   void cleanPotentialDisabledCFAlu(MachineInstr &CFAlu) const;
5745bb48eaSTom Stellard 
5845bb48eaSTom Stellard   /// Check whether LatrCFAlu can be merged into RootCFAlu and do it if
5945bb48eaSTom Stellard   /// it is the case.
604d295118SDuncan P. N. Exon Smith   bool mergeIfPossible(MachineInstr &RootCFAlu,
614d295118SDuncan P. N. Exon Smith                        const MachineInstr &LatrCFAlu) const;
6245bb48eaSTom Stellard 
6345bb48eaSTom Stellard public:
64*a2f57be2STom Stellard   static char ID;
65*a2f57be2STom Stellard 
668b61764cSFrancis Visoiu Mistrih   R600ClauseMergePass() : MachineFunctionPass(ID) { }
6745bb48eaSTom Stellard 
6845bb48eaSTom Stellard   bool runOnMachineFunction(MachineFunction &MF) override;
6945bb48eaSTom Stellard 
70117296c0SMehdi Amini   StringRef getPassName() const override;
7145bb48eaSTom Stellard };
7245bb48eaSTom Stellard 
73*a2f57be2STom Stellard } // end anonymous namespace
74*a2f57be2STom Stellard 
75*a2f57be2STom Stellard INITIALIZE_PASS_BEGIN(R600ClauseMergePass, DEBUG_TYPE,
76*a2f57be2STom Stellard                       "R600 Clause Merge", false, false)
77*a2f57be2STom Stellard INITIALIZE_PASS_END(R600ClauseMergePass, DEBUG_TYPE,
78*a2f57be2STom Stellard                     "R600 Clause Merge", false, false)
79*a2f57be2STom Stellard 
8045bb48eaSTom Stellard char R600ClauseMergePass::ID = 0;
8145bb48eaSTom Stellard 
82*a2f57be2STom Stellard char &llvm::R600ClauseMergePassID = R600ClauseMergePass::ID;
83*a2f57be2STom Stellard 
844d295118SDuncan P. N. Exon Smith unsigned R600ClauseMergePass::getCFAluSize(const MachineInstr &MI) const {
8545bb48eaSTom Stellard   assert(isCFAlu(MI));
864d295118SDuncan P. N. Exon Smith   return MI
874d295118SDuncan P. N. Exon Smith       .getOperand(TII->getOperandIdx(MI.getOpcode(), AMDGPU::OpName::COUNT))
884d295118SDuncan P. N. Exon Smith       .getImm();
8945bb48eaSTom Stellard }
9045bb48eaSTom Stellard 
914d295118SDuncan P. N. Exon Smith bool R600ClauseMergePass::isCFAluEnabled(const MachineInstr &MI) const {
9245bb48eaSTom Stellard   assert(isCFAlu(MI));
934d295118SDuncan P. N. Exon Smith   return MI
944d295118SDuncan P. N. Exon Smith       .getOperand(TII->getOperandIdx(MI.getOpcode(), AMDGPU::OpName::Enabled))
954d295118SDuncan P. N. Exon Smith       .getImm();
9645bb48eaSTom Stellard }
9745bb48eaSTom Stellard 
984d295118SDuncan P. N. Exon Smith void R600ClauseMergePass::cleanPotentialDisabledCFAlu(
994d295118SDuncan P. N. Exon Smith     MachineInstr &CFAlu) const {
10045bb48eaSTom Stellard   int CntIdx = TII->getOperandIdx(AMDGPU::CF_ALU, AMDGPU::OpName::COUNT);
1014d295118SDuncan P. N. Exon Smith   MachineBasicBlock::iterator I = CFAlu, E = CFAlu.getParent()->end();
10245bb48eaSTom Stellard   I++;
10345bb48eaSTom Stellard   do {
1044d295118SDuncan P. N. Exon Smith     while (I != E && !isCFAlu(*I))
10545bb48eaSTom Stellard       I++;
10645bb48eaSTom Stellard     if (I == E)
10745bb48eaSTom Stellard       return;
1084d295118SDuncan P. N. Exon Smith     MachineInstr &MI = *I++;
10945bb48eaSTom Stellard     if (isCFAluEnabled(MI))
11045bb48eaSTom Stellard       break;
1114d295118SDuncan P. N. Exon Smith     CFAlu.getOperand(CntIdx).setImm(getCFAluSize(CFAlu) + getCFAluSize(MI));
1124d295118SDuncan P. N. Exon Smith     MI.eraseFromParent();
11345bb48eaSTom Stellard   } while (I != E);
11445bb48eaSTom Stellard }
11545bb48eaSTom Stellard 
1164d295118SDuncan P. N. Exon Smith bool R600ClauseMergePass::mergeIfPossible(MachineInstr &RootCFAlu,
1174d295118SDuncan P. N. Exon Smith                                           const MachineInstr &LatrCFAlu) const {
11845bb48eaSTom Stellard   assert(isCFAlu(RootCFAlu) && isCFAlu(LatrCFAlu));
11945bb48eaSTom Stellard   int CntIdx = TII->getOperandIdx(AMDGPU::CF_ALU, AMDGPU::OpName::COUNT);
12045bb48eaSTom Stellard   unsigned RootInstCount = getCFAluSize(RootCFAlu),
12145bb48eaSTom Stellard       LaterInstCount = getCFAluSize(LatrCFAlu);
12245bb48eaSTom Stellard   unsigned CumuledInsts = RootInstCount + LaterInstCount;
12345bb48eaSTom Stellard   if (CumuledInsts >= TII->getMaxAlusPerClause()) {
12445bb48eaSTom Stellard     DEBUG(dbgs() << "Excess inst counts\n");
12545bb48eaSTom Stellard     return false;
12645bb48eaSTom Stellard   }
1274d295118SDuncan P. N. Exon Smith   if (RootCFAlu.getOpcode() == AMDGPU::CF_ALU_PUSH_BEFORE)
12845bb48eaSTom Stellard     return false;
12945bb48eaSTom Stellard   // Is KCache Bank 0 compatible ?
13045bb48eaSTom Stellard   int Mode0Idx =
13145bb48eaSTom Stellard       TII->getOperandIdx(AMDGPU::CF_ALU, AMDGPU::OpName::KCACHE_MODE0);
13245bb48eaSTom Stellard   int KBank0Idx =
13345bb48eaSTom Stellard       TII->getOperandIdx(AMDGPU::CF_ALU, AMDGPU::OpName::KCACHE_BANK0);
13445bb48eaSTom Stellard   int KBank0LineIdx =
13545bb48eaSTom Stellard       TII->getOperandIdx(AMDGPU::CF_ALU, AMDGPU::OpName::KCACHE_ADDR0);
1364d295118SDuncan P. N. Exon Smith   if (LatrCFAlu.getOperand(Mode0Idx).getImm() &&
1374d295118SDuncan P. N. Exon Smith       RootCFAlu.getOperand(Mode0Idx).getImm() &&
1384d295118SDuncan P. N. Exon Smith       (LatrCFAlu.getOperand(KBank0Idx).getImm() !=
1394d295118SDuncan P. N. Exon Smith            RootCFAlu.getOperand(KBank0Idx).getImm() ||
1404d295118SDuncan P. N. Exon Smith        LatrCFAlu.getOperand(KBank0LineIdx).getImm() !=
1414d295118SDuncan P. N. Exon Smith            RootCFAlu.getOperand(KBank0LineIdx).getImm())) {
14245bb48eaSTom Stellard     DEBUG(dbgs() << "Wrong KC0\n");
14345bb48eaSTom Stellard     return false;
14445bb48eaSTom Stellard   }
14545bb48eaSTom Stellard   // Is KCache Bank 1 compatible ?
14645bb48eaSTom Stellard   int Mode1Idx =
14745bb48eaSTom Stellard       TII->getOperandIdx(AMDGPU::CF_ALU, AMDGPU::OpName::KCACHE_MODE1);
14845bb48eaSTom Stellard   int KBank1Idx =
14945bb48eaSTom Stellard       TII->getOperandIdx(AMDGPU::CF_ALU, AMDGPU::OpName::KCACHE_BANK1);
15045bb48eaSTom Stellard   int KBank1LineIdx =
15145bb48eaSTom Stellard       TII->getOperandIdx(AMDGPU::CF_ALU, AMDGPU::OpName::KCACHE_ADDR1);
1524d295118SDuncan P. N. Exon Smith   if (LatrCFAlu.getOperand(Mode1Idx).getImm() &&
1534d295118SDuncan P. N. Exon Smith       RootCFAlu.getOperand(Mode1Idx).getImm() &&
1544d295118SDuncan P. N. Exon Smith       (LatrCFAlu.getOperand(KBank1Idx).getImm() !=
1554d295118SDuncan P. N. Exon Smith            RootCFAlu.getOperand(KBank1Idx).getImm() ||
1564d295118SDuncan P. N. Exon Smith        LatrCFAlu.getOperand(KBank1LineIdx).getImm() !=
1574d295118SDuncan P. N. Exon Smith            RootCFAlu.getOperand(KBank1LineIdx).getImm())) {
15845bb48eaSTom Stellard     DEBUG(dbgs() << "Wrong KC0\n");
15945bb48eaSTom Stellard     return false;
16045bb48eaSTom Stellard   }
1614d295118SDuncan P. N. Exon Smith   if (LatrCFAlu.getOperand(Mode0Idx).getImm()) {
1624d295118SDuncan P. N. Exon Smith     RootCFAlu.getOperand(Mode0Idx).setImm(
1634d295118SDuncan P. N. Exon Smith         LatrCFAlu.getOperand(Mode0Idx).getImm());
1644d295118SDuncan P. N. Exon Smith     RootCFAlu.getOperand(KBank0Idx).setImm(
1654d295118SDuncan P. N. Exon Smith         LatrCFAlu.getOperand(KBank0Idx).getImm());
1664d295118SDuncan P. N. Exon Smith     RootCFAlu.getOperand(KBank0LineIdx)
1674d295118SDuncan P. N. Exon Smith         .setImm(LatrCFAlu.getOperand(KBank0LineIdx).getImm());
16845bb48eaSTom Stellard   }
1694d295118SDuncan P. N. Exon Smith   if (LatrCFAlu.getOperand(Mode1Idx).getImm()) {
1704d295118SDuncan P. N. Exon Smith     RootCFAlu.getOperand(Mode1Idx).setImm(
1714d295118SDuncan P. N. Exon Smith         LatrCFAlu.getOperand(Mode1Idx).getImm());
1724d295118SDuncan P. N. Exon Smith     RootCFAlu.getOperand(KBank1Idx).setImm(
1734d295118SDuncan P. N. Exon Smith         LatrCFAlu.getOperand(KBank1Idx).getImm());
1744d295118SDuncan P. N. Exon Smith     RootCFAlu.getOperand(KBank1LineIdx)
1754d295118SDuncan P. N. Exon Smith         .setImm(LatrCFAlu.getOperand(KBank1LineIdx).getImm());
17645bb48eaSTom Stellard   }
1774d295118SDuncan P. N. Exon Smith   RootCFAlu.getOperand(CntIdx).setImm(CumuledInsts);
1784d295118SDuncan P. N. Exon Smith   RootCFAlu.setDesc(TII->get(LatrCFAlu.getOpcode()));
17945bb48eaSTom Stellard   return true;
18045bb48eaSTom Stellard }
18145bb48eaSTom Stellard 
18245bb48eaSTom Stellard bool R600ClauseMergePass::runOnMachineFunction(MachineFunction &MF) {
1837de74af9SAndrew Kaylor   if (skipFunction(*MF.getFunction()))
1847de74af9SAndrew Kaylor     return false;
1857de74af9SAndrew Kaylor 
18643e92fe3SMatt Arsenault   const R600Subtarget &ST = MF.getSubtarget<R600Subtarget>();
18743e92fe3SMatt Arsenault   TII = ST.getInstrInfo();
18843e92fe3SMatt Arsenault 
18945bb48eaSTom Stellard   for (MachineFunction::iterator BB = MF.begin(), BB_E = MF.end();
19045bb48eaSTom Stellard                                                   BB != BB_E; ++BB) {
19145bb48eaSTom Stellard     MachineBasicBlock &MBB = *BB;
19245bb48eaSTom Stellard     MachineBasicBlock::iterator I = MBB.begin(),  E = MBB.end();
19345bb48eaSTom Stellard     MachineBasicBlock::iterator LatestCFAlu = E;
19445bb48eaSTom Stellard     while (I != E) {
1954d295118SDuncan P. N. Exon Smith       MachineInstr &MI = *I++;
1964d295118SDuncan P. N. Exon Smith       if ((!TII->canBeConsideredALU(MI) && !isCFAlu(MI)) ||
1974d295118SDuncan P. N. Exon Smith           TII->mustBeLastInClause(MI.getOpcode()))
19845bb48eaSTom Stellard         LatestCFAlu = E;
19945bb48eaSTom Stellard       if (!isCFAlu(MI))
20045bb48eaSTom Stellard         continue;
20145bb48eaSTom Stellard       cleanPotentialDisabledCFAlu(MI);
20245bb48eaSTom Stellard 
2034d295118SDuncan P. N. Exon Smith       if (LatestCFAlu != E && mergeIfPossible(*LatestCFAlu, MI)) {
2044d295118SDuncan P. N. Exon Smith         MI.eraseFromParent();
20545bb48eaSTom Stellard       } else {
2064d295118SDuncan P. N. Exon Smith         assert(MI.getOperand(8).getImm() && "CF ALU instruction disabled");
20745bb48eaSTom Stellard         LatestCFAlu = MI;
20845bb48eaSTom Stellard       }
20945bb48eaSTom Stellard     }
21045bb48eaSTom Stellard   }
21145bb48eaSTom Stellard   return false;
21245bb48eaSTom Stellard }
21345bb48eaSTom Stellard 
214117296c0SMehdi Amini StringRef R600ClauseMergePass::getPassName() const {
21545bb48eaSTom Stellard   return "R600 Merge Clause Markers Pass";
21645bb48eaSTom Stellard }
21745bb48eaSTom Stellard 
2188b61764cSFrancis Visoiu Mistrih llvm::FunctionPass *llvm::createR600ClauseMergePass() {
2198b61764cSFrancis Visoiu Mistrih   return new R600ClauseMergePass();
22045bb48eaSTom Stellard }
221