From 379ff50dcc7ccf977379aee68fa9d10f69065d23 Mon Sep 17 00:00:00 2001 From: Richard-Qin-X Date: Sun, 9 Aug 2026 18:31:49 +0800 Subject: [MC] Implement RV64GC assembly emission --- backend/lib/Target/RISCV/RISCVInstPrinter.cpp | 279 ++++++++++++++++++++++++++ 1 file changed, 279 insertions(+) create mode 100644 backend/lib/Target/RISCV/RISCVInstPrinter.cpp (limited to 'backend/lib/Target/RISCV/RISCVInstPrinter.cpp') diff --git a/backend/lib/Target/RISCV/RISCVInstPrinter.cpp b/backend/lib/Target/RISCV/RISCVInstPrinter.cpp new file mode 100644 index 0000000..ba3e509 --- /dev/null +++ b/backend/lib/Target/RISCV/RISCVInstPrinter.cpp @@ -0,0 +1,279 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "rcc/Target/RISCV/RISCVInstPrinter.h" + +#include "rcc/CodeGen/Register.h" +#include "rcc/MC/MCExpr.h" +#include "rcc/MC/MCInst.h" +#include "rcc/MC/MCInstPrinter.h" +#include "rcc/Target/RISCV/RISCVTarget.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace rcc::riscv { +namespace { + +struct LinearFormat final { + std::string_view Name; + std::size_t OperandCount = 0; +}; + +constexpr std::array LinearFormats{ + LinearFormat{"none", 0}, + LinearFormat{"rd-imm", 2}, + LinearFormat{"rd-rs1-imm", 3}, + LinearFormat{"rd-rs1-rs2", 3}, + LinearFormat{"rs1-rs2-target", 3}, + LinearFormat{"rd-target", 2}, + LinearFormat{"imm-imm", 2}, + LinearFormat{"rd-csr-rs1", 3}, + LinearFormat{"rd-csr-imm", 3}, + LinearFormat{"frd-frs1-frs2-rm", 4}, + LinearFormat{"frd-frs1-frs2-frs3-rm", 5}, + LinearFormat{"frd-frs1-rm", 3}, + LinearFormat{"frd-frs1-frs2", 3}, + LinearFormat{"rd-frs1-rm", 3}, + LinearFormat{"rd-frs1", 2}, + LinearFormat{"rd-frs1-frs2", 3}, + LinearFormat{"frd-rs1-rm", 3}, + LinearFormat{"frd-rs1", 2}, + LinearFormat{"target", 1}, + LinearFormat{"rs1-target", 2}, + LinearFormat{"rs1", 1}, + LinearFormat{"rd-rs2", 2}, +}; + +[[nodiscard]] const AssemblyFormatInfo *assemblyFormat(AssemblyFormatID ID) noexcept { + const auto Formats = assemblyFormats(); + const auto Position = std::ranges::find(Formats, ID, &AssemblyFormatInfo::ID); + return Position == Formats.end() ? nullptr : &*Position; +} + +[[nodiscard]] std::optional linearOperandCount(std::string_view Name) noexcept { + const auto *const Position = std::ranges::find(LinearFormats, Name, &LinearFormat::Name); + return Position == LinearFormats.end() ? std::nullopt : std::optional(Position->OperandCount); +} + +[[nodiscard]] Expected requireOperandCount(const mc::MCInst &Instruction, + std::size_t ExpectedCount) { + if (Instruction.operands().size() != ExpectedCount) { + return makeUnexpected(ErrorCode::AssemblyLoweringFailed, + "RISC-V assembly format has an unexpected operand count"); + } + return {}; +} + +[[nodiscard]] std::string hexValue(std::uint64_t Value) { + std::array Digits{}; + const auto [End, Error] = std::to_chars(Digits.data(), Digits.data() + Digits.size(), Value, 16); + if (Error != std::errc{}) + return {}; + return "0x" + std::string(Digits.data(), End); +} + +[[nodiscard]] Expected formatOperand(const mc::MCOperand &Operand, + const TargetDescription &Target, + const mc::MCInstPrinter &Printer) { + if (const mc::MCRegister *Register = Operand.registerValue(); Register != nullptr) { + auto Physical = PhysicalRegister::create(Register->value()); + if (!Physical) + return std::unexpected(Physical.error()); + const auto Name = Target.registers().physicalRegisterMIRName(*Physical); + if (!Name) { + return makeUnexpected(ErrorCode::AssemblyLoweringFailed, + "RISC-V MC instruction references an unknown register"); + } + return std::string(*Name); + } + if (const std::int64_t *Immediate = Operand.immediateValue(); Immediate != nullptr) + return std::to_string(*Immediate); + if (const std::uint32_t *Bits = Operand.float32BitsValue(); Bits != nullptr) + return hexValue(*Bits); + if (const std::uint64_t *Bits = Operand.float64BitsValue(); Bits != nullptr) + return hexValue(*Bits); + if (const mc::MCExprRef *Expression = Operand.expressionValue(); Expression != nullptr) { + if (!*Expression) + return makeUnexpected(ErrorCode::AssemblyLoweringFailed, + "RISC-V MC instruction has a null expression operand"); + return mc::printMCExpression(**Expression, Printer); + } + return makeUnexpected(ErrorCode::InternalError, "RISC-V MC operand storage is invalid"); +} + +[[nodiscard]] Expected formatRegisterOperand(const mc::MCInst &Instruction, + std::size_t Index, + const TargetDescription &Target, + const mc::MCInstPrinter &Printer) { + if (Index >= Instruction.operands().size() || + Instruction.operands()[Index].registerValue() == nullptr) { + return makeUnexpected(ErrorCode::AssemblyLoweringFailed, + "RISC-V assembly format requires a register operand"); + } + return formatOperand(Instruction.operands()[Index], Target, Printer); +} + +[[nodiscard]] Expected formatAnyOperand(const mc::MCInst &Instruction, + std::size_t Index, + const TargetDescription &Target, + const mc::MCInstPrinter &Printer) { + if (Index >= Instruction.operands().size()) { + return makeUnexpected(ErrorCode::AssemblyLoweringFailed, + "RISC-V assembly format references an absent operand"); + } + return formatOperand(Instruction.operands()[Index], Target, Printer); +} + +[[nodiscard]] Expected formatAddress(const mc::MCInst &Instruction, + std::size_t OffsetIndex, std::size_t BaseIndex, + const TargetDescription &Target, + const mc::MCInstPrinter &Printer) { + auto Offset = formatAnyOperand(Instruction, OffsetIndex, Target, Printer); + if (!Offset) + return std::unexpected(Offset.error()); + auto Base = formatRegisterOperand(Instruction, BaseIndex, Target, Printer); + if (!Base) + return std::unexpected(Base.error()); + return *Offset + "(" + *Base + ")"; +} + +[[nodiscard]] Expected joinOperands(const mc::MCInst &Instruction, std::size_t Count, + const TargetDescription &Target, + const mc::MCInstPrinter &Printer) { + auto CountResult = requireOperandCount(Instruction, Count); + if (!CountResult) + return std::unexpected(CountResult.error()); + std::string Result; + for (std::size_t Index = 0; Index < Count; ++Index) { + auto Operand = formatAnyOperand(Instruction, Index, Target, Printer); + if (!Operand) + return std::unexpected(Operand.error()); + if (!Result.empty()) + Result += ", "; + Result += *Operand; + } + return Result; +} + +} // namespace + +Expected RISCVInstPrinter::printInstruction(const mc::MCInst &Instruction) const { + const AssemblyInstructionInfo *Assembly = + assemblyInstruction(Opcode::fromValue(Instruction.opcode().value())); + if (Assembly == nullptr || Assembly->Mnemonic.empty()) { + return makeUnexpected(ErrorCode::AssemblyLoweringFailed, + "RISC-V instruction has no generated assembly spelling"); + } + const AssemblyFormatInfo *Format = assemblyFormat(Assembly->Format); + if (Format == nullptr) { + return makeUnexpected(ErrorCode::InternalError, + "RISC-V instruction references an unknown assembly format"); + } + + std::string Operands; + if (const auto LinearCount = linearOperandCount(Format->Name)) { + auto Joined = joinOperands(Instruction, *LinearCount, *Target, *this); + if (!Joined) + return std::unexpected(Joined.error()); + Operands = std::move(*Joined); + } else if (Format->Name == "rd-offset-rs1" || Format->Name == "frd-offset-rs1" || + Format->Name == "rs2-offset-rs1" || Format->Name == "frs2-offset-rs1") { + auto Count = requireOperandCount(Instruction, 3); + if (!Count) + return std::unexpected(Count.error()); + auto First = formatRegisterOperand(Instruction, 0, *Target, *this); + if (!First) + return std::unexpected(First.error()); + auto Address = formatAddress(Instruction, 2, 1, *Target, *this); + if (!Address) + return std::unexpected(Address.error()); + Operands = *First + ", " + *Address; + } else if (Format->Name == "rd-paren-rs1") { + auto Count = requireOperandCount(Instruction, 2); + if (!Count) + return std::unexpected(Count.error()); + auto Destination = formatRegisterOperand(Instruction, 0, *Target, *this); + if (!Destination) + return std::unexpected(Destination.error()); + auto Base = formatRegisterOperand(Instruction, 1, *Target, *this); + if (!Base) + return std::unexpected(Base.error()); + Operands = *Destination + ", (" + *Base + ")"; + } else if (Format->Name == "rd-rs2-paren-rs1") { + auto Count = requireOperandCount(Instruction, 3); + if (!Count) + return std::unexpected(Count.error()); + auto Destination = formatRegisterOperand(Instruction, 0, *Target, *this); + if (!Destination) + return std::unexpected(Destination.error()); + auto Value = formatRegisterOperand(Instruction, 1, *Target, *this); + if (!Value) + return std::unexpected(Value.error()); + auto Base = formatRegisterOperand(Instruction, 2, *Target, *this); + if (!Base) + return std::unexpected(Base.error()); + Operands = *Destination + ", " + *Value + ", (" + *Base + ")"; + } else if (Format->Name == "imm-sp") { + auto Count = requireOperandCount(Instruction, 1); + if (!Count) + return std::unexpected(Count.error()); + auto Immediate = formatAnyOperand(Instruction, 0, *Target, *this); + if (!Immediate) + return std::unexpected(Immediate.error()); + Operands = "sp, " + *Immediate; + } else if (Format->Name == "rd-imm-sp") { + auto Count = requireOperandCount(Instruction, 2); + if (!Count) + return std::unexpected(Count.error()); + auto Destination = formatRegisterOperand(Instruction, 0, *Target, *this); + if (!Destination) + return std::unexpected(Destination.error()); + auto Immediate = formatAnyOperand(Instruction, 1, *Target, *this); + if (!Immediate) + return std::unexpected(Immediate.error()); + Operands = *Destination + ", sp, " + *Immediate; + } else if (Format->Name == "rd-offset-sp" || Format->Name == "frd-offset-sp" || + Format->Name == "rs2-offset-sp" || Format->Name == "frs2-offset-sp") { + auto Count = requireOperandCount(Instruction, 2); + if (!Count) + return std::unexpected(Count.error()); + auto First = formatRegisterOperand(Instruction, 0, *Target, *this); + if (!First) + return std::unexpected(First.error()); + auto Offset = formatAnyOperand(Instruction, 1, *Target, *this); + if (!Offset) + return std::unexpected(Offset.error()); + Operands = *First + ", " + *Offset + "(sp)"; + } else { + return makeUnexpected(ErrorCode::AssemblyLoweringFailed, + "RISC-V assembly printer does not support generated format '" + + std::string(Format->Name) + "'"); + } + + std::string Result(Assembly->Mnemonic); + if (!Operands.empty()) + Result += " " + Operands; + return Result; +} + +Expected RISCVInstPrinter::printTargetExpression(std::uint32_t Kind, + std::string_view Operand) const { + switch (static_cast(Kind)) { + case RISCVMCExprKind::CallPLT: + return std::string(Operand); + case RISCVMCExprKind::PCRelativeHigh: + return "%pcrel_hi(" + std::string(Operand) + ")"; + case RISCVMCExprKind::PCRelativeLow: + return "%pcrel_lo(" + std::string(Operand) + ")"; + } + return makeUnexpected(ErrorCode::AssemblyLoweringFailed, + "RISC-V MC expression has an unknown target kind"); +} + +} // namespace rcc::riscv -- cgit v1.2.3