1 /*-------------------------------------------------------------------------
2 gen.c - Z80 specific code generator.
4 Michael Hope <michaelh@juju.net.nz> 2000
5 Based on the mcs51 generator -
6 Sandeep Dutta . sandeep.dutta@usa.net (1998)
7 and - Jean-Louis VERN.jlvern@writeme.com (1999)
9 This program is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 2, or (at your option) any
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 In other words, you are welcome to use, share and improve this program.
25 You are forbidden to forbid anyone else to use, share and improve
26 what you give them. Help stamp out software-hoarding!
28 -------------------------------------------------------------------------*/
31 Benchmarks on dhry.c 2.1 with 32766 loops and a 10ms clock:
33 Base with asm strcpy / strcmp / memcpy: 23198 141 1A14
34 Improved WORD push 22784 144 19AE
35 With label1 on 22694 144 197E
36 With label2 on 22743 144 198A
37 With label3 on 22776 144 1999
38 With label4 on 22776 144 1999
39 With all 'label' on 22661 144 196F
40 With loopInvariant on 20919 156 19AB
41 With loopInduction on Breaks 198B
42 With all working on 20796 158 196C
43 Slightly better genCmp(signed) 20597 159 195B
44 Better reg packing, first peephole 20038 163 1873
45 With assign packing 19281 165 1849
47 With reg params for mul and div 16234 202 162D
49 1. Starting again at 3 Aug 01 34965 93 219C
51 Includes long mul/div in code
52 2. Optimised memcpy for acc use 32102 102 226B
53 3. Optimised strcpy for acc use 27819 117 2237
54 3a Optimised memcpy fun
55 4. Optimised strcmp fun 21999 149 2294
56 5. Optimised strcmp further 21660 151 228C
57 6. Optimised memcpy by unroling 20885 157 2201
58 7. After turning loop induction on 19862 165 236D
59 8. Same as 7 but with more info
60 9. With asm optimised strings 17030 192 2223
62 10 and below are with asm strings off.
64 Apparent advantage of turning on regparams:
66 Decent case is push of a constant
67 - ld hl,#n; push hl: (10+11)*nargs
68 2. Cost of pull from stack
69 Using asm with ld hl, etc
70 - ld hl,#2; add hl,sp; (ld bc,(hl); hl+=2)*nargs
72 3. Cost of fixing stack
76 So cost is (10+11+7+6+7+10)*nargs+10+11
78 = 123 for mul, div, strcmp, strcpy
79 Saving of (98298+32766+32766+32766)*123 = 24181308
80 At 192 d/s for 682411768t, speed up to 199. Hmm.
88 #ifdef HAVE_SYS_ISA_DEFS_H
89 #include <sys/isa_defs.h>
93 #include "SDCCglobl.h"
94 #include "SDCCpeeph.h"
99 /* This is the down and dirty file with all kinds of kludgy & hacky
100 stuff. This is what it is all about CODE GENERATION for a specific MCU.
101 Some of the routines may be reusable, will have to see */
103 /* Z80 calling convention description.
104 Parameters are passed right to left. As the stack grows downwards,
105 the parameters are arranged in left to right in memory.
106 Parameters may be passed in the HL and DE registers with one
108 PENDING: What if the parameter is a long?
109 Everything is caller saves. i.e. the caller must save any registers
110 that it wants to preserve over the call.
111 GB: The return value is returned in DEHL. DE is normally used as a
112 working register pair. Caller saves allows it to be used for a
114 va args functions do not use register parameters. All arguments
115 are passed on the stack.
116 IX is used as an index register to the top of the local variable
117 area. ix-0 is the top most local variable.
122 /* Set to enable debugging trace statements in the output assembly code. */
126 static char *_z80_return[] =
127 {"l", "h", "e", "d"};
128 static char *_gbz80_return[] =
129 {"e", "d", "l", "h"};
130 static char *_fReceive[] =
131 { "c", "b", "e", "d" };
133 static char **_fReturn;
136 extern FILE *codeOutFile;
144 /** Enum covering all the possible register pairs.
163 } _pairs[NUM_PAIRS] = {
164 { "??1", "?2", "?3" },
169 { "iy", "iy.l?", "iy.h?" },
170 { "ix", "ix.l?", "ix.h?" }
174 #define ACC_NAME _pairs[PAIR_AF].h
184 /** Code generator persistent data.
188 /** Used to optimised setting up of a pair by remebering what it
189 contains and adjusting instead of reloading where possible.
210 const char *lastFunctionName;
216 /** TRUE if the registers have already been saved. */
234 static const char *aopGet (asmop * aop, int offset, bool bit16);
250 _getTempPairName(void)
252 return _pairs[_getTempPairId()].name;
258 /* Clean up the line so that it is 'prettier' */
259 if (strchr (buf, ':'))
261 /* Is a label - cant do anything */
264 /* Change the first (and probably only) ' ' to a tab so
279 _newLineNode (char *line)
283 pl = traceAlloc(&_G.lines.trace, Safe_alloc ( sizeof (lineNode)));
284 pl->line = traceAlloc(&_G.lines.trace, Safe_strdup (line));
290 _vemit2 (const char *szFormat, va_list ap)
294 tvsprintf (buffer, szFormat, ap);
297 _G.lines.current = (_G.lines.current ?
298 connectLine (_G.lines.current, _newLineNode (buffer)) :
299 (_G.lines.head = _newLineNode (buffer)));
301 _G.lines.current->isInline = _G.lines.isInline;
305 emit2 (const char *szFormat,...)
309 va_start (ap, szFormat);
311 _vemit2 (szFormat, ap);
317 emitDebug (const char *szFormat,...)
323 va_start (ap, szFormat);
325 _vemit2 (szFormat, ap);
331 /*-----------------------------------------------------------------*/
332 /* emit2 - writes the code into a file : for now it is simple */
333 /*-----------------------------------------------------------------*/
335 _emit2 (const char *inst, const char *fmt,...)
338 char lb[INITIAL_INLINEASM];
345 sprintf (lb, "%s\t", inst);
346 vsprintf (lb + (strlen (lb)), fmt, ap);
349 vsprintf (lb, fmt, ap);
351 while (isspace (*lbp))
356 _G.lines.current = (_G.lines.current ?
357 connectLine (_G.lines.current, _newLineNode (lb)) :
358 (_G.lines.head = _newLineNode (lb)));
360 _G.lines.current->isInline = _G.lines.isInline;
365 _emitMove(const char *to, const char *from)
367 if (strcasecmp(to, from) != 0)
369 emit2("ld %s,%s", to, from);
374 // Could leave this to the peephole, but sometimes the peephole is inhibited.
379 _moveA(const char *moveFrom)
381 // Let the peephole optimiser take care of redundent loads
382 _emitMove(ACC_NAME, moveFrom);
392 getPairName (asmop * aop)
394 if (aop->type == AOP_REG)
396 switch (aop->aopu.aop_reg[0]->rIdx)
409 else if (aop->type == AOP_STR)
411 switch (*aop->aopu.aop_str[0])
424 wassertl (0, "Tried to get the pair name of something that isn't a pair");
429 getPairId (asmop * aop)
433 if (aop->type == AOP_REG)
435 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX) && (aop->aopu.aop_reg[1]->rIdx == B_IDX))
439 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX) && (aop->aopu.aop_reg[1]->rIdx == D_IDX))
443 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX) && (aop->aopu.aop_reg[1]->rIdx == H_IDX))
448 if (aop->type == AOP_STR)
450 if (!strcmp (aop->aopu.aop_str[0], "c") && !strcmp (aop->aopu.aop_str[1], "b"))
454 if (!strcmp (aop->aopu.aop_str[0], "e") && !strcmp (aop->aopu.aop_str[1], "d"))
458 if (!strcmp (aop->aopu.aop_str[0], "l") && !strcmp (aop->aopu.aop_str[1], "h"))
467 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
471 return (getPairId (aop) != PAIR_INVALID);
475 isPtrPair (asmop * aop)
477 PAIR_ID pairId = getPairId (aop);
488 /** Push a register pair onto the stack */
490 genPairPush (asmop * aop)
492 emit2 ("push %s", getPairName (aop));
496 _push (PAIR_ID pairId)
498 emit2 ("push %s", _pairs[pairId].name);
499 _G.stack.pushed += 2;
503 _pop (PAIR_ID pairId)
505 emit2 ("pop %s", _pairs[pairId].name);
506 _G.stack.pushed -= 2;
509 /*-----------------------------------------------------------------*/
510 /* newAsmop - creates a new asmOp */
511 /*-----------------------------------------------------------------*/
513 newAsmop (short type)
517 aop = traceAlloc(&_G.trace.aops, Safe_alloc (sizeof (asmop)));
522 /*-----------------------------------------------------------------*/
523 /* aopForSym - for a true symbol */
524 /*-----------------------------------------------------------------*/
526 aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
533 wassert (sym->etype);
535 space = SPEC_OCLS (sym->etype);
537 /* if already has one */
541 /* Assign depending on the storage class */
542 if (sym->onStack || sym->iaccess)
544 /* The pointer that is used depends on how big the offset is.
545 Normally everything is AOP_STK, but for offsets of < -128 or
546 > 127 on the Z80 an extended stack pointer is used.
548 if (IS_Z80 && (options.ommitFramePtr || sym->stack < INT8MIN || sym->stack > (int)(INT8MAX-getSize (sym->type))))
550 emitDebug ("; AOP_EXSTK for %s", sym->rname);
551 sym->aop = aop = newAsmop (AOP_EXSTK);
555 emitDebug ("; AOP_STK for %s", sym->rname);
556 sym->aop = aop = newAsmop (AOP_STK);
559 aop->size = getSize (sym->type);
560 aop->aopu.aop_stk = sym->stack;
564 /* special case for a function */
565 if (IS_FUNC (sym->type))
567 sym->aop = aop = newAsmop (AOP_IMMD);
568 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup (sym->rname));
575 /* if it is in direct space */
576 if (IN_REGSP (space) && !requires_a)
578 sym->aop = aop = newAsmop (AOP_SFR);
579 aop->aopu.aop_dir = sym->rname;
580 aop->size = getSize (sym->type);
581 emitDebug ("; AOP_SFR for %s", sym->rname);
586 /* only remaining is far space */
587 /* in which case DPTR gets the address */
590 emitDebug ("; AOP_HL for %s", sym->rname);
591 sym->aop = aop = newAsmop (AOP_HL);
595 sym->aop = aop = newAsmop (AOP_IY);
597 aop->size = getSize (sym->type);
598 aop->aopu.aop_dir = sym->rname;
600 /* if it is in code space */
601 if (IN_CODESPACE (space))
607 /*-----------------------------------------------------------------*/
608 /* aopForRemat - rematerialzes an object */
609 /*-----------------------------------------------------------------*/
611 aopForRemat (symbol * sym)
614 iCode *ic = sym->rematiCode;
615 asmop *aop = newAsmop (AOP_IMMD);
619 /* if plus or minus print the right hand side */
620 if (ic->op == '+' || ic->op == '-')
622 /* PENDING: for re-target */
623 sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
626 ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
629 /* we reached the end */
630 sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
634 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
638 /*-----------------------------------------------------------------*/
639 /* regsInCommon - two operands have some registers in common */
640 /*-----------------------------------------------------------------*/
642 regsInCommon (operand * op1, operand * op2)
647 /* if they have registers in common */
648 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
651 sym1 = OP_SYMBOL (op1);
652 sym2 = OP_SYMBOL (op2);
654 if (sym1->nRegs == 0 || sym2->nRegs == 0)
657 for (i = 0; i < sym1->nRegs; i++)
663 for (j = 0; j < sym2->nRegs; j++)
668 if (sym2->regs[j] == sym1->regs[i])
676 /*-----------------------------------------------------------------*/
677 /* operandsEqu - equivalent */
678 /*-----------------------------------------------------------------*/
680 operandsEqu (operand * op1, operand * op2)
684 /* if they not symbols */
685 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
688 sym1 = OP_SYMBOL (op1);
689 sym2 = OP_SYMBOL (op2);
691 /* if both are itemps & one is spilt
692 and the other is not then false */
693 if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
694 sym1->isspilt != sym2->isspilt)
697 /* if they are the same */
701 if (strcmp (sym1->rname, sym2->rname) == 0)
705 /* if left is a tmp & right is not */
706 if (IS_ITEMP (op1) &&
709 (sym1->usl.spillLoc == sym2))
712 if (IS_ITEMP (op2) &&
716 (sym2->usl.spillLoc == sym1))
722 /*-----------------------------------------------------------------*/
723 /* sameRegs - two asmops have the same registers */
724 /*-----------------------------------------------------------------*/
726 sameRegs (asmop * aop1, asmop * aop2)
730 if (aop1->type == AOP_SFR ||
731 aop2->type == AOP_SFR)
737 if (aop1->type != AOP_REG ||
738 aop2->type != AOP_REG)
741 if (aop1->size != aop2->size)
744 for (i = 0; i < aop1->size; i++)
745 if (aop1->aopu.aop_reg[i] !=
746 aop2->aopu.aop_reg[i])
752 /*-----------------------------------------------------------------*/
753 /* aopOp - allocates an asmop for an operand : */
754 /*-----------------------------------------------------------------*/
756 aopOp (operand * op, iCode * ic, bool result, bool requires_a)
765 /* if this a literal */
766 if (IS_OP_LITERAL (op))
768 op->aop = aop = newAsmop (AOP_LIT);
769 aop->aopu.aop_lit = op->operand.valOperand;
770 aop->size = getSize (operandType (op));
774 /* if already has a asmop then continue */
778 /* if the underlying symbol has a aop */
779 if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
781 op->aop = OP_SYMBOL (op)->aop;
785 /* if this is a true symbol */
786 if (IS_TRUE_SYMOP (op))
788 op->aop = aopForSym (ic, OP_SYMBOL (op), result, requires_a);
792 /* this is a temporary : this has
798 e) can be a return use only */
800 sym = OP_SYMBOL (op);
802 /* if the type is a conditional */
803 if (sym->regType == REG_CND)
805 aop = op->aop = sym->aop = newAsmop (AOP_CRY);
810 /* if it is spilt then two situations
812 b) has a spill location */
813 if (sym->isspilt || sym->nRegs == 0)
815 /* rematerialize it NOW */
818 sym->aop = op->aop = aop =
820 aop->size = getSize (sym->type);
826 if (sym->accuse == ACCUSE_A)
828 aop = op->aop = sym->aop = newAsmop (AOP_ACC);
829 aop->size = getSize (sym->type);
830 wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
832 aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
834 else if (sym->accuse == ACCUSE_HL)
837 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
838 aop->size = getSize (sym->type);
839 wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
840 aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
841 aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
845 wassertl (0, "Marked as being allocated into A or HL but is actually in neither");
853 aop = op->aop = sym->aop = newAsmop (AOP_STR);
854 aop->size = getSize (sym->type);
855 for (i = 0; i < 4; i++)
856 aop->aopu.aop_str[i] = _fReturn[i];
860 /* else spill location */
861 sym->aop = op->aop = aop =
862 aopForSym (ic, sym->usl.spillLoc, result, requires_a);
863 aop->size = getSize (sym->type);
867 /* must be in a register */
868 sym->aop = op->aop = aop = newAsmop (AOP_REG);
869 aop->size = sym->nRegs;
870 for (i = 0; i < sym->nRegs; i++)
871 aop->aopu.aop_reg[i] = sym->regs[i];
874 /*-----------------------------------------------------------------*/
875 /* freeAsmop - free up the asmop given to an operand */
876 /*----------------------------------------------------------------*/
878 freeAsmop (operand * op, asmop * aaop, iCode * ic)
895 if (aop->type == AOP_PAIRPTR && IS_Z80 && aop->aopu.aop_pairId == PAIR_DE)
897 _pop (aop->aopu.aop_pairId);
901 /* all other cases just dealloc */
907 OP_SYMBOL (op)->aop = NULL;
908 /* if the symbol has a spill */
910 SPIL_LOC (op)->aop = NULL;
917 isLitWord (asmop * aop)
919 /* if (aop->size != 2)
932 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
937 /* depending on type */
943 /* PENDING: for re-target */
946 tsprintf (s, "!hashedstr + %d", aop->aopu.aop_immd, offset);
948 else if (offset == 0)
950 tsprintf (s, "%s", aop->aopu.aop_immd);
954 tsprintf (s, "%s + %d", aop->aopu.aop_immd, offset);
956 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
960 value *val = aop->aopu.aop_lit;
961 /* if it is a float then it gets tricky */
962 /* otherwise it is fairly simple */
963 if (!IS_FLOAT (val->type))
965 unsigned long v = (unsigned long) floatFromVal (val);
971 else if (offset == 0)
977 wassertl(0, "Encountered an invalid offset while fetching a literal");
981 tsprintf (buffer, "!immedword", v);
983 tsprintf (buffer, "!constword", v);
985 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
991 convertFloat (&f, floatFromVal (val));
993 tsprintf (buffer, "!immedword", f.w[offset / 2]);
995 tsprintf (buffer, "!constword", f.w[offset / 2]);
996 rs = Safe_calloc (1, strlen (buffer) + 1);
997 return strcpy (rs, buffer);
1006 aopGetWord (asmop * aop, int offset)
1008 return aopGetLitWordLong (aop, offset, TRUE);
1012 isPtr (const char *s)
1014 if (!strcmp (s, "hl"))
1016 if (!strcmp (s, "ix"))
1018 if (!strcmp (s, "iy"))
1024 adjustPair (const char *pair, int *pold, int new)
1030 emit2 ("inc %s", pair);
1035 emit2 ("dec %s", pair);
1041 spillPair (PAIR_ID pairId)
1043 _G.pairs[pairId].last_type = AOP_INVALID;
1044 _G.pairs[pairId].base = NULL;
1050 spillPair (PAIR_HL);
1051 spillPair (PAIR_IY);
1055 requiresHL (asmop * aop)
1070 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1072 const char *l, *base;
1073 const char *pair = _pairs[pairId].name;
1074 l = aopGetLitWordLong (left, offset, FALSE);
1075 base = aopGetLitWordLong (left, 0, FALSE);
1076 wassert (l && pair && base);
1080 if (pairId == PAIR_HL || pairId == PAIR_IY)
1082 if (_G.pairs[pairId].last_type == left->type)
1084 if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1086 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1088 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1091 if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
1098 _G.pairs[pairId].last_type = left->type;
1099 _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1100 _G.pairs[pairId].offset = offset;
1102 /* Both a lit on the right and a true symbol on the left */
1103 emit2 ("ld %s,!hashedstr", pair, l);
1107 fetchPairLong (PAIR_ID pairId, asmop * aop, int offset)
1109 /* if this is remateriazable */
1110 if (isLitWord (aop)) {
1111 fetchLitPair (pairId, aop, offset);
1114 /* we need to get it byte by byte */
1115 if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1116 aopGet (aop, offset, FALSE);
1117 switch (aop->size - offset) {
1119 emit2 ("ld l,!*hl");
1120 emit2 ("ld h,!immedbyte", 0);
1123 // PENDING: Requires that you are only fetching two bytes.
1126 emit2 ("ld h,!*hl");
1130 wassertl (0, "Attempted to fetch too much data into HL");
1134 else if (IS_Z80 && aop->type == AOP_IY) {
1135 /* Instead of fetching relative to IY, just grab directly
1136 from the address IY refers to */
1137 char *l = aopGetLitWordLong (aop, offset, FALSE);
1139 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1141 if (aop->size < 2) {
1142 emit2("ld %s,!zero", _pairs[pairId].h);
1146 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1147 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1149 /* PENDING: check? */
1150 if (pairId == PAIR_HL)
1151 spillPair (PAIR_HL);
1156 fetchPair (PAIR_ID pairId, asmop * aop)
1158 fetchPairLong (pairId, aop, 0);
1162 fetchHL (asmop * aop)
1164 fetchPair (PAIR_HL, aop);
1168 setupPairFromSP (PAIR_ID id, int offset)
1170 wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
1172 if (offset < INT8MIN || offset > INT8MAX)
1174 emit2 ("ld hl,!immedword", offset);
1175 emit2 ("add hl,sp");
1179 emit2 ("!ldahlsp", offset);
1184 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1189 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
1190 fetchLitPair (pairId, aop, 0);
1194 wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
1196 fetchLitPair (pairId, aop, offset);
1197 _G.pairs[pairId].offset = offset;
1201 wassertl (IS_Z80, "Only the Z80 has an extended stack");
1202 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
1205 int offset = aop->aopu.aop_stk + _G.stack.offset;
1207 if (_G.pairs[pairId].last_type == aop->type &&
1208 _G.pairs[pairId].offset == offset)
1214 /* PENDING: Do this better. */
1215 sprintf (buffer, "%d", offset + _G.stack.pushed);
1216 emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
1217 emit2 ("add %s,sp", _pairs[pairId].name);
1218 _G.pairs[pairId].last_type = aop->type;
1219 _G.pairs[pairId].offset = offset;
1226 /* Doesnt include _G.stack.pushed */
1227 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1228 if (aop->aopu.aop_stk > 0)
1230 abso += _G.stack.param_offset;
1232 assert (pairId == PAIR_HL);
1233 /* In some cases we can still inc or dec hl */
1234 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1236 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1240 setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
1242 _G.pairs[pairId].offset = abso;
1247 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
1253 _G.pairs[pairId].last_type = aop->type;
1259 emit2 ("!tlabeldef", key);
1263 /*-----------------------------------------------------------------*/
1264 /* aopGet - for fetching value of the aop */
1265 /*-----------------------------------------------------------------*/
1267 aopGet (asmop * aop, int offset, bool bit16)
1271 /* offset is greater than size then zero */
1272 /* PENDING: this seems a bit screwed in some pointer cases. */
1273 if (offset > (aop->size - 1) &&
1274 aop->type != AOP_LIT)
1276 tsprintf (s, "!zero");
1277 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1280 /* depending on type */
1284 /* PENDING: re-target */
1286 tsprintf (s, "!immedwords", aop->aopu.aop_immd);
1291 tsprintf (s, "!bankimmeds", aop->aopu.aop_immd);
1294 tsprintf (s, "!msbimmeds", aop->aopu.aop_immd);
1297 tsprintf (s, "!lsbimmeds", aop->aopu.aop_immd);
1300 wassertl (0, "Fetching from beyond the limits of an immediate value.");
1303 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1307 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1310 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1314 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1317 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1320 return aop->aopu.aop_reg[offset]->name;
1324 setupPair (PAIR_HL, aop, offset);
1325 tsprintf (s, "!*hl");
1327 return traceAlloc(&_G.trace.aops, Safe_strdup (s));
1331 setupPair (PAIR_IY, aop, offset);
1332 tsprintf (s, "!*iyx", offset);
1334 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1338 setupPair (PAIR_IY, aop, offset);
1339 tsprintf (s, "!*iyx", offset, offset);
1341 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1346 setupPair (PAIR_HL, aop, offset);
1347 tsprintf (s, "!*hl");
1351 if (aop->aopu.aop_stk >= 0)
1352 offset += _G.stack.param_offset;
1353 tsprintf (s, "!*ixx", aop->aopu.aop_stk + offset);
1356 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1359 wassertl (0, "Tried to fetch from a bit variable");
1368 tsprintf(s, "!zero");
1369 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1373 wassert (offset < 2);
1374 return aop->aopu.aop_str[offset];
1377 return aopLiteral (aop->aopu.aop_lit, offset);
1381 unsigned long v = aop->aopu.aop_simplelit;
1384 tsprintf (s, "!immedbyte", (unsigned int) v & 0xff);
1386 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1390 return aop->aopu.aop_str[offset];
1393 setupPair (aop->aopu.aop_pairId, aop, offset);
1394 sprintf (s, "(%s)", _pairs[aop->aopu.aop_pairId].name);
1396 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1401 wassertl (0, "aopget got unsupported aop->type");
1406 isRegString (const char *s)
1408 if (!strcmp (s, "b") ||
1420 isConstant (const char *s)
1422 /* This is a bit of a hack... */
1423 return (*s == '#' || *s == '$');
1427 canAssignToPtr (const char *s)
1429 if (isRegString (s))
1436 /*-----------------------------------------------------------------*/
1437 /* aopPut - puts a string for a aop */
1438 /*-----------------------------------------------------------------*/
1440 aopPut (asmop * aop, const char *s, int offset)
1444 if (aop->size && offset > (aop->size - 1))
1446 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1447 "aopPut got offset > aop->size");
1452 tsprintf(buffer2, s);
1455 /* will assign value to value */
1456 /* depending on where it is ofcourse */
1462 if (strcmp (s, "a"))
1463 emit2 ("ld a,%s", s);
1464 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1469 if (strcmp (s, "a"))
1470 emit2 ("ld a,%s", s);
1471 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1475 if (!strcmp (s, "!*hl"))
1476 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1479 aop->aopu.aop_reg[offset]->name, s);
1484 if (!canAssignToPtr (s))
1486 emit2 ("ld a,%s", s);
1487 setupPair (PAIR_IY, aop, offset);
1488 emit2 ("ld !*iyx,a", offset);
1492 setupPair (PAIR_IY, aop, offset);
1493 emit2 ("ld !*iyx,%s", offset, s);
1499 /* PENDING: for re-target */
1500 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1502 emit2 ("ld a,!*hl");
1505 setupPair (PAIR_HL, aop, offset);
1507 emit2 ("ld !*hl,%s", s);
1512 if (!canAssignToPtr (s))
1514 emit2 ("ld a,%s", s);
1515 setupPair (PAIR_IY, aop, offset);
1516 emit2 ("ld !*iyx,a", offset);
1520 setupPair (PAIR_IY, aop, offset);
1521 emit2 ("ld !*iyx,%s", offset, s);
1528 /* PENDING: re-target */
1529 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1531 emit2 ("ld a,!*hl");
1534 setupPair (PAIR_HL, aop, offset);
1535 if (!canAssignToPtr (s))
1537 emit2 ("ld a,%s", s);
1538 emit2 ("ld !*hl,a");
1541 emit2 ("ld !*hl,%s", s);
1545 if (aop->aopu.aop_stk >= 0)
1546 offset += _G.stack.param_offset;
1547 if (!canAssignToPtr (s))
1549 emit2 ("ld a,%s", s);
1550 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
1553 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
1558 /* if bit variable */
1559 if (!aop->aopu.aop_dir)
1566 /* In bit space but not in C - cant happen */
1567 wassertl (0, "Tried to write into a bit variable");
1573 if (strcmp (aop->aopu.aop_str[offset], s))
1575 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1581 if (!offset && (strcmp (s, "acc") == 0))
1585 wassertl (0, "Tried to access past the end of A");
1589 if (strcmp (aop->aopu.aop_str[offset], s))
1590 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1595 wassert (offset < 2);
1596 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1600 setupPair (aop->aopu.aop_pairId, aop, offset);
1601 emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
1605 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1606 "aopPut got unsupported aop->type");
1611 #define AOP(op) op->aop
1612 #define AOP_TYPE(op) AOP(op)->type
1613 #define AOP_SIZE(op) AOP(op)->size
1614 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
1617 commitPair (asmop * aop, PAIR_ID id)
1619 if (id == PAIR_HL && requiresHL (aop))
1623 aopPut (aop, "a", 0);
1624 aopPut (aop, "d", 1);
1628 aopPut (aop, _pairs[id].l, 0);
1629 aopPut (aop, _pairs[id].h, 1);
1633 /*-----------------------------------------------------------------*/
1634 /* getDataSize - get the operand data size */
1635 /*-----------------------------------------------------------------*/
1637 getDataSize (operand * op)
1640 size = AOP_SIZE (op);
1644 wassertl (0, "Somehow got a three byte data pointer");
1649 /*-----------------------------------------------------------------*/
1650 /* movLeft2Result - move byte from left to result */
1651 /*-----------------------------------------------------------------*/
1653 movLeft2Result (operand * left, int offl,
1654 operand * result, int offr, int sign)
1657 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
1659 l = aopGet (AOP (left), offl, FALSE);
1663 aopPut (AOP (result), l, offr);
1667 if (getDataSize (left) == offl + 1)
1669 emit2 ("ld a,%s", l);
1670 aopPut (AOP (result), "a", offr);
1677 /** Put Acc into a register set
1680 outAcc (operand * result)
1683 size = getDataSize (result);
1686 aopPut (AOP (result), "a", 0);
1689 /* unsigned or positive */
1692 aopPut (AOP (result), "!zero", offset++);
1697 /** Take the value in carry and put it into a register
1700 outBitCLong (operand * result, bool swap_sense)
1702 /* if the result is bit */
1703 if (AOP_TYPE (result) == AOP_CRY)
1705 wassertl (0, "Tried to write carry to a bit");
1709 emit2 ("ld a,!zero");
1712 emit2 ("xor a,!immedbyte", 1);
1718 outBitC (operand * result)
1720 outBitCLong (result, FALSE);
1723 /*-----------------------------------------------------------------*/
1724 /* toBoolean - emit code for orl a,operator(sizeop) */
1725 /*-----------------------------------------------------------------*/
1727 _toBoolean (operand * oper)
1729 int size = AOP_SIZE (oper);
1733 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
1736 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
1740 if (AOP (oper)->type != AOP_ACC)
1743 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
1748 /*-----------------------------------------------------------------*/
1749 /* genNot - generate code for ! operation */
1750 /*-----------------------------------------------------------------*/
1754 sym_link *optype = operandType (IC_LEFT (ic));
1756 /* assign asmOps to operand & result */
1757 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
1758 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1760 /* if in bit space then a special case */
1761 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1763 wassertl (0, "Tried to negate a bit");
1766 /* if type float then do float */
1767 if (IS_FLOAT (optype))
1769 wassertl (0, "Tried to negate a float");
1772 _toBoolean (IC_LEFT (ic));
1777 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
1778 emit2 ("sub a,!one");
1779 outBitC (IC_RESULT (ic));
1781 /* release the aops */
1782 freeAsmop (IC_LEFT (ic), NULL, ic);
1783 freeAsmop (IC_RESULT (ic), NULL, ic);
1786 /*-----------------------------------------------------------------*/
1787 /* genCpl - generate code for complement */
1788 /*-----------------------------------------------------------------*/
1796 /* assign asmOps to operand & result */
1797 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1798 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1800 /* if both are in bit space then
1802 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1803 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1805 wassertl (0, "Left and the result are in bit space");
1808 size = AOP_SIZE (IC_RESULT (ic));
1811 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
1814 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1817 /* release the aops */
1818 freeAsmop (IC_LEFT (ic), NULL, ic);
1819 freeAsmop (IC_RESULT (ic), NULL, ic);
1823 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
1830 store de into result
1835 store de into result
1837 const char *first = isAdd ? "add" : "sub";
1838 const char *later = isAdd ? "adc" : "sbc";
1840 wassertl (IS_GB, "Code is only relevent to the gbz80");
1841 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
1843 fetchPair (PAIR_DE, left);
1846 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
1849 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
1852 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
1853 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
1855 fetchPairLong (PAIR_DE, left, MSB24);
1856 aopGet (right, MSB24, FALSE);
1860 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
1863 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
1865 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
1866 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
1870 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
1872 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
1875 /*-----------------------------------------------------------------*/
1876 /* genUminus - unary minus code generation */
1877 /*-----------------------------------------------------------------*/
1879 genUminus (iCode * ic)
1882 sym_link *optype, *rtype;
1885 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1886 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1888 /* if both in bit space then special
1890 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1891 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1893 wassertl (0, "Left and right are in bit space");
1897 optype = operandType (IC_LEFT (ic));
1898 rtype = operandType (IC_RESULT (ic));
1900 /* if float then do float stuff */
1901 if (IS_FLOAT (optype))
1903 wassertl (0, "Tried to do a unary minus on a float");
1907 /* otherwise subtract from zero */
1908 size = AOP_SIZE (IC_LEFT (ic));
1910 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
1912 /* Create a new asmop with value zero */
1913 asmop *azero = newAsmop (AOP_SIMPLELIT);
1914 azero->aopu.aop_simplelit = 0;
1916 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
1924 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
1925 emit2 ("ld a,!zero");
1926 emit2 ("sbc a,%s", l);
1927 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1930 /* if any remaining bytes in the result */
1931 /* we just need to propagate the sign */
1932 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
1937 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1941 /* release the aops */
1942 freeAsmop (IC_LEFT (ic), NULL, ic);
1943 freeAsmop (IC_RESULT (ic), NULL, ic);
1946 /*-----------------------------------------------------------------*/
1947 /* assignResultValue - */
1948 /*-----------------------------------------------------------------*/
1950 assignResultValue (operand * oper)
1952 int size = AOP_SIZE (oper);
1955 wassertl (size <= 4, "Got a result that is bigger than four bytes");
1956 topInA = requiresHL (AOP (oper));
1958 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
1960 /* We do it the hard way here. */
1962 aopPut (AOP (oper), _fReturn[0], 0);
1963 aopPut (AOP (oper), _fReturn[1], 1);
1965 aopPut (AOP (oper), _fReturn[0], 2);
1966 aopPut (AOP (oper), _fReturn[1], 3);
1972 aopPut (AOP (oper), _fReturn[size], size);
1978 _saveRegsForCall(iCode *ic, int sendSetSize)
1981 o Stack parameters are pushed before this function enters
1982 o DE and BC may be used in this function.
1983 o HL and DE may be used to return the result.
1984 o HL and DE may be used to send variables.
1985 o DE and BC may be used to store the result value.
1986 o HL may be used in computing the sent value of DE
1987 o The iPushes for other parameters occur before any addSets
1989 Logic: (to be run inside the first iPush or if none, before sending)
1990 o Compute if DE and/or BC are in use over the call
1991 o Compute if DE is used in the send set
1992 o Compute if DE and/or BC are used to hold the result value
1993 o If (DE is used, or in the send set) and is not used in the result, push.
1994 o If BC is used and is not in the result, push
1996 o If DE is used in the send set, fetch
1997 o If HL is used in the send set, fetch
2001 if (_G.saves.saved == FALSE) {
2002 bool deInUse, bcInUse;
2004 bool bcInRet = FALSE, deInRet = FALSE;
2007 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
2009 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2010 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2012 deSending = (sendSetSize > 1);
2014 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2016 if (bcInUse && bcInRet == FALSE) {
2018 _G.stack.pushedBC = TRUE;
2020 if (deInUse && deInRet == FALSE) {
2022 _G.stack.pushedDE = TRUE;
2025 _G.saves.saved = TRUE;
2028 /* Already saved. */
2032 /*-----------------------------------------------------------------*/
2033 /* genIpush - genrate code for pushing this gets a little complex */
2034 /*-----------------------------------------------------------------*/
2036 genIpush (iCode * ic)
2038 int size, offset = 0;
2041 /* if this is not a parm push : ie. it is spill push
2042 and spill push is always done on the local stack */
2045 wassertl(0, "Encountered an unsupported spill push.");
2049 if (_G.saves.saved == FALSE) {
2050 /* Caller saves, and this is the first iPush. */
2051 /* Scan ahead until we find the function that we are pushing parameters to.
2052 Count the number of addSets on the way to figure out what registers
2053 are used in the send set.
2056 iCode *walk = ic->next;
2059 if (walk->op == SEND) {
2062 else if (walk->op == CALL || walk->op == PCALL) {
2071 _saveRegsForCall(walk, nAddSets);
2074 /* Already saved by another iPush. */
2077 /* then do the push */
2078 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2080 size = AOP_SIZE (IC_LEFT (ic));
2082 if (isPair (AOP (IC_LEFT (ic))))
2084 _G.stack.pushed += 2;
2085 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2091 fetchHL (AOP (IC_LEFT (ic)));
2093 spillPair (PAIR_HL);
2094 _G.stack.pushed += 2;
2099 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
2101 spillPair (PAIR_HL);
2102 _G.stack.pushed += 2;
2103 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 0);
2105 spillPair (PAIR_HL);
2106 _G.stack.pushed += 2;
2112 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2114 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2116 emit2 ("ld a,(%s)", l);
2120 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2121 emit2 ("ld a,%s", l);
2129 freeAsmop (IC_LEFT (ic), NULL, ic);
2132 /*-----------------------------------------------------------------*/
2133 /* genIpop - recover the registers: can happen only for spilling */
2134 /*-----------------------------------------------------------------*/
2136 genIpop (iCode * ic)
2141 /* if the temp was not pushed then */
2142 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2145 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2146 size = AOP_SIZE (IC_LEFT (ic));
2147 offset = (size - 1);
2148 if (isPair (AOP (IC_LEFT (ic))))
2150 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2158 spillPair (PAIR_HL);
2159 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2163 freeAsmop (IC_LEFT (ic), NULL, ic);
2166 /* This is quite unfortunate */
2168 setArea (int inHome)
2171 static int lastArea = 0;
2173 if (_G.in_home != inHome) {
2175 const char *sz = port->mem.code_name;
2176 port->mem.code_name = "HOME";
2177 emit2("!area", CODE_NAME);
2178 port->mem.code_name = sz;
2181 emit2("!area", CODE_NAME); */
2182 _G.in_home = inHome;
2193 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2197 symbol *sym = OP_SYMBOL (op);
2199 if (sym->isspilt || sym->nRegs == 0)
2202 aopOp (op, ic, FALSE, FALSE);
2205 if (aop->type == AOP_REG)
2208 for (i = 0; i < aop->size; i++)
2210 if (pairId == PAIR_DE)
2212 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2213 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2215 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2218 else if (pairId == PAIR_BC)
2220 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2221 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2223 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2233 freeAsmop (IC_LEFT (ic), NULL, ic);
2237 /** Emit the code for a call statement
2240 emitCall (iCode * ic, bool ispcall)
2242 sym_link *detype = getSpec (operandType (IC_LEFT (ic)));
2244 bitVect *rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
2246 /* if caller saves & we have not saved then */
2252 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2254 /* if send set is not empty then assign */
2259 int nSend = elementsInSet(_G.sendSet);
2260 bool swapped = FALSE;
2262 int _z80_sendOrder[] = {
2267 /* Check if the parameters are swapped. If so route through hl instead. */
2268 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2270 sic = setFirstItem(_G.sendSet);
2271 sic = setNextItem(_G.sendSet);
2273 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2274 /* The second send value is loaded from one the one that holds the first
2275 send, i.e. it is overwritten. */
2276 /* Cache the first in HL, and load the second from HL instead. */
2277 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2278 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2284 for (sic = setFirstItem (_G.sendSet); sic;
2285 sic = setNextItem (_G.sendSet))
2288 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2290 size = AOP_SIZE (IC_LEFT (sic));
2291 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2292 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2294 // PENDING: Mild hack
2295 if (swapped == TRUE && send == 1) {
2297 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2300 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2302 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2305 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2309 freeAsmop (IC_LEFT (sic), NULL, sic);
2316 if (IS_BANKEDCALL (detype))
2318 werror (W_INDIR_BANKED);
2320 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2322 if (isLitWord (AOP (IC_LEFT (ic))))
2324 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2328 symbol *rlbl = newiTempLabel (NULL);
2329 spillPair (PAIR_HL);
2330 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2332 _G.stack.pushed += 2;
2334 fetchHL (AOP (IC_LEFT (ic)));
2336 emit2 ("!tlabeldef", (rlbl->key + 100));
2337 _G.stack.pushed -= 2;
2339 freeAsmop (IC_LEFT (ic), NULL, ic);
2343 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2344 OP_SYMBOL (IC_LEFT (ic))->rname :
2345 OP_SYMBOL (IC_LEFT (ic))->name;
2346 if (IS_BANKEDCALL (detype))
2348 emit2 ("call banked_call");
2349 emit2 ("!dws", name);
2350 emit2 ("!dw !bankimmeds", name);
2355 emit2 ("call %s", name);
2360 /* Mark the regsiters as restored. */
2361 _G.saves.saved = FALSE;
2363 /* if we need assign a result value */
2364 if ((IS_ITEMP (IC_RESULT (ic)) &&
2365 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2366 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2367 IS_TRUE_SYMOP (IC_RESULT (ic)))
2370 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2372 assignResultValue (IC_RESULT (ic));
2374 freeAsmop (IC_RESULT (ic), NULL, ic);
2377 /* adjust the stack for parameters if required */
2380 int i = ic->parmBytes;
2382 _G.stack.pushed -= i;
2385 emit2 ("!ldaspsp", i);
2392 emit2 ("ld hl,#%d", i);
2393 emit2 ("add hl,sp");
2410 if (_G.stack.pushedDE)
2412 bool dInUse = bitVectBitValue(rInUse, D_IDX);
2413 bool eInUse = bitVectBitValue(rInUse, E_IDX);
2415 if (dInUse && eInUse)
2431 wassertl (0, "Neither D or E were in use but it was pushed.");
2433 _G.stack.pushedDE = FALSE;
2436 if (_G.stack.pushedBC)
2438 bool bInUse = bitVectBitValue(rInUse, B_IDX);
2439 bool cInUse = bitVectBitValue(rInUse, C_IDX);
2441 // If both B and C are used in the return value, then we won't get
2443 if (bInUse && cInUse)
2459 wassertl (0, "Neither B or C were in use but it was pushed.");
2461 _G.stack.pushedBC = FALSE;
2465 /*-----------------------------------------------------------------*/
2466 /* genCall - generates a call statement */
2467 /*-----------------------------------------------------------------*/
2469 genCall (iCode * ic)
2471 emitCall (ic, FALSE);
2474 /*-----------------------------------------------------------------*/
2475 /* genPcall - generates a call by pointer statement */
2476 /*-----------------------------------------------------------------*/
2478 genPcall (iCode * ic)
2480 emitCall (ic, TRUE);
2483 /*-----------------------------------------------------------------*/
2484 /* resultRemat - result is rematerializable */
2485 /*-----------------------------------------------------------------*/
2487 resultRemat (iCode * ic)
2489 if (SKIP_IC (ic) || ic->op == IFX)
2492 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2494 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2495 if (sym->remat && !POINTER_SET (ic))
2502 extern set *publics;
2504 /*-----------------------------------------------------------------*/
2505 /* genFunction - generated code for function entry */
2506 /*-----------------------------------------------------------------*/
2508 genFunction (iCode * ic)
2510 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2514 bool bcInUse = FALSE;
2515 bool deInUse = FALSE;
2518 setArea (IS_NONBANKED (sym->etype));
2520 /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
2523 _G.receiveOffset = 0;
2525 /* Record the last function name for debugging. */
2526 _G.lastFunctionName = sym->rname;
2528 /* Create the function header */
2529 emit2 ("!functionheader", sym->name);
2530 /* PENDING: portability. */
2531 emit2 ("__%s_start:", sym->rname);
2532 emit2 ("!functionlabeldef", sym->rname);
2534 if (options.profile)
2536 emit2 ("!profileenter");
2539 fetype = getSpec (operandType (IC_LEFT (ic)));
2541 /* if critical function then turn interrupts off */
2542 if (SPEC_CRTCL (fetype))
2545 /* if this is an interrupt service routine then save all potentially used registers. */
2546 if (IS_ISR (sym->etype))
2551 /* PENDING: callee-save etc */
2553 _G.stack.param_offset = 0;
2556 /* Detect which registers are used. */
2560 for (i = 0; i < sym->regsUsed->size; i++)
2562 if (bitVectBitValue (sym->regsUsed, i))
2576 /* Other systems use DE as a temporary. */
2587 _G.stack.param_offset += 2;
2590 _G.stack.pushedBC = bcInUse;
2595 _G.stack.param_offset += 2;
2598 _G.stack.pushedDE = deInUse;
2601 /* adjust the stack for the function */
2602 _G.stack.last = sym->stack;
2604 if (sym->stack && IS_GB && sym->stack > -INT8MIN)
2605 emit2 ("!enterxl", sym->stack);
2606 else if (sym->stack)
2607 emit2 ("!enterx", sym->stack);
2610 _G.stack.offset = sym->stack;
2613 /*-----------------------------------------------------------------*/
2614 /* genEndFunction - generates epilogue for functions */
2615 /*-----------------------------------------------------------------*/
2617 genEndFunction (iCode * ic)
2619 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2621 if (IS_ISR (sym->etype))
2623 wassertl (0, "Tried to close an interrupt support function");
2627 if (SPEC_CRTCL (sym->etype))
2630 /* PENDING: calleeSave */
2632 if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
2634 emit2 ("!leavexl", _G.stack.offset);
2636 else if (_G.stack.offset)
2638 emit2 ("!leavex", _G.stack.offset);
2646 if (_G.stack.pushedDE)
2649 _G.stack.pushedDE = FALSE;
2652 if (_G.stack.pushedDE)
2655 _G.stack.pushedDE = FALSE;
2659 if (options.profile)
2661 emit2 ("!profileexit");
2665 /* Both baned and non-banked just ret */
2668 /* PENDING: portability. */
2669 emit2 ("__%s_end:", sym->rname);
2671 _G.flushStatics = 1;
2672 _G.stack.pushed = 0;
2673 _G.stack.offset = 0;
2676 /*-----------------------------------------------------------------*/
2677 /* genRet - generate code for return statement */
2678 /*-----------------------------------------------------------------*/
2683 /* Errk. This is a hack until I can figure out how
2684 to cause dehl to spill on a call */
2685 int size, offset = 0;
2687 /* if we have no return value then
2688 just generate the "ret" */
2692 /* we have something to return then
2693 move the return value into place */
2694 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2695 size = AOP_SIZE (IC_LEFT (ic));
2697 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
2701 emit2 ("ld de,%s", l);
2705 emit2 ("ld hl,%s", l);
2710 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
2712 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
2713 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
2719 l = aopGet (AOP (IC_LEFT (ic)), offset,
2721 if (strcmp (_fReturn[offset], l))
2722 emit2 ("ld %s,%s", _fReturn[offset++], l);
2726 freeAsmop (IC_LEFT (ic), NULL, ic);
2729 /* generate a jump to the return label
2730 if the next is not the return statement */
2731 if (!(ic->next && ic->next->op == LABEL &&
2732 IC_LABEL (ic->next) == returnLabel))
2734 emit2 ("jp !tlabel", returnLabel->key + 100);
2737 /*-----------------------------------------------------------------*/
2738 /* genLabel - generates a label */
2739 /*-----------------------------------------------------------------*/
2741 genLabel (iCode * ic)
2743 /* special case never generate */
2744 if (IC_LABEL (ic) == entryLabel)
2747 emitLabel (IC_LABEL (ic)->key + 100);
2750 /*-----------------------------------------------------------------*/
2751 /* genGoto - generates a ljmp */
2752 /*-----------------------------------------------------------------*/
2754 genGoto (iCode * ic)
2756 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
2759 /*-----------------------------------------------------------------*/
2760 /* genPlusIncr :- does addition with increment if possible */
2761 /*-----------------------------------------------------------------*/
2763 genPlusIncr (iCode * ic)
2765 unsigned int icount;
2766 unsigned int size = getDataSize (IC_RESULT (ic));
2767 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
2769 /* will try to generate an increment */
2770 /* if the right side is not a literal
2772 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
2775 emitDebug ("; genPlusIncr");
2777 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
2779 /* If result is a pair */
2780 if (resultId != PAIR_INVALID)
2782 if (isLitWord (AOP (IC_LEFT (ic))))
2784 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
2787 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
2789 fetchPair (resultId, AOP (IC_RIGHT (ic)));
2790 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
2796 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2800 movLeft2Result (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0);
2801 movLeft2Result (IC_LEFT (ic), 1, IC_RESULT (ic), 1, 0);
2805 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
2810 /* if the literal value of the right hand side
2811 is greater than 4 then it is not worth it */
2815 /* if increment 16 bits in register */
2816 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
2822 symbol *tlbl = NULL;
2823 tlbl = newiTempLabel (NULL);
2826 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
2829 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
2832 emitLabel (tlbl->key + 100);
2836 /* if the sizes are greater than 1 then we cannot */
2837 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
2838 AOP_SIZE (IC_LEFT (ic)) > 1)
2841 /* we can if the aops of the left & result match or
2842 if they are in registers and the registers are the
2844 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2848 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
2856 /*-----------------------------------------------------------------*/
2857 /* outBitAcc - output a bit in acc */
2858 /*-----------------------------------------------------------------*/
2860 outBitAcc (operand * result)
2862 symbol *tlbl = newiTempLabel (NULL);
2863 /* if the result is a bit */
2864 if (AOP_TYPE (result) == AOP_CRY)
2866 wassertl (0, "Tried to write A into a bit");
2870 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
2871 emit2 ("ld a,!one");
2872 emitLabel (tlbl->key + 100);
2878 couldDestroyCarry (asmop *aop)
2882 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
2891 shiftIntoPair (int idx, asmop *aop)
2893 PAIR_ID id = PAIR_INVALID;
2895 wassertl (IS_Z80, "Only implemented for the Z80");
2896 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
2908 wassertl (0, "Internal error - hit default case");
2911 emitDebug ("; Shift into pair idx %u", idx);
2915 setupPair (PAIR_HL, aop, 0);
2919 setupPair (PAIR_IY, aop, 0);
2921 emit2 ("pop %s", _pairs[id].name);
2924 aop->type = AOP_PAIRPTR;
2925 aop->aopu.aop_pairId = id;
2926 _G.pairs[id].offset = 0;
2927 _G.pairs[id].last_type = aop->type;
2931 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
2933 wassert (left && right);
2937 if (couldDestroyCarry (right) && couldDestroyCarry (result))
2939 shiftIntoPair (0, right);
2940 shiftIntoPair (1, result);
2942 else if (couldDestroyCarry (right))
2944 shiftIntoPair (0, right);
2946 else if (couldDestroyCarry (result))
2948 shiftIntoPair (0, result);
2957 /*-----------------------------------------------------------------*/
2958 /* genPlus - generates code for addition */
2959 /*-----------------------------------------------------------------*/
2961 genPlus (iCode * ic)
2963 int size, offset = 0;
2965 /* special cases :- */
2967 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2968 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
2969 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2971 /* Swap the left and right operands if:
2973 if literal, literal on the right or
2974 if left requires ACC or right is already
2977 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
2978 (AOP_NEEDSACC (IC_LEFT (ic))) ||
2979 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
2981 operand *t = IC_RIGHT (ic);
2982 IC_RIGHT (ic) = IC_LEFT (ic);
2986 /* if both left & right are in bit
2988 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
2989 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
2992 wassertl (0, "Tried to add two bits");
2995 /* if left in bit space & right literal */
2996 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
2997 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
2999 /* Can happen I guess */
3000 wassertl (0, "Tried to add a bit to a literal");
3003 /* if I can do an increment instead
3004 of add then GOOD for ME */
3005 if (genPlusIncr (ic) == TRUE)
3008 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3010 size = getDataSize (IC_RESULT (ic));
3012 /* Special case when left and right are constant */
3013 if (isPair (AOP (IC_RESULT (ic))))
3016 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3017 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3019 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3025 sprintf (buffer, "#(%s + %s)", left, right);
3026 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3031 if (isPair (AOP (IC_RIGHT (ic))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3033 /* Fetch into HL then do the add */
3034 spillPair (PAIR_HL);
3035 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3036 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3041 ld hl,sp+n trashes C so we cant afford to do it during an
3042 add with stack based varibles. Worst case is:
3055 So you cant afford to load up hl if either left, right, or result
3056 is on the stack (*sigh*) The alt is:
3064 Combinations in here are:
3065 * If left or right are in bc then the loss is small - trap later
3066 * If the result is in bc then the loss is also small
3070 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3071 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3072 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3074 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3075 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3076 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3077 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3079 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3081 /* Swap left and right */
3082 operand *t = IC_RIGHT (ic);
3083 IC_RIGHT (ic) = IC_LEFT (ic);
3086 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3088 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3089 emit2 ("add hl,bc");
3093 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3094 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3095 emit2 ("add hl,de");
3097 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3103 /* Be paranoid on the GB with 4 byte variables due to how C
3104 can be trashed by lda hl,n(sp).
3106 _gbz80_emitAddSubLong (ic, TRUE);
3111 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3115 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3117 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3120 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3123 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3127 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3130 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3133 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3135 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3139 freeAsmop (IC_LEFT (ic), NULL, ic);
3140 freeAsmop (IC_RIGHT (ic), NULL, ic);
3141 freeAsmop (IC_RESULT (ic), NULL, ic);
3145 /*-----------------------------------------------------------------*/
3146 /* genMinusDec :- does subtraction with deccrement if possible */
3147 /*-----------------------------------------------------------------*/
3149 genMinusDec (iCode * ic)
3151 unsigned int icount;
3152 unsigned int size = getDataSize (IC_RESULT (ic));
3154 /* will try to generate an increment */
3155 /* if the right side is not a literal we cannot */
3156 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3159 /* if the literal value of the right hand side
3160 is greater than 4 then it is not worth it */
3161 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3164 size = getDataSize (IC_RESULT (ic));
3166 /* if decrement 16 bits in register */
3167 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3168 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3171 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3175 /* If result is a pair */
3176 if (isPair (AOP (IC_RESULT (ic))))
3178 movLeft2Result (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0);
3179 movLeft2Result (IC_LEFT (ic), 1, IC_RESULT (ic), 1, 0);
3181 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3185 /* if increment 16 bits in register */
3186 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3190 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3193 emit2 ("dec %s", _getTempPairName());
3196 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3202 /* if the sizes are greater than 1 then we cannot */
3203 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3204 AOP_SIZE (IC_LEFT (ic)) > 1)
3207 /* we can if the aops of the left & result match or if they are in
3208 registers and the registers are the same */
3209 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3212 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3219 /*-----------------------------------------------------------------*/
3220 /* genMinus - generates code for subtraction */
3221 /*-----------------------------------------------------------------*/
3223 genMinus (iCode * ic)
3225 int size, offset = 0;
3226 unsigned long lit = 0L;
3228 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3229 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3230 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3232 /* special cases :- */
3233 /* if both left & right are in bit space */
3234 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3235 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3237 wassertl (0, "Tried to subtract two bits");
3241 /* if I can do an decrement instead of subtract then GOOD for ME */
3242 if (genMinusDec (ic) == TRUE)
3245 size = getDataSize (IC_RESULT (ic));
3247 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3252 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3256 /* Same logic as genPlus */
3259 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3260 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3261 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3263 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3264 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3265 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3266 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3268 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3269 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3271 if (left == PAIR_INVALID && right == PAIR_INVALID)
3276 else if (right == PAIR_INVALID)
3278 else if (left == PAIR_INVALID)
3281 fetchPair (left, AOP (IC_LEFT (ic)));
3282 /* Order is important. Right may be HL */
3283 fetchPair (right, AOP (IC_RIGHT (ic)));
3285 emit2 ("ld a,%s", _pairs[left].l);
3286 emit2 ("sub a,%s", _pairs[right].l);
3288 emit2 ("ld a,%s", _pairs[left].h);
3289 emit2 ("sbc a,%s", _pairs[right].h);
3291 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3292 aopPut (AOP (IC_RESULT (ic)), "e", 0);
3298 /* Be paranoid on the GB with 4 byte variables due to how C
3299 can be trashed by lda hl,n(sp).
3301 _gbz80_emitAddSubLong (ic, FALSE);
3306 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3308 /* if literal, add a,#-lit, else normal subb */
3311 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3312 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3316 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3319 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3323 /* first add without previous c */
3325 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
3327 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3329 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3332 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3333 AOP_SIZE (IC_LEFT (ic)) == 3 &&
3334 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3336 wassertl (0, "Tried to subtract on a long pointer");
3340 freeAsmop (IC_LEFT (ic), NULL, ic);
3341 freeAsmop (IC_RIGHT (ic), NULL, ic);
3342 freeAsmop (IC_RESULT (ic), NULL, ic);
3345 /*-----------------------------------------------------------------*/
3346 /* genMult - generates code for multiplication */
3347 /*-----------------------------------------------------------------*/
3349 genMult (iCode * ic)
3351 /* Shouldn't occur - all done through function calls */
3352 wassertl (0, "Multiplication is handled through support function calls");
3355 /*-----------------------------------------------------------------*/
3356 /* genDiv - generates code for division */
3357 /*-----------------------------------------------------------------*/
3361 /* Shouldn't occur - all done through function calls */
3362 wassertl (0, "Division is handled through support function calls");
3365 /*-----------------------------------------------------------------*/
3366 /* genMod - generates code for division */
3367 /*-----------------------------------------------------------------*/
3371 /* Shouldn't occur - all done through function calls */
3375 /*-----------------------------------------------------------------*/
3376 /* genIfxJump :- will create a jump depending on the ifx */
3377 /*-----------------------------------------------------------------*/
3379 genIfxJump (iCode * ic, char *jval)
3384 /* if true label then we jump if condition
3388 jlbl = IC_TRUE (ic);
3389 if (!strcmp (jval, "a"))
3393 else if (!strcmp (jval, "c"))
3397 else if (!strcmp (jval, "nc"))
3403 /* The buffer contains the bit on A that we should test */
3409 /* false label is present */
3410 jlbl = IC_FALSE (ic);
3411 if (!strcmp (jval, "a"))
3415 else if (!strcmp (jval, "c"))
3419 else if (!strcmp (jval, "nc"))
3425 /* The buffer contains the bit on A that we should test */
3429 /* Z80 can do a conditional long jump */
3430 if (!strcmp (jval, "a"))
3434 else if (!strcmp (jval, "c"))
3437 else if (!strcmp (jval, "nc"))
3442 emit2 ("bit %s,a", jval);
3444 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
3446 /* mark the icode as generated */
3452 _getPairIdName (PAIR_ID id)
3454 return _pairs[id].name;
3458 /** Generic compare for > or <
3461 genCmp (operand * left, operand * right,
3462 operand * result, iCode * ifx, int sign)
3464 int size, offset = 0;
3465 unsigned long lit = 0L;
3466 bool swap_sense = FALSE;
3468 /* if left & right are bit variables */
3469 if (AOP_TYPE (left) == AOP_CRY &&
3470 AOP_TYPE (right) == AOP_CRY)
3472 /* Cant happen on the Z80 */
3473 wassertl (0, "Tried to compare two bits");
3477 /* subtract right from left if at the
3478 end the carry flag is set then we know that
3479 left is greater than right */
3480 size = max (AOP_SIZE (left), AOP_SIZE (right));
3482 /* if unsigned char cmp with lit, just compare */
3484 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
3486 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3489 emit2 ("xor a,!immedbyte", 0x80);
3490 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
3493 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3495 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
3497 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
3498 // Pull left into DE and right into HL
3499 aopGet (AOP(left), LSB, FALSE);
3502 aopGet (AOP(right), LSB, FALSE);
3506 if (size == 0 && sign)
3508 // Highest byte when signed needs the bits flipped
3511 emit2 ("ld a,(de)");
3512 emit2 ("xor #0x80");
3514 emit2 ("ld a,(hl)");
3515 emit2 ("xor #0x80");
3519 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
3523 emit2 ("ld a,(de)");
3524 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
3534 spillPair (PAIR_HL);
3536 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
3538 setupPair (PAIR_HL, AOP (left), 0);
3539 aopGet (AOP(right), LSB, FALSE);
3543 if (size == 0 && sign)
3545 // Highest byte when signed needs the bits flipped
3548 emit2 ("ld a,(hl)");
3549 emit2 ("xor #0x80");
3551 emit2 ("ld a,%d(iy)", offset);
3552 emit2 ("xor #0x80");
3556 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
3560 emit2 ("ld a,(hl)");
3561 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
3570 spillPair (PAIR_HL);
3571 spillPair (PAIR_IY);
3575 if (AOP_TYPE (right) == AOP_LIT)
3577 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3578 /* optimize if(x < 0) or if(x >= 0) */
3583 /* No sign so it's always false */
3588 /* Just load in the top most bit */
3589 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
3590 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
3592 genIfxJump (ifx, "7");
3604 /* First setup h and l contaning the top most bytes XORed */
3605 bool fDidXor = FALSE;
3606 if (AOP_TYPE (left) == AOP_LIT)
3608 unsigned long lit = (unsigned long)
3609 floatFromVal (AOP (left)->aopu.aop_lit);
3610 emit2 ("ld %s,!immedbyte", _fTmp[0],
3611 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3615 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
3616 emit2 ("xor a,!immedbyte", 0x80);
3617 emit2 ("ld %s,a", _fTmp[0]);
3620 if (AOP_TYPE (right) == AOP_LIT)
3622 unsigned long lit = (unsigned long)
3623 floatFromVal (AOP (right)->aopu.aop_lit);
3624 emit2 ("ld %s,!immedbyte", _fTmp[1],
3625 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3629 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
3630 emit2 ("xor a,!immedbyte", 0x80);
3631 emit2 ("ld %s,a", _fTmp[1]);
3637 /* Do a long subtract */
3640 _moveA (aopGet (AOP (left), offset, FALSE));
3642 if (sign && size == 0)
3644 emit2 ("ld a,%s", _fTmp[0]);
3645 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
3649 /* Subtract through, propagating the carry */
3650 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
3658 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
3660 outBitCLong (result, swap_sense);
3664 /* if the result is used in the next
3665 ifx conditional branch then generate
3666 code a little differently */
3668 genIfxJump (ifx, swap_sense ? "nc" : "c");
3670 outBitCLong (result, swap_sense);
3671 /* leave the result in acc */
3675 /*-----------------------------------------------------------------*/
3676 /* genCmpGt :- greater than comparison */
3677 /*-----------------------------------------------------------------*/
3679 genCmpGt (iCode * ic, iCode * ifx)
3681 operand *left, *right, *result;
3682 sym_link *letype, *retype;
3685 left = IC_LEFT (ic);
3686 right = IC_RIGHT (ic);
3687 result = IC_RESULT (ic);
3689 letype = getSpec (operandType (left));
3690 retype = getSpec (operandType (right));
3691 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
3692 /* assign the amsops */
3693 aopOp (left, ic, FALSE, FALSE);
3694 aopOp (right, ic, FALSE, FALSE);
3695 aopOp (result, ic, TRUE, FALSE);
3697 genCmp (right, left, result, ifx, sign);
3699 freeAsmop (left, NULL, ic);
3700 freeAsmop (right, NULL, ic);
3701 freeAsmop (result, NULL, ic);
3704 /*-----------------------------------------------------------------*/
3705 /* genCmpLt - less than comparisons */
3706 /*-----------------------------------------------------------------*/
3708 genCmpLt (iCode * ic, iCode * ifx)
3710 operand *left, *right, *result;
3711 sym_link *letype, *retype;
3714 left = IC_LEFT (ic);
3715 right = IC_RIGHT (ic);
3716 result = IC_RESULT (ic);
3718 letype = getSpec (operandType (left));
3719 retype = getSpec (operandType (right));
3720 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
3722 /* assign the amsops */
3723 aopOp (left, ic, FALSE, FALSE);
3724 aopOp (right, ic, FALSE, FALSE);
3725 aopOp (result, ic, TRUE, FALSE);
3727 genCmp (left, right, result, ifx, sign);
3729 freeAsmop (left, NULL, ic);
3730 freeAsmop (right, NULL, ic);
3731 freeAsmop (result, NULL, ic);
3734 /*-----------------------------------------------------------------*/
3735 /* gencjneshort - compare and jump if not equal */
3736 /*-----------------------------------------------------------------*/
3738 gencjneshort (operand * left, operand * right, symbol * lbl)
3740 int size = max (AOP_SIZE (left), AOP_SIZE (right));
3742 unsigned long lit = 0L;
3744 /* Swap the left and right if it makes the computation easier */
3745 if (AOP_TYPE (left) == AOP_LIT)
3752 if (AOP_TYPE (right) == AOP_LIT)
3753 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3755 /* if the right side is a literal then anything goes */
3756 if (AOP_TYPE (right) == AOP_LIT &&
3757 AOP_TYPE (left) != AOP_DIR)
3761 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3766 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
3773 emit2 ("jp nz,!tlabel", lbl->key + 100);
3779 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3780 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
3783 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
3784 emit2 ("jp nz,!tlabel", lbl->key + 100);
3789 /* if the right side is in a register or in direct space or
3790 if the left is a pointer register & right is not */
3791 else if (AOP_TYPE (right) == AOP_REG ||
3792 AOP_TYPE (right) == AOP_DIR ||
3793 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
3797 _moveA (aopGet (AOP (left), offset, FALSE));
3798 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
3799 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
3801 emit2 ("jp nz,!tlabel", lbl->key + 100);
3804 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3805 emit2 ("jp nz,!tlabel", lbl->key + 100);
3812 /* right is a pointer reg need both a & b */
3813 /* PENDING: is this required? */
3816 _moveA (aopGet (AOP (right), offset, FALSE));
3817 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
3818 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
3824 /*-----------------------------------------------------------------*/
3825 /* gencjne - compare and jump if not equal */
3826 /*-----------------------------------------------------------------*/
3828 gencjne (operand * left, operand * right, symbol * lbl)
3830 symbol *tlbl = newiTempLabel (NULL);
3832 gencjneshort (left, right, lbl);
3835 emit2 ("ld a,!one");
3836 emit2 ("!shortjp !tlabel", tlbl->key + 100);
3837 emitLabel (lbl->key + 100);
3839 emitLabel (tlbl->key + 100);
3842 /*-----------------------------------------------------------------*/
3843 /* genCmpEq - generates code for equal to */
3844 /*-----------------------------------------------------------------*/
3846 genCmpEq (iCode * ic, iCode * ifx)
3848 operand *left, *right, *result;
3850 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
3851 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
3852 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
3854 emitDebug ("; genCmpEq: left %u, right %u, result %u\n", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
3856 /* Swap operands if it makes the operation easier. ie if:
3857 1. Left is a literal.
3859 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
3861 operand *t = IC_RIGHT (ic);
3862 IC_RIGHT (ic) = IC_LEFT (ic);
3866 if (ifx && !AOP_SIZE (result))
3869 /* if they are both bit variables */
3870 if (AOP_TYPE (left) == AOP_CRY &&
3871 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
3873 wassertl (0, "Tried to compare two bits");
3877 tlbl = newiTempLabel (NULL);
3878 gencjneshort (left, right, tlbl);
3881 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
3882 emitLabel (tlbl->key + 100);
3886 /* PENDING: do this better */
3887 symbol *lbl = newiTempLabel (NULL);
3888 emit2 ("!shortjp !tlabel", lbl->key + 100);
3889 emitLabel (tlbl->key + 100);
3890 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
3891 emitLabel (lbl->key + 100);
3894 /* mark the icode as generated */
3899 /* if they are both bit variables */
3900 if (AOP_TYPE (left) == AOP_CRY &&
3901 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
3903 wassertl (0, "Tried to compare a bit to either a literal or another bit");
3907 gencjne (left, right, newiTempLabel (NULL));
3908 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
3914 genIfxJump (ifx, "a");
3917 /* if the result is used in an arithmetic operation
3918 then put the result in place */
3919 if (AOP_TYPE (result) != AOP_CRY)
3923 /* leave the result in acc */
3927 freeAsmop (left, NULL, ic);
3928 freeAsmop (right, NULL, ic);
3929 freeAsmop (result, NULL, ic);
3932 /*-----------------------------------------------------------------*/
3933 /* ifxForOp - returns the icode containing the ifx for operand */
3934 /*-----------------------------------------------------------------*/
3936 ifxForOp (operand * op, iCode * ic)
3938 /* if true symbol then needs to be assigned */
3939 if (IS_TRUE_SYMOP (op))
3942 /* if this has register type condition and
3943 the next instruction is ifx with the same operand
3944 and live to of the operand is upto the ifx only then */
3946 ic->next->op == IFX &&
3947 IC_COND (ic->next)->key == op->key &&
3948 OP_SYMBOL (op)->liveTo <= ic->next->seq)
3954 /*-----------------------------------------------------------------*/
3955 /* genAndOp - for && operation */
3956 /*-----------------------------------------------------------------*/
3958 genAndOp (iCode * ic)
3960 operand *left, *right, *result;
3963 /* note here that && operations that are in an if statement are
3964 taken away by backPatchLabels only those used in arthmetic
3965 operations remain */
3966 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
3967 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
3968 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
3970 /* if both are bit variables */
3971 if (AOP_TYPE (left) == AOP_CRY &&
3972 AOP_TYPE (right) == AOP_CRY)
3974 wassertl (0, "Tried to and two bits");
3978 tlbl = newiTempLabel (NULL);
3980 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3982 emitLabel (tlbl->key + 100);
3986 freeAsmop (left, NULL, ic);
3987 freeAsmop (right, NULL, ic);
3988 freeAsmop (result, NULL, ic);
3991 /*-----------------------------------------------------------------*/
3992 /* genOrOp - for || operation */
3993 /*-----------------------------------------------------------------*/
3995 genOrOp (iCode * ic)
3997 operand *left, *right, *result;
4000 /* note here that || operations that are in an
4001 if statement are taken away by backPatchLabels
4002 only those used in arthmetic operations remain */
4003 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4004 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4005 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4007 /* if both are bit variables */
4008 if (AOP_TYPE (left) == AOP_CRY &&
4009 AOP_TYPE (right) == AOP_CRY)
4011 wassertl (0, "Tried to OR two bits");
4015 tlbl = newiTempLabel (NULL);
4017 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4019 emitLabel (tlbl->key + 100);
4023 freeAsmop (left, NULL, ic);
4024 freeAsmop (right, NULL, ic);
4025 freeAsmop (result, NULL, ic);
4028 /*-----------------------------------------------------------------*/
4029 /* isLiteralBit - test if lit == 2^n */
4030 /*-----------------------------------------------------------------*/
4032 isLiteralBit (unsigned long lit)
4034 unsigned long pw[32] =
4035 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
4036 0x100L, 0x200L, 0x400L, 0x800L,
4037 0x1000L, 0x2000L, 0x4000L, 0x8000L,
4038 0x10000L, 0x20000L, 0x40000L, 0x80000L,
4039 0x100000L, 0x200000L, 0x400000L, 0x800000L,
4040 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
4041 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
4044 for (idx = 0; idx < 32; idx++)
4050 /*-----------------------------------------------------------------*/
4051 /* jmpTrueOrFalse - */
4052 /*-----------------------------------------------------------------*/
4054 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
4056 // ugly but optimized by peephole
4059 symbol *nlbl = newiTempLabel (NULL);
4060 emit2 ("jp !tlabel", nlbl->key + 100);
4061 emitLabel (tlbl->key + 100);
4062 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
4063 emitLabel (nlbl->key + 100);
4067 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
4068 emitLabel (tlbl->key + 100);
4073 /*-----------------------------------------------------------------*/
4074 /* genAnd - code for and */
4075 /*-----------------------------------------------------------------*/
4077 genAnd (iCode * ic, iCode * ifx)
4079 operand *left, *right, *result;
4080 int size, offset = 0;
4081 unsigned long lit = 0L;
4084 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4085 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4086 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4088 /* if left is a literal & right is not then exchange them */
4089 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4090 AOP_NEEDSACC (left))
4092 operand *tmp = right;
4097 /* if result = right then exchange them */
4098 if (sameRegs (AOP (result), AOP (right)))
4100 operand *tmp = right;
4105 /* if right is bit then exchange them */
4106 if (AOP_TYPE (right) == AOP_CRY &&
4107 AOP_TYPE (left) != AOP_CRY)
4109 operand *tmp = right;
4113 if (AOP_TYPE (right) == AOP_LIT)
4114 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4116 size = AOP_SIZE (result);
4118 if (AOP_TYPE (left) == AOP_CRY)
4120 wassertl (0, "Tried to perform an AND with a bit as an operand");
4124 // if(val & 0xZZ) - size = 0, ifx != FALSE -
4125 // bit = val & 0xZZ - size = 1, ifx = FALSE -
4126 if ((AOP_TYPE (right) == AOP_LIT) &&
4127 (AOP_TYPE (result) == AOP_CRY) &&
4128 (AOP_TYPE (left) != AOP_CRY))
4130 symbol *tlbl = newiTempLabel (NULL);
4131 int sizel = AOP_SIZE (left);
4134 /* PENDING: Test case for this. */
4139 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
4141 _moveA (aopGet (AOP (left), offset, FALSE));
4142 if (bytelit != 0x0FFL)
4144 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4151 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4155 // bit = left & literal
4159 emit2 ("!tlabeldef", tlbl->key + 100);
4161 // if(left & literal)
4166 jmpTrueOrFalse (ifx, tlbl);
4174 /* if left is same as result */
4175 if (sameRegs (AOP (result), AOP (left)))
4177 for (; size--; offset++)
4179 if (AOP_TYPE (right) == AOP_LIT)
4181 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4186 aopPut (AOP (result), "!zero", offset);
4189 _moveA (aopGet (AOP (left), offset, FALSE));
4191 aopGet (AOP (right), offset, FALSE));
4192 aopPut (AOP (left), "a", offset);
4199 if (AOP_TYPE (left) == AOP_ACC)
4201 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
4205 _moveA (aopGet (AOP (left), offset, FALSE));
4207 aopGet (AOP (right), offset, FALSE));
4208 aopPut (AOP (left), "a", offset);
4215 // left & result in different registers
4216 if (AOP_TYPE (result) == AOP_CRY)
4218 wassertl (0, "Tried to AND where the result is in carry");
4222 for (; (size--); offset++)
4225 // result = left & right
4226 if (AOP_TYPE (right) == AOP_LIT)
4228 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4230 aopPut (AOP (result),
4231 aopGet (AOP (left), offset, FALSE),
4235 else if (bytelit == 0)
4237 aopPut (AOP (result), "!zero", offset);
4241 // faster than result <- left, anl result,right
4242 // and better if result is SFR
4243 if (AOP_TYPE (left) == AOP_ACC)
4244 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4247 _moveA (aopGet (AOP (left), offset, FALSE));
4249 aopGet (AOP (right), offset, FALSE));
4251 aopPut (AOP (result), "a", offset);
4258 freeAsmop (left, NULL, ic);
4259 freeAsmop (right, NULL, ic);
4260 freeAsmop (result, NULL, ic);
4263 /*-----------------------------------------------------------------*/
4264 /* genOr - code for or */
4265 /*-----------------------------------------------------------------*/
4267 genOr (iCode * ic, iCode * ifx)
4269 operand *left, *right, *result;
4270 int size, offset = 0;
4271 unsigned long lit = 0L;
4274 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4275 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4276 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4278 /* if left is a literal & right is not then exchange them */
4279 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4280 AOP_NEEDSACC (left))
4282 operand *tmp = right;
4287 /* if result = right then exchange them */
4288 if (sameRegs (AOP (result), AOP (right)))
4290 operand *tmp = right;
4295 /* if right is bit then exchange them */
4296 if (AOP_TYPE (right) == AOP_CRY &&
4297 AOP_TYPE (left) != AOP_CRY)
4299 operand *tmp = right;
4303 if (AOP_TYPE (right) == AOP_LIT)
4304 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4306 size = AOP_SIZE (result);
4308 if (AOP_TYPE (left) == AOP_CRY)
4310 wassertl (0, "Tried to OR where left is a bit");
4314 // if(val | 0xZZ) - size = 0, ifx != FALSE -
4315 // bit = val | 0xZZ - size = 1, ifx = FALSE -
4316 if ((AOP_TYPE (right) == AOP_LIT) &&
4317 (AOP_TYPE (result) == AOP_CRY) &&
4318 (AOP_TYPE (left) != AOP_CRY))
4320 symbol *tlbl = newiTempLabel (NULL);
4321 int sizel = AOP_SIZE (left);
4325 wassertl (0, "Result is assigned to a bit");
4327 /* PENDING: Modeled after the AND code which is inefficent. */
4330 bytelit = (lit >> (offset * 8)) & 0x0FFL;
4332 _moveA (aopGet (AOP (left), offset, FALSE));
4333 /* OR with any literal is the same as OR with itself. */
4335 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4341 jmpTrueOrFalse (ifx, tlbl);
4346 /* if left is same as result */
4347 if (sameRegs (AOP (result), AOP (left)))
4349 for (; size--; offset++)
4351 if (AOP_TYPE (right) == AOP_LIT)
4353 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4357 _moveA (aopGet (AOP (left), offset, FALSE));
4359 aopGet (AOP (right), offset, FALSE));
4360 aopPut (AOP (result), "a", offset);
4365 if (AOP_TYPE (left) == AOP_ACC)
4366 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4369 _moveA (aopGet (AOP (left), offset, FALSE));
4371 aopGet (AOP (right), offset, FALSE));
4372 aopPut (AOP (result), "a", offset);
4379 // left & result in different registers
4380 if (AOP_TYPE (result) == AOP_CRY)
4382 wassertl (0, "Result of OR is in a bit");
4385 for (; (size--); offset++)
4388 // result = left & right
4389 if (AOP_TYPE (right) == AOP_LIT)
4391 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4393 aopPut (AOP (result),
4394 aopGet (AOP (left), offset, FALSE),
4399 // faster than result <- left, anl result,right
4400 // and better if result is SFR
4401 if (AOP_TYPE (left) == AOP_ACC)
4402 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4405 _moveA (aopGet (AOP (left), offset, FALSE));
4407 aopGet (AOP (right), offset, FALSE));
4409 aopPut (AOP (result), "a", offset);
4410 /* PENDING: something weird is going on here. Add exception. */
4411 if (AOP_TYPE (result) == AOP_ACC)
4417 freeAsmop (left, NULL, ic);
4418 freeAsmop (right, NULL, ic);
4419 freeAsmop (result, NULL, ic);
4422 /*-----------------------------------------------------------------*/
4423 /* genXor - code for xclusive or */
4424 /*-----------------------------------------------------------------*/
4426 genXor (iCode * ic, iCode * ifx)
4428 operand *left, *right, *result;
4429 int size, offset = 0;
4430 unsigned long lit = 0L;
4432 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4433 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4434 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4436 /* if left is a literal & right is not then exchange them */
4437 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4438 AOP_NEEDSACC (left))
4440 operand *tmp = right;
4445 /* if result = right then exchange them */
4446 if (sameRegs (AOP (result), AOP (right)))
4448 operand *tmp = right;
4453 /* if right is bit then exchange them */
4454 if (AOP_TYPE (right) == AOP_CRY &&
4455 AOP_TYPE (left) != AOP_CRY)
4457 operand *tmp = right;
4461 if (AOP_TYPE (right) == AOP_LIT)
4462 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4464 size = AOP_SIZE (result);
4466 if (AOP_TYPE (left) == AOP_CRY)
4468 wassertl (0, "Tried to XOR a bit");
4472 // if(val & 0xZZ) - size = 0, ifx != FALSE -
4473 // bit = val & 0xZZ - size = 1, ifx = FALSE -
4474 if ((AOP_TYPE (right) == AOP_LIT) &&
4475 (AOP_TYPE (result) == AOP_CRY) &&
4476 (AOP_TYPE (left) != AOP_CRY))
4478 symbol *tlbl = newiTempLabel (NULL);
4479 int sizel = AOP_SIZE (left);
4483 /* PENDING: Test case for this. */
4484 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
4488 _moveA (aopGet (AOP (left), offset, FALSE));
4489 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4490 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4495 jmpTrueOrFalse (ifx, tlbl);
4499 wassertl (0, "Result of XOR was destined for a bit");
4504 /* if left is same as result */
4505 if (sameRegs (AOP (result), AOP (left)))
4507 for (; size--; offset++)
4509 if (AOP_TYPE (right) == AOP_LIT)
4511 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4515 _moveA (aopGet (AOP (right), offset, FALSE));
4517 aopGet (AOP (left), offset, FALSE));
4518 aopPut (AOP (result), "a", offset);
4523 if (AOP_TYPE (left) == AOP_ACC)
4525 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4529 _moveA (aopGet (AOP (right), offset, FALSE));
4531 aopGet (AOP (left), offset, FALSE));
4532 aopPut (AOP (result), "a", 0);
4539 // left & result in different registers
4540 if (AOP_TYPE (result) == AOP_CRY)
4542 wassertl (0, "Result of XOR is in a bit");
4545 for (; (size--); offset++)
4548 // result = left & right
4549 if (AOP_TYPE (right) == AOP_LIT)
4551 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4553 aopPut (AOP (result),
4554 aopGet (AOP (left), offset, FALSE),
4559 // faster than result <- left, anl result,right
4560 // and better if result is SFR
4561 if (AOP_TYPE (left) == AOP_ACC)
4563 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4567 _moveA (aopGet (AOP (right), offset, FALSE));
4569 aopGet (AOP (left), offset, FALSE));
4571 aopPut (AOP (result), "a", offset);
4576 freeAsmop (left, NULL, ic);
4577 freeAsmop (right, NULL, ic);
4578 freeAsmop (result, NULL, ic);
4581 /*-----------------------------------------------------------------*/
4582 /* genInline - write the inline code out */
4583 /*-----------------------------------------------------------------*/
4585 genInline (iCode * ic)
4587 char *buffer, *bp, *bp1;
4589 _G.lines.isInline += (!options.asmpeep);
4591 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
4592 strcpy (buffer, IC_INLINE (ic));
4594 /* emit each line as a code */
4619 _G.lines.isInline -= (!options.asmpeep);
4623 /*-----------------------------------------------------------------*/
4624 /* genRRC - rotate right with carry */
4625 /*-----------------------------------------------------------------*/
4632 /*-----------------------------------------------------------------*/
4633 /* genRLC - generate code for rotate left with carry */
4634 /*-----------------------------------------------------------------*/
4641 /*-----------------------------------------------------------------*/
4642 /* genGetHbit - generates code get highest order bit */
4643 /*-----------------------------------------------------------------*/
4645 genGetHbit (iCode * ic)
4647 operand *left, *result;
4648 left = IC_LEFT (ic);
4649 result = IC_RESULT (ic);
4650 aopOp (left, ic, FALSE, FALSE);
4651 aopOp (result, ic, FALSE, FALSE);
4653 /* get the highest order byte into a */
4654 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4656 if (AOP_TYPE (result) == AOP_CRY)
4664 /* PENDING: For re-target. */
4670 freeAsmop (left, NULL, ic);
4671 freeAsmop (result, NULL, ic);
4675 emitRsh2 (asmop *aop, int size, int is_signed)
4681 const char *l = aopGet (aop, size, FALSE);
4684 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
4694 /*-----------------------------------------------------------------*/
4695 /* shiftR2Left2Result - shift right two bytes from left to result */
4696 /*-----------------------------------------------------------------*/
4698 shiftR2Left2Result (operand * left, int offl,
4699 operand * result, int offr,
4700 int shCount, int is_signed)
4703 symbol *tlbl, *tlbl1;
4705 movLeft2Result (left, offl, result, offr, 0);
4706 movLeft2Result (left, offl + 1, result, offr + 1, 0);
4708 /* if (AOP(result)->type == AOP_REG) { */
4710 tlbl = newiTempLabel (NULL);
4711 tlbl1 = newiTempLabel (NULL);
4713 /* Left is already in result - so now do the shift */
4718 emitRsh2 (AOP (result), size, is_signed);
4723 emit2 ("ld a,!immedbyte+1", shCount);
4724 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4725 emitLabel (tlbl->key + 100);
4727 emitRsh2 (AOP (result), size, is_signed);
4729 emitLabel (tlbl1->key + 100);
4731 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4735 /*-----------------------------------------------------------------*/
4736 /* shiftL2Left2Result - shift left two bytes from left to result */
4737 /*-----------------------------------------------------------------*/
4739 shiftL2Left2Result (operand * left, int offl,
4740 operand * result, int offr, int shCount)
4742 if (sameRegs (AOP (result), AOP (left)) &&
4743 ((offl + MSB16) == offr))
4749 /* Copy left into result */
4750 movLeft2Result (left, offl, result, offr, 0);
4751 movLeft2Result (left, offl + 1, result, offr + 1, 0);
4753 /* PENDING: for now just see if it'll work. */
4754 /*if (AOP(result)->type == AOP_REG) { */
4758 symbol *tlbl, *tlbl1;
4761 tlbl = newiTempLabel (NULL);
4762 tlbl1 = newiTempLabel (NULL);
4764 /* Left is already in result - so now do the shift */
4767 emit2 ("ld a,!immedbyte+1", shCount);
4768 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4769 emitLabel (tlbl->key + 100);
4774 l = aopGet (AOP (result), offset, FALSE);
4778 emit2 ("sla %s", l);
4789 emitLabel (tlbl1->key + 100);
4791 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4796 /*-----------------------------------------------------------------*/
4797 /* AccRol - rotate left accumulator by known count */
4798 /*-----------------------------------------------------------------*/
4800 AccRol (int shCount)
4802 shCount &= 0x0007; // shCount : 0..7
4841 /*-----------------------------------------------------------------*/
4842 /* AccLsh - left shift accumulator by known count */
4843 /*-----------------------------------------------------------------*/
4845 AccLsh (int shCount)
4847 static const unsigned char SLMask[] =
4849 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
4858 else if (shCount == 2)
4865 /* rotate left accumulator */
4867 /* and kill the lower order bits */
4868 emit2 ("and a,!immedbyte", SLMask[shCount]);
4873 /*-----------------------------------------------------------------*/
4874 /* shiftL1Left2Result - shift left one byte from left to result */
4875 /*-----------------------------------------------------------------*/
4877 shiftL1Left2Result (operand * left, int offl,
4878 operand * result, int offr, int shCount)
4881 l = aopGet (AOP (left), offl, FALSE);
4883 /* shift left accumulator */
4885 aopPut (AOP (result), "a", offr);
4889 /*-----------------------------------------------------------------*/
4890 /* genlshTwo - left shift two bytes by known amount != 0 */
4891 /*-----------------------------------------------------------------*/
4893 genlshTwo (operand * result, operand * left, int shCount)
4895 int size = AOP_SIZE (result);
4897 wassert (size == 2);
4899 /* if shCount >= 8 */
4907 movLeft2Result (left, LSB, result, MSB16, 0);
4908 aopPut (AOP (result), "!zero", 0);
4909 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
4913 movLeft2Result (left, LSB, result, MSB16, 0);
4914 aopPut (AOP (result), "!zero", 0);
4919 aopPut (AOP (result), "!zero", LSB);
4922 /* 1 <= shCount <= 7 */
4931 shiftL2Left2Result (left, LSB, result, LSB, shCount);
4936 /*-----------------------------------------------------------------*/
4937 /* genlshOne - left shift a one byte quantity by known count */
4938 /*-----------------------------------------------------------------*/
4940 genlshOne (operand * result, operand * left, int shCount)
4942 shiftL1Left2Result (left, LSB, result, LSB, shCount);
4945 /*-----------------------------------------------------------------*/
4946 /* genLeftShiftLiteral - left shifting by known count */
4947 /*-----------------------------------------------------------------*/
4949 genLeftShiftLiteral (operand * left,
4954 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
4957 freeAsmop (right, NULL, ic);
4959 aopOp (left, ic, FALSE, FALSE);
4960 aopOp (result, ic, FALSE, FALSE);
4962 size = getSize (operandType (result));
4964 /* I suppose that the left size >= result size */
4970 else if (shCount >= (size * 8))
4974 aopPut (AOP (result), "!zero", size);
4982 genlshOne (result, left, shCount);
4985 genlshTwo (result, left, shCount);
4988 wassertl (0, "Shifting of longs is currently unsupported");
4994 freeAsmop (left, NULL, ic);
4995 freeAsmop (result, NULL, ic);
4998 /*-----------------------------------------------------------------*/
4999 /* genLeftShift - generates code for left shifting */
5000 /*-----------------------------------------------------------------*/
5002 genLeftShift (iCode * ic)
5006 symbol *tlbl, *tlbl1;
5007 operand *left, *right, *result;
5009 right = IC_RIGHT (ic);
5010 left = IC_LEFT (ic);
5011 result = IC_RESULT (ic);
5013 aopOp (right, ic, FALSE, FALSE);
5015 /* if the shift count is known then do it
5016 as efficiently as possible */
5017 if (AOP_TYPE (right) == AOP_LIT)
5019 genLeftShiftLiteral (left, right, result, ic);
5023 /* shift count is unknown then we have to form a loop get the loop
5024 count in B : Note: we take only the lower order byte since
5025 shifting more that 32 bits make no sense anyway, ( the largest
5026 size of an object can be only 32 bits ) */
5027 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5029 freeAsmop (right, NULL, ic);
5030 aopOp (left, ic, FALSE, FALSE);
5031 aopOp (result, ic, FALSE, FALSE);
5033 /* now move the left to the result if they are not the
5036 if (!sameRegs (AOP (left), AOP (result)))
5039 size = AOP_SIZE (result);
5043 l = aopGet (AOP (left), offset, FALSE);
5044 aopPut (AOP (result), l, offset);
5049 tlbl = newiTempLabel (NULL);
5050 size = AOP_SIZE (result);
5052 tlbl1 = newiTempLabel (NULL);
5054 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5055 emitLabel (tlbl->key + 100);
5056 l = aopGet (AOP (result), offset, FALSE);
5060 l = aopGet (AOP (result), offset, FALSE);
5064 emit2 ("sla %s", l);
5072 emitLabel (tlbl1->key + 100);
5074 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5076 freeAsmop (left, NULL, ic);
5077 freeAsmop (result, NULL, ic);
5080 /*-----------------------------------------------------------------*/
5081 /* genrshOne - left shift two bytes by known amount != 0 */
5082 /*-----------------------------------------------------------------*/
5084 genrshOne (operand * result, operand * left, int shCount, int is_signed)
5087 int size = AOP_SIZE (result);
5090 wassert (size == 1);
5091 wassert (shCount < 8);
5093 l = aopGet (AOP (left), 0, FALSE);
5095 if (AOP (result)->type == AOP_REG)
5097 aopPut (AOP (result), l, 0);
5098 l = aopGet (AOP (result), 0, FALSE);
5101 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5109 emit2 ("%s a", is_signed ? "sra" : "srl");
5111 aopPut (AOP (result), "a", 0);
5115 /*-----------------------------------------------------------------*/
5116 /* AccRsh - right shift accumulator by known count */
5117 /*-----------------------------------------------------------------*/
5119 AccRsh (int shCount)
5121 static const unsigned char SRMask[] =
5123 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
5128 /* rotate right accumulator */
5129 AccRol (8 - shCount);
5130 /* and kill the higher order bits */
5131 emit2 ("and a,!immedbyte", SRMask[shCount]);
5135 /*-----------------------------------------------------------------*/
5136 /* shiftR1Left2Result - shift right one byte from left to result */
5137 /*-----------------------------------------------------------------*/
5139 shiftR1Left2Result (operand * left, int offl,
5140 operand * result, int offr,
5141 int shCount, int sign)
5143 _moveA (aopGet (AOP (left), offl, FALSE));
5148 emit2 ("%s a", sign ? "sra" : "srl");
5155 aopPut (AOP (result), "a", offr);
5158 /*-----------------------------------------------------------------*/
5159 /* genrshTwo - right shift two bytes by known amount != 0 */
5160 /*-----------------------------------------------------------------*/
5162 genrshTwo (operand * result, operand * left,
5163 int shCount, int sign)
5165 /* if shCount >= 8 */
5171 shiftR1Left2Result (left, MSB16, result, LSB,
5176 movLeft2Result (left, MSB16, result, LSB, sign);
5180 /* Sign extend the result */
5181 _moveA(aopGet (AOP (result), 0, FALSE));
5185 aopPut (AOP (result), ACC_NAME, MSB16);
5189 aopPut (AOP (result), "!zero", 1);
5192 /* 1 <= shCount <= 7 */
5195 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
5199 /*-----------------------------------------------------------------*/
5200 /* genRightShiftLiteral - left shifting by known count */
5201 /*-----------------------------------------------------------------*/
5203 genRightShiftLiteral (operand * left,
5209 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5212 freeAsmop (right, NULL, ic);
5214 aopOp (left, ic, FALSE, FALSE);
5215 aopOp (result, ic, FALSE, FALSE);
5217 size = getSize (operandType (result));
5219 /* I suppose that the left size >= result size */
5225 else if (shCount >= (size * 8))
5227 aopPut (AOP (result), "!zero", size);
5233 genrshOne (result, left, shCount, sign);
5236 genrshTwo (result, left, shCount, sign);
5239 wassertl (0, "Asked to shift right a long which should be a function call");
5242 wassertl (0, "Entered default case in right shift delegate");
5245 freeAsmop (left, NULL, ic);
5246 freeAsmop (result, NULL, ic);
5249 /*-----------------------------------------------------------------*/
5250 /* genRightShift - generate code for right shifting */
5251 /*-----------------------------------------------------------------*/
5253 genRightShift (iCode * ic)
5255 operand *right, *left, *result;
5257 int size, offset, first = 1;
5261 symbol *tlbl, *tlbl1;
5263 /* if signed then we do it the hard way preserve the
5264 sign bit moving it inwards */
5265 retype = getSpec (operandType (IC_RESULT (ic)));
5267 is_signed = !SPEC_USIGN (retype);
5269 /* signed & unsigned types are treated the same : i.e. the
5270 signed is NOT propagated inwards : quoting from the
5271 ANSI - standard : "for E1 >> E2, is equivalent to division
5272 by 2**E2 if unsigned or if it has a non-negative value,
5273 otherwise the result is implementation defined ", MY definition
5274 is that the sign does not get propagated */
5276 right = IC_RIGHT (ic);
5277 left = IC_LEFT (ic);
5278 result = IC_RESULT (ic);
5280 aopOp (right, ic, FALSE, FALSE);
5282 /* if the shift count is known then do it
5283 as efficiently as possible */
5284 if (AOP_TYPE (right) == AOP_LIT)
5286 genRightShiftLiteral (left, right, result, ic, is_signed);
5290 aopOp (left, ic, FALSE, FALSE);
5291 aopOp (result, ic, FALSE, FALSE);
5293 /* now move the left to the result if they are not the
5295 if (!sameRegs (AOP (left), AOP (result)) &&
5296 AOP_SIZE (result) > 1)
5299 size = AOP_SIZE (result);
5303 l = aopGet (AOP (left), offset, FALSE);
5304 aopPut (AOP (result), l, offset);
5309 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5311 freeAsmop (right, NULL, ic);
5313 tlbl = newiTempLabel (NULL);
5314 tlbl1 = newiTempLabel (NULL);
5315 size = AOP_SIZE (result);
5318 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5319 emitLabel (tlbl->key + 100);
5322 l = aopGet (AOP (result), offset--, FALSE);
5325 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5333 emitLabel (tlbl1->key + 100);
5335 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5337 freeAsmop (left, NULL, ic);
5338 freeAsmop (result, NULL, ic);
5341 /*-----------------------------------------------------------------*/
5342 /* genGenPointerGet - get value from generic pointer space */
5343 /*-----------------------------------------------------------------*/
5345 genGenPointerGet (operand * left,
5346 operand * result, iCode * ic)
5349 sym_link *retype = getSpec (operandType (result));
5355 aopOp (left, ic, FALSE, FALSE);
5356 aopOp (result, ic, FALSE, FALSE);
5358 if (isPair (AOP (left)) && AOP_SIZE (result) == 1)
5361 if (isPtrPair (AOP (left)))
5363 tsprintf (buffer, "!*pair", getPairName (AOP (left)));
5364 aopPut (AOP (result), buffer, 0);
5368 emit2 ("ld a,!*pair", getPairName (AOP (left)));
5369 aopPut (AOP (result), "a", 0);
5371 freeAsmop (left, NULL, ic);
5375 /* For now we always load into IY */
5376 /* if this is remateriazable */
5377 fetchPair (pair, AOP (left));
5379 /* so iy now contains the address */
5380 freeAsmop (left, NULL, ic);
5382 /* if bit then unpack */
5383 if (IS_BITVAR (retype))
5389 size = AOP_SIZE (result);
5394 /* PENDING: make this better */
5395 if (!IS_GB && AOP (result)->type == AOP_REG)
5397 aopPut (AOP (result), "!*hl", offset++);
5401 emit2 ("ld a,!*pair", _pairs[pair].name);
5402 aopPut (AOP (result), "a", offset++);
5406 emit2 ("inc %s", _pairs[pair].name);
5407 _G.pairs[pair].offset++;
5413 freeAsmop (result, NULL, ic);
5416 /*-----------------------------------------------------------------*/
5417 /* genPointerGet - generate code for pointer get */
5418 /*-----------------------------------------------------------------*/
5420 genPointerGet (iCode * ic)
5422 operand *left, *result;
5423 sym_link *type, *etype;
5425 left = IC_LEFT (ic);
5426 result = IC_RESULT (ic);
5428 /* depending on the type of pointer we need to
5429 move it to the correct pointer register */
5430 type = operandType (left);
5431 etype = getSpec (type);
5433 genGenPointerGet (left, result, ic);
5437 isRegOrLit (asmop * aop)
5439 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
5444 /*-----------------------------------------------------------------*/
5445 /* genGenPointerSet - stores the value into a pointer location */
5446 /*-----------------------------------------------------------------*/
5448 genGenPointerSet (operand * right,
5449 operand * result, iCode * ic)
5452 sym_link *retype = getSpec (operandType (right));
5453 PAIR_ID pairId = PAIR_HL;
5455 aopOp (result, ic, FALSE, FALSE);
5456 aopOp (right, ic, FALSE, FALSE);
5461 /* Handle the exceptions first */
5462 if (isPair (AOP (result)) && (AOP_SIZE (right) == 1))
5465 const char *l = aopGet (AOP (right), 0, FALSE);
5466 const char *pair = getPairName (AOP (result));
5467 if (canAssignToPtr (l) && isPtr (pair))
5469 emit2 ("ld !*pair,%s", pair, l);
5474 emit2 ("ld !*pair,a", pair);
5479 /* if the operand is already in dptr
5480 then we do nothing else we move the value to dptr */
5481 if (AOP_TYPE (result) != AOP_STR)
5483 fetchPair (pairId, AOP (result));
5485 /* so hl know contains the address */
5486 freeAsmop (result, NULL, ic);
5488 /* if bit then unpack */
5489 if (IS_BITVAR (retype))
5495 size = AOP_SIZE (right);
5500 const char *l = aopGet (AOP (right), offset, FALSE);
5501 if (isRegOrLit (AOP (right)) && !IS_GB)
5503 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
5508 emit2 ("ld !*pair,a", _pairs[pairId].name);
5512 emit2 ("inc %s", _pairs[pairId].name);
5513 _G.pairs[pairId].offset++;
5519 freeAsmop (right, NULL, ic);
5522 /*-----------------------------------------------------------------*/
5523 /* genPointerSet - stores the value into a pointer location */
5524 /*-----------------------------------------------------------------*/
5526 genPointerSet (iCode * ic)
5528 operand *right, *result;
5529 sym_link *type, *etype;
5531 right = IC_RIGHT (ic);
5532 result = IC_RESULT (ic);
5534 /* depending on the type of pointer we need to
5535 move it to the correct pointer register */
5536 type = operandType (result);
5537 etype = getSpec (type);
5539 genGenPointerSet (right, result, ic);
5542 /*-----------------------------------------------------------------*/
5543 /* genIfx - generate code for Ifx statement */
5544 /*-----------------------------------------------------------------*/
5546 genIfx (iCode * ic, iCode * popIc)
5548 operand *cond = IC_COND (ic);
5551 aopOp (cond, ic, FALSE, TRUE);
5553 /* get the value into acc */
5554 if (AOP_TYPE (cond) != AOP_CRY)
5558 /* the result is now in the accumulator */
5559 freeAsmop (cond, NULL, ic);
5561 /* if there was something to be popped then do it */
5565 /* if the condition is a bit variable */
5566 if (isbit && IS_ITEMP (cond) &&
5568 genIfxJump (ic, SPIL_LOC (cond)->rname);
5569 else if (isbit && !IS_ITEMP (cond))
5570 genIfxJump (ic, OP_SYMBOL (cond)->rname);
5572 genIfxJump (ic, "a");
5577 /*-----------------------------------------------------------------*/
5578 /* genAddrOf - generates code for address of */
5579 /*-----------------------------------------------------------------*/
5581 genAddrOf (iCode * ic)
5583 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
5585 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
5587 /* if the operand is on the stack then we
5588 need to get the stack offset of this
5595 if (sym->stack <= 0)
5597 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
5601 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
5603 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
5607 emit2 ("ld de,!hashedstr", sym->rname);
5608 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
5616 /* if it has an offset then we need to compute it */
5618 emit2 ("ld hl,#%d+%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset, _G.stack.param_offset);
5620 emit2 ("ld hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
5621 emit2 ("add hl,sp");
5625 emit2 ("ld hl,#%s", sym->rname);
5627 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
5629 freeAsmop (IC_RESULT (ic), NULL, ic);
5632 /*-----------------------------------------------------------------*/
5633 /* genAssign - generate code for assignment */
5634 /*-----------------------------------------------------------------*/
5636 genAssign (iCode * ic)
5638 operand *result, *right;
5640 unsigned long lit = 0L;
5642 result = IC_RESULT (ic);
5643 right = IC_RIGHT (ic);
5645 /* Dont bother assigning if they are the same */
5646 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5648 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
5652 aopOp (right, ic, FALSE, FALSE);
5653 aopOp (result, ic, TRUE, FALSE);
5655 /* if they are the same registers */
5656 if (sameRegs (AOP (right), AOP (result)))
5658 emitDebug ("; (registers are the same)");
5662 /* if the result is a bit */
5663 if (AOP_TYPE (result) == AOP_CRY)
5665 wassertl (0, "Tried to assign to a bit");
5669 size = AOP_SIZE (result);
5672 if (AOP_TYPE (right) == AOP_LIT)
5673 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5674 if (isPair (AOP (result)))
5676 fetchPair (getPairId (AOP (result)), AOP (right));
5678 else if ((size > 1) &&
5679 (AOP_TYPE (result) != AOP_REG) &&
5680 (AOP_TYPE (right) == AOP_LIT) &&
5681 !IS_FLOAT (operandType (right)) &&
5684 bool fXored = FALSE;
5686 /* Work from the top down.
5687 Done this way so that we can use the cached copy of 0
5688 in A for a fast clear */
5691 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
5693 if (!fXored && size > 1)
5700 aopPut (AOP (result), "a", offset);
5704 aopPut (AOP (result), "!zero", offset);
5708 aopPut (AOP (result),
5709 aopGet (AOP (right), offset, FALSE),
5714 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
5716 /* Special case. Load into a and d, then load out. */
5717 _moveA (aopGet (AOP (right), 0, FALSE));
5718 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
5719 aopPut (AOP (result), "a", 0);
5720 aopPut (AOP (result), "e", 1);
5722 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
5724 /* Special case - simple memcpy */
5725 aopGet (AOP (right), LSB, FALSE);
5728 aopGet (AOP (result), LSB, FALSE);
5732 emit2 ("ld a,(de)");
5733 /* Peephole will optimise this. */
5734 emit2 ("ld (hl),a");
5742 spillPair (PAIR_HL);
5748 /* PENDING: do this check better */
5749 if (requiresHL (AOP (right)) && requiresHL (AOP (result)))
5751 _moveA (aopGet (AOP (right), offset, FALSE));
5752 aopPut (AOP (result), "a", offset);
5755 aopPut (AOP (result),
5756 aopGet (AOP (right), offset, FALSE),
5763 freeAsmop (right, NULL, ic);
5764 freeAsmop (result, NULL, ic);
5767 /*-----------------------------------------------------------------*/
5768 /* genJumpTab - genrates code for jump table */
5769 /*-----------------------------------------------------------------*/
5771 genJumpTab (iCode * ic)
5776 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
5777 /* get the condition into accumulator */
5778 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
5781 emit2 ("ld e,%s", l);
5782 emit2 ("ld d,!zero");
5783 jtab = newiTempLabel (NULL);
5785 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
5786 emit2 ("add hl,de");
5787 emit2 ("add hl,de");
5788 emit2 ("add hl,de");
5789 freeAsmop (IC_JTCOND (ic), NULL, ic);
5793 emitLabel (jtab->key + 100);
5794 /* now generate the jump labels */
5795 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
5796 jtab = setNextItem (IC_JTLABELS (ic)))
5797 emit2 ("jp !tlabel", jtab->key + 100);
5800 /*-----------------------------------------------------------------*/
5801 /* genCast - gen code for casting */
5802 /*-----------------------------------------------------------------*/
5804 genCast (iCode * ic)
5806 operand *result = IC_RESULT (ic);
5807 sym_link *ctype = operandType (IC_LEFT (ic));
5808 operand *right = IC_RIGHT (ic);
5811 /* if they are equivalent then do nothing */
5812 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5815 aopOp (right, ic, FALSE, FALSE);
5816 aopOp (result, ic, FALSE, FALSE);
5818 /* if the result is a bit */
5819 if (AOP_TYPE (result) == AOP_CRY)
5821 wassertl (0, "Tried to cast to a bit");
5824 /* if they are the same size : or less */
5825 if (AOP_SIZE (result) <= AOP_SIZE (right))
5828 /* if they are in the same place */
5829 if (sameRegs (AOP (right), AOP (result)))
5832 /* if they in different places then copy */
5833 size = AOP_SIZE (result);
5837 aopPut (AOP (result),
5838 aopGet (AOP (right), offset, FALSE),
5845 /* So we now know that the size of destination is greater
5846 than the size of the source */
5847 /* we move to result for the size of source */
5848 size = AOP_SIZE (right);
5852 aopPut (AOP (result),
5853 aopGet (AOP (right), offset, FALSE),
5858 /* now depending on the sign of the destination */
5859 size = AOP_SIZE (result) - AOP_SIZE (right);
5860 /* Unsigned or not an integral type - right fill with zeros */
5861 if (SPEC_USIGN (ctype) || !IS_SPEC (ctype))
5864 aopPut (AOP (result), "!zero", offset++);
5868 /* we need to extend the sign :{ */
5869 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
5875 aopPut (AOP (result), "a", offset++);
5879 freeAsmop (right, NULL, ic);
5880 freeAsmop (result, NULL, ic);
5883 /*-----------------------------------------------------------------*/
5884 /* genReceive - generate code for a receive iCode */
5885 /*-----------------------------------------------------------------*/
5887 genReceive (iCode * ic)
5889 if (isOperandInFarSpace (IC_RESULT (ic)) &&
5890 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
5891 IS_TRUE_SYMOP (IC_RESULT (ic))))
5901 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
5902 size = AOP_SIZE(IC_RESULT(ic));
5904 for (i = 0; i < size; i++) {
5905 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
5909 freeAsmop (IC_RESULT (ic), NULL, ic);
5914 /** Maximum number of bytes to emit per line. */
5918 /** Context for the byte output chunker. */
5921 unsigned char buffer[DBEMIT_MAX_RUN];
5926 /** Flushes a byte chunker by writing out all in the buffer and
5930 _dbFlush(DBEMITCTX *self)
5937 sprintf(line, ".db 0x%02X", self->buffer[0]);
5939 for (i = 1; i < self->pos; i++)
5941 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
5948 /** Write out another byte, buffering until a decent line is
5952 _dbEmit(DBEMITCTX *self, int c)
5954 if (self->pos == DBEMIT_MAX_RUN)
5958 self->buffer[self->pos++] = c;
5961 /** Context for a simple run length encoder. */
5965 unsigned char buffer[128];
5967 /** runLen may be equivalent to pos. */
5973 RLE_CHANGE_COST = 4,
5977 /** Flush the buffer of a run length encoder by writing out the run or
5978 data that it currently contains.
5981 _rleCommit(RLECTX *self)
5987 memset(&db, 0, sizeof(db));
5989 emit2(".db %u", self->pos);
5991 for (i = 0; i < self->pos; i++)
5993 _dbEmit(&db, self->buffer[i]);
6002 Can get either a run or a block of random stuff.
6003 Only want to change state if a good run comes in or a run ends.
6004 Detecting run end is easy.
6007 Say initial state is in run, len zero, last zero. Then if you get a
6008 few zeros then something else then a short run will be output.
6009 Seems OK. While in run mode, keep counting. While in random mode,
6010 keep a count of the run. If run hits margin, output all up to run,
6011 restart, enter run mode.
6014 /** Add another byte into the run length encoder, flushing as
6015 required. The run length encoder uses the Amiga IFF style, where
6016 a block is prefixed by its run length. A positive length means
6017 the next n bytes pass straight through. A negative length means
6018 that the next byte is repeated -n times. A zero terminates the
6022 _rleAppend(RLECTX *self, int c)
6026 if (c != self->last)
6028 /* The run has stopped. See if it is worthwhile writing it out
6029 as a run. Note that the random data comes in as runs of
6032 if (self->runLen > RLE_CHANGE_COST)
6034 /* Yes, worthwhile. */
6035 /* Commit whatever was in the buffer. */
6037 emit2(".db -%u,0x%02X", self->runLen, self->last);
6041 /* Not worthwhile. Append to the end of the random list. */
6042 for (i = 0; i < self->runLen; i++)
6044 if (self->pos >= RLE_MAX_BLOCK)
6049 self->buffer[self->pos++] = self->last;
6057 if (self->runLen >= RLE_MAX_BLOCK)
6059 /* Commit whatever was in the buffer. */
6062 emit2 (".db -%u,0x%02X", self->runLen, self->last);
6070 _rleFlush(RLECTX *self)
6072 _rleAppend(self, -1);
6079 /** genArrayInit - Special code for initialising an array with constant
6083 genArrayInit (iCode * ic)
6087 int elementSize = 0, eIndex, i;
6088 unsigned val, lastVal;
6092 memset(&rle, 0, sizeof(rle));
6094 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
6096 if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD)
6098 /* Emit the support function call and the destination address. */
6099 emit2("call __initrleblock");
6100 emit2(".dw %s", aopGetWord (AOP(IC_LEFT(ic)), 0));
6104 wassertl (0, "Unexpected operand to genArrayInit.\n");
6107 type = operandType(IC_LEFT(ic));
6109 if (type && type->next)
6111 elementSize = getSize(type->next);
6115 wassertl (0, "Can't determine element size in genArrayInit.");
6118 iLoop = IC_ARRAYILIST(ic);
6119 lastVal = (unsigned)-1;
6121 /* Feed all the bytes into the run length encoder which will handle
6123 This works well for mixed char data, and for random int and long
6132 for (i = 0; i < ix; i++)
6134 for (eIndex = 0; eIndex < elementSize; eIndex++)
6136 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
6137 _rleAppend(&rle, val);
6142 iLoop = iLoop->next;
6146 /* Mark the end of the run. */
6149 freeAsmop (IC_LEFT(ic), NULL, ic);
6152 /*-----------------------------------------------------------------*/
6153 /* genZ80Code - generate code for Z80 based controllers */
6154 /*-----------------------------------------------------------------*/
6156 genZ80Code (iCode * lic)
6164 _fReturn = _gbz80_return;
6165 _fTmp = _gbz80_return;
6169 _fReturn = _z80_return;
6170 _fTmp = _z80_return;
6173 _G.lines.head = _G.lines.current = NULL;
6175 for (ic = lic; ic; ic = ic->next)
6178 if (cln != ic->lineno)
6180 emit2 ("; %s %d", ic->filename, ic->lineno);
6183 /* if the result is marked as
6184 spilt and rematerializable or code for
6185 this has already been generated then
6187 if (resultRemat (ic) || ic->generated)
6190 /* depending on the operation */
6194 emitDebug ("; genNot");
6199 emitDebug ("; genCpl");
6204 emitDebug ("; genUminus");
6209 emitDebug ("; genIpush");
6214 /* IPOP happens only when trying to restore a
6215 spilt live range, if there is an ifx statement
6216 following this pop then the if statement might
6217 be using some of the registers being popped which
6218 would destory the contents of the register so
6219 we need to check for this condition and handle it */
6221 ic->next->op == IFX &&
6222 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
6224 emitDebug ("; genIfx");
6225 genIfx (ic->next, ic);
6229 emitDebug ("; genIpop");
6235 emitDebug ("; genCall");
6240 emitDebug ("; genPcall");
6245 emitDebug ("; genFunction");
6250 emitDebug ("; genEndFunction");
6251 genEndFunction (ic);
6255 emitDebug ("; genRet");
6260 emitDebug ("; genLabel");
6265 emitDebug ("; genGoto");
6270 emitDebug ("; genPlus");
6275 emitDebug ("; genMinus");
6280 emitDebug ("; genMult");
6285 emitDebug ("; genDiv");
6290 emitDebug ("; genMod");
6295 emitDebug ("; genCmpGt");
6296 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
6300 emitDebug ("; genCmpLt");
6301 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
6308 /* note these two are xlated by algebraic equivalence
6309 during parsing SDCC.y */
6310 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
6311 "got '>=' or '<=' shouldn't have come here");
6315 emitDebug ("; genCmpEq");
6316 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
6320 emitDebug ("; genAndOp");
6325 emitDebug ("; genOrOp");
6330 emitDebug ("; genXor");
6331 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
6335 emitDebug ("; genOr");
6336 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
6340 emitDebug ("; genAnd");
6341 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
6345 emitDebug ("; genInline");
6350 emitDebug ("; genRRC");
6355 emitDebug ("; genRLC");
6360 emitDebug ("; genGetHBIT");
6365 emitDebug ("; genLeftShift");
6370 emitDebug ("; genRightShift");
6374 case GET_VALUE_AT_ADDRESS:
6375 emitDebug ("; genPointerGet");
6381 if (POINTER_SET (ic))
6383 emitDebug ("; genAssign (pointer)");
6388 emitDebug ("; genAssign");
6394 emitDebug ("; genIfx");
6399 emitDebug ("; genAddrOf");
6404 emitDebug ("; genJumpTab");
6409 emitDebug ("; genCast");
6414 emitDebug ("; genReceive");
6419 emitDebug ("; addSet");
6420 addSet (&_G.sendSet, ic);
6433 /* now we are ready to call the
6434 peep hole optimizer */
6435 if (!options.nopeep)
6436 peepHole (&_G.lines.head);
6438 /* This is unfortunate */
6439 /* now do the actual printing */
6441 FILE *fp = codeOutFile;
6442 if (isInHome () && codeOutFile == code->oFile)
6443 codeOutFile = home->oFile;
6444 printLine (_G.lines.head, codeOutFile);
6445 if (_G.flushStatics)
6448 _G.flushStatics = 0;
6453 freeTrace(&_G.lines.trace);
6454 freeTrace(&_G.trace.aops);
6460 _isPairUsed (iCode * ic, PAIR_ID pairId)
6466 if (bitVectBitValue (ic->rMask, D_IDX))
6468 if (bitVectBitValue (ic->rMask, E_IDX))
6478 fetchLitSpecial (asmop * aop, bool negate, bool xor)
6481 value *val = aop->aopu.aop_lit;
6483 wassert (aop->type == AOP_LIT);
6484 wassert (!IS_FLOAT (val->type));
6486 v = (unsigned long) floatFromVal (val);
6494 tsprintf (buffer, "!immedword", v);
6495 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));