Logo Search packages:      
Sourcecode: cacao-source version File versions  Download package

simplereg.c

/* src/vm/jit/allocator/simplereg.c - register allocator

   Copyright (C) 1996-2005, 2007, 2008
   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO

   This file is part of CACAO.

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2, or (at
   your option) any later version.

   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
   02111-1307, USA.

*/


#include "config.h"

#include <assert.h>
#include <stdint.h>

#include "vm/types.h"

#include "arch.h"
#include "md-abi.h"

#include "mm/memory.h"

#include "vm/builtin.h"
#include "vm/exceptions.h"
#include "vm/resolve.h"
#include "vm/stringlocal.h"

#include "vm/jit/abi.h"
#include "vm/jit/reg.h"
#include "vm/jit/show.h"
#include "vm/jit/allocator/simplereg.h"

#include "vmcore/method.h"
#include "vmcore/options.h"


#if 0
#    define LOG(args) printf args
#else
#    define LOG(args)
#endif


/* function prototypes for this file ******************************************/

static void simplereg_allocate_interfaces(jitdata *jd);
static void simplereg_allocate_locals(jitdata *jd);
static void simplereg_allocate_temporaries(jitdata *jd);


/* size of a stackslot used by the internal ABI */

#if defined(HAS_4BYTE_STACKSLOT)
# define SIZE_OF_STACKSLOT 4
#else 
# define SIZE_OF_STACKSLOT 8
#endif


/* total number of registers */

#if defined(HAS_ADDRESS_REGISTER_FILE)
#define TOTAL_REG_CNT  (INT_REG_CNT + FLT_REG_CNT + ADR_REG_CNT)
#else
#define TOTAL_REG_CNT  (INT_REG_CNT + FLT_REG_CNT)
#endif


/* macros for handling register stacks ****************************************/

#define AVAIL_FRONT(cnt, limit)   ((cnt) < (limit))
#define AVAIL_BACK(cnt)           ((cnt) > 0)

#if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
#define AVAIL_FRONT_INT(cnt, limit)   ((cnt) < (limit) - intregsneeded)
#define AVAIL_BACK_INT(cnt)           ((cnt) > intregsneeded)
#else
#define AVAIL_FRONT_INT(cnt, limit)   AVAIL_FRONT(cnt, limit)
#define AVAIL_BACK_INT(cnt)           AVAIL_BACK(cnt)
#endif

#define POP_FRONT(stk, cnt, reg)   do {  reg = stk[cnt++];    } while (0)
#define POP_BACK(stk, cnt, reg)    do {  reg = stk[--cnt];    } while (0)
#define PUSH_FRONT(stk, cnt, reg)  do {  stk[--cnt] = (reg);  } while (0)
#define PUSH_BACK(stk, cnt, reg)   do {  stk[cnt++] = (reg);  } while (0)

#if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
#define POP_FRONT_INT(stk, cnt, reg)                                 \
    do {                                                             \
        if (intregsneeded) {                                         \
            reg = PACK_REGS(stk[cnt], stk[cnt+1]);                   \
            cnt += 2;                                                \
        }                                                            \
        else                                                         \
            POP_FRONT(stk, cnt, reg);                                \
    } while (0)
#else
#define POP_FRONT_INT(stk, cnt, reg)  POP_FRONT(stk, cnt, reg)
#endif

#if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
#define POP_BACK_INT(stk, cnt, reg)                                  \
    do {                                                             \
        if (intregsneeded) {                                         \
            cnt -= 2;                                                \
            reg = PACK_REGS(stk[cnt], stk[cnt+1]);                   \
        }                                                            \
        else                                                         \
            POP_BACK(stk, cnt, reg);                                 \
    } while (0)
#else
#define POP_BACK_INT(stk, cnt, reg)  POP_BACK(stk, cnt, reg)
#endif

#if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
#define PUSH_BACK_INT(stk, cnt, reg)                                 \
    do {                                                             \
        if (intregsneeded) {                                         \
            stk[cnt] = GET_LOW_REG(reg);                             \
            stk[cnt + 1] = GET_HIGH_REG(reg);                        \
            cnt += 2;                                                \
        }                                                            \
        else                                                         \
            PUSH_BACK(stk, cnt, reg);                                \
    } while (0)
#else
#define PUSH_BACK_INT(stk, cnt, reg)  PUSH_BACK(stk, cnt, reg)
#endif

#define AVAIL_ARG_FLT  AVAIL_FRONT(rd->argfltreguse, FLT_ARG_CNT)
#define AVAIL_TMP_FLT  AVAIL_BACK(rd->tmpfltreguse)
#define AVAIL_SAV_FLT  AVAIL_BACK(rd->savfltreguse)

#define AVAIL_ARG_ADR  AVAIL_FRONT(rd->argadrreguse, ADR_ARG_CNT)
#define AVAIL_TMP_ADR  AVAIL_BACK(rd->tmpadrreguse)
#define AVAIL_SAV_ADR  AVAIL_BACK(rd->savadrreguse)

#define AVAIL_ARG_INT  AVAIL_FRONT_INT(rd->argintreguse, INT_ARG_CNT)
#define AVAIL_TMP_INT  AVAIL_BACK_INT(rd->tmpintreguse)
#define AVAIL_SAV_INT  AVAIL_BACK_INT(rd->savintreguse)

#define AVAIL_FREE_ARG_FLT  AVAIL_BACK(rd->freeargflttop)
#define AVAIL_FREE_TMP_FLT  AVAIL_BACK(rd->freetmpflttop)
#define AVAIL_FREE_SAV_FLT  AVAIL_BACK(rd->freesavflttop)

#define AVAIL_FREE_ARG_ADR  AVAIL_BACK(rd->freeargadrtop)
#define AVAIL_FREE_TMP_ADR  AVAIL_BACK(rd->freetmpadrtop)
#define AVAIL_FREE_SAV_ADR  AVAIL_BACK(rd->freesavadrtop)

#define AVAIL_FREE_ARG_INT  AVAIL_BACK_INT(rd->freearginttop)
#define AVAIL_FREE_TMP_INT  AVAIL_BACK_INT(rd->freetmpinttop)
#define AVAIL_FREE_SAV_INT  AVAIL_BACK_INT(rd->freesavinttop)

#define TAKE_ARG_FLT(r)  POP_FRONT(abi_registers_float_argument, rd->argfltreguse, r)
#define TAKE_TMP_FLT(r)  POP_BACK(rd->tmpfltregs, rd->tmpfltreguse, r)
#define TAKE_SAV_FLT(r)  POP_BACK(rd->savfltregs, rd->savfltreguse, r)

#define TAKE_ARG_ADR(r)  POP_FRONT(rd->argadrregs, rd->argadrreguse, r)
#define TAKE_TMP_ADR(r)  POP_BACK(rd->tmpadrregs, rd->tmpadrreguse, r)
#define TAKE_SAV_ADR(r)  POP_BACK(rd->savadrregs, rd->savadrreguse, r)

#define TAKE_ARG_INT(r)  POP_FRONT_INT(abi_registers_integer_argument, rd->argintreguse, r)
#define TAKE_TMP_INT(r)  POP_BACK_INT(rd->tmpintregs, rd->tmpintreguse, r)
#define TAKE_SAV_INT(r)  POP_BACK_INT(rd->savintregs, rd->savintreguse, r)

#define TAKE_FREE_ARG_FLT(r)  POP_BACK(rd->freeargfltregs, rd->freeargflttop, r)
#define TAKE_FREE_TMP_FLT(r)  POP_BACK(rd->freetmpfltregs, rd->freetmpflttop, r)
#define TAKE_FREE_SAV_FLT(r)  POP_BACK(rd->freesavfltregs, rd->freesavflttop, r)

#define TAKE_FREE_ARG_ADR(r)  POP_BACK(rd->freeargadrregs, rd->freeargadrtop, r)
#define TAKE_FREE_TMP_ADR(r)  POP_BACK(rd->freetmpadrregs, rd->freetmpadrtop, r)
#define TAKE_FREE_SAV_ADR(r)  POP_BACK(rd->freesavadrregs, rd->freesavadrtop, r)

#define TAKE_FREE_ARG_INT(r)  POP_BACK_INT(rd->freeargintregs, rd->freearginttop, r)
#define TAKE_FREE_TMP_INT(r)  POP_BACK_INT(rd->freetmpintregs, rd->freetmpinttop, r)
#define TAKE_FREE_SAV_INT(r)  POP_BACK_INT(rd->freesavintregs, rd->freesavinttop, r)

