From d99ac29a2461fa23bfb70e228037c708ccac9b2a Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Fri, 17 Nov 2017 19:50:10 +0000 Subject: [PATCH] All .xdata sections are eligble for ICF Summary: Many small functions have identical unwind info because they push the same sets of CSRs in the same order and have the same stack and prologue size. The VC linker merges duplicate .xdata, and so should LLD. This reduces the .xdata section size of clang.exe from 1.8MB to 94KB. Reviewers: pcc, ruiu Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D40160 llvm-svn: 318547 --- lld/COFF/ICF.cpp | 17 ++++++-- lld/test/COFF/icf-xdata.s | 86 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 3 deletions(-) create mode 100644 lld/test/COFF/icf-xdata.s diff --git a/lld/COFF/ICF.cpp b/lld/COFF/ICF.cpp index ea2aeac44f7f..5253911e0f99 100644 --- a/lld/COFF/ICF.cpp +++ b/lld/COFF/ICF.cpp @@ -73,12 +73,23 @@ uint32_t ICF::getHash(SectionChunk *C) { // 2017) says that /opt:icf folds both functions and read-only data. // Despite that, the MSVC linker folds only functions. We found // a few instances of programs that are not safe for data merging. -// Therefore, we merge only functions just like the MSVC tool. +// Therefore, we merge only functions just like the MSVC tool. However, we merge +// identical .xdata sections, because the address of unwind information is +// insignificant to the user program and the Visual C++ linker does this. bool ICF::isEligible(SectionChunk *C) { + // Non-comdat chunks, dead chunks, and writable chunks are not elegible. + bool Writable = C->getPermissions() & llvm::COFF::IMAGE_SCN_MEM_WRITE; + if (!C->isCOMDAT() || !C->isLive() || Writable) + return false; + + // Code sections with external symbols are eligible. bool Global = C->Sym && C->Sym->isExternal(); bool Executable = C->getPermissions() & llvm::COFF::IMAGE_SCN_MEM_EXECUTE; - bool Writable = C->getPermissions() & llvm::COFF::IMAGE_SCN_MEM_WRITE; - return C->isCOMDAT() && C->isLive() && Global && Executable && !Writable; + if (Global && Executable) + return true; + + // .xdata unwind info sections are eligble. + return C->getSectionName().split('$').first == ".xdata"; } // Split an equivalence class into smaller classes. diff --git a/lld/test/COFF/icf-xdata.s b/lld/test/COFF/icf-xdata.s new file mode 100644 index 000000000000..8fb4bad057bd --- /dev/null +++ b/lld/test/COFF/icf-xdata.s @@ -0,0 +1,86 @@ +# RUN: llvm-mc %s -triple x86_64-windows-msvc -filetype=obj -o %t.obj +# RUN: lld-link %t.obj -dll -noentry -out:%t.dll +# RUN: llvm-readobj -sections %t.dll | FileCheck %s + +# There shouldn't be much xdata, because all three .pdata entries (12 bytes +# each) should use the same .xdata unwind info. +# CHECK: Name: .pdata +# CHECK-NEXT: VirtualSize: 0x24 +# CHECK: Name: .xdata +# CHECK-NEXT: VirtualSize: 0x8 + + .text +callee: + ret + + .def xdata1; + .scl 2; + .type 32; + .endef + .section .text,"xr",one_only,xdata1 + .globl xdata1 # -- Begin function xdata1 + .p2align 4, 0x90 +xdata1: # @xdata1 +.seh_proc xdata1 +# BB#0: # %entry + subq $40, %rsp + .seh_stackalloc 40 + .seh_endprologue + callq callee + nop + addq $40, %rsp + jmp callee # TAILCALL + .seh_handlerdata + .section .text,"xr",one_only,xdata1 + .seh_endproc + # -- End function + .def xdata2; + .scl 2; + .type 32; + .endef + .section .text,"xr",one_only,xdata2 + .globl xdata2 # -- Begin function xdata2 + .p2align 4, 0x90 +xdata2: # @xdata2 +.seh_proc xdata2 +# BB#0: # %entry + subq $40, %rsp + .seh_stackalloc 40 + .seh_endprologue + callq callee + callq callee + nop + addq $40, %rsp + jmp callee # TAILCALL + .seh_handlerdata + .section .text,"xr",one_only,xdata2 + .seh_endproc + # -- End function + .def xdata3; + .scl 2; + .type 32; + .endef + .section .text,"xr",one_only,xdata3 + .globl xdata3 # -- Begin function xdata3 + .p2align 4, 0x90 +xdata3: # @xdata3 +.seh_proc xdata3 +# BB#0: # %entry + subq $40, %rsp + .seh_stackalloc 40 + .seh_endprologue + callq callee + callq callee + callq callee + nop + addq $40, %rsp + jmp callee # TAILCALL + .seh_handlerdata + .section .text,"xr",one_only,xdata3 + .seh_endproc + # -- End function + .section .drectve,"yn" + .ascii " -export:xdata1" + .ascii " -export:xdata2" + .ascii " -export:xdata3" +