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 auto &FirstOp0 =
First->getOperand(0);
418 auto &SecondOp0 = Second->getOperand(0);
420 int64_t Off1 = FirstOp2.getImm();
421 int64_t Off2 = SecondOp2.getImm();
431 Register StartReg = FirstOp0.getReg();
432 Register NextReg = SecondOp0.getReg();
437 bool AddNextReg =
true;
439 if (
Opc == RISCV::LW) {
441 if (StartReg == RISCV::X0)
445 if (StartReg == Base1 || NextReg == Base1)
449 if (NextReg != StartReg + 1)
452 XqciOpc = RISCV::QC_LWMI;
453 StartRegState = RegState::Define;
454 NextRegState = RegState::ImplicitDefine;
456 assert(
Opc == RISCV::SW &&
"Expected a SW instruction");
457 if (StartReg == NextReg) {
458 XqciOpc = RISCV::QC_SETWMI;
459 StartRegState =
getKillRegState(FirstOp0.isKill() || SecondOp0.isKill());
461 }
else if (NextReg == StartReg + 1 && StartReg != RISCV::X0) {
462 XqciOpc = RISCV::QC_SWMI;
464 NextRegState = RegState::Implicit |
getKillRegState(SecondOp0.isKill());
471 First->getDebugLoc() ?
First->getDebugLoc() : Second->getDebugLoc();
472 MachineInstrBuilder MIB =
BuildMI(*MF,
DL,
TII->get(XqciOpc));
473 MIB.
addReg(StartReg, StartRegState)
480 MIB.
addReg(NextReg, NextRegState);
483 First->removeFromParent();
484 Second->removeFromParent();
489bool RISCVLoadStoreOptImpl::tryConvertToMIPSLdStPair(
495 Align RequiredAlignment;
496 switch (
First->getOpcode()) {
500 PairOpc = RISCV::MIPS_SWP;
501 RequiredAlignment =
Align(8);
504 PairOpc = RISCV::MIPS_LWP;
505 RequiredAlignment =
Align(8);
508 PairOpc = RISCV::MIPS_SDP;
509 RequiredAlignment =
Align(16);
512 PairOpc = RISCV::MIPS_LDP;
513 RequiredAlignment =
Align(16);
517 if (!
First->hasOneMemOperand())
527 MachineInstrBuilder MIB =
BuildMI(
528 *MF,
First->getDebugLoc() ?
First->getDebugLoc() : Second->getDebugLoc(),
531 .
add(Second->getOperand(0))
538 First->removeFromParent();
539 Second->removeFromParent();
549bool RISCVLoadStoreOptImpl::tryConvertToLdStPair(
554 if (!STI->
is64Bit() && STI->hasVendorXqcilsm())
555 return tryConvertToXqcilsmLdStPair(MF,
First, Second);
558 return tryConvertToMIPSLdStPair(MF,
First, Second);
579 bool &MergeForward) {
582 MachineInstr &FirstMI = *
I;
591 MergeForward =
false;
595 ModifiedRegUnits.
clear();
596 UsedRegUnits.
clear();
599 SmallVector<MachineInstr *, 4> MemInsns;
601 for (
unsigned Count = 0;
608 if (!
MI.isTransient())
613 Register MIBaseReg =
MI.getOperand(1).getReg();
614 int64_t MIOffset =
MI.getOperand(2).getImm();
616 if (BaseReg == MIBaseReg) {
617 if ((
Offset != MIOffset + OffsetStride) &&
618 (
Offset + OffsetStride != MIOffset)) {
628 TRI->isSuperOrSubRegisterEq(
Reg,
MI.getOperand(0).getReg())) {
636 if (!ModifiedRegUnits.
available(BaseReg))
643 if (ModifiedRegUnits.
available(
MI.getOperand(0).getReg()) &&
645 !UsedRegUnits.
available(
MI.getOperand(0).getReg())) &&
648 MergeForward =
false;
680 if (!ModifiedRegUnits.
available(BaseReg))
684 if (
MI.mayLoadOrStore())
710 int Offset =
I->getOperand(2).getImm();
711 int PairedOffset = Paired->getOperand(2).getImm();
712 bool InsertAfter = (
Offset < PairedOffset) ^ MergeForward;
715 Paired->getOperand(1).setIsKill(
false);
718 if (
I->getOperand(0).isUse()) {
722 MachineOperand &PairedRegOp = Paired->getOperand(0);
723 if (PairedRegOp.
isKill()) {
724 for (
auto It = std::next(
I); It != Paired; ++It) {
725 if (It->readsRegister(PairedRegOp.
getReg(),
TRI)) {
735 for (MachineInstr &
MI :
make_range(std::next(
I), std::next(Paired)))
744 MachineInstr *ToInsert = DeletionPoint->removeFromParent();
745 MachineBasicBlock &
MBB = *InsertionPoint->getParent();
750 Second = InsertionPoint;
754 First = InsertionPoint;
758 if (tryConvertToLdStPair(
First, Second)) {
761 }
else if (!STI->
is64Bit() && STI->hasVendorXqcilsm()) {
765 MachineInstr *MovedMI = Moved->removeFromParent();
777bool RISCVLoadStoreOptImpl::isValidZilsdRegPair(
Register First,
785 if (
First == RISCV::X0)
786 return Second == RISCV::X0;
789 unsigned FirstNum =
TRI->getEncodingValue(
First);
790 unsigned SecondNum =
TRI->getEncodingValue(Second);
793 return (FirstNum % 2 == 0) && (SecondNum == FirstNum + 1);
796void RISCVLoadStoreOptImpl::splitLdSdIntoTwo(MachineBasicBlock &
MBB,
799 MachineInstr *
MI = &*
MBBI;
802 const MachineOperand &FirstOp =
MI->getOperand(0);
803 const MachineOperand &SecondOp =
MI->getOperand(1);
804 const MachineOperand &BaseOp =
MI->getOperand(2);
810 const MachineOperand &
OffsetOp =
MI->getOperand(3);
818 unsigned Opc = IsLoad ? RISCV::LW : RISCV::SW;
819 MachineInstrBuilder MIB1, MIB2;
832 if (FirstReg == BaseReg) {
854 FirstReg != SecondReg &&
855 "First register and second register is impossible to be same register");
871 MIB2.
addImm(BaseOffset + 4);
892bool RISCVLoadStoreOptImpl::fixInvalidRegPairOp(
894 MachineInstr *
MI = &*
MBBI;
895 unsigned Opcode =
MI->getOpcode();
898 if (Opcode != RISCV::PseudoLD_RV32_OPT && Opcode != RISCV::PseudoSD_RV32_OPT)
901 bool IsLoad = Opcode == RISCV::PseudoLD_RV32_OPT;
903 const MachineOperand &FirstOp =
MI->getOperand(0);
904 const MachineOperand &SecondOp =
MI->getOperand(1);
908 if (!isValidZilsdRegPair(FirstReg, SecondReg)) {
910 splitLdSdIntoTwo(
MBB,
MBBI, IsLoad);
915 const MachineOperand &BaseOp =
MI->getOperand(2);
919 const MachineOperand &
OffsetOp =
MI->getOperand(3);
921 unsigned RealOpc = IsLoad ? RISCV::LD_RV32 : RISCV::SD_RV32;
924 MCRegister RegPair =
TRI->getMatchingSuperReg(FirstReg, RISCV::sub_gpr_even,
925 &RISCV::GPRPairRegClass);
941 LLVM_DEBUG(
dbgs() <<
"Converted pseudo to real instruction: " << *MIB
952 return new RISCVLoadStoreOptLegacy();
955bool RISCVLoadStoreOptLegacy::runOnMachineFunction(
MachineFunction &MF) {
958 RISCVLoadStoreOptImpl Impl;
959 return Impl.runOnMachineFunction(MF, [&]() {
960 return &getAnalysis<AAResultsWrapperPass>().getAAResults();
967 RISCVLoadStoreOptImpl Impl;
968 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.
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.