1 /*-------------------------------------------------------------------------
2 gen.c - Z80 specific code generator.
4 Michael Hope <michaelh@juju.net.nz> 2000
5 Based on the mcs51 generator -
6 Sandeep Dutta . sandeep.dutta@usa.net (1998)
7 and - Jean-Louis VERN.jlvern@writeme.com (1999)
9 This program is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 2, or (at your option) any
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 In other words, you are welcome to use, share and improve this program.
25 You are forbidden to forbid anyone else to use, share and improve
26 what you give them. Help stamp out software-hoarding!
28 -------------------------------------------------------------------------*/
31 Benchmarks on dhry.c 2.1 with 32766 loops and a 10ms clock:
33 Base with asm strcpy / strcmp / memcpy: 23198 141 1A14
34 Improved WORD push 22784 144 19AE
35 With label1 on 22694 144 197E
36 With label2 on 22743 144 198A
37 With label3 on 22776 144 1999
38 With label4 on 22776 144 1999
39 With all 'label' on 22661 144 196F
40 With loopInvariant on 20919 156 19AB
41 With loopInduction on Breaks 198B
42 With all working on 20796 158 196C
43 Slightly better genCmp(signed) 20597 159 195B
44 Better reg packing, first peephole 20038 163 1873
45 With assign packing 19281 165 1849
47 With reg params for mul and div 16234 202 162D
49 1. Starting again at 3 Aug 01 34965 93 219C
51 Includes long mul/div in code
52 2. Optimised memcpy for acc use 32102 102 226B
53 3. Optimised strcpy for acc use 27819 117 2237
54 3a Optimised memcpy fun
55 4. Optimised strcmp fun 21999 149 2294
56 5. Optimised strcmp further 21660 151 228C
57 6. Optimised memcpy by unroling 20885 157 2201
58 7. After turning loop induction on 19862 165 236D
59 8. Same as 7 but with more info
60 9. With asm optimised strings 17030 192 2223
62 10 and below are with asm strings off.
64 Apparent advantage of turning on regparams:
66 Decent case is push of a constant
67 - ld hl,#n; push hl: (10+11)*nargs
68 2. Cost of pull from stack
69 Using asm with ld hl, etc
70 - ld hl,#2; add hl,sp; (ld bc,(hl); hl+=2)*nargs
72 3. Cost of fixing stack
76 So cost is (10+11+7+6+7+10)*nargs+10+11
78 = 123 for mul, div, strcmp, strcpy
79 Saving of (98298+32766+32766+32766)*123 = 24181308
80 At 192 d/s for 682411768t, speed up to 199. Hmm.
88 #ifdef HAVE_SYS_ISA_DEFS_H
89 #include <sys/isa_defs.h>
93 #include "SDCCglobl.h"
94 #include "SDCCpeeph.h"
99 /* This is the down and dirty file with all kinds of kludgy & hacky
100 stuff. This is what it is all about CODE GENERATION for a specific MCU.
101 Some of the routines may be reusable, will have to see */
103 /* Z80 calling convention description.
104 Parameters are passed right to left. As the stack grows downwards,
105 the parameters are arranged in left to right in memory.
106 Parameters may be passed in the HL and DE registers with one
108 PENDING: What if the parameter is a long?
109 Everything is caller saves. i.e. the caller must save any registers
110 that it wants to preserve over the call.
111 GB: The return value is returned in DEHL. DE is normally used as a
112 working register pair. Caller saves allows it to be used for a
114 va args functions do not use register parameters. All arguments
115 are passed on the stack.
116 IX is used as an index register to the top of the local variable
117 area. ix-0 is the top most local variable.
122 /* Set to enable debugging trace statements in the output assembly code. */
126 static char *_z80_return[] =
127 {"l", "h", "e", "d"};
128 static char *_gbz80_return[] =
129 {"e", "d", "l", "h"};
130 static char *_fReceive[] =
131 { "c", "b", "e", "d" };
133 static char **_fReturn;
136 extern FILE *codeOutFile;
138 /** Enum covering all the possible register pairs.
157 } _pairs[NUM_PAIRS] = {
158 { "??1", "?2", "?3" },
163 { "iy", "iy.l?", "iy.h?" },
164 { "ix", "ix.l?", "ix.h?" }
168 #define ACC_NAME _pairs[PAIR_AF].h
170 #define RESULTONSTACK(x) \
171 (IC_RESULT(x) && IC_RESULT(x)->aop && \
172 IC_RESULT(x)->aop->type == AOP_STK )
182 /** Code generator persistent data.
186 /** Used to optimised setting up of a pair by remebering what it
187 contains and adjusting instead of reloading where possible.
208 const char *lastFunctionName;
214 /** TRUE if the registers have already been saved. */
227 static const char *aopGet (asmop * aop, int offset, bool bit16);
243 _getTempPairName(void)
245 return _pairs[_getTempPairId()].name;
251 /* Clean up the line so that it is 'prettier' */
252 if (strchr (buf, ':'))
254 /* Is a label - cant do anything */
257 /* Change the first (and probably only) ' ' to a tab so
272 _vemit2 (const char *szFormat, va_list ap)
276 tvsprintf (buffer, szFormat, ap);
279 _G.lines.current = (_G.lines.current ?
280 connectLine (_G.lines.current, newLineNode (buffer)) :
281 (_G.lines.head = newLineNode (buffer)));
283 _G.lines.current->isInline = _G.lines.isInline;
287 emit2 (const char *szFormat,...)
291 va_start (ap, szFormat);
293 _vemit2 (szFormat, ap);
299 emitDebug (const char *szFormat,...)
305 va_start (ap, szFormat);
307 _vemit2 (szFormat, ap);
313 /*-----------------------------------------------------------------*/
314 /* emit2 - writes the code into a file : for now it is simple */
315 /*-----------------------------------------------------------------*/
317 _emit2 (const char *inst, const char *fmt,...)
320 char lb[INITIAL_INLINEASM];
327 sprintf (lb, "%s\t", inst);
328 vsprintf (lb + (strlen (lb)), fmt, ap);
331 vsprintf (lb, fmt, ap);
333 while (isspace (*lbp))
338 _G.lines.current = (_G.lines.current ?
339 connectLine (_G.lines.current, newLineNode (lb)) :
340 (_G.lines.head = newLineNode (lb)));
342 _G.lines.current->isInline = _G.lines.isInline;
347 _emitMove(const char *to, const char *from)
349 if (strcasecmp(to, from) != 0)
351 emit2("ld %s,%s", to, from);
356 // Could leave this to the peephole, but sometimes the peephole is inhibited.
361 _moveA(const char *moveFrom)
363 // Let the peephole optimiser take care of redundent loads
364 _emitMove(ACC_NAME, moveFrom);
374 getPairName (asmop * aop)
376 if (aop->type == AOP_REG)
378 switch (aop->aopu.aop_reg[0]->rIdx)
391 else if (aop->type == AOP_STR)
393 switch (*aop->aopu.aop_str[0])
406 wassertl (0, "Tried to get the pair name of something that isn't a pair");
411 getPairId (asmop * aop)
415 if (aop->type == AOP_REG)
417 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX) && (aop->aopu.aop_reg[1]->rIdx == B_IDX))
421 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX) && (aop->aopu.aop_reg[1]->rIdx == D_IDX))
425 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX) && (aop->aopu.aop_reg[1]->rIdx == H_IDX))
430 if (aop->type == AOP_STR)
432 if (!strcmp (aop->aopu.aop_str[0], "c") && !strcmp (aop->aopu.aop_str[1], "b"))
436 if (!strcmp (aop->aopu.aop_str[0], "e") && !strcmp (aop->aopu.aop_str[1], "d"))
440 if (!strcmp (aop->aopu.aop_str[0], "l") && !strcmp (aop->aopu.aop_str[1], "h"))
449 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
453 return (getPairId (aop) != PAIR_INVALID);
457 isPtrPair (asmop * aop)
459 PAIR_ID pairId = getPairId (aop);
470 /** Push a register pair onto the stack */
472 genPairPush (asmop * aop)
474 emit2 ("push %s", getPairName (aop));
478 _push (PAIR_ID pairId)
480 emit2 ("push %s", _pairs[pairId].name);
481 _G.stack.pushed += 2;
485 _pop (PAIR_ID pairId)
487 emit2 ("pop %s", _pairs[pairId].name);
488 _G.stack.pushed -= 2;
491 /*-----------------------------------------------------------------*/
492 /* newAsmop - creates a new asmOp */
493 /*-----------------------------------------------------------------*/
495 newAsmop (short type)
499 aop = Safe_calloc (1, sizeof (asmop));
504 /*-----------------------------------------------------------------*/
505 /* aopForSym - for a true symbol */
506 /*-----------------------------------------------------------------*/
508 aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
515 wassert (sym->etype);
517 space = SPEC_OCLS (sym->etype);
519 /* if already has one */
523 /* Assign depending on the storage class */
524 if (sym->onStack || sym->iaccess)
526 emitDebug ("; AOP_STK for %s", sym->rname);
527 sym->aop = aop = newAsmop (AOP_STK);
528 aop->size = getSize (sym->type);
529 aop->aopu.aop_stk = sym->stack;
533 /* special case for a function */
534 if (IS_FUNC (sym->type))
536 sym->aop = aop = newAsmop (AOP_IMMD);
537 aop->aopu.aop_immd = Safe_calloc (1, strlen (sym->rname) + 1);
538 strcpy (aop->aopu.aop_immd, sym->rname);
545 /* if it is in direct space */
546 if (IN_REGSP (space) && !requires_a)
548 sym->aop = aop = newAsmop (AOP_SFR);
549 aop->aopu.aop_dir = sym->rname;
550 aop->size = getSize (sym->type);
551 emitDebug ("; AOP_SFR for %s", sym->rname);
556 /* only remaining is far space */
557 /* in which case DPTR gets the address */
560 emitDebug ("; AOP_HL for %s", sym->rname);
561 sym->aop = aop = newAsmop (AOP_HL);
565 sym->aop = aop = newAsmop (AOP_IY);
567 aop->size = getSize (sym->type);
568 aop->aopu.aop_dir = sym->rname;
570 /* if it is in code space */
571 if (IN_CODESPACE (space))
577 /*-----------------------------------------------------------------*/
578 /* aopForRemat - rematerialzes an object */
579 /*-----------------------------------------------------------------*/
581 aopForRemat (symbol * sym)
584 iCode *ic = sym->rematiCode;
585 asmop *aop = newAsmop (AOP_IMMD);
589 /* if plus or minus print the right hand side */
590 if (ic->op == '+' || ic->op == '-')
592 /* PENDING: for re-target */
593 sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
596 ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
599 /* we reached the end */
600 sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
604 aop->aopu.aop_immd = Safe_calloc (1, strlen (buffer) + 1);
605 strcpy (aop->aopu.aop_immd, buffer);
609 /*-----------------------------------------------------------------*/
610 /* regsInCommon - two operands have some registers in common */
611 /*-----------------------------------------------------------------*/
613 regsInCommon (operand * op1, operand * op2)
618 /* if they have registers in common */
619 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
622 sym1 = OP_SYMBOL (op1);
623 sym2 = OP_SYMBOL (op2);
625 if (sym1->nRegs == 0 || sym2->nRegs == 0)
628 for (i = 0; i < sym1->nRegs; i++)
634 for (j = 0; j < sym2->nRegs; j++)
639 if (sym2->regs[j] == sym1->regs[i])
647 /*-----------------------------------------------------------------*/
648 /* operandsEqu - equivalent */
649 /*-----------------------------------------------------------------*/
651 operandsEqu (operand * op1, operand * op2)
655 /* if they not symbols */
656 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
659 sym1 = OP_SYMBOL (op1);
660 sym2 = OP_SYMBOL (op2);
662 /* if both are itemps & one is spilt
663 and the other is not then false */
664 if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
665 sym1->isspilt != sym2->isspilt)
668 /* if they are the same */
672 if (strcmp (sym1->rname, sym2->rname) == 0)
676 /* if left is a tmp & right is not */
677 if (IS_ITEMP (op1) &&
680 (sym1->usl.spillLoc == sym2))
683 if (IS_ITEMP (op2) &&
687 (sym2->usl.spillLoc == sym1))
693 /*-----------------------------------------------------------------*/
694 /* sameRegs - two asmops have the same registers */
695 /*-----------------------------------------------------------------*/
697 sameRegs (asmop * aop1, asmop * aop2)
701 if (aop1->type == AOP_SFR ||
702 aop2->type == AOP_SFR)
708 if (aop1->type != AOP_REG ||
709 aop2->type != AOP_REG)
712 if (aop1->size != aop2->size)
715 for (i = 0; i < aop1->size; i++)
716 if (aop1->aopu.aop_reg[i] !=
717 aop2->aopu.aop_reg[i])
723 /*-----------------------------------------------------------------*/
724 /* aopOp - allocates an asmop for an operand : */
725 /*-----------------------------------------------------------------*/
727 aopOp (operand * op, iCode * ic, bool result, bool requires_a)
736 /* if this a literal */
737 if (IS_OP_LITERAL (op))
739 op->aop = aop = newAsmop (AOP_LIT);
740 aop->aopu.aop_lit = op->operand.valOperand;
741 aop->size = getSize (operandType (op));
745 /* if already has a asmop then continue */
749 /* if the underlying symbol has a aop */
750 if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
752 op->aop = OP_SYMBOL (op)->aop;
756 /* if this is a true symbol */
757 if (IS_TRUE_SYMOP (op))
759 op->aop = aopForSym (ic, OP_SYMBOL (op), result, requires_a);
763 /* this is a temporary : this has
769 e) can be a return use only */
771 sym = OP_SYMBOL (op);
773 /* if the type is a conditional */
774 if (sym->regType == REG_CND)
776 aop = op->aop = sym->aop = newAsmop (AOP_CRY);
781 /* if it is spilt then two situations
783 b) has a spill location */
784 if (sym->isspilt || sym->nRegs == 0)
786 /* rematerialize it NOW */
789 sym->aop = op->aop = aop =
791 aop->size = getSize (sym->type);
797 if (sym->accuse == ACCUSE_A)
799 aop = op->aop = sym->aop = newAsmop (AOP_ACC);
800 aop->size = getSize (sym->type);
801 wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
803 aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
805 else if (sym->accuse == ACCUSE_HL)
808 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
809 aop->size = getSize (sym->type);
810 wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
811 aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
812 aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
816 wassertl (0, "Marked as being allocated into A or HL but is actually in neither");
824 aop = op->aop = sym->aop = newAsmop (AOP_STR);
825 aop->size = getSize (sym->type);
826 for (i = 0; i < 4; i++)
827 aop->aopu.aop_str[i] = _fReturn[i];
831 /* else spill location */
832 sym->aop = op->aop = aop =
833 aopForSym (ic, sym->usl.spillLoc, result, requires_a);
834 aop->size = getSize (sym->type);
838 /* must be in a register */
839 sym->aop = op->aop = aop = newAsmop (AOP_REG);
840 aop->size = sym->nRegs;
841 for (i = 0; i < sym->nRegs; i++)
842 aop->aopu.aop_reg[i] = sym->regs[i];
845 /*-----------------------------------------------------------------*/
846 /* freeAsmop - free up the asmop given to an operand */
847 /*----------------------------------------------------------------*/
849 freeAsmop (operand * op, asmop * aaop, iCode * ic)
867 /* all other cases just dealloc */
873 OP_SYMBOL (op)->aop = NULL;
874 /* if the symbol has a spill */
876 SPIL_LOC (op)->aop = NULL;
882 isLitWord (asmop * aop)
884 /* if (aop->size != 2)
897 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
902 /* depending on type */
908 /* PENDING: for re-target */
911 tsprintf (s, "!hashedstr + %d", aop->aopu.aop_immd, offset);
913 else if (offset == 0)
915 tsprintf (s, "%s", aop->aopu.aop_immd);
919 tsprintf (s, "%s + %d", aop->aopu.aop_immd, offset);
925 value *val = aop->aopu.aop_lit;
926 /* if it is a float then it gets tricky */
927 /* otherwise it is fairly simple */
928 if (!IS_FLOAT (val->type))
930 unsigned long v = (unsigned long) floatFromVal (val);
936 else if (offset == 0)
942 wassertl(0, "Encountered an invalid offset while fetching a literal");
946 tsprintf (buffer, "!immedword", v);
948 tsprintf (buffer, "!constword", v);
950 return gc_strdup(buffer);
956 convertFloat (&f, floatFromVal (val));
958 tsprintf (buffer, "!immedword", f.w[offset / 2]);
960 tsprintf (buffer, "!constword", f.w[offset / 2]);
961 rs = Safe_calloc (1, strlen (buffer) + 1);
962 return strcpy (rs, buffer);
971 aopGetWord (asmop * aop, int offset)
973 return aopGetLitWordLong (aop, offset, TRUE);
977 isPtr (const char *s)
979 if (!strcmp (s, "hl"))
981 if (!strcmp (s, "ix"))
983 if (!strcmp (s, "iy"))
989 adjustPair (const char *pair, int *pold, int new)
995 emit2 ("inc %s", pair);
1000 emit2 ("dec %s", pair);
1006 spillPair (PAIR_ID pairId)
1008 _G.pairs[pairId].last_type = AOP_INVALID;
1009 _G.pairs[pairId].base = NULL;
1015 spillPair (PAIR_HL);
1016 spillPair (PAIR_IY);
1020 requiresHL (asmop * aop)
1034 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1036 const char *l, *base;
1037 const char *pair = _pairs[pairId].name;
1038 l = aopGetLitWordLong (left, offset, FALSE);
1039 base = aopGetLitWordLong (left, 0, FALSE);
1040 wassert (l && pair && base);
1044 if (pairId == PAIR_HL || pairId == PAIR_IY)
1046 if (_G.pairs[pairId].last_type == left->type)
1048 if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1050 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1052 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1055 if (pairId == PAIR_IY && abs (offset) < 127)
1062 _G.pairs[pairId].last_type = left->type;
1063 _G.pairs[pairId].base = gc_strdup (base);
1064 _G.pairs[pairId].offset = offset;
1066 /* Both a lit on the right and a true symbol on the left */
1067 emit2 ("ld %s,!hashedstr", pair, l);
1071 fetchPairLong (PAIR_ID pairId, asmop * aop, int offset)
1073 /* if this is remateriazable */
1074 if (isLitWord (aop)) {
1075 fetchLitPair (pairId, aop, offset);
1078 /* we need to get it byte by byte */
1079 if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1080 aopGet (aop, offset, FALSE);
1081 switch (aop->size - offset) {
1083 emit2 ("ld l,!*hl");
1084 emit2 ("ld h,!immedbyte", 0);
1087 // PENDING: Requires that you are only fetching two bytes.
1090 emit2 ("ld h,!*hl");
1094 wassertl (0, "Attempted to fetch too much data into HL");
1098 else if (IS_Z80 && aop->type == AOP_IY) {
1099 /* Instead of fetching relative to IY, just grab directly
1100 from the address IY refers to */
1101 char *l = aopGetLitWordLong (aop, offset, FALSE);
1103 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1105 if (aop->size < 2) {
1106 emit2("ld %s,!zero", _pairs[pairId].h);
1110 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1111 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1113 /* PENDING: check? */
1114 if (pairId == PAIR_HL)
1115 spillPair (PAIR_HL);
1120 fetchPair (PAIR_ID pairId, asmop * aop)
1122 fetchPairLong (pairId, aop, 0);
1126 fetchHL (asmop * aop)
1128 fetchPair (PAIR_HL, aop);
1132 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1134 assert (pairId == PAIR_HL || pairId == PAIR_IY);
1139 fetchLitPair (pairId, aop, 0);
1142 fetchLitPair (pairId, aop, offset);
1143 _G.pairs[pairId].offset = offset;
1147 /* Doesnt include _G.stack.pushed */
1148 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1149 if (aop->aopu.aop_stk > 0)
1151 abso += _G.stack.param_offset;
1153 assert (pairId == PAIR_HL);
1154 /* In some cases we can still inc or dec hl */
1155 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1157 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1161 emit2 ("!ldahlsp", abso + _G.stack.pushed);
1163 _G.pairs[pairId].offset = abso;
1169 _G.pairs[pairId].last_type = aop->type;
1175 emit2 ("!tlabeldef", key);
1179 /*-----------------------------------------------------------------*/
1180 /* aopGet - for fetching value of the aop */
1181 /*-----------------------------------------------------------------*/
1183 aopGet (asmop * aop, int offset, bool bit16)
1187 /* offset is greater than size then zero */
1188 /* PENDING: this seems a bit screwed in some pointer cases. */
1189 if (offset > (aop->size - 1) &&
1190 aop->type != AOP_LIT)
1192 tsprintf (s, "!zero");
1193 return gc_strdup(s);
1196 /* depending on type */
1200 /* PENDING: re-target */
1202 tsprintf (s, "!immedwords", aop->aopu.aop_immd);
1207 tsprintf (s, "!bankimmeds", aop->aopu.aop_immd);
1210 tsprintf (s, "!msbimmeds", aop->aopu.aop_immd);
1213 tsprintf (s, "!lsbimmeds", aop->aopu.aop_immd);
1216 wassertl (0, "Fetching from beyond the limits of an immediate value.");
1219 return gc_strdup(s);
1223 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1226 return gc_strdup(s);
1230 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1233 return gc_strdup(s);
1236 return aop->aopu.aop_reg[offset]->name;
1240 setupPair (PAIR_HL, aop, offset);
1241 tsprintf (s, "!*hl");
1243 return gc_strdup (s);
1247 setupPair (PAIR_IY, aop, offset);
1248 tsprintf (s, "!*iyx", offset);
1250 return gc_strdup(s);
1255 setupPair (PAIR_HL, aop, offset);
1256 tsprintf (s, "!*hl");
1260 if (aop->aopu.aop_stk >= 0)
1261 offset += _G.stack.param_offset;
1262 tsprintf (s, "!*ixx", aop->aopu.aop_stk + offset);
1265 return gc_strdup(s);
1268 wassertl (0, "Tried to fetch from a bit variable");
1277 tsprintf(s, "!zero");
1278 return gc_strdup(s);
1282 wassert (offset < 2);
1283 return aop->aopu.aop_str[offset];
1286 return aopLiteral (aop->aopu.aop_lit, offset);
1290 unsigned long v = aop->aopu.aop_simplelit;
1293 tsprintf (s, "!immedbyte", (unsigned int) v & 0xff);
1295 return gc_strdup(s);
1299 return aop->aopu.aop_str[offset];
1304 wassertl (0, "aopget got unsupported aop->type");
1309 isRegString (const char *s)
1311 if (!strcmp (s, "b") ||
1323 isConstant (const char *s)
1325 /* This is a bit of a hack... */
1326 return (*s == '#' || *s == '$');
1330 canAssignToPtr (const char *s)
1332 if (isRegString (s))
1339 /*-----------------------------------------------------------------*/
1340 /* aopPut - puts a string for a aop */
1341 /*-----------------------------------------------------------------*/
1343 aopPut (asmop * aop, const char *s, int offset)
1347 if (aop->size && offset > (aop->size - 1))
1349 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1350 "aopPut got offset > aop->size");
1355 tsprintf(buffer2, s);
1358 /* will assign value to value */
1359 /* depending on where it is ofcourse */
1365 if (strcmp (s, "a"))
1366 emit2 ("ld a,%s", s);
1367 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1372 if (strcmp (s, "a"))
1373 emit2 ("ld a,%s", s);
1374 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1378 if (!strcmp (s, "!*hl"))
1379 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1382 aop->aopu.aop_reg[offset]->name, s);
1387 setupPair (PAIR_IY, aop, offset);
1388 if (!canAssignToPtr (s))
1390 emit2 ("ld a,%s", s);
1391 emit2 ("ld !*iyx,a", offset);
1394 emit2 ("ld !*iyx,%s", offset, s);
1399 /* PENDING: for re-target */
1400 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1402 emit2 ("ld a,!*hl");
1405 setupPair (PAIR_HL, aop, offset);
1407 emit2 ("ld !*hl,%s", s);
1413 /* PENDING: re-target */
1414 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1416 emit2 ("ld a,!*hl");
1419 setupPair (PAIR_HL, aop, offset);
1420 if (!canAssignToPtr (s))
1422 emit2 ("ld a,%s", s);
1423 emit2 ("ld !*hl,a");
1426 emit2 ("ld !*hl,%s", s);
1430 if (aop->aopu.aop_stk >= 0)
1431 offset += _G.stack.param_offset;
1432 if (!canAssignToPtr (s))
1434 emit2 ("ld a,%s", s);
1435 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
1438 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
1443 /* if bit variable */
1444 if (!aop->aopu.aop_dir)
1451 /* In bit space but not in C - cant happen */
1452 wassertl (0, "Tried to write into a bit variable");
1458 if (strcmp (aop->aopu.aop_str[offset], s))
1460 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1466 if (!offset && (strcmp (s, "acc") == 0))
1470 wassertl (0, "Tried to access past the end of A");
1474 if (strcmp (aop->aopu.aop_str[offset], s))
1475 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1480 wassert (offset < 2);
1481 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1485 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1486 "aopPut got unsupported aop->type");
1491 #define AOP(op) op->aop
1492 #define AOP_TYPE(op) AOP(op)->type
1493 #define AOP_SIZE(op) AOP(op)->size
1494 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
1497 commitPair (asmop * aop, PAIR_ID id)
1499 if (id == PAIR_HL && requiresHL (aop))
1503 aopPut (aop, "a", 0);
1504 aopPut (aop, "d", 1);
1508 aopPut (aop, _pairs[id].l, 0);
1509 aopPut (aop, _pairs[id].h, 1);
1513 /*-----------------------------------------------------------------*/
1514 /* getDataSize - get the operand data size */
1515 /*-----------------------------------------------------------------*/
1517 getDataSize (operand * op)
1520 size = AOP_SIZE (op);
1524 wassertl (0, "Somehow got a three byte data pointer");
1529 /*-----------------------------------------------------------------*/
1530 /* movLeft2Result - move byte from left to result */
1531 /*-----------------------------------------------------------------*/
1533 movLeft2Result (operand * left, int offl,
1534 operand * result, int offr, int sign)
1537 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
1539 l = aopGet (AOP (left), offl, FALSE);
1543 aopPut (AOP (result), l, offr);
1547 if (getDataSize (left) == offl + 1)
1549 emit2 ("ld a,%s", l);
1550 aopPut (AOP (result), "a", offr);
1557 /** Put Acc into a register set
1560 outAcc (operand * result)
1563 size = getDataSize (result);
1566 aopPut (AOP (result), "a", 0);
1569 /* unsigned or positive */
1572 aopPut (AOP (result), "!zero", offset++);
1577 /** Take the value in carry and put it into a register
1580 outBitCLong (operand * result, bool swap_sense)
1582 /* if the result is bit */
1583 if (AOP_TYPE (result) == AOP_CRY)
1585 wassertl (0, "Tried to write carry to a bit");
1589 emit2 ("ld a,!zero");
1592 emit2 ("xor a,!immedbyte", 1);
1598 outBitC (operand * result)
1600 outBitCLong (result, FALSE);
1603 /*-----------------------------------------------------------------*/
1604 /* toBoolean - emit code for orl a,operator(sizeop) */
1605 /*-----------------------------------------------------------------*/
1607 _toBoolean (operand * oper)
1609 int size = AOP_SIZE (oper);
1613 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
1616 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
1620 if (AOP (oper)->type != AOP_ACC)
1623 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
1628 /*-----------------------------------------------------------------*/
1629 /* genNot - generate code for ! operation */
1630 /*-----------------------------------------------------------------*/
1634 sym_link *optype = operandType (IC_LEFT (ic));
1636 /* assign asmOps to operand & result */
1637 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
1638 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1640 /* if in bit space then a special case */
1641 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1643 wassertl (0, "Tried to negate a bit");
1646 /* if type float then do float */
1647 if (IS_FLOAT (optype))
1649 wassertl (0, "Tried to negate a float");
1652 _toBoolean (IC_LEFT (ic));
1657 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
1658 emit2 ("sub a,!one");
1659 outBitC (IC_RESULT (ic));
1661 /* release the aops */
1662 freeAsmop (IC_LEFT (ic), NULL, ic);
1663 freeAsmop (IC_RESULT (ic), NULL, ic);
1666 /*-----------------------------------------------------------------*/
1667 /* genCpl - generate code for complement */
1668 /*-----------------------------------------------------------------*/
1676 /* assign asmOps to operand & result */
1677 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1678 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1680 /* if both are in bit space then
1682 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1683 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1685 wassertl (0, "Left and the result are in bit space");
1688 size = AOP_SIZE (IC_RESULT (ic));
1691 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
1694 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1697 /* release the aops */
1698 freeAsmop (IC_LEFT (ic), NULL, ic);
1699 freeAsmop (IC_RESULT (ic), NULL, ic);
1703 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
1710 store de into result
1715 store de into result
1717 const char *first = isAdd ? "add" : "sub";
1718 const char *later = isAdd ? "adc" : "sbc";
1720 wassertl (IS_GB, "Code is only relevent to the gbz80");
1721 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
1723 fetchPair (PAIR_DE, left);
1726 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
1729 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
1732 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
1733 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
1735 fetchPairLong (PAIR_DE, left, MSB24);
1736 aopGet (right, MSB24, FALSE);
1740 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
1743 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
1745 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
1746 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
1750 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
1752 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
1755 /*-----------------------------------------------------------------*/
1756 /* genUminus - unary minus code generation */
1757 /*-----------------------------------------------------------------*/
1759 genUminus (iCode * ic)
1762 sym_link *optype, *rtype;
1765 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1766 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1768 /* if both in bit space then special
1770 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1771 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1773 wassertl (0, "Left and right are in bit space");
1777 optype = operandType (IC_LEFT (ic));
1778 rtype = operandType (IC_RESULT (ic));
1780 /* if float then do float stuff */
1781 if (IS_FLOAT (optype))
1783 wassertl (0, "Tried to do a unary minus on a float");
1787 /* otherwise subtract from zero */
1788 size = AOP_SIZE (IC_LEFT (ic));
1790 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
1792 /* Create a new asmop with value zero */
1793 asmop *azero = newAsmop (AOP_SIMPLELIT);
1794 azero->aopu.aop_simplelit = 0;
1796 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
1804 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
1805 emit2 ("ld a,!zero");
1806 emit2 ("sbc a,%s", l);
1807 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1810 /* if any remaining bytes in the result */
1811 /* we just need to propagate the sign */
1812 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
1817 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1821 /* release the aops */
1822 freeAsmop (IC_LEFT (ic), NULL, ic);
1823 freeAsmop (IC_RESULT (ic), NULL, ic);
1826 /*-----------------------------------------------------------------*/
1827 /* assignResultValue - */
1828 /*-----------------------------------------------------------------*/
1830 assignResultValue (operand * oper)
1832 int size = AOP_SIZE (oper);
1835 wassertl (size <= 4, "Got a result that is bigger than four bytes");
1836 topInA = requiresHL (AOP (oper));
1838 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
1840 /* We do it the hard way here. */
1842 aopPut (AOP (oper), _fReturn[0], 0);
1843 aopPut (AOP (oper), _fReturn[1], 1);
1845 aopPut (AOP (oper), _fReturn[0], 2);
1846 aopPut (AOP (oper), _fReturn[1], 3);
1852 aopPut (AOP (oper), _fReturn[size], size);
1858 _saveRegsForCall(iCode *ic, int sendSetSize)
1861 o Stack parameters are pushed before this function enters
1862 o DE and BC may be used in this function.
1863 o HL and DE may be used to return the result.
1864 o HL and DE may be used to send variables.
1865 o DE and BC may be used to store the result value.
1866 o HL may be used in computing the sent value of DE
1867 o The iPushes for other parameters occur before any addSets
1869 Logic: (to be run inside the first iPush or if none, before sending)
1870 o Compute if DE and/or BC are in use over the call
1871 o Compute if DE is used in the send set
1872 o Compute if DE and/or BC are used to hold the result value
1873 o If (DE is used, or in the send set) and is not used in the result, push.
1874 o If BC is used and is not in the result, push
1876 o If DE is used in the send set, fetch
1877 o If HL is used in the send set, fetch
1881 if (_G.saves.saved == FALSE) {
1882 bool deInUse, bcInUse;
1884 bool bcInRet = FALSE, deInRet = FALSE;
1887 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
1889 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
1890 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
1892 deSending = (sendSetSize > 1);
1894 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
1896 if (bcInUse && bcInRet == FALSE) {
1898 _G.stack.pushedBC = TRUE;
1900 if (deInUse && deInRet == FALSE) {
1902 _G.stack.pushedDE = TRUE;
1905 _G.saves.saved = TRUE;
1908 /* Already saved. */
1912 /*-----------------------------------------------------------------*/
1913 /* genIpush - genrate code for pushing this gets a little complex */
1914 /*-----------------------------------------------------------------*/
1916 genIpush (iCode * ic)
1918 int size, offset = 0;
1921 /* if this is not a parm push : ie. it is spill push
1922 and spill push is always done on the local stack */
1925 wassertl(0, "Encountered an unsupported spill push.");
1929 if (_G.saves.saved == FALSE) {
1930 /* Caller saves, and this is the first iPush. */
1931 /* Scan ahead until we find the function that we are pushing parameters to.
1932 Count the number of addSets on the way to figure out what registers
1933 are used in the send set.
1936 iCode *walk = ic->next;
1939 if (walk->op == SEND) {
1942 else if (walk->op == CALL || walk->op == PCALL) {
1951 _saveRegsForCall(walk, nAddSets);
1954 /* Already saved by another iPush. */
1957 /* then do the push */
1958 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1960 size = AOP_SIZE (IC_LEFT (ic));
1962 if (isPair (AOP (IC_LEFT (ic))))
1964 _G.stack.pushed += 2;
1965 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
1971 fetchHL (AOP (IC_LEFT (ic)));
1973 spillPair (PAIR_HL);
1974 _G.stack.pushed += 2;
1979 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
1981 spillPair (PAIR_HL);
1982 _G.stack.pushed += 2;
1983 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 0);
1985 spillPair (PAIR_HL);
1986 _G.stack.pushed += 2;
1992 if (AOP (IC_LEFT (ic))->type == AOP_IY)
1994 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
1996 emit2 ("ld a,(%s)", l);
2000 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2001 emit2 ("ld a,%s", l);
2009 freeAsmop (IC_LEFT (ic), NULL, ic);
2012 /*-----------------------------------------------------------------*/
2013 /* genIpop - recover the registers: can happen only for spilling */
2014 /*-----------------------------------------------------------------*/
2016 genIpop (iCode * ic)
2021 /* if the temp was not pushed then */
2022 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2025 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2026 size = AOP_SIZE (IC_LEFT (ic));
2027 offset = (size - 1);
2028 if (isPair (AOP (IC_LEFT (ic))))
2030 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2038 spillPair (PAIR_HL);
2039 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2043 freeAsmop (IC_LEFT (ic), NULL, ic);
2046 /* This is quite unfortunate */
2048 setArea (int inHome)
2051 static int lastArea = 0;
2053 if (_G.in_home != inHome) {
2055 const char *sz = port->mem.code_name;
2056 port->mem.code_name = "HOME";
2057 emit2("!area", CODE_NAME);
2058 port->mem.code_name = sz;
2061 emit2("!area", CODE_NAME); */
2062 _G.in_home = inHome;
2073 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2077 symbol *sym = OP_SYMBOL (op);
2079 if (sym->isspilt || sym->nRegs == 0)
2082 aopOp (op, ic, FALSE, FALSE);
2085 if (aop->type == AOP_REG)
2088 for (i = 0; i < aop->size; i++)
2090 if (pairId == PAIR_DE)
2092 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2093 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2095 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2098 else if (pairId == PAIR_BC)
2100 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2101 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2103 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2113 freeAsmop (IC_LEFT (ic), NULL, ic);
2117 /** Emit the code for a call statement
2120 emitCall (iCode * ic, bool ispcall)
2122 sym_link *detype = getSpec (operandType (IC_LEFT (ic)));
2124 bitVect *rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
2126 /* if caller saves & we have not saved then */
2132 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2134 /* if send set is not empty then assign */
2139 int nSend = elementsInSet(_G.sendSet);
2140 bool swapped = FALSE;
2142 int _z80_sendOrder[] = {
2147 /* Check if the parameters are swapped. If so route through hl instead. */
2148 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2150 sic = setFirstItem(_G.sendSet);
2151 sic = setNextItem(_G.sendSet);
2153 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2154 /* The second send value is loaded from one the one that holds the first
2155 send, i.e. it is overwritten. */
2156 /* Cache the first in HL, and load the second from HL instead. */
2157 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2158 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2164 for (sic = setFirstItem (_G.sendSet); sic;
2165 sic = setNextItem (_G.sendSet))
2168 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2170 size = AOP_SIZE (IC_LEFT (sic));
2171 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2172 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2174 // PENDING: Mild hack
2175 if (swapped == TRUE && send == 1) {
2177 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2180 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2182 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2185 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2189 freeAsmop (IC_LEFT (sic), NULL, sic);
2196 if (IS_BANKEDCALL (detype))
2198 werror (W_INDIR_BANKED);
2200 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2202 if (isLitWord (AOP (IC_LEFT (ic))))
2204 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2208 symbol *rlbl = newiTempLabel (NULL);
2209 spillPair (PAIR_HL);
2210 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2212 _G.stack.pushed += 2;
2214 fetchHL (AOP (IC_LEFT (ic)));
2216 emit2 ("!tlabeldef", (rlbl->key + 100));
2217 _G.stack.pushed -= 2;
2219 freeAsmop (IC_LEFT (ic), NULL, ic);
2223 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2224 OP_SYMBOL (IC_LEFT (ic))->rname :
2225 OP_SYMBOL (IC_LEFT (ic))->name;
2226 if (IS_BANKEDCALL (detype))
2228 emit2 ("call banked_call");
2229 emit2 ("!dws", name);
2230 emit2 ("!dw !bankimmeds", name);
2235 emit2 ("call %s", name);
2240 /* Mark the regsiters as restored. */
2241 _G.saves.saved = FALSE;
2243 /* if we need assign a result value */
2244 if ((IS_ITEMP (IC_RESULT (ic)) &&
2245 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2246 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2247 IS_TRUE_SYMOP (IC_RESULT (ic)))
2250 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2252 assignResultValue (IC_RESULT (ic));
2254 freeAsmop (IC_RESULT (ic), NULL, ic);
2257 /* adjust the stack for parameters if required */
2260 int i = ic->parmBytes;
2262 _G.stack.pushed -= i;
2265 emit2 ("!ldaspsp", i);
2272 emit2 ("ld hl,#%d", i);
2273 emit2 ("add hl,sp");
2290 if (_G.stack.pushedDE)
2292 bool dInUse = bitVectBitValue(rInUse, D_IDX);
2293 bool eInUse = bitVectBitValue(rInUse, E_IDX);
2295 if (dInUse && eInUse)
2311 wassertl (0, "Neither D or E were in use but it was pushed.");
2313 _G.stack.pushedDE = FALSE;
2316 if (_G.stack.pushedBC)
2318 bool bInUse = bitVectBitValue(rInUse, B_IDX);
2319 bool cInUse = bitVectBitValue(rInUse, C_IDX);
2321 // If both B and C are used in the return value, then we won't get
2323 if (bInUse && cInUse)
2339 wassertl (0, "Neither B or C were in use but it was pushed.");
2341 _G.stack.pushedBC = FALSE;
2345 /*-----------------------------------------------------------------*/
2346 /* genCall - generates a call statement */
2347 /*-----------------------------------------------------------------*/
2349 genCall (iCode * ic)
2351 emitCall (ic, FALSE);
2354 /*-----------------------------------------------------------------*/
2355 /* genPcall - generates a call by pointer statement */
2356 /*-----------------------------------------------------------------*/
2358 genPcall (iCode * ic)
2360 emitCall (ic, TRUE);
2363 /*-----------------------------------------------------------------*/
2364 /* resultRemat - result is rematerializable */
2365 /*-----------------------------------------------------------------*/
2367 resultRemat (iCode * ic)
2369 if (SKIP_IC (ic) || ic->op == IFX)
2372 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2374 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2375 if (sym->remat && !POINTER_SET (ic))
2382 extern set *publics;
2384 /*-----------------------------------------------------------------*/
2385 /* genFunction - generated code for function entry */
2386 /*-----------------------------------------------------------------*/
2388 genFunction (iCode * ic)
2390 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2394 bool bcInUse = FALSE;
2395 bool deInUse = FALSE;
2398 setArea (IS_NONBANKED (sym->etype));
2400 /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
2403 _G.receiveOffset = 0;
2405 /* Record the last function name for debugging. */
2406 _G.lastFunctionName = sym->rname;
2408 /* Create the function header */
2409 emit2 ("!functionheader", sym->name);
2410 /* PENDING: portability. */
2411 emit2 ("__%s_start:", sym->rname);
2412 emit2 ("!functionlabeldef", sym->rname);
2414 if (options.profile)
2416 emit2 ("!profileenter");
2419 fetype = getSpec (operandType (IC_LEFT (ic)));
2421 /* if critical function then turn interrupts off */
2422 if (SPEC_CRTCL (fetype))
2425 /* if this is an interrupt service routine then save all potentially used registers. */
2426 if (IS_ISR (sym->etype))
2431 /* PENDING: callee-save etc */
2433 _G.stack.param_offset = 0;
2436 /* Detect which registers are used. */
2440 for (i = 0; i < sym->regsUsed->size; i++)
2442 if (bitVectBitValue (sym->regsUsed, i))
2456 /* Other systems use DE as a temporary. */
2467 _G.stack.param_offset += 2;
2470 _G.stack.pushedBC = bcInUse;
2475 _G.stack.param_offset += 2;
2478 _G.stack.pushedDE = deInUse;
2481 /* adjust the stack for the function */
2482 _G.stack.last = sym->stack;
2485 emit2 ("!enterx", sym->stack);
2488 _G.stack.offset = sym->stack;
2491 /*-----------------------------------------------------------------*/
2492 /* genEndFunction - generates epilogue for functions */
2493 /*-----------------------------------------------------------------*/
2495 genEndFunction (iCode * ic)
2497 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2499 if (IS_ISR (sym->etype))
2501 wassertl (0, "Tried to close an interrupt support function");
2505 if (SPEC_CRTCL (sym->etype))
2508 /* PENDING: calleeSave */
2510 if (_G.stack.offset)
2512 emit2 ("!leavex", _G.stack.offset);
2520 if (_G.stack.pushedDE)
2523 _G.stack.pushedDE = FALSE;
2526 if (_G.stack.pushedDE)
2529 _G.stack.pushedDE = FALSE;
2533 if (options.profile)
2535 emit2 ("!profileexit");
2539 /* Both baned and non-banked just ret */
2542 /* PENDING: portability. */
2543 emit2 ("__%s_end:", sym->rname);
2545 _G.flushStatics = 1;
2546 _G.stack.pushed = 0;
2547 _G.stack.offset = 0;
2550 /*-----------------------------------------------------------------*/
2551 /* genRet - generate code for return statement */
2552 /*-----------------------------------------------------------------*/
2557 /* Errk. This is a hack until I can figure out how
2558 to cause dehl to spill on a call */
2559 int size, offset = 0;
2561 /* if we have no return value then
2562 just generate the "ret" */
2566 /* we have something to return then
2567 move the return value into place */
2568 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2569 size = AOP_SIZE (IC_LEFT (ic));
2571 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
2575 emit2 ("ld de,%s", l);
2579 emit2 ("ld hl,%s", l);
2584 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
2586 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
2587 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
2593 l = aopGet (AOP (IC_LEFT (ic)), offset,
2595 if (strcmp (_fReturn[offset], l))
2596 emit2 ("ld %s,%s", _fReturn[offset++], l);
2600 freeAsmop (IC_LEFT (ic), NULL, ic);
2603 /* generate a jump to the return label
2604 if the next is not the return statement */
2605 if (!(ic->next && ic->next->op == LABEL &&
2606 IC_LABEL (ic->next) == returnLabel))
2608 emit2 ("jp !tlabel", returnLabel->key + 100);
2611 /*-----------------------------------------------------------------*/
2612 /* genLabel - generates a label */
2613 /*-----------------------------------------------------------------*/
2615 genLabel (iCode * ic)
2617 /* special case never generate */
2618 if (IC_LABEL (ic) == entryLabel)
2621 emitLabel (IC_LABEL (ic)->key + 100);
2624 /*-----------------------------------------------------------------*/
2625 /* genGoto - generates a ljmp */
2626 /*-----------------------------------------------------------------*/
2628 genGoto (iCode * ic)
2630 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
2633 /*-----------------------------------------------------------------*/
2634 /* genPlusIncr :- does addition with increment if possible */
2635 /*-----------------------------------------------------------------*/
2637 genPlusIncr (iCode * ic)
2639 unsigned int icount;
2640 unsigned int size = getDataSize (IC_RESULT (ic));
2641 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
2643 /* will try to generate an increment */
2644 /* if the right side is not a literal
2646 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
2649 emitDebug ("; genPlusIncr");
2651 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
2653 /* If result is a pair */
2654 if (resultId != PAIR_INVALID)
2656 if (isLitWord (AOP (IC_LEFT (ic))))
2658 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
2661 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
2663 fetchPair (resultId, AOP (IC_RIGHT (ic)));
2664 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
2670 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2674 movLeft2Result (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0);
2675 movLeft2Result (IC_LEFT (ic), 1, IC_RESULT (ic), 1, 0);
2679 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
2684 /* if the literal value of the right hand side
2685 is greater than 4 then it is not worth it */
2689 /* if increment 16 bits in register */
2690 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
2696 symbol *tlbl = NULL;
2697 tlbl = newiTempLabel (NULL);
2700 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
2703 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
2706 emitLabel (tlbl->key + 100);
2710 /* if the sizes are greater than 1 then we cannot */
2711 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
2712 AOP_SIZE (IC_LEFT (ic)) > 1)
2715 /* we can if the aops of the left & result match or
2716 if they are in registers and the registers are the
2718 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2722 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
2730 /*-----------------------------------------------------------------*/
2731 /* outBitAcc - output a bit in acc */
2732 /*-----------------------------------------------------------------*/
2734 outBitAcc (operand * result)
2736 symbol *tlbl = newiTempLabel (NULL);
2737 /* if the result is a bit */
2738 if (AOP_TYPE (result) == AOP_CRY)
2740 wassertl (0, "Tried to write A into a bit");
2744 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
2745 emit2 ("ld a,!one");
2746 emitLabel (tlbl->key + 100);
2751 /*-----------------------------------------------------------------*/
2752 /* genPlus - generates code for addition */
2753 /*-----------------------------------------------------------------*/
2755 genPlus (iCode * ic)
2757 int size, offset = 0;
2759 /* special cases :- */
2761 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2762 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
2763 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2765 /* Swap the left and right operands if:
2767 if literal, literal on the right or
2768 if left requires ACC or right is already
2771 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
2772 (AOP_NEEDSACC (IC_LEFT (ic))) ||
2773 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
2775 operand *t = IC_RIGHT (ic);
2776 IC_RIGHT (ic) = IC_LEFT (ic);
2780 /* if both left & right are in bit
2782 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
2783 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
2786 wassertl (0, "Tried to add two bits");
2789 /* if left in bit space & right literal */
2790 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
2791 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
2793 /* Can happen I guess */
2794 wassertl (0, "Tried to add a bit to a literal");
2797 /* if I can do an increment instead
2798 of add then GOOD for ME */
2799 if (genPlusIncr (ic) == TRUE)
2802 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
2804 size = getDataSize (IC_RESULT (ic));
2806 /* Special case when left and right are constant */
2807 if (isPair (AOP (IC_RESULT (ic))))
2810 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
2811 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
2813 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
2819 sprintf (buffer, "#(%s + %s)", left, right);
2820 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
2825 if (isPair (AOP (IC_RIGHT (ic))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
2827 /* Fetch into HL then do the add */
2828 spillPair (PAIR_HL);
2829 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
2830 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
2835 ld hl,sp+n trashes C so we cant afford to do it during an
2836 add with stack based varibles. Worst case is:
2849 So you cant afford to load up hl if either left, right, or result
2850 is on the stack (*sigh*) The alt is:
2858 Combinations in here are:
2859 * If left or right are in bc then the loss is small - trap later
2860 * If the result is in bc then the loss is also small
2864 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
2865 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
2866 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
2868 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
2869 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
2870 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
2871 AOP_SIZE (IC_RIGHT (ic)) <= 2))
2873 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
2875 /* Swap left and right */
2876 operand *t = IC_RIGHT (ic);
2877 IC_RIGHT (ic) = IC_LEFT (ic);
2880 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
2882 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
2883 emit2 ("add hl,bc");
2887 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
2888 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
2889 emit2 ("add hl,de");
2891 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
2897 /* Be paranoid on the GB with 4 byte variables due to how C
2898 can be trashed by lda hl,n(sp).
2900 _gbz80_emitAddSubLong (ic, TRUE);
2907 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
2909 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
2912 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2915 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2919 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
2922 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2925 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2927 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2931 freeAsmop (IC_LEFT (ic), NULL, ic);
2932 freeAsmop (IC_RIGHT (ic), NULL, ic);
2933 freeAsmop (IC_RESULT (ic), NULL, ic);
2937 /*-----------------------------------------------------------------*/
2938 /* genMinusDec :- does subtraction with deccrement if possible */
2939 /*-----------------------------------------------------------------*/
2941 genMinusDec (iCode * ic)
2943 unsigned int icount;
2944 unsigned int size = getDataSize (IC_RESULT (ic));
2946 /* will try to generate an increment */
2947 /* if the right side is not a literal we cannot */
2948 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
2951 /* if the literal value of the right hand side
2952 is greater than 4 then it is not worth it */
2953 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
2956 size = getDataSize (IC_RESULT (ic));
2958 /* if decrement 16 bits in register */
2959 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
2960 (size > 1) && isPair (AOP (IC_RESULT (ic))))
2963 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
2967 /* If result is a pair */
2968 if (isPair (AOP (IC_RESULT (ic))))
2970 movLeft2Result (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0);
2971 movLeft2Result (IC_LEFT (ic), 1, IC_RESULT (ic), 1, 0);
2973 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
2977 /* if increment 16 bits in register */
2978 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
2982 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
2985 emit2 ("dec %s", _getTempPairName());
2988 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
2994 /* if the sizes are greater than 1 then we cannot */
2995 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
2996 AOP_SIZE (IC_LEFT (ic)) > 1)
2999 /* we can if the aops of the left & result match or if they are in
3000 registers and the registers are the same */
3001 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3004 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3011 /*-----------------------------------------------------------------*/
3012 /* genMinus - generates code for subtraction */
3013 /*-----------------------------------------------------------------*/
3015 genMinus (iCode * ic)
3017 int size, offset = 0;
3018 unsigned long lit = 0L;
3020 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3021 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3022 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3024 /* special cases :- */
3025 /* if both left & right are in bit space */
3026 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3027 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3029 wassertl (0, "Tried to subtract two bits");
3033 /* if I can do an decrement instead of subtract then GOOD for ME */
3034 if (genMinusDec (ic) == TRUE)
3037 size = getDataSize (IC_RESULT (ic));
3039 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3044 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3048 /* Same logic as genPlus */
3051 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3052 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3053 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3055 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3056 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3057 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3058 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3060 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3061 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3063 if (left == PAIR_INVALID && right == PAIR_INVALID)
3068 else if (right == PAIR_INVALID)
3070 else if (left == PAIR_INVALID)
3073 fetchPair (left, AOP (IC_LEFT (ic)));
3074 /* Order is important. Right may be HL */
3075 fetchPair (right, AOP (IC_RIGHT (ic)));
3077 emit2 ("ld a,%s", _pairs[left].l);
3078 emit2 ("sub a,%s", _pairs[right].l);
3080 emit2 ("ld a,%s", _pairs[left].h);
3081 emit2 ("sbc a,%s", _pairs[right].h);
3083 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3084 aopPut (AOP (IC_RESULT (ic)), "e", 0);
3090 /* Be paranoid on the GB with 4 byte variables due to how C
3091 can be trashed by lda hl,n(sp).
3093 _gbz80_emitAddSubLong (ic, FALSE);
3098 /* if literal, add a,#-lit, else normal subb */
3101 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3102 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3106 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3109 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3113 /* first add without previous c */
3115 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
3117 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3119 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3122 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3123 AOP_SIZE (IC_LEFT (ic)) == 3 &&
3124 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3126 wassertl (0, "Tried to subtract on a long pointer");
3130 freeAsmop (IC_LEFT (ic), NULL, ic);
3131 freeAsmop (IC_RIGHT (ic), NULL, ic);
3132 freeAsmop (IC_RESULT (ic), NULL, ic);
3135 /*-----------------------------------------------------------------*/
3136 /* genMult - generates code for multiplication */
3137 /*-----------------------------------------------------------------*/
3139 genMult (iCode * ic)
3141 /* Shouldn't occur - all done through function calls */
3142 wassertl (0, "Multiplication is handled through support function calls");
3145 /*-----------------------------------------------------------------*/
3146 /* genDiv - generates code for division */
3147 /*-----------------------------------------------------------------*/
3151 /* Shouldn't occur - all done through function calls */
3152 wassertl (0, "Division is handled through support function calls");
3155 /*-----------------------------------------------------------------*/
3156 /* genMod - generates code for division */
3157 /*-----------------------------------------------------------------*/
3161 /* Shouldn't occur - all done through function calls */
3165 /*-----------------------------------------------------------------*/
3166 /* genIfxJump :- will create a jump depending on the ifx */
3167 /*-----------------------------------------------------------------*/
3169 genIfxJump (iCode * ic, char *jval)
3174 /* if true label then we jump if condition
3178 jlbl = IC_TRUE (ic);
3179 if (!strcmp (jval, "a"))
3183 else if (!strcmp (jval, "c"))
3187 else if (!strcmp (jval, "nc"))
3193 /* The buffer contains the bit on A that we should test */
3199 /* false label is present */
3200 jlbl = IC_FALSE (ic);
3201 if (!strcmp (jval, "a"))
3205 else if (!strcmp (jval, "c"))
3209 else if (!strcmp (jval, "nc"))
3215 /* The buffer contains the bit on A that we should test */
3219 /* Z80 can do a conditional long jump */
3220 if (!strcmp (jval, "a"))
3224 else if (!strcmp (jval, "c"))
3227 else if (!strcmp (jval, "nc"))
3232 emit2 ("bit %s,a", jval);
3234 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
3236 /* mark the icode as generated */
3242 _getPairIdName (PAIR_ID id)
3244 return _pairs[id].name;
3248 /** Generic compare for > or <
3251 genCmp (operand * left, operand * right,
3252 operand * result, iCode * ifx, int sign)
3254 int size, offset = 0;
3255 unsigned long lit = 0L;
3256 bool swap_sense = FALSE;
3258 /* if left & right are bit variables */
3259 if (AOP_TYPE (left) == AOP_CRY &&
3260 AOP_TYPE (right) == AOP_CRY)
3262 /* Cant happen on the Z80 */
3263 wassertl (0, "Tried to compare two bits");
3267 /* subtract right from left if at the
3268 end the carry flag is set then we know that
3269 left is greater than right */
3270 size = max (AOP_SIZE (left), AOP_SIZE (right));
3272 /* if unsigned char cmp with lit, just compare */
3274 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
3276 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3279 emit2 ("xor a,!immedbyte", 0x80);
3280 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
3283 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3285 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
3287 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
3288 // Pull left into DE and right into HL
3289 aopGet (AOP(left), LSB, FALSE);
3292 aopGet (AOP(right), LSB, FALSE);
3296 if (size == 0 && sign)
3298 // Highest byte when signed needs the bits flipped
3301 emit2 ("ld a,(de)");
3302 emit2 ("xor #0x80");
3304 emit2 ("ld a,(hl)");
3305 emit2 ("xor #0x80");
3309 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
3313 emit2 ("ld a,(de)");
3314 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
3324 spillPair (PAIR_HL);
3328 if (AOP_TYPE (right) == AOP_LIT)
3330 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3331 /* optimize if(x < 0) or if(x >= 0) */
3336 /* No sign so it's always false */
3341 /* Just load in the top most bit */
3342 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
3343 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
3345 genIfxJump (ifx, "7");
3356 /* First setup h and l contaning the top most bytes XORed */
3357 bool fDidXor = FALSE;
3358 if (AOP_TYPE (left) == AOP_LIT)
3360 unsigned long lit = (unsigned long)
3361 floatFromVal (AOP (left)->aopu.aop_lit);
3362 emit2 ("ld %s,!immedbyte", _fTmp[0],
3363 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3367 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
3368 emit2 ("xor a,!immedbyte", 0x80);
3369 emit2 ("ld %s,a", _fTmp[0]);
3372 if (AOP_TYPE (right) == AOP_LIT)
3374 unsigned long lit = (unsigned long)
3375 floatFromVal (AOP (right)->aopu.aop_lit);
3376 emit2 ("ld %s,!immedbyte", _fTmp[1],
3377 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3381 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
3382 emit2 ("xor a,!immedbyte", 0x80);
3383 emit2 ("ld %s,a", _fTmp[1]);
3389 /* Do a long subtract */
3392 _moveA (aopGet (AOP (left), offset, FALSE));
3394 if (sign && size == 0)
3396 emit2 ("ld a,%s", _fTmp[0]);
3397 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
3401 /* Subtract through, propagating the carry */
3402 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
3410 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
3412 outBitCLong (result, swap_sense);
3416 /* if the result is used in the next
3417 ifx conditional branch then generate
3418 code a little differently */
3420 genIfxJump (ifx, swap_sense ? "nc" : "c");
3422 outBitCLong (result, swap_sense);
3423 /* leave the result in acc */
3427 /*-----------------------------------------------------------------*/
3428 /* genCmpGt :- greater than comparison */
3429 /*-----------------------------------------------------------------*/
3431 genCmpGt (iCode * ic, iCode * ifx)
3433 operand *left, *right, *result;
3434 sym_link *letype, *retype;
3437 left = IC_LEFT (ic);
3438 right = IC_RIGHT (ic);
3439 result = IC_RESULT (ic);
3441 letype = getSpec (operandType (left));
3442 retype = getSpec (operandType (right));
3443 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
3444 /* assign the amsops */
3445 aopOp (left, ic, FALSE, FALSE);
3446 aopOp (right, ic, FALSE, FALSE);
3447 aopOp (result, ic, TRUE, FALSE);
3449 genCmp (right, left, result, ifx, sign);
3451 freeAsmop (left, NULL, ic);
3452 freeAsmop (right, NULL, ic);
3453 freeAsmop (result, NULL, ic);
3456 /*-----------------------------------------------------------------*/
3457 /* genCmpLt - less than comparisons */
3458 /*-----------------------------------------------------------------*/
3460 genCmpLt (iCode * ic, iCode * ifx)
3462 operand *left, *right, *result;
3463 sym_link *letype, *retype;
3466 left = IC_LEFT (ic);
3467 right = IC_RIGHT (ic);
3468 result = IC_RESULT (ic);
3470 letype = getSpec (operandType (left));
3471 retype = getSpec (operandType (right));
3472 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
3474 /* assign the amsops */
3475 aopOp (left, ic, FALSE, FALSE);
3476 aopOp (right, ic, FALSE, FALSE);
3477 aopOp (result, ic, TRUE, FALSE);
3479 genCmp (left, right, result, ifx, sign);
3481 freeAsmop (left, NULL, ic);
3482 freeAsmop (right, NULL, ic);
3483 freeAsmop (result, NULL, ic);
3486 /*-----------------------------------------------------------------*/
3487 /* gencjneshort - compare and jump if not equal */
3488 /*-----------------------------------------------------------------*/
3490 gencjneshort (operand * left, operand * right, symbol * lbl)
3492 int size = max (AOP_SIZE (left), AOP_SIZE (right));
3494 unsigned long lit = 0L;
3496 /* Swap the left and right if it makes the computation easier */
3497 if (AOP_TYPE (left) == AOP_LIT)
3504 if (AOP_TYPE (right) == AOP_LIT)
3505 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3507 /* if the right side is a literal then anything goes */
3508 if (AOP_TYPE (right) == AOP_LIT &&
3509 AOP_TYPE (left) != AOP_DIR)
3513 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3520 emit2 ("or a,%s", aopGet (AOP (left), offset, FALSE));
3527 emit2 ("jp nz,!tlabel", lbl->key + 100);
3533 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3534 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
3537 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
3538 emit2 ("jp nz,!tlabel", lbl->key + 100);
3543 /* if the right side is in a register or in direct space or
3544 if the left is a pointer register & right is not */
3545 else if (AOP_TYPE (right) == AOP_REG ||
3546 AOP_TYPE (right) == AOP_DIR ||
3547 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
3551 _moveA (aopGet (AOP (left), offset, FALSE));
3552 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
3553 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
3555 emit2 ("jp nz,!tlabel", lbl->key + 100);
3558 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3559 emit2 ("jp nz,!tlabel", lbl->key + 100);
3566 /* right is a pointer reg need both a & b */
3567 /* PENDING: is this required? */
3570 _moveA (aopGet (AOP (right), offset, FALSE));
3571 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
3572 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
3578 /*-----------------------------------------------------------------*/
3579 /* gencjne - compare and jump if not equal */
3580 /*-----------------------------------------------------------------*/
3582 gencjne (operand * left, operand * right, symbol * lbl)
3584 symbol *tlbl = newiTempLabel (NULL);
3586 gencjneshort (left, right, lbl);
3589 emit2 ("ld a,!one");
3590 emit2 ("!shortjp !tlabel", tlbl->key + 100);
3591 emitLabel (lbl->key + 100);
3593 emitLabel (tlbl->key + 100);
3596 /*-----------------------------------------------------------------*/
3597 /* genCmpEq - generates code for equal to */
3598 /*-----------------------------------------------------------------*/
3600 genCmpEq (iCode * ic, iCode * ifx)
3602 operand *left, *right, *result;
3604 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
3605 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
3606 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
3608 emitDebug ("; genCmpEq: left %u, right %u, result %u\n", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
3610 /* Swap operands if it makes the operation easier. ie if:
3611 1. Left is a literal.
3613 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
3615 operand *t = IC_RIGHT (ic);
3616 IC_RIGHT (ic) = IC_LEFT (ic);
3620 if (ifx && !AOP_SIZE (result))
3623 /* if they are both bit variables */
3624 if (AOP_TYPE (left) == AOP_CRY &&
3625 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
3627 wassertl (0, "Tried to compare two bits");
3631 tlbl = newiTempLabel (NULL);
3632 gencjneshort (left, right, tlbl);
3635 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
3636 emitLabel (tlbl->key + 100);
3640 /* PENDING: do this better */
3641 symbol *lbl = newiTempLabel (NULL);
3642 emit2 ("!shortjp !tlabel", lbl->key + 100);
3643 emitLabel (tlbl->key + 100);
3644 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
3645 emitLabel (lbl->key + 100);
3648 /* mark the icode as generated */
3653 /* if they are both bit variables */
3654 if (AOP_TYPE (left) == AOP_CRY &&
3655 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
3657 wassertl (0, "Tried to compare a bit to either a literal or another bit");
3661 gencjne (left, right, newiTempLabel (NULL));
3662 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
3668 genIfxJump (ifx, "a");
3671 /* if the result is used in an arithmetic operation
3672 then put the result in place */
3673 if (AOP_TYPE (result) != AOP_CRY)
3677 /* leave the result in acc */
3681 freeAsmop (left, NULL, ic);
3682 freeAsmop (right, NULL, ic);
3683 freeAsmop (result, NULL, ic);
3686 /*-----------------------------------------------------------------*/
3687 /* ifxForOp - returns the icode containing the ifx for operand */
3688 /*-----------------------------------------------------------------*/
3690 ifxForOp (operand * op, iCode * ic)
3692 /* if true symbol then needs to be assigned */
3693 if (IS_TRUE_SYMOP (op))
3696 /* if this has register type condition and
3697 the next instruction is ifx with the same operand
3698 and live to of the operand is upto the ifx only then */
3700 ic->next->op == IFX &&
3701 IC_COND (ic->next)->key == op->key &&
3702 OP_SYMBOL (op)->liveTo <= ic->next->seq)
3708 /*-----------------------------------------------------------------*/
3709 /* genAndOp - for && operation */
3710 /*-----------------------------------------------------------------*/
3712 genAndOp (iCode * ic)
3714 operand *left, *right, *result;
3717 /* note here that && operations that are in an if statement are
3718 taken away by backPatchLabels only those used in arthmetic
3719 operations remain */
3720 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
3721 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
3722 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
3724 /* if both are bit variables */
3725 if (AOP_TYPE (left) == AOP_CRY &&
3726 AOP_TYPE (right) == AOP_CRY)
3728 wassertl (0, "Tried to and two bits");
3732 tlbl = newiTempLabel (NULL);
3734 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3736 emitLabel (tlbl->key + 100);
3740 freeAsmop (left, NULL, ic);
3741 freeAsmop (right, NULL, ic);
3742 freeAsmop (result, NULL, ic);
3745 /*-----------------------------------------------------------------*/
3746 /* genOrOp - for || operation */
3747 /*-----------------------------------------------------------------*/
3749 genOrOp (iCode * ic)
3751 operand *left, *right, *result;
3754 /* note here that || operations that are in an
3755 if statement are taken away by backPatchLabels
3756 only those used in arthmetic operations remain */
3757 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
3758 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
3759 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
3761 /* if both are bit variables */
3762 if (AOP_TYPE (left) == AOP_CRY &&
3763 AOP_TYPE (right) == AOP_CRY)
3765 wassertl (0, "Tried to OR two bits");
3769 tlbl = newiTempLabel (NULL);
3771 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3773 emitLabel (tlbl->key + 100);
3777 freeAsmop (left, NULL, ic);
3778 freeAsmop (right, NULL, ic);
3779 freeAsmop (result, NULL, ic);
3782 /*-----------------------------------------------------------------*/
3783 /* isLiteralBit - test if lit == 2^n */
3784 /*-----------------------------------------------------------------*/
3786 isLiteralBit (unsigned long lit)
3788 unsigned long pw[32] =
3789 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
3790 0x100L, 0x200L, 0x400L, 0x800L,
3791 0x1000L, 0x2000L, 0x4000L, 0x8000L,
3792 0x10000L, 0x20000L, 0x40000L, 0x80000L,
3793 0x100000L, 0x200000L, 0x400000L, 0x800000L,
3794 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
3795 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
3798 for (idx = 0; idx < 32; idx++)
3804 /*-----------------------------------------------------------------*/
3805 /* jmpTrueOrFalse - */
3806 /*-----------------------------------------------------------------*/
3808 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
3810 // ugly but optimized by peephole
3813 symbol *nlbl = newiTempLabel (NULL);
3814 emit2 ("jp !tlabel", nlbl->key + 100);
3815 emitLabel (tlbl->key + 100);
3816 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
3817 emitLabel (nlbl->key + 100);
3821 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
3822 emitLabel (tlbl->key + 100);
3827 /*-----------------------------------------------------------------*/
3828 /* genAnd - code for and */
3829 /*-----------------------------------------------------------------*/
3831 genAnd (iCode * ic, iCode * ifx)
3833 operand *left, *right, *result;
3834 int size, offset = 0;
3835 unsigned long lit = 0L;
3838 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
3839 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
3840 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
3842 /* if left is a literal & right is not then exchange them */
3843 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
3844 AOP_NEEDSACC (left))
3846 operand *tmp = right;
3851 /* if result = right then exchange them */
3852 if (sameRegs (AOP (result), AOP (right)))
3854 operand *tmp = right;
3859 /* if right is bit then exchange them */
3860 if (AOP_TYPE (right) == AOP_CRY &&
3861 AOP_TYPE (left) != AOP_CRY)
3863 operand *tmp = right;
3867 if (AOP_TYPE (right) == AOP_LIT)
3868 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3870 size = AOP_SIZE (result);
3872 if (AOP_TYPE (left) == AOP_CRY)
3874 wassertl (0, "Tried to perform an AND with a bit as an operand");
3878 // if(val & 0xZZ) - size = 0, ifx != FALSE -
3879 // bit = val & 0xZZ - size = 1, ifx = FALSE -
3880 if ((AOP_TYPE (right) == AOP_LIT) &&
3881 (AOP_TYPE (result) == AOP_CRY) &&
3882 (AOP_TYPE (left) != AOP_CRY))
3884 symbol *tlbl = newiTempLabel (NULL);
3885 int sizel = AOP_SIZE (left);
3888 /* PENDING: Test case for this. */
3893 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
3895 _moveA (aopGet (AOP (left), offset, FALSE));
3896 if (bytelit != 0x0FFL)
3898 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
3905 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3909 // bit = left & literal
3913 emit2 ("!tlabeldef", tlbl->key + 100);
3915 // if(left & literal)
3920 jmpTrueOrFalse (ifx, tlbl);
3928 /* if left is same as result */
3929 if (sameRegs (AOP (result), AOP (left)))
3931 for (; size--; offset++)
3933 if (AOP_TYPE (right) == AOP_LIT)
3935 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
3940 aopPut (AOP (result), "!zero", offset);
3943 _moveA (aopGet (AOP (left), offset, FALSE));
3945 aopGet (AOP (right), offset, FALSE));
3946 aopPut (AOP (left), "a", offset);
3953 if (AOP_TYPE (left) == AOP_ACC)
3955 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
3959 _moveA (aopGet (AOP (left), offset, FALSE));
3961 aopGet (AOP (right), offset, FALSE));
3962 aopPut (AOP (left), "a", offset);
3969 // left & result in different registers
3970 if (AOP_TYPE (result) == AOP_CRY)
3972 wassertl (0, "Tried to AND where the result is in carry");
3976 for (; (size--); offset++)
3979 // result = left & right
3980 if (AOP_TYPE (right) == AOP_LIT)
3982 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
3984 aopPut (AOP (result),
3985 aopGet (AOP (left), offset, FALSE),
3989 else if (bytelit == 0)
3991 aopPut (AOP (result), "!zero", offset);
3995 // faster than result <- left, anl result,right
3996 // and better if result is SFR
3997 if (AOP_TYPE (left) == AOP_ACC)
3998 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4001 _moveA (aopGet (AOP (left), offset, FALSE));
4003 aopGet (AOP (right), offset, FALSE));
4005 aopPut (AOP (result), "a", offset);
4012 freeAsmop (left, NULL, ic);
4013 freeAsmop (right, NULL, ic);
4014 freeAsmop (result, NULL, ic);
4017 /*-----------------------------------------------------------------*/
4018 /* genOr - code for or */
4019 /*-----------------------------------------------------------------*/
4021 genOr (iCode * ic, iCode * ifx)
4023 operand *left, *right, *result;
4024 int size, offset = 0;
4025 unsigned long lit = 0L;
4028 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4029 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4030 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4032 /* if left is a literal & right is not then exchange them */
4033 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4034 AOP_NEEDSACC (left))
4036 operand *tmp = right;
4041 /* if result = right then exchange them */
4042 if (sameRegs (AOP (result), AOP (right)))
4044 operand *tmp = right;
4049 /* if right is bit then exchange them */
4050 if (AOP_TYPE (right) == AOP_CRY &&
4051 AOP_TYPE (left) != AOP_CRY)
4053 operand *tmp = right;
4057 if (AOP_TYPE (right) == AOP_LIT)
4058 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4060 size = AOP_SIZE (result);
4062 if (AOP_TYPE (left) == AOP_CRY)
4064 wassertl (0, "Tried to OR where left is a bit");
4068 // if(val | 0xZZ) - size = 0, ifx != FALSE -
4069 // bit = val | 0xZZ - size = 1, ifx = FALSE -
4070 if ((AOP_TYPE (right) == AOP_LIT) &&
4071 (AOP_TYPE (result) == AOP_CRY) &&
4072 (AOP_TYPE (left) != AOP_CRY))
4074 symbol *tlbl = newiTempLabel (NULL);
4075 int sizel = AOP_SIZE (left);
4079 wassertl (0, "Result is assigned to a bit");
4081 /* PENDING: Modeled after the AND code which is inefficent. */
4084 bytelit = (lit >> (offset * 8)) & 0x0FFL;
4086 _moveA (aopGet (AOP (left), offset, FALSE));
4087 /* OR with any literal is the same as OR with itself. */
4089 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4095 jmpTrueOrFalse (ifx, tlbl);
4100 /* if left is same as result */
4101 if (sameRegs (AOP (result), AOP (left)))
4103 for (; size--; offset++)
4105 if (AOP_TYPE (right) == AOP_LIT)
4107 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4111 _moveA (aopGet (AOP (left), offset, FALSE));
4113 aopGet (AOP (right), offset, FALSE));
4114 aopPut (AOP (result), "a", offset);
4119 if (AOP_TYPE (left) == AOP_ACC)
4120 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4123 _moveA (aopGet (AOP (left), offset, FALSE));
4125 aopGet (AOP (right), offset, FALSE));
4126 aopPut (AOP (result), "a", offset);
4133 // left & result in different registers
4134 if (AOP_TYPE (result) == AOP_CRY)
4136 wassertl (0, "Result of OR is in a bit");
4139 for (; (size--); offset++)
4142 // result = left & right
4143 if (AOP_TYPE (right) == AOP_LIT)
4145 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4147 aopPut (AOP (result),
4148 aopGet (AOP (left), offset, FALSE),
4153 // faster than result <- left, anl result,right
4154 // and better if result is SFR
4155 if (AOP_TYPE (left) == AOP_ACC)
4156 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4159 _moveA (aopGet (AOP (left), offset, FALSE));
4161 aopGet (AOP (right), offset, FALSE));
4163 aopPut (AOP (result), "a", offset);
4164 /* PENDING: something weird is going on here. Add exception. */
4165 if (AOP_TYPE (result) == AOP_ACC)
4171 freeAsmop (left, NULL, ic);
4172 freeAsmop (right, NULL, ic);
4173 freeAsmop (result, NULL, ic);
4176 /*-----------------------------------------------------------------*/
4177 /* genXor - code for xclusive or */
4178 /*-----------------------------------------------------------------*/
4180 genXor (iCode * ic, iCode * ifx)
4182 operand *left, *right, *result;
4183 int size, offset = 0;
4184 unsigned long lit = 0L;
4186 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4187 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4188 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4190 /* if left is a literal & right is not then exchange them */
4191 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4192 AOP_NEEDSACC (left))
4194 operand *tmp = right;
4199 /* if result = right then exchange them */
4200 if (sameRegs (AOP (result), AOP (right)))
4202 operand *tmp = right;
4207 /* if right is bit then exchange them */
4208 if (AOP_TYPE (right) == AOP_CRY &&
4209 AOP_TYPE (left) != AOP_CRY)
4211 operand *tmp = right;
4215 if (AOP_TYPE (right) == AOP_LIT)
4216 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4218 size = AOP_SIZE (result);
4220 if (AOP_TYPE (left) == AOP_CRY)
4222 wassertl (0, "Tried to XOR a bit");
4226 // if(val & 0xZZ) - size = 0, ifx != FALSE -
4227 // bit = val & 0xZZ - size = 1, ifx = FALSE -
4228 if ((AOP_TYPE (right) == AOP_LIT) &&
4229 (AOP_TYPE (result) == AOP_CRY) &&
4230 (AOP_TYPE (left) != AOP_CRY))
4232 symbol *tlbl = newiTempLabel (NULL);
4233 int sizel = AOP_SIZE (left);
4237 /* PENDING: Test case for this. */
4238 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
4242 _moveA (aopGet (AOP (left), offset, FALSE));
4243 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4244 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4249 jmpTrueOrFalse (ifx, tlbl);
4253 wassertl (0, "Result of XOR was destined for a bit");
4258 /* if left is same as result */
4259 if (sameRegs (AOP (result), AOP (left)))
4261 for (; size--; offset++)
4263 if (AOP_TYPE (right) == AOP_LIT)
4265 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4269 _moveA (aopGet (AOP (right), offset, FALSE));
4271 aopGet (AOP (left), offset, FALSE));
4272 aopPut (AOP (result), "a", offset);
4277 if (AOP_TYPE (left) == AOP_ACC)
4279 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4283 _moveA (aopGet (AOP (right), offset, FALSE));
4285 aopGet (AOP (left), offset, FALSE));
4286 aopPut (AOP (result), "a", 0);
4293 // left & result in different registers
4294 if (AOP_TYPE (result) == AOP_CRY)
4296 wassertl (0, "Result of XOR is in a bit");
4299 for (; (size--); offset++)
4302 // result = left & right
4303 if (AOP_TYPE (right) == AOP_LIT)
4305 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4307 aopPut (AOP (result),
4308 aopGet (AOP (left), offset, FALSE),
4313 // faster than result <- left, anl result,right
4314 // and better if result is SFR
4315 if (AOP_TYPE (left) == AOP_ACC)
4317 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4321 _moveA (aopGet (AOP (right), offset, FALSE));
4323 aopGet (AOP (left), offset, FALSE));
4325 aopPut (AOP (result), "a", offset);
4330 freeAsmop (left, NULL, ic);
4331 freeAsmop (right, NULL, ic);
4332 freeAsmop (result, NULL, ic);
4335 /*-----------------------------------------------------------------*/
4336 /* genInline - write the inline code out */
4337 /*-----------------------------------------------------------------*/
4339 genInline (iCode * ic)
4341 char *buffer, *bp, *bp1;
4343 _G.lines.isInline += (!options.asmpeep);
4345 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
4346 strcpy (buffer, IC_INLINE (ic));
4348 /* emit each line as a code */
4373 _G.lines.isInline -= (!options.asmpeep);
4377 /*-----------------------------------------------------------------*/
4378 /* genRRC - rotate right with carry */
4379 /*-----------------------------------------------------------------*/
4386 /*-----------------------------------------------------------------*/
4387 /* genRLC - generate code for rotate left with carry */
4388 /*-----------------------------------------------------------------*/
4395 /*-----------------------------------------------------------------*/
4396 /* genGetHbit - generates code get highest order bit */
4397 /*-----------------------------------------------------------------*/
4399 genGetHbit (iCode * ic)
4401 operand *left, *result;
4402 left = IC_LEFT (ic);
4403 result = IC_RESULT (ic);
4404 aopOp (left, ic, FALSE, FALSE);
4405 aopOp (result, ic, FALSE, FALSE);
4407 /* get the highest order byte into a */
4408 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4410 if (AOP_TYPE (result) == AOP_CRY)
4418 /* PENDING: For re-target. */
4424 freeAsmop (left, NULL, ic);
4425 freeAsmop (result, NULL, ic);
4429 emitRsh2 (asmop *aop, int size, int is_signed)
4435 const char *l = aopGet (aop, size, FALSE);
4438 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
4448 /*-----------------------------------------------------------------*/
4449 /* shiftR2Left2Result - shift right two bytes from left to result */
4450 /*-----------------------------------------------------------------*/
4452 shiftR2Left2Result (operand * left, int offl,
4453 operand * result, int offr,
4454 int shCount, int is_signed)
4457 symbol *tlbl, *tlbl1;
4459 movLeft2Result (left, offl, result, offr, 0);
4460 movLeft2Result (left, offl + 1, result, offr + 1, 0);
4462 /* if (AOP(result)->type == AOP_REG) { */
4464 tlbl = newiTempLabel (NULL);
4465 tlbl1 = newiTempLabel (NULL);
4467 /* Left is already in result - so now do the shift */
4472 emitRsh2 (AOP (result), size, is_signed);
4477 emit2 ("ld a,!immedbyte+1", shCount);
4478 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4479 emitLabel (tlbl->key + 100);
4481 emitRsh2 (AOP (result), size, is_signed);
4483 emitLabel (tlbl1->key + 100);
4485 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4489 /*-----------------------------------------------------------------*/
4490 /* shiftL2Left2Result - shift left two bytes from left to result */
4491 /*-----------------------------------------------------------------*/
4493 shiftL2Left2Result (operand * left, int offl,
4494 operand * result, int offr, int shCount)
4496 if (sameRegs (AOP (result), AOP (left)) &&
4497 ((offl + MSB16) == offr))
4503 /* Copy left into result */
4504 movLeft2Result (left, offl, result, offr, 0);
4505 movLeft2Result (left, offl + 1, result, offr + 1, 0);
4507 /* PENDING: for now just see if it'll work. */
4508 /*if (AOP(result)->type == AOP_REG) { */
4512 symbol *tlbl, *tlbl1;
4515 tlbl = newiTempLabel (NULL);
4516 tlbl1 = newiTempLabel (NULL);
4518 /* Left is already in result - so now do the shift */
4521 emit2 ("ld a,!immedbyte+1", shCount);
4522 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4523 emitLabel (tlbl->key + 100);
4528 l = aopGet (AOP (result), offset, FALSE);
4532 emit2 ("sla %s", l);
4543 emitLabel (tlbl1->key + 100);
4545 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4550 /*-----------------------------------------------------------------*/
4551 /* AccRol - rotate left accumulator by known count */
4552 /*-----------------------------------------------------------------*/
4554 AccRol (int shCount)
4556 shCount &= 0x0007; // shCount : 0..7
4595 /*-----------------------------------------------------------------*/
4596 /* AccLsh - left shift accumulator by known count */
4597 /*-----------------------------------------------------------------*/
4599 AccLsh (int shCount)
4601 static const unsigned char SLMask[] =
4603 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
4612 else if (shCount == 2)
4619 /* rotate left accumulator */
4621 /* and kill the lower order bits */
4622 emit2 ("and a,!immedbyte", SLMask[shCount]);
4627 /*-----------------------------------------------------------------*/
4628 /* shiftL1Left2Result - shift left one byte from left to result */
4629 /*-----------------------------------------------------------------*/
4631 shiftL1Left2Result (operand * left, int offl,
4632 operand * result, int offr, int shCount)
4635 l = aopGet (AOP (left), offl, FALSE);
4637 /* shift left accumulator */
4639 aopPut (AOP (result), "a", offr);
4643 /*-----------------------------------------------------------------*/
4644 /* genlshTwo - left shift two bytes by known amount != 0 */
4645 /*-----------------------------------------------------------------*/
4647 genlshTwo (operand * result, operand * left, int shCount)
4649 int size = AOP_SIZE (result);
4651 wassert (size == 2);
4653 /* if shCount >= 8 */
4661 movLeft2Result (left, LSB, result, MSB16, 0);
4662 aopPut (AOP (result), "!zero", 0);
4663 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
4667 movLeft2Result (left, LSB, result, MSB16, 0);
4668 aopPut (AOP (result), "!zero", 0);
4673 aopPut (AOP (result), "!zero", LSB);
4676 /* 1 <= shCount <= 7 */
4685 shiftL2Left2Result (left, LSB, result, LSB, shCount);
4690 /*-----------------------------------------------------------------*/
4691 /* genlshOne - left shift a one byte quantity by known count */
4692 /*-----------------------------------------------------------------*/
4694 genlshOne (operand * result, operand * left, int shCount)
4696 shiftL1Left2Result (left, LSB, result, LSB, shCount);
4699 /*-----------------------------------------------------------------*/
4700 /* genLeftShiftLiteral - left shifting by known count */
4701 /*-----------------------------------------------------------------*/
4703 genLeftShiftLiteral (operand * left,
4708 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
4711 freeAsmop (right, NULL, ic);
4713 aopOp (left, ic, FALSE, FALSE);
4714 aopOp (result, ic, FALSE, FALSE);
4716 size = getSize (operandType (result));
4718 /* I suppose that the left size >= result size */
4724 else if (shCount >= (size * 8))
4728 aopPut (AOP (result), "!zero", size);
4736 genlshOne (result, left, shCount);
4739 genlshTwo (result, left, shCount);
4742 wassertl (0, "Shifting of longs is currently unsupported");
4748 freeAsmop (left, NULL, ic);
4749 freeAsmop (result, NULL, ic);
4752 /*-----------------------------------------------------------------*/
4753 /* genLeftShift - generates code for left shifting */
4754 /*-----------------------------------------------------------------*/
4756 genLeftShift (iCode * ic)
4760 symbol *tlbl, *tlbl1;
4761 operand *left, *right, *result;
4763 right = IC_RIGHT (ic);
4764 left = IC_LEFT (ic);
4765 result = IC_RESULT (ic);
4767 aopOp (right, ic, FALSE, FALSE);
4769 /* if the shift count is known then do it
4770 as efficiently as possible */
4771 if (AOP_TYPE (right) == AOP_LIT)
4773 genLeftShiftLiteral (left, right, result, ic);
4777 /* shift count is unknown then we have to form a loop get the loop
4778 count in B : Note: we take only the lower order byte since
4779 shifting more that 32 bits make no sense anyway, ( the largest
4780 size of an object can be only 32 bits ) */
4781 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
4783 freeAsmop (right, NULL, ic);
4784 aopOp (left, ic, FALSE, FALSE);
4785 aopOp (result, ic, FALSE, FALSE);
4787 /* now move the left to the result if they are not the
4790 if (!sameRegs (AOP (left), AOP (result)))
4793 size = AOP_SIZE (result);
4797 l = aopGet (AOP (left), offset, FALSE);
4798 aopPut (AOP (result), l, offset);
4803 tlbl = newiTempLabel (NULL);
4804 size = AOP_SIZE (result);
4806 tlbl1 = newiTempLabel (NULL);
4808 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4809 emitLabel (tlbl->key + 100);
4810 l = aopGet (AOP (result), offset, FALSE);
4814 l = aopGet (AOP (result), offset, FALSE);
4818 emit2 ("sla %s", l);
4826 emitLabel (tlbl1->key + 100);
4828 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4830 freeAsmop (left, NULL, ic);
4831 freeAsmop (result, NULL, ic);
4834 /*-----------------------------------------------------------------*/
4835 /* genrshOne - left shift two bytes by known amount != 0 */
4836 /*-----------------------------------------------------------------*/
4838 genrshOne (operand * result, operand * left, int shCount, int is_signed)
4841 int size = AOP_SIZE (result);
4844 wassert (size == 1);
4845 wassert (shCount < 8);
4847 l = aopGet (AOP (left), 0, FALSE);
4849 if (AOP (result)->type == AOP_REG)
4851 aopPut (AOP (result), l, 0);
4852 l = aopGet (AOP (result), 0, FALSE);
4855 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
4863 emit2 ("%s a", is_signed ? "sra" : "srl");
4865 aopPut (AOP (result), "a", 0);
4869 /*-----------------------------------------------------------------*/
4870 /* AccRsh - right shift accumulator by known count */
4871 /*-----------------------------------------------------------------*/
4873 AccRsh (int shCount)
4875 static const unsigned char SRMask[] =
4877 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
4882 /* rotate right accumulator */
4883 AccRol (8 - shCount);
4884 /* and kill the higher order bits */
4885 emit2 ("and a,!immedbyte", SRMask[shCount]);
4889 /*-----------------------------------------------------------------*/
4890 /* shiftR1Left2Result - shift right one byte from left to result */
4891 /*-----------------------------------------------------------------*/
4893 shiftR1Left2Result (operand * left, int offl,
4894 operand * result, int offr,
4895 int shCount, int sign)
4897 _moveA (aopGet (AOP (left), offl, FALSE));
4902 emit2 ("%s a", sign ? "sra" : "srl");
4909 aopPut (AOP (result), "a", offr);
4912 /*-----------------------------------------------------------------*/
4913 /* genrshTwo - right shift two bytes by known amount != 0 */
4914 /*-----------------------------------------------------------------*/
4916 genrshTwo (operand * result, operand * left,
4917 int shCount, int sign)
4919 /* if shCount >= 8 */
4925 shiftR1Left2Result (left, MSB16, result, LSB,
4930 movLeft2Result (left, MSB16, result, LSB, sign);
4934 /* Sign extend the result */
4935 _moveA(aopGet (AOP (result), 0, FALSE));
4939 aopPut (AOP (result), ACC_NAME, MSB16);
4943 aopPut (AOP (result), "!zero", 1);
4946 /* 1 <= shCount <= 7 */
4949 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
4953 /*-----------------------------------------------------------------*/
4954 /* genRightShiftLiteral - left shifting by known count */
4955 /*-----------------------------------------------------------------*/
4957 genRightShiftLiteral (operand * left,
4963 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
4966 freeAsmop (right, NULL, ic);
4968 aopOp (left, ic, FALSE, FALSE);
4969 aopOp (result, ic, FALSE, FALSE);
4971 size = getSize (operandType (result));
4973 /* I suppose that the left size >= result size */
4979 else if (shCount >= (size * 8))
4981 aopPut (AOP (result), "!zero", size);
4987 genrshOne (result, left, shCount, sign);
4990 genrshTwo (result, left, shCount, sign);
4993 wassertl (0, "Asked to shift right a long which should be a function call");
4996 wassertl (0, "Entered default case in right shift delegate");
4999 freeAsmop (left, NULL, ic);
5000 freeAsmop (result, NULL, ic);
5003 /*-----------------------------------------------------------------*/
5004 /* genRightShift - generate code for right shifting */
5005 /*-----------------------------------------------------------------*/
5007 genRightShift (iCode * ic)
5009 operand *right, *left, *result;
5011 int size, offset, first = 1;
5015 symbol *tlbl, *tlbl1;
5017 /* if signed then we do it the hard way preserve the
5018 sign bit moving it inwards */
5019 retype = getSpec (operandType (IC_RESULT (ic)));
5021 is_signed = !SPEC_USIGN (retype);
5023 /* signed & unsigned types are treated the same : i.e. the
5024 signed is NOT propagated inwards : quoting from the
5025 ANSI - standard : "for E1 >> E2, is equivalent to division
5026 by 2**E2 if unsigned or if it has a non-negative value,
5027 otherwise the result is implementation defined ", MY definition
5028 is that the sign does not get propagated */
5030 right = IC_RIGHT (ic);
5031 left = IC_LEFT (ic);
5032 result = IC_RESULT (ic);
5034 aopOp (right, ic, FALSE, FALSE);
5036 /* if the shift count is known then do it
5037 as efficiently as possible */
5038 if (AOP_TYPE (right) == AOP_LIT)
5040 genRightShiftLiteral (left, right, result, ic, is_signed);
5044 aopOp (left, ic, FALSE, FALSE);
5045 aopOp (result, ic, FALSE, FALSE);
5047 /* now move the left to the result if they are not the
5049 if (!sameRegs (AOP (left), AOP (result)) &&
5050 AOP_SIZE (result) > 1)
5053 size = AOP_SIZE (result);
5057 l = aopGet (AOP (left), offset, FALSE);
5058 aopPut (AOP (result), l, offset);
5063 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5065 freeAsmop (right, NULL, ic);
5067 tlbl = newiTempLabel (NULL);
5068 tlbl1 = newiTempLabel (NULL);
5069 size = AOP_SIZE (result);
5072 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5073 emitLabel (tlbl->key + 100);
5076 l = aopGet (AOP (result), offset--, FALSE);
5079 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5087 emitLabel (tlbl1->key + 100);
5089 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5091 freeAsmop (left, NULL, ic);
5092 freeAsmop (result, NULL, ic);
5095 /*-----------------------------------------------------------------*/
5096 /* genGenPointerGet - get value from generic pointer space */
5097 /*-----------------------------------------------------------------*/
5099 genGenPointerGet (operand * left,
5100 operand * result, iCode * ic)
5103 sym_link *retype = getSpec (operandType (result));
5109 aopOp (left, ic, FALSE, FALSE);
5110 aopOp (result, ic, FALSE, FALSE);
5112 if (isPair (AOP (left)) && AOP_SIZE (result) == 1)
5115 if (isPtrPair (AOP (left)))
5117 tsprintf (buffer, "!*pair", getPairName (AOP (left)));
5118 aopPut (AOP (result), buffer, 0);
5122 emit2 ("ld a,!*pair", getPairName (AOP (left)));
5123 aopPut (AOP (result), "a", 0);
5125 freeAsmop (left, NULL, ic);
5129 /* For now we always load into IY */
5130 /* if this is remateriazable */
5131 fetchPair (pair, AOP (left));
5133 /* so iy now contains the address */
5134 freeAsmop (left, NULL, ic);
5136 /* if bit then unpack */
5137 if (IS_BITVAR (retype))
5143 size = AOP_SIZE (result);
5148 /* PENDING: make this better */
5149 if (!IS_GB && AOP (result)->type == AOP_REG)
5151 aopPut (AOP (result), "!*hl", offset++);
5155 emit2 ("ld a,!*pair", _pairs[pair].name);
5156 aopPut (AOP (result), "a", offset++);
5160 emit2 ("inc %s", _pairs[pair].name);
5161 _G.pairs[pair].offset++;
5167 freeAsmop (result, NULL, ic);
5170 /*-----------------------------------------------------------------*/
5171 /* genPointerGet - generate code for pointer get */
5172 /*-----------------------------------------------------------------*/
5174 genPointerGet (iCode * ic)
5176 operand *left, *result;
5177 sym_link *type, *etype;
5179 left = IC_LEFT (ic);
5180 result = IC_RESULT (ic);
5182 /* depending on the type of pointer we need to
5183 move it to the correct pointer register */
5184 type = operandType (left);
5185 etype = getSpec (type);
5187 genGenPointerGet (left, result, ic);
5191 isRegOrLit (asmop * aop)
5193 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
5198 /*-----------------------------------------------------------------*/
5199 /* genGenPointerSet - stores the value into a pointer location */
5200 /*-----------------------------------------------------------------*/
5202 genGenPointerSet (operand * right,
5203 operand * result, iCode * ic)
5206 sym_link *retype = getSpec (operandType (right));
5207 PAIR_ID pairId = PAIR_HL;
5209 aopOp (result, ic, FALSE, FALSE);
5210 aopOp (right, ic, FALSE, FALSE);
5215 /* Handle the exceptions first */
5216 if (isPair (AOP (result)) && (AOP_SIZE (right) == 1))
5219 const char *l = aopGet (AOP (right), 0, FALSE);
5220 const char *pair = getPairName (AOP (result));
5221 if (canAssignToPtr (l) && isPtr (pair))
5223 emit2 ("ld !*pair,%s", pair, l);
5228 emit2 ("ld !*pair,a", pair);
5233 /* if the operand is already in dptr
5234 then we do nothing else we move the value to dptr */
5235 if (AOP_TYPE (result) != AOP_STR)
5237 fetchPair (pairId, AOP (result));
5239 /* so hl know contains the address */
5240 freeAsmop (result, NULL, ic);
5242 /* if bit then unpack */
5243 if (IS_BITVAR (retype))
5249 size = AOP_SIZE (right);
5254 const char *l = aopGet (AOP (right), offset, FALSE);
5255 if (isRegOrLit (AOP (right)) && !IS_GB)
5257 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
5262 emit2 ("ld !*pair,a", _pairs[pairId].name);
5266 emit2 ("inc %s", _pairs[pairId].name);
5267 _G.pairs[pairId].offset++;
5273 freeAsmop (right, NULL, ic);
5276 /*-----------------------------------------------------------------*/
5277 /* genPointerSet - stores the value into a pointer location */
5278 /*-----------------------------------------------------------------*/
5280 genPointerSet (iCode * ic)
5282 operand *right, *result;
5283 sym_link *type, *etype;
5285 right = IC_RIGHT (ic);
5286 result = IC_RESULT (ic);
5288 /* depending on the type of pointer we need to
5289 move it to the correct pointer register */
5290 type = operandType (result);
5291 etype = getSpec (type);
5293 genGenPointerSet (right, result, ic);
5296 /*-----------------------------------------------------------------*/
5297 /* genIfx - generate code for Ifx statement */
5298 /*-----------------------------------------------------------------*/
5300 genIfx (iCode * ic, iCode * popIc)
5302 operand *cond = IC_COND (ic);
5305 aopOp (cond, ic, FALSE, TRUE);
5307 /* get the value into acc */
5308 if (AOP_TYPE (cond) != AOP_CRY)
5312 /* the result is now in the accumulator */
5313 freeAsmop (cond, NULL, ic);
5315 /* if there was something to be popped then do it */
5319 /* if the condition is a bit variable */
5320 if (isbit && IS_ITEMP (cond) &&
5322 genIfxJump (ic, SPIL_LOC (cond)->rname);
5323 else if (isbit && !IS_ITEMP (cond))
5324 genIfxJump (ic, OP_SYMBOL (cond)->rname);
5326 genIfxJump (ic, "a");
5331 /*-----------------------------------------------------------------*/
5332 /* genAddrOf - generates code for address of */
5333 /*-----------------------------------------------------------------*/
5335 genAddrOf (iCode * ic)
5337 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
5339 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
5341 /* if the operand is on the stack then we
5342 need to get the stack offset of this
5349 if (sym->stack <= 0)
5351 emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset);
5355 emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
5362 emit2 ("ld de,!hashedstr", sym->rname);
5364 aopPut (AOP (IC_RESULT (ic)), "e", 0);
5365 aopPut (AOP (IC_RESULT (ic)), "d", 1);
5372 /* if it has an offset then we need to compute it */
5374 emit2 ("ld hl,#%d+%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset, _G.stack.param_offset);
5376 emit2 ("ld hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
5377 emit2 ("add hl,sp");
5381 emit2 ("ld hl,#%s", sym->rname);
5383 aopPut (AOP (IC_RESULT (ic)), "l", 0);
5384 aopPut (AOP (IC_RESULT (ic)), "h", 1);
5386 freeAsmop (IC_RESULT (ic), NULL, ic);
5389 /*-----------------------------------------------------------------*/
5390 /* genAssign - generate code for assignment */
5391 /*-----------------------------------------------------------------*/
5393 genAssign (iCode * ic)
5395 operand *result, *right;
5397 unsigned long lit = 0L;
5399 result = IC_RESULT (ic);
5400 right = IC_RIGHT (ic);
5402 /* Dont bother assigning if they are the same */
5403 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5405 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
5409 aopOp (right, ic, FALSE, FALSE);
5410 aopOp (result, ic, TRUE, FALSE);
5412 /* if they are the same registers */
5413 if (sameRegs (AOP (right), AOP (result)))
5415 emitDebug ("; (registers are the same)");
5419 /* if the result is a bit */
5420 if (AOP_TYPE (result) == AOP_CRY)
5422 wassertl (0, "Tried to assign to a bit");
5426 size = AOP_SIZE (result);
5429 if (AOP_TYPE (right) == AOP_LIT)
5430 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5431 if (isPair (AOP (result)))
5433 fetchPair (getPairId (AOP (result)), AOP (right));
5435 else if ((size > 1) &&
5436 (AOP_TYPE (result) != AOP_REG) &&
5437 (AOP_TYPE (right) == AOP_LIT) &&
5438 !IS_FLOAT (operandType (right)) &&
5441 bool fXored = FALSE;
5443 /* Work from the top down.
5444 Done this way so that we can use the cached copy of 0
5445 in A for a fast clear */
5448 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
5450 if (!fXored && size > 1)
5457 aopPut (AOP (result), "a", offset);
5461 aopPut (AOP (result), "!zero", offset);
5465 aopPut (AOP (result),
5466 aopGet (AOP (right), offset, FALSE),
5471 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
5473 /* Special case. Load into a and d, then load out. */
5474 _moveA (aopGet (AOP (right), 0, FALSE));
5475 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
5476 aopPut (AOP (result), "a", 0);
5477 aopPut (AOP (result), "e", 1);
5479 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
5481 /* Special case - simple memcpy */
5482 aopGet (AOP (right), LSB, FALSE);
5485 aopGet (AOP (result), LSB, FALSE);
5489 emit2 ("ld a,(de)");
5490 /* Peephole will optimise this. */
5491 emit2 ("ld (hl),a");
5499 spillPair (PAIR_HL);
5505 /* PENDING: do this check better */
5506 if (requiresHL (AOP (right)) && requiresHL (AOP (result)))
5508 _moveA (aopGet (AOP (right), offset, FALSE));
5509 aopPut (AOP (result), "a", offset);
5512 aopPut (AOP (result),
5513 aopGet (AOP (right), offset, FALSE),
5520 freeAsmop (right, NULL, ic);
5521 freeAsmop (result, NULL, ic);
5524 /*-----------------------------------------------------------------*/
5525 /* genJumpTab - genrates code for jump table */
5526 /*-----------------------------------------------------------------*/
5528 genJumpTab (iCode * ic)
5533 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
5534 /* get the condition into accumulator */
5535 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
5538 emit2 ("ld e,%s", l);
5539 emit2 ("ld d,!zero");
5540 jtab = newiTempLabel (NULL);
5542 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
5543 emit2 ("add hl,de");
5544 emit2 ("add hl,de");
5545 emit2 ("add hl,de");
5546 freeAsmop (IC_JTCOND (ic), NULL, ic);
5550 emitLabel (jtab->key + 100);
5551 /* now generate the jump labels */
5552 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
5553 jtab = setNextItem (IC_JTLABELS (ic)))
5554 emit2 ("jp !tlabel", jtab->key + 100);
5557 /*-----------------------------------------------------------------*/
5558 /* genCast - gen code for casting */
5559 /*-----------------------------------------------------------------*/
5561 genCast (iCode * ic)
5563 operand *result = IC_RESULT (ic);
5564 sym_link *ctype = operandType (IC_LEFT (ic));
5565 operand *right = IC_RIGHT (ic);
5568 /* if they are equivalent then do nothing */
5569 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5572 aopOp (right, ic, FALSE, FALSE);
5573 aopOp (result, ic, FALSE, FALSE);
5575 /* if the result is a bit */
5576 if (AOP_TYPE (result) == AOP_CRY)
5578 wassertl (0, "Tried to cast to a bit");
5581 /* if they are the same size : or less */
5582 if (AOP_SIZE (result) <= AOP_SIZE (right))
5585 /* if they are in the same place */
5586 if (sameRegs (AOP (right), AOP (result)))
5589 /* if they in different places then copy */
5590 size = AOP_SIZE (result);
5594 aopPut (AOP (result),
5595 aopGet (AOP (right), offset, FALSE),
5602 /* So we now know that the size of destination is greater
5603 than the size of the source */
5604 /* we move to result for the size of source */
5605 size = AOP_SIZE (right);
5609 aopPut (AOP (result),
5610 aopGet (AOP (right), offset, FALSE),
5615 /* now depending on the sign of the destination */
5616 size = AOP_SIZE (result) - AOP_SIZE (right);
5617 /* Unsigned or not an integral type - right fill with zeros */
5618 if (SPEC_USIGN (ctype) || !IS_SPEC (ctype))
5621 aopPut (AOP (result), "!zero", offset++);
5625 /* we need to extend the sign :{ */
5626 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
5632 aopPut (AOP (result), "a", offset++);
5636 freeAsmop (right, NULL, ic);
5637 freeAsmop (result, NULL, ic);
5640 /*-----------------------------------------------------------------*/
5641 /* genReceive - generate code for a receive iCode */
5642 /*-----------------------------------------------------------------*/
5644 genReceive (iCode * ic)
5646 if (isOperandInFarSpace (IC_RESULT (ic)) &&
5647 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
5648 IS_TRUE_SYMOP (IC_RESULT (ic))))
5658 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
5659 size = AOP_SIZE(IC_RESULT(ic));
5661 for (i = 0; i < size; i++) {
5662 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
5666 freeAsmop (IC_RESULT (ic), NULL, ic);
5671 /** Maximum number of bytes to emit per line. */
5675 /** Context for the byte output chunker. */
5678 unsigned char buffer[DBEMIT_MAX_RUN];
5683 /** Flushes a byte chunker by writing out all in the buffer and
5687 _dbFlush(DBEMITCTX *self)
5694 sprintf(line, ".db 0x%02X", self->buffer[0]);
5696 for (i = 1; i < self->pos; i++)
5698 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
5705 /** Write out another byte, buffering until a decent line is
5709 _dbEmit(DBEMITCTX *self, int c)
5711 if (self->pos == DBEMIT_MAX_RUN)
5715 self->buffer[self->pos++] = c;
5718 /** Context for a simple run length encoder. */
5722 unsigned char buffer[128];
5724 /** runLen may be equivalent to pos. */
5730 RLE_CHANGE_COST = 4,
5734 /** Flush the buffer of a run length encoder by writing out the run or
5735 data that it currently contains.
5738 _rleCommit(RLECTX *self)
5744 memset(&db, 0, sizeof(db));
5746 emit2(".db %u", self->pos);
5748 for (i = 0; i < self->pos; i++)
5750 _dbEmit(&db, self->buffer[i]);
5759 Can get either a run or a block of random stuff.
5760 Only want to change state if a good run comes in or a run ends.
5761 Detecting run end is easy.
5764 Say initial state is in run, len zero, last zero. Then if you get a
5765 few zeros then something else then a short run will be output.
5766 Seems OK. While in run mode, keep counting. While in random mode,
5767 keep a count of the run. If run hits margin, output all up to run,
5768 restart, enter run mode.
5771 /** Add another byte into the run length encoder, flushing as
5772 required. The run length encoder uses the Amiga IFF style, where
5773 a block is prefixed by its run length. A positive length means
5774 the next n bytes pass straight through. A negative length means
5775 that the next byte is repeated -n times. A zero terminates the
5779 _rleAppend(RLECTX *self, int c)
5783 if (c != self->last)
5785 /* The run has stopped. See if it is worthwhile writing it out
5786 as a run. Note that the random data comes in as runs of
5789 if (self->runLen > RLE_CHANGE_COST)
5791 /* Yes, worthwhile. */
5792 /* Commit whatever was in the buffer. */
5794 emit2(".db -%u,0x%02X", self->runLen, self->last);
5798 /* Not worthwhile. Append to the end of the random list. */
5799 for (i = 0; i < self->runLen; i++)
5801 if (self->pos >= RLE_MAX_BLOCK)
5806 self->buffer[self->pos++] = self->last;
5814 if (self->runLen >= RLE_MAX_BLOCK)
5816 /* Commit whatever was in the buffer. */
5819 emit2 (".db -%u,0x%02X", self->runLen, self->last);
5827 _rleFlush(RLECTX *self)
5829 _rleAppend(self, -1);
5836 /** genArrayInit - Special code for initialising an array with constant
5840 genArrayInit (iCode * ic)
5844 int elementSize = 0, eIndex, i;
5845 unsigned val, lastVal;
5849 memset(&rle, 0, sizeof(rle));
5851 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
5853 if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD)
5855 /* Emit the support function call and the destination address. */
5856 emit2("call __initrleblock");
5857 emit2(".dw %s", aopGetWord (AOP(IC_LEFT(ic)), 0));
5861 wassertl (0, "Unexpected operand to genArrayInit.\n");
5864 type = operandType(IC_LEFT(ic));
5866 if (type && type->next)
5868 elementSize = getSize(type->next);
5872 wassertl (0, "Can't determine element size in genArrayInit.");
5875 iLoop = IC_ARRAYILIST(ic);
5876 lastVal = (unsigned)-1;
5878 /* Feed all the bytes into the run length encoder which will handle
5880 This works well for mixed char data, and for random int and long
5889 for (i = 0; i < ix; i++)
5891 for (eIndex = 0; eIndex < elementSize; eIndex++)
5893 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
5894 _rleAppend(&rle, val);
5899 iLoop = iLoop->next;
5903 /* Mark the end of the run. */
5906 freeAsmop (IC_LEFT(ic), NULL, ic);
5909 /*-----------------------------------------------------------------*/
5910 /* genZ80Code - generate code for Z80 based controllers */
5911 /*-----------------------------------------------------------------*/
5913 genZ80Code (iCode * lic)
5921 _fReturn = _gbz80_return;
5922 _fTmp = _gbz80_return;
5926 _fReturn = _z80_return;
5927 _fTmp = _z80_return;
5930 _G.lines.head = _G.lines.current = NULL;
5932 for (ic = lic; ic; ic = ic->next)
5935 if (cln != ic->lineno)
5937 emit2 ("; %s %d", ic->filename, ic->lineno);
5940 /* if the result is marked as
5941 spilt and rematerializable or code for
5942 this has already been generated then
5944 if (resultRemat (ic) || ic->generated)
5947 /* depending on the operation */
5951 emitDebug ("; genNot");
5956 emitDebug ("; genCpl");
5961 emitDebug ("; genUminus");
5966 emitDebug ("; genIpush");
5971 /* IPOP happens only when trying to restore a
5972 spilt live range, if there is an ifx statement
5973 following this pop then the if statement might
5974 be using some of the registers being popped which
5975 would destory the contents of the register so
5976 we need to check for this condition and handle it */
5978 ic->next->op == IFX &&
5979 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
5981 emitDebug ("; genIfx");
5982 genIfx (ic->next, ic);
5986 emitDebug ("; genIpop");
5992 emitDebug ("; genCall");
5997 emitDebug ("; genPcall");
6002 emitDebug ("; genFunction");
6007 emitDebug ("; genEndFunction");
6008 genEndFunction (ic);
6012 emitDebug ("; genRet");
6017 emitDebug ("; genLabel");
6022 emitDebug ("; genGoto");
6027 emitDebug ("; genPlus");
6032 emitDebug ("; genMinus");
6037 emitDebug ("; genMult");
6042 emitDebug ("; genDiv");
6047 emitDebug ("; genMod");
6052 emitDebug ("; genCmpGt");
6053 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
6057 emitDebug ("; genCmpLt");
6058 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
6065 /* note these two are xlated by algebraic equivalence
6066 during parsing SDCC.y */
6067 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
6068 "got '>=' or '<=' shouldn't have come here");
6072 emitDebug ("; genCmpEq");
6073 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
6077 emitDebug ("; genAndOp");
6082 emitDebug ("; genOrOp");
6087 emitDebug ("; genXor");
6088 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
6092 emitDebug ("; genOr");
6093 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
6097 emitDebug ("; genAnd");
6098 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
6102 emitDebug ("; genInline");
6107 emitDebug ("; genRRC");
6112 emitDebug ("; genRLC");
6117 emitDebug ("; genGetHBIT");
6122 emitDebug ("; genLeftShift");
6127 emitDebug ("; genRightShift");
6131 case GET_VALUE_AT_ADDRESS:
6132 emitDebug ("; genPointerGet");
6138 if (POINTER_SET (ic))
6140 emitDebug ("; genAssign (pointer)");
6145 emitDebug ("; genAssign");
6151 emitDebug ("; genIfx");
6156 emitDebug ("; genAddrOf");
6161 emitDebug ("; genJumpTab");
6166 emitDebug ("; genCast");
6171 emitDebug ("; genReceive");
6176 emitDebug ("; addSet");
6177 addSet (&_G.sendSet, ic);
6190 /* now we are ready to call the
6191 peep hole optimizer */
6192 if (!options.nopeep)
6193 peepHole (&_G.lines.head);
6195 /* This is unfortunate */
6196 /* now do the actual printing */
6198 FILE *fp = codeOutFile;
6199 if (isInHome () && codeOutFile == code->oFile)
6200 codeOutFile = home->oFile;
6201 printLine (_G.lines.head, codeOutFile);
6202 if (_G.flushStatics)
6205 _G.flushStatics = 0;
6214 _isPairUsed (iCode * ic, PAIR_ID pairId)
6220 if (bitVectBitValue (ic->rMask, D_IDX))
6222 if (bitVectBitValue (ic->rMask, E_IDX))
6232 fetchLitSpecial (asmop * aop, bool negate, bool xor)
6235 value *val = aop->aopu.aop_lit;
6237 wassert (aop->type == AOP_LIT);
6238 wassert (!IS_FLOAT (val->type));
6240 v = (unsigned long) floatFromVal (val);
6248 tsprintf (buffer, "!immedword", v);
6249 return gc_strdup (buffer);