diff options
| author | Richard-Qin-X <richard.qin.001@gmail.com> | 2026-08-11 17:37:42 +0800 |
|---|---|---|
| committer | Richard-Qin-X <richard.qin.001@gmail.com> | 2026-08-11 17:37:42 +0800 |
| commit | 6a7b083f322f4ac47e58cbf9d4d5fd4d1f6fecd0 (patch) | |
| tree | f363c502f0e2b9cda2f12928049275a433db6ad4 /backend/include/rcc | |
| parent | adcf8c9b1bd1b47e00bf859693112cea1f7e8c9f (diff) | |
| download | rcc-project-6a7b083f322f4ac47e58cbf9d4d5fd4d1f6fecd0.tar.gz rcc-project-6a7b083f322f4ac47e58cbf9d4d5fd4d1f6fecd0.tar.xz | |
[MIR] Accept fixed-baseline LLVM syntax
Diffstat (limited to 'backend/include/rcc')
| -rw-r--r-- | backend/include/rcc/CodeGen/InlineAsm.h | 314 | ||||
| -rw-r--r-- | backend/include/rcc/CodeGen/MachineIRTypes.h | 2 | ||||
| -rw-r--r-- | backend/include/rcc/CodeGen/MachineMemOperand.h | 9 | ||||
| -rw-r--r-- | backend/include/rcc/CodeGen/MachineOperand.h | 1 | ||||
| -rw-r--r-- | backend/include/rcc/CodeGen/MachineRegisterInfo.h | 2 | ||||
| -rw-r--r-- | backend/include/rcc/CodeGen/TargetCodeGen.h | 5 | ||||
| -rw-r--r-- | backend/include/rcc/MIR/EmbeddedIR.h | 9 | ||||
| -rw-r--r-- | backend/include/rcc/MIR/MIDebugSyntax.h | 9 | ||||
| -rw-r--r-- | backend/include/rcc/MIR/MIParser.h | 1 |
9 files changed, 349 insertions, 3 deletions
diff --git a/backend/include/rcc/CodeGen/InlineAsm.h b/backend/include/rcc/CodeGen/InlineAsm.h new file mode 100644 index 0000000..492161f --- /dev/null +++ b/backend/include/rcc/CodeGen/InlineAsm.h @@ -0,0 +1,314 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_CODEGEN_INLINEASM_H +#define RCC_CODEGEN_INLINEASM_H + +#include <array> +#include <cstddef> +#include <cstdint> +#include <optional> +#include <string_view> +#include <vector> + +namespace rcc { + +inline constexpr std::size_t InlineAsmStringOperandIndex = 0; +inline constexpr std::size_t InlineAsmExtraInfoOperandIndex = 1; +inline constexpr std::size_t InlineAsmFirstConstraintOperandIndex = 2; + +enum class InlineAsmExtraInfoFlag : std::uint32_t { + HasSideEffects = 1U, + AlignStack = 2U, + IntelDialect = 4U, + MayLoad = 8U, + MayStore = 16U, + Convergent = 32U, + MayUnwind = 64U, +}; + +class InlineAsmExtraInfo final { +public: + explicit constexpr InlineAsmExtraInfo(std::uint32_t RawValue = 0) noexcept + : Value(RawValue) {} + + [[nodiscard]] constexpr std::uint32_t rawValue() const noexcept { + return Value; + } + + [[nodiscard]] constexpr bool has(InlineAsmExtraInfoFlag Flag) const noexcept { + return (Value & static_cast<std::uint32_t>(Flag)) != 0; + } + + constexpr void set(InlineAsmExtraInfoFlag Flag) noexcept { + Value |= static_cast<std::uint32_t>(Flag); + } + + [[nodiscard]] static constexpr std::optional<std::uint32_t> + namedFlagBits(std::string_view Name) noexcept { + if (Name == "sideeffect") + return static_cast<std::uint32_t>(InlineAsmExtraInfoFlag::HasSideEffects); + if (Name == "mayload") + return static_cast<std::uint32_t>(InlineAsmExtraInfoFlag::MayLoad); + if (Name == "maystore") + return static_cast<std::uint32_t>(InlineAsmExtraInfoFlag::MayStore); + if (Name == "isconvergent") + return static_cast<std::uint32_t>(InlineAsmExtraInfoFlag::Convergent); + if (Name == "alignstack") + return static_cast<std::uint32_t>(InlineAsmExtraInfoFlag::AlignStack); + if (Name == "unwind") + return static_cast<std::uint32_t>(InlineAsmExtraInfoFlag::MayUnwind); + if (Name == "attdialect") + return 0; + if (Name == "inteldialect") + return static_cast<std::uint32_t>(InlineAsmExtraInfoFlag::IntelDialect); + return std::nullopt; + } + + [[nodiscard]] std::vector<std::string_view> names() const { + std::vector<std::string_view> Result; + Result.reserve(7); + if (has(InlineAsmExtraInfoFlag::HasSideEffects)) + Result.push_back("sideeffect"); + if (has(InlineAsmExtraInfoFlag::MayLoad)) + Result.push_back("mayload"); + if (has(InlineAsmExtraInfoFlag::MayStore)) + Result.push_back("maystore"); + if (has(InlineAsmExtraInfoFlag::Convergent)) + Result.push_back("isconvergent"); + if (has(InlineAsmExtraInfoFlag::AlignStack)) + Result.push_back("alignstack"); + if (has(InlineAsmExtraInfoFlag::MayUnwind)) + Result.push_back("unwind"); + Result.push_back(has(InlineAsmExtraInfoFlag::IntelDialect) ? "inteldialect" : "attdialect"); + return Result; + } + + friend constexpr bool operator==(InlineAsmExtraInfo Left, + InlineAsmExtraInfo Right) noexcept = default; + +private: + std::uint32_t Value = 0; +}; + +enum class InlineAsmOperandKind : std::uint8_t { + RegisterUse = 1, + RegisterDef = 2, + RegisterDefEarlyClobber = 3, + Clobber = 4, + Immediate = 5, + Memory = 6, + Function = 7, +}; + +enum class InlineAsmMemoryConstraint : std::uint8_t { + Unknown = 0, + ES, + I, + K, + M, + O, + V, + A, + Q, + R, + S, + T, + UM, + UN, + UQ, + US, + UT, + UV, + UY, + X, + Z, + ZB, + ZC, + ZY, + P, + ZQ, + ZR, + ZS, + ZT, +}; + +struct InlineAsmMemoryConstraintName final { + std::string_view Name; + InlineAsmMemoryConstraint Constraint = InlineAsmMemoryConstraint::Unknown; +}; + +inline constexpr std::array InlineAsmMemoryConstraintNames{ + InlineAsmMemoryConstraintName{"es", InlineAsmMemoryConstraint::ES}, + InlineAsmMemoryConstraintName{"i", InlineAsmMemoryConstraint::I}, + InlineAsmMemoryConstraintName{"k", InlineAsmMemoryConstraint::K}, + InlineAsmMemoryConstraintName{"m", InlineAsmMemoryConstraint::M}, + InlineAsmMemoryConstraintName{"o", InlineAsmMemoryConstraint::O}, + InlineAsmMemoryConstraintName{"v", InlineAsmMemoryConstraint::V}, + InlineAsmMemoryConstraintName{"A", InlineAsmMemoryConstraint::A}, + InlineAsmMemoryConstraintName{"Q", InlineAsmMemoryConstraint::Q}, + InlineAsmMemoryConstraintName{"R", InlineAsmMemoryConstraint::R}, + InlineAsmMemoryConstraintName{"S", InlineAsmMemoryConstraint::S}, + InlineAsmMemoryConstraintName{"T", InlineAsmMemoryConstraint::T}, + InlineAsmMemoryConstraintName{"Um", InlineAsmMemoryConstraint::UM}, + InlineAsmMemoryConstraintName{"Un", InlineAsmMemoryConstraint::UN}, + InlineAsmMemoryConstraintName{"Uq", InlineAsmMemoryConstraint::UQ}, + InlineAsmMemoryConstraintName{"Us", InlineAsmMemoryConstraint::US}, + InlineAsmMemoryConstraintName{"Ut", InlineAsmMemoryConstraint::UT}, + InlineAsmMemoryConstraintName{"Uv", InlineAsmMemoryConstraint::UV}, + InlineAsmMemoryConstraintName{"Uy", InlineAsmMemoryConstraint::UY}, + InlineAsmMemoryConstraintName{"X", InlineAsmMemoryConstraint::X}, + InlineAsmMemoryConstraintName{"Z", InlineAsmMemoryConstraint::Z}, + InlineAsmMemoryConstraintName{"ZB", InlineAsmMemoryConstraint::ZB}, + InlineAsmMemoryConstraintName{"ZC", InlineAsmMemoryConstraint::ZC}, + InlineAsmMemoryConstraintName{"Zy", InlineAsmMemoryConstraint::ZY}, + InlineAsmMemoryConstraintName{"p", InlineAsmMemoryConstraint::P}, + InlineAsmMemoryConstraintName{"ZQ", InlineAsmMemoryConstraint::ZQ}, + InlineAsmMemoryConstraintName{"ZR", InlineAsmMemoryConstraint::ZR}, + InlineAsmMemoryConstraintName{"ZS", InlineAsmMemoryConstraint::ZS}, + InlineAsmMemoryConstraintName{"ZT", InlineAsmMemoryConstraint::ZT}, +}; + +class InlineAsmOperandFlag final { +public: + constexpr InlineAsmOperandFlag(InlineAsmOperandKind Kind, std::uint32_t OperandCount = 1) noexcept + : Value(static_cast<std::uint32_t>(Kind) | + ((OperandCount & OperandCountMask) << OperandCountShift)) {} + + explicit constexpr InlineAsmOperandFlag(std::uint32_t RawValue) noexcept : Value(RawValue) {} + + [[nodiscard]] constexpr std::uint32_t rawValue() const noexcept { + return Value; + } + + [[nodiscard]] constexpr InlineAsmOperandKind kind() const noexcept { + return static_cast<InlineAsmOperandKind>(Value & KindMask); + } + + [[nodiscard]] constexpr std::uint32_t operandCount() const noexcept { + return (Value >> OperandCountShift) & OperandCountMask; + } + + [[nodiscard]] constexpr bool isMatched() const noexcept { + return (Value & MatchedMask) != 0; + } + + [[nodiscard]] constexpr std::optional<std::uint32_t> matchingOperand() const noexcept { + return isMatched() ? std::optional((Value >> PayloadShift) & MatchedOperandMask) + : std::nullopt; + } + + [[nodiscard]] constexpr std::optional<std::uint32_t> registerClass() const noexcept { + if (isMatched()) + return std::nullopt; + const std::uint32_t Encoded = (Value >> PayloadShift) & RegisterClassMask; + return Encoded == 0 ? std::nullopt : std::optional(Encoded); + } + + [[nodiscard]] constexpr InlineAsmMemoryConstraint memoryConstraint() const noexcept { + if (isMatched()) + return InlineAsmMemoryConstraint::Unknown; + return static_cast<InlineAsmMemoryConstraint>((Value >> PayloadShift) & MatchedOperandMask); + } + + [[nodiscard]] constexpr bool setMatchingOperand(std::uint32_t OperandNumber) noexcept { + if (OperandNumber > MatchedOperandMask) + return false; + Value &= ~(MatchedMask | (MatchedOperandMask << PayloadShift)); + Value |= MatchedMask | (OperandNumber << PayloadShift); + return true; + } + + [[nodiscard]] constexpr bool setRegisterClass(std::uint32_t RegisterClass) noexcept { + if (RegisterClass == 0 || RegisterClass > RegisterClassMask || isMatched()) + return false; + Value &= ~(RegisterClassMask << PayloadShift); + Value |= RegisterClass << PayloadShift; + return true; + } + + [[nodiscard]] constexpr bool + setMemoryConstraint(InlineAsmMemoryConstraint Constraint) noexcept { + const std::uint32_t Encoded = static_cast<std::uint32_t>(Constraint); + if (Encoded == 0 || Encoded > MatchedOperandMask || isMatched()) + return false; + Value &= ~(MatchedOperandMask << PayloadShift); + Value |= Encoded << PayloadShift; + return true; + } + + [[nodiscard]] static constexpr std::optional<InlineAsmOperandKind> + kindForName(std::string_view Name) noexcept { + if (Name == "regdef") + return InlineAsmOperandKind::RegisterDef; + if (Name == "reguse") + return InlineAsmOperandKind::RegisterUse; + if (Name == "regdef-ec") + return InlineAsmOperandKind::RegisterDefEarlyClobber; + if (Name == "clobber") + return InlineAsmOperandKind::Clobber; + if (Name == "imm") + return InlineAsmOperandKind::Immediate; + if (Name == "mem") + return InlineAsmOperandKind::Memory; + return std::nullopt; + } + + [[nodiscard]] static constexpr std::string_view + kindName(InlineAsmOperandKind Kind) noexcept { + switch (Kind) { + case InlineAsmOperandKind::RegisterUse: + return "reguse"; + case InlineAsmOperandKind::RegisterDef: + return "regdef"; + case InlineAsmOperandKind::RegisterDefEarlyClobber: + return "regdef-ec"; + case InlineAsmOperandKind::Clobber: + return "clobber"; + case InlineAsmOperandKind::Immediate: + return "imm"; + case InlineAsmOperandKind::Memory: + case InlineAsmOperandKind::Function: + return "mem"; + } + return {}; + } + + [[nodiscard]] static constexpr std::optional<InlineAsmMemoryConstraint> + memoryConstraintForName(std::string_view Name) noexcept { + for (const InlineAsmMemoryConstraintName &Entry : InlineAsmMemoryConstraintNames) { + if (Entry.Name == Name) + return Entry.Constraint; + } + return std::nullopt; + } + + [[nodiscard]] static constexpr std::optional<std::string_view> + memoryConstraintName(InlineAsmMemoryConstraint Constraint) noexcept { + for (const InlineAsmMemoryConstraintName &Entry : InlineAsmMemoryConstraintNames) { + if (Entry.Constraint == Constraint) + return Entry.Name; + } + return std::nullopt; + } + + [[nodiscard]] constexpr bool isRegisterKind() const noexcept { + return kind() == InlineAsmOperandKind::RegisterUse || + kind() == InlineAsmOperandKind::RegisterDef || + kind() == InlineAsmOperandKind::RegisterDefEarlyClobber; + } + +private: + static constexpr std::uint32_t KindMask = 0x7U; + static constexpr std::uint32_t OperandCountShift = 3U; + static constexpr std::uint32_t OperandCountMask = 0x1FFFU; + static constexpr std::uint32_t PayloadShift = 16U; + static constexpr std::uint32_t MatchedOperandMask = 0x7FFFU; + static constexpr std::uint32_t RegisterClassMask = 0x3FFFU; + static constexpr std::uint32_t MatchedMask = 0x80000000U; + + std::uint32_t Value = 0; +}; + +} // namespace rcc + +#endif // RCC_CODEGEN_INLINEASM_H diff --git a/backend/include/rcc/CodeGen/MachineIRTypes.h b/backend/include/rcc/CodeGen/MachineIRTypes.h index 45b5ecf..e71b80e 100644 --- a/backend/include/rcc/CodeGen/MachineIRTypes.h +++ b/backend/include/rcc/CodeGen/MachineIRTypes.h @@ -218,7 +218,7 @@ public: BranchProbability Right) noexcept = default; private: - static constexpr std::uint32_t MaxRawValue = ~std::uint32_t{0}; + static constexpr std::uint32_t MaxRawValue = std::uint32_t{1} << 31U; explicit constexpr BranchProbability(std::uint32_t RawValue) noexcept : RawValue(RawValue) {} diff --git a/backend/include/rcc/CodeGen/MachineMemOperand.h b/backend/include/rcc/CodeGen/MachineMemOperand.h index a9e19a6..c5c1357 100644 --- a/backend/include/rcc/CodeGen/MachineMemOperand.h +++ b/backend/include/rcc/CodeGen/MachineMemOperand.h @@ -3,6 +3,7 @@ #ifndef RCC_CODEGEN_MACHINEMEMOPERAND_H #define RCC_CODEGEN_MACHINEMEMOPERAND_H +#include "rcc/CodeGen/GenericConstant.h" #include "rcc/CodeGen/LowLevelType.h" #include "rcc/CodeGen/MachineIRTypes.h" #include "rcc/CodeGen/MachineMetadata.h" @@ -140,6 +141,7 @@ public: GlobalSymbol, ExternalSymbol, IRValue, + IRConstant, Stack, GOT, ConstantPoolPseudo, @@ -157,6 +159,7 @@ public: [[nodiscard]] static MemoryBase globalSymbol(std::string Name); [[nodiscard]] static MemoryBase externalSymbol(std::string Name); [[nodiscard]] static MemoryBase irValue(std::string Name); + [[nodiscard]] static Expected<MemoryBase> irConstant(GenericConstantData Constant); [[nodiscard]] static MemoryBase stack(); [[nodiscard]] static MemoryBase got(); [[nodiscard]] static MemoryBase constantPoolPseudo(); @@ -173,12 +176,13 @@ public: [[nodiscard]] std::optional<ConstantPoolIndex> constantPoolIndex() const noexcept; [[nodiscard]] std::optional<JumpTableIndex> jumpTableIndex() const noexcept; [[nodiscard]] std::optional<std::string_view> symbolName() const noexcept; + [[nodiscard]] const GenericConstantData *constantValue() const noexcept; friend bool operator==(const MemoryBase &Left, const MemoryBase &Right) = default; private: - using Storage = - std::variant<std::monostate, FrameIndex, ConstantPoolIndex, JumpTableIndex, std::string>; + using Storage = std::variant<std::monostate, FrameIndex, ConstantPoolIndex, JumpTableIndex, + std::string, GenericConstantData>; MemoryBase(Kind BaseKind, Storage Value) : BaseKind(BaseKind), Value(std::move(Value)) {} @@ -193,6 +197,7 @@ struct MachineMemOperandDesc final { AtomicOrdering FailureOrdering = AtomicOrdering::NotAtomic; SyncScopeID SyncScope; MemorySize Size; + std::optional<LLT> MemoryType; Alignment Align; std::optional<Alignment> BaseAlign; std::uint32_t AddressSpace = 0; diff --git a/backend/include/rcc/CodeGen/MachineOperand.h b/backend/include/rcc/CodeGen/MachineOperand.h index 986ba0e..a7feafa 100644 --- a/backend/include/rcc/CodeGen/MachineOperand.h +++ b/backend/include/rcc/CodeGen/MachineOperand.h @@ -83,6 +83,7 @@ public: [[nodiscard]] bool isZero() const noexcept; [[nodiscard]] bool isNegative() const noexcept; [[nodiscard]] std::string toUnsignedDecimal() const; + [[nodiscard]] std::string toSignedDecimal() const; [[nodiscard]] Expected<void> verify() const; friend bool operator==(const IntegerImmediate &Left, const IntegerImmediate &Right) = default; diff --git a/backend/include/rcc/CodeGen/MachineRegisterInfo.h b/backend/include/rcc/CodeGen/MachineRegisterInfo.h index 14e50a3..cc9026e 100644 --- a/backend/include/rcc/CodeGen/MachineRegisterInfo.h +++ b/backend/include/rcc/CodeGen/MachineRegisterInfo.h @@ -14,6 +14,7 @@ #include <memory> #include <optional> #include <span> +#include <string> #include <unordered_map> #include <vector> @@ -79,6 +80,7 @@ private: }; struct VirtualRegisterInfo final { + std::optional<std::string> Name; std::optional<LLT> Type; std::optional<RegisterBankID> Bank; std::optional<RegisterClassID> RegClass; diff --git a/backend/include/rcc/CodeGen/TargetCodeGen.h b/backend/include/rcc/CodeGen/TargetCodeGen.h index f2aac5d..34a6de4 100644 --- a/backend/include/rcc/CodeGen/TargetCodeGen.h +++ b/backend/include/rcc/CodeGen/TargetCodeGen.h @@ -89,6 +89,11 @@ public: const TargetDescription &) const { return {}; } + + [[nodiscard]] virtual Expected<void> + constrainSelectedInstruction(MachineInstr &, MachineFunction &, const TargetDescription &) const { + return {}; + } }; class TargetSSAInfo { diff --git a/backend/include/rcc/MIR/EmbeddedIR.h b/backend/include/rcc/MIR/EmbeddedIR.h index 522a217..99f1493 100644 --- a/backend/include/rcc/MIR/EmbeddedIR.h +++ b/backend/include/rcc/MIR/EmbeddedIR.h @@ -6,6 +6,7 @@ #include "rcc/Support/TextDiagnostic.h" #include <cstddef> +#include <cstdint> #include <functional> #include <optional> #include <span> @@ -52,6 +53,10 @@ public: return IsDefinition; } + [[nodiscard]] bool isUnnamed() const noexcept { + return IsUnnamed; + } + [[nodiscard]] std::span<const EmbeddedIRReference> blocks() const noexcept { return Blocks; } @@ -80,9 +85,12 @@ private: std::string Name; TextRange NameRange; bool IsDefinition = false; + bool IsUnnamed = false; + std::uint64_t NextUnnamedSlot = 0; std::vector<EmbeddedIRReference> Blocks; std::vector<EmbeddedIRReference> Allocas; std::vector<EmbeddedIRReference> Values; + std::vector<EmbeddedIRReference> LocalReferences; 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; @@ -131,6 +139,7 @@ public: } [[nodiscard]] const EmbeddedIRFunction *function(std::string_view Name) const noexcept; + [[nodiscard]] const EmbeddedIRFunction *unnamedFunction(std::size_t Ordinal) const noexcept; [[nodiscard]] const EmbeddedIRReference *globalObject(std::string_view Name) const noexcept; [[nodiscard]] const EmbeddedIRMetadataDefinition *metadata(std::string_view Name) const noexcept; [[nodiscard]] const EmbeddedIRTypeDefinition * diff --git a/backend/include/rcc/MIR/MIDebugSyntax.h b/backend/include/rcc/MIR/MIDebugSyntax.h index a8427dc..4952128 100644 --- a/backend/include/rcc/MIR/MIDebugSyntax.h +++ b/backend/include/rcc/MIR/MIDebugSyntax.h @@ -5,6 +5,8 @@ #include <cstdint> #include <optional> +#include <span> +#include <string> #include <string_view> namespace rcc::mir { @@ -12,6 +14,13 @@ namespace rcc::mir { [[nodiscard]] std::optional<std::uint64_t> parseDIExpressionOpcodeName(std::string_view Name) noexcept; +[[nodiscard]] std::optional<std::uint64_t> +parseDIExpressionAttributeEncodingName(std::string_view Name) noexcept; + +[[nodiscard]] std::string invalidDIExpressionElementMessage(std::string_view Name); + +[[nodiscard]] std::string formatDIExpression(std::span<const std::uint64_t> Elements); + } // 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 116a97f..16af534 100644 --- a/backend/include/rcc/MIR/MIParser.h +++ b/backend/include/rcc/MIR/MIParser.h @@ -65,6 +65,7 @@ struct MIParserContext final { std::vector<MIJumpTableSlot> JumpTables; std::vector<MIMetadataSlot> Metadata; std::vector<MISyncScopeSlot> SyncScopes; + std::function<bool(std::string_view)> HasIRBlock; std::function<Expected<SyncScopeID>(std::string_view)> InternSyncScope; std::function<Expected<std::uint32_t>(std::uint32_t)> PointerSizeInBits; std::uint32_t DefaultPointerSizeInBits = 0; |
