Index: include/llvm/IR/DIBuilder.h =================================================================== --- include/llvm/IR/DIBuilder.h +++ include/llvm/IR/DIBuilder.h @@ -90,7 +90,10 @@ /// /// If \c AllowUnresolved, collect unresolved nodes attached to the module /// in order to resolve cycles during \a finalize(). - explicit DIBuilder(Module &M, bool AllowUnresolved = true); + /// + /// If \p CU is given a value other than nullptr, then set \p CUNode to CU. + explicit DIBuilder(Module &M, bool AllowUnresolved = true, + DICompileUnit *CU = nullptr); DIBuilder(const DIBuilder &) = delete; DIBuilder &operator=(const DIBuilder &) = delete; Index: lib/CodeGen/MachineOutliner.cpp =================================================================== --- lib/CodeGen/MachineOutliner.cpp +++ lib/CodeGen/MachineOutliner.cpp @@ -68,6 +68,7 @@ #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/IR/DIBuilder.h" #include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Mangler.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" @@ -97,6 +98,9 @@ /// The number of instructions in this \p Candidate. unsigned Len; + /// The MachineFunction containing this \p Candidate. + MachineFunction *MF = nullptr; + public: /// Set to false if the candidate overlapped with another candidate. bool InCandidateList = true; @@ -108,6 +112,15 @@ /// Contains all target-specific information for this \p Candidate. TargetInstrInfo::MachineOutlinerInfo MInfo; + /// If there is a DISubprogram associated with the function that this + /// Candidate lives in, return it. + DISubprogram *getSubprogramOrNull() const { + assert(MF && "Candidate has no MF!"); + if (DISubprogram *SP = MF->getFunction().getSubprogram()) + return SP; + return nullptr; + } + /// Return the number of instructions in this Candidate. unsigned getLength() const { return Len; } @@ -126,8 +139,9 @@ /// for some given candidate. unsigned Benefit = 0; - Candidate(unsigned StartIdx, unsigned Len, unsigned FunctionIdx) - : StartIdx(StartIdx), Len(Len), FunctionIdx(FunctionIdx) {} + Candidate(unsigned StartIdx, unsigned Len, unsigned FunctionIdx, + MachineFunction *MF) + : StartIdx(StartIdx), Len(Len), MF(MF), FunctionIdx(FunctionIdx) {} Candidate() {} @@ -163,6 +177,15 @@ /// Contains all target-specific information for this \p OutlinedFunction. TargetInstrInfo::MachineOutlinerInfo MInfo; + /// If there is a DISubprogram for any Candidate for this outlined function, + /// then return it. Otherwise, return nullptr. + DISubprogram *getSubprogramOrNull() const { + for (const auto &C : Candidates) + if (DISubprogram *SP = C->getSubprogramOrNull()) + return SP; + return nullptr; + } + /// Return the number of candidates for this \p OutlinedFunction. unsigned getOccurrenceCount() { return OccurrenceCount; } @@ -979,9 +1002,13 @@ MachineBasicBlock::iterator StartIt = Mapper.InstrList[StartIdx]; MachineBasicBlock::iterator EndIt = Mapper.InstrList[EndIdx]; + // Save the MachineFunction containing the Candidate. + MachineFunction *MF = StartIt->getParent()->getParent(); + assert(MF && "Candidate doesn't have a MF?"); + // Save the candidate and its location. CandidatesForRepeatedSeq.emplace_back(StartIdx, StringLen, - FunctionList.size()); + FunctionList.size(), MF); RepeatedSequenceLocs.emplace_back(std::make_pair(StartIt, EndIt)); } } @@ -1246,6 +1273,44 @@ TII.insertOutlinerEpilogue(MBB, MF, OF.MInfo); + // If there's a DISubprogram associated with this outlined function, then + // emit debug info for the outlined function. + if (DISubprogram *SP = OF.getSubprogramOrNull()) { + // We have a DISubprogram. Get its DICompileUnit. + DICompileUnit *CU = SP->getUnit(); + DIBuilder DB(M, true, CU); + DIFile *Unit = SP->getFile(); + Mangler Mg; + + // Walk over each IR function we created in the outliner and create + // DISubprograms for each function. + for (Function *F : CreatedIRFunctions) { + // Get the mangled name of the function for the linkage name. + std::string Dummy; + llvm::raw_string_ostream MangledNameStream(Dummy); + Mg.getNameWithPrefix(MangledNameStream, F, false); + + DISubprogram *SP = DB.createFunction( + Unit /* Context */, F->getName(), StringRef(MangledNameStream.str()), + Unit /* File */, + 0 /* Line 0 is reserved for compiler-generated code. */, + DB.createSubroutineType( + DB.getOrCreateTypeArray(None)), /* void type */ + false, true, 0, /* Line 0 is reserved for compiler-generated code. */ + DINode::DIFlags::FlagArtificial /* Compiler-generated code. */, + true /* Outlined code is optimized code by definition. */); + + // Don't add any new variables to the subprogram. + DB.finalizeSubprogram(SP); + + // Attach subprogram to the function. + F->setSubprogram(SP); + } + + // We're done with the DIBuilder. + DB.finalize(); + } + return &MF; } @@ -1388,41 +1453,5 @@ // Outline each of the candidates and return true if something was outlined. bool OutlinedSomething = outline(M, CandidateList, FunctionList, Mapper); - // If we have a compile unit, and we've outlined something, then set debug - // information on the outlined function. - if (M.debug_compile_units_begin() != M.debug_compile_units_end() && - OutlinedSomething) { - std::unique_ptr DB = llvm::make_unique(M); - - // Create a compile unit for the outlined function. - DICompileUnit *MCU = *M.debug_compile_units_begin(); - DIFile *Unit = DB->createFile(M.getName(), "/"); - DB->createCompileUnit(MCU->getSourceLanguage(), Unit, "machine-outliner", - true, "", MCU->getRuntimeVersion(), StringRef(), - DICompileUnit::DebugEmissionKind::NoDebug); - - // Walk over each IR function we created in the outliner and create - // DISubprograms for each function. - for (Function *F : CreatedIRFunctions) { - DISubprogram *SP = DB->createFunction( - Unit /* Context */, F->getName(), - StringRef() /* Empty linkage name. */, Unit /* File */, - 0 /* Line numbers don't matter*/, - DB->createSubroutineType(DB->getOrCreateTypeArray(None)), /* void */ - false, true, 0, /* Line in scope doesn't matter*/ - DINode::DIFlags::FlagArtificial /* Compiler-generated code. */, - true /* Outlined code is optimized code by definition. */); - - // Don't add any new variables to the subprogram. - DB->finalizeSubprogram(SP); - - // Attach subprogram to the function. - F->setSubprogram(SP); - } - - // We're done with the DIBuilder. - DB->finalize(); - } - return OutlinedSomething; } Index: lib/IR/DIBuilder.cpp =================================================================== --- lib/IR/DIBuilder.cpp +++ lib/IR/DIBuilder.cpp @@ -30,8 +30,8 @@ llvm::cl::desc("Use llvm.dbg.addr for all local variables"), cl::init(false), cl::Hidden); -DIBuilder::DIBuilder(Module &m, bool AllowUnresolvedNodes) - : M(m), VMContext(M.getContext()), CUNode(nullptr), +DIBuilder::DIBuilder(Module &m, bool AllowUnresolvedNodes, DICompileUnit *CU) + : M(m), VMContext(M.getContext()), CUNode(CU), DeclareFn(nullptr), ValueFn(nullptr), AllowUnresolvedNodes(AllowUnresolvedNodes) {} Index: test/CodeGen/X86/machine-outliner-disubprogram.ll =================================================================== --- test/CodeGen/X86/machine-outliner-disubprogram.ll +++ test/CodeGen/X86/machine-outliner-disubprogram.ll @@ -108,31 +108,26 @@ ret i32 0, !dbg !73 } -; CHECK [[UNIT:![0-9]+]] = distinct !DICompileUnit -; CHECK-SAME: file: [[FILE:![0-9]+]], -; CHECK-SAME: producer: "machine-outliner", -; CHECK-SAME: isOptimized: true, runtimeVersion: 0, emissionKind: NoDebug - ; CHECK: distinct !DISubprogram(name: "OUTLINED_FUNCTION_1", -; CHECK-SAME: scope: [[FILE]], -; CHECK-SAME: file: [[FILE]], +; CHECK-SAME: scope: !1, +; CHECK-SAME: file: !1, ; CHECK-SAME: type: [[TYPE:![0-9]+]], ; CHECK-SAME: isLocal: false, ; CHECK-SAME: isDefinition: true, ; CHECK-SAME: flags: DIFlagArtificial, ; CHECK-SAME: isOptimized: true, -; CHECK-SAME: unit: [[UNIT]], +; CHECK-SAME: unit: !0, ; CHECK-SAME: variables: [[VARS:![0-9]+]] -; CHECK: distinct !DISubprogram(name: "OUTLINED_FUNCTION_1", -; CHECK-SAME: scope: [[FILE]], -; CHECK-SAME: file: [[FILE]], +; CHECK: distinct !DISubprogram(name: "OUTLINED_FUNCTION_0", +; CHECK-SAME: scope: !1, +; CHECK-SAME: file: !1, ; CHECK-SAME: type: [[TYPE]], ; CHECK-SAME: isLocal: false, ; CHECK-SAME: isDefinition: true, ; CHECK-SAME: flags: DIFlagArtificial, ; CHECK-SAME: isOptimized: true, -; CHECK-SAME: unit: [[UNIT]], +; CHECK-SAME: unit: !0, ; CHECK-SAME: variables: [[VARS]] attributes #0 = { noinline noredzone nounwind optnone ssp uwtable "no-frame-pointer-elim"="true" }