llvm / llvm/llvm-project

[LTO][ThinLTO] Mixing of LTO and ThinLTO bitcode works in strange way

Open
#179,800 0 comments 2 reactions 0 assignees View on GitHub
LTO
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

Hello!

Considering the following C files:
- ftn.c:
```c
int ftn() {
return 77;
}
```
- main.c:
```c
int ftn();
int _start() {
return ftn();
}
```

And compiling them in different modes and checks using the following bash script:
```bash
#!/usr/bin/env bash

clang ftn.c -O3 -flto=thin -c -o ftn-thin.o
clang ftn.c -O3 -flto=full -c -o ftn-full.o

clang main.c -O3 -flto=thin -c -o main-thin.o
clang main.c -O3 -flto=full -c -o main-full.o

clang -fuse-ld=lld -nodefaultlibs -nostartfiles -flto=thin ftn-thin.o main-thin.o -o Sttt
clang -fuse-ld=lld -nodefaultlibs -nostartfiles -flto=thin ftn-thin.o main-full.o -o Sttf
clang -fuse-ld=lld -nodefaultlibs -nostartfiles -flto=thin ftn-full.o main-thin.o -o Stft
clang -fuse-ld=lld -nodefaultlibs -nostartfiles -flto=thin ftn-full.o main-full.o -o Stff

clang -fuse-ld=lld -nodefaultlibs -nostartfiles -flto=full ftn-thin.o main-thin.o -o Sftt
clang -fuse-ld=lld -nodefaultlibs -nostartfiles -flto=full ftn-thin.o main-full.o -o Sftf
clang -fuse-ld=lld -nodefaultlibs -nostartfiles -flto=full ftn-full.o main-thin.o -o Sfft
clang -fuse-ld=lld -nodefaultlibs -nostartfiles -flto=full ftn-full.o main-full.o -o Sfff

for filee in S*
do
objdump -S $filee > $filee.S
done

grep "ftn" S*.S -c
```

The output will be the following:
```
Sfff.S:0
Sfft.S:2
Sftf.S:2
Sftt.S:1
Stff.S:0
Stft.S:2
Sttf.S:2
Sttt.S:1
```

0 - `ftn` was inlined; `ftn` code is removed
1 - `ftn` was inlined, but `ftn` code is still presented
2 - `ftn` was not inlined

That means that:
| Binary name | LLD invocation | `ftn.c` mode | `main.c` mode | Resolution |
| :--- | :--- | :--- | :--- | --- |
| `Sfff` | `flto=full` | `flto=full` | `flto=full` | Works as expected |
| `Sfft` | `flto=full` | `flto=full` | `flto=thin` | LTO unexpectedly does not work: fullLTO does not need all information which is presented in ThinLTO bitcode |
| `Sftf` | `flto=full` | `flto=thin` | `flto=full` | LTO unexpectedly does not work: fullLTO does not need all information which is presented in ThinLTO bitcode |
| `Sftt` | `flto=full` | `flto=thin` | `flto=thin` | Works as expected, but it needs `-Wl,--gc-sections` for removing unused symbols |
| `Stff` | `flto=thin` | `flto=full` | `flto=full` | Unexpectedly works. ThinLTO does not have enough information |
| `Stft` | `flto=thin` | `flto=full` | `flto=thin` | LTO does not work as expected. ThinLTO does not have enough information from `main.c` |
| `Sttf` | `flto=thin` | `flto=thin` | `flto=full` | LTO does not work as expected. ThinLTO does not have enough information from `ftn.c` |
| `Sttt` | `flto=thin` | `flto=thin` | `flto=thin` | Works as expected, but it needs `-Wl,--gc-sections` for removing unused symbols |

So, my questions:
- Why linker with `-flto=thin` is able to work with fullLTO bitcode?
- Why linker with `-flto=full` is not able to use ThinLTO bitcode together with FatLTO bitcode?
- Why linker with `-flto=full` needs `-Wl,--gc-sections` to clean unused symbols in the case of `Sftt` binary?

Tested with clang with the most recent commits:
```
clang version 23.0.0git (https://github.com/llvm/llvm-project.git 2e429f7e1f5b490a703de4cf06ef65eed784f7ab)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /tmp/llvm/llvm-project/install/bin
Build config: +assertions
```

Contributor guide

Open the contributing guide

Research direction

Reproduce the eight combinations with the provided ftn.c, main.c, and bash commands using the reported Clang revision. Compare the generated binaries and objdump output, then trace how clang and lld select full LTO versus ThinLTO for mixed bitcode. Done means explaining the differing behavior and defining the expected handling for each combination.

Written by the indexing model from the issue text.

Assessment

Tech stack
c, shell
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.