// Licensing scope: see ../../LICENSE and this directory's LICENSE and NOTICE.
// Copyright 2023 WebAssembly Community Group participants.
// Retained historical upstream notice; current derivation remains unconfirmed.
// Conservative attribution from pinned Binaryen version_130 counterpart:
// Copyright 2022 WebAssembly Community Group participants
// Counterpart: src/passes/OptimizeCasts.cpp (5d704ad5); origin remains unconfirmed.
// Potentially incorporated Binaryen expression retains Apache-2.0 terms.
// Original Starshine contributions use the scoped MIT grant in ../../LICENSE.
// Modified for Starshine through 2026: implementation and validation use
// Starshine's representations and APIs; this is not an unchanged upstream file.
// Conservative notice retention does not establish copying or independence.

///|
pub fn optimize_casts_descriptor() -> @ir.HotPassDescriptor {
  @ir.HotPassDescriptor::new("optimize-casts", invalidates=[
    @ir.HotAnalysis::cfg(),
    @ir.HotAnalysis::dominance(),
    @ir.HotAnalysis::liveness(),
    @ir.HotAnalysis::use_def(),
    @ir.HotAnalysis::effects(),
    @ir.HotAnalysis::loop_info(),
    @ir.HotAnalysis::ssa(),
  ])
}

///|
pub fn optimize_casts_summary() -> String {
  "Remove provably redundant GC casts and fold ref.test outcomes from static reference types."
}

///|
fn oc_abs_heap_matches(
  source : @lib.AbsHeapType,
  target : @lib.AbsHeapType,
) -> Bool {
  if source == target {
    return true
  }
  match (source, target) {
    (@lib.NoneAbsHeapType, @lib.StructAbsHeapType)
    | (@lib.NoneAbsHeapType, @lib.ArrayAbsHeapType)
    | (@lib.NoneAbsHeapType, @lib.I31AbsHeapType)
    | (@lib.NoneAbsHeapType, @lib.EqAbsHeapType)
    | (@lib.NoneAbsHeapType, @lib.AnyAbsHeapType)
    | (@lib.NoFuncAbsHeapType, @lib.FuncAbsHeapType)
    | (@lib.NoContAbsHeapType, @lib.ContAbsHeapType)
    | (@lib.NoWaitqueueAbsHeapType, @lib.WaitqueueAbsHeapType)
    | (@lib.StringAbsHeapType, @lib.ExternAbsHeapType)
    | (@lib.NoExternAbsHeapType, @lib.ExternAbsHeapType)
    | (@lib.NoExternAbsHeapType, @lib.StringAbsHeapType)
    | (@lib.NoExnAbsHeapType, @lib.ExnAbsHeapType)
    | (@lib.I31AbsHeapType, @lib.EqAbsHeapType)
    | (@lib.I31AbsHeapType, @lib.AnyAbsHeapType)
    | (@lib.StructAbsHeapType, @lib.EqAbsHeapType)
    | (@lib.StructAbsHeapType, @lib.AnyAbsHeapType)
    | (@lib.ArrayAbsHeapType, @lib.EqAbsHeapType)
    | (@lib.ArrayAbsHeapType, @lib.AnyAbsHeapType)
    | (@lib.EqAbsHeapType, @lib.AnyAbsHeapType) => true
    _ => false
  }
}

///|
fn oc_comptype_matches_abs(ct : @lib.CompType, abs : @lib.AbsHeapType) -> Bool {
  match ct {
    @lib.StructCompType(_) =>
      abs == @lib.AbsHeapType::struct_() ||
      abs == @lib.AbsHeapType::eq() ||
      abs == @lib.AbsHeapType::any()
    @lib.ArrayCompType(_) =>
      abs == @lib.AbsHeapType::array() ||
      abs == @lib.AbsHeapType::eq() ||
      abs == @lib.AbsHeapType::any()
    @lib.FuncCompType(_, _) =>
      abs == @lib.AbsHeapType::func() || abs == @lib.AbsHeapType::any()
    @lib.ContCompType(_) => abs == @lib.AbsHeapType::cont()
  }
}

///|
fn oc_subtype_as_heap_matches(
  module_ctx : @ir.HotModuleContext,
  subtype : @lib.SubType,
  target : @lib.HeapType,
  fuel : Int32,
) -> Bool {
  if fuel <= 0 {
    return false
  }
  let (is_final, supers, ct) = match subtype {
    @lib.CompTypeSubType(_, ct) => (false, [], ct)
    @lib.SubType(is_final, supers, _, ct) => (is_final, supers, ct)
  }
  match target {
    @lib.AbsHeapTypeHeapType(abs) => {
      if subtype.metadata().is_shared() {
        return false
      }
      if oc_comptype_matches_abs(ct, abs) {
        return true
      }
      if is_final {
        return false
      }
    }
    @lib.SharedAbsHeapTypeHeapType(abs) => {
      if !subtype.metadata().is_shared() {
        return false
      }
      if oc_comptype_matches_abs(ct, abs) {
        return true
      }
      if is_final {
        return false
      }
    }
    _ => ()
  }
  for super_idx in supers {
    if oc_heap_matches(
        module_ctx,
        @lib.HeapType::new(super_idx),
        target,
        fuel - 1,
      ) {
      return true
    }
  }
  false
}

///|
fn oc_heap_identical(
  module_ctx : @ir.HotModuleContext,
  source : @lib.HeapType,
  target : @lib.HeapType,
) -> Bool {
  if source == target {
    return true
  }
  match (source, target) {
    (@lib.HeapType(_), @lib.HeapType(_)) => {
      let base = @validate.Env::new().with_types(module_ctx.subtypes)
      let env = @validate.Env::{ ..base, rec_stack: module_ctx.type_groups, }
      @validate.Match::matches(
        @lib.RefType::new(false, source, exact=true),
        @lib.RefType::new(false, target, exact=true),
        env,
      )
    }
    _ => false
  }
}

///|
fn oc_heap_matches(
  module_ctx : @ir.HotModuleContext,
  source : @lib.HeapType,
  target : @lib.HeapType,
  fuel : Int32,
) -> Bool {
  if oc_heap_identical(module_ctx, source, target) {
    return true
  }
  if fuel <= 0 {
    return false
  }
  match (source, target) {
    (@lib.AbsHeapTypeHeapType(source_abs), @lib.AbsHeapTypeHeapType(target_abs)) =>
      oc_abs_heap_matches(source_abs, target_abs)
    (
      @lib.SharedAbsHeapTypeHeapType(source_abs),
      @lib.SharedAbsHeapTypeHeapType(target_abs),
    ) => oc_abs_heap_matches(source_abs, target_abs)
    (@lib.HeapType(source_idx), _) =>
      match @ir.hot_module_resolve_subtype(module_ctx, source_idx) {
        Some(subtype) =>
          oc_subtype_as_heap_matches(module_ctx, subtype, target, fuel - 1)
        None => false
      }
    (_, @lib.HeapType(target_idx)) =>
      match source {
        @lib.AbsHeapTypeHeapType(@lib.NoneAbsHeapType) =>
          match @ir.hot_module_resolve_subtype(module_ctx, target_idx) {
            Some(subtype) =>
              match subtype.get_comptype() {
                @lib.StructCompType(_) | @lib.ArrayCompType(_) => true
                _ => false
              }
            None => false
          }
        @lib.AbsHeapTypeHeapType(@lib.NoFuncAbsHeapType) =>
          match @ir.hot_module_resolve_subtype(module_ctx, target_idx) {
            Some(subtype) =>
              match subtype.get_comptype() {
                @lib.FuncCompType(_, _) => true
                _ => false
              }
            None => false
          }
        _ => false
      }
    _ => false
  }
}

///|
fn oc_ref_type_from_node(func : @ir.HotFunc, node_id : Int32) -> @lib.RefType? {
  let results = @ir.hot_type_results(func, @ir.hot_node_type(func, node_id))
  if results.length() != 1 {
    return None
  }
  match results[0] {
    @lib.RefTypeValType(ref_type) => Some(ref_type)
    _ => None
  }
}

///|
fn oc_refinement_type_from_node(
  func : @ir.HotFunc,
  node_id : Int32,
) -> @lib.RefType? {
  match @ir.hot_node_exact_instr(func, node_id) {
    Some(@lib.Instruction::RefCast(_, _, _))
    | Some(@lib.Instruction::RefAsNonNull) =>
      oc_ref_type_from_node(func, node_id)
    _ => {
      let node = @ir.hot_node_get(func, node_id)
      match node.op {
        @ir.HotOp::LocalTee =>
          if @ir.hot_child_count(func, node_id) == 1 {
            let child_id = @ir.hot_child_get(func, node_id, 0)
            match @ir.hot_node_exact_instr(func, child_id) {
              Some(@lib.Instruction::RefCast(_, _, _))
              | Some(@lib.Instruction::RefAsNonNull) =>
                oc_ref_type_from_node(func, child_id)
              _ => oc_ref_type_from_node(func, node_id)
            }
          } else {
            oc_ref_type_from_node(func, node_id)
          }
        _ => oc_ref_type_from_node(func, node_id)
      }
    }
  }
}

///|
fn oc_target_ref_type(
  nullable : Bool,
  exact : Bool,
  heap_type : @lib.HeapType,
) -> @lib.RefType {
  @lib.RefType::new(nullable, heap_type, exact~)
}

///|
fn oc_ref_always_matches(
  module_ctx : @ir.HotModuleContext,
  source : @lib.RefType,
  target : @lib.RefType,
) -> Bool {
  if source.is_nullable() && !target.is_nullable() {
    return false
  }
  if target.is_exact() {
    return source.is_exact() &&
      oc_heap_identical(
        module_ctx,
        source.get_heap_type(),
        target.get_heap_type(),
      )
  }
  oc_heap_matches(
    module_ctx,
    source.get_heap_type(),
    target.get_heap_type(),
    512,
  )
}

///|
fn oc_comptype_may_overlap(a : @lib.CompType, b : @lib.CompType) -> Bool {
  match (a, b) {
    (@lib.StructCompType(_), @lib.StructCompType(_)) => true
    (@lib.ArrayCompType(_), @lib.ArrayCompType(_)) => true
    (@lib.FuncCompType(_, _), @lib.FuncCompType(_, _)) => true
    (@lib.ContCompType(_), @lib.ContCompType(_)) => true
    _ => false
  }
}

///|
fn oc_heap_never_matches(
  module_ctx : @ir.HotModuleContext,
  source : @lib.HeapType,
  target : @lib.HeapType,
) -> Bool {
  if oc_heap_matches(module_ctx, source, target, 512) {
    return false
  }
  match (source, target) {
    (@lib.AbsHeapTypeHeapType(source_abs), @lib.AbsHeapTypeHeapType(target_abs)) =>
      !oc_abs_heap_matches(source_abs, target_abs) &&
      !oc_abs_heap_matches(target_abs, source_abs)
    (@lib.HeapType(source_idx), @lib.HeapType(target_idx)) =>
      match
        (
          @ir.hot_module_resolve_subtype(module_ctx, source_idx),
          @ir.hot_module_resolve_subtype(module_ctx, target_idx),
        ) {
        (Some(source_subtype), Some(target_subtype)) =>
          !oc_comptype_may_overlap(
            source_subtype.get_comptype(),
            target_subtype.get_comptype(),
          )
        _ => false
      }
    (@lib.HeapType(source_idx), @lib.AbsHeapTypeHeapType(target_abs)) =>
      match @ir.hot_module_resolve_subtype(module_ctx, source_idx) {
        Some(source_subtype) =>
          !oc_comptype_matches_abs(source_subtype.get_comptype(), target_abs)
        None => false
      }
    (@lib.AbsHeapTypeHeapType(source_abs), @lib.HeapType(target_idx)) =>
      match @ir.hot_module_resolve_subtype(module_ctx, target_idx) {
        Some(target_subtype) =>
          !oc_comptype_matches_abs(target_subtype.get_comptype(), source_abs)
        None => false
      }
    _ => false
  }
}

