URL
https://opencores.org/ocsvn/raptor64/raptor64/trunk
Subversion Repositories raptor64
[/] [raptor64/] [trunk/] [software/] [c64/] [source/] [Analyze.c] - Rev 43
Go to most recent revision | Compare with Previous | Blame | View Log
#include <stdio.h> #include "c.h" #include "expr.h" #include "Statement.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 */ /******************************************************* Modified to support Raptor64 'C64' language by Robert Finch robfinch@opencores.org *******************************************************/ extern int popcnt(int m); /* * 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 */ /* * equalnode will return 1 if the expressions pointed to by * node1 and node2 are equivalent. */ static int equalnode(ENODE *node1, ENODE *node2) { // 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_nacon || node1->nodetype == en_autocon) && // node1->v.i == node2->v.i ) // return 1; // if( IsLValue(node1) && equalnode(node1->v.p[0], node2->v.p[0]) ) // return 1; // return 0; //} if (node1 == NULL || node2 == NULL) return FALSE; if (node1->nodetype != node2->nodetype) return FALSE; switch (node1->nodetype) { case en_icon: case en_labcon: case en_autocon: return (node1->i == node2->i); case en_nacon: return (!strcmp(node1->sp, node2->sp)); default: if( IsLValue(node1) && equalnode(node1->p[0], node2->p[0]) ) return TRUE; return FALSE; } } /* * SearchCSEList will search the common expression table for an entry * that matches the node passed and return a pointer to it. */ static CSE *SearchCSEList(ENODE *node) { CSE *csp; csp = olist; while( csp != NULL ) { if( equalnode(node,csp->exp) ) return csp; csp = csp->next; } return NULL; } /* * copy the node passed into a new enode so it wont get * corrupted during substitution. */ static ENODE *DuplicateEnode(ENODE *node) { ENODE *temp; if( node == NULL ) return NULL; temp = allocEnode(); memcpy(temp,node,sizeof(ENODE)); // copy all the fields return temp; } /* * InsertNodeIntoCSEList 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 *InsertNodeIntoCSEList(ENODE *node, int duse) { CSE *csp; if( (csp = SearchCSEList(node)) == NULL ) { /* add to tree */ csp = allocCSE(); csp->next = olist; csp->uses = 1; csp->duses = (duse != 0); csp->exp = DuplicateEnode(node); csp->voidf = 0; csp->reg = 0; olist = csp; return csp; } ++(csp->uses); if( duse ) ++(csp->duses); return csp; } /* * voidauto will void an auto dereference node which points to * the same auto constant as node. */ CSE *voidauto(ENODE *node) { CSE *csp; csp = olist; while( csp != NULL ) { if( IsLValue(csp->exp) && equalnode(node,csp->exp->p[0]) ) { if( csp->voidf ) return NULL; csp->voidf = 1; return csp; } csp = csp->next; } return NULL; } /* * 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. */ static void scanexpr(ENODE *node, int duse) { CSE *csp, *csp1; if( node == NULL ) return; switch( node->nodetype ) { case en_icon: case en_labcon: case en_nacon: InsertNodeIntoCSEList(node,duse); break; case en_autocon: if( (csp = voidauto(node)) != NULL ) { csp1 = InsertNodeIntoCSEList(node,duse); csp1->uses = (csp1->duses += csp->uses); } else InsertNodeIntoCSEList(node,duse); break; case en_b_ref: case en_c_ref: case en_h_ref: case en_w_ref: case en_ub_ref: case en_uc_ref: case en_uh_ref: case en_uw_ref: case en_bfieldref: case en_ubfieldref: case en_cfieldref: case en_ucfieldref: case en_hfieldref: case en_uhfieldref: case en_wfieldref: case en_uwfieldref: if( node->p[0]->nodetype == en_autocon ) { csp = InsertNodeIntoCSEList(node,duse); if( csp->voidf ) scanexpr(node->p[0],1); } else scanexpr(node->p[0],1); break; case en_cbc: case en_cbh: case en_cbw: case en_cch: case en_ccw: case en_chw: case en_uminus: case en_compl: case en_ainc: case en_adec: case en_not: scanexpr(node->p[0],duse); break; case en_asadd: case en_assub: case en_add: case en_sub: scanexpr(node->p[0],duse); scanexpr(node->p[1],duse); break; case en_mul: case en_mulu: case en_div: case en_udiv: case en_shl: case en_shr: case en_shru: 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_asmul: case en_asdiv: case en_asmod: case en_aslsh: case en_asrsh: case en_asand: case en_asxor: case en_asor: case en_cond: case en_void: case en_assign: scanexpr(node->p[0],0); scanexpr(node->p[1],0); break; case en_fcall: scanexpr(node->p[0],1); scanexpr(node->p[1],0); break; } } /* * scan will gather all optimizable expressions into the expression * list for a block of statements. */ static void scan(Statement *block) { while( block != NULL ) { switch( block->stype ) { case st_return: case st_throw: case st_expr: opt4(&block->exp); scanexpr(block->exp,0); break; case st_while: case st_until: case st_do: case st_dountil: opt4(&block->exp); scanexpr(block->exp,0); case st_doloop: case st_forever: scan(block->s1); break; case st_for: opt4(&block->initExpr); scanexpr(block->initExpr,0); opt4(&block->exp); scanexpr(block->exp,0); scan(block->s1); opt4(&block->incrExpr); scanexpr(block->incrExpr,0); break; case st_if: opt4(&block->exp); scanexpr(block->exp,0); scan(block->s1); scan(block->s2); break; case st_switch: opt4(&block->exp); scanexpr(block->exp,0); scan(block->s1); break; case st_case: scan(block->s1); break; case st_spinlock: scan(block->s1); break; } block = block->next; } } /* * exchange will exchange the order of two expression entries * following c1 in the linked list. */ static void exchange(CSE **c1) { CSE *csp1, *csp2; csp1 = *c1; csp2 = csp1->next; csp1->next = csp2->next; csp2->next = csp1; *c1 = csp2; } /* * returns the desirability of optimization for a subexpression. */ int OptimizationDesireability(CSE *csp) { if( csp->voidf || (csp->exp->nodetype == en_icon && csp->exp->i < 256 && csp->exp->i >= 0)) return 0; if( IsLValue(csp->exp) ) return 2 * csp->uses; return csp->uses; } /* * bsort implements a bubble sort on the expression list. */ int bsort(CSE **list) { CSE *csp1, *csp2; int i; csp1 = *list; if( csp1 == NULL || csp1->next == NULL ) return FALSE; i = bsort( &(csp1->next)); csp2 = csp1->next; if( OptimizationDesireability(csp1) < OptimizationDesireability(csp2) ) { exchange(list); return TRUE; } return FALSE; } /* * AllocateRegisterVars will allocate registers for the expressions that have * a high enough desirability. */ void AllocateRegisterVars() { CSE *csp; ENODE *exptr; int reg, mask, rmask; AMODE *ap, *ap2; int nn; reg = 11; mask = 0; rmask = 0; while( bsort(&olist) ); /* sort the expression list */ csp = olist; while( csp != NULL ) { if( OptimizationDesireability(csp) < 3 ) // was < 3 csp->reg = -1; // else if( csp->duses > csp->uses / 8 && reg < 18 ) // was / 4 else if( reg < 18 ) // was / 4 csp->reg = reg++; else csp->reg = -1; if( csp->reg != -1 ) { rmask = rmask | (1 << (31 - csp->reg)); mask = mask | (1 << csp->reg); } csp = csp->next; } if( mask != 0 ) { if (bitsset(rmask) < 2) { for (nn = 0; nn < 32; nn++) if (rmask & (0x80000000 >> nn)) { GenerateTriadic(op_subui,0,makereg(30),makereg(30),make_immed(8)); GenerateTriadic(op_sw,0,makereg(nn&31),make_indirect(30),NULL); } } else { GenerateTriadic(op_subui,0,makereg(30),makereg(30),make_immed(popcnt(mask)*8)); GenerateDiadic(op_sm,0,make_indirect(30),make_mask(mask),NULL); } } save_mask = mask; csp = olist; while( csp != NULL ) { if( csp->reg != -1 ) { /* see if preload needed */ exptr = csp->exp; if( !IsLValue(exptr) || (exptr->p[0]->i > 0) ) { initstack(); ap = GenerateExpression(exptr,F_REG|F_IMMED,8); ap2 = makereg(csp->reg); if (ap->mode==am_immed) GenerateTriadic(op_ori,0,ap2,makereg(0),ap); else GenerateDiadic(op_mov,0,ap2,ap); ReleaseTempRegister(ap); } } csp = csp->next; } } /* * repexpr will replace all allocated references within an expression * with tempref nodes. */ void repexpr(ENODE *node) { struct cse *csp; if( node == NULL ) return; switch( node->nodetype ) { case en_icon: case en_nacon: case en_labcon: case en_autocon: if( (csp = SearchCSEList(node)) != NULL ) if( csp->reg > 0 ) { node->nodetype = en_regvar; node->i = csp->reg; } break; case en_b_ref: case en_c_ref: case en_h_ref: case en_w_ref: case en_ub_ref: case en_uc_ref: case en_uh_ref: case en_uw_ref: case en_bfieldref: case en_ubfieldref: case en_cfieldref: case en_ucfieldref: case en_hfieldref: case en_uhfieldref: case en_wfieldref: case en_uwfieldref: if( (csp = SearchCSEList(node)) != NULL ) { if( csp->reg > 0 ) { node->nodetype = en_regvar; node->i = csp->reg; } else repexpr(node->p[0]); } else repexpr(node->p[0]); break; case en_cbc: case en_cbh: case en_cbw: case en_cch: case en_ccw: case en_chw: case en_uminus: case en_not: case en_compl: case en_ainc: case en_adec: repexpr(node->p[0]); break; case en_add: case en_sub: case en_mul: case en_mulu: case en_div: case en_udiv: case en_mod: case en_shl: case en_shru: case en_shr: 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_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_asrsh: case en_fcall: case en_assign: repexpr(node->p[0]); repexpr(node->p[1]); break; } } /* * repcse will scan through a block of statements replacing the * optimized expressions with their temporary references. */ void repcse(Statement *block) { while( block != NULL ) { switch( block->stype ) { case st_return: case st_throw: repexpr(block->exp); break; case st_expr: repexpr(block->exp); break; case st_while: case st_until: case st_do: case st_dountil: repexpr(block->exp); case st_doloop: case st_forever: repcse(block->s1); repcse(block->s2); break; case st_for: repexpr(block->initExpr); repexpr(block->exp); repcse(block->s1); repexpr(block->incrExpr); 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_try: case st_catch: case st_case: repcse(block->s1); break; case st_spinlock: repcse(block->s1); repcse(block->s2); // lockfail statement break; } block = block->next; } } /* * 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... */ void opt1(Statement *block) { olist = NULL; scan(block); /* collect expressions */ AllocateRegisterVars(); /* allocate registers */ repcse(block); /* replace allocated expressions */ }
Go to most recent revision | Compare with Previous | Blame | View Log