-
-
Notifications
You must be signed in to change notification settings - Fork 5.6k
Compiler: add Task call, invoke, and fetch optimizations and operations #59221
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -2345,7 +2345,7 @@ function abstract_finalizer(interp::AbstractInterpreter, argtypes::Vector{Any}, | |||||
finalizer_argvec = Any[argtypes[2], argtypes[3]] | ||||||
call = abstract_call(interp, ArgInfo(nothing, finalizer_argvec), StmtInfo(false, false), sv, #=max_methods=#1)::Future | ||||||
return Future{CallMeta}(call, interp, sv) do call, interp, sv | ||||||
return CallMeta(Nothing, Any, Effects(), FinalizerInfo(call.info, call.effects)) | ||||||
return CallMeta(Nothing, Any, Effects(), IndirectCallInfo(call.info, call.effects, false)) | ||||||
end | ||||||
end | ||||||
return Future(CallMeta(Nothing, Any, Effects(), NoCallInfo())) | ||||||
|
@@ -2679,6 +2679,8 @@ function abstract_call_known(interp::AbstractInterpreter, @nospecialize(f), | |||||
return Future(abstract_eval_isdefinedglobal(interp, sv, si.saw_latestworld, argtypes)) | ||||||
elseif f === Core.get_binding_type | ||||||
return Future(abstract_eval_get_binding_type(interp, sv, argtypes)) | ||||||
elseif f === Core._task | ||||||
return abstract_eval_task_builtin(interp, arginfo, si, sv) | ||||||
end | ||||||
rt = abstract_call_builtin(interp, f, arginfo, sv) | ||||||
ft = popfirst!(argtypes) | ||||||
|
@@ -3208,6 +3210,57 @@ function abstract_eval_splatnew(interp::AbstractInterpreter, e::Expr, sstate::St | |||||
return RTEffects(rt, Any, effects) | ||||||
end | ||||||
|
||||||
function abstract_eval_task_builtin(interp::AbstractInterpreter, arginfo::ArgInfo, si::StmtInfo, sv::AbsIntState) | ||||||
(; fargs, argtypes) = arginfo | ||||||
la = length(argtypes) | ||||||
𝕃ᵢ = typeinf_lattice(interp) | ||||||
# Check argument count: _task(func, size) or _task(func, size, ci) | ||||||
if la < 3 || la > 4 | ||||||
return Future(CallMeta(Bottom, Any, EFFECTS_THROWS, NoCallInfo())) | ||||||
end | ||||||
# Check that size argument is an Int | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
size_arg = argtypes[3] | ||||||
if !(widenconst(size_arg) ⊑ Int) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
return Future(CallMeta(Bottom, Any, EFFECTS_THROWS, NoCallInfo())) | ||||||
end | ||||||
|
||||||
func_arg = argtypes[2] | ||||||
|
||||||
# Handle optional Method/CodeInstance/Type argument (4th parameter) | ||||||
if la == 4 | ||||||
invoke_args = Any[Const(Core.invoke), func_arg, argtypes[4]] | ||||||
invoke_arginfo = ArgInfo(nothing, invoke_args) | ||||||
invoke_future = abstract_invoke(interp, invoke_arginfo, si, sv) | ||||||
return Future{CallMeta}(invoke_future, interp, sv) do invoke_result, interp, sv | ||||||
fetch_type = invoke_result.rt | ||||||
fetch_error = invoke_result.exct | ||||||
task_effects = invoke_result.effects | ||||||
if fetch_type === Any && fetch_error === Any | ||||||
rt_result = Task | ||||||
else | ||||||
rt_result = PartialTask(fetch_type, fetch_error) | ||||||
end | ||||||
info_result = IndirectCallInfo(invoke_result.info, task_effects, true) | ||||||
return CallMeta(rt_result, Any, Effects(), info_result) | ||||||
end | ||||||
end | ||||||
|
||||||
# Fallback to abstract_call for function analysis | ||||||
callinfo_future = abstract_call(interp, ArgInfo(nothing, Any[func_arg]), StmtInfo(true, si.saw_latestworld), sv, #=max_methods=#1) | ||||||
return Future{CallMeta}(callinfo_future, interp, sv) do callinfo, interp, sv | ||||||
fetch_type = callinfo.rt | ||||||
fetch_error = callinfo.exct | ||||||
task_effects = callinfo.effects | ||||||
if fetch_type === Any && fetch_error === Any | ||||||
rt_result = Task | ||||||
else | ||||||
rt_result = PartialTask(fetch_type, fetch_error) | ||||||
end | ||||||
info_result = IndirectCallInfo(callinfo.info, task_effects, true) | ||||||
return CallMeta(rt_result, Any, Effects(), info_result) | ||||||
end | ||||||
end | ||||||
|
||||||
function abstract_eval_new_opaque_closure(interp::AbstractInterpreter, e::Expr, sstate::StatementState, | ||||||
sv::AbsIntState) | ||||||
𝕃ᵢ = typeinf_lattice(interp) | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -454,33 +454,31 @@ end | |
add_edges_impl(edges::Vector{Any}, info::ReturnTypeCallInfo) = add_edges!(edges, info.info) | ||
|
||
""" | ||
info::FinalizerInfo <: CallInfo | ||
|
||
Represents the information of a potential (later) call to the finalizer on the given | ||
object type. | ||
""" | ||
struct FinalizerInfo <: CallInfo | ||
info::CallInfo # the callinfo for the finalizer call | ||
effects::Effects # the effects for the finalizer call | ||
end | ||
# merely allocating a finalizer does not imply edges (unless it gets inlined later) | ||
add_edges_impl(::Vector{Any}, ::FinalizerInfo) = nothing | ||
|
||
""" | ||
info::ModifyOpInfo <: CallInfo | ||
|
||
Represents a resolved call of one of: | ||
- `modifyfield!(obj, name, op, x, [order])` | ||
- `modifyglobal!(mod, var, op, x, order)` | ||
- `memoryrefmodify!(memref, op, x, order, boundscheck)` | ||
- `Intrinsics.atomic_pointermodify(ptr, op, x, order)` | ||
|
||
`info.info` wraps the call information of `op(getval(), x)`. | ||
""" | ||
struct ModifyOpInfo <: CallInfo | ||
info::CallInfo # the callinfo for the `op(getval(), x)` call | ||
info::IndirectCallInfo <: CallInfo | ||
|
||
Represents information about a call that involves an indirect/nested function call. | ||
Used for: | ||
- `modifyfield!(obj, name, op, x, [order])` where `op(getval(), x)` is called | ||
- `modifyglobal!(mod, var, op, x, order)` where `op(getval(), x)` is called | ||
- `memoryrefmodify!(memref, op, x, order, boundscheck)` where `op(getval(), x)` is called | ||
- `Intrinsics.atomic_pointermodify(ptr, op, x, order)` where `op(getval(), x)` is called | ||
- `Core._task(f, size)` where `f()` will be called when the task runs | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Aren't task and finalizer different from the modify functions in that the modify functions eagerly call the argument at the call site, while task and finalizer are deferred? I thought that was important. |
||
- `Core.finalizer(f, obj)` where `f(obj)` will be called during garbage collection | ||
|
||
Contains the CallInfo for the indirect function call, its effects, and whether | ||
the indirect call should contribute edges for invalidation tracking. | ||
""" | ||
struct IndirectCallInfo <: CallInfo | ||
info::CallInfo # the callinfo for the indirect function call | ||
effects::Effects # the effects for the indirect function call | ||
add_edges::Bool # whether to add edges for invalidation tracking | ||
end | ||
function add_edges_impl(edges::Vector{Any}, info::IndirectCallInfo) | ||
if info.add_edges | ||
add_edges!(edges, info.info) | ||
end | ||
# otherwise add no edges (e.g., for finalizers that don't imply edges unless inlined) | ||
end | ||
add_edges_impl(edges::Vector{Any}, info::ModifyOpInfo) = add_edges!(edges, info.info) | ||
|
||
struct VirtualMethodMatchInfo <: CallInfo | ||
info::Union{MethodMatchInfo,UnionSplitInfo,InvokeCallInfo} | ||
|
@@ -502,4 +500,5 @@ function add_edges_impl(edges::Vector{Any}, info::GlobalAccessInfo) | |
push!(edges, info.b) | ||
end | ||
|
||
|
||
@specialize |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.