///|
fn oc_ref_never_matches(
  module_ctx : @ir.HotModuleContext,
  source : @lib.RefType,
  target : @lib.RefType,
) -> Bool {
  if source.is_nullable() && target.is_nullable() {
    return false
  }
  if target.is_exact() {
    return source.is_exact() &&
      !oc_heap_identical(
        module_ctx,
        source.get_heap_type(),
        target.get_heap_type(),
      )
  }
  if source.is_exact() &&
    !oc_heap_matches(
      module_ctx,
      source.get_heap_type(),
      target.get_heap_type(),
      512,
    ) {
    return true
  }
  oc_heap_never_matches(
    module_ctx,
    source.get_heap_type(),
    target.get_heap_type(),
  )
}

///|
fn oc_replace_with_child(
  ctx : HotPassContext,
  func : @ir.HotFunc,
  node_id : Int32,
) -> Unit {
  if @ir.hot_child_count(func, node_id) != 1 {
    return
  }
  let child_id = @ir.hot_child_get(func, node_id, 0)
  pass_replace_node(
    ctx,
    func,
    node_id,
    @ir.hot_node_get(func, child_id),
    preserve_value_order=true,
  )
}

///|
fn oc_is_known_null_value(
  func : @ir.HotFunc,
  node_id : Int32,
  depth : Int32,
) -> Bool {
  if depth <= 0 || !@ir.hot_node_is_live(func, node_id) {
    return false
  }
  match @ir.hot_node_get(func, node_id).op {
    @ir.HotOp::RefNull => true
    @ir.HotOp::Block => {
      if !oc_block_is_plain_fallthrough(func, node_id) {
        return false
      }
      let body = @ir.hot_region_body_ref(func, node_id)
      let root_count = @ir.hot_region_root_count(func, body)
      if root_count == 0 {
        return false
      }
      oc_is_known_null_value(
        func,
        @ir.hot_region_get(func, body, root_count - 1),
        depth - 1,
      )
    }
    _ => false
  }
}

///|
fn oc_replace_nullable_known_null_desc_eq(
  ctx : HotPassContext,
  func : @ir.HotFunc,
  node_id : Int32,
  target_ref : @lib.RefType,
) -> Bool {
  if !target_ref.is_nullable() || @ir.hot_child_count(func, node_id) != 2 {
    return false
  }
  let source_id = @ir.hot_child_get(func, node_id, 0)
  if !oc_is_known_null_value(func, source_id, 64) {
    return false
  }
  let descriptor_id = @ir.hot_child_get(func, node_id, 1)
  let descriptor_eval = match oc_ref_type_from_node(func, descriptor_id) {
    Some(descriptor_ref) if descriptor_ref.is_nullable() => {
      let checked_ref = @lib.RefType::new(
        false,
        descriptor_ref.get_heap_type(),
        exact=descriptor_ref.is_exact(),
      )
      @ir.hot_build_heap(
        func,
        [@lib.ValType::ref_type(checked_ref)],
        @lib.Instruction::ref_as_non_null(),
        [descriptor_id],
      )
    }
    Some(_) => descriptor_id
    None => return false
  }
  let typed_null = @ir.hot_build_ref_null(func, target_ref)
  let temp = @ir.hot_build_block(
    func,
    @lib.BlockType::val_type(@lib.ValType::ref_type(target_ref)),
    [
      @ir.hot_build_drop(func, source_id),
      @ir.hot_build_drop(func, descriptor_eval),
      typed_null,
    ],
  )
  let replacement = @ir.hot_node_get(func, temp)
  @ir.hot_delete_node(func, temp)
  pass_replace_node(ctx, func, node_id, replacement)
  true
}

///|
fn oc_replace_with_const_i32(
  ctx : HotPassContext,
  func : @ir.HotFunc,
  node_id : Int32,
  value : Int32,
) -> Unit {
  let roots : Array[Int32] = []
  for child in oc_node_children(func, node_id) {
    let pure_read = match @ir.hot_node_get(func, child).op {
      @ir.HotOp::LocalGet
      | @ir.HotOp::GlobalGet
      | @ir.HotOp::RefNull
      | @ir.HotOp::RefFunc => true
      _ =>
        @ir.effects_is_pure(@ir.effects_for_node(func, child)) &&
        !@ir.hot_may_trap(func, child)
    }
    if !pure_read {
      roots.push(@ir.hot_build_drop(func, child))
    }
  }
  roots.push(@ir.hot_build_const_i32(func, @lib.I32(value)))
  let temp = if roots.length() == 1 {
    roots[0]
  } else {
    @ir.hot_build_block(
      func,
      @lib.BlockType::val_type(@lib.ValType::i32()),
      roots,
    )
  }
  let replacement = @ir.hot_node_get(func, temp)
  @ir.hot_delete_node(func, temp)
  pass_replace_node(ctx, func, node_id, replacement)
}

///|
fn oc_replace_with_unconditional_br(
  ctx : HotPassContext,
  func : @ir.HotFunc,
  node_id : Int32,
) -> Unit {
  let node = @ir.hot_node_get(func, node_id)
  let values : Array[Int32] = []
  for i = 0; i < @ir.hot_child_count(func, node_id); i = i + 1 {
    values.push(@ir.hot_child_get(func, node_id, i))
  }
  let temp = @ir.hot_build_br(func, node.imm0, values~)
  let replacement = @ir.hot_node_get(func, temp)
  @ir.hot_delete_node(func, temp)
  pass_replace_node(ctx, func, node_id, replacement)
}

///|
fn oc_node_children(func : @ir.HotFunc, node_id : Int32) -> Array[Int32] {
  let children : Array[Int32] = []
  for i = 0; i < @ir.hot_child_count(func, node_id); i = i + 1 {
    children.push(@ir.hot_child_get(func, node_id, i))
  }
  children
}

///|
fn oc_node_is_local_get(
  func : @ir.HotFunc,
  node_id : Int32,
  local_id : Int32,
) -> Bool {
  let node = @ir.hot_node_get(func, node_id)
  match node.op {
    @ir.HotOp::LocalGet => node.imm0 == local_id
    _ => false
  }
}

///|
fn oc_collect_local_get_counts(
  func : @ir.HotFunc,
  node_id : Int32,
  counts : Array[Int32],
  touched : Array[Int32],
) -> Unit {
  if !@ir.hot_node_is_live(func, node_id) {
    return
  }
  let node = @ir.hot_node_get(func, node_id)
  if node.op is @ir.HotOp::LocalGet &&
    node.imm0 >= 0 &&
    node.imm0 < counts.length() {
    if counts[node.imm0] == 0 {
      touched.push(node.imm0)
    }
    counts[node.imm0] += 1
  }
  for slot = 0; slot < @ir.hot_child_count(func, node_id); slot = slot + 1 {
    let child_id = @ir.hot_child_get(func, node_id, slot)
    oc_collect_local_get_counts(func, child_id, counts, touched)
  }
}

///|
/// Test helper for measuring a single-local walk independently of batching.
fn oc_count_local_gets(
  func : @ir.HotFunc,
  node_id : Int32,
  local_id : Int32,
) -> Int32 {
  if !@ir.hot_node_is_live(func, node_id) {
    return 0
  }
  let mut count = if oc_node_is_local_get(func, node_id, local_id) {
    1
  } else {
    0
  }
  for slot = 0; slot < @ir.hot_child_count(func, node_id); slot = slot + 1 {
    count += oc_count_local_gets(
      func,
      @ir.hot_child_get(func, node_id, slot),
      local_id,
    )
  }
  count
}

///|
// Restore a proven non-null result only when its storage was weakened.
fn oc_restore_capture_type(
  func : @ir.HotFunc,
  value_id : Int32,
  ref_type : @lib.RefType,
) -> Int32 {
  if ref_type.is_nullable() {
    return value_id
  }
  match oc_ref_type_from_node(func, value_id) {
    Some(value_type) if value_type == ref_type => value_id
    _ =>
      @ir.hot_build_heap(
        func,
        [@lib.ValType::ref_type(ref_type)],
        @lib.Instruction::ref_as_non_null(),
        [value_id],
      )
  }
}

///|
fn oc_retarget_local_gets_from_map(
  ctx : HotPassContext,
  func : @ir.HotFunc,
  node_id : Int32,
  retarget : Array[Bool],
  fresh_locals : Array[Int32],
  best_casts : Array[Int32],
) -> Int32 {
  if !@ir.hot_node_is_live(func, node_id) {
    return 0
  }
  let mut count = 0
  let node = @ir.hot_node_get(func, node_id)
  if node.op is @ir.HotOp::LocalGet &&
    node.imm0 >= 0 &&
    node.imm0 < retarget.length() &&
    retarget[node.imm0] {
    let fresh_local = fresh_locals[node.imm0]
    if fresh_local >= 0 {
      let ref_type = match oc_ref_type_from_node(func, best_casts[node.imm0]) {
        Some(ref_type) => ref_type
        None => return 0
      }
      let temp = oc_restore_capture_type(
        func,
        @ir.hot_build_local_get(func, fresh_local),
        ref_type,
      )
      let replacement = @ir.hot_node_get(func, temp)
      @ir.hot_delete_node(func, temp)
      pass_replace_node(ctx, func, node_id, replacement)
      count += 1
    }
  }
  for slot = 0; slot < @ir.hot_child_count(func, node_id); slot = slot + 1 {
    let child_id = @ir.hot_child_get(func, node_id, slot)
    count += oc_retarget_local_gets_from_map(
      ctx, func, child_id, retarget, fresh_locals, best_casts,
    )
  }
  count
}

///|
/// Test helper for measuring a single-local walk independently of batching.
fn oc_retarget_local_gets(
  ctx : HotPassContext,
  func : @ir.HotFunc,
  node_id : Int32,
  local_id : Int32,
  fresh_local : Int32,
) -> Int32 {
  if !@ir.hot_node_is_live(func, node_id) {
    return 0
  }
  let mut count = 0
  if oc_node_is_local_get(func, node_id, local_id) {
    let temp = @ir.hot_build_local_get(func, fresh_local)
    let replacement = @ir.hot_node_get(func, temp)
    @ir.hot_delete_node(func, temp)
    pass_replace_node(ctx, func, node_id, replacement)
    count += 1
  }
  for slot = 0; slot < @ir.hot_child_count(func, node_id); slot = slot + 1 {
    count += oc_retarget_local_gets(
      ctx,
      func,
      @ir.hot_child_get(func, node_id, slot),
      local_id,
      fresh_local,
    )
  }
  count
}

