Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
4bbf382
[llvm][RISCV] Implement Zilsd load/store pair optimization
4vtomat Sep 10, 2025
5722750
fixup! fix comments, move post-ra zilsd to RISCVLoadStoreOptimizer
4vtomat Sep 25, 2025
569a86c
Merge remote-tracking branch 'origin/main' into zilsd-optimizer
4vtomat Sep 25, 2025
ce8fc11
fixup! rename simm12 to simm12_lo
4vtomat Sep 25, 2025
2ff058f
fixup! negative test case, handle symbols
4vtomat Oct 7, 2025
a4cca81
Merge remote-tracking branch 'origin/main' into zilsd-optimizer
4vtomat Oct 8, 2025
294d83e
fixup! unused function
4vtomat Oct 13, 2025
14c0463
fixup! group memop kind, alignment, remove external symbol
4vtomat Oct 22, 2025
57c10b5
fixup! change MCPhysReg to MCRegister
4vtomat Oct 27, 2025
7c9b744
fixup! minor change
4vtomat Oct 30, 2025
90f3aa4
Merge remote-tracking branch 'origin/main' into zilsd-optimizer
4vtomat Nov 10, 2025
ed57a2c
fixup! clang format
4vtomat Nov 10, 2025
fff9d4b
fixup! fix prera alignment and simplify the code
4vtomat Nov 14, 2025
483104e
fixup! fix postra and simplify the code
4vtomat Nov 14, 2025
66d95f1
fixup! PseudoLD_RV32_OPT early clobber
4vtomat Nov 14, 2025
c4c4925
fixup! hint test
4vtomat Nov 14, 2025
7c377e3
fixup! dead/kill flag, alignment, remove early-clobber, required prop…
4vtomat Nov 20, 2025
fe67c22
fixup! clang-format
4vtomat Nov 20, 2025
696bad8
fixup! update test
4vtomat Nov 20, 2025
d79e21c
fixup! update test comments
4vtomat Nov 20, 2025
2a87065
fixup! update test comment
4vtomat Nov 20, 2025
44f5809
fixup! skip preserved register
4vtomat Nov 21, 2025
9453b78
fixup! add TODO
4vtomat Nov 21, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions llvm/lib/Target/RISCV/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ add_llvm_target(RISCVCodeGen
RISCVLandingPadSetup.cpp
RISCVLateBranchOpt.cpp
RISCVLoadStoreOptimizer.cpp
RISCVZilsdOptimizer.cpp
RISCVMachineFunctionInfo.cpp
RISCVMakeCompressible.cpp
RISCVMergeBaseOffset.cpp
Expand Down
6 changes: 6 additions & 0 deletions llvm/lib/Target/RISCV/RISCV.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,12 @@ void initializeRISCVPushPopOptPass(PassRegistry &);
FunctionPass *createRISCVLoadStoreOptPass();
void initializeRISCVLoadStoreOptPass(PassRegistry &);

FunctionPass *createRISCVPreAllocZilsdOptPass();
void initializeRISCVPreAllocZilsdOptPass(PassRegistry &);

FunctionPass *createRISCVPostAllocZilsdOptPass();
void initializeRISCVPostAllocZilsdOptPass(PassRegistry &);

FunctionPass *createRISCVZacasABIFixPass();
void initializeRISCVZacasABIFixPass(PassRegistry &);

Expand Down
5 changes: 5 additions & 0 deletions llvm/lib/Target/RISCV/RISCVFeatures.td
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,10 @@ def HasStdExtZilsd : Predicate<"Subtarget->hasStdExtZilsd()">,
AssemblerPredicate<(all_of FeatureStdExtZilsd),
"'Zilsd' (Load/Store pair instructions)">;

def TuneZilsd4ByteAlign
: SubtargetFeature<"zilsd-4byte-align", "AllowZilsd4ByteAlign", "true",
"Allow 4-byte alignment for Zilsd LD/SD instructions">;

// Multiply Extensions

def FeatureStdExtZmmul
Expand Down Expand Up @@ -1827,6 +1831,7 @@ def TunePreferVsetvliOverReadVLENB
"true",
"Prefer vsetvli over read vlenb CSR to calculate VLEN">;


// Assume that lock-free native-width atomics are available, even if the target
// and operating system combination would not usually provide them. The user
// is responsible for providing any necessary __sync implementations. Code
Expand Down
15 changes: 15 additions & 0 deletions llvm/lib/Target/RISCV/RISCVInstrInfoZilsd.td
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,21 @@ let Predicates = [HasStdExtZilsd, IsRV32] in {
def PseudoLD_RV32 : PseudoLoad<"ld", GPRPairRV32>;
def PseudoSD_RV32 : PseudoStore<"sd", GPRPairRV32>;

// Pseudo instructions for load/store optimization with 2 separate registers
def PseudoLD_RV32_OPT : Pseudo<(outs GPR:$rd1, GPR:$rd2), (ins GPR:$rs1, simm12:$imm12), [], "", ""> {
let hasSideEffects = 0;
let mayLoad = 1;
let mayStore = 0;
let isCodeGenOnly = 1;
}

def PseudoSD_RV32_OPT : Pseudo<(outs), (ins GPR:$rs1, GPR:$rs2, GPR:$rs3, simm12:$imm12), [], "", ""> {
let hasSideEffects = 0;
let mayLoad = 0;
let mayStore = 1;
let isCodeGenOnly = 1;
}

def : InstAlias<"ld $rd, (${rs1})", (LD_RV32 GPRPairRV32:$rd, GPR:$rs1, 0), 0>;
def : InstAlias<"sd $rs2, (${rs1})", (SD_RV32 GPRPairRV32:$rs2, GPR:$rs1, 0), 0>;
}
68 changes: 68 additions & 0 deletions llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -853,6 +853,44 @@ bool RISCVRegisterInfo::getRegAllocationHints(
const MachineRegisterInfo *MRI = &MF.getRegInfo();
auto &Subtarget = MF.getSubtarget<RISCVSubtarget>();

// Handle RegPairEven/RegPairOdd hints for Zilsd register pairs
std::pair<unsigned, Register> Hint = MRI->getRegAllocationHint(VirtReg);
unsigned HintType = Hint.first;
Register Partner = Hint.second;

if (HintType == RISCVRI::RegPairEven || HintType == RISCVRI::RegPairOdd) {
// Check if we want the even or odd register of a consecutive pair
bool WantOdd = (HintType == RISCVRI::RegPairOdd);

// First priority: Check if partner is already allocated
if (Partner.isVirtual() && VRM && VRM->hasPhys(Partner)) {
MCPhysReg PartnerPhys = VRM->getPhys(Partner);
// Calculate the exact register we need for consecutive pairing
MCPhysReg TargetReg = PartnerPhys + (WantOdd ? 1 : -1);

// Verify it's valid and available
if (RISCV::GPRRegClass.contains(TargetReg) &&
is_contained(Order, TargetReg)) {
Hints.push_back(TargetReg);
}
}

// Second priority: Try to find consecutive register pairs in the allocation
// order
for (MCPhysReg PhysReg : Order) {
if (!PhysReg)
continue;

unsigned RegNum = getEncodingValue(PhysReg);
// Check if this register matches the even/odd requirement
bool IsOdd = (RegNum % 2 != 0);

// Verify the pair register exists and is in the same register class
if ((WantOdd && IsOdd) || (!WantOdd && !IsOdd))
Copy link
Collaborator

@topperc topperc Nov 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we check reserved registers here like ARM so we don't hint X5 which can never pair with the reserved X4 register. We don't want to hint S1(X9) when S0(X8) is reserved for the frame pointer. And we don't want to hint X1, since X0 and X1 isn't a valid pair.

Users can also reserved registers from the command line.

We can fix this in a follow up.

Hints.push_back(PhysReg);
}
}

bool BaseImplRetVal = TargetRegisterInfo::getRegAllocationHints(
VirtReg, Order, Hints, MF, VRM, Matrix);

Expand Down Expand Up @@ -994,6 +1032,36 @@ bool RISCVRegisterInfo::getRegAllocationHints(
return BaseImplRetVal;
}

void RISCVRegisterInfo::updateRegAllocHint(Register Reg, Register NewReg,
MachineFunction &MF) const {
MachineRegisterInfo *MRI = &MF.getRegInfo();
std::pair<unsigned, Register> Hint = MRI->getRegAllocationHint(Reg);

// Handle RegPairEven/RegPairOdd hints for Zilsd register pairs
if ((Hint.first == RISCVRI::RegPairOdd ||
Hint.first == RISCVRI::RegPairEven) &&
Hint.second.isVirtual()) {
// If 'Reg' is one of the even/odd register pair and it's now changed
// (e.g. coalesced) into a different register, the other register of the
// pair allocation hint must be updated to reflect the relationship change.
Register Partner = Hint.second;
std::pair<unsigned, Register> PartnerHint =
MRI->getRegAllocationHint(Partner);

// Make sure partner still points to us
if (PartnerHint.second == Reg) {
// Update partner to point to NewReg instead of Reg
MRI->setRegAllocationHint(Partner, PartnerHint.first, NewReg);

// If NewReg is virtual, set up the reciprocal hint
// NewReg takes over Reg's role, so it gets the SAME hint type as Reg
if (NewReg.isVirtual()) {
MRI->setRegAllocationHint(NewReg, Hint.first, Partner);
}
}
}
}

Register
RISCVRegisterInfo::findVRegWithEncoding(const TargetRegisterClass &RegClass,
uint16_t Encoding) const {
Expand Down
10 changes: 10 additions & 0 deletions llvm/lib/Target/RISCV/RISCVRegisterInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ enum : uint8_t {
NFShiftMask = 0b111 << NFShift,
};

/// Register allocation hints for Zilsd register pairs
enum {
// Used for Zilsd LD/SD register pairs
RegPairOdd = 1,
RegPairEven = 2,
};

/// \returns the IsVRegClass for the register class.
static inline bool isVRegClass(uint8_t TSFlags) {
return (TSFlags & IsVRegClassShiftMask) >> IsVRegClassShift;
Expand Down Expand Up @@ -143,6 +150,9 @@ struct RISCVRegisterInfo : public RISCVGenRegisterInfo {
const MachineFunction &MF, const VirtRegMap *VRM,
const LiveRegMatrix *Matrix) const override;

void updateRegAllocHint(Register Reg, Register NewReg,
MachineFunction &MF) const override;

Register findVRegWithEncoding(const TargetRegisterClass &RegClass,
uint16_t Encoding) const;

Expand Down
8 changes: 8 additions & 0 deletions llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTarget() {
initializeRISCVPushPopOptPass(*PR);
initializeRISCVIndirectBranchTrackingPass(*PR);
initializeRISCVLoadStoreOptPass(*PR);
initializeRISCVPreAllocZilsdOptPass(*PR);
initializeRISCVPostAllocZilsdOptPass(*PR);
initializeRISCVExpandAtomicPseudoPass(*PR);
initializeRISCVRedundantCopyEliminationPass(*PR);
initializeRISCVAsmPrinterPass(*PR);
Expand Down Expand Up @@ -533,6 +535,10 @@ bool RISCVPassConfig::addGlobalInstructionSelect() {
void RISCVPassConfig::addPreSched2() {
addPass(createRISCVPostRAExpandPseudoPass());

// Add Zilsd post-allocation load/store optimization
if (TM->getOptLevel() != CodeGenOptLevel::None)
addPass(createRISCVPostAllocZilsdOptPass());

// Emit KCFI checks for indirect calls.
addPass(createKCFIPass());
if (TM->getOptLevel() != CodeGenOptLevel::None)
Expand Down Expand Up @@ -594,6 +600,8 @@ void RISCVPassConfig::addPreRegAlloc() {
if (TM->getOptLevel() != CodeGenOptLevel::None) {
addPass(createRISCVMergeBaseOffsetOptPass());
addPass(createRISCVVLOptimizerPass());
// Add Zilsd pre-allocation load/store optimization
addPass(createRISCVPreAllocZilsdOptPass());
}

addPass(createRISCVInsertReadWriteCSRPass());
Expand Down
Loading
Loading