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 /* otherwise subtract from zero */
1794 size = AOP_SIZE (IC_LEFT (ic));
1796 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
1798 /* Create a new asmop with value zero */
1799 asmop *azero = newAsmop (AOP_SIMPLELIT);
1800 azero->aopu.aop_simplelit = 0;
1802 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
1810 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
1811 emit2 ("ld a,!zero");
1812 emit2 ("sbc a,%s", l);
1813 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1816 /* if any remaining bytes in the result */
1817 /* we just need to propagate the sign */
1818 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
1823 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1827 /* release the aops */
1828 freeAsmop (IC_LEFT (ic), NULL, ic);
1829 freeAsmop (IC_RESULT (ic), NULL, ic);
1832 /*-----------------------------------------------------------------*/
1833 /* assignResultValue - */
1834 /*-----------------------------------------------------------------*/
1836 assignResultValue (operand * oper)
1838 int size = AOP_SIZE (oper);
1841 wassert (size <= 4);
1842 topInA = requiresHL (AOP (oper));
1846 wassert (size <= 2);
1848 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
1850 /* We do it the hard way here. */
1852 aopPut (AOP (oper), _fReturn[0], 0);
1853 aopPut (AOP (oper), _fReturn[1], 1);
1855 aopPut (AOP (oper), _fReturn[0], 2);
1856 aopPut (AOP (oper), _fReturn[1], 3);
1862 aopPut (AOP (oper), _fReturn[size], size);
1868 _saveRegsForCall(iCode *ic, int sendSetSize)
1871 o Stack parameters are pushed before this function enters
1872 o DE and BC may be used in this function.
1873 o HL and DE may be used to return the result.
1874 o HL and DE may be used to send variables.
1875 o DE and BC may be used to store the result value.
1876 o HL may be used in computing the sent value of DE
1877 o The iPushes for other parameters occur before any addSets
1879 Logic: (to be run inside the first iPush or if none, before sending)
1880 o Compute if DE and/or BC are in use over the call
1881 o Compute if DE is used in the send set
1882 o Compute if DE and/or BC are used to hold the result value
1883 o If (DE is used, or in the send set) and is not used in the result, push.
1884 o If BC is used and is not in the result, push
1886 o If DE is used in the send set, fetch
1887 o If HL is used in the send set, fetch
1891 if (_G.saves.saved == FALSE) {
1892 bool deInUse, bcInUse;
1894 bool bcInRet = FALSE, deInRet = FALSE;
1898 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
1902 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), z80_rUmaskForOp (IC_RESULT(ic)));
1906 /* Has no result, so in use is all of in use */
1911 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
1912 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
1914 deSending = (sendSetSize > 1);
1916 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
1918 if (bcInUse && bcInRet == FALSE) {
1920 _G.stack.pushedBC = TRUE;
1922 if (deInUse && deInRet == FALSE) {
1924 _G.stack.pushedDE = TRUE;
1927 _G.saves.saved = TRUE;
1930 /* Already saved. */
1934 /*-----------------------------------------------------------------*/
1935 /* genIpush - genrate code for pushing this gets a little complex */
1936 /*-----------------------------------------------------------------*/
1938 genIpush (iCode * ic)
1940 int size, offset = 0;
1943 /* if this is not a parm push : ie. it is spill push
1944 and spill push is always done on the local stack */
1947 wassertl(0, "Encountered an unsupported spill push.");
1951 if (_G.saves.saved == FALSE) {
1952 /* Caller saves, and this is the first iPush. */
1953 /* Scan ahead until we find the function that we are pushing parameters to.
1954 Count the number of addSets on the way to figure out what registers
1955 are used in the send set.
1958 iCode *walk = ic->next;
1961 if (walk->op == SEND) {
1964 else if (walk->op == CALL || walk->op == PCALL) {
1973 _saveRegsForCall(walk, nAddSets);
1976 /* Already saved by another iPush. */
1979 /* then do the push */
1980 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1982 size = AOP_SIZE (IC_LEFT (ic));
1984 if (isPair (AOP (IC_LEFT (ic))))
1986 _G.stack.pushed += 2;
1987 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
1993 fetchHL (AOP (IC_LEFT (ic)));
1995 spillPair (PAIR_HL);
1996 _G.stack.pushed += 2;
2001 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
2003 spillPair (PAIR_HL);
2004 _G.stack.pushed += 2;
2005 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 0);
2007 spillPair (PAIR_HL);
2008 _G.stack.pushed += 2;
2014 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2016 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2018 emit2 ("ld a,(%s)", l);
2022 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2023 emit2 ("ld a,%s", l);
2031 freeAsmop (IC_LEFT (ic), NULL, ic);
2034 /*-----------------------------------------------------------------*/
2035 /* genIpop - recover the registers: can happen only for spilling */
2036 /*-----------------------------------------------------------------*/
2038 genIpop (iCode * ic)
2043 /* if the temp was not pushed then */
2044 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2047 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2048 size = AOP_SIZE (IC_LEFT (ic));
2049 offset = (size - 1);
2050 if (isPair (AOP (IC_LEFT (ic))))
2052 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2060 spillPair (PAIR_HL);
2061 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2065 freeAsmop (IC_LEFT (ic), NULL, ic);
2068 /* This is quite unfortunate */
2070 setArea (int inHome)
2073 static int lastArea = 0;
2075 if (_G.in_home != inHome) {
2077 const char *sz = port->mem.code_name;
2078 port->mem.code_name = "HOME";
2079 emit2("!area", CODE_NAME);
2080 port->mem.code_name = sz;
2083 emit2("!area", CODE_NAME); */
2084 _G.in_home = inHome;
2095 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2099 symbol *sym = OP_SYMBOL (op);
2101 if (sym->isspilt || sym->nRegs == 0)
2104 aopOp (op, ic, FALSE, FALSE);
2107 if (aop->type == AOP_REG)
2110 for (i = 0; i < aop->size; i++)
2112 if (pairId == PAIR_DE)
2114 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2115 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2117 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2120 else if (pairId == PAIR_BC)
2122 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2123 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2125 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2135 freeAsmop (IC_LEFT (ic), NULL, ic);
2139 /** Emit the code for a call statement
2142 emitCall (iCode * ic, bool ispcall)
2144 sym_link *detype = getSpec (operandType (IC_LEFT (ic)));
2146 bitVect *rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
2148 /* if caller saves & we have not saved then */
2154 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2156 /* if send set is not empty then assign */
2161 int nSend = elementsInSet(_G.sendSet);
2162 bool swapped = FALSE;
2164 int _z80_sendOrder[] = {
2169 /* Check if the parameters are swapped. If so route through hl instead. */
2170 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2172 sic = setFirstItem(_G.sendSet);
2173 sic = setNextItem(_G.sendSet);
2175 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2176 /* The second send value is loaded from one the one that holds the first
2177 send, i.e. it is overwritten. */
2178 /* Cache the first in HL, and load the second from HL instead. */
2179 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2180 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2186 for (sic = setFirstItem (_G.sendSet); sic;
2187 sic = setNextItem (_G.sendSet))
2190 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2192 size = AOP_SIZE (IC_LEFT (sic));
2193 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2194 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2196 // PENDING: Mild hack
2197 if (swapped == TRUE && send == 1) {
2199 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2202 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2204 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2207 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2211 freeAsmop (IC_LEFT (sic), NULL, sic);
2218 if (IS_BANKEDCALL (detype))
2220 werror (W_INDIR_BANKED);
2222 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2224 if (isLitWord (AOP (IC_LEFT (ic))))
2226 emitDebug ("; Special case where the pCall is to a constant");
2227 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2231 symbol *rlbl = newiTempLabel (NULL);
2232 spillPair (PAIR_HL);
2233 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2235 _G.stack.pushed += 2;
2237 fetchHL (AOP (IC_LEFT (ic)));
2239 emit2 ("!tlabeldef", (rlbl->key + 100));
2240 _G.stack.pushed -= 2;
2242 freeAsmop (IC_LEFT (ic), NULL, ic);
2246 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2247 OP_SYMBOL (IC_LEFT (ic))->rname :
2248 OP_SYMBOL (IC_LEFT (ic))->name;
2249 if (IS_BANKEDCALL (detype))
2251 emit2 ("call banked_call");
2252 emit2 ("!dws", name);
2253 emit2 ("!dw !bankimmeds", name);
2258 emit2 ("call %s", name);
2263 /* Mark the regsiters as restored. */
2264 _G.saves.saved = FALSE;
2266 /* if we need assign a result value */
2267 if ((IS_ITEMP (IC_RESULT (ic)) &&
2268 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2269 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2270 IS_TRUE_SYMOP (IC_RESULT (ic)))
2273 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2275 assignResultValue (IC_RESULT (ic));
2277 freeAsmop (IC_RESULT (ic), NULL, ic);
2280 /* adjust the stack for parameters if required */
2283 int i = ic->parmBytes;
2285 _G.stack.pushed -= i;
2288 emit2 ("!ldaspsp", i);
2295 emit2 ("ld hl,#%d", i);
2296 emit2 ("add hl,sp");
2313 if (_G.stack.pushedDE)
2315 bool dInUse = bitVectBitValue(rInUse, D_IDX);
2316 bool eInUse = bitVectBitValue(rInUse, E_IDX);
2318 if (dInUse && eInUse)
2334 wassertl (0, "Neither D or E were in use but it was pushed.");
2336 _G.stack.pushedDE = FALSE;
2339 if (_G.stack.pushedBC)
2341 bool bInUse = bitVectBitValue(rInUse, B_IDX);
2342 bool cInUse = bitVectBitValue(rInUse, C_IDX);
2344 // If both B and C are used in the return value, then we won't get
2346 if (bInUse && cInUse)
2362 wassertl (0, "Neither B or C were in use but it was pushed.");
2364 _G.stack.pushedBC = FALSE;
2368 /*-----------------------------------------------------------------*/
2369 /* genCall - generates a call statement */
2370 /*-----------------------------------------------------------------*/
2372 genCall (iCode * ic)
2374 emitCall (ic, FALSE);
2377 /*-----------------------------------------------------------------*/
2378 /* genPcall - generates a call by pointer statement */
2379 /*-----------------------------------------------------------------*/
2381 genPcall (iCode * ic)
2383 emitCall (ic, TRUE);
2386 /*-----------------------------------------------------------------*/
2387 /* resultRemat - result is rematerializable */
2388 /*-----------------------------------------------------------------*/
2390 resultRemat (iCode * ic)
2392 if (SKIP_IC (ic) || ic->op == IFX)
2395 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2397 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2398 if (sym->remat && !POINTER_SET (ic))
2405 extern set *publics;
2407 /*-----------------------------------------------------------------*/
2408 /* genFunction - generated code for function entry */
2409 /*-----------------------------------------------------------------*/
2411 genFunction (iCode * ic)
2413 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2417 bool bcInUse = FALSE;
2418 bool deInUse = FALSE;
2421 setArea (IS_NONBANKED (sym->etype));
2423 /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
2426 _G.receiveOffset = 0;
2430 if (!IS_STATIC (sym->etype))
2432 addSetIfnotP (&publics, sym);
2436 /* Record the last function name for debugging. */
2437 _G.lastFunctionName = sym->rname;
2439 /* Create the function header */
2440 emit2 ("!functionheader", sym->name);
2441 /* PENDING: portability. */
2442 emit2 ("__%s_start:", sym->rname);
2443 emit2 ("!functionlabeldef", sym->rname);
2445 if (options.profile)
2447 emit2 ("!profileenter");
2450 fetype = getSpec (operandType (IC_LEFT (ic)));
2452 /* if critical function then turn interrupts off */
2453 if (SPEC_CRTCL (fetype))
2456 /* if this is an interrupt service routine then save all potentially used registers. */
2457 if (IS_ISR (sym->etype))
2462 /* PENDING: callee-save etc */
2464 _G.stack.param_offset = 0;
2467 /* Detect which registers are used. */
2471 for (i = 0; i < sym->regsUsed->size; i++)
2473 if (bitVectBitValue (sym->regsUsed, i))
2487 /* Other systems use DE as a temporary. */
2498 _G.stack.param_offset += 2;
2501 _G.stack.pushedBC = bcInUse;
2506 _G.stack.param_offset += 2;
2509 _G.stack.pushedDE = deInUse;
2512 /* adjust the stack for the function */
2513 _G.stack.last = sym->stack;
2516 emit2 ("!enterx", sym->stack);
2519 _G.stack.offset = sym->stack;
2522 /*-----------------------------------------------------------------*/
2523 /* genEndFunction - generates epilogue for functions */
2524 /*-----------------------------------------------------------------*/
2526 genEndFunction (iCode * ic)
2528 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2530 if (IS_ISR (sym->etype))
2536 if (SPEC_CRTCL (sym->etype))
2539 /* PENDING: calleeSave */
2541 if (_G.stack.offset)
2543 emit2 ("!leavex", _G.stack.offset);
2551 if (_G.stack.pushedDE)
2554 _G.stack.pushedDE = FALSE;
2557 if (_G.stack.pushedDE)
2560 _G.stack.pushedDE = FALSE;
2564 if (options.profile)
2566 emit2 ("!profileexit");
2570 /* Both baned and non-banked just ret */
2573 /* PENDING: portability. */
2574 emit2 ("__%s_end:", sym->rname);
2576 _G.flushStatics = 1;
2577 _G.stack.pushed = 0;
2578 _G.stack.offset = 0;
2581 /*-----------------------------------------------------------------*/
2582 /* genRet - generate code for return statement */
2583 /*-----------------------------------------------------------------*/
2588 /* Errk. This is a hack until I can figure out how
2589 to cause dehl to spill on a call */
2590 int size, offset = 0;
2592 /* if we have no return value then
2593 just generate the "ret" */
2597 /* we have something to return then
2598 move the return value into place */
2599 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2600 size = AOP_SIZE (IC_LEFT (ic));
2602 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
2606 emit2 ("ld de,%s", l);
2610 emit2 ("ld hl,%s", l);
2615 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
2617 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
2618 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
2624 l = aopGet (AOP (IC_LEFT (ic)), offset,
2626 if (strcmp (_fReturn[offset], l))
2627 emit2 ("ld %s,%s", _fReturn[offset++], l);
2631 freeAsmop (IC_LEFT (ic), NULL, ic);
2634 /* generate a jump to the return label
2635 if the next is not the return statement */
2636 if (!(ic->next && ic->next->op == LABEL &&
2637 IC_LABEL (ic->next) == returnLabel))
2639 emit2 ("jp !tlabel", returnLabel->key + 100);
2642 /*-----------------------------------------------------------------*/
2643 /* genLabel - generates a label */
2644 /*-----------------------------------------------------------------*/
2646 genLabel (iCode * ic)
2648 /* special case never generate */
2649 if (IC_LABEL (ic) == entryLabel)
2652 emitLabel (IC_LABEL (ic)->key + 100);
2655 /*-----------------------------------------------------------------*/
2656 /* genGoto - generates a ljmp */
2657 /*-----------------------------------------------------------------*/
2659 genGoto (iCode * ic)
2661 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
2664 /*-----------------------------------------------------------------*/
2665 /* genPlusIncr :- does addition with increment if possible */
2666 /*-----------------------------------------------------------------*/
2668 genPlusIncr (iCode * ic)
2670 unsigned int icount;
2671 unsigned int size = getDataSize (IC_RESULT (ic));
2672 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
2674 /* will try to generate an increment */
2675 /* if the right side is not a literal
2677 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
2680 emitDebug ("; genPlusIncr");
2682 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
2684 /* If result is a pair */
2685 if (resultId != PAIR_INVALID)
2687 if (isLitWord (AOP (IC_LEFT (ic))))
2689 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
2692 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
2694 fetchPair (resultId, AOP (IC_RIGHT (ic)));
2695 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
2701 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2705 movLeft2Result (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0);
2706 movLeft2Result (IC_LEFT (ic), 1, IC_RESULT (ic), 1, 0);
2710 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
2715 /* if the literal value of the right hand side
2716 is greater than 4 then it is not worth it */
2720 /* if increment 16 bits in register */
2721 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
2727 symbol *tlbl = NULL;
2728 tlbl = newiTempLabel (NULL);
2731 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
2734 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
2737 emitLabel (tlbl->key + 100);
2741 /* if the sizes are greater than 1 then we cannot */
2742 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
2743 AOP_SIZE (IC_LEFT (ic)) > 1)
2746 /* we can if the aops of the left & result match or
2747 if they are in registers and the registers are the
2749 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2753 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
2761 /*-----------------------------------------------------------------*/
2762 /* outBitAcc - output a bit in acc */
2763 /*-----------------------------------------------------------------*/
2765 outBitAcc (operand * result)
2767 symbol *tlbl = newiTempLabel (NULL);
2768 /* if the result is a bit */
2769 if (AOP_TYPE (result) == AOP_CRY)
2775 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
2776 emit2 ("ld a,!one");
2777 emitLabel (tlbl->key + 100);
2782 /*-----------------------------------------------------------------*/
2783 /* genPlus - generates code for addition */
2784 /*-----------------------------------------------------------------*/
2786 genPlus (iCode * ic)
2788 int size, offset = 0;
2790 /* special cases :- */
2792 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2793 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
2794 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2796 /* Swap the left and right operands if:
2798 if literal, literal on the right or
2799 if left requires ACC or right is already
2802 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
2803 (AOP_NEEDSACC (IC_LEFT (ic))) ||
2804 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
2806 operand *t = IC_RIGHT (ic);
2807 IC_RIGHT (ic) = IC_LEFT (ic);
2811 /* if both left & right are in bit
2813 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
2814 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
2820 /* if left in bit space & right literal */
2821 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
2822 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
2824 /* Can happen I guess */
2828 /* if I can do an increment instead
2829 of add then GOOD for ME */
2830 if (genPlusIncr (ic) == TRUE)
2833 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
2835 size = getDataSize (IC_RESULT (ic));
2837 /* Special case when left and right are constant */
2838 if (isPair (AOP (IC_RESULT (ic))))
2841 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
2842 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
2844 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
2850 sprintf (buffer, "#(%s + %s)", left, right);
2851 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
2856 if (isPair (AOP (IC_RIGHT (ic))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
2858 /* Fetch into HL then do the add */
2859 spillPair (PAIR_HL);
2860 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
2861 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
2866 ld hl,sp+n trashes C so we cant afford to do it during an
2867 add with stack based varibles. Worst case is:
2880 So you cant afford to load up hl if either left, right, or result
2881 is on the stack (*sigh*) The alt is:
2889 Combinations in here are:
2890 * If left or right are in bc then the loss is small - trap later
2891 * If the result is in bc then the loss is also small
2895 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
2896 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
2897 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
2899 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
2900 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
2901 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
2902 AOP_SIZE (IC_RIGHT (ic)) <= 2))
2904 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
2906 /* Swap left and right */
2907 operand *t = IC_RIGHT (ic);
2908 IC_RIGHT (ic) = IC_LEFT (ic);
2911 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
2913 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
2914 emit2 ("add hl,bc");
2918 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
2919 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
2920 emit2 ("add hl,de");
2922 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
2928 /* Be paranoid on the GB with 4 byte variables due to how C
2929 can be trashed by lda hl,n(sp).
2931 _gbz80_emitAddSubLong (ic, TRUE);
2938 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
2940 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
2943 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2946 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2950 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
2953 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2956 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
2958 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2962 freeAsmop (IC_LEFT (ic), NULL, ic);
2963 freeAsmop (IC_RIGHT (ic), NULL, ic);
2964 freeAsmop (IC_RESULT (ic), NULL, ic);
2968 /*-----------------------------------------------------------------*/
2969 /* genMinusDec :- does subtraction with deccrement if possible */
2970 /*-----------------------------------------------------------------*/
2972 genMinusDec (iCode * ic)
2974 unsigned int icount;
2975 unsigned int size = getDataSize (IC_RESULT (ic));
2977 /* will try to generate an increment */
2978 /* if the right side is not a literal we cannot */
2979 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
2982 /* if the literal value of the right hand side
2983 is greater than 4 then it is not worth it */
2984 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
2987 size = getDataSize (IC_RESULT (ic));
2989 /* if decrement 16 bits in register */
2990 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
2991 (size > 1) && isPair (AOP (IC_RESULT (ic))))
2994 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
2998 /* If result is a pair */
2999 if (isPair (AOP (IC_RESULT (ic))))
3001 movLeft2Result (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0);
3002 movLeft2Result (IC_LEFT (ic), 1, IC_RESULT (ic), 1, 0);
3004 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3008 /* if increment 16 bits in register */
3009 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3013 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3016 emit2 ("dec %s", _getTempPairName());
3019 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3025 /* if the sizes are greater than 1 then we cannot */
3026 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3027 AOP_SIZE (IC_LEFT (ic)) > 1)
3030 /* we can if the aops of the left & result match or if they are in
3031 registers and the registers are the same */
3032 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3035 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3042 /*-----------------------------------------------------------------*/
3043 /* genMinus - generates code for subtraction */
3044 /*-----------------------------------------------------------------*/
3046 genMinus (iCode * ic)
3048 int size, offset = 0;
3049 unsigned long lit = 0L;
3051 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3052 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3053 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3055 /* special cases :- */
3056 /* if both left & right are in bit space */
3057 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3058 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3064 /* if I can do an decrement instead of subtract then GOOD for ME */
3065 if (genMinusDec (ic) == TRUE)
3068 size = getDataSize (IC_RESULT (ic));
3070 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3075 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3079 /* Same logic as genPlus */
3082 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3083 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3084 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3086 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3087 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3088 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3089 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3091 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3092 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3094 if (left == PAIR_INVALID && right == PAIR_INVALID)
3099 else if (right == PAIR_INVALID)
3101 else if (left == PAIR_INVALID)
3104 fetchPair (left, AOP (IC_LEFT (ic)));
3105 /* Order is important. Right may be HL */
3106 fetchPair (right, AOP (IC_RIGHT (ic)));
3108 emit2 ("ld a,%s", _pairs[left].l);
3109 emit2 ("sub a,%s", _pairs[right].l);
3111 emit2 ("ld a,%s", _pairs[left].h);
3112 emit2 ("sbc a,%s", _pairs[right].h);
3114 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3115 aopPut (AOP (IC_RESULT (ic)), "e", 0);
3121 /* Be paranoid on the GB with 4 byte variables due to how C
3122 can be trashed by lda hl,n(sp).
3124 _gbz80_emitAddSubLong (ic, FALSE);
3129 /* if literal, add a,#-lit, else normal subb */
3132 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3133 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3137 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3140 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3144 /* first add without previous c */
3146 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
3148 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3150 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3153 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3154 AOP_SIZE (IC_LEFT (ic)) == 3 &&
3155 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3159 freeAsmop (IC_LEFT (ic), NULL, ic);
3160 freeAsmop (IC_RIGHT (ic), NULL, ic);
3161 freeAsmop (IC_RESULT (ic), NULL, ic);
3164 /*-----------------------------------------------------------------*/
3165 /* genMult - generates code for multiplication */
3166 /*-----------------------------------------------------------------*/
3168 genMult (iCode * ic)
3170 /* Shouldn't occur - all done through function calls */
3174 /*-----------------------------------------------------------------*/
3175 /* genDiv - generates code for division */
3176 /*-----------------------------------------------------------------*/
3180 /* Shouldn't occur - all done through function calls */
3184 /*-----------------------------------------------------------------*/
3185 /* genMod - generates code for division */
3186 /*-----------------------------------------------------------------*/
3190 /* Shouldn't occur - all done through function calls */
3194 /*-----------------------------------------------------------------*/
3195 /* genIfxJump :- will create a jump depending on the ifx */
3196 /*-----------------------------------------------------------------*/
3198 genIfxJump (iCode * ic, char *jval)
3203 /* if true label then we jump if condition
3207 jlbl = IC_TRUE (ic);
3208 if (!strcmp (jval, "a"))
3212 else if (!strcmp (jval, "c"))
3216 else if (!strcmp (jval, "nc"))
3222 /* The buffer contains the bit on A that we should test */
3228 /* false label is present */
3229 jlbl = IC_FALSE (ic);
3230 if (!strcmp (jval, "a"))
3234 else if (!strcmp (jval, "c"))
3238 else if (!strcmp (jval, "nc"))
3244 /* The buffer contains the bit on A that we should test */
3248 /* Z80 can do a conditional long jump */
3249 if (!strcmp (jval, "a"))
3253 else if (!strcmp (jval, "c"))
3256 else if (!strcmp (jval, "nc"))
3261 emit2 ("bit %s,a", jval);
3263 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
3265 /* mark the icode as generated */
3271 _getPairIdName (PAIR_ID id)
3273 return _pairs[id].name;
3277 /** Generic compare for > or <
3280 genCmp (operand * left, operand * right,
3281 operand * result, iCode * ifx, int sign)
3283 int size, offset = 0;
3284 unsigned long lit = 0L;
3285 bool swap_sense = FALSE;
3287 /* if left & right are bit variables */
3288 if (AOP_TYPE (left) == AOP_CRY &&
3289 AOP_TYPE (right) == AOP_CRY)
3291 /* Cant happen on the Z80 */
3296 /* subtract right from left if at the
3297 end the carry flag is set then we know that
3298 left is greater than right */
3299 size = max (AOP_SIZE (left), AOP_SIZE (right));
3301 /* if unsigned char cmp with lit, just compare */
3303 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
3305 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3308 emit2 ("xor a,!immedbyte", 0x80);
3309 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
3312 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3314 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
3316 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
3317 // Pull left into DE and right into HL
3318 aopGet (AOP(left), LSB, FALSE);
3321 aopGet (AOP(right), LSB, FALSE);
3325 if (size == 0 && sign)
3327 // Highest byte when signed needs the bits flipped
3330 emit2 ("ld a,(de)");
3331 emit2 ("xor #0x80");
3333 emit2 ("ld a,(hl)");
3334 emit2 ("xor #0x80");
3338 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
3342 emit2 ("ld a,(de)");
3343 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
3353 spillPair (PAIR_HL);
3358 // PENDING: Doesn't work around zero
3362 If the left or the right is a lit:
3363 Load -lit into HL, add to right via, check sense.
3365 if (IS_GB && size == 2 && (AOP_TYPE (right) == AOP_LIT || AOP_TYPE (left) == AOP_LIT))
3367 PAIR_ID id = PAIR_DE;
3368 asmop *lit = AOP (right);
3369 asmop *op = AOP (left);
3372 if (AOP_TYPE (left) == AOP_LIT)
3380 emit2 ("ld e,%s", aopGet (op, 0, 0));
3381 emit2 ("ld a,%s", aopGet (op, 1, 0));
3382 emit2 ("xor a,!immedbyte", 0x80);
3387 id = getPairId (op);
3388 if (id == PAIR_INVALID)
3390 fetchPair (PAIR_DE, op);
3394 spillPair (PAIR_HL);
3395 emit2 ("ld hl,%s", fetchLitSpecial (lit, TRUE, sign));
3396 emit2 ("add hl,%s", _getPairIdName (id));
3400 if (AOP_TYPE (right) == AOP_LIT)
3402 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3403 /* optimize if(x < 0) or if(x >= 0) */
3408 /* No sign so it's always false */
3413 /* Just load in the top most bit */
3414 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
3415 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
3417 genIfxJump (ifx, "7");
3428 /* First setup h and l contaning the top most bytes XORed */
3429 bool fDidXor = FALSE;
3430 if (AOP_TYPE (left) == AOP_LIT)
3432 unsigned long lit = (unsigned long)
3433 floatFromVal (AOP (left)->aopu.aop_lit);
3434 emit2 ("ld %s,!immedbyte", _fTmp[0],
3435 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3439 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
3440 emit2 ("xor a,!immedbyte", 0x80);
3441 emit2 ("ld %s,a", _fTmp[0]);
3444 if (AOP_TYPE (right) == AOP_LIT)
3446 unsigned long lit = (unsigned long)
3447 floatFromVal (AOP (right)->aopu.aop_lit);
3448 emit2 ("ld %s,!immedbyte", _fTmp[1],
3449 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3453 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
3454 emit2 ("xor a,!immedbyte", 0x80);
3455 emit2 ("ld %s,a", _fTmp[1]);
3461 /* Do a long subtract */
3464 _moveA (aopGet (AOP (left), offset, FALSE));
3466 if (sign && size == 0)
3468 emit2 ("ld a,%s", _fTmp[0]);
3469 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
3473 /* Subtract through, propagating the carry */
3474 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset++, FALSE));
3481 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
3483 outBitCLong (result, swap_sense);
3487 /* if the result is used in the next
3488 ifx conditional branch then generate
3489 code a little differently */
3491 genIfxJump (ifx, swap_sense ? "nc" : "c");
3493 outBitCLong (result, swap_sense);
3494 /* leave the result in acc */
3498 /*-----------------------------------------------------------------*/
3499 /* genCmpGt :- greater than comparison */
3500 /*-----------------------------------------------------------------*/
3502 genCmpGt (iCode * ic, iCode * ifx)
3504 operand *left, *right, *result;
3505 sym_link *letype, *retype;
3508 left = IC_LEFT (ic);
3509 right = IC_RIGHT (ic);
3510 result = IC_RESULT (ic);
3512 letype = getSpec (operandType (left));
3513 retype = getSpec (operandType (right));
3514 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
3515 /* assign the amsops */
3516 aopOp (left, ic, FALSE, FALSE);
3517 aopOp (right, ic, FALSE, FALSE);
3518 aopOp (result, ic, TRUE, FALSE);
3520 genCmp (right, left, result, ifx, sign);
3522 freeAsmop (left, NULL, ic);
3523 freeAsmop (right, NULL, ic);
3524 freeAsmop (result, NULL, ic);
3527 /*-----------------------------------------------------------------*/
3528 /* genCmpLt - less than comparisons */
3529 /*-----------------------------------------------------------------*/
3531 genCmpLt (iCode * ic, iCode * ifx)
3533 operand *left, *right, *result;
3534 sym_link *letype, *retype;
3537 left = IC_LEFT (ic);
3538 right = IC_RIGHT (ic);
3539 result = IC_RESULT (ic);
3541 letype = getSpec (operandType (left));
3542 retype = getSpec (operandType (right));
3543 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
3545 /* assign the amsops */
3546 aopOp (left, ic, FALSE, FALSE);
3547 aopOp (right, ic, FALSE, FALSE);
3548 aopOp (result, ic, TRUE, FALSE);
3550 genCmp (left, right, result, ifx, sign);
3552 freeAsmop (left, NULL, ic);
3553 freeAsmop (right, NULL, ic);
3554 freeAsmop (result, NULL, ic);
3557 /*-----------------------------------------------------------------*/
3558 /* gencjneshort - compare and jump if not equal */
3559 /*-----------------------------------------------------------------*/
3561 gencjneshort (operand * left, operand * right, symbol * lbl)
3563 int size = max (AOP_SIZE (left), AOP_SIZE (right));
3565 unsigned long lit = 0L;
3567 /* Swap the left and right if it makes the computation easier */
3568 if (AOP_TYPE (left) == AOP_LIT)
3575 if (AOP_TYPE (right) == AOP_LIT)
3576 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3578 /* if the right side is a literal then anything goes */
3579 if (AOP_TYPE (right) == AOP_LIT &&
3580 AOP_TYPE (left) != AOP_DIR)
3584 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3591 emit2 ("or a,%s", aopGet (AOP (left), offset, FALSE));
3598 emit2 ("jp nz,!tlabel", lbl->key + 100);
3604 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3605 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
3608 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
3609 emit2 ("jp nz,!tlabel", lbl->key + 100);
3614 /* if the right side is in a register or in direct space or
3615 if the left is a pointer register & right is not */
3616 else if (AOP_TYPE (right) == AOP_REG ||
3617 AOP_TYPE (right) == AOP_DIR ||
3618 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
3622 _moveA (aopGet (AOP (left), offset, FALSE));
3623 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
3624 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
3626 emit2 ("jp nz,!tlabel", lbl->key + 100);
3629 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3630 emit2 ("jp nz,!tlabel", lbl->key + 100);
3637 /* right is a pointer reg need both a & b */
3638 /* PENDING: is this required? */
3641 _moveA (aopGet (AOP (right), offset, FALSE));
3642 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
3643 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
3649 /*-----------------------------------------------------------------*/
3650 /* gencjne - compare and jump if not equal */
3651 /*-----------------------------------------------------------------*/
3653 gencjne (operand * left, operand * right, symbol * lbl)
3655 symbol *tlbl = newiTempLabel (NULL);
3657 gencjneshort (left, right, lbl);
3660 emit2 ("ld a,!one");
3661 emit2 ("!shortjp !tlabel", tlbl->key + 100);
3662 emitLabel (lbl->key + 100);
3664 emitLabel (tlbl->key + 100);
3667 /*-----------------------------------------------------------------*/
3668 /* genCmpEq - generates code for equal to */
3669 /*-----------------------------------------------------------------*/
3671 genCmpEq (iCode * ic, iCode * ifx)
3673 operand *left, *right, *result;
3675 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
3676 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
3677 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
3679 emitDebug ("; genCmpEq: left %u, right %u, result %u\n", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
3681 /* Swap operands if it makes the operation easier. ie if:
3682 1. Left is a literal.
3684 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
3686 operand *t = IC_RIGHT (ic);
3687 IC_RIGHT (ic) = IC_LEFT (ic);
3691 if (ifx && !AOP_SIZE (result))
3694 /* if they are both bit variables */
3695 if (AOP_TYPE (left) == AOP_CRY &&
3696 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
3702 tlbl = newiTempLabel (NULL);
3703 gencjneshort (left, right, tlbl);
3706 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
3707 emitLabel (tlbl->key + 100);
3711 /* PENDING: do this better */
3712 symbol *lbl = newiTempLabel (NULL);
3713 emit2 ("!shortjp !tlabel", lbl->key + 100);
3714 emitLabel (tlbl->key + 100);
3715 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
3716 emitLabel (lbl->key + 100);
3719 /* mark the icode as generated */
3724 /* if they are both bit variables */
3725 if (AOP_TYPE (left) == AOP_CRY &&
3726 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
3732 gencjne (left, right, newiTempLabel (NULL));
3733 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
3739 genIfxJump (ifx, "a");
3742 /* if the result is used in an arithmetic operation
3743 then put the result in place */
3744 if (AOP_TYPE (result) != AOP_CRY)
3748 /* leave the result in acc */
3752 freeAsmop (left, NULL, ic);
3753 freeAsmop (right, NULL, ic);
3754 freeAsmop (result, NULL, ic);
3757 /*-----------------------------------------------------------------*/
3758 /* ifxForOp - returns the icode containing the ifx for operand */
3759 /*-----------------------------------------------------------------*/
3761 ifxForOp (operand * op, iCode * ic)
3763 /* if true symbol then needs to be assigned */
3764 if (IS_TRUE_SYMOP (op))
3767 /* if this has register type condition and
3768 the next instruction is ifx with the same operand
3769 and live to of the operand is upto the ifx only then */
3771 ic->next->op == IFX &&
3772 IC_COND (ic->next)->key == op->key &&
3773 OP_SYMBOL (op)->liveTo <= ic->next->seq)
3779 /*-----------------------------------------------------------------*/
3780 /* genAndOp - for && operation */
3781 /*-----------------------------------------------------------------*/
3783 genAndOp (iCode * ic)
3785 operand *left, *right, *result;
3788 /* note here that && operations that are in an if statement are
3789 taken away by backPatchLabels only those used in arthmetic
3790 operations remain */
3791 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
3792 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
3793 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
3795 /* if both are bit variables */
3796 if (AOP_TYPE (left) == AOP_CRY &&
3797 AOP_TYPE (right) == AOP_CRY)
3803 tlbl = newiTempLabel (NULL);
3805 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3807 emitLabel (tlbl->key + 100);
3811 freeAsmop (left, NULL, ic);
3812 freeAsmop (right, NULL, ic);
3813 freeAsmop (result, NULL, ic);
3816 /*-----------------------------------------------------------------*/
3817 /* genOrOp - for || operation */
3818 /*-----------------------------------------------------------------*/
3820 genOrOp (iCode * ic)
3822 operand *left, *right, *result;
3825 /* note here that || operations that are in an
3826 if statement are taken away by backPatchLabels
3827 only those used in arthmetic operations remain */
3828 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
3829 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
3830 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
3832 /* if both are bit variables */
3833 if (AOP_TYPE (left) == AOP_CRY &&
3834 AOP_TYPE (right) == AOP_CRY)
3840 tlbl = newiTempLabel (NULL);
3842 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3844 emitLabel (tlbl->key + 100);
3848 freeAsmop (left, NULL, ic);
3849 freeAsmop (right, NULL, ic);
3850 freeAsmop (result, NULL, ic);
3853 /*-----------------------------------------------------------------*/
3854 /* isLiteralBit - test if lit == 2^n */
3855 /*-----------------------------------------------------------------*/
3857 isLiteralBit (unsigned long lit)
3859 unsigned long pw[32] =
3860 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
3861 0x100L, 0x200L, 0x400L, 0x800L,
3862 0x1000L, 0x2000L, 0x4000L, 0x8000L,
3863 0x10000L, 0x20000L, 0x40000L, 0x80000L,
3864 0x100000L, 0x200000L, 0x400000L, 0x800000L,
3865 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
3866 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
3869 for (idx = 0; idx < 32; idx++)
3875 /*-----------------------------------------------------------------*/
3876 /* jmpTrueOrFalse - */
3877 /*-----------------------------------------------------------------*/
3879 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
3881 // ugly but optimized by peephole
3884 symbol *nlbl = newiTempLabel (NULL);
3885 emit2 ("jp !tlabel", nlbl->key + 100);
3886 emitLabel (tlbl->key + 100);
3887 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
3888 emitLabel (nlbl->key + 100);
3892 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
3893 emitLabel (tlbl->key + 100);
3898 /*-----------------------------------------------------------------*/
3899 /* genAnd - code for and */
3900 /*-----------------------------------------------------------------*/
3902 genAnd (iCode * ic, iCode * ifx)
3904 operand *left, *right, *result;
3905 int size, offset = 0;
3906 unsigned long lit = 0L;
3909 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
3910 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
3911 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
3914 emitDebug ("; Type res[%d] = l[%d]&r[%d]",
3916 AOP_TYPE (left), AOP_TYPE (right));
3917 emitDebug ("; Size res[%d] = l[%d]&r[%d]",
3919 AOP_SIZE (left), AOP_SIZE (right));
3922 /* if left is a literal & right is not then exchange them */
3923 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
3924 AOP_NEEDSACC (left))
3926 operand *tmp = right;
3931 /* if result = right then exchange them */
3932 if (sameRegs (AOP (result), AOP (right)))
3934 operand *tmp = right;
3939 /* if right is bit then exchange them */
3940 if (AOP_TYPE (right) == AOP_CRY &&
3941 AOP_TYPE (left) != AOP_CRY)
3943 operand *tmp = right;
3947 if (AOP_TYPE (right) == AOP_LIT)
3948 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3950 size = AOP_SIZE (result);
3952 if (AOP_TYPE (left) == AOP_CRY)
3958 // if(val & 0xZZ) - size = 0, ifx != FALSE -
3959 // bit = val & 0xZZ - size = 1, ifx = FALSE -
3960 if ((AOP_TYPE (right) == AOP_LIT) &&
3961 (AOP_TYPE (result) == AOP_CRY) &&
3962 (AOP_TYPE (left) != AOP_CRY))
3964 int posbit = isLiteralBit (lit);
3969 _moveA (aopGet (AOP (left), posbit >> 3, FALSE));
3974 emit2 ("mov c,acc.%d", posbit & 0x07);
3981 sprintf (buffer, "%d", posbit & 0x07);
3982 genIfxJump (ifx, buffer);
3993 symbol *tlbl = newiTempLabel (NULL);
3994 int sizel = AOP_SIZE (left);
4002 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
4004 _moveA (aopGet (AOP (left), offset, FALSE));
4006 if ((posbit = isLiteralBit (bytelit)) != 0)
4009 emit2 ("jb acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
4013 if (bytelit != 0x0FFL)
4015 aopGet (AOP (right), offset, FALSE));
4019 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4024 // bit = left & literal
4028 emit2 ("!tlabeldef", tlbl->key + 100);
4030 // if(left & literal)
4034 jmpTrueOrFalse (ifx, tlbl);
4042 /* if left is same as result */
4043 if (sameRegs (AOP (result), AOP (left)))
4045 for (; size--; offset++)
4047 if (AOP_TYPE (right) == AOP_LIT)
4049 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4054 aopPut (AOP (result), "!zero", offset);
4057 _moveA (aopGet (AOP (left), offset, FALSE));
4059 aopGet (AOP (right), offset, FALSE));
4060 aopPut (AOP (left), "a", offset);
4067 if (AOP_TYPE (left) == AOP_ACC)
4073 _moveA (aopGet (AOP (left), offset, FALSE));
4075 aopGet (AOP (right), offset, FALSE));
4076 aopPut (AOP (left), "a", offset);
4083 // left & result in different registers
4084 if (AOP_TYPE (result) == AOP_CRY)
4090 for (; (size--); offset++)
4093 // result = left & right
4094 if (AOP_TYPE (right) == AOP_LIT)
4096 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4098 aopPut (AOP (result),
4099 aopGet (AOP (left), offset, FALSE),
4103 else if (bytelit == 0)
4105 aopPut (AOP (result), "!zero", offset);
4109 // faster than result <- left, anl result,right
4110 // and better if result is SFR
4111 if (AOP_TYPE (left) == AOP_ACC)
4112 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4115 _moveA (aopGet (AOP (left), offset, FALSE));
4117 aopGet (AOP (right), offset, FALSE));
4119 aopPut (AOP (result), "a", offset);
4126 freeAsmop (left, NULL, ic);
4127 freeAsmop (right, NULL, ic);
4128 freeAsmop (result, NULL, ic);
4131 /*-----------------------------------------------------------------*/
4132 /* genOr - code for or */
4133 /*-----------------------------------------------------------------*/
4135 genOr (iCode * ic, iCode * ifx)
4137 operand *left, *right, *result;
4138 int size, offset = 0;
4139 unsigned long lit = 0L;
4141 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4142 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4143 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4146 emitDebug ("; Type res[%d] = l[%d]&r[%d]",
4148 AOP_TYPE (left), AOP_TYPE (right));
4149 emitDebug ("; Size res[%d] = l[%d]&r[%d]",
4151 AOP_SIZE (left), AOP_SIZE (right));
4154 /* if left is a literal & right is not then exchange them */
4155 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4156 AOP_NEEDSACC (left))
4158 operand *tmp = right;
4163 /* if result = right then exchange them */
4164 if (sameRegs (AOP (result), AOP (right)))
4166 operand *tmp = right;
4171 /* if right is bit then exchange them */
4172 if (AOP_TYPE (right) == AOP_CRY &&
4173 AOP_TYPE (left) != AOP_CRY)
4175 operand *tmp = right;
4179 if (AOP_TYPE (right) == AOP_LIT)
4180 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4182 size = AOP_SIZE (result);
4184 if (AOP_TYPE (left) == AOP_CRY)
4190 if ((AOP_TYPE (right) == AOP_LIT) &&
4191 (AOP_TYPE (result) == AOP_CRY) &&
4192 (AOP_TYPE (left) != AOP_CRY))
4198 /* if left is same as result */
4199 if (sameRegs (AOP (result), AOP (left)))
4201 for (; size--; offset++)
4203 if (AOP_TYPE (right) == AOP_LIT)
4205 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4209 _moveA (aopGet (AOP (left), offset, FALSE));
4211 aopGet (AOP (right), offset, FALSE));
4212 aopPut (AOP (result), "a", offset);
4217 if (AOP_TYPE (left) == AOP_ACC)
4218 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4221 _moveA (aopGet (AOP (left), offset, FALSE));
4223 aopGet (AOP (right), offset, FALSE));
4224 aopPut (AOP (result), "a", offset);
4231 // left & result in different registers
4232 if (AOP_TYPE (result) == AOP_CRY)
4237 for (; (size--); offset++)
4240 // result = left & right
4241 if (AOP_TYPE (right) == AOP_LIT)
4243 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4245 aopPut (AOP (result),
4246 aopGet (AOP (left), offset, FALSE),
4251 // faster than result <- left, anl result,right
4252 // and better if result is SFR
4253 if (AOP_TYPE (left) == AOP_ACC)
4254 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4257 _moveA (aopGet (AOP (left), offset, FALSE));
4259 aopGet (AOP (right), offset, FALSE));
4261 aopPut (AOP (result), "a", offset);
4262 /* PENDING: something weird is going on here. Add exception. */
4263 if (AOP_TYPE (result) == AOP_ACC)
4269 freeAsmop (left, NULL, ic);
4270 freeAsmop (right, NULL, ic);
4271 freeAsmop (result, NULL, ic);
4274 /*-----------------------------------------------------------------*/
4275 /* genXor - code for xclusive or */
4276 /*-----------------------------------------------------------------*/
4278 genXor (iCode * ic, iCode * ifx)
4280 operand *left, *right, *result;
4281 int size, offset = 0;
4282 unsigned long lit = 0L;
4284 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4285 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4286 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4288 /* if left is a literal & right is not then exchange them */
4289 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4290 AOP_NEEDSACC (left))
4292 operand *tmp = right;
4297 /* if result = right then exchange them */
4298 if (sameRegs (AOP (result), AOP (right)))
4300 operand *tmp = right;
4305 /* if right is bit then exchange them */
4306 if (AOP_TYPE (right) == AOP_CRY &&
4307 AOP_TYPE (left) != AOP_CRY)
4309 operand *tmp = right;
4313 if (AOP_TYPE (right) == AOP_LIT)
4314 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4316 size = AOP_SIZE (result);
4318 if (AOP_TYPE (left) == AOP_CRY)
4324 if ((AOP_TYPE (right) == AOP_LIT) &&
4325 (AOP_TYPE (result) == AOP_CRY) &&
4326 (AOP_TYPE (left) != AOP_CRY))
4332 /* if left is same as result */
4333 if (sameRegs (AOP (result), AOP (left)))
4335 for (; size--; offset++)
4337 if (AOP_TYPE (right) == AOP_LIT)
4339 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4343 _moveA (aopGet (AOP (right), offset, FALSE));
4345 aopGet (AOP (left), offset, FALSE));
4346 aopPut (AOP (result), "a", offset);
4351 if (AOP_TYPE (left) == AOP_ACC)
4353 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4357 _moveA (aopGet (AOP (right), offset, FALSE));
4359 aopGet (AOP (left), offset, FALSE));
4360 aopPut (AOP (result), "a", 0);
4367 // left & result in different registers
4368 if (AOP_TYPE (result) == AOP_CRY)
4373 for (; (size--); offset++)
4376 // result = left & right
4377 if (AOP_TYPE (right) == AOP_LIT)
4379 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4381 aopPut (AOP (result),
4382 aopGet (AOP (left), offset, FALSE),
4387 // faster than result <- left, anl result,right
4388 // and better if result is SFR
4389 if (AOP_TYPE (left) == AOP_ACC)
4391 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4395 _moveA (aopGet (AOP (right), offset, FALSE));
4397 aopGet (AOP (left), offset, FALSE));
4399 aopPut (AOP (result), "a", offset);
4404 freeAsmop (left, NULL, ic);
4405 freeAsmop (right, NULL, ic);
4406 freeAsmop (result, NULL, ic);
4409 /*-----------------------------------------------------------------*/
4410 /* genInline - write the inline code out */
4411 /*-----------------------------------------------------------------*/
4413 genInline (iCode * ic)
4415 char *buffer, *bp, *bp1;
4417 _G.lines.isInline += (!options.asmpeep);
4419 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
4420 strcpy (buffer, IC_INLINE (ic));
4422 /* emit each line as a code */
4447 _G.lines.isInline -= (!options.asmpeep);
4451 /*-----------------------------------------------------------------*/
4452 /* genRRC - rotate right with carry */
4453 /*-----------------------------------------------------------------*/
4460 /*-----------------------------------------------------------------*/
4461 /* genRLC - generate code for rotate left with carry */
4462 /*-----------------------------------------------------------------*/
4469 /*-----------------------------------------------------------------*/
4470 /* genGetHbit - generates code get highest order bit */
4471 /*-----------------------------------------------------------------*/
4473 genGetHbit (iCode * ic)
4475 operand *left, *result;
4476 left = IC_LEFT (ic);
4477 result = IC_RESULT (ic);
4478 aopOp (left, ic, FALSE, FALSE);
4479 aopOp (result, ic, FALSE, FALSE);
4481 /* get the highest order byte into a */
4482 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4484 if (AOP_TYPE (result) == AOP_CRY)
4492 /* PENDING: For re-target. */
4498 freeAsmop (left, NULL, ic);
4499 freeAsmop (result, NULL, ic);
4503 emitRsh2 (asmop *aop, int size, int is_signed)
4509 const char *l = aopGet (aop, size, FALSE);
4512 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
4522 /*-----------------------------------------------------------------*/
4523 /* shiftR2Left2Result - shift right two bytes from left to result */
4524 /*-----------------------------------------------------------------*/
4526 shiftR2Left2Result (operand * left, int offl,
4527 operand * result, int offr,
4528 int shCount, int is_signed)
4531 symbol *tlbl, *tlbl1;
4533 movLeft2Result (left, offl, result, offr, 0);
4534 movLeft2Result (left, offl + 1, result, offr + 1, 0);
4536 /* if (AOP(result)->type == AOP_REG) { */
4538 tlbl = newiTempLabel (NULL);
4539 tlbl1 = newiTempLabel (NULL);
4541 /* Left is already in result - so now do the shift */
4546 emitRsh2 (AOP (result), size, is_signed);
4551 emit2 ("ld a,!immedbyte+1", shCount);
4552 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4553 emitLabel (tlbl->key + 100);
4555 emitRsh2 (AOP (result), size, is_signed);
4557 emitLabel (tlbl1->key + 100);
4559 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4563 /*-----------------------------------------------------------------*/
4564 /* shiftL2Left2Result - shift left two bytes from left to result */
4565 /*-----------------------------------------------------------------*/
4567 shiftL2Left2Result (operand * left, int offl,
4568 operand * result, int offr, int shCount)
4570 if (sameRegs (AOP (result), AOP (left)) &&
4571 ((offl + MSB16) == offr))
4577 /* Copy left into result */
4578 movLeft2Result (left, offl, result, offr, 0);
4579 movLeft2Result (left, offl + 1, result, offr + 1, 0);
4581 /* PENDING: for now just see if it'll work. */
4582 /*if (AOP(result)->type == AOP_REG) { */
4586 symbol *tlbl, *tlbl1;
4589 tlbl = newiTempLabel (NULL);
4590 tlbl1 = newiTempLabel (NULL);
4592 /* Left is already in result - so now do the shift */
4595 emit2 ("ld a,!immedbyte+1", shCount);
4596 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4597 emitLabel (tlbl->key + 100);
4602 l = aopGet (AOP (result), offset, FALSE);
4606 emit2 ("sla %s", l);
4617 emitLabel (tlbl1->key + 100);
4619 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4624 /*-----------------------------------------------------------------*/
4625 /* AccRol - rotate left accumulator by known count */
4626 /*-----------------------------------------------------------------*/
4628 AccRol (int shCount)
4630 shCount &= 0x0007; // shCount : 0..7
4669 /*-----------------------------------------------------------------*/
4670 /* AccLsh - left shift accumulator by known count */
4671 /*-----------------------------------------------------------------*/
4673 AccLsh (int shCount)
4675 static const unsigned char SLMask[] =
4677 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
4686 else if (shCount == 2)
4693 /* rotate left accumulator */
4695 /* and kill the lower order bits */
4696 emit2 ("and a,!immedbyte", SLMask[shCount]);
4701 /*-----------------------------------------------------------------*/
4702 /* shiftL1Left2Result - shift left one byte from left to result */
4703 /*-----------------------------------------------------------------*/
4705 shiftL1Left2Result (operand * left, int offl,
4706 operand * result, int offr, int shCount)
4709 l = aopGet (AOP (left), offl, FALSE);
4711 /* shift left accumulator */
4713 aopPut (AOP (result), "a", offr);
4717 /*-----------------------------------------------------------------*/
4718 /* genlshTwo - left shift two bytes by known amount != 0 */
4719 /*-----------------------------------------------------------------*/
4721 genlshTwo (operand * result, operand * left, int shCount)
4723 int size = AOP_SIZE (result);
4725 wassert (size == 2);
4727 /* if shCount >= 8 */
4735 movLeft2Result (left, LSB, result, MSB16, 0);
4736 aopPut (AOP (result), "!zero", 0);
4737 shiftL1Left2Result (left, MSB16, result, MSB16, shCount);
4741 movLeft2Result (left, LSB, result, MSB16, 0);
4742 aopPut (AOP (result), "!zero", 0);
4747 aopPut (AOP (result), "!zero", LSB);
4750 /* 1 <= shCount <= 7 */
4759 shiftL2Left2Result (left, LSB, result, LSB, shCount);
4764 /*-----------------------------------------------------------------*/
4765 /* genlshOne - left shift a one byte quantity by known count */
4766 /*-----------------------------------------------------------------*/
4768 genlshOne (operand * result, operand * left, int shCount)
4770 shiftL1Left2Result (left, LSB, result, LSB, shCount);
4773 /*-----------------------------------------------------------------*/
4774 /* genLeftShiftLiteral - left shifting by known count */
4775 /*-----------------------------------------------------------------*/
4777 genLeftShiftLiteral (operand * left,
4782 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
4785 freeAsmop (right, NULL, ic);
4787 aopOp (left, ic, FALSE, FALSE);
4788 aopOp (result, ic, FALSE, FALSE);
4790 size = getSize (operandType (result));
4793 emitDebug ("; shift left result %d, left %d", size,
4797 /* I suppose that the left size >= result size */
4803 else if (shCount >= (size * 8))
4807 aopPut (AOP (result), "!zero", size);
4815 genlshOne (result, left, shCount);
4818 genlshTwo (result, left, shCount);
4821 wassertl (0, "Shifting of longs is currently unsupported");
4827 freeAsmop (left, NULL, ic);
4828 freeAsmop (result, NULL, ic);
4831 /*-----------------------------------------------------------------*/
4832 /* genLeftShift - generates code for left shifting */
4833 /*-----------------------------------------------------------------*/
4835 genLeftShift (iCode * ic)
4839 symbol *tlbl, *tlbl1;
4840 operand *left, *right, *result;
4842 right = IC_RIGHT (ic);
4843 left = IC_LEFT (ic);
4844 result = IC_RESULT (ic);
4846 aopOp (right, ic, FALSE, FALSE);
4848 /* if the shift count is known then do it
4849 as efficiently as possible */
4850 if (AOP_TYPE (right) == AOP_LIT)
4852 genLeftShiftLiteral (left, right, result, ic);
4856 /* shift count is unknown then we have to form a loop get the loop
4857 count in B : Note: we take only the lower order byte since
4858 shifting more that 32 bits make no sense anyway, ( the largest
4859 size of an object can be only 32 bits ) */
4860 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
4862 freeAsmop (right, NULL, ic);
4863 aopOp (left, ic, FALSE, FALSE);
4864 aopOp (result, ic, FALSE, FALSE);
4866 /* now move the left to the result if they are not the
4869 if (!sameRegs (AOP (left), AOP (result)))
4872 size = AOP_SIZE (result);
4876 l = aopGet (AOP (left), offset, FALSE);
4877 aopPut (AOP (result), l, offset);
4882 size = AOP_SIZE (result);
4886 l = aopGet (AOP (left), offset, FALSE);
4887 aopPut (AOP (result), l, offset);
4893 tlbl = newiTempLabel (NULL);
4894 size = AOP_SIZE (result);
4896 tlbl1 = newiTempLabel (NULL);
4898 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4899 emitLabel (tlbl->key + 100);
4900 l = aopGet (AOP (result), offset, FALSE);
4904 l = aopGet (AOP (result), offset, FALSE);
4908 emit2 ("sla %s", l);
4916 emitLabel (tlbl1->key + 100);
4918 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4920 freeAsmop (left, NULL, ic);
4921 freeAsmop (result, NULL, ic);
4924 /*-----------------------------------------------------------------*/
4925 /* genrshOne - left shift two bytes by known amount != 0 */
4926 /*-----------------------------------------------------------------*/
4928 genrshOne (operand * result, operand * left, int shCount, int is_signed)
4931 int size = AOP_SIZE (result);
4934 wassert (size == 1);
4935 wassert (shCount < 8);
4937 l = aopGet (AOP (left), 0, FALSE);
4941 if (AOP (result)->type == AOP_REG)
4943 aopPut (AOP (result), l, 0);
4944 l = aopGet (AOP (result), 0, FALSE);
4947 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
4955 emit2 ("%s a", is_signed ? "sra" : "srl");
4957 aopPut (AOP (result), "a", 0);
4961 /*-----------------------------------------------------------------*/
4962 /* AccRsh - right shift accumulator by known count */
4963 /*-----------------------------------------------------------------*/
4965 AccRsh (int shCount)
4967 static const unsigned char SRMask[] =
4969 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
4974 /* rotate right accumulator */
4975 AccRol (8 - shCount);
4976 /* and kill the higher order bits */
4977 emit2 ("and a,!immedbyte", SRMask[shCount]);
4981 /*-----------------------------------------------------------------*/
4982 /* shiftR1Left2Result - shift right one byte from left to result */
4983 /*-----------------------------------------------------------------*/
4985 shiftR1Left2Result (operand * left, int offl,
4986 operand * result, int offr,
4987 int shCount, int sign)
4989 _moveA (aopGet (AOP (left), offl, FALSE));
4998 aopPut (AOP (result), "a", offr);
5001 /*-----------------------------------------------------------------*/
5002 /* genrshTwo - right shift two bytes by known amount != 0 */
5003 /*-----------------------------------------------------------------*/
5005 genrshTwo (operand * result, operand * left,
5006 int shCount, int sign)
5008 /* if shCount >= 8 */
5014 shiftR1Left2Result (left, MSB16, result, LSB,
5019 movLeft2Result (left, MSB16, result, LSB, sign);
5021 aopPut (AOP (result), "!zero", 1);
5023 /* 1 <= shCount <= 7 */
5026 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
5030 /*-----------------------------------------------------------------*/
5031 /* genRightShiftLiteral - left shifting by known count */
5032 /*-----------------------------------------------------------------*/
5034 genRightShiftLiteral (operand * left,
5040 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5043 freeAsmop (right, NULL, ic);
5045 aopOp (left, ic, FALSE, FALSE);
5046 aopOp (result, ic, FALSE, FALSE);
5048 size = getSize (operandType (result));
5050 emitDebug ("; shift right result %d, left %d", size,
5053 /* I suppose that the left size >= result size */
5059 else if (shCount >= (size * 8))
5061 aopPut (AOP (result), "!zero", size);
5067 genrshOne (result, left, shCount, sign);
5070 /* PENDING: sign support */
5071 genrshTwo (result, left, shCount, sign);
5074 wassertl (0, "Asked to shift right a long which should be a function call");
5077 wassertl (0, "Entered default case in right shift delegate");
5080 freeAsmop (left, NULL, ic);
5081 freeAsmop (result, NULL, ic);
5084 /*-----------------------------------------------------------------*/
5085 /* genRightShift - generate code for right shifting */
5086 /*-----------------------------------------------------------------*/
5088 genRightShift (iCode * ic)
5090 operand *right, *left, *result;
5092 int size, offset, first = 1;
5096 symbol *tlbl, *tlbl1;
5098 /* if signed then we do it the hard way preserve the
5099 sign bit moving it inwards */
5100 retype = getSpec (operandType (IC_RESULT (ic)));
5102 is_signed = !SPEC_USIGN (retype);
5104 /* signed & unsigned types are treated the same : i.e. the
5105 signed is NOT propagated inwards : quoting from the
5106 ANSI - standard : "for E1 >> E2, is equivalent to division
5107 by 2**E2 if unsigned or if it has a non-negative value,
5108 otherwise the result is implementation defined ", MY definition
5109 is that the sign does not get propagated */
5111 right = IC_RIGHT (ic);
5112 left = IC_LEFT (ic);
5113 result = IC_RESULT (ic);
5115 aopOp (right, ic, FALSE, FALSE);
5117 /* if the shift count is known then do it
5118 as efficiently as possible */
5119 if (AOP_TYPE (right) == AOP_LIT)
5121 genRightShiftLiteral (left, right, result, ic, is_signed);
5125 aopOp (left, ic, FALSE, FALSE);
5126 aopOp (result, ic, FALSE, FALSE);
5128 /* now move the left to the result if they are not the
5130 if (!sameRegs (AOP (left), AOP (result)) &&
5131 AOP_SIZE (result) > 1)
5134 size = AOP_SIZE (result);
5138 l = aopGet (AOP (left), offset, FALSE);
5139 aopPut (AOP (result), l, offset);
5144 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5146 freeAsmop (right, NULL, ic);
5148 tlbl = newiTempLabel (NULL);
5149 tlbl1 = newiTempLabel (NULL);
5150 size = AOP_SIZE (result);
5153 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5154 emitLabel (tlbl->key + 100);
5157 l = aopGet (AOP (result), offset--, FALSE);
5160 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5168 emitLabel (tlbl1->key + 100);
5170 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5172 freeAsmop (left, NULL, ic);
5173 freeAsmop (result, NULL, ic);
5176 /*-----------------------------------------------------------------*/
5177 /* genGenPointerGet - get value from generic pointer space */
5178 /*-----------------------------------------------------------------*/
5180 genGenPointerGet (operand * left,
5181 operand * result, iCode * ic)
5184 sym_link *retype = getSpec (operandType (result));
5190 aopOp (left, ic, FALSE, FALSE);
5191 aopOp (result, ic, FALSE, FALSE);
5193 if (isPair (AOP (left)) && AOP_SIZE (result) == 1)
5196 if (isPtrPair (AOP (left)))
5198 tsprintf (buffer, "!*pair", getPairName (AOP (left)));
5199 aopPut (AOP (result), buffer, 0);
5203 emit2 ("ld a,!*pair", getPairName (AOP (left)));
5204 aopPut (AOP (result), "a", 0);
5206 freeAsmop (left, NULL, ic);
5210 /* For now we always load into IY */
5211 /* if this is remateriazable */
5212 fetchPair (pair, AOP (left));
5214 /* so iy now contains the address */
5215 freeAsmop (left, NULL, ic);
5217 /* if bit then unpack */
5218 if (IS_BITVAR (retype))
5224 size = AOP_SIZE (result);
5229 /* PENDING: make this better */
5230 if (!IS_GB && AOP (result)->type == AOP_REG)
5232 aopPut (AOP (result), "!*hl", offset++);
5236 emit2 ("ld a,!*pair", _pairs[pair].name);
5237 aopPut (AOP (result), "a", offset++);
5241 emit2 ("inc %s", _pairs[pair].name);
5242 _G.pairs[pair].offset++;
5248 freeAsmop (result, NULL, ic);
5251 /*-----------------------------------------------------------------*/
5252 /* genPointerGet - generate code for pointer get */
5253 /*-----------------------------------------------------------------*/
5255 genPointerGet (iCode * ic)
5257 operand *left, *result;
5258 sym_link *type, *etype;
5260 left = IC_LEFT (ic);
5261 result = IC_RESULT (ic);
5263 /* depending on the type of pointer we need to
5264 move it to the correct pointer register */
5265 type = operandType (left);
5266 etype = getSpec (type);
5268 genGenPointerGet (left, result, ic);
5272 isRegOrLit (asmop * aop)
5274 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
5279 /*-----------------------------------------------------------------*/
5280 /* genGenPointerSet - stores the value into a pointer location */
5281 /*-----------------------------------------------------------------*/
5283 genGenPointerSet (operand * right,
5284 operand * result, iCode * ic)
5287 sym_link *retype = getSpec (operandType (right));
5288 PAIR_ID pairId = PAIR_HL;
5290 aopOp (result, ic, FALSE, FALSE);
5291 aopOp (right, ic, FALSE, FALSE);
5296 /* Handle the exceptions first */
5297 if (isPair (AOP (result)) && (AOP_SIZE (right) == 1))
5300 const char *l = aopGet (AOP (right), 0, FALSE);
5301 const char *pair = getPairName (AOP (result));
5302 if (canAssignToPtr (l) && isPtr (pair))
5304 emit2 ("ld !*pair,%s", pair, l);
5309 emit2 ("ld !*pair,a", pair);
5314 /* if the operand is already in dptr
5315 then we do nothing else we move the value to dptr */
5316 if (AOP_TYPE (result) != AOP_STR)
5318 fetchPair (pairId, AOP (result));
5320 /* so hl know contains the address */
5321 freeAsmop (result, NULL, ic);
5323 /* if bit then unpack */
5324 if (IS_BITVAR (retype))
5330 size = AOP_SIZE (right);
5335 const char *l = aopGet (AOP (right), offset, FALSE);
5336 if (isRegOrLit (AOP (right)) && !IS_GB)
5338 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
5343 emit2 ("ld !*pair,a", _pairs[pairId].name);
5347 emit2 ("inc %s", _pairs[pairId].name);
5348 _G.pairs[pairId].offset++;
5354 freeAsmop (right, NULL, ic);
5357 /*-----------------------------------------------------------------*/
5358 /* genPointerSet - stores the value into a pointer location */
5359 /*-----------------------------------------------------------------*/
5361 genPointerSet (iCode * ic)
5363 operand *right, *result;
5364 sym_link *type, *etype;
5366 right = IC_RIGHT (ic);
5367 result = IC_RESULT (ic);
5369 /* depending on the type of pointer we need to
5370 move it to the correct pointer register */
5371 type = operandType (result);
5372 etype = getSpec (type);
5374 genGenPointerSet (right, result, ic);
5377 /*-----------------------------------------------------------------*/
5378 /* genIfx - generate code for Ifx statement */
5379 /*-----------------------------------------------------------------*/
5381 genIfx (iCode * ic, iCode * popIc)
5383 operand *cond = IC_COND (ic);
5386 aopOp (cond, ic, FALSE, TRUE);
5388 /* get the value into acc */
5389 if (AOP_TYPE (cond) != AOP_CRY)
5393 /* the result is now in the accumulator */
5394 freeAsmop (cond, NULL, ic);
5396 /* if there was something to be popped then do it */
5400 /* if the condition is a bit variable */
5401 if (isbit && IS_ITEMP (cond) &&
5403 genIfxJump (ic, SPIL_LOC (cond)->rname);
5404 else if (isbit && !IS_ITEMP (cond))
5405 genIfxJump (ic, OP_SYMBOL (cond)->rname);
5407 genIfxJump (ic, "a");
5412 /*-----------------------------------------------------------------*/
5413 /* genAddrOf - generates code for address of */
5414 /*-----------------------------------------------------------------*/
5416 genAddrOf (iCode * ic)
5418 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
5420 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
5422 /* if the operand is on the stack then we
5423 need to get the stack offset of this
5430 if (sym->stack <= 0)
5432 emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset);
5436 emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
5443 emit2 ("ld de,!hashedstr", sym->rname);
5445 aopPut (AOP (IC_RESULT (ic)), "e", 0);
5446 aopPut (AOP (IC_RESULT (ic)), "d", 1);
5453 /* if it has an offset then we need to compute it */
5455 emit2 ("ld hl,#%d+%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset, _G.stack.param_offset);
5457 emit2 ("ld hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
5458 emit2 ("add hl,sp");
5462 emit2 ("ld hl,#%s", sym->rname);
5464 aopPut (AOP (IC_RESULT (ic)), "l", 0);
5465 aopPut (AOP (IC_RESULT (ic)), "h", 1);
5467 freeAsmop (IC_RESULT (ic), NULL, ic);
5470 /*-----------------------------------------------------------------*/
5471 /* genAssign - generate code for assignment */
5472 /*-----------------------------------------------------------------*/
5474 genAssign (iCode * ic)
5476 operand *result, *right;
5478 unsigned long lit = 0L;
5480 result = IC_RESULT (ic);
5481 right = IC_RIGHT (ic);
5484 /* Dont bother assigning if they are the same */
5485 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5487 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
5492 aopOp (right, ic, FALSE, FALSE);
5493 aopOp (result, ic, TRUE, FALSE);
5495 /* if they are the same registers */
5496 if (sameRegs (AOP (right), AOP (result)))
5498 emitDebug ("; (registers are the same)");
5502 /* if the result is a bit */
5503 if (AOP_TYPE (result) == AOP_CRY)
5509 size = AOP_SIZE (result);
5512 if (AOP_TYPE (right) == AOP_LIT)
5513 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5514 if (isPair (AOP (result)))
5516 fetchPair (getPairId (AOP (result)), AOP (right));
5518 else if ((size > 1) &&
5519 (AOP_TYPE (result) != AOP_REG) &&
5520 (AOP_TYPE (right) == AOP_LIT) &&
5521 !IS_FLOAT (operandType (right)) &&
5524 bool fXored = FALSE;
5526 /* Work from the top down.
5527 Done this way so that we can use the cached copy of 0
5528 in A for a fast clear */
5531 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
5533 if (!fXored && size > 1)
5540 aopPut (AOP (result), "a", offset);
5544 aopPut (AOP (result), "!zero", offset);
5548 aopPut (AOP (result),
5549 aopGet (AOP (right), offset, FALSE),
5554 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
5556 /* Special case. Load into a and d, then load out. */
5557 _moveA (aopGet (AOP (right), 0, FALSE));
5558 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
5559 aopPut (AOP (result), "a", 0);
5560 aopPut (AOP (result), "e", 1);
5562 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
5564 /* Special case - simple memcpy */
5565 aopGet (AOP (right), LSB, FALSE);
5568 aopGet (AOP (result), LSB, FALSE);
5572 emit2 ("ld a,(de)");
5573 /* Peephole will optimise this. */
5574 emit2 ("ld (hl),a");
5582 spillPair (PAIR_HL);
5588 /* PENDING: do this check better */
5589 if (requiresHL (AOP (right)) && requiresHL (AOP (result)))
5591 _moveA (aopGet (AOP (right), offset, FALSE));
5592 aopPut (AOP (result), "a", offset);
5595 aopPut (AOP (result),
5596 aopGet (AOP (right), offset, FALSE),
5603 freeAsmop (right, NULL, ic);
5604 freeAsmop (result, NULL, ic);
5607 /*-----------------------------------------------------------------*/
5608 /* genJumpTab - genrates code for jump table */
5609 /*-----------------------------------------------------------------*/
5611 genJumpTab (iCode * ic)
5616 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
5617 /* get the condition into accumulator */
5618 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
5621 emit2 ("ld e,%s", l);
5622 emit2 ("ld d,!zero");
5623 jtab = newiTempLabel (NULL);
5625 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
5626 emit2 ("add hl,de");
5627 emit2 ("add hl,de");
5628 emit2 ("add hl,de");
5629 freeAsmop (IC_JTCOND (ic), NULL, ic);
5633 emitLabel (jtab->key + 100);
5634 /* now generate the jump labels */
5635 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
5636 jtab = setNextItem (IC_JTLABELS (ic)))
5637 emit2 ("jp !tlabel", jtab->key + 100);
5640 /*-----------------------------------------------------------------*/
5641 /* genCast - gen code for casting */
5642 /*-----------------------------------------------------------------*/
5644 genCast (iCode * ic)
5646 operand *result = IC_RESULT (ic);
5647 sym_link *ctype = operandType (IC_LEFT (ic));
5648 operand *right = IC_RIGHT (ic);
5651 /* if they are equivalent then do nothing */
5652 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5655 aopOp (right, ic, FALSE, FALSE);
5656 aopOp (result, ic, FALSE, FALSE);
5658 /* if the result is a bit */
5659 if (AOP_TYPE (result) == AOP_CRY)
5664 /* if they are the same size : or less */
5665 if (AOP_SIZE (result) <= AOP_SIZE (right))
5668 /* if they are in the same place */
5669 if (sameRegs (AOP (right), AOP (result)))
5672 /* if they in different places then copy */
5673 size = AOP_SIZE (result);
5677 aopPut (AOP (result),
5678 aopGet (AOP (right), offset, FALSE),
5685 /* PENDING: should be OK. */
5687 /* if the result is of type pointer */
5694 /* so we now know that the size of destination is greater
5695 than the size of the source */
5696 /* we move to result for the size of source */
5697 size = AOP_SIZE (right);
5701 aopPut (AOP (result),
5702 aopGet (AOP (right), offset, FALSE),
5707 /* now depending on the sign of the destination */
5708 size = AOP_SIZE (result) - AOP_SIZE (right);
5709 /* Unsigned or not an integral type - right fill with zeros */
5710 if (SPEC_USIGN (ctype) || !IS_SPEC (ctype))
5713 aopPut (AOP (result), "!zero", offset++);
5717 /* we need to extend the sign :{ */
5718 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
5721 emitDebug ("; genCast: sign extend untested.");
5725 aopPut (AOP (result), "a", offset++);
5729 freeAsmop (right, NULL, ic);
5730 freeAsmop (result, NULL, ic);
5733 /*-----------------------------------------------------------------*/
5734 /* genReceive - generate code for a receive iCode */
5735 /*-----------------------------------------------------------------*/
5737 genReceive (iCode * ic)
5739 if (isOperandInFarSpace (IC_RESULT (ic)) &&
5740 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
5741 IS_TRUE_SYMOP (IC_RESULT (ic))))
5751 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
5752 size = AOP_SIZE(IC_RESULT(ic));
5754 for (i = 0; i < size; i++) {
5755 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
5759 freeAsmop (IC_RESULT (ic), NULL, ic);
5764 /** Maximum number of bytes to emit per line. */
5768 /** Context for the byte output chunker. */
5771 unsigned char buffer[DBEMIT_MAX_RUN];
5776 /** Flushes a byte chunker by writing out all in the buffer and
5780 _dbFlush(DBEMITCTX *self)
5787 sprintf(line, ".db 0x%02X", self->buffer[0]);
5789 for (i = 1; i < self->pos; i++)
5791 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
5798 /** Write out another byte, buffering until a decent line is
5802 _dbEmit(DBEMITCTX *self, int c)
5804 if (self->pos == DBEMIT_MAX_RUN)
5808 self->buffer[self->pos++] = c;
5811 /** Context for a simple run length encoder. */
5815 unsigned char buffer[128];
5817 /** runLen may be equivalent to pos. */
5823 RLE_CHANGE_COST = 4,
5827 /** Flush the buffer of a run length encoder by writing out the run or
5828 data that it currently contains.
5831 _rleCommit(RLECTX *self)
5837 memset(&db, 0, sizeof(db));
5839 emit2(".db %u", self->pos);
5841 for (i = 0; i < self->pos; i++)
5843 _dbEmit(&db, self->buffer[i]);
5852 Can get either a run or a block of random stuff.
5853 Only want to change state if a good run comes in or a run ends.
5854 Detecting run end is easy.
5857 Say initial state is in run, len zero, last zero. Then if you get a
5858 few zeros then something else then a short run will be output.
5859 Seems OK. While in run mode, keep counting. While in random mode,
5860 keep a count of the run. If run hits margin, output all up to run,
5861 restart, enter run mode.
5864 /** Add another byte into the run length encoder, flushing as
5865 required. The run length encoder uses the Amiga IFF style, where
5866 a block is prefixed by its run length. A positive length means
5867 the next n bytes pass straight through. A negative length means
5868 that the next byte is repeated -n times. A zero terminates the
5872 _rleAppend(RLECTX *self, int c)
5876 if (c != self->last)
5878 /* The run has stopped. See if it is worthwhile writing it out
5879 as a run. Note that the random data comes in as runs of
5882 if (self->runLen > RLE_CHANGE_COST)
5884 /* Yes, worthwhile. */
5885 /* Commit whatever was in the buffer. */
5887 emit2(".db -%u,0x%02X", self->runLen, self->last);
5891 /* Not worthwhile. Append to the end of the random list. */
5892 for (i = 0; i < self->runLen; i++)
5894 if (self->pos >= RLE_MAX_BLOCK)
5899 self->buffer[self->pos++] = self->last;
5907 if (self->runLen >= RLE_MAX_BLOCK)
5909 /* Commit whatever was in the buffer. */
5912 emit2 (".db -%u,0x%02X", self->runLen, self->last);
5920 _rleFlush(RLECTX *self)
5922 _rleAppend(self, -1);
5929 /** genArrayInit - Special code for initialising an array with constant
5933 genArrayInit (iCode * ic)
5937 int elementSize = 0, eIndex, i;
5938 unsigned val, lastVal;
5942 memset(&rle, 0, sizeof(rle));
5944 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
5946 if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD)
5948 /* Emit the support function call and the destination address. */
5949 emit2("call __initrleblock");
5950 emit2(".dw %s", aopGetWord (AOP(IC_LEFT(ic)), 0));
5954 wassertl (0, "Unexpected operand to genArrayInit.\n");
5957 type = operandType(IC_LEFT(ic));
5959 if (type && type->next)
5961 elementSize = getSize(type->next);
5965 wassertl (0, "Can't determine element size in genArrayInit.");
5968 iLoop = IC_ARRAYILIST(ic);
5969 lastVal = (unsigned)-1;
5971 /* Feed all the bytes into the run length encoder which will handle
5973 This works well for mixed char data, and for random int and long
5982 for (i = 0; i < ix; i++)
5984 for (eIndex = 0; eIndex < elementSize; eIndex++)
5986 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
5987 _rleAppend(&rle, val);
5992 iLoop = iLoop->next;
5996 /* Mark the end of the run. */
5999 freeAsmop (IC_LEFT(ic), NULL, ic);
6002 /*-----------------------------------------------------------------*/
6003 /* genZ80Code - generate code for Z80 based controllers */
6004 /*-----------------------------------------------------------------*/
6006 genZ80Code (iCode * lic)
6014 _fReturn = _gbz80_return;
6015 _fTmp = _gbz80_return;
6019 _fReturn = _z80_return;
6020 _fTmp = _z80_return;
6023 _G.lines.head = _G.lines.current = NULL;
6025 for (ic = lic; ic; ic = ic->next)
6028 if (cln != ic->lineno)
6030 emit2 ("; %s %d", ic->filename, ic->lineno);
6033 /* if the result is marked as
6034 spilt and rematerializable or code for
6035 this has already been generated then
6037 if (resultRemat (ic) || ic->generated)
6040 /* depending on the operation */
6044 emitDebug ("; genNot");
6049 emitDebug ("; genCpl");
6054 emitDebug ("; genUminus");
6059 emitDebug ("; genIpush");
6064 /* IPOP happens only when trying to restore a
6065 spilt live range, if there is an ifx statement
6066 following this pop then the if statement might
6067 be using some of the registers being popped which
6068 would destory the contents of the register so
6069 we need to check for this condition and handle it */
6071 ic->next->op == IFX &&
6072 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
6074 emitDebug ("; genIfx");
6075 genIfx (ic->next, ic);
6079 emitDebug ("; genIpop");
6085 emitDebug ("; genCall");
6090 emitDebug ("; genPcall");
6095 emitDebug ("; genFunction");
6100 emitDebug ("; genEndFunction");
6101 genEndFunction (ic);
6105 emitDebug ("; genRet");
6110 emitDebug ("; genLabel");
6115 emitDebug ("; genGoto");
6120 emitDebug ("; genPlus");
6125 emitDebug ("; genMinus");
6130 emitDebug ("; genMult");
6135 emitDebug ("; genDiv");
6140 emitDebug ("; genMod");
6145 emitDebug ("; genCmpGt");
6146 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
6150 emitDebug ("; genCmpLt");
6151 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
6158 /* note these two are xlated by algebraic equivalence
6159 during parsing SDCC.y */
6160 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
6161 "got '>=' or '<=' shouldn't have come here");
6165 emitDebug ("; genCmpEq");
6166 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
6170 emitDebug ("; genAndOp");
6175 emitDebug ("; genOrOp");
6180 emitDebug ("; genXor");
6181 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
6185 emitDebug ("; genOr");
6186 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
6190 emitDebug ("; genAnd");
6191 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
6195 emitDebug ("; genInline");
6200 emitDebug ("; genRRC");
6205 emitDebug ("; genRLC");
6210 emitDebug ("; genGetHBIT");
6215 emitDebug ("; genLeftShift");
6220 emitDebug ("; genRightShift");
6224 case GET_VALUE_AT_ADDRESS:
6225 emitDebug ("; genPointerGet");
6231 if (POINTER_SET (ic))
6233 emitDebug ("; genAssign (pointer)");
6238 emitDebug ("; genAssign");
6244 emitDebug ("; genIfx");
6249 emitDebug ("; genAddrOf");
6254 emitDebug ("; genJumpTab");
6259 emitDebug ("; genCast");
6264 emitDebug ("; genReceive");
6269 emitDebug ("; addSet");
6270 addSet (&_G.sendSet, ic);
6279 /* piCode(ic,stdout); */
6285 /* now we are ready to call the
6286 peep hole optimizer */
6287 if (!options.nopeep)
6288 peepHole (&_G.lines.head);
6290 /* This is unfortunate */
6291 /* now do the actual printing */
6293 FILE *fp = codeOutFile;
6294 if (isInHome () && codeOutFile == code->oFile)
6295 codeOutFile = home->oFile;
6296 printLine (_G.lines.head, codeOutFile);
6297 if (_G.flushStatics)
6300 _G.flushStatics = 0;
6309 _isPairUsed (iCode * ic, PAIR_ID pairId)
6315 if (bitVectBitValue (ic->rMask, D_IDX))
6317 if (bitVectBitValue (ic->rMask, E_IDX))
6327 fetchLitSpecial (asmop * aop, bool negate, bool xor)
6330 value *val = aop->aopu.aop_lit;
6332 wassert (aop->type == AOP_LIT);
6333 wassert (!IS_FLOAT (val->type));
6335 v = (unsigned long) floatFromVal (val);
6343 tsprintf (buffer, "!immedword", v);
6344 return gc_strdup (buffer);