1 /*-------------------------------------------------------------------------
2 gen.c - Z80 specific code generator.
4 Michael Hope <michaelh@juju.net.nz> 2000
5 Based on the mcs51 generator -
6 Sandeep Dutta . sandeep.dutta@usa.net (1998)
7 and - Jean-Louis VERN.jlvern@writeme.com (1999)
9 This program is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 2, or (at your option) any
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 In other words, you are welcome to use, share and improve this program.
25 You are forbidden to forbid anyone else to use, share and improve
26 what you give them. Help stamp out software-hoarding!
28 -------------------------------------------------------------------------*/
31 Benchmarks on dhry.c 2.1 with 32766 loops and a 10ms clock:
33 Base with asm strcpy / strcmp / memcpy: 23198 141 1A14
34 Improved WORD push 22784 144 19AE
35 With label1 on 22694 144 197E
36 With label2 on 22743 144 198A
37 With label3 on 22776 144 1999
38 With label4 on 22776 144 1999
39 With all 'label' on 22661 144 196F
40 With loopInvariant on 20919 156 19AB
41 With loopInduction on Breaks 198B
42 With all working on 20796 158 196C
43 Slightly better genCmp(signed) 20597 159 195B
44 Better reg packing, first peephole 20038 163 1873
45 With assign packing 19281 165 1849
47 With reg params for mul and div 16234 202 162D
49 1. Starting again at 3 Aug 01 34965 93 219C
51 Includes long mul/div in code
52 2. Optimised memcpy for acc use 32102 102 226B
53 3. Optimised strcpy for acc use 27819 117 2237
54 3a Optimised memcpy fun
55 4. Optimised strcmp fun 21999 149 2294
56 5. Optimised strcmp further 21660 151 228C
57 6. Optimised memcpy by unroling 20885 157 2201
58 7. After turning loop induction on 19862 165 236D
59 8. Same as 7 but with more info
60 9. With asm optimised strings 17030 192 2223
62 10 and below are with asm strings off.
64 Apparent advantage of turning on regparams:
66 Decent case is push of a constant
67 - ld hl,#n; push hl: (10+11)*nargs
68 2. Cost of pull from stack
69 Using asm with ld hl, etc
70 - ld hl,#2; add hl,sp; (ld bc,(hl); hl+=2)*nargs
72 3. Cost of fixing stack
76 So cost is (10+11+7+6+7+10)*nargs+10+11
78 = 123 for mul, div, strcmp, strcpy
79 Saving of (98298+32766+32766+32766)*123 = 24181308
80 At 192 d/s for 682411768t, speed up to 199. Hmm.
88 #ifdef HAVE_SYS_ISA_DEFS_H
89 #include <sys/isa_defs.h>
93 #include "SDCCglobl.h"
94 #include "SDCCpeeph.h"
99 /* this is the down and dirty file with all kinds of kludgy & hacky
100 stuff. This is what it is all about CODE GENERATION for a specific MCU.
101 Some of the routines may be reusable, will have to see */
103 /* Z80 calling convention description.
104 Parameters are passed right to left. As the stack grows downwards,
105 the parameters are arranged in left to right in memory.
106 Parameters may be passed in the HL and DE registers with one
108 PENDING: What if the parameter is a long?
109 Everything is caller saves. i.e. the caller must save any registers
110 that it wants to preserve over the call.
111 The return value is returned in DEHL. DE is normally used as a
112 working register pair. Caller saves allows it to be used for a
114 va args functions do not use register parameters. All arguments
115 are passed on the stack.
116 IX is used as an index register to the top of the local variable
117 area. ix-0 is the top most local variable.
124 static char *_z80_return[] =
125 {"l", "h", "e", "d"};
126 static char *_gbz80_return[] =
127 {"e", "d", "l", "h"};
128 static char *_fReceive[] =
129 { "c", "b", "e", "d" };
131 static char **_fReturn;
134 extern FILE *codeOutFile;
153 } _pairs[NUM_PAIRS] = {
154 { "??1", "?2", "?3" },
159 { "iy", "iy.l?", "iy.h?" },
160 { "ix", "ix.l?", "ix.h?" }
164 #define ACC_NAME _pairs[PAIR_AF].h
166 #define RESULTONSTACK(x) \
167 (IC_RESULT(x) && IC_RESULT(x)->aop && \
168 IC_RESULT(x)->aop->type == AOP_STK )
199 const char *lastFunctionName;
205 /** TRUE if the registers have already been saved. */
218 static const char *aopGet (asmop * aop, int offset, bool bit16);
223 /* Clean up the line so that it is 'prettier' */
224 if (strchr (buf, ':'))
226 /* Is a label - cant do anything */
229 /* Change the first (and probably only) ' ' to a tab so
244 _vemit2 (const char *szFormat, va_list ap)
248 tvsprintf (buffer, szFormat, ap);
251 _G.lines.current = (_G.lines.current ?
252 connectLine (_G.lines.current, newLineNode (buffer)) :
253 (_G.lines.head = newLineNode (buffer)));
255 _G.lines.current->isInline = _G.lines.isInline;
259 emit2 (const char *szFormat,...)
263 va_start (ap, szFormat);
265 _vemit2 (szFormat, ap);
271 emitDebug (const char *szFormat,...)
277 va_start (ap, szFormat);
279 _vemit2 (szFormat, ap);
285 /*-----------------------------------------------------------------*/
286 /* emit2 - writes the code into a file : for now it is simple */
287 /*-----------------------------------------------------------------*/
289 _emit2 (const char *inst, const char *fmt,...)
292 char lb[INITIAL_INLINEASM];
299 sprintf (lb, "%s\t", inst);
300 vsprintf (lb + (strlen (lb)), fmt, ap);
303 vsprintf (lb, fmt, ap);
305 while (isspace (*lbp))
310 _G.lines.current = (_G.lines.current ?
311 connectLine (_G.lines.current, newLineNode (lb)) :
312 (_G.lines.head = newLineNode (lb)));
314 _G.lines.current->isInline = _G.lines.isInline;
319 _emitMove(const char *to, const char *from)
321 if (strcasecmp(to, from) != 0)
323 emit2("ld %s,%s", to, from);
328 // Could leave this to the peephole, but sometimes the peephole is inhibited.
333 _moveA(const char *moveFrom)
335 // Let the peephole optimiser take care of redundent loads
336 _emitMove(ACC_NAME, moveFrom);
346 getPairName (asmop * aop)
348 if (aop->type == AOP_REG)
350 switch (aop->aopu.aop_reg[0]->rIdx)
363 else if (aop->type == AOP_STR)
365 switch (*aop->aopu.aop_str[0])
383 getPairId (asmop * aop)
387 if (aop->type == AOP_REG)
389 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX) && (aop->aopu.aop_reg[1]->rIdx == B_IDX))
393 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX) && (aop->aopu.aop_reg[1]->rIdx == D_IDX))
397 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX) && (aop->aopu.aop_reg[1]->rIdx == H_IDX))
402 if (aop->type == AOP_STR)
404 if (!strcmp (aop->aopu.aop_str[0], "c") && !strcmp (aop->aopu.aop_str[1], "b"))
408 if (!strcmp (aop->aopu.aop_str[0], "e") && !strcmp (aop->aopu.aop_str[1], "d"))
412 if (!strcmp (aop->aopu.aop_str[0], "l") && !strcmp (aop->aopu.aop_str[1], "h"))
421 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
425 return (getPairId (aop) != PAIR_INVALID);
429 isPtrPair (asmop * aop)
431 PAIR_ID pairId = getPairId (aop);
442 /** Push a register pair onto the stack */
444 genPairPush (asmop * aop)
446 emit2 ("push %s", getPairName (aop));
450 /*-----------------------------------------------------------------*/
451 /* newAsmop - creates a new asmOp */
452 /*-----------------------------------------------------------------*/
454 newAsmop (short type)
458 aop = Safe_calloc (1, sizeof (asmop));
463 /*-----------------------------------------------------------------*/
464 /* aopForSym - for a true symbol */
465 /*-----------------------------------------------------------------*/
467 aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
474 wassert (sym->etype);
476 space = SPEC_OCLS (sym->etype);
478 /* if already has one */
482 /* Assign depending on the storage class */
483 if (sym->onStack || sym->iaccess)
485 emitDebug ("; AOP_STK for %s", sym->rname);
486 sym->aop = aop = newAsmop (AOP_STK);
487 aop->size = getSize (sym->type);
488 aop->aopu.aop_stk = sym->stack;
492 /* special case for a function */
493 if (IS_FUNC (sym->type))
495 sym->aop = aop = newAsmop (AOP_IMMD);
496 aop->aopu.aop_immd = Safe_calloc (1, strlen (sym->rname) + 1);
497 strcpy (aop->aopu.aop_immd, sym->rname);
504 /* if it is in direct space */
505 if (IN_REGSP (space) && !requires_a)
507 sym->aop = aop = newAsmop (AOP_SFR);
508 aop->aopu.aop_dir = sym->rname;
509 aop->size = getSize (sym->type);
510 emitDebug ("; AOP_SFR for %s", sym->rname);
515 /* only remaining is far space */
516 /* in which case DPTR gets the address */
519 emitDebug ("; AOP_HL for %s", sym->rname);
520 sym->aop = aop = newAsmop (AOP_HL);
524 sym->aop = aop = newAsmop (AOP_IY);
526 aop->size = getSize (sym->type);
527 aop->aopu.aop_dir = sym->rname;
529 /* if it is in code space */
530 if (IN_CODESPACE (space))
536 /*-----------------------------------------------------------------*/
537 /* aopForRemat - rematerialzes an object */
538 /*-----------------------------------------------------------------*/
540 aopForRemat (symbol * sym)
543 iCode *ic = sym->rematiCode;
544 asmop *aop = newAsmop (AOP_IMMD);
548 /* if plus or minus print the right hand side */
549 if (ic->op == '+' || ic->op == '-')
551 /* PENDING: for re-target */
552 sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
555 ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
558 /* we reached the end */
559 sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
563 aop->aopu.aop_immd = Safe_calloc (1, strlen (buffer) + 1);
564 strcpy (aop->aopu.aop_immd, buffer);
568 /*-----------------------------------------------------------------*/
569 /* regsInCommon - two operands have some registers in common */
570 /*-----------------------------------------------------------------*/
572 regsInCommon (operand * op1, operand * op2)
577 /* if they have registers in common */
578 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
581 sym1 = OP_SYMBOL (op1);
582 sym2 = OP_SYMBOL (op2);
584 if (sym1->nRegs == 0 || sym2->nRegs == 0)
587 for (i = 0; i < sym1->nRegs; i++)
593 for (j = 0; j < sym2->nRegs; j++)
598 if (sym2->regs[j] == sym1->regs[i])
606 /*-----------------------------------------------------------------*/
607 /* operandsEqu - equivalent */
608 /*-----------------------------------------------------------------*/
610 operandsEqu (operand * op1, operand * op2)
614 /* if they not symbols */
615 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
618 sym1 = OP_SYMBOL (op1);
619 sym2 = OP_SYMBOL (op2);
621 /* if both are itemps & one is spilt
622 and the other is not then false */
623 if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
624 sym1->isspilt != sym2->isspilt)
627 /* if they are the same */
631 if (strcmp (sym1->rname, sym2->rname) == 0)
635 /* if left is a tmp & right is not */
636 if (IS_ITEMP (op1) &&
639 (sym1->usl.spillLoc == sym2))
642 if (IS_ITEMP (op2) &&
646 (sym2->usl.spillLoc == sym1))
652 /*-----------------------------------------------------------------*/
653 /* sameRegs - two asmops have the same registers */
654 /*-----------------------------------------------------------------*/
656 sameRegs (asmop * aop1, asmop * aop2)
660 if (aop1->type == AOP_SFR ||
661 aop2->type == AOP_SFR)
667 if (aop1->type != AOP_REG ||
668 aop2->type != AOP_REG)
671 if (aop1->size != aop2->size)
674 for (i = 0; i < aop1->size; i++)
675 if (aop1->aopu.aop_reg[i] !=
676 aop2->aopu.aop_reg[i])
682 /*-----------------------------------------------------------------*/
683 /* aopOp - allocates an asmop for an operand : */
684 /*-----------------------------------------------------------------*/
686 aopOp (operand * op, iCode * ic, bool result, bool requires_a)
695 /* if this a literal */
696 if (IS_OP_LITERAL (op))
698 op->aop = aop = newAsmop (AOP_LIT);
699 aop->aopu.aop_lit = op->operand.valOperand;
700 aop->size = getSize (operandType (op));
704 /* if already has a asmop then continue */
708 /* if the underlying symbol has a aop */
709 if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
711 op->aop = OP_SYMBOL (op)->aop;
715 /* if this is a true symbol */
716 if (IS_TRUE_SYMOP (op))
718 op->aop = aopForSym (ic, OP_SYMBOL (op), result, requires_a);
722 /* this is a temporary : this has
728 e) can be a return use only */
730 sym = OP_SYMBOL (op);
732 /* if the type is a conditional */
733 if (sym->regType == REG_CND)
735 aop = op->aop = sym->aop = newAsmop (AOP_CRY);
740 /* if it is spilt then two situations
742 b) has a spill location */
743 if (sym->isspilt || sym->nRegs == 0)
745 /* rematerialize it NOW */
748 sym->aop = op->aop = aop =
750 aop->size = getSize (sym->type);
756 if (sym->accuse == ACCUSE_A)
758 aop = op->aop = sym->aop = newAsmop (AOP_ACC);
759 aop->size = getSize (sym->type);
760 wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
762 aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
764 else if (sym->accuse == ACCUSE_HL)
767 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
768 aop->size = getSize (sym->type);
769 wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
770 aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
771 aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
783 aop = op->aop = sym->aop = newAsmop (AOP_STR);
784 aop->size = getSize (sym->type);
785 for (i = 0; i < 4; i++)
786 aop->aopu.aop_str[i] = _fReturn[i];
790 /* else spill location */
791 sym->aop = op->aop = aop =
792 aopForSym (ic, sym->usl.spillLoc, result, requires_a);
793 aop->size = getSize (sym->type);
797 /* must be in a register */
798 sym->aop = op->aop = aop = newAsmop (AOP_REG);
799 aop->size = sym->nRegs;
800 for (i = 0; i < sym->nRegs; i++)
801 aop->aopu.aop_reg[i] = sym->regs[i];
804 /*-----------------------------------------------------------------*/
805 /* freeAsmop - free up the asmop given to an operand */
806 /*----------------------------------------------------------------*/
808 freeAsmop (operand * op, asmop * aaop, iCode * ic)
826 /* all other cases just dealloc */
832 OP_SYMBOL (op)->aop = NULL;
833 /* if the symbol has a spill */
835 SPIL_LOC (op)->aop = NULL;
841 isLitWord (asmop * aop)
843 /* if (aop->size != 2)
856 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
861 /* depending on type */
867 /* PENDING: for re-target */
869 tsprintf (s, "!hashedstr + %d", aop->aopu.aop_immd, offset);
871 tsprintf (s, "%s + %d", aop->aopu.aop_immd, offset);
877 value *val = aop->aopu.aop_lit;
878 /* if it is a float then it gets tricky */
879 /* otherwise it is fairly simple */
880 if (!IS_FLOAT (val->type))
882 unsigned long v = (unsigned long) floatFromVal (val);
888 else if (offset == 0)
894 wassertl(0, "Encountered an invalid offset while fetching a literal");
898 tsprintf (buffer, "!immedword", v);
900 tsprintf (buffer, "!constword", v);
902 return gc_strdup(buffer);
908 convertFloat (&f, floatFromVal (val));
910 tsprintf (buffer, "!immedword", f.w[offset / 2]);
912 tsprintf (buffer, "!constword", f.w[offset / 2]);
913 rs = Safe_calloc (1, strlen (buffer) + 1);
914 return strcpy (rs, buffer);
923 aopGetWord (asmop * aop, int offset)
925 return aopGetLitWordLong (aop, offset, TRUE);
929 isPtr (const char *s)
931 if (!strcmp (s, "hl"))
933 if (!strcmp (s, "ix"))
935 if (!strcmp (s, "iy"))
941 adjustPair (const char *pair, int *pold, int new)
947 emit2 ("inc %s", pair);
952 emit2 ("dec %s", pair);
958 spillPair (PAIR_ID pairId)
960 _G.pairs[pairId].last_type = AOP_INVALID;
961 _G.pairs[pairId].lit = NULL;
972 requiresHL (asmop * aop)
986 fetchLitSpecial (asmop * aop, bool negate, bool xor)
989 value *val = aop->aopu.aop_lit;
991 wassert (aop->type == AOP_LIT);
992 wassert (!IS_FLOAT (val->type));
994 v = (unsigned long) floatFromVal (val);
1002 tsprintf (buffer, "!immedword", v);
1003 return gc_strdup (buffer);
1007 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1010 const char *pair = _pairs[pairId].name;
1011 l = aopGetLitWordLong (left, offset, FALSE);
1012 wassert (l && pair);
1016 if (pairId == PAIR_HL || pairId == PAIR_IY)
1018 if (_G.pairs[pairId].last_type == left->type)
1020 if (_G.pairs[pairId].lit && !strcmp (_G.pairs[pairId].lit, l))
1022 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1024 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1027 if (pairId == PAIR_IY && abs (offset) < 127)
1034 _G.pairs[pairId].last_type = left->type;
1035 _G.pairs[pairId].lit = gc_strdup (l);
1036 _G.pairs[pairId].offset = offset;
1038 if (IS_GB && pairId == PAIR_DE && 0)
1040 if (_G.pairs[pairId].lit && !strcmp (_G.pairs[pairId].lit, l))
1042 if (abs (_G.pairs[pairId].offset - offset) < 3)
1044 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1048 _G.pairs[pairId].last_type = left->type;
1049 _G.pairs[pairId].lit = gc_strdup (l);
1050 _G.pairs[pairId].offset = offset;
1052 /* Both a lit on the right and a true symbol on the left */
1053 emit2 ("ld %s,!hashedstr", pair, l);
1057 fetchPairLong (PAIR_ID pairId, asmop * aop, int offset)
1059 /* if this is remateriazable */
1060 if (isLitWord (aop)) {
1061 fetchLitPair (pairId, aop, offset);
1064 /* we need to get it byte by byte */
1065 if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1066 aopGet (aop, offset, FALSE);
1067 switch (aop->size) {
1069 emit2 ("ld l,!*hl");
1070 emit2 ("ld h,!immedbyte", 0);
1074 emit2 ("ld h,!*hl");
1078 emitDebug ("; WARNING: mlh woosed out. This code is invalid.");
1081 else if (IS_Z80 && aop->type == AOP_IY) {
1082 /* Instead of fetching relative to IY, just grab directly
1083 from the address IY refers to */
1084 char *l = aopGetLitWordLong (aop, offset, FALSE);
1086 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1088 if (aop->size < 2) {
1089 emit2("ld %s,!zero", _pairs[pairId].h);
1093 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1094 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1096 /* PENDING: check? */
1097 if (pairId == PAIR_HL)
1098 spillPair (PAIR_HL);
1103 fetchPair (PAIR_ID pairId, asmop * aop)
1105 fetchPairLong (pairId, aop, 0);
1109 fetchHL (asmop * aop)
1111 fetchPair (PAIR_HL, aop);
1115 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1117 assert (pairId == PAIR_HL || pairId == PAIR_IY);
1122 fetchLitPair (pairId, aop, 0);
1125 fetchLitPair (pairId, aop, offset);
1126 _G.pairs[pairId].offset = offset;
1130 /* Doesnt include _G.stack.pushed */
1131 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1132 if (aop->aopu.aop_stk > 0)
1134 abso += _G.stack.param_offset;
1136 assert (pairId == PAIR_HL);
1137 /* In some cases we can still inc or dec hl */
1138 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1140 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1144 emit2 ("!ldahlsp", abso + _G.stack.pushed);
1146 _G.pairs[pairId].offset = abso;
1152 _G.pairs[pairId].last_type = aop->type;
1158 emit2 ("!tlabeldef", key);
1162 /*-----------------------------------------------------------------*/
1163 /* aopGet - for fetching value of the aop */
1164 /*-----------------------------------------------------------------*/
1166 aopGet (asmop * aop, int offset, bool bit16)
1170 /* offset is greater than size then zero */
1171 /* PENDING: this seems a bit screwed in some pointer cases. */
1172 if (offset > (aop->size - 1) &&
1173 aop->type != AOP_LIT)
1175 tsprintf (s, "!zero");
1176 return gc_strdup(s);
1179 /* depending on type */
1183 /* PENDING: re-target */
1185 tsprintf (s, "!immedwords", aop->aopu.aop_immd);
1190 tsprintf (s, "!bankimmeds", aop->aopu.aop_immd);
1193 tsprintf (s, "!msbimmeds", aop->aopu.aop_immd);
1196 tsprintf (s, "!lsbimmeds", aop->aopu.aop_immd);
1202 return gc_strdup(s);
1206 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1209 return gc_strdup(s);
1213 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1216 return gc_strdup(s);
1219 return aop->aopu.aop_reg[offset]->name;
1223 setupPair (PAIR_HL, aop, offset);
1224 tsprintf (s, "!*hl");
1226 return gc_strdup (s);
1230 setupPair (PAIR_IY, aop, offset);
1231 tsprintf (s, "!*iyx", offset);
1233 return gc_strdup(s);
1238 setupPair (PAIR_HL, aop, offset);
1239 tsprintf (s, "!*hl");
1243 if (aop->aopu.aop_stk >= 0)
1244 offset += _G.stack.param_offset;
1245 tsprintf (s, "!*ixx", aop->aopu.aop_stk + offset);
1248 return gc_strdup(s);
1260 tsprintf(s, "!zero");
1261 return gc_strdup(s);
1265 wassert (offset < 2);
1266 return aop->aopu.aop_str[offset];
1269 return aopLiteral (aop->aopu.aop_lit, offset);
1273 return aop->aopu.aop_str[offset];
1278 wassertl (0, "aopget got unsupported aop->type");
1283 isRegString (const char *s)
1285 if (!strcmp (s, "b") ||
1297 isConstant (const char *s)
1299 /* This is a bit of a hack... */
1300 return (*s == '#' || *s == '$');
1304 canAssignToPtr (const char *s)
1306 if (isRegString (s))
1313 /*-----------------------------------------------------------------*/
1314 /* aopPut - puts a string for a aop */
1315 /*-----------------------------------------------------------------*/
1317 aopPut (asmop * aop, const char *s, int offset)
1321 if (aop->size && offset > (aop->size - 1))
1323 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1324 "aopPut got offset > aop->size");
1329 tsprintf(buffer2, s);
1332 /* will assign value to value */
1333 /* depending on where it is ofcourse */
1339 if (strcmp (s, "a"))
1340 emit2 ("ld a,%s", s);
1341 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1346 if (strcmp (s, "a"))
1347 emit2 ("ld a,%s", s);
1348 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1352 if (!strcmp (s, "!*hl"))
1353 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1356 aop->aopu.aop_reg[offset]->name, s);
1361 setupPair (PAIR_IY, aop, offset);
1362 if (!canAssignToPtr (s))
1364 emit2 ("ld a,%s", s);
1365 emit2 ("ld !*iyx,a", offset);
1368 emit2 ("ld !*iyx,%s", offset, s);
1373 /* PENDING: for re-target */
1374 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1376 emit2 ("ld a,!*hl");
1379 setupPair (PAIR_HL, aop, offset);
1381 emit2 ("ld !*hl,%s", s);
1387 /* PENDING: re-target */
1388 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1390 emit2 ("ld a,!*hl");
1393 setupPair (PAIR_HL, aop, offset);
1394 if (!canAssignToPtr (s))
1396 emit2 ("ld a,%s", s);
1397 emit2 ("ld !*hl,a");
1400 emit2 ("ld !*hl,%s", s);
1404 if (aop->aopu.aop_stk >= 0)
1405 offset += _G.stack.param_offset;
1406 if (!canAssignToPtr (s))
1408 emit2 ("ld a,%s", s);
1409 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
1412 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
1417 /* if bit variable */
1418 if (!aop->aopu.aop_dir)
1425 /* In bit space but not in C - cant happen */
1432 if (strcmp (aop->aopu.aop_str[offset], s))
1434 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1440 if (!offset && (strcmp (s, "acc") == 0))
1445 emitDebug ("; Error aopPut AOP_ACC");
1449 if (strcmp (aop->aopu.aop_str[offset], s))
1450 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1455 wassert (offset < 2);
1456 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1460 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1461 "aopPut got unsupported aop->type");
1466 #define AOP(op) op->aop
1467 #define AOP_TYPE(op) AOP(op)->type
1468 #define AOP_SIZE(op) AOP(op)->size
1469 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
1472 commitPair (asmop * aop, PAIR_ID id)
1474 if (id == PAIR_HL && requiresHL (aop))
1478 aopPut (aop, "a", 0);
1479 aopPut (aop, "d", 1);
1483 aopPut (aop, _pairs[id].l, 0);
1484 aopPut (aop, _pairs[id].h, 1);
1488 /*-----------------------------------------------------------------*/
1489 /* getDataSize - get the operand data size */
1490 /*-----------------------------------------------------------------*/
1492 getDataSize (operand * op)
1495 size = AOP_SIZE (op);
1504 /*-----------------------------------------------------------------*/
1505 /* movLeft2Result - move byte from left to result */
1506 /*-----------------------------------------------------------------*/
1508 movLeft2Result (operand * left, int offl,
1509 operand * result, int offr, int sign)
1512 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
1514 l = aopGet (AOP (left), offl, FALSE);
1518 aopPut (AOP (result), l, offr);
1528 /** Put Acc into a register set
1531 outAcc (operand * result)
1534 size = getDataSize (result);
1537 aopPut (AOP (result), "a", 0);
1540 /* unsigned or positive */
1543 aopPut (AOP (result), "!zero", offset++);
1548 /** Take the value in carry and put it into a register
1551 outBitCLong (operand * result, bool swap_sense)
1553 /* if the result is bit */
1554 if (AOP_TYPE (result) == AOP_CRY)
1556 emitDebug ("; Note: outBitC form 1");
1557 aopPut (AOP (result), "blah", 0);
1561 emit2 ("ld a,!zero");
1564 emit2 ("xor a,!immedbyte", 1);
1570 outBitC (operand * result)
1572 outBitCLong (result, FALSE);
1575 /*-----------------------------------------------------------------*/
1576 /* toBoolean - emit code for orl a,operator(sizeop) */
1577 /*-----------------------------------------------------------------*/
1579 _toBoolean (operand * oper)
1581 int size = AOP_SIZE (oper);
1585 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
1588 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
1592 if (AOP (oper)->type != AOP_ACC)
1595 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
1600 /*-----------------------------------------------------------------*/
1601 /* genNot - generate code for ! operation */
1602 /*-----------------------------------------------------------------*/
1606 sym_link *optype = operandType (IC_LEFT (ic));
1608 /* assign asmOps to operand & result */
1609 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
1610 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1612 /* if in bit space then a special case */
1613 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1618 /* if type float then do float */
1619 if (IS_FLOAT (optype))
1624 _toBoolean (IC_LEFT (ic));
1629 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
1630 emit2 ("sub a,!one");
1631 outBitC (IC_RESULT (ic));
1633 /* release the aops */
1634 freeAsmop (IC_LEFT (ic), NULL, ic);
1635 freeAsmop (IC_RESULT (ic), NULL, ic);
1638 /*-----------------------------------------------------------------*/
1639 /* genCpl - generate code for complement */
1640 /*-----------------------------------------------------------------*/
1648 /* assign asmOps to operand & result */
1649 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1650 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1652 /* if both are in bit space then
1654 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1655 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1660 size = AOP_SIZE (IC_RESULT (ic));
1663 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
1666 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1669 /* release the aops */
1670 freeAsmop (IC_LEFT (ic), NULL, ic);
1671 freeAsmop (IC_RESULT (ic), NULL, ic);
1674 /*-----------------------------------------------------------------*/
1675 /* genUminus - unary minus code generation */
1676 /*-----------------------------------------------------------------*/
1678 genUminus (iCode * ic)
1681 sym_link *optype, *rtype;
1684 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1685 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1687 /* if both in bit space then special
1689 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1690 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1696 optype = operandType (IC_LEFT (ic));
1697 rtype = operandType (IC_RESULT (ic));
1699 /* if float then do float stuff */
1700 if (IS_FLOAT (optype))
1706 /* otherwise subtract from zero */
1707 size = AOP_SIZE (IC_LEFT (ic));
1712 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
1713 emit2 ("ld a,!zero");
1714 emit2 ("sbc a,%s", l);
1715 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1718 /* if any remaining bytes in the result */
1719 /* we just need to propagate the sign */
1720 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
1725 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1729 /* release the aops */
1730 freeAsmop (IC_LEFT (ic), NULL, ic);
1731 freeAsmop (IC_RESULT (ic), NULL, ic);
1735 _push (PAIR_ID pairId)
1737 emit2 ("push %s", _pairs[pairId].name);
1738 _G.stack.pushed += 2;
1742 _pop (PAIR_ID pairId)
1744 emit2 ("pop %s", _pairs[pairId].name);
1745 _G.stack.pushed -= 2;
1749 /*-----------------------------------------------------------------*/
1750 /* assignResultValue - */
1751 /*-----------------------------------------------------------------*/
1753 assignResultValue (operand * oper)
1755 int size = AOP_SIZE (oper);
1758 wassert (size <= 4);
1759 topInA = requiresHL (AOP (oper));
1763 wassert (size <= 2);
1765 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
1767 /* We do it the hard way here. */
1769 aopPut (AOP (oper), _fReturn[0], 0);
1770 aopPut (AOP (oper), _fReturn[1], 1);
1772 _G.stack.pushed -= 2;
1773 aopPut (AOP (oper), _fReturn[0], 2);
1774 aopPut (AOP (oper), _fReturn[1], 3);
1780 aopPut (AOP (oper), _fReturn[size], size);
1786 _saveRegsForCall(iCode *ic, int sendSetSize)
1789 o Stack parameters are pushed before this function enters
1790 o DE and BC may be used in this function.
1791 o HL and DE may be used to return the result.
1792 o HL and DE may be used to send variables.
1793 o DE and BC may be used to store the result value.
1794 o HL may be used in computing the sent value of DE
1795 o The iPushes for other parameters occur before any addSets
1797 Logic: (to be run inside the first iPush or if none, before sending)
1798 o Compute if DE and/or BC are in use over the call
1799 o Compute if DE is used in the send set
1800 o Compute if DE and/or BC are used to hold the result value
1801 o If (DE is used, or in the send set) and is not used in the result, push.
1802 o If BC is used and is not in the result, push
1804 o If DE is used in the send set, fetch
1805 o If HL is used in the send set, fetch
1809 if (_G.saves.saved == FALSE) {
1810 bool deInUse, bcInUse;
1812 bool bcInRet = FALSE, deInRet = FALSE;
1816 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
1820 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), z80_rUmaskForOp (IC_RESULT(ic)));
1824 /* Has no result, so in use is all of in use */
1829 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
1830 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
1832 deSending = (sendSetSize > 1);
1834 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
1836 if (bcInUse && bcInRet == FALSE) {
1838 _G.stack.pushedBC = TRUE;
1840 if (deInUse && deInRet == FALSE) {
1842 _G.stack.pushedDE = TRUE;
1845 _G.saves.saved = TRUE;
1848 /* Already saved. */
1852 /*-----------------------------------------------------------------*/
1853 /* genIpush - genrate code for pushing this gets a little complex */
1854 /*-----------------------------------------------------------------*/
1856 genIpush (iCode * ic)
1858 int size, offset = 0;
1861 /* if this is not a parm push : ie. it is spill push
1862 and spill push is always done on the local stack */
1865 wassertl(0, "Encountered an unsupported spill push.");
1869 if (_G.saves.saved == FALSE) {
1870 /* Caller saves, and this is the first iPush. */
1871 /* Scan ahead until we find the function that we are pushing parameters to.
1872 Count the number of addSets on the way to figure out what registers
1873 are used in the send set.
1876 iCode *walk = ic->next;
1879 if (walk->op == SEND) {
1882 else if (walk->op == CALL || walk->op == PCALL) {
1891 _saveRegsForCall(walk, nAddSets);
1894 /* Already saved by another iPush. */
1897 /* then do the push */
1898 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1900 size = AOP_SIZE (IC_LEFT (ic));
1902 if (isPair (AOP (IC_LEFT (ic))))
1904 _G.stack.pushed += 2;
1905 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
1911 fetchHL (AOP (IC_LEFT (ic)));
1913 spillPair (PAIR_HL);
1914 _G.stack.pushed += 2;
1919 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
1921 spillPair (PAIR_HL);
1922 _G.stack.pushed += 2;
1923 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 0);
1925 spillPair (PAIR_HL);
1926 _G.stack.pushed += 2;
1932 if (AOP (IC_LEFT (ic))->type == AOP_IY)
1934 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
1936 emit2 ("ld a,(%s)", l);
1940 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
1941 emit2 ("ld a,%s", l);
1949 freeAsmop (IC_LEFT (ic), NULL, ic);
1952 /*-----------------------------------------------------------------*/
1953 /* genIpop - recover the registers: can happen only for spilling */
1954 /*-----------------------------------------------------------------*/
1956 genIpop (iCode * ic)
1961 /* if the temp was not pushed then */
1962 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
1965 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1966 size = AOP_SIZE (IC_LEFT (ic));
1967 offset = (size - 1);
1968 if (isPair (AOP (IC_LEFT (ic))))
1970 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
1978 spillPair (PAIR_HL);
1979 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
1983 freeAsmop (IC_LEFT (ic), NULL, ic);
1986 /* This is quite unfortunate */
1988 setArea (int inHome)
1991 static int lastArea = 0;
1993 if (_G.in_home != inHome) {
1995 const char *sz = port->mem.code_name;
1996 port->mem.code_name = "HOME";
1997 emit2("!area", CODE_NAME);
1998 port->mem.code_name = sz;
2001 emit2("!area", CODE_NAME); */
2002 _G.in_home = inHome;
2013 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2017 symbol *sym = OP_SYMBOL (op);
2019 if (sym->isspilt || sym->nRegs == 0)
2022 aopOp (op, ic, FALSE, FALSE);
2025 if (aop->type == AOP_REG)
2028 for (i = 0; i < aop->size; i++)
2030 if (pairId == PAIR_DE)
2032 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2033 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2035 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2038 else if (pairId == PAIR_BC)
2040 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2041 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2043 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2053 freeAsmop (IC_LEFT (ic), NULL, ic);
2057 /** Emit the code for a call statement
2060 emitCall (iCode * ic, bool ispcall)
2062 sym_link *detype = getSpec (operandType (IC_LEFT (ic)));
2064 bitVect *rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
2066 /* if caller saves & we have not saved then */
2072 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2074 /* if send set is not empty then assign */
2079 int nSend = elementsInSet(_G.sendSet);
2080 bool swapped = FALSE;
2082 int _z80_sendOrder[] = {
2087 /* Check if the parameters are swapped. If so route through hl instead. */
2088 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2090 sic = setFirstItem(_G.sendSet);
2091 sic = setNextItem(_G.sendSet);
2093 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2094 /* The second send value is loaded from one the one that holds the first
2095 send, i.e. it is overwritten. */
2096 /* Cache the first in HL, and load the second from HL instead. */
2097 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2098 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2104 for (sic = setFirstItem (_G.sendSet); sic;
2105 sic = setNextItem (_G.sendSet))
2108 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2110 size = AOP_SIZE (IC_LEFT (sic));
2111 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2112 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2114 // PENDING: Mild hack
2115 if (swapped == TRUE && send == 1) {
2117 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2120 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2122 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2125 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2129 freeAsmop (IC_LEFT (sic), NULL, sic);
2136 if (IS_BANKEDCALL (detype))
2138 werror (W_INDIR_BANKED);
2140 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2142 if (isLitWord (AOP (IC_LEFT (ic))))
2144 emitDebug ("; Special case where the pCall is to a constant");
2145 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2149 symbol *rlbl = newiTempLabel (NULL);
2150 spillPair (PAIR_HL);
2151 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2153 _G.stack.pushed += 2;
2155 fetchHL (AOP (IC_LEFT (ic)));
2157 emit2 ("!tlabeldef", (rlbl->key + 100));
2158 _G.stack.pushed -= 2;
2160 freeAsmop (IC_LEFT (ic), NULL, ic);
2164 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2165 OP_SYMBOL (IC_LEFT (ic))->rname :
2166 OP_SYMBOL (IC_LEFT (ic))->name;
2167 if (IS_BANKEDCALL (detype))
2169 emit2 ("call banked_call");
2170 emit2 ("!dws", name);
2171 emit2 ("!dw !bankimmeds", name);
2176 emit2 ("call %s", name);
2181 /* Mark the regsiters as restored. */
2182 _G.saves.saved = FALSE;
2184 /* if we need assign a result value */
2185 if ((IS_ITEMP (IC_RESULT (ic)) &&
2186 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2187 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2188 IS_TRUE_SYMOP (IC_RESULT (ic)))
2191 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2193 assignResultValue (IC_RESULT (ic));
2195 freeAsmop (IC_RESULT (ic), NULL, ic);
2198 /* adjust the stack for parameters if required */
2201 int i = ic->parmBytes;
2203 _G.stack.pushed -= i;
2206 emit2 ("!ldaspsp", i);
2213 emit2 ("ld hl,#%d", i);
2214 emit2 ("add hl,sp");
2231 if (_G.stack.pushedDE)
2233 bool dInUse = bitVectBitValue(rInUse, D_IDX);
2234 bool eInUse = bitVectBitValue(rInUse, E_IDX);
2236 if (dInUse && eInUse)
2252 wassertl (0, "Neither D or E were in use but it was pushed.");
2254 _G.stack.pushedDE = FALSE;
2257 if (_G.stack.pushedBC)
2259 bool bInUse = bitVectBitValue(rInUse, B_IDX);
2260 bool cInUse = bitVectBitValue(rInUse, C_IDX);
2262 // If both B and C are used in the return value, then we won't get
2264 if (bInUse && cInUse)
2280 wassertl (0, "Neither B or C were in use but it was pushed.");
2282 _G.stack.pushedBC = FALSE;
2286 /*-----------------------------------------------------------------*/
2287 /* genCall - generates a call statement */
2288 /*-----------------------------------------------------------------*/
2290 genCall (iCode * ic)
2292 emitCall (ic, FALSE);
2295 /*-----------------------------------------------------------------*/
2296 /* genPcall - generates a call by pointer statement */
2297 /*-----------------------------------------------------------------*/
2299 genPcall (iCode * ic)
2301 emitCall (ic, TRUE);
2304 /*-----------------------------------------------------------------*/
2305 /* resultRemat - result is rematerializable */
2306 /*-----------------------------------------------------------------*/
2308 resultRemat (iCode * ic)
2310 if (SKIP_IC (ic) || ic->op == IFX)
2313 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2315 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2316 if (sym->remat && !POINTER_SET (ic))
2323 extern set *publics;
2325 /*-----------------------------------------------------------------*/
2326 /* genFunction - generated code for function entry */
2327 /*-----------------------------------------------------------------*/
2329 genFunction (iCode * ic)
2331 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2335 bool bcInUse = FALSE;
2336 bool deInUse = FALSE;
2339 setArea (IS_NONBANKED (sym->etype));
2341 /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
2344 _G.receiveOffset = 0;
2348 if (!IS_STATIC (sym->etype))
2350 addSetIfnotP (&publics, sym);
2354 /* Record the last function name for debugging. */
2355 _G.lastFunctionName = sym->rname;
2357 /* Create the function header */
2358 emit2 ("!functionheader", sym->name);
2359 /* PENDING: portability. */
2360 emit2 ("__%s_start:", sym->rname);
2361 emit2 ("!functionlabeldef", sym->rname);
2363 if (options.profile)
2365 emit2 ("!profileenter");
2368 fetype = getSpec (operandType (IC_LEFT (ic)));
2370 /* if critical function then turn interrupts off */
2371 if (SPEC_CRTCL (fetype))
2374 /* if this is an interrupt service routine then save all potentially used registers. */
2375 if (IS_ISR (sym->etype))
2380 /* PENDING: callee-save etc */
2382 _G.stack.param_offset = 0;
2385 /* Detect which registers are used. */
2389 for (i = 0; i < sym->regsUsed->size; i++)
2391 if (bitVectBitValue (sym->regsUsed, i))
2405 /* Other systems use DE as a temporary. */
2416 _G.stack.param_offset += 2;
2419 _G.stack.pushedBC = bcInUse;
2424 _G.stack.param_offset += 2;
2427 _G.stack.pushedDE = deInUse;
2430 /* adjust the stack for the function */
2431 _G.stack.last = sym->stack;
2434 emit2 ("!enterx", sym->stack);
2437 _G.stack.offset = sym->stack;
2440 /*-----------------------------------------------------------------*/
2441 /* genEndFunction - generates epilogue for functions */
2442 /*-----------------------------------------------------------------*/
2444 genEndFunction (iCode * ic)
2446 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2448 if (IS_ISR (sym->etype))
2454 if (SPEC_CRTCL (sym->etype))
2457 /* PENDING: calleeSave */
2459 if (_G.stack.offset)
2461 emit2 ("!leavex", _G.stack.offset);
2469 if (_G.stack.pushedDE)
2472 _G.stack.pushedDE = FALSE;
2475 if (_G.stack.pushedDE)
2478 _G.stack.pushedDE = FALSE;
2482 if (options.profile)
2484 emit2 ("!profileexit");
2488 /* Both baned and non-banked just ret */
2491 /* PENDING: portability. */
2492 emit2 ("__%s_end:", sym->rname);
2494 _G.flushStatics = 1;
2495 _G.stack.pushed = 0;
2496 _G.stack.offset = 0;
2499 /*-----------------------------------------------------------------*/
2500 /* genRet - generate code for return statement */
2501 /*-----------------------------------------------------------------*/
2506 /* Errk. This is a hack until I can figure out how
2507 to cause dehl to spill on a call */
2508 int size, offset = 0;
2510 /* if we have no return value then
2511 just generate the "ret" */
2515 /* we have something to return then
2516 move the return value into place */
2517 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2518 size = AOP_SIZE (IC_LEFT (ic));
2520 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
2524 emit2 ("ld de,%s", l);
2528 emit2 ("ld hl,%s", l);
2533 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
2535 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
2536 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
2542 l = aopGet (AOP (IC_LEFT (ic)), offset,
2544 if (strcmp (_fReturn[offset], l))
2545 emit2 ("ld %s,%s", _fReturn[offset++], l);
2549 freeAsmop (IC_LEFT (ic), NULL, ic);
2552 /* generate a jump to the return label
2553 if the next is not the return statement */
2554 if (!(ic->next && ic->next->op == LABEL &&
2555 IC_LABEL (ic->next) == returnLabel))
2557 emit2 ("jp !tlabel", returnLabel->key + 100);
2560 /*-----------------------------------------------------------------*/
2561 /* genLabel - generates a label */
2562 /*-----------------------------------------------------------------*/
2564 genLabel (iCode * ic)
2566 /* special case never generate */
2567 if (IC_LABEL (ic) == entryLabel)
2570 emitLabel (IC_LABEL (ic)->key + 100);
2573 /*-----------------------------------------------------------------*/
2574 /* genGoto - generates a ljmp */
2575 /*-----------------------------------------------------------------*/
2577 genGoto (iCode * ic)
2579 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
2582 /*-----------------------------------------------------------------*/
2583 /* genPlusIncr :- does addition with increment if possible */
2584 /*-----------------------------------------------------------------*/
2586 genPlusIncr (iCode * ic)
2588 unsigned int icount;
2589 unsigned int size = getDataSize (IC_RESULT (ic));
2590 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
2592 /* will try to generate an increment */
2593 /* if the right side is not a literal
2595 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
2598 emitDebug ("; genPlusIncr");
2600 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
2602 /* If result is a pair */
2603 if (resultId != PAIR_INVALID)
2605 if (isLitWord (AOP (IC_LEFT (ic))))
2607 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
2610 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
2612 fetchPair (resultId, AOP (IC_RIGHT (ic)));
2613 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
2619 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2623 movLeft2Result (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0);
2624 movLeft2Result (IC_LEFT (ic), 1, IC_RESULT (ic), 1, 0);
2628 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
2633 /* if the literal value of the right hand side
2634 is greater than 4 then it is not worth it */
2638 /* if increment 16 bits in register */
2639 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
2645 symbol *tlbl = NULL;
2646 tlbl = newiTempLabel (NULL);
2649 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
2652 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
2655 emitLabel (tlbl->key + 100);
2659 /* if the sizes are greater than 1 then we cannot */
2660 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
2661 AOP_SIZE (IC_LEFT (ic)) > 1)
2664 /* we can if the aops of the left & result match or
2665 if they are in registers and the registers are the
2667 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2671 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
2679 /*-----------------------------------------------------------------*/
2680 /* outBitAcc - output a bit in acc */
2681 /*-----------------------------------------------------------------*/
2683 outBitAcc (operand * result)
2685 symbol *tlbl = newiTempLabel (NULL);
2686 /* if the result is a bit */
2687 if (AOP_TYPE (result) == AOP_CRY)
2693 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
2694 emit2 ("ld a,!one");
2695 emitLabel (tlbl->key + 100);
2700 /*-----------------------------------------------------------------*/
2701 /* genPlus - generates code for addition */
2702 /*-----------------------------------------------------------------*/
2704 genPlus (iCode * ic)
2706 int size, offset = 0;
2708 /* special cases :- */
2710 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2711 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
2712 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2714 /* Swap the left and right operands if:
2716 if literal, literal on the right or
2717 if left requires ACC or right is already
2720 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
2721 (AOP_NEEDSACC (IC_LEFT (ic))) ||
2722 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
2724 operand *t = IC_RIGHT (ic);
2725 IC_RIGHT (ic) = IC_LEFT (ic);
2729 /* if both left & right are in bit
2731 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
2732 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
2738 /* if left in bit space & right literal */
2739 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
2740 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
2742 /* Can happen I guess */
2746 /* if I can do an increment instead
2747 of add then GOOD for ME */
2748 if (genPlusIncr (ic) == TRUE)
2751 emitDebug ("; genPlusIncr failed");
2753 size = getDataSize (IC_RESULT (ic));
2755 /* Special case when left and right are constant */
2756 if (isPair (AOP (IC_RESULT (ic))))
2760 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
2761 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
2767 sprintf (buffer, "#(%s + %s)", left, right);
2768 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
2773 if (isPair (AOP (IC_RIGHT (ic))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
2775 /* Fetch into HL then do the add */
2776 spillPair (PAIR_HL);
2777 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
2778 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
2783 ld hl,sp+n trashes C so we cant afford to do it during an
2784 add with stack based varibles. Worst case is:
2797 So you cant afford to load up hl if either left, right, or result
2798 is on the stack (*sigh*) The alt is:
2806 Combinations in here are:
2807 * If left or right are in bc then the loss is small - trap later
2808 * If the result is in bc then the loss is also small
2812 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
2813 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
2814 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
2816 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
2817 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
2818 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
2819 AOP_SIZE (IC_RIGHT (ic)) <= 2))
2821 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
2823 /* Swap left and right */
2824 operand *t = IC_RIGHT (ic);
2825 IC_RIGHT (ic) = IC_LEFT (ic);
2828 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
2830 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
2831 emit2 ("add hl,bc");
2835 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
2836 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
2837 emit2 ("add hl,de");
2839 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
2844 emitDebug ("; WARNING: This add is probably broken.\n");
2851 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
2853 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
2856 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2859 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2863 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
2866 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2869 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2871 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2875 freeAsmop (IC_LEFT (ic), NULL, ic);
2876 freeAsmop (IC_RIGHT (ic), NULL, ic);
2877 freeAsmop (IC_RESULT (ic), NULL, ic);
2881 /*-----------------------------------------------------------------*/
2882 /* genMinusDec :- does subtraction with deccrement if possible */
2883 /*-----------------------------------------------------------------*/
2885 genMinusDec (iCode * ic)
2887 unsigned int icount;
2888 unsigned int size = getDataSize (IC_RESULT (ic));
2890 /* will try to generate an increment */
2891 /* if the right side is not a literal we cannot */
2892 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
2895 /* if the literal value of the right hand side
2896 is greater than 4 then it is not worth it */
2897 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
2900 size = getDataSize (IC_RESULT (ic));
2902 /* if decrement 16 bits in register */
2903 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
2904 (size > 1) && isPair (AOP (IC_RESULT (ic))))
2907 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
2911 /* If result is a pair */
2912 if (isPair (AOP (IC_RESULT (ic))))
2914 movLeft2Result (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0);
2915 movLeft2Result (IC_LEFT (ic), 1, IC_RESULT (ic), 1, 0);
2917 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
2921 /* if increment 16 bits in register */
2922 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
2925 fetchPair (PAIR_HL, AOP (IC_RESULT (ic)));
2930 aopPut (AOP (IC_RESULT (ic)), "l", LSB);
2931 aopPut (AOP (IC_RESULT (ic)), "h", MSB16);
2937 /* if the sizes are greater than 1 then we cannot */
2938 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
2939 AOP_SIZE (IC_LEFT (ic)) > 1)
2942 /* we can if the aops of the left & result match or if they are in
2943 registers and the registers are the same */
2944 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2947 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
2954 /*-----------------------------------------------------------------*/
2955 /* genMinus - generates code for subtraction */
2956 /*-----------------------------------------------------------------*/
2958 genMinus (iCode * ic)
2960 int size, offset = 0;
2961 unsigned long lit = 0L;
2963 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2964 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
2965 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2967 /* special cases :- */
2968 /* if both left & right are in bit space */
2969 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
2970 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
2976 /* if I can do an decrement instead of subtract then GOOD for ME */
2977 if (genMinusDec (ic) == TRUE)
2980 size = getDataSize (IC_RESULT (ic));
2982 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
2987 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
2991 /* Same logic as genPlus */
2994 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
2995 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
2996 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
2998 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
2999 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3000 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3001 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3003 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3004 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3006 if (left == PAIR_INVALID && right == PAIR_INVALID)
3011 else if (right == PAIR_INVALID)
3013 else if (left == PAIR_INVALID)
3016 fetchPair (left, AOP (IC_LEFT (ic)));
3017 /* Order is important. Right may be HL */
3018 fetchPair (right, AOP (IC_RIGHT (ic)));
3020 emit2 ("ld a,%s", _pairs[left].l);
3021 emit2 ("sub a,%s", _pairs[right].l);
3023 emit2 ("ld a,%s", _pairs[left].h);
3024 emit2 ("sbc a,%s", _pairs[right].h);
3026 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3027 aopPut (AOP (IC_RESULT (ic)), "e", 0);
3032 emitDebug ("; WARNING: This sub is probably broken.\n");
3037 /* if literal, add a,#-lit, else normal subb */
3040 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3041 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3045 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3048 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3052 /* first add without previous c */
3054 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
3056 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3058 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3061 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3062 AOP_SIZE (IC_LEFT (ic)) == 3 &&
3063 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3067 freeAsmop (IC_LEFT (ic), NULL, ic);
3068 freeAsmop (IC_RIGHT (ic), NULL, ic);
3069 freeAsmop (IC_RESULT (ic), NULL, ic);
3072 /*-----------------------------------------------------------------*/
3073 /* genMult - generates code for multiplication */
3074 /*-----------------------------------------------------------------*/
3076 genMult (iCode * ic)
3078 /* Shouldn't occur - all done through function calls */
3082 /*-----------------------------------------------------------------*/
3083 /* genDiv - generates code for division */
3084 /*-----------------------------------------------------------------*/
3088 /* Shouldn't occur - all done through function calls */
3092 /*-----------------------------------------------------------------*/
3093 /* genMod - generates code for division */
3094 /*-----------------------------------------------------------------*/
3098 /* Shouldn't occur - all done through function calls */
3102 /*-----------------------------------------------------------------*/
3103 /* genIfxJump :- will create a jump depending on the ifx */
3104 /*-----------------------------------------------------------------*/
3106 genIfxJump (iCode * ic, char *jval)
3111 /* if true label then we jump if condition
3115 jlbl = IC_TRUE (ic);
3116 if (!strcmp (jval, "a"))
3120 else if (!strcmp (jval, "c"))
3124 else if (!strcmp (jval, "nc"))
3130 /* The buffer contains the bit on A that we should test */
3136 /* false label is present */
3137 jlbl = IC_FALSE (ic);
3138 if (!strcmp (jval, "a"))
3142 else if (!strcmp (jval, "c"))
3146 else if (!strcmp (jval, "nc"))
3152 /* The buffer contains the bit on A that we should test */
3156 /* Z80 can do a conditional long jump */
3157 if (!strcmp (jval, "a"))
3161 else if (!strcmp (jval, "c"))
3164 else if (!strcmp (jval, "nc"))
3169 emit2 ("bit %s,a", jval);
3171 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
3173 /* mark the icode as generated */
3178 _getPairIdName (PAIR_ID id)
3180 return _pairs[id].name;
3183 /** Generic compare for > or <
3186 genCmp (operand * left, operand * right,
3187 operand * result, iCode * ifx, int sign)
3189 int size, offset = 0;
3190 unsigned long lit = 0L;
3191 bool swap_sense = FALSE;
3193 /* if left & right are bit variables */
3194 if (AOP_TYPE (left) == AOP_CRY &&
3195 AOP_TYPE (right) == AOP_CRY)
3197 /* Cant happen on the Z80 */
3202 /* subtract right from left if at the
3203 end the carry flag is set then we know that
3204 left is greater than right */
3205 size = max (AOP_SIZE (left), AOP_SIZE (right));
3207 /* if unsigned char cmp with lit, just compare */
3209 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
3211 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3214 emit2 ("xor a,!immedbyte", 0x80);
3215 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
3218 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3224 If the left or the right is a lit:
3225 Load -lit into HL, add to right via, check sense.
3227 if (IS_GB && size == 2 && (AOP_TYPE (right) == AOP_LIT || AOP_TYPE (left) == AOP_LIT))
3229 PAIR_ID id = PAIR_DE;
3230 asmop *lit = AOP (right);
3231 asmop *op = AOP (left);
3234 if (AOP_TYPE (left) == AOP_LIT)
3242 emit2 ("ld e,%s", aopGet (op, 0, 0));
3243 emit2 ("ld a,%s", aopGet (op, 1, 0));
3244 emit2 ("xor a,!immedbyte", 0x80);
3249 id = getPairId (op);
3250 if (id == PAIR_INVALID)
3252 fetchPair (PAIR_DE, op);
3256 spillPair (PAIR_HL);
3257 emit2 ("ld hl,%s", fetchLitSpecial (lit, TRUE, sign));
3258 emit2 ("add hl,%s", _getPairIdName (id));
3261 if (AOP_TYPE (right) == AOP_LIT)
3263 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3264 /* optimize if(x < 0) or if(x >= 0) */
3269 /* No sign so it's always false */
3274 /* Just load in the top most bit */
3275 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
3276 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
3278 genIfxJump (ifx, "7");
3289 /* First setup h and l contaning the top most bytes XORed */
3290 bool fDidXor = FALSE;
3291 if (AOP_TYPE (left) == AOP_LIT)
3293 unsigned long lit = (unsigned long)
3294 floatFromVal (AOP (left)->aopu.aop_lit);
3295 emit2 ("ld %s,!immedbyte", _fTmp[0],
3296 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3300 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
3301 emit2 ("xor a,!immedbyte", 0x80);
3302 emit2 ("ld %s,a", _fTmp[0]);
3305 if (AOP_TYPE (right) == AOP_LIT)
3307 unsigned long lit = (unsigned long)
3308 floatFromVal (AOP (right)->aopu.aop_lit);
3309 emit2 ("ld %s,!immedbyte", _fTmp[1],
3310 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3314 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
3315 emit2 ("xor a,!immedbyte", 0x80);
3316 emit2 ("ld %s,a", _fTmp[1]);
3328 /* Do a long subtract */
3331 _moveA (aopGet (AOP (left), offset, FALSE));
3333 if (sign && size == 0)
3335 emit2 ("ld a,%s", _fTmp[0]);
3336 emit2 ("sbc a,%s", _fTmp[1]);
3340 /* Subtract through, propagating the carry */
3341 emit2 ("sbc a,%s", aopGet (AOP (right), offset++, FALSE));
3348 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
3350 outBitCLong (result, swap_sense);
3354 /* if the result is used in the next
3355 ifx conditional branch then generate
3356 code a little differently */
3358 genIfxJump (ifx, swap_sense ? "nc" : "c");
3360 outBitCLong (result, swap_sense);
3361 /* leave the result in acc */
3365 /*-----------------------------------------------------------------*/
3366 /* genCmpGt :- greater than comparison */
3367 /*-----------------------------------------------------------------*/
3369 genCmpGt (iCode * ic, iCode * ifx)
3371 operand *left, *right, *result;
3372 sym_link *letype, *retype;
3375 left = IC_LEFT (ic);
3376 right = IC_RIGHT (ic);
3377 result = IC_RESULT (ic);
3379 letype = getSpec (operandType (left));
3380 retype = getSpec (operandType (right));
3381 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
3382 /* assign the amsops */
3383 aopOp (left, ic, FALSE, FALSE);
3384 aopOp (right, ic, FALSE, FALSE);
3385 aopOp (result, ic, TRUE, FALSE);
3387 genCmp (right, left, result, ifx, sign);
3389 freeAsmop (left, NULL, ic);
3390 freeAsmop (right, NULL, ic);
3391 freeAsmop (result, NULL, ic);
3394 /*-----------------------------------------------------------------*/
3395 /* genCmpLt - less than comparisons */
3396 /*-----------------------------------------------------------------*/
3398 genCmpLt (iCode * ic, iCode * ifx)
3400 operand *left, *right, *result;
3401 sym_link *letype, *retype;
3404 left = IC_LEFT (ic);
3405 right = IC_RIGHT (ic);
3406 result = IC_RESULT (ic);
3408 letype = getSpec (operandType (left));
3409 retype = getSpec (operandType (right));
3410 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
3412 /* assign the amsops */
3413 aopOp (left, ic, FALSE, FALSE);
3414 aopOp (right, ic, FALSE, FALSE);
3415 aopOp (result, ic, TRUE, FALSE);
3417 genCmp (left, right, result, ifx, sign);
3419 freeAsmop (left, NULL, ic);
3420 freeAsmop (right, NULL, ic);
3421 freeAsmop (result, NULL, ic);
3424 /*-----------------------------------------------------------------*/
3425 /* gencjneshort - compare and jump if not equal */
3426 /*-----------------------------------------------------------------*/
3428 gencjneshort (operand * left, operand * right, symbol * lbl)
3430 int size = max (AOP_SIZE (left), AOP_SIZE (right));
3432 unsigned long lit = 0L;
3434 /* Swap the left and right if it makes the computation easier */
3435 if (AOP_TYPE (left) == AOP_LIT)
3442 if (AOP_TYPE (right) == AOP_LIT)
3443 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3445 /* if the right side is a literal then anything goes */
3446 if (AOP_TYPE (right) == AOP_LIT &&
3447 AOP_TYPE (left) != AOP_DIR)
3451 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3458 emit2 ("or a,%s", aopGet (AOP (left), offset, FALSE));
3465 emit2 ("jp nz,!tlabel", lbl->key + 100);
3471 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3472 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
3475 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
3476 emit2 ("jp nz,!tlabel", lbl->key + 100);
3481 /* if the right side is in a register or in direct space or
3482 if the left is a pointer register & right is not */
3483 else if (AOP_TYPE (right) == AOP_REG ||
3484 AOP_TYPE (right) == AOP_DIR ||
3485 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
3489 _moveA (aopGet (AOP (left), offset, FALSE));
3490 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
3491 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
3493 emit2 ("jp nz,!tlabel", lbl->key + 100);
3496 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3497 emit2 ("jp nz,!tlabel", lbl->key + 100);
3504 /* right is a pointer reg need both a & b */
3505 /* PENDING: is this required? */
3508 _moveA (aopGet (AOP (right), offset, FALSE));
3509 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
3510 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
3516 /*-----------------------------------------------------------------*/
3517 /* gencjne - compare and jump if not equal */
3518 /*-----------------------------------------------------------------*/
3520 gencjne (operand * left, operand * right, symbol * lbl)
3522 symbol *tlbl = newiTempLabel (NULL);
3524 gencjneshort (left, right, lbl);
3527 emit2 ("ld a,!one");
3528 emit2 ("!shortjp !tlabel", tlbl->key + 100);
3529 emitLabel (lbl->key + 100);
3531 emitLabel (tlbl->key + 100);
3534 /*-----------------------------------------------------------------*/
3535 /* genCmpEq - generates code for equal to */
3536 /*-----------------------------------------------------------------*/
3538 genCmpEq (iCode * ic, iCode * ifx)
3540 operand *left, *right, *result;
3542 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
3543 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
3544 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
3546 emitDebug ("; genCmpEq: left %u, right %u, result %u\n", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
3548 /* Swap operands if it makes the operation easier. ie if:
3549 1. Left is a literal.
3551 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
3553 operand *t = IC_RIGHT (ic);
3554 IC_RIGHT (ic) = IC_LEFT (ic);
3558 if (ifx && !AOP_SIZE (result))
3561 /* if they are both bit variables */
3562 if (AOP_TYPE (left) == AOP_CRY &&
3563 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
3569 tlbl = newiTempLabel (NULL);
3570 gencjneshort (left, right, tlbl);
3573 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
3574 emitLabel (tlbl->key + 100);
3578 /* PENDING: do this better */
3579 symbol *lbl = newiTempLabel (NULL);
3580 emit2 ("!shortjp !tlabel", lbl->key + 100);
3581 emitLabel (tlbl->key + 100);
3582 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
3583 emitLabel (lbl->key + 100);
3586 /* mark the icode as generated */
3591 /* if they are both bit variables */
3592 if (AOP_TYPE (left) == AOP_CRY &&
3593 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
3599 gencjne (left, right, newiTempLabel (NULL));
3600 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
3606 genIfxJump (ifx, "a");
3609 /* if the result is used in an arithmetic operation
3610 then put the result in place */
3611 if (AOP_TYPE (result) != AOP_CRY)
3615 /* leave the result in acc */
3619 freeAsmop (left, NULL, ic);
3620 freeAsmop (right, NULL, ic);
3621 freeAsmop (result, NULL, ic);
3624 /*-----------------------------------------------------------------*/
3625 /* ifxForOp - returns the icode containing the ifx for operand */
3626 /*-----------------------------------------------------------------*/
3628 ifxForOp (operand * op, iCode * ic)
3630 /* if true symbol then needs to be assigned */
3631 if (IS_TRUE_SYMOP (op))
3634 /* if this has register type condition and
3635 the next instruction is ifx with the same operand
3636 and live to of the operand is upto the ifx only then */
3638 ic->next->op == IFX &&
3639 IC_COND (ic->next)->key == op->key &&
3640 OP_SYMBOL (op)->liveTo <= ic->next->seq)
3646 /*-----------------------------------------------------------------*/
3647 /* genAndOp - for && operation */
3648 /*-----------------------------------------------------------------*/
3650 genAndOp (iCode * ic)
3652 operand *left, *right, *result;
3655 /* note here that && operations that are in an if statement are
3656 taken away by backPatchLabels only those used in arthmetic
3657 operations remain */
3658 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
3659 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
3660 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
3662 /* if both are bit variables */
3663 if (AOP_TYPE (left) == AOP_CRY &&
3664 AOP_TYPE (right) == AOP_CRY)
3670 tlbl = newiTempLabel (NULL);
3672 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3674 emitLabel (tlbl->key + 100);
3678 freeAsmop (left, NULL, ic);
3679 freeAsmop (right, NULL, ic);
3680 freeAsmop (result, NULL, ic);
3683 /*-----------------------------------------------------------------*/
3684 /* genOrOp - for || operation */
3685 /*-----------------------------------------------------------------*/
3687 genOrOp (iCode * ic)
3689 operand *left, *right, *result;
3692 /* note here that || operations that are in an
3693 if statement are taken away by backPatchLabels
3694 only those used in arthmetic operations remain */
3695 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
3696 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
3697 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
3699 /* if both are bit variables */
3700 if (AOP_TYPE (left) == AOP_CRY &&
3701 AOP_TYPE (right) == AOP_CRY)
3707 tlbl = newiTempLabel (NULL);
3709 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3711 emitLabel (tlbl->key + 100);
3715 freeAsmop (left, NULL, ic);
3716 freeAsmop (right, NULL, ic);
3717 freeAsmop (result, NULL, ic);
3720 /*-----------------------------------------------------------------*/
3721 /* isLiteralBit - test if lit == 2^n */
3722 /*-----------------------------------------------------------------*/
3724 isLiteralBit (unsigned long lit)
3726 unsigned long pw[32] =
3727 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
3728 0x100L, 0x200L, 0x400L, 0x800L,
3729 0x1000L, 0x2000L, 0x4000L, 0x8000L,
3730 0x10000L, 0x20000L, 0x40000L, 0x80000L,
3731 0x100000L, 0x200000L, 0x400000L, 0x800000L,
3732 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
3733 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
3736 for (idx = 0; idx < 32; idx++)
3742 /*-----------------------------------------------------------------*/
3743 /* jmpTrueOrFalse - */
3744 /*-----------------------------------------------------------------*/
3746 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
3748 // ugly but optimized by peephole
3751 symbol *nlbl = newiTempLabel (NULL);
3752 emit2 ("jp !tlabel", nlbl->key + 100);
3753 emitLabel (tlbl->key + 100);
3754 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
3755 emitLabel (nlbl->key + 100);
3759 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
3760 emitLabel (tlbl->key + 100);
3765 /*-----------------------------------------------------------------*/
3766 /* genAnd - code for and */
3767 /*-----------------------------------------------------------------*/
3769 genAnd (iCode * ic, iCode * ifx)
3771 operand *left, *right, *result;
3772 int size, offset = 0;
3773 unsigned long lit = 0L;
3776 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
3777 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
3778 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
3781 emitDebug ("; Type res[%d] = l[%d]&r[%d]",
3783 AOP_TYPE (left), AOP_TYPE (right));
3784 emitDebug ("; Size res[%d] = l[%d]&r[%d]",
3786 AOP_SIZE (left), AOP_SIZE (right));
3789 /* if left is a literal & right is not then exchange them */
3790 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
3791 AOP_NEEDSACC (left))
3793 operand *tmp = right;
3798 /* if result = right then exchange them */
3799 if (sameRegs (AOP (result), AOP (right)))
3801 operand *tmp = right;
3806 /* if right is bit then exchange them */
3807 if (AOP_TYPE (right) == AOP_CRY &&
3808 AOP_TYPE (left) != AOP_CRY)
3810 operand *tmp = right;
3814 if (AOP_TYPE (right) == AOP_LIT)
3815 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3817 size = AOP_SIZE (result);
3819 if (AOP_TYPE (left) == AOP_CRY)
3825 // if(val & 0xZZ) - size = 0, ifx != FALSE -
3826 // bit = val & 0xZZ - size = 1, ifx = FALSE -
3827 if ((AOP_TYPE (right) == AOP_LIT) &&
3828 (AOP_TYPE (result) == AOP_CRY) &&
3829 (AOP_TYPE (left) != AOP_CRY))
3831 int posbit = isLiteralBit (lit);
3836 _moveA (aopGet (AOP (left), posbit >> 3, FALSE));
3841 emit2 ("mov c,acc.%d", posbit & 0x07);
3848 sprintf (buffer, "%d", posbit & 0x07);
3849 genIfxJump (ifx, buffer);
3860 symbol *tlbl = newiTempLabel (NULL);
3861 int sizel = AOP_SIZE (left);
3869 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
3871 _moveA (aopGet (AOP (left), offset, FALSE));
3873 if ((posbit = isLiteralBit (bytelit)) != 0)
3876 emit2 ("jb acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
3880 if (bytelit != 0x0FFL)
3882 aopGet (AOP (right), offset, FALSE));
3886 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3891 // bit = left & literal
3895 emit2 ("!tlabeldef", tlbl->key + 100);
3897 // if(left & literal)
3901 jmpTrueOrFalse (ifx, tlbl);
3909 /* if left is same as result */
3910 if (sameRegs (AOP (result), AOP (left)))
3912 for (; size--; offset++)
3914 if (AOP_TYPE (right) == AOP_LIT)
3916 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
3921 aopPut (AOP (result), "!zero", offset);
3924 _moveA (aopGet (AOP (left), offset, FALSE));
3926 aopGet (AOP (right), offset, FALSE));
3927 aopPut (AOP (left), "a", offset);
3934 if (AOP_TYPE (left) == AOP_ACC)
3940 _moveA (aopGet (AOP (left), offset, FALSE));
3942 aopGet (AOP (right), offset, FALSE));
3943 aopPut (AOP (left), "a", offset);
3950 // left & result in different registers
3951 if (AOP_TYPE (result) == AOP_CRY)
3957 for (; (size--); offset++)
3960 // result = left & right
3961 if (AOP_TYPE (right) == AOP_LIT)
3963 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
3965 aopPut (AOP (result),
3966 aopGet (AOP (left), offset, FALSE),
3970 else if (bytelit == 0)
3972 aopPut (AOP (result), "!zero", offset);
3976 // faster than result <- left, anl result,right
3977 // and better if result is SFR
3978 if (AOP_TYPE (left) == AOP_ACC)
3979 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
3982 _moveA (aopGet (AOP (left), offset, FALSE));
3984 aopGet (AOP (right), offset, FALSE));
3986 aopPut (AOP (result), "a", offset);
3993 freeAsmop (left, NULL, ic);
3994 freeAsmop (right, NULL, ic);
3995 freeAsmop (result, NULL, ic);
3998 /*-----------------------------------------------------------------*/
3999 /* genOr - code for or */
4000 /*-----------------------------------------------------------------*/
4002 genOr (iCode * ic, iCode * ifx)
4004 operand *left, *right, *result;
4005 int size, offset = 0;
4006 unsigned long lit = 0L;
4008 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4009 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4010 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4013 emitDebug ("; Type res[%d] = l[%d]&r[%d]",
4015 AOP_TYPE (left), AOP_TYPE (right));
4016 emitDebug ("; Size res[%d] = l[%d]&r[%d]",
4018 AOP_SIZE (left), AOP_SIZE (right));
4021 /* if left is a literal & right is not then exchange them */
4022 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4023 AOP_NEEDSACC (left))
4025 operand *tmp = right;
4030 /* if result = right then exchange them */
4031 if (sameRegs (AOP (result), AOP (right)))
4033 operand *tmp = right;
4038 /* if right is bit then exchange them */
4039 if (AOP_TYPE (right) == AOP_CRY &&
4040 AOP_TYPE (left) != AOP_CRY)
4042 operand *tmp = right;
4046 if (AOP_TYPE (right) == AOP_LIT)
4047 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4049 size = AOP_SIZE (result);
4051 if (AOP_TYPE (left) == AOP_CRY)
4057 if ((AOP_TYPE (right) == AOP_LIT) &&
4058 (AOP_TYPE (result) == AOP_CRY) &&
4059 (AOP_TYPE (left) != AOP_CRY))
4065 /* if left is same as result */
4066 if (sameRegs (AOP (result), AOP (left)))
4068 for (; size--; offset++)
4070 if (AOP_TYPE (right) == AOP_LIT)
4072 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4076 _moveA (aopGet (AOP (left), offset, FALSE));
4078 aopGet (AOP (right), offset, FALSE));
4079 aopPut (AOP (result), "a", offset);
4084 if (AOP_TYPE (left) == AOP_ACC)
4085 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4088 _moveA (aopGet (AOP (left), offset, FALSE));
4090 aopGet (AOP (right), offset, FALSE));
4091 aopPut (AOP (result), "a", offset);
4098 // left & result in different registers
4099 if (AOP_TYPE (result) == AOP_CRY)
4104 for (; (size--); offset++)
4107 // result = left & right
4108 if (AOP_TYPE (right) == AOP_LIT)
4110 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4112 aopPut (AOP (result),
4113 aopGet (AOP (left), offset, FALSE),
4118 // faster than result <- left, anl result,right
4119 // and better if result is SFR
4120 if (AOP_TYPE (left) == AOP_ACC)
4121 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4124 _moveA (aopGet (AOP (left), offset, FALSE));
4126 aopGet (AOP (right), offset, FALSE));
4128 aopPut (AOP (result), "a", offset);
4129 /* PENDING: something weird is going on here. Add exception. */
4130 if (AOP_TYPE (result) == AOP_ACC)
4136 freeAsmop (left, NULL, ic);
4137 freeAsmop (right, NULL, ic);
4138 freeAsmop (result, NULL, ic);
4141 /*-----------------------------------------------------------------*/
4142 /* genXor - code for xclusive or */
4143 /*-----------------------------------------------------------------*/
4145 genXor (iCode * ic, iCode * ifx)
4147 operand *left, *right, *result;
4148 int size, offset = 0;
4149 unsigned long lit = 0L;
4151 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4152 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4153 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4155 /* if left is a literal & right is not then exchange them */
4156 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4157 AOP_NEEDSACC (left))
4159 operand *tmp = right;
4164 /* if result = right then exchange them */
4165 if (sameRegs (AOP (result), AOP (right)))
4167 operand *tmp = right;
4172 /* if right is bit then exchange them */
4173 if (AOP_TYPE (right) == AOP_CRY &&
4174 AOP_TYPE (left) != AOP_CRY)
4176 operand *tmp = right;
4180 if (AOP_TYPE (right) == AOP_LIT)
4181 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4183 size = AOP_SIZE (result);
4185 if (AOP_TYPE (left) == AOP_CRY)
4191 if ((AOP_TYPE (right) == AOP_LIT) &&
4192 (AOP_TYPE (result) == AOP_CRY) &&
4193 (AOP_TYPE (left) != AOP_CRY))
4199 /* if left is same as result */
4200 if (sameRegs (AOP (result), AOP (left)))
4202 for (; size--; offset++)
4204 if (AOP_TYPE (right) == AOP_LIT)
4206 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4210 _moveA (aopGet (AOP (right), offset, FALSE));
4212 aopGet (AOP (left), offset, FALSE));
4213 aopPut (AOP (result), "a", offset);
4218 if (AOP_TYPE (left) == AOP_ACC)
4220 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4224 _moveA (aopGet (AOP (right), offset, FALSE));
4226 aopGet (AOP (left), offset, FALSE));
4227 aopPut (AOP (result), "a", 0);
4234 // left & result in different registers
4235 if (AOP_TYPE (result) == AOP_CRY)
4240 for (; (size--); offset++)
4243 // result = left & right
4244 if (AOP_TYPE (right) == AOP_LIT)
4246 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4248 aopPut (AOP (result),
4249 aopGet (AOP (left), offset, FALSE),
4254 // faster than result <- left, anl result,right
4255 // and better if result is SFR
4256 if (AOP_TYPE (left) == AOP_ACC)
4258 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4262 _moveA (aopGet (AOP (right), offset, FALSE));
4264 aopGet (AOP (left), offset, FALSE));
4266 aopPut (AOP (result), "a", offset);
4271 freeAsmop (left, NULL, ic);
4272 freeAsmop (right, NULL, ic);
4273 freeAsmop (result, NULL, ic);
4276 /*-----------------------------------------------------------------*/
4277 /* genInline - write the inline code out */
4278 /*-----------------------------------------------------------------*/
4280 genInline (iCode * ic)
4282 char *buffer, *bp, *bp1;
4284 _G.lines.isInline += (!options.asmpeep);
4286 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
4287 strcpy (buffer, IC_INLINE (ic));
4289 /* emit each line as a code */
4314 _G.lines.isInline -= (!options.asmpeep);
4318 /*-----------------------------------------------------------------*/
4319 /* genRRC - rotate right with carry */
4320 /*-----------------------------------------------------------------*/
4327 /*-----------------------------------------------------------------*/
4328 /* genRLC - generate code for rotate left with carry */
4329 /*-----------------------------------------------------------------*/
4336 /*-----------------------------------------------------------------*/
4337 /* genGetHbit - generates code get highest order bit */
4338 /*-----------------------------------------------------------------*/
4340 genGetHbit (iCode * ic)
4342 operand *left, *result;
4343 left = IC_LEFT (ic);
4344 result = IC_RESULT (ic);
4345 aopOp (left, ic, FALSE, FALSE);
4346 aopOp (result, ic, FALSE, FALSE);
4348 /* get the highest order byte into a */
4349 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4351 if (AOP_TYPE (result) == AOP_CRY)
4359 /* PENDING: For re-target. */
4365 freeAsmop (left, NULL, ic);
4366 freeAsmop (result, NULL, ic);
4370 emitRsh2 (asmop *aop, int size, int is_signed)
4376 const char *l = aopGet (aop, size, FALSE);
4379 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
4389 /*-----------------------------------------------------------------*/
4390 /* shiftR2Left2Result - shift right two bytes from left to result */
4391 /*-----------------------------------------------------------------*/
4393 shiftR2Left2Result (operand * left, int offl,
4394 operand * result, int offr,
4395 int shCount, int is_signed)
4398 symbol *tlbl, *tlbl1;
4400 movLeft2Result (left, offl, result, offr, 0);
4401 movLeft2Result (left, offl + 1, result, offr + 1, 0);
4403 /* if (AOP(result)->type == AOP_REG) { */
4405 tlbl = newiTempLabel (NULL);
4406 tlbl1 = newiTempLabel (NULL);
4408 /* Left is already in result - so now do the shift */
4413 emitRsh2 (AOP (result), size, is_signed);
4418 emit2 ("ld a,!immedbyte+1", shCount);
4419 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4420 emitLabel (tlbl->key + 100);
4422 emitRsh2 (AOP (result), size, is_signed);
4424 emitLabel (tlbl1->key + 100);
4426 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4430 /*-----------------------------------------------------------------*/
4431 /* shiftL2Left2Result - shift left two bytes from left to result */
4432 /*-----------------------------------------------------------------*/
4434 shiftL2Left2Result (operand * left, int offl,
4435 operand * result, int offr, int shCount)
4437 if (sameRegs (AOP (result), AOP (left)) &&
4438 ((offl + MSB16) == offr))
4444 /* Copy left into result */
4445 movLeft2Result (left, offl, result, offr, 0);
4446 movLeft2Result (left, offl + 1, result, offr + 1, 0);
4448 /* PENDING: for now just see if it'll work. */
4449 /*if (AOP(result)->type == AOP_REG) { */
4453 symbol *tlbl, *tlbl1;
4456 tlbl = newiTempLabel (NULL);
4457 tlbl1 = newiTempLabel (NULL);
4459 /* Left is already in result - so now do the shift */
4462 emit2 ("ld a,!immedbyte+1", shCount);
4463 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4464 emitLabel (tlbl->key + 100);
4470 l = aopGet (AOP (result), offset, FALSE);
4478 emitLabel (tlbl1->key + 100);
4480 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4485 /*-----------------------------------------------------------------*/
4486 /* AccRol - rotate left accumulator by known count */
4487 /*-----------------------------------------------------------------*/
4489 AccRol (int shCount)
4491 shCount &= 0x0007; // shCount : 0..7
4530 /*-----------------------------------------------------------------*/
4531 /* AccLsh - left shift accumulator by known count */
4532 /*-----------------------------------------------------------------*/
4534 AccLsh (int shCount)
4536 static const unsigned char SLMask[] =
4538 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
4547 else if (shCount == 2)
4554 /* rotate left accumulator */
4556 /* and kill the lower order bits */
4557 emit2 ("and a,!immedbyte", SLMask[shCount]);
4562 /*-----------------------------------------------------------------*/
4563 /* shiftL1Left2Result - shift left one byte from left to result */
4564 /*-----------------------------------------------------------------*/
4566 shiftL1Left2Result (operand * left, int offl,
4567 operand * result, int offr, int shCount)
4570 l = aopGet (AOP (left), offl, FALSE);
4572 /* shift left accumulator */
4574 aopPut (AOP (result), "a", offr);
4578 /*-----------------------------------------------------------------*/
4579 /* genlshTwo - left shift two bytes by known amount != 0 */
4580 /*-----------------------------------------------------------------*/
4582 genlshTwo (operand * result, operand * left, int shCount)
4584 int size = AOP_SIZE (result);
4586 wassert (size == 2);
4588 /* if shCount >= 8 */
4596 movLeft2Result (left, LSB, result, MSB16, 0);
4597 aopPut (AOP (result), "!zero", 0);
4598 shiftL1Left2Result (left, MSB16, result, MSB16, shCount);
4602 movLeft2Result (left, LSB, result, MSB16, 0);
4603 aopPut (AOP (result), "!zero", 0);
4608 aopPut (AOP (result), "!zero", LSB);
4611 /* 1 <= shCount <= 7 */
4620 shiftL2Left2Result (left, LSB, result, LSB, shCount);
4625 /*-----------------------------------------------------------------*/
4626 /* genlshOne - left shift a one byte quantity by known count */
4627 /*-----------------------------------------------------------------*/
4629 genlshOne (operand * result, operand * left, int shCount)
4631 shiftL1Left2Result (left, LSB, result, LSB, shCount);
4634 /*-----------------------------------------------------------------*/
4635 /* genLeftShiftLiteral - left shifting by known count */
4636 /*-----------------------------------------------------------------*/
4638 genLeftShiftLiteral (operand * left,
4643 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
4646 freeAsmop (right, NULL, ic);
4648 aopOp (left, ic, FALSE, FALSE);
4649 aopOp (result, ic, FALSE, FALSE);
4651 size = getSize (operandType (result));
4654 emitDebug ("; shift left result %d, left %d", size,
4658 /* I suppose that the left size >= result size */
4664 else if (shCount >= (size * 8))
4668 aopPut (AOP (result), "!zero", size);
4676 genlshOne (result, left, shCount);
4679 genlshTwo (result, left, shCount);
4682 wassertl (0, "Shifting of longs is currently unsupported");
4688 freeAsmop (left, NULL, ic);
4689 freeAsmop (result, NULL, ic);
4692 /*-----------------------------------------------------------------*/
4693 /* genLeftShift - generates code for left shifting */
4694 /*-----------------------------------------------------------------*/
4696 genLeftShift (iCode * ic)
4700 symbol *tlbl, *tlbl1;
4701 operand *left, *right, *result;
4703 right = IC_RIGHT (ic);
4704 left = IC_LEFT (ic);
4705 result = IC_RESULT (ic);
4707 aopOp (right, ic, FALSE, FALSE);
4709 /* if the shift count is known then do it
4710 as efficiently as possible */
4711 if (AOP_TYPE (right) == AOP_LIT)
4713 genLeftShiftLiteral (left, right, result, ic);
4717 /* shift count is unknown then we have to form a loop get the loop
4718 count in B : Note: we take only the lower order byte since
4719 shifting more that 32 bits make no sense anyway, ( the largest
4720 size of an object can be only 32 bits ) */
4721 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
4723 freeAsmop (right, NULL, ic);
4724 aopOp (left, ic, FALSE, FALSE);
4725 aopOp (result, ic, FALSE, FALSE);
4727 /* now move the left to the result if they are not the
4730 if (!sameRegs (AOP (left), AOP (result)))
4733 size = AOP_SIZE (result);
4737 l = aopGet (AOP (left), offset, FALSE);
4738 aopPut (AOP (result), l, offset);
4743 size = AOP_SIZE (result);
4747 l = aopGet (AOP (left), offset, FALSE);
4748 aopPut (AOP (result), l, offset);
4754 tlbl = newiTempLabel (NULL);
4755 size = AOP_SIZE (result);
4757 tlbl1 = newiTempLabel (NULL);
4759 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4760 emitLabel (tlbl->key + 100);
4761 l = aopGet (AOP (result), offset, FALSE);
4767 l = aopGet (AOP (result), offset++, FALSE);
4770 emitLabel (tlbl1->key + 100);
4772 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4774 freeAsmop (left, NULL, ic);
4775 freeAsmop (result, NULL, ic);
4778 /*-----------------------------------------------------------------*/
4779 /* genrshOne - left shift two bytes by known amount != 0 */
4780 /*-----------------------------------------------------------------*/
4782 genrshOne (operand * result, operand * left, int shCount, int is_signed)
4785 int size = AOP_SIZE (result);
4788 wassert (size == 1);
4789 wassert (shCount < 8);
4791 l = aopGet (AOP (left), 0, FALSE);
4795 if (AOP (result)->type == AOP_REG)
4797 aopPut (AOP (result), l, 0);
4798 l = aopGet (AOP (result), 0, FALSE);
4801 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
4809 emit2 ("%s a", is_signed ? "sra" : "srl");
4811 aopPut (AOP (result), "a", 0);
4815 /*-----------------------------------------------------------------*/
4816 /* AccRsh - right shift accumulator by known count */
4817 /*-----------------------------------------------------------------*/
4819 AccRsh (int shCount)
4821 static const unsigned char SRMask[] =
4823 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
4828 /* rotate right accumulator */
4829 AccRol (8 - shCount);
4830 /* and kill the higher order bits */
4831 emit2 ("and a,!immedbyte", SRMask[shCount]);
4835 /*-----------------------------------------------------------------*/
4836 /* shiftR1Left2Result - shift right one byte from left to result */
4837 /*-----------------------------------------------------------------*/
4839 shiftR1Left2Result (operand * left, int offl,
4840 operand * result, int offr,
4841 int shCount, int sign)
4843 _moveA (aopGet (AOP (left), offl, FALSE));
4852 aopPut (AOP (result), "a", offr);
4855 /*-----------------------------------------------------------------*/
4856 /* genrshTwo - right shift two bytes by known amount != 0 */
4857 /*-----------------------------------------------------------------*/
4859 genrshTwo (operand * result, operand * left,
4860 int shCount, int sign)
4862 /* if shCount >= 8 */
4868 shiftR1Left2Result (left, MSB16, result, LSB,
4873 movLeft2Result (left, MSB16, result, LSB, sign);
4875 aopPut (AOP (result), "!zero", 1);
4877 /* 1 <= shCount <= 7 */
4880 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
4884 /*-----------------------------------------------------------------*/
4885 /* genRightShiftLiteral - left shifting by known count */
4886 /*-----------------------------------------------------------------*/
4888 genRightShiftLiteral (operand * left,
4894 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
4897 freeAsmop (right, NULL, ic);
4899 aopOp (left, ic, FALSE, FALSE);
4900 aopOp (result, ic, FALSE, FALSE);
4902 size = getSize (operandType (result));
4904 emitDebug ("; shift right result %d, left %d", size,
4907 /* I suppose that the left size >= result size */
4913 else if (shCount >= (size * 8))
4915 aopPut (AOP (result), "!zero", size);
4921 genrshOne (result, left, shCount, sign);
4924 /* PENDING: sign support */
4925 genrshTwo (result, left, shCount, sign);
4928 wassertl (0, "Asked to shift right a long which should be a function call");
4931 wassertl (0, "Entered default case in right shift delegate");
4934 freeAsmop (left, NULL, ic);
4935 freeAsmop (result, NULL, ic);
4938 /*-----------------------------------------------------------------*/
4939 /* genRightShift - generate code for right shifting */
4940 /*-----------------------------------------------------------------*/
4942 genRightShift (iCode * ic)
4944 operand *right, *left, *result;
4946 int size, offset, first = 1;
4950 symbol *tlbl, *tlbl1;
4952 /* if signed then we do it the hard way preserve the
4953 sign bit moving it inwards */
4954 retype = getSpec (operandType (IC_RESULT (ic)));
4956 is_signed = !SPEC_USIGN (retype);
4958 /* signed & unsigned types are treated the same : i.e. the
4959 signed is NOT propagated inwards : quoting from the
4960 ANSI - standard : "for E1 >> E2, is equivalent to division
4961 by 2**E2 if unsigned or if it has a non-negative value,
4962 otherwise the result is implementation defined ", MY definition
4963 is that the sign does not get propagated */
4965 right = IC_RIGHT (ic);
4966 left = IC_LEFT (ic);
4967 result = IC_RESULT (ic);
4969 aopOp (right, ic, FALSE, FALSE);
4971 /* if the shift count is known then do it
4972 as efficiently as possible */
4973 if (AOP_TYPE (right) == AOP_LIT)
4975 genRightShiftLiteral (left, right, result, ic, is_signed);
4979 aopOp (left, ic, FALSE, FALSE);
4980 aopOp (result, ic, FALSE, FALSE);
4982 /* now move the left to the result if they are not the
4984 if (!sameRegs (AOP (left), AOP (result)) &&
4985 AOP_SIZE (result) > 1)
4988 size = AOP_SIZE (result);
4992 l = aopGet (AOP (left), offset, FALSE);
4993 aopPut (AOP (result), l, offset);
4998 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5000 freeAsmop (right, NULL, ic);
5002 tlbl = newiTempLabel (NULL);
5003 tlbl1 = newiTempLabel (NULL);
5004 size = AOP_SIZE (result);
5007 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5008 emitLabel (tlbl->key + 100);
5011 l = aopGet (AOP (result), offset--, FALSE);
5014 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5022 emitLabel (tlbl1->key + 100);
5024 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5026 freeAsmop (left, NULL, ic);
5027 freeAsmop (result, NULL, ic);
5030 /*-----------------------------------------------------------------*/
5031 /* genGenPointerGet - get value from generic pointer space */
5032 /*-----------------------------------------------------------------*/
5034 genGenPointerGet (operand * left,
5035 operand * result, iCode * ic)
5038 sym_link *retype = getSpec (operandType (result));
5044 aopOp (left, ic, FALSE, FALSE);
5045 aopOp (result, ic, FALSE, FALSE);
5047 if (isPair (AOP (left)) && AOP_SIZE (result) == 1)
5050 if (isPtrPair (AOP (left)))
5052 tsprintf (buffer, "!*pair", getPairName (AOP (left)));
5053 aopPut (AOP (result), buffer, 0);
5057 emit2 ("ld a,!*pair", getPairName (AOP (left)));
5058 aopPut (AOP (result), "a", 0);
5060 freeAsmop (left, NULL, ic);
5064 /* For now we always load into IY */
5065 /* if this is remateriazable */
5066 fetchPair (pair, AOP (left));
5068 /* so iy now contains the address */
5069 freeAsmop (left, NULL, ic);
5071 /* if bit then unpack */
5072 if (IS_BITVAR (retype))
5078 size = AOP_SIZE (result);
5083 /* PENDING: make this better */
5084 if (!IS_GB && AOP (result)->type == AOP_REG)
5086 aopPut (AOP (result), "!*hl", offset++);
5090 emit2 ("ld a,!*pair", _pairs[pair].name);
5091 aopPut (AOP (result), "a", offset++);
5095 emit2 ("inc %s", _pairs[pair].name);
5096 _G.pairs[pair].offset++;
5102 freeAsmop (result, NULL, ic);
5105 /*-----------------------------------------------------------------*/
5106 /* genPointerGet - generate code for pointer get */
5107 /*-----------------------------------------------------------------*/
5109 genPointerGet (iCode * ic)
5111 operand *left, *result;
5112 sym_link *type, *etype;
5114 left = IC_LEFT (ic);
5115 result = IC_RESULT (ic);
5117 /* depending on the type of pointer we need to
5118 move it to the correct pointer register */
5119 type = operandType (left);
5120 etype = getSpec (type);
5122 genGenPointerGet (left, result, ic);
5126 isRegOrLit (asmop * aop)
5128 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
5133 /*-----------------------------------------------------------------*/
5134 /* genGenPointerSet - stores the value into a pointer location */
5135 /*-----------------------------------------------------------------*/
5137 genGenPointerSet (operand * right,
5138 operand * result, iCode * ic)
5141 sym_link *retype = getSpec (operandType (right));
5142 PAIR_ID pairId = PAIR_HL;
5144 aopOp (result, ic, FALSE, FALSE);
5145 aopOp (right, ic, FALSE, FALSE);
5150 /* Handle the exceptions first */
5151 if (isPair (AOP (result)) && (AOP_SIZE (right) == 1))
5154 const char *l = aopGet (AOP (right), 0, FALSE);
5155 const char *pair = getPairName (AOP (result));
5156 if (canAssignToPtr (l) && isPtr (pair))
5158 emit2 ("ld !*pair,%s", pair, l);
5163 emit2 ("ld !*pair,a", pair);
5168 /* if the operand is already in dptr
5169 then we do nothing else we move the value to dptr */
5170 if (AOP_TYPE (result) != AOP_STR)
5172 fetchPair (pairId, AOP (result));
5174 /* so hl know contains the address */
5175 freeAsmop (result, NULL, ic);
5177 /* if bit then unpack */
5178 if (IS_BITVAR (retype))
5184 size = AOP_SIZE (right);
5189 const char *l = aopGet (AOP (right), offset, FALSE);
5190 if (isRegOrLit (AOP (right)) && !IS_GB)
5192 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
5197 emit2 ("ld !*pair,a", _pairs[pairId].name);
5201 emit2 ("inc %s", _pairs[pairId].name);
5202 _G.pairs[pairId].offset++;
5208 freeAsmop (right, NULL, ic);
5211 /*-----------------------------------------------------------------*/
5212 /* genPointerSet - stores the value into a pointer location */
5213 /*-----------------------------------------------------------------*/
5215 genPointerSet (iCode * ic)
5217 operand *right, *result;
5218 sym_link *type, *etype;
5220 right = IC_RIGHT (ic);
5221 result = IC_RESULT (ic);
5223 /* depending on the type of pointer we need to
5224 move it to the correct pointer register */
5225 type = operandType (result);
5226 etype = getSpec (type);
5228 genGenPointerSet (right, result, ic);
5231 /*-----------------------------------------------------------------*/
5232 /* genIfx - generate code for Ifx statement */
5233 /*-----------------------------------------------------------------*/
5235 genIfx (iCode * ic, iCode * popIc)
5237 operand *cond = IC_COND (ic);
5240 aopOp (cond, ic, FALSE, TRUE);
5242 /* get the value into acc */
5243 if (AOP_TYPE (cond) != AOP_CRY)
5247 /* the result is now in the accumulator */
5248 freeAsmop (cond, NULL, ic);
5250 /* if there was something to be popped then do it */
5254 /* if the condition is a bit variable */
5255 if (isbit && IS_ITEMP (cond) &&
5257 genIfxJump (ic, SPIL_LOC (cond)->rname);
5258 else if (isbit && !IS_ITEMP (cond))
5259 genIfxJump (ic, OP_SYMBOL (cond)->rname);
5261 genIfxJump (ic, "a");
5266 /*-----------------------------------------------------------------*/
5267 /* genAddrOf - generates code for address of */
5268 /*-----------------------------------------------------------------*/
5270 genAddrOf (iCode * ic)
5272 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
5274 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
5276 /* if the operand is on the stack then we
5277 need to get the stack offset of this
5284 if (sym->stack <= 0)
5286 emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset);
5290 emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
5297 emit2 ("ld de,!hashedstr", sym->rname);
5299 aopPut (AOP (IC_RESULT (ic)), "e", 0);
5300 aopPut (AOP (IC_RESULT (ic)), "d", 1);
5307 /* if it has an offset then we need to compute it */
5309 emit2 ("ld hl,#%d+%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset, _G.stack.param_offset);
5311 emit2 ("ld hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
5312 emit2 ("add hl,sp");
5316 emit2 ("ld hl,#%s", sym->rname);
5318 aopPut (AOP (IC_RESULT (ic)), "l", 0);
5319 aopPut (AOP (IC_RESULT (ic)), "h", 1);
5321 freeAsmop (IC_RESULT (ic), NULL, ic);
5324 /*-----------------------------------------------------------------*/
5325 /* genAssign - generate code for assignment */
5326 /*-----------------------------------------------------------------*/
5328 genAssign (iCode * ic)
5330 operand *result, *right;
5332 unsigned long lit = 0L;
5334 result = IC_RESULT (ic);
5335 right = IC_RIGHT (ic);
5338 /* Dont bother assigning if they are the same */
5339 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5341 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
5346 aopOp (right, ic, FALSE, FALSE);
5347 aopOp (result, ic, TRUE, FALSE);
5349 /* if they are the same registers */
5350 if (sameRegs (AOP (right), AOP (result)))
5352 emitDebug ("; (registers are the same)");
5356 /* if the result is a bit */
5357 if (AOP_TYPE (result) == AOP_CRY)
5363 size = AOP_SIZE (result);
5366 if (AOP_TYPE (right) == AOP_LIT)
5367 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5368 if (isPair (AOP (result)))
5370 fetchPair (getPairId (AOP (result)), AOP (right));
5372 else if ((size > 1) &&
5373 (AOP_TYPE (result) != AOP_REG) &&
5374 (AOP_TYPE (right) == AOP_LIT) &&
5375 !IS_FLOAT (operandType (right)) &&
5378 bool fXored = FALSE;
5380 /* Work from the top down.
5381 Done this way so that we can use the cached copy of 0
5382 in A for a fast clear */
5385 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
5387 if (!fXored && size > 1)
5394 aopPut (AOP (result), "a", offset);
5398 aopPut (AOP (result), "!zero", offset);
5402 aopPut (AOP (result),
5403 aopGet (AOP (right), offset, FALSE),
5408 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
5410 /* Special case. Load into a and d, then load out. */
5411 _moveA (aopGet (AOP (right), 0, FALSE));
5412 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
5413 aopPut (AOP (result), "a", 0);
5414 aopPut (AOP (result), "e", 1);
5420 /* PENDING: do this check better */
5421 if (requiresHL (AOP (right)) && requiresHL (AOP (result)))
5423 _moveA (aopGet (AOP (right), offset, FALSE));
5424 aopPut (AOP (result), "a", offset);
5427 aopPut (AOP (result),
5428 aopGet (AOP (right), offset, FALSE),
5435 freeAsmop (right, NULL, ic);
5436 freeAsmop (result, NULL, ic);
5439 /*-----------------------------------------------------------------*/
5440 /* genJumpTab - genrates code for jump table */
5441 /*-----------------------------------------------------------------*/
5443 genJumpTab (iCode * ic)
5448 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
5449 /* get the condition into accumulator */
5450 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
5453 emit2 ("ld e,%s", l);
5454 emit2 ("ld d,!zero");
5455 jtab = newiTempLabel (NULL);
5457 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
5458 emit2 ("add hl,de");
5459 emit2 ("add hl,de");
5460 emit2 ("add hl,de");
5461 freeAsmop (IC_JTCOND (ic), NULL, ic);
5465 emitLabel (jtab->key + 100);
5466 /* now generate the jump labels */
5467 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
5468 jtab = setNextItem (IC_JTLABELS (ic)))
5469 emit2 ("jp !tlabel", jtab->key + 100);
5472 /*-----------------------------------------------------------------*/
5473 /* genCast - gen code for casting */
5474 /*-----------------------------------------------------------------*/
5476 genCast (iCode * ic)
5478 operand *result = IC_RESULT (ic);
5479 sym_link *ctype = operandType (IC_LEFT (ic));
5480 operand *right = IC_RIGHT (ic);
5483 /* if they are equivalent then do nothing */
5484 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5487 aopOp (right, ic, FALSE, FALSE);
5488 aopOp (result, ic, FALSE, FALSE);
5490 /* if the result is a bit */
5491 if (AOP_TYPE (result) == AOP_CRY)
5496 /* if they are the same size : or less */
5497 if (AOP_SIZE (result) <= AOP_SIZE (right))
5500 /* if they are in the same place */
5501 if (sameRegs (AOP (right), AOP (result)))
5504 /* if they in different places then copy */
5505 size = AOP_SIZE (result);
5509 aopPut (AOP (result),
5510 aopGet (AOP (right), offset, FALSE),
5517 /* PENDING: should be OK. */
5519 /* if the result is of type pointer */
5526 /* so we now know that the size of destination is greater
5527 than the size of the source */
5528 /* we move to result for the size of source */
5529 size = AOP_SIZE (right);
5533 aopPut (AOP (result),
5534 aopGet (AOP (right), offset, FALSE),
5539 /* now depending on the sign of the destination */
5540 size = AOP_SIZE (result) - AOP_SIZE (right);
5541 /* Unsigned or not an integral type - right fill with zeros */
5542 if (SPEC_USIGN (ctype) || !IS_SPEC (ctype))
5545 aopPut (AOP (result), "!zero", offset++);
5549 /* we need to extend the sign :{ */
5550 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
5553 emitDebug ("; genCast: sign extend untested.");
5557 aopPut (AOP (result), "a", offset++);
5561 freeAsmop (right, NULL, ic);
5562 freeAsmop (result, NULL, ic);
5565 /*-----------------------------------------------------------------*/
5566 /* genReceive - generate code for a receive iCode */
5567 /*-----------------------------------------------------------------*/
5569 genReceive (iCode * ic)
5571 if (isOperandInFarSpace (IC_RESULT (ic)) &&
5572 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
5573 IS_TRUE_SYMOP (IC_RESULT (ic))))
5583 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
5584 size = AOP_SIZE(IC_RESULT(ic));
5586 for (i = 0; i < size; i++) {
5587 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
5591 freeAsmop (IC_RESULT (ic), NULL, ic);
5596 /** Maximum number of bytes to emit per line. */
5600 /** Context for the byte output chunker. */
5603 unsigned char buffer[DBEMIT_MAX_RUN];
5608 /** Flushes a byte chunker by writing out all in the buffer and
5612 _dbFlush(DBEMITCTX *self)
5619 sprintf(line, ".db 0x%02X", self->buffer[0]);
5621 for (i = 1; i < self->pos; i++)
5623 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
5630 /** Write out another byte, buffering until a decent line is
5634 _dbEmit(DBEMITCTX *self, int c)
5636 if (self->pos == DBEMIT_MAX_RUN)
5640 self->buffer[self->pos++] = c;
5643 /** Context for a simple run length encoder. */
5647 unsigned char buffer[128];
5649 /** runLen may be equivalent to pos. */
5655 RLE_CHANGE_COST = 4,
5659 /** Flush the buffer of a run length encoder by writing out the run or
5660 data that it currently contains.
5663 _rleCommit(RLECTX *self)
5669 memset(&db, 0, sizeof(db));
5671 emit2(".db %u", self->pos);
5673 for (i = 0; i < self->pos; i++)
5675 _dbEmit(&db, self->buffer[i]);
5684 Can get either a run or a block of random stuff.
5685 Only want to change state if a good run comes in or a run ends.
5686 Detecting run end is easy.
5689 Say initial state is in run, len zero, last zero. Then if you get a
5690 few zeros then something else then a short run will be output.
5691 Seems OK. While in run mode, keep counting. While in random mode,
5692 keep a count of the run. If run hits margin, output all up to run,
5693 restart, enter run mode.
5696 /** Add another byte into the run length encoder, flushing as
5697 required. The run length encoder uses the Amiga IFF style, where
5698 a block is prefixed by its run length. A positive length means
5699 the next n bytes pass straight through. A negative length means
5700 that the next byte is repeated -n times. A zero terminates the
5704 _rleAppend(RLECTX *self, int c)
5708 if (c != self->last)
5710 /* The run has stopped. See if it is worthwhile writing it out
5711 as a run. Note that the random data comes in as runs of
5714 if (self->runLen > RLE_CHANGE_COST)
5716 /* Yes, worthwhile. */
5717 /* Commit whatever was in the buffer. */
5719 emit2(".db -%u,0x%02X", self->runLen, self->last);
5723 /* Not worthwhile. Append to the end of the random list. */
5724 for (i = 0; i < self->runLen; i++)
5726 if (self->pos >= RLE_MAX_BLOCK)
5731 self->buffer[self->pos++] = self->last;
5739 if (self->runLen >= RLE_MAX_BLOCK)
5741 /* Commit whatever was in the buffer. */
5744 emit2 (".db -%u,0x%02X", self->runLen, self->last);
5752 _rleFlush(RLECTX *self)
5754 _rleAppend(self, -1);
5761 /** genArrayInit - Special code for initialising an array with constant
5765 genArrayInit (iCode * ic)
5769 int elementSize = 0, eIndex, i;
5770 unsigned val, lastVal;
5774 memset(&rle, 0, sizeof(rle));
5776 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
5778 if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD)
5780 /* Emit the support function call and the destination address. */
5781 emit2("call __initrleblock");
5782 emit2(".dw %s", aopGetWord (AOP(IC_LEFT(ic)), 0));
5786 wassertl (0, "Unexpected operand to genArrayInit.\n");
5789 type = operandType(IC_LEFT(ic));
5791 if (type && type->next)
5793 elementSize = getSize(type->next);
5797 wassertl (0, "Can't determine element size in genArrayInit.");
5800 iLoop = IC_ARRAYILIST(ic);
5801 lastVal = (unsigned)-1;
5803 /* Feed all the bytes into the run length encoder which will handle
5805 This works well for mixed char data, and for random int and long
5814 for (i = 0; i < ix; i++)
5816 for (eIndex = 0; eIndex < elementSize; eIndex++)
5818 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
5819 _rleAppend(&rle, val);
5824 iLoop = iLoop->next;
5828 /* Mark the end of the run. */
5831 freeAsmop (IC_LEFT(ic), NULL, ic);
5834 /*-----------------------------------------------------------------*/
5835 /* genZ80Code - generate code for Z80 based controllers */
5836 /*-----------------------------------------------------------------*/
5838 genZ80Code (iCode * lic)
5846 _fReturn = _gbz80_return;
5847 _fTmp = _gbz80_return;
5851 _fReturn = _z80_return;
5852 _fTmp = _z80_return;
5855 _G.lines.head = _G.lines.current = NULL;
5857 for (ic = lic; ic; ic = ic->next)
5860 if (cln != ic->lineno)
5862 emit2 ("; %s %d", ic->filename, ic->lineno);
5865 /* if the result is marked as
5866 spilt and rematerializable or code for
5867 this has already been generated then
5869 if (resultRemat (ic) || ic->generated)
5872 /* depending on the operation */
5876 emitDebug ("; genNot");
5881 emitDebug ("; genCpl");
5886 emitDebug ("; genUminus");
5891 emitDebug ("; genIpush");
5896 /* IPOP happens only when trying to restore a
5897 spilt live range, if there is an ifx statement
5898 following this pop then the if statement might
5899 be using some of the registers being popped which
5900 would destory the contents of the register so
5901 we need to check for this condition and handle it */
5903 ic->next->op == IFX &&
5904 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
5906 emitDebug ("; genIfx");
5907 genIfx (ic->next, ic);
5911 emitDebug ("; genIpop");
5917 emitDebug ("; genCall");
5922 emitDebug ("; genPcall");
5927 emitDebug ("; genFunction");
5932 emitDebug ("; genEndFunction");
5933 genEndFunction (ic);
5937 emitDebug ("; genRet");
5942 emitDebug ("; genLabel");
5947 emitDebug ("; genGoto");
5952 emitDebug ("; genPlus");
5957 emitDebug ("; genMinus");
5962 emitDebug ("; genMult");
5967 emitDebug ("; genDiv");
5972 emitDebug ("; genMod");
5977 emitDebug ("; genCmpGt");
5978 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
5982 emitDebug ("; genCmpLt");
5983 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
5990 /* note these two are xlated by algebraic equivalence
5991 during parsing SDCC.y */
5992 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
5993 "got '>=' or '<=' shouldn't have come here");
5997 emitDebug ("; genCmpEq");
5998 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
6002 emitDebug ("; genAndOp");
6007 emitDebug ("; genOrOp");
6012 emitDebug ("; genXor");
6013 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
6017 emitDebug ("; genOr");
6018 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
6022 emitDebug ("; genAnd");
6023 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
6027 emitDebug ("; genInline");
6032 emitDebug ("; genRRC");
6037 emitDebug ("; genRLC");
6042 emitDebug ("; genGetHBIT");
6047 emitDebug ("; genLeftShift");
6052 emitDebug ("; genRightShift");
6056 case GET_VALUE_AT_ADDRESS:
6057 emitDebug ("; genPointerGet");
6063 if (POINTER_SET (ic))
6065 emitDebug ("; genAssign (pointer)");
6070 emitDebug ("; genAssign");
6076 emitDebug ("; genIfx");
6081 emitDebug ("; genAddrOf");
6086 emitDebug ("; genJumpTab");
6091 emitDebug ("; genCast");
6096 emitDebug ("; genReceive");
6101 emitDebug ("; addSet");
6102 addSet (&_G.sendSet, ic);
6111 /* piCode(ic,stdout); */
6117 /* now we are ready to call the
6118 peep hole optimizer */
6119 if (!options.nopeep)
6120 peepHole (&_G.lines.head);
6122 /* This is unfortunate */
6123 /* now do the actual printing */
6125 FILE *fp = codeOutFile;
6126 if (isInHome () && codeOutFile == code->oFile)
6127 codeOutFile = home->oFile;
6128 printLine (_G.lines.head, codeOutFile);
6129 if (_G.flushStatics)
6132 _G.flushStatics = 0;
6141 _isPairUsed (iCode * ic, PAIR_ID pairId)
6147 if (bitVectBitValue (ic->rMask, D_IDX))
6149 if (bitVectBitValue (ic->rMask, E_IDX))