@@ -130,12 +130,15 @@ mutable struct OptimizationState{Interp<:AbstractInterpreter}
130
130
slottypes:: Vector{Any}
131
131
inlining:: InliningState{Interp}
132
132
cfg:: CFG
133
+ unreachable:: BitSet
134
+ bb_vartables:: Vector{Union{Nothing,VarTable}}
133
135
insert_coverage:: Bool
134
136
end
135
137
function OptimizationState (sv:: InferenceState , interp:: AbstractInterpreter )
136
138
inlining = InliningState (sv, interp)
137
139
return OptimizationState (sv. linfo, sv. src, nothing , sv. stmt_info, sv. mod,
138
- sv. sptypes, sv. slottypes, inlining, sv. cfg, sv. insert_coverage)
140
+ sv. sptypes, sv. slottypes, inlining, sv. cfg,
141
+ sv. unreachable, sv. bb_vartables, sv. insert_coverage)
139
142
end
140
143
function OptimizationState (linfo:: MethodInstance , src:: CodeInfo , interp:: AbstractInterpreter )
141
144
# prepare src for running optimization passes if it isn't already
@@ -159,7 +162,15 @@ function OptimizationState(linfo::MethodInstance, src::CodeInfo, interp::Abstrac
159
162
# This method is mostly used for unit testing the optimizer
160
163
inlining = InliningState (interp)
161
164
cfg = compute_basic_blocks (src. code)
162
- return OptimizationState (linfo, src, nothing , stmt_info, mod, sptypes, slottypes, inlining, cfg, false )
165
+ unreachable = BitSet ()
166
+ bb_vartables = Union{VarTable,Nothing}[]
167
+ for block = 1 : length (cfg. blocks)
168
+ push! (bb_vartables, VarState[
169
+ VarState (slottypes[slot], src. slotflags[slot] & SLOT_USEDUNDEF != 0 )
170
+ for slot = 1 : nslots
171
+ ])
172
+ end
173
+ return OptimizationState (linfo, src, nothing , stmt_info, mod, sptypes, slottypes, inlining, cfg, unreachable, bb_vartables, false )
163
174
end
164
175
function OptimizationState (linfo:: MethodInstance , interp:: AbstractInterpreter )
165
176
world = get_world_counter (interp)
@@ -168,7 +179,6 @@ function OptimizationState(linfo::MethodInstance, interp::AbstractInterpreter)
168
179
return OptimizationState (linfo, src, interp)
169
180
end
170
181
171
-
172
182
include (" compiler/ssair/driver.jl" )
173
183
174
184
function ir_to_codeinf! (opt:: OptimizationState )
@@ -328,7 +338,7 @@ function stmt_effect_flags(πβ::AbstractLattice, @nospecialize(stmt), @nospe
328
338
return (false , false , false )
329
339
end
330
340
end
331
- isa (stmt, UnoptSlot ) && error (" unexpected IR elements" )
341
+ isa (stmt, SlotNumber ) && error (" unexpected IR elements" )
332
342
return (true , true , true )
333
343
end
334
344
@@ -363,8 +373,6 @@ function argextype(
363
373
@assert false
364
374
elseif isa (x, SlotNumber)
365
375
return slottypes[x. id]
366
- elseif isa (x, TypedSlot)
367
- return x. typ
368
376
elseif isa (x, SSAValue)
369
377
return abstract_eval_ssavalue (x, src)
370
378
elseif isa (x, Argument)
@@ -523,12 +531,39 @@ function convert_to_ircode(ci::CodeInfo, sv::OptimizationState)
523
531
linetable = collect (LineInfoNode, linetable:: Vector{Any} ):: Vector{LineInfoNode}
524
532
end
525
533
534
+ # Update control-flow to reflect any unreachable branches.
535
+ ssavaluetypes = ci. ssavaluetypes:: Vector{Any}
536
+ code = copy_exprargs (ci. code)
537
+ for i = 1 : length (code)
538
+ expr = code[i]
539
+ if ! (i in sv. unreachable) && isa (expr, GotoIfNot)
540
+ # Replace this live GotoIfNot with:
541
+ # - no-op if :nothrow and the branch target is unreachable
542
+ # - cond if :nothrow and both targets are unreachable
543
+ # - typeassert if must-throw
544
+ if widenconst (argextype (expr. cond, ci, sv. sptypes)) === Bool
545
+ block = block_for_inst (sv. cfg, i)
546
+ if i + 1 in sv. unreachable
547
+ cfg_delete_edge! (sv. cfg, block, block + 1 )
548
+ expr = GotoNode (expr. dest)
549
+ elseif expr. dest in sv. unreachable
550
+ cfg_delete_edge! (sv. cfg, block, block_for_inst (sv. cfg, expr. dest))
551
+ expr = nothing
552
+ end
553
+ elseif ssavaluetypes[i] === Bottom
554
+ block = block_for_inst (sv. cfg, i)
555
+ cfg_delete_edge! (sv. cfg, block, block + 1 )
556
+ cfg_delete_edge! (sv. cfg, block, block_for_inst (sv. cfg, expr. dest))
557
+ expr = Expr (:call , Core. typeassert, expr. cond, Bool)
558
+ end
559
+ code[i] = expr
560
+ end
561
+ end
562
+
526
563
# Go through and add an unreachable node after every
527
564
# Union{} call. Then reindex labels.
528
- code = copy_exprargs (ci. code)
529
565
stmtinfo = sv. stmt_info
530
566
codelocs = ci. codelocs
531
- ssavaluetypes = ci. ssavaluetypes:: Vector{Any}
532
567
ssaflags = ci. ssaflags
533
568
meta = Expr[]
534
569
idx = 1
@@ -562,8 +597,8 @@ function convert_to_ircode(ci::CodeInfo, sv::OptimizationState)
562
597
idx += 1
563
598
prevloc = codeloc
564
599
end
565
- if ssavaluetypes[idx] === Union{} && ! (code[idx] isa Core . Const )
566
- # Type inference should have converted any must-throw terminators to an equivalent w/o control-flow edges
600
+ if ssavaluetypes[idx] === Union{} && ! (oldidx in sv . unreachable )
601
+ # We should have converted any must-throw terminators to an equivalent w/o control-flow edges
567
602
@assert ! isterminator (code[idx])
568
603
569
604
block = block_for_inst (sv. cfg, oldidx)
@@ -589,8 +624,8 @@ function convert_to_ircode(ci::CodeInfo, sv::OptimizationState)
589
624
590
625
# Verify that type-inference did its job
591
626
if JLOptions (). debug_level == 2
592
- for i = (idx + 1 ): (block_end - 1 )
593
- @assert (code[i] isa Core . Const) || is_meta_expr (code[i])
627
+ for i = (oldidx + 1 ): last (sv . cfg . blocks[block] . stmts )
628
+ @assert i in sv . unreachable
594
629
end
595
630
end
596
631
@@ -659,7 +694,7 @@ function slot2reg(ir::IRCode, ci::CodeInfo, sv::OptimizationState)
659
694
@timeit " domtree 1" domtree = construct_domtree (ir. cfg. blocks)
660
695
defuse_insts = scan_slot_def_use (nargs, ci, ir. stmts. stmt)
661
696
πβ = optimizer_lattice (sv. inlining. interp)
662
- @timeit " construct_ssa" ir = construct_ssa! (ci, ir, domtree, defuse_insts, sv . slottypes , πβ) # consumes `ir`
697
+ @timeit " construct_ssa" ir = construct_ssa! (ci, ir, sv, domtree, defuse_insts , πβ) # consumes `ir`
663
698
# NOTE now we have converted `ir` to the SSA form and eliminated slots
664
699
# let's resize `argtypes` now and remove unnecessary types for the eliminated slots
665
700
resize! (ir. argtypes, nargs)
@@ -888,10 +923,7 @@ function renumber_ir_elements!(body::Vector{Any}, ssachangemap::Vector{Int}, lab
888
923
end
889
924
890
925
function renumber_cfg_stmts! (cfg:: CFG , blockchangemap:: Vector{Int} )
891
- any_change = cumsum_ssamap! (blockchangemap)
892
- any_change || return
893
-
894
- last_end = 0
926
+ cumsum_ssamap! (blockchangemap) || return
895
927
for i = 1 : length (cfg. blocks)
896
928
old_range = cfg. blocks[i]. stmts
897
929
new_range = StmtRange (first (old_range) + ((i > 1 ) ? blockchangemap[i - 1 ] : 0 ),
0 commit comments