1 /*-------------------------------------------------------------------------
2 gen.c - Z80 specific code generator.
4 Michael Hope <michaelh@juju.net.nz> 2000
5 Based on the mcs51 generator -
6 Sandeep Dutta . sandeep.dutta@usa.net (1998)
7 and - Jean-Louis VERN.jlvern@writeme.com (1999)
9 This program is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 2, or (at your option) any
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 In other words, you are welcome to use, share and improve this program.
25 You are forbidden to forbid anyone else to use, share and improve
26 what you give them. Help stamp out software-hoarding!
28 -------------------------------------------------------------------------*/
31 Benchmarks on dhry.c 2.1 with 32766 loops and a 10ms clock:
33 Base with asm strcpy / strcmp / memcpy: 23198 141 1A14
34 Improved WORD push 22784 144 19AE
35 With label1 on 22694 144 197E
36 With label2 on 22743 144 198A
37 With label3 on 22776 144 1999
38 With label4 on 22776 144 1999
39 With all 'label' on 22661 144 196F
40 With loopInvariant on 20919 156 19AB
41 With loopInduction on Breaks 198B
42 With all working on 20796 158 196C
43 Slightly better genCmp(signed) 20597 159 195B
44 Better reg packing, first peephole 20038 163 1873
45 With assign packing 19281 165 1849
47 With reg params for mul and div 16234 202 162D
49 1. Starting again at 3 Aug 01 34965 93 219C
51 Includes long mul/div in code
52 2. Optimised memcpy for acc use 32102 102 226B
53 3. Optimised strcpy for acc use 27819 117 2237
54 3a Optimised memcpy fun
55 4. Optimised strcmp fun 21999 149 2294
56 5. Optimised strcmp further 21660 151 228C
57 6. Optimised memcpy by unroling 20885 157 2201
58 7. After turning loop induction on 19862 165 236D
59 8. Same as 7 but with more info
60 9. With asm optimised strings 17030 192 2223
62 10 and below are with asm strings off.
64 10 Mucho optimisations 13562 201 1FCC
66 Apparent advantage of turning on regparams:
68 Decent case is push of a constant
69 - ld hl,#n; push hl: (10+11)*nargs
70 2. Cost of pull from stack
71 Using asm with ld hl, etc
72 - ld hl,#2; add hl,sp; (ld bc,(hl); hl+=2)*nargs
74 3. Cost of fixing stack
78 So cost is (10+11+7+6+7+10)*nargs+10+11
80 = 123 for mul, div, strcmp, strcpy
81 Saving of (98298+32766+32766+32766)*123 = 24181308
82 At 192 d/s for 682411768t, speed up to 199. Hmm.
90 #if defined(__BORLANDC__) || defined(_MSC_VER)
91 #define STRCASECMP stricmp
93 #define STRCASECMP strcasecmp
97 #include "SDCCglobl.h"
98 #include "SDCCpeeph.h"
100 #include "SDCCglue.h"
101 #include "newalloc.h"
103 /* This is the down and dirty file with all kinds of kludgy & hacky
104 stuff. This is what it is all about CODE GENERATION for a specific MCU.
105 Some of the routines may be reusable, will have to see */
107 /* Z80 calling convention description.
108 Parameters are passed right to left. As the stack grows downwards,
109 the parameters are arranged in left to right in memory.
110 Parameters may be passed in the HL and DE registers with one
112 PENDING: What if the parameter is a long?
113 Everything is caller saves. i.e. the caller must save any registers
114 that it wants to preserve over the call.
115 GB: The return value is returned in DEHL. DE is normally used as a
116 working register pair. Caller saves allows it to be used for a
118 va args functions do not use register parameters. All arguments
119 are passed on the stack.
120 IX is used as an index register to the top of the local variable
121 area. ix-0 is the top most local variable.
126 /* Set to enable debugging trace statements in the output assembly code. */
130 static char *_z80_return[] =
131 {"l", "h", "e", "d"};
132 static char *_gbz80_return[] =
133 {"e", "d", "l", "h"};
134 static char *_fReceive[] =
135 { "c", "b", "e", "d" };
137 static char **_fReturn;
140 extern FILE *codeOutFile;
148 /** Enum covering all the possible register pairs.
167 } _pairs[NUM_PAIRS] = {
168 { "??1", "?2", "?3" },
173 { "iy", "iyl", "iyh" },
174 { "ix", "ixl", "ixh" }
178 #define ACC_NAME _pairs[PAIR_AF].h
188 /** Code generator persistent data.
192 /** Used to optimised setting up of a pair by remebering what it
193 contains and adjusting instead of reloading where possible.
221 const char *lastFunctionName;
227 /** TRUE if the registers have already been saved. */
245 static const char *aopGet (asmop * aop, int offset, bool bit16);
247 static const char *aopNames[] = {
267 isLastUse (iCode *ic, operand *op)
269 bitVect *uses = bitVectCopy (OP_USES (op));
271 while (!bitVectIsZero (uses))
273 if (bitVectFirstBit (uses) == ic->key)
275 if (bitVectnBitsOn (uses) == 1)
284 bitVectUnSetBit (uses, bitVectFirstBit (uses));
304 _getTempPairName(void)
306 return _pairs[_getTempPairId()].name;
310 isPairInUse (PAIR_ID id, iCode *ic)
314 return bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
316 else if (id == PAIR_BC)
318 return bitVectBitValue (ic->rMask, B_IDX) || bitVectBitValue(ic->rMask, C_IDX);
322 wassertl (0, "Only implemented for DE and BC");
328 isPairInUseNotInRet(PAIR_ID id, iCode *ic)
332 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
336 return bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
340 wassertl (0, "Only implemented for DE");
346 getFreePairId (iCode *ic)
348 if (!isPairInUse (PAIR_BC, ic))
352 else if (IS_Z80 && !isPairInUse (PAIR_DE, ic))
365 /* Clean up the line so that it is 'prettier' */
366 if (strchr (buf, ':'))
368 /* Is a label - cant do anything */
371 /* Change the first (and probably only) ' ' to a tab so
386 _newLineNode (char *line)
390 pl = traceAlloc(&_G.lines.trace, Safe_alloc ( sizeof (lineNode)));
391 pl->line = traceAlloc(&_G.lines.trace, Safe_strdup (line));
397 _vemit2 (const char *szFormat, va_list ap)
401 tvsprintf (buffer, sizeof(buffer), szFormat, ap);
404 _G.lines.current = (_G.lines.current ?
405 connectLine (_G.lines.current, _newLineNode (buffer)) :
406 (_G.lines.head = _newLineNode (buffer)));
408 _G.lines.current->isInline = _G.lines.isInline;
412 emit2 (const char *szFormat,...)
416 va_start (ap, szFormat);
418 _vemit2 (szFormat, ap);
424 emitDebug (const char *szFormat,...)
430 va_start (ap, szFormat);
432 _vemit2 (szFormat, ap);
438 /*-----------------------------------------------------------------*/
439 /* emit2 - writes the code into a file : for now it is simple */
440 /*-----------------------------------------------------------------*/
442 _emit2 (const char *inst, const char *fmt,...)
445 char lb[INITIAL_INLINEASM];
452 sprintf (lb, "%s\t", inst);
453 vsprintf (lb + (strlen (lb)), fmt, ap);
456 vsprintf (lb, fmt, ap);
458 while (isspace (*lbp))
463 _G.lines.current = (_G.lines.current ?
464 connectLine (_G.lines.current, _newLineNode (lb)) :
465 (_G.lines.head = _newLineNode (lb)));
467 _G.lines.current->isInline = _G.lines.isInline;
472 _emitMove(const char *to, const char *from)
474 if (STRCASECMP(to, from) != 0)
476 emit2("ld %s,%s", to, from);
481 // Could leave this to the peephole, but sometimes the peephole is inhibited.
486 aopDump(const char *plabel, asmop *aop)
488 emitDebug("; Dump of %s: type %s size %u", plabel, aopNames[aop->type], aop->size);
492 emitDebug("; aop_stk %d", aop->aopu.aop_stk);
495 /* No information. */
501 _moveA(const char *moveFrom)
503 // Let the peephole optimiser take care of redundent loads
504 _emitMove(ACC_NAME, moveFrom);
514 getPairName (asmop * aop)
516 if (aop->type == AOP_REG)
518 switch (aop->aopu.aop_reg[0]->rIdx)
531 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
534 for (i = 0; i < NUM_PAIRS; i++)
536 if (strcmp(aop->aopu.aop_str[0], _pairs[i].l) == 0)
538 return _pairs[i].name;
542 wassertl (0, "Tried to get the pair name of something that isn't a pair");
547 getPairId (asmop * aop)
551 if (aop->type == AOP_REG)
553 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX) && (aop->aopu.aop_reg[1]->rIdx == B_IDX))
557 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX) && (aop->aopu.aop_reg[1]->rIdx == D_IDX))
561 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX) && (aop->aopu.aop_reg[1]->rIdx == H_IDX))
566 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
569 for (i = 0; i < NUM_PAIRS; i++)
571 if (!strcmp (aop->aopu.aop_str[0], _pairs[i].l) && !strcmp (aop->aopu.aop_str[1], _pairs[i].h))
581 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
585 return (getPairId (aop) != PAIR_INVALID);
589 isPtrPair (asmop * aop)
591 PAIR_ID pairId = getPairId (aop);
604 spillPair (PAIR_ID pairId)
606 _G.pairs[pairId].last_type = AOP_INVALID;
607 _G.pairs[pairId].base = NULL;
610 /** Push a register pair onto the stack */
612 genPairPush (asmop * aop)
614 emit2 ("push %s", getPairName (aop));
618 _push (PAIR_ID pairId)
620 emit2 ("push %s", _pairs[pairId].name);
621 _G.stack.pushed += 2;
625 _pop (PAIR_ID pairId)
627 emit2 ("pop %s", _pairs[pairId].name);
628 _G.stack.pushed -= 2;
632 /*-----------------------------------------------------------------*/
633 /* newAsmop - creates a new asmOp */
634 /*-----------------------------------------------------------------*/
636 newAsmop (short type)
640 aop = traceAlloc(&_G.trace.aops, Safe_alloc (sizeof (asmop)));
645 /*-----------------------------------------------------------------*/
646 /* aopForSym - for a true symbol */
647 /*-----------------------------------------------------------------*/
649 aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
656 wassert (sym->etype);
658 space = SPEC_OCLS (sym->etype);
660 /* if already has one */
666 /* Assign depending on the storage class */
667 if (sym->onStack || sym->iaccess)
669 /* The pointer that is used depends on how big the offset is.
670 Normally everything is AOP_STK, but for offsets of < -128 or
671 > 127 on the Z80 an extended stack pointer is used.
673 if (IS_Z80 && (options.ommitFramePtr || sym->stack < INT8MIN || sym->stack > (int)(INT8MAX-getSize (sym->type))))
675 emitDebug ("; AOP_EXSTK for %s", sym->rname);
676 sym->aop = aop = newAsmop (AOP_EXSTK);
680 emitDebug ("; AOP_STK for %s", sym->rname);
681 sym->aop = aop = newAsmop (AOP_STK);
684 aop->size = getSize (sym->type);
685 aop->aopu.aop_stk = sym->stack;
689 /* special case for a function */
690 if (IS_FUNC (sym->type))
692 sym->aop = aop = newAsmop (AOP_IMMD);
693 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup (sym->rname));
700 /* if it is in direct space */
701 if (IN_REGSP (space) && !requires_a)
703 sym->aop = aop = newAsmop (AOP_SFR);
704 aop->aopu.aop_dir = sym->rname;
705 aop->size = getSize (sym->type);
706 emitDebug ("; AOP_SFR for %s", sym->rname);
711 /* only remaining is far space */
712 /* in which case DPTR gets the address */
715 emitDebug ("; AOP_HL for %s", sym->rname);
716 sym->aop = aop = newAsmop (AOP_HL);
720 sym->aop = aop = newAsmop (AOP_IY);
722 aop->size = getSize (sym->type);
723 aop->aopu.aop_dir = sym->rname;
725 /* if it is in code space */
726 if (IN_CODESPACE (space))
732 /*-----------------------------------------------------------------*/
733 /* aopForRemat - rematerialzes an object */
734 /*-----------------------------------------------------------------*/
736 aopForRemat (symbol * sym)
739 iCode *ic = sym->rematiCode;
740 asmop *aop = newAsmop (AOP_IMMD);
744 /* if plus or minus print the right hand side */
745 if (ic->op == '+' || ic->op == '-')
747 /* PENDING: for re-target */
748 sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
751 ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
754 /* we reached the end */
755 sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
759 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
763 /*-----------------------------------------------------------------*/
764 /* regsInCommon - two operands have some registers in common */
765 /*-----------------------------------------------------------------*/
767 regsInCommon (operand * op1, operand * op2)
772 /* if they have registers in common */
773 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
776 sym1 = OP_SYMBOL (op1);
777 sym2 = OP_SYMBOL (op2);
779 if (sym1->nRegs == 0 || sym2->nRegs == 0)
782 for (i = 0; i < sym1->nRegs; i++)
788 for (j = 0; j < sym2->nRegs; j++)
793 if (sym2->regs[j] == sym1->regs[i])
801 /*-----------------------------------------------------------------*/
802 /* operandsEqu - equivalent */
803 /*-----------------------------------------------------------------*/
805 operandsEqu (operand * op1, operand * op2)
809 /* if they not symbols */
810 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
813 sym1 = OP_SYMBOL (op1);
814 sym2 = OP_SYMBOL (op2);
816 /* if both are itemps & one is spilt
817 and the other is not then false */
818 if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
819 sym1->isspilt != sym2->isspilt)
822 /* if they are the same */
826 if (strcmp (sym1->rname, sym2->rname) == 0)
830 /* if left is a tmp & right is not */
831 if (IS_ITEMP (op1) &&
834 (sym1->usl.spillLoc == sym2))
837 if (IS_ITEMP (op2) &&
841 (sym2->usl.spillLoc == sym1))
847 /*-----------------------------------------------------------------*/
848 /* sameRegs - two asmops have the same registers */
849 /*-----------------------------------------------------------------*/
851 sameRegs (asmop * aop1, asmop * aop2)
855 if (aop1->type == AOP_SFR ||
856 aop2->type == AOP_SFR)
862 if (aop1->type != AOP_REG ||
863 aop2->type != AOP_REG)
866 if (aop1->size != aop2->size)
869 for (i = 0; i < aop1->size; i++)
870 if (aop1->aopu.aop_reg[i] !=
871 aop2->aopu.aop_reg[i])
877 /*-----------------------------------------------------------------*/
878 /* aopOp - allocates an asmop for an operand : */
879 /*-----------------------------------------------------------------*/
881 aopOp (operand * op, iCode * ic, bool result, bool requires_a)
890 /* if this a literal */
891 if (IS_OP_LITERAL (op))
893 op->aop = aop = newAsmop (AOP_LIT);
894 aop->aopu.aop_lit = op->operand.valOperand;
895 aop->size = getSize (operandType (op));
899 /* if already has a asmop then continue */
905 /* if the underlying symbol has a aop */
906 if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
908 op->aop = OP_SYMBOL (op)->aop;
912 /* if this is a true symbol */
913 if (IS_TRUE_SYMOP (op))
915 op->aop = aopForSym (ic, OP_SYMBOL (op), result, requires_a);
919 /* this is a temporary : this has
925 e) can be a return use only */
927 sym = OP_SYMBOL (op);
929 /* if the type is a conditional */
930 if (sym->regType == REG_CND)
932 aop = op->aop = sym->aop = newAsmop (AOP_CRY);
937 /* if it is spilt then two situations
939 b) has a spill location */
940 if (sym->isspilt || sym->nRegs == 0)
942 /* rematerialize it NOW */
945 sym->aop = op->aop = aop =
947 aop->size = getSize (sym->type);
954 aop = op->aop = sym->aop = newAsmop (AOP_STR);
955 aop->size = getSize (sym->type);
956 for (i = 0; i < 4; i++)
957 aop->aopu.aop_str[i] = _fReturn[i];
963 if (sym->accuse == ACCUSE_A)
965 aop = op->aop = sym->aop = newAsmop (AOP_ACC);
966 aop->size = getSize (sym->type);
967 wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
969 aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
971 else if (sym->accuse == ACCUSE_SCRATCH)
973 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
974 aop->size = getSize (sym->type);
975 wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
976 aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
977 aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
979 else if (sym->accuse == ACCUSE_IY)
981 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
982 aop->size = getSize (sym->type);
983 wassertl(aop->size <= 2, "Internal error: Caching in IY, but too big to fit in IY");
984 aop->aopu.aop_str[0] = _pairs[PAIR_IY].l;
985 aop->aopu.aop_str[1] = _pairs[PAIR_IY].h;
989 wassertl (0, "Marked as being allocated into A or HL but is actually in neither");
994 /* else spill location */
995 if (sym->usl.spillLoc && getSize(sym->type) != getSize(sym->usl.spillLoc->type)) {
996 /* force a new aop if sizes differ */
997 sym->usl.spillLoc->aop = NULL;
999 sym->aop = op->aop = aop =
1000 aopForSym (ic, sym->usl.spillLoc, result, requires_a);
1001 wassertl (aop->size >= getSize (sym->type), "Operand doesn't fit in the spill location");
1002 aop->size = getSize (sym->type);
1006 /* must be in a register */
1007 sym->aop = op->aop = aop = newAsmop (AOP_REG);
1008 aop->size = sym->nRegs;
1009 for (i = 0; i < sym->nRegs; i++)
1010 aop->aopu.aop_reg[i] = sym->regs[i];
1013 /*-----------------------------------------------------------------*/
1014 /* freeAsmop - free up the asmop given to an operand */
1015 /*----------------------------------------------------------------*/
1017 freeAsmop (operand * op, asmop * aaop, iCode * ic)
1034 if (aop->type == AOP_PAIRPTR && IS_Z80 && aop->aopu.aop_pairId == PAIR_DE)
1036 _pop (aop->aopu.aop_pairId);
1039 if (getPairId (aop) == PAIR_HL)
1041 spillPair (PAIR_HL);
1045 /* all other cases just dealloc */
1051 OP_SYMBOL (op)->aop = NULL;
1052 /* if the symbol has a spill */
1054 SPIL_LOC (op)->aop = NULL;
1061 isLitWord (asmop * aop)
1063 /* if (aop->size != 2)
1076 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
1078 /* depending on type */
1084 /* PENDING: for re-target */
1087 tsprintf (buffer, sizeof(buffer),
1088 "!hashedstr + %d", aop->aopu.aop_immd, offset);
1090 else if (offset == 0)
1092 tsprintf (buffer, sizeof(buffer),
1093 "%s", aop->aopu.aop_immd);
1097 tsprintf (buffer, sizeof(buffer),
1098 "%s + %d", aop->aopu.aop_immd, offset);
1100 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1104 value *val = aop->aopu.aop_lit;
1105 /* if it is a float then it gets tricky */
1106 /* otherwise it is fairly simple */
1107 if (!IS_FLOAT (val->type))
1109 unsigned long v = (unsigned long) floatFromVal (val);
1115 else if (offset == 0)
1121 wassertl(0, "Encountered an invalid offset while fetching a literal");
1125 tsprintf (buffer, sizeof(buffer), "!immedword", v);
1127 tsprintf (buffer, sizeof(buffer), "!constword", v);
1129 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1140 /* it is type float */
1141 fl.f = (float) floatFromVal (val);
1143 #ifdef WORDS_BIGENDIAN
1144 i = fl.c[3-offset] | (fl.c[3-offset-1]<<8);
1146 i = fl.c[offset] | (fl.c[offset+1]<<8);
1149 tsprintf (buffer, sizeof(buffer), "!immedword", i);
1151 tsprintf (buffer, sizeof(buffer), "!constword", i);
1153 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1162 aopGetWord (asmop * aop, int offset)
1164 return aopGetLitWordLong (aop, offset, TRUE);
1168 isPtr (const char *s)
1170 if (!strcmp (s, "hl"))
1172 if (!strcmp (s, "ix"))
1174 if (!strcmp (s, "iy"))
1180 adjustPair (const char *pair, int *pold, int new)
1186 emit2 ("inc %s", pair);
1191 emit2 ("dec %s", pair);
1199 spillPair (PAIR_HL);
1200 spillPair (PAIR_IY);
1204 requiresHL (asmop * aop)
1220 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1222 const char *l, *base;
1223 const char *pair = _pairs[pairId].name;
1224 l = aopGetLitWordLong (left, offset, FALSE);
1225 base = aopGetLitWordLong (left, 0, FALSE);
1226 wassert (l && pair && base);
1230 if (pairId == PAIR_HL || pairId == PAIR_IY)
1232 if (_G.pairs[pairId].last_type == left->type)
1234 if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1236 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1238 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1241 if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
1248 _G.pairs[pairId].last_type = left->type;
1249 _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1250 _G.pairs[pairId].offset = offset;
1252 /* Both a lit on the right and a true symbol on the left */
1253 emit2 ("ld %s,!hashedstr", pair, l);
1257 makeFreePairId (iCode *ic, bool *pisUsed)
1263 if (!bitVectBitValue (ic->rMask, B_IDX) && !bitVectBitValue(ic->rMask, C_IDX))
1267 else if (IS_Z80 && !bitVectBitValue (ic->rMask, D_IDX) && !bitVectBitValue(ic->rMask, E_IDX))
1285 fetchPairLong (PAIR_ID pairId, asmop * aop, iCode *ic, int offset)
1287 /* if this is remateriazable */
1288 if (isLitWord (aop)) {
1289 fetchLitPair (pairId, aop, offset);
1293 if (getPairId (aop) == pairId)
1297 /* we need to get it byte by byte */
1298 else if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1299 aopGet (aop, offset, FALSE);
1300 switch (aop->size - offset) {
1302 emit2 ("ld l,!*hl");
1303 emit2 ("ld h,!immedbyte", 0);
1306 // PENDING: Requires that you are only fetching two bytes.
1309 emit2 ("ld h,!*hl");
1313 wassertl (0, "Attempted to fetch too much data into HL");
1317 else if (IS_Z80 && aop->type == AOP_IY) {
1318 /* Instead of fetching relative to IY, just grab directly
1319 from the address IY refers to */
1320 char *l = aopGetLitWordLong (aop, offset, FALSE);
1322 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1324 if (aop->size < 2) {
1325 emit2("ld %s,!zero", _pairs[pairId].h);
1328 else if (pairId == PAIR_IY)
1332 emit2 ("push %s", _pairs[getPairId(aop)].name);
1338 PAIR_ID id = makeFreePairId (ic, &isUsed);
1341 /* Can't load into parts, so load into HL then exchange. */
1342 emit2 ("ld %s,%s", _pairs[id].l, aopGet (aop, offset, FALSE));
1343 emit2 ("ld %s,%s", _pairs[id].h, aopGet (aop, offset + 1, FALSE));
1344 emit2 ("push %s", _pairs[id].name);
1352 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1353 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1355 /* PENDING: check? */
1356 if (pairId == PAIR_HL)
1357 spillPair (PAIR_HL);
1362 fetchPair (PAIR_ID pairId, asmop * aop)
1364 fetchPairLong (pairId, aop, NULL, 0);
1368 fetchHL (asmop * aop)
1370 fetchPair (PAIR_HL, aop);
1374 setupPairFromSP (PAIR_ID id, int offset)
1376 wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
1378 if (offset < INT8MIN || offset > INT8MAX)
1380 emit2 ("ld hl,!immedword", offset);
1381 emit2 ("add hl,sp");
1385 emit2 ("!ldahlsp", offset);
1390 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1395 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
1396 fetchLitPair (pairId, aop, 0);
1400 wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
1402 fetchLitPair (pairId, aop, offset);
1403 _G.pairs[pairId].offset = offset;
1407 wassertl (IS_Z80, "Only the Z80 has an extended stack");
1408 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
1411 int offset = aop->aopu.aop_stk + _G.stack.offset;
1413 if (_G.pairs[pairId].last_type == aop->type &&
1414 _G.pairs[pairId].offset == offset)
1420 /* PENDING: Do this better. */
1421 sprintf (buffer, "%d", offset + _G.stack.pushed);
1422 emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
1423 emit2 ("add %s,sp", _pairs[pairId].name);
1424 _G.pairs[pairId].last_type = aop->type;
1425 _G.pairs[pairId].offset = offset;
1432 /* Doesnt include _G.stack.pushed */
1433 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1435 if (aop->aopu.aop_stk > 0)
1437 abso += _G.stack.param_offset;
1439 assert (pairId == PAIR_HL);
1440 /* In some cases we can still inc or dec hl */
1441 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1443 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1447 setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
1449 _G.pairs[pairId].offset = abso;
1454 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
1460 _G.pairs[pairId].last_type = aop->type;
1466 emit2 ("!tlabeldef", key);
1470 /*-----------------------------------------------------------------*/
1471 /* aopGet - for fetching value of the aop */
1472 /*-----------------------------------------------------------------*/
1474 aopGet (asmop * aop, int offset, bool bit16)
1476 // char *s = buffer;
1478 /* offset is greater than size then zero */
1479 /* PENDING: this seems a bit screwed in some pointer cases. */
1480 if (offset > (aop->size - 1) &&
1481 aop->type != AOP_LIT)
1483 tsprintf (buffer, sizeof(buffer), "!zero");
1484 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1487 /* depending on type */
1491 /* PENDING: re-target */
1493 tsprintf (buffer, sizeof(buffer), "!immedwords", aop->aopu.aop_immd);
1498 tsprintf (buffer, sizeof(buffer), "!bankimmeds", aop->aopu.aop_immd);
1501 tsprintf (buffer, sizeof(buffer), "!msbimmeds", aop->aopu.aop_immd);
1504 tsprintf (buffer, sizeof(buffer), "!lsbimmeds", aop->aopu.aop_immd);
1507 wassertl (0, "Fetching from beyond the limits of an immediate value.");
1510 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1514 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1515 SNPRINTF (buffer, sizeof(buffer), "a");
1517 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1521 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1522 SNPRINTF (buffer, sizeof(buffer), "a");
1524 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1527 return aop->aopu.aop_reg[offset]->name;
1531 setupPair (PAIR_HL, aop, offset);
1532 tsprintf (buffer, sizeof(buffer), "!*hl");
1534 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
1538 setupPair (PAIR_IY, aop, offset);
1539 tsprintf (buffer, sizeof(buffer), "!*iyx", offset);
1541 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1545 setupPair (PAIR_IY, aop, offset);
1546 tsprintf (buffer, sizeof(buffer), "!*iyx", offset, offset);
1548 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1553 setupPair (PAIR_HL, aop, offset);
1554 tsprintf (buffer, sizeof(buffer), "!*hl");
1558 if (aop->aopu.aop_stk >= 0)
1559 offset += _G.stack.param_offset;
1560 tsprintf (buffer, sizeof(buffer),
1561 "!*ixx", aop->aopu.aop_stk + offset);
1564 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1567 wassertl (0, "Tried to fetch from a bit variable");
1576 tsprintf(buffer, sizeof(buffer), "!zero");
1577 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1581 wassert (offset < 2);
1582 return aop->aopu.aop_str[offset];
1585 return aopLiteral (aop->aopu.aop_lit, offset);
1589 unsigned long v = aop->aopu.aop_simplelit;
1592 tsprintf (buffer, sizeof(buffer),
1593 "!immedbyte", (unsigned int) v & 0xff);
1595 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1599 return aop->aopu.aop_str[offset];
1602 setupPair (aop->aopu.aop_pairId, aop, offset);
1603 SNPRINTF (buffer, sizeof(buffer),
1604 "(%s)", _pairs[aop->aopu.aop_pairId].name);
1606 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1611 wassertl (0, "aopget got unsupported aop->type");
1616 isRegString (const char *s)
1618 if (!strcmp (s, "b") ||
1630 isConstant (const char *s)
1632 /* This is a bit of a hack... */
1633 return (*s == '#' || *s == '$');
1637 canAssignToPtr (const char *s)
1639 if (isRegString (s))
1646 /*-----------------------------------------------------------------*/
1647 /* aopPut - puts a string for a aop */
1648 /*-----------------------------------------------------------------*/
1650 aopPut (asmop * aop, const char *s, int offset)
1654 if (aop->size && offset > (aop->size - 1))
1656 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1657 "aopPut got offset > aop->size");
1662 tsprintf(buffer2, sizeof(buffer2), s);
1665 /* will assign value to value */
1666 /* depending on where it is ofcourse */
1672 if (strcmp (s, "a"))
1673 emit2 ("ld a,%s", s);
1674 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1679 if (strcmp (s, "a"))
1680 emit2 ("ld a,%s", s);
1681 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1685 if (!strcmp (s, "!*hl"))
1686 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1689 aop->aopu.aop_reg[offset]->name, s);
1694 if (!canAssignToPtr (s))
1696 emit2 ("ld a,%s", s);
1697 setupPair (PAIR_IY, aop, offset);
1698 emit2 ("ld !*iyx,a", offset);
1702 setupPair (PAIR_IY, aop, offset);
1703 emit2 ("ld !*iyx,%s", offset, s);
1709 /* PENDING: for re-target */
1710 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1712 emit2 ("ld a,!*hl");
1715 setupPair (PAIR_HL, aop, offset);
1717 emit2 ("ld !*hl,%s", s);
1722 if (!canAssignToPtr (s))
1724 emit2 ("ld a,%s", s);
1725 setupPair (PAIR_IY, aop, offset);
1726 emit2 ("ld !*iyx,a", offset);
1730 setupPair (PAIR_IY, aop, offset);
1731 emit2 ("ld !*iyx,%s", offset, s);
1738 /* PENDING: re-target */
1739 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1741 emit2 ("ld a,!*hl");
1744 setupPair (PAIR_HL, aop, offset);
1745 if (!canAssignToPtr (s))
1747 emit2 ("ld a,%s", s);
1748 emit2 ("ld !*hl,a");
1751 emit2 ("ld !*hl,%s", s);
1755 if (aop->aopu.aop_stk >= 0)
1756 offset += _G.stack.param_offset;
1757 if (!canAssignToPtr (s))
1759 emit2 ("ld a,%s", s);
1760 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
1764 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
1770 /* if bit variable */
1771 if (!aop->aopu.aop_dir)
1773 emit2 ("ld a,!zero");
1778 /* In bit space but not in C - cant happen */
1779 wassertl (0, "Tried to write into a bit variable");
1785 if (strcmp (aop->aopu.aop_str[offset], s))
1787 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1793 if (!offset && (strcmp (s, "acc") == 0))
1797 wassertl (0, "Tried to access past the end of A");
1801 if (strcmp (aop->aopu.aop_str[offset], s))
1802 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1807 wassert (offset < 2);
1808 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1812 setupPair (aop->aopu.aop_pairId, aop, offset);
1813 emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
1817 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1818 "aopPut got unsupported aop->type");
1823 #define AOP(op) op->aop
1824 #define AOP_TYPE(op) AOP(op)->type
1825 #define AOP_SIZE(op) AOP(op)->size
1826 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
1829 commitPair (asmop * aop, PAIR_ID id)
1831 /* PENDING: Verify this. */
1832 if (id == PAIR_HL && requiresHL (aop) && IS_GB)
1836 aopPut (aop, "a", 0);
1837 aopPut (aop, "d", 1);
1842 if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
1844 char *l = aopGetLitWordLong (aop, 0, FALSE);
1847 emit2 ("ld (%s),%s", l, _pairs[id].name);
1851 aopPut (aop, _pairs[id].l, 0);
1852 aopPut (aop, _pairs[id].h, 1);
1857 /*-----------------------------------------------------------------*/
1858 /* getDataSize - get the operand data size */
1859 /*-----------------------------------------------------------------*/
1861 getDataSize (operand * op)
1864 size = AOP_SIZE (op);
1868 wassertl (0, "Somehow got a three byte data pointer");
1873 /*-----------------------------------------------------------------*/
1874 /* movLeft2Result - move byte from left to result */
1875 /*-----------------------------------------------------------------*/
1877 movLeft2Result (operand * left, int offl,
1878 operand * result, int offr, int sign)
1882 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
1884 l = aopGet (AOP (left), offl, FALSE);
1888 aopPut (AOP (result), l, offr);
1892 if (getDataSize (left) == offl + 1)
1894 emit2 ("ld a,%s", l);
1895 aopPut (AOP (result), "a", offr);
1902 movLeft2ResultLong (operand * left, int offl,
1903 operand * result, int offr, int sign,
1908 movLeft2Result (left, offl, result, offr, sign);
1912 wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
1913 wassertl (size == 2, "Only implemented for two bytes or one");
1915 if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
1917 emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
1918 emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
1920 spillPair (PAIR_HL);
1922 else if ( getPairId ( AOP (result)) == PAIR_IY)
1924 PAIR_ID id = getPairId (AOP (left));
1925 if (id != PAIR_INVALID)
1927 emit2("push %s", _pairs[id].name);
1938 movLeft2Result (left, offl, result, offr, sign);
1939 movLeft2Result (left, offl+1, result, offr+1, sign);
1944 /** Put Acc into a register set
1947 outAcc (operand * result)
1950 size = getDataSize (result);
1953 aopPut (AOP (result), "a", 0);
1956 /* unsigned or positive */
1959 aopPut (AOP (result), "!zero", offset++);
1964 /** Take the value in carry and put it into a register
1967 outBitCLong (operand * result, bool swap_sense)
1969 /* if the result is bit */
1970 if (AOP_TYPE (result) == AOP_CRY)
1972 wassertl (0, "Tried to write carry to a bit");
1976 emit2 ("ld a,!zero");
1979 emit2 ("xor a,!immedbyte", 1);
1985 outBitC (operand * result)
1987 outBitCLong (result, FALSE);
1990 /*-----------------------------------------------------------------*/
1991 /* toBoolean - emit code for orl a,operator(sizeop) */
1992 /*-----------------------------------------------------------------*/
1994 _toBoolean (operand * oper)
1996 int size = AOP_SIZE (oper);
2000 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
2003 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
2007 if (AOP (oper)->type != AOP_ACC)
2010 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
2015 /*-----------------------------------------------------------------*/
2016 /* genNotFloat - generates not for float operations */
2017 /*-----------------------------------------------------------------*/
2019 genNotFloat (operand * op, operand * res)
2024 emitDebug ("; genNotFloat");
2026 /* we will put 127 in the first byte of
2028 aopPut (AOP (res), "!immedbyte", 0x7F);
2029 size = AOP_SIZE (op) - 1;
2032 _moveA (aopGet (op->aop, offset++, FALSE));
2036 emit2 ("or a,%s", aopGet (op->aop, offset++, FALSE));
2039 tlbl = newiTempLabel (NULL);
2040 aopPut (res->aop, "!one", 1);
2041 emit2 ("!shortjp z !tlabel", tlbl->key + 100);
2042 aopPut (res->aop, "!zero", 1);
2044 emitLabel(tlbl->key + 100);
2046 size = res->aop->size - 2;
2048 /* put zeros in the rest */
2050 aopPut (res->aop, "!zero", offset++);
2053 /*-----------------------------------------------------------------*/
2054 /* genNot - generate code for ! operation */
2055 /*-----------------------------------------------------------------*/
2059 sym_link *optype = operandType (IC_LEFT (ic));
2061 /* assign asmOps to operand & result */
2062 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
2063 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2065 /* if in bit space then a special case */
2066 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2068 wassertl (0, "Tried to negate a bit");
2071 /* if type float then do float */
2072 if (IS_FLOAT (optype))
2074 genNotFloat (IC_LEFT (ic), IC_RESULT (ic));
2078 _toBoolean (IC_LEFT (ic));
2083 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
2084 emit2 ("sub a,!one");
2085 outBitC (IC_RESULT (ic));
2088 /* release the aops */
2089 freeAsmop (IC_LEFT (ic), NULL, ic);
2090 freeAsmop (IC_RESULT (ic), NULL, ic);
2093 /*-----------------------------------------------------------------*/
2094 /* genCpl - generate code for complement */
2095 /*-----------------------------------------------------------------*/
2103 /* assign asmOps to operand & result */
2104 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2105 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2107 /* if both are in bit space then
2109 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2110 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2112 wassertl (0, "Left and the result are in bit space");
2115 size = AOP_SIZE (IC_RESULT (ic));
2118 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2121 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2124 /* release the aops */
2125 freeAsmop (IC_LEFT (ic), NULL, ic);
2126 freeAsmop (IC_RESULT (ic), NULL, ic);
2130 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
2137 store de into result
2142 store de into result
2144 const char *first = isAdd ? "add" : "sub";
2145 const char *later = isAdd ? "adc" : "sbc";
2147 wassertl (IS_GB, "Code is only relevent to the gbz80");
2148 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
2150 fetchPair (PAIR_DE, left);
2153 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
2156 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2159 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2160 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2162 fetchPairLong (PAIR_DE, left, NULL, MSB24);
2163 aopGet (right, MSB24, FALSE);
2167 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2170 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2172 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2173 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2177 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2179 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2182 /*-----------------------------------------------------------------*/
2183 /* genUminusFloat - unary minus for floating points */
2184 /*-----------------------------------------------------------------*/
2186 genUminusFloat (operand * op, operand * result)
2188 int size, offset = 0;
2190 emitDebug("; genUminusFloat");
2192 /* for this we just need to flip the
2193 first it then copy the rest in place */
2194 size = AOP_SIZE (op) - 1;
2196 _moveA(aopGet (AOP (op), MSB32, FALSE));
2198 emit2("xor a,!immedbyte", 0x80);
2199 aopPut (AOP (result), "a", MSB32);
2203 aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2208 /*-----------------------------------------------------------------*/
2209 /* genUminus - unary minus code generation */
2210 /*-----------------------------------------------------------------*/
2212 genUminus (iCode * ic)
2215 sym_link *optype, *rtype;
2218 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2219 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2221 /* if both in bit space then special
2223 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2224 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2226 wassertl (0, "Left and right are in bit space");
2230 optype = operandType (IC_LEFT (ic));
2231 rtype = operandType (IC_RESULT (ic));
2233 /* if float then do float stuff */
2234 if (IS_FLOAT (optype))
2236 genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2240 /* otherwise subtract from zero */
2241 size = AOP_SIZE (IC_LEFT (ic));
2243 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2245 /* Create a new asmop with value zero */
2246 asmop *azero = newAsmop (AOP_SIMPLELIT);
2247 azero->aopu.aop_simplelit = 0;
2249 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2257 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2258 emit2 ("ld a,!zero");
2259 emit2 ("sbc a,%s", l);
2260 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2263 /* if any remaining bytes in the result */
2264 /* we just need to propagate the sign */
2265 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2270 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2274 /* release the aops */
2275 freeAsmop (IC_LEFT (ic), NULL, ic);
2276 freeAsmop (IC_RESULT (ic), NULL, ic);
2279 /*-----------------------------------------------------------------*/
2280 /* assignResultValue - */
2281 /*-----------------------------------------------------------------*/
2283 assignResultValue (operand * oper)
2285 int size = AOP_SIZE (oper);
2288 wassertl (size <= 4, "Got a result that is bigger than four bytes");
2289 topInA = requiresHL (AOP (oper));
2291 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2293 /* We do it the hard way here. */
2295 aopPut (AOP (oper), _fReturn[0], 0);
2296 aopPut (AOP (oper), _fReturn[1], 1);
2298 aopPut (AOP (oper), _fReturn[0], 2);
2299 aopPut (AOP (oper), _fReturn[1], 3);
2305 aopPut (AOP (oper), _fReturn[size], size);
2310 /** Simple restore that doesn't take into account what is used in the
2314 _restoreRegsAfterCall(void)
2316 if (_G.stack.pushedDE)
2319 _G.stack.pushedDE = FALSE;
2321 if (_G.stack.pushedBC)
2324 _G.stack.pushedBC = FALSE;
2326 _G.saves.saved = FALSE;
2330 _saveRegsForCall(iCode *ic, int sendSetSize)
2333 o Stack parameters are pushed before this function enters
2334 o DE and BC may be used in this function.
2335 o HL and DE may be used to return the result.
2336 o HL and DE may be used to send variables.
2337 o DE and BC may be used to store the result value.
2338 o HL may be used in computing the sent value of DE
2339 o The iPushes for other parameters occur before any addSets
2341 Logic: (to be run inside the first iPush or if none, before sending)
2342 o Compute if DE and/or BC are in use over the call
2343 o Compute if DE is used in the send set
2344 o Compute if DE and/or BC are used to hold the result value
2345 o If (DE is used, or in the send set) and is not used in the result, push.
2346 o If BC is used and is not in the result, push
2348 o If DE is used in the send set, fetch
2349 o If HL is used in the send set, fetch
2353 if (_G.saves.saved == FALSE) {
2354 bool deInUse, bcInUse;
2356 bool bcInRet = FALSE, deInRet = FALSE;
2359 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
2361 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2362 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2364 deSending = (sendSetSize > 1);
2366 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2368 if (bcInUse && bcInRet == FALSE) {
2370 _G.stack.pushedBC = TRUE;
2372 if (deInUse && deInRet == FALSE) {
2374 _G.stack.pushedDE = TRUE;
2377 _G.saves.saved = TRUE;
2380 /* Already saved. */
2384 /*-----------------------------------------------------------------*/
2385 /* genIpush - genrate code for pushing this gets a little complex */
2386 /*-----------------------------------------------------------------*/
2388 genIpush (iCode * ic)
2390 int size, offset = 0;
2393 /* if this is not a parm push : ie. it is spill push
2394 and spill push is always done on the local stack */
2397 wassertl(0, "Encountered an unsupported spill push.");
2401 if (_G.saves.saved == FALSE) {
2402 /* Caller saves, and this is the first iPush. */
2403 /* Scan ahead until we find the function that we are pushing parameters to.
2404 Count the number of addSets on the way to figure out what registers
2405 are used in the send set.
2408 iCode *walk = ic->next;
2411 if (walk->op == SEND) {
2414 else if (walk->op == CALL || walk->op == PCALL) {
2423 _saveRegsForCall(walk, nAddSets);
2426 /* Already saved by another iPush. */
2429 /* then do the push */
2430 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2432 size = AOP_SIZE (IC_LEFT (ic));
2434 if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2436 _G.stack.pushed += 2;
2437 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2443 fetchHL (AOP (IC_LEFT (ic)));
2445 spillPair (PAIR_HL);
2446 _G.stack.pushed += 2;
2451 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
2453 spillPair (PAIR_HL);
2454 _G.stack.pushed += 2;
2455 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
2457 spillPair (PAIR_HL);
2458 _G.stack.pushed += 2;
2464 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2466 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2468 emit2 ("ld a,(%s)", l);
2472 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2473 emit2 ("ld a,%s", l);
2481 freeAsmop (IC_LEFT (ic), NULL, ic);
2484 /*-----------------------------------------------------------------*/
2485 /* genIpop - recover the registers: can happen only for spilling */
2486 /*-----------------------------------------------------------------*/
2488 genIpop (iCode * ic)
2493 /* if the temp was not pushed then */
2494 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2497 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2498 size = AOP_SIZE (IC_LEFT (ic));
2499 offset = (size - 1);
2500 if (isPair (AOP (IC_LEFT (ic))))
2502 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2510 spillPair (PAIR_HL);
2511 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2515 freeAsmop (IC_LEFT (ic), NULL, ic);
2518 /* This is quite unfortunate */
2520 setArea (int inHome)
2523 static int lastArea = 0;
2525 if (_G.in_home != inHome) {
2527 const char *sz = port->mem.code_name;
2528 port->mem.code_name = "HOME";
2529 emit2("!area", CODE_NAME);
2530 port->mem.code_name = sz;
2533 emit2("!area", CODE_NAME); */
2534 _G.in_home = inHome;
2545 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2549 symbol *sym = OP_SYMBOL (op);
2551 if (sym->isspilt || sym->nRegs == 0)
2554 aopOp (op, ic, FALSE, FALSE);
2557 if (aop->type == AOP_REG)
2560 for (i = 0; i < aop->size; i++)
2562 if (pairId == PAIR_DE)
2564 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2565 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2567 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2570 else if (pairId == PAIR_BC)
2572 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2573 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2575 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2585 freeAsmop (IC_LEFT (ic), NULL, ic);
2589 /** Emit the code for a call statement
2592 emitCall (iCode * ic, bool ispcall)
2594 sym_link *dtype = operandType (IC_LEFT (ic));
2596 /* if caller saves & we have not saved then */
2602 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2604 /* if send set is not empty then assign */
2609 int nSend = elementsInSet(_G.sendSet);
2610 bool swapped = FALSE;
2612 int _z80_sendOrder[] = {
2617 /* Check if the parameters are swapped. If so route through hl instead. */
2618 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2620 sic = setFirstItem(_G.sendSet);
2621 sic = setNextItem(_G.sendSet);
2623 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2624 /* The second send value is loaded from one the one that holds the first
2625 send, i.e. it is overwritten. */
2626 /* Cache the first in HL, and load the second from HL instead. */
2627 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2628 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2634 for (sic = setFirstItem (_G.sendSet); sic;
2635 sic = setNextItem (_G.sendSet))
2638 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2640 size = AOP_SIZE (IC_LEFT (sic));
2641 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2642 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2644 // PENDING: Mild hack
2645 if (swapped == TRUE && send == 1) {
2647 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2650 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2652 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2655 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2659 freeAsmop (IC_LEFT (sic), NULL, sic);
2666 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2668 werror (W_INDIR_BANKED);
2670 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2672 if (isLitWord (AOP (IC_LEFT (ic))))
2674 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2678 symbol *rlbl = newiTempLabel (NULL);
2679 spillPair (PAIR_HL);
2680 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2682 _G.stack.pushed += 2;
2684 fetchHL (AOP (IC_LEFT (ic)));
2686 emit2 ("!tlabeldef", (rlbl->key + 100));
2687 _G.stack.pushed -= 2;
2689 freeAsmop (IC_LEFT (ic), NULL, ic);
2693 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2694 OP_SYMBOL (IC_LEFT (ic))->rname :
2695 OP_SYMBOL (IC_LEFT (ic))->name;
2696 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2698 emit2 ("call banked_call");
2699 emit2 ("!dws", name);
2700 emit2 ("!dw !bankimmeds", name);
2705 emit2 ("call %s", name);
2710 /* Mark the regsiters as restored. */
2711 _G.saves.saved = FALSE;
2713 /* if we need assign a result value */
2714 if ((IS_ITEMP (IC_RESULT (ic)) &&
2715 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2716 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2717 IS_TRUE_SYMOP (IC_RESULT (ic)))
2720 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2722 assignResultValue (IC_RESULT (ic));
2724 freeAsmop (IC_RESULT (ic), NULL, ic);
2727 /* adjust the stack for parameters if required */
2730 int i = ic->parmBytes;
2732 _G.stack.pushed -= i;
2735 emit2 ("!ldaspsp", i);
2742 emit2 ("ld iy,!immedword", i);
2743 emit2 ("add iy,sp");
2763 if (_G.stack.pushedDE)
2765 bool dInRet = bitVectBitValue(ic->rUsed, D_IDX);
2766 bool eInRet = bitVectBitValue(ic->rUsed, E_IDX);
2768 if (dInRet && eInRet)
2770 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
2774 /* Only restore E */
2781 /* Only restore D */
2789 _G.stack.pushedDE = FALSE;
2792 if (_G.stack.pushedBC)
2794 bool bInRet = bitVectBitValue(ic->rUsed, B_IDX);
2795 bool cInRet = bitVectBitValue(ic->rUsed, C_IDX);
2797 if (bInRet && cInRet)
2799 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
2803 /* Only restore C */
2810 /* Only restore B */
2818 _G.stack.pushedBC = FALSE;
2822 /*-----------------------------------------------------------------*/
2823 /* genCall - generates a call statement */
2824 /*-----------------------------------------------------------------*/
2826 genCall (iCode * ic)
2828 emitCall (ic, FALSE);
2831 /*-----------------------------------------------------------------*/
2832 /* genPcall - generates a call by pointer statement */
2833 /*-----------------------------------------------------------------*/
2835 genPcall (iCode * ic)
2837 emitCall (ic, TRUE);
2840 /*-----------------------------------------------------------------*/
2841 /* resultRemat - result is rematerializable */
2842 /*-----------------------------------------------------------------*/
2844 resultRemat (iCode * ic)
2846 if (SKIP_IC (ic) || ic->op == IFX)
2849 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2851 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2852 if (sym->remat && !POINTER_SET (ic))
2859 extern set *publics;
2861 /*-----------------------------------------------------------------*/
2862 /* genFunction - generated code for function entry */
2863 /*-----------------------------------------------------------------*/
2865 genFunction (iCode * ic)
2867 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2870 bool bcInUse = FALSE;
2871 bool deInUse = FALSE;
2873 setArea (IFFUNC_NONBANKED (sym->type));
2875 /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
2878 _G.receiveOffset = 0;
2880 /* Record the last function name for debugging. */
2881 _G.lastFunctionName = sym->rname;
2883 /* Create the function header */
2884 emit2 ("!functionheader", sym->name);
2885 sprintf (buffer, "%s_start", sym->rname);
2886 emit2 ("!labeldef", buffer);
2887 emit2 ("!functionlabeldef", sym->rname);
2889 if (options.profile)
2891 emit2 ("!profileenter");
2894 ftype = operandType (IC_LEFT (ic));
2896 /* if critical function then turn interrupts off */
2897 if (IFFUNC_ISCRITICAL (ftype))
2900 /* if this is an interrupt service routine then save all potentially used registers. */
2901 if (IFFUNC_ISISR (sym->type))
2906 /* PENDING: callee-save etc */
2908 _G.stack.param_offset = 0;
2910 if (z80_opts.calleeSavesBC)
2915 /* Detect which registers are used. */
2916 if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
2919 for (i = 0; i < sym->regsUsed->size; i++)
2921 if (bitVectBitValue (sym->regsUsed, i))
2935 /* Other systems use DE as a temporary. */
2946 _G.stack.param_offset += 2;
2949 _G.calleeSaves.pushedBC = bcInUse;
2954 _G.stack.param_offset += 2;
2957 _G.calleeSaves.pushedDE = deInUse;
2959 /* adjust the stack for the function */
2960 _G.stack.last = sym->stack;
2962 if (sym->stack && IS_GB && sym->stack > -INT8MIN)
2963 emit2 ("!enterxl", sym->stack);
2964 else if (sym->stack)
2965 emit2 ("!enterx", sym->stack);
2968 _G.stack.offset = sym->stack;
2971 /*-----------------------------------------------------------------*/
2972 /* genEndFunction - generates epilogue for functions */
2973 /*-----------------------------------------------------------------*/
2975 genEndFunction (iCode * ic)
2977 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2979 if (IFFUNC_ISISR (sym->type))
2981 wassertl (0, "Tried to close an interrupt support function");
2985 if (IFFUNC_ISCRITICAL (sym->type))
2988 /* PENDING: calleeSave */
2990 if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
2992 emit2 ("!leavexl", _G.stack.offset);
2994 else if (_G.stack.offset)
2996 emit2 ("!leavex", _G.stack.offset);
3003 if (_G.calleeSaves.pushedDE)
3006 _G.calleeSaves.pushedDE = FALSE;
3009 if (_G.calleeSaves.pushedBC)
3012 _G.calleeSaves.pushedBC = FALSE;
3015 if (options.profile)
3017 emit2 ("!profileexit");
3021 /* Both baned and non-banked just ret */
3024 sprintf (buffer, "%s_end", sym->rname);
3025 emit2 ("!labeldef", buffer);
3027 _G.flushStatics = 1;
3028 _G.stack.pushed = 0;
3029 _G.stack.offset = 0;
3032 /*-----------------------------------------------------------------*/
3033 /* genRet - generate code for return statement */
3034 /*-----------------------------------------------------------------*/
3039 /* Errk. This is a hack until I can figure out how
3040 to cause dehl to spill on a call */
3041 int size, offset = 0;
3043 /* if we have no return value then
3044 just generate the "ret" */
3048 /* we have something to return then
3049 move the return value into place */
3050 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3051 size = AOP_SIZE (IC_LEFT (ic));
3053 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3057 emit2 ("ld de,%s", l);
3061 emit2 ("ld hl,%s", l);
3066 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3068 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3069 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3075 l = aopGet (AOP (IC_LEFT (ic)), offset,
3077 if (strcmp (_fReturn[offset], l))
3078 emit2 ("ld %s,%s", _fReturn[offset++], l);
3082 freeAsmop (IC_LEFT (ic), NULL, ic);
3085 /* generate a jump to the return label
3086 if the next is not the return statement */
3087 if (!(ic->next && ic->next->op == LABEL &&
3088 IC_LABEL (ic->next) == returnLabel))
3090 emit2 ("jp !tlabel", returnLabel->key + 100);
3093 /*-----------------------------------------------------------------*/
3094 /* genLabel - generates a label */
3095 /*-----------------------------------------------------------------*/
3097 genLabel (iCode * ic)
3099 /* special case never generate */
3100 if (IC_LABEL (ic) == entryLabel)
3103 emitLabel (IC_LABEL (ic)->key + 100);
3106 /*-----------------------------------------------------------------*/
3107 /* genGoto - generates a ljmp */
3108 /*-----------------------------------------------------------------*/
3110 genGoto (iCode * ic)
3112 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3115 /*-----------------------------------------------------------------*/
3116 /* genPlusIncr :- does addition with increment if possible */
3117 /*-----------------------------------------------------------------*/
3119 genPlusIncr (iCode * ic)
3121 unsigned int icount;
3122 unsigned int size = getDataSize (IC_RESULT (ic));
3123 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3125 /* will try to generate an increment */
3126 /* if the right side is not a literal
3128 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3131 emitDebug ("; genPlusIncr");
3133 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3135 /* If result is a pair */
3136 if (resultId != PAIR_INVALID)
3138 if (isLitWord (AOP (IC_LEFT (ic))))
3140 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3143 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3145 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3147 PAIR_ID freep = getFreePairId (ic);
3148 if (freep != PAIR_INVALID)
3150 fetchPair (freep, AOP (IC_RIGHT (ic)));
3151 emit2 ("add hl,%s", _pairs[freep].name);
3157 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3158 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3165 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3169 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3173 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3178 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3180 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3181 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3185 /* if the literal value of the right hand side
3186 is greater than 4 then it is not worth it */
3190 /* if increment 16 bits in register */
3191 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3197 symbol *tlbl = NULL;
3198 tlbl = newiTempLabel (NULL);
3201 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3204 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3207 emitLabel (tlbl->key + 100);
3211 /* if the sizes are greater than 1 then we cannot */
3212 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3213 AOP_SIZE (IC_LEFT (ic)) > 1)
3216 /* If the result is in a register then we can load then increment.
3218 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3220 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3223 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3228 /* we can if the aops of the left & result match or
3229 if they are in registers and the registers are the
3231 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3235 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3243 /*-----------------------------------------------------------------*/
3244 /* outBitAcc - output a bit in acc */
3245 /*-----------------------------------------------------------------*/
3247 outBitAcc (operand * result)
3249 symbol *tlbl = newiTempLabel (NULL);
3250 /* if the result is a bit */
3251 if (AOP_TYPE (result) == AOP_CRY)
3253 wassertl (0, "Tried to write A into a bit");
3257 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3258 emit2 ("ld a,!one");
3259 emitLabel (tlbl->key + 100);
3265 couldDestroyCarry (asmop *aop)
3269 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3278 shiftIntoPair (int idx, asmop *aop)
3280 PAIR_ID id = PAIR_INVALID;
3282 wassertl (IS_Z80, "Only implemented for the Z80");
3283 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3295 wassertl (0, "Internal error - hit default case");
3298 emitDebug ("; Shift into pair idx %u", idx);
3302 setupPair (PAIR_HL, aop, 0);
3306 setupPair (PAIR_IY, aop, 0);
3308 emit2 ("pop %s", _pairs[id].name);
3311 aop->type = AOP_PAIRPTR;
3312 aop->aopu.aop_pairId = id;
3313 _G.pairs[id].offset = 0;
3314 _G.pairs[id].last_type = aop->type;
3318 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
3320 wassert (left && right);
3324 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3326 shiftIntoPair (0, right);
3327 shiftIntoPair (1, result);
3329 else if (couldDestroyCarry (right))
3331 shiftIntoPair (0, right);
3333 else if (couldDestroyCarry (result))
3335 shiftIntoPair (0, result);
3344 /*-----------------------------------------------------------------*/
3345 /* genPlus - generates code for addition */
3346 /*-----------------------------------------------------------------*/
3348 genPlus (iCode * ic)
3350 int size, offset = 0;
3352 /* special cases :- */
3354 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3355 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3356 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3358 /* Swap the left and right operands if:
3360 if literal, literal on the right or
3361 if left requires ACC or right is already
3364 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3365 (AOP_NEEDSACC (IC_LEFT (ic))) ||
3366 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3368 operand *t = IC_RIGHT (ic);
3369 IC_RIGHT (ic) = IC_LEFT (ic);
3373 /* if both left & right are in bit
3375 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3376 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3379 wassertl (0, "Tried to add two bits");
3382 /* if left in bit space & right literal */
3383 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3384 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3386 /* Can happen I guess */
3387 wassertl (0, "Tried to add a bit to a literal");
3390 /* if I can do an increment instead
3391 of add then GOOD for ME */
3392 if (genPlusIncr (ic) == TRUE)
3395 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3397 size = getDataSize (IC_RESULT (ic));
3399 /* Special case when left and right are constant */
3400 if (isPair (AOP (IC_RESULT (ic))))
3403 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3404 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3406 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3412 sprintf (buffer, "#(%s + %s)", left, right);
3413 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3418 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3420 /* Fetch into HL then do the add */
3421 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3422 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3424 spillPair (PAIR_HL);
3426 if (left == PAIR_HL && right != PAIR_INVALID)
3428 emit2 ("add hl,%s", _pairs[right].name);
3431 else if (right == PAIR_HL && left != PAIR_INVALID)
3433 emit2 ("add hl,%s", _pairs[left].name);
3436 else if (right != PAIR_INVALID && right != PAIR_HL)
3438 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3439 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3442 else if (left != PAIR_INVALID && left != PAIR_HL)
3444 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3445 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3454 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3456 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3457 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3459 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3464 ld hl,sp+n trashes C so we cant afford to do it during an
3465 add with stack based varibles. Worst case is:
3478 So you cant afford to load up hl if either left, right, or result
3479 is on the stack (*sigh*) The alt is:
3487 Combinations in here are:
3488 * If left or right are in bc then the loss is small - trap later
3489 * If the result is in bc then the loss is also small
3493 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3494 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3495 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3497 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3498 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3499 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3500 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3502 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3504 /* Swap left and right */
3505 operand *t = IC_RIGHT (ic);
3506 IC_RIGHT (ic) = IC_LEFT (ic);
3509 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3511 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3512 emit2 ("add hl,bc");
3516 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3517 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3518 emit2 ("add hl,de");
3520 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3526 /* Be paranoid on the GB with 4 byte variables due to how C
3527 can be trashed by lda hl,n(sp).
3529 _gbz80_emitAddSubLong (ic, TRUE);
3534 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3538 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3540 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3543 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3546 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3550 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3553 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3556 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3558 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3562 freeAsmop (IC_LEFT (ic), NULL, ic);
3563 freeAsmop (IC_RIGHT (ic), NULL, ic);
3564 freeAsmop (IC_RESULT (ic), NULL, ic);
3568 /*-----------------------------------------------------------------*/
3569 /* genMinusDec :- does subtraction with deccrement if possible */
3570 /*-----------------------------------------------------------------*/
3572 genMinusDec (iCode * ic)
3574 unsigned int icount;
3575 unsigned int size = getDataSize (IC_RESULT (ic));
3577 /* will try to generate an increment */
3578 /* if the right side is not a literal we cannot */
3579 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3582 /* if the literal value of the right hand side
3583 is greater than 4 then it is not worth it */
3584 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3587 size = getDataSize (IC_RESULT (ic));
3589 /* if decrement 16 bits in register */
3590 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3591 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3594 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3598 /* If result is a pair */
3599 if (isPair (AOP (IC_RESULT (ic))))
3601 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3603 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3607 /* if increment 16 bits in register */
3608 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3612 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3615 emit2 ("dec %s", _getTempPairName());
3618 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3624 /* if the sizes are greater than 1 then we cannot */
3625 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3626 AOP_SIZE (IC_LEFT (ic)) > 1)
3629 /* we can if the aops of the left & result match or if they are in
3630 registers and the registers are the same */
3631 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3634 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3641 /*-----------------------------------------------------------------*/
3642 /* genMinus - generates code for subtraction */
3643 /*-----------------------------------------------------------------*/
3645 genMinus (iCode * ic)
3647 int size, offset = 0;
3648 unsigned long lit = 0L;
3650 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3651 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3652 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3654 /* special cases :- */
3655 /* if both left & right are in bit space */
3656 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3657 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3659 wassertl (0, "Tried to subtract two bits");
3663 /* if I can do an decrement instead of subtract then GOOD for ME */
3664 if (genMinusDec (ic) == TRUE)
3667 size = getDataSize (IC_RESULT (ic));
3669 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3674 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3678 /* Same logic as genPlus */
3681 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3682 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3683 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3685 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3686 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3687 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3688 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3690 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3691 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3693 if (left == PAIR_INVALID && right == PAIR_INVALID)
3698 else if (right == PAIR_INVALID)
3700 else if (left == PAIR_INVALID)
3703 fetchPair (left, AOP (IC_LEFT (ic)));
3704 /* Order is important. Right may be HL */
3705 fetchPair (right, AOP (IC_RIGHT (ic)));
3707 emit2 ("ld a,%s", _pairs[left].l);
3708 emit2 ("sub a,%s", _pairs[right].l);
3710 emit2 ("ld a,%s", _pairs[left].h);
3711 emit2 ("sbc a,%s", _pairs[right].h);
3713 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
3715 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3717 aopPut (AOP (IC_RESULT (ic)), "e", 0);
3723 /* Be paranoid on the GB with 4 byte variables due to how C
3724 can be trashed by lda hl,n(sp).
3726 _gbz80_emitAddSubLong (ic, FALSE);
3731 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3733 /* if literal, add a,#-lit, else normal subb */
3736 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3737 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3741 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3744 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3748 /* first add without previous c */
3750 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
3752 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3754 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3757 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3758 AOP_SIZE (IC_LEFT (ic)) == 3 &&
3759 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3761 wassertl (0, "Tried to subtract on a long pointer");
3765 freeAsmop (IC_LEFT (ic), NULL, ic);
3766 freeAsmop (IC_RIGHT (ic), NULL, ic);
3767 freeAsmop (IC_RESULT (ic), NULL, ic);
3770 /*-----------------------------------------------------------------*/
3771 /* genMult - generates code for multiplication */
3772 /*-----------------------------------------------------------------*/
3774 genMult (iCode * ic)
3778 /* If true then the final operation should be a subtract */
3779 bool active = FALSE;
3781 /* Shouldn't occur - all done through function calls */
3782 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3783 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3784 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3786 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
3787 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
3788 AOP_SIZE (IC_RESULT (ic)) > 2)
3790 wassertl (0, "Multiplication is handled through support function calls");
3793 /* Swap left and right such that right is a literal */
3794 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
3796 operand *t = IC_RIGHT (ic);
3797 IC_RIGHT (ic) = IC_LEFT (ic);
3801 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
3803 val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
3804 // wassertl (val > 0, "Multiply must be positive");
3805 wassertl (val != 1, "Can't multiply by 1");
3807 if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
3809 _G.stack.pushedDE = TRUE;
3812 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
3814 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
3822 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3827 /* Fully unroled version of mul.s. Not the most efficient.
3829 for (count = 0; count < 16; count++)
3831 if (count != 0 && active)
3833 emit2 ("add hl,hl");
3837 if (active == FALSE)
3844 emit2 ("add hl,de");
3853 if (IS_Z80 && _G.stack.pushedDE)
3856 _G.stack.pushedDE = FALSE;
3859 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3861 freeAsmop (IC_LEFT (ic), NULL, ic);
3862 freeAsmop (IC_RIGHT (ic), NULL, ic);
3863 freeAsmop (IC_RESULT (ic), NULL, ic);
3866 /*-----------------------------------------------------------------*/
3867 /* genDiv - generates code for division */
3868 /*-----------------------------------------------------------------*/
3872 /* Shouldn't occur - all done through function calls */
3873 wassertl (0, "Division is handled through support function calls");
3876 /*-----------------------------------------------------------------*/
3877 /* genMod - generates code for division */
3878 /*-----------------------------------------------------------------*/
3882 /* Shouldn't occur - all done through function calls */
3886 /*-----------------------------------------------------------------*/
3887 /* genIfxJump :- will create a jump depending on the ifx */
3888 /*-----------------------------------------------------------------*/
3890 genIfxJump (iCode * ic, char *jval)
3895 /* if true label then we jump if condition
3899 jlbl = IC_TRUE (ic);
3900 if (!strcmp (jval, "a"))
3904 else if (!strcmp (jval, "c"))
3908 else if (!strcmp (jval, "nc"))
3912 else if (!strcmp (jval, "m"))
3916 else if (!strcmp (jval, "p"))
3922 /* The buffer contains the bit on A that we should test */
3928 /* false label is present */
3929 jlbl = IC_FALSE (ic);
3930 if (!strcmp (jval, "a"))
3934 else if (!strcmp (jval, "c"))
3938 else if (!strcmp (jval, "nc"))
3942 else if (!strcmp (jval, "m"))
3946 else if (!strcmp (jval, "p"))
3952 /* The buffer contains the bit on A that we should test */
3956 /* Z80 can do a conditional long jump */
3957 if (!strcmp (jval, "a"))
3961 else if (!strcmp (jval, "c"))
3964 else if (!strcmp (jval, "nc"))
3967 else if (!strcmp (jval, "m"))
3970 else if (!strcmp (jval, "p"))
3975 emit2 ("bit %s,a", jval);
3977 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
3979 /* mark the icode as generated */
3985 _getPairIdName (PAIR_ID id)
3987 return _pairs[id].name;
3992 /* if unsigned char cmp with lit, just compare */
3994 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
3996 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3999 emit2 ("xor a,!immedbyte", 0x80);
4000 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4003 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4005 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4007 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4008 // Pull left into DE and right into HL
4009 aopGet (AOP(left), LSB, FALSE);
4012 aopGet (AOP(right), LSB, FALSE);
4016 if (size == 0 && sign)
4018 // Highest byte when signed needs the bits flipped
4021 emit2 ("ld a,(de)");
4022 emit2 ("xor !immedbyte", 0x80);
4024 emit2 ("ld a,(hl)");
4025 emit2 ("xor !immedbyte", 0x80);
4029 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4033 emit2 ("ld a,(de)");
4034 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4044 spillPair (PAIR_HL);
4046 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4048 setupPair (PAIR_HL, AOP (left), 0);
4049 aopGet (AOP(right), LSB, FALSE);
4053 if (size == 0 && sign)
4055 // Highest byte when signed needs the bits flipped
4058 emit2 ("ld a,(hl)");
4059 emit2 ("xor !immedbyte", 0x80);
4061 emit2 ("ld a,%d(iy)", offset);
4062 emit2 ("xor !immedbyte", 0x80);
4066 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4070 emit2 ("ld a,(hl)");
4071 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4080 spillPair (PAIR_HL);
4081 spillPair (PAIR_IY);
4085 if (AOP_TYPE (right) == AOP_LIT)
4087 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4088 /* optimize if(x < 0) or if(x >= 0) */
4093 /* No sign so it's always false */
4098 /* Just load in the top most bit */
4099 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4100 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4102 genIfxJump (ifx, "7");
4114 /* First setup h and l contaning the top most bytes XORed */
4115 bool fDidXor = FALSE;
4116 if (AOP_TYPE (left) == AOP_LIT)
4118 unsigned long lit = (unsigned long)
4119 floatFromVal (AOP (left)->aopu.aop_lit);
4120 emit2 ("ld %s,!immedbyte", _fTmp[0],
4121 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4125 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4126 emit2 ("xor a,!immedbyte", 0x80);
4127 emit2 ("ld %s,a", _fTmp[0]);
4130 if (AOP_TYPE (right) == AOP_LIT)
4132 unsigned long lit = (unsigned long)
4133 floatFromVal (AOP (right)->aopu.aop_lit);
4134 emit2 ("ld %s,!immedbyte", _fTmp[1],
4135 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4139 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4140 emit2 ("xor a,!immedbyte", 0x80);
4141 emit2 ("ld %s,a", _fTmp[1]);
4147 /* Do a long subtract */
4150 _moveA (aopGet (AOP (left), offset, FALSE));
4152 if (sign && size == 0)
4154 emit2 ("ld a,%s", _fTmp[0]);
4155 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4159 /* Subtract through, propagating the carry */
4160 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4168 /** Generic compare for > or <
4171 genCmp (operand * left, operand * right,
4172 operand * result, iCode * ifx, int sign)
4174 int size, offset = 0;
4175 unsigned long lit = 0L;
4176 bool swap_sense = FALSE;
4178 /* if left & right are bit variables */
4179 if (AOP_TYPE (left) == AOP_CRY &&
4180 AOP_TYPE (right) == AOP_CRY)
4182 /* Cant happen on the Z80 */
4183 wassertl (0, "Tried to compare two bits");
4187 /* Do a long subtract of right from left. */
4188 size = max (AOP_SIZE (left), AOP_SIZE (right));
4190 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4192 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4193 // Pull left into DE and right into HL
4194 aopGet (AOP(left), LSB, FALSE);
4197 aopGet (AOP(right), LSB, FALSE);
4201 emit2 ("ld a,(de)");
4202 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4211 spillPair (PAIR_HL);
4215 if (AOP_TYPE (right) == AOP_LIT)
4217 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4218 /* optimize if(x < 0) or if(x >= 0) */
4223 /* No sign so it's always false */
4228 /* Just load in the top most bit */
4229 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4230 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4232 genIfxJump (ifx, "7");
4243 genIfxJump (ifx, swap_sense ? "c" : "nc");
4254 _moveA (aopGet (AOP (left), offset, FALSE));
4255 /* Subtract through, propagating the carry */
4256 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4262 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4266 /* Shift the sign bit up into carry */
4269 outBitCLong (result, swap_sense);
4273 /* if the result is used in the next
4274 ifx conditional branch then generate
4275 code a little differently */
4283 genIfxJump (ifx, swap_sense ? "nc" : "c");
4287 genIfxJump (ifx, swap_sense ? "p" : "m");
4292 genIfxJump (ifx, swap_sense ? "nc" : "c");
4299 /* Shift the sign bit up into carry */
4302 outBitCLong (result, swap_sense);
4304 /* leave the result in acc */
4308 /*-----------------------------------------------------------------*/
4309 /* genCmpGt :- greater than comparison */
4310 /*-----------------------------------------------------------------*/
4312 genCmpGt (iCode * ic, iCode * ifx)
4314 operand *left, *right, *result;
4315 sym_link *letype, *retype;
4318 left = IC_LEFT (ic);
4319 right = IC_RIGHT (ic);
4320 result = IC_RESULT (ic);
4322 letype = getSpec (operandType (left));
4323 retype = getSpec (operandType (right));
4324 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4325 /* assign the amsops */
4326 aopOp (left, ic, FALSE, FALSE);
4327 aopOp (right, ic, FALSE, FALSE);
4328 aopOp (result, ic, TRUE, FALSE);
4330 genCmp (right, left, result, ifx, sign);
4332 freeAsmop (left, NULL, ic);
4333 freeAsmop (right, NULL, ic);
4334 freeAsmop (result, NULL, ic);
4337 /*-----------------------------------------------------------------*/
4338 /* genCmpLt - less than comparisons */
4339 /*-----------------------------------------------------------------*/
4341 genCmpLt (iCode * ic, iCode * ifx)
4343 operand *left, *right, *result;
4344 sym_link *letype, *retype;
4347 left = IC_LEFT (ic);
4348 right = IC_RIGHT (ic);
4349 result = IC_RESULT (ic);
4351 letype = getSpec (operandType (left));
4352 retype = getSpec (operandType (right));
4353 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4355 /* assign the amsops */
4356 aopOp (left, ic, FALSE, FALSE);
4357 aopOp (right, ic, FALSE, FALSE);
4358 aopOp (result, ic, TRUE, FALSE);
4360 genCmp (left, right, result, ifx, sign);
4362 freeAsmop (left, NULL, ic);
4363 freeAsmop (right, NULL, ic);
4364 freeAsmop (result, NULL, ic);
4367 /*-----------------------------------------------------------------*/
4368 /* gencjneshort - compare and jump if not equal */
4369 /*-----------------------------------------------------------------*/
4371 gencjneshort (operand * left, operand * right, symbol * lbl)
4373 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4375 unsigned long lit = 0L;
4377 /* Swap the left and right if it makes the computation easier */
4378 if (AOP_TYPE (left) == AOP_LIT)
4385 if (AOP_TYPE (right) == AOP_LIT)
4387 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4390 /* if the right side is a literal then anything goes */
4391 if (AOP_TYPE (right) == AOP_LIT &&
4392 AOP_TYPE (left) != AOP_DIR)
4396 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4401 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4408 emit2 ("jp nz,!tlabel", lbl->key + 100);
4414 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4415 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
4418 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
4419 emit2 ("jp nz,!tlabel", lbl->key + 100);
4424 /* if the right side is in a register or in direct space or
4425 if the left is a pointer register & right is not */
4426 else if (AOP_TYPE (right) == AOP_REG ||
4427 AOP_TYPE (right) == AOP_DIR ||
4428 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
4432 _moveA (aopGet (AOP (left), offset, FALSE));
4433 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
4434 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4436 emit2 ("jp nz,!tlabel", lbl->key + 100);
4439 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4440 emit2 ("jp nz,!tlabel", lbl->key + 100);
4447 /* right is a pointer reg need both a & b */
4448 /* PENDING: is this required? */
4451 _moveA (aopGet (AOP (right), offset, FALSE));
4452 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
4453 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
4459 /*-----------------------------------------------------------------*/
4460 /* gencjne - compare and jump if not equal */
4461 /*-----------------------------------------------------------------*/
4463 gencjne (operand * left, operand * right, symbol * lbl)
4465 symbol *tlbl = newiTempLabel (NULL);
4467 gencjneshort (left, right, lbl);
4470 emit2 ("ld a,!one");
4471 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4472 emitLabel (lbl->key + 100);
4474 emitLabel (tlbl->key + 100);
4477 /*-----------------------------------------------------------------*/
4478 /* genCmpEq - generates code for equal to */
4479 /*-----------------------------------------------------------------*/
4481 genCmpEq (iCode * ic, iCode * ifx)
4483 operand *left, *right, *result;
4485 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4486 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4487 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4489 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4491 /* Swap operands if it makes the operation easier. ie if:
4492 1. Left is a literal.
4494 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4496 operand *t = IC_RIGHT (ic);
4497 IC_RIGHT (ic) = IC_LEFT (ic);
4501 if (ifx && !AOP_SIZE (result))
4504 /* if they are both bit variables */
4505 if (AOP_TYPE (left) == AOP_CRY &&
4506 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4508 wassertl (0, "Tried to compare two bits");
4512 tlbl = newiTempLabel (NULL);
4513 gencjneshort (left, right, tlbl);
4516 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4517 emitLabel (tlbl->key + 100);
4521 /* PENDING: do this better */
4522 symbol *lbl = newiTempLabel (NULL);
4523 emit2 ("!shortjp !tlabel", lbl->key + 100);
4524 emitLabel (tlbl->key + 100);
4525 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4526 emitLabel (lbl->key + 100);
4529 /* mark the icode as generated */
4534 /* if they are both bit variables */
4535 if (AOP_TYPE (left) == AOP_CRY &&
4536 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4538 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4544 gencjne (left, right, newiTempLabel (NULL));
4545 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4552 genIfxJump (ifx, "a");
4555 /* if the result is used in an arithmetic operation
4556 then put the result in place */
4557 if (AOP_TYPE (result) != AOP_CRY)
4562 /* leave the result in acc */
4566 freeAsmop (left, NULL, ic);
4567 freeAsmop (right, NULL, ic);
4568 freeAsmop (result, NULL, ic);
4571 /*-----------------------------------------------------------------*/
4572 /* ifxForOp - returns the icode containing the ifx for operand */
4573 /*-----------------------------------------------------------------*/
4575 ifxForOp (operand * op, iCode * ic)
4577 /* if true symbol then needs to be assigned */
4578 if (IS_TRUE_SYMOP (op))
4581 /* if this has register type condition and
4582 the next instruction is ifx with the same operand
4583 and live to of the operand is upto the ifx only then */
4585 ic->next->op == IFX &&
4586 IC_COND (ic->next)->key == op->key &&
4587 OP_SYMBOL (op)->liveTo <= ic->next->seq)
4593 /*-----------------------------------------------------------------*/
4594 /* genAndOp - for && operation */
4595 /*-----------------------------------------------------------------*/
4597 genAndOp (iCode * ic)
4599 operand *left, *right, *result;
4602 /* note here that && operations that are in an if statement are
4603 taken away by backPatchLabels only those used in arthmetic
4604 operations remain */
4605 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4606 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4607 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4609 /* if both are bit variables */
4610 if (AOP_TYPE (left) == AOP_CRY &&
4611 AOP_TYPE (right) == AOP_CRY)
4613 wassertl (0, "Tried to and two bits");
4617 tlbl = newiTempLabel (NULL);
4619 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
4621 emitLabel (tlbl->key + 100);
4625 freeAsmop (left, NULL, ic);
4626 freeAsmop (right, NULL, ic);
4627 freeAsmop (result, NULL, ic);
4630 /*-----------------------------------------------------------------*/
4631 /* genOrOp - for || operation */
4632 /*-----------------------------------------------------------------*/
4634 genOrOp (iCode * ic)
4636 operand *left, *right, *result;
4639 /* note here that || operations that are in an
4640 if statement are taken away by backPatchLabels
4641 only those used in arthmetic operations remain */
4642 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4643 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4644 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4646 /* if both are bit variables */
4647 if (AOP_TYPE (left) == AOP_CRY &&
4648 AOP_TYPE (right) == AOP_CRY)
4650 wassertl (0, "Tried to OR two bits");
4654 tlbl = newiTempLabel (NULL);
4656 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4658 emitLabel (tlbl->key + 100);
4662 freeAsmop (left, NULL, ic);
4663 freeAsmop (right, NULL, ic);
4664 freeAsmop (result, NULL, ic);
4667 /*-----------------------------------------------------------------*/
4668 /* isLiteralBit - test if lit == 2^n */
4669 /*-----------------------------------------------------------------*/
4671 isLiteralBit (unsigned long lit)
4673 unsigned long pw[32] =
4674 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
4675 0x100L, 0x200L, 0x400L, 0x800L,
4676 0x1000L, 0x2000L, 0x4000L, 0x8000L,
4677 0x10000L, 0x20000L, 0x40000L, 0x80000L,
4678 0x100000L, 0x200000L, 0x400000L, 0x800000L,
4679 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
4680 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
4683 for (idx = 0; idx < 32; idx++)
4689 /*-----------------------------------------------------------------*/
4690 /* jmpTrueOrFalse - */
4691 /*-----------------------------------------------------------------*/
4693 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
4695 // ugly but optimized by peephole
4698 symbol *nlbl = newiTempLabel (NULL);
4699 emit2 ("jp !tlabel", nlbl->key + 100);
4700 emitLabel (tlbl->key + 100);
4701 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
4702 emitLabel (nlbl->key + 100);
4706 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
4707 emitLabel (tlbl->key + 100);
4712 /*-----------------------------------------------------------------*/
4713 /* genAnd - code for and */
4714 /*-----------------------------------------------------------------*/
4716 genAnd (iCode * ic, iCode * ifx)
4718 operand *left, *right, *result;
4719 int size, offset = 0;
4720 unsigned long lit = 0L;
4723 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4724 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4725 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4727 /* if left is a literal & right is not then exchange them */
4728 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4729 AOP_NEEDSACC (left))
4731 operand *tmp = right;
4736 /* if result = right then exchange them */
4737 if (sameRegs (AOP (result), AOP (right)))
4739 operand *tmp = right;
4744 /* if right is bit then exchange them */
4745 if (AOP_TYPE (right) == AOP_CRY &&
4746 AOP_TYPE (left) != AOP_CRY)
4748 operand *tmp = right;
4752 if (AOP_TYPE (right) == AOP_LIT)
4753 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4755 size = AOP_SIZE (result);
4757 if (AOP_TYPE (left) == AOP_CRY)
4759 wassertl (0, "Tried to perform an AND with a bit as an operand");
4763 // if(val & 0xZZ) - size = 0, ifx != FALSE -
4764 // bit = val & 0xZZ - size = 1, ifx = FALSE -
4765 if ((AOP_TYPE (right) == AOP_LIT) &&
4766 (AOP_TYPE (result) == AOP_CRY) &&
4767 (AOP_TYPE (left) != AOP_CRY))
4769 symbol *tlbl = newiTempLabel (NULL);
4770 int sizel = AOP_SIZE (left);
4773 /* PENDING: Test case for this. */
4778 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
4780 _moveA (aopGet (AOP (left), offset, FALSE));
4781 if (bytelit != 0x0FFL)
4783 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4790 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4794 // bit = left & literal
4798 emit2 ("!tlabeldef", tlbl->key + 100);
4800 // if(left & literal)
4805 jmpTrueOrFalse (ifx, tlbl);
4813 /* if left is same as result */
4814 if (sameRegs (AOP (result), AOP (left)))
4816 for (; size--; offset++)
4818 if (AOP_TYPE (right) == AOP_LIT)
4820 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4825 aopPut (AOP (result), "!zero", offset);
4828 _moveA (aopGet (AOP (left), offset, FALSE));
4830 aopGet (AOP (right), offset, FALSE));
4831 aopPut (AOP (left), "a", offset);
4838 if (AOP_TYPE (left) == AOP_ACC)
4840 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
4844 _moveA (aopGet (AOP (left), offset, FALSE));
4846 aopGet (AOP (right), offset, FALSE));
4847 aopPut (AOP (left), "a", offset);
4854 // left & result in different registers
4855 if (AOP_TYPE (result) == AOP_CRY)
4857 wassertl (0, "Tried to AND where the result is in carry");
4861 for (; (size--); offset++)
4864 // result = left & right
4865 if (AOP_TYPE (right) == AOP_LIT)
4867 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4869 aopPut (AOP (result),
4870 aopGet (AOP (left), offset, FALSE),
4874 else if (bytelit == 0)
4876 aopPut (AOP (result), "!zero", offset);
4880 // faster than result <- left, anl result,right
4881 // and better if result is SFR
4882 if (AOP_TYPE (left) == AOP_ACC)
4883 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4886 _moveA (aopGet (AOP (left), offset, FALSE));
4888 aopGet (AOP (right), offset, FALSE));
4890 aopPut (AOP (result), "a", offset);
4897 freeAsmop (left, NULL, ic);
4898 freeAsmop (right, NULL, ic);
4899 freeAsmop (result, NULL, ic);
4902 /*-----------------------------------------------------------------*/
4903 /* genOr - code for or */
4904 /*-----------------------------------------------------------------*/
4906 genOr (iCode * ic, iCode * ifx)
4908 operand *left, *right, *result;
4909 int size, offset = 0;
4910 unsigned long lit = 0L;
4913 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4914 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4915 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4917 /* if left is a literal & right is not then exchange them */
4918 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4919 AOP_NEEDSACC (left))
4921 operand *tmp = right;
4926 /* if result = right then exchange them */
4927 if (sameRegs (AOP (result), AOP (right)))
4929 operand *tmp = right;
4934 /* if right is bit then exchange them */
4935 if (AOP_TYPE (right) == AOP_CRY &&
4936 AOP_TYPE (left) != AOP_CRY)
4938 operand *tmp = right;
4942 if (AOP_TYPE (right) == AOP_LIT)
4943 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4945 size = AOP_SIZE (result);
4947 if (AOP_TYPE (left) == AOP_CRY)
4949 wassertl (0, "Tried to OR where left is a bit");
4953 // if(val | 0xZZ) - size = 0, ifx != FALSE -
4954 // bit = val | 0xZZ - size = 1, ifx = FALSE -
4955 if ((AOP_TYPE (right) == AOP_LIT) &&
4956 (AOP_TYPE (result) == AOP_CRY) &&
4957 (AOP_TYPE (left) != AOP_CRY))
4959 symbol *tlbl = newiTempLabel (NULL);
4960 int sizel = AOP_SIZE (left);
4964 wassertl (0, "Result is assigned to a bit");
4966 /* PENDING: Modeled after the AND code which is inefficent. */
4969 bytelit = (lit >> (offset * 8)) & 0x0FFL;
4971 _moveA (aopGet (AOP (left), offset, FALSE));
4972 /* OR with any literal is the same as OR with itself. */
4974 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4980 jmpTrueOrFalse (ifx, tlbl);
4985 /* if left is same as result */
4986 if (sameRegs (AOP (result), AOP (left)))
4988 for (; size--; offset++)
4990 if (AOP_TYPE (right) == AOP_LIT)
4992 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4996 _moveA (aopGet (AOP (left), offset, FALSE));
4998 aopGet (AOP (right), offset, FALSE));
4999 aopPut (AOP (result), "a", offset);
5004 if (AOP_TYPE (left) == AOP_ACC)
5005 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5008 _moveA (aopGet (AOP (left), offset, FALSE));
5010 aopGet (AOP (right), offset, FALSE));
5011 aopPut (AOP (result), "a", offset);
5018 // left & result in different registers
5019 if (AOP_TYPE (result) == AOP_CRY)
5021 wassertl (0, "Result of OR is in a bit");
5024 for (; (size--); offset++)
5027 // result = left & right
5028 if (AOP_TYPE (right) == AOP_LIT)
5030 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5032 aopPut (AOP (result),
5033 aopGet (AOP (left), offset, FALSE),
5038 // faster than result <- left, anl result,right
5039 // and better if result is SFR
5040 if (AOP_TYPE (left) == AOP_ACC)
5041 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5044 _moveA (aopGet (AOP (left), offset, FALSE));
5046 aopGet (AOP (right), offset, FALSE));
5048 aopPut (AOP (result), "a", offset);
5049 /* PENDING: something weird is going on here. Add exception. */
5050 if (AOP_TYPE (result) == AOP_ACC)
5056 freeAsmop (left, NULL, ic);
5057 freeAsmop (right, NULL, ic);
5058 freeAsmop (result, NULL, ic);
5061 /*-----------------------------------------------------------------*/
5062 /* genXor - code for xclusive or */
5063 /*-----------------------------------------------------------------*/
5065 genXor (iCode * ic, iCode * ifx)
5067 operand *left, *right, *result;
5068 int size, offset = 0;
5069 unsigned long lit = 0L;
5071 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5072 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5073 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5075 /* if left is a literal & right is not then exchange them */
5076 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5077 AOP_NEEDSACC (left))
5079 operand *tmp = right;
5084 /* if result = right then exchange them */
5085 if (sameRegs (AOP (result), AOP (right)))
5087 operand *tmp = right;
5092 /* if right is bit then exchange them */
5093 if (AOP_TYPE (right) == AOP_CRY &&
5094 AOP_TYPE (left) != AOP_CRY)
5096 operand *tmp = right;
5100 if (AOP_TYPE (right) == AOP_LIT)
5101 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5103 size = AOP_SIZE (result);
5105 if (AOP_TYPE (left) == AOP_CRY)
5107 wassertl (0, "Tried to XOR a bit");
5111 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5112 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5113 if ((AOP_TYPE (right) == AOP_LIT) &&
5114 (AOP_TYPE (result) == AOP_CRY) &&
5115 (AOP_TYPE (left) != AOP_CRY))
5117 symbol *tlbl = newiTempLabel (NULL);
5118 int sizel = AOP_SIZE (left);
5122 /* PENDING: Test case for this. */
5123 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5127 _moveA (aopGet (AOP (left), offset, FALSE));
5128 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5129 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5134 jmpTrueOrFalse (ifx, tlbl);
5138 wassertl (0, "Result of XOR was destined for a bit");
5143 /* if left is same as result */
5144 if (sameRegs (AOP (result), AOP (left)))
5146 for (; size--; offset++)
5148 if (AOP_TYPE (right) == AOP_LIT)
5150 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5154 _moveA (aopGet (AOP (right), offset, FALSE));
5156 aopGet (AOP (left), offset, FALSE));
5157 aopPut (AOP (result), "a", offset);
5162 if (AOP_TYPE (left) == AOP_ACC)
5164 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5168 _moveA (aopGet (AOP (right), offset, FALSE));
5170 aopGet (AOP (left), offset, FALSE));
5171 aopPut (AOP (result), "a", 0);
5178 // left & result in different registers
5179 if (AOP_TYPE (result) == AOP_CRY)
5181 wassertl (0, "Result of XOR is in a bit");
5184 for (; (size--); offset++)
5187 // result = left & right
5188 if (AOP_TYPE (right) == AOP_LIT)
5190 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5192 aopPut (AOP (result),
5193 aopGet (AOP (left), offset, FALSE),
5198 // faster than result <- left, anl result,right
5199 // and better if result is SFR
5200 if (AOP_TYPE (left) == AOP_ACC)
5202 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5206 _moveA (aopGet (AOP (right), offset, FALSE));
5208 aopGet (AOP (left), offset, FALSE));
5210 aopPut (AOP (result), "a", offset);
5215 freeAsmop (left, NULL, ic);
5216 freeAsmop (right, NULL, ic);
5217 freeAsmop (result, NULL, ic);
5220 /*-----------------------------------------------------------------*/
5221 /* genInline - write the inline code out */
5222 /*-----------------------------------------------------------------*/
5224 genInline (iCode * ic)
5226 char *buffer, *bp, *bp1;
5228 _G.lines.isInline += (!options.asmpeep);
5230 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5231 strcpy (buffer, IC_INLINE (ic));
5233 /* emit each line as a code */
5258 _G.lines.isInline -= (!options.asmpeep);
5262 /*-----------------------------------------------------------------*/
5263 /* genRRC - rotate right with carry */
5264 /*-----------------------------------------------------------------*/
5271 /*-----------------------------------------------------------------*/
5272 /* genRLC - generate code for rotate left with carry */
5273 /*-----------------------------------------------------------------*/
5280 /*-----------------------------------------------------------------*/
5281 /* genGetHbit - generates code get highest order bit */
5282 /*-----------------------------------------------------------------*/
5284 genGetHbit (iCode * ic)
5286 operand *left, *result;
5287 left = IC_LEFT (ic);
5288 result = IC_RESULT (ic);
5290 aopOp (left, ic, FALSE, FALSE);
5291 aopOp (result, ic, FALSE, FALSE);
5293 /* get the highest order byte into a */
5294 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5296 if (AOP_TYPE (result) == AOP_CRY)
5304 emit2 ("and a,!one");
5309 freeAsmop (left, NULL, ic);
5310 freeAsmop (result, NULL, ic);
5314 emitRsh2 (asmop *aop, int size, int is_signed)
5320 const char *l = aopGet (aop, size, FALSE);
5323 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5333 /*-----------------------------------------------------------------*/
5334 /* shiftR2Left2Result - shift right two bytes from left to result */
5335 /*-----------------------------------------------------------------*/
5337 shiftR2Left2Result (operand * left, int offl,
5338 operand * result, int offr,
5339 int shCount, int is_signed)
5342 symbol *tlbl, *tlbl1;
5344 movLeft2Result (left, offl, result, offr, 0);
5345 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5347 /* if (AOP(result)->type == AOP_REG) { */
5349 tlbl = newiTempLabel (NULL);
5350 tlbl1 = newiTempLabel (NULL);
5352 /* Left is already in result - so now do the shift */
5357 emitRsh2 (AOP (result), size, is_signed);
5362 emit2 ("ld a,!immedbyte+1", shCount);
5363 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5364 emitLabel (tlbl->key + 100);
5366 emitRsh2 (AOP (result), size, is_signed);
5368 emitLabel (tlbl1->key + 100);
5370 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5374 /*-----------------------------------------------------------------*/
5375 /* shiftL2Left2Result - shift left two bytes from left to result */
5376 /*-----------------------------------------------------------------*/
5378 shiftL2Left2Result (operand * left, int offl,
5379 operand * result, int offr, int shCount)
5381 if (sameRegs (AOP (result), AOP (left)) &&
5382 ((offl + MSB16) == offr))
5388 /* Copy left into result */
5389 movLeft2Result (left, offl, result, offr, 0);
5390 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5393 if (getPairId (AOP (result)) == PAIR_HL)
5397 emit2 ("add hl,hl");
5404 symbol *tlbl, *tlbl1;
5407 tlbl = newiTempLabel (NULL);
5408 tlbl1 = newiTempLabel (NULL);
5410 if (AOP (result)->type == AOP_REG)
5414 for (offset = 0; offset < size; offset++)
5416 l = aopGet (AOP (result), offset, FALSE);
5420 emit2 ("sla %s", l);
5431 /* Left is already in result - so now do the shift */
5434 emit2 ("ld a,!immedbyte+1", shCount);
5435 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5436 emitLabel (tlbl->key + 100);
5441 l = aopGet (AOP (result), offset, FALSE);
5445 emit2 ("sla %s", l);
5456 emitLabel (tlbl1->key + 100);
5458 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5464 /*-----------------------------------------------------------------*/
5465 /* AccRol - rotate left accumulator by known count */
5466 /*-----------------------------------------------------------------*/
5468 AccRol (int shCount)
5470 shCount &= 0x0007; // shCount : 0..7
5509 /*-----------------------------------------------------------------*/
5510 /* AccLsh - left shift accumulator by known count */
5511 /*-----------------------------------------------------------------*/
5513 AccLsh (int shCount)
5515 static const unsigned char SLMask[] =
5517 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5526 else if (shCount == 2)
5533 /* rotate left accumulator */
5535 /* and kill the lower order bits */
5536 emit2 ("and a,!immedbyte", SLMask[shCount]);
5541 /*-----------------------------------------------------------------*/
5542 /* shiftL1Left2Result - shift left one byte from left to result */
5543 /*-----------------------------------------------------------------*/
5545 shiftL1Left2Result (operand * left, int offl,
5546 operand * result, int offr, int shCount)
5549 l = aopGet (AOP (left), offl, FALSE);
5551 /* shift left accumulator */
5553 aopPut (AOP (result), "a", offr);
5557 /*-----------------------------------------------------------------*/
5558 /* genlshTwo - left shift two bytes by known amount != 0 */
5559 /*-----------------------------------------------------------------*/
5561 genlshTwo (operand * result, operand * left, int shCount)
5563 int size = AOP_SIZE (result);
5565 wassert (size == 2);
5567 /* if shCount >= 8 */
5575 movLeft2Result (left, LSB, result, MSB16, 0);
5576 aopPut (AOP (result), "!zero", 0);
5577 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
5581 movLeft2Result (left, LSB, result, MSB16, 0);
5582 aopPut (AOP (result), "!zero", 0);
5587 aopPut (AOP (result), "!zero", LSB);
5590 /* 1 <= shCount <= 7 */
5599 shiftL2Left2Result (left, LSB, result, LSB, shCount);
5604 /*-----------------------------------------------------------------*/
5605 /* genlshOne - left shift a one byte quantity by known count */
5606 /*-----------------------------------------------------------------*/
5608 genlshOne (operand * result, operand * left, int shCount)
5610 shiftL1Left2Result (left, LSB, result, LSB, shCount);
5613 /*-----------------------------------------------------------------*/
5614 /* genLeftShiftLiteral - left shifting by known count */
5615 /*-----------------------------------------------------------------*/
5617 genLeftShiftLiteral (operand * left,
5622 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5625 freeAsmop (right, NULL, ic);
5627 aopOp (left, ic, FALSE, FALSE);
5628 aopOp (result, ic, FALSE, FALSE);
5630 size = getSize (operandType (result));
5632 /* I suppose that the left size >= result size */
5638 else if (shCount >= (size * 8))
5642 aopPut (AOP (result), "!zero", size);
5650 genlshOne (result, left, shCount);
5653 genlshTwo (result, left, shCount);
5656 wassertl (0, "Shifting of longs is currently unsupported");
5662 freeAsmop (left, NULL, ic);
5663 freeAsmop (result, NULL, ic);
5666 /*-----------------------------------------------------------------*/
5667 /* genLeftShift - generates code for left shifting */
5668 /*-----------------------------------------------------------------*/
5670 genLeftShift (iCode * ic)
5674 symbol *tlbl, *tlbl1;
5675 operand *left, *right, *result;
5677 right = IC_RIGHT (ic);
5678 left = IC_LEFT (ic);
5679 result = IC_RESULT (ic);
5681 aopOp (right, ic, FALSE, FALSE);
5683 /* if the shift count is known then do it
5684 as efficiently as possible */
5685 if (AOP_TYPE (right) == AOP_LIT)
5687 genLeftShiftLiteral (left, right, result, ic);
5691 /* shift count is unknown then we have to form a loop get the loop
5692 count in B : Note: we take only the lower order byte since
5693 shifting more that 32 bits make no sense anyway, ( the largest
5694 size of an object can be only 32 bits ) */
5695 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5697 freeAsmop (right, NULL, ic);
5698 aopOp (left, ic, FALSE, FALSE);
5699 aopOp (result, ic, FALSE, FALSE);
5701 /* now move the left to the result if they are not the
5704 if (!sameRegs (AOP (left), AOP (result)))
5707 size = AOP_SIZE (result);
5711 l = aopGet (AOP (left), offset, FALSE);
5712 aopPut (AOP (result), l, offset);
5717 tlbl = newiTempLabel (NULL);
5718 size = AOP_SIZE (result);
5720 tlbl1 = newiTempLabel (NULL);
5722 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5723 emitLabel (tlbl->key + 100);
5724 l = aopGet (AOP (result), offset, FALSE);
5728 l = aopGet (AOP (result), offset, FALSE);
5732 emit2 ("sla %s", l);
5740 emitLabel (tlbl1->key + 100);
5742 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5744 freeAsmop (left, NULL, ic);
5745 freeAsmop (result, NULL, ic);
5748 /*-----------------------------------------------------------------*/
5749 /* genrshOne - left shift two bytes by known amount != 0 */
5750 /*-----------------------------------------------------------------*/
5752 genrshOne (operand * result, operand * left, int shCount, int is_signed)
5755 int size = AOP_SIZE (result);
5758 wassert (size == 1);
5759 wassert (shCount < 8);
5761 l = aopGet (AOP (left), 0, FALSE);
5763 if (AOP (result)->type == AOP_REG)
5765 aopPut (AOP (result), l, 0);
5766 l = aopGet (AOP (result), 0, FALSE);
5769 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5777 emit2 ("%s a", is_signed ? "sra" : "srl");
5779 aopPut (AOP (result), "a", 0);
5783 /*-----------------------------------------------------------------*/
5784 /* AccRsh - right shift accumulator by known count */
5785 /*-----------------------------------------------------------------*/
5787 AccRsh (int shCount)
5789 static const unsigned char SRMask[] =
5791 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
5796 /* rotate right accumulator */
5797 AccRol (8 - shCount);
5798 /* and kill the higher order bits */
5799 emit2 ("and a,!immedbyte", SRMask[shCount]);
5803 /*-----------------------------------------------------------------*/
5804 /* shiftR1Left2Result - shift right one byte from left to result */
5805 /*-----------------------------------------------------------------*/
5807 shiftR1Left2Result (operand * left, int offl,
5808 operand * result, int offr,
5809 int shCount, int sign)
5811 _moveA (aopGet (AOP (left), offl, FALSE));
5816 emit2 ("%s a", sign ? "sra" : "srl");
5823 aopPut (AOP (result), "a", offr);
5826 /*-----------------------------------------------------------------*/
5827 /* genrshTwo - right shift two bytes by known amount != 0 */
5828 /*-----------------------------------------------------------------*/
5830 genrshTwo (operand * result, operand * left,
5831 int shCount, int sign)
5833 /* if shCount >= 8 */
5839 shiftR1Left2Result (left, MSB16, result, LSB,
5844 movLeft2Result (left, MSB16, result, LSB, sign);
5848 /* Sign extend the result */
5849 _moveA(aopGet (AOP (result), 0, FALSE));
5853 aopPut (AOP (result), ACC_NAME, MSB16);
5857 aopPut (AOP (result), "!zero", 1);
5860 /* 1 <= shCount <= 7 */
5863 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
5867 /*-----------------------------------------------------------------*/
5868 /* genRightShiftLiteral - left shifting by known count */
5869 /*-----------------------------------------------------------------*/
5871 genRightShiftLiteral (operand * left,
5877 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5880 freeAsmop (right, NULL, ic);
5882 aopOp (left, ic, FALSE, FALSE);
5883 aopOp (result, ic, FALSE, FALSE);
5885 size = getSize (operandType (result));
5887 /* I suppose that the left size >= result size */
5893 else if (shCount >= (size * 8)) {
5895 if (!SPEC_USIGN(getSpec(operandType(left)))) {
5896 _moveA(aopGet (AOP (left), 0, FALSE));
5904 aopPut (AOP (result), s, size);
5911 genrshOne (result, left, shCount, sign);
5914 genrshTwo (result, left, shCount, sign);
5917 wassertl (0, "Asked to shift right a long which should be a function call");
5920 wassertl (0, "Entered default case in right shift delegate");
5923 freeAsmop (left, NULL, ic);
5924 freeAsmop (result, NULL, ic);
5927 /*-----------------------------------------------------------------*/
5928 /* genRightShift - generate code for right shifting */
5929 /*-----------------------------------------------------------------*/
5931 genRightShift (iCode * ic)
5933 operand *right, *left, *result;
5935 int size, offset, first = 1;
5939 symbol *tlbl, *tlbl1;
5941 /* if signed then we do it the hard way preserve the
5942 sign bit moving it inwards */
5943 retype = getSpec (operandType (IC_RESULT (ic)));
5945 is_signed = !SPEC_USIGN (retype);
5947 /* signed & unsigned types are treated the same : i.e. the
5948 signed is NOT propagated inwards : quoting from the
5949 ANSI - standard : "for E1 >> E2, is equivalent to division
5950 by 2**E2 if unsigned or if it has a non-negative value,
5951 otherwise the result is implementation defined ", MY definition
5952 is that the sign does not get propagated */
5954 right = IC_RIGHT (ic);
5955 left = IC_LEFT (ic);
5956 result = IC_RESULT (ic);
5958 aopOp (right, ic, FALSE, FALSE);
5960 /* if the shift count is known then do it
5961 as efficiently as possible */
5962 if (AOP_TYPE (right) == AOP_LIT)
5964 genRightShiftLiteral (left, right, result, ic, is_signed);
5968 aopOp (left, ic, FALSE, FALSE);
5969 aopOp (result, ic, FALSE, FALSE);
5971 /* now move the left to the result if they are not the
5973 if (!sameRegs (AOP (left), AOP (result)) &&
5974 AOP_SIZE (result) > 1)
5977 size = AOP_SIZE (result);
5981 l = aopGet (AOP (left), offset, FALSE);
5982 aopPut (AOP (result), l, offset);
5987 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5989 freeAsmop (right, NULL, ic);
5991 tlbl = newiTempLabel (NULL);
5992 tlbl1 = newiTempLabel (NULL);
5993 size = AOP_SIZE (result);
5996 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5997 emitLabel (tlbl->key + 100);
6000 l = aopGet (AOP (result), offset--, FALSE);
6003 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6011 emitLabel (tlbl1->key + 100);
6013 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6015 freeAsmop (left, NULL, ic);
6016 freeAsmop (result, NULL, ic);
6019 /*-----------------------------------------------------------------*/
6020 /* genGenPointerGet - get value from generic pointer space */
6021 /*-----------------------------------------------------------------*/
6023 genGenPointerGet (operand * left,
6024 operand * result, iCode * ic)
6027 sym_link *retype = getSpec (operandType (result));
6033 aopOp (left, ic, FALSE, FALSE);
6034 aopOp (result, ic, FALSE, FALSE);
6036 size = AOP_SIZE (result);
6038 if (isPair (AOP (left)) && size == 1)
6041 if (isPtrPair (AOP (left)))
6043 tsprintf (buffer, sizeof(buffer),
6044 "!*pair", getPairName (AOP (left)));
6045 aopPut (AOP (result), buffer, 0);
6049 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6050 aopPut (AOP (result), "a", 0);
6052 freeAsmop (left, NULL, ic);
6056 if (getPairId (AOP (left)) == PAIR_IY)
6063 tsprintf (at, sizeof(at), "!*iyx", offset);
6064 aopPut (AOP (result), at, offset);
6068 freeAsmop (left, NULL, ic);
6072 /* For now we always load into IY */
6073 /* if this is remateriazable */
6074 fetchPair (pair, AOP (left));
6076 /* if bit then unpack */
6077 if (IS_BITVAR (retype))
6081 else if (getPairId (AOP (result)) == PAIR_HL)
6083 wassertl (size == 2, "HL must be of size 2");
6084 emit2 ("ld a,!*hl");
6086 emit2 ("ld h,!*hl");
6088 spillPair (PAIR_HL);
6090 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6092 size = AOP_SIZE (result);
6097 /* PENDING: make this better */
6098 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6100 aopPut (AOP (result), "!*hl", offset++);
6104 emit2 ("ld a,!*pair", _pairs[pair].name);
6105 aopPut (AOP (result), "a", offset++);
6109 emit2 ("inc %s", _pairs[pair].name);
6110 _G.pairs[pair].offset++;
6113 /* Fixup HL back down */
6114 for (size = AOP_SIZE (result)-1; size; size--)
6116 emit2 ("dec %s", _pairs[pair].name);
6121 size = AOP_SIZE (result);
6126 /* PENDING: make this better */
6128 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6130 aopPut (AOP (result), "!*hl", offset++);
6134 emit2 ("ld a,!*pair", _pairs[pair].name);
6135 aopPut (AOP (result), "a", offset++);
6139 emit2 ("inc %s", _pairs[pair].name);
6140 _G.pairs[pair].offset++;
6145 freeAsmop (left, NULL, ic);
6148 freeAsmop (result, NULL, ic);
6151 /*-----------------------------------------------------------------*/
6152 /* genPointerGet - generate code for pointer get */
6153 /*-----------------------------------------------------------------*/
6155 genPointerGet (iCode * ic)
6157 operand *left, *result;
6158 sym_link *type, *etype;
6160 left = IC_LEFT (ic);
6161 result = IC_RESULT (ic);
6163 /* depending on the type of pointer we need to
6164 move it to the correct pointer register */
6165 type = operandType (left);
6166 etype = getSpec (type);
6168 genGenPointerGet (left, result, ic);
6172 isRegOrLit (asmop * aop)
6174 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6179 /*-----------------------------------------------------------------*/
6180 /* genGenPointerSet - stores the value into a pointer location */
6181 /*-----------------------------------------------------------------*/
6183 genGenPointerSet (operand * right,
6184 operand * result, iCode * ic)
6187 sym_link *retype = getSpec (operandType (right));
6188 PAIR_ID pairId = PAIR_HL;
6190 aopOp (result, ic, FALSE, FALSE);
6191 aopOp (right, ic, FALSE, FALSE);
6196 size = AOP_SIZE (right);
6198 /* Handle the exceptions first */
6199 if (isPair (AOP (result)) && size == 1)
6202 const char *l = aopGet (AOP (right), 0, FALSE);
6203 const char *pair = getPairName (AOP (result));
6204 if (canAssignToPtr (l) && isPtr (pair))
6206 emit2 ("ld !*pair,%s", pair, l);
6211 emit2 ("ld !*pair,a", pair);
6216 if ( getPairId( AOP (result)) == PAIR_IY)
6219 const char *l = aopGet (AOP (right), 0, FALSE);
6224 if (canAssignToPtr (l))
6226 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6230 _moveA (aopGet (AOP (right), offset, FALSE));
6231 emit2 ("ld !*iyx,a", offset);
6237 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result))
6243 const char *l = aopGet (AOP (right), offset, FALSE);
6244 if (isRegOrLit (AOP (right)) && !IS_GB)
6246 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
6251 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
6255 emit2 ("inc %s", _pairs[PAIR_HL].name);
6256 _G.pairs[PAIR_HL].offset++;
6261 /* Fixup HL back down */
6262 for (size = AOP_SIZE (right)-1; size; size--)
6264 emit2 ("dec %s", _pairs[PAIR_HL].name);
6269 /* if the operand is already in dptr
6270 then we do nothing else we move the value to dptr */
6271 if (AOP_TYPE (result) != AOP_STR)
6273 fetchPair (pairId, AOP (result));
6275 /* so hl know contains the address */
6276 freeAsmop (result, NULL, ic);
6278 /* if bit then unpack */
6279 if (IS_BITVAR (retype))
6289 const char *l = aopGet (AOP (right), offset, FALSE);
6290 if (isRegOrLit (AOP (right)) && !IS_GB)
6292 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
6297 emit2 ("ld !*pair,a", _pairs[pairId].name);
6301 emit2 ("inc %s", _pairs[pairId].name);
6302 _G.pairs[pairId].offset++;
6308 freeAsmop (right, NULL, ic);
6311 /*-----------------------------------------------------------------*/
6312 /* genPointerSet - stores the value into a pointer location */
6313 /*-----------------------------------------------------------------*/
6315 genPointerSet (iCode * ic)
6317 operand *right, *result;
6318 sym_link *type, *etype;
6320 right = IC_RIGHT (ic);
6321 result = IC_RESULT (ic);
6323 /* depending on the type of pointer we need to
6324 move it to the correct pointer register */
6325 type = operandType (result);
6326 etype = getSpec (type);
6328 genGenPointerSet (right, result, ic);
6331 /*-----------------------------------------------------------------*/
6332 /* genIfx - generate code for Ifx statement */
6333 /*-----------------------------------------------------------------*/
6335 genIfx (iCode * ic, iCode * popIc)
6337 operand *cond = IC_COND (ic);
6340 aopOp (cond, ic, FALSE, TRUE);
6342 /* get the value into acc */
6343 if (AOP_TYPE (cond) != AOP_CRY)
6347 /* the result is now in the accumulator */
6348 freeAsmop (cond, NULL, ic);
6350 /* if there was something to be popped then do it */
6354 /* if the condition is a bit variable */
6355 if (isbit && IS_ITEMP (cond) &&
6357 genIfxJump (ic, SPIL_LOC (cond)->rname);
6358 else if (isbit && !IS_ITEMP (cond))
6359 genIfxJump (ic, OP_SYMBOL (cond)->rname);
6361 genIfxJump (ic, "a");
6366 /*-----------------------------------------------------------------*/
6367 /* genAddrOf - generates code for address of */
6368 /*-----------------------------------------------------------------*/
6370 genAddrOf (iCode * ic)
6372 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
6374 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6376 /* if the operand is on the stack then we
6377 need to get the stack offset of this
6384 if (sym->stack <= 0)
6386 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
6390 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6392 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6396 emit2 ("ld de,!hashedstr", sym->rname);
6397 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
6405 /* if it has an offset then we need to compute it */
6407 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6409 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
6410 emit2 ("add hl,sp");
6414 emit2 ("ld hl,!hashedstr", sym->rname);
6416 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6418 freeAsmop (IC_RESULT (ic), NULL, ic);
6421 /*-----------------------------------------------------------------*/
6422 /* genAssign - generate code for assignment */
6423 /*-----------------------------------------------------------------*/
6425 genAssign (iCode * ic)
6427 operand *result, *right;
6429 unsigned long lit = 0L;
6431 result = IC_RESULT (ic);
6432 right = IC_RIGHT (ic);
6434 /* Dont bother assigning if they are the same */
6435 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6437 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
6441 aopOp (right, ic, FALSE, FALSE);
6442 aopOp (result, ic, TRUE, FALSE);
6444 /* if they are the same registers */
6445 if (sameRegs (AOP (right), AOP (result)))
6447 emitDebug ("; (registers are the same)");
6451 /* if the result is a bit */
6452 if (AOP_TYPE (result) == AOP_CRY)
6454 wassertl (0, "Tried to assign to a bit");
6458 size = AOP_SIZE (result);
6461 if (AOP_TYPE (right) == AOP_LIT)
6463 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6466 if (isPair (AOP (result)))
6468 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
6470 else if ((size > 1) &&
6471 (AOP_TYPE (result) != AOP_REG) &&
6472 (AOP_TYPE (right) == AOP_LIT) &&
6473 !IS_FLOAT (operandType (right)) &&
6476 bool fXored = FALSE;
6478 /* Work from the top down.
6479 Done this way so that we can use the cached copy of 0
6480 in A for a fast clear */
6483 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
6485 if (!fXored && size > 1)
6492 aopPut (AOP (result), "a", offset);
6496 aopPut (AOP (result), "!zero", offset);
6500 aopPut (AOP (result),
6501 aopGet (AOP (right), offset, FALSE),
6506 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
6508 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
6509 aopPut (AOP (result), "l", LSB);
6510 aopPut (AOP (result), "h", MSB16);
6512 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6514 /* Special case. Load into a and d, then load out. */
6515 _moveA (aopGet (AOP (right), 0, FALSE));
6516 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
6517 aopPut (AOP (result), "a", 0);
6518 aopPut (AOP (result), "e", 1);
6520 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6522 /* Special case - simple memcpy */
6523 aopGet (AOP (right), LSB, FALSE);
6526 aopGet (AOP (result), LSB, FALSE);
6530 emit2 ("ld a,(de)");
6531 /* Peephole will optimise this. */
6532 emit2 ("ld (hl),a");
6540 spillPair (PAIR_HL);
6546 /* PENDING: do this check better */
6547 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
6549 _moveA (aopGet (AOP (right), offset, FALSE));
6550 aopPut (AOP (result), "a", offset);
6553 aopPut (AOP (result),
6554 aopGet (AOP (right), offset, FALSE),
6561 freeAsmop (right, NULL, ic);
6562 freeAsmop (result, NULL, ic);
6565 /*-----------------------------------------------------------------*/
6566 /* genJumpTab - genrates code for jump table */
6567 /*-----------------------------------------------------------------*/
6569 genJumpTab (iCode * ic)
6574 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
6575 /* get the condition into accumulator */
6576 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
6579 emit2 ("ld e,%s", l);
6580 emit2 ("ld d,!zero");
6581 jtab = newiTempLabel (NULL);
6583 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
6584 emit2 ("add hl,de");
6585 emit2 ("add hl,de");
6586 emit2 ("add hl,de");
6587 freeAsmop (IC_JTCOND (ic), NULL, ic);
6591 emitLabel (jtab->key + 100);
6592 /* now generate the jump labels */
6593 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
6594 jtab = setNextItem (IC_JTLABELS (ic)))
6595 emit2 ("jp !tlabel", jtab->key + 100);
6598 /*-----------------------------------------------------------------*/
6599 /* genCast - gen code for casting */
6600 /*-----------------------------------------------------------------*/
6602 genCast (iCode * ic)
6604 operand *result = IC_RESULT (ic);
6605 sym_link *rtype = operandType (IC_RIGHT (ic));
6606 operand *right = IC_RIGHT (ic);
6609 /* if they are equivalent then do nothing */
6610 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6613 aopOp (right, ic, FALSE, FALSE);
6614 aopOp (result, ic, FALSE, FALSE);
6616 /* if the result is a bit */
6617 if (AOP_TYPE (result) == AOP_CRY)
6619 wassertl (0, "Tried to cast to a bit");
6622 /* if they are the same size : or less */
6623 if (AOP_SIZE (result) <= AOP_SIZE (right))
6626 /* if they are in the same place */
6627 if (sameRegs (AOP (right), AOP (result)))
6630 /* if they in different places then copy */
6631 size = AOP_SIZE (result);
6635 aopPut (AOP (result),
6636 aopGet (AOP (right), offset, FALSE),
6643 /* So we now know that the size of destination is greater
6644 than the size of the source */
6645 /* we move to result for the size of source */
6646 size = AOP_SIZE (right);
6650 aopPut (AOP (result),
6651 aopGet (AOP (right), offset, FALSE),
6656 /* now depending on the sign of the destination */
6657 size = AOP_SIZE (result) - AOP_SIZE (right);
6658 /* Unsigned or not an integral type - right fill with zeros */
6659 if (SPEC_USIGN (rtype) || !IS_SPEC (rtype) || AOP_TYPE(right)==AOP_CRY)
6662 aopPut (AOP (result), "!zero", offset++);
6666 /* we need to extend the sign :{ */
6667 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
6673 aopPut (AOP (result), "a", offset++);
6677 freeAsmop (right, NULL, ic);
6678 freeAsmop (result, NULL, ic);
6681 /*-----------------------------------------------------------------*/
6682 /* genReceive - generate code for a receive iCode */
6683 /*-----------------------------------------------------------------*/
6685 genReceive (iCode * ic)
6687 if (isOperandInFarSpace (IC_RESULT (ic)) &&
6688 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
6689 IS_TRUE_SYMOP (IC_RESULT (ic))))
6699 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6700 size = AOP_SIZE(IC_RESULT(ic));
6702 for (i = 0; i < size; i++) {
6703 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
6707 freeAsmop (IC_RESULT (ic), NULL, ic);
6712 /** Maximum number of bytes to emit per line. */
6716 /** Context for the byte output chunker. */
6719 unsigned char buffer[DBEMIT_MAX_RUN];
6724 /** Flushes a byte chunker by writing out all in the buffer and
6728 _dbFlush(DBEMITCTX *self)
6735 sprintf(line, ".db 0x%02X", self->buffer[0]);
6737 for (i = 1; i < self->pos; i++)
6739 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
6746 /** Write out another byte, buffering until a decent line is
6750 _dbEmit(DBEMITCTX *self, int c)
6752 if (self->pos == DBEMIT_MAX_RUN)
6756 self->buffer[self->pos++] = c;
6759 /** Context for a simple run length encoder. */
6763 unsigned char buffer[128];
6765 /** runLen may be equivalent to pos. */
6771 RLE_CHANGE_COST = 4,
6775 /** Flush the buffer of a run length encoder by writing out the run or
6776 data that it currently contains.
6779 _rleCommit(RLECTX *self)
6785 memset(&db, 0, sizeof(db));
6787 emit2(".db %u", self->pos);
6789 for (i = 0; i < self->pos; i++)
6791 _dbEmit(&db, self->buffer[i]);
6800 Can get either a run or a block of random stuff.
6801 Only want to change state if a good run comes in or a run ends.
6802 Detecting run end is easy.
6805 Say initial state is in run, len zero, last zero. Then if you get a
6806 few zeros then something else then a short run will be output.
6807 Seems OK. While in run mode, keep counting. While in random mode,
6808 keep a count of the run. If run hits margin, output all up to run,
6809 restart, enter run mode.
6812 /** Add another byte into the run length encoder, flushing as
6813 required. The run length encoder uses the Amiga IFF style, where
6814 a block is prefixed by its run length. A positive length means
6815 the next n bytes pass straight through. A negative length means
6816 that the next byte is repeated -n times. A zero terminates the
6820 _rleAppend(RLECTX *self, int c)
6824 if (c != self->last)
6826 /* The run has stopped. See if it is worthwhile writing it out
6827 as a run. Note that the random data comes in as runs of
6830 if (self->runLen > RLE_CHANGE_COST)
6832 /* Yes, worthwhile. */
6833 /* Commit whatever was in the buffer. */
6835 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
6839 /* Not worthwhile. Append to the end of the random list. */
6840 for (i = 0; i < self->runLen; i++)
6842 if (self->pos >= RLE_MAX_BLOCK)
6847 self->buffer[self->pos++] = self->last;
6855 if (self->runLen >= RLE_MAX_BLOCK)
6857 /* Commit whatever was in the buffer. */
6860 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
6868 _rleFlush(RLECTX *self)
6870 _rleAppend(self, -1);
6877 /** genArrayInit - Special code for initialising an array with constant
6881 genArrayInit (iCode * ic)
6885 int elementSize = 0, eIndex, i;
6886 unsigned val, lastVal;
6890 memset(&rle, 0, sizeof(rle));
6892 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
6894 _saveRegsForCall(ic, 0);
6896 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
6897 emit2 ("call __initrleblock");
6899 type = operandType(IC_LEFT(ic));
6901 if (type && type->next)
6903 elementSize = getSize(type->next);
6907 wassertl (0, "Can't determine element size in genArrayInit.");
6910 iLoop = IC_ARRAYILIST(ic);
6911 lastVal = (unsigned)-1;
6913 /* Feed all the bytes into the run length encoder which will handle
6915 This works well for mixed char data, and for random int and long
6924 for (i = 0; i < ix; i++)
6926 for (eIndex = 0; eIndex < elementSize; eIndex++)
6928 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
6929 _rleAppend(&rle, val);
6934 iLoop = iLoop->next;
6938 /* Mark the end of the run. */
6941 _restoreRegsAfterCall();
6945 freeAsmop (IC_LEFT(ic), NULL, ic);
6949 _swap (PAIR_ID one, PAIR_ID two)
6951 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
6957 emit2 ("ld a,%s", _pairs[one].l);
6958 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
6959 emit2 ("ld %s,a", _pairs[two].l);
6960 emit2 ("ld a,%s", _pairs[one].h);
6961 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
6962 emit2 ("ld %s,a", _pairs[two].h);
6966 /* The problem is that we may have all three pairs used and they may
6967 be needed in a different order.
6972 hl = hl => unity, fine
6976 hl = hl hl = hl, swap de <=> bc
6984 hl = bc de = de, swap bc <=> hl
6992 hl = de bc = bc, swap hl <=> de
6997 * Any pair = pair are done last
6998 * Any pair = iTemp are done last
6999 * Any swaps can be done any time
7007 So how do we detect the cases?
7008 How about a 3x3 matrix?
7012 x x x x (Fourth for iTemp/other)
7014 First determin which mode to use by counting the number of unity and
7017 Two - Assign the pair first, then the rest
7018 One - Swap the two, then the rest
7022 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7024 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7026 PAIR_BC, PAIR_HL, PAIR_DE
7028 int i, j, nunity = 0;
7029 memset (ids, PAIR_INVALID, sizeof (ids));
7032 wassert (nparams == 3);
7034 /* First save everything that needs to be saved. */
7035 _saveRegsForCall (ic, 0);
7037 /* Loading HL first means that DE is always fine. */
7038 for (i = 0; i < nparams; i++)
7040 aopOp (pparams[i], ic, FALSE, FALSE);
7041 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7044 /* Count the number of unity or iTemp assigns. */
7045 for (i = 0; i < 3; i++)
7047 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7055 /* Any order, fall through. */
7057 else if (nunity == 2)
7059 /* One is assigned. Pull it out and assign. */
7060 for (i = 0; i < 3; i++)
7062 for (j = 0; j < NUM_PAIRS; j++)
7064 if (ids[dest[i]][j] == TRUE)
7066 /* Found it. See if it's the right one. */
7067 if (j == PAIR_INVALID || j == dest[i])
7073 fetchPair(dest[i], AOP (pparams[i]));
7080 else if (nunity == 1)
7082 /* Find the pairs to swap. */
7083 for (i = 0; i < 3; i++)
7085 for (j = 0; j < NUM_PAIRS; j++)
7087 if (ids[dest[i]][j] == TRUE)
7089 if (j == PAIR_INVALID || j == dest[i])
7104 int next = getPairId (AOP (pparams[0]));
7105 emit2 ("push %s", _pairs[next].name);
7107 if (next == dest[1])
7109 fetchPair (dest[1], AOP (pparams[1]));
7110 fetchPair (dest[2], AOP (pparams[2]));
7114 fetchPair (dest[2], AOP (pparams[2]));
7115 fetchPair (dest[1], AOP (pparams[1]));
7117 emit2 ("pop %s", _pairs[dest[0]].name);
7120 /* Finally pull out all of the iTemps */
7121 for (i = 0; i < 3; i++)
7123 if (ids[dest[i]][PAIR_INVALID] == 1)
7125 fetchPair (dest[i], AOP (pparams[i]));
7131 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
7137 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
7141 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7143 setupForBuiltin3 (ic, nParams, pparams);
7145 label = newiTempLabel(NULL);
7147 emitLabel (label->key);
7148 emit2 ("ld a,(hl)");
7151 emit2 ("!shortjp nz,!tlabel ; 1", label->key);
7153 freeAsmop (from, NULL, ic->next);
7154 freeAsmop (to, NULL, ic);
7158 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
7160 operand *from, *to, *count;
7163 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
7168 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7170 setupForBuiltin3 (ic, nParams, pparams);
7174 freeAsmop (count, NULL, ic->next->next);
7175 freeAsmop (from, NULL, ic);
7177 _restoreRegsAfterCall();
7179 /* if we need assign a result value */
7180 if ((IS_ITEMP (IC_RESULT (ic)) &&
7181 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
7182 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
7183 IS_TRUE_SYMOP (IC_RESULT (ic)))
7185 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7186 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
7187 freeAsmop (IC_RESULT (ic), NULL, ic);
7190 freeAsmop (to, NULL, ic->next);
7193 /*-----------------------------------------------------------------*/
7194 /* genBuiltIn - calls the appropriate function to generating code */
7195 /* for a built in function */
7196 /*-----------------------------------------------------------------*/
7197 static void genBuiltIn (iCode *ic)
7199 operand *bi_parms[MAX_BUILTIN_ARGS];
7204 /* get all the arguments for a built in function */
7205 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
7207 /* which function is it */
7208 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
7210 if (strcmp(bif->name,"__builtin_strcpy")==0)
7212 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
7214 else if (strcmp(bif->name,"__builtin_memcpy")==0)
7216 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
7220 wassertl (0, "Unknown builtin function encountered");
7224 /*-----------------------------------------------------------------*/
7225 /* genZ80Code - generate code for Z80 based controllers */
7226 /*-----------------------------------------------------------------*/
7228 genZ80Code (iCode * lic)
7236 _fReturn = _gbz80_return;
7237 _fTmp = _gbz80_return;
7241 _fReturn = _z80_return;
7242 _fTmp = _z80_return;
7245 _G.lines.head = _G.lines.current = NULL;
7247 for (ic = lic; ic; ic = ic->next)
7250 if (cln != ic->lineno)
7252 if (!options.noCcodeInAsm) {
7253 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
7254 printCLine(ic->filename, ic->lineno));
7258 if (options.iCodeInAsm) {
7259 emit2 (";ic:%d: %s", ic->key, printILine(ic));
7261 /* if the result is marked as
7262 spilt and rematerializable or code for
7263 this has already been generated then
7265 if (resultRemat (ic) || ic->generated)
7268 /* depending on the operation */
7272 emitDebug ("; genNot");
7277 emitDebug ("; genCpl");
7282 emitDebug ("; genUminus");
7287 emitDebug ("; genIpush");
7292 /* IPOP happens only when trying to restore a
7293 spilt live range, if there is an ifx statement
7294 following this pop then the if statement might
7295 be using some of the registers being popped which
7296 would destory the contents of the register so
7297 we need to check for this condition and handle it */
7299 ic->next->op == IFX &&
7300 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
7302 emitDebug ("; genIfx");
7303 genIfx (ic->next, ic);
7307 emitDebug ("; genIpop");
7313 emitDebug ("; genCall");
7318 emitDebug ("; genPcall");
7323 emitDebug ("; genFunction");
7328 emitDebug ("; genEndFunction");
7329 genEndFunction (ic);
7333 emitDebug ("; genRet");
7338 emitDebug ("; genLabel");
7343 emitDebug ("; genGoto");
7348 emitDebug ("; genPlus");
7353 emitDebug ("; genMinus");
7358 emitDebug ("; genMult");
7363 emitDebug ("; genDiv");
7368 emitDebug ("; genMod");
7373 emitDebug ("; genCmpGt");
7374 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
7378 emitDebug ("; genCmpLt");
7379 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
7386 /* note these two are xlated by algebraic equivalence
7387 during parsing SDCC.y */
7388 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
7389 "got '>=' or '<=' shouldn't have come here");
7393 emitDebug ("; genCmpEq");
7394 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
7398 emitDebug ("; genAndOp");
7403 emitDebug ("; genOrOp");
7408 emitDebug ("; genXor");
7409 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
7413 emitDebug ("; genOr");
7414 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
7418 emitDebug ("; genAnd");
7419 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
7423 emitDebug ("; genInline");
7428 emitDebug ("; genRRC");
7433 emitDebug ("; genRLC");
7438 emitDebug ("; genGetHBIT");
7443 emitDebug ("; genLeftShift");
7448 emitDebug ("; genRightShift");
7452 case GET_VALUE_AT_ADDRESS:
7453 emitDebug ("; genPointerGet");
7459 if (POINTER_SET (ic))
7461 emitDebug ("; genAssign (pointer)");
7466 emitDebug ("; genAssign");
7472 emitDebug ("; genIfx");
7477 emitDebug ("; genAddrOf");
7482 emitDebug ("; genJumpTab");
7487 emitDebug ("; genCast");
7492 emitDebug ("; genReceive");
7497 if (ic->builtinSEND)
7499 emitDebug ("; genBuiltIn");
7504 emitDebug ("; addSet");
7505 addSet (&_G.sendSet, ic);
7510 emitDebug ("; genArrayInit");
7520 /* now we are ready to call the
7521 peep hole optimizer */
7522 if (!options.nopeep)
7523 peepHole (&_G.lines.head);
7525 /* This is unfortunate */
7526 /* now do the actual printing */
7528 FILE *fp = codeOutFile;
7529 if (isInHome () && codeOutFile == code->oFile)
7530 codeOutFile = home->oFile;
7531 printLine (_G.lines.head, codeOutFile);
7532 if (_G.flushStatics)
7535 _G.flushStatics = 0;
7540 freeTrace(&_G.lines.trace);
7541 freeTrace(&_G.trace.aops);
7547 _isPairUsed (iCode * ic, PAIR_ID pairId)
7553 if (bitVectBitValue (ic->rMask, D_IDX))
7555 if (bitVectBitValue (ic->rMask, E_IDX))
7565 fetchLitSpecial (asmop * aop, bool negate, bool xor)
7568 value *val = aop->aopu.aop_lit;
7570 wassert (aop->type == AOP_LIT);
7571 wassert (!IS_FLOAT (val->type));
7573 v = (unsigned long) floatFromVal (val);
7581 tsprintf (buffer, sizeof(buffer), "!immedword", v);
7582 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));