summaryrefslogtreecommitdiff
path: root/bcc/hardop.c
diff options
context:
space:
mode:
Diffstat (limited to 'bcc/hardop.c')
-rw-r--r--bcc/hardop.c510
1 files changed, 510 insertions, 0 deletions
diff --git a/bcc/hardop.c b/bcc/hardop.c
new file mode 100644
index 0000000..098d22b
--- /dev/null
+++ b/bcc/hardop.c
@@ -0,0 +1,510 @@
+/* hardop.c - hardware operations for bcc */
+
+/* Copyright (C) 1992 Bruce Evans */
+
+#include "const.h"
+#include "types.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 I8088
+ 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 BIG_ENDIAN == 0
+ ++source->offset.offi;
+# endif
+ outadr(source);
+# if BIG_ENDIAN == 0
+ --source->offset.offi;
+# endif
+# if MAXINDIRECT > 1
+ source->indcount = indcount;
+# else
+ source->indcount = 1;
+# endif
+ outop2str(opstr);
+ }
+ outregname(BREG);
+ outopsep();
+# if 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_t exitlab;
+ uoffset_t factor;
+ label_t 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();
+}