Skip to content

Commit

Permalink
[PR27284] Reverse the ownership between DICompileUnit and DISubprogram.
Browse files Browse the repository at this point in the history
Currently each Function points to a DISubprogram and DISubprogram has a
scope field. For member functions the scope is a DICompositeType. DIScopes
point to the DICompileUnit to facilitate type uniquing.

Distinct DISubprograms (with isDefinition: true) are not part of the type
hierarchy and cannot be uniqued. This change removes the subprograms
list from DICompileUnit and instead adds a pointer to the owning compile
unit to distinct DISubprograms. This would make it easy for ThinLTO to
strip unneeded DISubprograms and their transitively referenced debug info.

Motivation
----------

Materializing DISubprograms is currently the most expensive operation when
doing a ThinLTO build of clang.

We want the DISubprogram to be stored in a separate Bitcode block (or the
same block as the function body) so we can avoid having to expensively
deserialize all DISubprograms together with the global metadata. If a
function has been inlined into another subprogram we need to store a
reference the block containing the inlined subprogram.

Attached to https://llvm.org/bugs/show_bug.cgi?id=27284 is a python script
that updates LLVM IR testcases to the new format.

http://reviews.llvm.org/D19034
<rdar://problem/25256815>

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@266446 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
adrian-prantl committed Apr 15, 2016
1 parent fa0d0a5 commit 4eeaa0d
Show file tree
Hide file tree
Showing 540 changed files with 1,766 additions and 2,300 deletions.
4 changes: 2 additions & 2 deletions include/llvm/IR/DIBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -403,9 +403,9 @@ namespace llvm {
uint64_t AlignInBits = 0, unsigned Flags = DINode::FlagFwdDecl,
StringRef UniqueIdentifier = "");

/// Retain DIType* in a module even if it is not referenced
/// Retain DIScope* in a module even if it is not referenced
/// through debug info anchors.
void retainType(DIType *T);
void retainType(DIScope *T);

/// Create unspecified parameter type
/// for a subroutine type.
Expand Down
103 changes: 50 additions & 53 deletions include/llvm/IR/DebugInfoMetadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -959,25 +959,21 @@ class DICompileUnit : public DIScope {
StringRef Producer, bool IsOptimized, StringRef Flags,
unsigned RuntimeVersion, StringRef SplitDebugFilename,
unsigned EmissionKind, DICompositeTypeArray EnumTypes,
DITypeArray RetainedTypes, DISubprogramArray Subprograms,
DIGlobalVariableArray GlobalVariables,
DIScopeArray RetainedTypes, DIGlobalVariableArray GlobalVariables,
DIImportedEntityArray ImportedEntities, DIMacroNodeArray Macros,
uint64_t DWOId, StorageType Storage, bool ShouldCreate = true) {
return getImpl(Context, SourceLanguage, File,
getCanonicalMDString(Context, Producer), IsOptimized,
getCanonicalMDString(Context, Flags), RuntimeVersion,
getCanonicalMDString(Context, SplitDebugFilename),
EmissionKind, EnumTypes.get(), RetainedTypes.get(),
Subprograms.get(), GlobalVariables.get(),
ImportedEntities.get(), Macros.get(), DWOId, Storage,
ShouldCreate);
return getImpl(
Context, SourceLanguage, File, getCanonicalMDString(Context, Producer),
IsOptimized, getCanonicalMDString(Context, Flags), RuntimeVersion,
getCanonicalMDString(Context, SplitDebugFilename), EmissionKind,
EnumTypes.get(), RetainedTypes.get(), GlobalVariables.get(),
ImportedEntities.get(), Macros.get(), DWOId, Storage, ShouldCreate);
}
static DICompileUnit *
getImpl(LLVMContext &Context, unsigned SourceLanguage, Metadata *File,
MDString *Producer, bool IsOptimized, MDString *Flags,
unsigned RuntimeVersion, MDString *SplitDebugFilename,
unsigned EmissionKind, Metadata *EnumTypes,
Metadata *RetainedTypes, Metadata *Subprograms,
unsigned EmissionKind, Metadata *EnumTypes, Metadata *RetainedTypes,
Metadata *GlobalVariables, Metadata *ImportedEntities,
Metadata *Macros, uint64_t DWOId, StorageType Storage,
bool ShouldCreate = true);
Expand All @@ -986,7 +982,7 @@ class DICompileUnit : public DIScope {
return getTemporary(
getContext(), getSourceLanguage(), getFile(), getProducer(),
isOptimized(), getFlags(), getRuntimeVersion(), getSplitDebugFilename(),
getEmissionKind(), getEnumTypes(), getRetainedTypes(), getSubprograms(),
getEmissionKind(), getEnumTypes(), getRetainedTypes(),
getGlobalVariables(), getImportedEntities(), getMacros(), DWOId);
}

