Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions base/compiler/ssair/driver.jl
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,7 @@ function run_passes(ci::CodeInfo, nargs::Int, sv::OptimizationState)
#@timeit "verify 2" verify_ir(ir)
ir = compact!(ir)
#@Base.show ("before_sroa", ir)
@timeit "domtree 2" domtree = construct_domtree(ir.cfg)
@timeit "SROA" ir = getfield_elim_pass!(ir, domtree)
@timeit "SROA" ir = getfield_elim_pass!(ir)
#@Base.show ir.new_nodes
#@Base.show ("after_sroa", ir)
ir = adce_pass!(ir)
Expand Down
103 changes: 85 additions & 18 deletions base/compiler/ssair/ir.jl
Original file line number Diff line number Diff line change
Expand Up @@ -283,11 +283,13 @@ function setindex!(x::IRCode, @nospecialize(repl), s::SSAValue)
return x
end


# SSA values that need renaming
struct OldSSAValue
id::Int
end

# SSA values that are in `new_new_nodes` of an `IncrementalCompact` and are to
# be actually inserted next time (they become `new_nodes` next time)
struct NewSSAValue
id::Int
end
Expand Down Expand Up @@ -500,9 +502,11 @@ mutable struct IncrementalCompact
ir::IRCode
result::InstructionStream
result_bbs::Vector{BasicBlock}

ssa_rename::Vector{Any}
bb_rename_pred::Vector{Int}
bb_rename_succ::Vector{Int}

used_ssas::Vector{Int}
late_fixup::Vector{Int}
perm::Vector{Int}
Expand All @@ -512,13 +516,15 @@ mutable struct IncrementalCompact
# TODO: Switch these two to a min-heap of some sort
pending_nodes::NewNodeStream # New nodes that were after the compaction point at insertion time
pending_perm::Vector{Int}

# State
idx::Int
result_idx::Int
active_result_bb::Int
renamed_new_nodes::Bool
cfg_transforms_enabled::Bool
fold_constant_branches::Bool

