+ while (*pold > new) {
+ emitcode("dec", "%s", pair);
+ (*pold)--;
+ }
+}
+
+static void spillPair(PAIR_ID pairId)
+{
+ _G.pairs[pairId].last_type = AOP_INVALID;
+ _G.pairs[pairId].lit = NULL;
+}
+
+static void spillCached(void)
+{
+ spillPair(PAIR_HL);
+ spillPair(PAIR_IY);
+}
+
+static bool requiresHL(asmop *aop)
+{
+ switch (aop->type) {
+ case AOP_HL:
+ case AOP_STK:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+static char *fetchLitSpecial(asmop *aop, bool negate, bool xor)
+{
+ unsigned long v;
+ value * val = aop->aopu.aop_lit;
+
+ wassert(aop->type == AOP_LIT);
+ wassert(!IS_FLOAT(val->type));
+
+ v = floatFromVal(val);
+
+ if (xor)
+ v ^= 0x8000;
+ if (negate)
+ v = -v;
+ v &= 0xFFFF;
+
+ tsprintf(buffer, "!immedword", v);
+ return gc_strdup(buffer);
+}
+
+static void fetchLitPair(PAIR_ID pairId, asmop *left, int offset)
+{
+ const char *l;
+ const char *pair = _pairs[pairId].name;
+ l = aopGetLitWordLong(left, 0, FALSE);
+ wassert(l && pair);
+
+ if (isPtr(pair)) {
+ if (pairId == PAIR_HL || pairId == PAIR_IY) {
+ if (_G.pairs[pairId].last_type == left->type) {
+ if (_G.pairs[pairId].lit && !strcmp(_G.pairs[pairId].lit, l)) {
+ if (pairId == PAIR_HL && abs(_G.pairs[pairId].offset - offset) < 3) {
+ adjustPair(pair, &_G.pairs[pairId].offset, offset);
+ return;
+ }
+ if (pairId == PAIR_IY && abs(offset)<127) {
+ return;
+ }
+ }
+ }
+ }
+ _G.pairs[pairId].last_type = left->type;
+ _G.pairs[pairId].lit = gc_strdup(l);
+ _G.pairs[pairId].offset = offset;
+ }
+ if (IS_GB && pairId == PAIR_DE && 0) {
+ if (_G.pairs[pairId].lit && !strcmp(_G.pairs[pairId].lit, l)) {
+ if (abs(_G.pairs[pairId].offset - offset) < 3) {
+ adjustPair(pair, &_G.pairs[pairId].offset, offset);
+ return;
+ }
+ }
+ _G.pairs[pairId].last_type = left->type;
+ _G.pairs[pairId].lit = gc_strdup(l);
+ _G.pairs[pairId].offset = offset;
+ }
+ /* Both a lit on the right and a true symbol on the left */
+ if (offset)
+ emit2("ld %s,!hashedstr + %u", pair, l, offset);
+ else
+ emit2("ld %s,!hashedstr", pair, l);
+}
+
+static void fetchPairLong(PAIR_ID pairId, asmop *aop, int offset)
+{
+ /* if this is remateriazable */
+ if (isLitWord(aop)) {
+ fetchLitPair(pairId, aop, offset);
+ }
+ else { /* we need to get it byte by byte */
+ if (pairId == PAIR_HL && IS_GB && requiresHL(aop)) {
+ aopGet(aop, offset, FALSE);
+ switch (aop->size) {
+ case 1:
+ emit2("ld l,!*hl");
+ emit2("ld h,!immedbyte", 0);
+ break;
+ case 2:
+ emit2("!ldahli");
+ emit2("ld h,!*hl");
+ emit2("ld l,a");
+ break;
+ default:
+ emit2("; WARNING: mlh woosed out. This code is invalid.");
+ }
+ }
+ else if (IS_Z80 && aop->type == AOP_IY) {
+ /* Instead of fetching relative to IY, just grab directly
+ from the address IY refers to */
+ char *l = aopGetLitWordLong(aop, offset, FALSE);
+ wassert(l);
+ emit2("ld %s,(%s)", _pairs[pairId].name, l);
+ }
+ else {
+ emitcode("ld", "%s,%s", _pairs[pairId].l, aopGet(aop, offset, FALSE));
+ emitcode("ld", "%s,%s", _pairs[pairId].h, aopGet(aop, offset+1, FALSE));
+ }
+ /* PENDING: check? */
+ if (pairId == PAIR_HL)
+ spillPair(PAIR_HL);
+ }
+}
+
+static void fetchPair(PAIR_ID pairId, asmop *aop)
+{
+ fetchPairLong(pairId, aop, 0);
+}
+
+static void fetchHL(asmop *aop)
+{
+ fetchPair(PAIR_HL, aop);
+}
+
+static void setupPair(PAIR_ID pairId, asmop *aop, int offset)
+{
+ assert(pairId == PAIR_HL || pairId == PAIR_IY);
+
+ switch (aop->type) {
+ case AOP_IY:
+ fetchLitPair(pairId, aop, 0);
+ break;
+ case AOP_HL:
+ fetchLitPair(pairId, aop, offset);
+ _G.pairs[pairId].offset = offset;
+ break;
+ case AOP_STK: {
+ /* Doesnt include _G.stack.pushed */
+ int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
+ if (aop->aopu.aop_stk > 0) {
+ abso += _G.stack.param_offset;
+ }
+ assert(pairId == PAIR_HL);
+ /* In some cases we can still inc or dec hl */
+ if (_G.pairs[pairId].last_type == AOP_STK && abs(_G.pairs[pairId].offset - abso) < 3) {
+ adjustPair(_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
+ }
+ else {
+ emit2("!ldahlsp", abso +_G.stack.pushed);
+ }
+ _G.pairs[pairId].offset = abso;
+ break;
+ }
+ default:
+ wassert(0);
+ }
+ _G.pairs[pairId].last_type = aop->type;
+}
+
+static void emitLabel(int key)
+{
+ emit2("!tlabeldef", key);
+ spillCached();