[llvm] [GlobalOpt] Don't replace aliasee with alias that has weak linkage (PR #91483)

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Fri May 17 16:16:37 PDT 2024


MaskRay wrote:

> linkonce_odr on a function means you can replace a call to the function with the function's body (i.e. inlining). linkonce_odr on a function alias should mean the same thing, I think: a call to the alias can be replaced with the aliasee function's body. This allows a lot of useful optimizations, but it doesn't allow anything more that that. In particular, if you have an internal symbol `@f1`, and `@f2 = linkonce_odr hidden alias void (), ptr @f1`, the "odr-ness" only means that you can replace a call to `@f2` with a call to `@f1`.

Agreed.

> It doesn't allow replacing a call to `@f1` with a call to `@f2`, which is the transform that was causing trouble here. We sometimes refer to this as "derefinement".

While the transformation replaces aliases with their underlying functions, it doesn't work the other way around.
This patch prevents an optimization that would replace linkonce_odr/weak_odr aliases with their aliasees.
This is my concern.

Test output before this `isWeakForlinker` patch. No aliasee is replaced with its alias.

```
define void @foo() local_unnamed_addr {
  call void @f1_alias()
  ret void
}

define void @bar() local_unnamed_addr {
  call void @f1_alias()
  ret void
}

define void @baz() local_unnamed_addr {
  call void @f2_alias()
  ret void
}

define linkonce_odr hidden void @f1_alias() local_unnamed_addr {
  ret void
}

define linkonce_odr hidden void @f2_alias() local_unnamed_addr {
  ret void
}
```

Test output after this `isWeakForlinker` patch

```llvm
@f1_alias = linkonce_odr hidden alias void (), ptr @f1
@f2_alias = linkonce_odr hidden alias void (), ptr @f2

define void @foo() local_unnamed_addr {
  call void @f1_alias()
  ret void
}

define void @bar() local_unnamed_addr {
  call void @f1()
  ret void
}

define void @baz() local_unnamed_addr {
  call void @f2_alias()
  ret void
}

define internal void @f1() {
  ret void
}

define internal void @f2() {
  ret void
}
```

> Granted, the usage of linkonce_odr for aliases pointing to __tls_init stretches this definition of "equivalence" to its extreme limit; the different aliases don't do the same thing. It only works because the C++ standard explicitly allows reordering the initialization of thread-local variables.

Agree there is some stretch about the limit.
I want to know a minimal reproduce to better understand why `__tls_init` was problematic.


https://github.com/llvm/llvm-project/pull/91483


More information about the llvm-commits mailing list