-
Notifications
You must be signed in to change notification settings - Fork 13.7k
Description
As part of Thin LTO, functions from one module (or codegen unit, in Rust terms) get imported into other modules. I've observed incompatible definitions/declarations get imported:
Assume we start with (in pseudo-LL) in some module X
:
define void @outer(ptr noundef %0) {
call void @inner(ptr noundef %0)
}
define void @inner(ptr noundef %0) { ... }
Dead argument elimination comes along and does:
define void @outer(ptr noundef %0) {
call void @inner(ptr poison) ; `noundef` is gone.
}
define void @inner(ptr %0) { ... } ; `noundef` is gone.
So far so good. But now Thin LTO comes along and runs on a module Y
that doesn't contain or reference @outer
at all. Maybe it already contains a
declare void @inner(ptr noundef %0)
or maybe that gets (transitively) imported from some module Z
. Now suppose that @outer
also gets (transitively) imported. Suddenly we have in Y
:
define void @outer(ptr noundef %0) {
call void @inner(ptr poison) ; Passing `poison` to `noundef` parameter!
}
declare void @inner(ptr noundef %0)
I have no idea of whether this is a (fundamental) problem with LLVM or with how Rust implements (Thin) LTO.
Note: I've so far only reproduced this with rustc
compiled against LLVM HEAD, but wanted a tracking issue for further investigations.
Background: https://reviews.llvm.org/D133036 causes proc_macro
to get miscompiled, leading to rustc
segfaults. The patch got submitted once a few weeks ago and then rolled back. I noticed at the time, and wanted to preemptively figure out what's going on.
That patch eliminates function calls where undef
(or poison
) is passed to a parameter when that parameter is marked noundef
. In the example above, it would eliminate the call to @inner
.
cc @nikic