113 lines
5.4 KiB
TableGen
113 lines
5.4 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];
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// 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 $D0..$DE.
|
|
// 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).
|
|
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]>;
|
|
|
|
// 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)>;
|
|
|
|
// 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)>;
|
|
|
|
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;
|
|
}
|