# 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,MAIN:]] g F __TEXT,__text _main
-# CHECK: [[#%x,A:]] g F __TEXT,__text _a1
-# CHECK: [[#%x,H:]] g F __TEXT,__text _h
-# CHECK: [[#%x,A]] g F __TEXT,__text _a2
-# CHECK: [[#%x,A]] g F __TEXT,__text _a3
-# CHECK: [[#%x,B:]] g F __TEXT,__text _b
-# CHECK: [[#%x,B2:]] g F __TEXT,__text _b2
-# CHECK: [[#%x,C:]] g F __TEXT,__text _c
-# CHECK: [[#%x,D:]] g F __TEXT,__text _d
-# CHECK: [[#%x,E:]] g F __TEXT,__text _e
-# CHECK: [[#%x,F:]] g F __TEXT,__text _f
-# CHECK: [[#%x,G:]] g F __TEXT,__text _g
-# CHECK: [[#%x,I:]] g F __TEXT,__text _i
-# CHECK: [[#%x,J:]] g F __TEXT,__text _j
-# CHECK: [[#%x,SR:]] g F __TEXT,__text _sr1
-# CHECK: [[#%x,SR]] g F __TEXT,__text _sr2
-# CHECK: [[#%x,MR:]] g F __TEXT,__text _mr1
-# CHECK: [[#%x,MR]] g F __TEXT,__text _mr2
-# CHECK: [[#%x,K1:]] g O __TEXT,__foo _k1
-# CHECK: [[#%x,A:]] g F __TEXT,__text _k2
+# 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_1:]] l F __TEXT,__text _has_unwind_1
+# CHECK: [[#%x,HAS_UNWIND_2:]] l F __TEXT,__text _has_unwind_2
+# 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,XR:]] g F __TEXT,__text _xr1
-# COM: [[#%x,XR]] g F __TEXT,__text _xr2
+# 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: [[#%x,MAIN]] <_main>:
-# CHECK-NEXT: callq 0x[[#%x,A]] <_k2>
-# CHECK-NEXT: callq 0x[[#%x,A]] <_k2>
-# CHECK-NEXT: callq 0x[[#%x,A]] <_k2>
-# CHECK-NEXT: callq 0x[[#%x,B]] <_b>
-# CHECK-NEXT: callq 0x[[#%x,B2]] <_b2>
-# CHECK-NEXT: callq 0x[[#%x,C]] <_c>
-# CHECK-NEXT: callq 0x[[#%x,D]] <_d>
-# CHECK-NEXT: callq 0x[[#%x,E]] <_e>
-# CHECK-NEXT: callq 0x[[#%x,F]] <_f>
-# CHECK-NEXT: callq 0x[[#%x,G]] <_g>
-# CHECK-NEXT: callq 0x[[#%x,H]] <_h>
-# CHECK-NEXT: callq 0x[[#%x,I]] <_i>
-# CHECK-NEXT: callq 0x[[#%x,J]] <_j>
-# CHECK-NEXT: callq 0x[[#%x,K1]] <_k1>
-# CHECK-NEXT: callq 0x[[#%x,A]] <_k2>
-# CHECK-NEXT: callq 0x[[#%x,SR]] <_sr2>
-# CHECK-NEXT: callq 0x[[#%x,SR]] <_sr2>
-# CHECK-NEXT: callq 0x[[#%x,MR]] <_mr2>
-# CHECK-NEXT: callq 0x[[#%x,MR]] <_mr2>
-### FIXME: Mutually-recursive functions with identical bodies (see below)
-# COM-NEXT: callq 0x[[#%x,XR]] <_xr2>
-# COM-NEXT: callq 0x[[#%x,XR]] <_xr2>
+# 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_1:]] <_has_unwind_1>
+# CHECK: callq 0x[[#%x,HAS_UNWIND_2:]] <_has_unwind_2>
+# 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
#--- main.s
.subsections_via_symbols
.text
-.globl _h
-.alt_entry _h
-
-### Fold: _a1 & _a2 have identical bodies, flags, relocs
-.globl _a1
-.p2align 2
-_a1:
- callq _d
-### No fold: _h is an alt entry past _a1
-_h:
- mov ___nan@GOTPCREL(%rip), %rax
- callq ___isnan
+_abs1a_ref:
movabs $_abs1a, %rdx
- movl $0, %eax
- ret
-
-.globl _a2
-.p2align 2
-_a2:
- callq _d
- mov ___nan@GOTPCREL(%rip), %rax
- callq ___isnan
- movabs $_abs1a, %rdx
- movl $0, %eax
- ret
-### Fold: reference to absolute symbol with different name but identical value
-
-.globl _a3
-.p2align 2
-_a3:
- callq _d
- mov ___nan@GOTPCREL(%rip), %rax
- callq ___isnan
+_abs1b_ref:
movabs $_abs1b, %rdx
- movl $0, %eax
- ret
-### No fold: the absolute symbol value differs
+_abs1a_ref_with_addend:
+ movabs $_abs1a + 3, %rdx
-.globl _b
-.p2align 2
-_b:
- callq _d
- mov ___nan@GOTPCREL(%rip), %rax
- callq ___isnan
+_abs1b_ref_with_addend:
+ movabs $_abs1b + 3, %rdx
+
+## No fold: the absolute symbol value differs
+_abs2_ref:
movabs $_abs2, %rdx
- movl $0, %eax
- ret
-### No fold: _not_abs has the same value as _abs1{a,b}, but is not absolute.
+## No fold: _not_abs has the same value as _abs1{a,b}, but is not absolute.
+_not_abs_ref:
+ movabs $_not_abs, %rdx
-.globl _b2
-.p2align 2
-_b2:
- callq _d
+_dylib_ref_1:
mov ___nan@GOTPCREL(%rip), %rax
callq ___isnan
- movabs $_not_abs, %rdx
- movl $0, %eax
- ret
-
-### No fold: _c has slightly different body from _a1 & _a2
-.globl _c
-.p2align 2
-_c:
- callq _d
+_dylib_ref_2:
mov ___nan@GOTPCREL(%rip), %rax
callq ___isnan
- movabs $_abs1a, %rdx
- movl $1, %eax
- ret
-### No fold: _d has the same body as _a1 & _a2, but _d is recursive!
+## 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
-.globl _d
-.p2align 2
-_d:
- callq _d
- mov ___nan@GOTPCREL(%rip), %rax
- callq ___isnan
- movabs $_abs1a, %rdx
- movl $0, %eax
+_no_alt_entry:
+ movq $3132, %rax
ret
-### No fold: the function body is longer
+_defined_ref_with_addend_1:
+ callq _with_alt_entry + 4
-.globl _e
-.p2align 2
-_e:
- callq _d
- mov ___nan@GOTPCREL(%rip), %rax
- callq ___isnan
- movabs $_abs1a, %rdx
- movl $0, %eax
- ret
- nop
+_defined_ref_with_addend_2:
+ callq _with_alt_entry + 4
-### No fold: GOT referent dylib symbol differs
+## _recursive has the same body as its next two callers, but cannot be folded
+## with them.
+_recursive:
+ callq _recursive
-.globl _f
-.p2align 2
-_f:
- callq _d
- mov ___inf@GOTPCREL(%rip), %rax
- callq ___isnan
- movabs $_abs1a, %rdx
- movl $0, %eax
- ret
+_call_recursive_1:
+ callq _recursive
-### No fold: call referent dylib symbol differs
+_call_recursive_2:
+ callq _recursive
-.globl _g
-.p2align 2
-_g:
- callq _d
- mov ___nan@GOTPCREL(%rip), %rax
- callq ___isinf
- movabs $_abs1a, %rdx
- movl $0, %eax
- ret
+## Functions of different lengths should not be folded
+_check_length_1:
+ movq $97, %rax
+
+_check_length_2:
+ movq $97, %rax
+ .space 1
-### No fold: functions have personality and/or LSDA
-### Mere presence of personality and/or LSDA isolates a function into its own
-### equivalence class. We don't care if two functions happen to have identical
-### personality & LSDA.
+_my_personality:
+ mov $1345, %rax
-.globl _i
-.p2align 2
-_i:
+## No fold: functions have unwind info.
+## FIXME: Fold functions with identical unwind info.
+_has_unwind_1:
.cfi_startproc
- .cfi_personality 155, _my_personality0
- .cfi_lsda 16, _exception0
+ .cfi_personality 155, _my_personality
.cfi_def_cfa_offset 16
- callq _d
- mov ___nan@GOTPCREL(%rip), %rax
- callq ___isnan
- movabs $_abs1a, %rdx
- movl $0, %eax
ret
.cfi_endproc
-.globl _j
-.p2align 2
-_j:
+_has_unwind_2:
.cfi_startproc
- .cfi_personality 155, _my_personality0
- .cfi_lsda 16, _exception0
+ .cfi_personality 155, _my_personality
.cfi_def_cfa_offset 16
- callq _d
- mov ___nan@GOTPCREL(%rip), %rax
- callq ___isnan
- movabs $_abs1a, %rdx
- movl $0, %eax
ret
.cfi_endproc
-### No fold: _k1 is in a different section from _a1
-.section __TEXT,__foo
-.globl _k1
-.p2align 2
-_k1:
- callq _d
- mov ___nan@GOTPCREL(%rip), %rax
- callq ___isnan
- movabs $_abs1a, %rdx
- movl $0, %eax
- ret
- nopl (%rax)
-
-### Fold: _k2 is in a section that gets renamed and output as __text
-.section __TEXT,__StaticInit
-.globl _k2
-.p2align 2
-_k2:
- callq _d
- mov ___nan@GOTPCREL(%rip), %rax
- callq ___isnan
- movabs $_abs1a, %rdx
- movl $0, %eax
- ret
-## For some reason, llvm-mc generates different nop encodings when adding
-## padding for __StaticInit vs __text functions. So we explicitly specify the
-## nop here to make sure this function can be folded with _a1.
- nopl (%rax)
-
-### Fold: Simple recursion
-
-.text
-.globl _sr1
-.p2align 2
-_sr1:
- callq _sr1
- movl $0, %eax
- ret
-
-.globl _sr2
-.p2align 2
-_sr2:
- callq _sr2
- movl $0, %eax
- ret
-
-### Fold: Mutually-recursive functions with symmetric bodies
-
-.globl _mr1
-.p2align 2
-_mr1:
- callq _mr1 # call myself
- callq _mr2 # call my twin
- movl $0, %eax
- ret
-
-.globl _mr2
-.p2align 2
-_mr2:
- callq _mr2 # call myself
- callq _mr1 # call my twin
- movl $0, %eax
- ret
-
-### 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.
-
-.globl _xr1
-.p2align 2
-_xr1:
- callq _xr1 # call myself
- callq _xr2 # call my twin
+## 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
- ret
-.globl _xr2
-.p2align 2
-_xr2:
- callq _xr1 # call my twin
- callq _xr2 # call myself
+_asymmetric_recursive_2:
+ callq _asymmetric_recursive_1 # call my twin
+ callq _asymmetric_recursive_2 # call myself
movl $3, %eax
- ret
-###
+_init_1:
+ movq $12938, %rax
-.globl _main
-.p2align 2
-_main:
- callq _a1
- callq _a2
- callq _a3
- callq _b
- callq _b2
- callq _c
- callq _d
- callq _e
- callq _f
- callq _g
- callq _h
- callq _i
- callq _j
- callq _k1
- callq _k2
- callq _sr1
- callq _sr2
- callq _mr1
- callq _mr2
- callq _xr1
- callq _xr2
- ret
+## Fold: _init_2 is in a section that gets renamed and output as __text
+.section __TEXT,__StaticInit
+_init_2:
+ movq $12938, %rax
-.globl _my_personality0
-.p2align 2
-_my_personality0:
- movl $0, %eax
- ret
+## No fold: _init_3 is in a different output section from _init_{1,2}
+.section __TEXT,__foo
+_init_3:
+ movq $12938, %rax
-.section __TEXT,__gcc_except_tab
-.globl _exception0
-_exception0:
- .space 1
+.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 _mutually_recursive_1
+ callq _mutually_recursive_2
+ callq _asymmetric_recursive_1
+ callq _asymmetric_recursive_2
+ callq _init_1
+ callq _init_2
+ callq _init_3