Skip to content

Commit 113c2f3

Browse files
authored
Put back getfield :boundscheck hack (#48677)
We used to have this hack before #48246, but I removed it because I had hoped we don't need. Unfortunately, we weren't able to infer consistency of ``` @inbounds (1,2)[1] ``` With this hack, constprop is able to independently prove inbounded-ness, overriding the usual consistency taintaing that happens for inbounds.
1 parent afeda9f commit 113c2f3

File tree

2 files changed

+24
-2
lines changed

2 files changed

+24
-2
lines changed

base/compiler/abstractinterpretation.jl

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1974,6 +1974,14 @@ function abstract_call_known(interp::AbstractInterpreter, @nospecialize(f),
19741974
end
19751975
rt = abstract_call_builtin(interp, f, arginfo, sv, max_methods)
19761976
effects = builtin_effects(𝕃ᵢ, f, arginfo, rt)
1977+
if f === getfield && (fargs !== nothing && isexpr(fargs[end], :boundscheck)) && !is_nothrow(effects) && isa(sv, InferenceState)
1978+
# As a special case, we delayed tainting `noinbounds` for getfield calls in case we can prove
1979+
# in-boundedness indepedently. Here we need to put that back in other cases.
1980+
# N.B.: This isn't about the effects of the call itself, but a delayed contribution of the :boundscheck
1981+
# statement, so we need to merge this directly into sv, rather than modifying thte effects.
1982+
merge_effects!(interp, sv, Effects(EFFECTS_TOTAL; noinbounds=false,
1983+
consistent = (get_curr_ssaflag(sv) & IR_FLAG_INBOUNDS) != 0 ? ALWAYS_FALSE : ALWAYS_TRUE))
1984+
end
19771985
return CallMeta(rt, effects, NoCallInfo())
19781986
elseif isa(f, Core.OpaqueClosure)
19791987
# calling an OpaqueClosure about which we have no information returns no information
@@ -2195,6 +2203,15 @@ function abstract_eval_value_expr(interp::AbstractInterpreter, e::Expr, vtypes::
21952203
return rt
21962204
elseif head === :boundscheck
21972205
if isa(sv, InferenceState)
2206+
stmt = sv.src.code[sv.currpc]
2207+
if isexpr(stmt, :call)
2208+
f = abstract_eval_value(interp, stmt.args[1], vtypes, sv)
2209+
if f isa Const && f.val === getfield
2210+
# boundscheck of `getfield` call is analyzed by tfunc potentially without
2211+
# tainting :inbounds or :consistent when it's known to be nothrow
2212+
@goto delay_effects_analysis
2213+
end
2214+
end
21982215
# If there is no particular `@inbounds` for this function, then we only taint `:noinbounds`,
21992216
# which will subsequently taint `:consistent`-cy if this function is called from another
22002217
# function that uses `@inbounds`. However, if this `:boundscheck` is itself within an
@@ -2203,6 +2220,7 @@ function abstract_eval_value_expr(interp::AbstractInterpreter, e::Expr, vtypes::
22032220
merge_effects!(interp, sv, Effects(EFFECTS_TOTAL; noinbounds=false,
22042221
consistent = (get_curr_ssaflag(sv) & IR_FLAG_INBOUNDS) != 0 ? ALWAYS_FALSE : ALWAYS_TRUE))
22052222
end
2223+
@label delay_effects_analysis
22062224
rt = Bool
22072225
elseif head === :inbounds
22082226
@assert false && "Expected this to have been moved into flags"

test/compiler/effects.jl

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -739,15 +739,19 @@ end |> Core.Compiler.is_foldable_nothrow
739739

740740
# Test that dead `@inbounds` does not taint consistency
741741
# https://github.com/JuliaLang/julia/issues/48243
742-
@test Base.infer_effects() do
743-
false && @inbounds (1,2,3)[1]
742+
@test Base.infer_effects(Tuple{Int64}) do i
743+
false && @inbounds (1,2,3)[i]
744744
return 1
745745
end |> Core.Compiler.is_foldable_nothrow
746746

747747
@test Base.infer_effects(Tuple{Int64}) do i
748748
@inbounds (1,2,3)[i]
749749
end |> !Core.Compiler.is_consistent
750750

751+
@test Base.infer_effects(Tuple{Tuple{Int64}}) do x
752+
@inbounds x[1]
753+
end |> Core.Compiler.is_foldable_nothrow
754+
751755
# Test that :new of non-concrete, but otherwise known type
752756
# does not taint consistency.
753757
@eval struct ImmutRef{T}

0 commit comments

Comments
 (0)