44#define DEBUG_TYPE "riscv-zilsd-opt"
46STATISTIC(NumLDFormed,
"Number of LD instructions formed");
47STATISTIC(NumSDFormed,
"Number of SD instructions formed");
62 StringRef getPassName()
const override {
63 return "RISC-V pre-allocation Zilsd load/store optimization";
66 MachineFunctionProperties getRequiredProperties()
const override {
67 return MachineFunctionProperties().setIsSSA();
70 void getAnalysisUsage(AnalysisUsage &AU)
const override {
76 enum class MemoryOffsetKind {
84 using MemOffset = std::pair<MemoryOffsetKind, int>;
85 using BaseRegInfo = std::pair<unsigned, MemoryOffsetKind>;
89 bool rescheduleLoadStoreInstrs(MachineBasicBlock *
MBB);
90 bool canFormLdSdPair(MachineInstr *MI0, MachineInstr *MI1);
91 bool rescheduleOps(MachineBasicBlock *
MBB,
92 SmallVectorImpl<MachineInstr *> &MIs, BaseRegInfo
Base,
94 DenseMap<MachineInstr *, unsigned> &MI2LocMap);
95 bool isSafeToMove(MachineInstr *
MI, MachineInstr *Target,
bool MoveForward);
98 const RISCVSubtarget *STI;
99 const RISCVInstrInfo *TII;
100 const RISCVRegisterInfo *TRI;
101 MachineRegisterInfo *MRI;
103 MachineDominatorTree *DT;
109char RISCVPreAllocZilsdOpt::ID = 0;
112 "RISC-V pre-allocation Zilsd optimization",
false,
false)
125 if (!STI->getCLOpts().zilsd_opt || skipFunction(MF.getFunction()))
129 if (STI->is64Bit() || !STI->hasStdExtZilsd())
132 TII = STI->getInstrInfo();
133 TRI = STI->getRegisterInfo();
134 MRI = &MF.getRegInfo();
135 AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
136 DT = &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
140 RequiredAlign = STI->getZilsdAlign();
149RISCVPreAllocZilsdOpt::MemOffset
151 switch (
MI.getOpcode()) {
155 const MachineOperand &BaseOp =
MI.getOperand(1);
156 const MachineOperand &
OffsetOp =
MI.getOperand(2);
161 return std::make_pair(MemoryOffsetKind::FrameIdx,
OffsetOp.getImm());
162 return std::make_pair(MemoryOffsetKind::Imm,
OffsetOp.getImm());
168 return std::make_pair(MemoryOffsetKind::Global,
OffsetOp.getOffset());
170 return std::make_pair(MemoryOffsetKind::CPI,
OffsetOp.getOffset());
172 return std::make_pair(MemoryOffsetKind::BlockAddr,
182 return std::make_pair(MemoryOffsetKind::Unknown, 0);
185bool RISCVPreAllocZilsdOpt::canFormLdSdPair(MachineInstr *MI0,
195 if (Offset1 - Offset0 != 4)
199 const MachineMemOperand *MMO = *MI0->memoperands_begin();
200 if (MMO->
getAlign() < RequiredAlign)
205 if (MI0->getOperand(0).getReg() == MI1->getOperand(0).getReg())
211bool RISCVPreAllocZilsdOpt::isSafeToMove(MachineInstr *
MI, MachineInstr *Target,
225 const MachineOperand &BaseOp =
MI->getOperand(1);
227 unsigned ScanCount = 0;
228 for (
auto It = Start; It !=
End; ++It, ++ScanCount) {
230 if (It->isCall() || It->isTerminator()) {
231 LLVM_DEBUG(
dbgs() <<
"Cannot move across call/terminator: " << *It);
236 if (It->hasUnmodeledSideEffects()) {
237 LLVM_DEBUG(
dbgs() <<
"Cannot move across instruction with side effects: "
243 if (BaseOp.
isReg() && It->modifiesRegister(BaseOp.
getReg(),
TRI)) {
245 <<
" modified by: " << *It);
251 (It->readsRegister(DefReg,
TRI) || It->modifiesRegister(DefReg,
TRI))) {
253 <<
" used by: " << *It);
258 if (
MI->mayStore() && It->modifiesRegister(DefReg,
TRI)) {
260 <<
" modified by: " << *It);
265 if (It->mayLoadOrStore() && It->mayAlias(AA, *
MI,
false)) {
274bool RISCVPreAllocZilsdOpt::rescheduleOps(
275 MachineBasicBlock *
MBB, SmallVectorImpl<MachineInstr *> &MIs,
276 BaseRegInfo
Base,
bool IsLoad,
277 DenseMap<MachineInstr *, unsigned> &MI2LocMap) {
281 return getMemoryOpOffset(*A).second < getMemoryOpOffset(*B).second;
287 for (
size_t i = 0; i + 1 < MIs.
size(); i++) {
288 MachineInstr *MI0 = MIs[i];
289 MachineInstr *MI1 = MIs[i + 1];
293 const MachineOperand &BaseOp = MI0->
getOperand(1);
296 "Base register should be register or frame index");
304 if (!canFormLdSdPair(MI0, MI1))
309 bool MI1IsLater = MI2LocMap[MI1] > MI2LocMap[MI0];
313 MachineInstr *MoveInstr, *TargetInstr;
316 MoveInstr = MI1IsLater ? MI1 : MI0;
317 TargetInstr = MI1IsLater ? MI0 : MI1;
320 MoveInstr = MI1IsLater ? MI0 : MI1;
321 TargetInstr = MI1IsLater ? MI1 : MI0;
324 unsigned Distance = MI1IsLater ? MI2LocMap[MI1] - MI2LocMap[MI0]
325 : MI2LocMap[MI0] - MI2LocMap[MI1];
327 Distance > STI->
getCLOpts().zilsd_max_reschedule_distance)
335 if (MoveInstr != TargetInstr)
339 MachineInstrBuilder MIB;
389bool RISCVPreAllocZilsdOpt::isMemoryOp(
const MachineInstr &
MI) {
390 unsigned Opcode =
MI.getOpcode();
391 if (Opcode != RISCV::LW && Opcode != RISCV::SW)
394 if (!
MI.getOperand(1).isReg() && !
MI.getOperand(1).isFI())
399 if (!
MI.hasOneMemOperand())
402 const MachineMemOperand *MMO = *
MI.memoperands_begin();
409 if (
MI.getOperand(0).isReg() &&
MI.getOperand(0).isUndef())
413 if (
MI.getOperand(1).isReg() &&
MI.getOperand(1).isUndef())
419bool RISCVPreAllocZilsdOpt::rescheduleLoadStoreInstrs(MachineBasicBlock *
MBB) {
429 DenseMap<MachineInstr *, unsigned> MI2LocMap;
432 using Base2InstMap = DenseMap<BaseRegInfo, SmallVector<MachineInstr *, 4>>;
434 Base2InstMap Base2LdsMap;
435 Base2InstMap Base2StsMap;
446 if (
MI.isCall() ||
MI.isTerminator()) {
453 if (!
MI.isDebugInstr())
454 MI2LocMap[&
MI] = ++Loc;
461 bool IsLd = (
MI.getOpcode() == RISCV::LW);
462 const MachineOperand &BaseOp =
MI.getOperand(1);
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();
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)
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.
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.
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
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.
const RISCVOptions & getCLOpts() const
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.
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.
@ 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.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.