Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into sds/extended_slurp
Browse files Browse the repository at this point in the history
  • Loading branch information
simeonschaub committed Jan 20, 2022
2 parents 6c2eedb + 867c98f commit 29e002e
Show file tree
Hide file tree
Showing 50 changed files with 1,547 additions and 399 deletions.
4 changes: 4 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ Standard library changes
arithmetic to error if the result may be wrapping. Or use a package such as SaferIntegers.jl when
constructing the range. ([#40382])
* TCP socket objects now expose `closewrite` functionality and support half-open mode usage ([#40783]).
* `extrema` now supports `init` keyword argument ([#36265], [#43604]).
* Intersect returns a result with the eltype of the type-promoted eltypes of the two inputs ([#41769]).
* `Iterators.countfrom` now accepts any type that defines `+`. ([#37747])

Expand Down Expand Up @@ -142,6 +143,9 @@ Standard library changes
Further, percent utilization is now reported as a total or per-thread, based on whether the thread is idle or not at
each sample. `Profile.fetch()` by default strips out the new metadata to ensure backwards compatibility with external
profiling data consumers, but can be included with the `include_meta` kwarg. ([#41742])
* The new `Profile.Allocs` module allows memory allocations to be profiled. The stack trace, type, and size of each
allocation is recorded, and a `sample_rate` argument allows a tunable amount of allocations to be skipped,
reducing performance overhead. ([#42768])

#### Random

Expand Down
13 changes: 13 additions & 0 deletions base/compiler/compiler.jl
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,19 @@ include("compiler/abstractinterpretation.jl")
include("compiler/typeinfer.jl")
include("compiler/optimize.jl") # TODO: break this up further + extract utilities

# required for bootstrap
# TODO: find why this is needed and remove it.
function extrema(x::Array)
isempty(x) && throw(ArgumentError("collection must be non-empty"))
vmin = vmax = x[1]
for i in 2:length(x)
xi = x[i]
vmax = max(vmax, xi)
vmin = min(vmin, xi)
end
return vmin, vmax
end

include("compiler/bootstrap.jl")
ccall(:jl_set_typeinf_func, Cvoid, (Any,), typeinf_ext_toplevel)

Expand Down
48 changes: 26 additions & 22 deletions base/compiler/ssair/inlining.jl
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ function cfg_inline_item!(ir::IRCode, idx::Int, spec::ResolvedInliningSpec, stat
last_block_idx = last(state.cfg.blocks[block].stmts)
if false # TODO: ((idx+1) == last_block_idx && isa(ir[SSAValue(last_block_idx)], GotoNode))
need_split = false
post_bb_id = -ir[SSAValue(last_block_idx)].label
post_bb_id = -ir[SSAValue(last_block_idx)][:inst].label
else
post_bb_id = length(state.new_cfg_blocks) + length(inlinee_cfg.blocks) + (need_split_before ? 1 : 0)
need_split = true #!(idx == last_block_idx)
Expand Down Expand Up @@ -195,7 +195,7 @@ function cfg_inline_item!(ir::IRCode, idx::Int, spec::ResolvedInliningSpec, stat
for (old_block, new_block) in enumerate(bb_rename_range)
if (length(state.new_cfg_blocks[new_block].succs) == 0)
terminator_idx = last(inlinee_cfg.blocks[old_block].stmts)
terminator = spec.ir[SSAValue(terminator_idx)]
terminator = spec.ir[SSAValue(terminator_idx)][:inst]
if isa(terminator, ReturnNode) && isdefined(terminator, :val)
any_edges = true
push!(state.new_cfg_blocks[new_block].succs, post_bb_id)
Expand Down Expand Up @@ -849,7 +849,7 @@ function handle_single_case!(
ir::IRCode, idx::Int, stmt::Expr,
@nospecialize(case), todo::Vector{Pair{Int, Any}}, isinvoke::Bool = false)
if isa(case, ConstantCase)
ir[SSAValue(idx)] = case.val
ir[SSAValue(idx)][:inst] = case.val
elseif isa(case, MethodInstance)
isinvoke && rewrite_invoke_exprargs!(stmt)
stmt.head = :invoke
Expand Down Expand Up @@ -1053,7 +1053,9 @@ end
function check_effect_free!(ir::IRCode, idx::Int, @nospecialize(stmt), @nospecialize(rt))
if stmt_effect_free(stmt, rt, ir)
ir.stmts[idx][:flag] |= IR_FLAG_EFFECT_FREE
return true
end
return false
end

# Handles all analysis and inlining of intrinsics and builtins. In particular,
Expand Down Expand Up @@ -1107,10 +1109,16 @@ function process_simple!(ir::IRCode, idx::Int, state::InliningState, todo::Vecto
return nothing
end

check_effect_free!(ir, idx, stmt, rt)
if check_effect_free!(ir, idx, stmt, rt)
if sig.f === typeassert || sig.ft typeof(typeassert)
# typeassert is a no-op if effect free
ir.stmts[idx][:inst] = stmt.args[2]
return nothing
end
end

if sig.f !== Core.invoke && is_builtin(sig)
# No inlining for builtins (other invoke/apply)
# No inlining for builtins (other invoke/apply/typeassert)
return nothing
end

Expand All @@ -1119,7 +1127,7 @@ function process_simple!(ir::IRCode, idx::Int, state::InliningState, todo::Vecto
# Special case inliners for regular functions
lateres = late_inline_special_case!(ir, idx, stmt, rt, sig, state.params)
if isa(lateres, SomeCase)
ir[SSAValue(idx)] = lateres.val
ir[SSAValue(idx)][:inst] = lateres.val
check_effect_free!(ir, idx, lateres.val, rt)
return nothing
elseif is_return_type(sig.f)
Expand Down Expand Up @@ -1287,6 +1295,16 @@ function handle_const_opaque_closure_call!(
return nothing
end

function inline_const_if_inlineable!(inst::Instruction)
rt = inst[:type]
if rt isa Const && is_inlineable_constant(rt.val)
inst[:inst] = quoted(rt.val)
return true
end
inst[:flag] |= IR_FLAG_EFFECT_FREE
return false
end

function assemble_inline_todo!(ir::IRCode, state::InliningState)
# todo = (inline_idx, (isva, isinvoke, na), method, spvals, inline_linetable, inline_ir, lie)
todo = Pair{Int, Any}[]
Expand All @@ -1300,12 +1318,7 @@ function assemble_inline_todo!(ir::IRCode, state::InliningState)

# Check whether this call was @pure and evaluates to a constant
if info isa MethodResultPure
rt = ir.stmts[idx][:type]
if rt isa Const && is_inlineable_constant(rt.val)
ir.stmts[idx][:inst] = quoted(rt.val)
continue
end
ir.stmts[idx][:flag] |= IR_FLAG_EFFECT_FREE
inline_const_if_inlineable!(ir[SSAValue(idx)]) && continue
info = info.info
end
if info === false
Expand Down Expand Up @@ -1361,7 +1374,7 @@ end

function linear_inline_eligible(ir::IRCode)
length(ir.cfg.blocks) == 1 || return false
terminator = ir[SSAValue(last(ir.cfg.blocks[1].stmts))]
terminator = ir[SSAValue(last(ir.cfg.blocks[1].stmts))][:inst]
isa(terminator, ReturnNode) || return false
isdefined(terminator, :val) || return false
return true
Expand All @@ -1379,15 +1392,6 @@ function early_inline_special_case(
ir::IRCode, stmt::Expr, @nospecialize(type), sig::Signature,
params::OptimizationParams)
(; f, ft, argtypes) = sig
if (f === typeassert || ft typeof(typeassert)) && length(argtypes) == 3
# typeassert(x::S, T) => x, when S<:T
a3 = argtypes[3]
if (isType(a3) && !has_free_typevars(a3) && argtypes[2] a3.parameters[1]) ||
(isa(a3, Const) && isa(a3.val, Type) && argtypes[2] a3.val)
val = stmt.args[2]
return SomeCase(val === nothing ? QuoteNode(val) : val)
end
end

if params.inlining
if isa(type, Const) # || isconstType(type)
Expand Down
10 changes: 5 additions & 5 deletions base/compiler/ssair/ir.jl
Original file line number Diff line number Diff line change
Expand Up @@ -304,17 +304,17 @@ end

function getindex(x::IRCode, s::SSAValue)
if s.id <= length(x.stmts)
return x.stmts[s.id][:inst]
return x.stmts[s.id]
else
return x.new_nodes.stmts[s.id - length(x.stmts)][:inst]
return x.new_nodes.stmts[s.id - length(x.stmts)]
end
end

function setindex!(x::IRCode, @nospecialize(repl), s::SSAValue)
function setindex!(x::IRCode, repl::Instruction, s::SSAValue)
if s.id <= length(x.stmts)
x.stmts[s.id][:inst] = repl
x.stmts[s.id] = repl
else
x.new_nodes.stmts[s.id - length(x.stmts)][:inst] = repl
x.new_nodes.stmts[s.id - length(x.stmts)] = repl
end
return x
end
Expand Down
18 changes: 9 additions & 9 deletions base/compiler/ssair/passes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ function find_curblock(domtree::DomTree, allblocks::Vector{Int}, curblock::Int)
end

function val_for_def_expr(ir::IRCode, def::Int, fidx::Int)
ex = ir[SSAValue(def)]
ex = ir[SSAValue(def)][:inst]
if isexpr(ex, :new)
return ex.args[1+fidx]
else
Expand Down Expand Up @@ -838,7 +838,7 @@ function sroa_mutables!(ir::IRCode, defuses::IdDict{Int, Tuple{SPCSet, SSADefUse
nuses_total = used_ssas[idx] + nuses - length(intermediaries)
nleaves == nuses_total || continue
# Find the type for this allocation
defexpr = ir[SSAValue(idx)]
defexpr = ir[SSAValue(idx)][:inst]
isexpr(defexpr, :new) || continue
newidx = idx
typ = ir.stmts[newidx][:type]
Expand All @@ -853,7 +853,7 @@ function sroa_mutables!(ir::IRCode, defuses::IdDict{Int, Tuple{SPCSet, SSADefUse
fielddefuse = SSADefUse[SSADefUse() for _ = 1:fieldcount(typ)]
all_forwarded = true
for use in defuse.uses
stmt = ir[SSAValue(use)] # == `getfield` call
stmt = ir[SSAValue(use)][:inst] # == `getfield` call
# We may have discovered above that this use is dead
# after the getfield elim of immutables. In that case,
# it would have been deleted. That's fine, just ignore
Expand All @@ -867,7 +867,7 @@ function sroa_mutables!(ir::IRCode, defuses::IdDict{Int, Tuple{SPCSet, SSADefUse
push!(fielddefuse[field].uses, use)
end
for def in defuse.defs
stmt = ir[SSAValue(def)]::Expr # == `setfield!` call
stmt = ir[SSAValue(def)][:inst]::Expr # == `setfield!` call
field = try_compute_fieldidx_stmt(ir, stmt, typ)
field === nothing && @goto skip
isconst(typ, field) && @goto skip # we discovered an attempt to mutate a const field, which must error
Expand Down Expand Up @@ -918,7 +918,7 @@ function sroa_mutables!(ir::IRCode, defuses::IdDict{Int, Tuple{SPCSet, SSADefUse
end
# Now go through all uses and rewrite them
for stmt in du.uses
ir[SSAValue(stmt)] = compute_value_for_use(ir, domtree, allblocks, du, phinodes, fidx, stmt)
ir[SSAValue(stmt)][:inst] = compute_value_for_use(ir, domtree, allblocks, du, phinodes, fidx, stmt)
end
if !isbitstype(ftyp)
if preserve_uses !== nothing
Expand All @@ -928,7 +928,7 @@ function sroa_mutables!(ir::IRCode, defuses::IdDict{Int, Tuple{SPCSet, SSADefUse
end
end
for b in phiblocks
n = ir[phinodes[b]]::PhiNode
n = ir[phinodes[b]][:inst]::PhiNode
for p in ir.cfg.blocks[b].preds
push!(n.edges, p)
push!(n.values, compute_value_for_block(ir, domtree,
Expand All @@ -938,7 +938,7 @@ function sroa_mutables!(ir::IRCode, defuses::IdDict{Int, Tuple{SPCSet, SSADefUse
end
for stmt in du.defs
stmt == newidx && continue
ir[SSAValue(stmt)] = nothing
ir[SSAValue(stmt)][:inst] = nothing
end
end
preserve_uses === nothing && continue
Expand All @@ -950,7 +950,7 @@ function sroa_mutables!(ir::IRCode, defuses::IdDict{Int, Tuple{SPCSet, SSADefUse
end
# Insert the new preserves
for (use, new_preserves) in preserve_uses
ir[SSAValue(use)] = form_new_preserves(ir[SSAValue(use)]::Expr, intermediaries, new_preserves)
ir[SSAValue(use)][:inst] = form_new_preserves(ir[SSAValue(use)][:inst]::Expr, intermediaries, new_preserves)
end

@label skip
Expand Down Expand Up @@ -1219,7 +1219,7 @@ function type_lift_pass!(ir::IRCode)
end
end
if which !== SSAValue(0)
phi = ir[which]
phi = ir[which][:inst]
if isa(phi, PhiNode)
phi.values[use] = new_phi
else
Expand Down
2 changes: 1 addition & 1 deletion base/compiler/ssair/verify.jl
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ function verify_ir(ir::IRCode, print::Bool=true)
@verify_error "Operand $i of PhiC node $idx must be an SSA Value."
error("")
end
if !isa(ir[val], UpsilonNode)
if !isa(ir[val][:inst], UpsilonNode)
@verify_error "Operand $i of PhiC node $idx must reference an Upsilon node."
error("")
end
Expand Down
8 changes: 8 additions & 0 deletions base/compiler/tfuncs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1687,6 +1687,14 @@ function _builtin_nothrow(@nospecialize(f), argtypes::Array{Any,1}, @nospecializ
elseif f === Core.ifelse
length(argtypes) == 3 || return false
return argtypes[1] Bool
elseif f === typeassert
length(argtypes) == 2 || return false
a3 = argtypes[2]
if (isType(a3) && !has_free_typevars(a3) && argtypes[1] a3.parameters[1]) ||
(isa(a3, Const) && isa(a3.val, Type) && argtypes[1] a3.val)
return true
end
return false
end
return false
end
Expand Down
8 changes: 6 additions & 2 deletions base/compiler/typelimits.jl
Original file line number Diff line number Diff line change
Expand Up @@ -414,8 +414,12 @@ function tmerge(@nospecialize(typea), @nospecialize(typeb))
fields = Vector{Any}(undef, type_nfields)
anyconst = false
for i = 1:type_nfields
ity = tmerge(getfield_tfunc(typea, Const(i)),
getfield_tfunc(typeb, Const(i)))
ai = getfield_tfunc(typea, Const(i))
bi = getfield_tfunc(typeb, Const(i))
ity = tmerge(ai, bi)
if ai === Union{} || bi === Union{}
ity = widenconst(ity)
end
fields[i] = ity
anyconst |= has_nontrivial_const_info(ity)
end
Expand Down
1 change: 1 addition & 0 deletions base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,7 @@ export
eachindex,
eachrow,
eachslice,
extrema!,
extrema,
fill!,
fill,
Expand Down
2 changes: 1 addition & 1 deletion base/loading.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1437,7 +1437,7 @@ function create_expr_cache(pkg::PkgId, input::String, output::String, concrete_d
--startup-file=no --history-file=no --warn-overwrite=yes
--color=$(have_color === nothing ? "auto" : have_color ? "yes" : "no")
$trace
--eval 'eval(Meta.parse(read(stdin,String)))'`, stderr = internal_stderr, stdout = internal_stdout),
-`, stderr = internal_stderr, stdout = internal_stdout),
"w", stdout)
# write data over stdin to avoid the (unlikely) case of exceeding max command line size
write(io.in, """
Expand Down
74 changes: 0 additions & 74 deletions base/multidimensional.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1695,80 +1695,6 @@ _unique_dims(A::AbstractArray, dims::Colon) = invoke(unique, Tuple{Any}, A)
end
end

"""
extrema(A::AbstractArray; dims) -> Array{Tuple}
Compute the minimum and maximum elements of an array over the given dimensions.
# Examples
```jldoctest
julia> A = reshape(Vector(1:2:16), (2,2,2))
2×2×2 Array{Int64, 3}:
[:, :, 1] =
1 5
3 7
[:, :, 2] =
9 13
11 15
julia> extrema(A, dims = (1,2))
1×1×2 Array{Tuple{Int64, Int64}, 3}:
[:, :, 1] =
(1, 7)
[:, :, 2] =
(9, 15)
```
"""
extrema(A::AbstractArray; dims = :) = _extrema_dims(identity, A, dims)

"""
extrema(f, A::AbstractArray; dims) -> Array{Tuple}
Compute the minimum and maximum of `f` applied to each element in the given dimensions
of `A`.
!!! compat "Julia 1.2"
This method requires Julia 1.2 or later.
"""
extrema(f, A::AbstractArray; dims=:) = _extrema_dims(f, A, dims)

_extrema_dims(f, A::AbstractArray, ::Colon) = _extrema_itr(f, A)

function _extrema_dims(f, A::AbstractArray, dims)
sz = size(A)
for d in dims
sz = setindex(sz, 1, d)
end
T = promote_op(f, eltype(A))
B = Array{Tuple{T,T}}(undef, sz...)
return extrema!(f, B, A)
end

@noinline function extrema!(f, B, A)
require_one_based_indexing(B, A)
sA = size(A)
sB = size(B)
for I in CartesianIndices(sB)
fAI = f(A[I])
B[I] = (fAI, fAI)
end
Bmax = CartesianIndex(sB)
@inbounds @simd for I in CartesianIndices(sA)
J = min(Bmax,I)
BJ = B[J]
fAI = f(A[I])
if fAI < BJ[1]
B[J] = (fAI, BJ[2])
elseif fAI > BJ[2]
B[J] = (BJ[1], fAI)
end
end
return B
end
extrema!(B, A) = extrema!(identity, B, A)

# Show for pairs() with Cartesian indices. Needs to be here rather than show.jl for bootstrap order
function Base.showarg(io::IO, r::Iterators.Pairs{<:Integer, <:Any, <:Any, T}, toplevel) where T <: Union{AbstractVector, Tuple}
print(io, "pairs(::$T)")
Expand Down
Loading

0 comments on commit 29e002e

Please sign in to comment.