Index: include/llvm/IR/DIBuilder.h =================================================================== --- include/llvm/IR/DIBuilder.h +++ include/llvm/IR/DIBuilder.h @@ -45,6 +45,10 @@ 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 DIComputeUnit direct children. + DenseMap> AllMacrosPerParent; /// Track nodes that may be unresolved. SmallVector UnresolvedNodes; @@ -107,6 +111,23 @@ /// for a file. DIFile *createFile(StringRef Filename, StringRef Directory); + /// 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 entry for a macro file. + /// \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. + /// \param Elements List of macro node direct children. + DIMacroFile *createMacroFile(DIMacroFile *Parent, unsigned Line, + DIFile *File, DIMacroNodeArray Elements); + /// Create a single enumerator value. DIEnumerator *createEnumerator(StringRef Name, int64_t Val); @@ -435,6 +456,9 @@ /// 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); @@ -709,6 +733,9 @@ void replaceArrays(DICompositeType *&T, DINodeArray Elements, DINodeArray TParams = DINodeArray()); + /// Replace macro node arrays on a macro file. + void replaceArrays(DIMacroFile *&F, DIMacroNodeArray Elements); + /// Replace a temporary node. /// /// Call \a MDNode::replaceAllUsesWith() on \c N, replacing it with \c Index: lib/IR/DIBuilder.cpp =================================================================== --- lib/IR/DIBuilder.cpp +++ lib/IR/DIBuilder.cpp @@ -90,6 +90,15 @@ VMContext, SmallVector(AllImportedModules.begin(), AllImportedModules.end()))); + for (const auto &I : AllMacrosPerParent) { + if (I.first == nullptr) { + CUNode->replaceMacros(MDTuple::get(VMContext, I.second)); + continue; + } + DIMacroFile *MF = cast(I.first); + MF->replaceElements(getOrCreateMacroArray(I.second)); + } + // Now that all temp nodes have been replaced or deleted, resolve remaining // cycles. for (const auto &N : UnresolvedNodes) @@ -179,6 +188,30 @@ return DIFile::get(VMContext, Filename, Directory); } +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 MIType = (dwarf::MacinfoRecordType)MacroType; + auto *M = DIMacro::get(VMContext, MIType, LineNumber, Name, Value); + AllMacrosPerParent[Parent].push_back(M); + trackIfUnresolved(M); + return M; +} + +DIMacroFile *DIBuilder::createMacroFile(DIMacroFile *Parent, + unsigned LineNumber, DIFile *File, + DIMacroNodeArray Elements) { + auto *MF = DIMacroFile::get(VMContext, dwarf::DW_MACINFO_start_file, + LineNumber, File, Elements); + AllMacrosPerParent[Parent].push_back(MF); + trackIfUnresolved(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 +542,11 @@ 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) { @@ -850,3 +888,21 @@ if (TParams) trackIfUnresolved(TParams.get()); } + +void DIBuilder::replaceArrays(DIMacroFile *&F, DIMacroNodeArray Elements) { + { + TypedTrackingMDRef N(F); + if (Elements) + N->replaceElements(Elements); + F = N.get(); + } + + // If F isn't resolved, there's no problem. + if (!F->isResolved()) + return; + + if (Elements) { + MDNode *N = Elements.get(); + assert((!N || N->isResolved()) && "Expect macro arrays to be resolved!"); + } +} Index: unittests/IR/IRBuilderTest.cpp =================================================================== --- unittests/IR/IRBuilderTest.cpp +++ unittests/IR/IRBuilderTest.cpp @@ -432,4 +432,61 @@ 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, "main.c", "/", "llvm-c", + true, "", 0); + auto MDef0 = + DIB.createMacro(nullptr, 0, dwarf::DW_MACINFO_define, "M0", "V0"); + auto MF1 = DIB.createMacroFile(nullptr, 0, File1, DIMacroNodeArray()); + auto MDef1 = DIB.createMacro(MF1, 3, dwarf::DW_MACINFO_define, "M1", "V1"); + auto MF2 = DIB.createMacroFile(MF1, 5, File2, DIMacroNodeArray()); + auto MDef2 = DIB.createMacro(MF2, 1, dwarf::DW_MACINFO_define, "M2"); + auto MUndef1 = DIB.createMacro(MF1, 7, dwarf::DW_MACINFO_undef, "M1"); + + DIB.finalize(); + + 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, MF2->getMacinfoType()); + EXPECT_EQ(5, MF2->getLine()); + EXPECT_EQ(File2, MF2->getFile()); + + std::vector Vec0; + Vec0.push_back(MDef0); + Vec0.push_back(MF1); + auto MN0 = MDTuple::get(Ctx, Vec0); + EXPECT_EQ(MN0, CU->getRawMacros()); + + std::vector Vec1; + Vec1.push_back(MDef1); + Vec1.push_back(MF2); + Vec1.push_back(MUndef1); + auto MN1 = MDTuple::get(Ctx, Vec1); + EXPECT_EQ(MN1, MF1->getRawElements()); + + std::vector Vec2; + Vec2.push_back(MDef2); + auto MN2 = MDTuple::get(Ctx, Vec2); + EXPECT_EQ(MN2, MF2->getRawElements()); + EXPECT_TRUE(verifyModule(*M)); +} }