#pragma once // // This file is distributed under the MIT License. See LICENSE.md for details. // #include "revng/ADT/ConstexprString.h" #include "revng/ADT/STLExtras.h" namespace ptml { // Attribute in this context is a revng-specific macro that gets unrolled into // an `__attribute__(($something))` for the compiler. struct Attribute { std::string_view Macro; std::string_view Value; bool IsReal = false; }; // Annotation is an attribute that can also encode a value // (for example an abi name). struct Annotation { std::string_view Macro; std::string_view Prefix; }; struct AttributeRegistry { static constexpr std::array StaticAttributes{ Attribute{ .Macro = "_PACKED", .Value = "packed", .IsReal = true }, Attribute{ .Macro = "_STACK", .Value = "stack" }, Attribute{ .Macro = "_CAN_CONTAIN_CODE", .Value = "can_contain_code" } }; static constexpr std::array StaticAnnotations{ Annotation{ .Macro = "_REG", .Prefix = "reg:" }, Annotation{ .Macro = "_ABI", .Prefix = "abi:" }, Annotation{ .Macro = "_START_AT", .Prefix = "field_start_offset:" }, Annotation{ .Macro = "_SIZE", .Prefix = "struct_size:" }, Annotation{ .Macro = "_ENUM_UNDERLYING", .Prefix = "enum_underlying_type:" } }; // TODO: add dynamic containers if the need ever arises. private: template static consteval std::optional getAttributeImpl() { auto Result = std::ranges::find_if(StaticAttributes, [](auto &&A) { return *Macro == A.Macro; }); if (Result == StaticAttributes.end()) return std::nullopt; return *Result; } template static consteval std::optional getAnnotationImpl() { auto Result = std::ranges::find_if(StaticAnnotations, [](auto &&A) { return *Macro == A.Macro; }); if (Result == StaticAnnotations.end()) return std::nullopt; return *Result; } public: template static std::string getAttribute() { constexpr std::optional Attribute = getAttributeImpl(); if constexpr (Attribute) { return std::string(Attribute->Macro); } else { static_assert(value_always_false_v, "Unknown attribute."); } } template static std::string getAnnotation(std::string_view Value) { constexpr std::optional Annotation = getAnnotationImpl(); if constexpr (Annotation) { return std::string(Annotation->Macro) + "(" + std::string(Value) + ")"; } else { static_assert(value_always_false_v, "Unknown annotation."); } } template static std::string getAnnotation(uint64_t Value) { return getAnnotation(std::to_string(Value)); } template static consteval std::string_view getPrefix() { constexpr std::optional Annotation = getAnnotationImpl(); if constexpr (Annotation) { return Annotation->Prefix; } else { constexpr std::optional Attribute = getAttributeImpl(); if constexpr (Attribute) { return Attribute->Value; } else { static_assert(value_always_false_v, "Unknown attribute or annotation."); } } } // TODO: Generate `attributes.h` header instead of providing a static one, // which would enable users to Ctrl + click these macros. static std::string getDefinitions() { std::string Result; for (Attribute const &Attribute : StaticAttributes) { Result += "#define " + std::string(Attribute.Macro) + " __attribute__(("; if (Attribute.IsReal) Result += std::string(Attribute.Value); else Result += "annotate(\"" + std::string(Attribute.Value) + "\")"; Result += "))\n"; } for (Annotation const &Annotation : StaticAnnotations) { Result += "#define " + std::string(Annotation.Macro) + "(value) __attribute__((annotate(\"" + std::string(Annotation.Prefix) + "value\")))\n"; } return Result; } public: constexpr bool isMacro(llvm::StringRef String) const { auto Comparator = [String](const auto &A) { return std::string_view(String) == A.Macro; }; return revng::any_of(StaticAttributes, Comparator) || revng::any_of(StaticAnnotations, Comparator); } }; inline constexpr AttributeRegistry Attributes; } // namespace ptml