aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard-Qin-X <richard.qin.001@gmail.com>2026-08-12 00:26:10 +0800
committerRichard-Qin-X <richard.qin.001@gmail.com>2026-08-12 00:26:10 +0800
commitd91d57297bdb30b6363e259ab75d517dc333e292 (patch)
treeb931c72127e25a4acbf1f7b38ffdcba74ef270c7
parentadf3e4f02e330e052dbb75e9601bae5273ccfe6c (diff)
downloadrcc-project-d91d57297bdb30b6363e259ab75d517dc333e292.tar.gz
rcc-project-d91d57297bdb30b6363e259ab75d517dc333e292.tar.xz
[RISCV] Support absolute address operand flags
-rw-r--r--backend/include/rcc/Target/RISCV/RISCVInstPrinter.h2
-rw-r--r--backend/lib/Target/RISCV/RISCV.rccdesc8
-rw-r--r--backend/lib/Target/RISCV/RISCVAsmBackend.cpp26
-rw-r--r--backend/lib/Target/RISCV/RISCVInstPrinter.cpp4
-rw-r--r--backend/lib/Target/RISCV/RISCVMCCodeEmitter.cpp4
-rw-r--r--backend/lib/Target/RISCV/RISCVMCTargetLowering.cpp14
-rw-r--r--backend/unittests/Target/RISCVMCTest.cpp46
-rw-r--r--backend/unittests/Target/RISCVTargetTest.cpp8
8 files changed, 97 insertions, 15 deletions
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<std::uint32_t> 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<std::uint32_t>(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<std::uint32_t>(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<std::string> 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<std::uint32_t>(RISCVMCExprKind::AbsoluteHigh))
+ return fixupKind(RISCVFixupKind::High20);
if (*Kind == static_cast<std::uint32_t>(RISCVMCExprKind::PCRelativeHigh))
return fixupKind(RISCVFixupKind::PCRelativeHigh20);
if (*Kind == static_cast<std::uint32_t>(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<std::uint32_t>(RISCVMCExprKind::AbsoluteLow))
+ return fixupKind(Store ? RISCVFixupKind::Low12S : RISCVFixupKind::Low12I);
if (*Kind == static_cast<std::uint32_t>(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<std::uint32_t>(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::uint32_t>{std::unexpected(AbsoluteHighValue.error())};
+ if (!AbsoluteHighRelocation || *AbsoluteHighRelocation != 26)
+ return false;
+
+ auto AbsoluteLowExpression = symbolExpression(
+ Context, "absolute", static_cast<std::uint32_t>(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::uint32_t>{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<std::uint32_t>(rcc::riscv::RISCVMCExprKind::AbsoluteHigh), "symbol");
+ auto PrintedLow = Printer.printTargetExpression(
+ static_cast<std::uint32_t>(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 &&