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 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1025 const char *pair = _pairs[pairId].name;
1026 l = aopGetLitWordLong (left, offset, FALSE);
1027 wassert (l && pair);
1031 if (pairId == PAIR_HL || pairId == PAIR_IY)
1033 if (_G.pairs[pairId].last_type == left->type)
1035 if (_G.pairs[pairId].lit && !strcmp (_G.pairs[pairId].lit, l))
1037 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1039 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1042 if (pairId == PAIR_IY && abs (offset) < 127)
1049 _G.pairs[pairId].last_type = left->type;
1050 _G.pairs[pairId].lit = gc_strdup (l);
1051 _G.pairs[pairId].offset = offset;
1053 if (IS_GB && pairId == PAIR_DE && 0)
1055 if (_G.pairs[pairId].lit && !strcmp (_G.pairs[pairId].lit, l))
1057 if (abs (_G.pairs[pairId].offset - offset) < 3)
1059 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1063 _G.pairs[pairId].last_type = left->type;
1064 _G.pairs[pairId].lit = gc_strdup (l);
1065 _G.pairs[pairId].offset = offset;
1067 /* Both a lit on the right and a true symbol on the left */
1068 emit2 ("ld %s,!hashedstr", pair, l);
1072 fetchPairLong (PAIR_ID pairId, asmop * aop, int offset)
1074 /* if this is remateriazable */
1075 if (isLitWord (aop)) {
1076 fetchLitPair (pairId, aop, offset);
1079 /* we need to get it byte by byte */
1080 if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1081 aopGet (aop, offset, FALSE);
1082 switch (aop->size - offset) {
1084 emit2 ("ld l,!*hl");
1085 emit2 ("ld h,!immedbyte", 0);
1088 // PENDING: Requires that you are only fetching two bytes.
1091 emit2 ("ld h,!*hl");
1095 wassertl (0, "Attempted to fetch too much data into HL");
1099 else if (IS_Z80 && aop->type == AOP_IY) {
1100 /* Instead of fetching relative to IY, just grab directly
1101 from the address IY refers to */
1102 char *l = aopGetLitWordLong (aop, offset, FALSE);
1104 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1106 if (aop->size < 2) {
1107 emit2("ld %s,!zero", _pairs[pairId].h);
1111 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1112 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1114 /* PENDING: check? */
1115 if (pairId == PAIR_HL)
1116 spillPair (PAIR_HL);
1121 fetchPair (PAIR_ID pairId, asmop * aop)
1123 fetchPairLong (pairId, aop, 0);
1127 fetchHL (asmop * aop)
1129 fetchPair (PAIR_HL, aop);
1133 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1135 assert (pairId == PAIR_HL || pairId == PAIR_IY);
1140 fetchLitPair (pairId, aop, 0);
1143 fetchLitPair (pairId, aop, offset);
1144 _G.pairs[pairId].offset = offset;
1148 /* Doesnt include _G.stack.pushed */
1149 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1150 if (aop->aopu.aop_stk > 0)
1152 abso += _G.stack.param_offset;
1154 assert (pairId == PAIR_HL);
1155 /* In some cases we can still inc or dec hl */
1156 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1158 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1162 emit2 ("!ldahlsp", abso + _G.stack.pushed);
1164 _G.pairs[pairId].offset = abso;
1170 _G.pairs[pairId].last_type = aop->type;
1176 emit2 ("!tlabeldef", key);
1180 /*-----------------------------------------------------------------*/
1181 /* aopGet - for fetching value of the aop */
1182 /*-----------------------------------------------------------------*/
1184 aopGet (asmop * aop, int offset, bool bit16)
1188 /* offset is greater than size then zero */
1189 /* PENDING: this seems a bit screwed in some pointer cases. */
1190 if (offset > (aop->size - 1) &&
1191 aop->type != AOP_LIT)
1193 tsprintf (s, "!zero");
1194 return gc_strdup(s);
1197 /* depending on type */
1201 /* PENDING: re-target */
1203 tsprintf (s, "!immedwords", aop->aopu.aop_immd);
1208 tsprintf (s, "!bankimmeds", aop->aopu.aop_immd);
1211 tsprintf (s, "!msbimmeds", aop->aopu.aop_immd);
1214 tsprintf (s, "!lsbimmeds", aop->aopu.aop_immd);
1220 return gc_strdup(s);
1224 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1227 return gc_strdup(s);
1231 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1234 return gc_strdup(s);
1237 return aop->aopu.aop_reg[offset]->name;
1241 setupPair (PAIR_HL, aop, offset);
1242 tsprintf (s, "!*hl");
1244 return gc_strdup (s);
1248 setupPair (PAIR_IY, aop, offset);
1249 tsprintf (s, "!*iyx", offset);
1251 return gc_strdup(s);
1256 setupPair (PAIR_HL, aop, offset);
1257 tsprintf (s, "!*hl");
1261 if (aop->aopu.aop_stk >= 0)
1262 offset += _G.stack.param_offset;
1263 tsprintf (s, "!*ixx", aop->aopu.aop_stk + offset);
1266 return gc_strdup(s);
1278 tsprintf(s, "!zero");
1279 return gc_strdup(s);
1283 wassert (offset < 2);
1284 return aop->aopu.aop_str[offset];
1287 return aopLiteral (aop->aopu.aop_lit, offset);
1291 return aop->aopu.aop_str[offset];
1296 wassertl (0, "aopget got unsupported aop->type");
1301 isRegString (const char *s)
1303 if (!strcmp (s, "b") ||
1315 isConstant (const char *s)
1317 /* This is a bit of a hack... */
1318 return (*s == '#' || *s == '$');
1322 canAssignToPtr (const char *s)
1324 if (isRegString (s))
1331 /*-----------------------------------------------------------------*/
1332 /* aopPut - puts a string for a aop */
1333 /*-----------------------------------------------------------------*/
1335 aopPut (asmop * aop, const char *s, int offset)
1339 if (aop->size && offset > (aop->size - 1))
1341 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1342 "aopPut got offset > aop->size");
1347 tsprintf(buffer2, s);
1350 /* will assign value to value */
1351 /* depending on where it is ofcourse */
1357 if (strcmp (s, "a"))
1358 emit2 ("ld a,%s", s);
1359 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1364 if (strcmp (s, "a"))
1365 emit2 ("ld a,%s", s);
1366 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1370 if (!strcmp (s, "!*hl"))
1371 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1374 aop->aopu.aop_reg[offset]->name, s);
1379 setupPair (PAIR_IY, aop, offset);
1380 if (!canAssignToPtr (s))
1382 emit2 ("ld a,%s", s);
1383 emit2 ("ld !*iyx,a", offset);
1386 emit2 ("ld !*iyx,%s", offset, s);
1391 /* PENDING: for re-target */
1392 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1394 emit2 ("ld a,!*hl");
1397 setupPair (PAIR_HL, aop, offset);
1399 emit2 ("ld !*hl,%s", s);
1405 /* PENDING: re-target */
1406 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1408 emit2 ("ld a,!*hl");
1411 setupPair (PAIR_HL, aop, offset);
1412 if (!canAssignToPtr (s))
1414 emit2 ("ld a,%s", s);
1415 emit2 ("ld !*hl,a");
1418 emit2 ("ld !*hl,%s", s);
1422 if (aop->aopu.aop_stk >= 0)
1423 offset += _G.stack.param_offset;
1424 if (!canAssignToPtr (s))
1426 emit2 ("ld a,%s", s);
1427 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
1430 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
1435 /* if bit variable */
1436 if (!aop->aopu.aop_dir)
1443 /* In bit space but not in C - cant happen */
1450 if (strcmp (aop->aopu.aop_str[offset], s))
1452 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1458 if (!offset && (strcmp (s, "acc") == 0))
1463 emitDebug ("; Error aopPut AOP_ACC");
1467 if (strcmp (aop->aopu.aop_str[offset], s))
1468 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1473 wassert (offset < 2);
1474 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1478 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1479 "aopPut got unsupported aop->type");
1484 #define AOP(op) op->aop
1485 #define AOP_TYPE(op) AOP(op)->type
1486 #define AOP_SIZE(op) AOP(op)->size
1487 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
1490 commitPair (asmop * aop, PAIR_ID id)
1492 if (id == PAIR_HL && requiresHL (aop))
1496 aopPut (aop, "a", 0);
1497 aopPut (aop, "d", 1);
1501 aopPut (aop, _pairs[id].l, 0);
1502 aopPut (aop, _pairs[id].h, 1);
1506 /*-----------------------------------------------------------------*/
1507 /* getDataSize - get the operand data size */
1508 /*-----------------------------------------------------------------*/
1510 getDataSize (operand * op)
1513 size = AOP_SIZE (op);
1522 /*-----------------------------------------------------------------*/
1523 /* movLeft2Result - move byte from left to result */
1524 /*-----------------------------------------------------------------*/
1526 movLeft2Result (operand * left, int offl,
1527 operand * result, int offr, int sign)
1530 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
1532 l = aopGet (AOP (left), offl, FALSE);
1536 aopPut (AOP (result), l, offr);
1546 /** Put Acc into a register set
1549 outAcc (operand * result)
1552 size = getDataSize (result);
1555 aopPut (AOP (result), "a", 0);
1558 /* unsigned or positive */
1561 aopPut (AOP (result), "!zero", offset++);
1566 /** Take the value in carry and put it into a register
1569 outBitCLong (operand * result, bool swap_sense)
1571 /* if the result is bit */
1572 if (AOP_TYPE (result) == AOP_CRY)
1574 emitDebug ("; Note: outBitC form 1");
1575 aopPut (AOP (result), "blah", 0);
1579 emit2 ("ld a,!zero");
1582 emit2 ("xor a,!immedbyte", 1);
1588 outBitC (operand * result)
1590 outBitCLong (result, FALSE);
1593 /*-----------------------------------------------------------------*/
1594 /* toBoolean - emit code for orl a,operator(sizeop) */
1595 /*-----------------------------------------------------------------*/
1597 _toBoolean (operand * oper)
1599 int size = AOP_SIZE (oper);
1603 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
1606 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
1610 if (AOP (oper)->type != AOP_ACC)
1613 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
1618 /*-----------------------------------------------------------------*/
1619 /* genNot - generate code for ! operation */
1620 /*-----------------------------------------------------------------*/
1624 sym_link *optype = operandType (IC_LEFT (ic));
1626 /* assign asmOps to operand & result */
1627 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
1628 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1630 /* if in bit space then a special case */
1631 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1636 /* if type float then do float */
1637 if (IS_FLOAT (optype))
1642 _toBoolean (IC_LEFT (ic));
1647 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
1648 emit2 ("sub a,!one");
1649 outBitC (IC_RESULT (ic));
1651 /* release the aops */
1652 freeAsmop (IC_LEFT (ic), NULL, ic);
1653 freeAsmop (IC_RESULT (ic), NULL, ic);
1656 /*-----------------------------------------------------------------*/
1657 /* genCpl - generate code for complement */
1658 /*-----------------------------------------------------------------*/
1666 /* assign asmOps to operand & result */
1667 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1668 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1670 /* if both are in bit space then
1672 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1673 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1678 size = AOP_SIZE (IC_RESULT (ic));
1681 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
1684 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1687 /* release the aops */
1688 freeAsmop (IC_LEFT (ic), NULL, ic);
1689 freeAsmop (IC_RESULT (ic), NULL, ic);
1692 /*-----------------------------------------------------------------*/
1693 /* genUminus - unary minus code generation */
1694 /*-----------------------------------------------------------------*/
1696 genUminus (iCode * ic)
1699 sym_link *optype, *rtype;
1702 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1703 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1705 /* if both in bit space then special
1707 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1708 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1714 optype = operandType (IC_LEFT (ic));
1715 rtype = operandType (IC_RESULT (ic));
1717 /* if float then do float stuff */
1718 if (IS_FLOAT (optype))
1724 /* otherwise subtract from zero */
1725 size = AOP_SIZE (IC_LEFT (ic));
1730 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
1731 emit2 ("ld a,!zero");
1732 emit2 ("sbc a,%s", l);
1733 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1736 /* if any remaining bytes in the result */
1737 /* we just need to propagate the sign */
1738 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
1743 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1747 /* release the aops */
1748 freeAsmop (IC_LEFT (ic), NULL, ic);
1749 freeAsmop (IC_RESULT (ic), NULL, ic);
1753 _push (PAIR_ID pairId)
1755 emit2 ("push %s", _pairs[pairId].name);
1756 _G.stack.pushed += 2;
1760 _pop (PAIR_ID pairId)
1762 emit2 ("pop %s", _pairs[pairId].name);
1763 _G.stack.pushed -= 2;
1767 /*-----------------------------------------------------------------*/
1768 /* assignResultValue - */
1769 /*-----------------------------------------------------------------*/
1771 assignResultValue (operand * oper)
1773 int size = AOP_SIZE (oper);
1776 wassert (size <= 4);
1777 topInA = requiresHL (AOP (oper));
1781 wassert (size <= 2);
1783 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
1785 /* We do it the hard way here. */
1787 aopPut (AOP (oper), _fReturn[0], 0);
1788 aopPut (AOP (oper), _fReturn[1], 1);
1790 aopPut (AOP (oper), _fReturn[0], 2);
1791 aopPut (AOP (oper), _fReturn[1], 3);
1797 aopPut (AOP (oper), _fReturn[size], size);
1803 _saveRegsForCall(iCode *ic, int sendSetSize)
1806 o Stack parameters are pushed before this function enters
1807 o DE and BC may be used in this function.
1808 o HL and DE may be used to return the result.
1809 o HL and DE may be used to send variables.
1810 o DE and BC may be used to store the result value.
1811 o HL may be used in computing the sent value of DE
1812 o The iPushes for other parameters occur before any addSets
1814 Logic: (to be run inside the first iPush or if none, before sending)
1815 o Compute if DE and/or BC are in use over the call
1816 o Compute if DE is used in the send set
1817 o Compute if DE and/or BC are used to hold the result value
1818 o If (DE is used, or in the send set) and is not used in the result, push.
1819 o If BC is used and is not in the result, push
1821 o If DE is used in the send set, fetch
1822 o If HL is used in the send set, fetch
1826 if (_G.saves.saved == FALSE) {
1827 bool deInUse, bcInUse;
1829 bool bcInRet = FALSE, deInRet = FALSE;
1833 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
1837 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), z80_rUmaskForOp (IC_RESULT(ic)));
1841 /* Has no result, so in use is all of in use */
1846 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
1847 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
1849 deSending = (sendSetSize > 1);
1851 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
1853 if (bcInUse && bcInRet == FALSE) {
1855 _G.stack.pushedBC = TRUE;
1857 if (deInUse && deInRet == FALSE) {
1859 _G.stack.pushedDE = TRUE;
1862 _G.saves.saved = TRUE;
1865 /* Already saved. */
1869 /*-----------------------------------------------------------------*/
1870 /* genIpush - genrate code for pushing this gets a little complex */
1871 /*-----------------------------------------------------------------*/
1873 genIpush (iCode * ic)
1875 int size, offset = 0;
1878 /* if this is not a parm push : ie. it is spill push
1879 and spill push is always done on the local stack */
1882 wassertl(0, "Encountered an unsupported spill push.");
1886 if (_G.saves.saved == FALSE) {
1887 /* Caller saves, and this is the first iPush. */
1888 /* Scan ahead until we find the function that we are pushing parameters to.
1889 Count the number of addSets on the way to figure out what registers
1890 are used in the send set.
1893 iCode *walk = ic->next;
1896 if (walk->op == SEND) {
1899 else if (walk->op == CALL || walk->op == PCALL) {
1908 _saveRegsForCall(walk, nAddSets);
1911 /* Already saved by another iPush. */
1914 /* then do the push */
1915 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1917 size = AOP_SIZE (IC_LEFT (ic));
1919 if (isPair (AOP (IC_LEFT (ic))))
1921 _G.stack.pushed += 2;
1922 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
1928 fetchHL (AOP (IC_LEFT (ic)));
1930 spillPair (PAIR_HL);
1931 _G.stack.pushed += 2;
1936 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
1938 spillPair (PAIR_HL);
1939 _G.stack.pushed += 2;
1940 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 0);
1942 spillPair (PAIR_HL);
1943 _G.stack.pushed += 2;
1949 if (AOP (IC_LEFT (ic))->type == AOP_IY)
1951 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
1953 emit2 ("ld a,(%s)", l);
1957 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
1958 emit2 ("ld a,%s", l);
1966 freeAsmop (IC_LEFT (ic), NULL, ic);
1969 /*-----------------------------------------------------------------*/
1970 /* genIpop - recover the registers: can happen only for spilling */
1971 /*-----------------------------------------------------------------*/
1973 genIpop (iCode * ic)
1978 /* if the temp was not pushed then */
1979 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
1982 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1983 size = AOP_SIZE (IC_LEFT (ic));
1984 offset = (size - 1);
1985 if (isPair (AOP (IC_LEFT (ic))))
1987 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
1995 spillPair (PAIR_HL);
1996 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2000 freeAsmop (IC_LEFT (ic), NULL, ic);
2003 /* This is quite unfortunate */
2005 setArea (int inHome)
2008 static int lastArea = 0;
2010 if (_G.in_home != inHome) {
2012 const char *sz = port->mem.code_name;
2013 port->mem.code_name = "HOME";
2014 emit2("!area", CODE_NAME);
2015 port->mem.code_name = sz;
2018 emit2("!area", CODE_NAME); */
2019 _G.in_home = inHome;
2030 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2034 symbol *sym = OP_SYMBOL (op);
2036 if (sym->isspilt || sym->nRegs == 0)
2039 aopOp (op, ic, FALSE, FALSE);
2042 if (aop->type == AOP_REG)
2045 for (i = 0; i < aop->size; i++)
2047 if (pairId == PAIR_DE)
2049 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2050 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2052 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2055 else if (pairId == PAIR_BC)
2057 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2058 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2060 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2070 freeAsmop (IC_LEFT (ic), NULL, ic);
2074 /** Emit the code for a call statement
2077 emitCall (iCode * ic, bool ispcall)
2079 sym_link *detype = getSpec (operandType (IC_LEFT (ic)));
2081 bitVect *rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
2083 /* if caller saves & we have not saved then */
2089 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2091 /* if send set is not empty then assign */
2096 int nSend = elementsInSet(_G.sendSet);
2097 bool swapped = FALSE;
2099 int _z80_sendOrder[] = {
2104 /* Check if the parameters are swapped. If so route through hl instead. */
2105 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2107 sic = setFirstItem(_G.sendSet);
2108 sic = setNextItem(_G.sendSet);
2110 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2111 /* The second send value is loaded from one the one that holds the first
2112 send, i.e. it is overwritten. */
2113 /* Cache the first in HL, and load the second from HL instead. */
2114 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2115 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2121 for (sic = setFirstItem (_G.sendSet); sic;
2122 sic = setNextItem (_G.sendSet))
2125 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2127 size = AOP_SIZE (IC_LEFT (sic));
2128 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2129 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2131 // PENDING: Mild hack
2132 if (swapped == TRUE && send == 1) {
2134 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2137 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2139 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2142 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2146 freeAsmop (IC_LEFT (sic), NULL, sic);
2153 if (IS_BANKEDCALL (detype))
2155 werror (W_INDIR_BANKED);
2157 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2159 if (isLitWord (AOP (IC_LEFT (ic))))
2161 emitDebug ("; Special case where the pCall is to a constant");
2162 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2166 symbol *rlbl = newiTempLabel (NULL);
2167 spillPair (PAIR_HL);
2168 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2170 _G.stack.pushed += 2;
2172 fetchHL (AOP (IC_LEFT (ic)));
2174 emit2 ("!tlabeldef", (rlbl->key + 100));
2175 _G.stack.pushed -= 2;
2177 freeAsmop (IC_LEFT (ic), NULL, ic);
2181 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2182 OP_SYMBOL (IC_LEFT (ic))->rname :
2183 OP_SYMBOL (IC_LEFT (ic))->name;
2184 if (IS_BANKEDCALL (detype))
2186 emit2 ("call banked_call");
2187 emit2 ("!dws", name);
2188 emit2 ("!dw !bankimmeds", name);
2193 emit2 ("call %s", name);
2198 /* Mark the regsiters as restored. */
2199 _G.saves.saved = FALSE;
2201 /* if we need assign a result value */
2202 if ((IS_ITEMP (IC_RESULT (ic)) &&
2203 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2204 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2205 IS_TRUE_SYMOP (IC_RESULT (ic)))
2208 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2210 assignResultValue (IC_RESULT (ic));
2212 freeAsmop (IC_RESULT (ic), NULL, ic);
2215 /* adjust the stack for parameters if required */
2218 int i = ic->parmBytes;
2220 _G.stack.pushed -= i;
2223 emit2 ("!ldaspsp", i);
2230 emit2 ("ld hl,#%d", i);
2231 emit2 ("add hl,sp");
2248 if (_G.stack.pushedDE)
2250 bool dInUse = bitVectBitValue(rInUse, D_IDX);
2251 bool eInUse = bitVectBitValue(rInUse, E_IDX);
2253 if (dInUse && eInUse)
2269 wassertl (0, "Neither D or E were in use but it was pushed.");
2271 _G.stack.pushedDE = FALSE;
2274 if (_G.stack.pushedBC)
2276 bool bInUse = bitVectBitValue(rInUse, B_IDX);
2277 bool cInUse = bitVectBitValue(rInUse, C_IDX);
2279 // If both B and C are used in the return value, then we won't get
2281 if (bInUse && cInUse)
2297 wassertl (0, "Neither B or C were in use but it was pushed.");
2299 _G.stack.pushedBC = FALSE;
2303 /*-----------------------------------------------------------------*/
2304 /* genCall - generates a call statement */
2305 /*-----------------------------------------------------------------*/
2307 genCall (iCode * ic)
2309 emitCall (ic, FALSE);
2312 /*-----------------------------------------------------------------*/
2313 /* genPcall - generates a call by pointer statement */
2314 /*-----------------------------------------------------------------*/
2316 genPcall (iCode * ic)
2318 emitCall (ic, TRUE);
2321 /*-----------------------------------------------------------------*/
2322 /* resultRemat - result is rematerializable */
2323 /*-----------------------------------------------------------------*/
2325 resultRemat (iCode * ic)
2327 if (SKIP_IC (ic) || ic->op == IFX)
2330 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2332 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2333 if (sym->remat && !POINTER_SET (ic))
2340 extern set *publics;
2342 /*-----------------------------------------------------------------*/
2343 /* genFunction - generated code for function entry */
2344 /*-----------------------------------------------------------------*/
2346 genFunction (iCode * ic)
2348 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2352 bool bcInUse = FALSE;
2353 bool deInUse = FALSE;
2356 setArea (IS_NONBANKED (sym->etype));
2358 /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
2361 _G.receiveOffset = 0;
2365 if (!IS_STATIC (sym->etype))
2367 addSetIfnotP (&publics, sym);
2371 /* Record the last function name for debugging. */
2372 _G.lastFunctionName = sym->rname;
2374 /* Create the function header */
2375 emit2 ("!functionheader", sym->name);
2376 /* PENDING: portability. */
2377 emit2 ("__%s_start:", sym->rname);
2378 emit2 ("!functionlabeldef", sym->rname);
2380 if (options.profile)
2382 emit2 ("!profileenter");
2385 fetype = getSpec (operandType (IC_LEFT (ic)));
2387 /* if critical function then turn interrupts off */
2388 if (SPEC_CRTCL (fetype))
2391 /* if this is an interrupt service routine then save all potentially used registers. */
2392 if (IS_ISR (sym->etype))
2397 /* PENDING: callee-save etc */
2399 _G.stack.param_offset = 0;
2402 /* Detect which registers are used. */
2406 for (i = 0; i < sym->regsUsed->size; i++)
2408 if (bitVectBitValue (sym->regsUsed, i))
2422 /* Other systems use DE as a temporary. */
2433 _G.stack.param_offset += 2;
2436 _G.stack.pushedBC = bcInUse;
2441 _G.stack.param_offset += 2;
2444 _G.stack.pushedDE = deInUse;
2447 /* adjust the stack for the function */
2448 _G.stack.last = sym->stack;
2451 emit2 ("!enterx", sym->stack);
2454 _G.stack.offset = sym->stack;
2457 /*-----------------------------------------------------------------*/
2458 /* genEndFunction - generates epilogue for functions */
2459 /*-----------------------------------------------------------------*/
2461 genEndFunction (iCode * ic)
2463 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2465 if (IS_ISR (sym->etype))
2471 if (SPEC_CRTCL (sym->etype))
2474 /* PENDING: calleeSave */
2476 if (_G.stack.offset)
2478 emit2 ("!leavex", _G.stack.offset);
2486 if (_G.stack.pushedDE)
2489 _G.stack.pushedDE = FALSE;
2492 if (_G.stack.pushedDE)
2495 _G.stack.pushedDE = FALSE;
2499 if (options.profile)
2501 emit2 ("!profileexit");
2505 /* Both baned and non-banked just ret */
2508 /* PENDING: portability. */
2509 emit2 ("__%s_end:", sym->rname);
2511 _G.flushStatics = 1;
2512 _G.stack.pushed = 0;
2513 _G.stack.offset = 0;
2516 /*-----------------------------------------------------------------*/
2517 /* genRet - generate code for return statement */
2518 /*-----------------------------------------------------------------*/
2523 /* Errk. This is a hack until I can figure out how
2524 to cause dehl to spill on a call */
2525 int size, offset = 0;
2527 /* if we have no return value then
2528 just generate the "ret" */
2532 /* we have something to return then
2533 move the return value into place */
2534 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2535 size = AOP_SIZE (IC_LEFT (ic));
2537 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
2541 emit2 ("ld de,%s", l);
2545 emit2 ("ld hl,%s", l);
2550 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
2552 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
2553 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
2559 l = aopGet (AOP (IC_LEFT (ic)), offset,
2561 if (strcmp (_fReturn[offset], l))
2562 emit2 ("ld %s,%s", _fReturn[offset++], l);
2566 freeAsmop (IC_LEFT (ic), NULL, ic);
2569 /* generate a jump to the return label
2570 if the next is not the return statement */
2571 if (!(ic->next && ic->next->op == LABEL &&
2572 IC_LABEL (ic->next) == returnLabel))
2574 emit2 ("jp !tlabel", returnLabel->key + 100);
2577 /*-----------------------------------------------------------------*/
2578 /* genLabel - generates a label */
2579 /*-----------------------------------------------------------------*/
2581 genLabel (iCode * ic)
2583 /* special case never generate */
2584 if (IC_LABEL (ic) == entryLabel)
2587 emitLabel (IC_LABEL (ic)->key + 100);
2590 /*-----------------------------------------------------------------*/
2591 /* genGoto - generates a ljmp */
2592 /*-----------------------------------------------------------------*/
2594 genGoto (iCode * ic)
2596 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
2599 /*-----------------------------------------------------------------*/
2600 /* genPlusIncr :- does addition with increment if possible */
2601 /*-----------------------------------------------------------------*/
2603 genPlusIncr (iCode * ic)
2605 unsigned int icount;
2606 unsigned int size = getDataSize (IC_RESULT (ic));
2607 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
2609 /* will try to generate an increment */
2610 /* if the right side is not a literal
2612 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
2615 emitDebug ("; genPlusIncr");
2617 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
2619 /* If result is a pair */
2620 if (resultId != PAIR_INVALID)
2622 if (isLitWord (AOP (IC_LEFT (ic))))
2624 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
2627 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
2629 fetchPair (resultId, AOP (IC_RIGHT (ic)));
2630 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
2636 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2640 movLeft2Result (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0);
2641 movLeft2Result (IC_LEFT (ic), 1, IC_RESULT (ic), 1, 0);
2645 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
2650 /* if the literal value of the right hand side
2651 is greater than 4 then it is not worth it */
2655 /* if increment 16 bits in register */
2656 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
2662 symbol *tlbl = NULL;
2663 tlbl = newiTempLabel (NULL);
2666 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
2669 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
2672 emitLabel (tlbl->key + 100);
2676 /* if the sizes are greater than 1 then we cannot */
2677 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
2678 AOP_SIZE (IC_LEFT (ic)) > 1)
2681 /* we can if the aops of the left & result match or
2682 if they are in registers and the registers are the
2684 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2688 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
2696 /*-----------------------------------------------------------------*/
2697 /* outBitAcc - output a bit in acc */
2698 /*-----------------------------------------------------------------*/
2700 outBitAcc (operand * result)
2702 symbol *tlbl = newiTempLabel (NULL);
2703 /* if the result is a bit */
2704 if (AOP_TYPE (result) == AOP_CRY)
2710 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
2711 emit2 ("ld a,!one");
2712 emitLabel (tlbl->key + 100);
2717 /*-----------------------------------------------------------------*/
2718 /* genPlus - generates code for addition */
2719 /*-----------------------------------------------------------------*/
2721 genPlus (iCode * ic)
2723 int size, offset = 0;
2725 /* special cases :- */
2727 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2728 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
2729 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2731 /* Swap the left and right operands if:
2733 if literal, literal on the right or
2734 if left requires ACC or right is already
2737 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
2738 (AOP_NEEDSACC (IC_LEFT (ic))) ||
2739 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
2741 operand *t = IC_RIGHT (ic);
2742 IC_RIGHT (ic) = IC_LEFT (ic);
2746 /* if both left & right are in bit
2748 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
2749 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
2755 /* if left in bit space & right literal */
2756 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
2757 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
2759 /* Can happen I guess */
2763 /* if I can do an increment instead
2764 of add then GOOD for ME */
2765 if (genPlusIncr (ic) == TRUE)
2768 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
2770 size = getDataSize (IC_RESULT (ic));
2772 /* Special case when left and right are constant */
2773 if (isPair (AOP (IC_RESULT (ic))))
2776 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
2777 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
2779 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
2785 sprintf (buffer, "#(%s + %s)", left, right);
2786 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
2791 if (isPair (AOP (IC_RIGHT (ic))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
2793 /* Fetch into HL then do the add */
2794 spillPair (PAIR_HL);
2795 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
2796 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
2801 ld hl,sp+n trashes C so we cant afford to do it during an
2802 add with stack based varibles. Worst case is:
2815 So you cant afford to load up hl if either left, right, or result
2816 is on the stack (*sigh*) The alt is:
2824 Combinations in here are:
2825 * If left or right are in bc then the loss is small - trap later
2826 * If the result is in bc then the loss is also small
2830 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
2831 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
2832 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
2834 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
2835 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
2836 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
2837 AOP_SIZE (IC_RIGHT (ic)) <= 2))
2839 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
2841 /* Swap left and right */
2842 operand *t = IC_RIGHT (ic);
2843 IC_RIGHT (ic) = IC_LEFT (ic);
2846 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
2848 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
2849 emit2 ("add hl,bc");
2853 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
2854 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
2855 emit2 ("add hl,de");
2857 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
2869 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
2871 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
2874 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2877 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2881 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
2884 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2887 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2889 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2893 freeAsmop (IC_LEFT (ic), NULL, ic);
2894 freeAsmop (IC_RIGHT (ic), NULL, ic);
2895 freeAsmop (IC_RESULT (ic), NULL, ic);
2899 /*-----------------------------------------------------------------*/
2900 /* genMinusDec :- does subtraction with deccrement if possible */
2901 /*-----------------------------------------------------------------*/
2903 genMinusDec (iCode * ic)
2905 unsigned int icount;
2906 unsigned int size = getDataSize (IC_RESULT (ic));
2908 /* will try to generate an increment */
2909 /* if the right side is not a literal we cannot */
2910 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
2913 /* if the literal value of the right hand side
2914 is greater than 4 then it is not worth it */
2915 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
2918 size = getDataSize (IC_RESULT (ic));
2920 /* if decrement 16 bits in register */
2921 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
2922 (size > 1) && isPair (AOP (IC_RESULT (ic))))
2925 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
2929 /* If result is a pair */
2930 if (isPair (AOP (IC_RESULT (ic))))
2932 movLeft2Result (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0);
2933 movLeft2Result (IC_LEFT (ic), 1, IC_RESULT (ic), 1, 0);
2935 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
2939 /* if increment 16 bits in register */
2940 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
2944 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
2947 emit2 ("dec %s", _getTempPairName());
2950 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
2956 /* if the sizes are greater than 1 then we cannot */
2957 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
2958 AOP_SIZE (IC_LEFT (ic)) > 1)
2961 /* we can if the aops of the left & result match or if they are in
2962 registers and the registers are the same */
2963 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2966 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
2973 /*-----------------------------------------------------------------*/
2974 /* genMinus - generates code for subtraction */
2975 /*-----------------------------------------------------------------*/
2977 genMinus (iCode * ic)
2979 int size, offset = 0;
2980 unsigned long lit = 0L;
2982 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2983 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
2984 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2986 /* special cases :- */
2987 /* if both left & right are in bit space */
2988 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
2989 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
2995 /* if I can do an decrement instead of subtract then GOOD for ME */
2996 if (genMinusDec (ic) == TRUE)
2999 size = getDataSize (IC_RESULT (ic));
3001 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3006 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3010 /* Same logic as genPlus */
3013 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3014 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3015 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3017 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3018 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3019 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3020 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3022 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3023 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3025 if (left == PAIR_INVALID && right == PAIR_INVALID)
3030 else if (right == PAIR_INVALID)
3032 else if (left == PAIR_INVALID)
3035 fetchPair (left, AOP (IC_LEFT (ic)));
3036 /* Order is important. Right may be HL */
3037 fetchPair (right, AOP (IC_RIGHT (ic)));
3039 emit2 ("ld a,%s", _pairs[left].l);
3040 emit2 ("sub a,%s", _pairs[right].l);
3042 emit2 ("ld a,%s", _pairs[left].h);
3043 emit2 ("sbc a,%s", _pairs[right].h);
3045 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3046 aopPut (AOP (IC_RESULT (ic)), "e", 0);
3051 /* Anything could be on the stack, and we can't afford
3052 to setup the base pointer as that may nuke the carry.
3054 emitDebug ("; WARNING: This sub is probably broken.\n");
3059 /* if literal, add a,#-lit, else normal subb */
3062 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3063 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3067 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3070 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3074 /* first add without previous c */
3076 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
3078 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3080 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3083 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3084 AOP_SIZE (IC_LEFT (ic)) == 3 &&
3085 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3089 freeAsmop (IC_LEFT (ic), NULL, ic);
3090 freeAsmop (IC_RIGHT (ic), NULL, ic);
3091 freeAsmop (IC_RESULT (ic), NULL, ic);
3094 /*-----------------------------------------------------------------*/
3095 /* genMult - generates code for multiplication */
3096 /*-----------------------------------------------------------------*/
3098 genMult (iCode * ic)
3100 /* Shouldn't occur - all done through function calls */
3104 /*-----------------------------------------------------------------*/
3105 /* genDiv - generates code for division */
3106 /*-----------------------------------------------------------------*/
3110 /* Shouldn't occur - all done through function calls */
3114 /*-----------------------------------------------------------------*/
3115 /* genMod - generates code for division */
3116 /*-----------------------------------------------------------------*/
3120 /* Shouldn't occur - all done through function calls */
3124 /*-----------------------------------------------------------------*/
3125 /* genIfxJump :- will create a jump depending on the ifx */
3126 /*-----------------------------------------------------------------*/
3128 genIfxJump (iCode * ic, char *jval)
3133 /* if true label then we jump if condition
3137 jlbl = IC_TRUE (ic);
3138 if (!strcmp (jval, "a"))
3142 else if (!strcmp (jval, "c"))
3146 else if (!strcmp (jval, "nc"))
3152 /* The buffer contains the bit on A that we should test */
3158 /* false label is present */
3159 jlbl = IC_FALSE (ic);
3160 if (!strcmp (jval, "a"))
3164 else if (!strcmp (jval, "c"))
3168 else if (!strcmp (jval, "nc"))
3174 /* The buffer contains the bit on A that we should test */
3178 /* Z80 can do a conditional long jump */
3179 if (!strcmp (jval, "a"))
3183 else if (!strcmp (jval, "c"))
3186 else if (!strcmp (jval, "nc"))
3191 emit2 ("bit %s,a", jval);
3193 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
3195 /* mark the icode as generated */
3201 _getPairIdName (PAIR_ID id)
3203 return _pairs[id].name;
3207 /** Generic compare for > or <
3210 genCmp (operand * left, operand * right,
3211 operand * result, iCode * ifx, int sign)
3213 int size, offset = 0;
3214 unsigned long lit = 0L;
3215 bool swap_sense = FALSE;
3217 /* if left & right are bit variables */
3218 if (AOP_TYPE (left) == AOP_CRY &&
3219 AOP_TYPE (right) == AOP_CRY)
3221 /* Cant happen on the Z80 */
3226 /* subtract right from left if at the
3227 end the carry flag is set then we know that
3228 left is greater than right */
3229 size = max (AOP_SIZE (left), AOP_SIZE (right));
3231 /* if unsigned char cmp with lit, just compare */
3233 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
3235 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3238 emit2 ("xor a,!immedbyte", 0x80);
3239 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
3242 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3247 // PENDING: Doesn't work around zero
3251 If the left or the right is a lit:
3252 Load -lit into HL, add to right via, check sense.
3254 if (IS_GB && size == 2 && (AOP_TYPE (right) == AOP_LIT || AOP_TYPE (left) == AOP_LIT))
3256 PAIR_ID id = PAIR_DE;
3257 asmop *lit = AOP (right);
3258 asmop *op = AOP (left);
3261 if (AOP_TYPE (left) == AOP_LIT)
3269 emit2 ("ld e,%s", aopGet (op, 0, 0));
3270 emit2 ("ld a,%s", aopGet (op, 1, 0));
3271 emit2 ("xor a,!immedbyte", 0x80);
3276 id = getPairId (op);
3277 if (id == PAIR_INVALID)
3279 fetchPair (PAIR_DE, op);
3283 spillPair (PAIR_HL);
3284 emit2 ("ld hl,%s", fetchLitSpecial (lit, TRUE, sign));
3285 emit2 ("add hl,%s", _getPairIdName (id));
3289 if (AOP_TYPE (right) == AOP_LIT)
3291 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3292 /* optimize if(x < 0) or if(x >= 0) */
3297 /* No sign so it's always false */
3302 /* Just load in the top most bit */
3303 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
3304 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
3306 genIfxJump (ifx, "7");
3317 /* First setup h and l contaning the top most bytes XORed */
3318 bool fDidXor = FALSE;
3319 if (AOP_TYPE (left) == AOP_LIT)
3321 unsigned long lit = (unsigned long)
3322 floatFromVal (AOP (left)->aopu.aop_lit);
3323 emit2 ("ld %s,!immedbyte", _fTmp[0],
3324 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3328 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
3329 emit2 ("xor a,!immedbyte", 0x80);
3330 emit2 ("ld %s,a", _fTmp[0]);
3333 if (AOP_TYPE (right) == AOP_LIT)
3335 unsigned long lit = (unsigned long)
3336 floatFromVal (AOP (right)->aopu.aop_lit);
3337 emit2 ("ld %s,!immedbyte", _fTmp[1],
3338 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3342 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
3343 emit2 ("xor a,!immedbyte", 0x80);
3344 emit2 ("ld %s,a", _fTmp[1]);
3356 /* Do a long subtract */
3359 _moveA (aopGet (AOP (left), offset, FALSE));
3361 if (sign && size == 0)
3363 emit2 ("ld a,%s", _fTmp[0]);
3364 emit2 ("sbc a,%s", _fTmp[1]);
3368 /* Subtract through, propagating the carry */
3369 emit2 ("sbc a,%s", aopGet (AOP (right), offset++, FALSE));
3376 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
3378 outBitCLong (result, swap_sense);
3382 /* if the result is used in the next
3383 ifx conditional branch then generate
3384 code a little differently */
3386 genIfxJump (ifx, swap_sense ? "nc" : "c");
3388 outBitCLong (result, swap_sense);
3389 /* leave the result in acc */
3393 /*-----------------------------------------------------------------*/
3394 /* genCmpGt :- greater than comparison */
3395 /*-----------------------------------------------------------------*/
3397 genCmpGt (iCode * ic, iCode * ifx)
3399 operand *left, *right, *result;
3400 sym_link *letype, *retype;
3403 left = IC_LEFT (ic);
3404 right = IC_RIGHT (ic);
3405 result = IC_RESULT (ic);
3407 letype = getSpec (operandType (left));
3408 retype = getSpec (operandType (right));
3409 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
3410 /* assign the amsops */
3411 aopOp (left, ic, FALSE, FALSE);
3412 aopOp (right, ic, FALSE, FALSE);
3413 aopOp (result, ic, TRUE, FALSE);
3415 genCmp (right, left, result, ifx, sign);
3417 freeAsmop (left, NULL, ic);
3418 freeAsmop (right, NULL, ic);
3419 freeAsmop (result, NULL, ic);
3422 /*-----------------------------------------------------------------*/
3423 /* genCmpLt - less than comparisons */
3424 /*-----------------------------------------------------------------*/
3426 genCmpLt (iCode * ic, iCode * ifx)
3428 operand *left, *right, *result;
3429 sym_link *letype, *retype;
3432 left = IC_LEFT (ic);
3433 right = IC_RIGHT (ic);
3434 result = IC_RESULT (ic);
3436 letype = getSpec (operandType (left));
3437 retype = getSpec (operandType (right));
3438 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
3440 /* assign the amsops */
3441 aopOp (left, ic, FALSE, FALSE);
3442 aopOp (right, ic, FALSE, FALSE);
3443 aopOp (result, ic, TRUE, FALSE);
3445 genCmp (left, right, result, ifx, sign);
3447 freeAsmop (left, NULL, ic);
3448 freeAsmop (right, NULL, ic);
3449 freeAsmop (result, NULL, ic);
3452 /*-----------------------------------------------------------------*/
3453 /* gencjneshort - compare and jump if not equal */
3454 /*-----------------------------------------------------------------*/
3456 gencjneshort (operand * left, operand * right, symbol * lbl)
3458 int size = max (AOP_SIZE (left), AOP_SIZE (right));
3460 unsigned long lit = 0L;
3462 /* Swap the left and right if it makes the computation easier */
3463 if (AOP_TYPE (left) == AOP_LIT)
3470 if (AOP_TYPE (right) == AOP_LIT)
3471 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3473 /* if the right side is a literal then anything goes */
3474 if (AOP_TYPE (right) == AOP_LIT &&
3475 AOP_TYPE (left) != AOP_DIR)
3479 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3486 emit2 ("or a,%s", aopGet (AOP (left), offset, FALSE));
3493 emit2 ("jp nz,!tlabel", lbl->key + 100);
3499 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3500 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
3503 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
3504 emit2 ("jp nz,!tlabel", lbl->key + 100);
3509 /* if the right side is in a register or in direct space or
3510 if the left is a pointer register & right is not */
3511 else if (AOP_TYPE (right) == AOP_REG ||
3512 AOP_TYPE (right) == AOP_DIR ||
3513 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
3517 _moveA (aopGet (AOP (left), offset, FALSE));
3518 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
3519 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
3521 emit2 ("jp nz,!tlabel", lbl->key + 100);
3524 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3525 emit2 ("jp nz,!tlabel", lbl->key + 100);
3532 /* right is a pointer reg need both a & b */
3533 /* PENDING: is this required? */
3536 _moveA (aopGet (AOP (right), offset, FALSE));
3537 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
3538 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
3544 /*-----------------------------------------------------------------*/
3545 /* gencjne - compare and jump if not equal */
3546 /*-----------------------------------------------------------------*/
3548 gencjne (operand * left, operand * right, symbol * lbl)
3550 symbol *tlbl = newiTempLabel (NULL);
3552 gencjneshort (left, right, lbl);
3555 emit2 ("ld a,!one");
3556 emit2 ("!shortjp !tlabel", tlbl->key + 100);
3557 emitLabel (lbl->key + 100);
3559 emitLabel (tlbl->key + 100);
3562 /*-----------------------------------------------------------------*/
3563 /* genCmpEq - generates code for equal to */
3564 /*-----------------------------------------------------------------*/
3566 genCmpEq (iCode * ic, iCode * ifx)
3568 operand *left, *right, *result;
3570 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
3571 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
3572 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
3574 emitDebug ("; genCmpEq: left %u, right %u, result %u\n", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
3576 /* Swap operands if it makes the operation easier. ie if:
3577 1. Left is a literal.
3579 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
3581 operand *t = IC_RIGHT (ic);
3582 IC_RIGHT (ic) = IC_LEFT (ic);
3586 if (ifx && !AOP_SIZE (result))
3589 /* if they are both bit variables */
3590 if (AOP_TYPE (left) == AOP_CRY &&
3591 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
3597 tlbl = newiTempLabel (NULL);
3598 gencjneshort (left, right, tlbl);
3601 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
3602 emitLabel (tlbl->key + 100);
3606 /* PENDING: do this better */
3607 symbol *lbl = newiTempLabel (NULL);
3608 emit2 ("!shortjp !tlabel", lbl->key + 100);
3609 emitLabel (tlbl->key + 100);
3610 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
3611 emitLabel (lbl->key + 100);
3614 /* mark the icode as generated */
3619 /* if they are both bit variables */
3620 if (AOP_TYPE (left) == AOP_CRY &&
3621 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
3627 gencjne (left, right, newiTempLabel (NULL));
3628 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
3634 genIfxJump (ifx, "a");
3637 /* if the result is used in an arithmetic operation
3638 then put the result in place */
3639 if (AOP_TYPE (result) != AOP_CRY)
3643 /* leave the result in acc */
3647 freeAsmop (left, NULL, ic);
3648 freeAsmop (right, NULL, ic);
3649 freeAsmop (result, NULL, ic);
3652 /*-----------------------------------------------------------------*/
3653 /* ifxForOp - returns the icode containing the ifx for operand */
3654 /*-----------------------------------------------------------------*/
3656 ifxForOp (operand * op, iCode * ic)
3658 /* if true symbol then needs to be assigned */
3659 if (IS_TRUE_SYMOP (op))
3662 /* if this has register type condition and
3663 the next instruction is ifx with the same operand
3664 and live to of the operand is upto the ifx only then */
3666 ic->next->op == IFX &&
3667 IC_COND (ic->next)->key == op->key &&
3668 OP_SYMBOL (op)->liveTo <= ic->next->seq)
3674 /*-----------------------------------------------------------------*/
3675 /* genAndOp - for && operation */
3676 /*-----------------------------------------------------------------*/
3678 genAndOp (iCode * ic)
3680 operand *left, *right, *result;
3683 /* note here that && operations that are in an if statement are
3684 taken away by backPatchLabels only those used in arthmetic
3685 operations remain */
3686 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
3687 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
3688 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
3690 /* if both are bit variables */
3691 if (AOP_TYPE (left) == AOP_CRY &&
3692 AOP_TYPE (right) == AOP_CRY)
3698 tlbl = newiTempLabel (NULL);
3700 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3702 emitLabel (tlbl->key + 100);
3706 freeAsmop (left, NULL, ic);
3707 freeAsmop (right, NULL, ic);
3708 freeAsmop (result, NULL, ic);
3711 /*-----------------------------------------------------------------*/
3712 /* genOrOp - for || operation */
3713 /*-----------------------------------------------------------------*/
3715 genOrOp (iCode * ic)
3717 operand *left, *right, *result;
3720 /* note here that || operations that are in an
3721 if statement are taken away by backPatchLabels
3722 only those used in arthmetic operations remain */
3723 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
3724 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
3725 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
3727 /* if both are bit variables */
3728 if (AOP_TYPE (left) == AOP_CRY &&
3729 AOP_TYPE (right) == AOP_CRY)
3735 tlbl = newiTempLabel (NULL);
3737 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3739 emitLabel (tlbl->key + 100);
3743 freeAsmop (left, NULL, ic);
3744 freeAsmop (right, NULL, ic);
3745 freeAsmop (result, NULL, ic);
3748 /*-----------------------------------------------------------------*/
3749 /* isLiteralBit - test if lit == 2^n */
3750 /*-----------------------------------------------------------------*/
3752 isLiteralBit (unsigned long lit)
3754 unsigned long pw[32] =
3755 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
3756 0x100L, 0x200L, 0x400L, 0x800L,
3757 0x1000L, 0x2000L, 0x4000L, 0x8000L,
3758 0x10000L, 0x20000L, 0x40000L, 0x80000L,
3759 0x100000L, 0x200000L, 0x400000L, 0x800000L,
3760 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
3761 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
3764 for (idx = 0; idx < 32; idx++)
3770 /*-----------------------------------------------------------------*/
3771 /* jmpTrueOrFalse - */
3772 /*-----------------------------------------------------------------*/
3774 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
3776 // ugly but optimized by peephole
3779 symbol *nlbl = newiTempLabel (NULL);
3780 emit2 ("jp !tlabel", nlbl->key + 100);
3781 emitLabel (tlbl->key + 100);
3782 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
3783 emitLabel (nlbl->key + 100);
3787 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
3788 emitLabel (tlbl->key + 100);
3793 /*-----------------------------------------------------------------*/
3794 /* genAnd - code for and */
3795 /*-----------------------------------------------------------------*/
3797 genAnd (iCode * ic, iCode * ifx)
3799 operand *left, *right, *result;
3800 int size, offset = 0;
3801 unsigned long lit = 0L;
3804 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
3805 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
3806 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
3809 emitDebug ("; Type res[%d] = l[%d]&r[%d]",
3811 AOP_TYPE (left), AOP_TYPE (right));
3812 emitDebug ("; Size res[%d] = l[%d]&r[%d]",
3814 AOP_SIZE (left), AOP_SIZE (right));
3817 /* if left is a literal & right is not then exchange them */
3818 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
3819 AOP_NEEDSACC (left))
3821 operand *tmp = right;
3826 /* if result = right then exchange them */
3827 if (sameRegs (AOP (result), AOP (right)))
3829 operand *tmp = right;
3834 /* if right is bit then exchange them */
3835 if (AOP_TYPE (right) == AOP_CRY &&
3836 AOP_TYPE (left) != AOP_CRY)
3838 operand *tmp = right;
3842 if (AOP_TYPE (right) == AOP_LIT)
3843 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3845 size = AOP_SIZE (result);
3847 if (AOP_TYPE (left) == AOP_CRY)
3853 // if(val & 0xZZ) - size = 0, ifx != FALSE -
3854 // bit = val & 0xZZ - size = 1, ifx = FALSE -
3855 if ((AOP_TYPE (right) == AOP_LIT) &&
3856 (AOP_TYPE (result) == AOP_CRY) &&
3857 (AOP_TYPE (left) != AOP_CRY))
3859 int posbit = isLiteralBit (lit);
3864 _moveA (aopGet (AOP (left), posbit >> 3, FALSE));
3869 emit2 ("mov c,acc.%d", posbit & 0x07);
3876 sprintf (buffer, "%d", posbit & 0x07);
3877 genIfxJump (ifx, buffer);
3888 symbol *tlbl = newiTempLabel (NULL);
3889 int sizel = AOP_SIZE (left);
3897 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
3899 _moveA (aopGet (AOP (left), offset, FALSE));
3901 if ((posbit = isLiteralBit (bytelit)) != 0)
3904 emit2 ("jb acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
3908 if (bytelit != 0x0FFL)
3910 aopGet (AOP (right), offset, FALSE));
3914 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3919 // bit = left & literal
3923 emit2 ("!tlabeldef", tlbl->key + 100);
3925 // if(left & literal)
3929 jmpTrueOrFalse (ifx, tlbl);
3937 /* if left is same as result */
3938 if (sameRegs (AOP (result), AOP (left)))
3940 for (; size--; offset++)
3942 if (AOP_TYPE (right) == AOP_LIT)
3944 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
3949 aopPut (AOP (result), "!zero", offset);
3952 _moveA (aopGet (AOP (left), offset, FALSE));
3954 aopGet (AOP (right), offset, FALSE));
3955 aopPut (AOP (left), "a", offset);
3962 if (AOP_TYPE (left) == AOP_ACC)
3968 _moveA (aopGet (AOP (left), offset, FALSE));
3970 aopGet (AOP (right), offset, FALSE));
3971 aopPut (AOP (left), "a", offset);
3978 // left & result in different registers
3979 if (AOP_TYPE (result) == AOP_CRY)
3985 for (; (size--); offset++)
3988 // result = left & right
3989 if (AOP_TYPE (right) == AOP_LIT)
3991 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
3993 aopPut (AOP (result),
3994 aopGet (AOP (left), offset, FALSE),
3998 else if (bytelit == 0)
4000 aopPut (AOP (result), "!zero", offset);
4004 // faster than result <- left, anl result,right
4005 // and better if result is SFR
4006 if (AOP_TYPE (left) == AOP_ACC)
4007 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4010 _moveA (aopGet (AOP (left), offset, FALSE));
4012 aopGet (AOP (right), offset, FALSE));
4014 aopPut (AOP (result), "a", offset);
4021 freeAsmop (left, NULL, ic);
4022 freeAsmop (right, NULL, ic);
4023 freeAsmop (result, NULL, ic);
4026 /*-----------------------------------------------------------------*/
4027 /* genOr - code for or */
4028 /*-----------------------------------------------------------------*/
4030 genOr (iCode * ic, iCode * ifx)
4032 operand *left, *right, *result;
4033 int size, offset = 0;
4034 unsigned long lit = 0L;
4036 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4037 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4038 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4041 emitDebug ("; Type res[%d] = l[%d]&r[%d]",
4043 AOP_TYPE (left), AOP_TYPE (right));
4044 emitDebug ("; Size res[%d] = l[%d]&r[%d]",
4046 AOP_SIZE (left), AOP_SIZE (right));
4049 /* if left is a literal & right is not then exchange them */
4050 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4051 AOP_NEEDSACC (left))
4053 operand *tmp = right;
4058 /* if result = right then exchange them */
4059 if (sameRegs (AOP (result), AOP (right)))
4061 operand *tmp = right;
4066 /* if right is bit then exchange them */
4067 if (AOP_TYPE (right) == AOP_CRY &&
4068 AOP_TYPE (left) != AOP_CRY)
4070 operand *tmp = right;
4074 if (AOP_TYPE (right) == AOP_LIT)
4075 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4077 size = AOP_SIZE (result);
4079 if (AOP_TYPE (left) == AOP_CRY)
4085 if ((AOP_TYPE (right) == AOP_LIT) &&
4086 (AOP_TYPE (result) == AOP_CRY) &&
4087 (AOP_TYPE (left) != AOP_CRY))
4093 /* if left is same as result */
4094 if (sameRegs (AOP (result), AOP (left)))
4096 for (; size--; offset++)
4098 if (AOP_TYPE (right) == AOP_LIT)
4100 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4104 _moveA (aopGet (AOP (left), offset, FALSE));
4106 aopGet (AOP (right), offset, FALSE));
4107 aopPut (AOP (result), "a", offset);
4112 if (AOP_TYPE (left) == AOP_ACC)
4113 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4116 _moveA (aopGet (AOP (left), offset, FALSE));
4118 aopGet (AOP (right), offset, FALSE));
4119 aopPut (AOP (result), "a", offset);
4126 // left & result in different registers
4127 if (AOP_TYPE (result) == AOP_CRY)
4132 for (; (size--); offset++)
4135 // result = left & right
4136 if (AOP_TYPE (right) == AOP_LIT)
4138 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4140 aopPut (AOP (result),
4141 aopGet (AOP (left), offset, FALSE),
4146 // faster than result <- left, anl result,right
4147 // and better if result is SFR
4148 if (AOP_TYPE (left) == AOP_ACC)
4149 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4152 _moveA (aopGet (AOP (left), offset, FALSE));
4154 aopGet (AOP (right), offset, FALSE));
4156 aopPut (AOP (result), "a", offset);
4157 /* PENDING: something weird is going on here. Add exception. */
4158 if (AOP_TYPE (result) == AOP_ACC)
4164 freeAsmop (left, NULL, ic);
4165 freeAsmop (right, NULL, ic);
4166 freeAsmop (result, NULL, ic);
4169 /*-----------------------------------------------------------------*/
4170 /* genXor - code for xclusive or */
4171 /*-----------------------------------------------------------------*/
4173 genXor (iCode * ic, iCode * ifx)
4175 operand *left, *right, *result;
4176 int size, offset = 0;
4177 unsigned long lit = 0L;
4179 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4180 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4181 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4183 /* if left is a literal & right is not then exchange them */
4184 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4185 AOP_NEEDSACC (left))
4187 operand *tmp = right;
4192 /* if result = right then exchange them */
4193 if (sameRegs (AOP (result), AOP (right)))
4195 operand *tmp = right;
4200 /* if right is bit then exchange them */
4201 if (AOP_TYPE (right) == AOP_CRY &&
4202 AOP_TYPE (left) != AOP_CRY)
4204 operand *tmp = right;
4208 if (AOP_TYPE (right) == AOP_LIT)
4209 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4211 size = AOP_SIZE (result);
4213 if (AOP_TYPE (left) == AOP_CRY)
4219 if ((AOP_TYPE (right) == AOP_LIT) &&
4220 (AOP_TYPE (result) == AOP_CRY) &&
4221 (AOP_TYPE (left) != AOP_CRY))
4227 /* if left is same as result */
4228 if (sameRegs (AOP (result), AOP (left)))
4230 for (; size--; offset++)
4232 if (AOP_TYPE (right) == AOP_LIT)
4234 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4238 _moveA (aopGet (AOP (right), offset, FALSE));
4240 aopGet (AOP (left), offset, FALSE));
4241 aopPut (AOP (result), "a", offset);
4246 if (AOP_TYPE (left) == AOP_ACC)
4248 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4252 _moveA (aopGet (AOP (right), offset, FALSE));
4254 aopGet (AOP (left), offset, FALSE));
4255 aopPut (AOP (result), "a", 0);
4262 // left & result in different registers
4263 if (AOP_TYPE (result) == AOP_CRY)
4268 for (; (size--); offset++)
4271 // result = left & right
4272 if (AOP_TYPE (right) == AOP_LIT)
4274 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4276 aopPut (AOP (result),
4277 aopGet (AOP (left), offset, FALSE),
4282 // faster than result <- left, anl result,right
4283 // and better if result is SFR
4284 if (AOP_TYPE (left) == AOP_ACC)
4286 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4290 _moveA (aopGet (AOP (right), offset, FALSE));
4292 aopGet (AOP (left), offset, FALSE));
4294 aopPut (AOP (result), "a", offset);
4299 freeAsmop (left, NULL, ic);
4300 freeAsmop (right, NULL, ic);
4301 freeAsmop (result, NULL, ic);
4304 /*-----------------------------------------------------------------*/
4305 /* genInline - write the inline code out */
4306 /*-----------------------------------------------------------------*/
4308 genInline (iCode * ic)
4310 char *buffer, *bp, *bp1;
4312 _G.lines.isInline += (!options.asmpeep);
4314 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
4315 strcpy (buffer, IC_INLINE (ic));
4317 /* emit each line as a code */
4342 _G.lines.isInline -= (!options.asmpeep);
4346 /*-----------------------------------------------------------------*/
4347 /* genRRC - rotate right with carry */
4348 /*-----------------------------------------------------------------*/
4355 /*-----------------------------------------------------------------*/
4356 /* genRLC - generate code for rotate left with carry */
4357 /*-----------------------------------------------------------------*/
4364 /*-----------------------------------------------------------------*/
4365 /* genGetHbit - generates code get highest order bit */
4366 /*-----------------------------------------------------------------*/
4368 genGetHbit (iCode * ic)
4370 operand *left, *result;
4371 left = IC_LEFT (ic);
4372 result = IC_RESULT (ic);
4373 aopOp (left, ic, FALSE, FALSE);
4374 aopOp (result, ic, FALSE, FALSE);
4376 /* get the highest order byte into a */
4377 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4379 if (AOP_TYPE (result) == AOP_CRY)
4387 /* PENDING: For re-target. */
4393 freeAsmop (left, NULL, ic);
4394 freeAsmop (result, NULL, ic);
4398 emitRsh2 (asmop *aop, int size, int is_signed)
4404 const char *l = aopGet (aop, size, FALSE);
4407 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
4417 /*-----------------------------------------------------------------*/
4418 /* shiftR2Left2Result - shift right two bytes from left to result */
4419 /*-----------------------------------------------------------------*/
4421 shiftR2Left2Result (operand * left, int offl,
4422 operand * result, int offr,
4423 int shCount, int is_signed)
4426 symbol *tlbl, *tlbl1;
4428 movLeft2Result (left, offl, result, offr, 0);
4429 movLeft2Result (left, offl + 1, result, offr + 1, 0);
4431 /* if (AOP(result)->type == AOP_REG) { */
4433 tlbl = newiTempLabel (NULL);
4434 tlbl1 = newiTempLabel (NULL);
4436 /* Left is already in result - so now do the shift */
4441 emitRsh2 (AOP (result), size, is_signed);
4446 emit2 ("ld a,!immedbyte+1", shCount);
4447 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4448 emitLabel (tlbl->key + 100);
4450 emitRsh2 (AOP (result), size, is_signed);
4452 emitLabel (tlbl1->key + 100);
4454 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4458 /*-----------------------------------------------------------------*/
4459 /* shiftL2Left2Result - shift left two bytes from left to result */
4460 /*-----------------------------------------------------------------*/
4462 shiftL2Left2Result (operand * left, int offl,
4463 operand * result, int offr, int shCount)
4465 if (sameRegs (AOP (result), AOP (left)) &&
4466 ((offl + MSB16) == offr))
4472 /* Copy left into result */
4473 movLeft2Result (left, offl, result, offr, 0);
4474 movLeft2Result (left, offl + 1, result, offr + 1, 0);
4476 /* PENDING: for now just see if it'll work. */
4477 /*if (AOP(result)->type == AOP_REG) { */
4481 symbol *tlbl, *tlbl1;
4484 tlbl = newiTempLabel (NULL);
4485 tlbl1 = newiTempLabel (NULL);
4487 /* Left is already in result - so now do the shift */
4490 emit2 ("ld a,!immedbyte+1", shCount);
4491 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4492 emitLabel (tlbl->key + 100);
4498 l = aopGet (AOP (result), offset, FALSE);
4506 emitLabel (tlbl1->key + 100);
4508 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4513 /*-----------------------------------------------------------------*/
4514 /* AccRol - rotate left accumulator by known count */
4515 /*-----------------------------------------------------------------*/
4517 AccRol (int shCount)
4519 shCount &= 0x0007; // shCount : 0..7
4558 /*-----------------------------------------------------------------*/
4559 /* AccLsh - left shift accumulator by known count */
4560 /*-----------------------------------------------------------------*/
4562 AccLsh (int shCount)
4564 static const unsigned char SLMask[] =
4566 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
4575 else if (shCount == 2)
4582 /* rotate left accumulator */
4584 /* and kill the lower order bits */
4585 emit2 ("and a,!immedbyte", SLMask[shCount]);
4590 /*-----------------------------------------------------------------*/
4591 /* shiftL1Left2Result - shift left one byte from left to result */
4592 /*-----------------------------------------------------------------*/
4594 shiftL1Left2Result (operand * left, int offl,
4595 operand * result, int offr, int shCount)
4598 l = aopGet (AOP (left), offl, FALSE);
4600 /* shift left accumulator */
4602 aopPut (AOP (result), "a", offr);
4606 /*-----------------------------------------------------------------*/
4607 /* genlshTwo - left shift two bytes by known amount != 0 */
4608 /*-----------------------------------------------------------------*/
4610 genlshTwo (operand * result, operand * left, int shCount)
4612 int size = AOP_SIZE (result);
4614 wassert (size == 2);
4616 /* if shCount >= 8 */
4624 movLeft2Result (left, LSB, result, MSB16, 0);
4625 aopPut (AOP (result), "!zero", 0);
4626 shiftL1Left2Result (left, MSB16, result, MSB16, shCount);
4630 movLeft2Result (left, LSB, result, MSB16, 0);
4631 aopPut (AOP (result), "!zero", 0);
4636 aopPut (AOP (result), "!zero", LSB);
4639 /* 1 <= shCount <= 7 */
4648 shiftL2Left2Result (left, LSB, result, LSB, shCount);
4653 /*-----------------------------------------------------------------*/
4654 /* genlshOne - left shift a one byte quantity by known count */
4655 /*-----------------------------------------------------------------*/
4657 genlshOne (operand * result, operand * left, int shCount)
4659 shiftL1Left2Result (left, LSB, result, LSB, shCount);
4662 /*-----------------------------------------------------------------*/
4663 /* genLeftShiftLiteral - left shifting by known count */
4664 /*-----------------------------------------------------------------*/
4666 genLeftShiftLiteral (operand * left,
4671 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
4674 freeAsmop (right, NULL, ic);
4676 aopOp (left, ic, FALSE, FALSE);
4677 aopOp (result, ic, FALSE, FALSE);
4679 size = getSize (operandType (result));
4682 emitDebug ("; shift left result %d, left %d", size,
4686 /* I suppose that the left size >= result size */
4692 else if (shCount >= (size * 8))
4696 aopPut (AOP (result), "!zero", size);
4704 genlshOne (result, left, shCount);
4707 genlshTwo (result, left, shCount);
4710 wassertl (0, "Shifting of longs is currently unsupported");
4716 freeAsmop (left, NULL, ic);
4717 freeAsmop (result, NULL, ic);
4720 /*-----------------------------------------------------------------*/
4721 /* genLeftShift - generates code for left shifting */
4722 /*-----------------------------------------------------------------*/
4724 genLeftShift (iCode * ic)
4728 symbol *tlbl, *tlbl1;
4729 operand *left, *right, *result;
4731 right = IC_RIGHT (ic);
4732 left = IC_LEFT (ic);
4733 result = IC_RESULT (ic);
4735 aopOp (right, ic, FALSE, FALSE);
4737 /* if the shift count is known then do it
4738 as efficiently as possible */
4739 if (AOP_TYPE (right) == AOP_LIT)
4741 genLeftShiftLiteral (left, right, result, ic);
4745 /* shift count is unknown then we have to form a loop get the loop
4746 count in B : Note: we take only the lower order byte since
4747 shifting more that 32 bits make no sense anyway, ( the largest
4748 size of an object can be only 32 bits ) */
4749 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
4751 freeAsmop (right, NULL, ic);
4752 aopOp (left, ic, FALSE, FALSE);
4753 aopOp (result, ic, FALSE, FALSE);
4755 /* now move the left to the result if they are not the
4758 if (!sameRegs (AOP (left), AOP (result)))
4761 size = AOP_SIZE (result);
4765 l = aopGet (AOP (left), offset, FALSE);
4766 aopPut (AOP (result), l, offset);
4771 size = AOP_SIZE (result);
4775 l = aopGet (AOP (left), offset, FALSE);
4776 aopPut (AOP (result), l, offset);
4782 tlbl = newiTempLabel (NULL);
4783 size = AOP_SIZE (result);
4785 tlbl1 = newiTempLabel (NULL);
4787 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4788 emitLabel (tlbl->key + 100);
4789 l = aopGet (AOP (result), offset, FALSE);
4795 l = aopGet (AOP (result), offset++, FALSE);
4798 emitLabel (tlbl1->key + 100);
4800 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4802 freeAsmop (left, NULL, ic);
4803 freeAsmop (result, NULL, ic);
4806 /*-----------------------------------------------------------------*/
4807 /* genrshOne - left shift two bytes by known amount != 0 */
4808 /*-----------------------------------------------------------------*/
4810 genrshOne (operand * result, operand * left, int shCount, int is_signed)
4813 int size = AOP_SIZE (result);
4816 wassert (size == 1);
4817 wassert (shCount < 8);
4819 l = aopGet (AOP (left), 0, FALSE);
4823 if (AOP (result)->type == AOP_REG)
4825 aopPut (AOP (result), l, 0);
4826 l = aopGet (AOP (result), 0, FALSE);
4829 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
4837 emit2 ("%s a", is_signed ? "sra" : "srl");
4839 aopPut (AOP (result), "a", 0);
4843 /*-----------------------------------------------------------------*/
4844 /* AccRsh - right shift accumulator by known count */
4845 /*-----------------------------------------------------------------*/
4847 AccRsh (int shCount)
4849 static const unsigned char SRMask[] =
4851 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
4856 /* rotate right accumulator */
4857 AccRol (8 - shCount);
4858 /* and kill the higher order bits */
4859 emit2 ("and a,!immedbyte", SRMask[shCount]);
4863 /*-----------------------------------------------------------------*/
4864 /* shiftR1Left2Result - shift right one byte from left to result */
4865 /*-----------------------------------------------------------------*/
4867 shiftR1Left2Result (operand * left, int offl,
4868 operand * result, int offr,
4869 int shCount, int sign)
4871 _moveA (aopGet (AOP (left), offl, FALSE));
4880 aopPut (AOP (result), "a", offr);
4883 /*-----------------------------------------------------------------*/
4884 /* genrshTwo - right shift two bytes by known amount != 0 */
4885 /*-----------------------------------------------------------------*/
4887 genrshTwo (operand * result, operand * left,
4888 int shCount, int sign)
4890 /* if shCount >= 8 */
4896 shiftR1Left2Result (left, MSB16, result, LSB,
4901 movLeft2Result (left, MSB16, result, LSB, sign);
4903 aopPut (AOP (result), "!zero", 1);
4905 /* 1 <= shCount <= 7 */
4908 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
4912 /*-----------------------------------------------------------------*/
4913 /* genRightShiftLiteral - left shifting by known count */
4914 /*-----------------------------------------------------------------*/
4916 genRightShiftLiteral (operand * left,
4922 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
4925 freeAsmop (right, NULL, ic);
4927 aopOp (left, ic, FALSE, FALSE);
4928 aopOp (result, ic, FALSE, FALSE);
4930 size = getSize (operandType (result));
4932 emitDebug ("; shift right result %d, left %d", size,
4935 /* I suppose that the left size >= result size */
4941 else if (shCount >= (size * 8))
4943 aopPut (AOP (result), "!zero", size);
4949 genrshOne (result, left, shCount, sign);
4952 /* PENDING: sign support */
4953 genrshTwo (result, left, shCount, sign);
4956 wassertl (0, "Asked to shift right a long which should be a function call");
4959 wassertl (0, "Entered default case in right shift delegate");
4962 freeAsmop (left, NULL, ic);
4963 freeAsmop (result, NULL, ic);
4966 /*-----------------------------------------------------------------*/
4967 /* genRightShift - generate code for right shifting */
4968 /*-----------------------------------------------------------------*/
4970 genRightShift (iCode * ic)
4972 operand *right, *left, *result;
4974 int size, offset, first = 1;
4978 symbol *tlbl, *tlbl1;
4980 /* if signed then we do it the hard way preserve the
4981 sign bit moving it inwards */
4982 retype = getSpec (operandType (IC_RESULT (ic)));
4984 is_signed = !SPEC_USIGN (retype);
4986 /* signed & unsigned types are treated the same : i.e. the
4987 signed is NOT propagated inwards : quoting from the
4988 ANSI - standard : "for E1 >> E2, is equivalent to division
4989 by 2**E2 if unsigned or if it has a non-negative value,
4990 otherwise the result is implementation defined ", MY definition
4991 is that the sign does not get propagated */
4993 right = IC_RIGHT (ic);
4994 left = IC_LEFT (ic);
4995 result = IC_RESULT (ic);
4997 aopOp (right, ic, FALSE, FALSE);
4999 /* if the shift count is known then do it
5000 as efficiently as possible */
5001 if (AOP_TYPE (right) == AOP_LIT)
5003 genRightShiftLiteral (left, right, result, ic, is_signed);
5007 aopOp (left, ic, FALSE, FALSE);
5008 aopOp (result, ic, FALSE, FALSE);
5010 /* now move the left to the result if they are not the
5012 if (!sameRegs (AOP (left), AOP (result)) &&
5013 AOP_SIZE (result) > 1)
5016 size = AOP_SIZE (result);
5020 l = aopGet (AOP (left), offset, FALSE);
5021 aopPut (AOP (result), l, offset);
5026 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5028 freeAsmop (right, NULL, ic);
5030 tlbl = newiTempLabel (NULL);
5031 tlbl1 = newiTempLabel (NULL);
5032 size = AOP_SIZE (result);
5035 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5036 emitLabel (tlbl->key + 100);
5039 l = aopGet (AOP (result), offset--, FALSE);
5042 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5050 emitLabel (tlbl1->key + 100);
5052 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5054 freeAsmop (left, NULL, ic);
5055 freeAsmop (result, NULL, ic);
5058 /*-----------------------------------------------------------------*/
5059 /* genGenPointerGet - get value from generic pointer space */
5060 /*-----------------------------------------------------------------*/
5062 genGenPointerGet (operand * left,
5063 operand * result, iCode * ic)
5066 sym_link *retype = getSpec (operandType (result));
5072 aopOp (left, ic, FALSE, FALSE);
5073 aopOp (result, ic, FALSE, FALSE);
5075 if (isPair (AOP (left)) && AOP_SIZE (result) == 1)
5078 if (isPtrPair (AOP (left)))
5080 tsprintf (buffer, "!*pair", getPairName (AOP (left)));
5081 aopPut (AOP (result), buffer, 0);
5085 emit2 ("ld a,!*pair", getPairName (AOP (left)));
5086 aopPut (AOP (result), "a", 0);
5088 freeAsmop (left, NULL, ic);
5092 /* For now we always load into IY */
5093 /* if this is remateriazable */
5094 fetchPair (pair, AOP (left));
5096 /* so iy now contains the address */
5097 freeAsmop (left, NULL, ic);
5099 /* if bit then unpack */
5100 if (IS_BITVAR (retype))
5106 size = AOP_SIZE (result);
5111 /* PENDING: make this better */
5112 if (!IS_GB && AOP (result)->type == AOP_REG)
5114 aopPut (AOP (result), "!*hl", offset++);
5118 emit2 ("ld a,!*pair", _pairs[pair].name);
5119 aopPut (AOP (result), "a", offset++);
5123 emit2 ("inc %s", _pairs[pair].name);
5124 _G.pairs[pair].offset++;
5130 freeAsmop (result, NULL, ic);
5133 /*-----------------------------------------------------------------*/
5134 /* genPointerGet - generate code for pointer get */
5135 /*-----------------------------------------------------------------*/
5137 genPointerGet (iCode * ic)
5139 operand *left, *result;
5140 sym_link *type, *etype;
5142 left = IC_LEFT (ic);
5143 result = IC_RESULT (ic);
5145 /* depending on the type of pointer we need to
5146 move it to the correct pointer register */
5147 type = operandType (left);
5148 etype = getSpec (type);
5150 genGenPointerGet (left, result, ic);
5154 isRegOrLit (asmop * aop)
5156 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
5161 /*-----------------------------------------------------------------*/
5162 /* genGenPointerSet - stores the value into a pointer location */
5163 /*-----------------------------------------------------------------*/
5165 genGenPointerSet (operand * right,
5166 operand * result, iCode * ic)
5169 sym_link *retype = getSpec (operandType (right));
5170 PAIR_ID pairId = PAIR_HL;
5172 aopOp (result, ic, FALSE, FALSE);
5173 aopOp (right, ic, FALSE, FALSE);
5178 /* Handle the exceptions first */
5179 if (isPair (AOP (result)) && (AOP_SIZE (right) == 1))
5182 const char *l = aopGet (AOP (right), 0, FALSE);
5183 const char *pair = getPairName (AOP (result));
5184 if (canAssignToPtr (l) && isPtr (pair))
5186 emit2 ("ld !*pair,%s", pair, l);
5191 emit2 ("ld !*pair,a", pair);
5196 /* if the operand is already in dptr
5197 then we do nothing else we move the value to dptr */
5198 if (AOP_TYPE (result) != AOP_STR)
5200 fetchPair (pairId, AOP (result));
5202 /* so hl know contains the address */
5203 freeAsmop (result, NULL, ic);
5205 /* if bit then unpack */
5206 if (IS_BITVAR (retype))
5212 size = AOP_SIZE (right);
5217 const char *l = aopGet (AOP (right), offset, FALSE);
5218 if (isRegOrLit (AOP (right)) && !IS_GB)
5220 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
5225 emit2 ("ld !*pair,a", _pairs[pairId].name);
5229 emit2 ("inc %s", _pairs[pairId].name);
5230 _G.pairs[pairId].offset++;
5236 freeAsmop (right, NULL, ic);
5239 /*-----------------------------------------------------------------*/
5240 /* genPointerSet - stores the value into a pointer location */
5241 /*-----------------------------------------------------------------*/
5243 genPointerSet (iCode * ic)
5245 operand *right, *result;
5246 sym_link *type, *etype;
5248 right = IC_RIGHT (ic);
5249 result = IC_RESULT (ic);
5251 /* depending on the type of pointer we need to
5252 move it to the correct pointer register */
5253 type = operandType (result);
5254 etype = getSpec (type);
5256 genGenPointerSet (right, result, ic);
5259 /*-----------------------------------------------------------------*/
5260 /* genIfx - generate code for Ifx statement */
5261 /*-----------------------------------------------------------------*/
5263 genIfx (iCode * ic, iCode * popIc)
5265 operand *cond = IC_COND (ic);
5268 aopOp (cond, ic, FALSE, TRUE);
5270 /* get the value into acc */
5271 if (AOP_TYPE (cond) != AOP_CRY)
5275 /* the result is now in the accumulator */
5276 freeAsmop (cond, NULL, ic);
5278 /* if there was something to be popped then do it */
5282 /* if the condition is a bit variable */
5283 if (isbit && IS_ITEMP (cond) &&
5285 genIfxJump (ic, SPIL_LOC (cond)->rname);
5286 else if (isbit && !IS_ITEMP (cond))
5287 genIfxJump (ic, OP_SYMBOL (cond)->rname);
5289 genIfxJump (ic, "a");
5294 /*-----------------------------------------------------------------*/
5295 /* genAddrOf - generates code for address of */
5296 /*-----------------------------------------------------------------*/
5298 genAddrOf (iCode * ic)
5300 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
5302 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
5304 /* if the operand is on the stack then we
5305 need to get the stack offset of this
5312 if (sym->stack <= 0)
5314 emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset);
5318 emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
5325 emit2 ("ld de,!hashedstr", sym->rname);
5327 aopPut (AOP (IC_RESULT (ic)), "e", 0);
5328 aopPut (AOP (IC_RESULT (ic)), "d", 1);
5335 /* if it has an offset then we need to compute it */
5337 emit2 ("ld hl,#%d+%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset, _G.stack.param_offset);
5339 emit2 ("ld hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
5340 emit2 ("add hl,sp");
5344 emit2 ("ld hl,#%s", sym->rname);
5346 aopPut (AOP (IC_RESULT (ic)), "l", 0);
5347 aopPut (AOP (IC_RESULT (ic)), "h", 1);
5349 freeAsmop (IC_RESULT (ic), NULL, ic);
5352 /*-----------------------------------------------------------------*/
5353 /* genAssign - generate code for assignment */
5354 /*-----------------------------------------------------------------*/
5356 genAssign (iCode * ic)
5358 operand *result, *right;
5360 unsigned long lit = 0L;
5362 result = IC_RESULT (ic);
5363 right = IC_RIGHT (ic);
5366 /* Dont bother assigning if they are the same */
5367 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5369 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
5374 aopOp (right, ic, FALSE, FALSE);
5375 aopOp (result, ic, TRUE, FALSE);
5377 /* if they are the same registers */
5378 if (sameRegs (AOP (right), AOP (result)))
5380 emitDebug ("; (registers are the same)");
5384 /* if the result is a bit */
5385 if (AOP_TYPE (result) == AOP_CRY)
5391 size = AOP_SIZE (result);
5394 if (AOP_TYPE (right) == AOP_LIT)
5395 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5396 if (isPair (AOP (result)))
5398 fetchPair (getPairId (AOP (result)), AOP (right));
5400 else if ((size > 1) &&
5401 (AOP_TYPE (result) != AOP_REG) &&
5402 (AOP_TYPE (right) == AOP_LIT) &&
5403 !IS_FLOAT (operandType (right)) &&
5406 bool fXored = FALSE;
5408 /* Work from the top down.
5409 Done this way so that we can use the cached copy of 0
5410 in A for a fast clear */
5413 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
5415 if (!fXored && size > 1)
5422 aopPut (AOP (result), "a", offset);
5426 aopPut (AOP (result), "!zero", offset);
5430 aopPut (AOP (result),
5431 aopGet (AOP (right), offset, FALSE),
5436 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
5438 /* Special case. Load into a and d, then load out. */
5439 _moveA (aopGet (AOP (right), 0, FALSE));
5440 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
5441 aopPut (AOP (result), "a", 0);
5442 aopPut (AOP (result), "e", 1);
5448 /* PENDING: do this check better */
5449 if (requiresHL (AOP (right)) && requiresHL (AOP (result)))
5451 _moveA (aopGet (AOP (right), offset, FALSE));
5452 aopPut (AOP (result), "a", offset);
5455 aopPut (AOP (result),
5456 aopGet (AOP (right), offset, FALSE),
5463 freeAsmop (right, NULL, ic);
5464 freeAsmop (result, NULL, ic);
5467 /*-----------------------------------------------------------------*/
5468 /* genJumpTab - genrates code for jump table */
5469 /*-----------------------------------------------------------------*/
5471 genJumpTab (iCode * ic)
5476 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
5477 /* get the condition into accumulator */
5478 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
5481 emit2 ("ld e,%s", l);
5482 emit2 ("ld d,!zero");
5483 jtab = newiTempLabel (NULL);
5485 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
5486 emit2 ("add hl,de");
5487 emit2 ("add hl,de");
5488 emit2 ("add hl,de");
5489 freeAsmop (IC_JTCOND (ic), NULL, ic);
5493 emitLabel (jtab->key + 100);
5494 /* now generate the jump labels */
5495 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
5496 jtab = setNextItem (IC_JTLABELS (ic)))
5497 emit2 ("jp !tlabel", jtab->key + 100);
5500 /*-----------------------------------------------------------------*/
5501 /* genCast - gen code for casting */
5502 /*-----------------------------------------------------------------*/
5504 genCast (iCode * ic)
5506 operand *result = IC_RESULT (ic);
5507 sym_link *ctype = operandType (IC_LEFT (ic));
5508 operand *right = IC_RIGHT (ic);
5511 /* if they are equivalent then do nothing */
5512 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5515 aopOp (right, ic, FALSE, FALSE);
5516 aopOp (result, ic, FALSE, FALSE);
5518 /* if the result is a bit */
5519 if (AOP_TYPE (result) == AOP_CRY)
5524 /* if they are the same size : or less */
5525 if (AOP_SIZE (result) <= AOP_SIZE (right))
5528 /* if they are in the same place */
5529 if (sameRegs (AOP (right), AOP (result)))
5532 /* if they in different places then copy */
5533 size = AOP_SIZE (result);
5537 aopPut (AOP (result),
5538 aopGet (AOP (right), offset, FALSE),
5545 /* PENDING: should be OK. */
5547 /* if the result is of type pointer */
5554 /* so we now know that the size of destination is greater
5555 than the size of the source */
5556 /* we move to result for the size of source */
5557 size = AOP_SIZE (right);
5561 aopPut (AOP (result),
5562 aopGet (AOP (right), offset, FALSE),
5567 /* now depending on the sign of the destination */
5568 size = AOP_SIZE (result) - AOP_SIZE (right);
5569 /* Unsigned or not an integral type - right fill with zeros */
5570 if (SPEC_USIGN (ctype) || !IS_SPEC (ctype))
5573 aopPut (AOP (result), "!zero", offset++);
5577 /* we need to extend the sign :{ */
5578 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
5581 emitDebug ("; genCast: sign extend untested.");
5585 aopPut (AOP (result), "a", offset++);
5589 freeAsmop (right, NULL, ic);
5590 freeAsmop (result, NULL, ic);
5593 /*-----------------------------------------------------------------*/
5594 /* genReceive - generate code for a receive iCode */
5595 /*-----------------------------------------------------------------*/
5597 genReceive (iCode * ic)
5599 if (isOperandInFarSpace (IC_RESULT (ic)) &&
5600 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
5601 IS_TRUE_SYMOP (IC_RESULT (ic))))
5611 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
5612 size = AOP_SIZE(IC_RESULT(ic));
5614 for (i = 0; i < size; i++) {
5615 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
5619 freeAsmop (IC_RESULT (ic), NULL, ic);
5624 /** Maximum number of bytes to emit per line. */
5628 /** Context for the byte output chunker. */
5631 unsigned char buffer[DBEMIT_MAX_RUN];
5636 /** Flushes a byte chunker by writing out all in the buffer and
5640 _dbFlush(DBEMITCTX *self)
5647 sprintf(line, ".db 0x%02X", self->buffer[0]);
5649 for (i = 1; i < self->pos; i++)
5651 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
5658 /** Write out another byte, buffering until a decent line is
5662 _dbEmit(DBEMITCTX *self, int c)
5664 if (self->pos == DBEMIT_MAX_RUN)
5668 self->buffer[self->pos++] = c;
5671 /** Context for a simple run length encoder. */
5675 unsigned char buffer[128];
5677 /** runLen may be equivalent to pos. */
5683 RLE_CHANGE_COST = 4,
5687 /** Flush the buffer of a run length encoder by writing out the run or
5688 data that it currently contains.
5691 _rleCommit(RLECTX *self)
5697 memset(&db, 0, sizeof(db));
5699 emit2(".db %u", self->pos);
5701 for (i = 0; i < self->pos; i++)
5703 _dbEmit(&db, self->buffer[i]);
5712 Can get either a run or a block of random stuff.
5713 Only want to change state if a good run comes in or a run ends.
5714 Detecting run end is easy.
5717 Say initial state is in run, len zero, last zero. Then if you get a
5718 few zeros then something else then a short run will be output.
5719 Seems OK. While in run mode, keep counting. While in random mode,
5720 keep a count of the run. If run hits margin, output all up to run,
5721 restart, enter run mode.
5724 /** Add another byte into the run length encoder, flushing as
5725 required. The run length encoder uses the Amiga IFF style, where
5726 a block is prefixed by its run length. A positive length means
5727 the next n bytes pass straight through. A negative length means
5728 that the next byte is repeated -n times. A zero terminates the
5732 _rleAppend(RLECTX *self, int c)
5736 if (c != self->last)
5738 /* The run has stopped. See if it is worthwhile writing it out
5739 as a run. Note that the random data comes in as runs of
5742 if (self->runLen > RLE_CHANGE_COST)
5744 /* Yes, worthwhile. */
5745 /* Commit whatever was in the buffer. */
5747 emit2(".db -%u,0x%02X", self->runLen, self->last);
5751 /* Not worthwhile. Append to the end of the random list. */
5752 for (i = 0; i < self->runLen; i++)
5754 if (self->pos >= RLE_MAX_BLOCK)
5759 self->buffer[self->pos++] = self->last;
5767 if (self->runLen >= RLE_MAX_BLOCK)
5769 /* Commit whatever was in the buffer. */
5772 emit2 (".db -%u,0x%02X", self->runLen, self->last);
5780 _rleFlush(RLECTX *self)
5782 _rleAppend(self, -1);
5789 /** genArrayInit - Special code for initialising an array with constant
5793 genArrayInit (iCode * ic)
5797 int elementSize = 0, eIndex, i;
5798 unsigned val, lastVal;
5802 memset(&rle, 0, sizeof(rle));
5804 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
5806 if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD)
5808 /* Emit the support function call and the destination address. */
5809 emit2("call __initrleblock");
5810 emit2(".dw %s", aopGetWord (AOP(IC_LEFT(ic)), 0));
5814 wassertl (0, "Unexpected operand to genArrayInit.\n");
5817 type = operandType(IC_LEFT(ic));
5819 if (type && type->next)
5821 elementSize = getSize(type->next);
5825 wassertl (0, "Can't determine element size in genArrayInit.");
5828 iLoop = IC_ARRAYILIST(ic);
5829 lastVal = (unsigned)-1;
5831 /* Feed all the bytes into the run length encoder which will handle
5833 This works well for mixed char data, and for random int and long
5842 for (i = 0; i < ix; i++)
5844 for (eIndex = 0; eIndex < elementSize; eIndex++)
5846 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
5847 _rleAppend(&rle, val);
5852 iLoop = iLoop->next;
5856 /* Mark the end of the run. */
5859 freeAsmop (IC_LEFT(ic), NULL, ic);
5862 /*-----------------------------------------------------------------*/
5863 /* genZ80Code - generate code for Z80 based controllers */
5864 /*-----------------------------------------------------------------*/
5866 genZ80Code (iCode * lic)
5874 _fReturn = _gbz80_return;
5875 _fTmp = _gbz80_return;
5879 _fReturn = _z80_return;
5880 _fTmp = _z80_return;
5883 _G.lines.head = _G.lines.current = NULL;
5885 for (ic = lic; ic; ic = ic->next)
5888 if (cln != ic->lineno)
5890 emit2 ("; %s %d", ic->filename, ic->lineno);
5893 /* if the result is marked as
5894 spilt and rematerializable or code for
5895 this has already been generated then
5897 if (resultRemat (ic) || ic->generated)
5900 /* depending on the operation */
5904 emitDebug ("; genNot");
5909 emitDebug ("; genCpl");
5914 emitDebug ("; genUminus");
5919 emitDebug ("; genIpush");
5924 /* IPOP happens only when trying to restore a
5925 spilt live range, if there is an ifx statement
5926 following this pop then the if statement might
5927 be using some of the registers being popped which
5928 would destory the contents of the register so
5929 we need to check for this condition and handle it */
5931 ic->next->op == IFX &&
5932 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
5934 emitDebug ("; genIfx");
5935 genIfx (ic->next, ic);
5939 emitDebug ("; genIpop");
5945 emitDebug ("; genCall");
5950 emitDebug ("; genPcall");
5955 emitDebug ("; genFunction");
5960 emitDebug ("; genEndFunction");
5961 genEndFunction (ic);
5965 emitDebug ("; genRet");
5970 emitDebug ("; genLabel");
5975 emitDebug ("; genGoto");
5980 emitDebug ("; genPlus");
5985 emitDebug ("; genMinus");
5990 emitDebug ("; genMult");
5995 emitDebug ("; genDiv");
6000 emitDebug ("; genMod");
6005 emitDebug ("; genCmpGt");
6006 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
6010 emitDebug ("; genCmpLt");
6011 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
6018 /* note these two are xlated by algebraic equivalence
6019 during parsing SDCC.y */
6020 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
6021 "got '>=' or '<=' shouldn't have come here");
6025 emitDebug ("; genCmpEq");
6026 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
6030 emitDebug ("; genAndOp");
6035 emitDebug ("; genOrOp");
6040 emitDebug ("; genXor");
6041 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
6045 emitDebug ("; genOr");
6046 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
6050 emitDebug ("; genAnd");
6051 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
6055 emitDebug ("; genInline");
6060 emitDebug ("; genRRC");
6065 emitDebug ("; genRLC");
6070 emitDebug ("; genGetHBIT");
6075 emitDebug ("; genLeftShift");
6080 emitDebug ("; genRightShift");
6084 case GET_VALUE_AT_ADDRESS:
6085 emitDebug ("; genPointerGet");
6091 if (POINTER_SET (ic))
6093 emitDebug ("; genAssign (pointer)");
6098 emitDebug ("; genAssign");
6104 emitDebug ("; genIfx");
6109 emitDebug ("; genAddrOf");
6114 emitDebug ("; genJumpTab");
6119 emitDebug ("; genCast");
6124 emitDebug ("; genReceive");
6129 emitDebug ("; addSet");
6130 addSet (&_G.sendSet, ic);
6139 /* piCode(ic,stdout); */
6145 /* now we are ready to call the
6146 peep hole optimizer */
6147 if (!options.nopeep)
6148 peepHole (&_G.lines.head);
6150 /* This is unfortunate */
6151 /* now do the actual printing */
6153 FILE *fp = codeOutFile;
6154 if (isInHome () && codeOutFile == code->oFile)
6155 codeOutFile = home->oFile;
6156 printLine (_G.lines.head, codeOutFile);
6157 if (_G.flushStatics)
6160 _G.flushStatics = 0;
6169 _isPairUsed (iCode * ic, PAIR_ID pairId)
6175 if (bitVectBitValue (ic->rMask, D_IDX))
6177 if (bitVectBitValue (ic->rMask, E_IDX))
6187 fetchLitSpecial (asmop * aop, bool negate, bool xor)
6190 value *val = aop->aopu.aop_lit;
6192 wassert (aop->type == AOP_LIT);
6193 wassert (!IS_FLOAT (val->type));
6195 v = (unsigned long) floatFromVal (val);
6203 tsprintf (buffer, "!immedword", v);
6204 return gc_strdup (buffer);