Skip to content

Commit 59bffa5

Browse files
authored
Merge pull request #26726 from JuliaLang/kf/ssaexc
[NewOptimizer] Handle exceptions in new IR
2 parents 16e4f85 + 7ddc02d commit 59bffa5

27 files changed

+1972
-458
lines changed

base/boot.jl

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,14 @@
108108
# values::Vector{Any}
109109
#end
110110

111+
#struct PhiCNode
112+
# values::Vector{Any}
113+
#end
114+
115+
#struct UpsilonNode
116+
# val
117+
#end
118+
111119
#struct QuoteNode
112120
# value
113121
#end
@@ -151,7 +159,7 @@ export
151159
TypeError, ArgumentError, MethodError, AssertionError, LoadError, InitError,
152160
UndefKeywordError,
153161
# AST representation
154-
Expr, QuoteNode, LineNumberNode, GlobalRef, PiNode, PhiNode,
162+
Expr, QuoteNode, LineNumberNode, GlobalRef,
155163
# object model functions
156164
fieldtype, getfield, setfield!, nfields, throw, tuple, ===, isdefined, eval,
157165
# sizeof # not exported, to avoid conflicting with Base.sizeof
@@ -357,6 +365,9 @@ eval(Core, :(SlotNumber(n::Int) = $(Expr(:new, :SlotNumber, :n))))
357365
eval(Core, :(TypedSlot(n::Int, @nospecialize(t)) = $(Expr(:new, :TypedSlot, :n, :t))))
358366
eval(Core, :(PhiNode(edges::Array{Any, 1}, values::Array{Any, 1}) = $(Expr(:new, :PhiNode, :edges, :values))))
359367
eval(Core, :(PiNode(val, typ) = $(Expr(:new, :PiNode, :val, :typ))))
368+
eval(Core, :(PhiCNode(values::Array{Any, 1}) = $(Expr(:new, :PhiCNode, :values))))
369+
eval(Core, :(UpsilonNode(val) = $(Expr(:new, :UpsilonNode, :val))))
370+
eval(Core, :(UpsilonNode() = $(Expr(:new, :UpsilonNode))))
360371

361372
Module(name::Symbol=:anonymous, std_imports::Bool=true) = ccall(:jl_f_new_module, Ref{Module}, (Any, Bool), name, std_imports)
362373

@@ -419,13 +430,26 @@ function Symbol(a::Array{UInt8,1})
419430
end
420431
Symbol(s::Symbol) = s
421432

433+
struct LineInfoNode
434+
mod::Module
435+
method::Symbol
436+
file::Symbol
437+
line::Int
438+
inlined_at::Int
439+
LineInfoNode(mod::Module, method::Symbol, file::Symbol, line::Int, inlined_at::Int) =
440+
new(mod, method, file, line, inlined_at)
441+
end
442+
422443
# module providing the IR object model
423444
module IR
424445
export CodeInfo, MethodInstance, GotoNode, LabelNode,
425-
NewvarNode, SSAValue, Slot, SlotNumber, TypedSlot
446+
NewvarNode, SSAValue, Slot, SlotNumber, TypedSlot,
447+
PiNode, PhiNode, PhiCNode, UpsilonNode, LineInfoNode
426448

427449
import Core: CodeInfo, MethodInstance, GotoNode, LabelNode,
428-
NewvarNode, SSAValue, Slot, SlotNumber, TypedSlot
450+
NewvarNode, SSAValue, Slot, SlotNumber, TypedSlot,
451+
PiNode, PhiNode, PhiCNode, UpsilonNode, LineInfoNode
452+
429453
end
430454

431455
# docsystem basics

base/compiler/abstractinterpretation.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -866,7 +866,8 @@ function abstract_eval_global(M::Module, s::Symbol)
866866
end
867867

868868
function abstract_eval_ssavalue(s::SSAValue, src::CodeInfo)
869-
typ = src.ssavaluetypes[s.id + 1]
869+
new_style_ir = src.codelocs !== nothing
870+
typ = src.ssavaluetypes[new_style_ir ? s.id : (s.id + 1)]
870871
if typ === NOT_FOUND
871872
return Bottom
872873
end

base/compiler/optimize.jl

Lines changed: 27 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
# This file is a part of Julia. License is MIT: https://julialang.org/license
22

