File: icf.s

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (388 lines) | stat: -rw-r--r-- 13,509 bytes parent folder | download | duplicates (12)
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