Expand All @@ -999,23 +995,22 @@ class DICompileUnit : public DIScope {
(unsigned SourceLanguage, DIFile *File, StringRef Producer,
bool IsOptimized, StringRef Flags, unsigned RuntimeVersion,
StringRef SplitDebugFilename, DebugEmissionKind EmissionKind,
DICompositeTypeArray EnumTypes, DITypeArray RetainedTypes,
DISubprogramArray Subprograms, DIGlobalVariableArray GlobalVariables,
DICompositeTypeArray EnumTypes, DIScopeArray RetainedTypes,
DIGlobalVariableArray GlobalVariables,
DIImportedEntityArray ImportedEntities, DIMacroNodeArray Macros,
uint64_t DWOId),
(SourceLanguage, File, Producer, IsOptimized, Flags, RuntimeVersion,
SplitDebugFilename, EmissionKind, EnumTypes, RetainedTypes, Subprograms,
SplitDebugFilename, EmissionKind, EnumTypes, RetainedTypes,
GlobalVariables, ImportedEntities, Macros, DWOId))
DEFINE_MDNODE_GET_DISTINCT_TEMPORARY(
DICompileUnit,
(unsigned SourceLanguage, Metadata *File, MDString *Producer,
bool IsOptimized, MDString *Flags, unsigned RuntimeVersion,
MDString *SplitDebugFilename, unsigned EmissionKind, Metadata *EnumTypes,
Metadata *RetainedTypes, Metadata *Subprograms,
Metadata *GlobalVariables, Metadata *ImportedEntities, Metadata *Macros,
uint64_t DWOId),
Metadata *RetainedTypes, Metadata *GlobalVariables,
Metadata *ImportedEntities, Metadata *Macros, uint64_t DWOId),
(SourceLanguage, File, Producer, IsOptimized, Flags, RuntimeVersion,
SplitDebugFilename, EmissionKind, EnumTypes, RetainedTypes, Subprograms,
SplitDebugFilename, EmissionKind, EnumTypes, RetainedTypes,
GlobalVariables, ImportedEntities, Macros, DWOId))

