[ThinLTO] Import static functions from the same module as caller

Summary:
We can sometimes end up with multiple copies of a local function that
have the same GUID in the index. This happens when there are local
functions with the same name that are in different source files with the
same name (but in different directories), and they were compiled in
their own directory so had the same path at compile time.

In this case make sure we import the copy in the caller's module. While
it isn't a correctness problem (the renamed reference which is based on the
module IR hash will be unique since the module must have had an
externally visible function that was imported), importing the wrong copy
will result in lost performance opportunity since it won't be referenced
and inlined.

Reviewers: mehdi_amini

Subscribers: llvm-commits

Differential Revision: https://reviews.llvm.org/D28440

llvm-svn: 291841
This commit is contained in:
Teresa Johnson 2017-01-12 22:04:45 +00:00
parent cec59f6f3c
commit 83aaf358fd
2 changed files with 38 additions and 9 deletions

View File

@ -124,7 +124,7 @@ namespace {
static const GlobalValueSummary * static const GlobalValueSummary *
selectCallee(const ModuleSummaryIndex &Index, selectCallee(const ModuleSummaryIndex &Index,
const GlobalValueSummaryList &CalleeSummaryList, const GlobalValueSummaryList &CalleeSummaryList,
unsigned Threshold) { unsigned Threshold, StringRef CallerModulePath) {
auto It = llvm::find_if( auto It = llvm::find_if(
CalleeSummaryList, CalleeSummaryList,
[&](const std::unique_ptr<GlobalValueSummary> &SummaryPtr) { [&](const std::unique_ptr<GlobalValueSummary> &SummaryPtr) {
@ -145,6 +145,21 @@ selectCallee(const ModuleSummaryIndex &Index,
auto *Summary = cast<FunctionSummary>(GVSummary); auto *Summary = cast<FunctionSummary>(GVSummary);
// If this is a local function, make sure we import the copy
// in the caller's module. The only time a local function can
// share an entry in the index is if there is a local with the same name
// in another module that had the same source file name (in a different
// directory), where each was compiled in their own directory so there
// was not distinguishing path.
// However, do the import from another module if there is only one
// entry in the list - in that case this must be a reference due
// to indirect call profile data, since a function pointer can point to
// a local in another module.
if (GlobalValue::isLocalLinkage(Summary->linkage()) &&
CalleeSummaryList.size() > 1 &&
Summary->modulePath() != CallerModulePath)
return false;
if (Summary->instCount() > Threshold) if (Summary->instCount() > Threshold)
return false; return false;
@ -163,11 +178,13 @@ selectCallee(const ModuleSummaryIndex &Index,
/// null if there's no match. /// null if there's no match.
static const GlobalValueSummary *selectCallee(GlobalValue::GUID GUID, static const GlobalValueSummary *selectCallee(GlobalValue::GUID GUID,
unsigned Threshold, unsigned Threshold,
const ModuleSummaryIndex &Index) { const ModuleSummaryIndex &Index,
StringRef CallerModulePath) {
auto CalleeSummaryList = Index.findGlobalValueSummaryList(GUID); auto CalleeSummaryList = Index.findGlobalValueSummaryList(GUID);
if (CalleeSummaryList == Index.end()) if (CalleeSummaryList == Index.end())
return nullptr; // This function does not have a summary return nullptr; // This function does not have a summary
return selectCallee(Index, CalleeSummaryList->second, Threshold); return selectCallee(Index, CalleeSummaryList->second, Threshold,
CallerModulePath);
} }
using EdgeInfo = std::tuple<const FunctionSummary *, unsigned /* Threshold */, using EdgeInfo = std::tuple<const FunctionSummary *, unsigned /* Threshold */,
@ -202,7 +219,8 @@ static void computeImportForFunction(
const auto NewThreshold = const auto NewThreshold =
Threshold * GetBonusMultiplier(Edge.second.Hotness); Threshold * GetBonusMultiplier(Edge.second.Hotness);
auto *CalleeSummary = selectCallee(GUID, NewThreshold, Index); auto *CalleeSummary =
selectCallee(GUID, NewThreshold, Index, Summary.modulePath());
if (!CalleeSummary) { if (!CalleeSummary) {
DEBUG(dbgs() << "ignored! No qualifying callee with summary found.\n"); DEBUG(dbgs() << "ignored! No qualifying callee with summary found.\n");
continue; continue;

View File

@ -1,14 +1,25 @@
; Test handling when two files with the same source file name contain
; static functions with the same name (which will have the same GUID
; in the combined index.
; Do setup work for all below tests: generate bitcode and combined index ; Do setup work for all below tests: generate bitcode and combined index
; RUN: opt -module-summary -module-hash %s -o %t.bc ; RUN: opt -module-summary -module-hash %s -o %t.bc
; RUN: opt -module-summary -module-hash %p/Inputs/local_name_conflict1.ll -o %t2.bc ; RUN: opt -module-summary -module-hash %p/Inputs/local_name_conflict1.ll -o %t2.bc
; RUN: opt -module-summary -module-hash %p/Inputs/local_name_conflict2.ll -o %t3.bc ; RUN: opt -module-summary -module-hash %p/Inputs/local_name_conflict2.ll -o %t3.bc
; RUN: llvm-lto -thinlto-action=thinlink -o %t4.bc %t.bc %t2.bc %t3.bc ; RUN: llvm-lto -thinlto-action=thinlink -o %t4.bc %t.bc %t2.bc %t3.bc
; Make sure foo is promoted and renamed without complaint in both ; This module will import b() which should cause the copy of foo from
; Inputs/local_name_conflict1.ll and Inputs/local_name_conflict2.ll ; that module (%t3.bc) to be imported. Check that the imported reference's
; FIXME: Once the importer is fixed to import the correct copy of the ; promoted name matches the imported copy.
; local, we should be able to verify that via an import action. ; RUN: llvm-lto -thinlto-action=import %t.bc -thinlto-index=%t4.bc -o - | llvm-dis -o - | FileCheck %s --check-prefix=IMPORT
; RUN: llvm-lto -thinlto-action=promote %t2.bc -thinlto-index=%t4.bc -o - | llvm-dis -o - | FileCheck %s --check-prefix=EXPORTSTATIC ; IMPORT: call i32 @foo.llvm.[[HASH:[0-9A-F]+]]
; IMPORT: define available_externally hidden i32 @foo.llvm.[[HASH]]()
; The copy in %t2.bc should not be exported/promoted/renamed
; RUN: llvm-lto -thinlto-action=promote %t2.bc -thinlto-index=%t4.bc -o - | llvm-dis -o - | FileCheck %s --check-prefix=NOEXPORTSTATIC
; NOEXPORTSTATIC: define internal i32 @foo()
; Make sure foo is promoted and renamed without complaint in %t3.bc.
; RUN: llvm-lto -thinlto-action=promote %t3.bc -thinlto-index=%t4.bc -o - | llvm-dis -o - | FileCheck %s --check-prefix=EXPORTSTATIC ; RUN: llvm-lto -thinlto-action=promote %t3.bc -thinlto-index=%t4.bc -o - | llvm-dis -o - | FileCheck %s --check-prefix=EXPORTSTATIC
; EXPORTSTATIC: define hidden i32 @foo.llvm. ; EXPORTSTATIC: define hidden i32 @foo.llvm.