Index: include/llvm/Transforms/Utils/ImportedFunctionsInliningStatistics.h =================================================================== --- include/llvm/Transforms/Utils/ImportedFunctionsInliningStatistics.h +++ include/llvm/Transforms/Utils/ImportedFunctionsInliningStatistics.h @@ -77,6 +77,9 @@ int32_t NumberOfRealInlines = 0; bool Imported = false; bool Visited = false; + /// Number of instructions for imported function. Should not be set for + /// not imported function. + int NumberOfInstructions = 0; }; public: Index: lib/Transforms/Utils/ImportedFunctionsInliningStatistics.cpp =================================================================== --- lib/Transforms/Utils/ImportedFunctionsInliningStatistics.cpp +++ lib/Transforms/Utils/ImportedFunctionsInliningStatistics.cpp @@ -21,13 +21,24 @@ #include using namespace llvm; +static int getMetadataValue(const llvm::MDNode *Node) { + assert(Node != nullptr); + assert(Node->getNumOperands() == 1); + const auto &C = cast(*Node->getOperand(0)); + return C.getValue()->getUniqueInteger().getLimitedValue() ; +} + ImportedFunctionsInliningStatistics::InlineGraphNode & ImportedFunctionsInliningStatistics::createInlineGraphNode(const Function &F) { auto &ValueLookup = NodesMap[F.getName()]; if (!ValueLookup) { ValueLookup = llvm::make_unique(); - ValueLookup->Imported = F.getMetadata("thinlto_src_module") != nullptr; + if (F.getMetadata("thinlto_src_module") != nullptr) { + ValueLookup->Imported = true; + ValueLookup->NumberOfInstructions = + getMetadataValue(F.getMetadata("instructions_count")); + } } return *ValueLookup; } @@ -117,13 +128,17 @@ int(Node->second->NumberOfRealInlines > 0); } - if (Verbose) + if (Verbose) { + const auto &Val = *Node->second; Ostream << "Inlined " - << (Node->second->Imported ? "imported " : "not imported ") + << (Val.Imported ? "imported " : "not imported ") << "function [" << Node->first() << "]" - << ": #inlines = " << Node->second->NumberOfInlines - << ", #inlines_to_importing_module = " - << Node->second->NumberOfRealInlines << "\n"; + << ": #inlines = " << Val.NumberOfInlines + << ", #inlines_to_importing_module = " << Val.NumberOfRealInlines; + if (Val.Imported) + Ostream << ", number_of_instructions = " << Val.NumberOfInstructions; + Ostream << "\n"; + } } auto InlinedFunctionsCount = Index: test/Transforms/Inline/inline_stats.ll =================================================================== --- test/Transforms/Inline/inline_stats.ll +++ test/Transforms/Inline/inline_stats.ll @@ -6,10 +6,10 @@ ; CHECK-BASIC-NOT: -- Inlined not imported function ; CHECK-VERBOSE: -- List of inlined functions: ; CHECK-VERBOSE: Inlined not imported function [internal2]: #inlines = 6, #inlines_to_importing_module = 2 -; CHECK-VERBOSE: Inlined imported function [external2]: #inlines = 4, #inlines_to_importing_module = 1 -; CHECK-VERBOSE: Inlined imported function [external1]: #inlines = 3, #inlines_to_importing_module = 2 -; CHECK-VERBOSE: Inlined imported function [external5]: #inlines = 1, #inlines_to_importing_module = 1 -; CHECK-VERBOSE: Inlined imported function [external3]: #inlines = 1, #inlines_to_importing_module = 0 +; CHECK-VERBOSE: Inlined imported function [external2]: #inlines = 4, #inlines_to_importing_module = 1, number_of_instructions = 1 +; CHECK-VERBOSE: Inlined imported function [external1]: #inlines = 3, #inlines_to_importing_module = 2, number_of_instructions = 3 +; CHECK-VERBOSE: Inlined imported function [external5]: #inlines = 1, #inlines_to_importing_module = 1, number_of_instructions = 1 +; CHECK-VERBOSE: Inlined imported function [external3]: #inlines = 1, #inlines_to_importing_module = 0, number_of_instructions = 1 ; CHECK: -- Summary: ; CHECK: All functions: 10, imported functions: 7 @@ -36,33 +36,33 @@ ret void } -define void @external1() alwaysinline !thinlto_src_module !0 { +define void @external1() alwaysinline !thinlto_src_module !0 !instructions_count !4 { call fastcc void @internal2() call fastcc void @external2(); ret void } -define void @external2() alwaysinline !thinlto_src_module !1 { +define void @external2() alwaysinline !thinlto_src_module !1 !instructions_count !2 { ret void } -define void @external3() alwaysinline !thinlto_src_module !1 { +define void @external3() alwaysinline !thinlto_src_module !1 !instructions_count !2 { ret void } -define void @external4() !thinlto_src_module !1 { +define void @external4() !thinlto_src_module !1 !instructions_count !4 { call fastcc void @external1() call fastcc void @external2() ret void } -define void @external5() !thinlto_src_module !1 { +define void @external5() !thinlto_src_module !1 !instructions_count !2 { ret void } ; Assume big piece of code here. This function won't be inlined, so all the ; inlined function it will have won't affect real inlines. -define void @external_big() noinline !thinlto_src_module !1 { +define void @external_big() noinline !thinlto_src_module !1 !instructions_count !5 { ; CHECK-NOT: call fastcc void @internal2() call fastcc void @internal2() call fastcc void @internal2() @@ -78,10 +78,14 @@ } ; It should not be imported, but it should not break anything. -define void @external_notcalled() !thinlto_src_module !0 { +define void @external_notcalled() !thinlto_src_module !0 !instructions_count !3 { call void @external_notcalled() ret void } !0 = !{!"file.cc"} !1 = !{!"other.cc"} +!2 = !{i32 1} +!3 = !{i32 2} +!4 = !{i32 3} +!5 = !{i32 8}