Skip to content

Commit 30d5a34

Browse files
aviatesktopolarityoscardssmith
authored
inference: remove throw block deoptimization completely (#49260)
Co-authored-by: Cody Tapscott <topolarity@tapscott.me> Co-authored-by: Oscar Smith <oscardssmith@gmail.com>
1 parent f0a2a7a commit 30d5a34

File tree

10 files changed

+33
-96
lines changed

10 files changed

+33
-96
lines changed

base/compiler/abstractinterpretation.jl

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,6 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
4343
sv::AbsIntState, max_methods::Int)
4444
𝕃ₚ, 𝕃ᵢ = ipo_lattice(interp), typeinf_lattice(interp)
4545
ₚ, ₚ, = partialorder(𝕃ₚ), join(𝕃ₚ), join(𝕃ᵢ)
46-
if !should_infer_this_call(interp, sv)
47-
add_remark!(interp, sv, "Skipped call in throw block")
48-
# At this point we are guaranteed to end up throwing on this path,
49-
# which is all that's required for :consistent-cy. Of course, we don't
50-
# know anything else about this statement.
51-
effects = Effects(; consistent=ALWAYS_TRUE)
52-
return CallMeta(Any, Any, effects, NoCallInfo())
53-
end
54-
5546
argtypes = arginfo.argtypes
5647
matches = find_method_matches(interp, argtypes, atype; max_methods)
5748
if isa(matches, FailedMethodMatch)

base/compiler/compiler.jl

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,8 +184,7 @@ baremodule BuildSettings
184184
using Core: ARGS, include
185185
using Core.Compiler: >, getindex, length
186186

187-
MAX_METHODS::Int = 3
188-
UNOPTIMIZE_THROW_BLOCKS::Bool = true
187+
global MAX_METHODS::Int = 3
189188

190189
if length(ARGS) > 2 && ARGS[2] === "--buildsettings"
191190
include(BuildSettings, ARGS[3])

base/compiler/inferencestate.jl

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,6 @@ mutable struct InferenceState
348348
restrict_abstract_call_sites = isa(def, Module)
349349

350350
# some more setups
351-
InferenceParams(interp).unoptimize_throw_blocks && mark_throw_blocks!(src, handler_info)
352351
!iszero(cache_mode & CACHE_MODE_LOCAL) && push!(get_inference_cache(interp), result)
353352

