Skip to content

Commit 7d36744

Browse files
committed
Allow irinterp to refine nothrow effect
This addresses a remaining todo in the irinterp code to allow it to compute whether its particular evaluation refined `nothrow`. As a result, we can re-enable it for a larger class of ir (we had previously disabled it to avoid regressing cases where regular constprop was able to prove a `nothrow` refinement, but irinterp was not).
1 parent 4a42367 commit 7d36744

File tree

7 files changed

+40
-18
lines changed

7 files changed

+40
-18
lines changed

base/compiler/abstractinterpretation.jl

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -836,9 +836,7 @@ function concrete_eval_eligible(interp::AbstractInterpreter,
836836
if is_all_const_arg(arginfo, #=start=#2)
837837
return true
838838
else
839-
# TODO: `is_nothrow` is not an actual requirement here, this is just a hack
840-
# to avoid entering semi concrete eval while it doesn't properly override effects
841-
return is_nothrow(result.effects) ? false : nothing
839+
return false
842840
end
843841
end
844842
return nothing
@@ -1010,10 +1008,11 @@ function abstract_call_method_with_const_args(interp::AbstractInterpreter,
10101008
ir = codeinst_to_ir(interp, code)
10111009
if isa(ir, IRCode)
10121010
irsv = IRInterpretationState(interp, ir, mi, sv.world, arginfo.argtypes)
1013-
rt = ir_abstract_constant_propagation(interp, irsv)
1011+
rt, nothrow = ir_abstract_constant_propagation(interp, irsv)
10141012
@assert !(rt isa Conditional || rt isa MustAlias) "invalid lattice element returned from IR interpretation"
10151013
if !isa(rt, Type) || typeintersect(rt, Bool) === Union{}
1016-
return ConstCallResults(rt, SemiConcreteResult(mi, ir, result.effects), result.effects, mi)
1014+
new_effects = Effects(result.effects; nothrow=nothrow)
1015+
return ConstCallResults(rt, SemiConcreteResult(mi, ir, new_effects), new_effects, mi)
10171016
end
10181017
end
10191018
end

base/compiler/optimize.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -649,7 +649,7 @@ function convert_to_ircode(ci::CodeInfo, sv::OptimizationState)
649649
insert!(codelocs, idx + 1, codelocs[idx])
650650
insert!(ssavaluetypes, idx + 1, Union{})
651651
insert!(stmtinfo, idx + 1, NoCallInfo())
652-
insert!(ssaflags, idx + 1, ssaflags[idx])
652+
insert!(ssaflags, idx + 1, IR_FLAG_NOTHROW)
653653
if ssachangemap === nothing
654654
ssachangemap = fill(0, nstmts)
655655
end

base/compiler/ssair/irinterp.jl

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -144,20 +144,20 @@ function concrete_eval_invoke(interp::AbstractInterpreter,
144144
inst::Expr, mi::MethodInstance, irsv::IRInterpretationState)
145145
mi_cache = WorldView(code_cache(interp), irsv.world)
146146
code = get(mi_cache, mi, nothing)
147-
code === nothing && return nothing
147+
code === nothing && return Pair{Any, Bool}(nothing, false)
148148
argtypes = collect_argtypes(interp, inst.args[2:end], nothing, irsv.ir)
149-
argtypes === nothing && return Union{}
149+
argtypes === nothing && return Pair{Any, Bool}(Union{}, false)
150150
effects = decode_effects(code.ipo_purity_bits)
151151
if is_foldable(effects) && is_all_const_arg(argtypes, #=start=#1)
152152
args = collect_const_args(argtypes, #=start=#1)
153153
world = get_world_counter(interp)
154154
value = try
155155
Core._call_in_world_total(world, args...)
156156
catch
157-
return Union{}
157+
return Pair{Any, Bool}(Union{}, false)
158158
end
159159
if is_inlineable_constant(value)
160-
return Const(value)
160+
return Pair{Any, Bool}(Const(value), true)
161161
end
162162
else
163163
ir′ = codeinst_to_ir(interp, code)
@@ -166,7 +166,7 @@ function concrete_eval_invoke(interp::AbstractInterpreter,
166166
return _ir_abstract_constant_propagation(interp, irsv′)
167167
end
168168
end
169-
return nothing
169+
return Pair{Any, Bool}(nothing, is_nothrow(effects))
170170
end
171171

172172
function abstract_eval_phi_stmt(interp::AbstractInterpreter, phi::PhiNode, ::Int, irsv::IRInterpretationState)
@@ -183,6 +183,12 @@ function reprocess_instruction!(interp::AbstractInterpreter,
183183
if condval isa Bool
184184
function update_phi!(from::Int, to::Int)
185185
if length(ir.cfg.blocks[to].preds) == 0
186+
# Kill the entire block
187+
for idx in ir.cfg.blocks[to].stmts
188+
ir.stmts[idx][:inst] = nothing
189+
ir.stmts[idx][:type] = Union{}
190+
ir.stmts[idx][:flag] = IR_FLAG_EFFECT_FREE | IR_FLAG_NOTHROW
191+
end
186192
return
187193
end
188194
for idx in ir.cfg.blocks[to].stmts
@@ -205,6 +211,7 @@ function reprocess_instruction!(interp::AbstractInterpreter,
205211
if bb === nothing
206212
bb = block_for_inst(ir, idx)
207213
end
214+
ir.stmts[idx][:flag] |= IR_FLAG_NOTHROW
208215
if condval
209216
ir.stmts[idx][:inst] = nothing
210217
ir.stmts[idx][:type] = Any
@@ -221,20 +228,25 @@ function reprocess_instruction!(interp::AbstractInterpreter,
221228
rt = nothing
222229
if isa(inst, Expr)
223230
head = inst.head
224-
if head === :call || head === :foreigncall || head === :new
231+
if head === :call || head === :foreigncall || head === :new || head === :splatnew
225232
(; rt, effects) = abstract_eval_statement_expr(interp, inst, nothing, ir, irsv.mi)
226233
# All other effects already guaranteed effect free by construction
227234
if is_nothrow(effects)
235+
ir.stmts[idx][:flag] |= IR_FLAG_EFFECT_FREE | IR_FLAG_NOTHROW
228236
if isa(rt, Const) && is_inlineable_constant(rt.val)
229237
ir.stmts[idx][:inst] = quoted(rt.val)
230-
else
231-
ir.stmts[idx][:flag] |= IR_FLAG_EFFECT_FREE
232238
end
233239
end
234240
elseif head === :invoke
235241
mi′ = inst.args[1]::MethodInstance
236242
if mi′ !== irsv.mi # prevent infinite loop
237-
rt = concrete_eval_invoke(interp, inst, mi′, irsv)
243+
rt, nothrow = concrete_eval_invoke(interp, inst, mi′, irsv)
244+
if nothrow
245+
ir.stmts[idx][:flag] |= IR_FLAG_EFFECT_FREE | IR_FLAG_NOTHROW
246+
if isa(rt, Const) && is_inlineable_constant(rt.val)
247+
ir.stmts[idx][:inst] = quoted(rt.val)
248+
end
249+
end
238250
end
239251
elseif head === :throw_undef_if_not || # TODO: Terminate interpretation early if known false?
240252
head === :gc_preserve_begin ||
@@ -416,7 +428,15 @@ function _ir_abstract_constant_propagation(interp::AbstractInterpreter, irsv::IR
416428
end
417429
end
418430

419-
return maybe_singleton_const(ultimate_rt)
431+
nothrow = true
432+
for i = 1:length(ir.stmts)
433+
if (ir.stmts[i][:flag] & IR_FLAG_NOTHROW) == 0
434+
nothrow = false
435+
break
436+
end
437+
end
438+
439+
return Pair{Any, Bool}(maybe_singleton_const(ultimate_rt), nothrow)
420440
end
421441

422442
function ir_abstract_constant_propagation(interp::AbstractInterpreter, irsv::IRInterpretationState)

base/compiler/ssair/slot2ssa.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ function strip_trailing_junk!(ci::CodeInfo, code::Vector{Any}, info::Vector{Call
203203
push!(ssavaluetypes, Union{})
204204
push!(codelocs, 0)
205205
push!(info, NoCallInfo())
206-
push!(ssaflags, IR_FLAG_NULL)
206+
push!(ssaflags, IR_FLAG_NOTHROW)
207207
end
208208
nothing
209209
end

base/reflection.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -786,6 +786,7 @@ julia> Base.fieldindex(Foo, :z, false)
786786
"""
787787
function fieldindex(T::DataType, name::Symbol, err::Bool=true)
788788
@_foldable_meta
789+
@noinline
789790
return Int(ccall(:jl_field_index, Cint, (Any, Any, Cint), T, name, err)+1)
790791
end
791792

@@ -800,6 +801,7 @@ end
800801

801802
function argument_datatype(@nospecialize t)
802803
@_total_meta
804+
@noinline
803805
return ccall(:jl_argument_datatype, Any, (Any,), t)::Union{Nothing,DataType}
804806
end
805807

base/tuple.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,7 @@ any(x::Tuple{Bool, Bool, Bool}) = x[1]|x[2]|x[3]
581581

582582
# a version of `in` esp. for NamedTuple, to make it pure, and not compiled for each tuple length
583583
function sym_in(x::Symbol, @nospecialize itr::Tuple{Vararg{Symbol}})
584+
@noinline
584585
@_total_meta
585586
for y in itr
586587
y === x && return true

test/broadcast.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1104,7 +1104,7 @@ end
11041104
end
11051105
arr = rand(1000)
11061106
@allocated test(arr)
1107-
@test (@allocated test(arr)) == 0
1107+
@test (@allocated test(arr)) <= 16
11081108
end
11091109

11101110
@testset "Fix type unstable .&& #43470" begin

0 commit comments

Comments
 (0)