Add optimizer support for `invoke(f, ::CodeInstance, args...)` (#60442)
~~(I wrote this with assistance from Gemini since I'm not very used to
writing LLVM IR)~~ No longer using that code
This is an attempt to fix
https://github.com/JuliaLang/julia/issues/60441. After bumbling around a
bit, it seems that the problem is that `invoke(f, ::CodeInstance,
args...)` calls are not turned into `Expr(:invoke` statements in the IR,
but remains as `:call`s to the `invoke` builtin which ends up going
through the runtime.
~~There's probably a better way to do this, but the way I found was to
just detect these builtin calls in the LLVM IR, and send them to
`emit_invoke`.~~ I'm now detecting `InvokeCICallInfo`s in the inlining
step of the optimizer and turning those into `Expr(:invoke`s.
It appears to resolve the issue:
```julia
using BenchmarkTools
mysin(x::Float64) = sin(x)
@assert mysin(1.0) == sin(1.0)
const mysin_ci = Base.specialize_method(Base._which(Tuple{typeof(mysin), Float64})).cache
```
Before this PR:
```julia
julia> @btime invoke(mysin, mysin_ci, x) setup=(x=rand())
24.952 ns (2 allocations: 32 bytes)
0.7024964043721993
```
After this PR:
```julia
julia> @btime invoke(mysin, mysin_ci, x) setup=(x=rand())
4.748 ns (0 allocations: 0 bytes)
0.32283046823183426
```
(cherry picked from commit e1dda38c5151d5c31af584151f86c41779eaa6ad)