From d91d57297bdb30b6363e259ab75d517dc333e292 Mon Sep 17 00:00:00 2001 From: Richard-Qin-X Date: Wed, 12 Aug 2026 00:26:10 +0800 Subject: [RISCV] Support absolute address operand flags --- .../include/rcc/Target/RISCV/RISCVInstPrinter.h | 2 + backend/lib/Target/RISCV/RISCV.rccdesc | 8 ++-- backend/lib/Target/RISCV/RISCVAsmBackend.cpp | 26 +++++++++--- backend/lib/Target/RISCV/RISCVInstPrinter.cpp | 4 ++ backend/lib/Target/RISCV/RISCVMCCodeEmitter.cpp | 4 ++ backend/lib/Target/RISCV/RISCVMCTargetLowering.cpp | 14 +++++-- backend/unittests/Target/RISCVMCTest.cpp | 46 ++++++++++++++++++++++ backend/unittests/Target/RISCVTargetTest.cpp | 8 ++-- 8 files changed, 97 insertions(+), 15 deletions(-) (limited to 'backend') diff --git a/backend/include/rcc/Target/RISCV/RISCVInstPrinter.h b/backend/include/rcc/Target/RISCV/RISCVInstPrinter.h index 564ca2f..1b80218 100644 --- a/backend/include/rcc/Target/RISCV/RISCVInstPrinter.h +++ b/backend/include/rcc/Target/RISCV/RISCVInstPrinter.h @@ -16,6 +16,8 @@ enum class RISCVMCExprKind : std::uint32_t { CallPLT = 1, PCRelativeHigh = 2, PCRelativeLow = 3, + AbsoluteHigh = 4, + AbsoluteLow = 5, }; class RISCVInstPrinter final : public mc::MCInstPrinter { diff --git a/backend/lib/Target/RISCV/RISCV.rccdesc b/backend/lib/Target/RISCV/RISCV.rccdesc index 5000d8b..5ef719b 100644 --- a/backend/lib/Target/RISCV/RISCV.rccdesc +++ b/backend/lib/Target/RISCV/RISCV.rccdesc @@ -277,13 +277,15 @@ register_masks: preserved: [X1, X8, X9, X18, X19, X20, X21, X22, X23, X24, X25, X26, X27, F8_D, F9_D, F18_D, F19_D, F20_D, F21_D, F22_D, F23_D, F24_D, F25_D, F26_D, F27_D, F8_F, F9_F, F18_F, F19_F, F20_F, F21_F, F22_F, F23_F, F24_F, F25_F, F26_F, F27_F] mir_operand_flags: - direct_mask: 31 + direct_mask: 127 direct: - { name: riscv-call, value: 1 } - { name: riscv-pcrel-hi, value: 2 } - { name: riscv-pcrel-lo, value: 4 } - { name: riscv-copy-f32, value: 8 } - { name: riscv-copy-f64, value: 16 } + - { name: riscv-hi, value: 32 } + - { name: riscv-lo, value: 64 } bitmask: [] calling_conventions: @@ -429,7 +431,7 @@ instructions: encoding: 5175 operands: - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } - - { kinds: [immediate], immediate_predicate: SIMM20, name: IMM } + - { kinds: [immediate, constant_pool_index, jump_table_index, global_symbol, external_symbol, block_address, mc_symbol], immediate_predicate: SIMM20, allowed_target_flags: 32, name: IMM } num_explicit_defs: 1 flags: [produces_code, rematerializable] scheduling_class: ALU @@ -458,7 +460,7 @@ instructions: operands: - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } - - { kinds: [immediate], immediate_predicate: SIMM12, name: IMM } + - { kinds: [immediate, constant_pool_index, jump_table_index, global_symbol, external_symbol, block_address, mc_symbol], immediate_predicate: SIMM12, allowed_target_flags: 68, name: IMM } num_explicit_defs: 1 flags: [produces_code, rematerializable] scheduling_class: ALU diff --git a/backend/lib/Target/RISCV/RISCVAsmBackend.cpp b/backend/lib/Target/RISCV/RISCVAsmBackend.cpp index 4e07933..ac17403 100644 --- a/backend/lib/Target/RISCV/RISCVAsmBackend.cpp +++ b/backend/lib/Target/RISCV/RISCVAsmBackend.cpp @@ -261,16 +261,30 @@ Expected RISCVAsmBackend::relocationType(const mc::MCFixup &Fixup return std::unexpected(Kind.error()); return Relocation(RISCVRelocation::CallPLT); } + if (isTargetKind(Fixup.Kind, RISCVFixupKind::High20)) { + if (Value.TargetKind != 0) { + auto Kind = requireRelocationTargetKind( + Value, static_cast(RISCVMCExprKind::AbsoluteHigh), "R_RISCV_HI20"); + if (!Kind) + return std::unexpected(Kind.error()); + } + return Relocation(RISCVRelocation::High20); + } + if (isTargetKind(Fixup.Kind, RISCVFixupKind::Low12I) || + isTargetKind(Fixup.Kind, RISCVFixupKind::Low12S)) { + if (Value.TargetKind != 0) { + auto Kind = requireRelocationTargetKind( + Value, static_cast(RISCVMCExprKind::AbsoluteLow), "R_RISCV_LO12"); + if (!Kind) + return std::unexpected(Kind.error()); + } + return Relocation(isTargetKind(Fixup.Kind, RISCVFixupKind::Low12I) ? RISCVRelocation::Low12I + : RISCVRelocation::Low12S); + } if (Value.TargetKind != 0) { return makeUnexpected(ErrorCode::RelocationFailed, "RISC-V relocation has an unsupported target expression"); } - if (isTargetKind(Fixup.Kind, RISCVFixupKind::High20)) - return Relocation(RISCVRelocation::High20); - if (isTargetKind(Fixup.Kind, RISCVFixupKind::Low12I)) - return Relocation(RISCVRelocation::Low12I); - if (isTargetKind(Fixup.Kind, RISCVFixupKind::Low12S)) - return Relocation(RISCVRelocation::Low12S); if (isTargetKind(Fixup.Kind, RISCVFixupKind::JAL)) return Relocation(RISCVRelocation::JAL); if (isTargetKind(Fixup.Kind, RISCVFixupKind::Branch)) diff --git a/backend/lib/Target/RISCV/RISCVInstPrinter.cpp b/backend/lib/Target/RISCV/RISCVInstPrinter.cpp index 4699835..ec17b07 100644 --- a/backend/lib/Target/RISCV/RISCVInstPrinter.cpp +++ b/backend/lib/Target/RISCV/RISCVInstPrinter.cpp @@ -274,6 +274,10 @@ Expected RISCVInstPrinter::printTargetExpression(std::uint32_t Kind return "%pcrel_hi(" + std::string(Operand) + ")"; case RISCVMCExprKind::PCRelativeLow: return "%pcrel_lo(" + std::string(Operand) + ")"; + case RISCVMCExprKind::AbsoluteHigh: + return "%hi(" + std::string(Operand) + ")"; + case RISCVMCExprKind::AbsoluteLow: + return "%lo(" + std::string(Operand) + ")"; } return makeUnexpected(ErrorCode::AssemblyLoweringFailed, "RISC-V MC expression has an unknown target kind"); diff --git a/backend/lib/Target/RISCV/RISCVMCCodeEmitter.cpp b/backend/lib/Target/RISCV/RISCVMCCodeEmitter.cpp index 5f98887..81ac0f1 100644 --- a/backend/lib/Target/RISCV/RISCVMCCodeEmitter.cpp +++ b/backend/lib/Target/RISCV/RISCVMCCodeEmitter.cpp @@ -182,6 +182,8 @@ namespace { return std::unexpected(Kind.error()); if (*Kind == 0) return fixupKind(RISCVFixupKind::High20); + if (*Kind == static_cast(RISCVMCExprKind::AbsoluteHigh)) + return fixupKind(RISCVFixupKind::High20); if (*Kind == static_cast(RISCVMCExprKind::PCRelativeHigh)) return fixupKind(RISCVFixupKind::PCRelativeHigh20); if (*Kind == static_cast(RISCVMCExprKind::CallPLT)) @@ -196,6 +198,8 @@ namespace { return std::unexpected(Kind.error()); if (*Kind == 0) return fixupKind(Store ? RISCVFixupKind::Low12S : RISCVFixupKind::Low12I); + if (*Kind == static_cast(RISCVMCExprKind::AbsoluteLow)) + return fixupKind(Store ? RISCVFixupKind::Low12S : RISCVFixupKind::Low12I); if (*Kind == static_cast(RISCVMCExprKind::PCRelativeLow)) { return fixupKind(Store ? RISCVFixupKind::PCRelativeLow12S : RISCVFixupKind::PCRelativeLow12I); } diff --git a/backend/lib/Target/RISCV/RISCVMCTargetLowering.cpp b/backend/lib/Target/RISCV/RISCVMCTargetLowering.cpp index 19b1b11..ee41d47 100644 --- a/backend/lib/Target/RISCV/RISCVMCTargetLowering.cpp +++ b/backend/lib/Target/RISCV/RISCVMCTargetLowering.cpp @@ -45,9 +45,11 @@ constexpr std::uint32_t PCRelativeHighTargetFlag = 2; constexpr std::uint32_t PCRelativeLowTargetFlag = 4; constexpr std::uint32_t CopyF32TargetFlag = 8; constexpr std::uint32_t CopyF64TargetFlag = 16; -constexpr std::uint32_t KnownTargetFlags = CallTargetFlag | PCRelativeHighTargetFlag | - PCRelativeLowTargetFlag | CopyF32TargetFlag | - CopyF64TargetFlag; +constexpr std::uint32_t AbsoluteHighTargetFlag = 32; +constexpr std::uint32_t AbsoluteLowTargetFlag = 64; +constexpr std::uint32_t KnownTargetFlags = + CallTargetFlag | PCRelativeHighTargetFlag | PCRelativeLowTargetFlag | CopyF32TargetFlag | + CopyF64TargetFlag | AbsoluteHighTargetFlag | AbsoluteLowTargetFlag; struct TypeLayout final { std::uint64_t Size = 0; @@ -219,6 +221,12 @@ struct TypeLayout final { case PCRelativeLowTargetFlag: Kind = RISCVMCExprKind::PCRelativeLow; break; + case AbsoluteHighTargetFlag: + Kind = RISCVMCExprKind::AbsoluteHigh; + break; + case AbsoluteLowTargetFlag: + Kind = RISCVMCExprKind::AbsoluteLow; + break; default: return makeUnexpected(ErrorCode::AssemblyLoweringFailed, "RISC-V operand combines incompatible direct target flags"); diff --git a/backend/unittests/Target/RISCVMCTest.cpp b/backend/unittests/Target/RISCVMCTest.cpp index 4836708..1064cf3 100644 --- a/backend/unittests/Target/RISCVMCTest.cpp +++ b/backend/unittests/Target/RISCVMCTest.cpp @@ -170,6 +170,45 @@ symbolExpression(rcc::mc::MCContext &Context, std::string_view Name, std::uint32 return false; } + auto AbsoluteHighExpression = symbolExpression( + Context, "absolute", static_cast(rcc::riscv::RISCVMCExprKind::AbsoluteHigh)); + if (!AbsoluteHighExpression) + return false; + auto AbsoluteHigh = + instruction(LUI, {reg(X6), rcc::mc::MCOperand::expression(*AbsoluteHighExpression)}); + auto AbsoluteHighEncoding = Emitter.encodeInstruction(AbsoluteHigh); + if (!AbsoluteHighEncoding || AbsoluteHighEncoding->Fixups.size() != 1 || + AbsoluteHighEncoding->Fixups[0].Kind != + rcc::riscv::fixupKind(rcc::riscv::RISCVFixupKind::High20)) { + return false; + } + auto AbsoluteHighValue = rcc::mc::evaluateAsRelocatable(**AbsoluteHighExpression); + auto AbsoluteHighRelocation = + AbsoluteHighValue + ? Backend.relocationType(AbsoluteHighEncoding->Fixups[0], *AbsoluteHighValue) + : rcc::Expected{std::unexpected(AbsoluteHighValue.error())}; + if (!AbsoluteHighRelocation || *AbsoluteHighRelocation != 26) + return false; + + auto AbsoluteLowExpression = symbolExpression( + Context, "absolute", static_cast(rcc::riscv::RISCVMCExprKind::AbsoluteLow)); + if (!AbsoluteLowExpression) + return false; + auto AbsoluteLow = + instruction(ADDI, {reg(X6), reg(X6), rcc::mc::MCOperand::expression(*AbsoluteLowExpression)}); + auto AbsoluteLowEncoding = Emitter.encodeInstruction(AbsoluteLow); + if (!AbsoluteLowEncoding || AbsoluteLowEncoding->Fixups.size() != 1 || + AbsoluteLowEncoding->Fixups[0].Kind != + rcc::riscv::fixupKind(rcc::riscv::RISCVFixupKind::Low12I)) { + return false; + } + auto AbsoluteLowValue = rcc::mc::evaluateAsRelocatable(**AbsoluteLowExpression); + auto AbsoluteLowRelocation = + AbsoluteLowValue ? Backend.relocationType(AbsoluteLowEncoding->Fixups[0], *AbsoluteLowValue) + : rcc::Expected{std::unexpected(AbsoluteLowValue.error())}; + if (!AbsoluteLowRelocation || *AbsoluteLowRelocation != 27) + return false; + auto BranchExpression = symbolExpression(Context, "block"); if (!BranchExpression) return false; @@ -251,6 +290,13 @@ int main() { return fail(Target.error().message()); rcc::riscv::RISCVMCCodeEmitter Emitter(*Target); rcc::riscv::RISCVAsmBackend Backend; + rcc::riscv::RISCVInstPrinter Printer(*Target); + auto PrintedHigh = Printer.printTargetExpression( + static_cast(rcc::riscv::RISCVMCExprKind::AbsoluteHigh), "symbol"); + auto PrintedLow = Printer.printTargetExpression( + static_cast(rcc::riscv::RISCVMCExprKind::AbsoluteLow), "symbol"); + if (!PrintedHigh || *PrintedHigh != "%hi(symbol)" || !PrintedLow || *PrintedLow != "%lo(symbol)") + return fail("RISC-V absolute address modifiers do not print canonically"); if (!testEncodings(Emitter)) return fail("RISC-V MC encodings differ from the RV64GC reference encodings"); if (!testFixups(Emitter, Backend)) diff --git a/backend/unittests/Target/RISCVTargetTest.cpp b/backend/unittests/Target/RISCVTargetTest.cpp index 2d1be09..2077496 100644 --- a/backend/unittests/Target/RISCVTargetTest.cpp +++ b/backend/unittests/Target/RISCVTargetTest.cpp @@ -119,9 +119,11 @@ void testABIAndDebugFacts(TestContext &Context) { TextLP64DMask != nullptr && LP64DMask != nullptr && *TextLP64DMask == *LP64DMask, "RV64GC must expose named LP64 and LP64D call-preserved masks"); - Context.expect(MIRText->directOperandFlagMask() == 31 && - MIRText->directOperandFlag("riscv-call") == 1, - "RV64GC MIR target flags must expose the canonical direct-call spelling"); + Context.expect(MIRText->directOperandFlagMask() == 127 && + MIRText->directOperandFlag("riscv-call") == 1 && + MIRText->directOperandFlag("riscv-hi") == 32 && + MIRText->directOperandFlag("riscv-lo") == 64, + "RV64GC MIR target flags must expose canonical call and address spellings"); Context.expect(MIRText->dwarfRegister(X1) == 1, "the return-address register must retain its DWARF register number"); Context.expect(MIRText->dwarfRegister(F31D) == 63 && MIRText->dwarfRegister(F31F) == 63 && -- cgit v1.2.3