Skip to content

Commit 234945b

Browse files
committed
[LLD][COFF] Add fat-lto-object support
1 parent 1b1fe1e commit 234945b

File tree

6 files changed

+160
-2
lines changed

6 files changed

+160
-2
lines changed

lld/COFF/Config.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,9 @@ struct Configuration {
207207
// Used for /thinlto-remote-compiler-arg:<arg>
208208
llvm::SmallVector<llvm::StringRef, 0> dtltoCompilerArgs;
209209

210+
// Used for /fat-lto-objects
211+
bool fatLTOObjects = false;
212+
210213
// Used for /opt:[no]ltodebugpassmanager
211214
bool ltoDebugPassManager = false;
212215

lld/COFF/Driver.cpp

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "llvm/Config/llvm-config.h"
2929
#include "llvm/LTO/LTO.h"
3030
#include "llvm/Object/COFFImportFile.h"
31+
#include "llvm/Object/IRObjectFile.h"
3132
#include "llvm/Option/Arg.h"
3233
#include "llvm/Option/ArgList.h"
3334
#include "llvm/Option/Option.h"
@@ -256,6 +257,23 @@ MemoryBufferRef LinkerDriver::takeBuffer(std::unique_ptr<MemoryBuffer> mb) {
256257
return mbref;
257258
}
258259

260+
InputFile *LinkerDriver::tryCreateFatLTOFile(MemoryBufferRef mb,
261+
StringRef archiveName,
262+
uint64_t offsetInArchive,
263+
bool lazy) {
264+
if (!ctx.config.fatLTOObjects)
265+
return nullptr;
266+
267+
Expected<MemoryBufferRef> fatLTOData =
268+
IRObjectFile::findBitcodeInMemBuffer(mb);
269+
270+
if (errorToBool(fatLTOData.takeError()))
271+
return nullptr;
272+
273+
return BitcodeFile::create(ctx, *fatLTOData, archiveName, offsetInArchive,
274+
lazy);
275+
}
276+
259277
void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> mb,
260278
bool wholeArchive, bool lazy) {
261279
StringRef filename = mb->getBufferIdentifier();
@@ -289,7 +307,14 @@ void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> mb,
289307
case file_magic::bitcode:
290308
addFile(BitcodeFile::create(ctx, mbref, "", 0, lazy));
291309
break;
292-
case file_magic::coff_object:
310+
case file_magic::coff_object: {
311+
InputFile *obj = tryCreateFatLTOFile(mbref, "", 0, lazy);
312+
if (obj)
313+
addFile(obj);
314+
else
315+
addFile(ObjFile::create(ctx, mbref, lazy));
316+
break;
317+
}
293318
case file_magic::coff_import_library:
294319
addFile(ObjFile::create(ctx, mbref, lazy));
295320
break;
@@ -374,7 +399,9 @@ void LinkerDriver::addArchiveBuffer(MemoryBufferRef mb, StringRef symName,
374399

375400
InputFile *obj;
376401
if (magic == file_magic::coff_object) {
377-
obj = ObjFile::create(ctx, mb);
402+
obj = tryCreateFatLTOFile(mb, parentName, offsetInArchive, /*lazy=*/false);
403+
if (!obj)
404+
obj = ObjFile::create(ctx, mb);
378405
} else if (magic == file_magic::bitcode) {
379406
obj = BitcodeFile::create(ctx, mb, parentName, offsetInArchive,
380407
/*lazy=*/false);
@@ -2121,6 +2148,10 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
21212148
config->dtltoCompilerArgs =
21222149
args::getStrings(args, OPT_thinlto_remote_compiler_arg);
21232150

2151+
// Handle /fat-lto-objects
2152+
config->fatLTOObjects =
2153+
args.hasFlag(OPT_fat_lto_objects, OPT_fat_lto_objects_no, false);
2154+
21242155
// Handle /dwodir
21252156
config->dwoDir = args.getLastArgValue(OPT_dwodir);
21262157

lld/COFF/Driver.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,8 @@ class LinkerDriver {
169169

170170
std::set<std::string> visitedLibs;
171171

172+
InputFile *tryCreateFatLTOFile(MemoryBufferRef mb, StringRef archiveName,
173+
uint64_t offsetInArchive, bool lazy);
172174
void addBuffer(std::unique_ptr<MemoryBuffer> mb, bool wholeArchive,
173175
bool lazy);
174176
void addArchiveBuffer(MemoryBufferRef mbref, StringRef symName,

lld/COFF/Options.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,9 @@ def thinlto_remote_compiler_prepend_arg : P<"thinlto-remote-compiler-prepend-arg
298298
def thinlto_remote_compiler_arg : P<"thinlto-remote-compiler-arg",
299299
"Compiler arguments for the ThinLTO distributor to pass for ThinLTO backend "
300300
"compilations">;
301+
defm fat_lto_objects: B<"fat-lto-objects",
302+
"Use the .llvm.lto section, which contains LLVM bitcode, in fat LTO object files to perform LTO.",
303+
"Ignore the .llvm.lto section in relocatable object files (default).">;
301304
def lto_obj_path : P<
302305
"lto-obj-path",
303306
"output native object for merged LTO unit to this path">;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# RUN: llvm-mc -filetype=obj -triple=i386-pc-win32 %s -o %t
2+
# RUN: env LLD_IN_TEST=1 not lld-link %t /out:/dev/null /fat-lto-objects 2>&1 | FileCheck %s
3+
4+
# CHECK: error:{{.*}} Invalid bitcode signature
5+
6+
.section .llvm.lto,"ynD"
7+
L_llvm.embedded.object:
8+
.asciz "BC\300\3365\000"

lld/test/COFF/fatlto/fatlto.test

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
;; Basic FatLTO tests.
2+
; REQUIRES: x86
3+
4+
; RUN: rm -rf %t && split-file %s %t && cd %t
5+
6+
;; Ensure that input files contain .llvm.lto section.
7+
; RUN: llc a-LTO.ll --filetype=obj -o a-fatLTO.o --relocation-model=pic
8+
; RUN: opt < a-LTO.ll --module-summary -o a-fatLTO.bc
9+
; RUN: llvm-objcopy --add-section=.llvm.lto=a-fatLTO.bc --set-section-flags=.llvm.lto=exclude a-fatLTO.o
10+
11+
; RUN: llc main-LTO.ll --filetype=obj -o main-fatLTO.o --relocation-model=pic
12+
; RUN: opt < main-LTO.ll --module-summary -o main-fatLTO.bc
13+
; RUN: llvm-objcopy --add-section=.llvm.lto=main-fatLTO.bc --set-section-flags=.llvm.lto=exclude main-fatLTO.o
14+
15+
; RUN: llvm-readobj --sections a-fatLTO.o | FileCheck --check-prefix=HAS_LLVM_LTO %s
16+
; RUN: llvm-readobj --sections main-fatLTO.o | FileCheck --check-prefix=HAS_LLVM_LTO %s
17+
18+
;; Make sure that the section flags are set correctly
19+
; HAS_LLVM_LTO: Name: .llvm.lto (2F 34 00 00 00 00 00 00)
20+
; HAS_LLVM_LTO: Characteristics [
21+
; HAS_LLVM_LTO-SAME: (0xC0000800)
22+
; HAS_LLVM_LTO-NEXT: IMAGE_SCN_LNK_REMOVE (0x800)
23+
; HAS_LLVM_LTO-NEXT: IMAGE_SCN_MEM_READ (0x40000000)
24+
; HAS_LLVM_LTO-NEXT: IMAGE_SCN_MEM_WRITE (0x80000000)
25+
; HAS_LLVM_LTO-NEXT: ]
26+
27+
;; Final executable should not have .llvm.lto section no matter what the target is.
28+
; RUN: lld-link /timestamp:0 /out:foo-fatLTO /entry:main a-fatLTO.o main-fatLTO.o -fat-lto-objects
29+
; RUN: llvm-readobj --sections foo-fatLTO | FileCheck --check-prefix=CHECK-LTO-TARGET %s
30+
31+
;; Check that fat objects work w/ --start-lib.
32+
; RUN: lld-link /out:foo-fatLTO.start_lib /entry:main -start-lib a-fatLTO.o main-fatLTO.o -fat-lto-objects
33+
; RUN: llvm-readobj --sections foo-fatLTO.start_lib | FileCheck --check-prefix=CHECK-LTO-TARGET %s
34+
35+
;; Check if .llvm.lto section gets aggregated in LTO target.
36+
; CHECK-LTO-TARGET-NOT: Name: .llvm.lto
37+
38+
;; Final executable should not have .llvm.lto section no matter what the target is.
39+
; RUN: lld-link /timestamp:0 /out:foo-fatNoLTO /entry:main a-fatLTO.o %/t/main-fatLTO.o
40+
; RUN: llvm-readobj --sections foo-fatNoLTO | FileCheck --check-prefix=CHECK-NON-LTO-TARGET %s
41+
42+
;; Check if .llvm.lto section gets aggregated in non-LTO target.
43+
; CHECK-NON-LTO-TARGET-NOT: Name: .llvm.lto
44+
45+
;; Check if the LTO target executable produced from FatLTO object file is
46+
;; identical to the one produced from LTO modules.
47+
; RUN: opt < a-LTO.ll --module-summary -o a-LTO.bc
48+
; RUN: opt < main-LTO.ll --module-summary -o main-LTO.bc
49+
; RUN: lld-link /timestamp:0 /out:foo-LTO /entry:main a-LTO.bc main-LTO.bc
50+
; RUN: cmp foo-fatLTO foo-LTO
51+
52+
;; Check if the no-LTO target executable produced from FatLTO object file is
53+
;; identical to the one produced from regular object files.
54+
; RUN: llc a-LTO.ll --filetype=obj -o a.o
55+
; RUN: llc main-LTO.ll --filetype=obj -o main.o
56+
; RUN: lld-link /timestamp:0 /out:foo-noLTO /entry:main a.o main.o
57+
; RUN: cmp foo-fatNoLTO foo-noLTO
58+
59+
;; Check archive support.
60+
; RUN: llvm-ar rcs a.a a-fatLTO.o
61+
; RUN: lld-link /timestamp:0 /out:foo-fatLTO.archive /entry:main /wholearchive a.a main-LTO.bc -fat-lto-objects
62+
; RUN: cmp foo-fatLTO.archive foo-LTO
63+
64+
;--- a-LTO.ll
65+
target datalayout = "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32-a:0:32-S32"
66+
target triple = "i386-pc-windows-msvc19.33.0"
67+
68+
; Function Attrs: noinline nounwind uwtable
69+
define dso_local i32 @_start() #0 {
70+
entry:
71+
ret i32 0
72+
}
73+
74+
attributes #0 = { noinline nounwind uwtable }
75+
76+
!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6}
77+
78+
!0 = !{i32 1, !"NumRegisterParameters", i32 0}
79+
!1 = !{i32 2, !"Debug Info Version", i32 3}
80+
!2 = !{i32 1, !"wchar_size", i32 2}
81+
!3 = !{i32 7, !"frame-pointer", i32 2}
82+
!4 = !{i32 1, !"MaxTLSAlign", i32 65536}
83+
!5 = !{i32 1, !"ThinLTO", i32 0}
84+
!6 = !{i32 1, !"EnableSplitLTOUnit", i32 1}
85+
86+
;--- main-LTO.ll
87+
target datalayout = "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32-a:0:32-S32"
88+
target triple = "i386-pc-windows-msvc19.33.0"
89+
90+
; Function Attrs: noinline nounwind uwtable
91+
define dso_local i32 @main() #0 {
92+
entry:
93+
%retval = alloca i32, align 4
94+
store i32 0, ptr %retval, align 4
95+
%call = call i32 (...) @_start()
96+
ret i32 %call
97+
}
98+
99+
declare i32 @_start(...)
100+
101+
attributes #0 = { noinline nounwind uwtable }
102+
103+
!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6}
104+
105+
!0 = !{i32 1, !"NumRegisterParameters", i32 0}
106+
!1 = !{i32 2, !"Debug Info Version", i32 3}
107+
!2 = !{i32 1, !"wchar_size", i32 2}
108+
!3 = !{i32 7, !"frame-pointer", i32 2}
109+
!4 = !{i32 1, !"MaxTLSAlign", i32 65536}
110+
!5 = !{i32 1, !"ThinLTO", i32 0}
111+
!6 = !{i32 1, !"EnableSplitLTOUnit", i32 1}

0 commit comments

Comments
 (0)