Currently, the dead functions information getting from optimizations remarks does not contain debug location, but knowing where these dead functions locate could be useful for debugging or for detecting dead code.
Cause in `LTO::addRegularLTO()` we use `BitcodeModule::getLazyModule()` to read the bitcode module, when we pass Function F to `ore::NV()`, F is not materialized, so `F->getSubprogram()` returns nullptr, and there is no debug location information of dead functions in optimizations remarks.
This patch call `F->materialize()` before we pass Function F to `ore::NV()`, then debug location information will be emitted for dead functions in optimization remarks.
Reviewed By: tejohnson
Differential Revision: https://reviews.llvm.org/D109737
// Identify symbols exported dynamically, and that therefore could be
// referenced by a shared library not visible to the linker.
DenseSet<GlobalValue::GUID> DynamicExportSymbols;
+
+ // Diagnostic optimization remarks file
+ std::unique_ptr<ToolOutputFile> DiagnosticOutputFile;
};
/// The resolution for a symbol. The linker must provide a SymbolResolution for
for (GlobalValue *GV : Mod.Keep) {
if (LivenessFromIndex && !ThinLTO.CombinedIndex.isGUIDLive(GV->getGUID())) {
if (Function *F = dyn_cast<Function>(GV)) {
- OptimizationRemarkEmitter ORE(F, nullptr);
- ORE.emit(OptimizationRemark(DEBUG_TYPE, "deadfunction", F)
- << ore::NV("Function", F)
- << " not added to the combined module ");
+ if (DiagnosticOutputFile) {
+ if (Error Err = F->materialize())
+ return Err;
+ OptimizationRemarkEmitter ORE(F, nullptr);
+ ORE.emit(OptimizationRemark(DEBUG_TYPE, "deadfunction", F)
+ << ore::NV("Function", F)
+ << " not added to the combined module ");
+ }
}
continue;
}
Conf.RemarksHotnessThreshold);
if (!DiagFileOrErr)
return DiagFileOrErr.takeError();
+ DiagnosticOutputFile = std::move(*DiagFileOrErr);
// Finalize linking of regular LTO modules containing summaries now that
// we have computed liveness information.
return Err;
}
- return finalizeOptimizationRemarks(std::move(*DiagFileOrErr));
+ return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile));
}
static const char *libcallRoutineNames[] = {
; REMARK: Pass: lto
; REMARK-NEXT: Name: deadfunction
+; REMARK-NEXT: DebugLoc: { File: test.c, Line: 4, Column: 0 }
; REMARK-NEXT: Function: dead2
; REMARK-NEXT: Args:
; REMARK-NEXT: - Function: dead2
+; REMARK-NEXT: DebugLoc: { File: test.c, Line: 4, Column: 0 }
; REMARK-NEXT: - String: ' not added to the combined module '
; FULL-NOT: dead
ret void
}
-define void @dead2() {
+define void @dead2() !dbg !7 {
ret void
}
-!0 = !{i32 1, !"ThinLTO", i32 0}
-!llvm.module.flags = !{ !0 }
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, isOptimized: false, emissionKind: LineTablesOnly, enums: !2)
+!1 = !DIFile(filename: "test.c", directory: "/")
+!2 = !{}
+!3 = !{i32 2, !"Dwarf Version", i32 2}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"ThinLTO", i32 0}
+!7 = distinct !DISubprogram(name: "dead2", scope: !1, file: !1, line: 4, type: !8, isLocal: false, isDefinition: true, scopeLine: 4, isOptimized: false, unit: !0, retainedNodes: !2)
+!8 = !DISubroutineType(types: !2)