///|
fn temp_pool_contains(pool : Array[Int], idx : Int) -> Bool {
  for value in pool {
    if value == idx {
      return true
    }
  }
  false
}

///|
fn temp_pool_is_used(used : Array[Bool], idx : Int) -> Bool {
  idx >= 0 && idx < used.length() && used[idx]
}

///|
fn temp_pool_push_available(
  pool : Array[Int],
  used : Array[Bool],
  idx : Int,
) -> Unit {
  if !temp_pool_is_used(used, idx) && !temp_pool_contains(pool, idx) {
    pool.push(idx)
  }
}

///|
pub fn plan_temp_register_pool(
  used : Array[Bool],
  scratch : Array[Int],
  nonpreferred : Array[Int],
  preferred : Array[Int],
) -> Array[Int] {
  let pool : Array[Int] = []
  for idx in scratch {
    pool.push(idx)
  }
  let candidates : Array[Int] = []
  for idx in nonpreferred {
    candidates.push(idx)
  }
  for idx in preferred {
    candidates.push(idx)
  }
  for idx in candidates {
    if idx >= 8 {
      temp_pool_push_available(pool, used, idx)
    }
  }
  for idx in candidates {
    if idx < 8 {
      temp_pool_push_available(pool, used, idx)
    }
  }
  pool
}

///|
pub(all) struct TempRegisterChoice {
  preg : PhysicalReg
  next_cursor : Int
  save_slot : Int?
  next_spill_slot : Int
} derive(Eq, Debug)

///|
fn temp_id_in_list(values : Array[Int], value : Int) -> Bool {
  for item in values {
    if item == value {
      return true
    }
  }
  false
}

///|
pub fn choose_temp_register(
  class : RegClass,
  used_ids : Array[Int],
  temp_pool : Array[Int],
  fallback_candidates : Array[Int],
  reserved_ids : Array[Int],
  need_preserve : Bool,
  cursor : Int,
  next_spill_slot : Int,
) -> TempRegisterChoice {
  for i in 0..