39#define DEBUG_TYPE "riscv-load-store-opt"
40#define RISCV_LOAD_STORE_OPT_NAME "RISC-V Load / Store Optimizer"
46STATISTIC(NumLD2LW,
"Number of LD instructions split back to LW");
47STATISTIC(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 {
74 bool tryConvertToXqcilsmLdStPair(MachineFunction *MF,
78 bool tryConvertToMIPSLdStPair(MachineFunction *MF,
93 bool fixInvalidRegPairOp(MachineBasicBlock &
MBB,
96 void splitLdSdIntoTwo(MachineBasicBlock &
MBB,
101 MachineRegisterInfo *MRI;
102 const RISCVInstrInfo *TII;
103 const RISCVRegisterInfo *TRI;
104 const RISCVSubtarget *STI =
nullptr;
105 LiveRegUnits ModifiedRegUnits, UsedRegUnits;
109char RISCVLoadStoreOpt::ID = 0;
114 if (skipFunction(Fn.getFunction()))
117 bool MadeChange =
false;
119 TII = STI->getInstrInfo();
120 TRI = STI->getRegisterInfo();
121 MRI = &Fn.getRegInfo();
122 AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
123 ModifiedRegUnits.init(*
TRI);
124 UsedRegUnits.init(*
TRI);
126 if (STI->useMIPSLoadStorePairs() || STI->hasVendorXqcilsm()) {
127 for (MachineBasicBlock &MBB : Fn) {
128 LLVM_DEBUG(dbgs() <<
"MBB: " << MBB.getName() <<
"\n");
130 for (MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
132 if (TII->isPairableLdStInstOpc(MBBI->getOpcode()) &&
133 tryToPairLdStInst(MBBI))
141 if (!STI->is64Bit() && STI->hasStdExtZilsd()) {
142 for (auto &MBB : Fn) {
143 for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E;) {
144 if (fixInvalidRegPairOp(MBB, MBBI)) {
163 if (
MI.hasOrderedMemoryRef())
166 if (!
TII->isLdStSafeToPair(
MI,
TRI))
170 if (!STI->
is64Bit() && STI->hasVendorXqcilsm()) {
171 if (tryConvertToXqcilsmMultiLdSt(
MBBI))
180 MBBI = mergePairedInsns(
MBBI, Paired, MergeForward);
189 return MMOAlign >= RequiredAlignment;
196bool RISCVLoadStoreOpt::tryConvertToXqcilsmMultiLdSt(
198 MachineInstr &FirstMI = *FirstIt;
199 MachineFunction *MF = FirstMI.
getMF();
201 if (STI->
is64Bit() || !STI->hasVendorXqcilsm())
205 if (
Opc != RISCV::LW &&
Opc != RISCV::SW)
215 const MachineOperand &BaseOp = FirstMI.
getOperand(1);
216 const MachineOperand &OffOp = FirstMI.
getOperand(2);
221 int64_t BaseOff = OffOp.
getImm();
227 bool IsLoad = (
Opc == RISCV::LW);
231 if (StartReg == RISCV::X0)
233 if (StartReg ==
Base)
238 SmallVector<MachineInstr *, 8> Group;
243 int64_t ExpectedOff = BaseOff + 4;
245 enum class StoreMode {
Unknown, Setwmi, Swmi };
246 StoreMode SMode = StoreMode::Unknown;
249 MachineInstr &
MI = *It;
251 if (!
TII->isPairableLdStInstOpc(
MI.getOpcode()))
253 if (
MI.getOpcode() !=
Opc)
255 if (!
TII->isLdStSafeToPair(
MI,
TRI))
257 if (!
MI.hasOneMemOperand())
262 const MachineOperand &BaseMIOp =
MI.getOperand(1);
263 const MachineOperand &OffsetMIOp =
MI.getOperand(2);
269 if (Off != ExpectedOff)
275 if (
Reg != StartReg + Index)
282 if (SMode == StoreMode::Unknown) {
284 SMode = StoreMode::Setwmi;
285 else if (
Reg == StartReg + 1)
286 SMode = StoreMode::Swmi;
289 }
else if (SMode == StoreMode::Setwmi) {
293 if (
Reg != StartReg + Index)
308 if (Len < 3 || Len > 31)
312 unsigned StartRegState;
313 bool AddImplicitRegs =
true;
316 NewOpc = RISCV::QC_LWMI;
319 assert(SMode != StoreMode::Unknown &&
320 "Group should be large enough to know the store mode");
321 if (SMode == StoreMode::Setwmi) {
322 NewOpc = RISCV::QC_SETWMI;
324 bool StartKill =
false;
325 for (MachineInstr *
MI : Group)
326 StartKill |=
MI->getOperand(0).isKill();
328 AddImplicitRegs =
false;
331 if (StartReg == RISCV::X0)
333 NewOpc = RISCV::QC_SWMI;
334 StartRegState =
getKillRegState(Group.front()->getOperand(0).isKill());
339 bool BaseKill =
false;
340 for (MachineInstr *
MI : Group)
341 BaseKill |=
MI->getOperand(1).isKill();
347 MachineInstrBuilder MIB =
BuildMI(*MF,
DL,
TII->get(NewOpc));
348 MIB.
addReg(StartReg, StartRegState)
356 if (AddImplicitRegs) {
358 for (
unsigned i = 1; i <
Len; ++i) {
371 MachineBasicBlock *
MBB = FirstIt->getParent();
373 for (MachineInstr *
MI : Group)
374 MI->removeFromParent();
381bool RISCVLoadStoreOpt::tryConvertToXqcilsmLdStPair(
385 if ((
Opc != RISCV::LW &&
Opc != RISCV::SW) || Second->getOpcode() !=
Opc)
388 const auto &FirstOp1 =
First->getOperand(1);
389 const auto &SecondOp1 = Second->getOperand(1);
390 const auto &FirstOp2 =
First->getOperand(2);
391 const auto &SecondOp2 = Second->getOperand(2);
394 if (!FirstOp1.isReg() || !SecondOp1.isReg() || !FirstOp2.isImm() ||
399 Register Base2 = SecondOp1.getReg();
404 if (!
First->hasOneMemOperand() || !Second->hasOneMemOperand())
410 auto &FirstOp0 =
First->getOperand(0);
411 auto &SecondOp0 = Second->getOperand(0);
413 int64_t Off1 = FirstOp2.getImm();
414 int64_t Off2 = SecondOp2.getImm();
424 Register StartReg = FirstOp0.getReg();
425 Register NextReg = SecondOp0.getReg();
428 unsigned StartRegState;
429 unsigned NextRegState = 0;
430 bool AddNextReg =
true;
432 if (
Opc == RISCV::LW) {
434 if (StartReg == RISCV::X0)
438 if (StartReg == Base1 || NextReg == Base1)
442 if (NextReg != StartReg + 1)
445 XqciOpc = RISCV::QC_LWMI;
449 assert(
Opc == RISCV::SW &&
"Expected a SW instruction");
450 if (StartReg == NextReg) {
451 XqciOpc = RISCV::QC_SETWMI;
452 StartRegState =
getKillRegState(FirstOp0.isKill() || SecondOp0.isKill());
454 }
else if (NextReg == StartReg + 1 && StartReg != RISCV::X0) {
455 XqciOpc = RISCV::QC_SWMI;
464 First->getDebugLoc() ?
First->getDebugLoc() : Second->getDebugLoc();
465 MachineInstrBuilder MIB =
BuildMI(*MF,
DL,
TII->get(XqciOpc));
466 MIB.
addReg(StartReg, StartRegState)
473 MIB.
addReg(NextReg, NextRegState);
476 First->removeFromParent();
477 Second->removeFromParent();
482bool RISCVLoadStoreOpt::tryConvertToMIPSLdStPair(
488 Align RequiredAlignment;
489 switch (
First->getOpcode()) {
493 PairOpc = RISCV::MIPS_SWP;
494 RequiredAlignment =
Align(8);
497 PairOpc = RISCV::MIPS_LWP;
498 RequiredAlignment =
Align(8);
501 PairOpc = RISCV::MIPS_SDP;
502 RequiredAlignment =
Align(16);
505 PairOpc = RISCV::MIPS_LDP;
506 RequiredAlignment =
Align(16);
510 if (!
First->hasOneMemOperand())
520 MachineInstrBuilder MIB =
BuildMI(
521 *MF,
First->getDebugLoc() ?
First->getDebugLoc() : Second->getDebugLoc(),
524 .
add(Second->getOperand(0))
531 First->removeFromParent();
532 Second->removeFromParent();
542bool RISCVLoadStoreOpt::tryConvertToLdStPair(
544 MachineFunction *MF =
First->getMF();
547 if (!STI->
is64Bit() && STI->hasVendorXqcilsm())
548 return tryConvertToXqcilsmLdStPair(MF,
First, Second);
551 return tryConvertToMIPSLdStPair(MF,
First, Second);
572 bool &MergeForward) {
575 MachineInstr &FirstMI = *
I;
584 MergeForward =
false;
588 ModifiedRegUnits.
clear();
589 UsedRegUnits.
clear();
592 SmallVector<MachineInstr *, 4> MemInsns;
600 if (!
MI.isTransient())
605 Register MIBaseReg =
MI.getOperand(1).getReg();
606 int64_t MIOffset =
MI.getOperand(2).getImm();
608 if (BaseReg == MIBaseReg) {
609 if ((
Offset != MIOffset + OffsetStride) &&
610 (
Offset + OffsetStride != MIOffset)) {
620 TRI->isSuperOrSubRegisterEq(
Reg,
MI.getOperand(0).getReg())) {
628 if (!ModifiedRegUnits.
available(BaseReg))
635 if (ModifiedRegUnits.
available(
MI.getOperand(0).getReg()) &&
637 !UsedRegUnits.
available(
MI.getOperand(0).getReg())) &&
640 MergeForward =
false;
672 if (!ModifiedRegUnits.
available(BaseReg))
676 if (
MI.mayLoadOrStore())
702 int Offset =
I->getOperand(2).getImm();
703 int PairedOffset = Paired->getOperand(2).getImm();
704 bool InsertAfter = (
Offset < PairedOffset) ^ MergeForward;
707 Paired->getOperand(1).setIsKill(
false);
710 if (
I->getOperand(0).isUse()) {
714 MachineOperand &PairedRegOp = Paired->getOperand(0);
715 if (PairedRegOp.
isKill()) {
716 for (
auto It = std::next(
I); It != Paired; ++It) {
717 if (It->readsRegister(PairedRegOp.
getReg(),
TRI)) {
727 for (MachineInstr &
MI :
make_range(std::next(
I), std::next(Paired)))
732 MachineInstr *ToInsert = DeletionPoint->removeFromParent();
733 MachineBasicBlock &
MBB = *InsertionPoint->getParent();
738 Second = InsertionPoint;
741 First = InsertionPoint;
744 if (tryConvertToLdStPair(
First, Second)) {
747 }
else if (!STI->
is64Bit() && STI->hasVendorXqcilsm()) {
767 if (
First == RISCV::X0)
768 return Second == RISCV::X0;
771 unsigned FirstNum =
TRI->getEncodingValue(
First);
772 unsigned SecondNum =
TRI->getEncodingValue(Second);
775 return (FirstNum % 2 == 0) && (SecondNum == FirstNum + 1);
778void RISCVLoadStoreOpt::splitLdSdIntoTwo(MachineBasicBlock &
MBB,
781 MachineInstr *
MI = &*
MBBI;
784 const MachineOperand &FirstOp =
MI->getOperand(0);
785 const MachineOperand &SecondOp =
MI->getOperand(1);
786 const MachineOperand &BaseOp =
MI->getOperand(2);
792 const MachineOperand &
OffsetOp =
MI->getOperand(3);
800 unsigned Opc = IsLoad ? RISCV::LW : RISCV::SW;
801 MachineInstrBuilder MIB1, MIB2;
814 if (FirstReg == BaseReg) {
840 FirstReg != SecondReg &&
841 "First register and second register is impossible to be same register");
857 MIB2.
addImm(BaseOffset + 4);
878bool RISCVLoadStoreOpt::fixInvalidRegPairOp(MachineBasicBlock &
MBB,
880 MachineInstr *
MI = &*
MBBI;
881 unsigned Opcode =
MI->getOpcode();
884 if (Opcode != RISCV::PseudoLD_RV32_OPT && Opcode != RISCV::PseudoSD_RV32_OPT)
887 bool IsLoad = Opcode == RISCV::PseudoLD_RV32_OPT;
889 const MachineOperand &FirstOp =
MI->getOperand(0);
890 const MachineOperand &SecondOp =
MI->getOperand(1);
894 if (!isValidZilsdRegPair(FirstReg, SecondReg)) {
896 splitLdSdIntoTwo(
MBB,
MBBI, IsLoad);
901 const MachineOperand &BaseOp =
MI->getOperand(2);
905 const MachineOperand &
OffsetOp =
MI->getOperand(3);
907 unsigned RealOpc = IsLoad ? RISCV::LD_RV32 : RISCV::SD_RV32;
910 unsigned RegPair =
TRI->getMatchingSuperReg(FirstReg, RISCV::sub_gpr_even,
911 &RISCV::GPRPairRegClass);
928 LLVM_DEBUG(
dbgs() <<
"Converted pseudo to real instruction: " << *MIB
939 return new RISCVLoadStoreOpt();
unsigned const MachineRegisterInfo * MRI
static bool mayAlias(MachineInstr &MIa, SmallVectorImpl< MachineInstr * > &MemInsns, AliasAnalysis *AA)
static cl::opt< unsigned > LdStLimit("aarch64-load-store-scan-limit", cl::init(20), cl::Hidden)
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 cl::opt< unsigned > LdStLimit("riscv-load-store-scan-limit", cl::init(128), cl::Hidden)
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 & 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 & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register 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.
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.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ Implicit
Not emitted register (e.g. carry, or temporary result).
@ Define
Register definition.
initializer< Ty > init(const Ty &Val)
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.
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
unsigned getDeadRegState(bool B)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
FunctionAddr VTableAddr Count
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.
unsigned getKillRegState(bool B)
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.