Skip to content

Commit ead3218

Browse files
authored
Merge branch 'master' into delete_redundant_IteratorSize_method_for_Slices
2 parents ae93008 + b265dba commit ead3218

37 files changed

+394
-263
lines changed

Compiler/extras/CompilerDevTools/src/CompilerDevTools.jl

+8-6
Original file line numberDiff line numberDiff line change
@@ -47,17 +47,15 @@ end
4747

4848
function Compiler.transform_result_for_cache(interp::SplitCacheInterp, result::Compiler.InferenceResult, edges::Compiler.SimpleVector)
4949
opt = result.src::Compiler.OptimizationState
50-
ir = opt.result.ir::Compiler.IRCode
51-
override = GlobalRef(@__MODULE__(), :with_new_compiler)
50+
ir = opt.optresult.ir::Compiler.IRCode
51+
override = with_new_compiler
5252
for inst in ir.stmts
5353
stmt = inst[:stmt]
5454
isexpr(stmt, :call) || continue
5555
f = stmt.args[1]
5656
f === override && continue
57-
if isa(f, GlobalRef)
58-
T = widenconst(argextype(f, ir))
59-
T <: Core.Builtin && continue
60-
end
57+
T = widenconst(argextype(f, ir))
58+
T <: Core.Builtin && continue
6159
insert!(stmt.args, 1, override)
6260
insert!(stmt.args, 3, interp.owner)
6361
end
@@ -67,6 +65,10 @@ end
6765
with_new_compiler(f, args...; owner::SplitCacheOwner = SplitCacheOwner()) = with_new_compiler(f, owner, args...)
6866

