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 _push (PAIR_ID pairId)
488 emit2 ("push %s", _pairs[pairId].name);
489 _G.stack.pushed += 2;
493 _pop (PAIR_ID pairId)
495 emit2 ("pop %s", _pairs[pairId].name);
496 _G.stack.pushed -= 2;
499 /*-----------------------------------------------------------------*/
500 /* newAsmop - creates a new asmOp */
501 /*-----------------------------------------------------------------*/
503 newAsmop (short type)
507 aop = Safe_calloc (1, sizeof (asmop));
512 /*-----------------------------------------------------------------*/
513 /* aopForSym - for a true symbol */
514 /*-----------------------------------------------------------------*/
516 aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
523 wassert (sym->etype);
525 space = SPEC_OCLS (sym->etype);
527 /* if already has one */
531 /* Assign depending on the storage class */
532 if (sym->onStack || sym->iaccess)
534 emitDebug ("; AOP_STK for %s", sym->rname);
535 sym->aop = aop = newAsmop (AOP_STK);
536 aop->size = getSize (sym->type);
537 aop->aopu.aop_stk = sym->stack;
541 /* special case for a function */
542 if (IS_FUNC (sym->type))
544 sym->aop = aop = newAsmop (AOP_IMMD);
545 aop->aopu.aop_immd = Safe_calloc (1, strlen (sym->rname) + 1);
546 strcpy (aop->aopu.aop_immd, sym->rname);
553 /* if it is in direct space */
554 if (IN_REGSP (space) && !requires_a)
556 sym->aop = aop = newAsmop (AOP_SFR);
557 aop->aopu.aop_dir = sym->rname;
558 aop->size = getSize (sym->type);
559 emitDebug ("; AOP_SFR for %s", sym->rname);
564 /* only remaining is far space */
565 /* in which case DPTR gets the address */
568 emitDebug ("; AOP_HL for %s", sym->rname);
569 sym->aop = aop = newAsmop (AOP_HL);
573 sym->aop = aop = newAsmop (AOP_IY);
575 aop->size = getSize (sym->type);
576 aop->aopu.aop_dir = sym->rname;
578 /* if it is in code space */
579 if (IN_CODESPACE (space))
585 /*-----------------------------------------------------------------*/
586 /* aopForRemat - rematerialzes an object */
587 /*-----------------------------------------------------------------*/
589 aopForRemat (symbol * sym)
592 iCode *ic = sym->rematiCode;
593 asmop *aop = newAsmop (AOP_IMMD);
597 /* if plus or minus print the right hand side */
598 if (ic->op == '+' || ic->op == '-')
600 /* PENDING: for re-target */
601 sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
604 ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
607 /* we reached the end */
608 sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
612 aop->aopu.aop_immd = Safe_calloc (1, strlen (buffer) + 1);
613 strcpy (aop->aopu.aop_immd, buffer);
617 /*-----------------------------------------------------------------*/
618 /* regsInCommon - two operands have some registers in common */
619 /*-----------------------------------------------------------------*/
621 regsInCommon (operand * op1, operand * op2)
626 /* if they have registers in common */
627 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
630 sym1 = OP_SYMBOL (op1);
631 sym2 = OP_SYMBOL (op2);
633 if (sym1->nRegs == 0 || sym2->nRegs == 0)
636 for (i = 0; i < sym1->nRegs; i++)
642 for (j = 0; j < sym2->nRegs; j++)
647 if (sym2->regs[j] == sym1->regs[i])
655 /*-----------------------------------------------------------------*/
656 /* operandsEqu - equivalent */
657 /*-----------------------------------------------------------------*/
659 operandsEqu (operand * op1, operand * op2)
663 /* if they not symbols */
664 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
667 sym1 = OP_SYMBOL (op1);
668 sym2 = OP_SYMBOL (op2);
670 /* if both are itemps & one is spilt
671 and the other is not then false */
672 if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
673 sym1->isspilt != sym2->isspilt)
676 /* if they are the same */
680 if (strcmp (sym1->rname, sym2->rname) == 0)
684 /* if left is a tmp & right is not */
685 if (IS_ITEMP (op1) &&
688 (sym1->usl.spillLoc == sym2))
691 if (IS_ITEMP (op2) &&
695 (sym2->usl.spillLoc == sym1))
701 /*-----------------------------------------------------------------*/
702 /* sameRegs - two asmops have the same registers */
703 /*-----------------------------------------------------------------*/
705 sameRegs (asmop * aop1, asmop * aop2)
709 if (aop1->type == AOP_SFR ||
710 aop2->type == AOP_SFR)
716 if (aop1->type != AOP_REG ||
717 aop2->type != AOP_REG)
720 if (aop1->size != aop2->size)
723 for (i = 0; i < aop1->size; i++)
724 if (aop1->aopu.aop_reg[i] !=
725 aop2->aopu.aop_reg[i])
731 /*-----------------------------------------------------------------*/
732 /* aopOp - allocates an asmop for an operand : */
733 /*-----------------------------------------------------------------*/
735 aopOp (operand * op, iCode * ic, bool result, bool requires_a)
744 /* if this a literal */
745 if (IS_OP_LITERAL (op))
747 op->aop = aop = newAsmop (AOP_LIT);
748 aop->aopu.aop_lit = op->operand.valOperand;
749 aop->size = getSize (operandType (op));
753 /* if already has a asmop then continue */
757 /* if the underlying symbol has a aop */
758 if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
760 op->aop = OP_SYMBOL (op)->aop;
764 /* if this is a true symbol */
765 if (IS_TRUE_SYMOP (op))
767 op->aop = aopForSym (ic, OP_SYMBOL (op), result, requires_a);
771 /* this is a temporary : this has
777 e) can be a return use only */
779 sym = OP_SYMBOL (op);
781 /* if the type is a conditional */
782 if (sym->regType == REG_CND)
784 aop = op->aop = sym->aop = newAsmop (AOP_CRY);
789 /* if it is spilt then two situations
791 b) has a spill location */
792 if (sym->isspilt || sym->nRegs == 0)
794 /* rematerialize it NOW */
797 sym->aop = op->aop = aop =
799 aop->size = getSize (sym->type);
805 if (sym->accuse == ACCUSE_A)
807 aop = op->aop = sym->aop = newAsmop (AOP_ACC);
808 aop->size = getSize (sym->type);
809 wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
811 aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
813 else if (sym->accuse == ACCUSE_HL)
816 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
817 aop->size = getSize (sym->type);
818 wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
819 aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
820 aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
832 aop = op->aop = sym->aop = newAsmop (AOP_STR);
833 aop->size = getSize (sym->type);
834 for (i = 0; i < 4; i++)
835 aop->aopu.aop_str[i] = _fReturn[i];
839 /* else spill location */
840 sym->aop = op->aop = aop =
841 aopForSym (ic, sym->usl.spillLoc, result, requires_a);
842 aop->size = getSize (sym->type);
846 /* must be in a register */
847 sym->aop = op->aop = aop = newAsmop (AOP_REG);
848 aop->size = sym->nRegs;
849 for (i = 0; i < sym->nRegs; i++)
850 aop->aopu.aop_reg[i] = sym->regs[i];
853 /*-----------------------------------------------------------------*/
854 /* freeAsmop - free up the asmop given to an operand */
855 /*----------------------------------------------------------------*/
857 freeAsmop (operand * op, asmop * aaop, iCode * ic)
875 /* all other cases just dealloc */
881 OP_SYMBOL (op)->aop = NULL;
882 /* if the symbol has a spill */
884 SPIL_LOC (op)->aop = NULL;
890 isLitWord (asmop * aop)
892 /* if (aop->size != 2)
905 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
910 /* depending on type */
916 /* PENDING: for re-target */
919 tsprintf (s, "!hashedstr + %d", aop->aopu.aop_immd, offset);
921 else if (offset == 0)
923 tsprintf (s, "%s", aop->aopu.aop_immd);
927 tsprintf (s, "%s + %d", aop->aopu.aop_immd, offset);
933 value *val = aop->aopu.aop_lit;
934 /* if it is a float then it gets tricky */
935 /* otherwise it is fairly simple */
936 if (!IS_FLOAT (val->type))
938 unsigned long v = (unsigned long) floatFromVal (val);
944 else if (offset == 0)
950 wassertl(0, "Encountered an invalid offset while fetching a literal");
954 tsprintf (buffer, "!immedword", v);
956 tsprintf (buffer, "!constword", v);
958 return gc_strdup(buffer);
964 convertFloat (&f, floatFromVal (val));
966 tsprintf (buffer, "!immedword", f.w[offset / 2]);
968 tsprintf (buffer, "!constword", f.w[offset / 2]);
969 rs = Safe_calloc (1, strlen (buffer) + 1);
970 return strcpy (rs, buffer);
979 aopGetWord (asmop * aop, int offset)
981 return aopGetLitWordLong (aop, offset, TRUE);
985 isPtr (const char *s)
987 if (!strcmp (s, "hl"))
989 if (!strcmp (s, "ix"))
991 if (!strcmp (s, "iy"))
997 adjustPair (const char *pair, int *pold, int new)
1003 emit2 ("inc %s", pair);
1008 emit2 ("dec %s", pair);
1014 spillPair (PAIR_ID pairId)
1016 _G.pairs[pairId].last_type = AOP_INVALID;
1017 _G.pairs[pairId].base = NULL;
1023 spillPair (PAIR_HL);
1024 spillPair (PAIR_IY);
1028 requiresHL (asmop * aop)
1042 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1044 const char *l, *base;
1045 const char *pair = _pairs[pairId].name;
1046 l = aopGetLitWordLong (left, offset, FALSE);
1047 base = aopGetLitWordLong (left, 0, FALSE);
1048 wassert (l && pair && base);
1052 if (pairId == PAIR_HL || pairId == PAIR_IY)
1054 if (_G.pairs[pairId].last_type == left->type)
1056 if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1058 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1060 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1063 if (pairId == PAIR_IY && abs (offset) < 127)
1070 _G.pairs[pairId].last_type = left->type;
1071 _G.pairs[pairId].base = gc_strdup (base);
1072 _G.pairs[pairId].offset = offset;
1074 /* Both a lit on the right and a true symbol on the left */
1075 emit2 ("ld %s,!hashedstr", pair, l);
1079 fetchPairLong (PAIR_ID pairId, asmop * aop, int offset)
1081 /* if this is remateriazable */
1082 if (isLitWord (aop)) {
1083 fetchLitPair (pairId, aop, offset);
1086 /* we need to get it byte by byte */
1087 if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1088 aopGet (aop, offset, FALSE);
1089 switch (aop->size - offset) {
1091 emit2 ("ld l,!*hl");
1092 emit2 ("ld h,!immedbyte", 0);
1095 // PENDING: Requires that you are only fetching two bytes.
1098 emit2 ("ld h,!*hl");
1102 wassertl (0, "Attempted to fetch too much data into HL");
1106 else if (IS_Z80 && aop->type == AOP_IY) {
1107 /* Instead of fetching relative to IY, just grab directly
1108 from the address IY refers to */
1109 char *l = aopGetLitWordLong (aop, offset, FALSE);
1111 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1113 if (aop->size < 2) {
1114 emit2("ld %s,!zero", _pairs[pairId].h);
1118 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1119 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1121 /* PENDING: check? */
1122 if (pairId == PAIR_HL)
1123 spillPair (PAIR_HL);
1128 fetchPair (PAIR_ID pairId, asmop * aop)
1130 fetchPairLong (pairId, aop, 0);
1134 fetchHL (asmop * aop)
1136 fetchPair (PAIR_HL, aop);
1140 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1142 assert (pairId == PAIR_HL || pairId == PAIR_IY);
1147 fetchLitPair (pairId, aop, 0);
1150 fetchLitPair (pairId, aop, offset);
1151 _G.pairs[pairId].offset = offset;
1155 /* Doesnt include _G.stack.pushed */
1156 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1157 if (aop->aopu.aop_stk > 0)
1159 abso += _G.stack.param_offset;
1161 assert (pairId == PAIR_HL);
1162 /* In some cases we can still inc or dec hl */
1163 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1165 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1169 emit2 ("!ldahlsp", abso + _G.stack.pushed);
1171 _G.pairs[pairId].offset = abso;
1177 _G.pairs[pairId].last_type = aop->type;
1183 emit2 ("!tlabeldef", key);
1187 /*-----------------------------------------------------------------*/
1188 /* aopGet - for fetching value of the aop */
1189 /*-----------------------------------------------------------------*/
1191 aopGet (asmop * aop, int offset, bool bit16)
1195 /* offset is greater than size then zero */
1196 /* PENDING: this seems a bit screwed in some pointer cases. */
1197 if (offset > (aop->size - 1) &&
1198 aop->type != AOP_LIT)
1200 tsprintf (s, "!zero");
1201 return gc_strdup(s);
1204 /* depending on type */
1208 /* PENDING: re-target */
1210 tsprintf (s, "!immedwords", aop->aopu.aop_immd);
1215 tsprintf (s, "!bankimmeds", aop->aopu.aop_immd);
1218 tsprintf (s, "!msbimmeds", aop->aopu.aop_immd);
1221 tsprintf (s, "!lsbimmeds", aop->aopu.aop_immd);
1227 return gc_strdup(s);
1231 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1234 return gc_strdup(s);
1238 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1241 return gc_strdup(s);
1244 return aop->aopu.aop_reg[offset]->name;
1248 setupPair (PAIR_HL, aop, offset);
1249 tsprintf (s, "!*hl");
1251 return gc_strdup (s);
1255 setupPair (PAIR_IY, aop, offset);
1256 tsprintf (s, "!*iyx", offset);
1258 return gc_strdup(s);
1263 setupPair (PAIR_HL, aop, offset);
1264 tsprintf (s, "!*hl");
1268 if (aop->aopu.aop_stk >= 0)
1269 offset += _G.stack.param_offset;
1270 tsprintf (s, "!*ixx", aop->aopu.aop_stk + offset);
1273 return gc_strdup(s);
1285 tsprintf(s, "!zero");
1286 return gc_strdup(s);
1290 wassert (offset < 2);
1291 return aop->aopu.aop_str[offset];
1294 return aopLiteral (aop->aopu.aop_lit, offset);
1298 unsigned long v = aop->aopu.aop_simplelit;
1301 tsprintf (s, "!immedbyte", (unsigned int) v & 0xff);
1303 return gc_strdup(s);
1307 return aop->aopu.aop_str[offset];
1312 wassertl (0, "aopget got unsupported aop->type");
1317 isRegString (const char *s)
1319 if (!strcmp (s, "b") ||
1331 isConstant (const char *s)
1333 /* This is a bit of a hack... */
1334 return (*s == '#' || *s == '$');
1338 canAssignToPtr (const char *s)
1340 if (isRegString (s))
1347 /*-----------------------------------------------------------------*/
1348 /* aopPut - puts a string for a aop */
1349 /*-----------------------------------------------------------------*/
1351 aopPut (asmop * aop, const char *s, int offset)
1355 if (aop->size && offset > (aop->size - 1))
1357 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1358 "aopPut got offset > aop->size");
1363 tsprintf(buffer2, s);
1366 /* will assign value to value */
1367 /* depending on where it is ofcourse */
1373 if (strcmp (s, "a"))
1374 emit2 ("ld a,%s", s);
1375 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1380 if (strcmp (s, "a"))
1381 emit2 ("ld a,%s", s);
1382 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1386 if (!strcmp (s, "!*hl"))
1387 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1390 aop->aopu.aop_reg[offset]->name, s);
1395 setupPair (PAIR_IY, aop, offset);
1396 if (!canAssignToPtr (s))
1398 emit2 ("ld a,%s", s);
1399 emit2 ("ld !*iyx,a", offset);
1402 emit2 ("ld !*iyx,%s", offset, s);
1407 /* PENDING: for re-target */
1408 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1410 emit2 ("ld a,!*hl");
1413 setupPair (PAIR_HL, aop, offset);
1415 emit2 ("ld !*hl,%s", s);
1421 /* PENDING: re-target */
1422 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1424 emit2 ("ld a,!*hl");
1427 setupPair (PAIR_HL, aop, offset);
1428 if (!canAssignToPtr (s))
1430 emit2 ("ld a,%s", s);
1431 emit2 ("ld !*hl,a");
1434 emit2 ("ld !*hl,%s", s);
1438 if (aop->aopu.aop_stk >= 0)
1439 offset += _G.stack.param_offset;
1440 if (!canAssignToPtr (s))
1442 emit2 ("ld a,%s", s);
1443 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
1446 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
1451 /* if bit variable */
1452 if (!aop->aopu.aop_dir)
1459 /* In bit space but not in C - cant happen */
1466 if (strcmp (aop->aopu.aop_str[offset], s))
1468 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1474 if (!offset && (strcmp (s, "acc") == 0))
1479 emitDebug ("; Error aopPut AOP_ACC");
1483 if (strcmp (aop->aopu.aop_str[offset], s))
1484 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1489 wassert (offset < 2);
1490 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1494 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1495 "aopPut got unsupported aop->type");
1500 #define AOP(op) op->aop
1501 #define AOP_TYPE(op) AOP(op)->type
1502 #define AOP_SIZE(op) AOP(op)->size
1503 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
1506 commitPair (asmop * aop, PAIR_ID id)
1508 if (id == PAIR_HL && requiresHL (aop))
1512 aopPut (aop, "a", 0);
1513 aopPut (aop, "d", 1);
1517 aopPut (aop, _pairs[id].l, 0);
1518 aopPut (aop, _pairs[id].h, 1);
1522 /*-----------------------------------------------------------------*/
1523 /* getDataSize - get the operand data size */
1524 /*-----------------------------------------------------------------*/
1526 getDataSize (operand * op)
1529 size = AOP_SIZE (op);
1538 /*-----------------------------------------------------------------*/
1539 /* movLeft2Result - move byte from left to result */
1540 /*-----------------------------------------------------------------*/
1542 movLeft2Result (operand * left, int offl,
1543 operand * result, int offr, int sign)
1546 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
1548 l = aopGet (AOP (left), offl, FALSE);
1552 aopPut (AOP (result), l, offr);
1562 /** Put Acc into a register set
1565 outAcc (operand * result)
1568 size = getDataSize (result);
1571 aopPut (AOP (result), "a", 0);
1574 /* unsigned or positive */
1577 aopPut (AOP (result), "!zero", offset++);
1582 /** Take the value in carry and put it into a register
1585 outBitCLong (operand * result, bool swap_sense)
1587 /* if the result is bit */
1588 if (AOP_TYPE (result) == AOP_CRY)
1590 emitDebug ("; Note: outBitC form 1");
1591 aopPut (AOP (result), "blah", 0);
1595 emit2 ("ld a,!zero");
1598 emit2 ("xor a,!immedbyte", 1);
1604 outBitC (operand * result)
1606 outBitCLong (result, FALSE);
1609 /*-----------------------------------------------------------------*/
1610 /* toBoolean - emit code for orl a,operator(sizeop) */
1611 /*-----------------------------------------------------------------*/
1613 _toBoolean (operand * oper)
1615 int size = AOP_SIZE (oper);
1619 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
1622 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
1626 if (AOP (oper)->type != AOP_ACC)
1629 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
1634 /*-----------------------------------------------------------------*/
1635 /* genNot - generate code for ! operation */
1636 /*-----------------------------------------------------------------*/
1640 sym_link *optype = operandType (IC_LEFT (ic));
1642 /* assign asmOps to operand & result */
1643 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
1644 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1646 /* if in bit space then a special case */
1647 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1652 /* if type float then do float */
1653 if (IS_FLOAT (optype))
1658 _toBoolean (IC_LEFT (ic));
1663 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
1664 emit2 ("sub a,!one");
1665 outBitC (IC_RESULT (ic));
1667 /* release the aops */
1668 freeAsmop (IC_LEFT (ic), NULL, ic);
1669 freeAsmop (IC_RESULT (ic), NULL, ic);
1672 /*-----------------------------------------------------------------*/
1673 /* genCpl - generate code for complement */
1674 /*-----------------------------------------------------------------*/
1682 /* assign asmOps to operand & result */
1683 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1684 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1686 /* if both are in bit space then
1688 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1689 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1694 size = AOP_SIZE (IC_RESULT (ic));
1697 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
1700 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1703 /* release the aops */
1704 freeAsmop (IC_LEFT (ic), NULL, ic);
1705 freeAsmop (IC_RESULT (ic), NULL, ic);
1709 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
1716 store de into result
1721 store de into result
1723 const char *first = isAdd ? "add" : "sub";
1724 const char *later = isAdd ? "adc" : "sbc";
1726 wassertl (IS_GB, "Code is only relevent to the gbz80");
1727 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
1729 fetchPair (PAIR_DE, left);
1732 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
1735 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
1738 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
1739 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
1741 fetchPairLong (PAIR_DE, left, MSB24);
1742 aopGet (right, MSB24, FALSE);
1746 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
1749 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
1751 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
1752 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
1756 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
1758 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
1761 /*-----------------------------------------------------------------*/
1762 /* genUminus - unary minus code generation */
1763 /*-----------------------------------------------------------------*/
1765 genUminus (iCode * ic)
1768 sym_link *optype, *rtype;
1771 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1772 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1774 /* if both in bit space then special
1776 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1777 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1783 optype = operandType (IC_LEFT (ic));
1784 rtype = operandType (IC_RESULT (ic));
1786 /* if float then do float stuff */
1787 if (IS_FLOAT (optype))
1793 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
1795 /* Create a new asmop with value zero */
1796 asmop *azero = newAsmop (AOP_SIMPLELIT);
1797 azero->aopu.aop_simplelit = 0;
1799 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
1803 /* otherwise subtract from zero */
1804 size = AOP_SIZE (IC_LEFT (ic));
1809 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
1810 emit2 ("ld a,!zero");
1811 emit2 ("sbc a,%s", l);
1812 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1815 /* if any remaining bytes in the result */
1816 /* we just need to propagate the sign */
1817 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
1822 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1826 /* release the aops */
1827 freeAsmop (IC_LEFT (ic), NULL, ic);
1828 freeAsmop (IC_RESULT (ic), NULL, ic);
1831 /*-----------------------------------------------------------------*/
1832 /* assignResultValue - */
1833 /*-----------------------------------------------------------------*/
1835 assignResultValue (operand * oper)
1837 int size = AOP_SIZE (oper);
1840 wassert (size <= 4);
1841 topInA = requiresHL (AOP (oper));
1845 wassert (size <= 2);
1847 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
1849 /* We do it the hard way here. */
1851 aopPut (AOP (oper), _fReturn[0], 0);
1852 aopPut (AOP (oper), _fReturn[1], 1);
1854 aopPut (AOP (oper), _fReturn[0], 2);
1855 aopPut (AOP (oper), _fReturn[1], 3);
1861 aopPut (AOP (oper), _fReturn[size], size);
1867 _saveRegsForCall(iCode *ic, int sendSetSize)
1870 o Stack parameters are pushed before this function enters
1871 o DE and BC may be used in this function.
1872 o HL and DE may be used to return the result.
1873 o HL and DE may be used to send variables.
1874 o DE and BC may be used to store the result value.
1875 o HL may be used in computing the sent value of DE
1876 o The iPushes for other parameters occur before any addSets
1878 Logic: (to be run inside the first iPush or if none, before sending)
1879 o Compute if DE and/or BC are in use over the call
1880 o Compute if DE is used in the send set
1881 o Compute if DE and/or BC are used to hold the result value
1882 o If (DE is used, or in the send set) and is not used in the result, push.
1883 o If BC is used and is not in the result, push
1885 o If DE is used in the send set, fetch
1886 o If HL is used in the send set, fetch
1890 if (_G.saves.saved == FALSE) {
1891 bool deInUse, bcInUse;
1893 bool bcInRet = FALSE, deInRet = FALSE;
1897 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
1901 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), z80_rUmaskForOp (IC_RESULT(ic)));
1905 /* Has no result, so in use is all of in use */
1910 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
1911 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
1913 deSending = (sendSetSize > 1);
1915 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
1917 if (bcInUse && bcInRet == FALSE) {
1919 _G.stack.pushedBC = TRUE;
1921 if (deInUse && deInRet == FALSE) {
1923 _G.stack.pushedDE = TRUE;
1926 _G.saves.saved = TRUE;
1929 /* Already saved. */
1933 /*-----------------------------------------------------------------*/
1934 /* genIpush - genrate code for pushing this gets a little complex */
1935 /*-----------------------------------------------------------------*/
1937 genIpush (iCode * ic)
1939 int size, offset = 0;
1942 /* if this is not a parm push : ie. it is spill push
1943 and spill push is always done on the local stack */
1946 wassertl(0, "Encountered an unsupported spill push.");
1950 if (_G.saves.saved == FALSE) {
1951 /* Caller saves, and this is the first iPush. */
1952 /* Scan ahead until we find the function that we are pushing parameters to.
1953 Count the number of addSets on the way to figure out what registers
1954 are used in the send set.
1957 iCode *walk = ic->next;
1960 if (walk->op == SEND) {
1963 else if (walk->op == CALL || walk->op == PCALL) {
1972 _saveRegsForCall(walk, nAddSets);
1975 /* Already saved by another iPush. */
1978 /* then do the push */
1979 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1981 size = AOP_SIZE (IC_LEFT (ic));
1983 if (isPair (AOP (IC_LEFT (ic))))
1985 _G.stack.pushed += 2;
1986 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
1992 fetchHL (AOP (IC_LEFT (ic)));
1994 spillPair (PAIR_HL);
1995 _G.stack.pushed += 2;
2000 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
2002 spillPair (PAIR_HL);
2003 _G.stack.pushed += 2;
2004 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 0);
2006 spillPair (PAIR_HL);
2007 _G.stack.pushed += 2;
2013 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2015 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2017 emit2 ("ld a,(%s)", l);
2021 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2022 emit2 ("ld a,%s", l);
2030 freeAsmop (IC_LEFT (ic), NULL, ic);
2033 /*-----------------------------------------------------------------*/
2034 /* genIpop - recover the registers: can happen only for spilling */
2035 /*-----------------------------------------------------------------*/
2037 genIpop (iCode * ic)
2042 /* if the temp was not pushed then */
2043 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2046 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2047 size = AOP_SIZE (IC_LEFT (ic));
2048 offset = (size - 1);
2049 if (isPair (AOP (IC_LEFT (ic))))
2051 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2059 spillPair (PAIR_HL);
2060 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2064 freeAsmop (IC_LEFT (ic), NULL, ic);
2067 /* This is quite unfortunate */
2069 setArea (int inHome)
2072 static int lastArea = 0;
2074 if (_G.in_home != inHome) {
2076 const char *sz = port->mem.code_name;
2077 port->mem.code_name = "HOME";
2078 emit2("!area", CODE_NAME);
2079 port->mem.code_name = sz;
2082 emit2("!area", CODE_NAME); */
2083 _G.in_home = inHome;
2094 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2098 symbol *sym = OP_SYMBOL (op);
2100 if (sym->isspilt || sym->nRegs == 0)
2103 aopOp (op, ic, FALSE, FALSE);
2106 if (aop->type == AOP_REG)
2109 for (i = 0; i < aop->size; i++)
2111 if (pairId == PAIR_DE)
2113 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2114 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2116 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2119 else if (pairId == PAIR_BC)
2121 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2122 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2124 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2134 freeAsmop (IC_LEFT (ic), NULL, ic);
2138 /** Emit the code for a call statement
2141 emitCall (iCode * ic, bool ispcall)
2143 sym_link *detype = getSpec (operandType (IC_LEFT (ic)));
2145 bitVect *rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
2147 /* if caller saves & we have not saved then */
2153 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2155 /* if send set is not empty then assign */
2160 int nSend = elementsInSet(_G.sendSet);
2161 bool swapped = FALSE;
2163 int _z80_sendOrder[] = {
2168 /* Check if the parameters are swapped. If so route through hl instead. */
2169 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2171 sic = setFirstItem(_G.sendSet);
2172 sic = setNextItem(_G.sendSet);
2174 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2175 /* The second send value is loaded from one the one that holds the first
2176 send, i.e. it is overwritten. */
2177 /* Cache the first in HL, and load the second from HL instead. */
2178 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2179 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2185 for (sic = setFirstItem (_G.sendSet); sic;
2186 sic = setNextItem (_G.sendSet))
2189 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2191 size = AOP_SIZE (IC_LEFT (sic));
2192 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2193 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2195 // PENDING: Mild hack
2196 if (swapped == TRUE && send == 1) {
2198 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2201 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2203 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2206 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2210 freeAsmop (IC_LEFT (sic), NULL, sic);
2217 if (IS_BANKEDCALL (detype))
2219 werror (W_INDIR_BANKED);
2221 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2223 if (isLitWord (AOP (IC_LEFT (ic))))
2225 emitDebug ("; Special case where the pCall is to a constant");
2226 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2230 symbol *rlbl = newiTempLabel (NULL);
2231 spillPair (PAIR_HL);
2232 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2234 _G.stack.pushed += 2;
2236 fetchHL (AOP (IC_LEFT (ic)));
2238 emit2 ("!tlabeldef", (rlbl->key + 100));
2239 _G.stack.pushed -= 2;
2241 freeAsmop (IC_LEFT (ic), NULL, ic);
2245 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2246 OP_SYMBOL (IC_LEFT (ic))->rname :
2247 OP_SYMBOL (IC_LEFT (ic))->name;
2248 if (IS_BANKEDCALL (detype))
2250 emit2 ("call banked_call");
2251 emit2 ("!dws", name);
2252 emit2 ("!dw !bankimmeds", name);
2257 emit2 ("call %s", name);
2262 /* Mark the regsiters as restored. */
2263 _G.saves.saved = FALSE;
2265 /* if we need assign a result value */
2266 if ((IS_ITEMP (IC_RESULT (ic)) &&
2267 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2268 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2269 IS_TRUE_SYMOP (IC_RESULT (ic)))
2272 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2274 assignResultValue (IC_RESULT (ic));
2276 freeAsmop (IC_RESULT (ic), NULL, ic);
2279 /* adjust the stack for parameters if required */
2282 int i = ic->parmBytes;
2284 _G.stack.pushed -= i;
2287 emit2 ("!ldaspsp", i);
2294 emit2 ("ld hl,#%d", i);
2295 emit2 ("add hl,sp");
2312 if (_G.stack.pushedDE)
2314 bool dInUse = bitVectBitValue(rInUse, D_IDX);
2315 bool eInUse = bitVectBitValue(rInUse, E_IDX);
2317 if (dInUse && eInUse)
2333 wassertl (0, "Neither D or E were in use but it was pushed.");
2335 _G.stack.pushedDE = FALSE;
2338 if (_G.stack.pushedBC)
2340 bool bInUse = bitVectBitValue(rInUse, B_IDX);
2341 bool cInUse = bitVectBitValue(rInUse, C_IDX);
2343 // If both B and C are used in the return value, then we won't get
2345 if (bInUse && cInUse)
2361 wassertl (0, "Neither B or C were in use but it was pushed.");
2363 _G.stack.pushedBC = FALSE;
2367 /*-----------------------------------------------------------------*/
2368 /* genCall - generates a call statement */
2369 /*-----------------------------------------------------------------*/
2371 genCall (iCode * ic)
2373 emitCall (ic, FALSE);
2376 /*-----------------------------------------------------------------*/
2377 /* genPcall - generates a call by pointer statement */
2378 /*-----------------------------------------------------------------*/
2380 genPcall (iCode * ic)
2382 emitCall (ic, TRUE);
2385 /*-----------------------------------------------------------------*/
2386 /* resultRemat - result is rematerializable */
2387 /*-----------------------------------------------------------------*/
2389 resultRemat (iCode * ic)
2391 if (SKIP_IC (ic) || ic->op == IFX)
2394 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2396 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2397 if (sym->remat && !POINTER_SET (ic))
2404 extern set *publics;
2406 /*-----------------------------------------------------------------*/
2407 /* genFunction - generated code for function entry */
2408 /*-----------------------------------------------------------------*/
2410 genFunction (iCode * ic)
2412 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2416 bool bcInUse = FALSE;
2417 bool deInUse = FALSE;
2420 setArea (IS_NONBANKED (sym->etype));
2422 /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
2425 _G.receiveOffset = 0;
2429 if (!IS_STATIC (sym->etype))
2431 addSetIfnotP (&publics, sym);
2435 /* Record the last function name for debugging. */
2436 _G.lastFunctionName = sym->rname;
2438 /* Create the function header */
2439 emit2 ("!functionheader", sym->name);
2440 /* PENDING: portability. */
2441 emit2 ("__%s_start:", sym->rname);
2442 emit2 ("!functionlabeldef", sym->rname);
2444 if (options.profile)
2446 emit2 ("!profileenter");
2449 fetype = getSpec (operandType (IC_LEFT (ic)));
2451 /* if critical function then turn interrupts off */
2452 if (SPEC_CRTCL (fetype))
2455 /* if this is an interrupt service routine then save all potentially used registers. */
2456 if (IS_ISR (sym->etype))
2461 /* PENDING: callee-save etc */
2463 _G.stack.param_offset = 0;
2466 /* Detect which registers are used. */
2470 for (i = 0; i < sym->regsUsed->size; i++)
2472 if (bitVectBitValue (sym->regsUsed, i))
2486 /* Other systems use DE as a temporary. */
2497 _G.stack.param_offset += 2;
2500 _G.stack.pushedBC = bcInUse;
2505 _G.stack.param_offset += 2;
2508 _G.stack.pushedDE = deInUse;
2511 /* adjust the stack for the function */
2512 _G.stack.last = sym->stack;
2515 emit2 ("!enterx", sym->stack);
2518 _G.stack.offset = sym->stack;
2521 /*-----------------------------------------------------------------*/
2522 /* genEndFunction - generates epilogue for functions */
2523 /*-----------------------------------------------------------------*/
2525 genEndFunction (iCode * ic)
2527 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2529 if (IS_ISR (sym->etype))
2535 if (SPEC_CRTCL (sym->etype))
2538 /* PENDING: calleeSave */
2540 if (_G.stack.offset)
2542 emit2 ("!leavex", _G.stack.offset);
2550 if (_G.stack.pushedDE)
2553 _G.stack.pushedDE = FALSE;
2556 if (_G.stack.pushedDE)
2559 _G.stack.pushedDE = FALSE;
2563 if (options.profile)
2565 emit2 ("!profileexit");
2569 /* Both baned and non-banked just ret */
2572 /* PENDING: portability. */
2573 emit2 ("__%s_end:", sym->rname);
2575 _G.flushStatics = 1;
2576 _G.stack.pushed = 0;
2577 _G.stack.offset = 0;
2580 /*-----------------------------------------------------------------*/
2581 /* genRet - generate code for return statement */
2582 /*-----------------------------------------------------------------*/
2587 /* Errk. This is a hack until I can figure out how
2588 to cause dehl to spill on a call */
2589 int size, offset = 0;
2591 /* if we have no return value then
2592 just generate the "ret" */
2596 /* we have something to return then
2597 move the return value into place */
2598 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2599 size = AOP_SIZE (IC_LEFT (ic));
2601 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
2605 emit2 ("ld de,%s", l);
2609 emit2 ("ld hl,%s", l);
2614 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
2616 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
2617 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
2623 l = aopGet (AOP (IC_LEFT (ic)), offset,
2625 if (strcmp (_fReturn[offset], l))
2626 emit2 ("ld %s,%s", _fReturn[offset++], l);
2630 freeAsmop (IC_LEFT (ic), NULL, ic);
2633 /* generate a jump to the return label
2634 if the next is not the return statement */
2635 if (!(ic->next && ic->next->op == LABEL &&
2636 IC_LABEL (ic->next) == returnLabel))
2638 emit2 ("jp !tlabel", returnLabel->key + 100);
2641 /*-----------------------------------------------------------------*/
2642 /* genLabel - generates a label */
2643 /*-----------------------------------------------------------------*/
2645 genLabel (iCode * ic)
2647 /* special case never generate */
2648 if (IC_LABEL (ic) == entryLabel)
2651 emitLabel (IC_LABEL (ic)->key + 100);
2654 /*-----------------------------------------------------------------*/
2655 /* genGoto - generates a ljmp */
2656 /*-----------------------------------------------------------------*/
2658 genGoto (iCode * ic)
2660 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
2663 /*-----------------------------------------------------------------*/
2664 /* genPlusIncr :- does addition with increment if possible */
2665 /*-----------------------------------------------------------------*/
2667 genPlusIncr (iCode * ic)
2669 unsigned int icount;
2670 unsigned int size = getDataSize (IC_RESULT (ic));
2671 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
2673 /* will try to generate an increment */
2674 /* if the right side is not a literal
2676 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
2679 emitDebug ("; genPlusIncr");
2681 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
2683 /* If result is a pair */
2684 if (resultId != PAIR_INVALID)
2686 if (isLitWord (AOP (IC_LEFT (ic))))
2688 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
2691 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
2693 fetchPair (resultId, AOP (IC_RIGHT (ic)));
2694 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
2700 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2704 movLeft2Result (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0);
2705 movLeft2Result (IC_LEFT (ic), 1, IC_RESULT (ic), 1, 0);
2709 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
2714 /* if the literal value of the right hand side
2715 is greater than 4 then it is not worth it */
2719 /* if increment 16 bits in register */
2720 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
2726 symbol *tlbl = NULL;
2727 tlbl = newiTempLabel (NULL);
2730 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
2733 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
2736 emitLabel (tlbl->key + 100);
2740 /* if the sizes are greater than 1 then we cannot */
2741 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
2742 AOP_SIZE (IC_LEFT (ic)) > 1)
2745 /* we can if the aops of the left & result match or
2746 if they are in registers and the registers are the
2748 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2752 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
2760 /*-----------------------------------------------------------------*/
2761 /* outBitAcc - output a bit in acc */
2762 /*-----------------------------------------------------------------*/
2764 outBitAcc (operand * result)
2766 symbol *tlbl = newiTempLabel (NULL);
2767 /* if the result is a bit */
2768 if (AOP_TYPE (result) == AOP_CRY)
2774 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
2775 emit2 ("ld a,!one");
2776 emitLabel (tlbl->key + 100);
2781 /*-----------------------------------------------------------------*/
2782 /* genPlus - generates code for addition */
2783 /*-----------------------------------------------------------------*/
2785 genPlus (iCode * ic)
2787 int size, offset = 0;
2789 /* special cases :- */
2791 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2792 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
2793 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2795 /* Swap the left and right operands if:
2797 if literal, literal on the right or
2798 if left requires ACC or right is already
2801 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
2802 (AOP_NEEDSACC (IC_LEFT (ic))) ||
2803 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
2805 operand *t = IC_RIGHT (ic);
2806 IC_RIGHT (ic) = IC_LEFT (ic);
2810 /* if both left & right are in bit
2812 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
2813 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
2819 /* if left in bit space & right literal */
2820 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
2821 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
2823 /* Can happen I guess */
2827 /* if I can do an increment instead
2828 of add then GOOD for ME */
2829 if (genPlusIncr (ic) == TRUE)
2832 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
2834 size = getDataSize (IC_RESULT (ic));
2836 /* Special case when left and right are constant */
2837 if (isPair (AOP (IC_RESULT (ic))))
2840 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
2841 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
2843 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
2849 sprintf (buffer, "#(%s + %s)", left, right);
2850 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
2855 if (isPair (AOP (IC_RIGHT (ic))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
2857 /* Fetch into HL then do the add */
2858 spillPair (PAIR_HL);
2859 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
2860 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
2865 ld hl,sp+n trashes C so we cant afford to do it during an
2866 add with stack based varibles. Worst case is:
2879 So you cant afford to load up hl if either left, right, or result
2880 is on the stack (*sigh*) The alt is:
2888 Combinations in here are:
2889 * If left or right are in bc then the loss is small - trap later
2890 * If the result is in bc then the loss is also small
2894 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
2895 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
2896 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
2898 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
2899 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
2900 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
2901 AOP_SIZE (IC_RIGHT (ic)) <= 2))
2903 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
2905 /* Swap left and right */
2906 operand *t = IC_RIGHT (ic);
2907 IC_RIGHT (ic) = IC_LEFT (ic);
2910 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
2912 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
2913 emit2 ("add hl,bc");
2917 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
2918 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
2919 emit2 ("add hl,de");
2921 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
2927 /* Be paranoid on the GB with 4 byte variables due to how C
2928 can be trashed by lda hl,n(sp).
2930 _gbz80_emitAddSubLong (ic, TRUE);
2937 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
2939 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
2942 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2945 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2949 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
2952 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2955 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2957 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2961 freeAsmop (IC_LEFT (ic), NULL, ic);
2962 freeAsmop (IC_RIGHT (ic), NULL, ic);
2963 freeAsmop (IC_RESULT (ic), NULL, ic);
2967 /*-----------------------------------------------------------------*/
2968 /* genMinusDec :- does subtraction with deccrement if possible */
2969 /*-----------------------------------------------------------------*/
2971 genMinusDec (iCode * ic)
2973 unsigned int icount;
2974 unsigned int size = getDataSize (IC_RESULT (ic));
2976 /* will try to generate an increment */
2977 /* if the right side is not a literal we cannot */
2978 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
2981 /* if the literal value of the right hand side
2982 is greater than 4 then it is not worth it */
2983 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
2986 size = getDataSize (IC_RESULT (ic));
2988 /* if decrement 16 bits in register */
2989 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
2990 (size > 1) && isPair (AOP (IC_RESULT (ic))))
2993 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
2997 /* If result is a pair */
2998 if (isPair (AOP (IC_RESULT (ic))))
3000 movLeft2Result (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0);
3001 movLeft2Result (IC_LEFT (ic), 1, IC_RESULT (ic), 1, 0);
3003 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3007 /* if increment 16 bits in register */
3008 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3012 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3015 emit2 ("dec %s", _getTempPairName());
3018 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3024 /* if the sizes are greater than 1 then we cannot */
3025 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3026 AOP_SIZE (IC_LEFT (ic)) > 1)
3029 /* we can if the aops of the left & result match or if they are in
3030 registers and the registers are the same */
3031 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3034 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3041 /*-----------------------------------------------------------------*/
3042 /* genMinus - generates code for subtraction */
3043 /*-----------------------------------------------------------------*/
3045 genMinus (iCode * ic)
3047 int size, offset = 0;
3048 unsigned long lit = 0L;
3050 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3051 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3052 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3054 /* special cases :- */
3055 /* if both left & right are in bit space */
3056 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3057 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3063 /* if I can do an decrement instead of subtract then GOOD for ME */
3064 if (genMinusDec (ic) == TRUE)
3067 size = getDataSize (IC_RESULT (ic));
3069 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3074 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3078 /* Same logic as genPlus */
3081 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3082 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3083 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3085 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3086 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3087 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3088 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3090 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3091 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3093 if (left == PAIR_INVALID && right == PAIR_INVALID)
3098 else if (right == PAIR_INVALID)
3100 else if (left == PAIR_INVALID)
3103 fetchPair (left, AOP (IC_LEFT (ic)));
3104 /* Order is important. Right may be HL */
3105 fetchPair (right, AOP (IC_RIGHT (ic)));
3107 emit2 ("ld a,%s", _pairs[left].l);
3108 emit2 ("sub a,%s", _pairs[right].l);
3110 emit2 ("ld a,%s", _pairs[left].h);
3111 emit2 ("sbc a,%s", _pairs[right].h);
3113 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3114 aopPut (AOP (IC_RESULT (ic)), "e", 0);
3120 /* Be paranoid on the GB with 4 byte variables due to how C
3121 can be trashed by lda hl,n(sp).
3123 _gbz80_emitAddSubLong (ic, FALSE);
3128 /* if literal, add a,#-lit, else normal subb */
3131 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3132 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3136 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3139 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3143 /* first add without previous c */
3145 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
3147 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3149 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3152 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3153 AOP_SIZE (IC_LEFT (ic)) == 3 &&
3154 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3158 freeAsmop (IC_LEFT (ic), NULL, ic);
3159 freeAsmop (IC_RIGHT (ic), NULL, ic);
3160 freeAsmop (IC_RESULT (ic), NULL, ic);
3163 /*-----------------------------------------------------------------*/
3164 /* genMult - generates code for multiplication */
3165 /*-----------------------------------------------------------------*/
3167 genMult (iCode * ic)
3169 /* Shouldn't occur - all done through function calls */
3173 /*-----------------------------------------------------------------*/
3174 /* genDiv - generates code for division */
3175 /*-----------------------------------------------------------------*/
3179 /* Shouldn't occur - all done through function calls */
3183 /*-----------------------------------------------------------------*/
3184 /* genMod - generates code for division */
3185 /*-----------------------------------------------------------------*/
3189 /* Shouldn't occur - all done through function calls */
3193 /*-----------------------------------------------------------------*/
3194 /* genIfxJump :- will create a jump depending on the ifx */
3195 /*-----------------------------------------------------------------*/
3197 genIfxJump (iCode * ic, char *jval)
3202 /* if true label then we jump if condition
3206 jlbl = IC_TRUE (ic);
3207 if (!strcmp (jval, "a"))
3211 else if (!strcmp (jval, "c"))
3215 else if (!strcmp (jval, "nc"))
3221 /* The buffer contains the bit on A that we should test */
3227 /* false label is present */
3228 jlbl = IC_FALSE (ic);
3229 if (!strcmp (jval, "a"))
3233 else if (!strcmp (jval, "c"))
3237 else if (!strcmp (jval, "nc"))
3243 /* The buffer contains the bit on A that we should test */
3247 /* Z80 can do a conditional long jump */
3248 if (!strcmp (jval, "a"))
3252 else if (!strcmp (jval, "c"))
3255 else if (!strcmp (jval, "nc"))
3260 emit2 ("bit %s,a", jval);
3262 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
3264 /* mark the icode as generated */
3270 _getPairIdName (PAIR_ID id)
3272 return _pairs[id].name;
3276 /** Generic compare for > or <
3279 genCmp (operand * left, operand * right,
3280 operand * result, iCode * ifx, int sign)
3282 int size, offset = 0;
3283 unsigned long lit = 0L;
3284 bool swap_sense = FALSE;
3286 /* if left & right are bit variables */
3287 if (AOP_TYPE (left) == AOP_CRY &&
3288 AOP_TYPE (right) == AOP_CRY)
3290 /* Cant happen on the Z80 */
3295 /* subtract right from left if at the
3296 end the carry flag is set then we know that
3297 left is greater than right */
3298 size = max (AOP_SIZE (left), AOP_SIZE (right));
3300 /* if unsigned char cmp with lit, just compare */
3302 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
3304 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3307 emit2 ("xor a,!immedbyte", 0x80);
3308 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
3311 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3313 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
3315 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
3316 // Pull left into DE and right into HL
3317 aopGet (AOP(left), LSB, FALSE);
3320 aopGet (AOP(right), LSB, FALSE);
3324 if (size == 0 && sign)
3326 // Highest byte when signed needs the bits flipped
3329 emit2 ("ld a,(de)");
3330 emit2 ("xor #0x80");
3332 emit2 ("ld a,(hl)");
3333 emit2 ("xor #0x80");
3337 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
3341 emit2 ("ld a,(de)");
3342 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
3352 spillPair (PAIR_HL);
3357 // PENDING: Doesn't work around zero
3361 If the left or the right is a lit:
3362 Load -lit into HL, add to right via, check sense.
3364 if (IS_GB && size == 2 && (AOP_TYPE (right) == AOP_LIT || AOP_TYPE (left) == AOP_LIT))
3366 PAIR_ID id = PAIR_DE;
3367 asmop *lit = AOP (right);
3368 asmop *op = AOP (left);
3371 if (AOP_TYPE (left) == AOP_LIT)
3379 emit2 ("ld e,%s", aopGet (op, 0, 0));
3380 emit2 ("ld a,%s", aopGet (op, 1, 0));
3381 emit2 ("xor a,!immedbyte", 0x80);
3386 id = getPairId (op);
3387 if (id == PAIR_INVALID)
3389 fetchPair (PAIR_DE, op);
3393 spillPair (PAIR_HL);
3394 emit2 ("ld hl,%s", fetchLitSpecial (lit, TRUE, sign));
3395 emit2 ("add hl,%s", _getPairIdName (id));
3399 if (AOP_TYPE (right) == AOP_LIT)
3401 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3402 /* optimize if(x < 0) or if(x >= 0) */
3407 /* No sign so it's always false */
3412 /* Just load in the top most bit */
3413 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
3414 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
3416 genIfxJump (ifx, "7");
3427 /* First setup h and l contaning the top most bytes XORed */
3428 bool fDidXor = FALSE;
3429 if (AOP_TYPE (left) == AOP_LIT)
3431 unsigned long lit = (unsigned long)
3432 floatFromVal (AOP (left)->aopu.aop_lit);
3433 emit2 ("ld %s,!immedbyte", _fTmp[0],
3434 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3438 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
3439 emit2 ("xor a,!immedbyte", 0x80);
3440 emit2 ("ld %s,a", _fTmp[0]);
3443 if (AOP_TYPE (right) == AOP_LIT)
3445 unsigned long lit = (unsigned long)
3446 floatFromVal (AOP (right)->aopu.aop_lit);
3447 emit2 ("ld %s,!immedbyte", _fTmp[1],
3448 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3452 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
3453 emit2 ("xor a,!immedbyte", 0x80);
3454 emit2 ("ld %s,a", _fTmp[1]);
3460 /* Do a long subtract */
3463 _moveA (aopGet (AOP (left), offset, FALSE));
3465 if (sign && size == 0)
3467 emit2 ("ld a,%s", _fTmp[0]);
3468 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
3472 /* Subtract through, propagating the carry */
3473 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset++, FALSE));
3480 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
3482 outBitCLong (result, swap_sense);
3486 /* if the result is used in the next
3487 ifx conditional branch then generate
3488 code a little differently */
3490 genIfxJump (ifx, swap_sense ? "nc" : "c");
3492 outBitCLong (result, swap_sense);
3493 /* leave the result in acc */
3497 /*-----------------------------------------------------------------*/
3498 /* genCmpGt :- greater than comparison */
3499 /*-----------------------------------------------------------------*/
3501 genCmpGt (iCode * ic, iCode * ifx)
3503 operand *left, *right, *result;
3504 sym_link *letype, *retype;
3507 left = IC_LEFT (ic);
3508 right = IC_RIGHT (ic);
3509 result = IC_RESULT (ic);
3511 letype = getSpec (operandType (left));
3512 retype = getSpec (operandType (right));
3513 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
3514 /* assign the amsops */
3515 aopOp (left, ic, FALSE, FALSE);
3516 aopOp (right, ic, FALSE, FALSE);
3517 aopOp (result, ic, TRUE, FALSE);
3519 genCmp (right, left, result, ifx, sign);
3521 freeAsmop (left, NULL, ic);
3522 freeAsmop (right, NULL, ic);
3523 freeAsmop (result, NULL, ic);
3526 /*-----------------------------------------------------------------*/
3527 /* genCmpLt - less than comparisons */
3528 /*-----------------------------------------------------------------*/
3530 genCmpLt (iCode * ic, iCode * ifx)
3532 operand *left, *right, *result;
3533 sym_link *letype, *retype;
3536 left = IC_LEFT (ic);
3537 right = IC_RIGHT (ic);
3538 result = IC_RESULT (ic);
3540 letype = getSpec (operandType (left));
3541 retype = getSpec (operandType (right));
3542 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
3544 /* assign the amsops */
3545 aopOp (left, ic, FALSE, FALSE);
3546 aopOp (right, ic, FALSE, FALSE);
3547 aopOp (result, ic, TRUE, FALSE);
3549 genCmp (left, right, result, ifx, sign);
3551 freeAsmop (left, NULL, ic);
3552 freeAsmop (right, NULL, ic);
3553 freeAsmop (result, NULL, ic);
3556 /*-----------------------------------------------------------------*/
3557 /* gencjneshort - compare and jump if not equal */
3558 /*-----------------------------------------------------------------*/
3560 gencjneshort (operand * left, operand * right, symbol * lbl)
3562 int size = max (AOP_SIZE (left), AOP_SIZE (right));
3564 unsigned long lit = 0L;
3566 /* Swap the left and right if it makes the computation easier */
3567 if (AOP_TYPE (left) == AOP_LIT)
3574 if (AOP_TYPE (right) == AOP_LIT)
3575 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3577 /* if the right side is a literal then anything goes */
3578 if (AOP_TYPE (right) == AOP_LIT &&
3579 AOP_TYPE (left) != AOP_DIR)
3583 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3590 emit2 ("or a,%s", aopGet (AOP (left), offset, FALSE));
3597 emit2 ("jp nz,!tlabel", lbl->key + 100);
3603 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3604 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
3607 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
3608 emit2 ("jp nz,!tlabel", lbl->key + 100);
3613 /* if the right side is in a register or in direct space or
3614 if the left is a pointer register & right is not */
3615 else if (AOP_TYPE (right) == AOP_REG ||
3616 AOP_TYPE (right) == AOP_DIR ||
3617 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
3621 _moveA (aopGet (AOP (left), offset, FALSE));
3622 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
3623 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
3625 emit2 ("jp nz,!tlabel", lbl->key + 100);
3628 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3629 emit2 ("jp nz,!tlabel", lbl->key + 100);
3636 /* right is a pointer reg need both a & b */
3637 /* PENDING: is this required? */
3640 _moveA (aopGet (AOP (right), offset, FALSE));
3641 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
3642 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
3648 /*-----------------------------------------------------------------*/
3649 /* gencjne - compare and jump if not equal */
3650 /*-----------------------------------------------------------------*/
3652 gencjne (operand * left, operand * right, symbol * lbl)
3654 symbol *tlbl = newiTempLabel (NULL);
3656 gencjneshort (left, right, lbl);
3659 emit2 ("ld a,!one");
3660 emit2 ("!shortjp !tlabel", tlbl->key + 100);
3661 emitLabel (lbl->key + 100);
3663 emitLabel (tlbl->key + 100);
3666 /*-----------------------------------------------------------------*/
3667 /* genCmpEq - generates code for equal to */
3668 /*-----------------------------------------------------------------*/
3670 genCmpEq (iCode * ic, iCode * ifx)
3672 operand *left, *right, *result;
3674 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
3675 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
3676 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
3678 emitDebug ("; genCmpEq: left %u, right %u, result %u\n", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
3680 /* Swap operands if it makes the operation easier. ie if:
3681 1. Left is a literal.
3683 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
3685 operand *t = IC_RIGHT (ic);
3686 IC_RIGHT (ic) = IC_LEFT (ic);
3690 if (ifx && !AOP_SIZE (result))
3693 /* if they are both bit variables */
3694 if (AOP_TYPE (left) == AOP_CRY &&
3695 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
3701 tlbl = newiTempLabel (NULL);
3702 gencjneshort (left, right, tlbl);
3705 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
3706 emitLabel (tlbl->key + 100);
3710 /* PENDING: do this better */
3711 symbol *lbl = newiTempLabel (NULL);
3712 emit2 ("!shortjp !tlabel", lbl->key + 100);
3713 emitLabel (tlbl->key + 100);
3714 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
3715 emitLabel (lbl->key + 100);
3718 /* mark the icode as generated */
3723 /* if they are both bit variables */
3724 if (AOP_TYPE (left) == AOP_CRY &&
3725 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
3731 gencjne (left, right, newiTempLabel (NULL));
3732 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
3738 genIfxJump (ifx, "a");
3741 /* if the result is used in an arithmetic operation
3742 then put the result in place */
3743 if (AOP_TYPE (result) != AOP_CRY)
3747 /* leave the result in acc */
3751 freeAsmop (left, NULL, ic);
3752 freeAsmop (right, NULL, ic);
3753 freeAsmop (result, NULL, ic);
3756 /*-----------------------------------------------------------------*/
3757 /* ifxForOp - returns the icode containing the ifx for operand */
3758 /*-----------------------------------------------------------------*/
3760 ifxForOp (operand * op, iCode * ic)
3762 /* if true symbol then needs to be assigned */
3763 if (IS_TRUE_SYMOP (op))
3766 /* if this has register type condition and
3767 the next instruction is ifx with the same operand
3768 and live to of the operand is upto the ifx only then */
3770 ic->next->op == IFX &&
3771 IC_COND (ic->next)->key == op->key &&
3772 OP_SYMBOL (op)->liveTo <= ic->next->seq)
3778 /*-----------------------------------------------------------------*/
3779 /* genAndOp - for && operation */
3780 /*-----------------------------------------------------------------*/
3782 genAndOp (iCode * ic)
3784 operand *left, *right, *result;
3787 /* note here that && operations that are in an if statement are
3788 taken away by backPatchLabels only those used in arthmetic
3789 operations remain */
3790 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
3791 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
3792 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
3794 /* if both are bit variables */
3795 if (AOP_TYPE (left) == AOP_CRY &&
3796 AOP_TYPE (right) == AOP_CRY)
3802 tlbl = newiTempLabel (NULL);
3804 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3806 emitLabel (tlbl->key + 100);
3810 freeAsmop (left, NULL, ic);
3811 freeAsmop (right, NULL, ic);
3812 freeAsmop (result, NULL, ic);
3815 /*-----------------------------------------------------------------*/
3816 /* genOrOp - for || operation */
3817 /*-----------------------------------------------------------------*/
3819 genOrOp (iCode * ic)
3821 operand *left, *right, *result;
3824 /* note here that || operations that are in an
3825 if statement are taken away by backPatchLabels
3826 only those used in arthmetic operations remain */
3827 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
3828 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
3829 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
3831 /* if both are bit variables */
3832 if (AOP_TYPE (left) == AOP_CRY &&
3833 AOP_TYPE (right) == AOP_CRY)
3839 tlbl = newiTempLabel (NULL);
3841 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3843 emitLabel (tlbl->key + 100);
3847 freeAsmop (left, NULL, ic);
3848 freeAsmop (right, NULL, ic);
3849 freeAsmop (result, NULL, ic);
3852 /*-----------------------------------------------------------------*/
3853 /* isLiteralBit - test if lit == 2^n */
3854 /*-----------------------------------------------------------------*/
3856 isLiteralBit (unsigned long lit)
3858 unsigned long pw[32] =
3859 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
3860 0x100L, 0x200L, 0x400L, 0x800L,
3861 0x1000L, 0x2000L, 0x4000L, 0x8000L,
3862 0x10000L, 0x20000L, 0x40000L, 0x80000L,
3863 0x100000L, 0x200000L, 0x400000L, 0x800000L,
3864 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
3865 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
3868 for (idx = 0; idx < 32; idx++)
3874 /*-----------------------------------------------------------------*/
3875 /* jmpTrueOrFalse - */
3876 /*-----------------------------------------------------------------*/
3878 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
3880 // ugly but optimized by peephole
3883 symbol *nlbl = newiTempLabel (NULL);
3884 emit2 ("jp !tlabel", nlbl->key + 100);
3885 emitLabel (tlbl->key + 100);
3886 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
3887 emitLabel (nlbl->key + 100);
3891 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
3892 emitLabel (tlbl->key + 100);
3897 /*-----------------------------------------------------------------*/
3898 /* genAnd - code for and */
3899 /*-----------------------------------------------------------------*/
3901 genAnd (iCode * ic, iCode * ifx)
3903 operand *left, *right, *result;
3904 int size, offset = 0;
3905 unsigned long lit = 0L;
3908 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
3909 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
3910 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
3913 emitDebug ("; Type res[%d] = l[%d]&r[%d]",
3915 AOP_TYPE (left), AOP_TYPE (right));
3916 emitDebug ("; Size res[%d] = l[%d]&r[%d]",
3918 AOP_SIZE (left), AOP_SIZE (right));
3921 /* if left is a literal & right is not then exchange them */
3922 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
3923 AOP_NEEDSACC (left))
3925 operand *tmp = right;
3930 /* if result = right then exchange them */
3931 if (sameRegs (AOP (result), AOP (right)))
3933 operand *tmp = right;
3938 /* if right is bit then exchange them */
3939 if (AOP_TYPE (right) == AOP_CRY &&
3940 AOP_TYPE (left) != AOP_CRY)
3942 operand *tmp = right;
3946 if (AOP_TYPE (right) == AOP_LIT)
3947 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3949 size = AOP_SIZE (result);
3951 if (AOP_TYPE (left) == AOP_CRY)
3957 // if(val & 0xZZ) - size = 0, ifx != FALSE -
3958 // bit = val & 0xZZ - size = 1, ifx = FALSE -
3959 if ((AOP_TYPE (right) == AOP_LIT) &&
3960 (AOP_TYPE (result) == AOP_CRY) &&
3961 (AOP_TYPE (left) != AOP_CRY))
3963 int posbit = isLiteralBit (lit);
3968 _moveA (aopGet (AOP (left), posbit >> 3, FALSE));
3973 emit2 ("mov c,acc.%d", posbit & 0x07);
3980 sprintf (buffer, "%d", posbit & 0x07);
3981 genIfxJump (ifx, buffer);
3992 symbol *tlbl = newiTempLabel (NULL);
3993 int sizel = AOP_SIZE (left);
4001 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
4003 _moveA (aopGet (AOP (left), offset, FALSE));
4005 if ((posbit = isLiteralBit (bytelit)) != 0)
4008 emit2 ("jb acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
4012 if (bytelit != 0x0FFL)
4014 aopGet (AOP (right), offset, FALSE));
4018 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4023 // bit = left & literal
4027 emit2 ("!tlabeldef", tlbl->key + 100);
4029 // if(left & literal)
4033 jmpTrueOrFalse (ifx, tlbl);
4041 /* if left is same as result */
4042 if (sameRegs (AOP (result), AOP (left)))
4044 for (; size--; offset++)
4046 if (AOP_TYPE (right) == AOP_LIT)
4048 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4053 aopPut (AOP (result), "!zero", offset);
4056 _moveA (aopGet (AOP (left), offset, FALSE));
4058 aopGet (AOP (right), offset, FALSE));
4059 aopPut (AOP (left), "a", offset);
4066 if (AOP_TYPE (left) == AOP_ACC)
4072 _moveA (aopGet (AOP (left), offset, FALSE));
4074 aopGet (AOP (right), offset, FALSE));
4075 aopPut (AOP (left), "a", offset);
4082 // left & result in different registers
4083 if (AOP_TYPE (result) == AOP_CRY)
4089 for (; (size--); offset++)
4092 // result = left & right
4093 if (AOP_TYPE (right) == AOP_LIT)
4095 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4097 aopPut (AOP (result),
4098 aopGet (AOP (left), offset, FALSE),
4102 else if (bytelit == 0)
4104 aopPut (AOP (result), "!zero", offset);
4108 // faster than result <- left, anl result,right
4109 // and better if result is SFR
4110 if (AOP_TYPE (left) == AOP_ACC)
4111 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4114 _moveA (aopGet (AOP (left), offset, FALSE));
4116 aopGet (AOP (right), offset, FALSE));
4118 aopPut (AOP (result), "a", offset);
4125 freeAsmop (left, NULL, ic);
4126 freeAsmop (right, NULL, ic);
4127 freeAsmop (result, NULL, ic);
4130 /*-----------------------------------------------------------------*/
4131 /* genOr - code for or */
4132 /*-----------------------------------------------------------------*/
4134 genOr (iCode * ic, iCode * ifx)
4136 operand *left, *right, *result;
4137 int size, offset = 0;
4138 unsigned long lit = 0L;
4140 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4141 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4142 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4145 emitDebug ("; Type res[%d] = l[%d]&r[%d]",
4147 AOP_TYPE (left), AOP_TYPE (right));
4148 emitDebug ("; Size res[%d] = l[%d]&r[%d]",
4150 AOP_SIZE (left), AOP_SIZE (right));
4153 /* if left is a literal & right is not then exchange them */
4154 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4155 AOP_NEEDSACC (left))
4157 operand *tmp = right;
4162 /* if result = right then exchange them */
4163 if (sameRegs (AOP (result), AOP (right)))
4165 operand *tmp = right;
4170 /* if right is bit then exchange them */
4171 if (AOP_TYPE (right) == AOP_CRY &&
4172 AOP_TYPE (left) != AOP_CRY)
4174 operand *tmp = right;
4178 if (AOP_TYPE (right) == AOP_LIT)
4179 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4181 size = AOP_SIZE (result);
4183 if (AOP_TYPE (left) == AOP_CRY)
4189 if ((AOP_TYPE (right) == AOP_LIT) &&
4190 (AOP_TYPE (result) == AOP_CRY) &&
4191 (AOP_TYPE (left) != AOP_CRY))
4197 /* if left is same as result */
4198 if (sameRegs (AOP (result), AOP (left)))
4200 for (; size--; offset++)
4202 if (AOP_TYPE (right) == AOP_LIT)
4204 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4208 _moveA (aopGet (AOP (left), offset, FALSE));
4210 aopGet (AOP (right), offset, FALSE));
4211 aopPut (AOP (result), "a", offset);
4216 if (AOP_TYPE (left) == AOP_ACC)
4217 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4220 _moveA (aopGet (AOP (left), offset, FALSE));
4222 aopGet (AOP (right), offset, FALSE));
4223 aopPut (AOP (result), "a", offset);
4230 // left & result in different registers
4231 if (AOP_TYPE (result) == AOP_CRY)
4236 for (; (size--); offset++)
4239 // result = left & right
4240 if (AOP_TYPE (right) == AOP_LIT)
4242 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4244 aopPut (AOP (result),
4245 aopGet (AOP (left), offset, FALSE),
4250 // faster than result <- left, anl result,right
4251 // and better if result is SFR
4252 if (AOP_TYPE (left) == AOP_ACC)
4253 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4256 _moveA (aopGet (AOP (left), offset, FALSE));
4258 aopGet (AOP (right), offset, FALSE));
4260 aopPut (AOP (result), "a", offset);
4261 /* PENDING: something weird is going on here. Add exception. */
4262 if (AOP_TYPE (result) == AOP_ACC)
4268 freeAsmop (left, NULL, ic);
4269 freeAsmop (right, NULL, ic);
4270 freeAsmop (result, NULL, ic);
4273 /*-----------------------------------------------------------------*/
4274 /* genXor - code for xclusive or */
4275 /*-----------------------------------------------------------------*/
4277 genXor (iCode * ic, iCode * ifx)
4279 operand *left, *right, *result;
4280 int size, offset = 0;
4281 unsigned long lit = 0L;
4283 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4284 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4285 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4287 /* if left is a literal & right is not then exchange them */
4288 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4289 AOP_NEEDSACC (left))
4291 operand *tmp = right;
4296 /* if result = right then exchange them */
4297 if (sameRegs (AOP (result), AOP (right)))
4299 operand *tmp = right;
4304 /* if right is bit then exchange them */
4305 if (AOP_TYPE (right) == AOP_CRY &&
4306 AOP_TYPE (left) != AOP_CRY)
4308 operand *tmp = right;
4312 if (AOP_TYPE (right) == AOP_LIT)
4313 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4315 size = AOP_SIZE (result);
4317 if (AOP_TYPE (left) == AOP_CRY)
4323 if ((AOP_TYPE (right) == AOP_LIT) &&
4324 (AOP_TYPE (result) == AOP_CRY) &&
4325 (AOP_TYPE (left) != AOP_CRY))
4331 /* if left is same as result */
4332 if (sameRegs (AOP (result), AOP (left)))
4334 for (; size--; offset++)
4336 if (AOP_TYPE (right) == AOP_LIT)
4338 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4342 _moveA (aopGet (AOP (right), offset, FALSE));
4344 aopGet (AOP (left), offset, FALSE));
4345 aopPut (AOP (result), "a", offset);
4350 if (AOP_TYPE (left) == AOP_ACC)
4352 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4356 _moveA (aopGet (AOP (right), offset, FALSE));
4358 aopGet (AOP (left), offset, FALSE));
4359 aopPut (AOP (result), "a", 0);
4366 // left & result in different registers
4367 if (AOP_TYPE (result) == AOP_CRY)
4372 for (; (size--); offset++)
4375 // result = left & right
4376 if (AOP_TYPE (right) == AOP_LIT)
4378 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4380 aopPut (AOP (result),
4381 aopGet (AOP (left), offset, FALSE),
4386 // faster than result <- left, anl result,right
4387 // and better if result is SFR
4388 if (AOP_TYPE (left) == AOP_ACC)
4390 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4394 _moveA (aopGet (AOP (right), offset, FALSE));
4396 aopGet (AOP (left), offset, FALSE));
4398 aopPut (AOP (result), "a", offset);
4403 freeAsmop (left, NULL, ic);
4404 freeAsmop (right, NULL, ic);
4405 freeAsmop (result, NULL, ic);
4408 /*-----------------------------------------------------------------*/
4409 /* genInline - write the inline code out */
4410 /*-----------------------------------------------------------------*/
4412 genInline (iCode * ic)
4414 char *buffer, *bp, *bp1;
4416 _G.lines.isInline += (!options.asmpeep);
4418 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
4419 strcpy (buffer, IC_INLINE (ic));
4421 /* emit each line as a code */
4446 _G.lines.isInline -= (!options.asmpeep);
4450 /*-----------------------------------------------------------------*/
4451 /* genRRC - rotate right with carry */
4452 /*-----------------------------------------------------------------*/
4459 /*-----------------------------------------------------------------*/
4460 /* genRLC - generate code for rotate left with carry */
4461 /*-----------------------------------------------------------------*/
4468 /*-----------------------------------------------------------------*/
4469 /* genGetHbit - generates code get highest order bit */
4470 /*-----------------------------------------------------------------*/
4472 genGetHbit (iCode * ic)
4474 operand *left, *result;
4475 left = IC_LEFT (ic);
4476 result = IC_RESULT (ic);
4477 aopOp (left, ic, FALSE, FALSE);
4478 aopOp (result, ic, FALSE, FALSE);
4480 /* get the highest order byte into a */
4481 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4483 if (AOP_TYPE (result) == AOP_CRY)
4491 /* PENDING: For re-target. */
4497 freeAsmop (left, NULL, ic);
4498 freeAsmop (result, NULL, ic);
4502 emitRsh2 (asmop *aop, int size, int is_signed)
4508 const char *l = aopGet (aop, size, FALSE);
4511 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
4521 /*-----------------------------------------------------------------*/
4522 /* shiftR2Left2Result - shift right two bytes from left to result */
4523 /*-----------------------------------------------------------------*/
4525 shiftR2Left2Result (operand * left, int offl,
4526 operand * result, int offr,
4527 int shCount, int is_signed)
4530 symbol *tlbl, *tlbl1;
4532 movLeft2Result (left, offl, result, offr, 0);
4533 movLeft2Result (left, offl + 1, result, offr + 1, 0);
4535 /* if (AOP(result)->type == AOP_REG) { */
4537 tlbl = newiTempLabel (NULL);
4538 tlbl1 = newiTempLabel (NULL);
4540 /* Left is already in result - so now do the shift */
4545 emitRsh2 (AOP (result), size, is_signed);
4550 emit2 ("ld a,!immedbyte+1", shCount);
4551 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4552 emitLabel (tlbl->key + 100);
4554 emitRsh2 (AOP (result), size, is_signed);
4556 emitLabel (tlbl1->key + 100);
4558 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4562 /*-----------------------------------------------------------------*/
4563 /* shiftL2Left2Result - shift left two bytes from left to result */
4564 /*-----------------------------------------------------------------*/
4566 shiftL2Left2Result (operand * left, int offl,
4567 operand * result, int offr, int shCount)
4569 if (sameRegs (AOP (result), AOP (left)) &&
4570 ((offl + MSB16) == offr))
4576 /* Copy left into result */
4577 movLeft2Result (left, offl, result, offr, 0);
4578 movLeft2Result (left, offl + 1, result, offr + 1, 0);
4580 /* PENDING: for now just see if it'll work. */
4581 /*if (AOP(result)->type == AOP_REG) { */
4585 symbol *tlbl, *tlbl1;
4588 tlbl = newiTempLabel (NULL);
4589 tlbl1 = newiTempLabel (NULL);
4591 /* Left is already in result - so now do the shift */
4594 emit2 ("ld a,!immedbyte+1", shCount);
4595 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4596 emitLabel (tlbl->key + 100);
4601 l = aopGet (AOP (result), offset, FALSE);
4605 emit2 ("sla %s", l);
4616 emitLabel (tlbl1->key + 100);
4618 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4623 /*-----------------------------------------------------------------*/
4624 /* AccRol - rotate left accumulator by known count */
4625 /*-----------------------------------------------------------------*/
4627 AccRol (int shCount)
4629 shCount &= 0x0007; // shCount : 0..7
4668 /*-----------------------------------------------------------------*/
4669 /* AccLsh - left shift accumulator by known count */
4670 /*-----------------------------------------------------------------*/
4672 AccLsh (int shCount)
4674 static const unsigned char SLMask[] =
4676 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
4685 else if (shCount == 2)
4692 /* rotate left accumulator */
4694 /* and kill the lower order bits */
4695 emit2 ("and a,!immedbyte", SLMask[shCount]);
4700 /*-----------------------------------------------------------------*/
4701 /* shiftL1Left2Result - shift left one byte from left to result */
4702 /*-----------------------------------------------------------------*/
4704 shiftL1Left2Result (operand * left, int offl,
4705 operand * result, int offr, int shCount)
4708 l = aopGet (AOP (left), offl, FALSE);
4710 /* shift left accumulator */
4712 aopPut (AOP (result), "a", offr);
4716 /*-----------------------------------------------------------------*/
4717 /* genlshTwo - left shift two bytes by known amount != 0 */
4718 /*-----------------------------------------------------------------*/
4720 genlshTwo (operand * result, operand * left, int shCount)
4722 int size = AOP_SIZE (result);
4724 wassert (size == 2);
4726 /* if shCount >= 8 */
4734 movLeft2Result (left, LSB, result, MSB16, 0);
4735 aopPut (AOP (result), "!zero", 0);
4736 shiftL1Left2Result (left, MSB16, result, MSB16, shCount);
4740 movLeft2Result (left, LSB, result, MSB16, 0);
4741 aopPut (AOP (result), "!zero", 0);
4746 aopPut (AOP (result), "!zero", LSB);
4749 /* 1 <= shCount <= 7 */
4758 shiftL2Left2Result (left, LSB, result, LSB, shCount);
4763 /*-----------------------------------------------------------------*/
4764 /* genlshOne - left shift a one byte quantity by known count */
4765 /*-----------------------------------------------------------------*/
4767 genlshOne (operand * result, operand * left, int shCount)
4769 shiftL1Left2Result (left, LSB, result, LSB, shCount);
4772 /*-----------------------------------------------------------------*/
4773 /* genLeftShiftLiteral - left shifting by known count */
4774 /*-----------------------------------------------------------------*/
4776 genLeftShiftLiteral (operand * left,
4781 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
4784 freeAsmop (right, NULL, ic);
4786 aopOp (left, ic, FALSE, FALSE);
4787 aopOp (result, ic, FALSE, FALSE);
4789 size = getSize (operandType (result));
4792 emitDebug ("; shift left result %d, left %d", size,
4796 /* I suppose that the left size >= result size */
4802 else if (shCount >= (size * 8))
4806 aopPut (AOP (result), "!zero", size);
4814 genlshOne (result, left, shCount);
4817 genlshTwo (result, left, shCount);
4820 wassertl (0, "Shifting of longs is currently unsupported");
4826 freeAsmop (left, NULL, ic);
4827 freeAsmop (result, NULL, ic);
4830 /*-----------------------------------------------------------------*/
4831 /* genLeftShift - generates code for left shifting */
4832 /*-----------------------------------------------------------------*/
4834 genLeftShift (iCode * ic)
4838 symbol *tlbl, *tlbl1;
4839 operand *left, *right, *result;
4841 right = IC_RIGHT (ic);
4842 left = IC_LEFT (ic);
4843 result = IC_RESULT (ic);
4845 aopOp (right, ic, FALSE, FALSE);
4847 /* if the shift count is known then do it
4848 as efficiently as possible */
4849 if (AOP_TYPE (right) == AOP_LIT)
4851 genLeftShiftLiteral (left, right, result, ic);
4855 /* shift count is unknown then we have to form a loop get the loop
4856 count in B : Note: we take only the lower order byte since
4857 shifting more that 32 bits make no sense anyway, ( the largest
4858 size of an object can be only 32 bits ) */
4859 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
4861 freeAsmop (right, NULL, ic);
4862 aopOp (left, ic, FALSE, FALSE);
4863 aopOp (result, ic, FALSE, FALSE);
4865 /* now move the left to the result if they are not the
4868 if (!sameRegs (AOP (left), AOP (result)))
4871 size = AOP_SIZE (result);
4875 l = aopGet (AOP (left), offset, FALSE);
4876 aopPut (AOP (result), l, offset);
4881 size = AOP_SIZE (result);
4885 l = aopGet (AOP (left), offset, FALSE);
4886 aopPut (AOP (result), l, offset);
4892 tlbl = newiTempLabel (NULL);
4893 size = AOP_SIZE (result);
4895 tlbl1 = newiTempLabel (NULL);
4897 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4898 emitLabel (tlbl->key + 100);
4899 l = aopGet (AOP (result), offset, FALSE);
4903 l = aopGet (AOP (result), offset, FALSE);
4907 emit2 ("sla %s", l);
4915 emitLabel (tlbl1->key + 100);
4917 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4919 freeAsmop (left, NULL, ic);
4920 freeAsmop (result, NULL, ic);
4923 /*-----------------------------------------------------------------*/
4924 /* genrshOne - left shift two bytes by known amount != 0 */
4925 /*-----------------------------------------------------------------*/
4927 genrshOne (operand * result, operand * left, int shCount, int is_signed)
4930 int size = AOP_SIZE (result);
4933 wassert (size == 1);
4934 wassert (shCount < 8);
4936 l = aopGet (AOP (left), 0, FALSE);
4940 if (AOP (result)->type == AOP_REG)
4942 aopPut (AOP (result), l, 0);
4943 l = aopGet (AOP (result), 0, FALSE);
4946 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
4954 emit2 ("%s a", is_signed ? "sra" : "srl");
4956 aopPut (AOP (result), "a", 0);
4960 /*-----------------------------------------------------------------*/
4961 /* AccRsh - right shift accumulator by known count */
4962 /*-----------------------------------------------------------------*/
4964 AccRsh (int shCount)
4966 static const unsigned char SRMask[] =
4968 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
4973 /* rotate right accumulator */
4974 AccRol (8 - shCount);
4975 /* and kill the higher order bits */
4976 emit2 ("and a,!immedbyte", SRMask[shCount]);
4980 /*-----------------------------------------------------------------*/
4981 /* shiftR1Left2Result - shift right one byte from left to result */
4982 /*-----------------------------------------------------------------*/
4984 shiftR1Left2Result (operand * left, int offl,
4985 operand * result, int offr,
4986 int shCount, int sign)
4988 _moveA (aopGet (AOP (left), offl, FALSE));
4997 aopPut (AOP (result), "a", offr);
5000 /*-----------------------------------------------------------------*/
5001 /* genrshTwo - right shift two bytes by known amount != 0 */
5002 /*-----------------------------------------------------------------*/
5004 genrshTwo (operand * result, operand * left,
5005 int shCount, int sign)
5007 /* if shCount >= 8 */
5013 shiftR1Left2Result (left, MSB16, result, LSB,
5018 movLeft2Result (left, MSB16, result, LSB, sign);
5020 aopPut (AOP (result), "!zero", 1);
5022 /* 1 <= shCount <= 7 */
5025 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
5029 /*-----------------------------------------------------------------*/
5030 /* genRightShiftLiteral - left shifting by known count */
5031 /*-----------------------------------------------------------------*/
5033 genRightShiftLiteral (operand * left,
5039 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5042 freeAsmop (right, NULL, ic);
5044 aopOp (left, ic, FALSE, FALSE);
5045 aopOp (result, ic, FALSE, FALSE);
5047 size = getSize (operandType (result));
5049 emitDebug ("; shift right result %d, left %d", size,
5052 /* I suppose that the left size >= result size */
5058 else if (shCount >= (size * 8))
5060 aopPut (AOP (result), "!zero", size);
5066 genrshOne (result, left, shCount, sign);
5069 /* PENDING: sign support */
5070 genrshTwo (result, left, shCount, sign);
5073 wassertl (0, "Asked to shift right a long which should be a function call");
5076 wassertl (0, "Entered default case in right shift delegate");
5079 freeAsmop (left, NULL, ic);
5080 freeAsmop (result, NULL, ic);
5083 /*-----------------------------------------------------------------*/
5084 /* genRightShift - generate code for right shifting */
5085 /*-----------------------------------------------------------------*/
5087 genRightShift (iCode * ic)
5089 operand *right, *left, *result;
5091 int size, offset, first = 1;
5095 symbol *tlbl, *tlbl1;
5097 /* if signed then we do it the hard way preserve the
5098 sign bit moving it inwards */
5099 retype = getSpec (operandType (IC_RESULT (ic)));
5101 is_signed = !SPEC_USIGN (retype);
5103 /* signed & unsigned types are treated the same : i.e. the
5104 signed is NOT propagated inwards : quoting from the
5105 ANSI - standard : "for E1 >> E2, is equivalent to division
5106 by 2**E2 if unsigned or if it has a non-negative value,
5107 otherwise the result is implementation defined ", MY definition
5108 is that the sign does not get propagated */
5110 right = IC_RIGHT (ic);
5111 left = IC_LEFT (ic);
5112 result = IC_RESULT (ic);
5114 aopOp (right, ic, FALSE, FALSE);
5116 /* if the shift count is known then do it
5117 as efficiently as possible */
5118 if (AOP_TYPE (right) == AOP_LIT)
5120 genRightShiftLiteral (left, right, result, ic, is_signed);
5124 aopOp (left, ic, FALSE, FALSE);
5125 aopOp (result, ic, FALSE, FALSE);
5127 /* now move the left to the result if they are not the
5129 if (!sameRegs (AOP (left), AOP (result)) &&
5130 AOP_SIZE (result) > 1)
5133 size = AOP_SIZE (result);
5137 l = aopGet (AOP (left), offset, FALSE);
5138 aopPut (AOP (result), l, offset);
5143 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5145 freeAsmop (right, NULL, ic);
5147 tlbl = newiTempLabel (NULL);
5148 tlbl1 = newiTempLabel (NULL);
5149 size = AOP_SIZE (result);
5152 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5153 emitLabel (tlbl->key + 100);
5156 l = aopGet (AOP (result), offset--, FALSE);
5159 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5167 emitLabel (tlbl1->key + 100);
5169 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5171 freeAsmop (left, NULL, ic);
5172 freeAsmop (result, NULL, ic);
5175 /*-----------------------------------------------------------------*/
5176 /* genGenPointerGet - get value from generic pointer space */
5177 /*-----------------------------------------------------------------*/
5179 genGenPointerGet (operand * left,
5180 operand * result, iCode * ic)
5183 sym_link *retype = getSpec (operandType (result));
5189 aopOp (left, ic, FALSE, FALSE);
5190 aopOp (result, ic, FALSE, FALSE);
5192 if (isPair (AOP (left)) && AOP_SIZE (result) == 1)
5195 if (isPtrPair (AOP (left)))
5197 tsprintf (buffer, "!*pair", getPairName (AOP (left)));
5198 aopPut (AOP (result), buffer, 0);
5202 emit2 ("ld a,!*pair", getPairName (AOP (left)));
5203 aopPut (AOP (result), "a", 0);
5205 freeAsmop (left, NULL, ic);
5209 /* For now we always load into IY */
5210 /* if this is remateriazable */
5211 fetchPair (pair, AOP (left));
5213 /* so iy now contains the address */
5214 freeAsmop (left, NULL, ic);
5216 /* if bit then unpack */
5217 if (IS_BITVAR (retype))
5223 size = AOP_SIZE (result);
5228 /* PENDING: make this better */
5229 if (!IS_GB && AOP (result)->type == AOP_REG)
5231 aopPut (AOP (result), "!*hl", offset++);
5235 emit2 ("ld a,!*pair", _pairs[pair].name);
5236 aopPut (AOP (result), "a", offset++);
5240 emit2 ("inc %s", _pairs[pair].name);
5241 _G.pairs[pair].offset++;
5247 freeAsmop (result, NULL, ic);
5250 /*-----------------------------------------------------------------*/
5251 /* genPointerGet - generate code for pointer get */
5252 /*-----------------------------------------------------------------*/
5254 genPointerGet (iCode * ic)
5256 operand *left, *result;
5257 sym_link *type, *etype;
5259 left = IC_LEFT (ic);
5260 result = IC_RESULT (ic);
5262 /* depending on the type of pointer we need to
5263 move it to the correct pointer register */
5264 type = operandType (left);
5265 etype = getSpec (type);
5267 genGenPointerGet (left, result, ic);
5271 isRegOrLit (asmop * aop)
5273 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
5278 /*-----------------------------------------------------------------*/
5279 /* genGenPointerSet - stores the value into a pointer location */
5280 /*-----------------------------------------------------------------*/
5282 genGenPointerSet (operand * right,
5283 operand * result, iCode * ic)
5286 sym_link *retype = getSpec (operandType (right));
5287 PAIR_ID pairId = PAIR_HL;
5289 aopOp (result, ic, FALSE, FALSE);
5290 aopOp (right, ic, FALSE, FALSE);
5295 /* Handle the exceptions first */
5296 if (isPair (AOP (result)) && (AOP_SIZE (right) == 1))
5299 const char *l = aopGet (AOP (right), 0, FALSE);
5300 const char *pair = getPairName (AOP (result));
5301 if (canAssignToPtr (l) && isPtr (pair))
5303 emit2 ("ld !*pair,%s", pair, l);
5308 emit2 ("ld !*pair,a", pair);
5313 /* if the operand is already in dptr
5314 then we do nothing else we move the value to dptr */
5315 if (AOP_TYPE (result) != AOP_STR)
5317 fetchPair (pairId, AOP (result));
5319 /* so hl know contains the address */
5320 freeAsmop (result, NULL, ic);
5322 /* if bit then unpack */
5323 if (IS_BITVAR (retype))
5329 size = AOP_SIZE (right);
5334 const char *l = aopGet (AOP (right), offset, FALSE);
5335 if (isRegOrLit (AOP (right)) && !IS_GB)
5337 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
5342 emit2 ("ld !*pair,a", _pairs[pairId].name);
5346 emit2 ("inc %s", _pairs[pairId].name);
5347 _G.pairs[pairId].offset++;
5353 freeAsmop (right, NULL, ic);
5356 /*-----------------------------------------------------------------*/
5357 /* genPointerSet - stores the value into a pointer location */
5358 /*-----------------------------------------------------------------*/
5360 genPointerSet (iCode * ic)
5362 operand *right, *result;
5363 sym_link *type, *etype;
5365 right = IC_RIGHT (ic);
5366 result = IC_RESULT (ic);
5368 /* depending on the type of pointer we need to
5369 move it to the correct pointer register */
5370 type = operandType (result);
5371 etype = getSpec (type);
5373 genGenPointerSet (right, result, ic);
5376 /*-----------------------------------------------------------------*/
5377 /* genIfx - generate code for Ifx statement */
5378 /*-----------------------------------------------------------------*/
5380 genIfx (iCode * ic, iCode * popIc)
5382 operand *cond = IC_COND (ic);
5385 aopOp (cond, ic, FALSE, TRUE);
5387 /* get the value into acc */
5388 if (AOP_TYPE (cond) != AOP_CRY)
5392 /* the result is now in the accumulator */
5393 freeAsmop (cond, NULL, ic);
5395 /* if there was something to be popped then do it */
5399 /* if the condition is a bit variable */
5400 if (isbit && IS_ITEMP (cond) &&
5402 genIfxJump (ic, SPIL_LOC (cond)->rname);
5403 else if (isbit && !IS_ITEMP (cond))
5404 genIfxJump (ic, OP_SYMBOL (cond)->rname);
5406 genIfxJump (ic, "a");
5411 /*-----------------------------------------------------------------*/
5412 /* genAddrOf - generates code for address of */
5413 /*-----------------------------------------------------------------*/
5415 genAddrOf (iCode * ic)
5417 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
5419 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
5421 /* if the operand is on the stack then we
5422 need to get the stack offset of this
5429 if (sym->stack <= 0)
5431 emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset);
5435 emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
5442 emit2 ("ld de,!hashedstr", sym->rname);
5444 aopPut (AOP (IC_RESULT (ic)), "e", 0);
5445 aopPut (AOP (IC_RESULT (ic)), "d", 1);
5452 /* if it has an offset then we need to compute it */
5454 emit2 ("ld hl,#%d+%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset, _G.stack.param_offset);
5456 emit2 ("ld hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
5457 emit2 ("add hl,sp");
5461 emit2 ("ld hl,#%s", sym->rname);
5463 aopPut (AOP (IC_RESULT (ic)), "l", 0);
5464 aopPut (AOP (IC_RESULT (ic)), "h", 1);
5466 freeAsmop (IC_RESULT (ic), NULL, ic);
5469 /*-----------------------------------------------------------------*/
5470 /* genAssign - generate code for assignment */
5471 /*-----------------------------------------------------------------*/
5473 genAssign (iCode * ic)
5475 operand *result, *right;
5477 unsigned long lit = 0L;
5479 result = IC_RESULT (ic);
5480 right = IC_RIGHT (ic);
5483 /* Dont bother assigning if they are the same */
5484 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5486 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
5491 aopOp (right, ic, FALSE, FALSE);
5492 aopOp (result, ic, TRUE, FALSE);
5494 /* if they are the same registers */
5495 if (sameRegs (AOP (right), AOP (result)))
5497 emitDebug ("; (registers are the same)");
5501 /* if the result is a bit */
5502 if (AOP_TYPE (result) == AOP_CRY)
5508 size = AOP_SIZE (result);
5511 if (AOP_TYPE (right) == AOP_LIT)
5512 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5513 if (isPair (AOP (result)))
5515 fetchPair (getPairId (AOP (result)), AOP (right));
5517 else if ((size > 1) &&
5518 (AOP_TYPE (result) != AOP_REG) &&
5519 (AOP_TYPE (right) == AOP_LIT) &&
5520 !IS_FLOAT (operandType (right)) &&
5523 bool fXored = FALSE;
5525 /* Work from the top down.
5526 Done this way so that we can use the cached copy of 0
5527 in A for a fast clear */
5530 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
5532 if (!fXored && size > 1)
5539 aopPut (AOP (result), "a", offset);
5543 aopPut (AOP (result), "!zero", offset);
5547 aopPut (AOP (result),
5548 aopGet (AOP (right), offset, FALSE),
5553 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
5555 /* Special case. Load into a and d, then load out. */
5556 _moveA (aopGet (AOP (right), 0, FALSE));
5557 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
5558 aopPut (AOP (result), "a", 0);
5559 aopPut (AOP (result), "e", 1);
5561 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
5563 /* Special case - simple memcpy */
5564 aopGet (AOP (right), LSB, FALSE);
5567 aopGet (AOP (result), LSB, FALSE);
5571 emit2 ("ld a,(de)");
5572 /* Peephole will optimise this. */
5573 emit2 ("ld (hl),a");
5581 spillPair (PAIR_HL);
5587 /* PENDING: do this check better */
5588 if (requiresHL (AOP (right)) && requiresHL (AOP (result)))
5590 _moveA (aopGet (AOP (right), offset, FALSE));
5591 aopPut (AOP (result), "a", offset);
5594 aopPut (AOP (result),
5595 aopGet (AOP (right), offset, FALSE),
5602 freeAsmop (right, NULL, ic);
5603 freeAsmop (result, NULL, ic);
5606 /*-----------------------------------------------------------------*/
5607 /* genJumpTab - genrates code for jump table */
5608 /*-----------------------------------------------------------------*/
5610 genJumpTab (iCode * ic)
5615 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
5616 /* get the condition into accumulator */
5617 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
5620 emit2 ("ld e,%s", l);
5621 emit2 ("ld d,!zero");
5622 jtab = newiTempLabel (NULL);
5624 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
5625 emit2 ("add hl,de");
5626 emit2 ("add hl,de");
5627 emit2 ("add hl,de");
5628 freeAsmop (IC_JTCOND (ic), NULL, ic);
5632 emitLabel (jtab->key + 100);
5633 /* now generate the jump labels */
5634 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
5635 jtab = setNextItem (IC_JTLABELS (ic)))
5636 emit2 ("jp !tlabel", jtab->key + 100);
5639 /*-----------------------------------------------------------------*/
5640 /* genCast - gen code for casting */
5641 /*-----------------------------------------------------------------*/
5643 genCast (iCode * ic)
5645 operand *result = IC_RESULT (ic);
5646 sym_link *ctype = operandType (IC_LEFT (ic));
5647 operand *right = IC_RIGHT (ic);
5650 /* if they are equivalent then do nothing */
5651 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5654 aopOp (right, ic, FALSE, FALSE);
5655 aopOp (result, ic, FALSE, FALSE);
5657 /* if the result is a bit */
5658 if (AOP_TYPE (result) == AOP_CRY)
5663 /* if they are the same size : or less */
5664 if (AOP_SIZE (result) <= AOP_SIZE (right))
5667 /* if they are in the same place */
5668 if (sameRegs (AOP (right), AOP (result)))
5671 /* if they in different places then copy */
5672 size = AOP_SIZE (result);
5676 aopPut (AOP (result),
5677 aopGet (AOP (right), offset, FALSE),
5684 /* PENDING: should be OK. */
5686 /* if the result is of type pointer */
5693 /* so we now know that the size of destination is greater
5694 than the size of the source */
5695 /* we move to result for the size of source */
5696 size = AOP_SIZE (right);
5700 aopPut (AOP (result),
5701 aopGet (AOP (right), offset, FALSE),
5706 /* now depending on the sign of the destination */
5707 size = AOP_SIZE (result) - AOP_SIZE (right);
5708 /* Unsigned or not an integral type - right fill with zeros */
5709 if (SPEC_USIGN (ctype) || !IS_SPEC (ctype))
5712 aopPut (AOP (result), "!zero", offset++);
5716 /* we need to extend the sign :{ */
5717 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
5720 emitDebug ("; genCast: sign extend untested.");
5724 aopPut (AOP (result), "a", offset++);
5728 freeAsmop (right, NULL, ic);
5729 freeAsmop (result, NULL, ic);
5732 /*-----------------------------------------------------------------*/
5733 /* genReceive - generate code for a receive iCode */
5734 /*-----------------------------------------------------------------*/
5736 genReceive (iCode * ic)
5738 if (isOperandInFarSpace (IC_RESULT (ic)) &&
5739 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
5740 IS_TRUE_SYMOP (IC_RESULT (ic))))
5750 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
5751 size = AOP_SIZE(IC_RESULT(ic));
5753 for (i = 0; i < size; i++) {
5754 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
5758 freeAsmop (IC_RESULT (ic), NULL, ic);
5763 /** Maximum number of bytes to emit per line. */
5767 /** Context for the byte output chunker. */
5770 unsigned char buffer[DBEMIT_MAX_RUN];
5775 /** Flushes a byte chunker by writing out all in the buffer and
5779 _dbFlush(DBEMITCTX *self)
5786 sprintf(line, ".db 0x%02X", self->buffer[0]);
5788 for (i = 1; i < self->pos; i++)
5790 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
5797 /** Write out another byte, buffering until a decent line is
5801 _dbEmit(DBEMITCTX *self, int c)
5803 if (self->pos == DBEMIT_MAX_RUN)
5807 self->buffer[self->pos++] = c;
5810 /** Context for a simple run length encoder. */
5814 unsigned char buffer[128];
5816 /** runLen may be equivalent to pos. */
5822 RLE_CHANGE_COST = 4,
5826 /** Flush the buffer of a run length encoder by writing out the run or
5827 data that it currently contains.
5830 _rleCommit(RLECTX *self)
5836 memset(&db, 0, sizeof(db));
5838 emit2(".db %u", self->pos);
5840 for (i = 0; i < self->pos; i++)
5842 _dbEmit(&db, self->buffer[i]);
5851 Can get either a run or a block of random stuff.
5852 Only want to change state if a good run comes in or a run ends.
5853 Detecting run end is easy.
5856 Say initial state is in run, len zero, last zero. Then if you get a
5857 few zeros then something else then a short run will be output.
5858 Seems OK. While in run mode, keep counting. While in random mode,
5859 keep a count of the run. If run hits margin, output all up to run,
5860 restart, enter run mode.
5863 /** Add another byte into the run length encoder, flushing as
5864 required. The run length encoder uses the Amiga IFF style, where
5865 a block is prefixed by its run length. A positive length means
5866 the next n bytes pass straight through. A negative length means
5867 that the next byte is repeated -n times. A zero terminates the
5871 _rleAppend(RLECTX *self, int c)
5875 if (c != self->last)
5877 /* The run has stopped. See if it is worthwhile writing it out
5878 as a run. Note that the random data comes in as runs of
5881 if (self->runLen > RLE_CHANGE_COST)
5883 /* Yes, worthwhile. */
5884 /* Commit whatever was in the buffer. */
5886 emit2(".db -%u,0x%02X", self->runLen, self->last);
5890 /* Not worthwhile. Append to the end of the random list. */
5891 for (i = 0; i < self->runLen; i++)
5893 if (self->pos >= RLE_MAX_BLOCK)
5898 self->buffer[self->pos++] = self->last;
5906 if (self->runLen >= RLE_MAX_BLOCK)
5908 /* Commit whatever was in the buffer. */
5911 emit2 (".db -%u,0x%02X", self->runLen, self->last);
5919 _rleFlush(RLECTX *self)
5921 _rleAppend(self, -1);
5928 /** genArrayInit - Special code for initialising an array with constant
5932 genArrayInit (iCode * ic)
5936 int elementSize = 0, eIndex, i;
5937 unsigned val, lastVal;
5941 memset(&rle, 0, sizeof(rle));
5943 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
5945 if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD)
5947 /* Emit the support function call and the destination address. */
5948 emit2("call __initrleblock");
5949 emit2(".dw %s", aopGetWord (AOP(IC_LEFT(ic)), 0));
5953 wassertl (0, "Unexpected operand to genArrayInit.\n");
5956 type = operandType(IC_LEFT(ic));
5958 if (type && type->next)
5960 elementSize = getSize(type->next);
5964 wassertl (0, "Can't determine element size in genArrayInit.");
5967 iLoop = IC_ARRAYILIST(ic);
5968 lastVal = (unsigned)-1;
5970 /* Feed all the bytes into the run length encoder which will handle
5972 This works well for mixed char data, and for random int and long
5981 for (i = 0; i < ix; i++)
5983 for (eIndex = 0; eIndex < elementSize; eIndex++)
5985 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
5986 _rleAppend(&rle, val);
5991 iLoop = iLoop->next;
5995 /* Mark the end of the run. */
5998 freeAsmop (IC_LEFT(ic), NULL, ic);
6001 /*-----------------------------------------------------------------*/
6002 /* genZ80Code - generate code for Z80 based controllers */
6003 /*-----------------------------------------------------------------*/
6005 genZ80Code (iCode * lic)
6013 _fReturn = _gbz80_return;
6014 _fTmp = _gbz80_return;
6018 _fReturn = _z80_return;
6019 _fTmp = _z80_return;
6022 _G.lines.head = _G.lines.current = NULL;
6024 for (ic = lic; ic; ic = ic->next)
6027 if (cln != ic->lineno)
6029 emit2 ("; %s %d", ic->filename, ic->lineno);
6032 /* if the result is marked as
6033 spilt and rematerializable or code for
6034 this has already been generated then
6036 if (resultRemat (ic) || ic->generated)
6039 /* depending on the operation */
6043 emitDebug ("; genNot");
6048 emitDebug ("; genCpl");
6053 emitDebug ("; genUminus");
6058 emitDebug ("; genIpush");
6063 /* IPOP happens only when trying to restore a
6064 spilt live range, if there is an ifx statement
6065 following this pop then the if statement might
6066 be using some of the registers being popped which
6067 would destory the contents of the register so
6068 we need to check for this condition and handle it */
6070 ic->next->op == IFX &&
6071 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
6073 emitDebug ("; genIfx");
6074 genIfx (ic->next, ic);
6078 emitDebug ("; genIpop");
6084 emitDebug ("; genCall");
6089 emitDebug ("; genPcall");
6094 emitDebug ("; genFunction");
6099 emitDebug ("; genEndFunction");
6100 genEndFunction (ic);
6104 emitDebug ("; genRet");
6109 emitDebug ("; genLabel");
6114 emitDebug ("; genGoto");
6119 emitDebug ("; genPlus");
6124 emitDebug ("; genMinus");
6129 emitDebug ("; genMult");
6134 emitDebug ("; genDiv");
6139 emitDebug ("; genMod");
6144 emitDebug ("; genCmpGt");
6145 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
6149 emitDebug ("; genCmpLt");
6150 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
6157 /* note these two are xlated by algebraic equivalence
6158 during parsing SDCC.y */
6159 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
6160 "got '>=' or '<=' shouldn't have come here");
6164 emitDebug ("; genCmpEq");
6165 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
6169 emitDebug ("; genAndOp");
6174 emitDebug ("; genOrOp");
6179 emitDebug ("; genXor");
6180 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
6184 emitDebug ("; genOr");
6185 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
6189 emitDebug ("; genAnd");
6190 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
6194 emitDebug ("; genInline");
6199 emitDebug ("; genRRC");
6204 emitDebug ("; genRLC");
6209 emitDebug ("; genGetHBIT");
6214 emitDebug ("; genLeftShift");
6219 emitDebug ("; genRightShift");
6223 case GET_VALUE_AT_ADDRESS:
6224 emitDebug ("; genPointerGet");
6230 if (POINTER_SET (ic))
6232 emitDebug ("; genAssign (pointer)");
6237 emitDebug ("; genAssign");
6243 emitDebug ("; genIfx");
6248 emitDebug ("; genAddrOf");
6253 emitDebug ("; genJumpTab");
6258 emitDebug ("; genCast");
6263 emitDebug ("; genReceive");
6268 emitDebug ("; addSet");
6269 addSet (&_G.sendSet, ic);
6278 /* piCode(ic,stdout); */
6284 /* now we are ready to call the
6285 peep hole optimizer */
6286 if (!options.nopeep)
6287 peepHole (&_G.lines.head);
6289 /* This is unfortunate */
6290 /* now do the actual printing */
6292 FILE *fp = codeOutFile;
6293 if (isInHome () && codeOutFile == code->oFile)
6294 codeOutFile = home->oFile;
6295 printLine (_G.lines.head, codeOutFile);
6296 if (_G.flushStatics)
6299 _G.flushStatics = 0;
6308 _isPairUsed (iCode * ic, PAIR_ID pairId)
6314 if (bitVectBitValue (ic->rMask, D_IDX))
6316 if (bitVectBitValue (ic->rMask, E_IDX))
6326 fetchLitSpecial (asmop * aop, bool negate, bool xor)
6329 value *val = aop->aopu.aop_lit;
6331 wassert (aop->type == AOP_LIT);
6332 wassert (!IS_FLOAT (val->type));
6334 v = (unsigned long) floatFromVal (val);
6342 tsprintf (buffer, "!immedword", v);
6343 return gc_strdup (buffer);