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

hardop.c

/* hardop.c - hardware operations for bcc */

/* Copyright (C) 1992 Bruce Evans */

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

FORWARD void sub1 P((struct symstruct *source, struct symstruct *target));

PUBLIC void add(source, target)
struct symstruct *source;
struct symstruct *target;
{
    scalar_t sscalar;

    if (source->indcount == 0 && source->storage != CONSTANT &&
      (target->indcount != 0 || target->storage & ALLDATREGS))
      swapsym(target, source);
    if ((sscalar = source->type->scalar) & DLONG)
    {
      longop(ADDOP, source, target);
      return;
    }
    if (sscalar & RSCALAR)
    {
      floatop(ADDOP, source, target);
      return;
    }
    if (source->storage == CONSTANT)
    {
      extend(target);
      if (target->indcount != 0 || target->storage & reguse)
          loadany(target);
      target->offset.offi += (offset_T) source->offset.offv;
    }
    else if (source->indcount == 0)
    {
      /* target is also direct */
      sscalar |= target->type->scalar;    /* remember if unsigned/long */
      target->type = pctype;  /* fake to use indexadr() */
      indexadr(source, target);
    }
    else
    {
      /* source is indirect and not DREG */
      extend(target);
      load(target, DREG);
      outadd();
      movereg(source, DREG);
      if (source->type->scalar & CHAR)
          adc0();
    }
    target->type = iscalartotype(target->type->scalar | sscalar);
}

PUBLIC void incdec(op, source)
op_pt op;
struct symstruct *source;
{
    offset_T bump;
    bool_t postflag;
    store_t regmark;
    struct symstruct *target;
    struct symstruct targ;
#ifdef MC6809
    store_pt targreg;
#endif

    *(target = &targ) = *source;
    bump = 1;
    if (targ.type->constructor & POINTER)
      bump = targ.type->nexttype->typesize;
    if (op == PREDECOP || op == POSTDECOP)
      bump = -bump;
    postflag = FALSE;
    if (op == POSTDECOP || op == POSTINCOP)
      postflag = TRUE;
    reguse |= targ.storage;
    if (targ.type->scalar & DLONG)  /* cannot be direct */
    {
      if (postflag)
      {
          regmark = reguse;
          if (((reguse |= OPREG) & allindregs) == allindregs)
          {
            saveopreg();
            load(source, OPREG);
            pushreg(source->storage);
            restoreopreg();
          }
          else
          {
            loadany(source);
            reguse = regmark | source->storage;
            saveopreg();
          }
      }
      else
          saveopreg();
      pointat(target);
      switch (op)
      {
      case PREDECOP:
      case POSTDECOP:
          call("ldec");
          break;
      case PREINCOP:
      case POSTINCOP:
          call("linc");
          break;
      }
      outlongendian();
      restoreopreg();
      if (postflag && source->storage == OPREG)
          poplist(OPREG);
      return;
    }
    if (targ.type->scalar & RSCALAR)
    {
      saveopreg();
      pointat(target);
      switch (op)
      {
      case PREDECOP:
          call("Fpredec");
          break;
      case PREINCOP:
          call("Fpreinc");
          break;
      case POSTDECOP:
          call("Fpostdec");
          break;
      case POSTINCOP:
          call("Fpostinc");
          break;
      }
      outntypechar(targ.type);
      restoreopreg();
      if (postflag)
      {
          justpushed(source);
          source->type = targ.type;
      }
      return;
    }
    loadany(source);
#ifdef MC6809
    if (postflag && targ.flags != REGVAR &&
      !(source->storage & ALLDATREGS) &&
      ((reguse |= source->storage) & allindregs) != allindregs)
    {
      targreg = getindexreg();
      outlea();
      outregname(targreg);
      outtab();
      outshex(bump);
      outncregname(source->storage);
    }
    else
    {
      addconst(bump, targreg = source->storage);
      if (postflag)
          source->offset.offi = -bump;
    }
    storereg(targreg, target);
    target->storage = targreg;
    target->offset.offi = 0;
#else
    addconst(bump, source->storage);
    if (postflag)
      source->offset.offi = -bump;
    storereg(source->storage, target);
    target->storage = source->storage;
    target->offset.offi = 0;
#endif
}

PUBLIC void neg(target)
struct symstruct *target;
{
    scalar_t scalar;
    struct symstruct *source;

    if ((scalar = target->type->scalar) & DLONG)
      long1op(NEGOP, target);
    else if (scalar & RSCALAR)
      float1op(NEGOP, target);
    else
    {
      if (scalar & SHORT)
          extend(target);
      if (!(target->storage & ALLDATREGS))
      {
          /* load 0, subtract is shorter than load, negate */
          /* if no hardware integer negate; about the same if there is */
          sub1(target, source = constsym((value_t) 0));
          *target = *source;
      }
      else
      {
          load(target, DREG);
          negreg(target->storage);
          target->storage = DREG;
      }
      target->type = iscalartotype(scalar);
    }
}

PUBLIC void not(target)
struct symstruct *target;
{
    if (target->type->scalar & DLONG)
      long1op(NOTOP, target);
    else
    {
      extend(target);
      load(target, DREG);
      comDreg();
    }
}

/* 1-byte ops like AND acting on integers (not both constant) */

PUBLIC void op1(op, source, target)
op_pt op;
struct symstruct *source;
struct symstruct *target;
{
    char *opstr;
#ifdef OP1
# if MAXINDIRECT > 1
    indn_t indcount;
# endif
#endif
    bool_t resultchar;
    scalar_t resultscalar;
    scalar_t sscalar;
    scalar_t tscalar;

    if ((sscalar = source->type->scalar) & DLONG)
    {
      longop(op, source, target);
      return;
    }
    /* Emergency fix. The types of constants should be reduced here and in
     * other low-level routines anyway, and not in exptree.c and table.c,
     * and for the 80386 and maybe the 8086 they would be better not
     * reduced.
     */
    if (source->storage == CONSTANT && ischarconst(source->offset.offv))
    {
      if (sscalar & UNSIGNED)
          source->type = uctype;
      else
          source->type = ctype;
      sscalar = source->type->scalar;
    }
    tscalar = target->type->scalar;
    if (target->storage == CONSTANT && ischarconst(target->offset.offv))
    {
      if (sscalar & UNSIGNED)
          target->type = uctype;
      else
          target->type = ctype;
      tscalar = target->type->scalar;
    }
    resultscalar = sscalar | tscalar;
    if (op != ANDOP)
      resultchar = sscalar & tscalar & CHAR;
    else if ((resultchar = (sscalar | tscalar) & CHAR) != 0 &&
           source->storage == CONSTANT)
    {
      source->offset.offv &= CHMASKTO;
      if (sscalar & UNSIGNED)
          source->type = uctype;
      else
          source->type = ctype;
      sscalar = source->type->scalar;
    }
    if (target->indcount != 0 &&
      ((tscalar & CHAR && !(sscalar & CHAR) &&
       op != ANDOP) || (source->indcount == 0 && source->storage != CONSTANT)))
    {
      swapsym(target, source);
      sscalar = tscalar;
      tscalar = target->type->scalar;
    }
    if (source->indcount == 0 && source->storage != CONSTANT)
    {
      loadpres(source, target);
      push(source);
    }
#if MAXINDIRECT > 1
    else if (source->indcount >= MAXINDIRECT && !(sscalar & CHAR))
    {
      address(source);
      if (!(target->storage & ALLDATREGS))
          preserve(target);
      load(source, getindexreg());
      indirec(source);
    }
#endif
    if (!(tscalar & CHAR) &&
      op == ANDOP && sscalar & CHAR && target->indcount == 1)
      cast(ctype, target);
    if (!(target->storage & ALLDATREGS) || target->indcount != 0)
      pres2(target, source);
    load(target, DREG);
    opstr = opstring(op);
    if (source->storage == CONSTANT && op == ANDOP)
      andconst((offset_T) source->offset.offv);
#ifdef OP1
    else if (tscalar & CHAR && !(sscalar & CHAR) && op != ANDOP)
      outload();
    else
      outop2str(opstr);
#else /* OP1 */
    else
    {
      if (tscalar & CHAR && !(sscalar & CHAR) && op != ANDOP)
          extend(target);
      outop2str(opstr);
    }
#endif /* OP1 */
    if (source->storage == CONSTANT)
    {
      if (op != ANDOP)
      {
#ifdef OP1
          if (!(sscalar & CHAR))
          {
            outhiaccum();
            outncimmadr((offset_T) ((uoffset_T) source->offset.offv
                              >> (INT16BITSTO - CHBITSTO)));
            outop2str(opstr);
          }
          outregname(BREG);
          outncimmadr((offset_T) source->offset.offv & CHMASKTO);
#else /* OP1 */
          if (!(sscalar & CHAR))
          {
            outregname(DREG);
            bumplc();
          }
          else
            outregname(BREG);
# ifdef I80386
          if (i386_32 && !(sscalar & CHAR))
            bumplc2();
# endif
          outncimmadr((offset_T) source->offset.offv);

#endif /* OP1 */
      }
    }
    else if (sscalar & CHAR)
    {
      outregname(BREG);
      outopsep();
      outadr(source);
    }
    else
    {
#ifdef MC6809
      source->type = ctype;   /* fool outadr to avoid ,S++ */
#endif
#ifdef OP1
      if (!(tscalar & CHAR) || op != ANDOP)
      {
          outhiaccum();
# if MAXINDIRECT > 1
          indcount = source->indcount;
# endif
          outopsep();
# if INT_BIG_ENDIAN == 0
          ++source->offset.offi;
# endif
          outadr(source);
# if INT_BIG_ENDIAN == 0
          --source->offset.offi;
# endif
# if MAXINDIRECT > 1
          source->indcount = indcount;
# else
          source->indcount = 1;
# endif
          outop2str(opstr);
      }
      outregname(BREG);
      outopsep();
# if INT_BIG_ENDIAN
      ++source->offset.offi;
# endif
      outadr(source);
    }
#else /* OP1 */
      if (!(tscalar & CHAR) || op != ANDOP)
          outregname(DREG);
      else
          outregname(BREG);
      outopsep();
      outadr(source);
    }
