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);
236 static const char *aopNames[] = {
269 _getTempPairName(void)
271 return _pairs[_getTempPairId()].name;
275 getFreePairId (iCode *ic)
277 if (!(bitVectBitValue (ic->rMask, B_IDX) || bitVectBitValue(ic->rMask, C_IDX)))
281 else if (IS_Z80 && !(bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX)))
294 /* Clean up the line so that it is 'prettier' */
295 if (strchr (buf, ':'))
297 /* Is a label - cant do anything */
300 /* Change the first (and probably only) ' ' to a tab so
315 _newLineNode (char *line)
319 pl = traceAlloc(&_G.lines.trace, Safe_alloc ( sizeof (lineNode)));
320 pl->line = traceAlloc(&_G.lines.trace, Safe_strdup (line));
326 _vemit2 (const char *szFormat, va_list ap)
330 tvsprintf (buffer, szFormat, ap);
333 _G.lines.current = (_G.lines.current ?
334 connectLine (_G.lines.current, _newLineNode (buffer)) :
335 (_G.lines.head = _newLineNode (buffer)));
337 _G.lines.current->isInline = _G.lines.isInline;
341 emit2 (const char *szFormat,...)
345 va_start (ap, szFormat);
347 _vemit2 (szFormat, ap);
353 emitDebug (const char *szFormat,...)
359 va_start (ap, szFormat);
361 _vemit2 (szFormat, ap);
367 /*-----------------------------------------------------------------*/
368 /* emit2 - writes the code into a file : for now it is simple */
369 /*-----------------------------------------------------------------*/
371 _emit2 (const char *inst, const char *fmt,...)
374 char lb[INITIAL_INLINEASM];
381 sprintf (lb, "%s\t", inst);
382 vsprintf (lb + (strlen (lb)), fmt, ap);
385 vsprintf (lb, fmt, ap);
387 while (isspace (*lbp))
392 _G.lines.current = (_G.lines.current ?
393 connectLine (_G.lines.current, _newLineNode (lb)) :
394 (_G.lines.head = _newLineNode (lb)));
396 _G.lines.current->isInline = _G.lines.isInline;
401 _emitMove(const char *to, const char *from)
403 if (strcasecmp(to, from) != 0)
405 emit2("ld %s,%s", to, from);
410 // Could leave this to the peephole, but sometimes the peephole is inhibited.
415 aopDump(const char *plabel, asmop *aop)
417 emitDebug("; Dump of %s: type %s size %u", plabel, aopNames[aop->type], aop->size);
421 emitDebug("; aop_stk %d", aop->aopu.aop_stk);
424 /* No information. */
429 _moveA(const char *moveFrom)
431 // Let the peephole optimiser take care of redundent loads
432 _emitMove(ACC_NAME, moveFrom);
442 getPairName (asmop * aop)
444 if (aop->type == AOP_REG)
446 switch (aop->aopu.aop_reg[0]->rIdx)
459 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
462 for (i = 0; i < NUM_PAIRS; i++)
464 if (strcmp(aop->aopu.aop_str[0], _pairs[i].l) == 0)
466 return _pairs[i].name;
470 wassertl (0, "Tried to get the pair name of something that isn't a pair");
475 getPairId (asmop * aop)
479 if (aop->type == AOP_REG)
481 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX) && (aop->aopu.aop_reg[1]->rIdx == B_IDX))
485 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX) && (aop->aopu.aop_reg[1]->rIdx == D_IDX))
489 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX) && (aop->aopu.aop_reg[1]->rIdx == H_IDX))
494 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
497 for (i = 0; i < NUM_PAIRS; i++)
499 if (!strcmp (aop->aopu.aop_str[0], _pairs[i].l) && !strcmp (aop->aopu.aop_str[1], _pairs[i].h))
509 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
513 return (getPairId (aop) != PAIR_INVALID);
517 isPtrPair (asmop * aop)
519 PAIR_ID pairId = getPairId (aop);
532 spillPair (PAIR_ID pairId)
534 _G.pairs[pairId].last_type = AOP_INVALID;
535 _G.pairs[pairId].base = NULL;
538 /** Push a register pair onto the stack */
540 genPairPush (asmop * aop)
542 emit2 ("push %s", getPairName (aop));
546 _push (PAIR_ID pairId)
548 emit2 ("push %s", _pairs[pairId].name);
549 _G.stack.pushed += 2;
553 _pop (PAIR_ID pairId)
555 emit2 ("pop %s", _pairs[pairId].name);
556 _G.stack.pushed -= 2;
560 /*-----------------------------------------------------------------*/
561 /* newAsmop - creates a new asmOp */
562 /*-----------------------------------------------------------------*/
564 newAsmop (short type)
568 aop = traceAlloc(&_G.trace.aops, Safe_alloc (sizeof (asmop)));
573 /*-----------------------------------------------------------------*/
574 /* aopForSym - for a true symbol */
575 /*-----------------------------------------------------------------*/
577 aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
584 wassert (sym->etype);
586 space = SPEC_OCLS (sym->etype);
588 /* if already has one */
594 /* Assign depending on the storage class */
595 if (sym->onStack || sym->iaccess)
597 /* The pointer that is used depends on how big the offset is.
598 Normally everything is AOP_STK, but for offsets of < -128 or
599 > 127 on the Z80 an extended stack pointer is used.
601 if (IS_Z80 && (options.ommitFramePtr || sym->stack < INT8MIN || sym->stack > (int)(INT8MAX-getSize (sym->type))))
603 emitDebug ("; AOP_EXSTK for %s", sym->rname);
604 sym->aop = aop = newAsmop (AOP_EXSTK);
608 emitDebug ("; AOP_STK for %s", sym->rname);
609 sym->aop = aop = newAsmop (AOP_STK);
612 aop->size = getSize (sym->type);
613 aop->aopu.aop_stk = sym->stack;
617 /* special case for a function */
618 if (IS_FUNC (sym->type))
620 sym->aop = aop = newAsmop (AOP_IMMD);
621 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup (sym->rname));
628 /* if it is in direct space */
629 if (IN_REGSP (space) && !requires_a)
631 sym->aop = aop = newAsmop (AOP_SFR);
632 aop->aopu.aop_dir = sym->rname;
633 aop->size = getSize (sym->type);
634 emitDebug ("; AOP_SFR for %s", sym->rname);
639 /* only remaining is far space */
640 /* in which case DPTR gets the address */
643 emitDebug ("; AOP_HL for %s", sym->rname);
644 sym->aop = aop = newAsmop (AOP_HL);
648 sym->aop = aop = newAsmop (AOP_IY);
650 aop->size = getSize (sym->type);
651 aop->aopu.aop_dir = sym->rname;
653 /* if it is in code space */
654 if (IN_CODESPACE (space))
660 /*-----------------------------------------------------------------*/
661 /* aopForRemat - rematerialzes an object */
662 /*-----------------------------------------------------------------*/
664 aopForRemat (symbol * sym)
667 iCode *ic = sym->rematiCode;
668 asmop *aop = newAsmop (AOP_IMMD);
672 /* if plus or minus print the right hand side */
673 if (ic->op == '+' || ic->op == '-')
675 /* PENDING: for re-target */
676 sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
679 ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
682 /* we reached the end */
683 sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
687 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
691 /*-----------------------------------------------------------------*/
692 /* regsInCommon - two operands have some registers in common */
693 /*-----------------------------------------------------------------*/
695 regsInCommon (operand * op1, operand * op2)
700 /* if they have registers in common */
701 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
704 sym1 = OP_SYMBOL (op1);
705 sym2 = OP_SYMBOL (op2);
707 if (sym1->nRegs == 0 || sym2->nRegs == 0)
710 for (i = 0; i < sym1->nRegs; i++)
716 for (j = 0; j < sym2->nRegs; j++)
721 if (sym2->regs[j] == sym1->regs[i])
729 /*-----------------------------------------------------------------*/
730 /* operandsEqu - equivalent */
731 /*-----------------------------------------------------------------*/
733 operandsEqu (operand * op1, operand * op2)
737 /* if they not symbols */
738 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
741 sym1 = OP_SYMBOL (op1);
742 sym2 = OP_SYMBOL (op2);
744 /* if both are itemps & one is spilt
745 and the other is not then false */
746 if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
747 sym1->isspilt != sym2->isspilt)
750 /* if they are the same */
754 if (strcmp (sym1->rname, sym2->rname) == 0)
758 /* if left is a tmp & right is not */
759 if (IS_ITEMP (op1) &&
762 (sym1->usl.spillLoc == sym2))
765 if (IS_ITEMP (op2) &&
769 (sym2->usl.spillLoc == sym1))
775 /*-----------------------------------------------------------------*/
776 /* sameRegs - two asmops have the same registers */
777 /*-----------------------------------------------------------------*/
779 sameRegs (asmop * aop1, asmop * aop2)
783 if (aop1->type == AOP_SFR ||
784 aop2->type == AOP_SFR)
790 if (aop1->type != AOP_REG ||
791 aop2->type != AOP_REG)
794 if (aop1->size != aop2->size)
797 for (i = 0; i < aop1->size; i++)
798 if (aop1->aopu.aop_reg[i] !=
799 aop2->aopu.aop_reg[i])
805 /*-----------------------------------------------------------------*/
806 /* aopOp - allocates an asmop for an operand : */
807 /*-----------------------------------------------------------------*/
809 aopOp (operand * op, iCode * ic, bool result, bool requires_a)
818 /* if this a literal */
819 if (IS_OP_LITERAL (op))
821 op->aop = aop = newAsmop (AOP_LIT);
822 aop->aopu.aop_lit = op->operand.valOperand;
823 aop->size = getSize (operandType (op));
827 /* if already has a asmop then continue */
828 if (op->aop && aop->size == getSize(sym->type))
833 /* if the underlying symbol has a aop */
834 if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
836 op->aop = OP_SYMBOL (op)->aop;
840 /* if this is a true symbol */
841 if (IS_TRUE_SYMOP (op))
843 op->aop = aopForSym (ic, OP_SYMBOL (op), result, requires_a);
847 /* this is a temporary : this has
853 e) can be a return use only */
855 sym = OP_SYMBOL (op);
857 /* if the type is a conditional */
858 if (sym->regType == REG_CND)
860 aop = op->aop = sym->aop = newAsmop (AOP_CRY);
865 /* if it is spilt then two situations
867 b) has a spill location */
868 if (sym->isspilt || sym->nRegs == 0)
870 /* rematerialize it NOW */
873 sym->aop = op->aop = aop =
875 aop->size = getSize (sym->type);
882 aop = op->aop = sym->aop = newAsmop (AOP_STR);
883 aop->size = getSize (sym->type);
884 for (i = 0; i < 4; i++)
885 aop->aopu.aop_str[i] = _fReturn[i];
891 if (sym->accuse == ACCUSE_A)
893 aop = op->aop = sym->aop = newAsmop (AOP_ACC);
894 aop->size = getSize (sym->type);
895 wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
897 aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
899 else if (sym->accuse == ACCUSE_SCRATCH)
901 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
902 aop->size = getSize (sym->type);
903 wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
904 aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
905 aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
907 else if (sym->accuse == ACCUSE_IY)
909 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
910 aop->size = getSize (sym->type);
911 wassertl(aop->size <= 2, "Internal error: Caching in IY, but too big to fit in IY");
912 aop->aopu.aop_str[0] = _pairs[PAIR_IY].l;
913 aop->aopu.aop_str[1] = _pairs[PAIR_IY].h;
917 wassertl (0, "Marked as being allocated into A or HL but is actually in neither");
922 /* else spill location */
924 aopForSym (ic, sym->usl.spillLoc, result, requires_a);
925 wassertl (aop->size >= getSize (sym->type), "Operand doesn't fit in the spill location");
926 aop->size = getSize (sym->type);
930 /* must be in a register */
931 sym->aop = op->aop = aop = newAsmop (AOP_REG);
932 aop->size = sym->nRegs;
933 for (i = 0; i < sym->nRegs; i++)
934 aop->aopu.aop_reg[i] = sym->regs[i];
937 /*-----------------------------------------------------------------*/
938 /* freeAsmop - free up the asmop given to an operand */
939 /*----------------------------------------------------------------*/
941 freeAsmop (operand * op, asmop * aaop, iCode * ic)
958 if (aop->type == AOP_PAIRPTR && IS_Z80 && aop->aopu.aop_pairId == PAIR_DE)
960 _pop (aop->aopu.aop_pairId);
964 /* all other cases just dealloc */
970 OP_SYMBOL (op)->aop = NULL;
971 /* if the symbol has a spill */
973 SPIL_LOC (op)->aop = NULL;
980 isLitWord (asmop * aop)
982 /* if (aop->size != 2)
995 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
999 /* depending on type */
1005 /* PENDING: for re-target */
1008 tsprintf (s, "!hashedstr + %d", aop->aopu.aop_immd, offset);
1010 else if (offset == 0)
1012 tsprintf (s, "%s", aop->aopu.aop_immd);
1016 tsprintf (s, "%s + %d", aop->aopu.aop_immd, offset);
1018 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1022 value *val = aop->aopu.aop_lit;
1023 /* if it is a float then it gets tricky */
1024 /* otherwise it is fairly simple */
1025 if (!IS_FLOAT (val->type))
1027 unsigned long v = (unsigned long) floatFromVal (val);
1033 else if (offset == 0)
1039 wassertl(0, "Encountered an invalid offset while fetching a literal");
1043 tsprintf (buffer, "!immedword", v);
1045 tsprintf (buffer, "!constword", v);
1047 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1058 /* it is type float */
1059 fl.f = (float) floatFromVal (val);
1062 i = fl.c[3-offset] | (fl.c[3-offset-1]<<8);
1064 i = fl.c[offset] | (fl.c[offset+1]<<8);
1067 tsprintf (buffer, "!immedword", i);
1069 tsprintf (buffer, "!constword", i);
1071 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1080 aopGetWord (asmop * aop, int offset)
1082 return aopGetLitWordLong (aop, offset, TRUE);
1086 isPtr (const char *s)
1088 if (!strcmp (s, "hl"))
1090 if (!strcmp (s, "ix"))
1092 if (!strcmp (s, "iy"))
1098 adjustPair (const char *pair, int *pold, int new)
1104 emit2 ("inc %s", pair);
1109 emit2 ("dec %s", pair);
1117 spillPair (PAIR_HL);
1118 spillPair (PAIR_IY);
1122 requiresHL (asmop * aop)
1138 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1140 const char *l, *base;
1141 const char *pair = _pairs[pairId].name;
1142 l = aopGetLitWordLong (left, offset, FALSE);
1143 base = aopGetLitWordLong (left, 0, FALSE);
1144 wassert (l && pair && base);
1148 if (pairId == PAIR_HL || pairId == PAIR_IY)
1150 if (_G.pairs[pairId].last_type == left->type)
1152 if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1154 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1156 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1159 if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
1166 _G.pairs[pairId].last_type = left->type;
1167 _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1168 _G.pairs[pairId].offset = offset;
1170 /* Both a lit on the right and a true symbol on the left */
1171 emit2 ("ld %s,!hashedstr", pair, l);
1175 fetchPairLong (PAIR_ID pairId, asmop * aop, int offset)
1177 /* if this is remateriazable */
1178 if (isLitWord (aop)) {
1179 fetchLitPair (pairId, aop, offset);
1183 if (getPairId (aop) == pairId)
1187 /* we need to get it byte by byte */
1188 else if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1189 aopGet (aop, offset, FALSE);
1190 switch (aop->size - offset) {
1192 emit2 ("ld l,!*hl");
1193 emit2 ("ld h,!immedbyte", 0);
1196 // PENDING: Requires that you are only fetching two bytes.
1199 emit2 ("ld h,!*hl");
1203 wassertl (0, "Attempted to fetch too much data into HL");
1207 else if (IS_Z80 && aop->type == AOP_IY) {
1208 /* Instead of fetching relative to IY, just grab directly
1209 from the address IY refers to */
1210 char *l = aopGetLitWordLong (aop, offset, FALSE);
1212 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1214 if (aop->size < 2) {
1215 emit2("ld %s,!zero", _pairs[pairId].h);
1218 else if (pairId == PAIR_IY)
1222 emit2 ("push %s", _pairs[getPairId(aop)].name);
1228 /* Can't load into parts, so load into HL then exchange. */
1229 emit2 ("ld %s,%s", _pairs[PAIR_HL].l, aopGet (aop, offset, FALSE));
1230 emit2 ("ld %s,%s", _pairs[PAIR_HL].h, aopGet (aop, offset + 1, FALSE));
1237 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1238 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1240 /* PENDING: check? */
1241 if (pairId == PAIR_HL)
1242 spillPair (PAIR_HL);
1247 fetchPair (PAIR_ID pairId, asmop * aop)
1249 fetchPairLong (pairId, aop, 0);
1253 fetchHL (asmop * aop)
1255 fetchPair (PAIR_HL, aop);
1259 setupPairFromSP (PAIR_ID id, int offset)
1261 wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
1263 if (offset < INT8MIN || offset > INT8MAX)
1265 emit2 ("ld hl,!immedword", offset);
1266 emit2 ("add hl,sp");
1270 emit2 ("!ldahlsp", offset);
1275 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1280 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
1281 fetchLitPair (pairId, aop, 0);
1285 wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
1287 fetchLitPair (pairId, aop, offset);
1288 _G.pairs[pairId].offset = offset;
1292 wassertl (IS_Z80, "Only the Z80 has an extended stack");
1293 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
1296 int offset = aop->aopu.aop_stk + _G.stack.offset;
1298 if (_G.pairs[pairId].last_type == aop->type &&
1299 _G.pairs[pairId].offset == offset)
1305 /* PENDING: Do this better. */
1306 sprintf (buffer, "%d", offset + _G.stack.pushed);
1307 emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
1308 emit2 ("add %s,sp", _pairs[pairId].name);
1309 _G.pairs[pairId].last_type = aop->type;
1310 _G.pairs[pairId].offset = offset;
1317 /* Doesnt include _G.stack.pushed */
1318 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1320 if (aop->aopu.aop_stk > 0)
1322 abso += _G.stack.param_offset;
1324 assert (pairId == PAIR_HL);
1325 /* In some cases we can still inc or dec hl */
1326 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1328 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1332 setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
1334 _G.pairs[pairId].offset = abso;
1339 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
1345 _G.pairs[pairId].last_type = aop->type;
1351 emit2 ("!tlabeldef", key);
1355 /*-----------------------------------------------------------------*/
1356 /* aopGet - for fetching value of the aop */
1357 /*-----------------------------------------------------------------*/
1359 aopGet (asmop * aop, int offset, bool bit16)
1363 /* offset is greater than size then zero */
1364 /* PENDING: this seems a bit screwed in some pointer cases. */
1365 if (offset > (aop->size - 1) &&
1366 aop->type != AOP_LIT)
1368 tsprintf (s, "!zero");
1369 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1372 /* depending on type */
1376 /* PENDING: re-target */
1378 tsprintf (s, "!immedwords", aop->aopu.aop_immd);
1383 tsprintf (s, "!bankimmeds", aop->aopu.aop_immd);
1386 tsprintf (s, "!msbimmeds", aop->aopu.aop_immd);
1389 tsprintf (s, "!lsbimmeds", aop->aopu.aop_immd);
1392 wassertl (0, "Fetching from beyond the limits of an immediate value.");
1395 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1399 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1402 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1406 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1409 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1412 return aop->aopu.aop_reg[offset]->name;
1416 setupPair (PAIR_HL, aop, offset);
1417 tsprintf (s, "!*hl");
1419 return traceAlloc(&_G.trace.aops, Safe_strdup (s));
1423 setupPair (PAIR_IY, aop, offset);
1424 tsprintf (s, "!*iyx", offset);
1426 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1430 setupPair (PAIR_IY, aop, offset);
1431 tsprintf (s, "!*iyx", offset, offset);
1433 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1438 setupPair (PAIR_HL, aop, offset);
1439 tsprintf (s, "!*hl");
1443 if (aop->aopu.aop_stk >= 0)
1444 offset += _G.stack.param_offset;
1445 tsprintf (s, "!*ixx", aop->aopu.aop_stk + offset);
1448 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1451 wassertl (0, "Tried to fetch from a bit variable");
1460 tsprintf(s, "!zero");
1461 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1465 wassert (offset < 2);
1466 return aop->aopu.aop_str[offset];
1469 return aopLiteral (aop->aopu.aop_lit, offset);
1473 unsigned long v = aop->aopu.aop_simplelit;
1476 tsprintf (s, "!immedbyte", (unsigned int) v & 0xff);
1478 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1482 return aop->aopu.aop_str[offset];
1485 setupPair (aop->aopu.aop_pairId, aop, offset);
1486 sprintf (s, "(%s)", _pairs[aop->aopu.aop_pairId].name);
1488 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1493 wassertl (0, "aopget got unsupported aop->type");
1498 isRegString (const char *s)
1500 if (!strcmp (s, "b") ||
1512 isConstant (const char *s)
1514 /* This is a bit of a hack... */
1515 return (*s == '#' || *s == '$');
1519 canAssignToPtr (const char *s)
1521 if (isRegString (s))
1528 /*-----------------------------------------------------------------*/
1529 /* aopPut - puts a string for a aop */
1530 /*-----------------------------------------------------------------*/
1532 aopPut (asmop * aop, const char *s, int offset)
1536 if (aop->size && offset > (aop->size - 1))
1538 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1539 "aopPut got offset > aop->size");
1544 tsprintf(buffer2, s);
1547 /* will assign value to value */
1548 /* depending on where it is ofcourse */
1554 if (strcmp (s, "a"))
1555 emit2 ("ld a,%s", s);
1556 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1561 if (strcmp (s, "a"))
1562 emit2 ("ld a,%s", s);
1563 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1567 if (!strcmp (s, "!*hl"))
1568 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1571 aop->aopu.aop_reg[offset]->name, s);
1576 if (!canAssignToPtr (s))
1578 emit2 ("ld a,%s", s);
1579 setupPair (PAIR_IY, aop, offset);
1580 emit2 ("ld !*iyx,a", offset);
1584 setupPair (PAIR_IY, aop, offset);
1585 emit2 ("ld !*iyx,%s", offset, s);
1591 /* PENDING: for re-target */
1592 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1594 emit2 ("ld a,!*hl");
1597 setupPair (PAIR_HL, aop, offset);
1599 emit2 ("ld !*hl,%s", s);
1604 if (!canAssignToPtr (s))
1606 emit2 ("ld a,%s", s);
1607 setupPair (PAIR_IY, aop, offset);
1608 emit2 ("ld !*iyx,a", offset);
1612 setupPair (PAIR_IY, aop, offset);
1613 emit2 ("ld !*iyx,%s", offset, s);
1620 /* PENDING: re-target */
1621 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1623 emit2 ("ld a,!*hl");
1626 setupPair (PAIR_HL, aop, offset);
1627 if (!canAssignToPtr (s))
1629 emit2 ("ld a,%s", s);
1630 emit2 ("ld !*hl,a");
1633 emit2 ("ld !*hl,%s", s);
1637 if (aop->aopu.aop_stk >= 0)
1638 offset += _G.stack.param_offset;
1639 if (!canAssignToPtr (s))
1641 emit2 ("ld a,%s", s);
1642 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
1646 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
1652 /* if bit variable */
1653 if (!aop->aopu.aop_dir)
1660 /* In bit space but not in C - cant happen */
1661 wassertl (0, "Tried to write into a bit variable");
1667 if (strcmp (aop->aopu.aop_str[offset], s))
1669 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1675 if (!offset && (strcmp (s, "acc") == 0))
1679 wassertl (0, "Tried to access past the end of A");
1683 if (strcmp (aop->aopu.aop_str[offset], s))
1684 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1689 wassert (offset < 2);
1690 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1694 setupPair (aop->aopu.aop_pairId, aop, offset);
1695 emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
1699 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1700 "aopPut got unsupported aop->type");
1705 #define AOP(op) op->aop
1706 #define AOP_TYPE(op) AOP(op)->type
1707 #define AOP_SIZE(op) AOP(op)->size
1708 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
1711 commitPair (asmop * aop, PAIR_ID id)
1713 /* PENDING: Verify this. */
1714 if (id == PAIR_HL && requiresHL (aop) && IS_GB)
1718 aopPut (aop, "a", 0);
1719 aopPut (aop, "d", 1);
1724 if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
1726 char *l = aopGetLitWordLong (aop, 0, FALSE);
1729 emit2 ("ld (%s),%s", l, _pairs[id].name);
1733 aopPut (aop, _pairs[id].l, 0);
1734 aopPut (aop, _pairs[id].h, 1);
1739 /*-----------------------------------------------------------------*/
1740 /* getDataSize - get the operand data size */
1741 /*-----------------------------------------------------------------*/
1743 getDataSize (operand * op)
1746 size = AOP_SIZE (op);
1750 wassertl (0, "Somehow got a three byte data pointer");
1755 /*-----------------------------------------------------------------*/
1756 /* movLeft2Result - move byte from left to result */
1757 /*-----------------------------------------------------------------*/
1759 movLeft2Result (operand * left, int offl,
1760 operand * result, int offr, int sign)
1764 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
1766 l = aopGet (AOP (left), offl, FALSE);
1770 aopPut (AOP (result), l, offr);
1774 if (getDataSize (left) == offl + 1)
1776 emit2 ("ld a,%s", l);
1777 aopPut (AOP (result), "a", offr);
1784 movLeft2ResultLong (operand * left, int offl,
1785 operand * result, int offr, int sign,
1790 movLeft2Result (left, offl, result, offr, sign);
1794 wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
1795 wassertl (size == 2, "Only implemented for two bytes or one");
1797 if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
1799 emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
1800 emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
1803 else if ( getPairId ( AOP (result)) == PAIR_IY)
1805 PAIR_ID id = getPairId (AOP (left));
1806 if (id != PAIR_INVALID)
1808 emit2("push %s", _pairs[id].name);
1819 movLeft2Result (left, offl, result, offr, sign);
1820 movLeft2Result (left, offl+1, result, offr+1, sign);
1825 /** Put Acc into a register set
1828 outAcc (operand * result)
1831 size = getDataSize (result);
1834 aopPut (AOP (result), "a", 0);
1837 /* unsigned or positive */
1840 aopPut (AOP (result), "!zero", offset++);
1845 /** Take the value in carry and put it into a register
1848 outBitCLong (operand * result, bool swap_sense)
1850 /* if the result is bit */
1851 if (AOP_TYPE (result) == AOP_CRY)
1853 wassertl (0, "Tried to write carry to a bit");
1857 emit2 ("ld a,!zero");
1860 emit2 ("xor a,!immedbyte", 1);
1866 outBitC (operand * result)
1868 outBitCLong (result, FALSE);
1871 /*-----------------------------------------------------------------*/
1872 /* toBoolean - emit code for orl a,operator(sizeop) */
1873 /*-----------------------------------------------------------------*/
1875 _toBoolean (operand * oper)
1877 int size = AOP_SIZE (oper);
1881 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
1884 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
1888 if (AOP (oper)->type != AOP_ACC)
1891 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
1896 /*-----------------------------------------------------------------*/
1897 /* genNotFloat - generates not for float operations */
1898 /*-----------------------------------------------------------------*/
1900 genNotFloat (operand * op, operand * res)
1905 emitDebug ("; genNotFloat");
1907 /* we will put 127 in the first byte of
1909 aopPut (AOP (res), "!immedbyte", 0x7F);
1910 size = AOP_SIZE (op) - 1;
1913 _moveA (aopGet (op->aop, offset++, FALSE));
1917 emit2 ("or a,%s", aopGet (op->aop, offset++, FALSE));
1920 tlbl = newiTempLabel (NULL);
1921 aopPut (res->aop, "!one", 1);
1922 emit2 ("!shortjp z !tlabel", tlbl->key + 100);
1923 aopPut (res->aop, "!zero", 1);
1925 emitLabel(tlbl->key + 100);
1927 size = res->aop->size - 2;
1929 /* put zeros in the rest */
1931 aopPut (res->aop, "!zero", offset++);
1934 /*-----------------------------------------------------------------*/
1935 /* genNot - generate code for ! operation */
1936 /*-----------------------------------------------------------------*/
1940 sym_link *optype = operandType (IC_LEFT (ic));
1942 /* assign asmOps to operand & result */
1943 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
1944 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1946 /* if in bit space then a special case */
1947 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1949 wassertl (0, "Tried to negate a bit");
1952 /* if type float then do float */
1953 if (IS_FLOAT (optype))
1955 genNotFloat (IC_LEFT (ic), IC_RESULT (ic));
1959 _toBoolean (IC_LEFT (ic));
1964 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
1965 emit2 ("sub a,!one");
1966 outBitC (IC_RESULT (ic));
1969 /* release the aops */
1970 freeAsmop (IC_LEFT (ic), NULL, ic);
1971 freeAsmop (IC_RESULT (ic), NULL, ic);
1974 /*-----------------------------------------------------------------*/
1975 /* genCpl - generate code for complement */
1976 /*-----------------------------------------------------------------*/
1984 /* assign asmOps to operand & result */
1985 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1986 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1988 /* if both are in bit space then
1990 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1991 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1993 wassertl (0, "Left and the result are in bit space");
1996 size = AOP_SIZE (IC_RESULT (ic));
1999 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2002 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2005 /* release the aops */
2006 freeAsmop (IC_LEFT (ic), NULL, ic);
2007 freeAsmop (IC_RESULT (ic), NULL, ic);
2011 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
2018 store de into result
2023 store de into result
2025 const char *first = isAdd ? "add" : "sub";
2026 const char *later = isAdd ? "adc" : "sbc";
2028 wassertl (IS_GB, "Code is only relevent to the gbz80");
2029 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
2031 fetchPair (PAIR_DE, left);
2034 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
2037 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2040 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2041 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2043 fetchPairLong (PAIR_DE, left, MSB24);
2044 aopGet (right, MSB24, FALSE);
2048 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2051 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2053 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2054 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2058 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2060 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2063 /*-----------------------------------------------------------------*/
2064 /* genUminusFloat - unary minus for floating points */
2065 /*-----------------------------------------------------------------*/
2067 genUminusFloat (operand * op, operand * result)
2069 int size, offset = 0;
2071 emitDebug("; genUminusFloat");
2073 /* for this we just need to flip the
2074 first it then copy the rest in place */
2075 size = AOP_SIZE (op) - 1;
2077 _moveA(aopGet (AOP (op), MSB32, FALSE));
2079 emit2("xor a,!immedbyte", 0x80);
2080 aopPut (AOP (result), "a", MSB32);
2084 aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2089 /*-----------------------------------------------------------------*/
2090 /* genUminus - unary minus code generation */
2091 /*-----------------------------------------------------------------*/
2093 genUminus (iCode * ic)
2096 sym_link *optype, *rtype;
2099 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2100 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2102 /* if both in bit space then special
2104 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2105 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2107 wassertl (0, "Left and right are in bit space");
2111 optype = operandType (IC_LEFT (ic));
2112 rtype = operandType (IC_RESULT (ic));
2114 /* if float then do float stuff */
2115 if (IS_FLOAT (optype))
2117 genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2121 /* otherwise subtract from zero */
2122 size = AOP_SIZE (IC_LEFT (ic));
2124 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2126 /* Create a new asmop with value zero */
2127 asmop *azero = newAsmop (AOP_SIMPLELIT);
2128 azero->aopu.aop_simplelit = 0;
2130 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2138 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2139 emit2 ("ld a,!zero");
2140 emit2 ("sbc a,%s", l);
2141 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2144 /* if any remaining bytes in the result */
2145 /* we just need to propagate the sign */
2146 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2151 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2155 /* release the aops */
2156 freeAsmop (IC_LEFT (ic), NULL, ic);
2157 freeAsmop (IC_RESULT (ic), NULL, ic);
2160 /*-----------------------------------------------------------------*/
2161 /* assignResultValue - */
2162 /*-----------------------------------------------------------------*/
2164 assignResultValue (operand * oper)
2166 int size = AOP_SIZE (oper);
2169 wassertl (size <= 4, "Got a result that is bigger than four bytes");
2170 topInA = requiresHL (AOP (oper));
2172 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2174 /* We do it the hard way here. */
2176 aopPut (AOP (oper), _fReturn[0], 0);
2177 aopPut (AOP (oper), _fReturn[1], 1);
2179 aopPut (AOP (oper), _fReturn[0], 2);
2180 aopPut (AOP (oper), _fReturn[1], 3);
2186 aopPut (AOP (oper), _fReturn[size], size);
2191 /** Simple restore that doesn't take into account what is used in the
2195 _restoreRegsAfterCall(void)
2197 if (_G.stack.pushedDE)
2200 _G.stack.pushedDE = FALSE;
2202 if (_G.stack.pushedBC)
2205 _G.stack.pushedBC = FALSE;
2207 _G.saves.saved = FALSE;
2211 _saveRegsForCall(iCode *ic, int sendSetSize)
2214 o Stack parameters are pushed before this function enters
2215 o DE and BC may be used in this function.
2216 o HL and DE may be used to return the result.
2217 o HL and DE may be used to send variables.
2218 o DE and BC may be used to store the result value.
2219 o HL may be used in computing the sent value of DE
2220 o The iPushes for other parameters occur before any addSets
2222 Logic: (to be run inside the first iPush or if none, before sending)
2223 o Compute if DE and/or BC are in use over the call
2224 o Compute if DE is used in the send set
2225 o Compute if DE and/or BC are used to hold the result value
2226 o If (DE is used, or in the send set) and is not used in the result, push.
2227 o If BC is used and is not in the result, push
2229 o If DE is used in the send set, fetch
2230 o If HL is used in the send set, fetch
2234 if (_G.saves.saved == FALSE) {
2235 bool deInUse, bcInUse;
2237 bool bcInRet = FALSE, deInRet = FALSE;
2240 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
2242 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2243 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2245 deSending = (sendSetSize > 1);
2247 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2249 if (bcInUse && bcInRet == FALSE) {
2251 _G.stack.pushedBC = TRUE;
2253 if (deInUse && deInRet == FALSE) {
2255 _G.stack.pushedDE = TRUE;
2258 _G.saves.saved = TRUE;
2261 /* Already saved. */
2265 /*-----------------------------------------------------------------*/
2266 /* genIpush - genrate code for pushing this gets a little complex */
2267 /*-----------------------------------------------------------------*/
2269 genIpush (iCode * ic)
2271 int size, offset = 0;
2274 /* if this is not a parm push : ie. it is spill push
2275 and spill push is always done on the local stack */
2278 wassertl(0, "Encountered an unsupported spill push.");
2282 if (_G.saves.saved == FALSE) {
2283 /* Caller saves, and this is the first iPush. */
2284 /* Scan ahead until we find the function that we are pushing parameters to.
2285 Count the number of addSets on the way to figure out what registers
2286 are used in the send set.
2289 iCode *walk = ic->next;
2292 if (walk->op == SEND) {
2295 else if (walk->op == CALL || walk->op == PCALL) {
2304 _saveRegsForCall(walk, nAddSets);
2307 /* Already saved by another iPush. */
2310 /* then do the push */
2311 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2313 size = AOP_SIZE (IC_LEFT (ic));
2315 if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2317 _G.stack.pushed += 2;
2318 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2324 fetchHL (AOP (IC_LEFT (ic)));
2326 spillPair (PAIR_HL);
2327 _G.stack.pushed += 2;
2332 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
2334 spillPair (PAIR_HL);
2335 _G.stack.pushed += 2;
2336 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 0);
2338 spillPair (PAIR_HL);
2339 _G.stack.pushed += 2;
2345 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2347 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2349 emit2 ("ld a,(%s)", l);
2353 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2354 emit2 ("ld a,%s", l);
2362 freeAsmop (IC_LEFT (ic), NULL, ic);
2365 /*-----------------------------------------------------------------*/
2366 /* genIpop - recover the registers: can happen only for spilling */
2367 /*-----------------------------------------------------------------*/
2369 genIpop (iCode * ic)
2374 /* if the temp was not pushed then */
2375 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2378 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2379 size = AOP_SIZE (IC_LEFT (ic));
2380 offset = (size - 1);
2381 if (isPair (AOP (IC_LEFT (ic))))
2383 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2391 spillPair (PAIR_HL);
2392 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2396 freeAsmop (IC_LEFT (ic), NULL, ic);
2399 /* This is quite unfortunate */
2401 setArea (int inHome)
2404 static int lastArea = 0;
2406 if (_G.in_home != inHome) {
2408 const char *sz = port->mem.code_name;
2409 port->mem.code_name = "HOME";
2410 emit2("!area", CODE_NAME);
2411 port->mem.code_name = sz;
2414 emit2("!area", CODE_NAME); */
2415 _G.in_home = inHome;
2426 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2430 symbol *sym = OP_SYMBOL (op);
2432 if (sym->isspilt || sym->nRegs == 0)
2435 aopOp (op, ic, FALSE, FALSE);
2438 if (aop->type == AOP_REG)
2441 for (i = 0; i < aop->size; i++)
2443 if (pairId == PAIR_DE)
2445 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2446 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2448 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2451 else if (pairId == PAIR_BC)
2453 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2454 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2456 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2466 freeAsmop (IC_LEFT (ic), NULL, ic);
2470 /** Emit the code for a call statement
2473 emitCall (iCode * ic, bool ispcall)
2475 sym_link *dtype = operandType (IC_LEFT (ic));
2477 /* if caller saves & we have not saved then */
2483 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2485 /* if send set is not empty then assign */
2490 int nSend = elementsInSet(_G.sendSet);
2491 bool swapped = FALSE;
2493 int _z80_sendOrder[] = {
2498 /* Check if the parameters are swapped. If so route through hl instead. */
2499 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2501 sic = setFirstItem(_G.sendSet);
2502 sic = setNextItem(_G.sendSet);
2504 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2505 /* The second send value is loaded from one the one that holds the first
2506 send, i.e. it is overwritten. */
2507 /* Cache the first in HL, and load the second from HL instead. */
2508 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2509 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2515 for (sic = setFirstItem (_G.sendSet); sic;
2516 sic = setNextItem (_G.sendSet))
2519 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2521 size = AOP_SIZE (IC_LEFT (sic));
2522 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2523 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2525 // PENDING: Mild hack
2526 if (swapped == TRUE && send == 1) {
2528 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2531 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2533 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2536 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2540 freeAsmop (IC_LEFT (sic), NULL, sic);
2547 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2549 werror (W_INDIR_BANKED);
2551 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2553 if (isLitWord (AOP (IC_LEFT (ic))))
2555 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2559 symbol *rlbl = newiTempLabel (NULL);
2560 spillPair (PAIR_HL);
2561 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2563 _G.stack.pushed += 2;
2565 fetchHL (AOP (IC_LEFT (ic)));
2567 emit2 ("!tlabeldef", (rlbl->key + 100));
2568 _G.stack.pushed -= 2;
2570 freeAsmop (IC_LEFT (ic), NULL, ic);
2574 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2575 OP_SYMBOL (IC_LEFT (ic))->rname :
2576 OP_SYMBOL (IC_LEFT (ic))->name;
2577 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2579 emit2 ("call banked_call");
2580 emit2 ("!dws", name);
2581 emit2 ("!dw !bankimmeds", name);
2586 emit2 ("call %s", name);
2591 /* Mark the regsiters as restored. */
2592 _G.saves.saved = FALSE;
2594 /* if we need assign a result value */
2595 if ((IS_ITEMP (IC_RESULT (ic)) &&
2596 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2597 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2598 IS_TRUE_SYMOP (IC_RESULT (ic)))
2601 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2603 assignResultValue (IC_RESULT (ic));
2605 freeAsmop (IC_RESULT (ic), NULL, ic);
2608 /* adjust the stack for parameters if required */
2611 int i = ic->parmBytes;
2613 _G.stack.pushed -= i;
2616 emit2 ("!ldaspsp", i);
2623 emit2 ("ld iy,#%d", i);
2624 emit2 ("add iy,sp");
2644 if (_G.stack.pushedDE)
2646 bool dInRet = bitVectBitValue(ic->rUsed, D_IDX);
2647 bool eInRet = bitVectBitValue(ic->rUsed, E_IDX);
2649 if (dInRet && eInRet)
2651 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
2655 /* Only restore E */
2662 /* Only restore D */
2670 _G.stack.pushedDE = FALSE;
2673 if (_G.stack.pushedBC)
2675 bool bInRet = bitVectBitValue(ic->rUsed, B_IDX);
2676 bool cInRet = bitVectBitValue(ic->rUsed, C_IDX);
2678 if (bInRet && cInRet)
2680 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
2684 /* Only restore C */
2691 /* Only restore B */
2699 _G.stack.pushedBC = FALSE;
2703 /*-----------------------------------------------------------------*/
2704 /* genCall - generates a call statement */
2705 /*-----------------------------------------------------------------*/
2707 genCall (iCode * ic)
2709 emitCall (ic, FALSE);
2712 /*-----------------------------------------------------------------*/
2713 /* genPcall - generates a call by pointer statement */
2714 /*-----------------------------------------------------------------*/
2716 genPcall (iCode * ic)
2718 emitCall (ic, TRUE);
2721 /*-----------------------------------------------------------------*/
2722 /* resultRemat - result is rematerializable */
2723 /*-----------------------------------------------------------------*/
2725 resultRemat (iCode * ic)
2727 if (SKIP_IC (ic) || ic->op == IFX)
2730 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2732 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2733 if (sym->remat && !POINTER_SET (ic))
2740 extern set *publics;
2742 /*-----------------------------------------------------------------*/
2743 /* genFunction - generated code for function entry */
2744 /*-----------------------------------------------------------------*/
2746 genFunction (iCode * ic)
2748 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2752 bool bcInUse = FALSE;
2753 bool deInUse = FALSE;
2756 setArea (IFFUNC_NONBANKED (sym->type));
2758 /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
2761 _G.receiveOffset = 0;
2763 /* Record the last function name for debugging. */
2764 _G.lastFunctionName = sym->rname;
2766 /* Create the function header */
2767 emit2 ("!functionheader", sym->name);
2768 /* PENDING: portability. */
2769 emit2 ("__%s_start:", sym->rname);
2770 emit2 ("!functionlabeldef", sym->rname);
2772 if (options.profile)
2774 emit2 ("!profileenter");
2777 ftype = operandType (IC_LEFT (ic));
2779 /* if critical function then turn interrupts off */
2780 if (IFFUNC_ISCRITICAL (ftype))
2783 /* if this is an interrupt service routine then save all potentially used registers. */
2784 if (IFFUNC_ISISR (sym->type))
2789 /* PENDING: callee-save etc */
2791 _G.stack.param_offset = 0;
2794 /* Detect which registers are used. */
2798 for (i = 0; i < sym->regsUsed->size; i++)
2800 if (bitVectBitValue (sym->regsUsed, i))
2814 /* Other systems use DE as a temporary. */
2825 _G.stack.param_offset += 2;
2828 _G.stack.pushedBC = bcInUse;
2833 _G.stack.param_offset += 2;
2836 _G.stack.pushedDE = deInUse;
2839 /* adjust the stack for the function */
2840 _G.stack.last = sym->stack;
2842 if (sym->stack && IS_GB && sym->stack > -INT8MIN)
2843 emit2 ("!enterxl", sym->stack);
2844 else if (sym->stack)
2845 emit2 ("!enterx", sym->stack);
2848 _G.stack.offset = sym->stack;
2851 /*-----------------------------------------------------------------*/
2852 /* genEndFunction - generates epilogue for functions */
2853 /*-----------------------------------------------------------------*/
2855 genEndFunction (iCode * ic)
2857 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2859 if (IFFUNC_ISISR (sym->type))
2861 wassertl (0, "Tried to close an interrupt support function");
2865 if (IFFUNC_ISCRITICAL (sym->type))
2868 /* PENDING: calleeSave */
2870 if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
2872 emit2 ("!leavexl", _G.stack.offset);
2874 else if (_G.stack.offset)
2876 emit2 ("!leavex", _G.stack.offset);
2884 if (_G.stack.pushedDE)
2887 _G.stack.pushedDE = FALSE;
2890 if (_G.stack.pushedDE)
2893 _G.stack.pushedDE = FALSE;
2897 if (options.profile)
2899 emit2 ("!profileexit");
2903 /* Both baned and non-banked just ret */
2906 /* PENDING: portability. */
2907 emit2 ("__%s_end:", sym->rname);
2909 _G.flushStatics = 1;
2910 _G.stack.pushed = 0;
2911 _G.stack.offset = 0;
2914 /*-----------------------------------------------------------------*/
2915 /* genRet - generate code for return statement */
2916 /*-----------------------------------------------------------------*/
2921 /* Errk. This is a hack until I can figure out how
2922 to cause dehl to spill on a call */
2923 int size, offset = 0;
2925 /* if we have no return value then
2926 just generate the "ret" */
2930 /* we have something to return then
2931 move the return value into place */
2932 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2933 size = AOP_SIZE (IC_LEFT (ic));
2935 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
2939 emit2 ("ld de,%s", l);
2943 emit2 ("ld hl,%s", l);
2948 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
2950 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
2951 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
2957 l = aopGet (AOP (IC_LEFT (ic)), offset,
2959 if (strcmp (_fReturn[offset], l))
2960 emit2 ("ld %s,%s", _fReturn[offset++], l);
2964 freeAsmop (IC_LEFT (ic), NULL, ic);
2967 /* generate a jump to the return label
2968 if the next is not the return statement */
2969 if (!(ic->next && ic->next->op == LABEL &&
2970 IC_LABEL (ic->next) == returnLabel))
2972 emit2 ("jp !tlabel", returnLabel->key + 100);
2975 /*-----------------------------------------------------------------*/
2976 /* genLabel - generates a label */
2977 /*-----------------------------------------------------------------*/
2979 genLabel (iCode * ic)
2981 /* special case never generate */
2982 if (IC_LABEL (ic) == entryLabel)
2985 emitLabel (IC_LABEL (ic)->key + 100);
2988 /*-----------------------------------------------------------------*/
2989 /* genGoto - generates a ljmp */
2990 /*-----------------------------------------------------------------*/
2992 genGoto (iCode * ic)
2994 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
2997 /*-----------------------------------------------------------------*/
2998 /* genPlusIncr :- does addition with increment if possible */
2999 /*-----------------------------------------------------------------*/
3001 genPlusIncr (iCode * ic)
3003 unsigned int icount;
3004 unsigned int size = getDataSize (IC_RESULT (ic));
3005 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3007 /* will try to generate an increment */
3008 /* if the right side is not a literal
3010 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3013 emitDebug ("; genPlusIncr");
3015 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3017 /* If result is a pair */
3018 if (resultId != PAIR_INVALID)
3020 if (isLitWord (AOP (IC_LEFT (ic))))
3022 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3025 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3027 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3029 PAIR_ID freep = getFreePairId (ic);
3030 if (freep != PAIR_INVALID)
3032 fetchPair (freep, AOP (IC_RIGHT (ic)));
3033 emit2 ("add hl,%s", _pairs[freep].name);
3039 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3040 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3047 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3051 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3055 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3060 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3062 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3063 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3067 /* if the literal value of the right hand side
3068 is greater than 4 then it is not worth it */
3072 /* if increment 16 bits in register */
3073 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3079 symbol *tlbl = NULL;
3080 tlbl = newiTempLabel (NULL);
3083 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3086 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3089 emitLabel (tlbl->key + 100);
3093 /* if the sizes are greater than 1 then we cannot */
3094 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3095 AOP_SIZE (IC_LEFT (ic)) > 1)
3098 /* If the result is in a register then we can load then increment.
3100 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3102 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3105 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3110 /* we can if the aops of the left & result match or
3111 if they are in registers and the registers are the
3113 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3117 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3125 /*-----------------------------------------------------------------*/
3126 /* outBitAcc - output a bit in acc */
3127 /*-----------------------------------------------------------------*/
3129 outBitAcc (operand * result)
3131 symbol *tlbl = newiTempLabel (NULL);
3132 /* if the result is a bit */
3133 if (AOP_TYPE (result) == AOP_CRY)
3135 wassertl (0, "Tried to write A into a bit");
3139 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3140 emit2 ("ld a,!one");
3141 emitLabel (tlbl->key + 100);
3147 couldDestroyCarry (asmop *aop)
3151 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3160 shiftIntoPair (int idx, asmop *aop)
3162 PAIR_ID id = PAIR_INVALID;
3164 wassertl (IS_Z80, "Only implemented for the Z80");
3165 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3177 wassertl (0, "Internal error - hit default case");
3180 emitDebug ("; Shift into pair idx %u", idx);
3184 setupPair (PAIR_HL, aop, 0);
3188 setupPair (PAIR_IY, aop, 0);
3190 emit2 ("pop %s", _pairs[id].name);
3193 aop->type = AOP_PAIRPTR;
3194 aop->aopu.aop_pairId = id;
3195 _G.pairs[id].offset = 0;
3196 _G.pairs[id].last_type = aop->type;
3200 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
3202 wassert (left && right);
3206 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3208 shiftIntoPair (0, right);
3209 shiftIntoPair (1, result);
3211 else if (couldDestroyCarry (right))
3213 shiftIntoPair (0, right);
3215 else if (couldDestroyCarry (result))
3217 shiftIntoPair (0, result);
3226 /*-----------------------------------------------------------------*/
3227 /* genPlus - generates code for addition */
3228 /*-----------------------------------------------------------------*/
3230 genPlus (iCode * ic)
3232 int size, offset = 0;
3234 /* special cases :- */
3236 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3237 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3238 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3240 /* Swap the left and right operands if:
3242 if literal, literal on the right or
3243 if left requires ACC or right is already
3246 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3247 (AOP_NEEDSACC (IC_LEFT (ic))) ||
3248 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3250 operand *t = IC_RIGHT (ic);
3251 IC_RIGHT (ic) = IC_LEFT (ic);
3255 /* if both left & right are in bit
3257 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3258 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3261 wassertl (0, "Tried to add two bits");
3264 /* if left in bit space & right literal */
3265 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3266 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3268 /* Can happen I guess */
3269 wassertl (0, "Tried to add a bit to a literal");
3272 /* if I can do an increment instead
3273 of add then GOOD for ME */
3274 if (genPlusIncr (ic) == TRUE)
3277 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3279 size = getDataSize (IC_RESULT (ic));
3281 /* Special case when left and right are constant */
3282 if (isPair (AOP (IC_RESULT (ic))))
3285 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3286 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3288 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3294 sprintf (buffer, "#(%s + %s)", left, right);
3295 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3300 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3302 /* Fetch into HL then do the add */
3303 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3304 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3306 spillPair (PAIR_HL);
3308 if (left == PAIR_HL && right != PAIR_INVALID)
3310 emit2 ("add hl,%s", _pairs[right].name);
3313 else if (right == PAIR_HL && left != PAIR_INVALID)
3315 emit2 ("add hl,%s", _pairs[left].name);
3318 else if (right != PAIR_INVALID && right != PAIR_HL)
3320 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3321 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3324 else if (left != PAIR_INVALID && left != PAIR_HL)
3326 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3327 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3336 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3338 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3339 emit2 ("add hl,%s ; 2", getPairName (AOP (IC_RIGHT (ic))));
3341 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3346 ld hl,sp+n trashes C so we cant afford to do it during an
3347 add with stack based varibles. Worst case is:
3360 So you cant afford to load up hl if either left, right, or result
3361 is on the stack (*sigh*) The alt is:
3369 Combinations in here are:
3370 * If left or right are in bc then the loss is small - trap later
3371 * If the result is in bc then the loss is also small
3375 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3376 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3377 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3379 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3380 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3381 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3382 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3384 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3386 /* Swap left and right */
3387 operand *t = IC_RIGHT (ic);
3388 IC_RIGHT (ic) = IC_LEFT (ic);
3391 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3393 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3394 emit2 ("add hl,bc");
3398 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3399 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3400 emit2 ("add hl,de");
3402 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3408 /* Be paranoid on the GB with 4 byte variables due to how C
3409 can be trashed by lda hl,n(sp).
3411 _gbz80_emitAddSubLong (ic, TRUE);
3416 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3420 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3422 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3425 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3428 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3432 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3435 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3438 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3440 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3444 freeAsmop (IC_LEFT (ic), NULL, ic);
3445 freeAsmop (IC_RIGHT (ic), NULL, ic);
3446 freeAsmop (IC_RESULT (ic), NULL, ic);
3450 /*-----------------------------------------------------------------*/
3451 /* genMinusDec :- does subtraction with deccrement if possible */
3452 /*-----------------------------------------------------------------*/
3454 genMinusDec (iCode * ic)
3456 unsigned int icount;
3457 unsigned int size = getDataSize (IC_RESULT (ic));
3459 /* will try to generate an increment */
3460 /* if the right side is not a literal we cannot */
3461 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3464 /* if the literal value of the right hand side
3465 is greater than 4 then it is not worth it */
3466 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3469 size = getDataSize (IC_RESULT (ic));
3471 /* if decrement 16 bits in register */
3472 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3473 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3476 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3480 /* If result is a pair */
3481 if (isPair (AOP (IC_RESULT (ic))))
3483 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3485 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3489 /* if increment 16 bits in register */
3490 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3494 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3497 emit2 ("dec %s", _getTempPairName());
3500 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3506 /* if the sizes are greater than 1 then we cannot */
3507 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3508 AOP_SIZE (IC_LEFT (ic)) > 1)
3511 /* we can if the aops of the left & result match or if they are in
3512 registers and the registers are the same */
3513 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3516 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3523 /*-----------------------------------------------------------------*/
3524 /* genMinus - generates code for subtraction */
3525 /*-----------------------------------------------------------------*/
3527 genMinus (iCode * ic)
3529 int size, offset = 0;
3530 unsigned long lit = 0L;
3532 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3533 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3534 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3536 /* special cases :- */
3537 /* if both left & right are in bit space */
3538 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3539 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3541 wassertl (0, "Tried to subtract two bits");
3545 /* if I can do an decrement instead of subtract then GOOD for ME */
3546 if (genMinusDec (ic) == TRUE)
3549 size = getDataSize (IC_RESULT (ic));
3551 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3556 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3560 /* Same logic as genPlus */
3563 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3564 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3565 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3567 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3568 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3569 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3570 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3572 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3573 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3575 if (left == PAIR_INVALID && right == PAIR_INVALID)
3580 else if (right == PAIR_INVALID)
3582 else if (left == PAIR_INVALID)
3585 fetchPair (left, AOP (IC_LEFT (ic)));
3586 /* Order is important. Right may be HL */
3587 fetchPair (right, AOP (IC_RIGHT (ic)));
3589 emit2 ("ld a,%s", _pairs[left].l);
3590 emit2 ("sub a,%s", _pairs[right].l);
3592 emit2 ("ld a,%s", _pairs[left].h);
3593 emit2 ("sbc a,%s", _pairs[right].h);
3595 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
3597 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3599 aopPut (AOP (IC_RESULT (ic)), "e", 0);
3605 /* Be paranoid on the GB with 4 byte variables due to how C
3606 can be trashed by lda hl,n(sp).
3608 _gbz80_emitAddSubLong (ic, FALSE);
3613 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3615 /* if literal, add a,#-lit, else normal subb */
3618 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3619 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3623 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3626 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3630 /* first add without previous c */
3632 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
3634 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3636 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3639 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3640 AOP_SIZE (IC_LEFT (ic)) == 3 &&
3641 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3643 wassertl (0, "Tried to subtract on a long pointer");
3647 freeAsmop (IC_LEFT (ic), NULL, ic);
3648 freeAsmop (IC_RIGHT (ic), NULL, ic);
3649 freeAsmop (IC_RESULT (ic), NULL, ic);
3652 /*-----------------------------------------------------------------*/
3653 /* genMult - generates code for multiplication */
3654 /*-----------------------------------------------------------------*/
3656 genMult (iCode * ic)
3660 /* If true then the final operation should be a subtract */
3661 bool active = FALSE;
3663 /* Shouldn't occur - all done through function calls */
3664 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3665 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3666 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3668 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
3669 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
3670 AOP_SIZE (IC_RESULT (ic)) > 2)
3672 wassertl (0, "Multiplication is handled through support function calls");
3675 /* Swap left and right such that right is a literal */
3676 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
3678 operand *t = IC_RIGHT (ic);
3679 IC_RIGHT (ic) = IC_LEFT (ic);
3683 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
3685 val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
3686 // wassertl (val > 0, "Multiply must be positive");
3687 wassertl (val != 1, "Can't multiply by 1");
3693 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
3695 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
3703 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3708 /* Fully unroled version of mul.s. Not the most efficient.
3710 for (count = 0; count < 16; count++)
3712 if (count != 0 && active)
3714 emit2 ("add hl,hl");
3718 if (active == FALSE)
3725 emit2 ("add hl,de");
3739 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3741 freeAsmop (IC_LEFT (ic), NULL, ic);
3742 freeAsmop (IC_RIGHT (ic), NULL, ic);
3743 freeAsmop (IC_RESULT (ic), NULL, ic);
3746 /*-----------------------------------------------------------------*/
3747 /* genDiv - generates code for division */
3748 /*-----------------------------------------------------------------*/
3752 /* Shouldn't occur - all done through function calls */
3753 wassertl (0, "Division is handled through support function calls");
3756 /*-----------------------------------------------------------------*/
3757 /* genMod - generates code for division */
3758 /*-----------------------------------------------------------------*/
3762 /* Shouldn't occur - all done through function calls */
3766 /*-----------------------------------------------------------------*/
3767 /* genIfxJump :- will create a jump depending on the ifx */
3768 /*-----------------------------------------------------------------*/
3770 genIfxJump (iCode * ic, char *jval)
3775 /* if true label then we jump if condition
3779 jlbl = IC_TRUE (ic);
3780 if (!strcmp (jval, "a"))
3784 else if (!strcmp (jval, "c"))
3788 else if (!strcmp (jval, "nc"))
3792 else if (!strcmp (jval, "m"))
3796 else if (!strcmp (jval, "p"))
3802 /* The buffer contains the bit on A that we should test */
3808 /* false label is present */
3809 jlbl = IC_FALSE (ic);
3810 if (!strcmp (jval, "a"))
3814 else if (!strcmp (jval, "c"))
3818 else if (!strcmp (jval, "nc"))
3822 else if (!strcmp (jval, "m"))
3826 else if (!strcmp (jval, "p"))
3832 /* The buffer contains the bit on A that we should test */
3836 /* Z80 can do a conditional long jump */
3837 if (!strcmp (jval, "a"))
3841 else if (!strcmp (jval, "c"))
3844 else if (!strcmp (jval, "nc"))
3847 else if (!strcmp (jval, "m"))
3850 else if (!strcmp (jval, "p"))
3855 emit2 ("bit %s,a", jval);
3857 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
3859 /* mark the icode as generated */
3865 _getPairIdName (PAIR_ID id)
3867 return _pairs[id].name;
3872 /* if unsigned char cmp with lit, just compare */
3874 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
3876 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3879 emit2 ("xor a,!immedbyte", 0x80);
3880 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
3883 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3885 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
3887 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
3888 // Pull left into DE and right into HL
3889 aopGet (AOP(left), LSB, FALSE);
3892 aopGet (AOP(right), LSB, FALSE);
3896 if (size == 0 && sign)
3898 // Highest byte when signed needs the bits flipped
3901 emit2 ("ld a,(de)");
3902 emit2 ("xor #0x80");
3904 emit2 ("ld a,(hl)");
3905 emit2 ("xor #0x80");
3909 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
3913 emit2 ("ld a,(de)");
3914 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
3924 spillPair (PAIR_HL);
3926 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
3928 setupPair (PAIR_HL, AOP (left), 0);
3929 aopGet (AOP(right), LSB, FALSE);
3933 if (size == 0 && sign)
3935 // Highest byte when signed needs the bits flipped
3938 emit2 ("ld a,(hl)");
3939 emit2 ("xor #0x80");
3941 emit2 ("ld a,%d(iy)", offset);
3942 emit2 ("xor #0x80");
3946 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
3950 emit2 ("ld a,(hl)");
3951 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
3960 spillPair (PAIR_HL);
3961 spillPair (PAIR_IY);
3965 if (AOP_TYPE (right) == AOP_LIT)
3967 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3968 /* optimize if(x < 0) or if(x >= 0) */
3973 /* No sign so it's always false */
3978 /* Just load in the top most bit */
3979 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
3980 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
3982 genIfxJump (ifx, "7");
3994 /* First setup h and l contaning the top most bytes XORed */
3995 bool fDidXor = FALSE;
3996 if (AOP_TYPE (left) == AOP_LIT)
3998 unsigned long lit = (unsigned long)
3999 floatFromVal (AOP (left)->aopu.aop_lit);
4000 emit2 ("ld %s,!immedbyte", _fTmp[0],
4001 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4005 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4006 emit2 ("xor a,!immedbyte", 0x80);
4007 emit2 ("ld %s,a", _fTmp[0]);
4010 if (AOP_TYPE (right) == AOP_LIT)
4012 unsigned long lit = (unsigned long)
4013 floatFromVal (AOP (right)->aopu.aop_lit);
4014 emit2 ("ld %s,!immedbyte", _fTmp[1],
4015 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4019 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4020 emit2 ("xor a,!immedbyte", 0x80);
4021 emit2 ("ld %s,a", _fTmp[1]);
4027 /* Do a long subtract */
4030 _moveA (aopGet (AOP (left), offset, FALSE));
4032 if (sign && size == 0)
4034 emit2 ("ld a,%s", _fTmp[0]);
4035 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4039 /* Subtract through, propagating the carry */
4040 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4048 /** Generic compare for > or <
4051 genCmp (operand * left, operand * right,
4052 operand * result, iCode * ifx, int sign)
4054 int size, offset = 0;
4055 unsigned long lit = 0L;
4056 bool swap_sense = FALSE;
4058 /* if left & right are bit variables */
4059 if (AOP_TYPE (left) == AOP_CRY &&
4060 AOP_TYPE (right) == AOP_CRY)
4062 /* Cant happen on the Z80 */
4063 wassertl (0, "Tried to compare two bits");
4067 /* Do a long subtract of right from left. */
4068 size = max (AOP_SIZE (left), AOP_SIZE (right));
4070 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4072 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4073 // Pull left into DE and right into HL
4074 aopGet (AOP(left), LSB, FALSE);
4077 aopGet (AOP(right), LSB, FALSE);
4081 emit2 ("ld a,(de)");
4082 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4091 spillPair (PAIR_HL);
4095 if (AOP_TYPE (right) == AOP_LIT)
4097 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4098 /* optimize if(x < 0) or if(x >= 0) */
4103 /* No sign so it's always false */
4108 /* Just load in the top most bit */
4109 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4110 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4112 genIfxJump (ifx, "7");
4123 genIfxJump (ifx, swap_sense ? "c" : "nc");
4134 _moveA (aopGet (AOP (left), offset, FALSE));
4135 /* Subtract through, propagating the carry */
4136 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4142 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4146 /* Shift the sign bit up into carry */
4149 outBitCLong (result, swap_sense);
4153 /* if the result is used in the next
4154 ifx conditional branch then generate
4155 code a little differently */
4163 genIfxJump (ifx, swap_sense ? "nc" : "c");
4167 genIfxJump (ifx, swap_sense ? "p" : "m");
4172 genIfxJump (ifx, swap_sense ? "nc" : "c");
4179 /* Shift the sign bit up into carry */
4182 outBitCLong (result, swap_sense);
4184 /* leave the result in acc */
4188 /*-----------------------------------------------------------------*/
4189 /* genCmpGt :- greater than comparison */
4190 /*-----------------------------------------------------------------*/
4192 genCmpGt (iCode * ic, iCode * ifx)
4194 operand *left, *right, *result;
4195 sym_link *letype, *retype;
4198 left = IC_LEFT (ic);
4199 right = IC_RIGHT (ic);
4200 result = IC_RESULT (ic);
4202 letype = getSpec (operandType (left));
4203 retype = getSpec (operandType (right));
4204 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4205 /* assign the amsops */
4206 aopOp (left, ic, FALSE, FALSE);
4207 aopOp (right, ic, FALSE, FALSE);
4208 aopOp (result, ic, TRUE, FALSE);
4210 genCmp (right, left, result, ifx, sign);
4212 freeAsmop (left, NULL, ic);
4213 freeAsmop (right, NULL, ic);
4214 freeAsmop (result, NULL, ic);
4217 /*-----------------------------------------------------------------*/
4218 /* genCmpLt - less than comparisons */
4219 /*-----------------------------------------------------------------*/
4221 genCmpLt (iCode * ic, iCode * ifx)
4223 operand *left, *right, *result;
4224 sym_link *letype, *retype;
4227 left = IC_LEFT (ic);
4228 right = IC_RIGHT (ic);
4229 result = IC_RESULT (ic);
4231 letype = getSpec (operandType (left));
4232 retype = getSpec (operandType (right));
4233 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4235 /* assign the amsops */
4236 aopOp (left, ic, FALSE, FALSE);
4237 aopOp (right, ic, FALSE, FALSE);
4238 aopOp (result, ic, TRUE, FALSE);
4240 genCmp (left, right, result, ifx, sign);
4242 freeAsmop (left, NULL, ic);
4243 freeAsmop (right, NULL, ic);
4244 freeAsmop (result, NULL, ic);
4247 /*-----------------------------------------------------------------*/
4248 /* gencjneshort - compare and jump if not equal */
4249 /*-----------------------------------------------------------------*/
4251 gencjneshort (operand * left, operand * right, symbol * lbl)
4253 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4255 unsigned long lit = 0L;
4257 /* Swap the left and right if it makes the computation easier */
4258 if (AOP_TYPE (left) == AOP_LIT)
4265 if (AOP_TYPE (right) == AOP_LIT)
4267 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4270 /* if the right side is a literal then anything goes */
4271 if (AOP_TYPE (right) == AOP_LIT &&
4272 AOP_TYPE (left) != AOP_DIR)
4276 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4281 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4288 emit2 ("jp nz,!tlabel", lbl->key + 100);
4294 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4295 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
4298 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
4299 emit2 ("jp nz,!tlabel", lbl->key + 100);
4304 /* if the right side is in a register or in direct space or
4305 if the left is a pointer register & right is not */
4306 else if (AOP_TYPE (right) == AOP_REG ||
4307 AOP_TYPE (right) == AOP_DIR ||
4308 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
4312 _moveA (aopGet (AOP (left), offset, FALSE));
4313 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
4314 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4316 emit2 ("jp nz,!tlabel", lbl->key + 100);
4319 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4320 emit2 ("jp nz,!tlabel", lbl->key + 100);
4327 /* right is a pointer reg need both a & b */
4328 /* PENDING: is this required? */
4331 _moveA (aopGet (AOP (right), offset, FALSE));
4332 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
4333 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
4339 /*-----------------------------------------------------------------*/
4340 /* gencjne - compare and jump if not equal */
4341 /*-----------------------------------------------------------------*/
4343 gencjne (operand * left, operand * right, symbol * lbl)
4345 symbol *tlbl = newiTempLabel (NULL);
4347 gencjneshort (left, right, lbl);
4350 emit2 ("ld a,!one");
4351 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4352 emitLabel (lbl->key + 100);
4354 emitLabel (tlbl->key + 100);
4357 /*-----------------------------------------------------------------*/
4358 /* genCmpEq - generates code for equal to */
4359 /*-----------------------------------------------------------------*/
4361 genCmpEq (iCode * ic, iCode * ifx)
4363 operand *left, *right, *result;
4365 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4366 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4367 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4369 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4371 /* Swap operands if it makes the operation easier. ie if:
4372 1. Left is a literal.
4374 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4376 operand *t = IC_RIGHT (ic);
4377 IC_RIGHT (ic) = IC_LEFT (ic);
4381 if (ifx && !AOP_SIZE (result))
4384 /* if they are both bit variables */
4385 if (AOP_TYPE (left) == AOP_CRY &&
4386 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4388 wassertl (0, "Tried to compare two bits");
4392 tlbl = newiTempLabel (NULL);
4393 gencjneshort (left, right, tlbl);
4396 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4397 emitLabel (tlbl->key + 100);
4401 /* PENDING: do this better */
4402 symbol *lbl = newiTempLabel (NULL);
4403 emit2 ("!shortjp !tlabel", lbl->key + 100);
4404 emitLabel (tlbl->key + 100);
4405 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4406 emitLabel (lbl->key + 100);
4409 /* mark the icode as generated */
4414 /* if they are both bit variables */
4415 if (AOP_TYPE (left) == AOP_CRY &&
4416 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4418 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4424 gencjne (left, right, newiTempLabel (NULL));
4425 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4432 genIfxJump (ifx, "a");
4435 /* if the result is used in an arithmetic operation
4436 then put the result in place */
4437 if (AOP_TYPE (result) != AOP_CRY)
4442 /* leave the result in acc */
4446 freeAsmop (left, NULL, ic);
4447 freeAsmop (right, NULL, ic);
4448 freeAsmop (result, NULL, ic);
4451 /*-----------------------------------------------------------------*/
4452 /* ifxForOp - returns the icode containing the ifx for operand */
4453 /*-----------------------------------------------------------------*/
4455 ifxForOp (operand * op, iCode * ic)
4457 /* if true symbol then needs to be assigned */
4458 if (IS_TRUE_SYMOP (op))
4461 /* if this has register type condition and
4462 the next instruction is ifx with the same operand
4463 and live to of the operand is upto the ifx only then */
4465 ic->next->op == IFX &&
4466 IC_COND (ic->next)->key == op->key &&
4467 OP_SYMBOL (op)->liveTo <= ic->next->seq)
4473 /*-----------------------------------------------------------------*/
4474 /* genAndOp - for && operation */
4475 /*-----------------------------------------------------------------*/
4477 genAndOp (iCode * ic)
4479 operand *left, *right, *result;
4482 /* note here that && operations that are in an if statement are
4483 taken away by backPatchLabels only those used in arthmetic
4484 operations remain */
4485 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4486 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4487 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4489 /* if both are bit variables */
4490 if (AOP_TYPE (left) == AOP_CRY &&
4491 AOP_TYPE (right) == AOP_CRY)
4493 wassertl (0, "Tried to and two bits");
4497 tlbl = newiTempLabel (NULL);
4499 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
4501 emitLabel (tlbl->key + 100);
4505 freeAsmop (left, NULL, ic);
4506 freeAsmop (right, NULL, ic);
4507 freeAsmop (result, NULL, ic);
4510 /*-----------------------------------------------------------------*/
4511 /* genOrOp - for || operation */
4512 /*-----------------------------------------------------------------*/
4514 genOrOp (iCode * ic)
4516 operand *left, *right, *result;
4519 /* note here that || operations that are in an
4520 if statement are taken away by backPatchLabels
4521 only those used in arthmetic operations remain */
4522 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4523 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4524 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4526 /* if both are bit variables */
4527 if (AOP_TYPE (left) == AOP_CRY &&
4528 AOP_TYPE (right) == AOP_CRY)
4530 wassertl (0, "Tried to OR two bits");
4534 tlbl = newiTempLabel (NULL);
4536 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4538 emitLabel (tlbl->key + 100);
4542 freeAsmop (left, NULL, ic);
4543 freeAsmop (right, NULL, ic);
4544 freeAsmop (result, NULL, ic);
4547 /*-----------------------------------------------------------------*/
4548 /* isLiteralBit - test if lit == 2^n */
4549 /*-----------------------------------------------------------------*/
4551 isLiteralBit (unsigned long lit)
4553 unsigned long pw[32] =
4554 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
4555 0x100L, 0x200L, 0x400L, 0x800L,
4556 0x1000L, 0x2000L, 0x4000L, 0x8000L,
4557 0x10000L, 0x20000L, 0x40000L, 0x80000L,
4558 0x100000L, 0x200000L, 0x400000L, 0x800000L,
4559 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
4560 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
4563 for (idx = 0; idx < 32; idx++)
4569 /*-----------------------------------------------------------------*/
4570 /* jmpTrueOrFalse - */
4571 /*-----------------------------------------------------------------*/
4573 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
4575 // ugly but optimized by peephole
4578 symbol *nlbl = newiTempLabel (NULL);
4579 emit2 ("jp !tlabel", nlbl->key + 100);
4580 emitLabel (tlbl->key + 100);
4581 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
4582 emitLabel (nlbl->key + 100);
4586 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
4587 emitLabel (tlbl->key + 100);
4592 /*-----------------------------------------------------------------*/
4593 /* genAnd - code for and */
4594 /*-----------------------------------------------------------------*/
4596 genAnd (iCode * ic, iCode * ifx)
4598 operand *left, *right, *result;
4599 int size, offset = 0;
4600 unsigned long lit = 0L;
4603 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4604 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4605 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4607 /* if left is a literal & right is not then exchange them */
4608 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4609 AOP_NEEDSACC (left))
4611 operand *tmp = right;
4616 /* if result = right then exchange them */
4617 if (sameRegs (AOP (result), AOP (right)))
4619 operand *tmp = right;
4624 /* if right is bit then exchange them */
4625 if (AOP_TYPE (right) == AOP_CRY &&
4626 AOP_TYPE (left) != AOP_CRY)
4628 operand *tmp = right;
4632 if (AOP_TYPE (right) == AOP_LIT)
4633 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4635 size = AOP_SIZE (result);
4637 if (AOP_TYPE (left) == AOP_CRY)
4639 wassertl (0, "Tried to perform an AND with a bit as an operand");
4643 // if(val & 0xZZ) - size = 0, ifx != FALSE -
4644 // bit = val & 0xZZ - size = 1, ifx = FALSE -
4645 if ((AOP_TYPE (right) == AOP_LIT) &&
4646 (AOP_TYPE (result) == AOP_CRY) &&
4647 (AOP_TYPE (left) != AOP_CRY))
4649 symbol *tlbl = newiTempLabel (NULL);
4650 int sizel = AOP_SIZE (left);
4653 /* PENDING: Test case for this. */
4658 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
4660 _moveA (aopGet (AOP (left), offset, FALSE));
4661 if (bytelit != 0x0FFL)
4663 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4670 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4674 // bit = left & literal
4678 emit2 ("!tlabeldef", tlbl->key + 100);
4680 // if(left & literal)
4685 jmpTrueOrFalse (ifx, tlbl);
4693 /* if left is same as result */
4694 if (sameRegs (AOP (result), AOP (left)))
4696 for (; size--; offset++)
4698 if (AOP_TYPE (right) == AOP_LIT)
4700 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4705 aopPut (AOP (result), "!zero", offset);
4708 _moveA (aopGet (AOP (left), offset, FALSE));
4710 aopGet (AOP (right), offset, FALSE));
4711 aopPut (AOP (left), "a", offset);
4718 if (AOP_TYPE (left) == AOP_ACC)
4720 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
4724 _moveA (aopGet (AOP (left), offset, FALSE));
4726 aopGet (AOP (right), offset, FALSE));
4727 aopPut (AOP (left), "a", offset);
4734 // left & result in different registers
4735 if (AOP_TYPE (result) == AOP_CRY)
4737 wassertl (0, "Tried to AND where the result is in carry");
4741 for (; (size--); offset++)
4744 // result = left & right
4745 if (AOP_TYPE (right) == AOP_LIT)
4747 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4749 aopPut (AOP (result),
4750 aopGet (AOP (left), offset, FALSE),
4754 else if (bytelit == 0)
4756 aopPut (AOP (result), "!zero", offset);
4760 // faster than result <- left, anl result,right
4761 // and better if result is SFR
4762 if (AOP_TYPE (left) == AOP_ACC)
4763 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4766 _moveA (aopGet (AOP (left), offset, FALSE));
4768 aopGet (AOP (right), offset, FALSE));
4770 aopPut (AOP (result), "a", offset);
4777 freeAsmop (left, NULL, ic);
4778 freeAsmop (right, NULL, ic);
4779 freeAsmop (result, NULL, ic);
4782 /*-----------------------------------------------------------------*/
4783 /* genOr - code for or */
4784 /*-----------------------------------------------------------------*/
4786 genOr (iCode * ic, iCode * ifx)
4788 operand *left, *right, *result;
4789 int size, offset = 0;
4790 unsigned long lit = 0L;
4793 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4794 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4795 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4797 /* if left is a literal & right is not then exchange them */
4798 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4799 AOP_NEEDSACC (left))
4801 operand *tmp = right;
4806 /* if result = right then exchange them */
4807 if (sameRegs (AOP (result), AOP (right)))
4809 operand *tmp = right;
4814 /* if right is bit then exchange them */
4815 if (AOP_TYPE (right) == AOP_CRY &&
4816 AOP_TYPE (left) != AOP_CRY)
4818 operand *tmp = right;
4822 if (AOP_TYPE (right) == AOP_LIT)
4823 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4825 size = AOP_SIZE (result);
4827 if (AOP_TYPE (left) == AOP_CRY)
4829 wassertl (0, "Tried to OR where left is a bit");
4833 // if(val | 0xZZ) - size = 0, ifx != FALSE -
4834 // bit = val | 0xZZ - size = 1, ifx = FALSE -
4835 if ((AOP_TYPE (right) == AOP_LIT) &&
4836 (AOP_TYPE (result) == AOP_CRY) &&
4837 (AOP_TYPE (left) != AOP_CRY))
4839 symbol *tlbl = newiTempLabel (NULL);
4840 int sizel = AOP_SIZE (left);
4844 wassertl (0, "Result is assigned to a bit");
4846 /* PENDING: Modeled after the AND code which is inefficent. */
4849 bytelit = (lit >> (offset * 8)) & 0x0FFL;
4851 _moveA (aopGet (AOP (left), offset, FALSE));
4852 /* OR with any literal is the same as OR with itself. */
4854 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4860 jmpTrueOrFalse (ifx, tlbl);
4865 /* if left is same as result */
4866 if (sameRegs (AOP (result), AOP (left)))
4868 for (; size--; offset++)
4870 if (AOP_TYPE (right) == AOP_LIT)
4872 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4876 _moveA (aopGet (AOP (left), offset, FALSE));
4878 aopGet (AOP (right), offset, FALSE));
4879 aopPut (AOP (result), "a", offset);
4884 if (AOP_TYPE (left) == AOP_ACC)
4885 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4888 _moveA (aopGet (AOP (left), offset, FALSE));
4890 aopGet (AOP (right), offset, FALSE));
4891 aopPut (AOP (result), "a", offset);
4898 // left & result in different registers
4899 if (AOP_TYPE (result) == AOP_CRY)
4901 wassertl (0, "Result of OR is in a bit");
4904 for (; (size--); offset++)
4907 // result = left & right
4908 if (AOP_TYPE (right) == AOP_LIT)
4910 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4912 aopPut (AOP (result),
4913 aopGet (AOP (left), offset, FALSE),
4918 // faster than result <- left, anl result,right
4919 // and better if result is SFR
4920 if (AOP_TYPE (left) == AOP_ACC)
4921 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4924 _moveA (aopGet (AOP (left), offset, FALSE));
4926 aopGet (AOP (right), offset, FALSE));
4928 aopPut (AOP (result), "a", offset);
4929 /* PENDING: something weird is going on here. Add exception. */
4930 if (AOP_TYPE (result) == AOP_ACC)
4936 freeAsmop (left, NULL, ic);
4937 freeAsmop (right, NULL, ic);
4938 freeAsmop (result, NULL, ic);
4941 /*-----------------------------------------------------------------*/
4942 /* genXor - code for xclusive or */
4943 /*-----------------------------------------------------------------*/
4945 genXor (iCode * ic, iCode * ifx)
4947 operand *left, *right, *result;
4948 int size, offset = 0;
4949 unsigned long lit = 0L;
4951 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4952 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4953 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4955 /* if left is a literal & right is not then exchange them */
4956 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4957 AOP_NEEDSACC (left))
4959 operand *tmp = right;
4964 /* if result = right then exchange them */
4965 if (sameRegs (AOP (result), AOP (right)))
4967 operand *tmp = right;
4972 /* if right is bit then exchange them */
4973 if (AOP_TYPE (right) == AOP_CRY &&
4974 AOP_TYPE (left) != AOP_CRY)
4976 operand *tmp = right;
4980 if (AOP_TYPE (right) == AOP_LIT)
4981 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4983 size = AOP_SIZE (result);
4985 if (AOP_TYPE (left) == AOP_CRY)
4987 wassertl (0, "Tried to XOR a bit");
4991 // if(val & 0xZZ) - size = 0, ifx != FALSE -
4992 // bit = val & 0xZZ - size = 1, ifx = FALSE -
4993 if ((AOP_TYPE (right) == AOP_LIT) &&
4994 (AOP_TYPE (result) == AOP_CRY) &&
4995 (AOP_TYPE (left) != AOP_CRY))
4997 symbol *tlbl = newiTempLabel (NULL);
4998 int sizel = AOP_SIZE (left);
5002 /* PENDING: Test case for this. */
5003 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5007 _moveA (aopGet (AOP (left), offset, FALSE));
5008 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5009 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5014 jmpTrueOrFalse (ifx, tlbl);
5018 wassertl (0, "Result of XOR was destined for a bit");
5023 /* if left is same as result */
5024 if (sameRegs (AOP (result), AOP (left)))
5026 for (; size--; offset++)
5028 if (AOP_TYPE (right) == AOP_LIT)
5030 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5034 _moveA (aopGet (AOP (right), offset, FALSE));
5036 aopGet (AOP (left), offset, FALSE));
5037 aopPut (AOP (result), "a", offset);
5042 if (AOP_TYPE (left) == AOP_ACC)
5044 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5048 _moveA (aopGet (AOP (right), offset, FALSE));
5050 aopGet (AOP (left), offset, FALSE));
5051 aopPut (AOP (result), "a", 0);
5058 // left & result in different registers
5059 if (AOP_TYPE (result) == AOP_CRY)
5061 wassertl (0, "Result of XOR is in a bit");
5064 for (; (size--); offset++)
5067 // result = left & right
5068 if (AOP_TYPE (right) == AOP_LIT)
5070 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5072 aopPut (AOP (result),
5073 aopGet (AOP (left), offset, FALSE),
5078 // faster than result <- left, anl result,right
5079 // and better if result is SFR
5080 if (AOP_TYPE (left) == AOP_ACC)
5082 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5086 _moveA (aopGet (AOP (right), offset, FALSE));
5088 aopGet (AOP (left), offset, FALSE));
5090 aopPut (AOP (result), "a", offset);
5095 freeAsmop (left, NULL, ic);
5096 freeAsmop (right, NULL, ic);
5097 freeAsmop (result, NULL, ic);
5100 /*-----------------------------------------------------------------*/
5101 /* genInline - write the inline code out */
5102 /*-----------------------------------------------------------------*/
5104 genInline (iCode * ic)
5106 char *buffer, *bp, *bp1;
5108 _G.lines.isInline += (!options.asmpeep);
5110 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5111 strcpy (buffer, IC_INLINE (ic));
5113 /* emit each line as a code */
5138 _G.lines.isInline -= (!options.asmpeep);
5142 /*-----------------------------------------------------------------*/
5143 /* genRRC - rotate right with carry */
5144 /*-----------------------------------------------------------------*/
5151 /*-----------------------------------------------------------------*/
5152 /* genRLC - generate code for rotate left with carry */
5153 /*-----------------------------------------------------------------*/
5160 /*-----------------------------------------------------------------*/
5161 /* genGetHbit - generates code get highest order bit */
5162 /*-----------------------------------------------------------------*/
5164 genGetHbit (iCode * ic)
5166 operand *left, *result;
5167 left = IC_LEFT (ic);
5168 result = IC_RESULT (ic);
5170 aopOp (left, ic, FALSE, FALSE);
5171 aopOp (result, ic, FALSE, FALSE);
5173 /* get the highest order byte into a */
5174 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5176 if (AOP_TYPE (result) == AOP_CRY)
5184 emit2 ("and a,!one");
5189 freeAsmop (left, NULL, ic);
5190 freeAsmop (result, NULL, ic);
5194 emitRsh2 (asmop *aop, int size, int is_signed)
5200 const char *l = aopGet (aop, size, FALSE);
5203 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5213 /*-----------------------------------------------------------------*/
5214 /* shiftR2Left2Result - shift right two bytes from left to result */
5215 /*-----------------------------------------------------------------*/
5217 shiftR2Left2Result (operand * left, int offl,
5218 operand * result, int offr,
5219 int shCount, int is_signed)
5222 symbol *tlbl, *tlbl1;
5224 movLeft2Result (left, offl, result, offr, 0);
5225 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5227 /* if (AOP(result)->type == AOP_REG) { */
5229 tlbl = newiTempLabel (NULL);
5230 tlbl1 = newiTempLabel (NULL);
5232 /* Left is already in result - so now do the shift */
5237 emitRsh2 (AOP (result), size, is_signed);
5242 emit2 ("ld a,!immedbyte+1", shCount);
5243 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5244 emitLabel (tlbl->key + 100);
5246 emitRsh2 (AOP (result), size, is_signed);
5248 emitLabel (tlbl1->key + 100);
5250 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5254 /*-----------------------------------------------------------------*/
5255 /* shiftL2Left2Result - shift left two bytes from left to result */
5256 /*-----------------------------------------------------------------*/
5258 shiftL2Left2Result (operand * left, int offl,
5259 operand * result, int offr, int shCount)
5261 if (sameRegs (AOP (result), AOP (left)) &&
5262 ((offl + MSB16) == offr))
5268 /* Copy left into result */
5269 movLeft2Result (left, offl, result, offr, 0);
5270 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5272 /* PENDING: for now just see if it'll work. */
5273 /*if (AOP(result)->type == AOP_REG) { */
5277 symbol *tlbl, *tlbl1;
5280 tlbl = newiTempLabel (NULL);
5281 tlbl1 = newiTempLabel (NULL);
5283 /* Left is already in result - so now do the shift */
5286 emit2 ("ld a,!immedbyte+1", shCount);
5287 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5288 emitLabel (tlbl->key + 100);
5293 l = aopGet (AOP (result), offset, FALSE);
5297 emit2 ("sla %s", l);
5308 emitLabel (tlbl1->key + 100);
5310 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5315 /*-----------------------------------------------------------------*/
5316 /* AccRol - rotate left accumulator by known count */
5317 /*-----------------------------------------------------------------*/
5319 AccRol (int shCount)
5321 shCount &= 0x0007; // shCount : 0..7
5360 /*-----------------------------------------------------------------*/
5361 /* AccLsh - left shift accumulator by known count */
5362 /*-----------------------------------------------------------------*/
5364 AccLsh (int shCount)
5366 static const unsigned char SLMask[] =
5368 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5377 else if (shCount == 2)
5384 /* rotate left accumulator */
5386 /* and kill the lower order bits */
5387 emit2 ("and a,!immedbyte", SLMask[shCount]);
5392 /*-----------------------------------------------------------------*/
5393 /* shiftL1Left2Result - shift left one byte from left to result */
5394 /*-----------------------------------------------------------------*/
5396 shiftL1Left2Result (operand * left, int offl,
5397 operand * result, int offr, int shCount)
5400 l = aopGet (AOP (left), offl, FALSE);
5402 /* shift left accumulator */
5404 aopPut (AOP (result), "a", offr);
5408 /*-----------------------------------------------------------------*/
5409 /* genlshTwo - left shift two bytes by known amount != 0 */
5410 /*-----------------------------------------------------------------*/
5412 genlshTwo (operand * result, operand * left, int shCount)
5414 int size = AOP_SIZE (result);
5416 wassert (size == 2);
5418 /* if shCount >= 8 */
5426 movLeft2Result (left, LSB, result, MSB16, 0);
5427 aopPut (AOP (result), "!zero", 0);
5428 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
5432 movLeft2Result (left, LSB, result, MSB16, 0);
5433 aopPut (AOP (result), "!zero", 0);
5438 aopPut (AOP (result), "!zero", LSB);
5441 /* 1 <= shCount <= 7 */
5450 shiftL2Left2Result (left, LSB, result, LSB, shCount);
5455 /*-----------------------------------------------------------------*/
5456 /* genlshOne - left shift a one byte quantity by known count */
5457 /*-----------------------------------------------------------------*/
5459 genlshOne (operand * result, operand * left, int shCount)
5461 shiftL1Left2Result (left, LSB, result, LSB, shCount);
5464 /*-----------------------------------------------------------------*/
5465 /* genLeftShiftLiteral - left shifting by known count */
5466 /*-----------------------------------------------------------------*/
5468 genLeftShiftLiteral (operand * left,
5473 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5476 freeAsmop (right, NULL, ic);
5478 aopOp (left, ic, FALSE, FALSE);
5479 aopOp (result, ic, FALSE, FALSE);
5481 size = getSize (operandType (result));
5483 /* I suppose that the left size >= result size */
5489 else if (shCount >= (size * 8))
5493 aopPut (AOP (result), "!zero", size);
5501 genlshOne (result, left, shCount);
5504 genlshTwo (result, left, shCount);
5507 wassertl (0, "Shifting of longs is currently unsupported");
5513 freeAsmop (left, NULL, ic);
5514 freeAsmop (result, NULL, ic);
5517 /*-----------------------------------------------------------------*/
5518 /* genLeftShift - generates code for left shifting */
5519 /*-----------------------------------------------------------------*/
5521 genLeftShift (iCode * ic)
5525 symbol *tlbl, *tlbl1;
5526 operand *left, *right, *result;
5528 right = IC_RIGHT (ic);
5529 left = IC_LEFT (ic);
5530 result = IC_RESULT (ic);
5532 aopOp (right, ic, FALSE, FALSE);
5534 /* if the shift count is known then do it
5535 as efficiently as possible */
5536 if (AOP_TYPE (right) == AOP_LIT)
5538 genLeftShiftLiteral (left, right, result, ic);
5542 /* shift count is unknown then we have to form a loop get the loop
5543 count in B : Note: we take only the lower order byte since
5544 shifting more that 32 bits make no sense anyway, ( the largest
5545 size of an object can be only 32 bits ) */
5546 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5548 freeAsmop (right, NULL, ic);
5549 aopOp (left, ic, FALSE, FALSE);
5550 aopOp (result, ic, FALSE, FALSE);
5552 /* now move the left to the result if they are not the
5555 if (!sameRegs (AOP (left), AOP (result)))
5558 size = AOP_SIZE (result);
5562 l = aopGet (AOP (left), offset, FALSE);
5563 aopPut (AOP (result), l, offset);
5568 tlbl = newiTempLabel (NULL);
5569 size = AOP_SIZE (result);
5571 tlbl1 = newiTempLabel (NULL);
5573 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5574 emitLabel (tlbl->key + 100);
5575 l = aopGet (AOP (result), offset, FALSE);
5579 l = aopGet (AOP (result), offset, FALSE);
5583 emit2 ("sla %s", l);
5591 emitLabel (tlbl1->key + 100);
5593 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5595 freeAsmop (left, NULL, ic);
5596 freeAsmop (result, NULL, ic);
5599 /*-----------------------------------------------------------------*/
5600 /* genrshOne - left shift two bytes by known amount != 0 */
5601 /*-----------------------------------------------------------------*/
5603 genrshOne (operand * result, operand * left, int shCount, int is_signed)
5606 int size = AOP_SIZE (result);
5609 wassert (size == 1);
5610 wassert (shCount < 8);
5612 l = aopGet (AOP (left), 0, FALSE);
5614 if (AOP (result)->type == AOP_REG)
5616 aopPut (AOP (result), l, 0);
5617 l = aopGet (AOP (result), 0, FALSE);
5620 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5628 emit2 ("%s a", is_signed ? "sra" : "srl");
5630 aopPut (AOP (result), "a", 0);
5634 /*-----------------------------------------------------------------*/
5635 /* AccRsh - right shift accumulator by known count */
5636 /*-----------------------------------------------------------------*/
5638 AccRsh (int shCount)
5640 static const unsigned char SRMask[] =
5642 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
5647 /* rotate right accumulator */
5648 AccRol (8 - shCount);
5649 /* and kill the higher order bits */
5650 emit2 ("and a,!immedbyte", SRMask[shCount]);
5654 /*-----------------------------------------------------------------*/
5655 /* shiftR1Left2Result - shift right one byte from left to result */
5656 /*-----------------------------------------------------------------*/
5658 shiftR1Left2Result (operand * left, int offl,
5659 operand * result, int offr,
5660 int shCount, int sign)
5662 _moveA (aopGet (AOP (left), offl, FALSE));
5667 emit2 ("%s a", sign ? "sra" : "srl");
5674 aopPut (AOP (result), "a", offr);
5677 /*-----------------------------------------------------------------*/
5678 /* genrshTwo - right shift two bytes by known amount != 0 */
5679 /*-----------------------------------------------------------------*/
5681 genrshTwo (operand * result, operand * left,
5682 int shCount, int sign)
5684 /* if shCount >= 8 */
5690 shiftR1Left2Result (left, MSB16, result, LSB,
5695 movLeft2Result (left, MSB16, result, LSB, sign);
5699 /* Sign extend the result */
5700 _moveA(aopGet (AOP (result), 0, FALSE));
5704 aopPut (AOP (result), ACC_NAME, MSB16);
5708 aopPut (AOP (result), "!zero", 1);
5711 /* 1 <= shCount <= 7 */
5714 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
5718 /*-----------------------------------------------------------------*/
5719 /* genRightShiftLiteral - left shifting by known count */
5720 /*-----------------------------------------------------------------*/
5722 genRightShiftLiteral (operand * left,
5728 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5731 freeAsmop (right, NULL, ic);
5733 aopOp (left, ic, FALSE, FALSE);
5734 aopOp (result, ic, FALSE, FALSE);
5736 size = getSize (operandType (result));
5738 /* I suppose that the left size >= result size */
5744 else if (shCount >= (size * 8))
5746 aopPut (AOP (result), "!zero", size);
5752 genrshOne (result, left, shCount, sign);
5755 genrshTwo (result, left, shCount, sign);
5758 wassertl (0, "Asked to shift right a long which should be a function call");
5761 wassertl (0, "Entered default case in right shift delegate");
5764 freeAsmop (left, NULL, ic);
5765 freeAsmop (result, NULL, ic);
5768 /*-----------------------------------------------------------------*/
5769 /* genRightShift - generate code for right shifting */
5770 /*-----------------------------------------------------------------*/
5772 genRightShift (iCode * ic)
5774 operand *right, *left, *result;
5776 int size, offset, first = 1;
5780 symbol *tlbl, *tlbl1;
5782 /* if signed then we do it the hard way preserve the
5783 sign bit moving it inwards */
5784 retype = getSpec (operandType (IC_RESULT (ic)));
5786 is_signed = !SPEC_USIGN (retype);
5788 /* signed & unsigned types are treated the same : i.e. the
5789 signed is NOT propagated inwards : quoting from the
5790 ANSI - standard : "for E1 >> E2, is equivalent to division
5791 by 2**E2 if unsigned or if it has a non-negative value,
5792 otherwise the result is implementation defined ", MY definition
5793 is that the sign does not get propagated */
5795 right = IC_RIGHT (ic);
5796 left = IC_LEFT (ic);
5797 result = IC_RESULT (ic);
5799 aopOp (right, ic, FALSE, FALSE);
5801 /* if the shift count is known then do it
5802 as efficiently as possible */
5803 if (AOP_TYPE (right) == AOP_LIT)
5805 genRightShiftLiteral (left, right, result, ic, is_signed);
5809 aopOp (left, ic, FALSE, FALSE);
5810 aopOp (result, ic, FALSE, FALSE);
5812 /* now move the left to the result if they are not the
5814 if (!sameRegs (AOP (left), AOP (result)) &&
5815 AOP_SIZE (result) > 1)
5818 size = AOP_SIZE (result);
5822 l = aopGet (AOP (left), offset, FALSE);
5823 aopPut (AOP (result), l, offset);
5828 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5830 freeAsmop (right, NULL, ic);
5832 tlbl = newiTempLabel (NULL);
5833 tlbl1 = newiTempLabel (NULL);
5834 size = AOP_SIZE (result);
5837 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5838 emitLabel (tlbl->key + 100);
5841 l = aopGet (AOP (result), offset--, FALSE);
5844 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5852 emitLabel (tlbl1->key + 100);
5854 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5856 freeAsmop (left, NULL, ic);
5857 freeAsmop (result, NULL, ic);
5860 /*-----------------------------------------------------------------*/
5861 /* genGenPointerGet - get value from generic pointer space */
5862 /*-----------------------------------------------------------------*/
5864 genGenPointerGet (operand * left,
5865 operand * result, iCode * ic)
5868 sym_link *retype = getSpec (operandType (result));
5874 aopOp (left, ic, FALSE, FALSE);
5875 aopOp (result, ic, FALSE, FALSE);
5877 size = AOP_SIZE (result);
5879 if (isPair (AOP (left)) && size == 1)
5882 if (isPtrPair (AOP (left)))
5884 tsprintf (buffer, "!*pair", getPairName (AOP (left)));
5885 aopPut (AOP (result), buffer, 0);
5889 emit2 ("ld a,!*pair", getPairName (AOP (left)));
5890 aopPut (AOP (result), "a", 0);
5892 freeAsmop (left, NULL, ic);
5896 if ( getPairId( AOP (left)) == PAIR_IY)
5903 tsprintf (at, "!*iyx", offset);
5904 aopPut (AOP (result), at, offset);
5908 freeAsmop (left, NULL, ic);
5912 /* For now we always load into IY */
5913 /* if this is remateriazable */
5914 fetchPair (pair, AOP (left));
5916 freeAsmop (left, NULL, ic);
5918 /* if bit then unpack */
5919 if (IS_BITVAR (retype))
5923 else if ( getPairId( AOP (result)) == PAIR_HL)
5925 wassertl (size == 2, "HL must be of size 2");
5926 emit2 ("ld a,!*hl");
5928 emit2 ("ld h,!*hl");
5933 size = AOP_SIZE (result);
5938 /* PENDING: make this better */
5939 if (!IS_GB && AOP (result)->type == AOP_REG)
5941 aopPut (AOP (result), "!*hl", offset++);
5945 emit2 ("ld a,!*pair", _pairs[pair].name);
5946 aopPut (AOP (result), "a", offset++);
5950 emit2 ("inc %s", _pairs[pair].name);
5951 _G.pairs[pair].offset++;
5957 freeAsmop (result, NULL, ic);
5960 /*-----------------------------------------------------------------*/
5961 /* genPointerGet - generate code for pointer get */
5962 /*-----------------------------------------------------------------*/
5964 genPointerGet (iCode * ic)
5966 operand *left, *result;
5967 sym_link *type, *etype;
5969 left = IC_LEFT (ic);
5970 result = IC_RESULT (ic);
5972 /* depending on the type of pointer we need to
5973 move it to the correct pointer register */
5974 type = operandType (left);
5975 etype = getSpec (type);
5977 genGenPointerGet (left, result, ic);
5981 isRegOrLit (asmop * aop)
5983 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
5988 /*-----------------------------------------------------------------*/
5989 /* genGenPointerSet - stores the value into a pointer location */
5990 /*-----------------------------------------------------------------*/
5992 genGenPointerSet (operand * right,
5993 operand * result, iCode * ic)
5996 sym_link *retype = getSpec (operandType (right));
5997 PAIR_ID pairId = PAIR_HL;
5999 aopOp (result, ic, FALSE, FALSE);
6000 aopOp (right, ic, FALSE, FALSE);
6005 size = AOP_SIZE (right);
6007 /* Handle the exceptions first */
6008 if (isPair (AOP (result)) && size == 1)
6011 const char *l = aopGet (AOP (right), 0, FALSE);
6012 const char *pair = getPairName (AOP (result));
6013 if (canAssignToPtr (l) && isPtr (pair))
6015 emit2 ("ld !*pair,%s", pair, l);
6020 emit2 ("ld !*pair,a", pair);
6025 if ( getPairId( AOP (result)) == PAIR_IY)
6028 const char *l = aopGet (AOP (right), 0, FALSE);
6033 if (canAssignToPtr (l))
6035 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6039 _moveA (aopGet (AOP (right), offset, FALSE));
6040 emit2 ("ld !*iyx,a", offset);
6047 /* if the operand is already in dptr
6048 then we do nothing else we move the value to dptr */
6049 if (AOP_TYPE (result) != AOP_STR)
6051 fetchPair (pairId, AOP (result));
6053 /* so hl know contains the address */
6054 freeAsmop (result, NULL, ic);
6056 /* if bit then unpack */
6057 if (IS_BITVAR (retype))
6067 const char *l = aopGet (AOP (right), offset, FALSE);
6068 if (isRegOrLit (AOP (right)) && !IS_GB)
6070 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
6075 emit2 ("ld !*pair,a", _pairs[pairId].name);
6079 emit2 ("inc %s", _pairs[pairId].name);
6080 _G.pairs[pairId].offset++;
6086 freeAsmop (right, NULL, ic);
6089 /*-----------------------------------------------------------------*/
6090 /* genPointerSet - stores the value into a pointer location */
6091 /*-----------------------------------------------------------------*/
6093 genPointerSet (iCode * ic)
6095 operand *right, *result;
6096 sym_link *type, *etype;
6098 right = IC_RIGHT (ic);
6099 result = IC_RESULT (ic);
6101 /* depending on the type of pointer we need to
6102 move it to the correct pointer register */
6103 type = operandType (result);
6104 etype = getSpec (type);
6106 genGenPointerSet (right, result, ic);
6109 /*-----------------------------------------------------------------*/
6110 /* genIfx - generate code for Ifx statement */
6111 /*-----------------------------------------------------------------*/
6113 genIfx (iCode * ic, iCode * popIc)
6115 operand *cond = IC_COND (ic);
6118 aopOp (cond, ic, FALSE, TRUE);
6120 /* get the value into acc */
6121 if (AOP_TYPE (cond) != AOP_CRY)
6125 /* the result is now in the accumulator */
6126 freeAsmop (cond, NULL, ic);
6128 /* if there was something to be popped then do it */
6132 /* if the condition is a bit variable */
6133 if (isbit && IS_ITEMP (cond) &&
6135 genIfxJump (ic, SPIL_LOC (cond)->rname);
6136 else if (isbit && !IS_ITEMP (cond))
6137 genIfxJump (ic, OP_SYMBOL (cond)->rname);
6139 genIfxJump (ic, "a");
6144 /*-----------------------------------------------------------------*/
6145 /* genAddrOf - generates code for address of */
6146 /*-----------------------------------------------------------------*/
6148 genAddrOf (iCode * ic)
6150 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
6152 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6154 /* if the operand is on the stack then we
6155 need to get the stack offset of this
6162 if (sym->stack <= 0)
6164 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
6168 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6170 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6174 emit2 ("ld de,!hashedstr", sym->rname);
6175 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
6183 /* if it has an offset then we need to compute it */
6185 emit2 ("ld hl,#%d+%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset, _G.stack.param_offset);
6187 emit2 ("ld hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
6188 emit2 ("add hl,sp");
6192 emit2 ("ld hl,#%s", sym->rname);
6194 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6196 freeAsmop (IC_RESULT (ic), NULL, ic);
6199 /*-----------------------------------------------------------------*/
6200 /* genAssign - generate code for assignment */
6201 /*-----------------------------------------------------------------*/
6203 genAssign (iCode * ic)
6205 operand *result, *right;
6207 unsigned long lit = 0L;
6209 result = IC_RESULT (ic);
6210 right = IC_RIGHT (ic);
6212 /* Dont bother assigning if they are the same */
6213 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6215 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
6219 aopOp (right, ic, FALSE, FALSE);
6220 aopOp (result, ic, TRUE, FALSE);
6222 /* if they are the same registers */
6223 if (sameRegs (AOP (right), AOP (result)))
6225 emitDebug ("; (registers are the same)");
6229 /* if the result is a bit */
6230 if (AOP_TYPE (result) == AOP_CRY)
6232 wassertl (0, "Tried to assign to a bit");
6236 size = AOP_SIZE (result);
6239 if (AOP_TYPE (right) == AOP_LIT)
6241 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6244 if (isPair (AOP (result)))
6246 fetchPair (getPairId (AOP (result)), AOP (right));
6248 else if ((size > 1) &&
6249 (AOP_TYPE (result) != AOP_REG) &&
6250 (AOP_TYPE (right) == AOP_LIT) &&
6251 !IS_FLOAT (operandType (right)) &&
6254 bool fXored = FALSE;
6256 /* Work from the top down.
6257 Done this way so that we can use the cached copy of 0
6258 in A for a fast clear */
6261 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
6263 if (!fXored && size > 1)
6270 aopPut (AOP (result), "a", offset);
6274 aopPut (AOP (result), "!zero", offset);
6278 aopPut (AOP (result),
6279 aopGet (AOP (right), offset, FALSE),
6284 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
6286 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
6287 aopPut (AOP (result), "l", LSB);
6288 aopPut (AOP (result), "h", MSB16);
6290 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6292 /* Special case. Load into a and d, then load out. */
6293 _moveA (aopGet (AOP (right), 0, FALSE));
6294 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
6295 aopPut (AOP (result), "a", 0);
6296 aopPut (AOP (result), "e", 1);
6298 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6300 /* Special case - simple memcpy */
6301 aopGet (AOP (right), LSB, FALSE);
6304 aopGet (AOP (result), LSB, FALSE);
6308 emit2 ("ld a,(de)");
6309 /* Peephole will optimise this. */
6310 emit2 ("ld (hl),a");
6318 spillPair (PAIR_HL);
6324 /* PENDING: do this check better */
6325 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
6327 _moveA (aopGet (AOP (right), offset, FALSE));
6328 aopPut (AOP (result), "a", offset);
6331 aopPut (AOP (result),
6332 aopGet (AOP (right), offset, FALSE),
6339 freeAsmop (right, NULL, ic);
6340 freeAsmop (result, NULL, ic);
6343 /*-----------------------------------------------------------------*/
6344 /* genJumpTab - genrates code for jump table */
6345 /*-----------------------------------------------------------------*/
6347 genJumpTab (iCode * ic)
6352 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
6353 /* get the condition into accumulator */
6354 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
6357 emit2 ("ld e,%s", l);
6358 emit2 ("ld d,!zero");
6359 jtab = newiTempLabel (NULL);
6361 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
6362 emit2 ("add hl,de");
6363 emit2 ("add hl,de");
6364 emit2 ("add hl,de");
6365 freeAsmop (IC_JTCOND (ic), NULL, ic);
6369 emitLabel (jtab->key + 100);
6370 /* now generate the jump labels */
6371 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
6372 jtab = setNextItem (IC_JTLABELS (ic)))
6373 emit2 ("jp !tlabel", jtab->key + 100);
6376 /*-----------------------------------------------------------------*/
6377 /* genCast - gen code for casting */
6378 /*-----------------------------------------------------------------*/
6380 genCast (iCode * ic)
6382 operand *result = IC_RESULT (ic);
6383 sym_link *ctype = operandType (IC_LEFT (ic));
6384 operand *right = IC_RIGHT (ic);
6387 /* if they are equivalent then do nothing */
6388 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6391 aopOp (right, ic, FALSE, FALSE);
6392 aopOp (result, ic, FALSE, FALSE);
6394 /* if the result is a bit */
6395 if (AOP_TYPE (result) == AOP_CRY)
6397 wassertl (0, "Tried to cast to a bit");
6400 /* if they are the same size : or less */
6401 if (AOP_SIZE (result) <= AOP_SIZE (right))
6404 /* if they are in the same place */
6405 if (sameRegs (AOP (right), AOP (result)))
6408 /* if they in different places then copy */
6409 size = AOP_SIZE (result);
6413 aopPut (AOP (result),
6414 aopGet (AOP (right), offset, FALSE),
6421 /* So we now know that the size of destination is greater
6422 than the size of the source */
6423 /* we move to result for the size of source */
6424 size = AOP_SIZE (right);
6428 aopPut (AOP (result),
6429 aopGet (AOP (right), offset, FALSE),
6434 /* now depending on the sign of the destination */
6435 size = AOP_SIZE (result) - AOP_SIZE (right);
6436 /* Unsigned or not an integral type - right fill with zeros */
6437 if (SPEC_USIGN (ctype) || !IS_SPEC (ctype))
6440 aopPut (AOP (result), "!zero", offset++);
6444 /* we need to extend the sign :{ */
6445 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
6451 aopPut (AOP (result), "a", offset++);
6455 freeAsmop (right, NULL, ic);
6456 freeAsmop (result, NULL, ic);
6459 /*-----------------------------------------------------------------*/
6460 /* genReceive - generate code for a receive iCode */
6461 /*-----------------------------------------------------------------*/
6463 genReceive (iCode * ic)
6465 if (isOperandInFarSpace (IC_RESULT (ic)) &&
6466 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
6467 IS_TRUE_SYMOP (IC_RESULT (ic))))
6477 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6478 size = AOP_SIZE(IC_RESULT(ic));
6480 for (i = 0; i < size; i++) {
6481 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
6485 freeAsmop (IC_RESULT (ic), NULL, ic);
6490 /** Maximum number of bytes to emit per line. */
6494 /** Context for the byte output chunker. */
6497 unsigned char buffer[DBEMIT_MAX_RUN];
6502 /** Flushes a byte chunker by writing out all in the buffer and
6506 _dbFlush(DBEMITCTX *self)
6513 sprintf(line, ".db 0x%02X", self->buffer[0]);
6515 for (i = 1; i < self->pos; i++)
6517 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
6524 /** Write out another byte, buffering until a decent line is
6528 _dbEmit(DBEMITCTX *self, int c)
6530 if (self->pos == DBEMIT_MAX_RUN)
6534 self->buffer[self->pos++] = c;
6537 /** Context for a simple run length encoder. */
6541 unsigned char buffer[128];
6543 /** runLen may be equivalent to pos. */
6549 RLE_CHANGE_COST = 4,
6553 /** Flush the buffer of a run length encoder by writing out the run or
6554 data that it currently contains.
6557 _rleCommit(RLECTX *self)
6563 memset(&db, 0, sizeof(db));
6565 emit2(".db %u", self->pos);
6567 for (i = 0; i < self->pos; i++)
6569 _dbEmit(&db, self->buffer[i]);
6578 Can get either a run or a block of random stuff.
6579 Only want to change state if a good run comes in or a run ends.
6580 Detecting run end is easy.
6583 Say initial state is in run, len zero, last zero. Then if you get a
6584 few zeros then something else then a short run will be output.
6585 Seems OK. While in run mode, keep counting. While in random mode,
6586 keep a count of the run. If run hits margin, output all up to run,
6587 restart, enter run mode.
6590 /** Add another byte into the run length encoder, flushing as
6591 required. The run length encoder uses the Amiga IFF style, where
6592 a block is prefixed by its run length. A positive length means
6593 the next n bytes pass straight through. A negative length means
6594 that the next byte is repeated -n times. A zero terminates the
6598 _rleAppend(RLECTX *self, int c)
6602 if (c != self->last)
6604 /* The run has stopped. See if it is worthwhile writing it out
6605 as a run. Note that the random data comes in as runs of
6608 if (self->runLen > RLE_CHANGE_COST)
6610 /* Yes, worthwhile. */
6611 /* Commit whatever was in the buffer. */
6613 emit2(".db -%u,0x%02X", self->runLen, self->last);
6617 /* Not worthwhile. Append to the end of the random list. */
6618 for (i = 0; i < self->runLen; i++)
6620 if (self->pos >= RLE_MAX_BLOCK)
6625 self->buffer[self->pos++] = self->last;
6633 if (self->runLen >= RLE_MAX_BLOCK)
6635 /* Commit whatever was in the buffer. */
6638 emit2 (".db -%u,0x%02X", self->runLen, self->last);
6646 _rleFlush(RLECTX *self)
6648 _rleAppend(self, -1);
6655 /** genArrayInit - Special code for initialising an array with constant
6659 genArrayInit (iCode * ic)
6663 int elementSize = 0, eIndex, i;
6664 unsigned val, lastVal;
6668 memset(&rle, 0, sizeof(rle));
6670 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
6672 _saveRegsForCall(ic, 0);
6674 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
6675 emit2 ("call __initrleblock");
6677 type = operandType(IC_LEFT(ic));
6679 if (type && type->next)
6681 elementSize = getSize(type->next);
6685 wassertl (0, "Can't determine element size in genArrayInit.");
6688 iLoop = IC_ARRAYILIST(ic);
6689 lastVal = (unsigned)-1;
6691 /* Feed all the bytes into the run length encoder which will handle
6693 This works well for mixed char data, and for random int and long
6702 for (i = 0; i < ix; i++)
6704 for (eIndex = 0; eIndex < elementSize; eIndex++)
6706 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
6707 _rleAppend(&rle, val);
6712 iLoop = iLoop->next;
6716 /* Mark the end of the run. */
6719 _restoreRegsAfterCall();
6723 freeAsmop (IC_LEFT(ic), NULL, ic);
6727 _swap (PAIR_ID one, PAIR_ID two)
6729 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
6735 emit2 ("ld a,%s", _pairs[one].l);
6736 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
6737 emit2 ("ld %s,a", _pairs[two].l);
6738 emit2 ("ld a,%s", _pairs[one].h);
6739 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
6740 emit2 ("ld %s,a", _pairs[two].h);
6744 /* The problem is that we may have all three pairs used and they may
6745 be needed in a different order.
6750 hl = hl => unity, fine
6754 hl = hl hl = hl, swap de <=> bc
6762 hl = bc de = de, swap bc <=> hl
6770 hl = de bc = bc, swap hl <=> de
6775 * Any pair = pair are done last
6776 * Any pair = iTemp are done last
6777 * Any swaps can be done any time
6785 So how do we detect the cases?
6786 How about a 3x3 matrix?
6790 x x x x (Fourth for iTemp/other)
6792 First determin which mode to use by counting the number of unity and
6795 Two - Assign the pair first, then the rest
6796 One - Swap the two, then the rest
6800 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
6802 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
6804 PAIR_BC, PAIR_HL, PAIR_DE
6806 int i, j, nunity = 0;
6807 memset (ids, PAIR_INVALID, sizeof (ids));
6810 wassert (nparams == 3);
6812 /* First save everything that needs to be saved. */
6813 _saveRegsForCall (ic, 0);
6815 /* Loading HL first means that DE is always fine. */
6816 for (i = 0; i < nparams; i++)
6818 aopOp (pparams[i], ic, FALSE, FALSE);
6819 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
6822 /* Count the number of unity or iTemp assigns. */
6823 for (i = 0; i < 3; i++)
6825 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
6833 /* Any order, fall through. */
6835 else if (nunity == 2)
6837 /* One is assigned. Pull it out and assign. */
6838 for (i = 0; i < 3; i++)
6840 for (j = 0; j < NUM_PAIRS; j++)
6842 if (ids[dest[i]][j] == TRUE)
6844 /* Found it. See if it's the right one. */
6845 if (j == PAIR_INVALID || j == dest[i])
6851 fetchPair(dest[i], AOP (pparams[i]));
6858 else if (nunity == 1)
6860 /* Find the pairs to swap. */
6861 for (i = 0; i < 3; i++)
6863 for (j = 0; j < NUM_PAIRS; j++)
6865 if (ids[dest[i]][j] == TRUE)
6867 if (j == PAIR_INVALID || j == dest[i])
6882 int next = getPairId (AOP (pparams[0]));
6883 emit2 ("push %s", _pairs[next].name);
6885 if (next == dest[1])
6887 fetchPair (dest[1], AOP (pparams[1]));
6888 fetchPair (dest[2], AOP (pparams[2]));
6892 fetchPair (dest[2], AOP (pparams[2]));
6893 fetchPair (dest[1], AOP (pparams[1]));
6895 emit2 ("pop %s", _pairs[dest[0]].name);
6898 /* Finally pull out all of the iTemps */
6899 for (i = 0; i < 3; i++)
6901 if (ids[dest[i]][PAIR_INVALID] == 1)
6903 fetchPair (dest[i], AOP (pparams[i]));
6909 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
6915 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
6919 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
6921 setupForBuiltin3 (ic, nParams, pparams);
6923 label = newiTempLabel(NULL);
6925 emitLabel (label->key);
6926 emit2 ("ld a,(hl)");
6929 emit2 ("!shortjp nz,!tlabel ; 1", label->key);
6931 freeAsmop (from, NULL, ic->next);
6932 freeAsmop (to, NULL, ic);
6936 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
6938 operand *from, *to, *count;
6943 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
6948 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
6950 setupForBuiltin3 (ic, nParams, pparams);
6954 freeAsmop (count, NULL, ic->next->next);
6955 freeAsmop (from, NULL, ic);
6957 _restoreRegsAfterCall();
6959 /* if we need assign a result value */
6960 if ((IS_ITEMP (IC_RESULT (ic)) &&
6961 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
6962 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
6963 IS_TRUE_SYMOP (IC_RESULT (ic)))
6965 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6966 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
6967 freeAsmop (IC_RESULT (ic), NULL, ic);
6970 freeAsmop (to, NULL, ic->next);
6973 /*-----------------------------------------------------------------*/
6974 /* genBuiltIn - calls the appropriate function to generating code */
6975 /* for a built in function */
6976 /*-----------------------------------------------------------------*/
6977 static void genBuiltIn (iCode *ic)
6979 operand *bi_parms[MAX_BUILTIN_ARGS];
6984 /* get all the arguments for a built in function */
6985 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
6987 /* which function is it */
6988 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
6990 if (strcmp(bif->name,"__builtin_strcpy")==0)
6992 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
6994 else if (strcmp(bif->name,"__builtin_memcpy")==0)
6996 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
7000 wassertl (0, "Unknown builtin function encountered");
7004 /*-----------------------------------------------------------------*/
7005 /* genZ80Code - generate code for Z80 based controllers */
7006 /*-----------------------------------------------------------------*/
7008 genZ80Code (iCode * lic)
7016 _fReturn = _gbz80_return;
7017 _fTmp = _gbz80_return;
7021 _fReturn = _z80_return;
7022 _fTmp = _z80_return;
7025 _G.lines.head = _G.lines.current = NULL;
7027 for (ic = lic; ic; ic = ic->next)
7030 if (cln != ic->lineno)
7032 emit2 ("; %s %d", ic->filename, ic->lineno);
7035 /* if the result is marked as
7036 spilt and rematerializable or code for
7037 this has already been generated then
7039 if (resultRemat (ic) || ic->generated)
7042 /* depending on the operation */
7046 emitDebug ("; genNot");
7051 emitDebug ("; genCpl");
7056 emitDebug ("; genUminus");
7061 emitDebug ("; genIpush");
7066 /* IPOP happens only when trying to restore a
7067 spilt live range, if there is an ifx statement
7068 following this pop then the if statement might
7069 be using some of the registers being popped which
7070 would destory the contents of the register so
7071 we need to check for this condition and handle it */
7073 ic->next->op == IFX &&
7074 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
7076 emitDebug ("; genIfx");
7077 genIfx (ic->next, ic);
7081 emitDebug ("; genIpop");
7087 emitDebug ("; genCall");
7092 emitDebug ("; genPcall");
7097 emitDebug ("; genFunction");
7102 emitDebug ("; genEndFunction");
7103 genEndFunction (ic);
7107 emitDebug ("; genRet");
7112 emitDebug ("; genLabel");
7117 emitDebug ("; genGoto");
7122 emitDebug ("; genPlus");
7127 emitDebug ("; genMinus");
7132 emitDebug ("; genMult");
7137 emitDebug ("; genDiv");
7142 emitDebug ("; genMod");
7147 emitDebug ("; genCmpGt");
7148 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
7152 emitDebug ("; genCmpLt");
7153 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
7160 /* note these two are xlated by algebraic equivalence
7161 during parsing SDCC.y */
7162 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
7163 "got '>=' or '<=' shouldn't have come here");
7167 emitDebug ("; genCmpEq");
7168 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
7172 emitDebug ("; genAndOp");
7177 emitDebug ("; genOrOp");
7182 emitDebug ("; genXor");
7183 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
7187 emitDebug ("; genOr");
7188 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
7192 emitDebug ("; genAnd");
7193 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
7197 emitDebug ("; genInline");
7202 emitDebug ("; genRRC");
7207 emitDebug ("; genRLC");
7212 emitDebug ("; genGetHBIT");
7217 emitDebug ("; genLeftShift");
7222 emitDebug ("; genRightShift");
7226 case GET_VALUE_AT_ADDRESS:
7227 emitDebug ("; genPointerGet");
7233 if (POINTER_SET (ic))
7235 emitDebug ("; genAssign (pointer)");
7240 emitDebug ("; genAssign");
7246 emitDebug ("; genIfx");
7251 emitDebug ("; genAddrOf");
7256 emitDebug ("; genJumpTab");
7261 emitDebug ("; genCast");
7266 emitDebug ("; genReceive");
7271 if (ic->builtinSEND)
7273 emitDebug ("; genBuiltIn");
7278 emitDebug ("; addSet");
7279 addSet (&_G.sendSet, ic);
7284 emitDebug ("; genArrayInit");
7294 /* now we are ready to call the
7295 peep hole optimizer */
7296 if (!options.nopeep)
7297 peepHole (&_G.lines.head);
7299 /* This is unfortunate */
7300 /* now do the actual printing */
7302 FILE *fp = codeOutFile;
7303 if (isInHome () && codeOutFile == code->oFile)
7304 codeOutFile = home->oFile;
7305 printLine (_G.lines.head, codeOutFile);
7306 if (_G.flushStatics)
7309 _G.flushStatics = 0;
7314 freeTrace(&_G.lines.trace);
7315 freeTrace(&_G.trace.aops);
7321 _isPairUsed (iCode * ic, PAIR_ID pairId)
7327 if (bitVectBitValue (ic->rMask, D_IDX))
7329 if (bitVectBitValue (ic->rMask, E_IDX))
7339 fetchLitSpecial (asmop * aop, bool negate, bool xor)
7342 value *val = aop->aopu.aop_lit;
7344 wassert (aop->type == AOP_LIT);
7345 wassert (!IS_FLOAT (val->type));
7347 v = (unsigned long) floatFromVal (val);
7355 tsprintf (buffer, "!immedword", v);
7356 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));