Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions llvm/include/llvm/IR/ModuleSummaryIndex.h
Original file line number Diff line number Diff line change
Expand Up @@ -1909,6 +1909,11 @@ class ModuleSummaryIndex {

/// Checks if we can import global variable from another module.
bool canImportGlobalVar(const GlobalValueSummary *S, bool AnalyzeRefs) const;

/// Same as above but checks whether the global var is importable as a
/// declaration.
bool canImportGlobalVar(const GlobalValueSummary *S, bool AnalyzeRefs,
bool &CanImportDecl) const;
};

/// GraphTraits definition to build SCC for the index
Expand Down
3 changes: 2 additions & 1 deletion llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4764,7 +4764,8 @@ void IndexBitcodeWriter::writeCombinedGlobalValueSummary() {
NameVals.push_back(*ValueId);
assert(ModuleIdMap.count(VS->modulePath()));
NameVals.push_back(ModuleIdMap[VS->modulePath()]);
NameVals.push_back(getEncodedGVSummaryFlags(VS->flags()));
NameVals.push_back(
getEncodedGVSummaryFlags(VS->flags(), shouldImportValueAsDecl(VS)));
NameVals.push_back(getEncodedGVarFlags(VS->varflags()));
for (auto &RI : VS->refs()) {
auto RefValueId = getValueId(RI.getGUID());
Expand Down
18 changes: 16 additions & 2 deletions llvm/lib/IR/ModuleSummaryIndex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,13 @@ void ModuleSummaryIndex::propagateAttributes(

bool ModuleSummaryIndex::canImportGlobalVar(const GlobalValueSummary *S,
bool AnalyzeRefs) const {
bool CanImportDecl;
return canImportGlobalVar(S, AnalyzeRefs, CanImportDecl);
}

bool ModuleSummaryIndex::canImportGlobalVar(const GlobalValueSummary *S,
bool AnalyzeRefs,
bool &CanImportDecl) const {
auto HasRefsPreventingImport = [this](const GlobalVarSummary *GVS) {
// We don't analyze GV references during attribute propagation, so
// GV with non-trivial initializer can be marked either read or
Expand All @@ -348,13 +355,20 @@ bool ModuleSummaryIndex::canImportGlobalVar(const GlobalValueSummary *S,
};
auto *GVS = cast<GlobalVarSummary>(S->getBaseObject());

const bool nonInterposable =
!GlobalValue::isInterposableLinkage(S->linkage());
const bool eligibleToImport = !S->notEligibleToImport();

// It's correct to import a global variable only when it is not interposable
// and eligible to import.
CanImportDecl = (nonInterposable && eligibleToImport);

// Global variable with non-trivial initializer can be imported
// if it's readonly. This gives us extra opportunities for constant
// folding and converting indirect calls to direct calls. We don't
// analyze GV references during attribute propagation, because we
// don't know yet if it is readonly or not.
return !GlobalValue::isInterposableLinkage(S->linkage()) &&
!S->notEligibleToImport() &&
return nonInterposable && eligibleToImport &&
(!AnalyzeRefs || !HasRefsPreventingImport(GVS));
}

Expand Down
12 changes: 10 additions & 2 deletions llvm/lib/Transforms/IPO/FunctionImport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -430,10 +430,18 @@ class GlobalsImporter final {
// than as part of the logic deciding which functions to import (i.e.
// based on profile information). Should we decide to handle them here,
// we can refactor accordingly at that time.
if (!GVS || !Index.canImportGlobalVar(GVS, /* AnalyzeRefs */ true) ||
bool CanImportDecl = false;
if (!GVS ||
shouldSkipLocalInAnotherModule(GVS, VI.getSummaryList().size(),
Summary.modulePath()))
Summary.modulePath()) ||
!Index.canImportGlobalVar(GVS, /* AnalyzeRefs */ true,
CanImportDecl)) {
if (ImportDeclaration && CanImportDecl)
ImportList.maybeAddDeclaration(RefSummary->modulePath(),
VI.getGUID());

continue;
}

// If there isn't an entry for GUID, insert <GUID, Definition> pair.
// Otherwise, definition should take precedence over declaration.
Expand Down
32 changes: 31 additions & 1 deletion llvm/test/ThinLTO/X86/import_callee_declaration.ll
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,14 @@
; RUN: -r=main.bc,main,px \
; RUN: -r=main.bc,small_func, \
; RUN: -r=main.bc,large_func, \
; RUN: -r=main.bc,read_write_global_vars, \
; RUN: -r=main.bc,external_func, \
; RUN: -r=lib.bc,callee,pl \
; RUN: -r=lib.bc,large_indirect_callee,px \
; RUN: -r=lib.bc,large_indirect_bar,px \
; RUN: -r=lib.bc,small_func,px \
; RUN: -r=lib.bc,large_func,px \
; RUN: -r=lib.bc,read_write_global_vars,px \
; RUN: -r=lib.bc,large_indirect_callee_alias,px \
; RUN: -r=lib.bc,large_indirect_bar_alias,px \
; RUN: -r=lib.bc,calleeAddrs,px -r=lib.bc,calleeAddrs2,px -o summary main.bc lib.bc 2>&1 | FileCheck %s --check-prefix=DUMP
Expand Down Expand Up @@ -71,13 +74,22 @@
; MAIN-DIS: [[LARGEINDIRECT:\^[0-9]+]] = gv: (guid: 14343440786664691134, summaries: (function: (module: [[LIBMOD]], flags: ({{.*}} importType: declaration), insts: 8, {{.*}})))
; MAIN-DIS: gv: (guid: 16730173943625350469, summaries: (alias: (module: [[LIBMOD]], flags: ({{.*}} importType: declaration), aliasee: [[LARGEINDIRECT]])))

; RUN: opt -passes=function-import -import-all-index -summary-file=main.bc.thinlto.bc main.bc -o main-after-import.bc
; RUN: llvm-dis -o - main-after-import.bc | FileCheck %s --check-prefix=MAIN-IMPORT

; Tests that dso_local attribute is applied on a global var from its summary.
MAIN-IMPORT: @read_write_global_vars = external dso_local global [1 x ptr]

; Run in-process ThinLTO and tests that
; 1. `callee` remains internalized even if the symbols of its callers
; (large_func, large_indirect_callee, large_indirect_bar) are exported as
; declarations and visible to main module.
; 2. the debugging logs from `function-import` pass are expected.
; Set relocation model to static so the dso_local attribute from a summary is
; applied on the global variable declaration.

; RUN: llvm-lto2 run \
; RUN: -relocation-model=static \
; RUN: -debug-only=function-import \
; RUN: -save-temps \
; RUN: -thinlto-threads=1 \
Expand All @@ -87,11 +99,14 @@
; RUN: -r=main.bc,main,px \
; RUN: -r=main.bc,small_func, \
; RUN: -r=main.bc,large_func, \
; RUN: -r=main.bc,read_write_global_vars, \
; RUN: -r=main.bc,external_func, \
; RUN: -r=lib.bc,callee,pl \
; RUN: -r=lib.bc,large_indirect_callee,px \
; RUN: -r=lib.bc,large_indirect_bar,px \
; RUN: -r=lib.bc,small_func,px \
; RUN: -r=lib.bc,large_func,px \
; RUN: -r=lib.bc,read_write_global_vars,px \
; RUN: -r=lib.bc,large_indirect_callee_alias,px \
; RUN: -r=lib.bc,large_indirect_bar_alias,px \
; RUN: -r=lib.bc,calleeAddrs,px -r=lib.bc,calleeAddrs2,px -o in-process main.bc lib.bc 2>&1 | FileCheck %s --check-prefix=IMPORTDUMP
Expand All @@ -103,7 +118,7 @@
; IMPORTDUMP-DAG: Is importing function definition 13568239288960714650 small_indirect_callee from lib.cc
; IMPORTDUMP-DAG: Is importing function definition 6976996067367342685 small_func from lib.cc
; IMPORTDUMP-DAG: Is importing function declaration 2418497564662708935 large_func from lib.cc
; IMPORTDUMP-DAG: Not importing global 7680325410415171624 calleeAddrs from lib.cc
; IMPORTDUMP-DAG: Is importing global declaration 7680325410415171624 calleeAddrs from lib.cc
; IMPORTDUMP-DAG: Is importing alias declaration 16730173943625350469 large_indirect_callee_alias from lib.cc
; IMPORTDUMP-DAG: Is importing alias declaration 13590951773474913315 large_indirect_bar_alias from lib.cc
; IMPORTDUMP-DAG: Not importing function 13770917885399536773 large_indirect_bar
Expand All @@ -115,6 +130,8 @@
; IMPORT-DAG: define available_externally void @small_func
; IMPORT-DAG: define available_externally hidden void @small_indirect_callee
; IMPORT-DAG: declare void @large_func
; Tests that dso_local attribute is applied on a global var from its summary.
; IMPORT-DAG: @read_write_global_vars = external dso_local global [1 x ptr]
; IMPORT-NOT: large_indirect_callee
; IMPORT-NOT: large_indirect_callee_alias
; IMPORT-NOT: large_indirect_bar
Expand All @@ -126,9 +143,14 @@
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

@read_write_global_vars = external global [1 x ptr]

define i32 @main() {
call void @small_func()
call void @large_func()
%num = call ptr @external_func(ptr @read_write_global_vars)
store ptr %num, ptr getelementptr inbounds ([1 x ptr], ptr @read_write_global_vars, i64 0, i64 0)
%res1 = call i32 @external_func(ptr @read_write_global_vars)
ret i32 0
}

Expand All @@ -137,6 +159,8 @@ declare void @small_func()
; large_func without attributes
declare void @large_func()

declare ptr @external_func(ptr)

;--- lib.ll
source_filename = "lib.cc"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
Expand All @@ -149,6 +173,10 @@ target triple = "x86_64-unknown-linux-gnu"
; large_indirect_bar_alias is visible to main.ll but its aliasee isn't.
@calleeAddrs2 = global [1 x ptr] [ptr @large_indirect_bar_alias]

; @read_write_global_vars is not read-only nor write-only (in main.ll). It's not
; a constant global var and has references, so it's not importable as a definition.
@read_write_global_vars = dso_local global [1 x ptr] [ptr @large_indirect_callee]

define void @callee() #1 {
ret void
}
Expand Down Expand Up @@ -197,6 +225,8 @@ entry:
ret void
}

;declare void @external_func()

define void @large_func() #0 {
entry:
call void @callee()
Expand Down
Loading