/* $Header:miscopt.c 12.0$ */
/* $ACIS:miscopt.c 12.0$ */
/* $Source: /ibm/acis/usr/src/lib/c2_ca/RCS/miscopt.c,v $ */

#ifndef lint
static char *rcsid = "$Header:miscopt.c 12.0$";
#endif

/* MISCOPT.C
 
 
   External routines:
      MiscOpt()     Main routine
 
 
 
*/
 
#include "stdio.h"
#include "opt.h"
#include "instps.h"
#include "inst.h"
#include "error.h"
 
struct snode *scanFor();
static int highInc;
 
MiscOpt()
{
   register struct snode *funct, *efunct;
   struct snode *ScanFor();
 
   funct  = ScanFor(i_funct,  Root);
   efunct = ScanFor(i_efunct, funct);
   if(efunct==NULL)
      { fprintf(stderr,"_funct with no _efunct!!!\n"); return; }
   removeSPbumps( funct, efunct );
   twiddleProEpi( funct, efunct );
   removeNoops( funct, efunct );
}
 
                    /* --------------- */
 
/* scan program segment for certain no-ops which can be deleted
   Removes:    addi/subi/ai   r2,r2,0
               addi/subi/ai   r2,0
*/
static removeNoops(from, to)
register struct snode *from, *to;
{
   register struct snode *sn, *back;
   register int n;
 
   highInc = 0;
   for( sn=from; sn!=to; sn=sn->next )  {
      if( UNIMPORTANT(sn) )            continue;
/*    if( OPNUMBER(sn) != i_addi &&			tjm */
/*        OPNUMBER(sn) != i_ai   &&			tjm */
/*        OPNUMBER(sn) != i_subi )     continue; 	tjm */
      if( OPNUMBER(sn) != i_ai &&
          OPNUMBER(sn) != i_si )     continue; 
      if( strcmp(sn->op1,"sp") == 0 )  continue;
      if( sn->op3a != NULL )  {
         if( strcmp(sn->op1,sn->op2a) != 0 )  continue;
         if( strcmp(sn->op3a,"0") == 0 )
            MarkDeleted( sn );
         continue;
         }
      if( sn->op2a != NULL )  {
         if( strcmp(sn->op2a,"0") == 0 )  {
            MarkDeleted( sn );
            c.miscnoops += 1;
            }
         continue;
         }
      }
}
 
                    /* --------------- */
 
/* scan program segment for stack bumps which can be optimized
   Forms are:    subi  sp,n            ...
                 ...                   balrx r1,r2
                 balr  r1,r2           ai    sp,-n
                 ...                   addi  sp,n
                 addi  sp,n
*/
static removeSPbumps(from, to)
register struct snode *from, *to;
{
   register struct snode *sn, *back;
   register int n, nest, op;
 
   nest = highInc = 0;
 
   for( sn=from; sn!=to; sn=sn->next )  {
      if( UNIMPORTANT(sn) )            continue;
      op = OPNUMBER(sn);
/*    if( op != i_addi &&		tjm */
/*        op != i_ai   &&		tjm */
/*        op != i_subi )     continue;	tjm */
      if( op != i_ai &&
          op != i_si )     continue;
      if( strcmp(sn->op1,"sp") != 0 )  continue;
      if( sn->op3a != NULL )           continue;
      if( sn->op2b != NULL )           continue;
      if( sn->op2a == NULL )           continue;
      if( sn->op1  == NULL )           continue;
      if( op != i_ai )  {
/*       if( op == i_subi )  nest += 1;	tjm */
         if( op == i_si )  nest += 1;
             else            nest -= 1;
         if( nest > 1 )                continue;
         n = atoi( sn->op2a );
         if( n>highInc )
            highInc = n;
         }
      else  {  /* it's ai preceeded by balrx; yuck */
         back = sn->last;
         if( back==NULL )                 continue;
         if( OPNUMBER(back) != i_balrx )  continue;
         if( (nest+=1) > 1 )              continue;
         back->opcode = OpcodeEval( "balr" );
         MarkChanged( back );
         }
      MarkDeleted( sn );
      c.miscsp += 1;
      }
}
 
                    /* --------------- */
 
/* put stack addi/subi in prolog & epilog */
static twiddleProEpi( prolog, epilog )
register struct snode *prolog, *epilog;
{
   char s[20];
 
   if( highInc == 0 )   return;
   sprintf( s, "%d", highInc );
/* GenRS( "subi", SPREG, s, NULL, prolog );	tjm */
   GenRS( "si", SPREG, s, NULL, prolog );
/* GenRS( "addi", SPREG, s, NULL, epilog );	tjm */
   GenRS( "ai", SPREG, s, NULL, epilog );
}
