///|
// Width for partial-write temporaries
pub(all) enum TmpWidth {
  WFull
  Wsb
  Wub
  Wsh
  Wuh
  Wsw
  Wuw
} derive(Eq, Debug)

///|
// Width index as int (C: WFull=0, Wsb=1, ... Wuw=6)
#as_free_fn(width_code, deprecated="use `TmpWidth::code` instead")
pub fn TmpWidth::code(self : TmpWidth) -> Int {
  match self {
    WFull => 0
    Wsb => 1
    Wub => 2
    Wsh => 3
    Wuh => 4
    Wsw => 5
    Wuw => 6
  }
}

///|
// Construct TmpWidth from an int code (1..6 => Wsb..Wuw)
#as_free_fn(width_from_code, deprecated="use `TmpWidth::from_code` instead")
pub fn TmpWidth::from_code(c : Int) -> TmpWidth {
  match c {
    1 => Wsb
    2 => Wub
    3 => Wsh
    4 => Wuh
    5 => Wsw
    6 => Wuw
    _ => WFull
  }
}

///|
// Use type
pub(all) enum UseKind {
  UXXX
  UPhi
  UIns
  UJmp
} derive(Eq, Debug)

///|
// Use record
pub(all) struct Use {
  kind : UseKind
  blk_id : Int
  ins_idx : Int
  arg_num : Int
} derive(Debug, Eq)

///|
// Register allocation hint
pub(all) struct RegHint {
  mut r : Int // Preferred register, -1 if unset
  mut w : Int // Weight
  mut m : UInt64 // Bitmask of registers to avoid
} derive(Debug)

///|
pub fn RegHint::default() -> RegHint {
  RegHint::{ r: -1, w: 0, m: 0, }
}

///|
// Alias type
pub(all) enum AliasType {
  ABot
  ALoc
  ACon
  AEsc
  ASym
  AUnk
} derive(Eq, Debug)

///|
#as_free_fn(astack, deprecated="use `AliasType::astack` instead")
pub fn AliasType::astack(self : AliasType) -> Bool {
  match self {
    ALoc | AEsc => true
    _ => false
  }
}

///|
// Alias information
pub(all) struct AliasInfo {
  mut kind : AliasType
  mut base : Ref
  mut label : Int
  mut offset : Int64
  // The underlying stack-slot temporary id (the alloc), or -1.
  // Mirrors C's Alias.slot pointer; for an alloc it points to itself.
  mut slot : Int
} derive(Debug)

///|
pub fn AliasInfo::default() -> AliasInfo {
  AliasInfo::{ kind: ABot, base: Ref::none(), label: 0, offset: 0, slot: -1, }
}

///|
// Temporary variable - corresponds to struct Tmp in QBE
pub(all) struct Tmp {
  name : String
  uses : Array[Use]
  mut ndef : Int
  mut nuse : Int
  mut cost : Int
  mut slot : Int // Spill slot, -1 if unset
  mut cls : Class
  mut hint : RegHint
  mut is_phi : Int // 0 = no, >0 = phi class id
  mut alias_info : AliasInfo
  mut width : TmpWidth
  mut visit : Int
} derive(Debug)

///|
pub fn Tmp::new(name : String, cls : Class) -> Tmp {
  Tmp::{
    name,
    uses: Array::new(),
    ndef: 0,
    nuse: 0,
    cost: 0,
    slot: -1,
    cls,
    hint: RegHint::default(),
    is_phi: 0,
    alias_info: AliasInfo::default(),
    width: WFull,
    visit: 0,
  }
}