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

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

/* NODES.C  --  Utilities for creating and managing statement nodes

   External routines:
      NewNode()    Allocate a new node; set default values
      CopyNode()   Allocate a new node; copy fields from another
      InstNode()   Allocate a new node; set defaults from instruction table
      RestNode()   Allocate a new node; set 'rest' field as given
      GenRR()      Allocate a new node which holds an RR form instruction
      GenRRR()     Allocate a new node which holds an RRR form instruction
      GenRS()      Allocate a new node which holds an RS form instruction
 old  GenFREG()    Allocate a new node which holds a _freg pseudoop

      InsertNode()     Insert a node after another node in chain
      MoveAfter()      Move a node after another node in the chain

      NextImportant()  Return next node which is not unimportant

      MarkDeleted      Mark a node as deleted; flag it unimportant
      MarkNew          Mark a node as new
      MarkMoved        Mark a node as moved
      MarkChanged      Mark a node as changed
      ScanFor          Scan through program for a given opcode
      InvalidateFregs  Mark fregs information invalid

      PrintShortNode() Print a short form of the node (debug only)
      HexNodes()       Print node chain in hex (debug only)
      OneHexNode()     Print one node in hex (debug only)
      CheckNode()      Validate that a node & it's pointers are ok
      CheckAllNodes()  Validate whole node chain

*/

#include "stdio.h"
#include "opt.h"
#include "error.h"
#include "instps.h"


/***********************************************************/


/* Allocate and fill in a new and empty node
*/
struct snode *NewNode()
{
   register struct snode *new;
   new = (struct snode *) Myalloc( sizeof(struct snode) );
   if (new == NULL)
      {Error(E_STORAGE,"(in NewNode)", NULL);
       Running=FALSE; return NULL;}

   new->last    = NULL;
   new->next    = NULL;

   new->lineno  = 0;
   new->seqno   = 0;
   new->type    = 0;
   new->fregs   = 0;
   new->mods    = 0;
   new->modby   = 0;
   new->ldstype = 0;
   new->lablock = NULL;
   new->labsame = NULL;
   new->labels  = NULL;
   new->opcode  = NULL;
   new->op1     = NULL;
   new->op2a    = NULL;
   new->op2b    = NULL;
   new->op3a    = NULL;
   new->op3b    = NULL;
   new->rest    = NULL;

/* if(Debug)  fprintf(stderr,"New node created\n"); */

   return new;
}



/***********************************************************/


/* Allocate a new node and fillin with contents of existing node
*/
struct snode *CopyNode(old)
register struct snode *old;
{
   register struct snode *new;

   new = (struct snode *) Myalloc( sizeof(struct snode) );
   if (new == NULL)
     {Error( E_STORAGE,"(in NewNode)", old);
      Running=FALSE; return NULL;}

   new->last    = NULL;
   new->next    = NULL;

   new->lineno  = old->lineno;
   new->seqno   = old->seqno;
   new->type    = old->type;
   new->fregs   = old->fregs;
   new->mods    = old->mods | mod_new;
   new->modby   = old->modby | WhoRunning;
   new->ldstype = old->ldstype;
   new->lablock = NULL;
   new->labsame = NULL;
   new->labels  = old->labels;
   new->opcode  = old->opcode;
   new->op1     = old->op1;
   new->op2a    = old->op2a;
   new->op2b    = old->op2b;
   new->op3a    = old->op3a;
   new->op3b    = old->op3b;
   new->rest    = old->rest;

   return new;
}



/***********************************************************/

/* Allocate a new node and fillin from opcode table
*/
struct snode * InstNode(opcode)
char *opcode;
{
   struct snode *new;
   struct opStat *OpcodeEval();

   new = NewNode();
   if (new==NULL)  return NULL;
   new->opcode = OpcodeEval( opcode );
   if(new->opcode != NULL)   {
      new->type    = new->opcode->optype;
      new->ldstype = new->opcode->opldstype;
     }
   new->modby = WhoRunning;
   new->mods  = mod_new;
   return new;
}

/***********************************************************/


/* Allocate a new node and fillin 'rest' field.
   (Used for adding comments to output).
*/
struct snode *RestNode(sp, restString)
register char *restString;
register struct snode *sp;
{
   register struct snode *new;

   /* allocate a new snode */
   new = NewNode();
   if (new == NULL)
     {Error(E_STORAGE,"(in RestNode (a))",sp);
      Running=FALSE; return;}
   new->type = type_unimportant;
   new->mods = mod_new;
   new->modby = WhoRunning;

   /* add restString to node */
   new->rest = Myalloc(strlen(restString)+1);
   if (new->rest == NULL)
     {Error(E_STORAGE,"(in RestNode (b))",sp);
      Running=FALSE; return;}
   strcpy(new->rest, restString);

   /* add snode to chain */
   InsertNode(new, sp);
}