354353
this = new(
@@ -1102,30 +1101,6 @@ bail_out_apply(::AbstractInterpreter, state::InferenceLoopState, ::InferenceStat
11021101
bail_out_apply(::AbstractInterpreter, state::InferenceLoopState, ::IRInterpretationState) =
11031102
state.rt === Any
11041103

1105-
function should_infer_this_call(interp::AbstractInterpreter, sv::InferenceState)
1106-
if InferenceParams(interp).unoptimize_throw_blocks
1107-
# Disable inference of calls in throw blocks, since we're unlikely to
1108-
# need their types. There is one exception however: If up until now, the
1109-
# function has not seen any side effects, we would like to make sure there
1110-
# aren't any in the throw block either to enable other optimizations.
1111-
if is_stmt_throw_block(get_curr_ssaflag(sv))
1112-
should_infer_for_effects(sv) || return false
1113-
end
1114-
end
1115-
return true
1116-
end
1117-
function should_infer_for_effects(sv::InferenceState)
1118-
def = sv.linfo.def
1119-
def isa Method || return false # toplevel frame will not be [semi-]concrete-evaluated
1120-
effects = sv.ipo_effects
1121-
override = decode_effects_override(def.purity)
1122-
effects.consistent === ALWAYS_FALSE && !is_effect_overridden(override, :consistent) && return false
1123-
effects.effect_free === ALWAYS_FALSE && !is_effect_overridden(override, :effect_free) && return false
1124-
!effects.terminates && !is_effect_overridden(override, :terminates_globally) && return false
1125-
return true
1126-
end
1127-
should_infer_this_call(::AbstractInterpreter, ::IRInterpretationState) = true
1128-
11291104
add_remark!(::AbstractInterpreter, ::InferenceState, remark) = return
11301105
add_remark!(::AbstractInterpreter, ::IRInterpretationState, remark) = return
11311106

base/compiler/optimize.jl

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23,31 +23,29 @@ const IR_FLAG_INBOUNDS = one(UInt32) << 0
2323
const IR_FLAG_INLINE = one(UInt32) << 1
2424
# This statement is marked as @noinline by user
2525
const IR_FLAG_NOINLINE = one(UInt32) << 2
26-
# This statement is on a code path that eventually `throw`s.
27-
const IR_FLAG_THROW_BLOCK = one(UInt32) << 3
2826
# An optimization pass has updated this statement in a way that may
2927
# have exposed information that inference did not see. Re-running
3028
# inference on this statement may be profitable.
31-
const IR_FLAG_REFINED = one(UInt32) << 4
29+
const IR_FLAG_REFINED = one(UInt32) << 3
3230
# This statement is proven :consistent
33-
const IR_FLAG_CONSISTENT = one(UInt32) << 5
31+
const IR_FLAG_CONSISTENT = one(UInt32) << 4
3432
# This statement is proven :effect_free
35-
const IR_FLAG_EFFECT_FREE = one(UInt32) << 6
33+
const IR_FLAG_EFFECT_FREE = one(UInt32) << 5
3634
# This statement is proven :nothrow
37-
const IR_FLAG_NOTHROW = one(UInt32) << 7
35+
const IR_FLAG_NOTHROW = one(UInt32) << 6
3836
# This statement is proven :terminates
39-
const IR_FLAG_TERMINATES = one(UInt32) << 8
37+
const IR_FLAG_TERMINATES = one(UInt32) << 7
4038
# This statement is proven :noub
41-
const IR_FLAG_NOUB = one(UInt32) << 9
39+
const IR_FLAG_NOUB = one(UInt32) << 8
4240
# TODO: Both of these should eventually go away once
4341
# This statement is :effect_free == EFFECT_FREE_IF_INACCESSIBLEMEMONLY
44-
const IR_FLAG_EFIIMO = one(UInt32) << 10
42+
const IR_FLAG_EFIIMO = one(UInt32) << 9
4543
# This statement is :inaccessiblememonly == INACCESSIBLEMEM_OR_ARGMEMONLY
46-
const IR_FLAG_INACCESSIBLEMEM_OR_ARGMEM = one(UInt32) << 11
44+
const IR_FLAG_INACCESSIBLEMEM_OR_ARGMEM = one(UInt32) << 10
4745
# This statement has no users and may be deleted if flags get refined to IR_FLAGS_REMOVABLE
48-
const IR_FLAG_UNUSED = one(UInt32) << 12
46+
const IR_FLAG_UNUSED = one(UInt32) << 11
4947

50-
const NUM_IR_FLAGS = 13 # sync with julia.h
48+
const NUM_IR_FLAGS = 12 # sync with julia.h
5149

5250
const IR_FLAGS_EFFECTS =
5351
IR_FLAG_CONSISTENT | IR_FLAG_EFFECT_FREE | IR_FLAG_NOTHROW | IR_FLAG_TERMINATES | IR_FLAG_NOUB
@@ -249,9 +247,8 @@ end
249247

250248
_topmod(sv::OptimizationState) = _topmod(sv.mod)
251249

252-
is_stmt_inline(stmt_flag::UInt32) = has_flag(stmt_flag, IR_FLAG_INLINE)
253-
is_stmt_noinline(stmt_flag::UInt32) = has_flag(stmt_flag, IR_FLAG_NOINLINE)
254-
is_stmt_throw_block(stmt_flag::UInt32) = has_flag(stmt_flag, IR_FLAG_THROW_BLOCK)
250+
is_stmt_inline(stmt_flag::UInt32) = has_flag(stmt_flag, IR_FLAG_INLINE)
251+
is_stmt_noinline(stmt_flag::UInt32) = has_flag(stmt_flag, IR_FLAG_NOINLINE)
255252

256253
function new_expr_effect_flags(𝕃ₒ::AbstractLattice, args::Vector{Any}, src::Union{IRCode,IncrementalCompact}, pattern_match=nothing)
257254
Targ = args[1]
@@ -1272,7 +1269,7 @@ plus_saturate(x::Int, y::Int) = max(x, y, x+y)
12721269
isknowntype(@nospecialize T) = (T === Union{}) || isa(T, Const) || isconcretetype(widenconst(T))
12731270

12741271
function statement_cost(ex::Expr, line::Int, src::Union{CodeInfo, IRCode}, sptypes::Vector{VarState},
1275-
params::OptimizationParams, error_path::Bool = false)
1272+
params::OptimizationParams)
12761273
#=const=# UNKNOWN_CALL_COST = 20
12771274
head = ex.head
12781275
if is_meta_expr_head(head)
@@ -1333,10 +1330,10 @@ function statement_cost(ex::Expr, line::Int, src::Union{CodeInfo, IRCode}, sptyp
13331330
return 0
13341331
elseif (f === Core.memoryrefget || f === Core.memoryref_isassigned) && length(ex.args) >= 3
13351332
atyp = argextype(ex.args[2], src, sptypes)
1336-
return isknowntype(atyp) ? 1 : error_path ? params.inline_error_path_cost : params.inline_nonleaf_penalty
1333+
return isknowntype(atyp) ? 1 : params.inline_nonleaf_penalty
13371334
elseif f === Core.memoryrefset! && length(ex.args) >= 3
13381335
atyp = argextype(ex.args[2], src, sptypes)
1339-
return isknowntype(atyp) ? 5 : error_path ? params.inline_error_path_cost : params.inline_nonleaf_penalty
1336+
return isknowntype(atyp) ? 5 : params.inline_nonleaf_penalty
13401337
elseif f === typeassert && isconstType(widenconst(argextype(ex.args[3], src, sptypes)))
13411338
return 1
13421339
end
@@ -1352,7 +1349,7 @@ function statement_cost(ex::Expr, line::Int, src::Union{CodeInfo, IRCode}, sptyp
13521349
if extyp === Union{}
13531350
return 0
13541351
end
1355-
return error_path ? params.inline_error_path_cost : params.inline_nonleaf_penalty
1352+
return params.inline_nonleaf_penalty
13561353
elseif head === :foreigncall
13571354
foreigncall = ex.args[1]
13581355
if foreigncall isa QuoteNode && foreigncall.value === :jl_string_ptr
@@ -1375,7 +1372,7 @@ function statement_cost(ex::Expr, line::Int, src::Union{CodeInfo, IRCode}, sptyp
13751372
end
13761373
a = ex.args[2]
13771374
if a isa Expr
1378-
cost = plus_saturate(cost, statement_cost(a, -1, src, sptypes, params, error_path))
1375+
cost = plus_saturate(cost, statement_cost(a, -1, src, sptypes, params))
13791376
end
13801377
return cost
13811378
elseif head === :copyast
@@ -1389,8 +1386,7 @@ function statement_or_branch_cost(@nospecialize(stmt), line::Int, src::Union{Cod
13891386
thiscost = 0
13901387
dst(tgt) = isa(src, IRCode) ? first(src.cfg.blocks[tgt].stmts) : tgt
13911388
if stmt isa Expr
1392-
thiscost = statement_cost(stmt, line, src, sptypes, params,
1393-
is_stmt_throw_block(isa(src, IRCode) ? src.stmts.flag[line] : src.ssaflags[line]))::Int
1389+
thiscost = statement_cost(stmt, line, src, sptypes, params)::Int
13941390
elseif stmt isa GotoNode
13951391
# loops are generally always expensive
13961392
# but assume that forward jumps are already counted for from

base/compiler/types.jl

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -156,11 +156,6 @@ Parameters that control abstract interpretation-based type inference operation.
156156
information available. [`Base.@constprop :aggressive`](@ref Base.@constprop) can have a
157157
more fine-grained control on this configuration with per-method annotation basis.
158158
---
159-
- `inf_params.unoptimize_throw_blocks::Bool = true`\\
160-
If `true`, skips inferring calls that are in a block that is known to `throw`.
161-
It may improve the compiler latency without sacrificing the runtime performance
162-
in common situations.
163-
---
164159
- `inf_params.assume_bindings_static::Bool = false`\\
165160
If `true`, assumes that no new bindings will be added, i.e. a non-existing binding at
166161
inference time can be assumed to always not exist at runtime (and thus e.g. any access to
@@ -176,7 +171,6 @@ struct InferenceParams
176171
tuple_complexity_limit_depth::Int
177172
ipo_constant_propagation::Bool
178173
aggressive_constant_propagation::Bool
179-
unoptimize_throw_blocks::Bool
180174
assume_bindings_static::Bool
181175
ignore_recursion_hardlimit::Bool
182176

@@ -188,7 +182,6 @@ struct InferenceParams
188182
tuple_complexity_limit_depth::Int,
189183
ipo_constant_propagation::Bool,
190184
aggressive_constant_propagation::Bool,
191-
unoptimize_throw_blocks::Bool,
192185
assume_bindings_static::Bool,
193186
ignore_recursion_hardlimit::Bool)
194187
return new(
@@ -199,7 +192,6 @@ struct InferenceParams
199192
tuple_complexity_limit_depth,
200193
ipo_constant_propagation,
201194
aggressive_constant_propagation,
202-
unoptimize_throw_blocks,
203195
assume_bindings_static,
204196
ignore_recursion_hardlimit)
205197
end
@@ -213,7 +205,6 @@ function InferenceParams(
213205
#=tuple_complexity_limit_depth::Int=# 3,
214206
#=ipo_constant_propagation::Bool=# true,
215207
#=aggressive_constant_propagation::Bool=# false,
216-
#=unoptimize_throw_blocks::Bool=# BuildSettings.UNOPTIMIZE_THROW_BLOCKS,
217208
#=assume_bindings_static::Bool=# false,
218209
#=ignore_recursion_hardlimit::Bool=# false);
219210
max_methods::Int = params.max_methods,
@@ -223,7 +214,6 @@ function InferenceParams(
223214
tuple_complexity_limit_depth::Int = params.tuple_complexity_limit_depth,
224215
ipo_constant_propagation::Bool = params.ipo_constant_propagation,
225216
aggressive_constant_propagation::Bool = params.aggressive_constant_propagation,
226-
unoptimize_throw_blocks::Bool = params.unoptimize_throw_blocks,
227217
assume_bindings_static::Bool = params.assume_bindings_static,
228218
ignore_recursion_hardlimit::Bool = params.ignore_recursion_hardlimit)
229219
return InferenceParams(
@@ -234,7 +224,6 @@ function InferenceParams(
234224
tuple_complexity_limit_depth,
235225
ipo_constant_propagation,
236226
aggressive_constant_propagation,
237-
unoptimize_throw_blocks,
238227
assume_bindings_static,
239228
ignore_recursion_hardlimit)
240229
end
@@ -259,10 +248,6 @@ Parameters that control optimizer operation.
259248
tuple return types (in hopes of splitting it up). `opt_params.inline_tupleret_bonus` will
260249
be added to `opt_params.inline_cost_threshold` when making inlining decision.
261250
---
262-
- `opt_params.inline_error_path_cost::Int = 20`\\
263-
Specifies the penalty cost for an un-optimized dynamic call in a block that is known to
264-
`throw`. See also [`(inf_params::InferenceParams).unoptimize_throw_blocks`](@ref InferenceParams).
265-
---
266251
- `opt_params.max_tuple_splat::Int = 32`\\
267252
When attempting to inline `Core._apply_iterate`, abort the optimization if the tuple
268253
contains more than this many elements.
@@ -289,7 +274,6 @@ struct OptimizationParams
289274
inline_cost_threshold::Int
290275
inline_nonleaf_penalty::Int
291276
inline_tupleret_bonus::Int
292-
inline_error_path_cost::Int
293277
max_tuple_splat::Int
294278
compilesig_invokes::Bool
295279
assume_fatal_throw::Bool
@@ -300,7 +284,6 @@ struct OptimizationParams
300284
inline_cost_threshold::Int,
301285
inline_nonleaf_penalty::Int,
302286
inline_tupleret_bonus::Int,
303-
inline_error_path_cost::Int,
304287
max_tuple_splat::Int,
305288
compilesig_invokes::Bool,
306289
assume_fatal_throw::Bool,
@@ -310,7 +293,6 @@ struct OptimizationParams
310293
inline_cost_threshold,
311294
inline_nonleaf_penalty,
312295
inline_tupleret_bonus,
313-
inline_error_path_cost,
314296
max_tuple_splat,
315297
compilesig_invokes,
316298
assume_fatal_throw,
@@ -323,7 +305,6 @@ function OptimizationParams(
323305
#=inline_cost_threshold::Int=# 100,
324306
#=inline_nonleaf_penalty::Int=# 1000,
325307
#=inline_tupleret_bonus::Int=# 250,
326-
#=inline_error_path_cost::Int=# 20,
327308
#=max_tuple_splat::Int=# 32,
328309
#=compilesig_invokes::Bool=# true,
329310
#=assume_fatal_throw::Bool=# false,
@@ -332,7 +313,6 @@ function OptimizationParams(
332313
inline_cost_threshold::Int = params.inline_cost_threshold,
333314
inline_nonleaf_penalty::Int = params.inline_nonleaf_penalty,
334315
inline_tupleret_bonus::Int = params.inline_tupleret_bonus,
335-
inline_error_path_cost::Int = params.inline_error_path_cost,
336316
max_tuple_splat::Int = params.max_tuple_splat,
337317
compilesig_invokes::Bool = params.compilesig_invokes,
338318
assume_fatal_throw::Bool = params.assume_fatal_throw,
@@ -342,7 +322,6 @@ function OptimizationParams(
342322
inline_cost_threshold,
343323
inline_nonleaf_penalty,
344324
inline_tupleret_bonus,
345-
inline_error_path_cost,
346325
max_tuple_splat,
347326
compilesig_invokes,
348327
assume_fatal_throw,

src/julia.h

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ typedef union __jl_purity_overrides_t {
276276
} _jl_purity_overrides_t;
277277

278278
#define NUM_EFFECTS_OVERRIDES 10
279-
#define NUM_IR_FLAGS 13
279+
#define NUM_IR_FLAGS 12
280280

281281
// This type describes a single function body
282282
typedef struct _jl_code_info_t {
@@ -288,16 +288,15 @@ typedef struct _jl_code_info_t {
288288
// 1 << 0 = inbounds region
289289
// 1 << 1 = callsite inline region
290290
// 1 << 2 = callsite noinline region
291-
// 1 << 3 = throw block
292-
// 1 << 4 = refined statement
293-
// 1 << 5 = :consistent
294-
// 1 << 6 = :effect_free
295-
// 1 << 7 = :nothrow
296-
// 1 << 8 = :terminates
297-
// 1 << 9 = :noub
298-
// 1 << 10 = :effect_free_if_inaccessiblememonly
299-
// 1 << 11 = :inaccessiblemem_or_argmemonly
300-
// 1 << 12-19 = callsite effects overrides
291+
// 1 << 3 = refined statement
292+
// 1 << 4 = :consistent
293+
// 1 << 5 = :effect_free
294+
// 1 << 6 = :nothrow
295+
// 1 << 7 = :terminates
296+
// 1 << 8 = :noub
297+
// 1 << 9 = :effect_free_if_inaccessiblememonly
298+
// 1 << 10 = :inaccessiblemem_or_argmemonly
299+
// 1 << 11-19 = callsite effects overrides
301300
// miscellaneous data:
302301
jl_array_t *slotnames; // names of local variables
303302
jl_array_t *slotflags; // local var bit flags

stdlib/REPL/src/REPLCompletions.jl

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -556,8 +556,7 @@ struct REPLInterpreter <: CC.AbstractInterpreter
556556
function REPLInterpreter(limit_aggressive_inference::Bool=false;
557557
world::UInt = Base.get_world_counter(),
558558
inf_params::CC.InferenceParams = CC.InferenceParams(;
559-
aggressive_constant_propagation=true,
560-
unoptimize_throw_blocks=false),
559+
aggressive_constant_propagation=true),
561560
opt_params::CC.OptimizationParams = CC.OptimizationParams(),
562561
inf_cache::Vector{CC.InferenceResult} = CC.InferenceResult[])
563562
return new(limit_aggressive_inference, world, inf_params, opt_params, inf_cache)

test/compiler/AbstractInterpreter.jl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,6 @@ end == Val{6}
176176
@newinterp Issue48097Interp
177177
@MethodTable ISSUE_48097_MT
178178
CC.method_table(interp::Issue48097Interp) = CC.OverlayMethodTable(CC.get_inference_world(interp), ISSUE_48097_MT)
179-
CC.InferenceParams(::Issue48097Interp) = CC.InferenceParams(; unoptimize_throw_blocks=false)
180179
function CC.concrete_eval_eligible(interp::Issue48097Interp,
181180
@nospecialize(f), result::CC.MethodCallResult, arginfo::CC.ArgInfo, sv::CC.AbsIntState)
182181
ret = @invoke CC.concrete_eval_eligible(interp::CC.AbstractInterpreter,

test/compiler/codegen.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -697,7 +697,7 @@ mktempdir() do pfx
697697
libs_deleted += 1
698698
end
699699
@test libs_deleted > 0
700-
@test readchomp(`$pfx/bin/$(Base.julia_exename()) -e 'print("no codegen!\n")'`) == "no codegen!"
700+
@test readchomp(`$pfx/bin/$(Base.julia_exename()) --startup-file=no -e 'print("no codegen!\n")'`) == "no codegen!"
701701

702702
# PR #47343
703703
libs_emptied = 0

test/dict.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1510,9 +1510,9 @@ end
15101510
for T in (Int, Float64, String, Symbol)
15111511
@testset let T=T
15121512
@test !Core.Compiler.is_consistent(Base.infer_effects(getindex, (Dict{T,Any}, T)))
1513-
@test_broken Core.Compiler.is_effect_free(Base.infer_effects(getindex, (Dict{T,Any}, T)))
1513+
@test Core.Compiler.is_effect_free(Base.infer_effects(getindex, (Dict{T,Any}, T)))
15141514
@test !Core.Compiler.is_nothrow(Base.infer_effects(getindex, (Dict{T,Any}, T)))
1515-
@test_broken Core.Compiler.is_terminates(Base.infer_effects(getindex, (Dict{T,Any}, T)))
1515+
@test Core.Compiler.is_terminates(Base.infer_effects(getindex, (Dict{T,Any}, T)))
15161516
end
15171517
end
15181518

0 commit comments

Comments
 (0)