home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The C Users' Group Library 1994 August
/
wc-cdrom-cusersgrouplibrary-1994-08.iso
/
vol_300
/
357_01
/
cstar1.exe
/
G3.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-06-18
|
12KB
|
567 lines
/*
C* -- Code generation -- Low level routines.
Routines that start with g_ actually add nodes to the code list.
source: g3.c
started: February 3, 1986
version:
August 5, 1986
March 7, 1989
PUBLIC DOMAIN SOFTWARE
The CSTAR program was placed in the public domain on June 15, 1991,
by its author and sole owner,
Edward K. Ream
1617 Monroe Street
Madison, WI 53711
(608) 257-0802
CSTAR may be used for any commercial or non-commercial purpose.
See cstar.h or cstar.c for a DISCLAIMER OF WARRANTIES.
*/
#include "cstar.h"
#define ps_opcode(op) ((op <= Q_BRN)? xzp_tab[op] : (char *) NULL)
extern int nd_free;
/*
Externally visible routines:
*/
void g_init (void);
void g_line (int i);
void g_lit (char *s);
void g_1lab (int opcode, struct node *p);
void g_2lab (int opcode, struct node *p1, struct node *p2);
void g_0 (int opcode);
void g_1 (int opcode, struct node *p);
void g_1l (int opcode, struct node *p);
void g_1l2 (int opcode, struct node *p);
void g_2 (int opcode, struct node *p1, struct node *p2);
void g_2l1 (int opcode, struct node *p1, struct node *p2);
void g_qmove (struct node *loc1, struct node *loc2);
void g_2l2 (int opcode, struct node *p1, struct node *p2);
void g_label (struct node * p);
int mlen (struct node *p);
/*
Internal routines:
*/
static void gappend (struct node *p);
void
g_init(void)
{
TICK("g_init");
}
void
g_lit(char *s)
{
register struct node *q;
/* Create an op node. */
TRACEPB("g_lit", printf("(%s)\n", s));
q = new_cnode();
q -> c_code = O_LITERAL;
q -> c_lit = s;
/* Append to code list. */
gappend(q);
TICKX("g_lit");
}
void
g_line(int i)
{
register struct node *q;
TRACEPB("g_line", printf("%d\n", i));
/* Create an op node. */
q = new_cnode();
q -> c_code = O_LINENUM;
q -> c_linenum = i;
/* Append to code list. */
gappend(q);
TICKX("g_line");
}
/*
Generate code node for a jump or call to a label.
*/
void
g_1lab(int opcode, struct node *p)
{
register struct node *q;
TRACEPB("g_1lab", printf("(%d, %p)\n", opcode, p));
if (is_qtok(opcode)) {
RETURN_VOID("g_1lab");
}
/* Bump the reference count in the target. */
if (p -> c_code != O_LABEL && p -> c_code != O_ULABEL) {
printf("bad code list code %d\n", p -> c_code);
fatal("g_1lab: bad label type");
}
else {
/* Bump the reference count in the target. */
p -> c_refcount++;
}
/* Create a code node to handle the goto. */
q = new_cnode();
q -> c_code = opcode;
q -> c_arg1 = (void *) p;
/* Append to code list. */
gappend(q);
TICKX("g_1lab");
}
/*
generate code for a location with a call/jump to label
used on 68000 for DBcc Dn, Label, with the location designating
Dn.
*/
void
g_2lab(int opcode, struct node *p1, struct node *p2)
{
register struct node *q;
/* Bump the reference count in the target. */
TRACEPB("g_2lab", printf("(%d, %p, %p)\n", opcode, p1, p2));
if (p2 -> c_code != O_LABEL && p2 -> c_code != O_ULABEL) {
printf("bad code list code %d\n", p2 -> c_code);
fatal("g_2lab: bad label type");
}
else {
/* Bump the reference count in the target. */
p2 -> c_refcount++;
}
/* Create a code node to handle the instruction. */
q = new_cnode();
q -> c_code = opcode;
q -> c_arg1 = p1;
q -> c_arg2 = p2;
/* Append to code list. */
gappend(q);
TICKX("g_2lab");
}
/*
Generate an explicit X_TOK, or a node having an unknown number
of arguments
*/
void
g_x(int op, struct node *arg1, struct node *arg2, byte len)
{
register struct node *q;
/* Create a new code_node. */
TRACEPB("g_x", printf("(%d, %p, %p, %c)\n",
op, arg1, arg2, len));
q = new_cnode();
q -> c_code = op;
q -> c_arg1 = arg1;
q -> c_arg2 = arg2;
q -> c_len1 = len;
/* Append to code list. */
gappend(q);
TICKX("g_x");
}
/*
Generate code node for a 0 argument instruction.
*/
void
g_0(int opcode)
{
register struct node *q;
TRACEPB("g_0", printf("%s (%d)\n", ps_opcode(opcode), opcode));
/* Create an op node. */
q = new_cnode();
q -> c_code = opcode;
/* Append to code list. */
gappend(q);
TICKX("g_0");
}
/*
Generate code node for a 1 argument instruction.
*/
void
g_1(int opcode, struct node *p)
{
register struct node *q;
TRACEPB("g_1",
printf("%s (%d) ", ps_opcode(opcode), opcode);
pr_loc(p); printf("\n"));
/* Create a new code_node. */
q = new_cnode();
q -> c_code = opcode;
q -> c_arg1 = p;
/* Append to code list. */
gappend(q);
TICKX("g_1");
}
/*
Generate code node for a 1 argument instruction involving a length.
*/
void
g_1l(int opcode, struct node *p)
{
register struct node *q;
register struct type_node *t;
TRACEPB("g_1l",
printf("%s (%d) ", ps_opcode(opcode), opcode);
pr_loc(p); printf("\n"));
/* Create a new code_node. */
q = new_cnode();
q -> c_code = opcode;
q -> c_arg1 = p;
t = p -> n_cltype;
switch (t -> t_typtok) {
case INT_TYPE:
case POINTER_TYPE:
q -> c_len1 = (char) t -> t_tsize;
break;
case ARRAY_TYPE:
case STRUCT_TYPE:
q -> c_len1 = POINTER_SIZE;
break;
default:
g_error(p, "g_1l: not int or address");
}
/* Append to code list. */
gappend(q);
TICKX("g_1l");
}
/*
Generate code node for a 1 argument instruction involving a length.
The length is decreased one notch, as for the ext instruction.
*/
void
g_1l2(int opcode, struct node *p)
{
register struct node *q;
register struct type_node *t;
TRACEPB("g_1l2",
printf("%s (%d) ", ps_opcode(opcode), opcode);
pr_loc(p); printf("\n"));
/* Create a new code_node. */
q = new_cnode();
q -> c_code = opcode;
q -> c_arg1 = p;
t = p -> n_cltype;
switch (t -> t_typtok) {
case INT_TYPE:
q -> c_len1 = ((char) t -> t_tsize) >> 1;
break;
default:
g_error(p, "g_1l2: not an int");
}
/* Append to code list. */
gappend(q);
TICKX("g_1l2");
}
/*
Generate code node for a 2 argument instruction.
*/
void
g_2(int opcode, struct node *p1, struct node *p2)
{
register struct node *q;
TRACEPB("g_2",
printf("%s (%d) ", ps_opcode(opcode), opcode);
pr_loc(p1); printf(" "); pr_loc(p2); printf("\n"););
/* Create a new code_node. */
q = new_cnode();
q -> c_code = opcode;
q -> c_arg1 = p1;
q -> c_arg2 = p2;
/* Append to code list. */
gappend(q);
TICKX("g_2");
}
/*
Derive the effective machine length of a locnode
This is not the same as the length of the corresponding
c-language object because arrays and structures stand for
concealed pointer values in the contexts where this is used.
*/
int
mlen(struct node *p)
{
register struct type_node *t;
t = p -> n_cltype;
TRACEPB("mlen",
pr_loc(p); printf("\n");
pr_type(t));
#ifdef DEBUG
if (t == NULL) {
fatal("mlen: untyped loc_node");
}
#endif
switch (t -> t_typtok) {
case INT_TYPE:
RETURN_INT("mlen", (int) t -> t_tsize);
case POINTER_TYPE:
case ARRAY_TYPE:
case STRUCT_TYPE:
RETURN_INT("mlen", POINTER_SIZE);
default:
g_error(NULL, "mlen: not int or address");
RETURN_INT("mlen", POINTER_SIZE);
}
}
/*
Generate code node for a 2 argument instruction involving an
operator length.
*/
void
g_2l1(int opcode, struct node *p1, struct node *p2)
{
register struct node *q;
TRACEPB("g_2l1",
printf("(%s = %d, ", ps_opcode(opcode), opcode);
pr_loc(p1); printf(" ");
pr_loc(p2); printf("\n");
printf("%p, %p); length: %d: type %p: ",
p1, p2, mlen(p1), p1 -> n_cltype);
pr_type(p1 -> n_cltype); printf("\n"));
/* Create a new code_node. */
q = new_cnode();
q -> c_code = opcode;
q -> c_arg1 = p1;
q -> c_arg2 = p2;
q -> c_len1 = (char) mlen(p1);
/* Append to code list. */
gappend(q);
TICKX("g_2l1");
}
/*
Generate code node for a possibly quick move
This handles cases that the peephole (ultimately the opcode
assigner) can't for one reason or another; e.g. the
EXCESSLENOK option allows the semantics to be changed.
Take length from the SOURCE operand, which must be properly
massaged
*/
void
g_qmove(register struct node *loc1, register struct node *loc2)
{
register struct node *q;
register struct st_node *id;
register long i_cnst;
int f;
/* Create a new code_node. */
TRACEPB("g_qmove", printf("(%p, %p)\n", loc1, loc2));
q = new_cnode();
q -> c_code = X_MOVE;
q -> c_arg1 = loc1;
q -> c_arg2 = loc2;
q -> c_len1 = (char) mlen(loc1);
/* Append to code list. */
gappend(q);
if (is_cloc(loc1) && (
#if EXCESSLENOK
/* if it is allowed to clobber upper part of dreg */
(f = is_dloc(loc2)) ||
#endif
/* if it's faster to load via an available dreg */
(nd_free && loc2 -> n_mode != VALUE_MODE && mlen(loc2) == 4) )
) {
i_cnst = loc1 -> n_const;
if (id = loc1 -> n_cid) {
if (is_rstack(id -> st_sclass) ||
id->st_sclass == SUE_CLASS) {
/* i_cnst is now the true constant */
i_cnst += id -> st_offset;
}
else {
/* true constant is label and therefore unknown */
/* prevent the operation */
i_cnst = 256;
}
}
if (i_cnst <= 127 && i_cnst >= -128) {
q -> c_code = X_MOVEQ;
q -> c_len1 = 0;
if (!f) {
/* load a non-value location by loading quick
a dreg and moving that to the loc */
q -> c_arg2 = get_dtemp();
g_2l2(X_MOVE, q -> c_arg2, loc2);
free_temp(q -> c_arg2);
}
}
}
TICKX("g_qmove");
}
/*
Generate code node for a 2 argument instruction involving an
operator length.
*/
void
g_2l2(int opcode, struct node *p1, struct node *p2)
{
register struct node *q;
TRACEPB("g_2",
printf("%s (%d) ", ps_opcode(opcode), opcode);
pr_loc(p1); printf(" ");
pr_loc(p2); printf("\n"));
/* Create a new code_node. */
q = new_cnode();
q -> c_code = opcode;
q -> c_arg1 = p1;
q -> c_arg2 = p2;
q -> c_len1 = (char) mlen(p2);
/* Append to code list. */
gappend(q);
TICKX("g_2");
}
/*
----- L A B E L R O U T I N E S ----
Label nodes are created during code generation to represent all labels
generated by the program. Label nodes are created when first
referenced and are linked into the code linked when and if needed.
Label nodes contain a reference count field so that unneeded labels are
not output.
Internal (non-user) label nodes contain a count used eventually to
generate a unique label. The count needs to be assigned when the label
is first generated so that jumps to the label can be output before the
label is actually output.
*/
/*
Link the label node into the code list.
*/
void
g_label(struct node * p)
{
TRACEPB("g_label", printf("(%p)\n", p));
if (p -> c_code != O_LABEL && p -> c_code != O_ULABEL) {
printf("bad label type %d\n", p -> c_code);
fatal("g_label: bad label type");
}
TRACEP("g_label",
if (p -> c_code == O_LABEL) {
printf("L%d:\n", p -> c_labnum);
}
else {
printf("%s:\n", p -> c_labsym);
}) /* End of TRACE macro. */
/* Append to code list. */
gappend(p);
TICKX("g_label");
}
/*
Append a single code node to the end of the global code list.
*/
static void
gappend(struct node *p)
{
TRACEP("gappend",
printf("(%p)\n", p);
out_list(p));
if (p == NULL) {
return;
}
else if (code_head == NULL) {
code_head = p;
code_tail = p;
}
else {
p -> c_back = code_tail;
code_tail -> c_next = p;
code_tail = p;
}
}