@@ -116,11 +116,14 @@ function inline_cost_clamp(x::Int)
116
116
return convert (InlineCostType, x)
117
117
end
118
118
119
+ const SRC_FLAG_DECLARED_INLINE = 0x1
120
+ const SRC_FLAG_DECLARED_NOINLINE = 0x2
121
+
119
122
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
121
124
122
125
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
124
127
125
128
# ####################
126
129
# OptimizationState #
@@ -157,6 +160,7 @@ code_cache(state::InliningState) = WorldView(code_cache(state.interp), state.wor
157
160
158
161
mutable struct OptimizationResult
159
162
ir:: IRCode
163
+ inline_flag:: UInt8
160
164
simplified:: Bool # indicates whether the IR was processed with `cfg_simplify!`
161
165
end
162
166
168
172
mutable struct OptimizationState{Interp<: AbstractInterpreter }
169
173
linfo:: MethodInstance
170
174
src:: CodeInfo
171
- result :: Union{Nothing, OptimizationResult}
175
+ optresult :: Union{Nothing, OptimizationResult}
172
176
stmt_info:: Vector{CallInfo}
173
177
mod:: Module
174
178
sptypes:: Vector{VarState}
@@ -236,13 +240,29 @@ include("ssair/EscapeAnalysis.jl")
236
240
include (" ssair/passes.jl" )
237
241
include (" ssair/irinterp.jl" )
238
242
243
+ function ir_to_codeinf! (opt:: OptimizationState , frame:: InferenceState , edges:: SimpleVector )
244
+ ir_to_codeinf! (opt, edges, compute_inlining_cost (frame. interp, frame. result, opt. optresult))
245
+ end
246
+
247
+ function ir_to_codeinf! (opt:: OptimizationState , edges:: SimpleVector , inlining_cost:: InlineCostType )
248
+ src = ir_to_codeinf! (opt, edges)
249
+ src. inlining_cost = inlining_cost
250
+ src
251
+ end
252
+
253
+ function ir_to_codeinf! (opt:: OptimizationState , edges:: SimpleVector )
254
+ src = ir_to_codeinf! (opt)
255
+ src. edges = edges
256
+ src
257
+ end
258
+
239
259
function ir_to_codeinf! (opt:: OptimizationState )
240
- (; linfo, src, result ) = opt
241
- if result === nothing
260
+ (; linfo, src, optresult ) = opt
261
+ if optresult === nothing
242
262
return src
243
263
end
244
- src = ir_to_codeinf! (src, result . ir)
245
- opt. result = nothing
264
+ src = ir_to_codeinf! (src, optresult . ir)
265
+ opt. optresult = nothing
246
266
opt. src = src
247
267
maybe_validate_code (linfo, src, " optimized" )
248
268
return src
@@ -485,63 +505,12 @@ end
485
505
abstract_eval_ssavalue (s:: SSAValue , src:: Union{IRCode,IncrementalCompact} ) = types (src)[s]
486
506
487
507
"""
488
- finish(interp::AbstractInterpreter, opt::OptimizationState,
489
- ir::IRCode, caller::InferenceResult)
508
+ finishopt!(interp::AbstractInterpreter, opt::OptimizationState, ir::IRCode)
490
509
491
- Post-process information derived by Julia-level optimizations for later use.
492
- In particular, this function determines the inlineability of the optimized code.
510
+ Called at the end of optimization to store the resulting IR back into the OptimizationState.
493
511
"""
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
512
+ function finishopt! (interp:: AbstractInterpreter , opt:: OptimizationState , ir:: IRCode )
513
+ opt. optresult = OptimizationResult (ir, ccall (:jl_ir_flag_inlining , UInt8, (Any,), opt. src), false )
545
514
return nothing
546
515
end
547
516
@@ -1015,17 +984,20 @@ end
1015
984
function optimize (interp:: AbstractInterpreter , opt:: OptimizationState , caller:: InferenceResult )
1016
985
@timeit " optimizer" ir = run_passes_ipo_safe (opt. src, opt)
1017
986
ipo_dataflow_analysis! (interp, opt, ir, caller)
1018
- return finish (interp, opt, ir, caller)
987
+ finishopt! (interp, opt, ir)
988
+ return nothing
1019
989
end
1020
990
1021
- macro pass (name, expr)
991
+ const ALL_PASS_NAMES = String[]
992
+ macro pass (name:: String , expr)
1022
993
optimize_until = esc (:optimize_until )
1023
994
stage = esc (:__stage__ )
1024
- macrocall = :(@timeit $ ( esc ( name)) $ (esc (expr)))
995
+ macrocall = :(@timeit $ name $ (esc (expr)))
1025
996
macrocall. args[2 ] = __source__ # `@timeit` may want to use it
997
+ push! (ALL_PASS_NAMES, name)
1026
998
quote
1027
999
$ macrocall
1028
- matchpass ($ optimize_until, ($ stage += 1 ), $ ( esc ( name)) ) && $ (esc (:(@goto __done__)))
1000
+ matchpass ($ optimize_until, ($ stage += 1 ), $ name) && $ (esc (:(@goto __done__)))
1029
1001
end
1030
1002
end
1031
1003
@@ -1036,8 +1008,13 @@ matchpass(::Nothing, _, _) = false
1036
1008
function run_passes_ipo_safe (
1037
1009
ci:: CodeInfo ,
1038
1010
sv:: OptimizationState ,
1039
- optimize_until = nothing , # run all passes by default
1040
- )
1011
+ optimize_until:: Union{Nothing, Int, String} = nothing ) # run all passes by default
1012
+ if optimize_until isa String && ! contains_is (ALL_PASS_NAMES, optimize_until)
1013
+ error (" invalid `optimize_until` argument, no such optimization pass" )
1014
+ elseif optimize_until isa Int && (optimize_until < 1 || optimize_until > length (ALL_PASS_NAMES))
1015
+ error (" invalid `optimize_until` argument, no such optimization pass" )
1016
+ end
1017
+
1041
1018
__stage__ = 0 # used by @pass
1042
1019
# NOTE: The pass name MUST be unique for `optimize_until::String` to work
1043
1020
@pass " convert" ir = convert_to_ircode (ci, sv)
@@ -1459,7 +1436,7 @@ function statement_or_branch_cost(@nospecialize(stmt), line::Int, src::Union{Cod
1459
1436
return thiscost
1460
1437
end
1461
1438
1462
- function inline_cost (ir:: IRCode , params:: OptimizationParams , cost_threshold:: Int )
1439
+ function inline_cost_model (ir:: IRCode , params:: OptimizationParams , cost_threshold:: Int )
1463
1440
bodycost = 0
1464
1441
for i = 1 : length (ir. stmts)
1465
1442
stmt = ir[SSAValue (i)][:stmt ]
0 commit comments