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