cb424d7448
verify-patch-sanity.py validates every active recipe .patch has internally- consistent hunk line counts — catching the 'malformed patch at line N' failure at commit/CI/preflight time instead of hours into a cook. This cycle hit that class three times (qtwaylandscanner, sddm, xwayland), each only discovered when cookbook tried to apply the patch. Running it across the repo found 29 latent malformed patches (validated against GNU patch: e.g. relibc/P3-sysv-ipc reproduces 'malformed patch at line 22'). They were harmless only because they sit in vendored recipes (baked, not re- applied) — but would fail on any version-bump re-derivation. --fix recounts the hunk headers (body untouched) and repaired all 29. Wired into build-preflight.sh (Phase 1.0D) and redbear-ci.yml, with a unit test (test-patch-sanity.sh). Skips archived/legacy trees and unvalidatable formats (empty placeholders, bare-@@ git hunks).
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 -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
|