blob: 5e61e941bffa2deec569595bfb32e16b113d1600 [file] [log] [blame]
# REQUIRES: x86
# RUN: rm -rf %t; split-file %s %t
## Check that we fold identical function bodies correctly. Note: This test
## has many different functions; each group of similarly-named functions aim
## to test one aspect of ICF's logic. To prevent accidental folding across
## groups, we use `mov` instructions with a variety of immediates, with
## different immediate values for each group.
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin19.0.0 %t/main.s -o %t/main.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin19.0.0 %t/abs.s -o %t/abs.o
# RUN: %lld -lSystem --icf=all -o %t/main %t/main.o %t/abs.o
# 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,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
# CHECK: [[#%x,NOT_ABS_REF:]] l F __TEXT,__text _not_abs_ref
# CHECK: [[#%x,DYLIB_REF_2:]] l F __TEXT,__text _dylib_ref_1
# CHECK: [[#%x,DYLIB_REF_2:]] l F __TEXT,__text _dylib_ref_2
# CHECK: [[#%x,DYLIB_REF_3:]] l F __TEXT,__text _dylib_ref_3
# 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,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
# CHECK: [[#%x,CHECK_LENGTH_1:]] l F __TEXT,__text _check_length_1
# CHECK: [[#%x,CHECK_LENGTH_2:]] l F __TEXT,__text _check_length_2
# CHECK: [[#%x,HAS_UNWIND_2:]] l F __TEXT,__text _has_unwind_1
# CHECK: [[#%x,HAS_UNWIND_2:]] l F __TEXT,__text _has_unwind_2
# CHECK: [[#%x,HAS_UNWIND_3:]] l F __TEXT,__text _has_unwind_3
# CHECK: [[#%x,MUTALLY_RECURSIVE_2:]] l F __TEXT,__text _mutually_recursive_1
# CHECK: [[#%x,MUTALLY_RECURSIVE_2:]] l F __TEXT,__text _mutually_recursive_2
# CHECK: [[#%x,INIT_2:]] l F __TEXT,__text _init_1
# CHECK: [[#%x,INIT_2:]] l F __TEXT,__text _init_2
# CHECK: [[#%x,INIT_3:]] l O __TEXT,__foo _init_3
### FIXME: Mutually-recursive functions with identical bodies (see below)
# COM: [[#%x,ASYMMETRIC_RECURSIVE_2:]] l F __TEXT,__text _asymmetric_recursive_1
# COM: [[#%x,ASYMMETRIC_RECURSIVE_2]] l F __TEXT,__text _asymmetric_recursive_2
# 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,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>
# CHECK: callq 0x[[#%x,NOT_ABS_REF:]] <_not_abs_ref>
# CHECK: callq 0x[[#%x,DYLIB_REF_2:]] <_dylib_ref_2>
# CHECK: callq 0x[[#%x,DYLIB_REF_2:]] <_dylib_ref_2>
# CHECK: callq 0x[[#%x,DYLIB_REF_3:]] <_dylib_ref_3>
# CHECK: callq 0x[[#%x,ALT:]] <_alt>
# CHECK: callq 0x[[#%x,WITH_ALT_ENTRY:]] <_with_alt_entry>
# CHECK: callq 0x[[#%x,WITH_ALT_ENTRY:]] <_with_alt_entry>
# CHECK: callq 0x[[#%x,DEFINED_REF_WITH_ADDEND_2:]] <_defined_ref_with_addend_2>
# CHECK: callq 0x[[#%x,DEFINED_REF_WITH_ADDEND_2:]] <_defined_ref_with_addend_2>
# CHECK: callq 0x[[#%x,RECURSIVE:]] <_recursive>
# CHECK: callq 0x[[#%x,CALL_RECURSIVE_2:]] <_call_recursive_2>
# CHECK: callq 0x[[#%x,CALL_RECURSIVE_2:]] <_call_recursive_2>
# CHECK: callq 0x[[#%x,CHECK_LENGTH_1:]] <_check_length_1>
# CHECK: callq 0x[[#%x,CHECK_LENGTH_2:]] <_check_length_2>
# CHECK: callq 0x[[#%x,HAS_UNWIND_2:]] <_has_unwind_2>
# CHECK: callq 0x[[#%x,HAS_UNWIND_2:]] <_has_unwind_2>
# CHECK: callq 0x[[#%x,HAS_UNWIND_3:]] <_has_unwind_3>
# CHECK: callq 0x[[#%x,MUTALLY_RECURSIVE_2:]] <_mutually_recursive_2>
# CHECK: callq 0x[[#%x,MUTALLY_RECURSIVE_2:]] <_mutually_recursive_2>
## FIXME: Mutually-recursive functions with identical bodies (see below)
# COM: callq 0x[[#%x,ASYMMETRIC_RECURSIVE_2]] <_asymmetric_recursive_2>
# COM: callq 0x[[#%x,ASYMMETRIC_RECURSIVE_2]] <_asymmetric_recursive_2>
# CHECK: callq 0x[[#%x,INIT_2:]] <_init_2>
# CHECK: callq 0x[[#%x,INIT_2:]] <_init_2>
# CHECK: callq 0x[[#%x,INIT_3:]] <_init_3>
### TODO:
### * Fold: funcs only differ in alignment
### * No fold: func is weak? preemptable?
### * Test that we hash things appropriately w/ minimal collisions
#--- abs.s
.subsections_via_symbols
.globl _abs1a, _abs1b, _abs2, _not_abs
_abs1a = 0xfac3
_abs1b = 0xfac3
_abs2 = 0xf00d
.data
.space 0xfac3
## _not_abs has the same Defined::value as _abs1{a,b}
_not_abs:
#--- main.s
.subsections_via_symbols
.text
_abs1a_ref:
movabs $_abs1a, %rdx
_abs1b_ref:
movabs $_abs1b, %rdx
_abs1a_ref_with_addend:
movabs $_abs1a + 3, %rdx
_abs1b_ref_with_addend:
movabs $_abs1b + 3, %rdx
## No fold: the absolute symbol value differs
_abs2_ref:
movabs $_abs2, %rdx
## No fold: _not_abs has the same value as _abs1{a,b}, but is not absolute.
_not_abs_ref:
movabs $_not_abs, %rdx
_dylib_ref_1:
mov ___nan@GOTPCREL(%rip), %rax
callq ___isnan
_dylib_ref_2:
mov ___nan@GOTPCREL(%rip), %rax
callq ___isnan
## No fold: referent dylib symbol differs
_dylib_ref_3:
mov ___inf@GOTPCREL(%rip), %rax
callq ___inf
## We can merge two sections even if one of them has an alt entry. Just make
## sure we don't merge the alt entry symbol with a regular symbol.
.alt_entry _alt
_with_alt_entry:
movq $3132, %rax
_alt:
ret
_no_alt_entry:
movq $3132, %rax
ret
_defined_ref_with_addend_1:
callq _with_alt_entry + 4
_defined_ref_with_addend_2:
callq _with_alt_entry + 4
## _recursive has the same body as its next two callers, but cannot be folded
## with them.
_recursive:
callq _recursive
_call_recursive_1:
callq _recursive
_call_recursive_2:
callq _recursive
## Functions of different lengths should not be folded
_check_length_1:
movq $97, %rax
_check_length_2:
movq $97, %rax
.space 1
_my_personality:
mov $1345, %rax
## Functions with identical unwind info should be folded.
_has_unwind_1:
.cfi_startproc
.cfi_personality 155, _my_personality
.cfi_def_cfa_offset 16
ret
.cfi_endproc
_has_unwind_2:
.cfi_startproc
.cfi_personality 155, _my_personality
.cfi_def_cfa_offset 16
ret
.cfi_endproc
## This function has different unwind info from the preceding two, and therefore
## should not be folded.
_has_unwind_3:
.cfi_startproc
.cfi_personality 155, _my_personality
.cfi_def_cfa_offset 8
ret
.cfi_endproc
## Fold: Mutually-recursive functions with symmetric bodies
_mutually_recursive_1:
callq _mutually_recursive_1 # call myself
callq _mutually_recursive_2 # call my twin
_mutually_recursive_2:
callq _mutually_recursive_2 # call myself
callq _mutually_recursive_1 # call my twin
## Fold: Mutually-recursive functions with identical bodies
##
## FIXME: This test is currently broken. Recursive call sites have no relocs
## and the non-zero displacement field is already written to the section
## data, while non-recursive call sites use symbol relocs and section data
## contains zeros in the displacement field. Thus, ICF's equalsConstant()
## finds that the section data doesn't match.
##
## ELF folds this case properly because it emits symbol relocs for all calls,
## even recursive ones.
_asymmetric_recursive_1:
callq _asymmetric_recursive_1 # call myself
callq _asymmetric_recursive_2 # call my twin
movl $3, %eax
_asymmetric_recursive_2:
callq _asymmetric_recursive_1 # call my twin
callq _asymmetric_recursive_2 # call myself
movl $3, %eax
_init_1:
movq $12938, %rax
## Fold: _init_2 is in a section that gets renamed and output as __text
.section __TEXT,__StaticInit
_init_2:
movq $12938, %rax
## No fold: _init_3 is in a different output section from _init_{1,2}
.section __TEXT,__foo
_init_3:
movq $12938, %rax
.text
.globl _main
_main:
callq _abs1a_ref
callq _abs1b_ref
callq _abs1a_ref_with_addend
callq _abs1b_ref_with_addend
callq _abs2_ref
callq _not_abs_ref
callq _dylib_ref_1
callq _dylib_ref_2
callq _dylib_ref_3
callq _alt
callq _with_alt_entry
callq _no_alt_entry
callq _defined_ref_with_addend_1
callq _defined_ref_with_addend_2
callq _recursive
callq _call_recursive_1
callq _call_recursive_2
callq _check_length_1
callq _check_length_2
callq _has_unwind_1
callq _has_unwind_2
callq _has_unwind_3
callq _mutually_recursive_1
callq _mutually_recursive_2
callq _asymmetric_recursive_1
callq _asymmetric_recursive_2
callq _init_1
callq _init_2
callq _init_3