#endif /* OP1 */
    if (resultchar)
    {
      target->storage = BREG;
      if (resultscalar & UNSIGNED)
          target->type = uctype;
      else
          target->type = ctype;
    }
    else
    {
      target->storage = DREG;
      target->type = iscalartotype(resultscalar);
    }
}

PUBLIC void ptrsub(source, target)
struct symstruct *source;
struct symstruct *target;
{
    label_no exitlab;
    uoffset_T factor;
    label_no usignlab;

    if (source->indcount == 0 && source->storage != CONSTANT)
    {
      loadpres(source, target);
      push(source);
    }
    if (target->indcount == 0)
    {
      pres2(target, source);
      load(target, DREG);
    }
    factor = target->type->nexttype->typesize;
    source->type = target->type = itype;
    sub1(source, target);
    if (factor != 1)
    {
      pushlist(CCREG);
      sbranch(HS, usignlab = getlabel()); /* HS == no carry */
      negDreg();
      outnlabel(usignlab);
      target->type = uitype;
      softop(DIVOP, constsym((value_t) factor), target);
      target->type = itype;
      poplist(CCREG);
      sbranch(HS, exitlab = getlabel());
      negDreg();
      outnlabel(exitlab);
    }
}

PUBLIC void sub(source, target)
struct symstruct *source;
struct symstruct *target;
{
    scalar_t sscalar;

    if ((sscalar = source->type->scalar) & DLONG)
    {
      longop(SUBOP, source, target);
      return;
    }
    if (sscalar & RSCALAR)
    {
      floatop(SUBOP, source, target);
      return;
    }
    if (source->storage == CONSTANT)
    {
      extend(target);
      if (target->indcount != 0 || target->storage & reguse)
          loadany(target);
      target->offset.offi -= (offset_T) source->offset.offv;
    }
    else
      sub1(source, target);
    target->type = iscalartotype(target->type->scalar | sscalar);
}

PRIVATE void sub1(source, target)
struct symstruct *source;
struct symstruct *target;
{
    if (source->storage == CONSTANT)
      source->type = itype;
    else if (source->indcount == 0)
    {
      loadpres(source, target);
      push(source);
    }
    extend(target);
    load(target, DREG);
    outsub();
    movereg(source, DREG);
    if (source->type->scalar & CHAR)
      sbc0();
}

Generated by  Doxygen 1.6.0   Back to index