From 76d89700953ddd81cf31ab8f260eddf67e93aa85 Mon Sep 17 00:00:00 2001 From: Richard-Qin-X Date: Fri, 7 Aug 2026 01:27:41 +0800 Subject: [MIR] Complete document parsing and printing Implement the single LLVM-compatible MIR document path with structured\nembedded-IR references, YAML mappings, constants, and deterministic printing.\n\nKeep pointer LLT widths DataLayout-derived, reject layout-dependent output\nwhen embedded IR is omitted, and record the fixed-baseline compatibility\ncontract and regression coverage. --- backend/include/rcc/CodeGen/GenericConstant.h | 176 +++++++++++++++++++++ .../include/rcc/CodeGen/InstructionDescriptor.h | 1 + backend/include/rcc/CodeGen/MachineConstantPool.h | 9 +- backend/include/rcc/CodeGen/MachineFrameInfo.h | 79 ++++++++- .../rcc/CodeGen/MachineFunctionProperties.h | 4 + backend/include/rcc/CodeGen/MachineJumpTableInfo.h | 26 ++- backend/include/rcc/CodeGen/MachineMetadata.h | 12 +- backend/include/rcc/CodeGen/MachineOperand.h | 3 + backend/include/rcc/CodeGen/TargetMIRTextInfo.h | 63 ++++++++ 9 files changed, 351 insertions(+), 22 deletions(-) create mode 100644 backend/include/rcc/CodeGen/GenericConstant.h (limited to 'backend/include/rcc/CodeGen') diff --git a/backend/include/rcc/CodeGen/GenericConstant.h b/backend/include/rcc/CodeGen/GenericConstant.h new file mode 100644 index 0000000..11c5068 --- /dev/null +++ b/backend/include/rcc/CodeGen/GenericConstant.h @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_CODEGEN_GENERICCONSTANT_H +#define RCC_CODEGEN_GENERICCONSTANT_H + +#include "rcc/CodeGen/LowLevelType.h" +#include "rcc/CodeGen/MachineOperand.h" +#include "rcc/Support/Error.h" + +#include +#include +#include +#include +#include + +namespace rcc { + +enum class GenericConstantTypeKind : std::uint8_t { + Invalid, + Void, + Label, + Token, + Metadata, + Integer, + Byte, + Floating, + Pointer, + Array, + Vector, + Struct, + Function, + Named, +}; + +struct GenericConstantType final { + GenericConstantTypeKind Kind = GenericConstantTypeKind::Invalid; + std::uint32_t BitWidth = 0; + FloatSemantics Semantics = FloatSemantics::IEEEHalf; + std::uint32_t AddressSpace = 0; + std::uint64_t ElementCount = 0; + bool Scalable = false; + bool Packed = false; + bool VarArg = false; + bool NumericName = false; + std::string Name; + std::vector Elements; + + [[nodiscard]] static Expected integer(std::uint32_t BitWidth); + [[nodiscard]] static GenericConstantType primitive(GenericConstantTypeKind Kind) noexcept; + [[nodiscard]] static GenericConstantType byte() noexcept; + [[nodiscard]] static Expected floating(FloatSemantics Semantics); + [[nodiscard]] static GenericConstantType pointer(std::uint32_t AddressSpace = 0) noexcept; + [[nodiscard]] static Expected + array(std::uint64_t ElementCount, GenericConstantType Element); + [[nodiscard]] static Expected + vector(std::uint64_t ElementCount, GenericConstantType Element, bool Scalable = false); + [[nodiscard]] static Expected + structure(std::vector Elements, bool Packed = false); + [[nodiscard]] static Expected + function(GenericConstantType Return, std::vector Parameters, + bool VarArg = false); + [[nodiscard]] static Expected named(std::string Name, + bool NumericName = false); + + [[nodiscard]] Expected verify() const; + + friend bool operator==(const GenericConstantType &Left, + const GenericConstantType &Right) = default; +}; + +enum class GenericConstantKind : std::uint8_t { + Invalid, + Integer, + Floating, + NullPointer, + ZeroInitializer, + Undef, + Poison, + Aggregate, + ByteString, + GlobalAddress, + BlockAddress, + DSOLocalEquivalent, + NoCFI, + PointerAuth, + Expression, +}; + +enum class GenericConstantExpressionOpcode : std::uint8_t { + Invalid, + Trunc, + BitCast, + AddressSpaceCast, + IntToPtr, + PtrToAddr, + PtrToInt, + Add, + Sub, + Xor, + GetElementPtr, + ShuffleVector, + InsertElement, + ExtractElement, + Splat, +}; + +enum class GenericConstantExpressionFlag : std::uint8_t { + NoUnsignedWrap, + NoSignedWrap, + InBounds, + NoUnsignedSignedWrap, + GEPNoUnsignedWrap, + Count, +}; + +class GenericConstantExpressionFlags final { +public: + constexpr GenericConstantExpressionFlags() noexcept = default; + + [[nodiscard]] constexpr bool has(GenericConstantExpressionFlag Flag) const noexcept { + const auto Index = static_cast(Flag); + if (Index >= static_cast(GenericConstantExpressionFlag::Count)) + return false; + return (Mask & (std::uint8_t{1} << Index)) != 0; + } + + constexpr void set(GenericConstantExpressionFlag Flag) noexcept { + const auto Index = static_cast(Flag); + if (Index < static_cast(GenericConstantExpressionFlag::Count)) + Mask |= std::uint8_t{1} << Index; + } + + [[nodiscard]] constexpr std::uint8_t rawValue() const noexcept { + return Mask; + } + + friend constexpr bool operator==(GenericConstantExpressionFlags Left, + GenericConstantExpressionFlags Right) noexcept = default; + +private: + std::uint8_t Mask = 0; +}; + +struct GenericConstantData final { + GenericConstantType Type; + GenericConstantKind Kind = GenericConstantKind::Invalid; + std::optional IntegerValue; + std::optional FloatingValue; + std::vector ByteValue; + std::vector Elements; + std::string Symbol; + std::string Block; + bool NumericSymbol = false; + bool NumericBlock = false; + GenericConstantExpressionOpcode ExpressionOpcode = + GenericConstantExpressionOpcode::Invalid; + GenericConstantExpressionFlags ExpressionFlags; + std::optional SourceElementType; + std::optional InRangeStart; + std::optional InRangeEnd; + + [[nodiscard]] static Expected integer(IntegerImmediate Value); + [[nodiscard]] static Expected floating(FloatingPointBits Value); + [[nodiscard]] static Expected byteString(GenericConstantType Type, + std::vector Bytes); + + [[nodiscard]] Expected verify() const; + [[nodiscard]] bool referencesSymbol() const noexcept; + + friend bool operator==(const GenericConstantData &Left, + const GenericConstantData &Right) = default; +}; + +} // namespace rcc + +#endif // RCC_CODEGEN_GENERICCONSTANT_H diff --git a/backend/include/rcc/CodeGen/InstructionDescriptor.h b/backend/include/rcc/CodeGen/InstructionDescriptor.h index 94ea374..06e37d3 100644 --- a/backend/include/rcc/CodeGen/InstructionDescriptor.h +++ b/backend/include/rcc/CodeGen/InstructionDescriptor.h @@ -97,6 +97,7 @@ enum class InstructionFlag : std::uint8_t { Convergent, UnmodeledSideEffects, Phi, + FakeUse, Generic, TerminalEmission, Count, diff --git a/backend/include/rcc/CodeGen/MachineConstantPool.h b/backend/include/rcc/CodeGen/MachineConstantPool.h index cc9ae04..a0c269b 100644 --- a/backend/include/rcc/CodeGen/MachineConstantPool.h +++ b/backend/include/rcc/CodeGen/MachineConstantPool.h @@ -3,6 +3,7 @@ #ifndef RCC_CODEGEN_MACHINECONSTANTPOOL_H #define RCC_CODEGEN_MACHINECONSTANTPOOL_H +#include "rcc/CodeGen/GenericConstant.h" #include "rcc/CodeGen/MachineIRTypes.h" #include "rcc/CodeGen/MachineMemOperand.h" #include "rcc/CodeGen/TargetConstant.h" @@ -59,14 +60,6 @@ struct ConstantPoolPlacement final { const ConstantPoolPlacement &Right) = default; }; -struct GenericConstantData final { - std::string TypeIdentity; - std::vector Bytes; - - friend bool operator==(const GenericConstantData &Left, - const GenericConstantData &Right) = default; -}; - struct SymbolDifferenceConstant final { std::string Minuend; std::string Subtrahend; diff --git a/backend/include/rcc/CodeGen/MachineFrameInfo.h b/backend/include/rcc/CodeGen/MachineFrameInfo.h index 7c42bc2..48e3d7a 100644 --- a/backend/include/rcc/CodeGen/MachineFrameInfo.h +++ b/backend/include/rcc/CodeGen/MachineFrameInfo.h @@ -6,12 +6,14 @@ #include "rcc/CodeGen/MachineDebugInfo.h" #include "rcc/CodeGen/MachineIRTypes.h" #include "rcc/CodeGen/MachineMemOperand.h" +#include "rcc/CodeGen/Register.h" #include "rcc/CodeGen/StableID.h" #include "rcc/Support/Error.h" #include #include #include +#include #include #include #include @@ -22,6 +24,7 @@ namespace rcc { enum class StackObjectKind : std::uint8_t { Default, FixedABI, + FixedSpillSlot, SpillSlot, VariableSized, DynamicAlloca, @@ -101,13 +104,18 @@ struct StackObjectLifetimeRange final { struct StackObjectDesc final { StackObjectKind Kind = StackObjectKind::Default; + std::optional AllocaName; std::optional Size; Alignment Align; std::optional Offset; StackID Stack; bool IsDead = false; + bool IsImmutable = false; bool IsAliased = false; bool AddressTaken = false; + std::optional CalleeSavedRegister; + bool CalleeSavedRestored = true; + std::optional LocalOffset; std::vector Lifetime; std::optional DebugInfo; std::uint64_t TargetFlags = 0; @@ -143,6 +151,56 @@ private: friend class MachineFrameInfo; }; +enum class MachineFramePointerPolicy : std::uint8_t { + None, + NonLeaf, + All, + Reserved, + NonLeafNoReserve, + Count, +}; + +[[nodiscard]] std::optional +parseMachineFramePointerPolicy(std::string_view Name) noexcept; +[[nodiscard]] std::string_view +getMachineFramePointerPolicyName(MachineFramePointerPolicy Policy) noexcept; + +struct MachineFrameSaveRestorePoint final { + MachineBlockStableID Block; + std::vector Registers; + + friend bool operator==(const MachineFrameSaveRestorePoint &Left, + const MachineFrameSaveRestorePoint &Right) = default; +}; + +struct MachineFrameState final { + bool IsFrameAddressTaken = false; + bool IsReturnAddressTaken = false; + bool HasStackMap = false; + bool HasPatchPoint = false; + std::uint64_t StackSize = 0; + std::int32_t OffsetAdjustment = 0; + std::optional MaxAlignment; + bool AdjustsStack = false; + bool HasCalls = false; + MachineFramePointerPolicy FramePointerPolicy = MachineFramePointerPolicy::None; + std::optional StackProtector; + std::optional FunctionContext; + std::optional MaxCallFrameSize; + std::uint32_t CVBytesOfCalleeSavedRegisters = 0; + bool HasOpaqueSPAdjustment = false; + bool HasVAStart = false; + bool HasMustTailInVarArgFunc = false; + bool HasTailCall = false; + bool IsCalleeSavedInfoValid = false; + std::uint32_t LocalFrameSize = 0; + std::vector SavePoints; + std::vector RestorePoints; + + friend bool operator==(const MachineFrameState &Left, + const MachineFrameState &Right) = default; +}; + class MachineFrameInfo final { public: MachineFrameInfo() = default; @@ -169,31 +227,38 @@ public: return Frozen; } + [[nodiscard]] const MachineFrameState &state() const noexcept { + return State; + } + [[nodiscard]] std::optional staticStackSize() const noexcept { - return StaticStackSize; + if (!Frozen) + return std::nullopt; + return State.StackSize; } [[nodiscard]] Alignment stackAlignment() const noexcept { - return StackAlign; + return State.MaxAlignment.value_or(Alignment{}); } - [[nodiscard]] std::uint64_t maxCallFrameSize() const noexcept { - return MaxCallFrameSize; + [[nodiscard]] std::optional maxCallFrameSize() const noexcept { + return State.MaxCallFrameSize; } + [[nodiscard]] Expected setState(MachineFrameState NewState); [[nodiscard]] Expected setMaxCallFrameSize(std::uint64_t Size); + [[nodiscard]] Expected clearMaxCallFrameSize(); [[nodiscard]] Expected freeze(std::uint64_t Size, Alignment Align); [[nodiscard]] Expected verify() const; private: [[nodiscard]] static Expected verifyDescription(const StackObjectDesc &Description); + [[nodiscard]] static Expected verifyStateStructure(const MachineFrameState &State); [[nodiscard]] Expected mutableObject(FrameIndex Index); std::vector Objects; + MachineFrameState State; bool Frozen = false; - std::optional StaticStackSize; - Alignment StackAlign; - std::uint64_t MaxCallFrameSize = 0; }; } // namespace rcc diff --git a/backend/include/rcc/CodeGen/MachineFunctionProperties.h b/backend/include/rcc/CodeGen/MachineFunctionProperties.h index 7d1a5ad..39a4fce 100644 --- a/backend/include/rcc/CodeGen/MachineFunctionProperties.h +++ b/backend/include/rcc/CodeGen/MachineFunctionProperties.h @@ -27,6 +27,10 @@ enum class MachineFunctionProperty : std::uint8_t { FrameFinalized, NoFrameIndices, NoExecutablePseudos, + // These two properties mirror LLVM MIR pipeline state. They are deliberately + // separate from RCC's MachineCompilationStatus, which records a concrete run. + FailedISel, + FailsVerification, Count, }; diff --git a/backend/include/rcc/CodeGen/MachineJumpTableInfo.h b/backend/include/rcc/CodeGen/MachineJumpTableInfo.h index 6342281..b22ea50 100644 --- a/backend/include/rcc/CodeGen/MachineJumpTableInfo.h +++ b/backend/include/rcc/CodeGen/MachineJumpTableInfo.h @@ -21,10 +21,13 @@ class MachineBasicBlock; class MachineFunction; enum class JumpTableEntryEncoding : std::uint8_t { - AbsoluteAddress, - RelativeToTableBase, - RelativeToEntry, - CompressedOffset, + BlockAddress, + GPRelative64BlockAddress, + GPRelative32BlockAddress, + LabelDifference32, + LabelDifference64, + Inline, + Custom32, Target, Count, }; @@ -39,7 +42,7 @@ struct JumpTablePlacement final { }; struct MachineJumpTableDesc final { - JumpTableEntryEncoding Encoding = JumpTableEntryEncoding::AbsoluteAddress; + JumpTableEntryEncoding Encoding = JumpTableEntryEncoding::BlockAddress; std::uint8_t EntrySize = 8; Alignment Align; std::vector Targets; @@ -60,16 +63,24 @@ public: return std::holds_alternative(Description); } + [[nodiscard]] bool isPending() const noexcept { + return std::holds_alternative(Description); + } + [[nodiscard]] const MachineJumpTableDesc *description() const noexcept { return std::get_if(&Description); } private: + struct PendingDescription final {}; + MachineJumpTableEntry(JumpTableIndex Index, MachineJumpTableDesc Description) : Index(Index), Description(std::move(Description)) {} + explicit MachineJumpTableEntry(JumpTableIndex Index) + : Index(Index), Description(PendingDescription{}) {} JumpTableIndex Index; - std::variant Description; + std::variant Description; friend class MachineJumpTableInfo; }; @@ -85,6 +96,9 @@ public: ~MachineJumpTableInfo() = default; [[nodiscard]] Expected createTable(MachineJumpTableDesc Description); + [[nodiscard]] Expected reserveTable(); + [[nodiscard]] Expected defineReservedTable(JumpTableIndex Index, + MachineJumpTableDesc Description); [[nodiscard]] Expected updateTable(JumpTableIndex Index, MachineJumpTableDesc Description); [[nodiscard]] Expected eraseTable(JumpTableIndex Index); diff --git a/backend/include/rcc/CodeGen/MachineMetadata.h b/backend/include/rcc/CodeGen/MachineMetadata.h index 95033f6..df56b76 100644 --- a/backend/include/rcc/CodeGen/MachineMetadata.h +++ b/backend/include/rcc/CodeGen/MachineMetadata.h @@ -62,6 +62,11 @@ class MachineMetadataElement final { public: MachineMetadataElement() = default; + struct NullValue final { + friend constexpr bool operator==(NullValue Left, NullValue Right) noexcept = default; + }; + + [[nodiscard]] static MachineMetadataElement null(); [[nodiscard]] static Expected reference(MachineMetadataReference Reference); [[nodiscard]] static MachineMetadataElement string(std::string Value); @@ -78,14 +83,19 @@ public: return std::get_if(&Storage); } + [[nodiscard]] bool isNull() const noexcept { + return std::holds_alternative(Storage); + } + friend bool operator==(const MachineMetadataElement &Left, const MachineMetadataElement &Right) = default; private: + explicit MachineMetadataElement(NullValue Value) : Storage(Value) {} explicit MachineMetadataElement(MachineMetadataReference Reference) : Storage(Reference) {} explicit MachineMetadataElement(std::string Value) : Storage(std::move(Value)) {} - std::variant Storage; + std::variant Storage; }; struct MachineMetadataNode final { diff --git a/backend/include/rcc/CodeGen/MachineOperand.h b/backend/include/rcc/CodeGen/MachineOperand.h index 7344932..b8a6dcc 100644 --- a/backend/include/rcc/CodeGen/MachineOperand.h +++ b/backend/include/rcc/CodeGen/MachineOperand.h @@ -69,6 +69,8 @@ public: std::uint64_t Value); [[nodiscard]] static Expected fromSigned(std::uint32_t BitWidth, std::int64_t Value); + [[nodiscard]] static Expected parseDecimal(std::uint32_t BitWidth, + std::string_view Text); [[nodiscard]] std::uint32_t bitWidth() const noexcept { return BitWidth; @@ -80,6 +82,7 @@ public: [[nodiscard]] bool isZero() const noexcept; [[nodiscard]] bool isNegative() const noexcept; + [[nodiscard]] std::string toUnsignedDecimal() const; [[nodiscard]] Expected verify() const; friend bool operator==(const IntegerImmediate &Left, const IntegerImmediate &Right) = default; diff --git a/backend/include/rcc/CodeGen/TargetMIRTextInfo.h b/backend/include/rcc/CodeGen/TargetMIRTextInfo.h index 4fdbb3a..b8eb4ee 100644 --- a/backend/include/rcc/CodeGen/TargetMIRTextInfo.h +++ b/backend/include/rcc/CodeGen/TargetMIRTextInfo.h @@ -7,6 +7,8 @@ #include "rcc/CodeGen/MachineIRTypes.h" #include "rcc/CodeGen/Register.h" #include "rcc/CodeGen/RegisterMask.h" +#include "rcc/CodeGen/TargetConstant.h" +#include "rcc/CodeGen/TargetFunctionState.h" #include "rcc/Support/Error.h" #include @@ -24,6 +26,55 @@ namespace rcc { class TargetRegisterInfo; +enum class MIRTargetNodeKind : std::uint8_t { + Null, + Scalar, + Sequence, + Mapping, + Count, +}; + +struct MIRTargetMappingEntry; + +struct MIRTargetNode final { + MIRTargetNode(); + MIRTargetNode(const MIRTargetNode &); + MIRTargetNode &operator=(const MIRTargetNode &); + MIRTargetNode(MIRTargetNode &&) noexcept; + MIRTargetNode &operator=(MIRTargetNode &&) noexcept; + ~MIRTargetNode(); + + MIRTargetNodeKind Kind = MIRTargetNodeKind::Null; + std::string Scalar; + std::vector Sequence; + std::vector Mapping; + + [[nodiscard]] static MIRTargetNode null(); + [[nodiscard]] static MIRTargetNode scalar(std::string Value); + [[nodiscard]] static MIRTargetNode sequence(std::vector Values); + [[nodiscard]] static MIRTargetNode mapping(std::vector Entries); + + [[nodiscard]] const MIRTargetNode *mappingValue(std::string_view Key) const noexcept; + [[nodiscard]] Expected verify() const; + + friend bool operator==(const MIRTargetNode &Left, const MIRTargetNode &Right); +}; + +struct MIRTargetMappingEntry final { + std::string Key; + MIRTargetNode Value; + + friend bool operator==(const MIRTargetMappingEntry &Left, + const MIRTargetMappingEntry &Right) = default; +}; + +using MIRTargetFunctionStateParser = + Expected (*)(const MIRTargetNode &Node); +using MIRTargetFunctionStatePrinter = + Expected (*)(const TargetFunctionState &State); +using MIRTargetConstantParser = Expected (*)(std::string_view Text); +using MIRTargetConstantPrinter = Expected (*)(const TargetConstant &Constant); + struct MIRRegisterMaskDesc final { std::string Name; std::shared_ptr Mask; @@ -75,6 +126,10 @@ struct TargetMIRTextInfoDesc final { StackID::noAllocStack(), }; std::optional FunctionStateType; + MIRTargetFunctionStateParser ParseFunctionState = nullptr; + MIRTargetFunctionStatePrinter PrintFunctionState = nullptr; + MIRTargetConstantParser ParseTargetConstant = nullptr; + MIRTargetConstantPrinter PrintTargetConstant = nullptr; }; class TargetMIRTextInfo final { @@ -180,6 +235,14 @@ public: return Description.FunctionStateType; } + [[nodiscard]] Expected + parseFunctionState(const MIRTargetNode &Node) const; + [[nodiscard]] Expected + printFunctionState(const TargetFunctionState &State) const; + [[nodiscard]] Expected parseTargetConstant(std::string_view Text) const; + [[nodiscard]] Expected + printTargetConstant(const TargetConstant &Constant) const; + private: explicit TargetMIRTextInfo(TargetMIRTextInfoDesc Description) : Description(std::move(Description)) {} -- cgit v1.2.3