/***********************************************************/

/* generate an rr instruction */
GenRR(op, r1, r2, behind)
char *op;
int r1, r2;
struct snode *behind;
{
   struct snode * new;
   struct opStat *OpcodeEval();

   new = InstNode(op);
   InsertNode(new, behind);
   new->lineno    = behind->lineno;
   new->opcode    = OpcodeEval( op );  /* find opstat */
   new->op1       = (char*) Myalloc(8);
   if (new->op1 == NULL)
     {Error( E_STORAGE, "(in GenRR (a))",behind);
      Running=FALSE; return;}
   sprintf(new->op1,  "r%d\0", r1);
   new->op2a      = Myalloc(8);
   if (new->op2a == NULL)
     {Error( E_STORAGE, "(in GenRR (b))",behind);
      Running=FALSE; return;}
   sprintf(new->op2a, "r%d\0", r2);
   PrintShortNode(new, "Generated instruction:");
}

/***********************************************************/

/* generate an rrr instruction */
GenRRR(op, r1, r2, r3, behind)
char *op;
int r1, r2, r3;
struct snode *behind;
{
   struct snode * new;
   struct opStat *OpcodeEval();

   new = InstNode(op);
   InsertNode(new, behind);
   new->lineno    = behind->lineno;
   new->opcode    = OpcodeEval( op );  /* find opstat */
   new->op1       = (char*) Myalloc(8);
   if (new->op1 == NULL)
     {Error( E_STORAGE, "(in GenRRR (a))",behind);
      Running=FALSE; return;}
   sprintf(new->op1,  "r%d\0", r1);
   new->op2a      = Myalloc(8);
   if (new->op2a == NULL)
     {Error( E_STORAGE, "(in GenRRR (b))",behind);
      Running=FALSE; return;}
   sprintf(new->op2a, "r%d\0", r2);
   new->op3a      = Myalloc(8);
   if (new->op3a == NULL)
     {Error( E_STORAGE, "(in GenRRR (c))",behind);
      Running=FALSE; return;}
   sprintf(new->op3a, "r%d\0", r3);
   PrintShortNode(new, "Generated instruction:");
}

/***********************************************************/

/* generate a register-storage instruction */
GenRS(op, r1, opa, opb, behind)
char *op;
int r1;
register char *opa, *opb;
struct snode *behind;
{
   struct snode * new;
   struct opStat *OpcodeEval();

   new = InstNode(op);
   InsertNode(new, behind);
   new->lineno    = behind->lineno;
   new->opcode    = OpcodeEval( op );  /* find opstat */
   new->lablock   = NULL;
   new->labsame   = NULL;
   new->labels    = NULL;
   new->op1       = Myalloc(8);
   sprintf(new->op1,  "r%d\0", r1);
   new->op2a      = Myalloc(strlen(opa)+10);
   if (new->op2a == NULL)
     {Error( E_STORAGE, "(in GenRS (a))", behind);
      Running=FALSE; return;}
   strcpy(new->op2a,opa);
   new->op2b      = NULL;
   if( opb!=NULL )   {
      new->op2b      = Myalloc(strlen(opb)+10);
      if (new->op2b == NULL)
        {Error( E_STORAGE, "(in GenRS (b))", behind);
         Running=FALSE; return;}
      strcpy( new->op2b, opb );
      }
   PrintShortNode(new, "Generated instruction:");
}

/***********************************************************/


/* generate a free register declaration node */
/* ---
GenFREG(after, reg )
   register struct snode *after;
   register int reg;
{
/*    struct snode * new;
/*    if ( !SCRATCHREG(reg) )
/*       return;                    /* don't allow non-scratch freg */
/*    if ( after->next != NULL &&
/*         FREGS(after->next) &&
/*         REGFREE(after->next, reg) )
/*       return;                      /* no new freg needed here */
/*    new = InstNode( "_freg" );
/*    InsertNode(new, after);
/*    new->fregs     = 0x8000 >> reg; /* mark register free */
/*    new->lineno    = after->lineno;
/*    new->lablock   = NULL;
/*    new->labsame   = NULL;
/*    new->labels    = NULL;
/*    new->op1       = NULL;
/*    new->op2a      = NULL;
/*    new->op2b      = NULL;
/*    new->op3a      = NULL;
/*    new->op3b      = NULL;
/*    new->rest      = Myalloc(5);
/*    strcpy( new->rest, "0x00" );
/*    PrintShortNode(new, "Generated instruction:");
}
--- */

