Skip to content

Commit a4940e7

Browse files
authored
Backports for 1.12.0-rc3 (or 1.12.0) (#59577)
2 parents 7ad5a06 + 8327e55 commit a4940e7

32 files changed

+407
-82
lines changed

Compiler/src/ssair/passes.jl

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -872,6 +872,49 @@ function perform_lifting!(compact::IncrementalCompact,
872872
return Pair{Any, PhiNest}(stmt_val, PhiNest(visited_philikes, lifted_philikes, lifted_leaves, reverse_mapping, walker_callback))
873873
end
874874

875+
function lift_apply_args!(compact::IncrementalCompact, idx::Int, stmt::Expr, 𝕃ₒ::AbstractLattice)
876+
# Handle _apply_iterate calls: convert arguments to use `Core.svec`. The behavior of Core.svec (with boxing) better matches the ABI of codegen.
877+
compact[idx] = nothing
878+
for i in 4:length(stmt.args) # Skip iterate function, f, and first iterator
879+
arg = stmt.args[i]
880+
arg_type = argextype(arg, compact)
881+
svec_args = nothing
882+
if isa(arg_type, DataType) && arg_type.name === Tuple.name
883+
if isa(arg, SSAValue)
884+
arg_stmt = compact[arg][:stmt]
885+
if is_known_call(arg_stmt, Core.tuple, compact)
886+
svec_args = copy(arg_stmt.args)
887+
end
888+
end
889+
if svec_args === nothing
890+
# Fallback path: generate getfield calls for tuple elements
891+
tuple_length = length(arg_type.parameters)
892+
if tuple_length > 0 && !isvarargtype(arg_type.parameters[tuple_length])
893+
svec_args = Vector{Any}(undef, tuple_length + 1)
894+
for j in 1:tuple_length
895+
getfield_call = Expr(:call, GlobalRef(Core, :getfield), arg, j)
896+
getfield_type = arg_type.parameters[j]
897+
inst = compact[SSAValue(idx)]
898+
getfield_ssa = insert_node!(compact, SSAValue(idx), NewInstruction(getfield_call, getfield_type, NoCallInfo(), inst[:line], inst[:flag]))
899+
svec_args[j + 1] = getfield_ssa
900+
end
901+
end
902+
end
903+
end
904+
# Create Core.svec call if we have arguments
905+
if svec_args !== nothing
906+
svec_args[1] = GlobalRef(Core, :svec)
907+
new_svec_call = Expr(:call)
908+
new_svec_call.args = svec_args
909+
inst = compact[SSAValue(idx)]
910+
new_svec_ssa = insert_node!(compact, SSAValue(idx), NewInstruction(new_svec_call, SimpleVector, NoCallInfo(), inst[:line], inst[:flag]))
911+
stmt.args[i] = new_svec_ssa
912+
end
913+
end
914+
compact[idx] = stmt
915+
nothing
916+
end
917+
875918
function lift_svec_ref!(compact::IncrementalCompact, idx::Int, stmt::Expr)
876919
length(stmt.args) != 3 && return
877920

@@ -1375,6 +1418,9 @@ function sroa_pass!(ir::IRCode, inlining::Union{Nothing,InliningState}=nothing)
13751418
compact[SSAValue(idx)] = (compact[enter_ssa][:stmt]::EnterNode).scope
13761419
elseif isexpr(stmt, :new)
13771420
refine_new_effects!(𝕃ₒ, compact, idx, stmt)
1421+
elseif is_known_call(stmt, Core._apply_iterate, compact)
1422+
length(stmt.args) >= 4 || continue
1423+
lift_apply_args!(compact, idx, stmt, 𝕃ₒ)
13781424
end
13791425
continue
13801426
end

Compiler/src/tfuncs.jl

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,15 @@ end
585585
add_tfunc(nfields, 1, 1, nfields_tfunc, 1)
586586
add_tfunc(Core._expr, 1, INT_INF, @nospecs((𝕃::AbstractLattice, args...)->Expr), 100)
587587
add_tfunc(svec, 0, INT_INF, @nospecs((𝕃::AbstractLattice, args...)->SimpleVector), 20)
588+
589+
@nospecs function _svec_len_tfunc(𝕃::AbstractLattice, s)
590+
if isa(s, Const) && isa(s.val, SimpleVector)
591+
return Const(length(s.val))
592+
end
593+
return Int
594+
end
595+
add_tfunc(Core._svec_len, 1, 1, _svec_len_tfunc, 1)
596+
588597
@nospecs function _svec_ref_tfunc(𝕃::AbstractLattice, s, i)
589598
if isa(s, Const) && isa(i, Const)
590599
s, i = s.val, i.val
@@ -1986,15 +1995,8 @@ function tuple_tfunc(𝕃::AbstractLattice, argtypes::Vector{Any})
19861995
# UnionAll context is missing around this.
19871996
pop!(argtypes)
19881997
end
1989-
all_are_const = true
1990-
for i in 1:length(argtypes)
1991-
if !isa(argtypes[i], Const)
1992-
all_are_const = false
1993-
break
1994-
end
1995-
end
1996-
if all_are_const
1997-
return Const(ntuple(i::Int->argtypes[i].val, length(argtypes)))
1998+
if is_all_const_arg(argtypes, 1) # repeated from builtin_tfunction for the benefit of callers that use this tfunc directly
1999+
return Const(tuple(collect_const_args(argtypes, 1)...))
19982000
end
19992001
params = Vector{Any}(undef, length(argtypes))
20002002
anyinfo = false
@@ -2359,14 +2361,17 @@ function _builtin_nothrow(𝕃::AbstractLattice, @nospecialize(f::Builtin), argt
23592361
elseif f === Core.compilerbarrier
23602362
na == 2 || return false
23612363
return compilerbarrier_nothrow(argtypes[1], nothing)
2364+
elseif f === Core._svec_len
2365+
na == 1 || return false
2366+
return _svec_len_tfunc(𝕃, argtypes[1]) isa Const
23622367
elseif f === Core._svec_ref
23632368
na == 2 || return false
23642369
return _svec_ref_tfunc(𝕃, argtypes[1], argtypes[2]) isa Const
23652370
end
23662371
return false
23672372
end
23682373

2369-
# known to be always effect-free (in particular nothrow)
2374+
# known to be always effect-free (in particular also nothrow)
23702375
const _PURE_BUILTINS = Any[
23712376
tuple,
23722377
svec,
@@ -2395,6 +2400,8 @@ const _CONSISTENT_BUILTINS = Any[
23952400
donotdelete,
23962401
memoryrefnew,
23972402
memoryrefoffset,
2403+
Core._svec_len,
2404+
Core._svec_ref,
23982405
]
23992406

24002407
# known to be effect-free (but not necessarily nothrow)
@@ -2419,6 +2426,7 @@ const _EFFECT_FREE_BUILTINS = [
24192426
Core.throw_methoderror,
24202427
getglobal,
24212428
compilerbarrier,
2429+
Core._svec_len,
24222430
Core._svec_ref,
24232431
]
24242432

@@ -2453,6 +2461,7 @@ const _ARGMEM_BUILTINS = Any[
24532461
replacefield!,
24542462
setfield!,
24552463
swapfield!,
2464+
Core._svec_len,
24562465
Core._svec_ref,
24572466
]
24582467

@@ -2637,7 +2646,7 @@ function builtin_effects(𝕃::AbstractLattice, @nospecialize(f::Builtin), argty
26372646
else
26382647
if contains_is(_CONSISTENT_BUILTINS, f)
26392648
consistent = ALWAYS_TRUE
2640-
elseif f === memoryrefget || f === memoryrefset! || f === memoryref_isassigned || f === Core._svec_ref
2649+
elseif f === memoryrefget || f === memoryrefset! || f === memoryref_isassigned || f === Core._svec_len || f === Core._svec_ref
26412650
consistent = CONSISTENT_IF_INACCESSIBLEMEMONLY
26422651
elseif f === Core._typevar || f === Core.memorynew
26432652
consistent = CONSISTENT_IF_NOTRETURNED
@@ -2746,11 +2755,12 @@ end
27462755
function builtin_tfunction(interp::AbstractInterpreter, @nospecialize(f), argtypes::Vector{Any},
27472756
sv::Union{AbsIntState, Nothing})
27482757
𝕃ᵢ = typeinf_lattice(interp)
2749-
if isa(f, IntrinsicFunction)
2750-
if is_pure_intrinsic_infer(f) && all(@nospecialize(a) -> isa(a, Const), argtypes)
2751-
argvals = anymap(@nospecialize(a) -> (a::Const).val, argtypes)
2758+
# Early constant evaluation for foldable builtins with all const args
2759+
if isa(f, IntrinsicFunction) ? is_pure_intrinsic_infer(f) : (f in _PURE_BUILTINS || (f in _CONSISTENT_BUILTINS && f in _EFFECT_FREE_BUILTINS))
2760+
if is_all_const_arg(argtypes, 1)
2761+
argvals = collect_const_args(argtypes, 1)
27522762
try
2753-
# unroll a few cases which have specialized codegen
2763+
# unroll a few common cases for better codegen
27542764
if length(argvals) == 1
27552765
return Const(f(argvals[1]))
27562766
elseif length(argvals) == 2
@@ -2764,6 +2774,8 @@ function builtin_tfunction(interp::AbstractInterpreter, @nospecialize(f), argtyp
27642774
return Bottom
27652775
end
27662776
end
2777+
end
2778+
if isa(f, IntrinsicFunction)
27672779
iidx = Int(reinterpret(Int32, f)) + 1
27682780
if iidx < 0 || iidx > length(T_IFUNC)
27692781
# unknown intrinsic
@@ -2790,6 +2802,7 @@ function builtin_tfunction(interp::AbstractInterpreter, @nospecialize(f), argtyp
27902802
end
27912803
tf = T_FFUNC_VAL[fidx]
27922804
end
2805+
27932806
if hasvarargtype(argtypes)
27942807
if length(argtypes) - 1 > tf[2]
27952808
# definitely too many arguments

Compiler/test/codegen.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,14 +133,14 @@ if !is_debug_build && opt_level > 0
133133
# Array
134134
test_loads_no_call(strip_debug_calls(get_llvm(sizeof, Tuple{Vector{Int}})), [Iptr])
135135
# As long as the eltype is known we don't need to load the elsize, but do need to check isvector
136-
@test_skip test_loads_no_call(strip_debug_calls(get_llvm(sizeof, Tuple{Array{Any}})), ["atomic $Iptr", "ptr", "ptr", Iptr, Iptr, "ptr", Iptr])
136+
@test_skip test_loads_no_call(strip_debug_calls(get_llvm(sizeof, Tuple{Array{Any}})), ["atomic volatile $Iptr", "ptr", "ptr", Iptr, Iptr, "ptr", Iptr])
137137
# Memory
138138
test_loads_no_call(strip_debug_calls(get_llvm(core_sizeof, Tuple{Memory{Int}})), [Iptr])
139139
# As long as the eltype is known we don't need to load the elsize
140140
test_loads_no_call(strip_debug_calls(get_llvm(core_sizeof, Tuple{Memory{Any}})), [Iptr])
141141
# Check that we load the elsize and isunion from the typeof layout
142-
test_loads_no_call(strip_debug_calls(get_llvm(core_sizeof, Tuple{Memory})), [Iptr, "atomic $Iptr", "ptr", "i32", "i16"])
143-
test_loads_no_call(strip_debug_calls(get_llvm(core_sizeof, Tuple{Memory})), [Iptr, "atomic $Iptr", "ptr", "i32", "i16"])
142+
test_loads_no_call(strip_debug_calls(get_llvm(core_sizeof, Tuple{Memory})), [Iptr, "atomic volatile $Iptr", "ptr", "i32", "i16"])
143+
test_loads_no_call(strip_debug_calls(get_llvm(core_sizeof, Tuple{Memory})), [Iptr, "atomic volatile $Iptr", "ptr", "i32", "i16"])
144144
# Primitive Type size should be folded to a constant
145145
test_loads_no_call(strip_debug_calls(get_llvm(core_sizeof, Tuple{Ptr})), String[])
146146

Compiler/test/effects.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1466,7 +1466,7 @@ end
14661466
let effects = Base.infer_effects((Core.SimpleVector,Int); optimize=false) do svec, i
14671467
Core._svec_ref(svec, i)
14681468
end
1469-
@test !Compiler.is_consistent(effects)
1469+
@test Compiler.is_consistent(effects)
14701470
@test Compiler.is_effect_free(effects)
14711471
@test !Compiler.is_nothrow(effects)
14721472
@test Compiler.is_terminates(effects)

base/Base.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ using .Filesystem
174174
include("cmd.jl")
175175
include("process.jl")
176176
include("terminfo.jl")
177+
include("Terminals.jl") # Moved from REPL to reduce invalidations
177178
include("secretbuffer.jl")
178179

179180
# core math functions
File renamed without changes.

base/essentials.jl

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -934,11 +934,7 @@ setindex!(A::MemoryRef{Any}, @nospecialize(x)) = (memoryrefset!(A, x, :not_atomi
934934

935935
getindex(v::SimpleVector, i::Int) = (@_foldable_meta; Core._svec_ref(v, i))
936936
function length(v::SimpleVector)
937-
@_total_meta
938-
t = @_gc_preserve_begin v
939-
len = unsafe_load(Ptr{Int}(pointer_from_objref(v)))
940-
@_gc_preserve_end t
941-
return len
937+
Core._svec_len(v)
942938
end
943939
firstindex(v::SimpleVector) = 1
944940
lastindex(v::SimpleVector) = length(v)

base/sort.jl

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -563,12 +563,15 @@ function _sort!(v::UnwrappableSubArray, a::SubArrayOptimization, o::Ordering, kw
563563
@getkw lo hi
564564
# @assert v.stride1 == 1
565565
parent = v.parent
566-
if parent isa Array && !(parent isa Vector) && hi - lo < 100
566+
if parent isa Array && !(parent isa Vector) && hi - lo < 100 || !iszero(v.offset1)
567567
# vec(::Array{T, ≠1}) allocates and is therefore somewhat expensive.
568568
# We don't want that for small inputs.
569+
570+
# Additionally, if offset1 is non-zero, then this optimization is incompatible with
571+
# algorithms that track absolute first and last indices (e.g. ScratchQuickSort)
569572
_sort!(v, a.next, o, kw)
570573
else
571-
_sort!(vec(parent), a.next, o, (;kw..., lo = lo + v.offset1, hi = hi + v.offset1))
574+
_sort!(vec(parent), a.next, o, kw)
572575
end
573576
end
574577

base/stream.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ end
378378

379379
function isopen(x::Union{LibuvStream, LibuvServer})
380380
if x.status == StatusUninit || x.status == StatusInit || x.handle === C_NULL
381-
throw(ArgumentError("$x is not initialized"))
381+
throw(ArgumentError("stream not initialized"))
382382
end
383383
return x.status != StatusClosed
384384
end

contrib/generate_precompile.jl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,14 @@ hardcoded_precompile_statements = """
3434
precompile(Base.unsafe_string, (Ptr{UInt8},))
3535
precompile(Base.unsafe_string, (Ptr{Int8},))
3636
37+
# used by REPL
38+
precompile(Tuple{typeof(Base.getproperty), Base.Terminals.TTYTerminal, Symbol})
39+
precompile(Tuple{typeof(Base.reseteof), Base.Terminals.TTYTerminal})
40+
precompile(Tuple{typeof(Base.Terminals.enable_bracketed_paste), Base.Terminals.TTYTerminal})
41+
precompile(Tuple{typeof(Base.Terminals.width), Base.Terminals.TTYTerminal})
42+
precompile(Tuple{typeof(Base.Terminals.height), Base.Terminals.TTYTerminal})
43+
precompile(Tuple{typeof(Base.write), Base.Terminals.TTYTerminal, Array{UInt8, 1}})
44+
3745
# loading.jl - without these each precompile worker would precompile these because they're hit before pkgimages are loaded
3846
precompile(Base.__require, (Module, Symbol))
3947
precompile(Base.__require, (Base.PkgId,))

0 commit comments

Comments
 (0)