Skip to content

Commit e4a979d

Browse files
authored
Merge pull request #40029 from JuliaLang/backports-release-1.6
Backports release 1.6-RC3
2 parents 4b6b9fe + 845a52b commit e4a979d

File tree

21 files changed

+235
-58
lines changed

21 files changed

+235
-58
lines changed

NEWS.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,10 @@ Standard library changes
164164
results table ([#38042]).
165165
* `@testset` now supports the option `verbose` to show the test result summary
166166
of the children even if they all pass ([#33755]).
167+
* In `LinearIndices(::Tuple)` and `CartesianIndices(::Tuple)`, integers (as opposed to ranges of integers) in the
168+
argument tuple now consistently describe 1-based ranges, e.g, `CartesianIndices((3, 1:3))` is equivalent to
169+
`CartesianIndices((1:3, 1:3))`. This is how tuples of integers have always been documented to work, but a
170+
bug had caused erroneous behaviors with heterogeneous tuples containing both integers and ranges ([#37829], [#37928]).
167171

168172
#### Package Manager
169173

base/compiler/ssair/passes.jl

Lines changed: 29 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -344,26 +344,13 @@ function lift_leaves(compact::IncrementalCompact, @nospecialize(stmt),
344344
else
345345
typ = compact_exprtype(compact, leaf)
346346
if !isa(typ, Const)
347+
# TODO: (disabled since #27126)
347348
# If the leaf is an old ssa value, insert a getfield here
348349
# We will revisit this getfield later when compaction gets
349350
# to the appropriate point.
350351
# N.B.: This can be a bit dangerous because it can lead to
351352
# infinite loops if we accidentally insert a node just ahead
352353
# of where we are
353-
if is_old(compact, leaf) && (isa(field, Int) || isa(field, Symbol))
354-
(isa(typ, DataType) && (!typ.abstract)) || return nothing
355-
@assert !typ.mutable
356-
# If there's the potential for an undefref error on access, we cannot insert a getfield
357-
if field > typ.ninitialized && !isbits(fieldtype(typ, field))
358-
return nothing
359-
lifted_leaves[leaf] = RefValue{Any}(insert_node!(compact, leaf, make_MaybeUndef(result_t), Expr(:call, :unchecked_getfield, SSAValue(leaf.id), field), true))
360-
maybe_undef = true
361-
else
362-
return nothing
363-
lifted_leaves[leaf] = RefValue{Any}(insert_node!(compact, leaf, result_t, Expr(:call, getfield, SSAValue(leaf.id), field), true))
364-
end
365-
continue
366-
end
367354
return nothing
368355
end
369356
leaf = typ.val
@@ -540,7 +527,6 @@ function getfield_elim_pass!(ir::IRCode)
540527
result_t = compact_exprtype(compact, SSAValue(idx))
541528
is_getfield = is_setfield = false
542529
is_ccall = false
543-
is_unchecked = false
544530
# Step 1: Check whether the statement we're looking at is a getfield/setfield!
545531
if is_known_call(stmt, setfield!, compact)
546532
is_setfield = true
@@ -580,9 +566,6 @@ function getfield_elim_pass!(ir::IRCode)
580566
(isa(c1, Const) && isa(c2, Const)) && continue
581567
lift_comparison!(compact, idx, c1, c2, stmt, lifting_cache)
582568
continue
583-
elseif isexpr(stmt, :call) && stmt.args[1] === :unchecked_getfield
584-
is_getfield = true
585-
is_unchecked = true
586569
elseif isexpr(stmt, :foreigncall)
587570
nccallargs = length(stmt.args[3]::SimpleVector)
588571
new_preserves = Any[]
@@ -701,11 +684,11 @@ function getfield_elim_pass!(ir::IRCode)
701684
val = perform_lifting!(compact, visited_phinodes, field, lifting_cache, result_t, lifted_leaves, stmt.args[2])
702685

703686
# Insert the undef check if necessary
704-
if any_undef && !is_unchecked
687+
if any_undef
705688
if val === nothing
706689
insert_node!(compact, SSAValue(idx), Nothing, Expr(:throw_undef_if_not, Symbol("##getfield##"), false))
707690
else
708-
insert_node!(compact, SSAValue(idx), Nothing, Expr(:undefcheck, Symbol("##getfield##"), val.x))
691+
# val must be defined
709692
end
710693
else
711694
@assert val !== nothing
@@ -939,16 +922,30 @@ function type_lift_pass!(ir::IRCode)
939922
stmt = insts[idx][:inst]
940923
stmt isa Expr || continue
941924
if (stmt.head === :isdefined || stmt.head === :undefcheck)
942-
val = (stmt.head === :isdefined) ? stmt.args[1] : stmt.args[2]
943-
# undef can only show up by being introduced in a phi
944-
# node (or an UpsilonNode() argument to a PhiC node),
945-
# so lift all these nodes that have maybe undef values
925+
# after optimization, undef can only show up by being introduced in
926+
# a phi node (or an UpsilonNode() argument to a PhiC node), so lift
927+
# all these nodes that have maybe undef values
928+
val = stmt.args[(stmt.head === :isdefined) ? 1 : 2]
929+
if stmt.head === :isdefined && (val isa Slot || val isa GlobalRef ||
930+
isexpr(val, :static_parameter) || val isa Argument || val isa Symbol)
931+
# this is a legal node, so assume it was not introduced by
932+
# slot2ssa (at worst, we might leave in a runtime check that
933+
# shouldn't have been there)
934+
continue
935+
end
936+
# otherwise, we definitely have a corrupt node from slot2ssa, and
937+
# must fix or delete that now
946938
processed = IdDict{Int, Union{SSAValue, Bool}}()
947-
while isa(val, SSAValue) && isa(insts[val.id][:inst], PiNode)
948-
val = (insts[val.id][:inst]::PiNode).val
939+
def = val
940+
while true
941+
# peek through PiNodes
942+
isa(val, SSAValue) || break
943+
def = insts[val.id][:inst]
944+
isa(def, PiNode) || break
945+
val = def.val
949946
end
950-
if !isa(val, SSAValue) || (!isa(insts[val.id][:inst], PhiNode) && !isa(insts[val.id][:inst], PhiCNode))
951-
(isa(val, GlobalRef) || isexpr(val, :static_parameter)) && continue
947+
if !isa(val, SSAValue) || (!isa(def, PhiNode) && !isa(def, PhiCNode))
948+
# in most cases, reaching this statement implies we had a value
952949
if stmt.head === :undefcheck
953950
insts[idx][:inst] = nothing
954951
else
@@ -958,7 +955,6 @@ function type_lift_pass!(ir::IRCode)
958955
end
959956
stmt_id = val.id
960957
worklist = Tuple{Int, Int, SSAValue, Int}[(stmt_id, 0, SSAValue(0), 0)]
961-
def = insts[stmt_id][:inst]
962958
if !haskey(lifted_undef, stmt_id)
963959
first = true
964960
while !isempty(worklist)
@@ -1034,11 +1030,11 @@ function type_lift_pass!(ir::IRCode)
10341030
end
10351031
end
10361032
end
1037-
if stmt.head === :isdefined
1038-
insts[idx][:inst] = lifted_undef[stmt_id]
1039-
else
1040-
insts[idx][:inst] = Expr(:throw_undef_if_not, stmt.args[1], lifted_undef[stmt_id])
1033+
inst = lifted_undef[stmt_id]
1034+
if stmt.head === :undefcheck
1035+
inst = Expr(:throw_undef_if_not, stmt.args[1], inst)
10411036
end
1037+
insts[idx][:inst] = inst
10421038
end
10431039
end
10441040
ir

base/compiler/ssair/slot2ssa.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ function fixup_slot!(ir::IRCode, ci::CodeInfo, idx::Int, slot::Int, @nospecializ
103103
return undef_token
104104
end
105105
if !isa(ssa, Argument) && !(ssa === nothing) && ((ci.slotflags[slot] & SLOT_USEDUNDEF) != 0)
106+
# insert a temporary node. type_lift_pass! will remove it
106107
insert_node!(ir, idx, Any, Expr(:undefcheck, ci.slotnames[slot], ssa))
107108
end
108109
if isa(stmt, SlotNumber)
@@ -147,6 +148,7 @@ function fixemup!(cond, rename, ir::IRCode, ci::CodeInfo, idx::Int, @nospecializ
147148
return true
148149
end
149150
end
151+
# temporarily corrupt the isdefined node. type_lift_pass! will fix it
150152
stmt.args[1] = ssa
151153
end
152154
return stmt
@@ -162,7 +164,7 @@ function fixemup!(cond, rename, ir::IRCode, ci::CodeInfo, idx::Int, @nospecializ
162164
return nothing
163165
end
164166
op[] = x
165-
elseif isa(val, GlobalRef) && !isdefined(val.mod, val.name)
167+
elseif isa(val, GlobalRef) && !(isdefined(val.mod, val.name) && isconst(val.mod, val.name))
166168
op[] = NewSSAValue(insert_node!(ir, idx, Any, val).id - length(ir.stmts))
167169
end
168170
end

base/compiler/ssair/verify.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ function check_op(ir::IRCode, domtree::DomTree, @nospecialize(op), use_bb::Int,
3636
end
3737
end
3838
elseif isa(op, GlobalRef)
39-
if !isdefined(op.mod, op.name)
39+
if !isdefined(op.mod, op.name) || !isconst(op.mod, op.name)
4040
@verify_error "Unbound GlobalRef not allowed in value position"
4141
error("")
4242
end

base/compiler/tfuncs.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1144,7 +1144,7 @@ function apply_type_tfunc(@nospecialize(headtypetype), @nospecialize args...)
11441144
end
11451145
return allconst ? Const(ty) : Type{ty}
11461146
end
1147-
istuple = (headtype == Tuple)
1147+
istuple = isa(headtype, Type) && (headtype == Tuple)
11481148
if !istuple && !isa(headtype, UnionAll)
11491149
return Union{}
11501150
end

base/errorshow.jl

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -573,17 +573,17 @@ stacktrace_linebreaks()::Bool =
573573
tryparse(Bool, get(ENV, "JULIA_STACKTRACE_LINEBREAKS", "false")) === true
574574

575575
function show_full_backtrace(io::IO, trace::Vector; print_linebreaks::Bool)
576-
n = length(trace)
577-
ndigits_max = ndigits(n)
576+
num_frames = length(trace)
577+
ndigits_max = ndigits(num_frames)
578578

579579
modulecolordict = copy(STACKTRACE_FIXEDCOLORS)
580580
modulecolorcycler = Iterators.Stateful(Iterators.cycle(STACKTRACE_MODULECOLORS))
581581

582582
println(io, "\nStacktrace:")
583583

584-
for (i, frame) in enumerate(trace)
585-
print_stackframe(io, i, frame, 1, ndigits_max, modulecolordict, modulecolorcycler)
586-
if i < n
584+
for (i, (frame, n)) in enumerate(trace)
585+
print_stackframe(io, i, frame, n, ndigits_max, modulecolordict, modulecolorcycler)
586+
if i < num_frames
587587
println(io)
588588
print_linebreaks && println(io)
589589
end
@@ -782,8 +782,7 @@ function show_backtrace(io::IO, t::Vector)
782782

783783
try invokelatest(update_stackframes_callback[], filtered) catch end
784784
# process_backtrace returns a Vector{Tuple{Frame, Int}}
785-
frames = map(x->first(x)::StackFrame, filtered)
786-
show_full_backtrace(io, frames; print_linebreaks = stacktrace_linebreaks())
785+
show_full_backtrace(io, filtered; print_linebreaks = stacktrace_linebreaks())
787786
return
788787
end
789788

base/file.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1039,7 +1039,7 @@ function symlink(target::AbstractString, link::AbstractString;
10391039
@static if Sys.iswindows()
10401040
# creating file/directory symlinks requires Administrator privileges
10411041
# while junction points apparently do not
1042-
if !(flags & UV_FS_SYMLINK_JUNCTION) && err == UV__EPERM
1042+
if flags & UV_FS_SYMLINK_JUNCTION == 0 && err == UV__EPERM
10431043
msg = "On Windows, creating symlinks requires Administrator privileges.\n$msg"
10441044
end
10451045
end

src/llvm-alloc-opt.cpp

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,8 @@ void Optimizer::optimizeAll()
350350
if (field.hasobjref) {
351351
has_ref = true;
352352
// This can be relaxed a little based on hasload
353-
if (field.hasaggr || field.multiloc) {
353+
// TODO: add support for hasaggr load/store
354+
if (field.hasaggr || field.multiloc || field.size != sizeof(void*)) {
354355
has_refaggr = true;
355356
break;
356357
}
@@ -361,15 +362,12 @@ void Optimizer::optimizeAll()
361362
splitOnStack(orig);
362363
continue;
363364
}
364-
if (has_ref) {
365-
if (use_info.memops.size() != 1 || has_refaggr ||
366-
use_info.memops.begin()->second.size != sz) {
367-
if (use_info.hastypeof)
368-
optimizeTag(orig);
369-
continue;
370-
}
371-
// The object only has a single field that's a reference with only one kind of access.
365+
if (has_refaggr) {
366+
if (use_info.hastypeof)
367+
optimizeTag(orig);
368+
continue;
372369
}
370+
// The object has no fields with mix reference access
373371
moveToStack(orig, sz, has_ref);
374372
}
375373
}
@@ -444,6 +442,7 @@ Optimizer::AllocUseInfo::getField(uint32_t offset, uint32_t size, Type *elty)
444442
if (it->first + it->second.size >= offset + size) {
445443
if (it->second.elty != elty)
446444
it->second.elty = nullptr;
445+
assert(it->second.elty == nullptr || (it->first == offset && it->second.size == size));
447446
return *it;
448447
}
449448
if (it->first + it->second.size > offset) {
@@ -454,7 +453,7 @@ Optimizer::AllocUseInfo::getField(uint32_t offset, uint32_t size, Type *elty)
454453
else {
455454
it = memops.begin();
456455
}
457-
// Now fine the last slot that overlaps with the current memory location.
456+
// Now find the last slot that overlaps with the current memory location.
458457
// Also set `lb` if we didn't find any above.
459458
for (; it != end && it->first < offset + size; ++it) {
460459
if (lb == end)
@@ -493,8 +492,8 @@ bool Optimizer::AllocUseInfo::addMemOp(Instruction *inst, unsigned opno, uint32_
493492
memop.isaggr = isa<StructType>(elty) || isa<ArrayType>(elty) || isa<VectorType>(elty);
494493
memop.isobjref = hasObjref(elty);
495494
auto &field = getField(offset, size, elty);
496-
if (field.first != offset || field.second.size != size)
497-
field.second.multiloc = true;
495+
if (field.second.hasobjref != memop.isobjref)
496+
field.second.multiloc = true; // can't split this field, since it contains a mix of references and bits
498497
if (!isstore)
499498
field.second.hasload = true;
500499
if (memop.isobjref) {

stdlib/LinearAlgebra/src/diagonal.jl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,14 @@ end
697697
*(x::Transpose{<:Any,<:AbstractVector}, D::Diagonal, y::AbstractVector) = _mapreduce_prod(*, x, D, y)
698698
dot(x::AbstractVector, D::Diagonal, y::AbstractVector) = _mapreduce_prod(dot, x, D, y)
699699

700+
dot(A::Diagonal, B::Diagonal) = dot(A.diag, B.diag)
701+
function dot(D::Diagonal, B::AbstractMatrix)
702+
size(D) == size(B) || throw(DimensionMismatch("Matrix sizes $(size(D)) and $(size(B)) differ"))
703+
return dot(D.diag, view(B, diagind(B)))
704+
end
705+
706+
dot(A::AbstractMatrix, B::Diagonal) = conj(dot(B, A))
707+
700708
function _mapreduce_prod(f, x, D::Diagonal, y)
701709
if isempty(x) && isempty(D) && isempty(y)
702710
return zero(Base.promote_op(f, eltype(x), eltype(D), eltype(y)))

stdlib/LinearAlgebra/test/diagonal.jl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -733,4 +733,13 @@ end
733733
@test dot(zeros(Int32, 0), Diagonal(zeros(Int, 0)), zeros(Int16, 0)) === 0
734734
end
735735

736+
@testset "Inner product" begin
737+
A = Diagonal(rand(10) .+ im)
738+
B = Diagonal(rand(10) .+ im)
739+
@test dot(A, B) dot(Matrix(A), B)
740+
@test dot(A, B) dot(A, Matrix(B))
741+
@test dot(A, B) dot(Matrix(A), Matrix(B))
742+
@test dot(A, B) conj(dot(B, A))
743+
end
744+
736745
end # module TestDiagonal

0 commit comments

Comments
 (0)