aboutsummaryrefslogtreecommitdiff
path: root/backend
diff options
context:
space:
mode:
authorRichard-Qin-X <richard.qin.001@gmail.com>2026-08-24 16:37:25 +0800
committerRichard-Qin-X <richard.qin.001@gmail.com>2026-08-24 16:37:25 +0800
commit540c73a2f450af3d0aec6e039fab054471efdbb1 (patch)
tree9b260322eaeeac8b8741a30a273f7d407b683e5e /backend
parent936ac5647f82def050e6654d44d24a88906f4d7a (diff)
downloadrcc-project-540c73a2f450af3d0aec6e039fab054471efdbb1.tar.gz
rcc-project-540c73a2f450af3d0aec6e039fab054471efdbb1.tar.xz
[RISCV] Match LLVM frame lowering semantics
Diffstat (limited to 'backend')
-rw-r--r--backend/include/rcc/Target/RISCV/RISCVSubtarget.h14
-rw-r--r--backend/lib/CodeGen/FrameIndexElimination.cpp22
-rw-r--r--backend/lib/CodeGen/MIRPrinter.cpp24
-rw-r--r--backend/lib/CodeGen/MachineVerifier.cpp1
-rw-r--r--backend/lib/CodeGen/PrologueEpilogueInsertion.cpp7
-rw-r--r--backend/lib/Target/RISCV/RISCV.h2
-rw-r--r--backend/lib/Target/RISCV/RISCVFrameLowering.cpp195
-rw-r--r--backend/lib/Target/RISCV/RISCVOptimizationPipeline.cpp2
-rw-r--r--backend/lib/Target/RISCV/RISCVPipeline.cpp4
-rw-r--r--backend/lib/Target/RISCV/RISCVSubtarget.cpp13
-rw-r--r--backend/lib/Tooling/MIRFuzzer.cpp5
-rw-r--r--backend/lib/Tooling/PipelineDriver.cpp16
-rw-r--r--backend/tools/MIRTool/MIRToolMain.cpp14
13 files changed, 164 insertions, 155 deletions
diff --git a/backend/include/rcc/Target/RISCV/RISCVSubtarget.h b/backend/include/rcc/Target/RISCV/RISCVSubtarget.h
index c8a4298..52b99af 100644
--- a/backend/include/rcc/Target/RISCV/RISCVSubtarget.h
+++ b/backend/include/rcc/Target/RISCV/RISCVSubtarget.h
@@ -71,6 +71,13 @@ enum class RISCVSubtargetOption : std::uint8_t {
Count,
};
+enum class RISCVABI : std::uint8_t {
+ LP64,
+ LP64D,
+};
+
+[[nodiscard]] Expected<RISCVABI> parseRISCVABI(std::string_view Name);
+
class RISCVSubtargetFeatures final {
public:
[[nodiscard]] static Expected<RISCVSubtargetFeatures>
@@ -97,7 +104,7 @@ class RISCVSubtarget final {
public:
explicit RISCVSubtarget(RISCVSubtargetFeatures Features,
RelocationModel Relocation = RelocationModel::Static,
- CodeModel Code = CodeModel::Small);
+ CodeModel Code = CodeModel::Small, RISCVABI ABI = RISCVABI::LP64D);
RISCVSubtarget(const RISCVSubtarget &) = delete;
RISCVSubtarget &operator=(const RISCVSubtarget &) = delete;
RISCVSubtarget(RISCVSubtarget &&) = delete;
@@ -116,6 +123,10 @@ public:
return Code;
}
+ [[nodiscard]] RISCVABI targetABI() const noexcept {
+ return ABI;
+ }
+
[[nodiscard]] const TargetCallLowering *getCallLowering() const;
[[nodiscard]] InstructionSelector *getInstructionSelector() const;
[[nodiscard]] const LegalizerInfo *getLegalizerInfo() const;
@@ -126,6 +137,7 @@ private:
RISCVSubtargetFeatures Features;
RelocationModel Relocation;
CodeModel Code;
+ RISCVABI ABI;
mutable std::unique_ptr<TargetCallLowering> CallLoweringInfo;
mutable std::unique_ptr<InstructionSelector> InstSelector;
mutable std::unique_ptr<LegalizerInfo> Legalizer;
diff --git a/backend/lib/CodeGen/FrameIndexElimination.cpp b/backend/lib/CodeGen/FrameIndexElimination.cpp
index 53c64e1..acc502d 100644
--- a/backend/lib/CodeGen/FrameIndexElimination.cpp
+++ b/backend/lib/CodeGen/FrameIndexElimination.cpp
@@ -5,13 +5,11 @@
#include "rcc/CodeGen/MachineBasicBlock.h"
#include "rcc/CodeGen/MachineFunction.h"
#include "rcc/CodeGen/MachineInstr.h"
-#include "rcc/CodeGen/MachineMemOperand.h"
#include "rcc/CodeGen/MachineOperand.h"
#include "rcc/CodeGen/RegisterScavenger.h"
#include "rcc/CodeGen/TargetFrameLowering.h"
#include <cstddef>
-#include <utility>
namespace rcc {
@@ -32,26 +30,6 @@ Expected<bool> eliminateFrameIndices(MachineFunction &Function, const TargetDesc
Changed = true;
}
- for (std::size_t Index = 0; Index < Instruction->memOperands().size(); ++Index) {
- const MachineMemOperand *Memory = Instruction->memOperands()[Index];
- const auto Frame = Memory->description().Base.frameIndex();
- if (!Frame)
- continue;
- auto Reference = FrameLowering.getFrameIndexReference(Function, *Instruction, *Frame,
- Memory->description().Offset);
- if (!Reference)
- return std::unexpected(Reference.error());
- MachineMemOperandDesc Description = Memory->description();
- Description.Base = MemoryBase::stack();
- Description.Offset = Reference->Offset;
- auto Replacement = Function.createMemOperand(std::move(Description));
- if (!Replacement)
- return std::unexpected(Replacement.error());
- auto Replaced = Instruction->replaceMemOperand(Index, **Replacement);
- if (!Replaced)
- return std::unexpected(Replaced.error());
- Changed = true;
- }
Instruction = Next;
}
}
diff --git a/backend/lib/CodeGen/MIRPrinter.cpp b/backend/lib/CodeGen/MIRPrinter.cpp
index c684368..4683a81 100644
--- a/backend/lib/CodeGen/MIRPrinter.cpp
+++ b/backend/lib/CodeGen/MIRPrinter.cpp
@@ -959,27 +959,9 @@ Expected<void> MIRDocumentPrinter::printStackObjects(const MachineFunction &Func
"stack object contains state not represented by fixed LLVM MIR");
}
- std::string_view Type;
- switch (Description->Kind) {
- case StackObjectKind::Default:
- case StackObjectKind::FixedABI:
- Type = "default";
- break;
- case StackObjectKind::FixedSpillSlot:
- case StackObjectKind::SpillSlot:
- Type = "spill-slot";
- break;
- case StackObjectKind::VariableSized:
- Type = "variable-sized";
- break;
- case StackObjectKind::DynamicAlloca:
- case StackObjectKind::CalleeSaved:
- case StackObjectKind::EmergencySpill:
- case StackObjectKind::Target:
- case StackObjectKind::Count:
- return makeUnexpected(ErrorCode::Unsupported,
- "stack object kind has no fixed LLVM MIR representation");
- }
+ const std::string_view Type = Object->isSpill() ? "spill-slot"
+ : Object->isVariableSized() ? "variable-sized"
+ : "default";
Output.append(" - { id: ");
Output.append(std::to_string(Slot.TextID));
diff --git a/backend/lib/CodeGen/MachineVerifier.cpp b/backend/lib/CodeGen/MachineVerifier.cpp
index abccc56..085d7ac 100644
--- a/backend/lib/CodeGen/MachineVerifier.cpp
+++ b/backend/lib/CodeGen/MachineVerifier.cpp
@@ -692,7 +692,6 @@ private:
for (const MachineMemOperand *MemOperand : Instruction.memOperands()) {
const MemoryBase &Base = MemOperand->description().Base;
if (const auto Frame = Base.frameIndex()) {
- HasFrameIndex = true;
auto FrameResult = verifyFrameIndex(*Frame);
if (!FrameResult)
return FrameResult;
diff --git a/backend/lib/CodeGen/PrologueEpilogueInsertion.cpp b/backend/lib/CodeGen/PrologueEpilogueInsertion.cpp
index 99f3b20..4dc40c0 100644
--- a/backend/lib/CodeGen/PrologueEpilogueInsertion.cpp
+++ b/backend/lib/CodeGen/PrologueEpilogueInsertion.cpp
@@ -3,7 +3,6 @@
#include "rcc/CodeGen/PrologueEpilogueInsertion.h"
#include "rcc/CodeGen/FrameIndexElimination.h"
-#include "rcc/CodeGen/LiveVariables.h"
#include "rcc/CodeGen/MachineBasicBlock.h"
#include "rcc/CodeGen/MachineFunction.h"
#include "rcc/CodeGen/MachineFunctionCloner.h"
@@ -142,12 +141,6 @@ PrologueEpilogueInsertionPass::runImplementation(MachineFunction &Function,
if (!FrameIndices)
return std::unexpected(FrameIndices.error());
- if (Function.properties().has(MachineFunctionProperty::TracksLiveness)) {
- auto Rebuilt = rebuildMachineLiveness(Function, Target);
- if (!Rebuilt)
- return std::unexpected(Rebuilt.error());
- }
-
MachinePassResult Result;
Result.Changed = true;
Result.Changes = {MachinePassChange::Instructions, MachinePassChange::Operands,
diff --git a/backend/lib/Target/RISCV/RISCV.h b/backend/lib/Target/RISCV/RISCV.h
index 4eeaf64..a2212d4 100644
--- a/backend/lib/Target/RISCV/RISCV.h
+++ b/backend/lib/Target/RISCV/RISCV.h
@@ -26,7 +26,7 @@ class RISCVSubtarget;
createRISCVInstructionSelector(const RISCVSubtarget &Subtarget,
const RISCVRegisterBankInfo &RegisterBanks);
[[nodiscard]] const TargetRegisterAllocationInfo &registerAllocationInfo() noexcept;
-[[nodiscard]] const TargetFrameLowering &frameLowering() noexcept;
+[[nodiscard]] const TargetFrameLowering &frameLowering(RISCVABI ABI = RISCVABI::LP64D) noexcept;
[[nodiscard]] std::unique_ptr<TargetSchedulingHooks>
createSchedulingHooks(const RISCVSubtargetFeatures &Features);
[[nodiscard]] Expected<TargetSchedulingModel>
diff --git a/backend/lib/Target/RISCV/RISCVFrameLowering.cpp b/backend/lib/Target/RISCV/RISCVFrameLowering.cpp
index 9e921f0..df30c50 100644
--- a/backend/lib/Target/RISCV/RISCVFrameLowering.cpp
+++ b/backend/lib/Target/RISCV/RISCVFrameLowering.cpp
@@ -311,22 +311,34 @@ struct CallFrameRequirement final {
return Function.frameInfo().setMaxCallFrameSize(Maximum);
}
-[[nodiscard]] std::array<PhysicalRegisterID, 25> saveOrder() noexcept {
- return {
- PhysicalRegisterID::X1, PhysicalRegisterID::X8, PhysicalRegisterID::X9,
- PhysicalRegisterID::X18, PhysicalRegisterID::X19, PhysicalRegisterID::X20,
- PhysicalRegisterID::X21, PhysicalRegisterID::X22, PhysicalRegisterID::X23,
- PhysicalRegisterID::X24, PhysicalRegisterID::X25, PhysicalRegisterID::X26,
- PhysicalRegisterID::X27, PhysicalRegisterID::F8_D, PhysicalRegisterID::F9_D,
- PhysicalRegisterID::F18_D, PhysicalRegisterID::F19_D, PhysicalRegisterID::F20_D,
- PhysicalRegisterID::F21_D, PhysicalRegisterID::F22_D, PhysicalRegisterID::F23_D,
- PhysicalRegisterID::F24_D, PhysicalRegisterID::F25_D, PhysicalRegisterID::F26_D,
- PhysicalRegisterID::F27_D,
- };
+constexpr std::array LP64SaveOrder{
+ PhysicalRegisterID::X1, PhysicalRegisterID::X8, PhysicalRegisterID::X9,
+ PhysicalRegisterID::X18, PhysicalRegisterID::X19, PhysicalRegisterID::X20,
+ PhysicalRegisterID::X21, PhysicalRegisterID::X22, PhysicalRegisterID::X23,
+ PhysicalRegisterID::X24, PhysicalRegisterID::X25, PhysicalRegisterID::X26,
+ PhysicalRegisterID::X27,
+};
+
+constexpr std::array LP64DSaveOrder{
+ PhysicalRegisterID::X1, PhysicalRegisterID::X8, PhysicalRegisterID::X9,
+ PhysicalRegisterID::X18, PhysicalRegisterID::X19, PhysicalRegisterID::X20,
+ PhysicalRegisterID::X21, PhysicalRegisterID::X22, PhysicalRegisterID::X23,
+ PhysicalRegisterID::X24, PhysicalRegisterID::X25, PhysicalRegisterID::X26,
+ PhysicalRegisterID::X27, PhysicalRegisterID::F8_D, PhysicalRegisterID::F9_D,
+ PhysicalRegisterID::F18_D, PhysicalRegisterID::F19_D, PhysicalRegisterID::F20_D,
+ PhysicalRegisterID::F21_D, PhysicalRegisterID::F22_D, PhysicalRegisterID::F23_D,
+ PhysicalRegisterID::F24_D, PhysicalRegisterID::F25_D, PhysicalRegisterID::F26_D,
+ PhysicalRegisterID::F27_D,
+};
+
+[[nodiscard]] std::span<const PhysicalRegisterID> saveOrder(RISCVABI ABI) noexcept {
+ return ABI == RISCVABI::LP64D ? std::span<const PhysicalRegisterID>(LP64DSaveOrder)
+ : std::span<const PhysicalRegisterID>(LP64SaveOrder);
}
[[nodiscard]] Expected<std::vector<PhysicalRegister>>
-modifiedCalleeSavedRegisters(const MachineFunction &Function, const TargetDescription &Target) {
+modifiedCalleeSavedRegisters(const MachineFunction &Function, const TargetDescription &Target,
+ RISCVABI ABI) {
std::unordered_set<PhysicalRegister> Modified;
for (const StackObject &Object : Function.frameInfo().objects()) {
if (!Object.isTombstone() && !Object.description()->IsDead &&
@@ -344,7 +356,7 @@ modifiedCalleeSavedRegisters(const MachineFunction &Function, const TargetDescri
return makeUnexpected(ErrorCode::VerificationError,
"RISC-V callee-save analysis found a null register mask");
}
- for (const PhysicalRegisterID ID : saveOrder()) {
+ for (const PhysicalRegisterID ID : saveOrder(ABI)) {
auto Reg = physicalRegister(ID);
if (!Reg)
return std::unexpected(Reg.error());
@@ -363,7 +375,7 @@ modifiedCalleeSavedRegisters(const MachineFunction &Function, const TargetDescri
}
std::vector<PhysicalRegister> Result;
- for (const PhysicalRegisterID ID : saveOrder()) {
+ for (const PhysicalRegisterID ID : saveOrder(ABI)) {
auto Reg = physicalRegister(ID);
if (!Reg)
return std::unexpected(Reg.error());
@@ -403,11 +415,13 @@ modifiedCalleeSavedRegisters(const MachineFunction &Function, const TargetDescri
createStackMemory(MachineFunction &Function, FrameIndex Index, MemoryAccessFlag Access) {
auto Size = MemorySize::fixed(8);
auto Align = Alignment::create(8);
- if (!Size || !Align)
+ auto Type = LowLevelType::makeCategoryNeutralScalar(64);
+ if (!Size || !Align || !Type)
return makeUnexpected(ErrorCode::InternalError, "RISC-V spill facts are invalid");
MachineMemOperandDesc Description;
Description.Accesses = {Access};
Description.Size = *Size;
+ Description.MemoryType = *Type;
Description.Align = *Align;
Description.Base = MemoryBase::frameIndex(Index);
return Function.createMemOperand(std::move(Description));
@@ -417,11 +431,13 @@ createStackMemory(MachineFunction &Function, FrameIndex Index, MemoryAccessFlag
createResolvedStackMemory(MachineFunction &Function, MemoryAccessFlag Access, std::int64_t Offset) {
auto Size = MemorySize::fixed(8);
auto Align = Alignment::create(8);
- if (!Size || !Align)
+ auto Type = LowLevelType::makeCategoryNeutralScalar(64);
+ if (!Size || !Align || !Type)
return makeUnexpected(ErrorCode::InternalError, "RISC-V spill facts are invalid");
MachineMemOperandDesc Description;
Description.Accesses = {Access};
Description.Size = *Size;
+ Description.MemoryType = *Type;
Description.Align = *Align;
Description.Base = MemoryBase::stack();
Description.Offset = Offset;
@@ -474,7 +490,8 @@ createResolvedStackMemory(MachineFunction &Function, MemoryAccessFlag Access, st
return DwarfRegisterNumber::fromValue(*Number);
}
-[[nodiscard]] Expected<void> emitCFI(MachineIRBuilder &Builder, MachineCFIInstruction Instruction) {
+[[nodiscard]] Expected<void> emitCFI(MachineIRBuilder &Builder, MachineCFIInstruction Instruction,
+ MachineInstrFlag Flag) {
auto Index = Builder.function().cfiInfo().addInstruction(std::move(Instruction));
if (!Index)
return std::unexpected(Index.error());
@@ -483,6 +500,8 @@ createResolvedStackMemory(MachineFunction &Function, MemoryAccessFlag Access, st
return std::unexpected(Pending.error());
if (auto Result = Pending->addCFIInstruction(*Index); !Result)
return std::unexpected(Result.error());
+ if (auto Result = setFrameFlag(*Pending, Flag); !Result)
+ return std::unexpected(Result.error());
auto Built = Pending->build();
if (!Built)
return std::unexpected(Built.error());
@@ -514,13 +533,13 @@ void appendSLEB128(std::vector<std::uint8_t> &Bytes, std::int64_t Value) {
[[nodiscard]] Expected<void>
emitSavedRegisterCFI(MachineIRBuilder &Builder, const TargetDescription &Target,
- PhysicalRegister Reg, std::int64_t Offset,
+ PhysicalRegister Reg, std::int64_t Offset, MachineInstrFlag Flag,
std::optional<PhysicalRegister> ExpressionBase = std::nullopt) {
auto DwarfReg = dwarfRegister(Target, Reg);
if (!DwarfReg)
return std::unexpected(DwarfReg.error());
if (!ExpressionBase)
- return emitCFI(Builder, MachineCFIInstruction::offset(*DwarfReg, Offset));
+ return emitCFI(Builder, MachineCFIInstruction::offset(*DwarfReg, Offset), Flag);
auto DwarfBase = dwarfRegister(Target, *ExpressionBase);
if (!DwarfBase)
@@ -541,24 +560,30 @@ emitSavedRegisterCFI(MachineIRBuilder &Builder, const TargetDescription &Target,
auto Rule = MachineCFIInstruction::escape(std::move(Escape));
if (!Rule)
return std::unexpected(Rule.error());
- return emitCFI(Builder, std::move(*Rule));
+ return emitCFI(Builder, std::move(*Rule), Flag);
}
[[nodiscard]] Expected<void> emitRestoreRegisterCFI(MachineIRBuilder &Builder,
const TargetDescription &Target,
- PhysicalRegister Reg) {
+ PhysicalRegister Reg, MachineInstrFlag Flag) {
auto DwarfReg = dwarfRegister(Target, Reg);
if (!DwarfReg)
return std::unexpected(DwarfReg.error());
- return emitCFI(Builder, MachineCFIInstruction::restore(*DwarfReg));
+ return emitCFI(Builder, MachineCFIInstruction::restore(*DwarfReg), Flag);
}
[[nodiscard]] Expected<void> emitDefCFI(MachineIRBuilder &Builder, const TargetDescription &Target,
- PhysicalRegister Reg, std::int64_t Offset) {
+ PhysicalRegister Reg, std::int64_t Offset,
+ MachineInstrFlag Flag) {
auto DwarfReg = dwarfRegister(Target, Reg);
if (!DwarfReg)
return std::unexpected(DwarfReg.error());
- return emitCFI(Builder, MachineCFIInstruction::defCFA(*DwarfReg, Offset));
+ return emitCFI(Builder, MachineCFIInstruction::defCFA(*DwarfReg, Offset), Flag);
+}
+
+[[nodiscard]] Expected<void> emitDefCFAOffset(MachineIRBuilder &Builder, std::int64_t Offset,
+ MachineInstrFlag Flag) {
+ return emitCFI(Builder, MachineCFIInstruction::defCFAOffset(Offset), Flag);
}
[[nodiscard]] Expected<void> emitConstant(MachineIRBuilder &Builder, PhysicalRegister Destination,
@@ -825,17 +850,17 @@ emitSavedRegisterCFI(MachineIRBuilder &Builder, const TargetDescription &Target,
if (!Aligned)
return std::unexpected(Aligned.error());
Cursor = *Aligned;
+ if (Description.Size.value_or(0) > std::numeric_limits<std::uint64_t>::max() - Cursor) {
+ return makeUnexpected(ErrorCode::FrameLayoutFailed, "RISC-V frame size overflows uint64");
+ }
+ Cursor += Description.Size.value_or(0);
if (Cursor > static_cast<std::uint64_t>(std::numeric_limits<std::int64_t>::max())) {
return makeUnexpected(ErrorCode::FrameLayoutFailed,
"RISC-V frame offset exceeds signed 64-bit range");
}
- auto Set = Frame.setObjectOffset(Object->index(), static_cast<std::int64_t>(Cursor));
+ auto Set = Frame.setObjectOffset(Object->index(), -static_cast<std::int64_t>(Cursor));
if (!Set)
return std::unexpected(Set.error());
- if (Description.Size.value_or(0) > std::numeric_limits<std::uint64_t>::max() - Cursor) {
- return makeUnexpected(ErrorCode::FrameLayoutFailed, "RISC-V frame size overflows uint64");
- }
- Cursor += Description.Size.value_or(0);
}
return {};
};
@@ -850,14 +875,18 @@ emitSavedRegisterCFI(MachineIRBuilder &Builder, const TargetDescription &Target,
for (const StackObject *Object : PreallocatedLocals) {
const std::uint64_t LocalOffset =
static_cast<std::uint64_t>(*Object->description()->LocalOffset);
- if (BlobStart > static_cast<std::uint64_t>(std::numeric_limits<std::int64_t>::max()) ||
- LocalOffset >
- static_cast<std::uint64_t>(std::numeric_limits<std::int64_t>::max()) - BlobStart) {
+ const std::uint64_t Size = Object->description()->Size.value_or(0);
+ if (BlobStart > std::numeric_limits<std::uint64_t>::max() - LocalOffset ||
+ BlobStart + LocalOffset > std::numeric_limits<std::uint64_t>::max() - Size) {
+ return makeUnexpected(ErrorCode::FrameLayoutFailed,
+ "RISC-V local frame offset overflows uint64");
+ }
+ const std::uint64_t End = BlobStart + LocalOffset + Size;
+ if (End > static_cast<std::uint64_t>(std::numeric_limits<std::int64_t>::max())) {
return makeUnexpected(ErrorCode::FrameLayoutFailed,
"RISC-V local frame offset exceeds int64");
}
- auto Set = Frame.setObjectOffset(Object->index(),
- static_cast<std::int64_t>(BlobStart + LocalOffset));
+ auto Set = Frame.setObjectOffset(Object->index(), -static_cast<std::int64_t>(End));
if (!Set)
return std::unexpected(Set.error());
}
@@ -939,15 +968,15 @@ emitSavedRegisterCFI(MachineIRBuilder &Builder, const TargetDescription &Target,
return std::unexpected(Added.error());
BaseOffset = *Added;
}
- } else if (!requiresStackRealignment(Function) && HasFP &&
- !Instruction.flags().has(MachineInstrFlag::FrameSetup)) {
+ } else if (!HasFP || requiresBasePointer(Function) ||
+ Instruction.flags().has(MachineInstrFlag::FrameSetup)) {
if (Function.frameInfo().state().StackSize >
static_cast<std::uint64_t>(std::numeric_limits<std::int64_t>::max())) {
return makeUnexpected(ErrorCode::FrameLayoutFailed,
"RISC-V stack size exceeds signed 64-bit range");
}
auto Added =
- checkedAdd(BaseOffset, -static_cast<std::int64_t>(Function.frameInfo().state().StackSize));
+ checkedAdd(BaseOffset, static_cast<std::int64_t>(Function.frameInfo().state().StackSize));
if (!Added)
return std::unexpected(Added.error());
BaseOffset = *Added;
@@ -963,17 +992,21 @@ emitSavedRegisterCFI(MachineIRBuilder &Builder, const TargetDescription &Target,
}
PhysicalRegisterID BaseID = PhysicalRegisterID::X2;
std::int64_t Offset = *Object.Offset;
+ bool UsesPostAllocationBase = true;
if (requiresBasePointer(Function)) {
BaseID = PhysicalRegisterID::X9;
} else if (requiresFramePointer(Function)) {
BaseID = PhysicalRegisterID::X8;
+ UsesPostAllocationBase = false;
+ }
+ if (UsesPostAllocationBase) {
if (Function.frameInfo().state().StackSize >
static_cast<std::uint64_t>(std::numeric_limits<std::int64_t>::max())) {
return makeUnexpected(ErrorCode::FrameLayoutFailed,
"RISC-V stack size exceeds signed 64-bit range");
}
auto Adjusted =
- checkedAdd(Offset, -static_cast<std::int64_t>(Function.frameInfo().state().StackSize));
+ checkedAdd(Offset, static_cast<std::int64_t>(Function.frameInfo().state().StackSize));
if (!Adjusted)
return std::unexpected(Adjusted.error());
Offset = *Adjusted;
@@ -1029,8 +1062,8 @@ emitCalleeSave(MachineIRBuilder &Builder, PhysicalRegister Reg, FrameIndex Index
return std::nullopt;
}
-[[nodiscard]] bool isABIStackSaveRegister(PhysicalRegister Reg) {
- return std::ranges::any_of(saveOrder(), [Reg](PhysicalRegisterID ID) {
+[[nodiscard]] bool isABIStackSaveRegister(PhysicalRegister Reg, RISCVABI ABI) {
+ return std::ranges::any_of(saveOrder(ABI), [Reg](PhysicalRegisterID ID) {
auto Candidate = physicalRegister(ID);
return Candidate && *Candidate == Reg;
});
@@ -1038,7 +1071,7 @@ emitCalleeSave(MachineIRBuilder &Builder, PhysicalRegister Reg, FrameIndex Index
[[nodiscard]] Expected<void>
validateCalleeSaveObjects(const MachineFunction &Function,
- std::span<const PhysicalRegister> SavedRegisters) {
+ std::span<const PhysicalRegister> SavedRegisters, RISCVABI ABI) {
std::unordered_set<PhysicalRegister> Slots;
for (const StackObject &Object : Function.frameInfo().objects()) {
if (Object.isTombstone() || Object.description()->IsDead ||
@@ -1047,7 +1080,7 @@ validateCalleeSaveObjects(const MachineFunction &Function,
}
const StackObjectDesc &Description = *Object.description();
const PhysicalRegister Reg = *Description.CalleeSavedRegister;
- if (!isABIStackSaveRegister(Reg)) {
+ if (!isABIStackSaveRegister(Reg, ABI)) {
return makeUnexpected(ErrorCode::VerificationError,
"RISC-V callee-save object names a caller-saved register");
}
@@ -1133,10 +1166,12 @@ calleeSaveOperations(MachineBasicBlock &Block, const MachineFunction &Function,
class RISCVFrameLowering final : public TargetFrameLowering {
public:
+ explicit RISCVFrameLowering(RISCVABI ABI) noexcept : ABI(ABI) {}
+
[[nodiscard]] bool
isCalleeSavedRegister(PhysicalRegister Reg, const MachineFunction &,
const TargetDescription &Target) const noexcept override {
- return std::ranges::any_of(saveOrder(), [&](PhysicalRegisterID ID) {
+ return std::ranges::any_of(saveOrder(ABI), [&](PhysicalRegisterID ID) {
const auto Candidate = physicalRegister(ID);
return Candidate && Target.registers().regsOverlap(Reg, *Candidate);
});
@@ -1174,10 +1209,10 @@ public:
if (!FrameRegisters)
return std::unexpected(FrameRegisters.error());
- auto SavedRegisters = modifiedCalleeSavedRegisters(Function, Target);
+ auto SavedRegisters = modifiedCalleeSavedRegisters(Function, Target, ABI);
if (!SavedRegisters)
return std::unexpected(SavedRegisters.error());
- auto ExistingSlots = validateCalleeSaveObjects(Function, *SavedRegisters);
+ auto ExistingSlots = validateCalleeSaveObjects(Function, *SavedRegisters, ABI);
if (!ExistingSlots)
return std::unexpected(ExistingSlots.error());
auto Align8 = Alignment::create(8);
@@ -1195,7 +1230,7 @@ public:
if (!Created)
return std::unexpected(Created.error());
}
- auto CompleteSlots = validateCalleeSaveObjects(Function, *SavedRegisters);
+ auto CompleteSlots = validateCalleeSaveObjects(Function, *SavedRegisters, ABI);
if (!CompleteSlots)
return std::unexpected(CompleteSlots.error());
@@ -1524,7 +1559,7 @@ public:
auto CaptureIncomingSP = emitAddImmediate(Builder, *FP, *SP, 0, MachineInstrFlag::FrameSetup);
if (!CaptureIncomingSP)
return std::unexpected(CaptureIncomingSP.error());
- auto CFA = emitDefCFI(Builder, Target, *FP, 0);
+ auto CFA = emitDefCFI(Builder, Target, *FP, 0, MachineInstrFlag::FrameSetup);
if (!CFA)
return std::unexpected(CFA.error());
}
@@ -1549,7 +1584,8 @@ public:
return std::unexpected(Adjust.error());
}
if (!Realign) {
- auto CFA = emitDefCFI(Builder, Target, *SP, static_cast<std::int64_t>(StackSize));
+ auto CFA = emitDefCFAOffset(Builder, static_cast<std::int64_t>(StackSize),
+ MachineInstrFlag::FrameSetup);
if (!CFA)
return std::unexpected(CFA.error());
}
@@ -1588,8 +1624,8 @@ public:
return makeUnexpected(ErrorCode::InternalError,
"RISC-V realigned CFI slot is incomplete");
}
- auto CFI =
- emitSavedRegisterCFI(AfterSaves, Target, Reg, *Object->description()->Offset, *BP);
+ auto CFI = emitSavedRegisterCFI(AfterSaves, Target, Reg, *Object->description()->Offset,
+ MachineInstrFlag::FrameSetup, *BP);
if (!CFI)
return std::unexpected(CFI.error());
}
@@ -1604,15 +1640,12 @@ public:
return makeUnexpected(ErrorCode::InternalError,
"RISC-V callee-save CFI slot is incomplete");
}
- auto Offset =
- checkedAdd(*Object->description()->Offset, -static_cast<std::int64_t>(StackSize));
- if (!Offset)
- return std::unexpected(Offset.error());
MachineIRBuilder AfterSave(Function, Target);
auto PointAfterSave = AfterSave.setInsertPointAfter(*Save.Instruction);
if (!PointAfterSave)
return std::unexpected(PointAfterSave.error());
- auto CFI = emitSavedRegisterCFI(AfterSave, Target, Save.Reg, *Offset);
+ auto CFI = emitSavedRegisterCFI(AfterSave, Target, Save.Reg, *Object->description()->Offset,
+ MachineInstrFlag::FrameSetup);
if (!CFI)
return std::unexpected(CFI.error());
if (Index + 1U != Saves.size() || !requiresFramePointer(Function))
@@ -1630,7 +1663,7 @@ public:
if (!Set)
return std::unexpected(Set.error());
}
- auto CFA = emitDefCFI(AfterSave, Target, *FP, 0);
+ auto CFA = emitDefCFI(AfterSave, Target, *FP, 0, MachineInstrFlag::FrameSetup);
if (!CFA)
return std::unexpected(CFA.error());
}
@@ -1648,7 +1681,7 @@ public:
if (!Set)
return std::unexpected(Set.error());
}
- auto CFA = emitDefCFI(Builder, Target, *FP, 0);
+ auto CFA = emitDefCFI(Builder, Target, *FP, 0, MachineInstrFlag::FrameSetup);
if (!CFA)
return std::unexpected(CFA.error());
}
@@ -1678,7 +1711,6 @@ public:
const bool HasFP = requiresFramePointer(Function);
const bool Realign = requiresStackRealignment(Function);
const std::uint64_t StackSize = Function.frameInfo().state().StackSize;
- const bool HasFrameCFI = StackSize != 0 || !Function.records().calleeSavedRegisters().empty();
const std::vector<CalleeSaveOperation> BlockRestores =
calleeSaveOperations(Block, Function, true);
@@ -1700,18 +1732,6 @@ public:
"RISC-V epilogue has an incomplete callee-restore sequence");
}
- if (HasFrameCFI) {
- MachineIRBuilder RememberBuilder(Function, Target);
- auto Point = Restores.empty()
- ? RememberBuilder.setInsertPointBefore(Terminator)
- : RememberBuilder.setInsertPointBefore(*Restores.front().Instruction);
- if (!Point)
- return std::unexpected(Point.error());
- auto Remember = emitCFI(RememberBuilder, MachineCFIInstruction::rememberState());
- if (!Remember)
- return std::unexpected(Remember.error());
- }
-
for (const CalleeSaveOperation &Restore : Restores) {
if ((HasFP && Restore.Reg == *FP) || (Realign && Restore.Reg == *BP))
continue;
@@ -1719,7 +1739,8 @@ public:
auto Point = AfterRestore.setInsertPointAfter(*Restore.Instruction);
if (!Point)
return std::unexpected(Point.error());
- auto CFI = emitRestoreRegisterCFI(AfterRestore, Target, Restore.Reg);
+ auto CFI =
+ emitRestoreRegisterCFI(AfterRestore, Target, Restore.Reg, MachineInstrFlag::FrameDestroy);
if (!CFI)
return std::unexpected(CFI.error());
}
@@ -1738,7 +1759,7 @@ public:
auto RestoreSP = emitAddImmediate(Teardown, *SP, *FP, 0, MachineInstrFlag::FrameDestroy);
if (!RestoreSP)
return std::unexpected(RestoreSP.error());
- auto CFA = emitDefCFI(Teardown, Target, *SP, 0);
+ auto CFA = emitDefCFI(Teardown, Target, *SP, 0, MachineInstrFlag::FrameDestroy);
if (!CFA)
return std::unexpected(CFA.error());
if (FPRestore != Restores.end()) {
@@ -1746,7 +1767,7 @@ public:
auto After = AfterFP.setInsertPointAfter(*FPRestore->Instruction);
if (!After)
return std::unexpected(After.error());
- auto FPCFI = emitRestoreRegisterCFI(AfterFP, Target, *FP);
+ auto FPCFI = emitRestoreRegisterCFI(AfterFP, Target, *FP, MachineInstrFlag::FrameDestroy);
if (!FPCFI)
return std::unexpected(FPCFI.error());
}
@@ -1755,7 +1776,7 @@ public:
auto After = AfterBP.setInsertPointAfter(*BPRestore->Instruction);
if (!After)
return std::unexpected(After.error());
- auto BPCFI = emitRestoreRegisterCFI(AfterBP, Target, *BP);
+ auto BPCFI = emitRestoreRegisterCFI(AfterBP, Target, *BP, MachineInstrFlag::FrameDestroy);
if (!BPCFI)
return std::unexpected(BPCFI.error());
}
@@ -1770,7 +1791,7 @@ public:
auto RestoreSP = emitAddImmediate(Teardown, *SP, *FP, 0, MachineInstrFlag::FrameDestroy);
if (!RestoreSP)
return std::unexpected(RestoreSP.error());
- auto CFA = emitDefCFI(Teardown, Target, *SP, 0);
+ auto CFA = emitDefCFI(Teardown, Target, *SP, 0, MachineInstrFlag::FrameDestroy);
if (!CFA)
return std::unexpected(CFA.error());
if (FPRestore != Restores.end()) {
@@ -1778,7 +1799,7 @@ public:
auto After = AfterFP.setInsertPointAfter(*FPRestore->Instruction);
if (!After)
return std::unexpected(After.error());
- auto FPCFI = emitRestoreRegisterCFI(AfterFP, Target, *FP);
+ auto FPCFI = emitRestoreRegisterCFI(AfterFP, Target, *FP, MachineInstrFlag::FrameDestroy);
if (!FPCFI)
return std::unexpected(FPCFI.error());
}
@@ -1816,19 +1837,10 @@ public:
if (!Adjust)
return std::unexpected(Adjust.error());
}
- auto CFA = emitDefCFI(Teardown, Target, *SP, 0);
+ auto CFA = emitDefCFAOffset(Teardown, 0, MachineInstrFlag::FrameDestroy);
if (!CFA)
return std::unexpected(CFA.error());
}
- if (HasFrameCFI) {
- MachineIRBuilder RestoreBuilder(Function, Target);
- auto After = RestoreBuilder.setInsertPointAfter(Terminator);
- if (!After)
- return std::unexpected(After.error());
- auto Restore = emitCFI(RestoreBuilder, MachineCFIInstruction::restoreState());
- if (!Restore)
- return std::unexpected(Restore.error());
- }
return {};
}
@@ -2039,13 +2051,16 @@ private:
return std::unexpected(Built.error());
return {};
}
+
+ RISCVABI ABI;
};
} // namespace
-const TargetFrameLowering &frameLowering() noexcept {
- static const RISCVFrameLowering Info;
- return Info;
+const TargetFrameLowering &frameLowering(RISCVABI ABI) noexcept {
+ static const RISCVFrameLowering LP64Info(RISCVABI::LP64);
+ static const RISCVFrameLowering LP64DInfo(RISCVABI::LP64D);
+ return ABI == RISCVABI::LP64D ? LP64DInfo : LP64Info;
}
} // namespace rcc::riscv
diff --git a/backend/lib/Target/RISCV/RISCVOptimizationPipeline.cpp b/backend/lib/Target/RISCV/RISCVOptimizationPipeline.cpp
index 7571832..cfc5583 100644
--- a/backend/lib/Target/RISCV/RISCVOptimizationPipeline.cpp
+++ b/backend/lib/Target/RISCV/RISCVOptimizationPipeline.cpp
@@ -11,7 +11,7 @@ optimizationPipelineInfo(const RISCVSubtarget &Subtarget, bool EmitSchedulerDebu
.InstrInfo = instrInfo(),
.Combiner = machineCombinerInfo(),
.MemoryFolding = memoryFoldingInfo(),
- .FrameLowering = frameLowering(),
+ .FrameLowering = frameLowering(Subtarget.targetABI()),
.PseudoExpansion = pseudoExpansionInfo(),
.SchedulingModel = Subtarget.schedulingModel(),
.SchedulerOptions = {.EmitDebugOutput = EmitSchedulerDebugOutput},
diff --git a/backend/lib/Target/RISCV/RISCVPipeline.cpp b/backend/lib/Target/RISCV/RISCVPipeline.cpp
index 2af1d43..cfa09d0 100644
--- a/backend/lib/Target/RISCV/RISCVPipeline.cpp
+++ b/backend/lib/Target/RISCV/RISCVPipeline.cpp
@@ -29,7 +29,9 @@ namespace rcc::riscv {
namespace {
[[nodiscard]] LibcallLoweringInfo libcallLoweringInfo(const RISCVSubtarget &Subtarget) {
- return {Subtarget.getCallLowering(), callingConventionID(CallingConvention::LP64)};
+ const CallingConvention Convention =
+ Subtarget.targetABI() == RISCVABI::LP64D ? CallingConvention::LP64D : CallingConvention::LP64;
+ return {Subtarget.getCallLowering(), callingConventionID(Convention)};
}
template <typename PassT, typename... ArgumentT>
diff --git a/backend/lib/Target/RISCV/RISCVSubtarget.cpp b/backend/lib/Target/RISCV/RISCVSubtarget.cpp
index c30c898..499219b 100644
--- a/backend/lib/Target/RISCV/RISCVSubtarget.cpp
+++ b/backend/lib/Target/RISCV/RISCVSubtarget.cpp
@@ -102,6 +102,15 @@ constexpr std::array OptionNames{
} // namespace
+Expected<RISCVABI> parseRISCVABI(std::string_view Name) {
+ if (Name == "lp64")
+ return RISCVABI::LP64;
+ if (Name == "lp64d")
+ return RISCVABI::LP64D;
+ return makeUnexpected(ErrorCode::InvalidInvocation,
+ "RISC-V backend does not support target ABI '" + std::string(Name) + "'");
+}
+
Expected<RISCVSubtargetFeatures>
RISCVSubtargetFeatures::fromFeatureList(std::span<const std::string> Features) {
std::uint16_t Enabled = extensionBit(RISCVExtension::I);
@@ -185,8 +194,8 @@ bool RISCVSubtargetFeatures::hasFeature(std::string_view Feature) const noexcept
}
RISCVSubtarget::RISCVSubtarget(RISCVSubtargetFeatures Features, RelocationModel Relocation,
- CodeModel Code)
- : Features(Features), Relocation(Relocation), Code(Code),
+ CodeModel Code, RISCVABI ABI)
+ : Features(Features), Relocation(Relocation), Code(Code), ABI(ABI),
SchedulingHooks(createSchedulingHooks(Features)) {
auto Model = createSchedulingModel(*SchedulingHooks);
if (!Model)
diff --git a/backend/lib/Tooling/MIRFuzzer.cpp b/backend/lib/Tooling/MIRFuzzer.cpp
index 7f1cc66..79e1b50 100644
--- a/backend/lib/Tooling/MIRFuzzer.cpp
+++ b/backend/lib/Tooling/MIRFuzzer.cpp
@@ -298,7 +298,10 @@ private:
auto Features = riscv::RISCVSubtargetFeatures::fromFeatureList(Invocation.Features);
if (!Features)
return std::unexpected(Features.error());
- const riscv::RISCVSubtarget Subtarget(*Features, Invocation.Relocation, Invocation.Code);
+ auto ABI = riscv::parseRISCVABI(Invocation.ABI);
+ if (!ABI)
+ return std::unexpected(ABI.error());
+ const riscv::RISCVSubtarget Subtarget(*Features, Invocation.Relocation, Invocation.Code, *ABI);
auto Names = riscv::canonicalPipelinePassNames(*Function, Subtarget);
if (!Names)
return std::unexpected(Names.error());
diff --git a/backend/lib/Tooling/PipelineDriver.cpp b/backend/lib/Tooling/PipelineDriver.cpp
index 959ff4c..5bf57cf 100644
--- a/backend/lib/Tooling/PipelineDriver.cpp
+++ b/backend/lib/Tooling/PipelineDriver.cpp
@@ -262,7 +262,10 @@ runFunction(MachineFunction &Function, mir::MIRDocument &Document, const TargetD
riscv::RISCVSubtargetFeatures Features, bool AllowSnapshots,
MachinePassInstrumentation *Instrumentation) {
FunctionRunResult Result;
- const riscv::RISCVSubtarget Subtarget(Features, Invocation.Relocation, Invocation.Code);
+ auto ABI = riscv::parseRISCVABI(Invocation.ABI);
+ if (!ABI)
+ return std::unexpected(ABI.error());
+ const riscv::RISCVSubtarget Subtarget(Features, Invocation.Relocation, Invocation.Code, *ABI);
MachinePassManagerOptions ManagerOptions{
.VerifyBefore = true,
.VerifyEach = Controls.VerifyEach,
@@ -455,11 +458,16 @@ Expected<void> verifyRV64GCInvocation(const BackendInvocation &Invocation) {
auto Features = riscv::RISCVSubtargetFeatures::fromFeatureList(Invocation.Features);
if (!Features)
return std::unexpected(Features.error());
+ auto ABI = riscv::parseRISCVABI(Invocation.ABI);
+ if (!ABI)
+ return std::unexpected(ABI.error());
+ if (*ABI == riscv::RISCVABI::LP64D && !Features->has(riscv::RISCVExtension::D)) {
+ return makeUnexpected(ErrorCode::InvalidInvocation, "RISC-V LP64D requires the D extension");
+ }
if (Invocation.Triple != Expected.Triple || Invocation.CPU != Expected.CPU ||
- Invocation.TuneCPU != Expected.TuneCPU || Invocation.ABI != Expected.ABI ||
- Invocation.DataLayout != Expected.DataLayout) {
+ Invocation.TuneCPU != Expected.TuneCPU || Invocation.DataLayout != Expected.DataLayout) {
return makeUnexpected(ErrorCode::InvalidInvocation,
- "backend invocation does not select the supported RV64 LP64D target");
+ "backend invocation does not select a supported RV64 target");
}
if (Invocation.MIRReferenceRevision != LLVMReferenceRevision ||
Invocation.GenericOpcodeVersion != GenericOpcodeReferenceVersion ||
diff --git a/backend/tools/MIRTool/MIRToolMain.cpp b/backend/tools/MIRTool/MIRToolMain.cpp
index b635c27..cfee95d 100644
--- a/backend/tools/MIRTool/MIRToolMain.cpp
+++ b/backend/tools/MIRTool/MIRToolMain.cpp
@@ -706,9 +706,14 @@ void setBackendOption(std::vector<rcc::tooling::BackendOption> &Options, std::st
Command.Invocation.CPU = *CodeGenFlags.CPU;
if (CodeGenFlags.TuneCPU)
Command.Invocation.TuneCPU = *CodeGenFlags.TuneCPU;
- if (CodeGenFlags.ABI)
- Command.Invocation.ABI = *CodeGenFlags.ABI;
applyFeatureOverrides(std::move(CodeGenFlags.FeatureOverrides), Command.Invocation.Features);
+ if (CodeGenFlags.ABI) {
+ Command.Invocation.ABI = *CodeGenFlags.ABI;
+ } else {
+ const bool HasDoubleFloat =
+ std::ranges::find(Command.Invocation.Features, "+d") != Command.Invocation.Features.end();
+ Command.Invocation.ABI = HasDoubleFloat ? "lp64d" : "lp64";
+ }
if (CodeGenFlags.Relocation)
Command.Invocation.Relocation = *CodeGenFlags.Relocation;
if (CodeGenFlags.Code)
@@ -923,8 +928,11 @@ runWithCache(const CommandLine &Command, CanonicalMIR Input, const rcc::TargetDe
rcc::riscv::RISCVSubtargetFeatures::fromFeatureList(Command.Invocation.Features);
if (!Features)
return std::unexpected(Features.error());
+ auto ABI = rcc::riscv::parseRISCVABI(Command.Invocation.ABI);
+ if (!ABI)
+ return std::unexpected(ABI.error());
const rcc::riscv::RISCVSubtarget Subtarget(*Features, Command.Invocation.Relocation,
- Command.Invocation.Code);
+ Command.Invocation.Code, *ABI);
std::vector<std::string> Names;
for (std::size_t Index = 0; Index < Input->Document.unit().functionCount(); ++Index) {
const rcc::MachineFunction *Function = Input->Document.unit().functionAt(Index);