Skip to content
Permalink
Browse files

[PR27284] Reverse the ownership between DICompileUnit and DISubprogram.

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 4eeaa0da042055b1cd17b339e2dde518a3026033
Showing 540 changed files with 1,766 additions and 2,300 deletions.
@@ -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.
@@ -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);
@@ -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);
}

@@ -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(); }
@@ -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());
}
@@ -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.
///
@@ -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) {
@@ -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);
}
@@ -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:
@@ -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(); }

@@ -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());
}
@@ -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.
///
@@ -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)
@@ -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, ); \
@@ -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;
}

@@ -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, );
@@ -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;
}

@@ -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 * {
@@ -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:
@@ -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
Oops, something went wrong.

0 comments on commit 4eeaa0d

Please sign in to comment.
You can’t perform that action at this time.