@@ -93,23 +93,50 @@ function compute_value_for_use(ir::IRCode, domtree::DomTree, allblocks::Vector{I
93
93
end
94
94
end
95
95
96
+ # even when the allocation contains an uninitialized field, we try an extra effort to check
97
+ # if this load at `idx` have any "safe" `setfield!` calls that define the field
98
+ function has_safe_def (
99
+ ir:: IRCode , domtree:: DomTree , allblocks:: Vector{Int} , du:: SSADefUse ,
100
+ newidx:: Int , idx:: Int , inclusive:: Bool = false )
101
+ def = first (find_def_for_use (ir, domtree, allblocks, du, idx, inclusive))
102
+
103
+ # this field is supposed to be defined at the `:new` site (but it's not and thus this load will throw)
104
+ def == newidx && return false
105
+
106
+ def ≠ 0 && return true # found a "safe" definition
107
+
108
+ # we may be able to replace this load with `PhiNode` if all the predecessors have "safe" definitions
109
+ idxblock = block_for_inst (ir, idx)
110
+ for pred in ir. cfg. blocks[idxblock]. preds
111
+ lastidx = last (ir. cfg. blocks[pred]. stmts)
112
+ # NOTE `lastidx` isn't a load, thus we can use inclusive coondition within the `find_def_for_use`
113
+ has_safe_def (ir, domtree, allblocks, du, newidx, lastidx, true ) || return false
114
+ end
115
+ return true
116
+ end
117
+
96
118
# find the first dominating def for the given use
97
- function find_def_for_use (ir:: IRCode , domtree:: DomTree , allblocks:: Vector{Int} , du:: SSADefUse , use_idx:: Int )
98
- stmtblock = block_for_inst (ir. cfg, use_idx)
99
- curblock = find_curblock (domtree, allblocks, stmtblock)
119
+ function find_def_for_use (
120
+ ir:: IRCode , domtree:: DomTree , allblocks:: Vector{Int} , du:: SSADefUse , use:: Int , inclusive:: Bool = false )
121
+ useblock = block_for_inst (ir. cfg, use)
122
+ curblock = find_curblock (domtree, allblocks, useblock)
100
123
local def = 0
101
124
for idx in du. defs
102
125
if block_for_inst (ir. cfg, idx) == curblock
103
- if curblock != stmtblock
126
+ if curblock != useblock
104
127
# Find the last def in this block
105
128
def = max (def, idx)
106
129
else
107
130
# Find the last def before our use
108
- def = max (def, idx >= use_idx ? 0 : idx)
131
+ if inclusive
132
+ def = max (def, idx ≤ use ? idx : 0 )
133
+ else
134
+ def = max (def, idx < use ? idx : 0 )
135
+ end
109
136
end
110
137
end
111
138
end
112
- return def, stmtblock , curblock
139
+ return def, useblock , curblock
113
140
end
114
141
115
142
function collect_leaves (compact:: IncrementalCompact , @nospecialize (val), @nospecialize (typeconstraint))
@@ -842,16 +869,8 @@ function sroa_mutables!(ir::IRCode, defuses::IdDict{Int, Tuple{SPCSet, SSADefUse
842
869
allblocks = sort (vcat (phiblocks, ldu. def_bbs))
843
870
blocks[fidx] = phiblocks, allblocks
844
871
if fidx + 1 > length (defexpr. args)
845
- # even if the allocation contains an uninitialized field, we try an extra effort
846
- # to check if all uses have any "solid" `setfield!` calls that define the field
847
- # although we give up the cases below:
848
- # `def == idx`: this field can only defined at the allocation site (thus this case will throw)
849
- # `def == 0`: this field comes from `PhiNode`
850
- # we may be able to traverse control flows of PhiNode values, but it sounds
851
- # more complicated than beneficial under the current implementation
852
872
for use in du. uses
853
- def = find_def_for_use (ir, domtree, allblocks, du, use)[1 ]
854
- (def == 0 || def == newidx) && @goto skip
873
+ has_safe_def (ir, domtree, allblocks, du, newidx, use) || @goto skip
855
874
end
856
875
end
857
876
end
0 commit comments