///|
fn oc_collect_written_locals(
  func : @ir.HotFunc,
  node_id : Int32,
  writes : Array[Int32],
  write_mask : Array[Bool],
) -> Unit {
  if !@ir.hot_node_is_live(func, node_id) {
    return
  }
  let node = @ir.hot_node_get(func, node_id)
  match node.op {
    @ir.HotOp::LocalSet | @ir.HotOp::LocalTee =>
      if node.imm0 >= 0 &&
        node.imm0 < write_mask.length() &&
        !write_mask[node.imm0] {
        write_mask[node.imm0] = true
        writes.push(node.imm0)
      }
    _ => ()
  }
  for slot = 0; slot < @ir.hot_child_count(func, node_id); slot = slot + 1 {
    let child_id = @ir.hot_child_get(func, node_id, slot)
    oc_collect_written_locals(func, child_id, writes, write_mask)
  }
}

///|
fn oc_source_local_requires_nullable_check(
  func : @ir.HotFunc,
  source_id : Int32,
  requires_nullable_source : Bool,
) -> Bool {
  if !requires_nullable_source {
    return true
  }
  match oc_ref_type_from_node(func, source_id) {
    Some(ref_type) => ref_type.is_nullable()
    None => false
  }
}

///|
fn oc_plain_block_source_local(
  func : @ir.HotFunc,
  block_id : Int32,
  requires_nullable_source : Bool,
) -> Int32? {
  if !oc_block_is_plain_fallthrough(func, block_id) {
    return None
  }
  let body = @ir.hot_region_body_ref(func, block_id)
  let root_count = @ir.hot_region_root_count(func, body)
  if root_count <= 0 {
    return None
  }
  for idx = 0; idx < root_count - 1; idx = idx + 1 {
    let prefix_root = @ir.hot_region_get(func, body, idx)
    if !oc_dropped_nontrapping_pure_root(func, prefix_root) {
      return None
    }
  }
  let root_id = @ir.hot_region_get(func, body, root_count - 1)
  let root = @ir.hot_node_get(func, root_id)
  match root.op {
    @ir.HotOp::LocalGet =>
      if oc_source_local_requires_nullable_check(
          func, root_id, requires_nullable_source,
        ) {
        Some(root.imm0)
      } else {
        None
      }
    _ => None
  }
}

///|
fn oc_refinement_child_source_local(
  func : @ir.HotFunc,
  child_id : Int32,
  requires_nullable_source : Bool,
) -> Int32? {
  let child = @ir.hot_node_get(func, child_id)
  match child.op {
    @ir.HotOp::LocalGet | @ir.HotOp::LocalTee =>
      if oc_source_local_requires_nullable_check(
          func, child_id, requires_nullable_source,
        ) {
        Some(child.imm0)
      } else {
        None
      }
    @ir.HotOp::Block =>
      oc_plain_block_source_local(func, child_id, requires_nullable_source)
    _ => None
  }
}

///|
fn oc_is_nested_ref_as_nullable_cast(
  func : @ir.HotFunc,
  node_id : Int32,
) -> Bool {
  match @ir.hot_node_exact_instr(func, node_id) {
    Some(@lib.Instruction::RefAsNonNull) => ()
    _ => return false
  }
  if @ir.hot_child_count(func, node_id) != 1 {
    return false
  }
  let child_id = @ir.hot_child_get(func, node_id, 0)
  match @ir.hot_node_exact_instr(func, child_id) {
    Some(@lib.Instruction::RefCast(true, _, _)) => true
    _ => false
  }
}

///|
fn oc_nested_ref_as_cast_source_local(
  func : @ir.HotFunc,
  node_id : Int32,
) -> Int32? {
  if !oc_is_nested_ref_as_nullable_cast(func, node_id) {
    return None
  }
  let cast_id = @ir.hot_child_get(func, node_id, 0)
  if @ir.hot_child_count(func, cast_id) != 1 {
    return None
  }
  let source_id = @ir.hot_child_get(func, cast_id, 0)
  oc_refinement_child_source_local(func, source_id, false)
}

///|
fn oc_refinement_source_local(func : @ir.HotFunc, node_id : Int32) -> Int32? {
  let requires_nullable_source = match @ir.hot_node_exact_instr(func, node_id) {
    Some(@lib.Instruction::RefCast(_, _, _)) => false
    Some(@lib.Instruction::RefAsNonNull) => true
    _ => return None
  }
  if @ir.hot_child_count(func, node_id) != 1 {
    return None
  }
  let child_id = @ir.hot_child_get(func, node_id, 0)
  match
    oc_refinement_child_source_local(func, child_id, requires_nullable_source) {
    Some(local_id) => Some(local_id)
    None => oc_nested_ref_as_cast_source_local(func, node_id)
  }
}

///|
fn oc_early_refinement_source_local(
  func : @ir.HotFunc,
  node_id : Int32,
) -> Int32? {
  let requires_nullable_source = match @ir.hot_node_exact_instr(func, node_id) {
    Some(@lib.Instruction::RefCast(_, _, _)) => false
    Some(@lib.Instruction::RefAsNonNull) => true
    _ => return None
  }
  if @ir.hot_child_count(func, node_id) != 1 {
    return None
  }
  let child_id = @ir.hot_child_get(func, node_id, 0)
  let child = @ir.hot_node_get(func, child_id)
  match child.op {
    @ir.HotOp::LocalGet =>
      if oc_source_local_requires_nullable_check(
          func, child_id, requires_nullable_source,
        ) {
        Some(child.imm0)
      } else {
        None
      }
    @ir.HotOp::LocalTee =>
      if @ir.hot_child_count(func, child_id) == 1 {
        let tee_source = @ir.hot_child_get(func, child_id, 0)
        let source = @ir.hot_node_get(func, tee_source)
        match source.op {
          @ir.HotOp::LocalGet =>
            if source.imm0 != child.imm0 &&
              oc_source_local_requires_nullable_check(
                func, tee_source, requires_nullable_source,
              ) {
              Some(source.imm0)
            } else {
              None
            }
          _ => None
        }
      } else {
        None
      }
    _ => oc_nested_ref_as_cast_source_local(func, node_id)
  }
}

///|
fn oc_contains_local(locals : Array[Int32], local_id : Int32) -> Bool {
  for written in locals {
    if written == local_id {
      return true
    }
  }
  false
}

///|
fn oc_op_is_structured_control(op : @ir.HotOp) -> Bool {
  match op {
    @ir.HotOp::Block
    | @ir.HotOp::Loop
    | @ir.HotOp::If
    | @ir.HotOp::Try
    | @ir.HotOp::TryTable => true
    _ => false
  }
}

///|
fn oc_op_is_linear_block_barrier(op : @ir.HotOp) -> Bool {
  match op {
    @ir.HotOp::Unreachable
    | @ir.HotOp::Block
    | @ir.HotOp::Loop
    | @ir.HotOp::If
    | @ir.HotOp::Try
    | @ir.HotOp::TryTable
    | @ir.HotOp::Br
    | @ir.HotOp::BrIf
    | @ir.HotOp::BrTable
    | @ir.HotOp::BrOnNull
    | @ir.HotOp::BrOnNonNull
    | @ir.HotOp::BrOnCast
    | @ir.HotOp::BrOnCastFail
    | @ir.HotOp::Return
    | @ir.HotOp::ReturnCall
    | @ir.HotOp::ReturnCallIndirect
    | @ir.HotOp::ReturnCallRef
    | @ir.HotOp::Throw
    | @ir.HotOp::Rethrow
    | @ir.HotOp::ThrowRef
    | @ir.HotOp::Delegate => true
    _ => false
  }
}

///|
fn oc_node_has_linear_block_barrier(
  func : @ir.HotFunc,
  node_id : Int32,
) -> Bool {
  if !@ir.hot_node_is_live(func, node_id) {
    return false
  }
  let node = @ir.hot_node_get(func, node_id)
  if oc_op_is_linear_block_barrier(node.op) {
    return true
  }
  for slot = 0; slot < @ir.hot_child_count(func, node_id); slot = slot + 1 {
    let child_id = @ir.hot_child_get(func, node_id, slot)
    if oc_node_has_linear_block_barrier(func, child_id) {
      return true
    }
  }
  false
}

///|
fn oc_block_is_plain_fallthrough(func : @ir.HotFunc, block_id : Int32) -> Bool {
  let body = @ir.hot_region_body_ref(func, block_id)
  for idx = 0; idx < @ir.hot_region_root_count(func, body); idx = idx + 1 {
    if oc_node_has_linear_block_barrier(
        func,
        @ir.hot_region_get(func, body, idx),
      ) {
      return false
    }
  }
  true
}

///|
fn oc_plain_fallthrough_block_for_root(
  func : @ir.HotFunc,
  root_id : Int32,
) -> Int32? {
  let root = @ir.hot_node_get(func, root_id)
  match root.op {
    @ir.HotOp::Block => Some(root_id)
    @ir.HotOp::Drop =>
      if @ir.hot_child_count(func, root_id) == 1 {
        let child_id = @ir.hot_child_get(func, root_id, 0)
        match @ir.hot_node_get(func, child_id).op {
          @ir.HotOp::Block => Some(child_id)
          _ => None
        }
      } else {
        None
      }
    _ => None
  }
}

///|
// A refinement describes the value at the cast, so a later write to the same
// local in this expression kills it. Visit operands in evaluation order.
fn oc_forget_refinements_for_local(
  out : Array[(Int32, Int32)],
  local_id : Int32,
) -> Unit {
  let mut kept = 0
  for idx = 0; idx < out.length(); idx = idx + 1 {
    if out[idx].0 != local_id {
      out[kept] = out[idx]
      kept += 1
    }
  }
  while out.length() > kept {
    ignore(out.pop())
  }
}

///|
fn oc_collect_refinements(
  func : @ir.HotFunc,
  node_id : Int32,
  out : Array[(Int32, Int32)],
) -> Unit {
  if !@ir.hot_node_is_live(func, node_id) {
    return
  }
  let node = @ir.hot_node_get(func, node_id)
  if oc_op_is_structured_control(node.op) {
    return
  }
  for slot = 0; slot < @ir.hot_child_count(func, node_id); slot = slot + 1 {
    let child_id = @ir.hot_child_get(func, node_id, slot)
    oc_collect_refinements(func, child_id, out)
  }
  match node.op {
    @ir.HotOp::LocalSet | @ir.HotOp::LocalTee => {
      oc_forget_refinements_for_local(out, node.imm0)
      if @ir.hot_child_count(func, node_id) == 1 {
        let value_id = @ir.hot_child_get(func, node_id, 0)
        match @ir.hot_node_exact_instr(func, value_id) {
          Some(@lib.RefCast(_, _, _)) | Some(@lib.RefAsNonNull) =>
            out.push((node.imm0, value_id))
          _ => ()
        }
      }
    }
    _ => ()
  }
  match oc_refinement_source_local(func, node_id) {
    Some(local_id) => out.push((local_id, node_id))
    None => ()
  }
}

