Skip to content

Commit d2fdf78

Browse files
committed
[lld][WebAssembly] Implement --thinlto-index-only and --lto-obj-path.
The changes in this PR (both in the code and the tests) are largely copied directly from the ELF linker. Parial fix for #79604.
1 parent 56dcfbe commit d2fdf78

File tree

8 files changed

+241
-54
lines changed

8 files changed

+241
-54
lines changed

lld/test/wasm/lto/obj-path.ll

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
;; Copied from testr/ELF/lto/obj-path.ll
2+
;; Test --lto-obj-path= for regular LTO.
3+
4+
; RUN: rm -rf %t && split-file %s %t && cd %t
5+
; RUN: mkdir d
6+
; RUN: opt 1.ll -o 1.bc
7+
; RUN: opt 2.ll -o d/2.bc
8+
9+
; RUN: rm -f objpath.o
10+
; RUN: wasm-ld --lto-obj-path=objpath.o -shared 1.bc d/2.bc -o 3
11+
; RUN: llvm-nm 3 | FileCheck %s --check-prefix=NM
12+
; RUN: llvm-objdump -d objpath.o | FileCheck %s
13+
; RUN: ls 3* objpath* | count 2
14+
15+
; RUN: rm -f 3 objpath.o
16+
; RUN: wasm-ld --thinlto-index-only=3.txt --lto-obj-path=objpath.o -shared 1.bc d/2.bc -o 3
17+
; RUN: llvm-objdump -d objpath.o | FileCheck %s
18+
; RUN: not ls 3
19+
20+
; NM: T f
21+
; NM: T g
22+
23+
; CHECK: file format wasm
24+
; CHECK: <f>:
25+
; CHECK: <g>:
26+
27+
;; Test --lto-obj-path= for ThinLTO.
28+
; RUN: opt -module-summary 1.ll -o 1.bc
29+
; RUN: opt -module-summary 2.ll -o d/2.bc
30+
31+
; RUN: wasm-ld --lto-obj-path=objpath.o -shared 1.bc d/2.bc -o 3
32+
; RUN: llvm-nm 3 | FileCheck %s --check-prefix=NM3
33+
; RUN: llvm-objdump -d objpath.o1 | FileCheck %s --check-prefix=CHECK1
34+
; RUN: llvm-objdump -d objpath.o2 | FileCheck %s --check-prefix=CHECK2
35+
36+
; NM3: T f
37+
; NM3-NEXT: T g
38+
39+
; CHECK1: file format wasm
40+
; CHECK1-EMPTY:
41+
; CHECK1-NEXT: Disassembly of section CODE:
42+
; CHECK1: <f>:
43+
; CHECK1-EMPTY:
44+
; CHECK1-NEXT: end
45+
; CHECK1-NOT: {{.}}
46+
47+
; CHECK2: file format wasm
48+
; CHECK2-EMPTY:
49+
; CHECK2-NEXT: Disassembly of section CODE:
50+
; CHECK2: <g>:
51+
; CHECK2-EMPTY:
52+
; CHECK2-NEXT: end
53+
; CHECK2-NOT: {{.}}
54+
55+
;; With --thinlto-index-only, --lto-obj-path= creates just one file.
56+
; RUN: rm -f objpath.o objpath.o1 objpath.o2
57+
; RUN: wasm-ld --thinlto-index-only --lto-obj-path=objpath.o -shared 1.bc d/2.bc -o /dev/null
58+
; RUN: llvm-objdump -d objpath.o | FileCheck %s --check-prefix=EMPTY
59+
; RUN: not ls objpath.o1
60+
; RUN: not ls objpath.o2
61+
62+
;; Ensure lld emits empty combined module if specific obj-path.
63+
; RUN: mkdir obj
64+
; RUN: wasm-ld --lto-obj-path=objpath.o -shared 1.bc d/2.bc -o obj/out --save-temps
65+
; RUN: ls obj/out.lto.o out.lto.1.o d/out.lto.2.o
66+
67+
;; Ensure lld does not emit empty combined module by default.
68+
; RUN: rm -fr obj && mkdir obj
69+
; RUN: wasm-ld -shared 1.bc d/2.bc -o obj/out --save-temps
70+
; RUN: not test -e obj/out.lto.o
71+
72+
; EMPTY: file format wasm
73+
; EMPTY-NOT: {{.}}
74+
75+
;--- 1.ll
76+
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
77+
target triple = "wasm32-unknown-unknown"
78+
79+
declare void @g(...)
80+
81+
define void @f() {
82+
entry:
83+
call void (...) @g()
84+
ret void
85+
}
86+
87+
;--- 2.ll
88+
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
89+
target triple = "wasm32-unknown-unknown"
90+
91+
define void @g() {
92+
entry:
93+
ret void
94+
}

