From c02e900afbaf9a59ea70eed4ebb61cad6f372a44 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Tue, 15 Aug 2017 16:00:41 -0400 Subject: [PATCH] remove fallback constructor from Core.Inference Instead, define explicit constructors for built-in integer types in boot.jl. --- base/array.jl | 2 +- base/boot.jl | 167 ++++++++++++++++++++++++++++++++++++++++++++++++ base/coreimg.jl | 3 - base/int.jl | 60 +---------------- src/jltypes.c | 2 + 5 files changed, 172 insertions(+), 62 deletions(-) diff --git a/base/array.jl b/base/array.jl index 1141b364e2c0a..262362dd9e167 100644 --- a/base/array.jl +++ b/base/array.jl @@ -449,7 +449,7 @@ for (fname, felt) in ((:zeros,:zero), (:ones,:one)) $fname(a::AbstractArray, T::Type, dims...) = fill!(similar(a,T,dims...), $felt(T)) $fname(a::AbstractArray, T::Type=eltype(a)) = fill!(similar(a,T), $felt(T)) - $fname(T::Type, dims::Tuple) = fill!(Array{T}(Dims(dims)), $felt(T)) + $fname(T::Type, dims::Tuple) = fill!(Array{T}(convert(Dims, dims)::Dims), $felt(T)) $fname(dims::Tuple) = ($fname)(Float64, dims) $fname(T::Type, dims...) = $fname(T, dims) $fname(dims...) = $fname(dims) diff --git a/base/boot.jl b/base/boot.jl index be8f10aadd8dd..0ca5a25729800 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -200,6 +200,10 @@ mutable struct ErrorException <: Exception ErrorException(msg::AbstractString) = new(msg) end +macro _inline_meta() + Expr(:meta, :inline) +end + macro _noinline_meta() Expr(:meta, :noinline) end @@ -437,4 +441,167 @@ show(@nospecialize a) = show(STDOUT, a) print(@nospecialize a...) = print(STDOUT, a...) println(@nospecialize a...) = println(STDOUT, a...) +# constructors for built-in types + +import .Intrinsics: eq_int, trunc_int, lshr_int, sub_int, shl_int, bitcast, sext_int, zext_int, and_int + +throw_inexacterror(f::Symbol, T::Type, val) = (@_noinline_meta; throw(InexactError(f, T, val))) + +function is_top_bit_set(x) + @_inline_meta + eq_int(trunc_int(Int8, lshr_int(x, sub_int(shl_int(sizeof(x), 3), 1))), trunc_int(Int8, 1)) +end + +function check_top_bit(x) + @_inline_meta + is_top_bit_set(x) && throw_inexacterror(:check_top_bit, typeof(x), x) + x +end + +function checked_trunc_sint(::Type{To}, x::From) where {To,From} + @_inline_meta + y = trunc_int(To, x) + back = sext_int(From, y) + eq_int(x, back) || throw_inexacterror(:trunc, To, x) + y +end + +function checked_trunc_uint(::Type{To}, x::From) where {To,From} + @_inline_meta + y = trunc_int(To, x) + back = zext_int(From, y) + eq_int(x, back) || throw_inexacterror(:trunc, To, x) + y +end + +toInt8(x::Int8) = x +toInt8(x::Int16) = checked_trunc_sint(Int8, x) +toInt8(x::Int32) = checked_trunc_sint(Int8, x) +toInt8(x::Int64) = checked_trunc_sint(Int8, x) +toInt8(x::Int128) = checked_trunc_sint(Int8, x) +toInt8(x::UInt8) = bitcast(Int8, check_top_bit(x)) +toInt8(x::UInt16) = checked_trunc_sint(Int8, check_top_bit(x)) +toInt8(x::UInt32) = checked_trunc_sint(Int8, check_top_bit(x)) +toInt8(x::UInt64) = checked_trunc_sint(Int8, check_top_bit(x)) +toInt8(x::UInt128) = checked_trunc_sint(Int8, check_top_bit(x)) +toInt8(x::Bool) = and_int(zext_int(Int8, x), Int8(1)) +toInt16(x::Int8) = sext_int(Int16, x) +toInt16(x::Int16) = x +toInt16(x::Int32) = checked_trunc_sint(Int16, x) +toInt16(x::Int64) = checked_trunc_sint(Int16, x) +toInt16(x::Int128) = checked_trunc_sint(Int16, x) +toInt16(x::UInt8) = zext_int(Int16, x) +toInt16(x::UInt16) = bitcast(Int16, check_top_bit(x)) +toInt16(x::UInt32) = checked_trunc_sint(Int16, check_top_bit(x)) +toInt16(x::UInt64) = checked_trunc_sint(Int16, check_top_bit(x)) +toInt16(x::UInt128) = checked_trunc_sint(Int16, check_top_bit(x)) +toInt16(x::Bool) = and_int(zext_int(Int16, x), Int16(1)) +toInt32(x::Int8) = sext_int(Int32, x) +toInt32(x::Int16) = sext_int(Int32, x) +toInt32(x::Int32) = x +toInt32(x::Int64) = checked_trunc_sint(Int32, x) +toInt32(x::Int128) = checked_trunc_sint(Int32, x) +toInt32(x::UInt8) = zext_int(Int32, x) +toInt32(x::UInt16) = zext_int(Int32, x) +toInt32(x::UInt32) = bitcast(Int32, check_top_bit(x)) +toInt32(x::UInt64) = checked_trunc_sint(Int32, check_top_bit(x)) +toInt32(x::UInt128) = checked_trunc_sint(Int32, check_top_bit(x)) +toInt32(x::Bool) = and_int(zext_int(Int32, x), Int32(1)) +toInt64(x::Int8) = sext_int(Int64, x) +toInt64(x::Int16) = sext_int(Int64, x) +toInt64(x::Int32) = sext_int(Int64, x) +toInt64(x::Int64) = x +toInt64(x::Int128) = checked_trunc_sint(Int64, x) +toInt64(x::UInt8) = zext_int(Int64, x) +toInt64(x::UInt16) = zext_int(Int64, x) +toInt64(x::UInt32) = zext_int(Int64, x) +toInt64(x::UInt64) = bitcast(Int64, check_top_bit(x)) +toInt64(x::UInt128) = checked_trunc_sint(Int64, check_top_bit(x)) +toInt64(x::Bool) = and_int(zext_int(Int64, x), Int64(1)) +toInt128(x::Int8) = sext_int(Int128, x) +toInt128(x::Int16) = sext_int(Int128, x) +toInt128(x::Int32) = sext_int(Int128, x) +toInt128(x::Int64) = sext_int(Int128, x) +toInt128(x::Int128) = x +toInt128(x::UInt8) = zext_int(Int128, x) +toInt128(x::UInt16) = zext_int(Int128, x) +toInt128(x::UInt32) = zext_int(Int128, x) +toInt128(x::UInt64) = zext_int(Int128, x) +toInt128(x::UInt128) = bitcast(Int128, check_top_bit(x)) +toInt128(x::Bool) = and_int(zext_int(Int128, x), Int128(1)) +toUInt8(x::Int8) = bitcast(UInt8, check_top_bit(x)) +toUInt8(x::Int16) = checked_trunc_uint(UInt8, x) +toUInt8(x::Int32) = checked_trunc_uint(UInt8, x) +toUInt8(x::Int64) = checked_trunc_uint(UInt8, x) +toUInt8(x::Int128) = checked_trunc_uint(UInt8, x) +toUInt8(x::UInt8) = x +toUInt8(x::UInt16) = checked_trunc_uint(UInt8, x) +toUInt8(x::UInt32) = checked_trunc_uint(UInt8, x) +toUInt8(x::UInt64) = checked_trunc_uint(UInt8, x) +toUInt8(x::UInt128) = checked_trunc_uint(UInt8, x) +toUInt8(x::Bool) = and_int(zext_int(UInt8, x), UInt8(1)) +toUInt16(x::Int8) = sext_int(UInt16, check_top_bit(x)) +toUInt16(x::Int16) = bitcast(UInt16, check_top_bit(x)) +toUInt16(x::Int32) = checked_trunc_uint(UInt16, x) +toUInt16(x::Int64) = checked_trunc_uint(UInt16, x) +toUInt16(x::Int128) = checked_trunc_uint(UInt16, x) +toUInt16(x::UInt8) = zext_int(UInt16, x) +toUInt16(x::UInt16) = x +toUInt16(x::UInt32) = checked_trunc_uint(UInt16, x) +toUInt16(x::UInt64) = checked_trunc_uint(UInt16, x) +toUInt16(x::UInt128) = checked_trunc_uint(UInt16, x) +toUInt16(x::Bool) = and_int(zext_int(UInt16, x), UInt16(1)) +toUInt32(x::Int8) = sext_int(UInt32, check_top_bit(x)) +toUInt32(x::Int16) = sext_int(UInt32, check_top_bit(x)) +toUInt32(x::Int32) = bitcast(UInt32, check_top_bit(x)) +toUInt32(x::Int64) = checked_trunc_uint(UInt32, x) +toUInt32(x::Int128) = checked_trunc_uint(UInt32, x) +toUInt32(x::UInt8) = zext_int(UInt32, x) +toUInt32(x::UInt16) = zext_int(UInt32, x) +toUInt32(x::UInt32) = x +toUInt32(x::UInt64) = checked_trunc_uint(UInt32, x) +toUInt32(x::UInt128) = checked_trunc_uint(UInt32, x) +toUInt32(x::Bool) = and_int(zext_int(UInt32, x), UInt32(1)) +toUInt64(x::Int8) = sext_int(UInt64, check_top_bit(x)) +toUInt64(x::Int16) = sext_int(UInt64, check_top_bit(x)) +toUInt64(x::Int32) = sext_int(UInt64, check_top_bit(x)) +toUInt64(x::Int64) = bitcast(UInt64, check_top_bit(x)) +toUInt64(x::Int128) = checked_trunc_uint(UInt64, x) +toUInt64(x::UInt8) = zext_int(UInt64, x) +toUInt64(x::UInt16) = zext_int(UInt64, x) +toUInt64(x::UInt32) = zext_int(UInt64, x) +toUInt64(x::UInt64) = x +toUInt64(x::UInt128) = checked_trunc_uint(UInt64, x) +toUInt64(x::Bool) = and_int(zext_int(UInt64, x), UInt64(1)) +toUInt128(x::Int8) = sext_int(UInt128, check_top_bit(x)) +toUInt128(x::Int16) = sext_int(UInt128, check_top_bit(x)) +toUInt128(x::Int32) = sext_int(UInt128, check_top_bit(x)) +toUInt128(x::Int64) = sext_int(UInt128, check_top_bit(x)) +toUInt128(x::Int128) = bitcast(UInt128, check_top_bit(x)) +toUInt128(x::UInt8) = zext_int(UInt128, x) +toUInt128(x::UInt16) = zext_int(UInt128, x) +toUInt128(x::UInt32) = zext_int(UInt128, x) +toUInt128(x::UInt64) = zext_int(UInt128, x) +toUInt128(x::UInt128) = x +toUInt128(x::Bool) = and_int(zext_int(UInt128, x), UInt128(1)) + +# TODO: this is here to work around the 4 method limit in inference (#23210). +const BuiltinInts = Union{Int128, Int16, Int32, Int64, Int8, UInt128, UInt16, UInt32, UInt64, UInt8, Bool} +Int8(x::BuiltinInts) = toInt8(x)::Int8 +Int16(x::BuiltinInts) = toInt16(x)::Int16 +Int32(x::BuiltinInts) = toInt32(x)::Int32 +Int64(x::BuiltinInts) = toInt64(x)::Int64 +Int128(x::BuiltinInts) = toInt128(x)::Int128 +UInt8(x::BuiltinInts) = toUInt8(x)::UInt8 +UInt16(x::BuiltinInts) = toUInt16(x)::UInt16 +UInt32(x::BuiltinInts) = toUInt32(x)::UInt32 +UInt64(x::BuiltinInts) = toUInt64(x)::UInt64 +UInt128(x::BuiltinInts) = toUInt128(x)::UInt128 + +Bool(x::Bool) = x + +Int(x::Ptr) = bitcast(Int, x) +UInt(x::Ptr) = bitcast(UInt, x) +Ptr{T}(x::Union{Int,UInt,Ptr}) where {T} = bitcast(Ptr{T}, x) + ccall(:jl_set_istopmod, Void, (Any, Bool), Core, true) diff --git a/base/coreimg.jl b/base/coreimg.jl index 200bce4d7a8e8..2a5f13baf72a2 100644 --- a/base/coreimg.jl +++ b/base/coreimg.jl @@ -12,9 +12,6 @@ eval(m, x) = Core.eval(m, x) include(x) = Core.include(Inference, x) include(mod, x) = Core.include(mod, x) -# conditional to allow redefining Core.Inference after base exists -isdefined(Main, :Base) || ((::Type{T})(arg) where {T} = convert(T, arg)::T) - function return_type end ## Load essential files and libraries diff --git a/base/int.jl b/base/int.jl index 7650c6e5a1bb6..ec19107cde7c0 100644 --- a/base/int.jl +++ b/base/int.jl @@ -31,8 +31,8 @@ const BitUnsigned64T = Union{Type{UInt8}, Type{UInt16}, Type{UInt32}, Type{UIn const BitIntegerType = Union{map(T->Type{T}, BitInteger_types)...} -throw_inexacterror(f::Symbol, ::Type{T}, val) where T = - (@_noinline_meta; throw(InexactError(f, T, val))) +# calls constructors defined in boot.jl +convert(T::BitIntegerType, x::Union{BitInteger, Bool}) = T(x) ## integer comparisons ## @@ -420,75 +420,19 @@ trailing_ones(x::Integer) = trailing_zeros(~x) >>>(x::BitInteger, y::Int) = select_value(0 <= y, x >>> unsigned(y), x << unsigned(-y)) -function is_top_bit_set(x::BitInteger) - @_inline_meta - lshr_int(x, (sizeof(x) << 0x03) - 1) == rem(0x01, typeof(x)) -end -function check_top_bit(x::BitInteger) - @_inline_meta - is_top_bit_set(x) && throw_inexacterror(:check_top_bit, typeof(x), x) - x -end - -## integer conversions ## - -function checked_trunc_sint(::Type{To}, x::From) where {To,From} - @_inline_meta - y = trunc_int(To, x) - back = sext_int(From, y) - x == back || throw_inexacterror(:trunc, To, x) - y -end - -function checked_trunc_uint(::Type{To}, x::From) where {To,From} - @_inline_meta - y = trunc_int(To, x) - back = zext_int(From, y) - x == back || throw_inexacterror(:trunc, To, x) - y -end - for to in BitInteger_types, from in (BitInteger_types..., Bool) if !(to === from) if to.size < from.size - if to <: Signed - if from <: Unsigned - @eval convert(::Type{$to}, x::($from)) = - checked_trunc_sint($to, check_top_bit(x)) - else - @eval convert(::Type{$to}, x::($from)) = - checked_trunc_sint($to, x) - end - else - @eval convert(::Type{$to}, x::($from)) = - checked_trunc_uint($to, x) - end @eval rem(x::($from), ::Type{$to}) = trunc_int($to, x) elseif from === Bool - # Bools use i8 storage and may have garbage in their 7 high bits - @eval convert(::Type{$to}, x::($from)) = zext_int($to, x) & $to(1) @eval rem(x::($from), ::Type{$to}) = convert($to, x) elseif from.size < to.size if from <: Signed - if to <: Unsigned - @eval convert(::Type{$to}, x::($from)) = - sext_int($to, check_top_bit(x)) - else - @eval convert(::Type{$to}, x::($from)) = - sext_int($to, x) - end @eval rem(x::($from), ::Type{$to}) = sext_int($to, x) else - @eval convert(::Type{$to}, x::($from)) = zext_int($to, x) @eval rem(x::($from), ::Type{$to}) = convert($to, x) end else - if !((from <: Signed) === (to <: Signed)) - # raise InexactError if x's top bit is set - @eval convert(::Type{$to}, x::($from)) = bitcast($to, check_top_bit(x)) - else - @eval convert(::Type{$to}, x::($from)) = bitcast($to, x) - end @eval rem(x::($from), ::Type{$to}) = bitcast($to, x) end end diff --git a/src/jltypes.c b/src/jltypes.c index 3a2bdcd00ffb9..cbadb8e5065ee 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -403,6 +403,8 @@ static void flatten_type_union(jl_value_t **types, size_t n, jl_value_t **out, s STATIC_INLINE const char *datatype_module_name(jl_value_t *t) { + if (((jl_datatype_t*)t)->name->module == NULL) + return NULL; return jl_symbol_name(((jl_datatype_t*)t)->name->module->name); }