ref: 4d656cc381de1f2573bfc90a74a878a00f95148d
dir: /cc2/cgen.c/
#include <assert.h>
#include <stdarg.h>
#include <inttypes.h>
#include <stdlib.h>
#include "../inc/cc.h"
#include "cc2.h"
static Node *reguse[NREGS];
static char upper[] = {[DE] = D, [HL] = H, [BC] = B, [IY] = IYH};
static char lower[] = {[DE] = E, [HL] = L, [BC] = C, [IY] = IYL};
static char pair[] = {
[A] = A,
[H] = HL, [L] = HL,
[B] = BC, [C] = BC,
[D] = DE, [E] = DE,
[IYL] = IY, [IYH] = IY
};
Node
reg_E = {
.op = REG,
.reg = E
},
reg_D = {
.op = REG,
.reg = D
},
reg_H = {
.op = REG,
.reg = H
},
reg_L = {
.op = REG,
.reg = L
},
reg_C = {
.op= REG,
.reg = C
},
reg_B = {
.op= REG,
.reg = B
},
reg_A = {
.op= REG,
.reg = A
},
reg_IYL = {
.op = REG,
.reg = IYL
},
reg_IYH = {
.op = REG,
.reg = IYH
},
reg_DE = {
.op = REG,
.reg = DE
},
reg_HL = {
.op = REG,
.reg = HL
},
reg_BC = {
.op = REG,
.reg = BC
},
reg_IX = {
.op = REG,
.reg = IX
},
reg_IY = {
.op = REG,
.reg = IY
},
reg_SP = {
.op = REG,
.reg = SP
};
Node *regs[] = {
[A] = ®_A,
[B] = ®_B, [C] = ®_C,
[D] = ®_D, [E] = ®_E,
[H] = ®_H, [L] = ®_L,
[IYL] = ®_IYL, [IYH] = ®_IYH,
[HL] = ®_HL, [DE] = ®_DE, [BC]= ®_BC,
[IX] = ®_IX, [IY] = ®_IY, [SP] = ®_SP
};
static char
allocreg(Node *np)
{
static char reg8[] = {A, B, C, D, E, H, L, IYL, IY, 0};
static char reg16[] = {BC, DE, IY, 0};
char *bp, c;
switch (np->type.size) {
case 1:
for (bp = reg8; (c = *bp); ++bp) {
if (reguse[c])
continue;
reguse[c] = np;
return c;
}
/* TODO: Move variable to stack using PUSH/POP */
break;
case 2:
for (bp = reg16; (c = *bp); ++bp) {
char u = upper[c], l = lower[c];
if (reguse[u] || reguse[l])
continue;
reguse[u] = reguse[l] = np;
return c;
}
/* TODO: Move variable to stack using PUSH/POP */
break;
}
abort();
}
static void
moveto(Node *np, uint8_t reg)
{
Symbol *sym;
switch (np->op) {
case CONST:
switch (np->type.size) {
case 1:
case 2:
code(LDI, regs[reg], np);
break;
default:
abort();
}
break;
case AUTO:
sym = np->sym;
switch (np->type.size) {
case 1:
code(LDL, regs[reg], np);
break;
case 2:
code(LDL, regs[lower[reg]], np);
code(LDH, regs[upper[reg]], np);
break;
case 4:
case 8:
default:
abort();
}
break;
default:
abort();
}
np->op = REG;
}
static void
move(Node *np)
{
moveto(np, allocreg(np));
}
static void
push(uint8_t reg)
{
Node *np;
if (reg < NREGS)
reg = pair[reg];
if ((np = reguse[lower[reg]]) != NULL)
np->op = PUSHED;
if ((np = reguse[upper[reg]]) != NULL)
np->op = PUSHED;
code(PUSH, NULL, regs[reg]);
}
static void
accum(Node *np)
{
switch (np->type.size) {
case 1:
if (reguse[A])
push(A);
moveto(np, A);
break;
case 2:
if (reguse[H] || reguse[L])
push(HL);
moveto(np, HL);
break;
case 4:
case 8:
abort();
}
}
static void
index(Node *np)
{
if (reguse[H] || reguse[L])
push(HL);
code(LDI, ®_HL, np);
reguse[H] = reguse[L] = np;
np->op = INDEX;
}
static void
conmute(Node *np)
{
Node *p, *q;
p = np->left;
q = np->right;
np->left = q;
np->right = p;
}
static void
add(Node *np)
{
Node *lp = np->left, *rp = np->right;
if (rp->op == REG || lp->op == CONST) {
conmute(np);
lp = np->left;
rp = np->right;
}
switch (np->type.size) {
case 1:
switch (lp->op) {
case PAR:
case AUTO:
switch (rp->op) {
case MEM:
index(rp);
case PAR:
case AUTO:
case CONST:
accum(lp);
break;
default:
abort();
}
break;
case MEM:
if (reguse[A]) {
switch (rp->op) {
case PAR:
case AUTO:
case CONST:
break;
case MEM:
index(rp);
goto add_A;
default:
abort();
}
}
accum(lp);
break;
case REG:
if (lp->reg != A)
moveto(lp, A);
switch (rp->op) {
case REG:
case AUTO:
case PAR:
case CONST:
case MEM:
break;
default:
abort();
}
break;
default:
abort();
}
add_A:
code(ADD, lp, rp);
np->op = REG;
np->reg = A;
break;
case 2:
case 4:
case 8:
abort();
}
}
static void
assign(Node *np)
{
Node *lp = np->left, *rp = np->right;
switch (np->type.size) {
case 1:
switch (lp->op) {
case AUTO:
code(LDL, lp, rp);
break;
case REG:
code(MOV, lp, rp);
break;
case MEM:
index(lp);
code(LDL, lp, rp);
break;
default:
abort();
}
break;
default:
abort();
}
}
static void (*opnodes[])(Node *) = {
[OADD] = add,
[OASSIG] = assign
};
static void
cgen(Node *np, Node *parent)
{
Node *lp, *rp;
if (!np)
return;
if (np->addable >= ADDABLE)
return;
lp = np->left;
rp = np->right;
if (!lp) {
cgen(rp, np);
} else if (!rp) {
cgen(lp, np);
} else {
Node *p, *q;
if (lp->complex > rp->complex)
p = lp, q = rp;
else
p = rp, q = lp;
cgen(p, np);
cgen(q, np);
}
(*opnodes[np->op])(np);
}
static Node *
applycgen(Node *np)
{
cgen(np, NULL);
return NULL;
}
void
generate(void)
{
extern char odebug;
uint8_t i, size = curfun->u.f.locals;
char frame = size != 0 || odebug;
if (frame) {
code(PUSH, NULL, ®_IX);
code(MOV, ®_IX, ®_SP);
if (size > 6) {
code(MOV, ®_HL, imm(-size, &l_int16));
code(ADD, ®_HL, ®_SP);
code(MOV, ®_SP, ®_HL);
} else {
for (i = size; i != 0; i-= 2)
code(PUSH, NULL, ®_HL);
}
}
apply(applycgen);
if (frame) {
code(MOV, ®_SP, ®_IX);
code(POP, ®_IX, NULL);
code(RET, NULL, NULL);
}
}
/*
* This is strongly influenced by
* http://plan9.bell-labs.com/sys/doc/compiler.ps (/sys/doc/compiler.ps)
* calculate addresability as follows
* AUTO => 11 value+fp
* REGISTER => 13 register
* STATIC => 12 (value)
* CONST => 20 $value
*/
Node *
genaddable(Node *np)
{
Node *lp, *rp;
if (!np)
return np;
np->complex = 0;
np->addable = 0;
lp = np->left;
rp = np->right;
switch (np->op) {
case AUTO:
np->addable = 11;
break;
case REG:
np->addable = 13;
break;
case MEM:
np->addable = 12;
break;
case CONST:
np->addable = 20;
break;
default:
if (lp)
genaddable(lp);
if (rp)
genaddable(rp);
break;
}
if (np->addable > 10)
return np;
if (lp)
np->complex = lp->complex;
if (rp) {
int8_t d = np->complex - rp->complex;
if (d == 0)
++np->complex;
else if (d < 0)
np->complex = rp->complex;
}
if (np->complex == 0)
++np->complex;
return np;
}
void
addable(void)
{
apply(genaddable);
}