3-
include("compiler/ssair/driver.jl")
4-
53
#####################
64
# OptimizationState #
75
#####################
@@ -71,6 +69,8 @@ function OptimizationState(linfo::MethodInstance, params::Params)
7169
return OptimizationState(linfo, src, params)
7270
end
7371

72+
include("compiler/ssair/driver.jl")
73+
7474
_topmod(sv::OptimizationState) = _topmod(sv.mod)
7575

7676
genlabel(sv::OptimizationState) = LabelNode(sv.next_label += 1)
@@ -279,37 +279,33 @@ function optimize(me::InferenceState)
279279
me.linfo.inInference = false
280280
elseif me.optimize
281281
opt = OptimizationState(me)
282-
# This pass is required for the AST to be valid in codegen
283-
# if any `SSAValue` is created by type inference. Ref issue #6068
284-
# This (and `reindex_labels!`) needs to be run for `!me.optimize`
285-
# if we start to create `SSAValue` in type inference when not
286-
# optimizing and use unoptimized IR in codegen.
287-
gotoifnot_elim_pass!(opt)
288-
inlining_pass!(opt, opt.src.propagate_inbounds)
289-
any_enter = any_phi = false
290-
if enable_new_optimizer[]
291-
any_enter = any(x->isa(x, Expr) && x.head == :enter, opt.src.code)
292-
any_phi = any(x->isa(x, PhiNode) || (isa(x, Expr) && x.head == :(=) && isa(x.args[2], PhiNode)), opt.src.code)
293-
end
294-
if enable_new_optimizer[] && !any_enter && isa(def, Method)
282+
if enable_new_optimizer[] && isa(def, Method)
295283
reindex_labels!(opt)
296284
nargs = Int(opt.nargs) - 1
297285
if def isa Method
298-
topline = LineInfoNode(opt.mod, def.name, def.file, def.line, 0)
286+
topline = LineInfoNode(opt.mod, def.name, def.file, Int(def.line), Int(0))
299287
else
300288
topline = LineInfoNode(opt.mod, NullLineInfo.name, NullLineInfo.file, 0, 0)
301289
end
302290
linetable = [topline]
303-
ir = run_passes(opt.src, nargs, linetable)
304-
replace_code!(opt.src, ir, nargs, linetable)
305-
push!(opt.src.code, LabelNode(length(opt.src.code) + 1))
306-
any_phi = true
307-
elseif !any_phi
291+
@timeit "optimizer" ir = run_passes(opt.src, nargs, linetable, opt)
292+
force_noinline = any(x->isexpr(x, :meta) && x.args[1] == :noinline, ir.meta)
293+
#@timeit "legacy conversion" replace_code!(opt.src, ir, nargs, linetable)
294+
replace_code_newstyle!(opt.src, ir, nargs, linetable)
295+
else
296+
# This pass is required for the AST to be valid in codegen
297+
# if any `SSAValue` is created by type inference. Ref issue #6068
298+
# This (and `reindex_labels!`) needs to be run for `!me.optimize`
299+
# if we start to create `SSAValue` in type inference when not
300+
# optimizing and use unoptimized IR in codegen.
301+
gotoifnot_elim_pass!(opt)
302+
inlining_pass!(opt, opt.src.propagate_inbounds)
308303
# Clean up after inlining
309304
gotoifnot_elim_pass!(opt)
310305
basic_dce_pass!(opt)
311306
void_use_elim_pass!(opt)
312-
if !enable_new_optimizer[]
307+
any_phi = any(x->isa(x, PhiNode) || (isa(x, Expr) && x.head == :(=) && isa(x.args[2], PhiNode)), opt.src.code)
308+
if !any_phi && !enable_new_optimizer[]
313309
copy_duplicated_expr_pass!(opt)
314310
split_undef_flag_pass!(opt)
315311
fold_constant_getfield_pass!(opt)
@@ -321,13 +317,13 @@ function optimize(me::InferenceState)
321317
basic_dce_pass!(opt)
322318
void_use_elim_pass!(opt)
323319
end
324-
end
325-
# Pop metadata before label reindexing
326-
let code = opt.src.code::Array{Any,1}
327-
meta_elim_pass!(code, coverage_enabled())
328-
filter!(x -> x !== nothing, code)
329-
force_noinline = peekmeta(code, :noinline)[1]
330-
reindex_labels!(opt)
320+
# Pop metadata before label reindexing
321+
let code = opt.src.code::Array{Any,1}
322+
meta_elim_pass!(code, coverage_enabled())
323+
filter!(x -> x !== nothing, code)
324+
force_noinline = peekmeta(code, :noinline)[1]
325+
reindex_labels!(opt)
326+
end
331327
end
332328
me.min_valid = opt.min_valid
333329
me.max_valid = opt.max_valid
@@ -1510,7 +1506,7 @@ function inlineable(@nospecialize(f), @nospecialize(ft), e::Expr, atypes::Vector
15101506
end
15111507
end
15121508
edges = Any[newlabels[edge::Int + 1] - 1 for edge in edges]
1513-
a.args[2] = PhiNode(edges, a.args[2].values)
1509+
a.args[2] = PhiNode(edges, copy_exprargs(a.args[2].values))
15141510
elseif a.head === :meta && length(a.args) > 0
15151511
a1 = a.args[1]
15161512
if a1 === :push_loc
@@ -4234,6 +4230,7 @@ function reindex_labels!(body::Vector{Any})
42344230
elseif el.head === :(=)
42354231
if isa(el.args[2], PhiNode)
42364232
edges = Any[mapping[edge::Int + 1] - 1 for edge in el.args[2].edges]
4233+
@assert all(x->x >= 0, edges)
42374234
el.args[2] = PhiNode(convert(Vector{Any}, edges), el.args[2].values)
42384235
end
42394236
end

base/compiler/ssair/domtree.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ function construct_domtree(cfg)
6666
changed = false
6767
for n = 2:length(cfg.blocks)
6868
isempty(cfg.blocks[n].preds) && continue
69-
firstp, rest = Iterators.peel(cfg.blocks[n].preds)
69+
firstp, rest = Iterators.peel(Iterators.filter(p->p != 0, cfg.blocks[n].preds))
7070
new_doms = copy(dominators[firstp])
7171
for p in rest
7272
intersect!(new_doms, dominators[p])

base/compiler/ssair/driver.jl

Lines changed: 55 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,34 @@
1-
struct LineInfoNode
2-
mod::Module
3-
method::Symbol
4-
file::Symbol
5-
line::Int
6-
inlined_at::Int
7-
end
1+
using Core: LineInfoNode
82
const NullLineInfo = LineInfoNode(@__MODULE__, Symbol(""), Symbol(""), 0, 0)
93

4+
if false
5+
import Base: Base, @show
6+
else
7+
macro show(s)
8+
return :(println(stdout, $(QuoteNode(s)), " = ", $(esc(s))))
9+
end
10+
end
11+
1012
include("compiler/ssair/ir.jl")
1113
include("compiler/ssair/domtree.jl")
1214
include("compiler/ssair/slot2ssa.jl")
1315
include("compiler/ssair/queries.jl")
1416
include("compiler/ssair/passes.jl")
17+
include("compiler/ssair/inlining2.jl")
1518
include("compiler/ssair/verify.jl")
1619
include("compiler/ssair/legacy.jl")
20+
@isdefined(Base) && include("compiler/ssair/show.jl")
1721

18-
macro show(s)
19-
# return :(println($(QuoteNode(s)), " = ", $(esc(s))))
22+
function normalize_expr(stmt::Expr)
23+
if stmt.head === :gotoifnot
24+
return GotoIfNot(stmt.args...)
25+
elseif stmt.head === :return
26+
return ReturnNode((length(stmt.args) == 0 ? (nothing,) : stmt.args)...)
27+
elseif stmt.head === :unreachable
28+
return ReturnNode()
29+
else
30+
return stmt
31+
end
2032
end
2133

2234
function normalize(@nospecialize(stmt), meta::Vector{Any}, table::Vector{LineInfoNode}, loc::RefValue{Int})
@@ -62,12 +74,8 @@ function normalize(@nospecialize(stmt), meta::Vector{Any}, table::Vector{LineInf
6274
return nothing
6375
elseif stmt.head === :line
6476
return nothing # deprecated - we shouldn't encounter this
65-
elseif stmt.head === :gotoifnot
66-
return GotoIfNot(stmt.args...)
67-
elseif stmt.head === :return
68-
return ReturnNode((length(stmt.args) == 0 ? (nothing,) : stmt.args)...)
69-
elseif stmt.head === :unreachable
70-
return ReturnNode()
77+
else
78+
return normalize_expr(stmt)
7179
end
7280
elseif isa(stmt, LabelNode)
7381
return nothing
@@ -88,55 +96,61 @@ function normalize(@nospecialize(stmt), meta::Vector{Any}, table::Vector{LineInf
8896
return stmt
8997
end
9098

91-
function run_passes(ci::CodeInfo, nargs::Int, linetable::Vector{LineInfoNode})
99+
function just_construct_ssa(ci::CodeInfo, code::Vector{Any}, nargs::Int, linetable::Vector{LineInfoNode})
92100
mod = linetable[1].mod
93-
ci.code = copy(ci.code)
94101
# Go through and add an unreachable node after every
95102
# Union{} call. Then reindex labels.
96103
idx = 1
97-
while idx <= length(ci.code)
98-
stmt = ci.code[idx]
104+
while idx <= length(code)
105+
stmt = code[idx]
99106
if isexpr(stmt, :(=))
100107
stmt = stmt.args[2]
101108
end
102109
if isa(stmt, Expr) && stmt.typ === Union{}
103-
if !(idx < length(ci.code) && isexpr(ci.code[idx+1], :unreachable))
104-
insert!(ci.code, idx + 1, ReturnNode())
110+
if !(idx < length(code) && isexpr(code[idx+1], :unreachable))
111+
insert!(code, idx + 1, ReturnNode())
105112
idx += 1
106113
end
107114
end
108115
idx += 1
109116
end
110-
reindex_labels!(ci.code)
117+
reindex_labels!(code)
111118
meta = Any[]
112-
lines = fill(0, length(ci.code))
119+
lines = fill(0, length(code))
113120
let loc = RefValue(1)
114-
for i = 1:length(ci.code)
115-
stmt = ci.code[i]
121+
for i = 1:length(code)
122+
stmt = code[i]
116123
stmt = normalize(stmt, meta, linetable, loc)
117-
ci.code[i] = stmt
124+
code[i] = stmt
118125
if !(stmt === nothing)
119126
lines[i] = loc[]
120127
end
121128
end
122129
end
123-
ci.code = strip_trailing_junk!(ci.code, lines)
124-
cfg = compute_basic_blocks(ci.code)
125-
defuse_insts = scan_slot_def_use(nargs, ci)
126-
domtree = construct_domtree(cfg)
127-
ir = let code = Any[nothing for _ = 1:length(ci.code)]
130+
code = strip_trailing_junk!(code, lines)
131+
cfg = compute_basic_blocks(code)
132+
defuse_insts = scan_slot_def_use(nargs, ci, code)
133+
@timeit "domtree 1" domtree = construct_domtree(cfg)
134+
ir = let code = Any[nothing for _ = 1:length(code)]
128135
argtypes = ci.slottypes[1:(nargs+1)]
129-
IRCode(code, lines, cfg, argtypes, mod, meta)
136+
IRCode(code, Any[], lines, cfg, argtypes, mod, meta)
130137
end
131-
ir = construct_ssa!(ci, ir, domtree, defuse_insts, nargs)
138+
@timeit "construct_ssa" ir = construct_ssa!(ci, code, ir, domtree, defuse_insts, nargs)
139+
return ir
140+
end
141+
142+
function run_passes(ci::CodeInfo, nargs::Int, linetable::Vector{LineInfoNode}, sv::OptimizationState)
143+
ir = just_construct_ssa(ci, copy(ci.code), nargs, linetable)
132144
# TODO: Domsorting can produce an updated domtree - no need to recompute here
133-
domtree = construct_domtree(ir.cfg)
134-
ir = compact!(ir)
135-
verify_ir(ir)
136-
ir = getfield_elim_pass!(ir, domtree)
137-
ir = compact!(ir)
138-
ir = type_lift_pass!(ir)
139-
ir = compact!(ir)
140-
verify_ir(ir)
145+
@timeit "compact 1" ir = compact!(ir)
146+
#@timeit "verify 1" verify_ir(ir)
147+
@timeit "Inlining" ir = ssa_inlining_pass!(ir, nothing, linetable, sv)
148+
#@timeit "verify 2" verify_ir(ir)
149+
@timeit "domtree 2" domtree = construct_domtree(ir.cfg)
150+
@timeit "SROA" ir = getfield_elim_pass!(ir, domtree)
151+
@timeit "compact 2" ir = compact!(ir)
152+
@timeit "type lift" ir = type_lift_pass!(ir)
153+
@timeit "compact 3" ir = compact!(ir)
154+
#@timeit "verify 3" verify_ir(ir)
141155
return ir
142156
end

0 commit comments

Comments
 (0)