Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions Compiler/src/Compiler.jl
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,8 @@ using Core: ABIOverride, Builtin, CodeInstance, IntrinsicFunction, MethodInstanc
MethodTable, MethodCache, PartialOpaque, SimpleVector, TypeofVararg,
_apply_iterate, apply_type, compilerbarrier, donotdelete, memoryref_isassigned,
memoryrefget, memoryrefnew, memoryrefoffset, memoryrefset!, print, println, show, svec,
typename, unsafe_write, write
typename, unsafe_write, write, stdout, stderr

using Base
using Base: @_foldable_meta, @_gc_preserve_begin, @_gc_preserve_end, @nospecializeinfer,
PARTITION_KIND_GLOBAL, PARTITION_KIND_UNDEF_CONST, PARTITION_KIND_BACKDATED_CONST, PARTITION_KIND_DECLARED,
PARTITION_FLAG_DEPWARN,
Expand All @@ -64,7 +63,10 @@ using Base: @_foldable_meta, @_gc_preserve_begin, @_gc_preserve_end, @nospeciali
partition_restriction, quoted, rename_unionall, rewrap_unionall, specialize_method,
structdiff, tls_world_age, unconstrain_vararg_length, unionlen, uniontype_layout,
uniontypes, unsafe_convert, unwrap_unionall, unwrapva, vect, widen_diagonal,
_uncompressed_ir, maybe_add_binding_backedge!
_uncompressed_ir, maybe_add_binding_backedge!,
devnull, devnull as stdin

using Base
using Base.Order

import Base: ==, _topmod, append!, convert, copy, copy!, findall, first, get, get!,
Expand Down
8 changes: 6 additions & 2 deletions Compiler/src/abstractinterpretation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3444,9 +3444,13 @@ function refine_partial_type(@nospecialize t)
return t
end

abstract_eval_nonlinearized_foreigncall_name(interp::AbstractInterpreter, e, sstate::StatementState, sv::IRInterpretationState) = nothing
abstract_eval_nonlinearized_foreigncall_name(
::AbstractInterpreter, @nospecialize(e), ::StatementState, ::IRInterpretationState
) = nothing

