Skip to content

Commit

Permalink
inference: attach "Const.actual" flag to call instead of result type (#…
Browse files Browse the repository at this point in the history
…37333)

It was not a property of the type-lattice but of the call, so it was a
bit odd to track in this type (since it should not propagate). Instead,
we can attach this to the stmt_info field now, where inlining will find
it when needed.
  • Loading branch information
vtjnash authored Sep 3, 2020
1 parent a9743d8 commit 5c3557e
Show file tree
Hide file tree
Showing 10 changed files with 26 additions and 21 deletions.
3 changes: 1 addition & 2 deletions base/boot.jl
Original file line number Diff line number Diff line change
Expand Up @@ -404,8 +404,7 @@ eval(Core, :(CodeInstance(mi::MethodInstance, @nospecialize(rettype), @nospecial
min_world::UInt, max_world::UInt) =
ccall(:jl_new_codeinst, Ref{CodeInstance}, (Any, Any, Any, Any, Int32, UInt, UInt),
mi, rettype, inferred_const, inferred, const_flags, min_world, max_world)))
eval(Core, :(Const(@nospecialize(v)) = $(Expr(:new, :Const, :v, false))))
eval(Core, :(Const(@nospecialize(v), actual::Bool) = $(Expr(:new, :Const, :v, :actual))))
eval(Core, :(Const(@nospecialize(v)) = $(Expr(:new, :Const, :v))))
eval(Core, :(PartialStruct(@nospecialize(typ), fields::Array{Any, 1}) = $(Expr(:new, :PartialStruct, :typ, :fields))))
eval(Core, :(MethodMatch(@nospecialize(spec_types), sparams::SimpleVector, method::Method, fully_covers::Bool) =
$(Expr(:new, :MethodMatch, :spec_types, :sparams, :method, :fully_covers))))
Expand Down
10 changes: 4 additions & 6 deletions base/compiler/abstractinterpretation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
if f !== nothing && napplicable == 1 && is_method_pure(applicable[1]::MethodMatch)
val = pure_eval_call(f, argtypes)
if val !== false
return CallMeta(val, info)
# TODO: add some sort of edge(s)
return CallMeta(val, MethodResultPure())
end
end

