diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index bc9cfb557c540..dfbba476dbc45 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -319,7 +319,7 @@ added in the future: not be used lightly but only for specific situations such as an alternative to the *register pinning* performance technique often used when implementing functional programming languages. At the - moment only X86, AArch64, and RISCV support this convention. The + moment only X86, AArch64, and RISCV support this convention. The following limitations exist: - On *X86-32* only up to 4 bit type parameters are supported. No @@ -643,10 +643,10 @@ implementation defined, the optimizer can't do the latter. The former is challenging as many commonly expected properties, such as ``ptrtoint(v)-ptrtoint(v) == 0``, don't hold for non-integral types. Similar restrictions apply to intrinsics that might examine the pointer bits, -such as :ref:`llvm.ptrmask`. +such as :ref:`llvm.ptrmask`. The alignment information provided by the frontend for a non-integral pointer -(typically using attributes or metadata) must be valid for every possible +(typically using attributes or metadata) must be valid for every possible representation of the pointer. .. _globalvars: @@ -824,7 +824,8 @@ an optional :ref:`calling convention `, an optional ``unnamed_addr`` attribute, a return type, an optional :ref:`parameter attribute ` for the return type, a function name, a (possibly empty) argument list (each with optional :ref:`parameter -attributes `), optional :ref:`function attributes `, +attributes ` and an optional list of attached :ref:`metadata `), +optional :ref:`function attributes `, an optional address space, an optional section, an optional partition, an optional alignment, an optional :ref:`comdat `, an optional :ref:`garbage collector name `, an optional :ref:`prefix `, @@ -848,7 +849,7 @@ argument is of the following form: Syntax:: - [parameter Attrs] [name] + [parameter Attrs] (!name !N)* [name] LLVM function declarations consist of the "``declare``" keyword, an optional :ref:`linkage type `, an optional :ref:`visibility style diff --git a/llvm/include/llvm/AsmParser/LLParser.h b/llvm/include/llvm/AsmParser/LLParser.h index cf358c384f520..15c8a4cf354b6 100644 --- a/llvm/include/llvm/AsmParser/LLParser.h +++ b/llvm/include/llvm/AsmParser/LLParser.h @@ -285,6 +285,8 @@ namespace llvm { }; bool parseEnumAttribute(Attribute::AttrKind Attr, AttrBuilder &B, bool InAttrGroup); + bool parseOptionalParamMetadata( + SmallVectorImpl> &MDs); bool parseOptionalParamOrReturnAttrs(AttrBuilder &B, bool IsParam); bool parseOptionalParamAttrs(AttrBuilder &B) { return parseOptionalParamOrReturnAttrs(B, true); @@ -607,8 +609,10 @@ namespace llvm { Type *Ty; AttributeSet Attrs; std::string Name; - ArgInfo(LocTy L, Type *ty, AttributeSet Attr, const std::string &N) - : Loc(L), Ty(ty), Attrs(Attr), Name(N) {} + SmallVector, 8> MDs; + ArgInfo(LocTy L, Type *ty, AttributeSet Attr, const std::string &N, + const SmallVector, 8> &mds) + : Loc(L), Ty(ty), Attrs(Attr), Name(N), MDs(mds) {} }; bool parseArgumentList(SmallVectorImpl &ArgList, SmallVectorImpl &UnnamedArgNums, diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h index c6f0ddf29a6da..c3c968d4d0cb4 100644 --- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -369,6 +369,7 @@ enum MetadataCodes { 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_PARAM_ATTACHMENT = 48, // [ [valueid ,] [valueid, [n x [id, mdnode]]] }; // The constants block (CONSTANTS_BLOCK_ID) describes emission for each diff --git a/llvm/include/llvm/IR/Argument.h b/llvm/include/llvm/IR/Argument.h index f0c0ce75d2b7e..02209eba2d8be 100644 --- a/llvm/include/llvm/IR/Argument.h +++ b/llvm/include/llvm/IR/Argument.h @@ -177,6 +177,14 @@ class Argument final : public Value { static bool classof(const Value *V) { return V->getValueID() == ArgumentVal; } + + using Value::addMetadata; + using Value::clearMetadata; + using Value::eraseMetadata; + using Value::getAllMetadata; + using Value::getMetadata; + using Value::hasMetadata; + using Value::setMetadata; }; } // End llvm namespace diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp index d6c5993797de1..728df9c6da35a 100644 --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -1929,6 +1929,19 @@ bool LLParser::parseOptionalParamOrReturnAttrs(AttrBuilder &B, bool IsParam) { } } +/// Parse a potentially empty list of parameter or return attributes. +bool LLParser::parseOptionalParamMetadata( + SmallVectorImpl> &MDs) { + while (Lex.getKind() == lltok::MetadataVar) { + unsigned MDK; + MDNode *N; + if (parseMetadataAttachment(MDK, N)) + return true; + MDs.emplace_back(MDK, N); + } + return false; +} + static unsigned parseOptionalLinkageAux(lltok::Kind Kind, bool &HasLinkage) { HasLinkage = true; switch (Kind) { @@ -3058,7 +3071,9 @@ bool LLParser::parseArgumentList(SmallVectorImpl &ArgList, LocTy TypeLoc = Lex.getLoc(); Type *ArgTy = nullptr; AttrBuilder Attrs(M->getContext()); - if (parseType(ArgTy) || parseOptionalParamAttrs(Attrs)) + SmallVector, 8> MDs; + if (parseType(ArgTy) || parseOptionalParamAttrs(Attrs) || + parseOptionalParamMetadata(MDs)) return true; if (ArgTy->isVoidTy()) @@ -3087,7 +3102,7 @@ bool LLParser::parseArgumentList(SmallVectorImpl &ArgList, ArgList.emplace_back(TypeLoc, ArgTy, AttributeSet::get(ArgTy->getContext(), Attrs), - std::move(Name)); + std::move(Name), std::move(MDs)); } while (EatIfPresent(lltok::comma)); } @@ -3115,6 +3130,8 @@ bool LLParser::parseFunctionType(Type *&Result) { if (ArgList[i].Attrs.hasAttributes()) return error(ArgList[i].Loc, "argument attributes invalid in function type"); + if (!ArgList[i].MDs.empty()) + return error(ArgList[i].Loc, "metadata invalid in function type"); } SmallVector ArgListTy; @@ -6223,6 +6240,8 @@ bool LLParser::parseFunctionHeader(Function *&Fn, bool IsDefine, // Add all of the arguments we parsed to the function. Function::arg_iterator ArgIt = Fn->arg_begin(); for (unsigned i = 0, e = ArgList.size(); i != e; ++i, ++ArgIt) { + for (const auto &MD : ArgList[i].MDs) + ArgIt->addMetadata(MD.first, *MD.second); // If the argument has a name, insert it into the argument symbol table. if (ArgList[i].Name.empty()) continue; diff --git a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp index 770eb83af17f9..dbd741961dd3a 100644 --- a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp +++ b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp @@ -26,6 +26,7 @@ #include "llvm/Bitcode/BitcodeReader.h" #include "llvm/Bitcode/LLVMBitCodes.h" #include "llvm/Bitstream/BitstreamReader.h" +#include "llvm/IR/Argument.h" #include "llvm/IR/AutoUpgrade.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Constants.h" @@ -60,9 +61,6 @@ #include #include #include -namespace llvm { -class Argument; -} using namespace llvm; @@ -477,6 +475,7 @@ class MetadataLoader::MetadataLoaderImpl { function_ref CallBack); Error parseGlobalObjectAttachment(GlobalObject &GO, ArrayRef Record); + Error parseParamAttachment(Function &F, ArrayRef Record); Error parseMetadataKindRecord(SmallVectorImpl &Record); void resolveForwardRefsAndPlaceholders(PlaceholderQueue &Placeholders); @@ -2263,6 +2262,19 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata( NextMetadataNo++; break; } + case bitc::METADATA_PARAM_ATTACHMENT: { + unsigned RecordLength = Record.size(); + if (Record.empty() || (RecordLength - 2) % 2 == 1) + return error("Invalid record"); + unsigned ValueID = Record[0]; + if (ValueID >= ValueList.size()) + return error("Invalid record"); + if (auto *F = dyn_cast(ValueList[ValueID])) + if (Error Err = + parseParamAttachment(*F, ArrayRef(Record).slice(1))) + return Err; + break; + } } return Error::success(); #undef GET_OR_DISTINCT @@ -2321,6 +2333,24 @@ Error MetadataLoader::MetadataLoaderImpl::parseGlobalObjectAttachment( return Error::success(); } +Error MetadataLoader::MetadataLoaderImpl::parseParamAttachment( + Function &F, ArrayRef Record) { + assert((Record.size() - 1) % 2 == 0); + + auto *A = F.getArg(Record[0]); + for (unsigned I = 1, E = Record.size(); I != E; I += 2) { + auto K = MDKindMap.find(Record[I]); + if (K == MDKindMap.end()) + return error("Invalid ID"); + MDNode *MD = + dyn_cast_or_null(getMetadataFwdRefOrLoad(Record[I + 1])); + if (!MD) + return error("Invalid metadata attachment: expect fwd ref to MDNode"); + A->addMetadata(K->second, *MD); + } + return Error::success(); +} + /// Parse metadata attachments. Error MetadataLoader::MetadataLoaderImpl::parseMetadataAttachment( Function &F, ArrayRef InstructionList) { @@ -2406,6 +2436,14 @@ Error MetadataLoader::MetadataLoaderImpl::parseMetadataAttachment( } break; } + case bitc::METADATA_PARAM_ATTACHMENT: { + unsigned RecordLength = Record.size(); + if (Record.empty() || (RecordLength - 1) % 2 == 1) + return error("Invalid record"); + if (Error Err = parseParamAttachment(F, Record)) + return Err; + break; + } } } } diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp index a5fc267b1883b..9a9c4b413268e 100644 --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -29,6 +29,7 @@ #include "llvm/Bitstream/BitCodes.h" #include "llvm/Bitstream/BitstreamWriter.h" #include "llvm/Config/llvm-config.h" +#include "llvm/IR/Argument.h" #include "llvm/IR/Attributes.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Comdat.h" @@ -378,6 +379,8 @@ class ModuleBitcodeWriter : public ModuleBitcodeWriterBase { void writeFunctionMetadataAttachment(const Function &F); void pushGlobalMetadataAttachment(SmallVectorImpl &Record, const GlobalObject &GO); + void pushParamMetadataAttachment(SmallVectorImpl &Record, + const Argument &A); void writeModuleMetadataKinds(); void writeOperandBundleTags(); void writeSyncScopeNames(); @@ -2393,8 +2396,17 @@ void ModuleBitcodeWriter::writeModuleMetadata() { Stream.EmitRecord(bitc::METADATA_GLOBAL_DECL_ATTACHMENT, Record); }; for (const Function &F : M) - if (F.isDeclaration() && F.hasMetadata()) - AddDeclAttachedMetadata(F); + if (F.isDeclaration()) { + if (F.hasMetadata()) + AddDeclAttachedMetadata(F); + for (const auto &A : F.args()) + if (A.hasMetadata()) { + Record.push_back(VE.getValueID(&F)); + pushParamMetadataAttachment(Record, A); + Stream.EmitRecord(bitc::METADATA_PARAM_ATTACHMENT, Record); + Record.clear(); + } + } // FIXME: Only store metadata for declarations here, and move data for global // variable definitions to a separate block (PR28134). for (const GlobalVariable &GV : M.globals()) @@ -2426,11 +2438,30 @@ void ModuleBitcodeWriter::pushGlobalMetadataAttachment( } } +void ModuleBitcodeWriter::pushParamMetadataAttachment( + SmallVectorImpl &Record, const Argument &A) { + Record.push_back(A.getArgNo()); + // [n x [id, mdnode]] + SmallVector, 4> MDs; + A.getAllMetadata(MDs); + for (const auto &I : MDs) { + Record.push_back(I.first); + Record.push_back(VE.getMetadataID(I.second)); + } +} + void ModuleBitcodeWriter::writeFunctionMetadataAttachment(const Function &F) { Stream.EnterSubblock(bitc::METADATA_ATTACHMENT_ID, 3); SmallVector Record; + for (const auto &A : F.args()) + if (A.hasMetadata()) { + pushParamMetadataAttachment(Record, A); + Stream.EmitRecord(bitc::METADATA_PARAM_ATTACHMENT, Record); + Record.clear(); + } + if (F.hasMetadata()) { pushGlobalMetadataAttachment(Record, F); Stream.EmitRecord(bitc::METADATA_ATTACHMENT, Record, 0); @@ -3476,6 +3507,9 @@ void ModuleBitcodeWriter::writeFunction( bool NeedsMetadataAttachment = F.hasMetadata(); + for (auto IA = F.arg_begin(), E = F.arg_end(); IA != E; ++IA) + NeedsMetadataAttachment |= IA->hasMetadata(); + DILocation *LastDL = nullptr; SmallSetVector BlockAddressUsers; diff --git a/llvm/lib/Bitcode/Writer/ValueEnumerator.cpp b/llvm/lib/Bitcode/Writer/ValueEnumerator.cpp index fccb2a606f7ed..3f3b2fa23688e 100644 --- a/llvm/lib/Bitcode/Writer/ValueEnumerator.cpp +++ b/llvm/lib/Bitcode/Writer/ValueEnumerator.cpp @@ -398,8 +398,13 @@ ValueEnumerator::ValueEnumerator(const Module &M, // Enumerate types used by function bodies and argument lists. for (const Function &F : M) { - for (const Argument &A : F.args()) + for (const Argument &A : F.args()) { EnumerateType(A.getType()); + MDs.clear(); + A.getAllMetadata(MDs); + for (const auto &I : MDs) + EnumerateMetadata(F.isDeclaration() ? nullptr : &F, I.second); + } // Enumerate metadata attached to this function. MDs.clear(); diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp index 3c15784a0ed5e..b4d7ff5b887b5 100644 --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -857,6 +857,9 @@ class SlotTracker : public AbstractSlotTrackerStorage { /// Add all of the metadata from a function. void processFunctionMetadata(const Function &F); + /// Add all of the metadata from a argument. + void processParamMetadata(const Argument &A); + /// Add all of the metadata from an instruction. void processInstructionMetadata(const Instruction &I); @@ -1128,6 +1131,9 @@ void SlotTracker::processGlobalObjectMetadata(const GlobalObject &GO) { void SlotTracker::processFunctionMetadata(const Function &F) { processGlobalObjectMetadata(F); + for (const auto &A : F.args()) { + processParamMetadata(A); + } for (auto &BB : F) { for (auto &I : BB) { for (const DPValue &DPV : I.getDbgValueRange()) @@ -1162,6 +1168,14 @@ void SlotTracker::processInstructionMetadata(const Instruction &I) { CreateMetadataSlot(MD.second); } +void SlotTracker::processParamMetadata(const Argument &A) { + // Process metadata attached to this instruction. + SmallVector, 4> MDs; + A.getAllMetadata(MDs); + for (auto &MD : MDs) + CreateMetadataSlot(MD.second); +} + /// Clean up after incorporating a function. This is the only way to get out of /// the function incorporation state that affects get*Slot/Create*Slot. Function /// incorporation state is indicated by TheFunction != 0. @@ -3918,6 +3932,12 @@ void AssemblyWriter::printFunction(const Function *F) { Out << ' '; writeAttributeSet(ArgAttrs); } + auto *Arg = F->getArg(I); + if (Arg->hasMetadata()) { + SmallVector, 4> MDs; + Arg->getAllMetadata(MDs); + printMetadataAttachments(MDs, " "); + } } } else { // The arguments are meaningful here, print them in detail. @@ -4010,6 +4030,10 @@ void AssemblyWriter::printArgument(const Argument *Arg, AttributeSet Attrs) { writeAttributeSet(Attrs); } + SmallVector, 4> MDs; + Arg->getAllMetadata(MDs); + printMetadataAttachments(MDs, " "); + // Output name, if available... if (Arg->hasName()) { Out << ' '; diff --git a/llvm/lib/IR/Metadata.cpp b/llvm/lib/IR/Metadata.cpp index 37017a222d485..bd02ca69723c0 100644 --- a/llvm/lib/IR/Metadata.cpp +++ b/llvm/lib/IR/Metadata.cpp @@ -1477,7 +1477,8 @@ void Value::getAllMetadata( } void Value::setMetadata(unsigned KindID, MDNode *Node) { - assert(isa(this) || isa(this)); + assert(isa(this) || isa(this) || + isa(this)); // Handle the case when we're adding/updating metadata on a value. if (Node) { @@ -1511,7 +1512,8 @@ void Value::setMetadata(StringRef Kind, MDNode *Node) { } void Value::addMetadata(unsigned KindID, MDNode &MD) { - assert(isa(this) || isa(this)); + assert(isa(this) || isa(this) || + isa(this)); if (!HasMetadata) HasMetadata = true; getContext().pImpl->ValueMetadata[this].insert(KindID, MD); diff --git a/llvm/test/Assembler/metadata-decl.ll b/llvm/test/Assembler/metadata-decl.ll index 4f28638fd0f18..e7f249f114a69 100644 --- a/llvm/test/Assembler/metadata-decl.ll +++ b/llvm/test/Assembler/metadata-decl.ll @@ -1,11 +1,19 @@ ; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s ; RUN: llvm-as < %s | llvm-dis -materialize-metadata | FileCheck %s -; CHECK: @foo = external global i32, !foo !0 +; CHECK: @foo = external global i32, !foo [[M0:![0-9]+]] @foo = external global i32, !foo !0 -; CHECK: declare !bar !1 void @bar() +; CHECK: declare !bar [[M1:![0-9]+]] void @bar() declare !bar !1 void @bar() +; CHECK: declare void @test1(i32 noundef !foo [[M0]] !bar [[M1]], i32 !range [[M2:![0-9]+]]) +declare void @test1(i32 noundef !foo !0 !bar !1, i32 !range !2) + +; CHECK: [[M0]] = distinct !{} +; CHECK: [[M1]] = distinct !{} +; CHECK: [[M2]] = !{i32 1, i32 0} + !0 = distinct !{} !1 = distinct !{} +!2 = !{ i32 1, i32 0 } diff --git a/llvm/test/Assembler/metadata.ll b/llvm/test/Assembler/metadata.ll index 5b62bfafa6d7d..8efcf19091203 100644 --- a/llvm/test/Assembler/metadata.ll +++ b/llvm/test/Assembler/metadata.ll @@ -26,6 +26,11 @@ define void @test3() !bar !3 { unreachable, !bar !4 } +; CHECK: define void @test4(i32 noundef !foo [[M2]] !baz [[M5:![0-9]+]] %a, i32 !range [[M6:![0-9]+]] %b) +define void @test4(i32 noundef !foo !2 !baz !8 %a, i32 !range !9 %b) { + unreachable +} + ; CHECK-LABEL: define void @test_attachment_name() { ; CHECK: unreachable, !\342abc [[M4]] define void @test_attachment_name() { @@ -38,6 +43,8 @@ define void @test_attachment_name() { ; CHECK: [[M0]] = !DILocation ; CHECK: [[M1]] = distinct !DISubprogram ; CHECK: [[M4]] = distinct !{} +; CHECK: [[M5]] = distinct !{} +; CHECK: [[M6]] = !{i32 1, i32 0} !llvm.module.flags = !{!7} !llvm.dbg.cu = !{!5} @@ -52,6 +59,8 @@ define void @test_attachment_name() { splitDebugFilename: "abc.debug", emissionKind: 2) !6 = !DIFile(filename: "path/to/file", directory: "/path/to/dir") !7 = !{i32 2, !"Debug Info Version", i32 3} +!8 = distinct !{} +!9 = !{ i32 1, i32 0 } declare void @llvm.dbg.func.start(metadata) nounwind readnone