home *** CD-ROM | disk | FTP | other *** search
- /*
- * 68K/386 32-bit C compiler.
- *
- * copyright (c) 1996, David Lindauer
- *
- * This compiler is intended for educational use. It may not be used
- * for profit without the express written consent of the author.
- *
- * It may be freely redistributed, as long as this notice remains intact
- * and sources are distributed along with any executables derived from them.
- *
- * The author is not responsible for damages, either direct or consequential,
- * that may arise from use of this software.
- *
- * v1.5 August 1996
- * David Lindauer, gclind01@starbase.spd.louisville.edu
- *
- * Credits to Mathew Brandt for original K&R C compiler
- *
- */
- #include <stdio.h>
- #include "expr.h"
- #include "c.h"
- #include "gen.h"
- #include "cglbdec.h"
-
- /* pc-relative expressions not optimized */
- extern AMODE push[], pop[];
- extern OCODE *peep_tail;
- extern OCODE *entryref;
- extern SYM *currentfunc;
- extern int prm_stackcheck;
-
- extern long framedepth,stackdepth;
-
- int floatregs = 1,dataregs=1,addrregs = 1;
- /*
- * this module will step through the parse tree and find all
- * optimizable expressions. at present these expressions are
- * limited to expressions that are valid throughout the scope
- * of the function. the list of optimizable expressions is:
- *
- * constants
- * global and static addresses
- * auto addresses
- * contents of auto addresses.
- *
- * contents of auto addresses are valid only if the address is
- * never referred to without dereferencing.
- *
- * scan will build a list of optimizable expressions which
- * opt1 will replace during the second optimization pass.
- */
-
- static CSE *olist; /* list of optimizable expressions */
-
- int equalnode(ENODE *node1, ENODE *node2)
- /*
- * equalnode will return 1 if the expressions pointed to by
- * node1 and node2 are equivalent.
- */
- { if( node1 == 0 || node2 == 0 )
- return 0;
- if( node1->nodetype != node2->nodetype )
- return 0;
- if( (node1->nodetype == en_icon || node1->nodetype == en_labcon ||
- node1->nodetype == en_nalabcon || node1->nodetype == en_autoreg ||
- node1->nodetype == en_nacon || node1->nodetype == en_napccon
- || node1->nodetype == en_autocon || node1->nodetype == en_absacon) &&
- node1->v.i == node2->v.i )
- return 1;
- if (node1->nodetype == en_rcon && node1->v.f == node2->v.f)
- return 1;
- if( lvalue(node1) && equalnode(node1->v.p[0], node2->v.p[0]) )
- return 1;
- return 0;
- }
-
- CSE *searchnode(ENODE *node)
- /*
- * searchnode will search the common expression table for an entry
- * that matches the node passed and return a pointer to it.
- */
- { CSE *csp;
- csp = olist;
- while( csp != 0 ) {
- if( equalnode(node,csp->exp) )
- return csp;
- csp = csp->next;
- }
- return 0;
- }
-
- ENODE *copynode(ENODE *node)
- /*
- * copy the node passed into a new enode so it wont get
- * corrupted during substitution.
- */
- { ENODE *temp;
- if( node == 0 )
- return 0;
- temp = xalloc(sizeof(ENODE));
- temp->cflags = node->cflags;
- temp->nodetype = node->nodetype;
- temp->v.p[0] = node->v.p[0];
- temp->v.p[1] = node->v.p[1];
- return temp;
- }
-
- CSE *enternode(ENODE *node,int duse,int size)
- /*
- * enternode will enter a reference to an expression node into the
- * common expression table. duse is a flag indicating whether or not
- * this reference will be dereferenced.
- */
- { CSE *csp;
- if (size == 0)
- size = natural_size(node);
- if( (csp = searchnode(node)) == 0 ) { /* add to tree */
- csp = xalloc(sizeof(CSE));
- csp->next = olist;
- csp->uses = 1;
- csp->reg = -1;
- csp->duses = (duse != 0);
- csp->exp = copynode(node);
- csp->voidf = 0;
- csp->size = size;
- olist = csp;
- return csp;
- }
- else
- if (chksize(csp->size,size))
- csp->size = size;
- ++(csp->uses);
- if( duse )
- ++(csp->duses);
- return csp;
- }
-
- CSE *voidauto(ENODE *node)
- /*
- * voidauto will void an auto dereference node which points to
- * the same auto constant as node.
- */
- { CSE *csp;
- csp = olist;
- while( csp != 0 ) {
- if( lvalue(csp->exp) && equalnode(node,csp->exp->v.p[0]) ) {
- if( csp->voidf )
- return 0;
- csp->voidf = 1;
- return csp;
- }
- csp = csp->next;
- }
- return 0;
- }
-
- void scanexpr(ENODE *node, int duse,int size)
- /*
- * scanexpr will scan the expression pointed to by node for optimizable
- * subexpressions. when an optimizable expression is found it is entered
- * into the tree. if a reference to an autocon node is scanned the
- * corresponding auto dereferenced node will be voided. duse should be
- * set if the expression will be dereferenced.
- */
- { CSE *csp, *csp1;
- if( node == 0 )
- return;
- switch( node->nodetype ) {
- case en_rcon:
- case en_icon:
- case en_nalabcon:
- case en_napccon:
- case en_nacon:
- case en_absacon:
- enternode(node,duse,size);
- break;
- case en_autocon:
- case en_autoreg:
- if( (csp = voidauto(node)) != 0 ) {
- csp1 = enternode(node,duse,size);
- if (csp)
- csp1->uses = (csp1->duses += csp->uses);
- }
- else
- enternode(node,duse,size);
- break;
- case en_bits:
- scanexpr(node->v.p[0],duse,0);
- break;
- case en_floatref:
- case en_doubleref:
- case en_longdoubleref:
- case en_b_ref:
- case en_w_ref:
- case en_ul_ref:
- case en_l_ref:
- case en_ub_ref:
- case en_uw_ref:
- if( node->v.p[0]->nodetype == en_autocon
- || node->v.p[0]->nodetype == en_autoreg ) {
- csp = enternode(node,duse,size);
- if( csp && csp->voidf )
- scanexpr(node->v.p[0],1,0);
- }
-
- else
- scanexpr(node->v.p[0],1,0);
- break;
- case en_uminus:
- case en_compl: case en_ainc:
- case en_adec: case en_not:
- case en_cb: case en_cub:
- case en_cw: case en_cuw:
- case en_cl: case en_cul:
- case en_cf: case en_cd: case en_cp: case en_cld:
- scanexpr(node->v.p[0],duse,0);
- break;
- case en_asadd: case en_assub:
- size = natural_size(node->v.p[0]);
- scanexpr(node->v.p[0],duse,0);
- scanexpr(node->v.p[1],duse,size);
- break;
- case en_add: case en_sub:
- scanexpr(node->v.p[0],duse,0);
- scanexpr(node->v.p[1],duse,0);
- break;
- case en_asalsh: case en_asarsh: case en_alsh: case en_arsh:
- case en_asmul: case en_asdiv:
- case en_asmod: case en_aslsh:
- case en_asumod: case en_asudiv: case en_asumul:
- case en_asrsh: case en_asand:
- case en_assign: case en_refassign:
- size = natural_size(node->v.p[0]);
- scanexpr(node->v.p[0],0,0);
- scanexpr(node->v.p[1],0,size);
- break;
- case en_void:
- case en_pmul: case en_pdiv:
- case en_mul: case en_div:
- case en_umul: case en_udiv: case en_umod:
- case en_lsh: case en_rsh:
- case en_mod: case en_and:
- case en_or: case en_xor:
- case en_lor: case en_land:
- case en_eq: case en_ne:
- case en_gt: case en_ge:
- case en_lt: case en_le:
- case en_ugt: case en_uge: case en_ult: case en_ule:
- case en_asor: case en_cond:
- case en_moveblock: case en_stackblock: case en_callblock:
- scanexpr(node->v.p[0],0,0);
- scanexpr(node->v.p[1],0,0);
- break;
- case en_fcall: case en_intcall: case en_fcallb:
- case en_trapcall:
- scanexpr(node->v.p[0],1,0);
- scanexpr(node->v.p[1],0,0);
- break;
- }
- }
-
- void scan(SNODE *block)
- /*
- * scan will gather all optimizable expressions into the expression
- * list for a block of statements.
- */
- { while( block != 0 ) {
- switch( block->stype ) {
- case st_return:
- case st_expr:
- opt4(&block->exp);
- scanexpr(block->exp,0,0);
- break;
- case st_while:
- case st_do:
- opt4(&block->exp);
- scanexpr(block->exp,0,0);
- scan(block->s1);
- break;
- case st_for:
- opt4(&block->label);
- scanexpr(block->label,0,0);
- opt4(&block->exp);
- scanexpr(block->exp,0,0);
- scan(block->s1);
- opt4(&block->s2);
- scanexpr(block->s2,0,0);
- break;
- case st_if:
- opt4(&block->exp);
- scanexpr(block->exp,0,0);
- scan(block->s1);
- scan(block->s2);
- break;
- case st_switch:
- opt4(&block->exp);
- scanexpr(block->exp,0,0);
- scan(block->s1);
- break;
- case st_case:
- scan(block->s1);
- break;
- case st_block:
- scan(block->exp);
- break;
- }
- block = block->next;
- }
- }
-
- void exchange(CSE **c1)
- /*
- * exchange will exchange the order of two expression entries
- * following c1 in the linked list.
- */
- { CSE *csp1, *csp2;
- csp1 = *c1;
- csp2 = csp1->next;
- csp1->next = csp2->next;
- csp2->next = csp1;
- *c1 = csp2;
- }
-
- int desire(CSE *csp)
- /*
- * returns the desirability of optimization for a subexpression.
- */
- { if( csp->voidf || (csp->exp->nodetype == en_icon &&
- csp->exp->v.i < 16 && csp->exp->v.i >= 0))
- return 0;
- if( lvalue(csp->exp) )
- return 2 * csp->uses;
- return csp->uses;
- }
-
- int bsort(CSE **list)
- /*
- * bsort implements a bubble sort on the expression list.
- */
- { CSE *csp1, *csp2;
- csp1 = *list;
- if( csp1 == 0 || csp1->next == 0 )
- return 0;
- bsort( &(csp1->next));
- csp2 = csp1->next;
- if( desire(csp1) < desire(csp2) ) {
- exchange(list);
- return 1;
- }
- return 0;
- }
- void reserveregs(int *datareg, int *addreg, int *floatreg)
- /*
- * Reserve regs goes through and reserves a register for variables with
- * the REGISTER keyword. Note that it currently does register allocation
- * backwards...
- */
- {
- CSE *csp = olist;
-
- while (csp) {
- switch (csp->exp->nodetype) {
- case en_floatref:
- case en_doubleref:
- case en_longdoubleref:
- #ifdef i386
- break;
- #endif
- case en_b_ref:
- case en_w_ref:
- case en_l_ref:
- case en_ub_ref:
- case en_uw_ref:
- case en_ul_ref:
- if (csp->exp->v.p[0]->nodetype != en_autoreg)
- break;
- case en_autoreg:
- if (csp->exp->nodetype == en_floatref || csp->exp->nodetype == en_doubleref
- || csp->exp->nodetype == en_longdoubleref) {
- #ifndef i386
- if (*floatreg <24 && floatregs)
- csp->reg = (*floatreg)++;
- #endif
- }
- #ifdef i386
- else if( (csp->duses <= csp->uses / 4) && (*datareg < MAXDATA) &&dataregs)
- csp->reg = (*datareg)++;
- else if(( csp->size > 2 || csp->size <-2) && (*addreg < MAXADDRESS) && addrregs) {
- csp->reg = (*addreg)++;
- }
- #else
- else if( (*datareg < MAXDATA) && (csp->duses <= csp->uses/4) && dataregs)
- csp->reg = (*datareg)++;
- else if((csp->size > 1 || csp->size < -1) && (*addreg < MAXADDRESS) &&addrregs)
- csp->reg = (*addreg)++;
- #endif
- break;
- }
- csp = csp->next;
- }
- }
-
- void allocate(int datareg, int addreg, int floatreg )
- /*
- * allocate will allocate registers for the expressions that have
- * a high enough desirability.
- */
- { CSE *csp;
- ENODE *exptr;
- unsigned mask, rmask,i,fmask,frmask,size;
- AMODE *ap, *ap2;
- framedepth = 4;
- mask = 0;
- rmask = 0;
- fmask = frmask = 0;
- for (i=FREEDATA; i < datareg; i++) {
- rmask = rmask | (1 << (15 - i));
- mask = mask | (1 << i);
- }
- for (i=FREEADDRESS+8; i < addreg; i++) {
- rmask = rmask | (1 << (15 - i));
- mask = mask | (1 << i);
- }
- while( bsort(&olist) ); /* sort the expression list */
- csp = olist;
- while( csp != 0 ) {
- if (csp->reg == -1 && !(csp->exp->cflags & DF_VOL)) {
- if( desire(csp) < 3 )
- csp->reg = -1;
- else {
- if (csp->exp->nodetype == en_rcon
- || csp->exp->nodetype == en_floatref || csp->exp->nodetype ==en_doubleref
- || csp->exp->nodetype == en_longdoubleref) {
- #ifndef i386
- if (floatreg <24 && floatregs)
- csp->reg = floatreg++;
- #endif
- }
- #ifdef i386
- else if( (csp->duses <= csp->uses / 4) && (datareg < MAXDATA) &&dataregs)
- csp->reg = (datareg)++;
- else if(( csp->size >2 || csp->size < -2) && (addreg < MAXADDRESS) && addrregs) {
- csp->reg = (addreg)++;
- }
- #else
- else if( (datareg < MAXDATA) && (csp->duses <= csp->uses/4) && dataregs)
- csp->reg = (datareg)++;
- else if( (csp->size > 1 || csp->size < -1) && (addreg < MAXADDRESS) &&addrregs)
- csp->reg = (addreg)++;
- #endif
- }
- }
- if( csp->reg != -1 )
- {
- if (csp->reg < 16) {
- rmask = rmask | (1 << (15 - csp->reg));
- mask = mask | (1 << csp->reg);
- }
- else {
- frmask = frmask | (1 << (23 - csp->reg));
- fmask = fmask | (1 << (csp->reg-16));
- }
- }
- csp = csp->next;
- }
- #ifndef i386
- if (currentfunc->tp->lst.head !=0 && currentfunc->tp->lst.head != (SYM *)-1) {
- mask |= (1 << (LINKREG +8));
- rmask |= (1 << (15 - LINKREG -8));
- if (currentfunc->intflag) {
- mask |= 0x307;
- rmask |= 0xe0c0;
- }
- }
- #endif
- #ifdef i386
- if (currentfunc->intflag)
- gen_code(op_pushad,0,0,0);
- else
- #endif i386
- if( mask != 0 )
- #ifdef i386
- pushregs(rmask);
- #else
- gen_code(op_movem,4,make_mask(rmask,0,0),push);
- #endif
- save_mask = mask;
- if (fmask!=0)
- #ifndef i386
- gen_code(op_fmovem,10,make_mask(frmask,0,1),push);
- #endif
- fsave_mask = fmask;
- #ifndef i386
- if (mask & (1<<(LINKREG+8)))
- gen_code(op_move,4,makeareg(0), makeareg(LINKREG));
- #endif
-
- #ifdef i386
- gen_code(op_sub,4,makedreg(ESP), make_immed(lc_maxauto));
- stackdepth +=lc_maxauto;
- framedepth +=stackdepth;
- stackdepth = 0;
- #else
- gen_code(op_sub,4,make_immed(lc_maxauto), makeareg(7));
- #endif
- entryref = peep_tail;
- if (prm_stackcheck) {
- AMODE *ap1;
- ap = set_symbol("_stackerror",1);
- ap1 = set_symbol("_stackbottom",0);
- #ifdef i386
- ap1->mode = am_direct;
- gen_code(op_cmp,4,makedreg(ESP),ap1);
- gen_code(op_jb,0,ap,0);
- #else
- ap1->mode = am_indx;
- ap1->preg = BASEREG;
- gen_code(op_cmp,4,makeareg(7),ap1);
- gen_code(op_bhi,0,ap,0);
- #endif
- }
- csp = olist;
- while( csp != 0 ) {
- int sz;
- if( csp->reg != -1 )
- { /* see if preload needed */
- exptr = csp->exp;
- if( !lvalue(exptr) || (exptr->v.p[0]->v.i >= 0) )
- {
- initstack();
- sz = csp->size;
- ap = gen_expr(exptr,F_ALL,sz);
- #ifdef i386
- if( csp->reg < 8 ) {
- if (ap->mode == am_dreg)
- peep_tail->oper1->preg = csp->reg;
- else {
- ap2 = makedreg(csp->reg);
- gen_code(op_mov,sz,ap2,ap);
- do_extend(ap2,sz,4,F_DREG);
- }
- }
- else
- if (csp->reg < 16) {
- if (ap->mode == am_dreg)
- peep_tail->oper1->preg = csp->reg - 4;
- else {
- ap2 = makedreg(csp->reg - 4);
- gen_code(op_mov,4,ap2,ap);
- }
- }
- else {
- /* Should never get here */
- diag("float reg assigned in analyze");
- }
- #else
- if( csp->reg < 8 ) {
- if (ap->mode == am_dreg)
- peep_tail->oper2->preg = csp->reg;
- else {
- ap2 = makedreg(csp->reg);
- gen_code(op_move,sz,ap,ap2);
- do_extend(ap2,sz,4,F_DREG);
- }
- }
- else
- if (csp->reg < 16) {
- if (ap->mode == am_areg)
- peep_tail->oper2->preg = csp->reg - 8;
- else {
- ap2 = makeareg(csp->reg - 8);
- gen_code(op_move,4,ap,ap2);
- }
- }
- else {
- if (ap->mode == am_freg)
- peep_tail->oper2->preg = csp->reg - 16;
- else {
- ap2 = makefreg(csp->reg - 16);
- size = 8;
- if (exptr->nodetype == en_floatref)
- size = 6;
- gen_code(op_fmove,size,ap,ap2);
- }
- }
- #endif
- freeop(ap);
- }
- }
- csp = csp->next;
- }
- }
-
- void repexpr(ENODE *node)
- /*
- * repexpr will replace all allocated references within an expression
- * with tempref nodes.
- */
- { CSE *csp;
- if( node == 0 )
- return;
- switch( node->nodetype ) {
- case en_rcon:
- case en_icon:
- case en_nacon:
- case en_napccon:
- case en_autocon:
- case en_autoreg:
- case en_absacon:
- if( (csp = searchnode(node)) != 0 )
- if( csp->reg > 0 ) {
- node->nodetype = en_tempref;
- node->v.i = csp->reg | (csp->size << 8);
- }
- break;
- case en_floatref:
- case en_doubleref:
- case en_longdoubleref:
- case en_ub_ref:
- case en_uw_ref:
- case en_b_ref:
- case en_w_ref:
- case en_l_ref:
- case en_ul_ref:
- if( (csp = searchnode(node)) != 0 ) {
- if( csp->reg > 0 ) {
- node->nodetype = en_tempref;
- node->v.i = csp->reg | (csp->size << 8);
- }
- else
- repexpr(node->v.p[0]);
- }
- else
- repexpr(node->v.p[0]);
- break;
- case en_uminus: case en_bits:
- case en_not: case en_compl:
- case en_ainc: case en_adec:
- case en_cb: case en_cub:
- case en_cw: case en_cuw:
- case en_cl: case en_cul:
- case en_cf: case en_cd: case en_cp: case en_cld:
- repexpr(node->v.p[0]);
- break;
- case en_add: case en_sub:
- case en_umul: case en_udiv: case en_umod:
- case en_mul: case en_div:
- case en_mod: case en_lsh:
- case en_asalsh: case en_asarsh: case en_alsh: case en_arsh:
- case en_rsh: case en_and:
- case en_or: case en_xor:
- case en_land: case en_lor:
- case en_eq: case en_ne:
- case en_lt: case en_le:
- case en_ugt: case en_uge: case en_ult: case en_ule:
- case en_gt: case en_ge:
- case en_cond: case en_void:
- case en_asadd: case en_assub:
- case en_asmul: case en_asdiv:
- case en_asor: case en_asand:
- case en_asmod: case en_aslsh:
- case en_asumod: case en_asudiv: case en_asumul: case en_pmul:
- case en_asrsh: case en_fcall: case en_trapcall: case en_pdiv:
- case en_assign: case en_intcall: case en_fcallb: case en_refassign:
- case en_moveblock: case en_stackblock: case en_callblock:
- repexpr(node->v.p[0]);
- repexpr(node->v.p[1]);
- break;
- }
- }
-
- void repcse(SNODE *block)
- /*
- * repcse will scan through a block of statements replacing the
- * optimized expressions with their temporary references.
- */
- { while( block != 0 ) {
- switch( block->stype ) {
- case st_return:
- case st_expr:
- repexpr(block->exp);
- break;
- case st_while:
- case st_do:
- repexpr(block->exp);
- repcse(block->s1);
- break;
- case st_for:
- repexpr(block->label);
- repexpr(block->exp);
- repcse(block->s1);
- repexpr(block->s2);
- break;
- case st_if:
- repexpr(block->exp);
- repcse(block->s1);
- repcse(block->s2);
- break;
- case st_switch:
- repexpr(block->exp);
- repcse(block->s1);
- break;
- case st_case:
- repcse(block->s1);
- break;
- case st_block:
- repcse(block->exp);
- break;
- }
- block = block->next;
- }
- }
-
- void opt1(SNODE *block)
- /*
- * opt1 is the externally callable optimization routine. it will
- * collect and allocate common subexpressions and substitute the
- * tempref for all occurrances of the expression within the block.
- *
- * optimizer is currently turned off...
- */
- {
- int datareg = FREEDATA;
- int addreg = 8+FREEADDRESS;
- int floatreg = 16 + FREEFLOAT;
- olist = 0;
- scan(block); /* collect expressions */
- reserveregs(&datareg, &addreg, &floatreg); /* Allocate register vars */
- allocate(datareg, addreg,floatreg); /* allocate registers for opt*/
- repcse(block); /* replace allocated expressions */
- }