/****************************************************************************
**
**  Name:  LATN9.C
**
**  Description:
**      Deal with ATN9 (variable lifetime) records generated
**      when optimization is turned on in the compiler.  Currently
**      supports MRI C style of generation.
**
**  Status:  CODED
**
**  $Log:   S:/tbird/mt2_68k/l695/latn9.c_v  $
** 
**    Rev 1.0   13 Feb 1997 08:50:44   gene
** Initial revision.
** 
**    Rev 1.0   07 Sep 1995 10:32:04   gene
** Initial revision.
** 
**    Rev 1.15   29 Mar 1994 15:22:16   nghia
** Fixed bug in interpreting ATN9 meaning:
** -Changed LActivate(): search for the input symbol name index first.
** set any variables in the register to dead, if they're alive.
** set the new state for the specified symbol name index.
** -Added LResetRegs(): Reset all varriables assigned to the input register
** index to DEAD state.
** -Clean up bad design for interpreting ATN9.
** 
**    Rev 1.14   03 Aug 1993 17:22:50   nghia
** Removed LERR_xxxx to use standard error codes.
** 
**    Rev 1.13   27 Jul 1993 22:37:48   nghia
** Clean up compiler warning.
** 
**    Rev 1.12   16 Jun 1993 08:34:48   mindy
** Removed #ifdef statements that used to NULL out these routines.  Changed
** what I needed to get ATN9 records processed.
** 
**    Rev 1.10   23 Mar 1993 10:14:40   nghia
** Added comment blocks for coding standard.
** 
**    Rev 1.9   08 Mar 1993 10:17:16   nghia
** Cleanup and added comment block.
** 
**    Rev 1.8   27 Oct 1992 14:13:02   courtney
** Stub out body of ATN9 processing routines (#ifdef) until we fully
** support: ldr/sym/var.
** 
**    Rev 1.7   23 Oct 1992 17:42:52   courtney
** Activated storing lifetime info in the symbol table.
** 
**    Rev 1.6   14 Sep 1992 10:38:52   courtney
** Removed ifdef bracketing.
** 
**    Rev 1.5   14 Sep 1992 10:33:42   courtney
** Switch to TMalloc.
** 
**    Rev 1.4   03 Sep 1992 12:07:40   courtney
** Don't free element of linked list.
** 
**    Rev 1.3   31 Aug 1992 09:39:22   courtney
** Remember to free allocation.
** 
**    Rev 1.2   17 Feb 1992 16:30:00   courtney
** Cleanup - removed ifdef brackets.
** 
**    Rev 1.1   31 Dec 1991 10:58:10   courtney
** Added comment on retaining handle for later deallocation.
** 
**    Rev 1.0   12 Dec 1991 13:46:12   courtney
** Initial revision.
**
**  $Header:   S:/tbird/mt2_68k/l695/latn9.c_v   1.0   13 Feb 1997 08:50:44   gene  $
**
**  Copyright (C) 1991 Microtek International.  All rights reserved.
**
*****************************************************************************/

                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/
#ifndef __LDR__
#include "ldr.h"
#endif
#ifndef _HEAP_
#include "heap.h"
#endif
#ifndef _SYMBLSVR_
#include "symblsvr.h"
#endif
#ifndef __ERR__
#include "err.h"
#endif
#ifndef __LOPT__
#include "lopt.h"
#endif

                       /****************************
                        *                          *
                        *     LOCAL DEFINITIONS    *
                        *                          *
                        ****************************/

#define NUM_REGS  32     /* 695 only maps 32 registers */
BOOLEAN atn9_processed;

STATIC BOOLEAN notInitialized = TRUE;
/*
** Register map kept for each function - it's
** thrown away after the function is loaded.
*/
STATIC REG_INFO *RegMap[NUM_REGS];  /* IEEE 695 register mappings */

                       /****************************
                        *                          *
                        *    EXTERNAL VARIABLES    *
                        *                          *
                        ****************************/

                       /****************************
                        *                          *
                        *     LOCAL PROTOTYPES     *
                        *                          *
                        ****************************/

                       /****************************
                        *                          *
                        *      EXECUTABLE CODE     *
                        *                          *
                        ****************************/
