diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -5580,6 +5580,32 @@ More information about specific metadata nodes recognized by the optimizers and code generator is found below. +Extended Metadata +----------------- + +Extended metadata is a container for :ref:`structured data ` +with an extended metadata class name. + +Like metadata nodes, extended metadata can either be uniqued or ``distinct``. +Distinct nodes have an identity separate from their contents. + +For example: + +.. code-block:: llvm + + !0 = !my.data { size: i32 12, writable: i1 true } + !1 = distinct !my.mutable.data { hash: i32 12345678 } + +Extended metadata can be an alternative to building metadata out of generic +tuples with the following advantages: + +* Often more easily readable for humans +* Structured data and therefore extended metadata can more easily be extended + by simply adding a field with a previously unused name +* Code using extended metadata typically operates on an explicit, + per-metadata-class in-memory representations that are more efficient than + generic metadata nodes and easily admit convenient accessor methods + .. _specialized-metadata: Specialized Metadata Nodes diff --git a/llvm/include/llvm-c/DebugInfo.h b/llvm/include/llvm-c/DebugInfo.h --- a/llvm/include/llvm-c/DebugInfo.h +++ b/llvm/include/llvm-c/DebugInfo.h @@ -180,6 +180,7 @@ LLVMDIGenericSubrangeMetadataKind, LLVMDIArgListMetadataKind, LLVMDIAssignIDMetadataKind, + LLVMExtMetadataMetadataKind, }; typedef unsigned LLVMMetadataKind; diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h --- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -371,6 +371,7 @@ METADATA_GENERIC_SUBRANGE = 45, // [distinct, count, lo, up, stride] METADATA_ARG_LIST = 46, // [n x [type num, value num]] METADATA_ASSIGN_ID = 47, // [distinct, ...] + METADATA_EXT_METADATA = 48, // [distinct, classname, sdata] }; // The constants block (CONSTANTS_BLOCK_ID) describes emission for each diff --git a/llvm/include/llvm/IR/ExtMetadata.h b/llvm/include/llvm/IR/ExtMetadata.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/IR/ExtMetadata.h @@ -0,0 +1,191 @@ +//===- llvm/IR/ExtMetadata.h - Exten{ded,sible} metadata --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +/// @file +/// This file contains the declarations for base classes for extensible +// metadata. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_IR_EXTMETADATA_H +#define LLVM_IR_EXTMETADATA_H + +#include "llvm/IR/Metadata.h" +#include "llvm/IR/StructuredData.h" + +namespace llvm { + +class ExtMetadataClass; + +/// Base class for extended metadata that may be defined by users of LLVM. +class ExtMetadata : public MDNode { + friend class MDNode; + +public: + LLVMContext &getContext() const { return Context.getContext(); } + unsigned getClassId() const { return SubclassData16; } + + /// Get the extended metadata class name. + StringRef getClassName() const; + + /// Get the schema of the given index for this metadata's class. + ArrayRef getClassSchema(int i) const; + + /// Get the schema index to use for serializing this metadata. The actual + /// schema can be obtained via @ref getClassSchema. + /// Returns -1 if no schema is known. + int getSchema() const; + + /// Serialize the target type info into structured data. + /// + /// If UseSchema is true, fields are generated according to the schema + /// returned by @ref getSchema. + SmallVector> + serialize(bool UseSchema) const; + +protected: + ExtMetadata(LLVMContext &Context, unsigned ExtClassID, StorageType Storage, + ArrayRef Ops = {}) + : MDNode(Context, ExtMetadataKind, Storage, Ops), Context(Context) { + SubclassData16 = ExtClassID; + assert(checkClassId()); + } + +private: + ContextAndReplaceableUses Context; + + using Metadata::SubclassData16; // hide from derived classes + + bool checkClassId() const; + const ExtMetadataClass *getClass() const; + + TempMDNode cloneImpl() const { llvm_unreachable("not implemented"); } +}; + +/// Base class for deserialization of +class ExtMetadataDeserializer { + virtual void anchor(); + +public: + virtual ~ExtMetadataDeserializer() {} + + virtual Error parseField(StringRef K, sdata::Value V) = 0; + virtual Expected finish() = 0; +}; + +/// Description of a class of extended metadata. +/// +/// Extended metadata classes must be explicitly registered with the context(s) +/// in which they are used, before extended metadata is used for the first time. +/// +/// The lifetime of an ExtMetadataClass object must extend beyond the lifetime +/// of any context in which it is registered. +/// +/// TODO: Properly implement schemas +class ExtMetadataClass { + /// Create a deserializer for this metadata class. + using MakeDeserializerFn = std::unique_ptr( + LLVMContext &Ctx, bool IsDistinct); + + /// Given an extended metadata instance, check the type for validity and + /// return true if valid. + using VerifierFn = bool(const ExtMetadata *M, raw_ostream &Errs); + + /// Given an extended metadata instance, get the schema index to use for + /// serialization, or -1 if no schema is applicable. + using GetSchemaFn = int(const ExtMetadata *M); + + /// Serialize an extended metadata instance. + using SerializeFn = SmallVector>( + const ExtMetadata *M, bool UseSchema); + +private: + unsigned Id; + std::string Name; + MakeDeserializerFn *MakeDeserializer = nullptr; + SerializeFn *Serialize = nullptr; + GetSchemaFn *GetSchema = nullptr; + VerifierFn *Verifier = nullptr; + + ExtMetadataClass(const ExtMetadataClass &) = delete; + ExtMetadataClass &operator=(const ExtMetadataClass &) = delete; + ExtMetadataClass &operator=(ExtMetadataClass &&) = delete; + +public: + ExtMetadataClass(StringRef Name, MakeDeserializerFn *MakeDeserializer, + SerializeFn *Serialize); + ExtMetadataClass(ExtMetadataClass &&); + ~ExtMetadataClass(); + + ExtMetadataClass &setGetSchema(GetSchemaFn *Fn) { + GetSchema = Fn; + return *this; + } + ExtMetadataClass &setVerifier(VerifierFn *Fn) { + Verifier = Fn; + return *this; + } + + ExtMetadataClass &addSchema(ArrayRef Schema); + + unsigned getId() const { return Id; } + StringRef getName() const { return Name; } + + std::unique_ptr + makeDeserializer(LLVMContext &Ctx, bool IsDistinct) const { + return MakeDeserializer(Ctx, IsDistinct); + } + int getSchema(const ExtMetadata *M) const { + if (GetSchema) + return GetSchema(M); + return -1; + } + SmallVector> + serialize(const ExtMetadata *M, bool UseSchema) const { + return Serialize(M, UseSchema); + } + bool verify(const ExtMetadata *M, raw_ostream &Errs) const { + if (Verifier) + return Verifier(M, Errs); + return true; + } +}; + +/// Opaque holder for generic extended metadata +/// +/// This is used to preserve extended metadata whose class has not been +/// registered within the LLVMContext. +class GenericExtMetadata : public ExtMetadata { + class Deserializer; + + std::string ClassName; + SmallVector> Fields; + +public: + GenericExtMetadata( + LLVMContext &Ctx, StorageType Storage, StringRef ClassName, + SmallVector> InitFields); + + static bool classof(const ExtMetadata *M) { return M->getClassId() == 0; } + static bool classof(const Metadata *MD) { + if (const auto *ExtMD = dyn_cast(MD)) + return classof(ExtMD); + return false; + } + + static std::unique_ptr + makeDeserializer(LLVMContext &Ctx, StringRef ClassName, bool IsDistinct); + + StringRef getClassName() const { return ClassName; }; + + SmallVector> serialize() const; +}; + +} // namespace llvm + +#endif // LLVM_IR_EXTMETADATA_H diff --git a/llvm/include/llvm/IR/LLVMContext.h b/llvm/include/llvm/IR/LLVMContext.h --- a/llvm/include/llvm/IR/LLVMContext.h +++ b/llvm/include/llvm/IR/LLVMContext.h @@ -26,6 +26,7 @@ class DiagnosticInfo; enum DiagnosticSeverity : char; +class ExtMetadataClass; class Function; class Instruction; class LLVMContextImpl; @@ -327,6 +328,12 @@ /// Find an extension type class. const TargetExtTypeClass *findTargetExtTypeClass(StringRef Name) const; + /// Register an extended metadata class. + void registerExtMetadataClass(const ExtMetadataClass *Class); + + /// Find an extended metadata class. + const ExtMetadataClass *findExtMetadataClass(StringRef Name) const; + private: // Module needs access to the add/removeModule methods. friend class Module; diff --git a/llvm/include/llvm/IR/Metadata.def b/llvm/include/llvm/IR/Metadata.def --- a/llvm/include/llvm/IR/Metadata.def +++ b/llvm/include/llvm/IR/Metadata.def @@ -118,6 +118,7 @@ HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIArgList) HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIStringType) HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIGenericSubrange) +HANDLE_MDNODE_LEAF(ExtMetadata) #undef HANDLE_METADATA #undef HANDLE_METADATA_LEAF diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -28,6 +28,7 @@ #include "llvm/IR/Constants.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/ExtMetadata.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalIFunc.h" #include "llvm/IR/GlobalObject.h" @@ -4919,7 +4920,29 @@ return parse##CLASS(N, IsDistinct); #include "llvm/IR/Metadata.def" - return tokError("expected metadata type"); + SMLoc MDLoc = Lex.getLoc(); + std::string ClassName = Lex.getStrVal(); + Lex.Lex(); // eat !classname + + std::unique_ptr D; + if (const auto *C = Context.findExtMetadataClass(ClassName)) + D = C->makeDeserializer(Context, IsDistinct); + else + D = GenericExtMetadata::makeDeserializer(Context, ClassName, IsDistinct); + + if (parseStructuredData( + [&](LocTy KeyLoc, StringRef K, LocTy ValueLoc, sdata::Value V) { + if (Error Err = D->parseField(K, V)) + return error(KeyLoc, toString(std::move(Err))); + return false; + })) + return true; + + auto Result = D->finish(); + if (Error Err = Result.takeError()) + return error(MDLoc, toString(std::move(Err))); + N = Result.get(); + return false; } #define DECLARE_FIELD(NAME, TYPE, INIT) TYPE NAME INIT @@ -5792,6 +5815,7 @@ /// ::= !{...} /// ::= !"string" /// ::= !DILocation(...) +/// ::= ! { } bool LLParser::parseMetadata(Metadata *&MD, PerFunctionState *PFS) { if (Lex.getKind() == lltok::MetadataVar) { MDNode *N; diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -4595,8 +4595,14 @@ MDCallbacks.GetContainedTypeID = [&](unsigned I, unsigned J) { return getContainedTypeID(I, J); }; + MDCallbacks.DecodeStructuredData = + [&](ArrayRef &Tail, + function_ref ParseField) { + return decodeStructuredData(Tail, ParseField); + }; MDCallbacks.MDType = Callbacks.MDType; - MDLoader = MetadataLoader(Stream, *M, ValueList, IsImporting, MDCallbacks); + MDLoader = + MetadataLoader(Stream, *M, ValueList, IsImporting, MDCallbacks, Strtab); return parseModule(0, ShouldLazyLoadMetadata, Callbacks); } diff --git a/llvm/lib/Bitcode/Reader/MetadataLoader.h b/llvm/lib/Bitcode/Reader/MetadataLoader.h --- a/llvm/lib/Bitcode/Reader/MetadataLoader.h +++ b/llvm/lib/Bitcode/Reader/MetadataLoader.h @@ -28,6 +28,10 @@ class Module; class Type; template class ArrayRef; +namespace sdata { +class Symbol; +class Value; +} // namespace sdata typedef std::function GetTypeByIDTy; @@ -37,9 +41,14 @@ GetContainedTypeIDTy)> MDTypeCallbackTy; +typedef std::function &, + function_ref)> + DecodeStructuredDataTy; + struct MetadataLoaderCallbacks { GetTypeByIDTy GetTypeByID; GetContainedTypeIDTy GetContainedTypeID; + DecodeStructuredDataTy DecodeStructuredData; std::optional MDType; }; @@ -53,7 +62,7 @@ ~MetadataLoader(); MetadataLoader(BitstreamCursor &Stream, Module &TheModule, BitcodeReaderValueList &ValueList, bool IsImporting, - MetadataLoaderCallbacks Callbacks); + MetadataLoaderCallbacks Callbacks, StringRef Strtab); MetadataLoader &operator=(MetadataLoader &&); MetadataLoader(MetadataLoader &&); diff --git a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp --- a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp +++ b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp @@ -31,6 +31,7 @@ #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DebugInfoMetadata.h" +#include "llvm/IR/ExtMetadata.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalObject.h" #include "llvm/IR/GlobalVariable.h" @@ -471,6 +472,8 @@ /// True if metadata is being parsed for a module being ThinLTO imported. bool IsImporting = false; + StringRef Strtab; + Error parseOneMetadata(SmallVectorImpl &Record, unsigned Code, PlaceholderQueue &Placeholders, StringRef Blob, unsigned &NextMetadataNo); @@ -741,11 +744,12 @@ public: MetadataLoaderImpl(BitstreamCursor &Stream, Module &TheModule, BitcodeReaderValueList &ValueList, - MetadataLoaderCallbacks Callbacks, bool IsImporting) + MetadataLoaderCallbacks Callbacks, bool IsImporting, + StringRef Strtab) : MetadataList(TheModule.getContext(), Stream.SizeInBytes()), ValueList(ValueList), Stream(Stream), Context(TheModule.getContext()), TheModule(TheModule), Callbacks(std::move(Callbacks)), - IsImporting(IsImporting) {} + IsImporting(IsImporting), Strtab(Strtab) {} Error parseMetadata(bool ModuleLevel); @@ -2265,6 +2269,40 @@ NextMetadataNo++; break; } + case bitc::METADATA_EXT_METADATA: { + if (Record.size() < 4) + return error("Incomplete ExtMetadata record"); + + IsDistinct = Record[0]; + if (!Record[2] || Record[2] > Strtab.size() || + Record[1] > Strtab.size() - Record[2]) + return error("ExtMetadata has bad classname"); + + StringRef ClassName = Strtab.slice(Record[1], Record[1] + Record[2]); + std::unique_ptr D; + if (const auto *Class = Context.findExtMetadataClass(ClassName)) + D = Class->makeDeserializer(Context, IsDistinct); + else + D = GenericExtMetadata::makeDeserializer(Context, ClassName, IsDistinct); + + ArrayRef Tail = ArrayRef(Record).slice(3); + if (Error Err = Callbacks.DecodeStructuredData( + Tail, [&](StringRef K, sdata::Value V) { + return D->parseField(K, V); + })) + return Err; + + if (!Tail.empty()) + return error("Unexpected tail in ExtMetadata record"); + + auto Result = D->finish(); + if (Error Err = Result.takeError()) + return Err; + + MetadataList.assignValue(Result.get(), NextMetadataNo); + NextMetadataNo++; + break; + } } return Error::success(); #undef GET_OR_DISTINCT @@ -2480,9 +2518,11 @@ MetadataLoader::MetadataLoader(BitstreamCursor &Stream, Module &TheModule, BitcodeReaderValueList &ValueList, bool IsImporting, - MetadataLoaderCallbacks Callbacks) - : Pimpl(std::make_unique( - Stream, TheModule, ValueList, std::move(Callbacks), IsImporting)) {} + MetadataLoaderCallbacks Callbacks, + StringRef Strtab) + : Pimpl(std::make_unique(Stream, TheModule, ValueList, + std::move(Callbacks), + IsImporting, Strtab)) {} Error MetadataLoader::parseMetadata(bool ModuleLevel) { return Pimpl->parseMetadata(ModuleLevel); diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -37,6 +37,7 @@ #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DebugLoc.h" #include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/ExtMetadata.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalAlias.h" #include "llvm/IR/GlobalIFunc.h" @@ -372,6 +373,8 @@ void writeDIImportedEntity(const DIImportedEntity *N, SmallVectorImpl &Record, unsigned Abbrev); + void writeExtMetadata(const ExtMetadata *N, SmallVectorImpl &Record, + unsigned Abbrev); unsigned createNamedMetadataAbbrev(); void writeNamedMetadata(SmallVectorImpl &Record); unsigned createMetadataStringsAbbrev(); @@ -2167,6 +2170,22 @@ Record.clear(); } +void ModuleBitcodeWriter::writeExtMetadata(const ExtMetadata *N, + SmallVectorImpl &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + + StringRef ClassName = N->getClassName(); + Record.push_back(StrtabBuilder.add(ClassName)); + Record.push_back(ClassName.size()); + + auto Fields = N->serialize(false); + encodeStructuredData(Record, Fields); + + Stream.EmitRecord(bitc::METADATA_EXT_METADATA, Record, /*Abbrev=*/0); + Record.clear(); +} + unsigned ModuleBitcodeWriter::createNamedMetadataAbbrev() { auto Abbv = std::make_shared(); Abbv->Add(BitCodeAbbrevOp(bitc::METADATA_NAME)); diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -40,6 +40,7 @@ #include "llvm/IR/Constants.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/ExtMetadata.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalAlias.h" #include "llvm/IR/GlobalIFunc.h" @@ -1676,6 +1677,13 @@ Out << "}"; } +static void writeExtMetadata(raw_ostream &Out, const ExtMetadata *Node, + AsmWriterContext &WriterCtx) { + Out << '!' << Node->getClassName(); + auto Fields = Node->serialize(false); + printStructuredData(Out, Fields, WriterCtx); +} + namespace { struct FieldSeparator { diff --git a/llvm/lib/IR/CMakeLists.txt b/llvm/lib/IR/CMakeLists.txt --- a/llvm/lib/IR/CMakeLists.txt +++ b/llvm/lib/IR/CMakeLists.txt @@ -21,6 +21,7 @@ DiagnosticPrinter.cpp Dominators.cpp EHPersonalities.cpp + ExtMetadata.cpp FPEnv.cpp Function.cpp GCStrategy.cpp diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp --- a/llvm/lib/IR/ConstantRange.cpp +++ b/llvm/lib/IR/ConstantRange.cpp @@ -20,9 +20,9 @@ // //===----------------------------------------------------------------------===// +#include "llvm/IR/ConstantRange.h" #include "llvm/ADT/APInt.h" #include "llvm/Config/llvm-config.h" -#include "llvm/IR/ConstantRange.h" #include "llvm/IR/Constants.h" #include "llvm/IR/InstrTypes.h" #include "llvm/IR/Instruction.h" diff --git a/llvm/lib/IR/ExtMetadata.cpp b/llvm/lib/IR/ExtMetadata.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/IR/ExtMetadata.cpp @@ -0,0 +1,164 @@ +//===- ExtMetadata.cpp - Implement debug info metadata --------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the extensible Metadata classes. +// +//===----------------------------------------------------------------------===// + +#include "llvm/IR/ExtMetadata.h" + +#include "LLVMContextImpl.h" +#include "llvm/ADT/BitVector.h" + +#include + +using namespace llvm; + +namespace { + +// This registry only manages the global ID allocation. Class lookup is done +// via (single-threaded!) structures in LLVMContext. +struct ExtMetadataClassRegistry { + std::mutex Mutex; + BitVector Ids; + + static ExtMetadataClassRegistry &get() { + static ExtMetadataClassRegistry R; + return R; + } +}; + +} // anonymous namespace + +void ExtMetadataDeserializer::anchor() {} + +ExtMetadataClass::ExtMetadataClass(StringRef Name, + MakeDeserializerFn *MakeDeserializer, + SerializeFn *Serialize) + : Name(Name), MakeDeserializer(MakeDeserializer), Serialize(Serialize) { + assert(!Name.empty()); + + auto &R = ExtMetadataClassRegistry::get(); + auto Lock = std::scoped_lock(R.Mutex); + int i = R.Ids.find_first_unset(); + if (i != -1) { + R.Ids[i] = true; + } else { + i = R.Ids.size(); + if (i >= 65535) + report_fatal_error("too many extended metadata classes"); + R.Ids.push_back(true); + } + Id = i + 1; // 0 is reserved for GenericExtMetadata +} + +ExtMetadataClass::ExtMetadataClass(ExtMetadataClass &&RHS) { + Id = RHS.Id; + Name = RHS.Name; + MakeDeserializer = RHS.MakeDeserializer; + Serialize = RHS.Serialize; + GetSchema = RHS.GetSchema; + Verifier = RHS.Verifier; + + RHS.Id = 0; +} + +ExtMetadataClass::~ExtMetadataClass() { + if (Id != 0) { + auto &R = ExtMetadataClassRegistry::get(); + auto Lock = std::scoped_lock(R.Mutex); + R.Ids[Id - 1] = false; + } +} + +bool ExtMetadata::checkClassId() const { + if (!getClassId()) + return true; + + LLVMContext &C = getContext(); + C.pImpl->ExtMetadataClassesFrozen = true; + return getClassId() <= C.pImpl->ExtMetadataClassesById.size() && + C.pImpl->ExtMetadataClassesById[getClassId() - 1]; +} + +const ExtMetadataClass *ExtMetadata::getClass() const { + if (!getClassId()) + return nullptr; + + LLVMContext &C = getContext(); + return C.pImpl->ExtMetadataClassesById[getClassId() - 1]; +} + +StringRef ExtMetadata::getClassName() const { + if (!getClassId()) + return cast(this)->getClassName(); + return getClass()->getName(); +} + +ArrayRef ExtMetadata::getClassSchema(int i) const { + assert(getClassId()); + llvm_unreachable("not implemented"); +} + +int ExtMetadata::getSchema() const { + if (!getClassId()) + return -1; + return getClass()->getSchema(this); +} + +SmallVector> +ExtMetadata::serialize(bool UseSchema) const { + if (!getClassId()) + return cast(this)->serialize(); + return getClass()->serialize(this, UseSchema); +} + +GenericExtMetadata::GenericExtMetadata( + LLVMContext &Ctx, StorageType Storage, StringRef ClassName, + SmallVector> InitFields) + : ExtMetadata(Ctx, 0, Storage), ClassName(ClassName), + Fields(std::move(InitFields)) { + assert(!ClassName.empty()); + assert(!Ctx.findExtMetadataClass(ClassName)); +} + +class GenericExtMetadata::Deserializer : public ExtMetadataDeserializer { + LLVMContext &Ctx; + std::string ClassName; + bool IsDistinct; + SmallVector> Fields; + +public: + Deserializer(LLVMContext &Ctx, StringRef ClassName, bool IsDistinct) + : Ctx(Ctx), ClassName(ClassName), IsDistinct(IsDistinct) {} + + Error parseField(StringRef K, sdata::Value V) override { + Fields.emplace_back(K.str(), V); + return Error::success(); + } + + Expected finish() override { + // TODO: storage / uniquing / IsDistinct + return new (0, Distinct) + GenericExtMetadata(Ctx, Distinct, ClassName, std::move(Fields)); + } +}; + +std::unique_ptr +GenericExtMetadata::makeDeserializer(LLVMContext &Ctx, StringRef ClassName, + bool IsDistinct) { + return std::make_unique(Ctx, ClassName, IsDistinct); +} + +SmallVector> +GenericExtMetadata::serialize() const { + SmallVector> F; + for (const auto &[K, V] : Fields) + F.emplace_back(K, V); + return F; +} diff --git a/llvm/lib/IR/LLVMContext.cpp b/llvm/lib/IR/LLVMContext.cpp --- a/llvm/lib/IR/LLVMContext.cpp +++ b/llvm/lib/IR/LLVMContext.cpp @@ -19,6 +19,7 @@ #include "llvm/ADT/Twine.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/DiagnosticPrinter.h" +#include "llvm/IR/ExtMetadata.h" #include "llvm/IR/LLVMRemarkStreamer.h" #include "llvm/IR/TargetExtType.h" #include "llvm/Remarks/RemarkStreamer.h" @@ -424,3 +425,19 @@ return nullptr; } + +void LLVMContext::registerExtMetadataClass(const ExtMetadataClass *Class) { + assert(!pImpl->ExtMetadataClassesFrozen); + assert(!pImpl->ExtMetadataClassesByName.count(Class->getName())); + + pImpl->ExtMetadataClassesByName.try_emplace(Class->getName(), Class); + if (Class->getId() >= pImpl->ExtMetadataClassesById.size()) + pImpl->ExtMetadataClassesById.resize(Class->getId()); + pImpl->ExtMetadataClassesById[Class->getId() - 1] = Class; +} + +const ExtMetadataClass * +LLVMContext::findExtMetadataClass(StringRef Name) const { + pImpl->ExtMetadataClassesFrozen = true; + return pImpl->ExtMetadataClassesByName.lookup(Name); +} diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h --- a/llvm/lib/IR/LLVMContextImpl.h +++ b/llvm/lib/IR/LLVMContextImpl.h @@ -58,6 +58,7 @@ class BasicBlock; struct DiagnosticHandler; class ElementCount; +class ExtMetadataClass; class Function; class GlobalObject; class GlobalValue; @@ -1614,6 +1615,10 @@ SmallVector TargetExtTypeClasses; bool TargetExtTypeClassesFrozen = false; + SmallVector ExtMetadataClassesById; + StringMap ExtMetadataClassesByName; + bool ExtMetadataClassesFrozen = false; + /// Flag to indicate if Value (other than GlobalValue) retains their name or /// not. bool DiscardValueNames = false; diff --git a/llvm/lib/IR/Metadata.cpp b/llvm/lib/IR/Metadata.cpp --- a/llvm/lib/IR/Metadata.cpp +++ b/llvm/lib/IR/Metadata.cpp @@ -32,6 +32,7 @@ #include "llvm/IR/Constants.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DebugLoc.h" +#include "llvm/IR/ExtMetadata.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalObject.h" #include "llvm/IR/GlobalVariable.h" diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -971,6 +971,9 @@ llvm_unreachable("Invalid MDNode subclass"); case Metadata::MDTupleKind: break; + case Metadata::ExtMetadataKind: + // TODO: Hook up the verifier + break; #define HANDLE_SPECIALIZED_MDNODE_LEAF(CLASS) \ case Metadata::CLASS##Kind: \ visit##CLASS(cast(MD)); \ diff --git a/llvm/test/Assembler/extended-metadata.ll b/llvm/test/Assembler/extended-metadata.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Assembler/extended-metadata.ll @@ -0,0 +1,22 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2 +; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s + +define i32 @test1(ptr %p) !my.md !my.md { foo: i8 3 } { + %r = load i32, ptr %p, align 4, !my.md !0 + ret i32 %r +} + +!0 = !{ i32 5, !my.other{ bar: i16 22 } } + +; CHECK: define i32 @test1(ptr %p) !my.md !0 +; CHECK: %r = load i32, ptr %p, align 4, !my.md !1 +; +; TODO: the 'distinct's shouldn't be there +; +; CHECK: !0 = distinct !my.md{ +; CHECK-NEXT: foo: i8 3, +; CHECK-NEXT: } +; CHECK-NEXT: !1 = !{i32 5, !2} +; CHECK-NEXT: !2 = distinct !my.other{ +; CHECK-NEXT: bar: i16 22, +; CHECK-NEXT: }