Skip to content

Commit

Permalink
effects: pack bits better (JuliaLang#56737)
Browse files Browse the repository at this point in the history
There is no reason to preserve duplicates of the bits for the value
before and after inference, and many of the numbers in the comments had
gotten incorrect. Now we are able to pack all 16 bits of currently
defined bitflags into 20 bits, instead of 25 bits (although either case
still rounds up to 32).

There was also no reason for InferenceState to be mutating of CodeInfo
during execution, so remove that mutation.
  • Loading branch information
vtjnash authored Dec 4, 2024
1 parent 2590e67 commit 5ae2627
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 44 deletions.
25 changes: 12 additions & 13 deletions Compiler/src/inferencestate.jl
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ mutable struct InferenceState
bb_vartables::Vector{Union{Nothing,VarTable}} # nothing if not analyzed yet
bb_saw_latestworld::Vector{Bool}
ssavaluetypes::Vector{Any}
ssaflags::Vector{UInt32}
edges::Vector{Any}
stmt_info::Vector{CallInfo}

Expand Down Expand Up @@ -343,6 +344,7 @@ mutable struct InferenceState
bb_vartable1[i] = VarState(argtyp, i > nargtypes)
end
src.ssavaluetypes = ssavaluetypes = Any[ NOT_FOUND for i = 1:nssavalues ]
ssaflags = copy(src.ssaflags)

unreachable = BitSet()
pclimitations = IdSet{InferenceState}()
Expand Down Expand Up @@ -374,7 +376,7 @@ mutable struct InferenceState

this = new(
mi, WorldWithRange(world, valid_worlds), mod, sptypes, slottypes, src, cfg, spec_info,
currbb, currpc, ip, handler_info, ssavalue_uses, bb_vartables, bb_saw_latestworld, ssavaluetypes, edges, stmt_info,
currbb, currpc, ip, handler_info, ssavalue_uses, bb_vartables, bb_saw_latestworld, ssavaluetypes, ssaflags, edges, stmt_info,
tasks, pclimitations, limitations, cycle_backedges, callstack, parentid, frameid, cycleid,
result, unreachable, bestguess, exc_bestguess, ipo_effects,
restrict_abstract_call_sites, cache_mode, insert_coverage,
Expand Down Expand Up @@ -1004,25 +1006,22 @@ function callers_in_cycle(sv::InferenceState)
end
callers_in_cycle(sv::IRInterpretationState) = AbsIntCycle(sv.callstack::Vector{AbsIntState}, 0, 0)

get_curr_ssaflag(sv::InferenceState) = sv.src.ssaflags[sv.currpc]
get_curr_ssaflag(sv::InferenceState) = sv.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::InferenceState, flag::UInt32) = has_flag(sv.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
end
function set_curr_ssaflag!(sv::IRInterpretationState, flag::UInt32, mask::UInt32=typemax(UInt32))
curr_flag = sv.ir.stmts[sv.curridx][:flag]
sv.ir.stmts[sv.curridx][:flag] = (curr_flag & ~mask) | flag
curr_flag = sv.ssaflags[sv.currpc]
sv.ssaflags[sv.currpc] = (curr_flag & ~mask) | flag
nothing
end

add_curr_ssaflag!(sv::InferenceState, flag::UInt32) = sv.src.ssaflags[sv.currpc] |= flag
add_curr_ssaflag!(sv::InferenceState, flag::UInt32) = sv.ssaflags[sv.currpc] |= 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::InferenceState, flag::UInt32) = sv.ssaflags[sv.currpc] &= ~flag
sub_curr_ssaflag!(sv::IRInterpretationState, flag::UInt32) = sub_flag!(sv.ir.stmts[sv.curridx], flag)

function merge_effects!(::AbstractInterpreter, caller::InferenceState, effects::Effects)
Expand All @@ -1035,8 +1034,8 @@ function merge_effects!(::AbstractInterpreter, caller::InferenceState, effects::
end
merge_effects!(::AbstractInterpreter, ::IRInterpretationState, ::Effects) = return

decode_statement_effects_override(sv::AbsIntState) =
decode_statement_effects_override(get_curr_ssaflag(sv))
decode_statement_effects_override(sv::InferenceState) = decode_statement_effects_override(sv.src.ssaflags[sv.currpc])
decode_statement_effects_override(sv::IRInterpretationState) = decode_statement_effects_override(UInt32(0))

struct InferenceLoopState
rt
Expand Down
45 changes: 25 additions & 20 deletions Compiler/src/optimize.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,37 +17,41 @@ const SLOT_USEDUNDEF = 32 # slot has uses that might raise UndefVarError

const IR_FLAG_NULL = zero(UInt32)
# This statement is marked as @inbounds by user.
# Ff replaced by inlining, any contained boundschecks may be removed.
# If replaced by inlining, any contained boundschecks may be removed.
const IR_FLAG_INBOUNDS = one(UInt32) << 0
# This statement is marked as @inline by user
const IR_FLAG_INLINE = one(UInt32) << 1
# This statement is marked as @noinline by user
const IR_FLAG_NOINLINE = one(UInt32) << 2
# 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 = one(UInt32) << 3
# This statement is proven :consistent
const IR_FLAG_CONSISTENT = one(UInt32) << 4
const IR_FLAG_CONSISTENT = one(UInt32) << 3
# This statement is proven :effect_free
const IR_FLAG_EFFECT_FREE = one(UInt32) << 5
const IR_FLAG_EFFECT_FREE = one(UInt32) << 4
# This statement is proven :nothrow
const IR_FLAG_NOTHROW = one(UInt32) << 6
# This statement is proven :terminates
const IR_FLAG_TERMINATES = one(UInt32) << 7
# This statement is proven :noub
const IR_FLAG_NOUB = one(UInt32) << 8
# TODO: Both of these should eventually go away once
# This statement is :effect_free == EFFECT_FREE_IF_INACCESSIBLEMEMONLY
const IR_FLAG_EFIIMO = one(UInt32) << 9
# This statement is :inaccessiblememonly == INACCESSIBLEMEM_OR_ARGMEMONLY
const IR_FLAG_INACCESSIBLEMEM_OR_ARGMEM = one(UInt32) << 10
const IR_FLAG_NOTHROW = one(UInt32) << 5
# This statement is proven :terminates_globally
const IR_FLAG_TERMINATES = one(UInt32) << 6
#const IR_FLAG_TERMINATES_LOCALLY = one(UInt32) << 7
#const IR_FLAG_NOTASKSTATE = one(UInt32) << 8
#const IR_FLAG_INACCESSIBLEMEM = one(UInt32) << 9
const IR_FLAG_NOUB = one(UInt32) << 10
#const IR_FLAG_NOUBINIB = one(UInt32) << 11
#const IR_FLAG_CONSISTENTOVERLAY = one(UInt32) << 12
# This statement is :nortcall
const IR_FLAG_NORTCALL = one(UInt32) << 11
const IR_FLAG_NORTCALL = one(UInt32) << 13
# 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 = one(UInt32) << 16
# This statement has no users and may be deleted if flags get refined to IR_FLAGS_REMOVABLE
const IR_FLAG_UNUSED = one(UInt32) << 12
const IR_FLAG_UNUSED = one(UInt32) << 17
# TODO: Both of these next two should eventually go away once
# This statement is :effect_free == EFFECT_FREE_IF_INACCESSIBLEMEMONLY
const IR_FLAG_EFIIMO = one(UInt32) << 18
# This statement is :inaccessiblememonly == INACCESSIBLEMEM_OR_ARGMEMONLY
const IR_FLAG_INACCESSIBLEMEM_OR_ARGMEM = one(UInt32) << 19

const NUM_IR_FLAGS = 13 # sync with julia.h
const NUM_IR_FLAGS = 3 # sync with julia.h

const IR_FLAGS_EFFECTS =
IR_FLAG_CONSISTENT | IR_FLAG_EFFECT_FREE | IR_FLAG_NOTHROW |
Expand Down Expand Up @@ -815,6 +819,7 @@ function scan_non_dataflow_flags!(inst::Instruction, sv::PostOptAnalysisState)
sv.nortcall = false
end
end
nothing
end

function scan_inconsistency!(inst::Instruction, sv::PostOptAnalysisState)
Expand Down
3 changes: 2 additions & 1 deletion Compiler/src/typeinfer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,7 @@ function finishinfer!(me::InferenceState, interp::AbstractInterpreter)
ipo_effects = result.ipo_effects = me.ipo_effects = adjust_effects(me)
result.exc_result = me.exc_bestguess = refine_exception_type(me.exc_bestguess, ipo_effects)
me.src.rettype = widenconst(ignorelimited(bestguess))
me.src.ssaflags = me.ssaflags
me.src.min_world = first(me.world.valid_worlds)
me.src.max_world = last(me.world.valid_worlds)
istoplevel = !(me.linfo.def isa Method)
Expand Down Expand Up @@ -936,7 +937,7 @@ function codeinfo_for_const(interp::AbstractInterpreter, mi::MethodInstance, @no
tree.slotflags = fill(0x00, nargs)
tree.ssavaluetypes = 1
tree.debuginfo = DebugInfo(mi)
tree.ssaflags = UInt32[0]
tree.ssaflags = [IR_FLAG_NULL]
tree.rettype = Core.Typeof(val)
tree.edges = Core.svec()
set_inlineable!(tree, true)
Expand Down
13 changes: 3 additions & 10 deletions src/julia.h
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ typedef union __jl_purity_overrides_t {
} _jl_purity_overrides_t;

#define NUM_EFFECTS_OVERRIDES 11
#define NUM_IR_FLAGS 13
#define NUM_IR_FLAGS 3

// This type describes a single function body
typedef struct _jl_code_info_t {
Expand All @@ -292,15 +292,8 @@ typedef struct _jl_code_info_t {
// 1 << 0 = inbounds region
// 1 << 1 = callsite inline region
// 1 << 2 = callsite noinline region
// 1 << 3 = refined statement
// 1 << 4 = :consistent
// 1 << 5 = :effect_free
// 1 << 6 = :nothrow
// 1 << 7 = :terminates
// 1 << 8 = :noub
// 1 << 9 = :effect_free_if_inaccessiblememonly
// 1 << 10 = :inaccessiblemem_or_argmemonly
// 1 << 11-19 = callsite effects overrides
// 1 << 3-14 = purity
// 1 << 16+ = reserved for inference
// miscellaneous data:
jl_array_t *slotnames; // names of local variables
jl_array_t *slotflags; // local var bit flags
Expand Down

0 comments on commit 5ae2627

Please sign in to comment.