xref: /src/contrib/llvm-project/llvm/lib/CodeGen/MachineUniformityAnalysis.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1e3b55780SDimitry Andric //===- MachineUniformityAnalysis.cpp --------------------------------------===//
2e3b55780SDimitry Andric //
3e3b55780SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e3b55780SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e3b55780SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e3b55780SDimitry Andric //
7e3b55780SDimitry Andric //===----------------------------------------------------------------------===//
8e3b55780SDimitry Andric 
9e3b55780SDimitry Andric #include "llvm/CodeGen/MachineUniformityAnalysis.h"
10e3b55780SDimitry Andric #include "llvm/ADT/GenericUniformityImpl.h"
11e3b55780SDimitry Andric #include "llvm/CodeGen/MachineCycleAnalysis.h"
12e3b55780SDimitry Andric #include "llvm/CodeGen/MachineDominators.h"
13e3b55780SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
14e3b55780SDimitry Andric #include "llvm/CodeGen/MachineSSAContext.h"
15e3b55780SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h"
16e3b55780SDimitry Andric #include "llvm/InitializePasses.h"
17e3b55780SDimitry Andric 
18e3b55780SDimitry Andric using namespace llvm;
19e3b55780SDimitry Andric 
20e3b55780SDimitry Andric template <>
hasDivergentDefs(const MachineInstr & I) const21e3b55780SDimitry Andric bool llvm::GenericUniformityAnalysisImpl<MachineSSAContext>::hasDivergentDefs(
22e3b55780SDimitry Andric     const MachineInstr &I) const {
237fa27ce4SDimitry Andric   for (auto &op : I.all_defs()) {
24e3b55780SDimitry Andric     if (isDivergent(op.getReg()))
25e3b55780SDimitry Andric       return true;
26e3b55780SDimitry Andric   }
27e3b55780SDimitry Andric   return false;
28e3b55780SDimitry Andric }
29e3b55780SDimitry Andric 
30e3b55780SDimitry Andric template <>
markDefsDivergent(const MachineInstr & Instr)31e3b55780SDimitry Andric bool llvm::GenericUniformityAnalysisImpl<MachineSSAContext>::markDefsDivergent(
327fa27ce4SDimitry Andric     const MachineInstr &Instr) {
33e3b55780SDimitry Andric   bool insertedDivergent = false;
34e3b55780SDimitry Andric   const auto &MRI = F.getRegInfo();
357fa27ce4SDimitry Andric   const auto &RBI = *F.getSubtarget().getRegBankInfo();
36e3b55780SDimitry Andric   const auto &TRI = *MRI.getTargetRegisterInfo();
377fa27ce4SDimitry Andric   for (auto &op : Instr.all_defs()) {
38e3b55780SDimitry Andric     if (!op.getReg().isVirtual())
39e3b55780SDimitry Andric       continue;
40e3b55780SDimitry Andric     assert(!op.getSubReg());
417fa27ce4SDimitry Andric     if (TRI.isUniformReg(MRI, RBI, op.getReg()))
42e3b55780SDimitry Andric       continue;
43e3b55780SDimitry Andric     insertedDivergent |= markDivergent(op.getReg());
44e3b55780SDimitry Andric   }
45e3b55780SDimitry Andric   return insertedDivergent;
46e3b55780SDimitry Andric }
47e3b55780SDimitry Andric 
48e3b55780SDimitry Andric template <>
initialize()49e3b55780SDimitry Andric void llvm::GenericUniformityAnalysisImpl<MachineSSAContext>::initialize() {
50e3b55780SDimitry Andric   const auto &InstrInfo = *F.getSubtarget().getInstrInfo();
51e3b55780SDimitry Andric 
52e3b55780SDimitry Andric   for (const MachineBasicBlock &block : F) {
53e3b55780SDimitry Andric     for (const MachineInstr &instr : block) {
54e3b55780SDimitry Andric       auto uniformity = InstrInfo.getInstructionUniformity(instr);
55e3b55780SDimitry Andric       if (uniformity == InstructionUniformity::AlwaysUniform) {
56e3b55780SDimitry Andric         addUniformOverride(instr);
57e3b55780SDimitry Andric         continue;
58e3b55780SDimitry Andric       }
59e3b55780SDimitry Andric 
60e3b55780SDimitry Andric       if (uniformity == InstructionUniformity::NeverUniform) {
617fa27ce4SDimitry Andric         markDivergent(instr);
62e3b55780SDimitry Andric       }
63e3b55780SDimitry Andric     }
64e3b55780SDimitry Andric   }
65e3b55780SDimitry Andric }
66e3b55780SDimitry Andric 
67e3b55780SDimitry Andric template <>
pushUsers(Register Reg)68e3b55780SDimitry Andric void llvm::GenericUniformityAnalysisImpl<MachineSSAContext>::pushUsers(
69e3b55780SDimitry Andric     Register Reg) {
707fa27ce4SDimitry Andric   assert(isDivergent(Reg));
71e3b55780SDimitry Andric   const auto &RegInfo = F.getRegInfo();
72e3b55780SDimitry Andric   for (MachineInstr &UserInstr : RegInfo.use_instructions(Reg)) {
737fa27ce4SDimitry Andric     markDivergent(UserInstr);
74e3b55780SDimitry Andric   }
75e3b55780SDimitry Andric }
76e3b55780SDimitry Andric 
77e3b55780SDimitry Andric template <>
pushUsers(const MachineInstr & Instr)78e3b55780SDimitry Andric void llvm::GenericUniformityAnalysisImpl<MachineSSAContext>::pushUsers(
79e3b55780SDimitry Andric     const MachineInstr &Instr) {
80e3b55780SDimitry Andric   assert(!isAlwaysUniform(Instr));
81e3b55780SDimitry Andric   if (Instr.isTerminator())
82e3b55780SDimitry Andric     return;
837fa27ce4SDimitry Andric   for (const MachineOperand &op : Instr.all_defs()) {
847fa27ce4SDimitry Andric     auto Reg = op.getReg();
857fa27ce4SDimitry Andric     if (isDivergent(Reg))
867fa27ce4SDimitry Andric       pushUsers(Reg);
87e3b55780SDimitry Andric   }
88e3b55780SDimitry Andric }
89e3b55780SDimitry Andric 
90e3b55780SDimitry Andric template <>
usesValueFromCycle(const MachineInstr & I,const MachineCycle & DefCycle) const91e3b55780SDimitry Andric bool llvm::GenericUniformityAnalysisImpl<MachineSSAContext>::usesValueFromCycle(
92e3b55780SDimitry Andric     const MachineInstr &I, const MachineCycle &DefCycle) const {
93e3b55780SDimitry Andric   assert(!isAlwaysUniform(I));
94e3b55780SDimitry Andric   for (auto &Op : I.operands()) {
95e3b55780SDimitry Andric     if (!Op.isReg() || !Op.readsReg())
96e3b55780SDimitry Andric       continue;
97e3b55780SDimitry Andric     auto Reg = Op.getReg();
987fa27ce4SDimitry Andric 
997fa27ce4SDimitry Andric     // FIXME: Physical registers need to be properly checked instead of always
1007fa27ce4SDimitry Andric     // returning true
1017fa27ce4SDimitry Andric     if (Reg.isPhysical())
1027fa27ce4SDimitry Andric       return true;
1037fa27ce4SDimitry Andric 
104e3b55780SDimitry Andric     auto *Def = F.getRegInfo().getVRegDef(Reg);
105e3b55780SDimitry Andric     if (DefCycle.contains(Def->getParent()))
106e3b55780SDimitry Andric       return true;
107e3b55780SDimitry Andric   }
108e3b55780SDimitry Andric   return false;
109e3b55780SDimitry Andric }
110e3b55780SDimitry Andric 
1117fa27ce4SDimitry Andric template <>
1127fa27ce4SDimitry Andric void llvm::GenericUniformityAnalysisImpl<MachineSSAContext>::
propagateTemporalDivergence(const MachineInstr & I,const MachineCycle & DefCycle)1137fa27ce4SDimitry Andric     propagateTemporalDivergence(const MachineInstr &I,
1147fa27ce4SDimitry Andric                                 const MachineCycle &DefCycle) {
1157fa27ce4SDimitry Andric   const auto &RegInfo = F.getRegInfo();
1167fa27ce4SDimitry Andric   for (auto &Op : I.all_defs()) {
1177fa27ce4SDimitry Andric     if (!Op.getReg().isVirtual())
1187fa27ce4SDimitry Andric       continue;
1197fa27ce4SDimitry Andric     auto Reg = Op.getReg();
1207fa27ce4SDimitry Andric     if (isDivergent(Reg))
1217fa27ce4SDimitry Andric       continue;
1227fa27ce4SDimitry Andric     for (MachineInstr &UserInstr : RegInfo.use_instructions(Reg)) {
1237fa27ce4SDimitry Andric       if (DefCycle.contains(UserInstr.getParent()))
1247fa27ce4SDimitry Andric         continue;
1257fa27ce4SDimitry Andric       markDivergent(UserInstr);
1267fa27ce4SDimitry Andric     }
1277fa27ce4SDimitry Andric   }
1287fa27ce4SDimitry Andric }
1297fa27ce4SDimitry Andric 
1307fa27ce4SDimitry Andric template <>
isDivergentUse(const MachineOperand & U) const1317fa27ce4SDimitry Andric bool llvm::GenericUniformityAnalysisImpl<MachineSSAContext>::isDivergentUse(
1327fa27ce4SDimitry Andric     const MachineOperand &U) const {
1337fa27ce4SDimitry Andric   if (!U.isReg())
1347fa27ce4SDimitry Andric     return false;
1357fa27ce4SDimitry Andric 
1367fa27ce4SDimitry Andric   auto Reg = U.getReg();
1377fa27ce4SDimitry Andric   if (isDivergent(Reg))
1387fa27ce4SDimitry Andric     return true;
1397fa27ce4SDimitry Andric 
1407fa27ce4SDimitry Andric   const auto &RegInfo = F.getRegInfo();
1417fa27ce4SDimitry Andric   auto *Def = RegInfo.getOneDef(Reg);
1427fa27ce4SDimitry Andric   if (!Def)
1437fa27ce4SDimitry Andric     return true;
1447fa27ce4SDimitry Andric 
1457fa27ce4SDimitry Andric   auto *DefInstr = Def->getParent();
1467fa27ce4SDimitry Andric   auto *UseInstr = U.getParent();
1477fa27ce4SDimitry Andric   return isTemporalDivergent(*UseInstr->getParent(), *DefInstr);
1487fa27ce4SDimitry Andric }
1497fa27ce4SDimitry Andric 
150e3b55780SDimitry Andric // This ensures explicit instantiation of
151e3b55780SDimitry Andric // GenericUniformityAnalysisImpl::ImplDeleter::operator()
152e3b55780SDimitry Andric template class llvm::GenericUniformityInfo<MachineSSAContext>;
153e3b55780SDimitry Andric template struct llvm::GenericUniformityAnalysisImplDeleter<
154e3b55780SDimitry Andric     llvm::GenericUniformityAnalysisImpl<MachineSSAContext>>;
155e3b55780SDimitry Andric 
computeMachineUniformityInfo(MachineFunction & F,const MachineCycleInfo & cycleInfo,const MachineDominatorTree & domTree,bool HasBranchDivergence)1567fa27ce4SDimitry Andric MachineUniformityInfo llvm::computeMachineUniformityInfo(
1577fa27ce4SDimitry Andric     MachineFunction &F, const MachineCycleInfo &cycleInfo,
158ac9a064cSDimitry Andric     const MachineDominatorTree &domTree, bool HasBranchDivergence) {
159e3b55780SDimitry Andric   assert(F.getRegInfo().isSSA() && "Expected to be run on SSA form!");
160b1c73532SDimitry Andric   MachineUniformityInfo UI(domTree, cycleInfo);
1617fa27ce4SDimitry Andric   if (HasBranchDivergence)
1627fa27ce4SDimitry Andric     UI.compute();
1637fa27ce4SDimitry Andric   return UI;
164e3b55780SDimitry Andric }
165e3b55780SDimitry Andric 
166e3b55780SDimitry Andric namespace {
167e3b55780SDimitry Andric 
168e3b55780SDimitry Andric class MachineUniformityInfoPrinterPass : public MachineFunctionPass {
169e3b55780SDimitry Andric public:
170e3b55780SDimitry Andric   static char ID;
171e3b55780SDimitry Andric 
172e3b55780SDimitry Andric   MachineUniformityInfoPrinterPass();
173e3b55780SDimitry Andric 
174e3b55780SDimitry Andric   bool runOnMachineFunction(MachineFunction &F) override;
175e3b55780SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override;
176e3b55780SDimitry Andric };
177e3b55780SDimitry Andric 
178e3b55780SDimitry Andric } // namespace
179e3b55780SDimitry Andric 
180e3b55780SDimitry Andric char MachineUniformityAnalysisPass::ID = 0;
181e3b55780SDimitry Andric 
MachineUniformityAnalysisPass()182e3b55780SDimitry Andric MachineUniformityAnalysisPass::MachineUniformityAnalysisPass()
183e3b55780SDimitry Andric     : MachineFunctionPass(ID) {
184e3b55780SDimitry Andric   initializeMachineUniformityAnalysisPassPass(*PassRegistry::getPassRegistry());
185e3b55780SDimitry Andric }
186e3b55780SDimitry Andric 
187e3b55780SDimitry Andric INITIALIZE_PASS_BEGIN(MachineUniformityAnalysisPass, "machine-uniformity",
188e3b55780SDimitry Andric                       "Machine Uniformity Info Analysis", true, true)
INITIALIZE_PASS_DEPENDENCY(MachineCycleInfoWrapperPass)189e3b55780SDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineCycleInfoWrapperPass)
190ac9a064cSDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass)
191e3b55780SDimitry Andric INITIALIZE_PASS_END(MachineUniformityAnalysisPass, "machine-uniformity",
192e3b55780SDimitry Andric                     "Machine Uniformity Info Analysis", true, true)
193e3b55780SDimitry Andric 
194e3b55780SDimitry Andric void MachineUniformityAnalysisPass::getAnalysisUsage(AnalysisUsage &AU) const {
195e3b55780SDimitry Andric   AU.setPreservesAll();
196e3b55780SDimitry Andric   AU.addRequired<MachineCycleInfoWrapperPass>();
197ac9a064cSDimitry Andric   AU.addRequired<MachineDominatorTreeWrapperPass>();
198e3b55780SDimitry Andric   MachineFunctionPass::getAnalysisUsage(AU);
199e3b55780SDimitry Andric }
200e3b55780SDimitry Andric 
runOnMachineFunction(MachineFunction & MF)201e3b55780SDimitry Andric bool MachineUniformityAnalysisPass::runOnMachineFunction(MachineFunction &MF) {
202ac9a064cSDimitry Andric   auto &DomTree =
203ac9a064cSDimitry Andric       getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree().getBase();
204e3b55780SDimitry Andric   auto &CI = getAnalysis<MachineCycleInfoWrapperPass>().getCycleInfo();
2057fa27ce4SDimitry Andric   // FIXME: Query TTI::hasBranchDivergence. -run-pass seems to end up with a
2067fa27ce4SDimitry Andric   // default NoTTI
2077fa27ce4SDimitry Andric   UI = computeMachineUniformityInfo(MF, CI, DomTree, true);
208e3b55780SDimitry Andric   return false;
209e3b55780SDimitry Andric }
210e3b55780SDimitry Andric 
print(raw_ostream & OS,const Module *) const211e3b55780SDimitry Andric void MachineUniformityAnalysisPass::print(raw_ostream &OS,
212e3b55780SDimitry Andric                                           const Module *) const {
213e3b55780SDimitry Andric   OS << "MachineUniformityInfo for function: " << UI.getFunction().getName()
214e3b55780SDimitry Andric      << "\n";
215e3b55780SDimitry Andric   UI.print(OS);
216e3b55780SDimitry Andric }
217e3b55780SDimitry Andric 
218e3b55780SDimitry Andric char MachineUniformityInfoPrinterPass::ID = 0;
219e3b55780SDimitry Andric 
MachineUniformityInfoPrinterPass()220e3b55780SDimitry Andric MachineUniformityInfoPrinterPass::MachineUniformityInfoPrinterPass()
221e3b55780SDimitry Andric     : MachineFunctionPass(ID) {
222e3b55780SDimitry Andric   initializeMachineUniformityInfoPrinterPassPass(
223e3b55780SDimitry Andric       *PassRegistry::getPassRegistry());
224e3b55780SDimitry Andric }
225e3b55780SDimitry Andric 
226e3b55780SDimitry Andric INITIALIZE_PASS_BEGIN(MachineUniformityInfoPrinterPass,
227e3b55780SDimitry Andric                       "print-machine-uniformity",
228e3b55780SDimitry Andric                       "Print Machine Uniformity Info Analysis", true, true)
INITIALIZE_PASS_DEPENDENCY(MachineUniformityAnalysisPass)229e3b55780SDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineUniformityAnalysisPass)
230e3b55780SDimitry Andric INITIALIZE_PASS_END(MachineUniformityInfoPrinterPass,
231e3b55780SDimitry Andric                     "print-machine-uniformity",
232e3b55780SDimitry Andric                     "Print Machine Uniformity Info Analysis", true, true)
233e3b55780SDimitry Andric 
234e3b55780SDimitry Andric void MachineUniformityInfoPrinterPass::getAnalysisUsage(
235e3b55780SDimitry Andric     AnalysisUsage &AU) const {
236e3b55780SDimitry Andric   AU.setPreservesAll();
237e3b55780SDimitry Andric   AU.addRequired<MachineUniformityAnalysisPass>();
238e3b55780SDimitry Andric   MachineFunctionPass::getAnalysisUsage(AU);
239e3b55780SDimitry Andric }
240e3b55780SDimitry Andric 
runOnMachineFunction(MachineFunction & F)241e3b55780SDimitry Andric bool MachineUniformityInfoPrinterPass::runOnMachineFunction(
242e3b55780SDimitry Andric     MachineFunction &F) {
243e3b55780SDimitry Andric   auto &UI = getAnalysis<MachineUniformityAnalysisPass>();
244e3b55780SDimitry Andric   UI.print(errs());
245e3b55780SDimitry Andric   return false;
246e3b55780SDimitry Andric }
247