///|
/// The allocator's internal phases, in the order they run.
///
/// Reported through `RegallocConfig::observer` so a caller that owns a clock
/// can attribute compile time per phase. This module stays clock-free: it
/// only says which phase it is entering (ISS-371).
pub(all) enum RegallocPhase {
  LiveRanges
  SegmentConstruction
  BundleFormation
  BundleAllocation
  HomeAssignment
  OperandAssignment
  EdgeTransfers
  EditResolution
  Verification
} derive(Eq, Debug)

///|
pub impl Show for RegallocPhase with fn output(self, logger) {
  logger.write_string(
    match self {
      LiveRanges => "live_ranges"
      SegmentConstruction => "segment_construction"
      BundleFormation => "bundle_formation"
      BundleAllocation => "bundle_allocation"
      HomeAssignment => "home_assignment"
      OperandAssignment => "operand_assignment"
      EdgeTransfers => "edge_transfers"
      EditResolution => "edit_resolution"
      Verification => "verification"
    },
  )
}

///|
pub struct RegallocConfig {
  verify : Bool
  // Called as each phase begins, and once with None when the last one ends.
  // Absent by default so the allocator pays nothing when nobody is measuring.
  observer : ((RegallocPhase?) -> Unit)?
}

///|
pub fn RegallocConfig::RegallocConfig(
  verify? : Bool = true,
  observer? : ((RegallocPhase?) -> Unit)? = None,
) -> RegallocConfig {
  { verify, observer }
}

///|
pub fn RegallocConfig::verify(self : RegallocConfig) -> Bool {
  self.verify
}

///|
/// Announce that `phase` is starting, or that the last one has finished.
pub fn RegallocConfig::enter_phase(
  self : RegallocConfig,
  phase : RegallocPhase?,
) -> Unit {
  if self.observer is Some(notify) {
    notify(phase)
  }
}