Skip to content

Commit

Permalink
eliminate ccall intrinsic
Browse files Browse the repository at this point in the history
  • Loading branch information
vtjnash committed Oct 3, 2016
1 parent 7bb26e4 commit a09ee6c
Show file tree
Hide file tree
Showing 12 changed files with 86 additions and 82 deletions.
2 changes: 0 additions & 2 deletions base/boot.jl
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,6 @@
# runnable::Bool
# end

import Core.Intrinsics.ccall

export
# key types
Any, DataType, Vararg, ANY, NTuple,
Expand Down
119 changes: 62 additions & 57 deletions base/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -274,21 +274,6 @@ add_tfunc(lt_float, 2, 2, cmp_tfunc)
add_tfunc(le_float, 2, 2, cmp_tfunc)
add_tfunc(fpiseq, 2, 2, cmp_tfunc)
add_tfunc(fpislt, 2, 2, cmp_tfunc)
add_tfunc(Core.Intrinsics.ccall, 3, IInf,
function(fptr, rt, at, a...)
if !isType(rt)
return Any
end
t = rt.parameters[1]
if isa(t,DataType) && is((t::DataType).name,Ref.name)
t = t.parameters[1]
if is(t,Any)
return Union{} # a return type of Box{Any} is invalid
end
return t
end
return t
end)
add_tfunc(Core.Intrinsics.llvmcall, 3, IInf,
(fptr, rt, at, a...)->(isType(rt) ? rt.parameters[1] : Any))
add_tfunc(Core.Intrinsics.cglobal, 1, 2,
Expand Down Expand Up @@ -1156,45 +1141,68 @@ function abstract_eval_call(e::Expr, vtypes::VarTable, sv::InferenceState)
end

function abstract_eval(e::ANY, vtypes::VarTable, sv::InferenceState)
if isa(e,QuoteNode)
if isa(e, QuoteNode)
return abstract_eval_constant((e::QuoteNode).value)
elseif isa(e,SSAValue)
elseif isa(e, SSAValue)
return abstract_eval_ssavalue(e::SSAValue, sv.src)
elseif isa(e,Slot)
elseif isa(e, Slot)
return vtypes[e.id].typ
elseif isa(e,Symbol)
elseif isa(e, Symbol)
return abstract_eval_global(sv.mod, e)
elseif isa(e,GlobalRef)
return abstract_eval_global(e.mod, e.name)
end

if !isa(e,Expr)
if !isa(e, Expr)
return abstract_eval_constant(e)
end
e = e::Expr
if is(e.head,:call)
if is(e.head, :call)
t = abstract_eval_call(e, vtypes, sv)
elseif is(e.head,:null)
t = Void
elseif is(e.head,:new)
elseif is(e.head, :new)
t = abstract_eval(e.args[1], vtypes, sv)
if isType(t)
t = t.parameters[1]
else
t = Any
end
for i = 2:length(e.args)
abstract_eval(e.args[i], vtypes, sv)
if abstract_eval(e.args[i], vtypes, sv) === Bottom
rt = Bottom
end
end
elseif is(e.head,:&)
elseif is(e.head, :&)
abstract_eval(e.args[1], vtypes, sv)
t = Any
elseif is(e.head, :foreigncall)
abstract_eval(e.args[1], vtypes, sv)
rt = abstract_eval(e.args[2], vtypes, sv)
for i = 3:length(e.args)
if abstract_eval(e.args[i], vtypes, sv) === Bottom
rt = Bottom
end
end
if rt === Bottom
t = Bottom
elseif !isType(rt)
t = Any
else
t = rt.parameters[1]
if isa(t, DataType) && is((t::DataType).name, Ref.name)
t = t.parameters[1]
if t === Any
t = Bottom # a return type of Box{Any} is invalid
end
end
end
elseif is(e.head, :static_parameter)
n = e.args[1]
t = Any
if n <= length(sv.sp)
val = sv.sp[n]
if isa(val,TypeVar)
if isa(val, TypeVar)
# static param bound to typevar
# if the tvar does not refer to anything more specific than Any,
# the static param might actually be an integer, symbol, etc.
Expand All @@ -1205,13 +1213,13 @@ function abstract_eval(e::ANY, vtypes::VarTable, sv::InferenceState)
t = abstract_eval_constant(val)
end
end
elseif is(e.head,:method)
elseif is(e.head, :method)
t = (length(e.args) == 1) ? Any : Void
elseif is(e.head,:copyast)
elseif is(e.head, :copyast)
t = abstract_eval(e.args[1], vtypes, sv)
elseif is(e.head,:inert)
elseif is(e.head, :inert)
return abstract_eval_constant(e.args[1])
elseif is(e.head,:invoke)
elseif is(e.head, :invoke)
error("type inference data-flow error: tried to double infer a function")
else
t = Any
Expand Down Expand Up @@ -1261,26 +1269,26 @@ type StateUpdate
end

function abstract_interpret(e::ANY, vtypes::VarTable, sv::InferenceState)
!isa(e,Expr) && return vtypes
!isa(e, Expr) && return vtypes
# handle assignment
if is(e.head,:(=))
if is(e.head, :(=))
t = abstract_eval(e.args[2], vtypes, sv)
t === Bottom && return ()
lhs = e.args[1]
if isa(lhs,Slot) || isa(lhs,SSAValue)
if isa(lhs, Slot) || isa(lhs, SSAValue)
# don't bother for GlobalRef
return StateUpdate(lhs, VarState(t,false), vtypes)
return StateUpdate(lhs, VarState(t, false), vtypes)
end
elseif is(e.head,:call)
elseif is(e.head, :call) || is(e.head, :foreigncall)
t = abstract_eval(e, vtypes, sv)
t === Bottom && return ()
elseif is(e.head,:gotoifnot)
elseif is(e.head, :gotoifnot)
t = abstract_eval(e.args[1], vtypes, sv)
t === Bottom && return ()
elseif is(e.head,:method)
elseif is(e.head, :method)
fname = e.args[1]
if isa(fname,Slot)
return StateUpdate(fname, VarState(Any,false), vtypes)
if isa(fname, Slot)
return StateUpdate(fname, VarState(Any, false), vtypes)
end
end
return vtypes
Expand Down Expand Up @@ -2250,7 +2258,6 @@ function is_pure_builtin(f::ANY)
if isa(f,IntrinsicFunction)
if !(f === Intrinsics.pointerref || # this one is volatile
f === Intrinsics.pointerset || # this one is never effect-free
f === Intrinsics.ccall || # this one is never effect-free
f === Intrinsics.llvmcall) # this one is never effect-free
return true
end
Expand Down Expand Up @@ -2942,31 +2949,29 @@ const corenumtype = Union{Int32, Int64, Float32, Float64}
function inlining_pass(e::Expr, sv::InferenceState)
if e.head === :method
# avoid running the inlining pass on function definitions
return (e,())
return (e, ())
end
eargs = e.args
if length(eargs)<1
return (e,())
if length(eargs) < 1
return (e, ())
end
stmts = []
arg1 = eargs[1]
isccall = false
i0 = 1
# don't inline first (global) arguments of ccall, as this needs to be evaluated
# by the interpreter and inlining might put in something it can't handle,
# like another ccall (or try to move the variables out into the function)
if is_known_call(e, Core.Intrinsics.ccall, sv.src, sv.mod)
# 4 is rewritten to 2 below to handle the callee.
i0 = 4
if e.head === :foreigncall
# 3 is rewritten to 1 below to handle the callee.
i0 = 3
isccall = true
elseif is_known_call(e, Core.Intrinsics.llvmcall, sv.src, sv.mod)
i0 = 5
isccall = false
else
i0 = 1
isccall = false
end
has_stmts = false # needed to preserve order-of-execution
for _i=length(eargs):-1:i0
i = (isccall && _i == 4) ? 2 : _i
for _i = length(eargs):-1:i0
i = (isccall && _i == 3) ? 1 : _i
ei = eargs[i]
if isa(ei,Expr)
ei = ei::Expr
Expand Down Expand Up @@ -3006,17 +3011,17 @@ function inlining_pass(e::Expr, sv::InferenceState)
end
end
end
if e.head !== :call
return (e, stmts)
end
if isccall
le = length(eargs)
for i=5:2:le-1
if eargs[i] === eargs[i+1]
eargs[i+1] = 0
for i = 4:2:(le - 1)
if eargs[i] === eargs[i + 1]
eargs[i + 1] = 0
end
end
end
if e.head !== :call
return (e, stmts)
end

ft = exprtype(arg1, sv.src, sv.mod)
if isa(ft, Const)
Expand Down
4 changes: 0 additions & 4 deletions base/show.jl
Original file line number Diff line number Diff line change
Expand Up @@ -834,10 +834,6 @@ function show_unquoted(io::IO, ex::Expr, indent::Int, prec::Int)
print(io, " if ")
show_unquoted(io, args[1], indent)

elseif is(head, :ccall)
show_unquoted(io, :ccall, indent)
show_enclosed_list(io, '(', args, ",", ')', indent)

# comparison (i.e. "x < y < z")
elseif is(head, :comparison) && nargs >= 3 && (nargs&1==1)
comp_prec = minimum(operator_precedence, args[2:2:end])
Expand Down
2 changes: 1 addition & 1 deletion src/alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ jl_sym_t *new_sym; jl_sym_t *using_sym;
jl_sym_t *const_sym; jl_sym_t *thunk_sym;
jl_sym_t *anonymous_sym; jl_sym_t *underscore_sym;
jl_sym_t *abstracttype_sym; jl_sym_t *bitstype_sym;
jl_sym_t *compositetype_sym;
jl_sym_t *compositetype_sym; jl_sym_t *foreigncall_sym;
jl_sym_t *global_sym; jl_sym_t *list_sym;
jl_sym_t *dot_sym; jl_sym_t *newvar_sym;
jl_sym_t *boundscheck_sym; jl_sym_t *inbounds_sym;
Expand Down
3 changes: 2 additions & 1 deletion src/ccall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1384,14 +1384,15 @@ static const std::string verify_ccall_sig(size_t nargs, jl_value_t *&rt, jl_valu
return "";
}

// ccall(pointer, rettype, (argtypes...), args...)
// Expr(:ccall, pointer, rettype, (argtypes...), args...)
static jl_cgval_t emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx)
{
jl_ptls_t ptls = jl_get_ptls_states();
JL_NARGSV(ccall, 3);
jl_value_t *rt = NULL, *at = NULL;
native_sym_arg_t symarg = {};
JL_GC_PUSH3(&rt, &at, &symarg.gcroot);
args -= 1;

CallingConv::ID cc = CallingConv::C;
bool llvmcall = false;
Expand Down
24 changes: 13 additions & 11 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1944,16 +1944,6 @@ static void simple_escape_analysis(jl_value_t *expr, bool esc, jl_codectx_t *ctx
if (jl_value_t *fv = static_eval(f, ctx, false)) {
if (jl_typeis(fv, jl_intrinsic_type)) {
esc = false;
JL_I::intrinsic fi = (JL_I::intrinsic)jl_unbox_int32(fv);
if (fi == JL_I::ccall) {
esc = true;
simple_escape_analysis(jl_exprarg(e,1), esc, ctx);
// 2nd and 3d arguments are static
for(i=4; i < (size_t)alen; i+=2) {
simple_escape_analysis(jl_exprarg(e,i), esc, ctx);
}
return;
}
}
else {
if ((fv==jl_builtin_getfield && alen==3 &&
Expand All @@ -1966,10 +1956,19 @@ static void simple_escape_analysis(jl_value_t *expr, bool esc, jl_codectx_t *ctx
}
}

for(i=1; i < (size_t)alen; i++) {
for (i = 1; i < (size_t)alen; i++) {
simple_escape_analysis(jl_exprarg(e,i), esc, ctx);
}
}
else if (e->head == foreigncall_sym) {
esc = true;
simple_escape_analysis(jl_exprarg(e, 0), esc, ctx);
// 2nd and 3d arguments are static
size_t alen = jl_array_dim0(e->args);
for (i = 3; i < alen; i += 2) {
simple_escape_analysis(jl_exprarg(e, i), esc, ctx);
}
}
else if (e->head == method_sym) {
simple_escape_analysis(jl_exprarg(e,0), esc, ctx);
if (jl_expr_nargs(e) > 1) {
Expand Down Expand Up @@ -3373,6 +3372,9 @@ static jl_cgval_t emit_expr(jl_value_t *expr, jl_codectx_t *ctx)
}
return res;
}
else if (head == foreigncall_sym) {
return emit_ccall(args, jl_array_dim0(ex->args), ctx);
}
else if (head == assign_sym) {
emit_assignment(args[0], args[1], ctx);
return ghostValue(jl_void_type);
Expand Down
1 change: 0 additions & 1 deletion src/intrinsics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -857,7 +857,6 @@ static jl_cgval_t emit_intrinsic(intrinsic f, jl_value_t **args, size_t nargs,
}

switch (f) {
case ccall: return emit_ccall(args, nargs, ctx);
case cglobal_auto:
case cglobal: return emit_cglobal(args, nargs, ctx);
case llvmcall: return emit_llvmcall(args, nargs, ctx);
Expand Down
1 change: 0 additions & 1 deletion src/intrinsics.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,6 @@
ADD_I(pointerref, 3) \
ADD_I(pointerset, 4) \
/* c interface */ \
ALIAS(ccall, ccall) \
ADD_I(cglobal, 2) \
ALIAS(llvmcall, llvmcall) \
/* object access */ \
Expand Down
1 change: 1 addition & 0 deletions src/jltypes.c
Original file line number Diff line number Diff line change
Expand Up @@ -4035,6 +4035,7 @@ void jl_init_types(void)

empty_sym = jl_symbol("");
call_sym = jl_symbol("call");
foreigncall_sym = jl_symbol("foreigncall");
invoke_sym = jl_symbol("invoke");
quote_sym = jl_symbol("quote");
inert_sym = jl_symbol("inert");
Expand Down
2 changes: 1 addition & 1 deletion src/julia-syntax.scm
Original file line number Diff line number Diff line change
Expand Up @@ -3164,7 +3164,7 @@ f(x) = yt(x)
(list-head (cddr e) 2)
(compile-args (list-tail e 4) break-labels))
(compile-args (cdr e) break-labels)))
(callex (if (eq? (car e) 'foreigncall) (cons 'call (cons `(core ccall) args)) (cons (car e) args))))
(callex (cons (car e) args)))
(cond (tail (emit-return callex))
(value callex)
((eq? (car e) 'new) #f)
Expand Down
2 changes: 1 addition & 1 deletion src/julia_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -835,7 +835,7 @@ extern jl_sym_t *lambda_sym; extern jl_sym_t *assign_sym;
extern jl_sym_t *method_sym; extern jl_sym_t *slot_sym;
extern jl_sym_t *enter_sym; extern jl_sym_t *leave_sym;
extern jl_sym_t *exc_sym; extern jl_sym_t *new_sym;
extern jl_sym_t *compiler_temp_sym;
extern jl_sym_t *compiler_temp_sym; extern jl_sym_t *foreigncall_sym;
extern jl_sym_t *const_sym; extern jl_sym_t *thunk_sym;
extern jl_sym_t *anonymous_sym; extern jl_sym_t *underscore_sym;
extern jl_sym_t *abstracttype_sym; extern jl_sym_t *bitstype_sym;
Expand Down
7 changes: 5 additions & 2 deletions src/toplevel.c
Original file line number Diff line number Diff line change
Expand Up @@ -326,13 +326,16 @@ static jl_value_t *jl_static_eval(jl_value_t *ex, jl_module_t *mod,

int jl_has_intrinsics(jl_method_instance_t *li, jl_value_t *v, jl_module_t *m)
{
if (!jl_is_expr(v)) return 0;
if (!jl_is_expr(v))
return 0;
jl_expr_t *e = (jl_expr_t*)v;
if (jl_array_len(e->args) == 0)
return 0;
if (e->head == toplevel_sym || e->head == copyast_sym)
return 0;
jl_value_t *e0 = jl_exprarg(e, 0);
if (e->head == foreigncall_sym)
return 1;
if (e->head == call_sym) {
jl_value_t *sv = jl_static_eval(e0, m, li, li != NULL);
if (sv && jl_typeis(sv, jl_intrinsic_type))
Expand All @@ -345,7 +348,7 @@ int jl_has_intrinsics(jl_method_instance_t *li, jl_value_t *v, jl_module_t *m)
return 1;
}
int i;
for (i=0; i < jl_array_len(e->args); i++) {
for (i = 0; i < jl_array_len(e->args); i++) {
jl_value_t *a = jl_exprarg(e,i);
if (jl_is_expr(a) && jl_has_intrinsics(li, a, m))
return 1;
Expand Down

0 comments on commit a09ee6c

Please sign in to comment.