This matches ld64's behavior.
I also extended the icf-stabs.s test to demonstrate that even though
folded symbols have size zero, we cannot use the size-zero property in
lieu of `wasIdenticalCodeFolded`, because size zero symbols should still
get STABS entries.
Reviewed By: #lld-macho, thakis
Differential Revision: https://reviews.llvm.org/D136001
copy->live = false;
copy->wasCoalesced = true;
copy->replacement = this;
- for (auto ©Sym : copy->symbols)
+ for (auto ©Sym : copy->symbols) {
copySym->wasIdenticalCodeFolded = true;
+ copySym->size = 0;
+ }
symbols.insert(symbols.end(), copy->symbols.begin(), copy->symbols.end());
copy->symbols.clear();
# CHECK: Sections:
# CHECK-NEXT: Idx Name Size VMA Type
# CHECK-NEXT: 0 __text {{[0-9a-f]+}} [[#%x,TEXT:]] TEXT
-# CHECK-NEXT: 1 obj {{[0-9a-f]+}} [[#%x,DATA:]] DATA
+# CHECK-NEXT: 1 obj {{[0-9a-f]+}} [[#%x,DATA:]] TEXT
# CHECK-NEXT: 2 __cstring {{[0-9a-f]+}} [[#%x,CSTR:]] DATA
# CHECK-NEXT: 3 __common {{[0-9a-f]+}} [[#%x,BSS:]] BSS
# CHECK: SYMBOL TABLE:
# CHECK-DAG: [[#%x,MAIN:]] g F __TEXT,__text _main
# CHECK-DAG: [[#%x,NUMBER:]] g O __DATA,__common _number
-# CHECK-DAG: [[#%x,FOO:]] g O __TEXT,obj _foo
+# CHECK-DAG: [[#%x,FOO:]] g F __TEXT,obj _foo
# CHECK-DAG: [[#%x,HIWORLD:]] g O __TEXT,__cstring _hello_world
# CHECK-DAG: [[#%x,HIITSME:]] g O __TEXT,__cstring _hello_its_me
# STRIPPED-DAG: <<dead>> 0x0000000F [ 3] literal string: Hello, it's me
# STRIPPED-DAG: <<dead>> 0x00000001 [ 1] _number
+# RUN: %lld --icf=all -map %t/icf-map %t/test.o %t/foo.o %t/c-string-literal.o -o %t/icf
+# RUN: FileCheck --check-prefix=ICF %s < %t/icf-map
+
+# ICF: Symbols:
+# ICF-DAG: 0x[[#%X,FOO:]] 0x00000000 [ 2] _foo
+# ICF-DAG: 0x[[#FOO]] 0x00000001 [ 1] _bar
+
#--- foo.s
-.section __TEXT,obj
+## ICF will only fold sections marked as pure_instructions
+.section __TEXT,obj,regular,pure_instructions
.globl _foo
+.alt_entry _alt_foo
_foo:
nop
+.subsections_via_symbols
+
#--- test.s
.comm _number, 1
-.globl _main
+.globl _main, _bar
+.alt_entry _alt_bar
+
_main:
ret
+.section __TEXT,obj,regular,pure_instructions
+_bar:
+ nop
+
+.subsections_via_symbols
+
#--- c-string-literal.s
.globl _hello_world, _hello_its_me
_hello_its_me:
.asciz "Hello, it's me"
+
+.subsections_via_symbols
# RUN: %lld -lSystem --icf=all %t.o -o %t
# RUN: dsymutil -s %t | FileCheck %s -DDIR=%t -DSRC_PATH=%t.o
-# This should include no N_FUN entry for _bar2 (which is ICF'd into _bar),
-# but it does include a SECT EXT entry.
-# CHECK: (N_SO ) 00 0000 0000000000000000 '/tmp{{[/\\]}}test.cpp'
+## This should include no N_FUN entry for _baz (which is ICF'd into _bar),
+## but it does include a SECT EXT entry.
+## NOTE: We do not omit the N_FUN entry for _bar even though it is of size zero.
+## Only folded symbols get omitted.
+## NOTE: Unlike ld64, we also omit the N_FUN entry for _baz2.
+# CHECK: (N_SO ) 00 0000 0000000000000000 '/tmp{{[/\\]}}test.cpp'
# CHECK-NEXT: (N_OSO ) 03 0001 {{.*}} '[[SRC_PATH]]'
-# CHECK-NEXT: (N_FUN ) 01 0000 [[#%.16x,MAIN:]] '_main'
+# CHECK-NEXT: (N_FUN ) 01 0000 [[#%.16x,MAIN:]] '_main'
# CHECK-NEXT: (N_FUN ) 00 0000 000000000000000b{{$}}
-# CHECK-NEXT: (N_FUN ) 01 0000 [[#%.16x,BAR:]] '_bar'
+# CHECK-NEXT: (N_FUN ) 01 0000 [[#%.16x,BAR:]] '_bar'
+# CHECK-NEXT: (N_FUN ) 00 0000 0000000000000000{{$}}
+# CHECK-NEXT: (N_FUN ) 01 0000 [[#BAR]] '_bar2'
# CHECK-NEXT: (N_FUN ) 00 0000 0000000000000001{{$}}
# CHECK-NEXT: (N_SO ) 01 0000 0000000000000000{{$}}
-# CHECK-DAG: ( SECT EXT) 01 0000 [[#MAIN]] '_main'
-# CHECK-DAG: ( SECT EXT) 01 0000 [[#BAR]] '_bar'
+# CHECK-DAG: ( SECT EXT) 01 0000 [[#MAIN]] '_main'
+# CHECK-DAG: ( SECT EXT) 01 0000 [[#BAR]] '_bar'
# CHECK-DAG: ( SECT EXT) 01 0000 [[#BAR]] '_bar2'
+# CHECK-DAG: ( SECT EXT) 01 0000 [[#BAR]] '_baz'
+# CHECK-DAG: ( SECT EXT) 01 0000 [[#BAR]] '_baz2'
# CHECK-DAG: ( {{.*}}) {{[0-9]+}} 0010 {{[0-9a-f]+}} '__mh_execute_header'
# CHECK-DAG: ( {{.*}}) {{[0-9]+}} 0100 0000000000000000 'dyld_stub_binder'
# CHECK-EMPTY:
.text
-.globl _bar, _bar2, _main
+.globl _bar, _bar2, _baz, _baz2, _main
.subsections_via_symbols
_bar:
+_bar2:
ret
-_bar2:
+_baz:
+_baz2:
ret
_main:
Lfunc_begin0:
call _bar
- call _bar2
+ call _baz
ret
Lfunc_end0: