Logo Search packages:      
Sourcecode: linux86 version File versions  Download package

assign.c

/* assign.c - assignment and casting operations for bcc */

/* Copyright (C) 1992 Bruce Evans */

#include "bcc.h"
#include "byteord.h"
#include "gencode.h"
#include "reg.h"
#include "sc.h"
#include "sizes.h"
#include "type.h"

FORWARD void blockmove P((struct symstruct *source, struct symstruct *target));
FORWARD void call3 P((char *funcname, struct symstruct *target,
                  struct symstruct *source, uoffset_T size));
FORWARD void fconvert P((struct symstruct *source, struct typestruct *type));

PUBLIC void assign(source, target)
struct symstruct *source;
struct symstruct *target;
{
    store_pt regpushed;
    store_pt sourcereg;
    scalar_t tscalar;

    if (target->type->constructor & (ARRAY | FUNCTION) ||
      target->flags == TEMP || target->flags == (LABELLED | STRING) ||
      (target->indcount == 0 && target->flags != REGVAR))
    {
      bugerror("botched lvalue");
      return;
    }
    if (source->storage != target->storage
        || source->indcount != target->indcount
        || source->level != target->level
        || source->offset.offi != target->offset.offi   /* kludge union cmp */
        || source->type != target->type
        || ((source->storage & (LOCAL | GLOBAL)
            || source->level == OFFKLUDGELEVEL)
           && ((source->flags ^ target->flags) & LABELLED
               || (source->flags & LABELLED
                  && source->name.label != target->name.label)
               || (!(source->flags & LABELLED)
                  && strcmp(source->name.namep, target->name.namep) != 0))))
    {
      tscalar = target->type->scalar;
      if (tscalar & CHAR && source->storage == CONSTANT)
      {
          source->offset.offv &= CHMASKTO;
          source->type = target->type;
      }
      regpushed = preslval(source, target);
      if (!(tscalar & CHAR) || source->flags != TEMP ||
          source->offset.offi != sp || source->type->typesize > itypesize)
          cast(target->type, source);
      if (tscalar & RSCALAR)
      {
          if (source->storage == CONSTANT && (!reguse & doubleregs))
            load(source, doubleregs & ~DREG);
          if (source->storage != CONSTANT && source->indcount == 0)
          {
            /* XXX - 386 only */
            storereg(DREG, target);
#ifdef I80386
            if (i386_32)
            {
                if (tscalar & DOUBLE)
                {
                    target->indcount = 1;  /* XXX outnnadr clobbers this */
                    target->offset.offi += accregsize;
                    storereg(doubleregs & ~DREG, target);
                }
            }
            else
#endif
            if (tscalar & DOUBLE)
            {
                int i;
                for(i=1; i; i<<=1) if( i!= DREG && (doubleregs & i) )
                {
                   target->indcount = 1;  /* XXX outnnadr clobbers this */
                   target->offset.offi += accregsize;
                   storereg(i, target);
                }
            }
#ifdef I8088
            else if (tscalar & FLOAT)
            {
                target->indcount = 1;  /* XXX outnnadr clobbers this */
                target->offset.offi += accregsize;
                storereg(DATREG2, target);
            }
#endif
            target->storage = source->storage;
            target->offset.offi = 0;
          }
          else if (f_indirect(source) && tscalar & DOUBLE
                 && (!(reguse & OPREG) || target->storage == OPREG))
          {
            struct symstruct temptarg;

            temptarg = *target;
            pointat(&temptarg);
            call("Fpull");
            outntypechar(temptarg.type);
            sp += dtypesize;
          }
          else
            blockmove(source, target);
      }
      else if (target->type->constructor & STRUCTU)
          blockmove(source, target);
      else
      {
          if (tscalar & CHAR)
            load(source, DREG);
          else if (target->indcount == 0 && target->storage & regregs)
            load(source, target->storage);
          else
            loadany(source);
          if (tscalar & DLONG)
          {
            storereg(DREG, target);
            target->indcount = 1;
            target->offset.offi += accregsize;
          }
          if ((store_t) (sourcereg = source->storage) == DREG &&
            target->type->scalar & CHAR)
            sourcereg = BREG;
          storereg(sourcereg, target);
          if ((store_t) regpushed != 0)
          {
            /* DLONG */
            target->indcount = 1;
            target->offset.offi -= accregsize;
            recovlist(regpushed);
          }
          else
          {
            target->storage = sourcereg;
            target->offset.offi = 0;
            if (target->level == OFFKLUDGELEVEL)
                target->level = EXPRLEVEL;
          }
      }
    }
}

/* block move assumes itypesize == accregsize && BREG size == 1 */

PRIVATE void blockmove(source, target)
struct symstruct *source;
struct symstruct *target;
{
    struct symstruct oldtarget;
    uoffset_T typesize;
    struct symstruct worksource;

    oldtarget = *target;
    if ((typesize = target->type->typesize) >= 8 * itypesize ||
      source->indcount + target->indcount != 2)
    {
      address(source);
      address(target);
      call3("_memcpy", target, source, typesize);
    }
    else
    {
      if (source->level == OFFKLUDGELEVEL)
          addoffset(source);  /* else kludge is lost and offsets big */
      if (target->level == OFFKLUDGELEVEL)
          addoffset(target);
      worksource = *source;
      for (; typesize >= itypesize; typesize -= itypesize)
      {
          loadreg(source, DREG);
          worksource.offset.offi += itypesize;
          *source = worksource;
          storereg(DREG, target);
          target->indcount = 1;
          target->offset.offi += accregsize;
      }
      while (typesize-- != 0)
      {
          outload();
          outregname(BREG);
          outopsep();
          outadr(source);
          worksource.offset.offi += 1;
          *source = worksource;
          storereg(BREG, target);
          target->indcount = 1;
          target->offset.offi += 1;
      }
    }
    *target = oldtarget;
}

PRIVATE void call3(funcname, target, source, size)
char *funcname;
struct symstruct *target;
struct symstruct *source;
uoffset_T size;
{
    store_pt regpushed;
    offset_T spmark;
    struct symstruct *length;

    pushlist(regpushed = reguse & ~calleemask);
    spmark = sp;
    length = constsym((value_t) size);
    length->type = uitype;
    push(length);
    push(source);
    push(target);
    call(funcname);
    outnl();
    if (regpushed)
    {
      modstk(spmark);
      recovlist(regpushed);
    }
}

PUBLIC void cast(type, target)
struct typestruct *type;
struct symstruct *target;
{
    scalar_t newscalar;
    uoffset_T newsize;
    scalar_t oldscalar;
    uoffset_T oldsize;
    store_pt targreg;

    if (type->constructor & (ARRAY | FUNCTION)
      || (type->constructor & STRUCTU && target->type != type))
    {
      bugerror("botched implicit cast");
      return;
    }
    if (target->type == type)
      return;
    if (target->type->constructor == ARRAY)
      oldsize = ptypesize;
    else
      oldsize = target->type->typesize;
    newscalar = type->scalar;
    oldscalar = target->type->scalar;
    if ((newsize = type->typesize) == oldsize &&
      !((newscalar | oldscalar) & RSCALAR))
      ;
    else if (newsize == ctypesize)  /* char only */
    {
      if (oldscalar & RSCALAR)
          fconvert(target, type);
      else if (target->indcount == 1)
      {
#if DYNAMIC_LONG_ORDER
          if (long_big_endian)
#endif
#if DYNAMIC_LONG_ORDER || LONG_BIG_ENDIAN
# if INT_BIG_ENDIAN
            target->offset.offi += oldsize - ctypesize;
# else
          {
            if (oldscalar & DLONG)
                target->offset.offi += itypesize;     /* discard msword */
          }
# endif
#endif
#if DYNAMIC_LONG_ORDER
          else
#endif
#if DYNAMIC_LONG_ORDER || LONG_BIG_ENDIAN == 0
# if INT_BIG_ENDIAN
          target->offset.offi += ctypesize;
# else
          ;
# endif
#endif
      }
      else if (target->storage != CONSTANT)
      {
          load(target, DREG);
          target->storage = BREG;
      }
    }
    else if ((newscalar & (SHORT | INT | LONG) && !(newscalar & DLONG))
           || type->constructor & POINTER)
    {
      if (oldscalar & RSCALAR)
          fconvert(target, type);
      else if (oldsize < newsize)
          extend(target);
      else if (target->indcount == 1)
      {
#if DYNAMIC_LONG_ORDER
          if (long_big_endian)
#endif
#if DYNAMIC_LONG_ORDER || LONG_BIG_ENDIAN
          {
            if (oldscalar & DLONG)
                target->offset.offi += itypesize;     /* discard msword */
          }
#endif
      }
      else
          load(target, DREG);
    }
    else if (newscalar & DLONG)
    {
      if (oldscalar & RSCALAR)
          fconvert(target, type);
      else if (target->storage != CONSTANT)
      {
          extend(target);
          load(target, DREG);
          target->storage = targreg = getindexreg();
          if (oldscalar & UNSIGNED ||
            target->type->constructor & (ARRAY | FUNCTION | POINTER))
            uitol(targreg);
          else
            itol(targreg);
      }
    }
    else if (newscalar & RSCALAR)
    {
      saveopreg();            /* XXX */
      if (oldscalar & (ISCALAR | FLOAT))
          fpush(target);
      if (newscalar & FLOAT)
      {
          pointat(target);
          call("dto");
          outntypechar(type);
          justpushed(target); /* XXX - sets dtype wrong (harmless) and
                         * wastes (dtypesize - ftypesize) stack */
      }
      restoreopreg();
    }
    target->type = type;
}

/* extend char or short to int (unsigned if from unsigned) */

PUBLIC void extend(target)
struct symstruct *target;
{
    scalar_t tscalar;

    if ((tscalar = target->type->scalar) & (CHAR | SHORT))
    {
      if (target->storage != CONSTANT &&
          target->type->typesize < itypesize)
      {
          load(target, DREG);
          if (target->type == sctype)
            sctoi();
#if defined(I8088) && defined(I80386)
          else if (tscalar & SHORT)
          {
            if (tscalar & UNSIGNED)
                ustoi();
            else
                stoi();
          }
#endif
          else
            ctoi();
          target->storage = DREG;
      }
      if (tscalar & UNSIGNED)
          target->type = uitype;
      else
          target->type = itype;
    }
}

PRIVATE void fconvert(source, type)
struct symstruct *source;
struct typestruct *type;
{
    offset_T spmark;

    pushlist(reguse & OPREG);
    spmark = sp;
    pointat(source);
    if (source->type->scalar & DOUBLE)
      call("dto");
    else
      call("fto");
    if (type->scalar & UNSIGNED)
      outbyte('u');
    outntypechar(type);
    if (type->scalar & DLONG)
    {
      if (reguse & OPREG)
          bugerror("loading long into used reg");
      source->storage = OPREG;
    }
    else if (type->scalar & CHAR)
      source->storage = BREG;
    else
      source->storage = DREG;
    source->offset.offi =
      source->flags =
      source->indcount = 0;
    modstk(spmark);           /* could adjust later (load instead of pop) */
    poplist(reguse & OPREG);
}

Generated by  Doxygen 1.6.0   Back to index