Skip to content

Commit

Permalink
Merge branch 'master' into fa/reloctpath
Browse files Browse the repository at this point in the history
  • Loading branch information
DilumAluthge authored Oct 21, 2024
2 parents c2522e2 + 1fd7ada commit a9b6ad9
Show file tree
Hide file tree
Showing 58 changed files with 2,105 additions and 1,558 deletions.
2 changes: 1 addition & 1 deletion base/Base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,7 @@ include("deepcopy.jl")
include("download.jl")
include("summarysize.jl")
include("errorshow.jl")
include("util.jl")

include("initdefs.jl")
Filesystem.__postinit__()
Expand All @@ -549,7 +550,6 @@ include("loading.jl")

# misc useful functions & macros
include("timing.jl")
include("util.jl")
include("client.jl")
include("asyncmap.jl")

Expand Down
11 changes: 11 additions & 0 deletions base/array.jl
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,17 @@ copy
return $(Expr(:new, :(typeof(a)), :(memoryref(newmem)), :(a.size)))
end

# a mutating version of copyto! that results in dst aliasing src afterwards
function _take!(dst::Array{T,N}, src::Array{T,N}) where {T,N}
if getfield(dst, :ref) !== getfield(src, :ref)
setfield!(dst, :ref, getfield(src, :ref))
end
if getfield(dst, :size) !== getfield(src, :size)
setfield!(dst, :size, getfield(src, :size))
end
return dst
end

## Constructors ##

