42#define DEBUG_TYPE "riscv-load-store-opt"
43#define RISCV_LOAD_STORE_OPT_NAME "RISC-V Load / Store Optimizer"
45STATISTIC(NumLD2LW,
"Number of LD instructions split back to LW");
46STATISTIC(NumSD2SW,
"Number of SD instructions split back to SW");
57 MachineFunctionProperties getRequiredProperties()
const override {
58 return MachineFunctionProperties().setNoVRegs();
61 void getAnalysisUsage(AnalysisUsage &AU)
const override {
71class RISCVLoadStoreOptImpl {
97 bool fixInvalidRegPairOp(MachineBasicBlock &
MBB,
100 void splitLdSdIntoTwo(MachineBasicBlock &
MBB,
104 MachineRegisterInfo *MRI;
105 const RISCVInstrInfo *TII;
106 const RISCVRegisterInfo *TRI;
107 const RISCVSubtarget *STI =
nullptr;
108 LiveRegUnits ModifiedRegUnits, UsedRegUnits;
116char RISCVLoadStoreOptLegacy::ID = 0;
120bool RISCVLoadStoreOptImpl::runOnMachineFunction(
123 bool MadeChange =
false;
125 TII = STI->getInstrInfo();
126 TRI = STI->getRegisterInfo();
127 MRI = &MF.getRegInfo();
129 ModifiedRegUnits.init(*
TRI);
130 UsedRegUnits.init(*
TRI);
132 if (STI->useMIPSLoadStorePairs() || STI->hasVendorXqcilsm()) {
138 if (
TII->isPairableLdStInstOpc(
MBBI->getOpcode()) &&
139 tryToPairLdStInst(
MBBI))
147 if (!STI->is64Bit() && STI->hasStdExtZilsd()) {
148 for (
auto &
MBB : MF) {
150 if (fixInvalidRegPairOp(
MBB,
MBBI)) {
165bool RISCVLoadStoreOptImpl::tryToPairLdStInst(
170 if (
MI.hasOrderedMemoryRef())
173 if (!
TII->isLdStSafeToPair(
MI,
TRI))
177 if (!STI->
is64Bit() && STI->hasVendorXqcilsm()) {
178 if (tryConvertToXqcilsmMultiLdSt(
MBBI))
187 MBBI = mergePairedInsns(
MBBI, Paired, MergeForward);
196 return MMOAlign >= RequiredAlignment;
203bool RISCVLoadStoreOptImpl::tryConvertToXqcilsmMultiLdSt(
205 MachineInstr &FirstMI = *FirstIt;
208 if (STI->
is64Bit() || !STI->hasVendorXqcilsm())
212 if (
Opc != RISCV::LW &&
Opc != RISCV::SW)
222 const MachineOperand &BaseOp = FirstMI.
getOperand(1);
223 const MachineOperand &OffOp = FirstMI.
getOperand(2);
228 int64_t BaseOff = OffOp.
getImm();
234 bool IsLoad = (
Opc == RISCV::LW);
238 if (StartReg == RISCV::X0)
240 if (StartReg ==
Base)
245 SmallVector<MachineInstr *, 8> Group;
250 int64_t ExpectedOff = BaseOff + 4;
252 enum class StoreMode {
Unknown, Setwmi, Swmi };
253 StoreMode SMode = StoreMode::Unknown;
256 MachineInstr &
MI = *It;
258 if (!
TII->isPairableLdStInstOpc(
MI.getOpcode()))
260 if (
MI.getOpcode() !=
Opc)
262 if (!
TII->isLdStSafeToPair(
MI,
TRI))
264 if (!
MI.hasOneMemOperand())
269 const MachineOperand &BaseMIOp =
MI.getOperand(1);
270 const MachineOperand &OffsetMIOp =
MI.getOperand(2);
276 if (
Off != ExpectedOff)
282 if (
Reg != StartReg + Index)
289 if (SMode == StoreMode::Unknown) {
291 SMode = StoreMode::Setwmi;
292 else if (
Reg == StartReg + 1)
293 SMode = StoreMode::Swmi;
296 }
else if (SMode == StoreMode::Setwmi) {
300 if (
Reg != StartReg + Index)
315 if (Len < 3 || Len > 31)
320 bool AddImplicitRegs =
true;
323 NewOpc = RISCV::QC_LWMI;
324 StartRegState = RegState::Define;
326 assert(SMode != StoreMode::Unknown &&
327 "Group should be large enough to know the store mode");
328 if (SMode == StoreMode::Setwmi) {
329 NewOpc = RISCV::QC_SETWMI;
331 bool StartKill =
false;
332 for (MachineInstr *
MI : Group)
333 StartKill |=
MI->getOperand(0).isKill();
335 AddImplicitRegs =
false;
338 if (StartReg == RISCV::X0)
340 NewOpc = RISCV::QC_SWMI;
341 StartRegState =
getKillRegState(Group.front()->getOperand(0).isKill());
346 bool BaseKill =
false;
347 for (MachineInstr *
MI : Group)
348 BaseKill |=
MI->getOperand(1).isKill();
354 MachineInstrBuilder MIB =
BuildMI(*MF,
DL,
TII->get(NewOpc));
355 MIB.
addReg(StartReg, StartRegState)
363 if (AddImplicitRegs) {
365 for (
unsigned i = 1; i <
Len; ++i) {
369 State = RegState::ImplicitDefine;
371 State = RegState::Implicit |
378 MachineBasicBlock *
MBB = FirstIt->getParent();
380 for (MachineInstr *
MI : Group)
381 MI->removeFromParent();
388bool RISCVLoadStoreOptImpl::tryConvertToXqcilsmLdStPair(
392 if ((
Opc != RISCV::LW &&
Opc != RISCV::SW) || Second->getOpcode() !=
Opc)
395 const auto &FirstOp1 =
First->getOperand(1);
396 const auto &SecondOp1 = Second->getOperand(1);
397 const auto &FirstOp2 =
First->getOperand(2);
398 const auto &SecondOp2 = Second->getOperand(2);
401 if (!FirstOp1.isReg() || !SecondOp1.isReg() || !FirstOp2.isImm() ||
406 Register Base2 = SecondOp1.getReg();
411 if (!
First->hasOneMemOperand() || !Second->hasOneMemOperand())
417 const auto &FirstOp0 =
First->getOperand(0);
418 const auto &SecondOp0 = Second->getOperand(0);
420 int64_t Off1 = FirstOp2.getImm();
421 int64_t Off2 = SecondOp2.getImm();
422 assert(Off1 < Off2 &&
"Expected instructions to be ordered by offset");
427 Register StartReg = FirstOp0.getReg();
428 Register NextReg = SecondOp0.getReg();
433 bool AddNextReg =
true;
435 if (
Opc == RISCV::LW) {
437 if (StartReg == RISCV::X0)
441 if (StartReg == Base1 || NextReg == Base1)
445 if (NextReg != StartReg + 1)
448 XqciOpc = RISCV::QC_LWMI;
449 StartRegState = RegState::Define;
450 NextRegState = RegState::ImplicitDefine;
452 assert(
Opc == RISCV::SW &&
"Expected a SW instruction");
453 if (StartReg == NextReg) {
454 XqciOpc = RISCV::QC_SETWMI;
455 StartRegState =
getKillRegState(FirstOp0.isKill() || SecondOp0.isKill());
457 }
else if (NextReg == StartReg + 1 && StartReg != RISCV::X0) {
458 XqciOpc = RISCV::QC_SWMI;
460 NextRegState = RegState::Implicit |
getKillRegState(SecondOp0.isKill());
467 First->getDebugLoc() ?
First->getDebugLoc() : Second->getDebugLoc();
468 MachineInstrBuilder MIB =
BuildMI(*MF,
DL,
TII->get(XqciOpc));
469 MIB.
addReg(StartReg, StartRegState)
476 MIB.
addReg(NextReg, NextRegState);
479 First->removeFromParent();
480 Second->removeFromParent();
485bool RISCVLoadStoreOptImpl::tryConvertToMIPSLdStPair(
491 Align RequiredAlignment;
492 switch (
First->getOpcode()) {
496 PairOpc = RISCV::MIPS_SWP;
497 RequiredAlignment =
Align(8);
500 PairOpc = RISCV::MIPS_LWP;
501 RequiredAlignment =
Align(8);
504 PairOpc = RISCV::MIPS_SDP;
505 RequiredAlignment =
Align(16);
508 PairOpc = RISCV::MIPS_LDP;
509 RequiredAlignment =
Align(16);
513 if (!
First->hasOneMemOperand())
523 MachineInstrBuilder MIB =
BuildMI(
524 *MF,
First->getDebugLoc() ?
First->getDebugLoc() : Second->getDebugLoc(),
527 .
add(Second->getOperand(0))
534 First->removeFromParent();
535 Second->removeFromParent();
545bool RISCVLoadStoreOptImpl::tryConvertToLdStPair(
550 if (!STI->
is64Bit() && STI->hasVendorXqcilsm())
551 return tryConvertToXqcilsmLdStPair(MF,
First, Second);
554 return tryConvertToMIPSLdStPair(MF,
First, Second);
575 bool &MergeForward) {
578 MachineInstr &FirstMI = *
I;
587 MergeForward =
false;
591 ModifiedRegUnits.
clear();
592 UsedRegUnits.
clear();
595 SmallVector<MachineInstr *, 4> MemInsns;
597 for (
unsigned Count = 0;
604 if (!
MI.isTransient())
609 Register MIBaseReg =
MI.getOperand(1).getReg();
610 int64_t MIOffset =
MI.getOperand(2).getImm();
612 if (BaseReg == MIBaseReg) {
613 if ((
Offset != MIOffset + OffsetStride) &&
614 (
Offset + OffsetStride != MIOffset)) {
624 TRI->isSuperOrSubRegisterEq(
Reg,
MI.getOperand(0).getReg())) {
632 if (!ModifiedRegUnits.
available(BaseReg))
639 if (ModifiedRegUnits.
available(
MI.getOperand(0).getReg()) &&
641 !UsedRegUnits.
available(
MI.getOperand(0).getReg())) &&
644 MergeForward =
false;
676 if (!ModifiedRegUnits.
available(BaseReg))
680 if (
MI.mayLoadOrStore())
706 int Offset =
I->getOperand(2).getImm();
707 int PairedOffset = Paired->getOperand(2).getImm();
708 bool InsertAfter = (
Offset < PairedOffset) ^ MergeForward;
711 Paired->getOperand(1).setIsKill(
false);
714 if (
I->getOperand(0).isUse()) {
718 MachineOperand &PairedRegOp = Paired->getOperand(0);
719 if (PairedRegOp.
isKill()) {
720 for (
auto It = std::next(
I); It != Paired; ++It) {
721 if (It->readsRegister(PairedRegOp.
getReg(),
TRI)) {
731 for (MachineInstr &
MI :
make_range(std::next(
I), std::next(Paired)))
740 MachineInstr *ToInsert = DeletionPoint->removeFromParent();
741 MachineBasicBlock &
MBB = *InsertionPoint->getParent();
746 Second = InsertionPoint;
750 First = InsertionPoint;
754 if (tryConvertToLdStPair(
First, Second)) {
757 }
else if (!STI->
is64Bit() && STI->hasVendorXqcilsm()) {
761 MachineInstr *MovedMI = Moved->removeFromParent();
773bool RISCVLoadStoreOptImpl::isValidZilsdRegPair(
Register First,
781 if (
First == RISCV::X0)
782 return Second == RISCV::X0;
785 unsigned FirstNum =
TRI->getEncodingValue(
First);
786 unsigned SecondNum =
TRI->getEncodingValue(Second);
789 return (FirstNum % 2 == 0) && (SecondNum == FirstNum + 1);
792void RISCVLoadStoreOptImpl::splitLdSdIntoTwo(MachineBasicBlock &
MBB,
795 MachineInstr *
MI = &*
MBBI;
798 const MachineOperand &FirstOp =
MI->getOperand(0);
799 const MachineOperand &SecondOp =
MI->getOperand(1);
800 const MachineOperand &BaseOp =
MI->getOperand(2);
806 const MachineOperand &
OffsetOp =
MI->getOperand(3);
814 unsigned Opc = IsLoad ? RISCV::LW : RISCV::SW;
815 MachineInstrBuilder MIB1, MIB2;
828 if (FirstReg == BaseReg) {
850 FirstReg != SecondReg &&
851 "First register and second register is impossible to be same register");
867 MIB2.
addImm(BaseOffset + 4);
888bool RISCVLoadStoreOptImpl::fixInvalidRegPairOp(
890 MachineInstr *
MI = &*
MBBI;
891 unsigned Opcode =
MI->getOpcode();
894 if (Opcode != RISCV::PseudoLD_RV32_OPT && Opcode != RISCV::PseudoSD_RV32_OPT)
897 bool IsLoad = Opcode == RISCV::PseudoLD_RV32_OPT;
899 const MachineOperand &FirstOp =
MI->getOperand(0);
900 const MachineOperand &SecondOp =
MI->getOperand(1);
904 if (!isValidZilsdRegPair(FirstReg, SecondReg)) {
906 splitLdSdIntoTwo(
MBB,
MBBI, IsLoad);
911 const MachineOperand &BaseOp =
MI->getOperand(2);
915 const MachineOperand &
OffsetOp =
MI->getOperand(3);
917 unsigned RealOpc = IsLoad ? RISCV::LD_RV32 : RISCV::SD_RV32;
920 MCRegister RegPair =
TRI->getMatchingSuperReg(FirstReg, RISCV::sub_gpr_even,
921 &RISCV::GPRPairRegClass);
937 LLVM_DEBUG(
dbgs() <<
"Converted pseudo to real instruction: " << *MIB
948 return new RISCVLoadStoreOptLegacy();
951bool RISCVLoadStoreOptLegacy::runOnMachineFunction(
MachineFunction &MF) {
954 RISCVLoadStoreOptImpl Impl;
955 return Impl.runOnMachineFunction(MF, [&]() {
956 return &getAnalysis<AAResultsWrapperPass>().getAAResults();
963 RISCVLoadStoreOptImpl Impl;
964 bool Changed = Impl.runOnMachineFunction(MF, [&]() {
static bool mayAlias(MachineInstr &MIa, SmallVectorImpl< MachineInstr * > &MemInsns, AliasAnalysis *AA)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
MachineBasicBlock MachineBasicBlock::iterator MBBI
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
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(passName, arg, name, cfg, analysis)
MachineRegisterInfo & MRI
#define RISCV_LOAD_STORE_OPT_NAME
static bool isMemOpAligned(MachineInstr &MI, Align RequiredAlignment)
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 manager for alias analyses.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
AnalysisUsage & addRequired()
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
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.
static void accumulateUsedDefed(const MachineInstr &MI, LiveRegUnits &ModifiedRegUnits, LiveRegUnits &UsedRegUnits, const TargetRegisterInfo *TRI)
For a machine instruction MI, adds all register units used in UsedRegUnits and defined or clobbered i...
bool available(MCRegister Reg) const
Returns true if no part of physical register Reg is live.
void clear()
Clears the set.
LLVM_ABI instr_iterator insert(instr_iterator I, MachineInstr *M)
Insert MI into the instruction list before I, possibly inside a bundle.
LLVM_ABI instr_iterator erase(instr_iterator I)
Remove an instruction from the instruction list and delete it.
iterator insertAfter(iterator I, MachineInstr *MI)
Insert MI into the instruction list after I.
MachineInstrBundleIterator< MachineInstr > iterator
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 & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addBlockAddress(const BlockAddress *BA, int64_t Offset=0, unsigned TargetFlags=0) const
const MachineInstrBuilder & add(const MachineOperand &MO) const
const MachineInstrBuilder & addConstantPoolIndex(unsigned Idx, int Offset=0, unsigned TargetFlags=0) const
const MachineInstrBuilder & addGlobalAddress(const GlobalValue *GV, int64_t Offset=0, unsigned TargetFlags=0) const
const MachineInstrBuilder & addDef(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register definition operand.
const MachineInstrBuilder & cloneMemRefs(const MachineInstr &OtherMI) const
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineBasicBlock * getParent() const
LLVM_ABI bool mayAlias(BatchAAResults *AA, const MachineInstr &Other, bool UseTBAA) const
Returns true if this instruction's memory access aliases the memory access of Other.
bool mayLoad(QueryType Type=AnyInBundle) const
Return true if this instruction could possibly read memory.
bool hasOneMemOperand() const
Return true if this instruction has exactly one MachineMemOperand.
mmo_iterator memoperands_begin() const
Access to memory operands of the instruction.
LLVM_ABI const MachineFunction * getMF() const
Return the function that contains the basic block that this instruction belongs to.
const DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
const MachineOperand & getOperand(unsigned i) const
A description of a memory reference used in the backend.
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.
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
void setIsKill(bool Val=true)
Register getReg() const
getReg - Returns the register number.
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
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
An efficient, type-erasing, non-owning reference to a callable.
Pass manager infrastructure for declaring and invalidating analyses.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Abstract Attribute helper functions.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
BaseReg
Stack frame base register. Bit 0 of FREInfo.Info.
This is an optimization pass for GlobalISel generic memory operations.
IterT next_nodbg(IterT It, IterT End, bool SkipPseudoOp=true)
Increment It, then continue incrementing it while it points to a debug instruction.
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.
RegState
Flags to represent properties of register accesses.
constexpr RegState getKillRegState(bool B)
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
constexpr RegState getDeadRegState(bool B)
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
FunctionPass * createRISCVLoadStoreOptLegacyPass()
constexpr bool isUInt(uint64_t x)
Checks if an unsigned integer fits into the given bit width.
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Count
AAResults AliasAnalysis
Temporary typedef for legacy code that uses a generic AliasAnalysis pointer or reference.
IterT prev_nodbg(IterT It, IterT Begin, bool SkipPseudoOp=true)
Decrement It, then continue decrementing it while it points to a debug instruction.
constexpr bool isShiftedUInt(uint64_t x)
Checks if a unsigned integer is an N bit number shifted left by S.
This struct is a compact representation of a valid (non-zero power of two) alignment.