///|
pub type BlockId = Int32
///|
pub enum CfgEdgeKind {
FallthroughEdge
BranchEdge
ReturnEdge
ExceptionalEdge
UnreachableExitEdge
} derive(Eq, Debug)
///|
pub impl Show for CfgEdgeKind with fn output(self, logger) {
match self {
FallthroughEdge => logger.write_string("FallthroughEdge")
BranchEdge => logger.write_string("BranchEdge")
ReturnEdge => logger.write_string("ReturnEdge")
ExceptionalEdge => logger.write_string("ExceptionalEdge")
UnreachableExitEdge => logger.write_string("UnreachableExitEdge")
}
}
///|
pub enum CfgBlockBoundaryReason {
RootEntry
ControlHeader
LoopHeader
BodyRegionEntry
ThenRegionEntry
ElseRegionEntry
CatchRegionEntry
CatchListRegionEntry
Terminator
} derive(Eq, Debug)
///|
pub impl Show for CfgBlockBoundaryReason with fn output(self, logger) {
match self {
RootEntry => logger.write_string("RootEntry")
ControlHeader => logger.write_string("ControlHeader")
LoopHeader => logger.write_string("LoopHeader")
BodyRegionEntry => logger.write_string("BodyRegionEntry")
ThenRegionEntry => logger.write_string("ThenRegionEntry")
ElseRegionEntry => logger.write_string("ElseRegionEntry")
CatchRegionEntry => logger.write_string("CatchRegionEntry")
CatchListRegionEntry => logger.write_string("CatchListRegionEntry")
Terminator => logger.write_string("Terminator")
}
}
///|
pub enum CfgControlSuccessorPolicy {
InlineBodyRegion
SplitThenElse
SplitBodyCatch
SplitBodyCatchList
} derive(Eq, Debug)
///|
pub impl Show for CfgControlSuccessorPolicy with fn output(self, logger) {
match self {
InlineBodyRegion => logger.write_string("InlineBodyRegion")
SplitThenElse => logger.write_string("SplitThenElse")
SplitBodyCatch => logger.write_string("SplitBodyCatch")
SplitBodyCatchList => logger.write_string("SplitBodyCatchList")
}
}
///|
pub enum CfgExceptionTargetPolicy {
NoExceptionEdge
PropagateToCaller
ToCatchRegion
ToCatchListRegion
DelegateToTarget
} derive(Eq, Debug)
///|
pub impl Show for CfgExceptionTargetPolicy with fn output(self, logger) {
match self {
NoExceptionEdge => logger.write_string("NoExceptionEdge")
PropagateToCaller => logger.write_string("PropagateToCaller")
ToCatchRegion => logger.write_string("ToCatchRegion")
ToCatchListRegion => logger.write_string("ToCatchListRegion")
DelegateToTarget => logger.write_string("DelegateToTarget")
}
}
///|
fn cfg_is_root_node(func : HotFunc, node_id : NodeId) -> Bool {
for root_idx = 0; root_idx < hot_root_count(func); root_idx = root_idx + 1 {
if hot_root_get(func, root_idx) == node_id {
return true
}
}
false
}
///|
fn cfg_boundary_reason_from_region_role(
role : HotControlRegionRole,
) -> CfgBlockBoundaryReason {
match role {
HotControlRegionRole::BodyRegion => CfgBlockBoundaryReason::BodyRegionEntry
HotControlRegionRole::ThenRegion => CfgBlockBoundaryReason::ThenRegionEntry
HotControlRegionRole::ElseRegion => CfgBlockBoundaryReason::ElseRegionEntry
HotControlRegionRole::CatchRegion =>
CfgBlockBoundaryReason::CatchRegionEntry
HotControlRegionRole::CatchListRegion =>
CfgBlockBoundaryReason::CatchListRegionEntry
}
}
///|
fn cfg_op_is_terminator(op : HotOp) -> Bool {
match op {
HotOp::Block
| HotOp::Loop
| HotOp::If
| HotOp::Try
| HotOp::TryTable
| HotOp::Continuation
| HotOp::Br
| HotOp::BrIf
| HotOp::BrTable
| HotOp::BrOnNull
| HotOp::BrOnNonNull
| HotOp::BrOnCast
| HotOp::BrOnCastFail
| HotOp::Return
| HotOp::ReturnCall
| HotOp::ReturnCallIndirect
| HotOp::ReturnCallRef
| HotOp::Throw
| HotOp::Rethrow
| HotOp::ThrowRef
| HotOp::Delegate
| HotOp::Unreachable => true
_ => false
}
}
///|
pub fn cfg_block_boundary_reasons(
func : HotFunc,
node_id : NodeId,
) -> Array[CfgBlockBoundaryReason] {
let reasons : Array[CfgBlockBoundaryReason] = []
let op = hot_node_get(func, node_id).op
if cfg_is_root_node(func, node_id) {
reasons.push(CfgBlockBoundaryReason::RootEntry)
}
if hot_is_control_node(func, node_id) {
reasons.push(CfgBlockBoundaryReason::ControlHeader)
for slot_info in hot_control_region_slot_info(op) {
reasons.push(cfg_boundary_reason_from_region_role(slot_info.role))
}
}
if op == HotOp::Loop {
reasons.push(CfgBlockBoundaryReason::LoopHeader)
}
if cfg_op_is_terminator(op) {
reasons.push(CfgBlockBoundaryReason::Terminator)
}
reasons
}
///|
pub fn cfg_control_successor_policy(op : HotOp) -> CfgControlSuccessorPolicy? {
match op {
HotOp::Block | HotOp::Loop =>
Some(CfgControlSuccessorPolicy::InlineBodyRegion)
HotOp::If => Some(CfgControlSuccessorPolicy::SplitThenElse)
HotOp::Try => Some(CfgControlSuccessorPolicy::SplitBodyCatch)
HotOp::TryTable => Some(CfgControlSuccessorPolicy::SplitBodyCatchList)
_ => None
}
}
///|
pub fn cfg_exception_target_policy(op : HotOp) -> CfgExceptionTargetPolicy {
match op {
HotOp::Try => CfgExceptionTargetPolicy::ToCatchRegion
HotOp::TryTable => CfgExceptionTargetPolicy::ToCatchListRegion
HotOp::Throw | HotOp::ThrowRef | HotOp::Rethrow =>
CfgExceptionTargetPolicy::PropagateToCaller
HotOp::Delegate => CfgExceptionTargetPolicy::DelegateToTarget
_ => CfgExceptionTargetPolicy::NoExceptionEdge
}
}
///|
pub fn cfg_terminator_edge_kinds(op : HotOp) -> Array[CfgEdgeKind] {
match op {
HotOp::Br => [CfgEdgeKind::BranchEdge]
HotOp::BrIf
| HotOp::BrOnNull
| HotOp::BrOnNonNull
| HotOp::BrOnCast
| HotOp::BrOnCastFail =>
[CfgEdgeKind::BranchEdge, CfgEdgeKind::FallthroughEdge]
HotOp::BrTable => [CfgEdgeKind::BranchEdge]
HotOp::Return
| HotOp::ReturnCall
| HotOp::ReturnCallIndirect
| HotOp::ReturnCallRef => [CfgEdgeKind::ReturnEdge]
HotOp::Throw | HotOp::ThrowRef | HotOp::Rethrow | HotOp::Delegate =>
[CfgEdgeKind::ExceptionalEdge]
HotOp::Unreachable => [CfgEdgeKind::UnreachableExitEdge]
HotOp::Block | HotOp::Loop | HotOp::If | HotOp::Try | HotOp::TryTable =>
[CfgEdgeKind::FallthroughEdge]
_ => []
}
}