Skip to content

Commit 0c4487f

Browse files
Merge branch 'master' into ib/faster_first_test
2 parents fed1161 + 4b90899 commit 0c4487f

File tree

277 files changed

+7624
-4176
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

277 files changed

+7624
-4176
lines changed

.github/CODEOWNERS

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,10 @@ CODEOWNERS @JuliaLang/github-actions
44

55
/.github/workflows/rerun_failed.yml @DilumAluthge
66
/.github/workflows/statuses.yml @DilumAluthge
7+
/base/special/ @oscardssmith
8+
/base/sort.jl @LilithHafner
9+
/test/sorting.jl @LilithHafner
10+
/stdlib/*_jll @giordano
11+
/base/binaryplatforms.jl @giordano
12+
/src/julia_gcext.h @fingolfin
13+
/test/gcext/gcext.c @fingolfin

Compiler/Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "Compiler"
22
uuid = "807dbc54-b67e-4c79-8afb-eafe4df6f2e1"
3-
version = "0.0.3"
3+
version = "0.1.0"
44

55
[compat]
66
julia = "1.10"

Compiler/README.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# The `Compiler` module
2+
3+
This directory maintains the implementation of the Julia compiler.
4+
5+
Through a bootstrapping process, it is bundled into the Julia runtime as `Base.Compiler`.
6+
7+
You can also use this `Compiler` module as the `Compiler` standard library by following the steps below.
8+
9+
## How to use
10+
11+
To utilize this `Compiler.jl` standard library, you need to declare it as a dependency in
12+
your `Project.toml` as follows:
13+
> Project.toml
14+
```toml
15+
[deps]
16+
Compiler = "807dbc54-b67e-4c79-8afb-eafe4df6f2e1"
17+
18+
[compat]
19+
Compiler = "0.1"
20+
```
21+
22+
With the setup above, [the special placeholder version (v0.1.0)](https://github.com/JuliaLang/BaseCompiler.jl)
23+
will be installed by default.[^1]
24+
25+
[^1]: Currently, only version v0.1.0 is registered in the [General](https://github.com/JuliaRegistries/General) registry.
26+
27+
If needed, you can switch to a custom implementation of the `Compiler` module by running
28+
```julia-repl
29+
pkg> dev /path/to/Compiler.jl # to use a local implementation
30+
```
31+
or
32+
```julia-repl
33+
pkg> add https://url/of/Compiler/branch # to use a remote implementation
34+
```
35+
This feature is particularly useful for developing or experimenting with alternative compiler implementations.
36+
37+
> [!note]
38+
> The Compiler.jl standard library is available starting from Julia v1.10.
39+
> However, switching to a custom compiler implementation is supported only from
40+
> Julia v1.12 onwards.
41+
42+
> [!warning]
43+
> When using a custom, non-`Base` version of `Compiler` implementation, it may be necessary
44+
> to run `InteractiveUtils.@activate Compiler` to ensure proper functionality of certain
45+
> reflection utilities.

Compiler/extras/CompilerDevTools/src/CompilerDevTools.jl

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

4848
function Compiler.transform_result_for_cache(interp::SplitCacheInterp, result::Compiler.InferenceResult, edges::Compiler.SimpleVector)
4949
opt = result.src::Compiler.OptimizationState
50-
ir = opt.result.ir::Compiler.IRCode
50+
ir = opt.optresult.ir::Compiler.IRCode
5151
override = with_new_compiler
5252
for inst in ir.stmts
5353
stmt = inst[:stmt]

Compiler/src/Compiler.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,9 @@ using Base: @_foldable_meta, @_gc_preserve_begin, @_gc_preserve_end, @nospeciali
6565
structdiff, tls_world_age, unconstrain_vararg_length, unionlen, uniontype_layout,
6666
uniontypes, unsafe_convert, unwrap_unionall, unwrapva, vect, widen_diagonal,
6767
_uncompressed_ir, maybe_add_binding_backedge!, datatype_min_ninitialized,
68-
partialstruct_init_undefs, fieldcount_noerror
68+
partialstruct_init_undefs, fieldcount_noerror, _eval_import, _eval_using,
69+
get_ci_mi
70+
6971
using Base.Order
7072

7173
import Base: ==, _topmod, append!, convert, copy, copy!, findall, first, get, get!,

Compiler/src/abstractinterpretation.jl

Lines changed: 130 additions & 82 deletions
Large diffs are not rendered by default.

Compiler/src/optimize.jl

Lines changed: 75 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -116,11 +116,14 @@ function inline_cost_clamp(x::Int)
116116
return convert(InlineCostType, x)
117117
end
118118

119+
const SRC_FLAG_DECLARED_INLINE = 0x1
120+
const SRC_FLAG_DECLARED_NOINLINE = 0x2
121+
119122
is_declared_inline(@nospecialize src::MaybeCompressed) =
120-
ccall(:jl_ir_flag_inlining, UInt8, (Any,), src) == 1
123+
ccall(:jl_ir_flag_inlining, UInt8, (Any,), src) == SRC_FLAG_DECLARED_INLINE
121124

122125
is_declared_noinline(@nospecialize src::MaybeCompressed) =
123-
ccall(:jl_ir_flag_inlining, UInt8, (Any,), src) == 2
126+
ccall(:jl_ir_flag_inlining, UInt8, (Any,), src) == SRC_FLAG_DECLARED_NOINLINE
124127

125128
#####################
126129
# OptimizationState #
@@ -144,19 +147,50 @@ struct InliningState{Interp<:AbstractInterpreter}
144147
edges::Vector{Any}
145148
world::UInt
146149
interp::Interp
150+
opt_cache::IdDict{MethodInstance,CodeInstance}
147151
end
148-
function InliningState(sv::InferenceState, interp::AbstractInterpreter)
149-
return InliningState(sv.edges, frame_world(sv), interp)
152+
function InliningState(sv::InferenceState, interp::AbstractInterpreter,
153+
opt_cache::IdDict{MethodInstance,CodeInstance}=IdDict{MethodInstance,CodeInstance}())
154+
return InliningState(sv.edges, frame_world(sv), interp, opt_cache)
150155
end
151-
function InliningState(interp::AbstractInterpreter)
152-
return InliningState(Any[], get_inference_world(interp), interp)
156+
function InliningState(interp::AbstractInterpreter,
157+
opt_cache::IdDict{MethodInstance,CodeInstance}=IdDict{MethodInstance,CodeInstance}())
158+
return InliningState(Any[], get_inference_world(interp), interp, opt_cache)
159+
end
160+
161+
struct OptimizerCache{CodeCache}
162+
wvc::WorldView{CodeCache}
163+
owner
164+
opt_cache::IdDict{MethodInstance,CodeInstance}
165+
function OptimizerCache(
166+
wvc::WorldView{CodeCache},
167+
@nospecialize(owner),
168+
opt_cache::IdDict{MethodInstance,CodeInstance}) where CodeCache
169+
new{CodeCache}(wvc, owner, opt_cache)
170+
end
171+
end
172+
function get((; wvc, owner, opt_cache)::OptimizerCache, mi::MethodInstance, default)
173+
if haskey(opt_cache, mi)
174+
codeinst = opt_cache[mi]
175+
@assert codeinst.min_world wvc.worlds.min_world &&
176+
wvc.worlds.max_world codeinst.max_world &&
177+
codeinst.owner === owner
178+
@assert isdefined(codeinst, :inferred) && codeinst.inferred === nothing
179+
return codeinst
180+
end
181+
return get(wvc, mi, default)
153182
end
154183

155184
# get `code_cache(::AbstractInterpreter)` from `state::InliningState`
156-
code_cache(state::InliningState) = WorldView(code_cache(state.interp), state.world)
185+
function code_cache(state::InliningState)
186+
cache = WorldView(code_cache(state.interp), state.world)
187+
owner = cache_owner(state.interp)
188+
return OptimizerCache(cache, owner, state.opt_cache)
189+
end
157190

158191
mutable struct OptimizationResult
159192
ir::IRCode
193+
inline_flag::UInt8
160194
simplified::Bool # indicates whether the IR was processed with `cfg_simplify!`
161195
end
162196

@@ -168,7 +202,7 @@ end
168202
mutable struct OptimizationState{Interp<:AbstractInterpreter}
169203
linfo::MethodInstance
170204
src::CodeInfo
171-
result::Union{Nothing, OptimizationResult}
205+
optresult::Union{Nothing, OptimizationResult}
172206
stmt_info::Vector{CallInfo}
173207
mod::Module
174208
sptypes::Vector{VarState}
@@ -179,13 +213,15 @@ mutable struct OptimizationState{Interp<:AbstractInterpreter}
179213
bb_vartables::Vector{Union{Nothing,VarTable}}
180214
insert_coverage::Bool
181215
end
182-
function OptimizationState(sv::InferenceState, interp::AbstractInterpreter)
183-
inlining = InliningState(sv, interp)
216+
function OptimizationState(sv::InferenceState, interp::AbstractInterpreter,
217+
opt_cache::IdDict{MethodInstance,CodeInstance}=IdDict{MethodInstance,CodeInstance}())
218+
inlining = InliningState(sv, interp, opt_cache)
184219
return OptimizationState(sv.linfo, sv.src, nothing, sv.stmt_info, sv.mod,
185220
sv.sptypes, sv.slottypes, inlining, sv.cfg,
186221
sv.unreachable, sv.bb_vartables, sv.insert_coverage)
187222
end
188-
function OptimizationState(mi::MethodInstance, src::CodeInfo, interp::AbstractInterpreter)
223+
function OptimizationState(mi::MethodInstance, src::CodeInfo, interp::AbstractInterpreter,
224+
opt_cache::IdDict{MethodInstance,CodeInstance}=IdDict{MethodInstance,CodeInstance}())
189225
# prepare src for running optimization passes if it isn't already
190226
nssavalues = src.ssavaluetypes
191227
if nssavalues isa Int
@@ -205,7 +241,7 @@ function OptimizationState(mi::MethodInstance, src::CodeInfo, interp::AbstractIn
205241
mod = isa(def, Method) ? def.module : def
206242
# Allow using the global MI cache, but don't track edges.
207243
# This method is mostly used for unit testing the optimizer
208-
inlining = InliningState(interp)
244+
inlining = InliningState(interp, opt_cache)
209245
cfg = compute_basic_blocks(src.code)
210246
unreachable = BitSet()
211247
bb_vartables = Union{VarTable,Nothing}[]
@@ -236,13 +272,29 @@ include("ssair/EscapeAnalysis.jl")
236272
include("ssair/passes.jl")
237273
include("ssair/irinterp.jl")
238274

275+
function ir_to_codeinf!(opt::OptimizationState, frame::InferenceState, edges::SimpleVector)
276+
ir_to_codeinf!(opt, edges, compute_inlining_cost(frame.interp, frame.result, opt.optresult))
277+
end
278+
279+
function ir_to_codeinf!(opt::OptimizationState, edges::SimpleVector, inlining_cost::InlineCostType)
280+
src = ir_to_codeinf!(opt, edges)
281+
src.inlining_cost = inlining_cost
282+
src
283+
end
284+
285+
function ir_to_codeinf!(opt::OptimizationState, edges::SimpleVector)
286+
src = ir_to_codeinf!(opt)
287+
src.edges = edges
288+
src
289+
end
290+
239291
function ir_to_codeinf!(opt::OptimizationState)
240-
(; linfo, src, result) = opt
241-
if result === nothing
292+
(; linfo, src, optresult) = opt
293+
if optresult === nothing
242294
return src
243295
end
244-
src = ir_to_codeinf!(src, result.ir)
245-
opt.result = nothing
296+
src = ir_to_codeinf!(src, optresult.ir)
297+
opt.optresult = nothing
246298
opt.src = src
247299
maybe_validate_code(linfo, src, "optimized")
248300
return src
@@ -485,63 +537,12 @@ end
485537
abstract_eval_ssavalue(s::SSAValue, src::Union{IRCode,IncrementalCompact}) = types(src)[s]
486538

487539
"""
488-
finish(interp::AbstractInterpreter, opt::OptimizationState,
489-
ir::IRCode, caller::InferenceResult)
540+
finishopt!(interp::AbstractInterpreter, opt::OptimizationState, ir::IRCode)
490541
491-
Post-process information derived by Julia-level optimizations for later use.
492-
In particular, this function determines the inlineability of the optimized code.
542+
Called at the end of optimization to store the resulting IR back into the OptimizationState.
493543
"""
494-
function finish(interp::AbstractInterpreter, opt::OptimizationState,
495-
ir::IRCode, caller::InferenceResult)
496-
(; src, linfo) = opt
497-
(; def, specTypes) = linfo
498-
499-
force_noinline = is_declared_noinline(src)
500-
501-
# compute inlining and other related optimizations
502-
result = caller.result
503-
@assert !(result isa LimitedAccuracy)
504-
result = widenslotwrapper(result)
505-
506-
opt.result = OptimizationResult(ir, false)
507-
508-
# determine and cache inlineability
509-
if !force_noinline
510-
sig = unwrap_unionall(specTypes)
511-
if !(isa(sig, DataType) && sig.name === Tuple.name)
512-
force_noinline = true
513-
end
514-
if !is_declared_inline(src) && result === Bottom
515-
force_noinline = true
516-
end
517-
end
518-
if force_noinline
519-
set_inlineable!(src, false)
520-
elseif isa(def, Method)
521-
if is_declared_inline(src) && isdispatchtuple(specTypes)
522-
# obey @inline declaration if a dispatch barrier would not help
523-
set_inlineable!(src, true)
524-
else
525-
# compute the cost (size) of inlining this code
526-
params = OptimizationParams(interp)
527-
cost_threshold = default = params.inline_cost_threshold
528-
if (optimizer_lattice(interp), result, Tuple) && !isconcretetype(widenconst(result))
529-
cost_threshold += params.inline_tupleret_bonus
530-
end
531-
# if the method is declared as `@inline`, increase the cost threshold 20x
532-
if is_declared_inline(src)
533-
cost_threshold += 19*default
534-
end
535-
# a few functions get special treatment
536-
if def.module === _topmod(def.module)
537-
name = def.name
538-
if name === :iterate || name === :unsafe_convert || name === :cconvert
539-
cost_threshold += 4*default
540-
end
541-
end
542-
src.inlining_cost = inline_cost(ir, params, cost_threshold)
543-
end
544-
end
544+
function finishopt!(interp::AbstractInterpreter, opt::OptimizationState, ir::IRCode)
545+
opt.optresult = OptimizationResult(ir, ccall(:jl_ir_flag_inlining, UInt8, (Any,), opt.src), false)
545546
return nothing
546547
end
547548

@@ -1015,7 +1016,8 @@ end
10151016
function optimize(interp::AbstractInterpreter, opt::OptimizationState, caller::InferenceResult)
10161017
@zone "CC: OPTIMIZER" ir = run_passes_ipo_safe(opt.src, opt)
10171018
ipo_dataflow_analysis!(interp, opt, ir, caller)
1018-
return finish(interp, opt, ir, caller)
1019+
finishopt!(interp, opt, ir)
1020+
return nothing
10191021
end
10201022

10211023
const ALL_PASS_NAMES = String[]
@@ -1466,7 +1468,7 @@ function statement_or_branch_cost(@nospecialize(stmt), line::Int, src::Union{Cod
14661468
return thiscost
14671469
end
14681470

1469-
function inline_cost(ir::IRCode, params::OptimizationParams, cost_threshold::Int)
1471+
function inline_cost_model(ir::IRCode, params::OptimizationParams, cost_threshold::Int)
14701472
bodycost = 0
14711473
for i = 1:length(ir.stmts)
14721474
stmt = ir[SSAValue(i)][:stmt]

Compiler/src/ssair/inlining.jl

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -976,7 +976,7 @@ function retrieve_ir_for_inlining(mi::MethodInstance, ir::IRCode, preserve_local
976976
return ir, spec_info, DebugInfo(ir.debuginfo, length(ir.stmts))
977977
end
978978
function retrieve_ir_for_inlining(mi::MethodInstance, opt::OptimizationState, preserve_local_sources::Bool)
979-
result = opt.result
979+
result = opt.optresult
980980
if result !== nothing
981981
!result.simplified && simplify_ir!(result)
982982
return retrieve_ir_for_inlining(mi, result.ir, preserve_local_sources)
@@ -1159,14 +1159,18 @@ function is_builtin(𝕃ₒ::AbstractLattice, s::Signature)
11591159
end
11601160

11611161
function handle_invoke_call!(todo::Vector{Pair{Int,Any}},
1162-
ir::IRCode, idx::Int, stmt::Expr, info::InvokeCallInfo, flag::UInt32,
1162+
ir::IRCode, idx::Int, stmt::Expr, @nospecialize(info), flag::UInt32,
11631163
sig::Signature, state::InliningState)
1164-
match = info.match
1164+
nspl = nsplit(info)
1165+
nspl == 0 && return nothing # e.g. InvokeCICallInfo
1166+
@assert nspl == 1
1167+
mresult = getsplit(info, 1)
1168+
match = mresult.matches[1]
11651169
if !match.fully_covers
11661170
# TODO: We could union split out the signature check and continue on
11671171
return nothing
11681172
end
1169-
result = info.result
1173+
result = getresult(info, 1)
11701174
if isa(result, ConcreteResult)
11711175
item = concrete_result_item(result, info, state)
11721176
elseif isa(result, SemiConcreteResult)
@@ -1648,7 +1652,7 @@ function assemble_inline_todo!(ir::IRCode, state::InliningState)
16481652
handle_opaque_closure_call!(todo, ir, idx, stmt, info, flag, sig, state)
16491653
elseif isa(info, ModifyOpInfo)
16501654
handle_modifyop!_call!(ir, idx, stmt, info, state)
1651-
elseif isa(info, InvokeCallInfo)
1655+
elseif sig.f === Core.invoke
16521656
handle_invoke_call!(todo, ir, idx, stmt, info, flag, sig, state)
16531657
elseif isa(info, FinalizerInfo)
16541658
handle_finalizer_call!(ir, idx, stmt, info, state)

Compiler/src/ssair/ir.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -609,7 +609,7 @@ end
609609
elseif isa(stmt, EnterNode)
610610
op == 1 || throw(BoundsError())
611611
stmt = EnterNode(stmt.catch_dest, v)
612-
elseif isa(stmt, Union{AnySSAValue, GlobalRef})
612+
elseif isa(stmt, Union{AnySSAValue, Argument, GlobalRef})
613613
op == 1 || throw(BoundsError())
614614
stmt = v
615615
elseif isa(stmt, UpsilonNode)
@@ -640,7 +640,7 @@ end
640640
function userefs(@nospecialize(x))
641641
relevant = (isa(x, Expr) && is_relevant_expr(x)) ||
642642
isa(x, GotoIfNot) || isa(x, ReturnNode) || isa(x, SSAValue) || isa(x, OldSSAValue) || isa(x, NewSSAValue) ||
643-
isa(x, PiNode) || isa(x, PhiNode) || isa(x, PhiCNode) || isa(x, UpsilonNode) || isa(x, EnterNode)
643+
isa(x, PiNode) || isa(x, PhiNode) || isa(x, PhiCNode) || isa(x, UpsilonNode) || isa(x, EnterNode) || isa(x, Argument)
644644
return UseRefIterator(x, relevant)
645645
end
646646

@@ -810,7 +810,7 @@ end
810810
types(ir::Union{IRCode, IncrementalCompact}) = TypesView(ir)
811811

812812
function getindex(compact::IncrementalCompact, ssa::SSAValue)
813-
(1 ssa.id compact.result_idx) || throw(InvalidIRError())
813+
(1 ssa.id < compact.result_idx) || throw(InvalidIRError())
814814
return compact.result[ssa.id]
815815
end
816816

Compiler/src/ssair/passes.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ end
99
function is_known_invoke_or_call(@nospecialize(x), @nospecialize(func), ir::Union{IRCode,IncrementalCompact})
1010
isinvoke = isexpr(x, :invoke)
1111
(isinvoke || isexpr(x, :call)) || return false
12-
ft = argextype(x.args[isinvoke ? 2 : 1], ir)
12+
narg = isinvoke ? 2 : 1
13+
length(x.args) < narg && return false
14+
ft = argextype(x.args[narg], ir)
1315
return singleton_type(ft) === func
1416
end
1517

0 commit comments

Comments
 (0)