45#define DEBUG_TYPE "riscv-zilsd-opt"
47STATISTIC(NumLDFormed,
"Number of LD instructions formed");
48STATISTIC(NumSDFormed,
"Number of SD instructions formed");
52 cl::desc(
"Disable Zilsd load/store optimization"));
56 cl::desc(
"Maximum distance for rescheduling load/store instructions"));
69 bool runOnMachineFunction(MachineFunction &MF)
override;
71 StringRef getPassName()
const override {
72 return "RISC-V pre-allocation Zilsd load/store optimization";
75 MachineFunctionProperties getRequiredProperties()
const override {
76 return MachineFunctionProperties().setIsSSA();
79 void getAnalysisUsage(AnalysisUsage &AU)
const override {
85 enum class MemoryOffsetKind {
92 using MemOffset = std::pair<MemoryOffsetKind, int>;
93 using BaseRegInfo = std::pair<unsigned, MemoryOffsetKind>;
97 bool rescheduleLoadStoreInstrs(MachineBasicBlock *
MBB);
98 bool canFormLdSdPair(MachineInstr *MI0, MachineInstr *MI1);
99 bool rescheduleOps(MachineBasicBlock *
MBB,
100 SmallVectorImpl<MachineInstr *> &MIs, BaseRegInfo
Base,
102 DenseMap<MachineInstr *, unsigned> &MI2LocMap);
103 bool isSafeToMove(MachineInstr *
MI, MachineInstr *Target,
bool MoveForward);
106 const RISCVSubtarget *STI;
107 const RISCVInstrInfo *TII;
108 const RISCVRegisterInfo *TRI;
109 MachineRegisterInfo *MRI;
111 MachineDominatorTree *DT;
117char RISCVPreAllocZilsdOpt::ID = 0;
120 "RISC-V pre-allocation Zilsd optimization",
false,
false)
138 if (STI->is64Bit() || !STI->hasStdExtZilsd())
141 TII = STI->getInstrInfo();
142 TRI = STI->getRegisterInfo();
143 MRI = &MF.getRegInfo();
144 AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
145 DT = &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
149 RequiredAlign = STI->enableUnalignedScalarMem() ?
Align(1)
150 : STI->allowZilsd4ByteAlign() ?
Align(4)
153 for (
auto &
MBB : MF) {
160RISCVPreAllocZilsdOpt::MemOffset
162 switch (
MI.getOpcode()) {
166 const MachineOperand &
OffsetOp =
MI.getOperand(2);
170 return std::make_pair(MemoryOffsetKind::Imm,
OffsetOp.getImm());
175 return std::make_pair(MemoryOffsetKind::Global,
OffsetOp.getOffset());
177 return std::make_pair(MemoryOffsetKind::CPI,
OffsetOp.getOffset());
179 return std::make_pair(MemoryOffsetKind::BlockAddr,
189 return std::make_pair(MemoryOffsetKind::Unknown, 0);
192bool RISCVPreAllocZilsdOpt::canFormLdSdPair(MachineInstr *MI0,
202 if (Offset1 - Offset0 != 4)
206 const MachineMemOperand *MMO = *MI0->memoperands_begin();
207 if (MMO->
getAlign() < RequiredAlign)
212 Register FirstReg = MI0->getOperand(0).getReg();
213 Register SecondReg = MI1->getOperand(0).getReg();
214 if (FirstReg == SecondReg)
220bool RISCVPreAllocZilsdOpt::isSafeToMove(MachineInstr *
MI, MachineInstr *Target,
222 MachineBasicBlock *
MBB =
MI->getParent();
236 unsigned ScanCount = 0;
237 for (
auto It = Start; It != End; ++It, ++ScanCount) {
239 if (It->isCall() || It->isTerminator()) {
240 LLVM_DEBUG(
dbgs() <<
"Cannot move across call/terminator: " << *It);
245 if (It->hasUnmodeledSideEffects()) {
246 LLVM_DEBUG(
dbgs() <<
"Cannot move across instruction with side effects: "
252 if (It->modifiesRegister(BaseReg,
TRI)) {
254 <<
" modified by: " << *It);
260 (It->readsRegister(DefReg,
TRI) || It->modifiesRegister(DefReg,
TRI))) {
262 <<
" used by: " << *It);
267 if (
MI->mayStore() && It->modifiesRegister(DefReg,
TRI)) {
269 <<
" modified by: " << *It);
274 if (It->mayLoadOrStore() && It->mayAlias(AA, *
MI,
false)) {
283bool RISCVPreAllocZilsdOpt::rescheduleOps(
284 MachineBasicBlock *
MBB, SmallVectorImpl<MachineInstr *> &MIs,
285 BaseRegInfo
Base,
bool IsLoad,
286 DenseMap<MachineInstr *, unsigned> &MI2LocMap) {
290 return getMemoryOpOffset(*A).second < getMemoryOpOffset(*B).second;
296 for (
size_t i = 0; i + 1 < MIs.
size(); i++) {
297 MachineInstr *MI0 = MIs[i];
298 MachineInstr *MI1 = MIs[i + 1];
311 if (!canFormLdSdPair(MI0, MI1))
316 bool MI1IsLater = MI2LocMap[MI1] > MI2LocMap[MI0];
320 MachineInstr *MoveInstr, *TargetInstr;
323 MoveInstr = MI1IsLater ? MI1 : MI0;
324 TargetInstr = MI1IsLater ? MI0 : MI1;
327 MoveInstr = MI1IsLater ? MI0 : MI1;
328 TargetInstr = MI1IsLater ? MI1 : MI0;
331 unsigned Distance = MI1IsLater ? MI2LocMap[MI1] - MI2LocMap[MI0]
332 : MI2LocMap[MI0] - MI2LocMap[MI1];
342 if (MoveInstr != TargetInstr)
346 MachineInstrBuilder MIB;
394bool RISCVPreAllocZilsdOpt::isMemoryOp(
const MachineInstr &
MI) {
395 unsigned Opcode =
MI.getOpcode();
396 if (Opcode != RISCV::LW && Opcode != RISCV::SW)
399 if (!
MI.getOperand(1).isReg())
404 if (!
MI.hasOneMemOperand())
407 const MachineMemOperand *MMO = *
MI.memoperands_begin();
414 if (
MI.getOperand(0).isReg() &&
MI.getOperand(0).isUndef())
418 if (
MI.getOperand(1).isUndef())
424bool RISCVPreAllocZilsdOpt::rescheduleLoadStoreInstrs(MachineBasicBlock *
MBB) {
434 DenseMap<MachineInstr *, unsigned> MI2LocMap;
437 using Base2InstMap = DenseMap<BaseRegInfo, SmallVector<MachineInstr *, 4>>;
439 Base2InstMap Base2LdsMap;
440 Base2InstMap Base2StsMap;
451 if (
MI.isCall() ||
MI.isTerminator()) {
458 if (!
MI.isDebugInstr())
459 MI2LocMap[&
MI] = ++Loc;
466 bool IsLd = (
MI.getOpcode() == RISCV::LW);
468 bool StopHere =
false;
471 auto FindBases = [&](Base2InstMap &Base2Ops, BaseVec &Bases) {
475 BI->second.push_back(&
MI);
480 if (
any_of(BI->second, [&](
const MachineInstr *PrevMI) {
481 return Offset == getMemoryOpOffset(*PrevMI);
486 BI->second.push_back(&
MI);
491 FindBases(Base2LdsMap, LdBases);
493 FindBases(Base2StsMap, StBases);
504 for (
auto Base : LdBases) {
505 SmallVectorImpl<MachineInstr *> &Lds = Base2LdsMap[
Base];
506 if (Lds.
size() > 1) {
512 for (
auto Base : StBases) {
513 SmallVectorImpl<MachineInstr *> &Sts = Base2StsMap[
Base];
514 if (Sts.
size() > 1) {
528 return new RISCVPreAllocZilsdOpt();
unsigned const MachineRegisterInfo * MRI
static int getMemoryOpOffset(const MachineInstr &MI)
static bool isMemoryOp(const MachineInstr &MI)
Returns true if instruction is a memory operation that this pass is capable of operating on.
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)
static bool isSafeToMove(const MachineInstr &From, const MachineInstr &To)
Check if it's safe to move From down to To, checking that no physical registers are clobbered.
static cl::opt< bool > DisableZilsdOpt("disable-riscv-zilsd-opt", cl::Hidden, cl::init(false), cl::desc("Disable Zilsd load/store optimization"))
static cl::opt< unsigned > MaxRescheduleDistance("riscv-zilsd-max-reschedule-distance", cl::Hidden, cl::init(10), cl::desc("Maximum distance for rescheduling load/store instructions"))
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)
A wrapper pass to provide the legacy pass manager access to a suitably prepared AAResults object.
AnalysisUsage & addRequired()
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
FunctionPass class - This class is used to implement most global optimizations.
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.
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.
const MachineInstrBuilder & cloneMergedMemRefs(ArrayRef< const MachineInstr * > OtherMIs) const
const MachineInstrBuilder & add(const MachineOperand &MO) const
const MachineInstrBuilder & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register 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.
LLVM_ABI void eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
const MachineOperand & getOperand(unsigned i) const
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.
Register getReg() const
getReg - Returns the register number.
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
self_iterator getIterator()
Abstract Attribute helper functions.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ Define
Register definition.
initializer< Ty > init(const Ty &Val)
BaseReg
Stack frame base register. Bit 0 of FREInfo.Info.
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.
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
FunctionPass * createRISCVPreAllocZilsdOptPass()
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.
AAResults AliasAnalysis
Temporary typedef for legacy code that uses a generic AliasAnalysis pointer or reference.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
This struct is a compact representation of a valid (non-zero power of two) alignment.