1//===-- SIPostRABundler.cpp -----------------------------------------------===//
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/// This pass creates bundles of memory instructions to protect adjacent loads
11/// and stores from beeing rescheduled apart from each other post-RA.
12///
13//===----------------------------------------------------------------------===//
14
15#include "AMDGPU.h"
16#include "AMDGPUSubtarget.h"
17#include "SIDefines.h"
18#include "SIInstrInfo.h"
19#include "llvm/ADT/SmallSet.h"
20#include "llvm/CodeGen/MachineFunctionPass.h"
21#include "llvm/CodeGen/MachineInstrBundle.h"
22#include "llvm/InitializePasses.h"
23
24using namespace llvm;
25
26#define DEBUG_TYPE "si-post-ra-bundler"
27
28namespace {
29
30class SIPostRABundler : public MachineFunctionPass {
31public:
32  static char ID;
33
34public:
35  SIPostRABundler() : MachineFunctionPass(ID) {
36    initializeSIPostRABundlerPass(*PassRegistry::getPassRegistry());
37  }
38
39  bool runOnMachineFunction(MachineFunction &MF) override;
40
41  StringRef getPassName() const override {
42    return "SI post-RA bundler";
43  }
44
45  void getAnalysisUsage(AnalysisUsage &AU) const override {
46    AU.setPreservesAll();
47    MachineFunctionPass::getAnalysisUsage(AU);
48  }
49
50private:
51  const SIRegisterInfo *TRI;
52
53  SmallSet<Register, 16> Defs;
54
55  bool isDependentLoad(const MachineInstr &MI) const;
56
57};
58
59} // End anonymous namespace.
60
61INITIALIZE_PASS(SIPostRABundler, DEBUG_TYPE, "SI post-RA bundler", false, false)
62
63char SIPostRABundler::ID = 0;
64
65char &llvm::SIPostRABundlerID = SIPostRABundler::ID;
66
67FunctionPass *llvm::createSIPostRABundlerPass() {
68  return new SIPostRABundler();
69}
70
71bool SIPostRABundler::isDependentLoad(const MachineInstr &MI) const {
72  if (!MI.mayLoad())
73    return false;
74
75  for (const MachineOperand &Op : MI.explicit_operands()) {
76    if (!Op.isReg())
77      continue;
78    Register Reg = Op.getReg();
79    for (Register Def : Defs)
80      if (TRI->regsOverlap(Reg, Def))
81        return true;
82  }
83
84  return false;
85}
86
87bool SIPostRABundler::runOnMachineFunction(MachineFunction &MF) {
88  if (skipFunction(MF.getFunction()))
89    return false;
90
91  TRI = MF.getSubtarget<GCNSubtarget>().getRegisterInfo();
92  bool Changed = false;
93  const uint64_t MemFlags = SIInstrFlags::MTBUF | SIInstrFlags::MUBUF |
94                            SIInstrFlags::SMRD | SIInstrFlags::DS |
95                            SIInstrFlags::FLAT | SIInstrFlags::MIMG;
96
97  for (MachineBasicBlock &MBB : MF) {
98    MachineBasicBlock::instr_iterator Next;
99    MachineBasicBlock::instr_iterator B = MBB.instr_begin();
100    MachineBasicBlock::instr_iterator E = MBB.instr_end();
101    for (auto I = B; I != E; I = Next) {
102      Next = std::next(I);
103
104      const uint64_t IMemFlags = I->getDesc().TSFlags & MemFlags;
105
106      if (IMemFlags == 0 || I->isBundled() || !I->mayLoadOrStore() ||
107          B->mayLoad() != I->mayLoad() || B->mayStore() != I->mayStore() ||
108          ((B->getDesc().TSFlags & MemFlags) != IMemFlags) ||
109          isDependentLoad(*I)) {
110
111        if (B != I) {
112          if (std::next(B) != I) {
113            finalizeBundle(MBB, B, I);
114            Changed = true;
115          }
116          Next = I;
117        }
118
119        B = Next;
120        Defs.clear();
121        continue;
122      }
123
124      if (I->getNumExplicitDefs() == 0)
125        continue;
126
127      Defs.insert(I->defs().begin()->getReg());
128    }
129
130    if (B != E && std::next(B) != E) {
131      finalizeBundle(MBB, B, E);
132      Changed = true;
133    }
134
135    Defs.clear();
136  }
137
138  return Changed;
139}
140