Skip to content

Commit 01e0894

Browse files
committed
fix the optimizer's use of cached varargs type info for _apply unrolling
1 parent 70bd2c2 commit 01e0894

File tree

1 file changed

+43
-47
lines changed

1 file changed

+43
-47
lines changed

base/compiler/ssair/inlining.jl

Lines changed: 43 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -557,22 +557,43 @@ function spec_lambda(@nospecialize(atype), sv::OptimizationState, @nospecialize(
557557
linfo
558558
end
559559

560-
function rewrite_apply_exprargs!(ir::IRCode, idx::Int, argexprs::Vector{Any}, sv::OptimizationState)
560+
function rewrite_apply_exprargs!(ir::IRCode, idx::Int, argexprs::Vector{Any}, atypes::Vector{Any}, sv::OptimizationState)
561561
new_argexprs = Any[argexprs[2]]
562-
# Flatten all tuples
563-
for arg in argexprs[3:end]
564-
tupT = argextype(arg, ir, sv.sp)
565-
t = widenconst(tupT)
566-
for i = 1:length(t.parameters)
567-
# Insert a getfield call here
568-
new_call = Expr(:call, Core.getfield, arg, i)
569-
typ = getfield_tfunc(tupT, Const(i))
570-
new_arg = insert_node!(ir, idx, typ, new_call)
571-
push!(new_argexprs, new_arg)
562+
new_atypes = Any[atypes[2]]
563+
# loop over original arguments and flatten any known iterators
564+
for i in 3:length(argexprs)
565+
def = argexprs[i]
566+
# As a special case, if we can see the tuple() call, look at it's arguments to find
567+
# our types. They can be more precise (e.g. f(Bool, A...) would be lowered as
568+
# _apply(f, tuple(Bool)::Tuple{DataType}, A), which might not be precise enough to
569+
# get a good method match). This pattern is used in the array code a bunch.
570+
if isa(def, SSAValue) && is_tuple_call(ir, ir[def])
571+
def_args = ir[def].args
572+
def_atypes = Any[argextype(def_args[i], ir, sv.sp) for i in 2:length(def_args)]
573+
elseif isa(def, Argument) && def.n === length(ir.argtypes) && !isempty(sv.result_vargs)
574+
def_atypes = sv.result_vargs
575+
else
576+
def_atypes = Any[]
577+
for p in widenconst(atypes[i]).parameters
578+
if isa(p, DataType) && isdefined(p, :instance)
579+
# replace singleton types with their equivalent Const object
580+
p = Const(p.instance)
581+
elseif isconstType(p)
582+
p = Const(p.parameters[1])
583+
end
584+
push!(def_atypes, p)
585+
end
586+
end
587+
# now push flattened types into new_atypes and getfield exprs into new_argexprs
588+
for j in 1:length(def_atypes)
589+
def_atype = def_atypes[j]
590+
new_call = Expr(:call, Core.getfield, def, j)
591+
new_argexpr = insert_node!(ir, idx, def_atype, new_call)
592+
push!(new_argexprs, new_argexpr)
593+
push!(new_atypes, def_atype)
572594
end
573595
end
574-
argexprs = new_argexprs
575-
return argexprs
596+
return new_argexprs, new_atypes
576597
end
577598

578599
function rewrite_invoke_exprargs!(inserter, argexprs::Vector{Any})
@@ -780,52 +801,27 @@ function assemble_inline_todo!(ir::IRCode, linetable::Vector{LineInfoNode}, sv::
780801
isapply = isinvoke = false
781802

782803
# Handle _apply
783-
isapply = false
784804
if f === Core._apply
785-
new_atypes = Any[]
786-
ft = argextype(stmt.args[2], ir, sv.sp)
805+
ft = atypes[2]
787806
has_free_typevars(ft) && continue
788807
f = singleton_type(ft)
789-
# Push function type
790-
push!(new_atypes, ft)
791808
# Try to figure out the signature of the function being called
809+
# and if rewrite_apply_exprargs can deal with this form
792810
ok = true
793-
for (typ, def) in zip(atypes[3:end], stmt.args[3:end])
794-
typ = widenconst(typ)
795-
# We don't know what'll be in a SimpleVector, bail out
796-
isa(typ, SimpleVector) && (ok = false; break)
811+
for i = 3:length(atypes)
812+
typ = widenconst(atypes[i])
797813
# TODO: We could basically run the iteration protocol here
798-
if !isa(typ, DataType) || typ.name !== Tuple.name || isvatuple(typ)
814+
if !isa(typ, DataType) || typ.name !== Tuple.name ||
815+
isvatuple(typ) || length(typ.parameters) > sv.params.MAX_TUPLE_SPLAT
799816
ok = false
800817
break
801818
end
802-
if length(typ.parameters) > sv.params.MAX_TUPLE_SPLAT
803-
ok = false
804-
break
805-
end
806-
# As a special case, if we can see the tuple() call, look at it's arguments to find
807-
# our types. They can be more precise (e.g. f(Bool, A...) would be lowered as
808-
# _apply(f, tuple(Bool)::Tuple{DataType}, A), which might not be precise enough to
809-
# get a good method match). This pattern is used in the array code a bunch.
810-
if isa(def, SSAValue) && is_tuple_call(ir, ir[def])
811-
for tuparg in ir[def].args[2:end]
812-
push!(new_atypes, argextype(tuparg, ir, sv.sp))
813-
end
814-
elseif isa(def, Argument) && def.n === length(ir.argtypes) && !isempty(sv.result_vargs)
815-
append!(new_atypes, sv.result_vargs)
816-
else
817-
append!(new_atypes, typ.parameters)
818-
end
819819
end
820820
ok || continue
821-
atypes = new_atypes
822821
isapply = true
823-
end
824-
825-
# Independent of whether we can inline, the above analysis allows us to rewrite
826-
# this apply call to a regular call
827-
if isapply
828-
stmt.args = rewrite_apply_exprargs!(ir, idx, stmt.args, sv)
822+
# Independent of whether we can inline, the above analysis allows us to rewrite
823+
# this apply call to a regular call
824+
stmt.args, atypes = rewrite_apply_exprargs!(ir, idx, stmt.args, atypes, sv)
829825
end
830826

831827
if f !== Core.invoke && (isa(f, IntrinsicFunction) || ft IntrinsicFunction || isa(f, Builtin) || ft Builtin)

0 commit comments

Comments
 (0)