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 #if defined(__BORLANDC__) || defined(_MSC_VER)
91 #define STRCASECMP stricmp
93 #define STRCASECMP strcasecmp
97 #include "SDCCglobl.h"
98 #include "SDCCpeeph.h"
100 #include "SDCCglue.h"
101 #include "newalloc.h"
103 /* This is the down and dirty file with all kinds of kludgy & hacky
104 stuff. This is what it is all about CODE GENERATION for a specific MCU.
105 Some of the routines may be reusable, will have to see */
107 /* Z80 calling convention description.
108 Parameters are passed right to left. As the stack grows downwards,
109 the parameters are arranged in left to right in memory.
110 Parameters may be passed in the HL and DE registers with one
112 PENDING: What if the parameter is a long?
113 Everything is caller saves. i.e. the caller must save any registers
114 that it wants to preserve over the call.
115 GB: The return value is returned in DEHL. DE is normally used as a
116 working register pair. Caller saves allows it to be used for a
118 va args functions do not use register parameters. All arguments
119 are passed on the stack.
120 IX is used as an index register to the top of the local variable
121 area. ix-0 is the top most local variable.
126 /* Set to enable debugging trace statements in the output assembly code. */
130 static char *_z80_return[] =
131 {"l", "h", "e", "d"};
132 static char *_gbz80_return[] =
133 {"e", "d", "l", "h"};
134 static char *_fReceive[] =
135 { "c", "b", "e", "d" };
137 static char **_fReturn;
140 extern FILE *codeOutFile;
148 /** Enum covering all the possible register pairs.
167 } _pairs[NUM_PAIRS] = {
168 { "??1", "?2", "?3" },
173 { "iy", "iyl", "iyh" },
174 { "ix", "ixl", "ixh" }
178 #define ACC_NAME _pairs[PAIR_AF].h
188 /** Code generator persistent data.
192 /** Used to optimised setting up of a pair by remebering what it
193 contains and adjusting instead of reloading where possible.
222 const char *lastFunctionName;
228 /** TRUE if the registers have already been saved. */
246 static const char *aopGet (asmop * aop, int offset, bool bit16);
248 static const char *aopNames[] = {
268 isLastUse (iCode *ic, operand *op)
270 bitVect *uses = bitVectCopy (OP_USES (op));
272 while (!bitVectIsZero (uses))
274 if (bitVectFirstBit (uses) == ic->key)
276 if (bitVectnBitsOn (uses) == 1)
285 bitVectUnSetBit (uses, bitVectFirstBit (uses));
305 _getTempPairName(void)
307 return _pairs[_getTempPairId()].name;
311 isPairInUse (PAIR_ID id, iCode *ic)
315 return bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
317 else if (id == PAIR_BC)
319 return bitVectBitValue (ic->rMask, B_IDX) || bitVectBitValue(ic->rMask, C_IDX);
323 wassertl (0, "Only implemented for DE and BC");
329 isPairInUseNotInRet(PAIR_ID id, iCode *ic)
333 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
337 return bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
341 wassertl (0, "Only implemented for DE");
347 getFreePairId (iCode *ic)
349 if (!isPairInUse (PAIR_BC, ic))
353 else if (IS_Z80 && !isPairInUse (PAIR_DE, ic))
366 /* Clean up the line so that it is 'prettier' */
367 if (strchr (buf, ':'))
369 /* Is a label - cant do anything */
372 /* Change the first (and probably only) ' ' to a tab so
387 _newLineNode (char *line)
391 pl = traceAlloc(&_G.lines.trace, Safe_alloc ( sizeof (lineNode)));
392 pl->line = traceAlloc(&_G.lines.trace, Safe_strdup (line));
398 _vemit2 (const char *szFormat, va_list ap)
400 char buffer[INITIAL_INLINEASM];
402 tvsprintf (buffer, sizeof(buffer), szFormat, ap);
405 _G.lines.current = (_G.lines.current ?
406 connectLine (_G.lines.current, _newLineNode (buffer)) :
407 (_G.lines.head = _newLineNode (buffer)));
409 _G.lines.current->isInline = _G.lines.isInline;
413 emit2 (const char *szFormat,...)
417 va_start (ap, szFormat);
419 _vemit2 (szFormat, ap);
425 emitDebug (const char *szFormat,...)
431 va_start (ap, szFormat);
433 _vemit2 (szFormat, ap);
439 /*-----------------------------------------------------------------*/
440 /* emit2 - writes the code into a file : for now it is simple */
441 /*-----------------------------------------------------------------*/
443 _emit2 (const char *inst, const char *fmt,...)
446 char lb[INITIAL_INLINEASM];
453 sprintf (lb, "%s\t", inst);
454 vsprintf (lb + (strlen (lb)), fmt, ap);
457 vsprintf (lb, fmt, ap);
459 while (isspace (*lbp))
464 _G.lines.current = (_G.lines.current ?
465 connectLine (_G.lines.current, _newLineNode (lb)) :
466 (_G.lines.head = _newLineNode (lb)));
468 _G.lines.current->isInline = _G.lines.isInline;
473 _emitMove(const char *to, const char *from)
475 if (STRCASECMP(to, from) != 0)
477 emit2("ld %s,%s", to, from);
482 // Could leave this to the peephole, but sometimes the peephole is inhibited.
487 aopDump(const char *plabel, asmop *aop)
493 emitDebug("; Dump of %s: type %s size %u", plabel, aopNames[aop->type], aop->size);
498 emitDebug("; aop_stk %d", aop->aopu.aop_stk);
501 for (i=aop->size-1;i>=0;i--)
502 *rbp++ = *(aop->aopu.aop_reg[i]->name);
504 emitDebug("; reg = %s", regbuf);
507 emitDebug("; pairptr = (%s)", _pairs[aop->aopu.aop_pairId].name);
510 /* No information. */
516 _moveA(const char *moveFrom)
518 // Let the peephole optimiser take care of redundent loads
519 _emitMove(ACC_NAME, moveFrom);
529 getPairName (asmop * aop)
531 if (aop->type == AOP_REG)
533 switch (aop->aopu.aop_reg[0]->rIdx)
546 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
549 for (i = 0; i < NUM_PAIRS; i++)
551 if (strcmp(aop->aopu.aop_str[0], _pairs[i].l) == 0)
553 return _pairs[i].name;
557 wassertl (0, "Tried to get the pair name of something that isn't a pair");
562 getPairId (asmop * aop)
566 if (aop->type == AOP_REG)
568 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX) && (aop->aopu.aop_reg[1]->rIdx == B_IDX))
572 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX) && (aop->aopu.aop_reg[1]->rIdx == D_IDX))
576 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX) && (aop->aopu.aop_reg[1]->rIdx == H_IDX))
581 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
584 for (i = 0; i < NUM_PAIRS; i++)
586 if (!strcmp (aop->aopu.aop_str[0], _pairs[i].l) && !strcmp (aop->aopu.aop_str[1], _pairs[i].h))
596 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
600 return (getPairId (aop) != PAIR_INVALID);
603 /** Returns TRUE if the registers used in aop cannot be split into high
606 isUnsplitable (asmop * aop)
608 switch (getPairId (aop))
620 isPtrPair (asmop * aop)
622 PAIR_ID pairId = getPairId (aop);
635 spillPair (PAIR_ID pairId)
637 _G.pairs[pairId].last_type = AOP_INVALID;
638 _G.pairs[pairId].base = NULL;
641 /* Given a register name, spill the pair (if any) the register is part of */
643 spillPairReg (const char *regname)
645 if (strlen(regname)==1)
665 /** Push a register pair onto the stack */
667 genPairPush (asmop * aop)
669 emit2 ("push %s", getPairName (aop));
673 _push (PAIR_ID pairId)
675 emit2 ("push %s", _pairs[pairId].name);
676 _G.stack.pushed += 2;
680 _pop (PAIR_ID pairId)
682 emit2 ("pop %s", _pairs[pairId].name);
683 _G.stack.pushed -= 2;
688 genMovePairPair (PAIR_ID srcPair, PAIR_ID dstPair)
701 if (srcPair == PAIR_IX || srcPair == PAIR_IY)
708 emit2("ld %s,%s",_pairs[dstPair].l,_pairs[srcPair].l);
709 emit2("ld %s,%s",_pairs[dstPair].h,_pairs[srcPair].h);
712 wassertl (0, "Tried to move a nonphysical pair");
714 _G.pairs[dstPair].last_type = _G.pairs[srcPair].last_type;
715 _G.pairs[dstPair].base = _G.pairs[srcPair].base;
716 _G.pairs[dstPair].offset = _G.pairs[srcPair].offset;
720 /*-----------------------------------------------------------------*/
721 /* newAsmop - creates a new asmOp */
722 /*-----------------------------------------------------------------*/
724 newAsmop (short type)
728 aop = traceAlloc(&_G.trace.aops, Safe_alloc (sizeof (asmop)));
733 /*-----------------------------------------------------------------*/
734 /* aopForSym - for a true symbol */
735 /*-----------------------------------------------------------------*/
737 aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
744 wassert (sym->etype);
746 space = SPEC_OCLS (sym->etype);
748 /* if already has one */
754 /* Assign depending on the storage class */
755 if (sym->onStack || sym->iaccess)
757 /* The pointer that is used depends on how big the offset is.
758 Normally everything is AOP_STK, but for offsets of < -128 or
759 > 127 on the Z80 an extended stack pointer is used.
761 if (IS_Z80 && (_G.omitFramePtr || sym->stack < INT8MIN || sym->stack > (int)(INT8MAX-getSize (sym->type))))
763 emitDebug ("; AOP_EXSTK for %s", sym->rname);
764 sym->aop = aop = newAsmop (AOP_EXSTK);
768 emitDebug ("; AOP_STK for %s", sym->rname);
769 sym->aop = aop = newAsmop (AOP_STK);
772 aop->size = getSize (sym->type);
773 aop->aopu.aop_stk = sym->stack;
777 /* special case for a function */
778 if (IS_FUNC (sym->type))
780 sym->aop = aop = newAsmop (AOP_IMMD);
781 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup (sym->rname));
788 /* if it is in direct space */
789 if (IN_REGSP (space) && !requires_a)
791 sym->aop = aop = newAsmop (AOP_SFR);
792 aop->aopu.aop_dir = sym->rname;
793 aop->size = getSize (sym->type);
794 emitDebug ("; AOP_SFR for %s", sym->rname);
799 /* only remaining is far space */
800 /* in which case DPTR gets the address */
803 emitDebug ("; AOP_HL for %s", sym->rname);
804 sym->aop = aop = newAsmop (AOP_HL);
808 sym->aop = aop = newAsmop (AOP_IY);
810 aop->size = getSize (sym->type);
811 aop->aopu.aop_dir = sym->rname;
813 /* if it is in code space */
814 if (IN_CODESPACE (space))
820 /*-----------------------------------------------------------------*/
821 /* aopForRemat - rematerialzes an object */
822 /*-----------------------------------------------------------------*/
824 aopForRemat (symbol * sym)
827 iCode *ic = sym->rematiCode;
828 asmop *aop = newAsmop (AOP_IMMD);
832 /* if plus or minus print the right hand side */
833 if (ic->op == '+' || ic->op == '-')
835 /* PENDING: for re-target */
836 sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
839 ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
842 /* we reached the end */
843 sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
847 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
851 /*-----------------------------------------------------------------*/
852 /* regsInCommon - two operands have some registers in common */
853 /*-----------------------------------------------------------------*/
855 regsInCommon (operand * op1, operand * op2)
860 /* if they have registers in common */
861 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
864 sym1 = OP_SYMBOL (op1);
865 sym2 = OP_SYMBOL (op2);
867 if (sym1->nRegs == 0 || sym2->nRegs == 0)
870 for (i = 0; i < sym1->nRegs; i++)
876 for (j = 0; j < sym2->nRegs; j++)
881 if (sym2->regs[j] == sym1->regs[i])
889 /*-----------------------------------------------------------------*/
890 /* operandsEqu - equivalent */
891 /*-----------------------------------------------------------------*/
893 operandsEqu (operand * op1, operand * op2)
897 /* if they not symbols */
898 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
901 sym1 = OP_SYMBOL (op1);
902 sym2 = OP_SYMBOL (op2);
904 /* if both are itemps & one is spilt
905 and the other is not then false */
906 if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
907 sym1->isspilt != sym2->isspilt)
910 /* if they are the same */
914 if (strcmp (sym1->rname, sym2->rname) == 0)
918 /* if left is a tmp & right is not */
919 if (IS_ITEMP (op1) &&
922 (sym1->usl.spillLoc == sym2))
925 if (IS_ITEMP (op2) &&
929 (sym2->usl.spillLoc == sym1))
935 /*-----------------------------------------------------------------*/
936 /* sameRegs - two asmops have the same registers */
937 /*-----------------------------------------------------------------*/
939 sameRegs (asmop * aop1, asmop * aop2)
943 if (aop1->type == AOP_SFR ||
944 aop2->type == AOP_SFR)
950 if (aop1->type != AOP_REG ||
951 aop2->type != AOP_REG)
954 if (aop1->size != aop2->size)
957 for (i = 0; i < aop1->size; i++)
958 if (aop1->aopu.aop_reg[i] !=
959 aop2->aopu.aop_reg[i])
965 /*-----------------------------------------------------------------*/
966 /* aopOp - allocates an asmop for an operand : */
967 /*-----------------------------------------------------------------*/
969 aopOp (operand * op, iCode * ic, bool result, bool requires_a)
978 /* if this a literal */
979 if (IS_OP_LITERAL (op))
981 op->aop = aop = newAsmop (AOP_LIT);
982 aop->aopu.aop_lit = op->operand.valOperand;
983 aop->size = getSize (operandType (op));
987 /* if already has a asmop then continue */
993 /* if the underlying symbol has a aop */
994 if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
996 op->aop = OP_SYMBOL (op)->aop;
1000 /* if this is a true symbol */
1001 if (IS_TRUE_SYMOP (op))
1003 op->aop = aopForSym (ic, OP_SYMBOL (op), result, requires_a);
1007 /* this is a temporary : this has
1013 e) can be a return use only */
1015 sym = OP_SYMBOL (op);
1017 /* if the type is a conditional */
1018 if (sym->regType == REG_CND)
1020 aop = op->aop = sym->aop = newAsmop (AOP_CRY);
1025 /* if it is spilt then two situations
1027 b) has a spill location */
1028 if (sym->isspilt || sym->nRegs == 0)
1030 /* rematerialize it NOW */
1033 sym->aop = op->aop = aop =
1035 aop->size = getSize (sym->type);
1042 aop = op->aop = sym->aop = newAsmop (AOP_STR);
1043 aop->size = getSize (sym->type);
1044 for (i = 0; i < 4; i++)
1045 aop->aopu.aop_str[i] = _fReturn[i];
1051 if (sym->accuse == ACCUSE_A)
1053 aop = op->aop = sym->aop = newAsmop (AOP_ACC);
1054 aop->size = getSize (sym->type);
1055 wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
1057 aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
1059 else if (sym->accuse == ACCUSE_SCRATCH)
1061 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
1062 aop->size = getSize (sym->type);
1063 wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
1064 aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
1065 aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
1067 else if (sym->accuse == ACCUSE_IY)
1069 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
1070 aop->size = getSize (sym->type);
1071 wassertl(aop->size <= 2, "Internal error: Caching in IY, but too big to fit in IY");
1072 aop->aopu.aop_str[0] = _pairs[PAIR_IY].l;
1073 aop->aopu.aop_str[1] = _pairs[PAIR_IY].h;
1077 wassertl (0, "Marked as being allocated into A or HL but is actually in neither");
1082 /* else spill location */
1083 if (sym->usl.spillLoc && getSize(sym->type) != getSize(sym->usl.spillLoc->type)) {
1084 /* force a new aop if sizes differ */
1085 sym->usl.spillLoc->aop = NULL;
1087 sym->aop = op->aop = aop =
1088 aopForSym (ic, sym->usl.spillLoc, result, requires_a);
1089 aop->size = getSize (sym->type);
1093 /* must be in a register */
1094 sym->aop = op->aop = aop = newAsmop (AOP_REG);
1095 aop->size = sym->nRegs;
1096 for (i = 0; i < sym->nRegs; i++)
1097 aop->aopu.aop_reg[i] = sym->regs[i];
1100 /*-----------------------------------------------------------------*/
1101 /* freeAsmop - free up the asmop given to an operand */
1102 /*----------------------------------------------------------------*/
1104 freeAsmop (operand * op, asmop * aaop, iCode * ic)
1121 if (aop->type == AOP_PAIRPTR && IS_Z80 && aop->aopu.aop_pairId == PAIR_DE)
1123 _pop (aop->aopu.aop_pairId);
1126 if (getPairId (aop) == PAIR_HL)
1128 spillPair (PAIR_HL);
1132 /* all other cases just dealloc */
1138 OP_SYMBOL (op)->aop = NULL;
1139 /* if the symbol has a spill */
1141 SPIL_LOC (op)->aop = NULL;
1148 isLitWord (asmop * aop)
1150 /* if (aop->size != 2)
1163 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
1165 /* depending on type */
1171 /* PENDING: for re-target */
1174 tsprintf (buffer, sizeof(buffer),
1175 "!hashedstr + %d", aop->aopu.aop_immd, offset);
1177 else if (offset == 0)
1179 tsprintf (buffer, sizeof(buffer),
1180 "%s", aop->aopu.aop_immd);
1184 tsprintf (buffer, sizeof(buffer),
1185 "%s + %d", aop->aopu.aop_immd, offset);
1187 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1191 value *val = aop->aopu.aop_lit;
1192 /* if it is a float then it gets tricky */
1193 /* otherwise it is fairly simple */
1194 if (!IS_FLOAT (val->type))
1196 unsigned long v = (unsigned long) floatFromVal (val);
1202 else if (offset == 0)
1208 wassertl(0, "Encountered an invalid offset while fetching a literal");
1212 tsprintf (buffer, sizeof(buffer), "!immedword", v);
1214 tsprintf (buffer, sizeof(buffer), "!constword", v);
1216 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1227 /* it is type float */
1228 fl.f = (float) floatFromVal (val);
1230 #ifdef WORDS_BIGENDIAN
1231 i = fl.c[3-offset] | (fl.c[3-offset-1]<<8);
1233 i = fl.c[offset] | (fl.c[offset+1]<<8);
1236 tsprintf (buffer, sizeof(buffer), "!immedword", i);
1238 tsprintf (buffer, sizeof(buffer), "!constword", i);
1240 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1249 aopGetWord (asmop * aop, int offset)
1251 return aopGetLitWordLong (aop, offset, TRUE);
1255 isPtr (const char *s)
1257 if (!strcmp (s, "hl"))
1259 if (!strcmp (s, "ix"))
1261 if (!strcmp (s, "iy"))
1267 adjustPair (const char *pair, int *pold, int new)
1273 emit2 ("inc %s", pair);
1278 emit2 ("dec %s", pair);
1286 spillPair (PAIR_HL);
1287 spillPair (PAIR_IY);
1291 requiresHL (asmop * aop)
1307 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1309 const char *l, *base;
1310 const char *pair = _pairs[pairId].name;
1311 l = aopGetLitWordLong (left, offset, FALSE);
1312 base = aopGetLitWordLong (left, 0, FALSE);
1313 wassert (l && pair && base);
1317 if (pairId == PAIR_HL || pairId == PAIR_IY)
1319 if (_G.pairs[pairId].last_type == left->type)
1321 if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1323 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1325 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1328 if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
1335 _G.pairs[pairId].last_type = left->type;
1336 _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1337 _G.pairs[pairId].offset = offset;
1339 /* Both a lit on the right and a true symbol on the left */
1340 emit2 ("ld %s,!hashedstr", pair, l);
1344 makeFreePairId (iCode *ic, bool *pisUsed)
1350 if (!bitVectBitValue (ic->rMask, B_IDX) && !bitVectBitValue(ic->rMask, C_IDX))
1354 else if (IS_Z80 && !bitVectBitValue (ic->rMask, D_IDX) && !bitVectBitValue(ic->rMask, E_IDX))
1372 fetchPairLong (PAIR_ID pairId, asmop * aop, iCode *ic, int offset)
1374 /* if this is remateriazable */
1375 if (isLitWord (aop)) {
1376 fetchLitPair (pairId, aop, offset);
1380 if (getPairId (aop) == pairId)
1384 /* we need to get it byte by byte */
1385 else if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1386 aopGet (aop, offset, FALSE);
1387 switch (aop->size - offset) {
1389 emit2 ("ld l,!*hl");
1390 emit2 ("ld h,!immedbyte", 0);
1393 // PENDING: Requires that you are only fetching two bytes.
1396 emit2 ("ld h,!*hl");
1400 wassertl (0, "Attempted to fetch too much data into HL");
1404 else if (IS_Z80 && aop->type == AOP_IY) {
1405 /* Instead of fetching relative to IY, just grab directly
1406 from the address IY refers to */
1407 char *l = aopGetLitWordLong (aop, offset, FALSE);
1409 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1411 if (aop->size < 2) {
1412 emit2("ld %s,!zero", _pairs[pairId].h);
1415 else if (pairId == PAIR_IY)
1419 emit2 ("push %s", _pairs[getPairId(aop)].name);
1425 PAIR_ID id = makeFreePairId (ic, &isUsed);
1428 /* Can't load into parts, so load into HL then exchange. */
1429 emit2 ("ld %s,%s", _pairs[id].l, aopGet (aop, offset, FALSE));
1430 emit2 ("ld %s,%s", _pairs[id].h, aopGet (aop, offset + 1, FALSE));
1431 emit2 ("push %s", _pairs[id].name);
1437 else if (isUnsplitable(aop))
1439 emit2("push %s", _pairs[getPairId(aop)].name);
1440 emit2("pop %s", _pairs[pairId].name);
1444 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1445 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1447 /* PENDING: check? */
1448 if (pairId == PAIR_HL)
1449 spillPair (PAIR_HL);
1454 fetchPair (PAIR_ID pairId, asmop * aop)
1456 fetchPairLong (pairId, aop, NULL, 0);
1460 fetchHL (asmop * aop)
1462 fetchPair (PAIR_HL, aop);
1466 setupPairFromSP (PAIR_ID id, int offset)
1468 wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
1470 if (offset < INT8MIN || offset > INT8MAX)
1472 emit2 ("ld hl,!immedword", offset);
1473 emit2 ("add hl,sp");
1477 emit2 ("!ldahlsp", offset);
1482 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1487 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
1488 fetchLitPair (pairId, aop, 0);
1492 wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
1494 fetchLitPair (pairId, aop, offset);
1495 _G.pairs[pairId].offset = offset;
1499 wassertl (IS_Z80, "Only the Z80 has an extended stack");
1500 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
1503 int offset = aop->aopu.aop_stk + _G.stack.offset;
1505 if (_G.pairs[pairId].last_type == aop->type &&
1506 _G.pairs[pairId].offset == offset)
1512 /* PENDING: Do this better. */
1513 sprintf (buffer, "%d", offset + _G.stack.pushed);
1514 emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
1515 emit2 ("add %s,sp", _pairs[pairId].name);
1516 _G.pairs[pairId].last_type = aop->type;
1517 _G.pairs[pairId].offset = offset;
1524 /* Doesnt include _G.stack.pushed */
1525 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1527 if (aop->aopu.aop_stk > 0)
1529 abso += _G.stack.param_offset;
1531 assert (pairId == PAIR_HL);
1532 /* In some cases we can still inc or dec hl */
1533 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1535 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1539 setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
1541 _G.pairs[pairId].offset = abso;
1546 if (pairId != aop->aopu.aop_pairId)
1547 genMovePairPair(aop->aopu.aop_pairId, pairId);
1548 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
1554 _G.pairs[pairId].last_type = aop->type;
1560 emit2 ("!tlabeldef", key);
1564 /*-----------------------------------------------------------------*/
1565 /* aopGet - for fetching value of the aop */
1566 /*-----------------------------------------------------------------*/
1568 aopGet (asmop * aop, int offset, bool bit16)
1570 // char *s = buffer;
1572 /* offset is greater than size then zero */
1573 /* PENDING: this seems a bit screwed in some pointer cases. */
1574 if (offset > (aop->size - 1) &&
1575 aop->type != AOP_LIT)
1577 tsprintf (buffer, sizeof(buffer), "!zero");
1578 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1581 /* depending on type */
1585 /* PENDING: re-target */
1587 tsprintf (buffer, sizeof(buffer), "!immedwords", aop->aopu.aop_immd);
1592 tsprintf (buffer, sizeof(buffer), "!bankimmeds", aop->aopu.aop_immd);
1595 tsprintf (buffer, sizeof(buffer), "!msbimmeds", aop->aopu.aop_immd);
1598 tsprintf (buffer, sizeof(buffer), "!lsbimmeds", aop->aopu.aop_immd);
1601 wassertl (0, "Fetching from beyond the limits of an immediate value.");
1604 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1608 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1609 SNPRINTF (buffer, sizeof(buffer), "a");
1611 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1615 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1616 SNPRINTF (buffer, sizeof(buffer), "a");
1618 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1621 return aop->aopu.aop_reg[offset]->name;
1625 setupPair (PAIR_HL, aop, offset);
1626 tsprintf (buffer, sizeof(buffer), "!*hl");
1628 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
1632 setupPair (PAIR_IY, aop, offset);
1633 tsprintf (buffer, sizeof(buffer), "!*iyx", offset);
1635 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1639 setupPair (PAIR_IY, aop, offset);
1640 tsprintf (buffer, sizeof(buffer), "!*iyx", offset, offset);
1642 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1647 setupPair (PAIR_HL, aop, offset);
1648 tsprintf (buffer, sizeof(buffer), "!*hl");
1652 if (aop->aopu.aop_stk >= 0)
1653 offset += _G.stack.param_offset;
1654 tsprintf (buffer, sizeof(buffer),
1655 "!*ixx", aop->aopu.aop_stk + offset);
1658 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1661 wassertl (0, "Tried to fetch from a bit variable");
1670 tsprintf(buffer, sizeof(buffer), "!zero");
1671 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1675 wassert (offset < 2);
1676 return aop->aopu.aop_str[offset];
1679 return aopLiteral (aop->aopu.aop_lit, offset);
1683 unsigned long v = aop->aopu.aop_simplelit;
1686 tsprintf (buffer, sizeof(buffer),
1687 "!immedbyte", (unsigned int) v & 0xff);
1689 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1693 return aop->aopu.aop_str[offset];
1696 setupPair (aop->aopu.aop_pairId, aop, offset);
1697 if (aop->aopu.aop_pairId==PAIR_IX)
1698 SNPRINTF (buffer, sizeof(buffer),
1700 else if (aop->aopu.aop_pairId==PAIR_IY)
1701 SNPRINTF (buffer, sizeof(buffer),
1704 SNPRINTF (buffer, sizeof(buffer),
1705 "(%s)", _pairs[aop->aopu.aop_pairId].name);
1707 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1712 wassertl (0, "aopget got unsupported aop->type");
1717 isRegString (const char *s)
1719 if (!strcmp (s, "b") ||
1731 isConstant (const char *s)
1733 /* This is a bit of a hack... */
1734 return (*s == '#' || *s == '$');
1738 canAssignToPtr (const char *s)
1740 if (isRegString (s))
1747 /*-----------------------------------------------------------------*/
1748 /* aopPut - puts a string for a aop */
1749 /*-----------------------------------------------------------------*/
1751 aopPut (asmop * aop, const char *s, int offset)
1755 if (aop->size && offset > (aop->size - 1))
1757 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1758 "aopPut got offset > aop->size");
1763 tsprintf(buffer2, sizeof(buffer2), s);
1766 /* will assign value to value */
1767 /* depending on where it is ofcourse */
1773 if (strcmp (s, "a"))
1774 emit2 ("ld a,%s", s);
1775 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1780 if (strcmp (s, "a"))
1781 emit2 ("ld a,%s", s);
1782 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1786 if (!strcmp (s, "!*hl"))
1787 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1790 aop->aopu.aop_reg[offset]->name, s);
1791 spillPairReg(aop->aopu.aop_reg[offset]->name);
1796 if (!canAssignToPtr (s))
1798 emit2 ("ld a,%s", s);
1799 setupPair (PAIR_IY, aop, offset);
1800 emit2 ("ld !*iyx,a", offset);
1804 setupPair (PAIR_IY, aop, offset);
1805 emit2 ("ld !*iyx,%s", offset, s);
1811 /* PENDING: for re-target */
1812 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1814 emit2 ("ld a,!*hl");
1817 setupPair (PAIR_HL, aop, offset);
1819 emit2 ("ld !*hl,%s", s);
1824 if (!canAssignToPtr (s))
1826 emit2 ("ld a,%s", s);
1827 setupPair (PAIR_IY, aop, offset);
1828 emit2 ("ld !*iyx,a", offset);
1832 setupPair (PAIR_IY, aop, offset);
1833 emit2 ("ld !*iyx,%s", offset, s);
1840 /* PENDING: re-target */
1841 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1843 emit2 ("ld a,!*hl");
1846 setupPair (PAIR_HL, aop, offset);
1847 if (!canAssignToPtr (s))
1849 emit2 ("ld a,%s", s);
1850 emit2 ("ld !*hl,a");
1853 emit2 ("ld !*hl,%s", s);
1857 if (aop->aopu.aop_stk >= 0)
1858 offset += _G.stack.param_offset;
1859 if (!canAssignToPtr (s))
1861 emit2 ("ld a,%s", s);
1862 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
1866 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
1872 /* if bit variable */
1873 if (!aop->aopu.aop_dir)
1875 emit2 ("ld a,!zero");
1880 /* In bit space but not in C - cant happen */
1881 wassertl (0, "Tried to write into a bit variable");
1887 if (strcmp (aop->aopu.aop_str[offset], s))
1889 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1891 spillPairReg(aop->aopu.aop_str[offset]);
1896 if (!offset && (strcmp (s, "acc") == 0))
1900 wassertl (0, "Tried to access past the end of A");
1904 if (strcmp (aop->aopu.aop_str[offset], s))
1906 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1907 spillPairReg(aop->aopu.aop_str[offset]);
1913 wassert (offset < 2);
1914 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1915 spillPairReg(aop->aopu.aop_str[offset]);
1919 setupPair (aop->aopu.aop_pairId, aop, offset);
1920 if (aop->aopu.aop_pairId==PAIR_IX)
1921 emit2 ("ld !*ixx,%s", 0, s);
1922 else if (aop->aopu.aop_pairId==PAIR_IY)
1923 emit2 ("ld !*ixy,%s", 0, s);
1925 emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
1929 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1930 "aopPut got unsupported aop->type");
1935 #define AOP(op) op->aop
1936 #define AOP_TYPE(op) AOP(op)->type
1937 #define AOP_SIZE(op) AOP(op)->size
1938 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
1941 commitPair (asmop * aop, PAIR_ID id)
1943 /* PENDING: Verify this. */
1944 if (id == PAIR_HL && requiresHL (aop) && IS_GB)
1948 aopPut (aop, "a", 0);
1949 aopPut (aop, "d", 1);
1954 if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
1956 char *l = aopGetLitWordLong (aop, 0, FALSE);
1959 emit2 ("ld (%s),%s", l, _pairs[id].name);
1963 aopPut (aop, _pairs[id].l, 0);
1964 aopPut (aop, _pairs[id].h, 1);
1969 /*-----------------------------------------------------------------*/
1970 /* getDataSize - get the operand data size */
1971 /*-----------------------------------------------------------------*/
1973 getDataSize (operand * op)
1976 size = AOP_SIZE (op);
1980 wassertl (0, "Somehow got a three byte data pointer");
1985 /*-----------------------------------------------------------------*/
1986 /* movLeft2Result - move byte from left to result */
1987 /*-----------------------------------------------------------------*/
1989 movLeft2Result (operand * left, int offl,
1990 operand * result, int offr, int sign)
1994 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
1996 l = aopGet (AOP (left), offl, FALSE);
2000 aopPut (AOP (result), l, offr);
2004 if (getDataSize (left) == offl + 1)
2006 emit2 ("ld a,%s", l);
2007 aopPut (AOP (result), "a", offr);
2014 movLeft2ResultLong (operand * left, int offl,
2015 operand * result, int offr, int sign,
2020 movLeft2Result (left, offl, result, offr, sign);
2024 wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
2025 wassertl (size == 2, "Only implemented for two bytes or one");
2027 if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
2029 emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
2030 emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
2032 spillPair (PAIR_HL);
2034 else if ( getPairId ( AOP (result)) == PAIR_IY)
2036 PAIR_ID id = getPairId (AOP (left));
2037 if (id != PAIR_INVALID)
2039 emit2("push %s", _pairs[id].name);
2050 movLeft2Result (left, offl, result, offr, sign);
2051 movLeft2Result (left, offl+1, result, offr+1, sign);
2056 /** Put Acc into a register set
2059 outAcc (operand * result)
2062 size = getDataSize (result);
2065 aopPut (AOP (result), "a", 0);
2068 /* unsigned or positive */
2071 aopPut (AOP (result), "!zero", offset++);
2076 /** Take the value in carry and put it into a register
2079 outBitCLong (operand * result, bool swap_sense)
2081 /* if the result is bit */
2082 if (AOP_TYPE (result) == AOP_CRY)
2084 wassertl (0, "Tried to write carry to a bit");
2088 emit2 ("ld a,!zero");
2091 emit2 ("xor a,!immedbyte", 1);
2097 outBitC (operand * result)
2099 outBitCLong (result, FALSE);
2102 /*-----------------------------------------------------------------*/
2103 /* toBoolean - emit code for orl a,operator(sizeop) */
2104 /*-----------------------------------------------------------------*/
2106 _toBoolean (operand * oper)
2108 int size = AOP_SIZE (oper);
2112 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
2115 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
2119 if (AOP (oper)->type != AOP_ACC)
2122 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
2128 /*-----------------------------------------------------------------*/
2129 /* genNot - generate code for ! operation */
2130 /*-----------------------------------------------------------------*/
2135 /* assign asmOps to operand & result */
2136 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
2137 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2139 /* if in bit space then a special case */
2140 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2142 wassertl (0, "Tried to negate a bit");
2145 _toBoolean (IC_LEFT (ic));
2150 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
2151 emit2 ("sub a,!one");
2152 outBitC (IC_RESULT (ic));
2154 /* release the aops */
2155 freeAsmop (IC_LEFT (ic), NULL, ic);
2156 freeAsmop (IC_RESULT (ic), NULL, ic);
2159 /*-----------------------------------------------------------------*/
2160 /* genCpl - generate code for complement */
2161 /*-----------------------------------------------------------------*/
2169 /* assign asmOps to operand & result */
2170 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2171 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2173 /* if both are in bit space then
2175 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2176 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2178 wassertl (0, "Left and the result are in bit space");
2181 size = AOP_SIZE (IC_RESULT (ic));
2184 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2187 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2190 /* release the aops */
2191 freeAsmop (IC_LEFT (ic), NULL, ic);
2192 freeAsmop (IC_RESULT (ic), NULL, ic);
2196 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
2203 store de into result
2208 store de into result
2210 const char *first = isAdd ? "add" : "sub";
2211 const char *later = isAdd ? "adc" : "sbc";
2213 wassertl (IS_GB, "Code is only relevent to the gbz80");
2214 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
2216 fetchPair (PAIR_DE, left);
2219 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
2222 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2225 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2226 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2228 fetchPairLong (PAIR_DE, left, NULL, MSB24);
2229 aopGet (right, MSB24, FALSE);
2233 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2236 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2238 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2239 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2243 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2245 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2248 /*-----------------------------------------------------------------*/
2249 /* genUminusFloat - unary minus for floating points */
2250 /*-----------------------------------------------------------------*/
2252 genUminusFloat (operand * op, operand * result)
2254 int size, offset = 0;
2256 emitDebug("; genUminusFloat");
2258 /* for this we just need to flip the
2259 first it then copy the rest in place */
2260 size = AOP_SIZE (op) - 1;
2262 _moveA(aopGet (AOP (op), MSB32, FALSE));
2264 emit2("xor a,!immedbyte", 0x80);
2265 aopPut (AOP (result), "a", MSB32);
2269 aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2274 /*-----------------------------------------------------------------*/
2275 /* genUminus - unary minus code generation */
2276 /*-----------------------------------------------------------------*/
2278 genUminus (iCode * ic)
2281 sym_link *optype, *rtype;
2284 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2285 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2287 /* if both in bit space then special
2289 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2290 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2292 wassertl (0, "Left and right are in bit space");
2296 optype = operandType (IC_LEFT (ic));
2297 rtype = operandType (IC_RESULT (ic));
2299 /* if float then do float stuff */
2300 if (IS_FLOAT (optype))
2302 genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2306 /* otherwise subtract from zero */
2307 size = AOP_SIZE (IC_LEFT (ic));
2309 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2311 /* Create a new asmop with value zero */
2312 asmop *azero = newAsmop (AOP_SIMPLELIT);
2313 azero->aopu.aop_simplelit = 0;
2315 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2323 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2324 emit2 ("ld a,!zero");
2325 emit2 ("sbc a,%s", l);
2326 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2329 /* if any remaining bytes in the result */
2330 /* we just need to propagate the sign */
2331 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2336 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2340 /* release the aops */
2341 freeAsmop (IC_LEFT (ic), NULL, ic);
2342 freeAsmop (IC_RESULT (ic), NULL, ic);
2345 /*-----------------------------------------------------------------*/
2346 /* assignResultValue - */
2347 /*-----------------------------------------------------------------*/
2349 assignResultValue (operand * oper)
2351 int size = AOP_SIZE (oper);
2354 wassertl (size <= 4, "Got a result that is bigger than four bytes");
2355 topInA = requiresHL (AOP (oper));
2357 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2359 /* We do it the hard way here. */
2361 aopPut (AOP (oper), _fReturn[0], 0);
2362 aopPut (AOP (oper), _fReturn[1], 1);
2364 aopPut (AOP (oper), _fReturn[0], 2);
2365 aopPut (AOP (oper), _fReturn[1], 3);
2371 aopPut (AOP (oper), _fReturn[size], size);
2376 /** Simple restore that doesn't take into account what is used in the
2380 _restoreRegsAfterCall(void)
2382 if (_G.stack.pushedDE)
2385 _G.stack.pushedDE = FALSE;
2387 if (_G.stack.pushedBC)
2390 _G.stack.pushedBC = FALSE;
2392 _G.saves.saved = FALSE;
2396 _saveRegsForCall(iCode *ic, int sendSetSize)
2399 o Stack parameters are pushed before this function enters
2400 o DE and BC may be used in this function.
2401 o HL and DE may be used to return the result.
2402 o HL and DE may be used to send variables.
2403 o DE and BC may be used to store the result value.
2404 o HL may be used in computing the sent value of DE
2405 o The iPushes for other parameters occur before any addSets
2407 Logic: (to be run inside the first iPush or if none, before sending)
2408 o Compute if DE and/or BC are in use over the call
2409 o Compute if DE is used in the send set
2410 o Compute if DE and/or BC are used to hold the result value
2411 o If (DE is used, or in the send set) and is not used in the result, push.
2412 o If BC is used and is not in the result, push
2414 o If DE is used in the send set, fetch
2415 o If HL is used in the send set, fetch
2419 if (_G.saves.saved == FALSE) {
2420 bool deInUse, bcInUse;
2422 bool bcInRet = FALSE, deInRet = FALSE;
2425 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
2427 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2428 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2430 deSending = (sendSetSize > 1);
2432 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2434 if (bcInUse && bcInRet == FALSE) {
2436 _G.stack.pushedBC = TRUE;
2438 if (deInUse && deInRet == FALSE) {
2440 _G.stack.pushedDE = TRUE;
2443 _G.saves.saved = TRUE;
2446 /* Already saved. */
2450 /*-----------------------------------------------------------------*/
2451 /* genIpush - genrate code for pushing this gets a little complex */
2452 /*-----------------------------------------------------------------*/
2454 genIpush (iCode * ic)
2456 int size, offset = 0;
2459 /* if this is not a parm push : ie. it is spill push
2460 and spill push is always done on the local stack */
2463 wassertl(0, "Encountered an unsupported spill push.");
2467 if (_G.saves.saved == FALSE) {
2468 /* Caller saves, and this is the first iPush. */
2469 /* Scan ahead until we find the function that we are pushing parameters to.
2470 Count the number of addSets on the way to figure out what registers
2471 are used in the send set.
2474 iCode *walk = ic->next;
2477 if (walk->op == SEND) {
2480 else if (walk->op == CALL || walk->op == PCALL) {
2489 _saveRegsForCall(walk, nAddSets);
2492 /* Already saved by another iPush. */
2495 /* then do the push */
2496 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2498 size = AOP_SIZE (IC_LEFT (ic));
2500 if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2502 _G.stack.pushed += 2;
2503 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2509 fetchHL (AOP (IC_LEFT (ic)));
2511 spillPair (PAIR_HL);
2512 _G.stack.pushed += 2;
2517 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
2519 spillPair (PAIR_HL);
2520 _G.stack.pushed += 2;
2521 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
2523 spillPair (PAIR_HL);
2524 _G.stack.pushed += 2;
2530 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2532 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2534 emit2 ("ld a,(%s)", l);
2538 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2539 emit2 ("ld a,%s", l);
2547 freeAsmop (IC_LEFT (ic), NULL, ic);
2550 /*-----------------------------------------------------------------*/
2551 /* genIpop - recover the registers: can happen only for spilling */
2552 /*-----------------------------------------------------------------*/
2554 genIpop (iCode * ic)
2559 /* if the temp was not pushed then */
2560 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2563 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2564 size = AOP_SIZE (IC_LEFT (ic));
2565 offset = (size - 1);
2566 if (isPair (AOP (IC_LEFT (ic))))
2568 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2576 spillPair (PAIR_HL);
2577 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2581 freeAsmop (IC_LEFT (ic), NULL, ic);
2584 /* This is quite unfortunate */
2586 setArea (int inHome)
2589 static int lastArea = 0;
2591 if (_G.in_home != inHome) {
2593 const char *sz = port->mem.code_name;
2594 port->mem.code_name = "HOME";
2595 emit2("!area", CODE_NAME);
2596 port->mem.code_name = sz;
2599 emit2("!area", CODE_NAME); */
2600 _G.in_home = inHome;
2611 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2615 symbol *sym = OP_SYMBOL (op);
2617 if (sym->isspilt || sym->nRegs == 0)
2620 aopOp (op, ic, FALSE, FALSE);
2623 if (aop->type == AOP_REG)
2626 for (i = 0; i < aop->size; i++)
2628 if (pairId == PAIR_DE)
2630 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2631 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2633 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2636 else if (pairId == PAIR_BC)
2638 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2639 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2641 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2651 freeAsmop (IC_LEFT (ic), NULL, ic);
2655 /** Emit the code for a call statement
2658 emitCall (iCode * ic, bool ispcall)
2660 sym_link *dtype = operandType (IC_LEFT (ic));
2662 /* if caller saves & we have not saved then */
2668 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2670 /* if send set is not empty then assign */
2675 int nSend = elementsInSet(_G.sendSet);
2676 bool swapped = FALSE;
2678 int _z80_sendOrder[] = {
2683 /* Check if the parameters are swapped. If so route through hl instead. */
2684 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2686 sic = setFirstItem(_G.sendSet);
2687 sic = setNextItem(_G.sendSet);
2689 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2690 /* The second send value is loaded from one the one that holds the first
2691 send, i.e. it is overwritten. */
2692 /* Cache the first in HL, and load the second from HL instead. */
2693 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2694 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2700 for (sic = setFirstItem (_G.sendSet); sic;
2701 sic = setNextItem (_G.sendSet))
2704 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2706 size = AOP_SIZE (IC_LEFT (sic));
2707 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2708 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2710 // PENDING: Mild hack
2711 if (swapped == TRUE && send == 1) {
2713 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2716 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2718 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2721 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2725 freeAsmop (IC_LEFT (sic), NULL, sic);
2732 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2734 werror (W_INDIR_BANKED);
2736 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2738 if (isLitWord (AOP (IC_LEFT (ic))))
2740 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2744 symbol *rlbl = newiTempLabel (NULL);
2745 spillPair (PAIR_HL);
2746 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2748 _G.stack.pushed += 2;
2750 fetchHL (AOP (IC_LEFT (ic)));
2752 emit2 ("!tlabeldef", (rlbl->key + 100));
2753 _G.stack.pushed -= 2;
2755 freeAsmop (IC_LEFT (ic), NULL, ic);
2759 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2760 OP_SYMBOL (IC_LEFT (ic))->rname :
2761 OP_SYMBOL (IC_LEFT (ic))->name;
2762 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2764 emit2 ("call banked_call");
2765 emit2 ("!dws", name);
2766 emit2 ("!dw !bankimmeds", name);
2771 emit2 ("call %s", name);
2776 /* Mark the regsiters as restored. */
2777 _G.saves.saved = FALSE;
2779 /* if we need assign a result value */
2780 if ((IS_ITEMP (IC_RESULT (ic)) &&
2781 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2782 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2783 IS_TRUE_SYMOP (IC_RESULT (ic)))
2786 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2788 assignResultValue (IC_RESULT (ic));
2790 freeAsmop (IC_RESULT (ic), NULL, ic);
2793 /* adjust the stack for parameters if required */
2796 int i = ic->parmBytes;
2798 _G.stack.pushed -= i;
2801 emit2 ("!ldaspsp", i);
2808 emit2 ("ld iy,!immedword", i);
2809 emit2 ("add iy,sp");
2829 if (_G.stack.pushedDE)
2831 bool dInRet = bitVectBitValue(ic->rUsed, D_IDX);
2832 bool eInRet = bitVectBitValue(ic->rUsed, E_IDX);
2834 if (dInRet && eInRet)
2836 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
2840 /* Only restore E */
2847 /* Only restore D */
2855 _G.stack.pushedDE = FALSE;
2858 if (_G.stack.pushedBC)
2860 bool bInRet = bitVectBitValue(ic->rUsed, B_IDX);
2861 bool cInRet = bitVectBitValue(ic->rUsed, C_IDX);
2863 if (bInRet && cInRet)
2865 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
2869 /* Only restore C */
2876 /* Only restore B */
2884 _G.stack.pushedBC = FALSE;
2888 /*-----------------------------------------------------------------*/
2889 /* genCall - generates a call statement */
2890 /*-----------------------------------------------------------------*/
2892 genCall (iCode * ic)
2894 emitCall (ic, FALSE);
2897 /*-----------------------------------------------------------------*/
2898 /* genPcall - generates a call by pointer statement */
2899 /*-----------------------------------------------------------------*/
2901 genPcall (iCode * ic)
2903 emitCall (ic, TRUE);
2906 /*-----------------------------------------------------------------*/
2907 /* resultRemat - result is rematerializable */
2908 /*-----------------------------------------------------------------*/
2910 resultRemat (iCode * ic)
2912 if (SKIP_IC (ic) || ic->op == IFX)
2915 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2917 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2918 if (sym->remat && !POINTER_SET (ic))
2925 extern set *publics;
2927 /*-----------------------------------------------------------------*/
2928 /* genFunction - generated code for function entry */
2929 /*-----------------------------------------------------------------*/
2931 genFunction (iCode * ic)
2935 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2938 bool bcInUse = FALSE;
2939 bool deInUse = FALSE;
2941 setArea (IFFUNC_NONBANKED (sym->type));
2943 /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
2946 _G.receiveOffset = 0;
2948 /* Record the last function name for debugging. */
2949 _G.lastFunctionName = sym->rname;
2951 /* Create the function header */
2952 emit2 ("!functionheader", sym->name);
2953 sprintf (buffer, "%s_start", sym->rname);
2954 emit2 ("!labeldef", buffer);
2955 emit2 ("!functionlabeldef", sym->rname);
2957 if (options.profile)
2959 emit2 ("!profileenter");
2962 ftype = operandType (IC_LEFT (ic));
2964 /* if critical function then turn interrupts off */
2965 if (IFFUNC_ISCRITICAL (ftype))
2968 /* if this is an interrupt service routine then save all potentially used registers. */
2969 if (IFFUNC_ISISR (sym->type))
2974 /* PENDING: callee-save etc */
2976 _G.stack.param_offset = 0;
2978 if (z80_opts.calleeSavesBC)
2983 /* Detect which registers are used. */
2984 if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
2987 for (i = 0; i < sym->regsUsed->size; i++)
2989 if (bitVectBitValue (sym->regsUsed, i))
3003 /* Other systems use DE as a temporary. */
3014 _G.stack.param_offset += 2;
3017 _G.calleeSaves.pushedBC = bcInUse;
3022 _G.stack.param_offset += 2;
3025 _G.calleeSaves.pushedDE = deInUse;
3027 /* adjust the stack for the function */
3028 _G.stack.last = sym->stack;
3031 for (sym = setFirstItem (istack->syms); sym;
3032 sym = setNextItem (istack->syms))
3034 if (sym->_isparm && !IS_REGPARM (sym->etype))
3040 sym = OP_SYMBOL (IC_LEFT (ic));
3042 _G.omitFramePtr = options.ommitFramePtr;
3043 if (IS_Z80 && !stackParm && !sym->stack)
3045 /* When the conflicts between AOP_EXSTK && AOP_HLREG are fixed, */
3046 /* the above !sym->stack condition can be removed. -- EEP */
3048 emit2 ("!ldaspsp", -sym->stack);
3049 _G.omitFramePtr = TRUE;
3051 else if (sym->stack && IS_GB && sym->stack > -INT8MIN)
3052 emit2 ("!enterxl", sym->stack);
3053 else if (sym->stack)
3054 emit2 ("!enterx", sym->stack);
3057 _G.stack.offset = sym->stack;
3060 /*-----------------------------------------------------------------*/
3061 /* genEndFunction - generates epilogue for functions */
3062 /*-----------------------------------------------------------------*/
3064 genEndFunction (iCode * ic)
3066 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3068 if (IFFUNC_ISISR (sym->type))
3070 wassertl (0, "Tried to close an interrupt support function");
3074 if (IFFUNC_ISCRITICAL (sym->type))
3077 /* PENDING: calleeSave */
3079 if (IS_Z80 && _G.omitFramePtr)
3081 if (_G.stack.offset)
3082 emit2 ("!ldaspsp", _G.stack.offset);
3084 else if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
3086 emit2 ("!leavexl", _G.stack.offset);
3088 else if (_G.stack.offset)
3090 emit2 ("!leavex", _G.stack.offset);
3097 if (_G.calleeSaves.pushedDE)
3100 _G.calleeSaves.pushedDE = FALSE;
3103 if (_G.calleeSaves.pushedBC)
3106 _G.calleeSaves.pushedBC = FALSE;
3109 if (options.profile)
3111 emit2 ("!profileexit");
3115 /* Both baned and non-banked just ret */
3118 sprintf (buffer, "%s_end", sym->rname);
3119 emit2 ("!labeldef", buffer);
3121 _G.flushStatics = 1;
3122 _G.stack.pushed = 0;
3123 _G.stack.offset = 0;
3126 /*-----------------------------------------------------------------*/
3127 /* genRet - generate code for return statement */
3128 /*-----------------------------------------------------------------*/
3133 /* Errk. This is a hack until I can figure out how
3134 to cause dehl to spill on a call */
3135 int size, offset = 0;
3137 /* if we have no return value then
3138 just generate the "ret" */
3142 /* we have something to return then
3143 move the return value into place */
3144 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3145 size = AOP_SIZE (IC_LEFT (ic));
3147 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3151 emit2 ("ld de,%s", l);
3155 emit2 ("ld hl,%s", l);
3160 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3162 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3163 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3169 l = aopGet (AOP (IC_LEFT (ic)), offset,
3171 if (strcmp (_fReturn[offset], l))
3172 emit2 ("ld %s,%s", _fReturn[offset++], l);
3176 freeAsmop (IC_LEFT (ic), NULL, ic);
3179 /* generate a jump to the return label
3180 if the next is not the return statement */
3181 if (!(ic->next && ic->next->op == LABEL &&
3182 IC_LABEL (ic->next) == returnLabel))
3184 emit2 ("jp !tlabel", returnLabel->key + 100);
3187 /*-----------------------------------------------------------------*/
3188 /* genLabel - generates a label */
3189 /*-----------------------------------------------------------------*/
3191 genLabel (iCode * ic)
3193 /* special case never generate */
3194 if (IC_LABEL (ic) == entryLabel)
3197 emitLabel (IC_LABEL (ic)->key + 100);
3200 /*-----------------------------------------------------------------*/
3201 /* genGoto - generates a ljmp */
3202 /*-----------------------------------------------------------------*/
3204 genGoto (iCode * ic)
3206 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3209 /*-----------------------------------------------------------------*/
3210 /* genPlusIncr :- does addition with increment if possible */
3211 /*-----------------------------------------------------------------*/
3213 genPlusIncr (iCode * ic)
3215 unsigned int icount;
3216 unsigned int size = getDataSize (IC_RESULT (ic));
3217 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3219 /* will try to generate an increment */
3220 /* if the right side is not a literal
3222 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3225 emitDebug ("; genPlusIncr");
3227 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3229 /* If result is a pair */
3230 if (resultId != PAIR_INVALID)
3232 if (isLitWord (AOP (IC_LEFT (ic))))
3234 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3237 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3239 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3241 PAIR_ID freep = getFreePairId (ic);
3242 if (freep != PAIR_INVALID)
3244 fetchPair (freep, AOP (IC_RIGHT (ic)));
3245 emit2 ("add hl,%s", _pairs[freep].name);
3251 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3252 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3259 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3263 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3267 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3272 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3274 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3275 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3279 /* if the literal value of the right hand side
3280 is greater than 4 then it is not worth it */
3284 /* if increment 16 bits in register */
3285 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3291 symbol *tlbl = NULL;
3292 tlbl = newiTempLabel (NULL);
3295 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3298 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3301 emitLabel (tlbl->key + 100);
3305 /* if the sizes are greater than 1 then we cannot */
3306 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3307 AOP_SIZE (IC_LEFT (ic)) > 1)
3310 /* If the result is in a register then we can load then increment.
3312 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3314 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3317 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3322 /* we can if the aops of the left & result match or
3323 if they are in registers and the registers are the
3325 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3329 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3337 /*-----------------------------------------------------------------*/
3338 /* outBitAcc - output a bit in acc */
3339 /*-----------------------------------------------------------------*/
3341 outBitAcc (operand * result)
3343 symbol *tlbl = newiTempLabel (NULL);
3344 /* if the result is a bit */
3345 if (AOP_TYPE (result) == AOP_CRY)
3347 wassertl (0, "Tried to write A into a bit");
3351 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3352 emit2 ("ld a,!one");
3353 emitLabel (tlbl->key + 100);
3359 couldDestroyCarry (asmop *aop)
3363 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3372 shiftIntoPair (int idx, asmop *aop)
3374 PAIR_ID id = PAIR_INVALID;
3376 wassertl (IS_Z80, "Only implemented for the Z80");
3377 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3389 wassertl (0, "Internal error - hit default case");
3392 emitDebug ("; Shift into pair idx %u", idx);
3396 setupPair (PAIR_HL, aop, 0);
3400 setupPair (PAIR_IY, aop, 0);
3402 emit2 ("pop %s", _pairs[id].name);
3405 aop->type = AOP_PAIRPTR;
3406 aop->aopu.aop_pairId = id;
3407 _G.pairs[id].offset = 0;
3408 _G.pairs[id].last_type = aop->type;
3412 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
3414 wassert (left && right);
3418 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3420 shiftIntoPair (0, right);
3421 /* check result again, in case right == result */
3422 if (couldDestroyCarry (result))
3423 shiftIntoPair (1, result);
3425 else if (couldDestroyCarry (right))
3427 shiftIntoPair (0, right);
3429 else if (couldDestroyCarry (result))
3431 shiftIntoPair (0, result);
3440 /*-----------------------------------------------------------------*/
3441 /* genPlus - generates code for addition */
3442 /*-----------------------------------------------------------------*/
3444 genPlus (iCode * ic)
3446 int size, offset = 0;
3448 /* special cases :- */
3450 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3451 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3452 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3454 /* Swap the left and right operands if:
3456 if literal, literal on the right or
3457 if left requires ACC or right is already
3460 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3461 (AOP_NEEDSACC (IC_LEFT (ic))) ||
3462 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3464 operand *t = IC_RIGHT (ic);
3465 IC_RIGHT (ic) = IC_LEFT (ic);
3469 /* if both left & right are in bit
3471 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3472 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3475 wassertl (0, "Tried to add two bits");
3478 /* if left in bit space & right literal */
3479 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3480 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3482 /* Can happen I guess */
3483 wassertl (0, "Tried to add a bit to a literal");
3486 /* if I can do an increment instead
3487 of add then GOOD for ME */
3488 if (genPlusIncr (ic) == TRUE)
3491 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3493 size = getDataSize (IC_RESULT (ic));
3495 /* Special case when left and right are constant */
3496 if (isPair (AOP (IC_RESULT (ic))))
3499 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3500 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3502 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3508 sprintf (buffer, "#(%s + %s)", left, right);
3509 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3514 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3516 /* Fetch into HL then do the add */
3517 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3518 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3520 spillPair (PAIR_HL);
3522 if (left == PAIR_HL && right != PAIR_INVALID)
3524 emit2 ("add hl,%s", _pairs[right].name);
3527 else if (right == PAIR_HL && left != PAIR_INVALID)
3529 emit2 ("add hl,%s", _pairs[left].name);
3532 else if (right != PAIR_INVALID && right != PAIR_HL)
3534 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3535 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3538 else if (left != PAIR_INVALID && left != PAIR_HL)
3540 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3541 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3550 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3552 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3553 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3555 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3560 ld hl,sp+n trashes C so we cant afford to do it during an
3561 add with stack based varibles. Worst case is:
3574 So you cant afford to load up hl if either left, right, or result
3575 is on the stack (*sigh*) The alt is:
3583 Combinations in here are:
3584 * If left or right are in bc then the loss is small - trap later
3585 * If the result is in bc then the loss is also small
3589 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3590 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3591 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3593 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3594 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3595 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3596 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3598 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3600 /* Swap left and right */
3601 operand *t = IC_RIGHT (ic);
3602 IC_RIGHT (ic) = IC_LEFT (ic);
3605 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3607 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3608 emit2 ("add hl,bc");
3612 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3613 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3614 emit2 ("add hl,de");
3616 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3622 /* Be paranoid on the GB with 4 byte variables due to how C
3623 can be trashed by lda hl,n(sp).
3625 _gbz80_emitAddSubLong (ic, TRUE);
3630 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3634 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3636 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3639 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3642 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3646 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3649 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3652 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3654 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3658 freeAsmop (IC_LEFT (ic), NULL, ic);
3659 freeAsmop (IC_RIGHT (ic), NULL, ic);
3660 freeAsmop (IC_RESULT (ic), NULL, ic);
3664 /*-----------------------------------------------------------------*/
3665 /* genMinusDec :- does subtraction with deccrement if possible */
3666 /*-----------------------------------------------------------------*/
3668 genMinusDec (iCode * ic)
3670 unsigned int icount;
3671 unsigned int size = getDataSize (IC_RESULT (ic));
3673 /* will try to generate an increment */
3674 /* if the right side is not a literal we cannot */
3675 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3678 /* if the literal value of the right hand side
3679 is greater than 4 then it is not worth it */
3680 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3683 size = getDataSize (IC_RESULT (ic));
3685 /* if decrement 16 bits in register */
3686 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3687 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3690 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3694 /* If result is a pair */
3695 if (isPair (AOP (IC_RESULT (ic))))
3697 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3699 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3703 /* if increment 16 bits in register */
3704 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3708 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3711 emit2 ("dec %s", _getTempPairName());
3714 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3720 /* if the sizes are greater than 1 then we cannot */
3721 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3722 AOP_SIZE (IC_LEFT (ic)) > 1)
3725 /* we can if the aops of the left & result match or if they are in
3726 registers and the registers are the same */
3727 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3730 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3737 /*-----------------------------------------------------------------*/
3738 /* genMinus - generates code for subtraction */
3739 /*-----------------------------------------------------------------*/
3741 genMinus (iCode * ic)
3743 int size, offset = 0;
3744 unsigned long lit = 0L;
3746 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3747 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3748 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3750 /* special cases :- */
3751 /* if both left & right are in bit space */
3752 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3753 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3755 wassertl (0, "Tried to subtract two bits");
3759 /* if I can do an decrement instead of subtract then GOOD for ME */
3760 if (genMinusDec (ic) == TRUE)
3763 size = getDataSize (IC_RESULT (ic));
3765 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3770 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3774 /* Same logic as genPlus */
3777 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3778 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3779 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3781 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3782 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3783 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3784 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3786 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3787 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3789 if (left == PAIR_INVALID && right == PAIR_INVALID)
3794 else if (right == PAIR_INVALID)
3796 else if (left == PAIR_INVALID)
3799 fetchPair (left, AOP (IC_LEFT (ic)));
3800 /* Order is important. Right may be HL */
3801 fetchPair (right, AOP (IC_RIGHT (ic)));
3803 emit2 ("ld a,%s", _pairs[left].l);
3804 emit2 ("sub a,%s", _pairs[right].l);
3806 emit2 ("ld a,%s", _pairs[left].h);
3807 emit2 ("sbc a,%s", _pairs[right].h);
3809 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
3811 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3813 aopPut (AOP (IC_RESULT (ic)), "e", 0);
3819 /* Be paranoid on the GB with 4 byte variables due to how C
3820 can be trashed by lda hl,n(sp).
3822 _gbz80_emitAddSubLong (ic, FALSE);
3827 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3829 /* if literal, add a,#-lit, else normal subb */
3832 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3833 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3837 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3840 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3844 /* first add without previous c */
3846 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
3848 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3850 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3853 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3854 AOP_SIZE (IC_LEFT (ic)) == 3 &&
3855 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3857 wassertl (0, "Tried to subtract on a long pointer");
3861 freeAsmop (IC_LEFT (ic), NULL, ic);
3862 freeAsmop (IC_RIGHT (ic), NULL, ic);
3863 freeAsmop (IC_RESULT (ic), NULL, ic);
3866 /*-----------------------------------------------------------------*/
3867 /* genMult - generates code for multiplication */
3868 /*-----------------------------------------------------------------*/
3870 genMult (iCode * ic)
3874 /* If true then the final operation should be a subtract */
3875 bool active = FALSE;
3877 /* Shouldn't occur - all done through function calls */
3878 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3879 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3880 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3882 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
3883 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
3884 AOP_SIZE (IC_RESULT (ic)) > 2)
3886 wassertl (0, "Multiplication is handled through support function calls");
3889 /* Swap left and right such that right is a literal */
3890 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
3892 operand *t = IC_RIGHT (ic);
3893 IC_RIGHT (ic) = IC_LEFT (ic);
3897 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
3899 val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
3900 // wassertl (val > 0, "Multiply must be positive");
3901 wassertl (val != 1, "Can't multiply by 1");
3903 if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
3905 _G.stack.pushedDE = TRUE;
3908 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
3910 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
3918 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3923 /* Fully unroled version of mul.s. Not the most efficient.
3925 for (count = 0; count < 16; count++)
3927 if (count != 0 && active)
3929 emit2 ("add hl,hl");
3933 if (active == FALSE)
3940 emit2 ("add hl,de");
3949 if (IS_Z80 && _G.stack.pushedDE)
3952 _G.stack.pushedDE = FALSE;
3955 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3957 freeAsmop (IC_LEFT (ic), NULL, ic);
3958 freeAsmop (IC_RIGHT (ic), NULL, ic);
3959 freeAsmop (IC_RESULT (ic), NULL, ic);
3962 /*-----------------------------------------------------------------*/
3963 /* genDiv - generates code for division */
3964 /*-----------------------------------------------------------------*/
3968 /* Shouldn't occur - all done through function calls */
3969 wassertl (0, "Division is handled through support function calls");
3972 /*-----------------------------------------------------------------*/
3973 /* genMod - generates code for division */
3974 /*-----------------------------------------------------------------*/
3978 /* Shouldn't occur - all done through function calls */
3982 /*-----------------------------------------------------------------*/
3983 /* genIfxJump :- will create a jump depending on the ifx */
3984 /*-----------------------------------------------------------------*/
3986 genIfxJump (iCode * ic, char *jval)
3991 /* if true label then we jump if condition
3995 jlbl = IC_TRUE (ic);
3996 if (!strcmp (jval, "a"))
4000 else if (!strcmp (jval, "c"))
4004 else if (!strcmp (jval, "nc"))
4008 else if (!strcmp (jval, "m"))
4012 else if (!strcmp (jval, "p"))
4018 /* The buffer contains the bit on A that we should test */
4024 /* false label is present */
4025 jlbl = IC_FALSE (ic);
4026 if (!strcmp (jval, "a"))
4030 else if (!strcmp (jval, "c"))
4034 else if (!strcmp (jval, "nc"))
4038 else if (!strcmp (jval, "m"))
4042 else if (!strcmp (jval, "p"))
4048 /* The buffer contains the bit on A that we should test */
4052 /* Z80 can do a conditional long jump */
4053 if (!strcmp (jval, "a"))
4057 else if (!strcmp (jval, "c"))
4060 else if (!strcmp (jval, "nc"))
4063 else if (!strcmp (jval, "m"))
4066 else if (!strcmp (jval, "p"))
4071 emit2 ("bit %s,a", jval);
4073 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
4075 /* mark the icode as generated */
4081 _getPairIdName (PAIR_ID id)
4083 return _pairs[id].name;
4088 /* if unsigned char cmp with lit, just compare */
4090 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4092 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4095 emit2 ("xor a,!immedbyte", 0x80);
4096 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4099 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4101 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4103 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4104 // Pull left into DE and right into HL
4105 aopGet (AOP(left), LSB, FALSE);
4108 aopGet (AOP(right), LSB, FALSE);
4112 if (size == 0 && sign)
4114 // Highest byte when signed needs the bits flipped
4117 emit2 ("ld a,(de)");
4118 emit2 ("xor !immedbyte", 0x80);
4120 emit2 ("ld a,(hl)");
4121 emit2 ("xor !immedbyte", 0x80);
4125 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4129 emit2 ("ld a,(de)");
4130 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4140 spillPair (PAIR_HL);
4142 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4144 setupPair (PAIR_HL, AOP (left), 0);
4145 aopGet (AOP(right), LSB, FALSE);
4149 if (size == 0 && sign)
4151 // Highest byte when signed needs the bits flipped
4154 emit2 ("ld a,(hl)");
4155 emit2 ("xor !immedbyte", 0x80);
4157 emit2 ("ld a,%d(iy)", offset);
4158 emit2 ("xor !immedbyte", 0x80);
4162 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4166 emit2 ("ld a,(hl)");
4167 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4176 spillPair (PAIR_HL);
4177 spillPair (PAIR_IY);
4181 if (AOP_TYPE (right) == AOP_LIT)
4183 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4184 /* optimize if(x < 0) or if(x >= 0) */
4189 /* No sign so it's always false */
4194 /* Just load in the top most bit */
4195 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4196 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4198 genIfxJump (ifx, "7");
4210 /* First setup h and l contaning the top most bytes XORed */
4211 bool fDidXor = FALSE;
4212 if (AOP_TYPE (left) == AOP_LIT)
4214 unsigned long lit = (unsigned long)
4215 floatFromVal (AOP (left)->aopu.aop_lit);
4216 emit2 ("ld %s,!immedbyte", _fTmp[0],
4217 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4221 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4222 emit2 ("xor a,!immedbyte", 0x80);
4223 emit2 ("ld %s,a", _fTmp[0]);
4226 if (AOP_TYPE (right) == AOP_LIT)
4228 unsigned long lit = (unsigned long)
4229 floatFromVal (AOP (right)->aopu.aop_lit);
4230 emit2 ("ld %s,!immedbyte", _fTmp[1],
4231 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4235 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4236 emit2 ("xor a,!immedbyte", 0x80);
4237 emit2 ("ld %s,a", _fTmp[1]);
4243 /* Do a long subtract */
4246 _moveA (aopGet (AOP (left), offset, FALSE));
4248 if (sign && size == 0)
4250 emit2 ("ld a,%s", _fTmp[0]);
4251 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4255 /* Subtract through, propagating the carry */
4256 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4264 /** Generic compare for > or <
4267 genCmp (operand * left, operand * right,
4268 operand * result, iCode * ifx, int sign)
4270 int size, offset = 0;
4271 unsigned long lit = 0L;
4272 bool swap_sense = FALSE;
4274 /* if left & right are bit variables */
4275 if (AOP_TYPE (left) == AOP_CRY &&
4276 AOP_TYPE (right) == AOP_CRY)
4278 /* Cant happen on the Z80 */
4279 wassertl (0, "Tried to compare two bits");
4283 /* Do a long subtract of right from left. */
4284 size = max (AOP_SIZE (left), AOP_SIZE (right));
4286 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4288 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4289 // Pull left into DE and right into HL
4290 aopGet (AOP(left), LSB, FALSE);
4293 aopGet (AOP(right), LSB, FALSE);
4297 emit2 ("ld a,(de)");
4298 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4307 spillPair (PAIR_HL);
4311 if (AOP_TYPE (right) == AOP_LIT)
4313 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4314 /* optimize if(x < 0) or if(x >= 0) */
4319 /* No sign so it's always false */
4324 /* Just load in the top most bit */
4325 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4326 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4328 genIfxJump (ifx, "7");
4339 genIfxJump (ifx, swap_sense ? "c" : "nc");
4350 _moveA (aopGet (AOP (left), offset, FALSE));
4351 /* Subtract through, propagating the carry */
4352 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4358 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4362 /* Shift the sign bit up into carry */
4365 outBitCLong (result, swap_sense);
4369 /* if the result is used in the next
4370 ifx conditional branch then generate
4371 code a little differently */
4379 genIfxJump (ifx, swap_sense ? "nc" : "c");
4383 genIfxJump (ifx, swap_sense ? "p" : "m");
4388 genIfxJump (ifx, swap_sense ? "nc" : "c");
4395 /* Shift the sign bit up into carry */
4398 outBitCLong (result, swap_sense);
4400 /* leave the result in acc */
4404 /*-----------------------------------------------------------------*/
4405 /* genCmpGt :- greater than comparison */
4406 /*-----------------------------------------------------------------*/
4408 genCmpGt (iCode * ic, iCode * ifx)
4410 operand *left, *right, *result;
4411 sym_link *letype, *retype;
4414 left = IC_LEFT (ic);
4415 right = IC_RIGHT (ic);
4416 result = IC_RESULT (ic);
4418 letype = getSpec (operandType (left));
4419 retype = getSpec (operandType (right));
4420 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4421 /* assign the amsops */
4422 aopOp (left, ic, FALSE, FALSE);
4423 aopOp (right, ic, FALSE, FALSE);
4424 aopOp (result, ic, TRUE, FALSE);
4426 genCmp (right, left, result, ifx, sign);
4428 freeAsmop (left, NULL, ic);
4429 freeAsmop (right, NULL, ic);
4430 freeAsmop (result, NULL, ic);
4433 /*-----------------------------------------------------------------*/
4434 /* genCmpLt - less than comparisons */
4435 /*-----------------------------------------------------------------*/
4437 genCmpLt (iCode * ic, iCode * ifx)
4439 operand *left, *right, *result;
4440 sym_link *letype, *retype;
4443 left = IC_LEFT (ic);
4444 right = IC_RIGHT (ic);
4445 result = IC_RESULT (ic);
4447 letype = getSpec (operandType (left));
4448 retype = getSpec (operandType (right));
4449 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4451 /* assign the amsops */
4452 aopOp (left, ic, FALSE, FALSE);
4453 aopOp (right, ic, FALSE, FALSE);
4454 aopOp (result, ic, TRUE, FALSE);
4456 genCmp (left, right, result, ifx, sign);
4458 freeAsmop (left, NULL, ic);
4459 freeAsmop (right, NULL, ic);
4460 freeAsmop (result, NULL, ic);
4463 /*-----------------------------------------------------------------*/
4464 /* gencjneshort - compare and jump if not equal */
4465 /*-----------------------------------------------------------------*/
4467 gencjneshort (operand * left, operand * right, symbol * lbl)
4469 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4471 unsigned long lit = 0L;
4473 /* Swap the left and right if it makes the computation easier */
4474 if (AOP_TYPE (left) == AOP_LIT)
4481 if (AOP_TYPE (right) == AOP_LIT)
4483 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4486 /* if the right side is a literal then anything goes */
4487 if (AOP_TYPE (right) == AOP_LIT &&
4488 AOP_TYPE (left) != AOP_DIR)
4492 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4497 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4504 emit2 ("jp nz,!tlabel", lbl->key + 100);
4510 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4511 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
4514 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
4515 emit2 ("jp nz,!tlabel", lbl->key + 100);
4520 /* if the right side is in a register or in direct space or
4521 if the left is a pointer register & right is not */
4522 else if (AOP_TYPE (right) == AOP_REG ||
4523 AOP_TYPE (right) == AOP_DIR ||
4524 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
4528 _moveA (aopGet (AOP (left), offset, FALSE));
4529 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
4530 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4532 emit2 ("jp nz,!tlabel", lbl->key + 100);
4535 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4536 emit2 ("jp nz,!tlabel", lbl->key + 100);
4543 /* right is a pointer reg need both a & b */
4544 /* PENDING: is this required? */
4547 _moveA (aopGet (AOP (right), offset, FALSE));
4548 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
4549 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
4555 /*-----------------------------------------------------------------*/
4556 /* gencjne - compare and jump if not equal */
4557 /*-----------------------------------------------------------------*/
4559 gencjne (operand * left, operand * right, symbol * lbl)
4561 symbol *tlbl = newiTempLabel (NULL);
4563 gencjneshort (left, right, lbl);
4566 emit2 ("ld a,!one");
4567 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4568 emitLabel (lbl->key + 100);
4570 emitLabel (tlbl->key + 100);
4573 /*-----------------------------------------------------------------*/
4574 /* genCmpEq - generates code for equal to */
4575 /*-----------------------------------------------------------------*/
4577 genCmpEq (iCode * ic, iCode * ifx)
4579 operand *left, *right, *result;
4581 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4582 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4583 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4585 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4587 /* Swap operands if it makes the operation easier. ie if:
4588 1. Left is a literal.
4590 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4592 operand *t = IC_RIGHT (ic);
4593 IC_RIGHT (ic) = IC_LEFT (ic);
4597 if (ifx && !AOP_SIZE (result))
4600 /* if they are both bit variables */
4601 if (AOP_TYPE (left) == AOP_CRY &&
4602 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4604 wassertl (0, "Tried to compare two bits");
4608 tlbl = newiTempLabel (NULL);
4609 gencjneshort (left, right, tlbl);
4612 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4613 emitLabel (tlbl->key + 100);
4617 /* PENDING: do this better */
4618 symbol *lbl = newiTempLabel (NULL);
4619 emit2 ("!shortjp !tlabel", lbl->key + 100);
4620 emitLabel (tlbl->key + 100);
4621 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4622 emitLabel (lbl->key + 100);
4625 /* mark the icode as generated */
4630 /* if they are both bit variables */
4631 if (AOP_TYPE (left) == AOP_CRY &&
4632 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4634 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4640 gencjne (left, right, newiTempLabel (NULL));
4641 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4648 genIfxJump (ifx, "a");
4651 /* if the result is used in an arithmetic operation
4652 then put the result in place */
4653 if (AOP_TYPE (result) != AOP_CRY)
4658 /* leave the result in acc */
4662 freeAsmop (left, NULL, ic);
4663 freeAsmop (right, NULL, ic);
4664 freeAsmop (result, NULL, ic);
4667 /*-----------------------------------------------------------------*/
4668 /* ifxForOp - returns the icode containing the ifx for operand */
4669 /*-----------------------------------------------------------------*/
4671 ifxForOp (operand * op, iCode * ic)
4673 /* if true symbol then needs to be assigned */
4674 if (IS_TRUE_SYMOP (op))
4677 /* if this has register type condition and
4678 the next instruction is ifx with the same operand
4679 and live to of the operand is upto the ifx only then */
4681 ic->next->op == IFX &&
4682 IC_COND (ic->next)->key == op->key &&
4683 OP_SYMBOL (op)->liveTo <= ic->next->seq)
4689 /*-----------------------------------------------------------------*/
4690 /* genAndOp - for && operation */
4691 /*-----------------------------------------------------------------*/
4693 genAndOp (iCode * ic)
4695 operand *left, *right, *result;
4698 /* note here that && operations that are in an if statement are
4699 taken away by backPatchLabels only those used in arthmetic
4700 operations remain */
4701 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4702 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4703 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4705 /* if both are bit variables */
4706 if (AOP_TYPE (left) == AOP_CRY &&
4707 AOP_TYPE (right) == AOP_CRY)
4709 wassertl (0, "Tried to and two bits");
4713 tlbl = newiTempLabel (NULL);
4715 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
4717 emitLabel (tlbl->key + 100);
4721 freeAsmop (left, NULL, ic);
4722 freeAsmop (right, NULL, ic);
4723 freeAsmop (result, NULL, ic);
4726 /*-----------------------------------------------------------------*/
4727 /* genOrOp - for || operation */
4728 /*-----------------------------------------------------------------*/
4730 genOrOp (iCode * ic)
4732 operand *left, *right, *result;
4735 /* note here that || operations that are in an
4736 if statement are taken away by backPatchLabels
4737 only those used in arthmetic operations remain */
4738 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4739 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4740 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4742 /* if both are bit variables */
4743 if (AOP_TYPE (left) == AOP_CRY &&
4744 AOP_TYPE (right) == AOP_CRY)
4746 wassertl (0, "Tried to OR two bits");
4750 tlbl = newiTempLabel (NULL);
4752 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4754 emitLabel (tlbl->key + 100);
4758 freeAsmop (left, NULL, ic);
4759 freeAsmop (right, NULL, ic);
4760 freeAsmop (result, NULL, ic);
4763 /*-----------------------------------------------------------------*/
4764 /* isLiteralBit - test if lit == 2^n */
4765 /*-----------------------------------------------------------------*/
4767 isLiteralBit (unsigned long lit)
4769 unsigned long pw[32] =
4770 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
4771 0x100L, 0x200L, 0x400L, 0x800L,
4772 0x1000L, 0x2000L, 0x4000L, 0x8000L,
4773 0x10000L, 0x20000L, 0x40000L, 0x80000L,
4774 0x100000L, 0x200000L, 0x400000L, 0x800000L,
4775 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
4776 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
4779 for (idx = 0; idx < 32; idx++)
4785 /*-----------------------------------------------------------------*/
4786 /* jmpTrueOrFalse - */
4787 /*-----------------------------------------------------------------*/
4789 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
4791 // ugly but optimized by peephole
4794 symbol *nlbl = newiTempLabel (NULL);
4795 emit2 ("jp !tlabel", nlbl->key + 100);
4796 emitLabel (tlbl->key + 100);
4797 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
4798 emitLabel (nlbl->key + 100);
4802 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
4803 emitLabel (tlbl->key + 100);
4808 /*-----------------------------------------------------------------*/
4809 /* genAnd - code for and */
4810 /*-----------------------------------------------------------------*/
4812 genAnd (iCode * ic, iCode * ifx)
4814 operand *left, *right, *result;
4815 int size, offset = 0;
4816 unsigned long lit = 0L;
4819 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4820 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4821 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4823 /* if left is a literal & right is not then exchange them */
4824 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4825 AOP_NEEDSACC (left))
4827 operand *tmp = right;
4832 /* if result = right then exchange them */
4833 if (sameRegs (AOP (result), AOP (right)))
4835 operand *tmp = right;
4840 /* if right is bit then exchange them */
4841 if (AOP_TYPE (right) == AOP_CRY &&
4842 AOP_TYPE (left) != AOP_CRY)
4844 operand *tmp = right;
4848 if (AOP_TYPE (right) == AOP_LIT)
4849 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4851 size = AOP_SIZE (result);
4853 if (AOP_TYPE (left) == AOP_CRY)
4855 wassertl (0, "Tried to perform an AND with a bit as an operand");
4859 // if(val & 0xZZ) - size = 0, ifx != FALSE -
4860 // bit = val & 0xZZ - size = 1, ifx = FALSE -
4861 if ((AOP_TYPE (right) == AOP_LIT) &&
4862 (AOP_TYPE (result) == AOP_CRY) &&
4863 (AOP_TYPE (left) != AOP_CRY))
4865 symbol *tlbl = newiTempLabel (NULL);
4866 int sizel = AOP_SIZE (left);
4869 /* PENDING: Test case for this. */
4874 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
4876 _moveA (aopGet (AOP (left), offset, FALSE));
4877 if (bytelit != 0x0FFL)
4879 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4886 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4890 // bit = left & literal
4894 emit2 ("!tlabeldef", tlbl->key + 100);
4896 // if(left & literal)
4901 jmpTrueOrFalse (ifx, tlbl);
4909 /* if left is same as result */
4910 if (sameRegs (AOP (result), AOP (left)))
4912 for (; size--; offset++)
4914 if (AOP_TYPE (right) == AOP_LIT)
4916 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4921 aopPut (AOP (result), "!zero", offset);
4924 _moveA (aopGet (AOP (left), offset, FALSE));
4926 aopGet (AOP (right), offset, FALSE));
4927 aopPut (AOP (left), "a", offset);
4934 if (AOP_TYPE (left) == AOP_ACC)
4936 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
4940 _moveA (aopGet (AOP (left), offset, FALSE));
4942 aopGet (AOP (right), offset, FALSE));
4943 aopPut (AOP (left), "a", offset);
4950 // left & result in different registers
4951 if (AOP_TYPE (result) == AOP_CRY)
4953 wassertl (0, "Tried to AND where the result is in carry");
4957 for (; (size--); offset++)
4960 // result = left & right
4961 if (AOP_TYPE (right) == AOP_LIT)
4963 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4965 aopPut (AOP (result),
4966 aopGet (AOP (left), offset, FALSE),
4970 else if (bytelit == 0)
4972 aopPut (AOP (result), "!zero", offset);
4976 // faster than result <- left, anl result,right
4977 // and better if result is SFR
4978 if (AOP_TYPE (left) == AOP_ACC)
4979 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4982 _moveA (aopGet (AOP (left), offset, FALSE));
4984 aopGet (AOP (right), offset, FALSE));
4986 aopPut (AOP (result), "a", offset);
4993 freeAsmop (left, NULL, ic);
4994 freeAsmop (right, NULL, ic);
4995 freeAsmop (result, NULL, ic);
4998 /*-----------------------------------------------------------------*/
4999 /* genOr - code for or */
5000 /*-----------------------------------------------------------------*/
5002 genOr (iCode * ic, iCode * ifx)
5004 operand *left, *right, *result;
5005 int size, offset = 0;
5006 unsigned long lit = 0L;
5009 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5010 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5011 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5013 /* if left is a literal & right is not then exchange them */
5014 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5015 AOP_NEEDSACC (left))
5017 operand *tmp = right;
5022 /* if result = right then exchange them */
5023 if (sameRegs (AOP (result), AOP (right)))
5025 operand *tmp = right;
5030 /* if right is bit then exchange them */
5031 if (AOP_TYPE (right) == AOP_CRY &&
5032 AOP_TYPE (left) != AOP_CRY)
5034 operand *tmp = right;
5038 if (AOP_TYPE (right) == AOP_LIT)
5039 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5041 size = AOP_SIZE (result);
5043 if (AOP_TYPE (left) == AOP_CRY)
5045 wassertl (0, "Tried to OR where left is a bit");
5049 // if(val | 0xZZ) - size = 0, ifx != FALSE -
5050 // bit = val | 0xZZ - size = 1, ifx = FALSE -
5051 if ((AOP_TYPE (right) == AOP_LIT) &&
5052 (AOP_TYPE (result) == AOP_CRY) &&
5053 (AOP_TYPE (left) != AOP_CRY))
5055 symbol *tlbl = newiTempLabel (NULL);
5056 int sizel = AOP_SIZE (left);
5060 wassertl (0, "Result is assigned to a bit");
5062 /* PENDING: Modeled after the AND code which is inefficent. */
5065 bytelit = (lit >> (offset * 8)) & 0x0FFL;
5067 _moveA (aopGet (AOP (left), offset, FALSE));
5068 /* OR with any literal is the same as OR with itself. */
5070 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5076 jmpTrueOrFalse (ifx, tlbl);
5081 /* if left is same as result */
5082 if (sameRegs (AOP (result), AOP (left)))
5084 for (; size--; offset++)
5086 if (AOP_TYPE (right) == AOP_LIT)
5088 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5092 _moveA (aopGet (AOP (left), offset, FALSE));
5094 aopGet (AOP (right), offset, FALSE));
5095 aopPut (AOP (result), "a", offset);
5100 if (AOP_TYPE (left) == AOP_ACC)
5101 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5104 _moveA (aopGet (AOP (left), offset, FALSE));
5106 aopGet (AOP (right), offset, FALSE));
5107 aopPut (AOP (result), "a", offset);
5114 // left & result in different registers
5115 if (AOP_TYPE (result) == AOP_CRY)
5117 wassertl (0, "Result of OR is in a bit");
5120 for (; (size--); offset++)
5123 // result = left & right
5124 if (AOP_TYPE (right) == AOP_LIT)
5126 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5128 aopPut (AOP (result),
5129 aopGet (AOP (left), offset, FALSE),
5134 // faster than result <- left, anl result,right
5135 // and better if result is SFR
5136 if (AOP_TYPE (left) == AOP_ACC)
5137 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5140 _moveA (aopGet (AOP (left), offset, FALSE));
5142 aopGet (AOP (right), offset, FALSE));
5144 aopPut (AOP (result), "a", offset);
5145 /* PENDING: something weird is going on here. Add exception. */
5146 if (AOP_TYPE (result) == AOP_ACC)
5152 freeAsmop (left, NULL, ic);
5153 freeAsmop (right, NULL, ic);
5154 freeAsmop (result, NULL, ic);
5157 /*-----------------------------------------------------------------*/
5158 /* genXor - code for xclusive or */
5159 /*-----------------------------------------------------------------*/
5161 genXor (iCode * ic, iCode * ifx)
5163 operand *left, *right, *result;
5164 int size, offset = 0;
5165 unsigned long lit = 0L;
5167 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5168 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5169 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5171 /* if left is a literal & right is not then exchange them */
5172 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5173 AOP_NEEDSACC (left))
5175 operand *tmp = right;
5180 /* if result = right then exchange them */
5181 if (sameRegs (AOP (result), AOP (right)))
5183 operand *tmp = right;
5188 /* if right is bit then exchange them */
5189 if (AOP_TYPE (right) == AOP_CRY &&
5190 AOP_TYPE (left) != AOP_CRY)
5192 operand *tmp = right;
5196 if (AOP_TYPE (right) == AOP_LIT)
5197 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5199 size = AOP_SIZE (result);
5201 if (AOP_TYPE (left) == AOP_CRY)
5203 wassertl (0, "Tried to XOR a bit");
5207 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5208 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5209 if ((AOP_TYPE (right) == AOP_LIT) &&
5210 (AOP_TYPE (result) == AOP_CRY) &&
5211 (AOP_TYPE (left) != AOP_CRY))
5213 symbol *tlbl = newiTempLabel (NULL);
5214 int sizel = AOP_SIZE (left);
5218 /* PENDING: Test case for this. */
5219 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5223 _moveA (aopGet (AOP (left), offset, FALSE));
5224 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5225 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5230 jmpTrueOrFalse (ifx, tlbl);
5234 wassertl (0, "Result of XOR was destined for a bit");
5239 /* if left is same as result */
5240 if (sameRegs (AOP (result), AOP (left)))
5242 for (; size--; offset++)
5244 if (AOP_TYPE (right) == AOP_LIT)
5246 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5250 _moveA (aopGet (AOP (right), offset, FALSE));
5252 aopGet (AOP (left), offset, FALSE));
5253 aopPut (AOP (result), "a", offset);
5258 if (AOP_TYPE (left) == AOP_ACC)
5260 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5264 _moveA (aopGet (AOP (right), offset, FALSE));
5266 aopGet (AOP (left), offset, FALSE));
5267 aopPut (AOP (result), "a", offset);
5274 // left & result in different registers
5275 if (AOP_TYPE (result) == AOP_CRY)
5277 wassertl (0, "Result of XOR is in a bit");
5280 for (; (size--); offset++)
5283 // result = left & right
5284 if (AOP_TYPE (right) == AOP_LIT)
5286 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5288 aopPut (AOP (result),
5289 aopGet (AOP (left), offset, FALSE),
5294 // faster than result <- left, anl result,right
5295 // and better if result is SFR
5296 if (AOP_TYPE (left) == AOP_ACC)
5298 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5302 _moveA (aopGet (AOP (right), offset, FALSE));
5304 aopGet (AOP (left), offset, FALSE));
5306 aopPut (AOP (result), "a", offset);
5311 freeAsmop (left, NULL, ic);
5312 freeAsmop (right, NULL, ic);
5313 freeAsmop (result, NULL, ic);
5316 /*-----------------------------------------------------------------*/
5317 /* genInline - write the inline code out */
5318 /*-----------------------------------------------------------------*/
5320 genInline (iCode * ic)
5322 char *buffer, *bp, *bp1;
5324 _G.lines.isInline += (!options.asmpeep);
5326 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5327 strcpy (buffer, IC_INLINE (ic));
5329 /* emit each line as a code */
5354 _G.lines.isInline -= (!options.asmpeep);
5358 /*-----------------------------------------------------------------*/
5359 /* genRRC - rotate right with carry */
5360 /*-----------------------------------------------------------------*/
5367 /*-----------------------------------------------------------------*/
5368 /* genRLC - generate code for rotate left with carry */
5369 /*-----------------------------------------------------------------*/
5376 /*-----------------------------------------------------------------*/
5377 /* genGetHbit - generates code get highest order bit */
5378 /*-----------------------------------------------------------------*/
5380 genGetHbit (iCode * ic)
5382 operand *left, *result;
5383 left = IC_LEFT (ic);
5384 result = IC_RESULT (ic);
5386 aopOp (left, ic, FALSE, FALSE);
5387 aopOp (result, ic, FALSE, FALSE);
5389 /* get the highest order byte into a */
5390 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5392 if (AOP_TYPE (result) == AOP_CRY)
5400 emit2 ("and a,!one");
5405 freeAsmop (left, NULL, ic);
5406 freeAsmop (result, NULL, ic);
5410 emitRsh2 (asmop *aop, int size, int is_signed)
5416 const char *l = aopGet (aop, size, FALSE);
5419 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5429 /*-----------------------------------------------------------------*/
5430 /* shiftR2Left2Result - shift right two bytes from left to result */
5431 /*-----------------------------------------------------------------*/
5433 shiftR2Left2Result (operand * left, int offl,
5434 operand * result, int offr,
5435 int shCount, int is_signed)
5438 symbol *tlbl, *tlbl1;
5440 movLeft2Result (left, offl, result, offr, 0);
5441 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5443 /* if (AOP(result)->type == AOP_REG) { */
5445 tlbl = newiTempLabel (NULL);
5446 tlbl1 = newiTempLabel (NULL);
5448 /* Left is already in result - so now do the shift */
5453 emitRsh2 (AOP (result), size, is_signed);
5458 emit2 ("ld a,!immedbyte+1", shCount);
5459 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5460 emitLabel (tlbl->key + 100);
5462 emitRsh2 (AOP (result), size, is_signed);
5464 emitLabel (tlbl1->key + 100);
5466 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5470 /*-----------------------------------------------------------------*/
5471 /* shiftL2Left2Result - shift left two bytes from left to result */
5472 /*-----------------------------------------------------------------*/
5474 shiftL2Left2Result (operand * left, int offl,
5475 operand * result, int offr, int shCount)
5477 if (sameRegs (AOP (result), AOP (left)) &&
5478 ((offl + MSB16) == offr))
5484 /* Copy left into result */
5485 movLeft2Result (left, offl, result, offr, 0);
5486 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5489 if (getPairId (AOP (result)) == PAIR_HL)
5493 emit2 ("add hl,hl");
5500 symbol *tlbl, *tlbl1;
5503 tlbl = newiTempLabel (NULL);
5504 tlbl1 = newiTempLabel (NULL);
5506 if (AOP (result)->type == AOP_REG)
5510 for (offset = 0; offset < size; offset++)
5512 l = aopGet (AOP (result), offset, FALSE);
5516 emit2 ("sla %s", l);
5527 /* Left is already in result - so now do the shift */
5530 emit2 ("ld a,!immedbyte+1", shCount);
5531 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5532 emitLabel (tlbl->key + 100);
5537 l = aopGet (AOP (result), offset, FALSE);
5541 emit2 ("sla %s", l);
5552 emitLabel (tlbl1->key + 100);
5554 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5560 /*-----------------------------------------------------------------*/
5561 /* AccRol - rotate left accumulator by known count */
5562 /*-----------------------------------------------------------------*/
5564 AccRol (int shCount)
5566 shCount &= 0x0007; // shCount : 0..7
5643 /*-----------------------------------------------------------------*/
5644 /* AccLsh - left shift accumulator by known count */
5645 /*-----------------------------------------------------------------*/
5647 AccLsh (int shCount)
5649 static const unsigned char SLMask[] =
5651 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5660 else if (shCount == 2)
5667 /* rotate left accumulator */
5669 /* and kill the lower order bits */
5670 emit2 ("and a,!immedbyte", SLMask[shCount]);
5675 /*-----------------------------------------------------------------*/
5676 /* shiftL1Left2Result - shift left one byte from left to result */
5677 /*-----------------------------------------------------------------*/
5679 shiftL1Left2Result (operand * left, int offl,
5680 operand * result, int offr, int shCount)
5683 l = aopGet (AOP (left), offl, FALSE);
5685 /* shift left accumulator */
5687 aopPut (AOP (result), "a", offr);
5691 /*-----------------------------------------------------------------*/
5692 /* genlshTwo - left shift two bytes by known amount != 0 */
5693 /*-----------------------------------------------------------------*/
5695 genlshTwo (operand * result, operand * left, int shCount)
5697 int size = AOP_SIZE (result);
5699 wassert (size == 2);
5701 /* if shCount >= 8 */
5709 movLeft2Result (left, LSB, result, MSB16, 0);
5710 aopPut (AOP (result), "!zero", 0);
5711 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
5715 movLeft2Result (left, LSB, result, MSB16, 0);
5716 aopPut (AOP (result), "!zero", 0);
5721 aopPut (AOP (result), "!zero", LSB);
5724 /* 1 <= shCount <= 7 */
5733 shiftL2Left2Result (left, LSB, result, LSB, shCount);
5738 /*-----------------------------------------------------------------*/
5739 /* genlshOne - left shift a one byte quantity by known count */
5740 /*-----------------------------------------------------------------*/
5742 genlshOne (operand * result, operand * left, int shCount)
5744 shiftL1Left2Result (left, LSB, result, LSB, shCount);
5747 /*-----------------------------------------------------------------*/
5748 /* genLeftShiftLiteral - left shifting by known count */
5749 /*-----------------------------------------------------------------*/
5751 genLeftShiftLiteral (operand * left,
5756 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5759 freeAsmop (right, NULL, ic);
5761 aopOp (left, ic, FALSE, FALSE);
5762 aopOp (result, ic, FALSE, FALSE);
5764 size = getSize (operandType (result));
5766 /* I suppose that the left size >= result size */
5772 else if (shCount >= (size * 8))
5776 aopPut (AOP (result), "!zero", size);
5784 genlshOne (result, left, shCount);
5787 genlshTwo (result, left, shCount);
5790 wassertl (0, "Shifting of longs is currently unsupported");
5796 freeAsmop (left, NULL, ic);
5797 freeAsmop (result, NULL, ic);
5800 /*-----------------------------------------------------------------*/
5801 /* genLeftShift - generates code for left shifting */
5802 /*-----------------------------------------------------------------*/
5804 genLeftShift (iCode * ic)
5808 symbol *tlbl, *tlbl1;
5809 operand *left, *right, *result;
5811 right = IC_RIGHT (ic);
5812 left = IC_LEFT (ic);
5813 result = IC_RESULT (ic);
5815 aopOp (right, ic, FALSE, FALSE);
5817 /* if the shift count is known then do it
5818 as efficiently as possible */
5819 if (AOP_TYPE (right) == AOP_LIT)
5821 genLeftShiftLiteral (left, right, result, ic);
5825 /* shift count is unknown then we have to form a loop get the loop
5826 count in B : Note: we take only the lower order byte since
5827 shifting more that 32 bits make no sense anyway, ( the largest
5828 size of an object can be only 32 bits ) */
5829 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5831 freeAsmop (right, NULL, ic);
5832 aopOp (left, ic, FALSE, FALSE);
5833 aopOp (result, ic, FALSE, FALSE);
5835 /* now move the left to the result if they are not the
5838 if (!sameRegs (AOP (left), AOP (result)))
5841 size = AOP_SIZE (result);
5845 l = aopGet (AOP (left), offset, FALSE);
5846 aopPut (AOP (result), l, offset);
5851 tlbl = newiTempLabel (NULL);
5852 size = AOP_SIZE (result);
5854 tlbl1 = newiTempLabel (NULL);
5856 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5857 emitLabel (tlbl->key + 100);
5858 l = aopGet (AOP (result), offset, FALSE);
5862 l = aopGet (AOP (result), offset, FALSE);
5866 emit2 ("sla %s", l);
5874 emitLabel (tlbl1->key + 100);
5876 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5878 freeAsmop (left, NULL, ic);
5879 freeAsmop (result, NULL, ic);
5882 /*-----------------------------------------------------------------*/
5883 /* genrshOne - left shift two bytes by known amount != 0 */
5884 /*-----------------------------------------------------------------*/
5886 genrshOne (operand * result, operand * left, int shCount, int is_signed)
5889 int size = AOP_SIZE (result);
5892 wassert (size == 1);
5893 wassert (shCount < 8);
5895 l = aopGet (AOP (left), 0, FALSE);
5897 if (AOP (result)->type == AOP_REG)
5899 aopPut (AOP (result), l, 0);
5900 l = aopGet (AOP (result), 0, FALSE);
5903 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5911 emit2 ("%s a", is_signed ? "sra" : "srl");
5913 aopPut (AOP (result), "a", 0);
5917 /*-----------------------------------------------------------------*/
5918 /* AccRsh - right shift accumulator by known count */
5919 /*-----------------------------------------------------------------*/
5921 AccRsh (int shCount)
5923 static const unsigned char SRMask[] =
5925 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
5930 /* rotate right accumulator */
5931 AccRol (8 - shCount);
5932 /* and kill the higher order bits */
5933 emit2 ("and a,!immedbyte", SRMask[shCount]);
5937 /*-----------------------------------------------------------------*/
5938 /* shiftR1Left2Result - shift right one byte from left to result */
5939 /*-----------------------------------------------------------------*/
5941 shiftR1Left2Result (operand * left, int offl,
5942 operand * result, int offr,
5943 int shCount, int sign)
5945 _moveA (aopGet (AOP (left), offl, FALSE));
5950 emit2 ("%s a", sign ? "sra" : "srl");
5957 aopPut (AOP (result), "a", offr);
5960 /*-----------------------------------------------------------------*/
5961 /* genrshTwo - right shift two bytes by known amount != 0 */
5962 /*-----------------------------------------------------------------*/
5964 genrshTwo (operand * result, operand * left,
5965 int shCount, int sign)
5967 /* if shCount >= 8 */
5973 shiftR1Left2Result (left, MSB16, result, LSB,
5978 movLeft2Result (left, MSB16, result, LSB, sign);
5982 /* Sign extend the result */
5983 _moveA(aopGet (AOP (result), 0, FALSE));
5987 aopPut (AOP (result), ACC_NAME, MSB16);
5991 aopPut (AOP (result), "!zero", 1);
5994 /* 1 <= shCount <= 7 */
5997 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
6001 /*-----------------------------------------------------------------*/
6002 /* genRightShiftLiteral - left shifting by known count */
6003 /*-----------------------------------------------------------------*/
6005 genRightShiftLiteral (operand * left,
6011 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6014 freeAsmop (right, NULL, ic);
6016 aopOp (left, ic, FALSE, FALSE);
6017 aopOp (result, ic, FALSE, FALSE);
6019 size = getSize (operandType (result));
6021 /* I suppose that the left size >= result size */
6027 else if (shCount >= (size * 8)) {
6029 if (!SPEC_USIGN(getSpec(operandType(left)))) {
6030 _moveA(aopGet (AOP (left), 0, FALSE));
6038 aopPut (AOP (result), s, size);
6045 genrshOne (result, left, shCount, sign);
6048 genrshTwo (result, left, shCount, sign);
6051 wassertl (0, "Asked to shift right a long which should be a function call");
6054 wassertl (0, "Entered default case in right shift delegate");
6057 freeAsmop (left, NULL, ic);
6058 freeAsmop (result, NULL, ic);
6061 /*-----------------------------------------------------------------*/
6062 /* genRightShift - generate code for right shifting */
6063 /*-----------------------------------------------------------------*/
6065 genRightShift (iCode * ic)
6067 operand *right, *left, *result;
6069 int size, offset, first = 1;
6073 symbol *tlbl, *tlbl1;
6075 /* if signed then we do it the hard way preserve the
6076 sign bit moving it inwards */
6077 retype = getSpec (operandType (IC_RESULT (ic)));
6079 is_signed = !SPEC_USIGN (retype);
6081 /* signed & unsigned types are treated the same : i.e. the
6082 signed is NOT propagated inwards : quoting from the
6083 ANSI - standard : "for E1 >> E2, is equivalent to division
6084 by 2**E2 if unsigned or if it has a non-negative value,
6085 otherwise the result is implementation defined ", MY definition
6086 is that the sign does not get propagated */
6088 right = IC_RIGHT (ic);
6089 left = IC_LEFT (ic);
6090 result = IC_RESULT (ic);
6092 aopOp (right, ic, FALSE, FALSE);
6094 /* if the shift count is known then do it
6095 as efficiently as possible */
6096 if (AOP_TYPE (right) == AOP_LIT)
6098 genRightShiftLiteral (left, right, result, ic, is_signed);
6102 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6104 freeAsmop (right, NULL, ic);
6106 aopOp (left, ic, FALSE, FALSE);
6107 aopOp (result, ic, FALSE, FALSE);
6109 /* now move the left to the result if they are not the
6111 if (!sameRegs (AOP (left), AOP (result)))
6114 size = AOP_SIZE (result);
6118 l = aopGet (AOP (left), offset, FALSE);
6119 aopPut (AOP (result), l, offset);
6124 tlbl = newiTempLabel (NULL);
6125 tlbl1 = newiTempLabel (NULL);
6126 size = AOP_SIZE (result);
6129 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6130 emitLabel (tlbl->key + 100);
6133 l = aopGet (AOP (result), offset--, FALSE);
6136 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6144 emitLabel (tlbl1->key + 100);
6146 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6148 freeAsmop (left, NULL, ic);
6149 freeAsmop (result, NULL, ic);
6153 /*-----------------------------------------------------------------*/
6154 /* genUnpackBits - generates code for unpacking bits */
6155 /*-----------------------------------------------------------------*/
6157 genUnpackBits (operand * result, int pair)
6159 int offset = 0; /* result byte offset */
6160 int rsize; /* result size */
6161 int rlen = 0; /* remaining bitfield length */
6162 sym_link *etype; /* bitfield type information */
6163 int blen; /* bitfield length */
6164 int bstr; /* bitfield starting bit within byte */
6166 emitDebug ("; genUnpackBits");
6168 etype = getSpec (operandType (result));
6169 rsize = getSize (operandType (result));
6170 blen = SPEC_BLEN (etype);
6171 bstr = SPEC_BSTR (etype);
6173 /* If the bitfield length is less than a byte */
6176 emit2 ("ld a,!*pair", _pairs[pair].name);
6178 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6179 aopPut (AOP (result), "a", offset++);
6183 /* TODO: what if pair == PAIR_DE ? */
6184 if (getPairId (AOP (result)) == PAIR_HL)
6186 wassertl (rsize == 2, "HL must be of size 2");
6187 emit2 ("ld a,!*hl");
6189 emit2 ("ld h,!*hl");
6192 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6194 spillPair (PAIR_HL);
6198 /* Bit field did not fit in a byte. Copy all
6199 but the partial byte at the end. */
6200 for (rlen=blen;rlen>=8;rlen-=8)
6202 emit2 ("ld a,!*pair", _pairs[pair].name);
6203 aopPut (AOP (result), "a", offset++);
6206 emit2 ("inc %s", _pairs[pair].name);
6207 _G.pairs[pair].offset++;
6211 /* Handle the partial byte at the end */
6214 emit2 ("ld a,!*pair", _pairs[pair].name);
6215 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6216 aopPut (AOP (result), "a", offset++);
6224 aopPut (AOP (result), "!zero", offset++);
6228 /*-----------------------------------------------------------------*/
6229 /* genGenPointerGet - get value from generic pointer space */
6230 /*-----------------------------------------------------------------*/
6232 genGenPointerGet (operand * left,
6233 operand * result, iCode * ic)
6236 sym_link *retype = getSpec (operandType (result));
6242 aopOp (left, ic, FALSE, FALSE);
6243 aopOp (result, ic, FALSE, FALSE);
6245 size = AOP_SIZE (result);
6247 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6250 if (isPtrPair (AOP (left)))
6252 tsprintf (buffer, sizeof(buffer),
6253 "!*pair", getPairName (AOP (left)));
6254 aopPut (AOP (result), buffer, 0);
6258 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6259 aopPut (AOP (result), "a", 0);
6261 freeAsmop (left, NULL, ic);
6265 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6272 tsprintf (at, sizeof(at), "!*iyx", offset);
6273 aopPut (AOP (result), at, offset);
6277 freeAsmop (left, NULL, ic);
6281 /* For now we always load into IY */
6282 /* if this is remateriazable */
6283 fetchPair (pair, AOP (left));
6285 /* if bit then unpack */
6286 if (IS_BITVAR (retype))
6288 genUnpackBits (result, pair);
6289 freeAsmop (left, NULL, ic);
6293 else if (getPairId (AOP (result)) == PAIR_HL)
6295 wassertl (size == 2, "HL must be of size 2");
6296 emit2 ("ld a,!*hl");
6298 emit2 ("ld h,!*hl");
6300 spillPair (PAIR_HL);
6302 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6304 size = AOP_SIZE (result);
6309 /* PENDING: make this better */
6310 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6312 aopPut (AOP (result), "!*hl", offset++);
6316 emit2 ("ld a,!*pair", _pairs[pair].name);
6317 aopPut (AOP (result), "a", offset++);
6321 emit2 ("inc %s", _pairs[pair].name);
6322 _G.pairs[pair].offset++;
6325 /* Fixup HL back down */
6326 for (size = AOP_SIZE (result)-1; size; size--)
6328 emit2 ("dec %s", _pairs[pair].name);
6333 size = AOP_SIZE (result);
6338 /* PENDING: make this better */
6340 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6342 aopPut (AOP (result), "!*hl", offset++);
6346 emit2 ("ld a,!*pair", _pairs[pair].name);
6347 aopPut (AOP (result), "a", offset++);
6351 emit2 ("inc %s", _pairs[pair].name);
6352 _G.pairs[pair].offset++;
6357 freeAsmop (left, NULL, ic);
6360 freeAsmop (result, NULL, ic);
6363 /*-----------------------------------------------------------------*/
6364 /* genPointerGet - generate code for pointer get */
6365 /*-----------------------------------------------------------------*/
6367 genPointerGet (iCode * ic)
6369 operand *left, *result;
6370 sym_link *type, *etype;
6372 left = IC_LEFT (ic);
6373 result = IC_RESULT (ic);
6375 /* depending on the type of pointer we need to
6376 move it to the correct pointer register */
6377 type = operandType (left);
6378 etype = getSpec (type);
6380 genGenPointerGet (left, result, ic);
6384 isRegOrLit (asmop * aop)
6386 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6392 /*-----------------------------------------------------------------*/
6393 /* genPackBits - generates code for packed bit storage */
6394 /*-----------------------------------------------------------------*/
6396 genPackBits (sym_link * etype,
6401 int offset = 0; /* source byte offset */
6402 int rlen = 0; /* remaining bitfield length */
6403 int blen; /* bitfield length */
6404 int bstr; /* bitfield starting bit within byte */
6405 int litval; /* source literal value (if AOP_LIT) */
6406 unsigned char mask; /* bitmask within current byte */
6407 int extraPair; /* a tempory register */
6408 bool needPopExtra=0; /* need to restore original value of temp reg */
6410 emitDebug ("; genPackBits","");
6412 blen = SPEC_BLEN (etype);
6413 bstr = SPEC_BSTR (etype);
6415 /* If the bitfield length is less than a byte */
6418 mask = ((unsigned char) (0xFF << (blen + bstr)) |
6419 (unsigned char) (0xFF >> (8 - bstr)));
6421 if (AOP_TYPE (right) == AOP_LIT)
6423 /* Case with a bitfield length <8 and literal source
6425 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6427 litval &= (~mask) & 0xff;
6428 emit2 ("ld a,!*pair", _pairs[pair].name);
6429 if ((mask|litval)!=0xff)
6430 emit2 ("and a,!immedbyte", mask);
6432 emit2 ("or a,!immedbyte", litval);
6433 emit2 ("ld !*pair,a", _pairs[pair].name);
6438 /* Case with a bitfield length <8 and arbitrary source
6440 _moveA (aopGet (AOP (right), 0, FALSE));
6441 /* shift and mask source value */
6443 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6445 extraPair = getFreePairId(ic);
6446 if (extraPair == PAIR_INVALID)
6448 extraPair = PAIR_BC;
6449 if (getPairId (AOP (right)) != PAIR_BC
6450 || !isLastUse (ic, right))
6456 emit2 ("ld %s,a", _pairs[extraPair].l);
6457 emit2 ("ld a,!*pair", _pairs[pair].name);
6459 emit2 ("and a,!immedbyte", mask);
6460 emit2 ("or a,%s", _pairs[extraPair].l);
6461 emit2 ("ld !*pair,a", _pairs[pair].name);
6468 /* Bit length is greater than 7 bits. In this case, copy */
6469 /* all except the partial byte at the end */
6470 for (rlen=blen;rlen>=8;rlen-=8)
6472 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
6473 emit2 ("ld !*pair,a", _pairs[pair].name);
6476 emit2 ("inc %s", _pairs[pair].name);
6477 _G.pairs[pair].offset++;
6481 /* If there was a partial byte at the end */
6484 mask = (((unsigned char) -1 << rlen) & 0xff);
6486 if (AOP_TYPE (right) == AOP_LIT)
6488 /* Case with partial byte and literal source
6490 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6491 litval >>= (blen-rlen);
6492 litval &= (~mask) & 0xff;
6493 emit2 ("ld a,!*pair", _pairs[pair].name);
6494 if ((mask|litval)!=0xff)
6495 emit2 ("and a,!immedbyte", mask);
6497 emit2 ("or a,!immedbyte", litval);
6501 /* Case with partial byte and arbitrary source
6503 _moveA (aopGet (AOP (right), offset++, FALSE));
6504 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6506 extraPair = getFreePairId(ic);
6507 if (extraPair == PAIR_INVALID)
6509 extraPair = getPairId (AOP (right));
6510 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
6511 extraPair = PAIR_BC;
6513 if (getPairId (AOP (right)) != PAIR_BC
6514 || !isLastUse (ic, right))
6520 emit2 ("ld %s,a", _pairs[extraPair].l);
6521 emit2 ("ld a,!*pair", _pairs[pair].name);
6523 emit2 ("and a,!immedbyte", mask);
6524 emit2 ("or a,%s", _pairs[extraPair].l);
6529 emit2 ("ld !*pair,a", _pairs[pair].name);
6534 /*-----------------------------------------------------------------*/
6535 /* genGenPointerSet - stores the value into a pointer location */
6536 /*-----------------------------------------------------------------*/
6538 genGenPointerSet (operand * right,
6539 operand * result, iCode * ic)
6542 sym_link *retype = getSpec (operandType (right));
6543 sym_link *letype = getSpec (operandType (result));
6544 PAIR_ID pairId = PAIR_HL;
6547 aopOp (result, ic, FALSE, FALSE);
6548 aopOp (right, ic, FALSE, FALSE);
6553 size = AOP_SIZE (right);
6555 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
6556 emitDebug("; isBitvar = %d", isBitvar);
6558 /* Handle the exceptions first */
6559 if (isPair (AOP (result)) && size == 1 && !isBitvar)
6562 const char *l = aopGet (AOP (right), 0, FALSE);
6563 const char *pair = getPairName (AOP (result));
6564 if (canAssignToPtr (l) && isPtr (pair))
6566 emit2 ("ld !*pair,%s", pair, l);
6571 emit2 ("ld !*pair,a", pair);
6576 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
6579 const char *l = aopGet (AOP (right), 0, FALSE);
6584 if (canAssignToPtr (l))
6586 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6590 _moveA (aopGet (AOP (right), offset, FALSE));
6591 emit2 ("ld !*iyx,a", offset);
6597 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
6604 const char *l = aopGet (AOP (right), offset, FALSE);
6605 if (isRegOrLit (AOP (right)) && !IS_GB)
6607 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
6612 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
6616 emit2 ("inc %s", _pairs[PAIR_HL].name);
6617 _G.pairs[PAIR_HL].offset++;
6622 /* Fixup HL back down */
6623 for (size = AOP_SIZE (right)-1; size; size--)
6625 emit2 ("dec %s", _pairs[PAIR_HL].name);
6630 /* if the operand is already in dptr
6631 then we do nothing else we move the value to dptr */
6632 if (AOP_TYPE (result) != AOP_STR)
6634 fetchPair (pairId, AOP (result));
6636 /* so hl know contains the address */
6637 freeAsmop (result, NULL, ic);
6639 /* if bit then unpack */
6642 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
6652 const char *l = aopGet (AOP (right), offset, FALSE);
6653 if (isRegOrLit (AOP (right)) && !IS_GB)
6655 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
6660 emit2 ("ld !*pair,a", _pairs[pairId].name);
6664 emit2 ("inc %s", _pairs[pairId].name);
6665 _G.pairs[pairId].offset++;
6671 freeAsmop (right, NULL, ic);
6674 /*-----------------------------------------------------------------*/
6675 /* genPointerSet - stores the value into a pointer location */
6676 /*-----------------------------------------------------------------*/
6678 genPointerSet (iCode * ic)
6680 operand *right, *result;
6681 sym_link *type, *etype;
6683 right = IC_RIGHT (ic);
6684 result = IC_RESULT (ic);
6686 /* depending on the type of pointer we need to
6687 move it to the correct pointer register */
6688 type = operandType (result);
6689 etype = getSpec (type);
6691 genGenPointerSet (right, result, ic);
6694 /*-----------------------------------------------------------------*/
6695 /* genIfx - generate code for Ifx statement */
6696 /*-----------------------------------------------------------------*/
6698 genIfx (iCode * ic, iCode * popIc)
6700 operand *cond = IC_COND (ic);
6703 aopOp (cond, ic, FALSE, TRUE);
6705 /* get the value into acc */
6706 if (AOP_TYPE (cond) != AOP_CRY)
6710 /* the result is now in the accumulator */
6711 freeAsmop (cond, NULL, ic);
6713 /* if there was something to be popped then do it */
6717 /* if the condition is a bit variable */
6718 if (isbit && IS_ITEMP (cond) &&
6720 genIfxJump (ic, SPIL_LOC (cond)->rname);
6721 else if (isbit && !IS_ITEMP (cond))
6722 genIfxJump (ic, OP_SYMBOL (cond)->rname);
6724 genIfxJump (ic, "a");
6729 /*-----------------------------------------------------------------*/
6730 /* genAddrOf - generates code for address of */
6731 /*-----------------------------------------------------------------*/
6733 genAddrOf (iCode * ic)
6735 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
6737 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6739 /* if the operand is on the stack then we
6740 need to get the stack offset of this
6747 if (sym->stack <= 0)
6749 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
6753 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6755 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6759 emit2 ("ld de,!hashedstr", sym->rname);
6760 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
6768 /* if it has an offset then we need to compute it */
6770 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6772 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
6773 emit2 ("add hl,sp");
6777 emit2 ("ld hl,!hashedstr", sym->rname);
6779 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6781 freeAsmop (IC_RESULT (ic), NULL, ic);
6784 /*-----------------------------------------------------------------*/
6785 /* genAssign - generate code for assignment */
6786 /*-----------------------------------------------------------------*/
6788 genAssign (iCode * ic)
6790 operand *result, *right;
6792 unsigned long lit = 0L;
6794 result = IC_RESULT (ic);
6795 right = IC_RIGHT (ic);
6797 /* Dont bother assigning if they are the same */
6798 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6800 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
6804 aopOp (right, ic, FALSE, FALSE);
6805 aopOp (result, ic, TRUE, FALSE);
6807 /* if they are the same registers */
6808 if (sameRegs (AOP (right), AOP (result)))
6810 emitDebug ("; (registers are the same)");
6814 /* if the result is a bit */
6815 if (AOP_TYPE (result) == AOP_CRY)
6817 wassertl (0, "Tried to assign to a bit");
6821 size = AOP_SIZE (result);
6824 if (AOP_TYPE (right) == AOP_LIT)
6826 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6829 if (isPair (AOP (result)))
6831 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
6833 else if ((size > 1) &&
6834 (AOP_TYPE (result) != AOP_REG) &&
6835 (AOP_TYPE (right) == AOP_LIT) &&
6836 !IS_FLOAT (operandType (right)) &&
6839 bool fXored = FALSE;
6841 /* Work from the top down.
6842 Done this way so that we can use the cached copy of 0
6843 in A for a fast clear */
6846 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
6848 if (!fXored && size > 1)
6855 aopPut (AOP (result), "a", offset);
6859 aopPut (AOP (result), "!zero", offset);
6863 aopPut (AOP (result),
6864 aopGet (AOP (right), offset, FALSE),
6869 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
6871 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
6872 aopPut (AOP (result), "l", LSB);
6873 aopPut (AOP (result), "h", MSB16);
6875 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6877 /* Special case. Load into a and d, then load out. */
6878 _moveA (aopGet (AOP (right), 0, FALSE));
6879 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
6880 aopPut (AOP (result), "a", 0);
6881 aopPut (AOP (result), "e", 1);
6883 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6885 /* Special case - simple memcpy */
6886 aopGet (AOP (right), LSB, FALSE);
6889 aopGet (AOP (result), LSB, FALSE);
6893 emit2 ("ld a,(de)");
6894 /* Peephole will optimise this. */
6895 emit2 ("ld (hl),a");
6903 spillPair (PAIR_HL);
6909 /* PENDING: do this check better */
6910 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
6912 _moveA (aopGet (AOP (right), offset, FALSE));
6913 aopPut (AOP (result), "a", offset);
6916 aopPut (AOP (result),
6917 aopGet (AOP (right), offset, FALSE),
6924 freeAsmop (right, NULL, ic);
6925 freeAsmop (result, NULL, ic);
6928 /*-----------------------------------------------------------------*/
6929 /* genJumpTab - genrates code for jump table */
6930 /*-----------------------------------------------------------------*/
6932 genJumpTab (iCode * ic)
6937 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
6938 /* get the condition into accumulator */
6939 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
6942 emit2 ("ld e,%s", l);
6943 emit2 ("ld d,!zero");
6944 jtab = newiTempLabel (NULL);
6946 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
6947 emit2 ("add hl,de");
6948 emit2 ("add hl,de");
6949 emit2 ("add hl,de");
6950 freeAsmop (IC_JTCOND (ic), NULL, ic);
6954 emitLabel (jtab->key + 100);
6955 /* now generate the jump labels */
6956 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
6957 jtab = setNextItem (IC_JTLABELS (ic)))
6958 emit2 ("jp !tlabel", jtab->key + 100);
6961 /*-----------------------------------------------------------------*/
6962 /* genCast - gen code for casting */
6963 /*-----------------------------------------------------------------*/
6965 genCast (iCode * ic)
6967 operand *result = IC_RESULT (ic);
6968 sym_link *rtype = operandType (IC_RIGHT (ic));
6969 operand *right = IC_RIGHT (ic);
6972 /* if they are equivalent then do nothing */
6973 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6976 aopOp (right, ic, FALSE, FALSE);
6977 aopOp (result, ic, FALSE, FALSE);
6979 /* if the result is a bit */
6980 if (AOP_TYPE (result) == AOP_CRY)
6982 wassertl (0, "Tried to cast to a bit");
6985 /* if they are the same size : or less */
6986 if (AOP_SIZE (result) <= AOP_SIZE (right))
6989 /* if they are in the same place */
6990 if (sameRegs (AOP (right), AOP (result)))
6993 /* if they in different places then copy */
6994 size = AOP_SIZE (result);
6998 aopPut (AOP (result),
6999 aopGet (AOP (right), offset, FALSE),
7006 /* So we now know that the size of destination is greater
7007 than the size of the source */
7008 /* we move to result for the size of source */
7009 size = AOP_SIZE (right);
7013 aopPut (AOP (result),
7014 aopGet (AOP (right), offset, FALSE),
7019 /* now depending on the sign of the destination */
7020 size = AOP_SIZE (result) - AOP_SIZE (right);
7021 /* Unsigned or not an integral type - right fill with zeros */
7022 if (SPEC_USIGN (rtype) || !IS_SPEC (rtype) || AOP_TYPE(right)==AOP_CRY)
7025 aopPut (AOP (result), "!zero", offset++);
7029 /* we need to extend the sign :{ */
7030 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
7036 aopPut (AOP (result), "a", offset++);
7040 freeAsmop (right, NULL, ic);
7041 freeAsmop (result, NULL, ic);
7044 /*-----------------------------------------------------------------*/
7045 /* genReceive - generate code for a receive iCode */
7046 /*-----------------------------------------------------------------*/
7048 genReceive (iCode * ic)
7050 if (isOperandInFarSpace (IC_RESULT (ic)) &&
7051 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7052 IS_TRUE_SYMOP (IC_RESULT (ic))))
7062 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7063 size = AOP_SIZE(IC_RESULT(ic));
7065 for (i = 0; i < size; i++) {
7066 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7070 freeAsmop (IC_RESULT (ic), NULL, ic);
7073 /*-----------------------------------------------------------------*/
7074 /* genDummyRead - generate code for dummy read of volatiles */
7075 /*-----------------------------------------------------------------*/
7077 genDummyRead (iCode * ic)
7079 emit2 ("; genDummyRead not implemented");
7086 /** Maximum number of bytes to emit per line. */
7090 /** Context for the byte output chunker. */
7093 unsigned char buffer[DBEMIT_MAX_RUN];
7098 /** Flushes a byte chunker by writing out all in the buffer and
7102 _dbFlush(DBEMITCTX *self)
7109 sprintf(line, ".db 0x%02X", self->buffer[0]);
7111 for (i = 1; i < self->pos; i++)
7113 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7120 /** Write out another byte, buffering until a decent line is
7124 _dbEmit(DBEMITCTX *self, int c)
7126 if (self->pos == DBEMIT_MAX_RUN)
7130 self->buffer[self->pos++] = c;
7133 /** Context for a simple run length encoder. */
7137 unsigned char buffer[128];
7139 /** runLen may be equivalent to pos. */
7145 RLE_CHANGE_COST = 4,
7149 /** Flush the buffer of a run length encoder by writing out the run or
7150 data that it currently contains.
7153 _rleCommit(RLECTX *self)
7159 memset(&db, 0, sizeof(db));
7161 emit2(".db %u", self->pos);
7163 for (i = 0; i < self->pos; i++)
7165 _dbEmit(&db, self->buffer[i]);
7174 Can get either a run or a block of random stuff.
7175 Only want to change state if a good run comes in or a run ends.
7176 Detecting run end is easy.
7179 Say initial state is in run, len zero, last zero. Then if you get a
7180 few zeros then something else then a short run will be output.
7181 Seems OK. While in run mode, keep counting. While in random mode,
7182 keep a count of the run. If run hits margin, output all up to run,
7183 restart, enter run mode.
7186 /** Add another byte into the run length encoder, flushing as
7187 required. The run length encoder uses the Amiga IFF style, where
7188 a block is prefixed by its run length. A positive length means
7189 the next n bytes pass straight through. A negative length means
7190 that the next byte is repeated -n times. A zero terminates the
7194 _rleAppend(RLECTX *self, int c)
7198 if (c != self->last)
7200 /* The run has stopped. See if it is worthwhile writing it out
7201 as a run. Note that the random data comes in as runs of
7204 if (self->runLen > RLE_CHANGE_COST)
7206 /* Yes, worthwhile. */
7207 /* Commit whatever was in the buffer. */
7209 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7213 /* Not worthwhile. Append to the end of the random list. */
7214 for (i = 0; i < self->runLen; i++)
7216 if (self->pos >= RLE_MAX_BLOCK)
7221 self->buffer[self->pos++] = self->last;
7229 if (self->runLen >= RLE_MAX_BLOCK)
7231 /* Commit whatever was in the buffer. */
7234 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7242 _rleFlush(RLECTX *self)
7244 _rleAppend(self, -1);
7251 /** genArrayInit - Special code for initialising an array with constant
7255 genArrayInit (iCode * ic)
7259 int elementSize = 0, eIndex, i;
7260 unsigned val, lastVal;
7264 memset(&rle, 0, sizeof(rle));
7266 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7268 _saveRegsForCall(ic, 0);
7270 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7271 emit2 ("call __initrleblock");
7273 type = operandType(IC_LEFT(ic));
7275 if (type && type->next)
7277 elementSize = getSize(type->next);
7281 wassertl (0, "Can't determine element size in genArrayInit.");
7284 iLoop = IC_ARRAYILIST(ic);
7285 lastVal = (unsigned)-1;
7287 /* Feed all the bytes into the run length encoder which will handle
7289 This works well for mixed char data, and for random int and long
7298 for (i = 0; i < ix; i++)
7300 for (eIndex = 0; eIndex < elementSize; eIndex++)
7302 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7303 _rleAppend(&rle, val);
7308 iLoop = iLoop->next;
7312 /* Mark the end of the run. */
7315 _restoreRegsAfterCall();
7319 freeAsmop (IC_LEFT(ic), NULL, ic);
7323 _swap (PAIR_ID one, PAIR_ID two)
7325 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7331 emit2 ("ld a,%s", _pairs[one].l);
7332 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7333 emit2 ("ld %s,a", _pairs[two].l);
7334 emit2 ("ld a,%s", _pairs[one].h);
7335 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7336 emit2 ("ld %s,a", _pairs[two].h);
7340 /* The problem is that we may have all three pairs used and they may
7341 be needed in a different order.
7346 hl = hl => unity, fine
7350 hl = hl hl = hl, swap de <=> bc
7358 hl = bc de = de, swap bc <=> hl
7366 hl = de bc = bc, swap hl <=> de
7371 * Any pair = pair are done last
7372 * Any pair = iTemp are done last
7373 * Any swaps can be done any time
7381 So how do we detect the cases?
7382 How about a 3x3 matrix?
7386 x x x x (Fourth for iTemp/other)
7388 First determin which mode to use by counting the number of unity and
7391 Two - Assign the pair first, then the rest
7392 One - Swap the two, then the rest
7396 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7398 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7400 PAIR_BC, PAIR_HL, PAIR_DE
7402 int i, j, nunity = 0;
7403 memset (ids, PAIR_INVALID, sizeof (ids));
7406 wassert (nparams == 3);
7408 /* First save everything that needs to be saved. */
7409 _saveRegsForCall (ic, 0);
7411 /* Loading HL first means that DE is always fine. */
7412 for (i = 0; i < nparams; i++)
7414 aopOp (pparams[i], ic, FALSE, FALSE);
7415 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7418 /* Count the number of unity or iTemp assigns. */
7419 for (i = 0; i < 3; i++)
7421 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7429 /* Any order, fall through. */
7431 else if (nunity == 2)
7433 /* One is assigned. Pull it out and assign. */
7434 for (i = 0; i < 3; i++)
7436 for (j = 0; j < NUM_PAIRS; j++)
7438 if (ids[dest[i]][j] == TRUE)
7440 /* Found it. See if it's the right one. */
7441 if (j == PAIR_INVALID || j == dest[i])
7447 fetchPair(dest[i], AOP (pparams[i]));
7454 else if (nunity == 1)
7456 /* Find the pairs to swap. */
7457 for (i = 0; i < 3; i++)
7459 for (j = 0; j < NUM_PAIRS; j++)
7461 if (ids[dest[i]][j] == TRUE)
7463 if (j == PAIR_INVALID || j == dest[i])
7478 int next = getPairId (AOP (pparams[0]));
7479 emit2 ("push %s", _pairs[next].name);
7481 if (next == dest[1])
7483 fetchPair (dest[1], AOP (pparams[1]));
7484 fetchPair (dest[2], AOP (pparams[2]));
7488 fetchPair (dest[2], AOP (pparams[2]));
7489 fetchPair (dest[1], AOP (pparams[1]));
7491 emit2 ("pop %s", _pairs[dest[0]].name);
7494 /* Finally pull out all of the iTemps */
7495 for (i = 0; i < 3; i++)
7497 if (ids[dest[i]][PAIR_INVALID] == 1)
7499 fetchPair (dest[i], AOP (pparams[i]));
7505 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
7511 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
7515 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7517 setupForBuiltin3 (ic, nParams, pparams);
7519 label = newiTempLabel(NULL);
7521 emitLabel (label->key);
7522 emit2 ("ld a,(hl)");
7525 emit2 ("!shortjp nz,!tlabel ; 1", label->key);
7527 freeAsmop (from, NULL, ic->next);
7528 freeAsmop (to, NULL, ic);
7532 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
7534 operand *from, *to, *count;
7537 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
7542 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7544 setupForBuiltin3 (ic, nParams, pparams);
7548 freeAsmop (count, NULL, ic->next->next);
7549 freeAsmop (from, NULL, ic);
7551 _restoreRegsAfterCall();
7553 /* if we need assign a result value */
7554 if ((IS_ITEMP (IC_RESULT (ic)) &&
7555 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
7556 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
7557 IS_TRUE_SYMOP (IC_RESULT (ic)))
7559 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7560 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
7561 freeAsmop (IC_RESULT (ic), NULL, ic);
7564 freeAsmop (to, NULL, ic->next);
7567 /*-----------------------------------------------------------------*/
7568 /* genBuiltIn - calls the appropriate function to generating code */
7569 /* for a built in function */
7570 /*-----------------------------------------------------------------*/
7571 static void genBuiltIn (iCode *ic)
7573 operand *bi_parms[MAX_BUILTIN_ARGS];
7578 /* get all the arguments for a built in function */
7579 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
7581 /* which function is it */
7582 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
7584 if (strcmp(bif->name,"__builtin_strcpy")==0)
7586 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
7588 else if (strcmp(bif->name,"__builtin_memcpy")==0)
7590 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
7594 wassertl (0, "Unknown builtin function encountered");
7598 /*-----------------------------------------------------------------*/
7599 /* genZ80Code - generate code for Z80 based controllers */
7600 /*-----------------------------------------------------------------*/
7602 genZ80Code (iCode * lic)
7610 _fReturn = _gbz80_return;
7611 _fTmp = _gbz80_return;
7615 _fReturn = _z80_return;
7616 _fTmp = _z80_return;
7619 _G.lines.head = _G.lines.current = NULL;
7621 for (ic = lic; ic; ic = ic->next)
7624 if (cln != ic->lineno)
7626 if (!options.noCcodeInAsm) {
7627 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
7628 printCLine(ic->filename, ic->lineno));
7632 if (options.iCodeInAsm) {
7633 emit2 (";ic:%d: %s", ic->key, printILine(ic));
7635 /* if the result is marked as
7636 spilt and rematerializable or code for
7637 this has already been generated then
7639 if (resultRemat (ic) || ic->generated)
7642 /* depending on the operation */
7646 emitDebug ("; genNot");
7651 emitDebug ("; genCpl");
7656 emitDebug ("; genUminus");
7661 emitDebug ("; genIpush");
7666 /* IPOP happens only when trying to restore a
7667 spilt live range, if there is an ifx statement
7668 following this pop then the if statement might
7669 be using some of the registers being popped which
7670 would destory the contents of the register so
7671 we need to check for this condition and handle it */
7673 ic->next->op == IFX &&
7674 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
7676 emitDebug ("; genIfx");
7677 genIfx (ic->next, ic);
7681 emitDebug ("; genIpop");
7687 emitDebug ("; genCall");
7692 emitDebug ("; genPcall");
7697 emitDebug ("; genFunction");
7702 emitDebug ("; genEndFunction");
7703 genEndFunction (ic);
7707 emitDebug ("; genRet");
7712 emitDebug ("; genLabel");
7717 emitDebug ("; genGoto");
7722 emitDebug ("; genPlus");
7727 emitDebug ("; genMinus");
7732 emitDebug ("; genMult");
7737 emitDebug ("; genDiv");
7742 emitDebug ("; genMod");
7747 emitDebug ("; genCmpGt");
7748 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
7752 emitDebug ("; genCmpLt");
7753 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
7760 /* note these two are xlated by algebraic equivalence
7761 during parsing SDCC.y */
7762 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
7763 "got '>=' or '<=' shouldn't have come here");
7767 emitDebug ("; genCmpEq");
7768 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
7772 emitDebug ("; genAndOp");
7777 emitDebug ("; genOrOp");
7782 emitDebug ("; genXor");
7783 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
7787 emitDebug ("; genOr");
7788 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
7792 emitDebug ("; genAnd");
7793 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
7797 emitDebug ("; genInline");
7802 emitDebug ("; genRRC");
7807 emitDebug ("; genRLC");
7812 emitDebug ("; genGetHBIT");
7817 emitDebug ("; genLeftShift");
7822 emitDebug ("; genRightShift");
7826 case GET_VALUE_AT_ADDRESS:
7827 emitDebug ("; genPointerGet");
7833 if (POINTER_SET (ic))
7835 emitDebug ("; genAssign (pointer)");
7840 emitDebug ("; genAssign");
7846 emitDebug ("; genIfx");
7851 emitDebug ("; genAddrOf");
7856 emitDebug ("; genJumpTab");
7861 emitDebug ("; genCast");
7866 emitDebug ("; genReceive");
7871 if (ic->builtinSEND)
7873 emitDebug ("; genBuiltIn");
7878 emitDebug ("; addSet");
7879 addSet (&_G.sendSet, ic);
7884 emitDebug ("; genArrayInit");
7888 case DUMMY_READ_VOLATILE:
7898 /* now we are ready to call the
7899 peep hole optimizer */
7900 if (!options.nopeep)
7901 peepHole (&_G.lines.head);
7903 /* This is unfortunate */
7904 /* now do the actual printing */
7906 FILE *fp = codeOutFile;
7907 if (isInHome () && codeOutFile == code->oFile)
7908 codeOutFile = home->oFile;
7909 printLine (_G.lines.head, codeOutFile);
7910 if (_G.flushStatics)
7913 _G.flushStatics = 0;
7918 freeTrace(&_G.lines.trace);
7919 freeTrace(&_G.trace.aops);
7925 _isPairUsed (iCode * ic, PAIR_ID pairId)
7931 if (bitVectBitValue (ic->rMask, D_IDX))
7933 if (bitVectBitValue (ic->rMask, E_IDX))
7943 fetchLitSpecial (asmop * aop, bool negate, bool xor)
7946 value *val = aop->aopu.aop_lit;
7948 wassert (aop->type == AOP_LIT);
7949 wassert (!IS_FLOAT (val->type));
7951 v = (unsigned long) floatFromVal (val);
7959 tsprintf (buffer, sizeof(buffer), "!immedword", v);
7960 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));