diff --git a/llvm/include/llvm-c/DebugInfo.h b/llvm/include/llvm-c/DebugInfo.h --- a/llvm/include/llvm-c/DebugInfo.h +++ b/llvm/include/llvm-c/DebugInfo.h @@ -154,6 +154,7 @@ LLVMDITemplateValueParameterMetadataKind, LLVMDIGlobalVariableMetadataKind, LLVMDILocalVariableMetadataKind, + LLVMDIConstantMetadataKind, LLVMDILabelMetadataKind, LLVMDIObjCPropertyMetadataKind, LLVMDIImportedEntityMetadataKind, diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h --- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -342,8 +342,9 @@ METADATA_STRING_TYPE = 41, // [distinct, name, size, align,...] // Codes 42 and 43 are reserved for support for Fortran array specific debug // info. - METADATA_COMMON_BLOCK = 44, // [distinct, scope, name, variable,...] - METADATA_GENERIC_SUBRANGE = 45 // [distinct, count, lo, up, stride] + METADATA_COMMON_BLOCK = 44, // [distinct, scope, name, variable,...] + METADATA_GENERIC_SUBRANGE = 45, // [distinct, count, lo, up, stride] + METADATA_CONSTANT = 46 }; // The constants block (CONSTANTS_BLOCK_ID) describes emission for each diff --git a/llvm/include/llvm/IR/DIBuilder.h b/llvm/include/llvm/IR/DIBuilder.h --- a/llvm/include/llvm/IR/DIBuilder.h +++ b/llvm/include/llvm/IR/DIBuilder.h @@ -57,6 +57,7 @@ /// Metadata all of type DIMacroNode. /// DIMacroNode's with nullptr parent are DICompileUnit direct children. MapVector> AllMacrosPerParent; + SmallVector AllConstants; /// Track nodes that may be unresolved. SmallVector UnresolvedNodes; @@ -183,6 +184,19 @@ /// Create a single enumerator value. DIEnumerator *createEnumerator(StringRef Name, int64_t Val, bool IsUnsigned = false); + /// Create a named constant value. + /// \param Scope Scope of the Constant. + /// \param Name Name of the Constant. + /// \param File File descriptor containing the Constant. + /// \param Line Source Line number where the Constant is declared. + /// \param Type Type of the Constant, (Only 64-bit Signed Integer + /// supported for now). \param IsLocalToUnit Local to Current CU. \param + /// IsDefinition Declaration or Definition. \param Val Value of + /// the Constant. + DIConstant *createConstant(DIScope *Scope, StringRef Name, DIFile *File, + unsigned Line, DIType *Type, bool IsLocalToUnit, + bool IsDefinition, int64_t Val); + /// Create a DWARF unspecified type. DIBasicType *createUnspecifiedType(StringRef Name); diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h --- a/llvm/include/llvm/IR/DebugInfoMetadata.h +++ b/llvm/include/llvm/IR/DebugInfoMetadata.h @@ -197,6 +197,7 @@ case DITemplateValueParameterKind: case DIGlobalVariableKind: case DILocalVariableKind: + case DIConstantKind: case DILabelKind: case DIObjCPropertyKind: case DIImportedEntityKind: @@ -1367,7 +1368,8 @@ DIImportedEntityArray ImportedEntities, DIMacroNodeArray Macros, uint64_t DWOId, bool SplitDebugInlining, bool DebugInfoForProfiling, unsigned NameTableKind, bool RangesBaseAddress, StringRef SysRoot, - StringRef SDK, StorageType Storage, bool ShouldCreate = true) { + StringRef SDK, DINodeArray Constants, StorageType Storage, + bool ShouldCreate = true) { return getImpl( Context, SourceLanguage, File, getCanonicalMDString(Context, Producer), IsOptimized, getCanonicalMDString(Context, Flags), RuntimeVersion, @@ -1376,7 +1378,8 @@ ImportedEntities.get(), Macros.get(), DWOId, SplitDebugInlining, DebugInfoForProfiling, NameTableKind, RangesBaseAddress, getCanonicalMDString(Context, SysRoot), - getCanonicalMDString(Context, SDK), Storage, ShouldCreate); + getCanonicalMDString(Context, SDK), Constants.get(), Storage, + ShouldCreate); } static DICompileUnit * getImpl(LLVMContext &Context, unsigned SourceLanguage, Metadata *File, @@ -1387,7 +1390,7 @@ Metadata *Macros, uint64_t DWOId, bool SplitDebugInlining, bool DebugInfoForProfiling, unsigned NameTableKind, bool RangesBaseAddress, MDString *SysRoot, MDString *SDK, - StorageType Storage, bool ShouldCreate = true); + Metadata *Constants, StorageType Storage, bool ShouldCreate = true); TempDICompileUnit cloneImpl() const { return getTemporary( @@ -1396,7 +1399,7 @@ getEmissionKind(), getEnumTypes(), getRetainedTypes(), getGlobalVariables(), getImportedEntities(), getMacros(), DWOId, getSplitDebugInlining(), getDebugInfoForProfiling(), getNameTableKind(), - getRangesBaseAddress(), getSysRoot(), getSDK()); + getRangesBaseAddress(), getSysRoot(), getSDK(), getConstants()); } public: @@ -1413,12 +1416,12 @@ DIImportedEntityArray ImportedEntities, DIMacroNodeArray Macros, uint64_t DWOId, bool SplitDebugInlining, bool DebugInfoForProfiling, DebugNameTableKind NameTableKind, bool RangesBaseAddress, - StringRef SysRoot, StringRef SDK), + StringRef SysRoot, StringRef SDK, DINodeArray Constants), (SourceLanguage, File, Producer, IsOptimized, Flags, RuntimeVersion, SplitDebugFilename, EmissionKind, EnumTypes, RetainedTypes, GlobalVariables, ImportedEntities, Macros, DWOId, SplitDebugInlining, DebugInfoForProfiling, (unsigned)NameTableKind, RangesBaseAddress, - SysRoot, SDK)) + SysRoot, SDK, Constants)) DEFINE_MDNODE_GET_DISTINCT_TEMPORARY( DICompileUnit, (unsigned SourceLanguage, Metadata *File, MDString *Producer, @@ -1428,11 +1431,12 @@ Metadata *ImportedEntities, Metadata *Macros, uint64_t DWOId, bool SplitDebugInlining, bool DebugInfoForProfiling, unsigned NameTableKind, bool RangesBaseAddress, MDString *SysRoot, - MDString *SDK), + MDString *SDK, Metadata *Constants), (SourceLanguage, File, Producer, IsOptimized, Flags, RuntimeVersion, SplitDebugFilename, EmissionKind, EnumTypes, RetainedTypes, GlobalVariables, ImportedEntities, Macros, DWOId, SplitDebugInlining, - DebugInfoForProfiling, NameTableKind, RangesBaseAddress, SysRoot, SDK)) + DebugInfoForProfiling, NameTableKind, RangesBaseAddress, SysRoot, SDK, + Constants)) TempDICompileUnit clone() const { return cloneImpl(); } @@ -1468,6 +1472,9 @@ DIMacroNodeArray getMacros() const { return cast_or_null(getRawMacros()); } + DINodeArray getConstants() const { + return cast_or_null(getRawConstants()); + } uint64_t getDWOId() const { return DWOId; } void setDWOId(uint64_t DwoId) { DWOId = DwoId; } bool getSplitDebugInlining() const { return SplitDebugInlining; } @@ -1489,6 +1496,7 @@ Metadata *getRawMacros() const { return getOperand(8); } MDString *getRawSysRoot() const { return getOperandAs(9); } MDString *getRawSDK() const { return getOperandAs(10); } + Metadata *getRawConstants() const { return getOperand(11); } /// Replace arrays. /// @@ -1509,6 +1517,7 @@ replaceOperandWith(7, N.get()); } void replaceMacros(DIMacroNodeArray N) { replaceOperandWith(8, N.get()); } + void replaceConstants(DINodeArray N) { replaceOperandWith(11, N.get()); } /// @} static bool classof(const Metadata *MD) { @@ -3093,6 +3102,80 @@ } }; +/// Represents a named constant in the programming language, for example a +/// parameter construct in Fortran. +class DIConstant : public DINode { + friend class LLVMContextImpl; + friend class MDNode; + + unsigned Line; + bool IsLocalToUnit; + bool IsDefinition; + APInt Value; + + DIConstant(LLVMContext &C, StorageType Storage, unsigned Line, + bool IsLocalToUnit, bool IsDefinition, const APInt &Value, + ArrayRef Ops) + : DINode(C, DIConstantKind, Storage, dwarf::DW_TAG_constant, Ops), + Line(Line), IsLocalToUnit(IsLocalToUnit), IsDefinition(IsDefinition), + Value(Value) {} + ~DIConstant() = default; + + static DIConstant *getImpl(LLVMContext &Context, DIScope *Scope, + StringRef Name, DIFile *File, unsigned Line, + DIType *Type, bool IsLocalToUnit, + bool IsDefinition, const APInt &Value, + StorageType Storage, bool ShouldCreate = true) { + return getImpl(Context, Scope, getCanonicalMDString(Context, Name), File, + Line, Type, IsLocalToUnit, IsDefinition, Value, Storage, + ShouldCreate); + } + static DIConstant *getImpl(LLVMContext &Context, Metadata *Scope, + MDString *Name, Metadata *File, unsigned Line, + Metadata *Type, bool IsLocalToUnit, + bool IsDefinition, const APInt &Value, + StorageType Storage, bool ShouldCreate = true); + + TempDIConstant cloneImpl() const { + return getTemporary(getContext(), getScope(), getName(), getFile(), + getLine(), getType(), isLocalToUnit(), isDefinition(), + getValue()); + } + +public: + DEFINE_MDNODE_GET(DIConstant, + (DIScope * Scope, StringRef Name, DIFile *File, + unsigned Line, DIType *Type, bool IsLocalToUnit, + bool IsDefinition, APInt Value), + (Scope, Name, File, Line, Type, IsLocalToUnit, IsDefinition, + Value)) + DEFINE_MDNODE_GET(DIConstant, + (Metadata * Scope, MDString *Name, Metadata *File, + unsigned Line, Metadata *Type, bool IsLocalToUnit, + bool IsDefinition, APInt Value), + (Scope, Name, File, Line, Type, IsLocalToUnit, IsDefinition, + Value)) + + TempDIConstant clone() const { return cloneImpl(); } + + unsigned getLine() const { return Line; } + bool isLocalToUnit() const { return IsLocalToUnit; } + bool isDefinition() const { return IsDefinition; } + const APInt &getValue() const { return Value; } + DIScope *getScope() const { return cast_or_null(getRawScope()); } + StringRef getName() const { return getStringOperand(1); } + DIFile *getFile() const { return cast_or_null(getRawFile()); } + DIType *getType() const { return cast_or_null(getRawType()); } + + Metadata *getRawScope() const { return getOperand(0); } + MDString *getRawName() const { return getOperandAs(1); } + Metadata *getRawFile() const { return getOperand(2); } + Metadata *getRawType() const { return getOperand(3); } + static bool classof(const Metadata *MD) { + return MD->getMetadataID() == DIConstantKind; + } +}; + /// Label. /// class DILabel : public DINode { diff --git a/llvm/include/llvm/IR/Metadata.def b/llvm/include/llvm/IR/Metadata.def --- a/llvm/include/llvm/IR/Metadata.def +++ b/llvm/include/llvm/IR/Metadata.def @@ -107,6 +107,7 @@ HANDLE_SPECIALIZED_MDNODE_BRANCH(DIVariable) HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIGlobalVariable) HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DILocalVariable) +HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIConstant) HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DILabel) HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIObjCProperty) HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIImportedEntity) diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -4955,7 +4955,8 @@ OPTIONAL(nameTableKind, NameTableKindField, ); \ OPTIONAL(rangesBaseAddress, MDBoolField, = false); \ OPTIONAL(sysroot, MDStringField, ); \ - OPTIONAL(sdk, MDStringField, ); + OPTIONAL(sdk, MDStringField, ); \ + OPTIONAL(constants, MDField, ); PARSE_MD_FIELDS(); #undef VISIT_MD_FIELDS @@ -4964,7 +4965,7 @@ runtimeVersion.Val, splitDebugFilename.Val, emissionKind.Val, enums.Val, retainedTypes.Val, globals.Val, imports.Val, macros.Val, dwoId.Val, splitDebugInlining.Val, debugInfoForProfiling.Val, nameTableKind.Val, - rangesBaseAddress.Val, sysroot.Val, sdk.Val); + rangesBaseAddress.Val, sysroot.Val, sdk.Val, constants.Val); return false; } @@ -5233,6 +5234,28 @@ return false; } +bool LLParser::parseDIConstant(MDNode *&Result, bool IsDistinct) { +#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \ + REQUIRED(scope, MDField, (/* AllowNull */ false)); \ + OPTIONAL(name, MDStringField, ); \ + OPTIONAL(file, MDField, ); \ + OPTIONAL(line, LineField, ); \ + OPTIONAL(type, MDField, ); \ + OPTIONAL(isLocal, MDBoolField, ); \ + OPTIONAL(isDefinition, MDBoolField, (true)); \ + OPTIONAL(value, MDAPSIntField, ); + PARSE_MD_FIELDS(); +#undef VISIT_MD_FIELDS + APSInt Value(value.Val); + if (value.Val.isUnsigned() && value.Val.isSignBitSet()) + Value = Value.zext(Value.getBitWidth() + 1); + + Result = GET_OR_DISTINCT(DIConstant, + (Context, scope.Val, name.Val, file.Val, line.Val, + type.Val, isLocal.Val, isDefinition.Val, Value)); + return false; +} + /// parseDILabel: /// ::= !DILabel(scope: !0, name: "foo", file: !1, line: 7) bool LLParser::parseDILabel(MDNode *&Result, bool IsDistinct) { diff --git a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp --- a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp +++ b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp @@ -876,6 +876,7 @@ case bitc::METADATA_IMPORTED_ENTITY: case bitc::METADATA_GLOBAL_VAR_EXPR: case bitc::METADATA_GENERIC_SUBRANGE: + case bitc::METADATA_CONSTANT: // We don't expect to see any of these, if we see one, give up on // lazy-loading and fallback. MDStringRef.clear(); @@ -1609,7 +1610,7 @@ break; } case bitc::METADATA_COMPILE_UNIT: { - if (Record.size() < 14 || Record.size() > 22) + if (Record.size() < 14 || Record.size() > 23) return error("Invalid record"); // Ignore Record[0], which indicates whether this compile unit is @@ -1627,7 +1628,8 @@ Record.size() <= 18 ? 0 : Record[18], Record.size() <= 19 ? 0 : Record[19], Record.size() <= 20 ? nullptr : getMDString(Record[20]), - Record.size() <= 21 ? nullptr : getMDString(Record[21])); + Record.size() <= 21 ? nullptr : getMDString(Record[21]), + Record.size() <= 22 ? nullptr : getMDOrNull(Record[22])); MetadataList.assignValue(CU, NextMetadataNo); NextMetadataNo++; @@ -2005,6 +2007,24 @@ NextMetadataNo++; break; } + case bitc::METADATA_CONSTANT: { + if (Record.size() != 9) + return error("Invalid record"); + + APInt Value; + Value = APInt(64, unrotateSign(Record[8]), true /*Signed*/); + LLVM_DEBUG(dbgs() << "Constant Value: "; Value.dump()); + IsDistinct = Record[0]; + MetadataList.assignValue( + GET_OR_DISTINCT(DIConstant, + (Context, getMDOrNull(Record[1]), + getMDString(Record[2]), getMDOrNull(Record[3]), + Record[4], getMDOrNull(Record[5]), Record[6], + Record[7], Value)), + NextMetadataNo); + NextMetadataNo++; + break; + } case bitc::METADATA_OBJC_PROPERTY: { if (Record.size() != 8) return error("Invalid record"); diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -348,6 +348,8 @@ unsigned Abbrev); void writeDILocalVariable(const DILocalVariable *N, SmallVectorImpl &Record, unsigned Abbrev); + void writeDIConstant(const DIConstant *N, SmallVectorImpl &Record, + unsigned Abbrev); void writeDILabel(const DILabel *N, SmallVectorImpl &Record, unsigned Abbrev); void writeDIExpression(const DIExpression *N, @@ -1758,6 +1760,7 @@ Record.push_back(N->getRangesBaseAddress()); Record.push_back(VE.getMetadataOrNullID(N->getRawSysRoot())); Record.push_back(VE.getMetadataOrNullID(N->getRawSDK())); + Record.push_back(VE.getMetadataOrNullID(N->getConstants().get())); Stream.EmitRecord(bitc::METADATA_COMPILE_UNIT, Record, Abbrev); Record.clear(); @@ -1958,6 +1961,23 @@ Record.clear(); } +void ModuleBitcodeWriter::writeDIConstant(const DIConstant *N, + SmallVectorImpl &Record, + unsigned Abbrev) { + Record.push_back((uint64_t)N->isDistinct()); + Record.push_back(VE.getMetadataOrNullID(N->getScope())); + Record.push_back(VE.getMetadataOrNullID(N->getRawName())); + Record.push_back(VE.getMetadataOrNullID(N->getFile())); + Record.push_back(N->getLine()); + Record.push_back(VE.getMetadataOrNullID(N->getType())); + Record.push_back(N->isLocalToUnit()); + Record.push_back(N->isDefinition()); + emitWideAPInt(Record, N->getValue()); + + Stream.EmitRecord(bitc::METADATA_CONSTANT, Record, Abbrev); + Record.clear(); +} + void ModuleBitcodeWriter::writeDILabel( const DILabel *N, SmallVectorImpl &Record, unsigned Abbrev) { diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h @@ -152,6 +152,8 @@ DIE *getOrCreateCommonBlock(const DICommonBlock *CB, ArrayRef GlobalExprs); + DIE *getOrCreateConstantDIE(const DIConstant *C); + void addLocationAttribute(DIE *ToDIE, const DIGlobalVariable *GV, ArrayRef GlobalExprs); diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -134,6 +134,34 @@ File->getSource(), CUID); } +DIE *DwarfCompileUnit::getOrCreateConstantDIE(const DIConstant *C) { + // Check for pre-existence. + if (DIE *Die = getDIE(C)) + return Die; + + assert(C); + + auto *CContext = C->getScope(); + const DIType *CTy = C->getType(); + + DIE *ContextDIE = getOrCreateContextDIE(CContext); + // Add to map. + DIE *ConstantDIE = &createAndAddDIE(C->getTag(), *ContextDIE, C); + // Add name and type. + addString(*ConstantDIE, dwarf::DW_AT_name, C->getName()); + addSourceLine(*ConstantDIE, C); + addType(*ConstantDIE, CTy); + // Add scoping info. + if (!C->isLocalToUnit()) + addFlag(*ConstantDIE, dwarf::DW_AT_external); + if (C->isDefinition()) + addConstantValue(*ConstantDIE, C->getValue(), CTy); + else + addFlag(*ConstantDIE, dwarf::DW_AT_declaration); + + return ConstantDIE; +} + DIE *DwarfCompileUnit::getOrCreateGlobalVariableDIE( const DIGlobalVariable *GV, ArrayRef GlobalExprs) { // Check for pre-existence. diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -1209,7 +1209,8 @@ if (!HasNonLocalImportedEntities && CUNode->getEnumTypes().empty() && CUNode->getRetainedTypes().empty() && - CUNode->getGlobalVariables().empty() && CUNode->getMacros().empty()) + CUNode->getGlobalVariables().empty() && CUNode->getMacros().empty() && + CUNode->getConstants().empty()) continue; DwarfCompileUnit &CU = getOrCreateDwarfCompileUnit(CUNode); @@ -1243,6 +1244,9 @@ // There is no point in force-emitting a forward declaration. CU.getOrCreateTypeDIE(RT); } + for (auto *CS : CUNode->getConstants()) { + CU.getOrCreateConstantDIE(cast(CS)); + } // Emit imported_modules last so that the relevant context is already // available. for (auto *IE : CUNode->getImportedEntities()) diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h --- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h @@ -185,6 +185,7 @@ /// Add location information to specified debug information entry. void addSourceLine(DIE &Die, unsigned Line, const DIFile *File); + void addSourceLine(DIE &Die, const DIConstant *C); void addSourceLine(DIE &Die, const DILocalVariable *V); void addSourceLine(DIE &Die, const DIGlobalVariable *G); void addSourceLine(DIE &Die, const DISubprogram *SP); diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp --- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -425,6 +425,12 @@ addUInt(Die, dwarf::DW_AT_decl_line, None, Line); } +void DwarfUnit::addSourceLine(DIE &Die, const DIConstant *C) { + assert(C); + + addSourceLine(Die, C->getLine(), C->getFile()); +} + void DwarfUnit::addSourceLine(DIE &Die, const DILocalVariable *V) { assert(V); diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -2130,6 +2130,7 @@ Printer.printBool("rangesBaseAddress", N->getRangesBaseAddress(), false); Printer.printString("sysroot", N->getSysRoot()); Printer.printString("sdk", N->getSDK()); + Printer.printMetadata("constants", N->getRawConstants()); Out << ")"; } @@ -2314,6 +2315,22 @@ Out << ")"; } +static void writeDIConstant(raw_ostream &Out, const DIConstant *N, + TypePrinting *TypePrinter, SlotTracker *Machine, + const Module *Context) { + Out << "!DIConstant("; + MDFieldPrinter Printer(Out, TypePrinter, Machine, Context); + Printer.printString("name", N->getName()); + Printer.printMetadata("scope", N->getRawScope(), /* ShouldSkipNull */ false); + Printer.printMetadata("file", N->getRawFile()); + Printer.printInt("line", N->getLine()); + Printer.printMetadata("type", N->getRawType()); + Printer.printBool("isLocal", N->isLocalToUnit()); + Printer.printBool("isDefinition", N->isDefinition()); + Printer.printAPInt("value", N->getValue(), false, false); + Out << ")"; +} + static void writeDILabel(raw_ostream &Out, const DILabel *N, TypePrinting *TypePrinter, SlotTracker *Machine, const Module *Context) { diff --git a/llvm/lib/IR/DIBuilder.cpp b/llvm/lib/IR/DIBuilder.cpp --- a/llvm/lib/IR/DIBuilder.cpp +++ b/llvm/lib/IR/DIBuilder.cpp @@ -74,6 +74,7 @@ } CUNode->replaceEnumTypes(MDTuple::get(VMContext, AllEnumTypes)); + CUNode->replaceConstants(MDTuple::get(VMContext, AllConstants)); SmallVector RetainValues; // Declarations and definitions of the same type may be retained. Some @@ -152,7 +153,7 @@ VMContext, Lang, File, Producer, isOptimized, Flags, RunTimeVer, SplitName, Kind, nullptr, nullptr, nullptr, nullptr, nullptr, DWOId, SplitDebugInlining, DebugInfoForProfiling, NameTableKind, - RangesBaseAddress, SysRoot, SDK); + RangesBaseAddress, SysRoot, SDK, nullptr); // Create a named metadata so that it is easier to find cu in a module. NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.dbg.cu"); @@ -250,6 +251,17 @@ Name); } +DIConstant *DIBuilder::createConstant(DIScope *Scope, StringRef Name, + DIFile *File, unsigned Line, DIType *Type, + bool IsLocalToUnit, bool IsDefinition, + int64_t Val) { + assert(Scope && "Unable to create constant without scope"); + assert(!Name.empty() && "Unable to create constant without name"); + return DIConstant::get(VMContext, Scope, Name, File, Line, Type, + IsLocalToUnit, IsDefinition, + APInt(64, Val, true /*Signed*/)); +} + DIBasicType *DIBuilder::createUnspecifiedType(StringRef Name) { assert(!Name.empty() && "Unable to create type without name"); return DIBasicType::get(VMContext, dwarf::DW_TAG_unspecified_type, Name); diff --git a/llvm/lib/IR/DebugInfo.cpp b/llvm/lib/IR/DebugInfo.cpp --- a/llvm/lib/IR/DebugInfo.cpp +++ b/llvm/lib/IR/DebugInfo.cpp @@ -492,7 +492,8 @@ RetainedTypes, GlobalVariables, ImportedEntities, CU->getMacros(), CU->getDWOId(), CU->getSplitDebugInlining(), CU->getDebugInfoForProfiling(), CU->getNameTableKind(), - CU->getRangesBaseAddress(), CU->getSysRoot(), CU->getSDK()); + CU->getRangesBaseAddress(), CU->getSysRoot(), CU->getSDK(), + CU->getConstants()); } DILocation *getReplacementMDLocation(DILocation *MLD) { diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp --- a/llvm/lib/IR/DebugInfoMetadata.cpp +++ b/llvm/lib/IR/DebugInfoMetadata.cpp @@ -728,7 +728,8 @@ Metadata *GlobalVariables, Metadata *ImportedEntities, Metadata *Macros, uint64_t DWOId, bool SplitDebugInlining, bool DebugInfoForProfiling, unsigned NameTableKind, bool RangesBaseAddress, MDString *SysRoot, - MDString *SDK, StorageType Storage, bool ShouldCreate) { + MDString *SDK, Metadata *Constants, StorageType Storage, + bool ShouldCreate) { assert(Storage != Uniqued && "Cannot unique DICompileUnit"); assert(isCanonical(Producer) && "Expected canonical MDString"); assert(isCanonical(Flags) && "Expected canonical MDString"); @@ -744,7 +745,8 @@ ImportedEntities, Macros, SysRoot, - SDK}; + SDK, + Constants}; return storeImpl(new (array_lengthof(Ops)) DICompileUnit( Context, Storage, SourceLanguage, IsOptimized, RuntimeVersion, EmissionKind, DWOId, SplitDebugInlining, @@ -1000,6 +1002,20 @@ DEFINE_GETIMPL_STORE(DILocalVariable, (Line, Arg, Flags, AlignInBits), Ops); } +DIConstant *DIConstant::getImpl(LLVMContext &Context, Metadata *Scope, + MDString *Name, Metadata *File, unsigned Line, + Metadata *Type, bool IsLocalToUnit, + bool IsDefinition, const APInt &Value, + StorageType Storage, bool ShouldCreate) { + assert(Scope && "Expected scope"); + assert(isCanonical(Name) && "Expected canonical MDString"); + DEFINE_GETIMPL_LOOKUP(DIConstant, (Scope, Name, File, Line, Type, + IsLocalToUnit, IsDefinition, Value)); + Metadata *Ops[] = {Scope, Name, File, Type}; + DEFINE_GETIMPL_STORE(DIConstant, (Line, IsLocalToUnit, IsDefinition, Value), + Ops); +} + Optional DIVariable::getSizeInBits() const { // This is used by the Verifier so be mindful of broken types. const Metadata *RawType = getRawType(); diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h --- a/llvm/lib/IR/LLVMContextImpl.h +++ b/llvm/lib/IR/LLVMContextImpl.h @@ -1061,6 +1061,41 @@ } }; +template <> struct MDNodeKeyImpl { + Metadata *Scope; + MDString *Name; + Metadata *File; + unsigned Line; + Metadata *Type; + bool IsLocalToUnit; + bool IsDefinition; + APInt Value; + + MDNodeKeyImpl(Metadata *Scope, MDString *Name, Metadata *File, unsigned Line, + Metadata *Type, bool IsLocalToUnit, bool IsDefinition, + APInt Value) + : Scope(Scope), Name(Name), File(File), Line(Line), Type(Type), + IsLocalToUnit(IsLocalToUnit), IsDefinition(IsDefinition), Value(Value) { + } + MDNodeKeyImpl(const DIConstant *N) + : Scope(N->getRawScope()), Name(N->getRawName()), File(N->getRawFile()), + Line(N->getLine()), Type(N->getRawType()), + IsLocalToUnit(N->isLocalToUnit()), IsDefinition(N->isDefinition()), + Value(N->getValue()) {} + + bool isKeyOf(const DIConstant *RHS) const { + return Scope == RHS->getRawScope() && Name == RHS->getRawName() && + File == RHS->getRawFile() && Line == RHS->getLine() && + Type == RHS->getRawType() && IsLocalToUnit == RHS->isLocalToUnit() && + IsDefinition == RHS->isDefinition(); + } + + unsigned getHashValue() const { + return hash_combine(Scope, Name, File, Line, Type, IsLocalToUnit, + IsDefinition); + } +}; + template <> struct MDNodeKeyImpl { Metadata *Scope; MDString *Name; diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -1361,6 +1361,16 @@ AssertDI(!isa(Ty), "invalid type", &N, N.getType()); } +void Verifier::visitDIConstant(const DIConstant &N) { + + AssertDI(isType(N.getRawType()), "invalid type ref", &N, N.getRawType()); + AssertDI(N.getTag() == dwarf::DW_TAG_constant, "invalid tag", &N); + AssertDI(N.getRawScope() && isa(N.getRawScope()), + "constant requires a valid scope", &N, N.getRawScope()); + if (auto Ty = N.getType()) + AssertDI(!isa(Ty), "invalid type", &N, N.getType()); +} + void Verifier::visitDILabel(const DILabel &N) { if (auto *S = N.getRawScope()) AssertDI(isa(S), "invalid scope", &N, S); diff --git a/llvm/test/Assembler/diconstant.ll b/llvm/test/Assembler/diconstant.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Assembler/diconstant.ll @@ -0,0 +1,32 @@ +; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s + +; CHECK-DAG: ![[MODULE_SCOPE:.*]] = !DIModule +; CHECK-DAG: ![[SUBPROGRAM_SCOPE:.*]] = distinct !DISubprogram +; CHECK-DAG: !{{.*}} = !DIConstant(name: "local_constant", scope: ![[SUBPROGRAM_SCOPE]], file: !3, line: 10, type: !{{.*}}, isLocal: true, isDefinition: true, value: 42) +; CHECK-DAG: !{{.*}} = !DIConstant(name: "module_constant", scope: ![[MODULE_SCOPE]], file: !3, line: 4, type: !{{.*}}, isLocal: false, isDefinition: true, value: 24) + +!llvm.module.flags = !{!16, !17} +!llvm.dbg.cu = !{!4} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "foo", linkageName: "_dummy_0_", scope: !2, file: !3, line: 2, type: !14, isLocal: false, isDefinition: true) +!2 = !DIModule(scope: !4, name: "dummy", file: !3, line: 1) +!3 = !DIFile(filename: "fortran-constant.f90", directory: "/home/sourabh/work/dwarf/fortran") +!4 = distinct !DICompileUnit(language: DW_LANG_Fortran90, file: !3, producer: " F90 Flang - 1.5 2017-05-01", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !5, retainedTypes: !5, globals: !6, imports: !7, nameTableKind: None, constants: !12) +!5 = !{} +!6 = !{!0} +!7 = !{!8} +!8 = !DIImportedEntity(tag: DW_TAG_imported_module, scope: !9, entity: !2, file: !3, line: 9) +!9 = distinct !DISubprogram(name: "main", scope: !4, file: !3, line: 9, type: !10, scopeLine: 9, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagMainSubprogram, unit: !4) +!10 = !DISubroutineType(cc: DW_CC_program, types: !11) +!11 = !{null} +!12 = !{!13, !15} +!13 = !DIConstant(name: "local_constant", scope: !9, file: !3, line: 10, type: !14, isLocal: true, isDefinition: true, value: 42) +!14 = !DIBasicType(name: "integer", size: 32, align: 32, encoding: DW_ATE_signed) +!15 = !DIConstant(name: "module_constant", scope: !2, file: !3, line: 4, type: !14, isLocal: false, isDefinition: true, value: 24) +!16 = !{i32 2, !"Dwarf Version", i32 4} +!17 = !{i32 2, !"Debug Info Version", i32 3} +!18 = !DILocation(line: 12, column: 1, scope: !9) +!19 = distinct !DILocalVariable(scope: !9, file: !3, line: 12, type: !14, flags: DIFlagArtificial) +!20 = !DILocation(line: 0, scope: !9) +!21 = !DILocation(line: 13, column: 1, scope: !9) diff --git a/llvm/test/Bindings/llvm-c/debug_info.ll b/llvm/test/Bindings/llvm-c/debug_info.ll --- a/llvm/test/Bindings/llvm-c/debug_info.ll +++ b/llvm/test/Bindings/llvm-c/debug_info.ll @@ -24,7 +24,7 @@ ; CHECK-NEXT: !FooType = !{!28} ; CHECK-NEXT: !EnumTest = !{!3} -; CHECK: !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "llvm-c-test", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !11, imports: !19, macros: !23, splitDebugInlining: false, sysroot: "/") +; CHECK: !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "llvm-c-test", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !11, imports: !19, macros: !23, splitDebugInlining: false, sysroot: "/", constants: !15) ; CHECK-NEXT: !1 = !DIFile(filename: "debuginfo.c", directory: ".") ; CHECK-NEXT: !2 = !{!3} ; CHECK-NEXT: !3 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "EnumTest", scope: !4, file: !1, baseType: !6, size: 64, elements: !7) diff --git a/llvm/test/DebugInfo/fortran-parameter.ll b/llvm/test/DebugInfo/fortran-parameter.ll new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/fortran-parameter.ll @@ -0,0 +1,58 @@ +; RUN: %llc_dwarf -filetype=obj %s -o - | llvm-dwarfdump - | FileCheck %s + +;; This test check DebugInfo for fortran constants. +;; Fortran code snip: +;; ``` +;; module dummy +;; integer :: foo +;; integer, parameter:: module_constant = 24 +;; end module dummy +;; program main +;; use dummy +;; integer, parameter :: local_constant = 42 +;; print*, module_constant, local_constant +;; end +;; ``` + +; CHECK-LABEL: DW_TAG_module +; CHECK: DW_TAG_constant +; CHECK: DW_AT_name ("module_constant") +; CHECK: DW_AT_decl_file +; CHECK: DW_AT_decl_line (4) +; CHECK: DW_AT_type ({{.*}} "integer") +; CHECK: DW_AT_external (true) +; CHECK: DW_AT_const_value (24) + +; CHECK-LABEL: DW_TAG_subprogram +; CHECK: DW_TAG_constant +; CHECK: DW_AT_name ("local_constant") +; CHECK: DW_AT_decl_file +; CHECK: DW_AT_decl_line (10) +; CHECK: DW_AT_type ({{.*}} "integer") +; CHECK: DW_AT_const_value (42) + +!llvm.module.flags = !{!16, !17} +!llvm.dbg.cu = !{!4} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "foo", linkageName: "_dummy_0_", scope: !2, file: !3, line: 2, type: !14, isLocal: false, isDefinition: true) +!2 = !DIModule(scope: !4, name: "dummy", file: !3, line: 1) +!3 = !DIFile(filename: "fortran-constant.f90", directory: "/home/sourabh/work/dwarf/fortran") +!4 = distinct !DICompileUnit(language: DW_LANG_Fortran90, file: !3, producer: " F90 Flang - 1.5 2017-05-01", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !5, retainedTypes: !5, globals: !6, imports: !7, nameTableKind: None, constants: !12) +!5 = !{} +!6 = !{!0} +!7 = !{!8} +!8 = !DIImportedEntity(tag: DW_TAG_imported_module, scope: !9, entity: !2, file: !3, line: 9) +!9 = distinct !DISubprogram(name: "main", scope: !4, file: !3, line: 9, type: !10, scopeLine: 9, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagMainSubprogram, unit: !4) +!10 = !DISubroutineType(cc: DW_CC_program, types: !11) +!11 = !{null} +!12 = !{!13, !15} +!13 = !DIConstant(name: "local_constant", scope: !9, file: !3, line: 10, type: !14, isLocal: true, isDefinition: true, value: 42) +!14 = !DIBasicType(name: "integer", size: 32, align: 32, encoding: DW_ATE_signed) +!15 = !DIConstant(name: "module_constant", scope: !2, file: !3, line: 4, type: !14, isLocal: false, isDefinition: true, value: 24) +!16 = !{i32 2, !"Dwarf Version", i32 4} +!17 = !{i32 2, !"Debug Info Version", i32 3} +!18 = !DILocation(line: 12, column: 1, scope: !9) +!19 = distinct !DILocalVariable(scope: !9, file: !3, line: 12, type: !14, flags: DIFlagArtificial) +!20 = !DILocation(line: 0, scope: !9) +!21 = !DILocation(line: 13, column: 1, scope: !9) diff --git a/llvm/unittests/IR/MetadataTest.cpp b/llvm/unittests/IR/MetadataTest.cpp --- a/llvm/unittests/IR/MetadataTest.cpp +++ b/llvm/unittests/IR/MetadataTest.cpp @@ -97,7 +97,7 @@ Context, 1, getFile(), "clang", false, "-g", 2, "", DICompileUnit::FullDebug, getTuple(), getTuple(), getTuple(), getTuple(), getTuple(), 0, true, false, - DICompileUnit::DebugNameTableKind::Default, false, "/", ""); + DICompileUnit::DebugNameTableKind::Default, false, "/", "", getTuple()); } DIType *getBasicType(StringRef Name) { return DIBasicType::get(Context, dwarf::DW_TAG_unspecified_type, Name); @@ -1487,6 +1487,63 @@ DIEnumerator::get(Context, APInt::getMinValue(128), false, "val")); } +typedef MetadataTest DIConstantTest; + +TEST_F(DIConstantTest, getLocalConstant) { + DISubprogram *Subprogram = getSubprogram(); + DIFile *File = getFile(); + unsigned Line = 4; + DIType *Ty = DIBasicType::get(Context, dwarf::DW_TAG_base_type, "int", 32, 32, + dwarf::DW_ATE_signed, DINode::FlagZero); + DIScope *Scope = DILexicalBlock::get(Context, Subprogram, File, Line, 2); + bool IsLocalToUnit = true; + bool IsDefinition = true; + auto *Const = + DIConstant::get(Context, Scope, "localConstant", File, 4, Ty, + IsLocalToUnit, IsDefinition, APInt(64, 42, true)); + EXPECT_EQ(dwarf::DW_TAG_constant, Const->getTag()); + EXPECT_EQ(Scope, Const->getScope()); + EXPECT_NE(File, Const->getScope()); + EXPECT_EQ("localConstant", Const->getName()); + EXPECT_EQ(File, Const->getFile()); + EXPECT_EQ(Line, Const->getLine()); + EXPECT_EQ(Ty, DIBasicType::get(Context, dwarf::DW_TAG_base_type, "int", 32, + 32, dwarf::DW_ATE_signed, DINode::FlagZero)); + EXPECT_EQ(IsLocalToUnit, Const->isLocalToUnit()); + EXPECT_NE(false, Const->isLocalToUnit()); + EXPECT_EQ(IsDefinition, Const->isDefinition()); + EXPECT_NE(false, Const->isDefinition()); + EXPECT_EQ(42, Const->getValue().getSExtValue()); +} + +TEST_F(DIConstantTest, getModuleConstant) { + DIScope *Scope = getFile(); + DIFile *File = getFile(); + unsigned Line = 4; + DIType *Ty = DIBasicType::get(Context, dwarf::DW_TAG_base_type, "int", 32, 32, + dwarf::DW_ATE_signed, DINode::FlagZero); + auto *Module = DIModule::get(Context, File, Scope, StringRef("fortranModule"), + "-DNDEBUG", "-I.", "/tmp/m.apinotes", 1, true); + bool IsLocalToUnit = false; + bool IsDefinition = true; + auto *Const = + DIConstant::get(Context, Module, "moduleConstant", File, 4, Ty, + IsLocalToUnit, IsDefinition, APInt(64, 24, true)); + EXPECT_EQ(dwarf::DW_TAG_constant, Const->getTag()); + EXPECT_EQ(Module, Const->getScope()); + EXPECT_NE(Scope, Const->getScope()); + EXPECT_EQ("moduleConstant", Const->getName()); + EXPECT_EQ(File, Const->getFile()); + EXPECT_EQ(Line, Const->getLine()); + EXPECT_EQ(Ty, DIBasicType::get(Context, dwarf::DW_TAG_base_type, "int", 32, + 32, dwarf::DW_ATE_signed, DINode::FlagZero)); + EXPECT_EQ(IsLocalToUnit, Const->isLocalToUnit()); + EXPECT_NE(true, Const->isLocalToUnit()); + EXPECT_EQ(IsDefinition, Const->isDefinition()); + EXPECT_NE(false, Const->isDefinition()); + EXPECT_EQ(24, Const->getValue().getSExtValue()); +} + typedef MetadataTest DIBasicTypeTest; TEST_F(DIBasicTypeTest, get) { @@ -2110,11 +2167,13 @@ MDTuple *Macros = getTuple(); StringRef SysRoot = "/"; StringRef SDK = "MacOSX.sdk"; + MDTuple *Constants = getTuple(); auto *N = DICompileUnit::getDistinct( Context, SourceLanguage, File, Producer, IsOptimized, Flags, RuntimeVersion, SplitDebugFilename, EmissionKind, EnumTypes, RetainedTypes, GlobalVariables, ImportedEntities, Macros, DWOId, true, - false, DICompileUnit::DebugNameTableKind::Default, false, SysRoot, SDK); + false, DICompileUnit::DebugNameTableKind::Default, false, SysRoot, SDK, + Constants); EXPECT_EQ(dwarf::DW_TAG_compile_unit, N->getTag()); EXPECT_EQ(SourceLanguage, N->getSourceLanguage()); @@ -2133,6 +2192,7 @@ EXPECT_EQ(DWOId, N->getDWOId()); EXPECT_EQ(SysRoot, N->getSysRoot()); EXPECT_EQ(SDK, N->getSDK()); + EXPECT_EQ(Constants, N->getConstants().get()); TempDICompileUnit Temp = N->clone(); EXPECT_EQ(dwarf::DW_TAG_compile_unit, Temp->getTag()); @@ -2151,6 +2211,7 @@ EXPECT_EQ(Macros, Temp->getMacros().get()); EXPECT_EQ(SysRoot, Temp->getSysRoot()); EXPECT_EQ(SDK, Temp->getSDK()); + EXPECT_EQ(Constants, Temp->getConstants().get()); auto *TempAddress = Temp.get(); auto *Clone = MDNode::replaceWithPermanent(std::move(Temp)); @@ -2173,11 +2234,13 @@ uint64_t DWOId = 0xc0ffee; StringRef SysRoot = "/"; StringRef SDK = "MacOSX.sdk"; + MDTuple *Constants = MDTuple::getDistinct(Context, None); auto *N = DICompileUnit::getDistinct( Context, SourceLanguage, File, Producer, IsOptimized, Flags, RuntimeVersion, SplitDebugFilename, EmissionKind, EnumTypes, RetainedTypes, nullptr, ImportedEntities, nullptr, DWOId, true, false, - DICompileUnit::DebugNameTableKind::Default, false, SysRoot, SDK); + DICompileUnit::DebugNameTableKind::Default, false, SysRoot, SDK, + Constants); auto *GlobalVariables = MDTuple::getDistinct(Context, None); EXPECT_EQ(nullptr, N->getGlobalVariables().get());