home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_300 / 338_02 / peepgen.c < prev    next >
Text File  |  1979-12-31  |  11KB  |  363 lines

  1. #include        <stdio.h>
  2. #include        "c.h"
  3. #include        "expr.h"
  4. #include        "gen.h"
  5. #include        "cglbdec.h"
  6.  
  7. /*
  8.  *    68000 C compiler
  9.  *
  10.  *    Copyright 1984, 1985, 1986 Matthew Brandt.
  11.  *  all commercial rights reserved.
  12.  *
  13.  *    This compiler is intended as an instructive tool for personal use. Any
  14.  *    use for profit without the written consent of the author is prohibited.
  15.  *
  16.  *    This compiler may be distributed freely for non-commercial use as long
  17.  *    as this notice stays intact. Please forward any enhancements or questions
  18.  *    to:
  19.  *
  20.  *        Matthew Brandt
  21.  *        Box 920337
  22.  *        Norcross, Ga 30092
  23.  */
  24.  
  25. struct ocode    *peep_head = 0,
  26.                 *peep_tail = 0;
  27.  
  28. struct amode    *copy_addr(ap)
  29. /*
  30.  *      copy an address mode structure (these things dont last).
  31.  */
  32. struct amode    *ap;
  33. {       struct amode    *newap;
  34.         if( ap == 0 )
  35.                 return 0;
  36.         newap = xalloc(sizeof(struct amode));
  37.         newap->mode = ap->mode;
  38.         newap->preg = ap->preg;
  39.         newap->sreg = ap->sreg;
  40.         newap->tempflag = ap->tempflag;
  41.         newap->deep = ap->deep;
  42.         newap->offset = ap->offset;
  43.         return newap;
  44. }
  45.  
  46. gen_code(op,len,ap1,ap2)
  47. /*
  48.  *      generate a code sequence into the peep list.
  49.  */
  50. int             op, len;
  51. struct amode    *ap1, *ap2;
  52. {       struct ocode    *new;
  53.         new = xalloc(sizeof(struct ocode));
  54.         new->opcode = op;
  55.         new->length = len;
  56.         new->oper1 = copy_addr(ap1);
  57.         new->oper2 = copy_addr(ap2);
  58.         add_peep(new);
  59. }
  60.  
  61. add_peep(new)
  62. /*
  63.  *      add the ocoderuction pointed to by new to the peep list.
  64.  */
  65. struct ocode    *new;
  66. {       if( peep_head == 0 )
  67.                 {
  68.                 peep_head = peep_tail = new;
  69.                 new->fwd = 0;
  70.                 new->back = 0;
  71.                 }
  72.         else
  73.                 {
  74.                 new->fwd = 0;
  75.                 new->back = peep_tail;
  76.                 peep_tail->fwd = new;
  77.                 peep_tail = new;
  78.                 }
  79. }
  80.  
  81. gen_label(labno)
  82. /*
  83.  *      add a compiler generated label to the peep list.
  84.  */
  85. int     labno;
  86. {       struct ocode    *new;
  87.         new = xalloc(sizeof(struct ocode));
  88.         new->opcode = op_label;
  89.         new->oper1 = labno;
  90.         add_peep(new);
  91. }
  92.  
  93. flush_peep()
  94. /*
  95.  *      output all code and labels in the peep list.
  96.  */
  97. {       opt3();         /* do the peephole optimizations */
  98.         while( peep_head != 0 )
  99.                 {
  100.                 if( peep_head->opcode == op_label )
  101.                         put_label(peep_head->oper1);
  102.                 else
  103.                         put_ocode(peep_head);
  104.                 peep_head = peep_head->fwd;
  105.                 }
  106. }
  107.  
  108. put_ocode(p)
  109. /*
  110.  *      output the instruction passed.
  111.  */
  112. struct ocode    *p;
  113. {       put_code(p->opcode,p->length,p->oper1,p->oper2);
  114. }
  115.  
  116. peep_move(ip)
  117. /*
  118.  *      peephole optimization for move instructions.
  119.  *      makes quick immediates when possible.
  120.  *      changes move #0,d to clr d.
  121.  *      changes long moves to address registers to short when
  122.  *              possible.
  123.  *      changes move immediate to stack to pea.
  124.  */
  125. struct ocode    *ip;
  126. {       struct enode    *ep;
  127.         if( ip->oper1->mode != am_immed )
  128.                 return;
  129.         ep = ip->oper1->offset;
  130.         if( ep->nodetype != en_icon )
  131.                 return;
  132.         if( ip->oper2->mode == am_areg )
  133.                 {
  134.                 if( -32768 <= ep->v.i && ep->v.i <= 32768 )
  135.                         ip->length = 2;
  136.                 }
  137.         else if( ip->oper2->mode == am_dreg )
  138.                 {
  139.                 if( -128 <= ep->v.i && ep->v.i <= 127 )
  140.                         {
  141.                         ip->opcode = op_moveq;
  142.                         ip->length = 0;
  143.                         }
  144.                 }
  145.         else
  146.                 {
  147.                 if( ep->v.i == 0 )
  148.                         {
  149.                         ip->opcode = op_clr;
  150.                         ip->oper1 = ip->oper2;
  151.                         ip->oper2 = 0;
  152.                         }
  153.                 else if( ip->oper2->mode == am_adec && ip->oper2->preg == 7 )
  154.                         {
  155.                         ip->opcode = op_pea;
  156.                         ip->length = 0;
  157.                         ip->oper1->mode = am_direct;
  158.                         ip->oper2 = 0;
  159.                         }
  160.                 }
  161. }
  162.  
  163. int     equal_address(ap1,ap2)
  164. /*
  165.  *      compare two address nodes and return true if they are
  166.  *      equivalent.
  167.  */
  168. struct amode    *ap1, *ap2;
  169. {       if( ap1 == 0 || ap2 == 0 )
  170.                 return 0;
  171.         if( ap1->mode != ap2->mode )
  172.                 return 0;
  173.         switch( ap1->mode )
  174.                 {
  175.                 case am_areg:   case am_dreg:
  176.                 case am_ainc:   case am_adec:
  177.                         return ap1->preg == ap2->preg;
  178.                 }
  179.         return 0;
  180. }
  181.  
  182. peep_add(ip)
  183. /*
  184.  *      peephole optimization for add instructions.
  185.  *      makes quick immediates out of small constants.
  186.  */
  187. struct ocode    *ip;
  188. {       struct enode    *ep;
  189.         if( ip->oper1->mode != am_immed )
  190.                 return;
  191.         ep = ip->oper1->offset;
  192.         if( ip->oper2->mode != am_areg )
  193.                 ip->opcode = op_addi;
  194.         else
  195.                 {
  196.                 if( isshort(ep) )
  197.                         ip->length = 2;
  198.                 }
  199.         if( ep->nodetype != en_icon )
  200.                 return;
  201.         if( 1 <= ep->v.i && ep->v.i <= 8 )
  202.                 ip->opcode = op_addq;
  203.         else if( -8 <= ep->v.i && ep->v.i <= -1 )
  204.                 {
  205.                 ip->opcode = op_subq;
  206.                 ep->v.i = -ep->v.i;
  207.                 }
  208. }
  209.  
  210. peep_sub(ip)
  211. /*
  212.  *      peephole optimization for subtract instructions.
  213.  *      makes quick immediates out of small constants.
  214.  */
  215. struct ocode    *ip;
  216. {       struct enode    *ep;
  217.         if( ip->oper1->mode != am_immed )
  218.                 return;
  219.         ep = ip->oper1->offset;
  220.         if( ip->oper2->mode != am_areg )
  221.                 ip->opcode = op_subi;
  222.         else
  223.                 {
  224.                 if( isshort(ep) )
  225.                         ip->length = 2;
  226.                 }
  227.         if( ep->nodetype != en_icon )
  228.                 return;
  229.         if( 1 <= ep->v.i && ep->v.i <= 8 )
  230.                 ip->opcode = op_subq;
  231.         else if( -8 <= ep->v.i && ep->v.i <= -1 )
  232.                 {
  233.                 ip->opcode = op_addq;
  234.                 ep->v.i = -ep->v.i;
  235.                 }
  236. }
  237.  
  238. int     peep_cmp(ip)
  239. /*
  240.  *      peephole optimization for compare instructions.
  241.  *      changes compare #0 to tst and if previous instruction
  242.  *      should have set the condition codes properly delete.
  243.  *      return value is true if instruction was deleted.
  244.  */
  245. struct ocode    *ip;
  246. {       struct ocode    *prev;
  247.         struct enode    *ep;
  248.         if( ip->oper1->mode != am_immed )
  249.                 return;
  250.         ep = ip->oper1->offset;
  251.         if( ip->oper2->mode == am_areg )
  252.                 {
  253.                 if( isshort(ep) )
  254.                         ip->length = 2;
  255.                 return;
  256.                 }
  257.         ip->opcode = op_cmpi;
  258.         if( ep->nodetype != en_icon || ep->v.i != 0 )
  259.                 return;
  260.         ip->oper1 = ip->oper2;
  261.         ip->oper2 = 0;
  262.         ip->opcode = op_tst;
  263.         prev = ip->back;
  264.         if( prev == 0 )
  265.                 return;
  266.         if( (((prev->opcode == op_move || prev->opcode == op_moveq) &&
  267.                 equal_address(prev->oper1,ip->oper1)) &&
  268.                 prev->oper2->mode != am_areg) ||
  269.                 (prev->opcode != op_label &&
  270.                 equal_address(prev->oper2,ip->oper1)) )
  271.                 {
  272.                 prev->fwd = ip->fwd;
  273.                 if( prev->fwd != 0 )
  274.                         prev->fwd->back = prev;
  275.                 }
  276. }
  277.  
  278. peep_muldiv(ip,op)
  279. /*
  280.  *      changes multiplies and divides by convienient values
  281.  *      to shift operations. op should be either op_asl or
  282.  *      op_asr (for divide).
  283.  */
  284. struct ocode    *ip;
  285. {       int     shcnt;
  286.         if( ip->oper1->mode != am_immed )
  287.                 return;
  288.         if( ip->oper1->offset->nodetype != en_icon )
  289.                 return;
  290.         shcnt = ip->oper1->offset->v.i;
  291. /*      vax c doesn't do this type of switch well       */
  292.         if( shcnt == 2) shcnt = 1;
  293.         else if( shcnt == 4) shcnt = 2;
  294.         else if( shcnt == 8) shcnt = 3;
  295.         else if( shcnt == 16) shcnt = 4;
  296.         else if( shcnt == 32) shcnt = 5;
  297.         else if( shcnt == 64) shcnt = 6;
  298.         else if( shcnt == 128) shcnt = 7;
  299.         else if( shcnt == 256) shcnt = 8;
  300.         else if( shcnt == 512) shcnt = 9;
  301.         else if( shcnt == 1024) shcnt = 10;
  302.         else if( shcnt == 2048) shcnt = 11;
  303.         else if( shcnt == 4096) shcnt = 12;
  304.         else if( shcnt == 8192) shcnt = 13;
  305.         else if( shcnt == 16384) shcnt = 14;
  306.         else return;
  307.         ip->oper1->offset->v.i = shcnt;
  308.         ip->opcode = op;
  309.         ip->length = 4;
  310. }
  311.  
  312. peep_uctran(ip)
  313. /*
  314.  *      peephole optimization for unconditional transfers.
  315.  *      deletes instructions which have no path.
  316.  *      applies to bra, jmp, and rts instructions.
  317.  */
  318. struct ocode    *ip;
  319. {       while( ip->fwd != 0 && ip->fwd->opcode != op_label )
  320.                 {
  321.                 ip->fwd = ip->fwd->fwd;
  322.                 if( ip->fwd != 0 )
  323.                         ip->fwd->back = ip;
  324.                 }
  325. }
  326.  
  327. opt3()
  328. /*
  329.  *      peephole optimizer. This routine calls the instruction
  330.  *      specific optimization routines above for each instruction
  331.  *      in the peep list.
  332.  */
  333. {       struct ocode    *ip;
  334.         ip = peep_head;
  335.         while( ip != 0 )
  336.                 {
  337.                 switch( ip->opcode )
  338.                         {
  339.                         case op_move:
  340.                                 peep_move(ip);
  341.                                 break;
  342.                         case op_add:
  343.                                 peep_add(ip);
  344.                                 break;
  345.                         case op_sub:
  346.                                 peep_sub(ip);
  347.                                 break;
  348.                         case op_cmp:
  349.                                 peep_cmp(ip);
  350.                                 break;
  351.                         case op_muls:
  352.                                 peep_muldiv(ip,op_asl);
  353.                                 break;
  354.                         case op_bra:
  355.                         case op_jmp:
  356.                         case op_rts:
  357.                                 peep_uctran(ip);
  358.                         }
  359.                 ip = ip->fwd;
  360.                 }
  361. }
  362.  
  363.