#define PUSH_FREE_ARG_FLT(r)  PUSH_BACK(rd->freeargfltregs, rd->freeargflttop, r)
#define PUSH_FREE_TMP_FLT(r)  PUSH_BACK(rd->freetmpfltregs, rd->freetmpflttop, r)
#define PUSH_FREE_SAV_FLT(r)  PUSH_BACK(rd->freesavfltregs, rd->freesavflttop, r)

#define PUSH_FREE_ARG_ADR(r)  PUSH_BACK(rd->freeargadrregs, rd->freeargadrtop, r)
#define PUSH_FREE_TMP_ADR(r)  PUSH_BACK(rd->freetmpadrregs, rd->freetmpadrtop, r)
#define PUSH_FREE_SAV_ADR(r)  PUSH_BACK(rd->freesavadrregs, rd->freesavadrtop, r)

#define PUSH_FREE_ARG_INT(r)  PUSH_BACK_INT(rd->freeargintregs, rd->freearginttop, r)
#define PUSH_FREE_TMP_INT(r)  PUSH_BACK_INT(rd->freetmpintregs, rd->freetmpinttop, r)
#define PUSH_FREE_SAV_INT(r)  PUSH_BACK_INT(rd->freesavintregs, rd->freesavinttop, r)


/* macros for allocating memory slots ****************************************/

#define NEW_MEM_SLOT(r)                                              \
    do {                                                             \
        (r) = rd->memuse * SIZE_OF_STACKSLOT;                        \
        rd->memuse += memneeded + 1;                                 \
    } while (0)

#define NEW_MEM_SLOT_ALIGNED(r)                                      \
    do {                                                             \
        if ( (memneeded) && (rd->memuse & 1))                        \
            rd->memuse++;                                            \
        (r) = rd->memuse * SIZE_OF_STACKSLOT;                        \
        rd->memuse += memneeded + 1;                                 \
    } while (0)

#define NEW_MEM_SLOT_ALIGNED_REUSE_PADDING(r)                        \
    do {                                                             \
        if ( (memneeded) && (rd->memuse & 1)) {                      \
                  PUSH_BACK(rd->freemem, rd->freememtop, rd->memuse);      \
            rd->memuse++;                                            \
            }                                                            \
        (r) = rd->memuse * SIZE_OF_STACKSLOT;                        \
        rd->memuse += memneeded + 1;                                 \
    } while (0)

#if defined(ALIGN_LONGS_IN_MEMORY)
#define NEW_MEM_SLOT_INT_LNG(r)  NEW_MEM_SLOT_ALIGNED(r)
#else
#define NEW_MEM_SLOT_INT_LNG(r)  NEW_MEM_SLOT(r)
#endif

#if defined(ALIGN_DOUBLES_IN_MEMORY)
#define NEW_MEM_SLOT_FLT_DBL(r)  NEW_MEM_SLOT_ALIGNED(r)
#else
#define NEW_MEM_SLOT_FLT_DBL(r)  NEW_MEM_SLOT(r)
#endif

#if defined(ALIGN_LONGS_IN_MEMORY) || defined(ALIGN_DOUBLES_IN_MEMORY)
#define NEW_MEM_SLOT_REUSE_PADDING(r)  NEW_MEM_SLOT_ALIGNED_REUSE_PADDING(r)
#else
#define NEW_MEM_SLOT_REUSE_PADDING(r)  NEW_MEM_SLOT(r)
#endif


/* macros for creating/freeing temporary variables ***************************/

#define NEW_TEMP_REG(index)                                          \
    if ( ((index) >= jd->localcount)                                 \
         && (!(VAR(index)->flags & (INOUT | PREALLOC))) )            \
        simplereg_new_temp(jd, (index))


#define FREE_TEMP_REG(index)                                         \
    if (((index) > jd->localcount)                                   \
        && (!(VAR(index)->flags & (PREALLOC))))                      \
        simplereg_free_temp(jd, (index))


/* macro for getting a unique register index *********************************/

#if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
#define REG_INDEX_NON_ADR(regoff, type)                              \
    (IS_FLT_DBL_TYPE(type) ? (INT_REG_CNT + (regoff)) : (GET_LOW_REG(regoff)))
#else
#define REG_INDEX_NON_ADR(regoff, type)                              \
    (IS_FLT_DBL_TYPE(type) ? (INT_REG_CNT + (regoff)) : (regoff))
#endif

#if defined(HAS_ADDRESS_REGISTER_FILE)
#define REG_INDEX(regoff, type)                                      \
    (IS_ADR_TYPE(type) ? (regoff) : (ADR_REG_CNT + REG_INDEX_NON_ADR(regoff, type)))
#else
#define REG_INDEX(regoff, type)  REG_INDEX_NON_ADR(regoff, type)
#endif


/* regalloc ********************************************************************

   Does a simple register allocation.
      
*******************************************************************************/
      
bool regalloc(jitdata *jd)
{
      /* There is a problem with the use of unused float argument
         registers in leafmethods for stackslots on c7 (2 * Dual Core
         AMD Opteron(tm) Processor 270) - runtime for the jvm98 _mtrt
         benchmark is heaviliy increased. This could be prevented by
         setting rd->argfltreguse to FLT_ARG_CNT before calling
         simplereg_allocate_temporaries and setting it back to the original
         value before calling simplereg_allocate_locals.  */

      simplereg_allocate_interfaces(jd);
      simplereg_allocate_temporaries(jd);
      simplereg_allocate_locals(jd);

      /* everthing's ok */

      return true;
}


/* simplereg_allocate_interfaces ***********************************************

   Allocates registers for all interface variables.
      
*******************************************************************************/
      
