mirror of
https://github.com/RPCSX/llvm.git
synced 2024-11-30 15:10:33 +00:00
DWARF: Avoid cross-CU references under Fission
Turns out that the Fission/Split DWARF package format (DWP) is currently insufficient to handle cross-CU (ref_addr) references. So for now, duplicate any debug info needed in these situations: * inlined_subroutine's abstract_origin * inlined variable's abstract_origin * types Keep the ref_addr behavior in general, including in the split DWARF inline debug info that can be emitted into the object files for online symbolication. Keep a flag to use the old (ref_addr) behavior for testing ways of addressing this limitation in the DWP tool (& for those not using DWP packaging). git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@302858 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
022fc8e3fd
commit
054c35d6a2
@ -440,7 +440,7 @@ DIE *DwarfCompileUnit::constructInlinedScopeDIE(LexicalScope *Scope) {
|
||||
auto *InlinedSP = getDISubprogram(DS);
|
||||
// Find the subprogram's DwarfCompileUnit in the SPMap in case the subprogram
|
||||
// was inlined from another compile unit.
|
||||
DIE *OriginDIE = DU->getAbstractSPDies()[InlinedSP];
|
||||
DIE *OriginDIE = getAbstractSPDies()[InlinedSP];
|
||||
assert(OriginDIE && "Unable to find original DIE for an inlined subprogram.");
|
||||
|
||||
auto ScopeDIE = DIE::get(DIEValueAllocator, dwarf::DW_TAG_inlined_subroutine);
|
||||
@ -634,7 +634,7 @@ DIE *DwarfCompileUnit::createAndAddScopeChildren(LexicalScope *Scope,
|
||||
|
||||
void DwarfCompileUnit::constructAbstractSubprogramScopeDIE(
|
||||
LexicalScope *Scope) {
|
||||
DIE *&AbsDef = DU->getAbstractSPDies()[Scope->getScopeNode()];
|
||||
DIE *&AbsDef = getAbstractSPDies()[Scope->getScopeNode()];
|
||||
if (AbsDef)
|
||||
return;
|
||||
|
||||
@ -696,7 +696,7 @@ DIE *DwarfCompileUnit::constructImportedEntityDIE(
|
||||
|
||||
void DwarfCompileUnit::finishSubprogramDefinition(const DISubprogram *SP) {
|
||||
DIE *D = getDIE(SP);
|
||||
if (DIE *AbsSPDIE = DU->getAbstractSPDies().lookup(SP)) {
|
||||
if (DIE *AbsSPDIE = getAbstractSPDies().lookup(SP)) {
|
||||
if (D)
|
||||
// If this subprogram has an abstract definition, reference that
|
||||
addDIEEntry(*D, dwarf::DW_AT_abstract_origin, *AbsSPDIE);
|
||||
@ -708,6 +708,42 @@ void DwarfCompileUnit::finishSubprogramDefinition(const DISubprogram *SP) {
|
||||
}
|
||||
}
|
||||
|
||||
void DwarfCompileUnit::finishVariableDefinition(const DbgVariable &Var) {
|
||||
DbgVariable *AbsVar = getExistingAbstractVariable(
|
||||
InlinedVariable(Var.getVariable(), Var.getInlinedAt()));
|
||||
auto *VariableDie = Var.getDIE();
|
||||
if (AbsVar && AbsVar->getDIE()) {
|
||||
addDIEEntry(*VariableDie, dwarf::DW_AT_abstract_origin,
|
||||
*AbsVar->getDIE());
|
||||
} else
|
||||
applyVariableAttributes(Var, *VariableDie);
|
||||
}
|
||||
|
||||
DbgVariable *DwarfCompileUnit::getExistingAbstractVariable(InlinedVariable IV) {
|
||||
const DILocalVariable *Cleansed;
|
||||
return getExistingAbstractVariable(IV, Cleansed);
|
||||
}
|
||||
|
||||
// Find abstract variable, if any, associated with Var.
|
||||
DbgVariable *DwarfCompileUnit::getExistingAbstractVariable(
|
||||
InlinedVariable IV, const DILocalVariable *&Cleansed) {
|
||||
// More then one inlined variable corresponds to one abstract variable.
|
||||
Cleansed = IV.first;
|
||||
auto &AbstractVariables = getAbstractVariables();
|
||||
auto I = AbstractVariables.find(Cleansed);
|
||||
if (I != AbstractVariables.end())
|
||||
return I->second.get();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void DwarfCompileUnit::createAbstractVariable(const DILocalVariable *Var,
|
||||
LexicalScope *Scope) {
|
||||
assert(Scope && Scope->isAbstractScope());
|
||||
auto AbsDbgVariable = make_unique<DbgVariable>(Var, /* IA */ nullptr);
|
||||
DU->addScopeVariable(Scope, AbsDbgVariable.get());
|
||||
getAbstractVariables()[Var] = std::move(AbsDbgVariable);
|
||||
}
|
||||
|
||||
void DwarfCompileUnit::emitHeader(bool UseOffsets) {
|
||||
// Don't bother labeling the .dwo unit, as its offset isn't used.
|
||||
if (!Skeleton) {
|
||||
|
@ -68,6 +68,9 @@ class DwarfCompileUnit final : public DwarfUnit {
|
||||
// ranges/locs.
|
||||
const MCSymbol *BaseAddress;
|
||||
|
||||
DenseMap<const MDNode *, DIE *> AbstractSPDies;
|
||||
DenseMap<const MDNode *, std::unique_ptr<DbgVariable>> AbstractVariables;
|
||||
|
||||
/// \brief Construct a DIE for the given DbgVariable without initializing the
|
||||
/// DbgVariable's DIE reference.
|
||||
DIE *constructVariableDIEImpl(const DbgVariable &DV, bool Abstract);
|
||||
@ -76,6 +79,18 @@ class DwarfCompileUnit final : public DwarfUnit {
|
||||
|
||||
bool includeMinimalInlineScopes() const;
|
||||
|
||||
DenseMap<const MDNode *, DIE *> &getAbstractSPDies() {
|
||||
if (isDwoUnit() && !DD->shareAcrossDWOCUs())
|
||||
return AbstractSPDies;
|
||||
return DU->getAbstractSPDies();
|
||||
}
|
||||
|
||||
DenseMap<const MDNode *, std::unique_ptr<DbgVariable>> &getAbstractVariables() {
|
||||
if (isDwoUnit() && !DD->shareAcrossDWOCUs())
|
||||
return AbstractVariables;
|
||||
return DU->getAbstractVariables();
|
||||
}
|
||||
|
||||
public:
|
||||
DwarfCompileUnit(unsigned UID, const DICompileUnit *Node, AsmPrinter *A,
|
||||
DwarfDebug *DW, DwarfFile *DWU);
|
||||
@ -189,6 +204,13 @@ public:
|
||||
DIE *constructImportedEntityDIE(const DIImportedEntity *Module);
|
||||
|
||||
void finishSubprogramDefinition(const DISubprogram *SP);
|
||||
void finishVariableDefinition(const DbgVariable &Var);
|
||||
/// Find abstract variable associated with Var.
|
||||
typedef DbgValueHistoryMap::InlinedVariable InlinedVariable;
|
||||
DbgVariable *getExistingAbstractVariable(InlinedVariable IV,
|
||||
const DILocalVariable *&Cleansed);
|
||||
DbgVariable *getExistingAbstractVariable(InlinedVariable IV);
|
||||
void createAbstractVariable(const DILocalVariable *DV, LexicalScope *Scope);
|
||||
|
||||
/// Set the skeleton unit associated with this unit.
|
||||
void setSkeleton(DwarfCompileUnit &Skel) { Skeleton = &Skel; }
|
||||
|
@ -71,6 +71,10 @@ static cl::opt<bool> GenerateARangeSection("generate-arange-section",
|
||||
cl::desc("Generate dwarf aranges"),
|
||||
cl::init(false));
|
||||
|
||||
static cl::opt<bool> SplitDwarfCrossCuReferences(
|
||||
"split-dwarf-cross-cu-references", cl::Hidden,
|
||||
cl::desc("Enable cross-cu references in DWO files"), cl::init(false));
|
||||
|
||||
namespace {
|
||||
enum DefaultOnOff { Default, Enable, Disable };
|
||||
}
|
||||
@ -362,21 +366,29 @@ template <typename Func> static void forBothCUs(DwarfCompileUnit &CU, Func F) {
|
||||
F(*SkelCU);
|
||||
}
|
||||
|
||||
void DwarfDebug::constructAbstractSubprogramScopeDIE(LexicalScope *Scope) {
|
||||
bool DwarfDebug::shareAcrossDWOCUs() const {
|
||||
return SplitDwarfCrossCuReferences;
|
||||
}
|
||||
|
||||
void DwarfDebug::constructAbstractSubprogramScopeDIE(DwarfCompileUnit &SrcCU,
|
||||
LexicalScope *Scope) {
|
||||
assert(Scope && Scope->getScopeNode());
|
||||
assert(Scope->isAbstractScope());
|
||||
assert(!Scope->getInlinedAt());
|
||||
|
||||
auto *SP = cast<DISubprogram>(Scope->getScopeNode());
|
||||
|
||||
ProcessedSPNodes.insert(SP);
|
||||
|
||||
// Find the subprogram's DwarfCompileUnit in the SPMap in case the subprogram
|
||||
// was inlined from another compile unit.
|
||||
auto &CU = *CUMap.lookup(SP->getUnit());
|
||||
forBothCUs(CU, [&](DwarfCompileUnit &CU) {
|
||||
if (auto *SkelCU = CU.getSkeleton()) {
|
||||
(shareAcrossDWOCUs() ? CU : SrcCU)
|
||||
.constructAbstractSubprogramScopeDIE(Scope);
|
||||
if (CU.getCUNode()->getSplitDebugInlining())
|
||||
SkelCU->constructAbstractSubprogramScopeDIE(Scope);
|
||||
} else {
|
||||
CU.constructAbstractSubprogramScopeDIE(Scope);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void DwarfDebug::addGnuPubAttributes(DwarfUnit &U, DIE &D) const {
|
||||
@ -564,13 +576,7 @@ void DwarfDebug::finishVariableDefinitions() {
|
||||
// DIE::getUnit isn't simple - it walks parent pointers, etc.
|
||||
DwarfCompileUnit *Unit = CUDieMap.lookup(VariableDie->getUnitDie());
|
||||
assert(Unit);
|
||||
DbgVariable *AbsVar = getExistingAbstractVariable(
|
||||
InlinedVariable(Var->getVariable(), Var->getInlinedAt()));
|
||||
if (AbsVar && AbsVar->getDIE()) {
|
||||
Unit->addDIEEntry(*VariableDie, dwarf::DW_AT_abstract_origin,
|
||||
*AbsVar->getDIE());
|
||||
} else
|
||||
Unit->applyVariableAttributes(*Var, *VariableDie);
|
||||
Unit->finishVariableDefinition(*Var);
|
||||
}
|
||||
}
|
||||
|
||||
@ -718,58 +724,32 @@ void DwarfDebug::endModule() {
|
||||
}
|
||||
|
||||
// clean up.
|
||||
AbstractVariables.clear();
|
||||
// FIXME: AbstractVariables.clear();
|
||||
}
|
||||
|
||||
// Find abstract variable, if any, associated with Var.
|
||||
DbgVariable *
|
||||
DwarfDebug::getExistingAbstractVariable(InlinedVariable IV,
|
||||
const DILocalVariable *&Cleansed) {
|
||||
// More then one inlined variable corresponds to one abstract variable.
|
||||
Cleansed = IV.first;
|
||||
auto I = AbstractVariables.find(Cleansed);
|
||||
if (I != AbstractVariables.end())
|
||||
return I->second.get();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DbgVariable *DwarfDebug::getExistingAbstractVariable(InlinedVariable IV) {
|
||||
const DILocalVariable *Cleansed;
|
||||
return getExistingAbstractVariable(IV, Cleansed);
|
||||
}
|
||||
|
||||
void DwarfDebug::createAbstractVariable(const DILocalVariable *Var,
|
||||
LexicalScope *Scope) {
|
||||
assert(Scope && Scope->isAbstractScope());
|
||||
auto AbsDbgVariable = make_unique<DbgVariable>(Var, /* IA */ nullptr);
|
||||
InfoHolder.addScopeVariable(Scope, AbsDbgVariable.get());
|
||||
AbstractVariables[Var] = std::move(AbsDbgVariable);
|
||||
}
|
||||
|
||||
void DwarfDebug::ensureAbstractVariableIsCreated(InlinedVariable IV,
|
||||
void DwarfDebug::ensureAbstractVariableIsCreated(DwarfCompileUnit &CU, InlinedVariable IV,
|
||||
const MDNode *ScopeNode) {
|
||||
const DILocalVariable *Cleansed = nullptr;
|
||||
if (getExistingAbstractVariable(IV, Cleansed))
|
||||
if (CU.getExistingAbstractVariable(IV, Cleansed))
|
||||
return;
|
||||
|
||||
createAbstractVariable(Cleansed, LScopes.getOrCreateAbstractScope(
|
||||
CU.createAbstractVariable(Cleansed, LScopes.getOrCreateAbstractScope(
|
||||
cast<DILocalScope>(ScopeNode)));
|
||||
}
|
||||
|
||||
void DwarfDebug::ensureAbstractVariableIsCreatedIfScoped(
|
||||
void DwarfDebug::ensureAbstractVariableIsCreatedIfScoped(DwarfCompileUnit &CU,
|
||||
InlinedVariable IV, const MDNode *ScopeNode) {
|
||||
const DILocalVariable *Cleansed = nullptr;
|
||||
if (getExistingAbstractVariable(IV, Cleansed))
|
||||
if (CU.getExistingAbstractVariable(IV, Cleansed))
|
||||
return;
|
||||
|
||||
if (LexicalScope *Scope =
|
||||
LScopes.findAbstractScope(cast_or_null<DILocalScope>(ScopeNode)))
|
||||
createAbstractVariable(Cleansed, Scope);
|
||||
CU.createAbstractVariable(Cleansed, Scope);
|
||||
}
|
||||
|
||||
// Collect variable information from side table maintained by MF.
|
||||
void DwarfDebug::collectVariableInfoFromMFTable(
|
||||
DenseSet<InlinedVariable> &Processed) {
|
||||
DwarfCompileUnit &TheCU, DenseSet<InlinedVariable> &Processed) {
|
||||
for (const auto &VI : Asm->MF->getVariableDbgInfo()) {
|
||||
if (!VI.Var)
|
||||
continue;
|
||||
@ -784,7 +764,7 @@ void DwarfDebug::collectVariableInfoFromMFTable(
|
||||
if (!Scope)
|
||||
continue;
|
||||
|
||||
ensureAbstractVariableIsCreatedIfScoped(Var, Scope->getScopeNode());
|
||||
ensureAbstractVariableIsCreatedIfScoped(TheCU, Var, Scope->getScopeNode());
|
||||
auto RegVar = make_unique<DbgVariable>(Var.first, Var.second);
|
||||
RegVar->initializeMMI(VI.Expr, VI.Slot);
|
||||
if (InfoHolder.addScopeVariable(Scope, RegVar.get()))
|
||||
@ -955,9 +935,10 @@ DwarfDebug::buildLocationList(SmallVectorImpl<DebugLocEntry> &DebugLoc,
|
||||
}
|
||||
}
|
||||
|
||||
DbgVariable *DwarfDebug::createConcreteVariable(LexicalScope &Scope,
|
||||
DbgVariable *DwarfDebug::createConcreteVariable(DwarfCompileUnit &TheCU,
|
||||
LexicalScope &Scope,
|
||||
InlinedVariable IV) {
|
||||
ensureAbstractVariableIsCreatedIfScoped(IV, Scope.getScopeNode());
|
||||
ensureAbstractVariableIsCreatedIfScoped(TheCU, IV, Scope.getScopeNode());
|
||||
ConcreteVariables.push_back(make_unique<DbgVariable>(IV.first, IV.second));
|
||||
InfoHolder.addScopeVariable(&Scope, ConcreteVariables.back().get());
|
||||
return ConcreteVariables.back().get();
|
||||
@ -980,7 +961,7 @@ void DwarfDebug::collectVariableInfo(DwarfCompileUnit &TheCU,
|
||||
const DISubprogram *SP,
|
||||
DenseSet<InlinedVariable> &Processed) {
|
||||
// Grab the variable info that was squirreled away in the MMI side-table.
|
||||
collectVariableInfoFromMFTable(Processed);
|
||||
collectVariableInfoFromMFTable(TheCU, Processed);
|
||||
|
||||
for (const auto &I : DbgValues) {
|
||||
InlinedVariable IV = I.first;
|
||||
@ -1002,7 +983,7 @@ void DwarfDebug::collectVariableInfo(DwarfCompileUnit &TheCU,
|
||||
continue;
|
||||
|
||||
Processed.insert(IV);
|
||||
DbgVariable *RegVar = createConcreteVariable(*Scope, IV);
|
||||
DbgVariable *RegVar = createConcreteVariable(TheCU, *Scope, IV);
|
||||
|
||||
const MachineInstr *MInsn = Ranges.front().first;
|
||||
assert(MInsn->isDebugValue() && "History must begin with debug value");
|
||||
@ -1038,7 +1019,7 @@ void DwarfDebug::collectVariableInfo(DwarfCompileUnit &TheCU,
|
||||
for (const DILocalVariable *DV : SP->getVariables()) {
|
||||
if (Processed.insert(InlinedVariable(DV, nullptr)).second)
|
||||
if (LexicalScope *Scope = LScopes.findLexicalScope(DV->getScope()))
|
||||
createConcreteVariable(*Scope, InlinedVariable(DV, nullptr));
|
||||
createConcreteVariable(TheCU, *Scope, InlinedVariable(DV, nullptr));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1229,12 +1210,12 @@ void DwarfDebug::endFunctionImpl(const MachineFunction *MF) {
|
||||
for (const DILocalVariable *DV : SP->getVariables()) {
|
||||
if (!ProcessedVars.insert(InlinedVariable(DV, nullptr)).second)
|
||||
continue;
|
||||
ensureAbstractVariableIsCreated(InlinedVariable(DV, nullptr),
|
||||
ensureAbstractVariableIsCreated(TheCU, InlinedVariable(DV, nullptr),
|
||||
DV->getScope());
|
||||
assert(LScopes.getAbstractScopesList().size() == NumAbstractScopes
|
||||
&& "ensureAbstractVariableIsCreated inserted abstract scopes");
|
||||
}
|
||||
constructAbstractSubprogramScopeDIE(AScope);
|
||||
constructAbstractSubprogramScopeDIE(TheCU, AScope);
|
||||
}
|
||||
|
||||
ProcessedSPNodes.insert(SP);
|
||||
|
@ -210,7 +210,6 @@ class DwarfDebug : public DebugHandlerBase {
|
||||
DenseMap<const MCSymbol *, uint64_t> SymSize;
|
||||
|
||||
/// Collection of abstract variables.
|
||||
DenseMap<const MDNode *, std::unique_ptr<DbgVariable>> AbstractVariables;
|
||||
SmallVector<std::unique_ptr<DbgVariable>, 64> ConcreteVariables;
|
||||
|
||||
/// Collection of DebugLocEntry. Stored in a linked list so that DIELocLists
|
||||
@ -313,20 +312,16 @@ class DwarfDebug : public DebugHandlerBase {
|
||||
|
||||
typedef DbgValueHistoryMap::InlinedVariable InlinedVariable;
|
||||
|
||||
/// Find abstract variable associated with Var.
|
||||
DbgVariable *getExistingAbstractVariable(InlinedVariable IV,
|
||||
const DILocalVariable *&Cleansed);
|
||||
DbgVariable *getExistingAbstractVariable(InlinedVariable IV);
|
||||
void createAbstractVariable(const DILocalVariable *DV, LexicalScope *Scope);
|
||||
void ensureAbstractVariableIsCreated(InlinedVariable Var,
|
||||
void ensureAbstractVariableIsCreated(DwarfCompileUnit &CU, InlinedVariable Var,
|
||||
const MDNode *Scope);
|
||||
void ensureAbstractVariableIsCreatedIfScoped(InlinedVariable Var,
|
||||
void ensureAbstractVariableIsCreatedIfScoped(DwarfCompileUnit &CU, InlinedVariable Var,
|
||||
const MDNode *Scope);
|
||||
|
||||
DbgVariable *createConcreteVariable(LexicalScope &Scope, InlinedVariable IV);
|
||||
DbgVariable *createConcreteVariable(DwarfCompileUnit &TheCU,
|
||||
LexicalScope &Scope, InlinedVariable IV);
|
||||
|
||||
/// Construct a DIE for this abstract scope.
|
||||
void constructAbstractSubprogramScopeDIE(LexicalScope *Scope);
|
||||
void constructAbstractSubprogramScopeDIE(DwarfCompileUnit &SrcCU, LexicalScope *Scope);
|
||||
|
||||
void finishVariableDefinitions();
|
||||
|
||||
@ -446,7 +441,8 @@ class DwarfDebug : public DebugHandlerBase {
|
||||
const DbgValueHistoryMap::InstrRanges &Ranges);
|
||||
|
||||
/// Collect variable information from the side table maintained by MF.
|
||||
void collectVariableInfoFromMFTable(DenseSet<InlinedVariable> &P);
|
||||
void collectVariableInfoFromMFTable(DwarfCompileUnit &TheCU,
|
||||
DenseSet<InlinedVariable> &P);
|
||||
|
||||
protected:
|
||||
/// Gather pre-function debug information.
|
||||
@ -518,6 +514,8 @@ public:
|
||||
/// split dwarf proposal support.
|
||||
bool useSplitDwarf() const { return HasSplitDwarf; }
|
||||
|
||||
bool shareAcrossDWOCUs() const;
|
||||
|
||||
/// Returns the Dwarf Version.
|
||||
uint16_t getDwarfVersion() const;
|
||||
|
||||
|
@ -53,6 +53,7 @@ class DwarfFile {
|
||||
|
||||
// Collection of abstract subprogram DIEs.
|
||||
DenseMap<const MDNode *, DIE *> AbstractSPDies;
|
||||
DenseMap<const MDNode *, std::unique_ptr<DbgVariable>> AbstractVariables;
|
||||
|
||||
/// Maps MDNodes for type system with the corresponding DIEs. These DIEs can
|
||||
/// be shared across CUs, that is why we keep the map here instead
|
||||
@ -105,6 +106,9 @@ public:
|
||||
DenseMap<const MDNode *, DIE *> &getAbstractSPDies() {
|
||||
return AbstractSPDies;
|
||||
}
|
||||
DenseMap<const MDNode *, std::unique_ptr<DbgVariable>> &getAbstractVariables() {
|
||||
return AbstractVariables;
|
||||
}
|
||||
|
||||
void insertDIE(const MDNode *TypeMD, DIE *Die) {
|
||||
DITypeNodeToDieMap.insert(std::make_pair(TypeMD, Die));
|
||||
|
@ -173,7 +173,7 @@ int64_t DwarfUnit::getDefaultLowerBound() const {
|
||||
}
|
||||
|
||||
/// Check whether the DIE for this MDNode can be shared across CUs.
|
||||
static bool isShareableAcrossCUs(const DINode *D) {
|
||||
bool DwarfUnit::isShareableAcrossCUs(const DINode *D) const {
|
||||
// When the MDNode can be part of the type system, the DIE can be shared
|
||||
// across CUs.
|
||||
// Combining type units and cross-CU DIE sharing is lower value (since
|
||||
@ -181,6 +181,8 @@ static bool isShareableAcrossCUs(const DINode *D) {
|
||||
// level already) but may be implementable for some value in projects
|
||||
// building multiple independent libraries with LTO and then linking those
|
||||
// together.
|
||||
if (isDwoUnit() && !DD->shareAcrossDWOCUs())
|
||||
return false;
|
||||
return (isa<DIType>(D) ||
|
||||
(isa<DISubprogram>(D) && !cast<DISubprogram>(D)->isDefinition())) &&
|
||||
!GenerateDwarfTypeUnits;
|
||||
|
@ -103,6 +103,9 @@ protected:
|
||||
|
||||
bool applySubprogramDefinitionAttributes(const DISubprogram *SP, DIE &SPDie);
|
||||
|
||||
bool shareAcrossDWOCUs() const;
|
||||
bool isShareableAcrossCUs(const DINode *D) const;
|
||||
|
||||
public:
|
||||
// Accessors.
|
||||
AsmPrinter* getAsmPrinter() const { return Asm; }
|
||||
|
@ -1,46 +1,194 @@
|
||||
; RUN: llc -mtriple=x86_64-linux -split-dwarf-file=foo.dwo -filetype=obj -o - < %s | llvm-objdump -r - | FileCheck %s
|
||||
; RUN: llc -mtriple=x86_64-linux -split-dwarf-cross-cu-references -split-dwarf-file=foo.dwo -filetype=obj -o %t < %s
|
||||
; RUN: llvm-objdump -r %t | FileCheck %s
|
||||
; RUN: llvm-dwarfdump -debug-dump=info.dwo %t | FileCheck --check-prefix=ALL --check-prefix=INFO --check-prefix=DWO --check-prefix=CROSS %s
|
||||
; RUN: llvm-dwarfdump -debug-dump=info %t | FileCheck --check-prefix=ALL --check-prefix=INFO %s
|
||||
|
||||
; RUN: llc -mtriple=x86_64-linux -split-dwarf-file=foo.dwo -filetype=obj -o %t < %s
|
||||
; RUN: llvm-objdump -r %t | FileCheck %s
|
||||
; RUN: llvm-dwarfdump -debug-dump=info.dwo %t | FileCheck --check-prefix=ALL --check-prefix=DWO --check-prefix=NOCROSS %s
|
||||
; RUN: llvm-dwarfdump -debug-dump=info %t | FileCheck --check-prefix=ALL --check-prefix=INFO %s
|
||||
|
||||
; Testing cross-CU references for types, subprograms, and variables
|
||||
; Built from code something like this:
|
||||
; foo.cpp:
|
||||
; struct t1 { int i; };
|
||||
; void f();
|
||||
; __attribute__((always_inline)) void f1(t1 t) {
|
||||
; f();
|
||||
; }
|
||||
; void foo(t1 t) {
|
||||
; f1(t);
|
||||
; }
|
||||
; bar.cpp:
|
||||
; struct t1 { int i; };
|
||||
; void f1(t1);
|
||||
; void bar(t1 t) {
|
||||
; f1(t);
|
||||
; }
|
||||
; $ clang++-tot -emit-llvm -S {foo,bar}.cpp -g
|
||||
; $ llvm-link-tot {foo,bar}.ll -S -o foobar.ll
|
||||
; $ clang++-tot -emit-llvm foobar.ll -o foobar.opt.ll -S -c
|
||||
;
|
||||
; Then manually removing the original f1 definition, to simplify the DWARF a bit
|
||||
; (so it only has the inlined definitions, no concrete definition)
|
||||
|
||||
; Check that:
|
||||
; * no relocations are emitted for the debug_info.dwo section no matter what
|
||||
; * one debug_info->debug_info relocation in debug_info no matter what (for
|
||||
; split dwarf inlining)
|
||||
; * debug_info uses relocations and ref_addr no matter what
|
||||
; * debug_info.dwo uses relocations for types as well as abstract subprograms
|
||||
; and variables when -split-dwarf-cross-cu-references is used
|
||||
; * debug_info.dwo contains duplicate types, abstract subprograms and abstract
|
||||
; variables otherwise to avoid the need for cross-cu references
|
||||
|
||||
; CHECK-NOT: .rel{{a?}}.debug_info.dwo
|
||||
; CHECK: RELOCATION RECORDS FOR [.rel{{a?}}.debug_info]:
|
||||
; CHECK-NOT: RELOCATION RECORDS
|
||||
; Expect one relocation in debug_info, between f3 and f1.
|
||||
; Expect one relocation in debug_info, from the inlined f1 in foo to its
|
||||
; abstract origin in bar
|
||||
; CHECK: R_X86_64_32 .debug_info
|
||||
; CHECK-NOT: RELOCATION RECORDS
|
||||
; CHECK-NOT: .debug_info
|
||||
; CHECK: RELOCATION RECORDS
|
||||
; CHECK-NOT: .rel{{a?}}.debug_info.dwo
|
||||
|
||||
; ALL: Compile Unit
|
||||
; ALL: DW_TAG_compile_unit
|
||||
; DWO: DW_AT_name {{.*}} "foo.cpp"
|
||||
; ALL: 0x[[F1:.*]]: DW_TAG_subprogram
|
||||
; ALL: DW_AT_name {{.*}} "f1"
|
||||
; DWO: 0x[[F1T:.*]]: DW_TAG_formal_parameter
|
||||
; DWO: DW_AT_name {{.*}} "t"
|
||||
; DWO: DW_AT_type [DW_FORM_ref4] {{.*}}{0x[[T1:.*]]}
|
||||
; DWO: NULL
|
||||
; DWO: 0x[[T1]]: DW_TAG_structure_type
|
||||
; DWO: DW_AT_name {{.*}} "t1"
|
||||
; ALL: DW_TAG_subprogram
|
||||
; ALL: DW_AT_name {{.*}} "foo"
|
||||
; DWO: DW_TAG_formal_parameter
|
||||
; DWO: DW_AT_name {{.*}} "t"
|
||||
; DWO: DW_AT_type [DW_FORM_ref4] {{.*}}{0x[[T1]]}
|
||||
; ALL: DW_TAG_inlined_subroutine
|
||||
; ALL: DW_AT_abstract_origin [DW_FORM_ref4] {{.*}}{0x[[F1]]}
|
||||
; DWO: DW_TAG_formal_parameter
|
||||
; DWO: DW_AT_abstract_origin [DW_FORM_ref4] {{.*}}{0x[[F1T]]}
|
||||
|
||||
; Function Attrs: noinline nounwind optnone uwtable
|
||||
define void @_Z2f1v() !dbg !7 {
|
||||
entry:
|
||||
ret void, !dbg !10
|
||||
}
|
||||
; ALL: Compile Unit
|
||||
; ALL: DW_TAG_compile_unit
|
||||
; DWO: DW_AT_name {{.*}} "bar.cpp"
|
||||
; NOCROSS: 0x[[BAR_F1:.*]]: DW_TAG_subprogram
|
||||
; NOCROSS: DW_AT_name {{.*}} "f1"
|
||||
; NOCROSS: 0x[[BAR_F1T:.*]]: DW_TAG_formal_parameter
|
||||
; NOCROSS: DW_AT_name {{.*}} "t"
|
||||
; NOCROSS: DW_AT_type [DW_FORM_ref4] {{.*}}{0x[[BAR_T1:.*]]}
|
||||
; NOCROSS: NULL
|
||||
; NOCROSS: 0x[[BAR_T1]]: DW_TAG_structure_type
|
||||
; NOCROSS: DW_AT_name {{.*}} "t1"
|
||||
; ALL: DW_TAG_subprogram
|
||||
; ALL: DW_AT_name {{.*}} "bar"
|
||||
; DWO: DW_TAG_formal_parameter
|
||||
; DWO: DW_AT_name {{.*}} "t"
|
||||
; CROSS: DW_AT_type [DW_FORM_ref_addr] (0x00000000[[T1]]
|
||||
; NOCROSS: DW_AT_type [DW_FORM_ref4] {{.*}}{0x[[BAR_T1]]}
|
||||
; ALL: DW_TAG_inlined_subroutine
|
||||
; INFO: DW_AT_abstract_origin [DW_FORM_ref_addr] (0x00000000[[F1]]
|
||||
; NOCROSS: DW_AT_abstract_origin [DW_FORM_ref4] {{.*}}{0x[[BAR_F1]]}
|
||||
; DWO: DW_TAG_formal_parameter
|
||||
; CROSS: DW_AT_abstract_origin [DW_FORM_ref_addr] (0x00000000[[F1T]]
|
||||
; NOCROSS: DW_AT_abstract_origin [DW_FORM_ref4] {{.*}}{0x[[BAR_F1T]]
|
||||
|
||||
%struct.t1 = type { i32 }
|
||||
|
||||
; Function Attrs: nounwind readnone speculatable
|
||||
declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
|
||||
|
||||
declare void @_Z1fv() #2
|
||||
|
||||
; Function Attrs: noinline uwtable
|
||||
define void @_Z2f3v() !dbg !13 {
|
||||
define void @_Z3foo2t1(i32 %t.coerce) #3 !dbg !20 {
|
||||
entry:
|
||||
call void @_Z2f1v(), !dbg !14
|
||||
ret void, !dbg !16
|
||||
%t.i = alloca %struct.t1, align 4
|
||||
call void @llvm.dbg.declare(metadata %struct.t1* %t.i, metadata !15, metadata !16), !dbg !21
|
||||
%t = alloca %struct.t1, align 4
|
||||
%agg.tmp = alloca %struct.t1, align 4
|
||||
%coerce.dive = getelementptr inbounds %struct.t1, %struct.t1* %t, i32 0, i32 0
|
||||
store i32 %t.coerce, i32* %coerce.dive, align 4
|
||||
call void @llvm.dbg.declare(metadata %struct.t1* %t, metadata !23, metadata !16), !dbg !24
|
||||
%0 = bitcast %struct.t1* %agg.tmp to i8*, !dbg !25
|
||||
%1 = bitcast %struct.t1* %t to i8*, !dbg !25
|
||||
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* %1, i64 4, i32 4, i1 false), !dbg !25
|
||||
%coerce.dive1 = getelementptr inbounds %struct.t1, %struct.t1* %agg.tmp, i32 0, i32 0, !dbg !26
|
||||
%2 = load i32, i32* %coerce.dive1, align 4, !dbg !26
|
||||
%coerce.dive.i = getelementptr inbounds %struct.t1, %struct.t1* %t.i, i32 0, i32 0
|
||||
store i32 %2, i32* %coerce.dive.i, align 4
|
||||
call void @_Z1fv(), !dbg !27
|
||||
ret void, !dbg !28
|
||||
}
|
||||
|
||||
; Function Attrs: argmemonly nounwind
|
||||
declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i32, i1) #4
|
||||
|
||||
; Function Attrs: noinline uwtable
|
||||
define void @_Z3bar2t1(i32 %t.coerce) #3 !dbg !29 {
|
||||
entry:
|
||||
%t.i = alloca %struct.t1, align 4
|
||||
call void @llvm.dbg.declare(metadata %struct.t1* %t.i, metadata !15, metadata !16), !dbg !30
|
||||
%t = alloca %struct.t1, align 4
|
||||
%agg.tmp = alloca %struct.t1, align 4
|
||||
%coerce.dive = getelementptr inbounds %struct.t1, %struct.t1* %t, i32 0, i32 0
|
||||
store i32 %t.coerce, i32* %coerce.dive, align 4
|
||||
call void @llvm.dbg.declare(metadata %struct.t1* %t, metadata !32, metadata !16), !dbg !33
|
||||
%0 = bitcast %struct.t1* %agg.tmp to i8*, !dbg !34
|
||||
%1 = bitcast %struct.t1* %t to i8*, !dbg !34
|
||||
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* %1, i64 4, i32 4, i1 false), !dbg !34
|
||||
%coerce.dive1 = getelementptr inbounds %struct.t1, %struct.t1* %agg.tmp, i32 0, i32 0, !dbg !35
|
||||
%2 = load i32, i32* %coerce.dive1, align 4, !dbg !35
|
||||
%coerce.dive.i = getelementptr inbounds %struct.t1, %struct.t1* %t.i, i32 0, i32 0
|
||||
store i32 %2, i32* %coerce.dive.i, align 4
|
||||
call void @_Z1fv(), !dbg !36
|
||||
ret void, !dbg !37
|
||||
}
|
||||
|
||||
!llvm.dbg.cu = !{!0, !3}
|
||||
!llvm.ident = !{!5, !5}
|
||||
!llvm.module.flags = !{!6}
|
||||
!llvm.module.flags = !{!6, !7}
|
||||
|
||||
!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 5.0.0 (trunk 301051) (llvm/trunk 301062)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
|
||||
!1 = !DIFile(filename: "a.cpp", directory: "/usr/local/google/home/blaikie/dev/scratch")
|
||||
!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 5.0.0 (trunk 302809) (llvm/trunk 302815)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: true)
|
||||
!1 = !DIFile(filename: "foo.cpp", directory: "/usr/local/google/home/blaikie/dev/scratch")
|
||||
!2 = !{}
|
||||
!3 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !4, producer: "clang version 5.0.0 (trunk 301051) (llvm/trunk 301062)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
|
||||
!4 = !DIFile(filename: "b.cpp", directory: "/usr/local/google/home/blaikie/dev/scratch")
|
||||
!5 = !{!"clang version 5.0.0 (trunk 301051) (llvm/trunk 301062)"}
|
||||
!6 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
!7 = distinct !DISubprogram(name: "f1", linkageName: "_Z2f1v", scope: !1, file: !1, line: 1, type: !8, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
|
||||
!8 = !DISubroutineType(types: !9)
|
||||
!9 = !{null}
|
||||
!10 = !DILocation(line: 1, scope: !7)
|
||||
!11 = distinct !DISubprogram(name: "f2", linkageName: "_Z2f2v", scope: !1, file: !1, line: 1, type: !8, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
|
||||
!12 = !DILocation(line: 1, scope: !11)
|
||||
!13 = distinct !DISubprogram(name: "f3", linkageName: "_Z2f3v", scope: !4, file: !4, line: 1, type: !8, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: false, unit: !3, variables: !2)
|
||||
!14 = !DILocation(line: 1, scope: !11, inlinedAt: !15)
|
||||
!15 = distinct !DILocation(line: 1, scope: !13)
|
||||
!16 = !DILocation(line: 1, scope: !13)
|
||||
!3 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !4, producer: "clang version 5.0.0 (trunk 302809) (llvm/trunk 302815)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: true)
|
||||
!4 = !DIFile(filename: "bar.cpp", directory: "/usr/local/google/home/blaikie/dev/scratch")
|
||||
!5 = !{!"clang version 5.0.0 (trunk 302809) (llvm/trunk 302815)"}
|
||||
!6 = !{i32 2, !"Dwarf Version", i32 4}
|
||||
!7 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
!8 = distinct !DISubprogram(name: "f1", linkageName: "_Z2f12t1", scope: !1, file: !1, line: 3, type: !9, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
|
||||
!9 = !DISubroutineType(types: !10)
|
||||
!10 = !{null, !11}
|
||||
!11 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t1", file: !1, line: 1, size: 32, elements: !12, identifier: "_ZTS2t1")
|
||||
!12 = !{!13}
|
||||
!13 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !11, file: !1, line: 1, baseType: !14, size: 32)
|
||||
!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
|
||||
!15 = !DILocalVariable(name: "t", arg: 1, scope: !8, file: !1, line: 3, type: !11)
|
||||
!16 = !DIExpression()
|
||||
!17 = !DILocation(line: 3, column: 43, scope: !8)
|
||||
!18 = !DILocation(line: 4, column: 3, scope: !8)
|
||||
!19 = !DILocation(line: 5, column: 1, scope: !8)
|
||||
!20 = distinct !DISubprogram(name: "foo", linkageName: "_Z3foo2t1", scope: !1, file: !1, line: 6, type: !9, isLocal: false, isDefinition: true, scopeLine: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
|
||||
!21 = !DILocation(line: 3, column: 43, scope: !8, inlinedAt: !22)
|
||||
!22 = distinct !DILocation(line: 7, column: 3, scope: !20)
|
||||
!23 = !DILocalVariable(name: "t", arg: 1, scope: !20, file: !1, line: 6, type: !11)
|
||||
!24 = !DILocation(line: 6, column: 13, scope: !20)
|
||||
!25 = !DILocation(line: 7, column: 6, scope: !20)
|
||||
!26 = !DILocation(line: 7, column: 3, scope: !20)
|
||||
!27 = !DILocation(line: 4, column: 3, scope: !8, inlinedAt: !22)
|
||||
!28 = !DILocation(line: 8, column: 1, scope: !20)
|
||||
!29 = distinct !DISubprogram(name: "bar", linkageName: "_Z3bar2t1", scope: !4, file: !4, line: 3, type: !9, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: false, unit: !3, variables: !2)
|
||||
!30 = !DILocation(line: 3, column: 43, scope: !8, inlinedAt: !31)
|
||||
!31 = distinct !DILocation(line: 4, column: 3, scope: !29)
|
||||
!32 = !DILocalVariable(name: "t", arg: 1, scope: !29, file: !4, line: 3, type: !11)
|
||||
!33 = !DILocation(line: 3, column: 13, scope: !29)
|
||||
!34 = !DILocation(line: 4, column: 6, scope: !29)
|
||||
!35 = !DILocation(line: 4, column: 3, scope: !29)
|
||||
!36 = !DILocation(line: 4, column: 3, scope: !8, inlinedAt: !31)
|
||||
!37 = !DILocation(line: 5, column: 1, scope: !29)
|
||||
|
Loading…
Reference in New Issue
Block a user