518 lines
9.9 KiB
C
518 lines
9.9 KiB
C
/*
|
|
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
|
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
|
*/
|
|
#ifndef NORCSID
|
|
static char rcsid[] = "$Id$";
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "param.h"
|
|
#include "reg.h"
|
|
#include "lookup.h"
|
|
#include "property.h"
|
|
#include "expr.h"
|
|
#include "set.h"
|
|
#include "varinfo.h"
|
|
#include "instruct.h"
|
|
#include "token.h"
|
|
#include "regvar.h"
|
|
#include <cgg_cg.h>
|
|
#include <em_reg.h>
|
|
#include "subr.h"
|
|
#include "hall.h"
|
|
#include "extern.h"
|
|
|
|
extern int npatbytes;
|
|
extern set_t l_sets[];
|
|
|
|
|
|
void n_proc(char *name)
|
|
{
|
|
register symbol *sy_p;
|
|
|
|
sy_p = lookup(name, symproc, newsymbol);
|
|
sy_p->sy_value.syv_procoff = npatbytes + 1;
|
|
}
|
|
|
|
struct varinfo * make_erase(char *name)
|
|
{
|
|
expr_t e;
|
|
struct varinfo *result;
|
|
|
|
e = ident_expr(name);
|
|
if (e.ex_typ != TYPREG)
|
|
error("Register name required here");
|
|
NEW(result, struct varinfo);
|
|
result->vi_next = VI_NULL;
|
|
result->vi_int[0] = e.ex_index;
|
|
return (result);
|
|
}
|
|
|
|
void n_instr(char *name, char *asname, operand *oplist, struct varinfo *eraselist,
|
|
struct varinfo *cost)
|
|
{
|
|
register int instrno;
|
|
register int cc_count;
|
|
register instr_p ip;
|
|
|
|
instrno = NEXT(ninstr, MAXINSTR, "Instructions");
|
|
ip = &l_instr[instrno];
|
|
ip->i_name = name;
|
|
ip->i_asname = strlookup(asname != 0 ? asname : name);
|
|
ip->i_nops = 0;
|
|
ip->i_oplist = oplist;
|
|
ip->i_erases = eraselist;
|
|
if (cost == 0)
|
|
{
|
|
ip->i_cost.ct_space = 0;
|
|
ip->i_cost.ct_time = 0;
|
|
}
|
|
else
|
|
{
|
|
ip->i_cost.ct_space = cost->vi_int[0];
|
|
ip->i_cost.ct_space = cost->vi_int[1];
|
|
}
|
|
for (cc_count = 0; oplist != 0; oplist = oplist->o_next)
|
|
{
|
|
ip->i_nops++;
|
|
if (oplist->o_adorn & AD_CC)
|
|
cc_count++;
|
|
}
|
|
while (eraselist != VI_NULL )
|
|
{
|
|
if (eraselist->vi_int[0] == -1 && cc_count)
|
|
error("Instruction can't both set and break the condition codes");
|
|
eraselist = eraselist->vi_next;
|
|
}
|
|
if (cc_count > 1)
|
|
error("No instruction can set condition codes more than once");
|
|
}
|
|
|
|
void n_set(char *name, int number)
|
|
{
|
|
register symbol *sy_p;
|
|
|
|
sy_p = lookup(name, symset, newsymbol);
|
|
sy_p->sy_value.syv_setno = number;
|
|
}
|
|
|
|
void n_tok(char *name, struct varinfo *atts, int size,
|
|
struct varinfo *cost, struct varinfo *format)
|
|
{
|
|
register symbol *sy_p;
|
|
register token_p tp;
|
|
register struct varinfo *vip;
|
|
int i;
|
|
int tokno;
|
|
int thistokensize;
|
|
char formstr[50], smallstr[2];
|
|
|
|
sy_p = lookup(name, symtok, newsymbol);
|
|
NEW(tp, token_t);
|
|
tokno = NEXT(ntokens, MAXTOKENS, "Tokens");
|
|
sy_p->sy_value.syv_tokno = tokno;
|
|
l_tokens[tokno] = tp;
|
|
tp->tk_name = sy_p->sy_name;
|
|
tp->tk_size = size;
|
|
if (cost != 0)
|
|
{
|
|
tp->tk_cost.ct_space = cost->vi_int[0];
|
|
tp->tk_cost.ct_time = cost->vi_int[1];
|
|
}
|
|
else
|
|
{
|
|
tp->tk_cost.ct_space = 0;
|
|
tp->tk_cost.ct_time = 0;
|
|
}
|
|
for (i = 0, vip = atts; i < MAXATT && vip != 0; i++, vip = vip->vi_next)
|
|
{
|
|
tp->tk_att[i].ta_type = vip->vi_int[0];
|
|
tp->tk_att[i].ta_name = vip->vi_str[0];
|
|
vip->vi_str[0] = 0;
|
|
}
|
|
thistokensize = i;
|
|
if (i > maxtokensize)
|
|
maxtokensize = i;
|
|
if (vip != 0)
|
|
error("More then %d attributes, rest discarded", MAXATT);
|
|
for (; i < MAXATT; i++)
|
|
tp->tk_att[i].ta_type = -3;
|
|
if (format != 0)
|
|
{
|
|
formstr[0] = 0;
|
|
for (vip = format; vip != 0; vip = vip->vi_next)
|
|
{
|
|
if (vip->vi_int[0] == 0)
|
|
strcat(formstr, vip->vi_str[0]);
|
|
else
|
|
{
|
|
for (i = 0; i < thistokensize; i++)
|
|
{
|
|
if (strcmp(vip->vi_str[0], tp->tk_att[i].ta_name) == 0)
|
|
{
|
|
smallstr[0] = i + 1;
|
|
smallstr[1] = 0;
|
|
strcat(formstr, smallstr);
|
|
break;
|
|
}
|
|
}
|
|
if (i == thistokensize)
|
|
error("%s not a known attribute", vip->vi_str[0]);
|
|
}
|
|
}
|
|
tp->tk_format = strlookup(formstr);
|
|
}
|
|
else
|
|
tp->tk_format = -1;
|
|
}
|
|
|
|
void checkprintformat(int n)
|
|
{
|
|
register short *s;
|
|
register int i;
|
|
|
|
s = l_sets[n].set_val;
|
|
for (i = nregs; i < nregs + ntokens; i++)
|
|
if (BIT(s,i) && l_tokens[i - nregs]->tk_format < 0)
|
|
error("Token %s in set does not have printformat",
|
|
l_tokens[i - nregs]->tk_name);
|
|
}
|
|
|
|
void n_prop(char *name, int size)
|
|
{
|
|
int propno;
|
|
register symbol *sp;
|
|
|
|
propno = NEXT(nprops, MAXPROPS, "Properties");
|
|
sp = lookup(name, symprop, newsymbol);
|
|
sp->sy_value.syv_propno = propno;
|
|
if (size <= 0)
|
|
{
|
|
error("Size of property must be >0");
|
|
size = wordsize;
|
|
}
|
|
l_props[propno].pr_size = size;
|
|
}
|
|
|
|
void prophall(int n)
|
|
{
|
|
register int i;
|
|
short hallset[SETSIZE];
|
|
|
|
if (n < 0)
|
|
return;
|
|
for (i = 0; i < SETSIZE; i++)
|
|
hallset[i] = i < SZOFSET(MAXREGS) ? l_props[n].pr_regset[i] : 0;
|
|
nexthall(hallset);
|
|
}
|
|
|
|
int n_reg(char *name, char *printstring, int nmemb, int member1, int member2)
|
|
{
|
|
register symbol *sy_p;
|
|
register reginfo *ri_p;
|
|
int regno;
|
|
|
|
sy_p = lookup(name, symreg, newsymbol);
|
|
sy_p->sy_value.syv_regno = regno = NEXT(nregs, MAXREGS,
|
|
"Number of registers");
|
|
ri_p = &l_regs[regno];
|
|
ri_p->ri_name = mystrcpy(name);
|
|
ri_p->ri_repr = printstring != 0 ? mystrcpy(printstring) : ri_p->ri_name;
|
|
ri_p->ri_memb[0] = member1;
|
|
ri_p->ri_memb[1] = member2;
|
|
if (nmemb > maxmembers)
|
|
maxmembers = nmemb;
|
|
return (regno);
|
|
}
|
|
|
|
void make_const(void)
|
|
{
|
|
|
|
wordsize = cmustbeset("EM_WSIZE");
|
|
pointersize = cmustbeset("EM_PSIZE");
|
|
}
|
|
|
|
int cmustbeset(char *ident)
|
|
{
|
|
|
|
return (lookup(ident, symconst, mustexist)->sy_value.syv_cstval);
|
|
}
|
|
|
|
void n_const(char *ident, int val)
|
|
{
|
|
register symbol *sy_p;
|
|
|
|
sy_p = lookup(ident, symconst, newsymbol);
|
|
sy_p->sy_value.syv_cstval = val;
|
|
}
|
|
|
|
void n_sconst(char *ident, char *val)
|
|
{
|
|
register symbol *sy_p;
|
|
|
|
sy_p = lookup(ident, symsconst, newsymbol);
|
|
sy_p->sy_value.syv_stringno = strlookup(val);
|
|
}
|
|
|
|
static void add_regvar(int rvnum, reginfo *regp, int rv)
|
|
{
|
|
int overlap, wrong;
|
|
|
|
overlap = wrong = 0;
|
|
if (regp->ri_memb[0] != 0)
|
|
{
|
|
/* reglap: float may overlap with one subregister */
|
|
if (rv == reg_float && regp->ri_memb[1] == 0)
|
|
overlap = 1;
|
|
else
|
|
wrong = 1;
|
|
}
|
|
if (wrong)
|
|
error("Register variables may not have subregisters");
|
|
|
|
rvused |= ANY_REGVAR;
|
|
if (regp->ri_size == wordsize)
|
|
rvused |= SL_REGVAR;
|
|
else if (regp->ri_size == 2 * wordsize)
|
|
rvused |= DL_REGVAR;
|
|
|
|
wrong = 0;
|
|
if (overlap)
|
|
{
|
|
/* reglap = size of overlap float */
|
|
if (reglap == 0)
|
|
{
|
|
reglap = regp->ri_size;
|
|
if (reglap == rvsize[reg_float])
|
|
error("Two sizes of reg_float can't be same size");
|
|
}
|
|
else if (reglap != regp->ri_size)
|
|
wrong = 1;
|
|
}
|
|
else
|
|
{
|
|
if (nregvar[rv] == 0)
|
|
rvsize[rv] = regp->ri_size;
|
|
else if (rvsize[rv] != regp->ri_size)
|
|
wrong = 1;
|
|
}
|
|
if (wrong)
|
|
error("All register variables of one type must have the same size");
|
|
|
|
if (overlap)
|
|
{
|
|
reginfo *member_p = &l_regs[regp->ri_memb[0]];
|
|
int i;
|
|
|
|
/*
|
|
* reglap: Remove member_p from rvnumbers.
|
|
* Add reg_p in its place.
|
|
*/
|
|
wrong = 1;
|
|
for (i = 0; i < nregvar[rv]; i++)
|
|
{
|
|
if (rvnumbers[rv][i] == regp->ri_memb[0])
|
|
{
|
|
rvnumbers[rv][i] = rvnum;
|
|
wrong = 0;
|
|
break;
|
|
}
|
|
}
|
|
if (wrong)
|
|
error("Register variable %s can't overlap %s", regp->ri_name,
|
|
member_p->ri_name);
|
|
}
|
|
else
|
|
{
|
|
NEXT(nregvar[rv], MAXREGVAR, "Register variable");
|
|
rvnumbers[rv][nregvar[rv] - 1] = rvnum;
|
|
}
|
|
}
|
|
|
|
void regline(varinfo *rl, varinfo *pl, int rv)
|
|
{
|
|
register varinfo *rrl, *rpl;
|
|
register short *sp;
|
|
register reginfo *regp;
|
|
int thissize;
|
|
int propno;
|
|
|
|
for (rrl = rl; rrl != 0; rrl = rrl->vi_next)
|
|
{
|
|
regp = &l_regs[rrl->vi_int[0]];
|
|
thissize = 0;
|
|
for (rpl = pl; rpl != 0; rpl = rpl->vi_next)
|
|
{
|
|
propno = rpl->vi_int[0];
|
|
sp = l_props[propno].pr_regset;
|
|
BIS(sp, rrl->vi_int[0]);
|
|
if (thissize == 0)
|
|
thissize = l_props[propno].pr_size;
|
|
else if (thissize != -1 && thissize != l_props[propno].pr_size)
|
|
error("Register %s has no clear size", regp->ri_name);
|
|
}
|
|
regp->ri_size = thissize;
|
|
regp->ri_class = regclass;
|
|
regp->ri_rregvar = rv;
|
|
if (rv >= 0)
|
|
add_regvar(rrl->vi_int[0], regp, rv);
|
|
}
|
|
regclass++;
|
|
}
|
|
|
|
void check_reglap(void)
|
|
{
|
|
reginfo *regp;
|
|
int i;
|
|
|
|
if (reglap == 0)
|
|
return;
|
|
|
|
/* reglap: Check that every reg_float has size == reglap. */
|
|
for (i = 0; i < nregvar[reg_float]; i++)
|
|
{
|
|
regp = &l_regs[rvnumbers[reg_float][i]];
|
|
if (regp->ri_size != reglap)
|
|
error("Missing reg_float of size %d to contain %s", reglap,
|
|
regp->ri_name);
|
|
}
|
|
}
|
|
|
|
void setallreg(struct varinfo *vi)
|
|
{
|
|
|
|
nallreg = 0;
|
|
for (; vi != 0; vi = vi->vi_next)
|
|
{
|
|
if (vi->vi_int[0] < 0)
|
|
continue;
|
|
allreg[nallreg++] = vi->vi_int[0];
|
|
}
|
|
}
|
|
|
|
void freevi(register struct varinfo *vip)
|
|
{
|
|
register int i;
|
|
|
|
if (vip == 0)
|
|
return;
|
|
freevi(vip->vi_next);
|
|
freevi(vip->vi_vi);
|
|
for (i = 0; i < VI_NSTR; i++)
|
|
free((char *) vip->vi_str[i]);
|
|
free(vip);
|
|
}
|
|
|
|
int myatoi(register char *s)
|
|
{
|
|
register int base = 10;
|
|
register int sum = 0;
|
|
|
|
if (*s == '0')
|
|
{
|
|
base = 8;
|
|
s++;
|
|
if (*s == 'x')
|
|
{
|
|
base = 16;
|
|
s++;
|
|
}
|
|
}
|
|
for (;;)
|
|
{
|
|
switch (*s)
|
|
{
|
|
default:
|
|
return (sum);
|
|
case '8':
|
|
case '9':
|
|
if (base == 8)
|
|
error("Bad digit in octal number");
|
|
case '0':
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
sum = sum * base + *s++ - '0';
|
|
break;
|
|
case 'a':
|
|
case 'b':
|
|
case 'c':
|
|
case 'd':
|
|
case 'e':
|
|
case 'f':
|
|
if (base != 16)
|
|
error("Hexletter in number not expected");
|
|
sum = sum * base + 10 + *s++ - 'a';
|
|
break;
|
|
case 'A':
|
|
case 'B':
|
|
case 'C':
|
|
case 'D':
|
|
case 'E':
|
|
case 'F':
|
|
if (base != 16)
|
|
error("Hexletter in number not expected");
|
|
sum = sum * base + 10 + *s++ - 'A';
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
char *mystrcpy(char *s)
|
|
{
|
|
register char *p;
|
|
|
|
p = myalloc(strlen(s) + 1);
|
|
strcpy(p, s);
|
|
return (p);
|
|
}
|
|
|
|
char *myalloc(register int n)
|
|
{
|
|
register char *p, *result;
|
|
|
|
result = p = malloc(n);
|
|
if (p == (char *) 0)
|
|
fatal("Out of memory");
|
|
do
|
|
*p++ = 0;
|
|
while (--n);
|
|
return (result);
|
|
}
|
|
|
|
int chkincl(int value, int lwb, int upb)
|
|
{
|
|
|
|
if (value < lwb || value > upb)
|
|
error("Number %d should have been between %d and %d", value, lwb, upb);
|
|
return (value);
|
|
}
|
|
|
|
int subset(short *sp1, short *sp2, int setsize)
|
|
{
|
|
register int i;
|
|
|
|
for (i = 0; i < setsize; i++)
|
|
if ((sp1[i] | sp2[i]) != sp2[i])
|
|
return (0);
|
|
return (1);
|
|
}
|
|
|
|
int vilength(register struct varinfo *vip)
|
|
{
|
|
register int l = 0;
|
|
|
|
while (vip != 0)
|
|
{
|
|
vip = vip->vi_next;
|
|
l++;
|
|
}
|
|
return (l);
|
|
}
|