1bdd1243dSDimitry Andric //===- MachineUniformityAnalysis.cpp --------------------------------------===//
2bdd1243dSDimitry Andric //
3bdd1243dSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4bdd1243dSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5bdd1243dSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6bdd1243dSDimitry Andric //
7bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
8bdd1243dSDimitry Andric 
9bdd1243dSDimitry Andric #include "llvm/CodeGen/MachineUniformityAnalysis.h"
10bdd1243dSDimitry Andric #include "llvm/ADT/GenericUniformityImpl.h"
11bdd1243dSDimitry Andric #include "llvm/CodeGen/MachineCycleAnalysis.h"
12bdd1243dSDimitry Andric #include "llvm/CodeGen/MachineDominators.h"
13bdd1243dSDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
14bdd1243dSDimitry Andric #include "llvm/CodeGen/MachineSSAContext.h"
15bdd1243dSDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h"
16bdd1243dSDimitry Andric #include "llvm/InitializePasses.h"
17bdd1243dSDimitry Andric 
18bdd1243dSDimitry Andric using namespace llvm;
19bdd1243dSDimitry Andric 
20bdd1243dSDimitry Andric template <>
hasDivergentDefs(const MachineInstr & I) const21bdd1243dSDimitry Andric bool llvm::GenericUniformityAnalysisImpl<MachineSSAContext>::hasDivergentDefs(
22bdd1243dSDimitry Andric     const MachineInstr &I) const {
23fe013be4SDimitry Andric   for (auto &op : I.all_defs()) {
24bdd1243dSDimitry Andric     if (isDivergent(op.getReg()))
25bdd1243dSDimitry Andric       return true;
26bdd1243dSDimitry Andric   }
27bdd1243dSDimitry Andric   return false;
28bdd1243dSDimitry Andric }
29bdd1243dSDimitry Andric 
30bdd1243dSDimitry Andric template <>
markDefsDivergent(const MachineInstr & Instr)31bdd1243dSDimitry Andric bool llvm::GenericUniformityAnalysisImpl<MachineSSAContext>::markDefsDivergent(
32fe013be4SDimitry Andric     const MachineInstr &Instr) {
33bdd1243dSDimitry Andric   bool insertedDivergent = false;
34bdd1243dSDimitry Andric   const auto &MRI = F.getRegInfo();
35fe013be4SDimitry Andric   const auto &RBI = *F.getSubtarget().getRegBankInfo();
36bdd1243dSDimitry Andric   const auto &TRI = *MRI.getTargetRegisterInfo();
37fe013be4SDimitry Andric   for (auto &op : Instr.all_defs()) {
38bdd1243dSDimitry Andric     if (!op.getReg().isVirtual())
39bdd1243dSDimitry Andric       continue;
40bdd1243dSDimitry Andric     assert(!op.getSubReg());
41fe013be4SDimitry Andric     if (TRI.isUniformReg(MRI, RBI, op.getReg()))
42bdd1243dSDimitry Andric       continue;
43bdd1243dSDimitry Andric     insertedDivergent |= markDivergent(op.getReg());
44bdd1243dSDimitry Andric   }
45bdd1243dSDimitry Andric   return insertedDivergent;
46bdd1243dSDimitry Andric }
47bdd1243dSDimitry Andric 
48bdd1243dSDimitry Andric template <>
initialize()49bdd1243dSDimitry Andric void llvm::GenericUniformityAnalysisImpl<MachineSSAContext>::initialize() {
50bdd1243dSDimitry Andric   const auto &InstrInfo = *F.getSubtarget().getInstrInfo();
51bdd1243dSDimitry Andric 
52bdd1243dSDimitry Andric   for (const MachineBasicBlock &block : F) {
53bdd1243dSDimitry Andric     for (const MachineInstr &instr : block) {
54bdd1243dSDimitry Andric       auto uniformity = InstrInfo.getInstructionUniformity(instr);
55bdd1243dSDimitry Andric       if (uniformity == InstructionUniformity::AlwaysUniform) {
56bdd1243dSDimitry Andric         addUniformOverride(instr);
57bdd1243dSDimitry Andric         continue;
58bdd1243dSDimitry Andric       }
59bdd1243dSDimitry Andric 
60bdd1243dSDimitry Andric       if (uniformity == InstructionUniformity::NeverUniform) {
61fe013be4SDimitry Andric         markDivergent(instr);
62bdd1243dSDimitry Andric       }
63bdd1243dSDimitry Andric     }
64bdd1243dSDimitry Andric   }
65bdd1243dSDimitry Andric }
66bdd1243dSDimitry Andric 
67bdd1243dSDimitry Andric template <>
pushUsers(Register Reg)68bdd1243dSDimitry Andric void llvm::GenericUniformityAnalysisImpl<MachineSSAContext>::pushUsers(
69bdd1243dSDimitry Andric     Register Reg) {
70fe013be4SDimitry Andric   assert(isDivergent(Reg));
71bdd1243dSDimitry Andric   const auto &RegInfo = F.getRegInfo();
72bdd1243dSDimitry Andric   for (MachineInstr &UserInstr : RegInfo.use_instructions(Reg)) {
73fe013be4SDimitry Andric     markDivergent(UserInstr);
74bdd1243dSDimitry Andric   }
75bdd1243dSDimitry Andric }
76bdd1243dSDimitry Andric 
77bdd1243dSDimitry Andric template <>
pushUsers(const MachineInstr & Instr)78bdd1243dSDimitry Andric void llvm::GenericUniformityAnalysisImpl<MachineSSAContext>::pushUsers(
79bdd1243dSDimitry Andric     const MachineInstr &Instr) {
80bdd1243dSDimitry Andric   assert(!isAlwaysUniform(Instr));
81bdd1243dSDimitry Andric   if (Instr.isTerminator())
82bdd1243dSDimitry Andric     return;
83fe013be4SDimitry Andric   for (const MachineOperand &op : Instr.all_defs()) {
84fe013be4SDimitry Andric     auto Reg = op.getReg();
85fe013be4SDimitry Andric     if (isDivergent(Reg))
86fe013be4SDimitry Andric       pushUsers(Reg);
87bdd1243dSDimitry Andric   }
88bdd1243dSDimitry Andric }
89bdd1243dSDimitry Andric 
90bdd1243dSDimitry Andric template <>
usesValueFromCycle(const MachineInstr & I,const MachineCycle & DefCycle) const91bdd1243dSDimitry Andric bool llvm::GenericUniformityAnalysisImpl<MachineSSAContext>::usesValueFromCycle(
92bdd1243dSDimitry Andric     const MachineInstr &I, const MachineCycle &DefCycle) const {
93bdd1243dSDimitry Andric   assert(!isAlwaysUniform(I));
94bdd1243dSDimitry Andric   for (auto &Op : I.operands()) {
95bdd1243dSDimitry Andric     if (!Op.isReg() || !Op.readsReg())
96bdd1243dSDimitry Andric       continue;
97bdd1243dSDimitry Andric     auto Reg = Op.getReg();
98fe013be4SDimitry Andric 
99fe013be4SDimitry Andric     // FIXME: Physical registers need to be properly checked instead of always
100fe013be4SDimitry Andric     // returning true
101fe013be4SDimitry Andric     if (Reg.isPhysical())
102fe013be4SDimitry Andric       return true;
103fe013be4SDimitry Andric 
104bdd1243dSDimitry Andric     auto *Def = F.getRegInfo().getVRegDef(Reg);
105bdd1243dSDimitry Andric     if (DefCycle.contains(Def->getParent()))
106bdd1243dSDimitry Andric       return true;
107bdd1243dSDimitry Andric   }
108bdd1243dSDimitry Andric   return false;
109bdd1243dSDimitry Andric }
110bdd1243dSDimitry Andric 
111fe013be4SDimitry Andric template <>
112fe013be4SDimitry Andric void llvm::GenericUniformityAnalysisImpl<MachineSSAContext>::
propagateTemporalDivergence(const MachineInstr & I,const MachineCycle & DefCycle)113fe013be4SDimitry Andric     propagateTemporalDivergence(const MachineInstr &I,
114fe013be4SDimitry Andric                                 const MachineCycle &DefCycle) {
115fe013be4SDimitry Andric   const auto &RegInfo = F.getRegInfo();
116fe013be4SDimitry Andric   for (auto &Op : I.all_defs()) {
117fe013be4SDimitry Andric     if (!Op.getReg().isVirtual())
118fe013be4SDimitry Andric       continue;
119fe013be4SDimitry Andric     auto Reg = Op.getReg();
120fe013be4SDimitry Andric     if (isDivergent(Reg))
121fe013be4SDimitry Andric       continue;
122fe013be4SDimitry Andric     for (MachineInstr &UserInstr : RegInfo.use_instructions(Reg)) {
123fe013be4SDimitry Andric       if (DefCycle.contains(UserInstr.getParent()))
124fe013be4SDimitry Andric         continue;
125fe013be4SDimitry Andric       markDivergent(UserInstr);
126fe013be4SDimitry Andric     }
127fe013be4SDimitry Andric   }
128fe013be4SDimitry Andric }
129fe013be4SDimitry Andric 
130fe013be4SDimitry Andric template <>
isDivergentUse(const MachineOperand & U) const131fe013be4SDimitry Andric bool llvm::GenericUniformityAnalysisImpl<MachineSSAContext>::isDivergentUse(
132fe013be4SDimitry Andric     const MachineOperand &U) const {
133fe013be4SDimitry Andric   if (!U.isReg())
134fe013be4SDimitry Andric     return false;
135fe013be4SDimitry Andric 
136fe013be4SDimitry Andric   auto Reg = U.getReg();
137fe013be4SDimitry Andric   if (isDivergent(Reg))
138fe013be4SDimitry Andric     return true;
139fe013be4SDimitry Andric 
140fe013be4SDimitry Andric   const auto &RegInfo = F.getRegInfo();
141fe013be4SDimitry Andric   auto *Def = RegInfo.getOneDef(Reg);
142fe013be4SDimitry Andric   if (!Def)
143fe013be4SDimitry Andric     return true;
144fe013be4SDimitry Andric 
145fe013be4SDimitry Andric   auto *DefInstr = Def->getParent();
146fe013be4SDimitry Andric   auto *UseInstr = U.getParent();
147fe013be4SDimitry Andric   return isTemporalDivergent(*UseInstr->getParent(), *DefInstr);
148fe013be4SDimitry Andric }
149fe013be4SDimitry Andric 
150bdd1243dSDimitry Andric // This ensures explicit instantiation of
151bdd1243dSDimitry Andric // GenericUniformityAnalysisImpl::ImplDeleter::operator()
152bdd1243dSDimitry Andric template class llvm::GenericUniformityInfo<MachineSSAContext>;
153bdd1243dSDimitry Andric template struct llvm::GenericUniformityAnalysisImplDeleter<
154bdd1243dSDimitry Andric     llvm::GenericUniformityAnalysisImpl<MachineSSAContext>>;
155bdd1243dSDimitry Andric 
computeMachineUniformityInfo(MachineFunction & F,const MachineCycleInfo & cycleInfo,const MachineDomTree & domTree,bool HasBranchDivergence)156fe013be4SDimitry Andric MachineUniformityInfo llvm::computeMachineUniformityInfo(
157fe013be4SDimitry Andric     MachineFunction &F, const MachineCycleInfo &cycleInfo,
158fe013be4SDimitry Andric     const MachineDomTree &domTree, bool HasBranchDivergence) {
159bdd1243dSDimitry Andric   assert(F.getRegInfo().isSSA() && "Expected to be run on SSA form!");
160*c9157d92SDimitry Andric   MachineUniformityInfo UI(domTree, cycleInfo);
161fe013be4SDimitry Andric   if (HasBranchDivergence)
162fe013be4SDimitry Andric     UI.compute();
163fe013be4SDimitry Andric   return UI;
164bdd1243dSDimitry Andric }
165bdd1243dSDimitry Andric 
166bdd1243dSDimitry Andric namespace {
167bdd1243dSDimitry Andric 
168bdd1243dSDimitry Andric /// Legacy analysis pass which computes a \ref MachineUniformityInfo.
169bdd1243dSDimitry Andric class MachineUniformityAnalysisPass : public MachineFunctionPass {
170bdd1243dSDimitry Andric   MachineUniformityInfo UI;
171bdd1243dSDimitry Andric 
172bdd1243dSDimitry Andric public:
173bdd1243dSDimitry Andric   static char ID;
174bdd1243dSDimitry Andric 
175bdd1243dSDimitry Andric   MachineUniformityAnalysisPass();
176bdd1243dSDimitry Andric 
getUniformityInfo()177bdd1243dSDimitry Andric   MachineUniformityInfo &getUniformityInfo() { return UI; }
getUniformityInfo() const178bdd1243dSDimitry Andric   const MachineUniformityInfo &getUniformityInfo() const { return UI; }
179bdd1243dSDimitry Andric 
180bdd1243dSDimitry Andric   bool runOnMachineFunction(MachineFunction &F) override;
181bdd1243dSDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override;
182bdd1243dSDimitry Andric   void print(raw_ostream &OS, const Module *M = nullptr) const override;
183bdd1243dSDimitry Andric 
184bdd1243dSDimitry Andric   // TODO: verify analysis
185bdd1243dSDimitry Andric };
186bdd1243dSDimitry Andric 
187bdd1243dSDimitry Andric class MachineUniformityInfoPrinterPass : public MachineFunctionPass {
188bdd1243dSDimitry Andric public:
189bdd1243dSDimitry Andric   static char ID;
190bdd1243dSDimitry Andric 
191bdd1243dSDimitry Andric   MachineUniformityInfoPrinterPass();
192bdd1243dSDimitry Andric 
193bdd1243dSDimitry Andric   bool runOnMachineFunction(MachineFunction &F) override;
194bdd1243dSDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override;
195bdd1243dSDimitry Andric };
196bdd1243dSDimitry Andric 
197bdd1243dSDimitry Andric } // namespace
198bdd1243dSDimitry Andric 
199bdd1243dSDimitry Andric char MachineUniformityAnalysisPass::ID = 0;
200bdd1243dSDimitry Andric 
MachineUniformityAnalysisPass()201bdd1243dSDimitry Andric MachineUniformityAnalysisPass::MachineUniformityAnalysisPass()
202bdd1243dSDimitry Andric     : MachineFunctionPass(ID) {
203bdd1243dSDimitry Andric   initializeMachineUniformityAnalysisPassPass(*PassRegistry::getPassRegistry());
204bdd1243dSDimitry Andric }
205bdd1243dSDimitry Andric 
206bdd1243dSDimitry Andric INITIALIZE_PASS_BEGIN(MachineUniformityAnalysisPass, "machine-uniformity",
207bdd1243dSDimitry Andric                       "Machine Uniformity Info Analysis", true, true)
INITIALIZE_PASS_DEPENDENCY(MachineCycleInfoWrapperPass)208bdd1243dSDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineCycleInfoWrapperPass)
209bdd1243dSDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)
210bdd1243dSDimitry Andric INITIALIZE_PASS_END(MachineUniformityAnalysisPass, "machine-uniformity",
211bdd1243dSDimitry Andric                     "Machine Uniformity Info Analysis", true, true)
212bdd1243dSDimitry Andric 
213bdd1243dSDimitry Andric void MachineUniformityAnalysisPass::getAnalysisUsage(AnalysisUsage &AU) const {
214bdd1243dSDimitry Andric   AU.setPreservesAll();
215bdd1243dSDimitry Andric   AU.addRequired<MachineCycleInfoWrapperPass>();
216bdd1243dSDimitry Andric   AU.addRequired<MachineDominatorTree>();
217bdd1243dSDimitry Andric   MachineFunctionPass::getAnalysisUsage(AU);
218bdd1243dSDimitry Andric }
219bdd1243dSDimitry Andric 
runOnMachineFunction(MachineFunction & MF)220bdd1243dSDimitry Andric bool MachineUniformityAnalysisPass::runOnMachineFunction(MachineFunction &MF) {
221bdd1243dSDimitry Andric   auto &DomTree = getAnalysis<MachineDominatorTree>().getBase();
222bdd1243dSDimitry Andric   auto &CI = getAnalysis<MachineCycleInfoWrapperPass>().getCycleInfo();
223fe013be4SDimitry Andric   // FIXME: Query TTI::hasBranchDivergence. -run-pass seems to end up with a
224fe013be4SDimitry Andric   // default NoTTI
225fe013be4SDimitry Andric   UI = computeMachineUniformityInfo(MF, CI, DomTree, true);
226bdd1243dSDimitry Andric   return false;
227bdd1243dSDimitry Andric }
228bdd1243dSDimitry Andric 
print(raw_ostream & OS,const Module *) const229bdd1243dSDimitry Andric void MachineUniformityAnalysisPass::print(raw_ostream &OS,
230bdd1243dSDimitry Andric                                           const Module *) const {
231bdd1243dSDimitry Andric   OS << "MachineUniformityInfo for function: " << UI.getFunction().getName()
232bdd1243dSDimitry Andric      << "\n";
233bdd1243dSDimitry Andric   UI.print(OS);
234bdd1243dSDimitry Andric }
235bdd1243dSDimitry Andric 
236bdd1243dSDimitry Andric char MachineUniformityInfoPrinterPass::ID = 0;
237bdd1243dSDimitry Andric 
MachineUniformityInfoPrinterPass()238bdd1243dSDimitry Andric MachineUniformityInfoPrinterPass::MachineUniformityInfoPrinterPass()
239bdd1243dSDimitry Andric     : MachineFunctionPass(ID) {
240bdd1243dSDimitry Andric   initializeMachineUniformityInfoPrinterPassPass(
241bdd1243dSDimitry Andric       *PassRegistry::getPassRegistry());
242bdd1243dSDimitry Andric }
243bdd1243dSDimitry Andric 
244bdd1243dSDimitry Andric INITIALIZE_PASS_BEGIN(MachineUniformityInfoPrinterPass,
245bdd1243dSDimitry Andric                       "print-machine-uniformity",
246bdd1243dSDimitry Andric                       "Print Machine Uniformity Info Analysis", true, true)
INITIALIZE_PASS_DEPENDENCY(MachineUniformityAnalysisPass)247bdd1243dSDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineUniformityAnalysisPass)
248bdd1243dSDimitry Andric INITIALIZE_PASS_END(MachineUniformityInfoPrinterPass,
249bdd1243dSDimitry Andric                     "print-machine-uniformity",
250bdd1243dSDimitry Andric                     "Print Machine Uniformity Info Analysis", true, true)
251bdd1243dSDimitry Andric 
252bdd1243dSDimitry Andric void MachineUniformityInfoPrinterPass::getAnalysisUsage(
253bdd1243dSDimitry Andric     AnalysisUsage &AU) const {
254bdd1243dSDimitry Andric   AU.setPreservesAll();
255bdd1243dSDimitry Andric   AU.addRequired<MachineUniformityAnalysisPass>();
256bdd1243dSDimitry Andric   MachineFunctionPass::getAnalysisUsage(AU);
257bdd1243dSDimitry Andric }
258bdd1243dSDimitry Andric 
runOnMachineFunction(MachineFunction & F)259bdd1243dSDimitry Andric bool MachineUniformityInfoPrinterPass::runOnMachineFunction(
260bdd1243dSDimitry Andric     MachineFunction &F) {
261bdd1243dSDimitry Andric   auto &UI = getAnalysis<MachineUniformityAnalysisPass>();
262bdd1243dSDimitry Andric   UI.print(errs());
263bdd1243dSDimitry Andric   return false;
264bdd1243dSDimitry Andric }
265