///|
fn oc_collect_refinement_tee_source_aliases(
  func : @ir.HotFunc,
  node_id : Int32,
  out : Array[(Int32, Int32)],
) -> Unit {
  if !@ir.hot_node_is_live(func, node_id) {
    return
  }
  let node = @ir.hot_node_get(func, node_id)
  if oc_op_is_structured_control(node.op) {
    return
  }
  for slot = 0; slot < @ir.hot_child_count(func, node_id); slot = slot + 1 {
    let child_id = @ir.hot_child_get(func, node_id, slot)
    oc_collect_refinement_tee_source_aliases(func, child_id, out)
  }
  match node.op {
    @ir.HotOp::LocalSet | @ir.HotOp::LocalTee => {
      oc_forget_refinements_for_local(out, node.imm0)
      return
    }
    _ => ()
  }
  let requires_nullable_source = match @ir.hot_node_exact_instr(func, node_id) {
    Some(@lib.Instruction::RefCast(_, _, _)) => false
    Some(@lib.Instruction::RefAsNonNull) => true
    _ => return
  }
  if @ir.hot_child_count(func, node_id) == 1 {
    let child_id = @ir.hot_child_get(func, node_id, 0)
    let child = @ir.hot_node_get(func, child_id)
    match child.op {
      @ir.HotOp::LocalTee =>
        if @ir.hot_child_count(func, child_id) == 1 {
          let tee_source = @ir.hot_child_get(func, child_id, 0)
          let source = @ir.hot_node_get(func, tee_source)
          match source.op {
            @ir.HotOp::LocalGet =>
              if source.imm0 != child.imm0 &&
                oc_source_local_requires_nullable_check(
                  func, tee_source, requires_nullable_source,
                ) {
                out.push((source.imm0, node_id))
              }
            _ => ()
          }
        }
      _ => ()
    }
  }
}

///|
fn oc_existing_fresh_can_feed_refinement_source(
  func : @ir.HotFunc,
  candidate_id : Int32,
  current_id : Int32,
) -> Bool {
  match
    (
      oc_refinement_type_from_node(func, candidate_id),
      oc_refinement_type_from_node(func, current_id),
    ) {
    (Some(candidate), Some(current)) => candidate == current
    _ => false
  }
}

///|
fn oc_indexed_refinement_blocks_retarget(
  module_ctx : @ir.HotModuleContext,
  func : @ir.HotFunc,
  refinements : Array[(Int32, Int32)],
  refinement_heads : Array[Int32],
  refinement_next : Array[Int32],
  local_id : Int32,
  best_cast : Int32,
  has_existing_fresh : Bool,
  moved_refinalized_refinements : Array[Int32],
) -> Bool {
  let mut at = refinement_heads[local_id]
  while at >= 0 {
    let refinement = refinements[at]
    let can_feed_existing_equal = has_existing_fresh &&
      oc_existing_fresh_can_feed_refinement_source(
        func,
        best_cast,
        refinement.1,
      )
    let can_feed_refinalized_equal = oc_contains_local(
        moved_refinalized_refinements,
        refinement.1,
      ) &&
      oc_existing_fresh_can_feed_refinement_source(
        func,
        best_cast,
        refinement.1,
      )
    let can_feed_existing_source = has_existing_fresh &&
      oc_ref_cast_source_can_read_best_cast(
        module_ctx,
        func,
        best_cast,
        refinement.1,
      )
    if !oc_best_cast_can_feed_refinement_source(
        module_ctx,
        func,
        best_cast,
        refinement.1,
      ) &&
      !can_feed_existing_equal &&
      !can_feed_refinalized_equal &&
      !can_feed_existing_source {
      return true
    }
    at = refinement_next[at]
  }
  false
}

///|
fn oc_marked_equal_refinement_source_get(
  func : @ir.HotFunc,
  refinements : Array[(Int32, Int32)],
  local_id : Int32,
  best_cast : Int32,
  moved_refinalized_refinements : Array[Int32],
) -> Int32? {
  for refinement in refinements {
    if refinement.0 == local_id &&
      oc_contains_local(moved_refinalized_refinements, refinement.1) &&
      oc_existing_fresh_can_feed_refinement_source(
        func,
        best_cast,
        refinement.1,
      ) {
      match oc_direct_refinement_source_get(func, refinement.1) {
        Some((_, source_get)) => return Some(source_get)
        None => ()
      }
    }
  }
  None
}

///|
fn oc_ref_type_as_non_null(ref_type : @lib.RefType) -> @lib.RefType {
  @lib.RefType::new(false, ref_type.get_heap_type(), exact=ref_type.is_exact())
}

///|
fn oc_refinalize_marked_ref_cast_to_best(
  ctx : HotPassContext,
  func : @ir.HotFunc,
  module_ctx : @ir.HotModuleContext,
  root_id : Int32,
  best_cast : Int32,
  moved_refinalized_refinements : Array[Int32],
) -> Bool {
  let cast_id = match oc_single_dropped_child(func, root_id) {
    Some(child_id) => child_id
    None => return false
  }
  if !oc_contains_local(moved_refinalized_refinements, cast_id) {
    return false
  }
  match @ir.hot_node_exact_instr(func, cast_id) {
    Some(@lib.Instruction::RefCast(_, _, _)) => ()
    _ => return false
  }
  if @ir.hot_child_count(func, cast_id) != 1 {
    return false
  }
  if !oc_cast_is_more_refined(module_ctx, func, best_cast, cast_id) {
    return false
  }
  let best_target = match oc_refinement_type_from_node(func, best_cast) {
    Some(ref_type) => ref_type
    None => return false
  }
  let cast_node = @ir.hot_node_get(func, cast_id)
  let payload_id = @ir.hot_alloc_instr_payload(
    func,
    @ir.HotInstrPayload::new(@lib.Instruction::ref_cast_type(best_target)),
  )
  let replacement_id = @ir.hot_build_node(
    func,
    cast_node.op,
    @ir.hot_type_intern_value(func, @lib.ValType::ref_type(best_target)),
    imm0=cast_node.imm0,
    imm1=payload_id,
    children=oc_node_children(func, cast_id),
  )
  let replacement = @ir.hot_node_get(func, replacement_id)
  @ir.hot_delete_node(func, replacement_id)
  pass_replace_node(ctx, func, cast_id, replacement)
  true
}

///|
fn oc_ref_cast_source_can_read_best_cast(
  module_ctx : @ir.HotModuleContext,
  func : @ir.HotFunc,
  candidate_id : Int32,
  current_id : Int32,
) -> Bool {
  match @ir.hot_node_exact_instr(func, current_id) {
    Some(@lib.Instruction::RefCast(_, _, _)) => ()
    _ => return false
  }
  if @ir.hot_child_count(func, current_id) != 1 {
    return false
  }
  let candidate = match oc_refinement_type_from_node(func, candidate_id) {
    Some(ref_type) => ref_type
    None => return false
  }
  let source_id = @ir.hot_child_get(func, current_id, 0)
  let source = match oc_ref_type_from_node(func, source_id) {
    Some(ref_type) => ref_type
    None => return false
  }
  let target = match oc_refinement_type_from_node(func, current_id) {
    Some(ref_type) => ref_type
    None => return false
  }
  candidate != source &&
  oc_ref_always_matches(module_ctx, candidate, source) &&
  !oc_ref_never_matches(module_ctx, candidate, target)
}

///|
fn oc_nullable_best_cast_feeds_ref_as_non_null(
  module_ctx : @ir.HotModuleContext,
  func : @ir.HotFunc,
  candidate_id : Int32,
  current_id : Int32,
) -> Bool {
  match @ir.hot_node_exact_instr(func, current_id) {
    Some(@lib.Instruction::RefAsNonNull) => ()
    _ => return false
  }
  let candidate = match oc_refinement_type_from_node(func, candidate_id) {
    Some(ref_type) => ref_type
    None => return false
  }
  if !candidate.is_nullable() {
    return false
  }
  let current = match oc_refinement_type_from_node(func, current_id) {
    Some(ref_type) => ref_type
    None => return false
  }
  let candidate_after_as_non_null = oc_ref_type_as_non_null(candidate)
  candidate_after_as_non_null != current &&
  oc_ref_always_matches(module_ctx, candidate_after_as_non_null, current)
}

///|
fn oc_cast_is_more_refined(
  module_ctx : @ir.HotModuleContext,
  func : @ir.HotFunc,
  candidate_id : Int32,
  current_id : Int32,
) -> Bool {
  let candidate = match oc_refinement_type_from_node(func, candidate_id) {
    Some(ref_type) => ref_type
    None => return false
  }
  let current = match oc_refinement_type_from_node(func, current_id) {
    Some(ref_type) => ref_type
    None => return true
  }
  candidate != current && oc_ref_always_matches(module_ctx, candidate, current)
}

///|
fn oc_best_cast_can_feed_refinement_source(
  module_ctx : @ir.HotModuleContext,
  func : @ir.HotFunc,
  candidate_id : Int32,
  current_id : Int32,
) -> Bool {
  oc_cast_is_more_refined(module_ctx, func, candidate_id, current_id) ||
  oc_nullable_best_cast_feeds_ref_as_non_null(
    module_ctx, func, candidate_id, current_id,
  )
}

///|
fn oc_wrap_refinement_with_tee(
  ctx : HotPassContext,
  func : @ir.HotFunc,
  cast_id : Int32,
  fresh_local : Int32,
) -> Bool {
  if !@ir.hot_node_is_live(func, cast_id) {
    return false
  }
  let ref_type = match oc_ref_type_from_node(func, cast_id) {
    Some(ref_type) => ref_type
    None => return false
  }
  let cast_node = @ir.hot_node_get(func, cast_id)
  let clone = @ir.hot_build_node(
    func,
    cast_node.op,
    cast_node.ty,
    imm0=cast_node.imm0,
    imm1=cast_node.imm1,
    children=oc_node_children(func, cast_id),
  )
  let tee = @ir.hot_build_local_tee(func, fresh_local, clone)
  let temp = oc_restore_capture_type(func, tee, ref_type)
  let replacement = @ir.hot_node_get(func, temp)
  @ir.hot_delete_node(func, temp)
  pass_replace_node(ctx, func, cast_id, replacement)
  true
}

///|
fn oc_dropped_local_get(func : @ir.HotFunc, root_id : Int32) -> (Int32, Int32)? {
  if !@ir.hot_node_is_live(func, root_id) {
    return None
  }
  match @ir.hot_node_get(func, root_id).op {
    @ir.HotOp::Drop =>
      if @ir.hot_child_count(func, root_id) == 1 {
        let child_id = @ir.hot_child_get(func, root_id, 0)
        let child = @ir.hot_node_get(func, child_id)
        match child.op {
          @ir.HotOp::LocalGet => Some((child.imm0, child_id))
          _ => None
        }
      } else {
        None
      }
    _ => None
  }
}

///|
fn oc_nontrapping_pure_local_set(func : @ir.HotFunc, root_id : Int32) -> Int32? {
  if !@ir.hot_node_is_live(func, root_id) {
    return None
  }
  let root = @ir.hot_node_get(func, root_id)
  match root.op {
    @ir.HotOp::LocalSet =>
      if @ir.hot_child_count(func, root_id) == 1 {
        let child_id = @ir.hot_child_get(func, root_id, 0)
        if oc_i32_nontrapping_pure_tree(func, child_id, 64) {
          Some(root.imm0)
        } else {
          None
        }
      } else {
        None
      }
    _ => None
  }
}

