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
96 #ifdef HAVE_SYS_ISA_DEFS_H
97 #include <sys/isa_defs.h>
101 #include "SDCCglobl.h"
102 #include "SDCCpeeph.h"
104 #include "SDCCglue.h"
105 #include "newalloc.h"
107 /* This is the down and dirty file with all kinds of kludgy & hacky
108 stuff. This is what it is all about CODE GENERATION for a specific MCU.
109 Some of the routines may be reusable, will have to see */
111 /* Z80 calling convention description.
112 Parameters are passed right to left. As the stack grows downwards,
113 the parameters are arranged in left to right in memory.
114 Parameters may be passed in the HL and DE registers with one
116 PENDING: What if the parameter is a long?
117 Everything is caller saves. i.e. the caller must save any registers
118 that it wants to preserve over the call.
119 GB: The return value is returned in DEHL. DE is normally used as a
120 working register pair. Caller saves allows it to be used for a
122 va args functions do not use register parameters. All arguments
123 are passed on the stack.
124 IX is used as an index register to the top of the local variable
125 area. ix-0 is the top most local variable.
130 /* Set to enable debugging trace statements in the output assembly code. */
134 static char *_z80_return[] =
135 {"l", "h", "e", "d"};
136 static char *_gbz80_return[] =
137 {"e", "d", "l", "h"};
138 static char *_fReceive[] =
139 { "c", "b", "e", "d" };
141 static char **_fReturn;
144 extern FILE *codeOutFile;
152 /** Enum covering all the possible register pairs.
171 } _pairs[NUM_PAIRS] = {
172 { "??1", "?2", "?3" },
177 { "iy", "iyl", "iyh" },
178 { "ix", "ixl", "ixh" }
182 #define ACC_NAME _pairs[PAIR_AF].h
192 /** Code generator persistent data.
196 /** Used to optimised setting up of a pair by remebering what it
197 contains and adjusting instead of reloading where possible.
225 const char *lastFunctionName;
231 /** TRUE if the registers have already been saved. */
249 static const char *aopGet (asmop * aop, int offset, bool bit16);
251 static const char *aopNames[] = {
271 isLastUse (iCode *ic, operand *op)
273 bitVect *uses = bitVectCopy (OP_USES (op));
275 while (!bitVectIsZero (uses))
277 if (bitVectFirstBit (uses) == ic->key)
279 if (bitVectnBitsOn (uses) == 1)
288 bitVectUnSetBit (uses, bitVectFirstBit (uses));
308 _getTempPairName(void)
310 return _pairs[_getTempPairId()].name;
314 isPairInUse (PAIR_ID id, iCode *ic)
318 return bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
320 else if (id == PAIR_BC)
322 return bitVectBitValue (ic->rMask, B_IDX) || bitVectBitValue(ic->rMask, C_IDX);
326 wassertl (0, "Only implemented for DE and BC");
332 isPairInUseNotInRet(PAIR_ID id, iCode *ic)
336 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
340 return bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
344 wassertl (0, "Only implemented for DE");
350 getFreePairId (iCode *ic)
352 if (!isPairInUse (PAIR_BC, ic))
356 else if (IS_Z80 && !isPairInUse (PAIR_DE, ic))
369 /* Clean up the line so that it is 'prettier' */
370 if (strchr (buf, ':'))
372 /* Is a label - cant do anything */
375 /* Change the first (and probably only) ' ' to a tab so
390 _newLineNode (char *line)
394 pl = traceAlloc(&_G.lines.trace, Safe_alloc ( sizeof (lineNode)));
395 pl->line = traceAlloc(&_G.lines.trace, Safe_strdup (line));
401 _vemit2 (const char *szFormat, va_list ap)
405 tvsprintf (buffer, sizeof(buffer), szFormat, ap);
408 _G.lines.current = (_G.lines.current ?
409 connectLine (_G.lines.current, _newLineNode (buffer)) :
410 (_G.lines.head = _newLineNode (buffer)));
412 _G.lines.current->isInline = _G.lines.isInline;
416 emit2 (const char *szFormat,...)
420 va_start (ap, szFormat);
422 _vemit2 (szFormat, ap);
428 emitDebug (const char *szFormat,...)
434 va_start (ap, szFormat);
436 _vemit2 (szFormat, ap);
442 /*-----------------------------------------------------------------*/
443 /* emit2 - writes the code into a file : for now it is simple */
444 /*-----------------------------------------------------------------*/
446 _emit2 (const char *inst, const char *fmt,...)
449 char lb[INITIAL_INLINEASM];
456 sprintf (lb, "%s\t", inst);
457 vsprintf (lb + (strlen (lb)), fmt, ap);
460 vsprintf (lb, fmt, ap);
462 while (isspace (*lbp))
467 _G.lines.current = (_G.lines.current ?
468 connectLine (_G.lines.current, _newLineNode (lb)) :
469 (_G.lines.head = _newLineNode (lb)));
471 _G.lines.current->isInline = _G.lines.isInline;
476 _emitMove(const char *to, const char *from)
478 if (STRCASECMP(to, from) != 0)
480 emit2("ld %s,%s", to, from);
485 // Could leave this to the peephole, but sometimes the peephole is inhibited.
490 aopDump(const char *plabel, asmop *aop)
492 emitDebug("; Dump of %s: type %s size %u", plabel, aopNames[aop->type], aop->size);
496 emitDebug("; aop_stk %d", aop->aopu.aop_stk);
499 /* No information. */
505 _moveA(const char *moveFrom)
507 // Let the peephole optimiser take care of redundent loads
508 _emitMove(ACC_NAME, moveFrom);
518 getPairName (asmop * aop)
520 if (aop->type == AOP_REG)
522 switch (aop->aopu.aop_reg[0]->rIdx)
535 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
538 for (i = 0; i < NUM_PAIRS; i++)
540 if (strcmp(aop->aopu.aop_str[0], _pairs[i].l) == 0)
542 return _pairs[i].name;
546 wassertl (0, "Tried to get the pair name of something that isn't a pair");
551 getPairId (asmop * aop)
555 if (aop->type == AOP_REG)
557 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX) && (aop->aopu.aop_reg[1]->rIdx == B_IDX))
561 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX) && (aop->aopu.aop_reg[1]->rIdx == D_IDX))
565 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX) && (aop->aopu.aop_reg[1]->rIdx == H_IDX))
570 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
573 for (i = 0; i < NUM_PAIRS; i++)
575 if (!strcmp (aop->aopu.aop_str[0], _pairs[i].l) && !strcmp (aop->aopu.aop_str[1], _pairs[i].h))
585 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
589 return (getPairId (aop) != PAIR_INVALID);
593 isPtrPair (asmop * aop)
595 PAIR_ID pairId = getPairId (aop);
608 spillPair (PAIR_ID pairId)
610 _G.pairs[pairId].last_type = AOP_INVALID;
611 _G.pairs[pairId].base = NULL;
614 /** Push a register pair onto the stack */
616 genPairPush (asmop * aop)
618 emit2 ("push %s", getPairName (aop));
622 _push (PAIR_ID pairId)
624 emit2 ("push %s", _pairs[pairId].name);
625 _G.stack.pushed += 2;
629 _pop (PAIR_ID pairId)
631 emit2 ("pop %s", _pairs[pairId].name);
632 _G.stack.pushed -= 2;
636 /*-----------------------------------------------------------------*/
637 /* newAsmop - creates a new asmOp */
638 /*-----------------------------------------------------------------*/
640 newAsmop (short type)
644 aop = traceAlloc(&_G.trace.aops, Safe_alloc (sizeof (asmop)));
649 /*-----------------------------------------------------------------*/
650 /* aopForSym - for a true symbol */
651 /*-----------------------------------------------------------------*/
653 aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
660 wassert (sym->etype);
662 space = SPEC_OCLS (sym->etype);
664 /* if already has one */
670 /* Assign depending on the storage class */
671 if (sym->onStack || sym->iaccess)
673 /* The pointer that is used depends on how big the offset is.
674 Normally everything is AOP_STK, but for offsets of < -128 or
675 > 127 on the Z80 an extended stack pointer is used.
677 if (IS_Z80 && (options.ommitFramePtr || sym->stack < INT8MIN || sym->stack > (int)(INT8MAX-getSize (sym->type))))
679 emitDebug ("; AOP_EXSTK for %s", sym->rname);
680 sym->aop = aop = newAsmop (AOP_EXSTK);
684 emitDebug ("; AOP_STK for %s", sym->rname);
685 sym->aop = aop = newAsmop (AOP_STK);
688 aop->size = getSize (sym->type);
689 aop->aopu.aop_stk = sym->stack;
693 /* special case for a function */
694 if (IS_FUNC (sym->type))
696 sym->aop = aop = newAsmop (AOP_IMMD);
697 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup (sym->rname));
704 /* if it is in direct space */
705 if (IN_REGSP (space) && !requires_a)
707 sym->aop = aop = newAsmop (AOP_SFR);
708 aop->aopu.aop_dir = sym->rname;
709 aop->size = getSize (sym->type);
710 emitDebug ("; AOP_SFR for %s", sym->rname);
715 /* only remaining is far space */
716 /* in which case DPTR gets the address */
719 emitDebug ("; AOP_HL for %s", sym->rname);
720 sym->aop = aop = newAsmop (AOP_HL);
724 sym->aop = aop = newAsmop (AOP_IY);
726 aop->size = getSize (sym->type);
727 aop->aopu.aop_dir = sym->rname;
729 /* if it is in code space */
730 if (IN_CODESPACE (space))
736 /*-----------------------------------------------------------------*/
737 /* aopForRemat - rematerialzes an object */
738 /*-----------------------------------------------------------------*/
740 aopForRemat (symbol * sym)
743 iCode *ic = sym->rematiCode;
744 asmop *aop = newAsmop (AOP_IMMD);
748 /* if plus or minus print the right hand side */
749 if (ic->op == '+' || ic->op == '-')
751 /* PENDING: for re-target */
752 sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
755 ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
758 /* we reached the end */
759 sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
763 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
767 /*-----------------------------------------------------------------*/
768 /* regsInCommon - two operands have some registers in common */
769 /*-----------------------------------------------------------------*/
771 regsInCommon (operand * op1, operand * op2)
776 /* if they have registers in common */
777 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
780 sym1 = OP_SYMBOL (op1);
781 sym2 = OP_SYMBOL (op2);
783 if (sym1->nRegs == 0 || sym2->nRegs == 0)
786 for (i = 0; i < sym1->nRegs; i++)
792 for (j = 0; j < sym2->nRegs; j++)
797 if (sym2->regs[j] == sym1->regs[i])
805 /*-----------------------------------------------------------------*/
806 /* operandsEqu - equivalent */
807 /*-----------------------------------------------------------------*/
809 operandsEqu (operand * op1, operand * op2)
813 /* if they not symbols */
814 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
817 sym1 = OP_SYMBOL (op1);
818 sym2 = OP_SYMBOL (op2);
820 /* if both are itemps & one is spilt
821 and the other is not then false */
822 if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
823 sym1->isspilt != sym2->isspilt)
826 /* if they are the same */
830 if (strcmp (sym1->rname, sym2->rname) == 0)
834 /* if left is a tmp & right is not */
835 if (IS_ITEMP (op1) &&
838 (sym1->usl.spillLoc == sym2))
841 if (IS_ITEMP (op2) &&
845 (sym2->usl.spillLoc == sym1))
851 /*-----------------------------------------------------------------*/
852 /* sameRegs - two asmops have the same registers */
853 /*-----------------------------------------------------------------*/
855 sameRegs (asmop * aop1, asmop * aop2)
859 if (aop1->type == AOP_SFR ||
860 aop2->type == AOP_SFR)
866 if (aop1->type != AOP_REG ||
867 aop2->type != AOP_REG)
870 if (aop1->size != aop2->size)
873 for (i = 0; i < aop1->size; i++)
874 if (aop1->aopu.aop_reg[i] !=
875 aop2->aopu.aop_reg[i])
881 /*-----------------------------------------------------------------*/
882 /* aopOp - allocates an asmop for an operand : */
883 /*-----------------------------------------------------------------*/
885 aopOp (operand * op, iCode * ic, bool result, bool requires_a)
894 /* if this a literal */
895 if (IS_OP_LITERAL (op))
897 op->aop = aop = newAsmop (AOP_LIT);
898 aop->aopu.aop_lit = op->operand.valOperand;
899 aop->size = getSize (operandType (op));
903 /* if already has a asmop then continue */
909 /* if the underlying symbol has a aop */
910 if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
912 op->aop = OP_SYMBOL (op)->aop;
916 /* if this is a true symbol */
917 if (IS_TRUE_SYMOP (op))
919 op->aop = aopForSym (ic, OP_SYMBOL (op), result, requires_a);
923 /* this is a temporary : this has
929 e) can be a return use only */
931 sym = OP_SYMBOL (op);
933 /* if the type is a conditional */
934 if (sym->regType == REG_CND)
936 aop = op->aop = sym->aop = newAsmop (AOP_CRY);
941 /* if it is spilt then two situations
943 b) has a spill location */
944 if (sym->isspilt || sym->nRegs == 0)
946 /* rematerialize it NOW */
949 sym->aop = op->aop = aop =
951 aop->size = getSize (sym->type);
958 aop = op->aop = sym->aop = newAsmop (AOP_STR);
959 aop->size = getSize (sym->type);
960 for (i = 0; i < 4; i++)
961 aop->aopu.aop_str[i] = _fReturn[i];
967 if (sym->accuse == ACCUSE_A)
969 aop = op->aop = sym->aop = newAsmop (AOP_ACC);
970 aop->size = getSize (sym->type);
971 wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
973 aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
975 else if (sym->accuse == ACCUSE_SCRATCH)
977 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
978 aop->size = getSize (sym->type);
979 wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
980 aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
981 aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
983 else if (sym->accuse == ACCUSE_IY)
985 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
986 aop->size = getSize (sym->type);
987 wassertl(aop->size <= 2, "Internal error: Caching in IY, but too big to fit in IY");
988 aop->aopu.aop_str[0] = _pairs[PAIR_IY].l;
989 aop->aopu.aop_str[1] = _pairs[PAIR_IY].h;
993 wassertl (0, "Marked as being allocated into A or HL but is actually in neither");
998 /* else spill location */
999 if (sym->usl.spillLoc && getSize(sym->type) != getSize(sym->usl.spillLoc->type)) {
1000 /* force a new aop if sizes differ */
1001 sym->usl.spillLoc->aop = NULL;
1003 sym->aop = op->aop = aop =
1004 aopForSym (ic, sym->usl.spillLoc, result, requires_a);
1005 wassertl (aop->size >= getSize (sym->type), "Operand doesn't fit in the spill location");
1006 aop->size = getSize (sym->type);
1010 /* must be in a register */
1011 sym->aop = op->aop = aop = newAsmop (AOP_REG);
1012 aop->size = sym->nRegs;
1013 for (i = 0; i < sym->nRegs; i++)
1014 aop->aopu.aop_reg[i] = sym->regs[i];
1017 /*-----------------------------------------------------------------*/
1018 /* freeAsmop - free up the asmop given to an operand */
1019 /*----------------------------------------------------------------*/
1021 freeAsmop (operand * op, asmop * aaop, iCode * ic)
1038 if (aop->type == AOP_PAIRPTR && IS_Z80 && aop->aopu.aop_pairId == PAIR_DE)
1040 _pop (aop->aopu.aop_pairId);
1043 if (getPairId (aop) == PAIR_HL)
1045 spillPair (PAIR_HL);
1049 /* all other cases just dealloc */
1055 OP_SYMBOL (op)->aop = NULL;
1056 /* if the symbol has a spill */
1058 SPIL_LOC (op)->aop = NULL;
1065 isLitWord (asmop * aop)
1067 /* if (aop->size != 2)
1080 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
1082 /* depending on type */
1088 /* PENDING: for re-target */
1091 tsprintf (buffer, sizeof(buffer),
1092 "!hashedstr + %d", aop->aopu.aop_immd, offset);
1094 else if (offset == 0)
1096 tsprintf (buffer, sizeof(buffer),
1097 "%s", aop->aopu.aop_immd);
1101 tsprintf (buffer, sizeof(buffer),
1102 "%s + %d", aop->aopu.aop_immd, offset);
1104 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1108 value *val = aop->aopu.aop_lit;
1109 /* if it is a float then it gets tricky */
1110 /* otherwise it is fairly simple */
1111 if (!IS_FLOAT (val->type))
1113 unsigned long v = (unsigned long) floatFromVal (val);
1119 else if (offset == 0)
1125 wassertl(0, "Encountered an invalid offset while fetching a literal");
1129 tsprintf (buffer, sizeof(buffer), "!immedword", v);
1131 tsprintf (buffer, sizeof(buffer), "!constword", v);
1133 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1144 /* it is type float */
1145 fl.f = (float) floatFromVal (val);
1148 i = fl.c[3-offset] | (fl.c[3-offset-1]<<8);
1150 i = fl.c[offset] | (fl.c[offset+1]<<8);
1153 tsprintf (buffer, sizeof(buffer), "!immedword", i);
1155 tsprintf (buffer, sizeof(buffer), "!constword", i);
1157 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1166 aopGetWord (asmop * aop, int offset)
1168 return aopGetLitWordLong (aop, offset, TRUE);
1172 isPtr (const char *s)
1174 if (!strcmp (s, "hl"))
1176 if (!strcmp (s, "ix"))
1178 if (!strcmp (s, "iy"))
1184 adjustPair (const char *pair, int *pold, int new)
1190 emit2 ("inc %s", pair);
1195 emit2 ("dec %s", pair);
1203 spillPair (PAIR_HL);
1204 spillPair (PAIR_IY);
1208 requiresHL (asmop * aop)
1224 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1226 const char *l, *base;
1227 const char *pair = _pairs[pairId].name;
1228 l = aopGetLitWordLong (left, offset, FALSE);
1229 base = aopGetLitWordLong (left, 0, FALSE);
1230 wassert (l && pair && base);
1234 if (pairId == PAIR_HL || pairId == PAIR_IY)
1236 if (_G.pairs[pairId].last_type == left->type)
1238 if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1240 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1242 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1245 if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
1252 _G.pairs[pairId].last_type = left->type;
1253 _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1254 _G.pairs[pairId].offset = offset;
1256 /* Both a lit on the right and a true symbol on the left */
1257 emit2 ("ld %s,!hashedstr", pair, l);
1261 makeFreePairId (iCode *ic, bool *pisUsed)
1267 if (!bitVectBitValue (ic->rMask, B_IDX) && !bitVectBitValue(ic->rMask, C_IDX))
1271 else if (IS_Z80 && !bitVectBitValue (ic->rMask, D_IDX) && !bitVectBitValue(ic->rMask, E_IDX))
1289 fetchPairLong (PAIR_ID pairId, asmop * aop, iCode *ic, int offset)
1291 /* if this is remateriazable */
1292 if (isLitWord (aop)) {
1293 fetchLitPair (pairId, aop, offset);
1297 if (getPairId (aop) == pairId)
1301 /* we need to get it byte by byte */
1302 else if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1303 aopGet (aop, offset, FALSE);
1304 switch (aop->size - offset) {
1306 emit2 ("ld l,!*hl");
1307 emit2 ("ld h,!immedbyte", 0);
1310 // PENDING: Requires that you are only fetching two bytes.
1313 emit2 ("ld h,!*hl");
1317 wassertl (0, "Attempted to fetch too much data into HL");
1321 else if (IS_Z80 && aop->type == AOP_IY) {
1322 /* Instead of fetching relative to IY, just grab directly
1323 from the address IY refers to */
1324 char *l = aopGetLitWordLong (aop, offset, FALSE);
1326 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1328 if (aop->size < 2) {
1329 emit2("ld %s,!zero", _pairs[pairId].h);
1332 else if (pairId == PAIR_IY)
1336 emit2 ("push %s", _pairs[getPairId(aop)].name);
1342 PAIR_ID id = makeFreePairId (ic, &isUsed);
1345 /* Can't load into parts, so load into HL then exchange. */
1346 emit2 ("ld %s,%s", _pairs[id].l, aopGet (aop, offset, FALSE));
1347 emit2 ("ld %s,%s", _pairs[id].h, aopGet (aop, offset + 1, FALSE));
1348 emit2 ("push %s", _pairs[id].name);
1356 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1357 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1359 /* PENDING: check? */
1360 if (pairId == PAIR_HL)
1361 spillPair (PAIR_HL);
1366 fetchPair (PAIR_ID pairId, asmop * aop)
1368 fetchPairLong (pairId, aop, NULL, 0);
1372 fetchHL (asmop * aop)
1374 fetchPair (PAIR_HL, aop);
1378 setupPairFromSP (PAIR_ID id, int offset)
1380 wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
1382 if (offset < INT8MIN || offset > INT8MAX)
1384 emit2 ("ld hl,!immedword", offset);
1385 emit2 ("add hl,sp");
1389 emit2 ("!ldahlsp", offset);
1394 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1399 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
1400 fetchLitPair (pairId, aop, 0);
1404 wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
1406 fetchLitPair (pairId, aop, offset);
1407 _G.pairs[pairId].offset = offset;
1411 wassertl (IS_Z80, "Only the Z80 has an extended stack");
1412 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
1415 int offset = aop->aopu.aop_stk + _G.stack.offset;
1417 if (_G.pairs[pairId].last_type == aop->type &&
1418 _G.pairs[pairId].offset == offset)
1424 /* PENDING: Do this better. */
1425 sprintf (buffer, "%d", offset + _G.stack.pushed);
1426 emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
1427 emit2 ("add %s,sp", _pairs[pairId].name);
1428 _G.pairs[pairId].last_type = aop->type;
1429 _G.pairs[pairId].offset = offset;
1436 /* Doesnt include _G.stack.pushed */
1437 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1439 if (aop->aopu.aop_stk > 0)
1441 abso += _G.stack.param_offset;
1443 assert (pairId == PAIR_HL);
1444 /* In some cases we can still inc or dec hl */
1445 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1447 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1451 setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
1453 _G.pairs[pairId].offset = abso;
1458 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
1464 _G.pairs[pairId].last_type = aop->type;
1470 emit2 ("!tlabeldef", key);
1474 /*-----------------------------------------------------------------*/
1475 /* aopGet - for fetching value of the aop */
1476 /*-----------------------------------------------------------------*/
1478 aopGet (asmop * aop, int offset, bool bit16)
1480 // char *s = buffer;
1482 /* offset is greater than size then zero */
1483 /* PENDING: this seems a bit screwed in some pointer cases. */
1484 if (offset > (aop->size - 1) &&
1485 aop->type != AOP_LIT)
1487 tsprintf (buffer, sizeof(buffer), "!zero");
1488 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1491 /* depending on type */
1495 /* PENDING: re-target */
1497 tsprintf (buffer, sizeof(buffer), "!immedwords", aop->aopu.aop_immd);
1502 tsprintf (buffer, sizeof(buffer), "!bankimmeds", aop->aopu.aop_immd);
1505 tsprintf (buffer, sizeof(buffer), "!msbimmeds", aop->aopu.aop_immd);
1508 tsprintf (buffer, sizeof(buffer), "!lsbimmeds", aop->aopu.aop_immd);
1511 wassertl (0, "Fetching from beyond the limits of an immediate value.");
1514 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1518 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1519 SNPRINTF (buffer, sizeof(buffer), "a");
1521 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1525 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1526 SNPRINTF (buffer, sizeof(buffer), "a");
1528 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1531 return aop->aopu.aop_reg[offset]->name;
1535 setupPair (PAIR_HL, aop, offset);
1536 tsprintf (buffer, sizeof(buffer), "!*hl");
1538 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
1542 setupPair (PAIR_IY, aop, offset);
1543 tsprintf (buffer, sizeof(buffer), "!*iyx", offset);
1545 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1549 setupPair (PAIR_IY, aop, offset);
1550 tsprintf (buffer, sizeof(buffer), "!*iyx", offset, offset);
1552 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1557 setupPair (PAIR_HL, aop, offset);
1558 tsprintf (buffer, sizeof(buffer), "!*hl");
1562 if (aop->aopu.aop_stk >= 0)
1563 offset += _G.stack.param_offset;
1564 tsprintf (buffer, sizeof(buffer),
1565 "!*ixx", aop->aopu.aop_stk + offset);
1568 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1571 wassertl (0, "Tried to fetch from a bit variable");
1580 tsprintf(buffer, sizeof(buffer), "!zero");
1581 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1585 wassert (offset < 2);
1586 return aop->aopu.aop_str[offset];
1589 return aopLiteral (aop->aopu.aop_lit, offset);
1593 unsigned long v = aop->aopu.aop_simplelit;
1596 tsprintf (buffer, sizeof(buffer),
1597 "!immedbyte", (unsigned int) v & 0xff);
1599 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1603 return aop->aopu.aop_str[offset];
1606 setupPair (aop->aopu.aop_pairId, aop, offset);
1607 SNPRINTF (buffer, sizeof(buffer),
1608 "(%s)", _pairs[aop->aopu.aop_pairId].name);
1610 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1615 wassertl (0, "aopget got unsupported aop->type");
1620 isRegString (const char *s)
1622 if (!strcmp (s, "b") ||
1634 isConstant (const char *s)
1636 /* This is a bit of a hack... */
1637 return (*s == '#' || *s == '$');
1641 canAssignToPtr (const char *s)
1643 if (isRegString (s))
1650 /*-----------------------------------------------------------------*/
1651 /* aopPut - puts a string for a aop */
1652 /*-----------------------------------------------------------------*/
1654 aopPut (asmop * aop, const char *s, int offset)
1658 if (aop->size && offset > (aop->size - 1))
1660 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1661 "aopPut got offset > aop->size");
1666 tsprintf(buffer2, sizeof(buffer2), s);
1669 /* will assign value to value */
1670 /* depending on where it is ofcourse */
1676 if (strcmp (s, "a"))
1677 emit2 ("ld a,%s", s);
1678 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1683 if (strcmp (s, "a"))
1684 emit2 ("ld a,%s", s);
1685 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1689 if (!strcmp (s, "!*hl"))
1690 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1693 aop->aopu.aop_reg[offset]->name, s);
1698 if (!canAssignToPtr (s))
1700 emit2 ("ld a,%s", s);
1701 setupPair (PAIR_IY, aop, offset);
1702 emit2 ("ld !*iyx,a", offset);
1706 setupPair (PAIR_IY, aop, offset);
1707 emit2 ("ld !*iyx,%s", offset, s);
1713 /* PENDING: for re-target */
1714 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1716 emit2 ("ld a,!*hl");
1719 setupPair (PAIR_HL, aop, offset);
1721 emit2 ("ld !*hl,%s", s);
1726 if (!canAssignToPtr (s))
1728 emit2 ("ld a,%s", s);
1729 setupPair (PAIR_IY, aop, offset);
1730 emit2 ("ld !*iyx,a", offset);
1734 setupPair (PAIR_IY, aop, offset);
1735 emit2 ("ld !*iyx,%s", offset, s);
1742 /* PENDING: re-target */
1743 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1745 emit2 ("ld a,!*hl");
1748 setupPair (PAIR_HL, aop, offset);
1749 if (!canAssignToPtr (s))
1751 emit2 ("ld a,%s", s);
1752 emit2 ("ld !*hl,a");
1755 emit2 ("ld !*hl,%s", s);
1759 if (aop->aopu.aop_stk >= 0)
1760 offset += _G.stack.param_offset;
1761 if (!canAssignToPtr (s))
1763 emit2 ("ld a,%s", s);
1764 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
1768 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
1774 /* if bit variable */
1775 if (!aop->aopu.aop_dir)
1777 emit2 ("ld a,!zero");
1782 /* In bit space but not in C - cant happen */
1783 wassertl (0, "Tried to write into a bit variable");
1789 if (strcmp (aop->aopu.aop_str[offset], s))
1791 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1797 if (!offset && (strcmp (s, "acc") == 0))
1801 wassertl (0, "Tried to access past the end of A");
1805 if (strcmp (aop->aopu.aop_str[offset], s))
1806 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1811 wassert (offset < 2);
1812 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1816 setupPair (aop->aopu.aop_pairId, aop, offset);
1817 emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
1821 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1822 "aopPut got unsupported aop->type");
1827 #define AOP(op) op->aop
1828 #define AOP_TYPE(op) AOP(op)->type
1829 #define AOP_SIZE(op) AOP(op)->size
1830 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
1833 commitPair (asmop * aop, PAIR_ID id)
1835 /* PENDING: Verify this. */
1836 if (id == PAIR_HL && requiresHL (aop) && IS_GB)
1840 aopPut (aop, "a", 0);
1841 aopPut (aop, "d", 1);
1846 if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
1848 char *l = aopGetLitWordLong (aop, 0, FALSE);
1851 emit2 ("ld (%s),%s", l, _pairs[id].name);
1855 aopPut (aop, _pairs[id].l, 0);
1856 aopPut (aop, _pairs[id].h, 1);
1861 /*-----------------------------------------------------------------*/
1862 /* getDataSize - get the operand data size */
1863 /*-----------------------------------------------------------------*/
1865 getDataSize (operand * op)
1868 size = AOP_SIZE (op);
1872 wassertl (0, "Somehow got a three byte data pointer");
1877 /*-----------------------------------------------------------------*/
1878 /* movLeft2Result - move byte from left to result */
1879 /*-----------------------------------------------------------------*/
1881 movLeft2Result (operand * left, int offl,
1882 operand * result, int offr, int sign)
1886 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
1888 l = aopGet (AOP (left), offl, FALSE);
1892 aopPut (AOP (result), l, offr);
1896 if (getDataSize (left) == offl + 1)
1898 emit2 ("ld a,%s", l);
1899 aopPut (AOP (result), "a", offr);
1906 movLeft2ResultLong (operand * left, int offl,
1907 operand * result, int offr, int sign,
1912 movLeft2Result (left, offl, result, offr, sign);
1916 wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
1917 wassertl (size == 2, "Only implemented for two bytes or one");
1919 if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
1921 emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
1922 emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
1924 spillPair (PAIR_HL);
1926 else if ( getPairId ( AOP (result)) == PAIR_IY)
1928 PAIR_ID id = getPairId (AOP (left));
1929 if (id != PAIR_INVALID)
1931 emit2("push %s", _pairs[id].name);
1942 movLeft2Result (left, offl, result, offr, sign);
1943 movLeft2Result (left, offl+1, result, offr+1, sign);
1948 /** Put Acc into a register set
1951 outAcc (operand * result)
1954 size = getDataSize (result);
1957 aopPut (AOP (result), "a", 0);
1960 /* unsigned or positive */
1963 aopPut (AOP (result), "!zero", offset++);
1968 /** Take the value in carry and put it into a register
1971 outBitCLong (operand * result, bool swap_sense)
1973 /* if the result is bit */
1974 if (AOP_TYPE (result) == AOP_CRY)
1976 wassertl (0, "Tried to write carry to a bit");
1980 emit2 ("ld a,!zero");
1983 emit2 ("xor a,!immedbyte", 1);
1989 outBitC (operand * result)
1991 outBitCLong (result, FALSE);
1994 /*-----------------------------------------------------------------*/
1995 /* toBoolean - emit code for orl a,operator(sizeop) */
1996 /*-----------------------------------------------------------------*/
1998 _toBoolean (operand * oper)
2000 int size = AOP_SIZE (oper);
2004 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
2007 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
2011 if (AOP (oper)->type != AOP_ACC)
2014 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
2019 /*-----------------------------------------------------------------*/
2020 /* genNotFloat - generates not for float operations */
2021 /*-----------------------------------------------------------------*/
2023 genNotFloat (operand * op, operand * res)
2028 emitDebug ("; genNotFloat");
2030 /* we will put 127 in the first byte of
2032 aopPut (AOP (res), "!immedbyte", 0x7F);
2033 size = AOP_SIZE (op) - 1;
2036 _moveA (aopGet (op->aop, offset++, FALSE));
2040 emit2 ("or a,%s", aopGet (op->aop, offset++, FALSE));
2043 tlbl = newiTempLabel (NULL);
2044 aopPut (res->aop, "!one", 1);
2045 emit2 ("!shortjp z !tlabel", tlbl->key + 100);
2046 aopPut (res->aop, "!zero", 1);
2048 emitLabel(tlbl->key + 100);
2050 size = res->aop->size - 2;
2052 /* put zeros in the rest */
2054 aopPut (res->aop, "!zero", offset++);
2057 /*-----------------------------------------------------------------*/
2058 /* genNot - generate code for ! operation */
2059 /*-----------------------------------------------------------------*/
2063 sym_link *optype = operandType (IC_LEFT (ic));
2065 /* assign asmOps to operand & result */
2066 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
2067 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2069 /* if in bit space then a special case */
2070 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2072 wassertl (0, "Tried to negate a bit");
2075 /* if type float then do float */
2076 if (IS_FLOAT (optype))
2078 genNotFloat (IC_LEFT (ic), IC_RESULT (ic));
2082 _toBoolean (IC_LEFT (ic));
2087 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
2088 emit2 ("sub a,!one");
2089 outBitC (IC_RESULT (ic));
2092 /* release the aops */
2093 freeAsmop (IC_LEFT (ic), NULL, ic);
2094 freeAsmop (IC_RESULT (ic), NULL, ic);
2097 /*-----------------------------------------------------------------*/
2098 /* genCpl - generate code for complement */
2099 /*-----------------------------------------------------------------*/
2107 /* assign asmOps to operand & result */
2108 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2109 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2111 /* if both are in bit space then
2113 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2114 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2116 wassertl (0, "Left and the result are in bit space");
2119 size = AOP_SIZE (IC_RESULT (ic));
2122 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2125 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2128 /* release the aops */
2129 freeAsmop (IC_LEFT (ic), NULL, ic);
2130 freeAsmop (IC_RESULT (ic), NULL, ic);
2134 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
2141 store de into result
2146 store de into result
2148 const char *first = isAdd ? "add" : "sub";
2149 const char *later = isAdd ? "adc" : "sbc";
2151 wassertl (IS_GB, "Code is only relevent to the gbz80");
2152 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
2154 fetchPair (PAIR_DE, left);
2157 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
2160 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2163 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2164 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2166 fetchPairLong (PAIR_DE, left, NULL, MSB24);
2167 aopGet (right, MSB24, FALSE);
2171 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2174 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2176 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2177 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2181 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2183 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2186 /*-----------------------------------------------------------------*/
2187 /* genUminusFloat - unary minus for floating points */
2188 /*-----------------------------------------------------------------*/
2190 genUminusFloat (operand * op, operand * result)
2192 int size, offset = 0;
2194 emitDebug("; genUminusFloat");
2196 /* for this we just need to flip the
2197 first it then copy the rest in place */
2198 size = AOP_SIZE (op) - 1;
2200 _moveA(aopGet (AOP (op), MSB32, FALSE));
2202 emit2("xor a,!immedbyte", 0x80);
2203 aopPut (AOP (result), "a", MSB32);
2207 aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2212 /*-----------------------------------------------------------------*/
2213 /* genUminus - unary minus code generation */
2214 /*-----------------------------------------------------------------*/
2216 genUminus (iCode * ic)
2219 sym_link *optype, *rtype;
2222 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2223 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2225 /* if both in bit space then special
2227 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2228 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2230 wassertl (0, "Left and right are in bit space");
2234 optype = operandType (IC_LEFT (ic));
2235 rtype = operandType (IC_RESULT (ic));
2237 /* if float then do float stuff */
2238 if (IS_FLOAT (optype))
2240 genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2244 /* otherwise subtract from zero */
2245 size = AOP_SIZE (IC_LEFT (ic));
2247 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2249 /* Create a new asmop with value zero */
2250 asmop *azero = newAsmop (AOP_SIMPLELIT);
2251 azero->aopu.aop_simplelit = 0;
2253 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2261 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2262 emit2 ("ld a,!zero");
2263 emit2 ("sbc a,%s", l);
2264 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2267 /* if any remaining bytes in the result */
2268 /* we just need to propagate the sign */
2269 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2274 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2278 /* release the aops */
2279 freeAsmop (IC_LEFT (ic), NULL, ic);
2280 freeAsmop (IC_RESULT (ic), NULL, ic);
2283 /*-----------------------------------------------------------------*/
2284 /* assignResultValue - */
2285 /*-----------------------------------------------------------------*/
2287 assignResultValue (operand * oper)
2289 int size = AOP_SIZE (oper);
2292 wassertl (size <= 4, "Got a result that is bigger than four bytes");
2293 topInA = requiresHL (AOP (oper));
2295 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2297 /* We do it the hard way here. */
2299 aopPut (AOP (oper), _fReturn[0], 0);
2300 aopPut (AOP (oper), _fReturn[1], 1);
2302 aopPut (AOP (oper), _fReturn[0], 2);
2303 aopPut (AOP (oper), _fReturn[1], 3);
2309 aopPut (AOP (oper), _fReturn[size], size);
2314 /** Simple restore that doesn't take into account what is used in the
2318 _restoreRegsAfterCall(void)
2320 if (_G.stack.pushedDE)
2323 _G.stack.pushedDE = FALSE;
2325 if (_G.stack.pushedBC)
2328 _G.stack.pushedBC = FALSE;
2330 _G.saves.saved = FALSE;
2334 _saveRegsForCall(iCode *ic, int sendSetSize)
2337 o Stack parameters are pushed before this function enters
2338 o DE and BC may be used in this function.
2339 o HL and DE may be used to return the result.
2340 o HL and DE may be used to send variables.
2341 o DE and BC may be used to store the result value.
2342 o HL may be used in computing the sent value of DE
2343 o The iPushes for other parameters occur before any addSets
2345 Logic: (to be run inside the first iPush or if none, before sending)
2346 o Compute if DE and/or BC are in use over the call
2347 o Compute if DE is used in the send set
2348 o Compute if DE and/or BC are used to hold the result value
2349 o If (DE is used, or in the send set) and is not used in the result, push.
2350 o If BC is used and is not in the result, push
2352 o If DE is used in the send set, fetch
2353 o If HL is used in the send set, fetch
2357 if (_G.saves.saved == FALSE) {
2358 bool deInUse, bcInUse;
2360 bool bcInRet = FALSE, deInRet = FALSE;
2363 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
2365 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2366 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2368 deSending = (sendSetSize > 1);
2370 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2372 if (bcInUse && bcInRet == FALSE) {
2374 _G.stack.pushedBC = TRUE;
2376 if (deInUse && deInRet == FALSE) {
2378 _G.stack.pushedDE = TRUE;
2381 _G.saves.saved = TRUE;
2384 /* Already saved. */
2388 /*-----------------------------------------------------------------*/
2389 /* genIpush - genrate code for pushing this gets a little complex */
2390 /*-----------------------------------------------------------------*/
2392 genIpush (iCode * ic)
2394 int size, offset = 0;
2397 /* if this is not a parm push : ie. it is spill push
2398 and spill push is always done on the local stack */
2401 wassertl(0, "Encountered an unsupported spill push.");
2405 if (_G.saves.saved == FALSE) {
2406 /* Caller saves, and this is the first iPush. */
2407 /* Scan ahead until we find the function that we are pushing parameters to.
2408 Count the number of addSets on the way to figure out what registers
2409 are used in the send set.
2412 iCode *walk = ic->next;
2415 if (walk->op == SEND) {
2418 else if (walk->op == CALL || walk->op == PCALL) {
2427 _saveRegsForCall(walk, nAddSets);
2430 /* Already saved by another iPush. */
2433 /* then do the push */
2434 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2436 size = AOP_SIZE (IC_LEFT (ic));
2438 if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2440 _G.stack.pushed += 2;
2441 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2447 fetchHL (AOP (IC_LEFT (ic)));
2449 spillPair (PAIR_HL);
2450 _G.stack.pushed += 2;
2455 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
2457 spillPair (PAIR_HL);
2458 _G.stack.pushed += 2;
2459 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
2461 spillPair (PAIR_HL);
2462 _G.stack.pushed += 2;
2468 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2470 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2472 emit2 ("ld a,(%s)", l);
2476 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2477 emit2 ("ld a,%s", l);
2485 freeAsmop (IC_LEFT (ic), NULL, ic);
2488 /*-----------------------------------------------------------------*/
2489 /* genIpop - recover the registers: can happen only for spilling */
2490 /*-----------------------------------------------------------------*/
2492 genIpop (iCode * ic)
2497 /* if the temp was not pushed then */
2498 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2501 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2502 size = AOP_SIZE (IC_LEFT (ic));
2503 offset = (size - 1);
2504 if (isPair (AOP (IC_LEFT (ic))))
2506 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2514 spillPair (PAIR_HL);
2515 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2519 freeAsmop (IC_LEFT (ic), NULL, ic);
2522 /* This is quite unfortunate */
2524 setArea (int inHome)
2527 static int lastArea = 0;
2529 if (_G.in_home != inHome) {
2531 const char *sz = port->mem.code_name;
2532 port->mem.code_name = "HOME";
2533 emit2("!area", CODE_NAME);
2534 port->mem.code_name = sz;
2537 emit2("!area", CODE_NAME); */
2538 _G.in_home = inHome;
2549 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2553 symbol *sym = OP_SYMBOL (op);
2555 if (sym->isspilt || sym->nRegs == 0)
2558 aopOp (op, ic, FALSE, FALSE);
2561 if (aop->type == AOP_REG)
2564 for (i = 0; i < aop->size; i++)
2566 if (pairId == PAIR_DE)
2568 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2569 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2571 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2574 else if (pairId == PAIR_BC)
2576 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2577 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2579 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2589 freeAsmop (IC_LEFT (ic), NULL, ic);
2593 /** Emit the code for a call statement
2596 emitCall (iCode * ic, bool ispcall)
2598 sym_link *dtype = operandType (IC_LEFT (ic));
2600 /* if caller saves & we have not saved then */
2606 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2608 /* if send set is not empty then assign */
2613 int nSend = elementsInSet(_G.sendSet);
2614 bool swapped = FALSE;
2616 int _z80_sendOrder[] = {
2621 /* Check if the parameters are swapped. If so route through hl instead. */
2622 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2624 sic = setFirstItem(_G.sendSet);
2625 sic = setNextItem(_G.sendSet);
2627 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2628 /* The second send value is loaded from one the one that holds the first
2629 send, i.e. it is overwritten. */
2630 /* Cache the first in HL, and load the second from HL instead. */
2631 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2632 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2638 for (sic = setFirstItem (_G.sendSet); sic;
2639 sic = setNextItem (_G.sendSet))
2642 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2644 size = AOP_SIZE (IC_LEFT (sic));
2645 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2646 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2648 // PENDING: Mild hack
2649 if (swapped == TRUE && send == 1) {
2651 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2654 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2656 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2659 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2663 freeAsmop (IC_LEFT (sic), NULL, sic);
2670 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2672 werror (W_INDIR_BANKED);
2674 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2676 if (isLitWord (AOP (IC_LEFT (ic))))
2678 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2682 symbol *rlbl = newiTempLabel (NULL);
2683 spillPair (PAIR_HL);
2684 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2686 _G.stack.pushed += 2;
2688 fetchHL (AOP (IC_LEFT (ic)));
2690 emit2 ("!tlabeldef", (rlbl->key + 100));
2691 _G.stack.pushed -= 2;
2693 freeAsmop (IC_LEFT (ic), NULL, ic);
2697 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2698 OP_SYMBOL (IC_LEFT (ic))->rname :
2699 OP_SYMBOL (IC_LEFT (ic))->name;
2700 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2702 emit2 ("call banked_call");
2703 emit2 ("!dws", name);
2704 emit2 ("!dw !bankimmeds", name);
2709 emit2 ("call %s", name);
2714 /* Mark the regsiters as restored. */
2715 _G.saves.saved = FALSE;
2717 /* if we need assign a result value */
2718 if ((IS_ITEMP (IC_RESULT (ic)) &&
2719 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2720 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2721 IS_TRUE_SYMOP (IC_RESULT (ic)))
2724 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2726 assignResultValue (IC_RESULT (ic));
2728 freeAsmop (IC_RESULT (ic), NULL, ic);
2731 /* adjust the stack for parameters if required */
2734 int i = ic->parmBytes;
2736 _G.stack.pushed -= i;
2739 emit2 ("!ldaspsp", i);
2746 emit2 ("ld iy,!immedword", i);
2747 emit2 ("add iy,sp");
2767 if (_G.stack.pushedDE)
2769 bool dInRet = bitVectBitValue(ic->rUsed, D_IDX);
2770 bool eInRet = bitVectBitValue(ic->rUsed, E_IDX);
2772 if (dInRet && eInRet)
2774 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
2778 /* Only restore E */
2785 /* Only restore D */
2793 _G.stack.pushedDE = FALSE;
2796 if (_G.stack.pushedBC)
2798 bool bInRet = bitVectBitValue(ic->rUsed, B_IDX);
2799 bool cInRet = bitVectBitValue(ic->rUsed, C_IDX);
2801 if (bInRet && cInRet)
2803 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
2807 /* Only restore C */
2814 /* Only restore B */
2822 _G.stack.pushedBC = FALSE;
2826 /*-----------------------------------------------------------------*/
2827 /* genCall - generates a call statement */
2828 /*-----------------------------------------------------------------*/
2830 genCall (iCode * ic)
2832 emitCall (ic, FALSE);
2835 /*-----------------------------------------------------------------*/
2836 /* genPcall - generates a call by pointer statement */
2837 /*-----------------------------------------------------------------*/
2839 genPcall (iCode * ic)
2841 emitCall (ic, TRUE);
2844 /*-----------------------------------------------------------------*/
2845 /* resultRemat - result is rematerializable */
2846 /*-----------------------------------------------------------------*/
2848 resultRemat (iCode * ic)
2850 if (SKIP_IC (ic) || ic->op == IFX)
2853 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2855 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2856 if (sym->remat && !POINTER_SET (ic))
2863 extern set *publics;
2865 /*-----------------------------------------------------------------*/
2866 /* genFunction - generated code for function entry */
2867 /*-----------------------------------------------------------------*/
2869 genFunction (iCode * ic)
2871 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2874 bool bcInUse = FALSE;
2875 bool deInUse = FALSE;
2877 setArea (IFFUNC_NONBANKED (sym->type));
2879 /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
2882 _G.receiveOffset = 0;
2884 /* Record the last function name for debugging. */
2885 _G.lastFunctionName = sym->rname;
2887 /* Create the function header */
2888 emit2 ("!functionheader", sym->name);
2889 sprintf (buffer, "%s_start", sym->rname);
2890 emit2 ("!labeldef", buffer);
2891 emit2 ("!functionlabeldef", sym->rname);
2893 if (options.profile)
2895 emit2 ("!profileenter");
2898 ftype = operandType (IC_LEFT (ic));
2900 /* if critical function then turn interrupts off */
2901 if (IFFUNC_ISCRITICAL (ftype))
2904 /* if this is an interrupt service routine then save all potentially used registers. */
2905 if (IFFUNC_ISISR (sym->type))
2910 /* PENDING: callee-save etc */
2912 _G.stack.param_offset = 0;
2914 if (z80_opts.calleeSavesBC)
2919 /* Detect which registers are used. */
2920 if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
2923 for (i = 0; i < sym->regsUsed->size; i++)
2925 if (bitVectBitValue (sym->regsUsed, i))
2939 /* Other systems use DE as a temporary. */
2950 _G.stack.param_offset += 2;
2953 _G.calleeSaves.pushedBC = bcInUse;
2958 _G.stack.param_offset += 2;
2961 _G.calleeSaves.pushedDE = deInUse;
2963 /* adjust the stack for the function */
2964 _G.stack.last = sym->stack;
2966 if (sym->stack && IS_GB && sym->stack > -INT8MIN)
2967 emit2 ("!enterxl", sym->stack);
2968 else if (sym->stack)
2969 emit2 ("!enterx", sym->stack);
2972 _G.stack.offset = sym->stack;
2975 /*-----------------------------------------------------------------*/
2976 /* genEndFunction - generates epilogue for functions */
2977 /*-----------------------------------------------------------------*/
2979 genEndFunction (iCode * ic)
2981 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2983 if (IFFUNC_ISISR (sym->type))
2985 wassertl (0, "Tried to close an interrupt support function");
2989 if (IFFUNC_ISCRITICAL (sym->type))
2992 /* PENDING: calleeSave */
2994 if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
2996 emit2 ("!leavexl", _G.stack.offset);
2998 else if (_G.stack.offset)
3000 emit2 ("!leavex", _G.stack.offset);
3007 if (_G.calleeSaves.pushedDE)
3010 _G.calleeSaves.pushedDE = FALSE;
3013 if (_G.calleeSaves.pushedBC)
3016 _G.calleeSaves.pushedBC = FALSE;
3019 if (options.profile)
3021 emit2 ("!profileexit");
3025 /* Both baned and non-banked just ret */
3028 sprintf (buffer, "%s_end", sym->rname);
3029 emit2 ("!labeldef", buffer);
3031 _G.flushStatics = 1;
3032 _G.stack.pushed = 0;
3033 _G.stack.offset = 0;
3036 /*-----------------------------------------------------------------*/
3037 /* genRet - generate code for return statement */
3038 /*-----------------------------------------------------------------*/
3043 /* Errk. This is a hack until I can figure out how
3044 to cause dehl to spill on a call */
3045 int size, offset = 0;
3047 /* if we have no return value then
3048 just generate the "ret" */
3052 /* we have something to return then
3053 move the return value into place */
3054 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3055 size = AOP_SIZE (IC_LEFT (ic));
3057 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3061 emit2 ("ld de,%s", l);
3065 emit2 ("ld hl,%s", l);
3070 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3072 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3073 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3079 l = aopGet (AOP (IC_LEFT (ic)), offset,
3081 if (strcmp (_fReturn[offset], l))
3082 emit2 ("ld %s,%s", _fReturn[offset++], l);
3086 freeAsmop (IC_LEFT (ic), NULL, ic);
3089 /* generate a jump to the return label
3090 if the next is not the return statement */
3091 if (!(ic->next && ic->next->op == LABEL &&
3092 IC_LABEL (ic->next) == returnLabel))
3094 emit2 ("jp !tlabel", returnLabel->key + 100);
3097 /*-----------------------------------------------------------------*/
3098 /* genLabel - generates a label */
3099 /*-----------------------------------------------------------------*/
3101 genLabel (iCode * ic)
3103 /* special case never generate */
3104 if (IC_LABEL (ic) == entryLabel)
3107 emitLabel (IC_LABEL (ic)->key + 100);
3110 /*-----------------------------------------------------------------*/
3111 /* genGoto - generates a ljmp */
3112 /*-----------------------------------------------------------------*/
3114 genGoto (iCode * ic)
3116 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3119 /*-----------------------------------------------------------------*/
3120 /* genPlusIncr :- does addition with increment if possible */
3121 /*-----------------------------------------------------------------*/
3123 genPlusIncr (iCode * ic)
3125 unsigned int icount;
3126 unsigned int size = getDataSize (IC_RESULT (ic));
3127 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3129 /* will try to generate an increment */
3130 /* if the right side is not a literal
3132 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3135 emitDebug ("; genPlusIncr");
3137 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3139 /* If result is a pair */
3140 if (resultId != PAIR_INVALID)
3142 if (isLitWord (AOP (IC_LEFT (ic))))
3144 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3147 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3149 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3151 PAIR_ID freep = getFreePairId (ic);
3152 if (freep != PAIR_INVALID)
3154 fetchPair (freep, AOP (IC_RIGHT (ic)));
3155 emit2 ("add hl,%s", _pairs[freep].name);
3161 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3162 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3169 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3173 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3177 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3182 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3184 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3185 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3189 /* if the literal value of the right hand side
3190 is greater than 4 then it is not worth it */
3194 /* if increment 16 bits in register */
3195 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3201 symbol *tlbl = NULL;
3202 tlbl = newiTempLabel (NULL);
3205 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3208 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3211 emitLabel (tlbl->key + 100);
3215 /* if the sizes are greater than 1 then we cannot */
3216 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3217 AOP_SIZE (IC_LEFT (ic)) > 1)
3220 /* If the result is in a register then we can load then increment.
3222 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3224 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3227 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3232 /* we can if the aops of the left & result match or
3233 if they are in registers and the registers are the
3235 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3239 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3247 /*-----------------------------------------------------------------*/
3248 /* outBitAcc - output a bit in acc */
3249 /*-----------------------------------------------------------------*/
3251 outBitAcc (operand * result)
3253 symbol *tlbl = newiTempLabel (NULL);
3254 /* if the result is a bit */
3255 if (AOP_TYPE (result) == AOP_CRY)
3257 wassertl (0, "Tried to write A into a bit");
3261 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3262 emit2 ("ld a,!one");
3263 emitLabel (tlbl->key + 100);
3269 couldDestroyCarry (asmop *aop)
3273 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3282 shiftIntoPair (int idx, asmop *aop)
3284 PAIR_ID id = PAIR_INVALID;
3286 wassertl (IS_Z80, "Only implemented for the Z80");
3287 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3299 wassertl (0, "Internal error - hit default case");
3302 emitDebug ("; Shift into pair idx %u", idx);
3306 setupPair (PAIR_HL, aop, 0);
3310 setupPair (PAIR_IY, aop, 0);
3312 emit2 ("pop %s", _pairs[id].name);
3315 aop->type = AOP_PAIRPTR;
3316 aop->aopu.aop_pairId = id;
3317 _G.pairs[id].offset = 0;
3318 _G.pairs[id].last_type = aop->type;
3322 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
3324 wassert (left && right);
3328 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3330 shiftIntoPair (0, right);
3331 shiftIntoPair (1, result);
3333 else if (couldDestroyCarry (right))
3335 shiftIntoPair (0, right);
3337 else if (couldDestroyCarry (result))
3339 shiftIntoPair (0, result);
3348 /*-----------------------------------------------------------------*/
3349 /* genPlus - generates code for addition */
3350 /*-----------------------------------------------------------------*/
3352 genPlus (iCode * ic)
3354 int size, offset = 0;
3356 /* special cases :- */
3358 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3359 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3360 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3362 /* Swap the left and right operands if:
3364 if literal, literal on the right or
3365 if left requires ACC or right is already
3368 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3369 (AOP_NEEDSACC (IC_LEFT (ic))) ||
3370 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3372 operand *t = IC_RIGHT (ic);
3373 IC_RIGHT (ic) = IC_LEFT (ic);
3377 /* if both left & right are in bit
3379 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3380 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3383 wassertl (0, "Tried to add two bits");
3386 /* if left in bit space & right literal */
3387 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3388 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3390 /* Can happen I guess */
3391 wassertl (0, "Tried to add a bit to a literal");
3394 /* if I can do an increment instead
3395 of add then GOOD for ME */
3396 if (genPlusIncr (ic) == TRUE)
3399 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3401 size = getDataSize (IC_RESULT (ic));
3403 /* Special case when left and right are constant */
3404 if (isPair (AOP (IC_RESULT (ic))))
3407 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3408 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3410 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3416 sprintf (buffer, "#(%s + %s)", left, right);
3417 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3422 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3424 /* Fetch into HL then do the add */
3425 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3426 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3428 spillPair (PAIR_HL);
3430 if (left == PAIR_HL && right != PAIR_INVALID)
3432 emit2 ("add hl,%s", _pairs[right].name);
3435 else if (right == PAIR_HL && left != PAIR_INVALID)
3437 emit2 ("add hl,%s", _pairs[left].name);
3440 else if (right != PAIR_INVALID && right != PAIR_HL)
3442 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3443 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3446 else if (left != PAIR_INVALID && left != PAIR_HL)
3448 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3449 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3458 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3460 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3461 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3463 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3468 ld hl,sp+n trashes C so we cant afford to do it during an
3469 add with stack based varibles. Worst case is:
3482 So you cant afford to load up hl if either left, right, or result
3483 is on the stack (*sigh*) The alt is:
3491 Combinations in here are:
3492 * If left or right are in bc then the loss is small - trap later
3493 * If the result is in bc then the loss is also small
3497 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3498 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3499 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3501 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3502 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3503 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3504 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3506 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3508 /* Swap left and right */
3509 operand *t = IC_RIGHT (ic);
3510 IC_RIGHT (ic) = IC_LEFT (ic);
3513 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3515 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3516 emit2 ("add hl,bc");
3520 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3521 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3522 emit2 ("add hl,de");
3524 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3530 /* Be paranoid on the GB with 4 byte variables due to how C
3531 can be trashed by lda hl,n(sp).
3533 _gbz80_emitAddSubLong (ic, TRUE);
3538 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3542 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3544 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3547 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3550 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3554 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3557 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3560 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3562 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3566 freeAsmop (IC_LEFT (ic), NULL, ic);
3567 freeAsmop (IC_RIGHT (ic), NULL, ic);
3568 freeAsmop (IC_RESULT (ic), NULL, ic);
3572 /*-----------------------------------------------------------------*/
3573 /* genMinusDec :- does subtraction with deccrement if possible */
3574 /*-----------------------------------------------------------------*/
3576 genMinusDec (iCode * ic)
3578 unsigned int icount;
3579 unsigned int size = getDataSize (IC_RESULT (ic));
3581 /* will try to generate an increment */
3582 /* if the right side is not a literal we cannot */
3583 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3586 /* if the literal value of the right hand side
3587 is greater than 4 then it is not worth it */
3588 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3591 size = getDataSize (IC_RESULT (ic));
3593 /* if decrement 16 bits in register */
3594 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3595 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3598 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3602 /* If result is a pair */
3603 if (isPair (AOP (IC_RESULT (ic))))
3605 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3607 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3611 /* if increment 16 bits in register */
3612 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3616 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3619 emit2 ("dec %s", _getTempPairName());
3622 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3628 /* if the sizes are greater than 1 then we cannot */
3629 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3630 AOP_SIZE (IC_LEFT (ic)) > 1)
3633 /* we can if the aops of the left & result match or if they are in
3634 registers and the registers are the same */
3635 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3638 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3645 /*-----------------------------------------------------------------*/
3646 /* genMinus - generates code for subtraction */
3647 /*-----------------------------------------------------------------*/
3649 genMinus (iCode * ic)
3651 int size, offset = 0;
3652 unsigned long lit = 0L;
3654 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3655 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3656 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3658 /* special cases :- */
3659 /* if both left & right are in bit space */
3660 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3661 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3663 wassertl (0, "Tried to subtract two bits");
3667 /* if I can do an decrement instead of subtract then GOOD for ME */
3668 if (genMinusDec (ic) == TRUE)
3671 size = getDataSize (IC_RESULT (ic));
3673 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3678 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3682 /* Same logic as genPlus */
3685 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3686 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3687 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3689 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3690 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3691 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3692 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3694 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3695 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3697 if (left == PAIR_INVALID && right == PAIR_INVALID)
3702 else if (right == PAIR_INVALID)
3704 else if (left == PAIR_INVALID)
3707 fetchPair (left, AOP (IC_LEFT (ic)));
3708 /* Order is important. Right may be HL */
3709 fetchPair (right, AOP (IC_RIGHT (ic)));
3711 emit2 ("ld a,%s", _pairs[left].l);
3712 emit2 ("sub a,%s", _pairs[right].l);
3714 emit2 ("ld a,%s", _pairs[left].h);
3715 emit2 ("sbc a,%s", _pairs[right].h);
3717 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
3719 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3721 aopPut (AOP (IC_RESULT (ic)), "e", 0);
3727 /* Be paranoid on the GB with 4 byte variables due to how C
3728 can be trashed by lda hl,n(sp).
3730 _gbz80_emitAddSubLong (ic, FALSE);
3735 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3737 /* if literal, add a,#-lit, else normal subb */
3740 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3741 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3745 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3748 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3752 /* first add without previous c */
3754 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
3756 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3758 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3761 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3762 AOP_SIZE (IC_LEFT (ic)) == 3 &&
3763 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3765 wassertl (0, "Tried to subtract on a long pointer");
3769 freeAsmop (IC_LEFT (ic), NULL, ic);
3770 freeAsmop (IC_RIGHT (ic), NULL, ic);
3771 freeAsmop (IC_RESULT (ic), NULL, ic);
3774 /*-----------------------------------------------------------------*/
3775 /* genMult - generates code for multiplication */
3776 /*-----------------------------------------------------------------*/
3778 genMult (iCode * ic)
3782 /* If true then the final operation should be a subtract */
3783 bool active = FALSE;
3785 /* Shouldn't occur - all done through function calls */
3786 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3787 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3788 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3790 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
3791 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
3792 AOP_SIZE (IC_RESULT (ic)) > 2)
3794 wassertl (0, "Multiplication is handled through support function calls");
3797 /* Swap left and right such that right is a literal */
3798 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
3800 operand *t = IC_RIGHT (ic);
3801 IC_RIGHT (ic) = IC_LEFT (ic);
3805 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
3807 val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
3808 // wassertl (val > 0, "Multiply must be positive");
3809 wassertl (val != 1, "Can't multiply by 1");
3811 if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
3813 _G.stack.pushedDE = TRUE;
3816 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
3818 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
3826 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3831 /* Fully unroled version of mul.s. Not the most efficient.
3833 for (count = 0; count < 16; count++)
3835 if (count != 0 && active)
3837 emit2 ("add hl,hl");
3841 if (active == FALSE)
3848 emit2 ("add hl,de");
3857 if (IS_Z80 && _G.stack.pushedDE)
3860 _G.stack.pushedDE = FALSE;
3863 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3865 freeAsmop (IC_LEFT (ic), NULL, ic);
3866 freeAsmop (IC_RIGHT (ic), NULL, ic);
3867 freeAsmop (IC_RESULT (ic), NULL, ic);
3870 /*-----------------------------------------------------------------*/
3871 /* genDiv - generates code for division */
3872 /*-----------------------------------------------------------------*/
3876 /* Shouldn't occur - all done through function calls */
3877 wassertl (0, "Division is handled through support function calls");
3880 /*-----------------------------------------------------------------*/
3881 /* genMod - generates code for division */
3882 /*-----------------------------------------------------------------*/
3886 /* Shouldn't occur - all done through function calls */
3890 /*-----------------------------------------------------------------*/
3891 /* genIfxJump :- will create a jump depending on the ifx */
3892 /*-----------------------------------------------------------------*/
3894 genIfxJump (iCode * ic, char *jval)
3899 /* if true label then we jump if condition
3903 jlbl = IC_TRUE (ic);
3904 if (!strcmp (jval, "a"))
3908 else if (!strcmp (jval, "c"))
3912 else if (!strcmp (jval, "nc"))
3916 else if (!strcmp (jval, "m"))
3920 else if (!strcmp (jval, "p"))
3926 /* The buffer contains the bit on A that we should test */
3932 /* false label is present */
3933 jlbl = IC_FALSE (ic);
3934 if (!strcmp (jval, "a"))
3938 else if (!strcmp (jval, "c"))
3942 else if (!strcmp (jval, "nc"))
3946 else if (!strcmp (jval, "m"))
3950 else if (!strcmp (jval, "p"))
3956 /* The buffer contains the bit on A that we should test */
3960 /* Z80 can do a conditional long jump */
3961 if (!strcmp (jval, "a"))
3965 else if (!strcmp (jval, "c"))
3968 else if (!strcmp (jval, "nc"))
3971 else if (!strcmp (jval, "m"))
3974 else if (!strcmp (jval, "p"))
3979 emit2 ("bit %s,a", jval);
3981 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
3983 /* mark the icode as generated */
3989 _getPairIdName (PAIR_ID id)
3991 return _pairs[id].name;
3996 /* if unsigned char cmp with lit, just compare */
3998 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4000 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4003 emit2 ("xor a,!immedbyte", 0x80);
4004 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4007 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4009 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4011 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4012 // Pull left into DE and right into HL
4013 aopGet (AOP(left), LSB, FALSE);
4016 aopGet (AOP(right), LSB, FALSE);
4020 if (size == 0 && sign)
4022 // Highest byte when signed needs the bits flipped
4025 emit2 ("ld a,(de)");
4026 emit2 ("xor !immedbyte", 0x80);
4028 emit2 ("ld a,(hl)");
4029 emit2 ("xor !immedbyte", 0x80);
4033 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4037 emit2 ("ld a,(de)");
4038 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4048 spillPair (PAIR_HL);
4050 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4052 setupPair (PAIR_HL, AOP (left), 0);
4053 aopGet (AOP(right), LSB, FALSE);
4057 if (size == 0 && sign)
4059 // Highest byte when signed needs the bits flipped
4062 emit2 ("ld a,(hl)");
4063 emit2 ("xor !immedbyte", 0x80);
4065 emit2 ("ld a,%d(iy)", offset);
4066 emit2 ("xor !immedbyte", 0x80);
4070 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4074 emit2 ("ld a,(hl)");
4075 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4084 spillPair (PAIR_HL);
4085 spillPair (PAIR_IY);
4089 if (AOP_TYPE (right) == AOP_LIT)
4091 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4092 /* optimize if(x < 0) or if(x >= 0) */
4097 /* No sign so it's always false */
4102 /* Just load in the top most bit */
4103 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4104 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4106 genIfxJump (ifx, "7");
4118 /* First setup h and l contaning the top most bytes XORed */
4119 bool fDidXor = FALSE;
4120 if (AOP_TYPE (left) == AOP_LIT)
4122 unsigned long lit = (unsigned long)
4123 floatFromVal (AOP (left)->aopu.aop_lit);
4124 emit2 ("ld %s,!immedbyte", _fTmp[0],
4125 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4129 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4130 emit2 ("xor a,!immedbyte", 0x80);
4131 emit2 ("ld %s,a", _fTmp[0]);
4134 if (AOP_TYPE (right) == AOP_LIT)
4136 unsigned long lit = (unsigned long)
4137 floatFromVal (AOP (right)->aopu.aop_lit);
4138 emit2 ("ld %s,!immedbyte", _fTmp[1],
4139 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4143 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4144 emit2 ("xor a,!immedbyte", 0x80);
4145 emit2 ("ld %s,a", _fTmp[1]);
4151 /* Do a long subtract */
4154 _moveA (aopGet (AOP (left), offset, FALSE));
4156 if (sign && size == 0)
4158 emit2 ("ld a,%s", _fTmp[0]);
4159 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4163 /* Subtract through, propagating the carry */
4164 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4172 /** Generic compare for > or <
4175 genCmp (operand * left, operand * right,
4176 operand * result, iCode * ifx, int sign)
4178 int size, offset = 0;
4179 unsigned long lit = 0L;
4180 bool swap_sense = FALSE;
4182 /* if left & right are bit variables */
4183 if (AOP_TYPE (left) == AOP_CRY &&
4184 AOP_TYPE (right) == AOP_CRY)
4186 /* Cant happen on the Z80 */
4187 wassertl (0, "Tried to compare two bits");
4191 /* Do a long subtract of right from left. */
4192 size = max (AOP_SIZE (left), AOP_SIZE (right));
4194 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4196 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4197 // Pull left into DE and right into HL
4198 aopGet (AOP(left), LSB, FALSE);
4201 aopGet (AOP(right), LSB, FALSE);
4205 emit2 ("ld a,(de)");
4206 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4215 spillPair (PAIR_HL);
4219 if (AOP_TYPE (right) == AOP_LIT)
4221 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4222 /* optimize if(x < 0) or if(x >= 0) */
4227 /* No sign so it's always false */
4232 /* Just load in the top most bit */
4233 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4234 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4236 genIfxJump (ifx, "7");
4247 genIfxJump (ifx, swap_sense ? "c" : "nc");
4258 _moveA (aopGet (AOP (left), offset, FALSE));
4259 /* Subtract through, propagating the carry */
4260 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4266 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4270 /* Shift the sign bit up into carry */
4273 outBitCLong (result, swap_sense);
4277 /* if the result is used in the next
4278 ifx conditional branch then generate
4279 code a little differently */
4287 genIfxJump (ifx, swap_sense ? "nc" : "c");
4291 genIfxJump (ifx, swap_sense ? "p" : "m");
4296 genIfxJump (ifx, swap_sense ? "nc" : "c");
4303 /* Shift the sign bit up into carry */
4306 outBitCLong (result, swap_sense);
4308 /* leave the result in acc */
4312 /*-----------------------------------------------------------------*/
4313 /* genCmpGt :- greater than comparison */
4314 /*-----------------------------------------------------------------*/
4316 genCmpGt (iCode * ic, iCode * ifx)
4318 operand *left, *right, *result;
4319 sym_link *letype, *retype;
4322 left = IC_LEFT (ic);
4323 right = IC_RIGHT (ic);
4324 result = IC_RESULT (ic);
4326 letype = getSpec (operandType (left));
4327 retype = getSpec (operandType (right));
4328 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4329 /* assign the amsops */
4330 aopOp (left, ic, FALSE, FALSE);
4331 aopOp (right, ic, FALSE, FALSE);
4332 aopOp (result, ic, TRUE, FALSE);
4334 genCmp (right, left, result, ifx, sign);
4336 freeAsmop (left, NULL, ic);
4337 freeAsmop (right, NULL, ic);
4338 freeAsmop (result, NULL, ic);
4341 /*-----------------------------------------------------------------*/
4342 /* genCmpLt - less than comparisons */
4343 /*-----------------------------------------------------------------*/
4345 genCmpLt (iCode * ic, iCode * ifx)
4347 operand *left, *right, *result;
4348 sym_link *letype, *retype;
4351 left = IC_LEFT (ic);
4352 right = IC_RIGHT (ic);
4353 result = IC_RESULT (ic);
4355 letype = getSpec (operandType (left));
4356 retype = getSpec (operandType (right));
4357 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4359 /* assign the amsops */
4360 aopOp (left, ic, FALSE, FALSE);
4361 aopOp (right, ic, FALSE, FALSE);
4362 aopOp (result, ic, TRUE, FALSE);
4364 genCmp (left, right, result, ifx, sign);
4366 freeAsmop (left, NULL, ic);
4367 freeAsmop (right, NULL, ic);
4368 freeAsmop (result, NULL, ic);
4371 /*-----------------------------------------------------------------*/
4372 /* gencjneshort - compare and jump if not equal */
4373 /*-----------------------------------------------------------------*/
4375 gencjneshort (operand * left, operand * right, symbol * lbl)
4377 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4379 unsigned long lit = 0L;
4381 /* Swap the left and right if it makes the computation easier */
4382 if (AOP_TYPE (left) == AOP_LIT)
4389 if (AOP_TYPE (right) == AOP_LIT)
4391 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4394 /* if the right side is a literal then anything goes */
4395 if (AOP_TYPE (right) == AOP_LIT &&
4396 AOP_TYPE (left) != AOP_DIR)
4400 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4405 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4412 emit2 ("jp nz,!tlabel", lbl->key + 100);
4418 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4419 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
4422 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
4423 emit2 ("jp nz,!tlabel", lbl->key + 100);
4428 /* if the right side is in a register or in direct space or
4429 if the left is a pointer register & right is not */
4430 else if (AOP_TYPE (right) == AOP_REG ||
4431 AOP_TYPE (right) == AOP_DIR ||
4432 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
4436 _moveA (aopGet (AOP (left), offset, FALSE));
4437 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
4438 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4440 emit2 ("jp nz,!tlabel", lbl->key + 100);
4443 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4444 emit2 ("jp nz,!tlabel", lbl->key + 100);
4451 /* right is a pointer reg need both a & b */
4452 /* PENDING: is this required? */
4455 _moveA (aopGet (AOP (right), offset, FALSE));
4456 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
4457 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
4463 /*-----------------------------------------------------------------*/
4464 /* gencjne - compare and jump if not equal */
4465 /*-----------------------------------------------------------------*/
4467 gencjne (operand * left, operand * right, symbol * lbl)
4469 symbol *tlbl = newiTempLabel (NULL);
4471 gencjneshort (left, right, lbl);
4474 emit2 ("ld a,!one");
4475 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4476 emitLabel (lbl->key + 100);
4478 emitLabel (tlbl->key + 100);
4481 /*-----------------------------------------------------------------*/
4482 /* genCmpEq - generates code for equal to */
4483 /*-----------------------------------------------------------------*/
4485 genCmpEq (iCode * ic, iCode * ifx)
4487 operand *left, *right, *result;
4489 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4490 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4491 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4493 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4495 /* Swap operands if it makes the operation easier. ie if:
4496 1. Left is a literal.
4498 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4500 operand *t = IC_RIGHT (ic);
4501 IC_RIGHT (ic) = IC_LEFT (ic);
4505 if (ifx && !AOP_SIZE (result))
4508 /* if they are both bit variables */
4509 if (AOP_TYPE (left) == AOP_CRY &&
4510 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4512 wassertl (0, "Tried to compare two bits");
4516 tlbl = newiTempLabel (NULL);
4517 gencjneshort (left, right, tlbl);
4520 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4521 emitLabel (tlbl->key + 100);
4525 /* PENDING: do this better */
4526 symbol *lbl = newiTempLabel (NULL);
4527 emit2 ("!shortjp !tlabel", lbl->key + 100);
4528 emitLabel (tlbl->key + 100);
4529 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4530 emitLabel (lbl->key + 100);
4533 /* mark the icode as generated */
4538 /* if they are both bit variables */
4539 if (AOP_TYPE (left) == AOP_CRY &&
4540 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4542 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4548 gencjne (left, right, newiTempLabel (NULL));
4549 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4556 genIfxJump (ifx, "a");
4559 /* if the result is used in an arithmetic operation
4560 then put the result in place */
4561 if (AOP_TYPE (result) != AOP_CRY)
4566 /* leave the result in acc */
4570 freeAsmop (left, NULL, ic);
4571 freeAsmop (right, NULL, ic);
4572 freeAsmop (result, NULL, ic);
4575 /*-----------------------------------------------------------------*/
4576 /* ifxForOp - returns the icode containing the ifx for operand */
4577 /*-----------------------------------------------------------------*/
4579 ifxForOp (operand * op, iCode * ic)
4581 /* if true symbol then needs to be assigned */
4582 if (IS_TRUE_SYMOP (op))
4585 /* if this has register type condition and
4586 the next instruction is ifx with the same operand
4587 and live to of the operand is upto the ifx only then */
4589 ic->next->op == IFX &&
4590 IC_COND (ic->next)->key == op->key &&
4591 OP_SYMBOL (op)->liveTo <= ic->next->seq)
4597 /*-----------------------------------------------------------------*/
4598 /* genAndOp - for && operation */
4599 /*-----------------------------------------------------------------*/
4601 genAndOp (iCode * ic)
4603 operand *left, *right, *result;
4606 /* note here that && operations that are in an if statement are
4607 taken away by backPatchLabels only those used in arthmetic
4608 operations remain */
4609 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4610 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4611 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4613 /* if both are bit variables */
4614 if (AOP_TYPE (left) == AOP_CRY &&
4615 AOP_TYPE (right) == AOP_CRY)
4617 wassertl (0, "Tried to and two bits");
4621 tlbl = newiTempLabel (NULL);
4623 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
4625 emitLabel (tlbl->key + 100);
4629 freeAsmop (left, NULL, ic);
4630 freeAsmop (right, NULL, ic);
4631 freeAsmop (result, NULL, ic);
4634 /*-----------------------------------------------------------------*/
4635 /* genOrOp - for || operation */
4636 /*-----------------------------------------------------------------*/
4638 genOrOp (iCode * ic)
4640 operand *left, *right, *result;
4643 /* note here that || operations that are in an
4644 if statement are taken away by backPatchLabels
4645 only those used in arthmetic operations remain */
4646 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4647 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4648 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4650 /* if both are bit variables */
4651 if (AOP_TYPE (left) == AOP_CRY &&
4652 AOP_TYPE (right) == AOP_CRY)
4654 wassertl (0, "Tried to OR two bits");
4658 tlbl = newiTempLabel (NULL);
4660 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4662 emitLabel (tlbl->key + 100);
4666 freeAsmop (left, NULL, ic);
4667 freeAsmop (right, NULL, ic);
4668 freeAsmop (result, NULL, ic);
4671 /*-----------------------------------------------------------------*/
4672 /* isLiteralBit - test if lit == 2^n */
4673 /*-----------------------------------------------------------------*/
4675 isLiteralBit (unsigned long lit)
4677 unsigned long pw[32] =
4678 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
4679 0x100L, 0x200L, 0x400L, 0x800L,
4680 0x1000L, 0x2000L, 0x4000L, 0x8000L,
4681 0x10000L, 0x20000L, 0x40000L, 0x80000L,
4682 0x100000L, 0x200000L, 0x400000L, 0x800000L,
4683 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
4684 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
4687 for (idx = 0; idx < 32; idx++)
4693 /*-----------------------------------------------------------------*/
4694 /* jmpTrueOrFalse - */
4695 /*-----------------------------------------------------------------*/
4697 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
4699 // ugly but optimized by peephole
4702 symbol *nlbl = newiTempLabel (NULL);
4703 emit2 ("jp !tlabel", nlbl->key + 100);
4704 emitLabel (tlbl->key + 100);
4705 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
4706 emitLabel (nlbl->key + 100);
4710 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
4711 emitLabel (tlbl->key + 100);
4716 /*-----------------------------------------------------------------*/
4717 /* genAnd - code for and */
4718 /*-----------------------------------------------------------------*/
4720 genAnd (iCode * ic, iCode * ifx)
4722 operand *left, *right, *result;
4723 int size, offset = 0;
4724 unsigned long lit = 0L;
4727 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4728 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4729 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4731 /* if left is a literal & right is not then exchange them */
4732 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4733 AOP_NEEDSACC (left))
4735 operand *tmp = right;
4740 /* if result = right then exchange them */
4741 if (sameRegs (AOP (result), AOP (right)))
4743 operand *tmp = right;
4748 /* if right is bit then exchange them */
4749 if (AOP_TYPE (right) == AOP_CRY &&
4750 AOP_TYPE (left) != AOP_CRY)
4752 operand *tmp = right;
4756 if (AOP_TYPE (right) == AOP_LIT)
4757 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4759 size = AOP_SIZE (result);
4761 if (AOP_TYPE (left) == AOP_CRY)
4763 wassertl (0, "Tried to perform an AND with a bit as an operand");
4767 // if(val & 0xZZ) - size = 0, ifx != FALSE -
4768 // bit = val & 0xZZ - size = 1, ifx = FALSE -
4769 if ((AOP_TYPE (right) == AOP_LIT) &&
4770 (AOP_TYPE (result) == AOP_CRY) &&
4771 (AOP_TYPE (left) != AOP_CRY))
4773 symbol *tlbl = newiTempLabel (NULL);
4774 int sizel = AOP_SIZE (left);
4777 /* PENDING: Test case for this. */
4782 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
4784 _moveA (aopGet (AOP (left), offset, FALSE));
4785 if (bytelit != 0x0FFL)
4787 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4794 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4798 // bit = left & literal
4802 emit2 ("!tlabeldef", tlbl->key + 100);
4804 // if(left & literal)
4809 jmpTrueOrFalse (ifx, tlbl);
4817 /* if left is same as result */
4818 if (sameRegs (AOP (result), AOP (left)))
4820 for (; size--; offset++)
4822 if (AOP_TYPE (right) == AOP_LIT)
4824 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4829 aopPut (AOP (result), "!zero", offset);
4832 _moveA (aopGet (AOP (left), offset, FALSE));
4834 aopGet (AOP (right), offset, FALSE));
4835 aopPut (AOP (left), "a", offset);
4842 if (AOP_TYPE (left) == AOP_ACC)
4844 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
4848 _moveA (aopGet (AOP (left), offset, FALSE));
4850 aopGet (AOP (right), offset, FALSE));
4851 aopPut (AOP (left), "a", offset);
4858 // left & result in different registers
4859 if (AOP_TYPE (result) == AOP_CRY)
4861 wassertl (0, "Tried to AND where the result is in carry");
4865 for (; (size--); offset++)
4868 // result = left & right
4869 if (AOP_TYPE (right) == AOP_LIT)
4871 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4873 aopPut (AOP (result),
4874 aopGet (AOP (left), offset, FALSE),
4878 else if (bytelit == 0)
4880 aopPut (AOP (result), "!zero", offset);
4884 // faster than result <- left, anl result,right
4885 // and better if result is SFR
4886 if (AOP_TYPE (left) == AOP_ACC)
4887 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4890 _moveA (aopGet (AOP (left), offset, FALSE));
4892 aopGet (AOP (right), offset, FALSE));
4894 aopPut (AOP (result), "a", offset);
4901 freeAsmop (left, NULL, ic);
4902 freeAsmop (right, NULL, ic);
4903 freeAsmop (result, NULL, ic);
4906 /*-----------------------------------------------------------------*/
4907 /* genOr - code for or */
4908 /*-----------------------------------------------------------------*/
4910 genOr (iCode * ic, iCode * ifx)
4912 operand *left, *right, *result;
4913 int size, offset = 0;
4914 unsigned long lit = 0L;
4917 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4918 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4919 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4921 /* if left is a literal & right is not then exchange them */
4922 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4923 AOP_NEEDSACC (left))
4925 operand *tmp = right;
4930 /* if result = right then exchange them */
4931 if (sameRegs (AOP (result), AOP (right)))
4933 operand *tmp = right;
4938 /* if right is bit then exchange them */
4939 if (AOP_TYPE (right) == AOP_CRY &&
4940 AOP_TYPE (left) != AOP_CRY)
4942 operand *tmp = right;
4946 if (AOP_TYPE (right) == AOP_LIT)
4947 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4949 size = AOP_SIZE (result);
4951 if (AOP_TYPE (left) == AOP_CRY)
4953 wassertl (0, "Tried to OR where left is a bit");
4957 // if(val | 0xZZ) - size = 0, ifx != FALSE -
4958 // bit = val | 0xZZ - size = 1, ifx = FALSE -
4959 if ((AOP_TYPE (right) == AOP_LIT) &&
4960 (AOP_TYPE (result) == AOP_CRY) &&
4961 (AOP_TYPE (left) != AOP_CRY))
4963 symbol *tlbl = newiTempLabel (NULL);
4964 int sizel = AOP_SIZE (left);
4968 wassertl (0, "Result is assigned to a bit");
4970 /* PENDING: Modeled after the AND code which is inefficent. */
4973 bytelit = (lit >> (offset * 8)) & 0x0FFL;
4975 _moveA (aopGet (AOP (left), offset, FALSE));
4976 /* OR with any literal is the same as OR with itself. */
4978 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4984 jmpTrueOrFalse (ifx, tlbl);
4989 /* if left is same as result */
4990 if (sameRegs (AOP (result), AOP (left)))
4992 for (; size--; offset++)
4994 if (AOP_TYPE (right) == AOP_LIT)
4996 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5000 _moveA (aopGet (AOP (left), offset, FALSE));
5002 aopGet (AOP (right), offset, FALSE));
5003 aopPut (AOP (result), "a", offset);
5008 if (AOP_TYPE (left) == AOP_ACC)
5009 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5012 _moveA (aopGet (AOP (left), offset, FALSE));
5014 aopGet (AOP (right), offset, FALSE));
5015 aopPut (AOP (result), "a", offset);
5022 // left & result in different registers
5023 if (AOP_TYPE (result) == AOP_CRY)
5025 wassertl (0, "Result of OR is in a bit");
5028 for (; (size--); offset++)
5031 // result = left & right
5032 if (AOP_TYPE (right) == AOP_LIT)
5034 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5036 aopPut (AOP (result),
5037 aopGet (AOP (left), offset, FALSE),
5042 // faster than result <- left, anl result,right
5043 // and better if result is SFR
5044 if (AOP_TYPE (left) == AOP_ACC)
5045 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5048 _moveA (aopGet (AOP (left), offset, FALSE));
5050 aopGet (AOP (right), offset, FALSE));
5052 aopPut (AOP (result), "a", offset);
5053 /* PENDING: something weird is going on here. Add exception. */
5054 if (AOP_TYPE (result) == AOP_ACC)
5060 freeAsmop (left, NULL, ic);
5061 freeAsmop (right, NULL, ic);
5062 freeAsmop (result, NULL, ic);
5065 /*-----------------------------------------------------------------*/
5066 /* genXor - code for xclusive or */
5067 /*-----------------------------------------------------------------*/
5069 genXor (iCode * ic, iCode * ifx)
5071 operand *left, *right, *result;
5072 int size, offset = 0;
5073 unsigned long lit = 0L;
5075 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5076 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5077 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5079 /* if left is a literal & right is not then exchange them */
5080 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5081 AOP_NEEDSACC (left))
5083 operand *tmp = right;
5088 /* if result = right then exchange them */
5089 if (sameRegs (AOP (result), AOP (right)))
5091 operand *tmp = right;
5096 /* if right is bit then exchange them */
5097 if (AOP_TYPE (right) == AOP_CRY &&
5098 AOP_TYPE (left) != AOP_CRY)
5100 operand *tmp = right;
5104 if (AOP_TYPE (right) == AOP_LIT)
5105 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5107 size = AOP_SIZE (result);
5109 if (AOP_TYPE (left) == AOP_CRY)
5111 wassertl (0, "Tried to XOR a bit");
5115 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5116 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5117 if ((AOP_TYPE (right) == AOP_LIT) &&
5118 (AOP_TYPE (result) == AOP_CRY) &&
5119 (AOP_TYPE (left) != AOP_CRY))
5121 symbol *tlbl = newiTempLabel (NULL);
5122 int sizel = AOP_SIZE (left);
5126 /* PENDING: Test case for this. */
5127 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5131 _moveA (aopGet (AOP (left), offset, FALSE));
5132 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5133 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5138 jmpTrueOrFalse (ifx, tlbl);
5142 wassertl (0, "Result of XOR was destined for a bit");
5147 /* if left is same as result */
5148 if (sameRegs (AOP (result), AOP (left)))
5150 for (; size--; offset++)
5152 if (AOP_TYPE (right) == AOP_LIT)
5154 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5158 _moveA (aopGet (AOP (right), offset, FALSE));
5160 aopGet (AOP (left), offset, FALSE));
5161 aopPut (AOP (result), "a", offset);
5166 if (AOP_TYPE (left) == AOP_ACC)
5168 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5172 _moveA (aopGet (AOP (right), offset, FALSE));
5174 aopGet (AOP (left), offset, FALSE));
5175 aopPut (AOP (result), "a", 0);
5182 // left & result in different registers
5183 if (AOP_TYPE (result) == AOP_CRY)
5185 wassertl (0, "Result of XOR is in a bit");
5188 for (; (size--); offset++)
5191 // result = left & right
5192 if (AOP_TYPE (right) == AOP_LIT)
5194 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5196 aopPut (AOP (result),
5197 aopGet (AOP (left), offset, FALSE),
5202 // faster than result <- left, anl result,right
5203 // and better if result is SFR
5204 if (AOP_TYPE (left) == AOP_ACC)
5206 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5210 _moveA (aopGet (AOP (right), offset, FALSE));
5212 aopGet (AOP (left), offset, FALSE));
5214 aopPut (AOP (result), "a", offset);
5219 freeAsmop (left, NULL, ic);
5220 freeAsmop (right, NULL, ic);
5221 freeAsmop (result, NULL, ic);
5224 /*-----------------------------------------------------------------*/
5225 /* genInline - write the inline code out */
5226 /*-----------------------------------------------------------------*/
5228 genInline (iCode * ic)
5230 char *buffer, *bp, *bp1;
5232 _G.lines.isInline += (!options.asmpeep);
5234 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5235 strcpy (buffer, IC_INLINE (ic));
5237 /* emit each line as a code */
5262 _G.lines.isInline -= (!options.asmpeep);
5266 /*-----------------------------------------------------------------*/
5267 /* genRRC - rotate right with carry */
5268 /*-----------------------------------------------------------------*/
5275 /*-----------------------------------------------------------------*/
5276 /* genRLC - generate code for rotate left with carry */
5277 /*-----------------------------------------------------------------*/
5284 /*-----------------------------------------------------------------*/
5285 /* genGetHbit - generates code get highest order bit */
5286 /*-----------------------------------------------------------------*/
5288 genGetHbit (iCode * ic)
5290 operand *left, *result;
5291 left = IC_LEFT (ic);
5292 result = IC_RESULT (ic);
5294 aopOp (left, ic, FALSE, FALSE);
5295 aopOp (result, ic, FALSE, FALSE);
5297 /* get the highest order byte into a */
5298 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5300 if (AOP_TYPE (result) == AOP_CRY)
5308 emit2 ("and a,!one");
5313 freeAsmop (left, NULL, ic);
5314 freeAsmop (result, NULL, ic);
5318 emitRsh2 (asmop *aop, int size, int is_signed)
5324 const char *l = aopGet (aop, size, FALSE);
5327 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5337 /*-----------------------------------------------------------------*/
5338 /* shiftR2Left2Result - shift right two bytes from left to result */
5339 /*-----------------------------------------------------------------*/
5341 shiftR2Left2Result (operand * left, int offl,
5342 operand * result, int offr,
5343 int shCount, int is_signed)
5346 symbol *tlbl, *tlbl1;
5348 movLeft2Result (left, offl, result, offr, 0);
5349 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5351 /* if (AOP(result)->type == AOP_REG) { */
5353 tlbl = newiTempLabel (NULL);
5354 tlbl1 = newiTempLabel (NULL);
5356 /* Left is already in result - so now do the shift */
5361 emitRsh2 (AOP (result), size, is_signed);
5366 emit2 ("ld a,!immedbyte+1", shCount);
5367 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5368 emitLabel (tlbl->key + 100);
5370 emitRsh2 (AOP (result), size, is_signed);
5372 emitLabel (tlbl1->key + 100);
5374 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5378 /*-----------------------------------------------------------------*/
5379 /* shiftL2Left2Result - shift left two bytes from left to result */
5380 /*-----------------------------------------------------------------*/
5382 shiftL2Left2Result (operand * left, int offl,
5383 operand * result, int offr, int shCount)
5385 if (sameRegs (AOP (result), AOP (left)) &&
5386 ((offl + MSB16) == offr))
5392 /* Copy left into result */
5393 movLeft2Result (left, offl, result, offr, 0);
5394 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5397 if (getPairId (AOP (result)) == PAIR_HL)
5401 emit2 ("add hl,hl");
5408 symbol *tlbl, *tlbl1;
5411 tlbl = newiTempLabel (NULL);
5412 tlbl1 = newiTempLabel (NULL);
5414 if (AOP (result)->type == AOP_REG)
5418 for (offset = 0; offset < size; offset++)
5420 l = aopGet (AOP (result), offset, FALSE);
5424 emit2 ("sla %s", l);
5435 /* Left is already in result - so now do the shift */
5438 emit2 ("ld a,!immedbyte+1", shCount);
5439 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5440 emitLabel (tlbl->key + 100);
5445 l = aopGet (AOP (result), offset, FALSE);
5449 emit2 ("sla %s", l);
5460 emitLabel (tlbl1->key + 100);
5462 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5468 /*-----------------------------------------------------------------*/
5469 /* AccRol - rotate left accumulator by known count */
5470 /*-----------------------------------------------------------------*/
5472 AccRol (int shCount)
5474 shCount &= 0x0007; // shCount : 0..7
5513 /*-----------------------------------------------------------------*/
5514 /* AccLsh - left shift accumulator by known count */
5515 /*-----------------------------------------------------------------*/
5517 AccLsh (int shCount)
5519 static const unsigned char SLMask[] =
5521 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5530 else if (shCount == 2)
5537 /* rotate left accumulator */
5539 /* and kill the lower order bits */
5540 emit2 ("and a,!immedbyte", SLMask[shCount]);
5545 /*-----------------------------------------------------------------*/
5546 /* shiftL1Left2Result - shift left one byte from left to result */
5547 /*-----------------------------------------------------------------*/
5549 shiftL1Left2Result (operand * left, int offl,
5550 operand * result, int offr, int shCount)
5553 l = aopGet (AOP (left), offl, FALSE);
5555 /* shift left accumulator */
5557 aopPut (AOP (result), "a", offr);
5561 /*-----------------------------------------------------------------*/
5562 /* genlshTwo - left shift two bytes by known amount != 0 */
5563 /*-----------------------------------------------------------------*/
5565 genlshTwo (operand * result, operand * left, int shCount)
5567 int size = AOP_SIZE (result);
5569 wassert (size == 2);
5571 /* if shCount >= 8 */
5579 movLeft2Result (left, LSB, result, MSB16, 0);
5580 aopPut (AOP (result), "!zero", 0);
5581 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
5585 movLeft2Result (left, LSB, result, MSB16, 0);
5586 aopPut (AOP (result), "!zero", 0);
5591 aopPut (AOP (result), "!zero", LSB);
5594 /* 1 <= shCount <= 7 */
5603 shiftL2Left2Result (left, LSB, result, LSB, shCount);
5608 /*-----------------------------------------------------------------*/
5609 /* genlshOne - left shift a one byte quantity by known count */
5610 /*-----------------------------------------------------------------*/
5612 genlshOne (operand * result, operand * left, int shCount)
5614 shiftL1Left2Result (left, LSB, result, LSB, shCount);
5617 /*-----------------------------------------------------------------*/
5618 /* genLeftShiftLiteral - left shifting by known count */
5619 /*-----------------------------------------------------------------*/
5621 genLeftShiftLiteral (operand * left,
5626 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5629 freeAsmop (right, NULL, ic);
5631 aopOp (left, ic, FALSE, FALSE);
5632 aopOp (result, ic, FALSE, FALSE);
5634 size = getSize (operandType (result));
5636 /* I suppose that the left size >= result size */
5642 else if (shCount >= (size * 8))
5646 aopPut (AOP (result), "!zero", size);
5654 genlshOne (result, left, shCount);
5657 genlshTwo (result, left, shCount);
5660 wassertl (0, "Shifting of longs is currently unsupported");
5666 freeAsmop (left, NULL, ic);
5667 freeAsmop (result, NULL, ic);
5670 /*-----------------------------------------------------------------*/
5671 /* genLeftShift - generates code for left shifting */
5672 /*-----------------------------------------------------------------*/
5674 genLeftShift (iCode * ic)
5678 symbol *tlbl, *tlbl1;
5679 operand *left, *right, *result;
5681 right = IC_RIGHT (ic);
5682 left = IC_LEFT (ic);
5683 result = IC_RESULT (ic);
5685 aopOp (right, ic, FALSE, FALSE);
5687 /* if the shift count is known then do it
5688 as efficiently as possible */
5689 if (AOP_TYPE (right) == AOP_LIT)
5691 genLeftShiftLiteral (left, right, result, ic);
5695 /* shift count is unknown then we have to form a loop get the loop
5696 count in B : Note: we take only the lower order byte since
5697 shifting more that 32 bits make no sense anyway, ( the largest
5698 size of an object can be only 32 bits ) */
5699 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5701 freeAsmop (right, NULL, ic);
5702 aopOp (left, ic, FALSE, FALSE);
5703 aopOp (result, ic, FALSE, FALSE);
5705 /* now move the left to the result if they are not the
5708 if (!sameRegs (AOP (left), AOP (result)))
5711 size = AOP_SIZE (result);
5715 l = aopGet (AOP (left), offset, FALSE);
5716 aopPut (AOP (result), l, offset);
5721 tlbl = newiTempLabel (NULL);
5722 size = AOP_SIZE (result);
5724 tlbl1 = newiTempLabel (NULL);
5726 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5727 emitLabel (tlbl->key + 100);
5728 l = aopGet (AOP (result), offset, FALSE);
5732 l = aopGet (AOP (result), offset, FALSE);
5736 emit2 ("sla %s", l);
5744 emitLabel (tlbl1->key + 100);
5746 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5748 freeAsmop (left, NULL, ic);
5749 freeAsmop (result, NULL, ic);
5752 /*-----------------------------------------------------------------*/
5753 /* genrshOne - left shift two bytes by known amount != 0 */
5754 /*-----------------------------------------------------------------*/
5756 genrshOne (operand * result, operand * left, int shCount, int is_signed)
5759 int size = AOP_SIZE (result);
5762 wassert (size == 1);
5763 wassert (shCount < 8);
5765 l = aopGet (AOP (left), 0, FALSE);
5767 if (AOP (result)->type == AOP_REG)
5769 aopPut (AOP (result), l, 0);
5770 l = aopGet (AOP (result), 0, FALSE);
5773 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5781 emit2 ("%s a", is_signed ? "sra" : "srl");
5783 aopPut (AOP (result), "a", 0);
5787 /*-----------------------------------------------------------------*/
5788 /* AccRsh - right shift accumulator by known count */
5789 /*-----------------------------------------------------------------*/
5791 AccRsh (int shCount)
5793 static const unsigned char SRMask[] =
5795 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
5800 /* rotate right accumulator */
5801 AccRol (8 - shCount);
5802 /* and kill the higher order bits */
5803 emit2 ("and a,!immedbyte", SRMask[shCount]);
5807 /*-----------------------------------------------------------------*/
5808 /* shiftR1Left2Result - shift right one byte from left to result */
5809 /*-----------------------------------------------------------------*/
5811 shiftR1Left2Result (operand * left, int offl,
5812 operand * result, int offr,
5813 int shCount, int sign)
5815 _moveA (aopGet (AOP (left), offl, FALSE));
5820 emit2 ("%s a", sign ? "sra" : "srl");
5827 aopPut (AOP (result), "a", offr);
5830 /*-----------------------------------------------------------------*/
5831 /* genrshTwo - right shift two bytes by known amount != 0 */
5832 /*-----------------------------------------------------------------*/
5834 genrshTwo (operand * result, operand * left,
5835 int shCount, int sign)
5837 /* if shCount >= 8 */
5843 shiftR1Left2Result (left, MSB16, result, LSB,
5848 movLeft2Result (left, MSB16, result, LSB, sign);
5852 /* Sign extend the result */
5853 _moveA(aopGet (AOP (result), 0, FALSE));
5857 aopPut (AOP (result), ACC_NAME, MSB16);
5861 aopPut (AOP (result), "!zero", 1);
5864 /* 1 <= shCount <= 7 */
5867 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
5871 /*-----------------------------------------------------------------*/
5872 /* genRightShiftLiteral - left shifting by known count */
5873 /*-----------------------------------------------------------------*/
5875 genRightShiftLiteral (operand * left,
5881 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5884 freeAsmop (right, NULL, ic);
5886 aopOp (left, ic, FALSE, FALSE);
5887 aopOp (result, ic, FALSE, FALSE);
5889 size = getSize (operandType (result));
5891 /* I suppose that the left size >= result size */
5897 else if (shCount >= (size * 8)) {
5899 if (!SPEC_USIGN(getSpec(operandType(left)))) {
5900 _moveA(aopGet (AOP (left), 0, FALSE));
5908 aopPut (AOP (result), s, size);
5915 genrshOne (result, left, shCount, sign);
5918 genrshTwo (result, left, shCount, sign);
5921 wassertl (0, "Asked to shift right a long which should be a function call");
5924 wassertl (0, "Entered default case in right shift delegate");
5927 freeAsmop (left, NULL, ic);
5928 freeAsmop (result, NULL, ic);
5931 /*-----------------------------------------------------------------*/
5932 /* genRightShift - generate code for right shifting */
5933 /*-----------------------------------------------------------------*/
5935 genRightShift (iCode * ic)
5937 operand *right, *left, *result;
5939 int size, offset, first = 1;
5943 symbol *tlbl, *tlbl1;
5945 /* if signed then we do it the hard way preserve the
5946 sign bit moving it inwards */
5947 retype = getSpec (operandType (IC_RESULT (ic)));
5949 is_signed = !SPEC_USIGN (retype);
5951 /* signed & unsigned types are treated the same : i.e. the
5952 signed is NOT propagated inwards : quoting from the
5953 ANSI - standard : "for E1 >> E2, is equivalent to division
5954 by 2**E2 if unsigned or if it has a non-negative value,
5955 otherwise the result is implementation defined ", MY definition
5956 is that the sign does not get propagated */
5958 right = IC_RIGHT (ic);
5959 left = IC_LEFT (ic);
5960 result = IC_RESULT (ic);
5962 aopOp (right, ic, FALSE, FALSE);
5964 /* if the shift count is known then do it
5965 as efficiently as possible */
5966 if (AOP_TYPE (right) == AOP_LIT)
5968 genRightShiftLiteral (left, right, result, ic, is_signed);
5972 aopOp (left, ic, FALSE, FALSE);
5973 aopOp (result, ic, FALSE, FALSE);
5975 /* now move the left to the result if they are not the
5977 if (!sameRegs (AOP (left), AOP (result)) &&
5978 AOP_SIZE (result) > 1)
5981 size = AOP_SIZE (result);
5985 l = aopGet (AOP (left), offset, FALSE);
5986 aopPut (AOP (result), l, offset);
5991 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5993 freeAsmop (right, NULL, ic);
5995 tlbl = newiTempLabel (NULL);
5996 tlbl1 = newiTempLabel (NULL);
5997 size = AOP_SIZE (result);
6000 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6001 emitLabel (tlbl->key + 100);
6004 l = aopGet (AOP (result), offset--, FALSE);
6007 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6015 emitLabel (tlbl1->key + 100);
6017 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6019 freeAsmop (left, NULL, ic);
6020 freeAsmop (result, NULL, ic);
6023 /*-----------------------------------------------------------------*/
6024 /* genGenPointerGet - get value from generic pointer space */
6025 /*-----------------------------------------------------------------*/
6027 genGenPointerGet (operand * left,
6028 operand * result, iCode * ic)
6031 sym_link *retype = getSpec (operandType (result));
6037 aopOp (left, ic, FALSE, FALSE);
6038 aopOp (result, ic, FALSE, FALSE);
6040 size = AOP_SIZE (result);
6042 if (isPair (AOP (left)) && size == 1)
6045 if (isPtrPair (AOP (left)))
6047 tsprintf (buffer, sizeof(buffer),
6048 "!*pair", getPairName (AOP (left)));
6049 aopPut (AOP (result), buffer, 0);
6053 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6054 aopPut (AOP (result), "a", 0);
6056 freeAsmop (left, NULL, ic);
6060 if (getPairId (AOP (left)) == PAIR_IY)
6067 tsprintf (at, sizeof(at), "!*iyx", offset);
6068 aopPut (AOP (result), at, offset);
6072 freeAsmop (left, NULL, ic);
6076 /* For now we always load into IY */
6077 /* if this is remateriazable */
6078 fetchPair (pair, AOP (left));
6080 /* if bit then unpack */
6081 if (IS_BITVAR (retype))
6085 else if (getPairId (AOP (result)) == PAIR_HL)
6087 wassertl (size == 2, "HL must be of size 2");
6088 emit2 ("ld a,!*hl");
6090 emit2 ("ld h,!*hl");
6092 spillPair (PAIR_HL);
6094 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6096 size = AOP_SIZE (result);
6101 /* PENDING: make this better */
6102 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6104 aopPut (AOP (result), "!*hl", offset++);
6108 emit2 ("ld a,!*pair", _pairs[pair].name);
6109 aopPut (AOP (result), "a", offset++);
6113 emit2 ("inc %s", _pairs[pair].name);
6114 _G.pairs[pair].offset++;
6117 /* Fixup HL back down */
6118 for (size = AOP_SIZE (result)-1; size; size--)
6120 emit2 ("dec %s", _pairs[pair].name);
6125 size = AOP_SIZE (result);
6130 /* PENDING: make this better */
6132 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6134 aopPut (AOP (result), "!*hl", offset++);
6138 emit2 ("ld a,!*pair", _pairs[pair].name);
6139 aopPut (AOP (result), "a", offset++);
6143 emit2 ("inc %s", _pairs[pair].name);
6144 _G.pairs[pair].offset++;
6149 freeAsmop (left, NULL, ic);
6152 freeAsmop (result, NULL, ic);
6155 /*-----------------------------------------------------------------*/
6156 /* genPointerGet - generate code for pointer get */
6157 /*-----------------------------------------------------------------*/
6159 genPointerGet (iCode * ic)
6161 operand *left, *result;
6162 sym_link *type, *etype;
6164 left = IC_LEFT (ic);
6165 result = IC_RESULT (ic);
6167 /* depending on the type of pointer we need to
6168 move it to the correct pointer register */
6169 type = operandType (left);
6170 etype = getSpec (type);
6172 genGenPointerGet (left, result, ic);
6176 isRegOrLit (asmop * aop)
6178 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6183 /*-----------------------------------------------------------------*/
6184 /* genGenPointerSet - stores the value into a pointer location */
6185 /*-----------------------------------------------------------------*/
6187 genGenPointerSet (operand * right,
6188 operand * result, iCode * ic)
6191 sym_link *retype = getSpec (operandType (right));
6192 PAIR_ID pairId = PAIR_HL;
6194 aopOp (result, ic, FALSE, FALSE);
6195 aopOp (right, ic, FALSE, FALSE);
6200 size = AOP_SIZE (right);
6202 /* Handle the exceptions first */
6203 if (isPair (AOP (result)) && size == 1)
6206 const char *l = aopGet (AOP (right), 0, FALSE);
6207 const char *pair = getPairName (AOP (result));
6208 if (canAssignToPtr (l) && isPtr (pair))
6210 emit2 ("ld !*pair,%s", pair, l);
6215 emit2 ("ld !*pair,a", pair);
6220 if ( getPairId( AOP (result)) == PAIR_IY)
6223 const char *l = aopGet (AOP (right), 0, FALSE);
6228 if (canAssignToPtr (l))
6230 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6234 _moveA (aopGet (AOP (right), offset, FALSE));
6235 emit2 ("ld !*iyx,a", offset);
6241 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result))
6247 const char *l = aopGet (AOP (right), offset, FALSE);
6248 if (isRegOrLit (AOP (right)) && !IS_GB)
6250 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
6255 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
6259 emit2 ("inc %s", _pairs[PAIR_HL].name);
6260 _G.pairs[PAIR_HL].offset++;
6265 /* Fixup HL back down */
6266 for (size = AOP_SIZE (right)-1; size; size--)
6268 emit2 ("dec %s", _pairs[PAIR_HL].name);
6273 /* if the operand is already in dptr
6274 then we do nothing else we move the value to dptr */
6275 if (AOP_TYPE (result) != AOP_STR)
6277 fetchPair (pairId, AOP (result));
6279 /* so hl know contains the address */
6280 freeAsmop (result, NULL, ic);
6282 /* if bit then unpack */
6283 if (IS_BITVAR (retype))
6293 const char *l = aopGet (AOP (right), offset, FALSE);
6294 if (isRegOrLit (AOP (right)) && !IS_GB)
6296 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
6301 emit2 ("ld !*pair,a", _pairs[pairId].name);
6305 emit2 ("inc %s", _pairs[pairId].name);
6306 _G.pairs[pairId].offset++;
6312 freeAsmop (right, NULL, ic);
6315 /*-----------------------------------------------------------------*/
6316 /* genPointerSet - stores the value into a pointer location */
6317 /*-----------------------------------------------------------------*/
6319 genPointerSet (iCode * ic)
6321 operand *right, *result;
6322 sym_link *type, *etype;
6324 right = IC_RIGHT (ic);
6325 result = IC_RESULT (ic);
6327 /* depending on the type of pointer we need to
6328 move it to the correct pointer register */
6329 type = operandType (result);
6330 etype = getSpec (type);
6332 genGenPointerSet (right, result, ic);
6335 /*-----------------------------------------------------------------*/
6336 /* genIfx - generate code for Ifx statement */
6337 /*-----------------------------------------------------------------*/
6339 genIfx (iCode * ic, iCode * popIc)
6341 operand *cond = IC_COND (ic);
6344 aopOp (cond, ic, FALSE, TRUE);
6346 /* get the value into acc */
6347 if (AOP_TYPE (cond) != AOP_CRY)
6351 /* the result is now in the accumulator */
6352 freeAsmop (cond, NULL, ic);
6354 /* if there was something to be popped then do it */
6358 /* if the condition is a bit variable */
6359 if (isbit && IS_ITEMP (cond) &&
6361 genIfxJump (ic, SPIL_LOC (cond)->rname);
6362 else if (isbit && !IS_ITEMP (cond))
6363 genIfxJump (ic, OP_SYMBOL (cond)->rname);
6365 genIfxJump (ic, "a");
6370 /*-----------------------------------------------------------------*/
6371 /* genAddrOf - generates code for address of */
6372 /*-----------------------------------------------------------------*/
6374 genAddrOf (iCode * ic)
6376 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
6378 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6380 /* if the operand is on the stack then we
6381 need to get the stack offset of this
6388 if (sym->stack <= 0)
6390 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
6394 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6396 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6400 emit2 ("ld de,!hashedstr", sym->rname);
6401 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
6409 /* if it has an offset then we need to compute it */
6411 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6413 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
6414 emit2 ("add hl,sp");
6418 emit2 ("ld hl,!hashedstr", sym->rname);
6420 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6422 freeAsmop (IC_RESULT (ic), NULL, ic);
6425 /*-----------------------------------------------------------------*/
6426 /* genAssign - generate code for assignment */
6427 /*-----------------------------------------------------------------*/
6429 genAssign (iCode * ic)
6431 operand *result, *right;
6433 unsigned long lit = 0L;
6435 result = IC_RESULT (ic);
6436 right = IC_RIGHT (ic);
6438 /* Dont bother assigning if they are the same */
6439 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6441 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
6445 aopOp (right, ic, FALSE, FALSE);
6446 aopOp (result, ic, TRUE, FALSE);
6448 /* if they are the same registers */
6449 if (sameRegs (AOP (right), AOP (result)))
6451 emitDebug ("; (registers are the same)");
6455 /* if the result is a bit */
6456 if (AOP_TYPE (result) == AOP_CRY)
6458 wassertl (0, "Tried to assign to a bit");
6462 size = AOP_SIZE (result);
6465 if (AOP_TYPE (right) == AOP_LIT)
6467 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6470 if (isPair (AOP (result)))
6472 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
6474 else if ((size > 1) &&
6475 (AOP_TYPE (result) != AOP_REG) &&
6476 (AOP_TYPE (right) == AOP_LIT) &&
6477 !IS_FLOAT (operandType (right)) &&
6480 bool fXored = FALSE;
6482 /* Work from the top down.
6483 Done this way so that we can use the cached copy of 0
6484 in A for a fast clear */
6487 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
6489 if (!fXored && size > 1)
6496 aopPut (AOP (result), "a", offset);
6500 aopPut (AOP (result), "!zero", offset);
6504 aopPut (AOP (result),
6505 aopGet (AOP (right), offset, FALSE),
6510 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
6512 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
6513 aopPut (AOP (result), "l", LSB);
6514 aopPut (AOP (result), "h", MSB16);
6516 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6518 /* Special case. Load into a and d, then load out. */
6519 _moveA (aopGet (AOP (right), 0, FALSE));
6520 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
6521 aopPut (AOP (result), "a", 0);
6522 aopPut (AOP (result), "e", 1);
6524 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6526 /* Special case - simple memcpy */
6527 aopGet (AOP (right), LSB, FALSE);
6530 aopGet (AOP (result), LSB, FALSE);
6534 emit2 ("ld a,(de)");
6535 /* Peephole will optimise this. */
6536 emit2 ("ld (hl),a");
6544 spillPair (PAIR_HL);
6550 /* PENDING: do this check better */
6551 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
6553 _moveA (aopGet (AOP (right), offset, FALSE));
6554 aopPut (AOP (result), "a", offset);
6557 aopPut (AOP (result),
6558 aopGet (AOP (right), offset, FALSE),
6565 freeAsmop (right, NULL, ic);
6566 freeAsmop (result, NULL, ic);
6569 /*-----------------------------------------------------------------*/
6570 /* genJumpTab - genrates code for jump table */
6571 /*-----------------------------------------------------------------*/
6573 genJumpTab (iCode * ic)
6578 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
6579 /* get the condition into accumulator */
6580 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
6583 emit2 ("ld e,%s", l);
6584 emit2 ("ld d,!zero");
6585 jtab = newiTempLabel (NULL);
6587 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
6588 emit2 ("add hl,de");
6589 emit2 ("add hl,de");
6590 emit2 ("add hl,de");
6591 freeAsmop (IC_JTCOND (ic), NULL, ic);
6595 emitLabel (jtab->key + 100);
6596 /* now generate the jump labels */
6597 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
6598 jtab = setNextItem (IC_JTLABELS (ic)))
6599 emit2 ("jp !tlabel", jtab->key + 100);
6602 /*-----------------------------------------------------------------*/
6603 /* genCast - gen code for casting */
6604 /*-----------------------------------------------------------------*/
6606 genCast (iCode * ic)
6608 operand *result = IC_RESULT (ic);
6609 sym_link *rtype = operandType (IC_RIGHT (ic));
6610 operand *right = IC_RIGHT (ic);
6613 /* if they are equivalent then do nothing */
6614 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6617 aopOp (right, ic, FALSE, FALSE);
6618 aopOp (result, ic, FALSE, FALSE);
6620 /* if the result is a bit */
6621 if (AOP_TYPE (result) == AOP_CRY)
6623 wassertl (0, "Tried to cast to a bit");
6626 /* if they are the same size : or less */
6627 if (AOP_SIZE (result) <= AOP_SIZE (right))
6630 /* if they are in the same place */
6631 if (sameRegs (AOP (right), AOP (result)))
6634 /* if they in different places then copy */
6635 size = AOP_SIZE (result);
6639 aopPut (AOP (result),
6640 aopGet (AOP (right), offset, FALSE),
6647 /* So we now know that the size of destination is greater
6648 than the size of the source */
6649 /* we move to result for the size of source */
6650 size = AOP_SIZE (right);
6654 aopPut (AOP (result),
6655 aopGet (AOP (right), offset, FALSE),
6660 /* now depending on the sign of the destination */
6661 size = AOP_SIZE (result) - AOP_SIZE (right);
6662 /* Unsigned or not an integral type - right fill with zeros */
6663 if (SPEC_USIGN (rtype) || !IS_SPEC (rtype) || AOP_TYPE(right)==AOP_CRY)
6666 aopPut (AOP (result), "!zero", offset++);
6670 /* we need to extend the sign :{ */
6671 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
6677 aopPut (AOP (result), "a", offset++);
6681 freeAsmop (right, NULL, ic);
6682 freeAsmop (result, NULL, ic);
6685 /*-----------------------------------------------------------------*/
6686 /* genReceive - generate code for a receive iCode */
6687 /*-----------------------------------------------------------------*/
6689 genReceive (iCode * ic)
6691 if (isOperandInFarSpace (IC_RESULT (ic)) &&
6692 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
6693 IS_TRUE_SYMOP (IC_RESULT (ic))))
6703 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6704 size = AOP_SIZE(IC_RESULT(ic));
6706 for (i = 0; i < size; i++) {
6707 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
6711 freeAsmop (IC_RESULT (ic), NULL, ic);
6716 /** Maximum number of bytes to emit per line. */
6720 /** Context for the byte output chunker. */
6723 unsigned char buffer[DBEMIT_MAX_RUN];
6728 /** Flushes a byte chunker by writing out all in the buffer and
6732 _dbFlush(DBEMITCTX *self)
6739 sprintf(line, ".db 0x%02X", self->buffer[0]);
6741 for (i = 1; i < self->pos; i++)
6743 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
6750 /** Write out another byte, buffering until a decent line is
6754 _dbEmit(DBEMITCTX *self, int c)
6756 if (self->pos == DBEMIT_MAX_RUN)
6760 self->buffer[self->pos++] = c;
6763 /** Context for a simple run length encoder. */
6767 unsigned char buffer[128];
6769 /** runLen may be equivalent to pos. */
6775 RLE_CHANGE_COST = 4,
6779 /** Flush the buffer of a run length encoder by writing out the run or
6780 data that it currently contains.
6783 _rleCommit(RLECTX *self)
6789 memset(&db, 0, sizeof(db));
6791 emit2(".db %u", self->pos);
6793 for (i = 0; i < self->pos; i++)
6795 _dbEmit(&db, self->buffer[i]);
6804 Can get either a run or a block of random stuff.
6805 Only want to change state if a good run comes in or a run ends.
6806 Detecting run end is easy.
6809 Say initial state is in run, len zero, last zero. Then if you get a
6810 few zeros then something else then a short run will be output.
6811 Seems OK. While in run mode, keep counting. While in random mode,
6812 keep a count of the run. If run hits margin, output all up to run,
6813 restart, enter run mode.
6816 /** Add another byte into the run length encoder, flushing as
6817 required. The run length encoder uses the Amiga IFF style, where
6818 a block is prefixed by its run length. A positive length means
6819 the next n bytes pass straight through. A negative length means
6820 that the next byte is repeated -n times. A zero terminates the
6824 _rleAppend(RLECTX *self, int c)
6828 if (c != self->last)
6830 /* The run has stopped. See if it is worthwhile writing it out
6831 as a run. Note that the random data comes in as runs of
6834 if (self->runLen > RLE_CHANGE_COST)
6836 /* Yes, worthwhile. */
6837 /* Commit whatever was in the buffer. */
6839 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
6843 /* Not worthwhile. Append to the end of the random list. */
6844 for (i = 0; i < self->runLen; i++)
6846 if (self->pos >= RLE_MAX_BLOCK)
6851 self->buffer[self->pos++] = self->last;
6859 if (self->runLen >= RLE_MAX_BLOCK)
6861 /* Commit whatever was in the buffer. */
6864 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
6872 _rleFlush(RLECTX *self)
6874 _rleAppend(self, -1);
6881 /** genArrayInit - Special code for initialising an array with constant
6885 genArrayInit (iCode * ic)
6889 int elementSize = 0, eIndex, i;
6890 unsigned val, lastVal;
6894 memset(&rle, 0, sizeof(rle));
6896 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
6898 _saveRegsForCall(ic, 0);
6900 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
6901 emit2 ("call __initrleblock");
6903 type = operandType(IC_LEFT(ic));
6905 if (type && type->next)
6907 elementSize = getSize(type->next);
6911 wassertl (0, "Can't determine element size in genArrayInit.");
6914 iLoop = IC_ARRAYILIST(ic);
6915 lastVal = (unsigned)-1;
6917 /* Feed all the bytes into the run length encoder which will handle
6919 This works well for mixed char data, and for random int and long
6928 for (i = 0; i < ix; i++)
6930 for (eIndex = 0; eIndex < elementSize; eIndex++)
6932 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
6933 _rleAppend(&rle, val);
6938 iLoop = iLoop->next;
6942 /* Mark the end of the run. */
6945 _restoreRegsAfterCall();
6949 freeAsmop (IC_LEFT(ic), NULL, ic);
6953 _swap (PAIR_ID one, PAIR_ID two)
6955 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
6961 emit2 ("ld a,%s", _pairs[one].l);
6962 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
6963 emit2 ("ld %s,a", _pairs[two].l);
6964 emit2 ("ld a,%s", _pairs[one].h);
6965 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
6966 emit2 ("ld %s,a", _pairs[two].h);
6970 /* The problem is that we may have all three pairs used and they may
6971 be needed in a different order.
6976 hl = hl => unity, fine
6980 hl = hl hl = hl, swap de <=> bc
6988 hl = bc de = de, swap bc <=> hl
6996 hl = de bc = bc, swap hl <=> de
7001 * Any pair = pair are done last
7002 * Any pair = iTemp are done last
7003 * Any swaps can be done any time
7011 So how do we detect the cases?
7012 How about a 3x3 matrix?
7016 x x x x (Fourth for iTemp/other)
7018 First determin which mode to use by counting the number of unity and
7021 Two - Assign the pair first, then the rest
7022 One - Swap the two, then the rest
7026 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7028 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7030 PAIR_BC, PAIR_HL, PAIR_DE
7032 int i, j, nunity = 0;
7033 memset (ids, PAIR_INVALID, sizeof (ids));
7036 wassert (nparams == 3);
7038 /* First save everything that needs to be saved. */
7039 _saveRegsForCall (ic, 0);
7041 /* Loading HL first means that DE is always fine. */
7042 for (i = 0; i < nparams; i++)
7044 aopOp (pparams[i], ic, FALSE, FALSE);
7045 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7048 /* Count the number of unity or iTemp assigns. */
7049 for (i = 0; i < 3; i++)
7051 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7059 /* Any order, fall through. */
7061 else if (nunity == 2)
7063 /* One is assigned. Pull it out and assign. */
7064 for (i = 0; i < 3; i++)
7066 for (j = 0; j < NUM_PAIRS; j++)
7068 if (ids[dest[i]][j] == TRUE)
7070 /* Found it. See if it's the right one. */
7071 if (j == PAIR_INVALID || j == dest[i])
7077 fetchPair(dest[i], AOP (pparams[i]));
7084 else if (nunity == 1)
7086 /* Find the pairs to swap. */
7087 for (i = 0; i < 3; i++)
7089 for (j = 0; j < NUM_PAIRS; j++)
7091 if (ids[dest[i]][j] == TRUE)
7093 if (j == PAIR_INVALID || j == dest[i])
7108 int next = getPairId (AOP (pparams[0]));
7109 emit2 ("push %s", _pairs[next].name);
7111 if (next == dest[1])
7113 fetchPair (dest[1], AOP (pparams[1]));
7114 fetchPair (dest[2], AOP (pparams[2]));
7118 fetchPair (dest[2], AOP (pparams[2]));
7119 fetchPair (dest[1], AOP (pparams[1]));
7121 emit2 ("pop %s", _pairs[dest[0]].name);
7124 /* Finally pull out all of the iTemps */
7125 for (i = 0; i < 3; i++)
7127 if (ids[dest[i]][PAIR_INVALID] == 1)
7129 fetchPair (dest[i], AOP (pparams[i]));
7135 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
7141 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
7145 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7147 setupForBuiltin3 (ic, nParams, pparams);
7149 label = newiTempLabel(NULL);
7151 emitLabel (label->key);
7152 emit2 ("ld a,(hl)");
7155 emit2 ("!shortjp nz,!tlabel ; 1", label->key);
7157 freeAsmop (from, NULL, ic->next);
7158 freeAsmop (to, NULL, ic);
7162 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
7164 operand *from, *to, *count;
7167 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
7172 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7174 setupForBuiltin3 (ic, nParams, pparams);
7178 freeAsmop (count, NULL, ic->next->next);
7179 freeAsmop (from, NULL, ic);
7181 _restoreRegsAfterCall();
7183 /* if we need assign a result value */
7184 if ((IS_ITEMP (IC_RESULT (ic)) &&
7185 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
7186 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
7187 IS_TRUE_SYMOP (IC_RESULT (ic)))
7189 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7190 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
7191 freeAsmop (IC_RESULT (ic), NULL, ic);
7194 freeAsmop (to, NULL, ic->next);
7197 /*-----------------------------------------------------------------*/
7198 /* genBuiltIn - calls the appropriate function to generating code */
7199 /* for a built in function */
7200 /*-----------------------------------------------------------------*/
7201 static void genBuiltIn (iCode *ic)
7203 operand *bi_parms[MAX_BUILTIN_ARGS];
7208 /* get all the arguments for a built in function */
7209 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
7211 /* which function is it */
7212 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
7214 if (strcmp(bif->name,"__builtin_strcpy")==0)
7216 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
7218 else if (strcmp(bif->name,"__builtin_memcpy")==0)
7220 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
7224 wassertl (0, "Unknown builtin function encountered");
7228 /*-----------------------------------------------------------------*/
7229 /* genZ80Code - generate code for Z80 based controllers */
7230 /*-----------------------------------------------------------------*/
7232 genZ80Code (iCode * lic)
7240 _fReturn = _gbz80_return;
7241 _fTmp = _gbz80_return;
7245 _fReturn = _z80_return;
7246 _fTmp = _z80_return;
7249 _G.lines.head = _G.lines.current = NULL;
7251 for (ic = lic; ic; ic = ic->next)
7254 if (cln != ic->lineno)
7256 if (!options.noCcodeInAsm) {
7257 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
7258 printCLine(ic->filename, ic->lineno));
7262 if (options.iCodeInAsm) {
7263 emit2 (";ic:%d: %s", ic->key, printILine(ic));
7265 /* if the result is marked as
7266 spilt and rematerializable or code for
7267 this has already been generated then
7269 if (resultRemat (ic) || ic->generated)
7272 /* depending on the operation */
7276 emitDebug ("; genNot");
7281 emitDebug ("; genCpl");
7286 emitDebug ("; genUminus");
7291 emitDebug ("; genIpush");
7296 /* IPOP happens only when trying to restore a
7297 spilt live range, if there is an ifx statement
7298 following this pop then the if statement might
7299 be using some of the registers being popped which
7300 would destory the contents of the register so
7301 we need to check for this condition and handle it */
7303 ic->next->op == IFX &&
7304 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
7306 emitDebug ("; genIfx");
7307 genIfx (ic->next, ic);
7311 emitDebug ("; genIpop");
7317 emitDebug ("; genCall");
7322 emitDebug ("; genPcall");
7327 emitDebug ("; genFunction");
7332 emitDebug ("; genEndFunction");
7333 genEndFunction (ic);
7337 emitDebug ("; genRet");
7342 emitDebug ("; genLabel");
7347 emitDebug ("; genGoto");
7352 emitDebug ("; genPlus");
7357 emitDebug ("; genMinus");
7362 emitDebug ("; genMult");
7367 emitDebug ("; genDiv");
7372 emitDebug ("; genMod");
7377 emitDebug ("; genCmpGt");
7378 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
7382 emitDebug ("; genCmpLt");
7383 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
7390 /* note these two are xlated by algebraic equivalence
7391 during parsing SDCC.y */
7392 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
7393 "got '>=' or '<=' shouldn't have come here");
7397 emitDebug ("; genCmpEq");
7398 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
7402 emitDebug ("; genAndOp");
7407 emitDebug ("; genOrOp");
7412 emitDebug ("; genXor");
7413 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
7417 emitDebug ("; genOr");
7418 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
7422 emitDebug ("; genAnd");
7423 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
7427 emitDebug ("; genInline");
7432 emitDebug ("; genRRC");
7437 emitDebug ("; genRLC");
7442 emitDebug ("; genGetHBIT");
7447 emitDebug ("; genLeftShift");
7452 emitDebug ("; genRightShift");
7456 case GET_VALUE_AT_ADDRESS:
7457 emitDebug ("; genPointerGet");
7463 if (POINTER_SET (ic))
7465 emitDebug ("; genAssign (pointer)");
7470 emitDebug ("; genAssign");
7476 emitDebug ("; genIfx");
7481 emitDebug ("; genAddrOf");
7486 emitDebug ("; genJumpTab");
7491 emitDebug ("; genCast");
7496 emitDebug ("; genReceive");
7501 if (ic->builtinSEND)
7503 emitDebug ("; genBuiltIn");
7508 emitDebug ("; addSet");
7509 addSet (&_G.sendSet, ic);
7514 emitDebug ("; genArrayInit");
7524 /* now we are ready to call the
7525 peep hole optimizer */
7526 if (!options.nopeep)
7527 peepHole (&_G.lines.head);
7529 /* This is unfortunate */
7530 /* now do the actual printing */
7532 FILE *fp = codeOutFile;
7533 if (isInHome () && codeOutFile == code->oFile)
7534 codeOutFile = home->oFile;
7535 printLine (_G.lines.head, codeOutFile);
7536 if (_G.flushStatics)
7539 _G.flushStatics = 0;
7544 freeTrace(&_G.lines.trace);
7545 freeTrace(&_G.trace.aops);
7551 _isPairUsed (iCode * ic, PAIR_ID pairId)
7557 if (bitVectBitValue (ic->rMask, D_IDX))
7559 if (bitVectBitValue (ic->rMask, E_IDX))
7569 fetchLitSpecial (asmop * aop, bool negate, bool xor)
7572 value *val = aop->aopu.aop_lit;
7574 wassert (aop->type == AOP_LIT);
7575 wassert (!IS_FLOAT (val->type));
7577 v = (unsigned long) floatFromVal (val);
7585 tsprintf (buffer, sizeof(buffer), "!immedword", v);
7586 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));