scc

simple c99 compiler
git clone git://git.simple-cc.org/scc
Log | Files | Refs | Submodules | README | LICENSE

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:
Msrc/cmd/scc-cc/cc2/z80-scc/arch.h | 21++++++++++++++++++++-
Msrc/cmd/scc-cc/cc2/z80-scc/cgen.c | 470++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Msrc/cmd/scc-cc/cc2/z80-scc/code.c | 172++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
Msrc/cmd/scc-cc/cc2/z80-scc/peep.c | 15+++++++++++++++
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, &regs[IX], NULL); + code(ASMOV, &regs[IX], &regs[SP], NULL); + + constnode(&aux, offvar + 2, &ptrtype); + code(ASMOV, &regs[HL], &aux, NULL); + code(ASADD, &regs[HL], &regs[SP], &regs[HL]); + code(ASMOV, &regs[SP], &regs[HL], NULL); +} + +static void +efunction(void) +{ + setlabel(retlabel); + code(ASMOV, &regs[SP], &regs[IX], NULL); + code(ASPOP, &regs[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 = &regs[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, &regs[lower[dst]], idxnode(&low, offl), NULL); + code(ASLD, &regs[upper[dst]], idxnode(&high, offh), NULL); + use(dst, np); +} + +static void +moveto1(Node *np, int dst) +{ + int src; + Node *pdst = &regs[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, &regs[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, &regs[HL], &regs[HL], &regs[DE]); + use(src, reguse[dst]); + } else { + code(ASMOV, &regs[lower[dst]], &regs[lower[src]], NULL); + code(ASMOV, &regs[upper[dst]], &regs[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(&regs[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 &regs[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(); + } }