From 551f0b3fcd6f797ed6dca90f39123b0359396dcb Mon Sep 17 00:00:00 2001 From: Richard-Qin-X Date: Tue, 11 Aug 2026 20:08:36 +0800 Subject: [RISCV] Match LLVM call-frame pseudo semantics --- backend/lib/Target/RISCV/RISCV.rccdesc | 4 ++ backend/lib/Target/RISCV/RISCVCallLowering.cpp | 25 ++++++------ backend/lib/Target/RISCV/RISCVFrameLowering.cpp | 46 ++++++++-------------- .../lib/Target/RISCV/RISCVRegisterAllocation.cpp | 32 --------------- 4 files changed, 33 insertions(+), 74 deletions(-) (limited to 'backend/lib') diff --git a/backend/lib/Target/RISCV/RISCV.rccdesc b/backend/lib/Target/RISCV/RISCV.rccdesc index f8e22d4..ea3a775 100644 --- a/backend/lib/Target/RISCV/RISCV.rccdesc +++ b/backend/lib/Target/RISCV/RISCV.rccdesc @@ -3351,6 +3351,8 @@ instructions: - { kinds: [immediate, integer_immediate] } - { kinds: [immediate, integer_immediate] } num_explicit_defs: 0 + implicit_defs: [{ register: X2 }] + implicit_uses: [{ register: X2 }] flags: [pseudo, allowed_pre_legalizer, has_side_effects] owner: prologue_epilogue_insertion deadline: frame_finalized @@ -3362,6 +3364,8 @@ instructions: - { kinds: [immediate, integer_immediate] } - { kinds: [immediate, integer_immediate] } num_explicit_defs: 0 + implicit_defs: [{ register: X2 }] + implicit_uses: [{ register: X2 }] flags: [pseudo, allowed_pre_legalizer, has_side_effects] owner: prologue_epilogue_insertion deadline: frame_finalized diff --git a/backend/lib/Target/RISCV/RISCVCallLowering.cpp b/backend/lib/Target/RISCV/RISCVCallLowering.cpp index fd01d52..3a5805a 100644 --- a/backend/lib/Target/RISCV/RISCVCallLowering.cpp +++ b/backend/lib/Target/RISCV/RISCVCallLowering.cpp @@ -1172,20 +1172,20 @@ createMemoryOperand(MachineFunction &Function, MemoryAccessFlags Accesses, std:: [[nodiscard]] Expected emitCallFrameAdjustment(MachineIRBuilder &Builder, InstructionOpcode OpcodeValue, - const CallFrameRequirements &Frame, - MachineInstrFlag Flag) { + const CallFrameRequirements &Frame) { + if (Frame.SizeBytes > static_cast(std::numeric_limits::max())) { + return makeUnexpected(ErrorCode::Unsupported, + "RISC-V call-frame size does not fit a MIR immediate"); + } auto Instruction = Builder.buildInstr(targetOpcode(OpcodeValue)); if (!Instruction) return std::unexpected(Instruction.error()); - auto Size = addUnsignedImmediate(*Instruction, Frame.SizeBytes); + auto Size = Instruction->addImmediate(static_cast(Frame.SizeBytes)); if (!Size) return std::unexpected(Size.error()); - auto Align = addUnsignedImmediate(*Instruction, Frame.Align.bytes()); - if (!Align) - return std::unexpected(Align.error()); - auto Flags = Instruction->setFlags({Flag}); - if (!Flags) - return std::unexpected(Flags.error()); + auto PreparedBytes = Instruction->addImmediate(0); + if (!PreparedBytes) + return std::unexpected(PreparedBytes.error()); auto Built = Instruction->build(); if (!Built) return std::unexpected(Built.error()); @@ -1371,8 +1371,8 @@ emitOutgoingArguments(MachineIRBuilder &Builder, const CallLoweringPlan &Plan, [[nodiscard]] Expected emitCall(MachineIRBuilder &Builder, const CallLoweringPlan &Plan) { if (Plan.callFrame().EmitSetup) { - auto Down = emitCallFrameAdjustment(Builder, InstructionOpcode::ADJCALLSTACKDOWN, - Plan.callFrame(), MachineInstrFlag::FrameSetup); + auto Down = + emitCallFrameAdjustment(Builder, InstructionOpcode::ADJCALLSTACKDOWN, Plan.callFrame()); if (!Down) return std::unexpected(Down.error()); } @@ -1388,8 +1388,7 @@ emitOutgoingArguments(MachineIRBuilder &Builder, const CallLoweringPlan &Plan, return std::unexpected(Call.error()); if (Plan.callFrame().EmitDestroy) { - auto Up = emitCallFrameAdjustment(Builder, InstructionOpcode::ADJCALLSTACKUP, Plan.callFrame(), - MachineInstrFlag::FrameDestroy); + auto Up = emitCallFrameAdjustment(Builder, InstructionOpcode::ADJCALLSTACKUP, Plan.callFrame()); if (!Up) return std::unexpected(Up.error()); } diff --git a/backend/lib/Target/RISCV/RISCVFrameLowering.cpp b/backend/lib/Target/RISCV/RISCVFrameLowering.cpp index e47a9c8..4ba5540 100644 --- a/backend/lib/Target/RISCV/RISCVFrameLowering.cpp +++ b/backend/lib/Target/RISCV/RISCVFrameLowering.cpp @@ -102,29 +102,33 @@ constexpr std::uint8_t DwarfOpBaseRegisterExtended = 0x92U; struct CallFrameRequirement final { std::int64_t Amount = 0; - std::int64_t Alignment = 0; + std::int64_t PreparedBytes = 0; std::int64_t AlignedAmount = 0; }; [[nodiscard]] Expected callFrameRequirement(const MachineInstr &Instruction) { - if (Instruction.operandCount() != 2) { + if (Instruction.operandCount() < 2) { return makeUnexpected(ErrorCode::VerificationError, - "RISC-V call-frame pseudo requires exactly amount and alignment"); + "RISC-V call-frame pseudo requires amount and prepared-byte operands"); + } + for (std::size_t Index = 2; Index < Instruction.operandCount(); ++Index) { + const MachineOperand *Operand = Instruction.operandAt(Index); + if (Operand == nullptr || !Operand->isRegister() || !Operand->isImplicit()) { + return makeUnexpected(ErrorCode::VerificationError, + "RISC-V call-frame pseudo has an unexpected explicit operand"); + } } auto Amount = immediateValue(*Instruction.operandAt(0)); - auto RequestedAlignment = immediateValue(*Instruction.operandAt(1)); - if (!Amount || !RequestedAlignment || *Amount < 0 || *RequestedAlignment <= 0 || - !std::has_single_bit(static_cast(*RequestedAlignment))) { + auto PreparedBytes = immediateValue(*Instruction.operandAt(1)); + if (!Amount || !PreparedBytes || *Amount < 0 || *PreparedBytes < 0) { return makeUnexpected(ErrorCode::VerificationError, - "RISC-V call-frame amount or alignment is invalid"); + "RISC-V call-frame amount or prepared-byte count is invalid"); } - const std::uint64_t Alignment = - std::max(StackAlignmentBytes, static_cast(*RequestedAlignment)); - auto Aligned = alignTo(static_cast(*Amount), Alignment); + auto Aligned = alignTo(static_cast(*Amount), StackAlignmentBytes); if (!Aligned || *Aligned > static_cast(std::numeric_limits::max())) { return makeUnexpected(ErrorCode::FrameLayoutFailed, "RISC-V call-frame amount is too large"); } - return CallFrameRequirement{*Amount, *RequestedAlignment, static_cast(*Aligned)}; + return CallFrameRequirement{*Amount, *PreparedBytes, static_cast(*Aligned)}; } [[nodiscard]] Expected callFrameAmount(const MachineInstr &Instruction) { @@ -148,23 +152,6 @@ struct CallFrameRequirement final { if (!Object.isTombstone() && !Object.description()->IsDead) Result = std::max(Result, Object.description()->Align.bytes()); } - for (const MachineBasicBlock *Block = Function.firstBlock(); Block != nullptr; - Block = Block->next()) { - for (const MachineInstr *Instruction = Block->firstInstruction(); Instruction != nullptr; - Instruction = Instruction->next()) { - if (Instruction->opcode() != targetOpcode(InstructionOpcode::ADJCALLSTACKDOWN) && - Instruction->opcode() != targetOpcode(InstructionOpcode::ADJCALLSTACKUP)) { - continue; - } - if (Instruction->operandCount() < 2) - continue; - auto Requested = immediateValue(*Instruction->operandAt(1)); - if (Requested && *Requested > 0 && - std::has_single_bit(static_cast(*Requested))) { - Result = std::max(Result, static_cast(*Requested)); - } - } - } return Result; } @@ -314,7 +301,8 @@ struct CallFrameRequirement final { return makeUnexpected(ErrorCode::VerificationError, "RISC-V call-frame destroy has no matching setup"); } - if (Active->Amount != Requirement->Amount || Active->Alignment != Requirement->Alignment) { + if (Active->Amount != Requirement->Amount || + Active->PreparedBytes != Requirement->PreparedBytes) { return makeUnexpected(ErrorCode::VerificationError, "RISC-V call-frame setup and destroy requirements differ"); } diff --git a/backend/lib/Target/RISCV/RISCVRegisterAllocation.cpp b/backend/lib/Target/RISCV/RISCVRegisterAllocation.cpp index 81fc6dc..aee09a9 100644 --- a/backend/lib/Target/RISCV/RISCVRegisterAllocation.cpp +++ b/backend/lib/Target/RISCV/RISCVRegisterAllocation.cpp @@ -14,7 +14,6 @@ #include #include -#include #include #include #include @@ -37,20 +36,6 @@ struct SpillForm final { return RegisterClassID::fromValue(static_cast(Value)); } -[[nodiscard]] std::optional immediateValue(const MachineOperand &Operand) noexcept { - if (const auto *Immediate = Operand.getIf()) - return *Immediate; - const auto *Integer = Operand.getIf(); - if (Integer == nullptr || Integer->Value.bitWidth() == 0 || Integer->Value.bitWidth() > 64) { - return std::nullopt; - } - std::uint64_t Raw = Integer->Value.words().empty() ? 0 : Integer->Value.words().front(); - const std::uint32_t Width = Integer->Value.bitWidth(); - if (Width < 64 && (Raw & (std::uint64_t{1} << (Width - 1U))) != 0) - Raw |= ~std::uint64_t{0} << Width; - return std::bit_cast(Raw); -} - [[nodiscard]] constexpr std::optional spillForm(RegisterClassID Class) noexcept { if (Class == registerClassID(RegisterClass::GPR) || Class == registerClassID(RegisterClass::GPRC) || @@ -129,23 +114,6 @@ public: RequiredAlignment = std::max(RequiredAlignment, Object.description()->Align.bytes()); } } - for (const MachineBasicBlock *Block = Function.firstBlock(); Block != nullptr; - Block = Block->next()) { - for (const MachineInstr *Instruction = Block->firstInstruction(); Instruction != nullptr; - Instruction = Instruction->next()) { - if (Instruction->opcode() != targetOpcode(InstructionOpcode::ADJCALLSTACKDOWN) && - Instruction->opcode() != targetOpcode(InstructionOpcode::ADJCALLSTACKUP)) { - continue; - } - if (Instruction->operandCount() < 2) - continue; - const auto Requested = immediateValue(*Instruction->operandAt(1)); - if (Requested && *Requested > 0 && - std::has_single_bit(static_cast(*Requested))) { - RequiredAlignment = std::max(RequiredAlignment, static_cast(*Requested)); - } - } - } const bool RequiresRealignment = RequiredAlignment > 16; if (Reg.number() == static_cast(PhysicalRegisterID::X9)) return RequiresRealignment; -- cgit v1.2.3