-
Notifications
You must be signed in to change notification settings - Fork 15.3k
Add FatLTO support for COFF #165529
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Add FatLTO support for COFF #165529
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -28,6 +28,7 @@ | |
| #include "llvm/Config/llvm-config.h" | ||
| #include "llvm/LTO/LTO.h" | ||
| #include "llvm/Object/COFFImportFile.h" | ||
| #include "llvm/Object/IRObjectFile.h" | ||
| #include "llvm/Option/Arg.h" | ||
| #include "llvm/Option/ArgList.h" | ||
| #include "llvm/Option/Option.h" | ||
|
|
@@ -256,6 +257,23 @@ MemoryBufferRef LinkerDriver::takeBuffer(std::unique_ptr<MemoryBuffer> mb) { | |
| return mbref; | ||
| } | ||
|
|
||
| InputFile *LinkerDriver::tryCreateFatLTOFile(MemoryBufferRef mb, | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think we need this as a member function, it could just be Additionnaly, can we also handle the |
||
| StringRef archiveName, | ||
| uint64_t offsetInArchive, | ||
| bool lazy) { | ||
| if (!ctx.config.fatLTOObjects) | ||
| return nullptr; | ||
|
|
||
| Expected<MemoryBufferRef> fatLTOData = | ||
| IRObjectFile::findBitcodeInMemBuffer(mb); | ||
|
|
||
| if (errorToBool(fatLTOData.takeError())) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This does not segregate between "we haven't found the bitstream in the COFF object" vs. "there's an error while parsing the object". If the return code is
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is true that any COFF error will be handled later by |
||
| return nullptr; | ||
|
|
||
| return BitcodeFile::create(ctx, *fatLTOData, archiveName, offsetInArchive, | ||
| lazy); | ||
| } | ||
|
|
||
| void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> mb, | ||
| bool wholeArchive, bool lazy) { | ||
| StringRef filename = mb->getBufferIdentifier(); | ||
|
|
@@ -289,7 +307,14 @@ void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> mb, | |
| case file_magic::bitcode: | ||
| addFile(BitcodeFile::create(ctx, mbref, "", 0, lazy)); | ||
| break; | ||
| case file_magic::coff_object: | ||
| case file_magic::coff_object: { | ||
| InputFile *obj = tryCreateFatLTOFile(mbref, "", 0, lazy); | ||
| if (obj) | ||
| addFile(obj); | ||
| else | ||
| addFile(ObjFile::create(ctx, mbref, lazy)); | ||
| break; | ||
| } | ||
| case file_magic::coff_import_library: | ||
| addFile(ObjFile::create(ctx, mbref, lazy)); | ||
| break; | ||
|
|
@@ -374,7 +399,9 @@ void LinkerDriver::addArchiveBuffer(MemoryBufferRef mb, StringRef symName, | |
|
|
||
| InputFile *obj; | ||
| if (magic == file_magic::coff_object) { | ||
| obj = ObjFile::create(ctx, mb); | ||
| obj = tryCreateFatLTOFile(mb, parentName, offsetInArchive, /*lazy=*/false); | ||
| if (!obj) | ||
| obj = ObjFile::create(ctx, mb); | ||
| } else if (magic == file_magic::bitcode) { | ||
| obj = BitcodeFile::create(ctx, mb, parentName, offsetInArchive, | ||
| /*lazy=*/false); | ||
|
|
@@ -2121,6 +2148,10 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) { | |
| config->dtltoCompilerArgs = | ||
| args::getStrings(args, OPT_thinlto_remote_compiler_arg); | ||
|
|
||
| // Handle /fat-lto-objects | ||
| config->fatLTOObjects = | ||
| args.hasFlag(OPT_fat_lto_objects, OPT_fat_lto_objects_no, false); | ||
|
|
||
| // Handle /dwodir | ||
| config->dwoDir = args.getLastArgValue(OPT_dwodir); | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| # RUN: llvm-mc -filetype=obj -triple=i386-pc-win32 %s -o %t | ||
| # RUN: env LLD_IN_TEST=1 not lld-link %t /out:/dev/null /fat-lto-objects 2>&1 | FileCheck %s | ||
|
|
||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are you able to handle a COFF error here as well? For example, when dealing with a FAT LTO .OBJ, any of the |
||
| # CHECK: error:{{.*}} Invalid bitcode signature | ||
|
|
||
| .section .llvm.lto,"ynD" | ||
| L_llvm.embedded.object: | ||
| .asciz "BC\300\3365\000" | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,111 @@ | ||
| ;; Basic FatLTO tests. | ||
| ; REQUIRES: x86 | ||
|
|
||
| ; RUN: rm -rf %t && split-file %s %t && cd %t | ||
|
|
||
| ;; Ensure that input files contain .llvm.lto section. | ||
| ; RUN: llc a-LTO.ll --filetype=obj -o a-fatLTO.o --relocation-model=pic | ||
| ; RUN: opt < a-LTO.ll --module-summary -o a-fatLTO.bc | ||
| ; RUN: llvm-objcopy --add-section=.llvm.lto=a-fatLTO.bc --set-section-flags=.llvm.lto=exclude a-fatLTO.o | ||
|
|
||
| ; RUN: llc main-LTO.ll --filetype=obj -o main-fatLTO.o --relocation-model=pic | ||
| ; RUN: opt < main-LTO.ll --module-summary -o main-fatLTO.bc | ||
| ; RUN: llvm-objcopy --add-section=.llvm.lto=main-fatLTO.bc --set-section-flags=.llvm.lto=exclude main-fatLTO.o | ||
|
|
||
| ; RUN: llvm-readobj --sections a-fatLTO.o | FileCheck --check-prefix=HAS_LLVM_LTO %s | ||
| ; RUN: llvm-readobj --sections main-fatLTO.o | FileCheck --check-prefix=HAS_LLVM_LTO %s | ||
|
|
||
| ;; Make sure that the section flags are set correctly | ||
| ; HAS_LLVM_LTO: Name: .llvm.lto (2F 34 00 00 00 00 00 00) | ||
| ; HAS_LLVM_LTO: Characteristics [ | ||
| ; HAS_LLVM_LTO-SAME: (0xC0000800) | ||
| ; HAS_LLVM_LTO-NEXT: IMAGE_SCN_LNK_REMOVE (0x800) | ||
| ; HAS_LLVM_LTO-NEXT: IMAGE_SCN_MEM_READ (0x40000000) | ||
| ; HAS_LLVM_LTO-NEXT: IMAGE_SCN_MEM_WRITE (0x80000000) | ||
| ; HAS_LLVM_LTO-NEXT: ] | ||
|
|
||
| ;; Final executable should not have .llvm.lto section no matter what the target is. | ||
| ; RUN: lld-link /timestamp:0 /out:foo-fatLTO /entry:main a-fatLTO.o main-fatLTO.o -fat-lto-objects | ||
| ; RUN: llvm-readobj --sections foo-fatLTO | FileCheck --check-prefix=CHECK-LTO-TARGET %s | ||
|
|
||
| ;; Check that fat objects work w/ --start-lib. | ||
| ; RUN: lld-link /out:foo-fatLTO.start_lib /entry:main -start-lib a-fatLTO.o main-fatLTO.o -fat-lto-objects | ||
| ; RUN: llvm-readobj --sections foo-fatLTO.start_lib | FileCheck --check-prefix=CHECK-LTO-TARGET %s | ||
|
|
||
| ;; Check if .llvm.lto section gets aggregated in LTO target. | ||
| ; CHECK-LTO-TARGET-NOT: Name: .llvm.lto | ||
|
|
||
| ;; Final executable should not have .llvm.lto section no matter what the target is. | ||
| ; RUN: lld-link /timestamp:0 /out:foo-fatNoLTO /entry:main a-fatLTO.o %/t/main-fatLTO.o | ||
| ; RUN: llvm-readobj --sections foo-fatNoLTO | FileCheck --check-prefix=CHECK-NON-LTO-TARGET %s | ||
|
|
||
| ;; Check if .llvm.lto section gets aggregated in non-LTO target. | ||
| ; CHECK-NON-LTO-TARGET-NOT: Name: .llvm.lto | ||
|
|
||
| ;; Check if the LTO target executable produced from FatLTO object file is | ||
| ;; identical to the one produced from LTO modules. | ||
| ; RUN: opt < a-LTO.ll --module-summary -o a-LTO.bc | ||
| ; RUN: opt < main-LTO.ll --module-summary -o main-LTO.bc | ||
| ; RUN: lld-link /timestamp:0 /out:foo-LTO /entry:main a-LTO.bc main-LTO.bc | ||
| ; RUN: cmp foo-fatLTO foo-LTO | ||
|
|
||
| ;; Check if the no-LTO target executable produced from FatLTO object file is | ||
| ;; identical to the one produced from regular object files. | ||
| ; RUN: llc a-LTO.ll --filetype=obj -o a.o | ||
| ; RUN: llc main-LTO.ll --filetype=obj -o main.o | ||
| ; RUN: lld-link /timestamp:0 /out:foo-noLTO /entry:main a.o main.o | ||
| ; RUN: cmp foo-fatNoLTO foo-noLTO | ||
|
|
||
| ;; Check archive support. | ||
| ; RUN: llvm-ar rcs a.a a-fatLTO.o | ||
| ; RUN: lld-link /timestamp:0 /out:foo-fatLTO.archive /entry:main /wholearchive a.a main-LTO.bc -fat-lto-objects | ||
| ; RUN: cmp foo-fatLTO.archive foo-LTO | ||
|
|
||
| ;--- a-LTO.ll | ||
| 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" | ||
| target triple = "i386-pc-windows-msvc19.33.0" | ||
|
|
||
| ; Function Attrs: noinline nounwind uwtable | ||
| define dso_local i32 @_start() #0 { | ||
| entry: | ||
| ret i32 0 | ||
| } | ||
|
|
||
| attributes #0 = { noinline nounwind uwtable } | ||
|
|
||
| !llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6} | ||
|
|
||
| !0 = !{i32 1, !"NumRegisterParameters", i32 0} | ||
| !1 = !{i32 2, !"Debug Info Version", i32 3} | ||
| !2 = !{i32 1, !"wchar_size", i32 2} | ||
| !3 = !{i32 7, !"frame-pointer", i32 2} | ||
| !4 = !{i32 1, !"MaxTLSAlign", i32 65536} | ||
| !5 = !{i32 1, !"ThinLTO", i32 0} | ||
| !6 = !{i32 1, !"EnableSplitLTOUnit", i32 1} | ||
|
|
||
| ;--- main-LTO.ll | ||
| 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" | ||
| target triple = "i386-pc-windows-msvc19.33.0" | ||
|
|
||
| ; Function Attrs: noinline nounwind uwtable | ||
| define dso_local i32 @main() #0 { | ||
| entry: | ||
| %retval = alloca i32, align 4 | ||
| store i32 0, ptr %retval, align 4 | ||
| %call = call i32 (...) @_start() | ||
| ret i32 %call | ||
| } | ||
|
|
||
| declare i32 @_start(...) | ||
|
|
||
| attributes #0 = { noinline nounwind uwtable } | ||
|
|
||
| !llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6} | ||
|
|
||
| !0 = !{i32 1, !"NumRegisterParameters", i32 0} | ||
| !1 = !{i32 2, !"Debug Info Version", i32 3} | ||
| !2 = !{i32 1, !"wchar_size", i32 2} | ||
| !3 = !{i32 7, !"frame-pointer", i32 2} | ||
| !4 = !{i32 1, !"MaxTLSAlign", i32 65536} | ||
| !5 = !{i32 1, !"ThinLTO", i32 0} | ||
| !6 = !{i32 1, !"EnableSplitLTOUnit", i32 1} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Align the prefix on the left side. You can add whitespaces to align the pattern if desired, they will be ignored by FileCheck.