39#define DEBUG_TYPE "riscv-load-store-opt"
40#define RISCV_LOAD_STORE_OPT_NAME "RISC-V Load / Store Optimizer"
42STATISTIC(NumLD2LW,
"Number of LD instructions split back to LW");
43STATISTIC(NumSD2SW,
"Number of SD instructions split back to SW");
53 MachineFunctionProperties getRequiredProperties()
const override {
54 return MachineFunctionProperties().setNoVRegs();
57 void getAnalysisUsage(AnalysisUsage &AU)
const override {
89 bool fixInvalidRegPairOp(MachineBasicBlock &
MBB,
92 void splitLdSdIntoTwo(MachineBasicBlock &
MBB,
97 MachineRegisterInfo *MRI;
98 const RISCVInstrInfo *TII;
99 const RISCVRegisterInfo *TRI;
100 const RISCVSubtarget *STI =
nullptr;
101 LiveRegUnits ModifiedRegUnits, UsedRegUnits;
105char RISCVLoadStoreOpt::ID = 0;
110 if (skipFunction(Fn.getFunction()))
113 bool MadeChange =
false;
115 TII = STI->getInstrInfo();
116 TRI = STI->getRegisterInfo();
117 MRI = &Fn.getRegInfo();
118 AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
119 ModifiedRegUnits.init(*
TRI);
120 UsedRegUnits.init(*
TRI);
122 if (STI->useMIPSLoadStorePairs() || STI->hasVendorXqcilsm()) {
123 for (MachineBasicBlock &MBB : Fn) {
124 LLVM_DEBUG(dbgs() <<
"MBB: " << MBB.getName() <<
"\n");
126 for (MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
128 if (TII->isPairableLdStInstOpc(MBBI->getOpcode()) &&
129 tryToPairLdStInst(MBBI))
137 if (!STI->is64Bit() && STI->hasStdExtZilsd()) {
138 for (auto &MBB : Fn) {
139 for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E;) {
140 if (fixInvalidRegPairOp(MBB, MBBI)) {
159 if (
MI.hasOrderedMemoryRef())
162 if (!
TII->isLdStSafeToPair(
MI,
TRI))
166 if (!STI->
is64Bit() && STI->hasVendorXqcilsm()) {
167 if (tryConvertToXqcilsmMultiLdSt(
MBBI))
176 MBBI = mergePairedInsns(
MBBI, Paired, MergeForward);
185 return MMOAlign >= RequiredAlignment;
192bool RISCVLoadStoreOpt::tryConvertToXqcilsmMultiLdSt(
194 MachineInstr &FirstMI = *FirstIt;
197 if (STI->
is64Bit() || !STI->hasVendorXqcilsm())
201 if (
Opc != RISCV::LW &&
Opc != RISCV::SW)
211 const MachineOperand &BaseOp = FirstMI.
getOperand(1);
212 const MachineOperand &OffOp = FirstMI.
getOperand(2);
217 int64_t BaseOff = OffOp.
getImm();
223 bool IsLoad = (
Opc == RISCV::LW);
227 if (StartReg == RISCV::X0)
229 if (StartReg ==
Base)
234 SmallVector<MachineInstr *, 8> Group;
239 int64_t ExpectedOff = BaseOff + 4;
241 enum class StoreMode {
Unknown, Setwmi, Swmi };
242 StoreMode SMode = StoreMode::Unknown;
245 MachineInstr &
MI = *It;
247 if (!
TII->isPairableLdStInstOpc(
MI.getOpcode()))
249 if (
MI.getOpcode() !=
Opc)
251 if (!
TII->isLdStSafeToPair(
MI,
TRI))
253 if (!
MI.hasOneMemOperand())
258 const MachineOperand &BaseMIOp =
MI.getOperand(1);
259 const MachineOperand &OffsetMIOp =
MI.getOperand(2);
265 if (
Off != ExpectedOff)
271 if (
Reg != StartReg + Index)
278 if (SMode == StoreMode::Unknown) {
280 SMode = StoreMode::Setwmi;
281 else if (
Reg == StartReg + 1)
282 SMode = StoreMode::Swmi;
285 }
else if (SMode == StoreMode::Setwmi) {
289 if (
Reg != StartReg + Index)
304 if (Len < 3 || Len > 31)
309 bool AddImplicitRegs =
true;
312 NewOpc = RISCV::QC_LWMI;
313 StartRegState = RegState::Define;
315 assert(SMode != StoreMode::Unknown &&
316 "Group should be large enough to know the store mode");
317 if (SMode == StoreMode::Setwmi) {
318 NewOpc = RISCV::QC_SETWMI;
320 bool StartKill =
false;
321 for (MachineInstr *
MI : Group)
322 StartKill |=
MI->getOperand(0).isKill();
324 AddImplicitRegs =
false;
327 if (StartReg == RISCV::X0)
329 NewOpc = RISCV::QC_SWMI;
330 StartRegState =
getKillRegState(Group.front()->getOperand(0).isKill());
335 bool BaseKill =
false;
336 for (MachineInstr *
MI : Group)
337 BaseKill |=
MI->getOperand(1).isKill();
343 MachineInstrBuilder MIB =
BuildMI(*MF,
DL,
TII->get(NewOpc));
344 MIB.
addReg(StartReg, StartRegState)
352 if (AddImplicitRegs) {
354 for (
unsigned i = 1; i <
Len; ++i) {
358 State = RegState::ImplicitDefine;
360 State = RegState::Implicit |
367 MachineBasicBlock *
MBB = FirstIt->getParent();
369 for (MachineInstr *
MI : Group)
370 MI->removeFromParent();
377bool RISCVLoadStoreOpt::tryConvertToXqcilsmLdStPair(
381 if ((
Opc != RISCV::LW &&
Opc != RISCV::SW) || Second->getOpcode() !=
Opc)
384 const auto &FirstOp1 =
First->getOperand(1);
385 const auto &SecondOp1 = Second->getOperand(1);
386 const auto &FirstOp2 =
First->getOperand(2);
387 const auto &SecondOp2 = Second->getOperand(2);
390 if (!FirstOp1.isReg() || !SecondOp1.isReg() || !FirstOp2.isImm() ||
395 Register Base2 = SecondOp1.getReg();
400 if (!
First->hasOneMemOperand() || !Second->hasOneMemOperand())
406 auto &FirstOp0 =
First->getOperand(0);
407 auto &SecondOp0 = Second->getOperand(0);
409 int64_t Off1 = FirstOp2.getImm();
410 int64_t Off2 = SecondOp2.getImm();
420 Register StartReg = FirstOp0.getReg();
421 Register NextReg = SecondOp0.getReg();
426 bool AddNextReg =
true;
428 if (
Opc == RISCV::LW) {
430 if (StartReg == RISCV::X0)
434 if (StartReg == Base1 || NextReg == Base1)
438 if (NextReg != StartReg + 1)
441 XqciOpc = RISCV::QC_LWMI;
442 StartRegState = RegState::Define;
443 NextRegState = RegState::ImplicitDefine;
445 assert(
Opc == RISCV::SW &&
"Expected a SW instruction");
446 if (StartReg == NextReg) {
447 XqciOpc = RISCV::QC_SETWMI;
448 StartRegState =
getKillRegState(FirstOp0.isKill() || SecondOp0.isKill());
450 }
else if (NextReg == StartReg + 1 && StartReg != RISCV::X0) {
451 XqciOpc = RISCV::QC_SWMI;
453 NextRegState = RegState::Implicit |
getKillRegState(SecondOp0.isKill());
460 First->getDebugLoc() ?
First->getDebugLoc() : Second->getDebugLoc();
461 MachineInstrBuilder MIB =
BuildMI(*MF,
DL,
TII->get(XqciOpc));
462 MIB.
addReg(StartReg, StartRegState)
469 MIB.
addReg(NextReg, NextRegState);
472 First->removeFromParent();
473 Second->removeFromParent();
478bool RISCVLoadStoreOpt::tryConvertToMIPSLdStPair(
484 Align RequiredAlignment;
485 switch (
First->getOpcode()) {
489 PairOpc = RISCV::MIPS_SWP;
490 RequiredAlignment =
Align(8);
493 PairOpc = RISCV::MIPS_LWP;
494 RequiredAlignment =
Align(8);
497 PairOpc = RISCV::MIPS_SDP;
498 RequiredAlignment =
Align(16);
501 PairOpc = RISCV::MIPS_LDP;
502 RequiredAlignment =
Align(16);
506 if (!
First->hasOneMemOperand())
516 MachineInstrBuilder MIB =
BuildMI(
517 *MF,
First->getDebugLoc() ?
First->getDebugLoc() : Second->getDebugLoc(),
520 .
add(Second->getOperand(0))
527 First->removeFromParent();
528 Second->removeFromParent();
538bool RISCVLoadStoreOpt::tryConvertToLdStPair(
543 if (!STI->
is64Bit() && STI->hasVendorXqcilsm())
544 return tryConvertToXqcilsmLdStPair(MF,
First, Second);
547 return tryConvertToMIPSLdStPair(MF,
First, Second);
568 bool &MergeForward) {
571 MachineInstr &FirstMI = *
I;
580 MergeForward =
false;
584 ModifiedRegUnits.
clear();
585 UsedRegUnits.
clear();
588 SmallVector<MachineInstr *, 4> MemInsns;
590 for (
unsigned Count = 0;
597 if (!
MI.isTransient())
602 Register MIBaseReg =
MI.getOperand(1).getReg();
603 int64_t MIOffset =
MI.getOperand(2).getImm();
605 if (BaseReg == MIBaseReg) {
606 if ((
Offset != MIOffset + OffsetStride) &&
607 (
Offset + OffsetStride != MIOffset)) {
617 TRI->isSuperOrSubRegisterEq(
Reg,
MI.getOperand(0).getReg())) {
625 if (!ModifiedRegUnits.
available(BaseReg))
632 if (ModifiedRegUnits.
available(
MI.getOperand(0).getReg()) &&
634 !UsedRegUnits.
available(
MI.getOperand(0).getReg())) &&
637 MergeForward =
false;
669 if (!ModifiedRegUnits.
available(BaseReg))
673 if (
MI.mayLoadOrStore())
699 int Offset =
I->getOperand(2).getImm();
700 int PairedOffset = Paired->getOperand(2).getImm();
701 bool InsertAfter = (
Offset < PairedOffset) ^ MergeForward;
704 Paired->getOperand(1).setIsKill(
false);
707 if (
I->getOperand(0).isUse()) {
711 MachineOperand &PairedRegOp = Paired->getOperand(0);
712 if (PairedRegOp.
isKill()) {
713 for (
auto It = std::next(
I); It != Paired; ++It) {
714 if (It->readsRegister(PairedRegOp.
getReg(),
TRI)) {
724 for (MachineInstr &
MI :
make_range(std::next(
I), std::next(Paired)))
733 MachineInstr *ToInsert = DeletionPoint->removeFromParent();
734 MachineBasicBlock &
MBB = *InsertionPoint->getParent();
739 Second = InsertionPoint;
743 First = InsertionPoint;
747 if (tryConvertToLdStPair(
First, Second)) {
750 }
else if (!STI->
is64Bit() && STI->hasVendorXqcilsm()) {
754 MachineInstr *MovedMI = Moved->removeFromParent();
773 if (
First == RISCV::X0)
774 return Second == RISCV::X0;
777 unsigned FirstNum =
TRI->getEncodingValue(
First);
778 unsigned SecondNum =
TRI->getEncodingValue(Second);
781 return (FirstNum % 2 == 0) && (SecondNum == FirstNum + 1);
784void RISCVLoadStoreOpt::splitLdSdIntoTwo(MachineBasicBlock &
MBB,
787 MachineInstr *
MI = &*
MBBI;
790 const MachineOperand &FirstOp =
MI->getOperand(0);
791 const MachineOperand &SecondOp =
MI->getOperand(1);
792 const MachineOperand &BaseOp =
MI->getOperand(2);
798 const MachineOperand &
OffsetOp =
MI->getOperand(3);
806 unsigned Opc = IsLoad ? RISCV::LW : RISCV::SW;
807 MachineInstrBuilder MIB1, MIB2;
820 if (FirstReg == BaseReg) {
842 FirstReg != SecondReg &&
843 "First register and second register is impossible to be same register");
859 MIB2.
addImm(BaseOffset + 4);
880bool RISCVLoadStoreOpt::fixInvalidRegPairOp(MachineBasicBlock &
MBB,
882 MachineInstr *
MI = &*
MBBI;
883 unsigned Opcode =
MI->getOpcode();
886 if (Opcode != RISCV::PseudoLD_RV32_OPT && Opcode != RISCV::PseudoSD_RV32_OPT)
889 bool IsLoad = Opcode == RISCV::PseudoLD_RV32_OPT;
891 const MachineOperand &FirstOp =
MI->getOperand(0);
892 const MachineOperand &SecondOp =
MI->getOperand(1);
896 if (!isValidZilsdRegPair(FirstReg, SecondReg)) {
898 splitLdSdIntoTwo(
MBB,
MBBI, IsLoad);
903 const MachineOperand &BaseOp =
MI->getOperand(2);
907 const MachineOperand &
OffsetOp =
MI->getOperand(3);
909 unsigned RealOpc = IsLoad ? RISCV::LD_RV32 : RISCV::SD_RV32;
912 MCRegister RegPair =
TRI->getMatchingSuperReg(FirstReg, RISCV::sub_gpr_even,
913 &RISCV::GPRPairRegClass);
929 LLVM_DEBUG(
dbgs() <<
"Converted pseudo to real instruction: " << *MIB
940 return new RISCVLoadStoreOpt();
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)
#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)
AnalysisUsage & addRequired()
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.
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.
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)
#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.
FunctionPass * createRISCVLoadStoreOptPass()
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
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.
constexpr RegState getDeadRegState(bool B)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
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.
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.