1//===-- R600ClauseMergePass - Merge consecutive CF_ALU -------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9/// \file
10/// R600EmitClauseMarker pass emits CFAlu instruction in a conservative maneer.
11/// This pass is merging consecutive CFAlus where applicable.
12/// It needs to be called after IfCvt for best results.
13//===----------------------------------------------------------------------===//
14
15#include "AMDGPU.h"
16#include "AMDGPUSubtarget.h"
17#include "R600Defines.h"
18#include "R600InstrInfo.h"
19#include "R600MachineFunctionInfo.h"
20#include "R600RegisterInfo.h"
21#include "MCTargetDesc/AMDGPUMCTargetDesc.h"
22#include "llvm/CodeGen/MachineFunctionPass.h"
23#include "llvm/CodeGen/MachineInstrBuilder.h"
24#include "llvm/CodeGen/MachineRegisterInfo.h"
25#include "llvm/Support/Debug.h"
26#include "llvm/Support/raw_ostream.h"
27
28using namespace llvm;
29
30#define DEBUG_TYPE "r600mergeclause"
31
32namespace {
33
34static bool isCFAlu(const MachineInstr &MI) {
35  switch (MI.getOpcode()) {
36  case R600::CF_ALU:
37  case R600::CF_ALU_PUSH_BEFORE:
38    return true;
39  default:
40    return false;
41  }
42}
43
44class R600ClauseMergePass : public MachineFunctionPass {
45
46private:
47  const R600InstrInfo *TII;
48
49  unsigned getCFAluSize(const MachineInstr &MI) const;
50  bool isCFAluEnabled(const MachineInstr &MI) const;
51
52  /// IfCvt pass can generate "disabled" ALU clause marker that need to be
53  /// removed and their content affected to the previous alu clause.
54  /// This function parse instructions after CFAlu until it find a disabled
55  /// CFAlu and merge the content, or an enabled CFAlu.
56  void cleanPotentialDisabledCFAlu(MachineInstr &CFAlu) const;
57
58  /// Check whether LatrCFAlu can be merged into RootCFAlu and do it if
59  /// it is the case.
60  bool mergeIfPossible(MachineInstr &RootCFAlu,
61                       const MachineInstr &LatrCFAlu) const;
62
63public:
64  static char ID;
65
66  R600ClauseMergePass() : MachineFunctionPass(ID) { }
67
68  bool runOnMachineFunction(MachineFunction &MF) override;
69
70  StringRef getPassName() const override;
71};
72
73} // end anonymous namespace
74
75INITIALIZE_PASS_BEGIN(R600ClauseMergePass, DEBUG_TYPE,
76                      "R600 Clause Merge", false, false)
77INITIALIZE_PASS_END(R600ClauseMergePass, DEBUG_TYPE,
78                    "R600 Clause Merge", false, false)
79
80char R600ClauseMergePass::ID = 0;
81
82char &llvm::R600ClauseMergePassID = R600ClauseMergePass::ID;
83
84unsigned R600ClauseMergePass::getCFAluSize(const MachineInstr &MI) const {
85  assert(isCFAlu(MI));
86  return MI
87      .getOperand(TII->getOperandIdx(MI.getOpcode(), R600::OpName::COUNT))
88      .getImm();
89}
90
91bool R600ClauseMergePass::isCFAluEnabled(const MachineInstr &MI) const {
92  assert(isCFAlu(MI));
93  return MI
94      .getOperand(TII->getOperandIdx(MI.getOpcode(), R600::OpName::Enabled))
95      .getImm();
96}
97
98void R600ClauseMergePass::cleanPotentialDisabledCFAlu(
99    MachineInstr &CFAlu) const {
100  int CntIdx = TII->getOperandIdx(R600::CF_ALU, R600::OpName::COUNT);
101  MachineBasicBlock::iterator I = CFAlu, E = CFAlu.getParent()->end();
102  I++;
103  do {
104    while (I != E && !isCFAlu(*I))
105      I++;
106    if (I == E)
107      return;
108    MachineInstr &MI = *I++;
109    if (isCFAluEnabled(MI))
110      break;
111    CFAlu.getOperand(CntIdx).setImm(getCFAluSize(CFAlu) + getCFAluSize(MI));
112    MI.eraseFromParent();
113  } while (I != E);
114}
115
116bool R600ClauseMergePass::mergeIfPossible(MachineInstr &RootCFAlu,
117                                          const MachineInstr &LatrCFAlu) const {
118  assert(isCFAlu(RootCFAlu) && isCFAlu(LatrCFAlu));
119  int CntIdx = TII->getOperandIdx(R600::CF_ALU, R600::OpName::COUNT);
120  unsigned RootInstCount = getCFAluSize(RootCFAlu),
121      LaterInstCount = getCFAluSize(LatrCFAlu);
122  unsigned CumuledInsts = RootInstCount + LaterInstCount;
123  if (CumuledInsts >= TII->getMaxAlusPerClause()) {
124    LLVM_DEBUG(dbgs() << "Excess inst counts\n");
125    return false;
126  }
127  if (RootCFAlu.getOpcode() == R600::CF_ALU_PUSH_BEFORE)
128    return false;
129  // Is KCache Bank 0 compatible ?
130  int Mode0Idx =
131      TII->getOperandIdx(R600::CF_ALU, R600::OpName::KCACHE_MODE0);
132  int KBank0Idx =
133      TII->getOperandIdx(R600::CF_ALU, R600::OpName::KCACHE_BANK0);
134  int KBank0LineIdx =
135      TII->getOperandIdx(R600::CF_ALU, R600::OpName::KCACHE_ADDR0);
136  if (LatrCFAlu.getOperand(Mode0Idx).getImm() &&
137      RootCFAlu.getOperand(Mode0Idx).getImm() &&
138      (LatrCFAlu.getOperand(KBank0Idx).getImm() !=
139           RootCFAlu.getOperand(KBank0Idx).getImm() ||
140       LatrCFAlu.getOperand(KBank0LineIdx).getImm() !=
141           RootCFAlu.getOperand(KBank0LineIdx).getImm())) {
142    LLVM_DEBUG(dbgs() << "Wrong KC0\n");
143    return false;
144  }
145  // Is KCache Bank 1 compatible ?
146  int Mode1Idx =
147      TII->getOperandIdx(R600::CF_ALU, R600::OpName::KCACHE_MODE1);
148  int KBank1Idx =
149      TII->getOperandIdx(R600::CF_ALU, R600::OpName::KCACHE_BANK1);
150  int KBank1LineIdx =
151      TII->getOperandIdx(R600::CF_ALU, R600::OpName::KCACHE_ADDR1);
152  if (LatrCFAlu.getOperand(Mode1Idx).getImm() &&
153      RootCFAlu.getOperand(Mode1Idx).getImm() &&
154      (LatrCFAlu.getOperand(KBank1Idx).getImm() !=
155           RootCFAlu.getOperand(KBank1Idx).getImm() ||
156       LatrCFAlu.getOperand(KBank1LineIdx).getImm() !=
157           RootCFAlu.getOperand(KBank1LineIdx).getImm())) {
158    LLVM_DEBUG(dbgs() << "Wrong KC0\n");
159    return false;
160  }
161  if (LatrCFAlu.getOperand(Mode0Idx).getImm()) {
162    RootCFAlu.getOperand(Mode0Idx).setImm(
163        LatrCFAlu.getOperand(Mode0Idx).getImm());
164    RootCFAlu.getOperand(KBank0Idx).setImm(
165        LatrCFAlu.getOperand(KBank0Idx).getImm());
166    RootCFAlu.getOperand(KBank0LineIdx)
167        .setImm(LatrCFAlu.getOperand(KBank0LineIdx).getImm());
168  }
169  if (LatrCFAlu.getOperand(Mode1Idx).getImm()) {
170    RootCFAlu.getOperand(Mode1Idx).setImm(
171        LatrCFAlu.getOperand(Mode1Idx).getImm());
172    RootCFAlu.getOperand(KBank1Idx).setImm(
173        LatrCFAlu.getOperand(KBank1Idx).getImm());
174    RootCFAlu.getOperand(KBank1LineIdx)
175        .setImm(LatrCFAlu.getOperand(KBank1LineIdx).getImm());
176  }
177  RootCFAlu.getOperand(CntIdx).setImm(CumuledInsts);
178  RootCFAlu.setDesc(TII->get(LatrCFAlu.getOpcode()));
179  return true;
180}
181
182bool R600ClauseMergePass::runOnMachineFunction(MachineFunction &MF) {
183  if (skipFunction(MF.getFunction()))
184    return false;
185
186  const R600Subtarget &ST = MF.getSubtarget<R600Subtarget>();
187  TII = ST.getInstrInfo();
188
189  for (MachineFunction::iterator BB = MF.begin(), BB_E = MF.end();
190                                                  BB != BB_E; ++BB) {
191    MachineBasicBlock &MBB = *BB;
192    MachineBasicBlock::iterator I = MBB.begin(),  E = MBB.end();
193    MachineBasicBlock::iterator LatestCFAlu = E;
194    while (I != E) {
195      MachineInstr &MI = *I++;
196      if ((!TII->canBeConsideredALU(MI) && !isCFAlu(MI)) ||
197          TII->mustBeLastInClause(MI.getOpcode()))
198        LatestCFAlu = E;
199      if (!isCFAlu(MI))
200        continue;
201      cleanPotentialDisabledCFAlu(MI);
202
203      if (LatestCFAlu != E && mergeIfPossible(*LatestCFAlu, MI)) {
204        MI.eraseFromParent();
205      } else {
206        assert(MI.getOperand(8).getImm() && "CF ALU instruction disabled");
207        LatestCFAlu = MI;
208      }
209    }
210  }
211  return false;
212}
213
214StringRef R600ClauseMergePass::getPassName() const {
215  return "R600 Merge Clause Markers Pass";
216}
217
218llvm::FunctionPass *llvm::createR600ClauseMergePass() {
219  return new R600ClauseMergePass();
220}
221