diff --git a/base/compiler/abstractinterpretation.jl b/base/compiler/abstractinterpretation.jl index bb6281024e6fe..24d5eb52c1ffb 100644 --- a/base/compiler/abstractinterpretation.jl +++ b/base/compiler/abstractinterpretation.jl @@ -2705,7 +2705,7 @@ end function stmt_taints_inbounds_consistency(sv::AbsIntState) propagate_inbounds(sv) && return true - return (get_curr_ssaflag(sv) & IR_FLAG_INBOUNDS) != 0 + return has_curr_ssaflag(sv, IR_FLAG_INBOUNDS) end function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e), vtypes::VarTable, sv::InferenceState) @@ -2718,7 +2718,7 @@ function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e), else (; rt, exct, effects) = abstract_eval_statement_expr(interp, e, vtypes, sv) if effects.noub === NOUB_IF_NOINBOUNDS - if !iszero(get_curr_ssaflag(sv) & IR_FLAG_INBOUNDS) + if has_curr_ssaflag(sv, IR_FLAG_INBOUNDS) effects = Effects(effects; noub=ALWAYS_FALSE) elseif !propagate_inbounds(sv) # The callee read our inbounds flag, but unless we propagate inbounds, @@ -3258,7 +3258,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState) if exct !== Union{} update_exc_bestguess!(exct, frame, ipo_lattice(interp)) end - if (get_curr_ssaflag(frame) & IR_FLAG_NOTHROW) != IR_FLAG_NOTHROW + if !has_curr_ssaflag(frame, IR_FLAG_NOTHROW) propagate_to_error_handler!(currstate, frame, ๐•ƒแตข) end if rt === Bottom diff --git a/base/compiler/inferencestate.jl b/base/compiler/inferencestate.jl index 772dbe72d4dc1..7085b87db9beb 100644 --- a/base/compiler/inferencestate.jl +++ b/base/compiler/inferencestate.jl @@ -888,6 +888,9 @@ end get_curr_ssaflag(sv::InferenceState) = sv.src.ssaflags[sv.currpc] get_curr_ssaflag(sv::IRInterpretationState) = sv.ir.stmts[sv.curridx][:flag] +has_curr_ssaflag(sv::InferenceState, flag::UInt32) = has_flag(sv.src.ssaflags[sv.currpc], flag) +has_curr_ssaflag(sv::IRInterpretationState, flag::UInt32) = has_flag(sv.ir.stmts[sv.curridx][:flag], flag) + function set_curr_ssaflag!(sv::InferenceState, flag::UInt32, mask::UInt32=typemax(UInt32)) curr_flag = sv.src.ssaflags[sv.currpc] sv.src.ssaflags[sv.currpc] = (curr_flag & ~mask) | flag @@ -898,10 +901,10 @@ function set_curr_ssaflag!(sv::IRInterpretationState, flag::UInt32, mask::UInt32 end add_curr_ssaflag!(sv::InferenceState, flag::UInt32) = sv.src.ssaflags[sv.currpc] |= flag -add_curr_ssaflag!(sv::IRInterpretationState, flag::UInt32) = sv.ir.stmts[sv.curridx][:flag] |= flag +add_curr_ssaflag!(sv::IRInterpretationState, flag::UInt32) = add_flag!(sv.ir.stmts[sv.curridx], flag) sub_curr_ssaflag!(sv::InferenceState, flag::UInt32) = sv.src.ssaflags[sv.currpc] &= ~flag -sub_curr_ssaflag!(sv::IRInterpretationState, flag::UInt32) = sv.ir.stmts[sv.curridx][:flag] &= ~flag +sub_curr_ssaflag!(sv::IRInterpretationState, flag::UInt32) = sub_flag!(sv.ir.stmts[sv.curridx], flag) function merge_effects!(::AbstractInterpreter, caller::InferenceState, effects::Effects) if effects.effect_free === EFFECT_FREE_GLOBALLY diff --git a/base/compiler/optimize.jl b/base/compiler/optimize.jl index 43bdebed32b03..b0a4dfd1ced8d 100644 --- a/base/compiler/optimize.jl +++ b/base/compiler/optimize.jl @@ -15,36 +15,38 @@ const SLOT_USEDUNDEF = 32 # slot has uses that might raise UndefVarError # NOTE make sure to sync the flag definitions below with julia.h and `jl_code_info_set_ir` in method.c -const IR_FLAG_NULL = UInt32(0) +const IR_FLAG_NULL = zero(UInt32) # This statement is marked as @inbounds by user. # Ff replaced by inlining, any contained boundschecks may be removed. -const IR_FLAG_INBOUNDS = UInt32(1) << 0 +const IR_FLAG_INBOUNDS = one(UInt32) << 0 # This statement is marked as @inline by user -const IR_FLAG_INLINE = UInt32(1) << 1 +const IR_FLAG_INLINE = one(UInt32) << 1 # This statement is marked as @noinline by user -const IR_FLAG_NOINLINE = UInt32(1) << 2 -const IR_FLAG_THROW_BLOCK = UInt32(1) << 3 +const IR_FLAG_NOINLINE = one(UInt32) << 2 +const IR_FLAG_THROW_BLOCK = one(UInt32) << 3 # This statement was proven :effect_free -const IR_FLAG_EFFECT_FREE = UInt32(1) << 4 +const IR_FLAG_EFFECT_FREE = one(UInt32) << 4 # This statement was proven not to throw -const IR_FLAG_NOTHROW = UInt32(1) << 5 +const IR_FLAG_NOTHROW = one(UInt32) << 5 # This is :consistent -const IR_FLAG_CONSISTENT = UInt32(1) << 6 +const IR_FLAG_CONSISTENT = one(UInt32) << 6 # An optimization pass has updated this statement in a way that may # have exposed information that inference did not see. Re-running # inference on this statement may be profitable. -const IR_FLAG_REFINED = UInt32(1) << 7 +const IR_FLAG_REFINED = one(UInt32) << 7 # This is :noub == ALWAYS_TRUE -const IR_FLAG_NOUB = UInt32(1) << 8 +const IR_FLAG_NOUB = one(UInt32) << 8 # TODO: Both of these should eventually go away once # This is :effect_free == EFFECT_FREE_IF_INACCESSIBLEMEMONLY -const IR_FLAG_EFIIMO = UInt32(1) << 9 +const IR_FLAG_EFIIMO = one(UInt32) << 9 # This is :inaccessiblememonly == INACCESSIBLEMEM_OR_ARGMEMONLY -const IR_FLAG_INACCESSIBLE_OR_ARGMEM = UInt32(1) << 10 +const IR_FLAG_INACCESSIBLE_OR_ARGMEM = one(UInt32) << 10 const IR_FLAGS_EFFECTS = IR_FLAG_EFFECT_FREE | IR_FLAG_NOTHROW | IR_FLAG_CONSISTENT | IR_FLAG_NOUB +has_flag(curr::UInt32, flag::UInt32) = (curr & flag) == flag + const TOP_TUPLE = GlobalRef(Core, :tuple) # This corresponds to the type of `CodeInfo`'s `inlining_cost` field @@ -218,9 +220,9 @@ end _topmod(sv::OptimizationState) = _topmod(sv.mod) -is_stmt_inline(stmt_flag::UInt32) = stmt_flag & IR_FLAG_INLINE โ‰  0 -is_stmt_noinline(stmt_flag::UInt32) = stmt_flag & IR_FLAG_NOINLINE โ‰  0 -is_stmt_throw_block(stmt_flag::UInt32) = stmt_flag & IR_FLAG_THROW_BLOCK โ‰  0 +is_stmt_inline(stmt_flag::UInt32) = has_flag(stmt_flag, IR_FLAG_INLINE) +is_stmt_noinline(stmt_flag::UInt32) = has_flag(stmt_flag, IR_FLAG_NOINLINE) +is_stmt_throw_block(stmt_flag::UInt32) = has_flag(stmt_flag, IR_FLAG_THROW_BLOCK) function new_expr_effect_flags(๐•ƒโ‚’::AbstractLattice, args::Vector{Any}, src::Union{IRCode,IncrementalCompact}, pattern_match=nothing) Targ = args[1] @@ -468,7 +470,7 @@ end function any_stmt_may_throw(ir::IRCode, bb::Int) for stmt in ir.cfg.blocks[bb].stmts - if (ir[SSAValue(stmt)][:flag] & IR_FLAG_NOTHROW) != 0 + if has_flag(ir[SSAValue(stmt)], IR_FLAG_NOTHROW) return true end end @@ -702,7 +704,7 @@ function scan_non_dataflow_flags!(inst::Instruction, sv::PostOptAnalysisState) # ignore control flow node โ€“ they are not removable on their own and thus not # have `IR_FLAG_EFFECT_FREE` but still do not taint `:effect_free`-ness of # the whole method invocation - sv.all_effect_free &= !iszero(flag & IR_FLAG_EFFECT_FREE) + sv.all_effect_free &= has_flag(flag, IR_FLAG_EFFECT_FREE) end elseif sv.all_effect_free if (isexpr(stmt, :invoke) || isexpr(stmt, :new) || @@ -714,8 +716,8 @@ function scan_non_dataflow_flags!(inst::Instruction, sv::PostOptAnalysisState) sv.all_effect_free = false end end - sv.all_nothrow &= !iszero(flag & IR_FLAG_NOTHROW) - if iszero(flag & IR_FLAG_NOUB) + sv.all_nothrow &= has_flag(flag, IR_FLAG_NOTHROW) + if !has_flag(flag, IR_FLAG_NOUB) # Special case: `:boundscheck` into `getfield` or memory operations is `:noub_if_noinbounds` if is_conditional_noub(inst, sv) sv.any_conditional_ub = true @@ -960,11 +962,11 @@ function convert_to_ircode(ci::CodeInfo, sv::OptimizationState) ((block + 1) != destblock) && cfg_delete_edge!(sv.cfg, block, destblock) expr = Expr(:call, Core.typeassert, expr.cond, Bool) elseif i + 1 in sv.unreachable - @assert (ci.ssaflags[i] & IR_FLAG_NOTHROW) != 0 + @assert has_flag(ci.ssaflags[i], IR_FLAG_NOTHROW) cfg_delete_edge!(sv.cfg, block, block + 1) expr = GotoNode(expr.dest) elseif expr.dest in sv.unreachable - @assert (ci.ssaflags[i] & IR_FLAG_NOTHROW) != 0 + @assert has_flag(ci.ssaflags[i], IR_FLAG_NOTHROW) cfg_delete_edge!(sv.cfg, block, block_for_inst(sv.cfg, expr.dest)) expr = nothing end diff --git a/base/compiler/ssair/EscapeAnalysis/EscapeAnalysis.jl b/base/compiler/ssair/EscapeAnalysis/EscapeAnalysis.jl index 820975d405525..c05f3f53837a7 100644 --- a/base/compiler/ssair/EscapeAnalysis/EscapeAnalysis.jl +++ b/base/compiler/ssair/EscapeAnalysis/EscapeAnalysis.jl @@ -25,9 +25,9 @@ using ._TOP_MOD: # Base definitions unwrap_unionall, !, !=, !==, &, *, +, -, :, <, <<, =>, >, |, โˆˆ, โˆ‰, โˆฉ, โˆช, โ‰ , โ‰ค, โ‰ฅ, โІ using Core.Compiler: # Core.Compiler specific definitions Bottom, IRCode, IR_FLAG_NOTHROW, InferenceResult, SimpleInferenceLattice, - argextype, check_effect_free!, fieldcount_noerror, hasintersect, intrinsic_nothrow, - is_meta_expr_head, isbitstype, isexpr, println, setfield!_nothrow, singleton_type, - try_compute_field, try_compute_fieldidx, widenconst, โŠ‘, AbstractLattice + argextype, check_effect_free!, fieldcount_noerror, hasintersect, has_flag, + intrinsic_nothrow, is_meta_expr_head, isbitstype, isexpr, println, setfield!_nothrow, + singleton_type, try_compute_field, try_compute_fieldidx, widenconst, โŠ‘, AbstractLattice include(x) = _TOP_MOD.include(@__MODULE__, x) if _TOP_MOD === Core.Compiler @@ -975,7 +975,7 @@ end error("unexpected assignment found: inspect `Main.pc` and `Main.pc`") end -is_nothrow(ir::IRCode, pc::Int) = ir[SSAValue(pc)][:flag] & IR_FLAG_NOTHROW โ‰  0 +is_nothrow(ir::IRCode, pc::Int) = has_flag(ir[SSAValue(pc)], IR_FLAG_NOTHROW) # NOTE if we don't maintain the alias set that is separated from the lattice state, we can do # something like below: it essentially incorporates forward escape propagation in our default diff --git a/base/compiler/ssair/inlining.jl b/base/compiler/ssair/inlining.jl index f62e773567ac3..2e250bade533c 100644 --- a/base/compiler/ssair/inlining.jl +++ b/base/compiler/ssair/inlining.jl @@ -399,7 +399,7 @@ function ir_inline_item!(compact::IncrementalCompact, idx::Int, argexprs::Vector ssa_substitute = ir_prepare_inlining!(InsertHere(compact), compact, item.ir, item.mi, inlined_at, argexprs) - boundscheck = iszero(compact.result[idx][:flag] & IR_FLAG_INBOUNDS) ? boundscheck : :off + boundscheck = has_flag(compact.result[idx], IR_FLAG_INBOUNDS) ? :off : boundscheck # If the iterator already moved on to the next basic block, # temporarily re-open in again. @@ -1032,7 +1032,7 @@ function handle_single_case!(todo::Vector{Pair{Int,Any}}, stmt.head = :invoke pushfirst!(stmt.args, case.invoke) end - ir[SSAValue(idx)][:flag] |= flags_for_effects(case.effects) + add_flag!(ir[SSAValue(idx)], flags_for_effects(case.effects)) elseif case === nothing # Do, well, nothing else @@ -1257,13 +1257,14 @@ function check_effect_free!(ir::IRCode, idx::Int, @nospecialize(stmt), @nospecia end function check_effect_free!(ir::IRCode, idx::Int, @nospecialize(stmt), @nospecialize(rt), ๐•ƒโ‚’::AbstractLattice) (consistent, effect_free_and_nothrow, nothrow) = stmt_effect_flags(๐•ƒโ‚’, stmt, rt, ir) + inst = ir.stmts[idx] if consistent - ir.stmts[idx][:flag] |= IR_FLAG_CONSISTENT + add_flag!(inst, IR_FLAG_CONSISTENT) end if effect_free_and_nothrow - ir.stmts[idx][:flag] |= IR_FLAG_EFFECT_FREE | IR_FLAG_NOTHROW + add_flag!(inst, IR_FLAG_EFFECT_FREE | IR_FLAG_NOTHROW) elseif nothrow - ir.stmts[idx][:flag] |= IR_FLAG_NOTHROW + add_flag!(inst, IR_FLAG_NOTHROW) end if !(isexpr(stmt, :call) || isexpr(stmt, :invoke)) # There is a bit of a subtle point here, which is that some non-call @@ -1271,7 +1272,7 @@ function check_effect_free!(ir::IRCode, idx::Int, @nospecialize(stmt), @nospecia # illegal to introduce such statements that actually cause UB (for any # input). Ideally that'd be handled at insertion time (TODO), but for # the time being just do that here. - ir.stmts[idx][:flag] |= IR_FLAG_NOUB + add_flag!(inst, IR_FLAG_NOUB) end return effect_free_and_nothrow end @@ -1583,7 +1584,7 @@ function handle_cases!(todo::Vector{Pair{Int,Any}}, ir::IRCode, idx::Int, stmt:: end push!(todo, idx=>UnionSplit(fully_covered, atype, cases)) else - ir[SSAValue(idx)][:flag] |= flags_for_effects(joint_effects) + add_flag!(ir[SSAValue(idx)], flags_for_effects(joint_effects)) end return nothing end @@ -1682,7 +1683,7 @@ function inline_const_if_inlineable!(inst::Instruction) inst[:stmt] = quoted(rt.val) return true end - inst[:flag] |= IR_FLAG_EFFECT_FREE | IR_FLAG_NOTHROW + add_flag!(inst, IR_FLAG_EFFECT_FREE | IR_FLAG_NOTHROW) return false end @@ -1879,7 +1880,7 @@ function ssa_substitute_op!(insert_node!::Inserter, subst_inst::Instruction, @no return quoted(val) else flag = subst_inst[:flag] - maybe_undef = (flag & IR_FLAG_NOTHROW) == 0 && isa(val, TypeVar) + maybe_undef = !has_flag(flag, IR_FLAG_NOTHROW) && isa(val, TypeVar) (ret, tcheck_not) = insert_spval!(insert_node!, ssa_substitute.spvals_ssa::SSAValue, spidx, maybe_undef) if maybe_undef insert_node!( diff --git a/base/compiler/ssair/ir.jl b/base/compiler/ssair/ir.jl index e4ded5bd282da..5c347846e6e18 100644 --- a/base/compiler/ssair/ir.jl +++ b/base/compiler/ssair/ir.jl @@ -283,6 +283,10 @@ function setindex!(node::Instruction, newval::Instruction) return node end +has_flag(inst::Instruction, flag::UInt32) = has_flag(inst[:flag], flag) +add_flag!(inst::Instruction, flag::UInt32) = inst[:flag] |= flag +sub_flag!(inst::Instruction, flag::UInt32) = inst[:flag] &= ~flag + struct NewNodeInfo # Insertion position (interpretation depends on which array this is in) pos::Int @@ -334,18 +338,24 @@ function NewInstruction(inst::Instruction; return NewInstruction(stmt, type, info, line, flag) end @specialize -effect_free_and_nothrow(newinst::NewInstruction) = NewInstruction(newinst; flag=add_flag(newinst, IR_FLAG_EFFECT_FREE | IR_FLAG_NOTHROW)) -with_flags(newinst::NewInstruction, flags::UInt32) = NewInstruction(newinst; flag=add_flag(newinst, flags)) -without_flags(newinst::NewInstruction, flags::UInt32) = NewInstruction(newinst; flag=sub_flag(newinst, flags)) +effect_free_and_nothrow(newinst::NewInstruction) = add_flag(newinst, IR_FLAG_EFFECT_FREE | IR_FLAG_NOTHROW) function add_flag(newinst::NewInstruction, newflag::UInt32) flag = newinst.flag - flag === nothing && return newflag - return flag | newflag + if flag === nothing + flag = newflag + else + flag |= newflag + end + return NewInstruction(newinst; flag) end function sub_flag(newinst::NewInstruction, newflag::UInt32) flag = newinst.flag - flag === nothing && return IR_FLAG_NULL - return flag & ~newflag + if flag === nothing + flag = IR_FLAG_NULL + else + flag &= ~newflag + end + return NewInstruction(newinst; flag) end struct IRCode @@ -1325,7 +1335,7 @@ function process_node!(compact::IncrementalCompact, result_idx::Int, inst::Instr elseif isa(stmt, GlobalRef) total_flags = IR_FLAG_CONSISTENT | IR_FLAG_EFFECT_FREE flag = result[result_idx][:flag] - if (flag & total_flags) == total_flags + if has_flag(flag, total_flags) ssa_rename[idx] = stmt else ssa_rename[idx] = SSAValue(result_idx) @@ -1532,7 +1542,7 @@ function process_node!(compact::IncrementalCompact, result_idx::Int, inst::Instr else # Constant assign, replace uses of this ssa value with its result end - if (inst[:flag] & IR_FLAG_REFINED) != 0 && !isa(stmt, Refined) + if has_flag(inst, IR_FLAG_REFINED) && !isa(stmt, Refined) # If we're compacting away an instruction that was marked as refined, # leave a marker in the ssa_rename, so we can taint any users. stmt = Refined(stmt) @@ -1767,7 +1777,7 @@ function maybe_erase_unused!(callback::Function, compact::IncrementalCompact, id stmt = inst[:stmt] stmt === nothing && return false inst[:type] === Bottom && return false - effect_free = (inst[:flag] & (IR_FLAG_EFFECT_FREE | IR_FLAG_NOTHROW)) == IR_FLAG_EFFECT_FREE | IR_FLAG_NOTHROW + effect_free = has_flag(inst, (IR_FLAG_EFFECT_FREE | IR_FLAG_NOTHROW)) effect_free || return false foreachssa(stmt) do val::SSAValue if compact.used_ssas[val.id] == 1 diff --git a/base/compiler/ssair/irinterp.jl b/base/compiler/ssair/irinterp.jl index b1c3fddc3df6e..9f8bc17beca7f 100644 --- a/base/compiler/ssair/irinterp.jl +++ b/base/compiler/ssair/irinterp.jl @@ -138,7 +138,7 @@ function reprocess_instruction!(interp::AbstractInterpreter, inst::Instruction, if bb === nothing bb = block_for_inst(ir, idx) end - inst[:flag] |= IR_FLAG_NOTHROW + add_flag!(inst, IR_FLAG_NOTHROW) if condval inst[:stmt] = nothing inst[:type] = Any @@ -156,14 +156,14 @@ function reprocess_instruction!(interp::AbstractInterpreter, inst::Instruction, head = stmt.head if head === :call || head === :foreigncall || head === :new || head === :splatnew || head === :static_parameter || head === :isdefined || head === :boundscheck (; rt, effects) = abstract_eval_statement_expr(interp, stmt, nothing, irsv) - inst[:flag] |= flags_for_effects(effects) + add_flag!(inst, flags_for_effects(effects)) elseif head === :invoke rt, (nothrow, noub) = concrete_eval_invoke(interp, stmt, stmt.args[1]::MethodInstance, irsv) if nothrow - inst[:flag] |= IR_FLAG_NOTHROW + add_flag!(inst, IR_FLAG_NOTHROW) end if noub - inst[:flag] |= IR_FLAG_NOUB + add_flag!(inst, IR_FLAG_NOUB) end elseif head === :throw_undef_if_not condval = maybe_extract_const_bool(argextype(stmt.args[2], ir)) @@ -197,7 +197,7 @@ function reprocess_instruction!(interp::AbstractInterpreter, inst::Instruction, if rt !== nothing if isa(rt, Const) inst[:type] = rt - if is_inlineable_constant(rt.val) && (inst[:flag] & (IR_FLAG_EFFECT_FREE | IR_FLAG_NOTHROW)) == IR_FLAG_EFFECT_FREE | IR_FLAG_NOTHROW + if is_inlineable_constant(rt.val) && has_flag(inst, (IR_FLAG_EFFECT_FREE | IR_FLAG_NOTHROW)) inst[:stmt] = quoted(rt.val) end return true @@ -299,9 +299,9 @@ function _ir_abstract_constant_propagation(interp::AbstractInterpreter, irsv::IR typ = inst[:type] flag = inst[:flag] any_refined = false - if (flag & IR_FLAG_REFINED) != 0 + if has_flag(flag, IR_FLAG_REFINED) any_refined = true - inst[:flag] &= ~IR_FLAG_REFINED + sub_flag!(inst, IR_FLAG_REFINED) end for ur in userefs(stmt) val = ur[] @@ -351,8 +351,8 @@ function _ir_abstract_constant_propagation(interp::AbstractInterpreter, irsv::IR irsv.curridx = idx stmt = inst[:stmt] flag = inst[:flag] - if (flag & IR_FLAG_REFINED) != 0 - inst[:flag] &= ~IR_FLAG_REFINED + if has_flag(flag, IR_FLAG_REFINED) + sub_flag!(inst, IR_FLAG_REFINED) push!(stmt_ip, idx) end check_ret!(stmt, idx) @@ -408,8 +408,8 @@ function _ir_abstract_constant_propagation(interp::AbstractInterpreter, irsv::IR nothrow = noub = true for idx = 1:length(ir.stmts) flag = ir[SSAValue(idx)][:flag] - nothrow &= !iszero(flag & IR_FLAG_NOTHROW) - noub &= !iszero(flag & IR_FLAG_NOUB) + nothrow &= has_flag(flag, IR_FLAG_NOTHROW) + noub &= has_flag(flag, IR_FLAG_NOUB) (nothrow | noub) || break end diff --git a/base/compiler/ssair/passes.jl b/base/compiler/ssair/passes.jl index 6db47ed537e0e..9c6ed30dbbce8 100644 --- a/base/compiler/ssair/passes.jl +++ b/base/compiler/ssair/passes.jl @@ -934,17 +934,17 @@ end function refine_new_effects!(๐•ƒโ‚’::AbstractLattice, compact::IncrementalCompact, idx::Int, stmt::Expr) inst = compact[SSAValue(idx)] - if (inst[:flag] & (IR_FLAG_NOTHROW | IR_FLAG_EFFECT_FREE)) == (IR_FLAG_NOTHROW | IR_FLAG_EFFECT_FREE) + if has_flag(inst, (IR_FLAG_NOTHROW | IR_FLAG_EFFECT_FREE)) return # already accurate end (consistent, effect_free_and_nothrow, nothrow) = new_expr_effect_flags(๐•ƒโ‚’, stmt.args, compact, pattern_match_typeof) if consistent - inst[:flag] |= IR_FLAG_CONSISTENT + add_flag!(inst, IR_FLAG_CONSISTENT) end if effect_free_and_nothrow - inst[:flag] |= IR_FLAG_EFFECT_FREE | IR_FLAG_NOTHROW + add_flag!(inst, IR_FLAG_EFFECT_FREE | IR_FLAG_NOTHROW) elseif nothrow - inst[:flag] |= IR_FLAG_NOTHROW + add_flag!(inst, IR_FLAG_NOTHROW) end return nothing end @@ -1195,7 +1195,7 @@ function sroa_pass!(ir::IRCode, inlining::Union{Nothing,InliningState}=nothing) compact[idx] = lifted_val === nothing ? nothing : lifted_val.val if lifted_val !== nothing if !โŠ‘(๐•ƒโ‚’, compact[SSAValue(idx)][:type], result_t) - compact[SSAValue(idx)][:flag] |= IR_FLAG_REFINED + add_flag!(compact[SSAValue(idx)], IR_FLAG_REFINED) end end end @@ -1270,7 +1270,7 @@ function try_inline_finalizer!(ir::IRCode, argexprs::Vector{Any}, idx::Int, return true end -is_nothrow(ir::IRCode, ssa::SSAValue) = (ir[ssa][:flag] & IR_FLAG_NOTHROW) โ‰  0 +is_nothrow(ir::IRCode, ssa::SSAValue) = has_flag(ir[ssa], IR_FLAG_NOTHROW) function reachable_blocks(cfg::CFG, from_bb::Int, to_bb::Union{Nothing,Int} = nothing) worklist = Int[from_bb] @@ -1386,7 +1386,7 @@ function try_resolve_finalizer!(ir::IRCode, idx::Int, finalizer_idx::Int, defuse finalizer_stmt = ir[SSAValue(finalizer_idx)][:stmt] argexprs = Any[finalizer_stmt.args[2], finalizer_stmt.args[3]] - flags = info isa FinalizerInfo ? flags_for_effects(info.effects) : IR_FLAG_NULL + flag = info isa FinalizerInfo ? flags_for_effects(info.effects) : IR_FLAG_NULL if length(finalizer_stmt.args) >= 4 inline = finalizer_stmt.args[4] if inline === nothing @@ -1396,11 +1396,13 @@ function try_resolve_finalizer!(ir::IRCode, idx::Int, finalizer_idx::Int, defuse if inline::Bool && try_inline_finalizer!(ir, argexprs, loc, mi, info, inlining, attach_after) # the finalizer body has been inlined else - insert_node!(ir, loc, with_flags(NewInstruction(Expr(:invoke, mi, argexprs...), Nothing), flags), attach_after) + newinst = add_flag(NewInstruction(Expr(:invoke, mi, argexprs...), Nothing), flag) + insert_node!(ir, loc, newinst, attach_after) end end else - insert_node!(ir, loc, with_flags(NewInstruction(Expr(:call, argexprs...), Nothing), flags), attach_after) + newinst = add_flag(NewInstruction(Expr(:call, argexprs...), Nothing), flag) + insert_node!(ir, loc, newinst, attach_after) end # Erase the call to `finalizer` ir[SSAValue(finalizer_idx)][:stmt] = nothing @@ -1542,9 +1544,10 @@ function sroa_mutables!(ir::IRCode, defuses::IdDict{Int, Tuple{SPCSet, SSADefUse # Now go through all uses and rewrite them for use in du.uses if use.kind === :getfield - ir[SSAValue(use.idx)][:stmt] = compute_value_for_use(ir, domtree, allblocks, + inst = ir[SSAValue(use.idx)] + inst[:stmt] = compute_value_for_use(ir, domtree, allblocks, du, phinodes, fidx, use.idx) - ir[SSAValue(use.idx)][:flag] |= IR_FLAG_REFINED + add_flag!(inst, IR_FLAG_REFINED) elseif use.kind === :isdefined continue # already rewritten if possible elseif use.kind === :nopreserve @@ -1590,7 +1593,7 @@ function sroa_mutables!(ir::IRCode, defuses::IdDict{Int, Tuple{SPCSet, SSADefUse # know we have removed all uses of the mutable allocation. # As a result, if we ever do prove nothrow, we can delete # this statement then. - ir[ssa][:flag] |= IR_FLAG_EFFECT_FREE + add_flag!(ir[ssa], IR_FLAG_EFFECT_FREE) end end end