1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
|
# 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 -emit-compact-unwind-non-canonical=true -filetype=obj -triple=x86_64-apple-darwin19.0.0 %t/main.s -o %t/main.o
# RUN: llvm-mc -emit-compact-unwind-non-canonical=true -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
|