Index: lld/trunk/ELF/ICF.cpp =================================================================== --- lld/trunk/ELF/ICF.cpp +++ lld/trunk/ELF/ICF.cpp @@ -98,7 +98,8 @@ void segregate(size_t Begin, size_t End, bool Constant); template - bool constantEq(ArrayRef RelsA, ArrayRef RelsB); + bool constantEq(const InputSection *A, ArrayRef RelsA, + const InputSection *B, ArrayRef RelsB); template bool variableEq(const InputSection *A, ArrayRef RelsA, @@ -206,11 +207,53 @@ // Compare two lists of relocations. template template -bool ICF::constantEq(ArrayRef RelsA, ArrayRef 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(A) == getAddend(B); +bool ICF::constantEq(const InputSection *A, ArrayRef RelsA, + const InputSection *B, ArrayRef 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(RA); + uint64_t AddB = getAddend(RB); + + SymbolBody &SA = A->template getFile()->getRelocTargetSym(RA); + SymbolBody &SB = B->template getFile()->getRelocTargetSym(RB); + if (&SA == &SB) + return AddA == AddB; + + auto *DA = dyn_cast(&SA); + auto *DB = dyn_cast(&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(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(DA->Section); + if (!X) + return false; + auto *Y = cast(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 @@ return false; if (A->AreRelocsRela) - return constantEq(A->template relas(), B->template relas()); - return constantEq(A->template rels(), B->template rels()); + return constantEq(A, A->template relas(), B, + B->template relas()); + return constantEq(A, A->template rels(), B, B->template rels()); } // Compare two lists of relocations. Returns true if all pairs of @@ -243,22 +287,18 @@ if (&SA == &SB) return true; - auto *DA = dyn_cast(&SA); - auto *DB = dyn_cast(&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(&SA); + auto *DB = cast(&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(DA->Section); - auto *Y = dyn_cast(DB->Section); - if (!X || !Y) - return false; + if (!X) + return true; + auto *Y = cast(DB->Section); // Ineligible sections are in the special equivalence class 0. // They can never be the same in terms of the equivalence class. Index: lld/trunk/test/ELF/Inputs/icf-merge-sec.s =================================================================== --- lld/trunk/test/ELF/Inputs/icf-merge-sec.s +++ lld/trunk/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 Index: lld/trunk/test/ELF/Inputs/icf-merge.s =================================================================== --- lld/trunk/test/ELF/Inputs/icf-merge.s +++ lld/trunk/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 Index: lld/trunk/test/ELF/Inputs/icf-merge2.s =================================================================== --- lld/trunk/test/ELF/Inputs/icf-merge2.s +++ lld/trunk/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 Index: lld/trunk/test/ELF/Inputs/icf-merge3.s =================================================================== --- lld/trunk/test/ELF/Inputs/icf-merge3.s +++ lld/trunk/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 Index: lld/trunk/test/ELF/icf-merge-sec.s =================================================================== --- lld/trunk/test/ELF/icf-merge-sec.s +++ lld/trunk/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 Index: lld/trunk/test/ELF/icf-merge.s =================================================================== --- lld/trunk/test/ELF/icf-merge.s +++ lld/trunk/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