[lld] r332169 - COFF: ICF a section and its associated sections as a unit.

Peter Collingbourne via llvm-commits llvm-commits at lists.llvm.org
Fri May 11 19:12:41 PDT 2018


Author: pcc
Date: Fri May 11 19:12:40 2018
New Revision: 332169

URL: http://llvm.org/viewvc/llvm-project?rev=332169&view=rev
Log:
COFF: ICF a section and its associated sections as a unit.

This is needed to avoid merging two functions with identical
instructions but different xdata. It also reduces binary size by
deduplicating identical pdata sections.

Fixes PR35337.

Differential Revision: https://reviews.llvm.org/D46672

Added:
    lld/trunk/test/COFF/icf-pdata.s
Modified:
    lld/trunk/COFF/ICF.cpp

Modified: lld/trunk/COFF/ICF.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/ICF.cpp?rev=332169&r1=332168&r2=332169&view=diff
==============================================================================
--- lld/trunk/COFF/ICF.cpp (original)
+++ lld/trunk/COFF/ICF.cpp Fri May 11 19:12:40 2018
@@ -45,6 +45,8 @@ public:
 private:
   void segregate(size_t Begin, size_t End, bool Constant);
 
+  bool assocEquals(const SectionChunk *A, const SectionChunk *B);
+
   bool equalsConstant(const SectionChunk *A, const SectionChunk *B);
   bool equalsVariable(const SectionChunk *A, const SectionChunk *B);
 
@@ -91,8 +93,9 @@ bool ICF::isEligible(SectionChunk *C) {
   if (C->getOutputCharacteristics() & llvm::COFF::IMAGE_SCN_MEM_EXECUTE)
     return true;
 
-  // .xdata unwind info sections are eligible.
-  if (C->getSectionName().split('$').first == ".xdata")
+  // .pdata and .xdata unwind info sections are eligible.
+  StringRef OutSecName = C->getSectionName().split('$').first;
+  if (OutSecName == ".pdata" || OutSecName == ".xdata")
     return true;
 
   // So are vtables.
@@ -125,6 +128,19 @@ void ICF::segregate(size_t Begin, size_t
   }
 }
 
+// Returns true if two sections' associative children are equal.
+bool ICF::assocEquals(const SectionChunk *A, const SectionChunk *B) {
+  auto ChildClasses = [&](const SectionChunk *SC) {
+    std::vector<uint32_t> Classes;
+    for (const SectionChunk *C : SC->children())
+      if (!C->SectionName.startswith(".debug") &&
+          C->SectionName != ".gfids$y" && C->SectionName != ".gljmp$y")
+        Classes.push_back(C->Class[Cnt % 2]);
+    return Classes;
+  };
+  return ChildClasses(A) == ChildClasses(B);
+}
+
 // Compare "non-moving" part of two sections, namely everything
 // except relocation targets.
 bool ICF::equalsConstant(const SectionChunk *A, const SectionChunk *B) {
@@ -154,7 +170,8 @@ bool ICF::equalsConstant(const SectionCh
   return A->getOutputCharacteristics() == B->getOutputCharacteristics() &&
          A->SectionName == B->SectionName && A->Alignment == B->Alignment &&
          A->Header->SizeOfRawData == B->Header->SizeOfRawData &&
-         A->Checksum == B->Checksum && A->getContents() == B->getContents();
+         A->Checksum == B->Checksum && A->getContents() == B->getContents() &&
+         assocEquals(A, B);
 }
 
 // Compare "moving" part of two sections, namely relocation targets.
@@ -170,7 +187,9 @@ bool ICF::equalsVariable(const SectionCh
         return D1->getChunk()->Class[Cnt % 2] == D2->getChunk()->Class[Cnt % 2];
     return false;
   };
-  return std::equal(A->Relocs.begin(), A->Relocs.end(), B->Relocs.begin(), Eq);
+  return std::equal(A->Relocs.begin(), A->Relocs.end(), B->Relocs.begin(),
+                    Eq) &&
+         assocEquals(A, B);
 }
 
 // Find the first Chunk after Begin that has a different class from Begin.

Added: lld/trunk/test/COFF/icf-pdata.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/icf-pdata.s?rev=332169&view=auto
==============================================================================
--- lld/trunk/test/COFF/icf-pdata.s (added)
+++ lld/trunk/test/COFF/icf-pdata.s Fri May 11 19:12:40 2018
@@ -0,0 +1,97 @@
+# RUN: llvm-mc %s -triple x86_64-windows-msvc -filetype=obj -o %t.obj
+# RUN: lld-link %t.obj -dll -noentry -out:%t.dll -merge:.xdata=.xdata
+# RUN: llvm-readobj -sections -coff-exports %t.dll | FileCheck %s
+
+# CHECK:         Name: .pdata
+# CHECK-NEXT:    VirtualSize: 0x18
+# CHECK:         Name: .xdata
+# CHECK-NEXT:    VirtualSize: 0x10
+
+# CHECK:         Name: xdata1
+# CHECK-NEXT:    RVA: 0x1010
+# CHECK:         Name: xdata1a
+# CHECK-NEXT:    RVA: 0x1010
+# CHECK:         Name: xdata1b
+# CHECK-NEXT:    RVA: 0x1030
+
+	.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
+
+# xdata1a is identical to xdata1, so it should be ICFd, and so should its pdata.
+# It also has associative debug and CFG sections which should be ignored by ICF.
+	.def	 xdata1a;
+	.scl	2;
+	.type	32;
+	.endef
+	.section	.text,"xr",one_only,xdata1a
+	.globl	xdata1a                  # -- Begin function xdata1a
+	.p2align	4, 0x90
+xdata1a:                                 # @xdata1a
+.seh_proc xdata1a
+# 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,xdata1a
+	.seh_endproc
+
+	.section .debug$S,"r",associative,xdata1a
+	.section .gfids$y,"r",associative,xdata1a
+	.section .gljmp$y,"r",associative,xdata1a
+
+# xdata1b's text is identical to xdata1, but its xdata specifies a different
+# stack size, so it cannot be ICFd with xdata1.
+	.def	 xdata1b;
+	.scl	2;
+	.type	32;
+	.endef
+	.section	.text,"xr",one_only,xdata1b
+	.globl	xdata1b                  # -- Begin function xdata1b
+	.p2align	4, 0x90
+xdata1b:                                 # @xdata1b
+.seh_proc xdata1b
+# BB#0:                                 # %entry
+	subq	$40, %rsp
+	.seh_stackalloc 48
+	.seh_endprologue
+	callq	callee
+	nop
+	addq	$40, %rsp
+	jmp	callee                  # TAILCALL
+	.seh_handlerdata
+	.section	.text,"xr",one_only,xdata1b
+	.seh_endproc
+                                        # -- End function
+
+	.section	.drectve,"yn"
+	.ascii	" -export:xdata1"
+	.ascii	" -export:xdata1a"
+	.ascii	" -export:xdata1b"




More information about the llvm-commits mailing list