Expand Down Expand Up @@ -749,8 +750,7 @@ function pure_eval_call(@nospecialize(f), argtypes::Vector{Any})
args = Any[ (a = widenconditional(argtypes[i]); isa(a, Const) ? a.val : a.parameters[1]) for i in 2:length(argtypes) ]
try
value = Core._apply_pure(f, args)
# TODO: add some sort of edge(s)
return Const(value, true)
return Const(value)
catch
return false
end
Expand Down Expand Up @@ -997,7 +997,7 @@ function abstract_call_known(interp::AbstractInterpreter, @nospecialize(f),
max_methods = 1
elseif la == 3 && istopfunction(f, :typejoin)
val = pure_eval_call(f, argtypes)
return CallMeta(val === false ? Type : val, false)
return CallMeta(val === false ? Type : val, MethodResultPure())
end
atype = argtypes_to_type(argtypes)
return abstract_call_gf_by_type(interp, f, argtypes, atype, sv, max_methods)
Expand Down Expand Up @@ -1330,8 +1330,6 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
# only propagate information we know we can store
# and is valid inter-procedurally
rt = widenconst(rt)
elseif isa(rt, Const) && rt.actual
rt = Const(rt.val)
end
if tchanged(rt, frame.bestguess)
# new (wider) return type for frame
Expand Down
9 changes: 5 additions & 4 deletions base/compiler/ssair/inlining.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1142,10 +1142,11 @@ function assemble_inline_todo!(ir::IRCode, sv::OptimizationState)
(sig, invoke_data) = r

# Check whether this call was @pure and evaluates to a constant
if isa(sig.f, widenconst(sig.ft)) &&
isa(calltype, Const) && calltype.actual && is_inlineable_constant(calltype.val)
ir.stmts[idx][:inst] = quoted(calltype.val)
continue
if calltype isa Const && info isa MethodResultPure
if is_inlineable_constant(calltype.val)
ir.stmts[idx][:inst] = quoted(calltype.val)
continue
end
end

# Ok, now figure out what method to call
Expand Down
10 changes: 10 additions & 0 deletions base/compiler/stmtinfo.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,16 @@ struct MethodMatchInfo
results::Union{Missing, MethodLookupResult}
end

"""
struct MethodResultPure
This singleton represents a method result constant was proven to be
effect-free, including being no-throw (typically because the value was computed
by calling an `@pure` function).
"""
struct MethodResultPure end


"""
struct UnionSplitInfo
Expand Down
3 changes: 0 additions & 3 deletions base/compiler/typelattice.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@
# # The type of a value might be constant
# struct Const
# val
# actual::Bool # if true, we obtained `val` by actually calling a @pure function
# Const(@nospecialize(v)) = new(v, false)
# Const(@nospecialize(v), a::Bool) = new(v, a)
# end
#
# struct PartialStruct
Expand Down
2 changes: 1 addition & 1 deletion doc/src/devdocs/ssair.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ The corresponding IR (with irrelevant types stripped) is:
└── $(Expr(:unreachable))::Union{}
4 ┄ %13 = φᶜ (%3, %6, %9)::Bool
│ %14 = φᶜ (%4, %7, %10)::Core.Compiler.MaybeUndef(Int64)
│ %15 = φᶜ (%5)::Core.Const(1, false)
│ %15 = φᶜ (%5)::Core.Const(1)
└── $(Expr(:leave, 1))
5 ─ $(Expr(:pop_exception, :(%2)))::Any
│ $(Expr(:throw_undef_if_not, :y, :(%13)))::Any
Expand Down
2 changes: 1 addition & 1 deletion doc/src/manual/performance-tips.md
Original file line number Diff line number Diff line change
Expand Up @@ -1436,7 +1436,7 @@ julia> function f(x)
julia> @code_warntype f(3.2)
Variables
#self#::Core.Const(f, false)
#self#::Core.Const(f)
x::Float64
y::UNION{FLOAT64, INT64}
Expand Down
4 changes: 2 additions & 2 deletions src/jltypes.c
Original file line number Diff line number Diff line change
Expand Up @@ -2381,8 +2381,8 @@ void jl_init_types(void) JL_GC_DISABLED
jl_svecset(jl_code_instance_type->types, 1, jl_code_instance_type);

jl_const_type = jl_new_datatype(jl_symbol("Const"), core, jl_any_type, jl_emptysvec,
jl_perm_symsvec(2, "val", "actual"),
jl_svec2(jl_any_type, jl_bool_type), 0, 0, 2);
jl_perm_symsvec(1, "val"),
jl_svec1(jl_any_type), 0, 0, 1);

jl_partial_struct_type = jl_new_datatype(jl_symbol("PartialStruct"), core, jl_any_type, jl_emptysvec,
jl_perm_symsvec(2, "typ", "fields"),
Expand Down
2 changes: 1 addition & 1 deletion stdlib/Test/src/Test.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1320,7 +1320,7 @@ Int64
julia> @code_warntype f(2)
Variables
#self#::Core.Const(f, false)
#self#::Core.Const(f)
a::Int64
Body::UNION{FLOAT64, INT64}
Expand Down
2 changes: 1 addition & 1 deletion test/compiler/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1416,7 +1416,7 @@ using Core.Compiler: PartialStruct, nfields_tfunc, sizeof_tfunc, sizeof_nothrow
@test sizeof_nothrow(String)
@test !sizeof_nothrow(Type{String})
@test sizeof_tfunc(Type{Union{Int64, Int32}}) == Const(Core.sizeof(Union{Int64, Int32}))
let PT = PartialStruct(Tuple{Int64,UInt64}, Any[Const(10, false), UInt64])
let PT = PartialStruct(Tuple{Int64,UInt64}, Any[Const(10), UInt64])
@test sizeof_tfunc(PT) === Const(16)
@test nfields_tfunc(PT) === Const(2)
@test sizeof_nothrow(PT)
Expand Down

0 comments on commit 5c3557e

Please sign in to comment.