lld/test/wasm/lto/parallel.ll

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
; RUN: llvm-as -o %t.bc %s
2-
; RUN: rm -f %t.lto.o %t1.lto.o
3-
; RUN: wasm-ld --lto-partitions=2 -save-temps -o %t %t.bc -r
4-
; RUN: llvm-nm %t.lto.o | FileCheck --check-prefix=CHECK0 %s
5-
; RUN: llvm-nm %t1.lto.o | FileCheck --check-prefix=CHECK1 %s
1+
; RUN: rm -rf %t && mkdir %t && cd %t
2+
; RUN: llvm-as -o a.bc %s
3+
; RUN: wasm-ld --lto-partitions=2 -save-temps -o out a.bc -r
4+
; RUN: llvm-nm out.lto.o | FileCheck --check-prefix=CHECK0 %s
5+
; RUN: llvm-nm out.lto.1.o | FileCheck --check-prefix=CHECK1 %s
66

77
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
88
target triple = "wasm32-unknown-unknown-wasm"

lld/test/wasm/lto/thinlto.ll

Lines changed: 35 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,56 @@
11
; Basic ThinLTO tests.
2-
; RUN: opt -module-summary %s -o %t1.o
3-
; RUN: opt -module-summary %p/Inputs/thinlto.ll -o %t2.o
2+
; RUN: rm -rf %t && mkdir %t && cd %t
3+
; RUN: mkdir d e
4+
5+
; RUN: opt -module-summary %s -o a.o
6+
; RUN: opt -module-summary %p/Inputs/thinlto.ll -o d/b.o
47

58
; First force single-threaded mode
6-
; RUN: rm -f %t31.lto.o %t32.lto.o
7-
; RUN: wasm-ld -r -save-temps --thinlto-jobs=1 %t1.o %t2.o -o %t3
8-
; RUN: llvm-nm %t31.lto.o | FileCheck %s --check-prefix=NM1
9-
; RUN: llvm-nm %t32.lto.o | FileCheck %s --check-prefix=NM2
9+
; RUN: rm -f out.lto.a.o d/out.lto.b.o
10+
; RUN: wasm-ld -r -save-temps --thinlto-jobs=1 a.o d/b.o -o e/out
11+
; RUN: llvm-nm out.lto.a.o | FileCheck %s --check-prefix=NM1
12+
; RUN: llvm-nm d/out.lto.b.o | FileCheck %s --check-prefix=NM2
1013

1114
; Next force multi-threaded mode
12-
; RUN: rm -f %t31.lto.o %t32.lto.o
13-
; RUN: wasm-ld -r -save-temps --thinlto-jobs=2 %t1.o %t2.o -o %t3
14-
; RUN: llvm-nm %t31.lto.o | FileCheck %s --check-prefix=NM1
15-
; RUN: llvm-nm %t32.lto.o | FileCheck %s --check-prefix=NM2
15+
; RUN: rm -f out.lto.a.o d/out.lto.b.o
16+
; RUN: wasm-ld -r -save-temps --thinlto-jobs=2 a.o d/b.o -o e/out
17+
; RUN: llvm-nm out.lto.a.o | FileCheck %s --check-prefix=NM1
18+
; RUN: llvm-nm d/out.lto.b.o | FileCheck %s --check-prefix=NM2
1619

