unnamed_addr merges constants with different contents: initialized bytes with uninit bytes
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
According to the reference, I would not expect `unnamed_addr` to merge constants with different content (initialized bytes vs uninit bytes). Nevertheless LLVM generates code that allows linker to merge them. For example:
```llvm
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
@a = private unnamed_addr constant <{ [4 x i8], [4 x i8] }> <{ [4 x i8] undef, [4 x i8] zeroinitializer }>, align 4
@b = private unnamed_addr constant <{ [4 x i8], [4 x i8] }> zeroinitializer, align 4
define i32 @main() {
%1 = icmp ne ptr @a, @b
%2 = zext i1 %1 to i32
ret i32 %2
}
```
```console
$ clang-24 a.ll
$ ./a.out
$ echo "icmp ne ptr @a, @b evaluated to $?"
icmp ne ptr @a, @b evaluated to 0
```
What is perhaps more important, both GVN and SCCP assume that such merging is prohibited:
```llvm
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
@a = private unnamed_addr constant <{ [4 x i8], [4 x i8] }> <{ [4 x i8] undef, [4 x i8] zeroinitializer }>, align 4
@b = private unnamed_addr constant <{ [4 x i8], [4 x i8] }> zeroinitializer, align 4
define noundef i32 @f(ptr align 4 %p) {
%1 = icmp eq ptr %p, @a
call void @llvm.assume(i1 %1)
%2 = load i32, ptr %p, align 4
ret i32 %2
}
```
They optimize above to return `undef`, which is inconsistent with a situation where constants like `@a` and `@b` have the same address and `@f` is called with a pointer to `@b`.
```llvm
define noundef i32 @f(ptr align 4 %p) {
%1 = icmp eq ptr %p, @a
call void @llvm.assume(i1 %1)
ret i32 undef
}
```
Related issues: https://github.com/rust-lang/rust/issues/161973, https://github.com/rust-lang/rust/issues/162078
Contributor guide
Research direction
Start by running the supplied LLVM IR with clang-24 and reproducing the address comparison result. Then inspect the assumptions described for GVN and SCCP alongside linker merging of @a and @b. Done means the semantics of unnamed_addr, optimizer reasoning, and generated behavior agree for initialized and uninitialized bytes.
Written by the indexing model from the issue text.
Assessment
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100