1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 12:41:49 +01:00

Support the Nodebug emission kind for DICompileUnits.

Sample-based profiling and optimization remarks currently remove
DICompileUnits from llvm.dbg.cu to suppress the emission of debug info
from them. This is somewhat of a hack and only borderline legal IR.

This patch uses the recently introduced NoDebug emission kind in
DICompileUnit to achieve the same result without breaking the Verifier.
A nice side-effect of this change is that it is now possible to combine
NoDebug and regular compile units under LTO.

http://reviews.llvm.org/D18808
<rdar://problem/25427165>

llvm-svn: 265861
This commit is contained in:
Adrian Prantl 2016-04-08 22:43:03 +00:00
parent 744e3da853
commit 4300f8a4c5
9 changed files with 171 additions and 71 deletions

View File

@ -92,23 +92,13 @@ namespace llvm {
/// out into. /// out into.
/// \param Kind The kind of debug information to generate. /// \param Kind The kind of debug information to generate.
/// \param DWOId The DWOId if this is a split skeleton compile unit. /// \param DWOId The DWOId if this is a split skeleton compile unit.
/// \param EmitDebugInfo A boolean flag which indicates whether
/// debug information should be written to
/// the final output or not. When this is
/// false, debug information annotations will
/// be present in the IL but they are not
/// written to the final assembly or object
/// file. This supports tracking source
/// location information in the back end
/// without actually changing the output
/// (e.g., when using optimization remarks).
DICompileUnit * DICompileUnit *
createCompileUnit(unsigned Lang, StringRef File, StringRef Dir, createCompileUnit(unsigned Lang, StringRef File, StringRef Dir,
StringRef Producer, bool isOptimized, StringRef Flags, StringRef Producer, bool isOptimized, StringRef Flags,
unsigned RV, StringRef SplitName = StringRef(), unsigned RV, StringRef SplitName = StringRef(),
DICompileUnit::DebugEmissionKind Kind = DICompileUnit::DebugEmissionKind Kind =
DICompileUnit::DebugEmissionKind::FullDebug, DICompileUnit::DebugEmissionKind::FullDebug,
uint64_t DWOId = 0, bool EmitDebugInfo = true); uint64_t DWOId = 0);
/// Create a file descriptor to hold debugging information /// Create a file descriptor to hold debugging information
/// for a file. /// for a file.

View File

@ -40,7 +40,7 @@ typedef DenseMap<const MDString *, DIType *> DITypeIdentifierMap;
DISubprogram *getDISubprogram(const MDNode *Scope); DISubprogram *getDISubprogram(const MDNode *Scope);
/// \brief Generate map by visiting all retained types. /// \brief Generate map by visiting all retained types.
DITypeIdentifierMap generateDITypeIdentifierMap(const NamedMDNode *CU_Nodes); DITypeIdentifierMap generateDITypeIdentifierMap(const Module &M);
/// \brief Strip debug info in the module if it exists. /// \brief Strip debug info in the module if it exists.
/// ///

View File

@ -626,6 +626,58 @@ public:
return make_range(named_metadata_begin(), named_metadata_end()); return make_range(named_metadata_begin(), named_metadata_end());
} }
/// An iterator for DICompileUnits that skips those marked NoDebug.
class debug_compile_units_iterator
: public std::iterator<std::input_iterator_tag, DICompileUnit *> {
NamedMDNode *CUs;
unsigned Idx;
void SkipNoDebugCUs();
public:
explicit debug_compile_units_iterator(NamedMDNode *CUs, unsigned Idx)
: CUs(CUs), Idx(Idx) {
SkipNoDebugCUs();
}
debug_compile_units_iterator &operator++() {
++Idx;
SkipNoDebugCUs();
return *this;
}
debug_compile_units_iterator operator++(int) {
debug_compile_units_iterator T(*this);
++Idx;
return T;
}
bool operator==(const debug_compile_units_iterator &I) const {
return Idx == I.Idx;
}
bool operator!=(const debug_compile_units_iterator &I) const {
return Idx != I.Idx;
}
DICompileUnit *operator*() const;
DICompileUnit *operator->() const;
};
debug_compile_units_iterator debug_compile_units_begin() const {
auto *CUs = getNamedMetadata("llvm.dbg.cu");
return debug_compile_units_iterator(CUs, 0);
}
debug_compile_units_iterator debug_compile_units_end() const {
auto *CUs = getNamedMetadata("llvm.dbg.cu");
return debug_compile_units_iterator(CUs, CUs ? CUs->getNumOperands() : 0);
}
/// Return an iterator for all DICompileUnits listed in this Module's
/// llvm.dbg.cu named metadata node and aren't explicitly marked as
/// NoDebug.
iterator_range<debug_compile_units_iterator> debug_compile_units() const {
auto *CUs = getNamedMetadata("llvm.dbg.cu");
return make_range(
debug_compile_units_iterator(CUs, 0),
debug_compile_units_iterator(CUs, CUs ? CUs->getNumOperands() : 0));
}
/// @}
/// Destroy ConstantArrays in LLVMContext if they are not used. /// Destroy ConstantArrays in LLVMContext if they are not used.
/// ConstantArrays constructed during linking can cause quadratic memory /// ConstantArrays constructed during linking can cause quadratic memory
/// explosion. Releasing all unused constants can cause a 20% LTO compile-time /// explosion. Releasing all unused constants can cause a 20% LTO compile-time
@ -635,7 +687,6 @@ public:
/// be called where all uses of the LLVMContext are understood. /// be called where all uses of the LLVMContext are understood.
void dropTriviallyDeadConstantArrays(); void dropTriviallyDeadConstantArrays();
/// @}
/// @name Utility functions for printing and dumping Module objects /// @name Utility functions for printing and dumping Module objects
/// @{ /// @{