static void simplereg_allocate_interfaces(jitdata *jd)
{
      methodinfo   *m;
      codeinfo     *code;
      codegendata  *cd;
      registerdata *rd;

      int     s, t, tt, saved;
      int     intalloc, fltalloc; /* Remember allocated Register/Memory offset */
                      /* in case more vars are packed into this interface slot */
      int         memneeded = 0;
      /* Allocate LNG and DBL types first to ensure 2 memory slots or          */
      /* registers on HAS_4BYTE_STACKSLOT architectures.                       */
      int     typeloop[] = { TYPE_LNG, TYPE_DBL, TYPE_INT, TYPE_FLT, TYPE_ADR };
      int     flags, regoff;
#if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
      int         intregsneeded;
#endif

      /* get required compiler data */

      m    = jd->m;
      code = jd->code;
      cd   = jd->cd;
      rd   = jd->rd;

      /* rd->memuse was already set in stack.c to allocate stack space
         for passing arguments to called methods. */

#if defined(__I386__)
      if (checksync && code_is_synchronized(code)) {
            /* reserve 0(%esp) for Monitorenter/exit Argument on i386 */
            if (rd->memuse < 1)
                  rd->memuse = 1;
      }
#endif

      if (code_is_leafmethod(code)) {
            /* Reserve argument register, which will be used for Locals acting */
            /* as Parameters */
            if (rd->argintreguse < m->parseddesc->argintreguse)
                  rd->argintreguse = m->parseddesc->argintreguse;
            if (rd->argfltreguse < m->parseddesc->argfltreguse)
                  rd->argfltreguse = m->parseddesc->argfltreguse;
#ifdef HAS_ADDRESS_REGISTER_FILE
            if (rd->argadrreguse < m->parseddesc->argadrreguse)
                  rd->argadrreguse = m->parseddesc->argadrreguse;
#endif
      }

      for (s = 0; s < jd->maxinterfaces; s++) {
            intalloc = -1; fltalloc = -1;

            /* check if the interface at this stack depth must be a SAVEDVAR */

            saved = 0;

            for (tt = 0; tt <=4; tt++) {
                  if ((t = jd->interface_map[s * 5 + tt].flags) != UNUSED) {
                        saved |= t & SAVEDVAR;
                  }
            }

            /* allocate reg/mem for each type the interface is used as */

            for (tt = 0; tt <= 4; tt++) {
                  t = typeloop[tt];
                  if (jd->interface_map[s * 5 + t].flags == UNUSED)
                        continue;

                  flags = saved;
                  regoff = -1; /* initialize to invalid value */

#if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
                  intregsneeded = (IS_2_WORD_TYPE(t)) ? 1 : 0;
#endif

#if defined(HAS_4BYTE_STACKSLOT)
                  memneeded = (IS_2_WORD_TYPE(t)) ? 1 : 0;
#endif

                  if (!saved) {
#if defined(HAS_ADDRESS_REGISTER_FILE)
                        if (IS_ADR_TYPE(t)) {
                              if (!code_is_leafmethod(code) && AVAIL_ARG_ADR) {
                                    flags |= ARGREG;
                                    TAKE_ARG_ADR(regoff);
                              } 
                              else if (AVAIL_TMP_ADR) {
                                    TAKE_TMP_ADR(regoff);
                              } 
                              else if (AVAIL_SAV_ADR) {
                                    flags |= SAVREG;
                                    TAKE_SAV_ADR(regoff);
                              } 
                              else {
                                    flags |= INMEMORY;
                                    regoff = rd->memuse++ * SIZE_OF_STACKSLOT;
                              }                                   
                        } 
                        else /* !IS_ADR_TYPE */
#endif /* defined(HAS_ADDRESS_REGISTER_FILE) */
                        {
                              if (IS_FLT_DBL_TYPE(t)) {
                                    if (fltalloc >= 0) {
                                          /* Reuse memory slot(s)/register(s) for shared interface slots */
                                          flags |= jd->interface_map[fltalloc].flags & ~SAVEDVAR;
                                          regoff = jd->interface_map[fltalloc].regoff;
                                    } 
                                    else if (AVAIL_ARG_FLT) {
                                          flags |= ARGREG;
                                          TAKE_ARG_FLT(regoff);
                                    } 
                                    else if (AVAIL_TMP_FLT) {
                                          TAKE_TMP_FLT(regoff);
                                    } 
                                    else if (AVAIL_SAV_FLT) {
                                          flags |= SAVREG;
                                          TAKE_SAV_FLT(regoff);
                                    } 
                                    else {
                                          flags |= INMEMORY;
                                          NEW_MEM_SLOT_FLT_DBL(regoff);
                                    }
                                    fltalloc = s * 5 + t;
                              }
                              else { /* !IS_FLT_DBL_TYPE(t) */
#if (SIZEOF_VOID_P == 4) && !defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
                                    /*
                                     * for i386 put all longs in memory
                                     */
                                    if (IS_2_WORD_TYPE(t)) {
                                          flags |= INMEMORY;
                                          NEW_MEM_SLOT_INT_LNG(regoff);
                                    } 
                                    else
#endif
                                          if (intalloc >= 0) {
                                                /* Reuse memory slot(s)/register(s) for shared interface slots */
                                                flags |= jd->interface_map[intalloc].flags & ~SAVEDVAR;
                                                regoff = jd->interface_map[intalloc].regoff;
#if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
                                                /* reuse lower half */
                                                if (!(flags & INMEMORY) 
                                                            && IS_2_WORD_TYPE(intalloc % 5))
                                                      regoff = GET_LOW_REG(regoff);
#endif
                                          } 
                                          else {
                                                if (AVAIL_ARG_INT) {
                                                      flags |= ARGREG;
                                                      TAKE_ARG_INT(regoff);
                                                }
                                                else if (AVAIL_TMP_INT) {
                                                      TAKE_TMP_INT(regoff);
                                                }
                                                else if (AVAIL_SAV_INT) {
                                                      flags |= SAVREG;
                                                      TAKE_SAV_INT(regoff);
                                                }
                                                else {
                                                      flags |= INMEMORY;
                                                      NEW_MEM_SLOT_INT_LNG(regoff);
                                                }
                                          }

                                    intalloc = s * 5 + t;
                              } /* if (IS_FLT_DBL_TYPE(t)) */
                        } 
                  } 
                  else { /* (saved) */
                        /* now the same like above, but without a chance to take a temporary register */
#ifdef HAS_ADDRESS_REGISTER_FILE
                        if (IS_ADR_TYPE(t)) {
                              if (AVAIL_SAV_ADR) {
                                    TAKE_SAV_ADR(regoff);
                              }
                              else {
                                    flags |= INMEMORY;
                                    regoff = rd->memuse++ * SIZE_OF_STACKSLOT;
                              }                                   
                        } 
                        else
#endif
                        {
                              if (IS_FLT_DBL_TYPE(t)) {
                                    if (fltalloc >= 0) {
                                          flags |= jd->interface_map[fltalloc].flags & ~SAVEDVAR;
                                          regoff = jd->interface_map[fltalloc].regoff;
                                    } 
                                    else {
                                          if (AVAIL_SAV_FLT) {
                                                TAKE_SAV_FLT(regoff);
                                          }
                                          else {
                                                flags |= INMEMORY;
                                                NEW_MEM_SLOT_FLT_DBL(regoff);
                                          }
                                    }
                                    fltalloc = s * 5 + t;
                              }
                              else { /* IS_INT_LNG */
#if (SIZEOF_VOID_P == 4) && !defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
                                    /*
                                     * for i386 put all longs in memory
                                     */
                                    if (IS_2_WORD_TYPE(t)) {
                                          flags |= INMEMORY;
                                          NEW_MEM_SLOT_INT_LNG(regoff);
                                    } 
                                    else
#endif
                                    {
                                          if (intalloc >= 0) {
                                                flags |= jd->interface_map[intalloc].flags & ~SAVEDVAR;
                                                regoff = jd->interface_map[intalloc].regoff;
#if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
                                                /*  reuse lower half */
                                                if (!(flags & INMEMORY)
                                                            && IS_2_WORD_TYPE(intalloc % 5))
                                                      regoff = GET_LOW_REG(regoff);
#endif
                                          } 
                                          else {
                                                if (AVAIL_SAV_INT) {
                                                      TAKE_SAV_INT(regoff);
                                                } 
                                                else {
                                                      flags |= INMEMORY;
                                                      NEW_MEM_SLOT_INT_LNG(regoff);
                                                }
                                          }
                                          intalloc = s*5 + t;
                                    }
                              } /* if (IS_FLT_DBL_TYPE(t) else */
                        } /* if (IS_ADR_TYPE(t)) else */
                  } /* if (saved) else */
                  /* if (type >= 0) */

                  assert(regoff >= 0);
                  jd->interface_map[5*s + t].flags = flags | INOUT;
                  jd->interface_map[5*s + t].regoff = regoff;
            } /* for t */
      } /* for s */
}


/* simplereg_allocate_locals_leafmethod ****************************************

   Allocates registers for all local variables of a leafmethod.
      
*******************************************************************************/
      
