Skip to content

Commit

Permalink
ccall: support different types for vararg arguments (#32800)
Browse files Browse the repository at this point in the history
Not currently supported in the front-end syntax, this modifies the backend to represent it
and be capable of handling it (and need fewer lines of code!).
  • Loading branch information
vtjnash authored Aug 13, 2019
1 parent 4537d78 commit 7b4fa51
Show file tree
Hide file tree
Showing 10 changed files with 191 additions and 162 deletions.
4 changes: 2 additions & 2 deletions base/compiler/ssair/passes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,7 @@ function getfield_elim_pass!(ir::IRCode, domtree::DomTree)
is_getfield = true
is_unchecked = true
elseif isexpr(stmt, :foreigncall)
nccallargs = stmt.args[5]
nccallargs = length(stmt.args[3]::SimpleVector)
new_preserves = Any[]
old_preserves = stmt.args[(6+nccallargs):end]
for (pidx, preserved_arg) in enumerate(old_preserves)
Expand Down Expand Up @@ -817,7 +817,7 @@ function getfield_elim_pass!(ir::IRCode, domtree::DomTree)
# Insert the new preserves
for (use, new_preserves) in preserve_uses
useexpr = ir[SSAValue(use)]
nccallargs = useexpr.args[5]
nccallargs = length(useexpr.args[3]::SimpleVector)
old_preserves = filter(ssa->!isa(ssa, SSAValue) || !(ssa.id in intermediaries), useexpr.args[(6+nccallargs):end])
new_expr = Expr(:foreigncall, useexpr.args[1:(6+nccallargs-1)]...,
old_preserves..., new_preserves...)
Expand Down
2 changes: 1 addition & 1 deletion base/compiler/validation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const VALID_EXPR_HEADS = IdDict{Any,Any}(
:copyast => 1:1,
:meta => 0:typemax(Int),
:global => 1:1,
:foreigncall => 3:typemax(Int),
:foreigncall => 5:typemax(Int), # name, RT, AT, nreq, cconv, args..., roots...
:cfunction => 5:5,
:isdefined => 1:1,
:loopinfo => 0:typemax(Int),
Expand Down
4 changes: 2 additions & 2 deletions base/meta.jl
Original file line number Diff line number Diff line change
Expand Up @@ -313,9 +313,9 @@ function _partially_inline!(@nospecialize(x), slot_replacements::Vector{Any},
elseif i == 3
x.args[3] = Core.svec(Any[_instantiate_type_in_env(argt, type_signature, static_param_values) for argt in x.args[3]]...)
elseif i == 4
@assert isa((x.args[4]::QuoteNode).value, Symbol)
@assert isa(x.args[4], Int)
elseif i == 5
@assert isa(x.args[5], Int)
@assert isa((x.args[5]::QuoteNode).value, Symbol)
else
x.args[i] = _partially_inline!(x.args[i], slot_replacements,
type_signature, static_param_values,
Expand Down
33 changes: 33 additions & 0 deletions doc/src/devdocs/ast.md
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,39 @@ These symbols appear in the `head` field of [`Expr`](@ref)s in lowered form.

* `:inline` and `:noinline`: Inlining hints.

* `foreigncall`

Statically-computed container for `ccall` information. The fields are:

* `args[1]` : name

The expression that'll be parsed for the foreign function.

* `args[2]::Type` : RT

The (literal) return type, computed statically when the containing method was defined.

* `args[3]::SimpleVector` (of Types) : AT

The (literal) vector of argument types, computed statically when the containing method was defined.

* `args[4]::Int` : nreq

The number of required arguments for a varargs function definition.

* `args[5]::QuoteNode{Symbol}` : calling convention

The calling convention for the call.

* `args[6:length(args[3])]` : arguments

The values for all the arguments (with types of each given in args[3]).

* `args[(length(args[3]) + 1):end]` : gc-roots

The additional objects that may need to be gc-rooted for the duration of the call.
See [Working with LLVM](@ref Working-with-LLVM) for where these are derived from and how they get handled.


### Method

Expand Down
2 changes: 1 addition & 1 deletion doc/src/devdocs/llvm.md
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ need to make sure that the array does stay alive while we're doing the
[`ccall`](@ref). To understand how this is done, first recall the lowering of the
above code:
```julia
return $(Expr(:foreigncall, :(:foo), Cvoid, svec(Ptr{Float64}), :(:ccall), 1, :($(Expr(:foreigncall, :(:jl_array_ptr), Ptr{Float64}, svec(Any), :(:ccall), 1, :(A)))), :(A)))
return $(Expr(:foreigncall, :(:foo), Cvoid, svec(Ptr{Float64}), 0, :(:ccall), Expr(:foreigncall, :(:jl_array_ptr), Ptr{Float64}, svec(Any), 0, :(:ccall), :(A)), :(A)))
```
The last `:(A)`, is an extra argument list inserted during lowering that informs
the code generator which Julia level values need to be kept alive for the
Expand Down
Loading

0 comments on commit 7b4fa51

Please sign in to comment.