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