Index: include/llvm/IR/Constant.h =================================================================== --- include/llvm/IR/Constant.h +++ include/llvm/IR/Constant.h @@ -148,7 +148,7 @@ /// them. This method is useful for clients that want to check to see if a /// global is unused, but don't want to deal with potentially dead constants /// hanging off of the globals. - void removeDeadConstantUsers() const; + void removeDeadConstantUsers(bool SkipMetadataUses = true) const; Constant *stripPointerCasts() { return cast(Value::stripPointerCasts()); Index: include/llvm/IR/DebugInfoMetadata.h =================================================================== --- include/llvm/IR/DebugInfoMetadata.h +++ include/llvm/IR/DebugInfoMetadata.h @@ -139,6 +139,60 @@ iterator end() const { return N ? iterator(N->op_end()) : iterator(); } }; +/// A list of pairs (DIGlobalVariable, DIExpression). +/// +/// TODO: Implement optimized underlying storage instead of using an +/// MDTuple. +class DIGlobalVarExprList { + const MDTuple *N = nullptr; + friend class LLVMContextImpl; + friend class MDNode; + +public: + typedef std::pair DIGlobalVarExpr; + DIGlobalVarExprList(const MDTuple *N) + : N(N) { assert(!N || N->getNumOperands() % 2 == 0); } + ~DIGlobalVarExprList() = default; + + explicit operator bool() const { return get(); } + explicit operator MDTuple *() const { return get(); } + + MDTuple *get() const { return const_cast(N); } + MDTuple *operator->() const { return get(); } + MDTuple &operator*() const { return *get(); } + + DIGlobalVarExpr operator[](unsigned I) const { + return {cast(N->getOperand(2 * I)), + cast(N->getOperand(2 * I + 1))}; + } + + class iterator : std::iterator { + MDNode::op_iterator I = nullptr; + + public: + iterator() = default; + explicit iterator(MDNode::op_iterator I) : I(I) {} + DIGlobalVarExpr operator*() const { + return {cast(*I), cast(*std::next(I))}; + } + iterator &operator++() { + std::advance(I, 2); + return *this; + } + iterator operator++(int) { + iterator Temp(*this); + std::advance(I, 2); + return Temp; + } + bool operator==(const iterator &X) const { return I == X.I; } + bool operator!=(const iterator &X) const { return I != X.I; } + }; + + iterator begin() const { return N ? iterator(N->op_begin()) : iterator(); } + iterator end() const { return N ? iterator(N->op_end()) : iterator(); } +}; + /// \brief Tagged DWARF-like metadata node. /// /// A metadata node with a DWARF tag (i.e., a constant named \c DW_TAG_*, @@ -1836,6 +1890,7 @@ } }; + /// \brief Local variable. /// /// TODO: Split up flags. Index: include/llvm/IR/Function.h =================================================================== --- include/llvm/IR/Function.h +++ include/llvm/IR/Function.h @@ -72,13 +72,8 @@ /// Bits from GlobalObject::GlobalObjectSubclassData. enum { /// Whether this function is materializable. - IsMaterializableBit = 1 << 0, - HasMetadataHashEntryBit = 1 << 1 + IsMaterializableBit = 1 << 0 }; - void setGlobalObjectBit(unsigned Mask, bool Value) { - setGlobalObjectSubClassData((~Mask & getGlobalObjectSubClassData()) | - (Value ? Mask : 0u)); - } friend class SymbolTableListTraits; @@ -605,35 +600,6 @@ /// setjmp or other function that gcc recognizes as "returning twice". bool callsFunctionThatReturnsTwice() const; - /// \brief Check if this has any metadata. - bool hasMetadata() const { return hasMetadataHashEntry(); } - - /// \brief Get the current metadata attachment, if any. - /// - /// Returns \c nullptr if such an attachment is missing. - /// @{ - MDNode *getMetadata(unsigned KindID) const; - MDNode *getMetadata(StringRef Kind) const; - /// @} - - /// \brief Set a particular kind of metadata attachment. - /// - /// Sets the given attachment to \c MD, erasing it if \c MD is \c nullptr or - /// replacing it if it already exists. - /// @{ - void setMetadata(unsigned KindID, MDNode *MD); - void setMetadata(StringRef Kind, MDNode *MD); - /// @} - - /// \brief Get all current metadata attachments. - void - getAllMetadata(SmallVectorImpl> &MDs) const; - - /// \brief Drop metadata not in the given list. - /// - /// Drop all metadata from \c this not included in \c KnownIDs. - void dropUnknownMetadata(ArrayRef KnownIDs); - /// \brief Set the attached subprogram. /// /// Calls \a setMetadata() with \a LLVMContext::MD_dbg. @@ -655,15 +621,6 @@ Value::setValueSubclassData(D); } void setValueSubclassDataBit(unsigned Bit, bool On); - - bool hasMetadataHashEntry() const { - return getGlobalObjectSubClassData() & HasMetadataHashEntryBit; - } - void setHasMetadataHashEntry(bool HasEntry) { - setGlobalObjectBit(HasMetadataHashEntryBit, HasEntry); - } - - void clearMetadata(); }; template <> Index: include/llvm/IR/GlobalObject.h =================================================================== --- include/llvm/IR/GlobalObject.h +++ include/llvm/IR/GlobalObject.h @@ -21,6 +21,7 @@ namespace llvm { class Comdat; +class MDNode; class Module; class GlobalObject : public GlobalValue { @@ -39,11 +40,30 @@ Comdat *ObjComdat; static const unsigned AlignmentBits = 5; static const unsigned GlobalObjectSubClassDataBits = - GlobalValueSubClassDataBits - AlignmentBits; + GlobalValueSubClassDataBits - AlignmentBits - 1; + + /// Bits from GlobalObject::GlobalObjectSubclassData. + enum { + HasMetadataHashEntryBit = 1 << 1 + }; + + void setGlobalObjectBit(unsigned Mask, bool Value) { + setGlobalObjectSubClassData((~Mask & getGlobalObjectSubClassData()) | + (Value ? Mask : 0u)); + } + + void clearMetadata(); private: static const unsigned AlignmentMask = (1 << AlignmentBits) - 1; + bool hasMetadataHashEntry() const { + return getGlobalObjectSubClassData() & HasMetadataHashEntryBit; + } + void setHasMetadataHashEntry(bool HasEntry) { + setGlobalObjectBit(HasMetadataHashEntryBit, HasEntry); + } + public: unsigned getAlignment() const { unsigned Data = getGlobalValueSubClassData(); @@ -66,6 +86,36 @@ void copyAttributesFrom(const GlobalValue *Src) override; + + /// Check if this has any metadata. + bool hasMetadata() const { return hasMetadataHashEntry(); } + + /// Get the current metadata attachment, if any. + /// + /// Returns \c nullptr if such an attachment is missing. + /// @{ + MDNode *getMetadata(unsigned KindID) const; + MDNode *getMetadata(StringRef Kind) const; + /// @} + + /// Set a particular kind of metadata attachment. + /// + /// Sets the given attachment to \c MD, erasing it if \c MD is \c nullptr or + /// replacing it if it already exists. + /// @{ + void setMetadata(unsigned KindID, MDNode *MD); + void setMetadata(StringRef Kind, MDNode *MD); + /// @} + + /// Get all current metadata attachments. + void + getAllMetadata(SmallVectorImpl> &MDs) const; + + /// Drop metadata not in the given list. + /// + /// Drop all metadata from \c this not included in \c KnownIDs. + void dropUnknownMetadata(ArrayRef KnownIDs); + // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Value *V) { return V->getValueID() == Value::FunctionVal || Index: include/llvm/IR/GlobalValue.h =================================================================== --- include/llvm/IR/GlobalValue.h +++ include/llvm/IR/GlobalValue.h @@ -95,7 +95,7 @@ friend class Constant; void destroyConstantImpl(); Value *handleOperandChangeImpl(Value *From, Value *To); - + protected: /// \brief The intrinsic ID for this subclass (which must be a Function). /// Index: include/llvm/IR/GlobalVariable.h =================================================================== --- include/llvm/IR/GlobalVariable.h +++ include/llvm/IR/GlobalVariable.h @@ -29,6 +29,7 @@ class Module; class Constant; +class DIGlobalVarExprList; template class SymbolTableListTraits; class GlobalVariable : public GlobalObject, public ilist_node { @@ -163,6 +164,17 @@ static inline bool classof(const Value *V) { return V->getValueID() == Value::GlobalVariableVal; } + + /// Set the attached DIGlobalVarExprList. + /// + /// Calls \a setMetadata() with \a LLVMContext::MD_dbg. + void setGlobalVarExprs(DIGlobalVarExprList SP); + + /// Get the attached DIGlobalVarExprList. + /// + /// Calls \a getMetadata() with \a LLVMContext::MD_dbg and casts the result + /// to \a DIGlobalVariable. + DIGlobalVarExprList getGlobalVarExprs() const; }; template <> Index: lib/AsmParser/LLParser.cpp =================================================================== --- lib/AsmParser/LLParser.cpp +++ lib/AsmParser/LLParser.cpp @@ -791,10 +791,10 @@ /// ParseGlobal /// ::= GlobalVar '=' OptionalLinkage OptionalVisibility OptionalDLLStorageClass /// OptionalThreadLocal OptionalUnnamedAddr OptionalAddrSpace -/// OptionalExternallyInitialized GlobalType Type Const +/// OptionalExternallyInitialized GlobalType Type Const (, !dbg !42) /// ::= OptionalLinkage OptionalVisibility OptionalDLLStorageClass /// OptionalThreadLocal OptionalUnnamedAddr OptionalAddrSpace -/// OptionalExternallyInitialized GlobalType Type Const +/// OptionalExternallyInitialized GlobalType Type Const (, !dbg !42) /// /// Everything up to and including OptionalUnnamedAddr has been parsed /// already. @@ -884,8 +884,13 @@ // Parse attributes on the global. while (Lex.getKind() == lltok::comma) { Lex.Lex(); - - if (Lex.getKind() == lltok::kw_section) { + if (Lex.getKind() == lltok::MetadataVar) { + unsigned MDK; + MDNode *N; + if (ParseMetadataAttachment(MDK, N)) + return true; + GV->setMetadata(MDK, N); + } else if (Lex.getKind() == lltok::kw_section) { Lex.Lex(); GV->setSection(Lex.getStrVal()); if (ParseToken(lltok::StringConstant, "expected global section string")) Index: lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- lib/Bitcode/Reader/BitcodeReader.cpp +++ lib/Bitcode/Reader/BitcodeReader.cpp @@ -2320,14 +2320,22 @@ if (Record.size() != 11) return error("Invalid record"); - MetadataList.assignValue( - GET_OR_DISTINCT(DIGlobalVariable, Record[0], - (Context, getMDOrNull(Record[1]), - getMDString(Record[2]), getMDString(Record[3]), - getMDOrNull(Record[4]), Record[5], - getMDOrNull(Record[6]), Record[7], Record[8], - getMDOrNull(Record[9]), getMDOrNull(Record[10]))), - NextMetadataNo++); + auto *MD = GET_OR_DISTINCT( + DIGlobalVariable, Record[0], + (Context, getMDOrNull(Record[1]), getMDString(Record[2]), + getMDString(Record[3]), getMDOrNull(Record[4]), Record[5], + getMDOrNull(Record[6]), Record[7], Record[8], getMDOrNull(Record[9]), + nullptr)); + + MetadataList.assignValue(MD, NextMetadataNo++); + + // Make a best effort to upgrade the global metadata graph. + if (auto *Var = getMDOrNull(Record[10])) + if (auto *Val = dyn_cast_or_null(Var)) + if (auto *GO = dyn_cast_or_null(Val->getValue())) + GO->setGlobalVarExprs(MDTuple::getDistinct( + Context, {cast(MD), nullptr})); + break; } case bitc::METADATA_LOCAL_VAR: { @@ -3259,6 +3267,7 @@ SmallVector Record; std::vector SectionTable; std::vector GCTable; + std::vector> GlobalVarMetadata; // Read all the records for this module. while (1) { @@ -3267,8 +3276,14 @@ switch (Entry.Kind) { case BitstreamEntry::Error: return error("Malformed block"); - case BitstreamEntry::EndBlock: + case BitstreamEntry::EndBlock: { + for (auto &GVID : GlobalVarMetadata) + if (MDNode *MD = MetadataList.getMDNodeFwdRefOrNull(GVID.second)) + GVID.first->setMetadata(LLVMContext::MD_dbg, MD); + else + return error("Invalid debug info node"); return globalCleanup(); + } case BitstreamEntry::SubBlock: switch (Entry.ID) { @@ -3480,7 +3495,7 @@ // GLOBALVAR: [pointer type, isconst, initid, // linkage, alignment, section, visibility, threadlocal, // unnamed_addr, externally_initialized, dllstorageclass, - // comdat] + // comdat, metadata] case bitc::MODULE_CODE_GLOBALVAR: { if (Record.size() < 6) return error("Invalid record"); @@ -3557,6 +3572,12 @@ } else if (hasImplicitComdat(RawLinkage)) { NewGV->setComdat(reinterpret_cast(1)); } + + if (Record.size() > 12 && Record[12]) { + llvm::errs()<getAddressSpace() << 2 | 2 | GV.isConstant()); Vals.push_back(GV.isDeclaration() ? 0 : @@ -744,13 +744,14 @@ GV.getVisibility() != GlobalValue::DefaultVisibility || GV.hasUnnamedAddr() || GV.isExternallyInitialized() || GV.getDLLStorageClass() != GlobalValue::DefaultStorageClass || - GV.hasComdat()) { + GV.hasComdat() || GV.hasMetadata()) { Vals.push_back(getEncodedVisibility(GV)); Vals.push_back(getEncodedThreadLocalMode(GV)); Vals.push_back(GV.hasUnnamedAddr()); Vals.push_back(GV.isExternallyInitialized()); Vals.push_back(getEncodedDLLStorageClass(GV)); Vals.push_back(GV.hasComdat() ? VE.getComdatID(GV.getComdat()) : 0); + Vals.push_back(VE.getMetadataOrNullID(GV.getGlobalVarExprs().get())); } else { AbbrevToUse = SimpleGVarAbbrev; } Index: lib/Bitcode/Writer/ValueEnumerator.cpp =================================================================== --- lib/Bitcode/Writer/ValueEnumerator.cpp +++ lib/Bitcode/Writer/ValueEnumerator.cpp @@ -306,7 +306,7 @@ for (const GlobalVariable &GV : M.globals()) if (GV.hasInitializer()) EnumerateValue(GV.getInitializer()); - + // Enumerate the aliasees. for (const GlobalAlias &GA : M.aliases()) EnumerateValue(GA.getAliasee()); @@ -328,6 +328,11 @@ EnumerateNamedMetadata(M); SmallVector, 8> MDs; + for (const GlobalVariable &GV : M.globals()) { + GV.getAllMetadata(MDs); + for (const auto &I : MDs) + EnumerateMetadata(I.second); + } // Enumerate types used by function bodies and argument lists. for (const Function &F : M) { Index: lib/IR/AsmWriter.cpp =================================================================== --- lib/IR/AsmWriter.cpp +++ lib/IR/AsmWriter.cpp @@ -770,6 +770,11 @@ for (const GlobalVariable &Var : TheModule->globals()) { if (!Var.hasName()) CreateModuleSlot(&Var); + + SmallVector, 4> MDs; + Var.getAllMetadata(MDs); + for (auto &MD : MDs) + CreateMetadataSlot(MD.second); } for (const GlobalAlias &A : TheModule->aliases()) { @@ -2434,6 +2439,10 @@ if (GV->getAlignment()) Out << ", align " << GV->getAlignment(); + SmallVector, 1> MDs; + GV->getAllMetadata(MDs); + printMetadataAttachments(MDs, ", "); + printInfoComment(*GV); } Index: lib/IR/Constants.cpp =================================================================== --- lib/IR/Constants.cpp +++ lib/IR/Constants.cpp @@ -466,16 +466,19 @@ /// removeDeadUsersOfConstant - If the specified constantexpr is dead, remove /// it. This involves recursively eliminating any dead users of the /// constantexpr. -static bool removeDeadUsersOfConstant(const Constant *C) { +static bool removeDeadUsersOfConstant(const Constant *C, bool SkipMetadataUses) { if (isa(C)) return false; // Cannot remove this while (!C->use_empty()) { const Constant *User = dyn_cast(C->user_back()); if (!User) return false; // Non-constant usage; - if (!removeDeadUsersOfConstant(User)) + if (!removeDeadUsersOfConstant(User, SkipMetadataUses)) return false; // Constant wasn't dead } + if (!SkipMetadataUses && C->isUsedByMetadata()) + return false; + const_cast(C)->destroyConstant(); return true; } @@ -485,7 +488,7 @@ /// off of this constant, remove them. This method is useful for clients /// that want to check to see if a global is unused, but don't want to deal /// with potentially dead constants hanging off of the globals. -void Constant::removeDeadConstantUsers() const { +void Constant::removeDeadConstantUsers(bool SkipMetadataUses) const { Value::const_user_iterator I = user_begin(), E = user_end(); Value::const_user_iterator LastNonDeadUser = E; while (I != E) { @@ -496,7 +499,7 @@ continue; } - if (!removeDeadUsersOfConstant(User)) { + if (!removeDeadUsersOfConstant(User, SkipMetadataUses)) { // If the constant wasn't dead, remember that this was the last live use // and move on to the next constant. LastNonDeadUser = I; Index: lib/IR/LLVMContextImpl.h =================================================================== --- lib/IR/LLVMContextImpl.h +++ lib/IR/LLVMContextImpl.h @@ -1006,8 +1006,8 @@ /// Collection of per-instruction metadata used in this context. DenseMap InstructionMetadata; - /// Collection of per-function metadata used in this context. - DenseMap FunctionMetadata; + /// Collection of per-GO metadata used in this context. + DenseMap GlobalObjectMetadata; /// DiscriminatorTable - This table maps file:line locations to an /// integer representing the next DWARF path discriminator to assign to Index: lib/IR/Metadata.cpp =================================================================== --- lib/IR/Metadata.cpp +++ lib/IR/Metadata.cpp @@ -1230,24 +1230,24 @@ setHasMetadataHashEntry(false); } -MDNode *Function::getMetadata(unsigned KindID) const { +MDNode *GlobalObject::getMetadata(unsigned KindID) const { if (!hasMetadata()) return nullptr; - return getContext().pImpl->FunctionMetadata[this].lookup(KindID); + return getContext().pImpl->GlobalObjectMetadata[this].lookup(KindID); } -MDNode *Function::getMetadata(StringRef Kind) const { +MDNode *GlobalObject::getMetadata(StringRef Kind) const { if (!hasMetadata()) return nullptr; return getMetadata(getContext().getMDKindID(Kind)); } -void Function::setMetadata(unsigned KindID, MDNode *MD) { +void GlobalObject::setMetadata(unsigned KindID, MDNode *MD) { if (MD) { if (!hasMetadata()) setHasMetadataHashEntry(true); - getContext().pImpl->FunctionMetadata[this].set(KindID, *MD); + getContext().pImpl->GlobalObjectMetadata[this].set(KindID, *MD); return; } @@ -1255,29 +1255,29 @@ if (!hasMetadata()) return; - auto &Store = getContext().pImpl->FunctionMetadata[this]; + auto &Store = getContext().pImpl->GlobalObjectMetadata[this]; Store.erase(KindID); if (Store.empty()) clearMetadata(); } -void Function::setMetadata(StringRef Kind, MDNode *MD) { +void GlobalObject::setMetadata(StringRef Kind, MDNode *MD) { if (!MD && !hasMetadata()) return; setMetadata(getContext().getMDKindID(Kind), MD); } -void Function::getAllMetadata( +void GlobalObject::getAllMetadata( SmallVectorImpl> &MDs) const { MDs.clear(); if (!hasMetadata()) return; - getContext().pImpl->FunctionMetadata[this].getAll(MDs); + getContext().pImpl->GlobalObjectMetadata[this].getAll(MDs); } -void Function::dropUnknownMetadata(ArrayRef KnownIDs) { +void GlobalObject::dropUnknownMetadata(ArrayRef KnownIDs) { if (!hasMetadata()) return; if (KnownIDs.empty()) { @@ -1288,7 +1288,7 @@ SmallSet KnownSet; KnownSet.insert(KnownIDs.begin(), KnownIDs.end()); - auto &Store = getContext().pImpl->FunctionMetadata[this]; + auto &Store = getContext().pImpl->GlobalObjectMetadata[this]; assert(!Store.empty()); Store.remove_if([&KnownSet](const std::pair &I) { @@ -1299,10 +1299,10 @@ clearMetadata(); } -void Function::clearMetadata() { +void GlobalObject::clearMetadata() { if (!hasMetadata()) return; - getContext().pImpl->FunctionMetadata.erase(this); + getContext().pImpl->GlobalObjectMetadata.erase(this); setHasMetadataHashEntry(false); } @@ -1313,3 +1313,12 @@ DISubprogram *Function::getSubprogram() const { return cast_or_null(getMetadata(LLVMContext::MD_dbg)); } + +void GlobalVariable::setGlobalVarExprs(DIGlobalVarExprList L) { + setMetadata(LLVMContext::MD_dbg, L.get()); +} + +DIGlobalVarExprList GlobalVariable::getGlobalVarExprs() const { + return DIGlobalVarExprList( + cast_or_null(getMetadata(LLVMContext::MD_dbg))); +} Index: test/Assembler/diglobalvariable.ll =================================================================== --- test/Assembler/diglobalvariable.ll +++ test/Assembler/diglobalvariable.ll @@ -1,7 +1,7 @@ ; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s ; RUN: verify-uselistorder %s -@foo = global i32 0 +@foo = global i32 0, !dbg !10 ; CHECK: !named = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9} !named = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9} @@ -25,3 +25,4 @@ ; CHECK: !9 = !DIGlobalVariable(name: "mem", scope: !0, isLocal: false, isDefinition: true, declaration: !8) !9 = !DIGlobalVariable(name: "mem", scope: !0, declaration: !8) +!10 = distinct !{!6, null}