Issue 179800
Summary [LTO][ThinLTO] Mixing of LTO and ThinLTO bitcode works in strange way
Labels new issue
Assignees
Reporter foxtran
    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
```
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to