static void simplereg_allocate_locals_leafmethod(jitdata *jd)
{
      methodinfo   *m;
      codegendata  *cd;
      registerdata *rd;
      methoddesc *md;

      int     p, s, t, tt, varindex;
      int     intalloc, fltalloc;
      varinfo *v;
      int     intregsneeded = 0;
      int     memneeded = 0;
      int     typeloop[] = { TYPE_LNG, TYPE_DBL, TYPE_INT, TYPE_FLT, TYPE_ADR };
      int     fargcnt, iargcnt;
#ifdef HAS_ADDRESS_REGISTER_FILE
      int     aargcnt;
#endif

      /* get required compiler data */

      m  = jd->m;
      cd = jd->cd;
      rd = jd->rd;

      md = m->parseddesc;

      iargcnt = rd->argintreguse;
      fargcnt = rd->argfltreguse;
#ifdef HAS_ADDRESS_REGISTER_FILE
      aargcnt = rd->argadrreguse;
#endif
      for (p = 0, s = 0; s < jd->maxlocals; s++, p++) {
            intalloc = -1; fltalloc = -1;
            for (tt = 0; tt <= 4; tt++) {
                  t = typeloop[tt];
                  varindex = jd->local_map[s * 5 + t];
                  if (varindex == UNUSED)
                        continue;

                  v = VAR(varindex);

#if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
                  intregsneeded = (IS_2_WORD_TYPE(t)) ? 1 : 0;
#endif
#if defined(HAS_4BYTE_STACKSLOT)
                  memneeded = (IS_2_WORD_TYPE(t)) ? 1 : 0;
#endif

                  /*
                   *  The order of
                   *
                   *  #ifdef HAS_ADDRESS_REGISTER_FILE
                   *  if (IS_ADR_TYPE) { 
                   *  ...
                   *  } else 
                   *  #endif
                   *  if (IS_FLT_DBL) {
                   *  ...
                   *  } else { / int & lng
                   *  ...
                   *  }
                   *
                   *  must not to be changed!
                   */

#ifdef HAS_ADDRESS_REGISTER_FILE
                  if (IS_ADR_TYPE(t)) {
                        if ((p < md->paramcount) && !md->params[p].inmemory) {
                              v->flags = 0;
                              v->vv.regoff = rd->argadrregs[md->params[p].regoff];
                        }
                        else if (AVAIL_TMP_ADR) {
                              v->flags = 0;
                              TAKE_TMP_ADR(v->vv.regoff);
                        }
                        /* use unused argument registers as local registers */
                        else if ((p >= md->paramcount) &&
                                     (aargcnt < ADR_ARG_CNT)) 
                        {
                              v->flags = 0;
                              POP_FRONT(rd->argadrregs, aargcnt, v->vv.regoff);
                        }
                        else if (AVAIL_SAV_ADR) {
                              v->flags = 0;
                              TAKE_SAV_ADR(v->vv.regoff);
                        }
                        else {
                              v->flags |= INMEMORY;
                              v->vv.regoff = rd->memuse++ * SIZE_OF_STACKSLOT;
                        }                                   
                  } 
                  else {
#endif
                        if (IS_FLT_DBL_TYPE(t)) {
                              if (fltalloc >= 0) {
                                    v->flags = VAR(fltalloc)->flags;
                                    v->vv.regoff = VAR(fltalloc)->vv.regoff;
                              }
#if !defined(SUPPORT_PASS_FLOATARGS_IN_INTREGS)
                              /* We can only use float arguments as local variables,
                               * if we do not pass them in integer registers. */
                              else if ((p < md->paramcount) && !md->params[p].inmemory) {
                                    v->flags = 0;
                                    v->vv.regoff = md->params[p].regoff;
                              }
#endif
                              else if (AVAIL_TMP_FLT) {
                                    v->flags = 0;
                                    TAKE_TMP_FLT(v->vv.regoff);
                              }
                              /* use unused argument registers as local registers */
                              else if ((p >= md->paramcount) && (fargcnt < FLT_ARG_CNT)) {
                                    v->flags = 0;
                                    POP_FRONT(abi_registers_float_argument,
                                                  fargcnt, v->vv.regoff);
                              }
                              else if (AVAIL_SAV_FLT) {
                                    v->flags = 0;
                                    TAKE_SAV_FLT(v->vv.regoff);
                              }
                              else {
                                    v->flags = INMEMORY;
                                    NEW_MEM_SLOT_FLT_DBL(v->vv.regoff);
                              }
                              fltalloc = jd->local_map[s * 5 + t];

                        } 
                        else {
#if (SIZEOF_VOID_P == 4) && !defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
                              /*
                               * for i386 put all longs in memory
                               */
                              if (IS_2_WORD_TYPE(t)) {
                                    v->flags = INMEMORY;
                                    NEW_MEM_SLOT_INT_LNG(v->vv.regoff);
                              } 
                              else 
#endif
                              {
                                    if (intalloc >= 0) {
                                          v->flags = VAR(intalloc)->flags;
#if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
                                          if (!(v->flags & INMEMORY)
                                                && IS_2_WORD_TYPE(VAR(intalloc)->type))
                                                v->vv.regoff = GET_LOW_REG(
                                                                        VAR(intalloc)->vv.regoff);
                                          else
#endif
                                                v->vv.regoff = VAR(intalloc)->vv.regoff;
                                    }
                                    else if ((p < md->paramcount) && 
                                                 !md->params[p].inmemory) 
                                    {
                                          v->flags = 0;
#if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
                                          if (IS_2_WORD_TYPE(t))
                                                v->vv.regoff =
                                                      PACK_REGS(GET_LOW_REG(md->params[p].regoff),
                                                                    GET_HIGH_REG(md->params[p].regoff));
                                                else
#endif
                                                      v->vv.regoff = md->params[p].regoff;
                                    }
                                    else if (AVAIL_TMP_INT) {
                                          v->flags = 0;
                                          TAKE_TMP_INT(v->vv.regoff);
                                    }
                                    /*
                                     * use unused argument registers as local registers
                                     */
                                    else if ((p >= m->parseddesc->paramcount) &&
                                                 (iargcnt + intregsneeded < INT_ARG_CNT)) 
                                    {
                                          v->flags = 0;
                                          POP_FRONT_INT(abi_registers_integer_argument,
                                                              iargcnt, v->vv.regoff);
                                    }
                                    else if (AVAIL_SAV_INT) {
                                          v->flags = 0;
                                          TAKE_SAV_INT(v->vv.regoff);
                                    }
                                    else {
                                          v->flags = INMEMORY;
                                          NEW_MEM_SLOT_INT_LNG(v->vv.regoff);
                                    }
                              }
                              intalloc = jd->local_map[s * 5 + t];
                        }
#ifdef HAS_ADDRESS_REGISTER_FILE
                  }
#endif
            } /* for (tt=0;...) */

            /* If the current parameter is a 2-word type, the next local slot */
            /* is skipped.                                                    */

            if (p < md->paramcount)
                  if (IS_2_WORD_TYPE(md->paramtypes[p].type))
                        s++;
      }
}

/* simplereg_allocate_locals ***************************************************

   Allocates registers for all local variables.
      
*******************************************************************************/
      
static void simplereg_allocate_locals(jitdata *jd)
{
      codeinfo     *code;
      codegendata  *cd;
      registerdata *rd;

      int     s, t, tt, varindex;
      int     intalloc, fltalloc;
      varinfo *v;
      int     memneeded = 0;
      int     typeloop[] = { TYPE_LNG, TYPE_DBL, TYPE_INT, TYPE_FLT, TYPE_ADR };
#ifdef SUPPORT_COMBINE_INTEGER_REGISTERS
      s4 intregsneeded;
#endif

      /* get required compiler data */

      code = jd->code;
      cd   = jd->cd;
      rd   = jd->rd;

      if (code_is_leafmethod(code)) {
            simplereg_allocate_locals_leafmethod(jd);
            return;
      }

      for (s = 0; s < jd->maxlocals; s++) {
            intalloc = -1; fltalloc = -1;
            for (tt=0; tt<=4; tt++) {
                  t = typeloop[tt];

                  varindex = jd->local_map[s * 5 + t];
                  if (varindex == UNUSED)
                        continue;

                  v = VAR(varindex);

#ifdef SUPPORT_COMBINE_INTEGER_REGISTERS
                        intregsneeded = (IS_2_WORD_TYPE(t)) ? 1 : 0;
#endif

#if defined(HAS_4BYTE_STACKSLOT)
                        memneeded = (IS_2_WORD_TYPE(t)) ? 1 : 0;
#endif

#ifdef HAS_ADDRESS_REGISTER_FILE
                        if (IS_ADR_TYPE(t)) {
                              if (AVAIL_SAV_ADR) {
                                    v->flags = 0;
                                    TAKE_SAV_ADR(v->vv.regoff);
                              }
                              else {
                                    v->flags = INMEMORY;
                                    v->vv.regoff = rd->memuse++ * SIZE_OF_STACKSLOT;
                              }
                        } 
                        else {
#endif
                        if (IS_FLT_DBL_TYPE(t)) {
                              if (fltalloc >= 0) {
                                    v->flags = VAR(fltalloc)->flags;
                                    v->vv.regoff = VAR(fltalloc)->vv.regoff;
                              }
                              else if (AVAIL_SAV_FLT) {
                                    v->flags = 0;
                                    TAKE_SAV_FLT(v->vv.regoff);
                              }
                              else {
                                    v->flags = INMEMORY;
                                    NEW_MEM_SLOT_FLT_DBL(v->vv.regoff);
                              }
                              fltalloc = jd->local_map[s * 5 + t];
                        }
                        else {
#if (SIZEOF_VOID_P == 4) && !defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
                              /*
                               * for i386 put all longs in memory
                               */
                              if (IS_2_WORD_TYPE(t)) {
                                    v->flags = INMEMORY;
                                    NEW_MEM_SLOT_INT_LNG(v->vv.regoff);
                              } 
                              else {
#endif
                                    if (intalloc >= 0) {
                                          v->flags = VAR(intalloc)->flags;
#if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
                                          if (!(v->flags & INMEMORY)
                                                && IS_2_WORD_TYPE(VAR(intalloc)->type))
                                                v->vv.regoff = GET_LOW_REG(
                                                                      VAR(intalloc)->vv.regoff);
                                          else
#endif
                                                v->vv.regoff = VAR(intalloc)->vv.regoff;
                                    }
                                    else if (AVAIL_SAV_INT) {
                                          v->flags = 0;
                                          TAKE_SAV_INT(v->vv.regoff);
                                    }
                                    else {
                                          v->flags = INMEMORY;
                                          NEW_MEM_SLOT_INT_LNG(v->vv.regoff);
                                    }
#if (SIZEOF_VOID_P == 4) && !defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
                              }
#endif
                              intalloc = jd->local_map[s * 5 + t];
                        }
#ifdef HAS_ADDRESS_REGISTER_FILE
                        }
#endif
            }
      }
}


