diff --git a/lld/MachO/ICF.cpp b/lld/MachO/ICF.cpp --- a/lld/MachO/ICF.cpp +++ b/lld/MachO/ICF.cpp @@ -99,12 +99,12 @@ return false; if (ra.offset != rb.offset) return false; - if (ra.addend != rb.addend) - return false; if (ra.referent.is() != rb.referent.is()) return false; InputSection *isecA, *isecB; + int64_t addA = ra.addend; + int64_t addB = rb.addend; if (ra.referent.is()) { const auto *sa = ra.referent.get(); const auto *sb = rb.referent.get(); @@ -113,15 +113,18 @@ if (isa(sa)) { const auto *da = cast(sa); const auto *db = cast(sb); + addA += da->value; + addB += db->value; if (da->isec && db->isec) { isecA = da->isec; isecB = db->isec; } else { assert(da->isAbsolute() && db->isAbsolute()); - return da->value == db->value; + return addA == addB; } } else { assert(isa(sa)); + assert(addA == 0 && addB == 0); return sa == sb; } } else { @@ -135,10 +138,10 @@ assert(isecA->kind() == isecB->kind()); // We will compare ConcatInputSection contents in equalsVariable. if (isa(isecA)) - return true; + return addA == addB; // Else we have two literal sections. References to them are equal iff their // offsets in the output section are equal. - return isecA->getOffset(ra.addend) == isecB->getOffset(rb.addend); + return isecA->getOffset(addA) == isecB->getOffset(addB); }; return std::equal(ia->relocs.begin(), ia->relocs.end(), ib->relocs.begin(), f); @@ -235,22 +238,10 @@ parallelForEach(icfInputs, [&](ConcatInputSection *isec) { uint64_t hash = isec->icfEqClass[icfPass % 2]; for (const Reloc &r : isec->relocs) { - if (auto *sym = r.referent.dyn_cast()) { - if (auto *dylibSym = dyn_cast(sym)) - hash += dylibSym->stubsHelperIndex; - else if (auto *defined = dyn_cast(sym)) { - if (defined->isec) { - if (auto isec = dyn_cast(defined->isec)) - hash += defined->value + isec->icfEqClass[icfPass % 2]; - else - hash += defined->isec->kind() + - defined->isec->getOffset(defined->value); - } else { - hash += defined->value; - } - } else - llvm_unreachable("foldIdenticalSections symbol kind"); - } + if (auto *sym = r.referent.dyn_cast()) + if (auto *defined = dyn_cast(sym)) + if (auto isec = dyn_cast_or_null(defined->isec)) + hash += isec->icfEqClass[icfPass % 2]; } // Set MSB to 1 to avoid collisions with non-hashed classes. isec->icfEqClass[(icfPass + 1) % 2] = hash | (1ull << 63); diff --git a/lld/test/MachO/icf-literals.s b/lld/test/MachO/icf-literals.s --- a/lld/test/MachO/icf-literals.s +++ b/lld/test/MachO/icf-literals.s @@ -7,38 +7,51 @@ # CHECK: _main: # CHECK-NEXT: callq _foo2_ref # CHECK-NEXT: callq _foo2_ref +# CHECK-NEXT: callq _lfoo2_ref +# CHECK-NEXT: callq _lfoo2_ref # CHECK-NEXT: callq _bar2_ref # CHECK-NEXT: callq _bar2_ref # CHECK-NEXT: callq _baz2_ref # CHECK-NEXT: callq _baz2_ref # CHECK-NEXT: callq _qux2_ref # CHECK-NEXT: callq _qux2_ref +# CHECK-NEXT: callq _lqux2_ref +# CHECK-NEXT: callq _lqux2_ref -# CHECK: [[#%.16x,FOO:]] l O __TEXT,__cstring _foo1 -# CHECK-NEXT: [[#%.16x,FOO:]] l O __TEXT,__cstring _foo2 -# CHECK-NEXT: [[#%.16x,BAR:]] l O __TEXT,__cstring _bar1 -# CHECK-NEXT: [[#%.16x,BAR:]] l O __TEXT,__cstring _bar2 -# CHECK-NEXT: [[#%.16x,BAZ:]] l O __TEXT,__literals _baz1 -# CHECK-NEXT: [[#%.16x,BAZ:]] l O __TEXT,__literals _baz2 -# CHECK-NEXT: [[#%.16x,QUX:]] l O __TEXT,__literals _qux1 -# CHECK-NEXT: [[#%.16x,QUX:]] l O __TEXT,__literals _qux2 -# CHECK-NEXT: [[#%.16x,FOO_REF:]] l F __TEXT,__text _foo1_ref -# CHECK-NEXT: [[#%.16x,FOO_REF:]] l F __TEXT,__text _foo2_ref -# CHECK-NEXT: [[#%.16x,BAR_REF:]] l F __TEXT,__text _bar1_ref -# CHECK-NEXT: [[#%.16x,BAR_REF:]] l F __TEXT,__text _bar2_ref -# CHECK-NEXT: [[#%.16x,BAZ_REF:]] l F __TEXT,__text _baz1_ref -# CHECK-NEXT: [[#%.16x,BAZ_REF:]] l F __TEXT,__text _baz2_ref -# CHECK-NEXT: [[#%.16x,QUX_REF:]] l F __TEXT,__text _qux1_ref -# CHECK-NEXT: [[#%.16x,QUX_REF:]] l F __TEXT,__text _qux2_ref +# CHECK: [[#%.16x,FOO:]] l O __TEXT,__cstring _foo1 +# CHECK-NEXT: [[#%.16x,FOO:]] l O __TEXT,__cstring _foo2 +# CHECK-NEXT: [[#%.16x,BAR:]] l O __TEXT,__cstring _bar1 +# CHECK-NEXT: [[#%.16x,BAR:]] l O __TEXT,__cstring _bar2 +# CHECK-NEXT: [[#%.16x,BAZ:]] l O __TEXT,__literals _baz1 +# CHECK-NEXT: [[#%.16x,BAZ:]] l O __TEXT,__literals _baz2 +# CHECK-NEXT: [[#%.16x,QUX:]] l O __TEXT,__literals _qux1 +# CHECK-NEXT: [[#%.16x,QUX:]] l O __TEXT,__literals _qux2 +# CHECK-NEXT: [[#%.16x,FOO_REF:]] l F __TEXT,__text _foo1_ref +# CHECK-NEXT: [[#%.16x,FOO_REF:]] l F __TEXT,__text _foo2_ref +# CHECK-NEXT: [[#%.16x,LFOO_REF:]] l F __TEXT,__text _lfoo1_ref +# CHECK-NEXT: [[#%.16x,LFOO_REF:]] l F __TEXT,__text _lfoo2_ref +# CHECK-NEXT: [[#%.16x,BAR_REF:]] l F __TEXT,__text _bar1_ref +# CHECK-NEXT: [[#%.16x,BAR_REF:]] l F __TEXT,__text _bar2_ref +# CHECK-NEXT: [[#%.16x,BAZ_REF:]] l F __TEXT,__text _baz1_ref +# CHECK-NEXT: [[#%.16x,BAZ_REF:]] l F __TEXT,__text _baz2_ref +# CHECK-NEXT: [[#%.16x,QUX_REF:]] l F __TEXT,__text _qux1_ref +# CHECK-NEXT: [[#%.16x,QUX_REF:]] l F __TEXT,__text _qux2_ref +# CHECK-NEXT: [[#%.16x,LQUX_REF:]] l F __TEXT,__text _lqux1_ref +# CHECK-NEXT: [[#%.16x,LQUX_REF:]] l F __TEXT,__text _lqux2_ref ## _foo1 vs _bar1: same section, different offsets ## _foo1 vs _baz1: same offset, different sections +## Lfoo*, Lqux*: different embedded addends pointing to the same content .cstring _foo1: .asciz "foo" _foo2: .asciz "foo" +Lfoo1: + .asciz "foo" +Lfoo2: + .asciz "foo" _bar1: .asciz "bar" _bar2: @@ -53,34 +66,50 @@ .quad 0xbeef _qux2: .quad 0xbeef +Lqux1: + .quad 0xbeef +Lqux2: + .quad 0xbeef .text _foo1_ref: - mov _foo1@GOTPCREL(%rip), %rax + mov _foo1(%rip), %rax _foo2_ref: - mov _foo2@GOTPCREL(%rip), %rax + mov _foo2(%rip), %rax +_lfoo1_ref: + mov Lfoo1(%rip), %rax +_lfoo2_ref: + mov Lfoo2(%rip), %rax _bar1_ref: - mov _bar1@GOTPCREL(%rip), %rax + mov _bar1(%rip), %rax _bar2_ref: - mov _bar2@GOTPCREL(%rip), %rax + mov _bar2(%rip), %rax _baz1_ref: - mov _baz1@GOTPCREL(%rip), %rax + mov _baz1(%rip), %rax _baz2_ref: - mov _baz2@GOTPCREL(%rip), %rax + mov _baz2(%rip), %rax _qux1_ref: - mov _qux1@GOTPCREL(%rip), %rax + mov _qux1(%rip), %rax _qux2_ref: - mov _qux2@GOTPCREL(%rip), %rax + mov _qux2(%rip), %rax +_lqux1_ref: + mov Lqux1(%rip), %rax +_lqux2_ref: + mov Lqux2(%rip), %rax .globl _main _main: callq _foo1_ref callq _foo2_ref + callq _lfoo1_ref + callq _lfoo2_ref callq _bar1_ref callq _bar2_ref callq _baz1_ref callq _baz2_ref callq _qux1_ref callq _qux2_ref + callq _lqux1_ref + callq _lqux2_ref .subsections_via_symbols diff --git a/lld/test/MachO/icf.s b/lld/test/MachO/icf.s --- a/lld/test/MachO/icf.s +++ b/lld/test/MachO/icf.s @@ -13,8 +13,9 @@ # RUN: llvm-objdump -d --syms %t/main | FileCheck %s # CHECK-LABEL: SYMBOL TABLE: -# CHECK: [[#%x,ABS1B_REF:]] l F __TEXT,__text _abs1a_ref -# CHECK: [[#%x,ABS1B_REF:]] l F __TEXT,__text _abs1b_ref +# CHECK: [[#%x,ABS1C_REF:]] l F __TEXT,__text _abs1a_ref +# CHECK: [[#%x,ABS1C_REF:]] l F __TEXT,__text _abs1b_ref +# CHECK: [[#%x,ABS1C_REF:]] l F __TEXT,__text _abs1c_ref # CHECK: [[#%x,ABS1B_REF_WITH_ADDEND:]] l F __TEXT,__text _abs1a_ref_with_addend # CHECK: [[#%x,ABS1B_REF_WITH_ADDEND:]] l F __TEXT,__text _abs1b_ref_with_addend # CHECK: [[#%x,ABS2_REF:]] l F __TEXT,__text _abs2_ref @@ -25,8 +26,9 @@ # CHECK: [[#%x,ALT:]] l F __TEXT,__text _alt # CHECK: [[#%x,WITH_ALT_ENTRY:]] l F __TEXT,__text _with_alt_entry # CHECK: [[#%x,WITH_ALT_ENTRY:]] l F __TEXT,__text _no_alt_entry -# CHECK: [[#%x,DEFINED_REF_WITH_ADDEND_2:]] l F __TEXT,__text _defined_ref_with_addend_1 -# CHECK: [[#%x,DEFINED_REF_WITH_ADDEND_2:]] l F __TEXT,__text _defined_ref_with_addend_2 +# CHECK: [[#%x,DEFINED_REF_WITH_ADDEND_3:]] l F __TEXT,__text _defined_ref_with_addend_1 +# CHECK: [[#%x,DEFINED_REF_WITH_ADDEND_3:]] l F __TEXT,__text _defined_ref_with_addend_2 +# CHECK: [[#%x,DEFINED_REF_WITH_ADDEND_3:]] l F __TEXT,__text _defined_ref_with_addend_3 # CHECK: [[#%x,RECURSIVE:]] l F __TEXT,__text _recursive # CHECK: [[#%x,CALL_RECURSIVE_2:]] l F __TEXT,__text _call_recursive_1 # CHECK: [[#%x,CALL_RECURSIVE_2:]] l F __TEXT,__text _call_recursive_2 @@ -45,8 +47,9 @@ # CHECK-LABEL: Disassembly of section __TEXT,__text: # CHECK: <_main>: -# CHECK: callq 0x[[#%x,ABS1B_REF:]] <_abs1b_ref> -# CHECK: callq 0x[[#%x,ABS1B_REF:]] <_abs1b_ref> +# CHECK: callq 0x[[#%x,ABS1C_REF:]] <_abs1c_ref> +# CHECK: callq 0x[[#%x,ABS1C_REF:]] <_abs1c_ref> +# CHECK: callq 0x[[#%x,ABS1C_REF:]] <_abs1c_ref> # CHECK: callq 0x[[#%x,ABS1B_REF_WITH_ADDEND:]] <_abs1b_ref_with_addend> # CHECK: callq 0x[[#%x,ABS1B_REF_WITH_ADDEND:]] <_abs1b_ref_with_addend> # CHECK: callq 0x[[#%x,ABS2_REF:]] <_abs2_ref> @@ -83,9 +86,10 @@ #--- abs.s .subsections_via_symbols -.globl _abs1a, _abs1b, _abs2, _not_abs +.globl _abs1a, _abs1b, _abs1c, _abs2, _not_abs _abs1a = 0xfac3 _abs1b = 0xfac3 +_abs1c = 0xfac2 _abs2 = 0xf00d .data @@ -103,6 +107,9 @@ _abs1b_ref: movabs $_abs1b, %rdx +_abs1c_ref: + movabs $_abs1c + 1, %rdx + _abs1a_ref_with_addend: movabs $_abs1a + 3, %rdx @@ -148,6 +155,9 @@ _defined_ref_with_addend_2: callq _with_alt_entry + 4 +_defined_ref_with_addend_3: + callq _alt + 14 ## same address as _with_alt_entry + 4 + ## _recursive has the same body as its next two callers, but cannot be folded ## with them. _recursive: @@ -234,6 +244,7 @@ _main: callq _abs1a_ref callq _abs1b_ref + callq _abs1c_ref callq _abs1a_ref_with_addend callq _abs1b_ref_with_addend callq _abs2_ref @@ -246,6 +257,7 @@ callq _no_alt_entry callq _defined_ref_with_addend_1 callq _defined_ref_with_addend_2 + callq _defined_ref_with_addend_3 callq _recursive callq _call_recursive_1 callq _call_recursive_2