Page MenuHomePhabricator

[DebugInfo] Generate DWARF debug information for labels.
ClosedPublic

Authored by HsiangKai on Apr 12 2018, 1:15 AM.

Details

Summary

There are two forms for label debug information in DWARF format.

  1. Labels in a non-inlined function:

DW_TAG_label

DW_AT_name
DW_AT_decl_file
DW_AT_decl_line
DW_AT_low_pc
  1. Labels in an inlined function:

DW_TAG_label

DW_AT_abstract_origin
DW_AT_low_pc

We will collect label information from DBG_LABEL. Before every DBG_LABEL,
we will generate a temporary symbol to denote the location of the label.
The symbol could be used to get DW_AT_low_pc afterwards. So, we create a
mapping between 'inlined label' and DBG_LABEL MachineInstr in DebugHandlerBase.
The DBG_LABEL in the mapping is used to query the symbol before it.

The AbstractLabels in DwarfCompileUnit is used to process labels in inlined
functions.

We also keep a mapping between scope and labels in DwarfFile to help to
generate correct tree structure of DIEs.

Diff Detail

Repository
rL LLVM

Event Timeline

HsiangKai created this revision.Apr 12 2018, 1:15 AM
aprantl added inline comments.Apr 12 2018, 8:47 AM
lib/CodeGen/AsmPrinter/DebugHandlerBase.h
53 ↗(On Diff #142125)

Often it's better for readability to just define a struct with named members so we can access .label and .loc instead of .first and .second.

lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
490 ↗(On Diff #142125)

Please put the doxygen comment on the declaration and don't repeat the function name.

lib/CodeGen/AsmPrinter/DwarfDebug.cpp
1232 ↗(On Diff #142125)

This and the next function looks like it is almost the same code as createConcreteVariable and collectVariableInfo. Could the implementation be shared (see my comment on DwarfLabel)?

lib/CodeGen/AsmPrinter/DwarfDebug.h
191 ↗(On Diff #142125)

Could this share a common base with DbgVariable?

198 ↗(On Diff #142125)

///

202 ↗(On Diff #142125)
/// @{
/// Accessors.
208 ↗(On Diff #142125)

/// @}

210 ↗(On Diff #142125)

///

HsiangKai updated this revision to Diff 142532.Apr 14 2018, 7:00 PM

Update according to reviewers' comments.
Update test cases.

HsiangKai added inline comments.Apr 16 2018, 7:40 AM
lib/CodeGen/AsmPrinter/DebugHandlerBase.h
53 ↗(On Diff #142125)

If I group DILabel and DILocation in a struct, I need to add isEqual(), getHashValue(), getEmptyKey(), etc to conform the interface of MapVector. I think it is too complex for the purpose. std::pair is ready to use as the 'Key Type' of MapVector.

Use MapVector is easier to establish the mapping between InlinedLabel and MachineInstr.

HsiangKai marked 5 inline comments as done.Apr 16 2018, 8:03 AM
aprantl added inline comments.Apr 16 2018, 9:14 AM
lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp
170 ↗(On Diff #142532)

This comment should go to the declaration.

lib/CodeGen/AsmPrinter/DebugHandlerBase.h
53 ↗(On Diff #142125)

Fair point. One trick I've used in the past for situations like this is to define a struct that inherits from std::pair<> and defines a getLabel() and a getLocation() accessor function. Feel free to adopt this pattern if you think that it improves readability.

lib/CodeGen/AsmPrinter/DwarfDebug.h
191 ↗(On Diff #142125)

Is this feasible?

About combining DwarfLabel and DbgVariable.

lib/CodeGen/AsmPrinter/DwarfDebug.cpp
1232 ↗(On Diff #142125)

I took DILocalVariable as the reference model. So, you will find that some implementation is similar. However, processing of labels is much simpler than processing of variables. I do not need to handle location list for variables, instruction ranges that variables are accessible, local variables v.s. argument variables, and data types, etc.

The only similarity is they are both local entities in a function. They have function scope. They have DILocation to tell users where they are. I have no idea how to combine these two classes and make label processing simple and make sense.

lib/CodeGen/AsmPrinter/DwarfDebug.h
191 ↗(On Diff #142125)

The only similar data members are DILocation, and DIE *. The only similar member function is getTag(). It seems that there is few benefits to combine these two classes under a common base.

Processing labels is much simpler than variables. I have no idea how to combine these two classes and let the implementation simple and make sense.

aprantl added inline comments.
lib/CodeGen/AsmPrinter/DwarfDebug.cpp
1232 ↗(On Diff #142125)

+ @dblaikie: Do you also agree that it is better to keep labels and variables separate or should we make an effort to share bits of the implementation?

dblaikie added inline comments.Apr 19 2018, 3:10 PM
lib/CodeGen/AsmPrinter/DwarfDebug.cpp
1232 ↗(On Diff #142125)

Yeah, it certainly looks like many of these functions are similar/the same - though the label things talk about "inlined" instead of "abstract" - is there a reason for that? I would've thought it'd be exactly the same.

As for commoning the code - I would guess, in general, all the abstract handling should be basically the same (with a switch/if-chain on "how to populate abstract attributes for these entities" - variables would have name, type, location, and labels would just have name and location?)

HsiangKai added inline comments.Apr 20 2018, 1:13 AM
lib/CodeGen/AsmPrinter/DwarfDebug.cpp
1232 ↗(On Diff #142125)

There will be 'abstract labels' in inlined functions. So, I use the specific name, 'inlined label' for it. It is fine to follow the naming of variables.

If we want to combine the processing of abstract variables and labels, we need to review all processing for abstract variables. Not only create a common base class for DbgVariable and DwarfLabel, but all processing of abstract variables need to be reviewed. I need some time to refactor all of the related data structures and functions.

TODO: Refactor the patch to abstract the processing flow of abstract variables and abstract labels. The refactoring will start after mid of May.

Refactoring is done.

@aprantl: Please help me to review this patch. Thanks a lot.

Thank you for the patch.

It seems to me that with requireLabelBeforeInsn, the label will later be emitted as a temporary symbol with a unique but unspecified name (in DebugHandleBase::beginInstruction()). Is it correct?

Btw, can anyone tell me how to add inlined comments? Or I have to be in the reviewer list I guess?

Just click on the line number.

Thank you for the patch.

It seems to me that with requireLabelBeforeInsn, the label will later be emitted as a temporary symbol with a unique but unspecified name (in DebugHandleBase::beginInstruction()). Is it correct?

Yes, I generate a temporary label before the label intrinsic. In this way, I could get the address of the label afterward.

Btw, can anyone tell me how to add inlined comments? Or I have to be in the reviewer list I guess?

Thank you for the patch.

It seems to me that with requireLabelBeforeInsn, the label will later be emitted as a temporary symbol with a unique but unspecified name (in DebugHandleBase::beginInstruction()). Is it correct?

Yes, I generate a temporary label before the label intrinsic. In this way, I could get the address of the label afterward.

Yes, I mean that the label will later be named differently in the asm file than in the source? I don't know if this is something we should care about though, I'm just speaking from an user point of view

Thank you for the patch.

It seems to me that with requireLabelBeforeInsn, the label will later be emitted as a temporary symbol with a unique but unspecified name (in DebugHandleBase::beginInstruction()). Is it correct?

Yes, I generate a temporary label before the label intrinsic. In this way, I could get the address of the label afterward.

Yes, I mean that the label will later be named differently in the asm file than in the source? I don't know if this is something we should care about though, I'm just speaking from an user point of view

There is no 'label' entity in LLVM IR. The 'label' in C source code will be transformed into 'basic block' in LLVM.
So, we could not get the original name except from dbg.label intrinsic and metadata. That is why I created new kind of intrinsic and metadata for labels for debugging purpose.
I will print the label name in asm comments.

This is not super important, but: contrary to to DBG_VALUE intrinsics, DBG_LABELs don't have live ranges associated with them. I wonder if we really need to rename DbgValueHistoryCalculator. We're not calculating any "history" of labels, do we?

HsiangKai added a comment.EditedJun 7 2018, 11:27 PM

This is not super important, but: contrary to to DBG_VALUE intrinsics, DBG_LABELs don't have live ranges associated with them. I wonder if we really need to rename DbgValueHistoryCalculator. We're not calculating any "history" of labels, do we?

I need to get the mapping between “InlinedLabel” and DBG_LABEL MI. I put the operation in calculateDbgValueHistory(). Because calculateDbgValueHistory() no longer only calculates DbgValueHistoryMap, it also calculates DbgLabelInstrMap. So, I rename it.

Should I put DbgLabelInstrMap calculation in a new file, maybe called DbgLabelInstrCalculator.cpp/h?

I think this is starting to look good. I have a few more comments inline.

lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.h
57 ↗(On Diff #148545)

Please add a Doxygen comment explaining what this class is used for.

lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
829 ↗(On Diff #148545)

The old code on the left had more comments :-)

835 ↗(On Diff #148545)

can this be anything else? Should this be a static cast instead?

839 ↗(On Diff #148545)

Please don't check in commented-out code.

857 ↗(On Diff #148545)

I think you may be able to write this more compactly by

auto &MapEntry = getAbstractEntities()[Node];
if (...) {
  MapEntry = llvm>::make_unique(...)
  DU->addScopeVariable(Scope, cast<DbgVariable>(MapEntry.get());
} else
lib/CodeGen/AsmPrinter/DwarfDebug.h
64 ↗(On Diff #148545)

Doxygen comment?

79 ↗(On Diff #148545)

You can define group comments like this:

/// Accessors
/// @{
...
/// @}
HsiangKai updated this revision to Diff 154344.Jul 5 2018, 6:27 PM
HsiangKai marked 7 inline comments as done.
HsiangKai added inline comments.Jul 5 2018, 6:33 PM
lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
835 ↗(On Diff #148545)

Entity could be DbgVariable or DbgLabel. I use dyn_cast<> to cast and check their type. In this way, I could put them in if statement to ensure they are correct type before entering if block/else block.

aprantl accepted this revision.Jul 5 2018, 6:44 PM

A couple of cosmetic changes in line, but otherwise this LGTM.

lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.h
61 ↗(On Diff #154344)

/// For each inlined instance of a source-level label, keep ...

63 ↗(On Diff #154344)

a temporary (assembler) label ...

lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
842 ↗(On Diff #154344)

we use llvm_unreachable( instead of assert(0 &&

lib/CodeGen/AsmPrinter/DwarfDebug.cpp
1253 ↗(On Diff #154344)

point

1261 ↗(On Diff #154344)
if (auto *DV = dyn_cast<DILocalVariable>(DN)) {
    if (!Processed.insert(InlinedVariable(DV, nullptr)).second)
      continue;
if (LexicalScope *Scope = LScopes.findLexicalScope(DN->getScope()))
   createConcreteEntity(TheCU, *Scope, DN, nullptr);

?

lib/CodeGen/AsmPrinter/DwarfDebug.h
70 ↗(On Diff #154344)

Would be nice to rename to to InlinedAt in a follow-up commit.

lib/CodeGen/AsmPrinter/DwarfFile.h
63 ↗(On Diff #154344)

/// ... .

This revision is now accepted and ready to land.Jul 5 2018, 6:44 PM
HsiangKai updated this revision to Diff 154537.Jul 8 2018, 11:09 PM
HsiangKai marked 6 inline comments as done.
HsiangKai added inline comments.Jul 8 2018, 11:15 PM
lib/CodeGen/AsmPrinter/DwarfDebug.cpp
1261 ↗(On Diff #154344)

There is no apparent default version of getScope() in DINode. So, I could not merge these two code fragments into one.

This revision was automatically updated to reflect the committed changes.