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 bitVect *rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
2440 /* if caller saves & we have not saved then */
2446 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2448 /* if send set is not empty then assign */
2453 int nSend = elementsInSet(_G.sendSet);
2454 bool swapped = FALSE;
2456 int _z80_sendOrder[] = {
2461 /* Check if the parameters are swapped. If so route through hl instead. */
2462 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2464 sic = setFirstItem(_G.sendSet);
2465 sic = setNextItem(_G.sendSet);
2467 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2468 /* The second send value is loaded from one the one that holds the first
2469 send, i.e. it is overwritten. */
2470 /* Cache the first in HL, and load the second from HL instead. */
2471 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2472 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2478 for (sic = setFirstItem (_G.sendSet); sic;
2479 sic = setNextItem (_G.sendSet))
2482 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2484 size = AOP_SIZE (IC_LEFT (sic));
2485 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2486 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2488 // PENDING: Mild hack
2489 if (swapped == TRUE && send == 1) {
2491 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2494 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2496 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2499 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2503 freeAsmop (IC_LEFT (sic), NULL, sic);
2510 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2512 werror (W_INDIR_BANKED);
2514 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2516 if (isLitWord (AOP (IC_LEFT (ic))))
2518 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2522 symbol *rlbl = newiTempLabel (NULL);
2523 spillPair (PAIR_HL);
2524 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2526 _G.stack.pushed += 2;
2528 fetchHL (AOP (IC_LEFT (ic)));
2530 emit2 ("!tlabeldef", (rlbl->key + 100));
2531 _G.stack.pushed -= 2;
2533 freeAsmop (IC_LEFT (ic), NULL, ic);
2537 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2538 OP_SYMBOL (IC_LEFT (ic))->rname :
2539 OP_SYMBOL (IC_LEFT (ic))->name;
2540 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2542 emit2 ("call banked_call");
2543 emit2 ("!dws", name);
2544 emit2 ("!dw !bankimmeds", name);
2549 emit2 ("call %s", name);
2554 /* Mark the regsiters as restored. */
2555 _G.saves.saved = FALSE;
2557 /* if we need assign a result value */
2558 if ((IS_ITEMP (IC_RESULT (ic)) &&
2559 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2560 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2561 IS_TRUE_SYMOP (IC_RESULT (ic)))
2564 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2566 assignResultValue (IC_RESULT (ic));
2568 freeAsmop (IC_RESULT (ic), NULL, ic);
2571 /* adjust the stack for parameters if required */
2574 int i = ic->parmBytes;
2576 _G.stack.pushed -= i;
2579 emit2 ("!ldaspsp", i);
2586 emit2 ("ld hl,#%d", i);
2587 emit2 ("add hl,sp");
2605 if (_G.stack.pushedDE)
2607 bool dInUse = bitVectBitValue(rInUse, D_IDX);
2608 bool eInUse = bitVectBitValue(rInUse, E_IDX);
2610 if (dInUse && eInUse)
2626 wassertl (0, "Neither D or E were in use but it was pushed.");
2628 _G.stack.pushedDE = FALSE;
2631 if (_G.stack.pushedBC)
2633 bool bInUse = bitVectBitValue(rInUse, B_IDX);
2634 bool cInUse = bitVectBitValue(rInUse, C_IDX);
2636 // If both B and C are used in the return value, then we won't get
2638 if (bInUse && cInUse)
2654 wassertl (0, "Neither B or C were in use but it was pushed.");
2656 _G.stack.pushedBC = FALSE;
2660 /*-----------------------------------------------------------------*/
2661 /* genCall - generates a call statement */
2662 /*-----------------------------------------------------------------*/
2664 genCall (iCode * ic)
2666 emitCall (ic, FALSE);
2669 /*-----------------------------------------------------------------*/
2670 /* genPcall - generates a call by pointer statement */
2671 /*-----------------------------------------------------------------*/
2673 genPcall (iCode * ic)
2675 emitCall (ic, TRUE);
2678 /*-----------------------------------------------------------------*/
2679 /* resultRemat - result is rematerializable */
2680 /*-----------------------------------------------------------------*/
2682 resultRemat (iCode * ic)
2684 if (SKIP_IC (ic) || ic->op == IFX)
2687 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2689 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2690 if (sym->remat && !POINTER_SET (ic))
2697 extern set *publics;
2699 /*-----------------------------------------------------------------*/
2700 /* genFunction - generated code for function entry */
2701 /*-----------------------------------------------------------------*/
2703 genFunction (iCode * ic)
2705 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2709 bool bcInUse = FALSE;
2710 bool deInUse = FALSE;
2713 setArea (IFFUNC_NONBANKED (sym->type));
2715 /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
2718 _G.receiveOffset = 0;
2720 /* Record the last function name for debugging. */
2721 _G.lastFunctionName = sym->rname;
2723 /* Create the function header */
2724 emit2 ("!functionheader", sym->name);
2725 /* PENDING: portability. */
2726 emit2 ("__%s_start:", sym->rname);
2727 emit2 ("!functionlabeldef", sym->rname);
2729 if (options.profile)
2731 emit2 ("!profileenter");
2734 ftype = operandType (IC_LEFT (ic));
2736 /* if critical function then turn interrupts off */
2737 if (IFFUNC_ISCRITICAL (ftype))
2740 /* if this is an interrupt service routine then save all potentially used registers. */
2741 if (IFFUNC_ISISR (sym->type))
2746 /* PENDING: callee-save etc */
2748 _G.stack.param_offset = 0;
2751 /* Detect which registers are used. */
2755 for (i = 0; i < sym->regsUsed->size; i++)
2757 if (bitVectBitValue (sym->regsUsed, i))
2771 /* Other systems use DE as a temporary. */
2782 _G.stack.param_offset += 2;
2785 _G.stack.pushedBC = bcInUse;
2790 _G.stack.param_offset += 2;
2793 _G.stack.pushedDE = deInUse;
2796 /* adjust the stack for the function */
2797 _G.stack.last = sym->stack;
2799 if (sym->stack && IS_GB && sym->stack > -INT8MIN)
2800 emit2 ("!enterxl", sym->stack);
2801 else if (sym->stack)
2802 emit2 ("!enterx", sym->stack);
2805 _G.stack.offset = sym->stack;
2808 /*-----------------------------------------------------------------*/
2809 /* genEndFunction - generates epilogue for functions */
2810 /*-----------------------------------------------------------------*/
2812 genEndFunction (iCode * ic)
2814 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2816 if (IFFUNC_ISISR (sym->type))
2818 wassertl (0, "Tried to close an interrupt support function");
2822 if (IFFUNC_ISCRITICAL (sym->type))
2825 /* PENDING: calleeSave */
2827 if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
2829 emit2 ("!leavexl", _G.stack.offset);
2831 else if (_G.stack.offset)
2833 emit2 ("!leavex", _G.stack.offset);
2841 if (_G.stack.pushedDE)
2844 _G.stack.pushedDE = FALSE;
2847 if (_G.stack.pushedDE)
2850 _G.stack.pushedDE = FALSE;
2854 if (options.profile)
2856 emit2 ("!profileexit");
2860 /* Both baned and non-banked just ret */
2863 /* PENDING: portability. */
2864 emit2 ("__%s_end:", sym->rname);
2866 _G.flushStatics = 1;
2867 _G.stack.pushed = 0;
2868 _G.stack.offset = 0;
2871 /*-----------------------------------------------------------------*/
2872 /* genRet - generate code for return statement */
2873 /*-----------------------------------------------------------------*/
2878 /* Errk. This is a hack until I can figure out how
2879 to cause dehl to spill on a call */
2880 int size, offset = 0;
2882 /* if we have no return value then
2883 just generate the "ret" */
2887 /* we have something to return then
2888 move the return value into place */
2889 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2890 size = AOP_SIZE (IC_LEFT (ic));
2892 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
2896 emit2 ("ld de,%s", l);
2900 emit2 ("ld hl,%s", l);
2905 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
2907 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
2908 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
2914 l = aopGet (AOP (IC_LEFT (ic)), offset,
2916 if (strcmp (_fReturn[offset], l))
2917 emit2 ("ld %s,%s", _fReturn[offset++], l);
2921 freeAsmop (IC_LEFT (ic), NULL, ic);
2924 /* generate a jump to the return label
2925 if the next is not the return statement */
2926 if (!(ic->next && ic->next->op == LABEL &&
2927 IC_LABEL (ic->next) == returnLabel))
2929 emit2 ("jp !tlabel", returnLabel->key + 100);
2932 /*-----------------------------------------------------------------*/
2933 /* genLabel - generates a label */
2934 /*-----------------------------------------------------------------*/
2936 genLabel (iCode * ic)
2938 /* special case never generate */
2939 if (IC_LABEL (ic) == entryLabel)
2942 emitLabel (IC_LABEL (ic)->key + 100);
2945 /*-----------------------------------------------------------------*/
2946 /* genGoto - generates a ljmp */
2947 /*-----------------------------------------------------------------*/
2949 genGoto (iCode * ic)
2951 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
2954 /*-----------------------------------------------------------------*/
2955 /* genPlusIncr :- does addition with increment if possible */
2956 /*-----------------------------------------------------------------*/
2958 genPlusIncr (iCode * ic)
2960 unsigned int icount;
2961 unsigned int size = getDataSize (IC_RESULT (ic));
2962 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
2964 /* will try to generate an increment */
2965 /* if the right side is not a literal
2967 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
2970 emitDebug ("; genPlusIncr");
2972 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
2974 /* If result is a pair */
2975 if (resultId != PAIR_INVALID)
2977 if (isLitWord (AOP (IC_LEFT (ic))))
2979 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
2982 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
2984 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
2986 PAIR_ID freep = getFreePairId (ic);
2987 if (freep != PAIR_INVALID)
2989 fetchPair (freep, AOP (IC_RIGHT (ic)));
2990 emit2 ("add hl,%s", _pairs[freep].name);
2996 fetchPair (resultId, AOP (IC_RIGHT (ic)));
2997 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3004 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3008 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3012 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3017 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3019 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3020 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3024 /* if the literal value of the right hand side
3025 is greater than 4 then it is not worth it */
3029 /* if increment 16 bits in register */
3030 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3036 symbol *tlbl = NULL;
3037 tlbl = newiTempLabel (NULL);
3040 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3043 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3046 emitLabel (tlbl->key + 100);
3050 /* if the sizes are greater than 1 then we cannot */
3051 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3052 AOP_SIZE (IC_LEFT (ic)) > 1)
3055 /* If the result is in a register then we can load then increment.
3057 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3059 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3062 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3067 /* we can if the aops of the left & result match or
3068 if they are in registers and the registers are the
3070 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3074 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3082 /*-----------------------------------------------------------------*/
3083 /* outBitAcc - output a bit in acc */
3084 /*-----------------------------------------------------------------*/
3086 outBitAcc (operand * result)
3088 symbol *tlbl = newiTempLabel (NULL);
3089 /* if the result is a bit */
3090 if (AOP_TYPE (result) == AOP_CRY)
3092 wassertl (0, "Tried to write A into a bit");
3096 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3097 emit2 ("ld a,!one");
3098 emitLabel (tlbl->key + 100);
3104 couldDestroyCarry (asmop *aop)
3108 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3117 shiftIntoPair (int idx, asmop *aop)
3119 PAIR_ID id = PAIR_INVALID;
3121 wassertl (IS_Z80, "Only implemented for the Z80");
3122 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3134 wassertl (0, "Internal error - hit default case");
3137 emitDebug ("; Shift into pair idx %u", idx);
3141 setupPair (PAIR_HL, aop, 0);
3145 setupPair (PAIR_IY, aop, 0);
3147 emit2 ("pop %s", _pairs[id].name);
3150 aop->type = AOP_PAIRPTR;
3151 aop->aopu.aop_pairId = id;
3152 _G.pairs[id].offset = 0;
3153 _G.pairs[id].last_type = aop->type;
3157 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
3159 wassert (left && right);
3163 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3165 shiftIntoPair (0, right);
3166 shiftIntoPair (1, result);
3168 else if (couldDestroyCarry (right))
3170 shiftIntoPair (0, right);
3172 else if (couldDestroyCarry (result))
3174 shiftIntoPair (0, result);
3183 /*-----------------------------------------------------------------*/
3184 /* genPlus - generates code for addition */
3185 /*-----------------------------------------------------------------*/
3187 genPlus (iCode * ic)
3189 int size, offset = 0;
3191 /* special cases :- */
3193 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3194 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3195 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3197 /* Swap the left and right operands if:
3199 if literal, literal on the right or
3200 if left requires ACC or right is already
3203 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3204 (AOP_NEEDSACC (IC_LEFT (ic))) ||
3205 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3207 operand *t = IC_RIGHT (ic);
3208 IC_RIGHT (ic) = IC_LEFT (ic);
3212 /* if both left & right are in bit
3214 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3215 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3218 wassertl (0, "Tried to add two bits");
3221 /* if left in bit space & right literal */
3222 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3223 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3225 /* Can happen I guess */
3226 wassertl (0, "Tried to add a bit to a literal");
3229 /* if I can do an increment instead
3230 of add then GOOD for ME */
3231 if (genPlusIncr (ic) == TRUE)
3234 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3236 size = getDataSize (IC_RESULT (ic));
3238 /* Special case when left and right are constant */
3239 if (isPair (AOP (IC_RESULT (ic))))
3242 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3243 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3245 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3251 sprintf (buffer, "#(%s + %s)", left, right);
3252 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3257 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3259 /* Fetch into HL then do the add */
3260 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3261 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3263 spillPair (PAIR_HL);
3265 if (left == PAIR_HL && right != PAIR_INVALID)
3267 emit2 ("add hl,%s", _pairs[right].name);
3270 else if (right == PAIR_HL && left != PAIR_INVALID)
3272 emit2 ("add hl,%s", _pairs[left].name);
3275 else if (right != PAIR_INVALID && right != PAIR_HL)
3277 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3278 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3281 else if (left != PAIR_INVALID && left != PAIR_HL)
3283 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3284 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3293 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3295 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3296 emit2 ("add hl,%s ; 2", getPairName (AOP (IC_RIGHT (ic))));
3298 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3303 ld hl,sp+n trashes C so we cant afford to do it during an
3304 add with stack based varibles. Worst case is:
3317 So you cant afford to load up hl if either left, right, or result
3318 is on the stack (*sigh*) The alt is:
3326 Combinations in here are:
3327 * If left or right are in bc then the loss is small - trap later
3328 * If the result is in bc then the loss is also small
3332 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3333 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3334 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3336 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3337 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3338 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3339 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3341 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3343 /* Swap left and right */
3344 operand *t = IC_RIGHT (ic);
3345 IC_RIGHT (ic) = IC_LEFT (ic);
3348 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3350 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3351 emit2 ("add hl,bc");
3355 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3356 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3357 emit2 ("add hl,de");
3359 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3365 /* Be paranoid on the GB with 4 byte variables due to how C
3366 can be trashed by lda hl,n(sp).
3368 _gbz80_emitAddSubLong (ic, TRUE);
3373 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3377 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3379 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3382 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3385 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3389 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3392 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3395 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3397 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3401 freeAsmop (IC_LEFT (ic), NULL, ic);
3402 freeAsmop (IC_RIGHT (ic), NULL, ic);
3403 freeAsmop (IC_RESULT (ic), NULL, ic);
3407 /*-----------------------------------------------------------------*/
3408 /* genMinusDec :- does subtraction with deccrement if possible */
3409 /*-----------------------------------------------------------------*/
3411 genMinusDec (iCode * ic)
3413 unsigned int icount;
3414 unsigned int size = getDataSize (IC_RESULT (ic));
3416 /* will try to generate an increment */
3417 /* if the right side is not a literal we cannot */
3418 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3421 /* if the literal value of the right hand side
3422 is greater than 4 then it is not worth it */
3423 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3426 size = getDataSize (IC_RESULT (ic));
3428 /* if decrement 16 bits in register */
3429 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3430 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3433 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3437 /* If result is a pair */
3438 if (isPair (AOP (IC_RESULT (ic))))
3440 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3442 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3446 /* if increment 16 bits in register */
3447 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3451 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3454 emit2 ("dec %s", _getTempPairName());
3457 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3463 /* if the sizes are greater than 1 then we cannot */
3464 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3465 AOP_SIZE (IC_LEFT (ic)) > 1)
3468 /* we can if the aops of the left & result match or if they are in
3469 registers and the registers are the same */
3470 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3473 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3480 /*-----------------------------------------------------------------*/
3481 /* genMinus - generates code for subtraction */
3482 /*-----------------------------------------------------------------*/
3484 genMinus (iCode * ic)
3486 int size, offset = 0;
3487 unsigned long lit = 0L;
3489 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3490 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3491 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3493 /* special cases :- */
3494 /* if both left & right are in bit space */
3495 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3496 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3498 wassertl (0, "Tried to subtract two bits");
3502 /* if I can do an decrement instead of subtract then GOOD for ME */
3503 if (genMinusDec (ic) == TRUE)
3506 size = getDataSize (IC_RESULT (ic));
3508 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3513 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3517 /* Same logic as genPlus */
3520 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3521 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3522 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3524 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3525 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3526 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3527 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3529 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3530 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3532 if (left == PAIR_INVALID && right == PAIR_INVALID)
3537 else if (right == PAIR_INVALID)
3539 else if (left == PAIR_INVALID)
3542 fetchPair (left, AOP (IC_LEFT (ic)));
3543 /* Order is important. Right may be HL */
3544 fetchPair (right, AOP (IC_RIGHT (ic)));
3546 emit2 ("ld a,%s", _pairs[left].l);
3547 emit2 ("sub a,%s", _pairs[right].l);
3549 emit2 ("ld a,%s", _pairs[left].h);
3550 emit2 ("sbc a,%s", _pairs[right].h);
3552 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
3554 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3556 aopPut (AOP (IC_RESULT (ic)), "e", 0);
3562 /* Be paranoid on the GB with 4 byte variables due to how C
3563 can be trashed by lda hl,n(sp).
3565 _gbz80_emitAddSubLong (ic, FALSE);
3570 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3572 /* if literal, add a,#-lit, else normal subb */
3575 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3576 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3580 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3583 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3587 /* first add without previous c */
3589 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
3591 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3593 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3596 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3597 AOP_SIZE (IC_LEFT (ic)) == 3 &&
3598 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3600 wassertl (0, "Tried to subtract on a long pointer");
3604 freeAsmop (IC_LEFT (ic), NULL, ic);
3605 freeAsmop (IC_RIGHT (ic), NULL, ic);
3606 freeAsmop (IC_RESULT (ic), NULL, ic);
3609 /*-----------------------------------------------------------------*/
3610 /* genMult - generates code for multiplication */
3611 /*-----------------------------------------------------------------*/
3613 genMult (iCode * ic)
3617 /* If true then the final operation should be a subtract */
3618 bool active = FALSE;
3620 /* Shouldn't occur - all done through function calls */
3621 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3622 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3623 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3625 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
3626 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
3627 AOP_SIZE (IC_RESULT (ic)) > 2)
3629 wassertl (0, "Multiplication is handled through support function calls");
3632 /* Swap left and right such that right is a literal */
3633 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
3635 operand *t = IC_RIGHT (ic);
3636 IC_RIGHT (ic) = IC_LEFT (ic);
3640 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
3642 val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
3643 // wassertl (val > 0, "Multiply must be positive");
3644 wassertl (val != 1, "Can't multiply by 1");
3650 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
3652 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
3660 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3665 /* Fully unroled version of mul.s. Not the most efficient.
3667 for (count = 0; count < 16; count++)
3669 if (count != 0 && active)
3671 emit2 ("add hl,hl");
3675 if (active == FALSE)
3682 emit2 ("add hl,de");
3696 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3698 freeAsmop (IC_LEFT (ic), NULL, ic);
3699 freeAsmop (IC_RIGHT (ic), NULL, ic);
3700 freeAsmop (IC_RESULT (ic), NULL, ic);
3703 /*-----------------------------------------------------------------*/
3704 /* genDiv - generates code for division */
3705 /*-----------------------------------------------------------------*/
3709 /* Shouldn't occur - all done through function calls */
3710 wassertl (0, "Division is handled through support function calls");
3713 /*-----------------------------------------------------------------*/
3714 /* genMod - generates code for division */
3715 /*-----------------------------------------------------------------*/
3719 /* Shouldn't occur - all done through function calls */
3723 /*-----------------------------------------------------------------*/
3724 /* genIfxJump :- will create a jump depending on the ifx */
3725 /*-----------------------------------------------------------------*/
3727 genIfxJump (iCode * ic, char *jval)
3732 /* if true label then we jump if condition
3736 jlbl = IC_TRUE (ic);
3737 if (!strcmp (jval, "a"))
3741 else if (!strcmp (jval, "c"))
3745 else if (!strcmp (jval, "nc"))
3749 else if (!strcmp (jval, "m"))
3753 else if (!strcmp (jval, "p"))
3759 /* The buffer contains the bit on A that we should test */
3765 /* false label is present */
3766 jlbl = IC_FALSE (ic);
3767 if (!strcmp (jval, "a"))
3771 else if (!strcmp (jval, "c"))
3775 else if (!strcmp (jval, "nc"))
3779 else if (!strcmp (jval, "m"))
3783 else if (!strcmp (jval, "p"))
3789 /* The buffer contains the bit on A that we should test */
3793 /* Z80 can do a conditional long jump */
3794 if (!strcmp (jval, "a"))
3798 else if (!strcmp (jval, "c"))
3801 else if (!strcmp (jval, "nc"))
3804 else if (!strcmp (jval, "m"))
3807 else if (!strcmp (jval, "p"))
3812 emit2 ("bit %s,a", jval);
3814 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
3816 /* mark the icode as generated */
3822 _getPairIdName (PAIR_ID id)
3824 return _pairs[id].name;
3829 /* if unsigned char cmp with lit, just compare */
3831 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
3833 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3836 emit2 ("xor a,!immedbyte", 0x80);
3837 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
3840 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3842 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
3844 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
3845 // Pull left into DE and right into HL
3846 aopGet (AOP(left), LSB, FALSE);
3849 aopGet (AOP(right), LSB, FALSE);
3853 if (size == 0 && sign)
3855 // Highest byte when signed needs the bits flipped
3858 emit2 ("ld a,(de)");
3859 emit2 ("xor #0x80");
3861 emit2 ("ld a,(hl)");
3862 emit2 ("xor #0x80");
3866 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
3870 emit2 ("ld a,(de)");
3871 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
3881 spillPair (PAIR_HL);
3883 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
3885 setupPair (PAIR_HL, AOP (left), 0);
3886 aopGet (AOP(right), LSB, FALSE);
3890 if (size == 0 && sign)
3892 // Highest byte when signed needs the bits flipped
3895 emit2 ("ld a,(hl)");
3896 emit2 ("xor #0x80");
3898 emit2 ("ld a,%d(iy)", offset);
3899 emit2 ("xor #0x80");
3903 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
3907 emit2 ("ld a,(hl)");
3908 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
3917 spillPair (PAIR_HL);
3918 spillPair (PAIR_IY);
3922 if (AOP_TYPE (right) == AOP_LIT)
3924 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3925 /* optimize if(x < 0) or if(x >= 0) */
3930 /* No sign so it's always false */
3935 /* Just load in the top most bit */
3936 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
3937 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
3939 genIfxJump (ifx, "7");
3951 /* First setup h and l contaning the top most bytes XORed */
3952 bool fDidXor = FALSE;
3953 if (AOP_TYPE (left) == AOP_LIT)
3955 unsigned long lit = (unsigned long)
3956 floatFromVal (AOP (left)->aopu.aop_lit);
3957 emit2 ("ld %s,!immedbyte", _fTmp[0],
3958 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3962 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
3963 emit2 ("xor a,!immedbyte", 0x80);
3964 emit2 ("ld %s,a", _fTmp[0]);
3967 if (AOP_TYPE (right) == AOP_LIT)
3969 unsigned long lit = (unsigned long)
3970 floatFromVal (AOP (right)->aopu.aop_lit);
3971 emit2 ("ld %s,!immedbyte", _fTmp[1],
3972 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3976 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
3977 emit2 ("xor a,!immedbyte", 0x80);
3978 emit2 ("ld %s,a", _fTmp[1]);
3984 /* Do a long subtract */
3987 _moveA (aopGet (AOP (left), offset, FALSE));
3989 if (sign && size == 0)
3991 emit2 ("ld a,%s", _fTmp[0]);
3992 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
3996 /* Subtract through, propagating the carry */
3997 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4005 /** Generic compare for > or <
4008 genCmp (operand * left, operand * right,
4009 operand * result, iCode * ifx, int sign)
4011 int size, offset = 0;
4012 unsigned long lit = 0L;
4013 bool swap_sense = FALSE;
4015 /* if left & right are bit variables */
4016 if (AOP_TYPE (left) == AOP_CRY &&
4017 AOP_TYPE (right) == AOP_CRY)
4019 /* Cant happen on the Z80 */
4020 wassertl (0, "Tried to compare two bits");
4024 /* Do a long subtract of right from left. */
4025 size = max (AOP_SIZE (left), AOP_SIZE (right));
4027 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4029 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4030 // Pull left into DE and right into HL
4031 aopGet (AOP(left), LSB, FALSE);
4034 aopGet (AOP(right), LSB, FALSE);
4038 emit2 ("ld a,(de)");
4039 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4048 spillPair (PAIR_HL);
4052 if (AOP_TYPE (right) == AOP_LIT)
4054 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4055 /* optimize if(x < 0) or if(x >= 0) */
4060 /* No sign so it's always false */
4065 /* Just load in the top most bit */
4066 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4067 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4069 genIfxJump (ifx, "7");
4080 genIfxJump (ifx, swap_sense ? "c" : "nc");
4091 _moveA (aopGet (AOP (left), offset, FALSE));
4092 /* Subtract through, propagating the carry */
4093 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4099 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4103 /* Shift the sign bit up into carry */
4106 outBitCLong (result, swap_sense);
4110 /* if the result is used in the next
4111 ifx conditional branch then generate
4112 code a little differently */
4120 genIfxJump (ifx, swap_sense ? "nc" : "c");
4124 genIfxJump (ifx, swap_sense ? "p" : "m");
4129 genIfxJump (ifx, swap_sense ? "nc" : "c");
4136 /* Shift the sign bit up into carry */
4139 outBitCLong (result, swap_sense);
4141 /* leave the result in acc */
4145 /*-----------------------------------------------------------------*/
4146 /* genCmpGt :- greater than comparison */
4147 /*-----------------------------------------------------------------*/
4149 genCmpGt (iCode * ic, iCode * ifx)
4151 operand *left, *right, *result;
4152 sym_link *letype, *retype;
4155 left = IC_LEFT (ic);
4156 right = IC_RIGHT (ic);
4157 result = IC_RESULT (ic);
4159 letype = getSpec (operandType (left));
4160 retype = getSpec (operandType (right));
4161 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4162 /* assign the amsops */
4163 aopOp (left, ic, FALSE, FALSE);
4164 aopOp (right, ic, FALSE, FALSE);
4165 aopOp (result, ic, TRUE, FALSE);
4167 genCmp (right, left, result, ifx, sign);
4169 freeAsmop (left, NULL, ic);
4170 freeAsmop (right, NULL, ic);
4171 freeAsmop (result, NULL, ic);
4174 /*-----------------------------------------------------------------*/
4175 /* genCmpLt - less than comparisons */
4176 /*-----------------------------------------------------------------*/
4178 genCmpLt (iCode * ic, iCode * ifx)
4180 operand *left, *right, *result;
4181 sym_link *letype, *retype;
4184 left = IC_LEFT (ic);
4185 right = IC_RIGHT (ic);
4186 result = IC_RESULT (ic);
4188 letype = getSpec (operandType (left));
4189 retype = getSpec (operandType (right));
4190 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4192 /* assign the amsops */
4193 aopOp (left, ic, FALSE, FALSE);
4194 aopOp (right, ic, FALSE, FALSE);
4195 aopOp (result, ic, TRUE, FALSE);
4197 genCmp (left, right, result, ifx, sign);
4199 freeAsmop (left, NULL, ic);
4200 freeAsmop (right, NULL, ic);
4201 freeAsmop (result, NULL, ic);
4204 /*-----------------------------------------------------------------*/
4205 /* gencjneshort - compare and jump if not equal */
4206 /*-----------------------------------------------------------------*/
4208 gencjneshort (operand * left, operand * right, symbol * lbl)
4210 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4212 unsigned long lit = 0L;
4214 /* Swap the left and right if it makes the computation easier */
4215 if (AOP_TYPE (left) == AOP_LIT)
4222 if (AOP_TYPE (right) == AOP_LIT)
4223 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4225 /* if the right side is a literal then anything goes */
4226 if (AOP_TYPE (right) == AOP_LIT &&
4227 AOP_TYPE (left) != AOP_DIR)
4231 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4236 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4243 emit2 ("jp nz,!tlabel", lbl->key + 100);
4249 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4250 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
4253 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
4254 emit2 ("jp nz,!tlabel", lbl->key + 100);
4259 /* if the right side is in a register or in direct space or
4260 if the left is a pointer register & right is not */
4261 else if (AOP_TYPE (right) == AOP_REG ||
4262 AOP_TYPE (right) == AOP_DIR ||
4263 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
4267 _moveA (aopGet (AOP (left), offset, FALSE));
4268 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
4269 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4271 emit2 ("jp nz,!tlabel", lbl->key + 100);
4274 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4275 emit2 ("jp nz,!tlabel", lbl->key + 100);
4282 /* right is a pointer reg need both a & b */
4283 /* PENDING: is this required? */
4286 _moveA (aopGet (AOP (right), offset, FALSE));
4287 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
4288 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
4294 /*-----------------------------------------------------------------*/
4295 /* gencjne - compare and jump if not equal */
4296 /*-----------------------------------------------------------------*/
4298 gencjne (operand * left, operand * right, symbol * lbl)
4300 symbol *tlbl = newiTempLabel (NULL);
4302 gencjneshort (left, right, lbl);
4305 emit2 ("ld a,!one");
4306 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4307 emitLabel (lbl->key + 100);
4309 emitLabel (tlbl->key + 100);
4312 /*-----------------------------------------------------------------*/
4313 /* genCmpEq - generates code for equal to */
4314 /*-----------------------------------------------------------------*/
4316 genCmpEq (iCode * ic, iCode * ifx)
4318 operand *left, *right, *result;
4320 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4321 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4322 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4324 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4326 /* Swap operands if it makes the operation easier. ie if:
4327 1. Left is a literal.
4329 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4331 operand *t = IC_RIGHT (ic);
4332 IC_RIGHT (ic) = IC_LEFT (ic);
4336 if (ifx && !AOP_SIZE (result))
4339 /* if they are both bit variables */
4340 if (AOP_TYPE (left) == AOP_CRY &&
4341 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4343 wassertl (0, "Tried to compare two bits");
4347 tlbl = newiTempLabel (NULL);
4349 gencjneshort (left, right, tlbl);
4353 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4354 emitLabel (tlbl->key + 100);
4358 /* PENDING: do this better */
4359 symbol *lbl = newiTempLabel (NULL);
4361 emit2 ("!shortjp !tlabel", lbl->key + 100);
4362 emitLabel (tlbl->key + 100);
4363 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4364 emitLabel (lbl->key + 100);
4367 /* mark the icode as generated */
4372 /* if they are both bit variables */
4373 if (AOP_TYPE (left) == AOP_CRY &&
4374 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4376 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4382 gencjne (left, right, newiTempLabel (NULL));
4383 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4390 genIfxJump (ifx, "a");
4393 /* if the result is used in an arithmetic operation
4394 then put the result in place */
4395 if (AOP_TYPE (result) != AOP_CRY)
4400 /* leave the result in acc */
4404 freeAsmop (left, NULL, ic);
4405 freeAsmop (right, NULL, ic);
4406 freeAsmop (result, NULL, ic);
4409 /*-----------------------------------------------------------------*/
4410 /* ifxForOp - returns the icode containing the ifx for operand */
4411 /*-----------------------------------------------------------------*/
4413 ifxForOp (operand * op, iCode * ic)
4415 /* if true symbol then needs to be assigned */
4416 if (IS_TRUE_SYMOP (op))
4419 /* if this has register type condition and
4420 the next instruction is ifx with the same operand
4421 and live to of the operand is upto the ifx only then */
4423 ic->next->op == IFX &&
4424 IC_COND (ic->next)->key == op->key &&
4425 OP_SYMBOL (op)->liveTo <= ic->next->seq)
4431 /*-----------------------------------------------------------------*/
4432 /* genAndOp - for && operation */
4433 /*-----------------------------------------------------------------*/
4435 genAndOp (iCode * ic)
4437 operand *left, *right, *result;
4440 /* note here that && operations that are in an if statement are
4441 taken away by backPatchLabels only those used in arthmetic
4442 operations remain */
4443 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4444 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4445 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4447 /* if both are bit variables */
4448 if (AOP_TYPE (left) == AOP_CRY &&
4449 AOP_TYPE (right) == AOP_CRY)
4451 wassertl (0, "Tried to and two bits");
4455 tlbl = newiTempLabel (NULL);
4457 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
4459 emitLabel (tlbl->key + 100);
4463 freeAsmop (left, NULL, ic);
4464 freeAsmop (right, NULL, ic);
4465 freeAsmop (result, NULL, ic);
4468 /*-----------------------------------------------------------------*/
4469 /* genOrOp - for || operation */
4470 /*-----------------------------------------------------------------*/
4472 genOrOp (iCode * ic)
4474 operand *left, *right, *result;
4477 /* note here that || operations that are in an
4478 if statement are taken away by backPatchLabels
4479 only those used in arthmetic operations remain */
4480 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4481 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4482 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4484 /* if both are bit variables */
4485 if (AOP_TYPE (left) == AOP_CRY &&
4486 AOP_TYPE (right) == AOP_CRY)
4488 wassertl (0, "Tried to OR two bits");
4492 tlbl = newiTempLabel (NULL);
4494 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4496 emitLabel (tlbl->key + 100);
4500 freeAsmop (left, NULL, ic);
4501 freeAsmop (right, NULL, ic);
4502 freeAsmop (result, NULL, ic);
4505 /*-----------------------------------------------------------------*/
4506 /* isLiteralBit - test if lit == 2^n */
4507 /*-----------------------------------------------------------------*/
4509 isLiteralBit (unsigned long lit)
4511 unsigned long pw[32] =
4512 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
4513 0x100L, 0x200L, 0x400L, 0x800L,
4514 0x1000L, 0x2000L, 0x4000L, 0x8000L,
4515 0x10000L, 0x20000L, 0x40000L, 0x80000L,
4516 0x100000L, 0x200000L, 0x400000L, 0x800000L,
4517 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
4518 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
4521 for (idx = 0; idx < 32; idx++)
4527 /*-----------------------------------------------------------------*/
4528 /* jmpTrueOrFalse - */
4529 /*-----------------------------------------------------------------*/
4531 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
4533 // ugly but optimized by peephole
4536 symbol *nlbl = newiTempLabel (NULL);
4537 emit2 ("jp !tlabel", nlbl->key + 100);
4538 emitLabel (tlbl->key + 100);
4539 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
4540 emitLabel (nlbl->key + 100);
4544 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
4545 emitLabel (tlbl->key + 100);
4550 /*-----------------------------------------------------------------*/
4551 /* genAnd - code for and */
4552 /*-----------------------------------------------------------------*/
4554 genAnd (iCode * ic, iCode * ifx)
4556 operand *left, *right, *result;
4557 int size, offset = 0;
4558 unsigned long lit = 0L;
4561 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4562 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4563 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4565 /* if left is a literal & right is not then exchange them */
4566 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4567 AOP_NEEDSACC (left))
4569 operand *tmp = right;
4574 /* if result = right then exchange them */
4575 if (sameRegs (AOP (result), AOP (right)))
4577 operand *tmp = right;
4582 /* if right is bit then exchange them */
4583 if (AOP_TYPE (right) == AOP_CRY &&
4584 AOP_TYPE (left) != AOP_CRY)
4586 operand *tmp = right;
4590 if (AOP_TYPE (right) == AOP_LIT)
4591 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4593 size = AOP_SIZE (result);
4595 if (AOP_TYPE (left) == AOP_CRY)
4597 wassertl (0, "Tried to perform an AND with a bit as an operand");
4601 // if(val & 0xZZ) - size = 0, ifx != FALSE -
4602 // bit = val & 0xZZ - size = 1, ifx = FALSE -
4603 if ((AOP_TYPE (right) == AOP_LIT) &&
4604 (AOP_TYPE (result) == AOP_CRY) &&
4605 (AOP_TYPE (left) != AOP_CRY))
4607 symbol *tlbl = newiTempLabel (NULL);
4608 int sizel = AOP_SIZE (left);
4611 /* PENDING: Test case for this. */
4616 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
4618 _moveA (aopGet (AOP (left), offset, FALSE));
4619 if (bytelit != 0x0FFL)
4621 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4628 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4632 // bit = left & literal
4636 emit2 ("!tlabeldef", tlbl->key + 100);
4638 // if(left & literal)
4643 jmpTrueOrFalse (ifx, tlbl);
4651 /* if left is same as result */
4652 if (sameRegs (AOP (result), AOP (left)))
4654 for (; size--; offset++)
4656 if (AOP_TYPE (right) == AOP_LIT)
4658 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4663 aopPut (AOP (result), "!zero", offset);
4666 _moveA (aopGet (AOP (left), offset, FALSE));
4668 aopGet (AOP (right), offset, FALSE));
4669 aopPut (AOP (left), "a", offset);
4676 if (AOP_TYPE (left) == AOP_ACC)
4678 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
4682 _moveA (aopGet (AOP (left), offset, FALSE));
4684 aopGet (AOP (right), offset, FALSE));
4685 aopPut (AOP (left), "a", offset);
4692 // left & result in different registers
4693 if (AOP_TYPE (result) == AOP_CRY)
4695 wassertl (0, "Tried to AND where the result is in carry");
4699 for (; (size--); offset++)
4702 // result = left & right
4703 if (AOP_TYPE (right) == AOP_LIT)
4705 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4707 aopPut (AOP (result),
4708 aopGet (AOP (left), offset, FALSE),
4712 else if (bytelit == 0)
4714 aopPut (AOP (result), "!zero", offset);
4718 // faster than result <- left, anl result,right
4719 // and better if result is SFR
4720 if (AOP_TYPE (left) == AOP_ACC)
4721 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4724 _moveA (aopGet (AOP (left), offset, FALSE));
4726 aopGet (AOP (right), offset, FALSE));
4728 aopPut (AOP (result), "a", offset);
4735 freeAsmop (left, NULL, ic);
4736 freeAsmop (right, NULL, ic);
4737 freeAsmop (result, NULL, ic);
4740 /*-----------------------------------------------------------------*/
4741 /* genOr - code for or */
4742 /*-----------------------------------------------------------------*/
4744 genOr (iCode * ic, iCode * ifx)
4746 operand *left, *right, *result;
4747 int size, offset = 0;
4748 unsigned long lit = 0L;
4751 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4752 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4753 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4755 /* if left is a literal & right is not then exchange them */
4756 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4757 AOP_NEEDSACC (left))
4759 operand *tmp = right;
4764 /* if result = right then exchange them */
4765 if (sameRegs (AOP (result), AOP (right)))
4767 operand *tmp = right;
4772 /* if right is bit then exchange them */
4773 if (AOP_TYPE (right) == AOP_CRY &&
4774 AOP_TYPE (left) != AOP_CRY)
4776 operand *tmp = right;
4780 if (AOP_TYPE (right) == AOP_LIT)
4781 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4783 size = AOP_SIZE (result);
4785 if (AOP_TYPE (left) == AOP_CRY)
4787 wassertl (0, "Tried to OR where left is a bit");
4791 // if(val | 0xZZ) - size = 0, ifx != FALSE -
4792 // bit = val | 0xZZ - size = 1, ifx = FALSE -
4793 if ((AOP_TYPE (right) == AOP_LIT) &&
4794 (AOP_TYPE (result) == AOP_CRY) &&
4795 (AOP_TYPE (left) != AOP_CRY))
4797 symbol *tlbl = newiTempLabel (NULL);
4798 int sizel = AOP_SIZE (left);
4802 wassertl (0, "Result is assigned to a bit");
4804 /* PENDING: Modeled after the AND code which is inefficent. */
4807 bytelit = (lit >> (offset * 8)) & 0x0FFL;
4809 _moveA (aopGet (AOP (left), offset, FALSE));
4810 /* OR with any literal is the same as OR with itself. */
4812 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4818 jmpTrueOrFalse (ifx, tlbl);
4823 /* if left is same as result */
4824 if (sameRegs (AOP (result), AOP (left)))
4826 for (; size--; offset++)
4828 if (AOP_TYPE (right) == AOP_LIT)
4830 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4834 _moveA (aopGet (AOP (left), offset, FALSE));
4836 aopGet (AOP (right), offset, FALSE));
4837 aopPut (AOP (result), "a", offset);
4842 if (AOP_TYPE (left) == AOP_ACC)
4843 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4846 _moveA (aopGet (AOP (left), offset, FALSE));
4848 aopGet (AOP (right), offset, FALSE));
4849 aopPut (AOP (result), "a", offset);
4856 // left & result in different registers
4857 if (AOP_TYPE (result) == AOP_CRY)
4859 wassertl (0, "Result of OR is in a bit");
4862 for (; (size--); offset++)
4865 // result = left & right
4866 if (AOP_TYPE (right) == AOP_LIT)
4868 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4870 aopPut (AOP (result),
4871 aopGet (AOP (left), offset, FALSE),
4876 // faster than result <- left, anl result,right
4877 // and better if result is SFR
4878 if (AOP_TYPE (left) == AOP_ACC)
4879 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4882 _moveA (aopGet (AOP (left), offset, FALSE));
4884 aopGet (AOP (right), offset, FALSE));
4886 aopPut (AOP (result), "a", offset);
4887 /* PENDING: something weird is going on here. Add exception. */
4888 if (AOP_TYPE (result) == AOP_ACC)
4894 freeAsmop (left, NULL, ic);
4895 freeAsmop (right, NULL, ic);
4896 freeAsmop (result, NULL, ic);
4899 /*-----------------------------------------------------------------*/
4900 /* genXor - code for xclusive or */
4901 /*-----------------------------------------------------------------*/
4903 genXor (iCode * ic, iCode * ifx)
4905 operand *left, *right, *result;
4906 int size, offset = 0;
4907 unsigned long lit = 0L;
4909 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4910 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4911 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4913 /* if left is a literal & right is not then exchange them */
4914 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4915 AOP_NEEDSACC (left))
4917 operand *tmp = right;
4922 /* if result = right then exchange them */
4923 if (sameRegs (AOP (result), AOP (right)))
4925 operand *tmp = right;
4930 /* if right is bit then exchange them */
4931 if (AOP_TYPE (right) == AOP_CRY &&
4932 AOP_TYPE (left) != AOP_CRY)
4934 operand *tmp = right;
4938 if (AOP_TYPE (right) == AOP_LIT)
4939 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4941 size = AOP_SIZE (result);
4943 if (AOP_TYPE (left) == AOP_CRY)
4945 wassertl (0, "Tried to XOR a bit");
4949 // if(val & 0xZZ) - size = 0, ifx != FALSE -
4950 // bit = val & 0xZZ - size = 1, ifx = FALSE -
4951 if ((AOP_TYPE (right) == AOP_LIT) &&
4952 (AOP_TYPE (result) == AOP_CRY) &&
4953 (AOP_TYPE (left) != AOP_CRY))
4955 symbol *tlbl = newiTempLabel (NULL);
4956 int sizel = AOP_SIZE (left);
4960 /* PENDING: Test case for this. */
4961 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
4965 _moveA (aopGet (AOP (left), offset, FALSE));
4966 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4967 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4972 jmpTrueOrFalse (ifx, tlbl);
4976 wassertl (0, "Result of XOR was destined for a bit");
4981 /* if left is same as result */
4982 if (sameRegs (AOP (result), AOP (left)))
4984 for (; size--; offset++)
4986 if (AOP_TYPE (right) == AOP_LIT)
4988 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4992 _moveA (aopGet (AOP (right), offset, FALSE));
4994 aopGet (AOP (left), offset, FALSE));
4995 aopPut (AOP (result), "a", offset);
5000 if (AOP_TYPE (left) == AOP_ACC)
5002 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5006 _moveA (aopGet (AOP (right), offset, FALSE));
5008 aopGet (AOP (left), offset, FALSE));
5009 aopPut (AOP (result), "a", 0);
5016 // left & result in different registers
5017 if (AOP_TYPE (result) == AOP_CRY)
5019 wassertl (0, "Result of XOR is in a bit");
5022 for (; (size--); offset++)
5025 // result = left & right
5026 if (AOP_TYPE (right) == AOP_LIT)
5028 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5030 aopPut (AOP (result),
5031 aopGet (AOP (left), offset, FALSE),
5036 // faster than result <- left, anl result,right
5037 // and better if result is SFR
5038 if (AOP_TYPE (left) == AOP_ACC)
5040 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5044 _moveA (aopGet (AOP (right), offset, FALSE));
5046 aopGet (AOP (left), offset, FALSE));
5048 aopPut (AOP (result), "a", offset);
5053 freeAsmop (left, NULL, ic);
5054 freeAsmop (right, NULL, ic);
5055 freeAsmop (result, NULL, ic);
5058 /*-----------------------------------------------------------------*/
5059 /* genInline - write the inline code out */
5060 /*-----------------------------------------------------------------*/
5062 genInline (iCode * ic)
5064 char *buffer, *bp, *bp1;
5066 _G.lines.isInline += (!options.asmpeep);
5068 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5069 strcpy (buffer, IC_INLINE (ic));
5071 /* emit each line as a code */
5096 _G.lines.isInline -= (!options.asmpeep);
5100 /*-----------------------------------------------------------------*/
5101 /* genRRC - rotate right with carry */
5102 /*-----------------------------------------------------------------*/
5109 /*-----------------------------------------------------------------*/
5110 /* genRLC - generate code for rotate left with carry */
5111 /*-----------------------------------------------------------------*/
5118 /*-----------------------------------------------------------------*/
5119 /* genGetHbit - generates code get highest order bit */
5120 /*-----------------------------------------------------------------*/
5122 genGetHbit (iCode * ic)
5124 operand *left, *result;
5125 left = IC_LEFT (ic);
5126 result = IC_RESULT (ic);
5127 aopOp (left, ic, FALSE, FALSE);
5128 aopOp (result, ic, FALSE, FALSE);
5130 /* get the highest order byte into a */
5131 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5133 if (AOP_TYPE (result) == AOP_CRY)
5141 /* PENDING: For re-target. */
5147 freeAsmop (left, NULL, ic);
5148 freeAsmop (result, NULL, ic);
5152 emitRsh2 (asmop *aop, int size, int is_signed)
5158 const char *l = aopGet (aop, size, FALSE);
5161 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5171 /*-----------------------------------------------------------------*/
5172 /* shiftR2Left2Result - shift right two bytes from left to result */
5173 /*-----------------------------------------------------------------*/
5175 shiftR2Left2Result (operand * left, int offl,
5176 operand * result, int offr,
5177 int shCount, int is_signed)
5180 symbol *tlbl, *tlbl1;
5182 movLeft2Result (left, offl, result, offr, 0);
5183 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5185 /* if (AOP(result)->type == AOP_REG) { */
5187 tlbl = newiTempLabel (NULL);
5188 tlbl1 = newiTempLabel (NULL);
5190 /* Left is already in result - so now do the shift */
5195 emitRsh2 (AOP (result), size, is_signed);
5200 emit2 ("ld a,!immedbyte+1", shCount);
5201 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5202 emitLabel (tlbl->key + 100);
5204 emitRsh2 (AOP (result), size, is_signed);
5206 emitLabel (tlbl1->key + 100);
5208 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5212 /*-----------------------------------------------------------------*/
5213 /* shiftL2Left2Result - shift left two bytes from left to result */
5214 /*-----------------------------------------------------------------*/
5216 shiftL2Left2Result (operand * left, int offl,
5217 operand * result, int offr, int shCount)
5219 if (sameRegs (AOP (result), AOP (left)) &&
5220 ((offl + MSB16) == offr))
5226 /* Copy left into result */
5227 movLeft2Result (left, offl, result, offr, 0);
5228 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5230 /* PENDING: for now just see if it'll work. */
5231 /*if (AOP(result)->type == AOP_REG) { */
5235 symbol *tlbl, *tlbl1;
5238 tlbl = newiTempLabel (NULL);
5239 tlbl1 = newiTempLabel (NULL);
5241 /* Left is already in result - so now do the shift */
5244 emit2 ("ld a,!immedbyte+1", shCount);
5245 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5246 emitLabel (tlbl->key + 100);
5251 l = aopGet (AOP (result), offset, FALSE);
5255 emit2 ("sla %s", l);
5266 emitLabel (tlbl1->key + 100);
5268 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5273 /*-----------------------------------------------------------------*/
5274 /* AccRol - rotate left accumulator by known count */
5275 /*-----------------------------------------------------------------*/
5277 AccRol (int shCount)
5279 shCount &= 0x0007; // shCount : 0..7
5318 /*-----------------------------------------------------------------*/
5319 /* AccLsh - left shift accumulator by known count */
5320 /*-----------------------------------------------------------------*/
5322 AccLsh (int shCount)
5324 static const unsigned char SLMask[] =
5326 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5335 else if (shCount == 2)
5342 /* rotate left accumulator */
5344 /* and kill the lower order bits */
5345 emit2 ("and a,!immedbyte", SLMask[shCount]);
5350 /*-----------------------------------------------------------------*/
5351 /* shiftL1Left2Result - shift left one byte from left to result */
5352 /*-----------------------------------------------------------------*/
5354 shiftL1Left2Result (operand * left, int offl,
5355 operand * result, int offr, int shCount)
5358 l = aopGet (AOP (left), offl, FALSE);
5360 /* shift left accumulator */
5362 aopPut (AOP (result), "a", offr);
5366 /*-----------------------------------------------------------------*/
5367 /* genlshTwo - left shift two bytes by known amount != 0 */
5368 /*-----------------------------------------------------------------*/
5370 genlshTwo (operand * result, operand * left, int shCount)
5372 int size = AOP_SIZE (result);
5374 wassert (size == 2);
5376 /* if shCount >= 8 */
5384 movLeft2Result (left, LSB, result, MSB16, 0);
5385 aopPut (AOP (result), "!zero", 0);
5386 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
5390 movLeft2Result (left, LSB, result, MSB16, 0);
5391 aopPut (AOP (result), "!zero", 0);
5396 aopPut (AOP (result), "!zero", LSB);
5399 /* 1 <= shCount <= 7 */
5408 shiftL2Left2Result (left, LSB, result, LSB, shCount);
5413 /*-----------------------------------------------------------------*/
5414 /* genlshOne - left shift a one byte quantity by known count */
5415 /*-----------------------------------------------------------------*/
5417 genlshOne (operand * result, operand * left, int shCount)
5419 shiftL1Left2Result (left, LSB, result, LSB, shCount);
5422 /*-----------------------------------------------------------------*/
5423 /* genLeftShiftLiteral - left shifting by known count */
5424 /*-----------------------------------------------------------------*/
5426 genLeftShiftLiteral (operand * left,
5431 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5434 freeAsmop (right, NULL, ic);
5436 aopOp (left, ic, FALSE, FALSE);
5437 aopOp (result, ic, FALSE, FALSE);
5439 size = getSize (operandType (result));
5441 /* I suppose that the left size >= result size */
5447 else if (shCount >= (size * 8))
5451 aopPut (AOP (result), "!zero", size);
5459 genlshOne (result, left, shCount);
5462 genlshTwo (result, left, shCount);
5465 wassertl (0, "Shifting of longs is currently unsupported");
5471 freeAsmop (left, NULL, ic);
5472 freeAsmop (result, NULL, ic);
5475 /*-----------------------------------------------------------------*/
5476 /* genLeftShift - generates code for left shifting */
5477 /*-----------------------------------------------------------------*/
5479 genLeftShift (iCode * ic)
5483 symbol *tlbl, *tlbl1;
5484 operand *left, *right, *result;
5486 right = IC_RIGHT (ic);
5487 left = IC_LEFT (ic);
5488 result = IC_RESULT (ic);
5490 aopOp (right, ic, FALSE, FALSE);
5492 /* if the shift count is known then do it
5493 as efficiently as possible */
5494 if (AOP_TYPE (right) == AOP_LIT)
5496 genLeftShiftLiteral (left, right, result, ic);
5500 /* shift count is unknown then we have to form a loop get the loop
5501 count in B : Note: we take only the lower order byte since
5502 shifting more that 32 bits make no sense anyway, ( the largest
5503 size of an object can be only 32 bits ) */
5504 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5506 freeAsmop (right, NULL, ic);
5507 aopOp (left, ic, FALSE, FALSE);
5508 aopOp (result, ic, FALSE, FALSE);
5510 /* now move the left to the result if they are not the
5513 if (!sameRegs (AOP (left), AOP (result)))
5516 size = AOP_SIZE (result);
5520 l = aopGet (AOP (left), offset, FALSE);
5521 aopPut (AOP (result), l, offset);
5526 tlbl = newiTempLabel (NULL);
5527 size = AOP_SIZE (result);
5529 tlbl1 = newiTempLabel (NULL);
5531 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5532 emitLabel (tlbl->key + 100);
5533 l = aopGet (AOP (result), offset, FALSE);
5537 l = aopGet (AOP (result), offset, FALSE);
5541 emit2 ("sla %s", l);
5549 emitLabel (tlbl1->key + 100);
5551 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5553 freeAsmop (left, NULL, ic);
5554 freeAsmop (result, NULL, ic);
5557 /*-----------------------------------------------------------------*/
5558 /* genrshOne - left shift two bytes by known amount != 0 */
5559 /*-----------------------------------------------------------------*/
5561 genrshOne (operand * result, operand * left, int shCount, int is_signed)
5564 int size = AOP_SIZE (result);
5567 wassert (size == 1);
5568 wassert (shCount < 8);
5570 l = aopGet (AOP (left), 0, FALSE);
5572 if (AOP (result)->type == AOP_REG)
5574 aopPut (AOP (result), l, 0);
5575 l = aopGet (AOP (result), 0, FALSE);
5578 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5586 emit2 ("%s a", is_signed ? "sra" : "srl");
5588 aopPut (AOP (result), "a", 0);
5592 /*-----------------------------------------------------------------*/
5593 /* AccRsh - right shift accumulator by known count */
5594 /*-----------------------------------------------------------------*/
5596 AccRsh (int shCount)
5598 static const unsigned char SRMask[] =
5600 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
5605 /* rotate right accumulator */
5606 AccRol (8 - shCount);
5607 /* and kill the higher order bits */
5608 emit2 ("and a,!immedbyte", SRMask[shCount]);
5612 /*-----------------------------------------------------------------*/
5613 /* shiftR1Left2Result - shift right one byte from left to result */
5614 /*-----------------------------------------------------------------*/
5616 shiftR1Left2Result (operand * left, int offl,
5617 operand * result, int offr,
5618 int shCount, int sign)
5620 _moveA (aopGet (AOP (left), offl, FALSE));
5625 emit2 ("%s a", sign ? "sra" : "srl");
5632 aopPut (AOP (result), "a", offr);
5635 /*-----------------------------------------------------------------*/
5636 /* genrshTwo - right shift two bytes by known amount != 0 */
5637 /*-----------------------------------------------------------------*/
5639 genrshTwo (operand * result, operand * left,
5640 int shCount, int sign)
5642 /* if shCount >= 8 */
5648 shiftR1Left2Result (left, MSB16, result, LSB,
5653 movLeft2Result (left, MSB16, result, LSB, sign);
5657 /* Sign extend the result */
5658 _moveA(aopGet (AOP (result), 0, FALSE));
5662 aopPut (AOP (result), ACC_NAME, MSB16);
5666 aopPut (AOP (result), "!zero", 1);
5669 /* 1 <= shCount <= 7 */
5672 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
5676 /*-----------------------------------------------------------------*/
5677 /* genRightShiftLiteral - left shifting by known count */
5678 /*-----------------------------------------------------------------*/
5680 genRightShiftLiteral (operand * left,
5686 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5689 freeAsmop (right, NULL, ic);
5691 aopOp (left, ic, FALSE, FALSE);
5692 aopOp (result, ic, FALSE, FALSE);
5694 size = getSize (operandType (result));
5696 /* I suppose that the left size >= result size */
5702 else if (shCount >= (size * 8))
5704 aopPut (AOP (result), "!zero", size);
5710 genrshOne (result, left, shCount, sign);
5713 genrshTwo (result, left, shCount, sign);
5716 wassertl (0, "Asked to shift right a long which should be a function call");
5719 wassertl (0, "Entered default case in right shift delegate");
5722 freeAsmop (left, NULL, ic);
5723 freeAsmop (result, NULL, ic);
5726 /*-----------------------------------------------------------------*/
5727 /* genRightShift - generate code for right shifting */
5728 /*-----------------------------------------------------------------*/
5730 genRightShift (iCode * ic)
5732 operand *right, *left, *result;
5734 int size, offset, first = 1;
5738 symbol *tlbl, *tlbl1;
5740 /* if signed then we do it the hard way preserve the
5741 sign bit moving it inwards */
5742 retype = getSpec (operandType (IC_RESULT (ic)));
5744 is_signed = !SPEC_USIGN (retype);
5746 /* signed & unsigned types are treated the same : i.e. the
5747 signed is NOT propagated inwards : quoting from the
5748 ANSI - standard : "for E1 >> E2, is equivalent to division
5749 by 2**E2 if unsigned or if it has a non-negative value,
5750 otherwise the result is implementation defined ", MY definition
5751 is that the sign does not get propagated */
5753 right = IC_RIGHT (ic);
5754 left = IC_LEFT (ic);
5755 result = IC_RESULT (ic);
5757 aopOp (right, ic, FALSE, FALSE);
5759 /* if the shift count is known then do it
5760 as efficiently as possible */
5761 if (AOP_TYPE (right) == AOP_LIT)
5763 genRightShiftLiteral (left, right, result, ic, is_signed);
5767 aopOp (left, ic, FALSE, FALSE);
5768 aopOp (result, ic, FALSE, FALSE);
5770 /* now move the left to the result if they are not the
5772 if (!sameRegs (AOP (left), AOP (result)) &&
5773 AOP_SIZE (result) > 1)
5776 size = AOP_SIZE (result);
5780 l = aopGet (AOP (left), offset, FALSE);
5781 aopPut (AOP (result), l, offset);
5786 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5788 freeAsmop (right, NULL, ic);
5790 tlbl = newiTempLabel (NULL);
5791 tlbl1 = newiTempLabel (NULL);
5792 size = AOP_SIZE (result);
5795 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5796 emitLabel (tlbl->key + 100);
5799 l = aopGet (AOP (result), offset--, FALSE);
5802 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5810 emitLabel (tlbl1->key + 100);
5812 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5814 freeAsmop (left, NULL, ic);
5815 freeAsmop (result, NULL, ic);
5818 /*-----------------------------------------------------------------*/
5819 /* genGenPointerGet - get value from generic pointer space */
5820 /*-----------------------------------------------------------------*/
5822 genGenPointerGet (operand * left,
5823 operand * result, iCode * ic)
5826 sym_link *retype = getSpec (operandType (result));
5832 aopOp (left, ic, FALSE, FALSE);
5833 aopOp (result, ic, FALSE, FALSE);
5835 size = AOP_SIZE (result);
5837 if (isPair (AOP (left)) && size == 1)
5840 if (isPtrPair (AOP (left)))
5842 tsprintf (buffer, "!*pair", getPairName (AOP (left)));
5843 aopPut (AOP (result), buffer, 0);
5847 emit2 ("ld a,!*pair", getPairName (AOP (left)));
5848 aopPut (AOP (result), "a", 0);
5850 freeAsmop (left, NULL, ic);
5854 if ( getPairId( AOP (left)) == PAIR_IY)
5861 tsprintf (at, "!*iyx", offset);
5862 aopPut (AOP (result), at, offset);
5868 /* For now we always load into IY */
5869 /* if this is remateriazable */
5870 fetchPair (pair, AOP (left));
5872 freeAsmop (left, NULL, ic);
5874 /* if bit then unpack */
5875 if (IS_BITVAR (retype))
5879 else if ( getPairId( AOP (result)) == PAIR_HL)
5881 wassertl (size == 2, "HL must be of size 2");
5882 emit2 ("ld a,!*hl");
5884 emit2 ("ld h,!*hl");
5889 size = AOP_SIZE (result);
5894 /* PENDING: make this better */
5895 if (!IS_GB && AOP (result)->type == AOP_REG)
5897 aopPut (AOP (result), "!*hl", offset++);
5901 emit2 ("ld a,!*pair", _pairs[pair].name);
5902 aopPut (AOP (result), "a", offset++);
5906 emit2 ("inc %s", _pairs[pair].name);
5907 _G.pairs[pair].offset++;
5913 freeAsmop (result, NULL, ic);
5916 /*-----------------------------------------------------------------*/
5917 /* genPointerGet - generate code for pointer get */
5918 /*-----------------------------------------------------------------*/
5920 genPointerGet (iCode * ic)
5922 operand *left, *result;
5923 sym_link *type, *etype;
5925 left = IC_LEFT (ic);
5926 result = IC_RESULT (ic);
5928 /* depending on the type of pointer we need to
5929 move it to the correct pointer register */
5930 type = operandType (left);
5931 etype = getSpec (type);
5933 genGenPointerGet (left, result, ic);
5937 isRegOrLit (asmop * aop)
5939 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
5944 /*-----------------------------------------------------------------*/
5945 /* genGenPointerSet - stores the value into a pointer location */
5946 /*-----------------------------------------------------------------*/
5948 genGenPointerSet (operand * right,
5949 operand * result, iCode * ic)
5952 sym_link *retype = getSpec (operandType (right));
5953 PAIR_ID pairId = PAIR_HL;
5955 aopOp (result, ic, FALSE, FALSE);
5956 aopOp (right, ic, FALSE, FALSE);
5961 size = AOP_SIZE (right);
5963 /* Handle the exceptions first */
5964 if (isPair (AOP (result)) && size == 1)
5967 const char *l = aopGet (AOP (right), 0, FALSE);
5968 const char *pair = getPairName (AOP (result));
5969 if (canAssignToPtr (l) && isPtr (pair))
5971 emit2 ("ld !*pair,%s", pair, l);
5976 emit2 ("ld !*pair,a", pair);
5981 if ( getPairId( AOP (result)) == PAIR_IY)
5984 const char *l = aopGet (AOP (right), 0, FALSE);
5989 if (canAssignToPtr (l))
5991 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
5995 _moveA (aopGet (AOP (right), offset, FALSE));
5996 emit2 ("ld !*iyx,a", offset);
6003 /* if the operand is already in dptr
6004 then we do nothing else we move the value to dptr */
6005 if (AOP_TYPE (result) != AOP_STR)
6007 fetchPair (pairId, AOP (result));
6009 /* so hl know contains the address */
6010 freeAsmop (result, NULL, ic);
6012 /* if bit then unpack */
6013 if (IS_BITVAR (retype))
6023 const char *l = aopGet (AOP (right), offset, FALSE);
6024 if (isRegOrLit (AOP (right)) && !IS_GB)
6026 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
6031 emit2 ("ld !*pair,a", _pairs[pairId].name);
6035 emit2 ("inc %s", _pairs[pairId].name);
6036 _G.pairs[pairId].offset++;
6042 freeAsmop (right, NULL, ic);
6045 /*-----------------------------------------------------------------*/
6046 /* genPointerSet - stores the value into a pointer location */
6047 /*-----------------------------------------------------------------*/
6049 genPointerSet (iCode * ic)
6051 operand *right, *result;
6052 sym_link *type, *etype;
6054 right = IC_RIGHT (ic);
6055 result = IC_RESULT (ic);
6057 /* depending on the type of pointer we need to
6058 move it to the correct pointer register */
6059 type = operandType (result);
6060 etype = getSpec (type);
6062 genGenPointerSet (right, result, ic);
6065 /*-----------------------------------------------------------------*/
6066 /* genIfx - generate code for Ifx statement */
6067 /*-----------------------------------------------------------------*/
6069 genIfx (iCode * ic, iCode * popIc)
6071 operand *cond = IC_COND (ic);
6074 aopOp (cond, ic, FALSE, TRUE);
6076 /* get the value into acc */
6077 if (AOP_TYPE (cond) != AOP_CRY)
6081 /* the result is now in the accumulator */
6082 freeAsmop (cond, NULL, ic);
6084 /* if there was something to be popped then do it */
6088 /* if the condition is a bit variable */
6089 if (isbit && IS_ITEMP (cond) &&
6091 genIfxJump (ic, SPIL_LOC (cond)->rname);
6092 else if (isbit && !IS_ITEMP (cond))
6093 genIfxJump (ic, OP_SYMBOL (cond)->rname);
6095 genIfxJump (ic, "a");
6100 /*-----------------------------------------------------------------*/
6101 /* genAddrOf - generates code for address of */
6102 /*-----------------------------------------------------------------*/
6104 genAddrOf (iCode * ic)
6106 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
6108 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6110 /* if the operand is on the stack then we
6111 need to get the stack offset of this
6118 if (sym->stack <= 0)
6120 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
6124 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6126 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6130 emit2 ("ld de,!hashedstr", sym->rname);
6131 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
6139 /* if it has an offset then we need to compute it */
6141 emit2 ("ld hl,#%d+%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset, _G.stack.param_offset);
6143 emit2 ("ld hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
6144 emit2 ("add hl,sp");
6148 emit2 ("ld hl,#%s", sym->rname);
6150 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6152 freeAsmop (IC_RESULT (ic), NULL, ic);
6155 /*-----------------------------------------------------------------*/
6156 /* genAssign - generate code for assignment */
6157 /*-----------------------------------------------------------------*/
6159 genAssign (iCode * ic)
6161 operand *result, *right;
6163 unsigned long lit = 0L;
6165 result = IC_RESULT (ic);
6166 right = IC_RIGHT (ic);
6168 /* Dont bother assigning if they are the same */
6169 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6171 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
6175 aopOp (right, ic, FALSE, FALSE);
6176 aopOp (result, ic, TRUE, FALSE);
6178 /* if they are the same registers */
6179 if (sameRegs (AOP (right), AOP (result)))
6181 emitDebug ("; (registers are the same)");
6185 /* if the result is a bit */
6186 if (AOP_TYPE (result) == AOP_CRY)
6188 wassertl (0, "Tried to assign to a bit");
6192 size = AOP_SIZE (result);
6195 if (AOP_TYPE (right) == AOP_LIT)
6197 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6200 if (isPair (AOP (result)))
6202 fetchPair (getPairId (AOP (result)), AOP (right));
6204 else if ((size > 1) &&
6205 (AOP_TYPE (result) != AOP_REG) &&
6206 (AOP_TYPE (right) == AOP_LIT) &&
6207 !IS_FLOAT (operandType (right)) &&
6210 bool fXored = FALSE;
6212 /* Work from the top down.
6213 Done this way so that we can use the cached copy of 0
6214 in A for a fast clear */
6217 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
6219 if (!fXored && size > 1)
6226 aopPut (AOP (result), "a", offset);
6230 aopPut (AOP (result), "!zero", offset);
6234 aopPut (AOP (result),
6235 aopGet (AOP (right), offset, FALSE),
6240 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
6242 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
6243 aopPut (AOP (result), "l", LSB);
6244 aopPut (AOP (result), "h", MSB16);
6246 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6248 /* Special case. Load into a and d, then load out. */
6249 _moveA (aopGet (AOP (right), 0, FALSE));
6250 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
6251 aopPut (AOP (result), "a", 0);
6252 aopPut (AOP (result), "e", 1);
6254 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6256 /* Special case - simple memcpy */
6257 aopGet (AOP (right), LSB, FALSE);
6260 aopGet (AOP (result), LSB, FALSE);
6264 emit2 ("ld a,(de)");
6265 /* Peephole will optimise this. */
6266 emit2 ("ld (hl),a");
6274 spillPair (PAIR_HL);
6280 /* PENDING: do this check better */
6281 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
6283 _moveA (aopGet (AOP (right), offset, FALSE));
6284 aopPut (AOP (result), "a", offset);
6287 aopPut (AOP (result),
6288 aopGet (AOP (right), offset, FALSE),
6295 freeAsmop (right, NULL, ic);
6296 freeAsmop (result, NULL, ic);
6299 /*-----------------------------------------------------------------*/
6300 /* genJumpTab - genrates code for jump table */
6301 /*-----------------------------------------------------------------*/
6303 genJumpTab (iCode * ic)
6308 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
6309 /* get the condition into accumulator */
6310 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
6313 emit2 ("ld e,%s", l);
6314 emit2 ("ld d,!zero");
6315 jtab = newiTempLabel (NULL);
6317 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
6318 emit2 ("add hl,de");
6319 emit2 ("add hl,de");
6320 emit2 ("add hl,de");
6321 freeAsmop (IC_JTCOND (ic), NULL, ic);
6325 emitLabel (jtab->key + 100);
6326 /* now generate the jump labels */
6327 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
6328 jtab = setNextItem (IC_JTLABELS (ic)))
6329 emit2 ("jp !tlabel", jtab->key + 100);
6332 /*-----------------------------------------------------------------*/
6333 /* genCast - gen code for casting */
6334 /*-----------------------------------------------------------------*/
6336 genCast (iCode * ic)
6338 operand *result = IC_RESULT (ic);
6339 sym_link *ctype = operandType (IC_LEFT (ic));
6340 operand *right = IC_RIGHT (ic);
6343 /* if they are equivalent then do nothing */
6344 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6347 aopOp (right, ic, FALSE, FALSE);
6348 aopOp (result, ic, FALSE, FALSE);
6350 /* if the result is a bit */
6351 if (AOP_TYPE (result) == AOP_CRY)
6353 wassertl (0, "Tried to cast to a bit");
6356 /* if they are the same size : or less */
6357 if (AOP_SIZE (result) <= AOP_SIZE (right))
6360 /* if they are in the same place */
6361 if (sameRegs (AOP (right), AOP (result)))
6364 /* if they in different places then copy */
6365 size = AOP_SIZE (result);
6369 aopPut (AOP (result),
6370 aopGet (AOP (right), offset, FALSE),
6377 /* So we now know that the size of destination is greater
6378 than the size of the source */
6379 /* we move to result for the size of source */
6380 size = AOP_SIZE (right);
6384 aopPut (AOP (result),
6385 aopGet (AOP (right), offset, FALSE),
6390 /* now depending on the sign of the destination */
6391 size = AOP_SIZE (result) - AOP_SIZE (right);
6392 /* Unsigned or not an integral type - right fill with zeros */
6393 if (SPEC_USIGN (ctype) || !IS_SPEC (ctype))
6396 aopPut (AOP (result), "!zero", offset++);
6400 /* we need to extend the sign :{ */
6401 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
6407 aopPut (AOP (result), "a", offset++);
6411 freeAsmop (right, NULL, ic);
6412 freeAsmop (result, NULL, ic);
6415 /*-----------------------------------------------------------------*/
6416 /* genReceive - generate code for a receive iCode */
6417 /*-----------------------------------------------------------------*/
6419 genReceive (iCode * ic)
6421 if (isOperandInFarSpace (IC_RESULT (ic)) &&
6422 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
6423 IS_TRUE_SYMOP (IC_RESULT (ic))))
6433 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6434 size = AOP_SIZE(IC_RESULT(ic));
6436 for (i = 0; i < size; i++) {
6437 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
6441 freeAsmop (IC_RESULT (ic), NULL, ic);
6446 /** Maximum number of bytes to emit per line. */
6450 /** Context for the byte output chunker. */
6453 unsigned char buffer[DBEMIT_MAX_RUN];
6458 /** Flushes a byte chunker by writing out all in the buffer and
6462 _dbFlush(DBEMITCTX *self)
6469 sprintf(line, ".db 0x%02X", self->buffer[0]);
6471 for (i = 1; i < self->pos; i++)
6473 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
6480 /** Write out another byte, buffering until a decent line is
6484 _dbEmit(DBEMITCTX *self, int c)
6486 if (self->pos == DBEMIT_MAX_RUN)
6490 self->buffer[self->pos++] = c;
6493 /** Context for a simple run length encoder. */
6497 unsigned char buffer[128];
6499 /** runLen may be equivalent to pos. */
6505 RLE_CHANGE_COST = 4,
6509 /** Flush the buffer of a run length encoder by writing out the run or
6510 data that it currently contains.
6513 _rleCommit(RLECTX *self)
6519 memset(&db, 0, sizeof(db));
6521 emit2(".db %u", self->pos);
6523 for (i = 0; i < self->pos; i++)
6525 _dbEmit(&db, self->buffer[i]);
6534 Can get either a run or a block of random stuff.
6535 Only want to change state if a good run comes in or a run ends.
6536 Detecting run end is easy.
6539 Say initial state is in run, len zero, last zero. Then if you get a
6540 few zeros then something else then a short run will be output.
6541 Seems OK. While in run mode, keep counting. While in random mode,
6542 keep a count of the run. If run hits margin, output all up to run,
6543 restart, enter run mode.
6546 /** Add another byte into the run length encoder, flushing as
6547 required. The run length encoder uses the Amiga IFF style, where
6548 a block is prefixed by its run length. A positive length means
6549 the next n bytes pass straight through. A negative length means
6550 that the next byte is repeated -n times. A zero terminates the
6554 _rleAppend(RLECTX *self, int c)
6558 if (c != self->last)
6560 /* The run has stopped. See if it is worthwhile writing it out
6561 as a run. Note that the random data comes in as runs of
6564 if (self->runLen > RLE_CHANGE_COST)
6566 /* Yes, worthwhile. */
6567 /* Commit whatever was in the buffer. */
6569 emit2(".db -%u,0x%02X", self->runLen, self->last);
6573 /* Not worthwhile. Append to the end of the random list. */
6574 for (i = 0; i < self->runLen; i++)
6576 if (self->pos >= RLE_MAX_BLOCK)
6581 self->buffer[self->pos++] = self->last;
6589 if (self->runLen >= RLE_MAX_BLOCK)
6591 /* Commit whatever was in the buffer. */
6594 emit2 (".db -%u,0x%02X", self->runLen, self->last);
6602 _rleFlush(RLECTX *self)
6604 _rleAppend(self, -1);
6611 /** genArrayInit - Special code for initialising an array with constant
6615 genArrayInit (iCode * ic)
6619 int elementSize = 0, eIndex, i;
6620 unsigned val, lastVal;
6624 memset(&rle, 0, sizeof(rle));
6626 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
6628 _saveRegsForCall(ic, 0);
6630 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
6631 emit2 ("call __initrleblock");
6633 type = operandType(IC_LEFT(ic));
6635 if (type && type->next)
6637 elementSize = getSize(type->next);
6641 wassertl (0, "Can't determine element size in genArrayInit.");
6644 iLoop = IC_ARRAYILIST(ic);
6645 lastVal = (unsigned)-1;
6647 /* Feed all the bytes into the run length encoder which will handle
6649 This works well for mixed char data, and for random int and long
6658 for (i = 0; i < ix; i++)
6660 for (eIndex = 0; eIndex < elementSize; eIndex++)
6662 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
6663 _rleAppend(&rle, val);
6668 iLoop = iLoop->next;
6672 /* Mark the end of the run. */
6675 _restoreRegsAfterCall();
6679 freeAsmop (IC_LEFT(ic), NULL, ic);
6682 /*-----------------------------------------------------------------*/
6683 /* genZ80Code - generate code for Z80 based controllers */
6684 /*-----------------------------------------------------------------*/
6686 genZ80Code (iCode * lic)
6694 _fReturn = _gbz80_return;
6695 _fTmp = _gbz80_return;
6699 _fReturn = _z80_return;
6700 _fTmp = _z80_return;
6703 _G.lines.head = _G.lines.current = NULL;
6705 for (ic = lic; ic; ic = ic->next)
6708 if (cln != ic->lineno)
6710 emit2 ("; %s %d", ic->filename, ic->lineno);
6713 /* if the result is marked as
6714 spilt and rematerializable or code for
6715 this has already been generated then
6717 if (resultRemat (ic) || ic->generated)
6720 /* depending on the operation */
6724 emitDebug ("; genNot");
6729 emitDebug ("; genCpl");
6734 emitDebug ("; genUminus");
6739 emitDebug ("; genIpush");
6744 /* IPOP happens only when trying to restore a
6745 spilt live range, if there is an ifx statement
6746 following this pop then the if statement might
6747 be using some of the registers being popped which
6748 would destory the contents of the register so
6749 we need to check for this condition and handle it */
6751 ic->next->op == IFX &&
6752 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
6754 emitDebug ("; genIfx");
6755 genIfx (ic->next, ic);
6759 emitDebug ("; genIpop");
6765 emitDebug ("; genCall");
6770 emitDebug ("; genPcall");
6775 emitDebug ("; genFunction");
6780 emitDebug ("; genEndFunction");
6781 genEndFunction (ic);
6785 emitDebug ("; genRet");
6790 emitDebug ("; genLabel");
6795 emitDebug ("; genGoto");
6800 emitDebug ("; genPlus");
6805 emitDebug ("; genMinus");
6810 emitDebug ("; genMult");
6815 emitDebug ("; genDiv");
6820 emitDebug ("; genMod");
6825 emitDebug ("; genCmpGt");
6826 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
6830 emitDebug ("; genCmpLt");
6831 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
6838 /* note these two are xlated by algebraic equivalence
6839 during parsing SDCC.y */
6840 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
6841 "got '>=' or '<=' shouldn't have come here");
6845 emitDebug ("; genCmpEq");
6846 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
6850 emitDebug ("; genAndOp");
6855 emitDebug ("; genOrOp");
6860 emitDebug ("; genXor");
6861 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
6865 emitDebug ("; genOr");
6866 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
6870 emitDebug ("; genAnd");
6871 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
6875 emitDebug ("; genInline");
6880 emitDebug ("; genRRC");
6885 emitDebug ("; genRLC");
6890 emitDebug ("; genGetHBIT");
6895 emitDebug ("; genLeftShift");
6900 emitDebug ("; genRightShift");
6904 case GET_VALUE_AT_ADDRESS:
6905 emitDebug ("; genPointerGet");
6911 if (POINTER_SET (ic))
6913 emitDebug ("; genAssign (pointer)");
6918 emitDebug ("; genAssign");
6924 emitDebug ("; genIfx");
6929 emitDebug ("; genAddrOf");
6934 emitDebug ("; genJumpTab");
6939 emitDebug ("; genCast");
6944 emitDebug ("; genReceive");
6949 emitDebug ("; addSet");
6950 addSet (&_G.sendSet, ic);
6954 emitDebug ("; genArrayInit");
6964 /* now we are ready to call the
6965 peep hole optimizer */
6966 if (!options.nopeep)
6967 peepHole (&_G.lines.head);
6969 /* This is unfortunate */
6970 /* now do the actual printing */
6972 FILE *fp = codeOutFile;
6973 if (isInHome () && codeOutFile == code->oFile)
6974 codeOutFile = home->oFile;
6975 printLine (_G.lines.head, codeOutFile);
6976 if (_G.flushStatics)
6979 _G.flushStatics = 0;
6984 freeTrace(&_G.lines.trace);
6985 freeTrace(&_G.trace.aops);
6991 _isPairUsed (iCode * ic, PAIR_ID pairId)
6997 if (bitVectBitValue (ic->rMask, D_IDX))
6999 if (bitVectBitValue (ic->rMask, E_IDX))
7009 fetchLitSpecial (asmop * aop, bool negate, bool xor)
7012 value *val = aop->aopu.aop_lit;
7014 wassert (aop->type == AOP_LIT);
7015 wassert (!IS_FLOAT (val->type));
7017 v = (unsigned long) floatFromVal (val);
7025 tsprintf (buffer, "!immedword", v);
7026 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));