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 */
924 aopForSym (ic, sym->usl.spillLoc, result, requires_a);
925 wassertl (aop->size >= getSize (sym->type), "Operand doesn't fit in the spill location");
926 aop->size = getSize (sym->type);
927 /* PENDING: HACK. Can have different sizes in the same AOP. */
928 sym->usl.spillLoc->aop = NULL;
932 /* must be in a register */
933 sym->aop = op->aop = aop = newAsmop (AOP_REG);
934 aop->size = sym->nRegs;
935 for (i = 0; i < sym->nRegs; i++)
936 aop->aopu.aop_reg[i] = sym->regs[i];
939 /*-----------------------------------------------------------------*/
940 /* freeAsmop - free up the asmop given to an operand */
941 /*----------------------------------------------------------------*/
943 freeAsmop (operand * op, asmop * aaop, iCode * ic)
960 if (aop->type == AOP_PAIRPTR && IS_Z80 && aop->aopu.aop_pairId == PAIR_DE)
962 _pop (aop->aopu.aop_pairId);
966 /* all other cases just dealloc */
972 OP_SYMBOL (op)->aop = NULL;
973 /* if the symbol has a spill */
975 SPIL_LOC (op)->aop = NULL;
982 isLitWord (asmop * aop)
984 /* if (aop->size != 2)
997 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
1001 /* depending on type */
1007 /* PENDING: for re-target */
1010 tsprintf (s, "!hashedstr + %d", aop->aopu.aop_immd, offset);
1012 else if (offset == 0)
1014 tsprintf (s, "%s", aop->aopu.aop_immd);
1018 tsprintf (s, "%s + %d", aop->aopu.aop_immd, offset);
1020 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1024 value *val = aop->aopu.aop_lit;
1025 /* if it is a float then it gets tricky */
1026 /* otherwise it is fairly simple */
1027 if (!IS_FLOAT (val->type))
1029 unsigned long v = (unsigned long) floatFromVal (val);
1035 else if (offset == 0)
1041 wassertl(0, "Encountered an invalid offset while fetching a literal");
1045 tsprintf (buffer, "!immedword", v);
1047 tsprintf (buffer, "!constword", v);
1049 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1060 /* it is type float */
1061 fl.f = (float) floatFromVal (val);
1064 i = fl.c[3-offset] | (fl.c[3-offset-1]<<8);
1066 i = fl.c[offset] | (fl.c[offset+1]<<8);
1069 tsprintf (buffer, "!immedword", i);
1071 tsprintf (buffer, "!constword", i);
1073 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1082 aopGetWord (asmop * aop, int offset)
1084 return aopGetLitWordLong (aop, offset, TRUE);
1088 isPtr (const char *s)
1090 if (!strcmp (s, "hl"))
1092 if (!strcmp (s, "ix"))
1094 if (!strcmp (s, "iy"))
1100 adjustPair (const char *pair, int *pold, int new)
1106 emit2 ("inc %s", pair);
1111 emit2 ("dec %s", pair);
1119 spillPair (PAIR_HL);
1120 spillPair (PAIR_IY);
1124 requiresHL (asmop * aop)
1140 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1142 const char *l, *base;
1143 const char *pair = _pairs[pairId].name;
1144 l = aopGetLitWordLong (left, offset, FALSE);
1145 base = aopGetLitWordLong (left, 0, FALSE);
1146 wassert (l && pair && base);
1150 if (pairId == PAIR_HL || pairId == PAIR_IY)
1152 if (_G.pairs[pairId].last_type == left->type)
1154 if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1156 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1158 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1161 if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
1168 _G.pairs[pairId].last_type = left->type;
1169 _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1170 _G.pairs[pairId].offset = offset;
1172 /* Both a lit on the right and a true symbol on the left */
1173 emit2 ("ld %s,!hashedstr", pair, l);
1177 fetchPairLong (PAIR_ID pairId, asmop * aop, int offset)
1179 /* if this is remateriazable */
1180 if (isLitWord (aop)) {
1181 fetchLitPair (pairId, aop, offset);
1185 if (getPairId (aop) == pairId)
1189 /* we need to get it byte by byte */
1190 else if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1191 aopGet (aop, offset, FALSE);
1192 switch (aop->size - offset) {
1194 emit2 ("ld l,!*hl");
1195 emit2 ("ld h,!immedbyte", 0);
1198 // PENDING: Requires that you are only fetching two bytes.
1201 emit2 ("ld h,!*hl");
1205 wassertl (0, "Attempted to fetch too much data into HL");
1209 else if (IS_Z80 && aop->type == AOP_IY) {
1210 /* Instead of fetching relative to IY, just grab directly
1211 from the address IY refers to */
1212 char *l = aopGetLitWordLong (aop, offset, FALSE);
1214 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1216 if (aop->size < 2) {
1217 emit2("ld %s,!zero", _pairs[pairId].h);
1220 else if (pairId == PAIR_IY)
1224 emit2 ("push %s", _pairs[getPairId(aop)].name);
1230 /* Can't load into parts, so load into HL then exchange. */
1231 emit2 ("ld %s,%s", _pairs[PAIR_HL].l, aopGet (aop, offset, FALSE));
1232 emit2 ("ld %s,%s", _pairs[PAIR_HL].h, aopGet (aop, offset + 1, FALSE));
1239 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1240 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1242 /* PENDING: check? */
1243 if (pairId == PAIR_HL)
1244 spillPair (PAIR_HL);
1249 fetchPair (PAIR_ID pairId, asmop * aop)
1251 fetchPairLong (pairId, aop, 0);
1255 fetchHL (asmop * aop)
1257 fetchPair (PAIR_HL, aop);
1261 setupPairFromSP (PAIR_ID id, int offset)
1263 wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
1265 if (offset < INT8MIN || offset > INT8MAX)
1267 emit2 ("ld hl,!immedword", offset);
1268 emit2 ("add hl,sp");
1272 emit2 ("!ldahlsp", offset);
1277 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1282 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
1283 fetchLitPair (pairId, aop, 0);
1287 wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
1289 fetchLitPair (pairId, aop, offset);
1290 _G.pairs[pairId].offset = offset;
1294 wassertl (IS_Z80, "Only the Z80 has an extended stack");
1295 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
1298 int offset = aop->aopu.aop_stk + _G.stack.offset;
1300 if (_G.pairs[pairId].last_type == aop->type &&
1301 _G.pairs[pairId].offset == offset)
1307 /* PENDING: Do this better. */
1308 sprintf (buffer, "%d", offset + _G.stack.pushed);
1309 emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
1310 emit2 ("add %s,sp", _pairs[pairId].name);
1311 _G.pairs[pairId].last_type = aop->type;
1312 _G.pairs[pairId].offset = offset;
1319 /* Doesnt include _G.stack.pushed */
1320 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1322 if (aop->aopu.aop_stk > 0)
1324 abso += _G.stack.param_offset;
1326 assert (pairId == PAIR_HL);
1327 /* In some cases we can still inc or dec hl */
1328 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1330 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1334 setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
1336 _G.pairs[pairId].offset = abso;
1341 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
1347 _G.pairs[pairId].last_type = aop->type;
1353 emit2 ("!tlabeldef", key);
1357 /*-----------------------------------------------------------------*/
1358 /* aopGet - for fetching value of the aop */
1359 /*-----------------------------------------------------------------*/
1361 aopGet (asmop * aop, int offset, bool bit16)
1365 /* offset is greater than size then zero */
1366 /* PENDING: this seems a bit screwed in some pointer cases. */
1367 if (offset > (aop->size - 1) &&
1368 aop->type != AOP_LIT)
1370 tsprintf (s, "!zero");
1371 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1374 /* depending on type */
1378 /* PENDING: re-target */
1380 tsprintf (s, "!immedwords", aop->aopu.aop_immd);
1385 tsprintf (s, "!bankimmeds", aop->aopu.aop_immd);
1388 tsprintf (s, "!msbimmeds", aop->aopu.aop_immd);
1391 tsprintf (s, "!lsbimmeds", aop->aopu.aop_immd);
1394 wassertl (0, "Fetching from beyond the limits of an immediate value.");
1397 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1401 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1404 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1408 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1411 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1414 return aop->aopu.aop_reg[offset]->name;
1418 setupPair (PAIR_HL, aop, offset);
1419 tsprintf (s, "!*hl");
1421 return traceAlloc(&_G.trace.aops, Safe_strdup (s));
1425 setupPair (PAIR_IY, aop, offset);
1426 tsprintf (s, "!*iyx", offset);
1428 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1432 setupPair (PAIR_IY, aop, offset);
1433 tsprintf (s, "!*iyx", offset, offset);
1435 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1440 setupPair (PAIR_HL, aop, offset);
1441 tsprintf (s, "!*hl");
1445 if (aop->aopu.aop_stk >= 0)
1446 offset += _G.stack.param_offset;
1447 tsprintf (s, "!*ixx", aop->aopu.aop_stk + offset);
1450 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1453 wassertl (0, "Tried to fetch from a bit variable");
1462 tsprintf(s, "!zero");
1463 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1467 wassert (offset < 2);
1468 return aop->aopu.aop_str[offset];
1471 return aopLiteral (aop->aopu.aop_lit, offset);
1475 unsigned long v = aop->aopu.aop_simplelit;
1478 tsprintf (s, "!immedbyte", (unsigned int) v & 0xff);
1480 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1484 return aop->aopu.aop_str[offset];
1487 setupPair (aop->aopu.aop_pairId, aop, offset);
1488 sprintf (s, "(%s)", _pairs[aop->aopu.aop_pairId].name);
1490 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1495 wassertl (0, "aopget got unsupported aop->type");
1500 isRegString (const char *s)
1502 if (!strcmp (s, "b") ||
1514 isConstant (const char *s)
1516 /* This is a bit of a hack... */
1517 return (*s == '#' || *s == '$');
1521 canAssignToPtr (const char *s)
1523 if (isRegString (s))
1530 /*-----------------------------------------------------------------*/
1531 /* aopPut - puts a string for a aop */
1532 /*-----------------------------------------------------------------*/
1534 aopPut (asmop * aop, const char *s, int offset)
1538 if (aop->size && offset > (aop->size - 1))
1540 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1541 "aopPut got offset > aop->size");
1546 tsprintf(buffer2, s);
1549 /* will assign value to value */
1550 /* depending on where it is ofcourse */
1556 if (strcmp (s, "a"))
1557 emit2 ("ld a,%s", s);
1558 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1563 if (strcmp (s, "a"))
1564 emit2 ("ld a,%s", s);
1565 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1569 if (!strcmp (s, "!*hl"))
1570 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1573 aop->aopu.aop_reg[offset]->name, s);
1578 if (!canAssignToPtr (s))
1580 emit2 ("ld a,%s", s);
1581 setupPair (PAIR_IY, aop, offset);
1582 emit2 ("ld !*iyx,a", offset);
1586 setupPair (PAIR_IY, aop, offset);
1587 emit2 ("ld !*iyx,%s", offset, s);
1593 /* PENDING: for re-target */
1594 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1596 emit2 ("ld a,!*hl");
1599 setupPair (PAIR_HL, aop, offset);
1601 emit2 ("ld !*hl,%s", s);
1606 if (!canAssignToPtr (s))
1608 emit2 ("ld a,%s", s);
1609 setupPair (PAIR_IY, aop, offset);
1610 emit2 ("ld !*iyx,a", offset);
1614 setupPair (PAIR_IY, aop, offset);
1615 emit2 ("ld !*iyx,%s", offset, s);
1622 /* PENDING: re-target */
1623 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1625 emit2 ("ld a,!*hl");
1628 setupPair (PAIR_HL, aop, offset);
1629 if (!canAssignToPtr (s))
1631 emit2 ("ld a,%s", s);
1632 emit2 ("ld !*hl,a");
1635 emit2 ("ld !*hl,%s", s);
1639 if (aop->aopu.aop_stk >= 0)
1640 offset += _G.stack.param_offset;
1641 if (!canAssignToPtr (s))
1643 emit2 ("ld a,%s", s);
1644 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
1648 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
1654 /* if bit variable */
1655 if (!aop->aopu.aop_dir)
1662 /* In bit space but not in C - cant happen */
1663 wassertl (0, "Tried to write into a bit variable");
1669 if (strcmp (aop->aopu.aop_str[offset], s))
1671 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1677 if (!offset && (strcmp (s, "acc") == 0))
1681 wassertl (0, "Tried to access past the end of A");
1685 if (strcmp (aop->aopu.aop_str[offset], s))
1686 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1691 wassert (offset < 2);
1692 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1696 setupPair (aop->aopu.aop_pairId, aop, offset);
1697 emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
1701 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1702 "aopPut got unsupported aop->type");
1707 #define AOP(op) op->aop
1708 #define AOP_TYPE(op) AOP(op)->type
1709 #define AOP_SIZE(op) AOP(op)->size
1710 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
1713 commitPair (asmop * aop, PAIR_ID id)
1715 /* PENDING: Verify this. */
1716 if (id == PAIR_HL && requiresHL (aop) && IS_GB)
1720 aopPut (aop, "a", 0);
1721 aopPut (aop, "d", 1);
1726 if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
1728 char *l = aopGetLitWordLong (aop, 0, FALSE);
1731 emit2 ("ld (%s),%s", l, _pairs[id].name);
1735 aopPut (aop, _pairs[id].l, 0);
1736 aopPut (aop, _pairs[id].h, 1);
1741 /*-----------------------------------------------------------------*/
1742 /* getDataSize - get the operand data size */
1743 /*-----------------------------------------------------------------*/
1745 getDataSize (operand * op)
1748 size = AOP_SIZE (op);
1752 wassertl (0, "Somehow got a three byte data pointer");
1757 /*-----------------------------------------------------------------*/
1758 /* movLeft2Result - move byte from left to result */
1759 /*-----------------------------------------------------------------*/
1761 movLeft2Result (operand * left, int offl,
1762 operand * result, int offr, int sign)
1766 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
1768 l = aopGet (AOP (left), offl, FALSE);
1772 aopPut (AOP (result), l, offr);
1776 if (getDataSize (left) == offl + 1)
1778 emit2 ("ld a,%s", l);
1779 aopPut (AOP (result), "a", offr);
1786 movLeft2ResultLong (operand * left, int offl,
1787 operand * result, int offr, int sign,
1792 movLeft2Result (left, offl, result, offr, sign);
1796 wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
1797 wassertl (size == 2, "Only implemented for two bytes or one");
1799 if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
1801 emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
1802 emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
1805 else if ( getPairId ( AOP (result)) == PAIR_IY)
1807 PAIR_ID id = getPairId (AOP (left));
1808 if (id != PAIR_INVALID)
1810 emit2("push %s", _pairs[id].name);
1821 movLeft2Result (left, offl, result, offr, sign);
1822 movLeft2Result (left, offl+1, result, offr+1, sign);
1827 /** Put Acc into a register set
1830 outAcc (operand * result)
1833 size = getDataSize (result);
1836 aopPut (AOP (result), "a", 0);
1839 /* unsigned or positive */
1842 aopPut (AOP (result), "!zero", offset++);
1847 /** Take the value in carry and put it into a register
1850 outBitCLong (operand * result, bool swap_sense)
1852 /* if the result is bit */
1853 if (AOP_TYPE (result) == AOP_CRY)
1855 wassertl (0, "Tried to write carry to a bit");
1859 emit2 ("ld a,!zero");
1862 emit2 ("xor a,!immedbyte", 1);
1868 outBitC (operand * result)
1870 outBitCLong (result, FALSE);
1873 /*-----------------------------------------------------------------*/
1874 /* toBoolean - emit code for orl a,operator(sizeop) */
1875 /*-----------------------------------------------------------------*/
1877 _toBoolean (operand * oper)
1879 int size = AOP_SIZE (oper);
1883 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
1886 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
1890 if (AOP (oper)->type != AOP_ACC)
1893 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
1898 /*-----------------------------------------------------------------*/
1899 /* genNotFloat - generates not for float operations */
1900 /*-----------------------------------------------------------------*/
1902 genNotFloat (operand * op, operand * res)
1907 emitDebug ("; genNotFloat");
1909 /* we will put 127 in the first byte of
1911 aopPut (AOP (res), "!immedbyte", 0x7F);
1912 size = AOP_SIZE (op) - 1;
1915 _moveA (aopGet (op->aop, offset++, FALSE));
1919 emit2 ("or a,%s", aopGet (op->aop, offset++, FALSE));
1922 tlbl = newiTempLabel (NULL);
1923 aopPut (res->aop, "!one", 1);
1924 emit2 ("!shortjp z !tlabel", tlbl->key + 100);
1925 aopPut (res->aop, "!zero", 1);
1927 emitLabel(tlbl->key + 100);
1929 size = res->aop->size - 2;
1931 /* put zeros in the rest */
1933 aopPut (res->aop, "!zero", offset++);
1936 /*-----------------------------------------------------------------*/
1937 /* genNot - generate code for ! operation */
1938 /*-----------------------------------------------------------------*/
1942 sym_link *optype = operandType (IC_LEFT (ic));
1944 /* assign asmOps to operand & result */
1945 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
1946 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1948 /* if in bit space then a special case */
1949 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1951 wassertl (0, "Tried to negate a bit");
1954 /* if type float then do float */
1955 if (IS_FLOAT (optype))
1957 genNotFloat (IC_LEFT (ic), IC_RESULT (ic));
1961 _toBoolean (IC_LEFT (ic));
1966 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
1967 emit2 ("sub a,!one");
1968 outBitC (IC_RESULT (ic));
1971 /* release the aops */
1972 freeAsmop (IC_LEFT (ic), NULL, ic);
1973 freeAsmop (IC_RESULT (ic), NULL, ic);
1976 /*-----------------------------------------------------------------*/
1977 /* genCpl - generate code for complement */
1978 /*-----------------------------------------------------------------*/
1986 /* assign asmOps to operand & result */
1987 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1988 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1990 /* if both are in bit space then
1992 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1993 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1995 wassertl (0, "Left and the result are in bit space");
1998 size = AOP_SIZE (IC_RESULT (ic));
2001 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2004 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2007 /* release the aops */
2008 freeAsmop (IC_LEFT (ic), NULL, ic);
2009 freeAsmop (IC_RESULT (ic), NULL, ic);
2013 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
2020 store de into result
2025 store de into result
2027 const char *first = isAdd ? "add" : "sub";
2028 const char *later = isAdd ? "adc" : "sbc";
2030 wassertl (IS_GB, "Code is only relevent to the gbz80");
2031 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
2033 fetchPair (PAIR_DE, left);
2036 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
2039 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2042 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2043 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2045 fetchPairLong (PAIR_DE, left, MSB24);
2046 aopGet (right, MSB24, FALSE);
2050 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2053 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2055 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2056 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2060 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2062 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2065 /*-----------------------------------------------------------------*/
2066 /* genUminusFloat - unary minus for floating points */
2067 /*-----------------------------------------------------------------*/
2069 genUminusFloat (operand * op, operand * result)
2071 int size, offset = 0;
2073 emitDebug("; genUminusFloat");
2075 /* for this we just need to flip the
2076 first it then copy the rest in place */
2077 size = AOP_SIZE (op) - 1;
2079 _moveA(aopGet (AOP (op), MSB32, FALSE));
2081 emit2("xor a,!immedbyte", 0x80);
2082 aopPut (AOP (result), "a", MSB32);
2086 aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2091 /*-----------------------------------------------------------------*/
2092 /* genUminus - unary minus code generation */
2093 /*-----------------------------------------------------------------*/
2095 genUminus (iCode * ic)
2098 sym_link *optype, *rtype;
2101 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2102 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2104 /* if both in bit space then special
2106 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2107 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2109 wassertl (0, "Left and right are in bit space");
2113 optype = operandType (IC_LEFT (ic));
2114 rtype = operandType (IC_RESULT (ic));
2116 /* if float then do float stuff */
2117 if (IS_FLOAT (optype))
2119 genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2123 /* otherwise subtract from zero */
2124 size = AOP_SIZE (IC_LEFT (ic));
2126 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2128 /* Create a new asmop with value zero */
2129 asmop *azero = newAsmop (AOP_SIMPLELIT);
2130 azero->aopu.aop_simplelit = 0;
2132 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2140 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2141 emit2 ("ld a,!zero");
2142 emit2 ("sbc a,%s", l);
2143 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2146 /* if any remaining bytes in the result */
2147 /* we just need to propagate the sign */
2148 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2153 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2157 /* release the aops */
2158 freeAsmop (IC_LEFT (ic), NULL, ic);
2159 freeAsmop (IC_RESULT (ic), NULL, ic);
2162 /*-----------------------------------------------------------------*/
2163 /* assignResultValue - */
2164 /*-----------------------------------------------------------------*/
2166 assignResultValue (operand * oper)
2168 int size = AOP_SIZE (oper);
2171 wassertl (size <= 4, "Got a result that is bigger than four bytes");
2172 topInA = requiresHL (AOP (oper));
2174 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2176 /* We do it the hard way here. */
2178 aopPut (AOP (oper), _fReturn[0], 0);
2179 aopPut (AOP (oper), _fReturn[1], 1);
2181 aopPut (AOP (oper), _fReturn[0], 2);
2182 aopPut (AOP (oper), _fReturn[1], 3);
2188 aopPut (AOP (oper), _fReturn[size], size);
2193 /** Simple restore that doesn't take into account what is used in the
2197 _restoreRegsAfterCall(void)
2199 if (_G.stack.pushedDE)
2202 _G.stack.pushedDE = FALSE;
2204 if (_G.stack.pushedBC)
2207 _G.stack.pushedBC = FALSE;
2209 _G.saves.saved = FALSE;
2213 _saveRegsForCall(iCode *ic, int sendSetSize)
2216 o Stack parameters are pushed before this function enters
2217 o DE and BC may be used in this function.
2218 o HL and DE may be used to return the result.
2219 o HL and DE may be used to send variables.
2220 o DE and BC may be used to store the result value.
2221 o HL may be used in computing the sent value of DE
2222 o The iPushes for other parameters occur before any addSets
2224 Logic: (to be run inside the first iPush or if none, before sending)
2225 o Compute if DE and/or BC are in use over the call
2226 o Compute if DE is used in the send set
2227 o Compute if DE and/or BC are used to hold the result value
2228 o If (DE is used, or in the send set) and is not used in the result, push.
2229 o If BC is used and is not in the result, push
2231 o If DE is used in the send set, fetch
2232 o If HL is used in the send set, fetch
2236 if (_G.saves.saved == FALSE) {
2237 bool deInUse, bcInUse;
2239 bool bcInRet = FALSE, deInRet = FALSE;
2242 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
2244 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2245 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2247 deSending = (sendSetSize > 1);
2249 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2251 if (bcInUse && bcInRet == FALSE) {
2253 _G.stack.pushedBC = TRUE;
2255 if (deInUse && deInRet == FALSE) {
2257 _G.stack.pushedDE = TRUE;
2260 _G.saves.saved = TRUE;
2263 /* Already saved. */
2267 /*-----------------------------------------------------------------*/
2268 /* genIpush - genrate code for pushing this gets a little complex */
2269 /*-----------------------------------------------------------------*/
2271 genIpush (iCode * ic)
2273 int size, offset = 0;
2276 /* if this is not a parm push : ie. it is spill push
2277 and spill push is always done on the local stack */
2280 wassertl(0, "Encountered an unsupported spill push.");
2284 if (_G.saves.saved == FALSE) {
2285 /* Caller saves, and this is the first iPush. */
2286 /* Scan ahead until we find the function that we are pushing parameters to.
2287 Count the number of addSets on the way to figure out what registers
2288 are used in the send set.
2291 iCode *walk = ic->next;
2294 if (walk->op == SEND) {
2297 else if (walk->op == CALL || walk->op == PCALL) {
2306 _saveRegsForCall(walk, nAddSets);
2309 /* Already saved by another iPush. */
2312 /* then do the push */
2313 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2315 size = AOP_SIZE (IC_LEFT (ic));
2317 if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2319 _G.stack.pushed += 2;
2320 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2326 fetchHL (AOP (IC_LEFT (ic)));
2328 spillPair (PAIR_HL);
2329 _G.stack.pushed += 2;
2334 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
2336 spillPair (PAIR_HL);
2337 _G.stack.pushed += 2;
2338 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 0);
2340 spillPair (PAIR_HL);
2341 _G.stack.pushed += 2;
2347 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2349 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2351 emit2 ("ld a,(%s)", l);
2355 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2356 emit2 ("ld a,%s", l);
2364 freeAsmop (IC_LEFT (ic), NULL, ic);
2367 /*-----------------------------------------------------------------*/
2368 /* genIpop - recover the registers: can happen only for spilling */
2369 /*-----------------------------------------------------------------*/
2371 genIpop (iCode * ic)
2376 /* if the temp was not pushed then */
2377 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2380 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2381 size = AOP_SIZE (IC_LEFT (ic));
2382 offset = (size - 1);
2383 if (isPair (AOP (IC_LEFT (ic))))
2385 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2393 spillPair (PAIR_HL);
2394 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2398 freeAsmop (IC_LEFT (ic), NULL, ic);
2401 /* This is quite unfortunate */
2403 setArea (int inHome)
2406 static int lastArea = 0;
2408 if (_G.in_home != inHome) {
2410 const char *sz = port->mem.code_name;
2411 port->mem.code_name = "HOME";
2412 emit2("!area", CODE_NAME);
2413 port->mem.code_name = sz;
2416 emit2("!area", CODE_NAME); */
2417 _G.in_home = inHome;
2428 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2432 symbol *sym = OP_SYMBOL (op);
2434 if (sym->isspilt || sym->nRegs == 0)
2437 aopOp (op, ic, FALSE, FALSE);
2440 if (aop->type == AOP_REG)
2443 for (i = 0; i < aop->size; i++)
2445 if (pairId == PAIR_DE)
2447 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2448 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2450 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2453 else if (pairId == PAIR_BC)
2455 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2456 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2458 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2468 freeAsmop (IC_LEFT (ic), NULL, ic);
2472 /** Emit the code for a call statement
2475 emitCall (iCode * ic, bool ispcall)
2477 sym_link *dtype = operandType (IC_LEFT (ic));
2479 /* if caller saves & we have not saved then */
2485 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2487 /* if send set is not empty then assign */
2492 int nSend = elementsInSet(_G.sendSet);
2493 bool swapped = FALSE;
2495 int _z80_sendOrder[] = {
2500 /* Check if the parameters are swapped. If so route through hl instead. */
2501 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2503 sic = setFirstItem(_G.sendSet);
2504 sic = setNextItem(_G.sendSet);
2506 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2507 /* The second send value is loaded from one the one that holds the first
2508 send, i.e. it is overwritten. */
2509 /* Cache the first in HL, and load the second from HL instead. */
2510 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2511 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2517 for (sic = setFirstItem (_G.sendSet); sic;
2518 sic = setNextItem (_G.sendSet))
2521 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2523 size = AOP_SIZE (IC_LEFT (sic));
2524 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2525 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2527 // PENDING: Mild hack
2528 if (swapped == TRUE && send == 1) {
2530 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2533 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2535 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2538 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2542 freeAsmop (IC_LEFT (sic), NULL, sic);
2549 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2551 werror (W_INDIR_BANKED);
2553 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2555 if (isLitWord (AOP (IC_LEFT (ic))))
2557 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2561 symbol *rlbl = newiTempLabel (NULL);
2562 spillPair (PAIR_HL);
2563 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2565 _G.stack.pushed += 2;
2567 fetchHL (AOP (IC_LEFT (ic)));
2569 emit2 ("!tlabeldef", (rlbl->key + 100));
2570 _G.stack.pushed -= 2;
2572 freeAsmop (IC_LEFT (ic), NULL, ic);
2576 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2577 OP_SYMBOL (IC_LEFT (ic))->rname :
2578 OP_SYMBOL (IC_LEFT (ic))->name;
2579 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2581 emit2 ("call banked_call");
2582 emit2 ("!dws", name);
2583 emit2 ("!dw !bankimmeds", name);
2588 emit2 ("call %s", name);
2593 /* Mark the regsiters as restored. */
2594 _G.saves.saved = FALSE;
2596 /* if we need assign a result value */
2597 if ((IS_ITEMP (IC_RESULT (ic)) &&
2598 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2599 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2600 IS_TRUE_SYMOP (IC_RESULT (ic)))
2603 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2605 assignResultValue (IC_RESULT (ic));
2607 freeAsmop (IC_RESULT (ic), NULL, ic);
2610 /* adjust the stack for parameters if required */
2613 int i = ic->parmBytes;
2615 _G.stack.pushed -= i;
2618 emit2 ("!ldaspsp", i);
2625 emit2 ("ld iy,#%d", i);
2626 emit2 ("add iy,sp");
2646 if (_G.stack.pushedDE)
2648 bool dInRet = bitVectBitValue(ic->rUsed, D_IDX);
2649 bool eInRet = bitVectBitValue(ic->rUsed, E_IDX);
2651 if (dInRet && eInRet)
2653 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
2657 /* Only restore E */
2664 /* Only restore D */
2672 _G.stack.pushedDE = FALSE;
2675 if (_G.stack.pushedBC)
2677 bool bInRet = bitVectBitValue(ic->rUsed, B_IDX);
2678 bool cInRet = bitVectBitValue(ic->rUsed, C_IDX);
2680 if (bInRet && cInRet)
2682 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
2686 /* Only restore C */
2693 /* Only restore B */
2701 _G.stack.pushedBC = FALSE;
2705 /*-----------------------------------------------------------------*/
2706 /* genCall - generates a call statement */
2707 /*-----------------------------------------------------------------*/
2709 genCall (iCode * ic)
2711 emitCall (ic, FALSE);
2714 /*-----------------------------------------------------------------*/
2715 /* genPcall - generates a call by pointer statement */
2716 /*-----------------------------------------------------------------*/
2718 genPcall (iCode * ic)
2720 emitCall (ic, TRUE);
2723 /*-----------------------------------------------------------------*/
2724 /* resultRemat - result is rematerializable */
2725 /*-----------------------------------------------------------------*/
2727 resultRemat (iCode * ic)
2729 if (SKIP_IC (ic) || ic->op == IFX)
2732 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2734 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2735 if (sym->remat && !POINTER_SET (ic))
2742 extern set *publics;
2744 /*-----------------------------------------------------------------*/
2745 /* genFunction - generated code for function entry */
2746 /*-----------------------------------------------------------------*/
2748 genFunction (iCode * ic)
2750 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2754 bool bcInUse = FALSE;
2755 bool deInUse = FALSE;
2758 setArea (IFFUNC_NONBANKED (sym->type));
2760 /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
2763 _G.receiveOffset = 0;
2765 /* Record the last function name for debugging. */
2766 _G.lastFunctionName = sym->rname;
2768 /* Create the function header */
2769 emit2 ("!functionheader", sym->name);
2770 /* PENDING: portability. */
2771 emit2 ("__%s_start:", sym->rname);
2772 emit2 ("!functionlabeldef", sym->rname);
2774 if (options.profile)
2776 emit2 ("!profileenter");
2779 ftype = operandType (IC_LEFT (ic));
2781 /* if critical function then turn interrupts off */
2782 if (IFFUNC_ISCRITICAL (ftype))
2785 /* if this is an interrupt service routine then save all potentially used registers. */
2786 if (IFFUNC_ISISR (sym->type))
2791 /* PENDING: callee-save etc */
2793 _G.stack.param_offset = 0;
2796 /* Detect which registers are used. */
2800 for (i = 0; i < sym->regsUsed->size; i++)
2802 if (bitVectBitValue (sym->regsUsed, i))
2816 /* Other systems use DE as a temporary. */
2827 _G.stack.param_offset += 2;
2830 _G.stack.pushedBC = bcInUse;
2835 _G.stack.param_offset += 2;
2838 _G.stack.pushedDE = deInUse;
2841 /* adjust the stack for the function */
2842 _G.stack.last = sym->stack;
2844 if (sym->stack && IS_GB && sym->stack > -INT8MIN)
2845 emit2 ("!enterxl", sym->stack);
2846 else if (sym->stack)
2847 emit2 ("!enterx", sym->stack);
2850 _G.stack.offset = sym->stack;
2853 /*-----------------------------------------------------------------*/
2854 /* genEndFunction - generates epilogue for functions */
2855 /*-----------------------------------------------------------------*/
2857 genEndFunction (iCode * ic)
2859 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2861 if (IFFUNC_ISISR (sym->type))
2863 wassertl (0, "Tried to close an interrupt support function");
2867 if (IFFUNC_ISCRITICAL (sym->type))
2870 /* PENDING: calleeSave */
2872 if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
2874 emit2 ("!leavexl", _G.stack.offset);
2876 else if (_G.stack.offset)
2878 emit2 ("!leavex", _G.stack.offset);
2886 if (_G.stack.pushedDE)
2889 _G.stack.pushedDE = FALSE;
2892 if (_G.stack.pushedDE)
2895 _G.stack.pushedDE = FALSE;
2899 if (options.profile)
2901 emit2 ("!profileexit");
2905 /* Both baned and non-banked just ret */
2908 /* PENDING: portability. */
2909 emit2 ("__%s_end:", sym->rname);
2911 _G.flushStatics = 1;
2912 _G.stack.pushed = 0;
2913 _G.stack.offset = 0;
2916 /*-----------------------------------------------------------------*/
2917 /* genRet - generate code for return statement */
2918 /*-----------------------------------------------------------------*/
2923 /* Errk. This is a hack until I can figure out how
2924 to cause dehl to spill on a call */
2925 int size, offset = 0;
2927 /* if we have no return value then
2928 just generate the "ret" */
2932 /* we have something to return then
2933 move the return value into place */
2934 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2935 size = AOP_SIZE (IC_LEFT (ic));
2937 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
2941 emit2 ("ld de,%s", l);
2945 emit2 ("ld hl,%s", l);
2950 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
2952 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
2953 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
2959 l = aopGet (AOP (IC_LEFT (ic)), offset,
2961 if (strcmp (_fReturn[offset], l))
2962 emit2 ("ld %s,%s", _fReturn[offset++], l);
2966 freeAsmop (IC_LEFT (ic), NULL, ic);
2969 /* generate a jump to the return label
2970 if the next is not the return statement */
2971 if (!(ic->next && ic->next->op == LABEL &&
2972 IC_LABEL (ic->next) == returnLabel))
2974 emit2 ("jp !tlabel", returnLabel->key + 100);
2977 /*-----------------------------------------------------------------*/
2978 /* genLabel - generates a label */
2979 /*-----------------------------------------------------------------*/
2981 genLabel (iCode * ic)
2983 /* special case never generate */
2984 if (IC_LABEL (ic) == entryLabel)
2987 emitLabel (IC_LABEL (ic)->key + 100);
2990 /*-----------------------------------------------------------------*/
2991 /* genGoto - generates a ljmp */
2992 /*-----------------------------------------------------------------*/
2994 genGoto (iCode * ic)
2996 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
2999 /*-----------------------------------------------------------------*/
3000 /* genPlusIncr :- does addition with increment if possible */
3001 /*-----------------------------------------------------------------*/
3003 genPlusIncr (iCode * ic)
3005 unsigned int icount;
3006 unsigned int size = getDataSize (IC_RESULT (ic));
3007 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3009 /* will try to generate an increment */
3010 /* if the right side is not a literal
3012 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3015 emitDebug ("; genPlusIncr");
3017 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3019 /* If result is a pair */
3020 if (resultId != PAIR_INVALID)
3022 if (isLitWord (AOP (IC_LEFT (ic))))
3024 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3027 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3029 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3031 PAIR_ID freep = getFreePairId (ic);
3032 if (freep != PAIR_INVALID)
3034 fetchPair (freep, AOP (IC_RIGHT (ic)));
3035 emit2 ("add hl,%s", _pairs[freep].name);
3041 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3042 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3049 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3053 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3057 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3062 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3064 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3065 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3069 /* if the literal value of the right hand side
3070 is greater than 4 then it is not worth it */
3074 /* if increment 16 bits in register */
3075 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3081 symbol *tlbl = NULL;
3082 tlbl = newiTempLabel (NULL);
3085 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3088 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3091 emitLabel (tlbl->key + 100);
3095 /* if the sizes are greater than 1 then we cannot */
3096 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3097 AOP_SIZE (IC_LEFT (ic)) > 1)
3100 /* If the result is in a register then we can load then increment.
3102 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3104 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3107 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3112 /* we can if the aops of the left & result match or
3113 if they are in registers and the registers are the
3115 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3119 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3127 /*-----------------------------------------------------------------*/
3128 /* outBitAcc - output a bit in acc */
3129 /*-----------------------------------------------------------------*/
3131 outBitAcc (operand * result)
3133 symbol *tlbl = newiTempLabel (NULL);
3134 /* if the result is a bit */
3135 if (AOP_TYPE (result) == AOP_CRY)
3137 wassertl (0, "Tried to write A into a bit");
3141 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3142 emit2 ("ld a,!one");
3143 emitLabel (tlbl->key + 100);
3149 couldDestroyCarry (asmop *aop)
3153 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3162 shiftIntoPair (int idx, asmop *aop)
3164 PAIR_ID id = PAIR_INVALID;
3166 wassertl (IS_Z80, "Only implemented for the Z80");
3167 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3179 wassertl (0, "Internal error - hit default case");
3182 emitDebug ("; Shift into pair idx %u", idx);
3186 setupPair (PAIR_HL, aop, 0);
3190 setupPair (PAIR_IY, aop, 0);
3192 emit2 ("pop %s", _pairs[id].name);
3195 aop->type = AOP_PAIRPTR;
3196 aop->aopu.aop_pairId = id;
3197 _G.pairs[id].offset = 0;
3198 _G.pairs[id].last_type = aop->type;
3202 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
3204 wassert (left && right);
3208 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3210 shiftIntoPair (0, right);
3211 shiftIntoPair (1, result);
3213 else if (couldDestroyCarry (right))
3215 shiftIntoPair (0, right);
3217 else if (couldDestroyCarry (result))
3219 shiftIntoPair (0, result);
3228 /*-----------------------------------------------------------------*/
3229 /* genPlus - generates code for addition */
3230 /*-----------------------------------------------------------------*/
3232 genPlus (iCode * ic)
3234 int size, offset = 0;
3236 /* special cases :- */
3238 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3239 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3240 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3242 /* Swap the left and right operands if:
3244 if literal, literal on the right or
3245 if left requires ACC or right is already
3248 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3249 (AOP_NEEDSACC (IC_LEFT (ic))) ||
3250 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3252 operand *t = IC_RIGHT (ic);
3253 IC_RIGHT (ic) = IC_LEFT (ic);
3257 /* if both left & right are in bit
3259 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3260 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3263 wassertl (0, "Tried to add two bits");
3266 /* if left in bit space & right literal */
3267 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3268 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3270 /* Can happen I guess */
3271 wassertl (0, "Tried to add a bit to a literal");
3274 /* if I can do an increment instead
3275 of add then GOOD for ME */
3276 if (genPlusIncr (ic) == TRUE)
3279 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3281 size = getDataSize (IC_RESULT (ic));
3283 /* Special case when left and right are constant */
3284 if (isPair (AOP (IC_RESULT (ic))))
3287 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3288 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3290 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3296 sprintf (buffer, "#(%s + %s)", left, right);
3297 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3302 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3304 /* Fetch into HL then do the add */
3305 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3306 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3308 spillPair (PAIR_HL);
3310 if (left == PAIR_HL && right != PAIR_INVALID)
3312 emit2 ("add hl,%s", _pairs[right].name);
3315 else if (right == PAIR_HL && left != PAIR_INVALID)
3317 emit2 ("add hl,%s", _pairs[left].name);
3320 else if (right != PAIR_INVALID && right != PAIR_HL)
3322 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3323 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3326 else if (left != PAIR_INVALID && left != PAIR_HL)
3328 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3329 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3338 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3340 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3341 emit2 ("add hl,%s ; 2", getPairName (AOP (IC_RIGHT (ic))));
3343 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3348 ld hl,sp+n trashes C so we cant afford to do it during an
3349 add with stack based varibles. Worst case is:
3362 So you cant afford to load up hl if either left, right, or result
3363 is on the stack (*sigh*) The alt is:
3371 Combinations in here are:
3372 * If left or right are in bc then the loss is small - trap later
3373 * If the result is in bc then the loss is also small
3377 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3378 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3379 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3381 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3382 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3383 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3384 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3386 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3388 /* Swap left and right */
3389 operand *t = IC_RIGHT (ic);
3390 IC_RIGHT (ic) = IC_LEFT (ic);
3393 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3395 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3396 emit2 ("add hl,bc");
3400 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3401 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3402 emit2 ("add hl,de");
3404 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3410 /* Be paranoid on the GB with 4 byte variables due to how C
3411 can be trashed by lda hl,n(sp).
3413 _gbz80_emitAddSubLong (ic, TRUE);
3418 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3422 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3424 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3427 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3430 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3434 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3437 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3440 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3442 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3446 freeAsmop (IC_LEFT (ic), NULL, ic);
3447 freeAsmop (IC_RIGHT (ic), NULL, ic);
3448 freeAsmop (IC_RESULT (ic), NULL, ic);
3452 /*-----------------------------------------------------------------*/
3453 /* genMinusDec :- does subtraction with deccrement if possible */
3454 /*-----------------------------------------------------------------*/
3456 genMinusDec (iCode * ic)
3458 unsigned int icount;
3459 unsigned int size = getDataSize (IC_RESULT (ic));
3461 /* will try to generate an increment */
3462 /* if the right side is not a literal we cannot */
3463 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3466 /* if the literal value of the right hand side
3467 is greater than 4 then it is not worth it */
3468 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3471 size = getDataSize (IC_RESULT (ic));
3473 /* if decrement 16 bits in register */
3474 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3475 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3478 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3482 /* If result is a pair */
3483 if (isPair (AOP (IC_RESULT (ic))))
3485 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3487 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3491 /* if increment 16 bits in register */
3492 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3496 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3499 emit2 ("dec %s", _getTempPairName());
3502 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3508 /* if the sizes are greater than 1 then we cannot */
3509 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3510 AOP_SIZE (IC_LEFT (ic)) > 1)
3513 /* we can if the aops of the left & result match or if they are in
3514 registers and the registers are the same */
3515 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3518 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3525 /*-----------------------------------------------------------------*/
3526 /* genMinus - generates code for subtraction */
3527 /*-----------------------------------------------------------------*/
3529 genMinus (iCode * ic)
3531 int size, offset = 0;
3532 unsigned long lit = 0L;
3534 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3535 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3536 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3538 /* special cases :- */
3539 /* if both left & right are in bit space */
3540 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3541 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3543 wassertl (0, "Tried to subtract two bits");
3547 /* if I can do an decrement instead of subtract then GOOD for ME */
3548 if (genMinusDec (ic) == TRUE)
3551 size = getDataSize (IC_RESULT (ic));
3553 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3558 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3562 /* Same logic as genPlus */
3565 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3566 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3567 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3569 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3570 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3571 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3572 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3574 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3575 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3577 if (left == PAIR_INVALID && right == PAIR_INVALID)
3582 else if (right == PAIR_INVALID)
3584 else if (left == PAIR_INVALID)
3587 fetchPair (left, AOP (IC_LEFT (ic)));
3588 /* Order is important. Right may be HL */
3589 fetchPair (right, AOP (IC_RIGHT (ic)));
3591 emit2 ("ld a,%s", _pairs[left].l);
3592 emit2 ("sub a,%s", _pairs[right].l);
3594 emit2 ("ld a,%s", _pairs[left].h);
3595 emit2 ("sbc a,%s", _pairs[right].h);
3597 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
3599 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3601 aopPut (AOP (IC_RESULT (ic)), "e", 0);
3607 /* Be paranoid on the GB with 4 byte variables due to how C
3608 can be trashed by lda hl,n(sp).
3610 _gbz80_emitAddSubLong (ic, FALSE);
3615 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3617 /* if literal, add a,#-lit, else normal subb */
3620 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3621 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3625 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3628 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3632 /* first add without previous c */
3634 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
3636 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3638 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3641 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3642 AOP_SIZE (IC_LEFT (ic)) == 3 &&
3643 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3645 wassertl (0, "Tried to subtract on a long pointer");
3649 freeAsmop (IC_LEFT (ic), NULL, ic);
3650 freeAsmop (IC_RIGHT (ic), NULL, ic);
3651 freeAsmop (IC_RESULT (ic), NULL, ic);
3654 /*-----------------------------------------------------------------*/
3655 /* genMult - generates code for multiplication */
3656 /*-----------------------------------------------------------------*/
3658 genMult (iCode * ic)
3662 /* If true then the final operation should be a subtract */
3663 bool active = FALSE;
3665 /* Shouldn't occur - all done through function calls */
3666 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3667 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3668 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3670 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
3671 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
3672 AOP_SIZE (IC_RESULT (ic)) > 2)
3674 wassertl (0, "Multiplication is handled through support function calls");
3677 /* Swap left and right such that right is a literal */
3678 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
3680 operand *t = IC_RIGHT (ic);
3681 IC_RIGHT (ic) = IC_LEFT (ic);
3685 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
3687 val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
3688 // wassertl (val > 0, "Multiply must be positive");
3689 wassertl (val != 1, "Can't multiply by 1");
3695 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
3697 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
3705 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3710 /* Fully unroled version of mul.s. Not the most efficient.
3712 for (count = 0; count < 16; count++)
3714 if (count != 0 && active)
3716 emit2 ("add hl,hl");
3720 if (active == FALSE)
3727 emit2 ("add hl,de");
3741 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3743 freeAsmop (IC_LEFT (ic), NULL, ic);
3744 freeAsmop (IC_RIGHT (ic), NULL, ic);
3745 freeAsmop (IC_RESULT (ic), NULL, ic);
3748 /*-----------------------------------------------------------------*/
3749 /* genDiv - generates code for division */
3750 /*-----------------------------------------------------------------*/
3754 /* Shouldn't occur - all done through function calls */
3755 wassertl (0, "Division is handled through support function calls");
3758 /*-----------------------------------------------------------------*/
3759 /* genMod - generates code for division */
3760 /*-----------------------------------------------------------------*/
3764 /* Shouldn't occur - all done through function calls */
3768 /*-----------------------------------------------------------------*/
3769 /* genIfxJump :- will create a jump depending on the ifx */
3770 /*-----------------------------------------------------------------*/
3772 genIfxJump (iCode * ic, char *jval)
3777 /* if true label then we jump if condition
3781 jlbl = IC_TRUE (ic);
3782 if (!strcmp (jval, "a"))
3786 else if (!strcmp (jval, "c"))
3790 else if (!strcmp (jval, "nc"))
3794 else if (!strcmp (jval, "m"))
3798 else if (!strcmp (jval, "p"))
3804 /* The buffer contains the bit on A that we should test */
3810 /* false label is present */
3811 jlbl = IC_FALSE (ic);
3812 if (!strcmp (jval, "a"))
3816 else if (!strcmp (jval, "c"))
3820 else if (!strcmp (jval, "nc"))
3824 else if (!strcmp (jval, "m"))
3828 else if (!strcmp (jval, "p"))
3834 /* The buffer contains the bit on A that we should test */
3838 /* Z80 can do a conditional long jump */
3839 if (!strcmp (jval, "a"))
3843 else if (!strcmp (jval, "c"))
3846 else if (!strcmp (jval, "nc"))
3849 else if (!strcmp (jval, "m"))
3852 else if (!strcmp (jval, "p"))
3857 emit2 ("bit %s,a", jval);
3859 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
3861 /* mark the icode as generated */
3867 _getPairIdName (PAIR_ID id)
3869 return _pairs[id].name;
3874 /* if unsigned char cmp with lit, just compare */
3876 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
3878 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3881 emit2 ("xor a,!immedbyte", 0x80);
3882 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
3885 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3887 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
3889 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
3890 // Pull left into DE and right into HL
3891 aopGet (AOP(left), LSB, FALSE);
3894 aopGet (AOP(right), LSB, FALSE);
3898 if (size == 0 && sign)
3900 // Highest byte when signed needs the bits flipped
3903 emit2 ("ld a,(de)");
3904 emit2 ("xor #0x80");
3906 emit2 ("ld a,(hl)");
3907 emit2 ("xor #0x80");
3911 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
3915 emit2 ("ld a,(de)");
3916 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
3926 spillPair (PAIR_HL);
3928 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
3930 setupPair (PAIR_HL, AOP (left), 0);
3931 aopGet (AOP(right), LSB, FALSE);
3935 if (size == 0 && sign)
3937 // Highest byte when signed needs the bits flipped
3940 emit2 ("ld a,(hl)");
3941 emit2 ("xor #0x80");
3943 emit2 ("ld a,%d(iy)", offset);
3944 emit2 ("xor #0x80");
3948 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
3952 emit2 ("ld a,(hl)");
3953 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
3962 spillPair (PAIR_HL);
3963 spillPair (PAIR_IY);
3967 if (AOP_TYPE (right) == AOP_LIT)
3969 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3970 /* optimize if(x < 0) or if(x >= 0) */
3975 /* No sign so it's always false */
3980 /* Just load in the top most bit */
3981 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
3982 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
3984 genIfxJump (ifx, "7");
3996 /* First setup h and l contaning the top most bytes XORed */
3997 bool fDidXor = FALSE;
3998 if (AOP_TYPE (left) == AOP_LIT)
4000 unsigned long lit = (unsigned long)
4001 floatFromVal (AOP (left)->aopu.aop_lit);
4002 emit2 ("ld %s,!immedbyte", _fTmp[0],
4003 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4007 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4008 emit2 ("xor a,!immedbyte", 0x80);
4009 emit2 ("ld %s,a", _fTmp[0]);
4012 if (AOP_TYPE (right) == AOP_LIT)
4014 unsigned long lit = (unsigned long)
4015 floatFromVal (AOP (right)->aopu.aop_lit);
4016 emit2 ("ld %s,!immedbyte", _fTmp[1],
4017 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4021 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4022 emit2 ("xor a,!immedbyte", 0x80);
4023 emit2 ("ld %s,a", _fTmp[1]);
4029 /* Do a long subtract */
4032 _moveA (aopGet (AOP (left), offset, FALSE));
4034 if (sign && size == 0)
4036 emit2 ("ld a,%s", _fTmp[0]);
4037 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4041 /* Subtract through, propagating the carry */
4042 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4050 /** Generic compare for > or <
4053 genCmp (operand * left, operand * right,
4054 operand * result, iCode * ifx, int sign)
4056 int size, offset = 0;
4057 unsigned long lit = 0L;
4058 bool swap_sense = FALSE;
4060 /* if left & right are bit variables */
4061 if (AOP_TYPE (left) == AOP_CRY &&
4062 AOP_TYPE (right) == AOP_CRY)
4064 /* Cant happen on the Z80 */
4065 wassertl (0, "Tried to compare two bits");
4069 /* Do a long subtract of right from left. */
4070 size = max (AOP_SIZE (left), AOP_SIZE (right));
4072 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4074 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4075 // Pull left into DE and right into HL
4076 aopGet (AOP(left), LSB, FALSE);
4079 aopGet (AOP(right), LSB, FALSE);
4083 emit2 ("ld a,(de)");
4084 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4093 spillPair (PAIR_HL);
4097 if (AOP_TYPE (right) == AOP_LIT)
4099 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4100 /* optimize if(x < 0) or if(x >= 0) */
4105 /* No sign so it's always false */
4110 /* Just load in the top most bit */
4111 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4112 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4114 genIfxJump (ifx, "7");
4125 genIfxJump (ifx, swap_sense ? "c" : "nc");
4136 _moveA (aopGet (AOP (left), offset, FALSE));
4137 /* Subtract through, propagating the carry */
4138 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4144 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4148 /* Shift the sign bit up into carry */
4151 outBitCLong (result, swap_sense);
4155 /* if the result is used in the next
4156 ifx conditional branch then generate
4157 code a little differently */
4165 genIfxJump (ifx, swap_sense ? "nc" : "c");
4169 genIfxJump (ifx, swap_sense ? "p" : "m");
4174 genIfxJump (ifx, swap_sense ? "nc" : "c");
4181 /* Shift the sign bit up into carry */
4184 outBitCLong (result, swap_sense);
4186 /* leave the result in acc */
4190 /*-----------------------------------------------------------------*/
4191 /* genCmpGt :- greater than comparison */
4192 /*-----------------------------------------------------------------*/
4194 genCmpGt (iCode * ic, iCode * ifx)
4196 operand *left, *right, *result;
4197 sym_link *letype, *retype;
4200 left = IC_LEFT (ic);
4201 right = IC_RIGHT (ic);
4202 result = IC_RESULT (ic);
4204 letype = getSpec (operandType (left));
4205 retype = getSpec (operandType (right));
4206 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4207 /* assign the amsops */
4208 aopOp (left, ic, FALSE, FALSE);
4209 aopOp (right, ic, FALSE, FALSE);
4210 aopOp (result, ic, TRUE, FALSE);
4212 genCmp (right, left, result, ifx, sign);
4214 freeAsmop (left, NULL, ic);
4215 freeAsmop (right, NULL, ic);
4216 freeAsmop (result, NULL, ic);
4219 /*-----------------------------------------------------------------*/
4220 /* genCmpLt - less than comparisons */
4221 /*-----------------------------------------------------------------*/
4223 genCmpLt (iCode * ic, iCode * ifx)
4225 operand *left, *right, *result;
4226 sym_link *letype, *retype;
4229 left = IC_LEFT (ic);
4230 right = IC_RIGHT (ic);
4231 result = IC_RESULT (ic);
4233 letype = getSpec (operandType (left));
4234 retype = getSpec (operandType (right));
4235 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4237 /* assign the amsops */
4238 aopOp (left, ic, FALSE, FALSE);
4239 aopOp (right, ic, FALSE, FALSE);
4240 aopOp (result, ic, TRUE, FALSE);
4242 genCmp (left, right, result, ifx, sign);
4244 freeAsmop (left, NULL, ic);
4245 freeAsmop (right, NULL, ic);
4246 freeAsmop (result, NULL, ic);
4249 /*-----------------------------------------------------------------*/
4250 /* gencjneshort - compare and jump if not equal */
4251 /*-----------------------------------------------------------------*/
4253 gencjneshort (operand * left, operand * right, symbol * lbl)
4255 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4257 unsigned long lit = 0L;
4259 /* Swap the left and right if it makes the computation easier */
4260 if (AOP_TYPE (left) == AOP_LIT)
4267 if (AOP_TYPE (right) == AOP_LIT)
4269 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4272 /* if the right side is a literal then anything goes */
4273 if (AOP_TYPE (right) == AOP_LIT &&
4274 AOP_TYPE (left) != AOP_DIR)
4278 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4283 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4290 emit2 ("jp nz,!tlabel", lbl->key + 100);
4296 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4297 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
4300 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
4301 emit2 ("jp nz,!tlabel", lbl->key + 100);
4306 /* if the right side is in a register or in direct space or
4307 if the left is a pointer register & right is not */
4308 else if (AOP_TYPE (right) == AOP_REG ||
4309 AOP_TYPE (right) == AOP_DIR ||
4310 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
4314 _moveA (aopGet (AOP (left), offset, FALSE));
4315 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
4316 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4318 emit2 ("jp nz,!tlabel", lbl->key + 100);
4321 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4322 emit2 ("jp nz,!tlabel", lbl->key + 100);
4329 /* right is a pointer reg need both a & b */
4330 /* PENDING: is this required? */
4333 _moveA (aopGet (AOP (right), offset, FALSE));
4334 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
4335 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
4341 /*-----------------------------------------------------------------*/
4342 /* gencjne - compare and jump if not equal */
4343 /*-----------------------------------------------------------------*/
4345 gencjne (operand * left, operand * right, symbol * lbl)
4347 symbol *tlbl = newiTempLabel (NULL);
4349 gencjneshort (left, right, lbl);
4352 emit2 ("ld a,!one");
4353 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4354 emitLabel (lbl->key + 100);
4356 emitLabel (tlbl->key + 100);
4359 /*-----------------------------------------------------------------*/
4360 /* genCmpEq - generates code for equal to */
4361 /*-----------------------------------------------------------------*/
4363 genCmpEq (iCode * ic, iCode * ifx)
4365 operand *left, *right, *result;
4367 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4368 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4369 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4371 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4373 /* Swap operands if it makes the operation easier. ie if:
4374 1. Left is a literal.
4376 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4378 operand *t = IC_RIGHT (ic);
4379 IC_RIGHT (ic) = IC_LEFT (ic);
4383 if (ifx && !AOP_SIZE (result))
4386 /* if they are both bit variables */
4387 if (AOP_TYPE (left) == AOP_CRY &&
4388 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4390 wassertl (0, "Tried to compare two bits");
4394 tlbl = newiTempLabel (NULL);
4395 gencjneshort (left, right, tlbl);
4398 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4399 emitLabel (tlbl->key + 100);
4403 /* PENDING: do this better */
4404 symbol *lbl = newiTempLabel (NULL);
4405 emit2 ("!shortjp !tlabel", lbl->key + 100);
4406 emitLabel (tlbl->key + 100);
4407 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4408 emitLabel (lbl->key + 100);
4411 /* mark the icode as generated */
4416 /* if they are both bit variables */
4417 if (AOP_TYPE (left) == AOP_CRY &&
4418 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4420 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4426 gencjne (left, right, newiTempLabel (NULL));
4427 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4434 genIfxJump (ifx, "a");
4437 /* if the result is used in an arithmetic operation
4438 then put the result in place */
4439 if (AOP_TYPE (result) != AOP_CRY)
4444 /* leave the result in acc */
4448 freeAsmop (left, NULL, ic);
4449 freeAsmop (right, NULL, ic);
4450 freeAsmop (result, NULL, ic);
4453 /*-----------------------------------------------------------------*/
4454 /* ifxForOp - returns the icode containing the ifx for operand */
4455 /*-----------------------------------------------------------------*/
4457 ifxForOp (operand * op, iCode * ic)
4459 /* if true symbol then needs to be assigned */
4460 if (IS_TRUE_SYMOP (op))
4463 /* if this has register type condition and
4464 the next instruction is ifx with the same operand
4465 and live to of the operand is upto the ifx only then */
4467 ic->next->op == IFX &&
4468 IC_COND (ic->next)->key == op->key &&
4469 OP_SYMBOL (op)->liveTo <= ic->next->seq)
4475 /*-----------------------------------------------------------------*/
4476 /* genAndOp - for && operation */
4477 /*-----------------------------------------------------------------*/
4479 genAndOp (iCode * ic)
4481 operand *left, *right, *result;
4484 /* note here that && operations that are in an if statement are
4485 taken away by backPatchLabels only those used in arthmetic
4486 operations remain */
4487 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4488 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4489 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4491 /* if both are bit variables */
4492 if (AOP_TYPE (left) == AOP_CRY &&
4493 AOP_TYPE (right) == AOP_CRY)
4495 wassertl (0, "Tried to and two bits");
4499 tlbl = newiTempLabel (NULL);
4501 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
4503 emitLabel (tlbl->key + 100);
4507 freeAsmop (left, NULL, ic);
4508 freeAsmop (right, NULL, ic);
4509 freeAsmop (result, NULL, ic);
4512 /*-----------------------------------------------------------------*/
4513 /* genOrOp - for || operation */
4514 /*-----------------------------------------------------------------*/
4516 genOrOp (iCode * ic)
4518 operand *left, *right, *result;
4521 /* note here that || operations that are in an
4522 if statement are taken away by backPatchLabels
4523 only those used in arthmetic operations remain */
4524 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4525 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4526 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4528 /* if both are bit variables */
4529 if (AOP_TYPE (left) == AOP_CRY &&
4530 AOP_TYPE (right) == AOP_CRY)
4532 wassertl (0, "Tried to OR two bits");
4536 tlbl = newiTempLabel (NULL);
4538 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4540 emitLabel (tlbl->key + 100);
4544 freeAsmop (left, NULL, ic);
4545 freeAsmop (right, NULL, ic);
4546 freeAsmop (result, NULL, ic);
4549 /*-----------------------------------------------------------------*/
4550 /* isLiteralBit - test if lit == 2^n */
4551 /*-----------------------------------------------------------------*/
4553 isLiteralBit (unsigned long lit)
4555 unsigned long pw[32] =
4556 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
4557 0x100L, 0x200L, 0x400L, 0x800L,
4558 0x1000L, 0x2000L, 0x4000L, 0x8000L,
4559 0x10000L, 0x20000L, 0x40000L, 0x80000L,
4560 0x100000L, 0x200000L, 0x400000L, 0x800000L,
4561 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
4562 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
4565 for (idx = 0; idx < 32; idx++)
4571 /*-----------------------------------------------------------------*/
4572 /* jmpTrueOrFalse - */
4573 /*-----------------------------------------------------------------*/
4575 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
4577 // ugly but optimized by peephole
4580 symbol *nlbl = newiTempLabel (NULL);
4581 emit2 ("jp !tlabel", nlbl->key + 100);
4582 emitLabel (tlbl->key + 100);
4583 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
4584 emitLabel (nlbl->key + 100);
4588 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
4589 emitLabel (tlbl->key + 100);
4594 /*-----------------------------------------------------------------*/
4595 /* genAnd - code for and */
4596 /*-----------------------------------------------------------------*/
4598 genAnd (iCode * ic, iCode * ifx)
4600 operand *left, *right, *result;
4601 int size, offset = 0;
4602 unsigned long lit = 0L;
4605 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4606 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4607 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4609 /* if left is a literal & right is not then exchange them */
4610 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4611 AOP_NEEDSACC (left))
4613 operand *tmp = right;
4618 /* if result = right then exchange them */
4619 if (sameRegs (AOP (result), AOP (right)))
4621 operand *tmp = right;
4626 /* if right is bit then exchange them */
4627 if (AOP_TYPE (right) == AOP_CRY &&
4628 AOP_TYPE (left) != AOP_CRY)
4630 operand *tmp = right;
4634 if (AOP_TYPE (right) == AOP_LIT)
4635 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4637 size = AOP_SIZE (result);
4639 if (AOP_TYPE (left) == AOP_CRY)
4641 wassertl (0, "Tried to perform an AND with a bit as an operand");
4645 // if(val & 0xZZ) - size = 0, ifx != FALSE -
4646 // bit = val & 0xZZ - size = 1, ifx = FALSE -
4647 if ((AOP_TYPE (right) == AOP_LIT) &&
4648 (AOP_TYPE (result) == AOP_CRY) &&
4649 (AOP_TYPE (left) != AOP_CRY))
4651 symbol *tlbl = newiTempLabel (NULL);
4652 int sizel = AOP_SIZE (left);
4655 /* PENDING: Test case for this. */
4660 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
4662 _moveA (aopGet (AOP (left), offset, FALSE));
4663 if (bytelit != 0x0FFL)
4665 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4672 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4676 // bit = left & literal
4680 emit2 ("!tlabeldef", tlbl->key + 100);
4682 // if(left & literal)
4687 jmpTrueOrFalse (ifx, tlbl);
4695 /* if left is same as result */
4696 if (sameRegs (AOP (result), AOP (left)))
4698 for (; size--; offset++)
4700 if (AOP_TYPE (right) == AOP_LIT)
4702 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4707 aopPut (AOP (result), "!zero", offset);
4710 _moveA (aopGet (AOP (left), offset, FALSE));
4712 aopGet (AOP (right), offset, FALSE));
4713 aopPut (AOP (left), "a", offset);
4720 if (AOP_TYPE (left) == AOP_ACC)
4722 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
4726 _moveA (aopGet (AOP (left), offset, FALSE));
4728 aopGet (AOP (right), offset, FALSE));
4729 aopPut (AOP (left), "a", offset);
4736 // left & result in different registers
4737 if (AOP_TYPE (result) == AOP_CRY)
4739 wassertl (0, "Tried to AND where the result is in carry");
4743 for (; (size--); offset++)
4746 // result = left & right
4747 if (AOP_TYPE (right) == AOP_LIT)
4749 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4751 aopPut (AOP (result),
4752 aopGet (AOP (left), offset, FALSE),
4756 else if (bytelit == 0)
4758 aopPut (AOP (result), "!zero", offset);
4762 // faster than result <- left, anl result,right
4763 // and better if result is SFR
4764 if (AOP_TYPE (left) == AOP_ACC)
4765 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4768 _moveA (aopGet (AOP (left), offset, FALSE));
4770 aopGet (AOP (right), offset, FALSE));
4772 aopPut (AOP (result), "a", offset);
4779 freeAsmop (left, NULL, ic);
4780 freeAsmop (right, NULL, ic);
4781 freeAsmop (result, NULL, ic);
4784 /*-----------------------------------------------------------------*/
4785 /* genOr - code for or */
4786 /*-----------------------------------------------------------------*/
4788 genOr (iCode * ic, iCode * ifx)
4790 operand *left, *right, *result;
4791 int size, offset = 0;
4792 unsigned long lit = 0L;
4795 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4796 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4797 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4799 /* if left is a literal & right is not then exchange them */
4800 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4801 AOP_NEEDSACC (left))
4803 operand *tmp = right;
4808 /* if result = right then exchange them */
4809 if (sameRegs (AOP (result), AOP (right)))
4811 operand *tmp = right;
4816 /* if right is bit then exchange them */
4817 if (AOP_TYPE (right) == AOP_CRY &&
4818 AOP_TYPE (left) != AOP_CRY)
4820 operand *tmp = right;
4824 if (AOP_TYPE (right) == AOP_LIT)
4825 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4827 size = AOP_SIZE (result);
4829 if (AOP_TYPE (left) == AOP_CRY)
4831 wassertl (0, "Tried to OR where left is a bit");
4835 // if(val | 0xZZ) - size = 0, ifx != FALSE -
4836 // bit = val | 0xZZ - size = 1, ifx = FALSE -
4837 if ((AOP_TYPE (right) == AOP_LIT) &&
4838 (AOP_TYPE (result) == AOP_CRY) &&
4839 (AOP_TYPE (left) != AOP_CRY))
4841 symbol *tlbl = newiTempLabel (NULL);
4842 int sizel = AOP_SIZE (left);
4846 wassertl (0, "Result is assigned to a bit");
4848 /* PENDING: Modeled after the AND code which is inefficent. */
4851 bytelit = (lit >> (offset * 8)) & 0x0FFL;
4853 _moveA (aopGet (AOP (left), offset, FALSE));
4854 /* OR with any literal is the same as OR with itself. */
4856 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4862 jmpTrueOrFalse (ifx, tlbl);
4867 /* if left is same as result */
4868 if (sameRegs (AOP (result), AOP (left)))
4870 for (; size--; offset++)
4872 if (AOP_TYPE (right) == AOP_LIT)
4874 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4878 _moveA (aopGet (AOP (left), offset, FALSE));
4880 aopGet (AOP (right), offset, FALSE));
4881 aopPut (AOP (result), "a", offset);
4886 if (AOP_TYPE (left) == AOP_ACC)
4887 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4890 _moveA (aopGet (AOP (left), offset, FALSE));
4892 aopGet (AOP (right), offset, FALSE));
4893 aopPut (AOP (result), "a", offset);
4900 // left & result in different registers
4901 if (AOP_TYPE (result) == AOP_CRY)
4903 wassertl (0, "Result of OR is in a bit");
4906 for (; (size--); offset++)
4909 // result = left & right
4910 if (AOP_TYPE (right) == AOP_LIT)
4912 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4914 aopPut (AOP (result),
4915 aopGet (AOP (left), offset, FALSE),
4920 // faster than result <- left, anl result,right
4921 // and better if result is SFR
4922 if (AOP_TYPE (left) == AOP_ACC)
4923 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4926 _moveA (aopGet (AOP (left), offset, FALSE));
4928 aopGet (AOP (right), offset, FALSE));
4930 aopPut (AOP (result), "a", offset);
4931 /* PENDING: something weird is going on here. Add exception. */
4932 if (AOP_TYPE (result) == AOP_ACC)
4938 freeAsmop (left, NULL, ic);
4939 freeAsmop (right, NULL, ic);
4940 freeAsmop (result, NULL, ic);
4943 /*-----------------------------------------------------------------*/
4944 /* genXor - code for xclusive or */
4945 /*-----------------------------------------------------------------*/
4947 genXor (iCode * ic, iCode * ifx)
4949 operand *left, *right, *result;
4950 int size, offset = 0;
4951 unsigned long lit = 0L;
4953 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4954 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4955 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4957 /* if left is a literal & right is not then exchange them */
4958 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4959 AOP_NEEDSACC (left))
4961 operand *tmp = right;
4966 /* if result = right then exchange them */
4967 if (sameRegs (AOP (result), AOP (right)))
4969 operand *tmp = right;
4974 /* if right is bit then exchange them */
4975 if (AOP_TYPE (right) == AOP_CRY &&
4976 AOP_TYPE (left) != AOP_CRY)
4978 operand *tmp = right;
4982 if (AOP_TYPE (right) == AOP_LIT)
4983 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4985 size = AOP_SIZE (result);
4987 if (AOP_TYPE (left) == AOP_CRY)
4989 wassertl (0, "Tried to XOR a bit");
4993 // if(val & 0xZZ) - size = 0, ifx != FALSE -
4994 // bit = val & 0xZZ - size = 1, ifx = FALSE -
4995 if ((AOP_TYPE (right) == AOP_LIT) &&
4996 (AOP_TYPE (result) == AOP_CRY) &&
4997 (AOP_TYPE (left) != AOP_CRY))
4999 symbol *tlbl = newiTempLabel (NULL);
5000 int sizel = AOP_SIZE (left);
5004 /* PENDING: Test case for this. */
5005 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5009 _moveA (aopGet (AOP (left), offset, FALSE));
5010 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5011 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5016 jmpTrueOrFalse (ifx, tlbl);
5020 wassertl (0, "Result of XOR was destined for a bit");
5025 /* if left is same as result */
5026 if (sameRegs (AOP (result), AOP (left)))
5028 for (; size--; offset++)
5030 if (AOP_TYPE (right) == AOP_LIT)
5032 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5036 _moveA (aopGet (AOP (right), offset, FALSE));
5038 aopGet (AOP (left), offset, FALSE));
5039 aopPut (AOP (result), "a", offset);
5044 if (AOP_TYPE (left) == AOP_ACC)
5046 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5050 _moveA (aopGet (AOP (right), offset, FALSE));
5052 aopGet (AOP (left), offset, FALSE));
5053 aopPut (AOP (result), "a", 0);
5060 // left & result in different registers
5061 if (AOP_TYPE (result) == AOP_CRY)
5063 wassertl (0, "Result of XOR is in a bit");
5066 for (; (size--); offset++)
5069 // result = left & right
5070 if (AOP_TYPE (right) == AOP_LIT)
5072 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5074 aopPut (AOP (result),
5075 aopGet (AOP (left), offset, FALSE),
5080 // faster than result <- left, anl result,right
5081 // and better if result is SFR
5082 if (AOP_TYPE (left) == AOP_ACC)
5084 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5088 _moveA (aopGet (AOP (right), offset, FALSE));
5090 aopGet (AOP (left), offset, FALSE));
5092 aopPut (AOP (result), "a", offset);
5097 freeAsmop (left, NULL, ic);
5098 freeAsmop (right, NULL, ic);
5099 freeAsmop (result, NULL, ic);
5102 /*-----------------------------------------------------------------*/
5103 /* genInline - write the inline code out */
5104 /*-----------------------------------------------------------------*/
5106 genInline (iCode * ic)
5108 char *buffer, *bp, *bp1;
5110 _G.lines.isInline += (!options.asmpeep);
5112 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5113 strcpy (buffer, IC_INLINE (ic));
5115 /* emit each line as a code */
5140 _G.lines.isInline -= (!options.asmpeep);
5144 /*-----------------------------------------------------------------*/
5145 /* genRRC - rotate right with carry */
5146 /*-----------------------------------------------------------------*/
5153 /*-----------------------------------------------------------------*/
5154 /* genRLC - generate code for rotate left with carry */
5155 /*-----------------------------------------------------------------*/
5162 /*-----------------------------------------------------------------*/
5163 /* genGetHbit - generates code get highest order bit */
5164 /*-----------------------------------------------------------------*/
5166 genGetHbit (iCode * ic)
5168 operand *left, *result;
5169 left = IC_LEFT (ic);
5170 result = IC_RESULT (ic);
5172 aopOp (left, ic, FALSE, FALSE);
5173 aopOp (result, ic, FALSE, FALSE);
5175 /* get the highest order byte into a */
5176 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5178 if (AOP_TYPE (result) == AOP_CRY)
5186 emit2 ("and a,!one");
5191 freeAsmop (left, NULL, ic);
5192 freeAsmop (result, NULL, ic);
5196 emitRsh2 (asmop *aop, int size, int is_signed)
5202 const char *l = aopGet (aop, size, FALSE);
5205 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5215 /*-----------------------------------------------------------------*/
5216 /* shiftR2Left2Result - shift right two bytes from left to result */
5217 /*-----------------------------------------------------------------*/
5219 shiftR2Left2Result (operand * left, int offl,
5220 operand * result, int offr,
5221 int shCount, int is_signed)
5224 symbol *tlbl, *tlbl1;
5226 movLeft2Result (left, offl, result, offr, 0);
5227 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5229 /* if (AOP(result)->type == AOP_REG) { */
5231 tlbl = newiTempLabel (NULL);
5232 tlbl1 = newiTempLabel (NULL);
5234 /* Left is already in result - so now do the shift */
5239 emitRsh2 (AOP (result), size, is_signed);
5244 emit2 ("ld a,!immedbyte+1", shCount);
5245 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5246 emitLabel (tlbl->key + 100);
5248 emitRsh2 (AOP (result), size, is_signed);
5250 emitLabel (tlbl1->key + 100);
5252 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5256 /*-----------------------------------------------------------------*/
5257 /* shiftL2Left2Result - shift left two bytes from left to result */
5258 /*-----------------------------------------------------------------*/
5260 shiftL2Left2Result (operand * left, int offl,
5261 operand * result, int offr, int shCount)
5263 if (sameRegs (AOP (result), AOP (left)) &&
5264 ((offl + MSB16) == offr))
5270 /* Copy left into result */
5271 movLeft2Result (left, offl, result, offr, 0);
5272 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5274 /* PENDING: for now just see if it'll work. */
5275 /*if (AOP(result)->type == AOP_REG) { */
5279 symbol *tlbl, *tlbl1;
5282 tlbl = newiTempLabel (NULL);
5283 tlbl1 = newiTempLabel (NULL);
5285 /* Left is already in result - so now do the shift */
5288 emit2 ("ld a,!immedbyte+1", shCount);
5289 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5290 emitLabel (tlbl->key + 100);
5295 l = aopGet (AOP (result), offset, FALSE);
5299 emit2 ("sla %s", l);
5310 emitLabel (tlbl1->key + 100);
5312 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5317 /*-----------------------------------------------------------------*/
5318 /* AccRol - rotate left accumulator by known count */
5319 /*-----------------------------------------------------------------*/
5321 AccRol (int shCount)
5323 shCount &= 0x0007; // shCount : 0..7
5362 /*-----------------------------------------------------------------*/
5363 /* AccLsh - left shift accumulator by known count */
5364 /*-----------------------------------------------------------------*/
5366 AccLsh (int shCount)
5368 static const unsigned char SLMask[] =
5370 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5379 else if (shCount == 2)
5386 /* rotate left accumulator */
5388 /* and kill the lower order bits */
5389 emit2 ("and a,!immedbyte", SLMask[shCount]);
5394 /*-----------------------------------------------------------------*/
5395 /* shiftL1Left2Result - shift left one byte from left to result */
5396 /*-----------------------------------------------------------------*/
5398 shiftL1Left2Result (operand * left, int offl,
5399 operand * result, int offr, int shCount)
5402 l = aopGet (AOP (left), offl, FALSE);
5404 /* shift left accumulator */
5406 aopPut (AOP (result), "a", offr);
5410 /*-----------------------------------------------------------------*/
5411 /* genlshTwo - left shift two bytes by known amount != 0 */
5412 /*-----------------------------------------------------------------*/
5414 genlshTwo (operand * result, operand * left, int shCount)
5416 int size = AOP_SIZE (result);
5418 wassert (size == 2);
5420 /* if shCount >= 8 */
5428 movLeft2Result (left, LSB, result, MSB16, 0);
5429 aopPut (AOP (result), "!zero", 0);
5430 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
5434 movLeft2Result (left, LSB, result, MSB16, 0);
5435 aopPut (AOP (result), "!zero", 0);
5440 aopPut (AOP (result), "!zero", LSB);
5443 /* 1 <= shCount <= 7 */
5452 shiftL2Left2Result (left, LSB, result, LSB, shCount);
5457 /*-----------------------------------------------------------------*/
5458 /* genlshOne - left shift a one byte quantity by known count */
5459 /*-----------------------------------------------------------------*/
5461 genlshOne (operand * result, operand * left, int shCount)
5463 shiftL1Left2Result (left, LSB, result, LSB, shCount);
5466 /*-----------------------------------------------------------------*/
5467 /* genLeftShiftLiteral - left shifting by known count */
5468 /*-----------------------------------------------------------------*/
5470 genLeftShiftLiteral (operand * left,
5475 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5478 freeAsmop (right, NULL, ic);
5480 aopOp (left, ic, FALSE, FALSE);
5481 aopOp (result, ic, FALSE, FALSE);
5483 size = getSize (operandType (result));
5485 /* I suppose that the left size >= result size */
5491 else if (shCount >= (size * 8))
5495 aopPut (AOP (result), "!zero", size);
5503 genlshOne (result, left, shCount);
5506 genlshTwo (result, left, shCount);
5509 wassertl (0, "Shifting of longs is currently unsupported");
5515 freeAsmop (left, NULL, ic);
5516 freeAsmop (result, NULL, ic);
5519 /*-----------------------------------------------------------------*/
5520 /* genLeftShift - generates code for left shifting */
5521 /*-----------------------------------------------------------------*/
5523 genLeftShift (iCode * ic)
5527 symbol *tlbl, *tlbl1;
5528 operand *left, *right, *result;
5530 right = IC_RIGHT (ic);
5531 left = IC_LEFT (ic);
5532 result = IC_RESULT (ic);
5534 aopOp (right, ic, FALSE, FALSE);
5536 /* if the shift count is known then do it
5537 as efficiently as possible */
5538 if (AOP_TYPE (right) == AOP_LIT)
5540 genLeftShiftLiteral (left, right, result, ic);
5544 /* shift count is unknown then we have to form a loop get the loop
5545 count in B : Note: we take only the lower order byte since
5546 shifting more that 32 bits make no sense anyway, ( the largest
5547 size of an object can be only 32 bits ) */
5548 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5550 freeAsmop (right, NULL, ic);
5551 aopOp (left, ic, FALSE, FALSE);
5552 aopOp (result, ic, FALSE, FALSE);
5554 /* now move the left to the result if they are not the
5557 if (!sameRegs (AOP (left), AOP (result)))
5560 size = AOP_SIZE (result);
5564 l = aopGet (AOP (left), offset, FALSE);
5565 aopPut (AOP (result), l, offset);
5570 tlbl = newiTempLabel (NULL);
5571 size = AOP_SIZE (result);
5573 tlbl1 = newiTempLabel (NULL);
5575 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5576 emitLabel (tlbl->key + 100);
5577 l = aopGet (AOP (result), offset, FALSE);
5581 l = aopGet (AOP (result), offset, FALSE);
5585 emit2 ("sla %s", l);
5593 emitLabel (tlbl1->key + 100);
5595 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5597 freeAsmop (left, NULL, ic);
5598 freeAsmop (result, NULL, ic);
5601 /*-----------------------------------------------------------------*/
5602 /* genrshOne - left shift two bytes by known amount != 0 */
5603 /*-----------------------------------------------------------------*/
5605 genrshOne (operand * result, operand * left, int shCount, int is_signed)
5608 int size = AOP_SIZE (result);
5611 wassert (size == 1);
5612 wassert (shCount < 8);
5614 l = aopGet (AOP (left), 0, FALSE);
5616 if (AOP (result)->type == AOP_REG)
5618 aopPut (AOP (result), l, 0);
5619 l = aopGet (AOP (result), 0, FALSE);
5622 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5630 emit2 ("%s a", is_signed ? "sra" : "srl");
5632 aopPut (AOP (result), "a", 0);
5636 /*-----------------------------------------------------------------*/
5637 /* AccRsh - right shift accumulator by known count */
5638 /*-----------------------------------------------------------------*/
5640 AccRsh (int shCount)
5642 static const unsigned char SRMask[] =
5644 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
5649 /* rotate right accumulator */
5650 AccRol (8 - shCount);
5651 /* and kill the higher order bits */
5652 emit2 ("and a,!immedbyte", SRMask[shCount]);
5656 /*-----------------------------------------------------------------*/
5657 /* shiftR1Left2Result - shift right one byte from left to result */
5658 /*-----------------------------------------------------------------*/
5660 shiftR1Left2Result (operand * left, int offl,
5661 operand * result, int offr,
5662 int shCount, int sign)
5664 _moveA (aopGet (AOP (left), offl, FALSE));
5669 emit2 ("%s a", sign ? "sra" : "srl");
5676 aopPut (AOP (result), "a", offr);
5679 /*-----------------------------------------------------------------*/
5680 /* genrshTwo - right shift two bytes by known amount != 0 */
5681 /*-----------------------------------------------------------------*/
5683 genrshTwo (operand * result, operand * left,
5684 int shCount, int sign)
5686 /* if shCount >= 8 */
5692 shiftR1Left2Result (left, MSB16, result, LSB,
5697 movLeft2Result (left, MSB16, result, LSB, sign);
5701 /* Sign extend the result */
5702 _moveA(aopGet (AOP (result), 0, FALSE));
5706 aopPut (AOP (result), ACC_NAME, MSB16);
5710 aopPut (AOP (result), "!zero", 1);
5713 /* 1 <= shCount <= 7 */
5716 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
5720 /*-----------------------------------------------------------------*/
5721 /* genRightShiftLiteral - left shifting by known count */
5722 /*-----------------------------------------------------------------*/
5724 genRightShiftLiteral (operand * left,
5730 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5733 freeAsmop (right, NULL, ic);
5735 aopOp (left, ic, FALSE, FALSE);
5736 aopOp (result, ic, FALSE, FALSE);
5738 size = getSize (operandType (result));
5740 /* I suppose that the left size >= result size */
5746 else if (shCount >= (size * 8))
5748 aopPut (AOP (result), "!zero", size);
5754 genrshOne (result, left, shCount, sign);
5757 genrshTwo (result, left, shCount, sign);
5760 wassertl (0, "Asked to shift right a long which should be a function call");
5763 wassertl (0, "Entered default case in right shift delegate");
5766 freeAsmop (left, NULL, ic);
5767 freeAsmop (result, NULL, ic);
5770 /*-----------------------------------------------------------------*/
5771 /* genRightShift - generate code for right shifting */
5772 /*-----------------------------------------------------------------*/
5774 genRightShift (iCode * ic)
5776 operand *right, *left, *result;
5778 int size, offset, first = 1;
5782 symbol *tlbl, *tlbl1;
5784 /* if signed then we do it the hard way preserve the
5785 sign bit moving it inwards */
5786 retype = getSpec (operandType (IC_RESULT (ic)));
5788 is_signed = !SPEC_USIGN (retype);
5790 /* signed & unsigned types are treated the same : i.e. the
5791 signed is NOT propagated inwards : quoting from the
5792 ANSI - standard : "for E1 >> E2, is equivalent to division
5793 by 2**E2 if unsigned or if it has a non-negative value,
5794 otherwise the result is implementation defined ", MY definition
5795 is that the sign does not get propagated */
5797 right = IC_RIGHT (ic);
5798 left = IC_LEFT (ic);
5799 result = IC_RESULT (ic);
5801 aopOp (right, ic, FALSE, FALSE);
5803 /* if the shift count is known then do it
5804 as efficiently as possible */
5805 if (AOP_TYPE (right) == AOP_LIT)
5807 genRightShiftLiteral (left, right, result, ic, is_signed);
5811 aopOp (left, ic, FALSE, FALSE);
5812 aopOp (result, ic, FALSE, FALSE);
5814 /* now move the left to the result if they are not the
5816 if (!sameRegs (AOP (left), AOP (result)) &&
5817 AOP_SIZE (result) > 1)
5820 size = AOP_SIZE (result);
5824 l = aopGet (AOP (left), offset, FALSE);
5825 aopPut (AOP (result), l, offset);
5830 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5832 freeAsmop (right, NULL, ic);
5834 tlbl = newiTempLabel (NULL);
5835 tlbl1 = newiTempLabel (NULL);
5836 size = AOP_SIZE (result);
5839 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5840 emitLabel (tlbl->key + 100);
5843 l = aopGet (AOP (result), offset--, FALSE);
5846 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5854 emitLabel (tlbl1->key + 100);
5856 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5858 freeAsmop (left, NULL, ic);
5859 freeAsmop (result, NULL, ic);
5862 /*-----------------------------------------------------------------*/
5863 /* genGenPointerGet - get value from generic pointer space */
5864 /*-----------------------------------------------------------------*/
5866 genGenPointerGet (operand * left,
5867 operand * result, iCode * ic)
5870 sym_link *retype = getSpec (operandType (result));
5876 aopOp (left, ic, FALSE, FALSE);
5877 aopOp (result, ic, FALSE, FALSE);
5879 size = AOP_SIZE (result);
5881 if (isPair (AOP (left)) && size == 1)
5884 if (isPtrPair (AOP (left)))
5886 tsprintf (buffer, "!*pair", getPairName (AOP (left)));
5887 aopPut (AOP (result), buffer, 0);
5891 emit2 ("ld a,!*pair", getPairName (AOP (left)));
5892 aopPut (AOP (result), "a", 0);
5894 freeAsmop (left, NULL, ic);
5898 if ( getPairId( AOP (left)) == PAIR_IY)
5905 tsprintf (at, "!*iyx", offset);
5906 aopPut (AOP (result), at, offset);
5910 freeAsmop (left, NULL, ic);
5914 /* For now we always load into IY */
5915 /* if this is remateriazable */
5916 fetchPair (pair, AOP (left));
5918 freeAsmop (left, NULL, ic);
5920 /* if bit then unpack */
5921 if (IS_BITVAR (retype))
5925 else if ( getPairId( AOP (result)) == PAIR_HL)
5927 wassertl (size == 2, "HL must be of size 2");
5928 emit2 ("ld a,!*hl");
5930 emit2 ("ld h,!*hl");
5935 size = AOP_SIZE (result);
5940 /* PENDING: make this better */
5941 if (!IS_GB && AOP (result)->type == AOP_REG)
5943 aopPut (AOP (result), "!*hl", offset++);
5947 emit2 ("ld a,!*pair", _pairs[pair].name);
5948 aopPut (AOP (result), "a", offset++);
5952 emit2 ("inc %s", _pairs[pair].name);
5953 _G.pairs[pair].offset++;
5959 freeAsmop (result, NULL, ic);
5962 /*-----------------------------------------------------------------*/
5963 /* genPointerGet - generate code for pointer get */
5964 /*-----------------------------------------------------------------*/
5966 genPointerGet (iCode * ic)
5968 operand *left, *result;
5969 sym_link *type, *etype;
5971 left = IC_LEFT (ic);
5972 result = IC_RESULT (ic);
5974 /* depending on the type of pointer we need to
5975 move it to the correct pointer register */
5976 type = operandType (left);
5977 etype = getSpec (type);
5979 genGenPointerGet (left, result, ic);
5983 isRegOrLit (asmop * aop)
5985 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
5990 /*-----------------------------------------------------------------*/
5991 /* genGenPointerSet - stores the value into a pointer location */
5992 /*-----------------------------------------------------------------*/
5994 genGenPointerSet (operand * right,
5995 operand * result, iCode * ic)
5998 sym_link *retype = getSpec (operandType (right));
5999 PAIR_ID pairId = PAIR_HL;
6001 aopOp (result, ic, FALSE, FALSE);
6002 aopOp (right, ic, FALSE, FALSE);
6007 size = AOP_SIZE (right);
6009 /* Handle the exceptions first */
6010 if (isPair (AOP (result)) && size == 1)
6013 const char *l = aopGet (AOP (right), 0, FALSE);
6014 const char *pair = getPairName (AOP (result));
6015 if (canAssignToPtr (l) && isPtr (pair))
6017 emit2 ("ld !*pair,%s", pair, l);
6022 emit2 ("ld !*pair,a", pair);
6027 if ( getPairId( AOP (result)) == PAIR_IY)
6030 const char *l = aopGet (AOP (right), 0, FALSE);
6035 if (canAssignToPtr (l))
6037 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6041 _moveA (aopGet (AOP (right), offset, FALSE));
6042 emit2 ("ld !*iyx,a", offset);
6049 /* if the operand is already in dptr
6050 then we do nothing else we move the value to dptr */
6051 if (AOP_TYPE (result) != AOP_STR)
6053 fetchPair (pairId, AOP (result));
6055 /* so hl know contains the address */
6056 freeAsmop (result, NULL, ic);
6058 /* if bit then unpack */
6059 if (IS_BITVAR (retype))
6069 const char *l = aopGet (AOP (right), offset, FALSE);
6070 if (isRegOrLit (AOP (right)) && !IS_GB)
6072 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
6077 emit2 ("ld !*pair,a", _pairs[pairId].name);
6081 emit2 ("inc %s", _pairs[pairId].name);
6082 _G.pairs[pairId].offset++;
6088 freeAsmop (right, NULL, ic);
6091 /*-----------------------------------------------------------------*/
6092 /* genPointerSet - stores the value into a pointer location */
6093 /*-----------------------------------------------------------------*/
6095 genPointerSet (iCode * ic)
6097 operand *right, *result;
6098 sym_link *type, *etype;
6100 right = IC_RIGHT (ic);
6101 result = IC_RESULT (ic);
6103 /* depending on the type of pointer we need to
6104 move it to the correct pointer register */
6105 type = operandType (result);
6106 etype = getSpec (type);
6108 genGenPointerSet (right, result, ic);
6111 /*-----------------------------------------------------------------*/
6112 /* genIfx - generate code for Ifx statement */
6113 /*-----------------------------------------------------------------*/
6115 genIfx (iCode * ic, iCode * popIc)
6117 operand *cond = IC_COND (ic);
6120 aopOp (cond, ic, FALSE, TRUE);
6122 /* get the value into acc */
6123 if (AOP_TYPE (cond) != AOP_CRY)
6127 /* the result is now in the accumulator */
6128 freeAsmop (cond, NULL, ic);
6130 /* if there was something to be popped then do it */
6134 /* if the condition is a bit variable */
6135 if (isbit && IS_ITEMP (cond) &&
6137 genIfxJump (ic, SPIL_LOC (cond)->rname);
6138 else if (isbit && !IS_ITEMP (cond))
6139 genIfxJump (ic, OP_SYMBOL (cond)->rname);
6141 genIfxJump (ic, "a");
6146 /*-----------------------------------------------------------------*/
6147 /* genAddrOf - generates code for address of */
6148 /*-----------------------------------------------------------------*/
6150 genAddrOf (iCode * ic)
6152 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
6154 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6156 /* if the operand is on the stack then we
6157 need to get the stack offset of this
6164 if (sym->stack <= 0)
6166 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
6170 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6172 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6176 emit2 ("ld de,!hashedstr", sym->rname);
6177 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
6185 /* if it has an offset then we need to compute it */
6187 emit2 ("ld hl,#%d+%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset, _G.stack.param_offset);
6189 emit2 ("ld hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
6190 emit2 ("add hl,sp");
6194 emit2 ("ld hl,#%s", sym->rname);
6196 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6198 freeAsmop (IC_RESULT (ic), NULL, ic);
6201 /*-----------------------------------------------------------------*/
6202 /* genAssign - generate code for assignment */
6203 /*-----------------------------------------------------------------*/
6205 genAssign (iCode * ic)
6207 operand *result, *right;
6209 unsigned long lit = 0L;
6211 result = IC_RESULT (ic);
6212 right = IC_RIGHT (ic);
6214 /* Dont bother assigning if they are the same */
6215 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6217 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
6221 aopOp (right, ic, FALSE, FALSE);
6222 aopOp (result, ic, TRUE, FALSE);
6224 /* if they are the same registers */
6225 if (sameRegs (AOP (right), AOP (result)))
6227 emitDebug ("; (registers are the same)");
6231 /* if the result is a bit */
6232 if (AOP_TYPE (result) == AOP_CRY)
6234 wassertl (0, "Tried to assign to a bit");
6238 size = AOP_SIZE (result);
6241 if (AOP_TYPE (right) == AOP_LIT)
6243 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6246 if (isPair (AOP (result)))
6248 fetchPair (getPairId (AOP (result)), AOP (right));
6250 else if ((size > 1) &&
6251 (AOP_TYPE (result) != AOP_REG) &&
6252 (AOP_TYPE (right) == AOP_LIT) &&
6253 !IS_FLOAT (operandType (right)) &&
6256 bool fXored = FALSE;
6258 /* Work from the top down.
6259 Done this way so that we can use the cached copy of 0
6260 in A for a fast clear */
6263 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
6265 if (!fXored && size > 1)
6272 aopPut (AOP (result), "a", offset);
6276 aopPut (AOP (result), "!zero", offset);
6280 aopPut (AOP (result),
6281 aopGet (AOP (right), offset, FALSE),
6286 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
6288 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
6289 aopPut (AOP (result), "l", LSB);
6290 aopPut (AOP (result), "h", MSB16);
6292 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6294 /* Special case. Load into a and d, then load out. */
6295 _moveA (aopGet (AOP (right), 0, FALSE));
6296 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
6297 aopPut (AOP (result), "a", 0);
6298 aopPut (AOP (result), "e", 1);
6300 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6302 /* Special case - simple memcpy */
6303 aopGet (AOP (right), LSB, FALSE);
6306 aopGet (AOP (result), LSB, FALSE);
6310 emit2 ("ld a,(de)");
6311 /* Peephole will optimise this. */
6312 emit2 ("ld (hl),a");
6320 spillPair (PAIR_HL);
6326 /* PENDING: do this check better */
6327 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
6329 _moveA (aopGet (AOP (right), offset, FALSE));
6330 aopPut (AOP (result), "a", offset);
6333 aopPut (AOP (result),
6334 aopGet (AOP (right), offset, FALSE),
6341 freeAsmop (right, NULL, ic);
6342 freeAsmop (result, NULL, ic);
6345 /*-----------------------------------------------------------------*/
6346 /* genJumpTab - genrates code for jump table */
6347 /*-----------------------------------------------------------------*/
6349 genJumpTab (iCode * ic)
6354 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
6355 /* get the condition into accumulator */
6356 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
6359 emit2 ("ld e,%s", l);
6360 emit2 ("ld d,!zero");
6361 jtab = newiTempLabel (NULL);
6363 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
6364 emit2 ("add hl,de");
6365 emit2 ("add hl,de");
6366 emit2 ("add hl,de");
6367 freeAsmop (IC_JTCOND (ic), NULL, ic);
6371 emitLabel (jtab->key + 100);
6372 /* now generate the jump labels */
6373 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
6374 jtab = setNextItem (IC_JTLABELS (ic)))
6375 emit2 ("jp !tlabel", jtab->key + 100);
6378 /*-----------------------------------------------------------------*/
6379 /* genCast - gen code for casting */
6380 /*-----------------------------------------------------------------*/
6382 genCast (iCode * ic)
6384 operand *result = IC_RESULT (ic);
6385 sym_link *ctype = operandType (IC_LEFT (ic));
6386 operand *right = IC_RIGHT (ic);
6389 /* if they are equivalent then do nothing */
6390 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6393 aopOp (right, ic, FALSE, FALSE);
6394 aopOp (result, ic, FALSE, FALSE);
6396 /* if the result is a bit */
6397 if (AOP_TYPE (result) == AOP_CRY)
6399 wassertl (0, "Tried to cast to a bit");
6402 /* if they are the same size : or less */
6403 if (AOP_SIZE (result) <= AOP_SIZE (right))
6406 /* if they are in the same place */
6407 if (sameRegs (AOP (right), AOP (result)))
6410 /* if they in different places then copy */
6411 size = AOP_SIZE (result);
6415 aopPut (AOP (result),
6416 aopGet (AOP (right), offset, FALSE),
6423 /* So we now know that the size of destination is greater
6424 than the size of the source */
6425 /* we move to result for the size of source */
6426 size = AOP_SIZE (right);
6430 aopPut (AOP (result),
6431 aopGet (AOP (right), offset, FALSE),
6436 /* now depending on the sign of the destination */
6437 size = AOP_SIZE (result) - AOP_SIZE (right);
6438 /* Unsigned or not an integral type - right fill with zeros */
6439 if (SPEC_USIGN (ctype) || !IS_SPEC (ctype))
6442 aopPut (AOP (result), "!zero", offset++);
6446 /* we need to extend the sign :{ */
6447 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
6453 aopPut (AOP (result), "a", offset++);
6457 freeAsmop (right, NULL, ic);
6458 freeAsmop (result, NULL, ic);
6461 /*-----------------------------------------------------------------*/
6462 /* genReceive - generate code for a receive iCode */
6463 /*-----------------------------------------------------------------*/
6465 genReceive (iCode * ic)
6467 if (isOperandInFarSpace (IC_RESULT (ic)) &&
6468 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
6469 IS_TRUE_SYMOP (IC_RESULT (ic))))
6479 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6480 size = AOP_SIZE(IC_RESULT(ic));
6482 for (i = 0; i < size; i++) {
6483 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
6487 freeAsmop (IC_RESULT (ic), NULL, ic);
6492 /** Maximum number of bytes to emit per line. */
6496 /** Context for the byte output chunker. */
6499 unsigned char buffer[DBEMIT_MAX_RUN];
6504 /** Flushes a byte chunker by writing out all in the buffer and
6508 _dbFlush(DBEMITCTX *self)
6515 sprintf(line, ".db 0x%02X", self->buffer[0]);
6517 for (i = 1; i < self->pos; i++)
6519 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
6526 /** Write out another byte, buffering until a decent line is
6530 _dbEmit(DBEMITCTX *self, int c)
6532 if (self->pos == DBEMIT_MAX_RUN)
6536 self->buffer[self->pos++] = c;
6539 /** Context for a simple run length encoder. */
6543 unsigned char buffer[128];
6545 /** runLen may be equivalent to pos. */
6551 RLE_CHANGE_COST = 4,
6555 /** Flush the buffer of a run length encoder by writing out the run or
6556 data that it currently contains.
6559 _rleCommit(RLECTX *self)
6565 memset(&db, 0, sizeof(db));
6567 emit2(".db %u", self->pos);
6569 for (i = 0; i < self->pos; i++)
6571 _dbEmit(&db, self->buffer[i]);
6580 Can get either a run or a block of random stuff.
6581 Only want to change state if a good run comes in or a run ends.
6582 Detecting run end is easy.
6585 Say initial state is in run, len zero, last zero. Then if you get a
6586 few zeros then something else then a short run will be output.
6587 Seems OK. While in run mode, keep counting. While in random mode,
6588 keep a count of the run. If run hits margin, output all up to run,
6589 restart, enter run mode.
6592 /** Add another byte into the run length encoder, flushing as
6593 required. The run length encoder uses the Amiga IFF style, where
6594 a block is prefixed by its run length. A positive length means
6595 the next n bytes pass straight through. A negative length means
6596 that the next byte is repeated -n times. A zero terminates the
6600 _rleAppend(RLECTX *self, int c)
6604 if (c != self->last)
6606 /* The run has stopped. See if it is worthwhile writing it out
6607 as a run. Note that the random data comes in as runs of
6610 if (self->runLen > RLE_CHANGE_COST)
6612 /* Yes, worthwhile. */
6613 /* Commit whatever was in the buffer. */
6615 emit2(".db -%u,0x%02X", self->runLen, self->last);
6619 /* Not worthwhile. Append to the end of the random list. */
6620 for (i = 0; i < self->runLen; i++)
6622 if (self->pos >= RLE_MAX_BLOCK)
6627 self->buffer[self->pos++] = self->last;
6635 if (self->runLen >= RLE_MAX_BLOCK)
6637 /* Commit whatever was in the buffer. */
6640 emit2 (".db -%u,0x%02X", self->runLen, self->last);
6648 _rleFlush(RLECTX *self)
6650 _rleAppend(self, -1);
6657 /** genArrayInit - Special code for initialising an array with constant
6661 genArrayInit (iCode * ic)
6665 int elementSize = 0, eIndex, i;
6666 unsigned val, lastVal;
6670 memset(&rle, 0, sizeof(rle));
6672 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
6674 _saveRegsForCall(ic, 0);
6676 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
6677 emit2 ("call __initrleblock");
6679 type = operandType(IC_LEFT(ic));
6681 if (type && type->next)
6683 elementSize = getSize(type->next);
6687 wassertl (0, "Can't determine element size in genArrayInit.");
6690 iLoop = IC_ARRAYILIST(ic);
6691 lastVal = (unsigned)-1;
6693 /* Feed all the bytes into the run length encoder which will handle
6695 This works well for mixed char data, and for random int and long
6704 for (i = 0; i < ix; i++)
6706 for (eIndex = 0; eIndex < elementSize; eIndex++)
6708 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
6709 _rleAppend(&rle, val);
6714 iLoop = iLoop->next;
6718 /* Mark the end of the run. */
6721 _restoreRegsAfterCall();
6725 freeAsmop (IC_LEFT(ic), NULL, ic);
6729 _swap (PAIR_ID one, PAIR_ID two)
6731 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
6737 emit2 ("ld a,%s", _pairs[one].l);
6738 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
6739 emit2 ("ld %s,a", _pairs[two].l);
6740 emit2 ("ld a,%s", _pairs[one].h);
6741 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
6742 emit2 ("ld %s,a", _pairs[two].h);
6746 /* The problem is that we may have all three pairs used and they may
6747 be needed in a different order.
6752 hl = hl => unity, fine
6756 hl = hl hl = hl, swap de <=> bc
6764 hl = bc de = de, swap bc <=> hl
6772 hl = de bc = bc, swap hl <=> de
6777 * Any pair = pair are done last
6778 * Any pair = iTemp are done last
6779 * Any swaps can be done any time
6787 So how do we detect the cases?
6788 How about a 3x3 matrix?
6792 x x x x (Fourth for iTemp/other)
6794 First determin which mode to use by counting the number of unity and
6797 Two - Assign the pair first, then the rest
6798 One - Swap the two, then the rest
6802 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
6804 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
6806 PAIR_BC, PAIR_HL, PAIR_DE
6808 int i, j, nunity = 0;
6809 memset (ids, PAIR_INVALID, sizeof (ids));
6812 wassert (nparams == 3);
6814 /* First save everything that needs to be saved. */
6815 _saveRegsForCall (ic, 0);
6817 /* Loading HL first means that DE is always fine. */
6818 for (i = 0; i < nparams; i++)
6820 aopOp (pparams[i], ic, FALSE, FALSE);
6821 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
6824 /* Count the number of unity or iTemp assigns. */
6825 for (i = 0; i < 3; i++)
6827 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
6835 /* Any order, fall through. */
6837 else if (nunity == 2)
6839 /* One is assigned. Pull it out and assign. */
6840 for (i = 0; i < 3; i++)
6842 for (j = 0; j < NUM_PAIRS; j++)
6844 if (ids[dest[i]][j] == TRUE)
6846 /* Found it. See if it's the right one. */
6847 if (j == PAIR_INVALID || j == dest[i])
6853 fetchPair(dest[i], AOP (pparams[i]));
6860 else if (nunity == 1)
6862 /* Find the pairs to swap. */
6863 for (i = 0; i < 3; i++)
6865 for (j = 0; j < NUM_PAIRS; j++)
6867 if (ids[dest[i]][j] == TRUE)
6869 if (j == PAIR_INVALID || j == dest[i])
6884 int next = getPairId (AOP (pparams[0]));
6885 emit2 ("push %s", _pairs[next].name);
6887 if (next == dest[1])
6889 fetchPair (dest[1], AOP (pparams[1]));
6890 fetchPair (dest[2], AOP (pparams[2]));
6894 fetchPair (dest[2], AOP (pparams[2]));
6895 fetchPair (dest[1], AOP (pparams[1]));
6897 emit2 ("pop %s", _pairs[dest[0]].name);
6900 /* Finally pull out all of the iTemps */
6901 for (i = 0; i < 3; i++)
6903 if (ids[dest[i]][PAIR_INVALID] == 1)
6905 fetchPair (dest[i], AOP (pparams[i]));
6911 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
6917 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
6921 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
6923 setupForBuiltin3 (ic, nParams, pparams);
6925 label = newiTempLabel(NULL);
6927 emitLabel (label->key);
6928 emit2 ("ld a,(hl)");
6931 emit2 ("!shortjp nz,!tlabel ; 1", label->key);
6933 freeAsmop (from, NULL, ic->next);
6934 freeAsmop (to, NULL, ic);
6938 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
6940 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));