Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backports for 1.8-rc2/1.8.0 #45946

Merged
merged 9 commits into from
Jul 8, 2022
28 changes: 17 additions & 11 deletions base/array.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1833,6 +1833,11 @@ function reverseind(a::AbstractVector, i::Integer)
first(li) + last(li) - i
end

# This implementation of `midpoint` is performance-optimized but safe
# only if `lo <= hi`.
midpoint(lo::T, hi::T) where T<:Integer = lo + ((hi - lo) >>> 0x01)
midpoint(lo::Integer, hi::Integer) = midpoint(promote(lo, hi)...)

"""
reverse!(v [, start=1 [, stop=length(v) ]]) -> v

Expand Down Expand Up @@ -1861,17 +1866,18 @@ julia> A
"""
function reverse!(v::AbstractVector, start::Integer, stop::Integer=lastindex(v))
s, n = Int(start), Int(stop)
liv = LinearIndices(v)
if n <= s # empty case; ok
elseif !(first(liv) ≤ s ≤ last(liv))
throw(BoundsError(v, s))
elseif !(first(liv) ≤ n ≤ last(liv))
throw(BoundsError(v, n))
end
r = n
@inbounds for i in s:div(s+n-1, 2)
v[i], v[r] = v[r], v[i]
r -= 1
if n > s # non-empty and non-trivial
liv = LinearIndices(v)
if !(first(liv) ≤ s ≤ last(liv))
throw(BoundsError(v, s))
elseif !(first(liv) ≤ n ≤ last(liv))
throw(BoundsError(v, n))
end
r = n
@inbounds for i in s:midpoint(s, n-1)
v[i], v[r] = v[r], v[i]
r -= 1
end
end
return v
end
Expand Down
2 changes: 1 addition & 1 deletion base/broadcast.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1172,7 +1172,7 @@ Base.@propagate_inbounds dotview(B::BitArray, i::BitArray) = BitMaskedBitArray(B
Base.show(io::IO, B::BitMaskedBitArray) = foreach(arg->show(io, arg), (typeof(B), (B.parent, B.mask)))
# Override materialize! to prevent the BitMaskedBitArray from escaping to an overrideable method
@inline materialize!(B::BitMaskedBitArray, bc::Broadcasted{<:Any,<:Any,typeof(identity),Tuple{Bool}}) = fill!(B, bc.args[1])
@inline materialize!(B::BitMaskedBitArray, bc::Broadcasted{<:Any}) = materialize!(SubArray(B.parent, to_indices(B.parent, (B.mask,))), bc)
@inline materialize!(B::BitMaskedBitArray, bc::Broadcasted{<:Any}) = materialize!(@inbounds(view(B.parent, B.mask)), bc)
function Base.fill!(B::BitMaskedBitArray, b::Bool)
Bc = B.parent.chunks
Ic = B.mask.chunks
Expand Down
24 changes: 8 additions & 16 deletions base/reinterpretarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -152,23 +152,15 @@ strides(a::Union{DenseArray,StridedReshapedArray,StridedReinterpretArray}) = siz
stride(A::Union{DenseArray,StridedReshapedArray,StridedReinterpretArray}, k::Integer) =
k ≤ ndims(A) ? strides(A)[k] : length(A)

function strides(a::ReshapedReinterpretArray)
ap = parent(a)
els, elp = elsize(a), elsize(ap)
stp = strides(ap)
els == elp && return stp
els < elp && return (1, _checked_strides(stp, els, elp)...)
function strides(a::ReinterpretArray{T,<:Any,S,<:AbstractArray{S},IsReshaped}) where {T,S,IsReshaped}
_checkcontiguous(Bool, a) && return size_to_strides(1, size(a))
stp = strides(parent(a))
els, elp = sizeof(T), sizeof(S)
els == elp && return stp # 0dim parent is also handled here.
IsReshaped && els < elp && return (1, _checked_strides(stp, els, elp)...)
stp[1] == 1 || throw(ArgumentError("Parent must be contiguous in the 1st dimension!"))
return _checked_strides(tail(stp), els, elp)
end

function strides(a::NonReshapedReinterpretArray)
ap = parent(a)
els, elp = elsize(a), elsize(ap)
stp = strides(ap)
els == elp && return stp
stp[1] == 1 || throw(ArgumentError("Parent must be contiguous in the 1st dimension!"))
return (1, _checked_strides(tail(stp), els, elp)...)
st′ = _checked_strides(tail(stp), els, elp)
return IsReshaped ? st′ : (1, st′...)
end

@inline function _checked_strides(stp::Tuple, els::Integer, elp::Integer)
Expand Down
49 changes: 43 additions & 6 deletions base/reshapedarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -294,14 +294,51 @@ unsafe_convert(::Type{Ptr{T}}, V::SubArray{T,N,P,<:Tuple{Vararg{Union{RangeIndex
unsafe_convert(Ptr{T}, V.parent) + (first_index(V)-1)*sizeof(T)


_checkcontiguous(::Type{Bool}, A::AbstractArray) = size_to_strides(1, size(A)...) == strides(A)
_checkcontiguous(::Type{Bool}, A::Array) = true
_checkcontiguous(::Type{Bool}, A::AbstractArray) = false
# `strides(A::DenseArray)` calls `size_to_strides` by default.
# Thus it's OK to assume all `DenseArray`s are contiguously stored.
_checkcontiguous(::Type{Bool}, A::DenseArray) = true
_checkcontiguous(::Type{Bool}, A::ReshapedArray) = _checkcontiguous(Bool, parent(A))
_checkcontiguous(::Type{Bool}, A::FastContiguousSubArray) = _checkcontiguous(Bool, parent(A))

function strides(a::ReshapedArray)
# We can handle non-contiguous parent if it's a StridedVector
ndims(parent(a)) == 1 && return size_to_strides(only(strides(parent(a))), size(a)...)
_checkcontiguous(Bool, a) || throw(ArgumentError("Parent must be contiguous."))
size_to_strides(1, size(a)...)
_checkcontiguous(Bool, a) && return size_to_strides(1, size(a)...)
apsz::Dims = size(a.parent)
apst::Dims = strides(a.parent)
msz, mst, n = merge_adjacent_dim(apsz, apst) # Try to perform "lazy" reshape
n == ndims(a.parent) && return size_to_strides(mst, size(a)...) # Parent is stridevector like
return _reshaped_strides(size(a), 1, msz, mst, n, apsz, apst)
end

function _reshaped_strides(::Dims{0}, reshaped::Int, msz::Int, ::Int, ::Int, ::Dims, ::Dims)
reshaped == msz && return ()
throw(ArgumentError("Input is not strided."))
end
function _reshaped_strides(sz::Dims, reshaped::Int, msz::Int, mst::Int, n::Int, apsz::Dims, apst::Dims)
st = reshaped * mst
reshaped = reshaped * sz[1]
if length(sz) > 1 && reshaped == msz && sz[2] != 1
msz, mst, n = merge_adjacent_dim(apsz, apst, n + 1)
reshaped = 1
end
sts = _reshaped_strides(tail(sz), reshaped, msz, mst, n, apsz, apst)
return (st, sts...)
end

merge_adjacent_dim(::Dims{0}, ::Dims{0}) = 1, 1, 0
merge_adjacent_dim(apsz::Dims{1}, apst::Dims{1}) = apsz[1], apst[1], 1
function merge_adjacent_dim(apsz::Dims{N}, apst::Dims{N}, n::Int = 1) where {N}
sz, st = apsz[n], apst[n]
while n < N
szₙ, stₙ = apsz[n+1], apst[n+1]
if sz == 1
sz, st = szₙ, stₙ
elseif stₙ == st * sz || szₙ == 1
sz *= szₙ
else
break
end
n += 1
end
return sz, st, n
end
17 changes: 6 additions & 11 deletions base/sort.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ using .Base: copymutable, LinearIndices, length, (:),
AbstractMatrix, AbstractUnitRange, isless, identity, eltype, >, <, <=, >=, |, +, -, *, !,
extrema, sub_with_overflow, add_with_overflow, oneunit, div, getindex, setindex!,
length, resize!, fill, Missing, require_one_based_indexing, keytype,
UnitRange, max, min
UnitRange, max, min, midpoint

using .Base: >>>, !==

Expand Down Expand Up @@ -166,11 +166,6 @@ same thing as `partialsort!` but leaving `v` unmodified.
partialsort(v::AbstractVector, k::Union{Integer,OrdinalRange}; kws...) =
partialsort!(copymutable(v), k; kws...)

# This implementation of `midpoint` is performance-optimized but safe
# only if `lo <= hi`.
midpoint(lo::T, hi::T) where T<:Integer = lo + ((hi - lo) >>> 0x01)
midpoint(lo::Integer, hi::Integer) = midpoint(promote(lo, hi)...)

# reference on sorted binary search:
# http:https://www.tbray.org/ongoing/When/200x/2003/03/22/Binary

Expand Down Expand Up @@ -505,12 +500,12 @@ function sort!(v::AbstractVector, lo::Integer, hi::Integer, ::InsertionSortAlg,
j = i
x = v[i]
while j > lo
if lt(o, x, v[j-1])
v[j] = v[j-1]
j -= 1
continue
y = v[j-1]
if !lt(o, x, y)
break
end
break
v[j] = y
j -= 1
end
v[j] = x
end
Expand Down
5 changes: 5 additions & 0 deletions src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,11 @@ PUBLIC_HEADER_TARGETS := $(addprefix $(build_includedir)/julia/,$(notdir $(PUBLI
LLVM_LDFLAGS := $(shell $(LLVM_CONFIG_HOST) --ldflags)
LLVM_CXXFLAGS := $(shell $(LLVM_CONFIG_HOST) --cxxflags)

# llvm-config --cxxflags does not return -DNDEBUG
ifeq ($(shell $(LLVM_CONFIG_HOST) --assertion-mode),OFF)
LLVM_CXXFLAGS += -DNDEBUG
endif

ifeq ($(JULIACODEGEN),LLVM)
ifneq ($(USE_SYSTEM_LLVM),0)
CG_LLVMLINK += $(LLVM_LDFLAGS) $(shell $(LLVM_CONFIG_HOST) --libs --system-libs)
Expand Down
1 change: 1 addition & 0 deletions src/jl_uv.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ void JL_UV_LOCK(void)
}
else {
jl_atomic_fetch_add_relaxed(&jl_uv_n_waiters, 1);
jl_fence(); // [^store_buffering_2]
jl_wake_libuv();
JL_LOCK(&jl_uv_mutex);
jl_atomic_fetch_add_relaxed(&jl_uv_n_waiters, -1);
Expand Down
35 changes: 25 additions & 10 deletions src/jltypes.c
Original file line number Diff line number Diff line change
Expand Up @@ -420,10 +420,8 @@ static int datatype_name_cmp(jl_value_t *a, jl_value_t *b) JL_NOTSAFEPOINT

// sort singletons first, then DataTypes, then UnionAlls,
// ties broken alphabetically including module name & type parameters
static int union_sort_cmp(const void *ap, const void *bp) JL_NOTSAFEPOINT
static int union_sort_cmp(jl_value_t *a, jl_value_t *b) JL_NOTSAFEPOINT
{
jl_value_t *a = *(jl_value_t**)ap;
jl_value_t *b = *(jl_value_t**)bp;
if (a == NULL)
return b == NULL ? 0 : 1;
if (b == NULL)
Expand Down Expand Up @@ -458,16 +456,33 @@ static int union_sort_cmp(const void *ap, const void *bp) JL_NOTSAFEPOINT
}
}

static void isort_union(jl_value_t **a, size_t len) JL_NOTSAFEPOINT
{
size_t i, j;
for (i = 1; i < len; i++) {
jl_value_t *x = a[i];
for (j = i; j > 0; j--) {
jl_value_t *y = a[j - 1];
if (!(union_sort_cmp(x, y) < 0))
break;
a[j] = y;
}
a[j] = x;
}
}

JL_DLLEXPORT jl_value_t *jl_type_union(jl_value_t **ts, size_t n)
{
if (n == 0) return (jl_value_t*)jl_bottom_type;
if (n == 0)
return (jl_value_t*)jl_bottom_type;
size_t i;
for(i=0; i < n; i++) {
for (i = 0; i < n; i++) {
jl_value_t *pi = ts[i];
if (!(jl_is_type(pi) || jl_is_typevar(pi)))
jl_type_error("Union", (jl_value_t*)jl_type_type, pi);
}
if (n == 1) return ts[0];
if (n == 1)
return ts[0];

size_t nt = count_union_components(ts, n);
jl_value_t **temp;
Expand All @@ -476,9 +491,9 @@ JL_DLLEXPORT jl_value_t *jl_type_union(jl_value_t **ts, size_t n)
flatten_type_union(ts, n, temp, &count);
assert(count == nt);
size_t j;
for(i=0; i < nt; i++) {
int has_free = temp[i]!=NULL && jl_has_free_typevars(temp[i]);
for(j=0; j < nt; j++) {
for (i = 0; i < nt; i++) {
int has_free = temp[i] != NULL && jl_has_free_typevars(temp[i]);
for (j = 0; j < nt; j++) {
if (j != i && temp[i] && temp[j]) {
if (temp[i] == jl_bottom_type ||
temp[j] == (jl_value_t*)jl_any_type ||
Expand All @@ -490,7 +505,7 @@ JL_DLLEXPORT jl_value_t *jl_type_union(jl_value_t **ts, size_t n)
}
}
}
qsort(temp, nt, sizeof(jl_value_t*), union_sort_cmp);
isort_union(temp, nt);
jl_value_t **ptu = &temp[nt];
*ptu = jl_bottom_type;
int k;
Expand Down
11 changes: 9 additions & 2 deletions src/partr.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,14 @@ static const int16_t sleeping = 1;
// * 2a: `multiq_insert`
// * 2b: `jl_atomic_load_relaxed(&ptls->sleep_check_state)` in `jl_wakeup_thread` returns `not_sleeping`
// i.e., the dequeuer misses the enqueue and enqueuer misses the sleep state transition.

// [^store_buffering_2]: and also
// * Enqueuer:
// * 1a: `jl_atomic_store_relaxed(jl_uv_n_waiters, 1)` in `JL_UV_LOCK`
// * 1b: "cheap read" of `handle->pending` in `uv_async_send` (via `JL_UV_LOCK`) loads `0`
// * Dequeuer:
// * 2a: store `2` to `handle->pending` in `uv_async_send` (via `JL_UV_LOCK` in `jl_task_get_next`)
// * 2b: `jl_atomic_load_relaxed(jl_uv_n_waiters)` in `jl_task_get_next` returns `0`
// i.e., the dequeuer misses the `n_waiters` is set and enqueuer misses the `uv_stop` flag (in `signal_async`) transition to cleared

JULIA_DEBUG_SLEEPWAKE(
uint64_t wakeup_enter;
Expand Down Expand Up @@ -462,7 +469,7 @@ static int may_sleep(jl_ptls_t ptls) JL_NOTSAFEPOINT
// by the thread itself. As a result, if this returns false, it will
// continue returning false. If it returns true, we know the total
// modification order of the fences.
jl_fence(); // [^store_buffering_1]
jl_fence(); // [^store_buffering_1] [^store_buffering_2]
return jl_atomic_load_relaxed(&ptls->sleep_check_state) == sleeping;
}

Expand Down
71 changes: 52 additions & 19 deletions stdlib/LinearAlgebra/src/blas.jl
Original file line number Diff line number Diff line change
Expand Up @@ -169,18 +169,19 @@ end
# Level 1
# A help function to pick the pointer and inc for 1d like inputs.
@inline function vec_pointer_stride(x::AbstractArray, stride0check = nothing)
isdense(x) && return pointer(x), 1 # simpify runtime check when possibe
ndims(x) == 1 || strides(x) == Base.size_to_strides(stride(x, 1), size(x)...) ||
throw(ArgumentError("only support vector like inputs"))
st = stride(x, 1)
Base._checkcontiguous(Bool, x) && return pointer(x), 1 # simpify runtime check when possibe
st, ptr = checkedstride(x), pointer(x)
isnothing(stride0check) || (st == 0 && throw(stride0check))
ptr = st > 0 ? pointer(x) : pointer(x, lastindex(x))
ptr += min(st, 0) * sizeof(eltype(x)) * (length(x) - 1)
ptr, st
end
isdense(x) = x isa DenseArray
isdense(x::Base.FastContiguousSubArray) = isdense(parent(x))
isdense(x::Base.ReshapedArray) = isdense(parent(x))
isdense(x::Base.ReinterpretArray) = isdense(parent(x))
function checkedstride(x::AbstractArray)
szs::Dims = size(x)
sts::Dims = strides(x)
_, st, n = Base.merge_adjacent_dim(szs, sts)
n === ndims(x) && return st
throw(ArgumentError("only support vector like inputs"))
end
## copy

"""
Expand Down Expand Up @@ -1565,11 +1566,27 @@ for (mfname, elty) in ((:dsymm_,:Float64),
require_one_based_indexing(A, B, C)
m, n = size(C)
j = checksquare(A)
if j != (side == 'L' ? m : n)
throw(DimensionMismatch(lazy"A has size $(size(A)), C has size ($m,$n)"))
end
if size(B,2) != n
throw(DimensionMismatch(lazy"B has second dimension $(size(B,2)) but needs to match second dimension of C, $n"))
M, N = size(B)
if side == 'L'
if j != m
throw(DimensionMismatch(lazy"A has first dimension $j but needs to match first dimension of C, $m"))
end
if N != n
throw(DimensionMismatch(lazy"B has second dimension $N but needs to match second dimension of C, $n"))
end
if j != M
throw(DimensionMismatch(lazy"A has second dimension $j but needs to match first dimension of B, $M"))
end
else
if j != n
throw(DimensionMismatch(lazy"B has second dimension $j but needs to match second dimension of C, $n"))
end
if N != j
throw(DimensionMismatch(lazy"A has second dimension $N but needs to match first dimension of B, $j"))
end
if M != m
throw(DimensionMismatch(lazy"A has first dimension $M but needs to match first dimension of C, $m"))
end
end
chkstride1(A)
chkstride1(B)
Expand Down Expand Up @@ -1639,11 +1656,27 @@ for (mfname, elty) in ((:zhemm_,:ComplexF64),
require_one_based_indexing(A, B, C)
m, n = size(C)
j = checksquare(A)
if j != (side == 'L' ? m : n)
throw(DimensionMismatch(lazy"A has size $(size(A)), C has size ($m,$n)"))
end
if size(B,2) != n
throw(DimensionMismatch(lazy"B has second dimension $(size(B,2)) but needs to match second dimension of C, $n"))
M, N = size(B)
if side == 'L'
if j != m
throw(DimensionMismatch(lazy"A has first dimension $j but needs to match first dimension of C, $m"))
end
if N != n
throw(DimensionMismatch(lazy"B has second dimension $N but needs to match second dimension of C, $n"))
end
if j != M
throw(DimensionMismatch(lazy"A has second dimension $j but needs to match first dimension of B, $M"))
end
else
if j != n
throw(DimensionMismatch(lazy"B has second dimension $j but needs to match second dimension of C, $n"))
end
if N != j
throw(DimensionMismatch(lazy"A has second dimension $N but needs to match first dimension of B, $j"))
end
if M != m
throw(DimensionMismatch(lazy"A has first dimension $M but needs to match first dimension of C, $m"))
end
end
chkstride1(A)
chkstride1(B)
Expand Down
2 changes: 1 addition & 1 deletion stdlib/LinearAlgebra/src/bunchkaufman.jl
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ BunchKaufman(A::AbstractMatrix{T}, ipiv::AbstractVector{<:Integer}, uplo::Abstra
BunchKaufman{T,typeof(A),typeof(ipiv)}(A, ipiv, uplo, symmetric, rook, info)
# backwards-compatible constructors (remove with Julia 2.0)
@deprecate(BunchKaufman(LD, ipiv, uplo, symmetric, rook, info) where {T,S},
BunchKaufman{T,S,typeof(ipiv)}(LD, ipiv, uplo, symmetric, rook, info))
BunchKaufman{T,S,typeof(ipiv)}(LD, ipiv, uplo, symmetric, rook, info), false)

# iteration for destructuring into components
Base.iterate(S::BunchKaufman) = (S.D, Val(:UL))
Expand Down
Loading