diff options
| -rw-r--r-- | backend/include/rcc/Target/RISCV/RISCVSubtarget.h | 14 | ||||
| -rw-r--r-- | backend/lib/CodeGen/FrameIndexElimination.cpp | 22 | ||||
| -rw-r--r-- | backend/lib/CodeGen/MIRPrinter.cpp | 24 | ||||
| -rw-r--r-- | backend/lib/CodeGen/MachineVerifier.cpp | 1 | ||||
| -rw-r--r-- | backend/lib/CodeGen/PrologueEpilogueInsertion.cpp | 7 | ||||
| -rw-r--r-- | backend/lib/Target/RISCV/RISCV.h | 2 | ||||
| -rw-r--r-- | backend/lib/Target/RISCV/RISCVFrameLowering.cpp | 195 | ||||
| -rw-r--r-- | backend/lib/Target/RISCV/RISCVOptimizationPipeline.cpp | 2 | ||||
| -rw-r--r-- | backend/lib/Target/RISCV/RISCVPipeline.cpp | 4 | ||||
| -rw-r--r-- | backend/lib/Target/RISCV/RISCVSubtarget.cpp | 13 | ||||
| -rw-r--r-- | backend/lib/Tooling/MIRFuzzer.cpp | 5 | ||||
| -rw-r--r-- | backend/lib/Tooling/PipelineDriver.cpp | 16 | ||||
| -rw-r--r-- | backend/tools/MIRTool/MIRToolMain.cpp | 14 |
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 ®isterAllocationInfo() 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); |
