Skip to content

Commit b5d2250

Browse files
committed
Make :enter a proper node type
This is a prepratory commit in anticipation of giving :enter additional responsibilities of entering and restoring dynamic scopes for ScopedValue (c.f. #51352). This commit simply turns `:enter` into its own node type (like the other terminators). The changes are largely mechanical from the `Expr` version, but will make it easier to add additional semantics in a follow up PR.
1 parent 9ea29d9 commit b5d2250

24 files changed

+191
-174
lines changed

base/boot.jl

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,7 @@ eval(Core, quote
459459
ReturnNode(@nospecialize val) = $(Expr(:new, :ReturnNode, :val))
460460
ReturnNode() = $(Expr(:new, :ReturnNode)) # unassigned val indicates unreachable
461461
GotoIfNot(@nospecialize(cond), dest::Int) = $(Expr(:new, :GotoIfNot, :cond, :dest))
462+
EnterNode(dest::Int) = $(Expr(:new, :EnterNode, :dest))
462463
LineNumberNode(l::Int) = $(Expr(:new, :LineNumberNode, :l, nothing))
463464
function LineNumberNode(l::Int, @nospecialize(f))
464465
isa(f, String) && (f = Symbol(f))
@@ -626,12 +627,12 @@ module IR
626627
export CodeInfo, MethodInstance, CodeInstance, GotoNode, GotoIfNot, ReturnNode,
627628
NewvarNode, SSAValue, SlotNumber, Argument,
628629
PiNode, PhiNode, PhiCNode, UpsilonNode, LineInfoNode,
629-
Const, PartialStruct, InterConditional
630+
Const, PartialStruct, InterConditional, EnterNode
630631

631632
using Core: CodeInfo, MethodInstance, CodeInstance, GotoNode, GotoIfNot, ReturnNode,
632633
NewvarNode, SSAValue, SlotNumber, Argument,
633634
PiNode, PhiNode, PhiCNode, UpsilonNode, LineInfoNode,
634-
Const, PartialStruct, InterConditional
635+
Const, PartialStruct, InterConditional, EnterNode
635636

636637
end # module IR
637638

@@ -965,4 +966,7 @@ arraysize(a::Array) = a.size
965966
arraysize(a::Array, i::Int) = sle_int(i, nfields(a.size)) ? getfield(a.size, i) : 1
966967
export arrayref, arrayset, arraysize, const_arrayref
967968

969+
# For convenience
970+
EnterNode(old::EnterNode, new_dest::Int) = EnterNode(new_dest)
971+
968972
ccall(:jl_set_istopmod, Cvoid, (Any, Bool), Core, true)

base/compiler/abstractinterpretation.jl

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3102,8 +3102,8 @@ function update_exc_bestguess!(@nospecialize(exct), frame::InferenceState, 𝕃
31023102
handler_frame = frame.handlers[cur_hand]
31033103
if !(𝕃ₚ, exct, handler_frame.exct)
31043104
handler_frame.exct = tmerge(𝕃ₚ, handler_frame.exct, exct)
3105-
enter = frame.src.code[handler_frame.enter_idx]::Expr
3106-
exceptbb = block_for_inst(frame.cfg, enter.args[1]::Int)
3105+
enter = frame.src.code[handler_frame.enter_idx]::EnterNode
3106+
exceptbb = block_for_inst(frame.cfg, enter.catch_dest)
31073107
push!(frame.ip, exceptbb)
31083108
end
31093109
end
@@ -3114,8 +3114,8 @@ function propagate_to_error_handler!(currstate::VarTable, frame::InferenceState,
31143114
# exception handler, BEFORE applying any state changes.
31153115
cur_hand = frame.handler_at[frame.currpc][1]
31163116
if cur_hand != 0
3117-
enter = frame.src.code[frame.handlers[cur_hand].enter_idx]::Expr
3118-
exceptbb = block_for_inst(frame.cfg, enter.args[1]::Int)
3117+
enter = frame.src.code[frame.handlers[cur_hand].enter_idx]::EnterNode
3118+
exceptbb = block_for_inst(frame.cfg, enter.catch_dest)
31193119
if update_bbstate!(𝕃ᵢ, frame, exceptbb, currstate)
31203120
push!(frame.ip, exceptbb)
31213121
end
@@ -3256,8 +3256,9 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
32563256
end
32573257
ssavaluetypes[frame.currpc] = Any
32583258
@goto find_next_bb
3259-
elseif isexpr(stmt, :enter)
3259+
elseif isa(stmt, EnterNode)
32603260
ssavaluetypes[currpc] = Any
3261+
add_curr_ssaflag!(frame, IR_FLAG_NOTHROW)
32613262
@goto fallthrough
32623263
elseif isexpr(stmt, :leave)
32633264
ssavaluetypes[currpc] = Any

base/compiler/inferencestate.jl

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -362,8 +362,8 @@ function compute_trycatch(code::Vector{Any}, ip::BitSet)
362362
# start from all :enter statements and record the location of the try
363363
for pc = 1:n
364364
stmt = code[pc]
365-
if isexpr(stmt, :enter)
366-
l = stmt.args[1]::Int
365+
if isa(stmt, EnterNode)
366+
l = stmt.catch_dest
367367
push!(handlers, TryCatchFrame(Bottom, pc))
368368
handler_id = length(handlers)
369369
handler_at[pc + 1] = (handler_id, 0)
@@ -396,15 +396,15 @@ function compute_trycatch(code::Vector{Any}, ip::BitSet)
396396
elseif isa(stmt, ReturnNode)
397397
@assert !isdefined(stmt, :val) || cur_stacks[1] == 0 "unbalanced try/catch"
398398
break
399+
elseif isa(stmt, EnterNode)
400+
l = stmt.catch_dest
401+
# We assigned a handler number above. Here we just merge that
402+
# with out current handler information.
403+
handler_at[l] = (cur_stacks[1], handler_at[l][2])
404+
cur_stacks = (handler_at[pc´][1], cur_stacks[2])
399405
elseif isa(stmt, Expr)
400406
head = stmt.head
401-
if head === :enter
402-
l = stmt.args[1]::Int
403-
# We assigned a handler number above. Here we just merge that
404-
# with out current handler information.
405-
handler_at[l] = (cur_stacks[1], handler_at[l][2])
406-
cur_stacks = (handler_at[pc´][1], cur_stacks[2])
407-
elseif head === :leave
407+
if head === :leave
408408
l = 0
409409
for j = 1:length(stmt.args)
410410
arg = stmt.args[j]
@@ -415,7 +415,7 @@ function compute_trycatch(code::Vector{Any}, ip::BitSet)
415415
if enter_stmt === nothing
416416
continue
417417
end
418-
@assert isexpr(enter_stmt, :enter) "malformed :leave"
418+
@assert isa(enter_stmt, EnterNode) "malformed :leave"
419419
end
420420
l += 1
421421
end

base/compiler/optimize.jl

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,7 @@ function stmt_effect_flags(𝕃ₒ::AbstractLattice, @nospecialize(stmt), @nospe
270270
isa(stmt, PiNode) && return (true, true, true)
271271
isa(stmt, PhiNode) && return (true, true, true)
272272
isa(stmt, ReturnNode) && return (true, false, true)
273+
isa(stmt, EnterNode) && return (true, false, true)
273274
isa(stmt, GotoNode) && return (true, false, true)
274275
isa(stmt, GotoIfNot) && return (true, false, (𝕃ₒ, argextype(stmt.cond, src), Bool))
275276
if isa(stmt, GlobalRef)
@@ -761,7 +762,7 @@ end
761762
function ((; sv)::ScanStmt)(inst::Instruction, lstmt::Int, bb::Int)
762763
stmt = inst[:stmt]
763764

764-
if isexpr(stmt, :enter)
765+
if isa(stmt, EnterNode)
765766
# try/catch not yet modeled
766767
give_up_refinements!(sv)
767768
return nothing
@@ -971,8 +972,8 @@ function convert_to_ircode(ci::CodeInfo, sv::OptimizationState)
971972
expr = nothing
972973
end
973974
code[i] = expr
974-
elseif isexpr(expr, :enter)
975-
catchdest = expr.args[1]::Int
975+
elseif isa(expr, EnterNode)
976+
catchdest = expr.catch_dest
976977
if catchdest in sv.unreachable
977978
cfg_delete_edge!(sv.cfg, block_for_inst(sv.cfg, i), block_for_inst(sv.cfg, catchdest))
978979
code[i] = nothing
@@ -1239,12 +1240,6 @@ function statement_cost(ex::Expr, line::Int, src::Union{CodeInfo, IRCode}, sptyp
12391240
return cost
12401241
elseif head === :copyast
12411242
return 100
1242-
elseif head === :enter
1243-
# try/catch is a couple function calls,
1244-
# but don't inline functions with try/catch
1245-
# since these aren't usually performance-sensitive functions,
1246-
# and llvm is more likely to miscompile them when these functions get large
1247-
return typemax(Int)
12481243
end
12491244
return 0
12501245
end
@@ -1263,6 +1258,12 @@ function statement_or_branch_cost(@nospecialize(stmt), line::Int, src::Union{Cod
12631258
thiscost = dst(stmt.label) < line ? 40 : 0
12641259
elseif stmt isa GotoIfNot
12651260
thiscost = dst(stmt.dest) < line ? 40 : 0
1261+
elseif stmt isa EnterNode
1262+
# try/catch is a couple function calls,
1263+
# but don't inline functions with try/catch
1264+
# since these aren't usually performance-sensitive functions,
1265+
# and llvm is more likely to miscompile them when these functions get large
1266+
thiscost = typemax(Int)
12661267
end
12671268
return thiscost
12681269
end
@@ -1359,19 +1360,19 @@ function renumber_ir_elements!(body::Vector{Any}, ssachangemap::Vector{Int}, lab
13591360
i += 1
13601361
end
13611362
end
1363+
elseif isa(el, EnterNode)
1364+
tgt = el.catch_dest
1365+
was_deleted = labelchangemap[tgt] == typemin(Int)
1366+
if was_deleted
1367+
body[i] = nothing
1368+
else
1369+
body[i] = EnterNode(el, tgt + labelchangemap[tgt])
1370+
end
13621371
elseif isa(el, Expr)
13631372
if el.head === :(=) && el.args[2] isa Expr
13641373
el = el.args[2]::Expr
13651374
end
1366-
if el.head === :enter
1367-
tgt = el.args[1]::Int
1368-
was_deleted = labelchangemap[tgt] == typemin(Int)
1369-
if was_deleted
1370-
body[i] = nothing
1371-
else
1372-
el.args[1] = tgt + labelchangemap[tgt]
1373-
end
1374-
elseif !is_meta_expr_head(el.head)
1375+
if !is_meta_expr_head(el.head)
13751376
args = el.args
13761377
for i = 1:length(args)
13771378
el = args[i]

base/compiler/ssair/EscapeAnalysis/EscapeAnalysis.jl

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -652,7 +652,7 @@ function analyze_escapes(ir::IRCode, nargs::Int, 𝕃ₒ::AbstractLattice, get_e
652652
elseif is_meta_expr_head(head)
653653
# meta expressions doesn't account for any usages
654654
continue
655-
elseif head === :enter || head === :leave || head === :the_exception || head === :pop_exception
655+
elseif head === :leave || head === :the_exception || head === :pop_exception
656656
# ignore these expressions since escapes via exceptions are handled by `escape_exception!`
657657
# `escape_exception!` conservatively propagates `AllEscape` anyway,
658658
# and so escape information imposed on `:the_exception` isn't computed
@@ -666,6 +666,9 @@ function analyze_escapes(ir::IRCode, nargs::Int, 𝕃ₒ::AbstractLattice, get_e
666666
else
667667
add_conservative_changes!(astate, pc, stmt.args)
668668
end
669+
elseif isa(stmt, EnterNode)
670+
# Handled via escape_exception!
671+
continue
669672
elseif isa(stmt, ReturnNode)
670673
if isdefined(stmt, :val)
671674
add_escape_change!(astate, stmt.val, ReturnEscape(pc))
@@ -728,10 +731,10 @@ function compute_frameinfo(ir::IRCode)
728731
for idx in 1:nstmts+nnewnodes
729732
inst = ir[SSAValue(idx)]
730733
stmt = inst[:stmt]
731-
if isexpr(stmt, :enter)
734+
if isa(stmt, EnterNode)
732735
@assert idx nstmts "try/catch inside new_nodes unsupported"
733736
tryregions === nothing && (tryregions = UnitRange{Int}[])
734-
leave_block = stmt.args[1]::Int
737+
leave_block = stmt.catch_dest
735738
leave_pc = first(ir.cfg.blocks[leave_block].stmts)
736739
push!(tryregions, idx:leave_pc)
737740
elseif arrayinfo !== nothing

base/compiler/ssair/inlining.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -459,8 +459,8 @@ function ir_inline_item!(compact::IncrementalCompact, idx::Int, argexprs::Vector
459459
end
460460
elseif isa(stmt′, GotoNode)
461461
stmt′ = GotoNode(stmt′.label + bb_offset)
462-
elseif isa(stmt′, Expr) && stmt′.head === :enter
463-
stmt′ = Expr(:enter, stmt′.args[1]::Int + bb_offset)
462+
elseif isa(stmt′, EnterNode)
463+
stmt′ = EnterNode(stmt′, stmt′.catch_dest + bb_offset)
464464
elseif isa(stmt′, GotoIfNot)
465465
stmt′ = GotoIfNot(stmt′.cond, stmt′.dest + bb_offset)
466466
elseif isa(stmt′, PhiNode)
@@ -710,8 +710,8 @@ function batch_inline!(ir::IRCode, todo::Vector{Pair{Int,Any}}, propagate_inboun
710710
end
711711
elseif isa(stmt, GotoNode)
712712
compact[idx] = GotoNode(state.bb_rename[stmt.label])
713-
elseif isa(stmt, Expr) && stmt.head === :enter
714-
compact[idx] = Expr(:enter, state.bb_rename[stmt.args[1]::Int])
713+
elseif isa(stmt, EnterNode)
714+
compact[idx] = EnterNode(stmt, state.bb_rename[stmt.catch_dest])
715715
elseif isa(stmt, GotoIfNot)
716716
compact[idx] = GotoIfNot(stmt.cond, state.bb_rename[stmt.dest])
717717
elseif isa(stmt, PhiNode)

base/compiler/ssair/ir.jl

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
Core.PhiNode() = Core.PhiNode(Int32[], Any[])
44

5-
isterminator(@nospecialize(stmt)) = isa(stmt, GotoNode) || isa(stmt, GotoIfNot) || isa(stmt, ReturnNode)
5+
isterminator(@nospecialize(stmt)) = isa(stmt, GotoNode) || isa(stmt, GotoIfNot) || isa(stmt, ReturnNode) || isa(stmt, EnterNode)
66

77
struct CFG
88
blocks::Vector{BasicBlock}
@@ -60,16 +60,16 @@ block_for_inst(cfg::CFG, inst::Int) = block_for_inst(cfg.index, inst)
6060
# This is a fake dest to force the next stmt to start a bb
6161
idx < length(stmts) && push!(jump_dests, idx+1)
6262
push!(jump_dests, stmt.label)
63+
elseif isa(stmt, EnterNode)
64+
# :enter starts/ends a BB
65+
push!(jump_dests, idx)
66+
push!(jump_dests, idx+1)
67+
# The catch block is a jump dest
68+
push!(jump_dests, stmt.catch_dest)
6369
elseif isa(stmt, Expr)
6470
if stmt.head === :leave
6571
# :leave terminates a BB
6672
push!(jump_dests, idx+1)
67-
elseif stmt.head === :enter
68-
# :enter starts/ends a BB
69-
push!(jump_dests, idx)
70-
push!(jump_dests, idx+1)
71-
# The catch block is a jump dest
72-
push!(jump_dests, stmt.args[1]::Int)
7373
end
7474
end
7575
if isa(stmt, PhiNode)
@@ -125,11 +125,11 @@ function compute_basic_blocks(stmts::Vector{Any})
125125
push!(blocks[block′].preds, num)
126126
push!(b.succs, block′)
127127
end
128-
elseif isexpr(terminator, :enter)
128+
elseif isa(terminator, EnterNode)
129129
# :enter gets a virtual edge to the exception handler and
130130
# the exception handler gets a virtual edge from outside
131131
# the function.
132-
block′ = block_for_inst(basic_block_index, terminator.args[1]::Int)
132+
block′ = block_for_inst(basic_block_index, terminator.catch_dest)
133133
push!(blocks[block′].preds, num)
134134
push!(blocks[block′].preds, 0)
135135
push!(b.succs, block′)
@@ -456,6 +456,10 @@ struct UndefToken end; const UNDEF_TOKEN = UndefToken()
456456
isdefined(stmt, :val) || return OOB_TOKEN
457457
op == 1 || return OOB_TOKEN
458458
return stmt.val
459+
elseif isa(stmt, EnterNode)
460+
isdefined(stmt, :scope) || return OOB_TOKEN
461+
op == 1 || return OOB_TOKEN
462+
return stmt.scope
459463
elseif isa(stmt, PiNode)
460464
isdefined(stmt, :val) || return OOB_TOKEN
461465
op == 1 || return OOB_TOKEN
@@ -510,6 +514,9 @@ end
510514
elseif isa(stmt, GotoIfNot)
511515
op == 1 || throw(BoundsError())
512516
stmt = GotoIfNot(v, stmt.dest)
517+
elseif isa(stmt, EnterNode)
518+
op == 1 || throw(BoundsError())
519+
stmt = EnterNode(stmt.catch_dest, v)
513520
elseif isa(stmt, ReturnNode)
514521
op == 1 || throw(BoundsError())
515522
stmt = typeof(stmt)(v)
@@ -544,7 +551,7 @@ end
544551
function userefs(@nospecialize(x))
545552
relevant = (isa(x, Expr) && is_relevant_expr(x)) ||
546553
isa(x, GotoIfNot) || isa(x, ReturnNode) || isa(x, SSAValue) || isa(x, NewSSAValue) ||
547-
isa(x, PiNode) || isa(x, PhiNode) || isa(x, PhiCNode) || isa(x, UpsilonNode)
554+
isa(x, PiNode) || isa(x, PhiNode) || isa(x, PhiCNode) || isa(x, UpsilonNode) || isa(x, EnterNode)
548555
return UseRefIterator(x, relevant)
549556
end
550557

@@ -1379,13 +1386,15 @@ function process_node!(compact::IncrementalCompact, result_idx::Int, inst::Instr
13791386
result[result_idx][:stmt] = GotoIfNot(cond, label)
13801387
result_idx += 1
13811388
end
1389+
elseif cfg_transforms_enabled && isa(stmt, EnterNode)
1390+
label = bb_rename_succ[stmt.catch_dest]
1391+
@assert label > 0
1392+
ssa_rename[idx] = SSAValue(result_idx)
1393+
result[result_idx][:stmt] = EnterNode(stmt, label)
1394+
result_idx += 1
13821395
elseif isa(stmt, Expr)
13831396
stmt = renumber_ssa2!(stmt, ssa_rename, used_ssas, new_new_used_ssas, late_fixup, result_idx, do_rename_ssa, mark_refined!)::Expr
1384-
if cfg_transforms_enabled && isexpr(stmt, :enter)
1385-
label = bb_rename_succ[stmt.args[1]::Int]
1386-
@assert label > 0
1387-
stmt.args[1] = label
1388-
elseif isexpr(stmt, :throw_undef_if_not)
1397+
if isexpr(stmt, :throw_undef_if_not)
13891398
cond = stmt.args[2]
13901399
if isa(cond, Bool) && cond === true
13911400
# cond was folded to true - this statement
@@ -1445,7 +1454,7 @@ function process_node!(compact::IncrementalCompact, result_idx::Int, inst::Instr
14451454
ssa_rename[idx] = SSAValue(result_idx)
14461455
result[result_idx][:stmt] = stmt
14471456
result_idx += 1
1448-
elseif isa(stmt, ReturnNode) || isa(stmt, UpsilonNode) || isa(stmt, GotoIfNot)
1457+
elseif isa(stmt, ReturnNode) || isa(stmt, UpsilonNode) || isa(stmt, GotoIfNot) || isa(stmt, EnterNode)
14491458
ssa_rename[idx] = SSAValue(result_idx)
14501459
result[result_idx][:stmt] = renumber_ssa2!(stmt, ssa_rename, used_ssas, new_new_used_ssas, late_fixup, result_idx, do_rename_ssa, mark_refined!)
14511460
result_idx += 1

base/compiler/ssair/irinterp.jl

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ function kill_terminator_edges!(irsv::IRInterpretationState, term_idx::Int, bb::
9696
elseif isa(stmt, ReturnNode)
9797
# Nothing to do
9898
else
99-
@assert !isexpr(stmt, :enter)
99+
@assert !isa(stmt, EnterNode)
100100
kill_edge!(irsv, bb, bb+1)
101101
end
102102
end
@@ -222,8 +222,8 @@ function process_terminator!(@nospecialize(stmt), bb::Int, bb_ip::BitSetBoundedM
222222
backedge || push!(bb_ip, stmt.dest)
223223
push!(bb_ip, bb+1)
224224
return backedge
225-
elseif isexpr(stmt, :enter)
226-
dest = stmt.args[1]::Int
225+
elseif isa(stmt, EnterNode)
226+
dest = stmt.catch_dest
227227
@assert dest > bb
228228
push!(bb_ip, dest)
229229
push!(bb_ip, bb+1)
@@ -329,8 +329,7 @@ function _ir_abstract_constant_propagation(interp::AbstractInterpreter, irsv::IR
329329
delete!(ssa_refined, idx)
330330
end
331331
check_ret!(stmt, idx)
332-
is_terminator_or_phi = (isa(stmt, PhiNode) || isa(stmt, GotoNode) ||
333-
isa(stmt, GotoIfNot) || isa(stmt, ReturnNode) || isexpr(stmt, :enter))
332+
is_terminator_or_phi = (isa(stmt, PhiNode) || isterminator(stmt))
334333
if typ === Bottom && !(idx == lstmt && is_terminator_or_phi)
335334
return true
336335
end

0 commit comments

Comments
 (0)