Skip to content

Commit

Permalink
Merge branch 'master' into nz/complex-rational-div-1
Browse files Browse the repository at this point in the history
  • Loading branch information
nhz2 authored Nov 6, 2024
2 parents 4b337ef + d90c2e2 commit 3a9cf92
Show file tree
Hide file tree
Showing 49 changed files with 678 additions and 541 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/Whitespace.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ jobs:
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
with:
persist-credentials: false
- uses: julia-actions/setup-julia@9b79636afcfb07ab02c256cede01fe2db6ba808c # v2.6.0
with:
version: '1'
- name: Check whitespace
run: |
contrib/check-whitespace.jl
8 changes: 4 additions & 4 deletions base/Base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -354,14 +354,14 @@ include("set.jl")
include("char.jl")
function array_new_memory(mem::Memory{UInt8}, newlen::Int)
# add an optimization to array_new_memory for StringVector
if (@assume_effects :total @ccall jl_genericmemory_owner(mem::Any,)::Any) isa String
if (@assume_effects :total @ccall jl_genericmemory_owner(mem::Any,)::Any) === mem
# TODO: when implemented, this should use a memory growing call
return typeof(mem)(undef, newlen)
else
# If data is in a String, keep it that way.
# When implemented, this could use jl_gc_expand_string(oldstr, newlen) as an optimization
str = _string_n(newlen)
return (@assume_effects :total !:consistent @ccall jl_string_to_genericmemory(str::Any,)::Memory{UInt8})
else
# TODO: when implemented, this should use a memory growing call
return typeof(mem)(undef, newlen)
end
end
include("strings/basic.jl")
Expand Down
2 changes: 1 addition & 1 deletion base/abstractarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1584,7 +1584,7 @@ their component parts. A typical definition for an array that wraps a parent is
`Base.dataids(C::CustomArray) = dataids(C.parent)`.
"""
dataids(A::AbstractArray) = (UInt(objectid(A)),)
dataids(A::Memory) = (B = ccall(:jl_genericmemory_owner, Any, (Any,), A); (UInt(pointer(B isa typeof(A) ? B : A)),))
dataids(A::Memory) = (UInt(A.ptr),)
dataids(A::Array) = dataids(A.ref.mem)
dataids(::AbstractRange) = ()
dataids(x) = ()
Expand Down
4 changes: 0 additions & 4 deletions base/array.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3141,10 +3141,6 @@ function _wrap(ref::MemoryRef{T}, dims::NTuple{N, Int}) where {T, N}
mem_len = length(mem) + 1 - memoryrefoffset(ref)
len = Core.checked_dims(dims...)
@boundscheck mem_len >= len || invalid_wrap_err(mem_len, dims, len)
if N != 1 && !(ref === GenericMemoryRef(mem) && len === mem_len)
mem = ccall(:jl_genericmemory_slice, Memory{T}, (Any, Ptr{Cvoid}, Int), mem, ref.ptr_or_offset, len)
ref = memoryref(mem)
end
return ref
end

Expand Down
41 changes: 19 additions & 22 deletions base/compiler/abstractinterpretation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2466,7 +2466,7 @@ function abstract_eval_replaceglobal!(interp::AbstractInterpreter, sv::AbsIntSta
end
end

function args_are_actually_getglobal(argtypes)
function argtypes_are_actually_getglobal(argtypes::Vector{Any})
length(argtypes) in (3, 4) || return false
M = argtypes[2]
s = argtypes[3]
Expand Down Expand Up @@ -2506,21 +2506,21 @@ function abstract_call_known(interp::AbstractInterpreter, @nospecialize(f),
return Future(abstract_eval_setglobalonce!(interp, sv, argtypes))
elseif f === Core.replaceglobal!
return Future(abstract_eval_replaceglobal!(interp, sv, argtypes))
elseif f === Core.getfield && args_are_actually_getglobal(argtypes)
elseif f === Core.getfield && argtypes_are_actually_getglobal(argtypes)
return Future(abstract_eval_getglobal(interp, sv, argtypes))
elseif f === Core.isdefined && args_are_actually_getglobal(argtypes)
elseif f === Core.isdefined && argtypes_are_actually_getglobal(argtypes)
exct = Bottom
if length(argtypes) == 4
order = argtypes[4]
exct = global_order_exct(order, true, false)
if !(isa(order, Const) && get_atomic_order(order.val, true, false).x >= MEMORY_ORDER_UNORDERED.x)
exct = global_order_exct(order, #=loading=#true, #=storing=#false)
if !(isa(order, Const) && get_atomic_order(order.val, #=loading=#true, #=storing=#false).x >= MEMORY_ORDER_UNORDERED.x)
exct = Union{exct, ConcurrencyViolationError}
end
end
return Future(merge_exct(CallMeta(abstract_eval_isdefined(
interp,
GlobalRef((argtypes[2]::Const).val,
(argtypes[3]::Const).val),
GlobalRef((argtypes[2]::Const).val::Module,
(argtypes[3]::Const).val::Symbol),
sv),
NoCallInfo()), exct))
elseif f === Core.get_binding_type
Expand Down Expand Up @@ -3048,7 +3048,7 @@ function abstract_eval_copyast(interp::AbstractInterpreter, e::Expr, vtypes::Uni
end

function abstract_eval_isdefined_expr(interp::AbstractInterpreter, e::Expr, vtypes::Union{VarTable,Nothing},
sv::AbsIntState)
sv::AbsIntState)
sym = e.args[1]
if isa(sym, SlotNumber) && vtypes !== nothing
vtyp = vtypes[slot_id(sym)]
Expand Down Expand Up @@ -3315,16 +3315,13 @@ function abstract_eval_binding_partition!(interp::AbstractInterpreter, g::Global
end

function abstract_eval_partition_load(interp::AbstractInterpreter, partition::Core.BindingPartition)
consistent = inaccessiblememonly = ALWAYS_FALSE
nothrow = false
generic_effects = Effects(EFFECTS_TOTAL; consistent, nothrow, inaccessiblememonly)
if is_some_guard(binding_kind(partition))
if InferenceParams(interp).assume_bindings_static
return RTEffects(Union{}, UndefVarError, EFFECTS_THROWS)
else
# We do not currently assume an invalidation for guard -> defined transitions
# return RTEffects(Union{}, UndefVarError, EFFECTS_THROWS)
return RTEffects(Any, UndefVarError, generic_effects)
return RTEffects(Any, UndefVarError, generic_getglobal_effects)
end
end

Expand All @@ -3335,20 +3332,20 @@ function abstract_eval_partition_load(interp::AbstractInterpreter, partition::Co

rt = partition_restriction(partition)

if InferenceParams(interp).assume_bindings_static
return RTEffects(rt, UndefVarError, generic_getglobal_effects)
end

function abstract_eval_globalref(interp::AbstractInterpreter, g::GlobalRef, sv::AbsIntState)
partition = abstract_eval_binding_partition!(interp, g, sv)
ret = abstract_eval_partition_load(interp, partition)
if ret.rt !== Union{} && ret.exct === UndefVarError && InferenceParams(interp).assume_bindings_static
if isdefined(g, :binding) && isdefined(g.binding, :value)
return RTEffects(rt, Union{}, Effecst(generic_effects, nothrow=true))
return RTEffects(ret.rt, Union{}, Effects(generic_getglobal_effects, nothrow=true))
end
# We do not assume in general that assigned global bindings remain assigned.
# The existence of pkgimages allows them to revert in practice.
end

return RTEffects(rt, UndefVarError, generic_effects)
end

function abstract_eval_globalref(interp::AbstractInterpreter, g::GlobalRef, sv::AbsIntState)
partition = abstract_eval_binding_partition!(interp, g, sv)
return abstract_eval_partition_load(interp, partition)
return ret
end

function global_assignment_exct(interp::AbstractInterpreter, sv::AbsIntState, g::GlobalRef, @nospecialize(newty))
Expand Down Expand Up @@ -4045,7 +4042,6 @@ function typeinf(interp::AbstractInterpreter, frame::InferenceState)
takeprev = 0
while takenext >= frame.frameid
callee = takenext == 0 ? frame : callstack[takenext]::InferenceState
interp = callee.interp
if !isempty(callstack)
if length(callstack) - frame.frameid >= minwarn
topmethod = callstack[1].linfo
Expand All @@ -4059,6 +4055,7 @@ function typeinf(interp::AbstractInterpreter, frame::InferenceState)
takenext = length(callstack)
end
end
interp = callee.interp
nextstateid = takenext + 1 - frame.frameid
while length(nextstates) < nextstateid
push!(nextstates, CurrentState())
Expand Down
40 changes: 26 additions & 14 deletions base/compiler/inferencestate.jl
Original file line number Diff line number Diff line change
Expand Up @@ -227,10 +227,24 @@ struct HandlerInfo
handler_at::Vector{Tuple{Int,Int}} # tuple of current (handler, exception stack) value at the pc
end

struct WorldWithRange
this::UInt
valid_worlds::WorldRange
function WorldWithRange(world::UInt, valid_worlds::WorldRange)
if !(world in valid_worlds)
error("invalid age range update")
end
return new(world, valid_worlds)
end
end

intersect(world::WorldWithRange, valid_worlds::WorldRange) =
WorldWithRange(world.this, intersect(world.valid_worlds, valid_worlds))

mutable struct InferenceState
#= information about this method instance =#
linfo::MethodInstance
world::UInt
world::WorldWithRange
mod::Module
sptypes::Vector{VarState}
slottypes::Vector{Any}
Expand Down Expand Up @@ -265,7 +279,6 @@ mutable struct InferenceState
#= results =#
result::InferenceResult # remember where to put the result
unreachable::BitSet # statements that were found to be statically unreachable
valid_worlds::WorldRange
bestguess #::Type
exc_bestguess
ipo_effects::Effects
Expand Down Expand Up @@ -353,10 +366,10 @@ mutable struct InferenceState
parentid = frameid = cycleid = 0

this = new(
mi, world, mod, sptypes, slottypes, src, cfg, spec_info,
mi, WorldWithRange(world, valid_worlds), mod, sptypes, slottypes, src, cfg, spec_info,
currbb, currpc, ip, handler_info, ssavalue_uses, bb_vartables, ssavaluetypes, edges, stmt_info,
tasks, pclimitations, limitations, cycle_backedges, callstack, parentid, frameid, cycleid,
result, unreachable, valid_worlds, bestguess, exc_bestguess, ipo_effects,
result, unreachable, bestguess, exc_bestguess, ipo_effects,
restrict_abstract_call_sites, cache_mode, insert_coverage,
interp)

Expand All @@ -372,7 +385,7 @@ mutable struct InferenceState
# Apply generated function restrictions
if src.min_world != 1 || src.max_world != typemax(UInt)
# From generated functions
this.valid_worlds = WorldRange(src.min_world, src.max_world)
update_valid_age!(this, WorldRange(src.min_world, src.max_world))
end

return this
Expand Down Expand Up @@ -772,14 +785,13 @@ mutable struct IRInterpretationState
const spec_info::SpecInfo
const ir::IRCode
const mi::MethodInstance
const world::UInt
world::WorldWithRange
curridx::Int
const argtypes_refined::Vector{Bool}
const sptypes::Vector{VarState}
const tpdum::TwoPhaseDefUseMap
const ssa_refined::BitSet
const lazyreachability::LazyCFGReachability
valid_worlds::WorldRange
const tasks::Vector{WorkThunk}
const edges::Vector{Any}
callstack #::Vector{AbsIntState}
Expand Down Expand Up @@ -809,8 +821,8 @@ mutable struct IRInterpretationState
tasks = WorkThunk[]
edges = Any[]
callstack = AbsIntState[]
return new(spec_info, ir, mi, world, curridx, argtypes_refined, ir.sptypes, tpdum,
ssa_refined, lazyreachability, valid_worlds, tasks, edges, callstack, 0, 0)
return new(spec_info, ir, mi, WorldWithRange(world, valid_worlds), curridx, argtypes_refined, ir.sptypes, tpdum,
ssa_refined, lazyreachability, tasks, edges, callstack, 0, 0)
end
end

Expand Down Expand Up @@ -910,8 +922,8 @@ spec_info(sv::IRInterpretationState) = sv.spec_info
propagate_inbounds(sv::AbsIntState) = spec_info(sv).propagate_inbounds
method_for_inference_limit_heuristics(sv::AbsIntState) = spec_info(sv).method_for_inference_limit_heuristics

frame_world(sv::InferenceState) = sv.world
frame_world(sv::IRInterpretationState) = sv.world
frame_world(sv::InferenceState) = sv.world.this
frame_world(sv::IRInterpretationState) = sv.world.this

function is_effect_overridden(sv::AbsIntState, effect::Symbol)
if is_effect_overridden(frame_instance(sv), effect)
Expand All @@ -933,9 +945,8 @@ has_conditional(::AbstractLattice, ::IRInterpretationState) = false

# work towards converging the valid age range for sv
function update_valid_age!(sv::AbsIntState, valid_worlds::WorldRange)
valid_worlds = sv.valid_worlds = intersect(valid_worlds, sv.valid_worlds)
@assert sv.world in valid_worlds "invalid age range update"
return valid_worlds
sv.world = intersect(sv.world, valid_worlds)
return sv.world.valid_worlds
end

"""
Expand Down Expand Up @@ -1131,6 +1142,7 @@ function Future{T}(f, prev::Future{S}, interp::AbstractInterpreter, sv::AbsIntSt
else
@assert Core._hasmethod(Tuple{Core.Typeof(f), S, typeof(interp), typeof(sv)})
result = Future{T}()
@assert !isa(sv, InferenceState) || interp === sv.interp
push!(sv.tasks, function (interp, sv)
result[] = f(later[], interp, sv) # capture just later, instead of all of prev
return true
Expand Down
4 changes: 2 additions & 2 deletions base/compiler/optimize.jl
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ struct InliningState{Interp<:AbstractInterpreter}
interp::Interp
end
function InliningState(sv::InferenceState, interp::AbstractInterpreter)
return InliningState(sv.edges, sv.world, interp)
return InliningState(sv.edges, frame_world(sv), interp)
end
function InliningState(interp::AbstractInterpreter)
return InliningState(Any[], get_inference_world(interp), interp)
Expand Down Expand Up @@ -1033,7 +1033,7 @@ function run_passes_ipo_safe(
end
if is_asserts()
@timeit "verify 3" begin
verify_ir(ir, true, false, optimizer_lattice(sv.inlining.interp))
verify_ir(ir, true, false, optimizer_lattice(sv.inlining.interp), sv.linfo)
verify_linetable(ir.debuginfo, length(ir.stmts))
end
end
Expand Down
11 changes: 7 additions & 4 deletions base/compiler/ssair/EscapeAnalysis/EscapeAnalysis.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ using ._TOP_MOD: # Base definitions
using Core.Compiler: # Core.Compiler specific definitions
AbstractLattice, Bottom, IRCode, IR_FLAG_NOTHROW, InferenceResult, SimpleInferenceLattice,
argextype, fieldcount_noerror, hasintersect, has_flag, intrinsic_nothrow,
is_meta_expr_head, is_mutation_free_argtype, isexpr, println, setfield!_nothrow,
is_meta_expr_head, is_identity_free_argtype, isexpr, println, setfield!_nothrow,
singleton_type, try_compute_field, try_compute_fieldidx, widenconst,

include(x) = _TOP_MOD.include(@__MODULE__, x)
Expand Down Expand Up @@ -861,7 +861,7 @@ function add_escape_change!(astate::AnalysisState, @nospecialize(x), xinfo::Esca
xinfo ===&& return nothing # performance optimization
xidx = iridx(x, astate.estate)
if xidx !== nothing
if force || !is_mutation_free_argtype(argextype(x, astate.ir))
if force || !is_identity_free_argtype(argextype(x, astate.ir))
push!(astate.changes, EscapeChange(xidx, xinfo))
end
end
Expand All @@ -871,7 +871,7 @@ end
function add_liveness_change!(astate::AnalysisState, @nospecialize(x), livepc::Int)
xidx = iridx(x, astate.estate)
if xidx !== nothing
if !is_mutation_free_argtype(argextype(x, astate.ir))
if !is_identity_free_argtype(argextype(x, astate.ir))
push!(astate.changes, LivenessChange(xidx, livepc))
end
end
Expand Down Expand Up @@ -1077,7 +1077,10 @@ function escape_invoke!(astate::AnalysisState, pc::Int, args::Vector{Any})
# to consider the possibility of aliasing between them and the return value.
for argidx = first_idx:last_idx
arg = args[argidx]
if !is_mutation_free_argtype(argextype(arg, astate.ir))
if arg isa GlobalRef
continue # :effect_free guarantees that nothings escapes to the global scope
end
if !is_identity_free_argtype(argextype(arg, astate.ir))
add_alias_change!(astate, ret, arg)
end
end
Expand Down
5 changes: 4 additions & 1 deletion base/compiler/ssair/passes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1731,8 +1731,11 @@ function sroa_mutables!(ir::IRCode, defuses::IdDict{Int,Tuple{SPCSet,SSADefUse}}
if finalizer_useidx isa Int
nargs = length(ir.argtypes) # COMBAK this might need to be `Int(opt.src.nargs)`
estate = EscapeAnalysis.analyze_escapes(ir, nargs, 𝕃ₒ, get_escape_cache(inlining.interp))
# disable finalizer inlining when this allocation is aliased to somewhere,
# mostly likely to edges of `PhiNode`
hasaliases = EscapeAnalysis.getaliases(SSAValue(defidx), estate) !== nothing
einfo = estate[SSAValue(defidx)]
if EscapeAnalysis.has_no_escape(einfo)
if !hasaliases && EscapeAnalysis.has_no_escape(einfo)
already = BitSet(use.idx for use in defuse.uses)
for idx = einfo.Liveness
if idx already
Expand Down
Loading

0 comments on commit 3a9cf92

Please sign in to comment.