function IncrementalCompact(code::IRCode, allow_cfg_transforms::Bool=false)
# Sort by position with attach after nodes after regular ones
perm = my_sortperm(Int[let new_node = code.new_nodes.info[i]
Expand Down Expand Up @@ -820,7 +826,7 @@ function process_phinode_values(old_values::Vector{Any}, late_fixup::Vector{Int}
return values
end

function renumber_ssa2(val::SSAValue, ssanums::Vector{Any}, used_ssa::Vector{Int}, do_rename_ssa::Bool)
function renumber_ssa2(val::SSAValue, ssanums::Vector{Any}, used_ssas::Vector{Int}, do_rename_ssa::Bool)
id = val.id
if id > length(ssanums)
return val
Expand All @@ -829,22 +835,22 @@ function renumber_ssa2(val::SSAValue, ssanums::Vector{Any}, used_ssa::Vector{Int
val = ssanums[id]
end
if isa(val, SSAValue)
if used_ssa !== nothing
used_ssa[val.id] += 1
if used_ssas !== nothing
used_ssas[val.id] += 1
end
end
return val
end

function renumber_ssa2!(@nospecialize(stmt), ssanums::Vector{Any}, used_ssa::Vector{Int}, late_fixup::Vector{Int}, result_idx::Int, do_rename_ssa::Bool)
function renumber_ssa2!(@nospecialize(stmt), ssanums::Vector{Any}, used_ssas::Vector{Int}, late_fixup::Vector{Int}, result_idx::Int, do_rename_ssa::Bool)
urs = userefs(stmt)
for op in urs
val = op[]
if isa(val, OldSSAValue) || isa(val, NewSSAValue)
push!(late_fixup, result_idx)
end
if isa(val, SSAValue)
val = renumber_ssa2(val, ssanums, used_ssa, do_rename_ssa)
val = renumber_ssa2(val, ssanums, used_ssas, do_rename_ssa)
end
if isa(val, OldSSAValue) || isa(val, NewSSAValue)
push!(late_fixup, result_idx)
Expand All @@ -871,7 +877,8 @@ function kill_edge!(compact::IncrementalCompact, active_bb::Int, from::Int, to::
# Note: We recursively kill as many edges as are obviously dead. However, this
# may leave dead loops in the IR. We kill these later in a CFG cleanup pass (or
# worstcase during codegen).
preds, succs = compact.result_bbs[compact.bb_rename_succ[to]].preds, compact.result_bbs[compact.bb_rename_pred[from]].succs
preds = compact.result_bbs[compact.bb_rename_succ[to]].preds
succs = compact.result_bbs[compact.bb_rename_pred[from]].succs
deleteat!(preds, findfirst(x->x === compact.bb_rename_pred[from], preds)::Int)
deleteat!(succs, findfirst(x->x === compact.bb_rename_succ[to], succs)::Int)
# Check if the block is now dead
Expand All @@ -888,10 +895,13 @@ function kill_edge!(compact::IncrementalCompact, active_bb::Int, from::Int, to::
compact.result[last(stmts)][:inst] = ReturnNode()
end
else
# We need to remove this edge from any phi nodes
# Remove this edge from all phi nodes in `to` block
# NOTE: It is possible for `to` to contain only `nothing` statements,
# so we must be careful to stop at its last statement
if to < active_bb
idx = first(compact.result_bbs[compact.bb_rename_succ[to]].stmts)
while idx < length(compact.result)
stmts = compact.result_bbs[compact.bb_rename_succ[to]].stmts
idx = first(stmts)
while idx <= last(stmts)
stmt = compact.result[idx][:inst]
stmt === nothing && continue
isa(stmt, PhiNode) || break
Expand All @@ -903,8 +913,8 @@ function kill_edge!(compact::IncrementalCompact, active_bb::Int, from::Int, to::
idx += 1
end
else
idx = first(compact.ir.cfg.blocks[to].stmts)
for stmt in CompactPeekIterator(compact, idx)
stmts = compact.ir.cfg.blocks[to].stmts
for stmt in CompactPeekIterator(compact, first(stmts), last(stmts))
stmt === nothing && continue
isa(stmt, PhiNode) || break
i = findfirst(x-> x === from, stmt.edges)
Expand Down Expand Up @@ -984,15 +994,56 @@ function process_node!(compact::IncrementalCompact, result_idx::Int, inst::Instr
result[result_idx][:inst] = renumber_ssa2!(stmt, ssa_rename, used_ssas, late_fixup, result_idx, do_rename_ssa)
result_idx += 1
elseif isa(stmt, PhiNode)
values = process_phinode_values(stmt.values, late_fixup, processed_idx, result_idx, ssa_rename, used_ssas, do_rename_ssa)
if length(stmt.edges) == 1 && isassigned(values, 1) &&
if compact.cfg_transforms_enabled
# Rename phi node edges
map!(i -> compact.bb_rename_pred[i], stmt.edges, stmt.edges)

# Remove edges and values associated with dead blocks. Entries in
# `values` can be undefined when the phi node refers to something
# that is not defined. (This is not a sign that the compiler is
# unintentionally leaving some entries in `values` uninitialized.)
# For example, consider a reference to a variable that is only
# defined if some branch is taken.
#
# In order to leave undefined values undefined (undefined-ness is
# not a value we can copy), we copy only the edges and (defined)
# values we want to keep to new arrays initialized with undefined
# elements.
edges = Vector{Any}(undef, length(stmt.edges))
values = Vector{Any}(undef, length(stmt.values))
new_index = 1
for old_index in 1:length(stmt.edges)
if stmt.edges[old_index] != -1
edges[new_index] = stmt.edges[old_index]
if isassigned(stmt.values, old_index)
values[new_index] = stmt.values[old_index]
end
new_index += 1
end
end
resize!(edges, new_index-1)
resize!(values, new_index-1)
else
edges = stmt.edges
values = stmt.values
end

values = process_phinode_values(values, late_fixup, processed_idx, result_idx, ssa_rename, used_ssas, do_rename_ssa)
# Don't remove the phi node if it is before the definition of its value
# because doing so can create forward references. This should only
# happen with dead loops, but can cause problems when optimization
# passes look at all code, dead or not. This check should be
# unnecessary when DCE can remove those dead loops entirely, so this is
# just to be safe.
before_def = isassigned(values, 1) && isa(values[1], OldSSAValue) &&
idx < values[1].id
if length(edges) == 1 && isassigned(values, 1) && !before_def &&
length(compact.cfg_transforms_enabled ?
compact.result_bbs[compact.bb_rename_succ[active_bb]].preds :
compact.ir.cfg.blocks[active_bb].preds) == 1
# There's only one predecessor left - just replace it
ssa_rename[idx] = values[1]
else
edges = compact.cfg_transforms_enabled ? map!(i->compact.bb_rename_pred[i], stmt.edges, stmt.edges) : stmt.edges
result[result_idx][:inst] = PhiNode(edges, values)
result_idx += 1
end
Expand Down Expand Up @@ -1085,10 +1136,19 @@ end
struct CompactPeekIterator
compact::IncrementalCompact
start_idx::Int
end_idx::Int
end

function CompactPeekIterator(compact::IncrementalCompact, start_idx::Int)
return CompactPeekIterator(compact, start_idx, 0)
end

entry_at_idx(entry::NewNodeInfo, idx::Int) = entry.attach_after ? entry.pos == idx - 1 : entry.pos == idx
function iterate(it::CompactPeekIterator, (idx, aidx, bidx)::NTuple{3, Int}=(it.start_idx, it.compact.new_nodes_idx, 1))
if it.end_idx > 0 && idx > it.end_idx
return nothing
end

# TODO: Take advantage of the fact that these arrays are sorted
# TODO: this return value design is horrible
compact = it.compact
Expand Down Expand Up @@ -1146,7 +1206,7 @@ function iterate(compact::IncrementalCompact, (idx, active_bb)::Tuple{Int, Int}=
# Move to next block
compact.idx += 1
if finish_current_bb!(compact, active_bb, old_result_idx, true)
return iterate(compact, (compact.idx-1, active_bb + 1))
return iterate(compact, (compact.idx, active_bb + 1))
else
return Pair{Pair{Int, Int}, Any}(Pair{Int,Int}(compact.idx-1, old_result_idx), compact.result[old_result_idx][:inst]), (compact.idx, active_bb + 1)
end
Expand Down Expand Up @@ -1250,10 +1310,17 @@ function fixup_node(compact::IncrementalCompact, @nospecialize(stmt))
for ur in urs
val = ur[]
if isa(val, NewSSAValue)
ur[] = SSAValue(length(compact.result) + val.id)
val = SSAValue(length(compact.result) + val.id)
elseif isa(val, OldSSAValue)
ur[] = compact.ssa_rename[val.id]
val = compact.ssa_rename[val.id]
end
if isa(val, SSAValue) && val.id <= length(compact.used_ssas)
# If `val.id` is greater than the length of `compact.result` or
# `compact.used_ssas`, this SSA value is in `new_new_nodes`, so
# don't count the use
compact.used_ssas[val.id] += 1
end
ur[] = val
end
return urs[]
end
Expand Down
Loading