1+ function compact_exprtype (compact, value)
2+ if isa (value, Union{SSAValue, OldSSAValue})
3+ return types (compact)[value]
4+ elseif isa (value, Argument)
5+ return compact. ir. argtypes[value. n]
6+ end
7+ exprtype (value, compact. ir, compact. ir. mod)
8+ end
9+
10+ function getfield_elim_pass! (ir:: IRCode )
11+ compact = IncrementalCompact (ir)
12+ insertions = Vector {Any} ()
13+ for (idx, stmt) in compact
14+ isa (stmt, Expr) || continue
15+ is_known_call (stmt, getfield, ir, ir. mod) || continue
16+ isa (stmt. args[2 ], SSAValue) || continue
17+ field = stmt. args[3 ]
18+ isa (field, QuoteNode) && (field = field. value)
19+ isa (field, Union{Int, Symbol}) || continue
20+ orig_defidx = defidx = stmt. args[2 ]. id
21+ def = compact[defidx]
22+ typeconstraint = types (compact)[defidx]
23+ phi_locs = Tuple{Int, Int}[]
24+ while true
25+ if isa (def, PiNode)
26+ typeconstraint = typeintersect (typeconstraint, def. typ)
27+ if isa (def. val, SSAValue)
28+ defidx = def. val. id
29+ def = compact[defidx]
30+ else
31+ def = def. val
32+ end
33+ continue
34+ elseif isa (def, PhiNode)
35+ possible_predecessors = collect (Iterators. filter (1 : length (def. edges)) do n
36+ isassigned (def. values, n) || return false
37+ value = def. values[n]
38+ edge_typ = compact_exprtype (compact, value)
39+ return edge_typ ⊑ typeconstraint
40+ end )
41+ # For now, only look at unique predecessors
42+ if length (possible_predecessors) == 1
43+ n = possible_predecessors[1 ]
44+ pred = def. edges[n]
45+ val = def. values[n]
46+ if isa (val, SSAValue)
47+ push! (phi_locs, (pred, defidx))
48+ defidx = val. id
49+ def = compact[defidx]
50+ elseif def == val
51+ # This shouldn't really ever happen, but
52+ # patterns like this can occur in dead code,
53+ # so bail out.
54+ break
55+ else
56+ def = val
57+ end
58+ continue
59+ end
60+ end
61+ break
62+ end
63+ if isa (def, Expr) && is_known_call (def, tuple, ir, ir. mod) && isa (field, Int) && 1 <= field < length (def. args)
64+ forwarded = def. args[1 + field]
65+ elseif isexpr (def, :new )
66+ typ = def. typ
67+ if isa (typ, UnionAll)
68+ typ = unwrap_unionall (typ)
69+ end
70+ isa (typ, DataType) || continue
71+ ! typ. mutable || continue
72+ if isa (field, Symbol)
73+ field = fieldindex (typ, field, false )
74+ field == 0 && continue
75+ elseif isa (field, Integer)
76+ (1 <= field <= fieldcount (typ)) || continue
77+ end
78+ forwarded = def. args[1 + field]
79+ else
80+ continue
81+ end
82+ if ! isempty (phi_locs) && isa (forwarded, SSAValue)
83+ # TODO : We have have to use BB ids for phi_locs
84+ # to avoid index invalidation.
85+ push! (insertions, (idx, phi_locs))
86+ end
87+ compact[idx] = forwarded
88+ end
89+ ir = finish (compact)
90+ for (idx, phi_locs) in insertions
91+ # For non-dominating load-store forward, we may have to insert extra phi nodes
92+ # TODO : Can use the domtree to eliminate unnecessary phis, but ok for now
93+ forwarded = ir. stmts[idx]
94+ if isa (forwarded, SSAValue)
95+ forwarded_typ = ir. types[forwarded. id]
96+ for (pred, pos) in reverse! (phi_locs)
97+ node = PhiNode ()
98+ push! (node. edges, pred)
99+ push! (node. values, forwarded)
100+ forwarded = insert_node! (ir, pos, forwarded_typ, node)
101+ end
102+ end
103+ ir. stmts[idx] = forwarded
104+ end
105+ ir
106+ end
107+
1108function type_lift_pass! (ir:: IRCode )
2109 type_ctx_uses = Vector{Vector{Int}}[]
3110 has_non_type_ctx_uses = IdSet {Int} ()
@@ -81,4 +188,4 @@ function type_lift_pass!(ir::IRCode)
81188 end
82189 end
83190 ir
84- end
191+ end
0 commit comments