@@ -557,22 +557,43 @@ function spec_lambda(@nospecialize(atype), sv::OptimizationState, @nospecialize(
557
557
linfo
558
558
end
559
559
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 )
561
561
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)
572
594
end
573
595
end
574
- argexprs = new_argexprs
575
- return argexprs
596
+ return new_argexprs, new_atypes
576
597
end
577
598
578
599
function rewrite_invoke_exprargs! (inserter, argexprs:: Vector{Any} )
@@ -780,52 +801,27 @@ function assemble_inline_todo!(ir::IRCode, linetable::Vector{LineInfoNode}, sv::
780
801
isapply = isinvoke = false
781
802
782
803
# Handle _apply
783
- isapply = false
784
804
if f === Core. _apply
785
- new_atypes = Any[]
786
- ft = argextype (stmt. args[2 ], ir, sv. sp)
805
+ ft = atypes[2 ]
787
806
has_free_typevars (ft) && continue
788
807
f = singleton_type (ft)
789
- # Push function type
790
- push! (new_atypes, ft)
791
808
# Try to figure out the signature of the function being called
809
+ # and if rewrite_apply_exprargs can deal with this form
792
810
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])
797
813
# 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
799
816
ok = false
800
817
break
801
818
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
819
819
end
820
820
ok || continue
821
- atypes = new_atypes
822
821
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)
829
825
end
830
826
831
827
if f != = Core. invoke && (isa (f, IntrinsicFunction) || ft ⊑ IntrinsicFunction || isa (f, Builtin) || ft ⊑ Builtin)
0 commit comments