diff options
| author | Richard-Qin-X <richard.qin.001@gmail.com> | 2026-08-28 14:25:42 +0800 |
|---|---|---|
| committer | Richard-Qin-X <richard.qin.001@gmail.com> | 2026-08-28 14:25:42 +0800 |
| commit | 6889b82a5c9ecc6bd178760c66653d7af0121162 (patch) | |
| tree | d0465db788912487c36bd676656f416eaa8b1642 /backend/lib/Target/RISCV/RISCVAsmPrinter.cpp | |
| parent | 6e8feb15a0d256ca19e88185f78c81f689ce7d34 (diff) | |
| download | rcc-project-6889b82a5c9ecc6bd178760c66653d7af0121162.tar.gz rcc-project-6889b82a5c9ecc6bd178760c66653d7af0121162.tar.xz | |
[CodeGen] Separate assembly emission ownership
Diffstat (limited to 'backend/lib/Target/RISCV/RISCVAsmPrinter.cpp')
| -rw-r--r-- | backend/lib/Target/RISCV/RISCVAsmPrinter.cpp | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/backend/lib/Target/RISCV/RISCVAsmPrinter.cpp b/backend/lib/Target/RISCV/RISCVAsmPrinter.cpp new file mode 100644 index 0000000..095151c --- /dev/null +++ b/backend/lib/Target/RISCV/RISCVAsmPrinter.cpp @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "RISCVAsmPrinter.h" + +#include "rcc/CodeGen/MachineBasicBlock.h" +#include "rcc/CodeGen/MachineFunction.h" +#include "rcc/CodeGen/MachineJumpTableInfo.h" +#include "rcc/CodeGen/MachineMCContext.h" +#include "rcc/CodeGen/TargetConstant.h" +#include "rcc/MC/MCContext.h" +#include "rcc/MC/MCExpr.h" +#include "rcc/MC/MCStreamer.h" +#include "rcc/MC/MCSymbol.h" +#include "rcc/Target/RISCV/RISCVTargetRelocationKinds.h" + +#include <algorithm> +#include <cstddef> +#include <cstdint> +#include <ranges> +#include <span> +#include <utility> +#include <vector> + +namespace rcc::riscv { +namespace { + +[[nodiscard]] Expected<std::uint8_t> targetRelocationSize(TargetRelocationKindID Kind) { + if (Kind == targetRelocationKind(RISCVTargetRelocationKind::Absolute32)) + return 4; + if (Kind == targetRelocationKind(RISCVTargetRelocationKind::Absolute64)) + return 8; + return makeUnexpected(ErrorCode::Unsupported, + "RV64GC target constant has an unknown relocation kind"); +} + +[[nodiscard]] Expected<mc::MCExprRef> addOffset(mc::MCExprRef Expression, std::int64_t Offset) { + if (Offset == 0) + return Expression; + auto Result = mc::MCExpr::binary(mc::MCBinaryOperator::Add, std::move(Expression), + mc::MCExpr::constant(Offset)); + if (!Result) + return std::unexpected(Result.error()); + return *Result; +} + +[[nodiscard]] Expected<void> emitBytes(std::span<const std::byte> Bytes, mc::MCStreamer &Streamer) { + if (Bytes.empty()) + return {}; + std::vector<std::uint8_t> Storage; + Storage.reserve(Bytes.size()); + for (const std::byte Byte : Bytes) + Storage.push_back(std::to_integer<std::uint8_t>(Byte)); + return Streamer.emitBytes(Storage); +} + +} // namespace + +Expected<void> RISCVAsmPrinter::emitStartOfAsmFile() { + auto Attribute = streamer().emitDirective("attribute", "arch, \"rv64gc\""); + if (!Attribute) + return std::unexpected(Attribute.error()); + return streamer().emitDirective("attribute", "stack_align, 16"); +} + +Expected<void> RISCVAsmPrinter::emitEndOfAsmFile() { + mc::MCSectionDesc Note{ + .Name = ".note.GNU-stack", + .Kind = mc::MCSectionKind::Custom, + .Flags = {}, + .Alignment = 1, + .EntrySize = 0, + .Group = {}, + .UniqueID = std::nullopt, + }; + auto Section = machineContext().context().getOrCreateSection(std::move(Note)); + if (!Section) + return std::unexpected(Section.error()); + return streamer().switchSection(std::move(*Section)); +} + +Expected<void> RISCVAsmPrinter::emitTargetConstant(const TargetConstant &Constant) { + auto Emission = Constant.emit(); + if (!Emission) + return std::unexpected(Emission.error()); + auto DeclaredKind = Constant.relocationKind(); + if (!DeclaredKind) + return std::unexpected(DeclaredKind.error()); + if (Emission->Fixups.empty() != !DeclaredKind->has_value()) { + return makeUnexpected(ErrorCode::AssemblyLoweringFailed, + "RV64GC target constant relocation declaration is inconsistent"); + } + if (Emission->Fixups.empty()) + return emitBytes(Emission->Bytes, streamer()); + + std::vector<const TargetConstantFixup *> Fixups; + Fixups.reserve(Emission->Fixups.size()); + for (const TargetConstantFixup &Fixup : Emission->Fixups) { + if (Fixup.Kind != **DeclaredKind) { + return makeUnexpected(ErrorCode::AssemblyLoweringFailed, + "RV64GC target constant contains mixed relocation kinds"); + } + Fixups.push_back(&Fixup); + } + std::ranges::sort(Fixups, {}, [](const TargetConstantFixup *Fixup) { return Fixup->Offset; }); + + std::uint64_t Cursor = 0; + for (const TargetConstantFixup *Fixup : Fixups) { + auto Size = targetRelocationSize(Fixup->Kind); + if (!Size) + return std::unexpected(Size.error()); + if (Fixup->Offset < Cursor || Fixup->Offset > Emission->Bytes.size() || + *Size > Emission->Bytes.size() - static_cast<std::size_t>(Fixup->Offset)) { + return makeUnexpected(ErrorCode::AssemblyLoweringFailed, + "RV64GC target constant relocation storage is invalid"); + } + auto RawBytes = emitBytes(std::span<const std::byte>(Emission->Bytes) + .subspan(static_cast<std::size_t>(Cursor), + static_cast<std::size_t>(Fixup->Offset - Cursor)), + streamer()); + if (!RawBytes) + return std::unexpected(RawBytes.error()); + + auto Symbol = machineContext().symbol(Fixup->Symbol); + if (!Symbol) + return std::unexpected(Symbol.error()); + auto Expression = mc::MCExpr::symbol(std::move(*Symbol)); + if (!Expression) + return std::unexpected(Expression.error()); + auto WithAddend = addOffset(std::move(*Expression), Fixup->Addend); + if (!WithAddend) + return std::unexpected(WithAddend.error()); + auto Value = streamer().emitValue(std::move(*WithAddend), *Size); + if (!Value) + return std::unexpected(Value.error()); + Cursor = Fixup->Offset + *Size; + } + return emitBytes( + std::span<const std::byte>(Emission->Bytes).subspan(static_cast<std::size_t>(Cursor)), + streamer()); +} + +Expected<void> RISCVAsmPrinter::emitTargetJumpTable(const MachineFunction &Function, + const MachineJumpTableEntry &Entry) { + const MachineJumpTableDesc *Description = Entry.description(); + if (Description == nullptr) + return makeUnexpected(ErrorCode::InvalidArgument, "jump-table entry is not live"); + if (Description->Encoding == JumpTableEntryEncoding::Target) { + return makeUnexpected(ErrorCode::Unsupported, + "RV64GC jump table has an unknown target encoding"); + } + + mc::MCSymbolRef BaseSymbol; + if (Description->Encoding == JumpTableEntryEncoding::GPRelative32BlockAddress || + Description->Encoding == JumpTableEntryEncoding::GPRelative64BlockAddress) { + auto GlobalPointer = machineContext().symbol("__global_pointer$"); + if (!GlobalPointer) + return std::unexpected(GlobalPointer.error()); + BaseSymbol = std::move(*GlobalPointer); + } else if (Description->Encoding == JumpTableEntryEncoding::Custom32) { + BaseSymbol = machineContext().jumpTableSymbol(Function, Entry.index()); + } + + for (const MachineBasicBlock *TargetBlock : Description->Targets) { + if (TargetBlock == nullptr) + return makeUnexpected(ErrorCode::AssemblyLoweringFailed, "jump table has a null target"); + const mc::MCSymbolRef TargetSymbol = machineContext().blockSymbol(*TargetBlock); + if (!TargetSymbol) { + return makeUnexpected(ErrorCode::AssemblyLoweringFailed, + "jump-table target has no MC symbol"); + } + auto Expression = mc::MCExpr::symbol(TargetSymbol); + if (!Expression) + return std::unexpected(Expression.error()); + if (BaseSymbol) { + auto Base = mc::MCExpr::symbol(BaseSymbol); + if (!Base) + return std::unexpected(Base.error()); + Expression = mc::MCExpr::binary(mc::MCBinaryOperator::Subtract, std::move(*Expression), + std::move(*Base)); + if (!Expression) + return std::unexpected(Expression.error()); + } + auto Value = streamer().emitValue(std::move(*Expression), Description->EntrySize); + if (!Value) + return std::unexpected(Value.error()); + } + return {}; +} + +} // namespace rcc::riscv |
