xref: /llvm-project-15.0.7/lld/test/MachO/icf.s (revision f6017abb)
1# REQUIRES: x86
2# RUN: rm -rf %t; split-file %s %t
3
4## Check that we fold identical function bodies correctly. Note: This test
5## has many different functions; each group of similarly-named functions aim
6## to test one aspect of ICF's logic. To prevent accidental folding across
7## groups, we use `mov` instructions with a variety of immediates, with
8## different immediate values for each group.
9
10# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin19.0.0 %t/main.s -o %t/main.o
11# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin19.0.0 %t/abs.s -o %t/abs.o
12# RUN: %lld -lSystem --icf=all -o %t/main %t/main.o %t/abs.o
13# RUN: llvm-objdump -d --syms --dwarf=frames %t/main | FileCheck %s
14
15# CHECK-LABEL: SYMBOL TABLE:
16# CHECK: [[#%x,ABS1B_REF:]]                 l     F __TEXT,__text _abs1a_ref
17# CHECK: [[#%x,ABS1B_REF]]                  l     F __TEXT,__text _abs1b_ref
18# CHECK: [[#%x,ABS1B_REF_WITH_ADDEND:]]     l     F __TEXT,__text _abs1a_ref_with_addend
19# CHECK: [[#%x,ABS1B_REF_WITH_ADDEND]]      l     F __TEXT,__text _abs1b_ref_with_addend
20# CHECK: [[#%x,ABS2_REF:]]                  l     F __TEXT,__text _abs2_ref
21# CHECK: [[#%x,NOT_ABS_REF:]]               l     F __TEXT,__text _not_abs_ref
22# CHECK: [[#%x,DYLIB_REF_2:]]               l     F __TEXT,__text _dylib_ref_1
23# CHECK: [[#%x,DYLIB_REF_2]]                l     F __TEXT,__text _dylib_ref_2
24# CHECK: [[#%x,DYLIB_REF_3:]]               l     F __TEXT,__text _dylib_ref_3
25# CHECK: [[#%x,DYLIB_REF_4:]]               l     F __TEXT,__text _dylib_ref_4
26# CHECK: [[#%x,ALT:]]                       l     F __TEXT,__text _alt
27# CHECK: [[#%x,WITH_ALT_ENTRY:]]            l     F __TEXT,__text _with_alt_entry
28# CHECK: [[#%x,WITH_ALT_ENTRY]]             l     F __TEXT,__text _no_alt_entry
29# CHECK: [[#%x,DEFINED_REF_WITH_ADDEND_2:]] l     F __TEXT,__text _defined_ref_with_addend_1
30# CHECK: [[#%x,DEFINED_REF_WITH_ADDEND_2]]  l     F __TEXT,__text _defined_ref_with_addend_2
31# CHECK: [[#%x,DEFINED_REF_WITH_ADDEND_3:]] l     F __TEXT,__text _defined_ref_with_addend_3
32# CHECK: [[#%x,RECURSIVE:]]                 l     F __TEXT,__text _recursive
33# CHECK: [[#%x,CALL_RECURSIVE_2:]]          l     F __TEXT,__text _call_recursive_1
34# CHECK: [[#%x,CALL_RECURSIVE_2]]           l     F __TEXT,__text _call_recursive_2
35# CHECK: [[#%x,CHECK_LENGTH_1:]]            l     F __TEXT,__text _check_length_1
36# CHECK: [[#%x,CHECK_LENGTH_2:]]            l     F __TEXT,__text _check_length_2
37# CHECK: [[#%x,HAS_UNWIND_2:]]              l     F __TEXT,__text _has_unwind_1
38# CHECK: [[#%x,HAS_UNWIND_2]]               l     F __TEXT,__text _has_unwind_2
39# CHECK: [[#%x,HAS_UNWIND_3:]]              l     F __TEXT,__text _has_unwind_3
40# CHECK: [[#%x,HAS_UNWIND_4:]]              l     F __TEXT,__text _has_unwind_4
41# CHECK: [[#%x,HAS_ABS_PERSONALITY_1:]]     l     F __TEXT,__text _has_abs_personality_1
42# CHECK: [[#%x,HAS_ABS_PERSONALITY_2:]]     l     F __TEXT,__text _has_abs_personality_2
43# CHECK: [[#%x,HAS_EH_FRAME_1:]]            l     F __TEXT,__text _has_eh_frame_1
44# CHECK: [[#%x,HAS_EH_FRAME_2:]]            l     F __TEXT,__text _has_eh_frame_2
45# CHECK: [[#%x,HAS_EH_FRAME_3:]]            l     F __TEXT,__text _has_eh_frame_3
46# CHECK: [[#%x,MUTALLY_RECURSIVE_2:]]       l     F __TEXT,__text _mutually_recursive_1
47# CHECK: [[#%x,MUTALLY_RECURSIVE_2]]        l     F __TEXT,__text _mutually_recursive_2
48# CHECK: [[#%x,INIT_2:]]                    l     F __TEXT,__text _init_1
49# CHECK: [[#%x,INIT_2]]                     l     F __TEXT,__text _init_2
50# CHECK: [[#%x,INIT_3:]]                    l     O __TEXT,__foo  _init_3
51### FIXME: Mutually-recursive functions with identical bodies (see below)
52# COM:   [[#%x,ASYMMETRIC_RECURSIVE_2:]]    l   F __TEXT,__text _asymmetric_recursive_1
53# COM:   [[#%x,ASYMMETRIC_RECURSIVE_2]]     l   F __TEXT,__text _asymmetric_recursive_2
54# CHECK: [[#%x,GCC_EXCEPT_0:]]              l     O __TEXT,__gcc_except_tab GCC_except_table0
55# CHECK: [[#%x,GCC_EXCEPT_0]]               l     O __TEXT,__gcc_except_tab GCC_except_table1
56# CHECK: [[#%x,GCC_EXCEPT_2:]]              l     O __TEXT,__gcc_except_tab GCC_except_table2
57
58## Check that we don't accidentally dedup distinct EH frames.
59# CHECK: FDE {{.*}} pc=[[#%x,HAS_EH_FRAME_1]]
60# CHECK: FDE {{.*}} pc=[[#%x,HAS_EH_FRAME_2]]
61# CHECK: FDE {{.*}} pc=[[#%x,HAS_EH_FRAME_3]]
62
63# CHECK-LABEL: Disassembly of section __TEXT,__text:
64# CHECK:        <_main>:
65# CHECK: callq 0x[[#%x,ABS1B_REF]]                 <_abs1b_ref>
66# CHECK: callq 0x[[#%x,ABS1B_REF]]                 <_abs1b_ref>
67# CHECK: callq 0x[[#%x,ABS1B_REF_WITH_ADDEND]]     <_abs1b_ref_with_addend>
68# CHECK: callq 0x[[#%x,ABS1B_REF_WITH_ADDEND]]     <_abs1b_ref_with_addend>
69# CHECK: callq 0x[[#%x,ABS2_REF]]                  <_abs2_ref>
70# CHECK: callq 0x[[#%x,NOT_ABS_REF]]               <_not_abs_ref>
71# CHECK: callq 0x[[#%x,DYLIB_REF_2]]               <_dylib_ref_2>
72# CHECK: callq 0x[[#%x,DYLIB_REF_2]]               <_dylib_ref_2>
73# CHECK: callq 0x[[#%x,DYLIB_REF_3]]               <_dylib_ref_3>
74# CHECK: callq 0x[[#%x,DYLIB_REF_4]]               <_dylib_ref_4>
75# CHECK: callq 0x[[#%x,ALT]]                       <_alt>
76# CHECK: callq 0x[[#%x,WITH_ALT_ENTRY]]            <_with_alt_entry>
77# CHECK: callq 0x[[#%x,WITH_ALT_ENTRY]]            <_with_alt_entry>
78# CHECK: callq 0x[[#%x,DEFINED_REF_WITH_ADDEND_2]] <_defined_ref_with_addend_2>
79# CHECK: callq 0x[[#%x,DEFINED_REF_WITH_ADDEND_2]] <_defined_ref_with_addend_2>
80# CHECK: callq 0x[[#%x,DEFINED_REF_WITH_ADDEND_3]] <_defined_ref_with_addend_3>
81# CHECK: callq 0x[[#%x,RECURSIVE]]                 <_recursive>
82# CHECK: callq 0x[[#%x,CALL_RECURSIVE_2]]          <_call_recursive_2>
83# CHECK: callq 0x[[#%x,CALL_RECURSIVE_2]]          <_call_recursive_2>
84# CHECK: callq 0x[[#%x,CHECK_LENGTH_1]]            <_check_length_1>
85# CHECK: callq 0x[[#%x,CHECK_LENGTH_2]]            <_check_length_2>
86# CHECK: callq 0x[[#%x,HAS_UNWIND_2]]              <_has_unwind_2>
87# CHECK: callq 0x[[#%x,HAS_UNWIND_2]]              <_has_unwind_2>
88# CHECK: callq 0x[[#%x,HAS_UNWIND_3]]              <_has_unwind_3>
89# CHECK: callq 0x[[#%x,HAS_UNWIND_4]]              <_has_unwind_4>
90# CHECK: callq 0x[[#%x,HAS_ABS_PERSONALITY_1]]     <_has_abs_personality_1>
91# CHECK: callq 0x[[#%x,HAS_ABS_PERSONALITY_2]]     <_has_abs_personality_2>
92# CHECK: callq 0x[[#%x,HAS_EH_FRAME_1]]            <_has_eh_frame_1>
93# CHECK: callq 0x[[#%x,HAS_EH_FRAME_2]]            <_has_eh_frame_2>
94# CHECK: callq 0x[[#%x,HAS_EH_FRAME_3]]            <_has_eh_frame_3>
95# CHECK: callq 0x[[#%x,MUTALLY_RECURSIVE_2]]       <_mutually_recursive_2>
96# CHECK: callq 0x[[#%x,MUTALLY_RECURSIVE_2]]       <_mutually_recursive_2>
97## FIXME Mutually-recursive functions with identical bodies (see below)
98# COM:   callq 0x[[#%x,ASYMMETRIC_RECURSIVE_2]]    <_asymmetric_recursive_2>
99# COM:   callq 0x[[#%x,ASYMMETRIC_RECURSIVE_2]]    <_asymmetric_recursive_2>
100# CHECK: callq 0x[[#%x,INIT_2]]                    <_init_2>
101# CHECK: callq 0x[[#%x,INIT_2]]                    <_init_2>
102# CHECK: callq 0x[[#%x,INIT_3]]                    <_init_3>
103
104### TODO:
105### * Fold: funcs only differ in alignment
106### * No fold: func is weak? preemptible?
107### * Test that we hash things appropriately w/ minimal collisions
108
109#--- abs.s
110.subsections_via_symbols
111
112.globl _abs1a, _abs1b, _abs2, _not_abs
113_abs1a = 0xfac3
114_abs1b = 0xfac3
115_abs2 =  0xf00d
116
117.data
118.space 0xfac3
119## _not_abs has the same Defined::value as _abs1{a,b}
120_not_abs:
121
122#--- main.s
123.subsections_via_symbols
124.text
125
126_abs1a_ref:
127  movabs $_abs1a, %rdx
128
129_abs1b_ref:
130  movabs $_abs1b, %rdx
131
132_abs1a_ref_with_addend:
133  movabs $_abs1a + 3, %rdx
134
135_abs1b_ref_with_addend:
136  movabs $_abs1b + 3, %rdx
137
138## No fold: the absolute symbol value differs
139_abs2_ref:
140  movabs $_abs2, %rdx
141
142## No fold: _not_abs has the same value as _abs1{a,b}, but is not absolute.
143_not_abs_ref:
144  movabs $_not_abs, %rdx
145
146_dylib_ref_1:
147  mov ___nan@GOTPCREL(%rip), %rax
148  callq ___isnan
149
150_dylib_ref_2:
151  mov ___nan@GOTPCREL(%rip), %rax
152  callq ___isnan
153
154## No fold: referent dylib symbol differs
155_dylib_ref_3:
156  mov ___inf@GOTPCREL(%rip), %rax
157  callq ___inf
158
159## No fold: referent dylib addend differs
160_dylib_ref_4:
161  mov ___nan + 1@GOTPCREL(%rip), %rax
162  callq ___inf + 1
163
164## We can merge two sections even if one of them has an alt entry. Just make
165## sure we don't merge the alt entry symbol with a regular symbol.
166.alt_entry _alt
167_with_alt_entry:
168  movq $3132, %rax
169_alt:
170  ret
171
172_no_alt_entry:
173  movq $3132, %rax
174  ret
175
176_defined_ref_with_addend_1:
177  callq _with_alt_entry + 4
178
179_defined_ref_with_addend_2:
180  callq _with_alt_entry + 4
181
182# No fold: addend differs
183_defined_ref_with_addend_3:
184  callq _with_alt_entry + 8
185
186## _recursive has the same body as its next two callers, but cannot be folded
187## with them.
188_recursive:
189  callq _recursive
190
191_call_recursive_1:
192  callq _recursive
193
194_call_recursive_2:
195  callq _recursive
196
197## Functions of different lengths should not be folded
198_check_length_1:
199  movq $97, %rax
200
201_check_length_2:
202  movq $97, %rax
203  .space 1
204
205_my_personality:
206  mov $1345, %rax
207
208## Functions with identical unwind info should be folded.
209_has_unwind_1:
210  .cfi_startproc
211  .cfi_personality 155, _my_personality
212  .cfi_lsda 16, Lexception0
213  .cfi_def_cfa_offset 16
214  ret
215  .cfi_endproc
216
217_has_unwind_2:
218  .cfi_startproc
219  .cfi_personality 155, _my_personality
220  .cfi_lsda 16, Lexception1
221  .cfi_def_cfa_offset 16
222  ret
223  .cfi_endproc
224
225## This function has a different cfa_offset from the first two, and therefore
226## should not be folded.
227_has_unwind_3:
228  .cfi_startproc
229  .cfi_personality 155, _my_personality
230  .cfi_lsda 16, Lexception1
231  .cfi_def_cfa_offset 8
232  ret
233  .cfi_endproc
234
235## This function has a different LSDA from the first two, and therefore should
236## not be folded.
237_has_unwind_4:
238  .cfi_startproc
239  .cfi_personality 155, _my_personality
240  .cfi_lsda 16, Lexception2
241  .cfi_def_cfa_offset 16
242  ret
243  .cfi_endproc
244
245## The next two functions should not be folded as they refer to personalities
246## at different absolute addresses. This verifies that we are doing the right
247## thing in our "data slicing hack" for compact unwind.
248_has_abs_personality_1:
249  .cfi_startproc
250  .cfi_personality 155, _abs_personality_1
251  .cfi_def_cfa_offset 16
252  ret
253  .cfi_endproc
254
255_has_abs_personality_2:
256  .cfi_startproc
257  .cfi_personality 155, _abs_personality_2
258  .cfi_def_cfa_offset 16
259  ret
260  .cfi_endproc
261
262_abs_personality_1 = 0x1
263_abs_personality_2 = 0x2
264
265## In theory _has_eh_frame_{1, 2} can be dedup'ed, but we don't support this
266## yet.
267_has_eh_frame_1:
268  .cfi_startproc
269  .cfi_def_cfa_offset 8
270  ## cfi_escape cannot be encoded in compact unwind
271  .cfi_escape 0x2e, 0x10
272  ret
273  .cfi_endproc
274
275_has_eh_frame_2:
276  .cfi_startproc
277  .cfi_def_cfa_offset 8
278  ## cfi_escape cannot be encoded in compact unwind
279  .cfi_escape 0x2e, 0x10
280  ret
281  .cfi_endproc
282
283## The nop in this function body means that it cannot be folded with the
284## previous two, even though the unwind info is otherwise identical.
285_has_eh_frame_3:
286  .cfi_startproc
287  .cfi_def_cfa_offset 8
288  ## cfi_escape cannot be encoded in compact unwind
289  .cfi_escape 0x2e, 0x10
290  nop
291  ret
292  .cfi_endproc
293
294## Fold: Mutually-recursive functions with symmetric bodies
295_mutually_recursive_1:
296  callq _mutually_recursive_1 # call myself
297  callq _mutually_recursive_2 # call my twin
298
299_mutually_recursive_2:
300  callq _mutually_recursive_2 # call myself
301  callq _mutually_recursive_1 # call my twin
302
303## Fold: Mutually-recursive functions with identical bodies
304##
305## FIXME: This test is currently broken. Recursive call sites have no relocs
306## and the non-zero displacement field is already written to the section
307## data, while non-recursive call sites use symbol relocs and section data
308## contains zeros in the displacement field. Thus, ICF's equalsConstant()
309## finds that the section data doesn't match.
310##
311## ELF folds this case properly because it emits symbol relocs for all calls,
312## even recursive ones.
313
314_asymmetric_recursive_1:
315  callq _asymmetric_recursive_1 # call myself
316  callq _asymmetric_recursive_2 # call my twin
317  movl $3, %eax
318
319_asymmetric_recursive_2:
320  callq _asymmetric_recursive_1 # call my twin
321  callq _asymmetric_recursive_2 # call myself
322  movl $3, %eax
323
324_init_1:
325  movq $12938, %rax
326
327## Fold: _init_2 is in a section that gets renamed and output as __text
328.section __TEXT,__StaticInit
329_init_2:
330  movq $12938, %rax
331
332## No fold: _init_3 is in a different output section from _init_{1,2}
333.section __TEXT,__foo
334_init_3:
335  movq $12938, %rax
336
337.text
338.globl _main
339_main:
340  callq _abs1a_ref
341  callq _abs1b_ref
342  callq _abs1a_ref_with_addend
343  callq _abs1b_ref_with_addend
344  callq _abs2_ref
345  callq _not_abs_ref
346  callq _dylib_ref_1
347  callq _dylib_ref_2
348  callq _dylib_ref_3
349  callq _dylib_ref_4
350  callq _alt
351  callq _with_alt_entry
352  callq _no_alt_entry
353  callq _defined_ref_with_addend_1
354  callq _defined_ref_with_addend_2
355  callq _defined_ref_with_addend_3
356  callq _recursive
357  callq _call_recursive_1
358  callq _call_recursive_2
359  callq _check_length_1
360  callq _check_length_2
361  callq _has_unwind_1
362  callq _has_unwind_2
363  callq _has_unwind_3
364  callq _has_unwind_4
365  callq _has_abs_personality_1
366  callq _has_abs_personality_2
367  callq _has_eh_frame_1
368  callq _has_eh_frame_2
369  callq _has_eh_frame_3
370  callq _mutually_recursive_1
371  callq _mutually_recursive_2
372  callq _asymmetric_recursive_1
373  callq _asymmetric_recursive_2
374  callq _init_1
375  callq _init_2
376  callq _init_3
377
378.section __TEXT,__gcc_except_tab
379GCC_except_table0:
380Lexception0:
381  .byte 255
382
383GCC_except_table1:
384Lexception1:
385  .byte 255
386
387GCC_except_table2:
388Lexception2:
389  .byte 254
390