/******************************************************************************
**
**  LActivate
**
******************************************************************************/
RETCODE LActivate(U16 symNameIndex, U32 pc_offset,
                              VAR_LIFETIME_STATE lifeState) {
    VAR_LIFETIME_INFO lifep;
    LOOP_VAR i, foundReg = NUM_REGS;
    SYM_DESCRIPTOR sym = 0L;
    REG_INFO *rp;
    RETCODE symErr;

   // Add lifetime info for variable
   // only a single symbol can be active at any point in time,
   // for a particular register.

    // Linear search regmap for symNameIndex - foundReg is the register index
   for (i = 0; (i < NUM_REGS) && (foundReg == NUM_REGS) ; i++) {
      // traverse the chain of symbol assignments for this register 
      // if there are others currently alive here, we kill them
      for (rp = RegMap[i]; rp != NULL; rp = rp->next) {
         if (rp->nindex == symNameIndex) {
            foundReg = i; // foundReg will be < NUMREGS
            break;
         }
      }
   }
   
   // A register can only be used for one variable at a time
   // thus if there's a LIVE register variable all ready and
   // it's not the current one (i.e.: rp->nindex != symNameIndex)
   // then it's no longer active.
   if (foundReg < NUM_REGS) {
      // Traverse all lifeInfo chain of the foundReg and set the
      // new lifeInfo for the matched <symNameIndex>.  Others nodes that are
      // alive in the chain is set to DEAD.  This handles multiple variables
      // assigned to the same register and only one can be alive at a time.
      for (rp = RegMap[foundReg]; rp != NULL; rp = rp->next) {
         if ((rp->status == LIVE) && (rp->nindex != symNameIndex)
             && (lifeState == LIVE) ) {
            rp->status = DEAD;
            /* and tell the symbol table, send offset info */
            lifep.lifetimeAddr  = pc_offset;
            lifep.lifetimeClass = DEAD;
            if ((symErr = SymAddVarLifetimeInfo(rp->sym,
                  (VAR_LIFETIME_INFO FAR *)&lifep)) != GOOD) {
               Warning(symErr);
            }
         }
         // Now let take care of the real variable
         if ((rp->nindex == symNameIndex) && (!sym)) {
            // check status - if already alive or dead,
            // ignore redundant activation lifetime info.
            if (rp->status == lifeState)
               return (GOOD); // no need to concern about other vars
            sym = rp->sym;
            rp->status = lifep.lifetimeClass = lifeState;
            // Get the new lifetime info to set
            lifep.lifetimeAddr = pc_offset;
            if ((symErr = SymAddVarLifetimeInfo(sym,
                          (VAR_LIFETIME_INFO FAR *)&lifep)) != GOOD) 
               Warning(symErr);
         }
      }
   }
   return (GOOD);
}  /* LActivate */

/******************************************************************************
**
**  LSaveVar
**
******************************************************************************/
RETCODE LSaveVar(U16 symNameIndex, SYM_DESCRIPTOR symDesc, U16 regIndex,
                 VAR_LIFETIME_STATE lifeState) {
   RETCODE err;
   REG_INFO *rp, *rprev;
   //------------------------------------------------------------------------
   // Save ATN2 and ATN10 information for later ATN9 records.  Need
   // a different record keeping method then symbol table since ATN9
   // uses the symbol name index not the symbol type index (which is the
   // index that the symbol table keeps).
   //------------------------------------------------------------------------
   if( (err=CheckRegisterIndex(regIndex)) != GOOD ) return(err);
   
   // Allocate memory for life time node
   if ((rp = (REG_INFO *)TMalloc(sizeof(REG_INFO))) == NULL) {
      return(ER_NO_MEMORY);
   }
   // Assign first life time information for symNameIndex 
   rp->nindex = symNameIndex;
   rp->sym    = symDesc;
   rp->status = lifeState;
   rp->next   = NULL;

   if (RegMap[regIndex] == NULL)
      RegMap[regIndex] = rp;
   else {
      rprev = RegMap[regIndex];
      // Get the last one on chain 
      while (rprev->next != NULL)
         rprev = rprev->next;
      rprev->next = rp;
   }

   return (GOOD);
}  /* LSaveVar */

/******************************************************************************
**
**  LClearRegs
**
******************************************************************************/
RETCODE LClearRegs(VOID) {
   LOOP_VAR i;
   REG_INFO *rp;
   if (notInitialized) {
      for( i=0; i < NUM_REGS; i++ ) RegMap[i] = NULL;
      notInitialized = FALSE;
      return(GOOD);
   }
   for( i=0; i < NUM_REGS; i++ ) {
      rp = RegMap[i];
      while( rp != NULL ) {
         /* This is a timeslicing OS - not a great one but...
            we still need to assume information from freed pointer might
            bad since memory could already be reallocated.
          */
         REG_INFO *rpNext;
         rpNext = rp->next;
         TFree((LPSTR)rp);
         rp = rpNext;
      }
      RegMap[i] = NULL;
   }
   return (GOOD);
}  /* LClearRegs */

/******************************************************************************
**
**  LResetRegs
**
******************************************************************************/
RETCODE LResetRegs(U16 regIndex, U32 pc_offset, VAR_LIFETIME_STATE lifeState){
    VAR_LIFETIME_INFO lifep;
    REG_INFO *rp;
    RETCODE err;

   if ((err = CheckRegisterIndex(regIndex)) != GOOD) return(err);    
   // traverse the chain of symbol assignments for this register 
   // set them to the specified state.
   for (rp = RegMap[regIndex]; rp != NULL; rp = rp->next) {
      if (rp->status != lifeState) {
        rp->status = lifeState;         
        lifep.lifetimeClass = lifeState; 
        lifep.lifetimeAddr  = pc_offset;
        if ((err = SymAddVarLifetimeInfo(rp->sym,
            (VAR_LIFETIME_INFO FAR *)&lifep)) != GOOD) 
           Warning(err); // report warning
      }
   }
   return (GOOD);
}  /* LResetRegs */


/*****************
* End of LATN9.C *
*****************/
