commit 8198b4e6e7e36f66e5d28513e7935b2c404db8ad
parent 8377bd854349d9b9c20738f05d8cfc5abefc2787
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date: Thu, 26 Dec 2024 22:28:36 +0100
cc2/z80: Rewrite instruction selector
The z80 target was just a place holder, and this rewrite
is only a step to have a working target. Many changes are
expected to this target.
Diffstat:
4 files changed, 632 insertions(+), 46 deletions(-)
diff --git a/src/cmd/scc-cc/cc2/z80-scc/arch.h b/src/cmd/scc-cc/cc2/z80-scc/arch.h
@@ -1,5 +1,24 @@
enum asmop {
- ASJMP = ASLABEL + 1,
+ ASJP = ASLABEL + 1,
+ ASJR,
ASRET,
ASBRANCH,
+
+ ASPUSH,
+ ASPOP,
+
+ ASADD,
+
+ ASMOV,
+ ASST,
+ ASLD,
+ ASEXHL,
+};
+
+enum asregs {
+ A = 1, B, C, D, E, H, L, IYL, IYH, NREGS,
+ AF = NREGS, HL, DE, BC, IY, NPAIRS,
+ HLDE = NPAIRS, NQUAD,
+ EXHLDE = NQUAD, NOCT,
+ SP = NOCT, IX, NANY,
};
diff --git a/src/cmd/scc-cc/cc2/z80-scc/cgen.c b/src/cmd/scc-cc/cc2/z80-scc/cgen.c
@@ -1,18 +1,458 @@
#include <stdlib.h>
+#include <string.h>
#include <scc/scc.h>
#include "../cc2.h"
#include "arch.h"
+#define NLOCALS 16
+
+struct local {
+ Symbol *sym;
+ struct local *next;
+};
+
+static Symbol *retlabel;
+static int offpar, offvar;
+
+static Node *reguse[NPAIRS];
+static int upper[] = {[DE] = D, [HL] = H, [BC] = B, [IY] = IYH};
+static int lower[] = {[DE] = E, [HL] = L, [BC] = C, [IY] = IYL};
+static int pair[] = {
+ [A] = A,
+ [H] = HL, [L] = HL, [HL] = HL,
+ [B] = BC, [C] = BC, [BC] = BC,
+ [D] = DE, [E] = DE, [DE] = DE,
+ [IYL] = IY, [IYH] = IY, [IY] = IY
+};
+
+static Node regs[] = {
+ [E] = {
+ .op = OMREG,
+ .type.size = 1,
+ .u.reg = E
+ },
+ [D] = {
+ .op = OMREG,
+ .type.size = 1,
+ .u.reg = D
+ },
+ [H] = {
+ .op = OMREG,
+ .type.size = 1,
+ .u.reg = H
+ },
+ [L] = {
+ .op = OMREG,
+ .type.size = 1,
+ .u.reg = L
+ },
+ [C] = {
+ .op= OMREG,
+ .type.size = 1,
+ .u.reg = C
+ },
+ [B] = {
+ .op= OMREG,
+ .type.size = 1,
+ .u.reg = B
+ },
+ [A] = {
+ .op= OMREG,
+ .type.size = 1,
+ .u.reg = A
+ },
+ [IYL] = {
+ .op = OMREG,
+ .type.size = 1,
+ .u.reg = IYL
+ },
+ [IYH] = {
+ .op = OMREG,
+ .type.size = 1,
+ .u.reg = IYH
+ },
+ [DE] = {
+ .op = OMREG,
+ .type.size = 2,
+ .u.reg = DE
+ },
+ [HL] = {
+ .op = OMREG,
+ .type.size = 2,
+ .u.reg = HL
+ },
+ [BC] = {
+ .op = OMREG,
+ .type.size = 2,
+ .u.reg = BC
+ },
+ [IX] = {
+ .op = OMREG,
+ .type.size = 2,
+ .u.reg = IX
+ },
+ [IY] = {
+ .op = OMREG,
+ .type.size = 2,
+ .u.reg = IY
+ },
+ [SP] = {
+ .op = OMREG,
+ .type.size = 2,
+ .u.reg = SP
+ }
+};
+
static void
swtch(Node *idx)
{
}
+void
+defpar(Symbol *sym)
+{
+ unsigned align, size;
+
+ if (sym->kind != SREG && sym->kind != SAUTO)
+ return;
+ align = sym->type.align;
+ size = sym->type.size;
+
+ if (offpar == 0)
+ offpar = +2;
+
+ sym->u.off = offpar;
+ offpar += size;
+ offpar += offpar & 1;
+}
+
+void
+defvar(Symbol *sym)
+{
+ unsigned long align, size;
+
+ if (sym->kind != SREG && sym->kind != SAUTO)
+ return;
+ align = sym->type.align;
+ size = sym->type.size;
+
+ if (offvar == 0)
+ offvar = -2;
+
+ sym->u.off = offvar;
+ offvar -= size;
+ offvar -= offpar & 1;
+}
+
+static Node *
+function(void)
+{
+ Node aux;
+
+ memset(reguse, 0, sizeof(reguse));
+
+ retlabel = newlabel();
+
+ code(ASPUSH, NULL, ®s[IX], NULL);
+ code(ASMOV, ®s[IX], ®s[SP], NULL);
+
+ constnode(&aux, offvar + 2, &ptrtype);
+ code(ASMOV, ®s[HL], &aux, NULL);
+ code(ASADD, ®s[HL], ®s[SP], ®s[HL]);
+ code(ASMOV, ®s[SP], ®s[HL], NULL);
+}
+
+static void
+efunction(void)
+{
+ setlabel(retlabel);
+ code(ASMOV, ®s[SP], ®s[IX], NULL);
+ code(ASPOP, ®s[IX], NULL, NULL);
+ code(ASRET, NULL, NULL, NULL);
+ offpar = offvar = 0;
+}
+
+static void
+allocreg(Node *np)
+{
+}
+
+static void
+store(Node *np)
+{
+}
+
+static void
+load(Node *np)
+{
+}
+
+static void
+spill(int reg)
+{
+ Node *np, *r;
+ Symbol *sym;
+ int p, h, l;
+
+ if ((np = reguse[reg]) == NULL)
+ return;
+ r = ®s[reg];
+
+ store(r);
+ p = pair[reg];
+ l = lower[p];
+ h = upper[p];
+
+ if (reg >= NREGS)
+ reguse[l] = reguse[h] = NULL;
+ else
+ reguse[reg] = NULL;
+
+ if (!reguse[l] && !reguse[h])
+ reguse[p] = NULL;
+}
+
+static void
+use(int reg, Node *np)
+{
+ reguse[reg] = np;
+
+ if (reg < NREGS) {
+ reguse[pair[reg]] = np;
+ } else if (reg >= NREGS && reg < NPAIRS) {
+ reguse[lower[reg]] = np;
+ reguse[upper[reg]] = np;
+ } else {
+ abort();
+ }
+}
+
+static void
+load2(Node *np, int dst)
+{
+ long offl, offh;
+ Node low, high;
+
+ switch (np->op) {
+ case OAUTO:
+ offl = np->u.sym->u.off - 1;
+ offh = offl + 1;
+ break;
+ default:
+ abort();
+ }
+
+ code(ASLD, ®s[lower[dst]], idxnode(&low, offl), NULL);
+ code(ASLD, ®s[upper[dst]], idxnode(&high, offh), NULL);
+ use(dst, np);
+}
+
+static void
+moveto1(Node *np, int dst)
+{
+ int src;
+ Node *pdst = ®s[dst];
+
+ switch (np->op) {
+ case OAUTO:
+ code(ASLD, pdst, np, NULL);
+ break;
+ case OMREG:
+ src = np->u.reg;
+ if (src == dst)
+ return;
+
+ code(ASMOV, pdst, ®s[np->u.reg], NULL);
+ break;
+ default:
+ abort();
+ }
+
+ use(dst, np);
+}
+
+static void
+moveto2(Node *np, int dst)
+{
+ int src;
+ Node aux;
+
+ switch (np->op) {
+ case OAUTO:
+ load2(np, dst);
+ break;
+ case OMREG:
+ src = np->u.reg;
+ if (src == dst)
+ return;
+
+ if (src == HL && dst == DE || src == DE && dst == HL) {
+ code(ASEXHL, ®s[HL], ®s[HL], ®s[DE]);
+ use(src, reguse[dst]);
+ } else {
+ code(ASMOV, ®s[lower[dst]], ®s[lower[src]], NULL);
+ code(ASMOV, ®s[upper[dst]], ®s[upper[src]], NULL);
+ }
+ break;
+ default:
+ abort();
+ }
+
+ use(dst, np);
+}
+
+static void
+moveto4(Node *np, int dst)
+{
+ abort();
+}
+
+static void
+moveto8(Node *np, int dst)
+{
+ abort();
+}
+
+static void
+moveto(Node *np, int reg)
+{
+ switch (np->type.size) {
+ case 1:
+ moveto1(np, reg);
+ break;
+ case 2:
+ moveto2(np, reg);
+ break;
+ case 4:
+ moveto4(np, reg);
+ break;
+ case 8:
+ moveto4(np, reg);
+ break;
+ default:
+ abort();
+ }
+}
+
+static int
+cmpnode(Node *n1, Node *n2)
+{
+ if (n1 == n2)
+ return 1;
+ if (!n1 || !n2)
+ return 0;
+ if (n1->op != n2->op)
+ return 0;
+
+ switch (n1->op) {
+ case OAUTO:
+ return n1->u.sym == n2->u.sym;
+ default:
+ return 0;
+ }
+}
+
+static void
+move(Node *np, int reg)
+{
+ int i;
+
+ switch (np->type.size) {
+ case 1:
+ for (i = A; i < NREGS; ++i) {
+ if (cmpnode(reguse[i], np))
+ goto found;
+ }
+ break;
+ case 2:
+ for (i = AF; i < NPAIRS; ++i) {
+ if (cmpnode(reguse[i], np))
+ goto found;
+ }
+ break;
+ case 4:
+ abort();
+ case 8:
+ abort();
+ }
+
+ moveto(np, reg);
+ return;
+
+found:
+ moveto(®s[i], reg);
+}
+
+static int
+whatacc(Node *np)
+{
+ switch (np->type.size) {
+ case 1:
+ return A;
+ case 2:
+ return HL;
+ case 4:
+ return HLDE;
+ case 8:
+ return EXHLDE;
+ default:
+ abort();
+ }
+}
+
+static Node *
+acc(Node *np)
+{
+ int reg = whatacc(np);
+ move(np, reg);
+ return ®s[reg];
+}
+
static Node *
rhs(Node *np)
{
+ switch (np->op) {
+ case OAUTO:
+ return acc(np);
+ case OMEM:
+ case OSNEG:
+ case OTMP:
+ case OCONST:
+ case OREG:
+ case ONEG:
+ case OAND:
+ case OOR:
+ case OMOD:
+ case OSHL:
+ case OBAND:
+ case OBOR:
+ case OBXOR:
+ case OSHR:
+ case ODIV:
+ case OLT:
+ case OGT:
+ case OLE:
+ case OGE:
+ case OADD:
+ case OSUB:
+ case OMUL:
+ case OEQ:
+ case ONE:
+ case OCALL:
+ case OCALLE:
+ case OCAST:
+ case OASSIG:
+ case OASK:
+ case OCOMMA:
+ case OPTR:
+ case OADDR:
+ case OFIELD:
+ case OBUILTIN:
+ default:
+ abort();
+ }
}
static Node *
@@ -67,16 +507,37 @@ bool(Node *np, Symbol *true, Symbol *false)
}
}
-Node *
+static void
+ret(Node *np)
+{
+ Node aux;
+
+ if (np->left)
+ acc(np->left);
+ label2node(&aux, retlabel);
+ code(ASJP, NULL, &aux, NULL);
+}
+
+static Node *
cgen(Node *np)
{
Node aux, *p, *next;
setlabel(np->label);
switch (np->op) {
+ case OBFUN:
+ function();
+ break;
+ case OEFUN:
+ efunction();
+ break;
+ case ONOP:
+ case OBLOOP:
+ case OELOOP:
+ break;
case OJMP:
label2node(&aux, np->u.sym);
- code(ASJMP, NULL, &aux, NULL);
+ code(ASJP, NULL, &aux, NULL);
break;
case OBRANCH:
next = np->next;
@@ -85,8 +546,7 @@ cgen(Node *np)
bool(np->left, np->u.sym, next->label);
break;
case ORET:
- p = (np->left) ? rhs(np->left) : NULL;
- code(ASRET, NULL, p, NULL);
+ ret(np);
break;
case OBSWITCH:
swtch(rhs(np->left));
@@ -95,7 +555,7 @@ cgen(Node *np)
rhs(np);
break;
}
- return NULL;
+ return np;
}
void
diff --git a/src/cmd/scc-cc/cc2/z80-scc/code.c b/src/cmd/scc-cc/cc2/z80-scc/code.c
@@ -1,5 +1,6 @@
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <scc/cstd.h>
#include <scc/scc.h>
@@ -7,6 +8,8 @@
#include "../cc2.h"
#include "arch.h"
+#define ADDR_LEN (INTIDENTSIZ+64)
+
enum segment {
CODESEG,
DATASEG,
@@ -14,6 +17,27 @@ enum segment {
NOSEG
};
+static void src(void), dst(void), bin(void), lit(void), jmp(void);
+
+static struct opdata {
+ void (*fun)(void);
+ char *txt;
+} optbl[] = {
+ [ASPUSH] = {.fun = src, .txt = "push"},
+ [ASPOP] = {.fun = dst, .txt = "pop"},
+
+ [ASRET] = {.fun = lit, .txt = "ret"},
+ [ASJP] = {.fun = jmp, .txt = "jp"},
+ [ASJP] = {.fun = jmp, .txt = "jr"},
+ [ASBRANCH] = {0},
+
+ [ASMOV] = {.fun = bin, .txt = "ld"},
+ [ASEXHL] = {.fun = bin, .txt = "ex"},
+
+ [ASADD] = {.fun = bin, .txt = "add"},
+ [ASLD] = {.fun = bin, .txt = "ld"},
+};
+
static int curseg = NOSEG;
static unsigned long offpar, offvar;
@@ -21,9 +45,9 @@ static void
segment(int seg)
{
static char *txt[] = {
- [CODESEG] = "\tCSEG\n",
- [DATASEG] = "\tDSEG\n",
- [BSSSEG] = "\tASEG\n",
+ [CODESEG] = "\t.text\n",
+ [DATASEG] = "\t.data\n",
+ [BSSSEG] = "\t.bss\n",
};
if (seg == curseg)
@@ -35,7 +59,7 @@ segment(int seg)
static char *
symname(Symbol *sym)
{
- static char name[INTIDENTSIZ+1];
+ static char name[ADDR_LEN];
if (sym->name) {
switch (sym->kind) {
@@ -69,10 +93,10 @@ label(Symbol *sym)
switch (sym->kind) {
case SEXTRN:
- printf("\tEXTRN\t%s\n", name);
+ printf("\t.extrn\t%s\n", name);
return;
case SGLOB:
- printf("\tPUBLIC\t%s\n", name);
+ printf("\t.globl\t%s\n", name);
break;
}
@@ -155,40 +179,6 @@ size2asm(Type *tp)
printf(s, tp->size);
}
-/* TODO: how are initialized offpar and offvar??? */
-
-void
-defpar(Symbol *sym)
-{
- unsigned long align, size;
-
- if (sym->kind != SREG && sym->kind != SAUTO)
- return;
- align = sym->type.align;
- size = sym->type.size;
-
- offpar -= align-1 & ~align;
- sym->u.off = offpar;
- offpar -= size;
- sym->kind = SAUTO;
-}
-
-void
-defvar(Symbol *sym)
-{
- unsigned long align, size;
-
- if (sym->kind != SREG && sym->kind != SAUTO)
- return;
- align = sym->type.align;
- size = sym->type.size;
-
- offvar += align-1 & ~align;
- sym->u.off = offvar;
- offvar += size;
- sym->kind = SAUTO;
-}
-
void
deftype(Type *tp)
{
@@ -215,9 +205,111 @@ data(Node *np)
void
writeout(void)
{
+ if (!curfun)
+ return;
+ label(curfun);
+
+ for (pc = prog; pc; pc = pc->next) {
+ if (pc->label)
+ printf("%s:\n", symname(pc->label));
+ if (pc->op == ASLABEL)
+ continue;
+ (*optbl[pc->op].fun)();
+ }
}
void
endinit(void)
{
}
+
+static char *
+addr2txt(Addr *a)
+{
+ static char *regnames[] = {
+ [A] = "a",
+ [B] = "b",
+ [C] = "c",
+ [D] = "d",
+ [E] = "e",
+ [H] = "h",
+ [L] = "l",
+ [IYL] = "iyl",
+ [IYH] = "iyh",
+ [AF] = "af",
+ [HL] = "hl",
+ [DE] = "de",
+ [BC] = "bc",
+ [IY] = "iy",
+ [SP] = "sp",
+ [IX] = "ix",
+ };
+ static char addr[INTIDENTSIZ+1];
+
+ switch (a->kind) {
+ case SREG:
+ return regnames[a->u.reg];
+ case SINDEX:
+ sprintf(addr,"%ld(ix)", a->u.off);
+ return addr;
+ case SLABEL:
+ case STMP:
+ case SGLOB:
+ case SEXTRN:
+ case SPRIV:
+ case SLOCAL:
+ return symname(a->u.sym);
+ case SCONST:
+ sprintf(addr, "%lld", a->u.i);
+ return addr;
+ default:
+ abort();
+ }
+}
+
+static void
+lit(void)
+{
+ struct opdata *p = &optbl[pc->op];
+
+ printf("\t%s\n", p->txt);
+}
+
+static void
+bin(void)
+{
+ struct opdata *p = &optbl[pc->op];
+ char to[ADDR_LEN], from[ADDR_LEN];
+
+ strcpy(from, addr2txt(&pc->from1));
+ strcpy(to, addr2txt(&pc->to));
+ printf("\t%s\t%s,%s\n", p->txt, from, to);
+}
+
+static void
+src(void)
+{
+ struct opdata *p = &optbl[pc->op];
+ char from[ADDR_LEN];
+
+ strcpy(from, addr2txt(&pc->from1));
+ printf("\t%s\t%s\n", p->txt, from);
+}
+
+static void
+dst(void)
+{
+ struct opdata *p = &optbl[pc->op];
+ char to[ADDR_LEN];
+
+ strcpy(to, addr2txt(&pc->to));
+ printf("\t%s\t%s\n", p->txt, to);
+}
+
+static void
+jmp(void)
+{
+ struct opdata *p = &optbl[pc->op];
+
+ printf("\t%s\t%s\n", p->txt, addr2txt(&pc->from1));
+}
diff --git a/src/cmd/scc-cc/cc2/z80-scc/peep.c b/src/cmd/scc-cc/cc2/z80-scc/peep.c
@@ -3,7 +3,22 @@
#include "../cc2.h"
#include "arch.h"
+static void
+deljmp(void)
+{
+ if (!pc)
+ return;
+
+ if (pc->op == ASJP || pc->op == ASJR) {
+ if (pc->from1.u.sym == pc->next->label)
+ delcode();
+ }
+}
+
void
peephole(void)
{
+ for (pc = prog; pc; pc = pc->next) {
+ deljmp();
+ }
}