home *** CD-ROM | disk | FTP | other *** search
/ CD Shareware Magazine 1996 December / CD_shareware_12-96.iso / DOS / Programa / CCDL122.ZIP / SOURCE / GSTMT386.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-03  |  18.4 KB  |  631 lines

  1. /*
  2.  * 68K/386 32-bit C compiler.
  3.  *
  4.  * copyright (c) 1996, David Lindauer
  5.  * 
  6.  * This compiler is intended for educational use.  It may not be used
  7.  * for profit without the express written consent of the author.
  8.  *
  9.  * It may be freely redistributed, as long as this notice remains intact
  10.  * and sources are distributed along with any executables derived from them.
  11.  *
  12.  * The author is not responsible for damages, either direct or consequential,
  13.  * that may arise from use of this software.
  14.  *
  15.  * v1.5 August 1996
  16.  * David Lindauer, gclind01@starbase.spd.louisville.edu
  17.  *
  18.  * Credits to Mathew Brandt for original K&R C compiler
  19.  *
  20.  */
  21. #include        <stdio.h>
  22. #include        "expr.h"
  23. #include        "c.h"
  24. #include        "gen.h"
  25. #include        "cglbdec.h"
  26.  
  27. extern TYP              stdfunc;
  28. extern struct amode     push[], pop[];
  29. extern OCODE *peep_tail, *peep_head;
  30. extern long stackdepth,framedepth;
  31. extern SYM *currentfunc;
  32. extern int regs[3];
  33. extern int prm_cplusplus;
  34.  
  35. OCODE *entryref, *exitref;
  36. int funcfloat;
  37.  
  38. static int     breaklab;
  39. static int     contlab;
  40. static int deflab;
  41. static int     retlab;
  42. static int diddef;
  43. static int switchbottom, switchcount;
  44. static int switchtop;
  45. static int oldswitchsize=0;
  46. static int *switchlabels=0;
  47. static int *switchids=0;
  48. static int *switchbinlabels=0;
  49.  
  50. void genstmtini(void)
  51. {
  52.     oldswitchsize = 0;
  53.     switchlabels = switchids = switchbinlabels = 0;
  54. }
  55. AMODE    *makedreg(int r)
  56. /*
  57.  *      make an address reference to a data register.
  58.  */
  59. {       AMODE    *ap;
  60.         ap = xalloc(sizeof(AMODE));
  61.         ap->mode = am_dreg;
  62.         ap->preg = r;
  63.         return ap;
  64. }
  65.  
  66. AMODE    *makefreg(int r)
  67. /*
  68.  *      make an address reference to a data register.
  69.  */
  70. {       AMODE    *ap;
  71.         ap = xalloc(sizeof(AMODE));
  72.         ap->mode = am_freg;
  73.         ap->preg = r;
  74.         return ap;
  75. }
  76.  
  77. AMODE    *make_direct(int i)
  78. /*
  79.  *      make a direct reference to an immediate value.
  80.  */
  81. {       return make_offset(makenode(en_icon,(char *)i,0));
  82. }
  83.  
  84. AMODE    *make_strlab(char *s)
  85. /*
  86.  *      generate a direct reference to a string label.
  87.  */
  88. {       AMODE    *ap;
  89.         ap = xalloc(sizeof(AMODE));
  90.         ap->mode = am_direct;
  91.         ap->offset = makenode(en_nacon,s,0);
  92.         return ap;
  93. }
  94.  
  95. void genwhile(SNODE *stmt)
  96. /*
  97.  *      generate code to evaluate a while statement.
  98.  */
  99. {       int     lab1, lab2, lab3;
  100.         initstack();            /* initialize temp registers */
  101.         lab1 = contlab;         /* save old continue label */
  102.         contlab = nextlabel++;  /* new continue label */
  103.         if( stmt->s1 != 0 )      /* has block */
  104.                 {
  105.                         lab2 = breaklab;        /* save old break label */
  106.                 breaklab = nextlabel++;
  107.                                 gen_code(op_jmp,0,make_label(contlab),0);
  108.                                 lab3 = nextlabel++;
  109.                                 gen_label(lab3);
  110.                 genstmt(stmt->s1);
  111.                                 gen_label(contlab);
  112.                                 if (stmt->lst)
  113.                                      gen_line(stmt->lst);
  114.                 initstack();
  115.                 truejp(stmt->exp,lab3);
  116.                 gen_label(breaklab);
  117.                 breaklab = lab2;        /* restore old break label */
  118.                 }
  119.         else                            /* no loop code */
  120.                 {
  121.                                 if (stmt->lst)
  122.                                      gen_line(stmt->lst);
  123.                         gen_label(contlab);
  124.                 initstack();
  125.                 truejp(stmt->exp,contlab);
  126.                 }
  127.         contlab = lab1;         /* restore old continue label */
  128. }
  129.  
  130. void gen_for(SNODE *stmt)
  131. /*
  132.  *      generate code to evaluate a for loop
  133.  */
  134. {       int     old_break, old_cont, exit_label, loop_label;
  135.         old_break = breaklab;
  136.         old_cont = contlab;
  137.         loop_label = nextlabel++;
  138.         exit_label = nextlabel++;
  139.         contlab = nextlabel++;
  140.         initstack();
  141.         if( stmt->label != 0 )
  142.                 gen_expr(stmt->label,F_ALL | F_NOVALUE
  143.                         ,natural_size(stmt->label));
  144.                 
  145.         gen_code(op_jmp,0,make_label(contlab),0);
  146.         gen_label(loop_label);
  147.         if( stmt->s1 != 0 ) {
  148.                                 breaklab = exit_label;
  149.                 genstmt(stmt->s1);
  150.                 }
  151.         initstack();
  152.         if( stmt->s2 != 0 )
  153.                 gen_expr(stmt->s2,F_ALL | F_NOVALUE,natural_size(stmt->s2));
  154.                 gen_label(contlab);
  155.                 if (stmt->lst)
  156.                      gen_line(stmt->lst);
  157.         initstack();
  158.         if( stmt->exp != 0 )
  159.                 truejp(stmt->exp,loop_label);
  160.                 else
  161.                         gen_code(op_jmp,0,make_label(loop_label),0);
  162.                 gen_label(exit_label);
  163.                  breaklab = old_break;
  164.                 contlab = old_cont;
  165. }
  166.  
  167. void genif(SNODE *stmt)
  168. /*
  169.  *      generate code to evaluate an if statement.
  170.  */
  171. {       int     lab1, lab2;
  172.         lab1 = nextlabel++;     /* else label */
  173.         lab2 = nextlabel++;     /* exit label */
  174.         initstack();            /* clear temps */
  175.         falsejp(stmt->exp,lab1);
  176.         genstmt(stmt->s1);
  177.         if( stmt->s2 != 0 )             /* else part exists */
  178.                 {
  179.                 gen_code(op_jmp,0,make_label(lab2),0);
  180.                 gen_label(lab1);
  181.                 genstmt(stmt->s2);
  182.                 gen_label(lab2);
  183.                 }
  184.         else                            /* no else code */
  185.                 gen_label(lab1);
  186. }
  187.  
  188. void gendo(SNODE *stmt)
  189. /*
  190.  *      generate code for a do - while loop.
  191.  */
  192. {       int     oldcont, oldbreak;
  193.         oldcont = contlab;
  194.         oldbreak = breaklab;
  195.         contlab = nextlabel++;
  196.         gen_label(contlab);
  197.         if( stmt->s1 != 0 && stmt->s1->next != 0 )
  198.                 {
  199.                 breaklab = nextlabel++;
  200.                 genstmt(stmt->s1);      /* generate body */
  201.                 initstack();
  202.                 truejp(stmt->exp,contlab);
  203.                 gen_label(breaklab);
  204.                 }
  205.         else
  206.                 {
  207.                 genstmt(stmt->s1);
  208.                 initstack();
  209.                 truejp(stmt->exp,contlab);
  210.                 }
  211.         breaklab = oldbreak;
  212.         contlab = oldcont;
  213. }
  214.  
  215. AMODE *set_symbol(char *name,int flag)
  216. {
  217.     SYM *sp;
  218.     AMODE *ap;
  219.         sp = gsearch(name);
  220.         if( sp == 0 )
  221.                 {
  222.                 ++global_flag;
  223.                 sp = xalloc(sizeof(SYM));
  224.                 sp->tp = &stdfunc;
  225.                 sp->name = name;
  226.                                 if (flag)
  227.                                     sp->storage_class = sc_externalfunc;
  228.                                 else
  229.                     sp->storage_class = sc_external;
  230.                                 sp->extflag = 1;
  231.                 insert(sp,&gsyms);
  232.                 --global_flag;
  233.                 }
  234.                 ap = make_strlab(name);
  235.                 ap->mode = am_immed;
  236.     return ap;
  237. }
  238. void call_library(char *lib_name)
  239. /*
  240.  *      generate a call to a library routine.
  241.  */
  242. {
  243.                 AMODE *ap;
  244.                 ap = set_symbol(lib_name,1);
  245.         gen_code(op_call,0,ap,0);
  246. }
  247.  
  248. int analyzeswitch(SNODE *stmt)
  249. {
  250.     switchbottom = 0x7fff;
  251.     switchtop = 0;
  252.     switchcount = 0;
  253.     stmt = stmt->s1;
  254.     while (stmt) {
  255.         if (!stmt->s2) {
  256.             switchcount++;
  257.             if ((int)stmt->label < switchbottom)
  258.                 switchbottom = (int)stmt->label;
  259.             if ((int)stmt->label > switchtop)
  260.                 switchtop = (int)stmt->label;
  261.         }
  262.         stmt = stmt->next;
  263.     }
  264.     switchtop++;
  265.     if (switchcount == 0)
  266.         return(0);
  267.     if (switchcount > 3)
  268.         if (switchcount*10/(switchtop-switchbottom) >= 8)
  269.             return(1);
  270.     return(2);
  271. }
  272. void bingen(int lower, int avg, int higher,AMODE *ap1, int deflab, int size)
  273. {
  274.     AMODE *ap2 = make_immed(switchids[avg]);
  275.     AMODE *ap3 = make_label(switchlabels[avg]);
  276.     if (switchbinlabels[avg] != -1)
  277.         gen_label(switchbinlabels[avg]);
  278.     gen_code(op_cmp,4,ap1,ap2);
  279.     gen_code(op_je,0,ap3,0);
  280.     if (avg == lower) {
  281.         ap3 = make_label(deflab);
  282.         gen_code(op_jmp,0,ap3,0);
  283.     }
  284.     else {
  285.         int avg1 = (lower + avg)/2;
  286.         int avg2 = (higher + avg+1)/2;
  287.         if (avg+1 < higher) 
  288.             ap3 = make_label(switchbinlabels[avg2]=nextlabel++);
  289.         else
  290.             ap3 = make_label(deflab);
  291.         if (size < 0)
  292.             gen_code(op_jg,0,ap3,0);
  293.         else
  294.             gen_code(op_ja,0,ap3,0);
  295.         bingen(lower,avg1,avg,ap1,deflab,size);
  296.         if (avg+1 < higher)
  297.             bingen(avg+1,avg2,higher,ap1,deflab,size);
  298.     }
  299. }
  300. void genbinaryswitch(SNODE *stmt)
  301. {
  302.     int curlab, i=0,j,size = natural_size(stmt->exp);
  303.     AMODE *ap1;
  304.     deflab = nextlabel++;
  305.     curlab = nextlabel++;
  306.   initstack();
  307.   ap1 = gen_expr(stmt->exp,F_DREG,4);
  308.     global_flag++;
  309.     if (switchcount > oldswitchsize) {
  310.         switchlabels = xalloc((switchcount) * sizeof(int));
  311.         switchids = switchbinlabels = 0;
  312.         oldswitchsize = switchcount;
  313.     }
  314.     if (!switchids) {
  315.         switchbinlabels = xalloc((switchcount) * sizeof(int));
  316.         switchids = xalloc((switchcount) * sizeof(int));
  317.     }
  318.     global_flag--;
  319.     stmt = stmt->s1;
  320.     while (stmt) {
  321.                 if( stmt->s2 )          /* default case ? */
  322.                         {
  323.                         stmt->label = (SNODE *) deflab;
  324.                                                 diddef = TRUE;
  325.                         }
  326.                 else
  327.                         {
  328.                                                 switchlabels[i] = curlab;
  329.                                                 switchbinlabels[i] = -1;
  330.                                                 switchids[i++] = (int)stmt->label;
  331.                                                 stmt->label = (SNODE *)curlab;
  332.                         }
  333.                 if( stmt->s1 != 0 && stmt->next != 0 )
  334.                         curlab = nextlabel++;
  335.                 stmt = stmt->next;
  336.                 }
  337.     for (i=0; i < switchcount; i++)
  338.         for (j=i+1; j < switchcount; j++)
  339.             if (switchids[j] < switchids[i]) {
  340.                 int temp = switchids[i];
  341.                 switchids[i] = switchids[j];
  342.                 switchids[j] = temp;
  343.                 temp = switchlabels[i];
  344.                 switchlabels[i] = switchlabels[j];
  345.                 switchlabels[j] = temp;
  346.             }
  347.     bingen(0,(switchcount)/2,switchcount,ap1,deflab,size);
  348.     freeop(ap1);
  349. }
  350. void gencompactswitch(SNODE *stmt)
  351. {       int             tablab,curlab,i, size = natural_size(stmt->exp);
  352.         AMODE    *ap,*ap2;
  353.                 tablab = nextlabel++;
  354.         deflab = nextlabel++;
  355.         curlab = nextlabel++;
  356.         initstack();
  357.         ap = gen_expr(stmt->exp,F_DREG | F_VOL,4);
  358.                 initstack();
  359.                 if (switchbottom)
  360.                     gen_code(op_sub,4,ap,make_immed(switchbottom));
  361.                 if (size < 0)
  362.                     gen_code(op_jl,0,make_label(deflab),0);
  363.                 else
  364.                     gen_code(op_jb,0,make_label(deflab),0);
  365.                 gen_code(op_cmp,4,ap,make_immed(switchtop-switchbottom));
  366.                 if (size < 0)
  367.                     gen_code(op_jge,0,make_label(deflab),0);
  368.                 else
  369.                     gen_code(op_jnc,0,make_label(deflab),0);
  370.                 gen_code(op_shl,4,ap,make_immed(2));
  371.                 ap2 = xalloc(sizeof(AMODE));
  372.                 ap->mode = am_indisp;
  373.                 ap2->preg = ap->preg;
  374.                 ap->offset = makenode(en_labcon,(char *)tablab,0);
  375.                 gen_code(op_jmp,4,ap,0);
  376.  
  377.                 initstack();
  378.                 gen_label(tablab);
  379.     if (switchtop - switchbottom > oldswitchsize) {
  380.         global_flag++;
  381.         switchlabels = xalloc((switchtop-switchbottom) * sizeof(int));
  382.         switchids = switchbinlabels = 0;
  383.         global_flag--;
  384.         oldswitchsize = switchtop - switchbottom;
  385.     }
  386.     for (i=switchbottom; i < switchtop; i++) {
  387.         switchlabels[i-switchbottom] = deflab;
  388.     }
  389.     stmt = stmt->s1;
  390.     while (stmt) {
  391.                 if( stmt->s2 )          /* default case ? */
  392.                         {
  393.                         stmt->label = (SNODE *)deflab;
  394.                                                 diddef = TRUE;
  395.                         }
  396.                 else
  397.                         {
  398.                                                 switchlabels[(int)stmt->label-switchbottom] = curlab;
  399.                                                 stmt->label = (SNODE *)curlab;
  400.                         }
  401.                 if( stmt->s1 != 0 && stmt->next != 0 )
  402.                         curlab = nextlabel++;
  403.                 stmt = stmt->next;
  404.                 }
  405.     align(4);
  406.     for (i=0; i < switchtop-switchbottom; i++)
  407.         gen_code(op_dd,4,make_label(switchlabels[i]),0);
  408. }
  409.  
  410. void gencase(SNODE *stmt)
  411. /*
  412.  *      generate all cases for a switch statement.
  413.  */
  414. {       while( stmt != 0 )
  415.                 {
  416.                 if( stmt->s1 != 0 )
  417.                         {
  418.                         gen_label((int)stmt->label);
  419.                         genstmt(stmt->s1);
  420.                         }
  421.                 else if( stmt->next == 0 )
  422.                         gen_label((int)stmt->label);
  423.  
  424.                 stmt = stmt->next;
  425.                 }
  426. }
  427.  
  428. void genxswitch(SNODE *stmt)
  429. /*
  430.  *      analyze and generate best switch statement.
  431.  */
  432. {       int     oldbreak;
  433.         oldbreak = breaklab;
  434.         breaklab = nextlabel++;
  435.                 diddef = FALSE;
  436.                 switch (analyzeswitch(stmt)) {
  437.               case 2:
  438.                         genbinaryswitch(stmt);
  439.                         break;
  440.                     case 1:
  441.                         gencompactswitch(stmt);
  442.                         break;
  443.                     case 0:
  444.                         if (stmt->s1)
  445.                             stmt->s1->label = (SNODE *) nextlabel++;
  446.                         break;
  447.                 }
  448.         gencase(stmt->s1);
  449.                 if (!diddef)
  450.                     gen_label(deflab);
  451.         gen_label(breaklab);
  452.         breaklab = oldbreak;
  453. }
  454.  
  455. void genreturn(SNODE *stmt, int flag)
  456. /*
  457.  *      generate a return statement.
  458.  */
  459. {       AMODE    *ap,*ap1;
  460.                 int size;
  461.         if( stmt != 0 && stmt->exp != 0 ) {
  462.                 initstack();
  463.                                 if (currentfunc->tp->btp && currentfunc->tp->btp->type != bt_void && (currentfunc->tp->btp->type == bt_struct || currentfunc->tp->btp->type == bt_union)) {
  464.                                     size = currentfunc->tp->btp->size;
  465.                                     ap = gen_expr(stmt->exp,F_ALL,4);
  466.                                     ap1 = make_stack(-stackdepth-framedepth);
  467.                                     if (!(save_mask & 0x40))
  468.                                         gen_push(ESI,am_dreg,0);                                  
  469.                                     if (!(save_mask & 0x80))
  470.                                         gen_push(EDI,am_dreg,0);                                  
  471.                                     gen_code(op_mov,4,makedreg(ESI),ap);                          
  472.                                     gen_code(op_mov,4,makedreg(EDI),ap1);
  473.                                     gen_code(op_mov,4,makedreg(EAX),makedreg(EDI));
  474.                                     gen_code(op_mov,4,makedreg(ECX),make_immed(size));  
  475.                                     gen_code(op_rep,1,0,0);                                   
  476.                                     gen_code(op_movsb,1,0,0);                                      
  477.                                     if (!(save_mask & 0x80))
  478.                                         gen_pop(EDI,am_dreg,0);
  479.                                     if (!(save_mask & 0x40))
  480.                                         gen_pop(ESI,am_dreg,0);
  481.                                 }
  482.                                 else {
  483.                                     size = natural_size(stmt->exp);
  484.                     ap = gen_expr(stmt->exp,F_ALL,size);
  485.                                     if (size > 4) {
  486.                                         if (ap->mode != am_freg)
  487.                                             gen_code(op_fld,size,ap,0);
  488.                                     }
  489.                     else
  490.                             if( ap->mode != am_dreg || ap->preg != 0 )
  491.                             gen_code(op_mov,4,makedreg(0),ap);
  492.                 }
  493.                                 freeop(ap);
  494.                 }
  495.                 if (flag) {
  496.             if( retlab != -1 )
  497.                 gen_label(retlab);
  498.                     gen_code(op_add,4,makedreg(ESP),make_immed(lc_maxauto));
  499.                     exitref = peep_tail;
  500.           if( fsave_mask != 0 )
  501.                         diag("Float restore in return");
  502.                     if (currentfunc->intflag) {
  503.                         gen_code(op_popad,0,0,0);
  504.                gen_code(op_iretd,0,0,0);
  505.                     }
  506.                     else {
  507.                if( save_mask != 0 )
  508.                             popregs(save_mask);
  509.             gen_code(op_ret,0,0,0);
  510.                     }
  511.                 }
  512.         else {
  513.                     if (retlab == -1)
  514.             retlab = nextlabel++;
  515.           gen_code(op_jmp,0,make_label(retlab),0);
  516.                 }
  517. }
  518.  
  519. void genstmt(SNODE *stmt)
  520. /*
  521.  *      genstmt will generate a statement and follow the next pointer
  522.  *      until the block is generated.
  523.  */
  524. {
  525.            while( stmt != 0 )
  526.                 {
  527.                 switch( stmt->stype )
  528.                         {
  529.                                                 case st_block:
  530.                                                                 genstmt(stmt->exp);
  531.                                                                 break;
  532.                         case st_label:
  533.                                 gen_label((int)stmt->label);
  534.                                 break;
  535.                         case st_goto:
  536.                                 gen_code(op_jmp,0,make_label((int)stmt->label),0);
  537.                                 break;
  538.                         case st_expr:
  539.                                 initstack();
  540.                                 gen_expr(stmt->exp,F_ALL | F_NOVALUE,
  541.                                         natural_size(stmt->exp));
  542.                                 break;
  543.                         case st_return:
  544.                                 genreturn(stmt,0);
  545.                                 break;
  546.                         case st_if:
  547.                                 genif(stmt);
  548.                                 break;
  549.                         case st_while:
  550.                                 genwhile(stmt);
  551.                                 break;
  552.                         case st_do:
  553.                                 gendo(stmt);
  554.                                 break;
  555.                         case st_for:
  556.                                 gen_for(stmt);
  557.                                 break;
  558.                         case st_continue:
  559.                                 gen_code(op_jmp,0,make_label(contlab),0);
  560.                                 break;
  561.                         case st_break:
  562.                                 gen_code(op_jmp,0,make_label(breaklab),0);
  563.                                 break;
  564.                         case st_switch:
  565.                                 genxswitch(stmt);
  566.                                 break;
  567.                                                 case st_line:
  568.                                                                  gen_line(stmt);
  569.                                                                 break;
  570.                                                 case st__genword:
  571.                                                                 gen_code(op_genword,0,make_immed((int)stmt->exp),0);
  572.                                                                 break;
  573.                         default:
  574.  
  575.                                 diag("unknown statement.");
  576.                                 break;
  577.                         }
  578.                 stmt = stmt->next;
  579.                 }
  580. }
  581. void scppinit(void)
  582. {
  583.     if (!strcmp(currentfunc->name,"_main")) {
  584.         AMODE *ap1,*ap2,*ap3,*ap4;
  585.         int lbl = nextlabel++;
  586.         initstack();
  587.         ap1 = temp_data();
  588.         ap4 = xalloc(sizeof(AMODE));
  589.         ap4->preg = ap1->preg;
  590.         ap4->mode = am_indisp;
  591.         ap4->offset = makenode(en_icon,0,0);
  592.         ap2 = set_symbol("cppistart",0);
  593.         ap3 = set_symbol("cppiend",0);
  594.         gen_code(op_mov,4,ap1,ap2);
  595.         gen_label(lbl);
  596.         gen_code(op_push,4,ap1,0);
  597.         gen_code(op_call,4,ap4,0);
  598.         gen_code(op_pop,4,ap1,0);
  599.         gen_code(op_add,4,ap1,make_immed(4));
  600.         gen_code(op_cmp,4,ap1,ap3);
  601.         gen_code(op_jb,0,make_label(lbl),0);
  602.         freeop(ap1);
  603.     }
  604. }
  605.  
  606. void genfunc(SNODE *stmt)
  607. /*
  608.  *      generate a function body.
  609.  */
  610. {       retlab = contlab = breaklab = -1;
  611.         funcfloat = 0;
  612.                 init_muldivval();
  613.                 stackdepth = 0;
  614.                 if (stmt->stype == st_line) {
  615.                     gen_line(stmt);
  616.                     stmt = stmt->next;
  617.                 }
  618.                     
  619.         opt1(stmt);            /* push args & also subtracts SP */
  620.                 if (prm_cplusplus)
  621.                     scppinit();
  622.                 switchbottom = switchtop = 0;
  623.         genstmt(stmt);
  624.         genreturn(0,1);
  625.         if (!lc_maxauto) {
  626.             entryref->fwd->back = entryref->back;
  627.             entryref->back->fwd = entryref->fwd;
  628.             exitref->fwd->back = exitref->back;
  629.             exitref->back->fwd = exitref->fwd;
  630.         }
  631. }