kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

lto_phase1.sh (17393B)


      1 #!/usr/bin/env bash
      2 # Cross-TU LTO Phase 1: all source-building verbs route through the shared
      3 # staging engine, semantic frontends can emit into one open KitCg, and opaque
      4 # asm remains an ordinary object participant.
      5 set -euo pipefail
      6 
      7 ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
      8 KIT="${KIT:-$ROOT/build/kit}"
      9 WORK="$ROOT/build/test/opt/lto_phase1"
     10 mkdir -p "$WORK"
     11 
     12 call_mnemonics='\b(bl|blr|callq?|jalr?)\b'
     13 
     14 fail_log() {
     15   local label="$1"
     16   local log="$2"
     17   printf 'lto-phase1 FAILED: %s\n' "$label" >&2
     18   if [ -s "$log" ]; then
     19     sed 's/^/  | /' "$log" >&2
     20   fi
     21   exit 1
     22 }
     23 
     24 require_no_calls() {
     25   local dis="$1"
     26   local fn="$2"
     27   local label="$3"
     28   local body ncalls
     29   body="$(sed -n "/<$fn>:/,/^$/p" "$dis")"
     30   if [ -z "$body" ]; then
     31     fail_log "$label missing <$fn> in disassembly" "$dis"
     32   fi
     33   ncalls=$(printf '%s\n' "$body" | grep -cE "$call_mnemonics" || true)
     34   if [ "$ncalls" -ne 0 ]; then
     35     printf 'lto-phase1 FAILED: %s left %s call(s) in <%s>\n' \
     36       "$label" "$ncalls" "$fn" >&2
     37     printf '%s\n' "$body" | sed 's/^/  | /' >&2
     38     exit 1
     39   fi
     40 }
     41 
     42 require_has_calls() {
     43   local dis="$1"
     44   local fn="$2"
     45   local label="$3"
     46   local body ncalls
     47   body="$(sed -n "/<$fn>:/,/^$/p" "$dis")"
     48   if [ -z "$body" ]; then
     49     fail_log "$label missing <$fn> in disassembly" "$dis"
     50   fi
     51   ncalls=$(printf '%s\n' "$body" | grep -cE "$call_mnemonics" || true)
     52   if [ "$ncalls" -eq 0 ]; then
     53     printf 'lto-phase1 FAILED: %s inlined an interposable weak callee\n' \
     54       "$label" >&2
     55     printf '%s\n' "$body" | sed 's/^/  | /' >&2
     56     exit 1
     57   fi
     58 }
     59 
     60 require_symbol_bind() {
     61   local symtab="$1"
     62   local sym="$2"
     63   local bind="$3"
     64   local label="$4"
     65   if ! awk -v sym="$sym" -v bind="$bind" \
     66       '$2 == bind && $NF == sym { found = 1 } END { exit found ? 0 : 1 }' \
     67       "$symtab"; then
     68     fail_log "$label expected symbol '$sym' with bind '$bind'" "$symtab"
     69   fi
     70 }
     71 
     72 cat > "$WORK/callee.c" <<'EOF'
     73 int add7(int x) { return x + 7; }
     74 EOF
     75 cat > "$WORK/caller.c" <<'EOF'
     76 int add7(int);
     77 int call_add7(int x) { return add7(x) * 2; }
     78 EOF
     79 cat > "$WORK/entry.c" <<'EOF'
     80 int add7(int);
     81 int _start(void) { return add7(5); }
     82 EOF
     83 
     84 if ! "$KIT" build-obj -target aarch64-linux-gnu -O1 -ffreestanding -flto \
     85      "$WORK/callee.c" "$WORK/caller.c" -o "$WORK/build_obj.o" \
     86      > "$WORK/build_obj.out" 2>&1; then
     87   fail_log "build-obj -flto two-TU compile failed" "$WORK/build_obj.out"
     88 fi
     89 "$KIT" objdump -d "$WORK/build_obj.o" > "$WORK/build_obj.dis" 2>&1
     90 require_no_calls "$WORK/build_obj.dis" call_add7 "build-obj -flto"
     91 printf 'lto-phase1 build-obj fused cross-TU call\n'
     92 
     93 if ! "$KIT" cc -target aarch64-linux-gnu -O1 -ffreestanding -nostdlib \
     94      -e _start -flto "$WORK/callee.c" "$WORK/entry.c" \
     95      -o "$WORK/cc_lto.elf" > "$WORK/cc_lto.out" 2>&1; then
     96   fail_log "cc -flto link failed" "$WORK/cc_lto.out"
     97 fi
     98 "$KIT" objdump -d "$WORK/cc_lto.elf" > "$WORK/cc_lto.dis" 2>&1
     99 require_no_calls "$WORK/cc_lto.dis" _start "cc -flto"
    100 printf 'lto-phase1 cc fused cross-TU call\n'
    101 
    102 if ! "$KIT" build-exe -target aarch64-linux-gnu -O1 -ffreestanding \
    103      -nostdlib -e _start -flto "$WORK/callee.c" "$WORK/entry.c" \
    104      -o "$WORK/build_lto.elf" > "$WORK/build_lto.out" 2>&1; then
    105   fail_log "build-exe -flto link failed" "$WORK/build_lto.out"
    106 fi
    107 "$KIT" objdump -d "$WORK/build_lto.elf" > "$WORK/build_lto.dis" 2>&1
    108 require_no_calls "$WORK/build_lto.dis" _start "build-exe -flto"
    109 printf 'lto-phase1 build-exe fused cross-TU call\n'
    110 
    111 cat > "$WORK/internal_helper.c" <<'EOF'
    112 int arch_helper(int x) { return x + 9; }
    113 EOF
    114 cat > "$WORK/internal_entry.c" <<'EOF'
    115 int arch_helper(int);
    116 int _start(void) { return arch_helper(2); }
    117 EOF
    118 for target in aarch64-linux-gnu x86_64-linux-gnu riscv64-linux-gnu; do
    119   out="$WORK/internal_$target.elf"
    120   if ! "$KIT" cc -target "$target" -O1 -ffreestanding -nostdlib \
    121        -e _start -flto "$WORK/internal_helper.c" "$WORK/internal_entry.c" \
    122        -o "$out" > "$WORK/internal_$target.out" 2>&1; then
    123     fail_log "cc -flto internalization failed for $target" \
    124       "$WORK/internal_$target.out"
    125   fi
    126   "$KIT" objdump -d "$out" > "$WORK/internal_$target.dis" 2>&1
    127   "$KIT" objdump -t "$out" > "$WORK/internal_$target.sym" 2>&1
    128   require_no_calls "$WORK/internal_$target.dis" _start \
    129     "cc -flto internalized helper for $target"
    130   require_symbol_bind "$WORK/internal_$target.sym" arch_helper l \
    131     "cc -flto internal helper for $target"
    132   require_symbol_bind "$WORK/internal_$target.sym" _start g \
    133     "cc -flto entry preservation for $target"
    134 done
    135 printf 'lto-phase1 internalized non-preserved helpers on aa64/x64/rv64\n'
    136 
    137 cat > "$WORK/dead_ref.c" <<'EOF'
    138 int missing_external(void);
    139 int dead_global(void) { return missing_external(); }
    140 int _start(void) { return 0; }
    141 EOF
    142 if ! "$KIT" cc -target aarch64-linux-gnu -O1 -ffreestanding -nostdlib \
    143      -e _start -flto "$WORK/dead_ref.c" -o "$WORK/dead_ref.elf" \
    144      > "$WORK/dead_ref.out" 2>&1; then
    145   fail_log "dead LTO semantic ref leaked into final link" "$WORK/dead_ref.out"
    146 fi
    147 "$KIT" objdump -t "$WORK/dead_ref.elf" > "$WORK/dead_ref.sym" 2>&1
    148 if grep -q "missing_external" "$WORK/dead_ref.sym"; then
    149   fail_log "dead LTO semantic ref remained in symbol table" \
    150     "$WORK/dead_ref.sym"
    151 fi
    152 printf 'lto-phase1 dead semantic refs do not leak after prepass\n'
    153 
    154 if ! "$KIT" build-lib -target aarch64-linux-gnu -O1 -ffreestanding -flto \
    155      "$WORK/callee.c" "$WORK/caller.c" -o "$WORK/liblto.a" \
    156      > "$WORK/build_lib.out" 2>&1; then
    157   fail_log "build-lib -flto failed" "$WORK/build_lib.out"
    158 fi
    159 if ! "$KIT" ar t "$WORK/liblto.a" > "$WORK/ar.out" 2>&1; then
    160   fail_log "ar t on LTO archive failed" "$WORK/ar.out"
    161 fi
    162 members=$(grep -cE '\.o$' "$WORK/ar.out" || true)
    163 if [ "$members" -ne 1 ]; then
    164   fail_log "build-lib -flto should archive one merged semantic object" \
    165     "$WORK/ar.out"
    166 fi
    167 printf 'lto-phase1 build-lib archived one merged LTO object\n'
    168 
    169 cat > "$WORK/weak_only.c" <<'EOF'
    170 __attribute__((weak)) int weak_add1(int x) { return x + 1; }
    171 EOF
    172 cat > "$WORK/weak_caller.c" <<'EOF'
    173 int weak_add1(int);
    174 int weak_call(int x) { return weak_add1(x); }
    175 EOF
    176 if ! "$KIT" build-obj -target aarch64-linux-gnu -O1 -ffreestanding -flto \
    177      "$WORK/weak_only.c" "$WORK/weak_caller.c" -o "$WORK/weak_lto.o" \
    178      > "$WORK/weak_lto.out" 2>&1; then
    179   fail_log "weak LTO compile failed" "$WORK/weak_lto.out"
    180 fi
    181 "$KIT" objdump -d "$WORK/weak_lto.o" > "$WORK/weak_lto.dis" 2>&1
    182 require_has_calls "$WORK/weak_lto.dis" weak_call "weak LTO guard"
    183 printf 'lto-phase1 weak callee stayed out-of-line\n'
    184 
    185 cat > "$WORK/weak_entry.c" <<'EOF'
    186 int weak_add1(int);
    187 int _start(void) { return weak_add1(1); }
    188 EOF
    189 if ! "$KIT" cc -target aarch64-linux-gnu -O1 -ffreestanding -nostdlib \
    190      -e _start -flto "$WORK/weak_only.c" "$WORK/weak_entry.c" \
    191      -o "$WORK/weak_exe.elf" > "$WORK/weak_exe.out" 2>&1; then
    192   fail_log "weak executable LTO link failed" "$WORK/weak_exe.out"
    193 fi
    194 "$KIT" objdump -d "$WORK/weak_exe.elf" > "$WORK/weak_exe.dis" 2>&1
    195 "$KIT" objdump -t "$WORK/weak_exe.elf" > "$WORK/weak_exe.sym" 2>&1
    196 require_has_calls "$WORK/weak_exe.dis" _start "weak executable LTO guard"
    197 require_symbol_bind "$WORK/weak_exe.sym" weak_add1 w \
    198   "weak executable LTO preservation"
    199 printf 'lto-phase1 weak executable callee stayed weak and out-of-line\n'
    200 
    201 cat > "$WORK/weak_impl.c" <<'EOF'
    202 __attribute__((weak)) int pick(void) { return 1; }
    203 EOF
    204 cat > "$WORK/strong_impl.c" <<'EOF'
    205 int pick(void) { return 2; }
    206 EOF
    207 cat > "$WORK/pick_main.c" <<'EOF'
    208 int pick(void);
    209 int main(void) { return pick() == 2 ? 0 : 1; }
    210 EOF
    211 if ! "$KIT" cc -O1 -flto "$WORK/weak_impl.c" "$WORK/strong_impl.c" \
    212      "$WORK/pick_main.c" -o "$WORK/weakstrong" \
    213      > "$WORK/weakstrong.out" 2>&1; then
    214   fail_log "strong-over-weak function LTO link failed" "$WORK/weakstrong.out"
    215 fi
    216 if ! "$WORK/weakstrong"; then
    217   fail_log "strong-over-weak function LTO executable returned nonzero" \
    218     "$WORK/weakstrong.out"
    219 fi
    220 printf 'lto-phase1 strong function overrides weak definition\n'
    221 
    222 cat > "$WORK/weak_data.c" <<'EOF'
    223 __attribute__((weak)) int lto_data = 1;
    224 EOF
    225 cat > "$WORK/strong_data.c" <<'EOF'
    226 int lto_data = 2;
    227 EOF
    228 cat > "$WORK/data_main.c" <<'EOF'
    229 extern int lto_data;
    230 int main(void) { return lto_data == 2 ? 0 : 1; }
    231 EOF
    232 if ! "$KIT" cc -O1 -flto "$WORK/weak_data.c" "$WORK/strong_data.c" \
    233      "$WORK/data_main.c" -o "$WORK/weakdata" \
    234      > "$WORK/weakdata.out" 2>&1; then
    235   fail_log "strong-over-weak data LTO link failed" "$WORK/weakdata.out"
    236 fi
    237 if ! "$WORK/weakdata"; then
    238   fail_log "strong-over-weak data LTO executable returned nonzero" \
    239     "$WORK/weakdata.out"
    240 fi
    241 printf 'lto-phase1 strong data overrides weak definition\n'
    242 
    243 cat > "$WORK/odr1.c" <<'EOF'
    244 int odr_dup(void) { return 1; }
    245 EOF
    246 cat > "$WORK/odr2.c" <<'EOF'
    247 int odr_dup(void) { return 2; }
    248 EOF
    249 if bash -c '"$@"; rc=$?; exit $rc' _ "$KIT" build-obj -target aarch64-linux-gnu -O1 \
    250     -ffreestanding -flto "$WORK/odr1.c" "$WORK/odr2.c" \
    251     -o "$WORK/odr.o" > "$WORK/odr.out" 2>&1; then
    252   fail_log "duplicate strong definitions unexpectedly compiled" "$WORK/odr.out"
    253 fi
    254 if ! grep -q "duplicate definition of symbol" "$WORK/odr.out"; then
    255   fail_log "duplicate strong definitions lacked ODR diagnostic" "$WORK/odr.out"
    256 fi
    257 printf 'lto-phase1 duplicate strong definitions are rejected\n'
    258 
    259 # Cross-TU tentative definitions. kit is -fno-common: the C frontend lowers a
    260 # file-scope `int g;` to a strong .bss definition, so two of them in different
    261 # TUs conflict exactly as the non-LTO linker resolves them. These checks pin the
    262 # Phase 1 resolution-fidelity invariant — -flto staging merges symbols the same
    263 # way the linker does — and guard same-TU tentative coalescing inside a -flto
    264 # build (the legal `int g; int g;` case must not be misread as a redefinition).
    265 cat > "$WORK/tent_a.c" <<'EOF'
    266 int tentative_dup;
    267 EOF
    268 cat > "$WORK/tent_b.c" <<'EOF'
    269 int tentative_dup;
    270 EOF
    271 cat > "$WORK/tent_entry.c" <<'EOF'
    272 extern int tentative_dup;
    273 int _start(void) { return tentative_dup; }
    274 EOF
    275 
    276 # -flto staging must reject the duplicate tentative defs with the ODR diagnostic.
    277 if bash -c '"$@"; rc=$?; exit $rc' _ "$KIT" build-obj -target aarch64-linux-gnu -O1 \
    278     -ffreestanding -flto "$WORK/tent_a.c" "$WORK/tent_b.c" \
    279     -o "$WORK/tent_dup.o" > "$WORK/tent_dup_lto.out" 2>&1; then
    280   fail_log "cross-TU duplicate tentative defs compiled under -flto" \
    281     "$WORK/tent_dup_lto.out"
    282 fi
    283 if ! grep -q "duplicate definition of" "$WORK/tent_dup_lto.out"; then
    284   fail_log "cross-TU duplicate tentative defs lacked ODR diagnostic under -flto" \
    285     "$WORK/tent_dup_lto.out"
    286 fi
    287 
    288 # The non-LTO link of the same inputs must reject them too: LTO == linker.
    289 "$KIT" cc -target aarch64-linux-gnu -O0 -ffreestanding -c "$WORK/tent_a.c" \
    290     -o "$WORK/tent_a.o" > "$WORK/tent_a.out" 2>&1 ||
    291   fail_log "tentative TU a failed to compile" "$WORK/tent_a.out"
    292 "$KIT" cc -target aarch64-linux-gnu -O0 -ffreestanding -c "$WORK/tent_b.c" \
    293     -o "$WORK/tent_b.o" > "$WORK/tent_b.out" 2>&1 ||
    294   fail_log "tentative TU b failed to compile" "$WORK/tent_b.out"
    295 "$KIT" cc -target aarch64-linux-gnu -O0 -ffreestanding -c "$WORK/tent_entry.c" \
    296     -o "$WORK/tent_entry.o" > "$WORK/tent_entry.out" 2>&1 ||
    297   fail_log "tentative entry TU failed to compile" "$WORK/tent_entry.out"
    298 if bash -c '"$@"; rc=$?; exit $rc' _ "$KIT" cc -target aarch64-linux-gnu \
    299     -ffreestanding -nostdlib -e _start "$WORK/tent_a.o" "$WORK/tent_b.o" \
    300     "$WORK/tent_entry.o" -o "$WORK/tent_dup.elf" \
    301     > "$WORK/tent_dup_link.out" 2>&1; then
    302   fail_log "cross-TU duplicate tentative defs linked without -flto" \
    303     "$WORK/tent_dup_link.out"
    304 fi
    305 if ! grep -q "duplicate definition of" "$WORK/tent_dup_link.out"; then
    306   fail_log "non-LTO link lacked duplicate-definition diagnostic" \
    307     "$WORK/tent_dup_link.out"
    308 fi
    309 printf 'lto-phase1 cross-TU duplicate tentative defs rejected by -flto and linker\n'
    310 
    311 # Positive: one definition coalesced from same-TU tentatives, shared across TUs
    312 # through extern refs, links and observes shared storage at run time under -flto.
    313 cat > "$WORK/tent_def.c" <<'EOF'
    314 int shared_tentative;
    315 int shared_tentative; /* same-TU tentative coalescing inside an -flto build */
    316 EOF
    317 cat > "$WORK/tent_use.c" <<'EOF'
    318 extern int shared_tentative;
    319 int read_shared(void) { return shared_tentative; }
    320 EOF
    321 cat > "$WORK/tent_shared_main.c" <<'EOF'
    322 extern int shared_tentative;
    323 int read_shared(void);
    324 int main(void) { shared_tentative = 5; return read_shared() == 5 ? 0 : 1; }
    325 EOF
    326 if ! "$KIT" cc -O1 -flto "$WORK/tent_def.c" "$WORK/tent_use.c" \
    327     "$WORK/tent_shared_main.c" -o "$WORK/tent_shared" \
    328     > "$WORK/tent_shared.out" 2>&1; then
    329   fail_log "single tentative def shared across TUs failed under -flto" \
    330     "$WORK/tent_shared.out"
    331 fi
    332 if ! "$WORK/tent_shared"; then
    333   fail_log "cross-TU tentative shared storage incorrect under -flto" \
    334     "$WORK/tent_shared.out"
    335 fi
    336 printf 'lto-phase1 single tentative def shared across TUs under -flto\n'
    337 
    338 cat > "$WORK/c_frontend.c" <<'EOF'
    339 int c_frontend_value(void) { return 5; }
    340 EOF
    341 cat > "$WORK/toy_frontend.toy" <<'EOF'
    342 fn toy_frontend_value(): i64 {
    343   return 3;
    344 }
    345 EOF
    346 cat > "$WORK/wasm_frontend.wat" <<'EOF'
    347 (module
    348   (func (export "wasm_frontend_value") (result i32)
    349     i32.const 4))
    350 EOF
    351 if ! "$KIT" build-obj -O1 -flto "$WORK/c_frontend.c" \
    352      "$WORK/toy_frontend.toy" "$WORK/wasm_frontend.wat" \
    353      -o "$WORK/semantic_frontends.o" \
    354      > "$WORK/semantic_frontends.out" 2>&1; then
    355   fail_log "C/Toy/Wasm semantic LTO staging failed" \
    356     "$WORK/semantic_frontends.out"
    357 fi
    358 printf 'lto-phase1 C/Toy/Wasm semantic frontends staged together\n'
    359 
    360 if ! "$KIT" build-obj -O1 "$WORK/c_frontend.c" -o "$WORK/c_onetu.o" \
    361      > "$WORK/c_onetu.out" 2>&1; then
    362   fail_log "C one-TU compile_cg wrapper failed" "$WORK/c_onetu.out"
    363 fi
    364 if ! "$KIT" build-obj -O1 "$WORK/toy_frontend.toy" -o "$WORK/toy_onetu.o" \
    365      > "$WORK/toy_onetu.out" 2>&1; then
    366   fail_log "Toy one-TU compile_cg wrapper failed" "$WORK/toy_onetu.out"
    367 fi
    368 if ! "$KIT" build-obj -O1 "$WORK/wasm_frontend.wat" -o "$WORK/wasm_onetu.o" \
    369      > "$WORK/wasm_onetu.out" 2>&1; then
    370   fail_log "Wasm one-TU compile_cg wrapper failed" "$WORK/wasm_onetu.out"
    371 fi
    372 printf 'lto-phase1 C/Toy/Wasm one-TU builds use compile_cg wrapper\n'
    373 
    374 cat > "$WORK/use_asm.c" <<'EOF'
    375 int asm_add1(int);
    376 int call_asm(int x) { return asm_add1(x); }
    377 EOF
    378 cat > "$WORK/asm_add1.s" <<'EOF'
    379 .text
    380 .globl asm_add1
    381 asm_add1:
    382   add x0, x0, #1
    383   ret
    384 EOF
    385 if ! "$KIT" build-obj -target aarch64-linux-gnu -O1 -ffreestanding -flto \
    386      "$WORK/use_asm.c" "$WORK/asm_add1.s" -o "$WORK/opaque_asm.o" \
    387      > "$WORK/opaque_asm.out" 2>&1; then
    388   fail_log "opaque asm participation under -flto failed" "$WORK/opaque_asm.out"
    389 fi
    390 "$KIT" objdump -t "$WORK/opaque_asm.o" > "$WORK/opaque_asm.sym" 2>&1
    391 if ! grep -q "asm_add1" "$WORK/opaque_asm.sym"; then
    392   fail_log "opaque asm symbol missing from relocatable output" \
    393     "$WORK/opaque_asm.sym"
    394 fi
    395 printf 'lto-phase1 asm participated as opaque object\n'
    396 
    397 cat > "$WORK/opaque_keep.c" <<'EOF'
    398 int keep_me(void) { return 17; }
    399 int _start(void) { return 0; }
    400 EOF
    401 cat > "$WORK/opaque_ref.s" <<'EOF'
    402 .text
    403 .globl opaque_ref
    404 opaque_ref:
    405   bl keep_me
    406   ret
    407 EOF
    408 if ! "$KIT" cc -target aarch64-linux-gnu -O1 -ffreestanding -nostdlib \
    409      -e _start -flto "$WORK/opaque_keep.c" "$WORK/opaque_ref.s" \
    410      -o "$WORK/opaque_ref.elf" > "$WORK/opaque_ref.out" 2>&1; then
    411   fail_log "opaque object reference did not preserve LTO symbol" \
    412     "$WORK/opaque_ref.out"
    413 fi
    414 "$KIT" objdump -t "$WORK/opaque_ref.elf" > "$WORK/opaque_ref.sym" 2>&1
    415 require_symbol_bind "$WORK/opaque_ref.sym" keep_me g \
    416   "opaque object reference preservation"
    417 printf 'lto-phase1 opaque object reference preserved LTO definition\n'
    418 
    419 cat > "$WORK/archive_lto.c" <<'EOF'
    420 int archive_func(void);
    421 int lto_target(void) { return 41; }
    422 int _start(void) { return archive_func(); }
    423 EOF
    424 cat > "$WORK/archive_member.c" <<'EOF'
    425 int lto_target(void);
    426 int archive_func(void) { return lto_target() + 1; }
    427 EOF
    428 if ! "$KIT" cc -target aarch64-linux-gnu -O0 -ffreestanding -c \
    429      "$WORK/archive_member.c" -o "$WORK/archive_member.o" \
    430      > "$WORK/archive_member.out" 2>&1; then
    431   fail_log "archive member compile failed" "$WORK/archive_member.out"
    432 fi
    433 if ! "$KIT" ar rcs "$WORK/libsemantic.a" "$WORK/archive_member.o" \
    434      > "$WORK/archive_ar.out" 2>&1; then
    435   fail_log "archive creation failed" "$WORK/archive_ar.out"
    436 fi
    437 if ! "$KIT" cc -target aarch64-linux-gnu -O1 -ffreestanding -nostdlib \
    438      -e _start -flto "$WORK/archive_lto.c" "$WORK/libsemantic.a" \
    439      -o "$WORK/archive_lto.elf" > "$WORK/archive_lto.out" 2>&1; then
    440   fail_log "archive selected by semantic LTO ref failed to link back" \
    441     "$WORK/archive_lto.out"
    442 fi
    443 "$KIT" objdump -t "$WORK/archive_lto.elf" > "$WORK/archive_lto.sym" 2>&1
    444 require_symbol_bind "$WORK/archive_lto.sym" lto_target g \
    445   "archive semantic-ref preservation"
    446 require_symbol_bind "$WORK/archive_lto.sym" archive_func g \
    447   "archive semantic-ref selection"
    448 printf 'lto-phase1 archive semantic ref preserved callback target\n'
    449 
    450 if "$KIT" cc -shared -flto -nostdlib "$WORK/callee.c" \
    451     -o "$WORK/libbad.so" > "$WORK/shared_lto.out" 2>&1; then
    452   fail_log "cc -shared -flto unexpectedly succeeded" "$WORK/shared_lto.out"
    453 fi
    454 if ! grep -q "shared-library LTO output is not exercised" \
    455     "$WORK/shared_lto.out"; then
    456   fail_log "cc -shared -flto rejection missing shared-LTO diagnostic" \
    457     "$WORK/shared_lto.out"
    458 fi
    459 printf 'lto-phase1 shared-library LTO remains disabled\n'
    460 
    461 printf 'lto-phase1: ok\n'