Skip to content

Commit

Permalink
effects: complements #43852, implement effect override mechanisms
Browse files Browse the repository at this point in the history
The PR #43852 missed to implement the mechanism to override analyzed
effects with effect settings annotated by `Base.@assume_effects`.
This commits adds such an mechanism within `finish(::InferenceState, ::AbstractInterpreter)`,
just after inference analyzed frame effect.

Now we can do something like:
```julia
Base.@assume_effects :consistent :effect_free :terminates_globally consteval(
    f, args...; kwargs...) = f(args...; kwargs...)
const ___CONST_DICT___ = Dict{Any,Any}(:a => 1, :b => 2)
@test fully_eliminated() do
    consteval(getindex, ___CONST_DICT___, :a)
end
```
  • Loading branch information
aviatesk committed Mar 14, 2022
1 parent 98b4b06 commit f894fba
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 32 deletions.
7 changes: 0 additions & 7 deletions base/compiler/abstractinterpretation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -620,13 +620,6 @@ function abstract_call_method(interp::AbstractInterpreter, method::Method, @nosp
return MethodCallResult(rt, edgecycle, edgelimited, edge, edge_effects)
end

is_effect_overrided(sv::InferenceState, effect::Symbol) = is_effect_overrided(sv.linfo, effect)
function is_effect_overrided(linfo::MethodInstance, effect::Symbol)
def = linfo.def
return isa(def, Method) && is_effect_overrided(def, effect)
end
is_effect_overrided(method::Method, effect::Symbol) = getfield(decode_effects_override(method.purity), effect)

# keeps result and context information of abstract method call, will be used by succeeding constant-propagation
struct MethodCallResult
rt
Expand Down
15 changes: 15 additions & 0 deletions base/compiler/inferencestate.jl
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,23 @@ mutable struct InferenceState
return frame
end
end

Effects(state::InferenceState) = state.ipo_effects

function tristate_merge!(caller::InferenceState, effects::Effects)
caller.ipo_effects = tristate_merge(caller.ipo_effects, effects)
end
tristate_merge!(caller::InferenceState, callee::InferenceState) =
tristate_merge!(caller, Effects(callee))

is_effect_overrided(sv::InferenceState, effect::Symbol) = is_effect_overrided(sv.linfo, effect)
function is_effect_overrided(linfo::MethodInstance, effect::Symbol)
def = linfo.def
return isa(def, Method) && is_effect_overrided(def, effect)
end
is_effect_overrided(method::Method, effect::Symbol) = is_effect_overrided(decode_effects_override(method.purity), effect)
is_effect_overrided(override::EffectsOverride, effect::Symbol) = getfield(override, effect)

function any_inbounds(code::Vector{Any})
for i=1:length(code)
stmt = code[i]
Expand Down
28 changes: 19 additions & 9 deletions base/compiler/typeinfer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -494,7 +494,25 @@ function finish(me::InferenceState, interp::AbstractInterpreter)
end
me.result.valid_worlds = me.valid_worlds
me.result.result = me.bestguess
me.result.ipo_effects = rt_adjust_effects(me.bestguess, me.ipo_effects)
ipo_effects = rt_adjust_effects(me.bestguess, me.ipo_effects)
# override the analyzed effects using manually annotated effect settings
def = me.linfo.def
if isa(def, Method)
override = decode_effects_override(def.purity)
if is_effect_overrided(override, :consistent)
ipo_effects = Effects(ipo_effects; consistent=ALWAYS_TRUE)
end
if is_effect_overrided(override, :effect_free)
ipo_effects = Effects(ipo_effects; effect_free=ALWAYS_TRUE)
end
if is_effect_overrided(override, :nothrow)
ipo_effects = Effects(ipo_effects; nothrow=ALWAYS_TRUE)
end
if is_effect_overrided(override, :terminates_globally)
ipo_effects = Effects(ipo_effects; terminates=ALWAYS_TRUE)
end
end
me.result.ipo_effects = ipo_effects
validate_code_in_debug_mode(me.linfo, me.src, "inferred")
nothing
end
Expand Down Expand Up @@ -797,14 +815,6 @@ end

generating_sysimg() = ccall(:jl_generating_output, Cint, ()) != 0 && JLOptions().incremental == 0

function tristate_merge!(caller::InferenceState, callee::Effects)
caller.ipo_effects = tristate_merge(caller.ipo_effects, callee)
end

function tristate_merge!(caller::InferenceState, callee::InferenceState)
tristate_merge!(caller, Effects(callee))
end

ipo_effects(code::CodeInstance) = decode_effects(code.ipo_purity_bits)

# compute (and cache) an inferred AST and return the current best estimate of the result type
Expand Down
60 changes: 44 additions & 16 deletions base/compiler/types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,33 @@ struct Effects
# :consistent before caching. We may want to track it in the future.
inbounds_taints_consistency::Bool
end
Effects(consistent::TriState, effect_free::TriState, nothrow::TriState, terminates::TriState) =
Effects(consistent, effect_free, nothrow, terminates, false)
function Effects(
consistent::TriState,
effect_free::TriState,
nothrow::TriState,
terminates::TriState)
return Effects(
consistent,
effect_free,
nothrow,
terminates,
false)
end
Effects() = Effects(TRISTATE_UNKNOWN, TRISTATE_UNKNOWN, TRISTATE_UNKNOWN, TRISTATE_UNKNOWN)

Effects(e::Effects; consistent::TriState=e.consistent,
effect_free::TriState = e.effect_free, nothrow::TriState=e.nothrow, terminates::TriState=e.terminates,
inbounds_taints_consistency::Bool = e.inbounds_taints_consistency) =
Effects(consistent, effect_free, nothrow, terminates, inbounds_taints_consistency)
function Effects(e::Effects;
consistent::TriState = e.consistent,
effect_free::TriState = e.effect_free,
nothrow::TriState = e.nothrow,
terminates::TriState = e.terminates,
inbounds_taints_consistency::Bool = e.inbounds_taints_consistency)
return Effects(
consistent,
effect_free,
nothrow,
terminates,
inbounds_taints_consistency)
end

is_total_or_error(effects::Effects) =
effects.consistent === ALWAYS_TRUE && effects.effect_free === ALWAYS_TRUE &&
Expand All @@ -65,24 +84,32 @@ is_removable_if_unused(effects::Effects) =

const EFFECTS_TOTAL = Effects(ALWAYS_TRUE, ALWAYS_TRUE, ALWAYS_TRUE, ALWAYS_TRUE)

encode_effects(e::Effects) = e.consistent.state | (e.effect_free.state << 2) | (e.nothrow.state << 4) | (e.terminates.state << 6)
decode_effects(e::UInt8) =
Effects(TriState(e & 0x3),
function encode_effects(e::Effects)
return e.consistent.state |
(e.effect_free.state << 2) |
(e.nothrow.state << 4) |
(e.terminates.state << 6)
end
function decode_effects(e::UInt8)
return Effects(
TriState(e & 0x3),
TriState((e >> 2) & 0x3),
TriState((e >> 4) & 0x3),
TriState((e >> 6) & 0x3), false)
TriState((e >> 6) & 0x3),
false)
end

function tristate_merge(old::Effects, new::Effects)
Effects(tristate_merge(
return Effects(
tristate_merge(
old.consistent, new.consistent),
tristate_merge(
old.effect_free, new.effect_free),
tristate_merge(
old.nothrow, new.nothrow),
tristate_merge(
old.terminates, new.terminates),
old.inbounds_taints_consistency ||
new.inbounds_taints_consistency)
old.inbounds_taints_consistency | new.inbounds_taints_consistency)
end

struct EffectsOverride
Expand All @@ -100,16 +127,17 @@ function encode_effects_override(eo::EffectsOverride)
eo.nothrow && (e |= 0x04)
eo.terminates_globally && (e |= 0x08)
eo.terminates_locally && (e |= 0x10)
e
return e
end

decode_effects_override(e::UInt8) =
EffectsOverride(
function decode_effects_override(e::UInt8)
return EffectsOverride(
(e & 0x01) != 0x00,
(e & 0x02) != 0x00,
(e & 0x04) != 0x00,
(e & 0x08) != 0x00,
(e & 0x10) != 0x00)
end

"""
InferenceResult
Expand Down
7 changes: 7 additions & 0 deletions test/compiler/inline.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1088,6 +1088,13 @@ recur_termination22(x) = x * recur_termination21(x-1)
recur_termination21(12) + recur_termination22(12)
end

const ___CONST_DICT___ = Dict{Any,Any}(:a => 1, :b => 2)
Base.@assume_effects :consistent :effect_free :terminates_globally consteval(
f, args...; kwargs...) = f(args...; kwargs...)
@test fully_eliminated() do
consteval(getindex, ___CONST_DICT___, :a)
end

global x44200::Int = 0
function f44200()
global x = 0
Expand Down

0 comments on commit f894fba

Please sign in to comment.