///|
pub const HOT_FLAG_TERMINATOR : UInt32 = 1U
///|
pub const HOT_FLAG_CONTROL : UInt32 = 2U
///|
pub const HOT_FLAG_SIDE_EFFECT : UInt32 = 4U
///|
pub const HOT_FLAG_VALUE : UInt32 = 8U
///|
pub const HOT_FLAG_MAY_TRAP : UInt32 = 16U
///|
pub const HOT_FLAG_BRANCH : UInt32 = 32U
///|
pub const HOT_FLAG_CALL : UInt32 = 64U
///|
pub const HOT_FLAG_LOAD : UInt32 = 128U
///|
pub const HOT_FLAG_STORE : UInt32 = 256U
///|
pub const HOT_FLAG_THROWS : UInt32 = 512U
///|
pub const HOT_FLAG_HAS_EXCEPTIONAL_SUCC : UInt32 = 1024U
///|
fn hot_flags_include(bits : UInt32, flag : UInt32) -> Bool {
(bits & flag) == flag
}
///|
pub fn hot_default_flags_for_op(op : HotOp) -> UInt32 {
match op {
HotOp::Nop => 0U
HotOp::Unreachable => HOT_FLAG_TERMINATOR
HotOp::Block | HotOp::Loop | HotOp::If | HotOp::Try | HotOp::TryTable =>
HOT_FLAG_CONTROL
HotOp::Br | HotOp::BrTable => HOT_FLAG_BRANCH | HOT_FLAG_TERMINATOR
HotOp::BrIf
| HotOp::BrOnNull
| HotOp::BrOnNonNull
| HotOp::BrOnCast
| HotOp::BrOnCastFail => HOT_FLAG_BRANCH
HotOp::Return => HOT_FLAG_TERMINATOR | HOT_FLAG_SIDE_EFFECT
HotOp::Continuation =>
HOT_FLAG_CALL |
HOT_FLAG_BRANCH |
HOT_FLAG_SIDE_EFFECT |
HOT_FLAG_MAY_TRAP |
HOT_FLAG_HAS_EXCEPTIONAL_SUCC
HotOp::Call | HotOp::CallIndirect | HotOp::CallRef =>
HOT_FLAG_CALL |
HOT_FLAG_SIDE_EFFECT |
HOT_FLAG_MAY_TRAP |
HOT_FLAG_HAS_EXCEPTIONAL_SUCC
HotOp::ReturnCall | HotOp::ReturnCallIndirect | HotOp::ReturnCallRef =>
HOT_FLAG_CALL |
HOT_FLAG_SIDE_EFFECT |
HOT_FLAG_MAY_TRAP |
HOT_FLAG_HAS_EXCEPTIONAL_SUCC |
HOT_FLAG_TERMINATOR
HotOp::LocalGet
| HotOp::GlobalGet
| HotOp::Const
| HotOp::Select
| HotOp::RefNull
| HotOp::RefIsNull
| HotOp::RefFunc
| HotOp::RefGetDesc
| HotOp::RefTest
| HotOp::RefTestDesc
| HotOp::Unary
| HotOp::Binary
| HotOp::Compare
| HotOp::Convert
| HotOp::TupleMake
| HotOp::TupleExtract
| HotOp::StringOp => HOT_FLAG_VALUE
HotOp::RefCast | HotOp::RefCastDescEq => HOT_FLAG_VALUE | HOT_FLAG_MAY_TRAP
HotOp::Heap => HOT_FLAG_VALUE | HOT_FLAG_SIDE_EFFECT | HOT_FLAG_MAY_TRAP
HotOp::LocalSet | HotOp::GlobalSet | HotOp::Drop => HOT_FLAG_SIDE_EFFECT
HotOp::LocalTee => HOT_FLAG_SIDE_EFFECT | HOT_FLAG_VALUE
HotOp::Load => HOT_FLAG_VALUE | HOT_FLAG_MAY_TRAP | HOT_FLAG_LOAD
HotOp::Store => HOT_FLAG_SIDE_EFFECT | HOT_FLAG_MAY_TRAP | HOT_FLAG_STORE
HotOp::MemorySize => HOT_FLAG_VALUE
HotOp::MemoryGrow => HOT_FLAG_SIDE_EFFECT | HOT_FLAG_VALUE
HotOp::MemoryCopy
| HotOp::MemoryFill
| HotOp::MemoryInit
| HotOp::TableSet
| HotOp::TableFill
| HotOp::TableCopy
| HotOp::TableInit =>
HOT_FLAG_SIDE_EFFECT | HOT_FLAG_MAY_TRAP | HOT_FLAG_STORE
HotOp::DataDrop | HotOp::ElemDrop => HOT_FLAG_SIDE_EFFECT
HotOp::TableGet => HOT_FLAG_VALUE | HOT_FLAG_MAY_TRAP | HOT_FLAG_LOAD
HotOp::TableSize => HOT_FLAG_VALUE
HotOp::TableGrow => HOT_FLAG_SIDE_EFFECT | HOT_FLAG_VALUE
HotOp::Throw | HotOp::Rethrow | HotOp::ThrowRef =>
HOT_FLAG_SIDE_EFFECT |
HOT_FLAG_THROWS |
HOT_FLAG_HAS_EXCEPTIONAL_SUCC |
HOT_FLAG_TERMINATOR
HotOp::Catch => HOT_FLAG_VALUE
HotOp::Delegate | HotOp::CatchAll => 0U
HotOp::Atomic | HotOp::Simd => 0U
}
}
///|
fn hot_flags_for_exact_payload(
func : HotFunc,
op : HotOp,
payload_id : SideTableId,
) -> UInt32 {
let base = hot_default_flags_for_op(op)
if payload_id < 0 || payload_id >= func.instr_payloads.length() {
return base
}
let mask = match op {
HotOp::Unary =>
effects_mask_for_numeric_exact(
Some(hot_instr_payload_get(func, payload_id).instr),
)
HotOp::Simd =>
effects_mask_for_simd_exact(
Some(hot_instr_payload_get(func, payload_id).instr),
)
HotOp::StringOp =>
effects_mask_for_string_exact(
Some(hot_instr_payload_get(func, payload_id).instr),
)
_ => return base
}
let mut flags = if op == HotOp::Simd &&
(mask & EFFECT_MASK_MEMORY_WRITE) != 0U {
base
} else {
base | HOT_FLAG_VALUE
}
if (mask & EFFECT_MASK_MEMORY_READ) != 0U {
flags = flags | HOT_FLAG_LOAD
}
if (mask & EFFECT_MASK_MEMORY_WRITE) != 0U {
flags = flags | HOT_FLAG_STORE | HOT_FLAG_SIDE_EFFECT
}
if (mask & EFFECT_MASK_TRAP) != 0U {
flags = flags | HOT_FLAG_MAY_TRAP
}
flags
}
///|
pub fn hot_node_flags(func : HotFunc, node_id : NodeId) -> UInt32 {
func.nodes[node_id].flags
}
///|
pub fn hot_node_has_flag(
func : HotFunc,
node_id : NodeId,
flag : UInt32,
) -> Bool {
hot_flags_include(hot_node_flags(func, node_id), flag)
}
///|
pub fn hot_is_control_node(func : HotFunc, node_id : NodeId) -> Bool {
hot_node_has_flag(func, node_id, HOT_FLAG_CONTROL)
}
///|
pub fn hot_is_terminator_node(func : HotFunc, node_id : NodeId) -> Bool {
hot_node_has_flag(func, node_id, HOT_FLAG_TERMINATOR)
}
///|
pub fn hot_has_side_effect(func : HotFunc, node_id : NodeId) -> Bool {
hot_node_has_flag(func, node_id, HOT_FLAG_SIDE_EFFECT)
}
///|
pub fn hot_may_trap(func : HotFunc, node_id : NodeId) -> Bool {
hot_node_has_flag(func, node_id, HOT_FLAG_MAY_TRAP)
}
///|
pub fn hot_is_branch(func : HotFunc, node_id : NodeId) -> Bool {
hot_node_has_flag(func, node_id, HOT_FLAG_BRANCH)
}
///|
pub fn hot_has_exceptional_succ(func : HotFunc, node_id : NodeId) -> Bool {
hot_node_has_flag(func, node_id, HOT_FLAG_HAS_EXCEPTIONAL_SUCC)
}
///|
pub fn hot_node_may_throw_exception(func : HotFunc, node_id : NodeId) -> Bool {
hot_node_has_flag(func, node_id, HOT_FLAG_THROWS) ||
hot_has_exceptional_succ(func, node_id)
}