Skip to content

-mfs-split-ehcode and -fbasic-block-sections break linker garbage collection #165139

@yugr

Description

@yugr

-mfs-split-ehcode has an unfortunate side effect of breaking linker garbage collection enabled with --gc-sections.

Here is a simple example:

$ cat main.cc
extern void bar();

void foo() {
  try {
    bar();
  } catch (...) {
    bar();
  }
  bar();
}

int main() {
  return 0;
}

$ cat bar.cc
void bar() {}

# Without Splitter: foo removed successfully
$ clang++ main.cc bar.cc -fuse-ld=lld -ffunction-sections -fdata-sections -Wl,--gc-sections -Wl,--print-gc-sections |& grep foo
removing unused section /tmp/main-789e6f.o:(.text)
removing unused section /tmp/main-789e6f.o:(.text._Z3foov)
removing unused section /tmp/main-789e6f.o:(.text.__clang_call_terminate)

# With Splitter: foo NOT removed
$ clang++ main.cc bar.cc -fuse-ld=lld -ffunction-sections -fdata-sections -Wl,--gc-sections -Wl,--print-gc-sections -mllvm -enable-split-machine-functions -mllvm -mfs-split-ehcode |& grep foo

The reason for this is the following liveness chain:

  • exception table .gcc_except_table._Z3foov references foo.cold:
    Relocation section '.rela.gcc_except_table._Z3foov' at offset 0x4e8 contains 2 entries:
        Offset             Info             Type               Symbol's Value  Symbol's Name + Addend
    0000000000000001  0000000300000018 R_X86_64_PC64          0000000000000000 .text.split._Z3foov + 0
    0000000000000019  0000000300000018 R_X86_64_PC64          0000000000000000 .text.split._Z3foov + 0
    
    and is a GC root in Lld linker
  • foo.cold references foo:
    Relocation section '.rela.text.split._Z3foov' at offset 0x440 contains 7 entries:
        Offset             Info             Type               Symbol's Value  Symbol's Name + Addend
    ...
    0000000000000021  0000000200000004 R_X86_64_PLT32         0000000000000000 .text._Z3foov + 9
    ...
    

Thus foo (and foo.cold), although being clearly dead, end up in final executable.

This issue was found when investigating catastrophic code sizes increases in Rust projects under -enable-split-machine-functions -mfs-split-ehcode (10% tokio, 2x meilisearch, etc.). -basic-block-sections may have the same problem (I didn't check).

LLVM was build via

cmake -G Ninja "-DLLVM_ENABLE_ASSERTIONS=ON" "-DLLVM_UNREACHABLE_OPTIMIZE=OFF" "-DLLVM_ENABLE_PLUGINS=OFF" "-DLLVM_TARGETS_TO_BUILD=X86" "-DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=" "-DLLVM_INCLUDE_EXAMPLES=OFF" "-DLLVM_INCLUDE_DOCS=OFF" "-DLLVM_INCLUDE_BENCHMARKS=OFF" "-DLLVM_INCLUDE_TESTS=OFF" "-DLLVM_ENABLE_TERMINFO=OFF" "-DLLVM_ENABLE_LIBEDIT=OFF" "-DLLVM_ENABLE_BINDINGS=OFF" "-DLLVM_ENABLE_Z3_SOLVER=OFF" "-DLLVM_TARGET_ARCH=x86_64" "-DLLVM_DEFAULT_TARGET_TRIPLE=x86_64-unknown-linux-gnu" "-DLLVM_ENABLE_LIBXML2=OFF" "-DCMAKE_CXX_COMPILER=c++" "-DLLVM_ENABLE_ZSTD=OFF" "-DCMAKE_BUILD_TYPE=Release" -DLLVM_ENABLE_PROJECTS='clang;lld' ../llvm

from ToT:

commit e246fffb253c3ed9a2c0b4a71ef33d97c7b5629c (HEAD -> main, origin/main, origin/HEAD)
Author: Congzhe <[email protected]>
Date:   Sun Oct 26 00:39:49 2025 -0400

    Reland "[InstructionSimplify] Enhance simplifySelectInst() (#163453)" (#164694)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions