// Licensing scope: see ../../LICENSE and this directory's LICENSE and NOTICE.
// 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.

///|
priv struct SimplifyLocalsGetCounts {
  mut owner : @ir.HotFunc?
  mut revision : Int32
  mut local_count : Int32
  mut counts : Array[Int32]
}

///|
fn SimplifyLocalsGetCounts::new() -> SimplifyLocalsGetCounts {
  { owner: None, revision: -1, local_count: -1, counts: [], }
}

///|
fn simplify_locals_new_get_count_cache(
  func : @ir.HotFunc,
) -> SimplifyLocalsGetCounts? {
  let nodes = @ir.hot_node_count(func)
  if nodes >= 32 && nodes / 4 >= @ir.hot_local_count(func) {
    Some(SimplifyLocalsGetCounts::new())
  } else {
    None
  }
}

///|
fn simplify_locals_counts_for_cycle(
  func : @ir.HotFunc,
  cache : SimplifyLocalsGetCounts?,
  full_scans~ : Array[Int32]? = None,
) -> Array[Int32] {
  match cache {
    Some(cache) => cache.snapshot(func, full_scans~)
    None => {
      match full_scans {
        Some(scans) => scans[0] += 1
        None => ()
      }
      simplify_locals_count_local_gets(func)
    }
  }
}

///|
fn SimplifyLocalsGetCounts::snapshot(
  self : SimplifyLocalsGetCounts,
  func : @ir.HotFunc,
  full_scans~ : Array[Int32]? = None,
) -> Array[Int32] {
  let revision = @ir.hot_revision_current(func)
  let local_count = @ir.hot_local_count(func)
  match self.owner {
    Some(owner) if physical_equal(owner, func) &&
      self.revision == revision &&
      self.local_count == local_count => return self.counts.copy()
    _ => ()
  }
  match full_scans {
    Some(scans) => scans[0] += 1
    None => ()
  }
  let counts = simplify_locals_count_local_gets(func)
  self.owner = Some(func)
  self.revision = revision
  self.local_count = local_count
  self.counts = counts
  // Both cleanup consumers may adjust counts. Keep the stored fact read-only.
  counts.copy()
}