diff options
Diffstat (limited to 'backend/include')
| -rw-r--r-- | backend/include/rcc/CodeGen/GenericConstant.h | 176 | ||||
| -rw-r--r-- | backend/include/rcc/CodeGen/InstructionDescriptor.h | 1 | ||||
| -rw-r--r-- | backend/include/rcc/CodeGen/MachineConstantPool.h | 9 | ||||
| -rw-r--r-- | backend/include/rcc/CodeGen/MachineFrameInfo.h | 79 | ||||
| -rw-r--r-- | backend/include/rcc/CodeGen/MachineFunctionProperties.h | 4 | ||||
| -rw-r--r-- | backend/include/rcc/CodeGen/MachineJumpTableInfo.h | 26 | ||||
| -rw-r--r-- | backend/include/rcc/CodeGen/MachineMetadata.h | 12 | ||||
| -rw-r--r-- | backend/include/rcc/CodeGen/MachineOperand.h | 3 | ||||
| -rw-r--r-- | backend/include/rcc/CodeGen/TargetMIRTextInfo.h | 63 | ||||
| -rw-r--r-- | backend/include/rcc/MIR/EmbeddedIR.h | 39 | ||||
| -rw-r--r-- | backend/include/rcc/MIR/LLVMConstantSyntax.h | 52 | ||||
| -rw-r--r-- | backend/include/rcc/MIR/MIDebugSyntax.h | 17 | ||||
| -rw-r--r-- | backend/include/rcc/MIR/MIParser.h | 12 | ||||
| -rw-r--r-- | backend/include/rcc/MIR/MIRDocument.h | 143 |
14 files changed, 611 insertions, 25 deletions
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 <cstddef> +#include <cstdint> +#include <optional> +#include <string> +#include <vector> + +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<GenericConstantType> Elements; + + [[nodiscard]] static Expected<GenericConstantType> integer(std::uint32_t BitWidth); + [[nodiscard]] static GenericConstantType primitive(GenericConstantTypeKind Kind) noexcept; + [[nodiscard]] static GenericConstantType byte() noexcept; + [[nodiscard]] static Expected<GenericConstantType> floating(FloatSemantics Semantics); + [[nodiscard]] static GenericConstantType pointer(std::uint32_t AddressSpace = 0) noexcept; + [[nodiscard]] static Expected<GenericConstantType> + array(std::uint64_t ElementCount, GenericConstantType Element); + [[nodiscard]] static Expected<GenericConstantType> + vector(std::uint64_t ElementCount, GenericConstantType Element, bool Scalable = false); + [[nodiscard]] static Expected<GenericConstantType> + structure(std::vector<GenericConstantType> Elements, bool Packed = false); + [[nodiscard]] static Expected<GenericConstantType> + function(GenericConstantType Return, std::vector<GenericConstantType> Parameters, + bool VarArg = false); + [[nodiscard]] static Expected<GenericConstantType> named(std::string Name, + bool NumericName = false); + + [[nodiscard]] Expected<void> 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<std::uint8_t>(Flag); + if (Index >= static_cast<std::uint8_t>(GenericConstantExpressionFlag::Count)) + return false; + return (Mask & (std::uint8_t{1} << Index)) != 0; + } + + constexpr void set(GenericConstantExpressionFlag Flag) noexcept { + const auto Index = static_cast<std::uint8_t>(Flag); + if (Index < static_cast<std::uint8_t>(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<IntegerImmediate> IntegerValue; + std::optional<FloatingPointBits> FloatingValue; + std::vector<std::byte> ByteValue; + std::vector<GenericConstantData> Elements; + std::string Symbol; + std::string Block; + bool NumericSymbol = false; + bool NumericBlock = false; + GenericConstantExpressionOpcode ExpressionOpcode = + GenericConstantExpressionOpcode::Invalid; + GenericConstantExpressionFlags ExpressionFlags; + std::optional<GenericConstantType> SourceElementType; + std::optional<IntegerImmediate> InRangeStart; + std::optional<IntegerImmediate> InRangeEnd; + + [[nodiscard]] static Expected<GenericConstantData> integer(IntegerImmediate Value); + [[nodiscard]] static Expected<GenericConstantData> floating(FloatingPointBits Value); + [[nodiscard]] static Expected<GenericConstantData> byteString(GenericConstantType Type, + std::vector<std::byte> Bytes); + + [[nodiscard]] Expected<void> 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<std::byte> 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 <cstdint> #include <optional> #include <span> +#include <string> #include <string_view> #include <utility> #include <variant> @@ -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<std::string> AllocaName; std::optional<std::uint64_t> Size; Alignment Align; std::optional<std::int64_t> Offset; StackID Stack; bool IsDead = false; + bool IsImmutable = false; bool IsAliased = false; bool AddressTaken = false; + std::optional<PhysicalRegister> CalleeSavedRegister; + bool CalleeSavedRestored = true; + std::optional<std::int64_t> LocalOffset; std::vector<StackObjectLifetimeRange> Lifetime; std::optional<MachineVariableDebugInfo> 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<MachineFramePointerPolicy> +parseMachineFramePointerPolicy(std::string_view Name) noexcept; +[[nodiscard]] std::string_view +getMachineFramePointerPolicyName(MachineFramePointerPolicy Policy) noexcept; + +struct MachineFrameSaveRestorePoint final { + MachineBlockStableID Block; + std::vector<PhysicalRegister> 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<Alignment> MaxAlignment; + bool AdjustsStack = false; + bool HasCalls = false; + MachineFramePointerPolicy FramePointerPolicy = MachineFramePointerPolicy::None; + std::optional<FrameIndex> StackProtector; + std::optional<FrameIndex> FunctionContext; + std::optional<std::uint64_t> 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<MachineFrameSaveRestorePoint> SavePoints; + std::vector<MachineFrameSaveRestorePoint> 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<std::uint64_t> 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<std::uint64_t> maxCallFrameSize() const noexcept { + return State.MaxCallFrameSize; } + [[nodiscard]] Expected<void> setState(MachineFrameState NewState); [[nodiscard]] Expected<void> setMaxCallFrameSize(std::uint64_t Size); + [[nodiscard]] Expected<void> clearMaxCallFrameSize(); [[nodiscard]] Expected<void> freeze(std::uint64_t Size, Alignment Align); [[nodiscard]] Expected<void> verify() const; private: [[nodiscard]] static Expected<void> verifyDescription(const StackObjectDesc &Description); + [[nodiscard]] static Expected<void> verifyStateStructure(const MachineFrameState &State); [[nodiscard]] Expected<StackObject *> mutableObject(FrameIndex Index); std::vector<StackObject> Objects; + MachineFrameState State; bool Frozen = false; - std::optional<std::uint64_t> 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<MachineBasicBlock *> Targets; @@ -60,16 +63,24 @@ public: return std::holds_alternative<std::monostate>(Description); } + [[nodiscard]] bool isPending() const noexcept { + return std::holds_alternative<PendingDescription>(Description); + } + [[nodiscard]] const MachineJumpTableDesc *description() const noexcept { return std::get_if<MachineJumpTableDesc>(&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<std::monostate, MachineJumpTableDesc> Description; + std::variant<std::monostate, PendingDescription, MachineJumpTableDesc> Description; friend class MachineJumpTableInfo; }; @@ -85,6 +96,9 @@ public: ~MachineJumpTableInfo() = default; [[nodiscard]] Expected<JumpTableIndex> createTable(MachineJumpTableDesc Description); + [[nodiscard]] Expected<JumpTableIndex> reserveTable(); + [[nodiscard]] Expected<void> defineReservedTable(JumpTableIndex Index, + MachineJumpTableDesc Description); [[nodiscard]] Expected<void> updateTable(JumpTableIndex Index, MachineJumpTableDesc Description); [[nodiscard]] Expected<void> 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<MachineMetadataElement> reference(MachineMetadataReference Reference); [[nodiscard]] static MachineMetadataElement string(std::string Value); @@ -78,14 +83,19 @@ public: return std::get_if<std::string>(&Storage); } + [[nodiscard]] bool isNull() const noexcept { + return std::holds_alternative<NullValue>(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<std::monostate, MachineMetadataReference, std::string> Storage; + std::variant<std::monostate, NullValue, MachineMetadataReference, std::string> 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<IntegerImmediate> fromSigned(std::uint32_t BitWidth, std::int64_t Value); + [[nodiscard]] static Expected<IntegerImmediate> 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<void> 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 <cstdint> @@ -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<MIRTargetNode> Sequence; + std::vector<MIRTargetMappingEntry> Mapping; + + [[nodiscard]] static MIRTargetNode null(); + [[nodiscard]] static MIRTargetNode scalar(std::string Value); + [[nodiscard]] static MIRTargetNode sequence(std::vector<MIRTargetNode> Values); + [[nodiscard]] static MIRTargetNode mapping(std::vector<MIRTargetMappingEntry> Entries); + + [[nodiscard]] const MIRTargetNode *mappingValue(std::string_view Key) const noexcept; + [[nodiscard]] Expected<void> 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<TargetFunctionState> (*)(const MIRTargetNode &Node); +using MIRTargetFunctionStatePrinter = + Expected<MIRTargetNode> (*)(const TargetFunctionState &State); +using MIRTargetConstantParser = Expected<TargetConstant> (*)(std::string_view Text); +using MIRTargetConstantPrinter = Expected<std::string> (*)(const TargetConstant &Constant); + struct MIRRegisterMaskDesc final { std::string Name; std::shared_ptr<const RegisterMask> Mask; @@ -75,6 +126,10 @@ struct TargetMIRTextInfoDesc final { StackID::noAllocStack(), }; std::optional<TargetFunctionStateTypeID> 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<TargetFunctionState> + parseFunctionState(const MIRTargetNode &Node) const; + [[nodiscard]] Expected<MIRTargetNode> + printFunctionState(const TargetFunctionState &State) const; + [[nodiscard]] Expected<TargetConstant> parseTargetConstant(std::string_view Text) const; + [[nodiscard]] Expected<std::string> + printTargetConstant(const TargetConstant &Constant) const; + private: explicit TargetMIRTextInfo(TargetMIRTextInfoDesc Description) : Description(std::move(Description)) {} diff --git a/backend/include/rcc/MIR/EmbeddedIR.h b/backend/include/rcc/MIR/EmbeddedIR.h index 8e9e0f6..50567de 100644 --- a/backend/include/rcc/MIR/EmbeddedIR.h +++ b/backend/include/rcc/MIR/EmbeddedIR.h @@ -24,6 +24,20 @@ struct EmbeddedIRReference final { TextRange Range; }; +struct EmbeddedIRMetadataDefinition final { + std::string Name; + TextRange Range; + std::string DynamicType; +}; + +struct EmbeddedIRTypeDefinition final { + std::string Name; + TextRange Range; + std::string Definition; + TextRange DefinitionRange; + bool NumericName = false; +}; + class EmbeddedIRFunction final { public: [[nodiscard]] std::string_view name() const noexcept { @@ -46,8 +60,13 @@ public: return Allocas; } + [[nodiscard]] std::span<const EmbeddedIRReference> values() const noexcept { + return Values; + } + [[nodiscard]] const EmbeddedIRReference *block(std::string_view QueryName) const noexcept; [[nodiscard]] const EmbeddedIRReference *alloca(std::string_view QueryName) const noexcept; + [[nodiscard]] const EmbeddedIRReference *value(std::string_view QueryName) const noexcept; private: struct StringHash final { @@ -63,8 +82,10 @@ private: bool IsDefinition = false; std::vector<EmbeddedIRReference> Blocks; std::vector<EmbeddedIRReference> Allocas; + std::vector<EmbeddedIRReference> Values; std::unordered_map<std::string, std::size_t, StringHash, std::equal_to<>> BlockNameToIndex; std::unordered_map<std::string, std::size_t, StringHash, std::equal_to<>> AllocaNameToIndex; + std::unordered_map<std::string, std::size_t, StringHash, std::equal_to<>> ValueNameToIndex; friend class EmbeddedIRIndexer; }; @@ -101,13 +122,19 @@ public: return GlobalObjects; } - [[nodiscard]] std::span<const EmbeddedIRReference> metadataDefinitions() const noexcept { + [[nodiscard]] std::span<const EmbeddedIRMetadataDefinition> + metadataDefinitions() const noexcept { return MetadataDefinitions; } + [[nodiscard]] std::span<const EmbeddedIRTypeDefinition> typeDefinitions() const noexcept { + return TypeDefinitions; + } + [[nodiscard]] const EmbeddedIRFunction *function(std::string_view Name) const noexcept; [[nodiscard]] const EmbeddedIRReference *globalObject(std::string_view Name) const noexcept; - [[nodiscard]] const EmbeddedIRReference *metadata(std::string_view Name) const noexcept; + [[nodiscard]] const EmbeddedIRMetadataDefinition *metadata(std::string_view Name) const noexcept; + [[nodiscard]] const EmbeddedIRTypeDefinition *typeDefinition(std::string_view Name) const noexcept; [[nodiscard]] bool hasGlobalValue(std::string_view Name) const noexcept { return function(Name) != nullptr || globalObject(Name) != nullptr; } @@ -131,10 +158,12 @@ private: std::optional<TextRange> DataLayoutRange; std::vector<EmbeddedIRFunction> Functions; std::vector<EmbeddedIRReference> GlobalObjects; - std::vector<EmbeddedIRReference> MetadataDefinitions; + std::vector<EmbeddedIRMetadataDefinition> MetadataDefinitions; + std::vector<EmbeddedIRTypeDefinition> TypeDefinitions; std::unordered_map<std::string, std::size_t, StringHash, std::equal_to<>> FunctionNameToIndex; std::unordered_map<std::string, std::size_t, StringHash, std::equal_to<>> GlobalNameToIndex; std::unordered_map<std::string, std::size_t, StringHash, std::equal_to<>> MetadataNameToIndex; + std::unordered_map<std::string, std::size_t, StringHash, std::equal_to<>> TypeNameToIndex; friend class EmbeddedIRIndexer; }; @@ -159,6 +188,10 @@ public: return Diagnostics; } + [[nodiscard]] std::optional<EmbeddedIRReferenceIndex> takeIndex() && { + return std::move(Index); + } + private: EmbeddedIRIndexResult() = default; diff --git a/backend/include/rcc/MIR/LLVMConstantSyntax.h b/backend/include/rcc/MIR/LLVMConstantSyntax.h new file mode 100644 index 0000000..9d7a7d4 --- /dev/null +++ b/backend/include/rcc/MIR/LLVMConstantSyntax.h @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_MIR_LLVMCONSTANTSYNTAX_H +#define RCC_MIR_LLVMCONSTANTSYNTAX_H + +#include "rcc/CodeGen/GenericConstant.h" +#include "rcc/Support/Error.h" + +#include <cstddef> +#include <cstdint> +#include <span> +#include <string> +#include <string_view> + +namespace rcc::mir { + +struct LLVMNamedTypeDefinition final { + std::string_view Name; + std::string_view Definition; + bool NumericName = false; +}; + +struct LLVMConstantSyntaxOptions final { + std::uint32_t DefaultPointerSizeInBits = 0; + std::string_view DataLayout; + std::span<const LLVMNamedTypeDefinition> NamedTypes; + std::size_t MaximumDepth = 1024; + std::size_t MaximumNodes = std::size_t{1} << 24U; + std::size_t MaximumTokenLength = std::size_t{1} << 24U; +}; + +[[nodiscard]] Expected<GenericConstantData> +parseLLVMConstant(std::string_view Text, LLVMConstantSyntaxOptions Options = {}); + +[[nodiscard]] Expected<GenericConstantType> parseLLVMType(std::string_view Text, + LLVMConstantSyntaxOptions Options = {}); + +[[nodiscard]] Expected<std::string> printLLVMConstant(const GenericConstantData &Constant); + +[[nodiscard]] Expected<std::uint64_t> +llvmConstantStorageSize(const GenericConstantType &Type, LLVMConstantSyntaxOptions Options = {}); + +[[nodiscard]] Expected<Alignment> +llvmConstantPreferredAlignment(const GenericConstantType &Type, + LLVMConstantSyntaxOptions Options = {}); + +[[nodiscard]] Expected<std::uint32_t> llvmPointerSizeInBits(std::uint32_t AddressSpace, + LLVMConstantSyntaxOptions Options = {}); + +} // namespace rcc::mir + +#endif // RCC_MIR_LLVMCONSTANTSYNTAX_H diff --git a/backend/include/rcc/MIR/MIDebugSyntax.h b/backend/include/rcc/MIR/MIDebugSyntax.h new file mode 100644 index 0000000..a8427dc --- /dev/null +++ b/backend/include/rcc/MIR/MIDebugSyntax.h @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_MIR_MIDEBUGSYNTAX_H +#define RCC_MIR_MIDEBUGSYNTAX_H + +#include <cstdint> +#include <optional> +#include <string_view> + +namespace rcc::mir { + +[[nodiscard]] std::optional<std::uint64_t> +parseDIExpressionOpcodeName(std::string_view Name) noexcept; + +} // namespace rcc::mir + +#endif // RCC_MIR_MIDEBUGSYNTAX_H diff --git a/backend/include/rcc/MIR/MIParser.h b/backend/include/rcc/MIR/MIParser.h index 978e928..116a97f 100644 --- a/backend/include/rcc/MIR/MIParser.h +++ b/backend/include/rcc/MIR/MIParser.h @@ -5,15 +5,18 @@ #include "rcc/CodeGen/MachineIRTypes.h" #include "rcc/CodeGen/MachineMetadata.h" +#include "rcc/CodeGen/Register.h" #include "rcc/Support/Error.h" #include "rcc/Support/TextDiagnostic.h" #include <cstddef> #include <cstdint> +#include <functional> #include <memory> #include <optional> #include <span> #include <string> +#include <string_view> #include <vector> namespace rcc { @@ -23,6 +26,11 @@ class TargetDescription; namespace mir { +struct MIVirtualRegisterSlot final { + std::uint32_t TextID = 0; + Register Reg; +}; + struct MIFrameObjectSlot final { std::uint32_t TextID = 0; FrameIndex Index; @@ -50,12 +58,15 @@ struct MISyncScopeSlot final { }; struct MIParserContext final { + std::vector<MIVirtualRegisterSlot> VirtualRegisters; std::vector<MIFrameObjectSlot> StackObjects; std::vector<MIFrameObjectSlot> FixedStackObjects; std::vector<MIConstantPoolSlot> ConstantPoolItems; std::vector<MIJumpTableSlot> JumpTables; std::vector<MIMetadataSlot> Metadata; std::vector<MISyncScopeSlot> SyncScopes; + std::function<Expected<SyncScopeID>(std::string_view)> InternSyncScope; + std::function<Expected<std::uint32_t>(std::uint32_t)> PointerSizeInBits; std::uint32_t DefaultPointerSizeInBits = 0; }; @@ -66,6 +77,7 @@ struct MIParserOptions final { std::size_t MaximumInstructions = std::size_t{1} << 24U; std::size_t MaximumOperandsPerInstruction = std::size_t{1} << 20U; std::size_t MaximumMemoryOperandsPerInstruction = std::size_t{1} << 20U; + bool VerifyAfterParse = true; }; class MIParser final { diff --git a/backend/include/rcc/MIR/MIRDocument.h b/backend/include/rcc/MIR/MIRDocument.h new file mode 100644 index 0000000..7980ca1 --- /dev/null +++ b/backend/include/rcc/MIR/MIRDocument.h @@ -0,0 +1,143 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_MIR_MIRDOCUMENT_H +#define RCC_MIR_MIRDOCUMENT_H + +#include "rcc/CodeGen/CompilationUnit.h" +#include "rcc/CodeGen/StableID.h" +#include "rcc/MIR/EmbeddedIR.h" +#include "rcc/MIR/MIParser.h" +#include "rcc/MIR/MIPrinter.h" +#include "rcc/Support/TextDiagnostic.h" +#include "rcc/Support/YAML.h" + +#include <cstdint> +#include <optional> +#include <span> +#include <string> +#include <utility> +#include <vector> + +namespace rcc { + +class TargetDescription; + +namespace mir { + +struct MIRFunctionDocumentInfo final { + MachineFunctionStableID Function; + std::optional<bool> NoPHIs; + std::optional<bool> IsSSA; + std::optional<bool> NoVRegs; + std::optional<bool> HasFakeUses; + + friend bool operator==(const MIRFunctionDocumentInfo &Left, + const MIRFunctionDocumentInfo &Right) = default; +}; + +class MIRDocument final { +public: + MIRDocument(); + explicit MIRDocument(CompilationUnit Unit); + MIRDocument(const MIRDocument &) = delete; + MIRDocument &operator=(const MIRDocument &) = delete; + MIRDocument(MIRDocument &&) noexcept; + MIRDocument &operator=(MIRDocument &&) noexcept; + ~MIRDocument(); + + [[nodiscard]] CompilationUnit &unit() noexcept { + return Unit; + } + + [[nodiscard]] const CompilationUnit &unit() const noexcept { + return Unit; + } + + [[nodiscard]] const EmbeddedIRReferenceIndex *embeddedIR() const noexcept { + return EmbeddedIR ? &*EmbeddedIR : nullptr; + } + + [[nodiscard]] std::span<const MIRFunctionDocumentInfo> functionDocumentInfo() const noexcept { + return FunctionInfo; + } + + [[nodiscard]] std::span<const MISyncScopeSlot> syncScopes() const noexcept { + return SyncScopes; + } + +private: + CompilationUnit Unit; + std::optional<EmbeddedIRReferenceIndex> EmbeddedIR; + std::vector<MIRFunctionDocumentInfo> FunctionInfo; + std::vector<MISyncScopeSlot> SyncScopes; + + friend class MIRDocumentParser; +}; + +struct MIRDocumentParserOptions final { + yaml::ParseOptions YAML; + MIParserOptions MachineInstructions; + std::string DataLayout; + std::uint32_t DefaultPointerSizeInBits = 0; + bool VerifyMachineFunctions = true; +}; + +class MIRDocumentParseResult final { +public: + MIRDocumentParseResult(const MIRDocumentParseResult &) = delete; + MIRDocumentParseResult &operator=(const MIRDocumentParseResult &) = delete; + MIRDocumentParseResult(MIRDocumentParseResult &&) noexcept; + MIRDocumentParseResult &operator=(MIRDocumentParseResult &&) noexcept; + ~MIRDocumentParseResult(); + + [[nodiscard]] bool succeeded() const noexcept { + return Document.has_value() && Diagnostics.empty(); + } + + [[nodiscard]] MIRDocument *document() noexcept { + return Document ? &*Document : nullptr; + } + + [[nodiscard]] const MIRDocument *document() const noexcept { + return Document ? &*Document : nullptr; + } + + [[nodiscard]] const TextSource &source() const noexcept { + return Source; + } + + [[nodiscard]] std::span<const TextDiagnostic> diagnostics() const noexcept { + return Diagnostics; + } + +private: + MIRDocumentParseResult(std::string SourceName, std::string SourceText) + : Source(std::move(SourceName), std::move(SourceText)) {} + + TextSource Source; + std::optional<MIRDocument> Document; + std::vector<TextDiagnostic> Diagnostics; + + friend class MIRDocumentParser; +}; + +[[nodiscard]] MIRDocumentParseResult parseMIRDocument(const TargetDescription &Target, + std::string SourceName, + std::string SourceText, + MIRDocumentParserOptions Options = {}); + +struct MIRDocumentPrinterOptions final { + MIPrintMode Mode = MIPrintMode::Complete; + bool EmitEmbeddedIR = true; + std::string DataLayout; + std::uint32_t DefaultPointerSizeInBits = 0; +}; + +[[nodiscard]] Expected<std::string> printMIRDocument(const MIRDocument &Document, + const TargetDescription &Target, + MIRDocumentPrinterOptions Options = {}); + +} // namespace mir +} // namespace rcc + +#endif // RCC_MIR_MIRDOCUMENT_H |
