66//
77// ===----------------------------------------------------------------------===//
88//
9- // Bundle loads and stores that operate on consecutive memory locations to take
10- // the advantage of hardware load/store bonding.
9+ // This pass implements two key optimizations for RISC-V memory accesses:
10+ // 1. Load/Store Pairing: It identifies pairs of load or store instructions
11+ // operating on consecutive memory locations and merges them into a single
12+ // paired instruction, taking advantage of hardware support for paired
13+ // accesses. Much of the pairing logic is adapted from the
14+ // AArch64LoadStoreOpt pass.
15+ // 2. Load/Store Bonding: When direct pairing cannot be applied, the pass
16+ // bonds related memory instructions together into a bundle. This preserves
17+ // their proximity and prevents reordering that might violate memory
18+ // semantics. This technique benefits certain targets (e.g. MIPS P8700) by
19+ // ensuring that paired or bonded memory operations remain contiguous.
20+ //
21+ // NOTE: The AArch64LoadStoreOpt pass performs additional optimizations such as
22+ // merging zero store instructions, promoting loads that read directly
23+ // from a preceding store, and merging base register updates with
24+ // load/store instructions (via pre-/post-indexed addressing). These
25+ // advanced transformations are not yet implemented in the RISC-V pass but
26+ // represent potential future enhancements, as similar benefits could be
27+ // achieved on RISC-V architectures.
1128//
1229// ===----------------------------------------------------------------------===//
1330
2239using namespace llvm ;
2340
2441#define DEBUG_TYPE " riscv-load-store-opt"
25- #define RISCV_LOAD_STORE_OPT_NAME " RISCV Load / Store Optimizer"
42+ #define RISCV_LOAD_STORE_OPT_NAME " RISC-V Load / Store Optimizer"
2643namespace {
2744
2845struct RISCVLoadStoreOpt : public MachineFunctionPass {
@@ -66,6 +83,8 @@ struct RISCVLoadStoreOpt : public MachineFunctionPass {
6683 const RISCVInstrInfo *TII;
6784 const RISCVRegisterInfo *TRI;
6885 LiveRegUnits ModifiedRegUnits, UsedRegUnits;
86+ bool EnableLoadStorePairs = false ;
87+ bool EnableLoadStoreBonding = false ;
6988};
7089} // end anonymous namespace
7190
@@ -77,7 +96,9 @@ bool RISCVLoadStoreOpt::runOnMachineFunction(MachineFunction &Fn) {
7796 if (skipFunction (Fn.getFunction ()))
7897 return false ;
7998 const RISCVSubtarget &Subtarget = Fn.getSubtarget <RISCVSubtarget>();
80- if (!Subtarget.useLoadStorePairs ())
99+ EnableLoadStorePairs = Subtarget.useLoadStorePairs ();
100+ EnableLoadStoreBonding = Subtarget.useMIPSLoadStoreBonding ();
101+ if (!EnableLoadStorePairs && !EnableLoadStoreBonding)
81102 return false ;
82103
83104 bool MadeChange = false ;
@@ -107,12 +128,16 @@ bool RISCVLoadStoreOpt::runOnMachineFunction(MachineFunction &Fn) {
107128// instruction.
108129bool RISCVLoadStoreOpt::tryToPairLdStInst (MachineBasicBlock::iterator &MBBI) {
109130 MachineInstr &MI = *MBBI;
110- MachineBasicBlock::iterator E = MI.getParent ()->end ();
131+
132+ // If this is volatile, it is not a candidate.
133+ if (MI.hasOrderedMemoryRef ())
134+ return false ;
111135
112136 if (!TII->isLdStSafeToPair (MI, TRI))
113137 return false ;
114138
115139 // Look ahead for a pairable instruction.
140+ MachineBasicBlock::iterator E = MI.getParent ()->end ();
116141 bool MergeForward;
117142 MachineBasicBlock::iterator Paired = findMatchingInsn (MBBI, MergeForward);
118143 if (Paired != E) {
@@ -130,16 +155,16 @@ bool RISCVLoadStoreOpt::tryConvertToLdStPair(
130155 default :
131156 return false ;
132157 case RISCV::SW:
133- PairOpc = RISCV::SWP ;
158+ PairOpc = RISCV::MIPS_SWP ;
134159 break ;
135160 case RISCV::LW:
136- PairOpc = RISCV::LWP ;
161+ PairOpc = RISCV::MIPS_LWP ;
137162 break ;
138163 case RISCV::SD:
139- PairOpc = RISCV::SDP ;
164+ PairOpc = RISCV::MIPS_SDP ;
140165 break ;
141166 case RISCV::LD:
142- PairOpc = RISCV::LDP ;
167+ PairOpc = RISCV::MIPS_LDP ;
143168 break ;
144169 }
145170
@@ -201,8 +226,8 @@ RISCVLoadStoreOpt::findMatchingInsn(MachineBasicBlock::iterator I,
201226 bool MayLoad = FirstMI.mayLoad ();
202227 Register Reg = FirstMI.getOperand (0 ).getReg ();
203228 Register BaseReg = FirstMI.getOperand (1 ).getReg ();
204- int Offset = FirstMI.getOperand (2 ).getImm ();
205- int OffsetStride = (*FirstMI.memoperands_begin ())->getSize ().getValue ();
229+ int64_t Offset = FirstMI.getOperand (2 ).getImm ();
230+ int64_t OffsetStride = (*FirstMI.memoperands_begin ())->getSize ().getValue ();
206231
207232 MergeForward = false ;
208233
@@ -226,10 +251,9 @@ RISCVLoadStoreOpt::findMatchingInsn(MachineBasicBlock::iterator I,
226251 if (MI.getOpcode () == FirstMI.getOpcode () &&
227252 TII->isLdStSafeToPair (MI, TRI)) {
228253 Register MIBaseReg = MI.getOperand (1 ).getReg ();
229- int MIOffset = MI.getOperand (2 ).getImm ();
254+ int64_t MIOffset = MI.getOperand (2 ).getImm ();
230255
231256 if (BaseReg == MIBaseReg) {
232-
233257 if ((Offset != MIOffset + OffsetStride) &&
234258 (Offset + OffsetStride != MIOffset)) {
235259 LiveRegUnits::accumulateUsedDefed (MI, ModifiedRegUnits, UsedRegUnits,
@@ -349,12 +373,21 @@ RISCVLoadStoreOpt::mergePairedInsns(MachineBasicBlock::iterator I,
349373 First = InsertionPoint;
350374 }
351375
352- if (!tryConvertToLdStPair (First, Second))
376+ // It may pair them or creaate bundles. The instructions may still be bundled
377+ // together, preserving their proximity and the intent of keeping related
378+ // memory accesses together. This bundling can help subsequent passes maintain
379+ // any implicit ordering or avoid reordering that might violate memory
380+ // semantics. For exmaple, MIPS P8700 benefits from it.
381+ if (EnableLoadStorePairs && tryConvertToLdStPair (First, Second)) {
382+ LLVM_DEBUG (dbgs () << " Pairing load/store:\n " );
383+ LLVM_DEBUG (prev_nodbg (NextI, MBB.begin ())->print (dbgs ()));
384+ } else if (EnableLoadStoreBonding) {
353385 finalizeBundle (MBB, First.getInstrIterator (),
354386 std::next (Second).getInstrIterator ());
387+ LLVM_DEBUG (dbgs () << " Bonding load/store:\n " );
388+ LLVM_DEBUG (prev_nodbg (NextI, MBB.begin ())->print (dbgs ()));
389+ }
355390
356- LLVM_DEBUG (dbgs () << " Bonding pair load/store:\n " );
357- LLVM_DEBUG (prev_nodbg (NextI, MBB.begin ())->print (dbgs ()));
358391 return NextI;
359392}
360393
0 commit comments