static void simplereg_init(jitdata *jd, registerdata *rd)
{
      int i;

      rd->freememtop = 0;
#if defined(HAS_4BYTE_STACKSLOT)
      rd->freememtop_2 = 0;
#endif

      rd->freetmpinttop = 0;
      rd->freesavinttop = 0;
      rd->freetmpflttop = 0;
      rd->freesavflttop = 0;
#ifdef HAS_ADDRESS_REGISTER_FILE
      rd->freetmpadrtop = 0;
      rd->freesavadrtop = 0;
#endif

      rd->freearginttop = 0;
      rd->freeargflttop = 0;
#ifdef HAS_ADDRESS_REGISTER_FILE
      rd->freeargadrtop = 0;
#endif

      rd->regisoutvar = DMNEW(int, TOTAL_REG_CNT);
      rd->regcopycount = DMNEW(int, TOTAL_REG_CNT);
      MZERO(rd->regcopycount, int, TOTAL_REG_CNT);

      /* memcopycount is dynamically allocated when needed */

      rd->memcopycount = NULL;
      rd->memcopycountsize = 0;

      rd->intusedinout = DMNEW(int, INT_REG_CNT);
      MZERO(rd->intusedinout, int, INT_REG_CNT);
      rd->fltusedinout = DMNEW(int, FLT_REG_CNT);
      MZERO(rd->fltusedinout, int, FLT_REG_CNT);

      /* record the interface registers as used */

      for (i=0; i<rd->argintreguse; ++i)
            rd->intusedinout[abi_registers_integer_argument[i]] = 1;
      for (i=rd->tmpintreguse; i<INT_TMP_CNT; ++i)
            rd->intusedinout[rd->tmpintregs[i]] = 1;
      for (i=rd->savintreguse; i<INT_SAV_CNT; ++i)
            rd->intusedinout[rd->savintregs[i]] = 1;

      for (i=0; i<rd->argfltreguse; ++i)
            rd->fltusedinout[abi_registers_float_argument[i]] = 1;
      for (i=rd->tmpfltreguse; i<FLT_TMP_CNT; ++i)
            rd->fltusedinout[rd->tmpfltregs[i]] = 1;
      for (i=rd->savfltreguse; i<FLT_SAV_CNT; ++i)
            rd->fltusedinout[rd->savfltregs[i]] = 1;

#ifdef HAS_ADDRESS_REGISTER_FILE
      rd->adrusedinout = DMNEW(int, ADR_REG_CNT);
      MZERO(rd->adrusedinout, int, ADR_REG_CNT);

      for (i=0; i<rd->argadrreguse; ++i)
            rd->adrusedinout[rd->argadrregs[i]] = 1;
      for (i=rd->tmpadrreguse; i<ADR_TMP_CNT; ++i)
            rd->adrusedinout[rd->tmpadrregs[i]] = 1;
      for (i=rd->savadrreguse; i<ADR_SAV_CNT; ++i)
            rd->adrusedinout[rd->savadrregs[i]] = 1;
#endif
}


static void simplereg_init_block(registerdata *rd)
{
      int i;

      /* remove all interface registers from the free lists */

      for (i=0; i<rd->freearginttop; ++i)
            if (rd->intusedinout[rd->freeargintregs[i]]) {
                  rd->freeargintregs[i--] = rd->freeargintregs[--rd->freearginttop];
            }
      for (i=0; i<rd->freetmpinttop; ++i)
            if (rd->intusedinout[rd->freetmpintregs[i]]) {
                  rd->freetmpintregs[i--] = rd->freetmpintregs[--rd->freetmpinttop];
            }
      for (i=0; i<rd->freesavinttop; ++i)
            if (rd->intusedinout[rd->freesavintregs[i]]) {
                  rd->freesavintregs[i--] = rd->freesavintregs[--rd->freesavinttop];
            }

      for (i=0; i<rd->freeargflttop; ++i)
            if (rd->fltusedinout[rd->freeargfltregs[i]]) {
                  rd->freeargfltregs[i--] = rd->freeargfltregs[--rd->freeargflttop];
            }
      for (i=0; i<rd->freetmpflttop; ++i)
            if (rd->fltusedinout[rd->freetmpfltregs[i]]) {
                  rd->freetmpfltregs[i--] = rd->freetmpfltregs[--rd->freetmpflttop];
            }
      for (i=0; i<rd->freesavflttop; ++i)
            if (rd->fltusedinout[rd->freesavfltregs[i]]) {
                  rd->freesavfltregs[i--] = rd->freesavfltregs[--rd->freesavflttop];
            }

#ifdef HAS_ADDRESS_REGISTER_FILE
      for (i=0; i<rd->freeargadrtop; ++i)
            if (rd->adrusedinout[rd->freeargadrregs[i]]) {
                  rd->freeargadrregs[i--] = rd->freeargadrregs[--rd->freeargadrtop];
            }
      for (i=0; i<rd->freetmpadrtop; ++i)
            if (rd->adrusedinout[rd->freetmpadrregs[i]]) {
                  rd->freetmpadrregs[i--] = rd->freetmpadrregs[--rd->freetmpadrtop];
            }
      for (i=0; i<rd->freesavadrtop; ++i)
            if (rd->adrusedinout[rd->freesavadrregs[i]]) {
                  rd->freesavadrregs[i--] = rd->freesavadrregs[--rd->freesavadrtop];
            }
#endif
}


static void simplereg_new_temp(jitdata *jd, s4 index)
{
#ifdef SUPPORT_COMBINE_INTEGER_REGISTERS
      s4 intregsneeded;
#endif
      s4 memneeded;
      s4 tryagain;
      registerdata *rd;
      varinfo      *v;

      rd = jd->rd;
      v = VAR(index);

      /* assert that constants are not allocated */

      assert(v->type != TYPE_RET);

      /* Try to allocate a saved register if there is no temporary one          */
      /* available. This is what happens during the second run.                 */
      tryagain = (v->flags & SAVEDVAR) ? 1 : 2;

#ifdef SUPPORT_COMBINE_INTEGER_REGISTERS
      intregsneeded = (IS_2_WORD_TYPE(v->type)) ? 1 : 0;
#endif

#if defined(HAS_4BYTE_STACKSLOT)
      memneeded = (IS_2_WORD_TYPE(v->type)) ? 1 : 0;
#else
      memneeded = 0;
#endif

      for(; tryagain; --tryagain) {
            if (tryagain == 1) {
                  if (!(v->flags & SAVEDVAR))
                        v->flags |= SAVREG;
#ifdef HAS_ADDRESS_REGISTER_FILE
                  if (IS_ADR_TYPE(v->type)) {
                        if (AVAIL_FREE_SAV_ADR) {
                              TAKE_FREE_SAV_ADR(v->vv.regoff);
                              return;
                        } 
                        else if (AVAIL_SAV_ADR) {
                              TAKE_SAV_ADR(v->vv.regoff);
                              return;
                        }
                  } 
                  else
#endif
                  {
                        if (IS_FLT_DBL_TYPE(v->type)) {
                              if (AVAIL_FREE_SAV_FLT) {
                                    TAKE_FREE_SAV_FLT(v->vv.regoff);
                                    return;
                              } 
                              else if (AVAIL_SAV_FLT) {
                                    TAKE_SAV_FLT(v->vv.regoff);
                                    return;
                              }
                        } 
                        else {
#if (SIZEOF_VOID_P == 4) && !defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
                              /*
                               * for i386 put all longs in memory
                               */
                              if (!IS_2_WORD_TYPE(v->type))
#endif
                              {
                                    if (AVAIL_FREE_SAV_INT) {
                                          TAKE_FREE_SAV_INT(v->vv.regoff);
                                          return;
                                    } 
                                    else if (AVAIL_SAV_INT) {
                                          TAKE_SAV_INT(v->vv.regoff);
                                          return;
                                    }
                              }
                        }
                  }
            } 
            else { /* tryagain == 2 */
#ifdef HAS_ADDRESS_REGISTER_FILE
                  if (IS_ADR_TYPE(v->type)) {
                        if (AVAIL_FREE_TMP_ADR) {
                              TAKE_FREE_TMP_ADR(v->vv.regoff);
                              return;
                        } 
                        else if (AVAIL_TMP_ADR) {
                              TAKE_TMP_ADR(v->vv.regoff);
                              return;
                        }
                  } 
                  else
#endif
                  {
                        if (IS_FLT_DBL_TYPE(v->type)) {
                              if (AVAIL_FREE_ARG_FLT) {
                                    v->flags |= ARGREG;
                                    TAKE_FREE_ARG_FLT(v->vv.regoff);
                                    return;
                              } 
                              else if (AVAIL_ARG_FLT) {
                                    v->flags |= ARGREG;
                                    TAKE_ARG_FLT(v->vv.regoff);
                                    return;
                              } 
                              else if (AVAIL_FREE_TMP_FLT) {
                                    TAKE_FREE_TMP_FLT(v->vv.regoff);
                                    return;
                              } 
                              else if (AVAIL_TMP_FLT) {
                                    TAKE_TMP_FLT(v->vv.regoff);
                                    return;
                              }

                        } 
                        else {
#if (SIZEOF_VOID_P == 4) && !defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
                              /*
                               * for i386 put all longs in memory
                               */
                              if (!IS_2_WORD_TYPE(v->type))
#endif
                              {
                                    if (AVAIL_FREE_ARG_INT) {
                                          v->flags |= ARGREG;
                                          TAKE_FREE_ARG_INT(v->vv.regoff);
                                          return;
                                    } 
                                    else if (AVAIL_ARG_INT) {
                                          v->flags |= ARGREG;
                                          TAKE_ARG_INT(v->vv.regoff);
                                          return;
                                    } 
                                    else if (AVAIL_FREE_TMP_INT) {
                                          TAKE_FREE_TMP_INT(v->vv.regoff);
                                          return;
                                    } 
                                    else if (AVAIL_TMP_INT) {
                                          TAKE_TMP_INT(v->vv.regoff);
                                          return;
                                    }
                              } /* if (!IS_2_WORD_TYPE(s->type)) */
                        } /* if (IS_FLT_DBL_TYPE(s->type)) */
                  } /* if (IS_ADR_TYPE(s->type)) */
            } /* if (tryagain == 1) else */
      } /* for(; tryagain; --tryagain) */

      /* spill to memory */

      v->flags |= INMEMORY;

#if defined(HAS_4BYTE_STACKSLOT)
      if ((memneeded == 1) && (rd->freememtop_2 > 0))
            POP_BACK(rd->freemem_2, rd->freememtop_2, v->vv.regoff);
      else
#endif /*defined(HAS_4BYTE_STACKSLOT) */
            if ((memneeded == 0) && (rd->freememtop > 0))
                  POP_BACK(rd->freemem, rd->freememtop, v->vv.regoff);
            else
                  NEW_MEM_SLOT_REUSE_PADDING(v->vv.regoff);
}


