//===-- 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 num, string n> : Register { 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)>;