1 /*-------------------------------------------------------------------------
2 gen.c - Z80 specific code generator.
4 Benchmarks on dhry.c 2.1 with 32766 loops and a 10ms clock:
6 Base with asm strcpy / strcmp / memcpy: 23198 141 1A14
7 Improved WORD push 22784 144 19AE
8 With label1 on 22694 144 197E
9 With label2 on 22743 144 198A
10 With label3 on 22776 144 1999
11 With label4 on 22776 144 1999
12 With all 'label' on 22661 144 196F
13 With loopInvariant on 20919 156 19AB
14 With loopInduction on Breaks 198B
15 With all working on 20796 158 196C
16 Slightly better genCmp(signed) 20597 159 195B
17 Better reg packing, first peephole 20038 163 1873
18 With assign packing 19281 165 1849
20 With reg params for mul and div 16234 202 162D
22 1. Starting again at 3 Aug 01 34965 93 219C
24 Includes long mul/div in code
25 2. Optimised memcpy for acc use 32102 102 226B
26 3. Optimised strcpy for acc use 27819 117 2237
27 3a Optimised memcpy fun
28 4. Optimised strcmp fun 21999 149 2294
29 5. Optimised strcmp further 21660 151 228C
30 6. Optimised memcpy by unroling 20885 157 2201
31 7. After turning loop induction on 19862 165 236D
33 Michael Hope <michaelh@juju.net.nz> 2000
34 Based on the mcs51 generator -
35 Sandeep Dutta . sandeep.dutta@usa.net (1998)
36 and - Jean-Louis VERN.jlvern@writeme.com (1999)
38 This program is free software; you can redistribute it and/or modify it
39 under the terms of the GNU General Public License as published by the
40 Free Software Foundation; either version 2, or (at your option) any
43 This program is distributed in the hope that it will be useful,
44 but WITHOUT ANY WARRANTY; without even the implied warranty of
45 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
46 GNU General Public License for more details.
49 You should have received a copy of the GNU General Public License
50 along with this program; if not, write to the Free Software
51 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
53 In other words, you are welcome to use, share and improve this program.
54 You are forbidden to forbid anyone else to use, share and improve
55 what you give them. Help stamp out software-hoarding!
57 -------------------------------------------------------------------------*/
64 #ifdef HAVE_SYS_ISA_DEFS_H
65 #include <sys/isa_defs.h>
69 #include "SDCCglobl.h"
70 #include "SDCCpeeph.h"
75 /* this is the down and dirty file with all kinds of kludgy & hacky
76 stuff. This is what it is all about CODE GENERATION for a specific MCU.
77 Some of the routines may be reusable, will have to see */
79 /* Z80 calling convention description.
80 Parameters are passed right to left. As the stack grows downwards,
81 the parameters are arranged in left to right in memory.
82 Parameters may be passed in the HL and DE registers with one
84 PENDING: What if the parameter is a long?
85 Everything is caller saves. i.e. the caller must save any registers
86 that it wants to preserve over the call.
87 The return value is returned in DEHL. DE is normally used as a
88 working register pair. Caller saves allows it to be used for a
90 va args functions do not use register parameters. All arguments
91 are passed on the stack.
92 IX is used as an index register to the top of the local variable
93 area. ix-0 is the top most local variable.
100 static char *_z80_return[] =
101 {"l", "h", "e", "d"};
102 static char *_gbz80_return[] =
103 {"e", "d", "l", "h"};
104 static char *_fReceive[] =
105 { "c", "b", "e", "d" };
107 static char **_fReturn;
110 extern FILE *codeOutFile;
129 } _pairs[NUM_PAIRS] = {
130 { "??1", "?2", "?3" },
135 { "iy", "iy.l?", "iy.h?" },
136 { "ix", "ix.l?", "ix.h?" }
140 #define ACC_NAME _pairs[PAIR_AF].h
142 #define RESULTONSTACK(x) \
143 (IC_RESULT(x) && IC_RESULT(x)->aop && \
144 IC_RESULT(x)->aop->type == AOP_STK )
175 const char *lastFunctionName;
181 /** TRUE if the registers have already been saved. */
194 static const char *aopGet (asmop * aop, int offset, bool bit16);
199 /* Clean up the line so that it is 'prettier' */
200 if (strchr (buf, ':'))
202 /* Is a label - cant do anything */
205 /* Change the first (and probably only) ' ' to a tab so
220 _vemit2 (const char *szFormat, va_list ap)
224 tvsprintf (buffer, szFormat, ap);
227 _G.lines.current = (_G.lines.current ?
228 connectLine (_G.lines.current, newLineNode (buffer)) :
229 (_G.lines.head = newLineNode (buffer)));
231 _G.lines.current->isInline = _G.lines.isInline;
235 emit2 (const char *szFormat,...)
239 va_start (ap, szFormat);
241 _vemit2 (szFormat, ap);
247 emitDebug (const char *szFormat,...)
253 va_start (ap, szFormat);
255 _vemit2 (szFormat, ap);
261 /*-----------------------------------------------------------------*/
262 /* emit2 - writes the code into a file : for now it is simple */
263 /*-----------------------------------------------------------------*/
265 _emit2 (const char *inst, const char *fmt,...)
268 char lb[INITIAL_INLINEASM];
275 sprintf (lb, "%s\t", inst);
276 vsprintf (lb + (strlen (lb)), fmt, ap);
279 vsprintf (lb, fmt, ap);
281 while (isspace (*lbp))
286 _G.lines.current = (_G.lines.current ?
287 connectLine (_G.lines.current, newLineNode (lb)) :
288 (_G.lines.head = newLineNode (lb)));
290 _G.lines.current->isInline = _G.lines.isInline;
295 _emitMove(const char *to, const char *from)
297 if (strcasecmp(to, from) != 0)
299 emit2("ld %s,%s", to, from);
304 // Could leave this to the peephole, but sometimes the peephole is inhibited.
309 _moveA(const char *moveFrom)
311 // Let the peephole optimiser take care of redundent loads
312 _emitMove(ACC_NAME, moveFrom);
322 getPairName (asmop * aop)
324 if (aop->type == AOP_REG)
326 switch (aop->aopu.aop_reg[0]->rIdx)
339 else if (aop->type == AOP_STR)
341 switch (*aop->aopu.aop_str[0])
359 getPairId (asmop * aop)
363 if (aop->type == AOP_REG)
365 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX) && (aop->aopu.aop_reg[1]->rIdx == B_IDX))
369 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX) && (aop->aopu.aop_reg[1]->rIdx == D_IDX))
373 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX) && (aop->aopu.aop_reg[1]->rIdx == H_IDX))
378 if (aop->type == AOP_STR)
380 if (!strcmp (aop->aopu.aop_str[0], "c") && !strcmp (aop->aopu.aop_str[1], "b"))
384 if (!strcmp (aop->aopu.aop_str[0], "e") && !strcmp (aop->aopu.aop_str[1], "d"))
388 if (!strcmp (aop->aopu.aop_str[0], "l") && !strcmp (aop->aopu.aop_str[1], "h"))
397 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
401 return (getPairId (aop) != PAIR_INVALID);
405 isPtrPair (asmop * aop)
407 PAIR_ID pairId = getPairId (aop);
418 /** Push a register pair onto the stack */
420 genPairPush (asmop * aop)
422 emit2 ("push %s", getPairName (aop));
426 /*-----------------------------------------------------------------*/
427 /* newAsmop - creates a new asmOp */
428 /*-----------------------------------------------------------------*/
430 newAsmop (short type)
434 aop = Safe_calloc (1, sizeof (asmop));
439 /*-----------------------------------------------------------------*/
440 /* aopForSym - for a true symbol */
441 /*-----------------------------------------------------------------*/
443 aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
450 wassert (sym->etype);
452 space = SPEC_OCLS (sym->etype);
454 /* if already has one */
458 /* Assign depending on the storage class */
459 if (sym->onStack || sym->iaccess)
461 emitDebug ("; AOP_STK for %s", sym->rname);
462 sym->aop = aop = newAsmop (AOP_STK);
463 aop->size = getSize (sym->type);
464 aop->aopu.aop_stk = sym->stack;
468 /* special case for a function */
469 if (IS_FUNC (sym->type))
471 sym->aop = aop = newAsmop (AOP_IMMD);
472 aop->aopu.aop_immd = Safe_calloc (1, strlen (sym->rname) + 1);
473 strcpy (aop->aopu.aop_immd, sym->rname);
480 /* if it is in direct space */
481 if (IN_REGSP (space) && !requires_a)
483 sym->aop = aop = newAsmop (AOP_SFR);
484 aop->aopu.aop_dir = sym->rname;
485 aop->size = getSize (sym->type);
486 emitDebug ("; AOP_SFR for %s", sym->rname);
491 /* only remaining is far space */
492 /* in which case DPTR gets the address */
495 emitDebug ("; AOP_HL for %s", sym->rname);
496 sym->aop = aop = newAsmop (AOP_HL);
500 sym->aop = aop = newAsmop (AOP_IY);
502 aop->size = getSize (sym->type);
503 aop->aopu.aop_dir = sym->rname;
505 /* if it is in code space */
506 if (IN_CODESPACE (space))
512 /*-----------------------------------------------------------------*/
513 /* aopForRemat - rematerialzes an object */
514 /*-----------------------------------------------------------------*/
516 aopForRemat (symbol * sym)
519 iCode *ic = sym->rematiCode;
520 asmop *aop = newAsmop (AOP_IMMD);
524 /* if plus or minus print the right hand side */
525 if (ic->op == '+' || ic->op == '-')
527 /* PENDING: for re-target */
528 sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
531 ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
534 /* we reached the end */
535 sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
539 aop->aopu.aop_immd = Safe_calloc (1, strlen (buffer) + 1);
540 strcpy (aop->aopu.aop_immd, buffer);
544 /*-----------------------------------------------------------------*/
545 /* regsInCommon - two operands have some registers in common */
546 /*-----------------------------------------------------------------*/
548 regsInCommon (operand * op1, operand * op2)
553 /* if they have registers in common */
554 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
557 sym1 = OP_SYMBOL (op1);
558 sym2 = OP_SYMBOL (op2);
560 if (sym1->nRegs == 0 || sym2->nRegs == 0)
563 for (i = 0; i < sym1->nRegs; i++)
569 for (j = 0; j < sym2->nRegs; j++)
574 if (sym2->regs[j] == sym1->regs[i])
582 /*-----------------------------------------------------------------*/
583 /* operandsEqu - equivalent */
584 /*-----------------------------------------------------------------*/
586 operandsEqu (operand * op1, operand * op2)
590 /* if they not symbols */
591 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
594 sym1 = OP_SYMBOL (op1);
595 sym2 = OP_SYMBOL (op2);
597 /* if both are itemps & one is spilt
598 and the other is not then false */
599 if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
600 sym1->isspilt != sym2->isspilt)
603 /* if they are the same */
607 if (strcmp (sym1->rname, sym2->rname) == 0)
611 /* if left is a tmp & right is not */
612 if (IS_ITEMP (op1) &&
615 (sym1->usl.spillLoc == sym2))
618 if (IS_ITEMP (op2) &&
622 (sym2->usl.spillLoc == sym1))
628 /*-----------------------------------------------------------------*/
629 /* sameRegs - two asmops have the same registers */
630 /*-----------------------------------------------------------------*/
632 sameRegs (asmop * aop1, asmop * aop2)
636 if (aop1->type == AOP_SFR ||
637 aop2->type == AOP_SFR)
643 if (aop1->type != AOP_REG ||
644 aop2->type != AOP_REG)
647 if (aop1->size != aop2->size)
650 for (i = 0; i < aop1->size; i++)
651 if (aop1->aopu.aop_reg[i] !=
652 aop2->aopu.aop_reg[i])
658 /*-----------------------------------------------------------------*/
659 /* aopOp - allocates an asmop for an operand : */
660 /*-----------------------------------------------------------------*/
662 aopOp (operand * op, iCode * ic, bool result, bool requires_a)
671 /* if this a literal */
672 if (IS_OP_LITERAL (op))
674 op->aop = aop = newAsmop (AOP_LIT);
675 aop->aopu.aop_lit = op->operand.valOperand;
676 aop->size = getSize (operandType (op));
680 /* if already has a asmop then continue */
684 /* if the underlying symbol has a aop */
685 if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
687 op->aop = OP_SYMBOL (op)->aop;
691 /* if this is a true symbol */
692 if (IS_TRUE_SYMOP (op))
694 op->aop = aopForSym (ic, OP_SYMBOL (op), result, requires_a);
698 /* this is a temporary : this has
704 e) can be a return use only */
706 sym = OP_SYMBOL (op);
708 /* if the type is a conditional */
709 if (sym->regType == REG_CND)
711 aop = op->aop = sym->aop = newAsmop (AOP_CRY);
716 /* if it is spilt then two situations
718 b) has a spill location */
719 if (sym->isspilt || sym->nRegs == 0)
721 /* rematerialize it NOW */
724 sym->aop = op->aop = aop =
726 aop->size = getSize (sym->type);
732 if (sym->accuse == ACCUSE_A)
734 aop = op->aop = sym->aop = newAsmop (AOP_ACC);
735 aop->size = getSize (sym->type);
736 wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
738 aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
740 else if (sym->accuse == ACCUSE_HL)
743 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
744 aop->size = getSize (sym->type);
745 wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
746 aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
747 aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
759 aop = op->aop = sym->aop = newAsmop (AOP_STR);
760 aop->size = getSize (sym->type);
761 for (i = 0; i < 4; i++)
762 aop->aopu.aop_str[i] = _fReturn[i];
766 /* else spill location */
767 sym->aop = op->aop = aop =
768 aopForSym (ic, sym->usl.spillLoc, result, requires_a);
769 aop->size = getSize (sym->type);
773 /* must be in a register */
774 sym->aop = op->aop = aop = newAsmop (AOP_REG);
775 aop->size = sym->nRegs;
776 for (i = 0; i < sym->nRegs; i++)
777 aop->aopu.aop_reg[i] = sym->regs[i];
780 /*-----------------------------------------------------------------*/
781 /* freeAsmop - free up the asmop given to an operand */
782 /*----------------------------------------------------------------*/
784 freeAsmop (operand * op, asmop * aaop, iCode * ic)
802 /* all other cases just dealloc */
808 OP_SYMBOL (op)->aop = NULL;
809 /* if the symbol has a spill */
811 SPIL_LOC (op)->aop = NULL;
817 isLitWord (asmop * aop)
819 /* if (aop->size != 2)
832 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
837 /* depending on type */
843 /* PENDING: for re-target */
845 tsprintf (s, "!hashedstr + %d", aop->aopu.aop_immd, offset);
847 tsprintf (s, "%s + %d", aop->aopu.aop_immd, offset);
853 value *val = aop->aopu.aop_lit;
854 /* if it is a float then it gets tricky */
855 /* otherwise it is fairly simple */
856 if (!IS_FLOAT (val->type))
858 unsigned long v = (unsigned long) floatFromVal (val);
864 else if (offset == 0)
870 wassertl(0, "Encountered an invalid offset while fetching a literal");
874 tsprintf (buffer, "!immedword", v);
876 tsprintf (buffer, "!constword", v);
878 return gc_strdup(buffer);
884 convertFloat (&f, floatFromVal (val));
886 tsprintf (buffer, "!immedword", f.w[offset / 2]);
888 tsprintf (buffer, "!constword", f.w[offset / 2]);
889 rs = Safe_calloc (1, strlen (buffer) + 1);
890 return strcpy (rs, buffer);
899 aopGetWord (asmop * aop, int offset)
901 return aopGetLitWordLong (aop, offset, TRUE);
905 isPtr (const char *s)
907 if (!strcmp (s, "hl"))
909 if (!strcmp (s, "ix"))
911 if (!strcmp (s, "iy"))
917 adjustPair (const char *pair, int *pold, int new)
923 emit2 ("inc %s", pair);
928 emit2 ("dec %s", pair);
934 spillPair (PAIR_ID pairId)
936 _G.pairs[pairId].last_type = AOP_INVALID;
937 _G.pairs[pairId].lit = NULL;
948 requiresHL (asmop * aop)
962 fetchLitSpecial (asmop * aop, bool negate, bool xor)
965 value *val = aop->aopu.aop_lit;
967 wassert (aop->type == AOP_LIT);
968 wassert (!IS_FLOAT (val->type));
970 v = (unsigned long) floatFromVal (val);
978 tsprintf (buffer, "!immedword", v);
979 return gc_strdup (buffer);
983 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
986 const char *pair = _pairs[pairId].name;
987 l = aopGetLitWordLong (left, offset, FALSE);
992 if (pairId == PAIR_HL || pairId == PAIR_IY)
994 if (_G.pairs[pairId].last_type == left->type)
996 if (_G.pairs[pairId].lit && !strcmp (_G.pairs[pairId].lit, l))
998 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1000 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1003 if (pairId == PAIR_IY && abs (offset) < 127)
1010 _G.pairs[pairId].last_type = left->type;
1011 _G.pairs[pairId].lit = gc_strdup (l);
1012 _G.pairs[pairId].offset = offset;
1014 if (IS_GB && pairId == PAIR_DE && 0)
1016 if (_G.pairs[pairId].lit && !strcmp (_G.pairs[pairId].lit, l))
1018 if (abs (_G.pairs[pairId].offset - offset) < 3)
1020 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1024 _G.pairs[pairId].last_type = left->type;
1025 _G.pairs[pairId].lit = gc_strdup (l);
1026 _G.pairs[pairId].offset = offset;
1028 /* Both a lit on the right and a true symbol on the left */
1029 emit2 ("ld %s,!hashedstr", pair, l);
1033 fetchPairLong (PAIR_ID pairId, asmop * aop, int offset)
1035 /* if this is remateriazable */
1036 if (isLitWord (aop)) {
1037 fetchLitPair (pairId, aop, offset);
1040 /* we need to get it byte by byte */
1041 if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1042 aopGet (aop, offset, FALSE);
1043 switch (aop->size) {
1045 emit2 ("ld l,!*hl");
1046 emit2 ("ld h,!immedbyte", 0);
1050 emit2 ("ld h,!*hl");
1054 emitDebug ("; WARNING: mlh woosed out. This code is invalid.");
1057 else if (IS_Z80 && aop->type == AOP_IY) {
1058 /* Instead of fetching relative to IY, just grab directly
1059 from the address IY refers to */
1060 char *l = aopGetLitWordLong (aop, offset, FALSE);
1062 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1064 if (aop->size < 2) {
1065 emit2("ld %s,!zero", _pairs[pairId].h);
1069 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1070 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1072 /* PENDING: check? */
1073 if (pairId == PAIR_HL)
1074 spillPair (PAIR_HL);
1079 fetchPair (PAIR_ID pairId, asmop * aop)
1081 fetchPairLong (pairId, aop, 0);
1085 fetchHL (asmop * aop)
1087 fetchPair (PAIR_HL, aop);
1091 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1093 assert (pairId == PAIR_HL || pairId == PAIR_IY);
1098 fetchLitPair (pairId, aop, 0);
1101 fetchLitPair (pairId, aop, offset);
1102 _G.pairs[pairId].offset = offset;
1106 /* Doesnt include _G.stack.pushed */
1107 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1108 if (aop->aopu.aop_stk > 0)
1110 abso += _G.stack.param_offset;
1112 assert (pairId == PAIR_HL);
1113 /* In some cases we can still inc or dec hl */
1114 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1116 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1120 emit2 ("!ldahlsp", abso + _G.stack.pushed);
1122 _G.pairs[pairId].offset = abso;
1128 _G.pairs[pairId].last_type = aop->type;
1134 emit2 ("!tlabeldef", key);
1138 /*-----------------------------------------------------------------*/
1139 /* aopGet - for fetching value of the aop */
1140 /*-----------------------------------------------------------------*/
1142 aopGet (asmop * aop, int offset, bool bit16)
1146 /* offset is greater than size then zero */
1147 /* PENDING: this seems a bit screwed in some pointer cases. */
1148 if (offset > (aop->size - 1) &&
1149 aop->type != AOP_LIT)
1151 tsprintf (s, "!zero");
1152 return gc_strdup(s);
1155 /* depending on type */
1159 /* PENDING: re-target */
1161 tsprintf (s, "!immedwords", aop->aopu.aop_immd);
1166 tsprintf (s, "!bankimmeds", aop->aopu.aop_immd);
1169 tsprintf (s, "!msbimmeds", aop->aopu.aop_immd);
1172 tsprintf (s, "!lsbimmeds", aop->aopu.aop_immd);
1178 return gc_strdup(s);
1182 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1185 return gc_strdup(s);
1189 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1192 return gc_strdup(s);
1195 return aop->aopu.aop_reg[offset]->name;
1199 setupPair (PAIR_HL, aop, offset);
1200 tsprintf (s, "!*hl");
1202 return gc_strdup (s);
1206 setupPair (PAIR_IY, aop, offset);
1207 tsprintf (s, "!*iyx", offset);
1209 return gc_strdup(s);
1214 setupPair (PAIR_HL, aop, offset);
1215 tsprintf (s, "!*hl");
1219 if (aop->aopu.aop_stk >= 0)
1220 offset += _G.stack.param_offset;
1221 tsprintf (s, "!*ixx", aop->aopu.aop_stk + offset);
1224 return gc_strdup(s);
1236 tsprintf(s, "!zero");
1237 return gc_strdup(s);
1241 wassert (offset < 2);
1242 return aop->aopu.aop_str[offset];
1245 return aopLiteral (aop->aopu.aop_lit, offset);
1249 return aop->aopu.aop_str[offset];
1254 wassertl (0, "aopget got unsupported aop->type");
1259 isRegString (const char *s)
1261 if (!strcmp (s, "b") ||
1273 isConstant (const char *s)
1275 /* This is a bit of a hack... */
1276 return (*s == '#' || *s == '$');
1280 canAssignToPtr (const char *s)
1282 if (isRegString (s))
1289 /*-----------------------------------------------------------------*/
1290 /* aopPut - puts a string for a aop */
1291 /*-----------------------------------------------------------------*/
1293 aopPut (asmop * aop, const char *s, int offset)
1297 if (aop->size && offset > (aop->size - 1))
1299 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1300 "aopPut got offset > aop->size");
1305 tsprintf(buffer2, s);
1308 /* will assign value to value */
1309 /* depending on where it is ofcourse */
1315 if (strcmp (s, "a"))
1316 emit2 ("ld a,%s", s);
1317 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1322 if (strcmp (s, "a"))
1323 emit2 ("ld a,%s", s);
1324 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1328 if (!strcmp (s, "!*hl"))
1329 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1332 aop->aopu.aop_reg[offset]->name, s);
1337 setupPair (PAIR_IY, aop, offset);
1338 if (!canAssignToPtr (s))
1340 emit2 ("ld a,%s", s);
1341 emit2 ("ld !*iyx,a", offset);
1344 emit2 ("ld !*iyx,%s", offset, s);
1349 /* PENDING: for re-target */
1350 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1352 emit2 ("ld a,!*hl");
1355 setupPair (PAIR_HL, aop, offset);
1357 emit2 ("ld !*hl,%s", s);
1363 /* PENDING: re-target */
1364 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1366 emit2 ("ld a,!*hl");
1369 setupPair (PAIR_HL, aop, offset);
1370 if (!canAssignToPtr (s))
1372 emit2 ("ld a,%s", s);
1373 emit2 ("ld !*hl,a");
1376 emit2 ("ld !*hl,%s", s);
1380 if (aop->aopu.aop_stk >= 0)
1381 offset += _G.stack.param_offset;
1382 if (!canAssignToPtr (s))
1384 emit2 ("ld a,%s", s);
1385 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
1388 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
1393 /* if bit variable */
1394 if (!aop->aopu.aop_dir)
1401 /* In bit space but not in C - cant happen */
1408 if (strcmp (aop->aopu.aop_str[offset], s))
1410 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1416 if (!offset && (strcmp (s, "acc") == 0))
1421 emitDebug ("; Error aopPut AOP_ACC");
1425 if (strcmp (aop->aopu.aop_str[offset], s))
1426 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1431 wassert (offset < 2);
1432 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1436 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1437 "aopPut got unsupported aop->type");
1442 #define AOP(op) op->aop
1443 #define AOP_TYPE(op) AOP(op)->type
1444 #define AOP_SIZE(op) AOP(op)->size
1445 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
1448 commitPair (asmop * aop, PAIR_ID id)
1450 if (id == PAIR_HL && requiresHL (aop))
1454 aopPut (aop, "a", 0);
1455 aopPut (aop, "d", 1);
1459 aopPut (aop, _pairs[id].l, 0);
1460 aopPut (aop, _pairs[id].h, 1);
1464 /*-----------------------------------------------------------------*/
1465 /* getDataSize - get the operand data size */
1466 /*-----------------------------------------------------------------*/
1468 getDataSize (operand * op)
1471 size = AOP_SIZE (op);
1480 /*-----------------------------------------------------------------*/
1481 /* movLeft2Result - move byte from left to result */
1482 /*-----------------------------------------------------------------*/
1484 movLeft2Result (operand * left, int offl,
1485 operand * result, int offr, int sign)
1488 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
1490 l = aopGet (AOP (left), offl, FALSE);
1494 aopPut (AOP (result), l, offr);
1504 /** Put Acc into a register set
1507 outAcc (operand * result)
1510 size = getDataSize (result);
1513 aopPut (AOP (result), "a", 0);
1516 /* unsigned or positive */
1519 aopPut (AOP (result), "!zero", offset++);
1524 /** Take the value in carry and put it into a register
1527 outBitCLong (operand * result, bool swap_sense)
1529 /* if the result is bit */
1530 if (AOP_TYPE (result) == AOP_CRY)
1532 emitDebug ("; Note: outBitC form 1");
1533 aopPut (AOP (result), "blah", 0);
1537 emit2 ("ld a,!zero");
1540 emit2 ("xor a,!immedbyte", 1);
1546 outBitC (operand * result)
1548 outBitCLong (result, FALSE);
1551 /*-----------------------------------------------------------------*/
1552 /* toBoolean - emit code for orl a,operator(sizeop) */
1553 /*-----------------------------------------------------------------*/
1555 _toBoolean (operand * oper)
1557 int size = AOP_SIZE (oper);
1561 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
1564 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
1568 if (AOP (oper)->type != AOP_ACC)
1571 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
1576 /*-----------------------------------------------------------------*/
1577 /* genNot - generate code for ! operation */
1578 /*-----------------------------------------------------------------*/
1582 sym_link *optype = operandType (IC_LEFT (ic));
1584 /* assign asmOps to operand & result */
1585 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
1586 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1588 /* if in bit space then a special case */
1589 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1594 /* if type float then do float */
1595 if (IS_FLOAT (optype))
1600 _toBoolean (IC_LEFT (ic));
1605 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
1606 emit2 ("sub a,!one");
1607 outBitC (IC_RESULT (ic));
1609 /* release the aops */
1610 freeAsmop (IC_LEFT (ic), NULL, ic);
1611 freeAsmop (IC_RESULT (ic), NULL, ic);
1614 /*-----------------------------------------------------------------*/
1615 /* genCpl - generate code for complement */
1616 /*-----------------------------------------------------------------*/
1624 /* assign asmOps to operand & result */
1625 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1626 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1628 /* if both are in bit space then
1630 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1631 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1636 size = AOP_SIZE (IC_RESULT (ic));
1639 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
1642 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1645 /* release the aops */
1646 freeAsmop (IC_LEFT (ic), NULL, ic);
1647 freeAsmop (IC_RESULT (ic), NULL, ic);
1650 /*-----------------------------------------------------------------*/
1651 /* genUminus - unary minus code generation */
1652 /*-----------------------------------------------------------------*/
1654 genUminus (iCode * ic)
1657 sym_link *optype, *rtype;
1660 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1661 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1663 /* if both in bit space then special
1665 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1666 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1672 optype = operandType (IC_LEFT (ic));
1673 rtype = operandType (IC_RESULT (ic));
1675 /* if float then do float stuff */
1676 if (IS_FLOAT (optype))
1682 /* otherwise subtract from zero */
1683 size = AOP_SIZE (IC_LEFT (ic));
1688 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
1689 emit2 ("ld a,!zero");
1690 emit2 ("sbc a,%s", l);
1691 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1694 /* if any remaining bytes in the result */
1695 /* we just need to propagate the sign */
1696 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
1701 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1705 /* release the aops */
1706 freeAsmop (IC_LEFT (ic), NULL, ic);
1707 freeAsmop (IC_RESULT (ic), NULL, ic);
1711 _push (PAIR_ID pairId)
1713 emit2 ("push %s", _pairs[pairId].name);
1714 _G.stack.pushed += 2;
1718 _pop (PAIR_ID pairId)
1720 emit2 ("pop %s", _pairs[pairId].name);
1721 _G.stack.pushed -= 2;
1725 /*-----------------------------------------------------------------*/
1726 /* assignResultValue - */
1727 /*-----------------------------------------------------------------*/
1729 assignResultValue (operand * oper)
1731 int size = AOP_SIZE (oper);
1734 wassert (size <= 4);
1735 topInA = requiresHL (AOP (oper));
1739 wassert (size <= 2);
1741 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
1743 /* We do it the hard way here. */
1745 aopPut (AOP (oper), _fReturn[0], 0);
1746 aopPut (AOP (oper), _fReturn[1], 1);
1748 _G.stack.pushed -= 2;
1749 aopPut (AOP (oper), _fReturn[0], 2);
1750 aopPut (AOP (oper), _fReturn[1], 3);
1756 aopPut (AOP (oper), _fReturn[size], size);
1762 _saveRegsForCall(iCode *ic, int sendSetSize)
1765 o Stack parameters are pushed before this function enters
1766 o DE and BC may be used in this function.
1767 o HL and DE may be used to return the result.
1768 o HL and DE may be used to send variables.
1769 o DE and BC may be used to store the result value.
1770 o HL may be used in computing the sent value of DE
1771 o The iPushes for other parameters occur before any addSets
1773 Logic: (to be run inside the first iPush or if none, before sending)
1774 o Compute if DE and/or BC are in use over the call
1775 o Compute if DE is used in the send set
1776 o Compute if DE and/or BC are used to hold the result value
1777 o If (DE is used, or in the send set) and is not used in the result, push.
1778 o If BC is used and is not in the result, push
1780 o If DE is used in the send set, fetch
1781 o If HL is used in the send set, fetch
1785 if (_G.saves.saved == FALSE) {
1786 bool deInUse, bcInUse;
1788 bool bcInRet = FALSE, deInRet = FALSE;
1792 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
1796 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), z80_rUmaskForOp (IC_RESULT(ic)));
1800 /* Has no result, so in use is all of in use */
1805 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
1806 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
1808 deSending = (sendSetSize > 1);
1810 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
1812 if (bcInUse && bcInRet == FALSE) {
1814 _G.stack.pushedBC = TRUE;
1816 if (deInUse && deInRet == FALSE) {
1818 _G.stack.pushedDE = TRUE;
1821 _G.saves.saved = TRUE;
1824 /* Already saved. */
1828 /*-----------------------------------------------------------------*/
1829 /* genIpush - genrate code for pushing this gets a little complex */
1830 /*-----------------------------------------------------------------*/
1832 genIpush (iCode * ic)
1834 int size, offset = 0;
1837 /* if this is not a parm push : ie. it is spill push
1838 and spill push is always done on the local stack */
1841 wassertl(0, "Encountered an unsupported spill push.");
1845 if (_G.saves.saved == FALSE) {
1846 /* Caller saves, and this is the first iPush. */
1847 /* Scan ahead until we find the function that we are pushing parameters to.
1848 Count the number of addSets on the way to figure out what registers
1849 are used in the send set.
1852 iCode *walk = ic->next;
1855 if (walk->op == SEND) {
1858 else if (walk->op == CALL || walk->op == PCALL) {
1867 _saveRegsForCall(walk, nAddSets);
1870 /* Already saved by another iPush. */
1873 /* then do the push */
1874 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1876 size = AOP_SIZE (IC_LEFT (ic));
1878 if (isPair (AOP (IC_LEFT (ic))))
1880 _G.stack.pushed += 2;
1881 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
1887 fetchHL (AOP (IC_LEFT (ic)));
1889 spillPair (PAIR_HL);
1890 _G.stack.pushed += 2;
1895 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
1897 spillPair (PAIR_HL);
1898 _G.stack.pushed += 2;
1899 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 0);
1901 spillPair (PAIR_HL);
1902 _G.stack.pushed += 2;
1908 if (AOP (IC_LEFT (ic))->type == AOP_IY)
1910 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
1912 emit2 ("ld a,(%s)", l);
1916 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
1917 emit2 ("ld a,%s", l);
1925 freeAsmop (IC_LEFT (ic), NULL, ic);
1928 /*-----------------------------------------------------------------*/
1929 /* genIpop - recover the registers: can happen only for spilling */
1930 /*-----------------------------------------------------------------*/
1932 genIpop (iCode * ic)
1937 /* if the temp was not pushed then */
1938 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
1941 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1942 size = AOP_SIZE (IC_LEFT (ic));
1943 offset = (size - 1);
1944 if (isPair (AOP (IC_LEFT (ic))))
1946 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
1954 spillPair (PAIR_HL);
1955 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
1959 freeAsmop (IC_LEFT (ic), NULL, ic);
1962 /* This is quite unfortunate */
1964 setArea (int inHome)
1967 static int lastArea = 0;
1969 if (_G.in_home != inHome) {
1971 const char *sz = port->mem.code_name;
1972 port->mem.code_name = "HOME";
1973 emit2("!area", CODE_NAME);
1974 port->mem.code_name = sz;
1977 emit2("!area", CODE_NAME); */
1978 _G.in_home = inHome;
1989 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
1993 symbol *sym = OP_SYMBOL (op);
1995 if (sym->isspilt || sym->nRegs == 0)
1998 aopOp (op, ic, FALSE, FALSE);
2001 if (aop->type == AOP_REG)
2004 for (i = 0; i < aop->size; i++)
2006 if (pairId == PAIR_DE)
2008 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2009 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2011 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2014 else if (pairId == PAIR_BC)
2016 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2017 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2019 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2029 freeAsmop (IC_LEFT (ic), NULL, ic);
2033 /** Emit the code for a call statement
2036 emitCall (iCode * ic, bool ispcall)
2038 sym_link *detype = getSpec (operandType (IC_LEFT (ic)));
2040 bitVect *rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
2042 /* if caller saves & we have not saved then */
2048 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2050 /* if send set is not empty then assign */
2055 int nSend = elementsInSet(_G.sendSet);
2056 bool swapped = FALSE;
2058 int _z80_sendOrder[] = {
2063 /* Check if the parameters are swapped. If so route through hl instead. */
2064 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2066 sic = setFirstItem(_G.sendSet);
2067 sic = setNextItem(_G.sendSet);
2069 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2070 /* The second send value is loaded from one the one that holds the first
2071 send, i.e. it is overwritten. */
2072 /* Cache the first in HL, and load the second from HL instead. */
2073 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2074 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2080 for (sic = setFirstItem (_G.sendSet); sic;
2081 sic = setNextItem (_G.sendSet))
2084 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2086 size = AOP_SIZE (IC_LEFT (sic));
2087 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2088 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2090 // PENDING: Mild hack
2091 if (swapped == TRUE && send == 1) {
2093 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2096 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2098 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2101 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2105 freeAsmop (IC_LEFT (sic), NULL, sic);
2112 if (IS_BANKEDCALL (detype))
2114 werror (W_INDIR_BANKED);
2116 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2118 if (isLitWord (AOP (IC_LEFT (ic))))
2120 emitDebug ("; Special case where the pCall is to a constant");
2121 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2125 symbol *rlbl = newiTempLabel (NULL);
2126 spillPair (PAIR_HL);
2127 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2129 _G.stack.pushed += 2;
2131 fetchHL (AOP (IC_LEFT (ic)));
2133 emit2 ("!tlabeldef", (rlbl->key + 100));
2134 _G.stack.pushed -= 2;
2136 freeAsmop (IC_LEFT (ic), NULL, ic);
2140 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2141 OP_SYMBOL (IC_LEFT (ic))->rname :
2142 OP_SYMBOL (IC_LEFT (ic))->name;
2143 if (IS_BANKEDCALL (detype))
2145 emit2 ("call banked_call");
2146 emit2 ("!dws", name);
2147 emit2 ("!dw !bankimmeds", name);
2152 emit2 ("call %s", name);
2157 /* Mark the regsiters as restored. */
2158 _G.saves.saved = FALSE;
2160 /* if we need assign a result value */
2161 if ((IS_ITEMP (IC_RESULT (ic)) &&
2162 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2163 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2164 IS_TRUE_SYMOP (IC_RESULT (ic)))
2167 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2169 assignResultValue (IC_RESULT (ic));
2171 freeAsmop (IC_RESULT (ic), NULL, ic);
2174 /* adjust the stack for parameters if required */
2177 int i = ic->parmBytes;
2179 _G.stack.pushed -= i;
2182 emit2 ("!ldaspsp", i);
2189 emit2 ("ld hl,#%d", i);
2190 emit2 ("add hl,sp");
2207 if (_G.stack.pushedDE)
2209 bool dInUse = bitVectBitValue(rInUse, D_IDX);
2210 bool eInUse = bitVectBitValue(rInUse, E_IDX);
2212 if (dInUse && eInUse)
2228 wassertl (0, "Neither D or E were in use but it was pushed.");
2230 _G.stack.pushedDE = FALSE;
2233 if (_G.stack.pushedBC)
2235 bool bInUse = bitVectBitValue(rInUse, B_IDX);
2236 bool cInUse = bitVectBitValue(rInUse, C_IDX);
2238 // If both B and C are used in the return value, then we won't get
2240 if (bInUse && cInUse)
2256 wassertl (0, "Neither B or C were in use but it was pushed.");
2258 _G.stack.pushedBC = FALSE;
2262 /*-----------------------------------------------------------------*/
2263 /* genCall - generates a call statement */
2264 /*-----------------------------------------------------------------*/
2266 genCall (iCode * ic)
2268 emitCall (ic, FALSE);
2271 /*-----------------------------------------------------------------*/
2272 /* genPcall - generates a call by pointer statement */
2273 /*-----------------------------------------------------------------*/
2275 genPcall (iCode * ic)
2277 emitCall (ic, TRUE);
2280 /*-----------------------------------------------------------------*/
2281 /* resultRemat - result is rematerializable */
2282 /*-----------------------------------------------------------------*/
2284 resultRemat (iCode * ic)
2286 if (SKIP_IC (ic) || ic->op == IFX)
2289 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2291 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2292 if (sym->remat && !POINTER_SET (ic))
2299 extern set *publics;
2301 /*-----------------------------------------------------------------*/
2302 /* genFunction - generated code for function entry */
2303 /*-----------------------------------------------------------------*/
2305 genFunction (iCode * ic)
2307 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2311 bool bcInUse = FALSE;
2312 bool deInUse = FALSE;
2315 setArea (IS_NONBANKED (sym->etype));
2317 /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
2320 _G.receiveOffset = 0;
2324 if (!IS_STATIC (sym->etype))
2326 addSetIfnotP (&publics, sym);
2330 /* Record the last function name for debugging. */
2331 _G.lastFunctionName = sym->rname;
2333 /* Create the function header */
2334 emit2 ("!functionheader", sym->name);
2335 /* PENDING: portability. */
2336 emit2 ("__%s_start:", sym->rname);
2337 emit2 ("!functionlabeldef", sym->rname);
2339 if (options.profile)
2341 emit2 ("!profileenter");
2344 fetype = getSpec (operandType (IC_LEFT (ic)));
2346 /* if critical function then turn interrupts off */
2347 if (SPEC_CRTCL (fetype))
2350 /* if this is an interrupt service routine then save all potentially used registers. */
2351 if (IS_ISR (sym->etype))
2356 /* PENDING: callee-save etc */
2358 _G.stack.param_offset = 0;
2361 /* Detect which registers are used. */
2365 for (i = 0; i < sym->regsUsed->size; i++)
2367 if (bitVectBitValue (sym->regsUsed, i))
2381 /* Other systems use DE as a temporary. */
2392 _G.stack.param_offset += 2;
2395 _G.stack.pushedBC = bcInUse;
2400 _G.stack.param_offset += 2;
2403 _G.stack.pushedDE = deInUse;
2406 /* adjust the stack for the function */
2407 _G.stack.last = sym->stack;
2410 emit2 ("!enterx", sym->stack);
2413 _G.stack.offset = sym->stack;
2416 /*-----------------------------------------------------------------*/
2417 /* genEndFunction - generates epilogue for functions */
2418 /*-----------------------------------------------------------------*/
2420 genEndFunction (iCode * ic)
2422 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2424 if (IS_ISR (sym->etype))
2430 if (SPEC_CRTCL (sym->etype))
2433 /* PENDING: calleeSave */
2435 if (_G.stack.offset)
2437 emit2 ("!leavex", _G.stack.offset);
2445 if (_G.stack.pushedDE)
2448 _G.stack.pushedDE = FALSE;
2451 if (_G.stack.pushedDE)
2454 _G.stack.pushedDE = FALSE;
2458 if (options.profile)
2460 emit2 ("!profileexit");
2464 /* Both baned and non-banked just ret */
2467 /* PENDING: portability. */
2468 emit2 ("__%s_end:", sym->rname);
2470 _G.flushStatics = 1;
2471 _G.stack.pushed = 0;
2472 _G.stack.offset = 0;
2475 /*-----------------------------------------------------------------*/
2476 /* genRet - generate code for return statement */
2477 /*-----------------------------------------------------------------*/
2482 /* Errk. This is a hack until I can figure out how
2483 to cause dehl to spill on a call */
2484 int size, offset = 0;
2486 /* if we have no return value then
2487 just generate the "ret" */
2491 /* we have something to return then
2492 move the return value into place */
2493 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2494 size = AOP_SIZE (IC_LEFT (ic));
2496 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
2500 emit2 ("ld de,%s", l);
2504 emit2 ("ld hl,%s", l);
2509 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
2511 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
2512 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
2518 l = aopGet (AOP (IC_LEFT (ic)), offset,
2520 if (strcmp (_fReturn[offset], l))
2521 emit2 ("ld %s,%s", _fReturn[offset++], l);
2525 freeAsmop (IC_LEFT (ic), NULL, ic);
2528 /* generate a jump to the return label
2529 if the next is not the return statement */
2530 if (!(ic->next && ic->next->op == LABEL &&
2531 IC_LABEL (ic->next) == returnLabel))
2533 emit2 ("jp !tlabel", returnLabel->key + 100);
2536 /*-----------------------------------------------------------------*/
2537 /* genLabel - generates a label */
2538 /*-----------------------------------------------------------------*/
2540 genLabel (iCode * ic)
2542 /* special case never generate */
2543 if (IC_LABEL (ic) == entryLabel)
2546 emitLabel (IC_LABEL (ic)->key + 100);
2549 /*-----------------------------------------------------------------*/
2550 /* genGoto - generates a ljmp */
2551 /*-----------------------------------------------------------------*/
2553 genGoto (iCode * ic)
2555 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
2558 /*-----------------------------------------------------------------*/
2559 /* genPlusIncr :- does addition with increment if possible */
2560 /*-----------------------------------------------------------------*/
2562 genPlusIncr (iCode * ic)
2564 unsigned int icount;
2565 unsigned int size = getDataSize (IC_RESULT (ic));
2566 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
2568 /* will try to generate an increment */
2569 /* if the right side is not a literal
2571 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
2574 emitDebug ("; genPlusIncr");
2576 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
2578 /* If result is a pair */
2579 if (resultId != PAIR_INVALID)
2581 if (isLitWord (AOP (IC_LEFT (ic))))
2583 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
2586 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
2588 fetchPair (resultId, AOP (IC_RIGHT (ic)));
2589 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
2595 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2599 movLeft2Result (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0);
2600 movLeft2Result (IC_LEFT (ic), 1, IC_RESULT (ic), 1, 0);
2604 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
2609 /* if the literal value of the right hand side
2610 is greater than 4 then it is not worth it */
2614 /* if increment 16 bits in register */
2615 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
2621 symbol *tlbl = NULL;
2622 tlbl = newiTempLabel (NULL);
2625 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
2628 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
2631 emitLabel (tlbl->key + 100);
2635 /* if the sizes are greater than 1 then we cannot */
2636 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
2637 AOP_SIZE (IC_LEFT (ic)) > 1)
2640 /* we can if the aops of the left & result match or
2641 if they are in registers and the registers are the
2643 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2647 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
2655 /*-----------------------------------------------------------------*/
2656 /* outBitAcc - output a bit in acc */
2657 /*-----------------------------------------------------------------*/
2659 outBitAcc (operand * result)
2661 symbol *tlbl = newiTempLabel (NULL);
2662 /* if the result is a bit */
2663 if (AOP_TYPE (result) == AOP_CRY)
2669 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
2670 emit2 ("ld a,!one");
2671 emitLabel (tlbl->key + 100);
2676 /*-----------------------------------------------------------------*/
2677 /* genPlus - generates code for addition */
2678 /*-----------------------------------------------------------------*/
2680 genPlus (iCode * ic)
2682 int size, offset = 0;
2684 /* special cases :- */
2686 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2687 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
2688 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2690 /* Swap the left and right operands if:
2692 if literal, literal on the right or
2693 if left requires ACC or right is already
2696 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
2697 (AOP_NEEDSACC (IC_LEFT (ic))) ||
2698 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
2700 operand *t = IC_RIGHT (ic);
2701 IC_RIGHT (ic) = IC_LEFT (ic);
2705 /* if both left & right are in bit
2707 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
2708 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
2714 /* if left in bit space & right literal */
2715 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
2716 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
2718 /* Can happen I guess */
2722 /* if I can do an increment instead
2723 of add then GOOD for ME */
2724 if (genPlusIncr (ic) == TRUE)
2727 emitDebug ("; genPlusIncr failed");
2729 size = getDataSize (IC_RESULT (ic));
2731 /* Special case when left and right are constant */
2732 if (isPair (AOP (IC_RESULT (ic))))
2736 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
2737 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
2743 sprintf (buffer, "#(%s + %s)", left, right);
2744 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
2749 if (isPair (AOP (IC_RIGHT (ic))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
2751 /* Fetch into HL then do the add */
2752 spillPair (PAIR_HL);
2753 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
2754 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
2759 ld hl,sp+n trashes C so we cant afford to do it during an
2760 add with stack based varibles. Worst case is:
2773 So you cant afford to load up hl if either left, right, or result
2774 is on the stack (*sigh*) The alt is:
2782 Combinations in here are:
2783 * If left or right are in bc then the loss is small - trap later
2784 * If the result is in bc then the loss is also small
2788 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
2789 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
2790 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
2792 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
2793 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
2794 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
2795 AOP_SIZE (IC_RIGHT (ic)) <= 2))
2797 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
2799 /* Swap left and right */
2800 operand *t = IC_RIGHT (ic);
2801 IC_RIGHT (ic) = IC_LEFT (ic);
2804 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
2806 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
2807 emit2 ("add hl,bc");
2811 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
2812 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
2813 emit2 ("add hl,de");
2815 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
2820 emitDebug ("; WARNING: This add is probably broken.\n");
2827 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
2829 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
2832 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2835 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2839 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
2842 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2845 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2847 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2851 freeAsmop (IC_LEFT (ic), NULL, ic);
2852 freeAsmop (IC_RIGHT (ic), NULL, ic);
2853 freeAsmop (IC_RESULT (ic), NULL, ic);
2857 /*-----------------------------------------------------------------*/
2858 /* genMinusDec :- does subtraction with deccrement if possible */
2859 /*-----------------------------------------------------------------*/
2861 genMinusDec (iCode * ic)
2863 unsigned int icount;
2864 unsigned int size = getDataSize (IC_RESULT (ic));
2866 /* will try to generate an increment */
2867 /* if the right side is not a literal we cannot */
2868 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
2871 /* if the literal value of the right hand side
2872 is greater than 4 then it is not worth it */
2873 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
2876 size = getDataSize (IC_RESULT (ic));
2878 /* if decrement 16 bits in register */
2879 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
2880 (size > 1) && isPair (AOP (IC_RESULT (ic))))
2883 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
2887 /* If result is a pair */
2888 if (isPair (AOP (IC_RESULT (ic))))
2890 movLeft2Result (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0);
2891 movLeft2Result (IC_LEFT (ic), 1, IC_RESULT (ic), 1, 0);
2893 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
2897 /* if increment 16 bits in register */
2898 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
2901 fetchPair (PAIR_HL, AOP (IC_RESULT (ic)));
2906 aopPut (AOP (IC_RESULT (ic)), "l", LSB);
2907 aopPut (AOP (IC_RESULT (ic)), "h", MSB16);
2913 /* if the sizes are greater than 1 then we cannot */
2914 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
2915 AOP_SIZE (IC_LEFT (ic)) > 1)
2918 /* we can if the aops of the left & result match or if they are in
2919 registers and the registers are the same */
2920 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2923 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
2930 /*-----------------------------------------------------------------*/
2931 /* genMinus - generates code for subtraction */
2932 /*-----------------------------------------------------------------*/
2934 genMinus (iCode * ic)
2936 int size, offset = 0;
2937 unsigned long lit = 0L;
2939 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2940 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
2941 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2943 /* special cases :- */
2944 /* if both left & right are in bit space */
2945 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
2946 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
2952 /* if I can do an decrement instead of subtract then GOOD for ME */
2953 if (genMinusDec (ic) == TRUE)
2956 size = getDataSize (IC_RESULT (ic));
2958 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
2963 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
2967 /* Same logic as genPlus */
2970 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
2971 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
2972 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
2974 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
2975 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
2976 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
2977 AOP_SIZE (IC_RIGHT (ic)) <= 2))
2979 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
2980 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
2982 if (left == PAIR_INVALID && right == PAIR_INVALID)
2987 else if (right == PAIR_INVALID)
2989 else if (left == PAIR_INVALID)
2992 fetchPair (left, AOP (IC_LEFT (ic)));
2993 /* Order is important. Right may be HL */
2994 fetchPair (right, AOP (IC_RIGHT (ic)));
2996 emit2 ("ld a,%s", _pairs[left].l);
2997 emit2 ("sub a,%s", _pairs[right].l);
2999 emit2 ("ld a,%s", _pairs[left].h);
3000 emit2 ("sbc a,%s", _pairs[right].h);
3002 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3003 aopPut (AOP (IC_RESULT (ic)), "e", 0);
3008 emitDebug ("; WARNING: This sub is probably broken.\n");
3013 /* if literal, add a,#-lit, else normal subb */
3016 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3017 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3021 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3024 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3028 /* first add without previous c */
3030 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
3032 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3034 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3037 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3038 AOP_SIZE (IC_LEFT (ic)) == 3 &&
3039 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3043 freeAsmop (IC_LEFT (ic), NULL, ic);
3044 freeAsmop (IC_RIGHT (ic), NULL, ic);
3045 freeAsmop (IC_RESULT (ic), NULL, ic);
3048 /*-----------------------------------------------------------------*/
3049 /* genMult - generates code for multiplication */
3050 /*-----------------------------------------------------------------*/
3052 genMult (iCode * ic)
3054 /* Shouldn't occur - all done through function calls */
3058 /*-----------------------------------------------------------------*/
3059 /* genDiv - generates code for division */
3060 /*-----------------------------------------------------------------*/
3064 /* Shouldn't occur - all done through function calls */
3068 /*-----------------------------------------------------------------*/
3069 /* genMod - generates code for division */
3070 /*-----------------------------------------------------------------*/
3074 /* Shouldn't occur - all done through function calls */
3078 /*-----------------------------------------------------------------*/
3079 /* genIfxJump :- will create a jump depending on the ifx */
3080 /*-----------------------------------------------------------------*/
3082 genIfxJump (iCode * ic, char *jval)
3087 /* if true label then we jump if condition
3091 jlbl = IC_TRUE (ic);
3092 if (!strcmp (jval, "a"))
3096 else if (!strcmp (jval, "c"))
3100 else if (!strcmp (jval, "nc"))
3106 /* The buffer contains the bit on A that we should test */
3112 /* false label is present */
3113 jlbl = IC_FALSE (ic);
3114 if (!strcmp (jval, "a"))
3118 else if (!strcmp (jval, "c"))
3122 else if (!strcmp (jval, "nc"))
3128 /* The buffer contains the bit on A that we should test */
3132 /* Z80 can do a conditional long jump */
3133 if (!strcmp (jval, "a"))
3137 else if (!strcmp (jval, "c"))
3140 else if (!strcmp (jval, "nc"))
3145 emit2 ("bit %s,a", jval);
3147 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
3149 /* mark the icode as generated */
3154 _getPairIdName (PAIR_ID id)
3156 return _pairs[id].name;
3159 /** Generic compare for > or <
3162 genCmp (operand * left, operand * right,
3163 operand * result, iCode * ifx, int sign)
3165 int size, offset = 0;
3166 unsigned long lit = 0L;
3167 bool swap_sense = FALSE;
3169 /* if left & right are bit variables */
3170 if (AOP_TYPE (left) == AOP_CRY &&
3171 AOP_TYPE (right) == AOP_CRY)
3173 /* Cant happen on the Z80 */
3178 /* subtract right from left if at the
3179 end the carry flag is set then we know that
3180 left is greater than right */
3181 size = max (AOP_SIZE (left), AOP_SIZE (right));
3183 /* if unsigned char cmp with lit, just compare */
3185 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
3187 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3190 emit2 ("xor a,!immedbyte", 0x80);
3191 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
3194 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3200 If the left or the right is a lit:
3201 Load -lit into HL, add to right via, check sense.
3203 if (IS_GB && size == 2 && (AOP_TYPE (right) == AOP_LIT || AOP_TYPE (left) == AOP_LIT))
3205 PAIR_ID id = PAIR_DE;
3206 asmop *lit = AOP (right);
3207 asmop *op = AOP (left);
3210 if (AOP_TYPE (left) == AOP_LIT)
3218 emit2 ("ld e,%s", aopGet (op, 0, 0));
3219 emit2 ("ld a,%s", aopGet (op, 1, 0));
3220 emit2 ("xor a,!immedbyte", 0x80);
3225 id = getPairId (op);
3226 if (id == PAIR_INVALID)
3228 fetchPair (PAIR_DE, op);
3232 spillPair (PAIR_HL);
3233 emit2 ("ld hl,%s", fetchLitSpecial (lit, TRUE, sign));
3234 emit2 ("add hl,%s", _getPairIdName (id));
3237 if (AOP_TYPE (right) == AOP_LIT)
3239 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3240 /* optimize if(x < 0) or if(x >= 0) */
3245 /* No sign so it's always false */
3250 /* Just load in the top most bit */
3251 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
3252 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
3254 genIfxJump (ifx, "7");
3265 /* First setup h and l contaning the top most bytes XORed */
3266 bool fDidXor = FALSE;
3267 if (AOP_TYPE (left) == AOP_LIT)
3269 unsigned long lit = (unsigned long)
3270 floatFromVal (AOP (left)->aopu.aop_lit);
3271 emit2 ("ld %s,!immedbyte", _fTmp[0],
3272 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3276 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
3277 emit2 ("xor a,!immedbyte", 0x80);
3278 emit2 ("ld %s,a", _fTmp[0]);
3281 if (AOP_TYPE (right) == AOP_LIT)
3283 unsigned long lit = (unsigned long)
3284 floatFromVal (AOP (right)->aopu.aop_lit);
3285 emit2 ("ld %s,!immedbyte", _fTmp[1],
3286 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3290 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
3291 emit2 ("xor a,!immedbyte", 0x80);
3292 emit2 ("ld %s,a", _fTmp[1]);
3304 /* Do a long subtract */
3307 _moveA (aopGet (AOP (left), offset, FALSE));
3309 if (sign && size == 0)
3311 emit2 ("ld a,%s", _fTmp[0]);
3312 emit2 ("sbc a,%s", _fTmp[1]);
3316 /* Subtract through, propagating the carry */
3317 emit2 ("sbc a,%s", aopGet (AOP (right), offset++, FALSE));
3324 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
3326 outBitCLong (result, swap_sense);
3330 /* if the result is used in the next
3331 ifx conditional branch then generate
3332 code a little differently */
3334 genIfxJump (ifx, swap_sense ? "nc" : "c");
3336 outBitCLong (result, swap_sense);
3337 /* leave the result in acc */
3341 /*-----------------------------------------------------------------*/
3342 /* genCmpGt :- greater than comparison */
3343 /*-----------------------------------------------------------------*/
3345 genCmpGt (iCode * ic, iCode * ifx)
3347 operand *left, *right, *result;
3348 sym_link *letype, *retype;
3351 left = IC_LEFT (ic);
3352 right = IC_RIGHT (ic);
3353 result = IC_RESULT (ic);
3355 letype = getSpec (operandType (left));
3356 retype = getSpec (operandType (right));
3357 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
3358 /* assign the amsops */
3359 aopOp (left, ic, FALSE, FALSE);
3360 aopOp (right, ic, FALSE, FALSE);
3361 aopOp (result, ic, TRUE, FALSE);
3363 genCmp (right, left, result, ifx, sign);
3365 freeAsmop (left, NULL, ic);
3366 freeAsmop (right, NULL, ic);
3367 freeAsmop (result, NULL, ic);
3370 /*-----------------------------------------------------------------*/
3371 /* genCmpLt - less than comparisons */
3372 /*-----------------------------------------------------------------*/
3374 genCmpLt (iCode * ic, iCode * ifx)
3376 operand *left, *right, *result;
3377 sym_link *letype, *retype;
3380 left = IC_LEFT (ic);
3381 right = IC_RIGHT (ic);
3382 result = IC_RESULT (ic);
3384 letype = getSpec (operandType (left));
3385 retype = getSpec (operandType (right));
3386 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
3388 /* assign the amsops */
3389 aopOp (left, ic, FALSE, FALSE);
3390 aopOp (right, ic, FALSE, FALSE);
3391 aopOp (result, ic, TRUE, FALSE);
3393 genCmp (left, right, result, ifx, sign);
3395 freeAsmop (left, NULL, ic);
3396 freeAsmop (right, NULL, ic);
3397 freeAsmop (result, NULL, ic);
3400 /*-----------------------------------------------------------------*/
3401 /* gencjneshort - compare and jump if not equal */
3402 /*-----------------------------------------------------------------*/
3404 gencjneshort (operand * left, operand * right, symbol * lbl)
3406 int size = max (AOP_SIZE (left), AOP_SIZE (right));
3408 unsigned long lit = 0L;
3410 /* Swap the left and right if it makes the computation easier */
3411 if (AOP_TYPE (left) == AOP_LIT)
3418 if (AOP_TYPE (right) == AOP_LIT)
3419 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3421 /* if the right side is a literal then anything goes */
3422 if (AOP_TYPE (right) == AOP_LIT &&
3423 AOP_TYPE (left) != AOP_DIR)
3427 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3434 emit2 ("or a,%s", aopGet (AOP (left), offset, FALSE));
3441 emit2 ("jp nz,!tlabel", lbl->key + 100);
3447 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3448 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
3451 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
3452 emit2 ("jp nz,!tlabel", lbl->key + 100);
3457 /* if the right side is in a register or in direct space or
3458 if the left is a pointer register & right is not */
3459 else if (AOP_TYPE (right) == AOP_REG ||
3460 AOP_TYPE (right) == AOP_DIR ||
3461 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
3465 _moveA (aopGet (AOP (left), offset, FALSE));
3466 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
3467 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
3469 emit2 ("jp nz,!tlabel", lbl->key + 100);
3472 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3473 emit2 ("jp nz,!tlabel", lbl->key + 100);
3480 /* right is a pointer reg need both a & b */
3481 /* PENDING: is this required? */
3484 _moveA (aopGet (AOP (right), offset, FALSE));
3485 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
3486 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
3492 /*-----------------------------------------------------------------*/
3493 /* gencjne - compare and jump if not equal */
3494 /*-----------------------------------------------------------------*/
3496 gencjne (operand * left, operand * right, symbol * lbl)
3498 symbol *tlbl = newiTempLabel (NULL);
3500 gencjneshort (left, right, lbl);
3503 emit2 ("ld a,!one");
3504 emit2 ("!shortjp !tlabel", tlbl->key + 100);
3505 emitLabel (lbl->key + 100);
3507 emitLabel (tlbl->key + 100);
3510 /*-----------------------------------------------------------------*/
3511 /* genCmpEq - generates code for equal to */
3512 /*-----------------------------------------------------------------*/
3514 genCmpEq (iCode * ic, iCode * ifx)
3516 operand *left, *right, *result;
3518 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
3519 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
3520 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
3522 emitDebug ("; genCmpEq: left %u, right %u, result %u\n", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
3524 /* Swap operands if it makes the operation easier. ie if:
3525 1. Left is a literal.
3527 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
3529 operand *t = IC_RIGHT (ic);
3530 IC_RIGHT (ic) = IC_LEFT (ic);
3534 if (ifx && !AOP_SIZE (result))
3537 /* if they are both bit variables */
3538 if (AOP_TYPE (left) == AOP_CRY &&
3539 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
3545 tlbl = newiTempLabel (NULL);
3546 gencjneshort (left, right, tlbl);
3549 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
3550 emitLabel (tlbl->key + 100);
3554 /* PENDING: do this better */
3555 symbol *lbl = newiTempLabel (NULL);
3556 emit2 ("!shortjp !tlabel", lbl->key + 100);
3557 emitLabel (tlbl->key + 100);
3558 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
3559 emitLabel (lbl->key + 100);
3562 /* mark the icode as generated */
3567 /* if they are both bit variables */
3568 if (AOP_TYPE (left) == AOP_CRY &&
3569 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
3575 gencjne (left, right, newiTempLabel (NULL));
3576 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
3582 genIfxJump (ifx, "a");
3585 /* if the result is used in an arithmetic operation
3586 then put the result in place */
3587 if (AOP_TYPE (result) != AOP_CRY)
3591 /* leave the result in acc */
3595 freeAsmop (left, NULL, ic);
3596 freeAsmop (right, NULL, ic);
3597 freeAsmop (result, NULL, ic);
3600 /*-----------------------------------------------------------------*/
3601 /* ifxForOp - returns the icode containing the ifx for operand */
3602 /*-----------------------------------------------------------------*/
3604 ifxForOp (operand * op, iCode * ic)
3606 /* if true symbol then needs to be assigned */
3607 if (IS_TRUE_SYMOP (op))
3610 /* if this has register type condition and
3611 the next instruction is ifx with the same operand
3612 and live to of the operand is upto the ifx only then */
3614 ic->next->op == IFX &&
3615 IC_COND (ic->next)->key == op->key &&
3616 OP_SYMBOL (op)->liveTo <= ic->next->seq)
3622 /*-----------------------------------------------------------------*/
3623 /* genAndOp - for && operation */
3624 /*-----------------------------------------------------------------*/
3626 genAndOp (iCode * ic)
3628 operand *left, *right, *result;
3631 /* note here that && operations that are in an if statement are
3632 taken away by backPatchLabels only those used in arthmetic
3633 operations remain */
3634 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
3635 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
3636 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
3638 /* if both are bit variables */
3639 if (AOP_TYPE (left) == AOP_CRY &&
3640 AOP_TYPE (right) == AOP_CRY)
3646 tlbl = newiTempLabel (NULL);
3648 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3650 emitLabel (tlbl->key + 100);
3654 freeAsmop (left, NULL, ic);
3655 freeAsmop (right, NULL, ic);
3656 freeAsmop (result, NULL, ic);
3659 /*-----------------------------------------------------------------*/
3660 /* genOrOp - for || operation */
3661 /*-----------------------------------------------------------------*/
3663 genOrOp (iCode * ic)
3665 operand *left, *right, *result;
3668 /* note here that || operations that are in an
3669 if statement are taken away by backPatchLabels
3670 only those used in arthmetic operations remain */
3671 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
3672 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
3673 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
3675 /* if both are bit variables */
3676 if (AOP_TYPE (left) == AOP_CRY &&
3677 AOP_TYPE (right) == AOP_CRY)
3683 tlbl = newiTempLabel (NULL);
3685 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3687 emitLabel (tlbl->key + 100);
3691 freeAsmop (left, NULL, ic);
3692 freeAsmop (right, NULL, ic);
3693 freeAsmop (result, NULL, ic);
3696 /*-----------------------------------------------------------------*/
3697 /* isLiteralBit - test if lit == 2^n */
3698 /*-----------------------------------------------------------------*/
3700 isLiteralBit (unsigned long lit)
3702 unsigned long pw[32] =
3703 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
3704 0x100L, 0x200L, 0x400L, 0x800L,
3705 0x1000L, 0x2000L, 0x4000L, 0x8000L,
3706 0x10000L, 0x20000L, 0x40000L, 0x80000L,
3707 0x100000L, 0x200000L, 0x400000L, 0x800000L,
3708 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
3709 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
3712 for (idx = 0; idx < 32; idx++)
3718 /*-----------------------------------------------------------------*/
3719 /* jmpTrueOrFalse - */
3720 /*-----------------------------------------------------------------*/
3722 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
3724 // ugly but optimized by peephole
3727 symbol *nlbl = newiTempLabel (NULL);
3728 emit2 ("jp !tlabel", nlbl->key + 100);
3729 emitLabel (tlbl->key + 100);
3730 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
3731 emitLabel (nlbl->key + 100);
3735 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
3736 emitLabel (tlbl->key + 100);
3741 /*-----------------------------------------------------------------*/
3742 /* genAnd - code for and */
3743 /*-----------------------------------------------------------------*/
3745 genAnd (iCode * ic, iCode * ifx)
3747 operand *left, *right, *result;
3748 int size, offset = 0;
3749 unsigned long lit = 0L;
3752 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
3753 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
3754 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
3757 emitDebug ("; Type res[%d] = l[%d]&r[%d]",
3759 AOP_TYPE (left), AOP_TYPE (right));
3760 emitDebug ("; Size res[%d] = l[%d]&r[%d]",
3762 AOP_SIZE (left), AOP_SIZE (right));
3765 /* if left is a literal & right is not then exchange them */
3766 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
3767 AOP_NEEDSACC (left))
3769 operand *tmp = right;
3774 /* if result = right then exchange them */
3775 if (sameRegs (AOP (result), AOP (right)))
3777 operand *tmp = right;
3782 /* if right is bit then exchange them */
3783 if (AOP_TYPE (right) == AOP_CRY &&
3784 AOP_TYPE (left) != AOP_CRY)
3786 operand *tmp = right;
3790 if (AOP_TYPE (right) == AOP_LIT)
3791 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3793 size = AOP_SIZE (result);
3795 if (AOP_TYPE (left) == AOP_CRY)
3801 // if(val & 0xZZ) - size = 0, ifx != FALSE -
3802 // bit = val & 0xZZ - size = 1, ifx = FALSE -
3803 if ((AOP_TYPE (right) == AOP_LIT) &&
3804 (AOP_TYPE (result) == AOP_CRY) &&
3805 (AOP_TYPE (left) != AOP_CRY))
3807 int posbit = isLiteralBit (lit);
3812 _moveA (aopGet (AOP (left), posbit >> 3, FALSE));
3817 emit2 ("mov c,acc.%d", posbit & 0x07);
3824 sprintf (buffer, "%d", posbit & 0x07);
3825 genIfxJump (ifx, buffer);
3836 symbol *tlbl = newiTempLabel (NULL);
3837 int sizel = AOP_SIZE (left);
3845 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
3847 _moveA (aopGet (AOP (left), offset, FALSE));
3849 if ((posbit = isLiteralBit (bytelit)) != 0)
3852 emit2 ("jb acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
3856 if (bytelit != 0x0FFL)
3858 aopGet (AOP (right), offset, FALSE));
3862 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3867 // bit = left & literal
3871 emit2 ("!tlabeldef", tlbl->key + 100);
3873 // if(left & literal)
3877 jmpTrueOrFalse (ifx, tlbl);
3885 /* if left is same as result */
3886 if (sameRegs (AOP (result), AOP (left)))
3888 for (; size--; offset++)
3890 if (AOP_TYPE (right) == AOP_LIT)
3892 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
3897 aopPut (AOP (result), "!zero", offset);
3900 _moveA (aopGet (AOP (left), offset, FALSE));
3902 aopGet (AOP (right), offset, FALSE));
3903 aopPut (AOP (left), "a", offset);
3910 if (AOP_TYPE (left) == AOP_ACC)
3916 _moveA (aopGet (AOP (left), offset, FALSE));
3918 aopGet (AOP (right), offset, FALSE));
3919 aopPut (AOP (left), "a", offset);
3926 // left & result in different registers
3927 if (AOP_TYPE (result) == AOP_CRY)
3933 for (; (size--); offset++)
3936 // result = left & right
3937 if (AOP_TYPE (right) == AOP_LIT)
3939 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
3941 aopPut (AOP (result),
3942 aopGet (AOP (left), offset, FALSE),
3946 else if (bytelit == 0)
3948 aopPut (AOP (result), "!zero", offset);
3952 // faster than result <- left, anl result,right
3953 // and better if result is SFR
3954 if (AOP_TYPE (left) == AOP_ACC)
3955 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
3958 _moveA (aopGet (AOP (left), offset, FALSE));
3960 aopGet (AOP (right), offset, FALSE));
3962 aopPut (AOP (result), "a", offset);
3969 freeAsmop (left, NULL, ic);
3970 freeAsmop (right, NULL, ic);
3971 freeAsmop (result, NULL, ic);
3974 /*-----------------------------------------------------------------*/
3975 /* genOr - code for or */
3976 /*-----------------------------------------------------------------*/
3978 genOr (iCode * ic, iCode * ifx)
3980 operand *left, *right, *result;
3981 int size, offset = 0;
3982 unsigned long lit = 0L;
3984 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
3985 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
3986 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
3989 emitDebug ("; Type res[%d] = l[%d]&r[%d]",
3991 AOP_TYPE (left), AOP_TYPE (right));
3992 emitDebug ("; Size res[%d] = l[%d]&r[%d]",
3994 AOP_SIZE (left), AOP_SIZE (right));
3997 /* if left is a literal & right is not then exchange them */
3998 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
3999 AOP_NEEDSACC (left))
4001 operand *tmp = right;
4006 /* if result = right then exchange them */
4007 if (sameRegs (AOP (result), AOP (right)))
4009 operand *tmp = right;
4014 /* if right is bit then exchange them */
4015 if (AOP_TYPE (right) == AOP_CRY &&
4016 AOP_TYPE (left) != AOP_CRY)
4018 operand *tmp = right;
4022 if (AOP_TYPE (right) == AOP_LIT)
4023 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4025 size = AOP_SIZE (result);
4027 if (AOP_TYPE (left) == AOP_CRY)
4033 if ((AOP_TYPE (right) == AOP_LIT) &&
4034 (AOP_TYPE (result) == AOP_CRY) &&
4035 (AOP_TYPE (left) != AOP_CRY))
4041 /* if left is same as result */
4042 if (sameRegs (AOP (result), AOP (left)))
4044 for (; size--; offset++)
4046 if (AOP_TYPE (right) == AOP_LIT)
4048 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4052 _moveA (aopGet (AOP (left), offset, FALSE));
4054 aopGet (AOP (right), offset, FALSE));
4055 aopPut (AOP (result), "a", offset);
4060 if (AOP_TYPE (left) == AOP_ACC)
4061 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4064 _moveA (aopGet (AOP (left), offset, FALSE));
4066 aopGet (AOP (right), offset, FALSE));
4067 aopPut (AOP (result), "a", offset);
4074 // left & result in different registers
4075 if (AOP_TYPE (result) == AOP_CRY)
4080 for (; (size--); offset++)
4083 // result = left & right
4084 if (AOP_TYPE (right) == AOP_LIT)
4086 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4088 aopPut (AOP (result),
4089 aopGet (AOP (left), offset, FALSE),
4094 // faster than result <- left, anl result,right
4095 // and better if result is SFR
4096 if (AOP_TYPE (left) == AOP_ACC)
4097 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4100 _moveA (aopGet (AOP (left), offset, FALSE));
4102 aopGet (AOP (right), offset, FALSE));
4104 aopPut (AOP (result), "a", offset);
4105 /* PENDING: something weird is going on here. Add exception. */
4106 if (AOP_TYPE (result) == AOP_ACC)
4112 freeAsmop (left, NULL, ic);
4113 freeAsmop (right, NULL, ic);
4114 freeAsmop (result, NULL, ic);
4117 /*-----------------------------------------------------------------*/
4118 /* genXor - code for xclusive or */
4119 /*-----------------------------------------------------------------*/
4121 genXor (iCode * ic, iCode * ifx)
4123 operand *left, *right, *result;
4124 int size, offset = 0;
4125 unsigned long lit = 0L;
4127 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4128 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4129 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4131 /* if left is a literal & right is not then exchange them */
4132 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4133 AOP_NEEDSACC (left))
4135 operand *tmp = right;
4140 /* if result = right then exchange them */
4141 if (sameRegs (AOP (result), AOP (right)))
4143 operand *tmp = right;
4148 /* if right is bit then exchange them */
4149 if (AOP_TYPE (right) == AOP_CRY &&
4150 AOP_TYPE (left) != AOP_CRY)
4152 operand *tmp = right;
4156 if (AOP_TYPE (right) == AOP_LIT)
4157 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4159 size = AOP_SIZE (result);
4161 if (AOP_TYPE (left) == AOP_CRY)
4167 if ((AOP_TYPE (right) == AOP_LIT) &&
4168 (AOP_TYPE (result) == AOP_CRY) &&
4169 (AOP_TYPE (left) != AOP_CRY))
4175 /* if left is same as result */
4176 if (sameRegs (AOP (result), AOP (left)))
4178 for (; size--; offset++)
4180 if (AOP_TYPE (right) == AOP_LIT)
4182 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4186 _moveA (aopGet (AOP (right), offset, FALSE));
4188 aopGet (AOP (left), offset, FALSE));
4189 aopPut (AOP (result), "a", offset);
4194 if (AOP_TYPE (left) == AOP_ACC)
4196 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4200 _moveA (aopGet (AOP (right), offset, FALSE));
4202 aopGet (AOP (left), offset, FALSE));
4203 aopPut (AOP (result), "a", 0);
4210 // left & result in different registers
4211 if (AOP_TYPE (result) == AOP_CRY)
4216 for (; (size--); offset++)
4219 // result = left & right
4220 if (AOP_TYPE (right) == AOP_LIT)
4222 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4224 aopPut (AOP (result),
4225 aopGet (AOP (left), offset, FALSE),
4230 // faster than result <- left, anl result,right
4231 // and better if result is SFR
4232 if (AOP_TYPE (left) == AOP_ACC)
4234 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4238 _moveA (aopGet (AOP (right), offset, FALSE));
4240 aopGet (AOP (left), offset, FALSE));
4242 aopPut (AOP (result), "a", offset);
4247 freeAsmop (left, NULL, ic);
4248 freeAsmop (right, NULL, ic);
4249 freeAsmop (result, NULL, ic);
4252 /*-----------------------------------------------------------------*/
4253 /* genInline - write the inline code out */
4254 /*-----------------------------------------------------------------*/
4256 genInline (iCode * ic)
4258 char *buffer, *bp, *bp1;
4260 _G.lines.isInline += (!options.asmpeep);
4262 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
4263 strcpy (buffer, IC_INLINE (ic));
4265 /* emit each line as a code */
4290 _G.lines.isInline -= (!options.asmpeep);
4294 /*-----------------------------------------------------------------*/
4295 /* genRRC - rotate right with carry */
4296 /*-----------------------------------------------------------------*/
4303 /*-----------------------------------------------------------------*/
4304 /* genRLC - generate code for rotate left with carry */
4305 /*-----------------------------------------------------------------*/
4312 /*-----------------------------------------------------------------*/
4313 /* genGetHbit - generates code get highest order bit */
4314 /*-----------------------------------------------------------------*/
4316 genGetHbit (iCode * ic)
4318 operand *left, *result;
4319 left = IC_LEFT (ic);
4320 result = IC_RESULT (ic);
4321 aopOp (left, ic, FALSE, FALSE);
4322 aopOp (result, ic, FALSE, FALSE);
4324 /* get the highest order byte into a */
4325 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4327 if (AOP_TYPE (result) == AOP_CRY)
4335 /* PENDING: For re-target. */
4341 freeAsmop (left, NULL, ic);
4342 freeAsmop (result, NULL, ic);
4346 emitRsh2 (asmop *aop, int size, int is_signed)
4352 const char *l = aopGet (aop, size, FALSE);
4355 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
4365 /*-----------------------------------------------------------------*/
4366 /* shiftR2Left2Result - shift right two bytes from left to result */
4367 /*-----------------------------------------------------------------*/
4369 shiftR2Left2Result (operand * left, int offl,
4370 operand * result, int offr,
4371 int shCount, int is_signed)
4374 symbol *tlbl, *tlbl1;
4376 movLeft2Result (left, offl, result, offr, 0);
4377 movLeft2Result (left, offl + 1, result, offr + 1, 0);
4379 /* if (AOP(result)->type == AOP_REG) { */
4381 tlbl = newiTempLabel (NULL);
4382 tlbl1 = newiTempLabel (NULL);
4384 /* Left is already in result - so now do the shift */
4389 emitRsh2 (AOP (result), size, is_signed);
4394 emit2 ("ld a,!immedbyte+1", shCount);
4395 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4396 emitLabel (tlbl->key + 100);
4398 emitRsh2 (AOP (result), size, is_signed);
4400 emitLabel (tlbl1->key + 100);
4402 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4406 /*-----------------------------------------------------------------*/
4407 /* shiftL2Left2Result - shift left two bytes from left to result */
4408 /*-----------------------------------------------------------------*/
4410 shiftL2Left2Result (operand * left, int offl,
4411 operand * result, int offr, int shCount)
4413 if (sameRegs (AOP (result), AOP (left)) &&
4414 ((offl + MSB16) == offr))
4420 /* Copy left into result */
4421 movLeft2Result (left, offl, result, offr, 0);
4422 movLeft2Result (left, offl + 1, result, offr + 1, 0);
4424 /* PENDING: for now just see if it'll work. */
4425 /*if (AOP(result)->type == AOP_REG) { */
4429 symbol *tlbl, *tlbl1;
4432 tlbl = newiTempLabel (NULL);
4433 tlbl1 = newiTempLabel (NULL);
4435 /* Left is already in result - so now do the shift */
4438 emit2 ("ld a,!immedbyte+1", shCount);
4439 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4440 emitLabel (tlbl->key + 100);
4446 l = aopGet (AOP (result), offset, FALSE);
4454 emitLabel (tlbl1->key + 100);
4456 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4461 /*-----------------------------------------------------------------*/
4462 /* AccRol - rotate left accumulator by known count */
4463 /*-----------------------------------------------------------------*/
4465 AccRol (int shCount)
4467 shCount &= 0x0007; // shCount : 0..7
4506 /*-----------------------------------------------------------------*/
4507 /* AccLsh - left shift accumulator by known count */
4508 /*-----------------------------------------------------------------*/
4510 AccLsh (int shCount)
4512 static const unsigned char SLMask[] =
4514 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
4523 else if (shCount == 2)
4530 /* rotate left accumulator */
4532 /* and kill the lower order bits */
4533 emit2 ("and a,!immedbyte", SLMask[shCount]);
4538 /*-----------------------------------------------------------------*/
4539 /* shiftL1Left2Result - shift left one byte from left to result */
4540 /*-----------------------------------------------------------------*/
4542 shiftL1Left2Result (operand * left, int offl,
4543 operand * result, int offr, int shCount)
4546 l = aopGet (AOP (left), offl, FALSE);
4548 /* shift left accumulator */
4550 aopPut (AOP (result), "a", offr);
4554 /*-----------------------------------------------------------------*/
4555 /* genlshTwo - left shift two bytes by known amount != 0 */
4556 /*-----------------------------------------------------------------*/
4558 genlshTwo (operand * result, operand * left, int shCount)
4560 int size = AOP_SIZE (result);
4562 wassert (size == 2);
4564 /* if shCount >= 8 */
4572 movLeft2Result (left, LSB, result, MSB16, 0);
4573 aopPut (AOP (result), "!zero", 0);
4574 shiftL1Left2Result (left, MSB16, result, MSB16, shCount);
4578 movLeft2Result (left, LSB, result, MSB16, 0);
4579 aopPut (AOP (result), "!zero", 0);
4584 aopPut (AOP (result), "!zero", LSB);
4587 /* 1 <= shCount <= 7 */
4596 shiftL2Left2Result (left, LSB, result, LSB, shCount);
4601 /*-----------------------------------------------------------------*/
4602 /* genlshOne - left shift a one byte quantity by known count */
4603 /*-----------------------------------------------------------------*/
4605 genlshOne (operand * result, operand * left, int shCount)
4607 shiftL1Left2Result (left, LSB, result, LSB, shCount);
4610 /*-----------------------------------------------------------------*/
4611 /* genLeftShiftLiteral - left shifting by known count */
4612 /*-----------------------------------------------------------------*/
4614 genLeftShiftLiteral (operand * left,
4619 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
4622 freeAsmop (right, NULL, ic);
4624 aopOp (left, ic, FALSE, FALSE);
4625 aopOp (result, ic, FALSE, FALSE);
4627 size = getSize (operandType (result));
4630 emitDebug ("; shift left result %d, left %d", size,
4634 /* I suppose that the left size >= result size */
4640 else if (shCount >= (size * 8))
4644 aopPut (AOP (result), "!zero", size);
4652 genlshOne (result, left, shCount);
4655 genlshTwo (result, left, shCount);
4658 wassertl (0, "Shifting of longs is currently unsupported");
4664 freeAsmop (left, NULL, ic);
4665 freeAsmop (result, NULL, ic);
4668 /*-----------------------------------------------------------------*/
4669 /* genLeftShift - generates code for left shifting */
4670 /*-----------------------------------------------------------------*/
4672 genLeftShift (iCode * ic)
4676 symbol *tlbl, *tlbl1;
4677 operand *left, *right, *result;
4679 right = IC_RIGHT (ic);
4680 left = IC_LEFT (ic);
4681 result = IC_RESULT (ic);
4683 aopOp (right, ic, FALSE, FALSE);
4685 /* if the shift count is known then do it
4686 as efficiently as possible */
4687 if (AOP_TYPE (right) == AOP_LIT)
4689 genLeftShiftLiteral (left, right, result, ic);
4693 /* shift count is unknown then we have to form a loop get the loop
4694 count in B : Note: we take only the lower order byte since
4695 shifting more that 32 bits make no sense anyway, ( the largest
4696 size of an object can be only 32 bits ) */
4697 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
4699 freeAsmop (right, NULL, ic);
4700 aopOp (left, ic, FALSE, FALSE);
4701 aopOp (result, ic, FALSE, FALSE);
4703 /* now move the left to the result if they are not the
4706 if (!sameRegs (AOP (left), AOP (result)))
4709 size = AOP_SIZE (result);
4713 l = aopGet (AOP (left), offset, FALSE);
4714 aopPut (AOP (result), l, offset);
4719 size = AOP_SIZE (result);
4723 l = aopGet (AOP (left), offset, FALSE);
4724 aopPut (AOP (result), l, offset);
4730 tlbl = newiTempLabel (NULL);
4731 size = AOP_SIZE (result);
4733 tlbl1 = newiTempLabel (NULL);
4735 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4736 emitLabel (tlbl->key + 100);
4737 l = aopGet (AOP (result), offset, FALSE);
4743 l = aopGet (AOP (result), offset++, FALSE);
4746 emitLabel (tlbl1->key + 100);
4748 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4750 freeAsmop (left, NULL, ic);
4751 freeAsmop (result, NULL, ic);
4754 /*-----------------------------------------------------------------*/
4755 /* genrshOne - left shift two bytes by known amount != 0 */
4756 /*-----------------------------------------------------------------*/
4758 genrshOne (operand * result, operand * left, int shCount, int is_signed)
4761 int size = AOP_SIZE (result);
4764 wassert (size == 1);
4765 wassert (shCount < 8);
4767 l = aopGet (AOP (left), 0, FALSE);
4771 if (AOP (result)->type == AOP_REG)
4773 aopPut (AOP (result), l, 0);
4774 l = aopGet (AOP (result), 0, FALSE);
4777 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
4785 emit2 ("%s a", is_signed ? "sra" : "srl");
4787 aopPut (AOP (result), "a", 0);
4791 /*-----------------------------------------------------------------*/
4792 /* AccRsh - right shift accumulator by known count */
4793 /*-----------------------------------------------------------------*/
4795 AccRsh (int shCount)
4797 static const unsigned char SRMask[] =
4799 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
4804 /* rotate right accumulator */
4805 AccRol (8 - shCount);
4806 /* and kill the higher order bits */
4807 emit2 ("and a,!immedbyte", SRMask[shCount]);
4811 /*-----------------------------------------------------------------*/
4812 /* shiftR1Left2Result - shift right one byte from left to result */
4813 /*-----------------------------------------------------------------*/
4815 shiftR1Left2Result (operand * left, int offl,
4816 operand * result, int offr,
4817 int shCount, int sign)
4819 _moveA (aopGet (AOP (left), offl, FALSE));
4828 aopPut (AOP (result), "a", offr);
4831 /*-----------------------------------------------------------------*/
4832 /* genrshTwo - right shift two bytes by known amount != 0 */
4833 /*-----------------------------------------------------------------*/
4835 genrshTwo (operand * result, operand * left,
4836 int shCount, int sign)
4838 /* if shCount >= 8 */
4844 shiftR1Left2Result (left, MSB16, result, LSB,
4849 movLeft2Result (left, MSB16, result, LSB, sign);
4851 aopPut (AOP (result), "!zero", 1);
4853 /* 1 <= shCount <= 7 */
4856 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
4860 /*-----------------------------------------------------------------*/
4861 /* genRightShiftLiteral - left shifting by known count */
4862 /*-----------------------------------------------------------------*/
4864 genRightShiftLiteral (operand * left,
4870 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
4873 freeAsmop (right, NULL, ic);
4875 aopOp (left, ic, FALSE, FALSE);
4876 aopOp (result, ic, FALSE, FALSE);
4878 size = getSize (operandType (result));
4880 emitDebug ("; shift right result %d, left %d", size,
4883 /* I suppose that the left size >= result size */
4889 else if (shCount >= (size * 8))
4891 aopPut (AOP (result), "!zero", size);
4897 genrshOne (result, left, shCount, sign);
4900 /* PENDING: sign support */
4901 genrshTwo (result, left, shCount, sign);
4904 wassertl (0, "Asked to shift right a long which should be a function call");
4907 wassertl (0, "Entered default case in right shift delegate");
4910 freeAsmop (left, NULL, ic);
4911 freeAsmop (result, NULL, ic);
4914 /*-----------------------------------------------------------------*/
4915 /* genRightShift - generate code for right shifting */
4916 /*-----------------------------------------------------------------*/
4918 genRightShift (iCode * ic)
4920 operand *right, *left, *result;
4922 int size, offset, first = 1;
4926 symbol *tlbl, *tlbl1;
4928 /* if signed then we do it the hard way preserve the
4929 sign bit moving it inwards */
4930 retype = getSpec (operandType (IC_RESULT (ic)));
4932 is_signed = !SPEC_USIGN (retype);
4934 /* signed & unsigned types are treated the same : i.e. the
4935 signed is NOT propagated inwards : quoting from the
4936 ANSI - standard : "for E1 >> E2, is equivalent to division
4937 by 2**E2 if unsigned or if it has a non-negative value,
4938 otherwise the result is implementation defined ", MY definition
4939 is that the sign does not get propagated */
4941 right = IC_RIGHT (ic);
4942 left = IC_LEFT (ic);
4943 result = IC_RESULT (ic);
4945 aopOp (right, ic, FALSE, FALSE);
4947 /* if the shift count is known then do it
4948 as efficiently as possible */
4949 if (AOP_TYPE (right) == AOP_LIT)
4951 genRightShiftLiteral (left, right, result, ic, is_signed);
4955 aopOp (left, ic, FALSE, FALSE);
4956 aopOp (result, ic, FALSE, FALSE);
4958 /* now move the left to the result if they are not the
4960 if (!sameRegs (AOP (left), AOP (result)) &&
4961 AOP_SIZE (result) > 1)
4964 size = AOP_SIZE (result);
4968 l = aopGet (AOP (left), offset, FALSE);
4969 aopPut (AOP (result), l, offset);
4974 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
4976 freeAsmop (right, NULL, ic);
4978 tlbl = newiTempLabel (NULL);
4979 tlbl1 = newiTempLabel (NULL);
4980 size = AOP_SIZE (result);
4983 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4984 emitLabel (tlbl->key + 100);
4987 l = aopGet (AOP (result), offset--, FALSE);
4990 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
4998 emitLabel (tlbl1->key + 100);
5000 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5002 freeAsmop (left, NULL, ic);
5003 freeAsmop (result, NULL, ic);
5006 /*-----------------------------------------------------------------*/
5007 /* genGenPointerGet - get value from generic pointer space */
5008 /*-----------------------------------------------------------------*/
5010 genGenPointerGet (operand * left,
5011 operand * result, iCode * ic)
5014 sym_link *retype = getSpec (operandType (result));
5020 aopOp (left, ic, FALSE, FALSE);
5021 aopOp (result, ic, FALSE, FALSE);
5023 if (isPair (AOP (left)) && AOP_SIZE (result) == 1)
5026 if (isPtrPair (AOP (left)))
5028 tsprintf (buffer, "!*pair", getPairName (AOP (left)));
5029 aopPut (AOP (result), buffer, 0);
5033 emit2 ("ld a,!*pair", getPairName (AOP (left)));
5034 aopPut (AOP (result), "a", 0);
5036 freeAsmop (left, NULL, ic);
5040 /* For now we always load into IY */
5041 /* if this is remateriazable */
5042 fetchPair (pair, AOP (left));
5044 /* so iy now contains the address */
5045 freeAsmop (left, NULL, ic);
5047 /* if bit then unpack */
5048 if (IS_BITVAR (retype))
5054 size = AOP_SIZE (result);
5059 /* PENDING: make this better */
5060 if (!IS_GB && AOP (result)->type == AOP_REG)
5062 aopPut (AOP (result), "!*hl", offset++);
5066 emit2 ("ld a,!*pair", _pairs[pair].name);
5067 aopPut (AOP (result), "a", offset++);
5071 emit2 ("inc %s", _pairs[pair].name);
5072 _G.pairs[pair].offset++;
5078 freeAsmop (result, NULL, ic);
5081 /*-----------------------------------------------------------------*/
5082 /* genPointerGet - generate code for pointer get */
5083 /*-----------------------------------------------------------------*/
5085 genPointerGet (iCode * ic)
5087 operand *left, *result;
5088 sym_link *type, *etype;
5090 left = IC_LEFT (ic);
5091 result = IC_RESULT (ic);
5093 /* depending on the type of pointer we need to
5094 move it to the correct pointer register */
5095 type = operandType (left);
5096 etype = getSpec (type);
5098 genGenPointerGet (left, result, ic);
5102 isRegOrLit (asmop * aop)
5104 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
5109 /*-----------------------------------------------------------------*/
5110 /* genGenPointerSet - stores the value into a pointer location */
5111 /*-----------------------------------------------------------------*/
5113 genGenPointerSet (operand * right,
5114 operand * result, iCode * ic)
5117 sym_link *retype = getSpec (operandType (right));
5118 PAIR_ID pairId = PAIR_HL;
5120 aopOp (result, ic, FALSE, FALSE);
5121 aopOp (right, ic, FALSE, FALSE);
5126 /* Handle the exceptions first */
5127 if (isPair (AOP (result)) && (AOP_SIZE (right) == 1))
5130 const char *l = aopGet (AOP (right), 0, FALSE);
5131 const char *pair = getPairName (AOP (result));
5132 if (canAssignToPtr (l) && isPtr (pair))
5134 emit2 ("ld !*pair,%s", pair, l);
5139 emit2 ("ld !*pair,a", pair);
5144 /* if the operand is already in dptr
5145 then we do nothing else we move the value to dptr */
5146 if (AOP_TYPE (result) != AOP_STR)
5148 fetchPair (pairId, AOP (result));
5150 /* so hl know contains the address */
5151 freeAsmop (result, NULL, ic);
5153 /* if bit then unpack */
5154 if (IS_BITVAR (retype))
5160 size = AOP_SIZE (right);
5165 const char *l = aopGet (AOP (right), offset, FALSE);
5166 if (isRegOrLit (AOP (right)) && !IS_GB)
5168 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
5173 emit2 ("ld !*pair,a", _pairs[pairId].name);
5177 emit2 ("inc %s", _pairs[pairId].name);
5178 _G.pairs[pairId].offset++;
5184 freeAsmop (right, NULL, ic);
5187 /*-----------------------------------------------------------------*/
5188 /* genPointerSet - stores the value into a pointer location */
5189 /*-----------------------------------------------------------------*/
5191 genPointerSet (iCode * ic)
5193 operand *right, *result;
5194 sym_link *type, *etype;
5196 right = IC_RIGHT (ic);
5197 result = IC_RESULT (ic);
5199 /* depending on the type of pointer we need to
5200 move it to the correct pointer register */
5201 type = operandType (result);
5202 etype = getSpec (type);
5204 genGenPointerSet (right, result, ic);
5207 /*-----------------------------------------------------------------*/
5208 /* genIfx - generate code for Ifx statement */
5209 /*-----------------------------------------------------------------*/
5211 genIfx (iCode * ic, iCode * popIc)
5213 operand *cond = IC_COND (ic);
5216 aopOp (cond, ic, FALSE, TRUE);
5218 /* get the value into acc */
5219 if (AOP_TYPE (cond) != AOP_CRY)
5223 /* the result is now in the accumulator */
5224 freeAsmop (cond, NULL, ic);
5226 /* if there was something to be popped then do it */
5230 /* if the condition is a bit variable */
5231 if (isbit && IS_ITEMP (cond) &&
5233 genIfxJump (ic, SPIL_LOC (cond)->rname);
5234 else if (isbit && !IS_ITEMP (cond))
5235 genIfxJump (ic, OP_SYMBOL (cond)->rname);
5237 genIfxJump (ic, "a");
5242 /*-----------------------------------------------------------------*/
5243 /* genAddrOf - generates code for address of */
5244 /*-----------------------------------------------------------------*/
5246 genAddrOf (iCode * ic)
5248 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
5250 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
5252 /* if the operand is on the stack then we
5253 need to get the stack offset of this
5260 if (sym->stack <= 0)
5262 emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset);
5266 emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
5273 emit2 ("ld de,!hashedstr", sym->rname);
5275 aopPut (AOP (IC_RESULT (ic)), "e", 0);
5276 aopPut (AOP (IC_RESULT (ic)), "d", 1);
5283 /* if it has an offset then we need to compute it */
5285 emit2 ("ld hl,#%d+%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset, _G.stack.param_offset);
5287 emit2 ("ld hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
5288 emit2 ("add hl,sp");
5292 emit2 ("ld hl,#%s", sym->rname);
5294 aopPut (AOP (IC_RESULT (ic)), "l", 0);
5295 aopPut (AOP (IC_RESULT (ic)), "h", 1);
5297 freeAsmop (IC_RESULT (ic), NULL, ic);
5300 /*-----------------------------------------------------------------*/
5301 /* genAssign - generate code for assignment */
5302 /*-----------------------------------------------------------------*/
5304 genAssign (iCode * ic)
5306 operand *result, *right;
5308 unsigned long lit = 0L;
5310 result = IC_RESULT (ic);
5311 right = IC_RIGHT (ic);
5314 /* Dont bother assigning if they are the same */
5315 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5317 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
5322 aopOp (right, ic, FALSE, FALSE);
5323 aopOp (result, ic, TRUE, FALSE);
5325 /* if they are the same registers */
5326 if (sameRegs (AOP (right), AOP (result)))
5328 emitDebug ("; (registers are the same)");
5332 /* if the result is a bit */
5333 if (AOP_TYPE (result) == AOP_CRY)
5339 size = AOP_SIZE (result);
5342 if (AOP_TYPE (right) == AOP_LIT)
5343 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5344 if (isPair (AOP (result)))
5346 fetchPair (getPairId (AOP (result)), AOP (right));
5348 else if ((size > 1) &&
5349 (AOP_TYPE (result) != AOP_REG) &&
5350 (AOP_TYPE (right) == AOP_LIT) &&
5351 !IS_FLOAT (operandType (right)) &&
5354 bool fXored = FALSE;
5356 /* Work from the top down.
5357 Done this way so that we can use the cached copy of 0
5358 in A for a fast clear */
5361 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
5363 if (!fXored && size > 1)
5370 aopPut (AOP (result), "a", offset);
5374 aopPut (AOP (result), "!zero", offset);
5378 aopPut (AOP (result),
5379 aopGet (AOP (right), offset, FALSE),
5384 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
5386 /* Special case. Load into a and d, then load out. */
5387 _moveA (aopGet (AOP (right), 0, FALSE));
5388 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
5389 aopPut (AOP (result), "a", 0);
5390 aopPut (AOP (result), "e", 1);
5396 /* PENDING: do this check better */
5397 if (requiresHL (AOP (right)) && requiresHL (AOP (result)))
5399 _moveA (aopGet (AOP (right), offset, FALSE));
5400 aopPut (AOP (result), "a", offset);
5403 aopPut (AOP (result),
5404 aopGet (AOP (right), offset, FALSE),
5411 freeAsmop (right, NULL, ic);
5412 freeAsmop (result, NULL, ic);
5415 /*-----------------------------------------------------------------*/
5416 /* genJumpTab - genrates code for jump table */
5417 /*-----------------------------------------------------------------*/
5419 genJumpTab (iCode * ic)
5424 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
5425 /* get the condition into accumulator */
5426 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
5429 emit2 ("ld e,%s", l);
5430 emit2 ("ld d,!zero");
5431 jtab = newiTempLabel (NULL);
5433 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
5434 emit2 ("add hl,de");
5435 emit2 ("add hl,de");
5436 emit2 ("add hl,de");
5437 freeAsmop (IC_JTCOND (ic), NULL, ic);
5441 emitLabel (jtab->key + 100);
5442 /* now generate the jump labels */
5443 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
5444 jtab = setNextItem (IC_JTLABELS (ic)))
5445 emit2 ("jp !tlabel", jtab->key + 100);
5448 /*-----------------------------------------------------------------*/
5449 /* genCast - gen code for casting */
5450 /*-----------------------------------------------------------------*/
5452 genCast (iCode * ic)
5454 operand *result = IC_RESULT (ic);
5455 sym_link *ctype = operandType (IC_LEFT (ic));
5456 operand *right = IC_RIGHT (ic);
5459 /* if they are equivalent then do nothing */
5460 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5463 aopOp (right, ic, FALSE, FALSE);
5464 aopOp (result, ic, FALSE, FALSE);
5466 /* if the result is a bit */
5467 if (AOP_TYPE (result) == AOP_CRY)
5472 /* if they are the same size : or less */
5473 if (AOP_SIZE (result) <= AOP_SIZE (right))
5476 /* if they are in the same place */
5477 if (sameRegs (AOP (right), AOP (result)))
5480 /* if they in different places then copy */
5481 size = AOP_SIZE (result);
5485 aopPut (AOP (result),
5486 aopGet (AOP (right), offset, FALSE),
5493 /* PENDING: should be OK. */
5495 /* if the result is of type pointer */
5502 /* so we now know that the size of destination is greater
5503 than the size of the source */
5504 /* we move to result for the size of source */
5505 size = AOP_SIZE (right);
5509 aopPut (AOP (result),
5510 aopGet (AOP (right), offset, FALSE),
5515 /* now depending on the sign of the destination */
5516 size = AOP_SIZE (result) - AOP_SIZE (right);
5517 /* Unsigned or not an integral type - right fill with zeros */
5518 if (SPEC_USIGN (ctype) || !IS_SPEC (ctype))
5521 aopPut (AOP (result), "!zero", offset++);
5525 /* we need to extend the sign :{ */
5526 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
5529 emitDebug ("; genCast: sign extend untested.");
5533 aopPut (AOP (result), "a", offset++);
5537 freeAsmop (right, NULL, ic);
5538 freeAsmop (result, NULL, ic);
5541 /*-----------------------------------------------------------------*/
5542 /* genReceive - generate code for a receive iCode */
5543 /*-----------------------------------------------------------------*/
5545 genReceive (iCode * ic)
5547 if (isOperandInFarSpace (IC_RESULT (ic)) &&
5548 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
5549 IS_TRUE_SYMOP (IC_RESULT (ic))))
5559 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
5560 size = AOP_SIZE(IC_RESULT(ic));
5562 for (i = 0; i < size; i++) {
5563 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
5567 freeAsmop (IC_RESULT (ic), NULL, ic);
5572 /** Maximum number of bytes to emit per line. */
5576 /** Context for the byte output chunker. */
5579 unsigned char buffer[DBEMIT_MAX_RUN];
5584 /** Flushes a byte chunker by writing out all in the buffer and
5588 _dbFlush(DBEMITCTX *self)
5595 sprintf(line, ".db 0x%02X", self->buffer[0]);
5597 for (i = 1; i < self->pos; i++)
5599 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
5606 /** Write out another byte, buffering until a decent line is
5610 _dbEmit(DBEMITCTX *self, int c)
5612 if (self->pos == DBEMIT_MAX_RUN)
5616 self->buffer[self->pos++] = c;
5619 /** Context for a simple run length encoder. */
5623 unsigned char buffer[128];
5625 /** runLen may be equivalent to pos. */
5631 RLE_CHANGE_COST = 4,
5635 /** Flush the buffer of a run length encoder by writing out the run or
5636 data that it currently contains.
5639 _rleCommit(RLECTX *self)
5645 memset(&db, 0, sizeof(db));
5647 emit2(".db %u", self->pos);
5649 for (i = 0; i < self->pos; i++)
5651 _dbEmit(&db, self->buffer[i]);
5660 Can get either a run or a block of random stuff.
5661 Only want to change state if a good run comes in or a run ends.
5662 Detecting run end is easy.
5665 Say initial state is in run, len zero, last zero. Then if you get a
5666 few zeros then something else then a short run will be output.
5667 Seems OK. While in run mode, keep counting. While in random mode,
5668 keep a count of the run. If run hits margin, output all up to run,
5669 restart, enter run mode.
5672 /** Add another byte into the run length encoder, flushing as
5673 required. The run length encoder uses the Amiga IFF style, where
5674 a block is prefixed by its run length. A positive length means
5675 the next n bytes pass straight through. A negative length means
5676 that the next byte is repeated -n times. A zero terminates the
5680 _rleAppend(RLECTX *self, int c)
5684 if (c != self->last)
5686 /* The run has stopped. See if it is worthwhile writing it out
5687 as a run. Note that the random data comes in as runs of
5690 if (self->runLen > RLE_CHANGE_COST)
5692 /* Yes, worthwhile. */
5693 /* Commit whatever was in the buffer. */
5695 emit2(".db -%u,0x%02X", self->runLen, self->last);
5699 /* Not worthwhile. Append to the end of the random list. */
5700 for (i = 0; i < self->runLen; i++)
5702 if (self->pos >= RLE_MAX_BLOCK)
5707 self->buffer[self->pos++] = self->last;
5715 if (self->runLen >= RLE_MAX_BLOCK)
5717 /* Commit whatever was in the buffer. */
5720 emit2 (".db -%u,0x%02X", self->runLen, self->last);
5728 _rleFlush(RLECTX *self)
5730 _rleAppend(self, -1);
5737 /** genArrayInit - Special code for initialising an array with constant
5741 genArrayInit (iCode * ic)
5745 int elementSize = 0, eIndex, i;
5746 unsigned val, lastVal;
5750 memset(&rle, 0, sizeof(rle));
5752 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
5754 if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD)
5756 /* Emit the support function call and the destination address. */
5757 emit2("call __initrleblock");
5758 emit2(".dw %s", aopGetWord (AOP(IC_LEFT(ic)), 0));
5762 wassertl (0, "Unexpected operand to genArrayInit.\n");
5765 type = operandType(IC_LEFT(ic));
5767 if (type && type->next)
5769 elementSize = getSize(type->next);
5773 wassertl (0, "Can't determine element size in genArrayInit.");
5776 iLoop = IC_ARRAYILIST(ic);
5777 lastVal = (unsigned)-1;
5779 /* Feed all the bytes into the run length encoder which will handle
5781 This works well for mixed char data, and for random int and long
5790 for (i = 0; i < ix; i++)
5792 for (eIndex = 0; eIndex < elementSize; eIndex++)
5794 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
5795 _rleAppend(&rle, val);
5800 iLoop = iLoop->next;
5804 /* Mark the end of the run. */
5807 freeAsmop (IC_LEFT(ic), NULL, ic);
5810 /*-----------------------------------------------------------------*/
5811 /* genZ80Code - generate code for Z80 based controllers */
5812 /*-----------------------------------------------------------------*/
5814 genZ80Code (iCode * lic)
5822 _fReturn = _gbz80_return;
5823 _fTmp = _gbz80_return;
5827 _fReturn = _z80_return;
5828 _fTmp = _z80_return;
5831 _G.lines.head = _G.lines.current = NULL;
5833 for (ic = lic; ic; ic = ic->next)
5836 if (cln != ic->lineno)
5838 emit2 ("; %s %d", ic->filename, ic->lineno);
5841 /* if the result is marked as
5842 spilt and rematerializable or code for
5843 this has already been generated then
5845 if (resultRemat (ic) || ic->generated)
5848 /* depending on the operation */
5852 emitDebug ("; genNot");
5857 emitDebug ("; genCpl");
5862 emitDebug ("; genUminus");
5867 emitDebug ("; genIpush");
5872 /* IPOP happens only when trying to restore a
5873 spilt live range, if there is an ifx statement
5874 following this pop then the if statement might
5875 be using some of the registers being popped which
5876 would destory the contents of the register so
5877 we need to check for this condition and handle it */
5879 ic->next->op == IFX &&
5880 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
5882 emitDebug ("; genIfx");
5883 genIfx (ic->next, ic);
5887 emitDebug ("; genIpop");
5893 emitDebug ("; genCall");
5898 emitDebug ("; genPcall");
5903 emitDebug ("; genFunction");
5908 emitDebug ("; genEndFunction");
5909 genEndFunction (ic);
5913 emitDebug ("; genRet");
5918 emitDebug ("; genLabel");
5923 emitDebug ("; genGoto");
5928 emitDebug ("; genPlus");
5933 emitDebug ("; genMinus");
5938 emitDebug ("; genMult");
5943 emitDebug ("; genDiv");
5948 emitDebug ("; genMod");
5953 emitDebug ("; genCmpGt");
5954 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
5958 emitDebug ("; genCmpLt");
5959 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
5966 /* note these two are xlated by algebraic equivalence
5967 during parsing SDCC.y */
5968 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
5969 "got '>=' or '<=' shouldn't have come here");
5973 emitDebug ("; genCmpEq");
5974 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
5978 emitDebug ("; genAndOp");
5983 emitDebug ("; genOrOp");
5988 emitDebug ("; genXor");
5989 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
5993 emitDebug ("; genOr");
5994 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
5998 emitDebug ("; genAnd");
5999 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
6003 emitDebug ("; genInline");
6008 emitDebug ("; genRRC");
6013 emitDebug ("; genRLC");
6018 emitDebug ("; genGetHBIT");
6023 emitDebug ("; genLeftShift");
6028 emitDebug ("; genRightShift");
6032 case GET_VALUE_AT_ADDRESS:
6033 emitDebug ("; genPointerGet");
6039 if (POINTER_SET (ic))
6041 emitDebug ("; genAssign (pointer)");
6046 emitDebug ("; genAssign");
6052 emitDebug ("; genIfx");
6057 emitDebug ("; genAddrOf");
6062 emitDebug ("; genJumpTab");
6067 emitDebug ("; genCast");
6072 emitDebug ("; genReceive");
6077 emitDebug ("; addSet");
6078 addSet (&_G.sendSet, ic);
6087 /* piCode(ic,stdout); */
6093 /* now we are ready to call the
6094 peep hole optimizer */
6095 if (!options.nopeep)
6096 peepHole (&_G.lines.head);
6098 /* This is unfortunate */
6099 /* now do the actual printing */
6101 FILE *fp = codeOutFile;
6102 if (isInHome () && codeOutFile == code->oFile)
6103 codeOutFile = home->oFile;
6104 printLine (_G.lines.head, codeOutFile);
6105 if (_G.flushStatics)
6108 _G.flushStatics = 0;
6117 _isPairUsed (iCode * ic, PAIR_ID pairId)
6123 if (bitVectBitValue (ic->rMask, D_IDX))
6125 if (bitVectBitValue (ic->rMask, E_IDX))