197 lines
9.9 KiB
TableGen
197 lines
9.9 KiB
TableGen
//===-- 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. IMG0..IMG7 are caller-save: a call clobbers them,
|
||
// so regalloc spills around any call. IMG8..IMG15 are callee-saved:
|
||
// W65816ImgCalleeSave saves and restores them in any function that
|
||
// writes them, and callers keep values in them across calls, so hand
|
||
// asm called from C must not overwrite them without doing the same.
|
||
// 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)>;
|