diff --git a/llvm/include/llvm/IR/DIBuilder.h b/llvm/include/llvm/IR/DIBuilder.h index 932ae51b39dc..48cb7fe5df6f 100644 --- a/llvm/include/llvm/IR/DIBuilder.h +++ b/llvm/include/llvm/IR/DIBuilder.h @@ -17,7 +17,9 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/MapVector.h" #include "llvm/ADT/None.h" +#include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/IR/DebugInfo.h" @@ -51,6 +53,10 @@ namespace llvm { SmallVector AllSubprograms; SmallVector AllGVs; SmallVector AllImportedModules; + /// Map Macro parent (which can be DIMacroFile or nullptr) to a list of + /// Metadata all of type DIMacroNode. + /// DIMacroNode's with nullptr parent are DICompileUnit direct children. + MapVector> AllMacrosPerParent; /// Track nodes that may be unresolved. SmallVector UnresolvedNodes; @@ -116,6 +122,24 @@ namespace llvm { DIFile::ChecksumKind CSKind = DIFile::CSK_None, StringRef Checksum = StringRef()); + /// Create debugging information entry for a macro. + /// \param Parent Macro parent (could be nullptr). + /// \param Line Source line number where the macro is defined. + /// \param MacroType DW_MACINFO_define or DW_MACINFO_undef. + /// \param Name Macro name. + /// \param Value Macro value. + DIMacro *createMacro(DIMacroFile *Parent, unsigned Line, unsigned MacroType, + StringRef Name, StringRef Value = StringRef()); + + /// Create debugging information temporary entry for a macro file. + /// List of macro node direct children will be calculated by DIBuilder, + /// using the \p Parent relationship. + /// \param Parent Macro file parent (could be nullptr). + /// \param Line Source line number where the macro file is included. + /// \param File File descriptor containing the name of the macro file. + DIMacroFile *createTempMacroFile(DIMacroFile *Parent, unsigned Line, + DIFile *File); + /// Create a single enumerator value. DIEnumerator *createEnumerator(StringRef Name, int64_t Val); @@ -447,6 +471,9 @@ namespace llvm { /// Get a DINodeArray, create one if required. DINodeArray getOrCreateArray(ArrayRef Elements); + /// Get a DIMacroNodeArray, create one if required. + DIMacroNodeArray getOrCreateMacroArray(ArrayRef Elements); + /// Get a DITypeRefArray, create one if required. DITypeRefArray getOrCreateTypeArray(ArrayRef Elements); diff --git a/llvm/lib/IR/DIBuilder.cpp b/llvm/lib/IR/DIBuilder.cpp index 2ea572490b6d..d06161067f5f 100644 --- a/llvm/lib/IR/DIBuilder.cpp +++ b/llvm/lib/IR/DIBuilder.cpp @@ -90,6 +90,20 @@ void DIBuilder::finalize() { VMContext, SmallVector(AllImportedModules.begin(), AllImportedModules.end()))); + for (const auto &I : AllMacrosPerParent) { + // DIMacroNode's with nullptr parent are DICompileUnit direct children. + if (!I.first) { + CUNode->replaceMacros(MDTuple::get(VMContext, I.second.getArrayRef())); + continue; + } + // Otherwise, it must be a temporary DIMacroFile that need to be resolved. + auto *TMF = cast(I.first); + auto *MF = DIMacroFile::get(VMContext, dwarf::DW_MACINFO_start_file, + TMF->getLine(), TMF->getFile(), + getOrCreateMacroArray(I.second.getArrayRef())); + replaceTemporary(llvm::TempDIMacroNode(TMF), MF); + } + // Now that all temp nodes have been replaced or deleted, resolve remaining // cycles. for (const auto &N : UnresolvedNodes) @@ -179,6 +193,31 @@ DIFile *DIBuilder::createFile(StringRef Filename, StringRef Directory, return DIFile::get(VMContext, Filename, Directory, CSKind, Checksum); } +DIMacro *DIBuilder::createMacro(DIMacroFile *Parent, unsigned LineNumber, + unsigned MacroType, StringRef Name, + StringRef Value) { + assert(!Name.empty() && "Unable to create macro without name"); + assert((MacroType == dwarf::DW_MACINFO_undef || + MacroType == dwarf::DW_MACINFO_define) && + "Unexpected macro type"); + auto *M = DIMacro::get(VMContext, MacroType, LineNumber, Name, Value); + AllMacrosPerParent[Parent].insert(M); + return M; +} + +DIMacroFile *DIBuilder::createTempMacroFile(DIMacroFile *Parent, + unsigned LineNumber, DIFile *File) { + auto *MF = DIMacroFile::getTemporary(VMContext, dwarf::DW_MACINFO_start_file, + LineNumber, File, DIMacroNodeArray()) + .release(); + AllMacrosPerParent[Parent].insert(MF); + // Add the new temporary DIMacroFile to the macro per parent map as a parent. + // This is needed to assure DIMacroFile with no children to have an entry in + // the map. Otherwise, it will not be resolved in DIBuilder::finalize(). + AllMacrosPerParent.insert({MF, {}}); + return MF; +} + DIEnumerator *DIBuilder::createEnumerator(StringRef Name, int64_t Val) { assert(!Name.empty() && "Unable to create enumerator without name"); return DIEnumerator::get(VMContext, Val, Name); @@ -509,6 +548,11 @@ DINodeArray DIBuilder::getOrCreateArray(ArrayRef Elements) { return MDTuple::get(VMContext, Elements); } +DIMacroNodeArray +DIBuilder::getOrCreateMacroArray(ArrayRef Elements) { + return MDTuple::get(VMContext, Elements); +} + DITypeRefArray DIBuilder::getOrCreateTypeArray(ArrayRef Elements) { SmallVector Elts; for (unsigned i = 0, e = Elements.size(); i != e; ++i) { diff --git a/llvm/unittests/IR/IRBuilderTest.cpp b/llvm/unittests/IR/IRBuilderTest.cpp index 579384c5a5f4..833d13bed833 100644 --- a/llvm/unittests/IR/IRBuilderTest.cpp +++ b/llvm/unittests/IR/IRBuilderTest.cpp @@ -435,4 +435,73 @@ TEST_F(IRBuilderTest, DIImportedEntity) { EXPECT_TRUE(verifyModule(*M)); EXPECT_TRUE(CU->getImportedEntities().size() == 2); } + +// 0: #define M0 V0 <-- command line definition +// 0: main.c <-- main file +// 3: #define M1 V1 <-- M1 definition in main.c +// 5: #include "file.h" <-- inclusion of file.h from main.c +// 1: #define M2 <-- M2 definition in file.h with no value +// 7: #undef M1 V1 <-- M1 un-definition in main.c +TEST_F(IRBuilderTest, DIBuilderMacro) { + IRBuilder<> Builder(BB); + DIBuilder DIB(*M); + auto File1 = DIB.createFile("main.c", "/"); + auto File2 = DIB.createFile("file.h", "/"); + auto CU = DIB.createCompileUnit( + dwarf::DW_LANG_C, DIB.createFile("main.c", "/"), "llvm-c", true, "", 0); + auto MDef0 = + DIB.createMacro(nullptr, 0, dwarf::DW_MACINFO_define, "M0", "V0"); + auto TMF1 = DIB.createTempMacroFile(nullptr, 0, File1); + auto MDef1 = DIB.createMacro(TMF1, 3, dwarf::DW_MACINFO_define, "M1", "V1"); + auto TMF2 = DIB.createTempMacroFile(TMF1, 5, File2); + auto MDef2 = DIB.createMacro(TMF2, 1, dwarf::DW_MACINFO_define, "M2"); + auto MUndef1 = DIB.createMacro(TMF1, 7, dwarf::DW_MACINFO_undef, "M1"); + + EXPECT_EQ(dwarf::DW_MACINFO_define, MDef1->getMacinfoType()); + EXPECT_EQ(3, MDef1->getLine()); + EXPECT_EQ("M1", MDef1->getName()); + EXPECT_EQ("V1", MDef1->getValue()); + + EXPECT_EQ(dwarf::DW_MACINFO_undef, MUndef1->getMacinfoType()); + EXPECT_EQ(7, MUndef1->getLine()); + EXPECT_EQ("M1", MUndef1->getName()); + EXPECT_EQ("", MUndef1->getValue()); + + EXPECT_EQ(dwarf::DW_MACINFO_start_file, TMF2->getMacinfoType()); + EXPECT_EQ(5, TMF2->getLine()); + EXPECT_EQ(File2, TMF2->getFile()); + + DIB.finalize(); + + SmallVector Elements; + Elements.push_back(MDef2); + auto MF2 = DIMacroFile::get(Ctx, dwarf::DW_MACINFO_start_file, 5, File2, + DIB.getOrCreateMacroArray(Elements)); + + Elements.clear(); + Elements.push_back(MDef1); + Elements.push_back(MF2); + Elements.push_back(MUndef1); + auto MF1 = DIMacroFile::get(Ctx, dwarf::DW_MACINFO_start_file, 0, File1, + DIB.getOrCreateMacroArray(Elements)); + + Elements.clear(); + Elements.push_back(MDef0); + Elements.push_back(MF1); + auto MN0 = MDTuple::get(Ctx, Elements); + EXPECT_EQ(MN0, CU->getRawMacros()); + + Elements.clear(); + Elements.push_back(MDef1); + Elements.push_back(MF2); + Elements.push_back(MUndef1); + auto MN1 = MDTuple::get(Ctx, Elements); + EXPECT_EQ(MN1, MF1->getRawElements()); + + Elements.clear(); + Elements.push_back(MDef2); + auto MN2 = MDTuple::get(Ctx, Elements); + EXPECT_EQ(MN2, MF2->getRawElements()); + EXPECT_TRUE(verifyModule(*M)); +} }