// SPDX-License-Identifier: GPL-3.0-or-later #ifndef RCC_CODEGEN_TARGETFUNCTIONSTATE_H #define RCC_CODEGEN_TARGETFUNCTIONSTATE_H #include "rcc/CodeGen/MachineIRTypes.h" #include "rcc/Support/Error.h" #include #include #include #include #include #include #include #include #include namespace rcc { class MachineFunctionCloneContext; struct EncodedTargetFunctionState final { TargetFunctionStateTypeID TypeID; std::uint32_t Version = 0; std::vector Payload; friend bool operator==(const EncodedTargetFunctionState &Left, const EncodedTargetFunctionState &Right) = default; }; template concept TargetFunctionStateValue = std::move_constructible && requires(const ValueT &Value, const ValueT &Other, const MachineFunctionCloneContext &CloneContext, std::uint32_t Version, std::span Payload) { { ValueT::stableTypeID() } -> std::same_as; { ValueT::schemaVersion() } -> std::same_as; { Value.verify() } -> std::same_as>; { Value.clone(CloneContext) } -> std::same_as>; { Value.print() } -> std::same_as; { Value.encode() } -> std::same_as>>; { Value == Other } -> std::convertible_to; { ValueT::decode(Version, Payload) } -> std::same_as>; }; class TargetFunctionState final { public: TargetFunctionState() = default; TargetFunctionState(const TargetFunctionState &) = delete; TargetFunctionState &operator=(const TargetFunctionState &) = delete; TargetFunctionState(TargetFunctionState &&) noexcept; TargetFunctionState &operator=(TargetFunctionState &&) noexcept; ~TargetFunctionState(); template [[nodiscard]] static Expected create(ValueT Value) { if (ValueT::stableTypeID().value() == 0) { return makeUnexpected(ErrorCode::InvalidArgument, "target function state TypeID must be nonzero"); } if (ValueT::schemaVersion() == 0) { return makeUnexpected(ErrorCode::InvalidArgument, "target function state schema version must be nonzero"); } auto Verification = Value.verify(); if (!Verification) return std::unexpected(Verification.error()); std::unique_ptr NewStorage = std::make_unique>(std::move(Value)); return TargetFunctionState(std::move(NewStorage)); } template [[nodiscard]] static Expected decode(const EncodedTargetFunctionState &Encoded) { if (Encoded.TypeID != ValueT::stableTypeID()) { return makeUnexpected( ErrorCode::ParseError, "encoded target function state TypeID does not match its target schema"); } if (Encoded.Version == 0) { return makeUnexpected(ErrorCode::ParseError, "target function state version must be nonzero"); } auto Value = ValueT::decode(Encoded.Version, Encoded.Payload); if (!Value) return std::unexpected(Value.error()); return create(std::move(*Value)); } [[nodiscard]] bool hasValue() const noexcept { return Storage != nullptr; } [[nodiscard]] std::optional typeID() const noexcept; [[nodiscard]] std::optional schemaVersion() const noexcept; [[nodiscard]] Expected verify() const; [[nodiscard]] Expected clone(const MachineFunctionCloneContext &CloneContext) const; [[nodiscard]] Expected print() const; [[nodiscard]] Expected encode() const; [[nodiscard]] bool equals(const TargetFunctionState &Other) const noexcept; template [[nodiscard]] ValueT *getIf() noexcept { if (!hasType()) return nullptr; return &static_cast *>(Storage.get())->value(); } template [[nodiscard]] const ValueT *getIf() const noexcept { if (!hasType()) return nullptr; return &static_cast *>(Storage.get())->value(); } private: class Concept { public: Concept() = default; Concept(const Concept &) = delete; Concept &operator=(const Concept &) = delete; Concept(Concept &&) = delete; Concept &operator=(Concept &&) = delete; virtual ~Concept() = default; [[nodiscard]] virtual TargetFunctionStateTypeID typeID() const noexcept = 0; [[nodiscard]] virtual std::uint32_t schemaVersion() const noexcept = 0; [[nodiscard]] virtual const void *localTypeToken() const noexcept = 0; [[nodiscard]] virtual Expected verify() const = 0; [[nodiscard]] virtual Expected> cloneStorage(const MachineFunctionCloneContext &CloneContext) const = 0; [[nodiscard]] virtual std::string print() const = 0; [[nodiscard]] virtual Expected> encodePayload() const = 0; [[nodiscard]] virtual bool equals(const Concept &Other) const noexcept = 0; }; template [[nodiscard]] static const void *typeToken() noexcept { static const std::byte Token{}; return &Token; } template class Model final : public Concept { public: explicit Model(ValueT Value) : Value(std::move(Value)) {} [[nodiscard]] TargetFunctionStateTypeID typeID() const noexcept override { return ValueT::stableTypeID(); } [[nodiscard]] std::uint32_t schemaVersion() const noexcept override { return ValueT::schemaVersion(); } [[nodiscard]] const void *localTypeToken() const noexcept override { return TargetFunctionState::typeToken(); } [[nodiscard]] Expected verify() const override { return Value.verify(); } [[nodiscard]] Expected> cloneStorage(const MachineFunctionCloneContext &CloneContext) const override { auto Cloned = Value.clone(CloneContext); if (!Cloned) return std::unexpected(Cloned.error()); std::unique_ptr Result = std::make_unique>(std::move(*Cloned)); return Result; } [[nodiscard]] std::string print() const override { return Value.print(); } [[nodiscard]] Expected> encodePayload() const override { return Value.encode(); } [[nodiscard]] bool equals(const Concept &Other) const noexcept override { if (Other.localTypeToken() != TargetFunctionState::typeToken()) return false; return Value == static_cast &>(Other).Value; } [[nodiscard]] ValueT &value() noexcept { return Value; } [[nodiscard]] const ValueT &value() const noexcept { return Value; } private: ValueT Value; }; explicit TargetFunctionState(std::unique_ptr Storage) : Storage(std::move(Storage)) {} template [[nodiscard]] bool hasType() const noexcept { return Storage != nullptr && Storage->typeID() == ValueT::stableTypeID() && Storage->localTypeToken() == typeToken(); } std::unique_ptr Storage; }; } // namespace rcc #endif // RCC_CODEGEN_TARGETFUNCTIONSTATE_H