TempDICompileUnit clone() const { return cloneImpl(); }
Expand All @@ -1032,12 +1027,9 @@ class DICompileUnit : public DIScope {
DICompositeTypeArray getEnumTypes() const {
return cast_or_null<MDTuple>(getRawEnumTypes());
}
DITypeArray getRetainedTypes() const {
DIScopeArray getRetainedTypes() const {
return cast_or_null<MDTuple>(getRawRetainedTypes());
}
DISubprogramArray getSubprograms() const {
return cast_or_null<MDTuple>(getRawSubprograms());
}
DIGlobalVariableArray getGlobalVariables() const {
return cast_or_null<MDTuple>(getRawGlobalVariables());
}
Expand All @@ -1057,10 +1049,9 @@ class DICompileUnit : public DIScope {
}
Metadata *getRawEnumTypes() const { return getOperand(4); }
Metadata *getRawRetainedTypes() const { return getOperand(5); }
Metadata *getRawSubprograms() const { return getOperand(6); }
Metadata *getRawGlobalVariables() const { return getOperand(7); }
Metadata *getRawImportedEntities() const { return getOperand(8); }
Metadata *getRawMacros() const { return getOperand(9); }
Metadata *getRawGlobalVariables() const { return getOperand(6); }
Metadata *getRawImportedEntities() const { return getOperand(7); }
Metadata *getRawMacros() const { return getOperand(8); }

/// \brief Replace arrays.
///
Expand All @@ -1074,16 +1065,13 @@ class DICompileUnit : public DIScope {
void replaceRetainedTypes(DITypeArray N) {
replaceOperandWith(5, N.get());
}
void replaceSubprograms(DISubprogramArray N) {
replaceOperandWith(6, N.get());
}
void replaceGlobalVariables(DIGlobalVariableArray N) {
replaceOperandWith(7, N.get());
replaceOperandWith(6, N.get());
}
void replaceImportedEntities(DIImportedEntityArray N) {
replaceOperandWith(8, N.get());
replaceOperandWith(7, N.get());
}
void replaceMacros(DIMacroNodeArray N) { replaceOperandWith(9, N.get()); }
void replaceMacros(DIMacroNodeArray N) { replaceOperandWith(8, N.get()); }
/// @}

static bool classof(const Metadata *MD) {
Expand Down Expand Up @@ -1266,13 +1254,13 @@ class DISubprogram : public DILocalScope {
DISubroutineType *Type, bool IsLocalToUnit, bool IsDefinition,
unsigned ScopeLine, DITypeRef ContainingType, unsigned Virtuality,
unsigned VirtualIndex, unsigned Flags, bool IsOptimized,
DITemplateParameterArray TemplateParams, DISubprogram *Declaration,
DILocalVariableArray Variables, StorageType Storage,
bool ShouldCreate = true) {
DICompileUnit *Unit, DITemplateParameterArray TemplateParams,
DISubprogram *Declaration, DILocalVariableArray Variables,
StorageType Storage, bool ShouldCreate = true) {
return getImpl(Context, Scope, getCanonicalMDString(Context, Name),
getCanonicalMDString(Context, LinkageName), File, Line, Type,
IsLocalToUnit, IsDefinition, ScopeLine, ContainingType,
Virtuality, VirtualIndex, Flags, IsOptimized,
Virtuality, VirtualIndex, Flags, IsOptimized, Unit,
TemplateParams.get(), Declaration, Variables.get(), Storage,
ShouldCreate);
}
Expand All @@ -1281,16 +1269,17 @@ class DISubprogram : public DILocalScope {
MDString *LinkageName, Metadata *File, unsigned Line, Metadata *Type,
bool IsLocalToUnit, bool IsDefinition, unsigned ScopeLine,
Metadata *ContainingType, unsigned Virtuality, unsigned VirtualIndex,
unsigned Flags, bool IsOptimized, Metadata *TemplateParams,
Metadata *Declaration, Metadata *Variables, StorageType Storage,
bool ShouldCreate = true);
unsigned Flags, bool IsOptimized, Metadata *Unit,
Metadata *TemplateParams, Metadata *Declaration, Metadata *Variables,
StorageType Storage, bool ShouldCreate = true);

TempDISubprogram cloneImpl() const {
return getTemporary(
getContext(), getScope(), getName(), getLinkageName(), getFile(),
getLine(), getType(), isLocalToUnit(), isDefinition(), getScopeLine(),
getContainingType(), getVirtuality(), getVirtualIndex(), getFlags(),
isOptimized(), getTemplateParams(), getDeclaration(), getVariables());
return getTemporary(getContext(), getScope(), getName(), getLinkageName(),
getFile(), getLine(), getType(), isLocalToUnit(),
isDefinition(), getScopeLine(), getContainingType(),
getVirtuality(), getVirtualIndex(), getFlags(),
isOptimized(), getUnit(), getTemplateParams(),
getDeclaration(), getVariables());
}

public:
Expand All @@ -1300,24 +1289,25 @@ class DISubprogram : public DILocalScope {
bool IsLocalToUnit, bool IsDefinition, unsigned ScopeLine,
DITypeRef ContainingType, unsigned Virtuality,
unsigned VirtualIndex, unsigned Flags, bool IsOptimized,
DICompileUnit *Unit,
DITemplateParameterArray TemplateParams = nullptr,
DISubprogram *Declaration = nullptr,
DILocalVariableArray Variables = nullptr),
(Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit,
IsDefinition, ScopeLine, ContainingType, Virtuality,
VirtualIndex, Flags, IsOptimized, TemplateParams,
VirtualIndex, Flags, IsOptimized, Unit, TemplateParams,
Declaration, Variables))
DEFINE_MDNODE_GET(
DISubprogram,
(Metadata * Scope, MDString *Name, MDString *LinkageName, Metadata *File,
unsigned Line, Metadata *Type, bool IsLocalToUnit, bool IsDefinition,
unsigned ScopeLine, Metadata *ContainingType, unsigned Virtuality,
unsigned VirtualIndex, unsigned Flags, bool IsOptimized,
Metadata *TemplateParams = nullptr, Metadata *Declaration = nullptr,
Metadata *Variables = nullptr),
Metadata *Unit, Metadata *TemplateParams = nullptr,
Metadata *Declaration = nullptr, Metadata *Variables = nullptr),
(Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, IsDefinition,
ScopeLine, ContainingType, Virtuality, VirtualIndex, Flags, IsOptimized,
TemplateParams, Declaration, Variables))
Unit, TemplateParams, Declaration, Variables))

