home *** CD-ROM | disk | FTP | other *** search
/ CD Shareware Magazine 1996 December / CD_shareware_12-96.iso / DOS / Programa / CCDL122.ZIP / SOURCE / PEEP68.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-29  |  14.5 KB  |  487 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 SYM *currentfunc;
  28.  
  29. OCODE    *peep_head = 0,
  30.                 *peep_tail = 0;
  31.  
  32. void peepini(void)
  33. {
  34.     peep_head = peep_tail = 0;
  35. }
  36. AMODE    *copy_addr(AMODE *ap)
  37. /*
  38.  *      copy an address mode structure (these things dont last).
  39.  */
  40. {       AMODE    *newap;
  41.         if( ap == 0 )
  42.                 return 0;
  43.         newap = xalloc(sizeof(AMODE));
  44.         newap->mode = ap->mode;
  45.         newap->preg = ap->preg;
  46.         newap->sreg = ap->sreg;
  47.         newap->tempflag = ap->tempflag;
  48.         newap->offset = ap->offset;
  49.         return newap;
  50. }
  51.  
  52. void gen_code(int op,int len,AMODE *ap1,AMODE *ap2)
  53. /*
  54.  *      generate a code sequence into the peep list.
  55.  */
  56. {       OCODE    *new;
  57.         new = xalloc(sizeof(OCODE));
  58.         new->opcode = op;
  59.                 if (len < 0)
  60.             new->length = -len;
  61.                 else
  62.             new->length = len;
  63.         new->oper1 = copy_addr(ap1);
  64.         new->oper2 = copy_addr(ap2);
  65.                 new->oper3 = 0;
  66.         add_peep(new);
  67. }
  68. void gen_line(SNODE *stmt)
  69. {
  70.                 OCODE *new = xalloc(sizeof(OCODE));
  71.                 new->opcode = op_line;
  72.                 new->length = (int)stmt->exp;
  73.                 new->oper1 = (AMODE *)stmt->label;
  74.                 new->oper2 = 0;
  75.                 new->oper3= 0;
  76.                 add_peep(new);
  77. }
  78. void gen_codef(int op, int len, AMODE *ap1, AMODE *ap2)
  79. {
  80.   if (ap1->mode == am_freg) {
  81.         if (!ap2 || ap2->mode == am_freg)
  82.             len=10;
  83.     }
  84.     else if (ap2 && ap2->mode == am_freg) {
  85.         if (ap1->mode == am_immed)
  86.             len = 10;
  87.     }
  88.     gen_code(op,len,ap1,ap2);
  89. }
  90. void gen_code3(int op, int len, AMODE *ap1, AMODE *ap2, AMODE *ap3)
  91. {       OCODE    *new;
  92.         new = xalloc(sizeof(OCODE));
  93.         new->opcode = op;
  94.                 if (len < 0)
  95.             new->length = -len;
  96.                 else
  97.             new->length = len;
  98.         new->oper1 = copy_addr(ap1);
  99.         new->oper2 = copy_addr(ap2);
  100.                 new->oper3 = copy_addr(ap3);
  101.         add_peep(new);
  102. }
  103. void add_peep(OCODE *new)
  104. /*
  105.  *      add the ocoderuction pointed to by new to the peep list.
  106.  */
  107. {       if( peep_head == 0 )
  108.                 {
  109.                 peep_head = peep_tail = new;
  110.                 new->fwd = 0;
  111.                 new->back = 0;
  112.                 }
  113.         else
  114.                 {
  115.                 new->fwd = 0;
  116.                 new->back = peep_tail;
  117.                 peep_tail->fwd = new;
  118.                 peep_tail = new;
  119.                 }
  120. }
  121.  
  122. void gen_label(int labno)
  123. /*
  124.  *      add a compiler generated label to the peep list.
  125.  */
  126. {       OCODE    *new;
  127.         new = xalloc(sizeof(OCODE));
  128.         new->opcode = op_label;
  129.         new->oper1 = (AMODE *)labno;
  130.         add_peep(new);
  131. }
  132.  
  133. void flush_peep(void)
  134. /*
  135.  *      output all code and labels in the peep list.
  136.  */
  137. {       opt3();         /* do the peephole optimizations */
  138.         while( peep_head != 0 )
  139.                 {
  140.                 if( peep_head->opcode == op_label )
  141.                         put_label((int)peep_head->oper1);
  142.                 else
  143.                         put_ocode(peep_head);
  144.                 peep_head = peep_head->fwd;
  145.                 }
  146. }
  147.  
  148. void put_ocode(OCODE *p)
  149. /*
  150.  *      output the instruction passed.
  151.  */
  152. {       put_code(p->opcode,p->length,p->oper1,p->oper2,p->oper3);
  153. }
  154.  
  155. void peep_move(OCODE *ip)
  156. /*
  157.  *      peephole optimization for move instructions.
  158.  *      makes quick immediates when possible.
  159.  *      changes move #0,d to clr d.
  160.  *      changes long moves to address registers to short when
  161.  *              possible.
  162.  *      changes move immediate to stack to pea.
  163.  */
  164. {       ENODE    *ep;
  165.         if( ip->oper1->mode != am_immed )
  166.                 return;
  167.         ep = ip->oper1->offset;
  168.         if( ep->nodetype != en_icon )
  169.                 return;
  170.         if( ip->oper2->mode == am_areg )
  171.                 {
  172.                 if( -32768L <= ep->v.i && ep->v.i <= 32768L )
  173.                         ip->length = 2;
  174.                 }
  175.         else if( ip->oper2->mode == am_dreg )
  176.                 {
  177.                 if( -128 <= ep->v.i && ep->v.i <= 127 )
  178.                         {
  179.                         ip->opcode = op_moveq;
  180.                         ip->length = 0;
  181.                         }
  182.                 }
  183.         else
  184.                 {
  185.                 if( ep->v.i == 0 )
  186.                         {
  187.                         ip->opcode = op_clr;
  188.                         ip->oper1 = ip->oper2;
  189.                         ip->oper2 = 0;
  190.                         }
  191.                 else if( ip->oper2->mode == am_adec && ip->oper2->preg == 7 )
  192.                         {
  193.                         ip->opcode = op_pea;           
  194.                         ip->length = 0;
  195.                         ip->oper1->mode = am_direct;
  196.                         ip->oper2 = 0;
  197.                         }
  198.                 }
  199. }
  200.  
  201. /*
  202.  * get rid of a TST after a MOVE if the args match
  203.  */
  204. int peep_tst(OCODE *ip)
  205. {
  206.     if (ip->back->opcode == op_move) {
  207.         if (equalap(ip->back->oper2,ip->oper1)) {
  208.             ip->back->fwd = ip->fwd;
  209.             ip->fwd->back = ip->back;
  210.         }
  211.     }
  212. }
  213. int equalap(AMODE *ap1, AMODE *ap2)
  214. {
  215.     if (!ap1 || !ap2)
  216.         return(FALSE);
  217.     if (ap1->mode != ap2->mode)
  218.         return(FALSE);
  219.     if (ap1->mode != am_direct && ap1->mode != am_immed)
  220.         if (ap1->preg != ap2->preg)
  221.             return(FALSE);
  222.     if (ap1->mode == am_indx || ap1->mode == am_pcindx || ap1->mode == am_indx2
  223.             || ap1->mode == am_indx3 || ap1->mode == am_direct || ap1->mode == am_immed)
  224.         return(equalnode(ap1->offset, ap2->offset));
  225.     return(TRUE);
  226. }
  227.  
  228. int     equal_address(AMODE *ap1, AMODE *ap2)
  229. /*
  230.  *      compare two address nodes and return true if they are
  231.  *      equivalent.
  232.  */
  233. {       if( ap1 == 0 || ap2 == 0 )
  234.                 return 0;
  235.         if( ap1->mode != ap2->mode )
  236.                 return 0;
  237.         switch( ap1->mode )
  238.                 {
  239.                 case am_areg:   case am_dreg:
  240.                 case am_ainc:   case am_adec:
  241.                         return ap1->preg == ap2->preg;
  242.                 }
  243.         return 0;
  244. }
  245.  
  246. void peep_add(OCODE *ip)
  247. /*
  248.  *      peephole optimization for add instructions.
  249.  *      makes quick immediates out of small constants.
  250.  */
  251. {       ENODE    *ep;
  252.         if( ip->oper1->mode != am_immed )
  253.                 return;
  254.         ep = ip->oper1->offset;
  255.         if( ip->oper2->mode != am_areg )
  256.                 ip->opcode = op_addi;
  257.         else
  258.                 {
  259.                 if( isshort(ep) )
  260.                         ip->length = 2;
  261.                 }
  262.         if( ep->nodetype != en_icon )
  263.                 return;
  264.         if( 1 <= ep->v.i && ep->v.i <= 8 )
  265.                 ip->opcode = op_addq;
  266.         else if( -8 <= ep->v.i && ep->v.i <= -1 )
  267.                 {
  268.                 ip->opcode = op_subq;
  269.                 ep->v.i = -ep->v.i;
  270.                 }
  271. }
  272.  
  273. void peep_sub(OCODE *ip)
  274. /*
  275.  *      peephole optimization for subtract instructions.
  276.  *      makes quick immediates out of small constants.
  277.  */
  278. {       ENODE    *ep;
  279.         if( ip->oper1->mode != am_immed )
  280.                 return;
  281.         ep = ip->oper1->offset;
  282.         if( ip->oper2->mode != am_areg )
  283.                 ip->opcode = op_subi;
  284.         else
  285.                 {
  286.                 if( isshort(ep) )
  287.                         ip->length = 2;
  288.                 }
  289.         if( ep->nodetype != en_icon )
  290.                 return;
  291.         if( 1 <= ep->v.i && ep->v.i <= 8 )
  292.                 ip->opcode = op_subq;
  293.         else if( -8 <= ep->v.i && ep->v.i <= -1 )
  294.                 {
  295.                 ip->opcode = op_addq;
  296.                 ep->v.i = -ep->v.i;
  297.                 }
  298. }
  299.  
  300. void     peep_cmp(OCODE *ip)
  301. /*
  302.  *      peephole optimization for compare instructions.
  303.  *      changes compare #0 to tst and if previous instruction
  304.  *      should have set the condition codes properly delete.
  305.  *      return value is true if instruction was deleted.
  306.  */
  307. {       OCODE    *prev;
  308.         ENODE    *ep;
  309.         if( ip->oper1->mode != am_immed )
  310.                 return;
  311.         ep = ip->oper1->offset;
  312.         if( ip->oper2->mode == am_areg )
  313.                 {
  314.                 if( isshort(ep) )
  315.                         ip->length = 2;
  316.                 return;
  317.                 }
  318.         ip->opcode = op_cmpi;
  319.         if( ep->nodetype != en_icon || ep->v.i != 0 )
  320.                 return;
  321.         ip->oper1 = ip->oper2;
  322.         ip->oper2 = 0;
  323.         ip->opcode = op_tst;
  324.         prev = ip->back;
  325.         if( prev == 0 )
  326.                 return;
  327.         if( (((prev->opcode == op_move || prev->opcode == op_moveq) &&
  328.                 equal_address(prev->oper1,ip->oper1)) &&
  329.                 prev->oper2->mode != am_areg) ||
  330.                 (prev->opcode != op_label &&
  331.                 equal_address(prev->oper2,ip->oper1)) )
  332.                 {
  333.                 prev->fwd = ip->fwd;
  334.                 if( prev->fwd != 0 )
  335.                         prev->fwd->back = prev;
  336.                 }
  337. }
  338.  
  339. void peep_muldiv(OCODE *ip, int op)
  340. /*
  341.  *      changes multiplies and divides by convienient values
  342.  *      to shift operations. op should be either op_asl or
  343.  *      op_asr (for divide).
  344.  */
  345. {       int     shcnt;
  346.         if( ip->oper1->mode != am_immed )
  347.                 return;
  348.         if( ip->oper1->offset->nodetype != en_icon )
  349.                 return;
  350.         shcnt = ip->oper1->offset->v.i;
  351. /*      vax c doesn't do this type of switch well       */
  352.         if( shcnt == 2) shcnt = 1;
  353.         else if( shcnt == 4) shcnt = 2;
  354.         else if( shcnt == 8) shcnt = 3;
  355.         else if( shcnt == 16) shcnt = 4;
  356.         else if( shcnt == 32) shcnt = 5;
  357.         else if( shcnt == 64) shcnt = 6;
  358.         else if( shcnt == 128) shcnt = 7;
  359.         else if( shcnt == 256) shcnt = 8;
  360.         else if( shcnt == 512) shcnt = 9;
  361.         else if( shcnt == 1024) shcnt = 10;
  362.         else if( shcnt == 2048) shcnt = 11;
  363.         else if( shcnt == 4096) shcnt = 12;
  364.         else if( shcnt == 8192) shcnt = 13;
  365.         else if( shcnt == 16384) shcnt = 14;
  366.         else return;
  367.         ip->oper1->offset->v.i = shcnt;
  368.         ip->opcode = op;
  369.         ip->length = 4;
  370. }
  371.  
  372. void peep_uctran(OCODE *ip)
  373. /*
  374.  *      peephole optimization for unconditional transfers.
  375.  *      deletes instructions which have no path.
  376.  *      applies to bra, jmp, and rts instructions.
  377.  */
  378. {       while( ip->fwd != 0 && ip->fwd->opcode != op_label )
  379.                 {
  380.                 ip->fwd = ip->fwd->fwd;
  381.                 if( ip->fwd != 0 )
  382.                         ip->fwd->back = ip;
  383.                 }
  384. }
  385. void peep_label(OCODE *ip)
  386. /*
  387.  *        peephole optimization for labels
  388.  *        deletes relbranches that jump to the next instruction
  389.  */
  390. {
  391.             OCODE *curpos, *index;
  392.             curpos = ip;
  393.             do {
  394.                 curpos = curpos->back;
  395.             } while(curpos->opcode == op_label);
  396.             while ((curpos->opcode == op_bra) || curpos->opcode == op_cmp
  397.                         || curpos->opcode == op_cmpi || curpos->opcode == op_tst 
  398.                         || (curpos->opcode == op_bne) || (curpos->opcode == op_beq) 
  399.                         || (curpos->opcode == op_bge) || (curpos->opcode == op_ble) 
  400.                         || (curpos->opcode == op_bgt) || (curpos->opcode == op_blt) 
  401.                         || (curpos->opcode == op_bhs) || (curpos->opcode == op_bls) 
  402.                         || (curpos->opcode == op_bhi) || (curpos->opcode == op_blo) ) {
  403.                 index = curpos->fwd;
  404.                 if (curpos->opcode == op_cmpi || curpos->opcode == op_cmp
  405.                                 || curpos->opcode == op_tst) {
  406.                         curpos->back->fwd = curpos->fwd;
  407.                         curpos->fwd->back = curpos->back;
  408.                         curpos = curpos->back;
  409.                 }
  410.                 else {
  411.                     do {
  412.                         if ((int)index->oper1 == curpos->oper1->offset->v.i) {
  413.                             curpos->back->fwd = curpos->fwd;
  414.                             curpos->fwd->back = curpos->back;
  415.                             curpos = curpos->back;
  416.                             break;
  417.                         }
  418.                         index = index->fwd;
  419.                     } while (index != ip->fwd);
  420.                     if (index == ip->fwd)
  421.                         break;
  422.                 }
  423.                 while(curpos->opcode == op_label)
  424.                     curpos = curpos->back;
  425.             }
  426. }
  427.  
  428. void opt3(void)
  429. /*
  430.  *      peephole optimizer. This routine calls the instruction
  431.  *      specific optimization routines above for each instruction
  432.  *      in the peep list.
  433.  */
  434. {       OCODE    *ip;
  435.                 int deletedlink = FALSE;
  436.         ip = peep_head;
  437.         while( ip != 0 )
  438.                 {
  439.                                 if (ip->oper1 && ip->oper1->mode == am_indx && ip->oper1->offset->v.i == 0)
  440.                                     ip->oper1->mode = am_ind;
  441.                                 if (ip->oper2 && ip->oper2->mode == am_indx && ip->oper2->offset->v.i == 0)
  442.                                     ip->oper2->mode = am_ind;
  443.                 switch( ip->opcode )
  444.                         {
  445.                                                 case op_link:
  446.                                                                 if ((currentfunc->tp->lst.head == 0)
  447.                                                                             || currentfunc->tp->lst.head == (SYM *)-1)
  448.                                                                     if (ip->oper2->offset->v.i == 0) {
  449.                                                                         peep_head = peep_head->fwd;
  450.                                                                         deletedlink = TRUE;
  451.                                                                     }
  452.                                                                 break;
  453.                                                 case op_unlk:
  454.                                                                 if (deletedlink) {
  455.                                                                     ip->back->fwd = ip->fwd;
  456.                                                                     ip->fwd->back = ip->back;
  457.                                                                 }
  458.                                                                 break;
  459.                         case op_move:
  460.                                 peep_move(ip);
  461.                                 break;
  462.                         case op_add:
  463.                                 peep_add(ip);
  464.                                 break;
  465.                         case op_sub:
  466.                                 peep_sub(ip);
  467.                                 break;
  468.                                                 case op_tst:
  469.                                                                 peep_tst(ip);
  470.                                                                 break;
  471.                         case op_cmp:
  472.                                 peep_cmp(ip);
  473.                                 break;
  474.                         case op_muls:
  475.                                 peep_muldiv(ip,op_asl);
  476.                                 break;
  477.                                                 case op_label:
  478.                                                                 peep_label(ip);
  479.                                                                 break;
  480.                         case op_bra:
  481.                         case op_jmp:
  482.                         case op_rts:
  483.                                 peep_uctran(ip);
  484.                         }
  485.                 ip = ip->fwd;
  486.                 }
  487. }