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/include/rcc/CodeGen/AsmPrinter.h | 57 ++++++ backend/include/rcc/CodeGen/CompilationUnit.h | 13 ++ backend/include/rcc/CodeGen/GlobalObject.h | 196 +++++++++++++++++++++ backend/include/rcc/CodeGen/MachineMCContext.h | 68 +++++++ backend/include/rcc/CodeGen/TargetMCInstLowering.h | 69 ++++++++ backend/include/rcc/MC/MCCFI.h | 54 ++++++ backend/include/rcc/MC/MCContext.h | 43 +++++ backend/include/rcc/MC/MCExpr.h | 109 ++++++++++++ backend/include/rcc/MC/MCInst.h | 174 ++++++++++++++++++ backend/include/rcc/MC/MCInstPrinter.h | 31 ++++ backend/include/rcc/MC/MCSection.h | 108 ++++++++++++ backend/include/rcc/MC/MCStreamer.h | 93 ++++++++++ backend/include/rcc/MC/MCSymbol.h | 56 ++++++ backend/include/rcc/Support/Error.h | 1 + .../rcc/Target/RISCV/RISCVAssemblyPrinter.h | 35 ++++ .../include/rcc/Target/RISCV/RISCVInstPrinter.h | 36 ++++ .../rcc/Target/RISCV/RISCVMCTargetLowering.h | 62 +++++++ 17 files changed, 1205 insertions(+) create mode 100644 backend/include/rcc/CodeGen/AsmPrinter.h create mode 100644 backend/include/rcc/CodeGen/GlobalObject.h create mode 100644 backend/include/rcc/CodeGen/MachineMCContext.h create mode 100644 backend/include/rcc/CodeGen/TargetMCInstLowering.h create mode 100644 backend/include/rcc/MC/MCCFI.h create mode 100644 backend/include/rcc/MC/MCContext.h create mode 100644 backend/include/rcc/MC/MCExpr.h create mode 100644 backend/include/rcc/MC/MCInst.h create mode 100644 backend/include/rcc/MC/MCInstPrinter.h create mode 100644 backend/include/rcc/MC/MCSection.h create mode 100644 backend/include/rcc/MC/MCStreamer.h create mode 100644 backend/include/rcc/MC/MCSymbol.h create mode 100644 backend/include/rcc/Target/RISCV/RISCVAssemblyPrinter.h create mode 100644 backend/include/rcc/Target/RISCV/RISCVInstPrinter.h create mode 100644 backend/include/rcc/Target/RISCV/RISCVMCTargetLowering.h (limited to 'backend/include/rcc') diff --git a/backend/include/rcc/CodeGen/AsmPrinter.h b/backend/include/rcc/CodeGen/AsmPrinter.h new file mode 100644 index 0000000..82bad7d --- /dev/null +++ b/backend/include/rcc/CodeGen/AsmPrinter.h @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_CODEGEN_ASMPRINTER_H +#define RCC_CODEGEN_ASMPRINTER_H + +#include "rcc/Support/Error.h" + +namespace rcc { + +class CompilationUnit; +class MachineFunction; +class MachineMCContext; +class TargetDescription; +class TargetMCInstLowering; + +namespace mc { +class MCStreamer; +} // namespace mc + +struct AsmPrinterOptions final { + bool EmitFunctionDirectives = true; + bool EmitCFI = true; + bool EmitBlockLabels = true; + bool EmitInstructionSymbols = true; + bool VerifyInput = true; +}; + +class AsmPrinter final { +public: + AsmPrinter(const TargetDescription &Target, const TargetMCInstLowering &Lowering, + MachineMCContext &Context, mc::MCStreamer &Streamer, + AsmPrinterOptions Options = {}) noexcept + : Target(&Target), Lowering(&Lowering), Context(&Context), Streamer(&Streamer), + Options(Options) {} + + [[nodiscard]] Expected emitCompilationUnit(const CompilationUnit &Unit); + [[nodiscard]] Expected emitFunction(const MachineFunction &Function); + +private: + [[nodiscard]] Expected verifyFunction(const MachineFunction &Function) const; + [[nodiscard]] Expected emitGlobalObjects(const CompilationUnit &Unit); + [[nodiscard]] Expected emitFunctionBody(const MachineFunction &Function); + [[nodiscard]] Expected emitConstantPool(const MachineFunction &Function); + [[nodiscard]] Expected emitJumpTables(const MachineFunction &Function); + + const TargetDescription *Target; + const TargetMCInstLowering *Lowering; + MachineMCContext *Context; + mc::MCStreamer *Streamer; + AsmPrinterOptions Options; + bool UnitEmissionStarted = false; + bool UnitEmissionFinished = false; +}; + +} // namespace rcc + +#endif // RCC_CODEGEN_ASMPRINTER_H diff --git a/backend/include/rcc/CodeGen/CompilationUnit.h b/backend/include/rcc/CodeGen/CompilationUnit.h index d798438..14fd86f 100644 --- a/backend/include/rcc/CodeGen/CompilationUnit.h +++ b/backend/include/rcc/CodeGen/CompilationUnit.h @@ -3,6 +3,7 @@ #ifndef RCC_CODEGEN_COMPILATIONUNIT_H #define RCC_CODEGEN_COMPILATIONUNIT_H +#include "rcc/CodeGen/GlobalObject.h" #include "rcc/CodeGen/StableID.h" #include "rcc/Support/Error.h" @@ -28,6 +29,7 @@ public: ~CompilationUnit(); [[nodiscard]] Expected createMachineFunction(std::string Name); + [[nodiscard]] Expected addGlobalObject(GlobalObjectDesc Object); [[nodiscard]] std::size_t functionCount() const noexcept { return Functions.size(); @@ -40,6 +42,15 @@ public: [[nodiscard]] MachineFunction *function(MachineFunctionStableID ID) noexcept; [[nodiscard]] const MachineFunction *function(MachineFunctionStableID ID) const noexcept; + [[nodiscard]] std::size_t globalObjectCount() const noexcept { + return GlobalObjects.size(); + } + + [[nodiscard]] GlobalObjectDesc *globalObjectAt(std::size_t Index) noexcept; + [[nodiscard]] const GlobalObjectDesc *globalObjectAt(std::size_t Index) const noexcept; + [[nodiscard]] GlobalObjectDesc *globalObject(std::string_view Name) noexcept; + [[nodiscard]] const GlobalObjectDesc *globalObject(std::string_view Name) const noexcept; + [[nodiscard]] Expected verify() const; private: @@ -53,6 +64,8 @@ private: std::vector> Functions; std::unordered_map> FunctionNameToIndex; + std::vector> GlobalObjects; + std::unordered_map> GlobalNameToIndex; StableIDGenerator FunctionIDGenerator; }; diff --git a/backend/include/rcc/CodeGen/GlobalObject.h b/backend/include/rcc/CodeGen/GlobalObject.h new file mode 100644 index 0000000..49f1f42 --- /dev/null +++ b/backend/include/rcc/CodeGen/GlobalObject.h @@ -0,0 +1,196 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_CODEGEN_GLOBALOBJECT_H +#define RCC_CODEGEN_GLOBALOBJECT_H + +#include "rcc/CodeGen/GenericConstant.h" +#include "rcc/CodeGen/MachineIRTypes.h" +#include "rcc/CodeGen/TargetConstant.h" +#include "rcc/Support/Error.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace rcc { + +class GlobalInitializer; +using GlobalInitializerRef = std::shared_ptr; + +struct GlobalZeroFill final { + std::uint64_t Size = 0; +}; + +struct GlobalRepeatedInitializer final { + std::uint64_t Count = 0; + GlobalInitializerRef Value; +}; + +struct GlobalAggregateInitializer final { + std::vector Elements; +}; + +struct GlobalSymbolAddress final { + std::string Symbol; + std::int64_t Addend = 0; + std::uint8_t Size = 8; + std::uint32_t TargetFlags = 0; +}; + +struct GlobalSymbolDifference final { + std::string Minuend; + std::string Subtrahend; + std::int64_t Addend = 0; + std::uint8_t Size = 8; +}; + +struct GlobalAlignmentPadding final { + std::uint64_t Size = 0; + std::uint8_t Fill = 0; +}; + +struct GlobalUndefinedStorage final { + std::uint64_t Size = 0; +}; + +class GlobalInitializer final { +public: + enum class Kind : std::uint8_t { + Invalid, + Integer, + Floating, + Bytes, + ZeroFill, + Repeated, + Aggregate, + SymbolAddress, + SymbolDifference, + Target, + AlignmentPadding, + UndefinedStorage, + }; + + GlobalInitializer() = default; + GlobalInitializer(const GlobalInitializer &) = delete; + GlobalInitializer &operator=(const GlobalInitializer &) = delete; + GlobalInitializer(GlobalInitializer &&) noexcept = default; + GlobalInitializer &operator=(GlobalInitializer &&) noexcept = default; + ~GlobalInitializer() = default; + + [[nodiscard]] static GlobalInitializer integer(IntegerImmediate Value); + [[nodiscard]] static GlobalInitializer floating(FloatingPointBits Value); + [[nodiscard]] static Expected bytes(std::vector Value); + [[nodiscard]] static Expected zeroFill(std::uint64_t Size); + [[nodiscard]] static Expected repeated(std::uint64_t Count, + GlobalInitializer Value); + [[nodiscard]] static Expected + aggregate(std::vector Elements); + [[nodiscard]] static Expected symbolAddress(GlobalSymbolAddress Value); + [[nodiscard]] static Expected symbolDifference(GlobalSymbolDifference Value); + [[nodiscard]] static Expected target(TargetConstant Value); + [[nodiscard]] static Expected alignmentPadding(std::uint64_t Size, + std::uint8_t Fill = 0); + [[nodiscard]] static Expected undefinedStorage(std::uint64_t Size); + + [[nodiscard]] Kind kind() const noexcept; + + template [[nodiscard]] const ValueT *getIf() const noexcept { + return std::get_if(&Storage); + } + + [[nodiscard]] Expected verify(std::size_t MaximumDepth = 1024) const; + [[nodiscard]] Expected storageSize(std::size_t MaximumDepth = 1024) const; + +private: + using StorageT = + std::variant, + GlobalZeroFill, GlobalRepeatedInitializer, GlobalAggregateInitializer, + GlobalSymbolAddress, GlobalSymbolDifference, TargetConstant, + GlobalAlignmentPadding, GlobalUndefinedStorage>; + + explicit GlobalInitializer(StorageT Storage) : Storage(std::move(Storage)) {} + + StorageT Storage; +}; + +enum class GlobalLinkage : std::uint8_t { + External, + AvailableExternally, + LinkOnceAny, + LinkOnceODR, + WeakAny, + WeakODR, + Appending, + Internal, + Private, + ExternalWeak, + Common, + Count, +}; + +enum class GlobalVisibility : std::uint8_t { + Default, + Hidden, + Protected, + Count, +}; + +enum class GlobalTLSModel : std::uint8_t { + None, + GeneralDynamic, + LocalDynamic, + InitialExec, + LocalExec, + Count, +}; + +enum class GlobalUnnamedAddress : std::uint8_t { + None, + Local, + Global, + Count, +}; + +struct GlobalObjectDesc final { + std::string Symbol; + GenericConstantType ObjectType; + GlobalLinkage Linkage = GlobalLinkage::External; + GlobalVisibility Visibility = GlobalVisibility::Default; + bool DSOLocal = false; + std::optional Section; + Alignment Align; + std::uint64_t Size = 0; + std::uint32_t AddressSpace = 0; + GlobalTLSModel TLSModel = GlobalTLSModel::None; + bool ExternallyInitialized = false; + std::optional COMDAT; + bool IsConstant = false; + GlobalUnnamedAddress UnnamedAddress = GlobalUnnamedAddress::None; + std::optional Initializer; + std::vector DebugExpressions; + std::optional StableOrigin; + std::uint64_t TargetFlags = 0; + std::vector> TargetAttributes; + + GlobalObjectDesc() = default; + GlobalObjectDesc(const GlobalObjectDesc &) = delete; + GlobalObjectDesc &operator=(const GlobalObjectDesc &) = delete; + GlobalObjectDesc(GlobalObjectDesc &&) noexcept = default; + GlobalObjectDesc &operator=(GlobalObjectDesc &&) noexcept = default; + ~GlobalObjectDesc() = default; + + [[nodiscard]] bool isDeclaration() const noexcept { + return !Initializer.has_value() && Linkage != GlobalLinkage::Common; + } + + [[nodiscard]] Expected verify() const; +}; + +} // namespace rcc + +#endif // RCC_CODEGEN_GLOBALOBJECT_H diff --git a/backend/include/rcc/CodeGen/MachineMCContext.h b/backend/include/rcc/CodeGen/MachineMCContext.h new file mode 100644 index 0000000..2464dc5 --- /dev/null +++ b/backend/include/rcc/CodeGen/MachineMCContext.h @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_CODEGEN_MACHINEMCCONTEXT_H +#define RCC_CODEGEN_MACHINEMCCONTEXT_H + +#include "rcc/CodeGen/MachineIRTypes.h" +#include "rcc/MC/MCContext.h" +#include "rcc/MC/MCSymbol.h" +#include "rcc/Support/Error.h" + +#include +#include +#include + +namespace rcc { + +class CompilationUnit; +struct GlobalObjectDesc; +class MachineBasicBlock; +class MachineFunction; + +class MachineMCContext final { +public: + explicit MachineMCContext(mc::MCContext &Context) noexcept : Context(&Context) {} + + [[nodiscard]] Expected initialize(const CompilationUnit &Unit); + [[nodiscard]] Expected initializeFunction(const MachineFunction &Function); + + [[nodiscard]] mc::MCSymbolRef functionSymbol(const MachineFunction &Function) const noexcept; + [[nodiscard]] mc::MCSymbolRef globalSymbol(const GlobalObjectDesc &Object) const noexcept; + [[nodiscard]] mc::MCSymbolRef blockSymbol(const MachineBasicBlock &Block) const noexcept; + [[nodiscard]] mc::MCSymbolRef constantPoolSymbol(const MachineFunction &Function, + ConstantPoolIndex Index) const noexcept; + [[nodiscard]] mc::MCSymbolRef jumpTableSymbol(const MachineFunction &Function, + JumpTableIndex Index) const noexcept; + + [[nodiscard]] Expected symbol(std::string Name, + mc::MCSymbolKind Kind = mc::MCSymbolKind::Generic); + [[nodiscard]] Expected blockAddressSymbol(std::string_view FunctionName, + std::string_view BlockName) const; + + [[nodiscard]] mc::MCContext &context() const noexcept { + return *Context; + } + +private: + struct FunctionIndexKey final { + const MachineFunction *Function = nullptr; + std::uint32_t Index = 0; + + friend bool operator==(FunctionIndexKey Left, FunctionIndexKey Right) noexcept = default; + }; + + struct FunctionIndexHash final { + [[nodiscard]] std::size_t operator()(FunctionIndexKey Key) const noexcept; + }; + + mc::MCContext *Context; + std::unordered_map FunctionSymbols; + std::unordered_map GlobalSymbols; + std::unordered_map BlockSymbols; + std::unordered_map ConstantPoolSymbols; + std::unordered_map JumpTableSymbols; +}; + +} // namespace rcc + +#endif // RCC_CODEGEN_MACHINEMCCONTEXT_H diff --git a/backend/include/rcc/CodeGen/TargetMCInstLowering.h b/backend/include/rcc/CodeGen/TargetMCInstLowering.h new file mode 100644 index 0000000..875d2dd --- /dev/null +++ b/backend/include/rcc/CodeGen/TargetMCInstLowering.h @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_CODEGEN_TARGETMCINSTLOWERING_H +#define RCC_CODEGEN_TARGETMCINSTLOWERING_H + +#include "rcc/MC/MCInst.h" +#include "rcc/MC/MCInstPrinter.h" +#include "rcc/MC/MCSection.h" +#include "rcc/MC/MCStreamer.h" +#include "rcc/Support/Error.h" + +namespace rcc { + +class MachineConstantPoolEntry; +class GlobalInitializer; +struct GlobalObjectDesc; +class MachineFunction; +class MachineInstr; +class MachineJumpTableEntry; +class MachineMCContext; +struct GenericConstantData; +class TargetConstant; + +class TargetMCInstLowering { +public: + virtual ~TargetMCInstLowering() = default; + + [[nodiscard]] virtual const mc::MCInstPrinter &instructionPrinter() const noexcept = 0; + + [[nodiscard]] virtual Expected lowerInstruction(const MachineInstr &Instruction, + MachineMCContext &Context) const = 0; + + [[nodiscard]] virtual Expected emitTerminalInstruction(const MachineInstr &Instruction, + MachineMCContext &Context, + mc::MCStreamer &Streamer) const; + + [[nodiscard]] virtual Expected + textSection(const MachineFunction &Function) const = 0; + [[nodiscard]] virtual Expected + globalSection(const GlobalObjectDesc &Object, MachineMCContext &Context) const = 0; + [[nodiscard]] virtual Expected + constantPoolSection(const MachineFunction &Function, + const MachineConstantPoolEntry &Entry) const = 0; + [[nodiscard]] virtual Expected + jumpTableSection(const MachineFunction &Function, const MachineJumpTableEntry &Entry) const = 0; + + [[nodiscard]] virtual Expected emitFileHeader(MachineMCContext &Context, + mc::MCStreamer &Streamer) const; + [[nodiscard]] virtual Expected emitFileTrailer(MachineMCContext &Context, + mc::MCStreamer &Streamer) const; + [[nodiscard]] virtual Expected emitGenericConstant(const GenericConstantData &Constant, + std::uint64_t Size, + MachineMCContext &Context, + mc::MCStreamer &Streamer) const; + [[nodiscard]] virtual Expected emitGlobalInitializer(const GlobalInitializer &Initializer, + MachineMCContext &Context, + mc::MCStreamer &Streamer) const; + [[nodiscard]] virtual Expected emitTargetConstant(const TargetConstant &Constant, + MachineMCContext &Context, + mc::MCStreamer &Streamer) const; + [[nodiscard]] virtual Expected emitTargetJumpTable(const MachineFunction &Function, + const MachineJumpTableEntry &Entry, + MachineMCContext &Context, + mc::MCStreamer &Streamer) const; +}; + +} // namespace rcc + +#endif // RCC_CODEGEN_TARGETMCINSTLOWERING_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 +#include + +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 Operands; + std::vector Bytes; + MCSymbolRef Symbol; + + [[nodiscard]] Expected verify() const; +}; + +} // namespace rcc::mc + +#endif // RCC_MC_MCCFI_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 +#include +#include +#include +#include + +namespace rcc::mc { + +class MCContext final { +public: + [[nodiscard]] Expected getOrCreateSymbol(std::string Name, MCSymbolKind Kind); + [[nodiscard]] Expected createTemporarySymbol(std::string_view Prefix); + [[nodiscard]] MCSymbolRef symbol(std::string_view Name) const noexcept; + + [[nodiscard]] Expected 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{}(Value); + } + }; + + std::unordered_map> Symbols; + std::unordered_map> Sections; + std::uint64_t NextTemporarySymbol = 0; +}; + +} // namespace rcc::mc + +#endif // RCC_MC_MCCONTEXT_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 +#include +#include +#include +#include + +namespace rcc::mc { + +class MCExpr; +using MCExprRef = std::shared_ptr; + +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 symbol(MCSymbolRef Symbol); + [[nodiscard]] static Expected unary(MCUnaryOperator Operator, MCExprRef Operand); + [[nodiscard]] static Expected binary(MCBinaryOperator Operator, MCExprRef Left, + MCExprRef Right); + [[nodiscard]] static Expected target(std::uint32_t Kind, MCExprRef Operand); + + [[nodiscard]] Kind kind() const noexcept { + return ExpressionKind; + } + + template [[nodiscard]] const ValueT *getIf() const noexcept { + return std::get_if(&Storage); + } + + [[nodiscard]] Expected verify(std::size_t MaximumDepth = 256) const; + [[nodiscard]] std::optional evaluateAbsolute() const noexcept; + +private: + using StorageT = + std::variant; + + 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/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 +#include +#include +#include +#include +#include + +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(&Storage); + } + + [[nodiscard]] const std::int64_t *immediateValue() const noexcept { + return std::get_if(&Storage); + } + + [[nodiscard]] const std::uint32_t *float32BitsValue() const noexcept { + return std::get_if(&Storage); + } + + [[nodiscard]] const std::uint64_t *float64BitsValue() const noexcept { + return std::get_if(&Storage); + } + + [[nodiscard]] const MCExprRef *expressionValue() const noexcept { + return std::get_if(&Storage); + } + +private: + using StorageT = std::variant; + + 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 operands() const noexcept { + return Operands; + } + +private: + MCOpcode InstructionOpcode; + std::uint32_t Flags = 0; + std::uint64_t SourceIdentity = 0; + std::vector 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 +#include +#include + +namespace rcc::mc { + +class MCInstPrinter { +public: + virtual ~MCInstPrinter() = default; + + [[nodiscard]] virtual Expected printInstruction(const MCInst &Instruction) const = 0; + + [[nodiscard]] virtual Expected + printTargetExpression(std::uint32_t Kind, std::string_view Operand) const = 0; +}; + +[[nodiscard]] Expected printMCExpression(const MCExpr &Expression, + const MCInstPrinter &Printer); +[[nodiscard]] Expected printMCSymbolName(std::string_view Name); + +} // namespace rcc::mc + +#endif // RCC_MC_MCINSTPRINTER_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 +#include +#include +#include +#include +#include + +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 Flags) noexcept { + for (const MCSectionFlag Flag : Flags) + set(Flag); + } + + constexpr void set(MCSectionFlag Flag) noexcept { + const auto Index = static_cast(Flag); + if (Index < static_cast(MCSectionFlag::Count)) + Mask |= std::uint16_t{1} << Index; + } + + [[nodiscard]] constexpr bool has(MCSectionFlag Flag) const noexcept { + const auto Index = static_cast(Flag); + return Index < static_cast(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 UniqueID; + + [[nodiscard]] Expected 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; + +} // 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..3add976 --- /dev/null +++ b/backend/include/rcc/MC/MCStreamer.h @@ -0,0 +1,93 @@ +// 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 +#include +#include +#include +#include + +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 switchSection(MCSectionRef Section) = 0; + [[nodiscard]] virtual Expected emitLabel(MCSymbolRef Symbol) = 0; + [[nodiscard]] virtual Expected emitInstruction(const MCInst &Instruction) = 0; + [[nodiscard]] virtual Expected emitValue(MCExprRef Value, std::uint8_t Size) = 0; + [[nodiscard]] virtual Expected emitBytes(std::span Bytes) = 0; + [[nodiscard]] virtual Expected emitZeroFill(std::uint64_t Size) = 0; + [[nodiscard]] virtual Expected emitAlignment(std::uint64_t Alignment, std::uint8_t Fill = 0, + std::uint64_t MaximumBytes = 0) = 0; + [[nodiscard]] virtual Expected emitSymbolAttribute(MCSymbolRef Symbol, + MCSymbolAttribute Attribute) = 0; + [[nodiscard]] virtual Expected emitSymbolSize(MCSymbolRef Symbol, MCExprRef Size) = 0; + [[nodiscard]] virtual Expected emitDirective(std::string_view Name, + std::string_view Arguments = {}) = 0; + [[nodiscard]] virtual Expected emitCFI(const MCCFIInstruction &Instruction) = 0; + [[nodiscard]] virtual Expected emitInlineAssembly(std::string_view Text) = 0; + [[nodiscard]] virtual Expected emitComment(std::string_view Text) = 0; + [[nodiscard]] virtual Expected finish() = 0; +}; + +class AsmTextStreamer final : public MCStreamer { +public: + explicit AsmTextStreamer(const MCInstPrinter &Printer) noexcept : Printer(&Printer) {} + + [[nodiscard]] Expected switchSection(MCSectionRef Section) override; + [[nodiscard]] Expected emitLabel(MCSymbolRef Symbol) override; + [[nodiscard]] Expected emitInstruction(const MCInst &Instruction) override; + [[nodiscard]] Expected emitValue(MCExprRef Value, std::uint8_t Size) override; + [[nodiscard]] Expected emitBytes(std::span Bytes) override; + [[nodiscard]] Expected emitZeroFill(std::uint64_t Size) override; + [[nodiscard]] Expected emitAlignment(std::uint64_t Alignment, std::uint8_t Fill = 0, + std::uint64_t MaximumBytes = 0) override; + [[nodiscard]] Expected emitSymbolAttribute(MCSymbolRef Symbol, + MCSymbolAttribute Attribute) override; + [[nodiscard]] Expected emitSymbolSize(MCSymbolRef Symbol, MCExprRef Size) override; + [[nodiscard]] Expected emitDirective(std::string_view Name, + std::string_view Arguments = {}) override; + [[nodiscard]] Expected emitCFI(const MCCFIInstruction &Instruction) override; + [[nodiscard]] Expected emitInlineAssembly(std::string_view Text) override; + [[nodiscard]] Expected emitComment(std::string_view Text) override; + [[nodiscard]] Expected finish() override; + + [[nodiscard]] Expected takeOutput(); + +private: + [[nodiscard]] Expected appendLine(std::string_view Prefix, std::string_view Text); + [[nodiscard]] Expected requireActiveSection() const; + + const MCInstPrinter *Printer; + MCSectionRef CurrentSection; + std::unordered_set 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 +#include +#include +#include + +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; + +} // namespace rcc::mc + +#endif // RCC_MC_MCSYMBOL_H diff --git a/backend/include/rcc/Support/Error.h b/backend/include/rcc/Support/Error.h index d125383..3bdab97 100644 --- a/backend/include/rcc/Support/Error.h +++ b/backend/include/rcc/Support/Error.h @@ -25,6 +25,7 @@ enum class ErrorCode : std::uint8_t { PseudoExpansionFailed, FinalEncodabilityFailed, CFGOptimizationFailed, + AssemblyLoweringFailed, }; [[nodiscard]] std::string_view getErrorCodeName(ErrorCode Code) noexcept; diff --git a/backend/include/rcc/Target/RISCV/RISCVAssemblyPrinter.h b/backend/include/rcc/Target/RISCV/RISCVAssemblyPrinter.h new file mode 100644 index 0000000..5c8dca5 --- /dev/null +++ b/backend/include/rcc/Target/RISCV/RISCVAssemblyPrinter.h @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_TARGET_RISCV_RISCVASSEMBLYPRINTER_H +#define RCC_TARGET_RISCV_RISCVASSEMBLYPRINTER_H + +#include "rcc/CodeGen/AsmPrinter.h" +#include "rcc/CodeGen/TargetDescription.h" +#include "rcc/Support/Error.h" + +#include + +namespace rcc { +class CompilationUnit; +class MachineFunction; +} // namespace rcc + +namespace rcc::riscv { + +struct AssemblyEmissionOptions final { + bool EmitFunctionDirectives = true; + bool EmitCFI = true; + bool EmitBlockLabels = true; + bool VerifyInput = true; +}; + +[[nodiscard]] Expected emitAssembly(const CompilationUnit &Unit, + const TargetDescription &Target, + AssemblyEmissionOptions Options = {}); +[[nodiscard]] Expected emitAssembly(const MachineFunction &Function, + const TargetDescription &Target, + AssemblyEmissionOptions Options = {}); + +} // namespace rcc::riscv + +#endif // RCC_TARGET_RISCV_RISCVASSEMBLYPRINTER_H diff --git a/backend/include/rcc/Target/RISCV/RISCVInstPrinter.h b/backend/include/rcc/Target/RISCV/RISCVInstPrinter.h new file mode 100644 index 0000000..564ca2f --- /dev/null +++ b/backend/include/rcc/Target/RISCV/RISCVInstPrinter.h @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_TARGET_RISCV_RISCVINSTPRINTER_H +#define RCC_TARGET_RISCV_RISCVINSTPRINTER_H + +#include "rcc/CodeGen/TargetDescription.h" +#include "rcc/MC/MCInstPrinter.h" + +#include +#include +#include + +namespace rcc::riscv { + +enum class RISCVMCExprKind : std::uint32_t { + CallPLT = 1, + PCRelativeHigh = 2, + PCRelativeLow = 3, +}; + +class RISCVInstPrinter final : public mc::MCInstPrinter { +public: + explicit RISCVInstPrinter(const TargetDescription &Target) noexcept : Target(&Target) {} + + [[nodiscard]] Expected + printInstruction(const mc::MCInst &Instruction) const override; + [[nodiscard]] Expected + printTargetExpression(std::uint32_t Kind, std::string_view Operand) const override; + +private: + const TargetDescription *Target; +}; + +} // namespace rcc::riscv + +#endif // RCC_TARGET_RISCV_RISCVINSTPRINTER_H diff --git a/backend/include/rcc/Target/RISCV/RISCVMCTargetLowering.h b/backend/include/rcc/Target/RISCV/RISCVMCTargetLowering.h new file mode 100644 index 0000000..fd620ad --- /dev/null +++ b/backend/include/rcc/Target/RISCV/RISCVMCTargetLowering.h @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_TARGET_RISCV_RISCVMCTARGETLOWERING_H +#define RCC_TARGET_RISCV_RISCVMCTARGETLOWERING_H + +#include "rcc/CodeGen/TargetMCInstLowering.h" +#include "rcc/Target/RISCV/RISCVInstPrinter.h" + +namespace rcc::riscv { + +class RISCVMCTargetLowering final : public TargetMCInstLowering { +public: + explicit RISCVMCTargetLowering(const TargetDescription &Target) noexcept + : Target(&Target), Printer(Target) {} + + [[nodiscard]] const mc::MCInstPrinter &instructionPrinter() const noexcept override { + return Printer; + } + + [[nodiscard]] Expected lowerInstruction(const MachineInstr &Instruction, + MachineMCContext &Context) const override; + [[nodiscard]] Expected emitTerminalInstruction(const MachineInstr &Instruction, + MachineMCContext &Context, + mc::MCStreamer &Streamer) const override; + + [[nodiscard]] Expected + textSection(const MachineFunction &Function) const override; + [[nodiscard]] Expected globalSection(const GlobalObjectDesc &Object, + MachineMCContext &Context) const override; + [[nodiscard]] Expected + constantPoolSection(const MachineFunction &Function, + const MachineConstantPoolEntry &Entry) const override; + [[nodiscard]] Expected + jumpTableSection(const MachineFunction &Function, + const MachineJumpTableEntry &Entry) const override; + + [[nodiscard]] Expected emitFileHeader(MachineMCContext &Context, + mc::MCStreamer &Streamer) const override; + [[nodiscard]] Expected emitFileTrailer(MachineMCContext &Context, + mc::MCStreamer &Streamer) const override; + [[nodiscard]] Expected emitGenericConstant(const GenericConstantData &Constant, + std::uint64_t Size, MachineMCContext &Context, + mc::MCStreamer &Streamer) const override; + [[nodiscard]] Expected emitGlobalInitializer(const GlobalInitializer &Initializer, + MachineMCContext &Context, + mc::MCStreamer &Streamer) const override; + [[nodiscard]] Expected emitTargetConstant(const TargetConstant &Constant, + MachineMCContext &Context, + mc::MCStreamer &Streamer) const override; + [[nodiscard]] Expected emitTargetJumpTable(const MachineFunction &Function, + const MachineJumpTableEntry &Entry, + MachineMCContext &Context, + mc::MCStreamer &Streamer) const override; + +private: + const TargetDescription *Target; + RISCVInstPrinter Printer; +}; + +} // namespace rcc::riscv + +#endif // RCC_TARGET_RISCV_RISCVMCTARGETLOWERING_H -- cgit v1.2.3