Skip to content
Merged
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
9 changes: 9 additions & 0 deletions base/compiler/abstractinterpretation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2727,6 +2727,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
empty!(frame.pclimitations)
@goto find_next_bb
end
orig_condt = condt
if !(isa(condt, Const) || isa(condt, Conditional)) && isa(condx, SlotNumber)
# if this non-`Conditional` object is a slot, we form and propagate
# the conditional constraint on it
Expand Down Expand Up @@ -2758,6 +2759,14 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
handle_control_backedge!(interp, frame, currpc, stmt.dest)
@goto branch
else
if !⊑(𝕃ᵢ, orig_condt, Bool)
merge_effects!(interp, frame, EFFECTS_THROWS)
if !hasintersect(widenconst(orig_condt), Bool)
ssavaluetypes[currpc] = Bottom
@goto find_next_bb
end
end

# We continue with the true branch, but process the false
# branch here.
if isa(condt, Conditional)
Expand Down
4 changes: 3 additions & 1 deletion base/compiler/ssair/irinterp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,9 @@ function reprocess_instruction!(interp::AbstractInterpreter,
# Handled at the very end
return false
elseif isa(inst, PiNode)
rt = tmeet(typeinf_lattice(interp), argextype(inst.val, ir), inst.typ)
rt = tmeet(typeinf_lattice(interp), argextype(inst.val, ir), widenconst(inst.typ))
elseif inst === nothing
return false
else
ccall(:jl_, Cvoid, (Any,), inst)
error()
Expand Down
8 changes: 5 additions & 3 deletions base/compiler/ssair/slot2ssa.jl
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,9 @@ function iterated_dominance_frontier(cfg::CFG, liveness::BlockLiveness, domtree:
end

function rename_incoming_edge(old_edge::Int, old_to::Int, result_order::Vector{Int}, bb_rename::Vector{Int})
old_edge == 0 && return 0
new_edge_from = bb_rename[old_edge]
new_edge_from < 0 && return new_edge_from
if old_edge == old_to - 1
# Could have been a crit edge break
if new_edge_from < length(result_order) && result_order[new_edge_from + 1] == 0
Expand All @@ -363,7 +365,7 @@ function rename_phinode_edges(node::PhiNode, bb::Int, result_order::Vector{Int},
new_edges = Int32[]
for (idx, edge) in pairs(node.edges)
edge = Int(edge)
(edge == 0 || bb_rename[edge] != 0) || continue
(edge == 0 || bb_rename[edge] != -1) || continue
new_edge_from = edge == 0 ? 0 : rename_incoming_edge(edge, bb, result_order, bb_rename)
push!(new_edges, new_edge_from)
if isassigned(node.values, idx)
Expand All @@ -386,7 +388,7 @@ function domsort_ssa!(ir::IRCode, domtree::DomTree)
# First compute the new order of basic blocks
result_order = Int[]
stack = Int[]
bb_rename = zeros(Int, length(ir.cfg.blocks))
bb_rename = fill(-1, length(ir.cfg.blocks))
node = 1
ncritbreaks = 0
nnewfallthroughs = 0
Expand Down Expand Up @@ -497,7 +499,7 @@ function domsort_ssa!(ir::IRCode, domtree::DomTree)
bb_start_off += length(inst_range)
local new_preds, new_succs
let bb = bb, bb_rename = bb_rename, result_order = result_order
new_preds = Int[i == 0 ? 0 : rename_incoming_edge(i, bb, result_order, bb_rename) for i in ir.cfg.blocks[bb].preds]
new_preds = Int[bb for bb in (rename_incoming_edge(i, bb, result_order, bb_rename) for i in ir.cfg.blocks[bb].preds) if bb != -1]
new_succs = Int[ rename_outgoing_edge(i, bb, result_order, bb_rename) for i in ir.cfg.blocks[bb].succs]
end
new_bbs[new_bb] = BasicBlock(inst_range, new_preds, new_succs)
Expand Down
24 changes: 4 additions & 20 deletions base/compiler/typeinfer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -553,8 +553,7 @@ function finish(me::InferenceState, interp::AbstractInterpreter)
# annotate fulltree with type information,
# either because we are the outermost code, or we might use this later
doopt = (me.cached || me.parent !== nothing)
changemap = type_annotate!(interp, me, doopt)
recompute_cfg = changemap !== nothing
recompute_cfg = type_annotate!(interp, me, doopt)
if doopt && may_optimize(interp)
me.result.src = OptimizationState(me, OptimizationParams(interp), interp, recompute_cfg)
else
Expand Down Expand Up @@ -725,6 +724,7 @@ function type_annotate!(interp::AbstractInterpreter, sv::InferenceState, run_opt
slotflags = src.slotflags
nslots = length(slotflags)
undefs = fill(false, nslots)
any_unreachable = false

# this statement traversal does five things:
# 1. introduce temporary `TypedSlot`s that are supposed to be replaced with π-nodes later
Expand Down Expand Up @@ -752,13 +752,9 @@ function type_annotate!(interp::AbstractInterpreter, sv::InferenceState, run_opt
body[i] = annotate_slot_load!(undefs, i, sv, expr) # 1&2
ssavaluetypes[i] = widenconditional(ssavaluetypes[i]) # 4
else # i.e. any runtime execution will never reach this statement
any_unreachable = true
if is_meta_expr(expr) # keep any lexically scoped expressions
ssavaluetypes[i] = Any # 4
elseif run_optimizer
if changemap === nothing
changemap = fill(0, nexpr)
end
changemap[i] = -1 # 3&4: mark for the bulk deletion
else
ssavaluetypes[i] = Bottom # 4
body[i] = Const(expr) # annotate that this statement actually is dead
Expand All @@ -773,19 +769,7 @@ function type_annotate!(interp::AbstractInterpreter, sv::InferenceState, run_opt
end
end

# do the bulk deletion of unreached statements
if changemap !== nothing
inds = Int[i for (i,v) in enumerate(changemap) if v == -1]
deleteat!(body, inds)
deleteat!(ssavaluetypes, inds)
deleteat!(codelocs, inds)
deleteat!(stmt_info, inds)
deleteat!(ssaflags, inds)
renumber_ir_elements!(body, changemap)
return changemap
else
return nothing
end
return any_unreachable
end

# at the end, all items in b's cycle
Expand Down
19 changes: 6 additions & 13 deletions test/compiler/effects.jl
Original file line number Diff line number Diff line change
Expand Up @@ -696,16 +696,9 @@ end |> !Core.Compiler.is_consistent
@inbounds x[1]
end |> Core.Compiler.is_total

# unknown :static_parameter should taint :nothrow
# https://github.com/JuliaLang/julia/issues/46771
unknown_sparam_throw(::Union{Nothing, Type{T}}) where T = (T; nothing)
unknown_sparam_nothrow1(x::Ref{T}) where T = (T; nothing)
unknown_sparam_nothrow2(x::Ref{Ref{T}}) where T = (T; nothing)
@test Core.Compiler.is_nothrow(Base.infer_effects(unknown_sparam_throw, (Type{Int},)))
@test Core.Compiler.is_nothrow(Base.infer_effects(unknown_sparam_throw, (Type{<:Integer},)))
@test !Core.Compiler.is_nothrow(Base.infer_effects(unknown_sparam_throw, (Type,)))
@test !Core.Compiler.is_nothrow(Base.infer_effects(unknown_sparam_throw, (Nothing,)))
@test !Core.Compiler.is_nothrow(Base.infer_effects(unknown_sparam_throw, (Union{Type{Int},Nothing},)))
@test !Core.Compiler.is_nothrow(Base.infer_effects(unknown_sparam_throw, (Any,)))
@test Core.Compiler.is_nothrow(Base.infer_effects(unknown_sparam_nothrow1, (Ref,)))
@test Core.Compiler.is_nothrow(Base.infer_effects(unknown_sparam_nothrow2, (Ref{Ref{T}} where T,)))
# GotoIfNot should properly mark itself as throwing when given a non-Bool
# https://github.com/JuliaLang/julia/pull/48583
gotoifnot_throw_check_48583(x) = x ? x : 0
@test !Core.Compiler.is_nothrow(Base.infer_effects(gotoifnot_throw_check_48583, (Missing,)))
@test !Core.Compiler.is_nothrow(Base.infer_effects(gotoifnot_throw_check_48583, (Any,)))
@test Core.Compiler.is_nothrow(Base.infer_effects(gotoifnot_throw_check_48583, (Bool,)))