Skip to content

Commit

Permalink
Macro debug info support in LLVM IR
Browse files Browse the repository at this point in the history
Introduced DIMacro and DIMacroFile debug info metadata in the LLVM IR to support macros.

Differential Revision: http://reviews.llvm.org/D14687

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@255245 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
Amjad Aboud committed Dec 10, 2015
1 parent f1cbc17 commit 7db3980
Show file tree
Hide file tree
Showing 20 changed files with 509 additions and 40 deletions.
34 changes: 30 additions & 4 deletions docs/LangRef.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3751,9 +3751,9 @@ DICompileUnit
"""""""""""""

``DICompileUnit`` nodes represent a compile unit. The ``enums:``,
``retainedTypes:``, ``subprograms:``, ``globals:`` and ``imports:`` fields are
tuples containing the debug info to be emitted along with the compile unit,
regardless of code optimizations (some nodes are only emitted if there are
``retainedTypes:``, ``subprograms:``, ``globals:``, ``imports:`` and ``macros:``
fields are tuples containing the debug info to be emitted along with the compile
unit, regardless of code optimizations (some nodes are only emitted if there are
references to them from instructions).

.. code-block:: llvm
Expand All @@ -3762,7 +3762,7 @@ references to them from instructions).
isOptimized: true, flags: "-O2", runtimeVersion: 2,
splitDebugFilename: "abc.debug", emissionKind: 1,
enums: !2, retainedTypes: !3, subprograms: !4,
globals: !5, imports: !6)
globals: !5, imports: !6, macros: !7, dwoId: 0x0abcd)
Compile unit descriptors provide the root scope for objects declared in a
specific compilation unit. File descriptors are defined using this scope.
Expand Down Expand Up @@ -4128,6 +4128,32 @@ compile unit.
!2 = !DIImportedEntity(tag: DW_TAG_imported_module, name: "foo", scope: !0,
entity: !1, line: 7)
DIMacro
"""""""

``DIMacro`` nodes represent definition or undefinition of a macro identifiers.
The ``name:`` field is the macro identifier, followed by macro parameters when
definining a function-like macro, and the ``value`` field is the token-string
used to expand the macro identifier.

