1 /*-------------------------------------------------------------------------
2 gen.c - Z80 specific code generator.
4 Michael Hope <michaelh@juju.net.nz> 2000
5 Based on the mcs51 generator -
6 Sandeep Dutta . sandeep.dutta@usa.net (1998)
7 and - Jean-Louis VERN.jlvern@writeme.com (1999)
9 This program is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 2, or (at your option) any
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 In other words, you are welcome to use, share and improve this program.
25 You are forbidden to forbid anyone else to use, share and improve
26 what you give them. Help stamp out software-hoarding!
28 -------------------------------------------------------------------------*/
31 Benchmarks on dhry.c 2.1 with 32766 loops and a 10ms clock:
33 Base with asm strcpy / strcmp / memcpy: 23198 141 1A14
34 Improved WORD push 22784 144 19AE
35 With label1 on 22694 144 197E
36 With label2 on 22743 144 198A
37 With label3 on 22776 144 1999
38 With label4 on 22776 144 1999
39 With all 'label' on 22661 144 196F
40 With loopInvariant on 20919 156 19AB
41 With loopInduction on Breaks 198B
42 With all working on 20796 158 196C
43 Slightly better genCmp(signed) 20597 159 195B
44 Better reg packing, first peephole 20038 163 1873
45 With assign packing 19281 165 1849
47 With reg params for mul and div 16234 202 162D
49 1. Starting again at 3 Aug 01 34965 93 219C
51 Includes long mul/div in code
52 2. Optimised memcpy for acc use 32102 102 226B
53 3. Optimised strcpy for acc use 27819 117 2237
54 3a Optimised memcpy fun
55 4. Optimised strcmp fun 21999 149 2294
56 5. Optimised strcmp further 21660 151 228C
57 6. Optimised memcpy by unroling 20885 157 2201
58 7. After turning loop induction on 19862 165 236D
59 8. Same as 7 but with more info
60 9. With asm optimised strings 17030 192 2223
62 10 and below are with asm strings off.
64 Apparent advantage of turning on regparams:
66 Decent case is push of a constant
67 - ld hl,#n; push hl: (10+11)*nargs
68 2. Cost of pull from stack
69 Using asm with ld hl, etc
70 - ld hl,#2; add hl,sp; (ld bc,(hl); hl+=2)*nargs
72 3. Cost of fixing stack
76 So cost is (10+11+7+6+7+10)*nargs+10+11
78 = 123 for mul, div, strcmp, strcpy
79 Saving of (98298+32766+32766+32766)*123 = 24181308
80 At 192 d/s for 682411768t, speed up to 199. Hmm.
88 #ifdef HAVE_SYS_ISA_DEFS_H
89 #include <sys/isa_defs.h>
93 #include "SDCCglobl.h"
94 #include "SDCCpeeph.h"
99 /* this is the down and dirty file with all kinds of kludgy & hacky
100 stuff. This is what it is all about CODE GENERATION for a specific MCU.
101 Some of the routines may be reusable, will have to see */
103 /* Z80 calling convention description.
104 Parameters are passed right to left. As the stack grows downwards,
105 the parameters are arranged in left to right in memory.
106 Parameters may be passed in the HL and DE registers with one
108 PENDING: What if the parameter is a long?
109 Everything is caller saves. i.e. the caller must save any registers
110 that it wants to preserve over the call.
111 The return value is returned in DEHL. DE is normally used as a
112 working register pair. Caller saves allows it to be used for a
114 va args functions do not use register parameters. All arguments
115 are passed on the stack.
116 IX is used as an index register to the top of the local variable
117 area. ix-0 is the top most local variable.
124 static char *_z80_return[] =
125 {"l", "h", "e", "d"};
126 static char *_gbz80_return[] =
127 {"e", "d", "l", "h"};
128 static char *_fReceive[] =
129 { "c", "b", "e", "d" };
131 static char **_fReturn;
134 extern FILE *codeOutFile;
153 } _pairs[NUM_PAIRS] = {
154 { "??1", "?2", "?3" },
159 { "iy", "iy.l?", "iy.h?" },
160 { "ix", "ix.l?", "ix.h?" }
164 #define ACC_NAME _pairs[PAIR_AF].h
166 #define RESULTONSTACK(x) \
167 (IC_RESULT(x) && IC_RESULT(x)->aop && \
168 IC_RESULT(x)->aop->type == AOP_STK )
199 const char *lastFunctionName;
205 /** TRUE if the registers have already been saved. */
218 static const char *aopGet (asmop * aop, int offset, bool bit16);
234 _getTempPairName(void)
236 return _pairs[_getTempPairId()].name;
241 _getTempPairPart(int idx)
243 wassertl (idx == LSB || idx == MSB16, "Invalid pair offset");
247 return _pairs[_getTempPairId()].l;
251 return _pairs[_getTempPairId()].h;
259 /* Clean up the line so that it is 'prettier' */
260 if (strchr (buf, ':'))
262 /* Is a label - cant do anything */
265 /* Change the first (and probably only) ' ' to a tab so
280 _vemit2 (const char *szFormat, va_list ap)
284 tvsprintf (buffer, szFormat, ap);
287 _G.lines.current = (_G.lines.current ?
288 connectLine (_G.lines.current, newLineNode (buffer)) :
289 (_G.lines.head = newLineNode (buffer)));
291 _G.lines.current->isInline = _G.lines.isInline;
295 emit2 (const char *szFormat,...)
299 va_start (ap, szFormat);
301 _vemit2 (szFormat, ap);
307 emitDebug (const char *szFormat,...)
313 va_start (ap, szFormat);
315 _vemit2 (szFormat, ap);
321 /*-----------------------------------------------------------------*/
322 /* emit2 - writes the code into a file : for now it is simple */
323 /*-----------------------------------------------------------------*/
325 _emit2 (const char *inst, const char *fmt,...)
328 char lb[INITIAL_INLINEASM];
335 sprintf (lb, "%s\t", inst);
336 vsprintf (lb + (strlen (lb)), fmt, ap);
339 vsprintf (lb, fmt, ap);
341 while (isspace (*lbp))
346 _G.lines.current = (_G.lines.current ?
347 connectLine (_G.lines.current, newLineNode (lb)) :
348 (_G.lines.head = newLineNode (lb)));
350 _G.lines.current->isInline = _G.lines.isInline;
355 _emitMove(const char *to, const char *from)
357 if (strcasecmp(to, from) != 0)
359 emit2("ld %s,%s", to, from);
364 // Could leave this to the peephole, but sometimes the peephole is inhibited.
369 _moveA(const char *moveFrom)
371 // Let the peephole optimiser take care of redundent loads
372 _emitMove(ACC_NAME, moveFrom);
382 getPairName (asmop * aop)
384 if (aop->type == AOP_REG)
386 switch (aop->aopu.aop_reg[0]->rIdx)
399 else if (aop->type == AOP_STR)
401 switch (*aop->aopu.aop_str[0])
419 getPairId (asmop * aop)
423 if (aop->type == AOP_REG)
425 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX) && (aop->aopu.aop_reg[1]->rIdx == B_IDX))
429 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX) && (aop->aopu.aop_reg[1]->rIdx == D_IDX))
433 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX) && (aop->aopu.aop_reg[1]->rIdx == H_IDX))
438 if (aop->type == AOP_STR)
440 if (!strcmp (aop->aopu.aop_str[0], "c") && !strcmp (aop->aopu.aop_str[1], "b"))
444 if (!strcmp (aop->aopu.aop_str[0], "e") && !strcmp (aop->aopu.aop_str[1], "d"))
448 if (!strcmp (aop->aopu.aop_str[0], "l") && !strcmp (aop->aopu.aop_str[1], "h"))
457 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
461 return (getPairId (aop) != PAIR_INVALID);
465 isPtrPair (asmop * aop)
467 PAIR_ID pairId = getPairId (aop);
478 /** Push a register pair onto the stack */
480 genPairPush (asmop * aop)
482 emit2 ("push %s", getPairName (aop));
486 /*-----------------------------------------------------------------*/
487 /* newAsmop - creates a new asmOp */
488 /*-----------------------------------------------------------------*/
490 newAsmop (short type)
494 aop = Safe_calloc (1, sizeof (asmop));
499 /*-----------------------------------------------------------------*/
500 /* aopForSym - for a true symbol */
501 /*-----------------------------------------------------------------*/
503 aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
510 wassert (sym->etype);
512 space = SPEC_OCLS (sym->etype);
514 /* if already has one */
518 /* Assign depending on the storage class */
519 if (sym->onStack || sym->iaccess)
521 emitDebug ("; AOP_STK for %s", sym->rname);
522 sym->aop = aop = newAsmop (AOP_STK);
523 aop->size = getSize (sym->type);
524 aop->aopu.aop_stk = sym->stack;
528 /* special case for a function */
529 if (IS_FUNC (sym->type))
531 sym->aop = aop = newAsmop (AOP_IMMD);
532 aop->aopu.aop_immd = Safe_calloc (1, strlen (sym->rname) + 1);
533 strcpy (aop->aopu.aop_immd, sym->rname);
540 /* if it is in direct space */
541 if (IN_REGSP (space) && !requires_a)
543 sym->aop = aop = newAsmop (AOP_SFR);
544 aop->aopu.aop_dir = sym->rname;
545 aop->size = getSize (sym->type);
546 emitDebug ("; AOP_SFR for %s", sym->rname);
551 /* only remaining is far space */
552 /* in which case DPTR gets the address */
555 emitDebug ("; AOP_HL for %s", sym->rname);
556 sym->aop = aop = newAsmop (AOP_HL);
560 sym->aop = aop = newAsmop (AOP_IY);
562 aop->size = getSize (sym->type);
563 aop->aopu.aop_dir = sym->rname;
565 /* if it is in code space */
566 if (IN_CODESPACE (space))
572 /*-----------------------------------------------------------------*/
573 /* aopForRemat - rematerialzes an object */
574 /*-----------------------------------------------------------------*/
576 aopForRemat (symbol * sym)
579 iCode *ic = sym->rematiCode;
580 asmop *aop = newAsmop (AOP_IMMD);
584 /* if plus or minus print the right hand side */
585 if (ic->op == '+' || ic->op == '-')
587 /* PENDING: for re-target */
588 sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
591 ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
594 /* we reached the end */
595 sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
599 aop->aopu.aop_immd = Safe_calloc (1, strlen (buffer) + 1);
600 strcpy (aop->aopu.aop_immd, buffer);
604 /*-----------------------------------------------------------------*/
605 /* regsInCommon - two operands have some registers in common */
606 /*-----------------------------------------------------------------*/
608 regsInCommon (operand * op1, operand * op2)
613 /* if they have registers in common */
614 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
617 sym1 = OP_SYMBOL (op1);
618 sym2 = OP_SYMBOL (op2);
620 if (sym1->nRegs == 0 || sym2->nRegs == 0)
623 for (i = 0; i < sym1->nRegs; i++)
629 for (j = 0; j < sym2->nRegs; j++)
634 if (sym2->regs[j] == sym1->regs[i])
642 /*-----------------------------------------------------------------*/
643 /* operandsEqu - equivalent */
644 /*-----------------------------------------------------------------*/
646 operandsEqu (operand * op1, operand * op2)
650 /* if they not symbols */
651 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
654 sym1 = OP_SYMBOL (op1);
655 sym2 = OP_SYMBOL (op2);
657 /* if both are itemps & one is spilt
658 and the other is not then false */
659 if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
660 sym1->isspilt != sym2->isspilt)
663 /* if they are the same */
667 if (strcmp (sym1->rname, sym2->rname) == 0)
671 /* if left is a tmp & right is not */
672 if (IS_ITEMP (op1) &&
675 (sym1->usl.spillLoc == sym2))
678 if (IS_ITEMP (op2) &&
682 (sym2->usl.spillLoc == sym1))
688 /*-----------------------------------------------------------------*/
689 /* sameRegs - two asmops have the same registers */
690 /*-----------------------------------------------------------------*/
692 sameRegs (asmop * aop1, asmop * aop2)
696 if (aop1->type == AOP_SFR ||
697 aop2->type == AOP_SFR)
703 if (aop1->type != AOP_REG ||
704 aop2->type != AOP_REG)
707 if (aop1->size != aop2->size)
710 for (i = 0; i < aop1->size; i++)
711 if (aop1->aopu.aop_reg[i] !=
712 aop2->aopu.aop_reg[i])
718 /*-----------------------------------------------------------------*/
719 /* aopOp - allocates an asmop for an operand : */
720 /*-----------------------------------------------------------------*/
722 aopOp (operand * op, iCode * ic, bool result, bool requires_a)
731 /* if this a literal */
732 if (IS_OP_LITERAL (op))
734 op->aop = aop = newAsmop (AOP_LIT);
735 aop->aopu.aop_lit = op->operand.valOperand;
736 aop->size = getSize (operandType (op));
740 /* if already has a asmop then continue */
744 /* if the underlying symbol has a aop */
745 if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
747 op->aop = OP_SYMBOL (op)->aop;
751 /* if this is a true symbol */
752 if (IS_TRUE_SYMOP (op))
754 op->aop = aopForSym (ic, OP_SYMBOL (op), result, requires_a);
758 /* this is a temporary : this has
764 e) can be a return use only */
766 sym = OP_SYMBOL (op);
768 /* if the type is a conditional */
769 if (sym->regType == REG_CND)
771 aop = op->aop = sym->aop = newAsmop (AOP_CRY);
776 /* if it is spilt then two situations
778 b) has a spill location */
779 if (sym->isspilt || sym->nRegs == 0)
781 /* rematerialize it NOW */
784 sym->aop = op->aop = aop =
786 aop->size = getSize (sym->type);
792 if (sym->accuse == ACCUSE_A)
794 aop = op->aop = sym->aop = newAsmop (AOP_ACC);
795 aop->size = getSize (sym->type);
796 wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
798 aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
800 else if (sym->accuse == ACCUSE_HL)
803 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
804 aop->size = getSize (sym->type);
805 wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
806 aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
807 aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
819 aop = op->aop = sym->aop = newAsmop (AOP_STR);
820 aop->size = getSize (sym->type);
821 for (i = 0; i < 4; i++)
822 aop->aopu.aop_str[i] = _fReturn[i];
826 /* else spill location */
827 sym->aop = op->aop = aop =
828 aopForSym (ic, sym->usl.spillLoc, result, requires_a);
829 aop->size = getSize (sym->type);
833 /* must be in a register */
834 sym->aop = op->aop = aop = newAsmop (AOP_REG);
835 aop->size = sym->nRegs;
836 for (i = 0; i < sym->nRegs; i++)
837 aop->aopu.aop_reg[i] = sym->regs[i];
840 /*-----------------------------------------------------------------*/
841 /* freeAsmop - free up the asmop given to an operand */
842 /*----------------------------------------------------------------*/
844 freeAsmop (operand * op, asmop * aaop, iCode * ic)
862 /* all other cases just dealloc */
868 OP_SYMBOL (op)->aop = NULL;
869 /* if the symbol has a spill */
871 SPIL_LOC (op)->aop = NULL;
877 isLitWord (asmop * aop)
879 /* if (aop->size != 2)
892 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
897 /* depending on type */
903 /* PENDING: for re-target */
905 tsprintf (s, "!hashedstr + %d", aop->aopu.aop_immd, offset);
907 tsprintf (s, "%s + %d", aop->aopu.aop_immd, offset);
913 value *val = aop->aopu.aop_lit;
914 /* if it is a float then it gets tricky */
915 /* otherwise it is fairly simple */
916 if (!IS_FLOAT (val->type))
918 unsigned long v = (unsigned long) floatFromVal (val);
924 else if (offset == 0)
930 wassertl(0, "Encountered an invalid offset while fetching a literal");
934 tsprintf (buffer, "!immedword", v);
936 tsprintf (buffer, "!constword", v);
938 return gc_strdup(buffer);
944 convertFloat (&f, floatFromVal (val));
946 tsprintf (buffer, "!immedword", f.w[offset / 2]);
948 tsprintf (buffer, "!constword", f.w[offset / 2]);
949 rs = Safe_calloc (1, strlen (buffer) + 1);
950 return strcpy (rs, buffer);
959 aopGetWord (asmop * aop, int offset)
961 return aopGetLitWordLong (aop, offset, TRUE);
965 isPtr (const char *s)
967 if (!strcmp (s, "hl"))
969 if (!strcmp (s, "ix"))
971 if (!strcmp (s, "iy"))
977 adjustPair (const char *pair, int *pold, int new)
983 emit2 ("inc %s", pair);
988 emit2 ("dec %s", pair);
994 spillPair (PAIR_ID pairId)
996 _G.pairs[pairId].last_type = AOP_INVALID;
997 _G.pairs[pairId].lit = NULL;
1003 spillPair (PAIR_HL);
1004 spillPair (PAIR_IY);
1008 requiresHL (asmop * aop)
1022 fetchLitSpecial (asmop * aop, bool negate, bool xor)
1025 value *val = aop->aopu.aop_lit;
1027 wassert (aop->type == AOP_LIT);
1028 wassert (!IS_FLOAT (val->type));
1030 v = (unsigned long) floatFromVal (val);
1038 tsprintf (buffer, "!immedword", v);
1039 return gc_strdup (buffer);
1043 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1046 const char *pair = _pairs[pairId].name;
1047 l = aopGetLitWordLong (left, offset, FALSE);
1048 wassert (l && pair);
1052 if (pairId == PAIR_HL || pairId == PAIR_IY)
1054 if (_G.pairs[pairId].last_type == left->type)
1056 if (_G.pairs[pairId].lit && !strcmp (_G.pairs[pairId].lit, l))
1058 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1060 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1063 if (pairId == PAIR_IY && abs (offset) < 127)
1070 _G.pairs[pairId].last_type = left->type;
1071 _G.pairs[pairId].lit = gc_strdup (l);
1072 _G.pairs[pairId].offset = offset;
1074 if (IS_GB && pairId == PAIR_DE && 0)
1076 if (_G.pairs[pairId].lit && !strcmp (_G.pairs[pairId].lit, l))
1078 if (abs (_G.pairs[pairId].offset - offset) < 3)
1080 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1084 _G.pairs[pairId].last_type = left->type;
1085 _G.pairs[pairId].lit = gc_strdup (l);
1086 _G.pairs[pairId].offset = offset;
1088 /* Both a lit on the right and a true symbol on the left */
1089 emit2 ("ld %s,!hashedstr", pair, l);
1093 fetchPairLong (PAIR_ID pairId, asmop * aop, int offset)
1095 /* if this is remateriazable */
1096 if (isLitWord (aop)) {
1097 fetchLitPair (pairId, aop, offset);
1100 /* we need to get it byte by byte */
1101 if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1102 aopGet (aop, offset, FALSE);
1103 switch (aop->size - offset) {
1105 emit2 ("ld l,!*hl");
1106 emit2 ("ld h,!immedbyte", 0);
1109 // PENDING: Requires that you are only fetching two bytes.
1112 emit2 ("ld h,!*hl");
1116 wassertl (0, "Attempted to fetch too much data into HL");
1120 else if (IS_Z80 && aop->type == AOP_IY) {
1121 /* Instead of fetching relative to IY, just grab directly
1122 from the address IY refers to */
1123 char *l = aopGetLitWordLong (aop, offset, FALSE);
1125 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1127 if (aop->size < 2) {
1128 emit2("ld %s,!zero", _pairs[pairId].h);
1132 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1133 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1135 /* PENDING: check? */
1136 if (pairId == PAIR_HL)
1137 spillPair (PAIR_HL);
1142 fetchPair (PAIR_ID pairId, asmop * aop)
1144 fetchPairLong (pairId, aop, 0);
1148 fetchHL (asmop * aop)
1150 fetchPair (PAIR_HL, aop);
1154 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1156 assert (pairId == PAIR_HL || pairId == PAIR_IY);
1161 fetchLitPair (pairId, aop, 0);
1164 fetchLitPair (pairId, aop, offset);
1165 _G.pairs[pairId].offset = offset;
1169 /* Doesnt include _G.stack.pushed */
1170 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1171 if (aop->aopu.aop_stk > 0)
1173 abso += _G.stack.param_offset;
1175 assert (pairId == PAIR_HL);
1176 /* In some cases we can still inc or dec hl */
1177 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1179 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1183 emit2 ("!ldahlsp", abso + _G.stack.pushed);
1185 _G.pairs[pairId].offset = abso;
1191 _G.pairs[pairId].last_type = aop->type;
1197 emit2 ("!tlabeldef", key);
1201 /*-----------------------------------------------------------------*/
1202 /* aopGet - for fetching value of the aop */
1203 /*-----------------------------------------------------------------*/
1205 aopGet (asmop * aop, int offset, bool bit16)
1209 /* offset is greater than size then zero */
1210 /* PENDING: this seems a bit screwed in some pointer cases. */
1211 if (offset > (aop->size - 1) &&
1212 aop->type != AOP_LIT)
1214 tsprintf (s, "!zero");
1215 return gc_strdup(s);
1218 /* depending on type */
1222 /* PENDING: re-target */
1224 tsprintf (s, "!immedwords", aop->aopu.aop_immd);
1229 tsprintf (s, "!bankimmeds", aop->aopu.aop_immd);
1232 tsprintf (s, "!msbimmeds", aop->aopu.aop_immd);
1235 tsprintf (s, "!lsbimmeds", aop->aopu.aop_immd);
1241 return gc_strdup(s);
1245 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1248 return gc_strdup(s);
1252 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1255 return gc_strdup(s);
1258 return aop->aopu.aop_reg[offset]->name;
1262 setupPair (PAIR_HL, aop, offset);
1263 tsprintf (s, "!*hl");
1265 return gc_strdup (s);
1269 setupPair (PAIR_IY, aop, offset);
1270 tsprintf (s, "!*iyx", offset);
1272 return gc_strdup(s);
1277 setupPair (PAIR_HL, aop, offset);
1278 tsprintf (s, "!*hl");
1282 if (aop->aopu.aop_stk >= 0)
1283 offset += _G.stack.param_offset;
1284 tsprintf (s, "!*ixx", aop->aopu.aop_stk + offset);
1287 return gc_strdup(s);
1299 tsprintf(s, "!zero");
1300 return gc_strdup(s);
1304 wassert (offset < 2);
1305 return aop->aopu.aop_str[offset];
1308 return aopLiteral (aop->aopu.aop_lit, offset);
1312 return aop->aopu.aop_str[offset];
1317 wassertl (0, "aopget got unsupported aop->type");
1322 isRegString (const char *s)
1324 if (!strcmp (s, "b") ||
1336 isConstant (const char *s)
1338 /* This is a bit of a hack... */
1339 return (*s == '#' || *s == '$');
1343 canAssignToPtr (const char *s)
1345 if (isRegString (s))
1352 /*-----------------------------------------------------------------*/
1353 /* aopPut - puts a string for a aop */
1354 /*-----------------------------------------------------------------*/
1356 aopPut (asmop * aop, const char *s, int offset)
1360 if (aop->size && offset > (aop->size - 1))
1362 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1363 "aopPut got offset > aop->size");
1368 tsprintf(buffer2, s);
1371 /* will assign value to value */
1372 /* depending on where it is ofcourse */
1378 if (strcmp (s, "a"))
1379 emit2 ("ld a,%s", s);
1380 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1385 if (strcmp (s, "a"))
1386 emit2 ("ld a,%s", s);
1387 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1391 if (!strcmp (s, "!*hl"))
1392 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1395 aop->aopu.aop_reg[offset]->name, s);
1400 setupPair (PAIR_IY, aop, offset);
1401 if (!canAssignToPtr (s))
1403 emit2 ("ld a,%s", s);
1404 emit2 ("ld !*iyx,a", offset);
1407 emit2 ("ld !*iyx,%s", offset, s);
1412 /* PENDING: for re-target */
1413 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1415 emit2 ("ld a,!*hl");
1418 setupPair (PAIR_HL, aop, offset);
1420 emit2 ("ld !*hl,%s", s);
1426 /* PENDING: re-target */
1427 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1429 emit2 ("ld a,!*hl");
1432 setupPair (PAIR_HL, aop, offset);
1433 if (!canAssignToPtr (s))
1435 emit2 ("ld a,%s", s);
1436 emit2 ("ld !*hl,a");
1439 emit2 ("ld !*hl,%s", s);
1443 if (aop->aopu.aop_stk >= 0)
1444 offset += _G.stack.param_offset;
1445 if (!canAssignToPtr (s))
1447 emit2 ("ld a,%s", s);
1448 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
1451 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
1456 /* if bit variable */
1457 if (!aop->aopu.aop_dir)
1464 /* In bit space but not in C - cant happen */
1471 if (strcmp (aop->aopu.aop_str[offset], s))
1473 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1479 if (!offset && (strcmp (s, "acc") == 0))
1484 emitDebug ("; Error aopPut AOP_ACC");
1488 if (strcmp (aop->aopu.aop_str[offset], s))
1489 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1494 wassert (offset < 2);
1495 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1499 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1500 "aopPut got unsupported aop->type");
1505 #define AOP(op) op->aop
1506 #define AOP_TYPE(op) AOP(op)->type
1507 #define AOP_SIZE(op) AOP(op)->size
1508 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
1511 commitPair (asmop * aop, PAIR_ID id)
1513 if (id == PAIR_HL && requiresHL (aop))
1517 aopPut (aop, "a", 0);
1518 aopPut (aop, "d", 1);
1522 aopPut (aop, _pairs[id].l, 0);
1523 aopPut (aop, _pairs[id].h, 1);
1527 /*-----------------------------------------------------------------*/
1528 /* getDataSize - get the operand data size */
1529 /*-----------------------------------------------------------------*/
1531 getDataSize (operand * op)
1534 size = AOP_SIZE (op);
1543 /*-----------------------------------------------------------------*/
1544 /* movLeft2Result - move byte from left to result */
1545 /*-----------------------------------------------------------------*/
1547 movLeft2Result (operand * left, int offl,
1548 operand * result, int offr, int sign)
1551 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
1553 l = aopGet (AOP (left), offl, FALSE);
1557 aopPut (AOP (result), l, offr);
1567 /** Put Acc into a register set
1570 outAcc (operand * result)
1573 size = getDataSize (result);
1576 aopPut (AOP (result), "a", 0);
1579 /* unsigned or positive */
1582 aopPut (AOP (result), "!zero", offset++);
1587 /** Take the value in carry and put it into a register
1590 outBitCLong (operand * result, bool swap_sense)
1592 /* if the result is bit */
1593 if (AOP_TYPE (result) == AOP_CRY)
1595 emitDebug ("; Note: outBitC form 1");
1596 aopPut (AOP (result), "blah", 0);
1600 emit2 ("ld a,!zero");
1603 emit2 ("xor a,!immedbyte", 1);
1609 outBitC (operand * result)
1611 outBitCLong (result, FALSE);
1614 /*-----------------------------------------------------------------*/
1615 /* toBoolean - emit code for orl a,operator(sizeop) */
1616 /*-----------------------------------------------------------------*/
1618 _toBoolean (operand * oper)
1620 int size = AOP_SIZE (oper);
1624 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
1627 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
1631 if (AOP (oper)->type != AOP_ACC)
1634 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
1639 /*-----------------------------------------------------------------*/
1640 /* genNot - generate code for ! operation */
1641 /*-----------------------------------------------------------------*/
1645 sym_link *optype = operandType (IC_LEFT (ic));
1647 /* assign asmOps to operand & result */
1648 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
1649 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1651 /* if in bit space then a special case */
1652 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1657 /* if type float then do float */
1658 if (IS_FLOAT (optype))
1663 _toBoolean (IC_LEFT (ic));
1668 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
1669 emit2 ("sub a,!one");
1670 outBitC (IC_RESULT (ic));
1672 /* release the aops */
1673 freeAsmop (IC_LEFT (ic), NULL, ic);
1674 freeAsmop (IC_RESULT (ic), NULL, ic);
1677 /*-----------------------------------------------------------------*/
1678 /* genCpl - generate code for complement */
1679 /*-----------------------------------------------------------------*/
1687 /* assign asmOps to operand & result */
1688 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1689 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1691 /* if both are in bit space then
1693 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1694 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1699 size = AOP_SIZE (IC_RESULT (ic));
1702 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
1705 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1708 /* release the aops */
1709 freeAsmop (IC_LEFT (ic), NULL, ic);
1710 freeAsmop (IC_RESULT (ic), NULL, ic);
1713 /*-----------------------------------------------------------------*/
1714 /* genUminus - unary minus code generation */
1715 /*-----------------------------------------------------------------*/
1717 genUminus (iCode * ic)
1720 sym_link *optype, *rtype;
1723 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1724 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1726 /* if both in bit space then special
1728 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1729 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1735 optype = operandType (IC_LEFT (ic));
1736 rtype = operandType (IC_RESULT (ic));
1738 /* if float then do float stuff */
1739 if (IS_FLOAT (optype))
1745 /* otherwise subtract from zero */
1746 size = AOP_SIZE (IC_LEFT (ic));
1751 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
1752 emit2 ("ld a,!zero");
1753 emit2 ("sbc a,%s", l);
1754 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1757 /* if any remaining bytes in the result */
1758 /* we just need to propagate the sign */
1759 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
1764 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1768 /* release the aops */
1769 freeAsmop (IC_LEFT (ic), NULL, ic);
1770 freeAsmop (IC_RESULT (ic), NULL, ic);
1774 _push (PAIR_ID pairId)
1776 emit2 ("push %s", _pairs[pairId].name);
1777 _G.stack.pushed += 2;
1781 _pop (PAIR_ID pairId)
1783 emit2 ("pop %s", _pairs[pairId].name);
1784 _G.stack.pushed -= 2;
1788 /*-----------------------------------------------------------------*/
1789 /* assignResultValue - */
1790 /*-----------------------------------------------------------------*/
1792 assignResultValue (operand * oper)
1794 int size = AOP_SIZE (oper);
1797 wassert (size <= 4);
1798 topInA = requiresHL (AOP (oper));
1802 wassert (size <= 2);
1804 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
1806 /* We do it the hard way here. */
1808 aopPut (AOP (oper), _fReturn[0], 0);
1809 aopPut (AOP (oper), _fReturn[1], 1);
1811 aopPut (AOP (oper), _fReturn[0], 2);
1812 aopPut (AOP (oper), _fReturn[1], 3);
1818 aopPut (AOP (oper), _fReturn[size], size);
1824 _saveRegsForCall(iCode *ic, int sendSetSize)
1827 o Stack parameters are pushed before this function enters
1828 o DE and BC may be used in this function.
1829 o HL and DE may be used to return the result.
1830 o HL and DE may be used to send variables.
1831 o DE and BC may be used to store the result value.
1832 o HL may be used in computing the sent value of DE
1833 o The iPushes for other parameters occur before any addSets
1835 Logic: (to be run inside the first iPush or if none, before sending)
1836 o Compute if DE and/or BC are in use over the call
1837 o Compute if DE is used in the send set
1838 o Compute if DE and/or BC are used to hold the result value
1839 o If (DE is used, or in the send set) and is not used in the result, push.
1840 o If BC is used and is not in the result, push
1842 o If DE is used in the send set, fetch
1843 o If HL is used in the send set, fetch
1847 if (_G.saves.saved == FALSE) {
1848 bool deInUse, bcInUse;
1850 bool bcInRet = FALSE, deInRet = FALSE;
1854 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
1858 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), z80_rUmaskForOp (IC_RESULT(ic)));
1862 /* Has no result, so in use is all of in use */
1867 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
1868 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
1870 deSending = (sendSetSize > 1);
1872 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
1874 if (bcInUse && bcInRet == FALSE) {
1876 _G.stack.pushedBC = TRUE;
1878 if (deInUse && deInRet == FALSE) {
1880 _G.stack.pushedDE = TRUE;
1883 _G.saves.saved = TRUE;
1886 /* Already saved. */
1890 /*-----------------------------------------------------------------*/
1891 /* genIpush - genrate code for pushing this gets a little complex */
1892 /*-----------------------------------------------------------------*/
1894 genIpush (iCode * ic)
1896 int size, offset = 0;
1899 /* if this is not a parm push : ie. it is spill push
1900 and spill push is always done on the local stack */
1903 wassertl(0, "Encountered an unsupported spill push.");
1907 if (_G.saves.saved == FALSE) {
1908 /* Caller saves, and this is the first iPush. */
1909 /* Scan ahead until we find the function that we are pushing parameters to.
1910 Count the number of addSets on the way to figure out what registers
1911 are used in the send set.
1914 iCode *walk = ic->next;
1917 if (walk->op == SEND) {
1920 else if (walk->op == CALL || walk->op == PCALL) {
1929 _saveRegsForCall(walk, nAddSets);
1932 /* Already saved by another iPush. */
1935 /* then do the push */
1936 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1938 size = AOP_SIZE (IC_LEFT (ic));
1940 if (isPair (AOP (IC_LEFT (ic))))
1942 _G.stack.pushed += 2;
1943 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
1949 fetchHL (AOP (IC_LEFT (ic)));
1951 spillPair (PAIR_HL);
1952 _G.stack.pushed += 2;
1957 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
1959 spillPair (PAIR_HL);
1960 _G.stack.pushed += 2;
1961 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 0);
1963 spillPair (PAIR_HL);
1964 _G.stack.pushed += 2;
1970 if (AOP (IC_LEFT (ic))->type == AOP_IY)
1972 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
1974 emit2 ("ld a,(%s)", l);
1978 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
1979 emit2 ("ld a,%s", l);
1987 freeAsmop (IC_LEFT (ic), NULL, ic);
1990 /*-----------------------------------------------------------------*/
1991 /* genIpop - recover the registers: can happen only for spilling */
1992 /*-----------------------------------------------------------------*/
1994 genIpop (iCode * ic)
1999 /* if the temp was not pushed then */
2000 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2003 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2004 size = AOP_SIZE (IC_LEFT (ic));
2005 offset = (size - 1);
2006 if (isPair (AOP (IC_LEFT (ic))))
2008 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2016 spillPair (PAIR_HL);
2017 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2021 freeAsmop (IC_LEFT (ic), NULL, ic);
2024 /* This is quite unfortunate */
2026 setArea (int inHome)
2029 static int lastArea = 0;
2031 if (_G.in_home != inHome) {
2033 const char *sz = port->mem.code_name;
2034 port->mem.code_name = "HOME";
2035 emit2("!area", CODE_NAME);
2036 port->mem.code_name = sz;
2039 emit2("!area", CODE_NAME); */
2040 _G.in_home = inHome;
2051 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2055 symbol *sym = OP_SYMBOL (op);
2057 if (sym->isspilt || sym->nRegs == 0)
2060 aopOp (op, ic, FALSE, FALSE);
2063 if (aop->type == AOP_REG)
2066 for (i = 0; i < aop->size; i++)
2068 if (pairId == PAIR_DE)
2070 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2071 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2073 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2076 else if (pairId == PAIR_BC)
2078 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2079 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2081 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2091 freeAsmop (IC_LEFT (ic), NULL, ic);
2095 /** Emit the code for a call statement
2098 emitCall (iCode * ic, bool ispcall)
2100 sym_link *detype = getSpec (operandType (IC_LEFT (ic)));
2102 bitVect *rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
2104 /* if caller saves & we have not saved then */
2110 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2112 /* if send set is not empty then assign */
2117 int nSend = elementsInSet(_G.sendSet);
2118 bool swapped = FALSE;
2120 int _z80_sendOrder[] = {
2125 /* Check if the parameters are swapped. If so route through hl instead. */
2126 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2128 sic = setFirstItem(_G.sendSet);
2129 sic = setNextItem(_G.sendSet);
2131 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2132 /* The second send value is loaded from one the one that holds the first
2133 send, i.e. it is overwritten. */
2134 /* Cache the first in HL, and load the second from HL instead. */
2135 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2136 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2142 for (sic = setFirstItem (_G.sendSet); sic;
2143 sic = setNextItem (_G.sendSet))
2146 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2148 size = AOP_SIZE (IC_LEFT (sic));
2149 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2150 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2152 // PENDING: Mild hack
2153 if (swapped == TRUE && send == 1) {
2155 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2158 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2160 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2163 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2167 freeAsmop (IC_LEFT (sic), NULL, sic);
2174 if (IS_BANKEDCALL (detype))
2176 werror (W_INDIR_BANKED);
2178 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2180 if (isLitWord (AOP (IC_LEFT (ic))))
2182 emitDebug ("; Special case where the pCall is to a constant");
2183 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2187 symbol *rlbl = newiTempLabel (NULL);
2188 spillPair (PAIR_HL);
2189 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2191 _G.stack.pushed += 2;
2193 fetchHL (AOP (IC_LEFT (ic)));
2195 emit2 ("!tlabeldef", (rlbl->key + 100));
2196 _G.stack.pushed -= 2;
2198 freeAsmop (IC_LEFT (ic), NULL, ic);
2202 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2203 OP_SYMBOL (IC_LEFT (ic))->rname :
2204 OP_SYMBOL (IC_LEFT (ic))->name;
2205 if (IS_BANKEDCALL (detype))
2207 emit2 ("call banked_call");
2208 emit2 ("!dws", name);
2209 emit2 ("!dw !bankimmeds", name);
2214 emit2 ("call %s", name);
2219 /* Mark the regsiters as restored. */
2220 _G.saves.saved = FALSE;
2222 /* if we need assign a result value */
2223 if ((IS_ITEMP (IC_RESULT (ic)) &&
2224 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2225 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2226 IS_TRUE_SYMOP (IC_RESULT (ic)))
2229 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2231 assignResultValue (IC_RESULT (ic));
2233 freeAsmop (IC_RESULT (ic), NULL, ic);
2236 /* adjust the stack for parameters if required */
2239 int i = ic->parmBytes;
2241 _G.stack.pushed -= i;
2244 emit2 ("!ldaspsp", i);
2251 emit2 ("ld hl,#%d", i);
2252 emit2 ("add hl,sp");
2269 if (_G.stack.pushedDE)
2271 bool dInUse = bitVectBitValue(rInUse, D_IDX);
2272 bool eInUse = bitVectBitValue(rInUse, E_IDX);
2274 if (dInUse && eInUse)
2290 wassertl (0, "Neither D or E were in use but it was pushed.");
2292 _G.stack.pushedDE = FALSE;
2295 if (_G.stack.pushedBC)
2297 bool bInUse = bitVectBitValue(rInUse, B_IDX);
2298 bool cInUse = bitVectBitValue(rInUse, C_IDX);
2300 // If both B and C are used in the return value, then we won't get
2302 if (bInUse && cInUse)
2318 wassertl (0, "Neither B or C were in use but it was pushed.");
2320 _G.stack.pushedBC = FALSE;
2324 /*-----------------------------------------------------------------*/
2325 /* genCall - generates a call statement */
2326 /*-----------------------------------------------------------------*/
2328 genCall (iCode * ic)
2330 emitCall (ic, FALSE);
2333 /*-----------------------------------------------------------------*/
2334 /* genPcall - generates a call by pointer statement */
2335 /*-----------------------------------------------------------------*/
2337 genPcall (iCode * ic)
2339 emitCall (ic, TRUE);
2342 /*-----------------------------------------------------------------*/
2343 /* resultRemat - result is rematerializable */
2344 /*-----------------------------------------------------------------*/
2346 resultRemat (iCode * ic)
2348 if (SKIP_IC (ic) || ic->op == IFX)
2351 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2353 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2354 if (sym->remat && !POINTER_SET (ic))
2361 extern set *publics;
2363 /*-----------------------------------------------------------------*/
2364 /* genFunction - generated code for function entry */
2365 /*-----------------------------------------------------------------*/
2367 genFunction (iCode * ic)
2369 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2373 bool bcInUse = FALSE;
2374 bool deInUse = FALSE;
2377 setArea (IS_NONBANKED (sym->etype));
2379 /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
2382 _G.receiveOffset = 0;
2386 if (!IS_STATIC (sym->etype))
2388 addSetIfnotP (&publics, sym);
2392 /* Record the last function name for debugging. */
2393 _G.lastFunctionName = sym->rname;
2395 /* Create the function header */
2396 emit2 ("!functionheader", sym->name);
2397 /* PENDING: portability. */
2398 emit2 ("__%s_start:", sym->rname);
2399 emit2 ("!functionlabeldef", sym->rname);
2401 if (options.profile)
2403 emit2 ("!profileenter");
2406 fetype = getSpec (operandType (IC_LEFT (ic)));
2408 /* if critical function then turn interrupts off */
2409 if (SPEC_CRTCL (fetype))
2412 /* if this is an interrupt service routine then save all potentially used registers. */
2413 if (IS_ISR (sym->etype))
2418 /* PENDING: callee-save etc */
2420 _G.stack.param_offset = 0;
2423 /* Detect which registers are used. */
2427 for (i = 0; i < sym->regsUsed->size; i++)
2429 if (bitVectBitValue (sym->regsUsed, i))
2443 /* Other systems use DE as a temporary. */
2454 _G.stack.param_offset += 2;
2457 _G.stack.pushedBC = bcInUse;
2462 _G.stack.param_offset += 2;
2465 _G.stack.pushedDE = deInUse;
2468 /* adjust the stack for the function */
2469 _G.stack.last = sym->stack;
2472 emit2 ("!enterx", sym->stack);
2475 _G.stack.offset = sym->stack;
2478 /*-----------------------------------------------------------------*/
2479 /* genEndFunction - generates epilogue for functions */
2480 /*-----------------------------------------------------------------*/
2482 genEndFunction (iCode * ic)
2484 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2486 if (IS_ISR (sym->etype))
2492 if (SPEC_CRTCL (sym->etype))
2495 /* PENDING: calleeSave */
2497 if (_G.stack.offset)
2499 emit2 ("!leavex", _G.stack.offset);
2507 if (_G.stack.pushedDE)
2510 _G.stack.pushedDE = FALSE;
2513 if (_G.stack.pushedDE)
2516 _G.stack.pushedDE = FALSE;
2520 if (options.profile)
2522 emit2 ("!profileexit");
2526 /* Both baned and non-banked just ret */
2529 /* PENDING: portability. */
2530 emit2 ("__%s_end:", sym->rname);
2532 _G.flushStatics = 1;
2533 _G.stack.pushed = 0;
2534 _G.stack.offset = 0;
2537 /*-----------------------------------------------------------------*/
2538 /* genRet - generate code for return statement */
2539 /*-----------------------------------------------------------------*/
2544 /* Errk. This is a hack until I can figure out how
2545 to cause dehl to spill on a call */
2546 int size, offset = 0;
2548 /* if we have no return value then
2549 just generate the "ret" */
2553 /* we have something to return then
2554 move the return value into place */
2555 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2556 size = AOP_SIZE (IC_LEFT (ic));
2558 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
2562 emit2 ("ld de,%s", l);
2566 emit2 ("ld hl,%s", l);
2571 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
2573 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
2574 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
2580 l = aopGet (AOP (IC_LEFT (ic)), offset,
2582 if (strcmp (_fReturn[offset], l))
2583 emit2 ("ld %s,%s", _fReturn[offset++], l);
2587 freeAsmop (IC_LEFT (ic), NULL, ic);
2590 /* generate a jump to the return label
2591 if the next is not the return statement */
2592 if (!(ic->next && ic->next->op == LABEL &&
2593 IC_LABEL (ic->next) == returnLabel))
2595 emit2 ("jp !tlabel", returnLabel->key + 100);
2598 /*-----------------------------------------------------------------*/
2599 /* genLabel - generates a label */
2600 /*-----------------------------------------------------------------*/
2602 genLabel (iCode * ic)
2604 /* special case never generate */
2605 if (IC_LABEL (ic) == entryLabel)
2608 emitLabel (IC_LABEL (ic)->key + 100);
2611 /*-----------------------------------------------------------------*/
2612 /* genGoto - generates a ljmp */
2613 /*-----------------------------------------------------------------*/
2615 genGoto (iCode * ic)
2617 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
2620 /*-----------------------------------------------------------------*/
2621 /* genPlusIncr :- does addition with increment if possible */
2622 /*-----------------------------------------------------------------*/
2624 genPlusIncr (iCode * ic)
2626 unsigned int icount;
2627 unsigned int size = getDataSize (IC_RESULT (ic));
2628 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
2630 /* will try to generate an increment */
2631 /* if the right side is not a literal
2633 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
2636 emitDebug ("; genPlusIncr");
2638 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
2640 /* If result is a pair */
2641 if (resultId != PAIR_INVALID)
2643 if (isLitWord (AOP (IC_LEFT (ic))))
2645 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
2648 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
2650 fetchPair (resultId, AOP (IC_RIGHT (ic)));
2651 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
2657 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2661 movLeft2Result (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0);
2662 movLeft2Result (IC_LEFT (ic), 1, IC_RESULT (ic), 1, 0);
2666 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
2671 /* if the literal value of the right hand side
2672 is greater than 4 then it is not worth it */
2676 /* if increment 16 bits in register */
2677 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
2683 symbol *tlbl = NULL;
2684 tlbl = newiTempLabel (NULL);
2687 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
2690 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
2693 emitLabel (tlbl->key + 100);
2697 /* if the sizes are greater than 1 then we cannot */
2698 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
2699 AOP_SIZE (IC_LEFT (ic)) > 1)
2702 /* we can if the aops of the left & result match or
2703 if they are in registers and the registers are the
2705 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2709 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
2717 /*-----------------------------------------------------------------*/
2718 /* outBitAcc - output a bit in acc */
2719 /*-----------------------------------------------------------------*/
2721 outBitAcc (operand * result)
2723 symbol *tlbl = newiTempLabel (NULL);
2724 /* if the result is a bit */
2725 if (AOP_TYPE (result) == AOP_CRY)
2731 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
2732 emit2 ("ld a,!one");
2733 emitLabel (tlbl->key + 100);
2738 /*-----------------------------------------------------------------*/
2739 /* genPlus - generates code for addition */
2740 /*-----------------------------------------------------------------*/
2742 genPlus (iCode * ic)
2744 int size, offset = 0;
2746 /* special cases :- */
2748 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2749 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
2750 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2752 /* Swap the left and right operands if:
2754 if literal, literal on the right or
2755 if left requires ACC or right is already
2758 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
2759 (AOP_NEEDSACC (IC_LEFT (ic))) ||
2760 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
2762 operand *t = IC_RIGHT (ic);
2763 IC_RIGHT (ic) = IC_LEFT (ic);
2767 /* if both left & right are in bit
2769 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
2770 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
2776 /* if left in bit space & right literal */
2777 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
2778 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
2780 /* Can happen I guess */
2784 /* if I can do an increment instead
2785 of add then GOOD for ME */
2786 if (genPlusIncr (ic) == TRUE)
2789 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
2791 size = getDataSize (IC_RESULT (ic));
2793 /* Special case when left and right are constant */
2794 if (isPair (AOP (IC_RESULT (ic))))
2797 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
2798 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
2800 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
2806 sprintf (buffer, "#(%s + %s)", left, right);
2807 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
2812 if (isPair (AOP (IC_RIGHT (ic))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
2814 /* Fetch into HL then do the add */
2815 spillPair (PAIR_HL);
2816 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
2817 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
2822 ld hl,sp+n trashes C so we cant afford to do it during an
2823 add with stack based varibles. Worst case is:
2836 So you cant afford to load up hl if either left, right, or result
2837 is on the stack (*sigh*) The alt is:
2845 Combinations in here are:
2846 * If left or right are in bc then the loss is small - trap later
2847 * If the result is in bc then the loss is also small
2851 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
2852 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
2853 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
2855 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
2856 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
2857 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
2858 AOP_SIZE (IC_RIGHT (ic)) <= 2))
2860 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
2862 /* Swap left and right */
2863 operand *t = IC_RIGHT (ic);
2864 IC_RIGHT (ic) = IC_LEFT (ic);
2867 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
2869 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
2870 emit2 ("add hl,bc");
2874 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
2875 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
2876 emit2 ("add hl,de");
2878 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
2890 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
2892 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
2895 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2898 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2902 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
2905 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2908 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2910 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2914 freeAsmop (IC_LEFT (ic), NULL, ic);
2915 freeAsmop (IC_RIGHT (ic), NULL, ic);
2916 freeAsmop (IC_RESULT (ic), NULL, ic);
2920 /*-----------------------------------------------------------------*/
2921 /* genMinusDec :- does subtraction with deccrement if possible */
2922 /*-----------------------------------------------------------------*/
2924 genMinusDec (iCode * ic)
2926 unsigned int icount;
2927 unsigned int size = getDataSize (IC_RESULT (ic));
2929 /* will try to generate an increment */
2930 /* if the right side is not a literal we cannot */
2931 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
2934 /* if the literal value of the right hand side
2935 is greater than 4 then it is not worth it */
2936 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
2939 size = getDataSize (IC_RESULT (ic));
2941 /* if decrement 16 bits in register */
2942 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
2943 (size > 1) && isPair (AOP (IC_RESULT (ic))))
2946 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
2950 /* If result is a pair */
2951 if (isPair (AOP (IC_RESULT (ic))))
2953 movLeft2Result (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0);
2954 movLeft2Result (IC_LEFT (ic), 1, IC_RESULT (ic), 1, 0);
2956 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
2960 /* if increment 16 bits in register */
2961 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
2965 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
2968 emit2 ("dec %s", _getTempPairName());
2971 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
2977 /* if the sizes are greater than 1 then we cannot */
2978 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
2979 AOP_SIZE (IC_LEFT (ic)) > 1)
2982 /* we can if the aops of the left & result match or if they are in
2983 registers and the registers are the same */
2984 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2987 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
2994 /*-----------------------------------------------------------------*/
2995 /* genMinus - generates code for subtraction */
2996 /*-----------------------------------------------------------------*/
2998 genMinus (iCode * ic)
3000 int size, offset = 0;
3001 unsigned long lit = 0L;
3003 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3004 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3005 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3007 /* special cases :- */
3008 /* if both left & right are in bit space */
3009 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3010 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3016 /* if I can do an decrement instead of subtract then GOOD for ME */
3017 if (genMinusDec (ic) == TRUE)
3020 size = getDataSize (IC_RESULT (ic));
3022 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3027 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3031 /* Same logic as genPlus */
3034 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3035 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3036 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3038 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3039 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3040 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3041 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3043 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3044 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3046 if (left == PAIR_INVALID && right == PAIR_INVALID)
3051 else if (right == PAIR_INVALID)
3053 else if (left == PAIR_INVALID)
3056 fetchPair (left, AOP (IC_LEFT (ic)));
3057 /* Order is important. Right may be HL */
3058 fetchPair (right, AOP (IC_RIGHT (ic)));
3060 emit2 ("ld a,%s", _pairs[left].l);
3061 emit2 ("sub a,%s", _pairs[right].l);
3063 emit2 ("ld a,%s", _pairs[left].h);
3064 emit2 ("sbc a,%s", _pairs[right].h);
3066 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3067 aopPut (AOP (IC_RESULT (ic)), "e", 0);
3072 /* Anything could be on the stack, and we can't afford
3073 to setup the base pointer as that may nuke the carry.
3075 emitDebug ("; WARNING: This sub is probably broken.\n");
3080 /* if literal, add a,#-lit, else normal subb */
3083 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3084 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3088 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3091 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3095 /* first add without previous c */
3097 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
3099 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3101 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3104 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3105 AOP_SIZE (IC_LEFT (ic)) == 3 &&
3106 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3110 freeAsmop (IC_LEFT (ic), NULL, ic);
3111 freeAsmop (IC_RIGHT (ic), NULL, ic);
3112 freeAsmop (IC_RESULT (ic), NULL, ic);
3115 /*-----------------------------------------------------------------*/
3116 /* genMult - generates code for multiplication */
3117 /*-----------------------------------------------------------------*/
3119 genMult (iCode * ic)
3121 /* Shouldn't occur - all done through function calls */
3125 /*-----------------------------------------------------------------*/
3126 /* genDiv - generates code for division */
3127 /*-----------------------------------------------------------------*/
3131 /* Shouldn't occur - all done through function calls */
3135 /*-----------------------------------------------------------------*/
3136 /* genMod - generates code for division */
3137 /*-----------------------------------------------------------------*/
3141 /* Shouldn't occur - all done through function calls */
3145 /*-----------------------------------------------------------------*/
3146 /* genIfxJump :- will create a jump depending on the ifx */
3147 /*-----------------------------------------------------------------*/
3149 genIfxJump (iCode * ic, char *jval)
3154 /* if true label then we jump if condition
3158 jlbl = IC_TRUE (ic);
3159 if (!strcmp (jval, "a"))
3163 else if (!strcmp (jval, "c"))
3167 else if (!strcmp (jval, "nc"))
3173 /* The buffer contains the bit on A that we should test */
3179 /* false label is present */
3180 jlbl = IC_FALSE (ic);
3181 if (!strcmp (jval, "a"))
3185 else if (!strcmp (jval, "c"))
3189 else if (!strcmp (jval, "nc"))
3195 /* The buffer contains the bit on A that we should test */
3199 /* Z80 can do a conditional long jump */
3200 if (!strcmp (jval, "a"))
3204 else if (!strcmp (jval, "c"))
3207 else if (!strcmp (jval, "nc"))
3212 emit2 ("bit %s,a", jval);
3214 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
3216 /* mark the icode as generated */
3221 _getPairIdName (PAIR_ID id)
3223 return _pairs[id].name;
3226 /** Generic compare for > or <
3229 genCmp (operand * left, operand * right,
3230 operand * result, iCode * ifx, int sign)
3232 int size, offset = 0;
3233 unsigned long lit = 0L;
3234 bool swap_sense = FALSE;
3236 /* if left & right are bit variables */
3237 if (AOP_TYPE (left) == AOP_CRY &&
3238 AOP_TYPE (right) == AOP_CRY)
3240 /* Cant happen on the Z80 */
3245 /* subtract right from left if at the
3246 end the carry flag is set then we know that
3247 left is greater than right */
3248 size = max (AOP_SIZE (left), AOP_SIZE (right));
3250 /* if unsigned char cmp with lit, just compare */
3252 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
3254 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3257 emit2 ("xor a,!immedbyte", 0x80);
3258 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
3261 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3266 // PENDING: Doesn't work around zero
3270 If the left or the right is a lit:
3271 Load -lit into HL, add to right via, check sense.
3273 if (IS_GB && size == 2 && (AOP_TYPE (right) == AOP_LIT || AOP_TYPE (left) == AOP_LIT))
3275 PAIR_ID id = PAIR_DE;
3276 asmop *lit = AOP (right);
3277 asmop *op = AOP (left);
3280 if (AOP_TYPE (left) == AOP_LIT)
3288 emit2 ("ld e,%s", aopGet (op, 0, 0));
3289 emit2 ("ld a,%s", aopGet (op, 1, 0));
3290 emit2 ("xor a,!immedbyte", 0x80);
3295 id = getPairId (op);
3296 if (id == PAIR_INVALID)
3298 fetchPair (PAIR_DE, op);
3302 spillPair (PAIR_HL);
3303 emit2 ("ld hl,%s", fetchLitSpecial (lit, TRUE, sign));
3304 emit2 ("add hl,%s", _getPairIdName (id));
3308 if (AOP_TYPE (right) == AOP_LIT)
3310 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3311 /* optimize if(x < 0) or if(x >= 0) */
3316 /* No sign so it's always false */
3321 /* Just load in the top most bit */
3322 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
3323 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
3325 genIfxJump (ifx, "7");
3336 /* First setup h and l contaning the top most bytes XORed */
3337 bool fDidXor = FALSE;
3338 if (AOP_TYPE (left) == AOP_LIT)
3340 unsigned long lit = (unsigned long)
3341 floatFromVal (AOP (left)->aopu.aop_lit);
3342 emit2 ("ld %s,!immedbyte", _fTmp[0],
3343 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3347 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
3348 emit2 ("xor a,!immedbyte", 0x80);
3349 emit2 ("ld %s,a", _fTmp[0]);
3352 if (AOP_TYPE (right) == AOP_LIT)
3354 unsigned long lit = (unsigned long)
3355 floatFromVal (AOP (right)->aopu.aop_lit);
3356 emit2 ("ld %s,!immedbyte", _fTmp[1],
3357 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3361 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
3362 emit2 ("xor a,!immedbyte", 0x80);
3363 emit2 ("ld %s,a", _fTmp[1]);
3375 /* Do a long subtract */
3378 _moveA (aopGet (AOP (left), offset, FALSE));
3380 if (sign && size == 0)
3382 emit2 ("ld a,%s", _fTmp[0]);
3383 emit2 ("sbc a,%s", _fTmp[1]);
3387 /* Subtract through, propagating the carry */
3388 emit2 ("sbc a,%s", aopGet (AOP (right), offset++, FALSE));
3395 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
3397 outBitCLong (result, swap_sense);
3401 /* if the result is used in the next
3402 ifx conditional branch then generate
3403 code a little differently */
3405 genIfxJump (ifx, swap_sense ? "nc" : "c");
3407 outBitCLong (result, swap_sense);
3408 /* leave the result in acc */
3412 /*-----------------------------------------------------------------*/
3413 /* genCmpGt :- greater than comparison */
3414 /*-----------------------------------------------------------------*/
3416 genCmpGt (iCode * ic, iCode * ifx)
3418 operand *left, *right, *result;
3419 sym_link *letype, *retype;
3422 left = IC_LEFT (ic);
3423 right = IC_RIGHT (ic);
3424 result = IC_RESULT (ic);
3426 letype = getSpec (operandType (left));
3427 retype = getSpec (operandType (right));
3428 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
3429 /* assign the amsops */
3430 aopOp (left, ic, FALSE, FALSE);
3431 aopOp (right, ic, FALSE, FALSE);
3432 aopOp (result, ic, TRUE, FALSE);
3434 genCmp (right, left, result, ifx, sign);
3436 freeAsmop (left, NULL, ic);
3437 freeAsmop (right, NULL, ic);
3438 freeAsmop (result, NULL, ic);
3441 /*-----------------------------------------------------------------*/
3442 /* genCmpLt - less than comparisons */
3443 /*-----------------------------------------------------------------*/
3445 genCmpLt (iCode * ic, iCode * ifx)
3447 operand *left, *right, *result;
3448 sym_link *letype, *retype;
3451 left = IC_LEFT (ic);
3452 right = IC_RIGHT (ic);
3453 result = IC_RESULT (ic);
3455 letype = getSpec (operandType (left));
3456 retype = getSpec (operandType (right));
3457 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
3459 /* assign the amsops */
3460 aopOp (left, ic, FALSE, FALSE);
3461 aopOp (right, ic, FALSE, FALSE);
3462 aopOp (result, ic, TRUE, FALSE);
3464 genCmp (left, right, result, ifx, sign);
3466 freeAsmop (left, NULL, ic);
3467 freeAsmop (right, NULL, ic);
3468 freeAsmop (result, NULL, ic);
3471 /*-----------------------------------------------------------------*/
3472 /* gencjneshort - compare and jump if not equal */
3473 /*-----------------------------------------------------------------*/
3475 gencjneshort (operand * left, operand * right, symbol * lbl)
3477 int size = max (AOP_SIZE (left), AOP_SIZE (right));
3479 unsigned long lit = 0L;
3481 /* Swap the left and right if it makes the computation easier */
3482 if (AOP_TYPE (left) == AOP_LIT)
3489 if (AOP_TYPE (right) == AOP_LIT)
3490 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3492 /* if the right side is a literal then anything goes */
3493 if (AOP_TYPE (right) == AOP_LIT &&
3494 AOP_TYPE (left) != AOP_DIR)
3498 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3505 emit2 ("or a,%s", aopGet (AOP (left), offset, FALSE));
3512 emit2 ("jp nz,!tlabel", lbl->key + 100);
3518 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3519 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
3522 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
3523 emit2 ("jp nz,!tlabel", lbl->key + 100);
3528 /* if the right side is in a register or in direct space or
3529 if the left is a pointer register & right is not */
3530 else if (AOP_TYPE (right) == AOP_REG ||
3531 AOP_TYPE (right) == AOP_DIR ||
3532 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
3536 _moveA (aopGet (AOP (left), offset, FALSE));
3537 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
3538 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
3540 emit2 ("jp nz,!tlabel", lbl->key + 100);
3543 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3544 emit2 ("jp nz,!tlabel", lbl->key + 100);
3551 /* right is a pointer reg need both a & b */
3552 /* PENDING: is this required? */
3555 _moveA (aopGet (AOP (right), offset, FALSE));
3556 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
3557 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
3563 /*-----------------------------------------------------------------*/
3564 /* gencjne - compare and jump if not equal */
3565 /*-----------------------------------------------------------------*/
3567 gencjne (operand * left, operand * right, symbol * lbl)
3569 symbol *tlbl = newiTempLabel (NULL);
3571 gencjneshort (left, right, lbl);
3574 emit2 ("ld a,!one");
3575 emit2 ("!shortjp !tlabel", tlbl->key + 100);
3576 emitLabel (lbl->key + 100);
3578 emitLabel (tlbl->key + 100);
3581 /*-----------------------------------------------------------------*/
3582 /* genCmpEq - generates code for equal to */
3583 /*-----------------------------------------------------------------*/
3585 genCmpEq (iCode * ic, iCode * ifx)
3587 operand *left, *right, *result;
3589 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
3590 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
3591 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
3593 emitDebug ("; genCmpEq: left %u, right %u, result %u\n", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
3595 /* Swap operands if it makes the operation easier. ie if:
3596 1. Left is a literal.
3598 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
3600 operand *t = IC_RIGHT (ic);
3601 IC_RIGHT (ic) = IC_LEFT (ic);
3605 if (ifx && !AOP_SIZE (result))
3608 /* if they are both bit variables */
3609 if (AOP_TYPE (left) == AOP_CRY &&
3610 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
3616 tlbl = newiTempLabel (NULL);
3617 gencjneshort (left, right, tlbl);
3620 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
3621 emitLabel (tlbl->key + 100);
3625 /* PENDING: do this better */
3626 symbol *lbl = newiTempLabel (NULL);
3627 emit2 ("!shortjp !tlabel", lbl->key + 100);
3628 emitLabel (tlbl->key + 100);
3629 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
3630 emitLabel (lbl->key + 100);
3633 /* mark the icode as generated */
3638 /* if they are both bit variables */
3639 if (AOP_TYPE (left) == AOP_CRY &&
3640 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
3646 gencjne (left, right, newiTempLabel (NULL));
3647 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
3653 genIfxJump (ifx, "a");
3656 /* if the result is used in an arithmetic operation
3657 then put the result in place */
3658 if (AOP_TYPE (result) != AOP_CRY)
3662 /* leave the result in acc */
3666 freeAsmop (left, NULL, ic);
3667 freeAsmop (right, NULL, ic);
3668 freeAsmop (result, NULL, ic);
3671 /*-----------------------------------------------------------------*/
3672 /* ifxForOp - returns the icode containing the ifx for operand */
3673 /*-----------------------------------------------------------------*/
3675 ifxForOp (operand * op, iCode * ic)
3677 /* if true symbol then needs to be assigned */
3678 if (IS_TRUE_SYMOP (op))
3681 /* if this has register type condition and
3682 the next instruction is ifx with the same operand
3683 and live to of the operand is upto the ifx only then */
3685 ic->next->op == IFX &&
3686 IC_COND (ic->next)->key == op->key &&
3687 OP_SYMBOL (op)->liveTo <= ic->next->seq)
3693 /*-----------------------------------------------------------------*/
3694 /* genAndOp - for && operation */
3695 /*-----------------------------------------------------------------*/
3697 genAndOp (iCode * ic)
3699 operand *left, *right, *result;
3702 /* note here that && operations that are in an if statement are
3703 taken away by backPatchLabels only those used in arthmetic
3704 operations remain */
3705 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
3706 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
3707 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
3709 /* if both are bit variables */
3710 if (AOP_TYPE (left) == AOP_CRY &&
3711 AOP_TYPE (right) == AOP_CRY)
3717 tlbl = newiTempLabel (NULL);
3719 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3721 emitLabel (tlbl->key + 100);
3725 freeAsmop (left, NULL, ic);
3726 freeAsmop (right, NULL, ic);
3727 freeAsmop (result, NULL, ic);
3730 /*-----------------------------------------------------------------*/
3731 /* genOrOp - for || operation */
3732 /*-----------------------------------------------------------------*/
3734 genOrOp (iCode * ic)
3736 operand *left, *right, *result;
3739 /* note here that || operations that are in an
3740 if statement are taken away by backPatchLabels
3741 only those used in arthmetic operations remain */
3742 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
3743 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
3744 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
3746 /* if both are bit variables */
3747 if (AOP_TYPE (left) == AOP_CRY &&
3748 AOP_TYPE (right) == AOP_CRY)
3754 tlbl = newiTempLabel (NULL);
3756 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3758 emitLabel (tlbl->key + 100);
3762 freeAsmop (left, NULL, ic);
3763 freeAsmop (right, NULL, ic);
3764 freeAsmop (result, NULL, ic);
3767 /*-----------------------------------------------------------------*/
3768 /* isLiteralBit - test if lit == 2^n */
3769 /*-----------------------------------------------------------------*/
3771 isLiteralBit (unsigned long lit)
3773 unsigned long pw[32] =
3774 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
3775 0x100L, 0x200L, 0x400L, 0x800L,
3776 0x1000L, 0x2000L, 0x4000L, 0x8000L,
3777 0x10000L, 0x20000L, 0x40000L, 0x80000L,
3778 0x100000L, 0x200000L, 0x400000L, 0x800000L,
3779 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
3780 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
3783 for (idx = 0; idx < 32; idx++)
3789 /*-----------------------------------------------------------------*/
3790 /* jmpTrueOrFalse - */
3791 /*-----------------------------------------------------------------*/
3793 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
3795 // ugly but optimized by peephole
3798 symbol *nlbl = newiTempLabel (NULL);
3799 emit2 ("jp !tlabel", nlbl->key + 100);
3800 emitLabel (tlbl->key + 100);
3801 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
3802 emitLabel (nlbl->key + 100);
3806 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
3807 emitLabel (tlbl->key + 100);
3812 /*-----------------------------------------------------------------*/
3813 /* genAnd - code for and */
3814 /*-----------------------------------------------------------------*/
3816 genAnd (iCode * ic, iCode * ifx)
3818 operand *left, *right, *result;
3819 int size, offset = 0;
3820 unsigned long lit = 0L;
3823 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
3824 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
3825 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
3828 emitDebug ("; Type res[%d] = l[%d]&r[%d]",
3830 AOP_TYPE (left), AOP_TYPE (right));
3831 emitDebug ("; Size res[%d] = l[%d]&r[%d]",
3833 AOP_SIZE (left), AOP_SIZE (right));
3836 /* if left is a literal & right is not then exchange them */
3837 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
3838 AOP_NEEDSACC (left))
3840 operand *tmp = right;
3845 /* if result = right then exchange them */
3846 if (sameRegs (AOP (result), AOP (right)))
3848 operand *tmp = right;
3853 /* if right is bit then exchange them */
3854 if (AOP_TYPE (right) == AOP_CRY &&
3855 AOP_TYPE (left) != AOP_CRY)
3857 operand *tmp = right;
3861 if (AOP_TYPE (right) == AOP_LIT)
3862 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3864 size = AOP_SIZE (result);
3866 if (AOP_TYPE (left) == AOP_CRY)
3872 // if(val & 0xZZ) - size = 0, ifx != FALSE -
3873 // bit = val & 0xZZ - size = 1, ifx = FALSE -
3874 if ((AOP_TYPE (right) == AOP_LIT) &&
3875 (AOP_TYPE (result) == AOP_CRY) &&
3876 (AOP_TYPE (left) != AOP_CRY))
3878 int posbit = isLiteralBit (lit);
3883 _moveA (aopGet (AOP (left), posbit >> 3, FALSE));
3888 emit2 ("mov c,acc.%d", posbit & 0x07);
3895 sprintf (buffer, "%d", posbit & 0x07);
3896 genIfxJump (ifx, buffer);
3907 symbol *tlbl = newiTempLabel (NULL);
3908 int sizel = AOP_SIZE (left);
3916 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
3918 _moveA (aopGet (AOP (left), offset, FALSE));
3920 if ((posbit = isLiteralBit (bytelit)) != 0)
3923 emit2 ("jb acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
3927 if (bytelit != 0x0FFL)
3929 aopGet (AOP (right), offset, FALSE));
3933 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3938 // bit = left & literal
3942 emit2 ("!tlabeldef", tlbl->key + 100);
3944 // if(left & literal)
3948 jmpTrueOrFalse (ifx, tlbl);
3956 /* if left is same as result */
3957 if (sameRegs (AOP (result), AOP (left)))
3959 for (; size--; offset++)
3961 if (AOP_TYPE (right) == AOP_LIT)
3963 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
3968 aopPut (AOP (result), "!zero", offset);
3971 _moveA (aopGet (AOP (left), offset, FALSE));
3973 aopGet (AOP (right), offset, FALSE));
3974 aopPut (AOP (left), "a", offset);
3981 if (AOP_TYPE (left) == AOP_ACC)
3987 _moveA (aopGet (AOP (left), offset, FALSE));
3989 aopGet (AOP (right), offset, FALSE));
3990 aopPut (AOP (left), "a", offset);
3997 // left & result in different registers
3998 if (AOP_TYPE (result) == AOP_CRY)
4004 for (; (size--); offset++)
4007 // result = left & right
4008 if (AOP_TYPE (right) == AOP_LIT)
4010 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4012 aopPut (AOP (result),
4013 aopGet (AOP (left), offset, FALSE),
4017 else if (bytelit == 0)
4019 aopPut (AOP (result), "!zero", offset);
4023 // faster than result <- left, anl result,right
4024 // and better if result is SFR
4025 if (AOP_TYPE (left) == AOP_ACC)
4026 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4029 _moveA (aopGet (AOP (left), offset, FALSE));
4031 aopGet (AOP (right), offset, FALSE));
4033 aopPut (AOP (result), "a", offset);
4040 freeAsmop (left, NULL, ic);
4041 freeAsmop (right, NULL, ic);
4042 freeAsmop (result, NULL, ic);
4045 /*-----------------------------------------------------------------*/
4046 /* genOr - code for or */
4047 /*-----------------------------------------------------------------*/
4049 genOr (iCode * ic, iCode * ifx)
4051 operand *left, *right, *result;
4052 int size, offset = 0;
4053 unsigned long lit = 0L;
4055 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4056 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4057 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4060 emitDebug ("; Type res[%d] = l[%d]&r[%d]",
4062 AOP_TYPE (left), AOP_TYPE (right));
4063 emitDebug ("; Size res[%d] = l[%d]&r[%d]",
4065 AOP_SIZE (left), AOP_SIZE (right));
4068 /* if left is a literal & right is not then exchange them */
4069 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4070 AOP_NEEDSACC (left))
4072 operand *tmp = right;
4077 /* if result = right then exchange them */
4078 if (sameRegs (AOP (result), AOP (right)))
4080 operand *tmp = right;
4085 /* if right is bit then exchange them */
4086 if (AOP_TYPE (right) == AOP_CRY &&
4087 AOP_TYPE (left) != AOP_CRY)
4089 operand *tmp = right;
4093 if (AOP_TYPE (right) == AOP_LIT)
4094 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4096 size = AOP_SIZE (result);
4098 if (AOP_TYPE (left) == AOP_CRY)
4104 if ((AOP_TYPE (right) == AOP_LIT) &&
4105 (AOP_TYPE (result) == AOP_CRY) &&
4106 (AOP_TYPE (left) != AOP_CRY))
4112 /* if left is same as result */
4113 if (sameRegs (AOP (result), AOP (left)))
4115 for (; size--; offset++)
4117 if (AOP_TYPE (right) == AOP_LIT)
4119 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4123 _moveA (aopGet (AOP (left), offset, FALSE));
4125 aopGet (AOP (right), offset, FALSE));
4126 aopPut (AOP (result), "a", offset);
4131 if (AOP_TYPE (left) == AOP_ACC)
4132 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4135 _moveA (aopGet (AOP (left), offset, FALSE));
4137 aopGet (AOP (right), offset, FALSE));
4138 aopPut (AOP (result), "a", offset);
4145 // left & result in different registers
4146 if (AOP_TYPE (result) == AOP_CRY)
4151 for (; (size--); offset++)
4154 // result = left & right
4155 if (AOP_TYPE (right) == AOP_LIT)
4157 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4159 aopPut (AOP (result),
4160 aopGet (AOP (left), offset, FALSE),
4165 // faster than result <- left, anl result,right
4166 // and better if result is SFR
4167 if (AOP_TYPE (left) == AOP_ACC)
4168 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4171 _moveA (aopGet (AOP (left), offset, FALSE));
4173 aopGet (AOP (right), offset, FALSE));
4175 aopPut (AOP (result), "a", offset);
4176 /* PENDING: something weird is going on here. Add exception. */
4177 if (AOP_TYPE (result) == AOP_ACC)
4183 freeAsmop (left, NULL, ic);
4184 freeAsmop (right, NULL, ic);
4185 freeAsmop (result, NULL, ic);
4188 /*-----------------------------------------------------------------*/
4189 /* genXor - code for xclusive or */
4190 /*-----------------------------------------------------------------*/
4192 genXor (iCode * ic, iCode * ifx)
4194 operand *left, *right, *result;
4195 int size, offset = 0;
4196 unsigned long lit = 0L;
4198 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4199 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4200 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4202 /* if left is a literal & right is not then exchange them */
4203 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4204 AOP_NEEDSACC (left))
4206 operand *tmp = right;
4211 /* if result = right then exchange them */
4212 if (sameRegs (AOP (result), AOP (right)))
4214 operand *tmp = right;
4219 /* if right is bit then exchange them */
4220 if (AOP_TYPE (right) == AOP_CRY &&
4221 AOP_TYPE (left) != AOP_CRY)
4223 operand *tmp = right;
4227 if (AOP_TYPE (right) == AOP_LIT)
4228 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4230 size = AOP_SIZE (result);
4232 if (AOP_TYPE (left) == AOP_CRY)
4238 if ((AOP_TYPE (right) == AOP_LIT) &&
4239 (AOP_TYPE (result) == AOP_CRY) &&
4240 (AOP_TYPE (left) != AOP_CRY))
4246 /* if left is same as result */
4247 if (sameRegs (AOP (result), AOP (left)))
4249 for (; size--; offset++)
4251 if (AOP_TYPE (right) == AOP_LIT)
4253 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4257 _moveA (aopGet (AOP (right), offset, FALSE));
4259 aopGet (AOP (left), offset, FALSE));
4260 aopPut (AOP (result), "a", offset);
4265 if (AOP_TYPE (left) == AOP_ACC)
4267 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4271 _moveA (aopGet (AOP (right), offset, FALSE));
4273 aopGet (AOP (left), offset, FALSE));
4274 aopPut (AOP (result), "a", 0);
4281 // left & result in different registers
4282 if (AOP_TYPE (result) == AOP_CRY)
4287 for (; (size--); offset++)
4290 // result = left & right
4291 if (AOP_TYPE (right) == AOP_LIT)
4293 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4295 aopPut (AOP (result),
4296 aopGet (AOP (left), offset, FALSE),
4301 // faster than result <- left, anl result,right
4302 // and better if result is SFR
4303 if (AOP_TYPE (left) == AOP_ACC)
4305 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4309 _moveA (aopGet (AOP (right), offset, FALSE));
4311 aopGet (AOP (left), offset, FALSE));
4313 aopPut (AOP (result), "a", offset);
4318 freeAsmop (left, NULL, ic);
4319 freeAsmop (right, NULL, ic);
4320 freeAsmop (result, NULL, ic);
4323 /*-----------------------------------------------------------------*/
4324 /* genInline - write the inline code out */
4325 /*-----------------------------------------------------------------*/
4327 genInline (iCode * ic)
4329 char *buffer, *bp, *bp1;
4331 _G.lines.isInline += (!options.asmpeep);
4333 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
4334 strcpy (buffer, IC_INLINE (ic));
4336 /* emit each line as a code */
4361 _G.lines.isInline -= (!options.asmpeep);
4365 /*-----------------------------------------------------------------*/
4366 /* genRRC - rotate right with carry */
4367 /*-----------------------------------------------------------------*/
4374 /*-----------------------------------------------------------------*/
4375 /* genRLC - generate code for rotate left with carry */
4376 /*-----------------------------------------------------------------*/
4383 /*-----------------------------------------------------------------*/
4384 /* genGetHbit - generates code get highest order bit */
4385 /*-----------------------------------------------------------------*/
4387 genGetHbit (iCode * ic)
4389 operand *left, *result;
4390 left = IC_LEFT (ic);
4391 result = IC_RESULT (ic);
4392 aopOp (left, ic, FALSE, FALSE);
4393 aopOp (result, ic, FALSE, FALSE);
4395 /* get the highest order byte into a */
4396 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4398 if (AOP_TYPE (result) == AOP_CRY)
4406 /* PENDING: For re-target. */
4412 freeAsmop (left, NULL, ic);
4413 freeAsmop (result, NULL, ic);
4417 emitRsh2 (asmop *aop, int size, int is_signed)
4423 const char *l = aopGet (aop, size, FALSE);
4426 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
4436 /*-----------------------------------------------------------------*/
4437 /* shiftR2Left2Result - shift right two bytes from left to result */
4438 /*-----------------------------------------------------------------*/
4440 shiftR2Left2Result (operand * left, int offl,
4441 operand * result, int offr,
4442 int shCount, int is_signed)
4445 symbol *tlbl, *tlbl1;
4447 movLeft2Result (left, offl, result, offr, 0);
4448 movLeft2Result (left, offl + 1, result, offr + 1, 0);
4450 /* if (AOP(result)->type == AOP_REG) { */
4452 tlbl = newiTempLabel (NULL);
4453 tlbl1 = newiTempLabel (NULL);
4455 /* Left is already in result - so now do the shift */
4460 emitRsh2 (AOP (result), size, is_signed);
4465 emit2 ("ld a,!immedbyte+1", shCount);
4466 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4467 emitLabel (tlbl->key + 100);
4469 emitRsh2 (AOP (result), size, is_signed);
4471 emitLabel (tlbl1->key + 100);
4473 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4477 /*-----------------------------------------------------------------*/
4478 /* shiftL2Left2Result - shift left two bytes from left to result */
4479 /*-----------------------------------------------------------------*/
4481 shiftL2Left2Result (operand * left, int offl,
4482 operand * result, int offr, int shCount)
4484 if (sameRegs (AOP (result), AOP (left)) &&
4485 ((offl + MSB16) == offr))
4491 /* Copy left into result */
4492 movLeft2Result (left, offl, result, offr, 0);
4493 movLeft2Result (left, offl + 1, result, offr + 1, 0);
4495 /* PENDING: for now just see if it'll work. */
4496 /*if (AOP(result)->type == AOP_REG) { */
4500 symbol *tlbl, *tlbl1;
4503 tlbl = newiTempLabel (NULL);
4504 tlbl1 = newiTempLabel (NULL);
4506 /* Left is already in result - so now do the shift */
4509 emit2 ("ld a,!immedbyte+1", shCount);
4510 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4511 emitLabel (tlbl->key + 100);
4517 l = aopGet (AOP (result), offset, FALSE);
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, MSB16, 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));
4701 emitDebug ("; shift left result %d, left %d", size,
4705 /* I suppose that the left size >= result size */
4711 else if (shCount >= (size * 8))
4715 aopPut (AOP (result), "!zero", size);
4723 genlshOne (result, left, shCount);
4726 genlshTwo (result, left, shCount);
4729 wassertl (0, "Shifting of longs is currently unsupported");
4735 freeAsmop (left, NULL, ic);
4736 freeAsmop (result, NULL, ic);
4739 /*-----------------------------------------------------------------*/
4740 /* genLeftShift - generates code for left shifting */
4741 /*-----------------------------------------------------------------*/
4743 genLeftShift (iCode * ic)
4747 symbol *tlbl, *tlbl1;
4748 operand *left, *right, *result;
4750 right = IC_RIGHT (ic);
4751 left = IC_LEFT (ic);
4752 result = IC_RESULT (ic);
4754 aopOp (right, ic, FALSE, FALSE);
4756 /* if the shift count is known then do it
4757 as efficiently as possible */
4758 if (AOP_TYPE (right) == AOP_LIT)
4760 genLeftShiftLiteral (left, right, result, ic);
4764 /* shift count is unknown then we have to form a loop get the loop
4765 count in B : Note: we take only the lower order byte since
4766 shifting more that 32 bits make no sense anyway, ( the largest
4767 size of an object can be only 32 bits ) */
4768 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
4770 freeAsmop (right, NULL, ic);
4771 aopOp (left, ic, FALSE, FALSE);
4772 aopOp (result, ic, FALSE, FALSE);
4774 /* now move the left to the result if they are not the
4777 if (!sameRegs (AOP (left), AOP (result)))
4780 size = AOP_SIZE (result);
4784 l = aopGet (AOP (left), offset, FALSE);
4785 aopPut (AOP (result), l, offset);
4790 size = AOP_SIZE (result);
4794 l = aopGet (AOP (left), offset, FALSE);
4795 aopPut (AOP (result), l, offset);
4801 tlbl = newiTempLabel (NULL);
4802 size = AOP_SIZE (result);
4804 tlbl1 = newiTempLabel (NULL);
4806 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4807 emitLabel (tlbl->key + 100);
4808 l = aopGet (AOP (result), offset, FALSE);
4814 l = aopGet (AOP (result), offset++, FALSE);
4817 emitLabel (tlbl1->key + 100);
4819 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4821 freeAsmop (left, NULL, ic);
4822 freeAsmop (result, NULL, ic);
4825 /*-----------------------------------------------------------------*/
4826 /* genrshOne - left shift two bytes by known amount != 0 */
4827 /*-----------------------------------------------------------------*/
4829 genrshOne (operand * result, operand * left, int shCount, int is_signed)
4832 int size = AOP_SIZE (result);
4835 wassert (size == 1);
4836 wassert (shCount < 8);
4838 l = aopGet (AOP (left), 0, FALSE);
4842 if (AOP (result)->type == AOP_REG)
4844 aopPut (AOP (result), l, 0);
4845 l = aopGet (AOP (result), 0, FALSE);
4848 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
4856 emit2 ("%s a", is_signed ? "sra" : "srl");
4858 aopPut (AOP (result), "a", 0);
4862 /*-----------------------------------------------------------------*/
4863 /* AccRsh - right shift accumulator by known count */
4864 /*-----------------------------------------------------------------*/
4866 AccRsh (int shCount)
4868 static const unsigned char SRMask[] =
4870 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
4875 /* rotate right accumulator */
4876 AccRol (8 - shCount);
4877 /* and kill the higher order bits */
4878 emit2 ("and a,!immedbyte", SRMask[shCount]);
4882 /*-----------------------------------------------------------------*/
4883 /* shiftR1Left2Result - shift right one byte from left to result */
4884 /*-----------------------------------------------------------------*/
4886 shiftR1Left2Result (operand * left, int offl,
4887 operand * result, int offr,
4888 int shCount, int sign)
4890 _moveA (aopGet (AOP (left), offl, FALSE));
4899 aopPut (AOP (result), "a", offr);
4902 /*-----------------------------------------------------------------*/
4903 /* genrshTwo - right shift two bytes by known amount != 0 */
4904 /*-----------------------------------------------------------------*/
4906 genrshTwo (operand * result, operand * left,
4907 int shCount, int sign)
4909 /* if shCount >= 8 */
4915 shiftR1Left2Result (left, MSB16, result, LSB,
4920 movLeft2Result (left, MSB16, result, LSB, sign);
4922 aopPut (AOP (result), "!zero", 1);
4924 /* 1 <= shCount <= 7 */
4927 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
4931 /*-----------------------------------------------------------------*/
4932 /* genRightShiftLiteral - left shifting by known count */
4933 /*-----------------------------------------------------------------*/
4935 genRightShiftLiteral (operand * left,
4941 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
4944 freeAsmop (right, NULL, ic);
4946 aopOp (left, ic, FALSE, FALSE);
4947 aopOp (result, ic, FALSE, FALSE);
4949 size = getSize (operandType (result));
4951 emitDebug ("; shift right result %d, left %d", size,
4954 /* I suppose that the left size >= result size */
4960 else if (shCount >= (size * 8))
4962 aopPut (AOP (result), "!zero", size);
4968 genrshOne (result, left, shCount, sign);
4971 /* PENDING: sign support */
4972 genrshTwo (result, left, shCount, sign);
4975 wassertl (0, "Asked to shift right a long which should be a function call");
4978 wassertl (0, "Entered default case in right shift delegate");
4981 freeAsmop (left, NULL, ic);
4982 freeAsmop (result, NULL, ic);
4985 /*-----------------------------------------------------------------*/
4986 /* genRightShift - generate code for right shifting */
4987 /*-----------------------------------------------------------------*/
4989 genRightShift (iCode * ic)
4991 operand *right, *left, *result;
4993 int size, offset, first = 1;
4997 symbol *tlbl, *tlbl1;
4999 /* if signed then we do it the hard way preserve the
5000 sign bit moving it inwards */
5001 retype = getSpec (operandType (IC_RESULT (ic)));
5003 is_signed = !SPEC_USIGN (retype);
5005 /* signed & unsigned types are treated the same : i.e. the
5006 signed is NOT propagated inwards : quoting from the
5007 ANSI - standard : "for E1 >> E2, is equivalent to division
5008 by 2**E2 if unsigned or if it has a non-negative value,
5009 otherwise the result is implementation defined ", MY definition
5010 is that the sign does not get propagated */
5012 right = IC_RIGHT (ic);
5013 left = IC_LEFT (ic);
5014 result = IC_RESULT (ic);
5016 aopOp (right, ic, FALSE, FALSE);
5018 /* if the shift count is known then do it
5019 as efficiently as possible */
5020 if (AOP_TYPE (right) == AOP_LIT)
5022 genRightShiftLiteral (left, right, result, ic, is_signed);
5026 aopOp (left, ic, FALSE, FALSE);
5027 aopOp (result, ic, FALSE, FALSE);
5029 /* now move the left to the result if they are not the
5031 if (!sameRegs (AOP (left), AOP (result)) &&
5032 AOP_SIZE (result) > 1)
5035 size = AOP_SIZE (result);
5039 l = aopGet (AOP (left), offset, FALSE);
5040 aopPut (AOP (result), l, offset);
5045 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5047 freeAsmop (right, NULL, ic);
5049 tlbl = newiTempLabel (NULL);
5050 tlbl1 = newiTempLabel (NULL);
5051 size = AOP_SIZE (result);
5054 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5055 emitLabel (tlbl->key + 100);
5058 l = aopGet (AOP (result), offset--, FALSE);
5061 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5069 emitLabel (tlbl1->key + 100);
5071 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5073 freeAsmop (left, NULL, ic);
5074 freeAsmop (result, NULL, ic);
5077 /*-----------------------------------------------------------------*/
5078 /* genGenPointerGet - get value from generic pointer space */
5079 /*-----------------------------------------------------------------*/
5081 genGenPointerGet (operand * left,
5082 operand * result, iCode * ic)
5085 sym_link *retype = getSpec (operandType (result));
5091 aopOp (left, ic, FALSE, FALSE);
5092 aopOp (result, ic, FALSE, FALSE);
5094 if (isPair (AOP (left)) && AOP_SIZE (result) == 1)
5097 if (isPtrPair (AOP (left)))
5099 tsprintf (buffer, "!*pair", getPairName (AOP (left)));
5100 aopPut (AOP (result), buffer, 0);
5104 emit2 ("ld a,!*pair", getPairName (AOP (left)));
5105 aopPut (AOP (result), "a", 0);
5107 freeAsmop (left, NULL, ic);
5111 /* For now we always load into IY */
5112 /* if this is remateriazable */
5113 fetchPair (pair, AOP (left));
5115 /* so iy now contains the address */
5116 freeAsmop (left, NULL, ic);
5118 /* if bit then unpack */
5119 if (IS_BITVAR (retype))
5125 size = AOP_SIZE (result);
5130 /* PENDING: make this better */
5131 if (!IS_GB && AOP (result)->type == AOP_REG)
5133 aopPut (AOP (result), "!*hl", offset++);
5137 emit2 ("ld a,!*pair", _pairs[pair].name);
5138 aopPut (AOP (result), "a", offset++);
5142 emit2 ("inc %s", _pairs[pair].name);
5143 _G.pairs[pair].offset++;
5149 freeAsmop (result, NULL, ic);
5152 /*-----------------------------------------------------------------*/
5153 /* genPointerGet - generate code for pointer get */
5154 /*-----------------------------------------------------------------*/
5156 genPointerGet (iCode * ic)
5158 operand *left, *result;
5159 sym_link *type, *etype;
5161 left = IC_LEFT (ic);
5162 result = IC_RESULT (ic);
5164 /* depending on the type of pointer we need to
5165 move it to the correct pointer register */
5166 type = operandType (left);
5167 etype = getSpec (type);
5169 genGenPointerGet (left, result, ic);
5173 isRegOrLit (asmop * aop)
5175 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
5180 /*-----------------------------------------------------------------*/
5181 /* genGenPointerSet - stores the value into a pointer location */
5182 /*-----------------------------------------------------------------*/
5184 genGenPointerSet (operand * right,
5185 operand * result, iCode * ic)
5188 sym_link *retype = getSpec (operandType (right));
5189 PAIR_ID pairId = PAIR_HL;
5191 aopOp (result, ic, FALSE, FALSE);
5192 aopOp (right, ic, FALSE, FALSE);
5197 /* Handle the exceptions first */
5198 if (isPair (AOP (result)) && (AOP_SIZE (right) == 1))
5201 const char *l = aopGet (AOP (right), 0, FALSE);
5202 const char *pair = getPairName (AOP (result));
5203 if (canAssignToPtr (l) && isPtr (pair))
5205 emit2 ("ld !*pair,%s", pair, l);
5210 emit2 ("ld !*pair,a", pair);
5215 /* if the operand is already in dptr
5216 then we do nothing else we move the value to dptr */
5217 if (AOP_TYPE (result) != AOP_STR)
5219 fetchPair (pairId, AOP (result));
5221 /* so hl know contains the address */
5222 freeAsmop (result, NULL, ic);
5224 /* if bit then unpack */
5225 if (IS_BITVAR (retype))
5231 size = AOP_SIZE (right);
5236 const char *l = aopGet (AOP (right), offset, FALSE);
5237 if (isRegOrLit (AOP (right)) && !IS_GB)
5239 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
5244 emit2 ("ld !*pair,a", _pairs[pairId].name);
5248 emit2 ("inc %s", _pairs[pairId].name);
5249 _G.pairs[pairId].offset++;
5255 freeAsmop (right, NULL, ic);
5258 /*-----------------------------------------------------------------*/
5259 /* genPointerSet - stores the value into a pointer location */
5260 /*-----------------------------------------------------------------*/
5262 genPointerSet (iCode * ic)
5264 operand *right, *result;
5265 sym_link *type, *etype;
5267 right = IC_RIGHT (ic);
5268 result = IC_RESULT (ic);
5270 /* depending on the type of pointer we need to
5271 move it to the correct pointer register */
5272 type = operandType (result);
5273 etype = getSpec (type);
5275 genGenPointerSet (right, result, ic);
5278 /*-----------------------------------------------------------------*/
5279 /* genIfx - generate code for Ifx statement */
5280 /*-----------------------------------------------------------------*/
5282 genIfx (iCode * ic, iCode * popIc)
5284 operand *cond = IC_COND (ic);
5287 aopOp (cond, ic, FALSE, TRUE);
5289 /* get the value into acc */
5290 if (AOP_TYPE (cond) != AOP_CRY)
5294 /* the result is now in the accumulator */
5295 freeAsmop (cond, NULL, ic);
5297 /* if there was something to be popped then do it */
5301 /* if the condition is a bit variable */
5302 if (isbit && IS_ITEMP (cond) &&
5304 genIfxJump (ic, SPIL_LOC (cond)->rname);
5305 else if (isbit && !IS_ITEMP (cond))
5306 genIfxJump (ic, OP_SYMBOL (cond)->rname);
5308 genIfxJump (ic, "a");
5313 /*-----------------------------------------------------------------*/
5314 /* genAddrOf - generates code for address of */
5315 /*-----------------------------------------------------------------*/
5317 genAddrOf (iCode * ic)
5319 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
5321 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
5323 /* if the operand is on the stack then we
5324 need to get the stack offset of this
5331 if (sym->stack <= 0)
5333 emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset);
5337 emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
5344 emit2 ("ld de,!hashedstr", sym->rname);
5346 aopPut (AOP (IC_RESULT (ic)), "e", 0);
5347 aopPut (AOP (IC_RESULT (ic)), "d", 1);
5354 /* if it has an offset then we need to compute it */
5356 emit2 ("ld hl,#%d+%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset, _G.stack.param_offset);
5358 emit2 ("ld hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
5359 emit2 ("add hl,sp");
5363 emit2 ("ld hl,#%s", sym->rname);
5365 aopPut (AOP (IC_RESULT (ic)), "l", 0);
5366 aopPut (AOP (IC_RESULT (ic)), "h", 1);
5368 freeAsmop (IC_RESULT (ic), NULL, ic);
5371 /*-----------------------------------------------------------------*/
5372 /* genAssign - generate code for assignment */
5373 /*-----------------------------------------------------------------*/
5375 genAssign (iCode * ic)
5377 operand *result, *right;
5379 unsigned long lit = 0L;
5381 result = IC_RESULT (ic);
5382 right = IC_RIGHT (ic);
5385 /* Dont bother assigning if they are the same */
5386 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5388 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
5393 aopOp (right, ic, FALSE, FALSE);
5394 aopOp (result, ic, TRUE, FALSE);
5396 /* if they are the same registers */
5397 if (sameRegs (AOP (right), AOP (result)))
5399 emitDebug ("; (registers are the same)");
5403 /* if the result is a bit */
5404 if (AOP_TYPE (result) == AOP_CRY)
5410 size = AOP_SIZE (result);
5413 if (AOP_TYPE (right) == AOP_LIT)
5414 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5415 if (isPair (AOP (result)))
5417 fetchPair (getPairId (AOP (result)), AOP (right));
5419 else if ((size > 1) &&
5420 (AOP_TYPE (result) != AOP_REG) &&
5421 (AOP_TYPE (right) == AOP_LIT) &&
5422 !IS_FLOAT (operandType (right)) &&
5425 bool fXored = FALSE;
5427 /* Work from the top down.
5428 Done this way so that we can use the cached copy of 0
5429 in A for a fast clear */
5432 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
5434 if (!fXored && size > 1)
5441 aopPut (AOP (result), "a", offset);
5445 aopPut (AOP (result), "!zero", offset);
5449 aopPut (AOP (result),
5450 aopGet (AOP (right), offset, FALSE),
5455 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
5457 /* Special case. Load into a and d, then load out. */
5458 _moveA (aopGet (AOP (right), 0, FALSE));
5459 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
5460 aopPut (AOP (result), "a", 0);
5461 aopPut (AOP (result), "e", 1);
5467 /* PENDING: do this check better */
5468 if (requiresHL (AOP (right)) && requiresHL (AOP (result)))
5470 _moveA (aopGet (AOP (right), offset, FALSE));
5471 aopPut (AOP (result), "a", offset);
5474 aopPut (AOP (result),
5475 aopGet (AOP (right), offset, FALSE),
5482 freeAsmop (right, NULL, ic);
5483 freeAsmop (result, NULL, ic);
5486 /*-----------------------------------------------------------------*/
5487 /* genJumpTab - genrates code for jump table */
5488 /*-----------------------------------------------------------------*/
5490 genJumpTab (iCode * ic)
5495 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
5496 /* get the condition into accumulator */
5497 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
5500 emit2 ("ld e,%s", l);
5501 emit2 ("ld d,!zero");
5502 jtab = newiTempLabel (NULL);
5504 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
5505 emit2 ("add hl,de");
5506 emit2 ("add hl,de");
5507 emit2 ("add hl,de");
5508 freeAsmop (IC_JTCOND (ic), NULL, ic);
5512 emitLabel (jtab->key + 100);
5513 /* now generate the jump labels */
5514 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
5515 jtab = setNextItem (IC_JTLABELS (ic)))
5516 emit2 ("jp !tlabel", jtab->key + 100);
5519 /*-----------------------------------------------------------------*/
5520 /* genCast - gen code for casting */
5521 /*-----------------------------------------------------------------*/
5523 genCast (iCode * ic)
5525 operand *result = IC_RESULT (ic);
5526 sym_link *ctype = operandType (IC_LEFT (ic));
5527 operand *right = IC_RIGHT (ic);
5530 /* if they are equivalent then do nothing */
5531 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5534 aopOp (right, ic, FALSE, FALSE);
5535 aopOp (result, ic, FALSE, FALSE);
5537 /* if the result is a bit */
5538 if (AOP_TYPE (result) == AOP_CRY)
5543 /* if they are the same size : or less */
5544 if (AOP_SIZE (result) <= AOP_SIZE (right))
5547 /* if they are in the same place */
5548 if (sameRegs (AOP (right), AOP (result)))
5551 /* if they in different places then copy */
5552 size = AOP_SIZE (result);
5556 aopPut (AOP (result),
5557 aopGet (AOP (right), offset, FALSE),
5564 /* PENDING: should be OK. */
5566 /* if the result is of type pointer */
5573 /* so we now know that the size of destination is greater
5574 than the size of the source */
5575 /* we move to result for the size of source */
5576 size = AOP_SIZE (right);
5580 aopPut (AOP (result),
5581 aopGet (AOP (right), offset, FALSE),
5586 /* now depending on the sign of the destination */
5587 size = AOP_SIZE (result) - AOP_SIZE (right);
5588 /* Unsigned or not an integral type - right fill with zeros */
5589 if (SPEC_USIGN (ctype) || !IS_SPEC (ctype))
5592 aopPut (AOP (result), "!zero", offset++);
5596 /* we need to extend the sign :{ */
5597 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
5600 emitDebug ("; genCast: sign extend untested.");
5604 aopPut (AOP (result), "a", offset++);
5608 freeAsmop (right, NULL, ic);
5609 freeAsmop (result, NULL, ic);
5612 /*-----------------------------------------------------------------*/
5613 /* genReceive - generate code for a receive iCode */
5614 /*-----------------------------------------------------------------*/
5616 genReceive (iCode * ic)
5618 if (isOperandInFarSpace (IC_RESULT (ic)) &&
5619 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
5620 IS_TRUE_SYMOP (IC_RESULT (ic))))
5630 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
5631 size = AOP_SIZE(IC_RESULT(ic));
5633 for (i = 0; i < size; i++) {
5634 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
5638 freeAsmop (IC_RESULT (ic), NULL, ic);
5643 /** Maximum number of bytes to emit per line. */
5647 /** Context for the byte output chunker. */
5650 unsigned char buffer[DBEMIT_MAX_RUN];
5655 /** Flushes a byte chunker by writing out all in the buffer and
5659 _dbFlush(DBEMITCTX *self)
5666 sprintf(line, ".db 0x%02X", self->buffer[0]);
5668 for (i = 1; i < self->pos; i++)
5670 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
5677 /** Write out another byte, buffering until a decent line is
5681 _dbEmit(DBEMITCTX *self, int c)
5683 if (self->pos == DBEMIT_MAX_RUN)
5687 self->buffer[self->pos++] = c;
5690 /** Context for a simple run length encoder. */
5694 unsigned char buffer[128];
5696 /** runLen may be equivalent to pos. */
5702 RLE_CHANGE_COST = 4,
5706 /** Flush the buffer of a run length encoder by writing out the run or
5707 data that it currently contains.
5710 _rleCommit(RLECTX *self)
5716 memset(&db, 0, sizeof(db));
5718 emit2(".db %u", self->pos);
5720 for (i = 0; i < self->pos; i++)
5722 _dbEmit(&db, self->buffer[i]);
5731 Can get either a run or a block of random stuff.
5732 Only want to change state if a good run comes in or a run ends.
5733 Detecting run end is easy.
5736 Say initial state is in run, len zero, last zero. Then if you get a
5737 few zeros then something else then a short run will be output.
5738 Seems OK. While in run mode, keep counting. While in random mode,
5739 keep a count of the run. If run hits margin, output all up to run,
5740 restart, enter run mode.
5743 /** Add another byte into the run length encoder, flushing as
5744 required. The run length encoder uses the Amiga IFF style, where
5745 a block is prefixed by its run length. A positive length means
5746 the next n bytes pass straight through. A negative length means
5747 that the next byte is repeated -n times. A zero terminates the
5751 _rleAppend(RLECTX *self, int c)
5755 if (c != self->last)
5757 /* The run has stopped. See if it is worthwhile writing it out
5758 as a run. Note that the random data comes in as runs of
5761 if (self->runLen > RLE_CHANGE_COST)
5763 /* Yes, worthwhile. */
5764 /* Commit whatever was in the buffer. */
5766 emit2(".db -%u,0x%02X", self->runLen, self->last);
5770 /* Not worthwhile. Append to the end of the random list. */
5771 for (i = 0; i < self->runLen; i++)
5773 if (self->pos >= RLE_MAX_BLOCK)
5778 self->buffer[self->pos++] = self->last;
5786 if (self->runLen >= RLE_MAX_BLOCK)
5788 /* Commit whatever was in the buffer. */
5791 emit2 (".db -%u,0x%02X", self->runLen, self->last);
5799 _rleFlush(RLECTX *self)
5801 _rleAppend(self, -1);
5808 /** genArrayInit - Special code for initialising an array with constant
5812 genArrayInit (iCode * ic)
5816 int elementSize = 0, eIndex, i;
5817 unsigned val, lastVal;
5821 memset(&rle, 0, sizeof(rle));
5823 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
5825 if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD)
5827 /* Emit the support function call and the destination address. */
5828 emit2("call __initrleblock");
5829 emit2(".dw %s", aopGetWord (AOP(IC_LEFT(ic)), 0));
5833 wassertl (0, "Unexpected operand to genArrayInit.\n");
5836 type = operandType(IC_LEFT(ic));
5838 if (type && type->next)
5840 elementSize = getSize(type->next);
5844 wassertl (0, "Can't determine element size in genArrayInit.");
5847 iLoop = IC_ARRAYILIST(ic);
5848 lastVal = (unsigned)-1;
5850 /* Feed all the bytes into the run length encoder which will handle
5852 This works well for mixed char data, and for random int and long
5861 for (i = 0; i < ix; i++)
5863 for (eIndex = 0; eIndex < elementSize; eIndex++)
5865 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
5866 _rleAppend(&rle, val);
5871 iLoop = iLoop->next;
5875 /* Mark the end of the run. */
5878 freeAsmop (IC_LEFT(ic), NULL, ic);
5881 /*-----------------------------------------------------------------*/
5882 /* genZ80Code - generate code for Z80 based controllers */
5883 /*-----------------------------------------------------------------*/
5885 genZ80Code (iCode * lic)
5893 _fReturn = _gbz80_return;
5894 _fTmp = _gbz80_return;
5898 _fReturn = _z80_return;
5899 _fTmp = _z80_return;
5902 _G.lines.head = _G.lines.current = NULL;
5904 for (ic = lic; ic; ic = ic->next)
5907 if (cln != ic->lineno)
5909 emit2 ("; %s %d", ic->filename, ic->lineno);
5912 /* if the result is marked as
5913 spilt and rematerializable or code for
5914 this has already been generated then
5916 if (resultRemat (ic) || ic->generated)
5919 /* depending on the operation */
5923 emitDebug ("; genNot");
5928 emitDebug ("; genCpl");
5933 emitDebug ("; genUminus");
5938 emitDebug ("; genIpush");
5943 /* IPOP happens only when trying to restore a
5944 spilt live range, if there is an ifx statement
5945 following this pop then the if statement might
5946 be using some of the registers being popped which
5947 would destory the contents of the register so
5948 we need to check for this condition and handle it */
5950 ic->next->op == IFX &&
5951 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
5953 emitDebug ("; genIfx");
5954 genIfx (ic->next, ic);
5958 emitDebug ("; genIpop");
5964 emitDebug ("; genCall");
5969 emitDebug ("; genPcall");
5974 emitDebug ("; genFunction");
5979 emitDebug ("; genEndFunction");
5980 genEndFunction (ic);
5984 emitDebug ("; genRet");
5989 emitDebug ("; genLabel");
5994 emitDebug ("; genGoto");
5999 emitDebug ("; genPlus");
6004 emitDebug ("; genMinus");
6009 emitDebug ("; genMult");
6014 emitDebug ("; genDiv");
6019 emitDebug ("; genMod");
6024 emitDebug ("; genCmpGt");
6025 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
6029 emitDebug ("; genCmpLt");
6030 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
6037 /* note these two are xlated by algebraic equivalence
6038 during parsing SDCC.y */
6039 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
6040 "got '>=' or '<=' shouldn't have come here");
6044 emitDebug ("; genCmpEq");
6045 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
6049 emitDebug ("; genAndOp");
6054 emitDebug ("; genOrOp");
6059 emitDebug ("; genXor");
6060 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
6064 emitDebug ("; genOr");
6065 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
6069 emitDebug ("; genAnd");
6070 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
6074 emitDebug ("; genInline");
6079 emitDebug ("; genRRC");
6084 emitDebug ("; genRLC");
6089 emitDebug ("; genGetHBIT");
6094 emitDebug ("; genLeftShift");
6099 emitDebug ("; genRightShift");
6103 case GET_VALUE_AT_ADDRESS:
6104 emitDebug ("; genPointerGet");
6110 if (POINTER_SET (ic))
6112 emitDebug ("; genAssign (pointer)");
6117 emitDebug ("; genAssign");
6123 emitDebug ("; genIfx");
6128 emitDebug ("; genAddrOf");
6133 emitDebug ("; genJumpTab");
6138 emitDebug ("; genCast");
6143 emitDebug ("; genReceive");
6148 emitDebug ("; addSet");
6149 addSet (&_G.sendSet, ic);
6158 /* piCode(ic,stdout); */
6164 /* now we are ready to call the
6165 peep hole optimizer */
6166 if (!options.nopeep)
6167 peepHole (&_G.lines.head);
6169 /* This is unfortunate */
6170 /* now do the actual printing */
6172 FILE *fp = codeOutFile;
6173 if (isInHome () && codeOutFile == code->oFile)
6174 codeOutFile = home->oFile;
6175 printLine (_G.lines.head, codeOutFile);
6176 if (_G.flushStatics)
6179 _G.flushStatics = 0;
6188 _isPairUsed (iCode * ic, PAIR_ID pairId)
6194 if (bitVectBitValue (ic->rMask, D_IDX))
6196 if (bitVectBitValue (ic->rMask, E_IDX))