ref: 7761303503062221973c8bd9bad4cb019cebe7f6
dir: /cc1/code.c/
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "../inc/cc.h"
#include "cc1.h"
static void emitbin(unsigned, void *),
emitcast(unsigned, void *), emitswitch(unsigned, void *),
emitsym(unsigned, void *), emitfield(unsigned, void *),
emitexp(unsigned, void *),
emitsymid(unsigned, void *), emittext(unsigned, void *),
emitprint(unsigned, void *), emitfun(unsigned, void *),
emitret(unsigned, void *), emitdcl(unsigned, void *);
char *optxt[] = {
[OADD] = "+",
[OSUB] = "-",
[OMUL] = "*",
[OINC] = ";+",
[ODEC] = ";-",
[OPTR] = "@",
[OMOD] = "%",
[ODIV] = "/",
[OSHL] = "l",
[OSHR] = "r",
[OLT] = "<",
[OGT] = ">",
[OGE] = "]",
[OLE] = "[",
[OEQ] = "=",
[ONE] = "!",
[OBAND] = "&",
[OBXOR] = "^",
[OBOR] = "|",
[OASSIGN] = ":",
[OA_MUL] = ":*",
[OA_DIV] = ":/",
[OA_MOD] = ":%",
[OA_ADD] = ":+",
[OA_SUB] = ":-",
[OA_SHL] = ":l",
[OA_SHR] = ":r",
[OA_AND] = ":&",
[OA_XOR] = ":^",
[OA_OR] = ":|",
[OADDR] = "a",
[ONEG] = "_",
[OCPL] = "~",
[OAND] = "y",
[OOR] = "o",
[OASK] = "?",
[OCOMMA] = ",",
[OLABEL] = "L%d\n",
[ODEFAULT] = "\tf\tL%d\n",
[OCASE] = "\tw\tL%d",
[OSTRUCT] = "S%d\t(\n",
[OJUMP] = "\tj\tL%d\n",
[OBRANCH] = "\tj\tL%d",
[OEFUN] = "}",
[OESTRUCT] = ")",
[OELOOP] = "\tb",
[OBLOOP] = "\td"
};
void (*opcode[])(unsigned, void *) = {
[OADD] = emitbin,
[OSUB] = emitbin,
[OMUL] = emitbin,
[OINC] = emitbin,
[ODEC] = emitbin,
[OPTR] = emitbin,
[OMOD] = emitbin,
[ODIV] = emitbin,
[OSHL] = emitbin,
[OSHR] = emitbin,
[OLT] = emitbin,
[OGT] = emitbin,
[OGE] = emitbin,
[OLE] = emitbin,
[OEQ] = emitbin,
[ONE] = emitbin,
[OBAND] = emitbin,
[OBXOR] = emitbin,
[OBOR] = emitbin,
[OASSIGN] = emitbin,
[OA_MUL] = emitbin,
[OA_DIV] = emitbin,
[OA_MOD] = emitbin,
[OA_ADD] = emitbin,
[OA_SUB] = emitbin,
[OA_SHL] = emitbin,
[OA_SHR] = emitbin,
[OA_AND] = emitbin,
[OA_XOR] = emitbin,
[OA_OR] = emitbin,
[OADDR] = emitbin,
[ONEG] = emitbin,
[OCPL] = emitbin,
[OAND] = emitbin,
[OOR] = emitbin,
[OCOMMA] = emitbin,
[OCAST] = emitcast,
[OSYM] = emitsym,
[OASK] = emitbin,
[OCOLON] = emitbin,
[OFIELD]= emitfield,
[OEXPR] = emitexp,
[OLABEL] = emitsymid,
[ODEFAULT] = emitsymid,
[OCASE] = emitsymid,
[OSTRUCT] = emitsymid,
[OJUMP] = emitsymid,
[OBRANCH] = emitsymid,
[OEFUN] = emittext,
[OESTRUCT] = emittext,
[OELOOP] = emittext,
[OBLOOP] = emittext,
[OFUN] = emitfun,
[ORET] = emitret,
[ODECL] = emitdcl,
[OSWITCH] = emitswitch
};
static Node *simple_add(Type *, Node *, Node *),
*simple_sub(Type *, Node *, Node *),
*simple_mul(Type *, Node *, Node *),
*simple_div(Type *, Node *, Node *),
*simple_mod(Type *, Node *, Node *);
void
freetree(Node *np)
{
if (!np)
return;
freetree(np->left);
freetree(np->right);
free(np);
}
static void
emitnode(Node *np)
{
if (np)
(*opcode[np->op])(np->op, np);
}
void
emit(unsigned op, void *arg)
{
extern int failure;
if (failure)
return;
(*opcode[op])(op, arg);
}
static void
emitvar(Symbol *sym)
{
char c;
if (sym->flags & ISSTATIC)
c = (sym->flags & ISGLOBAL) ? 'Y' : 'T';
else if (sym->flags & ISGLOBAL)
c = 'G';
else if (sym->flags & ISREGISTER)
c = 'K';
else if (sym->flags & ISFIELD)
c = 'M';
else if (sym->flags & ISPARAM)
c = 'P';
else
c = 'A';
printf("%c%d", c, sym->id);
}
static void
emitconst(Node *np)
{
char *bp, c;
Symbol *sym = np->sym;
switch (BTYPE(np)) {
case INT:
printf("#%c%x", np->type->letter, sym->u.i);
break;
case ARY:
/*
* FIX: At this point we are going to assume
* that all the arrays are strings
*/
putchar('"');
for (bp = sym->u.s; c = *bp; ++bp)
printf("%02X", c & 0xFF);
break;
default:
/* TODO: Handle other kind of constants */
abort();
}
}
static void
emitsym(unsigned op, void *arg)
{
Node *np = arg;
putchar('\t');
(np->constant) ? emitconst(np) : emitvar(np->sym);
}
static void
emitletter(Type *tp)
{
putchar(tp->letter);
if (tp->op == ARY)
printf("%d", tp->id);
}
static void
emittype(Type *tp)
{
if (tp->printed)
return;
switch (tp->op) {
case ARY:
emittype(tp->type);
printf("V%d\t", tp->id);
emitletter(tp->type);
printf("\t#%d\n", tp->n.elem);
return;
case PTR:
emittype(tp->type);
return;
default:
abort();
}
}
static void
emitdcl(unsigned op, void *arg)
{
Symbol *sym = arg;
emittype(sym->type);
emitvar(sym);
putchar('\t');
emitletter(sym->type);
putchar('\n');
}
static void
emitcast(unsigned op, void *arg)
{
Node *np = arg, *lp = np->left;
emitnode(lp);
printf("\t%c%c", lp->type->letter, np->type->letter);
}
static void
emitbin(unsigned op, void *arg)
{
Node *np = arg;
char *s;
emitnode(np->left);
emitnode(np->right);
if ((s = optxt[op]) != NULL)
printf("\t%s%c", s, np->type->letter);
}
static void
emitexp(unsigned op, void *arg)
{
Node *np = arg;
emitnode(np);
putchar('\n');
freetree(np);
}
static void
emitfun(unsigned op, void *arg)
{
Symbol *sym = arg;
printf("%c%d\tF\t%s\t{\n",
sym->flags & ISGLOBAL ? 'G' : 'Y', sym->id, sym->name);
}
static void
emitret(unsigned op, void *arg)
{
Type *tp = arg;
fputs("\ty", stdout);
emitletter(tp);
}
static void
emittext(unsigned op, void *arg)
{
puts(optxt[op]);
}
static void
emitsymid(unsigned op, void *arg)
{
Symbol *sym = arg;
printf(optxt[op], sym->id);
}
static void
emitswitch(unsigned op, void *arg)
{
Caselist *lcase = arg;
printf("\teI\t#%0x", lcase->nr);
}
void
emitfield(unsigned op, void *arg)
{
Node *np = arg;
emitnode(np->left);
putchar('\t');
emitvar(np->sym);
}
Node *
node(unsigned op, Type *tp, Node *lp, Node *rp)
{
Node *np;
np = xmalloc(sizeof(*np));
np->op = op;
np->type = tp;
np->sym = NULL;
np->constant = np->symbol = np->lvalue = 0;
np->left = lp;
np->right = rp;
return np;
}
Node *
varnode(Symbol *sym)
{
Node *np;
np = node(OSYM, sym->type, NULL, NULL);
np->lvalue = 1;
np->constant = 0;
np->symbol = 1;
np->sym = sym;
return np;
}
Node *
constnode(Symbol *sym)
{
Node *np;
np = node(OSYM, sym->type, NULL, NULL);
np->symbol = 1;
np->constant = 1;
np->sym = sym;
return np;
}
Node *
sizeofnode(Type *tp)
{
Node *np;
Symbol *sym;
sym = newsym(NS_IDEN);
sym->type = sizettype;
sym->u.i = tp->size;
return constnode(sym);
}
#define SYMICMP(sym, val) (((sym)->type->sign) ? \
(sym)->u.i == (val) : (sym)->u.u == (val))
#define FOLDINT(sym, ls, rs, op) (((sym)->type->sign) ? \
((sym)->u.i = ((ls)->u.i op (rs)->u.i)) : \
((sym)->u.u = ((ls)->u.u op (rs)->u.u)))
#define CMPISYM(sym, ls, rs, op) (((sym)->type->sign) ? \
((ls)->u.i op (rs)->u.i) : ((ls)->u.u op (rs)->u.u))
Node *
simplify(unsigned char op, Type *tp, Node *lp, Node *rp)
{
Symbol *sym, *ls, *rs, aux;
if (!lp->constant || !rp->constant)
goto no_simplify;
ls = lp->sym, rs = rp->sym;
aux.type = tp;
/* TODO: Add overflow checkings */
if (isnodecmp(op)) {
/*
* Comparision nodes have integer type
* but the operands can have different
* type.
*/
switch (BTYPE(lp)) {
case INT: goto cmp_integers;
case FLOAT: goto cmp_floats;
default: goto no_simplify;
}
}
switch (tp->op) {
case INT:
cmp_integers:
switch (op) {
case OADD:
FOLDINT(&aux, ls, rs, +);
break;
case OSUB:
FOLDINT(&aux, ls, rs, -);
break;
case OMUL:
FOLDINT(&aux, ls, rs, *);
break;
case ODIV:
if (SYMICMP(&aux, 0))
goto division_by_0;
FOLDINT(&aux, ls, rs, /);
break;
case OMOD:
if (SYMICMP(&aux, 0))
goto division_by_0;
FOLDINT(&aux, ls, rs, %);
break;
case OSHL:
FOLDINT(&aux, ls, rs, <<);
break;
case OSHR:
FOLDINT(&aux, ls, rs, >>);
break;
case OBAND:
FOLDINT(&aux, ls, rs, &);
break;
case OBXOR:
FOLDINT(&aux, ls, rs, ^);
break;
case OBOR:
FOLDINT(&aux, ls, rs, |);
break;
case OAND:
FOLDINT(&aux, ls, rs, &&);
break;
case OOR:
FOLDINT(&aux, ls, rs, ||);
break;
case OLT:
aux.u.i = CMPISYM(&aux, ls, rs, <);
break;
case OGT:
aux.u.i = CMPISYM(&aux, ls, rs, >);
break;
case OGE:
aux.u.i = CMPISYM(&aux, ls, rs, >=);
break;
case OLE:
aux.u.i = CMPISYM(&aux, ls, rs, <=);
break;
case OEQ:
aux.u.i = CMPISYM(&aux, ls, rs, ==);
break;
case ONE:
aux.u.i = CMPISYM(&aux, ls, rs, !=);
break;
}
break;
case FLOAT:
cmp_floats:
switch (op) {
case OADD:
aux.u.f = ls->u.f + rs->u.f;
break;
case OSUB:
aux.u.f = ls->u.f - rs->u.f;
break;
case OMUL:
aux.u.f = ls->u.f * rs->u.f;
break;
case ODIV:
if (rs->u.f == 0.0)
goto division_by_0;
aux.u.f = ls->u.f / rs->u.f;
break;
case OLT:
aux.u.i = ls->u.f < rs->u.f;
break;
case OGT:
aux.u.i = ls->u.f > rs->u.f;
break;
case OGE:
aux.u.i = ls->u.f >= rs->u.f;
break;
case OLE:
aux.u.i = ls->u.f <= rs->u.f;
break;
case OEQ:
aux.u.i = ls->u.f == rs->u.f;
break;
case ONE:
aux.u.i = ls->u.f != rs->u.f;
break;
}
break;
default:
goto no_simplify;
}
sym = newsym(NS_IDEN);
sym->type = tp;
sym->u = aux.u;
return constnode(sym);
division_by_0:
warn("division by 0");
no_simplify:
return node(op, tp, lp, rp);
}
#define UFOLDINT(sym, ls, op) (((sym)->type->sign) ? \
((sym)->u.i = (op (ls)->u.i)) : \
((sym)->u.u = (op (ls)->u.u)))
Node *
usimplify(unsigned char op, Type *tp, Node *np)
{
Symbol *sym, *ns, aux;
if (!np->constant)
goto no_simplify;
ns = np->sym;
aux.type = tp;
switch (tp->op) {
case INT:
switch (op) {
case ONEG:
UFOLDINT(&aux, ns, -);
break;
case OCPL:
UFOLDINT(&aux, ns, ~);
break;
default:
goto no_simplify;
}
break;
case FLOAT:
if (op != ONEG)
goto no_simplify;
aux.u.f = -ns->u.f;
break;
default:
goto no_simplify;
}
sym = newsym(NS_IDEN);
sym->type = tp;
sym->u = aux.u;
return constnode(sym);
no_simplify:
return node(op, tp, np, NULL);
}