Skip to content

Commit

Permalink
optimizer: don't insert :throw_undef_if_not for defined slots (#55600)
Browse files Browse the repository at this point in the history
As an application of #55545, this commit avoids the
insertion of `:throw_undef_if_not` nodes when the defined-ness of a slot
is guaranteed by abstract interpretation.

```julia
julia> function isdefined_nothrow(c, x)
           local val
           if c
               val = x
           end
           if @isdefined val
               return val
           end
           return zero(Int)
       end;

julia> @code_typed isdefined_nothrow(true, 42)
```
```diff
diff --git a/old b/new
index c4980a5c9c..3d1d6d30f0 100644
--- a/old
+++ b/new
@@ -4,7 +4,6 @@ CodeInfo(
 3 ┄ %3 = φ (#2 => x, #1 => #undef)::Int64
 │   %4 = φ (#2 => true, #1 => false)::Bool
 └──      goto #5 if not %4
-4 ─      $(Expr(:throw_undef_if_not, :val, :(%4)))::Any
-└──      return %3
+4 ─      return %3
 5 ─      return 0
 ) => Int64
```
  • Loading branch information
aviatesk authored and KristofferC committed Sep 12, 2024
1 parent 69e2672 commit 32480cd
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 5 deletions.
9 changes: 6 additions & 3 deletions base/compiler/ssair/slot2ssa.jl
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ function fixup_slot!(ir::IRCode, ci::CodeInfo, idx::Int, slot::Int, @nospecializ
insert_node!(ir, idx, NewInstruction(
Expr(:throw_undef_if_not, ci.slotnames[slot], false), Any))
return UNDEF_TOKEN
elseif has_flag(ir.stmts[idx], IR_FLAG_NOTHROW)
# if the `isdefined`-ness of this slot is guaranteed by abstract interpretation,
# there is no need to form a `:throw_undef_if_not`
elseif def_ssa !== true
insert_node!(ir, idx, NewInstruction(
Expr(:throw_undef_if_not, ci.slotnames[slot], def_ssa), Any))
Expand Down Expand Up @@ -153,12 +156,12 @@ end

function fixup_uses!(ir::IRCode, ci::CodeInfo, code::Vector{Any}, uses::Vector{Int}, slot::Int, @nospecialize(ssa))
for use in uses
code[use] = fixemup!(x::SlotNumber->slot_id(x)==slot, stmt::SlotNumber->(ssa, true), ir, ci, use, code[use])
code[use] = fixemup!(x::SlotNumber->slot_id(x)==slot, ::SlotNumber->Pair{Any,Any}(ssa, true), ir, ci, use, code[use])
end
end

function rename_uses!(ir::IRCode, ci::CodeInfo, idx::Int, @nospecialize(stmt), renames::Vector{Pair{Any, Any}})
return fixemup!(stmt::SlotNumber->true, stmt::SlotNumber->renames[slot_id(stmt)], ir, ci, idx, stmt)
return fixemup!(::SlotNumber->true, x::SlotNumber->renames[slot_id(x)], ir, ci, idx, stmt)
end

# maybe use expr_type?
Expand Down Expand Up @@ -656,7 +659,7 @@ function construct_ssa!(ci::CodeInfo, ir::IRCode, sv::OptimizationState,
visited = BitSet()
new_nodes = ir.new_nodes
@timeit "SSA Rename" while !isempty(worklist)
(item::Int, pred, incoming_vals) = pop!(worklist)
(item, pred, incoming_vals) = pop!(worklist)
if sv.bb_vartables[item] === nothing
continue
end
Expand Down
8 changes: 6 additions & 2 deletions test/compiler/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6051,7 +6051,7 @@ end |> Core.Compiler.is_nothrow
end |> Core.Compiler.is_nothrow

# refine `undef` information from `@isdefined` check
@test Base.infer_effects((Bool,Int)) do c, x
function isdefined_nothrow(c, x)
local val
if c
val = x
Expand All @@ -6060,7 +6060,11 @@ end |> Core.Compiler.is_nothrow
return val
end
return zero(Int)
end |> Core.Compiler.is_nothrow
end
@test Core.Compiler.is_nothrow(Base.infer_effects(isdefined_nothrow, (Bool,Int)))
@test !any(first(only(code_typed(isdefined_nothrow, (Bool,Int)))).code) do @nospecialize x
Meta.isexpr(x, :throw_undef_if_not)
end

# End to end test case for the partially initialized struct with `PartialStruct`
@noinline broadcast_noescape1(a) = (broadcast(identity, a); nothing)
Expand Down

0 comments on commit 32480cd

Please sign in to comment.