Skip to content

Commit 4bbf382

Browse files
committed
[llvm][RISCV] Implement Zilsd load/store pair optimization
This commit implements a complete load/store optimization pass for the RISC-V Zilsd extension, which combines pairs of 32-bit load/store instructions into single 64-bit LD/SD instructions when possible. Default alignment is 8, it also provide zilsd-4byte-align feature for looser condition.
1 parent 53a4e4a commit 4bbf382

12 files changed

+2165
-0
lines changed

llvm/lib/Target/RISCV/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ add_llvm_target(RISCVCodeGen
5252
RISCVLandingPadSetup.cpp
5353
RISCVLateBranchOpt.cpp
5454
RISCVLoadStoreOptimizer.cpp
55+
RISCVZilsdOptimizer.cpp
5556
RISCVMachineFunctionInfo.cpp
5657
RISCVMakeCompressible.cpp
5758
RISCVMergeBaseOffset.cpp

llvm/lib/Target/RISCV/RISCV.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,12 @@ void initializeRISCVPushPopOptPass(PassRegistry &);
9393
FunctionPass *createRISCVLoadStoreOptPass();
9494
void initializeRISCVLoadStoreOptPass(PassRegistry &);
9595

96+
FunctionPass *createRISCVPreAllocZilsdOptPass();
97+
void initializeRISCVPreAllocZilsdOptPass(PassRegistry &);
98+
99+
FunctionPass *createRISCVPostAllocZilsdOptPass();
100+
void initializeRISCVPostAllocZilsdOptPass(PassRegistry &);
101+
96102
FunctionPass *createRISCVZacasABIFixPass();
97103
void initializeRISCVZacasABIFixPass(PassRegistry &);
98104

llvm/lib/Target/RISCV/RISCVFeatures.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,10 @@ def HasStdExtZilsd : Predicate<"Subtarget->hasStdExtZilsd()">,
194194
AssemblerPredicate<(all_of FeatureStdExtZilsd),
195195
"'Zilsd' (Load/Store pair instructions)">;
196196

197+
def TuneZilsd4ByteAlign
198+
: SubtargetFeature<"zilsd-4byte-align", "AllowZilsd4ByteAlign", "true",
199+
"Allow 4-byte alignment for Zilsd LD/SD instructions">;
200+
197201
// Multiply Extensions
198202

199203
def FeatureStdExtZmmul
@@ -1827,6 +1831,7 @@ def TunePreferVsetvliOverReadVLENB
18271831
"true",
18281832
"Prefer vsetvli over read vlenb CSR to calculate VLEN">;
18291833

1834+
18301835
// Assume that lock-free native-width atomics are available, even if the target
18311836
// and operating system combination would not usually provide them. The user
18321837
// is responsible for providing any necessary __sync implementations. Code

llvm/lib/Target/RISCV/RISCVInstrInfoZilsd.td

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,21 @@ let Predicates = [HasStdExtZilsd, IsRV32] in {
4747
def PseudoLD_RV32 : PseudoLoad<"ld", GPRPairRV32>;
4848
def PseudoSD_RV32 : PseudoStore<"sd", GPRPairRV32>;
4949

50+
// Pseudo instructions for load/store optimization with 2 separate registers
51+
def PseudoLD_RV32_OPT : Pseudo<(outs GPR:$rd1, GPR:$rd2), (ins GPR:$rs1, simm12:$imm12), [], "", ""> {
52+
let hasSideEffects = 0;
53+
let mayLoad = 1;
54+
let mayStore = 0;
55+
let isCodeGenOnly = 1;
56+
}
57+
58+
def PseudoSD_RV32_OPT : Pseudo<(outs), (ins GPR:$rs1, GPR:$rs2, GPR:$rs3, simm12:$imm12), [], "", ""> {
59+
let hasSideEffects = 0;
60+
let mayLoad = 0;
61+
let mayStore = 1;
62+
let isCodeGenOnly = 1;
63+
}
64+
5065
def : InstAlias<"ld $rd, (${rs1})", (LD_RV32 GPRPairRV32:$rd, GPR:$rs1, 0), 0>;
5166
def : InstAlias<"sd $rs2, (${rs1})", (SD_RV32 GPRPairRV32:$rs2, GPR:$rs1, 0), 0>;
5267
}

llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -853,6 +853,44 @@ bool RISCVRegisterInfo::getRegAllocationHints(
853853
const MachineRegisterInfo *MRI = &MF.getRegInfo();
854854
auto &Subtarget = MF.getSubtarget<RISCVSubtarget>();
855855

856+
// Handle RegPairEven/RegPairOdd hints for Zilsd register pairs
857+
std::pair<unsigned, Register> Hint = MRI->getRegAllocationHint(VirtReg);
858+
unsigned HintType = Hint.first;
859+
Register Partner = Hint.second;
860+
861+
if (HintType == RISCVRI::RegPairEven || HintType == RISCVRI::RegPairOdd) {
862+
// Check if we want the even or odd register of a consecutive pair
863+
bool WantOdd = (HintType == RISCVRI::RegPairOdd);
864+
865+
// First priority: Check if partner is already allocated
866+
if (Partner.isVirtual() && VRM && VRM->hasPhys(Partner)) {
867+
MCPhysReg PartnerPhys = VRM->getPhys(Partner);
868+
// Calculate the exact register we need for consecutive pairing
869+
MCPhysReg TargetReg = PartnerPhys + (WantOdd ? 1 : -1);
870+
871+
// Verify it's valid and available
872+
if (RISCV::GPRRegClass.contains(TargetReg) &&
873+
is_contained(Order, TargetReg)) {
874+
Hints.push_back(TargetReg);
875+
}
876+
}
877+
878+
// Second priority: Try to find consecutive register pairs in the allocation
879+
// order
880+
for (MCPhysReg PhysReg : Order) {
881+
if (!PhysReg)
882+
continue;
883+
884+
unsigned RegNum = getEncodingValue(PhysReg);
885+
// Check if this register matches the even/odd requirement
886+
bool IsOdd = (RegNum % 2 != 0);
887+
888+
// Verify the pair register exists and is in the same register class
889+
if ((WantOdd && IsOdd) || (!WantOdd && !IsOdd))
890+
Hints.push_back(PhysReg);
891+
}
892+
}
893+
856894
bool BaseImplRetVal = TargetRegisterInfo::getRegAllocationHints(
857895
VirtReg, Order, Hints, MF, VRM, Matrix);
858896

@@ -994,6 +1032,36 @@ bool RISCVRegisterInfo::getRegAllocationHints(
9941032
return BaseImplRetVal;
9951033
}
9961034

1035+
void RISCVRegisterInfo::updateRegAllocHint(Register Reg, Register NewReg,
1036+
MachineFunction &MF) const {
1037+
MachineRegisterInfo *MRI = &MF.getRegInfo();
1038+
std::pair<unsigned, Register> Hint = MRI->getRegAllocationHint(Reg);
1039+
1040+
// Handle RegPairEven/RegPairOdd hints for Zilsd register pairs
1041+
if ((Hint.first == RISCVRI::RegPairOdd ||
1042+
Hint.first == RISCVRI::RegPairEven) &&
1043+
Hint.second.isVirtual()) {
1044+
// If 'Reg' is one of the even/odd register pair and it's now changed
1045+
// (e.g. coalesced) into a different register, the other register of the
1046+
// pair allocation hint must be updated to reflect the relationship change.
1047+
Register Partner = Hint.second;
1048+
std::pair<unsigned, Register> PartnerHint =
1049+
MRI->getRegAllocationHint(Partner);
1050+
1051+
// Make sure partner still points to us
1052+
if (PartnerHint.second == Reg) {
1053+
// Update partner to point to NewReg instead of Reg
1054+
MRI->setRegAllocationHint(Partner, PartnerHint.first, NewReg);
1055+
1056+
// If NewReg is virtual, set up the reciprocal hint
1057+
// NewReg takes over Reg's role, so it gets the SAME hint type as Reg
1058+
if (NewReg.isVirtual()) {
1059+
MRI->setRegAllocationHint(NewReg, Hint.first, Partner);
1060+
}
1061+
}
1062+
}
1063+
}
1064+
9971065
Register
9981066
RISCVRegisterInfo::findVRegWithEncoding(const TargetRegisterClass &RegClass,
9991067
uint16_t Encoding) const {

llvm/lib/Target/RISCV/RISCVRegisterInfo.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,13 @@ enum : uint8_t {
3737
NFShiftMask = 0b111 << NFShift,
3838
};
3939

40+
/// Register allocation hints for Zilsd register pairs
41+
enum {
42+
// Used for Zilsd LD/SD register pairs
43+
RegPairOdd = 1,
44+
RegPairEven = 2,
45+
};
46+
4047
/// \returns the IsVRegClass for the register class.
4148
static inline bool isVRegClass(uint8_t TSFlags) {
4249
return (TSFlags & IsVRegClassShiftMask) >> IsVRegClassShift;
@@ -143,6 +150,9 @@ struct RISCVRegisterInfo : public RISCVGenRegisterInfo {
143150
const MachineFunction &MF, const VirtRegMap *VRM,
144151
const LiveRegMatrix *Matrix) const override;
145152

153+
void updateRegAllocHint(Register Reg, Register NewReg,
154+
MachineFunction &MF) const override;
155+
146156
Register findVRegWithEncoding(const TargetRegisterClass &RegClass,
147157
uint16_t Encoding) const;
148158

llvm/lib/Target/RISCV/RISCVTargetMachine.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,8 @@ extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTarget() {
136136
initializeRISCVPushPopOptPass(*PR);
137137
initializeRISCVIndirectBranchTrackingPass(*PR);
138138
initializeRISCVLoadStoreOptPass(*PR);
139+
initializeRISCVPreAllocZilsdOptPass(*PR);
140+
initializeRISCVPostAllocZilsdOptPass(*PR);
139141
initializeRISCVExpandAtomicPseudoPass(*PR);
140142
initializeRISCVRedundantCopyEliminationPass(*PR);
141143
initializeRISCVAsmPrinterPass(*PR);
@@ -533,6 +535,10 @@ bool RISCVPassConfig::addGlobalInstructionSelect() {
533535
void RISCVPassConfig::addPreSched2() {
534536
addPass(createRISCVPostRAExpandPseudoPass());
535537

538+
// Add Zilsd post-allocation load/store optimization
539+
if (TM->getOptLevel() != CodeGenOptLevel::None)
540+
addPass(createRISCVPostAllocZilsdOptPass());
541+
536542
// Emit KCFI checks for indirect calls.
537543
addPass(createKCFIPass());
538544
if (TM->getOptLevel() != CodeGenOptLevel::None)
@@ -594,6 +600,8 @@ void RISCVPassConfig::addPreRegAlloc() {
594600
if (TM->getOptLevel() != CodeGenOptLevel::None) {
595601
addPass(createRISCVMergeBaseOffsetOptPass());
596602
addPass(createRISCVVLOptimizerPass());
603+
// Add Zilsd pre-allocation load/store optimization
604+
addPass(createRISCVPreAllocZilsdOptPass());
597605
}
598606

599607
addPass(createRISCVInsertReadWriteCSRPass());

0 commit comments

Comments
 (0)