Skip to content

Commit 7e2c143

Browse files
committed
fixup: Address comments
It was not very obvious that bonding and pairing are two different things, so it is improved now. In addition, mentioned the AArch64 optimization and similarity with it.
1 parent 23f0f31 commit 7e2c143

File tree

6 files changed

+68
-23
lines changed

6 files changed

+68
-23
lines changed

llvm/lib/Target/RISCV/RISCVLoadStoreOptimizer.cpp

Lines changed: 49 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,25 @@
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

@@ -22,7 +39,7 @@
2239
using 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"
2643
namespace {
2744

2845
struct 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.
108129
bool 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

llvm/lib/Target/RISCV/RISCVSubtarget.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,15 @@ static cl::opt<unsigned> RISCVMinimumJumpTableEntries(
6262
"riscv-min-jump-table-entries", cl::Hidden,
6363
cl::desc("Set minimum number of entries to use a jump table on RISCV"));
6464

65+
static cl::opt<bool> UseMIPSLoadStorePairsOpt(
66+
"mips-riscv-load-store-pairs",
67+
cl::desc("RISCV: Enable the load/store pair optimization pass"),
68+
cl::init(false), cl::Hidden);
69+
6570
static cl::opt<bool>
66-
UseMIPSLoadStorePairsOpt("mips-riscv-load-store-pairs",
71+
UseMIPSLoadStoreBondingOpt("mips-riscv-load-store-bonding",
6772
cl::desc("RISCV: Optimize for load-store bonding"),
68-
cl::init(false), cl::Hidden);
73+
cl::init(true), cl::Hidden);
6974

7075
static cl::opt<bool>
7176
UseCCMovInsn("riscv-ccmov", cl::desc("RISCV: Use 'mips.ccmov' instruction"),
@@ -252,6 +257,10 @@ bool RISCVSubtarget::useLoadStorePairs() const {
252257
return UseMIPSLoadStorePairsOpt && HasVendorXMIPSLSP;
253258
}
254259

260+
bool RISCVSubtarget::useMIPSLoadStoreBonding() const {
261+
return UseMIPSLoadStoreBondingOpt && HasVendorXMIPSLSP;
262+
}
263+
255264
bool RISCVSubtarget::useCCMovInsn() const {
256265
return UseCCMovInsn && HasVendorXMIPSCMove;
257266
}

llvm/lib/Target/RISCV/RISCVSubtarget.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ class RISCVSubtarget : public RISCVGenSubtargetInfo {
189189
return is64Bit() ? 64 : 32;
190190
}
191191
bool useLoadStorePairs() const;
192+
bool useMIPSLoadStoreBonding() const;
192193
bool useCCMovInsn() const;
193194
unsigned getFLen() const {
194195
if (HasStdExtD)

llvm/lib/Target/RISCV/RISCVTargetMachine.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -312,11 +312,12 @@ ScheduleDAGInstrs *
312312
RISCVTargetMachine::createPostMachineScheduler(MachineSchedContext *C) const {
313313
ScheduleDAGMI *DAG = nullptr;
314314
const RISCVSubtarget &ST = C->MF->getSubtarget<RISCVSubtarget>();
315-
bool EnableLoadStoreClusteringForLoadStorePairOpt =
316-
!ST.getMacroFusions().empty() && ST.useLoadStorePairs();
315+
bool EnableLoadStoreClusteringForLoadStoreOpt =
316+
!ST.getMacroFusions().empty() &&
317+
(ST.useLoadStorePairs() || ST.useMIPSLoadStoreBonding());
317318

318319
if (EnablePostMISchedLoadStoreClustering ||
319-
EnableLoadStoreClusteringForLoadStorePairOpt) {
320+
EnableLoadStoreClusteringForLoadStoreOpt) {
320321
DAG = createGenericSchedPostRA(C);
321322
DAG->addMutation(createLoadClusterDAGMutation(
322323
DAG->TII, DAG->TRI, /*ReorderWhileClustering=*/true));
@@ -574,7 +575,7 @@ void RISCVPassConfig::addPreEmitPass() {
574575

575576
// LoadStoreOptimizer creates bundles for load-store bonding.
576577
addPass(createUnpackMachineBundles([](const MachineFunction &MF) {
577-
return MF.getSubtarget<RISCVSubtarget>().useLoadStorePairs();
578+
return MF.getSubtarget<RISCVSubtarget>().useMIPSLoadStoreBonding();
578579
}));
579580
}
580581

llvm/test/CodeGen/RISCV/O3-pipeline.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@
181181
; CHECK-NEXT: Post-RA pseudo instruction expansion pass
182182
; CHECK-NEXT: RISC-V post-regalloc pseudo instruction expansion pass
183183
; CHECK-NEXT: Insert KCFI indirect call checks
184-
; CHECK-NEXT: RISCV Load / Store Optimizer
184+
; CHECK-NEXT: RISC-V Load / Store Optimizer
185185
; CHECK-NEXT: MachineDominator Tree Construction
186186
; CHECK-NEXT: Machine Natural Loop Construction
187187
; CHECK-NEXT: PostRA Machine Instruction Scheduler

llvm/test/CodeGen/RISCV/load-store-pair.ll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2+
; testd and testf look for bonding only.
23
; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \
34
; RUN: | FileCheck %s -check-prefix=RV32I
45
; RUN: llc -mtriple=riscv32 -target-abi ilp32d -mattr=+d -verify-machineinstrs < %s \

0 commit comments

Comments
 (0)