//===-- W65816RegisterInfo.td - W65816 Register defs -------*- tablegen -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

//===----------------------------------------------------------------------===//
//  Declarations that describe the W65816 register file
//===----------------------------------------------------------------------===//

class W65816Reg<bits<8> num, string n> : Register<n> {
  field bits<8> Num = num;
  let Namespace = "W65816";
  let HWEncoding{7-0} = num;
  let DwarfNumbers = [num];
}

// SubRegIndices for synthetic 32-bit register pairs.  sub_lo addresses the
// low 16 bits (the natural i16-aligned half), sub_hi the high 16 bits.
// Used by Acc32 / Wide32 / AnyWide32 to model i32 (i.e. ptr32) values as
// pairs of i16 physical registers.
def sub_lo : SubRegIndex<16, 0>;
def sub_hi : SubRegIndex<16, 16>;

//===----------------------------------------------------------------------===//
//  Registers
//===----------------------------------------------------------------------===//
//
// The 65816 registers are variable-width: A, X and Y are each 8 or 16 bits
// wide depending on the M and X bits in the processor status register.  For
// the skeleton we model each physical register once and create parallel 8-bit
// and 16-bit register classes that share the same physical register.  A later
// pass is responsible for managing REP/SEP transitions and verifying that the
// selected width matches the current processor mode.
//
def A   : W65816Reg<0, "a">,   DwarfRegNum<[0]>;
def X   : W65816Reg<1, "x">,   DwarfRegNum<[1]>;
def Y   : W65816Reg<2, "y">,   DwarfRegNum<[2]>;
def SP  : W65816Reg<3, "sp">,  DwarfRegNum<[3]>;
def DP  : W65816Reg<4, "dp">,  DwarfRegNum<[4]>;
def DBR : W65816Reg<5, "dbr">, DwarfRegNum<[5]>;
def PBR : W65816Reg<6, "pbr">, DwarfRegNum<[6]>;
def PC  : W65816Reg<7, "pc">,  DwarfRegNum<[7]>;
def P   : W65816Reg<8, "p">,   DwarfRegNum<[8]>;

// Imaginary 16-bit registers backed by direct-page slots $C0..$DE
// (16 slots = 32 DP bytes).  The regalloc treats them as physical
// registers with cheap LDA/STA dp inter-register moves.  This
// relieves pressure on the single Acc16 register (A) so greedy
// regalloc can succeed on functions with multiple simultaneously-
// live i16 vregs.  Caller-save: callees may freely overwrite them,
// so regalloc spills around any call that might touch them.  Their
// HWEncoding is never emitted (asmprinter translates IMGn references
// into LDA/STA dp with the right address).
//
// Layout: IMG0..IMG7 at $D0..$DE (legacy slot block); IMG8..IMG15
// at $C0..$CE.  Avoid stepping on user DP allocations below $C0.
def IMG0  : W65816Reg<16, "img0">,  DwarfRegNum<[16]>;
def IMG1  : W65816Reg<17, "img1">,  DwarfRegNum<[17]>;
def IMG2  : W65816Reg<18, "img2">,  DwarfRegNum<[18]>;
def IMG3  : W65816Reg<19, "img3">,  DwarfRegNum<[19]>;
def IMG4  : W65816Reg<20, "img4">,  DwarfRegNum<[20]>;
def IMG5  : W65816Reg<21, "img5">,  DwarfRegNum<[21]>;
def IMG6  : W65816Reg<22, "img6">,  DwarfRegNum<[22]>;
def IMG7  : W65816Reg<23, "img7">,  DwarfRegNum<[23]>;
def IMG8  : W65816Reg<32, "img8">,  DwarfRegNum<[32]>;
def IMG9  : W65816Reg<33, "img9">,  DwarfRegNum<[33]>;
def IMG10 : W65816Reg<34, "img10">, DwarfRegNum<[34]>;
def IMG11 : W65816Reg<35, "img11">, DwarfRegNum<[35]>;
def IMG12 : W65816Reg<36, "img12">, DwarfRegNum<[36]>;
def IMG13 : W65816Reg<37, "img13">, DwarfRegNum<[37]>;
def IMG14 : W65816Reg<38, "img14">, DwarfRegNum<[38]>;
def IMG15 : W65816Reg<39, "img15">, DwarfRegNum<[39]>;

// DPF0 — pseudo-physreg modeling the i16 storage at DP $F0..$F1.
// Used as the carrier for the highest 16 bits of an i64/double
// return.  JSLpseudo Defs DPF0 so the SDAG combiner / scheduler
// can't merge or reorder reads of it across calls; we plumb the
// 4th return half via CopyFromReg(DPF0) in LowerCall, which lowers
// to `LDA $F0` via copyPhysReg.  Never allocated to a vreg —
// always a transient bridge from DP[$F0] to A.
def DPF0 : W65816Reg<24, "dpf0">, DwarfRegNum<[24]>;

//===----------------------------------------------------------------------===//
//  Register Classes
//===----------------------------------------------------------------------===//
//
// Acc8/Acc16 hold the accumulator A in 8-bit and 16-bit mode respectively.
// Idx8/Idx16 hold the index registers X and Y in 8-bit and 16-bit mode.
// PtrRegs holds the stack pointer for framing and pointer arithmetic; DP is
// reserved and not allocatable.

def Acc8  : RegisterClass<"W65816", [i8],  8,  (add A)>;
def Acc16 : RegisterClass<"W65816", [i16], 16, (add A)>;
def Idx8  : RegisterClass<"W65816", [i8],  8,  (add X, Y)>;
def Idx16 : RegisterClass<"W65816", [i16], 16, (add X, Y)>;

