Consider:
julia> @code_warntype Base.unsafe_convert(Ptr{Float64}, randn(10))
MethodInstance for Base.unsafe_convert(::Type{Ptr{Float64}}, ::Vector{Float64})
from unsafe_convert(::Type{Ptr{T}}, a::Array{T}) where T @ Base ~/.julia/juliaup/julia-1.9.2+0.x64.apple.darwin14/share/julia/base/pointer.jl:65
Static Parameters
T = Float64
Arguments
#self#::Core.Const(Base.unsafe_convert)
_::Core.Const(Ptr{Float64})
a::Vector{Float64}
Body::Ptr{Float64}
1 ─ %1 = $(Expr(:foreigncall, :(:jl_array_ptr), Ptr{T}, svec(Any), 0, :(:ccall), :(a)))::Ptr{Float64}
└── return %1
I’m specifically interested in the return type Ptr{T}
. The presence of this as a single argument to the :foreigncall
node surprised me, as my (clearly incomplete) mental model of lowered code would have expected something like the following to have been produced during lowering:
%1 = $(Expr(:static_parameter, 1)
%2 = Core.apply_type(Ptr, %1)
%3 = $(Expr(:foreigncall, :(:jl_array_ptr), %2, svec(Any), 0, :(:ccall), :(a)))
Could someone explain why this is lowered in this way, rather than expanded out?
For context, I’m interested because I’m trying to understand how Umlaut.jl might handle :foreigncall
nodes, how JuliaInterpreter.jl currently handles them, and what the compiler currently does.