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])
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;
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);
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);
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 */
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);
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 aopPut (AOP (result), "blah", 0);
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)
1646 /* if type float then do float */
1647 if (IS_FLOAT (optype))
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)
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)
1777 optype = operandType (IC_LEFT (ic));
1778 rtype = operandType (IC_RESULT (ic));
1780 /* if float then do float stuff */
1781 if (IS_FLOAT (optype))
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 wassert (size <= 4);
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))
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)
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)
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 */
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)
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))))
3128 freeAsmop (IC_LEFT (ic), NULL, ic);
3129 freeAsmop (IC_RIGHT (ic), NULL, ic);
3130 freeAsmop (IC_RESULT (ic), NULL, ic);
3133 /*-----------------------------------------------------------------*/
3134 /* genMult - generates code for multiplication */
3135 /*-----------------------------------------------------------------*/
3137 genMult (iCode * ic)
3139 /* Shouldn't occur - all done through function calls */
3143 /*-----------------------------------------------------------------*/
3144 /* genDiv - generates code for division */
3145 /*-----------------------------------------------------------------*/
3149 /* Shouldn't occur - all done through function calls */
3153 /*-----------------------------------------------------------------*/
3154 /* genMod - generates code for division */
3155 /*-----------------------------------------------------------------*/
3159 /* Shouldn't occur - all done through function calls */
3163 /*-----------------------------------------------------------------*/
3164 /* genIfxJump :- will create a jump depending on the ifx */
3165 /*-----------------------------------------------------------------*/
3167 genIfxJump (iCode * ic, char *jval)
3172 /* if true label then we jump if condition
3176 jlbl = IC_TRUE (ic);
3177 if (!strcmp (jval, "a"))
3181 else if (!strcmp (jval, "c"))
3185 else if (!strcmp (jval, "nc"))
3191 /* The buffer contains the bit on A that we should test */
3197 /* false label is present */
3198 jlbl = IC_FALSE (ic);
3199 if (!strcmp (jval, "a"))
3203 else if (!strcmp (jval, "c"))
3207 else if (!strcmp (jval, "nc"))
3213 /* The buffer contains the bit on A that we should test */
3217 /* Z80 can do a conditional long jump */
3218 if (!strcmp (jval, "a"))
3222 else if (!strcmp (jval, "c"))
3225 else if (!strcmp (jval, "nc"))
3230 emit2 ("bit %s,a", jval);
3232 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
3234 /* mark the icode as generated */
3240 _getPairIdName (PAIR_ID id)
3242 return _pairs[id].name;
3246 /** Generic compare for > or <
3249 genCmp (operand * left, operand * right,
3250 operand * result, iCode * ifx, int sign)
3252 int size, offset = 0;
3253 unsigned long lit = 0L;
3254 bool swap_sense = FALSE;
3256 /* if left & right are bit variables */
3257 if (AOP_TYPE (left) == AOP_CRY &&
3258 AOP_TYPE (right) == AOP_CRY)
3260 /* Cant happen on the Z80 */
3265 /* subtract right from left if at the
3266 end the carry flag is set then we know that
3267 left is greater than right */
3268 size = max (AOP_SIZE (left), AOP_SIZE (right));
3270 /* if unsigned char cmp with lit, just compare */
3272 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
3274 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3277 emit2 ("xor a,!immedbyte", 0x80);
3278 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
3281 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3283 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
3285 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
3286 // Pull left into DE and right into HL
3287 aopGet (AOP(left), LSB, FALSE);
3290 aopGet (AOP(right), LSB, FALSE);
3294 if (size == 0 && sign)
3296 // Highest byte when signed needs the bits flipped
3299 emit2 ("ld a,(de)");
3300 emit2 ("xor #0x80");
3302 emit2 ("ld a,(hl)");
3303 emit2 ("xor #0x80");
3307 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
3311 emit2 ("ld a,(de)");
3312 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
3322 spillPair (PAIR_HL);
3326 if (AOP_TYPE (right) == AOP_LIT)
3328 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3329 /* optimize if(x < 0) or if(x >= 0) */
3334 /* No sign so it's always false */
3339 /* Just load in the top most bit */
3340 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
3341 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
3343 genIfxJump (ifx, "7");
3354 /* First setup h and l contaning the top most bytes XORed */
3355 bool fDidXor = FALSE;
3356 if (AOP_TYPE (left) == AOP_LIT)
3358 unsigned long lit = (unsigned long)
3359 floatFromVal (AOP (left)->aopu.aop_lit);
3360 emit2 ("ld %s,!immedbyte", _fTmp[0],
3361 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3365 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
3366 emit2 ("xor a,!immedbyte", 0x80);
3367 emit2 ("ld %s,a", _fTmp[0]);
3370 if (AOP_TYPE (right) == AOP_LIT)
3372 unsigned long lit = (unsigned long)
3373 floatFromVal (AOP (right)->aopu.aop_lit);
3374 emit2 ("ld %s,!immedbyte", _fTmp[1],
3375 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3379 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
3380 emit2 ("xor a,!immedbyte", 0x80);
3381 emit2 ("ld %s,a", _fTmp[1]);
3387 /* Do a long subtract */
3390 _moveA (aopGet (AOP (left), offset, FALSE));
3392 if (sign && size == 0)
3394 emit2 ("ld a,%s", _fTmp[0]);
3395 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
3399 /* Subtract through, propagating the carry */
3400 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset++, FALSE));
3407 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
3409 outBitCLong (result, swap_sense);
3413 /* if the result is used in the next
3414 ifx conditional branch then generate
3415 code a little differently */
3417 genIfxJump (ifx, swap_sense ? "nc" : "c");
3419 outBitCLong (result, swap_sense);
3420 /* leave the result in acc */
3424 /*-----------------------------------------------------------------*/
3425 /* genCmpGt :- greater than comparison */
3426 /*-----------------------------------------------------------------*/
3428 genCmpGt (iCode * ic, iCode * ifx)
3430 operand *left, *right, *result;
3431 sym_link *letype, *retype;
3434 left = IC_LEFT (ic);
3435 right = IC_RIGHT (ic);
3436 result = IC_RESULT (ic);
3438 letype = getSpec (operandType (left));
3439 retype = getSpec (operandType (right));
3440 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
3441 /* assign the amsops */
3442 aopOp (left, ic, FALSE, FALSE);
3443 aopOp (right, ic, FALSE, FALSE);
3444 aopOp (result, ic, TRUE, FALSE);
3446 genCmp (right, left, result, ifx, sign);
3448 freeAsmop (left, NULL, ic);
3449 freeAsmop (right, NULL, ic);
3450 freeAsmop (result, NULL, ic);
3453 /*-----------------------------------------------------------------*/
3454 /* genCmpLt - less than comparisons */
3455 /*-----------------------------------------------------------------*/
3457 genCmpLt (iCode * ic, iCode * ifx)
3459 operand *left, *right, *result;
3460 sym_link *letype, *retype;
3463 left = IC_LEFT (ic);
3464 right = IC_RIGHT (ic);
3465 result = IC_RESULT (ic);
3467 letype = getSpec (operandType (left));
3468 retype = getSpec (operandType (right));
3469 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
3471 /* assign the amsops */
3472 aopOp (left, ic, FALSE, FALSE);
3473 aopOp (right, ic, FALSE, FALSE);
3474 aopOp (result, ic, TRUE, FALSE);
3476 genCmp (left, right, result, ifx, sign);
3478 freeAsmop (left, NULL, ic);
3479 freeAsmop (right, NULL, ic);
3480 freeAsmop (result, NULL, ic);
3483 /*-----------------------------------------------------------------*/
3484 /* gencjneshort - compare and jump if not equal */
3485 /*-----------------------------------------------------------------*/
3487 gencjneshort (operand * left, operand * right, symbol * lbl)
3489 int size = max (AOP_SIZE (left), AOP_SIZE (right));
3491 unsigned long lit = 0L;
3493 /* Swap the left and right if it makes the computation easier */
3494 if (AOP_TYPE (left) == AOP_LIT)
3501 if (AOP_TYPE (right) == AOP_LIT)
3502 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3504 /* if the right side is a literal then anything goes */
3505 if (AOP_TYPE (right) == AOP_LIT &&
3506 AOP_TYPE (left) != AOP_DIR)
3510 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3517 emit2 ("or a,%s", aopGet (AOP (left), offset, FALSE));
3524 emit2 ("jp nz,!tlabel", lbl->key + 100);
3530 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3531 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
3534 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
3535 emit2 ("jp nz,!tlabel", lbl->key + 100);
3540 /* if the right side is in a register or in direct space or
3541 if the left is a pointer register & right is not */
3542 else if (AOP_TYPE (right) == AOP_REG ||
3543 AOP_TYPE (right) == AOP_DIR ||
3544 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
3548 _moveA (aopGet (AOP (left), offset, FALSE));
3549 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
3550 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
3552 emit2 ("jp nz,!tlabel", lbl->key + 100);
3555 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3556 emit2 ("jp nz,!tlabel", lbl->key + 100);
3563 /* right is a pointer reg need both a & b */
3564 /* PENDING: is this required? */
3567 _moveA (aopGet (AOP (right), offset, FALSE));
3568 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
3569 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
3575 /*-----------------------------------------------------------------*/
3576 /* gencjne - compare and jump if not equal */
3577 /*-----------------------------------------------------------------*/
3579 gencjne (operand * left, operand * right, symbol * lbl)
3581 symbol *tlbl = newiTempLabel (NULL);
3583 gencjneshort (left, right, lbl);
3586 emit2 ("ld a,!one");
3587 emit2 ("!shortjp !tlabel", tlbl->key + 100);
3588 emitLabel (lbl->key + 100);
3590 emitLabel (tlbl->key + 100);
3593 /*-----------------------------------------------------------------*/
3594 /* genCmpEq - generates code for equal to */
3595 /*-----------------------------------------------------------------*/
3597 genCmpEq (iCode * ic, iCode * ifx)
3599 operand *left, *right, *result;
3601 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
3602 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
3603 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
3605 emitDebug ("; genCmpEq: left %u, right %u, result %u\n", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
3607 /* Swap operands if it makes the operation easier. ie if:
3608 1. Left is a literal.
3610 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
3612 operand *t = IC_RIGHT (ic);
3613 IC_RIGHT (ic) = IC_LEFT (ic);
3617 if (ifx && !AOP_SIZE (result))
3620 /* if they are both bit variables */
3621 if (AOP_TYPE (left) == AOP_CRY &&
3622 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
3628 tlbl = newiTempLabel (NULL);
3629 gencjneshort (left, right, tlbl);
3632 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
3633 emitLabel (tlbl->key + 100);
3637 /* PENDING: do this better */
3638 symbol *lbl = newiTempLabel (NULL);
3639 emit2 ("!shortjp !tlabel", lbl->key + 100);
3640 emitLabel (tlbl->key + 100);
3641 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
3642 emitLabel (lbl->key + 100);
3645 /* mark the icode as generated */
3650 /* if they are both bit variables */
3651 if (AOP_TYPE (left) == AOP_CRY &&
3652 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
3658 gencjne (left, right, newiTempLabel (NULL));
3659 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
3665 genIfxJump (ifx, "a");
3668 /* if the result is used in an arithmetic operation
3669 then put the result in place */
3670 if (AOP_TYPE (result) != AOP_CRY)
3674 /* leave the result in acc */
3678 freeAsmop (left, NULL, ic);
3679 freeAsmop (right, NULL, ic);
3680 freeAsmop (result, NULL, ic);
3683 /*-----------------------------------------------------------------*/
3684 /* ifxForOp - returns the icode containing the ifx for operand */
3685 /*-----------------------------------------------------------------*/
3687 ifxForOp (operand * op, iCode * ic)
3689 /* if true symbol then needs to be assigned */
3690 if (IS_TRUE_SYMOP (op))
3693 /* if this has register type condition and
3694 the next instruction is ifx with the same operand
3695 and live to of the operand is upto the ifx only then */
3697 ic->next->op == IFX &&
3698 IC_COND (ic->next)->key == op->key &&
3699 OP_SYMBOL (op)->liveTo <= ic->next->seq)
3705 /*-----------------------------------------------------------------*/
3706 /* genAndOp - for && operation */
3707 /*-----------------------------------------------------------------*/
3709 genAndOp (iCode * ic)
3711 operand *left, *right, *result;
3714 /* note here that && operations that are in an if statement are
3715 taken away by backPatchLabels only those used in arthmetic
3716 operations remain */
3717 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
3718 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
3719 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
3721 /* if both are bit variables */
3722 if (AOP_TYPE (left) == AOP_CRY &&
3723 AOP_TYPE (right) == AOP_CRY)
3729 tlbl = newiTempLabel (NULL);
3731 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3733 emitLabel (tlbl->key + 100);
3737 freeAsmop (left, NULL, ic);
3738 freeAsmop (right, NULL, ic);
3739 freeAsmop (result, NULL, ic);
3742 /*-----------------------------------------------------------------*/
3743 /* genOrOp - for || operation */
3744 /*-----------------------------------------------------------------*/
3746 genOrOp (iCode * ic)
3748 operand *left, *right, *result;
3751 /* note here that || operations that are in an
3752 if statement are taken away by backPatchLabels
3753 only those used in arthmetic operations remain */
3754 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
3755 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
3756 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
3758 /* if both are bit variables */
3759 if (AOP_TYPE (left) == AOP_CRY &&
3760 AOP_TYPE (right) == AOP_CRY)
3766 tlbl = newiTempLabel (NULL);
3768 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3770 emitLabel (tlbl->key + 100);
3774 freeAsmop (left, NULL, ic);
3775 freeAsmop (right, NULL, ic);
3776 freeAsmop (result, NULL, ic);
3779 /*-----------------------------------------------------------------*/
3780 /* isLiteralBit - test if lit == 2^n */
3781 /*-----------------------------------------------------------------*/
3783 isLiteralBit (unsigned long lit)
3785 unsigned long pw[32] =
3786 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
3787 0x100L, 0x200L, 0x400L, 0x800L,
3788 0x1000L, 0x2000L, 0x4000L, 0x8000L,
3789 0x10000L, 0x20000L, 0x40000L, 0x80000L,
3790 0x100000L, 0x200000L, 0x400000L, 0x800000L,
3791 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
3792 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
3795 for (idx = 0; idx < 32; idx++)
3801 /*-----------------------------------------------------------------*/
3802 /* jmpTrueOrFalse - */
3803 /*-----------------------------------------------------------------*/
3805 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
3807 // ugly but optimized by peephole
3810 symbol *nlbl = newiTempLabel (NULL);
3811 emit2 ("jp !tlabel", nlbl->key + 100);
3812 emitLabel (tlbl->key + 100);
3813 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
3814 emitLabel (nlbl->key + 100);
3818 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
3819 emitLabel (tlbl->key + 100);
3824 /*-----------------------------------------------------------------*/
3825 /* genAnd - code for and */
3826 /*-----------------------------------------------------------------*/
3828 genAnd (iCode * ic, iCode * ifx)
3830 operand *left, *right, *result;
3831 int size, offset = 0;
3832 unsigned long lit = 0L;
3835 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
3836 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
3837 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
3839 /* if left is a literal & right is not then exchange them */
3840 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
3841 AOP_NEEDSACC (left))
3843 operand *tmp = right;
3848 /* if result = right then exchange them */
3849 if (sameRegs (AOP (result), AOP (right)))
3851 operand *tmp = right;
3856 /* if right is bit then exchange them */
3857 if (AOP_TYPE (right) == AOP_CRY &&
3858 AOP_TYPE (left) != AOP_CRY)
3860 operand *tmp = right;
3864 if (AOP_TYPE (right) == AOP_LIT)
3865 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3867 size = AOP_SIZE (result);
3869 if (AOP_TYPE (left) == AOP_CRY)
3875 // if(val & 0xZZ) - size = 0, ifx != FALSE -
3876 // bit = val & 0xZZ - size = 1, ifx = FALSE -
3877 if ((AOP_TYPE (right) == AOP_LIT) &&
3878 (AOP_TYPE (result) == AOP_CRY) &&
3879 (AOP_TYPE (left) != AOP_CRY))
3881 int posbit = isLiteralBit (lit);
3886 _moveA (aopGet (AOP (left), posbit >> 3, FALSE));
3891 emit2 ("mov c,acc.%d", posbit & 0x07);
3898 sprintf (buffer, "%d", posbit & 0x07);
3899 genIfxJump (ifx, buffer);
3910 symbol *tlbl = newiTempLabel (NULL);
3911 int sizel = AOP_SIZE (left);
3919 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
3921 _moveA (aopGet (AOP (left), offset, FALSE));
3923 if ((posbit = isLiteralBit (bytelit)) != 0)
3926 emit2 ("jb acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
3930 if (bytelit != 0x0FFL)
3932 aopGet (AOP (right), offset, FALSE));
3936 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3941 // bit = left & literal
3945 emit2 ("!tlabeldef", tlbl->key + 100);
3947 // if(left & literal)
3951 jmpTrueOrFalse (ifx, tlbl);
3959 /* if left is same as result */
3960 if (sameRegs (AOP (result), AOP (left)))
3962 for (; size--; offset++)
3964 if (AOP_TYPE (right) == AOP_LIT)
3966 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
3971 aopPut (AOP (result), "!zero", offset);
3974 _moveA (aopGet (AOP (left), offset, FALSE));
3976 aopGet (AOP (right), offset, FALSE));
3977 aopPut (AOP (left), "a", offset);
3984 if (AOP_TYPE (left) == AOP_ACC)
3990 _moveA (aopGet (AOP (left), offset, FALSE));
3992 aopGet (AOP (right), offset, FALSE));
3993 aopPut (AOP (left), "a", offset);
4000 // left & result in different registers
4001 if (AOP_TYPE (result) == AOP_CRY)
4007 for (; (size--); offset++)
4010 // result = left & right
4011 if (AOP_TYPE (right) == AOP_LIT)
4013 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4015 aopPut (AOP (result),
4016 aopGet (AOP (left), offset, FALSE),
4020 else if (bytelit == 0)
4022 aopPut (AOP (result), "!zero", offset);
4026 // faster than result <- left, anl result,right
4027 // and better if result is SFR
4028 if (AOP_TYPE (left) == AOP_ACC)
4029 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4032 _moveA (aopGet (AOP (left), offset, FALSE));
4034 aopGet (AOP (right), offset, FALSE));
4036 aopPut (AOP (result), "a", offset);
4043 freeAsmop (left, NULL, ic);
4044 freeAsmop (right, NULL, ic);
4045 freeAsmop (result, NULL, ic);
4048 /*-----------------------------------------------------------------*/
4049 /* genOr - code for or */
4050 /*-----------------------------------------------------------------*/
4052 genOr (iCode * ic, iCode * ifx)
4054 operand *left, *right, *result;
4055 int size, offset = 0;
4056 unsigned long lit = 0L;
4058 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4059 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4060 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4062 /* if left is a literal & right is not then exchange them */
4063 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4064 AOP_NEEDSACC (left))
4066 operand *tmp = right;
4071 /* if result = right then exchange them */
4072 if (sameRegs (AOP (result), AOP (right)))
4074 operand *tmp = right;
4079 /* if right is bit then exchange them */
4080 if (AOP_TYPE (right) == AOP_CRY &&
4081 AOP_TYPE (left) != AOP_CRY)
4083 operand *tmp = right;
4087 if (AOP_TYPE (right) == AOP_LIT)
4088 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4090 size = AOP_SIZE (result);
4092 if (AOP_TYPE (left) == AOP_CRY)
4098 if ((AOP_TYPE (right) == AOP_LIT) &&
4099 (AOP_TYPE (result) == AOP_CRY) &&
4100 (AOP_TYPE (left) != AOP_CRY))
4106 /* if left is same as result */
4107 if (sameRegs (AOP (result), AOP (left)))
4109 for (; size--; offset++)
4111 if (AOP_TYPE (right) == AOP_LIT)
4113 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4117 _moveA (aopGet (AOP (left), offset, FALSE));
4119 aopGet (AOP (right), offset, FALSE));
4120 aopPut (AOP (result), "a", offset);
4125 if (AOP_TYPE (left) == AOP_ACC)
4126 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4129 _moveA (aopGet (AOP (left), offset, FALSE));
4131 aopGet (AOP (right), offset, FALSE));
4132 aopPut (AOP (result), "a", offset);
4139 // left & result in different registers
4140 if (AOP_TYPE (result) == AOP_CRY)
4145 for (; (size--); offset++)
4148 // result = left & right
4149 if (AOP_TYPE (right) == AOP_LIT)
4151 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4153 aopPut (AOP (result),
4154 aopGet (AOP (left), offset, FALSE),
4159 // faster than result <- left, anl result,right
4160 // and better if result is SFR
4161 if (AOP_TYPE (left) == AOP_ACC)
4162 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4165 _moveA (aopGet (AOP (left), offset, FALSE));
4167 aopGet (AOP (right), offset, FALSE));
4169 aopPut (AOP (result), "a", offset);
4170 /* PENDING: something weird is going on here. Add exception. */
4171 if (AOP_TYPE (result) == AOP_ACC)
4177 freeAsmop (left, NULL, ic);
4178 freeAsmop (right, NULL, ic);
4179 freeAsmop (result, NULL, ic);
4182 /*-----------------------------------------------------------------*/
4183 /* genXor - code for xclusive or */
4184 /*-----------------------------------------------------------------*/
4186 genXor (iCode * ic, iCode * ifx)
4188 operand *left, *right, *result;
4189 int size, offset = 0;
4190 unsigned long lit = 0L;
4192 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4193 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4194 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4196 /* if left is a literal & right is not then exchange them */
4197 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4198 AOP_NEEDSACC (left))
4200 operand *tmp = right;
4205 /* if result = right then exchange them */
4206 if (sameRegs (AOP (result), AOP (right)))
4208 operand *tmp = right;
4213 /* if right is bit then exchange them */
4214 if (AOP_TYPE (right) == AOP_CRY &&
4215 AOP_TYPE (left) != AOP_CRY)
4217 operand *tmp = right;
4221 if (AOP_TYPE (right) == AOP_LIT)
4222 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4224 size = AOP_SIZE (result);
4226 if (AOP_TYPE (left) == AOP_CRY)
4232 if ((AOP_TYPE (right) == AOP_LIT) &&
4233 (AOP_TYPE (result) == AOP_CRY) &&
4234 (AOP_TYPE (left) != AOP_CRY))
4240 /* if left is same as result */
4241 if (sameRegs (AOP (result), AOP (left)))
4243 for (; size--; offset++)
4245 if (AOP_TYPE (right) == AOP_LIT)
4247 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4251 _moveA (aopGet (AOP (right), offset, FALSE));
4253 aopGet (AOP (left), offset, FALSE));
4254 aopPut (AOP (result), "a", offset);
4259 if (AOP_TYPE (left) == AOP_ACC)
4261 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4265 _moveA (aopGet (AOP (right), offset, FALSE));
4267 aopGet (AOP (left), offset, FALSE));
4268 aopPut (AOP (result), "a", 0);
4275 // left & result in different registers
4276 if (AOP_TYPE (result) == AOP_CRY)
4281 for (; (size--); offset++)
4284 // result = left & right
4285 if (AOP_TYPE (right) == AOP_LIT)
4287 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4289 aopPut (AOP (result),
4290 aopGet (AOP (left), offset, FALSE),
4295 // faster than result <- left, anl result,right
4296 // and better if result is SFR
4297 if (AOP_TYPE (left) == AOP_ACC)
4299 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4303 _moveA (aopGet (AOP (right), offset, FALSE));
4305 aopGet (AOP (left), offset, FALSE));
4307 aopPut (AOP (result), "a", offset);
4312 freeAsmop (left, NULL, ic);
4313 freeAsmop (right, NULL, ic);
4314 freeAsmop (result, NULL, ic);
4317 /*-----------------------------------------------------------------*/
4318 /* genInline - write the inline code out */
4319 /*-----------------------------------------------------------------*/
4321 genInline (iCode * ic)
4323 char *buffer, *bp, *bp1;
4325 _G.lines.isInline += (!options.asmpeep);
4327 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
4328 strcpy (buffer, IC_INLINE (ic));
4330 /* emit each line as a code */
4355 _G.lines.isInline -= (!options.asmpeep);
4359 /*-----------------------------------------------------------------*/
4360 /* genRRC - rotate right with carry */
4361 /*-----------------------------------------------------------------*/
4368 /*-----------------------------------------------------------------*/
4369 /* genRLC - generate code for rotate left with carry */
4370 /*-----------------------------------------------------------------*/
4377 /*-----------------------------------------------------------------*/
4378 /* genGetHbit - generates code get highest order bit */
4379 /*-----------------------------------------------------------------*/
4381 genGetHbit (iCode * ic)
4383 operand *left, *result;
4384 left = IC_LEFT (ic);
4385 result = IC_RESULT (ic);
4386 aopOp (left, ic, FALSE, FALSE);
4387 aopOp (result, ic, FALSE, FALSE);
4389 /* get the highest order byte into a */
4390 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4392 if (AOP_TYPE (result) == AOP_CRY)
4400 /* PENDING: For re-target. */
4406 freeAsmop (left, NULL, ic);
4407 freeAsmop (result, NULL, ic);
4411 emitRsh2 (asmop *aop, int size, int is_signed)
4417 const char *l = aopGet (aop, size, FALSE);
4420 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
4430 /*-----------------------------------------------------------------*/
4431 /* shiftR2Left2Result - shift right two bytes from left to result */
4432 /*-----------------------------------------------------------------*/
4434 shiftR2Left2Result (operand * left, int offl,
4435 operand * result, int offr,
4436 int shCount, int is_signed)
4439 symbol *tlbl, *tlbl1;
4441 movLeft2Result (left, offl, result, offr, 0);
4442 movLeft2Result (left, offl + 1, result, offr + 1, 0);
4444 /* if (AOP(result)->type == AOP_REG) { */
4446 tlbl = newiTempLabel (NULL);
4447 tlbl1 = newiTempLabel (NULL);
4449 /* Left is already in result - so now do the shift */
4454 emitRsh2 (AOP (result), size, is_signed);
4459 emit2 ("ld a,!immedbyte+1", shCount);
4460 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4461 emitLabel (tlbl->key + 100);
4463 emitRsh2 (AOP (result), size, is_signed);
4465 emitLabel (tlbl1->key + 100);
4467 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4471 /*-----------------------------------------------------------------*/
4472 /* shiftL2Left2Result - shift left two bytes from left to result */
4473 /*-----------------------------------------------------------------*/
4475 shiftL2Left2Result (operand * left, int offl,
4476 operand * result, int offr, int shCount)
4478 if (sameRegs (AOP (result), AOP (left)) &&
4479 ((offl + MSB16) == offr))
4485 /* Copy left into result */
4486 movLeft2Result (left, offl, result, offr, 0);
4487 movLeft2Result (left, offl + 1, result, offr + 1, 0);
4489 /* PENDING: for now just see if it'll work. */
4490 /*if (AOP(result)->type == AOP_REG) { */
4494 symbol *tlbl, *tlbl1;
4497 tlbl = newiTempLabel (NULL);
4498 tlbl1 = newiTempLabel (NULL);
4500 /* Left is already in result - so now do the shift */
4503 emit2 ("ld a,!immedbyte+1", shCount);
4504 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4505 emitLabel (tlbl->key + 100);
4510 l = aopGet (AOP (result), offset, FALSE);
4514 emit2 ("sla %s", l);
4525 emitLabel (tlbl1->key + 100);
4527 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4532 /*-----------------------------------------------------------------*/
4533 /* AccRol - rotate left accumulator by known count */
4534 /*-----------------------------------------------------------------*/
4536 AccRol (int shCount)
4538 shCount &= 0x0007; // shCount : 0..7
4577 /*-----------------------------------------------------------------*/
4578 /* AccLsh - left shift accumulator by known count */
4579 /*-----------------------------------------------------------------*/
4581 AccLsh (int shCount)
4583 static const unsigned char SLMask[] =
4585 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
4594 else if (shCount == 2)
4601 /* rotate left accumulator */
4603 /* and kill the lower order bits */
4604 emit2 ("and a,!immedbyte", SLMask[shCount]);
4609 /*-----------------------------------------------------------------*/
4610 /* shiftL1Left2Result - shift left one byte from left to result */
4611 /*-----------------------------------------------------------------*/
4613 shiftL1Left2Result (operand * left, int offl,
4614 operand * result, int offr, int shCount)
4617 l = aopGet (AOP (left), offl, FALSE);
4619 /* shift left accumulator */
4621 aopPut (AOP (result), "a", offr);
4625 /*-----------------------------------------------------------------*/
4626 /* genlshTwo - left shift two bytes by known amount != 0 */
4627 /*-----------------------------------------------------------------*/
4629 genlshTwo (operand * result, operand * left, int shCount)
4631 int size = AOP_SIZE (result);
4633 wassert (size == 2);
4635 /* if shCount >= 8 */
4643 movLeft2Result (left, LSB, result, MSB16, 0);
4644 aopPut (AOP (result), "!zero", 0);
4645 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
4649 movLeft2Result (left, LSB, result, MSB16, 0);
4650 aopPut (AOP (result), "!zero", 0);
4655 aopPut (AOP (result), "!zero", LSB);
4658 /* 1 <= shCount <= 7 */
4667 shiftL2Left2Result (left, LSB, result, LSB, shCount);
4672 /*-----------------------------------------------------------------*/
4673 /* genlshOne - left shift a one byte quantity by known count */
4674 /*-----------------------------------------------------------------*/
4676 genlshOne (operand * result, operand * left, int shCount)
4678 shiftL1Left2Result (left, LSB, result, LSB, shCount);
4681 /*-----------------------------------------------------------------*/
4682 /* genLeftShiftLiteral - left shifting by known count */
4683 /*-----------------------------------------------------------------*/
4685 genLeftShiftLiteral (operand * left,
4690 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
4693 freeAsmop (right, NULL, ic);
4695 aopOp (left, ic, FALSE, FALSE);
4696 aopOp (result, ic, FALSE, FALSE);
4698 size = getSize (operandType (result));
4700 /* I suppose that the left size >= result size */
4706 else if (shCount >= (size * 8))
4710 aopPut (AOP (result), "!zero", size);
4718 genlshOne (result, left, shCount);
4721 genlshTwo (result, left, shCount);
4724 wassertl (0, "Shifting of longs is currently unsupported");
4730 freeAsmop (left, NULL, ic);
4731 freeAsmop (result, NULL, ic);
4734 /*-----------------------------------------------------------------*/
4735 /* genLeftShift - generates code for left shifting */
4736 /*-----------------------------------------------------------------*/
4738 genLeftShift (iCode * ic)
4742 symbol *tlbl, *tlbl1;
4743 operand *left, *right, *result;
4745 right = IC_RIGHT (ic);
4746 left = IC_LEFT (ic);
4747 result = IC_RESULT (ic);
4749 aopOp (right, ic, FALSE, FALSE);
4751 /* if the shift count is known then do it
4752 as efficiently as possible */
4753 if (AOP_TYPE (right) == AOP_LIT)
4755 genLeftShiftLiteral (left, right, result, ic);
4759 /* shift count is unknown then we have to form a loop get the loop
4760 count in B : Note: we take only the lower order byte since
4761 shifting more that 32 bits make no sense anyway, ( the largest
4762 size of an object can be only 32 bits ) */
4763 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
4765 freeAsmop (right, NULL, ic);
4766 aopOp (left, ic, FALSE, FALSE);
4767 aopOp (result, ic, FALSE, FALSE);
4769 /* now move the left to the result if they are not the
4772 if (!sameRegs (AOP (left), AOP (result)))
4775 size = AOP_SIZE (result);
4779 l = aopGet (AOP (left), offset, FALSE);
4780 aopPut (AOP (result), l, offset);
4785 tlbl = newiTempLabel (NULL);
4786 size = AOP_SIZE (result);
4788 tlbl1 = newiTempLabel (NULL);
4790 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4791 emitLabel (tlbl->key + 100);
4792 l = aopGet (AOP (result), offset, FALSE);
4796 l = aopGet (AOP (result), offset, FALSE);
4800 emit2 ("sla %s", l);
4808 emitLabel (tlbl1->key + 100);
4810 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4812 freeAsmop (left, NULL, ic);
4813 freeAsmop (result, NULL, ic);
4816 /*-----------------------------------------------------------------*/
4817 /* genrshOne - left shift two bytes by known amount != 0 */
4818 /*-----------------------------------------------------------------*/
4820 genrshOne (operand * result, operand * left, int shCount, int is_signed)
4823 int size = AOP_SIZE (result);
4826 wassert (size == 1);
4827 wassert (shCount < 8);
4829 l = aopGet (AOP (left), 0, FALSE);
4833 if (AOP (result)->type == AOP_REG)
4835 aopPut (AOP (result), l, 0);
4836 l = aopGet (AOP (result), 0, FALSE);
4839 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
4847 emit2 ("%s a", is_signed ? "sra" : "srl");
4849 aopPut (AOP (result), "a", 0);
4853 /*-----------------------------------------------------------------*/
4854 /* AccRsh - right shift accumulator by known count */
4855 /*-----------------------------------------------------------------*/
4857 AccRsh (int shCount)
4859 static const unsigned char SRMask[] =
4861 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
4866 /* rotate right accumulator */
4867 AccRol (8 - shCount);
4868 /* and kill the higher order bits */
4869 emit2 ("and a,!immedbyte", SRMask[shCount]);
4873 /*-----------------------------------------------------------------*/
4874 /* shiftR1Left2Result - shift right one byte from left to result */
4875 /*-----------------------------------------------------------------*/
4877 shiftR1Left2Result (operand * left, int offl,
4878 operand * result, int offr,
4879 int shCount, int sign)
4881 _moveA (aopGet (AOP (left), offl, FALSE));
4886 emit2 ("%s a", sign ? "sra" : "srl");
4893 aopPut (AOP (result), "a", offr);
4896 /*-----------------------------------------------------------------*/
4897 /* genrshTwo - right shift two bytes by known amount != 0 */
4898 /*-----------------------------------------------------------------*/
4900 genrshTwo (operand * result, operand * left,
4901 int shCount, int sign)
4903 /* if shCount >= 8 */
4909 shiftR1Left2Result (left, MSB16, result, LSB,
4914 movLeft2Result (left, MSB16, result, LSB, sign);
4916 aopPut (AOP (result), "!zero", 1);
4918 /* 1 <= shCount <= 7 */
4921 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
4925 /*-----------------------------------------------------------------*/
4926 /* genRightShiftLiteral - left shifting by known count */
4927 /*-----------------------------------------------------------------*/
4929 genRightShiftLiteral (operand * left,
4935 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
4938 freeAsmop (right, NULL, ic);
4940 aopOp (left, ic, FALSE, FALSE);
4941 aopOp (result, ic, FALSE, FALSE);
4943 size = getSize (operandType (result));
4945 /* I suppose that the left size >= result size */
4951 else if (shCount >= (size * 8))
4953 aopPut (AOP (result), "!zero", size);
4959 genrshOne (result, left, shCount, sign);
4962 /* PENDING: sign support */
4963 genrshTwo (result, left, shCount, sign);
4966 wassertl (0, "Asked to shift right a long which should be a function call");
4969 wassertl (0, "Entered default case in right shift delegate");
4972 freeAsmop (left, NULL, ic);
4973 freeAsmop (result, NULL, ic);
4976 /*-----------------------------------------------------------------*/
4977 /* genRightShift - generate code for right shifting */
4978 /*-----------------------------------------------------------------*/
4980 genRightShift (iCode * ic)
4982 operand *right, *left, *result;
4984 int size, offset, first = 1;
4988 symbol *tlbl, *tlbl1;
4990 /* if signed then we do it the hard way preserve the
4991 sign bit moving it inwards */
4992 retype = getSpec (operandType (IC_RESULT (ic)));
4994 is_signed = !SPEC_USIGN (retype);
4996 /* signed & unsigned types are treated the same : i.e. the
4997 signed is NOT propagated inwards : quoting from the
4998 ANSI - standard : "for E1 >> E2, is equivalent to division
4999 by 2**E2 if unsigned or if it has a non-negative value,
5000 otherwise the result is implementation defined ", MY definition
5001 is that the sign does not get propagated */
5003 right = IC_RIGHT (ic);
5004 left = IC_LEFT (ic);
5005 result = IC_RESULT (ic);
5007 aopOp (right, ic, FALSE, FALSE);
5009 /* if the shift count is known then do it
5010 as efficiently as possible */
5011 if (AOP_TYPE (right) == AOP_LIT)
5013 genRightShiftLiteral (left, right, result, ic, is_signed);
5017 aopOp (left, ic, FALSE, FALSE);
5018 aopOp (result, ic, FALSE, FALSE);
5020 /* now move the left to the result if they are not the
5022 if (!sameRegs (AOP (left), AOP (result)) &&
5023 AOP_SIZE (result) > 1)
5026 size = AOP_SIZE (result);
5030 l = aopGet (AOP (left), offset, FALSE);
5031 aopPut (AOP (result), l, offset);
5036 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5038 freeAsmop (right, NULL, ic);
5040 tlbl = newiTempLabel (NULL);
5041 tlbl1 = newiTempLabel (NULL);
5042 size = AOP_SIZE (result);
5045 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5046 emitLabel (tlbl->key + 100);
5049 l = aopGet (AOP (result), offset--, FALSE);
5052 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5060 emitLabel (tlbl1->key + 100);
5062 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5064 freeAsmop (left, NULL, ic);
5065 freeAsmop (result, NULL, ic);
5068 /*-----------------------------------------------------------------*/
5069 /* genGenPointerGet - get value from generic pointer space */
5070 /*-----------------------------------------------------------------*/
5072 genGenPointerGet (operand * left,
5073 operand * result, iCode * ic)
5076 sym_link *retype = getSpec (operandType (result));
5082 aopOp (left, ic, FALSE, FALSE);
5083 aopOp (result, ic, FALSE, FALSE);
5085 if (isPair (AOP (left)) && AOP_SIZE (result) == 1)
5088 if (isPtrPair (AOP (left)))
5090 tsprintf (buffer, "!*pair", getPairName (AOP (left)));
5091 aopPut (AOP (result), buffer, 0);
5095 emit2 ("ld a,!*pair", getPairName (AOP (left)));
5096 aopPut (AOP (result), "a", 0);
5098 freeAsmop (left, NULL, ic);
5102 /* For now we always load into IY */
5103 /* if this is remateriazable */
5104 fetchPair (pair, AOP (left));
5106 /* so iy now contains the address */
5107 freeAsmop (left, NULL, ic);
5109 /* if bit then unpack */
5110 if (IS_BITVAR (retype))
5116 size = AOP_SIZE (result);
5121 /* PENDING: make this better */
5122 if (!IS_GB && AOP (result)->type == AOP_REG)
5124 aopPut (AOP (result), "!*hl", offset++);
5128 emit2 ("ld a,!*pair", _pairs[pair].name);
5129 aopPut (AOP (result), "a", offset++);
5133 emit2 ("inc %s", _pairs[pair].name);
5134 _G.pairs[pair].offset++;
5140 freeAsmop (result, NULL, ic);
5143 /*-----------------------------------------------------------------*/
5144 /* genPointerGet - generate code for pointer get */
5145 /*-----------------------------------------------------------------*/
5147 genPointerGet (iCode * ic)
5149 operand *left, *result;
5150 sym_link *type, *etype;
5152 left = IC_LEFT (ic);
5153 result = IC_RESULT (ic);
5155 /* depending on the type of pointer we need to
5156 move it to the correct pointer register */
5157 type = operandType (left);
5158 etype = getSpec (type);
5160 genGenPointerGet (left, result, ic);
5164 isRegOrLit (asmop * aop)
5166 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
5171 /*-----------------------------------------------------------------*/
5172 /* genGenPointerSet - stores the value into a pointer location */
5173 /*-----------------------------------------------------------------*/
5175 genGenPointerSet (operand * right,
5176 operand * result, iCode * ic)
5179 sym_link *retype = getSpec (operandType (right));
5180 PAIR_ID pairId = PAIR_HL;
5182 aopOp (result, ic, FALSE, FALSE);
5183 aopOp (right, ic, FALSE, FALSE);
5188 /* Handle the exceptions first */
5189 if (isPair (AOP (result)) && (AOP_SIZE (right) == 1))
5192 const char *l = aopGet (AOP (right), 0, FALSE);
5193 const char *pair = getPairName (AOP (result));
5194 if (canAssignToPtr (l) && isPtr (pair))
5196 emit2 ("ld !*pair,%s", pair, l);
5201 emit2 ("ld !*pair,a", pair);
5206 /* if the operand is already in dptr
5207 then we do nothing else we move the value to dptr */
5208 if (AOP_TYPE (result) != AOP_STR)
5210 fetchPair (pairId, AOP (result));
5212 /* so hl know contains the address */
5213 freeAsmop (result, NULL, ic);
5215 /* if bit then unpack */
5216 if (IS_BITVAR (retype))
5222 size = AOP_SIZE (right);
5227 const char *l = aopGet (AOP (right), offset, FALSE);
5228 if (isRegOrLit (AOP (right)) && !IS_GB)
5230 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
5235 emit2 ("ld !*pair,a", _pairs[pairId].name);
5239 emit2 ("inc %s", _pairs[pairId].name);
5240 _G.pairs[pairId].offset++;
5246 freeAsmop (right, NULL, ic);
5249 /*-----------------------------------------------------------------*/
5250 /* genPointerSet - stores the value into a pointer location */
5251 /*-----------------------------------------------------------------*/
5253 genPointerSet (iCode * ic)
5255 operand *right, *result;
5256 sym_link *type, *etype;
5258 right = IC_RIGHT (ic);
5259 result = IC_RESULT (ic);
5261 /* depending on the type of pointer we need to
5262 move it to the correct pointer register */
5263 type = operandType (result);
5264 etype = getSpec (type);
5266 genGenPointerSet (right, result, ic);
5269 /*-----------------------------------------------------------------*/
5270 /* genIfx - generate code for Ifx statement */
5271 /*-----------------------------------------------------------------*/
5273 genIfx (iCode * ic, iCode * popIc)
5275 operand *cond = IC_COND (ic);
5278 aopOp (cond, ic, FALSE, TRUE);
5280 /* get the value into acc */
5281 if (AOP_TYPE (cond) != AOP_CRY)
5285 /* the result is now in the accumulator */
5286 freeAsmop (cond, NULL, ic);
5288 /* if there was something to be popped then do it */
5292 /* if the condition is a bit variable */
5293 if (isbit && IS_ITEMP (cond) &&
5295 genIfxJump (ic, SPIL_LOC (cond)->rname);
5296 else if (isbit && !IS_ITEMP (cond))
5297 genIfxJump (ic, OP_SYMBOL (cond)->rname);
5299 genIfxJump (ic, "a");
5304 /*-----------------------------------------------------------------*/
5305 /* genAddrOf - generates code for address of */
5306 /*-----------------------------------------------------------------*/
5308 genAddrOf (iCode * ic)
5310 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
5312 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
5314 /* if the operand is on the stack then we
5315 need to get the stack offset of this
5322 if (sym->stack <= 0)
5324 emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset);
5328 emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
5335 emit2 ("ld de,!hashedstr", sym->rname);
5337 aopPut (AOP (IC_RESULT (ic)), "e", 0);
5338 aopPut (AOP (IC_RESULT (ic)), "d", 1);
5345 /* if it has an offset then we need to compute it */
5347 emit2 ("ld hl,#%d+%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset, _G.stack.param_offset);
5349 emit2 ("ld hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
5350 emit2 ("add hl,sp");
5354 emit2 ("ld hl,#%s", sym->rname);
5356 aopPut (AOP (IC_RESULT (ic)), "l", 0);
5357 aopPut (AOP (IC_RESULT (ic)), "h", 1);
5359 freeAsmop (IC_RESULT (ic), NULL, ic);
5362 /*-----------------------------------------------------------------*/
5363 /* genAssign - generate code for assignment */
5364 /*-----------------------------------------------------------------*/
5366 genAssign (iCode * ic)
5368 operand *result, *right;
5370 unsigned long lit = 0L;
5372 result = IC_RESULT (ic);
5373 right = IC_RIGHT (ic);
5375 /* Dont bother assigning if they are the same */
5376 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5378 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
5382 aopOp (right, ic, FALSE, FALSE);
5383 aopOp (result, ic, TRUE, FALSE);
5385 /* if they are the same registers */
5386 if (sameRegs (AOP (right), AOP (result)))
5388 emitDebug ("; (registers are the same)");
5392 /* if the result is a bit */
5393 if (AOP_TYPE (result) == AOP_CRY)
5399 size = AOP_SIZE (result);
5402 if (AOP_TYPE (right) == AOP_LIT)
5403 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5404 if (isPair (AOP (result)))
5406 fetchPair (getPairId (AOP (result)), AOP (right));
5408 else if ((size > 1) &&
5409 (AOP_TYPE (result) != AOP_REG) &&
5410 (AOP_TYPE (right) == AOP_LIT) &&
5411 !IS_FLOAT (operandType (right)) &&
5414 bool fXored = FALSE;
5416 /* Work from the top down.
5417 Done this way so that we can use the cached copy of 0
5418 in A for a fast clear */
5421 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
5423 if (!fXored && size > 1)
5430 aopPut (AOP (result), "a", offset);
5434 aopPut (AOP (result), "!zero", offset);
5438 aopPut (AOP (result),
5439 aopGet (AOP (right), offset, FALSE),
5444 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
5446 /* Special case. Load into a and d, then load out. */
5447 _moveA (aopGet (AOP (right), 0, FALSE));
5448 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
5449 aopPut (AOP (result), "a", 0);
5450 aopPut (AOP (result), "e", 1);
5452 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
5454 /* Special case - simple memcpy */
5455 aopGet (AOP (right), LSB, FALSE);
5458 aopGet (AOP (result), LSB, FALSE);
5462 emit2 ("ld a,(de)");
5463 /* Peephole will optimise this. */
5464 emit2 ("ld (hl),a");
5472 spillPair (PAIR_HL);
5478 /* PENDING: do this check better */
5479 if (requiresHL (AOP (right)) && requiresHL (AOP (result)))
5481 _moveA (aopGet (AOP (right), offset, FALSE));
5482 aopPut (AOP (result), "a", offset);
5485 aopPut (AOP (result),
5486 aopGet (AOP (right), offset, FALSE),
5493 freeAsmop (right, NULL, ic);
5494 freeAsmop (result, NULL, ic);
5497 /*-----------------------------------------------------------------*/
5498 /* genJumpTab - genrates code for jump table */
5499 /*-----------------------------------------------------------------*/
5501 genJumpTab (iCode * ic)
5506 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
5507 /* get the condition into accumulator */
5508 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
5511 emit2 ("ld e,%s", l);
5512 emit2 ("ld d,!zero");
5513 jtab = newiTempLabel (NULL);
5515 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
5516 emit2 ("add hl,de");
5517 emit2 ("add hl,de");
5518 emit2 ("add hl,de");
5519 freeAsmop (IC_JTCOND (ic), NULL, ic);
5523 emitLabel (jtab->key + 100);
5524 /* now generate the jump labels */
5525 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
5526 jtab = setNextItem (IC_JTLABELS (ic)))
5527 emit2 ("jp !tlabel", jtab->key + 100);
5530 /*-----------------------------------------------------------------*/
5531 /* genCast - gen code for casting */
5532 /*-----------------------------------------------------------------*/
5534 genCast (iCode * ic)
5536 operand *result = IC_RESULT (ic);
5537 sym_link *ctype = operandType (IC_LEFT (ic));
5538 operand *right = IC_RIGHT (ic);
5541 /* if they are equivalent then do nothing */
5542 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5545 aopOp (right, ic, FALSE, FALSE);
5546 aopOp (result, ic, FALSE, FALSE);
5548 /* if the result is a bit */
5549 if (AOP_TYPE (result) == AOP_CRY)
5554 /* if they are the same size : or less */
5555 if (AOP_SIZE (result) <= AOP_SIZE (right))
5558 /* if they are in the same place */
5559 if (sameRegs (AOP (right), AOP (result)))
5562 /* if they in different places then copy */
5563 size = AOP_SIZE (result);
5567 aopPut (AOP (result),
5568 aopGet (AOP (right), offset, FALSE),
5575 /* So we now know that the size of destination is greater
5576 than the size of the source */
5577 /* we move to result for the size of source */
5578 size = AOP_SIZE (right);
5582 aopPut (AOP (result),
5583 aopGet (AOP (right), offset, FALSE),
5588 /* now depending on the sign of the destination */
5589 size = AOP_SIZE (result) - AOP_SIZE (right);
5590 /* Unsigned or not an integral type - right fill with zeros */
5591 if (SPEC_USIGN (ctype) || !IS_SPEC (ctype))
5594 aopPut (AOP (result), "!zero", offset++);
5598 /* we need to extend the sign :{ */
5599 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
5605 aopPut (AOP (result), "a", offset++);
5609 freeAsmop (right, NULL, ic);
5610 freeAsmop (result, NULL, ic);
5613 /*-----------------------------------------------------------------*/
5614 /* genReceive - generate code for a receive iCode */
5615 /*-----------------------------------------------------------------*/
5617 genReceive (iCode * ic)
5619 if (isOperandInFarSpace (IC_RESULT (ic)) &&
5620 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
5621 IS_TRUE_SYMOP (IC_RESULT (ic))))
5631 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
5632 size = AOP_SIZE(IC_RESULT(ic));
5634 for (i = 0; i < size; i++) {
5635 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
5639 freeAsmop (IC_RESULT (ic), NULL, ic);
5644 /** Maximum number of bytes to emit per line. */
5648 /** Context for the byte output chunker. */
5651 unsigned char buffer[DBEMIT_MAX_RUN];
5656 /** Flushes a byte chunker by writing out all in the buffer and
5660 _dbFlush(DBEMITCTX *self)
5667 sprintf(line, ".db 0x%02X", self->buffer[0]);
5669 for (i = 1; i < self->pos; i++)
5671 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
5678 /** Write out another byte, buffering until a decent line is
5682 _dbEmit(DBEMITCTX *self, int c)
5684 if (self->pos == DBEMIT_MAX_RUN)
5688 self->buffer[self->pos++] = c;
5691 /** Context for a simple run length encoder. */
5695 unsigned char buffer[128];
5697 /** runLen may be equivalent to pos. */
5703 RLE_CHANGE_COST = 4,
5707 /** Flush the buffer of a run length encoder by writing out the run or
5708 data that it currently contains.
5711 _rleCommit(RLECTX *self)
5717 memset(&db, 0, sizeof(db));
5719 emit2(".db %u", self->pos);
5721 for (i = 0; i < self->pos; i++)
5723 _dbEmit(&db, self->buffer[i]);
5732 Can get either a run or a block of random stuff.
5733 Only want to change state if a good run comes in or a run ends.
5734 Detecting run end is easy.
5737 Say initial state is in run, len zero, last zero. Then if you get a
5738 few zeros then something else then a short run will be output.
5739 Seems OK. While in run mode, keep counting. While in random mode,
5740 keep a count of the run. If run hits margin, output all up to run,
5741 restart, enter run mode.
5744 /** Add another byte into the run length encoder, flushing as
5745 required. The run length encoder uses the Amiga IFF style, where
5746 a block is prefixed by its run length. A positive length means
5747 the next n bytes pass straight through. A negative length means
5748 that the next byte is repeated -n times. A zero terminates the
5752 _rleAppend(RLECTX *self, int c)
5756 if (c != self->last)
5758 /* The run has stopped. See if it is worthwhile writing it out
5759 as a run. Note that the random data comes in as runs of
5762 if (self->runLen > RLE_CHANGE_COST)
5764 /* Yes, worthwhile. */
5765 /* Commit whatever was in the buffer. */
5767 emit2(".db -%u,0x%02X", self->runLen, self->last);
5771 /* Not worthwhile. Append to the end of the random list. */
5772 for (i = 0; i < self->runLen; i++)
5774 if (self->pos >= RLE_MAX_BLOCK)
5779 self->buffer[self->pos++] = self->last;
5787 if (self->runLen >= RLE_MAX_BLOCK)
5789 /* Commit whatever was in the buffer. */
5792 emit2 (".db -%u,0x%02X", self->runLen, self->last);
5800 _rleFlush(RLECTX *self)
5802 _rleAppend(self, -1);
5809 /** genArrayInit - Special code for initialising an array with constant
5813 genArrayInit (iCode * ic)
5817 int elementSize = 0, eIndex, i;
5818 unsigned val, lastVal;
5822 memset(&rle, 0, sizeof(rle));
5824 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
5826 if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD)
5828 /* Emit the support function call and the destination address. */
5829 emit2("call __initrleblock");
5830 emit2(".dw %s", aopGetWord (AOP(IC_LEFT(ic)), 0));
5834 wassertl (0, "Unexpected operand to genArrayInit.\n");
5837 type = operandType(IC_LEFT(ic));
5839 if (type && type->next)
5841 elementSize = getSize(type->next);
5845 wassertl (0, "Can't determine element size in genArrayInit.");
5848 iLoop = IC_ARRAYILIST(ic);
5849 lastVal = (unsigned)-1;
5851 /* Feed all the bytes into the run length encoder which will handle
5853 This works well for mixed char data, and for random int and long
5862 for (i = 0; i < ix; i++)
5864 for (eIndex = 0; eIndex < elementSize; eIndex++)
5866 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
5867 _rleAppend(&rle, val);
5872 iLoop = iLoop->next;
5876 /* Mark the end of the run. */
5879 freeAsmop (IC_LEFT(ic), NULL, ic);
5882 /*-----------------------------------------------------------------*/
5883 /* genZ80Code - generate code for Z80 based controllers */
5884 /*-----------------------------------------------------------------*/
5886 genZ80Code (iCode * lic)
5894 _fReturn = _gbz80_return;
5895 _fTmp = _gbz80_return;
5899 _fReturn = _z80_return;
5900 _fTmp = _z80_return;
5903 _G.lines.head = _G.lines.current = NULL;
5905 for (ic = lic; ic; ic = ic->next)
5908 if (cln != ic->lineno)
5910 emit2 ("; %s %d", ic->filename, ic->lineno);
5913 /* if the result is marked as
5914 spilt and rematerializable or code for
5915 this has already been generated then
5917 if (resultRemat (ic) || ic->generated)
5920 /* depending on the operation */
5924 emitDebug ("; genNot");
5929 emitDebug ("; genCpl");
5934 emitDebug ("; genUminus");
5939 emitDebug ("; genIpush");
5944 /* IPOP happens only when trying to restore a
5945 spilt live range, if there is an ifx statement
5946 following this pop then the if statement might
5947 be using some of the registers being popped which
5948 would destory the contents of the register so
5949 we need to check for this condition and handle it */
5951 ic->next->op == IFX &&
5952 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
5954 emitDebug ("; genIfx");
5955 genIfx (ic->next, ic);
5959 emitDebug ("; genIpop");
5965 emitDebug ("; genCall");
5970 emitDebug ("; genPcall");
5975 emitDebug ("; genFunction");
5980 emitDebug ("; genEndFunction");
5981 genEndFunction (ic);
5985 emitDebug ("; genRet");
5990 emitDebug ("; genLabel");
5995 emitDebug ("; genGoto");
6000 emitDebug ("; genPlus");
6005 emitDebug ("; genMinus");
6010 emitDebug ("; genMult");
6015 emitDebug ("; genDiv");
6020 emitDebug ("; genMod");
6025 emitDebug ("; genCmpGt");
6026 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
6030 emitDebug ("; genCmpLt");
6031 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
6038 /* note these two are xlated by algebraic equivalence
6039 during parsing SDCC.y */
6040 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
6041 "got '>=' or '<=' shouldn't have come here");
6045 emitDebug ("; genCmpEq");
6046 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
6050 emitDebug ("; genAndOp");
6055 emitDebug ("; genOrOp");
6060 emitDebug ("; genXor");
6061 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
6065 emitDebug ("; genOr");
6066 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
6070 emitDebug ("; genAnd");
6071 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
6075 emitDebug ("; genInline");
6080 emitDebug ("; genRRC");
6085 emitDebug ("; genRLC");
6090 emitDebug ("; genGetHBIT");
6095 emitDebug ("; genLeftShift");
6100 emitDebug ("; genRightShift");
6104 case GET_VALUE_AT_ADDRESS:
6105 emitDebug ("; genPointerGet");
6111 if (POINTER_SET (ic))
6113 emitDebug ("; genAssign (pointer)");
6118 emitDebug ("; genAssign");
6124 emitDebug ("; genIfx");
6129 emitDebug ("; genAddrOf");
6134 emitDebug ("; genJumpTab");
6139 emitDebug ("; genCast");
6144 emitDebug ("; genReceive");
6149 emitDebug ("; addSet");
6150 addSet (&_G.sendSet, ic);
6163 /* now we are ready to call the
6164 peep hole optimizer */
6165 if (!options.nopeep)
6166 peepHole (&_G.lines.head);
6168 /* This is unfortunate */
6169 /* now do the actual printing */
6171 FILE *fp = codeOutFile;
6172 if (isInHome () && codeOutFile == code->oFile)
6173 codeOutFile = home->oFile;
6174 printLine (_G.lines.head, codeOutFile);
6175 if (_G.flushStatics)
6178 _G.flushStatics = 0;
6187 _isPairUsed (iCode * ic, PAIR_ID pairId)
6193 if (bitVectBitValue (ic->rMask, D_IDX))
6195 if (bitVectBitValue (ic->rMask, E_IDX))
6205 fetchLitSpecial (asmop * aop, bool negate, bool xor)
6208 value *val = aop->aopu.aop_lit;
6210 wassert (aop->type == AOP_LIT);
6211 wassert (!IS_FLOAT (val->type));
6213 v = (unsigned long) floatFromVal (val);
6221 tsprintf (buffer, "!immedword", v);
6222 return gc_strdup (buffer);