Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
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);
Copy link
Collaborator

Choose a reason for hiding this comment

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

getPhy doesn't return MCPhysReg. It returns MCRegister. There's currently an implicit conversion operator from MCRegister to unsigned, but it is supposed to be removed in the future.

Copy link
Member Author

Choose a reason for hiding this comment

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

then how do we know if the register is already allocated lol?

Copy link
Collaborator

@topperc topperc Oct 2, 2025

Choose a reason for hiding this comment

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

This isn't a question of allocated or not.

MCPhysReg is a typedef for uint16_t. MCRegister is a class. It contains an implicit conversion operation to unsigned that makes this assignment work, but that operator is supposed to be removed.

You should use MCRegister instead of MCPhysReg so you don't rely on the implicit conversion.

Once you cahnge ParterPhys to MCRegister, you should use ParterPhys.id() for the addition on line 869 to do an explicit conversion instead of an implicit conversion.

// 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))
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