+ return aopGetLitWordLong(aop, offset, TRUE);
+}
+
+bool isPtr(const char *s)
+{
+ if (!strcmp(s, "hl"))
+ return TRUE;
+ if (!strcmp(s, "ix"))
+ return TRUE;
+ if (!strcmp(s, "iy"))
+ return TRUE;
+ return FALSE;
+}
+
+static void adjustPair(const char *pair, int *pold, int new)
+{
+ wassert(pair);
+
+ while (*pold < new) {
+ emitcode("inc", "%s", pair);
+ (*pold)++;
+ }
+ 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 void fetchLitPair(PAIR_ID pairId, asmop *left, int offset)
+{
+ const char *l;
+ const char *pair = _pairs[pairId].name;
+ l = aopGetLitWordLong(left, offset, 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;
+ }
+ /* Both a lit on the right and a true symbol on the left */
+ /* PENDING: for re-target */
+#if 0
+ if (offset)
+ emit2("ld %s,!hashedstr + %d", pair, l, offset);
+ else
+#endif
+ 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();