home *** CD-ROM | disk | FTP | other *** search
/ ftp.cs.arizona.edu / ftp.cs.arizona.edu.tar / ftp.cs.arizona.edu / icon / historic / v92.tgz / v92.tar / v92 / src / iconc / fixcode.c < prev    next >
C/C++ Source or Header  |  1996-03-22  |  12KB  |  373 lines

  1. /*
  2.  * fixcode.c - routines to "fix code" by determining what signals are returned
  3.  *   by continuations and what must be done when they are.  Also perform
  4.  *   optional control flow optimizations.
  5.  */
  6. #include "::h:gsupport.h"
  7. #include "ctrans.h"
  8. #include "cglobals.h"
  9. #include "ccode.h"
  10. #include "ctree.h"
  11. #include "csym.h"
  12. #include "cproto.h"
  13.  
  14. /*
  15.  * Prototypes for static functions.
  16.  */
  17. hidden struct code    *ck_unneed Params((struct code *cd, struct code *lbl));
  18. hidden novalue         clps_brch Params((struct code *branch));
  19. hidden novalue         dec_refs  Params((struct code *cd));
  20. hidden novalue         rm_unrch  Params((struct code *cd));
  21.  
  22. /*
  23.  * fix_fncs - go through the generated C functions, determine how calls
  24.  *  handle signals, in-line trivial functions where possible, remove
  25.  *  goto's which immediately precede their labels, and remove unreachable
  26.  *  code.
  27.  */
  28. novalue fix_fncs(fnc)
  29. struct c_fnc *fnc;
  30.    {
  31.    struct code *cd, *cd1;
  32.    struct code *contbody;
  33.    struct sig_act *sa;
  34.    struct sig_lst *sl;
  35.    struct code *call;
  36.    struct code *create;
  37.    struct code *ret_sig;
  38.    struct code *sig;
  39.    struct c_fnc *calledcont;
  40.    int no_break;
  41.    int collapse;
  42.  
  43.    /*
  44.     * Fix any called functions and decide how the calls handle the
  45.     *  returned signals.
  46.     */
  47.    fnc->flag |= CF_Mark;
  48.    for (call = fnc->call_lst; call != NULL; call = call->NextCall) {
  49.       calledcont = call->Cont;
  50.       if (calledcont != NULL) {
  51.          if  (!(calledcont->flag & CF_Mark))
  52.             fix_fncs(calledcont);
  53.          if (calledcont->flag & CF_ForeignSig) {
  54.             call->Flags |= ForeignSig;
  55.             fnc->flag |= CF_ForeignSig;
  56.             }
  57.          }
  58.  
  59.  
  60.       /*
  61.        * Try to collapse call chains of continuations.
  62.        */
  63.       if (opt_cntrl && calledcont != NULL) {
  64.          contbody = calledcont->cd.next;
  65.          if (call->OperName == NULL && contbody->cd_id == C_RetSig) {
  66.            /*
  67.             * A direct call of a continuation which consists of just a
  68.             *  return. Replace call with code to handle the returned signal.
  69.             */
  70.            ret_sig = contbody->SigRef->sig;
  71.            if (ret_sig == &resume)
  72.                cd1 = sig_cd(call->ContFail, fnc);
  73.             else
  74.                cd1 = sig_cd(ret_sig, fnc);
  75.             cd1->prev = call->prev;
  76.             cd1->prev->next = cd1;
  77.             cd1->next = call->next;
  78.             if (cd1->next != NULL)
  79.                cd1->next->prev = cd1;
  80.             --calledcont->ref_cnt;
  81.             continue;    /* move on to next call */
  82.             }
  83.          else if (contbody->cd_id == C_CallSig && contbody->next == NULL) {
  84.             /*
  85.              * The called continuation contains only a call.
  86.              */
  87.             if (call->OperName == NULL) {
  88.                /*
  89.                 * We call the continuation directly, so we can in-line it.
  90.                 *  We must replace signal returns with appropriate actions.
  91.                 */
  92.                if (--calledcont->ref_cnt != 0 && contbody->Cont != NULL)
  93.                   ++contbody->Cont->ref_cnt;
  94.                call->OperName = contbody->OperName;
  95.                call->ArgLst = contbody->ArgLst;
  96.                call->Cont = contbody->Cont;
  97.                call->Flags = contbody->Flags;
  98.                for (sa = contbody->SigActs; sa != NULL; sa = sa->next) {
  99.                   ret_sig = sa->cd->SigRef->sig;
  100.                   if (ret_sig == &resume)
  101.                      cd1 = sig_cd(call->ContFail, fnc);
  102.                   else
  103.                      cd1 = sig_cd(ret_sig, fnc);
  104.                   call->SigActs = new_sgact(sa->sig, cd1, call->SigActs);
  105.                   }
  106.                continue;    /* move on to next call */
  107.                }
  108.             else if (contbody->OperName == NULL) {
  109.                /*
  110.                 * The continuation simply calls another continuation. We can
  111.                 *  eliminate the intermediate continuation as long as we can
  112.                 *  move signal conversions to the other side of the operation.
  113.                 *  The operation only intercepts resume signals.
  114.                 */
  115.                collapse = 1;
  116.                for (sa = contbody->SigActs; sa != NULL; sa = sa->next) {
  117.                   ret_sig = sa->cd->SigRef->sig;
  118.                   if (sa->sig != ret_sig && (sa->sig == &resume ||
  119.                       ret_sig == &resume))
  120.                      collapse = 0;
  121.                   }
  122.                if (collapse) {
  123.                   if (--calledcont->ref_cnt != 0 && contbody->Cont != NULL)
  124.                      ++contbody->Cont->ref_cnt;
  125.                   call->Cont = contbody->Cont;
  126.                   for (sa = contbody->SigActs; sa != NULL; sa = sa->next) {
  127.                      ret_sig = sa->cd->SigRef->sig;
  128.                      if (ret_sig != &resume)
  129.                         call->SigActs = new_sgact(sa->sig, sig_cd(ret_sig, fnc),
  130.                            call->SigActs);
  131.                      }
  132.                   continue;    /* move on to next call */
  133.                   }
  134.                }
  135.             }
  136.          }
  137.  
  138.       /*
  139.        * We didn't do any optimizations. We must still figure out
  140.        *  out how to handle signals returned by the continuation.
  141.        */
  142.       if (calledcont != NULL) {
  143.          for (sl = calledcont->sig_lst; sl != NULL; sl = sl->next) {
  144.             if (sl->ref_cnt > 0) {
  145.                sig = sl->sig;
  146.                /*
  147.                 * If an operation is being called, it handles failure from the
  148.                 *  continuation.
  149.                 */
  150.                if (sig != &resume || call->OperName == NULL) {
  151.                   if (sig == &resume)
  152.                      cd1 = sig_cd(call->ContFail, fnc);
  153.                   else
  154.                      cd1 = sig_cd(sig, fnc);
  155.                   call->SigActs = new_sgact(sig, cd1, call->SigActs);
  156.                   }
  157.                }
  158.             }
  159.          }
  160.       }
  161.  
  162.    /*
  163.     * fix up the signal handling in the functions implementing co-expressions.
  164.     */
  165.    for (create = fnc->creatlst; create != NULL; create = create->NextCreat)
  166.       fix_fncs(create->Cont);
  167.  
  168.    if (!opt_cntrl)
  169.       return;  /* control flow optimizations disabled. */
  170.    /*
  171.     * Collapse branch chains and remove unreachable code.
  172.     */
  173.    for (cd = &(fnc->cd); cd != NULL; cd = cd->next) {
  174.       switch (cd->cd_id) {
  175.          case C_CallSig:
  176.             no_break = 1;
  177.             for (sa = cd->SigActs; sa != NULL; sa = sa->next) {
  178.                if (sa->cd->cd_id == C_Break) {
  179.                   switch (cd->next->cd_id) {
  180.                      case C_Goto:
  181.                         sa->cd->cd_id = cd->next->cd_id;
  182.                         sa->cd->Lbl = cd->next->Lbl;
  183.                         ++sa->cd->Lbl->RefCnt;
  184.                         break;
  185.                      case C_RetSig:
  186.                         sa->cd->cd_id = cd->next->cd_id;
  187.                         sa->cd->SigRef= cd->next->SigRef;
  188.                         ++sa->cd->SigRef->ref_cnt;
  189.                         break;
  190.                      default: 
  191.                         no_break = 0;
  192.                      }
  193.                   }
  194.                if (sa->cd->cd_id == C_Goto)
  195.                   clps_brch(sa->cd);
  196.                }
  197.             if (no_break)
  198.                rm_unrch(cd);
  199.             /*
  200.              * Try converting gotos into breaks.
  201.              */
  202.             for (sa = cd->SigActs; sa != NULL; sa = sa->next)
  203.                if (sa->cd->cd_id == C_Goto) {
  204.                   cd1 = cd->next;
  205.                   while (cd1 != NULL && (cd1->cd_id == C_Label ||
  206.                      cd1->cd_id == C_RBrack)) {
  207.                         if (cd1 == sa->cd->Lbl) {
  208.                            sa->cd->cd_id = C_Break;
  209.                            --cd1->RefCnt;
  210.                            break;
  211.                            }
  212.                         cd1 = cd1->next;
  213.                         }
  214.                   }
  215.             break;
  216.  
  217.          case C_Goto:
  218.             clps_brch(cd);
  219.             rm_unrch(cd);
  220.             if (cd->cd_id == C_Goto)
  221.                ck_unneed(cd, cd->Lbl);
  222.             break;
  223.  
  224.          case C_If:
  225.             if (cd->ThenStmt->cd_id == C_Goto) {
  226.                clps_brch(cd->ThenStmt);
  227.                if (cd->ThenStmt->cd_id == C_Goto)
  228.                   ck_unneed(cd, cd->ThenStmt->Lbl);
  229.                }
  230.             break;
  231.  
  232.          case C_PFail:
  233.          case C_PRet:
  234.          case C_RetSig:
  235.             rm_unrch(cd);
  236.             break;
  237.          }
  238.       }
  239.  
  240.    /*
  241.     * If this function only contains a return, indicate that we can
  242.     *  call a shared signal returning function instead of it. This is
  243.     *  a special case of "common subROUTINE elimination".
  244.     */
  245.    if (fnc->cd.next->cd_id == C_RetSig)
  246.       fnc->flag |= CF_SigOnly;
  247.    }
  248.  
  249. /*
  250.  * clps_brch - collapse branch chains.
  251.  */
  252. static novalue clps_brch(branch)
  253. struct code *branch;
  254.    {
  255.    struct code *cd;
  256.    int save_id;
  257.  
  258.    cd = branch->Lbl->next;
  259.    while (cd->cd_id == C_Label)
  260.       cd = cd->next;
  261.  
  262.    /*
  263.     * Avoid infinite recursion on empty infinite loops.
  264.     */
  265.    save_id = branch->cd_id;
  266.    branch->cd_id = 0;
  267.    if (cd->cd_id == C_Goto)
  268.       clps_brch(cd);
  269.    branch->cd_id = save_id;
  270.  
  271.    switch (cd->cd_id) {
  272.       case C_Goto:
  273.          --branch->Lbl->RefCnt;
  274.          ++cd->Lbl->RefCnt;
  275.          branch->Lbl = cd->Lbl;
  276.          break;
  277.       case C_RetSig:
  278.          /*
  279.           * This optimization requires that C_Goto have as many fields
  280.           *  as C_RetSig.
  281.           */
  282.          --branch->Lbl->RefCnt;
  283.          ++cd->SigRef->ref_cnt;
  284.          branch->cd_id = C_RetSig;
  285.          branch->SigRef = cd->SigRef;
  286.          break;
  287.       }
  288.    }
  289.  
  290. /*
  291.  * rm_unrch - any code after the given point up to the next label is
  292.  *   unreachable. Remove it.
  293.  */
  294. static novalue rm_unrch(cd)
  295. struct code *cd;
  296.    {
  297.    struct code *cd1;
  298.  
  299.    for (cd1 = cd->next; cd1 != NULL && cd1->cd_id != C_LBrack &&
  300.       (cd1->cd_id != C_Label || cd1->RefCnt == 0); cd1 = cd1->next) {
  301.          if (cd1->cd_id == C_RBrack) {
  302.             /*
  303.              * Continue deleting past a '}', but don't delete the '}' itself.
  304.              */
  305.             cd->next = cd1;
  306.             cd1->prev = cd;
  307.             cd = cd1;
  308.             }
  309.          else
  310.             dec_refs(cd1);
  311.          }
  312.    cd->next = cd1;
  313.    if (cd1 != NULL)
  314.       cd1->prev = cd;
  315.    }
  316.  
  317. /*
  318.  * dec_refs - decrement reference counts for things this code references.
  319.  */
  320. static novalue dec_refs(cd)
  321. struct code *cd;
  322.    {
  323.    struct sig_act *sa;
  324.  
  325.    if (cd == NULL)
  326.       return;
  327.    switch (cd->cd_id) {
  328.       case C_Goto:
  329.          --cd->Lbl->RefCnt;
  330.          return;
  331.       case C_RetSig:
  332.          --cd->SigRef->ref_cnt;
  333.          return;
  334.       case C_CallSig:
  335.          if (cd->Cont != NULL)
  336.             --cd->Cont->ref_cnt;
  337.          for (sa = cd->SigActs; sa != NULL; sa = sa->next)
  338.             dec_refs(sa->cd);
  339.          return;
  340.      case C_If:
  341.          dec_refs(cd->ThenStmt);
  342.          return;
  343.      case C_Create:
  344.         --cd->Cont->ref_cnt;
  345.          return;
  346.         }
  347.    }
  348.  
  349. /*
  350.  * ck_unneed - if there is nothing between a goto and its label, except
  351.  *   perhaps other labels or '}', it is useless, so remove it.
  352.  */
  353. static struct code *ck_unneed(cd, lbl)
  354. struct code *cd;
  355. struct code *lbl;
  356.    {
  357.    struct code *cd1;
  358.  
  359.    cd1 = cd->next;
  360.    while (cd1 != NULL && (cd1->cd_id == C_Label || cd1->cd_id == C_RBrack)) {
  361.       if (cd1 == lbl) {
  362.          cd = cd->prev;
  363.          cd->next = cd->next->next;
  364.          cd->next->prev = cd;
  365.          --lbl->RefCnt;
  366.          break;
  367.          }
  368.       cd1 = cd1->next;
  369.       }
  370.    return cd;
  371.    }
  372.  
  373.