GSTMT68.C
上传用户:hlzzc88
上传日期:2007-01-06
资源大小:220k
文件大小:24k
- /*
- * 68K/386 32-bit C compiler.
- *
- * copyright (c) 1997, 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 either the original sources or derived sources
- * are distributed along with any executables derived from the originals.
- *
- * The author is not responsible for any damages that may arise from use
- * of this software, either idirect or consequential.
- *
- * v1.35 March 1997
- * 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 "gen68.h"
- #include "diag.h"
- extern long lc_maxauto;
- extern int linkreg;
- extern long framedepth;
- extern TYP stdfunc;
- extern struct amode push[], pop[];
- extern OCODE *peep_tail, *peep_head, *peep_insert;
- extern long stackdepth;
- extern SYM *currentfunc;
- extern int prm_cplusplus,prm_linkreg, prm_phiform, prm_68020, prm_68010;
- extern int prm_rel, prm_smallcode;
- extern long firstlabel, nextlabel;
- extern int global_flag;
- extern int save_mask, fsave_mask;
- extern TABLE gsyms;
- static int diddef;
- static int breaklab;
- static int contlab;
- static int retlab;
- static long gswitchbottom, gswitchcount;
- static long gswitchtop;
- void genstmtini(void)
- {
- }
- AMODE *makedreg(int r)
- /*
- * make an address reference to a data register.
- */
- { AMODE *ap;
- ap = xalloc(sizeof(AMODE));
- ap->mode = am_dreg;
- ap->preg = r;
- return ap;
- }
- AMODE *makeareg(int r)
- /*
- * make an address reference to an address register.
- */
- { AMODE *ap;
- ap = xalloc(sizeof(AMODE));
- ap->mode = am_areg;
- ap->preg = r;
- return ap;
- }
- AMODE *makefreg(int r)
- /*
- * make an address reference to a data register.
- */
- { AMODE *ap;
- ap = xalloc(sizeof(AMODE));
- ap->mode = am_freg;
- ap->preg = r;
- return ap;
- }
- AMODE *make_mask(int mask, int reverse, int floatflag)
- /*
- * generate the mask address structure.
- */
- { AMODE *ap;
- ap = xalloc(sizeof(AMODE));
- if (floatflag)
- ap->mode = am_fmask;
- else
- ap->mode = am_mask;
- ap->preg = reverse;
- ap->offset = (ENODE *)mask;
- return ap;
- }
- AMODE *make_direct(int i)
- /*
- * make a direct reference to an immediate value.
- */
- { return make_offset(makenode(en_icon,(char *)i,0));
- }
- AMODE *make_strlab(char *s)
- /*
- * generate a direct reference to a string label.
- */
- { AMODE *ap;
- ap = xalloc(sizeof(AMODE));
- ap->mode = am_direct;
- ap->offset = makenode(en_nacon,s,0);
- return ap;
- }
- void genwhile(SNODE *stmt)
- /*
- * generate code to evaluate a while statement.
- */
- { int lab1, lab2, lab3;
- initstack(); /* initialize temp registers */
- lab1 = contlab; /* save old continue label */
- contlab = nextlabel++; /* new continue label */
- if( stmt->s1 != 0 ) /* has block */
- {
- lab2 = breaklab; /* save old break label */
- breaklab = nextlabel++;
- gen_code(op_bra,0,make_label(contlab),0);
- lab3 = nextlabel++;
- gen_label(lab3);
- genstmt(stmt->s1);
- gen_label(contlab);
- initstack();
- if (stmt->lst)
- gen_line(stmt->lst);
- truejp(stmt->exp,lab3);
- gen_label(breaklab);
- breaklab = lab2; /* restore old break label */
- }
- else /* no loop code */
- {
- if (stmt->lst)
- gen_line(stmt->lst);
- gen_label(contlab);
- initstack();
- truejp(stmt->exp,contlab);
- }
- contlab = lab1; /* restore old continue label */
- }
- void gen_for(SNODE *stmt)
- /*
- * generate code to evaluate a for loop
- */
- { int old_break, old_cont, exit_label, loop_label;
- old_break = breaklab;
- old_cont = contlab;
- loop_label = nextlabel++;
- exit_label = nextlabel++;
- contlab = nextlabel++;
- initstack();
- if( stmt->label != 0 )
- gen_expr(stmt->label,F_ALL | F_NOVALUE
- ,natural_size(stmt->label));
-
- gen_code(op_bra,0,make_label(contlab),0);
- gen_label(loop_label);
- if( stmt->s1 != 0 ) {
- breaklab = exit_label;
- genstmt(stmt->s1);
- }
- initstack();
- if( stmt->s2 != 0 )
- gen_expr(stmt->s2,F_ALL | F_NOVALUE,natural_size(stmt->s2));
- gen_label(contlab);
- if (stmt->lst)
- gen_line(stmt->lst);
- initstack();
- if( stmt->exp != 0 )
- truejp(stmt->exp,loop_label);
- else
- gen_code(op_bra,0,make_label(loop_label),0);
- gen_label(exit_label);
- breaklab = old_break;
- contlab = old_cont;
- }
- void genif(SNODE *stmt)
- /*
- * generate code to evaluate an if statement.
- */
- { int lab1, lab2;
- lab1 = nextlabel++; /* else label */
- lab2 = nextlabel++; /* exit label */
- initstack(); /* clear temps */
- falsejp(stmt->exp,lab1);
- genstmt(stmt->s1);
- if( stmt->s2 != 0 ) /* else part exists */
- {
- gen_code(op_bra,0,make_label(lab2),0);
- gen_label(lab1);
- genstmt(stmt->s2);
- gen_label(lab2);
- }
- else /* no else code */
- gen_label(lab1);
- }
- void gendo(SNODE *stmt)
- /*
- * generate code for a do - while loop.
- */
- { int oldcont, oldbreak;
- oldcont = contlab;
- oldbreak = breaklab;
- contlab = nextlabel++;
- gen_label(contlab);
- if( stmt->s1 != 0 && stmt->s1->next != 0 )
- {
- breaklab = nextlabel++;
- genstmt(stmt->s1); /* generate body */
- initstack();
- truejp(stmt->exp,contlab);
- gen_label(breaklab);
- }
- else
- {
- genstmt(stmt->s1);
- initstack();
- truejp(stmt->exp,contlab);
- }
- breaklab = oldbreak;
- contlab = oldcont;
- }
- void gen_genword(SNODE *stmt)
- /*
- * Generate data in the code stream
- */
- {
- gen_code(op_genword,2,make_immed((int)stmt->exp),0);
- }
- AMODE *set_symbol(char *name, int isproc)
- /*
- * generate a call to a library routine.
- */
- { SYM *sp;
- AMODE *result;
- sp = gsearch(name);
- if( sp == 0 )
- {
- ++global_flag;
- sp = xalloc(sizeof(SYM));
- sp->tp = &stdfunc;
- sp->name = name;
- if (isproc)
- sp->storage_class = sc_externalfunc;
- else
- sp->storage_class = sc_external;
- sp->extflag = TRUE;
- insert(sp,&gsyms);
- --global_flag;
- }
- result = make_strlab(name);
- return result;
- }
- AMODE *flush_for_libcall()
- {
- AMODE *result = temp_addr();
- temp_addr(); /* push any used addr temps */
- freeop(result); freeop(result);
- result = temp_data();
- temp_data(); temp_data(); /* push any used data registers */
- freeop(result); freeop(result); freeop(result);
- }
- AMODE *call_library(char *lib_name,int size)
- /*
- * generate a call to a library routine.
- */
- {
- AMODE *result;
- result = set_symbol(lib_name,1);
- gen_code(op_bsr,0,result,0);
- if (size)
- gen_code(op_add,4,make_immed(size),makeareg(7));
- result = temp_data();
- if (result->preg != 0)
- gen_code(op_move,4,makedreg(0),result);
- result->tempflag = TRUE;
- return result;
- }
- int analyzeswitch(SNODE *stmt)
- /*
- * Decide whitch type of switch statement to use
- */
- {
- gswitchbottom = 0x7fffffff;
- gswitchtop = -0x80000000;
- gswitchcount = 0;
- stmt = stmt->s1;
- while (stmt) {
- if (!stmt->s2) {
- gswitchcount++;
- if ((int)stmt->label < gswitchbottom)
- gswitchbottom = (int)stmt->label;
- if ((int)stmt->label > gswitchtop)
- gswitchtop = (int)stmt->label;
- }
- stmt = stmt->next;
- }
- gswitchtop++;
- if (gswitchcount == 0)
- return(0);
- if (gswitchcount > 3)
- if (gswitchcount*10/(gswitchtop-gswitchbottom) >= 8)
- return(1);
- return(2);
- }
-
- void bingen(int lower, int avg, int higher,AMODE *ap1, int deflab, int size, long *switchids, int *switchlabels, int *switchbinlabels)
- /*
- * Recursively output the compare/jump tree for a type of binary search
- * on the case value
- */
- {
- AMODE *ap2 = make_immed(switchids[avg]);
- AMODE *ap3 = make_label(switchlabels[avg]);
- if (switchbinlabels[avg] != -1)
- gen_label(switchbinlabels[avg]);
- gen_code(op_cmp,4,ap2,ap1);
- gen_code(op_beq,0,ap3,0);
- if (avg == lower) {
- ap3 = make_label(deflab);
- gen_code(op_bra,0,ap3,0);
- }
- else {
- int avg1 = (lower + avg)/2;
- int avg2 = (higher + avg+1)/2;
- if (avg+1 < higher)
- ap3 = make_label(switchbinlabels[avg2]=nextlabel++);
- else
- ap3 = make_label(deflab);
- if (size < 0)
- gen_code(op_bgt,0,ap3,0);
- else
- gen_code(op_bhi,0,ap3,0);
- bingen(lower,avg1,avg,ap1,deflab,size,switchids,switchlabels,switchbinlabels);
- if (avg+1 < higher)
- bingen(avg+1,avg2,higher,ap1,deflab,size,switchids,switchlabels,switchbinlabels);
- }
- }
- void genbinaryswitch(SNODE *stmt, int deflab)
- /*
- * Main routine for handling the binary switch setup
- */
- {
- int curlab, i=0,j,size = natural_size(stmt->exp);
- AMODE *ap1;
- long switchbottom=gswitchbottom, switchcount=gswitchcount;
- long switchtop=gswitchtop;
- int *switchlabels=0;
- long *switchids=0;
- int *switchbinlabels=0;
- curlab = nextlabel++;
- initstack();
- ap1 = gen_expr(stmt->exp,F_DREG,4);
- global_flag++;
- switchlabels = xalloc((switchcount) * sizeof(int));
- switchbinlabels = xalloc((switchcount) * sizeof(int));
- switchids = xalloc((switchcount) * sizeof(long));
- global_flag--;
- stmt = stmt->s1;
- while (stmt) {
- if( stmt->s2 ) /* default case ? */
- {
- stmt->label = (SNODE *) deflab;
- diddef = TRUE;
- }
- else
- {
- switchlabels[i] = curlab;
- switchbinlabels[i] = -1;
- switchids[i++] = (int)stmt->label;
- stmt->label = (SNODE *)curlab;
- }
- if( stmt->next != 0 )
- curlab = nextlabel++;
- stmt = stmt->next;
- }
- for (i=0; i < switchcount; i++)
- for (j=i+1; j < switchcount; j++)
- if (switchids[j] < switchids[i]) {
- int temp = switchids[i];
- switchids[i] = switchids[j];
- switchids[j] = temp;
- temp = switchlabels[i];
- switchlabels[i] = switchlabels[j];
- switchlabels[j] = temp;
- }
- bingen(0,(switchcount)/2,switchcount,ap1,deflab,size,switchids,switchlabels,switchbinlabels);
- }
- void gencompactswitch(SNODE *stmt, int deflab)
- /*
- * Generate a table lookup mechanism if the switch table isn't too sparse
- */
- { int tablab,curlab,i;
- AMODE *ap,*ap1,*ap2,*ap3;
- long switchbottom=gswitchbottom, switchcount=gswitchcount;
- long switchtop=gswitchtop;
- int *switchlabels=0;
- tablab = nextlabel++;
- curlab = nextlabel++;
- initstack();
- ap = gen_expr(stmt->exp,F_DREG | F_VOL,4);
- initstack();
- if (switchbottom) {
- gen_code(op_sub,4,make_immed(switchbottom),ap);
- gen_code(op_blo,0,make_label(deflab),0);
- }
- gen_code(op_cmp,4,make_immed(switchtop-switchbottom),ap);
- gen_code(op_bhs,0,make_label(deflab),0);
- ap1= temp_addr();
- ap2 = xalloc(sizeof(AMODE));
- if (prm_rel) {
- ap2->preg = ap1->preg;
- ap2->mode = am_pcindx;
- }
- else {
- ap2->mode = am_adirect;
- if (prm_smallcode)
- ap2->preg = 2;
- else
- ap2->preg = 4;
- }
- ap2->offset = makenode(en_labcon,(char *)tablab,0);
- gen_code(op_lea,0,ap2,ap1);
- if (prm_rel || prm_smallcode)
- gen_code(op_asl,4,make_immed(1),ap);
- else
- gen_code(op_asl,4,make_immed(2),ap);
- if (prm_rel) {
- gen_code(op_add,4,ap,ap1);
- ap2->mode = am_ind;
- gen_code(op_add,2,ap2,ap1);
- }
- else {
- ap3->sreg = ap->preg;
- ap3->preg = ap1->preg;
- ap3->scale = 0;
- ap3->offset = makenode(en_icon,0,0);
- ap3->mode = am_baseindxdata;
- gen_code(op_move,4,ap3,ap1);
- }
- ap1->mode = am_ind;
- gen_code(op_jmp,0,ap1,0);
- initstack();
- gen_label(tablab);
- switchlabels = xalloc((switchtop-switchbottom) * sizeof(int));
- for (i=switchbottom; i < switchtop; i++) {
- switchlabels[i-switchbottom] = deflab;
- }
- stmt = stmt->s1;
- while (stmt) {
- if( stmt->s2 ) /* default case ? */
- {
- stmt->label = (SNODE *)deflab;
- diddef = TRUE;
- }
- else
- {
- switchlabels[(int)stmt->label-switchbottom] = curlab;
- stmt->label = (SNODE *)curlab;
- }
- if( stmt->next != 0 )
- curlab = nextlabel++;
- stmt = stmt->next;
- }
- for (i=0; i < switchtop-switchbottom; i++)
- if (prm_smallcode || prm_rel)
- gen_code(op_dcl,2,make_label(switchlabels[i]),0);
- else
- gen_code(op_dcl,4,make_label(switchlabels[i]),0);
- }
- void gencase(SNODE *stmt)
- /*
- * generate all cases for a switch statement.
- */
- { while( stmt != 0 )
- {
- gen_label((int)stmt->label);
- if( stmt->s1 != 0 )
- {
- genstmt(stmt->s1);
- }
- stmt = stmt->next;
- }
- }
- void genxswitch(SNODE *stmt)
- /*
- * analyze and generate best switch statement.
- */
- { int oldbreak;
- int olddiddef = diddef;
- int deflab = nextlabel++;
- oldbreak = breaklab;
- breaklab = nextlabel++;
- diddef = FALSE;
- switch (analyzeswitch(stmt)) {
- case 2:
- genbinaryswitch(stmt,deflab);
- break;
- case 1:
- gencompactswitch(stmt,deflab);
- break;
- case 0:
- if (stmt->s1)
- stmt->s1->label = (SNODE *) nextlabel++;
- break;
- }
- gencase(stmt->s1);
- gen_label(breaklab);
- if (!diddef)
- gen_label(deflab);
- breaklab = oldbreak;
- diddef = olddiddef;
- }
- void genreturn(SNODE *stmt,int flag)
- /*
- * generate a return statement.
- */
- { AMODE *ap,*ap1,*ap2,*ap3;
- int size;
- if( stmt != 0 && stmt->exp != 0 )
- {
- initstack();
- if (currentfunc->tp->btp && currentfunc->tp->btp->type != bt_void && (currentfunc->tp->btp->type == bt_struct || currentfunc->tp->btp->type == bt_union)) {
- int lbl;
- lbl = nextlabel++;
- size = currentfunc->tp->btp->size;
- ap = gen_expr(stmt->exp,F_AREG | F_VOL,4);
- ap2 = xalloc(sizeof(AMODE));
- if (prm_linkreg && !currentfunc->intflag) {
- if (currentfunc->pascaldefn && currentfunc->tp->lst.head && currentfunc->tp->lst.head != (SYM *)-1) {
- ap2->preg = linkreg;
- ap2->mode = am_indx;
- ap2->offset = makenode(en_icon,(char *)(currentfunc->tp->lst.head->value.i + ((currentfunc->tp->lst.head->tp->size +3) &0xFFFFFFFCL)),0);
- }
- else {
- ap2->preg = linkreg;
- ap2->mode = am_indx;
- ap2->offset = makenode(en_icon,(char *)8,0);
- }
- }
- else if ( prm_phiform || currentfunc->intflag) {
- if (currentfunc->pascaldefn && currentfunc->tp->lst.head && currentfunc->tp->lst.head != (SYM *)-1) {
- ap2->preg = linkreg;
- ap2->mode = am_indx;
- ap2->offset = makenode(en_icon,(char *)(currentfunc->tp->lst.head->value.i + ((currentfunc->tp->lst.head->tp->size +3) &0xFFFFFFFCL)),0);
- }
- else {
- ap2->preg = linkreg;
- ap2->mode = am_ind;
- }
- }
- else {
- if (currentfunc->pascaldefn && currentfunc->tp->lst.head && currentfunc->tp->lst.head != (SYM *)-1) {
- ap2->preg = 7;
- ap2->mode = am_indx;
- ap2->offset = makenode(en_icon,(char *)(framedepth+stackdepth+currentfunc->tp->lst.head->value.i + ((currentfunc->tp->lst.head->tp->size+3) & 0xfffffffcL)),0);
- }
- else {
- ap2->preg = 7;
- ap2->mode = am_indx;
- ap2->offset = makenode(en_icon,(char *)(framedepth+stackdepth),0);
- }
- }
- ap3 = temp_addr();
- ap1 = temp_data();
- gen_code(op_move,4,ap2,ap3);
- ap->mode = am_ainc;
- ap3->mode = am_ainc;
- gen_code(op_move,4,make_immed(size),ap1);
- gen_label(lbl);
- gen_code(op_move,1,ap,ap3);
- gen_code(op_sub,4,make_immed(1),ap1);
- gen_code(op_bne,0,make_label(lbl),0);
- gen_code(op_move,4,ap2,makedreg(0));
- freeop(ap1);
- freeop(ap3);
- freeop(ap);
- }
- else {
- size = currentfunc->tp->btp->size;
- ap = gen_expr(stmt->exp,F_ALL,size);
- if (size > 4) {
- if( ap->mode != am_freg || ap->preg != 0 )
- gen_codef(op_fmove,size,ap,makefreg(0));
- }
- else
- if( ap->mode != am_dreg || ap->preg != 0 )
- gen_code(op_move,size,ap,makedreg(0));
- }
- }
- if (flag) {
- if( retlab != -1 )
- gen_label(retlab);
- if ((!prm_linkreg || currentfunc->intflag) && (lc_maxauto))
- if (lc_maxauto > 8) {
- AMODE *ap = xalloc(sizeof(AMODE));
- ap->mode = am_indx;
- ap->offset = makenode(en_icon,(char *)lc_maxauto,0);
- ap->preg = 7;
- gen_code(op_lea,0,ap,makeareg(7));
- }
- else
- gen_code(op_add,4,make_immed(lc_maxauto),makeareg(7));
- if( fsave_mask != 0 )
- gen_code(op_fmovem,10,pop,make_mask(fsave_mask,1,1));
- if( save_mask != 0 )
- gen_code(op_movem,4,pop,make_mask(save_mask,1,0));
- if (prm_linkreg && !currentfunc->intflag && (currentfunc->tp->lst.head && currentfunc->tp->lst.head != (SYM *)-1 || lc_maxauto)) {
- gen_code(op_unlk,0,makeareg(linkreg),0);
- }
- if (currentfunc->intflag)
- gen_code(op_rte,0,0,0);
- else
- if (currentfunc->pascaldefn) {
- long retsize = 0;
- if (currentfunc->tp->lst.head && currentfunc->tp->lst.head != (SYM *)-1) {
- retsize = currentfunc->tp->lst.head->value.i + ((currentfunc->tp->lst.head->tp->size +3) & 0xfffffffcl);
- if (prm_linkreg)
- retsize -= 8;
- }
- if (currentfunc->tp->btp && currentfunc->tp->btp->type != bt_void && (currentfunc->tp->btp->type == bt_struct || currentfunc->tp->btp->type == bt_union))
- retsize +=4;
- if (retsize) {
- if (prm_68020 || prm_68010)
- gen_code(op_rtd,0,make_immed(retsize),0);
- else {
- ap = temp_addr();
- freeop(ap);
- gen_code(op_move,4,pop,ap);
- if (retsize > 8) {
- ap1 = xalloc(sizeof(AMODE));
- ap1->mode = am_indx;
- ap1->offset = makenode(en_icon,(char *)retsize,0);
- ap1->preg = 7;
- gen_code(op_lea,0,ap1,makeareg(7));
- }
- else
- gen_code(op_add,4,make_immed(retsize),makeareg(7));
- ap->mode = am_ind;
- gen_code(op_jmp,0,ap,0);
- }
- return;
- }
- }
- gen_code(op_rts,0,0,0);
- }
- else {
- if (retlab == -1)
- retlab = nextlabel++;
- gen_code(op_bra,0,make_label(retlab),0);
- }
- }
- void genstmt(SNODE *stmt)
- /*
- * genstmt will generate a statement and follow the next pointer
- * until the block is generated.
- */
- {
- while( stmt != 0 )
- {
- switch( stmt->stype )
- {
- case st_block:
- genstmt(stmt->exp);
- break;
- case st_label:
- gen_label((int)stmt->label);
- break;
- case st_goto:
- gen_code(op_bra,0,make_label((int)stmt->label),0);
- break;
- case st_expr:
- initstack();
- gen_expr(stmt->exp,F_ALL | F_NOVALUE,
- natural_size(stmt->exp));
- break;
- case st_return:
- genreturn(stmt,0);
- break;
- case st_if:
- genif(stmt);
- break;
- case st_while:
- genwhile(stmt);
- break;
- case st_do:
- gendo(stmt);
- break;
- case st_for:
- gen_for(stmt);
- break;
- case st_line:
- gen_line(stmt);
- break;
- case st_continue:
- gen_code(op_bra,0,make_label(contlab),0);
- break;
- case st_break:
- gen_code(op_bra,0,make_label(breaklab),0);
- break;
- case st_switch:
- genxswitch(stmt);
- break;
- case st__genword:
- gen_genword(stmt);
- break;
- default:
- DIAG("unknown statement.");
- break;
- }
- stmt = stmt->next;
- }
- }
- #ifdef CPLUSPLUS
- void scppinit(void)
- /*
- * Call C++ reference variable and class initializers
- */
- {
- if (!strcmp(currentfunc->name,"_main")) {
- AMODE *ap1,*ap2,*ap3,*ap4;
- int lbl = nextlabel++;
- initstack();
- ap1 = temp_addr();
- ap4 = xalloc(sizeof(AMODE));
- ap4->preg = ap1->preg;
- ap4->mode = am_ind;
- ap2 = set_symbol("CPPSTART",0);
- ap3 = set_symbol("CPPEND",0);
- gen_code(op_lea,4,ap2,ap1);
- gen_label(lbl);
- gen_code(op_move,4,ap1,push);
- gen_code(op_jsr,4,ap4,0);
- gen_code(op_move,4,pop,ap1);
- gen_code(op_add,4,make_immed(4),ap1);
- gen_code(op_cmp,4,ap3,ap1);
- gen_code(op_bhi,0,make_label(lbl),0);
- freeop(ap1);
- }
- }
- #endif
- void genfunc(SNODE *stmt)
- /*
- * generate a function body.
- */
- { retlab = contlab = breaklab = -1;
- stackdepth = 0;
- if (stmt->stype == st_line) {
- gen_line(stmt);
- stmt = stmt->next;
- }
- gen_codelab(currentfunc); /* name of function */
- opt1(stmt); /* push args & Also loads link reg and subtracts SP */
- #ifdef CPLUSPLUS
- if (prm_cplusplus) {
- scppinit();
- }
- #endif
- genstmt(stmt);
- genreturn(0,1);
- }