Skip to content

Commit 93c158b

Browse files
committed
inliner: remove complicated (and wrong) code linearizer
1 parent 438c8a4 commit 93c158b

File tree

1 file changed

+57
-80
lines changed

1 file changed

+57
-80
lines changed

base/inference.jl

+57-80
Original file line numberDiff line numberDiff line change
@@ -3903,8 +3903,27 @@ function get_spec_lambda(atypes::ANY, sv, invoke_data::ANY)
39033903
end
39043904
end
39053905

3906-
function invoke_NF(argexprs, etype::ANY, atypes, sv, atype_unlimited::ANY,
3907-
invoke_data::ANY)
3906+
function linearize_args!(args::Vector{Any}, atypes::Vector{Any}, stmts::Vector{Any}, sv::InferenceState)
3907+
# linearize the IR by moving the arguments to SSA position
3908+
na = length(args)
3909+
@assert length(atypes) == na
3910+
newargs = Vector{Any}(na)
3911+
for i = na:-1:1
3912+
aei = args[i]
3913+
ti = atypes[i]
3914+
if isa(aei, Expr) || isa(aei, GlobalRef)
3915+
newvar = newvar!(sv, ti)
3916+
unshift!(stmts, Expr(:(=), newvar, aei))
3917+
else
3918+
newvar = aei
3919+
end
3920+
newargs[i] = newvar
3921+
end
3922+
return newargs
3923+
end
3924+
3925+
function invoke_NF(argexprs, etype::ANY, atypes::Vector{Any}, sv::InferenceState,
3926+
atype_unlimited::ANY, invoke_data::ANY)
39083927
# converts a :call to :invoke
39093928
nu = countunionsplit(atypes)
39103929
nu > sv.params.MAX_UNION_SPLITTING && return NF
@@ -3918,12 +3937,16 @@ function invoke_NF(argexprs, etype::ANY, atypes, sv, atype_unlimited::ANY,
39183937
end
39193938

39203939
if nu > 1
3940+
# linearize the IR by moving the arguments to SSA position
3941+
stmts = []
3942+
39213943
spec_miss = nothing
39223944
error_label = nothing
39233945
ex = Expr(:call)
3924-
ex.args = copy(argexprs)
39253946
ex.typ = etype
3926-
stmts = []
3947+
ex.args = linearize_args!(argexprs, atypes, stmts, sv)
3948+
invoke_texpr === nothing || insert!(stmts, 2, invoke_texpr)
3949+
invoke_fexpr === nothing || unshift!(stmts, invoke_fexpr)
39273950

39283951
local ret_var, merge, invoke_ex, spec_hit
39293952
ret_var = add_slot!(sv.src, widenconst(etype), false)
@@ -3933,26 +3956,6 @@ function invoke_NF(argexprs, etype::ANY, atypes, sv, atype_unlimited::ANY,
39333956
unshift!(invoke_ex.args, nothing)
39343957
spec_hit = false
39353958

3936-
# linearize the IR by moving the arguments to SSA position
3937-
for i = length(atypes):-1:1
3938-
if i == 1 && !(invoke_texpr === nothing)
3939-
unshift!(stmts, invoke_texpr)
3940-
end
3941-
ti = atypes[i]
3942-
aei = ex.args[i]
3943-
if !isa(aei, Slot) &&
3944-
!isa(aei, SSAValue) &&
3945-
!isa(aei, Symbol) &&
3946-
!isa(aei, QuoteNode) &&
3947-
!isa(aei, Int) &&
3948-
!isa(aei, Type) &&
3949-
!isa(aei, GlobalRef)
3950-
newvar = newvar!(sv, ti)
3951-
unshift!(stmts, :($newvar = $aei))
3952-
ex.args[i] = newvar
3953-
end
3954-
end
3955-
invoke_fexpr === nothing || unshift!(stmts, invoke_fexpr)
39563959
function splitunion(atypes::Vector{Any}, i::Int)
39573960
if i == 0
39583961
local sig = argtypes_to_type(atypes)
@@ -4020,6 +4023,7 @@ function invoke_NF(argexprs, etype::ANY, atypes, sv, atype_unlimited::ANY,
40204023
local cache_linfo = get_spec_lambda(atype_unlimited, sv, invoke_data)
40214024
cache_linfo === nothing && return NF
40224025
add_backedge!(cache_linfo, sv)
4026+
argexprs = copy(argexprs)
40234027
unshift!(argexprs, cache_linfo)
40244028
ex = Expr(:invoke)
40254029
ex.args = argexprs
@@ -4206,6 +4210,7 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference
42064210
end
42074211

42084212
argexprs0 = argexprs
4213+
atypes0 = atypes
42094214
na = Int(method.nargs)
42104215
# check for vararg function
42114216
isva = false
@@ -4214,6 +4219,7 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference
42144219
# construct tuple-forming expression for argument tail
42154220
vararg = mk_tuplecall(argexprs[na:end], sv)
42164221
argexprs = Any[argexprs[1:(na - 1)]..., vararg]
4222+
atypes = Any[atypes[1:(na - 1)]..., vararg.typ]
42174223
isva = true
42184224
elseif na != length(argexprs)
42194225
# we have a method match only because an earlier
@@ -4253,7 +4259,7 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference
42534259

42544260
# see if the method has been previously inferred (and cached)
42554261
linfo = code_for_method(method, metharg, methsp, sv.params.world, !force_infer) # Union{Void, MethodInstance}
4256-
isa(linfo, MethodInstance) || return invoke_NF(argexprs0, e.typ, atypes, sv,
4262+
isa(linfo, MethodInstance) || return invoke_NF(argexprs0, e.typ, atypes0, sv,
42574263
atype_unlimited, invoke_data)
42584264
linfo = linfo::MethodInstance
42594265
if linfo.jlcall_api == 2
@@ -4323,7 +4329,7 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference
43234329
src_inlineable = ccall(:jl_ast_flag_inlineable, Bool, (Any,), inferred)
43244330
end
43254331
if !src_inferred || !src_inlineable
4326-
return invoke_NF(argexprs0, e.typ, atypes, sv, atype_unlimited,
4332+
return invoke_NF(argexprs0, e.typ, atypes0, sv, atype_unlimited,
43274333
invoke_data)
43284334
end
43294335

@@ -4350,7 +4356,7 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference
43504356
if inline_worthy_stmts(current_stmts)
43514357
append!(current_stmts, ast)
43524358
if !inline_worthy_stmts(current_stmts)
4353-
return invoke_NF(argexprs0, e.typ, atypes, sv, atype_unlimited,
4359+
return invoke_NF(argexprs0, e.typ, atypes0, sv, atype_unlimited,
43544360
invoke_data)
43554361
end
43564362
end
@@ -4388,46 +4394,9 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference
43884394
prelude_stmts = []
43894395
stmts_free = true # true = all entries of stmts are effect_free
43904396

4391-
for i = na:-1:1 # stmts_free needs to be calculated in reverse-argument order
4392-
#args_i = args[i]
4393-
aei = argexprs[i]
4394-
aeitype = argtype = widenconst(exprtype(aei, sv.src, sv.mod))
4395-
if i == 1 && !(invoke_texpr === nothing)
4396-
unshift!(prelude_stmts, invoke_texpr)
4397-
end
4398-
4399-
# ok for argument to occur more than once if the actual argument
4400-
# is a symbol or constant, or is not affected by previous statements
4401-
# that will exist after the inlining pass finishes
4402-
affect_free = stmts_free # false = previous statements might affect the result of evaluating argument
4403-
occ = 0
4404-
for j = length(body.args):-1:1
4405-
b = body.args[j]
4406-
if occ < 6
4407-
occ += occurs_more(b, x->(isa(x, Slot) && slot_id(x) == i), 6)
4408-
end
4409-
if occ > 0 && affect_free && !effect_free(b, src, method.module, true)
4410-
#TODO: we might be able to short-circuit this test better by memoizing effect_free(b) in the for loop over i
4411-
affect_free = false
4412-
end
4413-
if occ > 5 && !affect_free
4414-
break
4415-
end
4416-
end
4417-
free = effect_free(aei, sv.src, sv.mod, true)
4418-
if ((occ==0 && aeitype===Bottom) || (occ > 1 && !inline_worthy(aei, occ*2000)) ||
4419-
(affect_free && !free) || (!affect_free && !effect_free(aei, sv.src, sv.mod, false)))
4420-
if occ != 0
4421-
vnew = newvar!(sv, aeitype)
4422-
argexprs[i] = vnew
4423-
unshift!(prelude_stmts, Expr(:(=), vnew, aei))
4424-
stmts_free &= free
4425-
elseif !free && !isType(aeitype)
4426-
unshift!(prelude_stmts, aei)
4427-
stmts_free = false
4428-
end
4429-
end
4430-
end
4397+
# linearize the IR by moving the arguments to SSA position
4398+
argexprs = linearize_args!(argexprs, atypes, prelude_stmts, sv)
4399+
invoke_texpr === nothing || insert!(prelude_stmts, 2, invoke_texpr)
44314400
invoke_fexpr === nothing || unshift!(prelude_stmts, invoke_fexpr)
44324401

44334402
# re-number the SSAValues and copy their type-info to the new ast
@@ -4478,19 +4447,18 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference
44784447
local retval
44794448
multiret = false
44804449
lastexpr = pop!(body.args)
4481-
if isa(lastexpr,LabelNode)
4450+
if isa(lastexpr, LabelNode)
44824451
push!(body.args, lastexpr)
44834452
push!(body.args, Expr(:call, GlobalRef(topmod, :error), "fatal error in type inference (lowering)"))
44844453
lastexpr = nothing
4485-
elseif !(isa(lastexpr,Expr) && lastexpr.head === :return)
4454+
elseif !(isa(lastexpr, Expr) && lastexpr.head === :return)
44864455
# code sometimes ends with a meta node, e.g. inbounds pop
44874456
push!(body.args, lastexpr)
44884457
lastexpr = nothing
44894458
end
44904459
for a in body.args
44914460
push!(stmts, a)
4492-
if isa(a,Expr)
4493-
a = a::Expr
4461+
if isa(a, Expr)
44944462
if a.head === :return
44954463
if !multiret
44964464
# create slot first time
@@ -4580,7 +4548,7 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference
45804548
end
45814549
end
45824550

4583-
if isa(expr,Expr)
4551+
if isa(expr, Expr)
45844552
old_t = e.typ
45854553
if old_t expr.typ
45864554
# if we had better type information than the content being inlined,
@@ -4618,10 +4586,10 @@ function inline_worthy(body::Expr, cost::Integer=1000) # precondition: 0 < cost;
46184586
nstmt += 1
46194587
end
46204588
end
4621-
if nstmt < (symlim + 500) ÷ 1000
4589+
if nstmt < (symlim + 500) ÷ 100
46224590
symlim *= 16
46234591
symlim ÷= 1000
4624-
if occurs_more(body, e->!inline_ignore(e), symlim) < symlim
4592+
if occurs_more(body, e -> !inline_ignore(e), symlim) < symlim
46254593
return true
46264594
end
46274595
end
@@ -5455,6 +5423,8 @@ end
54555423
# TODO can probably be removed when we switch to a linear IR
54565424
function getfield_elim_pass!(sv::InferenceState)
54575425
body = sv.src.code
5426+
nssavalues = length(sv.src.ssavaluetypes)
5427+
sv.ssavalue_defs = find_ssavalue_defs(body, nssavalues)
54585428
for i = 1:length(body)
54595429
body[i] = _getfield_elim_pass!(body[i], sv)
54605430
end
@@ -5468,11 +5438,18 @@ function _getfield_elim_pass!(e::Expr, sv::InferenceState)
54685438
(isa(e.args[3],Int) || isa(e.args[3],QuoteNode))
54695439
e1 = e.args[2]
54705440
j = e.args[3]
5471-
if isa(e1,Expr)
5472-
alloc = is_allocation(e1, sv)
5441+
single_use = true
5442+
while isa(e1, SSAValue)
5443+
single_use = false
5444+
def = sv.ssavalue_defs[e1.id + 1]
5445+
stmt = sv.src.code[def]::Expr
5446+
e1 = stmt.args[2]
5447+
end
5448+
if isa(e1, Expr)
5449+
alloc = single_use && is_allocation(e1, sv)
54735450
if alloc !== false
54745451
flen, fnames = alloc
5475-
if isa(j,QuoteNode)
5452+
if isa(j, QuoteNode)
54765453
j = findfirst(fnames, j.value)
54775454
end
54785455
if 1 <= j <= flen
@@ -5488,17 +5465,17 @@ function _getfield_elim_pass!(e::Expr, sv::InferenceState)
54885465
end
54895466
end
54905467
end
5491-
elseif isa(e1, GlobalRef) || isa(e1, Symbol) || isa(e1, Slot) || isa(e1, SSAValue)
5468+
elseif isa(e1, GlobalRef) || isa(e1, Symbol) || isa(e1, Slot)
54925469
# non-self-quoting value
54935470
else
54945471
if isa(e1, QuoteNode)
54955472
e1 = e1.value
54965473
end
5497-
if isimmutable(e1) || isa(e1,SimpleVector)
5474+
if isimmutable(e1) || isa(e1, SimpleVector)
54985475
# SimpleVector length field is immutable
54995476
if isa(j, QuoteNode)
55005477
j = j.value
5501-
if !(isa(j,Int) || isa(j,Symbol))
5478+
if !(isa(j, Int) || isa(j, Symbol))
55025479
return e
55035480
end
55045481
end

0 commit comments

Comments
 (0)