home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Interactive Guide
/
c-cplusplus-interactive-guide.iso
/
c_ref
/
csource4
/
204_01
/
gencode.c
< prev
next >
Wrap
Text File
|
1979-12-31
|
38KB
|
1,075 lines
#include <stdio.h>
#include "c.h"
#include "expr.h"
#include "gen.h"
#include "cglbdec.h"
/*
* 68000 C compiler
*
* Copyright 1984, 1985, 1986 Matthew Brandt.
* all commercial rights reserved.
*
* This compiler is intended as an instructive tool for personal use. Any
* use for profit without the written consent of the author is prohibited.
*
* This compiler may be distributed freely for non-commercial use as long
* as this notice stays intact. Please forward any enhancements or questions
* to:
*
* Matthew Brandt
* Box 920337
* Norcross, Ga 30092
*/
/*
* this module contains all of the code generation routines
* for evaluating expressions and conditions.
*/
extern struct amode push[], pop[];
struct amode *gen_expr(); /* forward declaration */
struct amode *make_label(lab)
/*
* construct a reference node for an internal label number.
*/
int lab;
{ struct enode *lnode;
struct amode *ap;
lnode = xalloc(sizeof(struct enode));
lnode->nodetype = en_labcon;
lnode->v.i = lab;
ap = xalloc(sizeof(struct amode));
ap->mode = am_direct;
ap->offset = lnode;
return ap;
}
struct amode *make_immed(i)
/*
* make a node to reference an immediate value i.
*/
int i;
{ struct amode *ap;
struct enode *ep;
ep = xalloc(sizeof(struct enode));
ep->nodetype = en_icon;
ep->v.i = i;
ap = xalloc(sizeof(struct amode));
ap->mode = am_immed;
ap->offset = ep;
return ap;
}
struct amode *make_offset(node)
/*
* make a direct reference to a node.
*/
struct enode *node;
{ struct amode *ap;
ap = xalloc(sizeof(struct amode));
ap->mode = am_direct;
ap->offset = node;
return ap;
}
make_legal(ap,flags,size)
/*
* make_legal will coerce the addressing mode in ap1 into a
* mode that is satisfactory for the flag word.
*/
struct amode *ap;
int flags, size;
{ struct amode *ap2;
if( ((flags & F_VOL) == 0) || ap->tempflag )
{
switch( ap->mode )
{
case am_immed:
if( flags & F_IMMED )
return; /* mode ok */
break;
case am_areg:
if( flags & F_AREG )
return;
break;
case am_dreg:
if( flags & F_DREG )
return;
break;
case am_ind: case am_indx:
case am_indx2: case am_xpc:
case am_direct: case am_indx3:
if( flags & F_MEM )
return;
break;
}
}
if( flags & F_DREG )
{
freeop(ap); /* maybe we can use it... */
ap2 = temp_data(); /* allocate to dreg */
gen_code(op_move,size,ap,ap2);
ap->mode = am_dreg;
ap->preg = ap2->preg;
ap->deep = ap2->deep;
ap->tempflag = 1;
return;
}
if( size == 1 )
{
freeop(ap);
ap2 = temp_data();
gen_code(op_move,1,ap,ap2);
gen_code(op_ext,2,ap2,0);
freeop(ap);
ap->mode = ap2->mode;
ap->preg = ap2->preg;
ap->deep = ap2->deep;
size = 2;
}
freeop(ap);
ap2 = temp_addr();
gen_code(op_move,size,ap,ap2);
ap->mode = am_areg;
ap->preg = ap2->preg;
ap->deep = ap2->deep;
ap->tempflag = 1;
}
do_extend(ap,isize,osize,flags)
/*
* if isize is not equal to osize then the operand ap will be
* loaded into a register (if not already) and if osize is
* greater than isize it will be extended to match.
*/
struct amode *ap;
int isize, osize, flags;
{ if( isize == osize )
return;
if( ap->mode != am_areg && ap->mode != am_dreg )
make_legal(ap,flags & (F_AREG | F_DREG),isize);
if( ap->mode == am_areg )
return; /* extend is automagic */
switch( isize )
{
case 1:
gen_code(op_ext,2,ap,0);
case 2:
if( osize == 4 )
gen_code(op_ext,4,ap,0);
}
}
int isshort(node)
/*
* return true if the node passed can be generated as a short
* offset.
*/
struct enode *node;
{ return node->nodetype == en_icon &&
(node->v.i >= -65536 && node->v.i <= 65535);
}
int isbyte(node)
/*
* return true if the node passed can be evaluated as a byte
* offset.
*/
struct enode *node;
{ return node->nodetype == en_icon &&
(-128 <= node->v.i && node->v.i <= 127);
}
struct amode *gen_index(node)
/*
* generate code to evaluate an index node (^+) and return
* the addressing mode of the result. This routine takes no
* flags since it always returns either am_ind or am_indx.
*/
struct enode *node;
{ struct amode *ap1, *ap2;
if( node->v.p[0]->nodetype == en_tempref &&
node->v.p[1]->nodetype == en_tempref &&
( node->v.p[0]->v.i >= 8 || node->v.p[1]->v.i >= 8 ))
{ /* both nodes are registers, one is address */
if( node->v.p[0]->v.i < 8 )
{
ap1 = gen_expr(node->v.p[1],F_AREG,4);
ap1->sreg = node->v.p[0]->v.i;
ap1->mode = am_indx2; /* 0(Ax,Dx) */
ap1->offset = makenode(en_icon,0,0);
return ap1;
}
ap1 = gen_expr(node->v.p[0],F_AREG,4);
ap2 = gen_expr(node->v.p[1],F_AREG | F_DREG,4);
if( ap2->mode == am_dreg )
{
ap1->mode = am_indx2;
ap1->sreg = ap2->preg;
}
else
{
ap1->mode = am_indx3;
ap1->sreg = ap2->preg;
}
ap1->offset = makenode(en_icon,0,0);
return ap1;
}
ap1 = gen_expr(node->v.p[0],F_AREG | F_IMMED,4);
if( ap1->mode == am_immed && isshort(ap1->offset) )
{
ap2 = gen_expr(node->v.p[1],F_AREG,4);
ap2->mode = am_indx;
ap2->offset = ap1->offset;
return ap2;
}
ap2 = gen_expr(node->v.p[1],F_ALL,4); /* get right op */
if( ap2->mode == am_immed && isshort(ap2->offset) &&
ap1->mode == am_areg ) /* make am_indx */
{
ap2->mode = am_indx;
ap2->preg = ap1->preg;
ap2->deep = ap1->deep;
return ap2;
}
validate(ap1);
make_legal(ap1,F_AREG | F_VOL,4);
gen_code(op_add,4,ap2,ap1); /* add left to address reg */
ap1->mode = am_ind; /* make indirect */
freeop(ap2); /* release any temps in ap2 */
return ap1; /* return indirect */
}
struct