/***********************************************************/


/* Put a node into the chain after a given node.
   If the given node is null, put at the front and set Root.
   If the next node after that given is null, set Tail.
   (Also make sure seqno not too far wrong by making it be
   that of a neighbor.)
*/
InsertNode( new, place )
register struct snode *new;   /* node to place into the chain */
register struct snode *place; /* node to place it after       */
{
   register struct snode *nextPlace;

   if (place == NULL) {
      new->last = NULL;
      new->next = Root;
      Root = new;
      if (Tail == NULL)  Tail = new;
      new->seqno = 1;  /* at front */
      }
   else {
      nextPlace = place->next;
      place->next = new;
      if (nextPlace!=NULL)
         nextPlace->last = new;
      else
         Tail = new;
      new->last   = place;
      new->next   = nextPlace;
      new->seqno = new->last->seqno; /* make same as prev node */
      }
   SeqnoWrong = TRUE;   /* remember to fix up seqno later */
}


/***********************************************************/


/* Move a node from one place to another in the chain.
   If the new place is null, put at the front and set Root.
   If the next node after that given is null, set Tail.
*/
MoveAfter( anode, place )
register struct snode *anode;   /* the node to move */
register struct snode *place;   /* the node to place it after */
{
   unHookNode( anode );
   InsertNode( anode, place );
}


/***********************************************************/


/* Unhook a node from the chain but do not free it from storage.
*/
static unHookNode( place )
register struct snode *place;   /* the node to unhook */
{
   if (place == NULL)   return;

   if (place->last == NULL)
      Root = place->next;
   else
      place->last->next = place->next;

   if (place->next == NULL)
      Tail = place->last;
   else
      place->next->last = place->last;

   place->next = NULL;
   place->last = NULL;
}

/***********************************************************/

MarkDeleted(sn)
register struct snode *sn;
{
   sn->type   = type_unimportant;
   sn->mods   |= mod_deleted;
   sn->modby  = WhoRunning;
   if(DEBUG1)  PrintShortNode( sn, "Deleted" );
}


MarkNew(sn)
register struct snode *sn;
{
   sn->mods   |= mod_new;
   sn->modby  = WhoRunning;
   if(DEBUG1)  PrintShortNode( sn, "New" );
}


MarkMoved(sn)
register struct snode *sn;
{
   sn->type   = type_unimportant;
   sn->mods   |= mod_moved;
   sn->modby  =  WhoRunning;
   if(DEBUG1)  PrintShortNode( sn, "Moved" );
}


MarkChanged(sn)
register struct snode *sn;
{
   sn->mods   |= mod_changed;
   sn->modby  =  WhoRunning;
   if(DEBUG1)  PrintShortNode( sn, "Changed" );
}


/***********************************************************/

/* return the next important node (or NULL if none)  */
struct snode *NextImportant( sp )
register struct snode *sp;
{
   register struct snode *temp;
   if(sp==NULL)  return NULL;
   temp = sp;
   sp = sp->next;
   while( sp!=NULL && UNIMPORTANT(sp) ) {
      temp = sp;
      sp = sp->next;
      }
   return sp;
}


/***********************************************************/

/* scan through program looking for a specific opcode */

struct snode *ScanFor(opnum, sn)
register int opnum;
register struct snode *sn;
{
   for( ; sn!=NULL; sn=sn->next )
      if( OPNUMBER(sn) == opnum )
         return sn;
   return NULL;
}

/***********************************************************/

/* for a range of nodes, loop through and mark the given register
   as not free in any _fregs nodes found                        */
InvalidateFregs(start, end, reg)
register struct snode *start, *end;
register int reg;
{
   register struct snode *sp;

   if( !SCRATCHREG(reg) )               return;
   if(DEBUG2) {
      fprintf(stderr,"Given reg %d, ", reg);
      PrintShortNode( start, "invalidate fregs from:" );
      PrintShortNode( end,   "   to:" );
      }
   if( start==NULL || end==NULL )
      return;
   for( sp=start; sp!=end; sp=sp->next )
      if( FREGS(sp) )  {
         if(DEBUG2) fprintf(stderr, "At line %d fregs is 0x%04x",
                   sp->lineno, sp->fregs );
         /* don't use xor or invert; moving to VM messes them up */
         sp->fregs &= (short) ( (long)0xFFFF7FFF >> reg);
         if(DEBUG2) fprintf(stderr, " and is changed to 0x%04x\n",
                            sp->fregs );
         }
}


