diff options
Diffstat (limited to 'backend/include/rcc/MC')
| -rw-r--r-- | backend/include/rcc/MC/ELFObjectWriter.h | 45 | ||||
| -rw-r--r-- | backend/include/rcc/MC/MCAsmBackend.h | 55 | ||||
| -rw-r--r-- | backend/include/rcc/MC/MCAssembler.h | 131 | ||||
| -rw-r--r-- | backend/include/rcc/MC/MCCFI.h | 54 | ||||
| -rw-r--r-- | backend/include/rcc/MC/MCCodeEmitter.h | 30 | ||||
| -rw-r--r-- | backend/include/rcc/MC/MCContext.h | 43 | ||||
| -rw-r--r-- | backend/include/rcc/MC/MCDwarfFrameEmitter.h | 44 | ||||
| -rw-r--r-- | backend/include/rcc/MC/MCExpr.h | 109 | ||||
| -rw-r--r-- | backend/include/rcc/MC/MCFixup.h | 52 | ||||
| -rw-r--r-- | backend/include/rcc/MC/MCInst.h | 174 | ||||
| -rw-r--r-- | backend/include/rcc/MC/MCInstPrinter.h | 31 | ||||
| -rw-r--r-- | backend/include/rcc/MC/MCObjectStreamer.h | 59 | ||||
| -rw-r--r-- | backend/include/rcc/MC/MCObjectWriter.h | 79 | ||||
| -rw-r--r-- | backend/include/rcc/MC/MCSection.h | 108 | ||||
| -rw-r--r-- | backend/include/rcc/MC/MCStreamer.h | 97 | ||||
| -rw-r--r-- | backend/include/rcc/MC/MCSymbol.h | 56 | ||||
| -rw-r--r-- | backend/include/rcc/MC/TargetRegistry.h | 89 |
17 files changed, 1256 insertions, 0 deletions
diff --git a/backend/include/rcc/MC/ELFObjectWriter.h b/backend/include/rcc/MC/ELFObjectWriter.h new file mode 100644 index 0000000..2cd8879 --- /dev/null +++ b/backend/include/rcc/MC/ELFObjectWriter.h @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_MC_ELFOBJECTWRITER_H +#define RCC_MC_ELFOBJECTWRITER_H + +#include "rcc/MC/MCObjectWriter.h" + +#include <cstdint> +#include <string> +#include <utility> +#include <vector> + +namespace rcc::mc { + +struct ELFExtraSection final { + std::string Name; + std::uint32_t Type = 1; + std::uint64_t Flags = 0; + std::uint64_t Alignment = 1; + std::uint64_t EntrySize = 0; + std::vector<std::uint8_t> Contents; +}; + +struct ELFObjectTargetInfo final { + std::uint16_t Machine = 0; + std::uint8_t OSABI = 0; + std::uint8_t ABIVersion = 0; + std::uint32_t Flags = 0; + std::vector<ELFExtraSection> ExtraSections; +}; + +class ELF64LEObjectWriter final : public MCObjectWriter { +public: + explicit ELF64LEObjectWriter(ELFObjectTargetInfo Target) : Target(std::move(Target)) {} + + [[nodiscard]] Expected<std::vector<std::uint8_t>> + writeObject(const MCAssembledObject &Object) const override; + +private: + ELFObjectTargetInfo Target; +}; + +} // namespace rcc::mc + +#endif // RCC_MC_ELFOBJECTWRITER_H diff --git a/backend/include/rcc/MC/MCAsmBackend.h b/backend/include/rcc/MC/MCAsmBackend.h new file mode 100644 index 0000000..76e6214 --- /dev/null +++ b/backend/include/rcc/MC/MCAsmBackend.h @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_MC_MCASMBACKEND_H +#define RCC_MC_MCASMBACKEND_H + +#include "rcc/MC/MCFixup.h" +#include "rcc/MC/MCInst.h" +#include "rcc/Support/Error.h" + +#include <cstdint> +#include <span> +#include <vector> + +namespace rcc::mc { + +struct MCFixupKindInfo final { + std::uint8_t StorageSize = 0; + bool PCRelative = false; +}; + +struct MCFixupRelocation final { + std::uint32_t Type = 0; + MCSymbolRef Symbol; + std::int64_t Addend = 0; +}; + +class MCAsmBackend { +public: + virtual ~MCAsmBackend() = default; + + [[nodiscard]] virtual Expected<MCFixupKindInfo> fixupKindInfo(MCFixupKind Kind) const = 0; + [[nodiscard]] virtual Expected<void> applyFixup(MCFixupKind Kind, std::span<std::uint8_t> Data, + std::uint64_t Offset, + std::int64_t Value) const = 0; + [[nodiscard]] virtual Expected<std::uint32_t> relocationType(const MCFixup &Fixup, + const MCValue &Value) const = 0; + [[nodiscard]] virtual Expected<std::vector<MCFixupRelocation>> + relocationsForFixup(const MCFixup &Fixup, const MCValue &Value) const; + + [[nodiscard]] virtual bool mayNeedRelaxation(const MCInst &) const noexcept { + return false; + } + [[nodiscard]] virtual Expected<bool> fixupNeedsRelaxation(const MCFixup &, std::int64_t) const { + return false; + } + [[nodiscard]] virtual Expected<MCInst> relaxInstruction(const MCInst &) const; + + [[nodiscard]] virtual std::uint32_t objectFlags() const noexcept { + return 0; + } +}; + +} // namespace rcc::mc + +#endif // RCC_MC_MCASMBACKEND_H diff --git a/backend/include/rcc/MC/MCAssembler.h b/backend/include/rcc/MC/MCAssembler.h new file mode 100644 index 0000000..7a75498 --- /dev/null +++ b/backend/include/rcc/MC/MCAssembler.h @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_MC_MCASSEMBLER_H +#define RCC_MC_MCASSEMBLER_H + +#include "rcc/MC/MCAsmBackend.h" +#include "rcc/MC/MCCodeEmitter.h" +#include "rcc/MC/MCDwarfFrameEmitter.h" +#include "rcc/MC/MCObjectWriter.h" +#include "rcc/MC/MCStreamer.h" +#include "rcc/Support/Error.h" + +#include <cstddef> +#include <cstdint> +#include <memory> +#include <optional> +#include <span> +#include <unordered_map> +#include <variant> +#include <vector> + +namespace rcc::mc { + +class MCAssembler final { +public: + MCAssembler(const MCCodeEmitter &Emitter, const MCAsmBackend &Backend) noexcept + : Emitter(&Emitter), Backend(&Backend) {} + + [[nodiscard]] Expected<void> switchSection(MCSectionRef Section); + [[nodiscard]] Expected<void> emitLabel(MCSymbolRef Symbol); + [[nodiscard]] Expected<void> emitInstruction(const MCInst &Instruction); + [[nodiscard]] Expected<void> emitValue(MCExprRef Value, std::uint8_t Size); + [[nodiscard]] Expected<void> emitBytes(std::span<const std::uint8_t> Bytes); + [[nodiscard]] Expected<void> emitZeroFill(std::uint64_t Size); + [[nodiscard]] Expected<void> emitAlignment(std::uint64_t Alignment, std::uint8_t Fill, + std::uint64_t MaximumBytes); + [[nodiscard]] Expected<void> emitSymbolAttribute(MCSymbolRef Symbol, MCSymbolAttribute Attribute); + [[nodiscard]] Expected<void> emitSymbolSize(MCSymbolRef Symbol, MCExprRef Size); + [[nodiscard]] Expected<void> emitCommonSymbol(MCSymbolRef Symbol, std::uint64_t Size, + std::uint64_t Alignment); + [[nodiscard]] Expected<void> emitCFI(const MCCFIInstruction &Instruction); + [[nodiscard]] Expected<void> configureDwarfFrame(MCSectionRef Section, MCDwarfFrameInfo Info); + + [[nodiscard]] Expected<MCAssembledObject> assemble(); + +private: + struct InstructionFragment final { + MCInst Instruction; + }; + struct DataFragment final { + std::vector<std::uint8_t> Bytes; + std::vector<MCFixup> Fixups; + }; + struct AlignmentFragment final { + std::uint64_t Alignment = 1; + std::uint8_t Fill = 0; + std::uint64_t MaximumBytes = 0; + }; + struct ZeroFillFragment final { + std::uint64_t Size = 0; + }; + using FragmentPayload = + std::variant<InstructionFragment, DataFragment, AlignmentFragment, ZeroFillFragment>; + + struct Fragment final { + FragmentPayload Payload; + std::uint64_t Offset = 0; + std::uint64_t Size = 0; + std::vector<std::uint8_t> EncodedBytes; + std::vector<MCFixup> Fixups; + }; + + struct SectionData final { + MCSectionRef Section; + std::vector<Fragment> Fragments; + std::uint64_t AddressSize = 0; + std::uint64_t Alignment = 1; + }; + + struct SymbolData final { + MCSymbolRef Symbol; + MCObjectSymbolBinding Binding = MCObjectSymbolBinding::Local; + bool BindingWasSet = false; + MCObjectSymbolType Type = MCObjectSymbolType::None; + MCObjectSymbolVisibility Visibility = MCObjectSymbolVisibility::Default; + std::optional<std::size_t> SectionIndex; + std::size_t FragmentIndex = 0; + MCExprRef Size; + std::uint64_t CommonSize = 0; + std::uint64_t CommonAlignment = 0; + }; + + struct CFIEvent final { + MCCFIInstruction Instruction; + std::size_t FragmentIndex = 0; + }; + + struct CFIProcedure final { + MCSymbolRef Function; + std::size_t SectionIndex = 0; + std::size_t BeginFragmentIndex = 0; + std::size_t EndFragmentIndex = 0; + std::vector<CFIEvent> Events; + bool IsClosed = false; + }; + + [[nodiscard]] Expected<std::size_t> currentSectionIndex() const; + [[nodiscard]] SymbolData &getOrCreateSymbol(MCSymbolRef Symbol); + [[nodiscard]] Expected<void> encodeFragments(); + [[nodiscard]] Expected<bool> layoutAndRelax(); + [[nodiscard]] Expected<MCAssembledObject> finalizeObject(); + [[nodiscard]] Expected<void> appendDwarfFrame(MCAssembledObject &Object) const; + [[nodiscard]] std::optional<std::uint64_t> symbolOffset(const SymbolData &Symbol) const; + + const MCCodeEmitter *Emitter; + const MCAsmBackend *Backend; + std::vector<SectionData> Sections; + std::unordered_map<const MCSection *, std::size_t> SectionIndices; + std::vector<SymbolData> Symbols; + std::unordered_map<const MCSymbol *, std::size_t> SymbolIndices; + std::optional<std::size_t> CurrentSection; + std::vector<CFIProcedure> CFIProcedures; + std::optional<std::size_t> ActiveCFIProcedure; + MCSectionRef EHFrameSection; + std::optional<MCDwarfFrameInfo> DwarfFrameInfo; + bool WasAssembled = false; +}; + +} // namespace rcc::mc + +#endif // RCC_MC_MCASSEMBLER_H diff --git a/backend/include/rcc/MC/MCCFI.h b/backend/include/rcc/MC/MCCFI.h new file mode 100644 index 0000000..e6ac396 --- /dev/null +++ b/backend/include/rcc/MC/MCCFI.h @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_MC_MCCFI_H +#define RCC_MC_MCCFI_H + +#include "rcc/MC/MCSymbol.h" +#include "rcc/Support/Error.h" + +#include <cstdint> +#include <vector> + +namespace rcc::mc { + +enum class MCCFIOperation : std::uint8_t { + StartProc, + EndProc, + Sections, + Personality, + LSDA, + SignalFrame, + ReturnColumn, + SameValue, + RememberState, + RestoreState, + Offset, + DefCFARegister, + DefCFAOffset, + DefCFA, + RelativeOffset, + AdjustCFAOffset, + Escape, + Restore, + Undefined, + Register, + WindowSave, + NegateReturnAddressState, + NegateReturnAddressStateWithPC, + GNUArgsSize, + Label, + ValueOffset, +}; + +struct MCCFIInstruction final { + MCCFIOperation Operation = MCCFIOperation::StartProc; + std::vector<std::int64_t> Operands; + std::vector<std::uint8_t> Bytes; + MCSymbolRef Symbol; + + [[nodiscard]] Expected<void> verify() const; +}; + +} // namespace rcc::mc + +#endif // RCC_MC_MCCFI_H diff --git a/backend/include/rcc/MC/MCCodeEmitter.h b/backend/include/rcc/MC/MCCodeEmitter.h new file mode 100644 index 0000000..7307a83 --- /dev/null +++ b/backend/include/rcc/MC/MCCodeEmitter.h @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_MC_MCCODEEMITTER_H +#define RCC_MC_MCCODEEMITTER_H + +#include "rcc/MC/MCFixup.h" +#include "rcc/MC/MCInst.h" +#include "rcc/Support/Error.h" + +#include <cstdint> +#include <vector> + +namespace rcc::mc { + +struct MCEncodedInstruction final { + std::vector<std::uint8_t> Bytes; + std::vector<MCFixup> Fixups; +}; + +class MCCodeEmitter { +public: + virtual ~MCCodeEmitter() = default; + + [[nodiscard]] virtual Expected<MCEncodedInstruction> + encodeInstruction(const MCInst &Instruction) const = 0; +}; + +} // namespace rcc::mc + +#endif // RCC_MC_MCCODEEMITTER_H diff --git a/backend/include/rcc/MC/MCContext.h b/backend/include/rcc/MC/MCContext.h new file mode 100644 index 0000000..e9b2d90 --- /dev/null +++ b/backend/include/rcc/MC/MCContext.h @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_MC_MCCONTEXT_H +#define RCC_MC_MCCONTEXT_H + +#include "rcc/MC/MCSection.h" +#include "rcc/MC/MCSymbol.h" +#include "rcc/Support/Error.h" + +#include <cstdint> +#include <functional> +#include <string> +#include <string_view> +#include <unordered_map> + +namespace rcc::mc { + +class MCContext final { +public: + [[nodiscard]] Expected<MCSymbolRef> getOrCreateSymbol(std::string Name, MCSymbolKind Kind); + [[nodiscard]] Expected<MCSymbolRef> createTemporarySymbol(std::string_view Prefix); + [[nodiscard]] MCSymbolRef symbol(std::string_view Name) const noexcept; + + [[nodiscard]] Expected<MCSectionRef> getOrCreateSection(MCSectionDesc Description); + [[nodiscard]] MCSectionRef section(std::string_view Name) const noexcept; + +private: + struct StringHash final { + using is_transparent = void; // NOLINT(readability-identifier-naming) + + [[nodiscard]] std::size_t operator()(std::string_view Value) const noexcept { + return std::hash<std::string_view>{}(Value); + } + }; + + std::unordered_map<std::string, MCSymbolRef, StringHash, std::equal_to<>> Symbols; + std::unordered_map<std::string, MCSectionRef, StringHash, std::equal_to<>> Sections; + std::uint64_t NextTemporarySymbol = 0; +}; + +} // namespace rcc::mc + +#endif // RCC_MC_MCCONTEXT_H diff --git a/backend/include/rcc/MC/MCDwarfFrameEmitter.h b/backend/include/rcc/MC/MCDwarfFrameEmitter.h new file mode 100644 index 0000000..f338f36 --- /dev/null +++ b/backend/include/rcc/MC/MCDwarfFrameEmitter.h @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_MC_MCDWARFFRAMEEMITTER_H +#define RCC_MC_MCDWARFFRAMEEMITTER_H + +#include "rcc/MC/MCAsmBackend.h" +#include "rcc/MC/MCCFI.h" +#include "rcc/MC/MCObjectWriter.h" +#include "rcc/Support/Error.h" + +#include <cstdint> +#include <span> +#include <vector> + +namespace rcc::mc { + +struct MCDwarfFrameInfo final { + std::uint64_t CodeAlignment = 1; + std::int64_t DataAlignment = -8; + std::uint32_t ReturnAddressRegister = 0; + std::uint32_t InitialCFARegister = 0; + std::uint64_t InitialCFAOffset = 0; + + [[nodiscard]] Expected<void> verify() const; +}; + +struct MCDwarfFrameInstruction final { + MCCFIInstruction Instruction; + std::uint64_t Offset = 0; +}; + +struct MCDwarfFrameProcedure final { + MCSymbolRef Function; + std::uint64_t AddressRange = 0; + std::vector<MCDwarfFrameInstruction> Instructions; +}; + +[[nodiscard]] Expected<MCObjectSection> +emitDwarfEHFrame(MCSectionRef Section, std::span<const MCDwarfFrameProcedure> Procedures, + const MCDwarfFrameInfo &Info, const MCAsmBackend &Backend); + +} // namespace rcc::mc + +#endif // RCC_MC_MCDWARFFRAMEEMITTER_H diff --git a/backend/include/rcc/MC/MCExpr.h b/backend/include/rcc/MC/MCExpr.h new file mode 100644 index 0000000..15ff6fd --- /dev/null +++ b/backend/include/rcc/MC/MCExpr.h @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_MC_MCEXPR_H +#define RCC_MC_MCEXPR_H + +#include "rcc/MC/MCSymbol.h" +#include "rcc/Support/Error.h" + +#include <cstddef> +#include <cstdint> +#include <memory> +#include <optional> +#include <variant> + +namespace rcc::mc { + +class MCExpr; +using MCExprRef = std::shared_ptr<const MCExpr>; + +enum class MCUnaryOperator : std::uint8_t { + Plus, + Minus, + BitwiseNot, + LogicalNot, +}; + +enum class MCBinaryOperator : std::uint8_t { + Add, + Subtract, + Multiply, + Divide, + Modulo, + ShiftLeft, + ShiftRight, + BitwiseAnd, + BitwiseOr, + BitwiseXor, + LogicalAnd, + LogicalOr, + Equal, + NotEqual, + Less, + LessEqual, + Greater, + GreaterEqual, +}; + +struct MCSymbolRefExpr final { + MCSymbolRef Symbol; +}; + +struct MCUnaryExpr final { + MCUnaryOperator Operator = MCUnaryOperator::Plus; + MCExprRef Operand; +}; + +struct MCBinaryExpr final { + MCBinaryOperator Operator = MCBinaryOperator::Add; + MCExprRef Left; + MCExprRef Right; +}; + +struct MCTargetExpr final { + std::uint32_t Kind = 0; + MCExprRef Operand; +}; + +class MCExpr final { +public: + enum class Kind : std::uint8_t { + Constant, + SymbolRef, + Unary, + Binary, + Target, + }; + + [[nodiscard]] static MCExprRef constant(std::int64_t Value); + [[nodiscard]] static Expected<MCExprRef> symbol(MCSymbolRef Symbol); + [[nodiscard]] static Expected<MCExprRef> unary(MCUnaryOperator Operator, MCExprRef Operand); + [[nodiscard]] static Expected<MCExprRef> binary(MCBinaryOperator Operator, MCExprRef Left, + MCExprRef Right); + [[nodiscard]] static Expected<MCExprRef> target(std::uint32_t Kind, MCExprRef Operand); + + [[nodiscard]] Kind kind() const noexcept { + return ExpressionKind; + } + + template <typename ValueT> [[nodiscard]] const ValueT *getIf() const noexcept { + return std::get_if<ValueT>(&Storage); + } + + [[nodiscard]] Expected<void> verify(std::size_t MaximumDepth = 256) const; + [[nodiscard]] std::optional<std::int64_t> evaluateAbsolute() const noexcept; + +private: + using StorageT = + std::variant<std::int64_t, MCSymbolRefExpr, MCUnaryExpr, MCBinaryExpr, MCTargetExpr>; + + MCExpr(Kind ExpressionKind, StorageT Storage) + : ExpressionKind(ExpressionKind), Storage(std::move(Storage)) {} + + Kind ExpressionKind; + StorageT Storage; +}; + +} // namespace rcc::mc + +#endif // RCC_MC_MCEXPR_H diff --git a/backend/include/rcc/MC/MCFixup.h b/backend/include/rcc/MC/MCFixup.h new file mode 100644 index 0000000..3329fab --- /dev/null +++ b/backend/include/rcc/MC/MCFixup.h @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_MC_MCFIXUP_H +#define RCC_MC_MCFIXUP_H + +#include "rcc/MC/MCExpr.h" +#include "rcc/Support/Error.h" + +#include <cstdint> + +namespace rcc::mc { + +using MCFixupKind = std::uint16_t; + +namespace fixup_kind { + +inline constexpr MCFixupKind None = 0; +inline constexpr MCFixupKind Data1 = 1; +inline constexpr MCFixupKind Data2 = 2; +inline constexpr MCFixupKind Data4 = 3; +inline constexpr MCFixupKind Data8 = 4; +inline constexpr MCFixupKind PCRelative4 = 5; +inline constexpr MCFixupKind FirstTarget = 256; + +} // namespace fixup_kind + +struct MCFixup final { + std::uint64_t Offset = 0; + MCExprRef Value; + MCFixupKind Kind = fixup_kind::None; + bool PCRelative = false; + bool LinkerRelaxable = false; + + [[nodiscard]] Expected<void> verify() const; +}; + +struct MCValue final { + MCSymbolRef AddSymbol; + MCSymbolRef SubtractSymbol; + std::int64_t Addend = 0; + std::uint32_t TargetKind = 0; + + [[nodiscard]] bool isAbsolute() const noexcept { + return !AddSymbol && !SubtractSymbol; + } +}; + +[[nodiscard]] Expected<MCValue> evaluateAsRelocatable(const MCExpr &Expression); + +} // namespace rcc::mc + +#endif // RCC_MC_MCFIXUP_H diff --git a/backend/include/rcc/MC/MCInst.h b/backend/include/rcc/MC/MCInst.h new file mode 100644 index 0000000..c6da93b --- /dev/null +++ b/backend/include/rcc/MC/MCInst.h @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_MC_MCINST_H +#define RCC_MC_MCINST_H + +#include "rcc/MC/MCExpr.h" + +#include <cstddef> +#include <cstdint> +#include <span> +#include <utility> +#include <variant> +#include <vector> + +namespace rcc::mc { + +class MCRegister final { +public: + constexpr MCRegister() noexcept = default; + + [[nodiscard]] static constexpr MCRegister fromValue(std::uint32_t Value) noexcept { + return MCRegister(Value); + } + + [[nodiscard]] constexpr std::uint32_t value() const noexcept { + return Value; + } + + [[nodiscard]] constexpr bool isValid() const noexcept { + return Value != 0; + } + + friend constexpr bool operator==(MCRegister Left, MCRegister Right) noexcept = default; + +private: + explicit constexpr MCRegister(std::uint32_t Value) noexcept : Value(Value) {} + + std::uint32_t Value = 0; +}; + +class MCOpcode final { +public: + constexpr MCOpcode() noexcept = default; + + [[nodiscard]] static constexpr MCOpcode fromValue(std::uint32_t Value) noexcept { + return MCOpcode(Value); + } + + [[nodiscard]] constexpr std::uint32_t value() const noexcept { + return Value; + } + + [[nodiscard]] constexpr bool isValid() const noexcept { + return Value != 0; + } + + friend constexpr bool operator==(MCOpcode Left, MCOpcode Right) noexcept = default; + +private: + explicit constexpr MCOpcode(std::uint32_t Value) noexcept : Value(Value) {} + + std::uint32_t Value = 0; +}; + +class MCOperand final { +public: + enum class Kind : std::uint8_t { + Register, + Immediate, + Float32Bits, + Float64Bits, + Expression, + }; + + [[nodiscard]] static MCOperand registerOperand(MCRegister Register) noexcept { + return MCOperand(Kind::Register, Register); + } + + [[nodiscard]] static MCOperand immediate(std::int64_t Value) noexcept { + return MCOperand(Kind::Immediate, Value); + } + + [[nodiscard]] static MCOperand float32Bits(std::uint32_t Value) noexcept { + return MCOperand(Kind::Float32Bits, Value); + } + + [[nodiscard]] static MCOperand float64Bits(std::uint64_t Value) noexcept { + return MCOperand(Kind::Float64Bits, Value); + } + + [[nodiscard]] static MCOperand expression(MCExprRef Value) { + return MCOperand(Kind::Expression, std::move(Value)); + } + + [[nodiscard]] Kind kind() const noexcept { + return OperandKind; + } + + [[nodiscard]] const MCRegister *registerValue() const noexcept { + return std::get_if<MCRegister>(&Storage); + } + + [[nodiscard]] const std::int64_t *immediateValue() const noexcept { + return std::get_if<std::int64_t>(&Storage); + } + + [[nodiscard]] const std::uint32_t *float32BitsValue() const noexcept { + return std::get_if<std::uint32_t>(&Storage); + } + + [[nodiscard]] const std::uint64_t *float64BitsValue() const noexcept { + return std::get_if<std::uint64_t>(&Storage); + } + + [[nodiscard]] const MCExprRef *expressionValue() const noexcept { + return std::get_if<MCExprRef>(&Storage); + } + +private: + using StorageT = std::variant<MCRegister, std::int64_t, std::uint32_t, std::uint64_t, MCExprRef>; + + MCOperand(Kind OperandKind, StorageT Storage) + : OperandKind(OperandKind), Storage(std::move(Storage)) {} + + Kind OperandKind; + StorageT Storage; +}; + +class MCInst final { +public: + explicit MCInst(MCOpcode InstructionOpcode) : InstructionOpcode(InstructionOpcode) {} + + [[nodiscard]] MCOpcode opcode() const noexcept { + return InstructionOpcode; + } + + void setFlags(std::uint32_t NewFlags) noexcept { + Flags = NewFlags; + } + + [[nodiscard]] std::uint32_t flags() const noexcept { + return Flags; + } + + void setSourceIdentity(std::uint64_t Identity) noexcept { + SourceIdentity = Identity; + } + + [[nodiscard]] std::uint64_t sourceIdentity() const noexcept { + return SourceIdentity; + } + + void reserveOperands(std::size_t Count) { + Operands.reserve(Count); + } + + void addOperand(MCOperand Operand) { + Operands.push_back(std::move(Operand)); + } + + [[nodiscard]] std::span<const MCOperand> operands() const noexcept { + return Operands; + } + +private: + MCOpcode InstructionOpcode; + std::uint32_t Flags = 0; + std::uint64_t SourceIdentity = 0; + std::vector<MCOperand> Operands; +}; + +} // namespace rcc::mc + +#endif // RCC_MC_MCINST_H diff --git a/backend/include/rcc/MC/MCInstPrinter.h b/backend/include/rcc/MC/MCInstPrinter.h new file mode 100644 index 0000000..6024ced --- /dev/null +++ b/backend/include/rcc/MC/MCInstPrinter.h @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_MC_MCINSTPRINTER_H +#define RCC_MC_MCINSTPRINTER_H + +#include "rcc/MC/MCInst.h" +#include "rcc/Support/Error.h" + +#include <cstdint> +#include <string> +#include <string_view> + +namespace rcc::mc { + +class MCInstPrinter { +public: + virtual ~MCInstPrinter() = default; + + [[nodiscard]] virtual Expected<std::string> printInstruction(const MCInst &Instruction) const = 0; + + [[nodiscard]] virtual Expected<std::string> + printTargetExpression(std::uint32_t Kind, std::string_view Operand) const = 0; +}; + +[[nodiscard]] Expected<std::string> printMCExpression(const MCExpr &Expression, + const MCInstPrinter &Printer); +[[nodiscard]] Expected<std::string> printMCSymbolName(std::string_view Name); + +} // namespace rcc::mc + +#endif // RCC_MC_MCINSTPRINTER_H diff --git a/backend/include/rcc/MC/MCObjectStreamer.h b/backend/include/rcc/MC/MCObjectStreamer.h new file mode 100644 index 0000000..4a6b56c --- /dev/null +++ b/backend/include/rcc/MC/MCObjectStreamer.h @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_MC_MCOBJECTSTREAMER_H +#define RCC_MC_MCOBJECTSTREAMER_H + +#include "rcc/MC/MCAssembler.h" +#include "rcc/MC/MCObjectWriter.h" +#include "rcc/MC/MCStreamer.h" + +#include <cstdint> +#include <span> +#include <string_view> +#include <vector> + +namespace rcc::mc { + +class ELFObjectStreamer final : public MCStreamer { +public: + ELFObjectStreamer(const MCCodeEmitter &Emitter, const MCAsmBackend &Backend, + const MCObjectWriter &Writer) noexcept + : Assembler(Emitter, Backend), Writer(&Writer) {} + + [[nodiscard]] Expected<void> switchSection(MCSectionRef Section) override; + [[nodiscard]] Expected<void> emitLabel(MCSymbolRef Symbol) override; + [[nodiscard]] Expected<void> emitInstruction(const MCInst &Instruction) override; + [[nodiscard]] Expected<void> emitValue(MCExprRef Value, std::uint8_t Size) override; + [[nodiscard]] Expected<void> emitBytes(std::span<const std::uint8_t> Bytes) override; + [[nodiscard]] Expected<void> emitZeroFill(std::uint64_t Size) override; + [[nodiscard]] Expected<void> emitAlignment(std::uint64_t Alignment, std::uint8_t Fill = 0, + std::uint64_t MaximumBytes = 0) override; + [[nodiscard]] Expected<void> emitSymbolAttribute(MCSymbolRef Symbol, + MCSymbolAttribute Attribute) override; + [[nodiscard]] Expected<void> emitSymbolSize(MCSymbolRef Symbol, MCExprRef Size) override; + [[nodiscard]] Expected<void> emitCommonSymbol(MCSymbolRef Symbol, std::uint64_t Size, + std::uint64_t Alignment) override; + [[nodiscard]] Expected<void> emitDirective(std::string_view Name, + std::string_view Arguments = {}) override; + [[nodiscard]] Expected<void> emitCFI(const MCCFIInstruction &Instruction) override; + [[nodiscard]] Expected<void> emitInlineAssembly(std::string_view Text) override; + [[nodiscard]] Expected<void> emitComment(std::string_view Text) override; + [[nodiscard]] Expected<void> finish() override; + + [[nodiscard]] Expected<void> configureDwarfFrame(MCSectionRef Section, MCDwarfFrameInfo Info); + + [[nodiscard]] Expected<std::vector<std::uint8_t>> takeOutput(); + +private: + [[nodiscard]] Expected<void> ensureOpen() const; + + MCAssembler Assembler; + const MCObjectWriter *Writer; + std::vector<std::uint8_t> Output; + bool IsFinished = false; + bool OutputWasTaken = false; +}; + +} // namespace rcc::mc + +#endif // RCC_MC_MCOBJECTSTREAMER_H diff --git a/backend/include/rcc/MC/MCObjectWriter.h b/backend/include/rcc/MC/MCObjectWriter.h new file mode 100644 index 0000000..16c6a50 --- /dev/null +++ b/backend/include/rcc/MC/MCObjectWriter.h @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_MC_MCOBJECTWRITER_H +#define RCC_MC_MCOBJECTWRITER_H + +#include "rcc/MC/MCSection.h" +#include "rcc/MC/MCSymbol.h" +#include "rcc/Support/Error.h" + +#include <cstddef> +#include <cstdint> +#include <optional> +#include <vector> + +namespace rcc::mc { + +enum class MCObjectSymbolBinding : std::uint8_t { + Local, + Global, + Weak, +}; + +enum class MCObjectSymbolType : std::uint8_t { + None, + Function, + Object, + TLSObject, + Section, +}; + +enum class MCObjectSymbolVisibility : std::uint8_t { + Default, + Hidden, + Protected, +}; + +struct MCObjectRelocation final { + std::uint64_t Offset = 0; + std::uint32_t Type = 0; + MCSymbolRef Symbol; + std::int64_t Addend = 0; +}; + +struct MCObjectSection final { + MCSectionRef Section; + std::vector<std::uint8_t> Contents; + std::uint64_t AddressSize = 0; + std::uint64_t Alignment = 1; + std::vector<MCObjectRelocation> Relocations; +}; + +struct MCObjectSymbol final { + MCSymbolRef Symbol; + MCObjectSymbolBinding Binding = MCObjectSymbolBinding::Local; + MCObjectSymbolType Type = MCObjectSymbolType::None; + MCObjectSymbolVisibility Visibility = MCObjectSymbolVisibility::Default; + std::optional<std::size_t> SectionIndex; + std::uint64_t Value = 0; + std::uint64_t Size = 0; + std::uint64_t CommonAlignment = 0; +}; + +struct MCAssembledObject final { + std::vector<MCObjectSection> Sections; + std::vector<MCObjectSymbol> Symbols; + std::uint32_t Flags = 0; +}; + +class MCObjectWriter { +public: + virtual ~MCObjectWriter() = default; + + [[nodiscard]] virtual Expected<std::vector<std::uint8_t>> + writeObject(const MCAssembledObject &Object) const = 0; +}; + +} // namespace rcc::mc + +#endif // RCC_MC_MCOBJECTWRITER_H diff --git a/backend/include/rcc/MC/MCSection.h b/backend/include/rcc/MC/MCSection.h new file mode 100644 index 0000000..4f76427 --- /dev/null +++ b/backend/include/rcc/MC/MCSection.h @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_MC_MCSECTION_H +#define RCC_MC_MCSECTION_H + +#include "rcc/MC/MCSymbol.h" +#include "rcc/Support/Error.h" + +#include <cstdint> +#include <initializer_list> +#include <memory> +#include <optional> +#include <string> +#include <string_view> + +namespace rcc::mc { + +enum class MCSectionKind : std::uint8_t { + Text, + ReadOnly, + Data, + BSS, + TLSData, + TLSBSS, + EHFrame, + Custom, +}; + +enum class MCSectionFlag : std::uint8_t { + Alloc, + Executable, + Writable, + Merge, + Strings, + TLS, + Group, + Retain, + Count, +}; + +class MCSectionFlags final { +public: + constexpr MCSectionFlags() noexcept = default; + + constexpr MCSectionFlags(std::initializer_list<MCSectionFlag> Flags) noexcept { + for (const MCSectionFlag Flag : Flags) + set(Flag); + } + + constexpr void set(MCSectionFlag Flag) noexcept { + const auto Index = static_cast<std::uint8_t>(Flag); + if (Index < static_cast<std::uint8_t>(MCSectionFlag::Count)) + Mask |= std::uint16_t{1} << Index; + } + + [[nodiscard]] constexpr bool has(MCSectionFlag Flag) const noexcept { + const auto Index = static_cast<std::uint8_t>(Flag); + return Index < static_cast<std::uint8_t>(MCSectionFlag::Count) && + (Mask & (std::uint16_t{1} << Index)) != 0; + } + + [[nodiscard]] constexpr std::uint16_t rawValue() const noexcept { + return Mask; + } + + friend constexpr bool operator==(MCSectionFlags Left, MCSectionFlags Right) noexcept = default; + +private: + std::uint16_t Mask = 0; +}; + +struct MCSectionDesc final { + std::string Name; + MCSectionKind Kind = MCSectionKind::Custom; + MCSectionFlags Flags; + std::uint64_t Alignment = 1; + std::uint64_t EntrySize = 0; + MCSymbolRef Group; + std::optional<std::uint64_t> UniqueID; + + [[nodiscard]] Expected<void> verify() const; + + friend bool operator==(const MCSectionDesc &Left, const MCSectionDesc &Right) = default; +}; + +class MCSection final { +public: + [[nodiscard]] std::string_view name() const noexcept { + return Description.Name; + } + + [[nodiscard]] const MCSectionDesc &description() const noexcept { + return Description; + } + +private: + explicit MCSection(MCSectionDesc Description) : Description(std::move(Description)) {} + + MCSectionDesc Description; + + friend class MCContext; +}; + +using MCSectionRef = std::shared_ptr<const MCSection>; + +} // namespace rcc::mc + +#endif // RCC_MC_MCSECTION_H diff --git a/backend/include/rcc/MC/MCStreamer.h b/backend/include/rcc/MC/MCStreamer.h new file mode 100644 index 0000000..ea37178 --- /dev/null +++ b/backend/include/rcc/MC/MCStreamer.h @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_MC_MCSTREAMER_H +#define RCC_MC_MCSTREAMER_H + +#include "rcc/MC/MCCFI.h" +#include "rcc/MC/MCInst.h" +#include "rcc/MC/MCInstPrinter.h" +#include "rcc/MC/MCSection.h" +#include "rcc/MC/MCSymbol.h" +#include "rcc/Support/Error.h" + +#include <cstdint> +#include <span> +#include <string> +#include <string_view> +#include <unordered_set> + +namespace rcc::mc { + +enum class MCSymbolAttribute : std::uint8_t { + Global, + Weak, + Local, + Hidden, + Protected, + Function, + Object, + TLSObject, +}; + +class MCStreamer { +public: + virtual ~MCStreamer() = default; + + [[nodiscard]] virtual Expected<void> switchSection(MCSectionRef Section) = 0; + [[nodiscard]] virtual Expected<void> emitLabel(MCSymbolRef Symbol) = 0; + [[nodiscard]] virtual Expected<void> emitInstruction(const MCInst &Instruction) = 0; + [[nodiscard]] virtual Expected<void> emitValue(MCExprRef Value, std::uint8_t Size) = 0; + [[nodiscard]] virtual Expected<void> emitBytes(std::span<const std::uint8_t> Bytes) = 0; + [[nodiscard]] virtual Expected<void> emitZeroFill(std::uint64_t Size) = 0; + [[nodiscard]] virtual Expected<void> emitAlignment(std::uint64_t Alignment, std::uint8_t Fill = 0, + std::uint64_t MaximumBytes = 0) = 0; + [[nodiscard]] virtual Expected<void> emitSymbolAttribute(MCSymbolRef Symbol, + MCSymbolAttribute Attribute) = 0; + [[nodiscard]] virtual Expected<void> emitSymbolSize(MCSymbolRef Symbol, MCExprRef Size) = 0; + [[nodiscard]] virtual Expected<void> emitCommonSymbol(MCSymbolRef Symbol, std::uint64_t Size, + std::uint64_t Alignment) = 0; + [[nodiscard]] virtual Expected<void> emitDirective(std::string_view Name, + std::string_view Arguments = {}) = 0; + [[nodiscard]] virtual Expected<void> emitCFI(const MCCFIInstruction &Instruction) = 0; + [[nodiscard]] virtual Expected<void> emitInlineAssembly(std::string_view Text) = 0; + [[nodiscard]] virtual Expected<void> emitComment(std::string_view Text) = 0; + [[nodiscard]] virtual Expected<void> finish() = 0; +}; + +class AsmTextStreamer final : public MCStreamer { +public: + explicit AsmTextStreamer(const MCInstPrinter &Printer) noexcept : Printer(&Printer) {} + + [[nodiscard]] Expected<void> switchSection(MCSectionRef Section) override; + [[nodiscard]] Expected<void> emitLabel(MCSymbolRef Symbol) override; + [[nodiscard]] Expected<void> emitInstruction(const MCInst &Instruction) override; + [[nodiscard]] Expected<void> emitValue(MCExprRef Value, std::uint8_t Size) override; + [[nodiscard]] Expected<void> emitBytes(std::span<const std::uint8_t> Bytes) override; + [[nodiscard]] Expected<void> emitZeroFill(std::uint64_t Size) override; + [[nodiscard]] Expected<void> emitAlignment(std::uint64_t Alignment, std::uint8_t Fill = 0, + std::uint64_t MaximumBytes = 0) override; + [[nodiscard]] Expected<void> emitSymbolAttribute(MCSymbolRef Symbol, + MCSymbolAttribute Attribute) override; + [[nodiscard]] Expected<void> emitSymbolSize(MCSymbolRef Symbol, MCExprRef Size) override; + [[nodiscard]] Expected<void> emitCommonSymbol(MCSymbolRef Symbol, std::uint64_t Size, + std::uint64_t Alignment) override; + [[nodiscard]] Expected<void> emitDirective(std::string_view Name, + std::string_view Arguments = {}) override; + [[nodiscard]] Expected<void> emitCFI(const MCCFIInstruction &Instruction) override; + [[nodiscard]] Expected<void> emitInlineAssembly(std::string_view Text) override; + [[nodiscard]] Expected<void> emitComment(std::string_view Text) override; + [[nodiscard]] Expected<void> finish() override; + + [[nodiscard]] Expected<std::string> takeOutput(); + +private: + [[nodiscard]] Expected<void> appendLine(std::string_view Prefix, std::string_view Text); + [[nodiscard]] Expected<void> requireActiveSection() const; + + const MCInstPrinter *Printer; + MCSectionRef CurrentSection; + std::unordered_set<std::string> DefinedSymbols; + std::string Output; + bool IsFinished = false; + bool OutputWasTaken = false; +}; + +} // namespace rcc::mc + +#endif // RCC_MC_MCSTREAMER_H diff --git a/backend/include/rcc/MC/MCSymbol.h b/backend/include/rcc/MC/MCSymbol.h new file mode 100644 index 0000000..1b7b878 --- /dev/null +++ b/backend/include/rcc/MC/MCSymbol.h @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_MC_MCSYMBOL_H +#define RCC_MC_MCSYMBOL_H + +#include <cstdint> +#include <memory> +#include <string> +#include <string_view> + +namespace rcc::mc { + +class MCContext; + +enum class MCSymbolKind : std::uint8_t { + Generic, + Function, + Object, + BasicBlock, + ConstantPool, + JumpTable, + LiteralIsland, + Section, + Temporary, +}; + +class MCSymbol final { +public: + [[nodiscard]] std::string_view name() const noexcept { + return Name; + } + + [[nodiscard]] MCSymbolKind kind() const noexcept { + return Kind; + } + + [[nodiscard]] bool isTemporary() const noexcept { + return Kind == MCSymbolKind::Temporary || Kind == MCSymbolKind::BasicBlock || + Kind == MCSymbolKind::ConstantPool || Kind == MCSymbolKind::JumpTable || + Kind == MCSymbolKind::LiteralIsland; + } + +private: + MCSymbol(std::string Name, MCSymbolKind Kind) : Name(std::move(Name)), Kind(Kind) {} + + std::string Name; + MCSymbolKind Kind; + + friend class MCContext; +}; + +using MCSymbolRef = std::shared_ptr<const MCSymbol>; + +} // namespace rcc::mc + +#endif // RCC_MC_MCSYMBOL_H diff --git a/backend/include/rcc/MC/TargetRegistry.h b/backend/include/rcc/MC/TargetRegistry.h new file mode 100644 index 0000000..3e1de7c --- /dev/null +++ b/backend/include/rcc/MC/TargetRegistry.h @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_MC_TARGETREGISTRY_H +#define RCC_MC_TARGETREGISTRY_H + +#include "rcc/Support/Error.h" + +#include <memory> +#include <span> +#include <string> +#include <string_view> + +namespace rcc { + +class TargetMachine; +struct TargetMachineOptions; + +class Target final { +public: + using MatchQualityFn = unsigned (*)(std::string_view Triple); + using NormalizeTripleFn = std::string (*)(std::string_view Triple); + using DefaultOptionsFn = TargetMachineOptions (*)(); + using DefaultABIFn = std::string (*)(std::span<const std::string> Features); + using TargetMachineCtorFn = Expected<std::unique_ptr<TargetMachine>> (*)( + const Target &RegisteredTarget, TargetMachineOptions Options); + + constexpr Target(std::string_view Name, std::string_view Description, bool IsDefault, + MatchQualityFn MatchQuality, NormalizeTripleFn NormalizeTriple, + DefaultOptionsFn DefaultOptions, DefaultABIFn DefaultABI, + std::span<const std::string_view> BaselineFeatures, + TargetMachineCtorFn TargetMachineCtor) noexcept + : Name(Name), Description(Description), IsDefault(IsDefault), MatchQuality(MatchQuality), + NormalizeTriple(NormalizeTriple), DefaultOptions(DefaultOptions), DefaultABI(DefaultABI), + BaselineFeatures(BaselineFeatures), TargetMachineCtor(TargetMachineCtor) {} + + [[nodiscard]] std::string_view name() const noexcept { + return Name; + } + + [[nodiscard]] std::string_view description() const noexcept { + return Description; + } + + [[nodiscard]] bool isDefault() const noexcept { + return IsDefault; + } + + [[nodiscard]] unsigned matchQuality(std::string_view Triple) const noexcept { + return MatchQuality(Triple); + } + + [[nodiscard]] std::string normalizeTriple(std::string_view Triple) const { + return NormalizeTriple(Triple); + } + + [[nodiscard]] TargetMachineOptions defaultMachineOptions() const; + [[nodiscard]] std::string defaultABI(std::span<const std::string> Features) const { + return DefaultABI(Features); + } + + [[nodiscard]] std::span<const std::string_view> baselineFeatures() const noexcept { + return BaselineFeatures; + } + + [[nodiscard]] Expected<std::unique_ptr<TargetMachine>> + createTargetMachine(TargetMachineOptions Options) const; + +private: + std::string_view Name; + std::string_view Description; + bool IsDefault = false; + MatchQualityFn MatchQuality = nullptr; + NormalizeTripleFn NormalizeTriple = nullptr; + DefaultOptionsFn DefaultOptions = nullptr; + DefaultABIFn DefaultABI = nullptr; + std::span<const std::string_view> BaselineFeatures; + TargetMachineCtorFn TargetMachineCtor = nullptr; +}; + +class TargetRegistry final { +public: + static void registerTarget(const Target &RegisteredTarget); + [[nodiscard]] static Expected<const Target *> lookupTarget(std::string_view Triple); + [[nodiscard]] static Expected<const Target *> defaultTarget(); +}; + +} // namespace rcc + +#endif // RCC_MC_TARGETREGISTRY_H |