static void simplereg_free(registerdata *rd, s4 flags, s4 regoff, s4 type)
{
      /* assert that constants are not freed */

      assert(type != TYPE_RET);

      /* if this is a copy of another variable, just decrement the copy counter */

      if (flags & INMEMORY) {
            int32_t memindex;

            if (flags & INOUT)
                  return;

            memindex = regoff / SIZE_OF_STACKSLOT;

            if (memindex < rd->memcopycountsize && rd->memcopycount[memindex]) {
                  rd->memcopycount[memindex]--;
                  return;
            }
      }
      else {
            s4 regindex;

            regindex = REG_INDEX(regoff, type);

            /* do not free interface registers that are needed as outvars */

            if (flags & INOUT) {
                  if (rd->regisoutvar[regindex]) {
                        LOG(("DONT FREE f=%02x r=%d t=%d\n", flags, regoff, type));
                        return;
                  }

                  LOG(("FREEING INVAR f=%02x r=%d t=%d\n", flags, regoff, type));
            }

            if (rd->regcopycount[regindex]) {
                  rd->regcopycount[regindex]--;
                  return;
            }
      }

      if (flags & INMEMORY) {
#if defined(HAS_4BYTE_STACKSLOT)
            if (IS_2_WORD_TYPE(type))
                  PUSH_BACK(rd->freemem_2, rd->freememtop_2, regoff);
            else 
#endif
                  PUSH_BACK(rd->freemem, rd->freememtop, regoff);

            return;
      } 

      /* freeing a register */

#ifdef HAS_ADDRESS_REGISTER_FILE
      if (IS_ADR_TYPE(type)) {
            if (flags & (SAVEDVAR | SAVREG))
                  PUSH_FREE_SAV_ADR(regoff);
            else
                  PUSH_FREE_TMP_ADR(regoff);
      } 
#endif
      else if (IS_FLT_DBL_TYPE(type)) {
            if (flags & (SAVEDVAR | SAVREG))
                  PUSH_FREE_SAV_FLT(regoff);
            else if (flags & ARGREG)
                  PUSH_FREE_ARG_FLT(regoff);
            else
                  PUSH_FREE_TMP_FLT(regoff);
      } 
      else { /* IS_INT_LNG_TYPE */
#if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
            s4 intregsneeded = (IS_2_WORD_TYPE(type)) ? 1 : 0;
#endif

            if (flags & (SAVEDVAR | SAVREG))
                  PUSH_FREE_SAV_INT(regoff);
            else if (flags & ARGREG)
                  PUSH_FREE_ARG_INT(regoff);
            else
                  PUSH_FREE_TMP_INT(regoff);
      }
}


static inline void simplereg_free_temp(jitdata *jd, s4 index)
{
      varinfo *v;

      v = VAR(index);

      simplereg_free(jd->rd, v->flags, v->vv.regoff, v->type);
}


static bool simplereg_alloc_dup(jitdata *jd, s4 srcindex, s4 dstindex)
{
      varinfo *sv;
      varinfo *dv;

      /* do not coalesce local variables here */

      if (srcindex <= jd->localcount || dstindex <= jd->localcount)
            return false;

      sv = VAR(srcindex);
      dv = VAR(dstindex);

      /* do not coalesce in/out vars or preallocated variables here */

      if ((sv->flags | dv->flags) & (INOUT | PREALLOC))
            return false;

      /* if the source is in memory, we can coalesce in any case */

      if (sv->flags & INMEMORY) {
            dv->flags |= INMEMORY;
            dv->vv.regoff = sv->vv.regoff;
            return true;
      }

      /* we do not allocate a REG_TMP to a REG_SAV variable */

      if ((sv->flags & SAVEDVAR) != (dv->flags & SAVEDVAR))
            return false;

      /* coalesce */
      dv->vv.regoff = sv->vv.regoff;
      dv->flags |= sv->flags & (SAVREG | ARGREG);

      return true;
}


