@@ -158,6 +158,19 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
158
158
sv. ssavalue_uses[sv. currpc] = saved_uses
159
159
end
160
160
end
161
+ this_argtypes = isa (matches, MethodMatches) ? argtypes : matches. applicable_argtypes[i]
162
+ this_arginfo = ArgInfo (fargs, this_argtypes)
163
+
164
+ early_const_call_result = abstract_call_method_with_const_args_early (interp,
165
+ f, match, this_arginfo, sv)
166
+ if early_const_call_result != = nothing
167
+ this_conditional = this_rt = early_const_call_result. rt
168
+ (; effects, const_result) = early_const_call_result
169
+ tristate_merge! (sv, effects)
170
+ push! (const_results, const_result)
171
+ any_const_result = true
172
+ @goto call_computed
173
+ end
161
174
162
175
result = abstract_call_method (interp, method, sig, match. sparams, multiple_matches, sv)
163
176
this_conditional = ignorelimited (result. rt)
@@ -166,8 +179,6 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
166
179
edge != = nothing && push! (edges, edge)
167
180
# try constant propagation with argtypes for this match
168
181
# this is in preparation for inlining, or improving the return result
169
- this_argtypes = isa (matches, MethodMatches) ? argtypes : matches. applicable_argtypes[i]
170
- this_arginfo = ArgInfo (fargs, this_argtypes)
171
182
const_call_result = abstract_call_method_with_const_args (interp, result,
172
183
f, this_arginfo, match, sv)
173
184
effects = result. edge_effects
@@ -187,6 +198,7 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
187
198
push! (const_results, const_result)
188
199
any_const_result |= const_result != = nothing
189
200
end
201
+ @label call_computed
190
202
@assert ! (this_conditional isa Conditional) " invalid lattice element returned from inter-procedural context"
191
203
seen += 1
192
204
rettype = tmerge (rettype, this_rt)
@@ -682,10 +694,11 @@ end
682
694
function pure_eval_eligible (interp:: AbstractInterpreter ,
683
695
@nospecialize (f), applicable:: Vector{Any} , arginfo:: ArgInfo , sv:: InferenceState )
684
696
# XXX we need to check that this pure function doesn't call any overlayed method
685
- return f != = nothing &&
686
- length (applicable) == 1 &&
687
- is_method_pure (applicable[1 ]:: MethodMatch ) &&
688
- is_all_const_arg (arginfo)
697
+ f != = nothing || return false
698
+ length (applicable) == 1 || return false
699
+ match = applicable[1 ]:: MethodMatch
700
+ is_method_pure (match) || return false
701
+ return is_all_const_arg (arginfo)
689
702
end
690
703
691
704
function is_method_pure (method:: Method , @nospecialize (sig), sparams:: SimpleVector )
@@ -718,16 +731,17 @@ end
718
731
719
732
function concrete_eval_eligible (interp:: AbstractInterpreter ,
720
733
@nospecialize (f), result:: MethodCallResult , arginfo:: ArgInfo , sv:: InferenceState )
721
- # disable concrete-evaluation since this function call is tainted by some overlayed
722
- # method and currently there is no direct way to execute overlayed methods
734
+ # disable concrete-evaluation if this function call is tainted by some overlayed
735
+ # method since currently there is no direct way to execute overlayed methods
723
736
isoverlayed (method_table (interp)) && ! is_nonoverlayed (result. edge_effects) && return false
724
- return f != = nothing &&
725
- result. edge != = nothing &&
726
- is_concrete_eval_eligible (result. edge_effects) &&
727
- is_all_const_arg (arginfo)
737
+ f != = nothing || return false
738
+ result. edge != = nothing || return false
739
+ is_concrete_eval_eligible (result. edge_effects) || return false
740
+ return is_all_const_arg (arginfo)
728
741
end
729
742
730
- function is_all_const_arg ((; argtypes):: ArgInfo )
743
+ is_all_const_arg ((; argtypes):: ArgInfo ) = is_all_const_arg (argtypes)
744
+ function is_all_const_arg (argtypes:: Vector{Any} )
731
745
for i = 2 : length (argtypes)
732
746
a = widenconditional (argtypes[i])
733
747
isa (a, Const) || isconstType (a) || issingletontype (a) || return false
@@ -746,26 +760,61 @@ end
746
760
function concrete_eval_call (interp:: AbstractInterpreter ,
747
761
@nospecialize (f), result:: MethodCallResult , arginfo:: ArgInfo , sv:: InferenceState )
748
762
concrete_eval_eligible (interp, f, result, arginfo, sv) || return nothing
763
+ return _concrete_eval_call (interp, f, arginfo, result. edge, sv)
764
+ end
765
+
766
+ function _concrete_eval_call (interp:: AbstractInterpreter ,
767
+ @nospecialize (f), arginfo:: ArgInfo , edge:: MethodInstance , sv:: InferenceState )
749
768
args = collect_const_args (arginfo)
750
769
world = get_world_counter (interp)
751
770
value = try
752
771
Core. _call_in_world_total (world, f, args... )
753
772
catch
754
773
# The evaulation threw. By :consistent-cy, we're guaranteed this would have happened at runtime
755
- return ConstCallResults (Union{}, ConcreteResult (result . edge, result . edge_effects ), result . edge_effects )
774
+ return ConstCallResults (Union{}, ConcreteResult (edge, EFFECTS_THROWS ), EFFECTS_THROWS )
756
775
end
757
776
if is_inlineable_constant (value) || call_result_unused (sv)
758
777
# If the constant is not inlineable, still do the const-prop, since the
759
778
# code that led to the creation of the Const may be inlineable in the same
760
779
# circumstance and may be optimizable.
761
- return ConstCallResults (Const (value), ConcreteResult (result . edge, EFFECTS_TOTAL, value), EFFECTS_TOTAL)
780
+ return ConstCallResults (Const (value), ConcreteResult (edge, EFFECTS_TOTAL, value), EFFECTS_TOTAL)
762
781
end
763
782
return nothing
764
783
end
765
784
785
+ function early_concrete_eval_eligible (interp:: AbstractInterpreter ,
786
+ @nospecialize (f), match:: MethodMatch , arginfo:: ArgInfo , sv:: InferenceState )
787
+ # the effects for this match may not be derived yet, so disable concrete-evaluation
788
+ # immediately when the interpreter can use overlayed methods
789
+ isoverlayed (method_table (interp)) && return false
790
+ f != = nothing || return false
791
+ is_concrete_eval_eligible (decode_effects_override (match. method. purity)) || return false
792
+ return is_all_const_arg (arginfo)
793
+ end
794
+
795
+ function early_concrete_eval (interp:: AbstractInterpreter ,
796
+ @nospecialize (f), match:: MethodMatch , arginfo:: ArgInfo , sv:: InferenceState )
797
+ early_concrete_eval_eligible (interp, f, match, arginfo, sv) || return nothing
798
+ edge = specialize_method (match. method, match. spec_types, match. sparams)
799
+ edge === nothing && return nothing
800
+ return _concrete_eval_call (interp, f, arginfo, edge, sv)
801
+ end
802
+
803
+ function abstract_call_method_with_const_args_early (interp:: AbstractInterpreter ,
804
+ @nospecialize (f), match:: MethodMatch , arginfo:: ArgInfo , sv:: InferenceState )
805
+ const_prop_enabled (interp, sv, match) || return nothing
806
+ val = early_concrete_eval (interp, f, match, arginfo, sv)
807
+ if val != = nothing
808
+ add_backedge! (val. const_result. mi, sv)
809
+ return val
810
+ end
811
+ # TODO early constant prop' for `@nospecialize`d methods?
812
+ return nothing
813
+ end
814
+
766
815
function const_prop_enabled (interp:: AbstractInterpreter , sv:: InferenceState , match:: MethodMatch )
767
816
if ! InferenceParams (interp). ipo_constant_propagation
768
- add_remark! (interp, sv, " [constprop] Disabled by parameter" )
817
+ add_remark! (interp, sv, " [constprop] Disabled by inference parameter" )
769
818
return false
770
819
end
771
820
method = match. method
@@ -789,12 +838,10 @@ end
789
838
function abstract_call_method_with_const_args (interp:: AbstractInterpreter , result:: MethodCallResult ,
790
839
@nospecialize (f), arginfo:: ArgInfo , match:: MethodMatch ,
791
840
sv:: InferenceState )
792
- if ! const_prop_enabled (interp, sv, match)
793
- return nothing
794
- end
841
+ const_prop_enabled (interp, sv, match) || return nothing
795
842
val = concrete_eval_call (interp, f, result, arginfo, sv)
796
843
if val != = nothing
797
- add_backedge! (result . edge , sv)
844
+ add_backedge! (val . const_result . mi , sv)
798
845
return val
799
846
end
800
847
mi = maybe_get_const_prop_profitable (interp, result, f, arginfo, match, sv)
0 commit comments