1720
;; --thinlto-jobs= defaults to --threads=.
18-
; RUN: rm -f %t31.lto.o %t32.lto.o
19-
; RUN: wasm-ld -r -save-temps --threads=2 %t1.o %t2.o -o %t3
20-
; RUN: llvm-nm %t31.lto.o | FileCheck %s --check-prefix=NM1
21-
; RUN: llvm-nm %t32.lto.o | FileCheck %s --check-prefix=NM2
21+
; RUN: rm -f out.lto.a.o d/out.lto.b.o
22+
; RUN: wasm-ld -r -save-temps --threads=2 a.o d/b.o -o e/out
23+
; RUN: llvm-nm out.lto.a.o | FileCheck %s --check-prefix=NM1
24+
; RUN: llvm-nm d/out.lto.b.o | FileCheck %s --check-prefix=NM2
2225

2326
;; --thinlto-jobs= overrides --threads=.
24-
; RUN: rm -f %t31.lto.o %t32.lto.o
25-
; RUN: wasm-ld -r -save-temps --threads=1 --thinlto-jobs=2 %t1.o %t2.o -o %t3
26-
; RUN: llvm-nm %t31.lto.o | FileCheck %s --check-prefix=NM1
27-
; RUN: llvm-nm %t32.lto.o | FileCheck %s --check-prefix=NM2
27+
; RUN: rm -f out.lto.a.o d/out.lto.b.o
28+
; RUN: wasm-ld -r -save-temps --threads=1 --thinlto-jobs=2 a.o d/b.o -o e/out
29+
; RUN: llvm-nm out.lto.a.o | FileCheck %s --check-prefix=NM1
30+
; RUN: llvm-nm d/out.lto.b.o | FileCheck %s --check-prefix=NM2
2831

2932
; Test with all threads, on all cores, on all CPU sockets
30-
; RUN: rm -f %t31.lto.o %t32.lto.o
31-
; RUN: wasm-ld -r -save-temps --thinlto-jobs=all %t1.o %t2.o -o %t3
32-
; RUN: llvm-nm %t31.lto.o | FileCheck %s --check-prefix=NM1
33-
; RUN: llvm-nm %t32.lto.o | FileCheck %s --check-prefix=NM2
33+
; RUN: rm -f out.lto.a.o d/out.lto.b.o
34+
; RUN: wasm-ld -r -save-temps --thinlto-jobs=all a.o d/b.o -o e/out
35+
; RUN: llvm-nm out.lto.a.o | FileCheck %s --check-prefix=NM1
36+
; RUN: llvm-nm d/out.lto.b.o | FileCheck %s --check-prefix=NM2
3437

3538
; Test with many more threads than the system has
36-
; RUN: rm -f %t31.lto.o %t32.lto.o
37-
; RUN: wasm-ld -r -save-temps --thinlto-jobs=100 %t1.o %t2.o -o %t3
38-
; RUN: llvm-nm %t31.lto.o | FileCheck %s --check-prefix=NM1
39-
; RUN: llvm-nm %t32.lto.o | FileCheck %s --check-prefix=NM2
39+
; RUN: rm -f out.lto.a.o d/out.lto.b.o
40+
; RUN: wasm-ld -r -save-temps --thinlto-jobs=100 a.o d/b.o -o e/out
41+
; RUN: llvm-nm out.lto.a.o | FileCheck %s --check-prefix=NM1
42+
; RUN: llvm-nm d/out.lto.b.o | FileCheck %s --check-prefix=NM2
4043

4144
; Test with a bad value
42-
; RUN: rm -f %t31.lto.o %t32.lto.o
43-
; RUN: not wasm-ld -r -save-temps --thinlto-jobs=foo %t1.o %t2.o -o %t3 2>&1 | FileCheck %s --check-prefix=BAD-JOBS
45+
; RUN: rm -f out.lto.a.o d/out.lto.b.o
46+
; RUN: not wasm-ld -r -save-temps --thinlto-jobs=foo a.o d/b.o -o e/out 2>&1 | FileCheck %s --check-prefix=BAD-JOBS
4447
; BAD-JOBS: error: --thinlto-jobs: invalid job count: foo
4548