/***********************************************************/

#define PR(s,t)  fprintf( stderr, (s), (t) )

PrintNode( node, msg )
register struct snode *node;
register char *msg;
{
   if(!Debug)  return;
   PR("\n\nStatement node -- %s  ", msg);
   if (node==NULL)           PR(" NULL node",0);
                             PR("\n  LineNo: %d",     node->lineno);
                             PR("\n  Type: %4x",      node->type);
                             PR("\n  FreeRegs: %4x",  node->fregs);
                             PR("\n  Ld/St: %4x",     node->ldstype);
                             PR("\n  Mods: %2x",      node->mods);
                             PR("\n  Mod by: %2x",    node->modby);
   if (node->labels != NULL) PR("\n  Labels: %s",     node->labels);
   if (node->opcode != NULL) PR("\n  Opcode: %s",     node->opcode->opname);
   if (node->op1    != NULL) PR("\n  Operand 1: %s",  node->op1);
   if (node->op2a   != NULL) PR("\n  Operand 2a: %s", node->op2a);
   if (node->op2b   != NULL) PR("\n  Operand 2b: %s", node->op2b);
   if (node->op3a   != NULL) PR("\n  Operand 3a: %s", node->op3a);
   if (node->op3b   != NULL) PR("\n  Operand 3b: %s", node->op3b);
   if (node->rest   != NULL) PR("\n  Rest: %s",       node->rest);
   if (node->last   != NULL)
      if (node->last->next != node)
         PR("\n *** node->last->next DOES NOT point back to node",0);
   PR("\n",0);
}

/***********************************************************/



PrintShortNode( node, msg )
register struct snode *node;
register char *msg;
{
   if(!Debug)  return;
   PR("%s  ", msg);
   if (node==NULL)           { PR(" NULL node\n",0); return; }
                               PR("[%d] ",node->lineno);
   if(MOVED(node) ||
      DELETED(node))           PR(" | ",0);
   if (node->labels != NULL)   PR("%s",   node->labels);
   if (node->opcode != NULL)   PR("  %s", node->opcode->opname);
   if (node->op1    != NULL)   PR(" %s",  node->op1);
   if (node->op2a   != NULL)   PR(",%s",  node->op2a);
   if (node->op2b   != NULL)   PR("(%s)", node->op2b);
   if (node->op3a   != NULL)   PR(",%s",  node->op3a);
   if (node->op3b   != NULL)   PR("(%s)", node->op3b);
   if (node->rest   != NULL)   PR(" %s",  node->rest);
   if (node->last   != NULL)
     if (node->last->next != node)
       PR("\n *** node->last->next DOES NOT point back to node",0);
   PR("\n",0);
}


/***********************************************************/


HexNodes(msg)
char *msg;
{
   register struct snode *node;

   fprintf(stderr, "%s\n", msg);
   for (node=Root; node!=NULL; node=node->next)
      fprintf(stderr," Node at: %6x  last=%6x  next=%6x \n",
                       node, node->last, node->next );
}



/***********************************************************/


OneHexNode(msg, node)
register struct snode *node;
register char *msg;
{

   if( msg && *msg )
      fprintf(stderr, "%s\n", msg);
   fprintf(stderr," Node at: %6x  last=%6x  next=%6x \n",
                    node, node->last, node->next );
}



/***********************************************************/


CheckNode( node )
register struct snode *node;
{
   register struct snode *lastp, *nextp;

   /* validate current node pointer */
   if( !ValidPointer(node) )   return FALSE;
   if( node == NULL )          return TRUE;

   /* get and validate fwd & back pointers of current node */
   lastp = node->last;
   nextp = node->next;
   if( !ValidPointer(lastp) )  return FALSE;
   if( !ValidPointer(nextp) )  return FALSE;

   /* check that prev node points to current node */
   if( lastp != NULL )
      if( ValidPointer(lastp->next) )
         if( lastp->next != node )
            return FALSE;

   /* check that next node points to current node */
   if( nextp != NULL )
      if( ValidPointer(nextp->last) )
         if( nextp->last != node )
            return FALSE;

   return TRUE;
}

/***********************************************************/


CheckAllNodes()
{
   register struct snode *node;
   register int badNode=FALSE;
   register int count;

   for (node=Root, count=0;  node!=NULL;  node=node->next, count++)
      if( ! CheckNode(node) ) {
         fprintf( stderr, "Node %d not chained correctly:\n", count );
         OneHexNode( "", node );
         badNode = TRUE;
         }
   if( badNode )
      HexNodes( "Full node chain in hex is:" );
}