similar(a::Array{T,1}) where {T} = Vector{T}(undef, size(a,1))
Expand Down
75 changes: 46 additions & 29 deletions base/compiler/ssair/slot2ssa.jl
Original file line number Diff line number Diff line change
Expand Up @@ -339,43 +339,58 @@ RPO traversal and in particular, any use of an SSA value must come after
(by linear order) its definition.
"""
function domsort_ssa!(ir::IRCode, domtree::DomTree)
# First compute the new order of basic blocks
# Mapping from new → old BB index
# An "old" index of 0 means that this was a BB inserted as part of a fixup (see below)
result_order = Int[]
stack = Int[]

# Mapping from old → new BB index
bb_rename = fill(-1, length(ir.cfg.blocks))
node = 1
ncritbreaks = 0
nnewfallthroughs = 0
while node !== -1
push!(result_order, node)
bb_rename[node] = length(result_order)
cs = domtree.nodes[node].children
terminator = ir[SSAValue(last(ir.cfg.blocks[node].stmts))][:stmt]
next_node = node + 1
node = -1

# The number of GotoNodes we need to insert to preserve control-flow after sorting
nfixupstmts = 0

# node queued up for scheduling (-1 === nothing)
node_to_schedule = 1
worklist = Int[]
while node_to_schedule !== -1
# First assign a new BB index to `node_to_schedule`
push!(result_order, node_to_schedule)
bb_rename[node_to_schedule] = length(result_order)
cs = domtree.nodes[node_to_schedule].children
terminator = ir[SSAValue(last(ir.cfg.blocks[node_to_schedule].stmts))][:stmt]
fallthrough = node_to_schedule + 1
node_to_schedule = -1

# Adding the nodes in reverse sorted order attempts to retain
# the original source order of the nodes as much as possible.
# This is not required for correctness, but is easier on the humans
for child in Iterators.Reverse(cs)
if child == next_node
for node in Iterators.Reverse(cs)
if node == fallthrough
# Schedule the fall through node first,
# so we can retain the fall through
node = next_node
node_to_schedule = node
else
push!(stack, child)
push!(worklist, node)
end
end
if node == -1 && !isempty(stack)
node = pop!(stack)
if node_to_schedule == -1 && !isempty(worklist)
node_to_schedule = pop!(worklist)
end
if node != next_node && !isa(terminator, Union{GotoNode, ReturnNode})
# If a fallthrough successor is no longer the fallthrough after sorting, we need to
# add a GotoNode (and either extend or split the basic block as necessary)
if node_to_schedule != fallthrough && !isa(terminator, Union{GotoNode, ReturnNode})
if isa(terminator, GotoIfNot)
# Need to break the critical edge
ncritbreaks += 1
push!(result_order, 0)
elseif isa(terminator, EnterNode) || isexpr(terminator, :leave)
# Cannot extend the BasicBlock with a goto, have to split it
push!(result_order, 0)
else
nnewfallthroughs += 1
# No need for a new block, just extend
@assert !isterminator(terminator)
end
# Reserve space for the fixup goto
nfixupstmts += 1
end
end
new_bbs = Vector{BasicBlock}(undef, length(result_order))
Expand All @@ -385,7 +400,7 @@ function domsort_ssa!(ir::IRCode, domtree::DomTree)
nstmts += length(ir.cfg.blocks[i].stmts)
end
end
result = InstructionStream(nstmts + ncritbreaks + nnewfallthroughs)
result = InstructionStream(nstmts + nfixupstmts)
inst_rename = Vector{SSAValue}(undef, length(ir.stmts) + length(ir.new_nodes))
@inbounds for i = 1:length(ir.stmts)
inst_rename[i] = SSAValue(-1)
Expand All @@ -394,7 +409,6 @@ function domsort_ssa!(ir::IRCode, domtree::DomTree)
inst_rename[i + length(ir.stmts)] = SSAValue(i + length(result))
end
bb_start_off = 0
crit_edge_breaks_fixup = Tuple{Int, Int}[]
for (new_bb, bb) in pairs(result_order)
if bb == 0
nidx = bb_start_off + 1
Expand Down Expand Up @@ -426,20 +440,23 @@ function domsort_ssa!(ir::IRCode, domtree::DomTree)
else
result[inst_range[end]][:stmt] = GotoNode(bb_rename[terminator.label])
end
elseif isa(terminator, GotoIfNot)
# Check if we need to break the critical edge
elseif isa(terminator, GotoIfNot) || isa(terminator, EnterNode) || isexpr(terminator, :leave)
# Check if we need to break the critical edge or split the block
if bb_rename[bb + 1] != new_bb + 1
@assert result_order[new_bb + 1] == 0
# Add an explicit goto node in the next basic block (we accounted for this above)
nidx = inst_range[end] + 1
node = result[nidx]
node[:stmt], node[:type], node[:line] = GotoNode(bb_rename[bb + 1]), Any, NoLineUpdate
end
result[inst_range[end]][:stmt] = GotoIfNot(terminator.cond, bb_rename[terminator.dest])
elseif !isa(terminator, ReturnNode)
if isa(terminator, EnterNode)
if isa(terminator, GotoIfNot)
result[inst_range[end]][:stmt] = GotoIfNot(terminator.cond, bb_rename[terminator.dest])
elseif isa(terminator, EnterNode)
result[inst_range[end]][:stmt] = EnterNode(terminator, terminator.catch_dest == 0 ? 0 : bb_rename[terminator.catch_dest])
else
@assert isexpr(terminator, :leave)
end
elseif !isa(terminator, ReturnNode)
if bb_rename[bb + 1] != new_bb + 1
# Add an explicit goto node
nidx = inst_range[end] + 1
Expand All @@ -452,7 +469,7 @@ function domsort_ssa!(ir::IRCode, domtree::DomTree)
local new_preds, new_succs
let bb = bb, bb_rename = bb_rename, result_order = result_order
new_preds = Int[bb for bb in (rename_incoming_edge(i, bb, result_order, bb_rename) for i in ir.cfg.blocks[bb].preds) if bb != -1]
new_succs = Int[ rename_outgoing_edge(i, bb, result_order, bb_rename) for i in ir.cfg.blocks[bb].succs]
new_succs = Int[ rename_outgoing_edge(i, bb, result_order, bb_rename) for i in ir.cfg.blocks[bb].succs]
end
new_bbs[new_bb] = BasicBlock(inst_range, new_preds, new_succs)
end
Expand Down
11 changes: 10 additions & 1 deletion base/irrationals.jl
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,16 @@ promote_rule(::Type{<:AbstractIrrational}, ::Type{Float16}) = Float16
promote_rule(::Type{<:AbstractIrrational}, ::Type{Float32}) = Float32
promote_rule(::Type{<:AbstractIrrational}, ::Type{<:AbstractIrrational}) = Float64
promote_rule(::Type{<:AbstractIrrational}, ::Type{T}) where {T<:Real} = promote_type(Float64, T)
promote_rule(::Type{S}, ::Type{T}) where {S<:AbstractIrrational,T<:Number} = promote_type(promote_type(S, real(T)), T)

function promote_rule(::Type{S}, ::Type{T}) where {S<:AbstractIrrational,T<:Number}
U = promote_type(S, real(T))
if S <: U
# prevent infinite recursion
promote_type(Float64, T)
else
promote_type(U, T)
end
end

AbstractFloat(x::AbstractIrrational) = Float64(x)::Float64
Float16(x::AbstractIrrational) = Float16(Float32(x)::Float32)
Expand Down
83 changes: 54 additions & 29 deletions base/loading.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1247,7 +1247,7 @@ function _include_from_serialized(pkg::PkgId, path::String, ocachepath::Union{No
else
io = open(path, "r")
try
iszero(isvalid_cache_header(io)) && return ArgumentError("Invalid header in cache file $path.")
iszero(isvalid_cache_header(io)) && return ArgumentError("Incompatible header in cache file $path.")
_, (includes, _, _), _, _, _, _, _, _ = parse_cache_header(io, path)
ignore_native = pkg_tracked(includes)
finally
Expand Down Expand Up @@ -1683,6 +1683,8 @@ function CacheFlags(cf::CacheFlags=CacheFlags(ccall(:jl_cache_flags, UInt8, ()))
opt_level === nothing ? cf.opt_level : opt_level
)
end
# reflecting jloptions.c defaults
const DefaultCacheFlags = CacheFlags(use_pkgimages=true, debug_level=isdebugbuild() ? 2 : 1, check_bounds=0, inline=true, opt_level=2)

function _cacheflag_to_uint8(cf::CacheFlags)::UInt8
f = UInt8(0)
Expand All @@ -1694,12 +1696,29 @@ function _cacheflag_to_uint8(cf::CacheFlags)::UInt8
return f
end

function translate_cache_flags(cacheflags::CacheFlags, defaultflags::CacheFlags)
opts = String[]
cacheflags.use_pkgimages != defaultflags.use_pkgimages && push!(opts, cacheflags.use_pkgimages ? "--pkgimages=yes" : "--pkgimages=no")
cacheflags.debug_level != defaultflags.debug_level && push!(opts, "-g$(cacheflags.debug_level)")
cacheflags.check_bounds != defaultflags.check_bounds && push!(opts, ("--check-bounds=auto", "--check-bounds=yes", "--check-bounds=no")[cacheflags.check_bounds + 1])
cacheflags.inline != defaultflags.inline && push!(opts, cacheflags.inline ? "--inline=yes" : "--inline=no")
cacheflags.opt_level != defaultflags.opt_level && push!(opts, "-O$(cacheflags.opt_level)")
return opts
end

function show(io::IO, cf::CacheFlags)
print(io, "use_pkgimages = ", cf.use_pkgimages)
print(io, ", debug_level = ", cf.debug_level)
print(io, ", check_bounds = ", cf.check_bounds)
print(io, ", inline = ", cf.inline)
print(io, ", opt_level = ", cf.opt_level)
print(io, "CacheFlags(")
print(io, "; use_pkgimages=")
print(io, cf.use_pkgimages)
print(io, ", debug_level=")
print(io, cf.debug_level)
print(io, ", check_bounds=")
print(io, cf.check_bounds)
print(io, ", inline=")
print(io, cf.inline)
print(io, ", opt_level=")
print(io, cf.opt_level)
print(io, ")")
end

struct ImageTarget
Expand Down Expand Up @@ -1868,7 +1887,7 @@ function isrelocatable(pkg::PkgId)
isnothing(path) && return false
io = open(path, "r")
try
iszero(isvalid_cache_header(io)) && throw(ArgumentError("Invalid header in cache file $cachefile."))
iszero(isvalid_cache_header(io)) && throw(ArgumentError("Incompatible header in cache file $cachefile."))
_, (includes, includes_srcfiles, _), _... = _parse_cache_header(io, path)
for inc in includes
!startswith(inc.filename, "@depot") && return false
Expand Down Expand Up @@ -1943,7 +1962,7 @@ function _tryrequire_from_serialized(pkg::PkgId, path::String, ocachepath::Union
io = open(path, "r")
ignore_native = false
try
iszero(isvalid_cache_header(io)) && return ArgumentError("Invalid header in cache file $path.")
iszero(isvalid_cache_header(io)) && return ArgumentError("Incompatible header in cache file $path.")
_, (includes, _, _), depmodnames, _, _, _, clone_targets, _ = parse_cache_header(io, path)

ignore_native = pkg_tracked(includes)
Expand Down Expand Up @@ -2953,7 +2972,8 @@ end

const PRECOMPILE_TRACE_COMPILE = Ref{String}()
function create_expr_cache(pkg::PkgId, input::String, output::String, output_o::Union{Nothing, String},
concrete_deps::typeof(_concrete_dependencies), flags::Cmd=``, internal_stderr::IO = stderr, internal_stdout::IO = stdout, isext::Bool=false)
concrete_deps::typeof(_concrete_dependencies), flags::Cmd=``, cacheflags::CacheFlags=CacheFlags(),
internal_stderr::IO = stderr, internal_stdout::IO = stdout, isext::Bool=false)
@nospecialize internal_stderr internal_stdout
rm(output, force=true) # Remove file if it exists
output_o === nothing || rm(output_o, force=true)
Expand Down Expand Up @@ -2996,24 +3016,29 @@ function create_expr_cache(pkg::PkgId, input::String, output::String, output_o::
deps = deps_eltype * "[" * join(deps_strs, ",") * "]"
precomp_stack = "Base.PkgId[$(join(map(pkg_str, vcat(Base.precompilation_stack, pkg)), ", "))]"

if output_o === nothing
# remove options that make no difference given the other cache options
cacheflags = CacheFlags(cacheflags, opt_level=0)
end
opts = translate_cache_flags(cacheflags, CacheFlags()) # julia_cmd is generated for the running system, and must be fixed if running for precompile instead
if output_o !== nothing
@debug "Generating object cache file for $(repr("text/plain", pkg))"
cpu_target = get(ENV, "JULIA_CPU_TARGET", nothing)
opts = `--output-o $(output_o) --output-ji $(output) --output-incremental=yes`
push!(opts, "--output-o", output_o)
else
@debug "Generating cache file for $(repr("text/plain", pkg))"
cpu_target = nothing
opts = `-O0 --output-ji $(output) --output-incremental=yes`
end
push!(opts, "--output-ji", output)
isassigned(PRECOMPILE_TRACE_COMPILE) && push!(opts, "--trace-compile=$(PRECOMPILE_TRACE_COMPILE[])")

trace = isassigned(PRECOMPILE_TRACE_COMPILE) ? `--trace-compile=$(PRECOMPILE_TRACE_COMPILE[]) --trace-compile-timing` : ``
io = open(pipeline(addenv(`$(julia_cmd(;cpu_target)::Cmd)
$(flags)
$(opts)
--startup-file=no --history-file=no --warn-overwrite=yes
--color=$(have_color === nothing ? "auto" : have_color ? "yes" : "no")
$trace
-`,
$(flags)
$(opts)
--output-incremental=yes
--startup-file=no --history-file=no --warn-overwrite=yes
$(have_color === nothing ? "--color=auto" : have_color ? "--color=yes" : "--color=no")
-`,
"OPENBLAS_NUM_THREADS" => 1,
"JULIA_NUM_THREADS" => 1),
stderr = internal_stderr, stdout = internal_stdout),
Expand Down Expand Up @@ -3131,7 +3156,7 @@ function compilecache(pkg::PkgId, path::String, internal_stderr::IO = stderr, in
close(tmpio_o)
close(tmpio_so)
end
p = create_expr_cache(pkg, path, tmppath, tmppath_o, concrete_deps, flags, internal_stderr, internal_stdout, isext)
p = create_expr_cache(pkg, path, tmppath, tmppath_o, concrete_deps, flags, cacheflags, internal_stderr, internal_stdout, isext)

if success(p)
if cache_objects
Expand All @@ -3154,7 +3179,7 @@ function compilecache(pkg::PkgId, path::String, internal_stderr::IO = stderr, in
# append extra crc to the end of the .ji file:
open(tmppath, "r+") do f
if iszero(isvalid_cache_header(f))
error("Invalid header for $(repr("text/plain", pkg)) in new cache file $(repr(tmppath)).")
error("Incompatible header for $(repr("text/plain", pkg)) in new cache file $(repr(tmppath)).")
end
seekend(f)
write(f, crc_so)
Expand Down Expand Up @@ -3545,7 +3570,7 @@ end
function parse_cache_header(cachefile::String)
io = open(cachefile, "r")
try
iszero(isvalid_cache_header(io)) && throw(ArgumentError("Invalid header in cache file $cachefile."))
iszero(isvalid_cache_header(io)) && throw(ArgumentError("Incompatible header in cache file $cachefile."))
ret = parse_cache_header(io, cachefile)
return ret
finally
Expand All @@ -3558,7 +3583,7 @@ function preferences_hash(cachefile::String)
io = open(cachefile, "r")
try
if iszero(isvalid_cache_header(io))
throw(ArgumentError("Invalid header in cache file $cachefile."))
throw(ArgumentError("Incompatible header in cache file $cachefile."))
end
return preferences_hash(io, cachefile)
finally
Expand All @@ -3574,7 +3599,7 @@ end
function cache_dependencies(cachefile::String)
io = open(cachefile, "r")
try
iszero(isvalid_cache_header(io)) && throw(ArgumentError("Invalid header in cache file $cachefile."))
iszero(isvalid_cache_header(io)) && throw(ArgumentError("Incompatible header in cache file $cachefile."))
return cache_dependencies(io, cachefile)
finally
close(io)
Expand Down Expand Up @@ -3614,7 +3639,7 @@ end
function read_dependency_src(cachefile::String, filename::AbstractString)
io = open(cachefile, "r")
try
iszero(isvalid_cache_header(io)) && throw(ArgumentError("Invalid header in cache file $cachefile."))
iszero(isvalid_cache_header(io)) && throw(ArgumentError("Incompatible header in cache file $cachefile."))
return read_dependency_src(io, cachefile, filename)
finally
close(io)
Expand Down Expand Up @@ -3898,9 +3923,9 @@ end
try
checksum = isvalid_cache_header(io)
if iszero(checksum)
@debug "Rejecting cache file $cachefile due to it containing an invalid cache header"
record_reason(reasons, "invalid header")
return true # invalid cache file
@debug "Rejecting cache file $cachefile due to it containing an incompatible cache header"
record_reason(reasons, "incompatible header")
return true # incompatible cache file
end
modules, (includes, _, requires), required_modules, srctextpos, prefs, prefs_hash, clone_targets, actual_flags = parse_cache_header(io, cachefile)
if isempty(modules)
Expand Down Expand Up @@ -4203,5 +4228,5 @@ end

precompile(include_package_for_output, (PkgId, String, Vector{String}, Vector{String}, Vector{String}, typeof(_concrete_dependencies), Nothing)) || @assert false
precompile(include_package_for_output, (PkgId, String, Vector{String}, Vector{String}, Vector{String}, typeof(_concrete_dependencies), String)) || @assert false
precompile(create_expr_cache, (PkgId, String, String, String, typeof(_concrete_dependencies), Cmd, IO, IO)) || @assert false
precompile(create_expr_cache, (PkgId, String, String, Nothing, typeof(_concrete_dependencies), Cmd, IO, IO)) || @assert false
precompile(create_expr_cache, (PkgId, String, String, String, typeof(_concrete_dependencies), Cmd, CacheFlags, IO, IO)) || @assert false
precompile(create_expr_cache, (PkgId, String, String, Nothing, typeof(_concrete_dependencies), Cmd, CacheFlags, IO, IO)) || @assert false
Loading

0 comments on commit a9b6ad9

Please sign in to comment.