47#define DEBUG_TYPE "riscv-pre-alloc-zilsd-opt"
49STATISTIC(NumLDFormed,
"Number of LD instructions formed");
50STATISTIC(NumSDFormed,
"Number of SD instructions formed");
65 StringRef getPassName()
const override {
66 return "RISC-V pre-allocation Zilsd load/store optimization";
69 MachineFunctionProperties getRequiredProperties()
const override {
70 return MachineFunctionProperties().setIsSSA();
73 void getAnalysisUsage(AnalysisUsage &AU)
const override {
81class RISCVPreAllocZilsdOptImpl {
82 enum class MemoryOffsetKind {
90 using MemOffset = std::pair<MemoryOffsetKind, int>;
91 using BaseRegInfo = std::pair<unsigned, MemoryOffsetKind>;
94 bool rescheduleLoadStoreInstrs(MachineBasicBlock *
MBB);
95 bool canFormLdSdPair(MachineInstr *MI0, MachineInstr *MI1);
96 bool rescheduleOps(MachineBasicBlock *
MBB,
97 SmallVectorImpl<MachineInstr *> &MIs, BaseRegInfo
Base,
99 DenseMap<MachineInstr *, unsigned> &MI2LocMap);
100 bool isSafeToMove(MachineInstr *
MI, MachineInstr *Target,
bool MoveForward);
103 const RISCVSubtarget *STI;
104 const RISCVInstrInfo *TII;
105 const RISCVRegisterInfo *TRI;
106 MachineRegisterInfo *MRI;
108 MachineDominatorTree *DT;
114 function_ref<MachineDominatorTree *()> GetMDT);
119char RISCVPreAllocZilsdOptLegacy::ID = 0;
122 "RISC-V pre-allocation Zilsd optimization",
false,
false)
132bool RISCVPreAllocZilsdOptImpl::runOnMachineFunction(
140 if (STI->
is64Bit() || !STI->hasStdExtZilsd())
145 MRI = &MF.getRegInfo();
153 for (
auto &
MBB : MF) {
160RISCVPreAllocZilsdOptImpl::MemOffset
161RISCVPreAllocZilsdOptImpl::getMemoryOpOffset(
const MachineInstr &
MI) {
162 switch (
MI.getOpcode()) {
166 const MachineOperand &BaseOp =
MI.getOperand(1);
167 const MachineOperand &
OffsetOp =
MI.getOperand(2);
172 return std::make_pair(MemoryOffsetKind::FrameIdx,
OffsetOp.getImm());
173 return std::make_pair(MemoryOffsetKind::Imm,
OffsetOp.getImm());
179 return std::make_pair(MemoryOffsetKind::Global,
OffsetOp.getOffset());
181 return std::make_pair(MemoryOffsetKind::CPI,
OffsetOp.getOffset());
183 return std::make_pair(MemoryOffsetKind::BlockAddr,
193 return std::make_pair(MemoryOffsetKind::Unknown, 0);
196bool RISCVPreAllocZilsdOptImpl::canFormLdSdPair(MachineInstr *MI0,
206 if (Offset1 - Offset0 != 4)
210 const MachineMemOperand *MMO = *MI0->memoperands_begin();
211 if (MMO->
getAlign() < RequiredAlign)
216 if (MI0->getOperand(0).getReg() == MI1->getOperand(0).getReg())
222bool RISCVPreAllocZilsdOptImpl::isSafeToMove(MachineInstr *
MI,
223 MachineInstr *Target,
237 const MachineOperand &BaseOp =
MI->getOperand(1);
239 unsigned ScanCount = 0;
240 for (
auto It = Start; It !=
End; ++It, ++ScanCount) {
242 if (It->isCall() || It->isTerminator()) {
243 LLVM_DEBUG(
dbgs() <<
"Cannot move across call/terminator: " << *It);
248 if (It->hasUnmodeledSideEffects()) {
249 LLVM_DEBUG(
dbgs() <<
"Cannot move across instruction with side effects: "
255 if (BaseOp.
isReg() && It->modifiesRegister(BaseOp.
getReg(),
TRI)) {
257 <<
" modified by: " << *It);
263 (It->readsRegister(DefReg,
TRI) || It->modifiesRegister(DefReg,
TRI))) {
265 <<
" used by: " << *It);
270 if (
MI->mayStore() && It->modifiesRegister(DefReg,
TRI)) {
272 <<
" modified by: " << *It);
277 if (It->mayLoadOrStore() && It->mayAlias(AA, *
MI,
false)) {
286bool RISCVPreAllocZilsdOptImpl::rescheduleOps(
287 MachineBasicBlock *
MBB, SmallVectorImpl<MachineInstr *> &MIs,
288 BaseRegInfo
Base,
bool IsLoad,
289 DenseMap<MachineInstr *, unsigned> &MI2LocMap) {
293 return getMemoryOpOffset(*A).second < getMemoryOpOffset(*B).second;
299 for (
size_t i = 0; i + 1 < MIs.
size(); i++) {
300 MachineInstr *MI0 = MIs[i];
301 MachineInstr *MI1 = MIs[i + 1];
305 const MachineOperand &BaseOp = MI0->
getOperand(1);
308 "Base register should be register or frame index");
316 if (!canFormLdSdPair(MI0, MI1))
321 bool MI1IsLater = MI2LocMap[MI1] > MI2LocMap[MI0];
325 MachineInstr *MoveInstr, *TargetInstr;
328 MoveInstr = MI1IsLater ? MI1 : MI0;
329 TargetInstr = MI1IsLater ? MI0 : MI1;
332 MoveInstr = MI1IsLater ? MI0 : MI1;
333 TargetInstr = MI1IsLater ? MI1 : MI0;
336 unsigned Distance = MI1IsLater ? MI2LocMap[MI1] - MI2LocMap[MI0]
337 : MI2LocMap[MI0] - MI2LocMap[MI1];
339 Distance > STI->
getCLOpts().zilsd_max_reschedule_distance)
347 if (MoveInstr != TargetInstr)
351 MachineInstrBuilder MIB;
401bool RISCVPreAllocZilsdOptImpl::isMemoryOp(
const MachineInstr &
MI) {
402 unsigned Opcode =
MI.getOpcode();
403 if (Opcode != RISCV::LW && Opcode != RISCV::SW)
406 if (!
MI.getOperand(1).isReg() && !
MI.getOperand(1).isFI())
411 if (!
MI.hasOneMemOperand())
414 const MachineMemOperand *MMO = *
MI.memoperands_begin();
421 if (
MI.getOperand(0).isReg() &&
MI.getOperand(0).isUndef())
425 if (
MI.getOperand(1).isReg() &&
MI.getOperand(1).isUndef())
431bool RISCVPreAllocZilsdOptImpl::rescheduleLoadStoreInstrs(
432 MachineBasicBlock *
MBB) {
442 DenseMap<MachineInstr *, unsigned> MI2LocMap;
445 using Base2InstMap = DenseMap<BaseRegInfo, SmallVector<MachineInstr *, 4>>;
447 Base2InstMap Base2LdsMap;
448 Base2InstMap Base2StsMap;
459 if (
MI.isCall() ||
MI.isTerminator()) {
466 if (!
MI.isDebugInstr())
467 MI2LocMap[&
MI] = ++Loc;
474 bool IsLd = (
MI.getOpcode() == RISCV::LW);
475 const MachineOperand &BaseOp =
MI.getOperand(1);
481 bool StopHere =
false;
484 auto FindBases = [&](Base2InstMap &Base2Ops, BaseVec &Bases) {
488 BI->second.push_back(&
MI);
493 if (
any_of(BI->second, [&](
const MachineInstr *PrevMI) {
494 return Offset == getMemoryOpOffset(*PrevMI);
499 BI->second.push_back(&
MI);
504 FindBases(Base2LdsMap, LdBases);
506 FindBases(Base2StsMap, StBases);
517 for (
auto Base : LdBases) {
518 SmallVectorImpl<MachineInstr *> &Lds = Base2LdsMap[
Base];
519 if (Lds.
size() > 1) {
525 for (
auto Base : StBases) {
526 SmallVectorImpl<MachineInstr *> &Sts = Base2StsMap[
Base];
527 if (Sts.
size() > 1) {
541 return new RISCVPreAllocZilsdOptLegacy();
544bool RISCVPreAllocZilsdOptLegacy::runOnMachineFunction(
MachineFunction &MF) {
547 RISCVPreAllocZilsdOptImpl Impl;
548 return Impl.runOnMachineFunction(
549 MF, [&]() {
return &getAnalysis<AAResultsWrapperPass>().getAAResults(); },
551 return &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
558 RISCVPreAllocZilsdOptImpl Impl;
559 bool Changed = Impl.runOnMachineFunction(
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static bool isMemoryOp(const MachineInstr &MI)
Returns true if instruction is a memory operation that this pass is capable of operating on.
static int getMemoryOpOffset(const MachineInstr &MI)
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
MachineBasicBlock MachineBasicBlock::iterator MBBI
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file defines the DenseMap class.
const HexagonInstrInfo * TII
std::pair< Instruction::BinaryOps, Value * > OffsetOp
Find all possible pairs (BinOp, RHS) that BinOp V, RHS can be simplified.
Register const TargetRegisterInfo * TRI
Promote Memory to Register
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
MachineRegisterInfo & MRI
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
static bool isSafeToMove(const MachineOperand *Def, const MachineOperand *Use, const MachineInstr *Insert, const WebAssemblyFunctionInfo &MFI, const MachineRegisterInfo &MRI, bool Optimize)
A manager for alias analyses.
A wrapper pass to provide the legacy pass manager access to a suitably prepared AAResults object.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
AnalysisUsage & addRequired()
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
Represents analyses that only rely on functions' control flow.
FunctionPass class - This class is used to implement most global optimizations.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
void splice(iterator Where, MachineBasicBlock *Other, iterator From)
Take an instruction from MBB 'Other' at the position From, and insert it into this MBB right before '...
MachineInstrBundleIterator< MachineInstr > iterator
Analysis pass which computes a MachineDominatorTree.
Analysis pass which computes a MachineDominatorTree.
DominatorTree Class - Concrete subclass of DominatorTreeBase that is used to compute a normal dominat...
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
Function & getFunction()
Return the LLVM function that this machine code represents.
const MachineInstrBuilder & cloneMergedMemRefs(ArrayRef< const MachineInstr * > OtherMIs) const
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
const MachineInstrBuilder & addFrameIndex(int Idx) const
const MachineInstrBuilder & addDef(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register definition operand.
Representation of each machine instruction.
bool hasOneMemOperand() const
Return true if this instruction has exactly one MachineMemOperand.
const DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
const MachineOperand & getOperand(unsigned i) const
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
bool isAtomic() const
Returns true if this operation has an atomic ordering requirement of unordered or higher,...
LLVM_ABI Align getAlign() const
Return the minimum known alignment in bytes of the actual memory reference.
bool isReg() const
isReg - Tests if this is a MO_Register operand.
Register getReg() const
getReg - Returns the register number.
bool isFI() const
isFI - Tests if this is a MO_FrameIndex operand.
void setRegAllocationHint(Register VReg, unsigned Type, Register PrefReg)
setRegAllocationHint - Specify a register allocation hint for the specified virtual register.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
const RISCVOptions & getCLOpts() const
const RISCVRegisterInfo * getRegisterInfo() const override
Align getZilsdAlign() const
const RISCVInstrInfo * getInstrInfo() const override
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
constexpr unsigned id() const
An efficient, type-erasing, non-owning reference to a callable.
self_iterator getIterator()
Pass manager infrastructure for declaring and invalidating analyses.
Abstract Attribute helper functions.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
This is an optimization pass for GlobalISel generic memory operations.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
@ Unknown
Not known to have no common set bits.
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
void sort(IteratorTy Start, IteratorTy End)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
@ Global
Append to llvm.global_dtors.
@ End
Run the machine verifier once, at the end of the pipeline.
AAResults AliasAnalysis
Temporary typedef for legacy code that uses a generic AliasAnalysis pointer or reference.
FunctionPass * createRISCVPreAllocZilsdOptLegacyPass()
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.