Skip to content

Commit

Permalink
Add optional hooks to inference parameters.
Browse files Browse the repository at this point in the history
This allows controling inference decisions,
for now only method calling.
  • Loading branch information
maleadt committed Oct 18, 2016
1 parent dc2f727 commit 8536254
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 2 deletions.
36 changes: 34 additions & 2 deletions base/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ import Core: _apply, svec, apply_type, Builtin, IntrinsicFunction, MethodInstanc
const MAX_TYPEUNION_LEN = 3
const MAX_TYPE_DEPTH = 7

immutable InferenceHooks
call

InferenceHooks(call) = new(call)
InferenceHooks() = new(nothing)
end

immutable InferenceParams
# optimization
inlining::Bool
Expand All @@ -16,12 +23,15 @@ immutable InferenceParams
MAX_TUPLE_SPLAT::Int
MAX_UNION_SPLITTING::Int

hooks::InferenceHooks

# reasonable defaults
InferenceParams(;inlining::Bool=inlining_enabled(),
tupletype_len::Int=15, tuple_depth::Int=4,
tuple_splat::Int=16, union_splitting::Int=4) =
tuple_splat::Int=16, union_splitting::Int=4,
hooks::InferenceHooks=InferenceHooks()) =
new(inlining, tupletype_len,
tuple_depth, tuple_splat, union_splitting)
tuple_depth, tuple_splat, union_splitting, hooks)
end

const UNION_SPLIT_MISMATCH_ERROR = false
Expand Down Expand Up @@ -1087,6 +1097,15 @@ end
argtypes_to_type(argtypes::Array{Any,1}) = Tuple{map(widenconst, argtypes)...}

function abstract_call(f::ANY, fargs, argtypes::Vector{Any}, vtypes::VarTable, sv::InferenceState)
if sv.params.hooks.call != nothing
hack = sv.params.hooks.call(f, argtypes_to_type(argtypes))
if hack != nothing
println("NOTICE: overriding abstract_call of ", f, " with ", hack)
f = hack
argtypes[1] = typeof(f)
end
end

if f === _apply
length(fargs)>1 || return Any
aft = argtypes[2]
Expand Down Expand Up @@ -3109,6 +3128,19 @@ function inlining_pass(e::Expr, sv::InferenceState)
end
end

if sv.params.hooks.call != nothing
argtypes = Vector{Any}(length(e.args))
argtypes[1] = ft
argtypes[2:end] = map(a->exprtype(a, sv.src, sv.mod), e.args[2:end])

hack = sv.params.hooks.call(f, argtypes_to_type(argtypes))
if hack != nothing
println("NOTICE: overriding inlining_pass of ", f, " with ", hack)
f = hack
ft = typeof(hack)
end
end

if sv.params.inlining
if isdefined(Main, :Base) &&
((isdefined(Main.Base, :^) && f === Main.Base.:^) ||
Expand Down
76 changes: 76 additions & 0 deletions demo.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
using LLVM

#
# Functions
#

@inline function child(x)
x+1
end

@inline function hacked_child(x)
x+2
end

function parent(x)
return child(x)
end


#
# Inference
#

f = parent
t = Tuple{Int}
tt = Base.to_tuple_type(t)

ms = Base._methods(f, tt, -1)
@assert length(ms) == 1
(sig, spvals, m) = first(ms)

# given a function and the argument tuple type (incl. the function type)
# return a tuple of the replacement function and its type, or nothing
function call_hook(f, tt)
if f == child
return hacked_child
end
return nothing
end
# alternatively, call_hook(f::typeof(child), tt) = return hacked_child
hooks = Core.Inference.InferenceHooks(call_hook)

# raise limits on inference parameters, performing a more exhaustive search
params = Core.Inference.InferenceParams(tuple_depth=32, hooks=hooks)

(code, rettyp) = Core.Inference.typeinf_code(m, sig, spvals, true, true, params)
code === nothing && error("inference not successful")
println("Returns: $rettyp")
print(Base.uncompressed_ast(m, code))
println()


#
# IRgen
#

# module set-up
mod = LLVM.Module("my_module")

# irgen
# TODO
exit()
fun = get(functions(mod), "parent")

# execution
ExecutionEngine(mod) do engine
args = [GenericValue(LLVM.Int32Type(), x)]

res = LLVM.run(engine, fun, args)
println(convert(Int, res))

dispose.(args)
dispose(res)
end

# jl_get_llvmf_defn vs jl_compile_linfo?

0 comments on commit 8536254

Please sign in to comment.