4649
; Check without --thinlto-jobs (which currently defaults to heavyweight_hardware_concurrency, meanning one thread per hardware core -- not SMT)
47-
; RUN: rm -f %t31.lto.o %t32.lto.o
48-
; RUN: wasm-ld -r -save-temps %t1.o %t2.o -o %t3
49-
; RUN: llvm-nm %t31.lto.o | FileCheck %s --check-prefix=NM1
50-
; RUN: llvm-nm %t32.lto.o | FileCheck %s --check-prefix=NM2
50+
; RUN: rm -f out.lto.a.o d/out.lto.b.o
51+
; RUN: wasm-ld -r -save-temps a.o d/b.o -o e/out
52+
; RUN: llvm-nm out.lto.a.o | FileCheck %s --check-prefix=NM1
53+
; RUN: llvm-nm d/out.lto.b.o | FileCheck %s --check-prefix=NM2
5154

5255
; NM1: T f
5356
; NM2: T g

lld/wasm/Config.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ struct Configuration {
7979
// Because dyamanic linking under Wasm is still experimental we default to
8080
// static linking
8181
bool isStatic = true;
82+
bool thinLTOEmitIndexFiles;
83+
bool thinLTOIndexOnly;
8284
bool trace;
8385
uint64_t globalBase;
8486
uint64_t initialHeap;
@@ -95,16 +97,18 @@ struct Configuration {
9597
unsigned ltoo;
9698
llvm::CodeGenOptLevel ltoCgo;
9799
unsigned optimize;
98-
llvm::StringRef thinLTOJobs;
99100
bool ltoDebugPassManager;
100101
UnresolvedPolicy unresolvedSymbols;
101102
BuildIdKind buildId = BuildIdKind::None;
102103

103104
llvm::StringRef entry;
105+
llvm::StringRef ltoObjPath;
104106
llvm::StringRef mapFile;
105107
llvm::StringRef outputFile;
106108
llvm::StringRef soName;
107109
llvm::StringRef thinLTOCacheDir;
110+
llvm::StringRef thinLTOJobs;
111+
llvm::StringRef thinLTOIndexOnlyArg;
108112
llvm::StringRef whyExtract;
109113

110114
llvm::StringSet<> allowUndefinedSymbols;

lld/wasm/Driver.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,7 @@ static void readConfigs(opt::InputArgList &args) {
542542
else
543543
error("invalid codegen optimization level for LTO: " + Twine(ltoCgo));
544544
config->ltoPartitions = args::getInteger(args, OPT_lto_partitions, 1);
545+
config->ltoObjPath = args.getLastArgValue(OPT_lto_obj_path_eq);
545546
config->ltoDebugPassManager = args.hasArg(OPT_lto_debug_pass_manager);
546547
config->mapFile = args.getLastArgValue(OPT_Map);
547548
config->optimize = args::getInteger(args, OPT_O, 1);
@@ -569,6 +570,12 @@ static void readConfigs(opt::InputArgList &args) {
569570
config->thinLTOCachePolicy = CHECK(
570571
parseCachePruningPolicy(args.getLastArgValue(OPT_thinlto_cache_policy)),
571572
"--thinlto-cache-policy: invalid cache policy");
573+
config->thinLTOEmitIndexFiles = args.hasArg(OPT_thinlto_emit_index_files) ||
574+
args.hasArg(OPT_thinlto_index_only) ||
575+
args.hasArg(OPT_thinlto_index_only_eq);
576+
config->thinLTOIndexOnly = args.hasArg(OPT_thinlto_index_only) ||
577+
args.hasArg(OPT_thinlto_index_only_eq);
578+
config->thinLTOIndexOnlyArg = args.getLastArgValue(OPT_thinlto_index_only_eq);
572579
config->unresolvedSymbols = getUnresolvedSymbolPolicy(args);
573580
config->whyExtract = args.getLastArgValue(OPT_why_extract);
574581
errorHandler().verbose = args.hasArg(OPT_verbose);
@@ -1379,6 +1386,10 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
13791386

13801387
writeWhyExtract();
13811388

1389+
// Bail out if normal linked output is skipped due to LTO.
1390+
if (config->thinLTOIndexOnly)
1391+
return;
1392+
13821393
createOptionalSymbols();
13831394

13841395
// Resolve any variant symbols that were created due to signature

0 commit comments

Comments
 (0)