View File

@ -466,15 +466,18 @@ void DwarfDebug::beginModule() {
const Module *M = MMI->getModule(); const Module *M = MMI->getModule();
NamedMDNode *CU_Nodes = M->getNamedMetadata("llvm.dbg.cu"); TypeIdentifierMap = generateDITypeIdentifierMap(*M);
if (!CU_Nodes) unsigned NumDebugCUs = 0;
return; for (DICompileUnit *CUNode : M->debug_compile_units()) {
TypeIdentifierMap = generateDITypeIdentifierMap(CU_Nodes); (void)CUNode;
++NumDebugCUs;
}
SingleCU = CU_Nodes->getNumOperands() == 1; // Tell MMI whether we have debug info.
MMI->setDebugInfoAvailability(NumDebugCUs > 0);
SingleCU = NumDebugCUs == 1;
for (MDNode *N : CU_Nodes->operands()) { for (DICompileUnit *CUNode : M->debug_compile_units()) {
auto *CUNode = cast<DICompileUnit>(N);
DwarfCompileUnit &CU = constructDwarfCompileUnit(CUNode); DwarfCompileUnit &CU = constructDwarfCompileUnit(CUNode);
for (auto *IE : CUNode->getImportedEntities()) for (auto *IE : CUNode->getImportedEntities())
CU.addImportedEntity(IE); CU.addImportedEntity(IE);
@ -500,9 +503,6 @@ void DwarfDebug::beginModule() {
for (auto *IE : CUNode->getImportedEntities()) for (auto *IE : CUNode->getImportedEntities())
constructAndAddImportedEntityDIE(CU, IE); constructAndAddImportedEntityDIE(CU, IE);
} }
// Tell MMI that we have debug info.
MMI->setDebugInfoAvailability(true);
} }
void DwarfDebug::finishVariableDefinitions() { void DwarfDebug::finishVariableDefinitions() {
@ -538,6 +538,9 @@ void DwarfDebug::collectDeadVariables() {
if (NamedMDNode *CU_Nodes = M->getNamedMetadata("llvm.dbg.cu")) { if (NamedMDNode *CU_Nodes = M->getNamedMetadata("llvm.dbg.cu")) {
for (MDNode *N : CU_Nodes->operands()) { for (MDNode *N : CU_Nodes->operands()) {
auto *TheCU = cast<DICompileUnit>(N); auto *TheCU = cast<DICompileUnit>(N);
if (TheCU->getEmissionKind() == DICompileUnit::NoDebug)
continue;
// Construct subprogram DIE and add variables DIEs. // Construct subprogram DIE and add variables DIEs.
DwarfCompileUnit *SPCU = DwarfCompileUnit *SPCU =
static_cast<DwarfCompileUnit *>(CUMap.lookup(TheCU)); static_cast<DwarfCompileUnit *>(CUMap.lookup(TheCU));
@ -1090,7 +1093,10 @@ void DwarfDebug::beginFunction(const MachineFunction *MF) {
// includes the directory of the cpp file being built, even when the file name // includes the directory of the cpp file being built, even when the file name
// is absolute (such as an <> lookup header))) // is absolute (such as an <> lookup header)))
DwarfCompileUnit *TheCU = SPMap.lookup(FnScope->getScopeNode()); DwarfCompileUnit *TheCU = SPMap.lookup(FnScope->getScopeNode());
assert(TheCU && "Unable to find compile unit!"); if (!TheCU)
// Once DISubprogram points to the owning CU, we can assert that the CU has
// a NoDebug EmissionKind here.
return;
if (Asm->OutStreamer->hasRawTextSupport()) if (Asm->OutStreamer->hasRawTextSupport())
// Use a single line table if we are generating assembly. // Use a single line table if we are generating assembly.
Asm->OutStreamer->getContext().setDwarfCompileUnitID(0); Asm->OutStreamer->getContext().setDwarfCompileUnitID(0);
@ -1113,7 +1119,10 @@ void DwarfDebug::endFunction(const MachineFunction *MF) {
"endFunction should be called with the same function as beginFunction"); "endFunction should be called with the same function as beginFunction");
if (!MMI->hasDebugInfo() || LScopes.empty() || if (!MMI->hasDebugInfo() || LScopes.empty() ||
!MF->getFunction()->getSubprogram()) { !MF->getFunction()->getSubprogram() ||
// Once DISubprogram points to the owning CU, we can check for a
// CU with a NoDebug EmissionKind here.
!SPMap.lookup(MF->getFunction()->getSubprogram())) {
// If we don't have a lexical scope for this function then there will // If we don't have a lexical scope for this function then there will
// be a hole in the range information. Keep note of this by setting the // be a hole in the range information. Keep note of this by setting the
// previously used section to nullptr. // previously used section to nullptr.

View File

@ -137,7 +137,7 @@ static DIScope *getNonCompileUnitScope(DIScope *N) {
DICompileUnit *DIBuilder::createCompileUnit( DICompileUnit *DIBuilder::createCompileUnit(
unsigned Lang, StringRef Filename, StringRef Directory, StringRef Producer, unsigned Lang, StringRef Filename, StringRef Directory, StringRef Producer,
bool isOptimized, StringRef Flags, unsigned RunTimeVer, StringRef SplitName, bool isOptimized, StringRef Flags, unsigned RunTimeVer, StringRef SplitName,
DICompileUnit::DebugEmissionKind Kind, uint64_t DWOId, bool EmitDebugInfo) { DICompileUnit::DebugEmissionKind Kind, uint64_t DWOId) {
assert(((Lang <= dwarf::DW_LANG_Fortran08 && Lang >= dwarf::DW_LANG_C89) || assert(((Lang <= dwarf::DW_LANG_Fortran08 && Lang >= dwarf::DW_LANG_C89) ||
(Lang <= dwarf::DW_LANG_hi_user && Lang >= dwarf::DW_LANG_lo_user)) && (Lang <= dwarf::DW_LANG_hi_user && Lang >= dwarf::DW_LANG_lo_user)) &&
@ -152,15 +152,8 @@ DICompileUnit *DIBuilder::createCompileUnit(
nullptr, nullptr, nullptr, nullptr, nullptr, DWOId); nullptr, nullptr, nullptr, nullptr, nullptr, DWOId);
// Create a named metadata so that it is easier to find cu in a module. // Create a named metadata so that it is easier to find cu in a module.
// Note that we only generate this when the caller wants to actually NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.dbg.cu");
// emit debug information. When we are only interested in tracking NMD->addOperand(CUNode);
// source line locations throughout the backend, we prevent codegen from
// emitting debug info in the final output by not generating llvm.dbg.cu.
if (EmitDebugInfo) {
NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.dbg.cu");
NMD->addOperand(CUNode);
}
trackIfUnresolved(CUNode); trackIfUnresolved(CUNode);
return CUNode; return CUNode;
} }

View File

@ -39,10 +39,9 @@ DISubprogram *llvm::getDISubprogram(const MDNode *Scope) {
} }
DITypeIdentifierMap DITypeIdentifierMap
llvm::generateDITypeIdentifierMap(const NamedMDNode *CU_Nodes) { llvm::generateDITypeIdentifierMap(const Module &M) {
DITypeIdentifierMap Map; DITypeIdentifierMap Map;
for (unsigned CUi = 0, CUe = CU_Nodes->getNumOperands(); CUi != CUe; ++CUi) { for (DICompileUnit *CU : M.debug_compile_units()) {
auto *CU = cast<DICompileUnit>(CU_Nodes->getOperand(CUi));
DINodeArray Retain = CU->getRetainedTypes(); DINodeArray Retain = CU->getRetainedTypes();
for (unsigned Ti = 0, Te = Retain.size(); Ti != Te; ++Ti) { for (unsigned Ti = 0, Te = Retain.size(); Ti != Te; ++Ti) {
if (!isa<DICompositeType>(Retain[Ti])) if (!isa<DICompositeType>(Retain[Ti]))
@ -79,42 +78,38 @@ void DebugInfoFinder::reset() {
} }
void DebugInfoFinder::InitializeTypeMap(const Module &M) { void DebugInfoFinder::InitializeTypeMap(const Module &M) {
if (!TypeMapInitialized) if (TypeMapInitialized)
if (NamedMDNode *CU_Nodes = M.getNamedMetadata("llvm.dbg.cu")) { return;
TypeIdentifierMap = generateDITypeIdentifierMap(CU_Nodes); TypeIdentifierMap = generateDITypeIdentifierMap(M);
TypeMapInitialized = true; TypeMapInitialized = true;
}
} }
void DebugInfoFinder::processModule(const Module &M) { void DebugInfoFinder::processModule(const Module &M) {
InitializeTypeMap(M); InitializeTypeMap(M);
if (NamedMDNode *CU_Nodes = M.getNamedMetadata("llvm.dbg.cu")) { for (auto *CU : M.debug_compile_units()) {
for (unsigned i = 0, e = CU_Nodes->getNumOperands(); i != e; ++i) { addCompileUnit(CU);
auto *CU = cast<DICompileUnit>(CU_Nodes->getOperand(i)); for (auto *DIG : CU->getGlobalVariables()) {
addCompileUnit(CU); if (addGlobalVariable(DIG)) {
for (auto *DIG : CU->getGlobalVariables()) { processScope(DIG->getScope());
if (addGlobalVariable(DIG)) { processType(DIG->getType().resolve(TypeIdentifierMap));
processScope(DIG->getScope());
processType(DIG->getType().resolve(TypeIdentifierMap));
}
} }
for (auto *SP : CU->getSubprograms()) }
for (auto *SP : CU->getSubprograms())
processSubprogram(SP);
for (auto *ET : CU->getEnumTypes())
processType(ET);
for (auto *RT : CU->getRetainedTypes())
processType(RT);
for (auto *Import : CU->getImportedEntities()) {
auto *Entity = Import->getEntity().resolve(TypeIdentifierMap);
if (auto *T = dyn_cast<DIType>(Entity))
processType(T);
else if (auto *SP = dyn_cast<DISubprogram>(Entity))
processSubprogram(SP); processSubprogram(SP);
for (auto *ET : CU->getEnumTypes()) else if (auto *NS = dyn_cast<DINamespace>(Entity))
processType(ET); processScope(NS->getScope());
for (auto *RT : CU->getRetainedTypes()) else if (auto *M = dyn_cast<DIModule>(Entity))
processType(RT); processScope(M->getScope());
for (auto *Import : CU->getImportedEntities()) {
auto *Entity = Import->getEntity().resolve(TypeIdentifierMap);
if (auto *T = dyn_cast<DIType>(Entity))
processType(T);
else if (auto *SP = dyn_cast<DISubprogram>(Entity))
processSubprogram(SP);
else if (auto *NS = dyn_cast<DINamespace>(Entity))
processScope(NS->getScope());
else if (auto *M = dyn_cast<DIModule>(Entity))
processScope(M->getScope());
}
} }
} }
} }

View File

@ -19,6 +19,7 @@
#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringExtras.h"
#include "llvm/IR/Constants.h" #include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h" #include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/GVMaterializer.h" #include "llvm/IR/GVMaterializer.h"
#include "llvm/IR/InstrTypes.h" #include "llvm/IR/InstrTypes.h"
#include "llvm/IR/LLVMContext.h" #include "llvm/IR/LLVMContext.h"
@ -380,6 +381,19 @@ void Module::setDataLayout(const DataLayout &Other) { DL = Other; }
const DataLayout &Module::getDataLayout() const { return DL; } const DataLayout &Module::getDataLayout() const { return DL; }
DICompileUnit *Module::debug_compile_units_iterator::operator*() const {
return cast<DICompileUnit>(CUs->getOperand(Idx));
}
DICompileUnit *Module::debug_compile_units_iterator::operator->() const {
return cast<DICompileUnit>(CUs->getOperand(Idx));
}
void Module::debug_compile_units_iterator::SkipNoDebugCUs() {
while (CUs && (Idx < CUs->getNumOperands()) &&
((*this)->getEmissionKind() == DICompileUnit::NoDebug))
++Idx;
}
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// Methods to control the materialization of GlobalValues in the Module. // Methods to control the materialization of GlobalValues in the Module.
// //

View File

@ -0,0 +1,50 @@
; RUN: llc %s -o %t -filetype=obj
; RUN: llvm-dwarfdump -debug-dump=info %t | FileCheck %s
; CHECK: DW_TAG_compile_unit
; CHECK: DW_TAG_subprogram
; CHECK: DW_AT_name{{.*}}"f"
; CHECK-NOT: DW_TAG_compile_unit
;
; created from
; void f() {} // compile with -g
; void g() {} // compile with -Rpass=inline
; and llvm-linking the result.
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.11.0"
; Function Attrs: nounwind ssp uwtable
define void @f() #0 !dbg !4 {
entry:
ret void, !dbg !15
}
; Function Attrs: nounwind ssp uwtable
define void @g() #0 !dbg !9 {
entry:
ret void, !dbg !16
}
attributes #0 = { nounwind ssp uwtable }
!llvm.dbg.cu = !{!0, !7}
!llvm.ident = !{!11, !11}
!llvm.module.flags = !{!12, !13, !14}
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 3.9.0 (trunk 265328) (llvm/trunk 265330)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, subprograms: !3)
!1 = !DIFile(filename: "test.c", directory: "/Volumes/Data/llvm")
!2 = !{}
!3 = !{!4}
!4 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 1, type: !5, isLocal: false, isDefinition: true, scopeLine: 1, isOptimized: false, variables: !2)
!5 = !DISubroutineType(types: !6)
!6 = !{null}
!7 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 3.9.0 (trunk 265328) (llvm/trunk 265330)", isOptimized: false, runtimeVersion: 0, emissionKind: NoDebug, enums: !2, subprograms: !8)
!8 = !{!9}
!9 = distinct !DISubprogram(name: "g", scope: !1, file: !1, line: 1, type: !10, isLocal: false, isDefinition: true, scopeLine: 1, isOptimized: false, variables: !2)
!10 = !DISubroutineType(types: !2)
!11 = !{!"clang version 3.9.0 (trunk 265328) (llvm/trunk 265330)"}
!12 = !{i32 2, !"Dwarf Version", i32 2}
!13 = !{i32 2, !"Debug Info Version", i32 3}
!14 = !{i32 1, !"PIC Level", i32 2}
!15 = !DILocation(line: 1, column: 12, scope: !4)
!16 = !DILocation(line: 1, column: 12, scope: !9)

View File

@ -45,9 +45,7 @@ struct BreakpointPrinter : public ModulePass {
bool runOnModule(Module &M) override { bool runOnModule(Module &M) override {
TypeIdentifierMap.clear(); TypeIdentifierMap.clear();
NamedMDNode *CU_Nodes = M.getNamedMetadata("llvm.dbg.cu"); TypeIdentifierMap = generateDITypeIdentifierMap(M);
if (CU_Nodes)
TypeIdentifierMap = generateDITypeIdentifierMap(CU_Nodes);
StringSet<> Processed; StringSet<> Processed;
if (NamedMDNode *NMD = M.getNamedMetadata("llvm.dbg.sp")) if (NamedMDNode *NMD = M.getNamedMetadata("llvm.dbg.sp"))