Index: include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- include/llvm/Bitcode/LLVMBitCodes.h +++ include/llvm/Bitcode/LLVMBitCodes.h @@ -252,6 +252,7 @@ METADATA_MACRO_FILE = 34, // [distinct, macinfo, line, file, ...] METADATA_STRINGS = 35, // [count, offset] blob([lengths][chars]) METADATA_GLOBAL_DECL_ATTACHMENT = 36, // [valueid, n x [id, mdnode]] + METADATA_GLOBAL_VAR_EXPR = 37, // [distinct, var, expr] }; // The constants block (CONSTANTS_BLOCK_ID) describes emission for each Index: include/llvm/IR/DIBuilder.h =================================================================== --- include/llvm/IR/DIBuilder.h +++ include/llvm/IR/DIBuilder.h @@ -49,7 +49,7 @@ /// Track the RetainTypes, since they can be updated later on. SmallVector AllRetainTypes; SmallVector AllSubprograms; - SmallVector AllGVs; + SmallVector AllGVs; SmallVector AllImportedModules; /// Track nodes that may be unresolved. @@ -465,20 +465,20 @@ /// \param Decl Reference to the corresponding declaration. /// \param AlignInBits Variable alignment(or 0 if no alignment attr was /// specified) - DIGlobalVariable *createGlobalVariable(DIScope *Context, StringRef Name, - StringRef LinkageName, DIFile *File, - unsigned LineNo, DIType *Ty, - bool isLocalToUnit, - DIExpression *Expr = nullptr, - MDNode *Decl = nullptr, - uint32_t AlignInBits = 0); + DIGlobalVarExpr createGlobalVariable(DIScope *Context, StringRef Name, + StringRef LinkageName, DIFile *File, + unsigned LineNo, DIType *Ty, + bool isLocalToUnit, + DIExpression *Expr = nullptr, + MDNode *Decl = nullptr, + uint32_t AlignInBits = 0); /// Identical to createGlobalVariable /// except that the resulting DbgNode is temporary and meant to be RAUWed. DIGlobalVariable *createTempGlobalVariableFwdDecl( DIScope *Context, StringRef Name, StringRef LinkageName, DIFile *File, - unsigned LineNo, DIType *Ty, bool isLocalToUnit, DIExpression *Expr, - MDNode *Decl = nullptr, uint32_t AlignInBits = 0); + unsigned LineNo, DIType *Ty, bool isLocalToUnit, MDNode *Decl = nullptr, + uint32_t AlignInBits = 0); /// Create a new descriptor for an auto variable. This is a local variable /// that is not a subprogram parameter. Index: include/llvm/IR/DebugInfo.h =================================================================== --- include/llvm/IR/DebugInfo.h +++ include/llvm/IR/DebugInfo.h @@ -89,7 +89,7 @@ void processSubprogram(DISubprogram *SP); void processScope(DIScope *Scope); bool addCompileUnit(DICompileUnit *CU); - bool addGlobalVariable(DIGlobalVariable *DIG); + bool addGlobalVariable(DIGlobalVarExpr DIG); bool addSubprogram(DISubprogram *SP); bool addType(DIType *DT); bool addScope(DIScope *Scope); @@ -98,7 +98,7 @@ typedef SmallVectorImpl::const_iterator compile_unit_iterator; typedef SmallVectorImpl::const_iterator subprogram_iterator; - typedef SmallVectorImpl::const_iterator + typedef SmallVectorImpl::const_iterator global_variable_iterator; typedef SmallVectorImpl::const_iterator type_iterator; typedef SmallVectorImpl::const_iterator scope_iterator; @@ -132,7 +132,7 @@ private: SmallVector CUs; SmallVector SPs; - SmallVector GVs; + SmallVector GVs; SmallVector TYs; SmallVector Scopes; SmallPtrSet NodesSeen; Index: include/llvm/IR/DebugInfoMetadata.h =================================================================== --- include/llvm/IR/DebugInfoMetadata.h +++ include/llvm/IR/DebugInfoMetadata.h @@ -997,6 +997,60 @@ } }; +/// Either a DIGlobalVariable or a DIGlobalVariableExpression. +typedef PointerUnion + DIGlobalVarExpr; +DIGlobalVarExpr makeDIGlobalVarExpr(MDNode *N); + +/// This is a wrapper for \a MDTuple that makes it act like an array holding \a +/// DIGlobalVarExpr. Unfortunately we can't use the generic +/// MDTupleTypedArrayWrapper here because of the PointerUnion. +class DIGlobalVarExprArray { + const MDTuple *N = nullptr; + +public: + DIGlobalVarExprArray() = default; + DIGlobalVarExprArray(const MDTuple *N) : N(N) {} + DIGlobalVarExprArray(const DIGlobalVarExprArray &Other) : N(Other.get()) {} + + 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(); } + + unsigned size() const { return N ? N->getNumOperands() : 0u; } + DIGlobalVarExpr operator[](unsigned I) const; + + class iterator + : std::iterator { + MDNode::op_iterator I = nullptr; + + public: + iterator() = default; + explicit iterator(MDNode::op_iterator I) : I(I) {} + DIGlobalVarExpr operator*() const { + return makeDIGlobalVarExpr(cast(*I)); + } + + iterator &operator++() { + ++I; + return *this; + } + iterator operator++(int) { + iterator Temp(*this); + ++I; + 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(); } +}; + /// Compile unit. class DICompileUnit : public DIScope { friend class LLVMContextImpl; @@ -1038,7 +1092,7 @@ StringRef Producer, bool IsOptimized, StringRef Flags, unsigned RuntimeVersion, StringRef SplitDebugFilename, unsigned EmissionKind, DICompositeTypeArray EnumTypes, - DIScopeArray RetainedTypes, DIGlobalVariableArray GlobalVariables, + DIScopeArray RetainedTypes, DIGlobalVarExprArray GlobalVariables, DIImportedEntityArray ImportedEntities, DIMacroNodeArray Macros, uint64_t DWOId, bool SplitDebugInlining, StorageType Storage, bool ShouldCreate = true) { @@ -1078,7 +1132,7 @@ bool IsOptimized, StringRef Flags, unsigned RuntimeVersion, StringRef SplitDebugFilename, DebugEmissionKind EmissionKind, DICompositeTypeArray EnumTypes, DIScopeArray RetainedTypes, - DIGlobalVariableArray GlobalVariables, + DIGlobalVarExprArray GlobalVariables, DIImportedEntityArray ImportedEntities, DIMacroNodeArray Macros, uint64_t DWOId, bool SplitDebugInlining), (SourceLanguage, File, Producer, IsOptimized, Flags, RuntimeVersion, @@ -1113,7 +1167,7 @@ DIScopeArray getRetainedTypes() const { return cast_or_null(getRawRetainedTypes()); } - DIGlobalVariableArray getGlobalVariables() const { + DIGlobalVarExprArray getGlobalVariables() const { return cast_or_null(getRawGlobalVariables()); } DIImportedEntityArray getImportedEntities() const { @@ -1152,7 +1206,7 @@ void replaceRetainedTypes(DITypeArray N) { replaceOperandWith(5, N.get()); } - void replaceGlobalVariables(DIGlobalVariableArray N) { + void replaceGlobalVariables(DIGlobalVarExprArray N) { replaceOperandWith(6, N.get()); } void replaceImportedEntities(DIImportedEntityArray N) { @@ -1963,6 +2017,9 @@ /// Return the size of this fragment in bits. uint64_t getFragmentSizeInBits() const; + /// Determine whether this represents a standalone constant value. + bool isConstant() const; + typedef ArrayRef::iterator element_iterator; element_iterator elements_begin() const { return getElements().begin(); } element_iterator elements_end() const { return getElements().end(); } @@ -2082,30 +2139,30 @@ IsLocalToUnit(IsLocalToUnit), IsDefinition(IsDefinition) {} ~DIGlobalVariable() = default; - static DIGlobalVariable * - getImpl(LLVMContext &Context, DIScope *Scope, StringRef Name, - StringRef LinkageName, DIFile *File, unsigned Line, DITypeRef Type, - bool IsLocalToUnit, bool IsDefinition, DIExpression *Expr, - DIDerivedType *StaticDataMemberDeclaration, uint32_t AlignInBits, - StorageType Storage, bool ShouldCreate = true) { + static DIGlobalVariable *getImpl(LLVMContext &Context, DIScope *Scope, + StringRef Name, StringRef LinkageName, + DIFile *File, unsigned Line, DITypeRef Type, + bool IsLocalToUnit, bool IsDefinition, + DIDerivedType *StaticDataMemberDeclaration, + uint32_t AlignInBits, StorageType Storage, + bool ShouldCreate = true) { return getImpl(Context, Scope, getCanonicalMDString(Context, Name), getCanonicalMDString(Context, LinkageName), File, Line, Type, - IsLocalToUnit, IsDefinition, Expr, - StaticDataMemberDeclaration, AlignInBits, Storage, - ShouldCreate); + IsLocalToUnit, IsDefinition, StaticDataMemberDeclaration, + AlignInBits, Storage, ShouldCreate); } static DIGlobalVariable * getImpl(LLVMContext &Context, Metadata *Scope, MDString *Name, MDString *LinkageName, Metadata *File, unsigned Line, Metadata *Type, - bool IsLocalToUnit, bool IsDefinition, Metadata *Expr, + bool IsLocalToUnit, bool IsDefinition, Metadata *StaticDataMemberDeclaration, uint32_t AlignInBits, StorageType Storage, bool ShouldCreate = true); TempDIGlobalVariable cloneImpl() const { return getTemporary(getContext(), getScope(), getName(), getLinkageName(), getFile(), getLine(), getType(), isLocalToUnit(), - isDefinition(), getExpr(), - getStaticDataMemberDeclaration(), getAlignInBits()); + isDefinition(), getStaticDataMemberDeclaration(), + getAlignInBits()); } public: @@ -2113,21 +2170,18 @@ (DIScope * Scope, StringRef Name, StringRef LinkageName, DIFile *File, unsigned Line, DITypeRef Type, bool IsLocalToUnit, bool IsDefinition, - DIExpression *Expr, DIDerivedType *StaticDataMemberDeclaration, uint32_t AlignInBits), (Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, - IsDefinition, Expr, StaticDataMemberDeclaration, - AlignInBits)) + IsDefinition, StaticDataMemberDeclaration, AlignInBits)) DEFINE_MDNODE_GET(DIGlobalVariable, (Metadata * Scope, MDString *Name, MDString *LinkageName, Metadata *File, unsigned Line, Metadata *Type, bool IsLocalToUnit, bool IsDefinition, - Metadata *Expr, Metadata *StaticDataMemberDeclaration, + Metadata *StaticDataMemberDeclaration, uint32_t AlignInBits), (Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, - IsDefinition, Expr, StaticDataMemberDeclaration, - AlignInBits)) + IsDefinition, StaticDataMemberDeclaration, AlignInBits)) TempDIGlobalVariable clone() const { return cloneImpl(); } @@ -2135,19 +2189,12 @@ bool isDefinition() const { return IsDefinition; } StringRef getDisplayName() const { return getStringOperand(4); } StringRef getLinkageName() const { return getStringOperand(5); } - DIExpression *getExpr() const { - return cast_or_null(getRawExpr()); - } - void replaceExpr(DIExpression *E) { - replaceOperandWith(6, E); - } DIDerivedType *getStaticDataMemberDeclaration() const { return cast_or_null(getRawStaticDataMemberDeclaration()); } MDString *getRawLinkageName() const { return getOperandAs(5); } - Metadata *getRawExpr() const { return getOperand(6); } - Metadata *getRawStaticDataMemberDeclaration() const { return getOperand(7); } + Metadata *getRawStaticDataMemberDeclaration() const { return getOperand(6); } static bool classof(const Metadata *MD) { return MD->getMetadataID() == DIGlobalVariableKind; @@ -2373,6 +2420,45 @@ } }; +/// A pair of DIGlobalVariable and DIExpression. +class DIGlobalVariableExpression : public MDNode { + friend class LLVMContextImpl; + friend class MDNode; + + DIGlobalVariableExpression(LLVMContext &C, StorageType Storage, + ArrayRef Ops) + : MDNode(C, DIGlobalVariableExpressionKind, Storage, Ops) {} + ~DIGlobalVariableExpression() = default; + + static DIGlobalVariableExpression * + getImpl(LLVMContext &Context, Metadata *Variable, Metadata *Expression, + StorageType Storage, bool ShouldCreate = true); + + TempDIGlobalVariableExpression cloneImpl() const { + return getTemporary(getContext(), getVariable(), getExpression()); + } + +public: + DEFINE_MDNODE_GET(DIGlobalVariableExpression, + (Metadata * Variable, Metadata *Expression), + (Variable, Expression)) + + TempDIGlobalVariableExpression clone() const { return cloneImpl(); } + + Metadata *getRawVariable() const { return getOperand(0); } + DIGlobalVariable *getVariable() const { + return cast_or_null(getRawVariable()); + } + Metadata *getRawExpression() const { return getOperand(1); } + DIExpression *getExpression() const { + return cast_or_null(getRawExpression()); + } + + static bool classof(const Metadata *MD) { + return MD->getMetadataID() == DIGlobalVariableExpressionKind; + } +}; + /// Macro Info DWARF-like metadata node. /// /// A metadata node with a DWARF macro info (i.e., a constant named @@ -2532,6 +2618,33 @@ } }; +/// Create a DIGlobalVarExpr union from an MDNode pointer. +inline DIGlobalVarExpr makeDIGlobalVarExpr(MDNode *N) { + if (auto *GV = dyn_cast(N)) + return DIGlobalVarExpr(GV); + return DIGlobalVarExpr(cast(N)); +} + +/// Helper class to directly access a DIGlobalVarExpr's DIGlobalVariable and for +/// unwrapping its MDNode pointer. +class UnwrappedDIGlobalVarExpr { + DIGlobalVarExpr Union; + +public: + UnwrappedDIGlobalVarExpr(DIGlobalVarExpr U) : Union(U) {} + DIGlobalVariable *getVariable() const { + auto *GV = Union.dyn_cast(); + if (!GV) + GV = Union.get()->getVariable(); + return GV; + } + operator MDNode *() const { + if (auto *GV = Union.dyn_cast()) + return cast(GV); + return cast(Union.get()); + } +}; + } // end namespace llvm #undef DEFINE_MDNODE_GET_UNPACK_IMPL Index: include/llvm/IR/GlobalVariable.h =================================================================== --- include/llvm/IR/GlobalVariable.h +++ include/llvm/IR/GlobalVariable.h @@ -20,6 +20,7 @@ #ifndef LLVM_IR_GLOBALVARIABLE_H #define LLVM_IR_GLOBALVARIABLE_H +#include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/Twine.h" #include "llvm/ADT/ilist_node.h" #include "llvm/IR/GlobalObject.h" @@ -31,10 +32,11 @@ namespace llvm { class Constant; -class DIGlobalVariable; class Module; template class SymbolTableListTraits; +class DIGlobalVariable; +class DIGlobalVariableExpression; class GlobalVariable : public GlobalObject, public ilist_node { friend class SymbolTableListTraits; @@ -170,8 +172,13 @@ /// drops not only the reference to the initializer but also to any metadata. void dropAllReferences(); - void addDebugInfo(DIGlobalVariable *GV); - void getDebugInfo(SmallVectorImpl &GVs) const; + // Avoid including the DebugInfoMetadata header. + using DIGlobalVarExpr = + PointerUnion; + /// Attach a DIGlobalVariable or DIGlobalVariableExpression. + void addDebugInfo(DIGlobalVarExpr GV); + /// Fill the vector with all debug info attachements. + void getDebugInfo(SmallVectorImpl &GVs) const; // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Value *V) { Index: include/llvm/IR/Metadata.def =================================================================== --- include/llvm/IR/Metadata.def +++ include/llvm/IR/Metadata.def @@ -82,6 +82,7 @@ HANDLE_MDNODE_LEAF_UNIQUABLE(MDTuple) HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DILocation) HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIExpression) +HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIGlobalVariableExpression) HANDLE_SPECIALIZED_MDNODE_BRANCH(DINode) HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(GenericDINode) HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DISubrange) Index: lib/Analysis/ModuleDebugInfoPrinter.cpp =================================================================== --- lib/Analysis/ModuleDebugInfoPrinter.cpp +++ lib/Analysis/ModuleDebugInfoPrinter.cpp @@ -91,7 +91,8 @@ O << '\n'; } - for (const DIGlobalVariable *GV : Finder.global_variables()) { + for (auto GVU : Finder.global_variables()) { + const auto *GV = UnwrappedDIGlobalVarExpr(GVU).getVariable(); O << "Global variable: " << GV->getName(); printFile(O, GV->getFilename(), GV->getDirectory(), GV->getLine()); if (!GV->getLinkageName().empty()) Index: lib/AsmParser/LLParser.cpp =================================================================== --- lib/AsmParser/LLParser.cpp +++ lib/AsmParser/LLParser.cpp @@ -4197,8 +4197,7 @@ /// ParseDIGlobalVariable: /// ::= !DIGlobalVariable(scope: !0, name: "foo", linkageName: "foo", /// file: !1, line: 7, type: !2, isLocal: false, -/// isDefinition: true, variable: i32* @foo, -/// declaration: !3, align: 8) +/// isDefinition: true, declaration: !3, align: 8) bool LLParser::ParseDIGlobalVariable(MDNode *&Result, bool IsDistinct) { #define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \ REQUIRED(name, MDStringField, (/* AllowEmpty */ false)); \ @@ -4209,7 +4208,6 @@ OPTIONAL(type, MDField, ); \ OPTIONAL(isLocal, MDBoolField, ); \ OPTIONAL(isDefinition, MDBoolField, (true)); \ - OPTIONAL(expr, MDField, ); \ OPTIONAL(declaration, MDField, ); \ OPTIONAL(align, MDUnsignedField, (0, UINT32_MAX)); PARSE_MD_FIELDS(); @@ -4218,8 +4216,7 @@ Result = GET_OR_DISTINCT(DIGlobalVariable, (Context, scope.Val, name.Val, linkageName.Val, file.Val, line.Val, type.Val, isLocal.Val, - isDefinition.Val, expr.Val, declaration.Val, - align.Val)); + isDefinition.Val, declaration.Val, align.Val)); return false; } @@ -4287,6 +4284,21 @@ return false; } +/// ParseDIGlobalVariableExpression: +/// ::= !DIGlobalVariableExpression(var: !0, expr: !1) +bool LLParser::ParseDIGlobalVariableExpression(MDNode *&Result, + bool IsDistinct) { +#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \ + REQUIRED(var, MDField, ); \ + REQUIRED(expr, MDField, ); + PARSE_MD_FIELDS(); +#undef VISIT_MD_FIELDS + + Result = + GET_OR_DISTINCT(DIGlobalVariableExpression, (Context, var.Val, expr.Val)); + return false; +} + /// ParseDIObjCProperty: /// ::= !DIObjCProperty(name: "foo", file: !1, line: 7, setter: "setFoo", /// getter: "getFoo", attributes: 7, type: !2) Index: lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- lib/Bitcode/Reader/BitcodeReader.cpp +++ lib/Bitcode/Reader/BitcodeReader.cpp @@ -2952,19 +2952,28 @@ } else { Expr = nullptr; } - } + } DIGlobalVariable *DGV = GET_OR_DISTINCT( DIGlobalVariable, (Context, getMDOrNull(Record[1]), getMDString(Record[2]), getMDString(Record[3]), getMDOrNull(Record[4]), Record[5], - getDITypeRefOrNull(Record[6]), Record[7], Record[8], Expr, + getDITypeRefOrNull(Record[6]), Record[7], Record[8], getMDOrNull(Record[10]), AlignInBits)); - MetadataList.assignValue(DGV, NextMetadataNo++); - - if (Attach) - Attach->addDebugInfo(DGV); + + DIGlobalVariableExpression *DGVE = nullptr; + if (Expr) { + DGVE = DIGlobalVariableExpression::getDistinct(Context, DGV, Expr); + MetadataList.assignValue(DGVE, NextMetadataNo++); + } else + MetadataList.assignValue(DGV, NextMetadataNo++); + if (Attach) { + if (Expr) + Attach->addDebugInfo(DGVE); + else + Attach->addDebugInfo(DGV); + } break; } case bitc::METADATA_LOCAL_VAR: { @@ -3014,6 +3023,17 @@ NextMetadataNo++); break; } + case bitc::METADATA_GLOBAL_VAR_EXPR: { + if (Record.size() != 3) + return error("Invalid record"); + + IsDistinct = Record[0]; + MetadataList.assignValue(GET_OR_DISTINCT(DIGlobalVariableExpression, + (Context, getMDOrNull(Record[1]), + getMDOrNull(Record[2]))), + NextMetadataNo++); + break; + } case bitc::METADATA_OBJC_PROPERTY: { if (Record.size() != 8) return error("Invalid record"); Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -210,6 +210,9 @@ SmallVectorImpl &Record, unsigned Abbrev); void writeDIExpression(const DIExpression *N, SmallVectorImpl &Record, unsigned Abbrev); + void writeDIGlobalVariableExpression(const DIGlobalVariableExpression *N, + SmallVectorImpl &Record, + unsigned Abbrev); void writeDIObjCProperty(const DIObjCProperty *N, SmallVectorImpl &Record, unsigned Abbrev); void writeDIImportedEntity(const DIImportedEntity *N, @@ -1683,7 +1686,7 @@ Record.push_back(VE.getMetadataOrNullID(N->getType())); Record.push_back(N->isLocalToUnit()); Record.push_back(N->isDefinition()); - Record.push_back(VE.getMetadataOrNullID(N->getRawExpr())); + Record.push_back(/* expr */ 0); Record.push_back(VE.getMetadataOrNullID(N->getStaticDataMemberDeclaration())); Record.push_back(N->getAlignInBits()); @@ -1735,6 +1738,17 @@ Record.clear(); } +void ModuleBitcodeWriter::writeDIGlobalVariableExpression( + const DIGlobalVariableExpression *N, SmallVectorImpl &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + Record.push_back(VE.getMetadataOrNullID(N->getVariable())); + Record.push_back(VE.getMetadataOrNullID(N->getExpression())); + + Stream.EmitRecord(bitc::METADATA_GLOBAL_VAR_EXPR, Record, Abbrev); + Record.clear(); +} + void ModuleBitcodeWriter::writeDIObjCProperty(const DIObjCProperty *N, SmallVectorImpl &Record, unsigned Abbrev) { Index: lib/CodeGen/AsmPrinter/CodeViewDebug.cpp =================================================================== --- lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -2198,13 +2198,15 @@ // it if we have at least one global to emit. switchToDebugSectionForSymbol(nullptr); MCSymbol *EndLabel = nullptr; - for (const DIGlobalVariable *G : CU->getGlobalVariables()) { + for (const auto GVU : CU->getGlobalVariables()) { + const DIGlobalVariable *G = UnwrappedDIGlobalVarExpr(GVU).getVariable(); if (const auto *GV = GlobalMap.lookup(G)) if (!GV->hasComdat() && !GV->isDeclarationForLinker()) { if (!EndLabel) { OS.AddComment("Symbol subsection for globals"); EndLabel = beginCVSubsection(ModuleSubstreamKind::Symbols); } + // FIXME: emitDebugInfoForGlobal() doesn't handle DIExpressions. emitDebugInfoForGlobal(G, GV, Asm->getSymbol(GV)); } } @@ -2213,7 +2215,8 @@ // Second, emit each global that is in a comdat into its own .debug$S // section along with its own symbol substream. - for (const DIGlobalVariable *G : CU->getGlobalVariables()) { + for (const auto GVU : CU->getGlobalVariables()) { + const DIGlobalVariable *G = UnwrappedDIGlobalVarExpr(GVU).getVariable(); if (const auto *GV = GlobalMap.lookup(G)) { if (GV->hasComdat()) { MCSymbol *GVSym = Asm->getSymbol(GV); @@ -2221,6 +2224,7 @@ Twine(GlobalValue::getRealLinkageName(GV->getName()))); switchToDebugSectionForSymbol(GVSym); EndLabel = beginCVSubsection(ModuleSubstreamKind::Symbols); + // FIXME: emitDebugInfoForGlobal() doesn't handle DIExpressions. emitDebugInfoForGlobal(G, GV, GVSym); endCVSubsection(EndLabel); } Index: lib/CodeGen/AsmPrinter/DwarfCompileUnit.h =================================================================== --- lib/CodeGen/AsmPrinter/DwarfCompileUnit.h +++ lib/CodeGen/AsmPrinter/DwarfCompileUnit.h @@ -91,9 +91,10 @@ /// Apply the DW_AT_stmt_list from this compile unit to the specified DIE. void applyStmtList(DIE &D); + typedef std::pair GlobalExpr; /// getOrCreateGlobalVariableDIE - get or create global variable DIE. DIE *getOrCreateGlobalVariableDIE(const DIGlobalVariable *GV, - const GlobalVariable *Global); + ArrayRef Globals); /// addLabelAddress - Add a dwarf label attribute data and value using /// either DW_FORM_addr or DW_FORM_GNU_addr_index. Index: lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -73,9 +73,8 @@ Asm->OutStreamer->hasRawTextSupport() ? 0 : getUniqueID()); } -/// getOrCreateGlobalVariableDIE - get or create global variable DIE. DIE *DwarfCompileUnit::getOrCreateGlobalVariableDIE( - const DIGlobalVariable *GV, const GlobalVariable *Global) { + const DIGlobalVariable *GV, ArrayRef Globals) { // Check for pre-existence. if (DIE *Die = getDIE(GV)) return Die; @@ -128,69 +127,70 @@ // Add location. bool addToAccelTable = false; - - DIExpression *Expr = GV->getExpr(); - - // For compatibility with DWARF 3 and earlier, - // DW_AT_location(DW_OP_constu, X, DW_OP_stack_value) becomes - // DW_AT_const_value(X). - if (Expr && Expr->getNumElements() == 3 && - Expr->getElement(0) == dwarf::DW_OP_constu && - Expr->getElement(2) == dwarf::DW_OP_stack_value) { - addConstantValue(*VariableDIE, /*Unsigned=*/true, Expr->getElement(1)); - // We cannot describe the location of dllimport'd variables: the computation - // of their address requires loads from the IAT. - } else if (!Global || !Global->hasDLLImportStorageClass()) { - DIELoc *Loc = new (DIEValueAllocator) DIELoc; - if (Global) { - addToAccelTable = true; - const MCSymbol *Sym = Asm->getSymbol(Global); - if (Global->isThreadLocal()) { - if (Asm->TM.Options.EmulatedTLS) { - // TODO: add debug info for emulated thread local mode. - } else { - // FIXME: Make this work with -gsplit-dwarf. - unsigned PointerSize = Asm->getDataLayout().getPointerSize(); - assert((PointerSize == 4 || PointerSize == 8) && - "Add support for other sizes if necessary"); - // Based on GCC's support for TLS: - if (!DD->useSplitDwarf()) { - // 1) Start with a constNu of the appropriate pointer size - addUInt(*Loc, dwarf::DW_FORM_data1, PointerSize == 4 - ? dwarf::DW_OP_const4u - : dwarf::DW_OP_const8u); - // 2) containing the (relocated) offset of the TLS variable - // within the module's TLS block. - addExpr(*Loc, dwarf::DW_FORM_udata, - Asm->getObjFileLowering().getDebugThreadLocalSymbol(Sym)); + DIELoc *Loc = nullptr; + for (auto &GE : Globals) { + const GlobalVariable *Global = GE.first; + const DIExpression *Expr = GE.second; + // For compatibility with DWARF 3 and earlier, + // DW_AT_location(DW_OP_constu, X, DW_OP_stack_value) becomes + // DW_AT_const_value(X). + if (Globals.size() == 1 && Expr && Expr->isConstant()) { + addConstantValue(*VariableDIE, /*Unsigned=*/true, Expr->getElement(1)); + // We cannot describe the location of dllimport'd variables: the + // computation of their address requires loads from the IAT. + } else if (!Global || !Global->hasDLLImportStorageClass()) { + if (!Loc) + Loc = new (DIEValueAllocator) DIELoc; + if (Global) { + addToAccelTable = true; + const MCSymbol *Sym = Asm->getSymbol(Global); + if (Global->isThreadLocal()) { + if (Asm->TM.Options.EmulatedTLS) { + // TODO: add debug info for emulated thread local mode. } else { - addUInt(*Loc, dwarf::DW_FORM_data1, dwarf::DW_OP_GNU_const_index); - addUInt(*Loc, dwarf::DW_FORM_udata, - DD->getAddressPool().getIndex(Sym, /* TLS */ true)); + // FIXME: Make this work with -gsplit-dwarf. + unsigned PointerSize = Asm->getDataLayout().getPointerSize(); + assert((PointerSize == 4 || PointerSize == 8) && + "Add support for other sizes if necessary"); + // Based on GCC's support for TLS: + if (!DD->useSplitDwarf()) { + // 1) Start with a constNu of the appropriate pointer size + addUInt(*Loc, dwarf::DW_FORM_data1, PointerSize == 4 + ? dwarf::DW_OP_const4u + : dwarf::DW_OP_const8u); + // 2) containing the (relocated) offset of the TLS variable + // within the module's TLS block. + addExpr(*Loc, dwarf::DW_FORM_udata, + Asm->getObjFileLowering().getDebugThreadLocalSymbol(Sym)); + } else { + addUInt(*Loc, dwarf::DW_FORM_data1, dwarf::DW_OP_GNU_const_index); + addUInt(*Loc, dwarf::DW_FORM_udata, + DD->getAddressPool().getIndex(Sym, /* TLS */ true)); + } + // 3) followed by an OP to make the debugger do a TLS lookup. + addUInt(*Loc, dwarf::DW_FORM_data1, + DD->useGNUTLSOpcode() ? dwarf::DW_OP_GNU_push_tls_address + : dwarf::DW_OP_form_tls_address); } - // 3) followed by an OP to make the debugger do a TLS lookup. - addUInt(*Loc, dwarf::DW_FORM_data1, - DD->useGNUTLSOpcode() ? dwarf::DW_OP_GNU_push_tls_address - : dwarf::DW_OP_form_tls_address); + } else { + DD->addArangeLabel(SymbolCU(this, Sym)); + addOpAddress(*Loc, Sym); } - } else { - DD->addArangeLabel(SymbolCU(this, Sym)); - addOpAddress(*Loc, Sym); - } - if (Expr) { - DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc); - DwarfExpr.addFragmentOffset(Expr); - DwarfExpr.AddExpression(Expr); - DwarfExpr.finalize(); + if (Expr) { + DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc); + DwarfExpr.addFragmentOffset(Expr); + DwarfExpr.AddExpression(Expr); + DwarfExpr.finalize(); + } } } - + } + if (Loc) addBlock(*VariableDIE, dwarf::DW_AT_location, Loc); - if (DD->useAllLinkageNames()) - addLinkageName(*VariableDIE, GV->getLinkageName()); - } + if (DD->useAllLinkageNames()) + addLinkageName(*VariableDIE, GV->getLinkageName()); if (addToAccelTable) { DD->addAccelName(GV->getName(), *VariableDIE); @@ -657,8 +657,11 @@ else if (auto *T = dyn_cast(Entity)) EntityDie = getOrCreateTypeDIE(T); else if (auto *GV = dyn_cast(Entity)) - EntityDie = getOrCreateGlobalVariableDIE(GV, nullptr); - else + EntityDie = getOrCreateGlobalVariableDIE(GV, {}); + else if (auto *GVE = dyn_cast(Entity)) { + GlobalExpr GE = {nullptr, GVE->getExpression()}; + EntityDie = getOrCreateGlobalVariableDIE(GVE->getVariable(), GE); + } else EntityDie = getDIE(Entity); assert(EntityDie); addSourceLine(*IMDie, Module->getLine(), Module->getScope()->getFilename(), Index: lib/CodeGen/AsmPrinter/DwarfDebug.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -478,21 +478,34 @@ // Tell MMI whether we have debug info. MMI->setDebugInfoAvailability(NumDebugCUs > 0); SingleCU = NumDebugCUs == 1; - - DenseMap GVMap; + DenseMap> + GVMap; for (const GlobalVariable &Global : M->globals()) { - SmallVector GVs; + SmallVector GVs; Global.getDebugInfo(GVs); - for (auto &GV : GVs) - GVMap[GV] = &Global; + for (auto GVU : GVs) + if (auto *GVE = GVU.dyn_cast()) + GVMap[GVE->getVariable()].push_back({&Global, GVE->getExpression()}); + else + GVMap[GVU.get()].push_back({&Global, nullptr}); } for (DICompileUnit *CUNode : M->debug_compile_units()) { DwarfCompileUnit &CU = constructDwarfCompileUnit(CUNode); for (auto *IE : CUNode->getImportedEntities()) CU.addImportedEntity(IE); - for (auto *GV : CUNode->getGlobalVariables()) - CU.getOrCreateGlobalVariableDIE(GV, GVMap.lookup(GV)); + + // Global Variables. + for (auto GV : CUNode->getGlobalVariables()) + if (auto *GVE = GV.dyn_cast()) + GVMap[GVE->getVariable()].push_back({nullptr, GVE->getExpression()}); + DenseSet Processed; + for (auto GVU : CUNode->getGlobalVariables()) { + DIGlobalVariable *GV = UnwrappedDIGlobalVarExpr(GVU).getVariable(); + if (Processed.insert(GV).second) + CU.getOrCreateGlobalVariableDIE(GV, GVMap.lookup(GV)); + } + for (auto *Ty : CUNode->getEnumTypes()) { // The enum types array by design contains pointers to // MDNodes rather than DIRefs. Unique them here. Index: lib/IR/AsmWriter.cpp =================================================================== --- lib/IR/AsmWriter.cpp +++ lib/IR/AsmWriter.cpp @@ -1827,7 +1827,6 @@ Printer.printMetadata("type", N->getRawType()); Printer.printBool("isLocal", N->isLocalToUnit()); Printer.printBool("isDefinition", N->isDefinition()); - Printer.printMetadata("expr", N->getExpr()); Printer.printMetadata("declaration", N->getRawStaticDataMemberDeclaration()); Printer.printInt("align", N->getAlignInBits()); Out << ")"; @@ -1870,6 +1869,18 @@ Out << ")"; } +static void writeDIGlobalVariableExpression(raw_ostream &Out, + const DIGlobalVariableExpression *N, + TypePrinting *TypePrinter, + SlotTracker *Machine, + const Module *Context) { + Out << "!DIGlobalVariableExpression("; + MDFieldPrinter Printer(Out, TypePrinter, Machine, Context); + Printer.printMetadata("var", N->getVariable()); + Printer.printMetadata("expr", N->getExpression()); + Out << ")"; +} + static void writeDIObjCProperty(raw_ostream &Out, const DIObjCProperty *N, TypePrinting *TypePrinter, SlotTracker *Machine, const Module *Context) { Index: lib/IR/DIBuilder.cpp =================================================================== --- lib/IR/DIBuilder.cpp +++ lib/IR/DIBuilder.cpp @@ -82,8 +82,13 @@ if (auto *SP = dyn_cast(N)) resolveVariables(SP); - if (!AllGVs.empty()) - CUNode->replaceGlobalVariables(MDTuple::get(VMContext, AllGVs)); + if (!AllGVs.empty()) { + std::vector Elts; + Elts.resize(AllGVs.size()); + for (auto GV : AllGVs) + Elts.push_back(UnwrappedDIGlobalVarExpr(GV)); + CUNode->replaceGlobalVariables(MDTuple::get(VMContext, Elts)); + } if (!AllImportedModules.empty()) CUNode->replaceImportedEntities(MDTuple::get( @@ -534,29 +539,32 @@ #endif } -DIGlobalVariable *DIBuilder::createGlobalVariable( +DIGlobalVarExpr DIBuilder::createGlobalVariable( DIScope *Context, StringRef Name, StringRef LinkageName, DIFile *F, - unsigned LineNumber, DIType *Ty, bool isLocalToUnit, - DIExpression *Expr, MDNode *Decl, uint32_t AlignInBits) { + unsigned LineNumber, DIType *Ty, bool isLocalToUnit, DIExpression *Expr, + MDNode *Decl, uint32_t AlignInBits) { checkGlobalVariableScope(Context); - auto *N = DIGlobalVariable::getDistinct( + auto *GV = DIGlobalVariable::getDistinct( VMContext, cast_or_null(Context), Name, LinkageName, F, - LineNumber, Ty, isLocalToUnit, true, Expr, - cast_or_null(Decl), AlignInBits); + LineNumber, Ty, isLocalToUnit, true, cast_or_null(Decl), + AlignInBits); + auto N = Expr ? DIGlobalVarExpr( + DIGlobalVariableExpression::get(VMContext, GV, Expr)) + : DIGlobalVarExpr(GV); AllGVs.push_back(N); return N; } DIGlobalVariable *DIBuilder::createTempGlobalVariableFwdDecl( DIScope *Context, StringRef Name, StringRef LinkageName, DIFile *F, - unsigned LineNumber, DIType *Ty, bool isLocalToUnit, - DIExpression *Expr, MDNode *Decl, uint32_t AlignInBits) { + unsigned LineNumber, DIType *Ty, bool isLocalToUnit, MDNode *Decl, + uint32_t AlignInBits) { checkGlobalVariableScope(Context); return DIGlobalVariable::getTemporary( VMContext, cast_or_null(Context), Name, LinkageName, F, - LineNumber, Ty, isLocalToUnit, false, Expr, + LineNumber, Ty, isLocalToUnit, false, cast_or_null(Decl), AlignInBits) .release(); } Index: lib/IR/DebugInfo.cpp =================================================================== --- lib/IR/DebugInfo.cpp +++ lib/IR/DebugInfo.cpp @@ -53,10 +53,11 @@ void DebugInfoFinder::processModule(const Module &M) { for (auto *CU : M.debug_compile_units()) { addCompileUnit(CU); - for (auto *DIG : CU->getGlobalVariables()) { + for (auto DIG : CU->getGlobalVariables()) { if (addGlobalVariable(DIG)) { - processScope(DIG->getScope()); - processType(DIG->getType().resolve()); + auto *GV = UnwrappedDIGlobalVarExpr(DIG).getVariable(); + processScope(GV->getScope()); + processType(GV->getType().resolve()); } } for (auto *ET : CU->getEnumTypes()) @@ -206,11 +207,8 @@ return true; } -bool DebugInfoFinder::addGlobalVariable(DIGlobalVariable *DIG) { - if (!DIG) - return false; - - if (!NodesSeen.insert(DIG).second) +bool DebugInfoFinder::addGlobalVariable(DIGlobalVarExpr DIG) { + if (!NodesSeen.insert(UnwrappedDIGlobalVarExpr(DIG)).second) return false; GVs.push_back(DIG); Index: lib/IR/DebugInfoMetadata.cpp =================================================================== --- lib/IR/DebugInfoMetadata.cpp +++ lib/IR/DebugInfoMetadata.cpp @@ -514,18 +514,17 @@ DIGlobalVariable::getImpl(LLVMContext &Context, Metadata *Scope, MDString *Name, MDString *LinkageName, Metadata *File, unsigned Line, Metadata *Type, bool IsLocalToUnit, bool IsDefinition, - Metadata *Variable, Metadata *StaticDataMemberDeclaration, - uint32_t AlignInBits, - StorageType Storage, bool ShouldCreate) { + uint32_t AlignInBits, StorageType Storage, + bool ShouldCreate) { assert(isCanonical(Name) && "Expected canonical MDString"); assert(isCanonical(LinkageName) && "Expected canonical MDString"); DEFINE_GETIMPL_LOOKUP(DIGlobalVariable, (Scope, Name, LinkageName, File, Line, Type, - IsLocalToUnit, IsDefinition, Variable, + IsLocalToUnit, IsDefinition, StaticDataMemberDeclaration, AlignInBits)); - Metadata *Ops[] = {Scope, Name, File, Type, - Name, LinkageName, Variable, StaticDataMemberDeclaration}; + Metadata *Ops[] = { + Scope, Name, File, Type, Name, LinkageName, StaticDataMemberDeclaration}; DEFINE_GETIMPL_STORE(DIGlobalVariable, (Line, IsLocalToUnit, IsDefinition, AlignInBits), Ops); @@ -581,10 +580,17 @@ default: return false; case dwarf::DW_OP_LLVM_fragment: - case dwarf::DW_OP_stack_value: - // We only support fragment and stack value expressions which appear at - // the end. + // A fragment operator must appear at the end. return I->get() + I->getSize() == E->get(); + case dwarf::DW_OP_stack_value: { + // Must be the last one or followed by a DW_OP_LLVM_fragment. + if (I->get() + I->getSize() == E->get()) + break; + auto J = I; + if ((++J)->getOp() != dwarf::DW_OP_LLVM_fragment) + return false; + break; + } case dwarf::DW_OP_constu: case dwarf::DW_OP_plus: case dwarf::DW_OP_minus: @@ -613,6 +619,34 @@ return getElement(getNumElements() - 1); } +bool DIExpression::isConstant() const { + // Recognize DW_OP_constu C DW_OP_stack_value (DW_OP_LLVM_fragment Len Ofs)?. + if (getNumElements() != 3 && getNumElements() != 6) + return false; + if (getElement(0) != dwarf::DW_OP_constu || + getElement(2) != dwarf::DW_OP_stack_value) + return false; + if (getNumElements() == 6 && getElement(3) != dwarf::DW_OP_LLVM_fragment) + return false; + return true; +} + +DIGlobalVariableExpression * +DIGlobalVariableExpression::getImpl(LLVMContext &Context, Metadata *Variable, + Metadata *Expression, StorageType Storage, + bool ShouldCreate) { + DEFINE_GETIMPL_LOOKUP(DIGlobalVariableExpression, (Variable, Expression)); + Metadata *Ops[] = {Variable, Expression}; + DEFINE_GETIMPL_STORE_NO_CONSTRUCTOR_ARGS(DIGlobalVariableExpression, Ops); +} + +DIGlobalVarExpr DIGlobalVarExprArray::operator[](unsigned I) const { + auto *GVU = N->getOperand(I).get(); + if (auto *GV = dyn_cast(GVU)) + return DIGlobalVarExpr(GV); + return DIGlobalVarExpr(cast(GVU)); +} + DIObjCProperty *DIObjCProperty::getImpl( LLVMContext &Context, MDString *Name, Metadata *File, unsigned Line, MDString *GetterName, MDString *SetterName, unsigned Attributes, Index: lib/IR/LLVMContextImpl.h =================================================================== --- lib/IR/LLVMContextImpl.h +++ lib/IR/LLVMContextImpl.h @@ -763,18 +763,16 @@ Metadata *Type; bool IsLocalToUnit; bool IsDefinition; - Metadata *Expr; Metadata *StaticDataMemberDeclaration; uint32_t AlignInBits; MDNodeKeyImpl(Metadata *Scope, MDString *Name, MDString *LinkageName, Metadata *File, unsigned Line, Metadata *Type, bool IsLocalToUnit, bool IsDefinition, - Metadata *Expr, Metadata *StaticDataMemberDeclaration, - uint32_t AlignInBits) + Metadata *StaticDataMemberDeclaration, uint32_t AlignInBits) : Scope(Scope), Name(Name), LinkageName(LinkageName), File(File), Line(Line), Type(Type), IsLocalToUnit(IsLocalToUnit), - IsDefinition(IsDefinition), Expr(Expr), + IsDefinition(IsDefinition), StaticDataMemberDeclaration(StaticDataMemberDeclaration), AlignInBits(AlignInBits) {} MDNodeKeyImpl(const DIGlobalVariable *N) @@ -782,7 +780,6 @@ LinkageName(N->getRawLinkageName()), File(N->getRawFile()), Line(N->getLine()), Type(N->getRawType()), IsLocalToUnit(N->isLocalToUnit()), IsDefinition(N->isDefinition()), - Expr(N->getRawExpr()), StaticDataMemberDeclaration(N->getRawStaticDataMemberDeclaration()), AlignInBits(N->getAlignInBits()) {} @@ -792,7 +789,6 @@ File == RHS->getRawFile() && Line == RHS->getLine() && Type == RHS->getRawType() && IsLocalToUnit == RHS->isLocalToUnit() && IsDefinition == RHS->isDefinition() && - Expr == RHS->getRawExpr() && StaticDataMemberDeclaration == RHS->getRawStaticDataMemberDeclaration() && AlignInBits == RHS->getAlignInBits(); @@ -806,7 +802,7 @@ // generated IR is random for each run and test fails with Align included. // TODO: make hashing work fine with such situations return hash_combine(Scope, Name, LinkageName, File, Line, Type, - IsLocalToUnit, IsDefinition, /* AlignInBits, */ Expr, + IsLocalToUnit, IsDefinition, /* AlignInBits, */ StaticDataMemberDeclaration); } }; @@ -863,6 +859,22 @@ } }; +template <> struct MDNodeKeyImpl { + Metadata *Variable; + Metadata *Expression; + + MDNodeKeyImpl(Metadata *Variable, Metadata *Expression) + : Variable(Variable), Expression(Expression) {} + MDNodeKeyImpl(const DIGlobalVariableExpression *N) + : Variable(N->getRawVariable()), Expression(N->getRawExpression()) {} + + bool isKeyOf(const DIGlobalVariableExpression *RHS) const { + return Variable == RHS->getRawVariable() && + Expression == RHS->getRawExpression(); + } + unsigned getHashValue() const { return hash_combine(Variable, Expression); } +}; + template <> struct MDNodeKeyImpl { MDString *Name; Metadata *File; Index: lib/IR/Metadata.cpp =================================================================== --- lib/IR/Metadata.cpp +++ lib/IR/Metadata.cpp @@ -1419,9 +1419,15 @@ // If an offset adjustment was specified we need to modify the DIExpression // to prepend the adjustment: // !DIExpression(DW_OP_plus, Offset, [original expr]) + auto *Attachment = MD.second; if (Offset != 0 && MD.first == LLVMContext::MD_dbg) { - DIGlobalVariable *GV = cast(MD.second); - DIExpression *E = GV->getExpr(); + DIGlobalVariable *GV = dyn_cast(Attachment); + DIExpression *E = nullptr; + if (!GV) { + auto *GVE = cast(Attachment); + GV = GVE->getVariable(); + E = GVE->getExpression(); + } ArrayRef OrigElements; if (E) OrigElements = E->getElements(); @@ -1429,9 +1435,10 @@ Elements[0] = dwarf::DW_OP_plus; Elements[1] = Offset; std::copy(OrigElements.begin(), OrigElements.end(), Elements.begin() + 2); - GV->replaceExpr(DIExpression::get(getContext(), Elements)); + E = DIExpression::get(getContext(), Elements); + Attachment = DIGlobalVariableExpression::get(getContext(), GV, E); } - addMetadata(MD.first, *MD.second); + addMetadata(MD.first, *Attachment); } } @@ -1452,14 +1459,13 @@ return cast_or_null(getMetadata(LLVMContext::MD_dbg)); } -void GlobalVariable::addDebugInfo(DIGlobalVariable *GV) { - addMetadata(LLVMContext::MD_dbg, *GV); +void GlobalVariable::addDebugInfo(DIGlobalVarExpr GV) { + addMetadata(LLVMContext::MD_dbg, *UnwrappedDIGlobalVarExpr(GV)); } -void GlobalVariable::getDebugInfo( - SmallVectorImpl &GVs) const { +void GlobalVariable::getDebugInfo(SmallVectorImpl &GVs) const { SmallVector MDs; getMetadata(LLVMContext::MD_dbg, MDs); for (MDNode *MD : MDs) - GVs.push_back(cast(MD)); + GVs.push_back(makeDIGlobalVarExpr(MD)); } Index: lib/IR/Verifier.cpp =================================================================== --- lib/IR/Verifier.cpp +++ lib/IR/Verifier.cpp @@ -975,8 +975,9 @@ if (auto *Array = N.getRawGlobalVariables()) { AssertDI(isa(Array), "invalid global variable list", &N, Array); for (Metadata *Op : N.getGlobalVariables()->operands()) { - AssertDI(Op && isa(Op), "invalid global variable ref", - &N, Op); + AssertDI(Op && (isa(Op) || + isa(Op)), + "invalid global variable ref", &N, Op); } } if (auto *Array = N.getRawImportedEntities()) { @@ -1119,8 +1120,6 @@ AssertDI(N.getTag() == dwarf::DW_TAG_variable, "invalid tag", &N); AssertDI(!N.getName().empty(), "missing global variable name", &N); - if (auto *V = N.getRawExpr()) - AssertDI(isa(V), "invalid expression location", &N, V); if (auto *Member = N.getRawStaticDataMemberDeclaration()) { AssertDI(isa(Member), "invalid static data member declaration", &N, Member); @@ -1140,6 +1139,17 @@ AssertDI(N.isValid(), "invalid expression", &N); } +void Verifier::visitDIGlobalVariableExpression( + const DIGlobalVariableExpression &GVE) { + AssertDI(GVE.getVariable(), "missing variable"); + if (auto *Var = GVE.getVariable()) + visitDIGlobalVariable(*Var); + // If the expression is empty the GVE should be canonicalized away. + AssertDI(GVE.getExpression(), "missing expression"); + if (auto *Expr = GVE.getExpression()) + visitDIExpression(*Expr); +} + void Verifier::visitDIObjCProperty(const DIObjCProperty &N) { AssertDI(N.getTag() == dwarf::DW_TAG_APPLE_property, "invalid tag", &N); if (auto *T = N.getRawType()) Index: lib/Transforms/IPO/StripSymbols.cpp =================================================================== --- lib/Transforms/IPO/StripSymbols.cpp +++ lib/Transforms/IPO/StripSymbols.cpp @@ -313,27 +313,31 @@ // replace the current list of potentially dead global variables/functions // with the live list. SmallVector LiveGlobalVariables; - DenseSet VisitedSet; + DenseSet VisitedSet; - std::set LiveGVs; + std::set LiveGVs; for (GlobalVariable &GV : M.globals()) { - SmallVector DIs; - GV.getDebugInfo(DIs); - for (DIGlobalVariable *DI : DIs) - LiveGVs.insert(DI); + SmallVector GVUs; + GV.getDebugInfo(GVUs); + for (auto GVU : GVUs) + LiveGVs.insert(GVU); } for (DICompileUnit *DIC : F.compile_units()) { // Create our live global variable list. bool GlobalVariableChange = false; - for (DIGlobalVariable *DIG : DIC->getGlobalVariables()) { + for (auto DIG : DIC->getGlobalVariables()) { + if (auto *GVE = DIG.dyn_cast()) + if (GVE->getExpression()->isConstant()) + LiveGVs.insert(DIG); + // Make sure we only visit each global variable only once. if (!VisitedSet.insert(DIG).second) continue; // If a global variable references DIG, the global variable is live. if (LiveGVs.count(DIG)) - LiveGlobalVariables.push_back(DIG); + LiveGlobalVariables.push_back(UnwrappedDIGlobalVarExpr(DIG)); else GlobalVariableChange = true; } Index: lib/Transforms/Instrumentation/AddressSanitizer.cpp =================================================================== --- lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -1651,9 +1651,9 @@ // Transfer the debug info. The payload starts at offset zero so we can // copy the debug info over as is. - SmallVector GVs; + SmallVector GVs; G->getDebugInfo(GVs); - for (auto *GV : GVs) + for (auto GV : GVs) NewGlobal->addDebugInfo(GV); Value *Indices2[2]; Index: test/Assembler/diglobalvariable.ll =================================================================== --- test/Assembler/diglobalvariable.ll +++ test/Assembler/diglobalvariable.ll @@ -3,8 +3,8 @@ @foo = global i32 0 -; CHECK: !named = !{!0, !1, !2, !3, !4, !5, !6, !8, !9, !10} -!named = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9} +; CHECK: !named = !{!0, !1, !2, !3, !4, !5, !6, !7, !8} +!named = !{!0, !1, !2, !3, !4, !5, !6, !7, !8} !0 = !DIFile(filename: "scope.h", directory: "/path/to/dir") !1 = distinct !{} @@ -17,12 +17,8 @@ file: !2, line: 7, type: !3, isLocal: true, isDefinition: false, align: 32) -; CHECK: !6 = !DIGlobalVariable(name: "foo", scope: !0, isLocal: false, isDefinition: true, expr: !7) -; CHECK: !7 = !DIExpression(DW_OP_constu, 42, DW_OP_stack_value) -!6 = !DIGlobalVariable(name: "foo", scope: !0, expr: !DIExpression(DW_OP_constu, 42, DW_OP_stack_value)) +!6 = !DICompositeType(tag: DW_TAG_structure_type, name: "Class", size: 8, align: 8) +!7 = !DIDerivedType(tag: DW_TAG_member, name: "mem", flags: DIFlagStaticMember, scope: !6, baseType: !3) -!7 = !DICompositeType(tag: DW_TAG_structure_type, name: "Class", size: 8, align: 8) -!8 = !DIDerivedType(tag: DW_TAG_member, name: "mem", flags: DIFlagStaticMember, scope: !7, baseType: !3) - -; CHECK: !10 = !DIGlobalVariable(name: "mem", scope: !0, isLocal: false, isDefinition: true, declaration: !9) -!9 = !DIGlobalVariable(name: "mem", scope: !0, declaration: !8) +; CHECK: !8 = !DIGlobalVariable(name: "mem", scope: !0, isLocal: false, isDefinition: true, declaration: !7) +!8 = !DIGlobalVariable(name: "mem", scope: !0, declaration: !7) Index: test/Assembler/diglobalvariableexpression.ll =================================================================== --- /dev/null +++ test/Assembler/diglobalvariableexpression.ll @@ -0,0 +1,23 @@ +; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s +; RUN: verify-uselistorder %s + +@foo = global i32 0 + +; CHECK: !named = !{!0, !1, !2, !3, !4, !5, !6, !7} +!named = !{!0, !1, !2, !3, !4, !5, !6, !7} + +!0 = !DIFile(filename: "scope.h", directory: "/path/to/dir") +!1 = distinct !{} +!2 = !DIFile(filename: "path/to/file", directory: "/path/to/dir") +!3 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) +!4 = distinct !{} + +; CHECK: !5 = !DIGlobalVariable(name: "foo", linkageName: "foo", scope: !0, file: !2, line: 7, type: !3, isLocal: true, isDefinition: false, align: 32) +!5 = !DIGlobalVariable(name: "foo", linkageName: "foo", scope: !0, + file: !2, line: 7, type: !3, isLocal: true, + isDefinition: false, align: 32) + +; CHECK: !6 = !DIGlobalVariableExpression(var: !5, expr: !7) +!6 = !DIGlobalVariableExpression(var: !5, expr: !7) +; CHECK: !7 = !DIExpression(DW_OP_constu, 42, DW_OP_stack_value) +!7 = !DIExpression(DW_OP_constu, 42, DW_OP_stack_value) Index: test/Bitcode/DIGlobalVariableExpr.ll =================================================================== --- /dev/null +++ test/Bitcode/DIGlobalVariableExpr.ll @@ -0,0 +1,26 @@ +; RUN: llvm-dis -o - %s.bc | FileCheck %s + +; CHECK: @g = common global i32 0, align 4, !dbg ![[G:[0-9]+]] +; CHECK: ![[G]] = {{.*}}!DIGlobalVariableExpression(var: ![[GVAR:[0-9]+]], expr: ![[GEXPR:[0-9]+]]) +; CHECK: ![[GVAR]] = distinct !DIGlobalVariable(name: "g", +; CHECK: !DIGlobalVariableExpression(var: ![[CVAR:[0-9]+]], expr: ![[CEXPR:[0-9]+]]) +; CHECK: ![[CVAR]] = distinct !DIGlobalVariable(name: "c", +; CHECK: ![[CEXPR]] = !DIExpression(DW_OP_constu, 23, DW_OP_stack_value) +; CHECK: ![[GEXPR]] = !DIExpression(DW_OP_plus, 1) +@g = common global i32 0, align 4, !dbg !0 + +!llvm.dbg.cu = !{!1} +!llvm.module.flags = !{!6, !7, !8} +!llvm.ident = !{!9} + +!0 = distinct !DIGlobalVariable(name: "g", scope: !1, file: !2, line: 1, type: !5, isLocal: false, isDefinition: true, expr: !DIExpression(DW_OP_plus, 1)) +!1 = distinct !DICompileUnit(language: DW_LANG_C99, file: !2, producer: "clang version 4.0.0 (trunk 286129) (llvm/trunk 286128)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !3, globals: !4) +!2 = !DIFile(filename: "a.c", directory: "/") +!3 = !{} +!4 = !{!0, !10} +!5 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!6 = !{i32 2, !"Dwarf Version", i32 4} +!7 = !{i32 2, !"Debug Info Version", i32 3} +!8 = !{i32 1, !"PIC Level", i32 2} +!9 = !{!"clang version 4.0.0 (trunk 286129) (llvm/trunk 286128)"} +!10 = distinct !DIGlobalVariable(name: "c", scope: !1, file: !2, line: 1, type: !5, isLocal: false, isDefinition: true, expr: !DIExpression(DW_OP_constu, 23, DW_OP_stack_value)) Index: test/Bitcode/diglobalvariable-3.8.ll =================================================================== --- test/Bitcode/diglobalvariable-3.8.ll +++ test/Bitcode/diglobalvariable-3.8.ll @@ -1,8 +1,20 @@ ; RUN: llvm-dis -o - %s.bc | FileCheck %s -; CHECK: !0 = distinct !DIGlobalVariable(name: "a", scope: null, isLocal: false, isDefinition: true, expr: !1) -; CHECK: !1 = !DIExpression(DW_OP_constu, 42, DW_OP_stack_value) +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!7, !8} -!named = !{!0} +; CHECK: !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 3.8.1", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3) +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 3.8.1", isOptimized: true, runtimeVersion: 0, emissionKind: 1, enums: !2, globals: !3) +!1 = !DIFile(filename: "g.c", directory: "/") +!2 = !{} +; CHECK: !3 = !{!4} +!3 = !{!4} +; CHECK: !4 = {{.*}}!DIGlobalVariableExpression(var: !5, expr: !8) +; CHECK: !5 = !DIGlobalVariable(name: "c", scope: !0, file: !1, line: 1, type: !6, isLocal: false, isDefinition: true) +; CHECK: !8 = !DIExpression(DW_OP_constu, 42, DW_OP_stack_value) +!4 = !DIGlobalVariable(name: "c", scope: !0, file: !1, line: 1, type: !5, isLocal: false, isDefinition: true, variable: i32 42) +!5 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !6) +!6 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) +!7 = !{i32 2, !"Dwarf Version", i32 2} +!8 = !{i32 2, !"Debug Info Version", i32 3} -!0 = distinct !DIGlobalVariable(name: "a", variable: i32 42) Index: test/DebugInfo/X86/multiple-at-const-val.ll =================================================================== --- test/DebugInfo/X86/multiple-at-const-val.ll +++ test/DebugInfo/X86/multiple-at-const-val.ll @@ -56,7 +56,8 @@ !960 = distinct !DISubprogram(name: "main", line: 73, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: true, unit: !0, scopeLine: 73, file: !1802, scope: null, type: !54, variables: !955) !961 = !DIFile(filename: "student2.cpp", directory: "/privite/tmp") !1786 = !{!1800} -!1800 = !DIGlobalVariable(name: "badbit", linkageName: "badbit", line: 331, isLocal: true, isDefinition: true, scope: !5, file: !5, type: !78, expr: !DIExpression(DW_OP_constu, 1, DW_OP_stack_value), declaration: !77) +!1800 = !DIGlobalVariableExpression(var: !1804, expr: !DIExpression(DW_OP_constu, 1, DW_OP_stack_value)) !1801 = !DIFile(filename: "os_base.h", directory: "/privite/tmp") !1802 = !DIFile(filename: "student2.cpp", directory: "/privite/tmp") !1803 = !{i32 1, !"Debug Info Version", i32 3} +!1804 = distinct !DIGlobalVariable(name: "badbit", linkageName: "badbit", line: 331, isLocal: true, isDefinition: true, scope: !5, file: !5, type: !78, declaration: !77) Index: test/DebugInfo/X86/pr12831.ll =================================================================== --- test/DebugInfo/X86/pr12831.ll +++ test/DebugInfo/X86/pr12831.ll @@ -174,7 +174,7 @@ !126 = distinct !DISubprogram(name: "function >", linkageName: "_ZN8functionIFvvEEC2IZN17BPLFunctionWriter9writeExprEvE3$_0EET_", line: 8, isLocal: true, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !0, scopeLine: 8, file: !6, scope: null, type: !23, templateParams: !47, declaration: !22, variables: !1) !127 = distinct !DISubprogram(name: "_M_not_empty_function >", linkageName: "_ZN13_Base_manager21_M_not_empty_functionIZN17BPLFunctionWriter9writeExprEvE3$_0EEvRKT_", line: 3, isLocal: true, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !0, scopeLine: 3, file: !6, scope: null, type: !117, templateParams: !120, declaration: !116, variables: !1) !128 = !{!130} -!130 = !DIGlobalVariable(name: "__stored_locally", linkageName: "__stored_locally", line: 2, isLocal: true, isDefinition: true, scope: !114, file: !6, type: !131, expr: !DIExpression(DW_OP_constu, 1, DW_OP_stack_value)) +!130 = !DIGlobalVariableExpression(var: !163, expr: !DIExpression(DW_OP_constu, 1, DW_OP_stack_value)) !131 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !132) !132 = !DIBasicType(tag: DW_TAG_base_type, name: "bool", size: 8, align: 8, encoding: DW_ATE_boolean) !133 = !DILocalVariable(name: "this", line: 19, arg: 1, flags: DIFlagArtificial, scope: !5, file: !6, type: !134) @@ -207,3 +207,4 @@ !160 = !DIFile(filename: "BPLFunctionWriter2.ii", directory: "/home/peter/crashdelta") !161 = !DIFile(filename: "BPLFunctionWriter.cpp", directory: "/home/peter/crashdelta") !162 = !{i32 1, !"Debug Info Version", i32 3} +!163 = distinct !DIGlobalVariable(name: "__stored_locally", linkageName: "__stored_locally", line: 2, isLocal: true, isDefinition: true, scope: !114, file: !6, type: !131) Index: test/DebugInfo/X86/split-global.ll =================================================================== --- /dev/null +++ test/DebugInfo/X86/split-global.ll @@ -0,0 +1,49 @@ +; RUN: llc -mtriple=x86_64-apple-darwin %s -o - -filetype=obj | \ +; RUN: llvm-dwarfdump --debug-dump=info - | FileCheck %s +; +; Test emitting debug info for fragmented global values. +; This is a handcrafted example of an SROAed global variable. +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.12.0" + +%struct.anon = type { i32, i32 } + +; CHECK: DW_TAG_variable +; CHECK-NEXT: DW_AT_name {{.*}}"point" +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_location [DW_FORM_exprloc] (<0x18> 03 00 00 00 00 00 00 00 00 93 04 03 04 00 00 00 00 00 00 00 93 04 ) +; [0x0000000000000000], piece 0x00000004, [0x0000000000000004], piece 0x00000004 +; CHECK-NOT: DW_TAG +; CHECK: DW_TAG +; CHECK: DW_TAG_variable +; CHECK-NEXT: DW_AT_name {{.*}}"part_const" +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_location [DW_FORM_exprloc] (<0x10> 03 08 00 00 00 00 00 00 00 93 04 10 02 9f 93 04 ) +; [0x0000000000000008], piece 0x00000004, constu 0x00000002, stack-value, piece 0x00000004 +; CHECK-NOT: DW_TAG +@point.x = global i32 1, align 4, !dbg !12 +@point.y = global i32 2, align 4, !dbg !13 + +@part_const.x = global i32 1, align 4, !dbg !15 + +!llvm.dbg.cu = !{!1} +!llvm.module.flags = !{!10, !11} + +!0 = distinct !DIGlobalVariable(name: "point", scope: !1, file: !2, line: 1, type: !5, isLocal: false, isDefinition: true) +!1 = distinct !DICompileUnit(language: DW_LANG_C99, file: !2, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4) +!2 = !DIFile(filename: "g.c", directory: "/") +!3 = !{} +!4 = !{!12, !13, !14, !15} +!5 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !2, line: 1, size: 64, elements: !6) +!6 = !{!7, !9} +!7 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !5, file: !2, line: 1, baseType: !8, size: 32) +!8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!9 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !5, file: !2, line: 1, baseType: !8, size: 32, offset: 32) +!10 = !{i32 2, !"Dwarf Version", i32 4} +!11 = !{i32 2, !"Debug Info Version", i32 3} +!12 = !DIGlobalVariableExpression(var: !0, expr: !DIExpression(DW_OP_LLVM_fragment, 0, 32)) +!13 = !DIGlobalVariableExpression(var: !0, expr: !DIExpression(DW_OP_LLVM_fragment, 32, 32)) +!14 = !DIGlobalVariableExpression(var: !16, expr: !DIExpression(DW_OP_LLVM_fragment, 0, 32)) +!15 = !DIGlobalVariableExpression(var: !16, expr: !DIExpression(DW_OP_constu, 2, + DW_OP_stack_value, DW_OP_LLVM_fragment, 32, 32)) +!16 = distinct !DIGlobalVariable(name: "part_const", scope: !1, file: !2, line: 1, type: !5, isLocal: false, isDefinition: true) Index: test/DebugInfo/X86/stack-value-dwarf4.ll =================================================================== --- test/DebugInfo/X86/stack-value-dwarf4.ll +++ test/DebugInfo/X86/stack-value-dwarf4.ll @@ -25,13 +25,14 @@ !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, producer: "clang", file: !4, globals: !1, emissionKind: FullDebug) !1 = !{!2} -!2 = distinct !DIGlobalVariable(name: "a", scope: null, isLocal: false, isDefinition: true, expr: !3, type: !5) +!2 = !DIGlobalVariableExpression(var: !8, expr: !3) !3 = !DIExpression(DW_OP_constu, 4, DW_OP_constu, 4, DW_OP_stack_value) !4 = !DIFile(filename: "", directory: "/") !5 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) !6 = !{i32 2, !"Dwarf Version", i32 2} !7 = !{i32 2, !"Debug Info Version", i32 3} +!8 = distinct !DIGlobalVariable(name: "a", scope: null, isLocal: false, isDefinition: true, type: !5) !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!6, !7} Index: test/DebugInfo/X86/unattached-global.ll =================================================================== --- test/DebugInfo/X86/unattached-global.ll +++ test/DebugInfo/X86/unattached-global.ll @@ -5,15 +5,16 @@ ; CHECK: .byte 0 # DW_AT_location -!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, producer: "clang", file: !4, globals: !1, emissionKind: FullDebug) +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, producer: "clang", file: !5, globals: !1, emissionKind: FullDebug) !1 = !{!2} -!2 = distinct !DIGlobalVariable(name: "a", scope: null, isLocal: false, isDefinition: true, expr: !3, type: !5) -!3 = !DIExpression(DW_OP_plus, 4) -!4 = !DIFile(filename: "", directory: "/") -!5 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) +!2 = !DIGlobalVariableExpression(var: !3, expr: !4) +!3 = distinct !DIGlobalVariable(name: "a", scope: null, isLocal: false, isDefinition: true, type: !6) +!4 = !DIExpression(DW_OP_plus, 4) +!5 = !DIFile(filename: "", directory: "/") +!6 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) -!6 = !{i32 2, !"Dwarf Version", i32 2} -!7 = !{i32 2, !"Debug Info Version", i32 3} +!7 = !{i32 2, !"Dwarf Version", i32 2} +!8 = !{i32 2, !"Debug Info Version", i32 3} !llvm.dbg.cu = !{!0} -!llvm.module.flags = !{!6, !7} +!llvm.module.flags = !{!7, !8} Index: test/Transforms/GlobalMerge/debug-info.ll =================================================================== --- test/Transforms/GlobalMerge/debug-info.ll +++ test/Transforms/GlobalMerge/debug-info.ll @@ -15,7 +15,8 @@ } ; CHECK: [[A]] = distinct !DIGlobalVariable(name: "a", scope: null, isLocal: false, isDefinition: true) -; CHECK: [[B]] = distinct !DIGlobalVariable(name: "b", scope: null, isLocal: false, isDefinition: true, expr: [[EXPR:![0-9]+]]) +; CHECK: [[B]] = !DIGlobalVariableExpression(var: [[BVAR:![0-9]+]], expr: [[EXPR:![0-9]+]]) +; CHECK: [[BVAR]] = distinct !DIGlobalVariable(name: "b", scope: null, isLocal: false, isDefinition: true) ; CHECK: [[EXPR]] = !DIExpression(DW_OP_plus, 4) !llvm.module.flags = !{!2, !3} Index: unittests/IR/MetadataTest.cpp =================================================================== --- unittests/IR/MetadataTest.cpp +++ unittests/IR/MetadataTest.cpp @@ -1828,16 +1828,13 @@ DIType *Type = getDerivedType(); bool IsLocalToUnit = false; bool IsDefinition = true; - auto *Expr = DIExpression::get(Context, {1, 2}); - auto *Expr2 = DIExpression::get(Context, {1, 2, 3}); DIDerivedType *StaticDataMemberDeclaration = cast(getDerivedType()); uint32_t AlignInBits = 8; auto *N = DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, IsDefinition, - Expr, StaticDataMemberDeclaration, - AlignInBits); + StaticDataMemberDeclaration, AlignInBits); EXPECT_EQ(dwarf::DW_TAG_variable, N->getTag()); EXPECT_EQ(Scope, N->getScope()); EXPECT_EQ(Name, N->getName()); @@ -1847,68 +1844,88 @@ EXPECT_EQ(Type, N->getType()); EXPECT_EQ(IsLocalToUnit, N->isLocalToUnit()); EXPECT_EQ(IsDefinition, N->isDefinition()); - EXPECT_EQ(Expr, N->getExpr()); EXPECT_EQ(StaticDataMemberDeclaration, N->getStaticDataMemberDeclaration()); EXPECT_EQ(AlignInBits, N->getAlignInBits()); EXPECT_EQ(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, IsDefinition, - Expr, StaticDataMemberDeclaration, - AlignInBits)); + StaticDataMemberDeclaration, AlignInBits)); EXPECT_NE(N, DIGlobalVariable::get(Context, getSubprogram(), Name, LinkageName, File, Line, Type, IsLocalToUnit, IsDefinition, - Expr, StaticDataMemberDeclaration, - AlignInBits)); + StaticDataMemberDeclaration, AlignInBits)); EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, "other", LinkageName, File, Line, Type, IsLocalToUnit, IsDefinition, - Expr, StaticDataMemberDeclaration, - AlignInBits)); + StaticDataMemberDeclaration, AlignInBits)); EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, "other", File, Line, - Type, IsLocalToUnit, IsDefinition, Expr, - StaticDataMemberDeclaration, - AlignInBits)); + Type, IsLocalToUnit, IsDefinition, + StaticDataMemberDeclaration, AlignInBits)); EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, getFile(), - Line, Type, IsLocalToUnit, IsDefinition, Expr, - StaticDataMemberDeclaration, - AlignInBits)); + Line, Type, IsLocalToUnit, IsDefinition, + StaticDataMemberDeclaration, AlignInBits)); EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, Line + 1, Type, IsLocalToUnit, IsDefinition, - Expr, StaticDataMemberDeclaration, - AlignInBits)); + StaticDataMemberDeclaration, AlignInBits)); EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, Line, getDerivedType(), IsLocalToUnit, IsDefinition, - Expr, StaticDataMemberDeclaration, - AlignInBits)); + StaticDataMemberDeclaration, AlignInBits)); EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, Line, Type, !IsLocalToUnit, IsDefinition, - Expr, StaticDataMemberDeclaration, - AlignInBits)); + StaticDataMemberDeclaration, AlignInBits)); EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, !IsDefinition, - Expr, StaticDataMemberDeclaration, - AlignInBits)); + StaticDataMemberDeclaration, AlignInBits)); EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, IsDefinition, - Expr2, StaticDataMemberDeclaration, + cast(getDerivedType()), AlignInBits)); - EXPECT_NE(N, - DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, Line, - Type, IsLocalToUnit, IsDefinition, Expr, - cast(getDerivedType()), - AlignInBits)); EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, IsDefinition, - Expr, StaticDataMemberDeclaration, + StaticDataMemberDeclaration, (AlignInBits << 1))); TempDIGlobalVariable Temp = N->clone(); EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); } +typedef MetadataTest DIGlobalVariableExpressionTest; + +TEST_F(DIGlobalVariableExpressionTest, get) { + DIScope *Scope = getSubprogram(); + StringRef Name = "name"; + StringRef LinkageName = "linkage"; + DIFile *File = getFile(); + unsigned Line = 5; + DIType *Type = getDerivedType(); + bool IsLocalToUnit = false; + bool IsDefinition = true; + auto *Expr = DIExpression::get(Context, {1, 2}); + auto *Expr2 = DIExpression::get(Context, {1, 2, 3}); + DIDerivedType *StaticDataMemberDeclaration = + cast(getDerivedType()); + uint32_t AlignInBits = 8; + + auto *Var = DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, + Line, Type, IsLocalToUnit, IsDefinition, + StaticDataMemberDeclaration, AlignInBits); + auto *Var2 = DIGlobalVariable::get(Context, Scope, "other", LinkageName, File, + Line, Type, IsLocalToUnit, IsDefinition, + StaticDataMemberDeclaration, AlignInBits); + auto *N = DIGlobalVariableExpression::get(Context, Var, Expr); + + EXPECT_EQ(Var, N->getVariable()); + EXPECT_EQ(Expr, N->getExpression()); + EXPECT_EQ(N, DIGlobalVariableExpression::get(Context, Var, Expr)); + EXPECT_NE(N, DIGlobalVariableExpression::get(Context, Var2, Expr)); + EXPECT_NE(N, DIGlobalVariableExpression::get(Context, Var, Expr2)); + + TempDIGlobalVariableExpression Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); +} + typedef MetadataTest DILocalVariableTest; TEST_F(DILocalVariableTest, get) {