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() &&
235bool RISCVPreAllocZilsdOpt::isSafeToMove(MachineInstr *
MI, MachineInstr *Target,
237 MachineBasicBlock *
MBB =
MI->getParent();
249 const MachineOperand &BaseOp =
MI->getOperand(1);
251 unsigned ScanCount = 0;
252 for (
auto It = Start; It != End; ++It, ++ScanCount) {
254 if (It->isCall() || It->isTerminator()) {
255 LLVM_DEBUG(
dbgs() <<
"Cannot move across call/terminator: " << *It);
260 if (It->hasUnmodeledSideEffects()) {
261 LLVM_DEBUG(
dbgs() <<
"Cannot move across instruction with side effects: "
267 if (BaseOp.
isReg() && It->modifiesRegister(BaseOp.
getReg(),
TRI)) {
269 <<
" modified by: " << *It);
275 (It->readsRegister(DefReg,
TRI) || It->modifiesRegister(DefReg,
TRI))) {
277 <<
" used by: " << *It);
282 if (
MI->mayStore() && It->modifiesRegister(DefReg,
TRI)) {
284 <<
" modified by: " << *It);
289 if (It->mayLoadOrStore() && It->mayAlias(AA, *
MI,
false)) {
298bool RISCVPreAllocZilsdOpt::rescheduleOps(
299 MachineBasicBlock *
MBB, SmallVectorImpl<MachineInstr *> &MIs,
300 BaseRegInfo
Base,
bool IsLoad,
301 DenseMap<MachineInstr *, unsigned> &MI2LocMap) {
305 return getMemoryOpOffset(*A).second < getMemoryOpOffset(*B).second;
311 for (
size_t i = 0; i + 1 < MIs.
size(); i++) {
312 MachineInstr *MI0 = MIs[i];
313 MachineInstr *MI1 = MIs[i + 1];
317 const MachineOperand &BaseOp = MI0->
getOperand(1);
320 "Base register should be register or frame index");
328 if (!canFormLdSdPair(MI0, MI1))
333 bool MI1IsLater = MI2LocMap[MI1] > MI2LocMap[MI0];
337 MachineInstr *MoveInstr, *TargetInstr;
340 MoveInstr = MI1IsLater ? MI1 : MI0;
341 TargetInstr = MI1IsLater ? MI0 : MI1;
344 MoveInstr = MI1IsLater ? MI0 : MI1;
345 TargetInstr = MI1IsLater ? MI1 : MI0;
348 unsigned Distance = MI1IsLater ? MI2LocMap[MI1] - MI2LocMap[MI0]
349 : MI2LocMap[MI0] - MI2LocMap[MI1];
359 if (MoveInstr != TargetInstr)
363 MachineInstrBuilder MIB;
368 .
addReg(FirstReg, RegState::Define)
369 .
addReg(SecondReg, RegState::Define);
413bool RISCVPreAllocZilsdOpt::isMemoryOp(
const MachineInstr &
MI) {
414 unsigned Opcode =
MI.getOpcode();
415 if (Opcode != RISCV::LW && Opcode != RISCV::SW)
418 if (!
MI.getOperand(1).isReg() && !
MI.getOperand(1).isFI())
423 if (!
MI.hasOneMemOperand())
426 const MachineMemOperand *MMO = *
MI.memoperands_begin();
433 if (
MI.getOperand(0).isReg() &&
MI.getOperand(0).isUndef())
437 if (
MI.getOperand(1).isReg() &&
MI.getOperand(1).isUndef())
443bool RISCVPreAllocZilsdOpt::rescheduleLoadStoreInstrs(MachineBasicBlock *
MBB) {
453 DenseMap<MachineInstr *, unsigned> MI2LocMap;
456 using Base2InstMap = DenseMap<BaseRegInfo, SmallVector<MachineInstr *, 4>>;
458 Base2InstMap Base2LdsMap;
459 Base2InstMap Base2StsMap;
470 if (
MI.isCall() ||
MI.isTerminator()) {
477 if (!
MI.isDebugInstr())
478 MI2LocMap[&
MI] = ++Loc;
485 bool IsLd = (
MI.getOpcode() == RISCV::LW);
486 const MachineOperand &BaseOp =
MI.getOperand(1);
492 bool StopHere =
false;
495 auto FindBases = [&](Base2InstMap &Base2Ops, BaseVec &Bases) {
499 BI->second.push_back(&
MI);
504 if (
any_of(BI->second, [&](
const MachineInstr *PrevMI) {
505 return Offset == getMemoryOpOffset(*PrevMI);
510 BI->second.push_back(&
MI);
515 FindBases(Base2LdsMap, LdBases);
517 FindBases(Base2StsMap, StBases);
528 for (
auto Base : LdBases) {
529 SmallVectorImpl<MachineInstr *> &Lds = Base2LdsMap[
Base];
530 if (Lds.
size() > 1) {
536 for (
auto Base : StBases) {
537 SmallVectorImpl<MachineInstr *> &Sts = Base2StsMap[
Base];
538 if (Sts.
size() > 1) {
552 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.
bool contains(MCRegister Reg) const
contains - Return true if the specified register is included in this register class.
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.
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.
const TargetRegisterClass * getRegClass(Register Reg) const
Return the register class of the specified virtual register.
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.
@ Unknown
Not known to have no common set bits.
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.