// Imaginary i16 registers backed by DP slots $D0..$DE.  Vregs in this
// class lower to LDA/STA dp on cross-class moves to A (4 cyc each
// way).  Used by ABridgeViaX (and future regalloc-pressure passes) as
// an alternative parking spot to stack spills.  Caller-save: a callee
// may freely overwrite $D0..$DF, so the allocator must spill IMGn
// vregs around any call.
def Img16 : RegisterClass<"W65816", [i16], 16,
                          (add IMG0,  IMG1,  IMG2,  IMG3,
                               IMG4,  IMG5,  IMG6,  IMG7,
                               IMG8,  IMG9,  IMG10, IMG11,
                               IMG12, IMG13, IMG14, IMG15)>;

// Acc-or-IMG combined class.  Vregs that are not constrained to A
// (i.e., not the source of an arithmetic op) get widened to this
// class pre-RA so greedy regalloc can pick A or any IMGn.  Listing
// A first so the allocator's default order prefers A; cross-class
// moves to/from A are LDA/STA dp via copyPhysReg.
def Wide16 : RegisterClass<"W65816", [i16], 16,
                           (add A, IMG0,  IMG1,  IMG2,  IMG3,
                                   IMG4,  IMG5,  IMG6,  IMG7,
                                   IMG8,  IMG9,  IMG10, IMG11,
                                   IMG12, IMG13, IMG14, IMG15)>;

def PtrRegs : RegisterClass<"W65816", [i16], 16, (add SP)>;

// Single-register class for DPF0, the i64-return high-half carrier.
// Not allocatable — only used as a CopyFromReg source in LowerCall;
// copyPhysReg lowers DPF0 → A by emitting `LDA $F0`.
def DPF0Reg : RegisterClass<"W65816", [i16], 16, (add DPF0)> {
  let isAllocatable = 0;
}

// Single-register class for the processor status register, used for condition
// code modeling.  Not currently allocatable.
def StatusReg : RegisterClass<"W65816", [i8], 8, (add P)> {
  let isAllocatable = 0;
}

//===----------------------------------------------------------------------===//
//  Synthetic 32-bit Register Pairs (for ptr32 mode)
//===----------------------------------------------------------------------===//
//
// The W65816 has no native 32-bit registers.  For 32-bit-pointer mode and
// any other i32 traffic we synthesize register pairs whose halves are
// existing i16 registers, accessed via sub_lo / sub_hi.
//
// AX32 pairs A:X for the calling-convention slot (first i32 arg/return).
// Heterogeneous: sub_lo is in Acc16, sub_hi is in Idx16.  Because of the
// heterogeneity, AX32 lives in its own single-element class (Acc32) — if
// it were grouped with the homogeneous IMG pairs in Wide32, TableGen would
// auto-derive a "wide32_with_sub_hi_in_idx8" subclass that pins the whole
// class to AX32.
//
// IMG01..IMG1415 pair adjacent IMG slots (each pair is 4 bytes of DP) into
// homogeneous i16-i16 pairs.  These hold ptr32 values backed entirely by
// direct page, so register-pair allocation can spill cleanly via Img16's
// existing rules.
//
// Acc32 / Wide32 / AnyWide32:
//   Acc32 = {AX32} — calling-convention slot only; not for general allocation.
//   Wide32 = {IMG01..IMG1415} — homogeneous i16-i16 pairs, freely allocatable.
//   AnyWide32 = Acc32 ∪ Wide32 — pre-RA flexibility for ptr32 vregs that
//     are not constrained to AX32; greedy regalloc can pick AX32 or any
//     Wide32 pair.
let SubRegIndices = [sub_lo, sub_hi], CoveredBySubRegs = 1 in {
  def AX32     : RegisterWithSubRegs<"ax32",    [A,     X]>,
                 DwarfRegNum<[40]> { let Namespace = "W65816"; }
  def IMG01    : RegisterWithSubRegs<"img01",   [IMG0,  IMG1]>,
                 DwarfRegNum<[41]> { let Namespace = "W65816"; }
  def IMG23    : RegisterWithSubRegs<"img23",   [IMG2,  IMG3]>,
                 DwarfRegNum<[42]> { let Namespace = "W65816"; }
  def IMG45    : RegisterWithSubRegs<"img45",   [IMG4,  IMG5]>,
                 DwarfRegNum<[43]> { let Namespace = "W65816"; }
  def IMG67    : RegisterWithSubRegs<"img67",   [IMG6,  IMG7]>,
                 DwarfRegNum<[44]> { let Namespace = "W65816"; }
  def IMG89    : RegisterWithSubRegs<"img89",   [IMG8,  IMG9]>,
                 DwarfRegNum<[45]> { let Namespace = "W65816"; }
  def IMG1011  : RegisterWithSubRegs<"img1011", [IMG10, IMG11]>,
                 DwarfRegNum<[46]> { let Namespace = "W65816"; }
  def IMG1213  : RegisterWithSubRegs<"img1213", [IMG12, IMG13]>,
                 DwarfRegNum<[47]> { let Namespace = "W65816"; }
  def IMG1415  : RegisterWithSubRegs<"img1415", [IMG14, IMG15]>,
                 DwarfRegNum<[48]> { let Namespace = "W65816"; }
}

def Acc32 : RegisterClass<"W65816", [i32], 16, (add AX32)>;

def Wide32 : RegisterClass<"W65816", [i32], 16,
                           (add IMG01, IMG23, IMG45, IMG67,
                                IMG89, IMG1011, IMG1213, IMG1415)>;

def AnyWide32 : RegisterClass<"W65816", [i32], 16,
                              (add AX32,
                                   IMG01, IMG23, IMG45, IMG67,
                                   IMG89, IMG1011, IMG1213, IMG1415)>;
