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 */
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 */
923 if (sym->usl.spillLoc && getSize(sym->type) != getSize(sym->usl.spillLoc->type)) {
924 /* force a new aop if sizes differ */
925 sym->usl.spillLoc->aop = NULL;
927 sym->aop = op->aop = aop =
928 aopForSym (ic, sym->usl.spillLoc, result, requires_a);
929 wassertl (aop->size >= getSize (sym->type), "Operand doesn't fit in the spill location");
930 aop->size = getSize (sym->type);
934 /* must be in a register */
935 sym->aop = op->aop = aop = newAsmop (AOP_REG);
936 aop->size = sym->nRegs;
937 for (i = 0; i < sym->nRegs; i++)
938 aop->aopu.aop_reg[i] = sym->regs[i];
941 /*-----------------------------------------------------------------*/
942 /* freeAsmop - free up the asmop given to an operand */
943 /*----------------------------------------------------------------*/
945 freeAsmop (operand * op, asmop * aaop, iCode * ic)
962 if (aop->type == AOP_PAIRPTR && IS_Z80 && aop->aopu.aop_pairId == PAIR_DE)
964 _pop (aop->aopu.aop_pairId);
968 /* all other cases just dealloc */
974 OP_SYMBOL (op)->aop = NULL;
975 /* if the symbol has a spill */
977 SPIL_LOC (op)->aop = NULL;
984 isLitWord (asmop * aop)
986 /* if (aop->size != 2)
999 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
1003 /* depending on type */
1009 /* PENDING: for re-target */
1012 tsprintf (s, "!hashedstr + %d", aop->aopu.aop_immd, offset);
1014 else if (offset == 0)
1016 tsprintf (s, "%s", aop->aopu.aop_immd);
1020 tsprintf (s, "%s + %d", aop->aopu.aop_immd, offset);
1022 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1026 value *val = aop->aopu.aop_lit;
1027 /* if it is a float then it gets tricky */
1028 /* otherwise it is fairly simple */
1029 if (!IS_FLOAT (val->type))
1031 unsigned long v = (unsigned long) floatFromVal (val);
1037 else if (offset == 0)
1043 wassertl(0, "Encountered an invalid offset while fetching a literal");
1047 tsprintf (buffer, "!immedword", v);
1049 tsprintf (buffer, "!constword", v);
1051 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1062 /* it is type float */
1063 fl.f = (float) floatFromVal (val);
1066 i = fl.c[3-offset] | (fl.c[3-offset-1]<<8);
1068 i = fl.c[offset] | (fl.c[offset+1]<<8);
1071 tsprintf (buffer, "!immedword", i);
1073 tsprintf (buffer, "!constword", i);
1075 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1084 aopGetWord (asmop * aop, int offset)
1086 return aopGetLitWordLong (aop, offset, TRUE);
1090 isPtr (const char *s)
1092 if (!strcmp (s, "hl"))
1094 if (!strcmp (s, "ix"))
1096 if (!strcmp (s, "iy"))
1102 adjustPair (const char *pair, int *pold, int new)
1108 emit2 ("inc %s", pair);
1113 emit2 ("dec %s", pair);
1121 spillPair (PAIR_HL);
1122 spillPair (PAIR_IY);
1126 requiresHL (asmop * aop)
1142 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1144 const char *l, *base;
1145 const char *pair = _pairs[pairId].name;
1146 l = aopGetLitWordLong (left, offset, FALSE);
1147 base = aopGetLitWordLong (left, 0, FALSE);
1148 wassert (l && pair && base);
1152 if (pairId == PAIR_HL || pairId == PAIR_IY)
1154 if (_G.pairs[pairId].last_type == left->type)
1156 if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1158 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1160 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1163 if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
1170 _G.pairs[pairId].last_type = left->type;
1171 _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1172 _G.pairs[pairId].offset = offset;
1174 /* Both a lit on the right and a true symbol on the left */
1175 emit2 ("ld %s,!hashedstr", pair, l);
1179 fetchPairLong (PAIR_ID pairId, asmop * aop, int offset)
1181 /* if this is remateriazable */
1182 if (isLitWord (aop)) {
1183 fetchLitPair (pairId, aop, offset);
1187 if (getPairId (aop) == pairId)
1191 /* we need to get it byte by byte */
1192 else if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1193 aopGet (aop, offset, FALSE);
1194 switch (aop->size - offset) {
1196 emit2 ("ld l,!*hl");
1197 emit2 ("ld h,!immedbyte", 0);
1200 // PENDING: Requires that you are only fetching two bytes.
1203 emit2 ("ld h,!*hl");
1207 wassertl (0, "Attempted to fetch too much data into HL");
1211 else if (IS_Z80 && aop->type == AOP_IY) {
1212 /* Instead of fetching relative to IY, just grab directly
1213 from the address IY refers to */
1214 char *l = aopGetLitWordLong (aop, offset, FALSE);
1216 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1218 if (aop->size < 2) {
1219 emit2("ld %s,!zero", _pairs[pairId].h);
1222 else if (pairId == PAIR_IY)
1226 emit2 ("push %s", _pairs[getPairId(aop)].name);
1232 /* Can't load into parts, so load into HL then exchange. */
1233 emit2 ("ld %s,%s", _pairs[PAIR_HL].l, aopGet (aop, offset, FALSE));
1234 emit2 ("ld %s,%s", _pairs[PAIR_HL].h, aopGet (aop, offset + 1, FALSE));
1241 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1242 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1244 /* PENDING: check? */
1245 if (pairId == PAIR_HL)
1246 spillPair (PAIR_HL);
1251 fetchPair (PAIR_ID pairId, asmop * aop)
1253 fetchPairLong (pairId, aop, 0);
1257 fetchHL (asmop * aop)
1259 fetchPair (PAIR_HL, aop);
1263 setupPairFromSP (PAIR_ID id, int offset)
1265 wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
1267 if (offset < INT8MIN || offset > INT8MAX)
1269 emit2 ("ld hl,!immedword", offset);
1270 emit2 ("add hl,sp");
1274 emit2 ("!ldahlsp", offset);
1279 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1284 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
1285 fetchLitPair (pairId, aop, 0);
1289 wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
1291 fetchLitPair (pairId, aop, offset);
1292 _G.pairs[pairId].offset = offset;
1296 wassertl (IS_Z80, "Only the Z80 has an extended stack");
1297 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
1300 int offset = aop->aopu.aop_stk + _G.stack.offset;
1302 if (_G.pairs[pairId].last_type == aop->type &&
1303 _G.pairs[pairId].offset == offset)
1309 /* PENDING: Do this better. */
1310 sprintf (buffer, "%d", offset + _G.stack.pushed);
1311 emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
1312 emit2 ("add %s,sp", _pairs[pairId].name);
1313 _G.pairs[pairId].last_type = aop->type;
1314 _G.pairs[pairId].offset = offset;
1321 /* Doesnt include _G.stack.pushed */
1322 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1324 if (aop->aopu.aop_stk > 0)
1326 abso += _G.stack.param_offset;
1328 assert (pairId == PAIR_HL);
1329 /* In some cases we can still inc or dec hl */
1330 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1332 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1336 setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
1338 _G.pairs[pairId].offset = abso;
1343 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
1349 _G.pairs[pairId].last_type = aop->type;
1355 emit2 ("!tlabeldef", key);
1359 /*-----------------------------------------------------------------*/
1360 /* aopGet - for fetching value of the aop */
1361 /*-----------------------------------------------------------------*/
1363 aopGet (asmop * aop, int offset, bool bit16)
1367 /* offset is greater than size then zero */
1368 /* PENDING: this seems a bit screwed in some pointer cases. */
1369 if (offset > (aop->size - 1) &&
1370 aop->type != AOP_LIT)
1372 tsprintf (s, "!zero");
1373 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1376 /* depending on type */
1380 /* PENDING: re-target */
1382 tsprintf (s, "!immedwords", aop->aopu.aop_immd);
1387 tsprintf (s, "!bankimmeds", aop->aopu.aop_immd);
1390 tsprintf (s, "!msbimmeds", aop->aopu.aop_immd);
1393 tsprintf (s, "!lsbimmeds", aop->aopu.aop_immd);
1396 wassertl (0, "Fetching from beyond the limits of an immediate value.");
1399 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1403 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1406 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1410 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1413 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1416 return aop->aopu.aop_reg[offset]->name;
1420 setupPair (PAIR_HL, aop, offset);
1421 tsprintf (s, "!*hl");
1423 return traceAlloc(&_G.trace.aops, Safe_strdup (s));
1427 setupPair (PAIR_IY, aop, offset);
1428 tsprintf (s, "!*iyx", offset);
1430 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1434 setupPair (PAIR_IY, aop, offset);
1435 tsprintf (s, "!*iyx", offset, offset);
1437 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1442 setupPair (PAIR_HL, aop, offset);
1443 tsprintf (s, "!*hl");
1447 if (aop->aopu.aop_stk >= 0)
1448 offset += _G.stack.param_offset;
1449 tsprintf (s, "!*ixx", aop->aopu.aop_stk + offset);
1452 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1455 wassertl (0, "Tried to fetch from a bit variable");
1464 tsprintf(s, "!zero");
1465 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1469 wassert (offset < 2);
1470 return aop->aopu.aop_str[offset];
1473 return aopLiteral (aop->aopu.aop_lit, offset);
1477 unsigned long v = aop->aopu.aop_simplelit;
1480 tsprintf (s, "!immedbyte", (unsigned int) v & 0xff);
1482 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1486 return aop->aopu.aop_str[offset];
1489 setupPair (aop->aopu.aop_pairId, aop, offset);
1490 sprintf (s, "(%s)", _pairs[aop->aopu.aop_pairId].name);
1492 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1497 wassertl (0, "aopget got unsupported aop->type");
1502 isRegString (const char *s)
1504 if (!strcmp (s, "b") ||
1516 isConstant (const char *s)
1518 /* This is a bit of a hack... */
1519 return (*s == '#' || *s == '$');
1523 canAssignToPtr (const char *s)
1525 if (isRegString (s))
1532 /*-----------------------------------------------------------------*/
1533 /* aopPut - puts a string for a aop */
1534 /*-----------------------------------------------------------------*/
1536 aopPut (asmop * aop, const char *s, int offset)
1540 if (aop->size && offset > (aop->size - 1))
1542 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1543 "aopPut got offset > aop->size");
1548 tsprintf(buffer2, s);
1551 /* will assign value to value */
1552 /* depending on where it is ofcourse */
1558 if (strcmp (s, "a"))
1559 emit2 ("ld a,%s", s);
1560 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1565 if (strcmp (s, "a"))
1566 emit2 ("ld a,%s", s);
1567 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1571 if (!strcmp (s, "!*hl"))
1572 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1575 aop->aopu.aop_reg[offset]->name, s);
1580 if (!canAssignToPtr (s))
1582 emit2 ("ld a,%s", s);
1583 setupPair (PAIR_IY, aop, offset);
1584 emit2 ("ld !*iyx,a", offset);
1588 setupPair (PAIR_IY, aop, offset);
1589 emit2 ("ld !*iyx,%s", offset, s);
1595 /* PENDING: for re-target */
1596 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1598 emit2 ("ld a,!*hl");
1601 setupPair (PAIR_HL, aop, offset);
1603 emit2 ("ld !*hl,%s", s);
1608 if (!canAssignToPtr (s))
1610 emit2 ("ld a,%s", s);
1611 setupPair (PAIR_IY, aop, offset);
1612 emit2 ("ld !*iyx,a", offset);
1616 setupPair (PAIR_IY, aop, offset);
1617 emit2 ("ld !*iyx,%s", offset, s);
1624 /* PENDING: re-target */
1625 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1627 emit2 ("ld a,!*hl");
1630 setupPair (PAIR_HL, aop, offset);
1631 if (!canAssignToPtr (s))
1633 emit2 ("ld a,%s", s);
1634 emit2 ("ld !*hl,a");
1637 emit2 ("ld !*hl,%s", s);
1641 if (aop->aopu.aop_stk >= 0)
1642 offset += _G.stack.param_offset;
1643 if (!canAssignToPtr (s))
1645 emit2 ("ld a,%s", s);
1646 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
1650 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
1656 /* if bit variable */
1657 if (!aop->aopu.aop_dir)
1664 /* In bit space but not in C - cant happen */
1665 wassertl (0, "Tried to write into a bit variable");
1671 if (strcmp (aop->aopu.aop_str[offset], s))
1673 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1679 if (!offset && (strcmp (s, "acc") == 0))
1683 wassertl (0, "Tried to access past the end of A");
1687 if (strcmp (aop->aopu.aop_str[offset], s))
1688 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1693 wassert (offset < 2);
1694 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1698 setupPair (aop->aopu.aop_pairId, aop, offset);
1699 emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
1703 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1704 "aopPut got unsupported aop->type");
1709 #define AOP(op) op->aop
1710 #define AOP_TYPE(op) AOP(op)->type
1711 #define AOP_SIZE(op) AOP(op)->size
1712 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
1715 commitPair (asmop * aop, PAIR_ID id)
1717 /* PENDING: Verify this. */
1718 if (id == PAIR_HL && requiresHL (aop) && IS_GB)
1722 aopPut (aop, "a", 0);
1723 aopPut (aop, "d", 1);
1728 if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
1730 char *l = aopGetLitWordLong (aop, 0, FALSE);
1733 emit2 ("ld (%s),%s", l, _pairs[id].name);
1737 aopPut (aop, _pairs[id].l, 0);
1738 aopPut (aop, _pairs[id].h, 1);
1743 /*-----------------------------------------------------------------*/
1744 /* getDataSize - get the operand data size */
1745 /*-----------------------------------------------------------------*/
1747 getDataSize (operand * op)
1750 size = AOP_SIZE (op);
1754 wassertl (0, "Somehow got a three byte data pointer");
1759 /*-----------------------------------------------------------------*/
1760 /* movLeft2Result - move byte from left to result */
1761 /*-----------------------------------------------------------------*/
1763 movLeft2Result (operand * left, int offl,
1764 operand * result, int offr, int sign)
1768 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
1770 l = aopGet (AOP (left), offl, FALSE);
1774 aopPut (AOP (result), l, offr);
1778 if (getDataSize (left) == offl + 1)
1780 emit2 ("ld a,%s", l);
1781 aopPut (AOP (result), "a", offr);
1788 movLeft2ResultLong (operand * left, int offl,
1789 operand * result, int offr, int sign,
1794 movLeft2Result (left, offl, result, offr, sign);
1798 wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
1799 wassertl (size == 2, "Only implemented for two bytes or one");
1801 if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
1803 emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
1804 emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
1807 else if ( getPairId ( AOP (result)) == PAIR_IY)
1809 PAIR_ID id = getPairId (AOP (left));
1810 if (id != PAIR_INVALID)
1812 emit2("push %s", _pairs[id].name);
1823 movLeft2Result (left, offl, result, offr, sign);
1824 movLeft2Result (left, offl+1, result, offr+1, sign);
1829 /** Put Acc into a register set
1832 outAcc (operand * result)
1835 size = getDataSize (result);
1838 aopPut (AOP (result), "a", 0);
1841 /* unsigned or positive */
1844 aopPut (AOP (result), "!zero", offset++);
1849 /** Take the value in carry and put it into a register
1852 outBitCLong (operand * result, bool swap_sense)
1854 /* if the result is bit */
1855 if (AOP_TYPE (result) == AOP_CRY)
1857 wassertl (0, "Tried to write carry to a bit");
1861 emit2 ("ld a,!zero");
1864 emit2 ("xor a,!immedbyte", 1);
1870 outBitC (operand * result)
1872 outBitCLong (result, FALSE);
1875 /*-----------------------------------------------------------------*/
1876 /* toBoolean - emit code for orl a,operator(sizeop) */
1877 /*-----------------------------------------------------------------*/
1879 _toBoolean (operand * oper)
1881 int size = AOP_SIZE (oper);
1885 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
1888 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
1892 if (AOP (oper)->type != AOP_ACC)
1895 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
1900 /*-----------------------------------------------------------------*/
1901 /* genNotFloat - generates not for float operations */
1902 /*-----------------------------------------------------------------*/
1904 genNotFloat (operand * op, operand * res)
1909 emitDebug ("; genNotFloat");
1911 /* we will put 127 in the first byte of
1913 aopPut (AOP (res), "!immedbyte", 0x7F);
1914 size = AOP_SIZE (op) - 1;
1917 _moveA (aopGet (op->aop, offset++, FALSE));
1921 emit2 ("or a,%s", aopGet (op->aop, offset++, FALSE));
1924 tlbl = newiTempLabel (NULL);
1925 aopPut (res->aop, "!one", 1);
1926 emit2 ("!shortjp z !tlabel", tlbl->key + 100);
1927 aopPut (res->aop, "!zero", 1);
1929 emitLabel(tlbl->key + 100);
1931 size = res->aop->size - 2;
1933 /* put zeros in the rest */
1935 aopPut (res->aop, "!zero", offset++);
1938 /*-----------------------------------------------------------------*/
1939 /* genNot - generate code for ! operation */
1940 /*-----------------------------------------------------------------*/
1944 sym_link *optype = operandType (IC_LEFT (ic));
1946 /* assign asmOps to operand & result */
1947 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
1948 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1950 /* if in bit space then a special case */
1951 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1953 wassertl (0, "Tried to negate a bit");
1956 /* if type float then do float */
1957 if (IS_FLOAT (optype))
1959 genNotFloat (IC_LEFT (ic), IC_RESULT (ic));
1963 _toBoolean (IC_LEFT (ic));
1968 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
1969 emit2 ("sub a,!one");
1970 outBitC (IC_RESULT (ic));
1973 /* release the aops */
1974 freeAsmop (IC_LEFT (ic), NULL, ic);
1975 freeAsmop (IC_RESULT (ic), NULL, ic);
1978 /*-----------------------------------------------------------------*/
1979 /* genCpl - generate code for complement */
1980 /*-----------------------------------------------------------------*/
1988 /* assign asmOps to operand & result */
1989 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1990 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1992 /* if both are in bit space then
1994 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1995 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1997 wassertl (0, "Left and the result are in bit space");
2000 size = AOP_SIZE (IC_RESULT (ic));
2003 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2006 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2009 /* release the aops */
2010 freeAsmop (IC_LEFT (ic), NULL, ic);
2011 freeAsmop (IC_RESULT (ic), NULL, ic);
2015 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
2022 store de into result
2027 store de into result
2029 const char *first = isAdd ? "add" : "sub";
2030 const char *later = isAdd ? "adc" : "sbc";
2032 wassertl (IS_GB, "Code is only relevent to the gbz80");
2033 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
2035 fetchPair (PAIR_DE, left);
2038 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
2041 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2044 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2045 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2047 fetchPairLong (PAIR_DE, left, MSB24);
2048 aopGet (right, MSB24, FALSE);
2052 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2055 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2057 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2058 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2062 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2064 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2067 /*-----------------------------------------------------------------*/
2068 /* genUminusFloat - unary minus for floating points */
2069 /*-----------------------------------------------------------------*/
2071 genUminusFloat (operand * op, operand * result)
2073 int size, offset = 0;
2075 emitDebug("; genUminusFloat");
2077 /* for this we just need to flip the
2078 first it then copy the rest in place */
2079 size = AOP_SIZE (op) - 1;
2081 _moveA(aopGet (AOP (op), MSB32, FALSE));
2083 emit2("xor a,!immedbyte", 0x80);
2084 aopPut (AOP (result), "a", MSB32);
2088 aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2093 /*-----------------------------------------------------------------*/
2094 /* genUminus - unary minus code generation */
2095 /*-----------------------------------------------------------------*/
2097 genUminus (iCode * ic)
2100 sym_link *optype, *rtype;
2103 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2104 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2106 /* if both in bit space then special
2108 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2109 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2111 wassertl (0, "Left and right are in bit space");
2115 optype = operandType (IC_LEFT (ic));
2116 rtype = operandType (IC_RESULT (ic));
2118 /* if float then do float stuff */
2119 if (IS_FLOAT (optype))
2121 genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2125 /* otherwise subtract from zero */
2126 size = AOP_SIZE (IC_LEFT (ic));
2128 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2130 /* Create a new asmop with value zero */
2131 asmop *azero = newAsmop (AOP_SIMPLELIT);
2132 azero->aopu.aop_simplelit = 0;
2134 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2142 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2143 emit2 ("ld a,!zero");
2144 emit2 ("sbc a,%s", l);
2145 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2148 /* if any remaining bytes in the result */
2149 /* we just need to propagate the sign */
2150 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2155 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2159 /* release the aops */
2160 freeAsmop (IC_LEFT (ic), NULL, ic);
2161 freeAsmop (IC_RESULT (ic), NULL, ic);
2164 /*-----------------------------------------------------------------*/
2165 /* assignResultValue - */
2166 /*-----------------------------------------------------------------*/
2168 assignResultValue (operand * oper)
2170 int size = AOP_SIZE (oper);
2173 wassertl (size <= 4, "Got a result that is bigger than four bytes");
2174 topInA = requiresHL (AOP (oper));
2176 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2178 /* We do it the hard way here. */
2180 aopPut (AOP (oper), _fReturn[0], 0);
2181 aopPut (AOP (oper), _fReturn[1], 1);
2183 aopPut (AOP (oper), _fReturn[0], 2);
2184 aopPut (AOP (oper), _fReturn[1], 3);
2190 aopPut (AOP (oper), _fReturn[size], size);
2195 /** Simple restore that doesn't take into account what is used in the
2199 _restoreRegsAfterCall(void)
2201 if (_G.stack.pushedDE)
2204 _G.stack.pushedDE = FALSE;
2206 if (_G.stack.pushedBC)
2209 _G.stack.pushedBC = FALSE;
2211 _G.saves.saved = FALSE;
2215 _saveRegsForCall(iCode *ic, int sendSetSize)
2218 o Stack parameters are pushed before this function enters
2219 o DE and BC may be used in this function.
2220 o HL and DE may be used to return the result.
2221 o HL and DE may be used to send variables.
2222 o DE and BC may be used to store the result value.
2223 o HL may be used in computing the sent value of DE
2224 o The iPushes for other parameters occur before any addSets
2226 Logic: (to be run inside the first iPush or if none, before sending)
2227 o Compute if DE and/or BC are in use over the call
2228 o Compute if DE is used in the send set
2229 o Compute if DE and/or BC are used to hold the result value
2230 o If (DE is used, or in the send set) and is not used in the result, push.
2231 o If BC is used and is not in the result, push
2233 o If DE is used in the send set, fetch
2234 o If HL is used in the send set, fetch
2238 if (_G.saves.saved == FALSE) {
2239 bool deInUse, bcInUse;
2241 bool bcInRet = FALSE, deInRet = FALSE;
2244 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
2246 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2247 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2249 deSending = (sendSetSize > 1);
2251 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2253 if (bcInUse && bcInRet == FALSE) {
2255 _G.stack.pushedBC = TRUE;
2257 if (deInUse && deInRet == FALSE) {
2259 _G.stack.pushedDE = TRUE;
2262 _G.saves.saved = TRUE;
2265 /* Already saved. */
2269 /*-----------------------------------------------------------------*/
2270 /* genIpush - genrate code for pushing this gets a little complex */
2271 /*-----------------------------------------------------------------*/
2273 genIpush (iCode * ic)
2275 int size, offset = 0;
2278 /* if this is not a parm push : ie. it is spill push
2279 and spill push is always done on the local stack */
2282 wassertl(0, "Encountered an unsupported spill push.");
2286 if (_G.saves.saved == FALSE) {
2287 /* Caller saves, and this is the first iPush. */
2288 /* Scan ahead until we find the function that we are pushing parameters to.
2289 Count the number of addSets on the way to figure out what registers
2290 are used in the send set.
2293 iCode *walk = ic->next;
2296 if (walk->op == SEND) {
2299 else if (walk->op == CALL || walk->op == PCALL) {
2308 _saveRegsForCall(walk, nAddSets);
2311 /* Already saved by another iPush. */
2314 /* then do the push */
2315 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2317 size = AOP_SIZE (IC_LEFT (ic));
2319 if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2321 _G.stack.pushed += 2;
2322 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2328 fetchHL (AOP (IC_LEFT (ic)));
2330 spillPair (PAIR_HL);
2331 _G.stack.pushed += 2;
2336 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
2338 spillPair (PAIR_HL);
2339 _G.stack.pushed += 2;
2340 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 0);
2342 spillPair (PAIR_HL);
2343 _G.stack.pushed += 2;
2349 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2351 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2353 emit2 ("ld a,(%s)", l);
2357 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2358 emit2 ("ld a,%s", l);
2366 freeAsmop (IC_LEFT (ic), NULL, ic);
2369 /*-----------------------------------------------------------------*/
2370 /* genIpop - recover the registers: can happen only for spilling */
2371 /*-----------------------------------------------------------------*/
2373 genIpop (iCode * ic)
2378 /* if the temp was not pushed then */
2379 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2382 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2383 size = AOP_SIZE (IC_LEFT (ic));
2384 offset = (size - 1);
2385 if (isPair (AOP (IC_LEFT (ic))))
2387 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2395 spillPair (PAIR_HL);
2396 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2400 freeAsmop (IC_LEFT (ic), NULL, ic);
2403 /* This is quite unfortunate */
2405 setArea (int inHome)
2408 static int lastArea = 0;
2410 if (_G.in_home != inHome) {
2412 const char *sz = port->mem.code_name;
2413 port->mem.code_name = "HOME";
2414 emit2("!area", CODE_NAME);
2415 port->mem.code_name = sz;
2418 emit2("!area", CODE_NAME); */
2419 _G.in_home = inHome;
2430 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2434 symbol *sym = OP_SYMBOL (op);
2436 if (sym->isspilt || sym->nRegs == 0)
2439 aopOp (op, ic, FALSE, FALSE);
2442 if (aop->type == AOP_REG)
2445 for (i = 0; i < aop->size; i++)
2447 if (pairId == PAIR_DE)
2449 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2450 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2452 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2455 else if (pairId == PAIR_BC)
2457 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2458 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2460 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2470 freeAsmop (IC_LEFT (ic), NULL, ic);
2474 /** Emit the code for a call statement
2477 emitCall (iCode * ic, bool ispcall)
2479 sym_link *dtype = operandType (IC_LEFT (ic));
2481 /* if caller saves & we have not saved then */
2487 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2489 /* if send set is not empty then assign */
2494 int nSend = elementsInSet(_G.sendSet);
2495 bool swapped = FALSE;
2497 int _z80_sendOrder[] = {
2502 /* Check if the parameters are swapped. If so route through hl instead. */
2503 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2505 sic = setFirstItem(_G.sendSet);
2506 sic = setNextItem(_G.sendSet);
2508 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2509 /* The second send value is loaded from one the one that holds the first
2510 send, i.e. it is overwritten. */
2511 /* Cache the first in HL, and load the second from HL instead. */
2512 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2513 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2519 for (sic = setFirstItem (_G.sendSet); sic;
2520 sic = setNextItem (_G.sendSet))
2523 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2525 size = AOP_SIZE (IC_LEFT (sic));
2526 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2527 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2529 // PENDING: Mild hack
2530 if (swapped == TRUE && send == 1) {
2532 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2535 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2537 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2540 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2544 freeAsmop (IC_LEFT (sic), NULL, sic);
2551 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2553 werror (W_INDIR_BANKED);
2555 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2557 if (isLitWord (AOP (IC_LEFT (ic))))
2559 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2563 symbol *rlbl = newiTempLabel (NULL);
2564 spillPair (PAIR_HL);
2565 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2567 _G.stack.pushed += 2;
2569 fetchHL (AOP (IC_LEFT (ic)));
2571 emit2 ("!tlabeldef", (rlbl->key + 100));
2572 _G.stack.pushed -= 2;
2574 freeAsmop (IC_LEFT (ic), NULL, ic);
2578 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2579 OP_SYMBOL (IC_LEFT (ic))->rname :
2580 OP_SYMBOL (IC_LEFT (ic))->name;
2581 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2583 emit2 ("call banked_call");
2584 emit2 ("!dws", name);
2585 emit2 ("!dw !bankimmeds", name);
2590 emit2 ("call %s", name);
2595 /* Mark the regsiters as restored. */
2596 _G.saves.saved = FALSE;
2598 /* if we need assign a result value */
2599 if ((IS_ITEMP (IC_RESULT (ic)) &&
2600 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2601 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2602 IS_TRUE_SYMOP (IC_RESULT (ic)))
2605 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2607 assignResultValue (IC_RESULT (ic));
2609 freeAsmop (IC_RESULT (ic), NULL, ic);
2612 /* adjust the stack for parameters if required */
2615 int i = ic->parmBytes;
2617 _G.stack.pushed -= i;
2620 emit2 ("!ldaspsp", i);
2627 emit2 ("ld iy,#%d", i);
2628 emit2 ("add iy,sp");
2648 if (_G.stack.pushedDE)
2650 bool dInRet = bitVectBitValue(ic->rUsed, D_IDX);
2651 bool eInRet = bitVectBitValue(ic->rUsed, E_IDX);
2653 if (dInRet && eInRet)
2655 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
2659 /* Only restore E */
2666 /* Only restore D */
2674 _G.stack.pushedDE = FALSE;
2677 if (_G.stack.pushedBC)
2679 bool bInRet = bitVectBitValue(ic->rUsed, B_IDX);
2680 bool cInRet = bitVectBitValue(ic->rUsed, C_IDX);
2682 if (bInRet && cInRet)
2684 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
2688 /* Only restore C */
2695 /* Only restore B */
2703 _G.stack.pushedBC = FALSE;
2707 /*-----------------------------------------------------------------*/
2708 /* genCall - generates a call statement */
2709 /*-----------------------------------------------------------------*/
2711 genCall (iCode * ic)
2713 emitCall (ic, FALSE);
2716 /*-----------------------------------------------------------------*/
2717 /* genPcall - generates a call by pointer statement */
2718 /*-----------------------------------------------------------------*/
2720 genPcall (iCode * ic)
2722 emitCall (ic, TRUE);
2725 /*-----------------------------------------------------------------*/
2726 /* resultRemat - result is rematerializable */
2727 /*-----------------------------------------------------------------*/
2729 resultRemat (iCode * ic)
2731 if (SKIP_IC (ic) || ic->op == IFX)
2734 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2736 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2737 if (sym->remat && !POINTER_SET (ic))
2744 extern set *publics;
2746 /*-----------------------------------------------------------------*/
2747 /* genFunction - generated code for function entry */
2748 /*-----------------------------------------------------------------*/
2750 genFunction (iCode * ic)
2752 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2756 bool bcInUse = FALSE;
2757 bool deInUse = FALSE;
2760 setArea (IFFUNC_NONBANKED (sym->type));
2762 /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
2765 _G.receiveOffset = 0;
2767 /* Record the last function name for debugging. */
2768 _G.lastFunctionName = sym->rname;
2770 /* Create the function header */
2771 emit2 ("!functionheader", sym->name);
2772 /* PENDING: portability. */
2773 emit2 ("__%s_start:", sym->rname);
2774 emit2 ("!functionlabeldef", sym->rname);
2776 if (options.profile)
2778 emit2 ("!profileenter");
2781 ftype = operandType (IC_LEFT (ic));
2783 /* if critical function then turn interrupts off */
2784 if (IFFUNC_ISCRITICAL (ftype))
2787 /* if this is an interrupt service routine then save all potentially used registers. */
2788 if (IFFUNC_ISISR (sym->type))
2793 /* PENDING: callee-save etc */
2795 _G.stack.param_offset = 0;
2798 /* Detect which registers are used. */
2802 for (i = 0; i < sym->regsUsed->size; i++)
2804 if (bitVectBitValue (sym->regsUsed, i))
2818 /* Other systems use DE as a temporary. */
2829 _G.stack.param_offset += 2;
2832 _G.stack.pushedBC = bcInUse;
2837 _G.stack.param_offset += 2;
2840 _G.stack.pushedDE = deInUse;
2843 /* adjust the stack for the function */
2844 _G.stack.last = sym->stack;
2846 if (sym->stack && IS_GB && sym->stack > -INT8MIN)
2847 emit2 ("!enterxl", sym->stack);
2848 else if (sym->stack)
2849 emit2 ("!enterx", sym->stack);
2852 _G.stack.offset = sym->stack;
2855 /*-----------------------------------------------------------------*/
2856 /* genEndFunction - generates epilogue for functions */
2857 /*-----------------------------------------------------------------*/
2859 genEndFunction (iCode * ic)
2861 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2863 if (IFFUNC_ISISR (sym->type))
2865 wassertl (0, "Tried to close an interrupt support function");
2869 if (IFFUNC_ISCRITICAL (sym->type))
2872 /* PENDING: calleeSave */
2874 if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
2876 emit2 ("!leavexl", _G.stack.offset);
2878 else if (_G.stack.offset)
2880 emit2 ("!leavex", _G.stack.offset);
2888 if (_G.stack.pushedDE)
2891 _G.stack.pushedDE = FALSE;
2894 if (_G.stack.pushedDE)
2897 _G.stack.pushedDE = FALSE;
2901 if (options.profile)
2903 emit2 ("!profileexit");
2907 /* Both baned and non-banked just ret */
2910 /* PENDING: portability. */
2911 emit2 ("__%s_end:", sym->rname);
2913 _G.flushStatics = 1;
2914 _G.stack.pushed = 0;
2915 _G.stack.offset = 0;
2918 /*-----------------------------------------------------------------*/
2919 /* genRet - generate code for return statement */
2920 /*-----------------------------------------------------------------*/
2925 /* Errk. This is a hack until I can figure out how
2926 to cause dehl to spill on a call */
2927 int size, offset = 0;
2929 /* if we have no return value then
2930 just generate the "ret" */
2934 /* we have something to return then
2935 move the return value into place */
2936 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2937 size = AOP_SIZE (IC_LEFT (ic));
2939 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
2943 emit2 ("ld de,%s", l);
2947 emit2 ("ld hl,%s", l);
2952 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
2954 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
2955 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
2961 l = aopGet (AOP (IC_LEFT (ic)), offset,
2963 if (strcmp (_fReturn[offset], l))
2964 emit2 ("ld %s,%s", _fReturn[offset++], l);
2968 freeAsmop (IC_LEFT (ic), NULL, ic);
2971 /* generate a jump to the return label
2972 if the next is not the return statement */
2973 if (!(ic->next && ic->next->op == LABEL &&
2974 IC_LABEL (ic->next) == returnLabel))
2976 emit2 ("jp !tlabel", returnLabel->key + 100);
2979 /*-----------------------------------------------------------------*/
2980 /* genLabel - generates a label */
2981 /*-----------------------------------------------------------------*/
2983 genLabel (iCode * ic)
2985 /* special case never generate */
2986 if (IC_LABEL (ic) == entryLabel)
2989 emitLabel (IC_LABEL (ic)->key + 100);
2992 /*-----------------------------------------------------------------*/
2993 /* genGoto - generates a ljmp */
2994 /*-----------------------------------------------------------------*/
2996 genGoto (iCode * ic)
2998 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3001 /*-----------------------------------------------------------------*/
3002 /* genPlusIncr :- does addition with increment if possible */
3003 /*-----------------------------------------------------------------*/
3005 genPlusIncr (iCode * ic)
3007 unsigned int icount;
3008 unsigned int size = getDataSize (IC_RESULT (ic));
3009 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3011 /* will try to generate an increment */
3012 /* if the right side is not a literal
3014 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3017 emitDebug ("; genPlusIncr");
3019 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3021 /* If result is a pair */
3022 if (resultId != PAIR_INVALID)
3024 if (isLitWord (AOP (IC_LEFT (ic))))
3026 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3029 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3031 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3033 PAIR_ID freep = getFreePairId (ic);
3034 if (freep != PAIR_INVALID)
3036 fetchPair (freep, AOP (IC_RIGHT (ic)));
3037 emit2 ("add hl,%s", _pairs[freep].name);
3043 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3044 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3051 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3055 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3059 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3064 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3066 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3067 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3071 /* if the literal value of the right hand side
3072 is greater than 4 then it is not worth it */
3076 /* if increment 16 bits in register */
3077 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3083 symbol *tlbl = NULL;
3084 tlbl = newiTempLabel (NULL);
3087 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3090 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3093 emitLabel (tlbl->key + 100);
3097 /* if the sizes are greater than 1 then we cannot */
3098 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3099 AOP_SIZE (IC_LEFT (ic)) > 1)
3102 /* If the result is in a register then we can load then increment.
3104 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3106 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3109 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3114 /* we can if the aops of the left & result match or
3115 if they are in registers and the registers are the
3117 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3121 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3129 /*-----------------------------------------------------------------*/
3130 /* outBitAcc - output a bit in acc */
3131 /*-----------------------------------------------------------------*/
3133 outBitAcc (operand * result)
3135 symbol *tlbl = newiTempLabel (NULL);
3136 /* if the result is a bit */
3137 if (AOP_TYPE (result) == AOP_CRY)
3139 wassertl (0, "Tried to write A into a bit");
3143 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3144 emit2 ("ld a,!one");
3145 emitLabel (tlbl->key + 100);
3151 couldDestroyCarry (asmop *aop)
3155 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3164 shiftIntoPair (int idx, asmop *aop)
3166 PAIR_ID id = PAIR_INVALID;
3168 wassertl (IS_Z80, "Only implemented for the Z80");
3169 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3181 wassertl (0, "Internal error - hit default case");
3184 emitDebug ("; Shift into pair idx %u", idx);
3188 setupPair (PAIR_HL, aop, 0);
3192 setupPair (PAIR_IY, aop, 0);
3194 emit2 ("pop %s", _pairs[id].name);
3197 aop->type = AOP_PAIRPTR;
3198 aop->aopu.aop_pairId = id;
3199 _G.pairs[id].offset = 0;
3200 _G.pairs[id].last_type = aop->type;
3204 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
3206 wassert (left && right);
3210 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3212 shiftIntoPair (0, right);
3213 shiftIntoPair (1, result);
3215 else if (couldDestroyCarry (right))
3217 shiftIntoPair (0, right);
3219 else if (couldDestroyCarry (result))
3221 shiftIntoPair (0, result);
3230 /*-----------------------------------------------------------------*/
3231 /* genPlus - generates code for addition */
3232 /*-----------------------------------------------------------------*/
3234 genPlus (iCode * ic)
3236 int size, offset = 0;
3238 /* special cases :- */
3240 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3241 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3242 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3244 /* Swap the left and right operands if:
3246 if literal, literal on the right or
3247 if left requires ACC or right is already
3250 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3251 (AOP_NEEDSACC (IC_LEFT (ic))) ||
3252 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3254 operand *t = IC_RIGHT (ic);
3255 IC_RIGHT (ic) = IC_LEFT (ic);
3259 /* if both left & right are in bit
3261 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3262 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3265 wassertl (0, "Tried to add two bits");
3268 /* if left in bit space & right literal */
3269 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3270 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3272 /* Can happen I guess */
3273 wassertl (0, "Tried to add a bit to a literal");
3276 /* if I can do an increment instead
3277 of add then GOOD for ME */
3278 if (genPlusIncr (ic) == TRUE)
3281 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3283 size = getDataSize (IC_RESULT (ic));
3285 /* Special case when left and right are constant */
3286 if (isPair (AOP (IC_RESULT (ic))))
3289 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3290 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3292 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3298 sprintf (buffer, "#(%s + %s)", left, right);
3299 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3304 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3306 /* Fetch into HL then do the add */
3307 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3308 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3310 spillPair (PAIR_HL);
3312 if (left == PAIR_HL && right != PAIR_INVALID)
3314 emit2 ("add hl,%s", _pairs[right].name);
3317 else if (right == PAIR_HL && left != PAIR_INVALID)
3319 emit2 ("add hl,%s", _pairs[left].name);
3322 else if (right != PAIR_INVALID && right != PAIR_HL)
3324 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3325 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3328 else if (left != PAIR_INVALID && left != PAIR_HL)
3330 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3331 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3340 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3342 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3343 emit2 ("add hl,%s ; 2", getPairName (AOP (IC_RIGHT (ic))));
3345 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3350 ld hl,sp+n trashes C so we cant afford to do it during an
3351 add with stack based varibles. Worst case is:
3364 So you cant afford to load up hl if either left, right, or result
3365 is on the stack (*sigh*) The alt is:
3373 Combinations in here are:
3374 * If left or right are in bc then the loss is small - trap later
3375 * If the result is in bc then the loss is also small
3379 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3380 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3381 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3383 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3384 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3385 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3386 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3388 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3390 /* Swap left and right */
3391 operand *t = IC_RIGHT (ic);
3392 IC_RIGHT (ic) = IC_LEFT (ic);
3395 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3397 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3398 emit2 ("add hl,bc");
3402 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3403 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3404 emit2 ("add hl,de");
3406 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3412 /* Be paranoid on the GB with 4 byte variables due to how C
3413 can be trashed by lda hl,n(sp).
3415 _gbz80_emitAddSubLong (ic, TRUE);
3420 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3424 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3426 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3429 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3432 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3436 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3439 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3442 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3444 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3448 freeAsmop (IC_LEFT (ic), NULL, ic);
3449 freeAsmop (IC_RIGHT (ic), NULL, ic);
3450 freeAsmop (IC_RESULT (ic), NULL, ic);
3454 /*-----------------------------------------------------------------*/
3455 /* genMinusDec :- does subtraction with deccrement if possible */
3456 /*-----------------------------------------------------------------*/
3458 genMinusDec (iCode * ic)
3460 unsigned int icount;
3461 unsigned int size = getDataSize (IC_RESULT (ic));
3463 /* will try to generate an increment */
3464 /* if the right side is not a literal we cannot */
3465 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3468 /* if the literal value of the right hand side
3469 is greater than 4 then it is not worth it */
3470 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3473 size = getDataSize (IC_RESULT (ic));
3475 /* if decrement 16 bits in register */
3476 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3477 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3480 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3484 /* If result is a pair */
3485 if (isPair (AOP (IC_RESULT (ic))))
3487 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3489 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3493 /* if increment 16 bits in register */
3494 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3498 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3501 emit2 ("dec %s", _getTempPairName());
3504 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3510 /* if the sizes are greater than 1 then we cannot */
3511 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3512 AOP_SIZE (IC_LEFT (ic)) > 1)
3515 /* we can if the aops of the left & result match or if they are in
3516 registers and the registers are the same */
3517 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3520 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3527 /*-----------------------------------------------------------------*/
3528 /* genMinus - generates code for subtraction */
3529 /*-----------------------------------------------------------------*/
3531 genMinus (iCode * ic)
3533 int size, offset = 0;
3534 unsigned long lit = 0L;
3536 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3537 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3538 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3540 /* special cases :- */
3541 /* if both left & right are in bit space */
3542 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3543 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3545 wassertl (0, "Tried to subtract two bits");
3549 /* if I can do an decrement instead of subtract then GOOD for ME */
3550 if (genMinusDec (ic) == TRUE)
3553 size = getDataSize (IC_RESULT (ic));
3555 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3560 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3564 /* Same logic as genPlus */
3567 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3568 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3569 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3571 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3572 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3573 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3574 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3576 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3577 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3579 if (left == PAIR_INVALID && right == PAIR_INVALID)
3584 else if (right == PAIR_INVALID)
3586 else if (left == PAIR_INVALID)
3589 fetchPair (left, AOP (IC_LEFT (ic)));
3590 /* Order is important. Right may be HL */
3591 fetchPair (right, AOP (IC_RIGHT (ic)));
3593 emit2 ("ld a,%s", _pairs[left].l);
3594 emit2 ("sub a,%s", _pairs[right].l);
3596 emit2 ("ld a,%s", _pairs[left].h);
3597 emit2 ("sbc a,%s", _pairs[right].h);
3599 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
3601 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3603 aopPut (AOP (IC_RESULT (ic)), "e", 0);
3609 /* Be paranoid on the GB with 4 byte variables due to how C
3610 can be trashed by lda hl,n(sp).
3612 _gbz80_emitAddSubLong (ic, FALSE);
3617 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3619 /* if literal, add a,#-lit, else normal subb */
3622 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3623 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3627 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3630 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3634 /* first add without previous c */
3636 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
3638 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3640 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3643 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3644 AOP_SIZE (IC_LEFT (ic)) == 3 &&
3645 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3647 wassertl (0, "Tried to subtract on a long pointer");
3651 freeAsmop (IC_LEFT (ic), NULL, ic);
3652 freeAsmop (IC_RIGHT (ic), NULL, ic);
3653 freeAsmop (IC_RESULT (ic), NULL, ic);
3656 /*-----------------------------------------------------------------*/
3657 /* genMult - generates code for multiplication */
3658 /*-----------------------------------------------------------------*/
3660 genMult (iCode * ic)
3664 /* If true then the final operation should be a subtract */
3665 bool active = FALSE;
3667 /* Shouldn't occur - all done through function calls */
3668 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3669 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3670 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3672 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
3673 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
3674 AOP_SIZE (IC_RESULT (ic)) > 2)
3676 wassertl (0, "Multiplication is handled through support function calls");
3679 /* Swap left and right such that right is a literal */
3680 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
3682 operand *t = IC_RIGHT (ic);
3683 IC_RIGHT (ic) = IC_LEFT (ic);
3687 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
3689 val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
3690 // wassertl (val > 0, "Multiply must be positive");
3691 wassertl (val != 1, "Can't multiply by 1");
3697 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
3699 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
3707 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3712 /* Fully unroled version of mul.s. Not the most efficient.
3714 for (count = 0; count < 16; count++)
3716 if (count != 0 && active)
3718 emit2 ("add hl,hl");
3722 if (active == FALSE)
3729 emit2 ("add hl,de");
3743 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3745 freeAsmop (IC_LEFT (ic), NULL, ic);
3746 freeAsmop (IC_RIGHT (ic), NULL, ic);
3747 freeAsmop (IC_RESULT (ic), NULL, ic);
3750 /*-----------------------------------------------------------------*/
3751 /* genDiv - generates code for division */
3752 /*-----------------------------------------------------------------*/
3756 /* Shouldn't occur - all done through function calls */
3757 wassertl (0, "Division is handled through support function calls");
3760 /*-----------------------------------------------------------------*/
3761 /* genMod - generates code for division */
3762 /*-----------------------------------------------------------------*/
3766 /* Shouldn't occur - all done through function calls */
3770 /*-----------------------------------------------------------------*/
3771 /* genIfxJump :- will create a jump depending on the ifx */
3772 /*-----------------------------------------------------------------*/
3774 genIfxJump (iCode * ic, char *jval)
3779 /* if true label then we jump if condition
3783 jlbl = IC_TRUE (ic);
3784 if (!strcmp (jval, "a"))
3788 else if (!strcmp (jval, "c"))
3792 else if (!strcmp (jval, "nc"))
3796 else if (!strcmp (jval, "m"))
3800 else if (!strcmp (jval, "p"))
3806 /* The buffer contains the bit on A that we should test */
3812 /* false label is present */
3813 jlbl = IC_FALSE (ic);
3814 if (!strcmp (jval, "a"))
3818 else if (!strcmp (jval, "c"))
3822 else if (!strcmp (jval, "nc"))
3826 else if (!strcmp (jval, "m"))
3830 else if (!strcmp (jval, "p"))
3836 /* The buffer contains the bit on A that we should test */
3840 /* Z80 can do a conditional long jump */
3841 if (!strcmp (jval, "a"))
3845 else if (!strcmp (jval, "c"))
3848 else if (!strcmp (jval, "nc"))
3851 else if (!strcmp (jval, "m"))
3854 else if (!strcmp (jval, "p"))
3859 emit2 ("bit %s,a", jval);
3861 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
3863 /* mark the icode as generated */
3869 _getPairIdName (PAIR_ID id)
3871 return _pairs[id].name;
3876 /* if unsigned char cmp with lit, just compare */
3878 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
3880 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3883 emit2 ("xor a,!immedbyte", 0x80);
3884 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
3887 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3889 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
3891 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
3892 // Pull left into DE and right into HL
3893 aopGet (AOP(left), LSB, FALSE);
3896 aopGet (AOP(right), LSB, FALSE);
3900 if (size == 0 && sign)
3902 // Highest byte when signed needs the bits flipped
3905 emit2 ("ld a,(de)");
3906 emit2 ("xor #0x80");
3908 emit2 ("ld a,(hl)");
3909 emit2 ("xor #0x80");
3913 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
3917 emit2 ("ld a,(de)");
3918 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
3928 spillPair (PAIR_HL);
3930 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
3932 setupPair (PAIR_HL, AOP (left), 0);
3933 aopGet (AOP(right), LSB, FALSE);
3937 if (size == 0 && sign)
3939 // Highest byte when signed needs the bits flipped
3942 emit2 ("ld a,(hl)");
3943 emit2 ("xor #0x80");
3945 emit2 ("ld a,%d(iy)", offset);
3946 emit2 ("xor #0x80");
3950 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
3954 emit2 ("ld a,(hl)");
3955 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
3964 spillPair (PAIR_HL);
3965 spillPair (PAIR_IY);
3969 if (AOP_TYPE (right) == AOP_LIT)
3971 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3972 /* optimize if(x < 0) or if(x >= 0) */
3977 /* No sign so it's always false */
3982 /* Just load in the top most bit */
3983 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
3984 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
3986 genIfxJump (ifx, "7");
3998 /* First setup h and l contaning the top most bytes XORed */
3999 bool fDidXor = FALSE;
4000 if (AOP_TYPE (left) == AOP_LIT)
4002 unsigned long lit = (unsigned long)
4003 floatFromVal (AOP (left)->aopu.aop_lit);
4004 emit2 ("ld %s,!immedbyte", _fTmp[0],
4005 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4009 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4010 emit2 ("xor a,!immedbyte", 0x80);
4011 emit2 ("ld %s,a", _fTmp[0]);
4014 if (AOP_TYPE (right) == AOP_LIT)
4016 unsigned long lit = (unsigned long)
4017 floatFromVal (AOP (right)->aopu.aop_lit);
4018 emit2 ("ld %s,!immedbyte", _fTmp[1],
4019 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4023 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4024 emit2 ("xor a,!immedbyte", 0x80);
4025 emit2 ("ld %s,a", _fTmp[1]);
4031 /* Do a long subtract */
4034 _moveA (aopGet (AOP (left), offset, FALSE));
4036 if (sign && size == 0)
4038 emit2 ("ld a,%s", _fTmp[0]);
4039 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4043 /* Subtract through, propagating the carry */
4044 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4052 /** Generic compare for > or <
4055 genCmp (operand * left, operand * right,
4056 operand * result, iCode * ifx, int sign)
4058 int size, offset = 0;
4059 unsigned long lit = 0L;
4060 bool swap_sense = FALSE;
4062 /* if left & right are bit variables */
4063 if (AOP_TYPE (left) == AOP_CRY &&
4064 AOP_TYPE (right) == AOP_CRY)
4066 /* Cant happen on the Z80 */
4067 wassertl (0, "Tried to compare two bits");
4071 /* Do a long subtract of right from left. */
4072 size = max (AOP_SIZE (left), AOP_SIZE (right));
4074 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4076 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4077 // Pull left into DE and right into HL
4078 aopGet (AOP(left), LSB, FALSE);
4081 aopGet (AOP(right), LSB, FALSE);
4085 emit2 ("ld a,(de)");
4086 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4095 spillPair (PAIR_HL);
4099 if (AOP_TYPE (right) == AOP_LIT)
4101 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4102 /* optimize if(x < 0) or if(x >= 0) */
4107 /* No sign so it's always false */
4112 /* Just load in the top most bit */
4113 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4114 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4116 genIfxJump (ifx, "7");
4127 genIfxJump (ifx, swap_sense ? "c" : "nc");
4138 _moveA (aopGet (AOP (left), offset, FALSE));
4139 /* Subtract through, propagating the carry */
4140 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4146 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4150 /* Shift the sign bit up into carry */
4153 outBitCLong (result, swap_sense);
4157 /* if the result is used in the next
4158 ifx conditional branch then generate
4159 code a little differently */
4167 genIfxJump (ifx, swap_sense ? "nc" : "c");
4171 genIfxJump (ifx, swap_sense ? "p" : "m");
4176 genIfxJump (ifx, swap_sense ? "nc" : "c");
4183 /* Shift the sign bit up into carry */
4186 outBitCLong (result, swap_sense);
4188 /* leave the result in acc */
4192 /*-----------------------------------------------------------------*/
4193 /* genCmpGt :- greater than comparison */
4194 /*-----------------------------------------------------------------*/
4196 genCmpGt (iCode * ic, iCode * ifx)
4198 operand *left, *right, *result;
4199 sym_link *letype, *retype;
4202 left = IC_LEFT (ic);
4203 right = IC_RIGHT (ic);
4204 result = IC_RESULT (ic);
4206 letype = getSpec (operandType (left));
4207 retype = getSpec (operandType (right));
4208 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4209 /* assign the amsops */
4210 aopOp (left, ic, FALSE, FALSE);
4211 aopOp (right, ic, FALSE, FALSE);
4212 aopOp (result, ic, TRUE, FALSE);
4214 genCmp (right, left, result, ifx, sign);
4216 freeAsmop (left, NULL, ic);
4217 freeAsmop (right, NULL, ic);
4218 freeAsmop (result, NULL, ic);
4221 /*-----------------------------------------------------------------*/
4222 /* genCmpLt - less than comparisons */
4223 /*-----------------------------------------------------------------*/
4225 genCmpLt (iCode * ic, iCode * ifx)
4227 operand *left, *right, *result;
4228 sym_link *letype, *retype;
4231 left = IC_LEFT (ic);
4232 right = IC_RIGHT (ic);
4233 result = IC_RESULT (ic);
4235 letype = getSpec (operandType (left));
4236 retype = getSpec (operandType (right));
4237 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4239 /* assign the amsops */
4240 aopOp (left, ic, FALSE, FALSE);
4241 aopOp (right, ic, FALSE, FALSE);
4242 aopOp (result, ic, TRUE, FALSE);
4244 genCmp (left, right, result, ifx, sign);
4246 freeAsmop (left, NULL, ic);
4247 freeAsmop (right, NULL, ic);
4248 freeAsmop (result, NULL, ic);
4251 /*-----------------------------------------------------------------*/
4252 /* gencjneshort - compare and jump if not equal */
4253 /*-----------------------------------------------------------------*/
4255 gencjneshort (operand * left, operand * right, symbol * lbl)
4257 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4259 unsigned long lit = 0L;
4261 /* Swap the left and right if it makes the computation easier */
4262 if (AOP_TYPE (left) == AOP_LIT)
4269 if (AOP_TYPE (right) == AOP_LIT)
4271 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4274 /* if the right side is a literal then anything goes */
4275 if (AOP_TYPE (right) == AOP_LIT &&
4276 AOP_TYPE (left) != AOP_DIR)
4280 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4285 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4292 emit2 ("jp nz,!tlabel", lbl->key + 100);
4298 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4299 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
4302 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
4303 emit2 ("jp nz,!tlabel", lbl->key + 100);
4308 /* if the right side is in a register or in direct space or
4309 if the left is a pointer register & right is not */
4310 else if (AOP_TYPE (right) == AOP_REG ||
4311 AOP_TYPE (right) == AOP_DIR ||
4312 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
4316 _moveA (aopGet (AOP (left), offset, FALSE));
4317 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
4318 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4320 emit2 ("jp nz,!tlabel", lbl->key + 100);
4323 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4324 emit2 ("jp nz,!tlabel", lbl->key + 100);
4331 /* right is a pointer reg need both a & b */
4332 /* PENDING: is this required? */
4335 _moveA (aopGet (AOP (right), offset, FALSE));
4336 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
4337 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
4343 /*-----------------------------------------------------------------*/
4344 /* gencjne - compare and jump if not equal */
4345 /*-----------------------------------------------------------------*/
4347 gencjne (operand * left, operand * right, symbol * lbl)
4349 symbol *tlbl = newiTempLabel (NULL);
4351 gencjneshort (left, right, lbl);
4354 emit2 ("ld a,!one");
4355 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4356 emitLabel (lbl->key + 100);
4358 emitLabel (tlbl->key + 100);
4361 /*-----------------------------------------------------------------*/
4362 /* genCmpEq - generates code for equal to */
4363 /*-----------------------------------------------------------------*/
4365 genCmpEq (iCode * ic, iCode * ifx)
4367 operand *left, *right, *result;
4369 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4370 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4371 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4373 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4375 /* Swap operands if it makes the operation easier. ie if:
4376 1. Left is a literal.
4378 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4380 operand *t = IC_RIGHT (ic);
4381 IC_RIGHT (ic) = IC_LEFT (ic);
4385 if (ifx && !AOP_SIZE (result))
4388 /* if they are both bit variables */
4389 if (AOP_TYPE (left) == AOP_CRY &&
4390 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4392 wassertl (0, "Tried to compare two bits");
4396 tlbl = newiTempLabel (NULL);
4397 gencjneshort (left, right, tlbl);
4400 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4401 emitLabel (tlbl->key + 100);
4405 /* PENDING: do this better */
4406 symbol *lbl = newiTempLabel (NULL);
4407 emit2 ("!shortjp !tlabel", lbl->key + 100);
4408 emitLabel (tlbl->key + 100);
4409 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4410 emitLabel (lbl->key + 100);
4413 /* mark the icode as generated */
4418 /* if they are both bit variables */
4419 if (AOP_TYPE (left) == AOP_CRY &&
4420 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4422 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4428 gencjne (left, right, newiTempLabel (NULL));
4429 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4436 genIfxJump (ifx, "a");
4439 /* if the result is used in an arithmetic operation
4440 then put the result in place */
4441 if (AOP_TYPE (result) != AOP_CRY)
4446 /* leave the result in acc */
4450 freeAsmop (left, NULL, ic);
4451 freeAsmop (right, NULL, ic);
4452 freeAsmop (result, NULL, ic);
4455 /*-----------------------------------------------------------------*/
4456 /* ifxForOp - returns the icode containing the ifx for operand */
4457 /*-----------------------------------------------------------------*/
4459 ifxForOp (operand * op, iCode * ic)
4461 /* if true symbol then needs to be assigned */
4462 if (IS_TRUE_SYMOP (op))
4465 /* if this has register type condition and
4466 the next instruction is ifx with the same operand
4467 and live to of the operand is upto the ifx only then */
4469 ic->next->op == IFX &&
4470 IC_COND (ic->next)->key == op->key &&
4471 OP_SYMBOL (op)->liveTo <= ic->next->seq)
4477 /*-----------------------------------------------------------------*/
4478 /* genAndOp - for && operation */
4479 /*-----------------------------------------------------------------*/
4481 genAndOp (iCode * ic)
4483 operand *left, *right, *result;
4486 /* note here that && operations that are in an if statement are
4487 taken away by backPatchLabels only those used in arthmetic
4488 operations remain */
4489 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4490 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4491 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4493 /* if both are bit variables */
4494 if (AOP_TYPE (left) == AOP_CRY &&
4495 AOP_TYPE (right) == AOP_CRY)
4497 wassertl (0, "Tried to and two bits");
4501 tlbl = newiTempLabel (NULL);
4503 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
4505 emitLabel (tlbl->key + 100);
4509 freeAsmop (left, NULL, ic);
4510 freeAsmop (right, NULL, ic);
4511 freeAsmop (result, NULL, ic);
4514 /*-----------------------------------------------------------------*/
4515 /* genOrOp - for || operation */
4516 /*-----------------------------------------------------------------*/
4518 genOrOp (iCode * ic)
4520 operand *left, *right, *result;
4523 /* note here that || operations that are in an
4524 if statement are taken away by backPatchLabels
4525 only those used in arthmetic operations remain */
4526 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4527 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4528 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4530 /* if both are bit variables */
4531 if (AOP_TYPE (left) == AOP_CRY &&
4532 AOP_TYPE (right) == AOP_CRY)
4534 wassertl (0, "Tried to OR two bits");
4538 tlbl = newiTempLabel (NULL);
4540 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4542 emitLabel (tlbl->key + 100);
4546 freeAsmop (left, NULL, ic);
4547 freeAsmop (right, NULL, ic);
4548 freeAsmop (result, NULL, ic);
4551 /*-----------------------------------------------------------------*/
4552 /* isLiteralBit - test if lit == 2^n */
4553 /*-----------------------------------------------------------------*/
4555 isLiteralBit (unsigned long lit)
4557 unsigned long pw[32] =
4558 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
4559 0x100L, 0x200L, 0x400L, 0x800L,
4560 0x1000L, 0x2000L, 0x4000L, 0x8000L,
4561 0x10000L, 0x20000L, 0x40000L, 0x80000L,
4562 0x100000L, 0x200000L, 0x400000L, 0x800000L,
4563 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
4564 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
4567 for (idx = 0; idx < 32; idx++)
4573 /*-----------------------------------------------------------------*/
4574 /* jmpTrueOrFalse - */
4575 /*-----------------------------------------------------------------*/
4577 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
4579 // ugly but optimized by peephole
4582 symbol *nlbl = newiTempLabel (NULL);
4583 emit2 ("jp !tlabel", nlbl->key + 100);
4584 emitLabel (tlbl->key + 100);
4585 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
4586 emitLabel (nlbl->key + 100);
4590 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
4591 emitLabel (tlbl->key + 100);
4596 /*-----------------------------------------------------------------*/
4597 /* genAnd - code for and */
4598 /*-----------------------------------------------------------------*/
4600 genAnd (iCode * ic, iCode * ifx)
4602 operand *left, *right, *result;
4603 int size, offset = 0;
4604 unsigned long lit = 0L;
4607 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4608 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4609 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4611 /* if left is a literal & right is not then exchange them */
4612 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4613 AOP_NEEDSACC (left))
4615 operand *tmp = right;
4620 /* if result = right then exchange them */
4621 if (sameRegs (AOP (result), AOP (right)))
4623 operand *tmp = right;
4628 /* if right is bit then exchange them */
4629 if (AOP_TYPE (right) == AOP_CRY &&
4630 AOP_TYPE (left) != AOP_CRY)
4632 operand *tmp = right;
4636 if (AOP_TYPE (right) == AOP_LIT)
4637 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4639 size = AOP_SIZE (result);
4641 if (AOP_TYPE (left) == AOP_CRY)
4643 wassertl (0, "Tried to perform an AND with a bit as an operand");
4647 // if(val & 0xZZ) - size = 0, ifx != FALSE -
4648 // bit = val & 0xZZ - size = 1, ifx = FALSE -
4649 if ((AOP_TYPE (right) == AOP_LIT) &&
4650 (AOP_TYPE (result) == AOP_CRY) &&
4651 (AOP_TYPE (left) != AOP_CRY))
4653 symbol *tlbl = newiTempLabel (NULL);
4654 int sizel = AOP_SIZE (left);
4657 /* PENDING: Test case for this. */
4662 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
4664 _moveA (aopGet (AOP (left), offset, FALSE));
4665 if (bytelit != 0x0FFL)
4667 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4674 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4678 // bit = left & literal
4682 emit2 ("!tlabeldef", tlbl->key + 100);
4684 // if(left & literal)
4689 jmpTrueOrFalse (ifx, tlbl);
4697 /* if left is same as result */
4698 if (sameRegs (AOP (result), AOP (left)))
4700 for (; size--; offset++)
4702 if (AOP_TYPE (right) == AOP_LIT)
4704 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4709 aopPut (AOP (result), "!zero", offset);
4712 _moveA (aopGet (AOP (left), offset, FALSE));
4714 aopGet (AOP (right), offset, FALSE));
4715 aopPut (AOP (left), "a", offset);
4722 if (AOP_TYPE (left) == AOP_ACC)
4724 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
4728 _moveA (aopGet (AOP (left), offset, FALSE));
4730 aopGet (AOP (right), offset, FALSE));
4731 aopPut (AOP (left), "a", offset);
4738 // left & result in different registers
4739 if (AOP_TYPE (result) == AOP_CRY)
4741 wassertl (0, "Tried to AND where the result is in carry");
4745 for (; (size--); offset++)
4748 // result = left & right
4749 if (AOP_TYPE (right) == AOP_LIT)
4751 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4753 aopPut (AOP (result),
4754 aopGet (AOP (left), offset, FALSE),
4758 else if (bytelit == 0)
4760 aopPut (AOP (result), "!zero", offset);
4764 // faster than result <- left, anl result,right
4765 // and better if result is SFR
4766 if (AOP_TYPE (left) == AOP_ACC)
4767 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4770 _moveA (aopGet (AOP (left), offset, FALSE));
4772 aopGet (AOP (right), offset, FALSE));
4774 aopPut (AOP (result), "a", offset);
4781 freeAsmop (left, NULL, ic);
4782 freeAsmop (right, NULL, ic);
4783 freeAsmop (result, NULL, ic);
4786 /*-----------------------------------------------------------------*/
4787 /* genOr - code for or */
4788 /*-----------------------------------------------------------------*/
4790 genOr (iCode * ic, iCode * ifx)
4792 operand *left, *right, *result;
4793 int size, offset = 0;
4794 unsigned long lit = 0L;
4797 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4798 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4799 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4801 /* if left is a literal & right is not then exchange them */
4802 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4803 AOP_NEEDSACC (left))
4805 operand *tmp = right;
4810 /* if result = right then exchange them */
4811 if (sameRegs (AOP (result), AOP (right)))
4813 operand *tmp = right;
4818 /* if right is bit then exchange them */
4819 if (AOP_TYPE (right) == AOP_CRY &&
4820 AOP_TYPE (left) != AOP_CRY)
4822 operand *tmp = right;
4826 if (AOP_TYPE (right) == AOP_LIT)
4827 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4829 size = AOP_SIZE (result);
4831 if (AOP_TYPE (left) == AOP_CRY)
4833 wassertl (0, "Tried to OR where left is a bit");
4837 // if(val | 0xZZ) - size = 0, ifx != FALSE -
4838 // bit = val | 0xZZ - size = 1, ifx = FALSE -
4839 if ((AOP_TYPE (right) == AOP_LIT) &&
4840 (AOP_TYPE (result) == AOP_CRY) &&
4841 (AOP_TYPE (left) != AOP_CRY))
4843 symbol *tlbl = newiTempLabel (NULL);
4844 int sizel = AOP_SIZE (left);
4848 wassertl (0, "Result is assigned to a bit");
4850 /* PENDING: Modeled after the AND code which is inefficent. */
4853 bytelit = (lit >> (offset * 8)) & 0x0FFL;
4855 _moveA (aopGet (AOP (left), offset, FALSE));
4856 /* OR with any literal is the same as OR with itself. */
4858 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4864 jmpTrueOrFalse (ifx, tlbl);
4869 /* if left is same as result */
4870 if (sameRegs (AOP (result), AOP (left)))
4872 for (; size--; offset++)
4874 if (AOP_TYPE (right) == AOP_LIT)
4876 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4880 _moveA (aopGet (AOP (left), offset, FALSE));
4882 aopGet (AOP (right), offset, FALSE));
4883 aopPut (AOP (result), "a", offset);
4888 if (AOP_TYPE (left) == AOP_ACC)
4889 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4892 _moveA (aopGet (AOP (left), offset, FALSE));
4894 aopGet (AOP (right), offset, FALSE));
4895 aopPut (AOP (result), "a", offset);
4902 // left & result in different registers
4903 if (AOP_TYPE (result) == AOP_CRY)
4905 wassertl (0, "Result of OR is in a bit");
4908 for (; (size--); offset++)
4911 // result = left & right
4912 if (AOP_TYPE (right) == AOP_LIT)
4914 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4916 aopPut (AOP (result),
4917 aopGet (AOP (left), offset, FALSE),
4922 // faster than result <- left, anl result,right
4923 // and better if result is SFR
4924 if (AOP_TYPE (left) == AOP_ACC)
4925 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4928 _moveA (aopGet (AOP (left), offset, FALSE));
4930 aopGet (AOP (right), offset, FALSE));
4932 aopPut (AOP (result), "a", offset);
4933 /* PENDING: something weird is going on here. Add exception. */
4934 if (AOP_TYPE (result) == AOP_ACC)
4940 freeAsmop (left, NULL, ic);
4941 freeAsmop (right, NULL, ic);
4942 freeAsmop (result, NULL, ic);
4945 /*-----------------------------------------------------------------*/
4946 /* genXor - code for xclusive or */
4947 /*-----------------------------------------------------------------*/
4949 genXor (iCode * ic, iCode * ifx)
4951 operand *left, *right, *result;
4952 int size, offset = 0;
4953 unsigned long lit = 0L;
4955 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4956 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4957 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4959 /* if left is a literal & right is not then exchange them */
4960 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4961 AOP_NEEDSACC (left))
4963 operand *tmp = right;
4968 /* if result = right then exchange them */
4969 if (sameRegs (AOP (result), AOP (right)))
4971 operand *tmp = right;
4976 /* if right is bit then exchange them */
4977 if (AOP_TYPE (right) == AOP_CRY &&
4978 AOP_TYPE (left) != AOP_CRY)
4980 operand *tmp = right;
4984 if (AOP_TYPE (right) == AOP_LIT)
4985 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4987 size = AOP_SIZE (result);
4989 if (AOP_TYPE (left) == AOP_CRY)
4991 wassertl (0, "Tried to XOR a bit");
4995 // if(val & 0xZZ) - size = 0, ifx != FALSE -
4996 // bit = val & 0xZZ - size = 1, ifx = FALSE -
4997 if ((AOP_TYPE (right) == AOP_LIT) &&
4998 (AOP_TYPE (result) == AOP_CRY) &&
4999 (AOP_TYPE (left) != AOP_CRY))
5001 symbol *tlbl = newiTempLabel (NULL);
5002 int sizel = AOP_SIZE (left);
5006 /* PENDING: Test case for this. */
5007 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5011 _moveA (aopGet (AOP (left), offset, FALSE));
5012 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5013 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5018 jmpTrueOrFalse (ifx, tlbl);
5022 wassertl (0, "Result of XOR was destined for a bit");
5027 /* if left is same as result */
5028 if (sameRegs (AOP (result), AOP (left)))
5030 for (; size--; offset++)
5032 if (AOP_TYPE (right) == AOP_LIT)
5034 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5038 _moveA (aopGet (AOP (right), offset, FALSE));
5040 aopGet (AOP (left), offset, FALSE));
5041 aopPut (AOP (result), "a", offset);
5046 if (AOP_TYPE (left) == AOP_ACC)
5048 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5052 _moveA (aopGet (AOP (right), offset, FALSE));
5054 aopGet (AOP (left), offset, FALSE));
5055 aopPut (AOP (result), "a", 0);
5062 // left & result in different registers
5063 if (AOP_TYPE (result) == AOP_CRY)
5065 wassertl (0, "Result of XOR is in a bit");
5068 for (; (size--); offset++)
5071 // result = left & right
5072 if (AOP_TYPE (right) == AOP_LIT)
5074 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5076 aopPut (AOP (result),
5077 aopGet (AOP (left), offset, FALSE),
5082 // faster than result <- left, anl result,right
5083 // and better if result is SFR
5084 if (AOP_TYPE (left) == AOP_ACC)
5086 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5090 _moveA (aopGet (AOP (right), offset, FALSE));
5092 aopGet (AOP (left), offset, FALSE));
5094 aopPut (AOP (result), "a", offset);
5099 freeAsmop (left, NULL, ic);
5100 freeAsmop (right, NULL, ic);
5101 freeAsmop (result, NULL, ic);
5104 /*-----------------------------------------------------------------*/
5105 /* genInline - write the inline code out */
5106 /*-----------------------------------------------------------------*/
5108 genInline (iCode * ic)
5110 char *buffer, *bp, *bp1;
5112 _G.lines.isInline += (!options.asmpeep);
5114 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5115 strcpy (buffer, IC_INLINE (ic));
5117 /* emit each line as a code */
5142 _G.lines.isInline -= (!options.asmpeep);
5146 /*-----------------------------------------------------------------*/
5147 /* genRRC - rotate right with carry */
5148 /*-----------------------------------------------------------------*/
5155 /*-----------------------------------------------------------------*/
5156 /* genRLC - generate code for rotate left with carry */
5157 /*-----------------------------------------------------------------*/
5164 /*-----------------------------------------------------------------*/
5165 /* genGetHbit - generates code get highest order bit */
5166 /*-----------------------------------------------------------------*/
5168 genGetHbit (iCode * ic)
5170 operand *left, *result;
5171 left = IC_LEFT (ic);
5172 result = IC_RESULT (ic);
5174 aopOp (left, ic, FALSE, FALSE);
5175 aopOp (result, ic, FALSE, FALSE);
5177 /* get the highest order byte into a */
5178 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5180 if (AOP_TYPE (result) == AOP_CRY)
5188 emit2 ("and a,!one");
5193 freeAsmop (left, NULL, ic);
5194 freeAsmop (result, NULL, ic);
5198 emitRsh2 (asmop *aop, int size, int is_signed)
5204 const char *l = aopGet (aop, size, FALSE);
5207 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5217 /*-----------------------------------------------------------------*/
5218 /* shiftR2Left2Result - shift right two bytes from left to result */
5219 /*-----------------------------------------------------------------*/
5221 shiftR2Left2Result (operand * left, int offl,
5222 operand * result, int offr,
5223 int shCount, int is_signed)
5226 symbol *tlbl, *tlbl1;
5228 movLeft2Result (left, offl, result, offr, 0);
5229 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5231 /* if (AOP(result)->type == AOP_REG) { */
5233 tlbl = newiTempLabel (NULL);
5234 tlbl1 = newiTempLabel (NULL);
5236 /* Left is already in result - so now do the shift */
5241 emitRsh2 (AOP (result), size, is_signed);
5246 emit2 ("ld a,!immedbyte+1", shCount);
5247 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5248 emitLabel (tlbl->key + 100);
5250 emitRsh2 (AOP (result), size, is_signed);
5252 emitLabel (tlbl1->key + 100);
5254 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5258 /*-----------------------------------------------------------------*/
5259 /* shiftL2Left2Result - shift left two bytes from left to result */
5260 /*-----------------------------------------------------------------*/
5262 shiftL2Left2Result (operand * left, int offl,
5263 operand * result, int offr, int shCount)
5265 if (sameRegs (AOP (result), AOP (left)) &&
5266 ((offl + MSB16) == offr))
5272 /* Copy left into result */
5273 movLeft2Result (left, offl, result, offr, 0);
5274 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5276 /* PENDING: for now just see if it'll work. */
5277 /*if (AOP(result)->type == AOP_REG) { */
5281 symbol *tlbl, *tlbl1;
5284 tlbl = newiTempLabel (NULL);
5285 tlbl1 = newiTempLabel (NULL);
5287 /* Left is already in result - so now do the shift */
5290 emit2 ("ld a,!immedbyte+1", shCount);
5291 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5292 emitLabel (tlbl->key + 100);
5297 l = aopGet (AOP (result), offset, FALSE);
5301 emit2 ("sla %s", l);
5312 emitLabel (tlbl1->key + 100);
5314 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5319 /*-----------------------------------------------------------------*/
5320 /* AccRol - rotate left accumulator by known count */
5321 /*-----------------------------------------------------------------*/
5323 AccRol (int shCount)
5325 shCount &= 0x0007; // shCount : 0..7
5364 /*-----------------------------------------------------------------*/
5365 /* AccLsh - left shift accumulator by known count */
5366 /*-----------------------------------------------------------------*/
5368 AccLsh (int shCount)
5370 static const unsigned char SLMask[] =
5372 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5381 else if (shCount == 2)
5388 /* rotate left accumulator */
5390 /* and kill the lower order bits */
5391 emit2 ("and a,!immedbyte", SLMask[shCount]);
5396 /*-----------------------------------------------------------------*/
5397 /* shiftL1Left2Result - shift left one byte from left to result */
5398 /*-----------------------------------------------------------------*/
5400 shiftL1Left2Result (operand * left, int offl,
5401 operand * result, int offr, int shCount)
5404 l = aopGet (AOP (left), offl, FALSE);
5406 /* shift left accumulator */
5408 aopPut (AOP (result), "a", offr);
5412 /*-----------------------------------------------------------------*/
5413 /* genlshTwo - left shift two bytes by known amount != 0 */
5414 /*-----------------------------------------------------------------*/
5416 genlshTwo (operand * result, operand * left, int shCount)
5418 int size = AOP_SIZE (result);
5420 wassert (size == 2);
5422 /* if shCount >= 8 */
5430 movLeft2Result (left, LSB, result, MSB16, 0);
5431 aopPut (AOP (result), "!zero", 0);
5432 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
5436 movLeft2Result (left, LSB, result, MSB16, 0);
5437 aopPut (AOP (result), "!zero", 0);
5442 aopPut (AOP (result), "!zero", LSB);
5445 /* 1 <= shCount <= 7 */
5454 shiftL2Left2Result (left, LSB, result, LSB, shCount);
5459 /*-----------------------------------------------------------------*/
5460 /* genlshOne - left shift a one byte quantity by known count */
5461 /*-----------------------------------------------------------------*/
5463 genlshOne (operand * result, operand * left, int shCount)
5465 shiftL1Left2Result (left, LSB, result, LSB, shCount);
5468 /*-----------------------------------------------------------------*/
5469 /* genLeftShiftLiteral - left shifting by known count */
5470 /*-----------------------------------------------------------------*/
5472 genLeftShiftLiteral (operand * left,
5477 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5480 freeAsmop (right, NULL, ic);
5482 aopOp (left, ic, FALSE, FALSE);
5483 aopOp (result, ic, FALSE, FALSE);
5485 size = getSize (operandType (result));
5487 /* I suppose that the left size >= result size */
5493 else if (shCount >= (size * 8))
5497 aopPut (AOP (result), "!zero", size);
5505 genlshOne (result, left, shCount);
5508 genlshTwo (result, left, shCount);
5511 wassertl (0, "Shifting of longs is currently unsupported");
5517 freeAsmop (left, NULL, ic);
5518 freeAsmop (result, NULL, ic);
5521 /*-----------------------------------------------------------------*/
5522 /* genLeftShift - generates code for left shifting */
5523 /*-----------------------------------------------------------------*/
5525 genLeftShift (iCode * ic)
5529 symbol *tlbl, *tlbl1;
5530 operand *left, *right, *result;
5532 right = IC_RIGHT (ic);
5533 left = IC_LEFT (ic);
5534 result = IC_RESULT (ic);
5536 aopOp (right, ic, FALSE, FALSE);
5538 /* if the shift count is known then do it
5539 as efficiently as possible */
5540 if (AOP_TYPE (right) == AOP_LIT)
5542 genLeftShiftLiteral (left, right, result, ic);
5546 /* shift count is unknown then we have to form a loop get the loop
5547 count in B : Note: we take only the lower order byte since
5548 shifting more that 32 bits make no sense anyway, ( the largest
5549 size of an object can be only 32 bits ) */
5550 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5552 freeAsmop (right, NULL, ic);
5553 aopOp (left, ic, FALSE, FALSE);
5554 aopOp (result, ic, FALSE, FALSE);
5556 /* now move the left to the result if they are not the
5559 if (!sameRegs (AOP (left), AOP (result)))
5562 size = AOP_SIZE (result);
5566 l = aopGet (AOP (left), offset, FALSE);
5567 aopPut (AOP (result), l, offset);
5572 tlbl = newiTempLabel (NULL);
5573 size = AOP_SIZE (result);
5575 tlbl1 = newiTempLabel (NULL);
5577 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5578 emitLabel (tlbl->key + 100);
5579 l = aopGet (AOP (result), offset, FALSE);
5583 l = aopGet (AOP (result), offset, FALSE);
5587 emit2 ("sla %s", l);
5595 emitLabel (tlbl1->key + 100);
5597 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5599 freeAsmop (left, NULL, ic);
5600 freeAsmop (result, NULL, ic);
5603 /*-----------------------------------------------------------------*/
5604 /* genrshOne - left shift two bytes by known amount != 0 */
5605 /*-----------------------------------------------------------------*/
5607 genrshOne (operand * result, operand * left, int shCount, int is_signed)
5610 int size = AOP_SIZE (result);
5613 wassert (size == 1);
5614 wassert (shCount < 8);
5616 l = aopGet (AOP (left), 0, FALSE);
5618 if (AOP (result)->type == AOP_REG)
5620 aopPut (AOP (result), l, 0);
5621 l = aopGet (AOP (result), 0, FALSE);
5624 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5632 emit2 ("%s a", is_signed ? "sra" : "srl");
5634 aopPut (AOP (result), "a", 0);
5638 /*-----------------------------------------------------------------*/
5639 /* AccRsh - right shift accumulator by known count */
5640 /*-----------------------------------------------------------------*/
5642 AccRsh (int shCount)
5644 static const unsigned char SRMask[] =
5646 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
5651 /* rotate right accumulator */
5652 AccRol (8 - shCount);
5653 /* and kill the higher order bits */
5654 emit2 ("and a,!immedbyte", SRMask[shCount]);
5658 /*-----------------------------------------------------------------*/
5659 /* shiftR1Left2Result - shift right one byte from left to result */
5660 /*-----------------------------------------------------------------*/
5662 shiftR1Left2Result (operand * left, int offl,
5663 operand * result, int offr,
5664 int shCount, int sign)
5666 _moveA (aopGet (AOP (left), offl, FALSE));
5671 emit2 ("%s a", sign ? "sra" : "srl");
5678 aopPut (AOP (result), "a", offr);
5681 /*-----------------------------------------------------------------*/
5682 /* genrshTwo - right shift two bytes by known amount != 0 */
5683 /*-----------------------------------------------------------------*/
5685 genrshTwo (operand * result, operand * left,
5686 int shCount, int sign)
5688 /* if shCount >= 8 */
5694 shiftR1Left2Result (left, MSB16, result, LSB,
5699 movLeft2Result (left, MSB16, result, LSB, sign);
5703 /* Sign extend the result */
5704 _moveA(aopGet (AOP (result), 0, FALSE));
5708 aopPut (AOP (result), ACC_NAME, MSB16);
5712 aopPut (AOP (result), "!zero", 1);
5715 /* 1 <= shCount <= 7 */
5718 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
5722 /*-----------------------------------------------------------------*/
5723 /* genRightShiftLiteral - left shifting by known count */
5724 /*-----------------------------------------------------------------*/
5726 genRightShiftLiteral (operand * left,
5732 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5735 freeAsmop (right, NULL, ic);
5737 aopOp (left, ic, FALSE, FALSE);
5738 aopOp (result, ic, FALSE, FALSE);
5740 size = getSize (operandType (result));
5742 /* I suppose that the left size >= result size */
5748 else if (shCount >= (size * 8))
5750 aopPut (AOP (result), "!zero", size);
5756 genrshOne (result, left, shCount, sign);
5759 genrshTwo (result, left, shCount, sign);
5762 wassertl (0, "Asked to shift right a long which should be a function call");
5765 wassertl (0, "Entered default case in right shift delegate");
5768 freeAsmop (left, NULL, ic);
5769 freeAsmop (result, NULL, ic);
5772 /*-----------------------------------------------------------------*/
5773 /* genRightShift - generate code for right shifting */
5774 /*-----------------------------------------------------------------*/
5776 genRightShift (iCode * ic)
5778 operand *right, *left, *result;
5780 int size, offset, first = 1;
5784 symbol *tlbl, *tlbl1;
5786 /* if signed then we do it the hard way preserve the
5787 sign bit moving it inwards */
5788 retype = getSpec (operandType (IC_RESULT (ic)));
5790 is_signed = !SPEC_USIGN (retype);
5792 /* signed & unsigned types are treated the same : i.e. the
5793 signed is NOT propagated inwards : quoting from the
5794 ANSI - standard : "for E1 >> E2, is equivalent to division
5795 by 2**E2 if unsigned or if it has a non-negative value,
5796 otherwise the result is implementation defined ", MY definition
5797 is that the sign does not get propagated */
5799 right = IC_RIGHT (ic);
5800 left = IC_LEFT (ic);
5801 result = IC_RESULT (ic);
5803 aopOp (right, ic, FALSE, FALSE);
5805 /* if the shift count is known then do it
5806 as efficiently as possible */
5807 if (AOP_TYPE (right) == AOP_LIT)
5809 genRightShiftLiteral (left, right, result, ic, is_signed);
5813 aopOp (left, ic, FALSE, FALSE);
5814 aopOp (result, ic, FALSE, FALSE);
5816 /* now move the left to the result if they are not the
5818 if (!sameRegs (AOP (left), AOP (result)) &&
5819 AOP_SIZE (result) > 1)
5822 size = AOP_SIZE (result);
5826 l = aopGet (AOP (left), offset, FALSE);
5827 aopPut (AOP (result), l, offset);
5832 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5834 freeAsmop (right, NULL, ic);
5836 tlbl = newiTempLabel (NULL);
5837 tlbl1 = newiTempLabel (NULL);
5838 size = AOP_SIZE (result);
5841 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5842 emitLabel (tlbl->key + 100);
5845 l = aopGet (AOP (result), offset--, FALSE);
5848 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5856 emitLabel (tlbl1->key + 100);
5858 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5860 freeAsmop (left, NULL, ic);
5861 freeAsmop (result, NULL, ic);
5864 /*-----------------------------------------------------------------*/
5865 /* genGenPointerGet - get value from generic pointer space */
5866 /*-----------------------------------------------------------------*/
5868 genGenPointerGet (operand * left,
5869 operand * result, iCode * ic)
5872 sym_link *retype = getSpec (operandType (result));
5878 aopOp (left, ic, FALSE, FALSE);
5879 aopOp (result, ic, FALSE, FALSE);
5881 size = AOP_SIZE (result);
5883 if (isPair (AOP (left)) && size == 1)
5886 if (isPtrPair (AOP (left)))
5888 tsprintf (buffer, "!*pair", getPairName (AOP (left)));
5889 aopPut (AOP (result), buffer, 0);
5893 emit2 ("ld a,!*pair", getPairName (AOP (left)));
5894 aopPut (AOP (result), "a", 0);
5896 freeAsmop (left, NULL, ic);
5900 if ( getPairId( AOP (left)) == PAIR_IY)
5907 tsprintf (at, "!*iyx", offset);
5908 aopPut (AOP (result), at, offset);
5912 freeAsmop (left, NULL, ic);
5916 /* For now we always load into IY */
5917 /* if this is remateriazable */
5918 fetchPair (pair, AOP (left));
5920 freeAsmop (left, NULL, ic);
5922 /* if bit then unpack */
5923 if (IS_BITVAR (retype))
5927 else if ( getPairId( AOP (result)) == PAIR_HL)
5929 wassertl (size == 2, "HL must be of size 2");
5930 emit2 ("ld a,!*hl");
5932 emit2 ("ld h,!*hl");
5937 size = AOP_SIZE (result);
5942 /* PENDING: make this better */
5943 if (!IS_GB && AOP (result)->type == AOP_REG)
5945 aopPut (AOP (result), "!*hl", offset++);
5949 emit2 ("ld a,!*pair", _pairs[pair].name);
5950 aopPut (AOP (result), "a", offset++);
5954 emit2 ("inc %s", _pairs[pair].name);
5955 _G.pairs[pair].offset++;
5961 freeAsmop (result, NULL, ic);
5964 /*-----------------------------------------------------------------*/
5965 /* genPointerGet - generate code for pointer get */
5966 /*-----------------------------------------------------------------*/
5968 genPointerGet (iCode * ic)
5970 operand *left, *result;
5971 sym_link *type, *etype;
5973 left = IC_LEFT (ic);
5974 result = IC_RESULT (ic);
5976 /* depending on the type of pointer we need to
5977 move it to the correct pointer register */
5978 type = operandType (left);
5979 etype = getSpec (type);
5981 genGenPointerGet (left, result, ic);
5985 isRegOrLit (asmop * aop)
5987 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
5992 /*-----------------------------------------------------------------*/
5993 /* genGenPointerSet - stores the value into a pointer location */
5994 /*-----------------------------------------------------------------*/
5996 genGenPointerSet (operand * right,
5997 operand * result, iCode * ic)
6000 sym_link *retype = getSpec (operandType (right));
6001 PAIR_ID pairId = PAIR_HL;
6003 aopOp (result, ic, FALSE, FALSE);
6004 aopOp (right, ic, FALSE, FALSE);
6009 size = AOP_SIZE (right);
6011 /* Handle the exceptions first */
6012 if (isPair (AOP (result)) && size == 1)
6015 const char *l = aopGet (AOP (right), 0, FALSE);
6016 const char *pair = getPairName (AOP (result));
6017 if (canAssignToPtr (l) && isPtr (pair))
6019 emit2 ("ld !*pair,%s", pair, l);
6024 emit2 ("ld !*pair,a", pair);
6029 if ( getPairId( AOP (result)) == PAIR_IY)
6032 const char *l = aopGet (AOP (right), 0, FALSE);
6037 if (canAssignToPtr (l))
6039 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6043 _moveA (aopGet (AOP (right), offset, FALSE));
6044 emit2 ("ld !*iyx,a", offset);
6051 /* if the operand is already in dptr
6052 then we do nothing else we move the value to dptr */
6053 if (AOP_TYPE (result) != AOP_STR)
6055 fetchPair (pairId, AOP (result));
6057 /* so hl know contains the address */
6058 freeAsmop (result, NULL, ic);
6060 /* if bit then unpack */
6061 if (IS_BITVAR (retype))
6071 const char *l = aopGet (AOP (right), offset, FALSE);
6072 if (isRegOrLit (AOP (right)) && !IS_GB)
6074 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
6079 emit2 ("ld !*pair,a", _pairs[pairId].name);
6083 emit2 ("inc %s", _pairs[pairId].name);
6084 _G.pairs[pairId].offset++;
6090 freeAsmop (right, NULL, ic);
6093 /*-----------------------------------------------------------------*/
6094 /* genPointerSet - stores the value into a pointer location */
6095 /*-----------------------------------------------------------------*/
6097 genPointerSet (iCode * ic)
6099 operand *right, *result;
6100 sym_link *type, *etype;
6102 right = IC_RIGHT (ic);
6103 result = IC_RESULT (ic);
6105 /* depending on the type of pointer we need to
6106 move it to the correct pointer register */
6107 type = operandType (result);
6108 etype = getSpec (type);
6110 genGenPointerSet (right, result, ic);
6113 /*-----------------------------------------------------------------*/
6114 /* genIfx - generate code for Ifx statement */
6115 /*-----------------------------------------------------------------*/
6117 genIfx (iCode * ic, iCode * popIc)
6119 operand *cond = IC_COND (ic);
6122 aopOp (cond, ic, FALSE, TRUE);
6124 /* get the value into acc */
6125 if (AOP_TYPE (cond) != AOP_CRY)
6129 /* the result is now in the accumulator */
6130 freeAsmop (cond, NULL, ic);
6132 /* if there was something to be popped then do it */
6136 /* if the condition is a bit variable */
6137 if (isbit && IS_ITEMP (cond) &&
6139 genIfxJump (ic, SPIL_LOC (cond)->rname);
6140 else if (isbit && !IS_ITEMP (cond))
6141 genIfxJump (ic, OP_SYMBOL (cond)->rname);
6143 genIfxJump (ic, "a");
6148 /*-----------------------------------------------------------------*/
6149 /* genAddrOf - generates code for address of */
6150 /*-----------------------------------------------------------------*/
6152 genAddrOf (iCode * ic)
6154 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
6156 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6158 /* if the operand is on the stack then we
6159 need to get the stack offset of this
6166 if (sym->stack <= 0)
6168 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
6172 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6174 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6178 emit2 ("ld de,!hashedstr", sym->rname);
6179 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
6187 /* if it has an offset then we need to compute it */
6189 emit2 ("ld hl,#%d+%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset, _G.stack.param_offset);
6191 emit2 ("ld hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
6192 emit2 ("add hl,sp");
6196 emit2 ("ld hl,#%s", sym->rname);
6198 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6200 freeAsmop (IC_RESULT (ic), NULL, ic);
6203 /*-----------------------------------------------------------------*/
6204 /* genAssign - generate code for assignment */
6205 /*-----------------------------------------------------------------*/
6207 genAssign (iCode * ic)
6209 operand *result, *right;
6211 unsigned long lit = 0L;
6213 result = IC_RESULT (ic);
6214 right = IC_RIGHT (ic);
6216 /* Dont bother assigning if they are the same */
6217 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6219 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
6223 aopOp (right, ic, FALSE, FALSE);
6224 aopOp (result, ic, TRUE, FALSE);
6226 /* if they are the same registers */
6227 if (sameRegs (AOP (right), AOP (result)))
6229 emitDebug ("; (registers are the same)");
6233 /* if the result is a bit */
6234 if (AOP_TYPE (result) == AOP_CRY)
6236 wassertl (0, "Tried to assign to a bit");
6240 size = AOP_SIZE (result);
6243 if (AOP_TYPE (right) == AOP_LIT)
6245 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6248 if (isPair (AOP (result)))
6250 fetchPair (getPairId (AOP (result)), AOP (right));
6252 else if ((size > 1) &&
6253 (AOP_TYPE (result) != AOP_REG) &&
6254 (AOP_TYPE (right) == AOP_LIT) &&
6255 !IS_FLOAT (operandType (right)) &&
6258 bool fXored = FALSE;
6260 /* Work from the top down.
6261 Done this way so that we can use the cached copy of 0
6262 in A for a fast clear */
6265 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
6267 if (!fXored && size > 1)
6274 aopPut (AOP (result), "a", offset);
6278 aopPut (AOP (result), "!zero", offset);
6282 aopPut (AOP (result),
6283 aopGet (AOP (right), offset, FALSE),
6288 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
6290 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
6291 aopPut (AOP (result), "l", LSB);
6292 aopPut (AOP (result), "h", MSB16);
6294 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6296 /* Special case. Load into a and d, then load out. */
6297 _moveA (aopGet (AOP (right), 0, FALSE));
6298 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
6299 aopPut (AOP (result), "a", 0);
6300 aopPut (AOP (result), "e", 1);
6302 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6304 /* Special case - simple memcpy */
6305 aopGet (AOP (right), LSB, FALSE);
6308 aopGet (AOP (result), LSB, FALSE);
6312 emit2 ("ld a,(de)");
6313 /* Peephole will optimise this. */
6314 emit2 ("ld (hl),a");
6322 spillPair (PAIR_HL);
6328 /* PENDING: do this check better */
6329 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
6331 _moveA (aopGet (AOP (right), offset, FALSE));
6332 aopPut (AOP (result), "a", offset);
6335 aopPut (AOP (result),
6336 aopGet (AOP (right), offset, FALSE),
6343 freeAsmop (right, NULL, ic);
6344 freeAsmop (result, NULL, ic);
6347 /*-----------------------------------------------------------------*/
6348 /* genJumpTab - genrates code for jump table */
6349 /*-----------------------------------------------------------------*/
6351 genJumpTab (iCode * ic)
6356 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
6357 /* get the condition into accumulator */
6358 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
6361 emit2 ("ld e,%s", l);
6362 emit2 ("ld d,!zero");
6363 jtab = newiTempLabel (NULL);
6365 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
6366 emit2 ("add hl,de");
6367 emit2 ("add hl,de");
6368 emit2 ("add hl,de");
6369 freeAsmop (IC_JTCOND (ic), NULL, ic);
6373 emitLabel (jtab->key + 100);
6374 /* now generate the jump labels */
6375 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
6376 jtab = setNextItem (IC_JTLABELS (ic)))
6377 emit2 ("jp !tlabel", jtab->key + 100);
6380 /*-----------------------------------------------------------------*/
6381 /* genCast - gen code for casting */
6382 /*-----------------------------------------------------------------*/
6384 genCast (iCode * ic)
6386 operand *result = IC_RESULT (ic);
6387 sym_link *ctype = operandType (IC_LEFT (ic));
6388 operand *right = IC_RIGHT (ic);
6391 /* if they are equivalent then do nothing */
6392 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6395 aopOp (right, ic, FALSE, FALSE);
6396 aopOp (result, ic, FALSE, FALSE);
6398 /* if the result is a bit */
6399 if (AOP_TYPE (result) == AOP_CRY)
6401 wassertl (0, "Tried to cast to a bit");
6404 /* if they are the same size : or less */
6405 if (AOP_SIZE (result) <= AOP_SIZE (right))
6408 /* if they are in the same place */
6409 if (sameRegs (AOP (right), AOP (result)))
6412 /* if they in different places then copy */
6413 size = AOP_SIZE (result);
6417 aopPut (AOP (result),
6418 aopGet (AOP (right), offset, FALSE),
6425 /* So we now know that the size of destination is greater
6426 than the size of the source */
6427 /* we move to result for the size of source */
6428 size = AOP_SIZE (right);
6432 aopPut (AOP (result),
6433 aopGet (AOP (right), offset, FALSE),
6438 /* now depending on the sign of the destination */
6439 size = AOP_SIZE (result) - AOP_SIZE (right);
6440 /* Unsigned or not an integral type - right fill with zeros */
6441 if (SPEC_USIGN (ctype) || !IS_SPEC (ctype))
6444 aopPut (AOP (result), "!zero", offset++);
6448 /* we need to extend the sign :{ */
6449 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
6455 aopPut (AOP (result), "a", offset++);
6459 freeAsmop (right, NULL, ic);
6460 freeAsmop (result, NULL, ic);
6463 /*-----------------------------------------------------------------*/
6464 /* genReceive - generate code for a receive iCode */
6465 /*-----------------------------------------------------------------*/
6467 genReceive (iCode * ic)
6469 if (isOperandInFarSpace (IC_RESULT (ic)) &&
6470 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
6471 IS_TRUE_SYMOP (IC_RESULT (ic))))
6481 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6482 size = AOP_SIZE(IC_RESULT(ic));
6484 for (i = 0; i < size; i++) {
6485 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
6489 freeAsmop (IC_RESULT (ic), NULL, ic);
6494 /** Maximum number of bytes to emit per line. */
6498 /** Context for the byte output chunker. */
6501 unsigned char buffer[DBEMIT_MAX_RUN];
6506 /** Flushes a byte chunker by writing out all in the buffer and
6510 _dbFlush(DBEMITCTX *self)
6517 sprintf(line, ".db 0x%02X", self->buffer[0]);
6519 for (i = 1; i < self->pos; i++)
6521 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
6528 /** Write out another byte, buffering until a decent line is
6532 _dbEmit(DBEMITCTX *self, int c)
6534 if (self->pos == DBEMIT_MAX_RUN)
6538 self->buffer[self->pos++] = c;
6541 /** Context for a simple run length encoder. */
6545 unsigned char buffer[128];
6547 /** runLen may be equivalent to pos. */
6553 RLE_CHANGE_COST = 4,
6557 /** Flush the buffer of a run length encoder by writing out the run or
6558 data that it currently contains.
6561 _rleCommit(RLECTX *self)
6567 memset(&db, 0, sizeof(db));
6569 emit2(".db %u", self->pos);
6571 for (i = 0; i < self->pos; i++)
6573 _dbEmit(&db, self->buffer[i]);
6582 Can get either a run or a block of random stuff.
6583 Only want to change state if a good run comes in or a run ends.
6584 Detecting run end is easy.
6587 Say initial state is in run, len zero, last zero. Then if you get a
6588 few zeros then something else then a short run will be output.
6589 Seems OK. While in run mode, keep counting. While in random mode,
6590 keep a count of the run. If run hits margin, output all up to run,
6591 restart, enter run mode.
6594 /** Add another byte into the run length encoder, flushing as
6595 required. The run length encoder uses the Amiga IFF style, where
6596 a block is prefixed by its run length. A positive length means
6597 the next n bytes pass straight through. A negative length means
6598 that the next byte is repeated -n times. A zero terminates the
6602 _rleAppend(RLECTX *self, int c)
6606 if (c != self->last)
6608 /* The run has stopped. See if it is worthwhile writing it out
6609 as a run. Note that the random data comes in as runs of
6612 if (self->runLen > RLE_CHANGE_COST)
6614 /* Yes, worthwhile. */
6615 /* Commit whatever was in the buffer. */
6617 emit2(".db -%u,0x%02X", self->runLen, self->last);
6621 /* Not worthwhile. Append to the end of the random list. */
6622 for (i = 0; i < self->runLen; i++)
6624 if (self->pos >= RLE_MAX_BLOCK)
6629 self->buffer[self->pos++] = self->last;
6637 if (self->runLen >= RLE_MAX_BLOCK)
6639 /* Commit whatever was in the buffer. */
6642 emit2 (".db -%u,0x%02X", self->runLen, self->last);
6650 _rleFlush(RLECTX *self)
6652 _rleAppend(self, -1);
6659 /** genArrayInit - Special code for initialising an array with constant
6663 genArrayInit (iCode * ic)
6667 int elementSize = 0, eIndex, i;
6668 unsigned val, lastVal;
6672 memset(&rle, 0, sizeof(rle));
6674 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
6676 _saveRegsForCall(ic, 0);
6678 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
6679 emit2 ("call __initrleblock");
6681 type = operandType(IC_LEFT(ic));
6683 if (type && type->next)
6685 elementSize = getSize(type->next);
6689 wassertl (0, "Can't determine element size in genArrayInit.");
6692 iLoop = IC_ARRAYILIST(ic);
6693 lastVal = (unsigned)-1;
6695 /* Feed all the bytes into the run length encoder which will handle
6697 This works well for mixed char data, and for random int and long
6706 for (i = 0; i < ix; i++)
6708 for (eIndex = 0; eIndex < elementSize; eIndex++)
6710 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
6711 _rleAppend(&rle, val);
6716 iLoop = iLoop->next;
6720 /* Mark the end of the run. */
6723 _restoreRegsAfterCall();
6727 freeAsmop (IC_LEFT(ic), NULL, ic);
6731 _swap (PAIR_ID one, PAIR_ID two)
6733 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
6739 emit2 ("ld a,%s", _pairs[one].l);
6740 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
6741 emit2 ("ld %s,a", _pairs[two].l);
6742 emit2 ("ld a,%s", _pairs[one].h);
6743 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
6744 emit2 ("ld %s,a", _pairs[two].h);
6748 /* The problem is that we may have all three pairs used and they may
6749 be needed in a different order.
6754 hl = hl => unity, fine
6758 hl = hl hl = hl, swap de <=> bc
6766 hl = bc de = de, swap bc <=> hl
6774 hl = de bc = bc, swap hl <=> de
6779 * Any pair = pair are done last
6780 * Any pair = iTemp are done last
6781 * Any swaps can be done any time
6789 So how do we detect the cases?
6790 How about a 3x3 matrix?
6794 x x x x (Fourth for iTemp/other)
6796 First determin which mode to use by counting the number of unity and
6799 Two - Assign the pair first, then the rest
6800 One - Swap the two, then the rest
6804 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
6806 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
6808 PAIR_BC, PAIR_HL, PAIR_DE
6810 int i, j, nunity = 0;
6811 memset (ids, PAIR_INVALID, sizeof (ids));
6814 wassert (nparams == 3);
6816 /* First save everything that needs to be saved. */
6817 _saveRegsForCall (ic, 0);
6819 /* Loading HL first means that DE is always fine. */
6820 for (i = 0; i < nparams; i++)
6822 aopOp (pparams[i], ic, FALSE, FALSE);
6823 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
6826 /* Count the number of unity or iTemp assigns. */
6827 for (i = 0; i < 3; i++)
6829 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
6837 /* Any order, fall through. */
6839 else if (nunity == 2)
6841 /* One is assigned. Pull it out and assign. */
6842 for (i = 0; i < 3; i++)
6844 for (j = 0; j < NUM_PAIRS; j++)
6846 if (ids[dest[i]][j] == TRUE)
6848 /* Found it. See if it's the right one. */
6849 if (j == PAIR_INVALID || j == dest[i])
6855 fetchPair(dest[i], AOP (pparams[i]));
6862 else if (nunity == 1)
6864 /* Find the pairs to swap. */
6865 for (i = 0; i < 3; i++)
6867 for (j = 0; j < NUM_PAIRS; j++)
6869 if (ids[dest[i]][j] == TRUE)
6871 if (j == PAIR_INVALID || j == dest[i])
6886 int next = getPairId (AOP (pparams[0]));
6887 emit2 ("push %s", _pairs[next].name);
6889 if (next == dest[1])
6891 fetchPair (dest[1], AOP (pparams[1]));
6892 fetchPair (dest[2], AOP (pparams[2]));
6896 fetchPair (dest[2], AOP (pparams[2]));
6897 fetchPair (dest[1], AOP (pparams[1]));
6899 emit2 ("pop %s", _pairs[dest[0]].name);
6902 /* Finally pull out all of the iTemps */
6903 for (i = 0; i < 3; i++)
6905 if (ids[dest[i]][PAIR_INVALID] == 1)
6907 fetchPair (dest[i], AOP (pparams[i]));
6913 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
6919 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
6923 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
6925 setupForBuiltin3 (ic, nParams, pparams);
6927 label = newiTempLabel(NULL);
6929 emitLabel (label->key);
6930 emit2 ("ld a,(hl)");
6933 emit2 ("!shortjp nz,!tlabel ; 1", label->key);
6935 freeAsmop (from, NULL, ic->next);
6936 freeAsmop (to, NULL, ic);
6940 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
6942 operand *from, *to, *count;
6945 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
6950 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
6952 setupForBuiltin3 (ic, nParams, pparams);
6956 freeAsmop (count, NULL, ic->next->next);
6957 freeAsmop (from, NULL, ic);
6959 _restoreRegsAfterCall();
6961 /* if we need assign a result value */
6962 if ((IS_ITEMP (IC_RESULT (ic)) &&
6963 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
6964 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
6965 IS_TRUE_SYMOP (IC_RESULT (ic)))
6967 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6968 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
6969 freeAsmop (IC_RESULT (ic), NULL, ic);
6972 freeAsmop (to, NULL, ic->next);
6975 /*-----------------------------------------------------------------*/
6976 /* genBuiltIn - calls the appropriate function to generating code */
6977 /* for a built in function */
6978 /*-----------------------------------------------------------------*/
6979 static void genBuiltIn (iCode *ic)
6981 operand *bi_parms[MAX_BUILTIN_ARGS];
6986 /* get all the arguments for a built in function */
6987 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
6989 /* which function is it */
6990 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
6992 if (strcmp(bif->name,"__builtin_strcpy")==0)
6994 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
6996 else if (strcmp(bif->name,"__builtin_memcpy")==0)
6998 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
7002 wassertl (0, "Unknown builtin function encountered");
7006 /*-----------------------------------------------------------------*/
7007 /* genZ80Code - generate code for Z80 based controllers */
7008 /*-----------------------------------------------------------------*/
7010 genZ80Code (iCode * lic)
7018 _fReturn = _gbz80_return;
7019 _fTmp = _gbz80_return;
7023 _fReturn = _z80_return;
7024 _fTmp = _z80_return;
7027 _G.lines.head = _G.lines.current = NULL;
7029 for (ic = lic; ic; ic = ic->next)
7032 if (cln != ic->lineno)
7034 emit2 ("; %s %d", ic->filename, ic->lineno);
7037 /* if the result is marked as
7038 spilt and rematerializable or code for
7039 this has already been generated then
7041 if (resultRemat (ic) || ic->generated)
7044 /* depending on the operation */
7048 emitDebug ("; genNot");
7053 emitDebug ("; genCpl");
7058 emitDebug ("; genUminus");
7063 emitDebug ("; genIpush");
7068 /* IPOP happens only when trying to restore a
7069 spilt live range, if there is an ifx statement
7070 following this pop then the if statement might
7071 be using some of the registers being popped which
7072 would destory the contents of the register so
7073 we need to check for this condition and handle it */
7075 ic->next->op == IFX &&
7076 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
7078 emitDebug ("; genIfx");
7079 genIfx (ic->next, ic);
7083 emitDebug ("; genIpop");
7089 emitDebug ("; genCall");
7094 emitDebug ("; genPcall");
7099 emitDebug ("; genFunction");
7104 emitDebug ("; genEndFunction");
7105 genEndFunction (ic);
7109 emitDebug ("; genRet");
7114 emitDebug ("; genLabel");
7119 emitDebug ("; genGoto");
7124 emitDebug ("; genPlus");
7129 emitDebug ("; genMinus");
7134 emitDebug ("; genMult");
7139 emitDebug ("; genDiv");
7144 emitDebug ("; genMod");
7149 emitDebug ("; genCmpGt");
7150 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
7154 emitDebug ("; genCmpLt");
7155 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
7162 /* note these two are xlated by algebraic equivalence
7163 during parsing SDCC.y */
7164 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
7165 "got '>=' or '<=' shouldn't have come here");
7169 emitDebug ("; genCmpEq");
7170 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
7174 emitDebug ("; genAndOp");
7179 emitDebug ("; genOrOp");
7184 emitDebug ("; genXor");
7185 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
7189 emitDebug ("; genOr");
7190 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
7194 emitDebug ("; genAnd");
7195 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
7199 emitDebug ("; genInline");
7204 emitDebug ("; genRRC");
7209 emitDebug ("; genRLC");
7214 emitDebug ("; genGetHBIT");
7219 emitDebug ("; genLeftShift");
7224 emitDebug ("; genRightShift");
7228 case GET_VALUE_AT_ADDRESS:
7229 emitDebug ("; genPointerGet");
7235 if (POINTER_SET (ic))
7237 emitDebug ("; genAssign (pointer)");
7242 emitDebug ("; genAssign");
7248 emitDebug ("; genIfx");
7253 emitDebug ("; genAddrOf");
7258 emitDebug ("; genJumpTab");
7263 emitDebug ("; genCast");
7268 emitDebug ("; genReceive");
7273 if (ic->builtinSEND)
7275 emitDebug ("; genBuiltIn");
7280 emitDebug ("; addSet");
7281 addSet (&_G.sendSet, ic);
7286 emitDebug ("; genArrayInit");
7296 /* now we are ready to call the
7297 peep hole optimizer */
7298 if (!options.nopeep)
7299 peepHole (&_G.lines.head);
7301 /* This is unfortunate */
7302 /* now do the actual printing */
7304 FILE *fp = codeOutFile;
7305 if (isInHome () && codeOutFile == code->oFile)
7306 codeOutFile = home->oFile;
7307 printLine (_G.lines.head, codeOutFile);
7308 if (_G.flushStatics)
7311 _G.flushStatics = 0;
7316 freeTrace(&_G.lines.trace);
7317 freeTrace(&_G.trace.aops);
7323 _isPairUsed (iCode * ic, PAIR_ID pairId)
7329 if (bitVectBitValue (ic->rMask, D_IDX))
7331 if (bitVectBitValue (ic->rMask, E_IDX))
7341 fetchLitSpecial (asmop * aop, bool negate, bool xor)
7344 value *val = aop->aopu.aop_lit;
7346 wassert (aop->type == AOP_LIT);
7347 wassert (!IS_FLOAT (val->type));
7349 v = (unsigned long) floatFromVal (val);
7357 tsprintf (buffer, "!immedword", v);
7358 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));