diff --git a/src/copyable_task.jl b/src/copyable_task.jl index 2210c5e..4ba0f36 100644 --- a/src/copyable_task.jl +++ b/src/copyable_task.jl @@ -84,11 +84,13 @@ function build_callable(sig::Type{<:Tuple}) return fresh_copy(mc_cache[key]) else ir = Base.code_ircode_by_type(sig)[1][1] + # Check whether this is a varargs call. + isva = which(sig).isva bb, refs, types = derive_copyable_task_ir(BBCode(ir)) unoptimised_ir = IRCode(bb) optimised_ir = optimise_ir!(unoptimised_ir) mc_ret_type = callable_ret_type(sig, types) - mc = misty_closure(mc_ret_type, optimised_ir, refs...; do_compile=true) + mc = misty_closure(mc_ret_type, optimised_ir, refs...; isva=isva, do_compile=true) mc_cache[key] = mc return mc, refs[end] end @@ -315,7 +317,7 @@ end """ set_taped_globals!(t::TapedTask, new_taped_globals)::Nothing -Set the `taped_globals` of `t` to `new_taped_globals`. Any calls to +Set the `taped_globals` of `t` to `new_taped_globals`. Any calls to [`get_taped_globals`](@ref) in future calls to `consume(t)` (either directly, or implicitly via iteration) will see this new value. """ @@ -573,7 +575,7 @@ function derive_copyable_task_ir(ir::BBCode)::Tuple{BBCode,Tuple,Vector{Any}} # We enforced above the condition that the final statement in a basic block must not # produce. This ensures that the final split does not produce. While not strictly # necessary, this simplifies the implementation (see below). - # + # # As a result of the above, a basic block will be associated to exactly one split if it # does not contain any statements which may produce. # @@ -595,7 +597,7 @@ function derive_copyable_task_ir(ir::BBCode)::Tuple{BBCode,Tuple,Vector{Any}} # Owing to splitting blocks up, we will need to re-label some `GotoNode`s and # `GotoIfNot`s. To understand this, consider the following block, whose original `ID` # we assume to be `ID(old_id)`. - # ID(new_id) - %1 = φ(ID(3) => ...) + # ID(new_id) - %1 = φ(ID(3) => ...) # ID(new_id) - %3 = call_which_must_not_produce(...) # ID(new_id) - %4 = produce(%3) # ID(old_id) - GotoNode(ID(5)) diff --git a/src/test_utils.jl b/src/test_utils.jl index f8390e2..98e3abc 100644 --- a/src/test_utils.jl +++ b/src/test_utils.jl @@ -170,6 +170,38 @@ function test_cases() [true, 1], none, ), + Testcase( + "nested with args (static)", + nothing, + (static_nested_outer_args,), + nothing, + [:a, :b, false], + none, + ), + Testcase( + "nested with args (static + used)", + nothing, + (static_nested_outer_use_produced_args,), + nothing, + [:a, :b, 1], + none, + ), + Testcase( + "nested with args (dynamic)", + nothing, + (dynamic_nested_outer_args, Ref{Any}(nested_inner_args)), + nothing, + [:a, :b, false], + none, + ), + Testcase( + "nested with args (dynamic + used)", + nothing, + (dynamic_nested_outer_use_produced_args, Ref{Any}(nested_inner_args)), + nothing, + [:a, :b, 1], + none, + ), Testcase( "callable struct", nothing, (CallableStruct(5), 4), nothing, [5, 4, 9], allocs ), @@ -334,6 +366,40 @@ function dynamic_nested_outer_use_produced(f::Ref{Any}) return nothing end +@noinline function nested_inner_args(xs...) + for x in xs + produce(x) + end + return 1 +end + +Libtask.might_produce(::Type{<:Tuple{typeof(nested_inner_args),Any}}) = true +Libtask.might_produce(::Type{<:Tuple{typeof(nested_inner_args),Any,Vararg}}) = true + +function static_nested_outer_args() + nested_inner_args(:a, :b) + produce(false) + return nothing +end + +function static_nested_outer_use_produced_args() + y = nested_inner_args(:a, :b) + produce(y) + return nothing +end + +function dynamic_nested_outer_args(f::Ref{Any}) + f[](:a, :b) + produce(false) + return nothing +end + +function dynamic_nested_outer_use_produced_args(f::Ref{Any}) + y = f[](:a, :b) + produce(y) + return nothing +end + struct CallableStruct{T} x::T end