.. code-block:: llvm
!2 = !DIMacro(macinfo: DW_MACINFO_define, line: 7, name: "foo(x)",
value: "((x) + 1)")
!3 = !DIMacro(macinfo: DW_MACINFO_undef, line: 30, name: "foo")
DIMacroFile
"""""""""""

``DIMacroFile`` nodes represent inclusion of source files.
The ``nodes:`` field is a list of ``DIMacro`` and ``DIMacroFile`` nodes that
appear in the included source file.

.. code-block:: llvm
!2 = !DIMacroFile(macinfo: DW_MACINFO_start_file, line: 7, file: !2,
nodes: !3)
'``tbaa``' Metadata
^^^^^^^^^^^^^^^^^^^

Expand Down
4 changes: 3 additions & 1 deletion include/llvm/Bitcode/LLVMBitCodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,9 @@ enum { BITCODE_CURRENT_EPOCH = 0 };
METADATA_EXPRESSION = 29, // [distinct, n x element]
METADATA_OBJC_PROPERTY = 30, // [distinct, name, file, line, ...]
METADATA_IMPORTED_ENTITY=31, // [distinct, tag, scope, entity, line, name]
METADATA_MODULE=32, // [distinct, scope, name, ...]
METADATA_MODULE = 32, // [distinct, scope, name, ...]
METADATA_MACRO = 33, // [distinct, macinfo, line, name, value]
METADATA_MACRO_FILE = 34, // [distinct, macinfo, line, file, ...]
};

// The constants block (CONSTANTS_BLOCK_ID) describes emission for each
Expand Down
187 changes: 177 additions & 10 deletions include/llvm/IR/DebugInfoMetadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -949,31 +949,32 @@ class DICompileUnit : public DIScope {
unsigned EmissionKind, DICompositeTypeArray EnumTypes,
DITypeArray RetainedTypes, DISubprogramArray Subprograms,
DIGlobalVariableArray GlobalVariables,
DIImportedEntityArray ImportedEntities, uint64_t DWOId,
StorageType Storage, bool ShouldCreate = true) {
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(), DWOId, Storage, ShouldCreate);
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, Metadata *GlobalVariables,
Metadata *ImportedEntities, uint64_t DWOId, StorageType Storage,
bool ShouldCreate = true);
Metadata *ImportedEntities, Metadata *Macros, uint64_t DWOId,
StorageType Storage, bool ShouldCreate = true);

TempDICompileUnit cloneImpl() const {
return getTemporary(
getContext(), getSourceLanguage(), getFile(), getProducer(),
isOptimized(), getFlags(), getRuntimeVersion(), getSplitDebugFilename(),
getEmissionKind(), getEnumTypes(), getRetainedTypes(), getSubprograms(),
getGlobalVariables(), getImportedEntities(), DWOId);
getGlobalVariables(), getImportedEntities(), getMacros(), DWOId);
}

static void get() = delete;
Expand All @@ -987,20 +988,22 @@ class DICompileUnit : public DIScope {
StringRef SplitDebugFilename, unsigned EmissionKind,
DICompositeTypeArray EnumTypes, DITypeArray RetainedTypes,
DISubprogramArray Subprograms, DIGlobalVariableArray GlobalVariables,
DIImportedEntityArray ImportedEntities, uint64_t DWOId),
DIImportedEntityArray ImportedEntities, DIMacroNodeArray Macros,
uint64_t DWOId),
(SourceLanguage, File, Producer, IsOptimized, Flags, RuntimeVersion,
SplitDebugFilename, EmissionKind, EnumTypes, RetainedTypes, Subprograms,
GlobalVariables, ImportedEntities, DWOId))
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, uint64_t DWOId),
Metadata *GlobalVariables, Metadata *ImportedEntities, Metadata *Macros,
uint64_t DWOId),
(SourceLanguage, File, Producer, IsOptimized, Flags, RuntimeVersion,
SplitDebugFilename, EmissionKind, EnumTypes, RetainedTypes, Subprograms,
GlobalVariables, ImportedEntities, DWOId))
GlobalVariables, ImportedEntities, Macros, DWOId))

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

Expand All @@ -1026,6 +1029,9 @@ class DICompileUnit : public DIScope {
DIImportedEntityArray getImportedEntities() const {
return cast_or_null<MDTuple>(getRawImportedEntities());
}
DIMacroNodeArray getMacros() const {
return cast_or_null<MDTuple>(getRawMacros());
}
uint64_t getDWOId() const { return DWOId; }
void setDWOId(uint64_t DwoId) { DWOId = DwoId; }

Expand All @@ -1039,6 +1045,7 @@ class DICompileUnit : public DIScope {
Metadata *getRawSubprograms() const { return getOperand(6); }
Metadata *getRawGlobalVariables() const { return getOperand(7); }
Metadata *getRawImportedEntities() const { return getOperand(8); }
Metadata *getRawMacros() const { return getOperand(9); }

/// \brief Replace arrays.
///
Expand All @@ -1061,6 +1068,7 @@ class DICompileUnit : public DIScope {
void replaceImportedEntities(DIImportedEntityArray N) {
replaceOperandWith(8, N.get());
}
void replaceMacros(DIMacroNodeArray N) { replaceOperandWith(9, N.get()); }
/// @}

static bool classof(const Metadata *MD) {
Expand Down Expand Up @@ -2199,6 +2207,165 @@ class DIImportedEntity : public DINode {
}
};

/// \brief Macro Info DWARF-like metadata node.
///
/// A metadata node with a DWARF macro info (i.e., a constant named
/// \c DW_MACINFO_*, defined in llvm/Support/Dwarf.h). Called \a DIMacroNode
/// because it's potentially used for non-DWARF output.
class DIMacroNode : public MDNode {
friend class LLVMContextImpl;
friend class MDNode;

protected:
DIMacroNode(LLVMContext &C, unsigned ID, StorageType Storage, unsigned MIType,
ArrayRef<Metadata *> Ops1, ArrayRef<Metadata *> Ops2 = None)
: MDNode(C, ID, Storage, Ops1, Ops2) {
assert(MIType < 1u << 16);
SubclassData16 = MIType;
}
~DIMacroNode() = default;

template <class Ty> Ty *getOperandAs(unsigned I) const {
return cast_or_null<Ty>(getOperand(I));
}

StringRef getStringOperand(unsigned I) const {
if (auto *S = getOperandAs<MDString>(I))
return S->getString();
return StringRef();
}

static MDString *getCanonicalMDString(LLVMContext &Context, StringRef S) {
if (S.empty())
return nullptr;
return MDString::get(Context, S);
}

public:
unsigned getMacinfoType() const { return SubclassData16; }

static bool classof(const Metadata *MD) {
switch (MD->getMetadataID()) {
default:
return false;
case DIMacroKind:
case DIMacroFileKind:
return true;
}
}
};

class DIMacro : public DIMacroNode {
friend class LLVMContextImpl;
friend class MDNode;

unsigned Line;

DIMacro(LLVMContext &C, StorageType Storage, unsigned MIType, unsigned Line,
ArrayRef<Metadata *> Ops)
: DIMacroNode(C, DIMacroKind, Storage, MIType, Ops), Line(Line) {}
~DIMacro() = default;

static DIMacro *getImpl(LLVMContext &Context, unsigned MIType, unsigned Line,
StringRef Name, StringRef Value, StorageType Storage,
bool ShouldCreate = true) {
return getImpl(Context, MIType, Line, getCanonicalMDString(Context, Name),
getCanonicalMDString(Context, Value), Storage, ShouldCreate);
}
static DIMacro *getImpl(LLVMContext &Context, unsigned MIType, unsigned Line,
MDString *Name, MDString *Value, StorageType Storage,
bool ShouldCreate = true);

TempDIMacro cloneImpl() const {
return getTemporary(getContext(), getMacinfoType(), getLine(), getName(),
getValue());
}

public:
DEFINE_MDNODE_GET(DIMacro, (unsigned MIType, unsigned Line, StringRef Name,
StringRef Value = ""),
(MIType, Line, Name, Value))
DEFINE_MDNODE_GET(DIMacro, (unsigned MIType, unsigned Line, MDString *Name,
MDString *Value),
(MIType, Line, Name, Value))

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

unsigned getLine() const { return Line; }

StringRef getName() const { return getStringOperand(0); }
StringRef getValue() const { return getStringOperand(1); }

MDString *getRawName() const { return getOperandAs<MDString>(0); }
MDString *getRawValue() const { return getOperandAs<MDString>(1); }

static bool classof(const Metadata *MD) {
return MD->getMetadataID() == DIMacroKind;
}
};

class DIMacroFile : public DIMacroNode {
friend class LLVMContextImpl;
friend class MDNode;

unsigned Line;

DIMacroFile(LLVMContext &C, StorageType Storage, unsigned MIType,
unsigned Line, ArrayRef<Metadata *> Ops)
: DIMacroNode(C, DIMacroFileKind, Storage, MIType, Ops), Line(Line) {}
~DIMacroFile() = default;

static DIMacroFile *getImpl(LLVMContext &Context, unsigned MIType,
unsigned Line, DIFile *File,
DIMacroNodeArray Elements, StorageType Storage,
bool ShouldCreate = true) {
return getImpl(Context, MIType, Line, static_cast<Metadata *>(File),
Elements.get(), Storage, ShouldCreate);
}

static DIMacroFile *getImpl(LLVMContext &Context, unsigned MIType,
unsigned Line, Metadata *File, Metadata *Elements,
StorageType Storage, bool ShouldCreate = true);

TempDIMacroFile cloneImpl() const {
return getTemporary(getContext(), getMacinfoType(), getLine(), getFile(),
getElements());
}

public:
DEFINE_MDNODE_GET(DIMacroFile, (unsigned MIType, unsigned Line, DIFile *File,
DIMacroNodeArray Elements),
(MIType, Line, File, Elements))
DEFINE_MDNODE_GET(DIMacroFile, (unsigned MIType, unsigned Line,
Metadata *File, Metadata *Elements),
(MIType, Line, File, Elements))

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

void replaceElements(DIMacroNodeArray Elements) {
#ifndef NDEBUG
for (DIMacroNode *Op : getElements())
assert(std::find(Elements->op_begin(), Elements->op_end(), Op) &&
"Lost a macro node during macro node list replacement");
#endif
replaceOperandWith(1, Elements.get());
}

unsigned getLine() const { return Line; }
DIFile *getFile() const { return cast_or_null<DIFile>(getRawFile()); }

DIMacroNodeArray getElements() const {
return cast_or_null<MDTuple>(getRawElements());
}

Metadata *getRawFile() const { return getOperand(0); }
Metadata *getRawElements() const { return getOperand(1); }

static bool classof(const Metadata *MD) {
return MD->getMetadataID() == DIMacroFileKind;
}
};

} // end namespace llvm

#undef DEFINE_MDNODE_GET_UNPACK_IMPL
Expand Down
3 changes: 3 additions & 0 deletions include/llvm/IR/Metadata.def
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIGlobalVariable)
HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DILocalVariable)
HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIObjCProperty)
HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIImportedEntity)
HANDLE_SPECIALIZED_MDNODE_BRANCH(DIMacroNode)
HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIMacro)
HANDLE_SPECIALIZED_MDNODE_LEAF_UNIQUABLE(DIMacroFile)

#undef HANDLE_METADATA
#undef HANDLE_METADATA_LEAF
Expand Down
4 changes: 3 additions & 1 deletion include/llvm/IR/Metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,9 @@ class Metadata {
DIImportedEntityKind,
ConstantAsMetadataKind,
LocalAsMetadataKind,
MDStringKind
MDStringKind,
DIMacroKind,
DIMacroFileKind
};

protected:
Expand Down
2 changes: 2 additions & 0 deletions include/llvm/Support/Dwarf.h
Original file line number Diff line number Diff line change
Expand Up @@ -625,13 +625,15 @@ const char *GDBIndexEntryLinkageString(GDBIndexEntryLinkage Linkage);
///
/// \li \a getTag() returns \a DW_TAG_invalid on invalid input.
/// \li \a getVirtuality() returns \a DW_VIRTUALITY_invalid on invalid input.
/// \li \a getMacinfo() returns \a DW_MACINFO_invalid on invalid input.
///
/// @{
unsigned getTag(StringRef TagString);
unsigned getOperationEncoding(StringRef OperationEncodingString);
unsigned getVirtuality(StringRef VirtualityString);
unsigned getLanguage(StringRef LanguageString);
unsigned getAttributeEncoding(StringRef EncodingString);
unsigned getMacinfo(StringRef MacinfoString);
/// @}

/// \brief Returns the symbolic string representing Val when used as a value
Expand Down
1 change: 1 addition & 0 deletions lib/AsmParser/LLLexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -778,6 +778,7 @@ lltok::Kind LLLexer::LexIdentifier() {
DWKEYWORD(VIRTUALITY, DwarfVirtuality);
DWKEYWORD(LANG, DwarfLang);
DWKEYWORD(OP, DwarfOp);
DWKEYWORD(MACINFO, DwarfMacinfo);
#undef DWKEYWORD

if (Keyword.startswith("DIFlag")) {
Expand Down
Loading

0 comments on commit 7db3980

Please sign in to comment.