Skip to content

Commit a92e12a

Browse files
jumerckxJules Merckvtjnash
authored
use stmt instead of Instruction in populate_def_use_map! (#56201)
Fixes four related issues with SSA use counting in the optimizer: 1. populate_def_use_map! was incorrectly using `inst` instead of `inst[:stmt]` when iterating userefs, causing it to miss actual uses. 2. Early bailout in ScanStmt when encountering EnterNode or when there are no refinable effects caused incomplete SSA use counting in the TwoPhaseDefUseMap, leading to bounds errors when populate_def_use_map! tried to write beyond allocated array size. 3. scan_inconsistency! assumed the boundscheck argument was always a constant, but it can also be an SSA value that needs to be counted. The fix loops through all args to count SSAs in tpdum, but only checks non-boundscheck args (all except the last) when determining if the statement is inconsistent, preserving the special case that allows boundscheck to be inconsistent without tainting the overall statement. 4. check_inconsistentcy! was not convergent and not used correctly. These fixes correspond to the patches in: https://github.com/chalk-lab/Mooncake.jl/blob/main/src/interpreter/patch_for_319.jl I imagine this maybe needs a test but not sure how to properly unit test this without creating a full end-to-end test using `Base.code_ircode` and so on. The changes don't seem to have a performance impact reflected in the benchmark job, so the fast paths are simply removed now. If they seem impactful later, we can re-evaluate how to add those back correctly. Fix #56193 Co-authored-by: Jules Merck <[email protected]> Co-authored-by: Jameson Nash <[email protected]> With rebasing help by Claude Code
1 parent 5a5fc98 commit a92e12a

File tree

2 files changed

+25
-22
lines changed

2 files changed

+25
-22
lines changed

Compiler/src/optimize.jl

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -861,10 +861,14 @@ function scan_inconsistency!(inst::Instruction, sv::PostOptAnalysisState)
861861
# Special case: For `getfield` and memory operations, we allow inconsistency of the :boundscheck argument
862862
(; inconsistent, tpdum) = sv
863863
if iscall_with_boundscheck(stmt, sv)
864-
for i = 1:(length(stmt.args)-1)
864+
for i = 1:length(stmt.args)
865865
val = stmt.args[i]
866+
# SSAValue should be the only permitted argument type which can be inconsistent found here.
867+
# Others (e.g. GlobalRef) should have been moved to statement position. See stmt_effect_flags.
866868
if isa(val, SSAValue)
867-
stmt_inconsistent |= val.id in inconsistent
869+
if i < length(stmt.args) # not the boundscheck argument (which is last)
870+
stmt_inconsistent |= val.id in inconsistent
871+
end
868872
count!(tpdum, val)
869873
end
870874
end
@@ -891,7 +895,7 @@ function ((; sv)::ScanStmt)(inst::Instruction, lstmt::Int, bb::Int)
891895
if isa(stmt, EnterNode)
892896
# try/catch not yet modeled
893897
give_up_refinements!(sv)
894-
return nothing
898+
return true # don't bail out early -- can cause tpdum counts to be off
895899
end
896900

897901
scan_non_dataflow_flags!(inst, sv)
@@ -937,36 +941,36 @@ function ((; sv)::ScanStmt)(inst::Instruction, lstmt::Int, bb::Int)
937941
end
938942
end
939943

940-
# bail out early if there are no possibilities to refine the effects
941-
if !any_refinable(sv)
942-
return nothing
943-
end
944+
# Do not bail out early, as this can cause tpdum counts to be off.
945+
# # bail out early if there are no possibilities to refine the effects
946+
# if !any_refinable(sv)
947+
# return nothing
948+
# end
944949

945950
return true
946951
end
947952

948953
function check_inconsistentcy!(sv::PostOptAnalysisState, scanner::BBScanner)
949954
(; ir, inconsistent, tpdum) = sv
950955

956+
sv.all_retpaths_consistent || return
951957
scan!(ScanStmt(sv), scanner, false)
958+
sv.all_retpaths_consistent || return
952959
complete!(tpdum); push!(scanner.bb_ip, 1)
953960
populate_def_use_map!(tpdum, scanner)
954961

955962
stmt_ip = BitSetBoundedMinPrioritySet(length(ir.stmts))
956963
for def in inconsistent
957-
for use in tpdum[def]
958-
if !(use in inconsistent)
959-
push!(inconsistent, use)
960-
append!(stmt_ip, tpdum[use])
961-
end
962-
end
963-
end
964+
append!(stmt_ip, tpdum[def])
965+
end
964966
lazydomtree = LazyDomtree(ir)
965967
while !isempty(stmt_ip)
966968
idx = popfirst!(stmt_ip)
969+
idx in inconsistent && continue # already processed
967970
inst = ir[SSAValue(idx)]
968971
stmt = inst[:stmt]
969972
if iscall_with_boundscheck(stmt, sv)
973+
# recompute inconsistent flags for call while skipping boundscheck (last) argument
970974
any_non_boundscheck_inconsistent = false
971975
for i = 1:(length(stmt.args)-1)
972976
val = stmt.args[i]
@@ -978,19 +982,18 @@ function check_inconsistentcy!(sv::PostOptAnalysisState, scanner::BBScanner)
978982
any_non_boundscheck_inconsistent || continue
979983
elseif isa(stmt, ReturnNode)
980984
sv.all_retpaths_consistent = false
985+
return
981986
elseif isa(stmt, GotoIfNot)
982987
bb = block_for_inst(ir, idx)
983988
cfg = ir.cfg
984989
blockliveness = BlockLiveness(cfg.blocks[bb].succs, nothing)
985990
for succ in iterated_dominance_frontier(cfg, blockliveness, get!(lazydomtree))
986991
visit_bb_phis!(ir, succ) do phiidx::Int
987-
push!(inconsistent, phiidx)
988-
push!(stmt_ip, phiidx)
992+
phiidx in inconsistent || push!(stmt_ip, phiidx)
989993
end
990994
end
991995
end
992-
sv.all_retpaths_consistent || break
993-
append!(inconsistent, tpdum[idx])
996+
push!(inconsistent, idx)
994997
append!(stmt_ip, tpdum[idx])
995998
end
996999
end
@@ -1009,9 +1012,9 @@ function ipo_dataflow_analysis!(interp::AbstractInterpreter, opt::OptimizationSt
10091012
completed_scan = scan!(ScanStmt(sv), scanner, true)
10101013

10111014
if !completed_scan
1012-
if sv.all_retpaths_consistent
1013-
check_inconsistentcy!(sv, scanner)
1014-
else
1015+
# finish scanning for all_retpaths_consistent computation
1016+
check_inconsistentcy!(sv, scanner)
1017+
if !sv.all_retpaths_consistent
10151018
# No longer any dataflow concerns, just scan the flags
10161019
scan!(scanner, false) do inst::Instruction, ::Int, ::Int
10171020
scan_non_dataflow_flags!(inst, sv)

Compiler/src/ssair/irinterp.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ end
294294

295295
function populate_def_use_map!(tpdum::TwoPhaseDefUseMap, scanner::BBScanner)
296296
scan!(scanner, false) do inst::Instruction, lstmt::Int, bb::Int
297-
for ur in userefs(inst)
297+
for ur in userefs(inst[:stmt])
298298
val = ur[]
299299
if isa(val, SSAValue)
300300
push!(tpdum[val.id], inst.idx)

0 commit comments

Comments
 (0)