function abstract_eval_nonlinearized_foreigncall_name(interp::AbstractInterpreter, e, sstate::StatementState, sv::AbsIntState)
function abstract_eval_nonlinearized_foreigncall_name(
interp::AbstractInterpreter, @nospecialize(e), sstate::StatementState, sv::InferenceState
)
if isexpr(e, :call)
n = length(e.args)
argtypes = Vector{Any}(undef, n)
Expand Down
2 changes: 2 additions & 0 deletions Compiler/src/opaque_closure.jl
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ function Core.OpaqueClosure(ir::IRCode, @nospecialize env...;
end
src.slotflags = fill(zero(UInt8), nargtypes)
src.slottypes = copy(ir.argtypes)
src.min_world = ir.valid_worlds.min_world
src.max_world = ir.valid_worlds.max_world
src.isva = isva
src.nargs = UInt(nargtypes)
src = ir_to_codeinf!(src, ir)
Expand Down
19 changes: 15 additions & 4 deletions Compiler/src/tfuncs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -586,15 +586,19 @@ add_tfunc(nfields, 1, 1, nfields_tfunc, 1)
add_tfunc(Core._expr, 1, INT_INF, @nospecs((𝕃::AbstractLattice, args...)->Expr), 100)
add_tfunc(svec, 0, INT_INF, @nospecs((𝕃::AbstractLattice, args...)->SimpleVector), 20)

@nospecs function _svec_len_tfunc(𝕃::AbstractLattice, s)
@nospecs function _svec_len_tfunc(::AbstractLattice, s)
if isa(s, Const) && isa(s.val, SimpleVector)
return Const(length(s.val))
end
return Int
end
add_tfunc(Core._svec_len, 1, 1, _svec_len_tfunc, 1)
@nospecs function _svec_len_nothrow(𝕃::AbstractLattice, s)
⊑ = partialorder(𝕃)
return s ⊑ SimpleVector
end

@nospecs function _svec_ref_tfunc(𝕃::AbstractLattice, s, i)
@nospecs function _svec_ref_tfunc(::AbstractLattice, s, i)
if isa(s, Const) && isa(i, Const)
s, i = s.val, i.val
if isa(s, SimpleVector) && isa(i, Int)
Expand All @@ -604,7 +608,7 @@ add_tfunc(Core._svec_len, 1, 1, _svec_len_tfunc, 1)
return Any
end
add_tfunc(Core._svec_ref, 2, 2, _svec_ref_tfunc, 1)
@nospecs function typevar_tfunc(𝕃::AbstractLattice, n, lb_arg, ub_arg)
@nospecs function typevar_tfunc(::AbstractLattice, n, lb_arg, ub_arg)
lb = Union{}
ub = Any
ub_certain = lb_certain = true
Expand Down Expand Up @@ -2363,7 +2367,7 @@ function _builtin_nothrow(𝕃::AbstractLattice, @nospecialize(f::Builtin), argt
return compilerbarrier_nothrow(argtypes[1], nothing)
elseif f === Core._svec_len
na == 1 || return false
return _svec_len_tfunc(𝕃, argtypes[1]) isa Const
return _svec_len_nothrow(𝕃, argtypes[1])
elseif f === Core._svec_ref
na == 2 || return false
return _svec_ref_tfunc(𝕃, argtypes[1], argtypes[2]) isa Const
Expand Down Expand Up @@ -2974,6 +2978,13 @@ function intrinsic_exct(𝕃::AbstractLattice, f::IntrinsicFunction, argtypes::V
return Union{}
end

if f === Intrinsics.add_ptr || f === Intrinsics.sub_ptr
if !(argtypes[1] ⊑ Ptr && argtypes[2] ⊑ UInt)
return TypeError
end
return Union{}
end

# The remaining intrinsics are math/bits/comparison intrinsics.
# All the non-floating point intrinsics work on primitive values of the same type.
isshift = f === shl_int || f === lshr_int || f === ashr_int
Expand Down
7 changes: 7 additions & 0 deletions Compiler/test/effects.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1438,6 +1438,11 @@ let effects = Base.infer_effects(Core.Intrinsics.pointerset, Tuple{Vararg{Any}})
@test Compiler.is_consistent(effects)
@test !Compiler.is_effect_free(effects)
end
@test Compiler.intrinsic_nothrow(Core.Intrinsics.add_ptr, Any[Ptr{Int}, UInt])
@test Compiler.intrinsic_nothrow(Core.Intrinsics.sub_ptr, Any[Ptr{Int}, UInt])
@test !Compiler.intrinsic_nothrow(Core.Intrinsics.add_ptr, Any[UInt, UInt])
@test !Compiler.intrinsic_nothrow(Core.Intrinsics.sub_ptr, Any[UInt, UInt])
@test Compiler.is_nothrow(Base.infer_effects(+, Tuple{Ptr{UInt8}, UInt}))
# effects modeling for atomic intrinsics
# these functions especially need to be marked !effect_free since they imply synchronization
for atomicfunc = Any[
Expand Down Expand Up @@ -1471,3 +1476,5 @@ let effects = Base.infer_effects((Core.SimpleVector,Int); optimize=false) do sve
@test !Compiler.is_nothrow(effects)
@test Compiler.is_terminates(effects)
end

@test Compiler.is_nothrow(Base.infer_effects(length, (Core.SimpleVector,)))
9 changes: 9 additions & 0 deletions Compiler/test/validation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@ using Test, Core.IR

include("setup_Compiler.jl")

@testset "stdio validation" begin
for s in (:stdout, :stderr, :print, :println, :write)
@test getglobal(Compiler, s) === getglobal(Core, s)
@test isconst(Compiler, s)
end
@test Compiler.stdin === devnull
@test isconst(Compiler, :stdin)
end

function f22938(a, b, x...)
nothing
nothing
Expand Down
6 changes: 6 additions & 0 deletions base/div.jl
Original file line number Diff line number Diff line change
Expand Up @@ -385,3 +385,9 @@ end
# NOTE: C89 fmod() and x87 FPREM implicitly provide truncating float division,
# so it is used here as the basis of float div().
div(x::T, y::T, r::RoundingMode) where {T<:AbstractFloat} = convert(T, round((x - rem(x, y, r)) / y))

# Vincent Lefèvre: "The Euclidean Division Implemented with a Floating-Point Division and a Floor"
# https://inria.hal.science/inria-00070403
# Theorem 1 implies that the following are exact if eps(x/y) <= 1
div(x::Float32, y::Float32, r::RoundingMode) = Float32(round(Float64(x) / Float64(y), r))
div(x::Float16, y::Float16, r::RoundingMode) = Float16(round(Float32(x) / Float32(y), r))
16 changes: 8 additions & 8 deletions base/errorshow.jl
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ function showerror(io::IO, ex::MethodError)
is_arg_types = !isa(ex.args, Tuple)
arg_types = is_arg_types ? ex.args : typesof(ex.args...)
arg_types_param::SimpleVector = (unwrap_unionall(arg_types)::DataType).parameters
san_arg_types_param = Any[rewrap_unionall(a, arg_types) for a in arg_types_param]
san_arg_types_param = Any[rewrap_unionall(arg_types_param[i], arg_types) for i in 1:length(arg_types_param)]
f = ex.f
meth = methods_including_ambiguous(f, arg_types)
if isa(meth, MethodList) && length(meth) > 1
Expand Down Expand Up @@ -399,10 +399,10 @@ function showerror_ambiguous(io::IO, meths, f, args::Type)
sigfix = typeintersect(m.sig, sigfix)
end
if isa(unwrap_unionall(sigfix), DataType) && sigfix <: Tuple
let sigfix=sigfix
if all(m->morespecific(sigfix, m.sig), meths)
let sigfix=Core.Box(sigfix)
if all(m->morespecific(sigfix.contents, m.sig), meths)
print(io, "\nPossible fix, define\n ")
show_tuple_as_call(io, :function, sigfix)
show_tuple_as_call(io, :function, sigfix.contents)
else
print(io, "To resolve the ambiguity, try making one of the methods more specific, or ")
print(io, "adding a new method more specific than any of the existing applicable methods.")
Expand Down Expand Up @@ -487,10 +487,10 @@ function show_method_candidates(io::IO, ex::MethodError, kwargs=[])
# If isvarargtype then it checks whether the rest of the input arguments matches
# the varargtype
if Base.isvarargtype(sig[i])
sigstr = (unwrapva(unwrap_unionall(sig[i])), "...")
sigstr = Core.svec(unwrapva(unwrap_unionall(sig[i])), "...")
j = length(t_i)
else
sigstr = (sig[i],)
sigstr = Core.svec(sig[i],)
j = i
end
# Checks if the type of arg 1:i of the input intersects with the current method
Expand Down Expand Up @@ -536,9 +536,9 @@ function show_method_candidates(io::IO, ex::MethodError, kwargs=[])
for (k, sigtype) in enumerate(sig[length(t_i)+1:end])
sigtype = isvarargtype(sigtype) ? unwrap_unionall(sigtype) : sigtype
if Base.isvarargtype(sigtype)
sigstr = (unwrapva(sigtype::Core.TypeofVararg), "...")
sigstr = Core.svec(unwrapva(sigtype::Core.TypeofVararg), "...")
else
sigstr = (sigtype,)
sigstr = Core.svec(sigtype,)
end
if !((min(length(t_i), length(sig)) == 0) && k==1)
print(iob, ", ")
Expand Down
1 change: 1 addition & 0 deletions base/experimental.jl
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,7 @@ the handler for that type.
This interface is experimental and subject to change or removal without notice.
"""
function show_error_hints(io, ex, args...)
@nospecialize
hinters = get(_hint_handlers, typeof(ex), nothing)
isnothing(hinters) && return
for handler in hinters
Expand Down
25 changes: 13 additions & 12 deletions base/float.jl
Original file line number Diff line number Diff line change
Expand Up @@ -808,13 +808,8 @@ precision(::Type{T}; base::Integer=2) where {T<:AbstractFloat} = _precision(T, b
precision(::T; base::Integer=2) where {T<:AbstractFloat} = precision(T; base)


"""
nextfloat(x::AbstractFloat, n::Integer)

The result of `n` iterative applications of `nextfloat` to `x` if `n >= 0`, or `-n`
applications of [`prevfloat`](@ref) if `n < 0`.
"""
function nextfloat(f::IEEEFloat, d::Integer)
function _nextfloat(f::IEEEFloat, dneg::Bool, da::Integer)
# da must be > 0
F = typeof(f)
fumax = reinterpret(Unsigned, F(Inf))
U = typeof(fumax)
Expand All @@ -824,8 +819,6 @@ function nextfloat(f::IEEEFloat, d::Integer)
fneg = fi < 0
fu = unsigned(fi & typemax(fi))

dneg = d < 0
da = uabs(d)
if da > typemax(U)
fneg = dneg
fu = fumax
Expand All @@ -852,6 +845,14 @@ function nextfloat(f::IEEEFloat, d::Integer)
reinterpret(F, fu)
end

"""
nextfloat(x::AbstractFloat, n::Integer)

The result of `n` iterative applications of `nextfloat` to `x` if `n >= 0`, or `-n`
applications of [`prevfloat`](@ref) if `n < 0`.
"""
nextfloat(f::AbstractFloat, d::Integer) = _nextfloat(f, isnegative(d), uabs(d))

"""
nextfloat(x::AbstractFloat)

Expand All @@ -860,23 +861,23 @@ If no such `y` exists (e.g. if `x` is `Inf` or `NaN`), then return `x`.

See also: [`prevfloat`](@ref), [`eps`](@ref), [`issubnormal`](@ref).
"""
nextfloat(x::AbstractFloat) = nextfloat(x,1)
nextfloat(x::AbstractFloat) = nextfloat(x, 1)

"""
prevfloat(x::AbstractFloat, n::Integer)

The result of `n` iterative applications of `prevfloat` to `x` if `n >= 0`, or `-n`
applications of [`nextfloat`](@ref) if `n < 0`.
"""
prevfloat(x::AbstractFloat, d::Integer) = nextfloat(x, -d)
prevfloat(x::AbstractFloat, d::Integer) = _nextfloat(x, ispositive(d), uabs(d))

"""
prevfloat(x::AbstractFloat)

Return the largest floating point number `y` of the same type as `x` such that `y < x`.
If no such `y` exists (e.g. if `x` is `-Inf` or `NaN`), then return `x`.
"""
prevfloat(x::AbstractFloat) = nextfloat(x,-1)
prevfloat(x::AbstractFloat) = nextfloat(x, -1)

for Ti in (Int8, Int16, Int32, Int64, Int128, UInt8, UInt16, UInt32, UInt64, UInt128)
for Tf in (Float16, Float32, Float64)
Expand Down
34 changes: 24 additions & 10 deletions base/intfuncs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ gcd(a::Rational) = checked_abs(a.num) // a.den
lcm(a::Union{Integer,Rational}) = gcd(a)
gcd(a::Unsigned, b::Signed) = gcd(promote(a, abs(b))...)
gcd(a::Signed, b::Unsigned) = gcd(promote(abs(a), b)...)
lcm(a::Unsigned, b::Signed) = lcm(promote(a, abs(b))...)
lcm(a::Signed, b::Unsigned) = lcm(promote(abs(a), b)...)
gcd(a::Real, b::Real) = gcd(promote(a,b)...)
lcm(a::Real, b::Real) = lcm(promote(a,b)...)
gcd(a::Real, b::Real, c::Real...) = gcd(a, gcd(b, c...))
Expand Down Expand Up @@ -252,6 +254,16 @@ function gcdx(a::Real, b::Real, cs::Real...)
d′, x, ys... = gcdx(d, cs...)
return d′, i*x, j*x, ys...
end
function gcdx(a::Signed, b::Unsigned)
R = promote_type(typeof(a), typeof(b))
_a = a % signed(R) # handle the case a == typemin(typeof(a)) if R != typeof(a)
d, u, v = gcdx(promote(abs(_a), b)...)
d, flipsign(u, a), v
end
function gcdx(a::Unsigned, b::Signed)
d, v, u = gcdx(b, a)
d, u, v
end

# multiplicative inverse of n mod m, error if none

Expand Down Expand Up @@ -477,18 +489,20 @@ julia> powermod(5, 3, 19)
function powermod(x::Integer, p::Integer, m::T) where T<:Integer
p == 0 && return mod(one(m),m)
# When the concrete type of p is signed and has the lowest value,
# `p != 0 && p == -p` is equivalent to `p == typemin(typeof(p))` for 2's complement representation.
# `p < 0 && p == -p` is equivalent to `p == typemin(typeof(p))` for 2's complement representation.
# but will work for integer types like `BigInt` that don't have `typemin` defined
# It needs special handling otherwise will cause overflow problem.
if p == -p
imod = invmod(x, m)
rhalf = powermod(imod, -(p÷2), m)
r::T = mod(widemul(rhalf, rhalf), m)
isodd(p) && (r = mod(widemul(r, imod), m))
#else odd
return r
elseif p < 0
return powermod(invmod(x, m), -p, m)
if p < 0
if p == -p
imod = invmod(x, m)
rhalf = powermod(imod, -(p÷2), m)
r::T = mod(widemul(rhalf, rhalf), m)
isodd(p) && (r = mod(widemul(r, imod), m))
#else odd
return r
else
return powermod(invmod(x, m), -p, m)
end
end
(m == 1 || m == -1) && return zero(m)
b = oftype(m,mod(x,m)) # this also checks for divide by zero
Expand Down
10 changes: 6 additions & 4 deletions base/iobuffer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -604,7 +604,8 @@ end
end
# The fast path here usually checks there is already room, then does nothing.
# When append is true, new data is added after io.size, not io.ptr
existing_space = min(lastindex(io.data), io.maxsize + get_offset(io)) - (io.append ? io.size : io.ptr - 1)
start_offset = io.append ? io.size : io.ptr - 1
existing_space = min(lastindex(io.data) - start_offset, io.maxsize - (start_offset - get_offset(io)))
if existing_space < nshort % Int
# Outline this function to make it more likely that ensureroom inlines itself
return ensureroom_slowpath(io, nshort, existing_space)
Expand Down Expand Up @@ -824,12 +825,13 @@ function unsafe_write(to::GenericIOBuffer, p::Ptr{UInt8}, nb::UInt)
append = to.append
ptr = append ? size+1 : to.ptr
data = to.data
to_write = min(nb, (min(Int(length(data))::Int, to.maxsize + get_offset(to)) - ptr + 1) % UInt) % Int
start_offset = ptr - 1
to_write = max(0, min(nb, (min(Int(length(data))::Int - start_offset, to.maxsize - (start_offset - get_offset(to)))) % UInt) % Int)
# Dispatch based on the type of data, to possibly allow using memcpy
_unsafe_write(data, p, ptr, to_write % UInt)
# Update to.size only if the ptr has advanced to higher than
# the previous size. Otherwise, we just overwrote existing data
to.size = max(size, ptr + to_write - 1)
to.size = max(size, start_offset + to_write)
# If to.append, we only update size, not ptr.
if !append
to.ptr = ptr + to_write
Expand Down Expand Up @@ -867,7 +869,7 @@ end
ptr = (to.append ? to.size+1 : to.ptr)
# We have just ensured there is room for 1 byte, EXCEPT if we were to exceed
# maxsize. So, we just need to check that here.
if ptr > to.maxsize + get_offset(to)
if ptr - get_offset(to) > to.maxsize
return 0
else
to.data[ptr] = a
Expand Down
8 changes: 7 additions & 1 deletion base/mpfr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -391,12 +391,18 @@ BigFloat(x::Union{Float16,Float32}, r::MPFRRoundingMode=rounding_raw(BigFloat);
BigFloat(Float64(x), r; precision=precision)

function BigFloat(x::Rational, r::MPFRRoundingMode=rounding_raw(BigFloat); precision::Integer=_precision_with_base_2(BigFloat))
r_den = _opposite_round(r)
setprecision(BigFloat, precision) do
setrounding_raw(BigFloat, r) do
BigFloat(numerator(x))::BigFloat / BigFloat(denominator(x))::BigFloat
BigFloat(numerator(x))::BigFloat / BigFloat(denominator(x), r_den)::BigFloat
end
end
end
function _opposite_round(r::MPFRRoundingMode)
r == MPFRRoundUp && return MPFRRoundDown
r == MPFRRoundDown && return MPFRRoundUp
return r
end

function tryparse(::Type{BigFloat}, s::AbstractString; base::Integer=0, precision::Integer=_precision_with_base_2(BigFloat), rounding::MPFRRoundingMode=rounding_raw(BigFloat))
!isempty(s) && isspace(s[end]) && return tryparse(BigFloat, rstrip(s), base = base)
Expand Down
3 changes: 2 additions & 1 deletion base/stream.jl
Original file line number Diff line number Diff line change
Expand Up @@ -617,7 +617,8 @@ end
function alloc_request(buffer::IOBuffer, recommended_size::UInt)
ensureroom(buffer, recommended_size)
ptr = buffer.append ? buffer.size + 1 : buffer.ptr
nb = min(length(buffer.data), buffer.maxsize + get_offset(buffer)) - ptr + 1
start_offset = ptr - 1
nb = max(0, min(length(buffer.data) - start_offset, buffer.maxsize - (start_offset - get_offset(buffer))))
return (Ptr{Cvoid}(pointer(buffer.data, ptr)), nb)
end

Expand Down
2 changes: 1 addition & 1 deletion stdlib/Mmap/src/Mmap.jl
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ function mmap(io::IO,
overflow && throw(ArgumentError("requested size prod($((len, dims...))) too large, would overflow typeof(size(T)) == $(typeof(len))"))
end
len >= 0 || throw(ArgumentError("requested size must be ≥ 0, got $len"))
len == 0 && return Array{T}(undef, ntuple(x->0,Val(N)))
len == 0 && return Array{T}(undef, dims)
len < typemax(Int) - PAGESIZE || throw(ArgumentError("requested size must be < $(typemax(Int)-PAGESIZE), got $len"))

offset >= 0 || throw(ArgumentError("requested offset must be ≥ 0, got $offset"))
Expand Down
Loading