6
6
//
7
7
// ===----------------------------------------------------------------------===//
8
8
//
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.
11
28
//
12
29
// ===----------------------------------------------------------------------===//
13
30
22
39
using namespace llvm ;
23
40
24
41
#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"
26
43
namespace {
27
44
28
45
struct RISCVLoadStoreOpt : public MachineFunctionPass {
@@ -66,6 +83,8 @@ struct RISCVLoadStoreOpt : public MachineFunctionPass {
66
83
const RISCVInstrInfo *TII;
67
84
const RISCVRegisterInfo *TRI;
68
85
LiveRegUnits ModifiedRegUnits, UsedRegUnits;
86
+ bool EnableLoadStorePairs = false ;
87
+ bool EnableLoadStoreBonding = false ;
69
88
};
70
89
} // end anonymous namespace
71
90
@@ -77,7 +96,9 @@ bool RISCVLoadStoreOpt::runOnMachineFunction(MachineFunction &Fn) {
77
96
if (skipFunction (Fn.getFunction ()))
78
97
return false ;
79
98
const RISCVSubtarget &Subtarget = Fn.getSubtarget <RISCVSubtarget>();
80
- if (!Subtarget.useLoadStorePairs ())
99
+ EnableLoadStorePairs = Subtarget.useLoadStorePairs ();
100
+ EnableLoadStoreBonding = Subtarget.useMIPSLoadStoreBonding ();
101
+ if (!EnableLoadStorePairs && !EnableLoadStoreBonding)
81
102
return false ;
82
103
83
104
bool MadeChange = false ;
@@ -107,12 +128,16 @@ bool RISCVLoadStoreOpt::runOnMachineFunction(MachineFunction &Fn) {
107
128
// instruction.
108
129
bool RISCVLoadStoreOpt::tryToPairLdStInst (MachineBasicBlock::iterator &MBBI) {
109
130
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 ;
111
135
112
136
if (!TII->isLdStSafeToPair (MI, TRI))
113
137
return false ;
114
138
115
139
// Look ahead for a pairable instruction.
140
+ MachineBasicBlock::iterator E = MI.getParent ()->end ();
116
141
bool MergeForward;
117
142
MachineBasicBlock::iterator Paired = findMatchingInsn (MBBI, MergeForward);
118
143
if (Paired != E) {
@@ -130,16 +155,16 @@ bool RISCVLoadStoreOpt::tryConvertToLdStPair(
130
155
default :
131
156
return false ;
132
157
case RISCV::SW:
133
- PairOpc = RISCV::SWP ;
158
+ PairOpc = RISCV::MIPS_SWP ;
134
159
break ;
135
160
case RISCV::LW:
136
- PairOpc = RISCV::LWP ;
161
+ PairOpc = RISCV::MIPS_LWP ;
137
162
break ;
138
163
case RISCV::SD:
139
- PairOpc = RISCV::SDP ;
164
+ PairOpc = RISCV::MIPS_SDP ;
140
165
break ;
141
166
case RISCV::LD:
142
- PairOpc = RISCV::LDP ;
167
+ PairOpc = RISCV::MIPS_LDP ;
143
168
break ;
144
169
}
145
170
@@ -201,8 +226,8 @@ RISCVLoadStoreOpt::findMatchingInsn(MachineBasicBlock::iterator I,
201
226
bool MayLoad = FirstMI.mayLoad ();
202
227
Register Reg = FirstMI.getOperand (0 ).getReg ();
203
228
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 ();
206
231
207
232
MergeForward = false ;
208
233
@@ -226,10 +251,9 @@ RISCVLoadStoreOpt::findMatchingInsn(MachineBasicBlock::iterator I,
226
251
if (MI.getOpcode () == FirstMI.getOpcode () &&
227
252
TII->isLdStSafeToPair (MI, TRI)) {
228
253
Register MIBaseReg = MI.getOperand (1 ).getReg ();
229
- int MIOffset = MI.getOperand (2 ).getImm ();
254
+ int64_t MIOffset = MI.getOperand (2 ).getImm ();
230
255
231
256
if (BaseReg == MIBaseReg) {
232
-
233
257
if ((Offset != MIOffset + OffsetStride) &&
234
258
(Offset + OffsetStride != MIOffset)) {
235
259
LiveRegUnits::accumulateUsedDefed (MI, ModifiedRegUnits, UsedRegUnits,
@@ -349,12 +373,21 @@ RISCVLoadStoreOpt::mergePairedInsns(MachineBasicBlock::iterator I,
349
373
First = InsertionPoint;
350
374
}
351
375
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) {
353
385
finalizeBundle (MBB, First.getInstrIterator (),
354
386
std::next (Second).getInstrIterator ());
387
+ LLVM_DEBUG (dbgs () << " Bonding load/store:\n " );
388
+ LLVM_DEBUG (prev_nodbg (NextI, MBB.begin ())->print (dbgs ()));
389
+ }
355
390
356
- LLVM_DEBUG (dbgs () << " Bonding pair load/store:\n " );
357
- LLVM_DEBUG (prev_nodbg (NextI, MBB.begin ())->print (dbgs ()));
358
391
return NextI;
359
392
}
360
393
0 commit comments