///|
// RISC-V 64 (rv64) target constants.
// Mirrors target.mbt but for RISC-V 64-bit architecture.

///|
// RISC-V 64 register numbers (as virtual tmp ids, matching C enum Rv64Reg)

///|
// Caller-save registers (T0-T5, A0-A7)
pub const T0 : Int = 1

///|
pub const T1 : Int = 2

///|
pub const T2 : Int = 3

///|
pub const T3 : Int = 4

///|
pub const T4 : Int = 5

///|
pub const T5 : Int = 6

///|
pub const A0 : Int = 7

///|
pub const A1 : Int = 8

///|
pub const A2 : Int = 9

///|
pub const A3 : Int = 10

///|
pub const A4 : Int = 11

///|
pub const A5 : Int = 12

///|
pub const A6 : Int = 13

///|
pub const A7 : Int = 14

///|
// Callee-save registers (S1-S11)
pub const S1 : Int = 15

///|
pub const S2 : Int = 16

///|
pub const S3 : Int = 17

///|
pub const S4 : Int = 18

///|
pub const S5 : Int = 19

///|
pub const S6 : Int = 20

///|
pub const S7 : Int = 21

///|
pub const S8 : Int = 22

///|
pub const S9 : Int = 23

///|
pub const S10 : Int = 24

///|
pub const S11 : Int = 25

///|
// Globally live registers
pub const FP : Int = 26

///|
pub const SP : Int = 27

///|
pub const GP : Int = 28

///|
pub const TP : Int = 29

///|
pub const RA : Int = 30

///|
// FP caller-save registers (FT0-FT10, FA0-FA7)
pub const FT0 : Int = 31

///|
pub const FT1 : Int = 32

///|
pub const FT2 : Int = 33

///|
pub const FT3 : Int = 34

///|
pub const FT4 : Int = 35

///|
pub const FT5 : Int = 36

///|
pub const FT6 : Int = 37

///|
pub const FT7 : Int = 38

///|
pub const FT8 : Int = 39

///|
pub const FT9 : Int = 40

///|
pub const FT10 : Int = 41

///|
pub const FA0 : Int = 42

///|
pub const FA1 : Int = 43

///|
pub const FA2 : Int = 44

///|
pub const FA3 : Int = 45

///|
pub const FA4 : Int = 46

///|
pub const FA5 : Int = 47

///|
pub const FA6 : Int = 48

///|
pub const FA7 : Int = 49

///|
// FP callee-save registers (FS0-FS11)
pub const FS0 : Int = 50

///|
pub const FS1 : Int = 51

///|
pub const FS2 : Int = 52

///|
pub const FS3 : Int = 53

///|
pub const FS4 : Int = 54

///|
pub const FS5 : Int = 55

///|
pub const FS6 : Int = 56

///|
pub const FS7 : Int = 57

///|
pub const FS8 : Int = 58

///|
pub const FS9 : Int = 59

///|
pub const FS10 : Int = 60

///|
pub const FS11 : Int = 61

///|
// Reserved registers
pub const T6 : Int = 62

///|
pub const FT11 : Int = 63

///|
// Tmp0 - first non-register temporary
pub const Rv64Tmp0 : Int = 64

///|
// Number of general purpose registers (T0-RA)
pub const Rv64NGPR : Int = 30

///|
// Number of float registers (FT0-FS11)
pub const Rv64NFPR : Int = 32

///|
// Number of caller-save GPRs (T0-A7)
pub const Rv64NGPS : Int = 14

///|
// Number of caller-save FPRs (FT0-FA7)
pub const Rv64NFPS : Int = 18

///|
// Number of callee-save registers (S1-S11, FS0-FS11)
pub const Rv64NCLR : Int = 23

///|
// RISC-V caller-save register list (C rv64_rsave in targ.c)
pub let rv64_rsave : Array[Int] = [
  T0,
  T1,
  T2,
  T3,
  T4,
  T5,
  A0,
  A1,
  A2,
  A3,
  A4,
  A5,
  A6,
  A7,
  FA0,
  FA1,
  FA2,
  FA3,
  FA4,
  FA5,
  FA6,
  FA7,
  FT0,
  FT1,
  FT2,
  FT3,
  FT4,
  FT5,
  FT6,
  FT7,
  FT8,
  FT9,
  FT10,
]

///|
// RISC-V callee-save register list (C rv64_rclob in targ.c)
pub let rv64_rclob : Array[Int] = [
  S1,
  S2,
  S3,
  S4,
  S5,
  S6,
  S7,
  S8,
  S9,
  S10,
  S11,
  FS0,
  FS1,
  FS2,
  FS3,
  FS4,
  FS5,
  FS6,
  FS7,
  FS8,
  FS9,
  FS10,
  FS11,
]

///|
// RISC-V globally live registers bitmask (FP | SP | GP | TP | RA)
pub fn rv64_rglob_mask() -> UInt64 {
  let one : UInt64 = 1
  (one << FP) | (one << SP) | (one << GP) | (one << TP) | (one << RA)
}

