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 {
93 using MemOffset = std::pair<MemoryOffsetKind, int>;
94 using BaseRegInfo = std::pair<unsigned, MemoryOffsetKind>;
98 bool rescheduleLoadStoreInstrs(MachineBasicBlock *
MBB);
99 bool canFormLdSdPair(MachineInstr *MI0, MachineInstr *MI1);
100 bool rescheduleOps(MachineBasicBlock *
MBB,
101 SmallVectorImpl<MachineInstr *> &MIs, BaseRegInfo
Base,
103 DenseMap<MachineInstr *, unsigned> &MI2LocMap);
104 bool isSafeToMove(MachineInstr *
MI, MachineInstr *Target,
bool MoveForward);
107 const RISCVSubtarget *STI;
108 const RISCVInstrInfo *TII;
109 const RISCVRegisterInfo *TRI;
110 MachineRegisterInfo *MRI;
112 MachineDominatorTree *DT;
118char RISCVPreAllocZilsdOpt::ID = 0;
121 "RISC-V pre-allocation Zilsd optimization",
false,
false)
139 if (STI->is64Bit() || !STI->hasStdExtZilsd())
142 TII = STI->getInstrInfo();
143 TRI = STI->getRegisterInfo();
144 MRI = &MF.getRegInfo();
145 AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
146 DT = &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
150 RequiredAlign = STI->getZilsdAlign();
159RISCVPreAllocZilsdOpt::MemOffset
161 switch (
MI.getOpcode()) {
165 const MachineOperand &BaseOp =
MI.getOperand(1);
166 const MachineOperand &
OffsetOp =
MI.getOperand(2);
171 return std::make_pair(MemoryOffsetKind::FrameIdx,
OffsetOp.getImm());
172 return std::make_pair(MemoryOffsetKind::Imm,
OffsetOp.getImm());
178 return std::make_pair(MemoryOffsetKind::Global,
OffsetOp.getOffset());
180 return std::make_pair(MemoryOffsetKind::CPI,
OffsetOp.getOffset());
182 return std::make_pair(MemoryOffsetKind::BlockAddr,
192 return std::make_pair(MemoryOffsetKind::Unknown, 0);
195bool RISCVPreAllocZilsdOpt::canFormLdSdPair(MachineInstr *MI0,
205 if (Offset1 - Offset0 != 4)
209 const MachineMemOperand *MMO = *MI0->memoperands_begin();
210 if (MMO->
getAlign() < RequiredAlign)
221 Register FirstReg = MI0->getOperand(0).getReg();
222 Register SecondReg = MI1->getOperand(0).getReg();
223 if (FirstReg == SecondReg) {
225 if (FirstOpDefInst->
isCopy() &&
234bool RISCVPreAllocZilsdOpt::isSafeToMove(MachineInstr *
MI, MachineInstr *Target,
236 MachineBasicBlock *
MBB =
MI->getParent();
248 const MachineOperand &BaseOp =
MI->getOperand(1);
250 unsigned ScanCount = 0;
251 for (
auto It = Start; It != End; ++It, ++ScanCount) {
253 if (It->isCall() || It->isTerminator()) {
254 LLVM_DEBUG(
dbgs() <<
"Cannot move across call/terminator: " << *It);
259 if (It->hasUnmodeledSideEffects()) {
260 LLVM_DEBUG(
dbgs() <<
"Cannot move across instruction with side effects: "
266 if (BaseOp.
isReg() && It->modifiesRegister(BaseOp.
getReg(),
TRI)) {
268 <<
" modified by: " << *It);
274 (It->readsRegister(DefReg,
TRI) || It->modifiesRegister(DefReg,
TRI))) {
276 <<
" used by: " << *It);
281 if (
MI->mayStore() && It->modifiesRegister(DefReg,
TRI)) {
283 <<
" modified by: " << *It);
288 if (It->mayLoadOrStore() && It->mayAlias(AA, *
MI,
false)) {
297bool RISCVPreAllocZilsdOpt::rescheduleOps(
298 MachineBasicBlock *
MBB, SmallVectorImpl<MachineInstr *> &MIs,
299 BaseRegInfo
Base,
bool IsLoad,
300 DenseMap<MachineInstr *, unsigned> &MI2LocMap) {
304 return getMemoryOpOffset(*A).second < getMemoryOpOffset(*B).second;
310 for (
size_t i = 0; i + 1 < MIs.
size(); i++) {
311 MachineInstr *MI0 = MIs[i];
312 MachineInstr *MI1 = MIs[i + 1];
316 const MachineOperand &BaseOp = MI0->
getOperand(1);
319 "Base register should be register or frame index");
327 if (!canFormLdSdPair(MI0, MI1))
332 bool MI1IsLater = MI2LocMap[MI1] > MI2LocMap[MI0];
336 MachineInstr *MoveInstr, *TargetInstr;
339 MoveInstr = MI1IsLater ? MI1 : MI0;
340 TargetInstr = MI1IsLater ? MI0 : MI1;
343 MoveInstr = MI1IsLater ? MI0 : MI1;
344 TargetInstr = MI1IsLater ? MI1 : MI0;
347 unsigned Distance = MI1IsLater ? MI2LocMap[MI1] - MI2LocMap[MI0]
348 : MI2LocMap[MI0] - MI2LocMap[MI1];
358 if (MoveInstr != TargetInstr)
362 MachineInstrBuilder MIB;
367 .
addReg(FirstReg, RegState::Define)
368 .
addReg(SecondReg, RegState::Define);
412bool RISCVPreAllocZilsdOpt::isMemoryOp(
const MachineInstr &
MI) {
413 unsigned Opcode =
MI.getOpcode();
414 if (Opcode != RISCV::LW && Opcode != RISCV::SW)
417 if (!
MI.getOperand(1).isReg() && !
MI.getOperand(1).isFI())
422 if (!
MI.hasOneMemOperand())
425 const MachineMemOperand *MMO = *
MI.memoperands_begin();
432 if (
MI.getOperand(0).isReg() &&
MI.getOperand(0).isUndef())
436 if (
MI.getOperand(1).isReg() &&
MI.getOperand(1).isUndef())
442bool RISCVPreAllocZilsdOpt::rescheduleLoadStoreInstrs(MachineBasicBlock *
MBB) {
452 DenseMap<MachineInstr *, unsigned> MI2LocMap;
455 using Base2InstMap = DenseMap<BaseRegInfo, SmallVector<MachineInstr *, 4>>;
457 Base2InstMap Base2LdsMap;
458 Base2InstMap Base2StsMap;
469 if (
MI.isCall() ||
MI.isTerminator()) {
476 if (!
MI.isDebugInstr())
477 MI2LocMap[&
MI] = ++Loc;
484 bool IsLd = (
MI.getOpcode() == RISCV::LW);
485 const MachineOperand &BaseOp =
MI.getOperand(1);
491 bool StopHere =
false;
494 auto FindBases = [&](Base2InstMap &Base2Ops, BaseVec &Bases) {
498 BI->second.push_back(&
MI);
503 if (
any_of(BI->second, [&](
const MachineInstr *PrevMI) {
504 return Offset == getMemoryOpOffset(*PrevMI);
509 BI->second.push_back(&
MI);
514 FindBases(Base2LdsMap, LdBases);
516 FindBases(Base2StsMap, StBases);
527 for (
auto Base : LdBases) {
528 SmallVectorImpl<MachineInstr *> &Lds = Base2LdsMap[
Base];
529 if (Lds.
size() > 1) {
535 for (
auto Base : StBases) {
536 SmallVectorImpl<MachineInstr *> &Sts = Base2StsMap[
Base];
537 if (Sts.
size() > 1) {
551 return new RISCVPreAllocZilsdOpt();
for(const MachineOperand &MO :llvm::drop_begin(OldMI.operands(), Desc.getNumOperands()))
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
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 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)
static bool isSafeToMove(const MachineOperand *Def, const MachineOperand *Use, const MachineInstr *Insert, const WebAssemblyFunctionInfo &MFI, const MachineRegisterInfo &MRI, bool Optimize)
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 & 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
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.
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.
LLVM_ABI MachineInstr * getUniqueVRegDef(Register Reg) const
getUniqueVRegDef - Return the unique machine instr that defines the specified virtual register or nul...
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
constexpr unsigned id() const
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.
initializer< Ty > init(const Ty &Val)
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.