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 <> 21bdd1243dSDimitry Andric bool llvm::GenericUniformityAnalysisImpl<MachineSSAContext>::hasDivergentDefs( 22bdd1243dSDimitry Andric const MachineInstr &I) const { 2306c3fb27SDimitry 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 <> 31bdd1243dSDimitry Andric bool llvm::GenericUniformityAnalysisImpl<MachineSSAContext>::markDefsDivergent( 3206c3fb27SDimitry Andric const MachineInstr &Instr) { 33bdd1243dSDimitry Andric bool insertedDivergent = false; 34bdd1243dSDimitry Andric const auto &MRI = F.getRegInfo(); 3506c3fb27SDimitry Andric const auto &RBI = *F.getSubtarget().getRegBankInfo(); 36bdd1243dSDimitry Andric const auto &TRI = *MRI.getTargetRegisterInfo(); 3706c3fb27SDimitry Andric for (auto &op : Instr.all_defs()) { 38bdd1243dSDimitry Andric if (!op.getReg().isVirtual()) 39bdd1243dSDimitry Andric continue; 40bdd1243dSDimitry Andric assert(!op.getSubReg()); 4106c3fb27SDimitry 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 <> 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) { 6106c3fb27SDimitry Andric markDivergent(instr); 62bdd1243dSDimitry Andric } 63bdd1243dSDimitry Andric } 64bdd1243dSDimitry Andric } 65bdd1243dSDimitry Andric } 66bdd1243dSDimitry Andric 67bdd1243dSDimitry Andric template <> 68bdd1243dSDimitry Andric void llvm::GenericUniformityAnalysisImpl<MachineSSAContext>::pushUsers( 69bdd1243dSDimitry Andric Register Reg) { 7006c3fb27SDimitry Andric assert(isDivergent(Reg)); 71bdd1243dSDimitry Andric const auto &RegInfo = F.getRegInfo(); 72bdd1243dSDimitry Andric for (MachineInstr &UserInstr : RegInfo.use_instructions(Reg)) { 7306c3fb27SDimitry Andric markDivergent(UserInstr); 74bdd1243dSDimitry Andric } 75bdd1243dSDimitry Andric } 76bdd1243dSDimitry Andric 77bdd1243dSDimitry Andric template <> 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; 8306c3fb27SDimitry Andric for (const MachineOperand &op : Instr.all_defs()) { 8406c3fb27SDimitry Andric auto Reg = op.getReg(); 8506c3fb27SDimitry Andric if (isDivergent(Reg)) 8606c3fb27SDimitry Andric pushUsers(Reg); 87bdd1243dSDimitry Andric } 88bdd1243dSDimitry Andric } 89bdd1243dSDimitry Andric 90bdd1243dSDimitry Andric template <> 91bdd1243dSDimitry 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(); 9806c3fb27SDimitry Andric 9906c3fb27SDimitry Andric // FIXME: Physical registers need to be properly checked instead of always 10006c3fb27SDimitry Andric // returning true 10106c3fb27SDimitry Andric if (Reg.isPhysical()) 10206c3fb27SDimitry Andric return true; 10306c3fb27SDimitry 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 11106c3fb27SDimitry Andric template <> 11206c3fb27SDimitry Andric void llvm::GenericUniformityAnalysisImpl<MachineSSAContext>:: 11306c3fb27SDimitry Andric propagateTemporalDivergence(const MachineInstr &I, 11406c3fb27SDimitry Andric const MachineCycle &DefCycle) { 11506c3fb27SDimitry Andric const auto &RegInfo = F.getRegInfo(); 11606c3fb27SDimitry Andric for (auto &Op : I.all_defs()) { 11706c3fb27SDimitry Andric if (!Op.getReg().isVirtual()) 11806c3fb27SDimitry Andric continue; 11906c3fb27SDimitry Andric auto Reg = Op.getReg(); 12006c3fb27SDimitry Andric if (isDivergent(Reg)) 12106c3fb27SDimitry Andric continue; 12206c3fb27SDimitry Andric for (MachineInstr &UserInstr : RegInfo.use_instructions(Reg)) { 12306c3fb27SDimitry Andric if (DefCycle.contains(UserInstr.getParent())) 12406c3fb27SDimitry Andric continue; 12506c3fb27SDimitry Andric markDivergent(UserInstr); 12606c3fb27SDimitry Andric } 12706c3fb27SDimitry Andric } 12806c3fb27SDimitry Andric } 12906c3fb27SDimitry Andric 13006c3fb27SDimitry Andric template <> 13106c3fb27SDimitry Andric bool llvm::GenericUniformityAnalysisImpl<MachineSSAContext>::isDivergentUse( 13206c3fb27SDimitry Andric const MachineOperand &U) const { 13306c3fb27SDimitry Andric if (!U.isReg()) 13406c3fb27SDimitry Andric return false; 13506c3fb27SDimitry Andric 13606c3fb27SDimitry Andric auto Reg = U.getReg(); 13706c3fb27SDimitry Andric if (isDivergent(Reg)) 13806c3fb27SDimitry Andric return true; 13906c3fb27SDimitry Andric 14006c3fb27SDimitry Andric const auto &RegInfo = F.getRegInfo(); 14106c3fb27SDimitry Andric auto *Def = RegInfo.getOneDef(Reg); 14206c3fb27SDimitry Andric if (!Def) 14306c3fb27SDimitry Andric return true; 14406c3fb27SDimitry Andric 14506c3fb27SDimitry Andric auto *DefInstr = Def->getParent(); 14606c3fb27SDimitry Andric auto *UseInstr = U.getParent(); 14706c3fb27SDimitry Andric return isTemporalDivergent(*UseInstr->getParent(), *DefInstr); 14806c3fb27SDimitry Andric } 14906c3fb27SDimitry 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 15606c3fb27SDimitry Andric MachineUniformityInfo llvm::computeMachineUniformityInfo( 15706c3fb27SDimitry Andric MachineFunction &F, const MachineCycleInfo &cycleInfo, 158*0fca6ea1SDimitry Andric const MachineDominatorTree &domTree, bool HasBranchDivergence) { 159bdd1243dSDimitry Andric assert(F.getRegInfo().isSSA() && "Expected to be run on SSA form!"); 1605f757f3fSDimitry Andric MachineUniformityInfo UI(domTree, cycleInfo); 16106c3fb27SDimitry Andric if (HasBranchDivergence) 16206c3fb27SDimitry Andric UI.compute(); 16306c3fb27SDimitry Andric return UI; 164bdd1243dSDimitry Andric } 165bdd1243dSDimitry Andric 166bdd1243dSDimitry Andric namespace { 167bdd1243dSDimitry Andric 168bdd1243dSDimitry Andric class MachineUniformityInfoPrinterPass : public MachineFunctionPass { 169bdd1243dSDimitry Andric public: 170bdd1243dSDimitry Andric static char ID; 171bdd1243dSDimitry Andric 172bdd1243dSDimitry Andric MachineUniformityInfoPrinterPass(); 173bdd1243dSDimitry Andric 174bdd1243dSDimitry Andric bool runOnMachineFunction(MachineFunction &F) override; 175bdd1243dSDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override; 176bdd1243dSDimitry Andric }; 177bdd1243dSDimitry Andric 178bdd1243dSDimitry Andric } // namespace 179bdd1243dSDimitry Andric 180bdd1243dSDimitry Andric char MachineUniformityAnalysisPass::ID = 0; 181bdd1243dSDimitry Andric 182bdd1243dSDimitry Andric MachineUniformityAnalysisPass::MachineUniformityAnalysisPass() 183bdd1243dSDimitry Andric : MachineFunctionPass(ID) { 184bdd1243dSDimitry Andric initializeMachineUniformityAnalysisPassPass(*PassRegistry::getPassRegistry()); 185bdd1243dSDimitry Andric } 186bdd1243dSDimitry Andric 187bdd1243dSDimitry Andric INITIALIZE_PASS_BEGIN(MachineUniformityAnalysisPass, "machine-uniformity", 188bdd1243dSDimitry Andric "Machine Uniformity Info Analysis", true, true) 189bdd1243dSDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineCycleInfoWrapperPass) 190*0fca6ea1SDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass) 191bdd1243dSDimitry Andric INITIALIZE_PASS_END(MachineUniformityAnalysisPass, "machine-uniformity", 192bdd1243dSDimitry Andric "Machine Uniformity Info Analysis", true, true) 193bdd1243dSDimitry Andric 194bdd1243dSDimitry Andric void MachineUniformityAnalysisPass::getAnalysisUsage(AnalysisUsage &AU) const { 195bdd1243dSDimitry Andric AU.setPreservesAll(); 196bdd1243dSDimitry Andric AU.addRequired<MachineCycleInfoWrapperPass>(); 197*0fca6ea1SDimitry Andric AU.addRequired<MachineDominatorTreeWrapperPass>(); 198bdd1243dSDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 199bdd1243dSDimitry Andric } 200bdd1243dSDimitry Andric 201bdd1243dSDimitry Andric bool MachineUniformityAnalysisPass::runOnMachineFunction(MachineFunction &MF) { 202*0fca6ea1SDimitry Andric auto &DomTree = 203*0fca6ea1SDimitry Andric getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree().getBase(); 204bdd1243dSDimitry Andric auto &CI = getAnalysis<MachineCycleInfoWrapperPass>().getCycleInfo(); 20506c3fb27SDimitry Andric // FIXME: Query TTI::hasBranchDivergence. -run-pass seems to end up with a 20606c3fb27SDimitry Andric // default NoTTI 20706c3fb27SDimitry Andric UI = computeMachineUniformityInfo(MF, CI, DomTree, true); 208bdd1243dSDimitry Andric return false; 209bdd1243dSDimitry Andric } 210bdd1243dSDimitry Andric 211bdd1243dSDimitry Andric void MachineUniformityAnalysisPass::print(raw_ostream &OS, 212bdd1243dSDimitry Andric const Module *) const { 213bdd1243dSDimitry Andric OS << "MachineUniformityInfo for function: " << UI.getFunction().getName() 214bdd1243dSDimitry Andric << "\n"; 215bdd1243dSDimitry Andric UI.print(OS); 216bdd1243dSDimitry Andric } 217bdd1243dSDimitry Andric 218bdd1243dSDimitry Andric char MachineUniformityInfoPrinterPass::ID = 0; 219bdd1243dSDimitry Andric 220bdd1243dSDimitry Andric MachineUniformityInfoPrinterPass::MachineUniformityInfoPrinterPass() 221bdd1243dSDimitry Andric : MachineFunctionPass(ID) { 222bdd1243dSDimitry Andric initializeMachineUniformityInfoPrinterPassPass( 223bdd1243dSDimitry Andric *PassRegistry::getPassRegistry()); 224bdd1243dSDimitry Andric } 225bdd1243dSDimitry Andric 226bdd1243dSDimitry Andric INITIALIZE_PASS_BEGIN(MachineUniformityInfoPrinterPass, 227bdd1243dSDimitry Andric "print-machine-uniformity", 228bdd1243dSDimitry Andric "Print Machine Uniformity Info Analysis", true, true) 229bdd1243dSDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineUniformityAnalysisPass) 230bdd1243dSDimitry Andric INITIALIZE_PASS_END(MachineUniformityInfoPrinterPass, 231bdd1243dSDimitry Andric "print-machine-uniformity", 232bdd1243dSDimitry Andric "Print Machine Uniformity Info Analysis", true, true) 233bdd1243dSDimitry Andric 234bdd1243dSDimitry Andric void MachineUniformityInfoPrinterPass::getAnalysisUsage( 235bdd1243dSDimitry Andric AnalysisUsage &AU) const { 236bdd1243dSDimitry Andric AU.setPreservesAll(); 237bdd1243dSDimitry Andric AU.addRequired<MachineUniformityAnalysisPass>(); 238bdd1243dSDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 239bdd1243dSDimitry Andric } 240bdd1243dSDimitry Andric 241bdd1243dSDimitry Andric bool MachineUniformityInfoPrinterPass::runOnMachineFunction( 242bdd1243dSDimitry Andric MachineFunction &F) { 243bdd1243dSDimitry Andric auto &UI = getAnalysis<MachineUniformityAnalysisPass>(); 244bdd1243dSDimitry Andric UI.print(errs()); 245bdd1243dSDimitry Andric return false; 246bdd1243dSDimitry Andric } 247