Statically known but dynamically selected functions are not inlined
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
This pattern prevents inlining (https://godbolt.org/z/G5bjTWGYK):
```llvm
define dso_local noundef i32 @foo() local_unnamed_addr {
entry:
ret i32 1
}
define dso_local noundef i32 @bar() local_unnamed_addr {
entry:
ret i32 2
}
define dso_local i32 @test(i32 noundef %b) local_unnamed_addr {
entry:
%tobool.not = icmp eq i32 %b, 0
%cond = select i1 %tobool.not, ptr @bar, ptr @foo
%call = tail call i32 %cond() #2
ret i32 %call
}
```
It does not matter if the function pointer is assigned using control flow + phi instead of select, as long as there is a single call node.
This can be reproduced both in C (https://godbolt.org/z/7d8sr6r4o):
```c
__attribute__((always_inline))
int foo() { return 1; }
__attribute__((always_inline))
int bar() { return 2; }
typedef int (*fptr)();
int test(int b) {
fptr f = b ? foo : bar;
return f();
}
```
and with virtual functions (https://godbolt.org/z/bP8cvTo4W):
```c++
struct A {
virtual int foo() = 0;
};
struct B : public A {
int foo() override { return 1; }
};
struct C : public A {
int foo() override { return 2; }
};
int test(bool pred) {
B b;
C c;
A *a = pred ? static_cast(&b) : static_cast(&c);
return a->foo();
}
```
Contributor guide
Research direction
The LLVM IR, C, and C++ reproductions in the issue, via the linked Compiler Explorer cases, are the starting points. First reproduce the missed inlining, then trace the optimizer's handling of a single indirect call whose target comes from select/phi or virtual dispatch. Done means the shown statically known calls are inlined in generated output while preserving behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c, cpp
- Domain
- compilers, performance
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100