Skip to content

Commit

Permalink
Merge branch 'master' into pc/newpm-asan-basicaa
Browse files Browse the repository at this point in the history
  • Loading branch information
gbaraldi authored Mar 22, 2023
2 parents 62fa3b4 + 6d678fe commit c91062c
Show file tree
Hide file tree
Showing 63 changed files with 1,003 additions and 653 deletions.
2 changes: 1 addition & 1 deletion Make.inc
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ endif
JULIA_VERSION := $(shell cat $(JULIAHOME)/VERSION)
JULIA_MAJOR_VERSION := $(shell echo $(JULIA_VERSION) | cut -d'-' -f 1 | cut -d'.' -f 1)
JULIA_MINOR_VERSION := $(shell echo $(JULIA_VERSION) | cut -d'-' -f 1 | cut -d'.' -f 2)
JULIA_PATCH_VERSION := $(shell echo $(JULIA_VERSION) | cut -d'-' -f 1 | cut -d'.' -f 3)
JULIA_PATCH_VERSION := $(shell echo $(JULIA_VERSION) | cut -d'-' -f 1 | cut -d'+' -f 1 | cut -d'.' -f 3)

# libjulia's SONAME will follow the format libjulia.so.$(SOMAJOR). Before v1.0.0,
# SOMAJOR will be a two-decimal value, e.g. libjulia.so.0.5, whereas at and beyond
Expand Down
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ Standard library changes
`Factorization` ([#46874]).
* New functions `hermitianpart` and `hermitianpart!` for extracting the Hermitian
(real symmetric) part of a matrix ([#31836]).
* The `norm` of the adjoint or transpose of an `AbstractMatrix` now returns the norm of the
parent matrix by default, matching the current behaviour for `AbstractVector`s ([#49020]).

#### Printf
* Format specifiers now support dynamic width and precision, e.g. `%*s` and `%*.*g` ([#40105]).
Expand Down
18 changes: 10 additions & 8 deletions base/compiler/abstractinterpretation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
# as we may want to concrete-evaluate this frame in cases when there are
# no overlayed calls, try an additional effort now to check if this call
# isn't overlayed rather than just handling it conservatively
matches = find_matching_methods(arginfo.argtypes, atype, method_table(interp),
matches = find_matching_methods(typeinf_lattice(interp), arginfo.argtypes, atype, method_table(interp),
InferenceParams(interp).max_union_splitting, max_methods)
if !isa(matches, FailedMethodMatch)
nonoverlayed = matches.nonoverlayed
Expand All @@ -75,7 +75,7 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
end

argtypes = arginfo.argtypes
matches = find_matching_methods(argtypes, atype, method_table(interp),
matches = find_matching_methods(typeinf_lattice(interp), argtypes, atype, method_table(interp),
InferenceParams(interp).max_union_splitting, max_methods)
if isa(matches, FailedMethodMatch)
add_remark!(interp, sv, matches.reason)
Expand Down Expand Up @@ -273,11 +273,12 @@ struct UnionSplitMethodMatches
end
any_ambig(m::UnionSplitMethodMatches) = any(any_ambig, m.info.matches)

function find_matching_methods(argtypes::Vector{Any}, @nospecialize(atype), method_table::MethodTableView,
function find_matching_methods(𝕃::AbstractLattice,
argtypes::Vector{Any}, @nospecialize(atype), method_table::MethodTableView,
max_union_splitting::Int, max_methods::Int)
# NOTE this is valid as far as any "constant" lattice element doesn't represent `Union` type
if 1 < unionsplitcost(argtypes) <= max_union_splitting
split_argtypes = switchtupleunion(argtypes)
if 1 < unionsplitcost(𝕃, argtypes) <= max_union_splitting
split_argtypes = switchtupleunion(𝕃, argtypes)
infos = MethodMatchInfo[]
applicable = Any[]
applicable_argtypes = Vector{Any}[] # arrays like `argtypes`, including constants, for each match
Expand Down Expand Up @@ -979,8 +980,9 @@ function abstract_call_method_with_const_args(interp::AbstractInterpreter,
if code !== nothing
ir = codeinst_to_ir(interp, code)
if isa(ir, IRCode)
irsv = IRInterpretationState(interp, ir, mi, sv.world, arginfo.argtypes)
rt, nothrow = ir_abstract_constant_propagation(interp, irsv)
irinterp = switch_to_irinterp(interp)
irsv = IRInterpretationState(irinterp, ir, mi, sv.world, arginfo.argtypes)
rt, nothrow = ir_abstract_constant_propagation(irinterp, irsv)
@assert !(rt isa Conditional || rt isa MustAlias) "invalid lattice element returned from IR interpretation"
if !isa(rt, Type) || typeintersect(rt, Bool) === Union{}
new_effects = Effects(result.effects; nothrow=nothrow)
Expand Down Expand Up @@ -1495,7 +1497,7 @@ function abstract_apply(interp::AbstractInterpreter, argtypes::Vector{Any}, si::
end
res = Union{}
nargs = length(aargtypes)
splitunions = 1 < unionsplitcost(aargtypes) <= InferenceParams(interp).max_apply_union_enum
splitunions = 1 < unionsplitcost(typeinf_lattice(interp), aargtypes) <= InferenceParams(interp).max_apply_union_enum
ctypes = [Any[aft]]
infos = Vector{MaybeAbstractIterationInfo}[MaybeAbstractIterationInfo[]]
effects = EFFECTS_TOTAL
Expand Down
4 changes: 4 additions & 0 deletions base/compiler/abstractlattice.jl
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,10 @@ has_mustalias(𝕃::AbstractLattice) = has_mustalias(widenlattice(𝕃))
has_mustalias(::AnyMustAliasesLattice) = true
has_mustalias(::JLTypeLattice) = false

has_extended_unionsplit(𝕃::AbstractLattice) = has_extended_unionsplit(widenlattice(𝕃))
has_extended_unionsplit(::AnyMustAliasesLattice) = true
has_extended_unionsplit(::JLTypeLattice) = false

# Curried versions
(lattice::AbstractLattice) = (@nospecialize(a), @nospecialize(b)) -> (lattice, a, b)
(lattice::AbstractLattice) = (@nospecialize(a), @nospecialize(b)) -> (lattice, a, b)
Expand Down
5 changes: 2 additions & 3 deletions base/compiler/ssair/inlining.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1494,6 +1494,7 @@ end

function handle_concrete_result!(cases::Vector{InliningCase}, result::ConcreteResult, @nospecialize(info::CallInfo), state::InliningState)
case = concrete_result_item(result, info, state)
case === nothing && return false
push!(cases, InliningCase(result.mi.specTypes, case))
return true
end
Expand All @@ -1505,10 +1506,8 @@ function concrete_result_item(result::ConcreteResult, @nospecialize(info::CallIn
invokesig::Union{Nothing,Vector{Any}}=nothing)
if !may_inline_concrete_result(result)
et = InliningEdgeTracker(state.et, invokesig)
case = compileable_specialization(result.mi, result.effects, et, info;
return compileable_specialization(result.mi, result.effects, et, info;
compilesig_invokes=OptimizationParams(state.interp).compilesig_invokes)
@assert case !== nothing "concrete evaluation should never happen for uncompileable callsite"
return case
end
@assert result.effects === EFFECTS_TOTAL
return ConstantCase(quoted(result.result))
Expand Down
4 changes: 3 additions & 1 deletion base/compiler/ssair/ir.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1349,7 +1349,9 @@ function process_node!(compact::IncrementalCompact, result_idx::Int, inst::Instr
elseif isa(stmt, PhiNode)
if cfg_transforms_enabled
# Rename phi node edges
map!(i -> bb_rename_pred[i], stmt.edges, stmt.edges)
let bb_rename_pred=bb_rename_pred
map!(i::Int32 -> bb_rename_pred[i], stmt.edges, stmt.edges)
end

# Remove edges and values associated with dead blocks. Entries in
# `values` can be undefined when the phi node refers to something
Expand Down
39 changes: 32 additions & 7 deletions base/compiler/tfuncs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1628,6 +1628,7 @@ function apply_type_nothrow(𝕃::AbstractLattice, argtypes::Vector{Any}, @nospe
(headtype === Union) && return true
isa(rt, Const) && return true
u = headtype
# TODO: implement optimization for isvarargtype(u) and istuple occurences (which are valid but are not UnionAll)
for i = 2:length(argtypes)
isa(u, UnionAll) || return false
ai = widenconditional(argtypes[i])
Expand Down Expand Up @@ -1747,6 +1748,9 @@ const _tvarnames = Symbol[:_A, :_B, :_C, :_D, :_E, :_F, :_G, :_H, :_I, :_J, :_K,
end
ua = ua.body
end
if largs > outer_start && isa(headtype, UnionAll) # e.g. !isvarargtype(ua) && !istuple
return Bottom # too many arguments
end
outer_start = outer_start - largs + 1

varnamectr = 1
Expand Down Expand Up @@ -1815,19 +1819,40 @@ const _tvarnames = Symbol[:_A, :_B, :_C, :_D, :_E, :_F, :_G, :_H, :_I, :_J, :_K,
push!(outervars, v)
end
end
if isa(ua, UnionAll)
if ua isa UnionAll
ua = ua.body
else
ua = nothing
#otherwise, sometimes ua isa Vararg (Core.TypeofVararg) or Tuple (DataType)
end
end
local appl
try
appl = apply_type(headtype, tparams...)
catch ex
# type instantiation might fail if one of the type parameters
# doesn't match, which could happen if a type estimate is too coarse
return isvarargtype(headtype) ? TypeofVararg : Type{<:headtype}
# type instantiation might fail if one of the type parameters doesn't
# match, which could happen only if a type estimate is too coarse
# and might guess a concrete value while the actual type for it is Bottom
if !uncertain
return Union{}
end
canconst = false
uncertain = true
empty!(outervars)
outer_start = 1
# FIXME: if these vars are substituted with TypeVar here, the result
# might be wider than the input, so should we use the `.name.wrapper`
# object here instead, to replace all of these outervars with
# unconstrained ones? Note that this code is nearly unreachable though,
# and possibly should simply return Union{} here also, since
# `apply_type` is already quite conservative about detecting and
# throwing errors.
appl = headtype
if isa(appl, UnionAll)
for _ = 1:largs
appl = appl::UnionAll
push!(outervars, appl.var)
appl = appl.body
end
end
end
!uncertain && canconst && return Const(appl)
if isvarargtype(appl)
Expand Down Expand Up @@ -2542,7 +2567,7 @@ function abstract_applicable(interp::AbstractInterpreter, argtypes::Vector{Any},
isvarargtype(argtypes[2]) && return CallMeta(Bool, EFFECTS_UNKNOWN, NoCallInfo())
argtypes = argtypes[2:end]
atype = argtypes_to_type(argtypes)
matches = find_matching_methods(argtypes, atype, method_table(interp),
matches = find_matching_methods(typeinf_lattice(interp), argtypes, atype, method_table(interp),
InferenceParams(interp).max_union_splitting, max_methods)
if isa(matches, FailedMethodMatch)
rt = Bool # too many matches to analyze
Expand Down
110 changes: 53 additions & 57 deletions base/compiler/typeinfer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -959,76 +959,74 @@ function typeinf_ircode(
sparams::SimpleVector,
optimize_until::Union{Integer,AbstractString,Nothing},
)
ccall(:jl_typeinf_timing_begin, Cvoid, ())
start_time = ccall(:jl_typeinf_timing_begin, UInt64, ())
frame = typeinf_frame(interp, method, atype, sparams, false)
if frame === nothing
ccall(:jl_typeinf_timing_end, Cvoid, ())
ccall(:jl_typeinf_timing_end, Cvoid, (UInt64,), start_time)
return nothing, Any
end
(; result) = frame
opt = OptimizationState(frame, interp)
ir = run_passes(opt.src, opt, result, optimize_until)
rt = widenconst(ignorelimited(result.result))
ccall(:jl_typeinf_timing_end, Cvoid, ())
ccall(:jl_typeinf_timing_end, Cvoid, (UInt64,), start_time)
return ir, rt
end

# compute an inferred frame
function typeinf_frame(interp::AbstractInterpreter, method::Method, @nospecialize(atype), sparams::SimpleVector, run_optimizer::Bool)
mi = specialize_method(method, atype, sparams)::MethodInstance
ccall(:jl_typeinf_timing_begin, Cvoid, ())
start_time = ccall(:jl_typeinf_timing_begin, UInt64, ())
result = InferenceResult(mi, typeinf_lattice(interp))
frame = InferenceState(result, run_optimizer ? :global : :no, interp)
frame === nothing && return nothing
typeinf(interp, frame)
ccall(:jl_typeinf_timing_end, Cvoid, ())
ccall(:jl_typeinf_timing_end, Cvoid, (UInt64,), start_time)
return frame
end

# compute (and cache) an inferred AST and return type
function typeinf_ext(interp::AbstractInterpreter, mi::MethodInstance)
method = mi.def::Method
for i = 1:2 # test-and-lock-and-test
i == 2 && ccall(:jl_typeinf_timing_begin, Cvoid, ())
code = get(code_cache(interp), mi, nothing)
if code isa CodeInstance
# see if this code already exists in the cache
inf = @atomic :monotonic code.inferred
if use_const_api(code)
i == 2 && ccall(:jl_typeinf_timing_end, Cvoid, ())
tree = ccall(:jl_new_code_info_uninit, Ref{CodeInfo}, ())
rettype_const = code.rettype_const
tree.code = Any[ ReturnNode(quoted(rettype_const)) ]
nargs = Int(method.nargs)
tree.slotnames = ccall(:jl_uncompress_argnames, Vector{Symbol}, (Any,), method.slot_syms)
tree.slotflags = fill(IR_FLAG_NULL, nargs)
tree.ssavaluetypes = 1
tree.codelocs = Int32[1]
tree.linetable = LineInfoNode[LineInfoNode(method.module, method.name, method.file, method.line, Int32(0))]
tree.inferred = true
tree.ssaflags = UInt8[0]
set_inlineable!(tree, true)
tree.parent = mi
tree.rettype = Core.Typeof(rettype_const)
tree.min_world = code.min_world
tree.max_world = code.max_world
return tree
elseif isa(inf, CodeInfo)
i == 2 && ccall(:jl_typeinf_timing_end, Cvoid, ())
if !(inf.min_world == code.min_world &&
inf.max_world == code.max_world &&
inf.rettype === code.rettype)
inf = copy(inf)
inf.min_world = code.min_world
inf.max_world = code.max_world
inf.rettype = code.rettype
end
return inf
elseif isa(inf, Vector{UInt8})
i == 2 && ccall(:jl_typeinf_timing_end, Cvoid, ())
inf = _uncompressed_ir(code, inf)
return inf
start_time = ccall(:jl_typeinf_timing_begin, UInt64, ())
code = get(code_cache(interp), mi, nothing)
if code isa CodeInstance
# see if this code already exists in the cache
inf = @atomic :monotonic code.inferred
if use_const_api(code)
ccall(:jl_typeinf_timing_end, Cvoid, (UInt64,), start_time)
tree = ccall(:jl_new_code_info_uninit, Ref{CodeInfo}, ())
rettype_const = code.rettype_const
tree.code = Any[ ReturnNode(quoted(rettype_const)) ]
nargs = Int(method.nargs)
tree.slotnames = ccall(:jl_uncompress_argnames, Vector{Symbol}, (Any,), method.slot_syms)
tree.slotflags = fill(IR_FLAG_NULL, nargs)
tree.ssavaluetypes = 1
tree.codelocs = Int32[1]
tree.linetable = LineInfoNode[LineInfoNode(method.module, method.name, method.file, method.line, Int32(0))]
tree.inferred = true
tree.ssaflags = UInt8[0]
set_inlineable!(tree, true)
tree.parent = mi
tree.rettype = Core.Typeof(rettype_const)
tree.min_world = code.min_world
tree.max_world = code.max_world
return tree
elseif isa(inf, CodeInfo)
ccall(:jl_typeinf_timing_end, Cvoid, (UInt64,), start_time)
if !(inf.min_world == code.min_world &&
inf.max_world == code.max_world &&
inf.rettype === code.rettype)
inf = copy(inf)
inf.min_world = code.min_world
inf.max_world = code.max_world
inf.rettype = code.rettype
end
return inf
elseif isa(inf, Vector{UInt8})
ccall(:jl_typeinf_timing_end, Cvoid, (UInt64,), start_time)
inf = _uncompressed_ir(code, inf)
return inf
end
end
if ccall(:jl_get_module_infer, Cint, (Any,), method.module) == 0 && !generating_sysimg()
Expand All @@ -1039,7 +1037,7 @@ function typeinf_ext(interp::AbstractInterpreter, mi::MethodInstance)
frame = InferenceState(result, #=cache=#:global, interp)
frame === nothing && return nothing
typeinf(interp, frame)
ccall(:jl_typeinf_timing_end, Cvoid, ())
ccall(:jl_typeinf_timing_end, Cvoid, (UInt64,), start_time)
frame.src.inferred || return nothing
return frame.src
end
Expand All @@ -1050,18 +1048,16 @@ function typeinf_type(interp::AbstractInterpreter, method::Method, @nospecialize
return Union{} # don't ask: it does weird and unnecessary things, if it occurs during bootstrap
end
mi = specialize_method(method, atype, sparams)::MethodInstance
for i = 1:2 # test-and-lock-and-test
i == 2 && ccall(:jl_typeinf_timing_begin, Cvoid, ())
code = get(code_cache(interp), mi, nothing)
if code isa CodeInstance
# see if this rettype already exists in the cache
i == 2 && ccall(:jl_typeinf_timing_end, Cvoid, ())
return code.rettype
end
start_time = ccall(:jl_typeinf_timing_begin, UInt64, ())
code = get(code_cache(interp), mi, nothing)
if code isa CodeInstance
# see if this rettype already exists in the cache
ccall(:jl_typeinf_timing_end, Cvoid, (UInt64,), start_time)
return code.rettype
end
result = InferenceResult(mi, typeinf_lattice(interp))
typeinf(interp, result, :global)
ccall(:jl_typeinf_timing_end, Cvoid, ())
ccall(:jl_typeinf_timing_end, Cvoid, (UInt64,), start_time)
is_inferred(result) || return nothing
return widenconst(ignorelimited(result.result))
end
Expand All @@ -1076,15 +1072,15 @@ function typeinf_ext_toplevel(interp::AbstractInterpreter, linfo::MethodInstance
src = linfo.uninferred::CodeInfo
if !src.inferred
# toplevel lambda - infer directly
ccall(:jl_typeinf_timing_begin, Cvoid, ())
start_time = ccall(:jl_typeinf_timing_begin, UInt64, ())
if !src.inferred
result = InferenceResult(linfo, typeinf_lattice(interp))
frame = InferenceState(result, src, #=cache=#:global, interp)
typeinf(interp, frame)
@assert is_inferred(frame) # TODO: deal with this better
src = frame.src
end
ccall(:jl_typeinf_timing_end, Cvoid, ())
ccall(:jl_typeinf_timing_end, Cvoid, (UInt64,), start_time)
end
end
return src
Expand Down
2 changes: 2 additions & 0 deletions base/compiler/typelattice.jl
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ end
MustAlias(var::SlotNumber, @nospecialize(vartyp), fldidx::Int, @nospecialize(fldtyp)) =
MustAlias(slot_id(var), vartyp, fldidx, fldtyp)

_uniontypes(x::MustAlias, ts) = _uniontypes(widenconst(x), ts)

"""
alias::InterMustAlias
Expand Down
Loading

0 comments on commit c91062c

Please sign in to comment.