diff --git a/base/boot.jl b/base/boot.jl index 099a9e863922e..e653a82399ba5 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -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)))) diff --git a/base/compiler/abstractinterpretation.jl b/base/compiler/abstractinterpretation.jl index 2a80316be6a99..8ede6fb53c04e 100644 --- a/base/compiler/abstractinterpretation.jl +++ b/base/compiler/abstractinterpretation.jl @@ -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 @@ -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 @@ -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) @@ -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 diff --git a/base/compiler/ssair/inlining.jl b/base/compiler/ssair/inlining.jl index c19627dea5794..2e7f3e3c9d685 100644 --- a/base/compiler/ssair/inlining.jl +++ b/base/compiler/ssair/inlining.jl @@ -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 diff --git a/base/compiler/stmtinfo.jl b/base/compiler/stmtinfo.jl index 9ba4dc30cca29..199eb405006be 100644 --- a/base/compiler/stmtinfo.jl +++ b/base/compiler/stmtinfo.jl @@ -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 diff --git a/base/compiler/typelattice.jl b/base/compiler/typelattice.jl index 69c0214570c83..17a444e840b77 100644 --- a/base/compiler/typelattice.jl +++ b/base/compiler/typelattice.jl @@ -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 diff --git a/doc/src/devdocs/ssair.md b/doc/src/devdocs/ssair.md index 9ec189c2c6afd..d0ad27b833301 100644 --- a/doc/src/devdocs/ssair.md +++ b/doc/src/devdocs/ssair.md @@ -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 diff --git a/doc/src/manual/performance-tips.md b/doc/src/manual/performance-tips.md index 9606d0e372a39..60a64df8ac854 100644 --- a/doc/src/manual/performance-tips.md +++ b/doc/src/manual/performance-tips.md @@ -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} diff --git a/src/jltypes.c b/src/jltypes.c index 59fa08ccb6f93..dd36776f1bac1 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -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"), diff --git a/stdlib/Test/src/Test.jl b/stdlib/Test/src/Test.jl index 36fdb1fb8a314..a590f4a2c25a1 100644 --- a/stdlib/Test/src/Test.jl +++ b/stdlib/Test/src/Test.jl @@ -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} diff --git a/test/compiler/inference.jl b/test/compiler/inference.jl index b2eb93c94a903..6ed0a4011b0b3 100644 --- a/test/compiler/inference.jl +++ b/test/compiler/inference.jl @@ -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)