6967
function with_new_compiler(f, owner::SplitCacheOwner, args...)
68+
# We try to avoid introducing `with_new_compiler` in the first place,
69+
# but if we can't see the type, it's still possible to end up with a
70+
# builtin here - simply forward to the ordinary builtin call.
71+
isa(f, Core.Builtin) && return f(args...)
7072
mi = lookup_method_instance(f, args...)
7173
new_compiler_ci = Core.OptimizedGenerics.CompilerPlugins.typeinf(
7274
owner, mi, Compiler.SOURCE_MODE_ABI

Compiler/extras/CompilerDevTools/test/runtests.jl

+4
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,8 @@ using CompilerDevTools: lookup_method_instance, SplitCacheInterp
1717
# required extra work to be cached under the same cache owner.
1818
mi = lookup_method_instance(do_work, 1, 2)
1919
@test haskey(cache, mi)
20+
21+
# Should not error with a builtin whose type we do not know
22+
f_unknown_builtin() = Base.compilerbarrier(:type, isa)(1, Int)
23+
with_new_compiler(f_unknown_builtin, interp.owner) === true
2024
end;

Compiler/src/abstractinterpretation.jl

+22-26
Original file line numberDiff line numberDiff line change
@@ -2574,9 +2574,9 @@ function abstract_eval_replaceglobal!(interp::AbstractInterpreter, sv::AbsIntSta
25742574
M isa Module || return CallMeta(Union{}, TypeError, EFFECTS_THROWS, NoCallInfo())
25752575
s isa Symbol || return CallMeta(Union{}, TypeError, EFFECTS_THROWS, NoCallInfo())
25762576
gr = GlobalRef(M, s)
2577-
(valid_worlds, (rte, T)) = scan_leaf_partitions(interp, gr, sv.world) do interp, _, partition
2577+
(valid_worlds, (rte, T)) = scan_leaf_partitions(interp, gr, sv.world) do interp, binding, partition
25782578
partition_T = nothing
2579-
partition_rte = abstract_eval_partition_load(interp, partition)
2579+
partition_rte = abstract_eval_partition_load(interp, binding, partition)
25802580
if binding_kind(partition) == PARTITION_KIND_GLOBAL
25812581
partition_T = partition_restriction(partition)
25822582
end
@@ -3409,7 +3409,7 @@ function abstract_eval_statement_expr(interp::AbstractInterpreter, e::Expr, ssta
34093409
elseif ehead === :cfunction
34103410
return abstract_eval_cfunction(interp, e, sstate, sv)
34113411
elseif ehead === :method
3412-
rt = (length(e.args) == 1) ? Any : Nothing
3412+
rt = (length(e.args) == 1) ? Any : Method
34133413
return RTEffects(rt, Any, EFFECTS_UNKNOWN)
34143414
elseif ehead === :copyast
34153415
return abstract_eval_copyast(interp, e, sstate, sv)
@@ -3558,13 +3558,11 @@ function abstract_eval_binding_partition!(interp::AbstractInterpreter, g::Global
35583558
return partition
35593559
end
35603560

3561-
abstract_eval_partition_load(interp::Union{AbstractInterpreter, Nothing}, ::Core.Binding, partition::Core.BindingPartition) =
3562-
abstract_eval_partition_load(interp, partition)
3563-
function abstract_eval_partition_load(interp::Union{AbstractInterpreter, Nothing}, partition::Core.BindingPartition)
3561+
function abstract_eval_partition_load(interp::Union{AbstractInterpreter, Nothing}, binding::Core.Binding, partition::Core.BindingPartition)
35643562
kind = binding_kind(partition)
35653563
isdepwarn = (partition.kind & PARTITION_FLAG_DEPWARN) != 0
35663564
local_getglobal_effects = Effects(generic_getglobal_effects, effect_free=isdepwarn ? ALWAYS_FALSE : ALWAYS_TRUE)
3567-
if is_some_guard(kind) || kind == PARTITION_KIND_UNDEF_CONST
3565+
if is_some_guard(kind)
35683566
if interp !== nothing && InferenceParams(interp).assume_bindings_static
35693567
return RTEffects(Union{}, UndefVarError, EFFECTS_THROWS)
35703568
else
@@ -3590,12 +3588,23 @@ function abstract_eval_partition_load(interp::Union{AbstractInterpreter, Nothing
35903588
# Could be replaced by a backdated const which has an effect, so we can't assume it won't.
35913589
# Besides, we would prefer not to merge the world range for this into the world range for
35923590
# _GLOBAL, because that would pessimize codegen.
3593-
local_getglobal_effects = Effects(local_getglobal_effects, effect_free=ALWAYS_FALSE)
3591+
effects = Effects(local_getglobal_effects, effect_free=ALWAYS_FALSE)
35943592
rt = Any
35953593
else
35963594
rt = partition_restriction(partition)
3595+
effects = local_getglobal_effects
3596+
end
3597+
if (interp !== nothing && InferenceParams(interp).assume_bindings_static &&
3598+
kind in (PARTITION_KIND_GLOBAL, PARTITION_KIND_DECLARED) &&
3599+
isdefined(binding, :value))
3600+
exct = Union{}
3601+
effects = Effects(generic_getglobal_effects; nothrow=true)
3602+
else
3603+
# We do not assume in general that assigned global bindings remain assigned.
3604+
# The existence of pkgimages allows them to revert in practice.
3605+
exct = UndefVarError
35973606
end
3598-
return RTEffects(rt, UndefVarError, local_getglobal_effects)
3607+
return RTEffects(rt, exct, effects)
35993608
end
36003609

36013610
function scan_specified_partitions(query::Function, walk_binding_partition::Function, interp, g::GlobalRef, wwr::WorldWithRange)
@@ -3643,28 +3652,15 @@ scan_partitions(query::Function, interp, g::GlobalRef, wwr::WorldWithRange) =
36433652
abstract_load_all_consistent_leaf_partitions(interp, g::GlobalRef, wwr::WorldWithRange) =
36443653
scan_leaf_partitions(abstract_eval_partition_load, interp, g, wwr)
36453654

3646-
function abstract_eval_globalref_partition(interp, binding::Core.Binding, partition::Core.BindingPartition)
3647-
# For inference purposes, we don't particularly care which global binding we end up loading, we only
3648-
# care about its type. However, we would still like to terminate the world range for the particular
3649-
# binding we end up reaching such that codegen can emit a simpler pointer load.
3650-
Pair{RTEffects, Union{Nothing, Core.Binding}}(
3651-
abstract_eval_partition_load(interp, partition),
3652-
binding_kind(partition) in (PARTITION_KIND_GLOBAL, PARTITION_KIND_DECLARED) ? binding : nothing)
3653-
end
3654-
36553655
function abstract_eval_globalref(interp, g::GlobalRef, saw_latestworld::Bool, sv::AbsIntState)
36563656
if saw_latestworld
36573657
return RTEffects(Any, Any, generic_getglobal_effects)
36583658
end
3659-
(valid_worlds, (ret, binding_if_global)) = scan_leaf_partitions(abstract_eval_globalref_partition, interp, g, sv.world)
3659+
# For inference purposes, we don't particularly care which global binding we end up loading, we only
3660+
# care about its type. However, we would still like to terminate the world range for the particular
3661+
# binding we end up reaching such that codegen can emit a simpler pointer load.
3662+
(valid_worlds, ret) = scan_leaf_partitions(abstract_eval_partition_load, interp, g, sv.world)
36603663
update_valid_age!(sv, valid_worlds)
3661-
if ret.rt !== Union{} && ret.exct === UndefVarError && binding_if_global !== nothing && InferenceParams(interp).assume_bindings_static
3662-
if isdefined(binding_if_global, :value)
3663-
ret = RTEffects(ret.rt, Union{}, Effects(generic_getglobal_effects, nothrow=true))
3664-
end
3665-
# We do not assume in general that assigned global bindings remain assigned.
3666-
# The existence of pkgimages allows them to revert in practice.
3667-
end
36683664
return ret
36693665
end
36703666

Compiler/src/optimize.jl

+46-69
Original file line numberDiff line numberDiff line change
@@ -116,11 +116,14 @@ function inline_cost_clamp(x::Int)
116116
return convert(InlineCostType, x)
117117
end
118118

119+
const SRC_FLAG_DECLARED_INLINE = 0x1
120+
const SRC_FLAG_DECLARED_NOINLINE = 0x2
121+
119122
is_declared_inline(@nospecialize src::MaybeCompressed) =
120-
ccall(:jl_ir_flag_inlining, UInt8, (Any,), src) == 1
123+
ccall(:jl_ir_flag_inlining, UInt8, (Any,), src) == SRC_FLAG_DECLARED_INLINE
121124

122125
is_declared_noinline(@nospecialize src::MaybeCompressed) =
123-
ccall(:jl_ir_flag_inlining, UInt8, (Any,), src) == 2
126+
ccall(:jl_ir_flag_inlining, UInt8, (Any,), src) == SRC_FLAG_DECLARED_NOINLINE
124127

125128
#####################
126129
# OptimizationState #
@@ -157,6 +160,7 @@ code_cache(state::InliningState) = WorldView(code_cache(state.interp), state.wor
157160

158161
mutable struct OptimizationResult
159162
ir::IRCode
163+
inline_flag::UInt8
160164
simplified::Bool # indicates whether the IR was processed with `cfg_simplify!`
161165
end
162166

@@ -168,7 +172,7 @@ end
168172
mutable struct OptimizationState{Interp<:AbstractInterpreter}
169173
linfo::MethodInstance
170174
src::CodeInfo
171-
result::Union{Nothing, OptimizationResult}
175+
optresult::Union{Nothing, OptimizationResult}
172176
stmt_info::Vector{CallInfo}
173177
mod::Module
174178
sptypes::Vector{VarState}
@@ -236,13 +240,29 @@ include("ssair/EscapeAnalysis.jl")
236240
include("ssair/passes.jl")
237241
include("ssair/irinterp.jl")
238242

243+
function ir_to_codeinf!(opt::OptimizationState, frame::InferenceState, edges::SimpleVector)
244+
ir_to_codeinf!(opt, edges, compute_inlining_cost(frame.interp, frame.result, opt.optresult))
245+
end
246+
247+
function ir_to_codeinf!(opt::OptimizationState, edges::SimpleVector, inlining_cost::InlineCostType)
248+
src = ir_to_codeinf!(opt, edges)
249+
src.inlining_cost = inlining_cost
250+
src
251+
end
252+
253+
function ir_to_codeinf!(opt::OptimizationState, edges::SimpleVector)
254+
src = ir_to_codeinf!(opt)
255+
src.edges = edges
256+
src
257+
end
258+
239259
function ir_to_codeinf!(opt::OptimizationState)
240-
(; linfo, src, result) = opt
241-
if result === nothing
260+
(; linfo, src, optresult) = opt
261+
if optresult === nothing
242262
return src
243263
end
244-
src = ir_to_codeinf!(src, result.ir)
245-
opt.result = nothing
264+
src = ir_to_codeinf!(src, optresult.ir)
265+
opt.optresult = nothing
246266
opt.src = src
247267
maybe_validate_code(linfo, src, "optimized")
248268
return src
@@ -485,63 +505,12 @@ end
485505
abstract_eval_ssavalue(s::SSAValue, src::Union{IRCode,IncrementalCompact}) = types(src)[s]
486506

487507
"""
488-
finish(interp::AbstractInterpreter, opt::OptimizationState,
489-
ir::IRCode, caller::InferenceResult)
508+
finishopt!(interp::AbstractInterpreter, opt::OptimizationState, ir::IRCode)
490509
491-
Post-process information derived by Julia-level optimizations for later use.
492-
In particular, this function determines the inlineability of the optimized code.
510+
Called at the end of optimization to store the resulting IR back into the OptimizationState.
493511
"""
494-
function finish(interp::AbstractInterpreter, opt::OptimizationState,
495-
ir::IRCode, caller::InferenceResult)
496-
(; src, linfo) = opt
497-
(; def, specTypes) = linfo
498-
499-
force_noinline = is_declared_noinline(src)
500-
501-
# compute inlining and other related optimizations
502-
result = caller.result
503-
@assert !(result isa LimitedAccuracy)
504-
result = widenslotwrapper(result)
505-
506-
opt.result = OptimizationResult(ir, false)
507-
508-
# determine and cache inlineability
509-
if !force_noinline
510-
sig = unwrap_unionall(specTypes)
511-
if !(isa(sig, DataType) && sig.name === Tuple.name)
512-
force_noinline = true
513-
end
514-
if !is_declared_inline(src) && result === Bottom
515-
force_noinline = true
516-
end
517-
end
518-
if force_noinline
519-
set_inlineable!(src, false)
520-
elseif isa(def, Method)
521-
if is_declared_inline(src) && isdispatchtuple(specTypes)
522-
# obey @inline declaration if a dispatch barrier would not help
523-
set_inlineable!(src, true)
524-
else
525-
# compute the cost (size) of inlining this code
526-
params = OptimizationParams(interp)
527-
cost_threshold = default = params.inline_cost_threshold
528-
if (optimizer_lattice(interp), result, Tuple) && !isconcretetype(widenconst(result))
529-
cost_threshold += params.inline_tupleret_bonus
530-
end
531-
# if the method is declared as `@inline`, increase the cost threshold 20x
532-
if is_declared_inline(src)
533-
cost_threshold += 19*default
534-
end
535-
# a few functions get special treatment
536-
if def.module === _topmod(def.module)
537-
name = def.name
538-
if name === :iterate || name === :unsafe_convert || name === :cconvert
539-
cost_threshold += 4*default
540-
end
541-
end
542-
src.inlining_cost = inline_cost(ir, params, cost_threshold)
543-
end
544-
end
512+
function finishopt!(interp::AbstractInterpreter, opt::OptimizationState, ir::IRCode)
513+
opt.optresult = OptimizationResult(ir, ccall(:jl_ir_flag_inlining, UInt8, (Any,), opt.src), false)
545514
return nothing
546515
end
547516

@@ -1015,17 +984,20 @@ end
1015984
function optimize(interp::AbstractInterpreter, opt::OptimizationState, caller::InferenceResult)
1016985
@timeit "optimizer" ir = run_passes_ipo_safe(opt.src, opt)
1017986
ipo_dataflow_analysis!(interp, opt, ir, caller)
1018-
return finish(interp, opt, ir, caller)
987+
finishopt!(interp, opt, ir)
988+
return nothing
1019989
end
1020990

1021-
macro pass(name, expr)
991+
const ALL_PASS_NAMES = String[]
992+
macro pass(name::String, expr)
1022993
optimize_until = esc(:optimize_until)
1023994
stage = esc(:__stage__)
1024-
macrocall = :(@timeit $(esc(name)) $(esc(expr)))
995+
macrocall = :(@timeit $name $(esc(expr)))
1025996
macrocall.args[2] = __source__ # `@timeit` may want to use it
997+
push!(ALL_PASS_NAMES, name)
1026998
quote
1027999
$macrocall
1028-
matchpass($optimize_until, ($stage += 1), $(esc(name))) && $(esc(:(@goto __done__)))
1000+
matchpass($optimize_until, ($stage += 1), $name) && $(esc(:(@goto __done__)))
10291001
end
10301002
end
10311003

@@ -1036,8 +1008,13 @@ matchpass(::Nothing, _, _) = false
10361008
function run_passes_ipo_safe(
10371009
ci::CodeInfo,
10381010
sv::OptimizationState,
1039-
optimize_until = nothing, # run all passes by default
1040-
)
1011+
optimize_until::Union{Nothing, Int, String} = nothing) # run all passes by default
1012+
if optimize_until isa String && !contains_is(ALL_PASS_NAMES, optimize_until)
1013+
error("invalid `optimize_until` argument, no such optimization pass")
1014+
elseif optimize_until isa Int && (optimize_until < 1 || optimize_until > length(ALL_PASS_NAMES))
1015+
error("invalid `optimize_until` argument, no such optimization pass")
1016+
end
1017+
10411018
__stage__ = 0 # used by @pass
10421019
# NOTE: The pass name MUST be unique for `optimize_until::String` to work
10431020
@pass "convert" ir = convert_to_ircode(ci, sv)
@@ -1459,7 +1436,7 @@ function statement_or_branch_cost(@nospecialize(stmt), line::Int, src::Union{Cod
14591436
return thiscost
14601437
end
14611438

1462-
function inline_cost(ir::IRCode, params::OptimizationParams, cost_threshold::Int)
1439+
function inline_cost_model(ir::IRCode, params::OptimizationParams, cost_threshold::Int)
14631440
bodycost = 0
14641441
for i = 1:length(ir.stmts)
14651442
stmt = ir[SSAValue(i)][:stmt]

Compiler/src/ssair/inlining.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -976,7 +976,7 @@ function retrieve_ir_for_inlining(mi::MethodInstance, ir::IRCode, preserve_local
976976
return ir, spec_info, DebugInfo(ir.debuginfo, length(ir.stmts))
977977
end
978978
function retrieve_ir_for_inlining(mi::MethodInstance, opt::OptimizationState, preserve_local_sources::Bool)
979-
result = opt.result
979+
result = opt.optresult
980980
if result !== nothing
981981
!result.simplified && simplify_ir!(result)
982982
return retrieve_ir_for_inlining(mi, result.ir, preserve_local_sources)

0 commit comments

Comments
 (0)