llvm-project/llvm/lib/CodeGen/MachineCycleAnalysis.cpp
Sameer Sahasrabuddhe 475ce4c200 RFC: Uniformity Analysis for Irreducible Control Flow
Uniformity analysis is a generalization of divergence analysis to
include irreducible control flow:

  1. The proposed spec presents a notion of "maximal convergence" that
     captures the existing convention of converging threads at the
     headers of natual loops.

  2. Maximal convergence is then extended to irreducible cycles. The
     identity of irreducible cycles is determined by the choices made
     in a depth-first traversal of the control flow graph. Uniformity
     analysis uses criteria that depend only on closed paths and not
     cycles, to determine maximal convergence. This makes it a
     conservative analysis that is independent of the effect of DFS on
     CycleInfo.

  3. The analysis is implemented as a template that can be
     instantiated for both LLVM IR and Machine IR.

Validation:
  - passes existing tests for divergence analysis
  - passes new tests with irreducible control flow
  - passes equivalent tests in MIR and GMIR

Based on concepts originally outlined by
Nicolai Haehnle <nicolai.haehnle@amd.com>

With contributions from Ruiling Song <ruiling.song@amd.com> and
Jay Foad <jay.foad@amd.com>.

Support for GMIR and lit tests for GMIR/MIR added by
Yashwant Singh <yashwant.singh@amd.com>.

Differential Revision: https://reviews.llvm.org/D130746
2022-12-20 07:22:24 +05:30

150 lines
5.1 KiB
C++

//===- MachineCycleAnalysis.cpp - Compute CycleInfo for Machine IR --------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "llvm/CodeGen/MachineCycleAnalysis.h"
#include "llvm/ADT/GenericCycleImpl.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/MachineSSAContext.h"
#include "llvm/CodeGen/TargetInstrInfo.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/InitializePasses.h"
using namespace llvm;
template class llvm::GenericCycleInfo<llvm::MachineSSAContext>;
template class llvm::GenericCycle<llvm::MachineSSAContext>;
char MachineCycleInfoWrapperPass::ID = 0;
MachineCycleInfoWrapperPass::MachineCycleInfoWrapperPass()
: MachineFunctionPass(ID) {
initializeMachineCycleInfoWrapperPassPass(*PassRegistry::getPassRegistry());
}
INITIALIZE_PASS_BEGIN(MachineCycleInfoWrapperPass, "machine-cycles",
"Machine Cycle Info Analysis", true, true)
INITIALIZE_PASS_END(MachineCycleInfoWrapperPass, "machine-cycles",
"Machine Cycle Info Analysis", true, true)
void MachineCycleInfoWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesAll();
MachineFunctionPass::getAnalysisUsage(AU);
}
bool MachineCycleInfoWrapperPass::runOnMachineFunction(MachineFunction &Func) {
CI.clear();
F = &Func;
CI.compute(Func);
return false;
}
void MachineCycleInfoWrapperPass::print(raw_ostream &OS, const Module *) const {
OS << "MachineCycleInfo for function: " << F->getName() << "\n";
CI.print(OS);
}
void MachineCycleInfoWrapperPass::releaseMemory() {
CI.clear();
F = nullptr;
}
class MachineCycleInfoPrinterPass : public MachineFunctionPass {
public:
static char ID;
MachineCycleInfoPrinterPass();
bool runOnMachineFunction(MachineFunction &F) override;
void getAnalysisUsage(AnalysisUsage &AU) const override;
};
char MachineCycleInfoPrinterPass::ID = 0;
MachineCycleInfoPrinterPass::MachineCycleInfoPrinterPass()
: MachineFunctionPass(ID) {
initializeMachineCycleInfoPrinterPassPass(*PassRegistry::getPassRegistry());
}
INITIALIZE_PASS_BEGIN(MachineCycleInfoPrinterPass, "print-machine-cycles",
"Print Machine Cycle Info Analysis", true, true)
INITIALIZE_PASS_DEPENDENCY(MachineCycleInfoWrapperPass)
INITIALIZE_PASS_END(MachineCycleInfoPrinterPass, "print-machine-cycles",
"Print Machine Cycle Info Analysis", true, true)
void MachineCycleInfoPrinterPass::getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesAll();
AU.addRequired<MachineCycleInfoWrapperPass>();
MachineFunctionPass::getAnalysisUsage(AU);
}
bool MachineCycleInfoPrinterPass::runOnMachineFunction(MachineFunction &F) {
auto &CI = getAnalysis<MachineCycleInfoWrapperPass>();
CI.print(errs());
return false;
}
bool llvm::isCycleInvariant(const MachineCycle *Cycle, MachineInstr &I) {
MachineFunction *MF = I.getParent()->getParent();
MachineRegisterInfo *MRI = &MF->getRegInfo();
const TargetSubtargetInfo &ST = MF->getSubtarget();
const TargetRegisterInfo *TRI = ST.getRegisterInfo();
const TargetInstrInfo *TII = ST.getInstrInfo();
// The instruction is cycle invariant if all of its operands are.
for (const MachineOperand &MO : I.operands()) {
if (!MO.isReg())
continue;
Register Reg = MO.getReg();
if (Reg == 0)
continue;
// An instruction that uses or defines a physical register can't e.g. be
// hoisted, so mark this as not invariant.
if (Register::isPhysicalRegister(Reg)) {
if (MO.isUse()) {
// If the physreg has no defs anywhere, it's just an ambient register
// and we can freely move its uses. Alternatively, if it's allocatable,
// it could get allocated to something with a def during allocation.
// However, if the physreg is known to always be caller saved/restored
// then this use is safe to hoist.
if (!MRI->isConstantPhysReg(Reg) &&
!(TRI->isCallerPreservedPhysReg(Reg.asMCReg(), *I.getMF())) &&
!TII->isIgnorableUse(MO))
return false;
// Otherwise it's safe to move.
continue;
} else if (!MO.isDead()) {
// A def that isn't dead can't be moved.
return false;
} else if (any_of(Cycle->getEntries(),
[&](const MachineBasicBlock *Block) {
return Block->isLiveIn(Reg);
})) {
// If the reg is live into any header of the cycle we can't hoist an
// instruction which would clobber it.
return false;
}
}
if (!MO.isUse())
continue;
assert(MRI->getVRegDef(Reg) && "Machine instr not mapped for this vreg?!");
// If the cycle contains the definition of an operand, then the instruction
// isn't cycle invariant.
if (Cycle->contains(MRI->getVRegDef(Reg)->getParent()))
return false;
}
// If we got this far, the instruction is cycle invariant!
return true;
}