///|
fn oc_nontrapping_pure_tee_value(func : @ir.HotFunc, node_id : Int32) -> Bool {
  if !@ir.hot_node_is_live(func, node_id) {
    return false
  }
  match @ir.hot_node_get(func, node_id).op {
    @ir.HotOp::LocalGet => true
    _ => oc_i32_nontrapping_pure_tree(func, node_id, 64)
  }
}

///|
fn oc_dropped_nontrapping_pure_local_tee(
  func : @ir.HotFunc,
  root_id : Int32,
) -> Int32? {
  if !@ir.hot_node_is_live(func, root_id) {
    return None
  }
  match @ir.hot_node_get(func, root_id).op {
    @ir.HotOp::Drop =>
      if @ir.hot_child_count(func, root_id) == 1 {
        let tee_id = @ir.hot_child_get(func, root_id, 0)
        let tee = @ir.hot_node_get(func, tee_id)
        match tee.op {
          @ir.HotOp::LocalTee =>
            if @ir.hot_child_count(func, tee_id) == 1 {
              let value_id = @ir.hot_child_get(func, tee_id, 0)
              if oc_nontrapping_pure_tee_value(func, value_id) {
                Some(tee.imm0)
              } else {
                None
              }
            } else {
              None
            }
          _ => None
        }
      } else {
        None
      }
    _ => None
  }
}

///|
fn oc_direct_dropped_refinement(
  func : @ir.HotFunc,
  root_id : Int32,
) -> (Int32, Int32)? {
  if !@ir.hot_node_is_live(func, root_id) {
    return None
  }
  match @ir.hot_node_get(func, root_id).op {
    @ir.HotOp::Drop =>
      if @ir.hot_child_count(func, root_id) == 1 {
        let child_id = @ir.hot_child_get(func, root_id, 0)
        match oc_early_refinement_source_local(func, child_id) {
          Some(local_id) => Some((local_id, child_id))
          None => None
        }
      } else {
        None
      }
    _ => None
  }
}

///|
fn oc_direct_refinement_source_get(
  func : @ir.HotFunc,
  cast_id : Int32,
) -> (Int32, Int32)? {
  let requires_nullable_source = match @ir.hot_node_exact_instr(func, cast_id) {
    Some(@lib.Instruction::RefCast(_, _, _)) => false
    Some(@lib.Instruction::RefAsNonNull) => true
    _ => return None
  }
  if @ir.hot_child_count(func, cast_id) != 1 {
    return None
  }
  let child_id = @ir.hot_child_get(func, cast_id, 0)
  let child = @ir.hot_node_get(func, child_id)
  match child.op {
    @ir.HotOp::LocalGet =>
      if oc_source_local_requires_nullable_check(
          func, child_id, requires_nullable_source,
        ) {
        Some((child.imm0, child_id))
      } else {
        None
      }
    _ => None
  }
}

///|
fn oc_single_dropped_child(func : @ir.HotFunc, root_id : Int32) -> Int32? {
  if !@ir.hot_node_is_live(func, root_id) {
    return None
  }
  match @ir.hot_node_get(func, root_id).op {
    @ir.HotOp::Drop =>
      if @ir.hot_child_count(func, root_id) == 1 {
        Some(@ir.hot_child_get(func, root_id, 0))
      } else {
        None
      }
    _ => None
  }
}

///|
fn oc_nullable_ref_cast_early_source_local(
  func : @ir.HotFunc,
  node_id : Int32,
) -> Int32? {
  match @ir.hot_node_exact_instr(func, node_id) {
    Some(@lib.Instruction::RefCast(true, _, _)) => ()
    _ => return None
  }
  oc_early_refinement_source_local(func, node_id)
}

///|
fn oc_ref_as_non_null_early_source_local(
  func : @ir.HotFunc,
  node_id : Int32,
) -> Int32? {
  match @ir.hot_node_exact_instr(func, node_id) {
    Some(@lib.Instruction::RefAsNonNull) => ()
    _ => return None
  }
  oc_early_refinement_source_local(func, node_id)
}

///|
fn oc_separate_ref_as_cast_pair(
  func : @ir.HotFunc,
  first_root : Int32,
  second_root : Int32,
) -> (Int32, Int32, Int32)? {
  let first_child = match oc_single_dropped_child(func, first_root) {
    Some(child_id) => child_id
    None => return None
  }
  let second_child = match oc_single_dropped_child(func, second_root) {
    Some(child_id) => child_id
    None => return None
  }
  match
    (
      oc_nullable_ref_cast_early_source_local(func, first_child),
      oc_ref_as_non_null_early_source_local(func, second_child),
    ) {
    (Some(cast_local), Some(as_local)) =>
      if cast_local == as_local {
        return Some((cast_local, first_child, second_child))
      }
    _ => ()
  }
  match
    (
      oc_ref_as_non_null_early_source_local(func, first_child),
      oc_nullable_ref_cast_early_source_local(func, second_child),
    ) {
    (Some(as_local), Some(cast_local)) =>
      if as_local == cast_local {
        return Some((as_local, second_child, first_child))
      }
    _ => ()
  }
  None
}

///|
fn oc_build_nested_ref_as_cast_from_pair(
  func : @ir.HotFunc,
  source_local : Int32,
  cast_id : Int32,
  ref_as_id : Int32,
) -> Int32? {
  match @ir.hot_node_exact_instr(func, cast_id) {
    Some(@lib.Instruction::RefCast(true, _, _)) => ()
    _ => return None
  }
  match @ir.hot_node_exact_instr(func, ref_as_id) {
    Some(@lib.Instruction::RefAsNonNull) => ()
    _ => return None
  }
  let cast_ref = match oc_ref_type_from_node(func, cast_id) {
    Some(ref_type) => ref_type
    None => return None
  }
  let cast_node = @ir.hot_node_get(func, cast_id)
  let ref_as_node = @ir.hot_node_get(func, ref_as_id)
  let cloned_get = @ir.hot_build_local_get(func, source_local)
  let cloned_cast = @ir.hot_build_node(
    func,
    cast_node.op,
    cast_node.ty,
    imm0=cast_node.imm0,
    imm1=cast_node.imm1,
    children=[cloned_get],
  )
  let ref_as_ty = @ir.hot_type_intern_value(
    func,
    @lib.ValType::ref_type(oc_ref_type_as_non_null(cast_ref)),
  )
  Some(
    @ir.hot_build_node(
      func,
      ref_as_node.op,
      ref_as_ty,
      imm0=ref_as_node.imm0,
      imm1=ref_as_node.imm1,
      children=[cloned_cast],
    ),
  )
}

///|
fn oc_clone_refinement_replacing_source_get(
  func : @ir.HotFunc,
  node_id : Int32,
  source_local : Int32,
) -> Int32 {
  let node = @ir.hot_node_get(func, node_id)
  match node.op {
    @ir.HotOp::LocalGet =>
      if node.imm0 == source_local {
        return @ir.hot_build_local_get(func, source_local)
      }
    _ => ()
  }
  let children = oc_node_children(func, node_id)
  let cloned_children = Array::new(capacity=children.length())
  for child_id in children {
    cloned_children.push(
      oc_clone_refinement_replacing_source_get(func, child_id, source_local),
    )
  }
  @ir.hot_build_node(
    func,
    node.op,
    node.ty,
    imm0=node.imm0,
    imm1=node.imm1,
    children=cloned_children,
  )
}

///|
fn oc_duplicate_refinement_at_get(
  ctx : HotPassContext,
  func : @ir.HotFunc,
  get_id : Int32,
  cast_id : Int32,
) -> Bool {
  if !@ir.hot_node_is_live(func, get_id) || !@ir.hot_node_is_live(func, cast_id) {
    return false
  }
  let get_node = @ir.hot_node_get(func, get_id)
  match get_node.op {
    @ir.HotOp::LocalGet => ()
    _ => return false
  }
  let cloned_cast = if oc_is_nested_ref_as_nullable_cast(func, cast_id) {
    oc_clone_refinement_replacing_source_get(func, cast_id, get_node.imm0)
  } else {
    let cast_node = @ir.hot_node_get(func, cast_id)
    let cloned_get = @ir.hot_build_local_get(func, get_node.imm0)
    @ir.hot_build_node(
      func,
      cast_node.op,
      cast_node.ty,
      imm0=cast_node.imm0,
      imm1=cast_node.imm1,
      children=[cloned_get],
    )
  }
  let replacement = @ir.hot_node_get(func, cloned_cast)
  @ir.hot_delete_node(func, cloned_cast)
  pass_replace_node(ctx, func, get_id, replacement)
  true
}

///|
fn oc_duplicate_separate_ref_as_cast_at_get(
  ctx : HotPassContext,
  func : @ir.HotFunc,
  get_id : Int32,
  cast_id : Int32,
  ref_as_id : Int32,
) -> Bool {
  if !@ir.hot_node_is_live(func, get_id) {
    return false
  }
  let get_node = @ir.hot_node_get(func, get_id)
  match get_node.op {
    @ir.HotOp::LocalGet => ()
    _ => return false
  }
  let nested = match
    oc_build_nested_ref_as_cast_from_pair(
      func,
      get_node.imm0,
      cast_id,
      ref_as_id,
    ) {
    Some(node_id) => node_id
    None => return false
  }
  let replacement = @ir.hot_node_get(func, nested)
  @ir.hot_delete_node(func, nested)
  pass_replace_node(ctx, func, get_id, replacement)
  true
}

///|
fn oc_clear_pending_get(
  pending_gets : Array[Int32],
  pending_get_best_refinements : Array[Int32],
  local_id : Int32,
) -> Unit {
  pending_gets[local_id] = -1
  pending_get_best_refinements[local_id] = -1
}

///|
fn oc_clear_pending_gets(
  pending_gets : Array[Int32],
  pending_get_best_refinements : Array[Int32],
) -> Unit {
  for i = 0; i < pending_gets.length(); i = i + 1 {
    oc_clear_pending_get(pending_gets, pending_get_best_refinements, i)
  }
}

///|
fn oc_flush_pending_get(
  ctx : HotPassContext,
  func : @ir.HotFunc,
  pending_gets : Array[Int32],
  pending_get_best_refinements : Array[Int32],
  moved_refinalized_refinements : Array[Int32],
  local_id : Int32,
) -> Bool {
  let get_id = pending_gets[local_id]
  let best_refinement = pending_get_best_refinements[local_id]
  if get_id < 0 || best_refinement < 0 {
    return false
  }
  let changed = oc_duplicate_refinement_at_get(
    ctx, func, get_id, best_refinement,
  )
  if changed &&
    !oc_contains_local(moved_refinalized_refinements, best_refinement) {
    moved_refinalized_refinements.push(best_refinement)
  }
  changed
}

