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)
1837 aopPut (aop, "a", 0);
1839 aopPut (aop, "d", 1);
1844 if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
1846 char *l = aopGetLitWordLong (aop, 0, FALSE);
1849 emit2 ("ld (%s),%s", l, _pairs[id].name);
1853 aopPut (aop, _pairs[id].l, 0);
1855 aopPut (aop, _pairs[id].h, 1);
1860 /*-----------------------------------------------------------------*/
1861 /* getDataSize - get the operand data size */
1862 /*-----------------------------------------------------------------*/
1864 getDataSize (operand * op)
1867 size = AOP_SIZE (op);
1871 wassertl (0, "Somehow got a three byte data pointer");
1876 /*-----------------------------------------------------------------*/
1877 /* movLeft2Result - move byte from left to result */
1878 /*-----------------------------------------------------------------*/
1880 movLeft2Result (operand * left, int offl,
1881 operand * result, int offr, int sign)
1885 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
1887 l = aopGet (AOP (left), offl, FALSE);
1891 aopPut (AOP (result), l, offr);
1895 if (getDataSize (left) == offl + 1)
1897 emit2 ("ld a,%s", l);
1898 aopPut (AOP (result), "a", offr);
1905 movLeft2ResultLong (operand * left, int offl,
1906 operand * result, int offr, int sign,
1911 movLeft2Result (left, offl, result, offr, sign);
1915 wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
1916 wassertl (size == 2, "Only implemented for two bytes or one");
1918 if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
1920 emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
1921 emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
1923 spillPair (PAIR_HL);
1925 else if ( getPairId ( AOP (result)) == PAIR_IY)
1927 PAIR_ID id = getPairId (AOP (left));
1928 if (id != PAIR_INVALID)
1930 emit2("push %s", _pairs[id].name);
1941 movLeft2Result (left, offl, result, offr, sign);
1942 movLeft2Result (left, offl+1, result, offr+1, sign);
1947 /** Put Acc into a register set
1950 outAcc (operand * result)
1953 size = getDataSize (result);
1956 aopPut (AOP (result), "a", 0);
1959 /* unsigned or positive */
1962 aopPut (AOP (result), "!zero", offset++);
1967 /** Take the value in carry and put it into a register
1970 outBitCLong (operand * result, bool swap_sense)
1972 /* if the result is bit */
1973 if (AOP_TYPE (result) == AOP_CRY)
1975 wassertl (0, "Tried to write carry to a bit");
1979 emit2 ("ld a,!zero");
1982 emit2 ("xor a,!immedbyte", 1);
1988 outBitC (operand * result)
1990 outBitCLong (result, FALSE);
1993 /*-----------------------------------------------------------------*/
1994 /* toBoolean - emit code for orl a,operator(sizeop) */
1995 /*-----------------------------------------------------------------*/
1997 _toBoolean (operand * oper)
1999 int size = AOP_SIZE (oper);
2003 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
2006 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
2010 if (AOP (oper)->type != AOP_ACC)
2013 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
2018 /*-----------------------------------------------------------------*/
2019 /* genNotFloat - generates not for float operations */
2020 /*-----------------------------------------------------------------*/
2022 genNotFloat (operand * op, operand * res)
2027 emitDebug ("; genNotFloat");
2029 /* we will put 127 in the first byte of
2031 aopPut (AOP (res), "!immedbyte", 0x7F);
2032 size = AOP_SIZE (op) - 1;
2035 _moveA (aopGet (op->aop, offset++, FALSE));
2039 emit2 ("or a,%s", aopGet (op->aop, offset++, FALSE));
2042 tlbl = newiTempLabel (NULL);
2043 aopPut (res->aop, "!one", 1);
2044 emit2 ("!shortjp z !tlabel", tlbl->key + 100);
2045 aopPut (res->aop, "!zero", 1);
2047 emitLabel(tlbl->key + 100);
2049 size = res->aop->size - 2;
2051 /* put zeros in the rest */
2053 aopPut (res->aop, "!zero", offset++);
2056 /*-----------------------------------------------------------------*/
2057 /* genNot - generate code for ! operation */
2058 /*-----------------------------------------------------------------*/
2062 sym_link *optype = operandType (IC_LEFT (ic));
2064 /* assign asmOps to operand & result */
2065 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
2066 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2068 /* if in bit space then a special case */
2069 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2071 wassertl (0, "Tried to negate a bit");
2074 /* if type float then do float */
2075 if (IS_FLOAT (optype))
2077 genNotFloat (IC_LEFT (ic), IC_RESULT (ic));
2081 _toBoolean (IC_LEFT (ic));
2086 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
2087 emit2 ("sub a,!one");
2088 outBitC (IC_RESULT (ic));
2091 /* release the aops */
2092 freeAsmop (IC_LEFT (ic), NULL, ic);
2093 freeAsmop (IC_RESULT (ic), NULL, ic);
2096 /*-----------------------------------------------------------------*/
2097 /* genCpl - generate code for complement */
2098 /*-----------------------------------------------------------------*/
2106 /* assign asmOps to operand & result */
2107 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2108 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2110 /* if both are in bit space then
2112 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2113 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2115 wassertl (0, "Left and the result are in bit space");
2118 size = AOP_SIZE (IC_RESULT (ic));
2121 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2124 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2127 /* release the aops */
2128 freeAsmop (IC_LEFT (ic), NULL, ic);
2129 freeAsmop (IC_RESULT (ic), NULL, ic);
2133 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
2140 store de into result
2145 store de into result
2147 const char *first = isAdd ? "add" : "sub";
2148 const char *later = isAdd ? "adc" : "sbc";
2150 wassertl (IS_GB, "Code is only relevent to the gbz80");
2151 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
2153 fetchPair (PAIR_DE, left);
2156 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
2159 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2162 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2163 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2165 fetchPairLong (PAIR_DE, left, NULL, MSB24);
2166 aopGet (right, MSB24, FALSE);
2170 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2173 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2175 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2176 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2180 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2182 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2185 /*-----------------------------------------------------------------*/
2186 /* genUminusFloat - unary minus for floating points */
2187 /*-----------------------------------------------------------------*/
2189 genUminusFloat (operand * op, operand * result)
2191 int size, offset = 0;
2193 emitDebug("; genUminusFloat");
2195 /* for this we just need to flip the
2196 first it then copy the rest in place */
2197 size = AOP_SIZE (op) - 1;
2199 _moveA(aopGet (AOP (op), MSB32, FALSE));
2201 emit2("xor a,!immedbyte", 0x80);
2202 aopPut (AOP (result), "a", MSB32);
2206 aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2211 /*-----------------------------------------------------------------*/
2212 /* genUminus - unary minus code generation */
2213 /*-----------------------------------------------------------------*/
2215 genUminus (iCode * ic)
2218 sym_link *optype, *rtype;
2221 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2222 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2224 /* if both in bit space then special
2226 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2227 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2229 wassertl (0, "Left and right are in bit space");
2233 optype = operandType (IC_LEFT (ic));
2234 rtype = operandType (IC_RESULT (ic));
2236 /* if float then do float stuff */
2237 if (IS_FLOAT (optype))
2239 genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2243 /* otherwise subtract from zero */
2244 size = AOP_SIZE (IC_LEFT (ic));
2246 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2248 /* Create a new asmop with value zero */
2249 asmop *azero = newAsmop (AOP_SIMPLELIT);
2250 azero->aopu.aop_simplelit = 0;
2252 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2260 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2261 emit2 ("ld a,!zero");
2262 emit2 ("sbc a,%s", l);
2263 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2266 /* if any remaining bytes in the result */
2267 /* we just need to propagate the sign */
2268 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2273 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2277 /* release the aops */
2278 freeAsmop (IC_LEFT (ic), NULL, ic);
2279 freeAsmop (IC_RESULT (ic), NULL, ic);
2282 /*-----------------------------------------------------------------*/
2283 /* assignResultValue - */
2284 /*-----------------------------------------------------------------*/
2286 assignResultValue (operand * oper)
2288 int size = AOP_SIZE (oper);
2291 wassertl (size <= 4, "Got a result that is bigger than four bytes");
2292 topInA = requiresHL (AOP (oper));
2294 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2296 /* We do it the hard way here. */
2298 aopPut (AOP (oper), _fReturn[0], 0);
2299 aopPut (AOP (oper), _fReturn[1], 1);
2301 aopPut (AOP (oper), _fReturn[0], 2);
2302 aopPut (AOP (oper), _fReturn[1], 3);
2308 aopPut (AOP (oper), _fReturn[size], size);
2313 /** Simple restore that doesn't take into account what is used in the
2317 _restoreRegsAfterCall(void)
2319 if (_G.stack.pushedDE)
2322 _G.stack.pushedDE = FALSE;
2324 if (_G.stack.pushedBC)
2327 _G.stack.pushedBC = FALSE;
2329 _G.saves.saved = FALSE;
2333 _saveRegsForCall(iCode *ic, int sendSetSize)
2336 o Stack parameters are pushed before this function enters
2337 o DE and BC may be used in this function.
2338 o HL and DE may be used to return the result.
2339 o HL and DE may be used to send variables.
2340 o DE and BC may be used to store the result value.
2341 o HL may be used in computing the sent value of DE
2342 o The iPushes for other parameters occur before any addSets
2344 Logic: (to be run inside the first iPush or if none, before sending)
2345 o Compute if DE and/or BC are in use over the call
2346 o Compute if DE is used in the send set
2347 o Compute if DE and/or BC are used to hold the result value
2348 o If (DE is used, or in the send set) and is not used in the result, push.
2349 o If BC is used and is not in the result, push
2351 o If DE is used in the send set, fetch
2352 o If HL is used in the send set, fetch
2356 if (_G.saves.saved == FALSE) {
2357 bool deInUse, bcInUse;
2359 bool bcInRet = FALSE, deInRet = FALSE;
2362 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
2364 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2365 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2367 deSending = (sendSetSize > 1);
2369 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2371 if (bcInUse && bcInRet == FALSE) {
2373 _G.stack.pushedBC = TRUE;
2375 if (deInUse && deInRet == FALSE) {
2377 _G.stack.pushedDE = TRUE;
2380 _G.saves.saved = TRUE;
2383 /* Already saved. */
2387 /*-----------------------------------------------------------------*/
2388 /* genIpush - genrate code for pushing this gets a little complex */
2389 /*-----------------------------------------------------------------*/
2391 genIpush (iCode * ic)
2393 int size, offset = 0;
2396 /* if this is not a parm push : ie. it is spill push
2397 and spill push is always done on the local stack */
2400 wassertl(0, "Encountered an unsupported spill push.");
2404 if (_G.saves.saved == FALSE) {
2405 /* Caller saves, and this is the first iPush. */
2406 /* Scan ahead until we find the function that we are pushing parameters to.
2407 Count the number of addSets on the way to figure out what registers
2408 are used in the send set.
2411 iCode *walk = ic->next;
2414 if (walk->op == SEND) {
2417 else if (walk->op == CALL || walk->op == PCALL) {
2426 _saveRegsForCall(walk, nAddSets);
2429 /* Already saved by another iPush. */
2432 /* then do the push */
2433 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2435 size = AOP_SIZE (IC_LEFT (ic));
2437 if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2439 _G.stack.pushed += 2;
2440 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2446 fetchHL (AOP (IC_LEFT (ic)));
2448 spillPair (PAIR_HL);
2449 _G.stack.pushed += 2;
2454 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
2456 spillPair (PAIR_HL);
2457 _G.stack.pushed += 2;
2458 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
2460 spillPair (PAIR_HL);
2461 _G.stack.pushed += 2;
2467 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2469 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2471 emit2 ("ld a,(%s)", l);
2475 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2476 emit2 ("ld a,%s", l);
2484 freeAsmop (IC_LEFT (ic), NULL, ic);
2487 /*-----------------------------------------------------------------*/
2488 /* genIpop - recover the registers: can happen only for spilling */
2489 /*-----------------------------------------------------------------*/
2491 genIpop (iCode * ic)
2496 /* if the temp was not pushed then */
2497 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2500 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2501 size = AOP_SIZE (IC_LEFT (ic));
2502 offset = (size - 1);
2503 if (isPair (AOP (IC_LEFT (ic))))
2505 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2513 spillPair (PAIR_HL);
2514 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2518 freeAsmop (IC_LEFT (ic), NULL, ic);
2521 /* This is quite unfortunate */
2523 setArea (int inHome)
2526 static int lastArea = 0;
2528 if (_G.in_home != inHome) {
2530 const char *sz = port->mem.code_name;
2531 port->mem.code_name = "HOME";
2532 emit2("!area", CODE_NAME);
2533 port->mem.code_name = sz;
2536 emit2("!area", CODE_NAME); */
2537 _G.in_home = inHome;
2548 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2552 symbol *sym = OP_SYMBOL (op);
2554 if (sym->isspilt || sym->nRegs == 0)
2557 aopOp (op, ic, FALSE, FALSE);
2560 if (aop->type == AOP_REG)
2563 for (i = 0; i < aop->size; i++)
2565 if (pairId == PAIR_DE)
2567 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2568 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2570 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2573 else if (pairId == PAIR_BC)
2575 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2576 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2578 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2588 freeAsmop (IC_LEFT (ic), NULL, ic);
2592 /** Emit the code for a call statement
2595 emitCall (iCode * ic, bool ispcall)
2597 sym_link *dtype = operandType (IC_LEFT (ic));
2599 /* if caller saves & we have not saved then */
2605 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2607 /* if send set is not empty then assign */
2612 int nSend = elementsInSet(_G.sendSet);
2613 bool swapped = FALSE;
2615 int _z80_sendOrder[] = {
2620 /* Check if the parameters are swapped. If so route through hl instead. */
2621 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2623 sic = setFirstItem(_G.sendSet);
2624 sic = setNextItem(_G.sendSet);
2626 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2627 /* The second send value is loaded from one the one that holds the first
2628 send, i.e. it is overwritten. */
2629 /* Cache the first in HL, and load the second from HL instead. */
2630 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2631 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2637 for (sic = setFirstItem (_G.sendSet); sic;
2638 sic = setNextItem (_G.sendSet))
2641 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2643 size = AOP_SIZE (IC_LEFT (sic));
2644 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2645 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2647 // PENDING: Mild hack
2648 if (swapped == TRUE && send == 1) {
2650 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2653 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2655 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2658 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2662 freeAsmop (IC_LEFT (sic), NULL, sic);
2669 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2671 werror (W_INDIR_BANKED);
2673 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2675 if (isLitWord (AOP (IC_LEFT (ic))))
2677 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2681 symbol *rlbl = newiTempLabel (NULL);
2682 spillPair (PAIR_HL);
2683 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2685 _G.stack.pushed += 2;
2687 fetchHL (AOP (IC_LEFT (ic)));
2689 emit2 ("!tlabeldef", (rlbl->key + 100));
2690 _G.stack.pushed -= 2;
2692 freeAsmop (IC_LEFT (ic), NULL, ic);
2696 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2697 OP_SYMBOL (IC_LEFT (ic))->rname :
2698 OP_SYMBOL (IC_LEFT (ic))->name;
2699 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2701 emit2 ("call banked_call");
2702 emit2 ("!dws", name);
2703 emit2 ("!dw !bankimmeds", name);
2708 emit2 ("call %s", name);
2713 /* Mark the regsiters as restored. */
2714 _G.saves.saved = FALSE;
2716 /* if we need assign a result value */
2717 if ((IS_ITEMP (IC_RESULT (ic)) &&
2718 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2719 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2720 IS_TRUE_SYMOP (IC_RESULT (ic)))
2723 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2725 assignResultValue (IC_RESULT (ic));
2727 freeAsmop (IC_RESULT (ic), NULL, ic);
2730 /* adjust the stack for parameters if required */
2733 int i = ic->parmBytes;
2735 _G.stack.pushed -= i;
2738 emit2 ("!ldaspsp", i);
2745 emit2 ("ld iy,!immedword", i);
2746 emit2 ("add iy,sp");
2766 if (_G.stack.pushedDE)
2768 bool dInRet = bitVectBitValue(ic->rUsed, D_IDX);
2769 bool eInRet = bitVectBitValue(ic->rUsed, E_IDX);
2771 if (dInRet && eInRet)
2773 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
2777 /* Only restore E */
2784 /* Only restore D */
2792 _G.stack.pushedDE = FALSE;
2795 if (_G.stack.pushedBC)
2797 bool bInRet = bitVectBitValue(ic->rUsed, B_IDX);
2798 bool cInRet = bitVectBitValue(ic->rUsed, C_IDX);
2800 if (bInRet && cInRet)
2802 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
2806 /* Only restore C */
2813 /* Only restore B */
2821 _G.stack.pushedBC = FALSE;
2825 /*-----------------------------------------------------------------*/
2826 /* genCall - generates a call statement */
2827 /*-----------------------------------------------------------------*/
2829 genCall (iCode * ic)
2831 emitCall (ic, FALSE);
2834 /*-----------------------------------------------------------------*/
2835 /* genPcall - generates a call by pointer statement */
2836 /*-----------------------------------------------------------------*/
2838 genPcall (iCode * ic)
2840 emitCall (ic, TRUE);
2843 /*-----------------------------------------------------------------*/
2844 /* resultRemat - result is rematerializable */
2845 /*-----------------------------------------------------------------*/
2847 resultRemat (iCode * ic)
2849 if (SKIP_IC (ic) || ic->op == IFX)
2852 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2854 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2855 if (sym->remat && !POINTER_SET (ic))
2862 extern set *publics;
2864 /*-----------------------------------------------------------------*/
2865 /* genFunction - generated code for function entry */
2866 /*-----------------------------------------------------------------*/
2868 genFunction (iCode * ic)
2870 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2873 bool bcInUse = FALSE;
2874 bool deInUse = FALSE;
2876 setArea (IFFUNC_NONBANKED (sym->type));
2878 /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
2881 _G.receiveOffset = 0;
2883 /* Record the last function name for debugging. */
2884 _G.lastFunctionName = sym->rname;
2886 /* Create the function header */
2887 emit2 ("!functionheader", sym->name);
2888 sprintf (buffer, "%s_start", sym->rname);
2889 emit2 ("!labeldef", buffer);
2890 emit2 ("!functionlabeldef", sym->rname);
2892 if (options.profile)
2894 emit2 ("!profileenter");
2897 ftype = operandType (IC_LEFT (ic));
2899 /* if critical function then turn interrupts off */
2900 if (IFFUNC_ISCRITICAL (ftype))
2903 /* if this is an interrupt service routine then save all potentially used registers. */
2904 if (IFFUNC_ISISR (sym->type))
2909 /* PENDING: callee-save etc */
2911 _G.stack.param_offset = 0;
2913 if (z80_opts.calleeSavesBC)
2918 /* Detect which registers are used. */
2919 if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
2922 for (i = 0; i < sym->regsUsed->size; i++)
2924 if (bitVectBitValue (sym->regsUsed, i))
2938 /* Other systems use DE as a temporary. */
2949 _G.stack.param_offset += 2;
2952 _G.calleeSaves.pushedBC = bcInUse;
2957 _G.stack.param_offset += 2;
2960 _G.calleeSaves.pushedDE = deInUse;
2962 /* adjust the stack for the function */
2963 _G.stack.last = sym->stack;
2965 if (sym->stack && IS_GB && sym->stack > -INT8MIN)
2966 emit2 ("!enterxl", sym->stack);
2967 else if (sym->stack)
2968 emit2 ("!enterx", sym->stack);
2971 _G.stack.offset = sym->stack;
2974 /*-----------------------------------------------------------------*/
2975 /* genEndFunction - generates epilogue for functions */
2976 /*-----------------------------------------------------------------*/
2978 genEndFunction (iCode * ic)
2980 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2982 if (IFFUNC_ISISR (sym->type))
2984 wassertl (0, "Tried to close an interrupt support function");
2988 if (IFFUNC_ISCRITICAL (sym->type))
2991 /* PENDING: calleeSave */
2993 if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
2995 emit2 ("!leavexl", _G.stack.offset);
2997 else if (_G.stack.offset)
2999 emit2 ("!leavex", _G.stack.offset);
3006 if (_G.calleeSaves.pushedDE)
3009 _G.calleeSaves.pushedDE = FALSE;
3012 if (_G.calleeSaves.pushedBC)
3015 _G.calleeSaves.pushedBC = FALSE;
3018 if (options.profile)
3020 emit2 ("!profileexit");
3024 /* Both baned and non-banked just ret */
3027 sprintf (buffer, "%s_end", sym->rname);
3028 emit2 ("!labeldef", buffer);
3030 _G.flushStatics = 1;
3031 _G.stack.pushed = 0;
3032 _G.stack.offset = 0;
3035 /*-----------------------------------------------------------------*/
3036 /* genRet - generate code for return statement */
3037 /*-----------------------------------------------------------------*/
3042 /* Errk. This is a hack until I can figure out how
3043 to cause dehl to spill on a call */
3044 int size, offset = 0;
3046 /* if we have no return value then
3047 just generate the "ret" */
3051 /* we have something to return then
3052 move the return value into place */
3053 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3054 size = AOP_SIZE (IC_LEFT (ic));
3056 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3060 emit2 ("ld de,%s", l);
3064 emit2 ("ld hl,%s", l);
3069 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3071 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3072 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3078 l = aopGet (AOP (IC_LEFT (ic)), offset,
3080 if (strcmp (_fReturn[offset], l))
3081 emit2 ("ld %s,%s", _fReturn[offset++], l);
3085 freeAsmop (IC_LEFT (ic), NULL, ic);
3088 /* generate a jump to the return label
3089 if the next is not the return statement */
3090 if (!(ic->next && ic->next->op == LABEL &&
3091 IC_LABEL (ic->next) == returnLabel))
3093 emit2 ("jp !tlabel", returnLabel->key + 100);
3096 /*-----------------------------------------------------------------*/
3097 /* genLabel - generates a label */
3098 /*-----------------------------------------------------------------*/
3100 genLabel (iCode * ic)
3102 /* special case never generate */
3103 if (IC_LABEL (ic) == entryLabel)
3106 emitLabel (IC_LABEL (ic)->key + 100);
3109 /*-----------------------------------------------------------------*/
3110 /* genGoto - generates a ljmp */
3111 /*-----------------------------------------------------------------*/
3113 genGoto (iCode * ic)
3115 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3118 /*-----------------------------------------------------------------*/
3119 /* genPlusIncr :- does addition with increment if possible */
3120 /*-----------------------------------------------------------------*/
3122 genPlusIncr (iCode * ic)
3124 unsigned int icount;
3125 unsigned int size = getDataSize (IC_RESULT (ic));
3126 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3128 /* will try to generate an increment */
3129 /* if the right side is not a literal
3131 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3134 emitDebug ("; genPlusIncr");
3136 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3138 /* If result is a pair */
3139 if (resultId != PAIR_INVALID)
3141 if (isLitWord (AOP (IC_LEFT (ic))))
3143 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3146 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3148 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3150 PAIR_ID freep = getFreePairId (ic);
3151 if (freep != PAIR_INVALID)
3153 fetchPair (freep, AOP (IC_RIGHT (ic)));
3154 emit2 ("add hl,%s", _pairs[freep].name);
3160 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3161 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3168 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3172 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3176 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3181 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3183 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3184 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3188 /* if the literal value of the right hand side
3189 is greater than 4 then it is not worth it */
3193 /* if increment 16 bits in register */
3194 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3200 symbol *tlbl = NULL;
3201 tlbl = newiTempLabel (NULL);
3204 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3207 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3210 emitLabel (tlbl->key + 100);
3214 /* if the sizes are greater than 1 then we cannot */
3215 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3216 AOP_SIZE (IC_LEFT (ic)) > 1)
3219 /* If the result is in a register then we can load then increment.
3221 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3223 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3226 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3231 /* we can if the aops of the left & result match or
3232 if they are in registers and the registers are the
3234 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3238 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3246 /*-----------------------------------------------------------------*/
3247 /* outBitAcc - output a bit in acc */
3248 /*-----------------------------------------------------------------*/
3250 outBitAcc (operand * result)
3252 symbol *tlbl = newiTempLabel (NULL);
3253 /* if the result is a bit */
3254 if (AOP_TYPE (result) == AOP_CRY)
3256 wassertl (0, "Tried to write A into a bit");
3260 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3261 emit2 ("ld a,!one");
3262 emitLabel (tlbl->key + 100);
3268 couldDestroyCarry (asmop *aop)
3272 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3281 shiftIntoPair (int idx, asmop *aop)
3283 PAIR_ID id = PAIR_INVALID;
3285 wassertl (IS_Z80, "Only implemented for the Z80");
3286 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3298 wassertl (0, "Internal error - hit default case");
3301 emitDebug ("; Shift into pair idx %u", idx);
3305 setupPair (PAIR_HL, aop, 0);
3309 setupPair (PAIR_IY, aop, 0);
3311 emit2 ("pop %s", _pairs[id].name);
3314 aop->type = AOP_PAIRPTR;
3315 aop->aopu.aop_pairId = id;
3316 _G.pairs[id].offset = 0;
3317 _G.pairs[id].last_type = aop->type;
3321 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
3323 wassert (left && right);
3327 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3329 shiftIntoPair (0, right);
3330 shiftIntoPair (1, result);
3332 else if (couldDestroyCarry (right))
3334 shiftIntoPair (0, right);
3336 else if (couldDestroyCarry (result))
3338 shiftIntoPair (0, result);
3347 /*-----------------------------------------------------------------*/
3348 /* genPlus - generates code for addition */
3349 /*-----------------------------------------------------------------*/
3351 genPlus (iCode * ic)
3353 int size, offset = 0;
3355 /* special cases :- */
3357 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3358 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3359 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3361 /* Swap the left and right operands if:
3363 if literal, literal on the right or
3364 if left requires ACC or right is already
3367 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3368 (AOP_NEEDSACC (IC_LEFT (ic))) ||
3369 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3371 operand *t = IC_RIGHT (ic);
3372 IC_RIGHT (ic) = IC_LEFT (ic);
3376 /* if both left & right are in bit
3378 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3379 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3382 wassertl (0, "Tried to add two bits");
3385 /* if left in bit space & right literal */
3386 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3387 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3389 /* Can happen I guess */
3390 wassertl (0, "Tried to add a bit to a literal");
3393 /* if I can do an increment instead
3394 of add then GOOD for ME */
3395 if (genPlusIncr (ic) == TRUE)
3398 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3400 size = getDataSize (IC_RESULT (ic));
3402 /* Special case when left and right are constant */
3403 if (isPair (AOP (IC_RESULT (ic))))
3406 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3407 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3409 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3415 sprintf (buffer, "#(%s + %s)", left, right);
3416 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3421 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3423 /* Fetch into HL then do the add */
3424 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3425 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3427 spillPair (PAIR_HL);
3429 if (left == PAIR_HL && right != PAIR_INVALID)
3431 emit2 ("add hl,%s", _pairs[right].name);
3434 else if (right == PAIR_HL && left != PAIR_INVALID)
3436 emit2 ("add hl,%s", _pairs[left].name);
3439 else if (right != PAIR_INVALID && right != PAIR_HL)
3441 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3442 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3445 else if (left != PAIR_INVALID && left != PAIR_HL)
3447 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3448 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3457 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3459 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3460 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3462 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3467 ld hl,sp+n trashes C so we cant afford to do it during an
3468 add with stack based varibles. Worst case is:
3481 So you cant afford to load up hl if either left, right, or result
3482 is on the stack (*sigh*) The alt is:
3490 Combinations in here are:
3491 * If left or right are in bc then the loss is small - trap later
3492 * If the result is in bc then the loss is also small
3496 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3497 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3498 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3500 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3501 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3502 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3503 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3505 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3507 /* Swap left and right */
3508 operand *t = IC_RIGHT (ic);
3509 IC_RIGHT (ic) = IC_LEFT (ic);
3512 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3514 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3515 emit2 ("add hl,bc");
3519 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3520 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3521 emit2 ("add hl,de");
3523 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3529 /* Be paranoid on the GB with 4 byte variables due to how C
3530 can be trashed by lda hl,n(sp).
3532 _gbz80_emitAddSubLong (ic, TRUE);
3537 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3541 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3543 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3546 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3549 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3553 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3556 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3559 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3561 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3565 freeAsmop (IC_LEFT (ic), NULL, ic);
3566 freeAsmop (IC_RIGHT (ic), NULL, ic);
3567 freeAsmop (IC_RESULT (ic), NULL, ic);
3571 /*-----------------------------------------------------------------*/
3572 /* genMinusDec :- does subtraction with deccrement if possible */
3573 /*-----------------------------------------------------------------*/
3575 genMinusDec (iCode * ic)
3577 unsigned int icount;
3578 unsigned int size = getDataSize (IC_RESULT (ic));
3580 /* will try to generate an increment */
3581 /* if the right side is not a literal we cannot */
3582 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3585 /* if the literal value of the right hand side
3586 is greater than 4 then it is not worth it */
3587 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3590 size = getDataSize (IC_RESULT (ic));
3592 /* if decrement 16 bits in register */
3593 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3594 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3597 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3601 /* If result is a pair */
3602 if (isPair (AOP (IC_RESULT (ic))))
3604 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3606 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3610 /* if increment 16 bits in register */
3611 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3615 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3618 emit2 ("dec %s", _getTempPairName());
3621 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3627 /* if the sizes are greater than 1 then we cannot */
3628 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3629 AOP_SIZE (IC_LEFT (ic)) > 1)
3632 /* we can if the aops of the left & result match or if they are in
3633 registers and the registers are the same */
3634 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3637 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3644 /*-----------------------------------------------------------------*/
3645 /* genMinus - generates code for subtraction */
3646 /*-----------------------------------------------------------------*/
3648 genMinus (iCode * ic)
3650 int size, offset = 0;
3651 unsigned long lit = 0L;
3653 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3654 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3655 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3657 /* special cases :- */
3658 /* if both left & right are in bit space */
3659 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3660 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3662 wassertl (0, "Tried to subtract two bits");
3666 /* if I can do an decrement instead of subtract then GOOD for ME */
3667 if (genMinusDec (ic) == TRUE)
3670 size = getDataSize (IC_RESULT (ic));
3672 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3677 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3681 /* Same logic as genPlus */
3684 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3685 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3686 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3688 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3689 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3690 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3691 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3693 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3694 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3696 if (left == PAIR_INVALID && right == PAIR_INVALID)
3701 else if (right == PAIR_INVALID)
3703 else if (left == PAIR_INVALID)
3706 fetchPair (left, AOP (IC_LEFT (ic)));
3707 /* Order is important. Right may be HL */
3708 fetchPair (right, AOP (IC_RIGHT (ic)));
3710 emit2 ("ld a,%s", _pairs[left].l);
3711 emit2 ("sub a,%s", _pairs[right].l);
3713 emit2 ("ld a,%s", _pairs[left].h);
3714 emit2 ("sbc a,%s", _pairs[right].h);
3716 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
3718 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3720 aopPut (AOP (IC_RESULT (ic)), "e", 0);
3726 /* Be paranoid on the GB with 4 byte variables due to how C
3727 can be trashed by lda hl,n(sp).
3729 _gbz80_emitAddSubLong (ic, FALSE);
3734 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3736 /* if literal, add a,#-lit, else normal subb */
3739 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3740 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3744 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3747 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3751 /* first add without previous c */
3753 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
3755 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3757 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3760 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3761 AOP_SIZE (IC_LEFT (ic)) == 3 &&
3762 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3764 wassertl (0, "Tried to subtract on a long pointer");
3768 freeAsmop (IC_LEFT (ic), NULL, ic);
3769 freeAsmop (IC_RIGHT (ic), NULL, ic);
3770 freeAsmop (IC_RESULT (ic), NULL, ic);
3773 /*-----------------------------------------------------------------*/
3774 /* genMult - generates code for multiplication */
3775 /*-----------------------------------------------------------------*/
3777 genMult (iCode * ic)
3781 /* If true then the final operation should be a subtract */
3782 bool active = FALSE;
3784 /* Shouldn't occur - all done through function calls */
3785 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3786 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3787 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3789 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
3790 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
3791 AOP_SIZE (IC_RESULT (ic)) > 2)
3793 wassertl (0, "Multiplication is handled through support function calls");
3796 /* Swap left and right such that right is a literal */
3797 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
3799 operand *t = IC_RIGHT (ic);
3800 IC_RIGHT (ic) = IC_LEFT (ic);
3804 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
3806 val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
3807 // wassertl (val > 0, "Multiply must be positive");
3808 wassertl (val != 1, "Can't multiply by 1");
3810 if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
3812 _G.stack.pushedDE = TRUE;
3815 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
3817 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
3825 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3830 /* Fully unroled version of mul.s. Not the most efficient.
3832 for (count = 0; count < 16; count++)
3834 if (count != 0 && active)
3836 emit2 ("add hl,hl");
3840 if (active == FALSE)
3847 emit2 ("add hl,de");
3856 if (IS_Z80 && _G.stack.pushedDE)
3859 _G.stack.pushedDE = FALSE;
3862 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3864 freeAsmop (IC_LEFT (ic), NULL, ic);
3865 freeAsmop (IC_RIGHT (ic), NULL, ic);
3866 freeAsmop (IC_RESULT (ic), NULL, ic);
3869 /*-----------------------------------------------------------------*/
3870 /* genDiv - generates code for division */
3871 /*-----------------------------------------------------------------*/
3875 /* Shouldn't occur - all done through function calls */
3876 wassertl (0, "Division is handled through support function calls");
3879 /*-----------------------------------------------------------------*/
3880 /* genMod - generates code for division */
3881 /*-----------------------------------------------------------------*/
3885 /* Shouldn't occur - all done through function calls */
3889 /*-----------------------------------------------------------------*/
3890 /* genIfxJump :- will create a jump depending on the ifx */
3891 /*-----------------------------------------------------------------*/
3893 genIfxJump (iCode * ic, char *jval)
3898 /* if true label then we jump if condition
3902 jlbl = IC_TRUE (ic);
3903 if (!strcmp (jval, "a"))
3907 else if (!strcmp (jval, "c"))
3911 else if (!strcmp (jval, "nc"))
3915 else if (!strcmp (jval, "m"))
3919 else if (!strcmp (jval, "p"))
3925 /* The buffer contains the bit on A that we should test */
3931 /* false label is present */
3932 jlbl = IC_FALSE (ic);
3933 if (!strcmp (jval, "a"))
3937 else if (!strcmp (jval, "c"))
3941 else if (!strcmp (jval, "nc"))
3945 else if (!strcmp (jval, "m"))
3949 else if (!strcmp (jval, "p"))
3955 /* The buffer contains the bit on A that we should test */
3959 /* Z80 can do a conditional long jump */
3960 if (!strcmp (jval, "a"))
3964 else if (!strcmp (jval, "c"))
3967 else if (!strcmp (jval, "nc"))
3970 else if (!strcmp (jval, "m"))
3973 else if (!strcmp (jval, "p"))
3978 emit2 ("bit %s,a", jval);
3980 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
3982 /* mark the icode as generated */
3988 _getPairIdName (PAIR_ID id)
3990 return _pairs[id].name;
3995 /* if unsigned char cmp with lit, just compare */
3997 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
3999 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4002 emit2 ("xor a,!immedbyte", 0x80);
4003 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4006 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4008 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4010 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4011 // Pull left into DE and right into HL
4012 aopGet (AOP(left), LSB, FALSE);
4015 aopGet (AOP(right), LSB, FALSE);
4019 if (size == 0 && sign)
4021 // Highest byte when signed needs the bits flipped
4024 emit2 ("ld a,(de)");
4025 emit2 ("xor !immedbyte", 0x80);
4027 emit2 ("ld a,(hl)");
4028 emit2 ("xor !immedbyte", 0x80);
4032 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4036 emit2 ("ld a,(de)");
4037 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4047 spillPair (PAIR_HL);
4049 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4051 setupPair (PAIR_HL, AOP (left), 0);
4052 aopGet (AOP(right), LSB, FALSE);
4056 if (size == 0 && sign)
4058 // Highest byte when signed needs the bits flipped
4061 emit2 ("ld a,(hl)");
4062 emit2 ("xor !immedbyte", 0x80);
4064 emit2 ("ld a,%d(iy)", offset);
4065 emit2 ("xor !immedbyte", 0x80);
4069 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4073 emit2 ("ld a,(hl)");
4074 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4083 spillPair (PAIR_HL);
4084 spillPair (PAIR_IY);
4088 if (AOP_TYPE (right) == AOP_LIT)
4090 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4091 /* optimize if(x < 0) or if(x >= 0) */
4096 /* No sign so it's always false */
4101 /* Just load in the top most bit */
4102 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4103 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4105 genIfxJump (ifx, "7");
4117 /* First setup h and l contaning the top most bytes XORed */
4118 bool fDidXor = FALSE;
4119 if (AOP_TYPE (left) == AOP_LIT)
4121 unsigned long lit = (unsigned long)
4122 floatFromVal (AOP (left)->aopu.aop_lit);
4123 emit2 ("ld %s,!immedbyte", _fTmp[0],
4124 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4128 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4129 emit2 ("xor a,!immedbyte", 0x80);
4130 emit2 ("ld %s,a", _fTmp[0]);
4133 if (AOP_TYPE (right) == AOP_LIT)
4135 unsigned long lit = (unsigned long)
4136 floatFromVal (AOP (right)->aopu.aop_lit);
4137 emit2 ("ld %s,!immedbyte", _fTmp[1],
4138 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4142 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4143 emit2 ("xor a,!immedbyte", 0x80);
4144 emit2 ("ld %s,a", _fTmp[1]);
4150 /* Do a long subtract */
4153 _moveA (aopGet (AOP (left), offset, FALSE));
4155 if (sign && size == 0)
4157 emit2 ("ld a,%s", _fTmp[0]);
4158 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4162 /* Subtract through, propagating the carry */
4163 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4171 /** Generic compare for > or <
4174 genCmp (operand * left, operand * right,
4175 operand * result, iCode * ifx, int sign)
4177 int size, offset = 0;
4178 unsigned long lit = 0L;
4179 bool swap_sense = FALSE;
4181 /* if left & right are bit variables */
4182 if (AOP_TYPE (left) == AOP_CRY &&
4183 AOP_TYPE (right) == AOP_CRY)
4185 /* Cant happen on the Z80 */
4186 wassertl (0, "Tried to compare two bits");
4190 /* Do a long subtract of right from left. */
4191 size = max (AOP_SIZE (left), AOP_SIZE (right));
4193 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4195 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4196 // Pull left into DE and right into HL
4197 aopGet (AOP(left), LSB, FALSE);
4200 aopGet (AOP(right), LSB, FALSE);
4204 emit2 ("ld a,(de)");
4205 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4214 spillPair (PAIR_HL);
4218 if (AOP_TYPE (right) == AOP_LIT)
4220 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4221 /* optimize if(x < 0) or if(x >= 0) */
4226 /* No sign so it's always false */
4231 /* Just load in the top most bit */
4232 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4233 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4235 genIfxJump (ifx, "7");
4246 genIfxJump (ifx, swap_sense ? "c" : "nc");
4257 _moveA (aopGet (AOP (left), offset, FALSE));
4258 /* Subtract through, propagating the carry */
4259 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4265 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4269 /* Shift the sign bit up into carry */
4272 outBitCLong (result, swap_sense);
4276 /* if the result is used in the next
4277 ifx conditional branch then generate
4278 code a little differently */
4286 genIfxJump (ifx, swap_sense ? "nc" : "c");
4290 genIfxJump (ifx, swap_sense ? "p" : "m");
4295 genIfxJump (ifx, swap_sense ? "nc" : "c");
4302 /* Shift the sign bit up into carry */
4305 outBitCLong (result, swap_sense);
4307 /* leave the result in acc */
4311 /*-----------------------------------------------------------------*/
4312 /* genCmpGt :- greater than comparison */
4313 /*-----------------------------------------------------------------*/
4315 genCmpGt (iCode * ic, iCode * ifx)
4317 operand *left, *right, *result;
4318 sym_link *letype, *retype;
4321 left = IC_LEFT (ic);
4322 right = IC_RIGHT (ic);
4323 result = IC_RESULT (ic);
4325 letype = getSpec (operandType (left));
4326 retype = getSpec (operandType (right));
4327 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4328 /* assign the amsops */
4329 aopOp (left, ic, FALSE, FALSE);
4330 aopOp (right, ic, FALSE, FALSE);
4331 aopOp (result, ic, TRUE, FALSE);
4333 genCmp (right, left, result, ifx, sign);
4335 freeAsmop (left, NULL, ic);
4336 freeAsmop (right, NULL, ic);
4337 freeAsmop (result, NULL, ic);
4340 /*-----------------------------------------------------------------*/
4341 /* genCmpLt - less than comparisons */
4342 /*-----------------------------------------------------------------*/
4344 genCmpLt (iCode * ic, iCode * ifx)
4346 operand *left, *right, *result;
4347 sym_link *letype, *retype;
4350 left = IC_LEFT (ic);
4351 right = IC_RIGHT (ic);
4352 result = IC_RESULT (ic);
4354 letype = getSpec (operandType (left));
4355 retype = getSpec (operandType (right));
4356 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4358 /* assign the amsops */
4359 aopOp (left, ic, FALSE, FALSE);
4360 aopOp (right, ic, FALSE, FALSE);
4361 aopOp (result, ic, TRUE, FALSE);
4363 genCmp (left, right, result, ifx, sign);
4365 freeAsmop (left, NULL, ic);
4366 freeAsmop (right, NULL, ic);
4367 freeAsmop (result, NULL, ic);
4370 /*-----------------------------------------------------------------*/
4371 /* gencjneshort - compare and jump if not equal */
4372 /*-----------------------------------------------------------------*/
4374 gencjneshort (operand * left, operand * right, symbol * lbl)
4376 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4378 unsigned long lit = 0L;
4380 /* Swap the left and right if it makes the computation easier */
4381 if (AOP_TYPE (left) == AOP_LIT)
4388 if (AOP_TYPE (right) == AOP_LIT)
4390 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4393 /* if the right side is a literal then anything goes */
4394 if (AOP_TYPE (right) == AOP_LIT &&
4395 AOP_TYPE (left) != AOP_DIR)
4399 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4404 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4411 emit2 ("jp nz,!tlabel", lbl->key + 100);
4417 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4418 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
4421 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
4422 emit2 ("jp nz,!tlabel", lbl->key + 100);
4427 /* if the right side is in a register or in direct space or
4428 if the left is a pointer register & right is not */
4429 else if (AOP_TYPE (right) == AOP_REG ||
4430 AOP_TYPE (right) == AOP_DIR ||
4431 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
4435 _moveA (aopGet (AOP (left), offset, FALSE));
4436 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
4437 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4439 emit2 ("jp nz,!tlabel", lbl->key + 100);
4442 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4443 emit2 ("jp nz,!tlabel", lbl->key + 100);
4450 /* right is a pointer reg need both a & b */
4451 /* PENDING: is this required? */
4454 _moveA (aopGet (AOP (right), offset, FALSE));
4455 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
4456 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
4462 /*-----------------------------------------------------------------*/
4463 /* gencjne - compare and jump if not equal */
4464 /*-----------------------------------------------------------------*/
4466 gencjne (operand * left, operand * right, symbol * lbl)
4468 symbol *tlbl = newiTempLabel (NULL);
4470 gencjneshort (left, right, lbl);
4473 emit2 ("ld a,!one");
4474 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4475 emitLabel (lbl->key + 100);
4477 emitLabel (tlbl->key + 100);
4480 /*-----------------------------------------------------------------*/
4481 /* genCmpEq - generates code for equal to */
4482 /*-----------------------------------------------------------------*/
4484 genCmpEq (iCode * ic, iCode * ifx)
4486 operand *left, *right, *result;
4488 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4489 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4490 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4492 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4494 /* Swap operands if it makes the operation easier. ie if:
4495 1. Left is a literal.
4497 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4499 operand *t = IC_RIGHT (ic);
4500 IC_RIGHT (ic) = IC_LEFT (ic);
4504 if (ifx && !AOP_SIZE (result))
4507 /* if they are both bit variables */
4508 if (AOP_TYPE (left) == AOP_CRY &&
4509 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4511 wassertl (0, "Tried to compare two bits");
4515 tlbl = newiTempLabel (NULL);
4516 gencjneshort (left, right, tlbl);
4519 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4520 emitLabel (tlbl->key + 100);
4524 /* PENDING: do this better */
4525 symbol *lbl = newiTempLabel (NULL);
4526 emit2 ("!shortjp !tlabel", lbl->key + 100);
4527 emitLabel (tlbl->key + 100);
4528 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4529 emitLabel (lbl->key + 100);
4532 /* mark the icode as generated */
4537 /* if they are both bit variables */
4538 if (AOP_TYPE (left) == AOP_CRY &&
4539 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4541 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4547 gencjne (left, right, newiTempLabel (NULL));
4548 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4555 genIfxJump (ifx, "a");
4558 /* if the result is used in an arithmetic operation
4559 then put the result in place */
4560 if (AOP_TYPE (result) != AOP_CRY)
4565 /* leave the result in acc */
4569 freeAsmop (left, NULL, ic);
4570 freeAsmop (right, NULL, ic);
4571 freeAsmop (result, NULL, ic);
4574 /*-----------------------------------------------------------------*/
4575 /* ifxForOp - returns the icode containing the ifx for operand */
4576 /*-----------------------------------------------------------------*/
4578 ifxForOp (operand * op, iCode * ic)
4580 /* if true symbol then needs to be assigned */
4581 if (IS_TRUE_SYMOP (op))
4584 /* if this has register type condition and
4585 the next instruction is ifx with the same operand
4586 and live to of the operand is upto the ifx only then */
4588 ic->next->op == IFX &&
4589 IC_COND (ic->next)->key == op->key &&
4590 OP_SYMBOL (op)->liveTo <= ic->next->seq)
4596 /*-----------------------------------------------------------------*/
4597 /* genAndOp - for && operation */
4598 /*-----------------------------------------------------------------*/
4600 genAndOp (iCode * ic)
4602 operand *left, *right, *result;
4605 /* note here that && operations that are in an if statement are
4606 taken away by backPatchLabels only those used in arthmetic
4607 operations remain */
4608 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4609 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4610 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4612 /* if both are bit variables */
4613 if (AOP_TYPE (left) == AOP_CRY &&
4614 AOP_TYPE (right) == AOP_CRY)
4616 wassertl (0, "Tried to and two bits");
4620 tlbl = newiTempLabel (NULL);
4622 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
4624 emitLabel (tlbl->key + 100);
4628 freeAsmop (left, NULL, ic);
4629 freeAsmop (right, NULL, ic);
4630 freeAsmop (result, NULL, ic);
4633 /*-----------------------------------------------------------------*/
4634 /* genOrOp - for || operation */
4635 /*-----------------------------------------------------------------*/
4637 genOrOp (iCode * ic)
4639 operand *left, *right, *result;
4642 /* note here that || operations that are in an
4643 if statement are taken away by backPatchLabels
4644 only those used in arthmetic operations remain */
4645 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4646 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4647 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4649 /* if both are bit variables */
4650 if (AOP_TYPE (left) == AOP_CRY &&
4651 AOP_TYPE (right) == AOP_CRY)
4653 wassertl (0, "Tried to OR two bits");
4657 tlbl = newiTempLabel (NULL);
4659 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4661 emitLabel (tlbl->key + 100);
4665 freeAsmop (left, NULL, ic);
4666 freeAsmop (right, NULL, ic);
4667 freeAsmop (result, NULL, ic);
4670 /*-----------------------------------------------------------------*/
4671 /* isLiteralBit - test if lit == 2^n */
4672 /*-----------------------------------------------------------------*/
4674 isLiteralBit (unsigned long lit)
4676 unsigned long pw[32] =
4677 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
4678 0x100L, 0x200L, 0x400L, 0x800L,
4679 0x1000L, 0x2000L, 0x4000L, 0x8000L,
4680 0x10000L, 0x20000L, 0x40000L, 0x80000L,
4681 0x100000L, 0x200000L, 0x400000L, 0x800000L,
4682 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
4683 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
4686 for (idx = 0; idx < 32; idx++)
4692 /*-----------------------------------------------------------------*/
4693 /* jmpTrueOrFalse - */
4694 /*-----------------------------------------------------------------*/
4696 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
4698 // ugly but optimized by peephole
4701 symbol *nlbl = newiTempLabel (NULL);
4702 emit2 ("jp !tlabel", nlbl->key + 100);
4703 emitLabel (tlbl->key + 100);
4704 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
4705 emitLabel (nlbl->key + 100);
4709 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
4710 emitLabel (tlbl->key + 100);
4715 /*-----------------------------------------------------------------*/
4716 /* genAnd - code for and */
4717 /*-----------------------------------------------------------------*/
4719 genAnd (iCode * ic, iCode * ifx)
4721 operand *left, *right, *result;
4722 int size, offset = 0;
4723 unsigned long lit = 0L;
4726 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4727 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4728 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4730 /* if left is a literal & right is not then exchange them */
4731 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4732 AOP_NEEDSACC (left))
4734 operand *tmp = right;
4739 /* if result = right then exchange them */
4740 if (sameRegs (AOP (result), AOP (right)))
4742 operand *tmp = right;
4747 /* if right is bit then exchange them */
4748 if (AOP_TYPE (right) == AOP_CRY &&
4749 AOP_TYPE (left) != AOP_CRY)
4751 operand *tmp = right;
4755 if (AOP_TYPE (right) == AOP_LIT)
4756 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4758 size = AOP_SIZE (result);
4760 if (AOP_TYPE (left) == AOP_CRY)
4762 wassertl (0, "Tried to perform an AND with a bit as an operand");
4766 // if(val & 0xZZ) - size = 0, ifx != FALSE -
4767 // bit = val & 0xZZ - size = 1, ifx = FALSE -
4768 if ((AOP_TYPE (right) == AOP_LIT) &&
4769 (AOP_TYPE (result) == AOP_CRY) &&
4770 (AOP_TYPE (left) != AOP_CRY))
4772 symbol *tlbl = newiTempLabel (NULL);
4773 int sizel = AOP_SIZE (left);
4776 /* PENDING: Test case for this. */
4781 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
4783 _moveA (aopGet (AOP (left), offset, FALSE));
4784 if (bytelit != 0x0FFL)
4786 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4793 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4797 // bit = left & literal
4801 emit2 ("!tlabeldef", tlbl->key + 100);
4803 // if(left & literal)
4808 jmpTrueOrFalse (ifx, tlbl);
4816 /* if left is same as result */
4817 if (sameRegs (AOP (result), AOP (left)))
4819 for (; size--; offset++)
4821 if (AOP_TYPE (right) == AOP_LIT)
4823 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4828 aopPut (AOP (result), "!zero", offset);
4831 _moveA (aopGet (AOP (left), offset, FALSE));
4833 aopGet (AOP (right), offset, FALSE));
4834 aopPut (AOP (left), "a", offset);
4841 if (AOP_TYPE (left) == AOP_ACC)
4843 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
4847 _moveA (aopGet (AOP (left), offset, FALSE));
4849 aopGet (AOP (right), offset, FALSE));
4850 aopPut (AOP (left), "a", offset);
4857 // left & result in different registers
4858 if (AOP_TYPE (result) == AOP_CRY)
4860 wassertl (0, "Tried to AND where the result is in carry");
4864 for (; (size--); offset++)
4867 // result = left & right
4868 if (AOP_TYPE (right) == AOP_LIT)
4870 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4872 aopPut (AOP (result),
4873 aopGet (AOP (left), offset, FALSE),
4877 else if (bytelit == 0)
4879 aopPut (AOP (result), "!zero", offset);
4883 // faster than result <- left, anl result,right
4884 // and better if result is SFR
4885 if (AOP_TYPE (left) == AOP_ACC)
4886 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4889 _moveA (aopGet (AOP (left), offset, FALSE));
4891 aopGet (AOP (right), offset, FALSE));
4893 aopPut (AOP (result), "a", offset);
4900 freeAsmop (left, NULL, ic);
4901 freeAsmop (right, NULL, ic);
4902 freeAsmop (result, NULL, ic);
4905 /*-----------------------------------------------------------------*/
4906 /* genOr - code for or */
4907 /*-----------------------------------------------------------------*/
4909 genOr (iCode * ic, iCode * ifx)
4911 operand *left, *right, *result;
4912 int size, offset = 0;
4913 unsigned long lit = 0L;
4916 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4917 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4918 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4920 /* if left is a literal & right is not then exchange them */
4921 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4922 AOP_NEEDSACC (left))
4924 operand *tmp = right;
4929 /* if result = right then exchange them */
4930 if (sameRegs (AOP (result), AOP (right)))
4932 operand *tmp = right;
4937 /* if right is bit then exchange them */
4938 if (AOP_TYPE (right) == AOP_CRY &&
4939 AOP_TYPE (left) != AOP_CRY)
4941 operand *tmp = right;
4945 if (AOP_TYPE (right) == AOP_LIT)
4946 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4948 size = AOP_SIZE (result);
4950 if (AOP_TYPE (left) == AOP_CRY)
4952 wassertl (0, "Tried to OR where left is a bit");
4956 // if(val | 0xZZ) - size = 0, ifx != FALSE -
4957 // bit = val | 0xZZ - size = 1, ifx = FALSE -
4958 if ((AOP_TYPE (right) == AOP_LIT) &&
4959 (AOP_TYPE (result) == AOP_CRY) &&
4960 (AOP_TYPE (left) != AOP_CRY))
4962 symbol *tlbl = newiTempLabel (NULL);
4963 int sizel = AOP_SIZE (left);
4967 wassertl (0, "Result is assigned to a bit");
4969 /* PENDING: Modeled after the AND code which is inefficent. */
4972 bytelit = (lit >> (offset * 8)) & 0x0FFL;
4974 _moveA (aopGet (AOP (left), offset, FALSE));
4975 /* OR with any literal is the same as OR with itself. */
4977 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4983 jmpTrueOrFalse (ifx, tlbl);
4988 /* if left is same as result */
4989 if (sameRegs (AOP (result), AOP (left)))
4991 for (; size--; offset++)
4993 if (AOP_TYPE (right) == AOP_LIT)
4995 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4999 _moveA (aopGet (AOP (left), offset, FALSE));
5001 aopGet (AOP (right), offset, FALSE));
5002 aopPut (AOP (result), "a", offset);
5007 if (AOP_TYPE (left) == AOP_ACC)
5008 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5011 _moveA (aopGet (AOP (left), offset, FALSE));
5013 aopGet (AOP (right), offset, FALSE));
5014 aopPut (AOP (result), "a", offset);
5021 // left & result in different registers
5022 if (AOP_TYPE (result) == AOP_CRY)
5024 wassertl (0, "Result of OR is in a bit");
5027 for (; (size--); offset++)
5030 // result = left & right
5031 if (AOP_TYPE (right) == AOP_LIT)
5033 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5035 aopPut (AOP (result),
5036 aopGet (AOP (left), offset, FALSE),
5041 // faster than result <- left, anl result,right
5042 // and better if result is SFR
5043 if (AOP_TYPE (left) == AOP_ACC)
5044 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5047 _moveA (aopGet (AOP (left), offset, FALSE));
5049 aopGet (AOP (right), offset, FALSE));
5051 aopPut (AOP (result), "a", offset);
5052 /* PENDING: something weird is going on here. Add exception. */
5053 if (AOP_TYPE (result) == AOP_ACC)
5059 freeAsmop (left, NULL, ic);
5060 freeAsmop (right, NULL, ic);
5061 freeAsmop (result, NULL, ic);
5064 /*-----------------------------------------------------------------*/
5065 /* genXor - code for xclusive or */
5066 /*-----------------------------------------------------------------*/
5068 genXor (iCode * ic, iCode * ifx)
5070 operand *left, *right, *result;
5071 int size, offset = 0;
5072 unsigned long lit = 0L;
5074 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5075 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5076 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5078 /* if left is a literal & right is not then exchange them */
5079 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5080 AOP_NEEDSACC (left))
5082 operand *tmp = right;
5087 /* if result = right then exchange them */
5088 if (sameRegs (AOP (result), AOP (right)))
5090 operand *tmp = right;
5095 /* if right is bit then exchange them */
5096 if (AOP_TYPE (right) == AOP_CRY &&
5097 AOP_TYPE (left) != AOP_CRY)
5099 operand *tmp = right;
5103 if (AOP_TYPE (right) == AOP_LIT)
5104 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5106 size = AOP_SIZE (result);
5108 if (AOP_TYPE (left) == AOP_CRY)
5110 wassertl (0, "Tried to XOR a bit");
5114 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5115 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5116 if ((AOP_TYPE (right) == AOP_LIT) &&
5117 (AOP_TYPE (result) == AOP_CRY) &&
5118 (AOP_TYPE (left) != AOP_CRY))
5120 symbol *tlbl = newiTempLabel (NULL);
5121 int sizel = AOP_SIZE (left);
5125 /* PENDING: Test case for this. */
5126 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5130 _moveA (aopGet (AOP (left), offset, FALSE));
5131 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5132 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5137 jmpTrueOrFalse (ifx, tlbl);
5141 wassertl (0, "Result of XOR was destined for a bit");
5146 /* if left is same as result */
5147 if (sameRegs (AOP (result), AOP (left)))
5149 for (; size--; offset++)
5151 if (AOP_TYPE (right) == AOP_LIT)
5153 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5157 _moveA (aopGet (AOP (right), offset, FALSE));
5159 aopGet (AOP (left), offset, FALSE));
5160 aopPut (AOP (result), "a", offset);
5165 if (AOP_TYPE (left) == AOP_ACC)
5167 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5171 _moveA (aopGet (AOP (right), offset, FALSE));
5173 aopGet (AOP (left), offset, FALSE));
5174 aopPut (AOP (result), "a", 0);
5181 // left & result in different registers
5182 if (AOP_TYPE (result) == AOP_CRY)
5184 wassertl (0, "Result of XOR is in a bit");
5187 for (; (size--); offset++)
5190 // result = left & right
5191 if (AOP_TYPE (right) == AOP_LIT)
5193 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5195 aopPut (AOP (result),
5196 aopGet (AOP (left), offset, FALSE),
5201 // faster than result <- left, anl result,right
5202 // and better if result is SFR
5203 if (AOP_TYPE (left) == AOP_ACC)
5205 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5209 _moveA (aopGet (AOP (right), offset, FALSE));
5211 aopGet (AOP (left), offset, FALSE));
5213 aopPut (AOP (result), "a", offset);
5218 freeAsmop (left, NULL, ic);
5219 freeAsmop (right, NULL, ic);
5220 freeAsmop (result, NULL, ic);
5223 /*-----------------------------------------------------------------*/
5224 /* genInline - write the inline code out */
5225 /*-----------------------------------------------------------------*/
5227 genInline (iCode * ic)
5229 char *buffer, *bp, *bp1;
5231 _G.lines.isInline += (!options.asmpeep);
5233 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5234 strcpy (buffer, IC_INLINE (ic));
5236 /* emit each line as a code */
5261 _G.lines.isInline -= (!options.asmpeep);
5265 /*-----------------------------------------------------------------*/
5266 /* genRRC - rotate right with carry */
5267 /*-----------------------------------------------------------------*/
5274 /*-----------------------------------------------------------------*/
5275 /* genRLC - generate code for rotate left with carry */
5276 /*-----------------------------------------------------------------*/
5283 /*-----------------------------------------------------------------*/
5284 /* genGetHbit - generates code get highest order bit */
5285 /*-----------------------------------------------------------------*/
5287 genGetHbit (iCode * ic)
5289 operand *left, *result;
5290 left = IC_LEFT (ic);
5291 result = IC_RESULT (ic);
5293 aopOp (left, ic, FALSE, FALSE);
5294 aopOp (result, ic, FALSE, FALSE);
5296 /* get the highest order byte into a */
5297 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5299 if (AOP_TYPE (result) == AOP_CRY)
5307 emit2 ("and a,!one");
5312 freeAsmop (left, NULL, ic);
5313 freeAsmop (result, NULL, ic);
5317 emitRsh2 (asmop *aop, int size, int is_signed)
5323 const char *l = aopGet (aop, size, FALSE);
5326 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5336 /*-----------------------------------------------------------------*/
5337 /* shiftR2Left2Result - shift right two bytes from left to result */
5338 /*-----------------------------------------------------------------*/
5340 shiftR2Left2Result (operand * left, int offl,
5341 operand * result, int offr,
5342 int shCount, int is_signed)
5345 symbol *tlbl, *tlbl1;
5347 movLeft2Result (left, offl, result, offr, 0);
5348 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5350 /* if (AOP(result)->type == AOP_REG) { */
5352 tlbl = newiTempLabel (NULL);
5353 tlbl1 = newiTempLabel (NULL);
5355 /* Left is already in result - so now do the shift */
5360 emitRsh2 (AOP (result), size, is_signed);
5365 emit2 ("ld a,!immedbyte+1", shCount);
5366 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5367 emitLabel (tlbl->key + 100);
5369 emitRsh2 (AOP (result), size, is_signed);
5371 emitLabel (tlbl1->key + 100);
5373 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5377 /*-----------------------------------------------------------------*/
5378 /* shiftL2Left2Result - shift left two bytes from left to result */
5379 /*-----------------------------------------------------------------*/
5381 shiftL2Left2Result (operand * left, int offl,
5382 operand * result, int offr, int shCount)
5384 if (sameRegs (AOP (result), AOP (left)) &&
5385 ((offl + MSB16) == offr))
5391 /* Copy left into result */
5392 movLeft2Result (left, offl, result, offr, 0);
5393 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5396 if (getPairId (AOP (result)) == PAIR_HL)
5400 emit2 ("add hl,hl");
5407 symbol *tlbl, *tlbl1;
5410 tlbl = newiTempLabel (NULL);
5411 tlbl1 = newiTempLabel (NULL);
5413 if (AOP (result)->type == AOP_REG)
5417 for (offset = 0; offset < size; offset++)
5419 l = aopGet (AOP (result), offset, FALSE);
5423 emit2 ("sla %s", l);
5434 /* Left is already in result - so now do the shift */
5437 emit2 ("ld a,!immedbyte+1", shCount);
5438 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5439 emitLabel (tlbl->key + 100);
5444 l = aopGet (AOP (result), offset, FALSE);
5448 emit2 ("sla %s", l);
5459 emitLabel (tlbl1->key + 100);
5461 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5467 /*-----------------------------------------------------------------*/
5468 /* AccRol - rotate left accumulator by known count */
5469 /*-----------------------------------------------------------------*/
5471 AccRol (int shCount)
5473 shCount &= 0x0007; // shCount : 0..7
5512 /*-----------------------------------------------------------------*/
5513 /* AccLsh - left shift accumulator by known count */
5514 /*-----------------------------------------------------------------*/
5516 AccLsh (int shCount)
5518 static const unsigned char SLMask[] =
5520 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5529 else if (shCount == 2)
5536 /* rotate left accumulator */
5538 /* and kill the lower order bits */
5539 emit2 ("and a,!immedbyte", SLMask[shCount]);
5544 /*-----------------------------------------------------------------*/
5545 /* shiftL1Left2Result - shift left one byte from left to result */
5546 /*-----------------------------------------------------------------*/
5548 shiftL1Left2Result (operand * left, int offl,
5549 operand * result, int offr, int shCount)
5552 l = aopGet (AOP (left), offl, FALSE);
5554 /* shift left accumulator */
5556 aopPut (AOP (result), "a", offr);
5560 /*-----------------------------------------------------------------*/
5561 /* genlshTwo - left shift two bytes by known amount != 0 */
5562 /*-----------------------------------------------------------------*/
5564 genlshTwo (operand * result, operand * left, int shCount)
5566 int size = AOP_SIZE (result);
5568 wassert (size == 2);
5570 /* if shCount >= 8 */
5578 movLeft2Result (left, LSB, result, MSB16, 0);
5579 aopPut (AOP (result), "!zero", 0);
5580 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
5584 movLeft2Result (left, LSB, result, MSB16, 0);
5585 aopPut (AOP (result), "!zero", 0);
5590 aopPut (AOP (result), "!zero", LSB);
5593 /* 1 <= shCount <= 7 */
5602 shiftL2Left2Result (left, LSB, result, LSB, shCount);
5607 /*-----------------------------------------------------------------*/
5608 /* genlshOne - left shift a one byte quantity by known count */
5609 /*-----------------------------------------------------------------*/
5611 genlshOne (operand * result, operand * left, int shCount)
5613 shiftL1Left2Result (left, LSB, result, LSB, shCount);
5616 /*-----------------------------------------------------------------*/
5617 /* genLeftShiftLiteral - left shifting by known count */
5618 /*-----------------------------------------------------------------*/
5620 genLeftShiftLiteral (operand * left,
5625 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5628 freeAsmop (right, NULL, ic);
5630 aopOp (left, ic, FALSE, FALSE);
5631 aopOp (result, ic, FALSE, FALSE);
5633 size = getSize (operandType (result));
5635 /* I suppose that the left size >= result size */
5641 else if (shCount >= (size * 8))
5645 aopPut (AOP (result), "!zero", size);
5653 genlshOne (result, left, shCount);
5656 genlshTwo (result, left, shCount);
5659 wassertl (0, "Shifting of longs is currently unsupported");
5665 freeAsmop (left, NULL, ic);
5666 freeAsmop (result, NULL, ic);
5669 /*-----------------------------------------------------------------*/
5670 /* genLeftShift - generates code for left shifting */
5671 /*-----------------------------------------------------------------*/
5673 genLeftShift (iCode * ic)
5677 symbol *tlbl, *tlbl1;
5678 operand *left, *right, *result;
5680 right = IC_RIGHT (ic);
5681 left = IC_LEFT (ic);
5682 result = IC_RESULT (ic);
5684 aopOp (right, ic, FALSE, FALSE);
5686 /* if the shift count is known then do it
5687 as efficiently as possible */
5688 if (AOP_TYPE (right) == AOP_LIT)
5690 genLeftShiftLiteral (left, right, result, ic);
5694 /* shift count is unknown then we have to form a loop get the loop
5695 count in B : Note: we take only the lower order byte since
5696 shifting more that 32 bits make no sense anyway, ( the largest
5697 size of an object can be only 32 bits ) */
5698 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5700 freeAsmop (right, NULL, ic);
5701 aopOp (left, ic, FALSE, FALSE);
5702 aopOp (result, ic, FALSE, FALSE);
5704 /* now move the left to the result if they are not the
5707 if (!sameRegs (AOP (left), AOP (result)))
5710 size = AOP_SIZE (result);
5714 l = aopGet (AOP (left), offset, FALSE);
5715 aopPut (AOP (result), l, offset);
5720 tlbl = newiTempLabel (NULL);
5721 size = AOP_SIZE (result);
5723 tlbl1 = newiTempLabel (NULL);
5725 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5726 emitLabel (tlbl->key + 100);
5727 l = aopGet (AOP (result), offset, FALSE);
5731 l = aopGet (AOP (result), offset, FALSE);
5735 emit2 ("sla %s", l);
5743 emitLabel (tlbl1->key + 100);
5745 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5747 freeAsmop (left, NULL, ic);
5748 freeAsmop (result, NULL, ic);
5751 /*-----------------------------------------------------------------*/
5752 /* genrshOne - left shift two bytes by known amount != 0 */
5753 /*-----------------------------------------------------------------*/
5755 genrshOne (operand * result, operand * left, int shCount, int is_signed)
5758 int size = AOP_SIZE (result);
5761 wassert (size == 1);
5762 wassert (shCount < 8);
5764 l = aopGet (AOP (left), 0, FALSE);
5766 if (AOP (result)->type == AOP_REG)
5768 aopPut (AOP (result), l, 0);
5769 l = aopGet (AOP (result), 0, FALSE);
5772 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5780 emit2 ("%s a", is_signed ? "sra" : "srl");
5782 aopPut (AOP (result), "a", 0);
5786 /*-----------------------------------------------------------------*/
5787 /* AccRsh - right shift accumulator by known count */
5788 /*-----------------------------------------------------------------*/
5790 AccRsh (int shCount)
5792 static const unsigned char SRMask[] =
5794 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
5799 /* rotate right accumulator */
5800 AccRol (8 - shCount);
5801 /* and kill the higher order bits */
5802 emit2 ("and a,!immedbyte", SRMask[shCount]);
5806 /*-----------------------------------------------------------------*/
5807 /* shiftR1Left2Result - shift right one byte from left to result */
5808 /*-----------------------------------------------------------------*/
5810 shiftR1Left2Result (operand * left, int offl,
5811 operand * result, int offr,
5812 int shCount, int sign)
5814 _moveA (aopGet (AOP (left), offl, FALSE));
5819 emit2 ("%s a", sign ? "sra" : "srl");
5826 aopPut (AOP (result), "a", offr);
5829 /*-----------------------------------------------------------------*/
5830 /* genrshTwo - right shift two bytes by known amount != 0 */
5831 /*-----------------------------------------------------------------*/
5833 genrshTwo (operand * result, operand * left,
5834 int shCount, int sign)
5836 /* if shCount >= 8 */
5842 shiftR1Left2Result (left, MSB16, result, LSB,
5847 movLeft2Result (left, MSB16, result, LSB, sign);
5851 /* Sign extend the result */
5852 _moveA(aopGet (AOP (result), 0, FALSE));
5856 aopPut (AOP (result), ACC_NAME, MSB16);
5860 aopPut (AOP (result), "!zero", 1);
5863 /* 1 <= shCount <= 7 */
5866 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
5870 /*-----------------------------------------------------------------*/
5871 /* genRightShiftLiteral - left shifting by known count */
5872 /*-----------------------------------------------------------------*/
5874 genRightShiftLiteral (operand * left,
5880 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5883 freeAsmop (right, NULL, ic);
5885 aopOp (left, ic, FALSE, FALSE);
5886 aopOp (result, ic, FALSE, FALSE);
5888 size = getSize (operandType (result));
5890 /* I suppose that the left size >= result size */
5896 else if (shCount >= (size * 8)) {
5898 if (!SPEC_USIGN(getSpec(operandType(left)))) {
5899 _moveA(aopGet (AOP (left), 0, FALSE));
5907 aopPut (AOP (result), s, size);
5914 genrshOne (result, left, shCount, sign);
5917 genrshTwo (result, left, shCount, sign);
5920 wassertl (0, "Asked to shift right a long which should be a function call");
5923 wassertl (0, "Entered default case in right shift delegate");
5926 freeAsmop (left, NULL, ic);
5927 freeAsmop (result, NULL, ic);
5930 /*-----------------------------------------------------------------*/
5931 /* genRightShift - generate code for right shifting */
5932 /*-----------------------------------------------------------------*/
5934 genRightShift (iCode * ic)
5936 operand *right, *left, *result;
5938 int size, offset, first = 1;
5942 symbol *tlbl, *tlbl1;
5944 /* if signed then we do it the hard way preserve the
5945 sign bit moving it inwards */
5946 retype = getSpec (operandType (IC_RESULT (ic)));
5948 is_signed = !SPEC_USIGN (retype);
5950 /* signed & unsigned types are treated the same : i.e. the
5951 signed is NOT propagated inwards : quoting from the
5952 ANSI - standard : "for E1 >> E2, is equivalent to division
5953 by 2**E2 if unsigned or if it has a non-negative value,
5954 otherwise the result is implementation defined ", MY definition
5955 is that the sign does not get propagated */
5957 right = IC_RIGHT (ic);
5958 left = IC_LEFT (ic);
5959 result = IC_RESULT (ic);
5961 aopOp (right, ic, FALSE, FALSE);
5963 /* if the shift count is known then do it
5964 as efficiently as possible */
5965 if (AOP_TYPE (right) == AOP_LIT)
5967 genRightShiftLiteral (left, right, result, ic, is_signed);
5971 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5973 freeAsmop (right, NULL, ic);
5975 aopOp (left, ic, FALSE, FALSE);
5976 aopOp (result, ic, FALSE, FALSE);
5978 /* now move the left to the result if they are not the
5980 if (!sameRegs (AOP (left), AOP (result)))
5983 size = AOP_SIZE (result);
5987 l = aopGet (AOP (left), offset, FALSE);
5988 aopPut (AOP (result), l, offset);
5993 tlbl = newiTempLabel (NULL);
5994 tlbl1 = newiTempLabel (NULL);
5995 size = AOP_SIZE (result);
5998 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5999 emitLabel (tlbl->key + 100);
6002 l = aopGet (AOP (result), offset--, FALSE);
6005 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6013 emitLabel (tlbl1->key + 100);
6015 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6017 freeAsmop (left, NULL, ic);
6018 freeAsmop (result, NULL, ic);
6021 /*-----------------------------------------------------------------*/
6022 /* genGenPointerGet - get value from generic pointer space */
6023 /*-----------------------------------------------------------------*/
6025 genGenPointerGet (operand * left,
6026 operand * result, iCode * ic)
6029 sym_link *retype = getSpec (operandType (result));
6035 aopOp (left, ic, FALSE, FALSE);
6036 aopOp (result, ic, FALSE, FALSE);
6038 size = AOP_SIZE (result);
6040 if (isPair (AOP (left)) && size == 1)
6043 if (isPtrPair (AOP (left)))
6045 tsprintf (buffer, sizeof(buffer),
6046 "!*pair", getPairName (AOP (left)));
6047 aopPut (AOP (result), buffer, 0);
6051 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6052 aopPut (AOP (result), "a", 0);
6054 freeAsmop (left, NULL, ic);
6058 if (getPairId (AOP (left)) == PAIR_IY)
6065 tsprintf (at, sizeof(at), "!*iyx", offset);
6066 aopPut (AOP (result), at, offset);
6070 freeAsmop (left, NULL, ic);
6074 /* For now we always load into IY */
6075 /* if this is remateriazable */
6076 fetchPair (pair, AOP (left));
6078 /* if bit then unpack */
6079 if (IS_BITVAR (retype))
6083 else if (getPairId (AOP (result)) == PAIR_HL)
6085 wassertl (size == 2, "HL must be of size 2");
6086 emit2 ("ld a,!*hl");
6088 emit2 ("ld h,!*hl");
6090 spillPair (PAIR_HL);
6092 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6094 size = AOP_SIZE (result);
6099 /* PENDING: make this better */
6100 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6102 aopPut (AOP (result), "!*hl", offset++);
6106 emit2 ("ld a,!*pair", _pairs[pair].name);
6107 aopPut (AOP (result), "a", offset++);
6111 emit2 ("inc %s", _pairs[pair].name);
6112 _G.pairs[pair].offset++;
6115 /* Fixup HL back down */
6116 for (size = AOP_SIZE (result)-1; size; size--)
6118 emit2 ("dec %s", _pairs[pair].name);
6123 size = AOP_SIZE (result);
6128 /* PENDING: make this better */
6130 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6132 aopPut (AOP (result), "!*hl", offset++);
6136 emit2 ("ld a,!*pair", _pairs[pair].name);
6137 aopPut (AOP (result), "a", offset++);
6141 emit2 ("inc %s", _pairs[pair].name);
6142 _G.pairs[pair].offset++;
6147 freeAsmop (left, NULL, ic);
6150 freeAsmop (result, NULL, ic);
6153 /*-----------------------------------------------------------------*/
6154 /* genPointerGet - generate code for pointer get */
6155 /*-----------------------------------------------------------------*/
6157 genPointerGet (iCode * ic)
6159 operand *left, *result;
6160 sym_link *type, *etype;
6162 left = IC_LEFT (ic);
6163 result = IC_RESULT (ic);
6165 /* depending on the type of pointer we need to
6166 move it to the correct pointer register */
6167 type = operandType (left);
6168 etype = getSpec (type);
6170 genGenPointerGet (left, result, ic);
6174 isRegOrLit (asmop * aop)
6176 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6181 /*-----------------------------------------------------------------*/
6182 /* genGenPointerSet - stores the value into a pointer location */
6183 /*-----------------------------------------------------------------*/
6185 genGenPointerSet (operand * right,
6186 operand * result, iCode * ic)
6189 sym_link *retype = getSpec (operandType (right));
6190 PAIR_ID pairId = PAIR_HL;
6192 aopOp (result, ic, FALSE, FALSE);
6193 aopOp (right, ic, FALSE, FALSE);
6198 size = AOP_SIZE (right);
6200 /* Handle the exceptions first */
6201 if (isPair (AOP (result)) && size == 1)
6204 const char *l = aopGet (AOP (right), 0, FALSE);
6205 const char *pair = getPairName (AOP (result));
6206 if (canAssignToPtr (l) && isPtr (pair))
6208 emit2 ("ld !*pair,%s", pair, l);
6213 emit2 ("ld !*pair,a", pair);
6218 if ( getPairId( AOP (result)) == PAIR_IY)
6221 const char *l = aopGet (AOP (right), 0, FALSE);
6226 if (canAssignToPtr (l))
6228 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6232 _moveA (aopGet (AOP (right), offset, FALSE));
6233 emit2 ("ld !*iyx,a", offset);
6239 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result))
6245 const char *l = aopGet (AOP (right), offset, FALSE);
6246 if (isRegOrLit (AOP (right)) && !IS_GB)
6248 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
6253 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
6257 emit2 ("inc %s", _pairs[PAIR_HL].name);
6258 _G.pairs[PAIR_HL].offset++;
6263 /* Fixup HL back down */
6264 for (size = AOP_SIZE (right)-1; size; size--)
6266 emit2 ("dec %s", _pairs[PAIR_HL].name);
6271 /* if the operand is already in dptr
6272 then we do nothing else we move the value to dptr */
6273 if (AOP_TYPE (result) != AOP_STR)
6275 fetchPair (pairId, AOP (result));
6277 /* so hl know contains the address */
6278 freeAsmop (result, NULL, ic);
6280 /* if bit then unpack */
6281 if (IS_BITVAR (retype))
6291 const char *l = aopGet (AOP (right), offset, FALSE);
6292 if (isRegOrLit (AOP (right)) && !IS_GB)
6294 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
6299 emit2 ("ld !*pair,a", _pairs[pairId].name);
6303 emit2 ("inc %s", _pairs[pairId].name);
6304 _G.pairs[pairId].offset++;
6310 freeAsmop (right, NULL, ic);
6313 /*-----------------------------------------------------------------*/
6314 /* genPointerSet - stores the value into a pointer location */
6315 /*-----------------------------------------------------------------*/
6317 genPointerSet (iCode * ic)
6319 operand *right, *result;
6320 sym_link *type, *etype;
6322 right = IC_RIGHT (ic);
6323 result = IC_RESULT (ic);
6325 /* depending on the type of pointer we need to
6326 move it to the correct pointer register */
6327 type = operandType (result);
6328 etype = getSpec (type);
6330 genGenPointerSet (right, result, ic);
6333 /*-----------------------------------------------------------------*/
6334 /* genIfx - generate code for Ifx statement */
6335 /*-----------------------------------------------------------------*/
6337 genIfx (iCode * ic, iCode * popIc)
6339 operand *cond = IC_COND (ic);
6342 aopOp (cond, ic, FALSE, TRUE);
6344 /* get the value into acc */
6345 if (AOP_TYPE (cond) != AOP_CRY)
6349 /* the result is now in the accumulator */
6350 freeAsmop (cond, NULL, ic);
6352 /* if there was something to be popped then do it */
6356 /* if the condition is a bit variable */
6357 if (isbit && IS_ITEMP (cond) &&
6359 genIfxJump (ic, SPIL_LOC (cond)->rname);
6360 else if (isbit && !IS_ITEMP (cond))
6361 genIfxJump (ic, OP_SYMBOL (cond)->rname);
6363 genIfxJump (ic, "a");
6368 /*-----------------------------------------------------------------*/
6369 /* genAddrOf - generates code for address of */
6370 /*-----------------------------------------------------------------*/
6372 genAddrOf (iCode * ic)
6374 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
6376 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6378 /* if the operand is on the stack then we
6379 need to get the stack offset of this
6386 if (sym->stack <= 0)
6388 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
6392 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6394 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6398 emit2 ("ld de,!hashedstr", sym->rname);
6399 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
6407 /* if it has an offset then we need to compute it */
6409 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6411 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
6412 emit2 ("add hl,sp");
6416 emit2 ("ld hl,!hashedstr", sym->rname);
6418 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6420 freeAsmop (IC_RESULT (ic), NULL, ic);
6423 /*-----------------------------------------------------------------*/
6424 /* genAssign - generate code for assignment */
6425 /*-----------------------------------------------------------------*/
6427 genAssign (iCode * ic)
6429 operand *result, *right;
6431 unsigned long lit = 0L;
6433 result = IC_RESULT (ic);
6434 right = IC_RIGHT (ic);
6436 /* Dont bother assigning if they are the same */
6437 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6439 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
6443 aopOp (right, ic, FALSE, FALSE);
6444 aopOp (result, ic, TRUE, FALSE);
6446 /* if they are the same registers */
6447 if (sameRegs (AOP (right), AOP (result)))
6449 emitDebug ("; (registers are the same)");
6453 /* if the result is a bit */
6454 if (AOP_TYPE (result) == AOP_CRY)
6456 wassertl (0, "Tried to assign to a bit");
6460 size = AOP_SIZE (result);
6463 if (AOP_TYPE (right) == AOP_LIT)
6465 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6468 if (isPair (AOP (result)))
6470 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
6472 else if ((size > 1) &&
6473 (AOP_TYPE (result) != AOP_REG) &&
6474 (AOP_TYPE (right) == AOP_LIT) &&
6475 !IS_FLOAT (operandType (right)) &&
6478 bool fXored = FALSE;
6480 /* Work from the top down.
6481 Done this way so that we can use the cached copy of 0
6482 in A for a fast clear */
6485 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
6487 if (!fXored && size > 1)
6494 aopPut (AOP (result), "a", offset);
6498 aopPut (AOP (result), "!zero", offset);
6502 aopPut (AOP (result),
6503 aopGet (AOP (right), offset, FALSE),
6508 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
6510 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
6511 aopPut (AOP (result), "l", LSB);
6512 aopPut (AOP (result), "h", MSB16);
6514 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6516 /* Special case. Load into a and d, then load out. */
6517 _moveA (aopGet (AOP (right), 0, FALSE));
6518 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
6519 aopPut (AOP (result), "a", 0);
6520 aopPut (AOP (result), "e", 1);
6522 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6524 /* Special case - simple memcpy */
6525 aopGet (AOP (right), LSB, FALSE);
6528 aopGet (AOP (result), LSB, FALSE);
6532 emit2 ("ld a,(de)");
6533 /* Peephole will optimise this. */
6534 emit2 ("ld (hl),a");
6542 spillPair (PAIR_HL);
6548 /* PENDING: do this check better */
6549 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
6551 _moveA (aopGet (AOP (right), offset, FALSE));
6552 aopPut (AOP (result), "a", offset);
6555 aopPut (AOP (result),
6556 aopGet (AOP (right), offset, FALSE),
6563 freeAsmop (right, NULL, ic);
6564 freeAsmop (result, NULL, ic);
6567 /*-----------------------------------------------------------------*/
6568 /* genJumpTab - genrates code for jump table */
6569 /*-----------------------------------------------------------------*/
6571 genJumpTab (iCode * ic)
6576 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
6577 /* get the condition into accumulator */
6578 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
6581 emit2 ("ld e,%s", l);
6582 emit2 ("ld d,!zero");
6583 jtab = newiTempLabel (NULL);
6585 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
6586 emit2 ("add hl,de");
6587 emit2 ("add hl,de");
6588 emit2 ("add hl,de");
6589 freeAsmop (IC_JTCOND (ic), NULL, ic);
6593 emitLabel (jtab->key + 100);
6594 /* now generate the jump labels */
6595 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
6596 jtab = setNextItem (IC_JTLABELS (ic)))
6597 emit2 ("jp !tlabel", jtab->key + 100);
6600 /*-----------------------------------------------------------------*/
6601 /* genCast - gen code for casting */
6602 /*-----------------------------------------------------------------*/
6604 genCast (iCode * ic)
6606 operand *result = IC_RESULT (ic);
6607 sym_link *rtype = operandType (IC_RIGHT (ic));
6608 operand *right = IC_RIGHT (ic);
6611 /* if they are equivalent then do nothing */
6612 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6615 aopOp (right, ic, FALSE, FALSE);
6616 aopOp (result, ic, FALSE, FALSE);
6618 /* if the result is a bit */
6619 if (AOP_TYPE (result) == AOP_CRY)
6621 wassertl (0, "Tried to cast to a bit");
6624 /* if they are the same size : or less */
6625 if (AOP_SIZE (result) <= AOP_SIZE (right))
6628 /* if they are in the same place */
6629 if (sameRegs (AOP (right), AOP (result)))
6632 /* if they in different places then copy */
6633 size = AOP_SIZE (result);
6637 aopPut (AOP (result),
6638 aopGet (AOP (right), offset, FALSE),
6645 /* So we now know that the size of destination is greater
6646 than the size of the source */
6647 /* we move to result for the size of source */
6648 size = AOP_SIZE (right);
6652 aopPut (AOP (result),
6653 aopGet (AOP (right), offset, FALSE),
6658 /* now depending on the sign of the destination */
6659 size = AOP_SIZE (result) - AOP_SIZE (right);
6660 /* Unsigned or not an integral type - right fill with zeros */
6661 if (SPEC_USIGN (rtype) || !IS_SPEC (rtype) || AOP_TYPE(right)==AOP_CRY)
6664 aopPut (AOP (result), "!zero", offset++);
6668 /* we need to extend the sign :{ */
6669 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
6675 aopPut (AOP (result), "a", offset++);
6679 freeAsmop (right, NULL, ic);
6680 freeAsmop (result, NULL, ic);
6683 /*-----------------------------------------------------------------*/
6684 /* genReceive - generate code for a receive iCode */
6685 /*-----------------------------------------------------------------*/
6687 genReceive (iCode * ic)
6689 if (isOperandInFarSpace (IC_RESULT (ic)) &&
6690 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
6691 IS_TRUE_SYMOP (IC_RESULT (ic))))
6701 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6702 size = AOP_SIZE(IC_RESULT(ic));
6704 for (i = 0; i < size; i++) {
6705 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
6709 freeAsmop (IC_RESULT (ic), NULL, ic);
6714 /** Maximum number of bytes to emit per line. */
6718 /** Context for the byte output chunker. */
6721 unsigned char buffer[DBEMIT_MAX_RUN];
6726 /** Flushes a byte chunker by writing out all in the buffer and
6730 _dbFlush(DBEMITCTX *self)
6737 sprintf(line, ".db 0x%02X", self->buffer[0]);
6739 for (i = 1; i < self->pos; i++)
6741 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
6748 /** Write out another byte, buffering until a decent line is
6752 _dbEmit(DBEMITCTX *self, int c)
6754 if (self->pos == DBEMIT_MAX_RUN)
6758 self->buffer[self->pos++] = c;
6761 /** Context for a simple run length encoder. */
6765 unsigned char buffer[128];
6767 /** runLen may be equivalent to pos. */
6773 RLE_CHANGE_COST = 4,
6777 /** Flush the buffer of a run length encoder by writing out the run or
6778 data that it currently contains.
6781 _rleCommit(RLECTX *self)
6787 memset(&db, 0, sizeof(db));
6789 emit2(".db %u", self->pos);
6791 for (i = 0; i < self->pos; i++)
6793 _dbEmit(&db, self->buffer[i]);
6802 Can get either a run or a block of random stuff.
6803 Only want to change state if a good run comes in or a run ends.
6804 Detecting run end is easy.
6807 Say initial state is in run, len zero, last zero. Then if you get a
6808 few zeros then something else then a short run will be output.
6809 Seems OK. While in run mode, keep counting. While in random mode,
6810 keep a count of the run. If run hits margin, output all up to run,
6811 restart, enter run mode.
6814 /** Add another byte into the run length encoder, flushing as
6815 required. The run length encoder uses the Amiga IFF style, where
6816 a block is prefixed by its run length. A positive length means
6817 the next n bytes pass straight through. A negative length means
6818 that the next byte is repeated -n times. A zero terminates the
6822 _rleAppend(RLECTX *self, int c)
6826 if (c != self->last)
6828 /* The run has stopped. See if it is worthwhile writing it out
6829 as a run. Note that the random data comes in as runs of
6832 if (self->runLen > RLE_CHANGE_COST)
6834 /* Yes, worthwhile. */
6835 /* Commit whatever was in the buffer. */
6837 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
6841 /* Not worthwhile. Append to the end of the random list. */
6842 for (i = 0; i < self->runLen; i++)
6844 if (self->pos >= RLE_MAX_BLOCK)
6849 self->buffer[self->pos++] = self->last;
6857 if (self->runLen >= RLE_MAX_BLOCK)
6859 /* Commit whatever was in the buffer. */
6862 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
6870 _rleFlush(RLECTX *self)
6872 _rleAppend(self, -1);
6879 /** genArrayInit - Special code for initialising an array with constant
6883 genArrayInit (iCode * ic)
6887 int elementSize = 0, eIndex, i;
6888 unsigned val, lastVal;
6892 memset(&rle, 0, sizeof(rle));
6894 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
6896 _saveRegsForCall(ic, 0);
6898 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
6899 emit2 ("call __initrleblock");
6901 type = operandType(IC_LEFT(ic));
6903 if (type && type->next)
6905 elementSize = getSize(type->next);
6909 wassertl (0, "Can't determine element size in genArrayInit.");
6912 iLoop = IC_ARRAYILIST(ic);
6913 lastVal = (unsigned)-1;
6915 /* Feed all the bytes into the run length encoder which will handle
6917 This works well for mixed char data, and for random int and long
6926 for (i = 0; i < ix; i++)
6928 for (eIndex = 0; eIndex < elementSize; eIndex++)
6930 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
6931 _rleAppend(&rle, val);
6936 iLoop = iLoop->next;
6940 /* Mark the end of the run. */
6943 _restoreRegsAfterCall();
6947 freeAsmop (IC_LEFT(ic), NULL, ic);
6951 _swap (PAIR_ID one, PAIR_ID two)
6953 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
6959 emit2 ("ld a,%s", _pairs[one].l);
6960 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
6961 emit2 ("ld %s,a", _pairs[two].l);
6962 emit2 ("ld a,%s", _pairs[one].h);
6963 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
6964 emit2 ("ld %s,a", _pairs[two].h);
6968 /* The problem is that we may have all three pairs used and they may
6969 be needed in a different order.
6974 hl = hl => unity, fine
6978 hl = hl hl = hl, swap de <=> bc
6986 hl = bc de = de, swap bc <=> hl
6994 hl = de bc = bc, swap hl <=> de
6999 * Any pair = pair are done last
7000 * Any pair = iTemp are done last
7001 * Any swaps can be done any time
7009 So how do we detect the cases?
7010 How about a 3x3 matrix?
7014 x x x x (Fourth for iTemp/other)
7016 First determin which mode to use by counting the number of unity and
7019 Two - Assign the pair first, then the rest
7020 One - Swap the two, then the rest
7024 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7026 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7028 PAIR_BC, PAIR_HL, PAIR_DE
7030 int i, j, nunity = 0;
7031 memset (ids, PAIR_INVALID, sizeof (ids));
7034 wassert (nparams == 3);
7036 /* First save everything that needs to be saved. */
7037 _saveRegsForCall (ic, 0);
7039 /* Loading HL first means that DE is always fine. */
7040 for (i = 0; i < nparams; i++)
7042 aopOp (pparams[i], ic, FALSE, FALSE);
7043 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7046 /* Count the number of unity or iTemp assigns. */
7047 for (i = 0; i < 3; i++)
7049 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7057 /* Any order, fall through. */
7059 else if (nunity == 2)
7061 /* One is assigned. Pull it out and assign. */
7062 for (i = 0; i < 3; i++)
7064 for (j = 0; j < NUM_PAIRS; j++)
7066 if (ids[dest[i]][j] == TRUE)
7068 /* Found it. See if it's the right one. */
7069 if (j == PAIR_INVALID || j == dest[i])
7075 fetchPair(dest[i], AOP (pparams[i]));
7082 else if (nunity == 1)
7084 /* Find the pairs to swap. */
7085 for (i = 0; i < 3; i++)
7087 for (j = 0; j < NUM_PAIRS; j++)
7089 if (ids[dest[i]][j] == TRUE)
7091 if (j == PAIR_INVALID || j == dest[i])
7106 int next = getPairId (AOP (pparams[0]));
7107 emit2 ("push %s", _pairs[next].name);
7109 if (next == dest[1])
7111 fetchPair (dest[1], AOP (pparams[1]));
7112 fetchPair (dest[2], AOP (pparams[2]));
7116 fetchPair (dest[2], AOP (pparams[2]));
7117 fetchPair (dest[1], AOP (pparams[1]));
7119 emit2 ("pop %s", _pairs[dest[0]].name);
7122 /* Finally pull out all of the iTemps */
7123 for (i = 0; i < 3; i++)
7125 if (ids[dest[i]][PAIR_INVALID] == 1)
7127 fetchPair (dest[i], AOP (pparams[i]));
7133 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
7139 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
7143 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7145 setupForBuiltin3 (ic, nParams, pparams);
7147 label = newiTempLabel(NULL);
7149 emitLabel (label->key);
7150 emit2 ("ld a,(hl)");
7153 emit2 ("!shortjp nz,!tlabel ; 1", label->key);
7155 freeAsmop (from, NULL, ic->next);
7156 freeAsmop (to, NULL, ic);
7160 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
7162 operand *from, *to, *count;
7165 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
7170 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7172 setupForBuiltin3 (ic, nParams, pparams);
7176 freeAsmop (count, NULL, ic->next->next);
7177 freeAsmop (from, NULL, ic);
7179 _restoreRegsAfterCall();
7181 /* if we need assign a result value */
7182 if ((IS_ITEMP (IC_RESULT (ic)) &&
7183 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
7184 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
7185 IS_TRUE_SYMOP (IC_RESULT (ic)))
7187 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7188 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
7189 freeAsmop (IC_RESULT (ic), NULL, ic);
7192 freeAsmop (to, NULL, ic->next);
7195 /*-----------------------------------------------------------------*/
7196 /* genBuiltIn - calls the appropriate function to generating code */
7197 /* for a built in function */
7198 /*-----------------------------------------------------------------*/
7199 static void genBuiltIn (iCode *ic)
7201 operand *bi_parms[MAX_BUILTIN_ARGS];
7206 /* get all the arguments for a built in function */
7207 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
7209 /* which function is it */
7210 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
7212 if (strcmp(bif->name,"__builtin_strcpy")==0)
7214 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
7216 else if (strcmp(bif->name,"__builtin_memcpy")==0)
7218 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
7222 wassertl (0, "Unknown builtin function encountered");
7226 /*-----------------------------------------------------------------*/
7227 /* genZ80Code - generate code for Z80 based controllers */
7228 /*-----------------------------------------------------------------*/
7230 genZ80Code (iCode * lic)
7238 _fReturn = _gbz80_return;
7239 _fTmp = _gbz80_return;
7243 _fReturn = _z80_return;
7244 _fTmp = _z80_return;
7247 _G.lines.head = _G.lines.current = NULL;
7249 for (ic = lic; ic; ic = ic->next)
7252 if (cln != ic->lineno)
7254 if (!options.noCcodeInAsm) {
7255 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
7256 printCLine(ic->filename, ic->lineno));
7260 if (options.iCodeInAsm) {
7261 emit2 (";ic:%d: %s", ic->key, printILine(ic));
7263 /* if the result is marked as
7264 spilt and rematerializable or code for
7265 this has already been generated then
7267 if (resultRemat (ic) || ic->generated)
7270 /* depending on the operation */
7274 emitDebug ("; genNot");
7279 emitDebug ("; genCpl");
7284 emitDebug ("; genUminus");
7289 emitDebug ("; genIpush");
7294 /* IPOP happens only when trying to restore a
7295 spilt live range, if there is an ifx statement
7296 following this pop then the if statement might
7297 be using some of the registers being popped which
7298 would destory the contents of the register so
7299 we need to check for this condition and handle it */
7301 ic->next->op == IFX &&
7302 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
7304 emitDebug ("; genIfx");
7305 genIfx (ic->next, ic);
7309 emitDebug ("; genIpop");
7315 emitDebug ("; genCall");
7320 emitDebug ("; genPcall");
7325 emitDebug ("; genFunction");
7330 emitDebug ("; genEndFunction");
7331 genEndFunction (ic);
7335 emitDebug ("; genRet");
7340 emitDebug ("; genLabel");
7345 emitDebug ("; genGoto");
7350 emitDebug ("; genPlus");
7355 emitDebug ("; genMinus");
7360 emitDebug ("; genMult");
7365 emitDebug ("; genDiv");
7370 emitDebug ("; genMod");
7375 emitDebug ("; genCmpGt");
7376 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
7380 emitDebug ("; genCmpLt");
7381 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
7388 /* note these two are xlated by algebraic equivalence
7389 during parsing SDCC.y */
7390 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
7391 "got '>=' or '<=' shouldn't have come here");
7395 emitDebug ("; genCmpEq");
7396 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
7400 emitDebug ("; genAndOp");
7405 emitDebug ("; genOrOp");
7410 emitDebug ("; genXor");
7411 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
7415 emitDebug ("; genOr");
7416 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
7420 emitDebug ("; genAnd");
7421 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
7425 emitDebug ("; genInline");
7430 emitDebug ("; genRRC");
7435 emitDebug ("; genRLC");
7440 emitDebug ("; genGetHBIT");
7445 emitDebug ("; genLeftShift");
7450 emitDebug ("; genRightShift");
7454 case GET_VALUE_AT_ADDRESS:
7455 emitDebug ("; genPointerGet");
7461 if (POINTER_SET (ic))
7463 emitDebug ("; genAssign (pointer)");
7468 emitDebug ("; genAssign");
7474 emitDebug ("; genIfx");
7479 emitDebug ("; genAddrOf");
7484 emitDebug ("; genJumpTab");
7489 emitDebug ("; genCast");
7494 emitDebug ("; genReceive");
7499 if (ic->builtinSEND)
7501 emitDebug ("; genBuiltIn");
7506 emitDebug ("; addSet");
7507 addSet (&_G.sendSet, ic);
7512 emitDebug ("; genArrayInit");
7522 /* now we are ready to call the
7523 peep hole optimizer */
7524 if (!options.nopeep)
7525 peepHole (&_G.lines.head);
7527 /* This is unfortunate */
7528 /* now do the actual printing */
7530 FILE *fp = codeOutFile;
7531 if (isInHome () && codeOutFile == code->oFile)
7532 codeOutFile = home->oFile;
7533 printLine (_G.lines.head, codeOutFile);
7534 if (_G.flushStatics)
7537 _G.flushStatics = 0;
7542 freeTrace(&_G.lines.trace);
7543 freeTrace(&_G.trace.aops);
7549 _isPairUsed (iCode * ic, PAIR_ID pairId)
7555 if (bitVectBitValue (ic->rMask, D_IDX))
7557 if (bitVectBitValue (ic->rMask, E_IDX))
7567 fetchLitSpecial (asmop * aop, bool negate, bool xor)
7570 value *val = aop->aopu.aop_lit;
7572 wassert (aop->type == AOP_LIT);
7573 wassert (!IS_FLOAT (val->type));
7575 v = (unsigned long) floatFromVal (val);
7583 tsprintf (buffer, sizeof(buffer), "!immedword", v);
7584 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));