summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Collingbourne <peter@pcc.me.uk>2017-06-12 00:05:54 +0000
committerPeter Collingbourne <peter@pcc.me.uk>2017-06-12 00:05:54 +0000
commitbfd5113ca1020054114602879daab4048574f8e5 (patch)
treec6eb6167dbe099d6179806d685ffc79c29246f73
parentdc7936ecedfdb88cbca3e9710bbecc823920ff07 (diff)
downloadbcm5719-llvm-bfd5113ca1020054114602879daab4048574f8e5.tar.gz
bcm5719-llvm-bfd5113ca1020054114602879daab4048574f8e5.zip
ELF: Teach ICF about relocations referring to merge input sections.
Relocations referring to merge sections are considered equal if they resolve to the same offset in the same output section. Differential Revision: https://reviews.llvm.org/D34094 llvm-svn: 305177
-rw-r--r--lld/ELF/ICF.cpp84
-rw-r--r--lld/test/ELF/Inputs/icf-merge-sec.s9
-rw-r--r--lld/test/ELF/Inputs/icf-merge.s10
-rw-r--r--lld/test/ELF/Inputs/icf-merge2.s10
-rw-r--r--lld/test/ELF/Inputs/icf-merge3.s10
-rw-r--r--lld/test/ELF/icf-merge-sec.s18
-rw-r--r--lld/test/ELF/icf-merge.s27
7 files changed, 146 insertions, 22 deletions
diff --git a/lld/ELF/ICF.cpp b/lld/ELF/ICF.cpp
index 536032bdc3a..09512a8b09d 100644
--- a/lld/ELF/ICF.cpp
+++ b/lld/ELF/ICF.cpp
@@ -98,7 +98,8 @@ private:
void segregate(size_t Begin, size_t End, bool Constant);
template <class RelTy>
- bool constantEq(ArrayRef<RelTy> RelsA, ArrayRef<RelTy> RelsB);
+ bool constantEq(const InputSection *A, ArrayRef<RelTy> RelsA,
+ const InputSection *B, ArrayRef<RelTy> RelsB);
template <class RelTy>
bool variableEq(const InputSection *A, ArrayRef<RelTy> RelsA,
@@ -206,11 +207,53 @@ void ICF<ELFT>::segregate(size_t Begin, size_t End, bool Constant) {
// Compare two lists of relocations.
template <class ELFT>
template <class RelTy>
-bool ICF<ELFT>::constantEq(ArrayRef<RelTy> RelsA, ArrayRef<RelTy> RelsB) {
- auto Eq = [](const RelTy &A, const RelTy &B) {
- return A.r_offset == B.r_offset &&
- A.getType(Config->IsMips64EL) == B.getType(Config->IsMips64EL) &&
- getAddend<ELFT>(A) == getAddend<ELFT>(B);
+bool ICF<ELFT>::constantEq(const InputSection *A, ArrayRef<RelTy> RelsA,
+ const InputSection *B, ArrayRef<RelTy> RelsB) {
+ auto Eq = [&](const RelTy &RA, const RelTy &RB) {
+ if (RA.r_offset != RB.r_offset ||
+ RA.getType(Config->IsMips64EL) != RB.getType(Config->IsMips64EL))
+ return false;
+ uint64_t AddA = getAddend<ELFT>(RA);
+ uint64_t AddB = getAddend<ELFT>(RB);
+
+ SymbolBody &SA = A->template getFile<ELFT>()->getRelocTargetSym(RA);
+ SymbolBody &SB = B->template getFile<ELFT>()->getRelocTargetSym(RB);
+ if (&SA == &SB)
+ return AddA == AddB;
+
+ auto *DA = dyn_cast<DefinedRegular>(&SA);
+ auto *DB = dyn_cast<DefinedRegular>(&SB);
+ if (!DA || !DB)
+ return false;
+
+ // Relocations referring to absolute symbols are constant-equal if their
+ // values are equal.
+ if (!DA->Section || !DB->Section)
+ return !DA->Section && !DB->Section &&
+ DA->Value + AddA == DB->Value + AddB;
+
+ if (DA->Section->kind() != DB->Section->kind())
+ return false;
+
+ // Relocations referring to InputSections are constant-equal if their
+ // section offsets are equal.
+ if (isa<InputSection>(DA->Section))
+ return DA->Value + AddA == DB->Value + AddB;
+
+ // Relocations referring to MergeInputSections are constant-equal if their
+ // offsets in the output section are equal.
+ auto *X = dyn_cast<MergeInputSection>(DA->Section);
+ if (!X)
+ return false;
+ auto *Y = cast<MergeInputSection>(DB->Section);
+ if (X->getParent() != Y->getParent())
+ return false;
+
+ uint64_t OffsetA =
+ SA.isSection() ? X->getOffset(AddA) : X->getOffset(DA->Value) + AddA;
+ uint64_t OffsetB =
+ SB.isSection() ? Y->getOffset(AddB) : Y->getOffset(DB->Value) + AddB;
+ return OffsetA == OffsetB;
};
return RelsA.size() == RelsB.size() &&
@@ -226,8 +269,9 @@ bool ICF<ELFT>::equalsConstant(const InputSection *A, const InputSection *B) {
return false;
if (A->AreRelocsRela)
- return constantEq(A->template relas<ELFT>(), B->template relas<ELFT>());
- return constantEq(A->template rels<ELFT>(), B->template rels<ELFT>());
+ return constantEq(A, A->template relas<ELFT>(), B,
+ B->template relas<ELFT>());
+ return constantEq(A, A->template rels<ELFT>(), B, B->template rels<ELFT>());
}
// Compare two lists of relocations. Returns true if all pairs of
@@ -243,22 +287,18 @@ bool ICF<ELFT>::variableEq(const InputSection *A, ArrayRef<RelTy> RelsA,
if (&SA == &SB)
return true;
- auto *DA = dyn_cast<DefinedRegular>(&SA);
- auto *DB = dyn_cast<DefinedRegular>(&SB);
- if (!DA || !DB)
- return false;
- if (DA->Value != DB->Value)
- return false;
-
- // Either both symbols must be absolute...
- if (!DA->Section || !DB->Section)
- return !DA->Section && !DB->Section;
+ auto *DA = cast<DefinedRegular>(&SA);
+ auto *DB = cast<DefinedRegular>(&SB);
- // Or the two sections must be in the same equivalence class.
+ // We already dealt with absolute and non-InputSection symbols in
+ // constantEq, and for InputSections we have already checked everything
+ // except the equivalence class.
+ if (!DA->Section)
+ return true;
auto *X = dyn_cast<InputSection>(DA->Section);
- auto *Y = dyn_cast<InputSection>(DB->Section);
- if (!X || !Y)
- return false;
+ if (!X)
+ return true;
+ auto *Y = cast<InputSection>(DB->Section);
// Ineligible sections are in the special equivalence class 0.
// They can never be the same in terms of the equivalence class.
diff --git a/lld/test/ELF/Inputs/icf-merge-sec.s b/lld/test/ELF/Inputs/icf-merge-sec.s
new file mode 100644
index 00000000000..7454e952e38
--- /dev/null
+++ b/lld/test/ELF/Inputs/icf-merge-sec.s
@@ -0,0 +1,9 @@
+.section .rodata.str,"aMS",@progbits,1
+.asciz "bar"
+.asciz "baz"
+.asciz "foo"
+
+.section .text.f2,"ax"
+.globl f2
+f2:
+.quad .rodata.str+8
diff --git a/lld/test/ELF/Inputs/icf-merge.s b/lld/test/ELF/Inputs/icf-merge.s
new file mode 100644
index 00000000000..8a099298f5c
--- /dev/null
+++ b/lld/test/ELF/Inputs/icf-merge.s
@@ -0,0 +1,10 @@
+.section .rodata.str,"aMS",@progbits,1
+.asciz "bar"
+.asciz "baz"
+foo:
+.asciz "foo"
+
+.section .text.f2,"ax"
+.globl f2
+f2:
+lea foo+42(%rip), %rax
diff --git a/lld/test/ELF/Inputs/icf-merge2.s b/lld/test/ELF/Inputs/icf-merge2.s
new file mode 100644
index 00000000000..e845a6177e2
--- /dev/null
+++ b/lld/test/ELF/Inputs/icf-merge2.s
@@ -0,0 +1,10 @@
+.section .rodata.str,"aMS",@progbits,1
+.asciz "bar"
+.asciz "baz"
+boo:
+.asciz "boo"
+
+.section .text.f2,"ax"
+.globl f2
+f2:
+lea boo+42(%rip), %rax
diff --git a/lld/test/ELF/Inputs/icf-merge3.s b/lld/test/ELF/Inputs/icf-merge3.s
new file mode 100644
index 00000000000..91bf05ebea2
--- /dev/null
+++ b/lld/test/ELF/Inputs/icf-merge3.s
@@ -0,0 +1,10 @@
+.section .rodata.str,"aMS",@progbits,1
+.asciz "bar"
+.asciz "baz"
+foo:
+.asciz "foo"
+
+.section .text.f2,"ax"
+.globl f2
+f2:
+lea foo+43(%rip), %rax
diff --git a/lld/test/ELF/icf-merge-sec.s b/lld/test/ELF/icf-merge-sec.s
new file mode 100644
index 00000000000..39f6a884fa9
--- /dev/null
+++ b/lld/test/ELF/icf-merge-sec.s
@@ -0,0 +1,18 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %S/Inputs/icf-merge-sec.s -o %t2
+# RUN: ld.lld %t %t2 -o %t3 --icf=all --verbose | FileCheck %s
+
+# CHECK: selected .text.f1
+# CHECK: removed .text.f2
+
+.section .rodata.str,"aMS",@progbits,1
+.asciz "foo"
+.asciz "string 1"
+.asciz "string 2"
+
+.section .text.f1,"ax"
+.globl f1
+f1:
+.quad .rodata.str
diff --git a/lld/test/ELF/icf-merge.s b/lld/test/ELF/icf-merge.s
new file mode 100644
index 00000000000..938b749da6b
--- /dev/null
+++ b/lld/test/ELF/icf-merge.s
@@ -0,0 +1,27 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %S/Inputs/icf-merge.s -o %t1
+# RUN: ld.lld %t %t1 -o %t1.out --icf=all --verbose | FileCheck %s
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %S/Inputs/icf-merge2.s -o %t2
+# RUN: ld.lld %t %t2 -o %t3.out --icf=all --verbose | FileCheck --check-prefix=NOMERGE %s
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %S/Inputs/icf-merge3.s -o %t3
+# RUN: ld.lld %t %t3 -o %t3.out --icf=all --verbose | FileCheck --check-prefix=NOMERGE %s
+
+# CHECK: selected .text.f1
+# CHECK: removed .text.f2
+
+# NOMERGE-NOT: selected .text.f
+
+.section .rodata.str,"aMS",@progbits,1
+foo:
+.asciz "foo"
+.asciz "string 1"
+.asciz "string 2"
+
+.section .text.f1,"ax"
+.globl f1
+f1:
+lea foo+42(%rip), %rax
OpenPOWER on IntegriCloud