///|
fn oc_flush_pending_gets(
  ctx : HotPassContext,
  func : @ir.HotFunc,
  pending_gets : Array[Int32],
  pending_get_best_refinements : Array[Int32],
  moved_refinalized_refinements : Array[Int32],
) -> Bool {
  let mut changed = false
  for local_id = 0; local_id < pending_gets.length(); local_id = local_id + 1 {
    if oc_flush_pending_get(
        ctx, func, pending_gets, pending_get_best_refinements, moved_refinalized_refinements,
        local_id,
      ) {
      changed = true
    }
  }
  changed
}

///|
fn oc_clear_pending_refinements(
  pending_refinement_casts : Array[Int32],
  pending_refinement_gets : Array[Int32],
) -> Unit {
  for i = 0; i < pending_refinement_casts.length(); i = i + 1 {
    pending_refinement_casts[i] = -1
    pending_refinement_gets[i] = -1
  }
}

///|
fn oc_clear_later_reuse(
  best_casts : Array[Int32],
  fresh_locals : Array[Int32],
  active_best_mask : Array[Bool],
  active_best_locals : Array[Int32],
  fresh_by_cast : Array[Int32],
  fresh_cast_ids : Array[Int32],
) -> Unit {
  for local_id in active_best_locals {
    best_casts[local_id] = -1
    fresh_locals[local_id] = -1
    active_best_mask[local_id] = false
  }
  active_best_locals.clear()
  for cast_id in fresh_cast_ids {
    fresh_by_cast[cast_id] = -1
  }
  fresh_cast_ids.clear()
}

///|
// -2 marks an inner-frame cast without an allocated carrier.
// The site mark can remain across barriers; it does not retain a reuse fact.
fn oc_mark_scope_limited_cast(
  fresh_by_cast : Array[Int32],
  cast_id : Int32,
) -> Unit {
  if cast_id >= 0 &&
    cast_id < fresh_by_cast.length() &&
    fresh_by_cast[cast_id] == -1 {
    fresh_by_cast[cast_id] = -2
  }
}

///|
fn oc_find_fresh_local_for_cast(
  fresh_by_cast : Array[Int32],
  cast_id : Int32,
) -> Int32? {
  if cast_id >= 0 &&
    cast_id < fresh_by_cast.length() &&
    fresh_by_cast[cast_id] >= 0 {
    return Some(fresh_by_cast[cast_id])
  }
  None
}

///|
fn oc_i32_nontrapping_pure_tree(
  func : @ir.HotFunc,
  node_id : Int32,
  fuel : Int32,
) -> Bool {
  if fuel <= 0 || !@ir.hot_node_is_live(func, node_id) {
    return false
  }
  match @ir.hot_node_get(func, node_id).op {
    @ir.HotOp::Const | @ir.HotOp::LocalGet => true
    @ir.HotOp::Unary =>
      if @ir.hot_child_count(func, node_id) == 1 {
        match @ir.hot_node_exact_instr(func, node_id) {
          Some(@lib.I32Eqz) => {
            let child_id = @ir.hot_child_get(func, node_id, 0)
            oc_i32_nontrapping_pure_tree(func, child_id, fuel - 1)
          }
          _ => false
        }
      } else {
        false
      }
    @ir.HotOp::Binary =>
      if @ir.hot_child_count(func, node_id) == 2 {
        match @ir.hot_node_exact_instr(func, node_id) {
          Some(@lib.I32Add)
          | Some(@lib.I32Sub)
          | Some(@lib.I32Mul)
          | Some(@lib.I32And)
          | Some(@lib.I32Or)
          | Some(@lib.I32Xor)
          | Some(@lib.I32Shl)
          | Some(@lib.I32ShrS)
          | Some(@lib.I32ShrU)
          | Some(@lib.I32Rotl)
          | Some(@lib.I32Rotr) => {
            let lhs_id = @ir.hot_child_get(func, node_id, 0)
            let rhs_id = @ir.hot_child_get(func, node_id, 1)
            oc_i32_nontrapping_pure_tree(func, lhs_id, fuel - 1) &&
            oc_i32_nontrapping_pure_tree(func, rhs_id, fuel - 1)
          }
          _ => false
        }
      } else {
        false
      }
    _ => false
  }
}

///|
fn oc_dropped_nontrapping_pure_root(
  func : @ir.HotFunc,
  root_id : Int32,
) -> Bool {
  if !@ir.hot_node_is_live(func, root_id) {
    return false
  }
  match @ir.hot_node_get(func, root_id).op {
    @ir.HotOp::Nop => true
    @ir.HotOp::Drop =>
      if @ir.hot_child_count(func, root_id) == 1 {
        let child_id = @ir.hot_child_get(func, root_id, 0)
        oc_i32_nontrapping_pure_tree(func, child_id, 64)
      } else {
        false
      }
    _ => false
  }
}

///|
fn oc_early_motion_scan_region(
  ctx : HotPassContext,
  func : @ir.HotFunc,
  module_ctx : @ir.HotModuleContext,
  local_count : Int32,
  pending_gets : Array[Int32],
  pending_get_best_refinements : Array[Int32],
  pending_refinement_casts : Array[Int32],
  pending_refinement_gets : Array[Int32],
  seen_refinements : Array[Bool],
  moved_refinalized_refinements : Array[Int32],
  region : @ir.HotRegionRef,
) -> Bool {
  let mut changed = false
  let root_count = @ir.hot_region_root_count(func, region)
  for root_idx = 0; root_idx < root_count; root_idx = root_idx + 1 {
    let root_id = @ir.hot_region_get(func, region, root_idx)
    if root_idx + 1 < root_count {
      let next_root = @ir.hot_region_get(func, region, root_idx + 1)
      match oc_separate_ref_as_cast_pair(func, root_id, next_root) {
        Some((local_id, cast_id, ref_as_id)) =>
          if local_id >= 0 &&
            local_id < local_count &&
            !seen_refinements[local_id] &&
            pending_gets[local_id] >= 0 {
            if oc_duplicate_separate_ref_as_cast_at_get(
                ctx,
                func,
                pending_gets[local_id],
                cast_id,
                ref_as_id,
              ) {
              changed = true
              seen_refinements[local_id] = true
              if !oc_contains_local(moved_refinalized_refinements, cast_id) {
                moved_refinalized_refinements.push(cast_id)
              }
              oc_clear_pending_gets(pending_gets, pending_get_best_refinements)
              continue
            }
          }
        None => ()
      }
    }
    match oc_direct_dropped_refinement(func, root_id) {
      Some((local_id, cast_id)) => {
        if local_id >= 0 && local_id < local_count {
          if pending_gets[local_id] >= 0 {
            let pending_best = pending_get_best_refinements[local_id]
            if !seen_refinements[local_id] || pending_best >= 0 {
              if pending_best < 0 ||
                oc_cast_is_more_refined(module_ctx, func, cast_id, pending_best) {
                pending_get_best_refinements[local_id] = cast_id
              } else if oc_existing_fresh_can_feed_refinement_source(
                  func, pending_best, cast_id,
                ) &&
                !oc_contains_local(moved_refinalized_refinements, cast_id) {
                moved_refinalized_refinements.push(cast_id)
              }
            }
          }
          let pending_cast = pending_refinement_casts[local_id]
          if pending_cast >= 0 &&
            pending_refinement_gets[local_id] >= 0 &&
            oc_cast_is_more_refined(module_ctx, func, cast_id, pending_cast) {
            if oc_duplicate_refinement_at_get(
                ctx,
                func,
                pending_refinement_gets[local_id],
                cast_id,
              ) {
              changed = true
              if !oc_contains_local(moved_refinalized_refinements, cast_id) {
                moved_refinalized_refinements.push(cast_id)
              }
              if !oc_contains_local(moved_refinalized_refinements, pending_cast) {
                moved_refinalized_refinements.push(pending_cast)
              }
            }
          } else if pending_cast >= 0 &&
            pending_refinement_gets[local_id] >= 0 &&
            oc_cast_is_more_refined(module_ctx, func, pending_cast, cast_id) {
            match oc_direct_refinement_source_get(func, cast_id) {
              Some((_, source_get)) =>
                if oc_duplicate_refinement_at_get(
                    ctx, func, source_get, pending_cast,
                  ) {
                  changed = true
                  moved_refinalized_refinements.push(cast_id)
                }
              None => ()
            }
          }
          seen_refinements[local_id] = true
        }
        oc_clear_pending_refinements(
          pending_refinement_casts, pending_refinement_gets,
        )
        match oc_direct_refinement_source_get(func, cast_id) {
          Some((source_local, source_get)) =>
            if source_local >= 0 && source_local < local_count {
              pending_refinement_casts[source_local] = cast_id
              pending_refinement_gets[source_local] = source_get
            }
          None => ()
        }
        continue
      }
      None => ()
    }
    match oc_dropped_local_get(func, root_id) {
      Some((local_id, get_id)) => {
        if local_id >= 0 && local_id < local_count {
          if pending_gets[local_id] < 0 {
            pending_gets[local_id] = get_id
            pending_get_best_refinements[local_id] = -1
          }
        }
        continue
      }
      None => ()
    }
    match oc_nontrapping_pure_local_set(func, root_id) {
      Some(local_id) => {
        if local_id >= 0 && local_id < local_count {
          if oc_flush_pending_get(
              ctx, func, pending_gets, pending_get_best_refinements, moved_refinalized_refinements,
              local_id,
            ) {
            changed = true
          }
          oc_clear_pending_get(
            pending_gets, pending_get_best_refinements, local_id,
          )
          pending_refinement_casts[local_id] = -1
          pending_refinement_gets[local_id] = -1
          seen_refinements[local_id] = false
        }
        continue
      }
      None => ()
    }
    match oc_dropped_nontrapping_pure_local_tee(func, root_id) {
      Some(local_id) => {
        if local_id >= 0 && local_id < local_count {
          if oc_flush_pending_get(
              ctx, func, pending_gets, pending_get_best_refinements, moved_refinalized_refinements,
              local_id,
            ) {
            changed = true
          }
          oc_clear_pending_get(
            pending_gets, pending_get_best_refinements, local_id,
          )
          pending_refinement_casts[local_id] = -1
          pending_refinement_gets[local_id] = -1
          seen_refinements[local_id] = false
        }
        continue
      }
      None => ()
    }
    if oc_dropped_nontrapping_pure_root(func, root_id) {
      continue
    }
    if oc_flush_pending_gets(
        ctx, func, pending_gets, pending_get_best_refinements, moved_refinalized_refinements,
      ) {
      changed = true
    }
    oc_clear_pending_gets(pending_gets, pending_get_best_refinements)
    oc_clear_pending_refinements(
      pending_refinement_casts, pending_refinement_gets,
    )
    for local_id = 0; local_id < local_count; local_id = local_id + 1 {
      seen_refinements[local_id] = false
    }
  }
  if oc_flush_pending_gets(
      ctx, func, pending_gets, pending_get_best_refinements, moved_refinalized_refinements,
    ) {
    changed = true
  }
  changed
}

