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 10 Mucho optimisations 13562 201 1FCC
66 Apparent advantage of turning on regparams:
68 Decent case is push of a constant
69 - ld hl,#n; push hl: (10+11)*nargs
70 2. Cost of pull from stack
71 Using asm with ld hl, etc
72 - ld hl,#2; add hl,sp; (ld bc,(hl); hl+=2)*nargs
74 3. Cost of fixing stack
78 So cost is (10+11+7+6+7+10)*nargs+10+11
80 = 123 for mul, div, strcmp, strcpy
81 Saving of (98298+32766+32766+32766)*123 = 24181308
82 At 192 d/s for 682411768t, speed up to 199. Hmm.
90 #ifdef HAVE_SYS_ISA_DEFS_H
91 #include <sys/isa_defs.h>
95 #include "SDCCglobl.h"
96 #include "SDCCpeeph.h"
101 /* This is the down and dirty file with all kinds of kludgy & hacky
102 stuff. This is what it is all about CODE GENERATION for a specific MCU.
103 Some of the routines may be reusable, will have to see */
105 /* Z80 calling convention description.
106 Parameters are passed right to left. As the stack grows downwards,
107 the parameters are arranged in left to right in memory.
108 Parameters may be passed in the HL and DE registers with one
110 PENDING: What if the parameter is a long?
111 Everything is caller saves. i.e. the caller must save any registers
112 that it wants to preserve over the call.
113 GB: The return value is returned in DEHL. DE is normally used as a
114 working register pair. Caller saves allows it to be used for a
116 va args functions do not use register parameters. All arguments
117 are passed on the stack.
118 IX is used as an index register to the top of the local variable
119 area. ix-0 is the top most local variable.
124 /* Set to enable debugging trace statements in the output assembly code. */
128 static char *_z80_return[] =
129 {"l", "h", "e", "d"};
130 static char *_gbz80_return[] =
131 {"e", "d", "l", "h"};
132 static char *_fReceive[] =
133 { "c", "b", "e", "d" };
135 static char **_fReturn;
138 extern FILE *codeOutFile;
146 /** Enum covering all the possible register pairs.
165 } _pairs[NUM_PAIRS] = {
166 { "??1", "?2", "?3" },
171 { "iy", "iyl", "iyh" },
172 { "ix", "ixl", "ixh" }
176 #define ACC_NAME _pairs[PAIR_AF].h
186 /** Code generator persistent data.
190 /** Used to optimised setting up of a pair by remebering what it
191 contains and adjusting instead of reloading where possible.
219 const char *lastFunctionName;
225 /** TRUE if the registers have already been saved. */
243 static const char *aopGet (asmop * aop, int offset, bool bit16);
245 static const char *aopNames[] = {
265 isLastUse (iCode *ic, operand *op)
267 bitVect *uses = bitVectCopy (OP_USES (op));
269 while (!bitVectIsZero (uses))
271 if (bitVectFirstBit (uses) == ic->key)
273 if (bitVectnBitsOn (uses) == 1)
282 bitVectUnSetBit (uses, bitVectFirstBit (uses));
302 _getTempPairName(void)
304 return _pairs[_getTempPairId()].name;
308 isPairInUse (PAIR_ID id, iCode *ic)
312 return bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
314 else if (id == PAIR_BC)
316 return bitVectBitValue (ic->rMask, B_IDX) || bitVectBitValue(ic->rMask, C_IDX);
320 wassertl (0, "Only implemented for DE and BC");
326 isPairInUseNotInRet(PAIR_ID id, iCode *ic)
330 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
334 return bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
338 wassertl (0, "Only implemented for DE");
344 getFreePairId (iCode *ic)
346 if (!isPairInUse (PAIR_BC, ic))
350 else if (IS_Z80 && !isPairInUse (PAIR_DE, ic))
363 /* Clean up the line so that it is 'prettier' */
364 if (strchr (buf, ':'))
366 /* Is a label - cant do anything */
369 /* Change the first (and probably only) ' ' to a tab so
384 _newLineNode (char *line)
388 pl = traceAlloc(&_G.lines.trace, Safe_alloc ( sizeof (lineNode)));
389 pl->line = traceAlloc(&_G.lines.trace, Safe_strdup (line));
395 _vemit2 (const char *szFormat, va_list ap)
399 tvsprintf (buffer, szFormat, ap);
402 _G.lines.current = (_G.lines.current ?
403 connectLine (_G.lines.current, _newLineNode (buffer)) :
404 (_G.lines.head = _newLineNode (buffer)));
406 _G.lines.current->isInline = _G.lines.isInline;
410 emit2 (const char *szFormat,...)
414 va_start (ap, szFormat);
416 _vemit2 (szFormat, ap);
422 emitDebug (const char *szFormat,...)
428 va_start (ap, szFormat);
430 _vemit2 (szFormat, ap);
436 /*-----------------------------------------------------------------*/
437 /* emit2 - writes the code into a file : for now it is simple */
438 /*-----------------------------------------------------------------*/
440 _emit2 (const char *inst, const char *fmt,...)
443 char lb[INITIAL_INLINEASM];
450 sprintf (lb, "%s\t", inst);
451 vsprintf (lb + (strlen (lb)), fmt, ap);
454 vsprintf (lb, fmt, ap);
456 while (isspace (*lbp))
461 _G.lines.current = (_G.lines.current ?
462 connectLine (_G.lines.current, _newLineNode (lb)) :
463 (_G.lines.head = _newLineNode (lb)));
465 _G.lines.current->isInline = _G.lines.isInline;
470 _emitMove(const char *to, const char *from)
472 if (strcasecmp(to, from) != 0)
474 emit2("ld %s,%s", to, from);
479 // Could leave this to the peephole, but sometimes the peephole is inhibited.
484 aopDump(const char *plabel, asmop *aop)
486 emitDebug("; Dump of %s: type %s size %u", plabel, aopNames[aop->type], aop->size);
490 emitDebug("; aop_stk %d", aop->aopu.aop_stk);
493 /* No information. */
498 _moveA(const char *moveFrom)
500 // Let the peephole optimiser take care of redundent loads
501 _emitMove(ACC_NAME, moveFrom);
511 getPairName (asmop * aop)
513 if (aop->type == AOP_REG)
515 switch (aop->aopu.aop_reg[0]->rIdx)
528 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
531 for (i = 0; i < NUM_PAIRS; i++)
533 if (strcmp(aop->aopu.aop_str[0], _pairs[i].l) == 0)
535 return _pairs[i].name;
539 wassertl (0, "Tried to get the pair name of something that isn't a pair");
544 getPairId (asmop * aop)
548 if (aop->type == AOP_REG)
550 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX) && (aop->aopu.aop_reg[1]->rIdx == B_IDX))
554 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX) && (aop->aopu.aop_reg[1]->rIdx == D_IDX))
558 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX) && (aop->aopu.aop_reg[1]->rIdx == H_IDX))
563 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
566 for (i = 0; i < NUM_PAIRS; i++)
568 if (!strcmp (aop->aopu.aop_str[0], _pairs[i].l) && !strcmp (aop->aopu.aop_str[1], _pairs[i].h))
578 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
582 return (getPairId (aop) != PAIR_INVALID);
586 isPtrPair (asmop * aop)
588 PAIR_ID pairId = getPairId (aop);
601 spillPair (PAIR_ID pairId)
603 _G.pairs[pairId].last_type = AOP_INVALID;
604 _G.pairs[pairId].base = NULL;
607 /** Push a register pair onto the stack */
609 genPairPush (asmop * aop)
611 emit2 ("push %s", getPairName (aop));
615 _push (PAIR_ID pairId)
617 emit2 ("push %s", _pairs[pairId].name);
618 _G.stack.pushed += 2;
622 _pop (PAIR_ID pairId)
624 emit2 ("pop %s", _pairs[pairId].name);
625 _G.stack.pushed -= 2;
629 /*-----------------------------------------------------------------*/
630 /* newAsmop - creates a new asmOp */
631 /*-----------------------------------------------------------------*/
633 newAsmop (short type)
637 aop = traceAlloc(&_G.trace.aops, Safe_alloc (sizeof (asmop)));
642 /*-----------------------------------------------------------------*/
643 /* aopForSym - for a true symbol */
644 /*-----------------------------------------------------------------*/
646 aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
653 wassert (sym->etype);
655 space = SPEC_OCLS (sym->etype);
657 /* if already has one */
663 /* Assign depending on the storage class */
664 if (sym->onStack || sym->iaccess)
666 /* The pointer that is used depends on how big the offset is.
667 Normally everything is AOP_STK, but for offsets of < -128 or
668 > 127 on the Z80 an extended stack pointer is used.
670 if (IS_Z80 && (options.ommitFramePtr || sym->stack < INT8MIN || sym->stack > (int)(INT8MAX-getSize (sym->type))))
672 emitDebug ("; AOP_EXSTK for %s", sym->rname);
673 sym->aop = aop = newAsmop (AOP_EXSTK);
677 emitDebug ("; AOP_STK for %s", sym->rname);
678 sym->aop = aop = newAsmop (AOP_STK);
681 aop->size = getSize (sym->type);
682 aop->aopu.aop_stk = sym->stack;
686 /* special case for a function */
687 if (IS_FUNC (sym->type))
689 sym->aop = aop = newAsmop (AOP_IMMD);
690 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup (sym->rname));
697 /* if it is in direct space */
698 if (IN_REGSP (space) && !requires_a)
700 sym->aop = aop = newAsmop (AOP_SFR);
701 aop->aopu.aop_dir = sym->rname;
702 aop->size = getSize (sym->type);
703 emitDebug ("; AOP_SFR for %s", sym->rname);
708 /* only remaining is far space */
709 /* in which case DPTR gets the address */
712 emitDebug ("; AOP_HL for %s", sym->rname);
713 sym->aop = aop = newAsmop (AOP_HL);
717 sym->aop = aop = newAsmop (AOP_IY);
719 aop->size = getSize (sym->type);
720 aop->aopu.aop_dir = sym->rname;
722 /* if it is in code space */
723 if (IN_CODESPACE (space))
729 /*-----------------------------------------------------------------*/
730 /* aopForRemat - rematerialzes an object */
731 /*-----------------------------------------------------------------*/
733 aopForRemat (symbol * sym)
736 iCode *ic = sym->rematiCode;
737 asmop *aop = newAsmop (AOP_IMMD);
741 /* if plus or minus print the right hand side */
742 if (ic->op == '+' || ic->op == '-')
744 /* PENDING: for re-target */
745 sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
748 ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
751 /* we reached the end */
752 sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
756 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
760 /*-----------------------------------------------------------------*/
761 /* regsInCommon - two operands have some registers in common */
762 /*-----------------------------------------------------------------*/
764 regsInCommon (operand * op1, operand * op2)
769 /* if they have registers in common */
770 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
773 sym1 = OP_SYMBOL (op1);
774 sym2 = OP_SYMBOL (op2);
776 if (sym1->nRegs == 0 || sym2->nRegs == 0)
779 for (i = 0; i < sym1->nRegs; i++)
785 for (j = 0; j < sym2->nRegs; j++)
790 if (sym2->regs[j] == sym1->regs[i])
798 /*-----------------------------------------------------------------*/
799 /* operandsEqu - equivalent */
800 /*-----------------------------------------------------------------*/
802 operandsEqu (operand * op1, operand * op2)
806 /* if they not symbols */
807 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
810 sym1 = OP_SYMBOL (op1);
811 sym2 = OP_SYMBOL (op2);
813 /* if both are itemps & one is spilt
814 and the other is not then false */
815 if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
816 sym1->isspilt != sym2->isspilt)
819 /* if they are the same */
823 if (strcmp (sym1->rname, sym2->rname) == 0)
827 /* if left is a tmp & right is not */
828 if (IS_ITEMP (op1) &&
831 (sym1->usl.spillLoc == sym2))
834 if (IS_ITEMP (op2) &&
838 (sym2->usl.spillLoc == sym1))
844 /*-----------------------------------------------------------------*/
845 /* sameRegs - two asmops have the same registers */
846 /*-----------------------------------------------------------------*/
848 sameRegs (asmop * aop1, asmop * aop2)
852 if (aop1->type == AOP_SFR ||
853 aop2->type == AOP_SFR)
859 if (aop1->type != AOP_REG ||
860 aop2->type != AOP_REG)
863 if (aop1->size != aop2->size)
866 for (i = 0; i < aop1->size; i++)
867 if (aop1->aopu.aop_reg[i] !=
868 aop2->aopu.aop_reg[i])
874 /*-----------------------------------------------------------------*/
875 /* aopOp - allocates an asmop for an operand : */
876 /*-----------------------------------------------------------------*/
878 aopOp (operand * op, iCode * ic, bool result, bool requires_a)
887 /* if this a literal */
888 if (IS_OP_LITERAL (op))
890 op->aop = aop = newAsmop (AOP_LIT);
891 aop->aopu.aop_lit = op->operand.valOperand;
892 aop->size = getSize (operandType (op));
896 /* if already has a asmop then continue */
902 /* if the underlying symbol has a aop */
903 if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
905 op->aop = OP_SYMBOL (op)->aop;
909 /* if this is a true symbol */
910 if (IS_TRUE_SYMOP (op))
912 op->aop = aopForSym (ic, OP_SYMBOL (op), result, requires_a);
916 /* this is a temporary : this has
922 e) can be a return use only */
924 sym = OP_SYMBOL (op);
926 /* if the type is a conditional */
927 if (sym->regType == REG_CND)
929 aop = op->aop = sym->aop = newAsmop (AOP_CRY);
934 /* if it is spilt then two situations
936 b) has a spill location */
937 if (sym->isspilt || sym->nRegs == 0)
939 /* rematerialize it NOW */
942 sym->aop = op->aop = aop =
944 aop->size = getSize (sym->type);
951 aop = op->aop = sym->aop = newAsmop (AOP_STR);
952 aop->size = getSize (sym->type);
953 for (i = 0; i < 4; i++)
954 aop->aopu.aop_str[i] = _fReturn[i];
960 if (sym->accuse == ACCUSE_A)
962 aop = op->aop = sym->aop = newAsmop (AOP_ACC);
963 aop->size = getSize (sym->type);
964 wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
966 aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
968 else if (sym->accuse == ACCUSE_SCRATCH)
970 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
971 aop->size = getSize (sym->type);
972 wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
973 aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
974 aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
976 else if (sym->accuse == ACCUSE_IY)
978 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
979 aop->size = getSize (sym->type);
980 wassertl(aop->size <= 2, "Internal error: Caching in IY, but too big to fit in IY");
981 aop->aopu.aop_str[0] = _pairs[PAIR_IY].l;
982 aop->aopu.aop_str[1] = _pairs[PAIR_IY].h;
986 wassertl (0, "Marked as being allocated into A or HL but is actually in neither");
991 /* else spill location */
992 if (sym->usl.spillLoc && getSize(sym->type) != getSize(sym->usl.spillLoc->type)) {
993 /* force a new aop if sizes differ */
994 sym->usl.spillLoc->aop = NULL;
996 sym->aop = op->aop = aop =
997 aopForSym (ic, sym->usl.spillLoc, result, requires_a);
998 wassertl (aop->size >= getSize (sym->type), "Operand doesn't fit in the spill location");
999 aop->size = getSize (sym->type);
1003 /* must be in a register */
1004 sym->aop = op->aop = aop = newAsmop (AOP_REG);
1005 aop->size = sym->nRegs;
1006 for (i = 0; i < sym->nRegs; i++)
1007 aop->aopu.aop_reg[i] = sym->regs[i];
1010 /*-----------------------------------------------------------------*/
1011 /* freeAsmop - free up the asmop given to an operand */
1012 /*----------------------------------------------------------------*/
1014 freeAsmop (operand * op, asmop * aaop, iCode * ic)
1031 if (aop->type == AOP_PAIRPTR && IS_Z80 && aop->aopu.aop_pairId == PAIR_DE)
1033 _pop (aop->aopu.aop_pairId);
1036 if (getPairId (aop) == PAIR_HL)
1038 spillPair (PAIR_HL);
1042 /* all other cases just dealloc */
1048 OP_SYMBOL (op)->aop = NULL;
1049 /* if the symbol has a spill */
1051 SPIL_LOC (op)->aop = NULL;
1058 isLitWord (asmop * aop)
1060 /* if (aop->size != 2)
1073 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
1077 /* depending on type */
1083 /* PENDING: for re-target */
1086 tsprintf (s, "!hashedstr + %d", aop->aopu.aop_immd, offset);
1088 else if (offset == 0)
1090 tsprintf (s, "%s", aop->aopu.aop_immd);
1094 tsprintf (s, "%s + %d", aop->aopu.aop_immd, offset);
1096 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1100 value *val = aop->aopu.aop_lit;
1101 /* if it is a float then it gets tricky */
1102 /* otherwise it is fairly simple */
1103 if (!IS_FLOAT (val->type))
1105 unsigned long v = (unsigned long) floatFromVal (val);
1111 else if (offset == 0)
1117 wassertl(0, "Encountered an invalid offset while fetching a literal");
1121 tsprintf (buffer, "!immedword", v);
1123 tsprintf (buffer, "!constword", v);
1125 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1136 /* it is type float */
1137 fl.f = (float) floatFromVal (val);
1140 i = fl.c[3-offset] | (fl.c[3-offset-1]<<8);
1142 i = fl.c[offset] | (fl.c[offset+1]<<8);
1145 tsprintf (buffer, "!immedword", i);
1147 tsprintf (buffer, "!constword", i);
1149 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1158 aopGetWord (asmop * aop, int offset)
1160 return aopGetLitWordLong (aop, offset, TRUE);
1164 isPtr (const char *s)
1166 if (!strcmp (s, "hl"))
1168 if (!strcmp (s, "ix"))
1170 if (!strcmp (s, "iy"))
1176 adjustPair (const char *pair, int *pold, int new)
1182 emit2 ("inc %s", pair);
1187 emit2 ("dec %s", pair);
1195 spillPair (PAIR_HL);
1196 spillPair (PAIR_IY);
1200 requiresHL (asmop * aop)
1216 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1218 const char *l, *base;
1219 const char *pair = _pairs[pairId].name;
1220 l = aopGetLitWordLong (left, offset, FALSE);
1221 base = aopGetLitWordLong (left, 0, FALSE);
1222 wassert (l && pair && base);
1226 if (pairId == PAIR_HL || pairId == PAIR_IY)
1228 if (_G.pairs[pairId].last_type == left->type)
1230 if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1232 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1234 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1237 if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
1244 _G.pairs[pairId].last_type = left->type;
1245 _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1246 _G.pairs[pairId].offset = offset;
1248 /* Both a lit on the right and a true symbol on the left */
1249 emit2 ("ld %s,!hashedstr", pair, l);
1253 makeFreePairId (iCode *ic, bool *pisUsed)
1259 if (!bitVectBitValue (ic->rMask, B_IDX) && !bitVectBitValue(ic->rMask, C_IDX))
1263 else if (IS_Z80 && !bitVectBitValue (ic->rMask, D_IDX) && !bitVectBitValue(ic->rMask, E_IDX))
1281 fetchPairLong (PAIR_ID pairId, asmop * aop, iCode *ic, int offset)
1283 /* if this is remateriazable */
1284 if (isLitWord (aop)) {
1285 fetchLitPair (pairId, aop, offset);
1289 if (getPairId (aop) == pairId)
1293 /* we need to get it byte by byte */
1294 else if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1295 aopGet (aop, offset, FALSE);
1296 switch (aop->size - offset) {
1298 emit2 ("ld l,!*hl");
1299 emit2 ("ld h,!immedbyte", 0);
1302 // PENDING: Requires that you are only fetching two bytes.
1305 emit2 ("ld h,!*hl");
1309 wassertl (0, "Attempted to fetch too much data into HL");
1313 else if (IS_Z80 && aop->type == AOP_IY) {
1314 /* Instead of fetching relative to IY, just grab directly
1315 from the address IY refers to */
1316 char *l = aopGetLitWordLong (aop, offset, FALSE);
1318 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1320 if (aop->size < 2) {
1321 emit2("ld %s,!zero", _pairs[pairId].h);
1324 else if (pairId == PAIR_IY)
1328 emit2 ("push %s", _pairs[getPairId(aop)].name);
1334 PAIR_ID id = makeFreePairId (ic, &isUsed);
1337 /* Can't load into parts, so load into HL then exchange. */
1338 emit2 ("ld %s,%s", _pairs[id].l, aopGet (aop, offset, FALSE));
1339 emit2 ("ld %s,%s", _pairs[id].h, aopGet (aop, offset + 1, FALSE));
1340 emit2 ("push %s", _pairs[id].name);
1348 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1349 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1351 /* PENDING: check? */
1352 if (pairId == PAIR_HL)
1353 spillPair (PAIR_HL);
1358 fetchPair (PAIR_ID pairId, asmop * aop)
1360 fetchPairLong (pairId, aop, NULL, 0);
1364 fetchHL (asmop * aop)
1366 fetchPair (PAIR_HL, aop);
1370 setupPairFromSP (PAIR_ID id, int offset)
1372 wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
1374 if (offset < INT8MIN || offset > INT8MAX)
1376 emit2 ("ld hl,!immedword", offset);
1377 emit2 ("add hl,sp");
1381 emit2 ("!ldahlsp", offset);
1386 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1391 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
1392 fetchLitPair (pairId, aop, 0);
1396 wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
1398 fetchLitPair (pairId, aop, offset);
1399 _G.pairs[pairId].offset = offset;
1403 wassertl (IS_Z80, "Only the Z80 has an extended stack");
1404 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
1407 int offset = aop->aopu.aop_stk + _G.stack.offset;
1409 if (_G.pairs[pairId].last_type == aop->type &&
1410 _G.pairs[pairId].offset == offset)
1416 /* PENDING: Do this better. */
1417 sprintf (buffer, "%d", offset + _G.stack.pushed);
1418 emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
1419 emit2 ("add %s,sp", _pairs[pairId].name);
1420 _G.pairs[pairId].last_type = aop->type;
1421 _G.pairs[pairId].offset = offset;
1428 /* Doesnt include _G.stack.pushed */
1429 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1431 if (aop->aopu.aop_stk > 0)
1433 abso += _G.stack.param_offset;
1435 assert (pairId == PAIR_HL);
1436 /* In some cases we can still inc or dec hl */
1437 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1439 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1443 setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
1445 _G.pairs[pairId].offset = abso;
1450 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
1456 _G.pairs[pairId].last_type = aop->type;
1462 emit2 ("!tlabeldef", key);
1466 /*-----------------------------------------------------------------*/
1467 /* aopGet - for fetching value of the aop */
1468 /*-----------------------------------------------------------------*/
1470 aopGet (asmop * aop, int offset, bool bit16)
1474 /* offset is greater than size then zero */
1475 /* PENDING: this seems a bit screwed in some pointer cases. */
1476 if (offset > (aop->size - 1) &&
1477 aop->type != AOP_LIT)
1479 tsprintf (s, "!zero");
1480 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1483 /* depending on type */
1487 /* PENDING: re-target */
1489 tsprintf (s, "!immedwords", aop->aopu.aop_immd);
1494 tsprintf (s, "!bankimmeds", aop->aopu.aop_immd);
1497 tsprintf (s, "!msbimmeds", aop->aopu.aop_immd);
1500 tsprintf (s, "!lsbimmeds", aop->aopu.aop_immd);
1503 wassertl (0, "Fetching from beyond the limits of an immediate value.");
1506 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1510 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1513 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1517 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1520 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1523 return aop->aopu.aop_reg[offset]->name;
1527 setupPair (PAIR_HL, aop, offset);
1528 tsprintf (s, "!*hl");
1530 return traceAlloc(&_G.trace.aops, Safe_strdup (s));
1534 setupPair (PAIR_IY, aop, offset);
1535 tsprintf (s, "!*iyx", offset);
1537 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1541 setupPair (PAIR_IY, aop, offset);
1542 tsprintf (s, "!*iyx", offset, offset);
1544 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1549 setupPair (PAIR_HL, aop, offset);
1550 tsprintf (s, "!*hl");
1554 if (aop->aopu.aop_stk >= 0)
1555 offset += _G.stack.param_offset;
1556 tsprintf (s, "!*ixx", aop->aopu.aop_stk + offset);
1559 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1562 wassertl (0, "Tried to fetch from a bit variable");
1571 tsprintf(s, "!zero");
1572 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1576 wassert (offset < 2);
1577 return aop->aopu.aop_str[offset];
1580 return aopLiteral (aop->aopu.aop_lit, offset);
1584 unsigned long v = aop->aopu.aop_simplelit;
1587 tsprintf (s, "!immedbyte", (unsigned int) v & 0xff);
1589 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1593 return aop->aopu.aop_str[offset];
1596 setupPair (aop->aopu.aop_pairId, aop, offset);
1597 sprintf (s, "(%s)", _pairs[aop->aopu.aop_pairId].name);
1599 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1604 wassertl (0, "aopget got unsupported aop->type");
1609 isRegString (const char *s)
1611 if (!strcmp (s, "b") ||
1623 isConstant (const char *s)
1625 /* This is a bit of a hack... */
1626 return (*s == '#' || *s == '$');
1630 canAssignToPtr (const char *s)
1632 if (isRegString (s))
1639 /*-----------------------------------------------------------------*/
1640 /* aopPut - puts a string for a aop */
1641 /*-----------------------------------------------------------------*/
1643 aopPut (asmop * aop, const char *s, int offset)
1647 if (aop->size && offset > (aop->size - 1))
1649 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1650 "aopPut got offset > aop->size");
1655 tsprintf(buffer2, s);
1658 /* will assign value to value */
1659 /* depending on where it is ofcourse */
1665 if (strcmp (s, "a"))
1666 emit2 ("ld a,%s", s);
1667 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1672 if (strcmp (s, "a"))
1673 emit2 ("ld a,%s", s);
1674 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1678 if (!strcmp (s, "!*hl"))
1679 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1682 aop->aopu.aop_reg[offset]->name, s);
1687 if (!canAssignToPtr (s))
1689 emit2 ("ld a,%s", s);
1690 setupPair (PAIR_IY, aop, offset);
1691 emit2 ("ld !*iyx,a", offset);
1695 setupPair (PAIR_IY, aop, offset);
1696 emit2 ("ld !*iyx,%s", offset, s);
1702 /* PENDING: for re-target */
1703 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1705 emit2 ("ld a,!*hl");
1708 setupPair (PAIR_HL, aop, offset);
1710 emit2 ("ld !*hl,%s", s);
1715 if (!canAssignToPtr (s))
1717 emit2 ("ld a,%s", s);
1718 setupPair (PAIR_IY, aop, offset);
1719 emit2 ("ld !*iyx,a", offset);
1723 setupPair (PAIR_IY, aop, offset);
1724 emit2 ("ld !*iyx,%s", offset, s);
1731 /* PENDING: re-target */
1732 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1734 emit2 ("ld a,!*hl");
1737 setupPair (PAIR_HL, aop, offset);
1738 if (!canAssignToPtr (s))
1740 emit2 ("ld a,%s", s);
1741 emit2 ("ld !*hl,a");
1744 emit2 ("ld !*hl,%s", s);
1748 if (aop->aopu.aop_stk >= 0)
1749 offset += _G.stack.param_offset;
1750 if (!canAssignToPtr (s))
1752 emit2 ("ld a,%s", s);
1753 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
1757 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
1763 /* if bit variable */
1764 if (!aop->aopu.aop_dir)
1766 emit2 ("ld a,!zero");
1771 /* In bit space but not in C - cant happen */
1772 wassertl (0, "Tried to write into a bit variable");
1778 if (strcmp (aop->aopu.aop_str[offset], s))
1780 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1786 if (!offset && (strcmp (s, "acc") == 0))
1790 wassertl (0, "Tried to access past the end of A");
1794 if (strcmp (aop->aopu.aop_str[offset], s))
1795 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1800 wassert (offset < 2);
1801 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1805 setupPair (aop->aopu.aop_pairId, aop, offset);
1806 emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
1810 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1811 "aopPut got unsupported aop->type");
1816 #define AOP(op) op->aop
1817 #define AOP_TYPE(op) AOP(op)->type
1818 #define AOP_SIZE(op) AOP(op)->size
1819 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
1822 commitPair (asmop * aop, PAIR_ID id)
1824 /* PENDING: Verify this. */
1825 if (id == PAIR_HL && requiresHL (aop) && IS_GB)
1829 aopPut (aop, "a", 0);
1830 aopPut (aop, "d", 1);
1835 if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
1837 char *l = aopGetLitWordLong (aop, 0, FALSE);
1840 emit2 ("ld (%s),%s", l, _pairs[id].name);
1844 aopPut (aop, _pairs[id].l, 0);
1845 aopPut (aop, _pairs[id].h, 1);
1850 /*-----------------------------------------------------------------*/
1851 /* getDataSize - get the operand data size */
1852 /*-----------------------------------------------------------------*/
1854 getDataSize (operand * op)
1857 size = AOP_SIZE (op);
1861 wassertl (0, "Somehow got a three byte data pointer");
1866 /*-----------------------------------------------------------------*/
1867 /* movLeft2Result - move byte from left to result */
1868 /*-----------------------------------------------------------------*/
1870 movLeft2Result (operand * left, int offl,
1871 operand * result, int offr, int sign)
1875 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
1877 l = aopGet (AOP (left), offl, FALSE);
1881 aopPut (AOP (result), l, offr);
1885 if (getDataSize (left) == offl + 1)
1887 emit2 ("ld a,%s", l);
1888 aopPut (AOP (result), "a", offr);
1895 movLeft2ResultLong (operand * left, int offl,
1896 operand * result, int offr, int sign,
1901 movLeft2Result (left, offl, result, offr, sign);
1905 wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
1906 wassertl (size == 2, "Only implemented for two bytes or one");
1908 if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
1910 emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
1911 emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
1913 spillPair (PAIR_HL);
1915 else if ( getPairId ( AOP (result)) == PAIR_IY)
1917 PAIR_ID id = getPairId (AOP (left));
1918 if (id != PAIR_INVALID)
1920 emit2("push %s", _pairs[id].name);
1931 movLeft2Result (left, offl, result, offr, sign);
1932 movLeft2Result (left, offl+1, result, offr+1, sign);
1937 /** Put Acc into a register set
1940 outAcc (operand * result)
1943 size = getDataSize (result);
1946 aopPut (AOP (result), "a", 0);
1949 /* unsigned or positive */
1952 aopPut (AOP (result), "!zero", offset++);
1957 /** Take the value in carry and put it into a register
1960 outBitCLong (operand * result, bool swap_sense)
1962 /* if the result is bit */
1963 if (AOP_TYPE (result) == AOP_CRY)
1965 wassertl (0, "Tried to write carry to a bit");
1969 emit2 ("ld a,!zero");
1972 emit2 ("xor a,!immedbyte", 1);
1978 outBitC (operand * result)
1980 outBitCLong (result, FALSE);
1983 /*-----------------------------------------------------------------*/
1984 /* toBoolean - emit code for orl a,operator(sizeop) */
1985 /*-----------------------------------------------------------------*/
1987 _toBoolean (operand * oper)
1989 int size = AOP_SIZE (oper);
1993 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
1996 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
2000 if (AOP (oper)->type != AOP_ACC)
2003 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
2008 /*-----------------------------------------------------------------*/
2009 /* genNotFloat - generates not for float operations */
2010 /*-----------------------------------------------------------------*/
2012 genNotFloat (operand * op, operand * res)
2017 emitDebug ("; genNotFloat");
2019 /* we will put 127 in the first byte of
2021 aopPut (AOP (res), "!immedbyte", 0x7F);
2022 size = AOP_SIZE (op) - 1;
2025 _moveA (aopGet (op->aop, offset++, FALSE));
2029 emit2 ("or a,%s", aopGet (op->aop, offset++, FALSE));
2032 tlbl = newiTempLabel (NULL);
2033 aopPut (res->aop, "!one", 1);
2034 emit2 ("!shortjp z !tlabel", tlbl->key + 100);
2035 aopPut (res->aop, "!zero", 1);
2037 emitLabel(tlbl->key + 100);
2039 size = res->aop->size - 2;
2041 /* put zeros in the rest */
2043 aopPut (res->aop, "!zero", offset++);
2046 /*-----------------------------------------------------------------*/
2047 /* genNot - generate code for ! operation */
2048 /*-----------------------------------------------------------------*/
2052 sym_link *optype = operandType (IC_LEFT (ic));
2054 /* assign asmOps to operand & result */
2055 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
2056 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2058 /* if in bit space then a special case */
2059 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2061 wassertl (0, "Tried to negate a bit");
2064 /* if type float then do float */
2065 if (IS_FLOAT (optype))
2067 genNotFloat (IC_LEFT (ic), IC_RESULT (ic));
2071 _toBoolean (IC_LEFT (ic));
2076 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
2077 emit2 ("sub a,!one");
2078 outBitC (IC_RESULT (ic));
2081 /* release the aops */
2082 freeAsmop (IC_LEFT (ic), NULL, ic);
2083 freeAsmop (IC_RESULT (ic), NULL, ic);
2086 /*-----------------------------------------------------------------*/
2087 /* genCpl - generate code for complement */
2088 /*-----------------------------------------------------------------*/
2096 /* assign asmOps to operand & result */
2097 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2098 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2100 /* if both are in bit space then
2102 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2103 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2105 wassertl (0, "Left and the result are in bit space");
2108 size = AOP_SIZE (IC_RESULT (ic));
2111 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2114 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2117 /* release the aops */
2118 freeAsmop (IC_LEFT (ic), NULL, ic);
2119 freeAsmop (IC_RESULT (ic), NULL, ic);
2123 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
2130 store de into result
2135 store de into result
2137 const char *first = isAdd ? "add" : "sub";
2138 const char *later = isAdd ? "adc" : "sbc";
2140 wassertl (IS_GB, "Code is only relevent to the gbz80");
2141 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
2143 fetchPair (PAIR_DE, left);
2146 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
2149 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2152 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2153 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2155 fetchPairLong (PAIR_DE, left, NULL, MSB24);
2156 aopGet (right, MSB24, FALSE);
2160 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2163 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2165 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2166 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2170 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2172 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2175 /*-----------------------------------------------------------------*/
2176 /* genUminusFloat - unary minus for floating points */
2177 /*-----------------------------------------------------------------*/
2179 genUminusFloat (operand * op, operand * result)
2181 int size, offset = 0;
2183 emitDebug("; genUminusFloat");
2185 /* for this we just need to flip the
2186 first it then copy the rest in place */
2187 size = AOP_SIZE (op) - 1;
2189 _moveA(aopGet (AOP (op), MSB32, FALSE));
2191 emit2("xor a,!immedbyte", 0x80);
2192 aopPut (AOP (result), "a", MSB32);
2196 aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2201 /*-----------------------------------------------------------------*/
2202 /* genUminus - unary minus code generation */
2203 /*-----------------------------------------------------------------*/
2205 genUminus (iCode * ic)
2208 sym_link *optype, *rtype;
2211 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2212 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2214 /* if both in bit space then special
2216 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2217 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2219 wassertl (0, "Left and right are in bit space");
2223 optype = operandType (IC_LEFT (ic));
2224 rtype = operandType (IC_RESULT (ic));
2226 /* if float then do float stuff */
2227 if (IS_FLOAT (optype))
2229 genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2233 /* otherwise subtract from zero */
2234 size = AOP_SIZE (IC_LEFT (ic));
2236 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2238 /* Create a new asmop with value zero */
2239 asmop *azero = newAsmop (AOP_SIMPLELIT);
2240 azero->aopu.aop_simplelit = 0;
2242 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2250 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2251 emit2 ("ld a,!zero");
2252 emit2 ("sbc a,%s", l);
2253 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2256 /* if any remaining bytes in the result */
2257 /* we just need to propagate the sign */
2258 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2263 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2267 /* release the aops */
2268 freeAsmop (IC_LEFT (ic), NULL, ic);
2269 freeAsmop (IC_RESULT (ic), NULL, ic);
2272 /*-----------------------------------------------------------------*/
2273 /* assignResultValue - */
2274 /*-----------------------------------------------------------------*/
2276 assignResultValue (operand * oper)
2278 int size = AOP_SIZE (oper);
2281 wassertl (size <= 4, "Got a result that is bigger than four bytes");
2282 topInA = requiresHL (AOP (oper));
2284 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2286 /* We do it the hard way here. */
2288 aopPut (AOP (oper), _fReturn[0], 0);
2289 aopPut (AOP (oper), _fReturn[1], 1);
2291 aopPut (AOP (oper), _fReturn[0], 2);
2292 aopPut (AOP (oper), _fReturn[1], 3);
2298 aopPut (AOP (oper), _fReturn[size], size);
2303 /** Simple restore that doesn't take into account what is used in the
2307 _restoreRegsAfterCall(void)
2309 if (_G.stack.pushedDE)
2312 _G.stack.pushedDE = FALSE;
2314 if (_G.stack.pushedBC)
2317 _G.stack.pushedBC = FALSE;
2319 _G.saves.saved = FALSE;
2323 _saveRegsForCall(iCode *ic, int sendSetSize)
2326 o Stack parameters are pushed before this function enters
2327 o DE and BC may be used in this function.
2328 o HL and DE may be used to return the result.
2329 o HL and DE may be used to send variables.
2330 o DE and BC may be used to store the result value.
2331 o HL may be used in computing the sent value of DE
2332 o The iPushes for other parameters occur before any addSets
2334 Logic: (to be run inside the first iPush or if none, before sending)
2335 o Compute if DE and/or BC are in use over the call
2336 o Compute if DE is used in the send set
2337 o Compute if DE and/or BC are used to hold the result value
2338 o If (DE is used, or in the send set) and is not used in the result, push.
2339 o If BC is used and is not in the result, push
2341 o If DE is used in the send set, fetch
2342 o If HL is used in the send set, fetch
2346 if (_G.saves.saved == FALSE) {
2347 bool deInUse, bcInUse;
2349 bool bcInRet = FALSE, deInRet = FALSE;
2352 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
2354 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2355 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2357 deSending = (sendSetSize > 1);
2359 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2361 if (bcInUse && bcInRet == FALSE) {
2363 _G.stack.pushedBC = TRUE;
2365 if (deInUse && deInRet == FALSE) {
2367 _G.stack.pushedDE = TRUE;
2370 _G.saves.saved = TRUE;
2373 /* Already saved. */
2377 /*-----------------------------------------------------------------*/
2378 /* genIpush - genrate code for pushing this gets a little complex */
2379 /*-----------------------------------------------------------------*/
2381 genIpush (iCode * ic)
2383 int size, offset = 0;
2386 /* if this is not a parm push : ie. it is spill push
2387 and spill push is always done on the local stack */
2390 wassertl(0, "Encountered an unsupported spill push.");
2394 if (_G.saves.saved == FALSE) {
2395 /* Caller saves, and this is the first iPush. */
2396 /* Scan ahead until we find the function that we are pushing parameters to.
2397 Count the number of addSets on the way to figure out what registers
2398 are used in the send set.
2401 iCode *walk = ic->next;
2404 if (walk->op == SEND) {
2407 else if (walk->op == CALL || walk->op == PCALL) {
2416 _saveRegsForCall(walk, nAddSets);
2419 /* Already saved by another iPush. */
2422 /* then do the push */
2423 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2425 size = AOP_SIZE (IC_LEFT (ic));
2427 if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2429 _G.stack.pushed += 2;
2430 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2436 fetchHL (AOP (IC_LEFT (ic)));
2438 spillPair (PAIR_HL);
2439 _G.stack.pushed += 2;
2444 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
2446 spillPair (PAIR_HL);
2447 _G.stack.pushed += 2;
2448 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
2450 spillPair (PAIR_HL);
2451 _G.stack.pushed += 2;
2457 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2459 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2461 emit2 ("ld a,(%s)", l);
2465 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2466 emit2 ("ld a,%s", l);
2474 freeAsmop (IC_LEFT (ic), NULL, ic);
2477 /*-----------------------------------------------------------------*/
2478 /* genIpop - recover the registers: can happen only for spilling */
2479 /*-----------------------------------------------------------------*/
2481 genIpop (iCode * ic)
2486 /* if the temp was not pushed then */
2487 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2490 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2491 size = AOP_SIZE (IC_LEFT (ic));
2492 offset = (size - 1);
2493 if (isPair (AOP (IC_LEFT (ic))))
2495 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2503 spillPair (PAIR_HL);
2504 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2508 freeAsmop (IC_LEFT (ic), NULL, ic);
2511 /* This is quite unfortunate */
2513 setArea (int inHome)
2516 static int lastArea = 0;
2518 if (_G.in_home != inHome) {
2520 const char *sz = port->mem.code_name;
2521 port->mem.code_name = "HOME";
2522 emit2("!area", CODE_NAME);
2523 port->mem.code_name = sz;
2526 emit2("!area", CODE_NAME); */
2527 _G.in_home = inHome;
2538 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2542 symbol *sym = OP_SYMBOL (op);
2544 if (sym->isspilt || sym->nRegs == 0)
2547 aopOp (op, ic, FALSE, FALSE);
2550 if (aop->type == AOP_REG)
2553 for (i = 0; i < aop->size; i++)
2555 if (pairId == PAIR_DE)
2557 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2558 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2560 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2563 else if (pairId == PAIR_BC)
2565 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2566 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2568 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2578 freeAsmop (IC_LEFT (ic), NULL, ic);
2582 /** Emit the code for a call statement
2585 emitCall (iCode * ic, bool ispcall)
2587 sym_link *dtype = operandType (IC_LEFT (ic));
2589 /* if caller saves & we have not saved then */
2595 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2597 /* if send set is not empty then assign */
2602 int nSend = elementsInSet(_G.sendSet);
2603 bool swapped = FALSE;
2605 int _z80_sendOrder[] = {
2610 /* Check if the parameters are swapped. If so route through hl instead. */
2611 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2613 sic = setFirstItem(_G.sendSet);
2614 sic = setNextItem(_G.sendSet);
2616 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2617 /* The second send value is loaded from one the one that holds the first
2618 send, i.e. it is overwritten. */
2619 /* Cache the first in HL, and load the second from HL instead. */
2620 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2621 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2627 for (sic = setFirstItem (_G.sendSet); sic;
2628 sic = setNextItem (_G.sendSet))
2631 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2633 size = AOP_SIZE (IC_LEFT (sic));
2634 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2635 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2637 // PENDING: Mild hack
2638 if (swapped == TRUE && send == 1) {
2640 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2643 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2645 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2648 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2652 freeAsmop (IC_LEFT (sic), NULL, sic);
2659 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2661 werror (W_INDIR_BANKED);
2663 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2665 if (isLitWord (AOP (IC_LEFT (ic))))
2667 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2671 symbol *rlbl = newiTempLabel (NULL);
2672 spillPair (PAIR_HL);
2673 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2675 _G.stack.pushed += 2;
2677 fetchHL (AOP (IC_LEFT (ic)));
2679 emit2 ("!tlabeldef", (rlbl->key + 100));
2680 _G.stack.pushed -= 2;
2682 freeAsmop (IC_LEFT (ic), NULL, ic);
2686 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2687 OP_SYMBOL (IC_LEFT (ic))->rname :
2688 OP_SYMBOL (IC_LEFT (ic))->name;
2689 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2691 emit2 ("call banked_call");
2692 emit2 ("!dws", name);
2693 emit2 ("!dw !bankimmeds", name);
2698 emit2 ("call %s", name);
2703 /* Mark the regsiters as restored. */
2704 _G.saves.saved = FALSE;
2706 /* if we need assign a result value */
2707 if ((IS_ITEMP (IC_RESULT (ic)) &&
2708 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2709 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2710 IS_TRUE_SYMOP (IC_RESULT (ic)))
2713 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2715 assignResultValue (IC_RESULT (ic));
2717 freeAsmop (IC_RESULT (ic), NULL, ic);
2720 /* adjust the stack for parameters if required */
2723 int i = ic->parmBytes;
2725 _G.stack.pushed -= i;
2728 emit2 ("!ldaspsp", i);
2735 emit2 ("ld iy,!immedword", i);
2736 emit2 ("add iy,sp");
2756 if (_G.stack.pushedDE)
2758 bool dInRet = bitVectBitValue(ic->rUsed, D_IDX);
2759 bool eInRet = bitVectBitValue(ic->rUsed, E_IDX);
2761 if (dInRet && eInRet)
2763 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
2767 /* Only restore E */
2774 /* Only restore D */
2782 _G.stack.pushedDE = FALSE;
2785 if (_G.stack.pushedBC)
2787 bool bInRet = bitVectBitValue(ic->rUsed, B_IDX);
2788 bool cInRet = bitVectBitValue(ic->rUsed, C_IDX);
2790 if (bInRet && cInRet)
2792 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
2796 /* Only restore C */
2803 /* Only restore B */
2811 _G.stack.pushedBC = FALSE;
2815 /*-----------------------------------------------------------------*/
2816 /* genCall - generates a call statement */
2817 /*-----------------------------------------------------------------*/
2819 genCall (iCode * ic)
2821 emitCall (ic, FALSE);
2824 /*-----------------------------------------------------------------*/
2825 /* genPcall - generates a call by pointer statement */
2826 /*-----------------------------------------------------------------*/
2828 genPcall (iCode * ic)
2830 emitCall (ic, TRUE);
2833 /*-----------------------------------------------------------------*/
2834 /* resultRemat - result is rematerializable */
2835 /*-----------------------------------------------------------------*/
2837 resultRemat (iCode * ic)
2839 if (SKIP_IC (ic) || ic->op == IFX)
2842 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2844 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2845 if (sym->remat && !POINTER_SET (ic))
2852 extern set *publics;
2854 /*-----------------------------------------------------------------*/
2855 /* genFunction - generated code for function entry */
2856 /*-----------------------------------------------------------------*/
2858 genFunction (iCode * ic)
2860 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2863 bool bcInUse = FALSE;
2864 bool deInUse = FALSE;
2866 setArea (IFFUNC_NONBANKED (sym->type));
2868 /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
2871 _G.receiveOffset = 0;
2873 /* Record the last function name for debugging. */
2874 _G.lastFunctionName = sym->rname;
2876 /* Create the function header */
2877 emit2 ("!functionheader", sym->name);
2878 sprintf (buffer, "%s_start", sym->rname);
2879 emit2 ("!labeldef", buffer);
2880 emit2 ("!functionlabeldef", sym->rname);
2882 if (options.profile)
2884 emit2 ("!profileenter");
2887 ftype = operandType (IC_LEFT (ic));
2889 /* if critical function then turn interrupts off */
2890 if (IFFUNC_ISCRITICAL (ftype))
2893 /* if this is an interrupt service routine then save all potentially used registers. */
2894 if (IFFUNC_ISISR (sym->type))
2899 /* PENDING: callee-save etc */
2901 _G.stack.param_offset = 0;
2903 if (z80_opts.calleeSavesBC)
2908 /* Detect which registers are used. */
2909 if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
2912 for (i = 0; i < sym->regsUsed->size; i++)
2914 if (bitVectBitValue (sym->regsUsed, i))
2928 /* Other systems use DE as a temporary. */
2939 _G.stack.param_offset += 2;
2942 _G.calleeSaves.pushedBC = bcInUse;
2947 _G.stack.param_offset += 2;
2950 _G.calleeSaves.pushedDE = deInUse;
2952 /* adjust the stack for the function */
2953 _G.stack.last = sym->stack;
2955 if (sym->stack && IS_GB && sym->stack > -INT8MIN)
2956 emit2 ("!enterxl", sym->stack);
2957 else if (sym->stack)
2958 emit2 ("!enterx", sym->stack);
2961 _G.stack.offset = sym->stack;
2964 /*-----------------------------------------------------------------*/
2965 /* genEndFunction - generates epilogue for functions */
2966 /*-----------------------------------------------------------------*/
2968 genEndFunction (iCode * ic)
2970 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2972 if (IFFUNC_ISISR (sym->type))
2974 wassertl (0, "Tried to close an interrupt support function");
2978 if (IFFUNC_ISCRITICAL (sym->type))
2981 /* PENDING: calleeSave */
2983 if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
2985 emit2 ("!leavexl", _G.stack.offset);
2987 else if (_G.stack.offset)
2989 emit2 ("!leavex", _G.stack.offset);
2996 if (_G.calleeSaves.pushedDE)
2999 _G.calleeSaves.pushedDE = FALSE;
3002 if (_G.calleeSaves.pushedBC)
3005 _G.calleeSaves.pushedBC = FALSE;
3008 if (options.profile)
3010 emit2 ("!profileexit");
3014 /* Both baned and non-banked just ret */
3017 sprintf (buffer, "%s_end", sym->rname);
3018 emit2 ("!labeldef", buffer);
3020 _G.flushStatics = 1;
3021 _G.stack.pushed = 0;
3022 _G.stack.offset = 0;
3025 /*-----------------------------------------------------------------*/
3026 /* genRet - generate code for return statement */
3027 /*-----------------------------------------------------------------*/
3032 /* Errk. This is a hack until I can figure out how
3033 to cause dehl to spill on a call */
3034 int size, offset = 0;
3036 /* if we have no return value then
3037 just generate the "ret" */
3041 /* we have something to return then
3042 move the return value into place */
3043 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3044 size = AOP_SIZE (IC_LEFT (ic));
3046 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3050 emit2 ("ld de,%s", l);
3054 emit2 ("ld hl,%s", l);
3059 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3061 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3062 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3068 l = aopGet (AOP (IC_LEFT (ic)), offset,
3070 if (strcmp (_fReturn[offset], l))
3071 emit2 ("ld %s,%s", _fReturn[offset++], l);
3075 freeAsmop (IC_LEFT (ic), NULL, ic);
3078 /* generate a jump to the return label
3079 if the next is not the return statement */
3080 if (!(ic->next && ic->next->op == LABEL &&
3081 IC_LABEL (ic->next) == returnLabel))
3083 emit2 ("jp !tlabel", returnLabel->key + 100);
3086 /*-----------------------------------------------------------------*/
3087 /* genLabel - generates a label */
3088 /*-----------------------------------------------------------------*/
3090 genLabel (iCode * ic)
3092 /* special case never generate */
3093 if (IC_LABEL (ic) == entryLabel)
3096 emitLabel (IC_LABEL (ic)->key + 100);
3099 /*-----------------------------------------------------------------*/
3100 /* genGoto - generates a ljmp */
3101 /*-----------------------------------------------------------------*/
3103 genGoto (iCode * ic)
3105 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3108 /*-----------------------------------------------------------------*/
3109 /* genPlusIncr :- does addition with increment if possible */
3110 /*-----------------------------------------------------------------*/
3112 genPlusIncr (iCode * ic)
3114 unsigned int icount;
3115 unsigned int size = getDataSize (IC_RESULT (ic));
3116 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3118 /* will try to generate an increment */
3119 /* if the right side is not a literal
3121 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3124 emitDebug ("; genPlusIncr");
3126 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3128 /* If result is a pair */
3129 if (resultId != PAIR_INVALID)
3131 if (isLitWord (AOP (IC_LEFT (ic))))
3133 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3136 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3138 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3140 PAIR_ID freep = getFreePairId (ic);
3141 if (freep != PAIR_INVALID)
3143 fetchPair (freep, AOP (IC_RIGHT (ic)));
3144 emit2 ("add hl,%s", _pairs[freep].name);
3150 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3151 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3158 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3162 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3166 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3171 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3173 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3174 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3178 /* if the literal value of the right hand side
3179 is greater than 4 then it is not worth it */
3183 /* if increment 16 bits in register */
3184 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3190 symbol *tlbl = NULL;
3191 tlbl = newiTempLabel (NULL);
3194 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3197 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3200 emitLabel (tlbl->key + 100);
3204 /* if the sizes are greater than 1 then we cannot */
3205 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3206 AOP_SIZE (IC_LEFT (ic)) > 1)
3209 /* If the result is in a register then we can load then increment.
3211 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3213 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3216 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3221 /* we can if the aops of the left & result match or
3222 if they are in registers and the registers are the
3224 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3228 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3236 /*-----------------------------------------------------------------*/
3237 /* outBitAcc - output a bit in acc */
3238 /*-----------------------------------------------------------------*/
3240 outBitAcc (operand * result)
3242 symbol *tlbl = newiTempLabel (NULL);
3243 /* if the result is a bit */
3244 if (AOP_TYPE (result) == AOP_CRY)
3246 wassertl (0, "Tried to write A into a bit");
3250 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3251 emit2 ("ld a,!one");
3252 emitLabel (tlbl->key + 100);
3258 couldDestroyCarry (asmop *aop)
3262 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3271 shiftIntoPair (int idx, asmop *aop)
3273 PAIR_ID id = PAIR_INVALID;
3275 wassertl (IS_Z80, "Only implemented for the Z80");
3276 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3288 wassertl (0, "Internal error - hit default case");
3291 emitDebug ("; Shift into pair idx %u", idx);
3295 setupPair (PAIR_HL, aop, 0);
3299 setupPair (PAIR_IY, aop, 0);
3301 emit2 ("pop %s", _pairs[id].name);
3304 aop->type = AOP_PAIRPTR;
3305 aop->aopu.aop_pairId = id;
3306 _G.pairs[id].offset = 0;
3307 _G.pairs[id].last_type = aop->type;
3311 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
3313 wassert (left && right);
3317 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3319 shiftIntoPair (0, right);
3320 shiftIntoPair (1, result);
3322 else if (couldDestroyCarry (right))
3324 shiftIntoPair (0, right);
3326 else if (couldDestroyCarry (result))
3328 shiftIntoPair (0, result);
3337 /*-----------------------------------------------------------------*/
3338 /* genPlus - generates code for addition */
3339 /*-----------------------------------------------------------------*/
3341 genPlus (iCode * ic)
3343 int size, offset = 0;
3345 /* special cases :- */
3347 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3348 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3349 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3351 /* Swap the left and right operands if:
3353 if literal, literal on the right or
3354 if left requires ACC or right is already
3357 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3358 (AOP_NEEDSACC (IC_LEFT (ic))) ||
3359 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3361 operand *t = IC_RIGHT (ic);
3362 IC_RIGHT (ic) = IC_LEFT (ic);
3366 /* if both left & right are in bit
3368 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3369 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3372 wassertl (0, "Tried to add two bits");
3375 /* if left in bit space & right literal */
3376 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3377 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3379 /* Can happen I guess */
3380 wassertl (0, "Tried to add a bit to a literal");
3383 /* if I can do an increment instead
3384 of add then GOOD for ME */
3385 if (genPlusIncr (ic) == TRUE)
3388 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3390 size = getDataSize (IC_RESULT (ic));
3392 /* Special case when left and right are constant */
3393 if (isPair (AOP (IC_RESULT (ic))))
3396 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3397 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3399 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3405 sprintf (buffer, "#(%s + %s)", left, right);
3406 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3411 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3413 /* Fetch into HL then do the add */
3414 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3415 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3417 spillPair (PAIR_HL);
3419 if (left == PAIR_HL && right != PAIR_INVALID)
3421 emit2 ("add hl,%s", _pairs[right].name);
3424 else if (right == PAIR_HL && left != PAIR_INVALID)
3426 emit2 ("add hl,%s", _pairs[left].name);
3429 else if (right != PAIR_INVALID && right != PAIR_HL)
3431 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3432 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3435 else if (left != PAIR_INVALID && left != PAIR_HL)
3437 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3438 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3447 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3449 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3450 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3452 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3457 ld hl,sp+n trashes C so we cant afford to do it during an
3458 add with stack based varibles. Worst case is:
3471 So you cant afford to load up hl if either left, right, or result
3472 is on the stack (*sigh*) The alt is:
3480 Combinations in here are:
3481 * If left or right are in bc then the loss is small - trap later
3482 * If the result is in bc then the loss is also small
3486 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3487 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3488 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3490 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3491 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3492 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3493 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3495 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3497 /* Swap left and right */
3498 operand *t = IC_RIGHT (ic);
3499 IC_RIGHT (ic) = IC_LEFT (ic);
3502 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3504 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3505 emit2 ("add hl,bc");
3509 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3510 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3511 emit2 ("add hl,de");
3513 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3519 /* Be paranoid on the GB with 4 byte variables due to how C
3520 can be trashed by lda hl,n(sp).
3522 _gbz80_emitAddSubLong (ic, TRUE);
3527 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3531 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3533 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3536 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3539 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3543 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3546 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3549 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3551 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3555 freeAsmop (IC_LEFT (ic), NULL, ic);
3556 freeAsmop (IC_RIGHT (ic), NULL, ic);
3557 freeAsmop (IC_RESULT (ic), NULL, ic);
3561 /*-----------------------------------------------------------------*/
3562 /* genMinusDec :- does subtraction with deccrement if possible */
3563 /*-----------------------------------------------------------------*/
3565 genMinusDec (iCode * ic)
3567 unsigned int icount;
3568 unsigned int size = getDataSize (IC_RESULT (ic));
3570 /* will try to generate an increment */
3571 /* if the right side is not a literal we cannot */
3572 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3575 /* if the literal value of the right hand side
3576 is greater than 4 then it is not worth it */
3577 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3580 size = getDataSize (IC_RESULT (ic));
3582 /* if decrement 16 bits in register */
3583 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3584 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3587 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3591 /* If result is a pair */
3592 if (isPair (AOP (IC_RESULT (ic))))
3594 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3596 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3600 /* if increment 16 bits in register */
3601 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3605 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3608 emit2 ("dec %s", _getTempPairName());
3611 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3617 /* if the sizes are greater than 1 then we cannot */
3618 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3619 AOP_SIZE (IC_LEFT (ic)) > 1)
3622 /* we can if the aops of the left & result match or if they are in
3623 registers and the registers are the same */
3624 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3627 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3634 /*-----------------------------------------------------------------*/
3635 /* genMinus - generates code for subtraction */
3636 /*-----------------------------------------------------------------*/
3638 genMinus (iCode * ic)
3640 int size, offset = 0;
3641 unsigned long lit = 0L;
3643 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3644 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3645 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3647 /* special cases :- */
3648 /* if both left & right are in bit space */
3649 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3650 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3652 wassertl (0, "Tried to subtract two bits");
3656 /* if I can do an decrement instead of subtract then GOOD for ME */
3657 if (genMinusDec (ic) == TRUE)
3660 size = getDataSize (IC_RESULT (ic));
3662 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3667 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3671 /* Same logic as genPlus */
3674 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3675 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3676 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3678 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3679 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3680 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3681 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3683 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3684 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3686 if (left == PAIR_INVALID && right == PAIR_INVALID)
3691 else if (right == PAIR_INVALID)
3693 else if (left == PAIR_INVALID)
3696 fetchPair (left, AOP (IC_LEFT (ic)));
3697 /* Order is important. Right may be HL */
3698 fetchPair (right, AOP (IC_RIGHT (ic)));
3700 emit2 ("ld a,%s", _pairs[left].l);
3701 emit2 ("sub a,%s", _pairs[right].l);
3703 emit2 ("ld a,%s", _pairs[left].h);
3704 emit2 ("sbc a,%s", _pairs[right].h);
3706 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
3708 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3710 aopPut (AOP (IC_RESULT (ic)), "e", 0);
3716 /* Be paranoid on the GB with 4 byte variables due to how C
3717 can be trashed by lda hl,n(sp).
3719 _gbz80_emitAddSubLong (ic, FALSE);
3724 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3726 /* if literal, add a,#-lit, else normal subb */
3729 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3730 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3734 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3737 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3741 /* first add without previous c */
3743 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
3745 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3747 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3750 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3751 AOP_SIZE (IC_LEFT (ic)) == 3 &&
3752 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3754 wassertl (0, "Tried to subtract on a long pointer");
3758 freeAsmop (IC_LEFT (ic), NULL, ic);
3759 freeAsmop (IC_RIGHT (ic), NULL, ic);
3760 freeAsmop (IC_RESULT (ic), NULL, ic);
3763 /*-----------------------------------------------------------------*/
3764 /* genMult - generates code for multiplication */
3765 /*-----------------------------------------------------------------*/
3767 genMult (iCode * ic)
3771 /* If true then the final operation should be a subtract */
3772 bool active = FALSE;
3774 /* Shouldn't occur - all done through function calls */
3775 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3776 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3777 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3779 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
3780 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
3781 AOP_SIZE (IC_RESULT (ic)) > 2)
3783 wassertl (0, "Multiplication is handled through support function calls");
3786 /* Swap left and right such that right is a literal */
3787 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
3789 operand *t = IC_RIGHT (ic);
3790 IC_RIGHT (ic) = IC_LEFT (ic);
3794 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
3796 val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
3797 // wassertl (val > 0, "Multiply must be positive");
3798 wassertl (val != 1, "Can't multiply by 1");
3800 if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
3802 _G.stack.pushedDE = TRUE;
3805 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
3807 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
3815 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3820 /* Fully unroled version of mul.s. Not the most efficient.
3822 for (count = 0; count < 16; count++)
3824 if (count != 0 && active)
3826 emit2 ("add hl,hl");
3830 if (active == FALSE)
3837 emit2 ("add hl,de");
3846 if (IS_Z80 && _G.stack.pushedDE)
3849 _G.stack.pushedDE = FALSE;
3852 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3854 freeAsmop (IC_LEFT (ic), NULL, ic);
3855 freeAsmop (IC_RIGHT (ic), NULL, ic);
3856 freeAsmop (IC_RESULT (ic), NULL, ic);
3859 /*-----------------------------------------------------------------*/
3860 /* genDiv - generates code for division */
3861 /*-----------------------------------------------------------------*/
3865 /* Shouldn't occur - all done through function calls */
3866 wassertl (0, "Division is handled through support function calls");
3869 /*-----------------------------------------------------------------*/
3870 /* genMod - generates code for division */
3871 /*-----------------------------------------------------------------*/
3875 /* Shouldn't occur - all done through function calls */
3879 /*-----------------------------------------------------------------*/
3880 /* genIfxJump :- will create a jump depending on the ifx */
3881 /*-----------------------------------------------------------------*/
3883 genIfxJump (iCode * ic, char *jval)
3888 /* if true label then we jump if condition
3892 jlbl = IC_TRUE (ic);
3893 if (!strcmp (jval, "a"))
3897 else if (!strcmp (jval, "c"))
3901 else if (!strcmp (jval, "nc"))
3905 else if (!strcmp (jval, "m"))
3909 else if (!strcmp (jval, "p"))
3915 /* The buffer contains the bit on A that we should test */
3921 /* false label is present */
3922 jlbl = IC_FALSE (ic);
3923 if (!strcmp (jval, "a"))
3927 else if (!strcmp (jval, "c"))
3931 else if (!strcmp (jval, "nc"))
3935 else if (!strcmp (jval, "m"))
3939 else if (!strcmp (jval, "p"))
3945 /* The buffer contains the bit on A that we should test */
3949 /* Z80 can do a conditional long jump */
3950 if (!strcmp (jval, "a"))
3954 else if (!strcmp (jval, "c"))
3957 else if (!strcmp (jval, "nc"))
3960 else if (!strcmp (jval, "m"))
3963 else if (!strcmp (jval, "p"))
3968 emit2 ("bit %s,a", jval);
3970 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
3972 /* mark the icode as generated */
3978 _getPairIdName (PAIR_ID id)
3980 return _pairs[id].name;
3985 /* if unsigned char cmp with lit, just compare */
3987 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
3989 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3992 emit2 ("xor a,!immedbyte", 0x80);
3993 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
3996 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3998 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4000 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4001 // Pull left into DE and right into HL
4002 aopGet (AOP(left), LSB, FALSE);
4005 aopGet (AOP(right), LSB, FALSE);
4009 if (size == 0 && sign)
4011 // Highest byte when signed needs the bits flipped
4014 emit2 ("ld a,(de)");
4015 emit2 ("xor !immedbyte", 0x80);
4017 emit2 ("ld a,(hl)");
4018 emit2 ("xor !immedbyte", 0x80);
4022 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4026 emit2 ("ld a,(de)");
4027 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4037 spillPair (PAIR_HL);
4039 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4041 setupPair (PAIR_HL, AOP (left), 0);
4042 aopGet (AOP(right), LSB, FALSE);
4046 if (size == 0 && sign)
4048 // Highest byte when signed needs the bits flipped
4051 emit2 ("ld a,(hl)");
4052 emit2 ("xor !immedbyte", 0x80);
4054 emit2 ("ld a,%d(iy)", offset);
4055 emit2 ("xor !immedbyte", 0x80);
4059 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4063 emit2 ("ld a,(hl)");
4064 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4073 spillPair (PAIR_HL);
4074 spillPair (PAIR_IY);
4078 if (AOP_TYPE (right) == AOP_LIT)
4080 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4081 /* optimize if(x < 0) or if(x >= 0) */
4086 /* No sign so it's always false */
4091 /* Just load in the top most bit */
4092 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4093 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4095 genIfxJump (ifx, "7");
4107 /* First setup h and l contaning the top most bytes XORed */
4108 bool fDidXor = FALSE;
4109 if (AOP_TYPE (left) == AOP_LIT)
4111 unsigned long lit = (unsigned long)
4112 floatFromVal (AOP (left)->aopu.aop_lit);
4113 emit2 ("ld %s,!immedbyte", _fTmp[0],
4114 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4118 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4119 emit2 ("xor a,!immedbyte", 0x80);
4120 emit2 ("ld %s,a", _fTmp[0]);
4123 if (AOP_TYPE (right) == AOP_LIT)
4125 unsigned long lit = (unsigned long)
4126 floatFromVal (AOP (right)->aopu.aop_lit);
4127 emit2 ("ld %s,!immedbyte", _fTmp[1],
4128 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4132 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4133 emit2 ("xor a,!immedbyte", 0x80);
4134 emit2 ("ld %s,a", _fTmp[1]);
4140 /* Do a long subtract */
4143 _moveA (aopGet (AOP (left), offset, FALSE));
4145 if (sign && size == 0)
4147 emit2 ("ld a,%s", _fTmp[0]);
4148 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4152 /* Subtract through, propagating the carry */
4153 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4161 /** Generic compare for > or <
4164 genCmp (operand * left, operand * right,
4165 operand * result, iCode * ifx, int sign)
4167 int size, offset = 0;
4168 unsigned long lit = 0L;
4169 bool swap_sense = FALSE;
4171 /* if left & right are bit variables */
4172 if (AOP_TYPE (left) == AOP_CRY &&
4173 AOP_TYPE (right) == AOP_CRY)
4175 /* Cant happen on the Z80 */
4176 wassertl (0, "Tried to compare two bits");
4180 /* Do a long subtract of right from left. */
4181 size = max (AOP_SIZE (left), AOP_SIZE (right));
4183 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4185 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4186 // Pull left into DE and right into HL
4187 aopGet (AOP(left), LSB, FALSE);
4190 aopGet (AOP(right), LSB, FALSE);
4194 emit2 ("ld a,(de)");
4195 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4204 spillPair (PAIR_HL);
4208 if (AOP_TYPE (right) == AOP_LIT)
4210 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4211 /* optimize if(x < 0) or if(x >= 0) */
4216 /* No sign so it's always false */
4221 /* Just load in the top most bit */
4222 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4223 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4225 genIfxJump (ifx, "7");
4236 genIfxJump (ifx, swap_sense ? "c" : "nc");
4247 _moveA (aopGet (AOP (left), offset, FALSE));
4248 /* Subtract through, propagating the carry */
4249 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4255 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4259 /* Shift the sign bit up into carry */
4262 outBitCLong (result, swap_sense);
4266 /* if the result is used in the next
4267 ifx conditional branch then generate
4268 code a little differently */
4276 genIfxJump (ifx, swap_sense ? "nc" : "c");
4280 genIfxJump (ifx, swap_sense ? "p" : "m");
4285 genIfxJump (ifx, swap_sense ? "nc" : "c");
4292 /* Shift the sign bit up into carry */
4295 outBitCLong (result, swap_sense);
4297 /* leave the result in acc */
4301 /*-----------------------------------------------------------------*/
4302 /* genCmpGt :- greater than comparison */
4303 /*-----------------------------------------------------------------*/
4305 genCmpGt (iCode * ic, iCode * ifx)
4307 operand *left, *right, *result;
4308 sym_link *letype, *retype;
4311 left = IC_LEFT (ic);
4312 right = IC_RIGHT (ic);
4313 result = IC_RESULT (ic);
4315 letype = getSpec (operandType (left));
4316 retype = getSpec (operandType (right));
4317 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4318 /* assign the amsops */
4319 aopOp (left, ic, FALSE, FALSE);
4320 aopOp (right, ic, FALSE, FALSE);
4321 aopOp (result, ic, TRUE, FALSE);
4323 genCmp (right, left, result, ifx, sign);
4325 freeAsmop (left, NULL, ic);
4326 freeAsmop (right, NULL, ic);
4327 freeAsmop (result, NULL, ic);
4330 /*-----------------------------------------------------------------*/
4331 /* genCmpLt - less than comparisons */
4332 /*-----------------------------------------------------------------*/
4334 genCmpLt (iCode * ic, iCode * ifx)
4336 operand *left, *right, *result;
4337 sym_link *letype, *retype;
4340 left = IC_LEFT (ic);
4341 right = IC_RIGHT (ic);
4342 result = IC_RESULT (ic);
4344 letype = getSpec (operandType (left));
4345 retype = getSpec (operandType (right));
4346 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4348 /* assign the amsops */
4349 aopOp (left, ic, FALSE, FALSE);
4350 aopOp (right, ic, FALSE, FALSE);
4351 aopOp (result, ic, TRUE, FALSE);
4353 genCmp (left, right, result, ifx, sign);
4355 freeAsmop (left, NULL, ic);
4356 freeAsmop (right, NULL, ic);
4357 freeAsmop (result, NULL, ic);
4360 /*-----------------------------------------------------------------*/
4361 /* gencjneshort - compare and jump if not equal */
4362 /*-----------------------------------------------------------------*/
4364 gencjneshort (operand * left, operand * right, symbol * lbl)
4366 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4368 unsigned long lit = 0L;
4370 /* Swap the left and right if it makes the computation easier */
4371 if (AOP_TYPE (left) == AOP_LIT)
4378 if (AOP_TYPE (right) == AOP_LIT)
4380 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4383 /* if the right side is a literal then anything goes */
4384 if (AOP_TYPE (right) == AOP_LIT &&
4385 AOP_TYPE (left) != AOP_DIR)
4389 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4394 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4401 emit2 ("jp nz,!tlabel", lbl->key + 100);
4407 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4408 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
4411 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
4412 emit2 ("jp nz,!tlabel", lbl->key + 100);
4417 /* if the right side is in a register or in direct space or
4418 if the left is a pointer register & right is not */
4419 else if (AOP_TYPE (right) == AOP_REG ||
4420 AOP_TYPE (right) == AOP_DIR ||
4421 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
4425 _moveA (aopGet (AOP (left), offset, FALSE));
4426 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
4427 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4429 emit2 ("jp nz,!tlabel", lbl->key + 100);
4432 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4433 emit2 ("jp nz,!tlabel", lbl->key + 100);
4440 /* right is a pointer reg need both a & b */
4441 /* PENDING: is this required? */
4444 _moveA (aopGet (AOP (right), offset, FALSE));
4445 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
4446 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
4452 /*-----------------------------------------------------------------*/
4453 /* gencjne - compare and jump if not equal */
4454 /*-----------------------------------------------------------------*/
4456 gencjne (operand * left, operand * right, symbol * lbl)
4458 symbol *tlbl = newiTempLabel (NULL);
4460 gencjneshort (left, right, lbl);
4463 emit2 ("ld a,!one");
4464 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4465 emitLabel (lbl->key + 100);
4467 emitLabel (tlbl->key + 100);
4470 /*-----------------------------------------------------------------*/
4471 /* genCmpEq - generates code for equal to */
4472 /*-----------------------------------------------------------------*/
4474 genCmpEq (iCode * ic, iCode * ifx)
4476 operand *left, *right, *result;
4478 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4479 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4480 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4482 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4484 /* Swap operands if it makes the operation easier. ie if:
4485 1. Left is a literal.
4487 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4489 operand *t = IC_RIGHT (ic);
4490 IC_RIGHT (ic) = IC_LEFT (ic);
4494 if (ifx && !AOP_SIZE (result))
4497 /* if they are both bit variables */
4498 if (AOP_TYPE (left) == AOP_CRY &&
4499 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4501 wassertl (0, "Tried to compare two bits");
4505 tlbl = newiTempLabel (NULL);
4506 gencjneshort (left, right, tlbl);
4509 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4510 emitLabel (tlbl->key + 100);
4514 /* PENDING: do this better */
4515 symbol *lbl = newiTempLabel (NULL);
4516 emit2 ("!shortjp !tlabel", lbl->key + 100);
4517 emitLabel (tlbl->key + 100);
4518 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4519 emitLabel (lbl->key + 100);
4522 /* mark the icode as generated */
4527 /* if they are both bit variables */
4528 if (AOP_TYPE (left) == AOP_CRY &&
4529 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4531 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4537 gencjne (left, right, newiTempLabel (NULL));
4538 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4545 genIfxJump (ifx, "a");
4548 /* if the result is used in an arithmetic operation
4549 then put the result in place */
4550 if (AOP_TYPE (result) != AOP_CRY)
4555 /* leave the result in acc */
4559 freeAsmop (left, NULL, ic);
4560 freeAsmop (right, NULL, ic);
4561 freeAsmop (result, NULL, ic);
4564 /*-----------------------------------------------------------------*/
4565 /* ifxForOp - returns the icode containing the ifx for operand */
4566 /*-----------------------------------------------------------------*/
4568 ifxForOp (operand * op, iCode * ic)
4570 /* if true symbol then needs to be assigned */
4571 if (IS_TRUE_SYMOP (op))
4574 /* if this has register type condition and
4575 the next instruction is ifx with the same operand
4576 and live to of the operand is upto the ifx only then */
4578 ic->next->op == IFX &&
4579 IC_COND (ic->next)->key == op->key &&
4580 OP_SYMBOL (op)->liveTo <= ic->next->seq)
4586 /*-----------------------------------------------------------------*/
4587 /* genAndOp - for && operation */
4588 /*-----------------------------------------------------------------*/
4590 genAndOp (iCode * ic)
4592 operand *left, *right, *result;
4595 /* note here that && operations that are in an if statement are
4596 taken away by backPatchLabels only those used in arthmetic
4597 operations remain */
4598 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4599 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4600 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4602 /* if both are bit variables */
4603 if (AOP_TYPE (left) == AOP_CRY &&
4604 AOP_TYPE (right) == AOP_CRY)
4606 wassertl (0, "Tried to and two bits");
4610 tlbl = newiTempLabel (NULL);
4612 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
4614 emitLabel (tlbl->key + 100);
4618 freeAsmop (left, NULL, ic);
4619 freeAsmop (right, NULL, ic);
4620 freeAsmop (result, NULL, ic);
4623 /*-----------------------------------------------------------------*/
4624 /* genOrOp - for || operation */
4625 /*-----------------------------------------------------------------*/
4627 genOrOp (iCode * ic)
4629 operand *left, *right, *result;
4632 /* note here that || operations that are in an
4633 if statement are taken away by backPatchLabels
4634 only those used in arthmetic operations remain */
4635 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4636 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4637 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4639 /* if both are bit variables */
4640 if (AOP_TYPE (left) == AOP_CRY &&
4641 AOP_TYPE (right) == AOP_CRY)
4643 wassertl (0, "Tried to OR two bits");
4647 tlbl = newiTempLabel (NULL);
4649 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4651 emitLabel (tlbl->key + 100);
4655 freeAsmop (left, NULL, ic);
4656 freeAsmop (right, NULL, ic);
4657 freeAsmop (result, NULL, ic);
4660 /*-----------------------------------------------------------------*/
4661 /* isLiteralBit - test if lit == 2^n */
4662 /*-----------------------------------------------------------------*/
4664 isLiteralBit (unsigned long lit)
4666 unsigned long pw[32] =
4667 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
4668 0x100L, 0x200L, 0x400L, 0x800L,
4669 0x1000L, 0x2000L, 0x4000L, 0x8000L,
4670 0x10000L, 0x20000L, 0x40000L, 0x80000L,
4671 0x100000L, 0x200000L, 0x400000L, 0x800000L,
4672 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
4673 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
4676 for (idx = 0; idx < 32; idx++)
4682 /*-----------------------------------------------------------------*/
4683 /* jmpTrueOrFalse - */
4684 /*-----------------------------------------------------------------*/
4686 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
4688 // ugly but optimized by peephole
4691 symbol *nlbl = newiTempLabel (NULL);
4692 emit2 ("jp !tlabel", nlbl->key + 100);
4693 emitLabel (tlbl->key + 100);
4694 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
4695 emitLabel (nlbl->key + 100);
4699 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
4700 emitLabel (tlbl->key + 100);
4705 /*-----------------------------------------------------------------*/
4706 /* genAnd - code for and */
4707 /*-----------------------------------------------------------------*/
4709 genAnd (iCode * ic, iCode * ifx)
4711 operand *left, *right, *result;
4712 int size, offset = 0;
4713 unsigned long lit = 0L;
4716 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4717 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4718 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4720 /* if left is a literal & right is not then exchange them */
4721 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4722 AOP_NEEDSACC (left))
4724 operand *tmp = right;
4729 /* if result = right then exchange them */
4730 if (sameRegs (AOP (result), AOP (right)))
4732 operand *tmp = right;
4737 /* if right is bit then exchange them */
4738 if (AOP_TYPE (right) == AOP_CRY &&
4739 AOP_TYPE (left) != AOP_CRY)
4741 operand *tmp = right;
4745 if (AOP_TYPE (right) == AOP_LIT)
4746 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4748 size = AOP_SIZE (result);
4750 if (AOP_TYPE (left) == AOP_CRY)
4752 wassertl (0, "Tried to perform an AND with a bit as an operand");
4756 // if(val & 0xZZ) - size = 0, ifx != FALSE -
4757 // bit = val & 0xZZ - size = 1, ifx = FALSE -
4758 if ((AOP_TYPE (right) == AOP_LIT) &&
4759 (AOP_TYPE (result) == AOP_CRY) &&
4760 (AOP_TYPE (left) != AOP_CRY))
4762 symbol *tlbl = newiTempLabel (NULL);
4763 int sizel = AOP_SIZE (left);
4766 /* PENDING: Test case for this. */
4771 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
4773 _moveA (aopGet (AOP (left), offset, FALSE));
4774 if (bytelit != 0x0FFL)
4776 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4783 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4787 // bit = left & literal
4791 emit2 ("!tlabeldef", tlbl->key + 100);
4793 // if(left & literal)
4798 jmpTrueOrFalse (ifx, tlbl);
4806 /* if left is same as result */
4807 if (sameRegs (AOP (result), AOP (left)))
4809 for (; size--; offset++)
4811 if (AOP_TYPE (right) == AOP_LIT)
4813 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4818 aopPut (AOP (result), "!zero", offset);
4821 _moveA (aopGet (AOP (left), offset, FALSE));
4823 aopGet (AOP (right), offset, FALSE));
4824 aopPut (AOP (left), "a", offset);
4831 if (AOP_TYPE (left) == AOP_ACC)
4833 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
4837 _moveA (aopGet (AOP (left), offset, FALSE));
4839 aopGet (AOP (right), offset, FALSE));
4840 aopPut (AOP (left), "a", offset);
4847 // left & result in different registers
4848 if (AOP_TYPE (result) == AOP_CRY)
4850 wassertl (0, "Tried to AND where the result is in carry");
4854 for (; (size--); offset++)
4857 // result = left & right
4858 if (AOP_TYPE (right) == AOP_LIT)
4860 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4862 aopPut (AOP (result),
4863 aopGet (AOP (left), offset, FALSE),
4867 else if (bytelit == 0)
4869 aopPut (AOP (result), "!zero", offset);
4873 // faster than result <- left, anl result,right
4874 // and better if result is SFR
4875 if (AOP_TYPE (left) == AOP_ACC)
4876 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4879 _moveA (aopGet (AOP (left), offset, FALSE));
4881 aopGet (AOP (right), offset, FALSE));
4883 aopPut (AOP (result), "a", offset);
4890 freeAsmop (left, NULL, ic);
4891 freeAsmop (right, NULL, ic);
4892 freeAsmop (result, NULL, ic);
4895 /*-----------------------------------------------------------------*/
4896 /* genOr - code for or */
4897 /*-----------------------------------------------------------------*/
4899 genOr (iCode * ic, iCode * ifx)
4901 operand *left, *right, *result;
4902 int size, offset = 0;
4903 unsigned long lit = 0L;
4906 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4907 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4908 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4910 /* if left is a literal & right is not then exchange them */
4911 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4912 AOP_NEEDSACC (left))
4914 operand *tmp = right;
4919 /* if result = right then exchange them */
4920 if (sameRegs (AOP (result), AOP (right)))
4922 operand *tmp = right;
4927 /* if right is bit then exchange them */
4928 if (AOP_TYPE (right) == AOP_CRY &&
4929 AOP_TYPE (left) != AOP_CRY)
4931 operand *tmp = right;
4935 if (AOP_TYPE (right) == AOP_LIT)
4936 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4938 size = AOP_SIZE (result);
4940 if (AOP_TYPE (left) == AOP_CRY)
4942 wassertl (0, "Tried to OR where left is a bit");
4946 // if(val | 0xZZ) - size = 0, ifx != FALSE -
4947 // bit = val | 0xZZ - size = 1, ifx = FALSE -
4948 if ((AOP_TYPE (right) == AOP_LIT) &&
4949 (AOP_TYPE (result) == AOP_CRY) &&
4950 (AOP_TYPE (left) != AOP_CRY))
4952 symbol *tlbl = newiTempLabel (NULL);
4953 int sizel = AOP_SIZE (left);
4957 wassertl (0, "Result is assigned to a bit");
4959 /* PENDING: Modeled after the AND code which is inefficent. */
4962 bytelit = (lit >> (offset * 8)) & 0x0FFL;
4964 _moveA (aopGet (AOP (left), offset, FALSE));
4965 /* OR with any literal is the same as OR with itself. */
4967 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4973 jmpTrueOrFalse (ifx, tlbl);
4978 /* if left is same as result */
4979 if (sameRegs (AOP (result), AOP (left)))
4981 for (; size--; offset++)
4983 if (AOP_TYPE (right) == AOP_LIT)
4985 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4989 _moveA (aopGet (AOP (left), offset, FALSE));
4991 aopGet (AOP (right), offset, FALSE));
4992 aopPut (AOP (result), "a", offset);
4997 if (AOP_TYPE (left) == AOP_ACC)
4998 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5001 _moveA (aopGet (AOP (left), offset, FALSE));
5003 aopGet (AOP (right), offset, FALSE));
5004 aopPut (AOP (result), "a", offset);
5011 // left & result in different registers
5012 if (AOP_TYPE (result) == AOP_CRY)
5014 wassertl (0, "Result of OR is in a bit");
5017 for (; (size--); offset++)
5020 // result = left & right
5021 if (AOP_TYPE (right) == AOP_LIT)
5023 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5025 aopPut (AOP (result),
5026 aopGet (AOP (left), offset, FALSE),
5031 // faster than result <- left, anl result,right
5032 // and better if result is SFR
5033 if (AOP_TYPE (left) == AOP_ACC)
5034 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5037 _moveA (aopGet (AOP (left), offset, FALSE));
5039 aopGet (AOP (right), offset, FALSE));
5041 aopPut (AOP (result), "a", offset);
5042 /* PENDING: something weird is going on here. Add exception. */
5043 if (AOP_TYPE (result) == AOP_ACC)
5049 freeAsmop (left, NULL, ic);
5050 freeAsmop (right, NULL, ic);
5051 freeAsmop (result, NULL, ic);
5054 /*-----------------------------------------------------------------*/
5055 /* genXor - code for xclusive or */
5056 /*-----------------------------------------------------------------*/
5058 genXor (iCode * ic, iCode * ifx)
5060 operand *left, *right, *result;
5061 int size, offset = 0;
5062 unsigned long lit = 0L;
5064 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5065 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5066 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5068 /* if left is a literal & right is not then exchange them */
5069 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5070 AOP_NEEDSACC (left))
5072 operand *tmp = right;
5077 /* if result = right then exchange them */
5078 if (sameRegs (AOP (result), AOP (right)))
5080 operand *tmp = right;
5085 /* if right is bit then exchange them */
5086 if (AOP_TYPE (right) == AOP_CRY &&
5087 AOP_TYPE (left) != AOP_CRY)
5089 operand *tmp = right;
5093 if (AOP_TYPE (right) == AOP_LIT)
5094 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5096 size = AOP_SIZE (result);
5098 if (AOP_TYPE (left) == AOP_CRY)
5100 wassertl (0, "Tried to XOR a bit");
5104 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5105 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5106 if ((AOP_TYPE (right) == AOP_LIT) &&
5107 (AOP_TYPE (result) == AOP_CRY) &&
5108 (AOP_TYPE (left) != AOP_CRY))
5110 symbol *tlbl = newiTempLabel (NULL);
5111 int sizel = AOP_SIZE (left);
5115 /* PENDING: Test case for this. */
5116 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5120 _moveA (aopGet (AOP (left), offset, FALSE));
5121 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5122 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5127 jmpTrueOrFalse (ifx, tlbl);
5131 wassertl (0, "Result of XOR was destined for a bit");
5136 /* if left is same as result */
5137 if (sameRegs (AOP (result), AOP (left)))
5139 for (; size--; offset++)
5141 if (AOP_TYPE (right) == AOP_LIT)
5143 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5147 _moveA (aopGet (AOP (right), offset, FALSE));
5149 aopGet (AOP (left), offset, FALSE));
5150 aopPut (AOP (result), "a", offset);
5155 if (AOP_TYPE (left) == AOP_ACC)
5157 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5161 _moveA (aopGet (AOP (right), offset, FALSE));
5163 aopGet (AOP (left), offset, FALSE));
5164 aopPut (AOP (result), "a", 0);
5171 // left & result in different registers
5172 if (AOP_TYPE (result) == AOP_CRY)
5174 wassertl (0, "Result of XOR is in a bit");
5177 for (; (size--); offset++)
5180 // result = left & right
5181 if (AOP_TYPE (right) == AOP_LIT)
5183 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5185 aopPut (AOP (result),
5186 aopGet (AOP (left), offset, FALSE),
5191 // faster than result <- left, anl result,right
5192 // and better if result is SFR
5193 if (AOP_TYPE (left) == AOP_ACC)
5195 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5199 _moveA (aopGet (AOP (right), offset, FALSE));
5201 aopGet (AOP (left), offset, FALSE));
5203 aopPut (AOP (result), "a", offset);
5208 freeAsmop (left, NULL, ic);
5209 freeAsmop (right, NULL, ic);
5210 freeAsmop (result, NULL, ic);
5213 /*-----------------------------------------------------------------*/
5214 /* genInline - write the inline code out */
5215 /*-----------------------------------------------------------------*/
5217 genInline (iCode * ic)
5219 char *buffer, *bp, *bp1;
5221 _G.lines.isInline += (!options.asmpeep);
5223 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5224 strcpy (buffer, IC_INLINE (ic));
5226 /* emit each line as a code */
5251 _G.lines.isInline -= (!options.asmpeep);
5255 /*-----------------------------------------------------------------*/
5256 /* genRRC - rotate right with carry */
5257 /*-----------------------------------------------------------------*/
5264 /*-----------------------------------------------------------------*/
5265 /* genRLC - generate code for rotate left with carry */
5266 /*-----------------------------------------------------------------*/
5273 /*-----------------------------------------------------------------*/
5274 /* genGetHbit - generates code get highest order bit */
5275 /*-----------------------------------------------------------------*/
5277 genGetHbit (iCode * ic)
5279 operand *left, *result;
5280 left = IC_LEFT (ic);
5281 result = IC_RESULT (ic);
5283 aopOp (left, ic, FALSE, FALSE);
5284 aopOp (result, ic, FALSE, FALSE);
5286 /* get the highest order byte into a */
5287 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5289 if (AOP_TYPE (result) == AOP_CRY)
5297 emit2 ("and a,!one");
5302 freeAsmop (left, NULL, ic);
5303 freeAsmop (result, NULL, ic);
5307 emitRsh2 (asmop *aop, int size, int is_signed)
5313 const char *l = aopGet (aop, size, FALSE);
5316 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5326 /*-----------------------------------------------------------------*/
5327 /* shiftR2Left2Result - shift right two bytes from left to result */
5328 /*-----------------------------------------------------------------*/
5330 shiftR2Left2Result (operand * left, int offl,
5331 operand * result, int offr,
5332 int shCount, int is_signed)
5335 symbol *tlbl, *tlbl1;
5337 movLeft2Result (left, offl, result, offr, 0);
5338 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5340 /* if (AOP(result)->type == AOP_REG) { */
5342 tlbl = newiTempLabel (NULL);
5343 tlbl1 = newiTempLabel (NULL);
5345 /* Left is already in result - so now do the shift */
5350 emitRsh2 (AOP (result), size, is_signed);
5355 emit2 ("ld a,!immedbyte+1", shCount);
5356 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5357 emitLabel (tlbl->key + 100);
5359 emitRsh2 (AOP (result), size, is_signed);
5361 emitLabel (tlbl1->key + 100);
5363 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5367 /*-----------------------------------------------------------------*/
5368 /* shiftL2Left2Result - shift left two bytes from left to result */
5369 /*-----------------------------------------------------------------*/
5371 shiftL2Left2Result (operand * left, int offl,
5372 operand * result, int offr, int shCount)
5374 if (sameRegs (AOP (result), AOP (left)) &&
5375 ((offl + MSB16) == offr))
5381 /* Copy left into result */
5382 movLeft2Result (left, offl, result, offr, 0);
5383 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5386 if (getPairId (AOP (result)) == PAIR_HL)
5390 emit2 ("add hl,hl");
5397 symbol *tlbl, *tlbl1;
5400 tlbl = newiTempLabel (NULL);
5401 tlbl1 = newiTempLabel (NULL);
5403 if (AOP (result)->type == AOP_REG)
5407 for (offset = 0; offset < size; offset++)
5409 l = aopGet (AOP (result), offset, FALSE);
5413 emit2 ("sla %s", l);
5424 /* Left is already in result - so now do the shift */
5427 emit2 ("ld a,!immedbyte+1", shCount);
5428 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5429 emitLabel (tlbl->key + 100);
5434 l = aopGet (AOP (result), offset, FALSE);
5438 emit2 ("sla %s", l);
5449 emitLabel (tlbl1->key + 100);
5451 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5457 /*-----------------------------------------------------------------*/
5458 /* AccRol - rotate left accumulator by known count */
5459 /*-----------------------------------------------------------------*/
5461 AccRol (int shCount)
5463 shCount &= 0x0007; // shCount : 0..7
5502 /*-----------------------------------------------------------------*/
5503 /* AccLsh - left shift accumulator by known count */
5504 /*-----------------------------------------------------------------*/
5506 AccLsh (int shCount)
5508 static const unsigned char SLMask[] =
5510 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5519 else if (shCount == 2)
5526 /* rotate left accumulator */
5528 /* and kill the lower order bits */
5529 emit2 ("and a,!immedbyte", SLMask[shCount]);
5534 /*-----------------------------------------------------------------*/
5535 /* shiftL1Left2Result - shift left one byte from left to result */
5536 /*-----------------------------------------------------------------*/
5538 shiftL1Left2Result (operand * left, int offl,
5539 operand * result, int offr, int shCount)
5542 l = aopGet (AOP (left), offl, FALSE);
5544 /* shift left accumulator */
5546 aopPut (AOP (result), "a", offr);
5550 /*-----------------------------------------------------------------*/
5551 /* genlshTwo - left shift two bytes by known amount != 0 */
5552 /*-----------------------------------------------------------------*/
5554 genlshTwo (operand * result, operand * left, int shCount)
5556 int size = AOP_SIZE (result);
5558 wassert (size == 2);
5560 /* if shCount >= 8 */
5568 movLeft2Result (left, LSB, result, MSB16, 0);
5569 aopPut (AOP (result), "!zero", 0);
5570 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
5574 movLeft2Result (left, LSB, result, MSB16, 0);
5575 aopPut (AOP (result), "!zero", 0);
5580 aopPut (AOP (result), "!zero", LSB);
5583 /* 1 <= shCount <= 7 */
5592 shiftL2Left2Result (left, LSB, result, LSB, shCount);
5597 /*-----------------------------------------------------------------*/
5598 /* genlshOne - left shift a one byte quantity by known count */
5599 /*-----------------------------------------------------------------*/
5601 genlshOne (operand * result, operand * left, int shCount)
5603 shiftL1Left2Result (left, LSB, result, LSB, shCount);
5606 /*-----------------------------------------------------------------*/
5607 /* genLeftShiftLiteral - left shifting by known count */
5608 /*-----------------------------------------------------------------*/
5610 genLeftShiftLiteral (operand * left,
5615 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5618 freeAsmop (right, NULL, ic);
5620 aopOp (left, ic, FALSE, FALSE);
5621 aopOp (result, ic, FALSE, FALSE);
5623 size = getSize (operandType (result));
5625 /* I suppose that the left size >= result size */
5631 else if (shCount >= (size * 8))
5635 aopPut (AOP (result), "!zero", size);
5643 genlshOne (result, left, shCount);
5646 genlshTwo (result, left, shCount);
5649 wassertl (0, "Shifting of longs is currently unsupported");
5655 freeAsmop (left, NULL, ic);
5656 freeAsmop (result, NULL, ic);
5659 /*-----------------------------------------------------------------*/
5660 /* genLeftShift - generates code for left shifting */
5661 /*-----------------------------------------------------------------*/
5663 genLeftShift (iCode * ic)
5667 symbol *tlbl, *tlbl1;
5668 operand *left, *right, *result;
5670 right = IC_RIGHT (ic);
5671 left = IC_LEFT (ic);
5672 result = IC_RESULT (ic);
5674 aopOp (right, ic, FALSE, FALSE);
5676 /* if the shift count is known then do it
5677 as efficiently as possible */
5678 if (AOP_TYPE (right) == AOP_LIT)
5680 genLeftShiftLiteral (left, right, result, ic);
5684 /* shift count is unknown then we have to form a loop get the loop
5685 count in B : Note: we take only the lower order byte since
5686 shifting more that 32 bits make no sense anyway, ( the largest
5687 size of an object can be only 32 bits ) */
5688 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5690 freeAsmop (right, NULL, ic);
5691 aopOp (left, ic, FALSE, FALSE);
5692 aopOp (result, ic, FALSE, FALSE);
5694 /* now move the left to the result if they are not the
5697 if (!sameRegs (AOP (left), AOP (result)))
5700 size = AOP_SIZE (result);
5704 l = aopGet (AOP (left), offset, FALSE);
5705 aopPut (AOP (result), l, offset);
5710 tlbl = newiTempLabel (NULL);
5711 size = AOP_SIZE (result);
5713 tlbl1 = newiTempLabel (NULL);
5715 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5716 emitLabel (tlbl->key + 100);
5717 l = aopGet (AOP (result), offset, FALSE);
5721 l = aopGet (AOP (result), offset, FALSE);
5725 emit2 ("sla %s", l);
5733 emitLabel (tlbl1->key + 100);
5735 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5737 freeAsmop (left, NULL, ic);
5738 freeAsmop (result, NULL, ic);
5741 /*-----------------------------------------------------------------*/
5742 /* genrshOne - left shift two bytes by known amount != 0 */
5743 /*-----------------------------------------------------------------*/
5745 genrshOne (operand * result, operand * left, int shCount, int is_signed)
5748 int size = AOP_SIZE (result);
5751 wassert (size == 1);
5752 wassert (shCount < 8);
5754 l = aopGet (AOP (left), 0, FALSE);
5756 if (AOP (result)->type == AOP_REG)
5758 aopPut (AOP (result), l, 0);
5759 l = aopGet (AOP (result), 0, FALSE);
5762 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5770 emit2 ("%s a", is_signed ? "sra" : "srl");
5772 aopPut (AOP (result), "a", 0);
5776 /*-----------------------------------------------------------------*/
5777 /* AccRsh - right shift accumulator by known count */
5778 /*-----------------------------------------------------------------*/
5780 AccRsh (int shCount)
5782 static const unsigned char SRMask[] =
5784 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
5789 /* rotate right accumulator */
5790 AccRol (8 - shCount);
5791 /* and kill the higher order bits */
5792 emit2 ("and a,!immedbyte", SRMask[shCount]);
5796 /*-----------------------------------------------------------------*/
5797 /* shiftR1Left2Result - shift right one byte from left to result */
5798 /*-----------------------------------------------------------------*/
5800 shiftR1Left2Result (operand * left, int offl,
5801 operand * result, int offr,
5802 int shCount, int sign)
5804 _moveA (aopGet (AOP (left), offl, FALSE));
5809 emit2 ("%s a", sign ? "sra" : "srl");
5816 aopPut (AOP (result), "a", offr);
5819 /*-----------------------------------------------------------------*/
5820 /* genrshTwo - right shift two bytes by known amount != 0 */
5821 /*-----------------------------------------------------------------*/
5823 genrshTwo (operand * result, operand * left,
5824 int shCount, int sign)
5826 /* if shCount >= 8 */
5832 shiftR1Left2Result (left, MSB16, result, LSB,
5837 movLeft2Result (left, MSB16, result, LSB, sign);
5841 /* Sign extend the result */
5842 _moveA(aopGet (AOP (result), 0, FALSE));
5846 aopPut (AOP (result), ACC_NAME, MSB16);
5850 aopPut (AOP (result), "!zero", 1);
5853 /* 1 <= shCount <= 7 */
5856 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
5860 /*-----------------------------------------------------------------*/
5861 /* genRightShiftLiteral - left shifting by known count */
5862 /*-----------------------------------------------------------------*/
5864 genRightShiftLiteral (operand * left,
5870 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5873 freeAsmop (right, NULL, ic);
5875 aopOp (left, ic, FALSE, FALSE);
5876 aopOp (result, ic, FALSE, FALSE);
5878 size = getSize (operandType (result));
5880 /* I suppose that the left size >= result size */
5886 else if (shCount >= (size * 8))
5888 aopPut (AOP (result), "!zero", size);
5894 genrshOne (result, left, shCount, sign);
5897 genrshTwo (result, left, shCount, sign);
5900 wassertl (0, "Asked to shift right a long which should be a function call");
5903 wassertl (0, "Entered default case in right shift delegate");
5906 freeAsmop (left, NULL, ic);
5907 freeAsmop (result, NULL, ic);
5910 /*-----------------------------------------------------------------*/
5911 /* genRightShift - generate code for right shifting */
5912 /*-----------------------------------------------------------------*/
5914 genRightShift (iCode * ic)
5916 operand *right, *left, *result;
5918 int size, offset, first = 1;
5922 symbol *tlbl, *tlbl1;
5924 /* if signed then we do it the hard way preserve the
5925 sign bit moving it inwards */
5926 retype = getSpec (operandType (IC_RESULT (ic)));
5928 is_signed = !SPEC_USIGN (retype);
5930 /* signed & unsigned types are treated the same : i.e. the
5931 signed is NOT propagated inwards : quoting from the
5932 ANSI - standard : "for E1 >> E2, is equivalent to division
5933 by 2**E2 if unsigned or if it has a non-negative value,
5934 otherwise the result is implementation defined ", MY definition
5935 is that the sign does not get propagated */
5937 right = IC_RIGHT (ic);
5938 left = IC_LEFT (ic);
5939 result = IC_RESULT (ic);
5941 aopOp (right, ic, FALSE, FALSE);
5943 /* if the shift count is known then do it
5944 as efficiently as possible */
5945 if (AOP_TYPE (right) == AOP_LIT)
5947 genRightShiftLiteral (left, right, result, ic, is_signed);
5951 aopOp (left, ic, FALSE, FALSE);
5952 aopOp (result, ic, FALSE, FALSE);
5954 /* now move the left to the result if they are not the
5956 if (!sameRegs (AOP (left), AOP (result)) &&
5957 AOP_SIZE (result) > 1)
5960 size = AOP_SIZE (result);
5964 l = aopGet (AOP (left), offset, FALSE);
5965 aopPut (AOP (result), l, offset);
5970 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5972 freeAsmop (right, NULL, ic);
5974 tlbl = newiTempLabel (NULL);
5975 tlbl1 = newiTempLabel (NULL);
5976 size = AOP_SIZE (result);
5979 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5980 emitLabel (tlbl->key + 100);
5983 l = aopGet (AOP (result), offset--, FALSE);
5986 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5994 emitLabel (tlbl1->key + 100);
5996 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5998 freeAsmop (left, NULL, ic);
5999 freeAsmop (result, NULL, ic);
6002 /*-----------------------------------------------------------------*/
6003 /* genGenPointerGet - get value from generic pointer space */
6004 /*-----------------------------------------------------------------*/
6006 genGenPointerGet (operand * left,
6007 operand * result, iCode * ic)
6010 sym_link *retype = getSpec (operandType (result));
6016 aopOp (left, ic, FALSE, FALSE);
6017 aopOp (result, ic, FALSE, FALSE);
6019 size = AOP_SIZE (result);
6021 if (isPair (AOP (left)) && size == 1)
6024 if (isPtrPair (AOP (left)))
6026 tsprintf (buffer, "!*pair", getPairName (AOP (left)));
6027 aopPut (AOP (result), buffer, 0);
6031 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6032 aopPut (AOP (result), "a", 0);
6034 freeAsmop (left, NULL, ic);
6038 if (getPairId (AOP (left)) == PAIR_IY)
6045 tsprintf (at, "!*iyx", offset);
6046 aopPut (AOP (result), at, offset);
6050 freeAsmop (left, NULL, ic);
6054 /* For now we always load into IY */
6055 /* if this is remateriazable */
6056 fetchPair (pair, AOP (left));
6058 /* if bit then unpack */
6059 if (IS_BITVAR (retype))
6063 else if (getPairId (AOP (result)) == PAIR_HL)
6065 wassertl (size == 2, "HL must be of size 2");
6066 emit2 ("ld a,!*hl");
6068 emit2 ("ld h,!*hl");
6070 spillPair (PAIR_HL);
6072 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6074 size = AOP_SIZE (result);
6079 /* PENDING: make this better */
6080 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6082 aopPut (AOP (result), "!*hl", offset++);
6086 emit2 ("ld a,!*pair", _pairs[pair].name);
6087 aopPut (AOP (result), "a", offset++);
6091 emit2 ("inc %s", _pairs[pair].name);
6092 _G.pairs[pair].offset++;
6095 /* Fixup HL back down */
6096 for (size = AOP_SIZE (result)-1; size; size--)
6098 emit2 ("dec %s", _pairs[pair].name);
6103 size = AOP_SIZE (result);
6108 /* PENDING: make this better */
6110 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6112 aopPut (AOP (result), "!*hl", offset++);
6116 emit2 ("ld a,!*pair", _pairs[pair].name);
6117 aopPut (AOP (result), "a", offset++);
6121 emit2 ("inc %s", _pairs[pair].name);
6122 _G.pairs[pair].offset++;
6127 freeAsmop (left, NULL, ic);
6130 freeAsmop (result, NULL, ic);
6133 /*-----------------------------------------------------------------*/
6134 /* genPointerGet - generate code for pointer get */
6135 /*-----------------------------------------------------------------*/
6137 genPointerGet (iCode * ic)
6139 operand *left, *result;
6140 sym_link *type, *etype;
6142 left = IC_LEFT (ic);
6143 result = IC_RESULT (ic);
6145 /* depending on the type of pointer we need to
6146 move it to the correct pointer register */
6147 type = operandType (left);
6148 etype = getSpec (type);
6150 genGenPointerGet (left, result, ic);
6154 isRegOrLit (asmop * aop)
6156 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6161 /*-----------------------------------------------------------------*/
6162 /* genGenPointerSet - stores the value into a pointer location */
6163 /*-----------------------------------------------------------------*/
6165 genGenPointerSet (operand * right,
6166 operand * result, iCode * ic)
6169 sym_link *retype = getSpec (operandType (right));
6170 PAIR_ID pairId = PAIR_HL;
6172 aopOp (result, ic, FALSE, FALSE);
6173 aopOp (right, ic, FALSE, FALSE);
6178 size = AOP_SIZE (right);
6180 /* Handle the exceptions first */
6181 if (isPair (AOP (result)) && size == 1)
6184 const char *l = aopGet (AOP (right), 0, FALSE);
6185 const char *pair = getPairName (AOP (result));
6186 if (canAssignToPtr (l) && isPtr (pair))
6188 emit2 ("ld !*pair,%s", pair, l);
6193 emit2 ("ld !*pair,a", pair);
6198 if ( getPairId( AOP (result)) == PAIR_IY)
6201 const char *l = aopGet (AOP (right), 0, FALSE);
6206 if (canAssignToPtr (l))
6208 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6212 _moveA (aopGet (AOP (right), offset, FALSE));
6213 emit2 ("ld !*iyx,a", offset);
6219 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result))
6225 const char *l = aopGet (AOP (right), offset, FALSE);
6226 if (isRegOrLit (AOP (right)) && !IS_GB)
6228 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
6233 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
6237 emit2 ("inc %s", _pairs[PAIR_HL].name);
6238 _G.pairs[PAIR_HL].offset++;
6243 /* Fixup HL back down */
6244 for (size = AOP_SIZE (right)-1; size; size--)
6246 emit2 ("dec %s", _pairs[PAIR_HL].name);
6251 /* if the operand is already in dptr
6252 then we do nothing else we move the value to dptr */
6253 if (AOP_TYPE (result) != AOP_STR)
6255 fetchPair (pairId, AOP (result));
6257 /* so hl know contains the address */
6258 freeAsmop (result, NULL, ic);
6260 /* if bit then unpack */
6261 if (IS_BITVAR (retype))
6271 const char *l = aopGet (AOP (right), offset, FALSE);
6272 if (isRegOrLit (AOP (right)) && !IS_GB)
6274 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
6279 emit2 ("ld !*pair,a", _pairs[pairId].name);
6283 emit2 ("inc %s", _pairs[pairId].name);
6284 _G.pairs[pairId].offset++;
6290 freeAsmop (right, NULL, ic);
6293 /*-----------------------------------------------------------------*/
6294 /* genPointerSet - stores the value into a pointer location */
6295 /*-----------------------------------------------------------------*/
6297 genPointerSet (iCode * ic)
6299 operand *right, *result;
6300 sym_link *type, *etype;
6302 right = IC_RIGHT (ic);
6303 result = IC_RESULT (ic);
6305 /* depending on the type of pointer we need to
6306 move it to the correct pointer register */
6307 type = operandType (result);
6308 etype = getSpec (type);
6310 genGenPointerSet (right, result, ic);
6313 /*-----------------------------------------------------------------*/
6314 /* genIfx - generate code for Ifx statement */
6315 /*-----------------------------------------------------------------*/
6317 genIfx (iCode * ic, iCode * popIc)
6319 operand *cond = IC_COND (ic);
6322 aopOp (cond, ic, FALSE, TRUE);
6324 /* get the value into acc */
6325 if (AOP_TYPE (cond) != AOP_CRY)
6329 /* the result is now in the accumulator */
6330 freeAsmop (cond, NULL, ic);
6332 /* if there was something to be popped then do it */
6336 /* if the condition is a bit variable */
6337 if (isbit && IS_ITEMP (cond) &&
6339 genIfxJump (ic, SPIL_LOC (cond)->rname);
6340 else if (isbit && !IS_ITEMP (cond))
6341 genIfxJump (ic, OP_SYMBOL (cond)->rname);
6343 genIfxJump (ic, "a");
6348 /*-----------------------------------------------------------------*/
6349 /* genAddrOf - generates code for address of */
6350 /*-----------------------------------------------------------------*/
6352 genAddrOf (iCode * ic)
6354 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
6356 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6358 /* if the operand is on the stack then we
6359 need to get the stack offset of this
6366 if (sym->stack <= 0)
6368 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
6372 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6374 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6378 emit2 ("ld de,!hashedstr", sym->rname);
6379 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
6387 /* if it has an offset then we need to compute it */
6389 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6391 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
6392 emit2 ("add hl,sp");
6396 emit2 ("ld hl,!hashedstr", sym->rname);
6398 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6400 freeAsmop (IC_RESULT (ic), NULL, ic);
6403 /*-----------------------------------------------------------------*/
6404 /* genAssign - generate code for assignment */
6405 /*-----------------------------------------------------------------*/
6407 genAssign (iCode * ic)
6409 operand *result, *right;
6411 unsigned long lit = 0L;
6413 result = IC_RESULT (ic);
6414 right = IC_RIGHT (ic);
6416 /* Dont bother assigning if they are the same */
6417 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6419 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
6423 aopOp (right, ic, FALSE, FALSE);
6424 aopOp (result, ic, TRUE, FALSE);
6426 /* if they are the same registers */
6427 if (sameRegs (AOP (right), AOP (result)))
6429 emitDebug ("; (registers are the same)");
6433 /* if the result is a bit */
6434 if (AOP_TYPE (result) == AOP_CRY)
6436 wassertl (0, "Tried to assign to a bit");
6440 size = AOP_SIZE (result);
6443 if (AOP_TYPE (right) == AOP_LIT)
6445 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6448 if (isPair (AOP (result)))
6450 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
6452 else if ((size > 1) &&
6453 (AOP_TYPE (result) != AOP_REG) &&
6454 (AOP_TYPE (right) == AOP_LIT) &&
6455 !IS_FLOAT (operandType (right)) &&
6458 bool fXored = FALSE;
6460 /* Work from the top down.
6461 Done this way so that we can use the cached copy of 0
6462 in A for a fast clear */
6465 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
6467 if (!fXored && size > 1)
6474 aopPut (AOP (result), "a", offset);
6478 aopPut (AOP (result), "!zero", offset);
6482 aopPut (AOP (result),
6483 aopGet (AOP (right), offset, FALSE),
6488 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
6490 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
6491 aopPut (AOP (result), "l", LSB);
6492 aopPut (AOP (result), "h", MSB16);
6494 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6496 /* Special case. Load into a and d, then load out. */
6497 _moveA (aopGet (AOP (right), 0, FALSE));
6498 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
6499 aopPut (AOP (result), "a", 0);
6500 aopPut (AOP (result), "e", 1);
6502 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6504 /* Special case - simple memcpy */
6505 aopGet (AOP (right), LSB, FALSE);
6508 aopGet (AOP (result), LSB, FALSE);
6512 emit2 ("ld a,(de)");
6513 /* Peephole will optimise this. */
6514 emit2 ("ld (hl),a");
6522 spillPair (PAIR_HL);
6528 /* PENDING: do this check better */
6529 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
6531 _moveA (aopGet (AOP (right), offset, FALSE));
6532 aopPut (AOP (result), "a", offset);
6535 aopPut (AOP (result),
6536 aopGet (AOP (right), offset, FALSE),
6543 freeAsmop (right, NULL, ic);
6544 freeAsmop (result, NULL, ic);
6547 /*-----------------------------------------------------------------*/
6548 /* genJumpTab - genrates code for jump table */
6549 /*-----------------------------------------------------------------*/
6551 genJumpTab (iCode * ic)
6556 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
6557 /* get the condition into accumulator */
6558 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
6561 emit2 ("ld e,%s", l);
6562 emit2 ("ld d,!zero");
6563 jtab = newiTempLabel (NULL);
6565 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
6566 emit2 ("add hl,de");
6567 emit2 ("add hl,de");
6568 emit2 ("add hl,de");
6569 freeAsmop (IC_JTCOND (ic), NULL, ic);
6573 emitLabel (jtab->key + 100);
6574 /* now generate the jump labels */
6575 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
6576 jtab = setNextItem (IC_JTLABELS (ic)))
6577 emit2 ("jp !tlabel", jtab->key + 100);
6580 /*-----------------------------------------------------------------*/
6581 /* genCast - gen code for casting */
6582 /*-----------------------------------------------------------------*/
6584 genCast (iCode * ic)
6586 operand *result = IC_RESULT (ic);
6587 sym_link *rtype = operandType (IC_RIGHT (ic));
6588 operand *right = IC_RIGHT (ic);
6591 /* if they are equivalent then do nothing */
6592 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6595 aopOp (right, ic, FALSE, FALSE);
6596 aopOp (result, ic, FALSE, FALSE);
6598 /* if the result is a bit */
6599 if (AOP_TYPE (result) == AOP_CRY)
6601 wassertl (0, "Tried to cast to a bit");
6604 /* if they are the same size : or less */
6605 if (AOP_SIZE (result) <= AOP_SIZE (right))
6608 /* if they are in the same place */
6609 if (sameRegs (AOP (right), AOP (result)))
6612 /* if they in different places then copy */
6613 size = AOP_SIZE (result);
6617 aopPut (AOP (result),
6618 aopGet (AOP (right), offset, FALSE),
6625 /* So we now know that the size of destination is greater
6626 than the size of the source */
6627 /* we move to result for the size of source */
6628 size = AOP_SIZE (right);
6632 aopPut (AOP (result),
6633 aopGet (AOP (right), offset, FALSE),
6638 /* now depending on the sign of the destination */
6639 size = AOP_SIZE (result) - AOP_SIZE (right);
6640 /* Unsigned or not an integral type - right fill with zeros */
6641 if (SPEC_USIGN (rtype) || !IS_SPEC (rtype) || AOP_TYPE(right)==AOP_CRY)
6644 aopPut (AOP (result), "!zero", offset++);
6648 /* we need to extend the sign :{ */
6649 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
6655 aopPut (AOP (result), "a", offset++);
6659 freeAsmop (right, NULL, ic);
6660 freeAsmop (result, NULL, ic);
6663 /*-----------------------------------------------------------------*/
6664 /* genReceive - generate code for a receive iCode */
6665 /*-----------------------------------------------------------------*/
6667 genReceive (iCode * ic)
6669 if (isOperandInFarSpace (IC_RESULT (ic)) &&
6670 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
6671 IS_TRUE_SYMOP (IC_RESULT (ic))))
6681 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6682 size = AOP_SIZE(IC_RESULT(ic));
6684 for (i = 0; i < size; i++) {
6685 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
6689 freeAsmop (IC_RESULT (ic), NULL, ic);
6694 /** Maximum number of bytes to emit per line. */
6698 /** Context for the byte output chunker. */
6701 unsigned char buffer[DBEMIT_MAX_RUN];
6706 /** Flushes a byte chunker by writing out all in the buffer and
6710 _dbFlush(DBEMITCTX *self)
6717 sprintf(line, ".db 0x%02X", self->buffer[0]);
6719 for (i = 1; i < self->pos; i++)
6721 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
6728 /** Write out another byte, buffering until a decent line is
6732 _dbEmit(DBEMITCTX *self, int c)
6734 if (self->pos == DBEMIT_MAX_RUN)
6738 self->buffer[self->pos++] = c;
6741 /** Context for a simple run length encoder. */
6745 unsigned char buffer[128];
6747 /** runLen may be equivalent to pos. */
6753 RLE_CHANGE_COST = 4,
6757 /** Flush the buffer of a run length encoder by writing out the run or
6758 data that it currently contains.
6761 _rleCommit(RLECTX *self)
6767 memset(&db, 0, sizeof(db));
6769 emit2(".db %u", self->pos);
6771 for (i = 0; i < self->pos; i++)
6773 _dbEmit(&db, self->buffer[i]);
6782 Can get either a run or a block of random stuff.
6783 Only want to change state if a good run comes in or a run ends.
6784 Detecting run end is easy.
6787 Say initial state is in run, len zero, last zero. Then if you get a
6788 few zeros then something else then a short run will be output.
6789 Seems OK. While in run mode, keep counting. While in random mode,
6790 keep a count of the run. If run hits margin, output all up to run,
6791 restart, enter run mode.
6794 /** Add another byte into the run length encoder, flushing as
6795 required. The run length encoder uses the Amiga IFF style, where
6796 a block is prefixed by its run length. A positive length means
6797 the next n bytes pass straight through. A negative length means
6798 that the next byte is repeated -n times. A zero terminates the
6802 _rleAppend(RLECTX *self, int c)
6806 if (c != self->last)
6808 /* The run has stopped. See if it is worthwhile writing it out
6809 as a run. Note that the random data comes in as runs of
6812 if (self->runLen > RLE_CHANGE_COST)
6814 /* Yes, worthwhile. */
6815 /* Commit whatever was in the buffer. */
6817 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
6821 /* Not worthwhile. Append to the end of the random list. */
6822 for (i = 0; i < self->runLen; i++)
6824 if (self->pos >= RLE_MAX_BLOCK)
6829 self->buffer[self->pos++] = self->last;
6837 if (self->runLen >= RLE_MAX_BLOCK)
6839 /* Commit whatever was in the buffer. */
6842 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
6850 _rleFlush(RLECTX *self)
6852 _rleAppend(self, -1);
6859 /** genArrayInit - Special code for initialising an array with constant
6863 genArrayInit (iCode * ic)
6867 int elementSize = 0, eIndex, i;
6868 unsigned val, lastVal;
6872 memset(&rle, 0, sizeof(rle));
6874 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
6876 _saveRegsForCall(ic, 0);
6878 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
6879 emit2 ("call __initrleblock");
6881 type = operandType(IC_LEFT(ic));
6883 if (type && type->next)
6885 elementSize = getSize(type->next);
6889 wassertl (0, "Can't determine element size in genArrayInit.");
6892 iLoop = IC_ARRAYILIST(ic);
6893 lastVal = (unsigned)-1;
6895 /* Feed all the bytes into the run length encoder which will handle
6897 This works well for mixed char data, and for random int and long
6906 for (i = 0; i < ix; i++)
6908 for (eIndex = 0; eIndex < elementSize; eIndex++)
6910 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
6911 _rleAppend(&rle, val);
6916 iLoop = iLoop->next;
6920 /* Mark the end of the run. */
6923 _restoreRegsAfterCall();
6927 freeAsmop (IC_LEFT(ic), NULL, ic);
6931 _swap (PAIR_ID one, PAIR_ID two)
6933 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
6939 emit2 ("ld a,%s", _pairs[one].l);
6940 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
6941 emit2 ("ld %s,a", _pairs[two].l);
6942 emit2 ("ld a,%s", _pairs[one].h);
6943 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
6944 emit2 ("ld %s,a", _pairs[two].h);
6948 /* The problem is that we may have all three pairs used and they may
6949 be needed in a different order.
6954 hl = hl => unity, fine
6958 hl = hl hl = hl, swap de <=> bc
6966 hl = bc de = de, swap bc <=> hl
6974 hl = de bc = bc, swap hl <=> de
6979 * Any pair = pair are done last
6980 * Any pair = iTemp are done last
6981 * Any swaps can be done any time
6989 So how do we detect the cases?
6990 How about a 3x3 matrix?
6994 x x x x (Fourth for iTemp/other)
6996 First determin which mode to use by counting the number of unity and
6999 Two - Assign the pair first, then the rest
7000 One - Swap the two, then the rest
7004 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7006 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7008 PAIR_BC, PAIR_HL, PAIR_DE
7010 int i, j, nunity = 0;
7011 memset (ids, PAIR_INVALID, sizeof (ids));
7014 wassert (nparams == 3);
7016 /* First save everything that needs to be saved. */
7017 _saveRegsForCall (ic, 0);
7019 /* Loading HL first means that DE is always fine. */
7020 for (i = 0; i < nparams; i++)
7022 aopOp (pparams[i], ic, FALSE, FALSE);
7023 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7026 /* Count the number of unity or iTemp assigns. */
7027 for (i = 0; i < 3; i++)
7029 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7037 /* Any order, fall through. */
7039 else if (nunity == 2)
7041 /* One is assigned. Pull it out and assign. */
7042 for (i = 0; i < 3; i++)
7044 for (j = 0; j < NUM_PAIRS; j++)
7046 if (ids[dest[i]][j] == TRUE)
7048 /* Found it. See if it's the right one. */
7049 if (j == PAIR_INVALID || j == dest[i])
7055 fetchPair(dest[i], AOP (pparams[i]));
7062 else if (nunity == 1)
7064 /* Find the pairs to swap. */
7065 for (i = 0; i < 3; i++)
7067 for (j = 0; j < NUM_PAIRS; j++)
7069 if (ids[dest[i]][j] == TRUE)
7071 if (j == PAIR_INVALID || j == dest[i])
7086 int next = getPairId (AOP (pparams[0]));
7087 emit2 ("push %s", _pairs[next].name);
7089 if (next == dest[1])
7091 fetchPair (dest[1], AOP (pparams[1]));
7092 fetchPair (dest[2], AOP (pparams[2]));
7096 fetchPair (dest[2], AOP (pparams[2]));
7097 fetchPair (dest[1], AOP (pparams[1]));
7099 emit2 ("pop %s", _pairs[dest[0]].name);
7102 /* Finally pull out all of the iTemps */
7103 for (i = 0; i < 3; i++)
7105 if (ids[dest[i]][PAIR_INVALID] == 1)
7107 fetchPair (dest[i], AOP (pparams[i]));
7113 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
7119 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
7123 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7125 setupForBuiltin3 (ic, nParams, pparams);
7127 label = newiTempLabel(NULL);
7129 emitLabel (label->key);
7130 emit2 ("ld a,(hl)");
7133 emit2 ("!shortjp nz,!tlabel ; 1", label->key);
7135 freeAsmop (from, NULL, ic->next);
7136 freeAsmop (to, NULL, ic);
7140 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
7142 operand *from, *to, *count;
7145 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
7150 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7152 setupForBuiltin3 (ic, nParams, pparams);
7156 freeAsmop (count, NULL, ic->next->next);
7157 freeAsmop (from, NULL, ic);
7159 _restoreRegsAfterCall();
7161 /* if we need assign a result value */
7162 if ((IS_ITEMP (IC_RESULT (ic)) &&
7163 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
7164 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
7165 IS_TRUE_SYMOP (IC_RESULT (ic)))
7167 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7168 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
7169 freeAsmop (IC_RESULT (ic), NULL, ic);
7172 freeAsmop (to, NULL, ic->next);
7175 /*-----------------------------------------------------------------*/
7176 /* genBuiltIn - calls the appropriate function to generating code */
7177 /* for a built in function */
7178 /*-----------------------------------------------------------------*/
7179 static void genBuiltIn (iCode *ic)
7181 operand *bi_parms[MAX_BUILTIN_ARGS];
7186 /* get all the arguments for a built in function */
7187 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
7189 /* which function is it */
7190 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
7192 if (strcmp(bif->name,"__builtin_strcpy")==0)
7194 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
7196 else if (strcmp(bif->name,"__builtin_memcpy")==0)
7198 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
7202 wassertl (0, "Unknown builtin function encountered");
7206 /*-----------------------------------------------------------------*/
7207 /* genZ80Code - generate code for Z80 based controllers */
7208 /*-----------------------------------------------------------------*/
7210 genZ80Code (iCode * lic)
7218 _fReturn = _gbz80_return;
7219 _fTmp = _gbz80_return;
7223 _fReturn = _z80_return;
7224 _fTmp = _z80_return;
7227 _G.lines.head = _G.lines.current = NULL;
7229 for (ic = lic; ic; ic = ic->next)
7232 if (cln != ic->lineno)
7234 emit2 ("; %s %d", ic->filename, ic->lineno);
7237 /* if the result is marked as
7238 spilt and rematerializable or code for
7239 this has already been generated then
7241 if (resultRemat (ic) || ic->generated)
7244 /* depending on the operation */
7248 emitDebug ("; genNot");
7253 emitDebug ("; genCpl");
7258 emitDebug ("; genUminus");
7263 emitDebug ("; genIpush");
7268 /* IPOP happens only when trying to restore a
7269 spilt live range, if there is an ifx statement
7270 following this pop then the if statement might
7271 be using some of the registers being popped which
7272 would destory the contents of the register so
7273 we need to check for this condition and handle it */
7275 ic->next->op == IFX &&
7276 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
7278 emitDebug ("; genIfx");
7279 genIfx (ic->next, ic);
7283 emitDebug ("; genIpop");
7289 emitDebug ("; genCall");
7294 emitDebug ("; genPcall");
7299 emitDebug ("; genFunction");
7304 emitDebug ("; genEndFunction");
7305 genEndFunction (ic);
7309 emitDebug ("; genRet");
7314 emitDebug ("; genLabel");
7319 emitDebug ("; genGoto");
7324 emitDebug ("; genPlus");
7329 emitDebug ("; genMinus");
7334 emitDebug ("; genMult");
7339 emitDebug ("; genDiv");
7344 emitDebug ("; genMod");
7349 emitDebug ("; genCmpGt");
7350 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
7354 emitDebug ("; genCmpLt");
7355 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
7362 /* note these two are xlated by algebraic equivalence
7363 during parsing SDCC.y */
7364 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
7365 "got '>=' or '<=' shouldn't have come here");
7369 emitDebug ("; genCmpEq");
7370 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
7374 emitDebug ("; genAndOp");
7379 emitDebug ("; genOrOp");
7384 emitDebug ("; genXor");
7385 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
7389 emitDebug ("; genOr");
7390 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
7394 emitDebug ("; genAnd");
7395 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
7399 emitDebug ("; genInline");
7404 emitDebug ("; genRRC");
7409 emitDebug ("; genRLC");
7414 emitDebug ("; genGetHBIT");
7419 emitDebug ("; genLeftShift");
7424 emitDebug ("; genRightShift");
7428 case GET_VALUE_AT_ADDRESS:
7429 emitDebug ("; genPointerGet");
7435 if (POINTER_SET (ic))
7437 emitDebug ("; genAssign (pointer)");
7442 emitDebug ("; genAssign");
7448 emitDebug ("; genIfx");
7453 emitDebug ("; genAddrOf");
7458 emitDebug ("; genJumpTab");
7463 emitDebug ("; genCast");
7468 emitDebug ("; genReceive");
7473 if (ic->builtinSEND)
7475 emitDebug ("; genBuiltIn");
7480 emitDebug ("; addSet");
7481 addSet (&_G.sendSet, ic);
7486 emitDebug ("; genArrayInit");
7496 /* now we are ready to call the
7497 peep hole optimizer */
7498 if (!options.nopeep)
7499 peepHole (&_G.lines.head);
7501 /* This is unfortunate */
7502 /* now do the actual printing */
7504 FILE *fp = codeOutFile;
7505 if (isInHome () && codeOutFile == code->oFile)
7506 codeOutFile = home->oFile;
7507 printLine (_G.lines.head, codeOutFile);
7508 if (_G.flushStatics)
7511 _G.flushStatics = 0;
7516 freeTrace(&_G.lines.trace);
7517 freeTrace(&_G.trace.aops);
7523 _isPairUsed (iCode * ic, PAIR_ID pairId)
7529 if (bitVectBitValue (ic->rMask, D_IDX))
7531 if (bitVectBitValue (ic->rMask, E_IDX))
7541 fetchLitSpecial (asmop * aop, bool negate, bool xor)
7544 value *val = aop->aopu.aop_lit;
7546 wassert (aop->type == AOP_LIT);
7547 wassert (!IS_FLOAT (val->type));
7549 v = (unsigned long) floatFromVal (val);
7557 tsprintf (buffer, "!immedword", v);
7558 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));