summaryrefslogtreecommitdiff
path: root/bcc/longop.c
diff options
context:
space:
mode:
Diffstat (limited to 'bcc/longop.c')
-rw-r--r--bcc/longop.c169
1 files changed, 169 insertions, 0 deletions
diff --git a/bcc/longop.c b/bcc/longop.c
new file mode 100644
index 0000000..f678e11
--- /dev/null
+++ b/bcc/longop.c
@@ -0,0 +1,169 @@
+/* longop.c - software operations on longs for bcc */
+
+/* Copyright (C) 1992 Bruce Evans */
+
+#include "const.h"
+#include "types.h"
+#include "byteord.h"
+#include "gencode.h"
+#include "reg.h"
+#include "scan.h"
+#include "type.h"
+
+/*-----------------------------------------------------------------------------
+ longop(operation code, source leaf, target leaf)
+ handles all binary operations on longs
+ source and target must already have been converted to long,
+ (except source is int for shifts) and not more than singly indirect
+ hence they must be direct (in an index reg paired with DREG),
+ or singly indirect (local, global, or from an index reg)
+-----------------------------------------------------------------------------*/
+
+PUBLIC void longop(op, source, target)
+op_pt op;
+struct symstruct *source;
+struct symstruct *target;
+{
+ store_pt reglist;
+ store_t regmark;
+ bool_t shiftflag;
+ scalar_t scalar;
+ offset_t spmark;
+
+ pushlist(reglist = (regmark = reguse) & (OPREG | OPWORKREG));
+ reguse &= ~reglist;
+ spmark = sp;
+ shiftflag = FALSE;
+ scalar = target->type->scalar;
+ if ((op_t) op == SLOP || (op_t) op == SROP)
+ shiftflag = TRUE;
+ else
+ scalar |= source->type->scalar;
+ if ((source->indcount == 0 && !shiftflag) ||
+ source->storage & (DREG | OPREG | OPWORKREG))
+ {
+ pres2(source, target);
+ push(source);
+ }
+ if (!shiftflag)
+ address(source);
+ load(target, OPREG);
+ if (source->storage == CONSTANT && shiftflag)
+ {
+ if (scalar & UNSIGNED)
+ target->type = ultype;
+ if ((op_t) op == SLOP)
+ source->offset.offv = lslconst(source->offset.offv,
+ target->storage);
+ else
+ source->offset.offv = lsrconst(source->offset.offv,
+ target->storage, scalar & UNSIGNED);
+ if (source->offset.offv == 0)
+ goto shiftdone;
+ }
+ load(source, OPWORKREG);
+ switch ((op_t) op)
+ {
+ case ADDOP:
+ call("ladd");
+ break;
+ case ANDOP:
+ call("land");
+ break;
+ case DIVOP:
+ call("ldiv");
+ break;
+ case EOROP:
+ call("leor");
+ break;
+ case EQOP:
+ call("lcmp");
+ break;
+ case MODOP:
+ call("lmod");
+ break;
+ case MULOP:
+ call("lmul");
+ break;
+ case OROP:
+ call("lor");
+ break;
+ case SLOP:
+ call("lsl");
+ break;
+ case SROP:
+ call("lsr");
+ break;
+ case SUBOP:
+ call("lsub");
+ break;
+ }
+ if (scalar & UNSIGNED)
+ {
+ outbyte('u');
+ target->type = ultype;
+ }
+ outlongendian();
+
+shiftdone:
+ if ((reguse = regmark) & OPREG && op != EQOP)
+ load(target, getindexreg());
+ if (reglist)
+ {
+#ifdef I8088
+ if (op == EQOP)
+ changesp(spmark, FALSE);
+ else
+#endif
+ modstk(spmark);
+ poplist(reglist);
+ }
+}
+
+/*-----------------------------------------------------------------------------
+ long1op(operation code, target leaf)
+ handles all unary operations on longs except inc/dec
+ target must be not more than singly indirect
+ hence it must be direct (in an index reg paired with DREG),
+ or singly indirect (local, global, or from an index reg)
+-----------------------------------------------------------------------------*/
+
+PUBLIC void long1op(op, target)
+op_pt op;
+struct symstruct *target;
+{
+ pushlist(reguse & OPREG);
+ load(target, OPREG);
+ if (op == NOTOP)
+ call("lcom");
+ else if (op == NEGOP)
+ call("lneg");
+ else
+ call("ltst");
+ outlongendian();
+ if (reguse & OPREG)
+ {
+ if (op != EQOP)
+ load(target, getindexreg());
+ poplist(reguse & OPREG);
+ }
+}
+
+PUBLIC void outlongendian()
+{
+#ifdef MC6809
+ outbyte('_');
+#endif
+#if DYNAMIC_LONG_ORDER
+ if (long_big_endian)
+#endif
+#if DYNAMIC_LONG_ORDER || LONG_BIG_ENDIAN
+ outnbyte('b');
+#endif
+#if DYNAMIC_LONG_ORDER
+ else
+#endif
+#if DYNAMIC_LONG_ORDER || LONG_BIG_ENDIAN == 0
+ outnbyte('l');
+#endif
+}