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