summaryrefslogtreecommitdiffstats
path: root/llvm/test/Transforms/FunctionImport
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/test/Transforms/FunctionImport')
-rw-r--r--llvm/test/Transforms/FunctionImport/Inputs/adjustable_threshold.ll37
-rw-r--r--llvm/test/Transforms/FunctionImport/Inputs/comdat.ll10
-rw-r--r--llvm/test/Transforms/FunctionImport/Inputs/funcimport.ll165
-rw-r--r--llvm/test/Transforms/FunctionImport/Inputs/funcimport_alias.ll7
-rw-r--r--llvm/test/Transforms/FunctionImport/Inputs/funcimport_cutoff.ll9
-rw-r--r--llvm/test/Transforms/FunctionImport/Inputs/funcimport_debug.ll26
-rw-r--r--llvm/test/Transforms/FunctionImport/Inputs/funcimport_forcecold.ll4
-rw-r--r--llvm/test/Transforms/FunctionImport/Inputs/funcimport_resolved1.ll34
-rw-r--r--llvm/test/Transforms/FunctionImport/Inputs/funcimport_resolved2.ll6
-rw-r--r--llvm/test/Transforms/FunctionImport/Inputs/funcimport_var2.ll10
-rw-r--r--llvm/test/Transforms/FunctionImport/Inputs/hotness_based_import.ll81
-rw-r--r--llvm/test/Transforms/FunctionImport/Inputs/import_stats.ll16
-rw-r--r--llvm/test/Transforms/FunctionImport/Inputs/inlineasm.ll11
-rw-r--r--llvm/test/Transforms/FunctionImport/Inputs/not-prevailing.ll6
-rw-r--r--llvm/test/Transforms/FunctionImport/adjustable_threshold.ll31
-rw-r--r--llvm/test/Transforms/FunctionImport/comdat.ll32
-rw-r--r--llvm/test/Transforms/FunctionImport/funcimport.ll162
-rw-r--r--llvm/test/Transforms/FunctionImport/funcimport_alias.ll25
-rw-r--r--llvm/test/Transforms/FunctionImport/funcimport_cutoff.ll49
-rw-r--r--llvm/test/Transforms/FunctionImport/funcimport_debug.ll53
-rw-r--r--llvm/test/Transforms/FunctionImport/funcimport_forcecold.ll36
-rw-r--r--llvm/test/Transforms/FunctionImport/funcimport_forcecold_samplepgo.ll37
-rw-r--r--llvm/test/Transforms/FunctionImport/funcimport_resolved.ll52
-rw-r--r--llvm/test/Transforms/FunctionImport/funcimport_var.ll27
-rw-r--r--llvm/test/Transforms/FunctionImport/hotness_based_import.ll137
-rw-r--r--llvm/test/Transforms/FunctionImport/import_stats.ll71
-rw-r--r--llvm/test/Transforms/FunctionImport/inlineasm.ll19
-rw-r--r--llvm/test/Transforms/FunctionImport/not-prevailing.ll18
28 files changed, 1171 insertions, 0 deletions
diff --git a/llvm/test/Transforms/FunctionImport/Inputs/adjustable_threshold.ll b/llvm/test/Transforms/FunctionImport/Inputs/adjustable_threshold.ll
new file mode 100644
index 00000000000..fd4644d264a
--- /dev/null
+++ b/llvm/test/Transforms/FunctionImport/Inputs/adjustable_threshold.ll
@@ -0,0 +1,37 @@
+define void @globalfunc1() {
+entry:
+ call void @trampoline()
+ ret void
+}
+; Adds an artificial level in the call graph to reduce the importing threshold
+define void @trampoline() {
+entry:
+ call void @largefunction()
+ ret void
+}
+
+define void @globalfunc2() {
+entry:
+ call void @largefunction()
+ ret void
+}
+
+
+; Size is 5: if two layers below in the call graph the threshold will be 4,
+; but if only one layer below the threshold will be 7.
+define void @largefunction() {
+ entry:
+ call void @staticfunc2()
+ call void @staticfunc2()
+ call void @staticfunc2()
+ call void @staticfunc2()
+ call void @staticfunc2()
+ ret void
+}
+
+define internal void @staticfunc2() {
+entry:
+ ret void
+}
+
+
diff --git a/llvm/test/Transforms/FunctionImport/Inputs/comdat.ll b/llvm/test/Transforms/FunctionImport/Inputs/comdat.ll
new file mode 100644
index 00000000000..1df6f25351e
--- /dev/null
+++ b/llvm/test/Transforms/FunctionImport/Inputs/comdat.ll
@@ -0,0 +1,10 @@
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc19.0.24215"
+
+define void @main() {
+entry:
+ call i8* @lwt_fun()
+ ret void
+}
+
+declare i8* @lwt_fun()
diff --git a/llvm/test/Transforms/FunctionImport/Inputs/funcimport.ll b/llvm/test/Transforms/FunctionImport/Inputs/funcimport.ll
new file mode 100644
index 00000000000..201d4492671
--- /dev/null
+++ b/llvm/test/Transforms/FunctionImport/Inputs/funcimport.ll
@@ -0,0 +1,165 @@
+@globalvar = global i32 1, align 4
+@staticvar = internal global i32 1, align 4
+@staticconstvar = internal unnamed_addr constant [2 x i32] [i32 10, i32 20], align 4
+@commonvar = common global i32 0, align 4
+@P = internal global void ()* null, align 8
+
+@weakalias = weak alias void (...), bitcast (void ()* @globalfunc1 to void (...)*)
+@analias = alias void (...), bitcast (void ()* @globalfunc2 to void (...)*)
+@linkoncealias = alias void (...), bitcast (void ()* @linkoncefunc to void (...)*)
+
+define void @globalfunc1() #0 {
+entry:
+ call void @funcwithpersonality()
+ call void (...) @variadic_va_start()
+ ret void
+}
+
+define void @globalfunc2() #0 {
+entry:
+ ret void
+}
+
+define linkonce_odr void @linkoncefunc() #0 {
+entry:
+ ret void
+}
+
+define i32 @referencestatics(i32 %i) #0 {
+entry:
+ %i.addr = alloca i32, align 4
+ store i32 %i, i32* %i.addr, align 4
+ %call = call i32 @staticfunc()
+ %0 = load i32, i32* @staticvar, align 4
+ %add = add nsw i32 %call, %0
+ %1 = load i32, i32* %i.addr, align 4
+ %idxprom = sext i32 %1 to i64
+ %arrayidx = getelementptr inbounds [2 x i32], [2 x i32]* @staticconstvar, i64 0, i64 %idxprom
+ %2 = load i32, i32* %arrayidx, align 4
+ %add1 = add nsw i32 %add, %2
+ ret i32 %add1
+}
+
+define i32 @referenceglobals(i32 %i) #0 {
+entry:
+ %i.addr = alloca i32, align 4
+ store i32 %i, i32* %i.addr, align 4
+ call void @globalfunc1()
+ %0 = load i32, i32* @globalvar, align 4
+ ret i32 %0
+}
+
+define i32 @referencecommon(i32 %i) #0 {
+entry:
+ %i.addr = alloca i32, align 4
+ store i32 %i, i32* %i.addr, align 4
+ %0 = load i32, i32* @commonvar, align 4
+ ret i32 %0
+}
+
+define void @setfuncptr() #0 {
+entry:
+ store void ()* @staticfunc2, void ()** @P, align 8
+ ret void
+}
+
+define void @callfuncptr() #0 {
+entry:
+ %0 = load void ()*, void ()** @P, align 8
+ call void %0()
+ ret void
+}
+
+@weakvar = weak global i32 1, align 4
+define weak void @weakfunc() #0 {
+entry:
+ ret void
+}
+
+define linkonce void @linkoncefunc2() #0 {
+entry:
+ ret void
+}
+
+define internal i32 @staticfunc() #0 {
+entry:
+ ret i32 1
+}
+
+declare i32 @__gxx_personality_v0(...)
+
+; Add enough instructions to prevent import with inst limit of 5
+define internal void @funcwithpersonality() #2 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
+entry:
+ call void @globalfunc2()
+ call void @globalfunc2()
+ call void @globalfunc2()
+ call void @globalfunc2()
+ call void @globalfunc2()
+ call void @globalfunc2()
+ ret void
+}
+
+define internal void @staticfunc2() #0 {
+entry:
+ ret void
+}
+
+define void @referencelargelinkonce() #0 {
+entry:
+ call void @linkonceodr()
+ ret void
+}
+
+; A large enough linkonce_odr function that should never be imported
+define linkonce_odr void @linkonceodr() #0 {
+entry:
+ call void @globalfunc2()
+ call void @globalfunc2()
+ call void @globalfunc2()
+ call void @globalfunc2()
+ call void @globalfunc2()
+ call void @globalfunc2()
+ call void @globalfunc2()
+ call void @globalfunc2()
+ call void @globalfunc2()
+ call void @globalfunc2()
+ call void @globalfunc2()
+ call void @globalfunc2()
+ call void @globalfunc2()
+ call void @globalfunc2()
+ call void @globalfunc2()
+ call void @globalfunc2()
+ call void @globalfunc2()
+ call void @globalfunc2()
+ call void @globalfunc2()
+ call void @globalfunc2()
+ call void @globalfunc2()
+ call void @globalfunc2()
+ call void @globalfunc2()
+ call void @globalfunc2()
+ call void @globalfunc2()
+ call void @globalfunc2()
+ call void @globalfunc2()
+ call void @globalfunc2()
+ call void @globalfunc2()
+ call void @globalfunc2()
+ ret void
+}
+
+; Variadic function without va_start can be imported because inliner
+; can handle it.
+define void @variadic_no_va_start(...) {
+ ret void
+}
+
+; Variadic function with va_start should not be imported because inliner
+; doesn't handle it.
+define void @variadic_va_start(...) {
+ %ap = alloca i8*, align 8
+ %ap.0 = bitcast i8** %ap to i8*
+ call void @llvm.va_start(i8* %ap.0)
+ ret void
+}
+
+declare void @llvm.va_start(i8*) nounwind
diff --git a/llvm/test/Transforms/FunctionImport/Inputs/funcimport_alias.ll b/llvm/test/Transforms/FunctionImport/Inputs/funcimport_alias.ll
new file mode 100644
index 00000000000..f897aeda6ce
--- /dev/null
+++ b/llvm/test/Transforms/FunctionImport/Inputs/funcimport_alias.ll
@@ -0,0 +1,7 @@
+declare void @analias()
+
+define void @callanalias() #0 {
+entry:
+ call void @analias()
+ ret void
+}
diff --git a/llvm/test/Transforms/FunctionImport/Inputs/funcimport_cutoff.ll b/llvm/test/Transforms/FunctionImport/Inputs/funcimport_cutoff.ll
new file mode 100644
index 00000000000..4283215d74c
--- /dev/null
+++ b/llvm/test/Transforms/FunctionImport/Inputs/funcimport_cutoff.ll
@@ -0,0 +1,9 @@
+define void @foo() {
+entry:
+ ret void
+}
+
+define void @bar() {
+entry:
+ ret void
+}
diff --git a/llvm/test/Transforms/FunctionImport/Inputs/funcimport_debug.ll b/llvm/test/Transforms/FunctionImport/Inputs/funcimport_debug.ll
new file mode 100644
index 00000000000..f553af41896
--- /dev/null
+++ b/llvm/test/Transforms/FunctionImport/Inputs/funcimport_debug.ll
@@ -0,0 +1,26 @@
+; ModuleID = 'funcimport_debug.o'
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function Attrs: nounwind uwtable
+define void @func() #0 !dbg !4 {
+entry:
+ ret void, !dbg !10
+}
+
+attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!7, !8}
+!llvm.ident = !{!9}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 3.8.0 (trunk 255685) (llvm/trunk 255682)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+!1 = !DIFile(filename: "funcimport_debug.c", directory: ".")
+!2 = !{}
+!4 = distinct !DISubprogram(name: "func", scope: !1, file: !1, line: 1, type: !5, isLocal: false, isDefinition: true, scopeLine: 1, isOptimized: false, unit: !0, retainedNodes: !2)
+!5 = !DISubroutineType(types: !6)
+!6 = !{null}
+!7 = !{i32 2, !"Dwarf Version", i32 4}
+!8 = !{i32 2, !"Debug Info Version", i32 3}
+!9 = !{!"clang version 3.8.0 (trunk 255685) (llvm/trunk 255682)"}
+!10 = !DILocation(line: 2, column: 1, scope: !4)
diff --git a/llvm/test/Transforms/FunctionImport/Inputs/funcimport_forcecold.ll b/llvm/test/Transforms/FunctionImport/Inputs/funcimport_forcecold.ll
new file mode 100644
index 00000000000..a59d68c1e18
--- /dev/null
+++ b/llvm/test/Transforms/FunctionImport/Inputs/funcimport_forcecold.ll
@@ -0,0 +1,4 @@
+define void @foo() {
+entry:
+ ret void
+}
diff --git a/llvm/test/Transforms/FunctionImport/Inputs/funcimport_resolved1.ll b/llvm/test/Transforms/FunctionImport/Inputs/funcimport_resolved1.ll
new file mode 100644
index 00000000000..2b2443c96af
--- /dev/null
+++ b/llvm/test/Transforms/FunctionImport/Inputs/funcimport_resolved1.ll
@@ -0,0 +1,34 @@
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.11.0"
+
+define void @foo() {
+ call void @linkonceodrfunc()
+ call void @linkonceodrfunc2()
+ ret void
+}
+
+define linkonce_odr void @linkonceodrfunc() {
+ call void @f()
+ call void @f()
+ call void @f()
+ call void @f()
+ call void @f()
+ call void @f()
+ call void @f()
+ ret void
+}
+
+define linkonce_odr void @linkonceodrfunc2() {
+ call void @f()
+ call void @f()
+ call void @f()
+ call void @f()
+ call void @f()
+ call void @f()
+ call void @f()
+ ret void
+}
+
+define internal void @f() {
+ ret void
+}
diff --git a/llvm/test/Transforms/FunctionImport/Inputs/funcimport_resolved2.ll b/llvm/test/Transforms/FunctionImport/Inputs/funcimport_resolved2.ll
new file mode 100644
index 00000000000..278a7f4553f
--- /dev/null
+++ b/llvm/test/Transforms/FunctionImport/Inputs/funcimport_resolved2.ll
@@ -0,0 +1,6 @@
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.11.0"
+
+define linkonce_odr void @linkonceodrfunc() {
+ ret void
+}
diff --git a/llvm/test/Transforms/FunctionImport/Inputs/funcimport_var2.ll b/llvm/test/Transforms/FunctionImport/Inputs/funcimport_var2.ll
new file mode 100644
index 00000000000..95abe658e34
--- /dev/null
+++ b/llvm/test/Transforms/FunctionImport/Inputs/funcimport_var2.ll
@@ -0,0 +1,10 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@link = internal global i32 0, align 4
+
+; Function Attrs: norecurse nounwind readnone uwtable
+define nonnull i32* @get_link() local_unnamed_addr {
+ ret i32* @link
+}
+
diff --git a/llvm/test/Transforms/FunctionImport/Inputs/hotness_based_import.ll b/llvm/test/Transforms/FunctionImport/Inputs/hotness_based_import.ll
new file mode 100644
index 00000000000..6951b65818d
--- /dev/null
+++ b/llvm/test/Transforms/FunctionImport/Inputs/hotness_based_import.ll
@@ -0,0 +1,81 @@
+; ModuleID = 'thinlto-function-summary-callgraph-profile-summary2.ll'
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+
+define void @hot1() #1 {
+ ret void
+}
+define void @hot2() #1 !prof !20 {
+ call void @calledFromHot()
+ call void @calledFromHot()
+ ret void
+}
+define void @hot3() #1 !prof !20 {
+ call void @calledFromHot()
+ call void @calledFromHot()
+ call void @calledFromHot()
+ ret void
+}
+define void @cold() #1 !prof !0 {
+ ret void
+}
+define void @cold2() #1 !prof !0 {
+ call void @calledFromCold()
+ call void @calledFromCold()
+ ret void
+}
+
+define void @none1() #1 {
+ ret void
+}
+
+define void @none2() #1 {
+ call void @calledFromNone()
+ ret void
+}
+define void @none3() #1 {
+ call void @calledFromNone()
+ call void @calledFromNone()
+ ret void
+}
+
+define void @calledFromCold() {
+ ret void
+}
+
+define void @calledFromHot() !prof !20 {
+ call void @calledFromHot2()
+ ret void
+}
+
+define void @calledFromHot2() !prof !20 {
+ call void @calledFromHot3()
+ ret void
+}
+
+define void @calledFromNone() !prof !0 {
+ ret void
+}
+
+declare void @calledFromHot3()
+
+!0 = !{!"function_entry_count", i64 1}
+!20 = !{!"function_entry_count", i64 110}
+
+!llvm.module.flags = !{!1}
+
+!1 = !{i32 1, !"ProfileSummary", !2}
+!2 = !{!3, !4, !5, !6, !7, !8, !9, !10}
+!3 = !{!"ProfileFormat", !"InstrProf"}
+!4 = !{!"TotalCount", i64 10000}
+!5 = !{!"MaxCount", i64 10}
+!6 = !{!"MaxInternalCount", i64 1}
+!7 = !{!"MaxFunctionCount", i64 1000}
+!8 = !{!"NumCounts", i64 3}
+!9 = !{!"NumFunctions", i64 3}
+!10 = !{!"DetailedSummary", !11}
+!11 = !{!12, !13, !14}
+!12 = !{i32 10000, i64 100, i32 1}
+!13 = !{i32 999000, i64 100, i32 1}
+!14 = !{i32 999999, i64 1, i32 2} \ No newline at end of file
diff --git a/llvm/test/Transforms/FunctionImport/Inputs/import_stats.ll b/llvm/test/Transforms/FunctionImport/Inputs/import_stats.ll
new file mode 100644
index 00000000000..818fbf20d6f
--- /dev/null
+++ b/llvm/test/Transforms/FunctionImport/Inputs/import_stats.ll
@@ -0,0 +1,16 @@
+; ModuleID = 'import_stats2.ll'
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@globalvar = global i32 1, align 4
+
+define void @hot() {
+ store i32 0, i32* @globalvar, align 4
+ ret void
+}
+define void @critical() {
+ ret void
+}
+define void @none() {
+ ret void
+}
diff --git a/llvm/test/Transforms/FunctionImport/Inputs/inlineasm.ll b/llvm/test/Transforms/FunctionImport/Inputs/inlineasm.ll
new file mode 100644
index 00000000000..1ffc5db5f8b
--- /dev/null
+++ b/llvm/test/Transforms/FunctionImport/Inputs/inlineasm.ll
@@ -0,0 +1,11 @@
+@myvar = internal constant i8 1, align 1
+@llvm.used = appending global [1 x i8*] [i8* @myvar], section "llvm.metadata"
+
+define void @foo(i64* %v) #0 {
+entry:
+ %v.addr = alloca i64*, align 8
+ store i64* %v, i64** %v.addr, align 8
+ %0 = load i64*, i64** %v.addr, align 8
+ call void asm sideeffect "movzbl myvar(%rip), %eax\0A\09movq %rax, $0\0A\09", "=*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i64* %0) #1
+ ret void
+}
diff --git a/llvm/test/Transforms/FunctionImport/Inputs/not-prevailing.ll b/llvm/test/Transforms/FunctionImport/Inputs/not-prevailing.ll
new file mode 100644
index 00000000000..ca17d7f377c
--- /dev/null
+++ b/llvm/test/Transforms/FunctionImport/Inputs/not-prevailing.ll
@@ -0,0 +1,6 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define weak i32 @foo() {
+ ret i32 0
+}
diff --git a/llvm/test/Transforms/FunctionImport/adjustable_threshold.ll b/llvm/test/Transforms/FunctionImport/adjustable_threshold.ll
new file mode 100644
index 00000000000..adb8b0dffb0
--- /dev/null
+++ b/llvm/test/Transforms/FunctionImport/adjustable_threshold.ll
@@ -0,0 +1,31 @@
+; Do setup work for all below tests: generate bitcode and combined index
+; RUN: opt -module-summary %s -o %t.bc
+; RUN: opt -module-summary %p/Inputs/adjustable_threshold.ll -o %t2.bc
+; RUN: llvm-lto -thinlto -o %t3 %t.bc %t2.bc
+
+; Test import with default progressive instruction factor
+; RUN: opt -function-import -summary-file %t3.thinlto.bc %t.bc -import-instr-limit=10 -S | FileCheck %s --check-prefix=CHECK --check-prefix=INSTLIM-DEFAULT
+; INSTLIM-DEFAULT: call void @staticfunc2.llvm.
+
+; Test import with a reduced progressive instruction factor
+; RUN: opt -function-import -summary-file %t3.thinlto.bc %t.bc -import-instr-limit=10 -import-instr-evolution-factor=0.5 -S | FileCheck %s --check-prefix=CHECK --check-prefix=INSTLIM-PROGRESSIVE
+; INSTLIM-PROGRESSIVE-NOT: call void @staticfunc
+
+
+
+declare void @globalfunc1()
+declare void @globalfunc2()
+
+define void @entry() {
+entry:
+; Call site are processed in reversed order!
+
+; On the direct call, we reconsider @largefunction with a higher threshold and
+; import it
+ call void @globalfunc2()
+; When importing globalfunc1, the threshold was limited and @largefunction was
+; not imported.
+ call void @globalfunc1()
+ ret void
+}
+
diff --git a/llvm/test/Transforms/FunctionImport/comdat.ll b/llvm/test/Transforms/FunctionImport/comdat.ll
new file mode 100644
index 00000000000..29e8cb538ab
--- /dev/null
+++ b/llvm/test/Transforms/FunctionImport/comdat.ll
@@ -0,0 +1,32 @@
+; Test to ensure that comdat is renamed consistently when comdat leader is
+; promoted and renamed due to an import. Required by COFF.
+
+; REQUIRES: x86-registered-target
+
+; RUN: opt -thinlto-bc -o %t1.bc %s
+; RUN: opt -thinlto-bc -o %t2.bc %S/Inputs/comdat.ll
+; RUN: llvm-lto2 run -save-temps -o %t3 %t1.bc %t2.bc \
+; RUN: -r %t1.bc,lwt_fun,plx \
+; RUN: -r %t2.bc,main,plx \
+; RUN: -r %t2.bc,lwt_fun,
+; RUN: llvm-dis -o - %t3.1.3.import.bc | FileCheck %s
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc19.0.24215"
+
+; CHECK: $lwt.llvm.[[HASH:[0-9]+]] = comdat any
+$lwt = comdat any
+
+; CHECK: @lwt_aliasee = private unnamed_addr global {{.*}}, comdat($lwt.llvm.[[HASH]])
+@lwt_aliasee = private unnamed_addr global [1 x i8*] [i8* null], comdat($lwt)
+
+; CHECK: @lwt.llvm.[[HASH]] = hidden unnamed_addr alias
+@lwt = internal unnamed_addr alias [1 x i8*], [1 x i8*]* @lwt_aliasee
+
+; Below function should get imported into other module, resulting in @lwt being
+; promoted and renamed.
+define i8* @lwt_fun() {
+ %1 = getelementptr inbounds [1 x i8*], [1 x i8*]* @lwt, i32 0, i32 0
+ %2 = load i8*, i8** %1
+ ret i8* %2
+}
diff --git a/llvm/test/Transforms/FunctionImport/funcimport.ll b/llvm/test/Transforms/FunctionImport/funcimport.ll
new file mode 100644
index 00000000000..0d09d94a0fc
--- /dev/null
+++ b/llvm/test/Transforms/FunctionImport/funcimport.ll
@@ -0,0 +1,162 @@
+; Do setup work for all below tests: generate bitcode and combined index
+; RUN: opt -module-summary %s -o %t.bc
+; RUN: opt -module-summary %p/Inputs/funcimport.ll -o %t2.bc
+; RUN: llvm-lto -thinlto -print-summary-global-ids -o %t3 %t.bc %t2.bc 2>&1 | FileCheck %s --check-prefix=GUID
+
+; Do the import now
+; RUN: opt -function-import -stats -print-imports -enable-import-metadata -summary-file %t3.thinlto.bc %t.bc -S 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=INSTLIMDEF
+; Try again with new pass manager
+; RUN: opt -passes='function-import' -stats -print-imports -enable-import-metadata -summary-file %t3.thinlto.bc %t.bc -S 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=INSTLIMDEF
+; RUN: opt -passes='function-import' -debug-only=function-import -enable-import-metadata -summary-file %t3.thinlto.bc %t.bc -S 2>&1 | FileCheck %s --check-prefix=DUMP
+; "-stats" and "-debug-only" require +Asserts.
+; REQUIRES: asserts
+
+; Test import with smaller instruction limit
+; RUN: opt -function-import -enable-import-metadata -summary-file %t3.thinlto.bc %t.bc -import-instr-limit=5 -S | FileCheck %s --check-prefix=CHECK --check-prefix=INSTLIM5
+; INSTLIM5-NOT: @staticfunc.llvm.
+
+
+define i32 @main() #0 {
+entry:
+ call void (...) @weakalias()
+ call void (...) @analias()
+ call void (...) @linkoncealias()
+ %call = call i32 (...) @referencestatics()
+ %call1 = call i32 (...) @referenceglobals()
+ %call2 = call i32 (...) @referencecommon()
+ call void (...) @setfuncptr()
+ call void (...) @callfuncptr()
+ call void (...) @weakfunc()
+ call void (...) @linkoncefunc2()
+ call void (...) @referencelargelinkonce()
+ call void (...) @variadic_no_va_start()
+ call void (...) @variadic_va_start()
+ ret i32 0
+}
+
+; Won't import weak alias
+; CHECK-DAG: declare void @weakalias
+declare void @weakalias(...) #1
+
+; External alias imported as available_externally copy of aliasee
+; CHECK-DAG: define available_externally void @analias
+declare void @analias(...) #1
+
+; External alias imported as available_externally copy of aliasee
+; (linkoncealias is an external alias to a linkonce_odr)
+declare void @linkoncealias(...) #1
+; CHECK-DAG: define available_externally void @linkoncealias()
+
+; INSTLIMDEF-DAG: Import referencestatics
+; INSTLIMDEF-DAG: define available_externally i32 @referencestatics(i32 %i) !thinlto_src_module !0 {
+; INSTLIM5-DAG: declare i32 @referencestatics(...)
+declare i32 @referencestatics(...) #1
+
+; The import of referencestatics will expose call to staticfunc that
+; should in turn be imported as a promoted/renamed and hidden function.
+; Ensure that the call is to the properly-renamed function.
+; INSTLIMDEF-DAG: Import staticfunc
+; INSTLIMDEF-DAG: %call = call i32 @staticfunc.llvm.
+; INSTLIMDEF-DAG: define available_externally hidden i32 @staticfunc.llvm.{{.*}} !thinlto_src_module !0 {
+
+; INSTLIMDEF-DAG: Import referenceglobals
+; CHECK-DAG: define available_externally i32 @referenceglobals(i32 %i) !thinlto_src_module !0 {
+declare i32 @referenceglobals(...) #1
+
+; The import of referenceglobals will expose call to globalfunc1 that
+; should in turn be imported.
+; INSTLIMDEF-DAG: Import globalfunc1
+; CHECK-DAG: define available_externally void @globalfunc1() !thinlto_src_module !0
+
+; INSTLIMDEF-DAG: Import referencecommon
+; CHECK-DAG: define available_externally i32 @referencecommon(i32 %i) !thinlto_src_module !0 {
+declare i32 @referencecommon(...) #1
+
+; INSTLIMDEF-DAG: Import setfuncptr
+; CHECK-DAG: define available_externally void @setfuncptr() !thinlto_src_module !0 {
+declare void @setfuncptr(...) #1
+
+; INSTLIMDEF-DAG: Import callfuncptr
+; CHECK-DAG: define available_externally void @callfuncptr() !thinlto_src_module !0 {
+declare void @callfuncptr(...) #1
+
+; Ensure that all uses of local variable @P which has used in setfuncptr
+; and callfuncptr are to the same promoted/renamed global.
+; CHECK-DAG: @P.llvm.{{.*}} = available_externally hidden global void ()* null
+; CHECK-DAG: %0 = load void ()*, void ()** @P.llvm.
+; CHECK-DAG: store void ()* @staticfunc2.llvm.{{.*}}, void ()** @P.llvm.
+
+; Ensure that @referencelargelinkonce definition is pulled in, but later we
+; also check that the linkonceodr function is not.
+; CHECK-DAG: define available_externally void @referencelargelinkonce() !thinlto_src_module !0 {
+; INSTLIM5-DAG: declare void @linkonceodr()
+declare void @referencelargelinkonce(...)
+
+; Won't import weak func
+; CHECK-DAG: declare void @weakfunc(...)
+declare void @weakfunc(...) #1
+
+; Won't import linkonce func
+; CHECK-DAG: declare void @linkoncefunc2(...)
+declare void @linkoncefunc2(...) #1
+
+; INSTLIMDEF-DAG: Import funcwithpersonality
+; INSTLIMDEF-DAG: define available_externally hidden void @funcwithpersonality.llvm.{{.*}}() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) !thinlto_src_module !0 {
+; INSTLIM5-DAG: declare hidden void @funcwithpersonality.llvm.{{.*}}()
+
+; We can import variadic functions without a va_start, since the inliner
+; can handle them.
+; INSTLIMDEF-DAG: Import variadic_no_va_start
+; CHECK-DAG: define available_externally void @variadic_no_va_start(...) !thinlto_src_module !0 {
+declare void @variadic_no_va_start(...)
+
+; We can import variadic functions with a va_start, since the inliner
+; can sometimes handle them.
+; CHECK-DAG: define available_externally void @variadic_va_start(...)
+declare void @variadic_va_start(...)
+
+; INSTLIMDEF-DAG: Import globalfunc2
+; INSTLIMDEF-DAG: 15 function-import - Number of functions imported
+; INSTLIMDEF-DAG: 4 function-import - Number of global variables imported
+
+; CHECK-DAG: !0 = !{!"{{.*}}/Inputs/funcimport.ll"}
+
+; The actual GUID values will depend on path to test.
+; GUID-DAG: GUID {{.*}} is weakalias
+; GUID-DAG: GUID {{.*}} is referenceglobals
+; GUID-DAG: GUID {{.*}} is weakfunc
+; GUID-DAG: GUID {{.*}} is main
+; GUID-DAG: GUID {{.*}} is referencecommon
+; GUID-DAG: GUID {{.*}} is analias
+; GUID-DAG: GUID {{.*}} is referencestatics
+; GUID-DAG: GUID {{.*}} is linkoncealias
+; GUID-DAG: GUID {{.*}} is setfuncptr
+; GUID-DAG: GUID {{.*}} is callfuncptr
+; GUID-DAG: GUID {{.*}} is funcwithpersonality
+; GUID-DAG: GUID {{.*}} is setfuncptr
+; GUID-DAG: GUID {{.*}} is staticfunc2
+; GUID-DAG: GUID {{.*}} is __gxx_personality_v0
+; GUID-DAG: GUID {{.*}} is referencestatics
+; GUID-DAG: GUID {{.*}} is globalfunc1
+; GUID-DAG: GUID {{.*}} is globalfunc2
+; GUID-DAG: GUID {{.*}} is P
+; GUID-DAG: GUID {{.*}} is staticvar
+; GUID-DAG: GUID {{.*}} is commonvar
+; GUID-DAG: GUID {{.*}} is weakalias
+; GUID-DAG: GUID {{.*}} is staticfunc
+; GUID-DAG: GUID {{.*}} is weakfunc
+; GUID-DAG: GUID {{.*}} is referenceglobals
+; GUID-DAG: GUID {{.*}} is weakvar
+; GUID-DAG: GUID {{.*}} is staticconstvar
+; GUID-DAG: GUID {{.*}} is analias
+; GUID-DAG: GUID {{.*}} is globalvar
+; GUID-DAG: GUID {{.*}} is referencecommon
+; GUID-DAG: GUID {{.*}} is linkoncealias
+; GUID-DAG: GUID {{.*}} is callfuncptr
+; GUID-DAG: GUID {{.*}} is linkoncefunc
+
+; DUMP: Module [[M1:.*]] imports from 1 module
+; DUMP-NEXT: 15 functions imported from [[M2:.*]]
+; DUMP-NEXT: 4 vars imported from [[M2]]
+; DUMP: Imported 15 functions for Module [[M1]]
+; DUMP-NEXT: Imported 4 global variables for Module [[M1]]
diff --git a/llvm/test/Transforms/FunctionImport/funcimport_alias.ll b/llvm/test/Transforms/FunctionImport/funcimport_alias.ll
new file mode 100644
index 00000000000..7868e08d32f
--- /dev/null
+++ b/llvm/test/Transforms/FunctionImport/funcimport_alias.ll
@@ -0,0 +1,25 @@
+; Do setup work for all below tests: generate bitcode and combined index
+; RUN: opt -module-summary %s -o %t.bc
+; RUN: opt -module-summary %p/Inputs/funcimport_alias.ll -o %t2.bc
+; RUN: llvm-lto -thinlto -o %t3 %t.bc %t2.bc
+
+; Do the import now. Ensures that the importer handles an external call
+; from imported callanalias() to a function that is defined already in
+; the dest module, but as an alias.
+; RUN: opt -function-import -summary-file %t3.thinlto.bc %t.bc -S | FileCheck %s
+
+define i32 @main() #0 {
+entry:
+ call void @callanalias()
+ ret i32 0
+}
+
+@analias = alias void (), void ()* @globalfunc
+
+define void @globalfunc() #0 {
+entry:
+ ret void
+}
+
+declare void @callanalias() #1
+; CHECK-DAG: define available_externally void @callanalias()
diff --git a/llvm/test/Transforms/FunctionImport/funcimport_cutoff.ll b/llvm/test/Transforms/FunctionImport/funcimport_cutoff.ll
new file mode 100644
index 00000000000..dac4bd14faa
--- /dev/null
+++ b/llvm/test/Transforms/FunctionImport/funcimport_cutoff.ll
@@ -0,0 +1,49 @@
+; Test to ensure that thin linking with -import-cutoff stops importing when
+; expected.
+
+; "-stats" and "-debug-only" require +Asserts.
+; REQUIRES: asserts
+
+; RUN: opt -module-summary %s -o %t.bc
+; RUN: opt -module-summary %p/Inputs/funcimport_cutoff.ll -o %t2.bc
+; RUN: llvm-lto -thinlto -o %t3 %t.bc %t2.bc
+
+; First do with default options, which should import both foo and bar
+; RUN: opt -function-import -stats -print-imports -summary-file %t3.thinlto.bc %t.bc -S 2>&1 | FileCheck %s --check-prefix=IMPORT
+
+; Next try to restrict to 1 import. This should import just foo.
+; RUN: opt -import-cutoff=1 -function-import -stats -print-imports -summary-file %t3.thinlto.bc %t.bc -S 2>&1 | FileCheck %s --check-prefix=IMPORT1
+
+; Next try to restrict to 0 imports. This should not import.
+; RUN: opt -import-cutoff=0 -function-import -stats -print-imports -summary-file %t3.thinlto.bc %t.bc -S 2>&1 | FileCheck %s --check-prefix=NOIMPORT
+
+define i32 @main() {
+entry:
+ call void @foo()
+ call void @bar()
+ ret i32 0
+}
+
+declare void @foo()
+declare void @bar()
+
+; Check -print-imports output
+; IMPORT: Import foo
+; IMPORT: Import bar
+; IMPORT1: Import foo
+; IMPORT1-NOT: Import bar
+; NOIMPORT-NOT: Import foo
+; NOIMPORT-NOT: Import bar
+
+; Check -S output
+; IMPORT-DAG: define available_externally void @foo()
+; IMPORT-DAG: define available_externally void @bar()
+; NOIMPORT-DAG: declare void @foo()
+; NOIMPORT-DAG: declare void @bar()
+; IMPORT1-DAG: define available_externally void @foo()
+; IMPORT1-DAG: declare void @bar()
+
+; Check -stats output
+; IMPORT: 2 function-import - Number of functions imported
+; IMPORT1: 1 function-import - Number of functions imported
+; NOIMPORT-NOT: function-import - Number of functions imported
diff --git a/llvm/test/Transforms/FunctionImport/funcimport_debug.ll b/llvm/test/Transforms/FunctionImport/funcimport_debug.ll
new file mode 100644
index 00000000000..e764d78c300
--- /dev/null
+++ b/llvm/test/Transforms/FunctionImport/funcimport_debug.ll
@@ -0,0 +1,53 @@
+; Do setup work for all below tests: generate bitcode and combined index
+; RUN: opt -module-summary %s -o %t.bc
+; RUN: opt -module-summary %p/Inputs/funcimport_debug.ll -o %t2.bc
+; RUN: llvm-lto -thinlto -o %t3 %t.bc %t2.bc
+
+; Do the import now and confirm that metadata is linked for imported function.
+; RUN: opt -function-import -summary-file %t3.thinlto.bc %t.bc -S | FileCheck %s
+
+; CHECK: define available_externally void @func()
+
+; Check that we have exactly two subprograms (that func's subprogram wasn't
+; linked more than once for example), and that they are connected to
+; the correct compile unit.
+; CHECK: ![[CU1:[0-9]+]] = distinct !DICompileUnit(
+; CHECK: ![[CU2:[0-9]+]] = distinct !DICompileUnit(
+; CHECK: distinct !DISubprogram(name: "main"
+; CHECK-SAME: unit: ![[CU1]]
+; CHECK: distinct !DISubprogram(name: "func"
+; CHECK-SAME: unit: ![[CU2]]
+; CHECK-NOT: distinct !DISubprogram
+
+; ModuleID = 'funcimport_debug.o'
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function Attrs: nounwind uwtable
+define i32 @main() #0 !dbg !4 {
+entry:
+ call void (...) @func(), !dbg !11
+ ret i32 0, !dbg !12
+}
+
+declare void @func(...) #1
+
+attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!8, !9}
+!llvm.ident = !{!10}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 3.8.0 (trunk 255685) (llvm/trunk 255682)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+!1 = !DIFile(filename: "funcimport_debug.c", directory: ".")
+!2 = !{}
+!4 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 2, type: !5, isLocal: false, isDefinition: true, scopeLine: 2, isOptimized: false, unit: !0, retainedNodes: !2)
+!5 = !DISubroutineType(types: !6)
+!6 = !{!7}
+!7 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+!8 = !{i32 2, !"Dwarf Version", i32 4}
+!9 = !{i32 2, !"Debug Info Version", i32 3}
+!10 = !{!"clang version 3.8.0 (trunk 255685) (llvm/trunk 255682)"}
+!11 = !DILocation(line: 3, column: 3, scope: !4)
+!12 = !DILocation(line: 4, column: 1, scope: !4)
diff --git a/llvm/test/Transforms/FunctionImport/funcimport_forcecold.ll b/llvm/test/Transforms/FunctionImport/funcimport_forcecold.ll
new file mode 100644
index 00000000000..a9aa77f9afe
--- /dev/null
+++ b/llvm/test/Transforms/FunctionImport/funcimport_forcecold.ll
@@ -0,0 +1,36 @@
+; Test to ensure that building summary with -force-summary-edges-cold
+; blocks importing as expected.
+
+; "-stats" and "-debug-only" require +Asserts.
+; REQUIRES: asserts
+
+; First do with default options, which should import
+; RUN: opt -module-summary %s -o %t.bc
+; RUN: opt -module-summary %p/Inputs/funcimport_forcecold.ll -o %t2.bc
+; RUN: llvm-lto -thinlto -o %t3 %t.bc %t2.bc
+; RUN: opt -function-import -stats -print-imports -summary-file %t3.thinlto.bc %t.bc -S 2>&1 | FileCheck %s --check-prefix=IMPORT
+
+; Next rebuild caller module summary with non-critical edges forced cold (which
+; should affect all edges in this test as we don't have any sample pgo).
+; Make sure we don't import.
+; RUN: opt -force-summary-edges-cold=all-non-critical -module-summary %s -o %t.bc
+; RUN: llvm-lto -thinlto -o %t3 %t.bc %t2.bc
+; RUN: opt -function-import -stats -print-imports -summary-file %t3.thinlto.bc %t.bc -S 2>&1 | FileCheck %s --check-prefix=NOIMPORT
+
+; Next rebuild caller module summary with all edges forced cold.
+; Make sure we don't import.
+; RUN: opt -force-summary-edges-cold=all -module-summary %s -o %t.bc
+; RUN: llvm-lto -thinlto -o %t3 %t.bc %t2.bc
+; RUN: opt -function-import -stats -print-imports -summary-file %t3.thinlto.bc %t.bc -S 2>&1 | FileCheck %s --check-prefix=NOIMPORT
+
+define i32 @main() {
+entry:
+ call void @foo()
+ ret i32 0
+}
+
+; IMPORT: Import foo
+; NOIMPORT-NOT: Import foo
+; IMPORT: define available_externally void @foo()
+; NOIMPORT: declare void @foo()
+declare void @foo()
diff --git a/llvm/test/Transforms/FunctionImport/funcimport_forcecold_samplepgo.ll b/llvm/test/Transforms/FunctionImport/funcimport_forcecold_samplepgo.ll
new file mode 100644
index 00000000000..4ff02b9ba0f
--- /dev/null
+++ b/llvm/test/Transforms/FunctionImport/funcimport_forcecold_samplepgo.ll
@@ -0,0 +1,37 @@
+; Test to ensure that building summary with -force-summary-edges-cold
+; blocks importing as expected.
+
+; "-stats" and "-debug-only" require +Asserts.
+; REQUIRES: asserts
+
+; First do with default options, which should import
+; RUN: opt -module-summary %s -o %t.bc
+; RUN: opt -module-summary %p/Inputs/funcimport_forcecold.ll -o %t2.bc
+; RUN: llvm-lto -thinlto -o %t3 %t.bc %t2.bc
+; RUN: opt -function-import -stats -print-imports -summary-file %t3.thinlto.bc %t.bc -S 2>&1 | FileCheck %s --check-prefix=IMPORT
+
+; Next rebuild caller module summary with only non-critical edges forced cold,
+; which should still import in this case.
+; RUN: opt -force-summary-edges-cold=all-non-critical -module-summary %s -o %t.bc
+; RUN: llvm-lto -thinlto -o %t3 %t.bc %t2.bc
+; RUN: opt -function-import -stats -print-imports -summary-file %t3.thinlto.bc %t.bc -S 2>&1 | FileCheck %s --check-prefix=IMPORT
+
+; Next rebuild caller module summary with all edges forced cold.
+; Make sure we don't import.
+; RUN: opt -force-summary-edges-cold=all -module-summary %s -o %t.bc
+; RUN: llvm-lto -thinlto -o %t3 %t.bc %t2.bc
+; RUN: opt -function-import -stats -print-imports -summary-file %t3.thinlto.bc %t.bc -S 2>&1 | FileCheck %s --check-prefix=NOIMPORT
+
+define i32 @main() !prof !1 {
+entry:
+ call void @foo()
+ ret i32 0
+}
+
+; IMPORT: Import foo
+; NOIMPORT-NOT: Import foo
+; IMPORT: define available_externally void @foo()
+; NOIMPORT: declare void @foo()
+declare void @foo()
+
+!1 = !{!"function_entry_count", i64 110, i64 6699318081062747564}
diff --git a/llvm/test/Transforms/FunctionImport/funcimport_resolved.ll b/llvm/test/Transforms/FunctionImport/funcimport_resolved.ll
new file mode 100644
index 00000000000..b256a613602
--- /dev/null
+++ b/llvm/test/Transforms/FunctionImport/funcimport_resolved.ll
@@ -0,0 +1,52 @@
+; Test to ensure that we always select the same copy of a linkonce function
+; when it is encountered with different thresholds. When we encounter the
+; copy in funcimport_resolved1.ll with a higher threshold via the direct call
+; from main(), it will be selected for importing. When we encounter it with a
+; lower threshold by reaching it from the deeper call chain via foo(), it
+; won't be selected for importing. We don't want to select both the copy from
+; funcimport_resolved1.ll and the smaller one from funcimport_resolved2.ll,
+; leaving it up to the backend to figure out which one to actually import.
+; The linkonce_odr may have different instruction counts in practice due to
+; different inlines in the compile step.
+
+; Require asserts so we can use -debug-only
+; REQUIRES: asserts
+
+; REQUIRES: x86-registered-target
+
+; RUN: opt -module-summary %s -o %t.bc
+; RUN: opt -module-summary %p/Inputs/funcimport_resolved1.ll -o %t2.bc
+; RUN: opt -module-summary %p/Inputs/funcimport_resolved2.ll -o %t3.bc
+
+; First do a sanity check that all callees are imported with the default
+; instruction limit
+; RUN: llvm-lto2 run %t.bc %t2.bc %t3.bc -o %t4 -r=%t.bc,_main,pl -r=%t.bc,_linkonceodrfunc,l -r=%t.bc,_foo,l -r=%t2.bc,_foo,pl -r=%t2.bc,_linkonceodrfunc,pl -r=%t2.bc,_linkonceodrfunc2,pl -r=%t3.bc,_linkonceodrfunc,l -thinlto-threads=1 -debug-only=function-import 2>&1 | FileCheck %s --check-prefix=INSTLIMDEFAULT
+; INSTLIMDEFAULT: Is importing function {{.*}} foo from {{.*}}funcimport_resolved1.ll
+; INSTLIMDEFAULT: Is importing function {{.*}} linkonceodrfunc from {{.*}}funcimport_resolved1.ll
+; INSTLIMDEFAULT: Is importing function {{.*}} linkonceodrfunc2 from {{.*}}funcimport_resolved1.ll
+; INSTLIMDEFAULT: Is importing function {{.*}} f from {{.*}}funcimport_resolved1.ll
+; INSTLIMDEFAULT-NOT: Is importing function {{.*}} linkonceodrfunc from {{.*}}funcimport_resolved2.ll
+
+; Now run with the lower threshold that will only allow linkonceodrfunc to be
+; imported from funcimport_resolved1.ll when encountered via the direct call
+; from main(). Ensure we don't also select the copy in funcimport_resolved2.ll
+; when it is encountered via the deeper call chain.
+; RUN: llvm-lto2 run %t.bc %t2.bc %t3.bc -o %t4 -r=%t.bc,_main,pl -r=%t.bc,_linkonceodrfunc,l -r=%t.bc,_foo,l -r=%t2.bc,_foo,pl -r=%t2.bc,_linkonceodrfunc,pl -r=%t2.bc,_linkonceodrfunc2,pl -r=%t3.bc,_linkonceodrfunc,l -thinlto-threads=1 -debug-only=function-import -import-instr-limit=8 2>&1 | FileCheck %s --check-prefix=INSTLIM8
+; INSTLIM8: Is importing function {{.*}} foo from {{.*}}funcimport_resolved1.ll
+; INSTLIM8: Is importing function {{.*}} linkonceodrfunc from {{.*}}funcimport_resolved1.ll
+; INSTLIM8: Not importing function {{.*}} linkonceodrfunc2 from {{.*}}funcimport_resolved1.ll
+; INSTLIM8: Is importing function {{.*}} f from {{.*}}funcimport_resolved1.ll
+; INSTLIM8-NOT: Is importing function {{.*}} linkonceodrfunc from {{.*}}funcimport_resolved2.ll
+
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.11.0"
+
+define i32 @main() #0 {
+entry:
+ call void (...) @foo()
+ call void (...) @linkonceodrfunc()
+ ret i32 0
+}
+
+declare void @foo(...) #1
+declare void @linkonceodrfunc(...) #1
diff --git a/llvm/test/Transforms/FunctionImport/funcimport_var.ll b/llvm/test/Transforms/FunctionImport/funcimport_var.ll
new file mode 100644
index 00000000000..edd874e6297
--- /dev/null
+++ b/llvm/test/Transforms/FunctionImport/funcimport_var.ll
@@ -0,0 +1,27 @@
+; This test makes sure a static var is not selected as a callee target
+; (which will crash compilation).
+; RUN: opt -module-summary %s -o %t.bc
+; RUN: opt -module-summary %p/Inputs/funcimport_var2.ll -o %t2.bc
+; RUN: llvm-lto -thinlto -thinlto-action=thinlink -o %t3 %t.bc %t2.bc
+; RUN: llvm-lto -thinlto -thinlto-action=import -thinlto-index=%t3 %t.bc %t2.bc
+; RUN: llvm-lto -thinlto -thinlto-action=run %t.bc %t2.bc -exported-symbol=_Z4LinkPKcS0_
+; RUN: llvm-nm %t.bc.thinlto.o | FileCheck %s
+; RUN: llvm-lto2 run %t.bc %t2.bc -o %t.out \
+; RUN: -r %t.bc,_Z4LinkPKcS0_,plx \
+; RUN: -r %t.bc,link,l \
+; RUN: -r %t2.bc,get_link,plx
+; RUN: llvm-nm %t.out.1 | FileCheck %s
+; CHECK: U link
+
+; REQUIRES: x86-registered-target
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define i32 @_Z4LinkPKcS0_(i8*, i8*) local_unnamed_addr {
+ %3 = tail call i32 @link(i8* %0, i8* %1) #2
+ ret i32 %3
+}
+
+; Function Attrs: nounwind
+declare i32 @link(i8*, i8*) local_unnamed_addr
diff --git a/llvm/test/Transforms/FunctionImport/hotness_based_import.ll b/llvm/test/Transforms/FunctionImport/hotness_based_import.ll
new file mode 100644
index 00000000000..9de8714072d
--- /dev/null
+++ b/llvm/test/Transforms/FunctionImport/hotness_based_import.ll
@@ -0,0 +1,137 @@
+; Test to check the callgraph in summary when there is PGO
+; RUN: opt -module-summary %s -o %t.bc
+; RUN: opt -module-summary %p/Inputs/hotness_based_import.ll -o %t2.bc
+; RUN: llvm-lto -thinlto -o %t3 %t.bc %t2.bc
+
+; Test import with default hot multiplier (3) and default hot-evolution-factor (1.0)
+; RUN: opt -function-import -summary-file %t3.thinlto.bc %t.bc -import-instr-limit=1 --S | FileCheck %s --check-prefix=CHECK --check-prefix=HOT-DEFAULT
+; RUN: opt -function-import -summary-file %t3.thinlto.bc %t.bc -import-instr-limit=1 --S -import-hot-multiplier=3.0 -import-cold-multiplier=0.0 | FileCheck %s --check-prefix=CHECK --check-prefix=HOT-DEFAULT
+; RUN: opt -function-import -summary-file %t3.thinlto.bc %t.bc -import-instr-limit=1 --S -import-hot-multiplier=3.0 | FileCheck %s --check-prefix=CHECK --check-prefix=HOT-DEFAULT
+; RUN: opt -function-import -summary-file %t3.thinlto.bc %t.bc -import-instr-limit=1 --S -import-hot-multiplier=3.0 -import-instr-evolution-factor=0.0 | FileCheck %s --check-prefix=CHECK --check-prefix=HOT-DEFAULT
+; RUN: opt -function-import -summary-file %t3.thinlto.bc %t.bc -import-instr-limit=1 --S -import-hot-multiplier=3.0 -import-hot-evolution-factor=1.0 | FileCheck %s --check-prefix=CHECK --check-prefix=HOT-DEFAULT
+; HOT-DEFAULT-DAG: define available_externally void @hot1()
+; HOT-DEFAULT-DAG: define available_externally void @hot2()
+; HOT-DEFAULT-DAG: define available_externally void @calledFromHot()
+; HOT-DEFAULT-DAG: define available_externally void @calledFromHot2()
+; HOT-DEFAULT-DAG: define available_externally void @none1()
+; HOT-DEFAULT-NOT: define available_externally void @cold()
+; HOT-DEFAULT-NOT: define available_externally void @hot3()
+; HOT-DEFAULT-NOT: define available_externally void @none2()
+; HOT-DEFAULT-NOT: define available_externally void @none3()
+; HOT-DEFAULT-NOT: define available_externally void @cold2()
+; HOT-DEFAULT-NOT: define available_externally void @calledFromCold()
+; HOT-DEFAULT-NOT: define available_externally void @calledFromNone()
+
+; This one tests if we decay threshold for hot callsites. With hot-evolution-factor of 0
+; we should not import any of calledFromHot functions
+; RUN: opt -function-import -summary-file %t3.thinlto.bc %t.bc -import-instr-limit=1 --S -import-hot-multiplier=3.0 -import-hot-evolution-factor=0.0 | FileCheck %s --check-prefix=CHECK --check-prefix=HOT-EVOLUTION
+; HOT-EVOLUTION-DAG: define available_externally void @hot1()
+; HOT-EVOLUTION-DAG: define available_externally void @hot2()
+; HOT-EVOLUTION-DAG: define available_externally void @none1()
+; HOT-EVOLUTION-NOT: define available_externally void @hot3()
+; HOT-EVOLUTION-NOT: define available_externally void @cold()
+; HOT-EVOLUTION-NOT: define available_externally void @none2()
+; HOT-EVOLUTION-NOT: define available_externally void @none3()
+; HOT-EVOLUTION-NOT: define available_externally void @cold2()
+; HOT-EVOLUTION-NOT: define available_externally void @calledFromHot()
+; HOT-EVOLUTION-NOT: define available_externally void @calledFromHot2()
+
+; Test import with hot multiplier 1.0 - treat hot callsites as normal.
+; RUN: opt -function-import -summary-file %t3.thinlto.bc %t.bc -import-instr-limit=1 -import-hot-multiplier=1.0 --S | FileCheck %s --check-prefix=CHECK --check-prefix=HOT-ONE
+; HOT-ONE-DAG: define available_externally void @hot1()
+; HOT-ONE-DAG: define available_externally void @none1()
+; HOT-ONE-NOT: define available_externally void @cold()
+; HOT-ONE-NOT: define available_externally void @hot2()
+; HOT-ONE-NOT: define available_externally void @hot3()
+; HOT-ONE-NOT: define available_externally void @none2()
+; HOT-ONE-NOT: define available_externally void @none3()
+; HOT-ONE-NOT: define available_externally void @cold2()
+
+; RUN: opt -function-import -summary-file %t3.thinlto.bc %t.bc -import-instr-limit=1 -import-hot-multiplier=1.0 -import-cold-multiplier=1.0 --S | FileCheck %s --check-prefix=CHECK --check-prefix=HOT-COLD-ONE
+; HOT-COLD-ONE-DAG: define available_externally void @hot1()
+; HOT-COLD-ONE-DAG: define available_externally void @cold()
+; HOT-COLD-ONE-DAG: define available_externally void @none1()
+; HOT-COLD-ONE-NOT: define available_externally void @hot2()
+; HOT-COLD-ONE-NOT: define available_externally void @hot3()
+; HOT-COLD-ONE-NOT: define available_externally void @none2()
+; HOT-COLD-ONE-NOT: define available_externally void @none3()
+; HOT-COLD-ONE-NOT: define available_externally void @cold2()
+
+; Test import with hot multiplier 0.0 and high threshold - don't import functions called from hot callsite.
+; RUN: opt -function-import -summary-file %t3.thinlto.bc %t.bc -import-instr-limit=10 -import-hot-multiplier=0.0 -import-cold-multiplier=1.0 --S | FileCheck %s --check-prefix=CHECK --check-prefix=HOT-ZERO
+; HOT-ZERO-DAG: define available_externally void @cold()
+; HOT-ZERO-DAG: define available_externally void @none1()
+; HOT-ZERO-DAG: define available_externally void @none2()
+; HOT-ZERO-DAG: define available_externally void @none3()
+; HOT-ZERO-DAG: define available_externally void @cold2()
+; HOT-ZERO-DAG: define available_externally void @calledFromCold()
+; HOT-ZERO-DAG: define available_externally void @calledFromNone()
+; HOT-ZERO-NOT: define available_externally void @hot2()
+; HOT-ZERO-NOT: define available_externally void @hot1()
+; HOT-ZERO-NOT: define available_externally void @hot3()
+; HOT-ZERO-NOT: define available_externally void @calledFromHot()
+; HOT-ZERO-NOT: define available_externally void @calledFromHot2()
+
+
+; ModuleID = 'thinlto-function-summary-callgraph.ll'
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; This function have high profile count, so entry block is hot.
+define void @hot_function(i1 %a, i1 %a2) !prof !20 {
+entry:
+ call void @hot1()
+ br i1 %a, label %Cold, label %Hot, !prof !41
+Cold: ; 1/1000 goes here
+ call void @cold()
+ call void @cold2()
+ call void @hot2()
+ call void @none1()
+ br label %exit
+Hot: ; 999/1000 goes here
+ call void @hot2()
+ call void @hot3()
+ br i1 %a2, label %None1, label %None2, !prof !42
+None1: ; half goes here
+ call void @none1()
+ call void @none2()
+ br label %exit
+None2: ; half goes here
+ call void @none3()
+ br label %exit
+exit:
+ ret void
+}
+
+declare void @hot1() #1
+declare void @hot2() #1
+declare void @hot3() #1
+declare void @cold() #1
+declare void @cold2() #1
+declare void @none1() #1
+declare void @none2() #1
+declare void @none3() #1
+
+
+!41 = !{!"branch_weights", i32 1, i32 1000}
+!42 = !{!"branch_weights", i32 1, i32 1}
+
+
+
+!llvm.module.flags = !{!1}
+!20 = !{!"function_entry_count", i64 110}
+
+!1 = !{i32 1, !"ProfileSummary", !2}
+!2 = !{!3, !4, !5, !6, !7, !8, !9, !10}
+!3 = !{!"ProfileFormat", !"InstrProf"}
+!4 = !{!"TotalCount", i64 10000}
+!5 = !{!"MaxCount", i64 10}
+!6 = !{!"MaxInternalCount", i64 1}
+!7 = !{!"MaxFunctionCount", i64 1000}
+!8 = !{!"NumCounts", i64 3}
+!9 = !{!"NumFunctions", i64 3}
+!10 = !{!"DetailedSummary", !11}
+!11 = !{!12, !13, !14}
+!12 = !{i32 10000, i64 100, i32 1}
+!13 = !{i32 999000, i64 100, i32 1}
+!14 = !{i32 999999, i64 1, i32 2}
diff --git a/llvm/test/Transforms/FunctionImport/import_stats.ll b/llvm/test/Transforms/FunctionImport/import_stats.ll
new file mode 100644
index 00000000000..2cb415d1e96
--- /dev/null
+++ b/llvm/test/Transforms/FunctionImport/import_stats.ll
@@ -0,0 +1,71 @@
+; Test to check thin link importing stats
+
+; -stats requires asserts
+; REQUIRES: asserts
+
+; REQUIRES: x86-registered-target
+
+; RUN: opt -module-summary %s -o %t.bc
+; RUN: opt -module-summary %p/Inputs/import_stats.ll -o %t2.bc
+
+; Test thin link stats with both new and old LTO
+; RUN: llvm-lto -thinlto-action=run -stats %t.bc %t2.bc \
+; RUN: 2>&1 | FileCheck %s --check-prefix=THINLINKSTATS
+; RUN: llvm-lto2 run -stats -o %t3 %t.bc %t2.bc \
+; RUN: -r %t.bc,hot_function,plx \
+; RUN: -r %t.bc,hot, \
+; RUN: -r %t.bc,critical, \
+; RUN: -r %t.bc,none, \
+; RUN: -r %t2.bc,hot,plx \
+; RUN: -r %t2.bc,critical,plx \
+; RUN: -r %t2.bc,none,plx \
+; RUN: -r %t2.bc,globalvar,plx \
+; RUN: 2>&1 | FileCheck %s --check-prefix=THINLINKSTATS
+
+; THINLINKSTATS-DAG: 1 function-import - Number of global variables thin link decided to import
+; THINLINKSTATS-DAG: 1 function-import - Number of critical functions thin link decided to import
+; THINLINKSTATS-DAG: 3 function-import - Number of functions thin link decided to import
+; THINLINKSTATS-DAG: 1 function-import - Number of hot functions thin link decided to import
+
+; ModuleID = 'import_stats.ll'
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; This function has a high profile count, so entry block is hot.
+define void @hot_function(i1 %a) !prof !20 {
+entry:
+ call void @hot()
+ call void @critical()
+ br i1 %a, label %None1, label %None2, !prof !42
+None1: ; half goes here
+ call void @none()
+ br label %exit
+None2: ; half goes here
+ br label %exit
+exit:
+ ret void
+}
+
+declare void @hot()
+declare void @none()
+declare void @critical()
+
+!42 = !{!"branch_weights", i32 1, i32 1}
+
+!llvm.module.flags = !{!1}
+!20 = !{!"function_entry_count", i64 100, i64 696010031887058302}
+
+!1 = !{i32 1, !"ProfileSummary", !2}
+!2 = !{!3, !4, !5, !6, !7, !8, !9, !10}
+!3 = !{!"ProfileFormat", !"InstrProf"}
+!4 = !{!"TotalCount", i64 300}
+!5 = !{!"MaxCount", i64 100}
+!6 = !{!"MaxInternalCount", i64 100}
+!7 = !{!"MaxFunctionCount", i64 100}
+!8 = !{!"NumCounts", i64 4}
+!9 = !{!"NumFunctions", i64 1}
+!10 = !{!"DetailedSummary", !11}
+!11 = !{!12, !13, !14}
+!12 = !{i32 10000, i64 100, i32 1}
+!13 = !{i32 999000, i64 100, i32 1}
+!14 = !{i32 999999, i64 1, i32 4}
diff --git a/llvm/test/Transforms/FunctionImport/inlineasm.ll b/llvm/test/Transforms/FunctionImport/inlineasm.ll
new file mode 100644
index 00000000000..de6fd7a9cfc
--- /dev/null
+++ b/llvm/test/Transforms/FunctionImport/inlineasm.ll
@@ -0,0 +1,19 @@
+; Do setup work for all below tests: generate bitcode and combined index
+; RUN: opt -module-summary %s -o %t.bc
+; RUN: opt -module-summary %p/Inputs/inlineasm.ll -o %t2.bc
+; RUN: llvm-lto -thinlto -o %t3 %t.bc %t2.bc
+
+; Attempt the import now, ensure below that file containing inline assembly
+; is not imported from. Otherwise we would need to promote its local variable
+; used in the inline assembly, which would not see the rename.
+; RUN: opt -function-import -summary-file %t3.thinlto.bc %t.bc -S 2>&1 | FileCheck %s
+
+define i32 @main() #0 {
+entry:
+ %f = alloca i64, align 8
+ call void @foo(i64* %f)
+ ret i32 0
+}
+
+; CHECK: declare void @foo(i64*)
+declare void @foo(i64*) #1
diff --git a/llvm/test/Transforms/FunctionImport/not-prevailing.ll b/llvm/test/Transforms/FunctionImport/not-prevailing.ll
new file mode 100644
index 00000000000..4412715e043
--- /dev/null
+++ b/llvm/test/Transforms/FunctionImport/not-prevailing.ll
@@ -0,0 +1,18 @@
+; RUN: opt -module-summary %s -o %t1.bc
+; RUN: opt -module-summary -o %t2.bc %S/Inputs/not-prevailing.ll
+; RUN: not llvm-lto2 run -o %t3.bc %t1.bc %t2.bc -r %t1.bc,bar,px \
+; RUN: -r %t1.bc,foo,x -r %t2.bc,foo,x -save-temps 2>&1 | FileCheck %s
+
+; CHECK: Interposable and available_externally/linkonce_odr/weak_odr symbol
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define available_externally i32 @foo() {
+ ret i32 1
+}
+
+define i32 @bar() {
+ %1 = call i32 @foo()
+ ret i32 %1
+}
OpenPOWER on IntegriCloud