///|
// Number of globally live registers
pub const Rv64NRGLOB : Int = 5

///|
// The registers returned by a call, given its RCall ref (C rv64_retregs).
// Returns (bits, ngp, nfpr).
pub fn Ref::rv64_retregs(self : Ref) -> (UInt64, Int, Int) {
  let mut b : UInt64 = 0
  let v = self.call_val()
  let ni = v & 3
  let nf = (v >> 2) & 3
  if ni >= 1 {
    b = b | (1UL << A0)
  }
  if ni >= 2 {
    b = b | (1UL << A1)
  }
  if nf >= 1 {
    b = b | (1UL << FA0)
  }
  if nf >= 2 {
    b = b | (1UL << FA1)
  }
  (b, ni, nf)
}

///|
// The registers used to pass arguments, given an RCall ref (C rv64_argregs).
// Returns (bits, ngp, nfpr).
pub fn Ref::rv64_argregs(self : Ref) -> (UInt64, Int, Int) {
  let mut b : UInt64 = 0
  let v = self.call_val()
  let ni = (v >> 4) & 15
  let nf = (v >> 8) & 15
  let t5 = (v >> 12) & 1
  for j in 0.. String {
  match reg {
    FP => "fp"
    SP => "sp"
    GP => "gp"
    TP => "tp"
    RA => "ra"
    T0 => "t0"
    T1 => "t1"
    T2 => "t2"
    T3 => "t3"
    T4 => "t4"
    T5 => "t5"
    A0 => "a0"
    A1 => "a1"
    A2 => "a2"
    A3 => "a3"
    A4 => "a4"
    A5 => "a5"
    A6 => "a6"
    A7 => "a7"
    S1 => "s1"
    S2 => "s2"
    S3 => "s3"
    S4 => "s4"
    S5 => "s5"
    S6 => "s6"
    S7 => "s7"
    S8 => "s8"
    S9 => "s9"
    S10 => "s10"
    S11 => "s11"
    FT0 => "ft0"
    FT1 => "ft1"
    FT2 => "ft2"
    FT3 => "ft3"
    FT4 => "ft4"
    FT5 => "ft5"
    FT6 => "ft6"
    FT7 => "ft7"
    FT8 => "ft8"
    FT9 => "ft9"
    FT10 => "ft10"
    FA0 => "fa0"
    FA1 => "fa1"
    FA2 => "fa2"
    FA3 => "fa3"
    FA4 => "fa4"
    FA5 => "fa5"
    FA6 => "fa6"
    FA7 => "fa7"
    FS0 => "fs0"
    FS1 => "fs1"
    FS2 => "fs2"
    FS3 => "fs3"
    FS4 => "fs4"
    FS5 => "fs5"
    FS6 => "fs6"
    FS7 => "fs7"
    FS8 => "fs8"
    FS9 => "fs9"
    FS10 => "fs10"
    FS11 => "fs11"
    T6 => "t6"
    FT11 => "ft11"
    _ => "?"
  }
}

///|
// RISC-V pointer size: Kl (64-bit).
// On amd64 Km=Kl; on wasm32 Km=Kw; on rv64 Km=Kl.
pub const Rv64KmIsWide : Int = 1

///|
// RISC-V call return registers (C rv64 retregs): A0/A1 and FA0/FA1.
fn rv64_target_retregs(r : Ref) -> (UInt64, Int, Int) {
  let mut b : UInt64 = 0
  let v = r.call_val()
  let ni = v & 3
  let nf = (v >> 2) & 3
  if ni >= 1 {
    b = b | (1UL << A0)
  }
  if ni >= 2 {
    b = b | (1UL << A1)
  }
  if nf >= 1 {
    b = b | (1UL << FA0)
  }
  if nf >= 2 {
    b = b | (1UL << FA1)
  }
  (b, ni, nf)
}

///|
// RISC-V call argument registers (C rv64 argregs): A0.. and FA0...
fn rv64_target_argregs(r : Ref) -> (UInt64, Int, Int) {
  let mut b : UInt64 = 0
  let v = r.call_val()
  let ni = (v >> 4) & 15
  let nf = (v >> 8) & 15
  let ra = (v >> 12) & 1
  for j in 0.. Unit {
  target_cfg.gpr_base = T0
  target_cfg.fpr_base = FT0
  target_cfg.ngpr = Rv64NGPR
  target_cfg.nfpr = Rv64NFPR
  target_cfg.fpr_class_base = FT0
  target_cfg.post_call_gpr = Rv64NGPS
  target_cfg.post_call_fpr = Rv64NFPS
  target_cfg.rglob_mask = rv64_rglob_mask()
  target_cfg.rsave = rv64_rsave
  target_cfg.retregs = rv64_target_retregs
  target_cfg.argregs = rv64_target_argregs
}