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 Apparent advantage of turning on regparams:
66 Decent case is push of a constant
67 - ld hl,#n; push hl: (10+11)*nargs
68 2. Cost of pull from stack
69 Using asm with ld hl, etc
70 - ld hl,#2; add hl,sp; (ld bc,(hl); hl+=2)*nargs
72 3. Cost of fixing stack
76 So cost is (10+11+7+6+7+10)*nargs+10+11
78 = 123 for mul, div, strcmp, strcpy
79 Saving of (98298+32766+32766+32766)*123 = 24181308
80 At 192 d/s for 682411768t, speed up to 199. Hmm.
88 #ifdef HAVE_SYS_ISA_DEFS_H
89 #include <sys/isa_defs.h>
93 #include "SDCCglobl.h"
94 #include "SDCCpeeph.h"
99 /* This is the down and dirty file with all kinds of kludgy & hacky
100 stuff. This is what it is all about CODE GENERATION for a specific MCU.
101 Some of the routines may be reusable, will have to see */
103 /* Z80 calling convention description.
104 Parameters are passed right to left. As the stack grows downwards,
105 the parameters are arranged in left to right in memory.
106 Parameters may be passed in the HL and DE registers with one
108 PENDING: What if the parameter is a long?
109 Everything is caller saves. i.e. the caller must save any registers
110 that it wants to preserve over the call.
111 GB: The return value is returned in DEHL. DE is normally used as a
112 working register pair. Caller saves allows it to be used for a
114 va args functions do not use register parameters. All arguments
115 are passed on the stack.
116 IX is used as an index register to the top of the local variable
117 area. ix-0 is the top most local variable.
122 /* Set to enable debugging trace statements in the output assembly code. */
126 static char *_z80_return[] =
127 {"l", "h", "e", "d"};
128 static char *_gbz80_return[] =
129 {"e", "d", "l", "h"};
130 static char *_fReceive[] =
131 { "c", "b", "e", "d" };
133 static char **_fReturn;
136 extern FILE *codeOutFile;
144 /** Enum covering all the possible register pairs.
163 } _pairs[NUM_PAIRS] = {
164 { "??1", "?2", "?3" },
169 { "iy", "iyl", "iyh" },
170 { "ix", "ixl", "ixh" }
174 #define ACC_NAME _pairs[PAIR_AF].h
184 /** Code generator persistent data.
188 /** Used to optimised setting up of a pair by remebering what it
189 contains and adjusting instead of reloading where possible.
210 const char *lastFunctionName;
216 /** TRUE if the registers have already been saved. */
234 static const char *aopGet (asmop * aop, int offset, bool bit16);
250 _getTempPairName(void)
252 return _pairs[_getTempPairId()].name;
256 getFreePairId (iCode *ic)
258 if (!(bitVectBitValue (ic->rMask, B_IDX) || bitVectBitValue(ic->rMask, C_IDX)))
262 else if (IS_Z80 && !(bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX)))
275 /* Clean up the line so that it is 'prettier' */
276 if (strchr (buf, ':'))
278 /* Is a label - cant do anything */
281 /* Change the first (and probably only) ' ' to a tab so
296 _newLineNode (char *line)
300 pl = traceAlloc(&_G.lines.trace, Safe_alloc ( sizeof (lineNode)));
301 pl->line = traceAlloc(&_G.lines.trace, Safe_strdup (line));
307 _vemit2 (const char *szFormat, va_list ap)
311 tvsprintf (buffer, szFormat, ap);
314 _G.lines.current = (_G.lines.current ?
315 connectLine (_G.lines.current, _newLineNode (buffer)) :
316 (_G.lines.head = _newLineNode (buffer)));
318 _G.lines.current->isInline = _G.lines.isInline;
322 emit2 (const char *szFormat,...)
326 va_start (ap, szFormat);
328 _vemit2 (szFormat, ap);
334 emitDebug (const char *szFormat,...)
340 va_start (ap, szFormat);
342 _vemit2 (szFormat, ap);
348 /*-----------------------------------------------------------------*/
349 /* emit2 - writes the code into a file : for now it is simple */
350 /*-----------------------------------------------------------------*/
352 _emit2 (const char *inst, const char *fmt,...)
355 char lb[INITIAL_INLINEASM];
362 sprintf (lb, "%s\t", inst);
363 vsprintf (lb + (strlen (lb)), fmt, ap);
366 vsprintf (lb, fmt, ap);
368 while (isspace (*lbp))
373 _G.lines.current = (_G.lines.current ?
374 connectLine (_G.lines.current, _newLineNode (lb)) :
375 (_G.lines.head = _newLineNode (lb)));
377 _G.lines.current->isInline = _G.lines.isInline;
382 _emitMove(const char *to, const char *from)
384 if (strcasecmp(to, from) != 0)
386 emit2("ld %s,%s", to, from);
391 // Could leave this to the peephole, but sometimes the peephole is inhibited.
396 _moveA(const char *moveFrom)
398 // Let the peephole optimiser take care of redundent loads
399 _emitMove(ACC_NAME, moveFrom);
409 getPairName (asmop * aop)
411 if (aop->type == AOP_REG)
413 switch (aop->aopu.aop_reg[0]->rIdx)
426 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
429 for (i = 0; i < NUM_PAIRS; i++)
431 if (strcmp(aop->aopu.aop_str[0], _pairs[i].l) == 0)
433 return _pairs[i].name;
437 wassertl (0, "Tried to get the pair name of something that isn't a pair");
442 getPairId (asmop * aop)
446 if (aop->type == AOP_REG)
448 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX) && (aop->aopu.aop_reg[1]->rIdx == B_IDX))
452 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX) && (aop->aopu.aop_reg[1]->rIdx == D_IDX))
456 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX) && (aop->aopu.aop_reg[1]->rIdx == H_IDX))
461 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
464 for (i = 0; i < NUM_PAIRS; i++)
466 if (!strcmp (aop->aopu.aop_str[0], _pairs[i].l) && !strcmp (aop->aopu.aop_str[1], _pairs[i].h))
476 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
480 return (getPairId (aop) != PAIR_INVALID);
484 isPtrPair (asmop * aop)
486 PAIR_ID pairId = getPairId (aop);
499 spillPair (PAIR_ID pairId)
501 _G.pairs[pairId].last_type = AOP_INVALID;
502 _G.pairs[pairId].base = NULL;
505 /** Push a register pair onto the stack */
507 genPairPush (asmop * aop)
509 emit2 ("push %s", getPairName (aop));
513 _push (PAIR_ID pairId)
515 emit2 ("push %s", _pairs[pairId].name);
516 _G.stack.pushed += 2;
520 _pop (PAIR_ID pairId)
522 emit2 ("pop %s", _pairs[pairId].name);
523 _G.stack.pushed -= 2;
527 /*-----------------------------------------------------------------*/
528 /* newAsmop - creates a new asmOp */
529 /*-----------------------------------------------------------------*/
531 newAsmop (short type)
535 aop = traceAlloc(&_G.trace.aops, Safe_alloc (sizeof (asmop)));
540 /*-----------------------------------------------------------------*/
541 /* aopForSym - for a true symbol */
542 /*-----------------------------------------------------------------*/
544 aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
551 wassert (sym->etype);
553 space = SPEC_OCLS (sym->etype);
555 /* if already has one */
559 /* Assign depending on the storage class */
560 if (sym->onStack || sym->iaccess)
562 /* The pointer that is used depends on how big the offset is.
563 Normally everything is AOP_STK, but for offsets of < -128 or
564 > 127 on the Z80 an extended stack pointer is used.
566 if (IS_Z80 && (options.ommitFramePtr || sym->stack < INT8MIN || sym->stack > (int)(INT8MAX-getSize (sym->type))))
568 emitDebug ("; AOP_EXSTK for %s", sym->rname);
569 sym->aop = aop = newAsmop (AOP_EXSTK);
573 emitDebug ("; AOP_STK for %s", sym->rname);
574 sym->aop = aop = newAsmop (AOP_STK);
577 aop->size = getSize (sym->type);
578 aop->aopu.aop_stk = sym->stack;
582 /* special case for a function */
583 if (IS_FUNC (sym->type))
585 sym->aop = aop = newAsmop (AOP_IMMD);
586 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup (sym->rname));
593 /* if it is in direct space */
594 if (IN_REGSP (space) && !requires_a)
596 sym->aop = aop = newAsmop (AOP_SFR);
597 aop->aopu.aop_dir = sym->rname;
598 aop->size = getSize (sym->type);
599 emitDebug ("; AOP_SFR for %s", sym->rname);
604 /* only remaining is far space */
605 /* in which case DPTR gets the address */
608 emitDebug ("; AOP_HL for %s", sym->rname);
609 sym->aop = aop = newAsmop (AOP_HL);
613 sym->aop = aop = newAsmop (AOP_IY);
615 aop->size = getSize (sym->type);
616 aop->aopu.aop_dir = sym->rname;
618 /* if it is in code space */
619 if (IN_CODESPACE (space))
625 /*-----------------------------------------------------------------*/
626 /* aopForRemat - rematerialzes an object */
627 /*-----------------------------------------------------------------*/
629 aopForRemat (symbol * sym)
632 iCode *ic = sym->rematiCode;
633 asmop *aop = newAsmop (AOP_IMMD);
637 /* if plus or minus print the right hand side */
638 if (ic->op == '+' || ic->op == '-')
640 /* PENDING: for re-target */
641 sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
644 ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
647 /* we reached the end */
648 sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
652 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
656 /*-----------------------------------------------------------------*/
657 /* regsInCommon - two operands have some registers in common */
658 /*-----------------------------------------------------------------*/
660 regsInCommon (operand * op1, operand * op2)
665 /* if they have registers in common */
666 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
669 sym1 = OP_SYMBOL (op1);
670 sym2 = OP_SYMBOL (op2);
672 if (sym1->nRegs == 0 || sym2->nRegs == 0)
675 for (i = 0; i < sym1->nRegs; i++)
681 for (j = 0; j < sym2->nRegs; j++)
686 if (sym2->regs[j] == sym1->regs[i])
694 /*-----------------------------------------------------------------*/
695 /* operandsEqu - equivalent */
696 /*-----------------------------------------------------------------*/
698 operandsEqu (operand * op1, operand * op2)
702 /* if they not symbols */
703 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
706 sym1 = OP_SYMBOL (op1);
707 sym2 = OP_SYMBOL (op2);
709 /* if both are itemps & one is spilt
710 and the other is not then false */
711 if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
712 sym1->isspilt != sym2->isspilt)
715 /* if they are the same */
719 if (strcmp (sym1->rname, sym2->rname) == 0)
723 /* if left is a tmp & right is not */
724 if (IS_ITEMP (op1) &&
727 (sym1->usl.spillLoc == sym2))
730 if (IS_ITEMP (op2) &&
734 (sym2->usl.spillLoc == sym1))
740 /*-----------------------------------------------------------------*/
741 /* sameRegs - two asmops have the same registers */
742 /*-----------------------------------------------------------------*/
744 sameRegs (asmop * aop1, asmop * aop2)
748 if (aop1->type == AOP_SFR ||
749 aop2->type == AOP_SFR)
755 if (aop1->type != AOP_REG ||
756 aop2->type != AOP_REG)
759 if (aop1->size != aop2->size)
762 for (i = 0; i < aop1->size; i++)
763 if (aop1->aopu.aop_reg[i] !=
764 aop2->aopu.aop_reg[i])
770 /*-----------------------------------------------------------------*/
771 /* aopOp - allocates an asmop for an operand : */
772 /*-----------------------------------------------------------------*/
774 aopOp (operand * op, iCode * ic, bool result, bool requires_a)
783 /* if this a literal */
784 if (IS_OP_LITERAL (op))
786 op->aop = aop = newAsmop (AOP_LIT);
787 aop->aopu.aop_lit = op->operand.valOperand;
788 aop->size = getSize (operandType (op));
792 /* if already has a asmop then continue */
796 /* if the underlying symbol has a aop */
797 if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
799 op->aop = OP_SYMBOL (op)->aop;
803 /* if this is a true symbol */
804 if (IS_TRUE_SYMOP (op))
806 op->aop = aopForSym (ic, OP_SYMBOL (op), result, requires_a);
810 /* this is a temporary : this has
816 e) can be a return use only */
818 sym = OP_SYMBOL (op);
820 /* if the type is a conditional */
821 if (sym->regType == REG_CND)
823 aop = op->aop = sym->aop = newAsmop (AOP_CRY);
828 /* if it is spilt then two situations
830 b) has a spill location */
831 if (sym->isspilt || sym->nRegs == 0)
833 /* rematerialize it NOW */
836 sym->aop = op->aop = aop =
838 aop->size = getSize (sym->type);
845 aop = op->aop = sym->aop = newAsmop (AOP_STR);
846 aop->size = getSize (sym->type);
847 for (i = 0; i < 4; i++)
848 aop->aopu.aop_str[i] = _fReturn[i];
854 if (sym->accuse == ACCUSE_A)
856 aop = op->aop = sym->aop = newAsmop (AOP_ACC);
857 aop->size = getSize (sym->type);
858 wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
860 aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
862 else if (sym->accuse == ACCUSE_SCRATCH)
864 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
865 aop->size = getSize (sym->type);
866 wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
867 aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
868 aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
870 else if (sym->accuse == ACCUSE_IY)
872 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
873 aop->size = getSize (sym->type);
874 wassertl(aop->size <= 2, "Internal error: Caching in IY, but too big to fit in IY");
875 aop->aopu.aop_str[0] = _pairs[PAIR_IY].l;
876 aop->aopu.aop_str[1] = _pairs[PAIR_IY].h;
880 wassertl (0, "Marked as being allocated into A or HL but is actually in neither");
885 /* else spill location */
886 sym->aop = op->aop = aop =
887 aopForSym (ic, sym->usl.spillLoc, result, requires_a);
888 aop->size = getSize (sym->type);
892 /* must be in a register */
893 sym->aop = op->aop = aop = newAsmop (AOP_REG);
894 aop->size = sym->nRegs;
895 for (i = 0; i < sym->nRegs; i++)
896 aop->aopu.aop_reg[i] = sym->regs[i];
899 /*-----------------------------------------------------------------*/
900 /* freeAsmop - free up the asmop given to an operand */
901 /*----------------------------------------------------------------*/
903 freeAsmop (operand * op, asmop * aaop, iCode * ic)
920 if (aop->type == AOP_PAIRPTR && IS_Z80 && aop->aopu.aop_pairId == PAIR_DE)
922 _pop (aop->aopu.aop_pairId);
926 /* all other cases just dealloc */
932 OP_SYMBOL (op)->aop = NULL;
933 /* if the symbol has a spill */
935 SPIL_LOC (op)->aop = NULL;
942 isLitWord (asmop * aop)
944 /* if (aop->size != 2)
957 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
961 /* depending on type */
967 /* PENDING: for re-target */
970 tsprintf (s, "!hashedstr + %d", aop->aopu.aop_immd, offset);
972 else if (offset == 0)
974 tsprintf (s, "%s", aop->aopu.aop_immd);
978 tsprintf (s, "%s + %d", aop->aopu.aop_immd, offset);
980 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
984 value *val = aop->aopu.aop_lit;
985 /* if it is a float then it gets tricky */
986 /* otherwise it is fairly simple */
987 if (!IS_FLOAT (val->type))
989 unsigned long v = (unsigned long) floatFromVal (val);
995 else if (offset == 0)
1001 wassertl(0, "Encountered an invalid offset while fetching a literal");
1005 tsprintf (buffer, "!immedword", v);
1007 tsprintf (buffer, "!constword", v);
1009 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1020 /* it is type float */
1021 fl.f = (float) floatFromVal (val);
1024 i = fl.c[3-offset] | (fl.c[3-offset-1]<<8);
1026 i = fl.c[offset] | (fl.c[offset+1]<<8);
1029 tsprintf (buffer, "!immedword", i);
1031 tsprintf (buffer, "!constword", i);
1033 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1042 aopGetWord (asmop * aop, int offset)
1044 return aopGetLitWordLong (aop, offset, TRUE);
1048 isPtr (const char *s)
1050 if (!strcmp (s, "hl"))
1052 if (!strcmp (s, "ix"))
1054 if (!strcmp (s, "iy"))
1060 adjustPair (const char *pair, int *pold, int new)
1066 emit2 ("inc %s", pair);
1071 emit2 ("dec %s", pair);
1079 spillPair (PAIR_HL);
1080 spillPair (PAIR_IY);
1084 requiresHL (asmop * aop)
1100 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1102 const char *l, *base;
1103 const char *pair = _pairs[pairId].name;
1104 l = aopGetLitWordLong (left, offset, FALSE);
1105 base = aopGetLitWordLong (left, 0, FALSE);
1106 wassert (l && pair && base);
1110 if (pairId == PAIR_HL || pairId == PAIR_IY)
1112 if (_G.pairs[pairId].last_type == left->type)
1114 if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1116 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1118 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1121 if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
1128 _G.pairs[pairId].last_type = left->type;
1129 _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1130 _G.pairs[pairId].offset = offset;
1132 /* Both a lit on the right and a true symbol on the left */
1133 emit2 ("ld %s,!hashedstr", pair, l);
1137 fetchPairLong (PAIR_ID pairId, asmop * aop, int offset)
1139 /* if this is remateriazable */
1140 if (isLitWord (aop)) {
1141 fetchLitPair (pairId, aop, offset);
1145 if (getPairId (aop) == pairId)
1149 /* we need to get it byte by byte */
1150 else if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1151 aopGet (aop, offset, FALSE);
1152 switch (aop->size - offset) {
1154 emit2 ("ld l,!*hl");
1155 emit2 ("ld h,!immedbyte", 0);
1158 // PENDING: Requires that you are only fetching two bytes.
1161 emit2 ("ld h,!*hl");
1165 wassertl (0, "Attempted to fetch too much data into HL");
1169 else if (IS_Z80 && aop->type == AOP_IY) {
1170 /* Instead of fetching relative to IY, just grab directly
1171 from the address IY refers to */
1172 char *l = aopGetLitWordLong (aop, offset, FALSE);
1174 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1176 if (aop->size < 2) {
1177 emit2("ld %s,!zero", _pairs[pairId].h);
1180 else if (pairId == PAIR_IY)
1184 emit2 ("push %s", _pairs[getPairId(aop)].name);
1190 /* Can't load into parts, so load into HL then exchange. */
1191 emit2 ("ld %s,%s", _pairs[PAIR_HL].l, aopGet (aop, offset, FALSE));
1192 emit2 ("ld %s,%s", _pairs[PAIR_HL].h, aopGet (aop, offset + 1, FALSE));
1199 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1200 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1202 /* PENDING: check? */
1203 if (pairId == PAIR_HL)
1204 spillPair (PAIR_HL);
1209 fetchPair (PAIR_ID pairId, asmop * aop)
1211 fetchPairLong (pairId, aop, 0);
1215 fetchHL (asmop * aop)
1217 fetchPair (PAIR_HL, aop);
1221 setupPairFromSP (PAIR_ID id, int offset)
1223 wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
1225 if (offset < INT8MIN || offset > INT8MAX)
1227 emit2 ("ld hl,!immedword", offset);
1228 emit2 ("add hl,sp");
1232 emit2 ("!ldahlsp", offset);
1237 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1242 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
1243 fetchLitPair (pairId, aop, 0);
1247 wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
1249 fetchLitPair (pairId, aop, offset);
1250 _G.pairs[pairId].offset = offset;
1254 wassertl (IS_Z80, "Only the Z80 has an extended stack");
1255 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
1258 int offset = aop->aopu.aop_stk + _G.stack.offset;
1260 if (_G.pairs[pairId].last_type == aop->type &&
1261 _G.pairs[pairId].offset == offset)
1267 /* PENDING: Do this better. */
1268 sprintf (buffer, "%d", offset + _G.stack.pushed);
1269 emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
1270 emit2 ("add %s,sp", _pairs[pairId].name);
1271 _G.pairs[pairId].last_type = aop->type;
1272 _G.pairs[pairId].offset = offset;
1279 /* Doesnt include _G.stack.pushed */
1280 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1281 if (aop->aopu.aop_stk > 0)
1283 abso += _G.stack.param_offset;
1285 assert (pairId == PAIR_HL);
1286 /* In some cases we can still inc or dec hl */
1287 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1289 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1293 setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
1295 _G.pairs[pairId].offset = abso;
1300 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
1306 _G.pairs[pairId].last_type = aop->type;
1312 emit2 ("!tlabeldef", key);
1316 /*-----------------------------------------------------------------*/
1317 /* aopGet - for fetching value of the aop */
1318 /*-----------------------------------------------------------------*/
1320 aopGet (asmop * aop, int offset, bool bit16)
1324 /* offset is greater than size then zero */
1325 /* PENDING: this seems a bit screwed in some pointer cases. */
1326 if (offset > (aop->size - 1) &&
1327 aop->type != AOP_LIT)
1329 tsprintf (s, "!zero");
1330 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1333 /* depending on type */
1337 /* PENDING: re-target */
1339 tsprintf (s, "!immedwords", aop->aopu.aop_immd);
1344 tsprintf (s, "!bankimmeds", aop->aopu.aop_immd);
1347 tsprintf (s, "!msbimmeds", aop->aopu.aop_immd);
1350 tsprintf (s, "!lsbimmeds", aop->aopu.aop_immd);
1353 wassertl (0, "Fetching from beyond the limits of an immediate value.");
1356 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1360 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1363 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1367 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1370 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1373 return aop->aopu.aop_reg[offset]->name;
1377 setupPair (PAIR_HL, aop, offset);
1378 tsprintf (s, "!*hl");
1380 return traceAlloc(&_G.trace.aops, Safe_strdup (s));
1384 setupPair (PAIR_IY, aop, offset);
1385 tsprintf (s, "!*iyx", offset);
1387 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1391 setupPair (PAIR_IY, aop, offset);
1392 tsprintf (s, "!*iyx", offset, offset);
1394 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1399 setupPair (PAIR_HL, aop, offset);
1400 tsprintf (s, "!*hl");
1404 if (aop->aopu.aop_stk >= 0)
1405 offset += _G.stack.param_offset;
1406 tsprintf (s, "!*ixx", aop->aopu.aop_stk + offset);
1409 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1412 wassertl (0, "Tried to fetch from a bit variable");
1421 tsprintf(s, "!zero");
1422 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1426 wassert (offset < 2);
1427 return aop->aopu.aop_str[offset];
1430 return aopLiteral (aop->aopu.aop_lit, offset);
1434 unsigned long v = aop->aopu.aop_simplelit;
1437 tsprintf (s, "!immedbyte", (unsigned int) v & 0xff);
1439 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1443 return aop->aopu.aop_str[offset];
1446 setupPair (aop->aopu.aop_pairId, aop, offset);
1447 sprintf (s, "(%s)", _pairs[aop->aopu.aop_pairId].name);
1449 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1454 wassertl (0, "aopget got unsupported aop->type");
1459 isRegString (const char *s)
1461 if (!strcmp (s, "b") ||
1473 isConstant (const char *s)
1475 /* This is a bit of a hack... */
1476 return (*s == '#' || *s == '$');
1480 canAssignToPtr (const char *s)
1482 if (isRegString (s))
1489 /*-----------------------------------------------------------------*/
1490 /* aopPut - puts a string for a aop */
1491 /*-----------------------------------------------------------------*/
1493 aopPut (asmop * aop, const char *s, int offset)
1497 if (aop->size && offset > (aop->size - 1))
1499 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1500 "aopPut got offset > aop->size");
1505 tsprintf(buffer2, s);
1508 /* will assign value to value */
1509 /* depending on where it is ofcourse */
1515 if (strcmp (s, "a"))
1516 emit2 ("ld a,%s", s);
1517 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1522 if (strcmp (s, "a"))
1523 emit2 ("ld a,%s", s);
1524 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1528 if (!strcmp (s, "!*hl"))
1529 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1532 aop->aopu.aop_reg[offset]->name, s);
1537 if (!canAssignToPtr (s))
1539 emit2 ("ld a,%s", s);
1540 setupPair (PAIR_IY, aop, offset);
1541 emit2 ("ld !*iyx,a", offset);
1545 setupPair (PAIR_IY, aop, offset);
1546 emit2 ("ld !*iyx,%s", offset, s);
1552 /* PENDING: for re-target */
1553 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1555 emit2 ("ld a,!*hl");
1558 setupPair (PAIR_HL, aop, offset);
1560 emit2 ("ld !*hl,%s", s);
1565 if (!canAssignToPtr (s))
1567 emit2 ("ld a,%s", s);
1568 setupPair (PAIR_IY, aop, offset);
1569 emit2 ("ld !*iyx,a", offset);
1573 setupPair (PAIR_IY, aop, offset);
1574 emit2 ("ld !*iyx,%s", offset, s);
1581 /* PENDING: re-target */
1582 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1584 emit2 ("ld a,!*hl");
1587 setupPair (PAIR_HL, aop, offset);
1588 if (!canAssignToPtr (s))
1590 emit2 ("ld a,%s", s);
1591 emit2 ("ld !*hl,a");
1594 emit2 ("ld !*hl,%s", s);
1598 if (aop->aopu.aop_stk >= 0)
1599 offset += _G.stack.param_offset;
1600 if (!canAssignToPtr (s))
1602 emit2 ("ld a,%s", s);
1603 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
1607 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
1613 /* if bit variable */
1614 if (!aop->aopu.aop_dir)
1621 /* In bit space but not in C - cant happen */
1622 wassertl (0, "Tried to write into a bit variable");
1628 if (strcmp (aop->aopu.aop_str[offset], s))
1630 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1636 if (!offset && (strcmp (s, "acc") == 0))
1640 wassertl (0, "Tried to access past the end of A");
1644 if (strcmp (aop->aopu.aop_str[offset], s))
1645 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1650 wassert (offset < 2);
1651 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1655 setupPair (aop->aopu.aop_pairId, aop, offset);
1656 emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
1660 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1661 "aopPut got unsupported aop->type");
1666 #define AOP(op) op->aop
1667 #define AOP_TYPE(op) AOP(op)->type
1668 #define AOP_SIZE(op) AOP(op)->size
1669 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
1672 commitPair (asmop * aop, PAIR_ID id)
1674 /* PENDING: Verify this. */
1675 if (id == PAIR_HL && requiresHL (aop) && IS_GB)
1679 aopPut (aop, "a", 0);
1680 aopPut (aop, "d", 1);
1685 if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
1687 char *l = aopGetLitWordLong (aop, 0, FALSE);
1690 emit2 ("ld (%s),%s", l, _pairs[id].name);
1694 aopPut (aop, _pairs[id].l, 0);
1695 aopPut (aop, _pairs[id].h, 1);
1700 /*-----------------------------------------------------------------*/
1701 /* getDataSize - get the operand data size */
1702 /*-----------------------------------------------------------------*/
1704 getDataSize (operand * op)
1707 size = AOP_SIZE (op);
1711 wassertl (0, "Somehow got a three byte data pointer");
1716 /*-----------------------------------------------------------------*/
1717 /* movLeft2Result - move byte from left to result */
1718 /*-----------------------------------------------------------------*/
1720 movLeft2Result (operand * left, int offl,
1721 operand * result, int offr, int sign)
1725 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
1727 l = aopGet (AOP (left), offl, FALSE);
1731 aopPut (AOP (result), l, offr);
1735 if (getDataSize (left) == offl + 1)
1737 emit2 ("ld a,%s", l);
1738 aopPut (AOP (result), "a", offr);
1745 movLeft2ResultLong (operand * left, int offl,
1746 operand * result, int offr, int sign,
1751 movLeft2Result (left, offl, result, offr, sign);
1755 wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
1756 wassertl (size == 2, "Only implemented for two bytes or one");
1758 if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
1760 emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
1761 emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
1764 else if ( getPairId ( AOP (result)) == PAIR_IY)
1766 PAIR_ID id = getPairId (AOP (left));
1767 if (id != PAIR_INVALID)
1769 emit2("push %s", _pairs[id].name);
1780 movLeft2Result (left, offl, result, offr, sign);
1781 movLeft2Result (left, offl+1, result, offr+1, sign);
1786 /** Put Acc into a register set
1789 outAcc (operand * result)
1792 size = getDataSize (result);
1795 aopPut (AOP (result), "a", 0);
1798 /* unsigned or positive */
1801 aopPut (AOP (result), "!zero", offset++);
1806 /** Take the value in carry and put it into a register
1809 outBitCLong (operand * result, bool swap_sense)
1811 /* if the result is bit */
1812 if (AOP_TYPE (result) == AOP_CRY)
1814 wassertl (0, "Tried to write carry to a bit");
1818 emit2 ("ld a,!zero");
1821 emit2 ("xor a,!immedbyte", 1);
1827 outBitC (operand * result)
1829 outBitCLong (result, FALSE);
1832 /*-----------------------------------------------------------------*/
1833 /* toBoolean - emit code for orl a,operator(sizeop) */
1834 /*-----------------------------------------------------------------*/
1836 _toBoolean (operand * oper)
1838 int size = AOP_SIZE (oper);
1842 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
1845 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
1849 if (AOP (oper)->type != AOP_ACC)
1852 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
1857 /*-----------------------------------------------------------------*/
1858 /* genNotFloat - generates not for float operations */
1859 /*-----------------------------------------------------------------*/
1861 genNotFloat (operand * op, operand * res)
1866 emitDebug ("; genNotFloat");
1868 /* we will put 127 in the first byte of
1870 aopPut (AOP (res), "!immedbyte", 0x7F);
1871 size = AOP_SIZE (op) - 1;
1874 _moveA (aopGet (op->aop, offset++, FALSE));
1878 emit2 ("or a,%s", aopGet (op->aop, offset++, FALSE));
1881 tlbl = newiTempLabel (NULL);
1882 aopPut (res->aop, "!one", 1);
1883 emit2 ("!shortjp z !tlabel", tlbl->key + 100);
1884 aopPut (res->aop, "!zero", 1);
1886 emitLabel(tlbl->key + 100);
1888 size = res->aop->size - 2;
1890 /* put zeros in the rest */
1892 aopPut (res->aop, "!zero", offset++);
1895 /*-----------------------------------------------------------------*/
1896 /* genNot - generate code for ! operation */
1897 /*-----------------------------------------------------------------*/
1901 sym_link *optype = operandType (IC_LEFT (ic));
1903 /* assign asmOps to operand & result */
1904 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
1905 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1907 /* if in bit space then a special case */
1908 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1910 wassertl (0, "Tried to negate a bit");
1913 /* if type float then do float */
1914 if (IS_FLOAT (optype))
1916 genNotFloat (IC_LEFT (ic), IC_RESULT (ic));
1920 _toBoolean (IC_LEFT (ic));
1925 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
1926 emit2 ("sub a,!one");
1927 outBitC (IC_RESULT (ic));
1930 /* release the aops */
1931 freeAsmop (IC_LEFT (ic), NULL, ic);
1932 freeAsmop (IC_RESULT (ic), NULL, ic);
1935 /*-----------------------------------------------------------------*/
1936 /* genCpl - generate code for complement */
1937 /*-----------------------------------------------------------------*/
1945 /* assign asmOps to operand & result */
1946 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1947 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1949 /* if both are in bit space then
1951 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1952 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1954 wassertl (0, "Left and the result are in bit space");
1957 size = AOP_SIZE (IC_RESULT (ic));
1960 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
1963 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1966 /* release the aops */
1967 freeAsmop (IC_LEFT (ic), NULL, ic);
1968 freeAsmop (IC_RESULT (ic), NULL, ic);
1972 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
1979 store de into result
1984 store de into result
1986 const char *first = isAdd ? "add" : "sub";
1987 const char *later = isAdd ? "adc" : "sbc";
1989 wassertl (IS_GB, "Code is only relevent to the gbz80");
1990 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
1992 fetchPair (PAIR_DE, left);
1995 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
1998 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2001 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2002 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2004 fetchPairLong (PAIR_DE, left, MSB24);
2005 aopGet (right, MSB24, FALSE);
2009 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2012 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2014 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2015 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2019 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2021 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2024 /*-----------------------------------------------------------------*/
2025 /* genUminusFloat - unary minus for floating points */
2026 /*-----------------------------------------------------------------*/
2028 genUminusFloat (operand * op, operand * result)
2030 int size, offset = 0;
2032 emitDebug("; genUminusFloat");
2034 /* for this we just need to flip the
2035 first it then copy the rest in place */
2036 size = AOP_SIZE (op) - 1;
2038 _moveA(aopGet (AOP (op), MSB32, FALSE));
2040 emit2("xor a,!immedbyte", 0x80);
2041 aopPut (AOP (result), "a", MSB32);
2045 aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2050 /*-----------------------------------------------------------------*/
2051 /* genUminus - unary minus code generation */
2052 /*-----------------------------------------------------------------*/
2054 genUminus (iCode * ic)
2057 sym_link *optype, *rtype;
2060 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2061 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2063 /* if both in bit space then special
2065 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2066 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2068 wassertl (0, "Left and right are in bit space");
2072 optype = operandType (IC_LEFT (ic));
2073 rtype = operandType (IC_RESULT (ic));
2075 /* if float then do float stuff */
2076 if (IS_FLOAT (optype))
2078 genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2082 /* otherwise subtract from zero */
2083 size = AOP_SIZE (IC_LEFT (ic));
2085 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2087 /* Create a new asmop with value zero */
2088 asmop *azero = newAsmop (AOP_SIMPLELIT);
2089 azero->aopu.aop_simplelit = 0;
2091 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2099 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2100 emit2 ("ld a,!zero");
2101 emit2 ("sbc a,%s", l);
2102 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2105 /* if any remaining bytes in the result */
2106 /* we just need to propagate the sign */
2107 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2112 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2116 /* release the aops */
2117 freeAsmop (IC_LEFT (ic), NULL, ic);
2118 freeAsmop (IC_RESULT (ic), NULL, ic);
2121 /*-----------------------------------------------------------------*/
2122 /* assignResultValue - */
2123 /*-----------------------------------------------------------------*/
2125 assignResultValue (operand * oper)
2127 int size = AOP_SIZE (oper);
2130 wassertl (size <= 4, "Got a result that is bigger than four bytes");
2131 topInA = requiresHL (AOP (oper));
2133 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2135 /* We do it the hard way here. */
2137 aopPut (AOP (oper), _fReturn[0], 0);
2138 aopPut (AOP (oper), _fReturn[1], 1);
2140 aopPut (AOP (oper), _fReturn[0], 2);
2141 aopPut (AOP (oper), _fReturn[1], 3);
2147 aopPut (AOP (oper), _fReturn[size], size);
2152 /** Simple restore that doesn't take into account what is used in the
2156 _restoreRegsAfterCall(void)
2158 if (_G.stack.pushedDE)
2161 _G.stack.pushedDE = FALSE;
2163 if (_G.stack.pushedBC)
2166 _G.stack.pushedBC = FALSE;
2168 _G.saves.saved = FALSE;
2172 _saveRegsForCall(iCode *ic, int sendSetSize)
2175 o Stack parameters are pushed before this function enters
2176 o DE and BC may be used in this function.
2177 o HL and DE may be used to return the result.
2178 o HL and DE may be used to send variables.
2179 o DE and BC may be used to store the result value.
2180 o HL may be used in computing the sent value of DE
2181 o The iPushes for other parameters occur before any addSets
2183 Logic: (to be run inside the first iPush or if none, before sending)
2184 o Compute if DE and/or BC are in use over the call
2185 o Compute if DE is used in the send set
2186 o Compute if DE and/or BC are used to hold the result value
2187 o If (DE is used, or in the send set) and is not used in the result, push.
2188 o If BC is used and is not in the result, push
2190 o If DE is used in the send set, fetch
2191 o If HL is used in the send set, fetch
2195 if (_G.saves.saved == FALSE) {
2196 bool deInUse, bcInUse;
2198 bool bcInRet = FALSE, deInRet = FALSE;
2201 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
2203 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2204 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2206 deSending = (sendSetSize > 1);
2208 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2210 if (bcInUse && bcInRet == FALSE) {
2212 _G.stack.pushedBC = TRUE;
2214 if (deInUse && deInRet == FALSE) {
2216 _G.stack.pushedDE = TRUE;
2219 _G.saves.saved = TRUE;
2222 /* Already saved. */
2226 /*-----------------------------------------------------------------*/
2227 /* genIpush - genrate code for pushing this gets a little complex */
2228 /*-----------------------------------------------------------------*/
2230 genIpush (iCode * ic)
2232 int size, offset = 0;
2235 /* if this is not a parm push : ie. it is spill push
2236 and spill push is always done on the local stack */
2239 wassertl(0, "Encountered an unsupported spill push.");
2243 if (_G.saves.saved == FALSE) {
2244 /* Caller saves, and this is the first iPush. */
2245 /* Scan ahead until we find the function that we are pushing parameters to.
2246 Count the number of addSets on the way to figure out what registers
2247 are used in the send set.
2250 iCode *walk = ic->next;
2253 if (walk->op == SEND) {
2256 else if (walk->op == CALL || walk->op == PCALL) {
2265 _saveRegsForCall(walk, nAddSets);
2268 /* Already saved by another iPush. */
2271 /* then do the push */
2272 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2274 size = AOP_SIZE (IC_LEFT (ic));
2276 if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2278 _G.stack.pushed += 2;
2279 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2285 fetchHL (AOP (IC_LEFT (ic)));
2287 spillPair (PAIR_HL);
2288 _G.stack.pushed += 2;
2293 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
2295 spillPair (PAIR_HL);
2296 _G.stack.pushed += 2;
2297 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 0);
2299 spillPair (PAIR_HL);
2300 _G.stack.pushed += 2;
2306 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2308 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2310 emit2 ("ld a,(%s)", l);
2314 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2315 emit2 ("ld a,%s", l);
2323 freeAsmop (IC_LEFT (ic), NULL, ic);
2326 /*-----------------------------------------------------------------*/
2327 /* genIpop - recover the registers: can happen only for spilling */
2328 /*-----------------------------------------------------------------*/
2330 genIpop (iCode * ic)
2335 /* if the temp was not pushed then */
2336 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2339 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2340 size = AOP_SIZE (IC_LEFT (ic));
2341 offset = (size - 1);
2342 if (isPair (AOP (IC_LEFT (ic))))
2344 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2352 spillPair (PAIR_HL);
2353 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2357 freeAsmop (IC_LEFT (ic), NULL, ic);
2360 /* This is quite unfortunate */
2362 setArea (int inHome)
2365 static int lastArea = 0;
2367 if (_G.in_home != inHome) {
2369 const char *sz = port->mem.code_name;
2370 port->mem.code_name = "HOME";
2371 emit2("!area", CODE_NAME);
2372 port->mem.code_name = sz;
2375 emit2("!area", CODE_NAME); */
2376 _G.in_home = inHome;
2387 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2391 symbol *sym = OP_SYMBOL (op);
2393 if (sym->isspilt || sym->nRegs == 0)
2396 aopOp (op, ic, FALSE, FALSE);
2399 if (aop->type == AOP_REG)
2402 for (i = 0; i < aop->size; i++)
2404 if (pairId == PAIR_DE)
2406 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2407 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2409 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2412 else if (pairId == PAIR_BC)
2414 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2415 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2417 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2427 freeAsmop (IC_LEFT (ic), NULL, ic);
2431 /** Emit the code for a call statement
2434 emitCall (iCode * ic, bool ispcall)
2436 sym_link *dtype = operandType (IC_LEFT (ic));
2438 /* if caller saves & we have not saved then */
2444 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2446 /* if send set is not empty then assign */
2451 int nSend = elementsInSet(_G.sendSet);
2452 bool swapped = FALSE;
2454 int _z80_sendOrder[] = {
2459 /* Check if the parameters are swapped. If so route through hl instead. */
2460 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2462 sic = setFirstItem(_G.sendSet);
2463 sic = setNextItem(_G.sendSet);
2465 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2466 /* The second send value is loaded from one the one that holds the first
2467 send, i.e. it is overwritten. */
2468 /* Cache the first in HL, and load the second from HL instead. */
2469 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2470 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2476 for (sic = setFirstItem (_G.sendSet); sic;
2477 sic = setNextItem (_G.sendSet))
2480 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2482 size = AOP_SIZE (IC_LEFT (sic));
2483 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2484 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2486 // PENDING: Mild hack
2487 if (swapped == TRUE && send == 1) {
2489 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2492 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2494 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2497 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2501 freeAsmop (IC_LEFT (sic), NULL, sic);
2508 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2510 werror (W_INDIR_BANKED);
2512 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2514 if (isLitWord (AOP (IC_LEFT (ic))))
2516 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2520 symbol *rlbl = newiTempLabel (NULL);
2521 spillPair (PAIR_HL);
2522 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2524 _G.stack.pushed += 2;
2526 fetchHL (AOP (IC_LEFT (ic)));
2528 emit2 ("!tlabeldef", (rlbl->key + 100));
2529 _G.stack.pushed -= 2;
2531 freeAsmop (IC_LEFT (ic), NULL, ic);
2535 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2536 OP_SYMBOL (IC_LEFT (ic))->rname :
2537 OP_SYMBOL (IC_LEFT (ic))->name;
2538 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2540 emit2 ("call banked_call");
2541 emit2 ("!dws", name);
2542 emit2 ("!dw !bankimmeds", name);
2547 emit2 ("call %s", name);
2552 /* Mark the regsiters as restored. */
2553 _G.saves.saved = FALSE;
2555 /* if we need assign a result value */
2556 if ((IS_ITEMP (IC_RESULT (ic)) &&
2557 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2558 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2559 IS_TRUE_SYMOP (IC_RESULT (ic)))
2562 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2564 assignResultValue (IC_RESULT (ic));
2566 freeAsmop (IC_RESULT (ic), NULL, ic);
2569 /* adjust the stack for parameters if required */
2572 int i = ic->parmBytes;
2574 _G.stack.pushed -= i;
2577 emit2 ("!ldaspsp", i);
2584 emit2 ("ld iy,#%d", i);
2585 emit2 ("add iy,sp");
2605 if (_G.stack.pushedDE)
2607 bool dInRet = bitVectBitValue(ic->rUsed, D_IDX);
2608 bool eInRet = bitVectBitValue(ic->rUsed, E_IDX);
2610 if (dInRet && eInRet)
2612 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
2616 /* Only restore E */
2623 /* Only restore D */
2631 _G.stack.pushedDE = FALSE;
2634 if (_G.stack.pushedBC)
2636 bool bInRet = bitVectBitValue(ic->rUsed, B_IDX);
2637 bool cInRet = bitVectBitValue(ic->rUsed, C_IDX);
2639 if (bInRet && cInRet)
2641 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
2645 /* Only restore C */
2652 /* Only restore B */
2660 _G.stack.pushedBC = FALSE;
2664 /*-----------------------------------------------------------------*/
2665 /* genCall - generates a call statement */
2666 /*-----------------------------------------------------------------*/
2668 genCall (iCode * ic)
2670 emitCall (ic, FALSE);
2673 /*-----------------------------------------------------------------*/
2674 /* genPcall - generates a call by pointer statement */
2675 /*-----------------------------------------------------------------*/
2677 genPcall (iCode * ic)
2679 emitCall (ic, TRUE);
2682 /*-----------------------------------------------------------------*/
2683 /* resultRemat - result is rematerializable */
2684 /*-----------------------------------------------------------------*/
2686 resultRemat (iCode * ic)
2688 if (SKIP_IC (ic) || ic->op == IFX)
2691 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2693 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2694 if (sym->remat && !POINTER_SET (ic))
2701 extern set *publics;
2703 /*-----------------------------------------------------------------*/
2704 /* genFunction - generated code for function entry */
2705 /*-----------------------------------------------------------------*/
2707 genFunction (iCode * ic)
2709 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2713 bool bcInUse = FALSE;
2714 bool deInUse = FALSE;
2717 setArea (IFFUNC_NONBANKED (sym->type));
2719 /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
2722 _G.receiveOffset = 0;
2724 /* Record the last function name for debugging. */
2725 _G.lastFunctionName = sym->rname;
2727 /* Create the function header */
2728 emit2 ("!functionheader", sym->name);
2729 /* PENDING: portability. */
2730 emit2 ("__%s_start:", sym->rname);
2731 emit2 ("!functionlabeldef", sym->rname);
2733 if (options.profile)
2735 emit2 ("!profileenter");
2738 ftype = operandType (IC_LEFT (ic));
2740 /* if critical function then turn interrupts off */
2741 if (IFFUNC_ISCRITICAL (ftype))
2744 /* if this is an interrupt service routine then save all potentially used registers. */
2745 if (IFFUNC_ISISR (sym->type))
2750 /* PENDING: callee-save etc */
2752 _G.stack.param_offset = 0;
2755 /* Detect which registers are used. */
2759 for (i = 0; i < sym->regsUsed->size; i++)
2761 if (bitVectBitValue (sym->regsUsed, i))
2775 /* Other systems use DE as a temporary. */
2786 _G.stack.param_offset += 2;
2789 _G.stack.pushedBC = bcInUse;
2794 _G.stack.param_offset += 2;
2797 _G.stack.pushedDE = deInUse;
2800 /* adjust the stack for the function */
2801 _G.stack.last = sym->stack;
2803 if (sym->stack && IS_GB && sym->stack > -INT8MIN)
2804 emit2 ("!enterxl", sym->stack);
2805 else if (sym->stack)
2806 emit2 ("!enterx", sym->stack);
2809 _G.stack.offset = sym->stack;
2812 /*-----------------------------------------------------------------*/
2813 /* genEndFunction - generates epilogue for functions */
2814 /*-----------------------------------------------------------------*/
2816 genEndFunction (iCode * ic)
2818 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2820 if (IFFUNC_ISISR (sym->type))
2822 wassertl (0, "Tried to close an interrupt support function");
2826 if (IFFUNC_ISCRITICAL (sym->type))
2829 /* PENDING: calleeSave */
2831 if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
2833 emit2 ("!leavexl", _G.stack.offset);
2835 else if (_G.stack.offset)
2837 emit2 ("!leavex", _G.stack.offset);
2845 if (_G.stack.pushedDE)
2848 _G.stack.pushedDE = FALSE;
2851 if (_G.stack.pushedDE)
2854 _G.stack.pushedDE = FALSE;
2858 if (options.profile)
2860 emit2 ("!profileexit");
2864 /* Both baned and non-banked just ret */
2867 /* PENDING: portability. */
2868 emit2 ("__%s_end:", sym->rname);
2870 _G.flushStatics = 1;
2871 _G.stack.pushed = 0;
2872 _G.stack.offset = 0;
2875 /*-----------------------------------------------------------------*/
2876 /* genRet - generate code for return statement */
2877 /*-----------------------------------------------------------------*/
2882 /* Errk. This is a hack until I can figure out how
2883 to cause dehl to spill on a call */
2884 int size, offset = 0;
2886 /* if we have no return value then
2887 just generate the "ret" */
2891 /* we have something to return then
2892 move the return value into place */
2893 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2894 size = AOP_SIZE (IC_LEFT (ic));
2896 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
2900 emit2 ("ld de,%s", l);
2904 emit2 ("ld hl,%s", l);
2909 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
2911 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
2912 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
2918 l = aopGet (AOP (IC_LEFT (ic)), offset,
2920 if (strcmp (_fReturn[offset], l))
2921 emit2 ("ld %s,%s", _fReturn[offset++], l);
2925 freeAsmop (IC_LEFT (ic), NULL, ic);
2928 /* generate a jump to the return label
2929 if the next is not the return statement */
2930 if (!(ic->next && ic->next->op == LABEL &&
2931 IC_LABEL (ic->next) == returnLabel))
2933 emit2 ("jp !tlabel", returnLabel->key + 100);
2936 /*-----------------------------------------------------------------*/
2937 /* genLabel - generates a label */
2938 /*-----------------------------------------------------------------*/
2940 genLabel (iCode * ic)
2942 /* special case never generate */
2943 if (IC_LABEL (ic) == entryLabel)
2946 emitLabel (IC_LABEL (ic)->key + 100);
2949 /*-----------------------------------------------------------------*/
2950 /* genGoto - generates a ljmp */
2951 /*-----------------------------------------------------------------*/
2953 genGoto (iCode * ic)
2955 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
2958 /*-----------------------------------------------------------------*/
2959 /* genPlusIncr :- does addition with increment if possible */
2960 /*-----------------------------------------------------------------*/
2962 genPlusIncr (iCode * ic)
2964 unsigned int icount;
2965 unsigned int size = getDataSize (IC_RESULT (ic));
2966 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
2968 /* will try to generate an increment */
2969 /* if the right side is not a literal
2971 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
2974 emitDebug ("; genPlusIncr");
2976 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
2978 /* If result is a pair */
2979 if (resultId != PAIR_INVALID)
2981 if (isLitWord (AOP (IC_LEFT (ic))))
2983 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
2986 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
2988 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
2990 PAIR_ID freep = getFreePairId (ic);
2991 if (freep != PAIR_INVALID)
2993 fetchPair (freep, AOP (IC_RIGHT (ic)));
2994 emit2 ("add hl,%s", _pairs[freep].name);
3000 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3001 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3008 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3012 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3016 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3021 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3023 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3024 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3028 /* if the literal value of the right hand side
3029 is greater than 4 then it is not worth it */
3033 /* if increment 16 bits in register */
3034 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3040 symbol *tlbl = NULL;
3041 tlbl = newiTempLabel (NULL);
3044 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3047 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3050 emitLabel (tlbl->key + 100);
3054 /* if the sizes are greater than 1 then we cannot */
3055 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3056 AOP_SIZE (IC_LEFT (ic)) > 1)
3059 /* If the result is in a register then we can load then increment.
3061 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3063 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3066 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3071 /* we can if the aops of the left & result match or
3072 if they are in registers and the registers are the
3074 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3078 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3086 /*-----------------------------------------------------------------*/
3087 /* outBitAcc - output a bit in acc */
3088 /*-----------------------------------------------------------------*/
3090 outBitAcc (operand * result)
3092 symbol *tlbl = newiTempLabel (NULL);
3093 /* if the result is a bit */
3094 if (AOP_TYPE (result) == AOP_CRY)
3096 wassertl (0, "Tried to write A into a bit");
3100 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3101 emit2 ("ld a,!one");
3102 emitLabel (tlbl->key + 100);
3108 couldDestroyCarry (asmop *aop)
3112 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3121 shiftIntoPair (int idx, asmop *aop)
3123 PAIR_ID id = PAIR_INVALID;
3125 wassertl (IS_Z80, "Only implemented for the Z80");
3126 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3138 wassertl (0, "Internal error - hit default case");
3141 emitDebug ("; Shift into pair idx %u", idx);
3145 setupPair (PAIR_HL, aop, 0);
3149 setupPair (PAIR_IY, aop, 0);
3151 emit2 ("pop %s", _pairs[id].name);
3154 aop->type = AOP_PAIRPTR;
3155 aop->aopu.aop_pairId = id;
3156 _G.pairs[id].offset = 0;
3157 _G.pairs[id].last_type = aop->type;
3161 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
3163 wassert (left && right);
3167 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3169 shiftIntoPair (0, right);
3170 shiftIntoPair (1, result);
3172 else if (couldDestroyCarry (right))
3174 shiftIntoPair (0, right);
3176 else if (couldDestroyCarry (result))
3178 shiftIntoPair (0, result);
3187 /*-----------------------------------------------------------------*/
3188 /* genPlus - generates code for addition */
3189 /*-----------------------------------------------------------------*/
3191 genPlus (iCode * ic)
3193 int size, offset = 0;
3195 /* special cases :- */
3197 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3198 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3199 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3201 /* Swap the left and right operands if:
3203 if literal, literal on the right or
3204 if left requires ACC or right is already
3207 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3208 (AOP_NEEDSACC (IC_LEFT (ic))) ||
3209 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3211 operand *t = IC_RIGHT (ic);
3212 IC_RIGHT (ic) = IC_LEFT (ic);
3216 /* if both left & right are in bit
3218 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3219 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3222 wassertl (0, "Tried to add two bits");
3225 /* if left in bit space & right literal */
3226 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3227 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3229 /* Can happen I guess */
3230 wassertl (0, "Tried to add a bit to a literal");
3233 /* if I can do an increment instead
3234 of add then GOOD for ME */
3235 if (genPlusIncr (ic) == TRUE)
3238 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3240 size = getDataSize (IC_RESULT (ic));
3242 /* Special case when left and right are constant */
3243 if (isPair (AOP (IC_RESULT (ic))))
3246 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3247 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3249 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3255 sprintf (buffer, "#(%s + %s)", left, right);
3256 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3261 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3263 /* Fetch into HL then do the add */
3264 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3265 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3267 spillPair (PAIR_HL);
3269 if (left == PAIR_HL && right != PAIR_INVALID)
3271 emit2 ("add hl,%s", _pairs[right].name);
3274 else if (right == PAIR_HL && left != PAIR_INVALID)
3276 emit2 ("add hl,%s", _pairs[left].name);
3279 else if (right != PAIR_INVALID && right != PAIR_HL)
3281 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3282 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3285 else if (left != PAIR_INVALID && left != PAIR_HL)
3287 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3288 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3297 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3299 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3300 emit2 ("add hl,%s ; 2", getPairName (AOP (IC_RIGHT (ic))));
3302 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3307 ld hl,sp+n trashes C so we cant afford to do it during an
3308 add with stack based varibles. Worst case is:
3321 So you cant afford to load up hl if either left, right, or result
3322 is on the stack (*sigh*) The alt is:
3330 Combinations in here are:
3331 * If left or right are in bc then the loss is small - trap later
3332 * If the result is in bc then the loss is also small
3336 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3337 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3338 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3340 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3341 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3342 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3343 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3345 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3347 /* Swap left and right */
3348 operand *t = IC_RIGHT (ic);
3349 IC_RIGHT (ic) = IC_LEFT (ic);
3352 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3354 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3355 emit2 ("add hl,bc");
3359 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3360 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3361 emit2 ("add hl,de");
3363 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3369 /* Be paranoid on the GB with 4 byte variables due to how C
3370 can be trashed by lda hl,n(sp).
3372 _gbz80_emitAddSubLong (ic, TRUE);
3377 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3381 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3383 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3386 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3389 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3393 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3396 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3399 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3401 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3405 freeAsmop (IC_LEFT (ic), NULL, ic);
3406 freeAsmop (IC_RIGHT (ic), NULL, ic);
3407 freeAsmop (IC_RESULT (ic), NULL, ic);
3411 /*-----------------------------------------------------------------*/
3412 /* genMinusDec :- does subtraction with deccrement if possible */
3413 /*-----------------------------------------------------------------*/
3415 genMinusDec (iCode * ic)
3417 unsigned int icount;
3418 unsigned int size = getDataSize (IC_RESULT (ic));
3420 /* will try to generate an increment */
3421 /* if the right side is not a literal we cannot */
3422 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3425 /* if the literal value of the right hand side
3426 is greater than 4 then it is not worth it */
3427 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3430 size = getDataSize (IC_RESULT (ic));
3432 /* if decrement 16 bits in register */
3433 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3434 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3437 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3441 /* If result is a pair */
3442 if (isPair (AOP (IC_RESULT (ic))))
3444 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3446 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3450 /* if increment 16 bits in register */
3451 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3455 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3458 emit2 ("dec %s", _getTempPairName());
3461 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3467 /* if the sizes are greater than 1 then we cannot */
3468 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3469 AOP_SIZE (IC_LEFT (ic)) > 1)
3472 /* we can if the aops of the left & result match or if they are in
3473 registers and the registers are the same */
3474 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3477 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3484 /*-----------------------------------------------------------------*/
3485 /* genMinus - generates code for subtraction */
3486 /*-----------------------------------------------------------------*/
3488 genMinus (iCode * ic)
3490 int size, offset = 0;
3491 unsigned long lit = 0L;
3493 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3494 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3495 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3497 /* special cases :- */
3498 /* if both left & right are in bit space */
3499 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3500 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3502 wassertl (0, "Tried to subtract two bits");
3506 /* if I can do an decrement instead of subtract then GOOD for ME */
3507 if (genMinusDec (ic) == TRUE)
3510 size = getDataSize (IC_RESULT (ic));
3512 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3517 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3521 /* Same logic as genPlus */
3524 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3525 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3526 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3528 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3529 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3530 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3531 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3533 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3534 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3536 if (left == PAIR_INVALID && right == PAIR_INVALID)
3541 else if (right == PAIR_INVALID)
3543 else if (left == PAIR_INVALID)
3546 fetchPair (left, AOP (IC_LEFT (ic)));
3547 /* Order is important. Right may be HL */
3548 fetchPair (right, AOP (IC_RIGHT (ic)));
3550 emit2 ("ld a,%s", _pairs[left].l);
3551 emit2 ("sub a,%s", _pairs[right].l);
3553 emit2 ("ld a,%s", _pairs[left].h);
3554 emit2 ("sbc a,%s", _pairs[right].h);
3556 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
3558 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3560 aopPut (AOP (IC_RESULT (ic)), "e", 0);
3566 /* Be paranoid on the GB with 4 byte variables due to how C
3567 can be trashed by lda hl,n(sp).
3569 _gbz80_emitAddSubLong (ic, FALSE);
3574 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3576 /* if literal, add a,#-lit, else normal subb */
3579 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3580 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3584 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3587 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3591 /* first add without previous c */
3593 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
3595 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3597 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3600 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3601 AOP_SIZE (IC_LEFT (ic)) == 3 &&
3602 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3604 wassertl (0, "Tried to subtract on a long pointer");
3608 freeAsmop (IC_LEFT (ic), NULL, ic);
3609 freeAsmop (IC_RIGHT (ic), NULL, ic);
3610 freeAsmop (IC_RESULT (ic), NULL, ic);
3613 /*-----------------------------------------------------------------*/
3614 /* genMult - generates code for multiplication */
3615 /*-----------------------------------------------------------------*/
3617 genMult (iCode * ic)
3621 /* If true then the final operation should be a subtract */
3622 bool active = FALSE;
3624 /* Shouldn't occur - all done through function calls */
3625 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3626 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3627 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3629 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
3630 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
3631 AOP_SIZE (IC_RESULT (ic)) > 2)
3633 wassertl (0, "Multiplication is handled through support function calls");
3636 /* Swap left and right such that right is a literal */
3637 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
3639 operand *t = IC_RIGHT (ic);
3640 IC_RIGHT (ic) = IC_LEFT (ic);
3644 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
3646 val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
3647 // wassertl (val > 0, "Multiply must be positive");
3648 wassertl (val != 1, "Can't multiply by 1");
3654 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
3656 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
3664 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3669 /* Fully unroled version of mul.s. Not the most efficient.
3671 for (count = 0; count < 16; count++)
3673 if (count != 0 && active)
3675 emit2 ("add hl,hl");
3679 if (active == FALSE)
3686 emit2 ("add hl,de");
3700 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3702 freeAsmop (IC_LEFT (ic), NULL, ic);
3703 freeAsmop (IC_RIGHT (ic), NULL, ic);
3704 freeAsmop (IC_RESULT (ic), NULL, ic);
3707 /*-----------------------------------------------------------------*/
3708 /* genDiv - generates code for division */
3709 /*-----------------------------------------------------------------*/
3713 /* Shouldn't occur - all done through function calls */
3714 wassertl (0, "Division is handled through support function calls");
3717 /*-----------------------------------------------------------------*/
3718 /* genMod - generates code for division */
3719 /*-----------------------------------------------------------------*/
3723 /* Shouldn't occur - all done through function calls */
3727 /*-----------------------------------------------------------------*/
3728 /* genIfxJump :- will create a jump depending on the ifx */
3729 /*-----------------------------------------------------------------*/
3731 genIfxJump (iCode * ic, char *jval)
3736 /* if true label then we jump if condition
3740 jlbl = IC_TRUE (ic);
3741 if (!strcmp (jval, "a"))
3745 else if (!strcmp (jval, "c"))
3749 else if (!strcmp (jval, "nc"))
3753 else if (!strcmp (jval, "m"))
3757 else if (!strcmp (jval, "p"))
3763 /* The buffer contains the bit on A that we should test */
3769 /* false label is present */
3770 jlbl = IC_FALSE (ic);
3771 if (!strcmp (jval, "a"))
3775 else if (!strcmp (jval, "c"))
3779 else if (!strcmp (jval, "nc"))
3783 else if (!strcmp (jval, "m"))
3787 else if (!strcmp (jval, "p"))
3793 /* The buffer contains the bit on A that we should test */
3797 /* Z80 can do a conditional long jump */
3798 if (!strcmp (jval, "a"))
3802 else if (!strcmp (jval, "c"))
3805 else if (!strcmp (jval, "nc"))
3808 else if (!strcmp (jval, "m"))
3811 else if (!strcmp (jval, "p"))
3816 emit2 ("bit %s,a", jval);
3818 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
3820 /* mark the icode as generated */
3826 _getPairIdName (PAIR_ID id)
3828 return _pairs[id].name;
3833 /* if unsigned char cmp with lit, just compare */
3835 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
3837 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3840 emit2 ("xor a,!immedbyte", 0x80);
3841 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
3844 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3846 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
3848 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
3849 // Pull left into DE and right into HL
3850 aopGet (AOP(left), LSB, FALSE);
3853 aopGet (AOP(right), LSB, FALSE);
3857 if (size == 0 && sign)
3859 // Highest byte when signed needs the bits flipped
3862 emit2 ("ld a,(de)");
3863 emit2 ("xor #0x80");
3865 emit2 ("ld a,(hl)");
3866 emit2 ("xor #0x80");
3870 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
3874 emit2 ("ld a,(de)");
3875 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
3885 spillPair (PAIR_HL);
3887 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
3889 setupPair (PAIR_HL, AOP (left), 0);
3890 aopGet (AOP(right), LSB, FALSE);
3894 if (size == 0 && sign)
3896 // Highest byte when signed needs the bits flipped
3899 emit2 ("ld a,(hl)");
3900 emit2 ("xor #0x80");
3902 emit2 ("ld a,%d(iy)", offset);
3903 emit2 ("xor #0x80");
3907 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
3911 emit2 ("ld a,(hl)");
3912 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
3921 spillPair (PAIR_HL);
3922 spillPair (PAIR_IY);
3926 if (AOP_TYPE (right) == AOP_LIT)
3928 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3929 /* optimize if(x < 0) or if(x >= 0) */
3934 /* No sign so it's always false */
3939 /* Just load in the top most bit */
3940 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
3941 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
3943 genIfxJump (ifx, "7");
3955 /* First setup h and l contaning the top most bytes XORed */
3956 bool fDidXor = FALSE;
3957 if (AOP_TYPE (left) == AOP_LIT)
3959 unsigned long lit = (unsigned long)
3960 floatFromVal (AOP (left)->aopu.aop_lit);
3961 emit2 ("ld %s,!immedbyte", _fTmp[0],
3962 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3966 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
3967 emit2 ("xor a,!immedbyte", 0x80);
3968 emit2 ("ld %s,a", _fTmp[0]);
3971 if (AOP_TYPE (right) == AOP_LIT)
3973 unsigned long lit = (unsigned long)
3974 floatFromVal (AOP (right)->aopu.aop_lit);
3975 emit2 ("ld %s,!immedbyte", _fTmp[1],
3976 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3980 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
3981 emit2 ("xor a,!immedbyte", 0x80);
3982 emit2 ("ld %s,a", _fTmp[1]);
3988 /* Do a long subtract */
3991 _moveA (aopGet (AOP (left), offset, FALSE));
3993 if (sign && size == 0)
3995 emit2 ("ld a,%s", _fTmp[0]);
3996 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4000 /* Subtract through, propagating the carry */
4001 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4009 /** Generic compare for > or <
4012 genCmp (operand * left, operand * right,
4013 operand * result, iCode * ifx, int sign)
4015 int size, offset = 0;
4016 unsigned long lit = 0L;
4017 bool swap_sense = FALSE;
4019 /* if left & right are bit variables */
4020 if (AOP_TYPE (left) == AOP_CRY &&
4021 AOP_TYPE (right) == AOP_CRY)
4023 /* Cant happen on the Z80 */
4024 wassertl (0, "Tried to compare two bits");
4028 /* Do a long subtract of right from left. */
4029 size = max (AOP_SIZE (left), AOP_SIZE (right));
4031 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4033 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4034 // Pull left into DE and right into HL
4035 aopGet (AOP(left), LSB, FALSE);
4038 aopGet (AOP(right), LSB, FALSE);
4042 emit2 ("ld a,(de)");
4043 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4052 spillPair (PAIR_HL);
4056 if (AOP_TYPE (right) == AOP_LIT)
4058 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4059 /* optimize if(x < 0) or if(x >= 0) */
4064 /* No sign so it's always false */
4069 /* Just load in the top most bit */
4070 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4071 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4073 genIfxJump (ifx, "7");
4084 genIfxJump (ifx, swap_sense ? "c" : "nc");
4095 _moveA (aopGet (AOP (left), offset, FALSE));
4096 /* Subtract through, propagating the carry */
4097 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4103 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4107 /* Shift the sign bit up into carry */
4110 outBitCLong (result, swap_sense);
4114 /* if the result is used in the next
4115 ifx conditional branch then generate
4116 code a little differently */
4124 genIfxJump (ifx, swap_sense ? "nc" : "c");
4128 genIfxJump (ifx, swap_sense ? "p" : "m");
4133 genIfxJump (ifx, swap_sense ? "nc" : "c");
4140 /* Shift the sign bit up into carry */
4143 outBitCLong (result, swap_sense);
4145 /* leave the result in acc */
4149 /*-----------------------------------------------------------------*/
4150 /* genCmpGt :- greater than comparison */
4151 /*-----------------------------------------------------------------*/
4153 genCmpGt (iCode * ic, iCode * ifx)
4155 operand *left, *right, *result;
4156 sym_link *letype, *retype;
4159 left = IC_LEFT (ic);
4160 right = IC_RIGHT (ic);
4161 result = IC_RESULT (ic);
4163 letype = getSpec (operandType (left));
4164 retype = getSpec (operandType (right));
4165 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4166 /* assign the amsops */
4167 aopOp (left, ic, FALSE, FALSE);
4168 aopOp (right, ic, FALSE, FALSE);
4169 aopOp (result, ic, TRUE, FALSE);
4171 genCmp (right, left, result, ifx, sign);
4173 freeAsmop (left, NULL, ic);
4174 freeAsmop (right, NULL, ic);
4175 freeAsmop (result, NULL, ic);
4178 /*-----------------------------------------------------------------*/
4179 /* genCmpLt - less than comparisons */
4180 /*-----------------------------------------------------------------*/
4182 genCmpLt (iCode * ic, iCode * ifx)
4184 operand *left, *right, *result;
4185 sym_link *letype, *retype;
4188 left = IC_LEFT (ic);
4189 right = IC_RIGHT (ic);
4190 result = IC_RESULT (ic);
4192 letype = getSpec (operandType (left));
4193 retype = getSpec (operandType (right));
4194 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4196 /* assign the amsops */
4197 aopOp (left, ic, FALSE, FALSE);
4198 aopOp (right, ic, FALSE, FALSE);
4199 aopOp (result, ic, TRUE, FALSE);
4201 genCmp (left, right, result, ifx, sign);
4203 freeAsmop (left, NULL, ic);
4204 freeAsmop (right, NULL, ic);
4205 freeAsmop (result, NULL, ic);
4208 /*-----------------------------------------------------------------*/
4209 /* gencjneshort - compare and jump if not equal */
4210 /*-----------------------------------------------------------------*/
4212 gencjneshort (operand * left, operand * right, symbol * lbl)
4214 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4216 unsigned long lit = 0L;
4218 /* Swap the left and right if it makes the computation easier */
4219 if (AOP_TYPE (left) == AOP_LIT)
4226 if (AOP_TYPE (right) == AOP_LIT)
4228 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4231 /* if the right side is a literal then anything goes */
4232 if (AOP_TYPE (right) == AOP_LIT &&
4233 AOP_TYPE (left) != AOP_DIR)
4237 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4242 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4249 emit2 ("jp nz,!tlabel", lbl->key + 100);
4255 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4256 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
4259 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
4260 emit2 ("jp nz,!tlabel", lbl->key + 100);
4265 /* if the right side is in a register or in direct space or
4266 if the left is a pointer register & right is not */
4267 else if (AOP_TYPE (right) == AOP_REG ||
4268 AOP_TYPE (right) == AOP_DIR ||
4269 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
4273 _moveA (aopGet (AOP (left), offset, FALSE));
4274 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
4275 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4277 emit2 ("jp nz,!tlabel", lbl->key + 100);
4280 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4281 emit2 ("jp nz,!tlabel", lbl->key + 100);
4288 /* right is a pointer reg need both a & b */
4289 /* PENDING: is this required? */
4292 _moveA (aopGet (AOP (right), offset, FALSE));
4293 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
4294 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
4300 /*-----------------------------------------------------------------*/
4301 /* gencjne - compare and jump if not equal */
4302 /*-----------------------------------------------------------------*/
4304 gencjne (operand * left, operand * right, symbol * lbl)
4306 symbol *tlbl = newiTempLabel (NULL);
4308 gencjneshort (left, right, lbl);
4311 emit2 ("ld a,!one");
4312 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4313 emitLabel (lbl->key + 100);
4315 emitLabel (tlbl->key + 100);
4318 /*-----------------------------------------------------------------*/
4319 /* genCmpEq - generates code for equal to */
4320 /*-----------------------------------------------------------------*/
4322 genCmpEq (iCode * ic, iCode * ifx)
4324 operand *left, *right, *result;
4326 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4327 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4328 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4330 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4332 /* Swap operands if it makes the operation easier. ie if:
4333 1. Left is a literal.
4335 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4337 operand *t = IC_RIGHT (ic);
4338 IC_RIGHT (ic) = IC_LEFT (ic);
4342 if (ifx && !AOP_SIZE (result))
4345 /* if they are both bit variables */
4346 if (AOP_TYPE (left) == AOP_CRY &&
4347 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4349 wassertl (0, "Tried to compare two bits");
4353 tlbl = newiTempLabel (NULL);
4354 gencjneshort (left, right, tlbl);
4357 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4358 emitLabel (tlbl->key + 100);
4362 /* PENDING: do this better */
4363 symbol *lbl = newiTempLabel (NULL);
4364 emit2 ("!shortjp !tlabel", lbl->key + 100);
4365 emitLabel (tlbl->key + 100);
4366 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4367 emitLabel (lbl->key + 100);
4370 /* mark the icode as generated */
4375 /* if they are both bit variables */
4376 if (AOP_TYPE (left) == AOP_CRY &&
4377 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4379 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4385 gencjne (left, right, newiTempLabel (NULL));
4386 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4393 genIfxJump (ifx, "a");
4396 /* if the result is used in an arithmetic operation
4397 then put the result in place */
4398 if (AOP_TYPE (result) != AOP_CRY)
4403 /* leave the result in acc */
4407 freeAsmop (left, NULL, ic);
4408 freeAsmop (right, NULL, ic);
4409 freeAsmop (result, NULL, ic);
4412 /*-----------------------------------------------------------------*/
4413 /* ifxForOp - returns the icode containing the ifx for operand */
4414 /*-----------------------------------------------------------------*/
4416 ifxForOp (operand * op, iCode * ic)
4418 /* if true symbol then needs to be assigned */
4419 if (IS_TRUE_SYMOP (op))
4422 /* if this has register type condition and
4423 the next instruction is ifx with the same operand
4424 and live to of the operand is upto the ifx only then */
4426 ic->next->op == IFX &&
4427 IC_COND (ic->next)->key == op->key &&
4428 OP_SYMBOL (op)->liveTo <= ic->next->seq)
4434 /*-----------------------------------------------------------------*/
4435 /* genAndOp - for && operation */
4436 /*-----------------------------------------------------------------*/
4438 genAndOp (iCode * ic)
4440 operand *left, *right, *result;
4443 /* note here that && operations that are in an if statement are
4444 taken away by backPatchLabels only those used in arthmetic
4445 operations remain */
4446 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4447 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4448 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4450 /* if both are bit variables */
4451 if (AOP_TYPE (left) == AOP_CRY &&
4452 AOP_TYPE (right) == AOP_CRY)
4454 wassertl (0, "Tried to and two bits");
4458 tlbl = newiTempLabel (NULL);
4460 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
4462 emitLabel (tlbl->key + 100);
4466 freeAsmop (left, NULL, ic);
4467 freeAsmop (right, NULL, ic);
4468 freeAsmop (result, NULL, ic);
4471 /*-----------------------------------------------------------------*/
4472 /* genOrOp - for || operation */
4473 /*-----------------------------------------------------------------*/
4475 genOrOp (iCode * ic)
4477 operand *left, *right, *result;
4480 /* note here that || operations that are in an
4481 if statement are taken away by backPatchLabels
4482 only those used in arthmetic operations remain */
4483 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4484 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4485 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4487 /* if both are bit variables */
4488 if (AOP_TYPE (left) == AOP_CRY &&
4489 AOP_TYPE (right) == AOP_CRY)
4491 wassertl (0, "Tried to OR two bits");
4495 tlbl = newiTempLabel (NULL);
4497 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4499 emitLabel (tlbl->key + 100);
4503 freeAsmop (left, NULL, ic);
4504 freeAsmop (right, NULL, ic);
4505 freeAsmop (result, NULL, ic);
4508 /*-----------------------------------------------------------------*/
4509 /* isLiteralBit - test if lit == 2^n */
4510 /*-----------------------------------------------------------------*/
4512 isLiteralBit (unsigned long lit)
4514 unsigned long pw[32] =
4515 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
4516 0x100L, 0x200L, 0x400L, 0x800L,
4517 0x1000L, 0x2000L, 0x4000L, 0x8000L,
4518 0x10000L, 0x20000L, 0x40000L, 0x80000L,
4519 0x100000L, 0x200000L, 0x400000L, 0x800000L,
4520 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
4521 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
4524 for (idx = 0; idx < 32; idx++)
4530 /*-----------------------------------------------------------------*/
4531 /* jmpTrueOrFalse - */
4532 /*-----------------------------------------------------------------*/
4534 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
4536 // ugly but optimized by peephole
4539 symbol *nlbl = newiTempLabel (NULL);
4540 emit2 ("jp !tlabel", nlbl->key + 100);
4541 emitLabel (tlbl->key + 100);
4542 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
4543 emitLabel (nlbl->key + 100);
4547 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
4548 emitLabel (tlbl->key + 100);
4553 /*-----------------------------------------------------------------*/
4554 /* genAnd - code for and */
4555 /*-----------------------------------------------------------------*/
4557 genAnd (iCode * ic, iCode * ifx)
4559 operand *left, *right, *result;
4560 int size, offset = 0;
4561 unsigned long lit = 0L;
4564 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4565 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4566 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4568 /* if left is a literal & right is not then exchange them */
4569 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4570 AOP_NEEDSACC (left))
4572 operand *tmp = right;
4577 /* if result = right then exchange them */
4578 if (sameRegs (AOP (result), AOP (right)))
4580 operand *tmp = right;
4585 /* if right is bit then exchange them */
4586 if (AOP_TYPE (right) == AOP_CRY &&
4587 AOP_TYPE (left) != AOP_CRY)
4589 operand *tmp = right;
4593 if (AOP_TYPE (right) == AOP_LIT)
4594 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4596 size = AOP_SIZE (result);
4598 if (AOP_TYPE (left) == AOP_CRY)
4600 wassertl (0, "Tried to perform an AND with a bit as an operand");
4604 // if(val & 0xZZ) - size = 0, ifx != FALSE -
4605 // bit = val & 0xZZ - size = 1, ifx = FALSE -
4606 if ((AOP_TYPE (right) == AOP_LIT) &&
4607 (AOP_TYPE (result) == AOP_CRY) &&
4608 (AOP_TYPE (left) != AOP_CRY))
4610 symbol *tlbl = newiTempLabel (NULL);
4611 int sizel = AOP_SIZE (left);
4614 /* PENDING: Test case for this. */
4619 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
4621 _moveA (aopGet (AOP (left), offset, FALSE));
4622 if (bytelit != 0x0FFL)
4624 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4631 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4635 // bit = left & literal
4639 emit2 ("!tlabeldef", tlbl->key + 100);
4641 // if(left & literal)
4646 jmpTrueOrFalse (ifx, tlbl);
4654 /* if left is same as result */
4655 if (sameRegs (AOP (result), AOP (left)))
4657 for (; size--; offset++)
4659 if (AOP_TYPE (right) == AOP_LIT)
4661 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4666 aopPut (AOP (result), "!zero", offset);
4669 _moveA (aopGet (AOP (left), offset, FALSE));
4671 aopGet (AOP (right), offset, FALSE));
4672 aopPut (AOP (left), "a", offset);
4679 if (AOP_TYPE (left) == AOP_ACC)
4681 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
4685 _moveA (aopGet (AOP (left), offset, FALSE));
4687 aopGet (AOP (right), offset, FALSE));
4688 aopPut (AOP (left), "a", offset);
4695 // left & result in different registers
4696 if (AOP_TYPE (result) == AOP_CRY)
4698 wassertl (0, "Tried to AND where the result is in carry");
4702 for (; (size--); offset++)
4705 // result = left & right
4706 if (AOP_TYPE (right) == AOP_LIT)
4708 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4710 aopPut (AOP (result),
4711 aopGet (AOP (left), offset, FALSE),
4715 else if (bytelit == 0)
4717 aopPut (AOP (result), "!zero", offset);
4721 // faster than result <- left, anl result,right
4722 // and better if result is SFR
4723 if (AOP_TYPE (left) == AOP_ACC)
4724 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4727 _moveA (aopGet (AOP (left), offset, FALSE));
4729 aopGet (AOP (right), offset, FALSE));
4731 aopPut (AOP (result), "a", offset);
4738 freeAsmop (left, NULL, ic);
4739 freeAsmop (right, NULL, ic);
4740 freeAsmop (result, NULL, ic);
4743 /*-----------------------------------------------------------------*/
4744 /* genOr - code for or */
4745 /*-----------------------------------------------------------------*/
4747 genOr (iCode * ic, iCode * ifx)
4749 operand *left, *right, *result;
4750 int size, offset = 0;
4751 unsigned long lit = 0L;
4754 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4755 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4756 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4758 /* if left is a literal & right is not then exchange them */
4759 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4760 AOP_NEEDSACC (left))
4762 operand *tmp = right;
4767 /* if result = right then exchange them */
4768 if (sameRegs (AOP (result), AOP (right)))
4770 operand *tmp = right;
4775 /* if right is bit then exchange them */
4776 if (AOP_TYPE (right) == AOP_CRY &&
4777 AOP_TYPE (left) != AOP_CRY)
4779 operand *tmp = right;
4783 if (AOP_TYPE (right) == AOP_LIT)
4784 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4786 size = AOP_SIZE (result);
4788 if (AOP_TYPE (left) == AOP_CRY)
4790 wassertl (0, "Tried to OR where left is a bit");
4794 // if(val | 0xZZ) - size = 0, ifx != FALSE -
4795 // bit = val | 0xZZ - size = 1, ifx = FALSE -
4796 if ((AOP_TYPE (right) == AOP_LIT) &&
4797 (AOP_TYPE (result) == AOP_CRY) &&
4798 (AOP_TYPE (left) != AOP_CRY))
4800 symbol *tlbl = newiTempLabel (NULL);
4801 int sizel = AOP_SIZE (left);
4805 wassertl (0, "Result is assigned to a bit");
4807 /* PENDING: Modeled after the AND code which is inefficent. */
4810 bytelit = (lit >> (offset * 8)) & 0x0FFL;
4812 _moveA (aopGet (AOP (left), offset, FALSE));
4813 /* OR with any literal is the same as OR with itself. */
4815 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4821 jmpTrueOrFalse (ifx, tlbl);
4826 /* if left is same as result */
4827 if (sameRegs (AOP (result), AOP (left)))
4829 for (; size--; offset++)
4831 if (AOP_TYPE (right) == AOP_LIT)
4833 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4837 _moveA (aopGet (AOP (left), offset, FALSE));
4839 aopGet (AOP (right), offset, FALSE));
4840 aopPut (AOP (result), "a", offset);
4845 if (AOP_TYPE (left) == AOP_ACC)
4846 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4849 _moveA (aopGet (AOP (left), offset, FALSE));
4851 aopGet (AOP (right), offset, FALSE));
4852 aopPut (AOP (result), "a", offset);
4859 // left & result in different registers
4860 if (AOP_TYPE (result) == AOP_CRY)
4862 wassertl (0, "Result of OR is in a bit");
4865 for (; (size--); offset++)
4868 // result = left & right
4869 if (AOP_TYPE (right) == AOP_LIT)
4871 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4873 aopPut (AOP (result),
4874 aopGet (AOP (left), offset, FALSE),
4879 // faster than result <- left, anl result,right
4880 // and better if result is SFR
4881 if (AOP_TYPE (left) == AOP_ACC)
4882 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4885 _moveA (aopGet (AOP (left), offset, FALSE));
4887 aopGet (AOP (right), offset, FALSE));
4889 aopPut (AOP (result), "a", offset);
4890 /* PENDING: something weird is going on here. Add exception. */
4891 if (AOP_TYPE (result) == AOP_ACC)
4897 freeAsmop (left, NULL, ic);
4898 freeAsmop (right, NULL, ic);
4899 freeAsmop (result, NULL, ic);
4902 /*-----------------------------------------------------------------*/
4903 /* genXor - code for xclusive or */
4904 /*-----------------------------------------------------------------*/
4906 genXor (iCode * ic, iCode * ifx)
4908 operand *left, *right, *result;
4909 int size, offset = 0;
4910 unsigned long lit = 0L;
4912 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4913 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4914 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4916 /* if left is a literal & right is not then exchange them */
4917 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4918 AOP_NEEDSACC (left))
4920 operand *tmp = right;
4925 /* if result = right then exchange them */
4926 if (sameRegs (AOP (result), AOP (right)))
4928 operand *tmp = right;
4933 /* if right is bit then exchange them */
4934 if (AOP_TYPE (right) == AOP_CRY &&
4935 AOP_TYPE (left) != AOP_CRY)
4937 operand *tmp = right;
4941 if (AOP_TYPE (right) == AOP_LIT)
4942 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4944 size = AOP_SIZE (result);
4946 if (AOP_TYPE (left) == AOP_CRY)
4948 wassertl (0, "Tried to XOR a bit");
4952 // if(val & 0xZZ) - size = 0, ifx != FALSE -
4953 // bit = val & 0xZZ - size = 1, ifx = FALSE -
4954 if ((AOP_TYPE (right) == AOP_LIT) &&
4955 (AOP_TYPE (result) == AOP_CRY) &&
4956 (AOP_TYPE (left) != AOP_CRY))
4958 symbol *tlbl = newiTempLabel (NULL);
4959 int sizel = AOP_SIZE (left);
4963 /* PENDING: Test case for this. */
4964 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
4968 _moveA (aopGet (AOP (left), offset, FALSE));
4969 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4970 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4975 jmpTrueOrFalse (ifx, tlbl);
4979 wassertl (0, "Result of XOR was destined for a bit");
4984 /* if left is same as result */
4985 if (sameRegs (AOP (result), AOP (left)))
4987 for (; size--; offset++)
4989 if (AOP_TYPE (right) == AOP_LIT)
4991 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4995 _moveA (aopGet (AOP (right), offset, FALSE));
4997 aopGet (AOP (left), offset, FALSE));
4998 aopPut (AOP (result), "a", offset);
5003 if (AOP_TYPE (left) == AOP_ACC)
5005 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5009 _moveA (aopGet (AOP (right), offset, FALSE));
5011 aopGet (AOP (left), offset, FALSE));
5012 aopPut (AOP (result), "a", 0);
5019 // left & result in different registers
5020 if (AOP_TYPE (result) == AOP_CRY)
5022 wassertl (0, "Result of XOR is in a bit");
5025 for (; (size--); offset++)
5028 // result = left & right
5029 if (AOP_TYPE (right) == AOP_LIT)
5031 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5033 aopPut (AOP (result),
5034 aopGet (AOP (left), offset, FALSE),
5039 // faster than result <- left, anl result,right
5040 // and better if result is SFR
5041 if (AOP_TYPE (left) == AOP_ACC)
5043 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5047 _moveA (aopGet (AOP (right), offset, FALSE));
5049 aopGet (AOP (left), offset, FALSE));
5051 aopPut (AOP (result), "a", offset);
5056 freeAsmop (left, NULL, ic);
5057 freeAsmop (right, NULL, ic);
5058 freeAsmop (result, NULL, ic);
5061 /*-----------------------------------------------------------------*/
5062 /* genInline - write the inline code out */
5063 /*-----------------------------------------------------------------*/
5065 genInline (iCode * ic)
5067 char *buffer, *bp, *bp1;
5069 _G.lines.isInline += (!options.asmpeep);
5071 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5072 strcpy (buffer, IC_INLINE (ic));
5074 /* emit each line as a code */
5099 _G.lines.isInline -= (!options.asmpeep);
5103 /*-----------------------------------------------------------------*/
5104 /* genRRC - rotate right with carry */
5105 /*-----------------------------------------------------------------*/
5112 /*-----------------------------------------------------------------*/
5113 /* genRLC - generate code for rotate left with carry */
5114 /*-----------------------------------------------------------------*/
5121 /*-----------------------------------------------------------------*/
5122 /* genGetHbit - generates code get highest order bit */
5123 /*-----------------------------------------------------------------*/
5125 genGetHbit (iCode * ic)
5127 operand *left, *result;
5128 left = IC_LEFT (ic);
5129 result = IC_RESULT (ic);
5130 aopOp (left, ic, FALSE, FALSE);
5131 aopOp (result, ic, FALSE, FALSE);
5133 /* get the highest order byte into a */
5134 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5136 if (AOP_TYPE (result) == AOP_CRY)
5144 /* PENDING: For re-target. */
5150 freeAsmop (left, NULL, ic);
5151 freeAsmop (result, NULL, ic);
5155 emitRsh2 (asmop *aop, int size, int is_signed)
5161 const char *l = aopGet (aop, size, FALSE);
5164 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5174 /*-----------------------------------------------------------------*/
5175 /* shiftR2Left2Result - shift right two bytes from left to result */
5176 /*-----------------------------------------------------------------*/
5178 shiftR2Left2Result (operand * left, int offl,
5179 operand * result, int offr,
5180 int shCount, int is_signed)
5183 symbol *tlbl, *tlbl1;
5185 movLeft2Result (left, offl, result, offr, 0);
5186 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5188 /* if (AOP(result)->type == AOP_REG) { */
5190 tlbl = newiTempLabel (NULL);
5191 tlbl1 = newiTempLabel (NULL);
5193 /* Left is already in result - so now do the shift */
5198 emitRsh2 (AOP (result), size, is_signed);
5203 emit2 ("ld a,!immedbyte+1", shCount);
5204 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5205 emitLabel (tlbl->key + 100);
5207 emitRsh2 (AOP (result), size, is_signed);
5209 emitLabel (tlbl1->key + 100);
5211 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5215 /*-----------------------------------------------------------------*/
5216 /* shiftL2Left2Result - shift left two bytes from left to result */
5217 /*-----------------------------------------------------------------*/
5219 shiftL2Left2Result (operand * left, int offl,
5220 operand * result, int offr, int shCount)
5222 if (sameRegs (AOP (result), AOP (left)) &&
5223 ((offl + MSB16) == offr))
5229 /* Copy left into result */
5230 movLeft2Result (left, offl, result, offr, 0);
5231 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5233 /* PENDING: for now just see if it'll work. */
5234 /*if (AOP(result)->type == AOP_REG) { */
5238 symbol *tlbl, *tlbl1;
5241 tlbl = newiTempLabel (NULL);
5242 tlbl1 = newiTempLabel (NULL);
5244 /* Left is already in result - so now do the shift */
5247 emit2 ("ld a,!immedbyte+1", shCount);
5248 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5249 emitLabel (tlbl->key + 100);
5254 l = aopGet (AOP (result), offset, FALSE);
5258 emit2 ("sla %s", l);
5269 emitLabel (tlbl1->key + 100);
5271 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5276 /*-----------------------------------------------------------------*/
5277 /* AccRol - rotate left accumulator by known count */
5278 /*-----------------------------------------------------------------*/
5280 AccRol (int shCount)
5282 shCount &= 0x0007; // shCount : 0..7
5321 /*-----------------------------------------------------------------*/
5322 /* AccLsh - left shift accumulator by known count */
5323 /*-----------------------------------------------------------------*/
5325 AccLsh (int shCount)
5327 static const unsigned char SLMask[] =
5329 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5338 else if (shCount == 2)
5345 /* rotate left accumulator */
5347 /* and kill the lower order bits */
5348 emit2 ("and a,!immedbyte", SLMask[shCount]);
5353 /*-----------------------------------------------------------------*/
5354 /* shiftL1Left2Result - shift left one byte from left to result */
5355 /*-----------------------------------------------------------------*/
5357 shiftL1Left2Result (operand * left, int offl,
5358 operand * result, int offr, int shCount)
5361 l = aopGet (AOP (left), offl, FALSE);
5363 /* shift left accumulator */
5365 aopPut (AOP (result), "a", offr);
5369 /*-----------------------------------------------------------------*/
5370 /* genlshTwo - left shift two bytes by known amount != 0 */
5371 /*-----------------------------------------------------------------*/
5373 genlshTwo (operand * result, operand * left, int shCount)
5375 int size = AOP_SIZE (result);
5377 wassert (size == 2);
5379 /* if shCount >= 8 */
5387 movLeft2Result (left, LSB, result, MSB16, 0);
5388 aopPut (AOP (result), "!zero", 0);
5389 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
5393 movLeft2Result (left, LSB, result, MSB16, 0);
5394 aopPut (AOP (result), "!zero", 0);
5399 aopPut (AOP (result), "!zero", LSB);
5402 /* 1 <= shCount <= 7 */
5411 shiftL2Left2Result (left, LSB, result, LSB, shCount);
5416 /*-----------------------------------------------------------------*/
5417 /* genlshOne - left shift a one byte quantity by known count */
5418 /*-----------------------------------------------------------------*/
5420 genlshOne (operand * result, operand * left, int shCount)
5422 shiftL1Left2Result (left, LSB, result, LSB, shCount);
5425 /*-----------------------------------------------------------------*/
5426 /* genLeftShiftLiteral - left shifting by known count */
5427 /*-----------------------------------------------------------------*/
5429 genLeftShiftLiteral (operand * left,
5434 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5437 freeAsmop (right, NULL, ic);
5439 aopOp (left, ic, FALSE, FALSE);
5440 aopOp (result, ic, FALSE, FALSE);
5442 size = getSize (operandType (result));
5444 /* I suppose that the left size >= result size */
5450 else if (shCount >= (size * 8))
5454 aopPut (AOP (result), "!zero", size);
5462 genlshOne (result, left, shCount);
5465 genlshTwo (result, left, shCount);
5468 wassertl (0, "Shifting of longs is currently unsupported");
5474 freeAsmop (left, NULL, ic);
5475 freeAsmop (result, NULL, ic);
5478 /*-----------------------------------------------------------------*/
5479 /* genLeftShift - generates code for left shifting */
5480 /*-----------------------------------------------------------------*/
5482 genLeftShift (iCode * ic)
5486 symbol *tlbl, *tlbl1;
5487 operand *left, *right, *result;
5489 right = IC_RIGHT (ic);
5490 left = IC_LEFT (ic);
5491 result = IC_RESULT (ic);
5493 aopOp (right, ic, FALSE, FALSE);
5495 /* if the shift count is known then do it
5496 as efficiently as possible */
5497 if (AOP_TYPE (right) == AOP_LIT)
5499 genLeftShiftLiteral (left, right, result, ic);
5503 /* shift count is unknown then we have to form a loop get the loop
5504 count in B : Note: we take only the lower order byte since
5505 shifting more that 32 bits make no sense anyway, ( the largest
5506 size of an object can be only 32 bits ) */
5507 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5509 freeAsmop (right, NULL, ic);
5510 aopOp (left, ic, FALSE, FALSE);
5511 aopOp (result, ic, FALSE, FALSE);
5513 /* now move the left to the result if they are not the
5516 if (!sameRegs (AOP (left), AOP (result)))
5519 size = AOP_SIZE (result);
5523 l = aopGet (AOP (left), offset, FALSE);
5524 aopPut (AOP (result), l, offset);
5529 tlbl = newiTempLabel (NULL);
5530 size = AOP_SIZE (result);
5532 tlbl1 = newiTempLabel (NULL);
5534 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5535 emitLabel (tlbl->key + 100);
5536 l = aopGet (AOP (result), offset, FALSE);
5540 l = aopGet (AOP (result), offset, FALSE);
5544 emit2 ("sla %s", l);
5552 emitLabel (tlbl1->key + 100);
5554 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5556 freeAsmop (left, NULL, ic);
5557 freeAsmop (result, NULL, ic);
5560 /*-----------------------------------------------------------------*/
5561 /* genrshOne - left shift two bytes by known amount != 0 */
5562 /*-----------------------------------------------------------------*/
5564 genrshOne (operand * result, operand * left, int shCount, int is_signed)
5567 int size = AOP_SIZE (result);
5570 wassert (size == 1);
5571 wassert (shCount < 8);
5573 l = aopGet (AOP (left), 0, FALSE);
5575 if (AOP (result)->type == AOP_REG)
5577 aopPut (AOP (result), l, 0);
5578 l = aopGet (AOP (result), 0, FALSE);
5581 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5589 emit2 ("%s a", is_signed ? "sra" : "srl");
5591 aopPut (AOP (result), "a", 0);
5595 /*-----------------------------------------------------------------*/
5596 /* AccRsh - right shift accumulator by known count */
5597 /*-----------------------------------------------------------------*/
5599 AccRsh (int shCount)
5601 static const unsigned char SRMask[] =
5603 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
5608 /* rotate right accumulator */
5609 AccRol (8 - shCount);
5610 /* and kill the higher order bits */
5611 emit2 ("and a,!immedbyte", SRMask[shCount]);
5615 /*-----------------------------------------------------------------*/
5616 /* shiftR1Left2Result - shift right one byte from left to result */
5617 /*-----------------------------------------------------------------*/
5619 shiftR1Left2Result (operand * left, int offl,
5620 operand * result, int offr,
5621 int shCount, int sign)
5623 _moveA (aopGet (AOP (left), offl, FALSE));
5628 emit2 ("%s a", sign ? "sra" : "srl");
5635 aopPut (AOP (result), "a", offr);
5638 /*-----------------------------------------------------------------*/
5639 /* genrshTwo - right shift two bytes by known amount != 0 */
5640 /*-----------------------------------------------------------------*/
5642 genrshTwo (operand * result, operand * left,
5643 int shCount, int sign)
5645 /* if shCount >= 8 */
5651 shiftR1Left2Result (left, MSB16, result, LSB,
5656 movLeft2Result (left, MSB16, result, LSB, sign);
5660 /* Sign extend the result */
5661 _moveA(aopGet (AOP (result), 0, FALSE));
5665 aopPut (AOP (result), ACC_NAME, MSB16);
5669 aopPut (AOP (result), "!zero", 1);
5672 /* 1 <= shCount <= 7 */
5675 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
5679 /*-----------------------------------------------------------------*/
5680 /* genRightShiftLiteral - left shifting by known count */
5681 /*-----------------------------------------------------------------*/
5683 genRightShiftLiteral (operand * left,
5689 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5692 freeAsmop (right, NULL, ic);
5694 aopOp (left, ic, FALSE, FALSE);
5695 aopOp (result, ic, FALSE, FALSE);
5697 size = getSize (operandType (result));
5699 /* I suppose that the left size >= result size */
5705 else if (shCount >= (size * 8))
5707 aopPut (AOP (result), "!zero", size);
5713 genrshOne (result, left, shCount, sign);
5716 genrshTwo (result, left, shCount, sign);
5719 wassertl (0, "Asked to shift right a long which should be a function call");
5722 wassertl (0, "Entered default case in right shift delegate");
5725 freeAsmop (left, NULL, ic);
5726 freeAsmop (result, NULL, ic);
5729 /*-----------------------------------------------------------------*/
5730 /* genRightShift - generate code for right shifting */
5731 /*-----------------------------------------------------------------*/
5733 genRightShift (iCode * ic)
5735 operand *right, *left, *result;
5737 int size, offset, first = 1;
5741 symbol *tlbl, *tlbl1;
5743 /* if signed then we do it the hard way preserve the
5744 sign bit moving it inwards */
5745 retype = getSpec (operandType (IC_RESULT (ic)));
5747 is_signed = !SPEC_USIGN (retype);
5749 /* signed & unsigned types are treated the same : i.e. the
5750 signed is NOT propagated inwards : quoting from the
5751 ANSI - standard : "for E1 >> E2, is equivalent to division
5752 by 2**E2 if unsigned or if it has a non-negative value,
5753 otherwise the result is implementation defined ", MY definition
5754 is that the sign does not get propagated */
5756 right = IC_RIGHT (ic);
5757 left = IC_LEFT (ic);
5758 result = IC_RESULT (ic);
5760 aopOp (right, ic, FALSE, FALSE);
5762 /* if the shift count is known then do it
5763 as efficiently as possible */
5764 if (AOP_TYPE (right) == AOP_LIT)
5766 genRightShiftLiteral (left, right, result, ic, is_signed);
5770 aopOp (left, ic, FALSE, FALSE);
5771 aopOp (result, ic, FALSE, FALSE);
5773 /* now move the left to the result if they are not the
5775 if (!sameRegs (AOP (left), AOP (result)) &&
5776 AOP_SIZE (result) > 1)
5779 size = AOP_SIZE (result);
5783 l = aopGet (AOP (left), offset, FALSE);
5784 aopPut (AOP (result), l, offset);
5789 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5791 freeAsmop (right, NULL, ic);
5793 tlbl = newiTempLabel (NULL);
5794 tlbl1 = newiTempLabel (NULL);
5795 size = AOP_SIZE (result);
5798 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5799 emitLabel (tlbl->key + 100);
5802 l = aopGet (AOP (result), offset--, FALSE);
5805 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5813 emitLabel (tlbl1->key + 100);
5815 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5817 freeAsmop (left, NULL, ic);
5818 freeAsmop (result, NULL, ic);
5821 /*-----------------------------------------------------------------*/
5822 /* genGenPointerGet - get value from generic pointer space */
5823 /*-----------------------------------------------------------------*/
5825 genGenPointerGet (operand * left,
5826 operand * result, iCode * ic)
5829 sym_link *retype = getSpec (operandType (result));
5835 aopOp (left, ic, FALSE, FALSE);
5836 aopOp (result, ic, FALSE, FALSE);
5838 size = AOP_SIZE (result);
5840 if (isPair (AOP (left)) && size == 1)
5843 if (isPtrPair (AOP (left)))
5845 tsprintf (buffer, "!*pair", getPairName (AOP (left)));
5846 aopPut (AOP (result), buffer, 0);
5850 emit2 ("ld a,!*pair", getPairName (AOP (left)));
5851 aopPut (AOP (result), "a", 0);
5853 freeAsmop (left, NULL, ic);
5857 if ( getPairId( AOP (left)) == PAIR_IY)
5864 tsprintf (at, "!*iyx", offset);
5865 aopPut (AOP (result), at, offset);
5871 /* For now we always load into IY */
5872 /* if this is remateriazable */
5873 fetchPair (pair, AOP (left));
5875 freeAsmop (left, NULL, ic);
5877 /* if bit then unpack */
5878 if (IS_BITVAR (retype))
5882 else if ( getPairId( AOP (result)) == PAIR_HL)
5884 wassertl (size == 2, "HL must be of size 2");
5885 emit2 ("ld a,!*hl");
5887 emit2 ("ld h,!*hl");
5892 size = AOP_SIZE (result);
5897 /* PENDING: make this better */
5898 if (!IS_GB && AOP (result)->type == AOP_REG)
5900 aopPut (AOP (result), "!*hl", offset++);
5904 emit2 ("ld a,!*pair", _pairs[pair].name);
5905 aopPut (AOP (result), "a", offset++);
5909 emit2 ("inc %s", _pairs[pair].name);
5910 _G.pairs[pair].offset++;
5916 freeAsmop (result, NULL, ic);
5919 /*-----------------------------------------------------------------*/
5920 /* genPointerGet - generate code for pointer get */
5921 /*-----------------------------------------------------------------*/
5923 genPointerGet (iCode * ic)
5925 operand *left, *result;
5926 sym_link *type, *etype;
5928 left = IC_LEFT (ic);
5929 result = IC_RESULT (ic);
5931 /* depending on the type of pointer we need to
5932 move it to the correct pointer register */
5933 type = operandType (left);
5934 etype = getSpec (type);
5936 genGenPointerGet (left, result, ic);
5940 isRegOrLit (asmop * aop)
5942 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
5947 /*-----------------------------------------------------------------*/
5948 /* genGenPointerSet - stores the value into a pointer location */
5949 /*-----------------------------------------------------------------*/
5951 genGenPointerSet (operand * right,
5952 operand * result, iCode * ic)
5955 sym_link *retype = getSpec (operandType (right));
5956 PAIR_ID pairId = PAIR_HL;
5958 aopOp (result, ic, FALSE, FALSE);
5959 aopOp (right, ic, FALSE, FALSE);
5964 size = AOP_SIZE (right);
5966 /* Handle the exceptions first */
5967 if (isPair (AOP (result)) && size == 1)
5970 const char *l = aopGet (AOP (right), 0, FALSE);
5971 const char *pair = getPairName (AOP (result));
5972 if (canAssignToPtr (l) && isPtr (pair))
5974 emit2 ("ld !*pair,%s", pair, l);
5979 emit2 ("ld !*pair,a", pair);
5984 if ( getPairId( AOP (result)) == PAIR_IY)
5987 const char *l = aopGet (AOP (right), 0, FALSE);
5992 if (canAssignToPtr (l))
5994 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
5998 _moveA (aopGet (AOP (right), offset, FALSE));
5999 emit2 ("ld !*iyx,a", offset);
6006 /* if the operand is already in dptr
6007 then we do nothing else we move the value to dptr */
6008 if (AOP_TYPE (result) != AOP_STR)
6010 fetchPair (pairId, AOP (result));
6012 /* so hl know contains the address */
6013 freeAsmop (result, NULL, ic);
6015 /* if bit then unpack */
6016 if (IS_BITVAR (retype))
6026 const char *l = aopGet (AOP (right), offset, FALSE);
6027 if (isRegOrLit (AOP (right)) && !IS_GB)
6029 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
6034 emit2 ("ld !*pair,a", _pairs[pairId].name);
6038 emit2 ("inc %s", _pairs[pairId].name);
6039 _G.pairs[pairId].offset++;
6045 freeAsmop (right, NULL, ic);
6048 /*-----------------------------------------------------------------*/
6049 /* genPointerSet - stores the value into a pointer location */
6050 /*-----------------------------------------------------------------*/
6052 genPointerSet (iCode * ic)
6054 operand *right, *result;
6055 sym_link *type, *etype;
6057 right = IC_RIGHT (ic);
6058 result = IC_RESULT (ic);
6060 /* depending on the type of pointer we need to
6061 move it to the correct pointer register */
6062 type = operandType (result);
6063 etype = getSpec (type);
6065 genGenPointerSet (right, result, ic);
6068 /*-----------------------------------------------------------------*/
6069 /* genIfx - generate code for Ifx statement */
6070 /*-----------------------------------------------------------------*/
6072 genIfx (iCode * ic, iCode * popIc)
6074 operand *cond = IC_COND (ic);
6077 aopOp (cond, ic, FALSE, TRUE);
6079 /* get the value into acc */
6080 if (AOP_TYPE (cond) != AOP_CRY)
6084 /* the result is now in the accumulator */
6085 freeAsmop (cond, NULL, ic);
6087 /* if there was something to be popped then do it */
6091 /* if the condition is a bit variable */
6092 if (isbit && IS_ITEMP (cond) &&
6094 genIfxJump (ic, SPIL_LOC (cond)->rname);
6095 else if (isbit && !IS_ITEMP (cond))
6096 genIfxJump (ic, OP_SYMBOL (cond)->rname);
6098 genIfxJump (ic, "a");
6103 /*-----------------------------------------------------------------*/
6104 /* genAddrOf - generates code for address of */
6105 /*-----------------------------------------------------------------*/
6107 genAddrOf (iCode * ic)
6109 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
6111 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6113 /* if the operand is on the stack then we
6114 need to get the stack offset of this
6121 if (sym->stack <= 0)
6123 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
6127 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6129 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6133 emit2 ("ld de,!hashedstr", sym->rname);
6134 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
6142 /* if it has an offset then we need to compute it */
6144 emit2 ("ld hl,#%d+%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset, _G.stack.param_offset);
6146 emit2 ("ld hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
6147 emit2 ("add hl,sp");
6151 emit2 ("ld hl,#%s", sym->rname);
6153 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6155 freeAsmop (IC_RESULT (ic), NULL, ic);
6158 /*-----------------------------------------------------------------*/
6159 /* genAssign - generate code for assignment */
6160 /*-----------------------------------------------------------------*/
6162 genAssign (iCode * ic)
6164 operand *result, *right;
6166 unsigned long lit = 0L;
6168 result = IC_RESULT (ic);
6169 right = IC_RIGHT (ic);
6171 /* Dont bother assigning if they are the same */
6172 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6174 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
6178 aopOp (right, ic, FALSE, FALSE);
6179 aopOp (result, ic, TRUE, FALSE);
6181 /* if they are the same registers */
6182 if (sameRegs (AOP (right), AOP (result)))
6184 emitDebug ("; (registers are the same)");
6188 /* if the result is a bit */
6189 if (AOP_TYPE (result) == AOP_CRY)
6191 wassertl (0, "Tried to assign to a bit");
6195 size = AOP_SIZE (result);
6198 if (AOP_TYPE (right) == AOP_LIT)
6200 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6203 if (isPair (AOP (result)))
6205 fetchPair (getPairId (AOP (result)), AOP (right));
6207 else if ((size > 1) &&
6208 (AOP_TYPE (result) != AOP_REG) &&
6209 (AOP_TYPE (right) == AOP_LIT) &&
6210 !IS_FLOAT (operandType (right)) &&
6213 bool fXored = FALSE;
6215 /* Work from the top down.
6216 Done this way so that we can use the cached copy of 0
6217 in A for a fast clear */
6220 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
6222 if (!fXored && size > 1)
6229 aopPut (AOP (result), "a", offset);
6233 aopPut (AOP (result), "!zero", offset);
6237 aopPut (AOP (result),
6238 aopGet (AOP (right), offset, FALSE),
6243 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
6245 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
6246 aopPut (AOP (result), "l", LSB);
6247 aopPut (AOP (result), "h", MSB16);
6249 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6251 /* Special case. Load into a and d, then load out. */
6252 _moveA (aopGet (AOP (right), 0, FALSE));
6253 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
6254 aopPut (AOP (result), "a", 0);
6255 aopPut (AOP (result), "e", 1);
6257 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6259 /* Special case - simple memcpy */
6260 aopGet (AOP (right), LSB, FALSE);
6263 aopGet (AOP (result), LSB, FALSE);
6267 emit2 ("ld a,(de)");
6268 /* Peephole will optimise this. */
6269 emit2 ("ld (hl),a");
6277 spillPair (PAIR_HL);
6283 /* PENDING: do this check better */
6284 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
6286 _moveA (aopGet (AOP (right), offset, FALSE));
6287 aopPut (AOP (result), "a", offset);
6290 aopPut (AOP (result),
6291 aopGet (AOP (right), offset, FALSE),
6298 freeAsmop (right, NULL, ic);
6299 freeAsmop (result, NULL, ic);
6302 /*-----------------------------------------------------------------*/
6303 /* genJumpTab - genrates code for jump table */
6304 /*-----------------------------------------------------------------*/
6306 genJumpTab (iCode * ic)
6311 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
6312 /* get the condition into accumulator */
6313 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
6316 emit2 ("ld e,%s", l);
6317 emit2 ("ld d,!zero");
6318 jtab = newiTempLabel (NULL);
6320 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
6321 emit2 ("add hl,de");
6322 emit2 ("add hl,de");
6323 emit2 ("add hl,de");
6324 freeAsmop (IC_JTCOND (ic), NULL, ic);
6328 emitLabel (jtab->key + 100);
6329 /* now generate the jump labels */
6330 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
6331 jtab = setNextItem (IC_JTLABELS (ic)))
6332 emit2 ("jp !tlabel", jtab->key + 100);
6335 /*-----------------------------------------------------------------*/
6336 /* genCast - gen code for casting */
6337 /*-----------------------------------------------------------------*/
6339 genCast (iCode * ic)
6341 operand *result = IC_RESULT (ic);
6342 sym_link *ctype = operandType (IC_LEFT (ic));
6343 operand *right = IC_RIGHT (ic);
6346 /* if they are equivalent then do nothing */
6347 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6350 aopOp (right, ic, FALSE, FALSE);
6351 aopOp (result, ic, FALSE, FALSE);
6353 /* if the result is a bit */
6354 if (AOP_TYPE (result) == AOP_CRY)
6356 wassertl (0, "Tried to cast to a bit");
6359 /* if they are the same size : or less */
6360 if (AOP_SIZE (result) <= AOP_SIZE (right))
6363 /* if they are in the same place */
6364 if (sameRegs (AOP (right), AOP (result)))
6367 /* if they in different places then copy */
6368 size = AOP_SIZE (result);
6372 aopPut (AOP (result),
6373 aopGet (AOP (right), offset, FALSE),
6380 /* So we now know that the size of destination is greater
6381 than the size of the source */
6382 /* we move to result for the size of source */
6383 size = AOP_SIZE (right);
6387 aopPut (AOP (result),
6388 aopGet (AOP (right), offset, FALSE),
6393 /* now depending on the sign of the destination */
6394 size = AOP_SIZE (result) - AOP_SIZE (right);
6395 /* Unsigned or not an integral type - right fill with zeros */
6396 if (SPEC_USIGN (ctype) || !IS_SPEC (ctype))
6399 aopPut (AOP (result), "!zero", offset++);
6403 /* we need to extend the sign :{ */
6404 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
6410 aopPut (AOP (result), "a", offset++);
6414 freeAsmop (right, NULL, ic);
6415 freeAsmop (result, NULL, ic);
6418 /*-----------------------------------------------------------------*/
6419 /* genReceive - generate code for a receive iCode */
6420 /*-----------------------------------------------------------------*/
6422 genReceive (iCode * ic)
6424 if (isOperandInFarSpace (IC_RESULT (ic)) &&
6425 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
6426 IS_TRUE_SYMOP (IC_RESULT (ic))))
6436 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6437 size = AOP_SIZE(IC_RESULT(ic));
6439 for (i = 0; i < size; i++) {
6440 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
6444 freeAsmop (IC_RESULT (ic), NULL, ic);
6449 /** Maximum number of bytes to emit per line. */
6453 /** Context for the byte output chunker. */
6456 unsigned char buffer[DBEMIT_MAX_RUN];
6461 /** Flushes a byte chunker by writing out all in the buffer and
6465 _dbFlush(DBEMITCTX *self)
6472 sprintf(line, ".db 0x%02X", self->buffer[0]);
6474 for (i = 1; i < self->pos; i++)
6476 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
6483 /** Write out another byte, buffering until a decent line is
6487 _dbEmit(DBEMITCTX *self, int c)
6489 if (self->pos == DBEMIT_MAX_RUN)
6493 self->buffer[self->pos++] = c;
6496 /** Context for a simple run length encoder. */
6500 unsigned char buffer[128];
6502 /** runLen may be equivalent to pos. */
6508 RLE_CHANGE_COST = 4,
6512 /** Flush the buffer of a run length encoder by writing out the run or
6513 data that it currently contains.
6516 _rleCommit(RLECTX *self)
6522 memset(&db, 0, sizeof(db));
6524 emit2(".db %u", self->pos);
6526 for (i = 0; i < self->pos; i++)
6528 _dbEmit(&db, self->buffer[i]);
6537 Can get either a run or a block of random stuff.
6538 Only want to change state if a good run comes in or a run ends.
6539 Detecting run end is easy.
6542 Say initial state is in run, len zero, last zero. Then if you get a
6543 few zeros then something else then a short run will be output.
6544 Seems OK. While in run mode, keep counting. While in random mode,
6545 keep a count of the run. If run hits margin, output all up to run,
6546 restart, enter run mode.
6549 /** Add another byte into the run length encoder, flushing as
6550 required. The run length encoder uses the Amiga IFF style, where
6551 a block is prefixed by its run length. A positive length means
6552 the next n bytes pass straight through. A negative length means
6553 that the next byte is repeated -n times. A zero terminates the
6557 _rleAppend(RLECTX *self, int c)
6561 if (c != self->last)
6563 /* The run has stopped. See if it is worthwhile writing it out
6564 as a run. Note that the random data comes in as runs of
6567 if (self->runLen > RLE_CHANGE_COST)
6569 /* Yes, worthwhile. */
6570 /* Commit whatever was in the buffer. */
6572 emit2(".db -%u,0x%02X", self->runLen, self->last);
6576 /* Not worthwhile. Append to the end of the random list. */
6577 for (i = 0; i < self->runLen; i++)
6579 if (self->pos >= RLE_MAX_BLOCK)
6584 self->buffer[self->pos++] = self->last;
6592 if (self->runLen >= RLE_MAX_BLOCK)
6594 /* Commit whatever was in the buffer. */
6597 emit2 (".db -%u,0x%02X", self->runLen, self->last);
6605 _rleFlush(RLECTX *self)
6607 _rleAppend(self, -1);
6614 /** genArrayInit - Special code for initialising an array with constant
6618 genArrayInit (iCode * ic)
6622 int elementSize = 0, eIndex, i;
6623 unsigned val, lastVal;
6627 memset(&rle, 0, sizeof(rle));
6629 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
6631 _saveRegsForCall(ic, 0);
6633 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
6634 emit2 ("call __initrleblock");
6636 type = operandType(IC_LEFT(ic));
6638 if (type && type->next)
6640 elementSize = getSize(type->next);
6644 wassertl (0, "Can't determine element size in genArrayInit.");
6647 iLoop = IC_ARRAYILIST(ic);
6648 lastVal = (unsigned)-1;
6650 /* Feed all the bytes into the run length encoder which will handle
6652 This works well for mixed char data, and for random int and long
6661 for (i = 0; i < ix; i++)
6663 for (eIndex = 0; eIndex < elementSize; eIndex++)
6665 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
6666 _rleAppend(&rle, val);
6671 iLoop = iLoop->next;
6675 /* Mark the end of the run. */
6678 _restoreRegsAfterCall();
6682 freeAsmop (IC_LEFT(ic), NULL, ic);
6686 _swap (PAIR_ID one, PAIR_ID two)
6688 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
6694 emit2 ("ld a,%s", _pairs[one].l);
6695 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
6696 emit2 ("ld %s,a", _pairs[two].l);
6697 emit2 ("ld a,%s", _pairs[one].h);
6698 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
6699 emit2 ("ld %s,a", _pairs[two].h);
6703 /* The problem is that we may have all three pairs used and they may
6704 be needed in a different order.
6709 hl = hl => unity, fine
6713 hl = hl hl = hl, swap de <=> bc
6721 hl = bc de = de, swap bc <=> hl
6729 hl = de bc = bc, swap hl <=> de
6734 * Any pair = pair are done last
6735 * Any pair = iTemp are done last
6736 * Any swaps can be done any time
6744 So how do we detect the cases?
6745 How about a 3x3 matrix?
6749 x x x x (Fourth for iTemp/other)
6751 First determin which mode to use by counting the number of unity and
6754 Two - Assign the pair first, then the rest
6755 One - Swap the two, then the rest
6759 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
6761 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
6763 PAIR_BC, PAIR_HL, PAIR_DE
6765 int i, j, nunity = 0;
6766 memset (ids, PAIR_INVALID, sizeof (ids));
6769 wassert (nparams == 3);
6771 /* First save everything that needs to be saved. */
6772 _saveRegsForCall (ic, 0);
6774 /* Loading HL first means that DE is always fine. */
6775 for (i = 0; i < nparams; i++)
6777 aopOp (pparams[i], ic, FALSE, FALSE);
6778 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
6781 /* Count the number of unity or iTemp assigns. */
6782 for (i = 0; i < 3; i++)
6784 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
6792 /* Any order, fall through. */
6794 else if (nunity == 2)
6796 /* One is assigned. Pull it out and assign. */
6797 for (i = 0; i < 3; i++)
6799 for (j = 0; j < NUM_PAIRS; j++)
6801 if (ids[dest[i]][j] == TRUE)
6803 /* Found it. See if it's the right one. */
6804 if (j == PAIR_INVALID || j == dest[i])
6810 fetchPair(dest[i], AOP (pparams[i]));
6817 else if (nunity == 1)
6819 /* Find the pairs to swap. */
6820 for (i = 0; i < 3; i++)
6822 for (j = 0; j < NUM_PAIRS; j++)
6824 if (ids[dest[i]][j] == TRUE)
6826 if (j == PAIR_INVALID || j == dest[i])
6841 int next = getPairId (AOP (pparams[0]));
6842 emit2 ("push %s", _pairs[next].name);
6844 if (next == dest[1])
6846 fetchPair (dest[1], AOP (pparams[1]));
6847 fetchPair (dest[2], AOP (pparams[2]));
6851 fetchPair (dest[2], AOP (pparams[2]));
6852 fetchPair (dest[1], AOP (pparams[1]));
6854 emit2 ("pop %s", _pairs[dest[0]].name);
6857 /* Finally pull out all of the iTemps */
6858 for (i = 0; i < 3; i++)
6860 if (ids[dest[i]][PAIR_INVALID] == 1)
6862 fetchPair (dest[i], AOP (pparams[i]));
6868 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
6874 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
6878 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
6880 setupForBuiltin3 (ic, nParams, pparams);
6882 label = newiTempLabel(NULL);
6884 emitLabel (label->key);
6885 emit2 ("ld a,(hl)");
6888 emit2 ("!shortjp nz,!tlabel ; 1", label->key);
6890 freeAsmop (from, NULL, ic->next);
6891 freeAsmop (to, NULL, ic);
6895 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
6897 operand *from, *to, *count;
6902 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
6907 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
6909 setupForBuiltin3 (ic, nParams, pparams);
6913 freeAsmop (count, NULL, ic->next->next);
6914 freeAsmop (from, NULL, ic);
6916 _restoreRegsAfterCall();
6918 /* if we need assign a result value */
6919 if ((IS_ITEMP (IC_RESULT (ic)) &&
6920 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
6921 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
6922 IS_TRUE_SYMOP (IC_RESULT (ic)))
6924 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6925 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
6926 freeAsmop (IC_RESULT (ic), NULL, ic);
6929 freeAsmop (to, NULL, ic->next);
6932 /*-----------------------------------------------------------------*/
6933 /* genBuiltIn - calls the appropriate function to generating code */
6934 /* for a built in function */
6935 /*-----------------------------------------------------------------*/
6936 static void genBuiltIn (iCode *ic)
6938 operand *bi_parms[MAX_BUILTIN_ARGS];
6943 /* get all the arguments for a built in function */
6944 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
6946 /* which function is it */
6947 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
6949 if (strcmp(bif->name,"__builtin_strcpy")==0)
6951 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
6953 else if (strcmp(bif->name,"__builtin_memcpy")==0)
6955 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
6959 wassertl (0, "Unknown builtin function encountered");
6963 /*-----------------------------------------------------------------*/
6964 /* genZ80Code - generate code for Z80 based controllers */
6965 /*-----------------------------------------------------------------*/
6967 genZ80Code (iCode * lic)
6975 _fReturn = _gbz80_return;
6976 _fTmp = _gbz80_return;
6980 _fReturn = _z80_return;
6981 _fTmp = _z80_return;
6984 _G.lines.head = _G.lines.current = NULL;
6986 for (ic = lic; ic; ic = ic->next)
6989 if (cln != ic->lineno)
6991 emit2 ("; %s %d", ic->filename, ic->lineno);
6994 /* if the result is marked as
6995 spilt and rematerializable or code for
6996 this has already been generated then
6998 if (resultRemat (ic) || ic->generated)
7001 /* depending on the operation */
7005 emitDebug ("; genNot");
7010 emitDebug ("; genCpl");
7015 emitDebug ("; genUminus");
7020 emitDebug ("; genIpush");
7025 /* IPOP happens only when trying to restore a
7026 spilt live range, if there is an ifx statement
7027 following this pop then the if statement might
7028 be using some of the registers being popped which
7029 would destory the contents of the register so
7030 we need to check for this condition and handle it */
7032 ic->next->op == IFX &&
7033 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
7035 emitDebug ("; genIfx");
7036 genIfx (ic->next, ic);
7040 emitDebug ("; genIpop");
7046 emitDebug ("; genCall");
7051 emitDebug ("; genPcall");
7056 emitDebug ("; genFunction");
7061 emitDebug ("; genEndFunction");
7062 genEndFunction (ic);
7066 emitDebug ("; genRet");
7071 emitDebug ("; genLabel");
7076 emitDebug ("; genGoto");
7081 emitDebug ("; genPlus");
7086 emitDebug ("; genMinus");
7091 emitDebug ("; genMult");
7096 emitDebug ("; genDiv");
7101 emitDebug ("; genMod");
7106 emitDebug ("; genCmpGt");
7107 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
7111 emitDebug ("; genCmpLt");
7112 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
7119 /* note these two are xlated by algebraic equivalence
7120 during parsing SDCC.y */
7121 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
7122 "got '>=' or '<=' shouldn't have come here");
7126 emitDebug ("; genCmpEq");
7127 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
7131 emitDebug ("; genAndOp");
7136 emitDebug ("; genOrOp");
7141 emitDebug ("; genXor");
7142 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
7146 emitDebug ("; genOr");
7147 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
7151 emitDebug ("; genAnd");
7152 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
7156 emitDebug ("; genInline");
7161 emitDebug ("; genRRC");
7166 emitDebug ("; genRLC");
7171 emitDebug ("; genGetHBIT");
7176 emitDebug ("; genLeftShift");
7181 emitDebug ("; genRightShift");
7185 case GET_VALUE_AT_ADDRESS:
7186 emitDebug ("; genPointerGet");
7192 if (POINTER_SET (ic))
7194 emitDebug ("; genAssign (pointer)");
7199 emitDebug ("; genAssign");
7205 emitDebug ("; genIfx");
7210 emitDebug ("; genAddrOf");
7215 emitDebug ("; genJumpTab");
7220 emitDebug ("; genCast");
7225 emitDebug ("; genReceive");
7230 if (ic->builtinSEND)
7232 emitDebug ("; genBuiltIn");
7237 emitDebug ("; addSet");
7238 addSet (&_G.sendSet, ic);
7243 emitDebug ("; genArrayInit");
7253 /* now we are ready to call the
7254 peep hole optimizer */
7255 if (!options.nopeep)
7256 peepHole (&_G.lines.head);
7258 /* This is unfortunate */
7259 /* now do the actual printing */
7261 FILE *fp = codeOutFile;
7262 if (isInHome () && codeOutFile == code->oFile)
7263 codeOutFile = home->oFile;
7264 printLine (_G.lines.head, codeOutFile);
7265 if (_G.flushStatics)
7268 _G.flushStatics = 0;
7273 freeTrace(&_G.lines.trace);
7274 freeTrace(&_G.trace.aops);
7280 _isPairUsed (iCode * ic, PAIR_ID pairId)
7286 if (bitVectBitValue (ic->rMask, D_IDX))
7288 if (bitVectBitValue (ic->rMask, E_IDX))
7298 fetchLitSpecial (asmop * aop, bool negate, bool xor)
7301 value *val = aop->aopu.aop_lit;
7303 wassert (aop->type == AOP_LIT);
7304 wassert (!IS_FLOAT (val->type));
7306 v = (unsigned long) floatFromVal (val);
7314 tsprintf (buffer, "!immedword", v);
7315 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));