/* simplereg_allocate_temporaries **********************************************

   Allocate temporary (non-interface, non-local) registers.

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

static void simplereg_allocate_temporaries(jitdata *jd)
{
      methodinfo         *m;
      registerdata       *rd;
      s4                  i;
      s4                  len;
      instruction        *iptr;
      basicblock         *bptr;
      builtintable_entry *bte;
      methoddesc         *md;
      s4                 *argp;
      varinfo            *v;
      s4                  flags;
      s4                  regoff;
      s4                  type;
      s4                  regindex;

      /* get required compiler data */

      m  = jd->m;
      rd = jd->rd;

      /* initialize temp registers */

      simplereg_init(jd, rd);

      bptr = jd->basicblocks;

      while (bptr != NULL) {
            if (bptr->flags >= BBREACHED) {

                  LOG(("\nallocating block L%03d\n", bptr->nr));

                  simplereg_init_block(rd);

                  /* assert that all copy counts are zero */

#if !defined(NDEBUG) && !defined(ENABLE_SSA)
                  for (i=0; i < TOTAL_REG_CNT; ++i)
                        assert(rd->regcopycount[i] == 0);
#endif

                  /* reset outvar flags */

                  MZERO(rd->regisoutvar, int, TOTAL_REG_CNT);

                  /* set allocation of invars */

                  for (i=0; i<bptr->indepth; ++i) 
                  {
                        v = VAR(bptr->invars[i]);
                        if (v->type == TYPE_RET)
                              continue;

                        v->vv.regoff = jd->interface_map[5*i + v->type].regoff;
                        v->flags  = jd->interface_map[5*i + v->type].flags;

                        if (!(v->flags & INMEMORY))
                              rd->regcopycount[REG_INDEX(v->vv.regoff, v->type)] = 1;
                  }

                  /* set allocation of outvars */

                  for (i=0; i<bptr->outdepth; ++i) 
                  {
                        v = VAR(bptr->outvars[i]);
                        if (v->type == TYPE_RET)
                              continue;

                        v->vv.regoff = jd->interface_map[5*i + v->type].regoff;
                        v->flags  = jd->interface_map[5*i + v->type].flags;

                        if (!(v->flags & INMEMORY)) {
                              regindex = REG_INDEX(v->vv.regoff, v->type);
                              rd->regcopycount[regindex] = 1;
                              rd->regisoutvar[regindex] = 1;
                        }
                  }

                  /* free interface registers not used in this block */

                  for (i=0; i < 5 * jd->maxinterfaces; ++i) {
                        type = i%5;
                        regoff = jd->interface_map[i].regoff;
                        flags = jd->interface_map[i].flags;

                        if (!(flags & INMEMORY)) {
                              if (!rd->regcopycount[REG_INDEX(regoff, type)]) {
                                    LOG(("MAY REUSE interface register f=%02x r=%d t=%d\n", 
                                                      flags, regoff, type));
                                    simplereg_free(rd, flags, regoff, type);

                                    /* mark it, so it is not freed again */
                                    rd->regcopycount[REG_INDEX(regoff, type)] = -1;
                              }
                        }
                  }

                  /* reset copy counts */

                  MZERO(rd->regcopycount, int, TOTAL_REG_CNT);

                  /* iterate over ICMDS to allocate temporary variables */

                  iptr = bptr->iinstr;
                  len = bptr->icount;

                  while (--len >= 0)  {

                        switch (iptr->opc) {

                              /* pop 0 push 0 */

                        case ICMD_JSR:
                        case ICMD_NOP:
                        case ICMD_CHECKNULL:
                        case ICMD_IINC:
                        case ICMD_RET:
                        case ICMD_RETURN:
                        case ICMD_GOTO:
                        case ICMD_PUTSTATICCONST:
                        case ICMD_INLINE_START:
                        case ICMD_INLINE_END:
                        case ICMD_INLINE_BODY:
                              break;

                              /* pop 0 push 1 const */
                              
                        case ICMD_ICONST:
                        case ICMD_LCONST:
                        case ICMD_FCONST:
                        case ICMD_DCONST:
                        case ICMD_ACONST:
                        case ICMD_GETEXCEPTION:

                              /* pop 0 push 1 load */
                              
                        case ICMD_ILOAD:
                        case ICMD_LLOAD:
                        case ICMD_FLOAD:
                        case ICMD_DLOAD:
                        case ICMD_ALOAD:
                              NEW_TEMP_REG(iptr->dst.varindex);
                              break;

                              /* pop 2 push 1 */

                        case ICMD_IALOAD:
                        case ICMD_LALOAD:
                        case ICMD_FALOAD:
                        case ICMD_DALOAD:
                        case ICMD_AALOAD:

                        case ICMD_BALOAD:
                        case ICMD_CALOAD:
                        case ICMD_SALOAD:
                              FREE_TEMP_REG(iptr->sx.s23.s2.varindex);
                              FREE_TEMP_REG(iptr->s1.varindex);
                              NEW_TEMP_REG(iptr->dst.varindex);
                              break;

                              /* pop 3 push 0 */

                        case ICMD_IASTORE:
                        case ICMD_LASTORE:
                        case ICMD_FASTORE:
                        case ICMD_DASTORE:
                        case ICMD_AASTORE:

                        case ICMD_BASTORE:
                        case ICMD_CASTORE:
                        case ICMD_SASTORE:
                              FREE_TEMP_REG(iptr->sx.s23.s3.varindex);
                              FREE_TEMP_REG(iptr->sx.s23.s2.varindex);
                              FREE_TEMP_REG(iptr->s1.varindex);
                              break;

                              /* pop 1 push 0 store */

                        case ICMD_ISTORE:
                        case ICMD_LSTORE:
                        case ICMD_FSTORE:
                        case ICMD_DSTORE:
                        case ICMD_ASTORE:

                              /* pop 1 push 0 */

                        case ICMD_POP:

                        case ICMD_IRETURN:
                        case ICMD_LRETURN:
                        case ICMD_FRETURN:
                        case ICMD_DRETURN:
                        case ICMD_ARETURN:

                        case ICMD_ATHROW:

                        case ICMD_PUTSTATIC:
                        case ICMD_PUTFIELDCONST:

                              /* pop 1 push 0 branch */

                        case ICMD_IFNULL:
                        case ICMD_IFNONNULL:

                        case ICMD_IFEQ:
                        case ICMD_IFNE:
                        case ICMD_IFLT:
                        case ICMD_IFGE:
                        case ICMD_IFGT:
                        case ICMD_IFLE:

                        case ICMD_IF_LEQ:
                        case ICMD_IF_LNE:
                        case ICMD_IF_LLT:
                        case ICMD_IF_LGE:
                        case ICMD_IF_LGT:
                        case ICMD_IF_LLE:

                              /* pop 1 push 0 table branch */

                        case ICMD_TABLESWITCH:
                        case ICMD_LOOKUPSWITCH:

                        case ICMD_MONITORENTER:
                        case ICMD_MONITOREXIT:
                              FREE_TEMP_REG(iptr->s1.varindex);
                              break;

                              /* pop 2 push 0 branch */

                        case ICMD_IF_ICMPEQ:
                        case ICMD_IF_ICMPNE:
                        case ICMD_IF_ICMPLT:
                        case ICMD_IF_ICMPGE:
                        case ICMD_IF_ICMPGT:
                        case ICMD_IF_ICMPLE:

                        case ICMD_IF_LCMPEQ:
                        case ICMD_IF_LCMPNE:
                        case ICMD_IF_LCMPLT:
                        case ICMD_IF_LCMPGE:
                        case ICMD_IF_LCMPGT:
                        case ICMD_IF_LCMPLE:

                        case ICMD_IF_ACMPEQ:
                        case ICMD_IF_ACMPNE:

                              /* pop 2 push 0 */

                        case ICMD_POP2:

                        case ICMD_PUTFIELD:

                        case ICMD_IASTORECONST:
                        case ICMD_LASTORECONST:
                        case ICMD_AASTORECONST:
                        case ICMD_BASTORECONST:
                        case ICMD_CASTORECONST:
                        case ICMD_SASTORECONST:
                              FREE_TEMP_REG(iptr->sx.s23.s2.varindex);
                              FREE_TEMP_REG(iptr->s1.varindex);
                              break;

                              /* pop 0 push 1 copy */
                              
                        case ICMD_COPY:
                              /* src === dst->prev (identical Stackslot Element)     */
                              /* src --> dst       (copied value, take same reg/mem) */

                              if (!simplereg_alloc_dup(jd, iptr->s1.varindex, iptr->dst.varindex)) {
                                    NEW_TEMP_REG(iptr->dst.varindex);
                              } 
                              else {
                                    v = VAROP(iptr->dst);

                                    if (v->flags & INMEMORY) {
                                          int32_t memindex = v->vv.regoff / SIZE_OF_STACKSLOT;
                                          if (memindex >= rd->memcopycountsize) {
                                                int newsize = (memindex + 1) * 2;
                                                i = rd->memcopycountsize;
                                                rd->memcopycount = DMREALLOC(rd->memcopycount, int, i, newsize);
                                                MZERO(rd->memcopycount + i, int, newsize - i);
                                                rd->memcopycountsize = newsize;
                                          }
                                          rd->memcopycount[memindex]++;
                                    }
                                    else {
                                          /* XXX split reg/mem variables on arm may need special handling here */

                                          s4 regindex = REG_INDEX(v->vv.regoff, v->type);

                                          rd->regcopycount[regindex]++;
                                    }
                              }
                              break;

                              /* pop 1 push 1 move */

                        case ICMD_MOVE:
                              if (!simplereg_alloc_dup(jd, iptr->s1.varindex, iptr->dst.varindex)) {
                                    NEW_TEMP_REG(iptr->dst.varindex);
                                    FREE_TEMP_REG(iptr->s1.varindex);
                              }
                              break;

                              /* pop 2 push 1 */
                              
                        case ICMD_IADD:
                        case ICMD_ISUB:
                        case ICMD_IMUL:
                        case ICMD_IDIV:
                        case ICMD_IREM:

                        case ICMD_ISHL:
                        case ICMD_ISHR:
                        case ICMD_IUSHR:
                        case ICMD_IAND:
                        case ICMD_IOR:
                        case ICMD_IXOR:

                        case ICMD_LADD:
                        case ICMD_LSUB:
                        case ICMD_LMUL:
                        case ICMD_LDIV:
                        case ICMD_LREM:

                        case ICMD_LOR:
                        case ICMD_LAND:
                        case ICMD_LXOR:

                        case ICMD_LSHL:
                        case ICMD_LSHR:
                        case ICMD_LUSHR:

                        case ICMD_FADD:
                        case ICMD_FSUB:
                        case ICMD_FMUL:
                        case ICMD_FDIV:
                        case ICMD_FREM:

                        case ICMD_DADD:
                        case ICMD_DSUB:
                        case ICMD_DMUL:
                        case ICMD_DDIV:
                        case ICMD_DREM:

                        case ICMD_LCMP:
                        case ICMD_FCMPL:
                        case ICMD_FCMPG:
                        case ICMD_DCMPL:
                        case ICMD_DCMPG:
                              FREE_TEMP_REG(iptr->sx.s23.s2.varindex);
                              FREE_TEMP_REG(iptr->s1.varindex);
                              NEW_TEMP_REG(iptr->dst.varindex);
                              break;

                              /* pop 1 push 1 */
                              
                        case ICMD_IADDCONST:
                        case ICMD_ISUBCONST:
                        case ICMD_IMULCONST:
                        case ICMD_IMULPOW2:
                        case ICMD_IDIVPOW2:
                        case ICMD_IREMPOW2:
                        case ICMD_IANDCONST:
                        case ICMD_IORCONST:
                        case ICMD_IXORCONST:
                        case ICMD_ISHLCONST:
                        case ICMD_ISHRCONST:
                        case ICMD_IUSHRCONST:

                        case ICMD_LADDCONST:
                        case ICMD_LSUBCONST:
                        case ICMD_LMULCONST:
                        case ICMD_LMULPOW2:
                        case ICMD_LDIVPOW2:
                        case ICMD_LREMPOW2:
                        case ICMD_LANDCONST:
                        case ICMD_LORCONST:
                        case ICMD_LXORCONST:
                        case ICMD_LSHLCONST:
                        case ICMD_LSHRCONST:
                        case ICMD_LUSHRCONST:

                        case ICMD_INEG:
                        case ICMD_INT2BYTE:
                        case ICMD_INT2CHAR:
                        case ICMD_INT2SHORT:
                        case ICMD_LNEG:
                        case ICMD_FNEG:
                        case ICMD_DNEG:

                        case ICMD_I2L:
                        case ICMD_I2F:
                        case ICMD_I2D:
                        case ICMD_L2I:
                        case ICMD_L2F:
                        case ICMD_L2D:
                        case ICMD_F2I:
                        case ICMD_F2L:
                        case ICMD_F2D:
                        case ICMD_D2I:
                        case ICMD_D2L:
                        case ICMD_D2F:

                        case ICMD_CHECKCAST:

                        case ICMD_ARRAYLENGTH:
                        case ICMD_INSTANCEOF:

                        case ICMD_NEWARRAY:
                        case ICMD_ANEWARRAY:

                        case ICMD_GETFIELD:
                              FREE_TEMP_REG(iptr->s1.varindex);
                              NEW_TEMP_REG(iptr->dst.varindex);
                              break;

                              /* pop 0 push 1 */
                              
                        case ICMD_GETSTATIC:

                        case ICMD_NEW:
                              NEW_TEMP_REG(iptr->dst.varindex);
                              break;

                              /* pop many push any */
                              
                        case ICMD_INVOKESTATIC:
                        case ICMD_INVOKESPECIAL:
                        case ICMD_INVOKEVIRTUAL:
                        case ICMD_INVOKEINTERFACE:
                              INSTRUCTION_GET_METHODDESC(iptr,md);
                              i = md->paramcount;
                              argp = iptr->sx.s23.s2.args;
                              while (--i >= 0) {
                                    FREE_TEMP_REG(*argp);
                                    argp++;
                              }
                              if (md->returntype.type != TYPE_VOID)
                                    NEW_TEMP_REG(iptr->dst.varindex);
                              break;

                        case ICMD_BUILTIN:
                              bte = iptr->sx.s23.s3.bte;
                              md = bte->md;
                              i = md->paramcount;
                              argp = iptr->sx.s23.s2.args;
                              while (--i >= 0) {
                                    FREE_TEMP_REG(*argp);
                                    argp++;
                              }
                              if (md->returntype.type != TYPE_VOID)
                                    NEW_TEMP_REG(iptr->dst.varindex);
                              break;

                        case ICMD_MULTIANEWARRAY:
                              i = iptr->s1.argcount;
                              argp = iptr->sx.s23.s2.args;
                              while (--i >= 0) {
                                    FREE_TEMP_REG(*argp);
                                    argp++;
                              }
                              NEW_TEMP_REG(iptr->dst.varindex);
                              break;

                        default:
                              exceptions_throw_internalerror("Unknown ICMD %d during register allocation",
                                                                           iptr->opc);
                              return;
                        } /* switch */
                        iptr++;
                  } /* while instructions */
            } /* if */
            bptr = bptr->next;
      } /* while blocks */
}


