Skip to content

Commit

Permalink
lattice overhaul step 3: simplify tmerge
Browse files Browse the repository at this point in the history
  • Loading branch information
aviatesk committed Jan 22, 2022
1 parent 9a46952 commit 0750387
Show file tree
Hide file tree
Showing 14 changed files with 309 additions and 283 deletions.
59 changes: 32 additions & 27 deletions base/compiler/abstractinterpretation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
if const_result !== nothing
any_const_result = true
end
this_rt = tmerge(this_rt, rt)
this_rt = this_rt rt
if bail_out_call(interp, this_rt, sv)
break
end
Expand Down Expand Up @@ -139,16 +139,16 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
this_rt = widenconditional(this_rt)
@assert !isConditional(this_conditional) "invalid lattice element returned from inter-procedural context"
seen += 1
rettype = tmerge(rettype, this_rt)
rettype = rettype this_rt
if this_conditional !==&& is_lattice_bool(rettype) && fargs !== nothing
if conditionals === nothing
conditionals = LatticeElement[⊥ for _ in 1:length(argtypes)],
LatticeElement[⊥ for _ in 1:length(argtypes)]
end
for i = 1:length(argtypes)
cnd = conditional_argtype(this_conditional, sig, argtypes, i)
conditionals[1][i] = tmerge(conditionals[1][i], cnd.vtype)
conditionals[2][i] = tmerge(conditionals[2][i], cnd.elsetype)
conditionals[1][i] = conditionals[1][i] cnd.vtype
conditionals[2][i] = conditionals[2][i] cnd.elsetype
end
end
if bail_out_call(interp, rettype, sv)
Expand Down Expand Up @@ -290,7 +290,7 @@ In such cases `maybecondinfo` should be either of:
- `maybecondinfo::Tuple{Vector{Any},Vector{Any}}`: precomputed argument type refinement information
- method call signature tuple type
When we deal with multiple `MethodMatch`es, it's better to precompute `maybecondinfo` by
`tmerge`ing argument signature type of each method call.
`⊔`-joining argument signature type of each method call.
"""
function from_interprocedural!(rt::LatticeElement, sv::InferenceState, arginfo::ArgInfo, @nospecialize(maybecondinfo))
rt = collect_limitations!(rt, sv)
Expand Down Expand Up @@ -916,7 +916,7 @@ function precise_container_type(interp::AbstractInterpreter, itft::LatticeElemen
tps = (t::DataType).parameters
_all(valid_as_lattice, tps) || continue
for j in 1:ltp
result[j] = tmerge(result[j], rewrap_unionall(tps[j], tti0))
result[j] = result[j] NativeType(rewrap_unionall(tps[j], tti0))
end
end
return result, nothing
Expand Down Expand Up @@ -1019,9 +1019,9 @@ function abstract_iteration(interp::AbstractInterpreter, itft::LatticeElement, i
end
break
end
valtype0 = tmerge(valtype0, nounion.parameters[1])
valtype0 = valtype0 NativeType(nounion.parameters[1])
valtype = widenconst(valtype0)
statetype0 = tmerge(statetype0, nounion.parameters[2])
statetype0 = statetype0 NativeType(nounion.parameters[2])
statetype = widenconst(statetype0)
stateordonet = abstract_call_known(interp, iteratef, ArgInfo(nothing, LatticeElement[Const(iteratef), itertype, statetype0]), sv).rt
stateordonet_widened = widenconst(stateordonet)
Expand Down Expand Up @@ -1067,14 +1067,14 @@ function abstract_apply(interp::AbstractInterpreter, argtypes::Argtypes, sv::Inf
cti = cti_info[1]::Argtypes
info = cti_info[2]::MaybeAbstractIterationInfo
# We can't represent a repeating sequence of the same types,
# so tmerge everything together to get one type that represents
# so ⊔-join everything together to get one type that represents
# everything.
argt = cti[end]
if isVararg(argt)
argt = NativeType(unwrapva(vararg(argt)))
end
for i in 1:(length(cti)-1)
argt = tmerge(argt, cti[i])
argt = argt cti[i]
end
cti = LatticeElement[NativeType(Vararg{widenconst(argt)})]
end
Expand All @@ -1083,12 +1083,13 @@ function abstract_apply(interp::AbstractInterpreter, argtypes::Argtypes, sv::Inf
end
for j = 1:length(ctypes)
ct = ctypes[j]::Vector{LatticeElement}
if isVararg(ct[end])
ctend = ct[end]
if isVararg(ctend)
# This is vararg, we're not gonna be able to do any inling,
# drop the info
info = nothing
tail = tuple_tail_elem(ct[end], cti)
push!(ctypes´, push!(ct[1:(end - 1)], tail))
tail = tuple_tail_elem(unwrapva(vararg(ctend)), anymap(vawidenconst, cti))
push!(ctypes´, push!(ct[1:(end - 1)], NativeType(tail)))
else
push!(ctypes´, append!(ct[:], cti))
end
Expand All @@ -1106,15 +1107,17 @@ function abstract_apply(interp::AbstractInterpreter, argtypes::Argtypes, sv::Inf
lct = length(ct)
# truncate argument list at the first Vararg
for i = 1:lct-1
if isVararg(ct[i])
ct[i] = tuple_tail_elem(ct[i], ct[(i+1):lct])
cti = ct[i]
if isVararg(cti)
tail = tuple_tail_elem(vararg(cti), Any[vawidenconst(ct[j]) for j = (i+1):lct]) # TODO (lattice overhaul) we want to unwrapva(vararg(cti)) ?
ct[i] = NativeType(tail)
resize!(ct, i)
break
end
end
call = abstract_call(interp, ArgInfo(nothing, ct), sv, max_methods)
push!(retinfos, ApplyCallInfo(call.info, arginfo))
res = tmerge(res, call.rt)
res = res call.rt
if bail_out_apply(interp, res, sv)
if i != length(ctypes)
# No point carrying forward the info, we're not gonna inline it anyway
Expand All @@ -1128,6 +1131,8 @@ function abstract_apply(interp::AbstractInterpreter, argtypes::Argtypes, sv::Inf
return CallMeta(res, retinfo)
end

vawidenconst(t::LatticeElement) = isVararg(t) ? vararg(t) : widenconst(t)

function is_method_pure(method::Method, @nospecialize(sig), sparams::SimpleVector)
if isdefined(method, :generator)
method.generator.expand_early || return false
Expand Down Expand Up @@ -1201,7 +1206,7 @@ function abstract_call_builtin(
if isa(b, SlotNumber) && cnd.slot_id == slot_id(b)
ty = (cnd.elsetype ty ? cnd.elsetype : (ty widenconst(cnd.elsetype)))
end
return tmerge(tx, ty)
return tx ty
end
end
end
Expand Down Expand Up @@ -1288,13 +1293,13 @@ function abstract_call_builtin(
cnd = isdefined_tfunc(ty, fld)
if isConst(cnd)
if constant(cnd)::Bool
vtype = tmerge(vtype, ty)
vtype = vtype ty
else
elsetype = tmerge(elsetype, ty)
elsetype = elsetype ty
end
else
vtype = tmerge(vtype, ty)
elsetype = tmerge(elsetype, ty)
vtype = vtype ty
elsetype = elsetype ty
end
end
return Conditional(a.id, vtype, elsetype)
Expand Down Expand Up @@ -1653,7 +1658,7 @@ function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e),
if isa(e, PhiNode)
rt =
for val in e.values
rt = tmerge(rt, abstract_eval_special_value(interp, val, vtypes, sv))
rt = rt abstract_eval_special_value(interp, val, vtypes, sv)
end
return rt
end
Expand Down Expand Up @@ -1691,7 +1696,7 @@ function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e),
end
if !anyrefine
anyrefine = has_nontrivial_const_info(at) || # constant information
at ft # just a type-level information, but more precise than the declared type
at ft # just a type-level information, but more precise than the declared type
end
ats[i-1] = at
end
Expand Down Expand Up @@ -1830,7 +1835,7 @@ end
function widenreturn(rt::LatticeElement, bestguess::LatticeElement, nslots::Int, slottypes::Argtypes, changes::VarTable)
if !(bestguess Bool) || unwraptype(bestguess) === Bool
# give up inter-procedural constraint back-propagation
# when tmerge would widen the result anyways (as an optimization)
# when would widen the result anyways (as an optimization)
rt = widenconditional(rt)
else
if isConditional(rt)
Expand Down Expand Up @@ -1988,7 +1993,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
bestguess = frame.bestguess
rt = abstract_eval_value(interp, stmt.val, changes, frame)
rt = widenreturn(rt, bestguess, nslots, slottypes, changes)
# narrow representation of bestguess slightly to prepare for tmerge with rt
# narrow representation of bestguess slightly to prepare for with rt
if isInterConditional(rt) && isConst(bestguess)
let cnd = interconditional(rt)
slot_id = cnd.slot_id
Expand All @@ -2008,9 +2013,9 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
if !isempty(frame.limitations)
rt = LimitedAccuracy(rt, copy(frame.limitations))
end
if tchanged(rt, bestguess)
if bestguess rt
# new (wider) return type for frame
bestguess = tmerge(bestguess, rt)
bestguess = bestguess rt
# TODO: if isInterConditional(bestguess) && !interesting(bestguess); bestguess = widenconditional(bestguess); end
frame.bestguess = bestguess
for (caller, caller_pc) in frame.cycle_backedges
Expand Down
4 changes: 2 additions & 2 deletions base/compiler/inferencestate.jl
Original file line number Diff line number Diff line change
Expand Up @@ -322,8 +322,8 @@ function record_ssa_assign(ssa_id::Int, new::LatticeElement, frame::InferenceSta
if old === NOT_FOUND || !(new old)
# typically, we expect that old ⊑ new (that output information only
# gets less precise with worse input information), but to actually
# guarantee convergence we need to use tmerge here to ensure that is true
ssavaluetypes[ssa_id] = old === NOT_FOUND ? new : tmerge(old, new)
# guarantee convergence we need to use here to ensure that is true
ssavaluetypes[ssa_id] = old === NOT_FOUND ? new : old new
W = frame.ip
s = frame.stmt_types
for r in frame.ssavalue_uses[ssa_id]
Expand Down
4 changes: 2 additions & 2 deletions base/compiler/ssair/inlining.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1042,9 +1042,9 @@ function narrow_opaque_closure!(ir::IRCode, stmt::Expr, @nospecialize(info), sta
ub, exact = instanceof_tfunc(ubt)
exact || return
# Narrow opaque closure type
newT = widenconst(tmerge(lb, info.unspec.rt) ub)
newT = typeintersect(typemerge(lb, widenconst(info.unspec.rt)), ub)
if newT !== ub
# N.B.: Narrowing the ub requires a backdge on the mi whose type
# N.B.: Narrowing the ub requires a backedge on the mi whose type
# information we're using, since a change in that function may
# invalidate ub result.
stmt.args[4] = newT
Expand Down
4 changes: 1 addition & 3 deletions base/compiler/ssair/passes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ function walk_to_defs(compact::IncrementalCompact, @nospecialize(defssa), @nospe
# path, with a different type constraint. We may have
# to redo some work here with the wider typeconstraint
push!(worklist_defs, new_def)
push!(worklist_constraints, unwraptype(tmerge(new_constraint, visited_constraints[new_def])))
push!(worklist_constraints, typemerge(new_constraint, visited_constraints[new_def]))
end
continue
end
Expand Down Expand Up @@ -468,8 +468,6 @@ function walk_to_def(compact::IncrementalCompact, @nospecialize(leaf))
return Pair{Any, Any}(def, leaf)
end

make_MaybeUndef(@nospecialize(typ)) = isa(typ, MaybeUndef) ? typ : MaybeUndef(typ)

"""
lift_comparison!(compact::IncrementalCompact, idx::Int, stmt::Expr)
Expand Down
6 changes: 3 additions & 3 deletions base/compiler/ssair/slot2ssa.jl
Original file line number Diff line number Diff line change
Expand Up @@ -592,7 +592,7 @@ function recompute_type(node::Union{PhiNode, PhiCNode}, ci::CodeInfo, ir::IRCode
while isDelayedTyp(typ)
typ = types(ir)[getDelayedTyp(typ).phi::NewSSAValue]
end
new_typ = tmerge(new_typ, was_maybe_undef ? MaybeUndef(typ) : typ)
new_typ = new_typ (was_maybe_undef ? MaybeUndef(typ) : typ)
end
return new_typ
end
Expand Down Expand Up @@ -735,7 +735,7 @@ function construct_ssa!(ci::CodeInfo, ir::IRCode, domtree::DomTree,
if isDelayedTyp(typ)
push!(type_refine_phi, ssaval.id)
end
new_typ = isDelayedTyp(typ) ?: tmerge(old_entry[:type], typ)
new_typ = isDelayedTyp(typ) ?: (old_entry[:type] typ)
old_entry[:type] = new_typ
old_entry[:inst] = node
incoming_vals[slot] = ssaval
Expand Down Expand Up @@ -869,7 +869,7 @@ function construct_ssa!(ci::CodeInfo, ir::IRCode, domtree::DomTree,
while isDelayedTyp(typ)
typ = types(ir)[getDelayedTyp(typ).phi::NewSSAValue]
end
new_typ = tmerge(new_typ, typ)
new_typ = new_typ typ
end
node[:type] = new_typ
end
Expand Down
22 changes: 10 additions & 12 deletions base/compiler/tfuncs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ function ifelse_tfunc(cnd::LatticeElement, x::LatticeElement, y::LatticeElement)
elseif !(Bool cnd)
return
end
return tmerge(x, y)
return x y
end
add_tfunc(Core.ifelse, 3, 3, ifelse_tfunc, 1)

Expand Down Expand Up @@ -318,8 +318,7 @@ function isdefined_tfunc(arg1::LatticeElement, sym::LatticeElement)
end
end
elseif isa(a1, Union)
return tmerge(isdefined_tfunc(NativeType(a1.a), sym),
isdefined_tfunc(NativeType(a1.b), sym))
return isdefined_tfunc(NativeType(a1.a), sym) isdefined_tfunc(NativeType(a1.b), sym)
end
return LBool
end
Expand Down Expand Up @@ -391,8 +390,7 @@ function _sizeof_tfunc(@nospecialize x#=::Type=#)
isconstType(x) && return _const_sizeof(x.parameters[1])
xu = unwrap_unionall(x)
if isa(xu, Union)
return tmerge(_sizeof_tfunc(rewrap_unionall(xu.a, x)),
_sizeof_tfunc(rewrap_unionall(xu.b, x)))
return _sizeof_tfunc(rewrap_unionall(xu.a, x)) _sizeof_tfunc(rewrap_unionall(xu.b, x))
end
# Core.sizeof operates on either a type or a value. First check which
# case we're in.
Expand Down Expand Up @@ -433,7 +431,7 @@ function _nfields_tfunc(@nospecialize(x#=::Type=#))
na === LInt && return na
nb = _nfields_tfunc(x.b)
nb === LInt && return nb
return tmerge(na, nb)
return na nb
end
return LInt
end
Expand Down Expand Up @@ -874,8 +872,8 @@ end
function __getfield_tfunc(@nospecialize(s0#=::Type=#), name::LatticeElement, setfield::Bool)
s = unwrap_unionall(s0)
if isa(s, Union)
return tmerge(__getfield_tfunc(rewrap_unionall(s.a, s0), name, setfield),
__getfield_tfunc(rewrap_unionall(s.b, s0), name, setfield))
return __getfield_tfunc(rewrap_unionall(s.a, s0), name, setfield)
__getfield_tfunc(rewrap_unionall(s.b, s0), name, setfield)
end
isa(s, DataType) || return
isabstracttype(s) && return
Expand Down Expand Up @@ -924,7 +922,7 @@ function __getfield_tfunc(@nospecialize(s0#=::Type=#), name::LatticeElement, set
for i in 1:nf
_ft = ftypes[i]
setfield && isconst(s, i) && continue
t = tmerge(t, NativeType(rewrap_unionall(unwrapva(_ft), s0)))
t = t NativeType(rewrap_unionall(unwrapva(_ft), s0))
t ===&& break
end
return t
Expand Down Expand Up @@ -1150,8 +1148,8 @@ function fieldtype_tfunc(s0::LatticeElement, name::LatticeElement)

su = unwrap_unionall(s)
if isa(su, Union)
return tmerge(fieldtype_tfunc(NativeType(rewrap_unionall(su.a, s)), name),
fieldtype_tfunc(NativeType(rewrap_unionall(su.b, s)), name))
return fieldtype_tfunc(NativeType(rewrap_unionall(su.a, s)), name)
fieldtype_tfunc(NativeType(rewrap_unionall(su.b, s)), name)
end

s, exact = instanceof_tfunc(s0)
Expand Down Expand Up @@ -1221,7 +1219,7 @@ function _fieldtype_tfunc(@nospecialize(s#=::Type=#), exact::Bool, name::Lattice
else
ft1 = Const(ft1)
end
t = tmerge(t, ft1)
t = t ft1
t ===&& break
end
return t
Expand Down
Loading

0 comments on commit 0750387

Please sign in to comment.