summaryrefslogtreecommitdiff
path: root/bcc/preserve.c
diff options
context:
space:
mode:
Diffstat (limited to 'bcc/preserve.c')
-rw-r--r--bcc/preserve.c216
1 files changed, 216 insertions, 0 deletions
diff --git a/bcc/preserve.c b/bcc/preserve.c
new file mode 100644
index 0000000..74b0f34
--- /dev/null
+++ b/bcc/preserve.c
@@ -0,0 +1,216 @@
+/* preserve.c - preserve opererands or registers in use for bcc */
+
+/* Copyright (C) 1992 Bruce Evans */
+
+#include "const.h"
+#include "types.h"
+#include "gencode.h"
+#include "reg.h"
+#include "type.h"
+
+/* change stack ptr without changing condition codes */
+
+PUBLIC void changesp(newsp, absflag)
+offset_t newsp;
+bool_pt absflag;
+{
+ if (newsp != sp || ((bool_t) absflag && switchnow != NULL))
+ {
+#ifdef FRAMEPOINTER
+ if (newsp != framep || (!(bool_t) absflag && switchnow != NULL))
+ {
+ outleasp();
+ if (!(bool_t) absflag && switchnow != NULL)
+ outswoffset(newsp);
+ else
+ outoffset(newsp - framep);
+ outindframereg();
+ outnl();
+ }
+ else
+ regtransfer(FRAMEREG, STACKREG);
+ sp = newsp;
+ if (framep == 0)
+ bugerror("no frame pointer");
+#else
+# ifdef I8088
+ outleasp();
+ outoffset(newsp - sp);
+ outindstackreg();
+ outnl();
+# else
+ modstk(newsp); /* this should preserve CC */
+# endif
+#endif /* FRAMEPOINTER */
+ }
+}
+
+/* load source to any while preserving target */
+
+PUBLIC void loadpres(source, target)
+struct symstruct *source;
+struct symstruct *target;
+{
+ store_t regmark;
+
+ if (target->storage & ALLDATREGS)
+ {
+ if (source->type->scalar & CHAR)
+ {
+ push(target);
+ load(source, DREG);
+ }
+ else
+ load(source, getindexreg());
+ }
+ else
+ {
+ regmark = reguse;
+ reguse |= target->storage;
+ loadany(source);
+ reguse = regmark;
+ }
+}
+
+/* change stack ptr */
+
+PUBLIC void modstk(newsp)
+offset_t newsp;
+{
+ if (newsp != sp)
+ {
+#ifdef FRAMEPOINTER
+ if (newsp != framep || framep == 0 || switchnow != NULL)
+ addconst(newsp - sp, STACKREG);
+ else
+ regtransfer(FRAMEREG, STACKREG);
+#else
+# ifdef I8088
+ addconst(newsp - sp, STACKREG);
+# else
+ outleasp();
+ outoffset(newsp - sp);
+ outncspregname();
+# endif
+#endif
+ sp = newsp;
+ }
+}
+
+/* preserve target without changing source */
+
+PUBLIC void pres2(source, target)
+struct symstruct *source;
+struct symstruct *target;
+{
+ if (target->storage & allregs)
+ {
+ if (target->storage & (allregs - allindregs) /* XXX */ ||
+ (target->indcount == 0 &&
+ target->type->scalar & (DLONG | RSCALAR)))
+ push(target); /* XXX - perhaps not float */
+ else if (((target->storage | reguse) & allindregs) == allindregs)
+ {
+ loadpres(target, source);
+ push(target);
+ }
+ else
+ reguse |= target->storage;
+ }
+}
+
+/* preserve source */
+
+PUBLIC void preserve(source)
+struct symstruct *source;
+{
+ if (source->storage & allregs)
+ {
+ if (source->storage & (allregs - allindregs) /* XXX */ ||
+ ((source->storage | reguse) & allindregs) == allindregs)
+ push(source);
+ else
+ reguse |= source->storage;
+ }
+}
+
+/* preserve lvalue target without changing source or target */
+
+PUBLIC store_pt preslval(source, target)
+struct symstruct *source;
+struct symstruct *target;
+{
+ store_pt regpushed;
+
+ if (target->indcount == 0)
+ reguse &= ~target->storage;
+ else
+ reguse = (target->storage | reguse) & allindregs;
+ if (!((source->type->scalar | target->type->scalar) & (DLONG | RSCALAR))
+ || reguse != allindregs)
+ return 0; /* XXX - perhaps not float */
+ reguse = source->storage | target->storage; /* free one other than s/t */
+ pushreg(regpushed = getindexreg());
+ reguse = ~(store_t) regpushed & allindregs;
+ return regpushed;
+}
+
+PUBLIC void recovlist(reglist)
+store_pt reglist;
+{
+ poplist(reglist);
+ reguse |= (store_t) reglist;
+}
+
+#ifdef I8088
+PRIVATE smalin_t regoffset[] = {0, 0, 0, 1, 2, 3, 0, 0, 0, 4, 5};
+ /* CONSTANT, BREG, ax = DREG, bx = INDREG0, si = INDREG1, di = INDREG2 */
+ /* LOCAL, GLOBAL, STACKREG, cx = DATREG1, dx = DATREG2 */
+#endif
+#ifdef MC6809
+PRIVATE smalin_t regoffset[] = {0, 0, 0, 1, 3, 2};
+ /* CONSTANT, BREG, DREG, XREG = INDREG0, UREG = INDREG1, YREG = INDREG2 */
+#endif
+
+PUBLIC void savereturn(savelist, saveoffset)
+store_pt savelist;
+offset_t saveoffset;
+{
+ store_t reg;
+ smalin_t *regoffptr;
+ offset_t spoffset;
+
+ if (savelist == 0)
+ return;
+#ifdef MC6809 /* must check this */
+ if (savelist == XREG || savelist == INDREG1)
+ saveoffset -= accregsize; /* patch for DREG/YREG not saved */
+#endif
+ for (reg = 1, regoffptr = regoffset; reg != 0; ++regoffptr, reg <<= 1)
+ if (reg & savelist)
+ {
+ outstore();
+ spoffset = saveoffset + *regoffptr * maxregsize;
+#ifdef I8088
+# ifdef FRAMEPOINTER
+ if (switchnow != NULL)
+ outswoffset(spoffset);
+ else
+ outoffset(spoffset - framep);
+ outindframereg();
+# else
+ outoffset(spoffset - sp);
+ outindstackreg();
+# endif
+ outncregname(reg);
+#endif
+#ifdef MC6809
+ if (reg == YREG)
+ bumplc();
+ outregname(reg);
+ outtab();
+ outoffset(spoffset - sp);
+ outncspregname();
+#endif
+ }
+}