#if defined(ENABLE_STATISTICS)
void simplereg_make_statistics(jitdata *jd)
{
      methodinfo   *m;
      codegendata  *cd;
      registerdata *rd;
      int i;
      s4 len;
#if 0
      stackelement_t*    src, src_old;
      stackelement_t*    dst;
      instruction *iptr;
#endif
      basicblock  *bptr;
      int size_interface; /* == maximum size of in/out stack at basic block boundaries */
      bool in_register;
      varinfo *var;

      /* get required compiler data */

      m  = jd->m;
      cd = jd->cd;
      rd = jd->rd;

      in_register = true;

      size_interface = 0;

            /* count how many local variables are held in memory or register */
            for(i=0; i < jd->localcount; i++) {
                  if (VAR(i)->flags & INMEMORY) {
                        count_locals_spilled++;
                        in_register=false;
                  }
                  else {
                        count_locals_register++;
                  }
            }

            /* count how many stack slots are held in memory or register */

            bptr = jd->basicblocks;

            while (bptr != NULL) {
                  if (bptr->flags >= BBREACHED) {

#if defined(ENABLE_LSRA) || defined(ENABLE_SSA)
                  if (!opt_lsra) {
#endif      
                        /* check for memory moves from interface to BB instack */
                        len = bptr->indepth;
                        
                        if (len > size_interface) size_interface = len;

                        while (len) {
                              len--;
                              var = VAR(bptr->invars[len]);

                              /* invars statistics (currently none) */
                        }

                        /* check for memory moves from BB outstack to interface */
                        len = bptr->outdepth;
                        if (len > size_interface) size_interface = len;

                        while (len) {
                              len--;
                              var = VAR(bptr->outvars[len]);

                              /* outvars statistics (currently none) */
                        }
#if defined(ENABLE_LSRA) || defined(ENABLE_SSA)
                  }
#endif      


#if 0
                        dst = bptr->instack;
                        iptr = bptr->iinstr;
                        len = bptr->icount;
                        src_old = NULL;

                        while (--len >= 0)  {
                              src = dst;
                              dst = iptr->dst.var;

                              if ((src!= NULL) && (src != src_old)) { /* new stackslot */
                                    switch (src->varkind) {
                                    case TEMPVAR:
                                    case STACKVAR:
                                          if (!(src->flags & INMEMORY)) 
                                                count_ss_register++;
                                          else {
                                                count_ss_spilled++;
                                                in_register=false;
                                          }                       
                                          break;
                                          /*                            case LOCALVAR: */
                                          /*                                  if (!(rd->locals[src->varnum][src->type].flags & INMEMORY)) */
                                          /*                                        count_ss_register++; */
                                          /*                                  else */
                                          /*                                        count_ss_spilled++; */
                                          /*                                  break; */
                                    case ARGVAR:
                                          if (!(src->flags & INMEMORY)) 
                                                count_argument_mem_ss++;
                                          else
                                                count_argument_reg_ss++;
                                          break;


                                          /*                                  if (IS_FLT_DBL_TYPE(src->type)) { */
                                          /*                                        if (src->varnum < FLT_ARG_CNT) { */
                                          /*                                              count_ss_register++; */
                                          /*                                              break; */
                                          /*                                        } */
                                          /*                                  } else { */
                                          /* #if defined(__POWERPC__) */
                                          /*                                        if (src->varnum < INT_ARG_CNT - (IS_2_WORD_TYPE(src->type) != 0)) { */
                                          /* #else */
                                          /*                                        if (src->varnum < INT_ARG_CNT) { */
                                          /* #endif */
                                          /*                                              count_ss_register++; */
                                          /*                                              break; */
                                          /*                                        } */
                                          /*                                  } */
                                          /*                                  count_ss_spilled++; */
                                          /*                                  break; */
                                    }
                              }
                              src_old = src;
                              
                              iptr++;
                        } /* while instructions */
#endif
                  } /* if */

                  bptr = bptr->next;
            } /* while blocks */

            count_interface_size += size_interface; /* accummulate the size of the interface (between bb boundaries) */
            if (in_register) count_method_in_register++;
            if (in_register) {
/*                printf("INREGISTER: %s%s%s\n",m->class->name->text, m->name->text, m->descriptor->text); */
            }
}
#endif /* defined(ENABLE_STATISTICS) */


/*
 * These are local overrides for various environment variables in Emacs.
 * Please do not remove this and leave it at the end of the file, where
 * Emacs will automagically detect them.
 * ---------------------------------------------------------------------
 * Local variables:
 * mode: c
 * indent-tabs-mode: t
 * c-basic-offset: 4
 * tab-width: 4
 * End:
 * vim:noexpandtab:sw=4:ts=4:
 */

Generated by  Doxygen 1.6.0   Back to index