TempDISubprogram clone() const { return cloneImpl(); }

Expand Down Expand Up @@ -1376,6 +1366,12 @@ class DISubprogram : public DILocalScope {
return DITypeRef(getRawContainingType());
}

DICompileUnit *getUnit() const {
return cast_or_null<DICompileUnit>(getRawUnit());
}
void replaceUnit(DICompileUnit *CU) {
replaceOperandWith(7, CU);
}
DITemplateParameterArray getTemplateParams() const {
return cast_or_null<MDTuple>(getRawTemplateParams());
}
Expand All @@ -1389,9 +1385,10 @@ class DISubprogram : public DILocalScope {
Metadata *getRawScope() const { return getOperand(1); }
Metadata *getRawType() const { return getOperand(5); }
Metadata *getRawContainingType() const { return getOperand(6); }
Metadata *getRawTemplateParams() const { return getOperand(7); }
Metadata *getRawDeclaration() const { return getOperand(8); }
Metadata *getRawVariables() const { return getOperand(9); }
Metadata *getRawUnit() const { return getOperand(7); }
Metadata *getRawTemplateParams() const { return getOperand(8); }
Metadata *getRawDeclaration() const { return getOperand(9); }
Metadata *getRawVariables() const { return getOperand(10); }

/// \brief Check if this subprogram describes the given function.
///
Expand Down
18 changes: 8 additions & 10 deletions lib/AsmParser/LLParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3875,8 +3875,7 @@ bool LLParser::ParseDIFile(MDNode *&Result, bool IsDistinct) {
/// ::= !DICompileUnit(language: DW_LANG_C99, file: !0, producer: "clang",
/// isOptimized: true, flags: "-O2", runtimeVersion: 1,
/// splitDebugFilename: "abc.debug",
/// emissionKind: FullDebug,
/// enums: !1, retainedTypes: !2, subprograms: !3,
/// emissionKind: FullDebug, enums: !1, retainedTypes: !2,
/// globals: !4, imports: !5, macros: !6, dwoId: 0x0abcd)
bool LLParser::ParseDICompileUnit(MDNode *&Result, bool IsDistinct) {
if (!IsDistinct)
Expand All @@ -3893,7 +3892,6 @@ bool LLParser::ParseDICompileUnit(MDNode *&Result, bool IsDistinct) {
OPTIONAL(emissionKind, EmissionKindField, ); \
OPTIONAL(enums, MDField, ); \
OPTIONAL(retainedTypes, MDField, ); \
OPTIONAL(subprograms, MDField, ); \
OPTIONAL(globals, MDField, ); \
OPTIONAL(imports, MDField, ); \
OPTIONAL(macros, MDField, ); \
Expand All @@ -3904,8 +3902,7 @@ bool LLParser::ParseDICompileUnit(MDNode *&Result, bool IsDistinct) {
Result = DICompileUnit::getDistinct(
Context, language.Val, file.Val, producer.Val, isOptimized.Val, flags.Val,
runtimeVersion.Val, splitDebugFilename.Val, emissionKind.Val, enums.Val,
retainedTypes.Val, subprograms.Val, globals.Val, imports.Val, macros.Val,
dwoId.Val);
retainedTypes.Val, globals.Val, imports.Val, macros.Val, dwoId.Val);
return false;
}

Expand Down Expand Up @@ -3934,6 +3931,7 @@ bool LLParser::ParseDISubprogram(MDNode *&Result, bool IsDistinct) {
OPTIONAL(virtualIndex, MDUnsignedField, (0, UINT32_MAX)); \
OPTIONAL(flags, DIFlagField, ); \
OPTIONAL(isOptimized, MDBoolField, ); \
OPTIONAL(unit, MDField, ); \
OPTIONAL(templateParams, MDField, ); \
OPTIONAL(declaration, MDField, ); \
OPTIONAL(variables, MDField, );
Expand All @@ -3946,11 +3944,11 @@ bool LLParser::ParseDISubprogram(MDNode *&Result, bool IsDistinct) {
"missing 'distinct', required for !DISubprogram when 'isDefinition'");

Result = GET_OR_DISTINCT(
DISubprogram,
(Context, scope.Val, name.Val, linkageName.Val, file.Val, line.Val,
type.Val, isLocal.Val, isDefinition.Val, scopeLine.Val,
containingType.Val, virtuality.Val, virtualIndex.Val, flags.Val,
isOptimized.Val, templateParams.Val, declaration.Val, variables.Val));
DISubprogram, (Context, scope.Val, name.Val, linkageName.Val, file.Val,
line.Val, type.Val, isLocal.Val, isDefinition.Val,
scopeLine.Val, containingType.Val, virtuality.Val,
virtualIndex.Val, flags.Val, isOptimized.Val, unit.Val,
templateParams.Val, declaration.Val, variables.Val));
return false;
}

Expand Down
49 changes: 33 additions & 16 deletions lib/Bitcode/Reader/BitcodeReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1948,6 +1948,7 @@ std::error_code BitcodeReader::parseMetadata(bool ModuleLevel) {
if (Stream.EnterSubBlock(bitc::METADATA_BLOCK_ID))
return error("Invalid record");

std::vector<std::pair<DICompileUnit *, Metadata *>> CUSubprograms;
SmallVector<uint64_t, 64> Record;

auto getMD = [&](unsigned ID) -> Metadata * {
Expand Down Expand Up @@ -1976,6 +1977,13 @@ std::error_code BitcodeReader::parseMetadata(bool ModuleLevel) {
case BitstreamEntry::Error:
return error("Malformed block");
case BitstreamEntry::EndBlock:
// Upgrade old-style CU <-> SP pointers to point from SP to CU.
for (auto CU_SP : CUSubprograms)
if (auto *SPs = dyn_cast_or_null<MDTuple>(CU_SP.second))
for (auto &Op : SPs->operands())
if (auto *SP = dyn_cast_or_null<MDNode>(Op))
SP->replaceOperandWith(7, CU_SP.first);

MetadataList.tryToResolveCycles();
return std::error_code();
case BitstreamEntry::Record:
Expand Down Expand Up @@ -2232,38 +2240,47 @@ std::error_code BitcodeReader::parseMetadata(bool ModuleLevel) {

// Ignore Record[0], which indicates whether this compile unit is
// distinct. It's always distinct.
MetadataList.assignValue(
DICompileUnit::getDistinct(
Context, Record[1], getMDOrNull(Record[2]),
getMDString(Record[3]), Record[4], getMDString(Record[5]),
Record[6], getMDString(Record[7]), Record[8],
getMDOrNull(Record[9]), getMDOrNull(Record[10]),
getMDOrNull(Record[11]), getMDOrNull(Record[12]),
getMDOrNull(Record[13]),
Record.size() <= 15 ? nullptr : getMDOrNull(Record[15]),
Record.size() <= 14 ? 0 : Record[14]),
NextMetadataNo++);
auto *CU = DICompileUnit::getDistinct(
Context, Record[1], getMDOrNull(Record[2]), getMDString(Record[3]),
Record[4], getMDString(Record[5]), Record[6], getMDString(Record[7]),
Record[8], getMDOrNull(Record[9]), getMDOrNull(Record[10]),
getMDOrNull(Record[12]), getMDOrNull(Record[13]),
Record.size() <= 15 ? nullptr : getMDOrNull(Record[15]),
Record.size() <= 14 ? 0 : Record[14]);

MetadataList.assignValue(CU, NextMetadataNo++);

// Move the Upgrade the list of subprograms.
if (Metadata *SPs = getMDOrNull(Record[11]))
CUSubprograms.push_back({CU, SPs});
break;
}
case bitc::METADATA_SUBPROGRAM: {
if (Record.size() != 18 && Record.size() != 19)
return error("Invalid record");

bool HasFn = Record.size() == 19;
// Version 1 has a Function as Record[15].
// Version 2 has removed Record[15].
// Version 3 has the Unit as Record[15].
Metadata *CUorFn = getMDOrNull(Record[15]);
unsigned Offset = Record.size() == 19 ? 1 : 0;
bool HasFn = Offset && dyn_cast_or_null<ConstantAsMetadata>(CUorFn);
bool HasCU = Offset && !HasFn;
DISubprogram *SP = GET_OR_DISTINCT(
DISubprogram,
Record[0] || Record[8], // All definitions should be distinct.
(Context, getMDOrNull(Record[1]), getMDString(Record[2]),
getMDString(Record[3]), getMDOrNull(Record[4]), Record[5],
getMDOrNull(Record[6]), Record[7], Record[8], Record[9],
getMDOrNull(Record[10]), Record[11], Record[12], Record[13],
Record[14], getMDOrNull(Record[15 + HasFn]),
getMDOrNull(Record[16 + HasFn]), getMDOrNull(Record[17 + HasFn])));
Record[14], HasCU ? CUorFn : nullptr,
getMDOrNull(Record[15 + Offset]), getMDOrNull(Record[16 + Offset]),
getMDOrNull(Record[17 + Offset])));
MetadataList.assignValue(SP, NextMetadataNo++);

// Upgrade sp->function mapping to function->sp mapping.
if (HasFn && Record[15]) {
if (auto *CMD = dyn_cast<ConstantAsMetadata>(getMDOrNull(Record[15])))
if (HasFn) {
if (auto *CMD = dyn_cast<ConstantAsMetadata>(CUorFn))
if (auto *F = dyn_cast<Function>(CMD->getValue())) {
if (F->isMaterializable())
// Defer until materialized; unmaterialized functions may not have
Expand Down
Loading

0 comments on commit 4eeaa0d

Please sign in to comment.