///|
fn oc_early_motion_scan_fresh_region(
  ctx : HotPassContext,
  func : @ir.HotFunc,
  module_ctx : @ir.HotModuleContext,
  moved_refinalized_refinements : Array[Int32],
  region : @ir.HotRegionRef,
) -> Bool {
  let local_count = @ir.hot_local_count(func)
  let pending_gets = Array::make(local_count, -1)
  let pending_get_best_refinements = Array::make(local_count, -1)
  let pending_refinement_casts = Array::make(local_count, -1)
  let pending_refinement_gets = Array::make(local_count, -1)
  let seen_refinements = Array::make(local_count, false)
  oc_early_motion_scan_region(
    ctx, func, module_ctx, local_count, pending_gets, pending_get_best_refinements,
    pending_refinement_casts, pending_refinement_gets, seen_refinements, moved_refinalized_refinements,
    region,
  )
}

///|
fn oc_early_motion_scan_nested_regions(
  ctx : HotPassContext,
  func : @ir.HotFunc,
  module_ctx : @ir.HotModuleContext,
  moved_refinalized_refinements : Array[Int32],
  region : @ir.HotRegionRef,
) -> Bool {
  let mut changed = oc_early_motion_scan_fresh_region(
    ctx, func, module_ctx, moved_refinalized_refinements, region,
  )
  let root_count = @ir.hot_region_root_count(func, region)
  for idx = 0; idx < root_count; idx = idx + 1 {
    let root_id = @ir.hot_region_get(func, region, idx)
    if root_id < 0 || !@ir.hot_node_is_live(func, root_id) {
      continue
    }
    match @ir.hot_node_get(func, root_id).op {
      @ir.HotOp::Block | @ir.HotOp::Loop =>
        if oc_early_motion_scan_nested_regions(
            ctx,
            func,
            module_ctx,
            moved_refinalized_refinements,
            @ir.hot_region_body_ref(func, root_id),
          ) {
          changed = true
        }
      @ir.HotOp::If => {
        if oc_early_motion_scan_nested_regions(
            ctx,
            func,
            module_ctx,
            moved_refinalized_refinements,
            @ir.hot_region_then_ref(func, root_id),
          ) {
          changed = true
        }
        match @ir.hot_region_else_ref(func, root_id) {
          Some(else_ref) =>
            if oc_early_motion_scan_nested_regions(
                ctx, func, module_ctx, moved_refinalized_refinements, else_ref,
              ) {
              changed = true
            }
          None => ()
        }
      }
      @ir.HotOp::Try => {
        if oc_early_motion_scan_nested_regions(
            ctx,
            func,
            module_ctx,
            moved_refinalized_refinements,
            @ir.hot_region_body_ref(func, root_id),
          ) {
          changed = true
        }
        match @ir.hot_region_catch_ref(func, root_id) {
          Some(catch_ref) =>
            if oc_early_motion_scan_nested_regions(
                ctx, func, module_ctx, moved_refinalized_refinements, catch_ref,
              ) {
              changed = true
            }
          None => ()
        }
      }
      @ir.HotOp::TryTable => {
        if oc_early_motion_scan_nested_regions(
            ctx,
            func,
            module_ctx,
            moved_refinalized_refinements,
            @ir.hot_region_body_ref(func, root_id),
          ) {
          changed = true
        }
        if oc_early_motion_scan_nested_regions(
            ctx,
            func,
            module_ctx,
            moved_refinalized_refinements,
            @ir.hot_region_catch_list_ref(func, root_id),
          ) {
          changed = true
        }
      }
      _ => ()
    }
  }
  changed
}

///|
fn oc_early_motion_run(
  ctx : HotPassContext,
  func : @ir.HotFunc,
  module_ctx : @ir.HotModuleContext,
  moved_refinalized_refinements : Array[Int32],
) -> Bool {
  oc_early_motion_scan_nested_regions(
    ctx,
    func,
    module_ctx,
    moved_refinalized_refinements,
    @ir.HotRegionRef::root(),
  )
}

///|
// A fixed visit budget keeps the additional proof independent of large
// structured bodies. Nested control, calls and continuation edges stay closed.
fn oc_flat_fallthrough_node_cost(
  func : @ir.HotFunc,
  node_id : Int32,
  budget : Int32,
) -> Int32 {
  if budget <= 0 || !@ir.hot_node_is_live(func, node_id) {
    return -1
  }
  let node = @ir.hot_node_get(func, node_id)
  if oc_op_is_linear_block_barrier(node.op) ||
    (
      node.flags &
      (@ir.HOT_FLAG_CALL | @ir.HOT_FLAG_BRANCH | @ir.HOT_FLAG_TERMINATOR)
    ) !=
    0U {
    return -1
  }
  let mut cost = 1
  for slot = 0; slot < node.child_count; slot = slot + 1 {
    let child_cost = oc_flat_fallthrough_node_cost(
      func,
      @ir.hot_child_get(func, node_id, slot),
      budget - cost,
    )
    if child_cost < 0 {
      return -1
    }
    cost += child_cost
  }
  cost
}

///|
fn oc_flat_fallthrough_region_cost(
  func : @ir.HotFunc,
  region : @ir.HotRegionRef,
  budget : Int32,
) -> Int32 {
  let mut cost = 0
  for idx = 0; idx < @ir.hot_region_root_count(func, region); idx = idx + 1 {
    let root_cost = oc_flat_fallthrough_node_cost(
      func,
      @ir.hot_region_get(func, region, idx),
      budget - cost,
    )
    if root_cost < 0 {
      return -1
    }
    cost += root_cost
  }
  cost
}

///|
fn oc_if_has_flat_fallthrough(func : @ir.HotFunc, node_id : Int32) -> Bool {
  let node = @ir.hot_node_get(func, node_id)
  if !(node.op is @ir.HotOp::If) {
    return false
  }
  let mut budget = 256
  // Include the condition and typed entry operands without treating the arm
  // region containers as nested control frames.
  for idx = 0; idx < pass_value_operand_count(func, node_id); idx = idx + 1 {
    let cost = oc_flat_fallthrough_node_cost(
      func,
      @ir.hot_child_get(func, node_id, pass_value_operand_slot(node, idx)),
      budget,
    )
    if cost < 0 {
      return false
    }
    budget -= cost
  }
  let then_cost = oc_flat_fallthrough_region_cost(
    func,
    @ir.hot_region_then_ref(func, node_id),
    budget,
  )
  if then_cost < 0 {
    return false
  }
  budget -= then_cost
  match @ir.hot_region_else_ref(func, node_id) {
    Some(region) => oc_flat_fallthrough_region_cost(func, region, budget) >= 0
    None => true
  }
}

///|
fn oc_later_reuse_scan_region(
  ctx : HotPassContext,
  func : @ir.HotFunc,
  module_ctx : @ir.HotModuleContext,
  local_count : Int32,
  best_casts : Array[Int32],
  fresh_locals : Array[Int32],
  moved_refinalized_refinements : Array[Int32],
  local_get_counts : Array[Int32],
  touched_get_locals : Array[Int32],
  retarget_mask : Array[Bool],
  retarget_locals : Array[Int32],
  write_mask : Array[Bool],
  writes : Array[Int32],
  refinements : Array[(Int32, Int32)],
  refinement_aliases : Array[(Int32, Int32)],
  refinement_heads : Array[Int32],
  refinement_next : Array[Int32],
  refinement_head_touched : Array[Int32],
  active_best_mask : Array[Bool],
  active_best_locals : Array[Int32],
  fresh_by_cast : Array[Int32],
  fresh_cast_ids : Array[Int32],
  region : @ir.HotRegionRef,
  inside_control_frame : Bool,
) -> Bool {
  let mut changed = false
  let mut previous_flat_if = false
  let root_count = @ir.hot_region_root_count(func, region)
  for root_idx = 0; root_idx < root_count; root_idx = root_idx + 1 {
    let root_id = @ir.hot_region_get(func, region, root_idx)
    let follows_flat_if = previous_flat_if
    previous_flat_if = false
    match oc_plain_fallthrough_block_for_root(func, root_id) {
      Some(block_id) =>
        if oc_block_is_plain_fallthrough(func, block_id) {
          if oc_later_reuse_scan_region(
              ctx,
              func,
              module_ctx,
              local_count,
              best_casts,
              fresh_locals,
              moved_refinalized_refinements,
              local_get_counts,
              touched_get_locals,
              retarget_mask,
              retarget_locals,
              write_mask,
              writes,
              refinements,
              refinement_aliases,
              refinement_heads,
              refinement_next,
              refinement_head_touched,
              active_best_mask,
              active_best_locals,
              fresh_by_cast,
              fresh_cast_ids,
              @ir.hot_region_body_ref(func, block_id),
              true,
            ) {
            changed = true
          }
          continue
        }
      None => ()
    }
    for local_id in writes {
      write_mask[local_id] = false
    }
    writes.clear()
    oc_collect_written_locals(func, root_id, writes, write_mask)
    if !inside_control_frame &&
      !active_best_locals.is_empty() &&
      oc_if_has_flat_fallthrough(func, root_id) {
      for local_id in writes {
        best_casts[local_id] = -1
        fresh_locals[local_id] = -1
      }
      // Preserve only incoming facts. Do not rewrite arm reads or publish
      // refinements that execute on just one branch.
      previous_flat_if = true
      continue
    }
    if follows_flat_if {
      match oc_single_dropped_child(func, root_id) {
        Some(cast_id) =>
          match @ir.hot_node_exact_instr(func, cast_id) {
            Some(@lib.RefCast(_, _, _)) =>
              match oc_direct_refinement_source_get(func, cast_id) {
                Some((local_id, _)) if local_id >= 0 && local_id < local_count => {
                  let best_cast = best_casts[local_id]
                  if best_cast >= 0 &&
                    !write_mask[local_id] &&
                    oc_existing_fresh_can_feed_refinement_source(
                      func, best_cast, cast_id,
                    ) {
                    // The preceding cast already proved this same unchanged
                    // value. Change only the discarded root occurrence so a
                    // shared cast node keeps its earlier trap. No carrier is needed.
                    @ir.hot_root_set(func, root_idx, @ir.hot_build_nop(func))
                    pass_mark_mutated(ctx, func)
                    changed = true
                    continue
                  }
                }
                _ => ()
              }
            _ => ()
          }
        None => ()
      }
    }
    for local_id in refinement_head_touched {
      refinement_heads[local_id] = -1
    }
    refinement_head_touched.clear()
    refinements.clear()
    refinement_next.clear()
    oc_collect_refinements(func, root_id, refinements)
    for idx = 0; idx < refinements.length(); idx = idx + 1 {
      let local_id = refinements[idx].0
      if local_id >= 0 && local_id < local_count {
        if refinement_heads[local_id] < 0 {
          refinement_head_touched.push(local_id)
        }
        refinement_next.push(refinement_heads[local_id])
        refinement_heads[local_id] = idx
      } else {
        refinement_next.push(-1)
      }
    }
    refinement_aliases.clear()
    oc_collect_refinement_tee_source_aliases(func, root_id, refinement_aliases)
    for local_id in touched_get_locals {
      local_get_counts[local_id] = 0
    }
    touched_get_locals.clear()
    oc_collect_local_get_counts(
      func, root_id, local_get_counts, touched_get_locals,
    )
    for local_id in retarget_locals {
      retarget_mask[local_id] = false
    }
    retarget_locals.clear()
    let has_linear_barrier = oc_node_has_linear_block_barrier(func, root_id)
    if has_linear_barrier {
      oc_clear_later_reuse(
        best_casts, fresh_locals, active_best_mask, active_best_locals, fresh_by_cast,
        fresh_cast_ids,
      )
    } else {
      for local_id in touched_get_locals {
        let best_cast = best_casts[local_id]
        if best_cast >= 0 &&
          !write_mask[local_id] &&
          !oc_indexed_refinement_blocks_retarget(
            module_ctx,
            func,
            refinements,
            refinement_heads,
            refinement_next,
            local_id,
            best_cast,
            fresh_locals[local_id] >= 0,
            moved_refinalized_refinements,
          ) {
          let fresh_local = if fresh_locals[local_id] >= 0 {
            fresh_locals[local_id]
          } else {
            match oc_find_fresh_local_for_cast(fresh_by_cast, best_cast) {
              Some(fresh) => {
                fresh_locals[local_id] = fresh
                fresh
              }
              None => {
                let ref_type = match oc_ref_type_from_node(func, best_cast) {
                  Some(ref_type) => ref_type
                  None => continue
                }
                // An inner-frame write cannot initialize a parent-frame local.
                let can_escape_frame = best_cast >= fresh_by_cast.length() ||
                  fresh_by_cast[best_cast] == -2
                let fresh_ref_type = @lib.RefType::new(
                  ref_type.is_nullable() || can_escape_frame,
                  ref_type.get_heap_type(),
                  exact=ref_type.is_exact(),
                )
                let fresh = @ir.hot_append_body_local(
                  func,
                  @lib.ValType::ref_type(fresh_ref_type),
                )
                fresh_locals[local_id] = fresh
                ignore(oc_wrap_refinement_with_tee(ctx, func, best_cast, fresh))
                if best_cast >= 0 && best_cast < fresh_by_cast.length() {
                  fresh_by_cast[best_cast] = fresh
                  fresh_cast_ids.push(best_cast)
                }
                fresh
              }
            }
          }
          ignore(fresh_local)
          retarget_mask[local_id] = true
          retarget_locals.push(local_id)
        }
      }
      if !retarget_locals.is_empty() &&
        oc_retarget_local_gets_from_map(
          ctx, func, root_id, retarget_mask, fresh_locals, best_casts,
        ) >
        0 {
        changed = true
        for local_id in retarget_locals {
          if oc_refinalize_marked_ref_cast_to_best(
              ctx,
              func,
              module_ctx,
              root_id,
              best_casts[local_id],
              moved_refinalized_refinements,
            ) {
            changed = true
          }
        }
      }
    }
    for local_id in writes {
      if local_id >= 0 && local_id < local_count {
        best_casts[local_id] = -1
        fresh_locals[local_id] = -1
      }
    }
    for refinement in refinements {
      let (local_id, cast_id) = refinement
      if local_id >= 0 && local_id < local_count {
        if !active_best_mask[local_id] {
          active_best_mask[local_id] = true
          active_best_locals.push(local_id)
        }
        if best_casts[local_id] < 0 ||
          oc_cast_is_more_refined(
            module_ctx,
            func,
            cast_id,
            best_casts[local_id],
          ) {
          best_casts[local_id] = cast_id
          fresh_locals[local_id] = -1
          if inside_control_frame {
            oc_mark_scope_limited_cast(fresh_by_cast, cast_id)
          }
        }
      }
    }
    for refinement in refinement_aliases {
      let (local_id, cast_id) = refinement
      if local_id >= 0 && local_id < local_count {
        if !active_best_mask[local_id] {
          active_best_mask[local_id] = true
          active_best_locals.push(local_id)
        }
        if best_casts[local_id] < 0 ||
          oc_cast_is_more_refined(
            module_ctx,
            func,
            cast_id,
            best_casts[local_id],
          ) {
          best_casts[local_id] = cast_id
          fresh_locals[local_id] = -1
          if inside_control_frame {
            oc_mark_scope_limited_cast(fresh_by_cast, cast_id)
          }
        }
      }
    }
  }
  changed
}

