EntryExitInstrumenter: skip available_externally linkage

gnu::always_inline functions, which lower to available_externally, may
not have definitions external to the module. -finstrument-function
family options instrumentating the function (which takes the function
address) may lead to a linker error if the function is not optimized
out, e.g.

```
// -std=c++17 or above with libstdc++
 #include <string>
std::string str;
int main() {}
```

Simplified reproduce:
```
template <typename T>
struct A {
  [[gnu::always_inline]] T bar(T a) { return a * 2; }
};
extern template class A<int>;
int main(int argc, char **argv) {
  return A<int>().bar(argc);
}
```

GCC's -finstrument-function instrumentation skips such functions
(https://gcc.gnu.org/PR78333). Let's skip such functions
(available_externally) as well.

Fix #50742

Pull Request: https://github.com/llvm/llvm-project/pull/121452
This commit is contained in:
Fangrui Song 2025-01-03 09:25:08 -08:00 committed by GitHub
parent c19f0f005a
commit e6f76378c2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 13 additions and 0 deletions

View File

@ -103,6 +103,12 @@ static bool runOnFunction(Function &F, bool PostInlining) {
if (F.hasFnAttribute(Attribute::Naked))
return false;
// available_externally functions may not have definitions external to the
// module (e.g. gnu::always_inline). Instrumenting them might lead to linker
// errors if they are optimized out. Skip them like GCC.
if (F.hasAvailableExternallyLinkage())
return false;
StringRef EntryAttr = PostInlining ? "instrument-function-entry-inlined"
: "instrument-function-entry";

View File

@ -129,6 +129,13 @@ define void @naked() naked {
ret void
}
define available_externally void @always_inline() {
; CHECK-LABEL: define available_externally void @always_inline() {
; CHECK-NEXT: ret void
;
ret void
}
; The attributes are "consumed" when the instrumentation is inserted.
; CHECK: attributes
; CHECK-NOT: instrument-function