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 ("; Can't optimise plus by inc, falling back to the normal way");
2753 size = getDataSize (IC_RESULT (ic));
2755 /* Special case when left and right are constant */
2756 if (isPair (AOP (IC_RESULT (ic))))
2759 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
2760 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
2762 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
2768 sprintf (buffer, "#(%s + %s)", left, right);
2769 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
2774 if (isPair (AOP (IC_RIGHT (ic))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
2776 /* Fetch into HL then do the add */
2777 spillPair (PAIR_HL);
2778 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
2779 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
2784 ld hl,sp+n trashes C so we cant afford to do it during an
2785 add with stack based varibles. Worst case is:
2798 So you cant afford to load up hl if either left, right, or result
2799 is on the stack (*sigh*) The alt is:
2807 Combinations in here are:
2808 * If left or right are in bc then the loss is small - trap later
2809 * If the result is in bc then the loss is also small
2813 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
2814 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
2815 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
2817 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
2818 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
2819 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
2820 AOP_SIZE (IC_RIGHT (ic)) <= 2))
2822 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
2824 /* Swap left and right */
2825 operand *t = IC_RIGHT (ic);
2826 IC_RIGHT (ic) = IC_LEFT (ic);
2829 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
2831 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
2832 emit2 ("add hl,bc");
2836 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
2837 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
2838 emit2 ("add hl,de");
2840 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
2845 wassertl (0, "Hit bad case for add");
2852 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
2854 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
2857 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2860 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2864 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
2867 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2870 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2872 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2876 freeAsmop (IC_LEFT (ic), NULL, ic);
2877 freeAsmop (IC_RIGHT (ic), NULL, ic);
2878 freeAsmop (IC_RESULT (ic), NULL, ic);
2882 /*-----------------------------------------------------------------*/
2883 /* genMinusDec :- does subtraction with deccrement if possible */
2884 /*-----------------------------------------------------------------*/
2886 genMinusDec (iCode * ic)
2888 unsigned int icount;
2889 unsigned int size = getDataSize (IC_RESULT (ic));
2891 /* will try to generate an increment */
2892 /* if the right side is not a literal we cannot */
2893 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
2896 /* if the literal value of the right hand side
2897 is greater than 4 then it is not worth it */
2898 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
2901 size = getDataSize (IC_RESULT (ic));
2903 /* if decrement 16 bits in register */
2904 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
2905 (size > 1) && isPair (AOP (IC_RESULT (ic))))
2908 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
2912 /* If result is a pair */
2913 if (isPair (AOP (IC_RESULT (ic))))
2915 movLeft2Result (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0);
2916 movLeft2Result (IC_LEFT (ic), 1, IC_RESULT (ic), 1, 0);
2918 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
2922 /* if increment 16 bits in register */
2923 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
2926 fetchPair (PAIR_HL, AOP (IC_RESULT (ic)));
2931 aopPut (AOP (IC_RESULT (ic)), "l", LSB);
2932 aopPut (AOP (IC_RESULT (ic)), "h", MSB16);
2938 /* if the sizes are greater than 1 then we cannot */
2939 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
2940 AOP_SIZE (IC_LEFT (ic)) > 1)
2943 /* we can if the aops of the left & result match or if they are in
2944 registers and the registers are the same */
2945 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2948 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
2955 /*-----------------------------------------------------------------*/
2956 /* genMinus - generates code for subtraction */
2957 /*-----------------------------------------------------------------*/
2959 genMinus (iCode * ic)
2961 int size, offset = 0;
2962 unsigned long lit = 0L;
2964 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2965 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
2966 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2968 /* special cases :- */
2969 /* if both left & right are in bit space */
2970 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
2971 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
2977 /* if I can do an decrement instead of subtract then GOOD for ME */
2978 if (genMinusDec (ic) == TRUE)
2981 size = getDataSize (IC_RESULT (ic));
2983 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
2988 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
2992 /* Same logic as genPlus */
2995 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
2996 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
2997 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
2999 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3000 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3001 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3002 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3004 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3005 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3007 if (left == PAIR_INVALID && right == PAIR_INVALID)
3012 else if (right == PAIR_INVALID)
3014 else if (left == PAIR_INVALID)
3017 fetchPair (left, AOP (IC_LEFT (ic)));
3018 /* Order is important. Right may be HL */
3019 fetchPair (right, AOP (IC_RIGHT (ic)));
3021 emit2 ("ld a,%s", _pairs[left].l);
3022 emit2 ("sub a,%s", _pairs[right].l);
3024 emit2 ("ld a,%s", _pairs[left].h);
3025 emit2 ("sbc a,%s", _pairs[right].h);
3027 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3028 aopPut (AOP (IC_RESULT (ic)), "e", 0);
3033 emitDebug ("; WARNING: This sub is probably broken.\n");
3038 /* if literal, add a,#-lit, else normal subb */
3041 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3042 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3046 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3049 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3053 /* first add without previous c */
3055 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
3057 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3059 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3062 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3063 AOP_SIZE (IC_LEFT (ic)) == 3 &&
3064 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3068 freeAsmop (IC_LEFT (ic), NULL, ic);
3069 freeAsmop (IC_RIGHT (ic), NULL, ic);
3070 freeAsmop (IC_RESULT (ic), NULL, ic);
3073 /*-----------------------------------------------------------------*/
3074 /* genMult - generates code for multiplication */
3075 /*-----------------------------------------------------------------*/
3077 genMult (iCode * ic)
3079 /* Shouldn't occur - all done through function calls */
3083 /*-----------------------------------------------------------------*/
3084 /* genDiv - generates code for division */
3085 /*-----------------------------------------------------------------*/
3089 /* Shouldn't occur - all done through function calls */
3093 /*-----------------------------------------------------------------*/
3094 /* genMod - generates code for division */
3095 /*-----------------------------------------------------------------*/
3099 /* Shouldn't occur - all done through function calls */
3103 /*-----------------------------------------------------------------*/
3104 /* genIfxJump :- will create a jump depending on the ifx */
3105 /*-----------------------------------------------------------------*/
3107 genIfxJump (iCode * ic, char *jval)
3112 /* if true label then we jump if condition
3116 jlbl = IC_TRUE (ic);
3117 if (!strcmp (jval, "a"))
3121 else if (!strcmp (jval, "c"))
3125 else if (!strcmp (jval, "nc"))
3131 /* The buffer contains the bit on A that we should test */
3137 /* false label is present */
3138 jlbl = IC_FALSE (ic);
3139 if (!strcmp (jval, "a"))
3143 else if (!strcmp (jval, "c"))
3147 else if (!strcmp (jval, "nc"))
3153 /* The buffer contains the bit on A that we should test */
3157 /* Z80 can do a conditional long jump */
3158 if (!strcmp (jval, "a"))
3162 else if (!strcmp (jval, "c"))
3165 else if (!strcmp (jval, "nc"))
3170 emit2 ("bit %s,a", jval);
3172 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
3174 /* mark the icode as generated */
3179 _getPairIdName (PAIR_ID id)
3181 return _pairs[id].name;
3184 /** Generic compare for > or <
3187 genCmp (operand * left, operand * right,
3188 operand * result, iCode * ifx, int sign)
3190 int size, offset = 0;
3191 unsigned long lit = 0L;
3192 bool swap_sense = FALSE;
3194 /* if left & right are bit variables */
3195 if (AOP_TYPE (left) == AOP_CRY &&
3196 AOP_TYPE (right) == AOP_CRY)
3198 /* Cant happen on the Z80 */
3203 /* subtract right from left if at the
3204 end the carry flag is set then we know that
3205 left is greater than right */
3206 size = max (AOP_SIZE (left), AOP_SIZE (right));
3208 /* if unsigned char cmp with lit, just compare */
3210 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
3212 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3215 emit2 ("xor a,!immedbyte", 0x80);
3216 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
3219 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3225 If the left or the right is a lit:
3226 Load -lit into HL, add to right via, check sense.
3228 if (IS_GB && size == 2 && (AOP_TYPE (right) == AOP_LIT || AOP_TYPE (left) == AOP_LIT))
3230 PAIR_ID id = PAIR_DE;
3231 asmop *lit = AOP (right);
3232 asmop *op = AOP (left);
3235 if (AOP_TYPE (left) == AOP_LIT)
3243 emit2 ("ld e,%s", aopGet (op, 0, 0));
3244 emit2 ("ld a,%s", aopGet (op, 1, 0));
3245 emit2 ("xor a,!immedbyte", 0x80);
3250 id = getPairId (op);
3251 if (id == PAIR_INVALID)
3253 fetchPair (PAIR_DE, op);
3257 spillPair (PAIR_HL);
3258 emit2 ("ld hl,%s", fetchLitSpecial (lit, TRUE, sign));
3259 emit2 ("add hl,%s", _getPairIdName (id));
3262 if (AOP_TYPE (right) == AOP_LIT)
3264 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3265 /* optimize if(x < 0) or if(x >= 0) */
3270 /* No sign so it's always false */
3275 /* Just load in the top most bit */
3276 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
3277 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
3279 genIfxJump (ifx, "7");
3290 /* First setup h and l contaning the top most bytes XORed */
3291 bool fDidXor = FALSE;
3292 if (AOP_TYPE (left) == AOP_LIT)
3294 unsigned long lit = (unsigned long)
3295 floatFromVal (AOP (left)->aopu.aop_lit);
3296 emit2 ("ld %s,!immedbyte", _fTmp[0],
3297 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3301 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
3302 emit2 ("xor a,!immedbyte", 0x80);
3303 emit2 ("ld %s,a", _fTmp[0]);
3306 if (AOP_TYPE (right) == AOP_LIT)
3308 unsigned long lit = (unsigned long)
3309 floatFromVal (AOP (right)->aopu.aop_lit);
3310 emit2 ("ld %s,!immedbyte", _fTmp[1],
3311 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3315 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
3316 emit2 ("xor a,!immedbyte", 0x80);
3317 emit2 ("ld %s,a", _fTmp[1]);
3329 /* Do a long subtract */
3332 _moveA (aopGet (AOP (left), offset, FALSE));
3334 if (sign && size == 0)
3336 emit2 ("ld a,%s", _fTmp[0]);
3337 emit2 ("sbc a,%s", _fTmp[1]);
3341 /* Subtract through, propagating the carry */
3342 emit2 ("sbc a,%s", aopGet (AOP (right), offset++, FALSE));
3349 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
3351 outBitCLong (result, swap_sense);
3355 /* if the result is used in the next
3356 ifx conditional branch then generate
3357 code a little differently */
3359 genIfxJump (ifx, swap_sense ? "nc" : "c");
3361 outBitCLong (result, swap_sense);
3362 /* leave the result in acc */
3366 /*-----------------------------------------------------------------*/
3367 /* genCmpGt :- greater than comparison */
3368 /*-----------------------------------------------------------------*/
3370 genCmpGt (iCode * ic, iCode * ifx)
3372 operand *left, *right, *result;
3373 sym_link *letype, *retype;
3376 left = IC_LEFT (ic);
3377 right = IC_RIGHT (ic);
3378 result = IC_RESULT (ic);
3380 letype = getSpec (operandType (left));
3381 retype = getSpec (operandType (right));
3382 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
3383 /* assign the amsops */
3384 aopOp (left, ic, FALSE, FALSE);
3385 aopOp (right, ic, FALSE, FALSE);
3386 aopOp (result, ic, TRUE, FALSE);
3388 genCmp (right, left, result, ifx, sign);
3390 freeAsmop (left, NULL, ic);
3391 freeAsmop (right, NULL, ic);
3392 freeAsmop (result, NULL, ic);
3395 /*-----------------------------------------------------------------*/
3396 /* genCmpLt - less than comparisons */
3397 /*-----------------------------------------------------------------*/
3399 genCmpLt (iCode * ic, iCode * ifx)
3401 operand *left, *right, *result;
3402 sym_link *letype, *retype;
3405 left = IC_LEFT (ic);
3406 right = IC_RIGHT (ic);
3407 result = IC_RESULT (ic);
3409 letype = getSpec (operandType (left));
3410 retype = getSpec (operandType (right));
3411 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
3413 /* assign the amsops */
3414 aopOp (left, ic, FALSE, FALSE);
3415 aopOp (right, ic, FALSE, FALSE);
3416 aopOp (result, ic, TRUE, FALSE);
3418 genCmp (left, right, result, ifx, sign);
3420 freeAsmop (left, NULL, ic);
3421 freeAsmop (right, NULL, ic);
3422 freeAsmop (result, NULL, ic);
3425 /*-----------------------------------------------------------------*/
3426 /* gencjneshort - compare and jump if not equal */
3427 /*-----------------------------------------------------------------*/
3429 gencjneshort (operand * left, operand * right, symbol * lbl)
3431 int size = max (AOP_SIZE (left), AOP_SIZE (right));
3433 unsigned long lit = 0L;
3435 /* Swap the left and right if it makes the computation easier */
3436 if (AOP_TYPE (left) == AOP_LIT)
3443 if (AOP_TYPE (right) == AOP_LIT)
3444 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3446 /* if the right side is a literal then anything goes */
3447 if (AOP_TYPE (right) == AOP_LIT &&
3448 AOP_TYPE (left) != AOP_DIR)
3452 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3459 emit2 ("or a,%s", aopGet (AOP (left), offset, FALSE));
3466 emit2 ("jp nz,!tlabel", lbl->key + 100);
3472 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3473 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
3476 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
3477 emit2 ("jp nz,!tlabel", lbl->key + 100);
3482 /* if the right side is in a register or in direct space or
3483 if the left is a pointer register & right is not */
3484 else if (AOP_TYPE (right) == AOP_REG ||
3485 AOP_TYPE (right) == AOP_DIR ||
3486 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
3490 _moveA (aopGet (AOP (left), offset, FALSE));
3491 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
3492 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
3494 emit2 ("jp nz,!tlabel", lbl->key + 100);
3497 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3498 emit2 ("jp nz,!tlabel", lbl->key + 100);
3505 /* right is a pointer reg need both a & b */
3506 /* PENDING: is this required? */
3509 _moveA (aopGet (AOP (right), offset, FALSE));
3510 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
3511 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
3517 /*-----------------------------------------------------------------*/
3518 /* gencjne - compare and jump if not equal */
3519 /*-----------------------------------------------------------------*/
3521 gencjne (operand * left, operand * right, symbol * lbl)
3523 symbol *tlbl = newiTempLabel (NULL);
3525 gencjneshort (left, right, lbl);
3528 emit2 ("ld a,!one");
3529 emit2 ("!shortjp !tlabel", tlbl->key + 100);
3530 emitLabel (lbl->key + 100);
3532 emitLabel (tlbl->key + 100);
3535 /*-----------------------------------------------------------------*/
3536 /* genCmpEq - generates code for equal to */
3537 /*-----------------------------------------------------------------*/
3539 genCmpEq (iCode * ic, iCode * ifx)
3541 operand *left, *right, *result;
3543 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
3544 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
3545 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
3547 emitDebug ("; genCmpEq: left %u, right %u, result %u\n", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
3549 /* Swap operands if it makes the operation easier. ie if:
3550 1. Left is a literal.
3552 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
3554 operand *t = IC_RIGHT (ic);
3555 IC_RIGHT (ic) = IC_LEFT (ic);
3559 if (ifx && !AOP_SIZE (result))
3562 /* if they are both bit variables */
3563 if (AOP_TYPE (left) == AOP_CRY &&
3564 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
3570 tlbl = newiTempLabel (NULL);
3571 gencjneshort (left, right, tlbl);
3574 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
3575 emitLabel (tlbl->key + 100);
3579 /* PENDING: do this better */
3580 symbol *lbl = newiTempLabel (NULL);
3581 emit2 ("!shortjp !tlabel", lbl->key + 100);
3582 emitLabel (tlbl->key + 100);
3583 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
3584 emitLabel (lbl->key + 100);
3587 /* mark the icode as generated */
3592 /* if they are both bit variables */
3593 if (AOP_TYPE (left) == AOP_CRY &&
3594 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
3600 gencjne (left, right, newiTempLabel (NULL));
3601 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
3607 genIfxJump (ifx, "a");
3610 /* if the result is used in an arithmetic operation
3611 then put the result in place */
3612 if (AOP_TYPE (result) != AOP_CRY)
3616 /* leave the result in acc */
3620 freeAsmop (left, NULL, ic);
3621 freeAsmop (right, NULL, ic);
3622 freeAsmop (result, NULL, ic);
3625 /*-----------------------------------------------------------------*/
3626 /* ifxForOp - returns the icode containing the ifx for operand */
3627 /*-----------------------------------------------------------------*/
3629 ifxForOp (operand * op, iCode * ic)
3631 /* if true symbol then needs to be assigned */
3632 if (IS_TRUE_SYMOP (op))
3635 /* if this has register type condition and
3636 the next instruction is ifx with the same operand
3637 and live to of the operand is upto the ifx only then */
3639 ic->next->op == IFX &&
3640 IC_COND (ic->next)->key == op->key &&
3641 OP_SYMBOL (op)->liveTo <= ic->next->seq)
3647 /*-----------------------------------------------------------------*/
3648 /* genAndOp - for && operation */
3649 /*-----------------------------------------------------------------*/
3651 genAndOp (iCode * ic)
3653 operand *left, *right, *result;
3656 /* note here that && operations that are in an if statement are
3657 taken away by backPatchLabels only those used in arthmetic
3658 operations remain */
3659 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
3660 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
3661 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
3663 /* if both are bit variables */
3664 if (AOP_TYPE (left) == AOP_CRY &&
3665 AOP_TYPE (right) == AOP_CRY)
3671 tlbl = newiTempLabel (NULL);
3673 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3675 emitLabel (tlbl->key + 100);
3679 freeAsmop (left, NULL, ic);
3680 freeAsmop (right, NULL, ic);
3681 freeAsmop (result, NULL, ic);
3684 /*-----------------------------------------------------------------*/
3685 /* genOrOp - for || operation */
3686 /*-----------------------------------------------------------------*/
3688 genOrOp (iCode * ic)
3690 operand *left, *right, *result;
3693 /* note here that || operations that are in an
3694 if statement are taken away by backPatchLabels
3695 only those used in arthmetic operations remain */
3696 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
3697 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
3698 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
3700 /* if both are bit variables */
3701 if (AOP_TYPE (left) == AOP_CRY &&
3702 AOP_TYPE (right) == AOP_CRY)
3708 tlbl = newiTempLabel (NULL);
3710 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3712 emitLabel (tlbl->key + 100);
3716 freeAsmop (left, NULL, ic);
3717 freeAsmop (right, NULL, ic);
3718 freeAsmop (result, NULL, ic);
3721 /*-----------------------------------------------------------------*/
3722 /* isLiteralBit - test if lit == 2^n */
3723 /*-----------------------------------------------------------------*/
3725 isLiteralBit (unsigned long lit)
3727 unsigned long pw[32] =
3728 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
3729 0x100L, 0x200L, 0x400L, 0x800L,
3730 0x1000L, 0x2000L, 0x4000L, 0x8000L,
3731 0x10000L, 0x20000L, 0x40000L, 0x80000L,
3732 0x100000L, 0x200000L, 0x400000L, 0x800000L,
3733 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
3734 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
3737 for (idx = 0; idx < 32; idx++)
3743 /*-----------------------------------------------------------------*/
3744 /* jmpTrueOrFalse - */
3745 /*-----------------------------------------------------------------*/
3747 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
3749 // ugly but optimized by peephole
3752 symbol *nlbl = newiTempLabel (NULL);
3753 emit2 ("jp !tlabel", nlbl->key + 100);
3754 emitLabel (tlbl->key + 100);
3755 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
3756 emitLabel (nlbl->key + 100);
3760 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
3761 emitLabel (tlbl->key + 100);
3766 /*-----------------------------------------------------------------*/
3767 /* genAnd - code for and */
3768 /*-----------------------------------------------------------------*/
3770 genAnd (iCode * ic, iCode * ifx)
3772 operand *left, *right, *result;
3773 int size, offset = 0;
3774 unsigned long lit = 0L;
3777 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
3778 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
3779 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
3782 emitDebug ("; Type res[%d] = l[%d]&r[%d]",
3784 AOP_TYPE (left), AOP_TYPE (right));
3785 emitDebug ("; Size res[%d] = l[%d]&r[%d]",
3787 AOP_SIZE (left), AOP_SIZE (right));
3790 /* if left is a literal & right is not then exchange them */
3791 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
3792 AOP_NEEDSACC (left))
3794 operand *tmp = right;
3799 /* if result = right then exchange them */
3800 if (sameRegs (AOP (result), AOP (right)))
3802 operand *tmp = right;
3807 /* if right is bit then exchange them */
3808 if (AOP_TYPE (right) == AOP_CRY &&
3809 AOP_TYPE (left) != AOP_CRY)
3811 operand *tmp = right;
3815 if (AOP_TYPE (right) == AOP_LIT)
3816 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3818 size = AOP_SIZE (result);
3820 if (AOP_TYPE (left) == AOP_CRY)
3826 // if(val & 0xZZ) - size = 0, ifx != FALSE -
3827 // bit = val & 0xZZ - size = 1, ifx = FALSE -
3828 if ((AOP_TYPE (right) == AOP_LIT) &&
3829 (AOP_TYPE (result) == AOP_CRY) &&
3830 (AOP_TYPE (left) != AOP_CRY))
3832 int posbit = isLiteralBit (lit);
3837 _moveA (aopGet (AOP (left), posbit >> 3, FALSE));
3842 emit2 ("mov c,acc.%d", posbit & 0x07);
3849 sprintf (buffer, "%d", posbit & 0x07);
3850 genIfxJump (ifx, buffer);
3861 symbol *tlbl = newiTempLabel (NULL);
3862 int sizel = AOP_SIZE (left);
3870 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
3872 _moveA (aopGet (AOP (left), offset, FALSE));
3874 if ((posbit = isLiteralBit (bytelit)) != 0)
3877 emit2 ("jb acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
3881 if (bytelit != 0x0FFL)
3883 aopGet (AOP (right), offset, FALSE));
3887 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3892 // bit = left & literal
3896 emit2 ("!tlabeldef", tlbl->key + 100);
3898 // if(left & literal)
3902 jmpTrueOrFalse (ifx, tlbl);
3910 /* if left is same as result */
3911 if (sameRegs (AOP (result), AOP (left)))
3913 for (; size--; offset++)
3915 if (AOP_TYPE (right) == AOP_LIT)
3917 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
3922 aopPut (AOP (result), "!zero", offset);
3925 _moveA (aopGet (AOP (left), offset, FALSE));
3927 aopGet (AOP (right), offset, FALSE));
3928 aopPut (AOP (left), "a", offset);
3935 if (AOP_TYPE (left) == AOP_ACC)
3941 _moveA (aopGet (AOP (left), offset, FALSE));
3943 aopGet (AOP (right), offset, FALSE));
3944 aopPut (AOP (left), "a", offset);
3951 // left & result in different registers
3952 if (AOP_TYPE (result) == AOP_CRY)
3958 for (; (size--); offset++)
3961 // result = left & right
3962 if (AOP_TYPE (right) == AOP_LIT)
3964 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
3966 aopPut (AOP (result),
3967 aopGet (AOP (left), offset, FALSE),
3971 else if (bytelit == 0)
3973 aopPut (AOP (result), "!zero", offset);
3977 // faster than result <- left, anl result,right
3978 // and better if result is SFR
3979 if (AOP_TYPE (left) == AOP_ACC)
3980 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
3983 _moveA (aopGet (AOP (left), offset, FALSE));
3985 aopGet (AOP (right), offset, FALSE));
3987 aopPut (AOP (result), "a", offset);
3994 freeAsmop (left, NULL, ic);
3995 freeAsmop (right, NULL, ic);
3996 freeAsmop (result, NULL, ic);
3999 /*-----------------------------------------------------------------*/
4000 /* genOr - code for or */
4001 /*-----------------------------------------------------------------*/
4003 genOr (iCode * ic, iCode * ifx)
4005 operand *left, *right, *result;
4006 int size, offset = 0;
4007 unsigned long lit = 0L;
4009 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4010 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4011 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4014 emitDebug ("; Type res[%d] = l[%d]&r[%d]",
4016 AOP_TYPE (left), AOP_TYPE (right));
4017 emitDebug ("; Size res[%d] = l[%d]&r[%d]",
4019 AOP_SIZE (left), AOP_SIZE (right));
4022 /* if left is a literal & right is not then exchange them */
4023 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4024 AOP_NEEDSACC (left))
4026 operand *tmp = right;
4031 /* if result = right then exchange them */
4032 if (sameRegs (AOP (result), AOP (right)))
4034 operand *tmp = right;
4039 /* if right is bit then exchange them */
4040 if (AOP_TYPE (right) == AOP_CRY &&
4041 AOP_TYPE (left) != AOP_CRY)
4043 operand *tmp = right;
4047 if (AOP_TYPE (right) == AOP_LIT)
4048 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4050 size = AOP_SIZE (result);
4052 if (AOP_TYPE (left) == AOP_CRY)
4058 if ((AOP_TYPE (right) == AOP_LIT) &&
4059 (AOP_TYPE (result) == AOP_CRY) &&
4060 (AOP_TYPE (left) != AOP_CRY))
4066 /* if left is same as result */
4067 if (sameRegs (AOP (result), AOP (left)))
4069 for (; size--; offset++)
4071 if (AOP_TYPE (right) == AOP_LIT)
4073 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4077 _moveA (aopGet (AOP (left), offset, FALSE));
4079 aopGet (AOP (right), offset, FALSE));
4080 aopPut (AOP (result), "a", offset);
4085 if (AOP_TYPE (left) == AOP_ACC)
4086 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4089 _moveA (aopGet (AOP (left), offset, FALSE));
4091 aopGet (AOP (right), offset, FALSE));
4092 aopPut (AOP (result), "a", offset);
4099 // left & result in different registers
4100 if (AOP_TYPE (result) == AOP_CRY)
4105 for (; (size--); offset++)
4108 // result = left & right
4109 if (AOP_TYPE (right) == AOP_LIT)
4111 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4113 aopPut (AOP (result),
4114 aopGet (AOP (left), offset, FALSE),
4119 // faster than result <- left, anl result,right
4120 // and better if result is SFR
4121 if (AOP_TYPE (left) == AOP_ACC)
4122 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4125 _moveA (aopGet (AOP (left), offset, FALSE));
4127 aopGet (AOP (right), offset, FALSE));
4129 aopPut (AOP (result), "a", offset);
4130 /* PENDING: something weird is going on here. Add exception. */
4131 if (AOP_TYPE (result) == AOP_ACC)
4137 freeAsmop (left, NULL, ic);
4138 freeAsmop (right, NULL, ic);
4139 freeAsmop (result, NULL, ic);
4142 /*-----------------------------------------------------------------*/
4143 /* genXor - code for xclusive or */
4144 /*-----------------------------------------------------------------*/
4146 genXor (iCode * ic, iCode * ifx)
4148 operand *left, *right, *result;
4149 int size, offset = 0;
4150 unsigned long lit = 0L;
4152 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4153 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4154 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4156 /* if left is a literal & right is not then exchange them */
4157 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4158 AOP_NEEDSACC (left))
4160 operand *tmp = right;
4165 /* if result = right then exchange them */
4166 if (sameRegs (AOP (result), AOP (right)))
4168 operand *tmp = right;
4173 /* if right is bit then exchange them */
4174 if (AOP_TYPE (right) == AOP_CRY &&
4175 AOP_TYPE (left) != AOP_CRY)
4177 operand *tmp = right;
4181 if (AOP_TYPE (right) == AOP_LIT)
4182 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4184 size = AOP_SIZE (result);
4186 if (AOP_TYPE (left) == AOP_CRY)
4192 if ((AOP_TYPE (right) == AOP_LIT) &&
4193 (AOP_TYPE (result) == AOP_CRY) &&
4194 (AOP_TYPE (left) != AOP_CRY))
4200 /* if left is same as result */
4201 if (sameRegs (AOP (result), AOP (left)))
4203 for (; size--; offset++)
4205 if (AOP_TYPE (right) == AOP_LIT)
4207 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4211 _moveA (aopGet (AOP (right), offset, FALSE));
4213 aopGet (AOP (left), offset, FALSE));
4214 aopPut (AOP (result), "a", offset);
4219 if (AOP_TYPE (left) == AOP_ACC)
4221 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4225 _moveA (aopGet (AOP (right), offset, FALSE));
4227 aopGet (AOP (left), offset, FALSE));
4228 aopPut (AOP (result), "a", 0);
4235 // left & result in different registers
4236 if (AOP_TYPE (result) == AOP_CRY)
4241 for (; (size--); offset++)
4244 // result = left & right
4245 if (AOP_TYPE (right) == AOP_LIT)
4247 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4249 aopPut (AOP (result),
4250 aopGet (AOP (left), offset, FALSE),
4255 // faster than result <- left, anl result,right
4256 // and better if result is SFR
4257 if (AOP_TYPE (left) == AOP_ACC)
4259 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4263 _moveA (aopGet (AOP (right), offset, FALSE));
4265 aopGet (AOP (left), offset, FALSE));
4267 aopPut (AOP (result), "a", offset);
4272 freeAsmop (left, NULL, ic);
4273 freeAsmop (right, NULL, ic);
4274 freeAsmop (result, NULL, ic);
4277 /*-----------------------------------------------------------------*/
4278 /* genInline - write the inline code out */
4279 /*-----------------------------------------------------------------*/
4281 genInline (iCode * ic)
4283 char *buffer, *bp, *bp1;
4285 _G.lines.isInline += (!options.asmpeep);
4287 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
4288 strcpy (buffer, IC_INLINE (ic));
4290 /* emit each line as a code */
4315 _G.lines.isInline -= (!options.asmpeep);
4319 /*-----------------------------------------------------------------*/
4320 /* genRRC - rotate right with carry */
4321 /*-----------------------------------------------------------------*/
4328 /*-----------------------------------------------------------------*/
4329 /* genRLC - generate code for rotate left with carry */
4330 /*-----------------------------------------------------------------*/
4337 /*-----------------------------------------------------------------*/
4338 /* genGetHbit - generates code get highest order bit */
4339 /*-----------------------------------------------------------------*/
4341 genGetHbit (iCode * ic)
4343 operand *left, *result;
4344 left = IC_LEFT (ic);
4345 result = IC_RESULT (ic);
4346 aopOp (left, ic, FALSE, FALSE);
4347 aopOp (result, ic, FALSE, FALSE);
4349 /* get the highest order byte into a */
4350 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4352 if (AOP_TYPE (result) == AOP_CRY)
4360 /* PENDING: For re-target. */
4366 freeAsmop (left, NULL, ic);
4367 freeAsmop (result, NULL, ic);
4371 emitRsh2 (asmop *aop, int size, int is_signed)
4377 const char *l = aopGet (aop, size, FALSE);
4380 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
4390 /*-----------------------------------------------------------------*/
4391 /* shiftR2Left2Result - shift right two bytes from left to result */
4392 /*-----------------------------------------------------------------*/
4394 shiftR2Left2Result (operand * left, int offl,
4395 operand * result, int offr,
4396 int shCount, int is_signed)
4399 symbol *tlbl, *tlbl1;
4401 movLeft2Result (left, offl, result, offr, 0);
4402 movLeft2Result (left, offl + 1, result, offr + 1, 0);
4404 /* if (AOP(result)->type == AOP_REG) { */
4406 tlbl = newiTempLabel (NULL);
4407 tlbl1 = newiTempLabel (NULL);
4409 /* Left is already in result - so now do the shift */
4414 emitRsh2 (AOP (result), size, is_signed);
4419 emit2 ("ld a,!immedbyte+1", shCount);
4420 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4421 emitLabel (tlbl->key + 100);
4423 emitRsh2 (AOP (result), size, is_signed);
4425 emitLabel (tlbl1->key + 100);
4427 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4431 /*-----------------------------------------------------------------*/
4432 /* shiftL2Left2Result - shift left two bytes from left to result */
4433 /*-----------------------------------------------------------------*/
4435 shiftL2Left2Result (operand * left, int offl,
4436 operand * result, int offr, int shCount)
4438 if (sameRegs (AOP (result), AOP (left)) &&
4439 ((offl + MSB16) == offr))
4445 /* Copy left into result */
4446 movLeft2Result (left, offl, result, offr, 0);
4447 movLeft2Result (left, offl + 1, result, offr + 1, 0);
4449 /* PENDING: for now just see if it'll work. */
4450 /*if (AOP(result)->type == AOP_REG) { */
4454 symbol *tlbl, *tlbl1;
4457 tlbl = newiTempLabel (NULL);
4458 tlbl1 = newiTempLabel (NULL);
4460 /* Left is already in result - so now do the shift */
4463 emit2 ("ld a,!immedbyte+1", shCount);
4464 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4465 emitLabel (tlbl->key + 100);
4471 l = aopGet (AOP (result), offset, FALSE);
4479 emitLabel (tlbl1->key + 100);
4481 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4486 /*-----------------------------------------------------------------*/
4487 /* AccRol - rotate left accumulator by known count */
4488 /*-----------------------------------------------------------------*/
4490 AccRol (int shCount)
4492 shCount &= 0x0007; // shCount : 0..7
4531 /*-----------------------------------------------------------------*/
4532 /* AccLsh - left shift accumulator by known count */
4533 /*-----------------------------------------------------------------*/
4535 AccLsh (int shCount)
4537 static const unsigned char SLMask[] =
4539 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
4548 else if (shCount == 2)
4555 /* rotate left accumulator */
4557 /* and kill the lower order bits */
4558 emit2 ("and a,!immedbyte", SLMask[shCount]);
4563 /*-----------------------------------------------------------------*/
4564 /* shiftL1Left2Result - shift left one byte from left to result */
4565 /*-----------------------------------------------------------------*/
4567 shiftL1Left2Result (operand * left, int offl,
4568 operand * result, int offr, int shCount)
4571 l = aopGet (AOP (left), offl, FALSE);
4573 /* shift left accumulator */
4575 aopPut (AOP (result), "a", offr);
4579 /*-----------------------------------------------------------------*/
4580 /* genlshTwo - left shift two bytes by known amount != 0 */
4581 /*-----------------------------------------------------------------*/
4583 genlshTwo (operand * result, operand * left, int shCount)
4585 int size = AOP_SIZE (result);
4587 wassert (size == 2);
4589 /* if shCount >= 8 */
4597 movLeft2Result (left, LSB, result, MSB16, 0);
4598 aopPut (AOP (result), "!zero", 0);
4599 shiftL1Left2Result (left, MSB16, result, MSB16, shCount);
4603 movLeft2Result (left, LSB, result, MSB16, 0);
4604 aopPut (AOP (result), "!zero", 0);
4609 aopPut (AOP (result), "!zero", LSB);
4612 /* 1 <= shCount <= 7 */
4621 shiftL2Left2Result (left, LSB, result, LSB, shCount);
4626 /*-----------------------------------------------------------------*/
4627 /* genlshOne - left shift a one byte quantity by known count */
4628 /*-----------------------------------------------------------------*/
4630 genlshOne (operand * result, operand * left, int shCount)
4632 shiftL1Left2Result (left, LSB, result, LSB, shCount);
4635 /*-----------------------------------------------------------------*/
4636 /* genLeftShiftLiteral - left shifting by known count */
4637 /*-----------------------------------------------------------------*/
4639 genLeftShiftLiteral (operand * left,
4644 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
4647 freeAsmop (right, NULL, ic);
4649 aopOp (left, ic, FALSE, FALSE);
4650 aopOp (result, ic, FALSE, FALSE);
4652 size = getSize (operandType (result));
4655 emitDebug ("; shift left result %d, left %d", size,
4659 /* I suppose that the left size >= result size */
4665 else if (shCount >= (size * 8))
4669 aopPut (AOP (result), "!zero", size);
4677 genlshOne (result, left, shCount);
4680 genlshTwo (result, left, shCount);
4683 wassertl (0, "Shifting of longs is currently unsupported");
4689 freeAsmop (left, NULL, ic);
4690 freeAsmop (result, NULL, ic);
4693 /*-----------------------------------------------------------------*/
4694 /* genLeftShift - generates code for left shifting */
4695 /*-----------------------------------------------------------------*/
4697 genLeftShift (iCode * ic)
4701 symbol *tlbl, *tlbl1;
4702 operand *left, *right, *result;
4704 right = IC_RIGHT (ic);
4705 left = IC_LEFT (ic);
4706 result = IC_RESULT (ic);
4708 aopOp (right, ic, FALSE, FALSE);
4710 /* if the shift count is known then do it
4711 as efficiently as possible */
4712 if (AOP_TYPE (right) == AOP_LIT)
4714 genLeftShiftLiteral (left, right, result, ic);
4718 /* shift count is unknown then we have to form a loop get the loop
4719 count in B : Note: we take only the lower order byte since
4720 shifting more that 32 bits make no sense anyway, ( the largest
4721 size of an object can be only 32 bits ) */
4722 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
4724 freeAsmop (right, NULL, ic);
4725 aopOp (left, ic, FALSE, FALSE);
4726 aopOp (result, ic, FALSE, FALSE);
4728 /* now move the left to the result if they are not the
4731 if (!sameRegs (AOP (left), AOP (result)))
4734 size = AOP_SIZE (result);
4738 l = aopGet (AOP (left), offset, FALSE);
4739 aopPut (AOP (result), l, offset);
4744 size = AOP_SIZE (result);
4748 l = aopGet (AOP (left), offset, FALSE);
4749 aopPut (AOP (result), l, offset);
4755 tlbl = newiTempLabel (NULL);
4756 size = AOP_SIZE (result);
4758 tlbl1 = newiTempLabel (NULL);
4760 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4761 emitLabel (tlbl->key + 100);
4762 l = aopGet (AOP (result), offset, FALSE);
4768 l = aopGet (AOP (result), offset++, FALSE);
4771 emitLabel (tlbl1->key + 100);
4773 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4775 freeAsmop (left, NULL, ic);
4776 freeAsmop (result, NULL, ic);
4779 /*-----------------------------------------------------------------*/
4780 /* genrshOne - left shift two bytes by known amount != 0 */
4781 /*-----------------------------------------------------------------*/
4783 genrshOne (operand * result, operand * left, int shCount, int is_signed)
4786 int size = AOP_SIZE (result);
4789 wassert (size == 1);
4790 wassert (shCount < 8);
4792 l = aopGet (AOP (left), 0, FALSE);
4796 if (AOP (result)->type == AOP_REG)
4798 aopPut (AOP (result), l, 0);
4799 l = aopGet (AOP (result), 0, FALSE);
4802 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
4810 emit2 ("%s a", is_signed ? "sra" : "srl");
4812 aopPut (AOP (result), "a", 0);
4816 /*-----------------------------------------------------------------*/
4817 /* AccRsh - right shift accumulator by known count */
4818 /*-----------------------------------------------------------------*/
4820 AccRsh (int shCount)
4822 static const unsigned char SRMask[] =
4824 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
4829 /* rotate right accumulator */
4830 AccRol (8 - shCount);
4831 /* and kill the higher order bits */
4832 emit2 ("and a,!immedbyte", SRMask[shCount]);
4836 /*-----------------------------------------------------------------*/
4837 /* shiftR1Left2Result - shift right one byte from left to result */
4838 /*-----------------------------------------------------------------*/
4840 shiftR1Left2Result (operand * left, int offl,
4841 operand * result, int offr,
4842 int shCount, int sign)
4844 _moveA (aopGet (AOP (left), offl, FALSE));
4853 aopPut (AOP (result), "a", offr);
4856 /*-----------------------------------------------------------------*/
4857 /* genrshTwo - right shift two bytes by known amount != 0 */
4858 /*-----------------------------------------------------------------*/
4860 genrshTwo (operand * result, operand * left,
4861 int shCount, int sign)
4863 /* if shCount >= 8 */
4869 shiftR1Left2Result (left, MSB16, result, LSB,
4874 movLeft2Result (left, MSB16, result, LSB, sign);
4876 aopPut (AOP (result), "!zero", 1);
4878 /* 1 <= shCount <= 7 */
4881 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
4885 /*-----------------------------------------------------------------*/
4886 /* genRightShiftLiteral - left shifting by known count */
4887 /*-----------------------------------------------------------------*/
4889 genRightShiftLiteral (operand * left,
4895 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
4898 freeAsmop (right, NULL, ic);
4900 aopOp (left, ic, FALSE, FALSE);
4901 aopOp (result, ic, FALSE, FALSE);
4903 size = getSize (operandType (result));
4905 emitDebug ("; shift right result %d, left %d", size,
4908 /* I suppose that the left size >= result size */
4914 else if (shCount >= (size * 8))
4916 aopPut (AOP (result), "!zero", size);
4922 genrshOne (result, left, shCount, sign);
4925 /* PENDING: sign support */
4926 genrshTwo (result, left, shCount, sign);
4929 wassertl (0, "Asked to shift right a long which should be a function call");
4932 wassertl (0, "Entered default case in right shift delegate");
4935 freeAsmop (left, NULL, ic);
4936 freeAsmop (result, NULL, ic);
4939 /*-----------------------------------------------------------------*/
4940 /* genRightShift - generate code for right shifting */
4941 /*-----------------------------------------------------------------*/
4943 genRightShift (iCode * ic)
4945 operand *right, *left, *result;
4947 int size, offset, first = 1;
4951 symbol *tlbl, *tlbl1;
4953 /* if signed then we do it the hard way preserve the
4954 sign bit moving it inwards */
4955 retype = getSpec (operandType (IC_RESULT (ic)));
4957 is_signed = !SPEC_USIGN (retype);
4959 /* signed & unsigned types are treated the same : i.e. the
4960 signed is NOT propagated inwards : quoting from the
4961 ANSI - standard : "for E1 >> E2, is equivalent to division
4962 by 2**E2 if unsigned or if it has a non-negative value,
4963 otherwise the result is implementation defined ", MY definition
4964 is that the sign does not get propagated */
4966 right = IC_RIGHT (ic);
4967 left = IC_LEFT (ic);
4968 result = IC_RESULT (ic);
4970 aopOp (right, ic, FALSE, FALSE);
4972 /* if the shift count is known then do it
4973 as efficiently as possible */
4974 if (AOP_TYPE (right) == AOP_LIT)
4976 genRightShiftLiteral (left, right, result, ic, is_signed);
4980 aopOp (left, ic, FALSE, FALSE);
4981 aopOp (result, ic, FALSE, FALSE);
4983 /* now move the left to the result if they are not the
4985 if (!sameRegs (AOP (left), AOP (result)) &&
4986 AOP_SIZE (result) > 1)
4989 size = AOP_SIZE (result);
4993 l = aopGet (AOP (left), offset, FALSE);
4994 aopPut (AOP (result), l, offset);
4999 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5001 freeAsmop (right, NULL, ic);
5003 tlbl = newiTempLabel (NULL);
5004 tlbl1 = newiTempLabel (NULL);
5005 size = AOP_SIZE (result);
5008 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5009 emitLabel (tlbl->key + 100);
5012 l = aopGet (AOP (result), offset--, FALSE);
5015 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5023 emitLabel (tlbl1->key + 100);
5025 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5027 freeAsmop (left, NULL, ic);
5028 freeAsmop (result, NULL, ic);
5031 /*-----------------------------------------------------------------*/
5032 /* genGenPointerGet - get value from generic pointer space */
5033 /*-----------------------------------------------------------------*/
5035 genGenPointerGet (operand * left,
5036 operand * result, iCode * ic)
5039 sym_link *retype = getSpec (operandType (result));
5045 aopOp (left, ic, FALSE, FALSE);
5046 aopOp (result, ic, FALSE, FALSE);
5048 if (isPair (AOP (left)) && AOP_SIZE (result) == 1)
5051 if (isPtrPair (AOP (left)))
5053 tsprintf (buffer, "!*pair", getPairName (AOP (left)));
5054 aopPut (AOP (result), buffer, 0);
5058 emit2 ("ld a,!*pair", getPairName (AOP (left)));
5059 aopPut (AOP (result), "a", 0);
5061 freeAsmop (left, NULL, ic);
5065 /* For now we always load into IY */
5066 /* if this is remateriazable */
5067 fetchPair (pair, AOP (left));
5069 /* so iy now contains the address */
5070 freeAsmop (left, NULL, ic);
5072 /* if bit then unpack */
5073 if (IS_BITVAR (retype))
5079 size = AOP_SIZE (result);
5084 /* PENDING: make this better */
5085 if (!IS_GB && AOP (result)->type == AOP_REG)
5087 aopPut (AOP (result), "!*hl", offset++);
5091 emit2 ("ld a,!*pair", _pairs[pair].name);
5092 aopPut (AOP (result), "a", offset++);
5096 emit2 ("inc %s", _pairs[pair].name);
5097 _G.pairs[pair].offset++;
5103 freeAsmop (result, NULL, ic);
5106 /*-----------------------------------------------------------------*/
5107 /* genPointerGet - generate code for pointer get */
5108 /*-----------------------------------------------------------------*/
5110 genPointerGet (iCode * ic)
5112 operand *left, *result;
5113 sym_link *type, *etype;
5115 left = IC_LEFT (ic);
5116 result = IC_RESULT (ic);
5118 /* depending on the type of pointer we need to
5119 move it to the correct pointer register */
5120 type = operandType (left);
5121 etype = getSpec (type);
5123 genGenPointerGet (left, result, ic);
5127 isRegOrLit (asmop * aop)
5129 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
5134 /*-----------------------------------------------------------------*/
5135 /* genGenPointerSet - stores the value into a pointer location */
5136 /*-----------------------------------------------------------------*/
5138 genGenPointerSet (operand * right,
5139 operand * result, iCode * ic)
5142 sym_link *retype = getSpec (operandType (right));
5143 PAIR_ID pairId = PAIR_HL;
5145 aopOp (result, ic, FALSE, FALSE);
5146 aopOp (right, ic, FALSE, FALSE);
5151 /* Handle the exceptions first */
5152 if (isPair (AOP (result)) && (AOP_SIZE (right) == 1))
5155 const char *l = aopGet (AOP (right), 0, FALSE);
5156 const char *pair = getPairName (AOP (result));
5157 if (canAssignToPtr (l) && isPtr (pair))
5159 emit2 ("ld !*pair,%s", pair, l);
5164 emit2 ("ld !*pair,a", pair);
5169 /* if the operand is already in dptr
5170 then we do nothing else we move the value to dptr */
5171 if (AOP_TYPE (result) != AOP_STR)
5173 fetchPair (pairId, AOP (result));
5175 /* so hl know contains the address */
5176 freeAsmop (result, NULL, ic);
5178 /* if bit then unpack */
5179 if (IS_BITVAR (retype))
5185 size = AOP_SIZE (right);
5190 const char *l = aopGet (AOP (right), offset, FALSE);
5191 if (isRegOrLit (AOP (right)) && !IS_GB)
5193 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
5198 emit2 ("ld !*pair,a", _pairs[pairId].name);
5202 emit2 ("inc %s", _pairs[pairId].name);
5203 _G.pairs[pairId].offset++;
5209 freeAsmop (right, NULL, ic);
5212 /*-----------------------------------------------------------------*/
5213 /* genPointerSet - stores the value into a pointer location */
5214 /*-----------------------------------------------------------------*/
5216 genPointerSet (iCode * ic)
5218 operand *right, *result;
5219 sym_link *type, *etype;
5221 right = IC_RIGHT (ic);
5222 result = IC_RESULT (ic);
5224 /* depending on the type of pointer we need to
5225 move it to the correct pointer register */
5226 type = operandType (result);
5227 etype = getSpec (type);
5229 genGenPointerSet (right, result, ic);
5232 /*-----------------------------------------------------------------*/
5233 /* genIfx - generate code for Ifx statement */
5234 /*-----------------------------------------------------------------*/
5236 genIfx (iCode * ic, iCode * popIc)
5238 operand *cond = IC_COND (ic);
5241 aopOp (cond, ic, FALSE, TRUE);
5243 /* get the value into acc */
5244 if (AOP_TYPE (cond) != AOP_CRY)
5248 /* the result is now in the accumulator */
5249 freeAsmop (cond, NULL, ic);
5251 /* if there was something to be popped then do it */
5255 /* if the condition is a bit variable */
5256 if (isbit && IS_ITEMP (cond) &&
5258 genIfxJump (ic, SPIL_LOC (cond)->rname);
5259 else if (isbit && !IS_ITEMP (cond))
5260 genIfxJump (ic, OP_SYMBOL (cond)->rname);
5262 genIfxJump (ic, "a");
5267 /*-----------------------------------------------------------------*/
5268 /* genAddrOf - generates code for address of */
5269 /*-----------------------------------------------------------------*/
5271 genAddrOf (iCode * ic)
5273 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
5275 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
5277 /* if the operand is on the stack then we
5278 need to get the stack offset of this
5285 if (sym->stack <= 0)
5287 emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset);
5291 emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
5298 emit2 ("ld de,!hashedstr", sym->rname);
5300 aopPut (AOP (IC_RESULT (ic)), "e", 0);
5301 aopPut (AOP (IC_RESULT (ic)), "d", 1);
5308 /* if it has an offset then we need to compute it */
5310 emit2 ("ld hl,#%d+%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset, _G.stack.param_offset);
5312 emit2 ("ld hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
5313 emit2 ("add hl,sp");
5317 emit2 ("ld hl,#%s", sym->rname);
5319 aopPut (AOP (IC_RESULT (ic)), "l", 0);
5320 aopPut (AOP (IC_RESULT (ic)), "h", 1);
5322 freeAsmop (IC_RESULT (ic), NULL, ic);
5325 /*-----------------------------------------------------------------*/
5326 /* genAssign - generate code for assignment */
5327 /*-----------------------------------------------------------------*/
5329 genAssign (iCode * ic)
5331 operand *result, *right;
5333 unsigned long lit = 0L;
5335 result = IC_RESULT (ic);
5336 right = IC_RIGHT (ic);
5339 /* Dont bother assigning if they are the same */
5340 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5342 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
5347 aopOp (right, ic, FALSE, FALSE);
5348 aopOp (result, ic, TRUE, FALSE);
5350 /* if they are the same registers */
5351 if (sameRegs (AOP (right), AOP (result)))
5353 emitDebug ("; (registers are the same)");
5357 /* if the result is a bit */
5358 if (AOP_TYPE (result) == AOP_CRY)
5364 size = AOP_SIZE (result);
5367 if (AOP_TYPE (right) == AOP_LIT)
5368 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5369 if (isPair (AOP (result)))
5371 fetchPair (getPairId (AOP (result)), AOP (right));
5373 else if ((size > 1) &&
5374 (AOP_TYPE (result) != AOP_REG) &&
5375 (AOP_TYPE (right) == AOP_LIT) &&
5376 !IS_FLOAT (operandType (right)) &&
5379 bool fXored = FALSE;
5381 /* Work from the top down.
5382 Done this way so that we can use the cached copy of 0
5383 in A for a fast clear */
5386 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
5388 if (!fXored && size > 1)
5395 aopPut (AOP (result), "a", offset);
5399 aopPut (AOP (result), "!zero", offset);
5403 aopPut (AOP (result),
5404 aopGet (AOP (right), offset, FALSE),
5409 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
5411 /* Special case. Load into a and d, then load out. */
5412 _moveA (aopGet (AOP (right), 0, FALSE));
5413 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
5414 aopPut (AOP (result), "a", 0);
5415 aopPut (AOP (result), "e", 1);
5421 /* PENDING: do this check better */
5422 if (requiresHL (AOP (right)) && requiresHL (AOP (result)))
5424 _moveA (aopGet (AOP (right), offset, FALSE));
5425 aopPut (AOP (result), "a", offset);
5428 aopPut (AOP (result),
5429 aopGet (AOP (right), offset, FALSE),
5436 freeAsmop (right, NULL, ic);
5437 freeAsmop (result, NULL, ic);
5440 /*-----------------------------------------------------------------*/
5441 /* genJumpTab - genrates code for jump table */
5442 /*-----------------------------------------------------------------*/
5444 genJumpTab (iCode * ic)
5449 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
5450 /* get the condition into accumulator */
5451 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
5454 emit2 ("ld e,%s", l);
5455 emit2 ("ld d,!zero");
5456 jtab = newiTempLabel (NULL);
5458 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
5459 emit2 ("add hl,de");
5460 emit2 ("add hl,de");
5461 emit2 ("add hl,de");
5462 freeAsmop (IC_JTCOND (ic), NULL, ic);
5466 emitLabel (jtab->key + 100);
5467 /* now generate the jump labels */
5468 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
5469 jtab = setNextItem (IC_JTLABELS (ic)))
5470 emit2 ("jp !tlabel", jtab->key + 100);
5473 /*-----------------------------------------------------------------*/
5474 /* genCast - gen code for casting */
5475 /*-----------------------------------------------------------------*/
5477 genCast (iCode * ic)
5479 operand *result = IC_RESULT (ic);
5480 sym_link *ctype = operandType (IC_LEFT (ic));
5481 operand *right = IC_RIGHT (ic);
5484 /* if they are equivalent then do nothing */
5485 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5488 aopOp (right, ic, FALSE, FALSE);
5489 aopOp (result, ic, FALSE, FALSE);
5491 /* if the result is a bit */
5492 if (AOP_TYPE (result) == AOP_CRY)
5497 /* if they are the same size : or less */
5498 if (AOP_SIZE (result) <= AOP_SIZE (right))
5501 /* if they are in the same place */
5502 if (sameRegs (AOP (right), AOP (result)))
5505 /* if they in different places then copy */
5506 size = AOP_SIZE (result);
5510 aopPut (AOP (result),
5511 aopGet (AOP (right), offset, FALSE),
5518 /* PENDING: should be OK. */
5520 /* if the result is of type pointer */
5527 /* so we now know that the size of destination is greater
5528 than the size of the source */
5529 /* we move to result for the size of source */
5530 size = AOP_SIZE (right);
5534 aopPut (AOP (result),
5535 aopGet (AOP (right), offset, FALSE),
5540 /* now depending on the sign of the destination */
5541 size = AOP_SIZE (result) - AOP_SIZE (right);
5542 /* Unsigned or not an integral type - right fill with zeros */
5543 if (SPEC_USIGN (ctype) || !IS_SPEC (ctype))
5546 aopPut (AOP (result), "!zero", offset++);
5550 /* we need to extend the sign :{ */
5551 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
5554 emitDebug ("; genCast: sign extend untested.");
5558 aopPut (AOP (result), "a", offset++);
5562 freeAsmop (right, NULL, ic);
5563 freeAsmop (result, NULL, ic);
5566 /*-----------------------------------------------------------------*/
5567 /* genReceive - generate code for a receive iCode */
5568 /*-----------------------------------------------------------------*/
5570 genReceive (iCode * ic)
5572 if (isOperandInFarSpace (IC_RESULT (ic)) &&
5573 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
5574 IS_TRUE_SYMOP (IC_RESULT (ic))))
5584 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
5585 size = AOP_SIZE(IC_RESULT(ic));
5587 for (i = 0; i < size; i++) {
5588 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
5592 freeAsmop (IC_RESULT (ic), NULL, ic);
5597 /** Maximum number of bytes to emit per line. */
5601 /** Context for the byte output chunker. */
5604 unsigned char buffer[DBEMIT_MAX_RUN];
5609 /** Flushes a byte chunker by writing out all in the buffer and
5613 _dbFlush(DBEMITCTX *self)
5620 sprintf(line, ".db 0x%02X", self->buffer[0]);
5622 for (i = 1; i < self->pos; i++)
5624 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
5631 /** Write out another byte, buffering until a decent line is
5635 _dbEmit(DBEMITCTX *self, int c)
5637 if (self->pos == DBEMIT_MAX_RUN)
5641 self->buffer[self->pos++] = c;
5644 /** Context for a simple run length encoder. */
5648 unsigned char buffer[128];
5650 /** runLen may be equivalent to pos. */
5656 RLE_CHANGE_COST = 4,
5660 /** Flush the buffer of a run length encoder by writing out the run or
5661 data that it currently contains.
5664 _rleCommit(RLECTX *self)
5670 memset(&db, 0, sizeof(db));
5672 emit2(".db %u", self->pos);
5674 for (i = 0; i < self->pos; i++)
5676 _dbEmit(&db, self->buffer[i]);
5685 Can get either a run or a block of random stuff.
5686 Only want to change state if a good run comes in or a run ends.
5687 Detecting run end is easy.
5690 Say initial state is in run, len zero, last zero. Then if you get a
5691 few zeros then something else then a short run will be output.
5692 Seems OK. While in run mode, keep counting. While in random mode,
5693 keep a count of the run. If run hits margin, output all up to run,
5694 restart, enter run mode.
5697 /** Add another byte into the run length encoder, flushing as
5698 required. The run length encoder uses the Amiga IFF style, where
5699 a block is prefixed by its run length. A positive length means
5700 the next n bytes pass straight through. A negative length means
5701 that the next byte is repeated -n times. A zero terminates the
5705 _rleAppend(RLECTX *self, int c)
5709 if (c != self->last)
5711 /* The run has stopped. See if it is worthwhile writing it out
5712 as a run. Note that the random data comes in as runs of
5715 if (self->runLen > RLE_CHANGE_COST)
5717 /* Yes, worthwhile. */
5718 /* Commit whatever was in the buffer. */
5720 emit2(".db -%u,0x%02X", self->runLen, self->last);
5724 /* Not worthwhile. Append to the end of the random list. */
5725 for (i = 0; i < self->runLen; i++)
5727 if (self->pos >= RLE_MAX_BLOCK)
5732 self->buffer[self->pos++] = self->last;
5740 if (self->runLen >= RLE_MAX_BLOCK)
5742 /* Commit whatever was in the buffer. */
5745 emit2 (".db -%u,0x%02X", self->runLen, self->last);
5753 _rleFlush(RLECTX *self)
5755 _rleAppend(self, -1);
5762 /** genArrayInit - Special code for initialising an array with constant
5766 genArrayInit (iCode * ic)
5770 int elementSize = 0, eIndex, i;
5771 unsigned val, lastVal;
5775 memset(&rle, 0, sizeof(rle));
5777 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
5779 if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD)
5781 /* Emit the support function call and the destination address. */
5782 emit2("call __initrleblock");
5783 emit2(".dw %s", aopGetWord (AOP(IC_LEFT(ic)), 0));
5787 wassertl (0, "Unexpected operand to genArrayInit.\n");
5790 type = operandType(IC_LEFT(ic));
5792 if (type && type->next)
5794 elementSize = getSize(type->next);
5798 wassertl (0, "Can't determine element size in genArrayInit.");
5801 iLoop = IC_ARRAYILIST(ic);
5802 lastVal = (unsigned)-1;
5804 /* Feed all the bytes into the run length encoder which will handle
5806 This works well for mixed char data, and for random int and long
5815 for (i = 0; i < ix; i++)
5817 for (eIndex = 0; eIndex < elementSize; eIndex++)
5819 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
5820 _rleAppend(&rle, val);
5825 iLoop = iLoop->next;
5829 /* Mark the end of the run. */
5832 freeAsmop (IC_LEFT(ic), NULL, ic);
5835 /*-----------------------------------------------------------------*/
5836 /* genZ80Code - generate code for Z80 based controllers */
5837 /*-----------------------------------------------------------------*/
5839 genZ80Code (iCode * lic)
5847 _fReturn = _gbz80_return;
5848 _fTmp = _gbz80_return;
5852 _fReturn = _z80_return;
5853 _fTmp = _z80_return;
5856 _G.lines.head = _G.lines.current = NULL;
5858 for (ic = lic; ic; ic = ic->next)
5861 if (cln != ic->lineno)
5863 emit2 ("; %s %d", ic->filename, ic->lineno);
5866 /* if the result is marked as
5867 spilt and rematerializable or code for
5868 this has already been generated then
5870 if (resultRemat (ic) || ic->generated)
5873 /* depending on the operation */
5877 emitDebug ("; genNot");
5882 emitDebug ("; genCpl");
5887 emitDebug ("; genUminus");
5892 emitDebug ("; genIpush");
5897 /* IPOP happens only when trying to restore a
5898 spilt live range, if there is an ifx statement
5899 following this pop then the if statement might
5900 be using some of the registers being popped which
5901 would destory the contents of the register so
5902 we need to check for this condition and handle it */
5904 ic->next->op == IFX &&
5905 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
5907 emitDebug ("; genIfx");
5908 genIfx (ic->next, ic);
5912 emitDebug ("; genIpop");
5918 emitDebug ("; genCall");
5923 emitDebug ("; genPcall");
5928 emitDebug ("; genFunction");
5933 emitDebug ("; genEndFunction");
5934 genEndFunction (ic);
5938 emitDebug ("; genRet");
5943 emitDebug ("; genLabel");
5948 emitDebug ("; genGoto");
5953 emitDebug ("; genPlus");
5958 emitDebug ("; genMinus");
5963 emitDebug ("; genMult");
5968 emitDebug ("; genDiv");
5973 emitDebug ("; genMod");
5978 emitDebug ("; genCmpGt");
5979 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
5983 emitDebug ("; genCmpLt");
5984 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
5991 /* note these two are xlated by algebraic equivalence
5992 during parsing SDCC.y */
5993 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
5994 "got '>=' or '<=' shouldn't have come here");
5998 emitDebug ("; genCmpEq");
5999 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
6003 emitDebug ("; genAndOp");
6008 emitDebug ("; genOrOp");
6013 emitDebug ("; genXor");
6014 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
6018 emitDebug ("; genOr");
6019 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
6023 emitDebug ("; genAnd");
6024 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
6028 emitDebug ("; genInline");
6033 emitDebug ("; genRRC");
6038 emitDebug ("; genRLC");
6043 emitDebug ("; genGetHBIT");
6048 emitDebug ("; genLeftShift");
6053 emitDebug ("; genRightShift");
6057 case GET_VALUE_AT_ADDRESS:
6058 emitDebug ("; genPointerGet");
6064 if (POINTER_SET (ic))
6066 emitDebug ("; genAssign (pointer)");
6071 emitDebug ("; genAssign");
6077 emitDebug ("; genIfx");
6082 emitDebug ("; genAddrOf");
6087 emitDebug ("; genJumpTab");
6092 emitDebug ("; genCast");
6097 emitDebug ("; genReceive");
6102 emitDebug ("; addSet");
6103 addSet (&_G.sendSet, ic);
6112 /* piCode(ic,stdout); */
6118 /* now we are ready to call the
6119 peep hole optimizer */
6120 if (!options.nopeep)
6121 peepHole (&_G.lines.head);
6123 /* This is unfortunate */
6124 /* now do the actual printing */
6126 FILE *fp = codeOutFile;
6127 if (isInHome () && codeOutFile == code->oFile)
6128 codeOutFile = home->oFile;
6129 printLine (_G.lines.head, codeOutFile);
6130 if (_G.flushStatics)
6133 _G.flushStatics = 0;
6142 _isPairUsed (iCode * ic, PAIR_ID pairId)
6148 if (bitVectBitValue (ic->rMask, D_IDX))
6150 if (bitVectBitValue (ic->rMask, E_IDX))