///|
fn oc_later_reuse_run(
  ctx : HotPassContext,
  func : @ir.HotFunc,
  module_ctx : @ir.HotModuleContext,
  moved_refinalized_refinements : Array[Int32],
) -> Bool {
  let local_count = @ir.hot_local_count(func)
  let best_casts = Array::make(local_count, -1)
  let fresh_locals = Array::make(local_count, -1)
  let local_get_counts = Array::make(local_count, 0)
  let touched_get_locals : Array[Int32] = []
  let retarget_mask = Array::make(local_count, false)
  let retarget_locals : Array[Int32] = []
  let write_mask = Array::make(local_count, false)
  let writes : Array[Int32] = []
  let refinements : Array[(Int32, Int32)] = []
  let refinement_aliases : Array[(Int32, Int32)] = []
  let refinement_heads = Array::make(local_count, -1)
  let refinement_next : Array[Int32] = []
  let refinement_head_touched : Array[Int32] = []
  let active_best_mask = Array::make(local_count, false)
  let active_best_locals : Array[Int32] = []
  let fresh_by_cast = Array::make(@ir.hot_node_count(func), -1)
  let fresh_cast_ids : Array[Int32] = []
  oc_later_reuse_scan_region(
    ctx,
    func,
    module_ctx,
    local_count,
    best_casts,
    fresh_locals,
    moved_refinalized_refinements,
    local_get_counts,
    touched_get_locals,
    retarget_mask,
    retarget_locals,
    write_mask,
    writes,
    refinements,
    refinement_aliases,
    refinement_heads,
    refinement_next,
    refinement_head_touched,
    active_best_mask,
    active_best_locals,
    fresh_by_cast,
    fresh_cast_ids,
    @ir.HotRegionRef::root(),
    false,
  )
}

///|
fn oc_rewrite_node(
  ctx : HotPassContext,
  func : @ir.HotFunc,
  module_ctx : @ir.HotModuleContext,
  node_id : Int32,
) -> Bool {
  if !@ir.hot_node_is_live(func, node_id) {
    return false
  }
  match @ir.hot_node_exact_instr(func, node_id) {
    Some(@lib.Instruction::RefCast(nullable, exact, heap_type)) => {
      if @ir.hot_child_count(func, node_id) != 1 {
        return false
      }
      let child_id = @ir.hot_child_get(func, node_id, 0)
      match oc_ref_type_from_node(func, child_id) {
        Some(source_ref) => {
          let target_ref = oc_target_ref_type(nullable, exact, heap_type)
          if oc_ref_always_matches(module_ctx, source_ref, target_ref) {
            oc_replace_with_child(ctx, func, node_id)
            return true
          }
        }
        None => ()
      }
      false
    }
    Some(@lib.Instruction::RefCastDescEq(nullable, exact, heap_type)) => {
      let target_ref = oc_target_ref_type(nullable, exact, heap_type)
      if @ir.hot_child_count(func, node_id) == 2 {
        return oc_replace_nullable_known_null_desc_eq(
          ctx, func, node_id, target_ref,
        )
      }
      if @ir.hot_child_count(func, node_id) != 1 {
        return false
      }
      let child_id = @ir.hot_child_get(func, node_id, 0)
      match oc_ref_type_from_node(func, child_id) {
        Some(source_ref) =>
          if oc_ref_always_matches(module_ctx, source_ref, target_ref) {
            oc_replace_with_child(ctx, func, node_id)
            return true
          }
        None => ()
      }
      false
    }
    Some(@lib.Instruction::RefTest(nullable, false, heap_type))
    | Some(@lib.Instruction::RefTestDesc(nullable, heap_type)) => {
      if @ir.hot_child_count(func, node_id) != 1 {
        return false
      }
      let child_id = @ir.hot_child_get(func, node_id, 0)
      match oc_ref_type_from_node(func, child_id) {
        Some(source_ref) => {
          let target_ref = oc_target_ref_type(nullable, false, heap_type)
          if oc_ref_always_matches(module_ctx, source_ref, target_ref) {
            oc_replace_with_const_i32(ctx, func, node_id, 1)
            return true
          }
          if oc_ref_never_matches(module_ctx, source_ref, target_ref) {
            oc_replace_with_const_i32(ctx, func, node_id, 0)
            return true
          }
        }
        None => ()
      }
      false
    }
    Some(
      @lib.Instruction::BrOnCast(
        _,
        @lib.CastOp(_, nullable, _, exact),
        _,
        heap_type
      )
    ) => {
      if @ir.hot_child_count(func, node_id) == 0 {
        return false
      }
      let child_id = @ir.hot_child_get(
        func,
        node_id,
        @ir.hot_child_count(func, node_id) - 1,
      )
      match oc_ref_type_from_node(func, child_id) {
        Some(source_ref) => {
          let target_ref = oc_target_ref_type(nullable, exact, heap_type)
          if oc_ref_always_matches(module_ctx, source_ref, target_ref) {
            oc_replace_with_unconditional_br(ctx, func, node_id)
            return true
          }
          if oc_ref_never_matches(module_ctx, source_ref, target_ref) &&
            @ir.hot_child_count(func, node_id) == 1 {
            oc_replace_with_child(ctx, func, node_id)
            return true
          }
        }
        None => ()
      }
      false
    }
    Some(
      @lib.Instruction::BrOnCastFail(
        _,
        @lib.CastOp(_, nullable, _, exact),
        _,
        heap_type
      )
    ) => {
      if @ir.hot_child_count(func, node_id) != 1 {
        return false
      }
      let child_id = @ir.hot_child_get(func, node_id, 0)
      match oc_ref_type_from_node(func, child_id) {
        Some(source_ref) => {
          let target_ref = oc_target_ref_type(nullable, exact, heap_type)
          if oc_ref_always_matches(module_ctx, source_ref, target_ref) {
            oc_replace_with_child(ctx, func, node_id)
            return true
          }
          if oc_ref_never_matches(module_ctx, source_ref, target_ref) {
            oc_replace_with_unconditional_br(ctx, func, node_id)
            return true
          }
        }
        None => ()
      }
      false
    }
    _ => false
  }
}

///|
fn oc_static_fold_run(
  ctx : HotPassContext,
  func : @ir.HotFunc,
  module_ctx : @ir.HotModuleContext,
) -> Bool {
  let mut changed = false
  let node_count = func.nodes.length()
  for node_id = 0; node_id < node_count; node_id = node_id + 1 {
    if oc_rewrite_node(ctx, func, module_ctx, node_id) {
      changed = true
    }
  }
  changed
}

///|
pub fn optimize_casts_run(
  ctx : HotPassContext,
  func : @ir.HotFunc,
) -> HotPassResult {
  let module_ctx = match ctx.module_ctx {
    Some(module_ctx) => module_ctx
    None => return HotPassResult::unchanged()
  }
  let mut changed = false
  let moved_refinalized_refinements : Array[Int32] = []
  if oc_static_fold_run(ctx, func, module_ctx) {
    changed = true
  }
  if oc_early_motion_run(ctx, func, module_ctx, moved_refinalized_refinements) {
    changed = true
    if oc_static_fold_run(ctx, func, module_ctx) {
      changed = true
    }
  }
  if oc_later_reuse_run(ctx, func, module_ctx, moved_refinalized_refinements) {
    changed = true
  }
  if changed {
    HotPassResult::changed()
  } else {
    HotPassResult::unchanged()
  }
}