diff options
| author | Richard-Qin-X <richard.qin.001@gmail.com> | 2026-08-07 01:27:41 +0800 |
|---|---|---|
| committer | Richard-Qin-X <richard.qin.001@gmail.com> | 2026-08-07 01:27:41 +0800 |
| commit | 76d89700953ddd81cf31ab8f260eddf67e93aa85 (patch) | |
| tree | c96a453164154b2d1559cea36910df52103f0f19 /backend/include/rcc/CodeGen | |
| parent | 183e2354e9fdd107be420cbb185c1d239434aa48 (diff) | |
| download | rcc-project-76d89700953ddd81cf31ab8f260eddf67e93aa85.tar.gz rcc-project-76d89700953ddd81cf31ab8f260eddf67e93aa85.tar.xz | |
[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.
Diffstat (limited to 'backend/include/rcc/CodeGen')
| -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 |
9 files changed, 351 insertions, 22 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)) {} |
