389 lines
13 KiB
ArmAsm
389 lines
13 KiB
ArmAsm
# 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 --dwarf=frames %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,DYLIB_REF_4:]] l F __TEXT,__text _dylib_ref_4
|
|
# CHECK: [[#%x,ALT:]] l F __TEXT,__text _alt
|
|
# CHECK: [[#%x,WITH_ALT_ENTRY:]] l F __TEXT,__text _with_alt_entry
|
|
# CHECK: [[#%x,NO_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_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
|
|
# 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,HAS_UNWIND_4:]] l F __TEXT,__text _has_unwind_4
|
|
# CHECK: [[#%x,HAS_ABS_PERSONALITY_1:]] l F __TEXT,__text _has_abs_personality_1
|
|
# CHECK: [[#%x,HAS_ABS_PERSONALITY_2:]] l F __TEXT,__text _has_abs_personality_2
|
|
# CHECK: [[#%x,HAS_EH_FRAME_1:]] l F __TEXT,__text _has_eh_frame_1
|
|
# CHECK: [[#%x,HAS_EH_FRAME_2:]] l F __TEXT,__text _has_eh_frame_2
|
|
# CHECK: [[#%x,HAS_EH_FRAME_3:]] l F __TEXT,__text _has_eh_frame_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: [[#%x,GCC_EXCEPT_0:]] l O __TEXT,__gcc_except_tab GCC_except_table0
|
|
# CHECK: [[#%x,GCC_EXCEPT_0]] l O __TEXT,__gcc_except_tab GCC_except_table1
|
|
# CHECK: [[#%x,GCC_EXCEPT_2:]] l O __TEXT,__gcc_except_tab GCC_except_table2
|
|
|
|
## Check that we don't accidentally dedup distinct EH frames.
|
|
# CHECK: FDE {{.*}} pc=[[#%x,HAS_EH_FRAME_1]]
|
|
# CHECK: FDE {{.*}} pc=[[#%x,HAS_EH_FRAME_2]]
|
|
# CHECK: FDE {{.*}} pc=[[#%x,HAS_EH_FRAME_3]]
|
|
|
|
# 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,DYLIB_REF_4]] <_dylib_ref_4>
|
|
# CHECK: callq 0x[[#%x,ALT]] <_alt>
|
|
# CHECK: callq 0x[[#%x,WITH_ALT_ENTRY]] <_with_alt_entry>
|
|
# CHECK: callq 0x[[#%x,NO_ALT_ENTRY]] <_no_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,DEFINED_REF_WITH_ADDEND_3]] <_defined_ref_with_addend_3>
|
|
# 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,HAS_UNWIND_4]] <_has_unwind_4>
|
|
# CHECK: callq 0x[[#%x,HAS_ABS_PERSONALITY_1]] <_has_abs_personality_1>
|
|
# CHECK: callq 0x[[#%x,HAS_ABS_PERSONALITY_2]] <_has_abs_personality_2>
|
|
# CHECK: callq 0x[[#%x,HAS_EH_FRAME_1]] <_has_eh_frame_1>
|
|
# CHECK: callq 0x[[#%x,HAS_EH_FRAME_2]] <_has_eh_frame_2>
|
|
# CHECK: callq 0x[[#%x,HAS_EH_FRAME_3]] <_has_eh_frame_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? preemptible?
|
|
### * 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
|
|
|
|
## No fold: referent dylib addend differs
|
|
_dylib_ref_4:
|
|
mov ___nan + 1@GOTPCREL(%rip), %rax
|
|
callq ___inf + 1
|
|
|
|
## Sections with alt entries cannot be merged.
|
|
.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
|
|
|
|
# No fold: addend differs
|
|
_defined_ref_with_addend_3:
|
|
callq _with_alt_entry + 8
|
|
|
|
## _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_lsda 16, Lexception0
|
|
.cfi_def_cfa_offset 16
|
|
ret
|
|
.cfi_endproc
|
|
|
|
_has_unwind_2:
|
|
.cfi_startproc
|
|
.cfi_personality 155, _my_personality
|
|
.cfi_lsda 16, Lexception1
|
|
.cfi_def_cfa_offset 16
|
|
ret
|
|
.cfi_endproc
|
|
|
|
## This function has a different cfa_offset from the first two, and therefore
|
|
## should not be folded.
|
|
_has_unwind_3:
|
|
.cfi_startproc
|
|
.cfi_personality 155, _my_personality
|
|
.cfi_lsda 16, Lexception1
|
|
.cfi_def_cfa_offset 8
|
|
ret
|
|
.cfi_endproc
|
|
|
|
## This function has a different LSDA from the first two, and therefore should
|
|
## not be folded.
|
|
_has_unwind_4:
|
|
.cfi_startproc
|
|
.cfi_personality 155, _my_personality
|
|
.cfi_lsda 16, Lexception2
|
|
.cfi_def_cfa_offset 16
|
|
ret
|
|
.cfi_endproc
|
|
|
|
## The next two functions should not be folded as they refer to personalities
|
|
## at different absolute addresses. This verifies that we are doing the right
|
|
## thing in our "data slicing hack" for compact unwind.
|
|
_has_abs_personality_1:
|
|
.cfi_startproc
|
|
.cfi_personality 155, _abs_personality_1
|
|
.cfi_def_cfa_offset 16
|
|
ret
|
|
.cfi_endproc
|
|
|
|
_has_abs_personality_2:
|
|
.cfi_startproc
|
|
.cfi_personality 155, _abs_personality_2
|
|
.cfi_def_cfa_offset 16
|
|
ret
|
|
.cfi_endproc
|
|
|
|
_abs_personality_1 = 0x1
|
|
_abs_personality_2 = 0x2
|
|
|
|
## In theory _has_eh_frame_{1, 2} can be dedup'ed, but we don't support this
|
|
## yet.
|
|
_has_eh_frame_1:
|
|
.cfi_startproc
|
|
.cfi_def_cfa_offset 8
|
|
## cfi_escape cannot be encoded in compact unwind
|
|
.cfi_escape 0x2e, 0x10
|
|
ret
|
|
.cfi_endproc
|
|
|
|
_has_eh_frame_2:
|
|
.cfi_startproc
|
|
.cfi_def_cfa_offset 8
|
|
## cfi_escape cannot be encoded in compact unwind
|
|
.cfi_escape 0x2e, 0x10
|
|
ret
|
|
.cfi_endproc
|
|
|
|
## The nop in this function body means that it cannot be folded with the
|
|
## previous two, even though the unwind info is otherwise identical.
|
|
_has_eh_frame_3:
|
|
.cfi_startproc
|
|
.cfi_def_cfa_offset 8
|
|
## cfi_escape cannot be encoded in compact unwind
|
|
.cfi_escape 0x2e, 0x10
|
|
nop
|
|
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 _dylib_ref_4
|
|
callq _alt
|
|
callq _with_alt_entry
|
|
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
|
|
callq _check_length_1
|
|
callq _check_length_2
|
|
callq _has_unwind_1
|
|
callq _has_unwind_2
|
|
callq _has_unwind_3
|
|
callq _has_unwind_4
|
|
callq _has_abs_personality_1
|
|
callq _has_abs_personality_2
|
|
callq _has_eh_frame_1
|
|
callq _has_eh_frame_2
|
|
callq _has_eh_frame_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
|
|
|
|
.section __TEXT,__gcc_except_tab
|
|
GCC_except_table0:
|
|
Lexception0:
|
|
.byte 255
|
|
|
|
GCC_except_table1:
|
|
Lexception1:
|
|
.byte 255
|
|
|
|
GCC_except_table2:
|
|
Lexception2:
|
|
.byte 254
|