Skip to content

Commit

Permalink
eliminate ccall intrinsic
Browse files Browse the repository at this point in the history
  • Loading branch information
vtjnash committed Jan 19, 2017
1 parent 91f9e82 commit 45efc24
Show file tree
Hide file tree
Showing 11 changed files with 76 additions and 73 deletions.
2 changes: 0 additions & 2 deletions base/boot.jl
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,6 @@
# runnable::Bool
# end

import Core.Intrinsics.ccall

export
# key types
Any, DataType, Vararg, ANY, NTuple,
Expand Down
100 changes: 52 additions & 48 deletions base/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,9 @@ add_tfunc(throw, 1, 1, x->Bottom)
# the inverse of typeof_tfunc
function instanceof_tfunc(t::ANY)
# TODO improve
if isa(t, Const)
if t === Bottom
return t
elseif isa(t, Const)
if isa(t.val, Type)
return t.val
end
Expand All @@ -358,27 +360,14 @@ add_tfunc(ne_float_fast, 2, 2, cmp_tfunc)
add_tfunc(lt_float_fast, 2, 2, cmp_tfunc)
add_tfunc(le_float_fast, 2, 2, cmp_tfunc)

chk_tfunc = (x,y) -> Tuple{widenconst(x),Bool}
chk_tfunc = (x::ANY, y::ANY) -> Tuple{widenconst(x), Bool}
add_tfunc(checked_sadd_int, 2, 2, chk_tfunc)
add_tfunc(checked_uadd_int, 2, 2, chk_tfunc)
add_tfunc(checked_ssub_int, 2, 2, chk_tfunc)
add_tfunc(checked_usub_int, 2, 2, chk_tfunc)
add_tfunc(checked_smul_int, 2, 2, chk_tfunc)
add_tfunc(checked_umul_int, 2, 2, chk_tfunc)

const _Ref_name = Ref.body.name
add_tfunc(Core.Intrinsics.ccall, 3, IInf,
function(fptr::ANY, rt::ANY, at::ANY, a...)
t = instanceof_tfunc(rt)
if isa(t, DataType) && (t::DataType).name === _Ref_name
t = t.parameters[1]
if 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::ANY, rt::ANY, at::ANY, a...) -> instanceof_tfunc(rt))
cglobal_tfunc(fptr::ANY) = Ptr{Void}
Expand Down Expand Up @@ -1407,20 +1396,22 @@ function abstract_eval_call(e::Expr, vtypes::VarTable, sv::InferenceState)
return abstract_call(f, e.args, argtypes, vtypes, sv)
end

const _Ref_name = Ref.body.name

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[slot_id(e)].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
Expand All @@ -1431,17 +1422,33 @@ function abstract_eval(e::ANY, vtypes::VarTable, sv::InferenceState)
elseif e.head === :new
t = instanceof_tfunc(abstract_eval(e.args[1], vtypes, sv))
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 e.head === :&
abstract_eval(e.args[1], vtypes, sv)
t = Any
elseif e.head === :foreigncall
abstract_eval(e.args[1], vtypes, sv)
t = instanceof_tfunc(abstract_eval(e.args[2], vtypes, sv))
for i = 3:length(e.args)
if abstract_eval(e.args[i], vtypes, sv) === Bottom
t = Bottom
end
end
if isa(t, DataType) && (t::DataType).name === _Ref_name
t = t.parameters[1]
if t === Any
t = Bottom # a return type of Ref{Any} is invalid
end
end
elseif 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 Down Expand Up @@ -1509,26 +1516,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 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 e.head === :call
elseif e.head === :call || e.head === :foreigncall
t = abstract_eval(e, vtypes, sv)
t === Bottom && return ()
elseif e.head === :gotoifnot
t = abstract_eval(e.args[1], vtypes, sv)
t === Bottom && return ()
elseif 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 @@ -2723,7 +2730,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
f === Intrinsics.checked_trunc_sint ||
f === Intrinsics.checked_trunc_uint ||
Expand Down Expand Up @@ -3598,32 +3604,30 @@ 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
if isccall && _i == 4
i = 2
for _i = length(eargs):-1:i0
if isccall && _i == 3
i = 1
isccallee = true
else
i = _i
Expand Down Expand Up @@ -3682,17 +3686,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 @@ -859,10 +859,6 @@ function show_unquoted(io::IO, ex::Expr, indent::Int, prec::Int)
print(io, " if ")
show_unquoted(io, args[1], indent)

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

# comparison (i.e. "x < y < z")
elseif head === :comparison && nargs >= 3 && (nargs&1==1)
comp_prec = minimum(operator_precedence, args[2:2:end])
Expand Down
3 changes: 2 additions & 1 deletion src/ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,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 Expand Up @@ -358,6 +358,7 @@ void jl_init_frontend(void)
empty_sym = jl_symbol("");
call_sym = jl_symbol("call");
invoke_sym = jl_symbol("invoke");
foreigncall_sym = jl_symbol("foreigncall");
quote_sym = jl_symbol("quote");
inert_sym = jl_symbol("inert");
top_sym = jl_symbol("top");
Expand Down
3 changes: 2 additions & 1 deletion src/ccall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1372,14 +1372,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 @@ -1986,16 +1986,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 @@ -2008,10 +1998,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 @@ -3504,6 +3503,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 @@ -861,7 +861,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
2 changes: 1 addition & 1 deletion src/julia-syntax.scm
Original file line number Diff line number Diff line change
Expand Up @@ -3265,7 +3265,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 @@ -838,7 +838,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 @@ -334,13 +334,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 @@ -353,7 +356,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 45efc24

Please sign in to comment.