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;
223 iCode *current_iCode;
229 /** TRUE if the registers have already been saved. */
247 static const char *aopGet (asmop * aop, int offset, bool bit16);
249 static const char *aopNames[] = {
269 isLastUse (iCode *ic, operand *op)
271 bitVect *uses = bitVectCopy (OP_USES (op));
273 while (!bitVectIsZero (uses))
275 if (bitVectFirstBit (uses) == ic->key)
277 if (bitVectnBitsOn (uses) == 1)
286 bitVectUnSetBit (uses, bitVectFirstBit (uses));
306 _getTempPairName(void)
308 return _pairs[_getTempPairId()].name;
312 isPairInUse (PAIR_ID id, iCode *ic)
316 return bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
318 else if (id == PAIR_BC)
320 return bitVectBitValue (ic->rMask, B_IDX) || bitVectBitValue(ic->rMask, C_IDX);
324 wassertl (0, "Only implemented for DE and BC");
330 isPairInUseNotInRet(PAIR_ID id, iCode *ic)
334 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
338 return bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
342 wassertl (0, "Only implemented for DE");
348 getFreePairId (iCode *ic)
350 if (!isPairInUse (PAIR_BC, ic))
354 else if (IS_Z80 && !isPairInUse (PAIR_DE, ic))
367 /* Clean up the line so that it is 'prettier' */
368 if (strchr (buf, ':'))
370 /* Is a label - cant do anything */
373 /* Change the first (and probably only) ' ' to a tab so
388 _newLineNode (char *line)
392 pl = traceAlloc(&_G.lines.trace, Safe_alloc ( sizeof (lineNode)));
393 pl->line = traceAlloc(&_G.lines.trace, Safe_strdup (line));
399 _vemit2 (const char *szFormat, va_list ap)
401 char buffer[INITIAL_INLINEASM];
403 tvsprintf (buffer, sizeof(buffer), szFormat, ap);
406 _G.lines.current = (_G.lines.current ?
407 connectLine (_G.lines.current, _newLineNode (buffer)) :
408 (_G.lines.head = _newLineNode (buffer)));
410 _G.lines.current->isInline = _G.lines.isInline;
411 _G.lines.current->ic = _G.current_iCode;
415 emit2 (const char *szFormat,...)
419 va_start (ap, szFormat);
421 _vemit2 (szFormat, ap);
427 emitDebug (const char *szFormat,...)
433 va_start (ap, szFormat);
435 _vemit2 (szFormat, ap);
441 /*-----------------------------------------------------------------*/
442 /* emit2 - writes the code into a file : for now it is simple */
443 /*-----------------------------------------------------------------*/
445 _emit2 (const char *inst, const char *fmt,...)
448 char lb[INITIAL_INLINEASM];
455 sprintf (lb, "%s\t", inst);
456 vsprintf (lb + (strlen (lb)), fmt, ap);
459 vsprintf (lb, fmt, ap);
461 while (isspace (*lbp))
466 _G.lines.current = (_G.lines.current ?
467 connectLine (_G.lines.current, _newLineNode (lb)) :
468 (_G.lines.head = _newLineNode (lb)));
470 _G.lines.current->isInline = _G.lines.isInline;
471 _G.lines.current->ic = _G.current_iCode;
476 _emitMove(const char *to, const char *from)
478 if (STRCASECMP(to, from) != 0)
480 emit2("ld %s,%s", to, from);
485 // Could leave this to the peephole, but sometimes the peephole is inhibited.
490 aopDump(const char *plabel, asmop *aop)
496 emitDebug("; Dump of %s: type %s size %u", plabel, aopNames[aop->type], aop->size);
501 emitDebug("; aop_stk %d", aop->aopu.aop_stk);
504 for (i=aop->size-1;i>=0;i--)
505 *rbp++ = *(aop->aopu.aop_reg[i]->name);
507 emitDebug("; reg = %s", regbuf);
510 emitDebug("; pairptr = (%s)", _pairs[aop->aopu.aop_pairId].name);
513 /* No information. */
519 _moveA(const char *moveFrom)
521 // Let the peephole optimiser take care of redundent loads
522 _emitMove(ACC_NAME, moveFrom);
532 getPairName (asmop * aop)
534 if (aop->type == AOP_REG)
536 switch (aop->aopu.aop_reg[0]->rIdx)
549 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
552 for (i = 0; i < NUM_PAIRS; i++)
554 if (strcmp(aop->aopu.aop_str[0], _pairs[i].l) == 0)
556 return _pairs[i].name;
560 wassertl (0, "Tried to get the pair name of something that isn't a pair");
565 getPairId (asmop * aop)
569 if (aop->type == AOP_REG)
571 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX) && (aop->aopu.aop_reg[1]->rIdx == B_IDX))
575 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX) && (aop->aopu.aop_reg[1]->rIdx == D_IDX))
579 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX) && (aop->aopu.aop_reg[1]->rIdx == H_IDX))
584 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
587 for (i = 0; i < NUM_PAIRS; i++)
589 if (!strcmp (aop->aopu.aop_str[0], _pairs[i].l) && !strcmp (aop->aopu.aop_str[1], _pairs[i].h))
599 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
603 return (getPairId (aop) != PAIR_INVALID);
606 /** Returns TRUE if the registers used in aop cannot be split into high
609 isUnsplitable (asmop * aop)
611 switch (getPairId (aop))
623 isPtrPair (asmop * aop)
625 PAIR_ID pairId = getPairId (aop);
638 spillPair (PAIR_ID pairId)
640 _G.pairs[pairId].last_type = AOP_INVALID;
641 _G.pairs[pairId].base = NULL;
644 /* Given a register name, spill the pair (if any) the register is part of */
646 spillPairReg (const char *regname)
648 if (strlen(regname)==1)
668 /** Push a register pair onto the stack */
670 genPairPush (asmop * aop)
672 emit2 ("push %s", getPairName (aop));
676 _push (PAIR_ID pairId)
678 emit2 ("push %s", _pairs[pairId].name);
679 _G.stack.pushed += 2;
683 _pop (PAIR_ID pairId)
685 emit2 ("pop %s", _pairs[pairId].name);
686 _G.stack.pushed -= 2;
691 genMovePairPair (PAIR_ID srcPair, PAIR_ID dstPair)
704 if (srcPair == PAIR_IX || srcPair == PAIR_IY)
711 emit2("ld %s,%s",_pairs[dstPair].l,_pairs[srcPair].l);
712 emit2("ld %s,%s",_pairs[dstPair].h,_pairs[srcPair].h);
715 wassertl (0, "Tried to move a nonphysical pair");
717 _G.pairs[dstPair].last_type = _G.pairs[srcPair].last_type;
718 _G.pairs[dstPair].base = _G.pairs[srcPair].base;
719 _G.pairs[dstPair].offset = _G.pairs[srcPair].offset;
723 /*-----------------------------------------------------------------*/
724 /* newAsmop - creates a new asmOp */
725 /*-----------------------------------------------------------------*/
727 newAsmop (short type)
731 aop = traceAlloc(&_G.trace.aops, Safe_alloc (sizeof (asmop)));
736 /*-----------------------------------------------------------------*/
737 /* aopForSym - for a true symbol */
738 /*-----------------------------------------------------------------*/
740 aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
747 wassert (sym->etype);
749 space = SPEC_OCLS (sym->etype);
751 /* if already has one */
757 /* Assign depending on the storage class */
758 if (sym->onStack || sym->iaccess)
760 /* The pointer that is used depends on how big the offset is.
761 Normally everything is AOP_STK, but for offsets of < -128 or
762 > 127 on the Z80 an extended stack pointer is used.
764 if (IS_Z80 && (_G.omitFramePtr || sym->stack < INT8MIN || sym->stack > (int)(INT8MAX-getSize (sym->type))))
766 emitDebug ("; AOP_EXSTK for %s", sym->rname);
767 sym->aop = aop = newAsmop (AOP_EXSTK);
771 emitDebug ("; AOP_STK for %s", sym->rname);
772 sym->aop = aop = newAsmop (AOP_STK);
775 aop->size = getSize (sym->type);
776 aop->aopu.aop_stk = sym->stack;
780 /* special case for a function */
781 if (IS_FUNC (sym->type))
783 sym->aop = aop = newAsmop (AOP_IMMD);
784 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup (sym->rname));
791 /* if it is in direct space */
792 if (IN_REGSP (space) && !requires_a)
794 sym->aop = aop = newAsmop (AOP_SFR);
795 aop->aopu.aop_dir = sym->rname;
796 aop->size = getSize (sym->type);
797 emitDebug ("; AOP_SFR for %s", sym->rname);
802 /* only remaining is far space */
803 /* in which case DPTR gets the address */
806 emitDebug ("; AOP_HL for %s", sym->rname);
807 sym->aop = aop = newAsmop (AOP_HL);
811 sym->aop = aop = newAsmop (AOP_IY);
813 aop->size = getSize (sym->type);
814 aop->aopu.aop_dir = sym->rname;
816 /* if it is in code space */
817 if (IN_CODESPACE (space))
823 /*-----------------------------------------------------------------*/
824 /* aopForRemat - rematerialzes an object */
825 /*-----------------------------------------------------------------*/
827 aopForRemat (symbol * sym)
830 iCode *ic = sym->rematiCode;
831 asmop *aop = newAsmop (AOP_IMMD);
835 /* if plus or minus print the right hand side */
836 if (ic->op == '+' || ic->op == '-')
838 /* PENDING: for re-target */
839 sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
842 ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
845 /* we reached the end */
846 sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
850 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
854 /*-----------------------------------------------------------------*/
855 /* regsInCommon - two operands have some registers in common */
856 /*-----------------------------------------------------------------*/
858 regsInCommon (operand * op1, operand * op2)
863 /* if they have registers in common */
864 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
867 sym1 = OP_SYMBOL (op1);
868 sym2 = OP_SYMBOL (op2);
870 if (sym1->nRegs == 0 || sym2->nRegs == 0)
873 for (i = 0; i < sym1->nRegs; i++)
879 for (j = 0; j < sym2->nRegs; j++)
884 if (sym2->regs[j] == sym1->regs[i])
892 /*-----------------------------------------------------------------*/
893 /* operandsEqu - equivalent */
894 /*-----------------------------------------------------------------*/
896 operandsEqu (operand * op1, operand * op2)
900 /* if they not symbols */
901 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
904 sym1 = OP_SYMBOL (op1);
905 sym2 = OP_SYMBOL (op2);
907 /* if both are itemps & one is spilt
908 and the other is not then false */
909 if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
910 sym1->isspilt != sym2->isspilt)
913 /* if they are the same */
917 if (strcmp (sym1->rname, sym2->rname) == 0)
921 /* if left is a tmp & right is not */
922 if (IS_ITEMP (op1) &&
925 (sym1->usl.spillLoc == sym2))
928 if (IS_ITEMP (op2) &&
932 (sym2->usl.spillLoc == sym1))
938 /*-----------------------------------------------------------------*/
939 /* sameRegs - two asmops have the same registers */
940 /*-----------------------------------------------------------------*/
942 sameRegs (asmop * aop1, asmop * aop2)
946 if (aop1->type == AOP_SFR ||
947 aop2->type == AOP_SFR)
953 if (aop1->type != AOP_REG ||
954 aop2->type != AOP_REG)
957 if (aop1->size != aop2->size)
960 for (i = 0; i < aop1->size; i++)
961 if (aop1->aopu.aop_reg[i] !=
962 aop2->aopu.aop_reg[i])
968 /*-----------------------------------------------------------------*/
969 /* aopOp - allocates an asmop for an operand : */
970 /*-----------------------------------------------------------------*/
972 aopOp (operand * op, iCode * ic, bool result, bool requires_a)
981 /* if this a literal */
982 if (IS_OP_LITERAL (op))
984 op->aop = aop = newAsmop (AOP_LIT);
985 aop->aopu.aop_lit = op->operand.valOperand;
986 aop->size = getSize (operandType (op));
990 /* if already has a asmop then continue */
996 /* if the underlying symbol has a aop */
997 if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
999 op->aop = OP_SYMBOL (op)->aop;
1003 /* if this is a true symbol */
1004 if (IS_TRUE_SYMOP (op))
1006 op->aop = aopForSym (ic, OP_SYMBOL (op), result, requires_a);
1010 /* this is a temporary : this has
1016 e) can be a return use only */
1018 sym = OP_SYMBOL (op);
1020 /* if the type is a conditional */
1021 if (sym->regType == REG_CND)
1023 aop = op->aop = sym->aop = newAsmop (AOP_CRY);
1028 /* if it is spilt then two situations
1030 b) has a spill location */
1031 if (sym->isspilt || sym->nRegs == 0)
1033 /* rematerialize it NOW */
1036 sym->aop = op->aop = aop =
1038 aop->size = getSize (sym->type);
1045 aop = op->aop = sym->aop = newAsmop (AOP_STR);
1046 aop->size = getSize (sym->type);
1047 for (i = 0; i < 4; i++)
1048 aop->aopu.aop_str[i] = _fReturn[i];
1054 if (sym->accuse == ACCUSE_A)
1056 aop = op->aop = sym->aop = newAsmop (AOP_ACC);
1057 aop->size = getSize (sym->type);
1058 wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
1060 aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
1062 else if (sym->accuse == ACCUSE_SCRATCH)
1064 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
1065 aop->size = getSize (sym->type);
1066 wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
1067 aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
1068 aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
1070 else if (sym->accuse == ACCUSE_IY)
1072 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
1073 aop->size = getSize (sym->type);
1074 wassertl(aop->size <= 2, "Internal error: Caching in IY, but too big to fit in IY");
1075 aop->aopu.aop_str[0] = _pairs[PAIR_IY].l;
1076 aop->aopu.aop_str[1] = _pairs[PAIR_IY].h;
1080 wassertl (0, "Marked as being allocated into A or HL but is actually in neither");
1085 /* else spill location */
1086 if (sym->usl.spillLoc && getSize(sym->type) != getSize(sym->usl.spillLoc->type)) {
1087 /* force a new aop if sizes differ */
1088 sym->usl.spillLoc->aop = NULL;
1090 sym->aop = op->aop = aop =
1091 aopForSym (ic, sym->usl.spillLoc, result, requires_a);
1092 aop->size = getSize (sym->type);
1096 /* must be in a register */
1097 sym->aop = op->aop = aop = newAsmop (AOP_REG);
1098 aop->size = sym->nRegs;
1099 for (i = 0; i < sym->nRegs; i++)
1100 aop->aopu.aop_reg[i] = sym->regs[i];
1103 /*-----------------------------------------------------------------*/
1104 /* freeAsmop - free up the asmop given to an operand */
1105 /*----------------------------------------------------------------*/
1107 freeAsmop (operand * op, asmop * aaop, iCode * ic)
1124 if (aop->type == AOP_PAIRPTR && IS_Z80 && aop->aopu.aop_pairId == PAIR_DE)
1126 _pop (aop->aopu.aop_pairId);
1129 if (getPairId (aop) == PAIR_HL)
1131 spillPair (PAIR_HL);
1135 /* all other cases just dealloc */
1141 OP_SYMBOL (op)->aop = NULL;
1142 /* if the symbol has a spill */
1144 SPIL_LOC (op)->aop = NULL;
1151 isLitWord (asmop * aop)
1153 /* if (aop->size != 2)
1166 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
1168 /* depending on type */
1174 /* PENDING: for re-target */
1177 tsprintf (buffer, sizeof(buffer),
1178 "!hashedstr + %d", aop->aopu.aop_immd, offset);
1180 else if (offset == 0)
1182 tsprintf (buffer, sizeof(buffer),
1183 "%s", aop->aopu.aop_immd);
1187 tsprintf (buffer, sizeof(buffer),
1188 "%s + %d", aop->aopu.aop_immd, offset);
1190 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1194 value *val = aop->aopu.aop_lit;
1195 /* if it is a float then it gets tricky */
1196 /* otherwise it is fairly simple */
1197 if (!IS_FLOAT (val->type))
1199 unsigned long v = (unsigned long) floatFromVal (val);
1205 else if (offset == 0)
1211 wassertl(0, "Encountered an invalid offset while fetching a literal");
1215 tsprintf (buffer, sizeof(buffer), "!immedword", v);
1217 tsprintf (buffer, sizeof(buffer), "!constword", v);
1219 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1230 /* it is type float */
1231 fl.f = (float) floatFromVal (val);
1233 #ifdef WORDS_BIGENDIAN
1234 i = fl.c[3-offset] | (fl.c[3-offset-1]<<8);
1236 i = fl.c[offset] | (fl.c[offset+1]<<8);
1239 tsprintf (buffer, sizeof(buffer), "!immedword", i);
1241 tsprintf (buffer, sizeof(buffer), "!constword", i);
1243 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1252 aopGetWord (asmop * aop, int offset)
1254 return aopGetLitWordLong (aop, offset, TRUE);
1258 isPtr (const char *s)
1260 if (!strcmp (s, "hl"))
1262 if (!strcmp (s, "ix"))
1264 if (!strcmp (s, "iy"))
1270 adjustPair (const char *pair, int *pold, int new)
1276 emit2 ("inc %s", pair);
1281 emit2 ("dec %s", pair);
1289 spillPair (PAIR_HL);
1290 spillPair (PAIR_IY);
1294 requiresHL (asmop * aop)
1310 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1312 const char *l, *base;
1313 const char *pair = _pairs[pairId].name;
1314 l = aopGetLitWordLong (left, offset, FALSE);
1315 base = aopGetLitWordLong (left, 0, FALSE);
1316 wassert (l && pair && base);
1320 if (pairId == PAIR_HL || pairId == PAIR_IY)
1322 if (_G.pairs[pairId].last_type == left->type)
1324 if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1326 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1328 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1331 if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
1338 _G.pairs[pairId].last_type = left->type;
1339 _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1340 _G.pairs[pairId].offset = offset;
1342 /* Both a lit on the right and a true symbol on the left */
1343 emit2 ("ld %s,!hashedstr", pair, l);
1347 makeFreePairId (iCode *ic, bool *pisUsed)
1353 if (!bitVectBitValue (ic->rMask, B_IDX) && !bitVectBitValue(ic->rMask, C_IDX))
1357 else if (IS_Z80 && !bitVectBitValue (ic->rMask, D_IDX) && !bitVectBitValue(ic->rMask, E_IDX))
1375 fetchPairLong (PAIR_ID pairId, asmop * aop, iCode *ic, int offset)
1377 /* if this is remateriazable */
1378 if (isLitWord (aop)) {
1379 fetchLitPair (pairId, aop, offset);
1383 if (getPairId (aop) == pairId)
1387 /* we need to get it byte by byte */
1388 else if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1389 aopGet (aop, offset, FALSE);
1390 switch (aop->size - offset) {
1392 emit2 ("ld l,!*hl");
1393 emit2 ("ld h,!immedbyte", 0);
1396 // PENDING: Requires that you are only fetching two bytes.
1399 emit2 ("ld h,!*hl");
1403 wassertl (0, "Attempted to fetch too much data into HL");
1407 else if (IS_Z80 && aop->type == AOP_IY) {
1408 /* Instead of fetching relative to IY, just grab directly
1409 from the address IY refers to */
1410 char *l = aopGetLitWordLong (aop, offset, FALSE);
1412 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1414 if (aop->size < 2) {
1415 emit2("ld %s,!zero", _pairs[pairId].h);
1418 else if (pairId == PAIR_IY)
1422 emit2 ("push %s", _pairs[getPairId(aop)].name);
1428 PAIR_ID id = makeFreePairId (ic, &isUsed);
1431 /* Can't load into parts, so load into HL then exchange. */
1432 emit2 ("ld %s,%s", _pairs[id].l, aopGet (aop, offset, FALSE));
1433 emit2 ("ld %s,%s", _pairs[id].h, aopGet (aop, offset + 1, FALSE));
1434 emit2 ("push %s", _pairs[id].name);
1440 else if (isUnsplitable(aop))
1442 emit2("push %s", _pairs[getPairId(aop)].name);
1443 emit2("pop %s", _pairs[pairId].name);
1447 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1448 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1450 /* PENDING: check? */
1451 if (pairId == PAIR_HL)
1452 spillPair (PAIR_HL);
1457 fetchPair (PAIR_ID pairId, asmop * aop)
1459 fetchPairLong (pairId, aop, NULL, 0);
1463 fetchHL (asmop * aop)
1465 fetchPair (PAIR_HL, aop);
1469 setupPairFromSP (PAIR_ID id, int offset)
1471 wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
1473 if (offset < INT8MIN || offset > INT8MAX)
1475 emit2 ("ld hl,!immedword", offset);
1476 emit2 ("add hl,sp");
1480 emit2 ("!ldahlsp", offset);
1485 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1490 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
1491 fetchLitPair (pairId, aop, 0);
1495 wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
1497 fetchLitPair (pairId, aop, offset);
1498 _G.pairs[pairId].offset = offset;
1502 wassertl (IS_Z80, "Only the Z80 has an extended stack");
1503 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
1506 int offset = aop->aopu.aop_stk + _G.stack.offset;
1508 if (_G.pairs[pairId].last_type == aop->type &&
1509 _G.pairs[pairId].offset == offset)
1515 /* PENDING: Do this better. */
1516 sprintf (buffer, "%d", offset + _G.stack.pushed);
1517 emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
1518 emit2 ("add %s,sp", _pairs[pairId].name);
1519 _G.pairs[pairId].last_type = aop->type;
1520 _G.pairs[pairId].offset = offset;
1527 /* Doesnt include _G.stack.pushed */
1528 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1530 if (aop->aopu.aop_stk > 0)
1532 abso += _G.stack.param_offset;
1534 assert (pairId == PAIR_HL);
1535 /* In some cases we can still inc or dec hl */
1536 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1538 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1542 setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
1544 _G.pairs[pairId].offset = abso;
1549 if (pairId != aop->aopu.aop_pairId)
1550 genMovePairPair(aop->aopu.aop_pairId, pairId);
1551 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
1557 _G.pairs[pairId].last_type = aop->type;
1563 emit2 ("!tlabeldef", key);
1567 /*-----------------------------------------------------------------*/
1568 /* aopGet - for fetching value of the aop */
1569 /*-----------------------------------------------------------------*/
1571 aopGet (asmop * aop, int offset, bool bit16)
1573 // char *s = buffer;
1575 /* offset is greater than size then zero */
1576 /* PENDING: this seems a bit screwed in some pointer cases. */
1577 if (offset > (aop->size - 1) &&
1578 aop->type != AOP_LIT)
1580 tsprintf (buffer, sizeof(buffer), "!zero");
1581 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1584 /* depending on type */
1588 /* PENDING: re-target */
1590 tsprintf (buffer, sizeof(buffer), "!immedwords", aop->aopu.aop_immd);
1595 tsprintf (buffer, sizeof(buffer), "!bankimmeds", aop->aopu.aop_immd);
1598 tsprintf (buffer, sizeof(buffer), "!msbimmeds", aop->aopu.aop_immd);
1601 tsprintf (buffer, sizeof(buffer), "!lsbimmeds", aop->aopu.aop_immd);
1604 wassertl (0, "Fetching from beyond the limits of an immediate value.");
1607 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1611 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1612 SNPRINTF (buffer, sizeof(buffer), "a");
1614 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1618 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1619 SNPRINTF (buffer, sizeof(buffer), "a");
1621 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1624 return aop->aopu.aop_reg[offset]->name;
1628 setupPair (PAIR_HL, aop, offset);
1629 tsprintf (buffer, sizeof(buffer), "!*hl");
1631 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
1635 setupPair (PAIR_IY, aop, offset);
1636 tsprintf (buffer, sizeof(buffer), "!*iyx", offset);
1638 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1642 setupPair (PAIR_IY, aop, offset);
1643 tsprintf (buffer, sizeof(buffer), "!*iyx", offset, offset);
1645 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1650 setupPair (PAIR_HL, aop, offset);
1651 tsprintf (buffer, sizeof(buffer), "!*hl");
1655 if (aop->aopu.aop_stk >= 0)
1656 offset += _G.stack.param_offset;
1657 tsprintf (buffer, sizeof(buffer),
1658 "!*ixx", aop->aopu.aop_stk + offset);
1661 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1664 wassertl (0, "Tried to fetch from a bit variable");
1673 tsprintf(buffer, sizeof(buffer), "!zero");
1674 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1678 wassert (offset < 2);
1679 return aop->aopu.aop_str[offset];
1682 return aopLiteral (aop->aopu.aop_lit, offset);
1686 unsigned long v = aop->aopu.aop_simplelit;
1689 tsprintf (buffer, sizeof(buffer),
1690 "!immedbyte", (unsigned int) v & 0xff);
1692 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1696 return aop->aopu.aop_str[offset];
1699 setupPair (aop->aopu.aop_pairId, aop, offset);
1700 if (aop->aopu.aop_pairId==PAIR_IX)
1701 SNPRINTF (buffer, sizeof(buffer),
1703 else if (aop->aopu.aop_pairId==PAIR_IY)
1704 SNPRINTF (buffer, sizeof(buffer),
1707 SNPRINTF (buffer, sizeof(buffer),
1708 "(%s)", _pairs[aop->aopu.aop_pairId].name);
1710 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1715 wassertl (0, "aopget got unsupported aop->type");
1720 isRegString (const char *s)
1722 if (!strcmp (s, "b") ||
1734 isConstant (const char *s)
1736 /* This is a bit of a hack... */
1737 return (*s == '#' || *s == '$');
1741 canAssignToPtr (const char *s)
1743 if (isRegString (s))
1750 /*-----------------------------------------------------------------*/
1751 /* aopPut - puts a string for a aop */
1752 /*-----------------------------------------------------------------*/
1754 aopPut (asmop * aop, const char *s, int offset)
1758 if (aop->size && offset > (aop->size - 1))
1760 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1761 "aopPut got offset > aop->size");
1766 tsprintf(buffer2, sizeof(buffer2), s);
1769 /* will assign value to value */
1770 /* depending on where it is ofcourse */
1776 if (strcmp (s, "a"))
1777 emit2 ("ld a,%s", s);
1778 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1783 if (strcmp (s, "a"))
1784 emit2 ("ld a,%s", s);
1785 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1789 if (!strcmp (s, "!*hl"))
1790 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1793 aop->aopu.aop_reg[offset]->name, s);
1794 spillPairReg(aop->aopu.aop_reg[offset]->name);
1799 if (!canAssignToPtr (s))
1801 emit2 ("ld a,%s", s);
1802 setupPair (PAIR_IY, aop, offset);
1803 emit2 ("ld !*iyx,a", offset);
1807 setupPair (PAIR_IY, aop, offset);
1808 emit2 ("ld !*iyx,%s", offset, s);
1814 /* PENDING: for re-target */
1815 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1817 emit2 ("ld a,!*hl");
1820 setupPair (PAIR_HL, aop, offset);
1822 emit2 ("ld !*hl,%s", s);
1827 if (!canAssignToPtr (s))
1829 emit2 ("ld a,%s", s);
1830 setupPair (PAIR_IY, aop, offset);
1831 emit2 ("ld !*iyx,a", offset);
1835 setupPair (PAIR_IY, aop, offset);
1836 emit2 ("ld !*iyx,%s", offset, s);
1843 /* PENDING: re-target */
1844 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1846 emit2 ("ld a,!*hl");
1849 setupPair (PAIR_HL, aop, offset);
1850 if (!canAssignToPtr (s))
1852 emit2 ("ld a,%s", s);
1853 emit2 ("ld !*hl,a");
1856 emit2 ("ld !*hl,%s", s);
1860 if (aop->aopu.aop_stk >= 0)
1861 offset += _G.stack.param_offset;
1862 if (!canAssignToPtr (s))
1864 emit2 ("ld a,%s", s);
1865 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
1869 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
1875 /* if bit variable */
1876 if (!aop->aopu.aop_dir)
1878 emit2 ("ld a,!zero");
1883 /* In bit space but not in C - cant happen */
1884 wassertl (0, "Tried to write into a bit variable");
1890 if (strcmp (aop->aopu.aop_str[offset], s))
1892 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1894 spillPairReg(aop->aopu.aop_str[offset]);
1899 if (!offset && (strcmp (s, "acc") == 0))
1903 wassertl (0, "Tried to access past the end of A");
1907 if (strcmp (aop->aopu.aop_str[offset], s))
1909 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1910 spillPairReg(aop->aopu.aop_str[offset]);
1916 wassert (offset < 2);
1917 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1918 spillPairReg(aop->aopu.aop_str[offset]);
1922 setupPair (aop->aopu.aop_pairId, aop, offset);
1923 if (aop->aopu.aop_pairId==PAIR_IX)
1924 emit2 ("ld !*ixx,%s", 0, s);
1925 else if (aop->aopu.aop_pairId==PAIR_IY)
1926 emit2 ("ld !*ixy,%s", 0, s);
1928 emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
1932 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1933 "aopPut got unsupported aop->type");
1938 #define AOP(op) op->aop
1939 #define AOP_TYPE(op) AOP(op)->type
1940 #define AOP_SIZE(op) AOP(op)->size
1941 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
1944 commitPair (asmop * aop, PAIR_ID id)
1946 /* PENDING: Verify this. */
1947 if (id == PAIR_HL && requiresHL (aop) && IS_GB)
1951 aopPut (aop, "a", 0);
1952 aopPut (aop, "d", 1);
1957 if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
1959 char *l = aopGetLitWordLong (aop, 0, FALSE);
1962 emit2 ("ld (%s),%s", l, _pairs[id].name);
1966 aopPut (aop, _pairs[id].l, 0);
1967 aopPut (aop, _pairs[id].h, 1);
1972 /*-----------------------------------------------------------------*/
1973 /* getDataSize - get the operand data size */
1974 /*-----------------------------------------------------------------*/
1976 getDataSize (operand * op)
1979 size = AOP_SIZE (op);
1983 wassertl (0, "Somehow got a three byte data pointer");
1988 /*-----------------------------------------------------------------*/
1989 /* movLeft2Result - move byte from left to result */
1990 /*-----------------------------------------------------------------*/
1992 movLeft2Result (operand * left, int offl,
1993 operand * result, int offr, int sign)
1997 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
1999 l = aopGet (AOP (left), offl, FALSE);
2003 aopPut (AOP (result), l, offr);
2007 if (getDataSize (left) == offl + 1)
2009 emit2 ("ld a,%s", l);
2010 aopPut (AOP (result), "a", offr);
2017 movLeft2ResultLong (operand * left, int offl,
2018 operand * result, int offr, int sign,
2023 movLeft2Result (left, offl, result, offr, sign);
2027 wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
2028 wassertl (size == 2, "Only implemented for two bytes or one");
2030 if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
2032 emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
2033 emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
2035 spillPair (PAIR_HL);
2037 else if ( getPairId ( AOP (result)) == PAIR_IY)
2039 PAIR_ID id = getPairId (AOP (left));
2040 if (id != PAIR_INVALID)
2042 emit2("push %s", _pairs[id].name);
2053 movLeft2Result (left, offl, result, offr, sign);
2054 movLeft2Result (left, offl+1, result, offr+1, sign);
2059 /** Put Acc into a register set
2062 outAcc (operand * result)
2065 size = getDataSize (result);
2068 aopPut (AOP (result), "a", 0);
2071 /* unsigned or positive */
2074 aopPut (AOP (result), "!zero", offset++);
2079 /** Take the value in carry and put it into a register
2082 outBitCLong (operand * result, bool swap_sense)
2084 /* if the result is bit */
2085 if (AOP_TYPE (result) == AOP_CRY)
2087 wassertl (0, "Tried to write carry to a bit");
2091 emit2 ("ld a,!zero");
2094 emit2 ("xor a,!immedbyte", 1);
2100 outBitC (operand * result)
2102 outBitCLong (result, FALSE);
2105 /*-----------------------------------------------------------------*/
2106 /* toBoolean - emit code for orl a,operator(sizeop) */
2107 /*-----------------------------------------------------------------*/
2109 _toBoolean (operand * oper)
2111 int size = AOP_SIZE (oper);
2115 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
2118 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
2122 if (AOP (oper)->type != AOP_ACC)
2125 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
2131 /*-----------------------------------------------------------------*/
2132 /* genNot - generate code for ! operation */
2133 /*-----------------------------------------------------------------*/
2138 /* assign asmOps to operand & result */
2139 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
2140 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2142 /* if in bit space then a special case */
2143 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2145 wassertl (0, "Tried to negate a bit");
2148 _toBoolean (IC_LEFT (ic));
2153 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
2154 emit2 ("sub a,!one");
2155 outBitC (IC_RESULT (ic));
2157 /* release the aops */
2158 freeAsmop (IC_LEFT (ic), NULL, ic);
2159 freeAsmop (IC_RESULT (ic), NULL, ic);
2162 /*-----------------------------------------------------------------*/
2163 /* genCpl - generate code for complement */
2164 /*-----------------------------------------------------------------*/
2172 /* assign asmOps to operand & result */
2173 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2174 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2176 /* if both are in bit space then
2178 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2179 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2181 wassertl (0, "Left and the result are in bit space");
2184 size = AOP_SIZE (IC_RESULT (ic));
2187 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2190 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2193 /* release the aops */
2194 freeAsmop (IC_LEFT (ic), NULL, ic);
2195 freeAsmop (IC_RESULT (ic), NULL, ic);
2199 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
2206 store de into result
2211 store de into result
2213 const char *first = isAdd ? "add" : "sub";
2214 const char *later = isAdd ? "adc" : "sbc";
2216 wassertl (IS_GB, "Code is only relevent to the gbz80");
2217 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
2219 fetchPair (PAIR_DE, left);
2222 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
2225 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2228 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2229 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2231 fetchPairLong (PAIR_DE, left, NULL, MSB24);
2232 aopGet (right, MSB24, FALSE);
2236 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2239 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2241 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2242 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2246 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2248 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2251 /*-----------------------------------------------------------------*/
2252 /* genUminusFloat - unary minus for floating points */
2253 /*-----------------------------------------------------------------*/
2255 genUminusFloat (operand * op, operand * result)
2257 int size, offset = 0;
2259 emitDebug("; genUminusFloat");
2261 /* for this we just need to flip the
2262 first it then copy the rest in place */
2263 size = AOP_SIZE (op) - 1;
2265 _moveA(aopGet (AOP (op), MSB32, FALSE));
2267 emit2("xor a,!immedbyte", 0x80);
2268 aopPut (AOP (result), "a", MSB32);
2272 aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2277 /*-----------------------------------------------------------------*/
2278 /* genUminus - unary minus code generation */
2279 /*-----------------------------------------------------------------*/
2281 genUminus (iCode * ic)
2284 sym_link *optype, *rtype;
2287 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2288 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2290 /* if both in bit space then special
2292 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2293 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2295 wassertl (0, "Left and right are in bit space");
2299 optype = operandType (IC_LEFT (ic));
2300 rtype = operandType (IC_RESULT (ic));
2302 /* if float then do float stuff */
2303 if (IS_FLOAT (optype))
2305 genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2309 /* otherwise subtract from zero */
2310 size = AOP_SIZE (IC_LEFT (ic));
2312 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2314 /* Create a new asmop with value zero */
2315 asmop *azero = newAsmop (AOP_SIMPLELIT);
2316 azero->aopu.aop_simplelit = 0;
2318 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2326 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2327 emit2 ("ld a,!zero");
2328 emit2 ("sbc a,%s", l);
2329 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2332 /* if any remaining bytes in the result */
2333 /* we just need to propagate the sign */
2334 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2339 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2343 /* release the aops */
2344 freeAsmop (IC_LEFT (ic), NULL, ic);
2345 freeAsmop (IC_RESULT (ic), NULL, ic);
2348 /*-----------------------------------------------------------------*/
2349 /* assignResultValue - */
2350 /*-----------------------------------------------------------------*/
2352 assignResultValue (operand * oper)
2354 int size = AOP_SIZE (oper);
2357 wassertl (size <= 4, "Got a result that is bigger than four bytes");
2358 topInA = requiresHL (AOP (oper));
2360 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2362 /* We do it the hard way here. */
2364 aopPut (AOP (oper), _fReturn[0], 0);
2365 aopPut (AOP (oper), _fReturn[1], 1);
2367 aopPut (AOP (oper), _fReturn[0], 2);
2368 aopPut (AOP (oper), _fReturn[1], 3);
2374 aopPut (AOP (oper), _fReturn[size], size);
2379 /** Simple restore that doesn't take into account what is used in the
2383 _restoreRegsAfterCall(void)
2385 if (_G.stack.pushedDE)
2388 _G.stack.pushedDE = FALSE;
2390 if (_G.stack.pushedBC)
2393 _G.stack.pushedBC = FALSE;
2395 _G.saves.saved = FALSE;
2399 _saveRegsForCall(iCode *ic, int sendSetSize)
2402 o Stack parameters are pushed before this function enters
2403 o DE and BC may be used in this function.
2404 o HL and DE may be used to return the result.
2405 o HL and DE may be used to send variables.
2406 o DE and BC may be used to store the result value.
2407 o HL may be used in computing the sent value of DE
2408 o The iPushes for other parameters occur before any addSets
2410 Logic: (to be run inside the first iPush or if none, before sending)
2411 o Compute if DE and/or BC are in use over the call
2412 o Compute if DE is used in the send set
2413 o Compute if DE and/or BC are used to hold the result value
2414 o If (DE is used, or in the send set) and is not used in the result, push.
2415 o If BC is used and is not in the result, push
2417 o If DE is used in the send set, fetch
2418 o If HL is used in the send set, fetch
2422 if (_G.saves.saved == FALSE) {
2423 bool deInUse, bcInUse;
2425 bool bcInRet = FALSE, deInRet = FALSE;
2428 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask),
2429 z80_rUmaskForOp (IC_RESULT(ic)));
2431 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2432 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2434 deSending = (sendSetSize > 1);
2436 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2438 if (bcInUse && bcInRet == FALSE) {
2440 _G.stack.pushedBC = TRUE;
2442 if (deInUse && deInRet == FALSE) {
2444 _G.stack.pushedDE = TRUE;
2447 _G.saves.saved = TRUE;
2450 /* Already saved. */
2454 /*-----------------------------------------------------------------*/
2455 /* genIpush - genrate code for pushing this gets a little complex */
2456 /*-----------------------------------------------------------------*/
2458 genIpush (iCode * ic)
2460 int size, offset = 0;
2463 /* if this is not a parm push : ie. it is spill push
2464 and spill push is always done on the local stack */
2467 wassertl(0, "Encountered an unsupported spill push.");
2471 if (_G.saves.saved == FALSE) {
2472 /* Caller saves, and this is the first iPush. */
2473 /* Scan ahead until we find the function that we are pushing parameters to.
2474 Count the number of addSets on the way to figure out what registers
2475 are used in the send set.
2478 iCode *walk = ic->next;
2481 if (walk->op == SEND) {
2484 else if (walk->op == CALL || walk->op == PCALL) {
2493 _saveRegsForCall(walk, nAddSets);
2496 /* Already saved by another iPush. */
2499 /* then do the push */
2500 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2502 size = AOP_SIZE (IC_LEFT (ic));
2504 if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2506 _G.stack.pushed += 2;
2507 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2513 fetchHL (AOP (IC_LEFT (ic)));
2515 spillPair (PAIR_HL);
2516 _G.stack.pushed += 2;
2521 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
2523 spillPair (PAIR_HL);
2524 _G.stack.pushed += 2;
2525 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
2527 spillPair (PAIR_HL);
2528 _G.stack.pushed += 2;
2534 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2536 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2538 emit2 ("ld a,(%s)", l);
2542 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2543 emit2 ("ld a,%s", l);
2551 freeAsmop (IC_LEFT (ic), NULL, ic);
2554 /*-----------------------------------------------------------------*/
2555 /* genIpop - recover the registers: can happen only for spilling */
2556 /*-----------------------------------------------------------------*/
2558 genIpop (iCode * ic)
2563 /* if the temp was not pushed then */
2564 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2567 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2568 size = AOP_SIZE (IC_LEFT (ic));
2569 offset = (size - 1);
2570 if (isPair (AOP (IC_LEFT (ic))))
2572 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2580 spillPair (PAIR_HL);
2581 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2585 freeAsmop (IC_LEFT (ic), NULL, ic);
2588 /* This is quite unfortunate */
2590 setArea (int inHome)
2593 static int lastArea = 0;
2595 if (_G.in_home != inHome) {
2597 const char *sz = port->mem.code_name;
2598 port->mem.code_name = "HOME";
2599 emit2("!area", CODE_NAME);
2600 port->mem.code_name = sz;
2603 emit2("!area", CODE_NAME); */
2604 _G.in_home = inHome;
2615 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2619 symbol *sym = OP_SYMBOL (op);
2621 if (sym->isspilt || sym->nRegs == 0)
2624 aopOp (op, ic, FALSE, FALSE);
2627 if (aop->type == AOP_REG)
2630 for (i = 0; i < aop->size; i++)
2632 if (pairId == PAIR_DE)
2634 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2635 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2637 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2640 else if (pairId == PAIR_BC)
2642 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2643 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2645 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2655 freeAsmop (IC_LEFT (ic), NULL, ic);
2659 /** Emit the code for a call statement
2662 emitCall (iCode * ic, bool ispcall)
2664 bool bInRet, cInRet, dInRet, eInRet;
2665 sym_link *dtype = operandType (IC_LEFT (ic));
2667 /* if caller saves & we have not saved then */
2673 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2675 /* if send set is not empty then assign */
2680 int nSend = elementsInSet(_G.sendSet);
2681 bool swapped = FALSE;
2683 int _z80_sendOrder[] = {
2688 /* Check if the parameters are swapped. If so route through hl instead. */
2689 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2691 sic = setFirstItem(_G.sendSet);
2692 sic = setNextItem(_G.sendSet);
2694 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2695 /* The second send value is loaded from one the one that holds the first
2696 send, i.e. it is overwritten. */
2697 /* Cache the first in HL, and load the second from HL instead. */
2698 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2699 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2705 for (sic = setFirstItem (_G.sendSet); sic;
2706 sic = setNextItem (_G.sendSet))
2709 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2711 size = AOP_SIZE (IC_LEFT (sic));
2712 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2713 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2715 // PENDING: Mild hack
2716 if (swapped == TRUE && send == 1) {
2718 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2721 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2723 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2726 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2730 freeAsmop (IC_LEFT (sic), NULL, sic);
2737 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2739 werror (W_INDIR_BANKED);
2741 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2743 if (isLitWord (AOP (IC_LEFT (ic))))
2745 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2749 symbol *rlbl = newiTempLabel (NULL);
2750 spillPair (PAIR_HL);
2751 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2753 _G.stack.pushed += 2;
2755 fetchHL (AOP (IC_LEFT (ic)));
2757 emit2 ("!tlabeldef", (rlbl->key + 100));
2758 _G.stack.pushed -= 2;
2760 freeAsmop (IC_LEFT (ic), NULL, ic);
2764 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2765 OP_SYMBOL (IC_LEFT (ic))->rname :
2766 OP_SYMBOL (IC_LEFT (ic))->name;
2767 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2769 emit2 ("call banked_call");
2770 emit2 ("!dws", name);
2771 emit2 ("!dw !bankimmeds", name);
2776 emit2 ("call %s", name);
2781 /* Mark the regsiters as restored. */
2782 _G.saves.saved = FALSE;
2784 /* if we need assign a result value */
2785 if ((IS_ITEMP (IC_RESULT (ic)) &&
2786 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2787 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2788 IS_TRUE_SYMOP (IC_RESULT (ic)))
2791 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2793 assignResultValue (IC_RESULT (ic));
2795 freeAsmop (IC_RESULT (ic), NULL, ic);
2798 /* adjust the stack for parameters if required */
2801 int i = ic->parmBytes;
2803 _G.stack.pushed -= i;
2806 emit2 ("!ldaspsp", i);
2813 emit2 ("ld iy,!immedword", i);
2814 emit2 ("add iy,sp");
2835 bitVect *result = z80_rUmaskForOp (IC_RESULT (ic));
2836 bInRet = bitVectBitValue(result, B_IDX);
2837 cInRet = bitVectBitValue(result, C_IDX);
2838 dInRet = bitVectBitValue(result, D_IDX);
2839 eInRet = bitVectBitValue(result, E_IDX);
2849 if (_G.stack.pushedDE)
2851 if (dInRet && eInRet)
2853 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
2857 /* Only restore E */
2864 /* Only restore D */
2872 _G.stack.pushedDE = FALSE;
2875 if (_G.stack.pushedBC)
2877 if (bInRet && cInRet)
2879 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
2883 /* Only restore C */
2890 /* Only restore B */
2898 _G.stack.pushedBC = FALSE;
2902 /*-----------------------------------------------------------------*/
2903 /* genCall - generates a call statement */
2904 /*-----------------------------------------------------------------*/
2906 genCall (iCode * ic)
2908 emitCall (ic, FALSE);
2911 /*-----------------------------------------------------------------*/
2912 /* genPcall - generates a call by pointer statement */
2913 /*-----------------------------------------------------------------*/
2915 genPcall (iCode * ic)
2917 emitCall (ic, TRUE);
2920 /*-----------------------------------------------------------------*/
2921 /* resultRemat - result is rematerializable */
2922 /*-----------------------------------------------------------------*/
2924 resultRemat (iCode * ic)
2926 if (SKIP_IC (ic) || ic->op == IFX)
2929 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2931 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2932 if (sym->remat && !POINTER_SET (ic))
2939 extern set *publics;
2941 /*-----------------------------------------------------------------*/
2942 /* genFunction - generated code for function entry */
2943 /*-----------------------------------------------------------------*/
2945 genFunction (iCode * ic)
2949 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2952 bool bcInUse = FALSE;
2953 bool deInUse = FALSE;
2955 setArea (IFFUNC_NONBANKED (sym->type));
2957 /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
2960 _G.receiveOffset = 0;
2962 /* Record the last function name for debugging. */
2963 _G.lastFunctionName = sym->rname;
2965 /* Create the function header */
2966 emit2 ("!functionheader", sym->name);
2967 sprintf (buffer, "%s_start", sym->rname);
2968 emit2 ("!labeldef", buffer);
2969 emit2 ("!functionlabeldef", sym->rname);
2971 if (options.profile)
2973 emit2 ("!profileenter");
2976 ftype = operandType (IC_LEFT (ic));
2978 /* if critical function then turn interrupts off */
2979 if (IFFUNC_ISCRITICAL (ftype))
2982 /* if this is an interrupt service routine then save all potentially used registers. */
2983 if (IFFUNC_ISISR (sym->type))
2988 /* PENDING: callee-save etc */
2990 _G.stack.param_offset = 0;
2992 if (z80_opts.calleeSavesBC)
2997 /* Detect which registers are used. */
2998 if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
3001 for (i = 0; i < sym->regsUsed->size; i++)
3003 if (bitVectBitValue (sym->regsUsed, i))
3017 /* Other systems use DE as a temporary. */
3028 _G.stack.param_offset += 2;
3031 _G.calleeSaves.pushedBC = bcInUse;
3036 _G.stack.param_offset += 2;
3039 _G.calleeSaves.pushedDE = deInUse;
3041 /* adjust the stack for the function */
3042 _G.stack.last = sym->stack;
3045 for (sym = setFirstItem (istack->syms); sym;
3046 sym = setNextItem (istack->syms))
3048 if (sym->_isparm && !IS_REGPARM (sym->etype))
3054 sym = OP_SYMBOL (IC_LEFT (ic));
3056 _G.omitFramePtr = options.ommitFramePtr;
3057 if (IS_Z80 && !stackParm && !sym->stack)
3059 /* When the conflicts between AOP_EXSTK && AOP_HLREG are fixed, */
3060 /* the above !sym->stack condition can be removed. -- EEP */
3062 emit2 ("!ldaspsp", -sym->stack);
3063 _G.omitFramePtr = TRUE;
3065 else if (sym->stack && IS_GB && sym->stack > -INT8MIN)
3066 emit2 ("!enterxl", sym->stack);
3067 else if (sym->stack)
3068 emit2 ("!enterx", sym->stack);
3071 _G.stack.offset = sym->stack;
3074 /*-----------------------------------------------------------------*/
3075 /* genEndFunction - generates epilogue for functions */
3076 /*-----------------------------------------------------------------*/
3078 genEndFunction (iCode * ic)
3080 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3082 if (IFFUNC_ISISR (sym->type))
3084 wassertl (0, "Tried to close an interrupt support function");
3088 if (IFFUNC_ISCRITICAL (sym->type))
3091 /* PENDING: calleeSave */
3093 if (IS_Z80 && _G.omitFramePtr)
3095 if (_G.stack.offset)
3096 emit2 ("!ldaspsp", _G.stack.offset);
3098 else if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
3100 emit2 ("!leavexl", _G.stack.offset);
3102 else if (_G.stack.offset)
3104 emit2 ("!leavex", _G.stack.offset);
3111 if (_G.calleeSaves.pushedDE)
3114 _G.calleeSaves.pushedDE = FALSE;
3117 if (_G.calleeSaves.pushedBC)
3120 _G.calleeSaves.pushedBC = FALSE;
3123 if (options.profile)
3125 emit2 ("!profileexit");
3129 /* Both baned and non-banked just ret */
3132 sprintf (buffer, "%s_end", sym->rname);
3133 emit2 ("!labeldef", buffer);
3135 _G.flushStatics = 1;
3136 _G.stack.pushed = 0;
3137 _G.stack.offset = 0;
3140 /*-----------------------------------------------------------------*/
3141 /* genRet - generate code for return statement */
3142 /*-----------------------------------------------------------------*/
3147 /* Errk. This is a hack until I can figure out how
3148 to cause dehl to spill on a call */
3149 int size, offset = 0;
3151 /* if we have no return value then
3152 just generate the "ret" */
3156 /* we have something to return then
3157 move the return value into place */
3158 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3159 size = AOP_SIZE (IC_LEFT (ic));
3161 aopDump("IC_LEFT", AOP(IC_LEFT(ic)));
3164 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3168 emit2 ("ld de,%s", l);
3172 emit2 ("ld hl,%s", l);
3178 fetchPair(IS_GB ? PAIR_DE : PAIR_HL, AOP (IC_LEFT (ic)));
3182 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3184 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3185 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3191 l = aopGet (AOP (IC_LEFT (ic)), offset,
3193 if (strcmp (_fReturn[offset], l))
3194 emit2 ("ld %s,%s", _fReturn[offset], l);
3199 freeAsmop (IC_LEFT (ic), NULL, ic);
3202 /* generate a jump to the return label
3203 if the next is not the return statement */
3204 if (!(ic->next && ic->next->op == LABEL &&
3205 IC_LABEL (ic->next) == returnLabel))
3207 emit2 ("jp !tlabel", returnLabel->key + 100);
3210 /*-----------------------------------------------------------------*/
3211 /* genLabel - generates a label */
3212 /*-----------------------------------------------------------------*/
3214 genLabel (iCode * ic)
3216 /* special case never generate */
3217 if (IC_LABEL (ic) == entryLabel)
3220 emitLabel (IC_LABEL (ic)->key + 100);
3223 /*-----------------------------------------------------------------*/
3224 /* genGoto - generates a ljmp */
3225 /*-----------------------------------------------------------------*/
3227 genGoto (iCode * ic)
3229 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3232 /*-----------------------------------------------------------------*/
3233 /* genPlusIncr :- does addition with increment if possible */
3234 /*-----------------------------------------------------------------*/
3236 genPlusIncr (iCode * ic)
3238 unsigned int icount;
3239 unsigned int size = getDataSize (IC_RESULT (ic));
3240 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3242 /* will try to generate an increment */
3243 /* if the right side is not a literal
3245 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3248 emitDebug ("; genPlusIncr");
3250 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3252 /* If result is a pair */
3253 if (resultId != PAIR_INVALID)
3255 if (isLitWord (AOP (IC_LEFT (ic))))
3257 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3260 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3262 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3264 PAIR_ID freep = getFreePairId (ic);
3265 if (freep != PAIR_INVALID)
3267 fetchPair (freep, AOP (IC_RIGHT (ic)));
3268 emit2 ("add hl,%s", _pairs[freep].name);
3274 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3275 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3282 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3286 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3290 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3295 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3297 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3298 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3302 /* if the literal value of the right hand side
3303 is greater than 4 then it is not worth it */
3307 /* if increment 16 bits in register */
3308 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3314 symbol *tlbl = NULL;
3315 tlbl = newiTempLabel (NULL);
3318 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3321 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3324 emitLabel (tlbl->key + 100);
3328 /* if the sizes are greater than 1 then we cannot */
3329 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3330 AOP_SIZE (IC_LEFT (ic)) > 1)
3333 /* If the result is in a register then we can load then increment.
3335 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3337 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3340 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3345 /* we can if the aops of the left & result match or
3346 if they are in registers and the registers are the
3348 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3352 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3360 /*-----------------------------------------------------------------*/
3361 /* outBitAcc - output a bit in acc */
3362 /*-----------------------------------------------------------------*/
3364 outBitAcc (operand * result)
3366 symbol *tlbl = newiTempLabel (NULL);
3367 /* if the result is a bit */
3368 if (AOP_TYPE (result) == AOP_CRY)
3370 wassertl (0, "Tried to write A into a bit");
3374 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3375 emit2 ("ld a,!one");
3376 emitLabel (tlbl->key + 100);
3382 couldDestroyCarry (asmop *aop)
3386 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3395 shiftIntoPair (int idx, asmop *aop)
3397 PAIR_ID id = PAIR_INVALID;
3399 wassertl (IS_Z80, "Only implemented for the Z80");
3400 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3412 wassertl (0, "Internal error - hit default case");
3415 emitDebug ("; Shift into pair idx %u", idx);
3419 setupPair (PAIR_HL, aop, 0);
3423 setupPair (PAIR_IY, aop, 0);
3425 emit2 ("pop %s", _pairs[id].name);
3428 aop->type = AOP_PAIRPTR;
3429 aop->aopu.aop_pairId = id;
3430 _G.pairs[id].offset = 0;
3431 _G.pairs[id].last_type = aop->type;
3435 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
3437 wassert (left && right);
3441 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3443 shiftIntoPair (0, right);
3444 /* check result again, in case right == result */
3445 if (couldDestroyCarry (result))
3446 shiftIntoPair (1, result);
3448 else if (couldDestroyCarry (right))
3450 shiftIntoPair (0, right);
3452 else if (couldDestroyCarry (result))
3454 shiftIntoPair (0, result);
3463 /*-----------------------------------------------------------------*/
3464 /* genPlus - generates code for addition */
3465 /*-----------------------------------------------------------------*/
3467 genPlus (iCode * ic)
3469 int size, offset = 0;
3471 /* special cases :- */
3473 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3474 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3475 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3477 /* Swap the left and right operands if:
3479 if literal, literal on the right or
3480 if left requires ACC or right is already
3483 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3484 (AOP_NEEDSACC (IC_LEFT (ic))) ||
3485 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3487 operand *t = IC_RIGHT (ic);
3488 IC_RIGHT (ic) = IC_LEFT (ic);
3492 /* if both left & right are in bit
3494 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3495 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3498 wassertl (0, "Tried to add two bits");
3501 /* if left in bit space & right literal */
3502 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3503 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3505 /* Can happen I guess */
3506 wassertl (0, "Tried to add a bit to a literal");
3509 /* if I can do an increment instead
3510 of add then GOOD for ME */
3511 if (genPlusIncr (ic) == TRUE)
3514 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3516 size = getDataSize (IC_RESULT (ic));
3518 /* Special case when left and right are constant */
3519 if (isPair (AOP (IC_RESULT (ic))))
3522 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3523 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3525 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3531 sprintf (buffer, "#(%s + %s)", left, right);
3532 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3537 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3539 /* Fetch into HL then do the add */
3540 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3541 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3543 spillPair (PAIR_HL);
3545 if (left == PAIR_HL && right != PAIR_INVALID)
3547 emit2 ("add hl,%s", _pairs[right].name);
3550 else if (right == PAIR_HL && left != PAIR_INVALID)
3552 emit2 ("add hl,%s", _pairs[left].name);
3555 else if (right != PAIR_INVALID && right != PAIR_HL)
3557 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3558 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3561 else if (left != PAIR_INVALID && left != PAIR_HL)
3563 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3564 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3573 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3575 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3576 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3578 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3583 ld hl,sp+n trashes C so we cant afford to do it during an
3584 add with stack based varibles. Worst case is:
3597 So you cant afford to load up hl if either left, right, or result
3598 is on the stack (*sigh*) The alt is:
3606 Combinations in here are:
3607 * If left or right are in bc then the loss is small - trap later
3608 * If the result is in bc then the loss is also small
3612 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3613 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3614 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3616 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3617 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3618 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3619 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3621 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3623 /* Swap left and right */
3624 operand *t = IC_RIGHT (ic);
3625 IC_RIGHT (ic) = IC_LEFT (ic);
3628 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3630 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3631 emit2 ("add hl,bc");
3635 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3636 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3637 emit2 ("add hl,de");
3639 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3645 /* Be paranoid on the GB with 4 byte variables due to how C
3646 can be trashed by lda hl,n(sp).
3648 _gbz80_emitAddSubLong (ic, TRUE);
3653 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3657 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3659 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3662 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3665 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3669 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3672 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3675 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3677 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3681 freeAsmop (IC_LEFT (ic), NULL, ic);
3682 freeAsmop (IC_RIGHT (ic), NULL, ic);
3683 freeAsmop (IC_RESULT (ic), NULL, ic);
3687 /*-----------------------------------------------------------------*/
3688 /* genMinusDec :- does subtraction with deccrement if possible */
3689 /*-----------------------------------------------------------------*/
3691 genMinusDec (iCode * ic)
3693 unsigned int icount;
3694 unsigned int size = getDataSize (IC_RESULT (ic));
3696 /* will try to generate an increment */
3697 /* if the right side is not a literal we cannot */
3698 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3701 /* if the literal value of the right hand side
3702 is greater than 4 then it is not worth it */
3703 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3706 size = getDataSize (IC_RESULT (ic));
3708 /* if decrement 16 bits in register */
3709 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3710 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3713 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3717 /* If result is a pair */
3718 if (isPair (AOP (IC_RESULT (ic))))
3720 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3722 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3726 /* if increment 16 bits in register */
3727 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3731 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3734 emit2 ("dec %s", _getTempPairName());
3737 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3743 /* if the sizes are greater than 1 then we cannot */
3744 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3745 AOP_SIZE (IC_LEFT (ic)) > 1)
3748 /* we can if the aops of the left & result match or if they are in
3749 registers and the registers are the same */
3750 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3753 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3760 /*-----------------------------------------------------------------*/
3761 /* genMinus - generates code for subtraction */
3762 /*-----------------------------------------------------------------*/
3764 genMinus (iCode * ic)
3766 int size, offset = 0;
3767 unsigned long lit = 0L;
3769 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3770 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3771 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3773 /* special cases :- */
3774 /* if both left & right are in bit space */
3775 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3776 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3778 wassertl (0, "Tried to subtract two bits");
3782 /* if I can do an decrement instead of subtract then GOOD for ME */
3783 if (genMinusDec (ic) == TRUE)
3786 size = getDataSize (IC_RESULT (ic));
3788 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3793 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3797 /* Same logic as genPlus */
3800 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3801 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3802 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3804 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3805 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3806 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3807 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3809 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3810 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3812 if (left == PAIR_INVALID && right == PAIR_INVALID)
3817 else if (right == PAIR_INVALID)
3819 else if (left == PAIR_INVALID)
3822 fetchPair (left, AOP (IC_LEFT (ic)));
3823 /* Order is important. Right may be HL */
3824 fetchPair (right, AOP (IC_RIGHT (ic)));
3826 emit2 ("ld a,%s", _pairs[left].l);
3827 emit2 ("sub a,%s", _pairs[right].l);
3829 emit2 ("ld a,%s", _pairs[left].h);
3830 emit2 ("sbc a,%s", _pairs[right].h);
3832 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
3834 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3836 aopPut (AOP (IC_RESULT (ic)), "e", 0);
3842 /* Be paranoid on the GB with 4 byte variables due to how C
3843 can be trashed by lda hl,n(sp).
3845 _gbz80_emitAddSubLong (ic, FALSE);
3850 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3852 /* if literal, add a,#-lit, else normal subb */
3855 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3856 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3860 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3863 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3867 /* first add without previous c */
3869 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
3871 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3873 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3876 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3877 AOP_SIZE (IC_LEFT (ic)) == 3 &&
3878 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3880 wassertl (0, "Tried to subtract on a long pointer");
3884 freeAsmop (IC_LEFT (ic), NULL, ic);
3885 freeAsmop (IC_RIGHT (ic), NULL, ic);
3886 freeAsmop (IC_RESULT (ic), NULL, ic);
3889 /*-----------------------------------------------------------------*/
3890 /* genMult - generates code for multiplication */
3891 /*-----------------------------------------------------------------*/
3893 genMult (iCode * ic)
3897 /* If true then the final operation should be a subtract */
3898 bool active = FALSE;
3900 /* Shouldn't occur - all done through function calls */
3901 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3902 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3903 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3905 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
3906 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
3907 AOP_SIZE (IC_RESULT (ic)) > 2)
3909 wassertl (0, "Multiplication is handled through support function calls");
3912 /* Swap left and right such that right is a literal */
3913 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
3915 operand *t = IC_RIGHT (ic);
3916 IC_RIGHT (ic) = IC_LEFT (ic);
3920 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
3922 val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
3923 // wassertl (val > 0, "Multiply must be positive");
3924 wassertl (val != 1, "Can't multiply by 1");
3926 if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
3928 _G.stack.pushedDE = TRUE;
3931 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
3933 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
3941 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3946 /* Fully unroled version of mul.s. Not the most efficient.
3948 for (count = 0; count < 16; count++)
3950 if (count != 0 && active)
3952 emit2 ("add hl,hl");
3956 if (active == FALSE)
3963 emit2 ("add hl,de");
3972 if (IS_Z80 && _G.stack.pushedDE)
3975 _G.stack.pushedDE = FALSE;
3978 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3980 freeAsmop (IC_LEFT (ic), NULL, ic);
3981 freeAsmop (IC_RIGHT (ic), NULL, ic);
3982 freeAsmop (IC_RESULT (ic), NULL, ic);
3985 /*-----------------------------------------------------------------*/
3986 /* genDiv - generates code for division */
3987 /*-----------------------------------------------------------------*/
3991 /* Shouldn't occur - all done through function calls */
3992 wassertl (0, "Division is handled through support function calls");
3995 /*-----------------------------------------------------------------*/
3996 /* genMod - generates code for division */
3997 /*-----------------------------------------------------------------*/
4001 /* Shouldn't occur - all done through function calls */
4005 /*-----------------------------------------------------------------*/
4006 /* genIfxJump :- will create a jump depending on the ifx */
4007 /*-----------------------------------------------------------------*/
4009 genIfxJump (iCode * ic, char *jval)
4014 /* if true label then we jump if condition
4018 jlbl = IC_TRUE (ic);
4019 if (!strcmp (jval, "a"))
4023 else if (!strcmp (jval, "c"))
4027 else if (!strcmp (jval, "nc"))
4031 else if (!strcmp (jval, "m"))
4035 else if (!strcmp (jval, "p"))
4041 /* The buffer contains the bit on A that we should test */
4047 /* false label is present */
4048 jlbl = IC_FALSE (ic);
4049 if (!strcmp (jval, "a"))
4053 else if (!strcmp (jval, "c"))
4057 else if (!strcmp (jval, "nc"))
4061 else if (!strcmp (jval, "m"))
4065 else if (!strcmp (jval, "p"))
4071 /* The buffer contains the bit on A that we should test */
4075 /* Z80 can do a conditional long jump */
4076 if (!strcmp (jval, "a"))
4080 else if (!strcmp (jval, "c"))
4083 else if (!strcmp (jval, "nc"))
4086 else if (!strcmp (jval, "m"))
4089 else if (!strcmp (jval, "p"))
4094 emit2 ("bit %s,a", jval);
4096 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
4098 /* mark the icode as generated */
4104 _getPairIdName (PAIR_ID id)
4106 return _pairs[id].name;
4111 /* if unsigned char cmp with lit, just compare */
4113 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4115 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4118 emit2 ("xor a,!immedbyte", 0x80);
4119 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4122 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4124 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4126 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4127 // Pull left into DE and right into HL
4128 aopGet (AOP(left), LSB, FALSE);
4131 aopGet (AOP(right), LSB, FALSE);
4135 if (size == 0 && sign)
4137 // Highest byte when signed needs the bits flipped
4140 emit2 ("ld a,(de)");
4141 emit2 ("xor !immedbyte", 0x80);
4143 emit2 ("ld a,(hl)");
4144 emit2 ("xor !immedbyte", 0x80);
4148 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4152 emit2 ("ld a,(de)");
4153 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4163 spillPair (PAIR_HL);
4165 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4167 setupPair (PAIR_HL, AOP (left), 0);
4168 aopGet (AOP(right), LSB, FALSE);
4172 if (size == 0 && sign)
4174 // Highest byte when signed needs the bits flipped
4177 emit2 ("ld a,(hl)");
4178 emit2 ("xor !immedbyte", 0x80);
4180 emit2 ("ld a,%d(iy)", offset);
4181 emit2 ("xor !immedbyte", 0x80);
4185 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4189 emit2 ("ld a,(hl)");
4190 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4199 spillPair (PAIR_HL);
4200 spillPair (PAIR_IY);
4204 if (AOP_TYPE (right) == AOP_LIT)
4206 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4207 /* optimize if(x < 0) or if(x >= 0) */
4212 /* No sign so it's always false */
4217 /* Just load in the top most bit */
4218 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4219 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4221 genIfxJump (ifx, "7");
4233 /* First setup h and l contaning the top most bytes XORed */
4234 bool fDidXor = FALSE;
4235 if (AOP_TYPE (left) == AOP_LIT)
4237 unsigned long lit = (unsigned long)
4238 floatFromVal (AOP (left)->aopu.aop_lit);
4239 emit2 ("ld %s,!immedbyte", _fTmp[0],
4240 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4244 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4245 emit2 ("xor a,!immedbyte", 0x80);
4246 emit2 ("ld %s,a", _fTmp[0]);
4249 if (AOP_TYPE (right) == AOP_LIT)
4251 unsigned long lit = (unsigned long)
4252 floatFromVal (AOP (right)->aopu.aop_lit);
4253 emit2 ("ld %s,!immedbyte", _fTmp[1],
4254 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4258 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4259 emit2 ("xor a,!immedbyte", 0x80);
4260 emit2 ("ld %s,a", _fTmp[1]);
4266 /* Do a long subtract */
4269 _moveA (aopGet (AOP (left), offset, FALSE));
4271 if (sign && size == 0)
4273 emit2 ("ld a,%s", _fTmp[0]);
4274 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4278 /* Subtract through, propagating the carry */
4279 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4287 /** Generic compare for > or <
4290 genCmp (operand * left, operand * right,
4291 operand * result, iCode * ifx, int sign)
4293 int size, offset = 0;
4294 unsigned long lit = 0L;
4295 bool swap_sense = FALSE;
4297 /* if left & right are bit variables */
4298 if (AOP_TYPE (left) == AOP_CRY &&
4299 AOP_TYPE (right) == AOP_CRY)
4301 /* Cant happen on the Z80 */
4302 wassertl (0, "Tried to compare two bits");
4306 /* Do a long subtract of right from left. */
4307 size = max (AOP_SIZE (left), AOP_SIZE (right));
4309 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4311 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4312 // Pull left into DE and right into HL
4313 aopGet (AOP(left), LSB, FALSE);
4316 aopGet (AOP(right), LSB, FALSE);
4320 emit2 ("ld a,(de)");
4321 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4330 spillPair (PAIR_HL);
4334 if (AOP_TYPE (right) == AOP_LIT)
4336 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4337 /* optimize if(x < 0) or if(x >= 0) */
4342 /* No sign so it's always false */
4347 /* Just load in the top most bit */
4348 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4349 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4351 genIfxJump (ifx, "7");
4362 genIfxJump (ifx, swap_sense ? "c" : "nc");
4373 _moveA (aopGet (AOP (left), offset, FALSE));
4374 /* Subtract through, propagating the carry */
4375 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4381 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4385 /* Shift the sign bit up into carry */
4388 outBitCLong (result, swap_sense);
4392 /* if the result is used in the next
4393 ifx conditional branch then generate
4394 code a little differently */
4402 genIfxJump (ifx, swap_sense ? "nc" : "c");
4406 genIfxJump (ifx, swap_sense ? "p" : "m");
4411 genIfxJump (ifx, swap_sense ? "nc" : "c");
4418 /* Shift the sign bit up into carry */
4421 outBitCLong (result, swap_sense);
4423 /* leave the result in acc */
4427 /*-----------------------------------------------------------------*/
4428 /* genCmpGt :- greater than comparison */
4429 /*-----------------------------------------------------------------*/
4431 genCmpGt (iCode * ic, iCode * ifx)
4433 operand *left, *right, *result;
4434 sym_link *letype, *retype;
4437 left = IC_LEFT (ic);
4438 right = IC_RIGHT (ic);
4439 result = IC_RESULT (ic);
4441 letype = getSpec (operandType (left));
4442 retype = getSpec (operandType (right));
4443 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4444 /* assign the amsops */
4445 aopOp (left, ic, FALSE, FALSE);
4446 aopOp (right, ic, FALSE, FALSE);
4447 aopOp (result, ic, TRUE, FALSE);
4449 genCmp (right, left, result, ifx, sign);
4451 freeAsmop (left, NULL, ic);
4452 freeAsmop (right, NULL, ic);
4453 freeAsmop (result, NULL, ic);
4456 /*-----------------------------------------------------------------*/
4457 /* genCmpLt - less than comparisons */
4458 /*-----------------------------------------------------------------*/
4460 genCmpLt (iCode * ic, iCode * ifx)
4462 operand *left, *right, *result;
4463 sym_link *letype, *retype;
4466 left = IC_LEFT (ic);
4467 right = IC_RIGHT (ic);
4468 result = IC_RESULT (ic);
4470 letype = getSpec (operandType (left));
4471 retype = getSpec (operandType (right));
4472 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4474 /* assign the amsops */
4475 aopOp (left, ic, FALSE, FALSE);
4476 aopOp (right, ic, FALSE, FALSE);
4477 aopOp (result, ic, TRUE, FALSE);
4479 genCmp (left, right, result, ifx, sign);
4481 freeAsmop (left, NULL, ic);
4482 freeAsmop (right, NULL, ic);
4483 freeAsmop (result, NULL, ic);
4486 /*-----------------------------------------------------------------*/
4487 /* gencjneshort - compare and jump if not equal */
4488 /*-----------------------------------------------------------------*/
4490 gencjneshort (operand * left, operand * right, symbol * lbl)
4492 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4494 unsigned long lit = 0L;
4496 /* Swap the left and right if it makes the computation easier */
4497 if (AOP_TYPE (left) == AOP_LIT)
4504 if (AOP_TYPE (right) == AOP_LIT)
4506 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4509 /* if the right side is a literal then anything goes */
4510 if (AOP_TYPE (right) == AOP_LIT &&
4511 AOP_TYPE (left) != AOP_DIR)
4515 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4520 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4527 emit2 ("jp nz,!tlabel", lbl->key + 100);
4533 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4534 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
4537 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
4538 emit2 ("jp nz,!tlabel", lbl->key + 100);
4543 /* if the right side is in a register or in direct space or
4544 if the left is a pointer register & right is not */
4545 else if (AOP_TYPE (right) == AOP_REG ||
4546 AOP_TYPE (right) == AOP_DIR ||
4547 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
4551 _moveA (aopGet (AOP (left), offset, FALSE));
4552 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
4553 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4555 emit2 ("jp nz,!tlabel", lbl->key + 100);
4558 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4559 emit2 ("jp nz,!tlabel", lbl->key + 100);
4566 /* right is a pointer reg need both a & b */
4567 /* PENDING: is this required? */
4570 _moveA (aopGet (AOP (right), offset, FALSE));
4571 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
4572 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
4578 /*-----------------------------------------------------------------*/
4579 /* gencjne - compare and jump if not equal */
4580 /*-----------------------------------------------------------------*/
4582 gencjne (operand * left, operand * right, symbol * lbl)
4584 symbol *tlbl = newiTempLabel (NULL);
4586 gencjneshort (left, right, lbl);
4589 emit2 ("ld a,!one");
4590 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4591 emitLabel (lbl->key + 100);
4593 emitLabel (tlbl->key + 100);
4596 /*-----------------------------------------------------------------*/
4597 /* genCmpEq - generates code for equal to */
4598 /*-----------------------------------------------------------------*/
4600 genCmpEq (iCode * ic, iCode * ifx)
4602 operand *left, *right, *result;
4604 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4605 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4606 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4608 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4610 /* Swap operands if it makes the operation easier. ie if:
4611 1. Left is a literal.
4613 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4615 operand *t = IC_RIGHT (ic);
4616 IC_RIGHT (ic) = IC_LEFT (ic);
4620 if (ifx && !AOP_SIZE (result))
4623 /* if they are both bit variables */
4624 if (AOP_TYPE (left) == AOP_CRY &&
4625 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4627 wassertl (0, "Tried to compare two bits");
4631 tlbl = newiTempLabel (NULL);
4632 gencjneshort (left, right, tlbl);
4635 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4636 emitLabel (tlbl->key + 100);
4640 /* PENDING: do this better */
4641 symbol *lbl = newiTempLabel (NULL);
4642 emit2 ("!shortjp !tlabel", lbl->key + 100);
4643 emitLabel (tlbl->key + 100);
4644 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4645 emitLabel (lbl->key + 100);
4648 /* mark the icode as generated */
4653 /* if they are both bit variables */
4654 if (AOP_TYPE (left) == AOP_CRY &&
4655 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4657 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4663 gencjne (left, right, newiTempLabel (NULL));
4664 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4671 genIfxJump (ifx, "a");
4674 /* if the result is used in an arithmetic operation
4675 then put the result in place */
4676 if (AOP_TYPE (result) != AOP_CRY)
4681 /* leave the result in acc */
4685 freeAsmop (left, NULL, ic);
4686 freeAsmop (right, NULL, ic);
4687 freeAsmop (result, NULL, ic);
4690 /*-----------------------------------------------------------------*/
4691 /* ifxForOp - returns the icode containing the ifx for operand */
4692 /*-----------------------------------------------------------------*/
4694 ifxForOp (operand * op, iCode * ic)
4696 /* if true symbol then needs to be assigned */
4697 if (IS_TRUE_SYMOP (op))
4700 /* if this has register type condition and
4701 the next instruction is ifx with the same operand
4702 and live to of the operand is upto the ifx only then */
4704 ic->next->op == IFX &&
4705 IC_COND (ic->next)->key == op->key &&
4706 OP_SYMBOL (op)->liveTo <= ic->next->seq)
4712 /*-----------------------------------------------------------------*/
4713 /* genAndOp - for && operation */
4714 /*-----------------------------------------------------------------*/
4716 genAndOp (iCode * ic)
4718 operand *left, *right, *result;
4721 /* note here that && operations that are in an if statement are
4722 taken away by backPatchLabels only those used in arthmetic
4723 operations remain */
4724 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4725 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4726 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4728 /* if both are bit variables */
4729 if (AOP_TYPE (left) == AOP_CRY &&
4730 AOP_TYPE (right) == AOP_CRY)
4732 wassertl (0, "Tried to and two bits");
4736 tlbl = newiTempLabel (NULL);
4738 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
4740 emitLabel (tlbl->key + 100);
4744 freeAsmop (left, NULL, ic);
4745 freeAsmop (right, NULL, ic);
4746 freeAsmop (result, NULL, ic);
4749 /*-----------------------------------------------------------------*/
4750 /* genOrOp - for || operation */
4751 /*-----------------------------------------------------------------*/
4753 genOrOp (iCode * ic)
4755 operand *left, *right, *result;
4758 /* note here that || operations that are in an
4759 if statement are taken away by backPatchLabels
4760 only those used in arthmetic operations remain */
4761 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4762 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4763 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4765 /* if both are bit variables */
4766 if (AOP_TYPE (left) == AOP_CRY &&
4767 AOP_TYPE (right) == AOP_CRY)
4769 wassertl (0, "Tried to OR two bits");
4773 tlbl = newiTempLabel (NULL);
4775 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4777 emitLabel (tlbl->key + 100);
4781 freeAsmop (left, NULL, ic);
4782 freeAsmop (right, NULL, ic);
4783 freeAsmop (result, NULL, ic);
4786 /*-----------------------------------------------------------------*/
4787 /* isLiteralBit - test if lit == 2^n */
4788 /*-----------------------------------------------------------------*/
4790 isLiteralBit (unsigned long lit)
4792 unsigned long pw[32] =
4793 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
4794 0x100L, 0x200L, 0x400L, 0x800L,
4795 0x1000L, 0x2000L, 0x4000L, 0x8000L,
4796 0x10000L, 0x20000L, 0x40000L, 0x80000L,
4797 0x100000L, 0x200000L, 0x400000L, 0x800000L,
4798 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
4799 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
4802 for (idx = 0; idx < 32; idx++)
4808 /*-----------------------------------------------------------------*/
4809 /* jmpTrueOrFalse - */
4810 /*-----------------------------------------------------------------*/
4812 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
4814 // ugly but optimized by peephole
4817 symbol *nlbl = newiTempLabel (NULL);
4818 emit2 ("jp !tlabel", nlbl->key + 100);
4819 emitLabel (tlbl->key + 100);
4820 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
4821 emitLabel (nlbl->key + 100);
4825 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
4826 emitLabel (tlbl->key + 100);
4831 /*-----------------------------------------------------------------*/
4832 /* genAnd - code for and */
4833 /*-----------------------------------------------------------------*/
4835 genAnd (iCode * ic, iCode * ifx)
4837 operand *left, *right, *result;
4838 int size, offset = 0;
4839 unsigned long lit = 0L;
4842 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4843 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4844 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4846 /* if left is a literal & right is not then exchange them */
4847 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4848 AOP_NEEDSACC (left))
4850 operand *tmp = right;
4855 /* if result = right then exchange them */
4856 if (sameRegs (AOP (result), AOP (right)))
4858 operand *tmp = right;
4863 /* if right is bit then exchange them */
4864 if (AOP_TYPE (right) == AOP_CRY &&
4865 AOP_TYPE (left) != AOP_CRY)
4867 operand *tmp = right;
4871 if (AOP_TYPE (right) == AOP_LIT)
4872 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4874 size = AOP_SIZE (result);
4876 if (AOP_TYPE (left) == AOP_CRY)
4878 wassertl (0, "Tried to perform an AND with a bit as an operand");
4882 // if(val & 0xZZ) - size = 0, ifx != FALSE -
4883 // bit = val & 0xZZ - size = 1, ifx = FALSE -
4884 if ((AOP_TYPE (right) == AOP_LIT) &&
4885 (AOP_TYPE (result) == AOP_CRY) &&
4886 (AOP_TYPE (left) != AOP_CRY))
4888 symbol *tlbl = newiTempLabel (NULL);
4889 int sizel = AOP_SIZE (left);
4892 /* PENDING: Test case for this. */
4897 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
4899 _moveA (aopGet (AOP (left), offset, FALSE));
4900 if (bytelit != 0x0FFL)
4902 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4909 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4913 // bit = left & literal
4917 emit2 ("!tlabeldef", tlbl->key + 100);
4919 // if(left & literal)
4924 jmpTrueOrFalse (ifx, tlbl);
4932 /* if left is same as result */
4933 if (sameRegs (AOP (result), AOP (left)))
4935 for (; size--; offset++)
4937 if (AOP_TYPE (right) == AOP_LIT)
4939 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4944 aopPut (AOP (result), "!zero", offset);
4947 _moveA (aopGet (AOP (left), offset, FALSE));
4949 aopGet (AOP (right), offset, FALSE));
4950 aopPut (AOP (left), "a", offset);
4957 if (AOP_TYPE (left) == AOP_ACC)
4959 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
4963 _moveA (aopGet (AOP (left), offset, FALSE));
4965 aopGet (AOP (right), offset, FALSE));
4966 aopPut (AOP (left), "a", offset);
4973 // left & result in different registers
4974 if (AOP_TYPE (result) == AOP_CRY)
4976 wassertl (0, "Tried to AND where the result is in carry");
4980 for (; (size--); offset++)
4983 // result = left & right
4984 if (AOP_TYPE (right) == AOP_LIT)
4986 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4988 aopPut (AOP (result),
4989 aopGet (AOP (left), offset, FALSE),
4993 else if (bytelit == 0)
4995 aopPut (AOP (result), "!zero", offset);
4999 // faster than result <- left, anl result,right
5000 // and better if result is SFR
5001 if (AOP_TYPE (left) == AOP_ACC)
5002 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5005 _moveA (aopGet (AOP (left), offset, FALSE));
5007 aopGet (AOP (right), offset, FALSE));
5009 aopPut (AOP (result), "a", offset);
5016 freeAsmop (left, NULL, ic);
5017 freeAsmop (right, NULL, ic);
5018 freeAsmop (result, NULL, ic);
5021 /*-----------------------------------------------------------------*/
5022 /* genOr - code for or */
5023 /*-----------------------------------------------------------------*/
5025 genOr (iCode * ic, iCode * ifx)
5027 operand *left, *right, *result;
5028 int size, offset = 0;
5029 unsigned long lit = 0L;
5032 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5033 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5034 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5036 /* if left is a literal & right is not then exchange them */
5037 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5038 AOP_NEEDSACC (left))
5040 operand *tmp = right;
5045 /* if result = right then exchange them */
5046 if (sameRegs (AOP (result), AOP (right)))
5048 operand *tmp = right;
5053 /* if right is bit then exchange them */
5054 if (AOP_TYPE (right) == AOP_CRY &&
5055 AOP_TYPE (left) != AOP_CRY)
5057 operand *tmp = right;
5061 if (AOP_TYPE (right) == AOP_LIT)
5062 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5064 size = AOP_SIZE (result);
5066 if (AOP_TYPE (left) == AOP_CRY)
5068 wassertl (0, "Tried to OR where left is a bit");
5072 // if(val | 0xZZ) - size = 0, ifx != FALSE -
5073 // bit = val | 0xZZ - size = 1, ifx = FALSE -
5074 if ((AOP_TYPE (right) == AOP_LIT) &&
5075 (AOP_TYPE (result) == AOP_CRY) &&
5076 (AOP_TYPE (left) != AOP_CRY))
5078 symbol *tlbl = newiTempLabel (NULL);
5079 int sizel = AOP_SIZE (left);
5083 wassertl (0, "Result is assigned to a bit");
5085 /* PENDING: Modeled after the AND code which is inefficent. */
5088 bytelit = (lit >> (offset * 8)) & 0x0FFL;
5090 _moveA (aopGet (AOP (left), offset, FALSE));
5091 /* OR with any literal is the same as OR with itself. */
5093 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5099 jmpTrueOrFalse (ifx, tlbl);
5104 /* if left is same as result */
5105 if (sameRegs (AOP (result), AOP (left)))
5107 for (; size--; offset++)
5109 if (AOP_TYPE (right) == AOP_LIT)
5111 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5115 _moveA (aopGet (AOP (left), offset, FALSE));
5117 aopGet (AOP (right), offset, FALSE));
5118 aopPut (AOP (result), "a", offset);
5123 if (AOP_TYPE (left) == AOP_ACC)
5124 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5127 _moveA (aopGet (AOP (left), offset, FALSE));
5129 aopGet (AOP (right), offset, FALSE));
5130 aopPut (AOP (result), "a", offset);
5137 // left & result in different registers
5138 if (AOP_TYPE (result) == AOP_CRY)
5140 wassertl (0, "Result of OR is in a bit");
5143 for (; (size--); offset++)
5146 // result = left & right
5147 if (AOP_TYPE (right) == AOP_LIT)
5149 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5151 aopPut (AOP (result),
5152 aopGet (AOP (left), offset, FALSE),
5157 // faster than result <- left, anl result,right
5158 // and better if result is SFR
5159 if (AOP_TYPE (left) == AOP_ACC)
5160 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5163 _moveA (aopGet (AOP (left), offset, FALSE));
5165 aopGet (AOP (right), offset, FALSE));
5167 aopPut (AOP (result), "a", offset);
5168 /* PENDING: something weird is going on here. Add exception. */
5169 if (AOP_TYPE (result) == AOP_ACC)
5175 freeAsmop (left, NULL, ic);
5176 freeAsmop (right, NULL, ic);
5177 freeAsmop (result, NULL, ic);
5180 /*-----------------------------------------------------------------*/
5181 /* genXor - code for xclusive or */
5182 /*-----------------------------------------------------------------*/
5184 genXor (iCode * ic, iCode * ifx)
5186 operand *left, *right, *result;
5187 int size, offset = 0;
5188 unsigned long lit = 0L;
5190 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5191 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5192 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5194 /* if left is a literal & right is not then exchange them */
5195 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5196 AOP_NEEDSACC (left))
5198 operand *tmp = right;
5203 /* if result = right then exchange them */
5204 if (sameRegs (AOP (result), AOP (right)))
5206 operand *tmp = right;
5211 /* if right is bit then exchange them */
5212 if (AOP_TYPE (right) == AOP_CRY &&
5213 AOP_TYPE (left) != AOP_CRY)
5215 operand *tmp = right;
5219 if (AOP_TYPE (right) == AOP_LIT)
5220 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5222 size = AOP_SIZE (result);
5224 if (AOP_TYPE (left) == AOP_CRY)
5226 wassertl (0, "Tried to XOR a bit");
5230 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5231 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5232 if ((AOP_TYPE (right) == AOP_LIT) &&
5233 (AOP_TYPE (result) == AOP_CRY) &&
5234 (AOP_TYPE (left) != AOP_CRY))
5236 symbol *tlbl = newiTempLabel (NULL);
5237 int sizel = AOP_SIZE (left);
5241 /* PENDING: Test case for this. */
5242 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5246 _moveA (aopGet (AOP (left), offset, FALSE));
5247 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5248 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5253 jmpTrueOrFalse (ifx, tlbl);
5257 wassertl (0, "Result of XOR was destined for a bit");
5262 /* if left is same as result */
5263 if (sameRegs (AOP (result), AOP (left)))
5265 for (; size--; offset++)
5267 if (AOP_TYPE (right) == AOP_LIT)
5269 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5273 _moveA (aopGet (AOP (right), offset, FALSE));
5275 aopGet (AOP (left), offset, FALSE));
5276 aopPut (AOP (result), "a", offset);
5281 if (AOP_TYPE (left) == AOP_ACC)
5283 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5287 _moveA (aopGet (AOP (right), offset, FALSE));
5289 aopGet (AOP (left), offset, FALSE));
5290 aopPut (AOP (result), "a", offset);
5297 // left & result in different registers
5298 if (AOP_TYPE (result) == AOP_CRY)
5300 wassertl (0, "Result of XOR is in a bit");
5303 for (; (size--); offset++)
5306 // result = left & right
5307 if (AOP_TYPE (right) == AOP_LIT)
5309 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5311 aopPut (AOP (result),
5312 aopGet (AOP (left), offset, FALSE),
5317 // faster than result <- left, anl result,right
5318 // and better if result is SFR
5319 if (AOP_TYPE (left) == AOP_ACC)
5321 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5325 _moveA (aopGet (AOP (right), offset, FALSE));
5327 aopGet (AOP (left), offset, FALSE));
5329 aopPut (AOP (result), "a", offset);
5334 freeAsmop (left, NULL, ic);
5335 freeAsmop (right, NULL, ic);
5336 freeAsmop (result, NULL, ic);
5339 /*-----------------------------------------------------------------*/
5340 /* genInline - write the inline code out */
5341 /*-----------------------------------------------------------------*/
5343 genInline (iCode * ic)
5345 char *buffer, *bp, *bp1;
5347 _G.lines.isInline += (!options.asmpeep);
5349 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5350 strcpy (buffer, IC_INLINE (ic));
5352 /* emit each line as a code */
5377 _G.lines.isInline -= (!options.asmpeep);
5381 /*-----------------------------------------------------------------*/
5382 /* genRRC - rotate right with carry */
5383 /*-----------------------------------------------------------------*/
5390 /*-----------------------------------------------------------------*/
5391 /* genRLC - generate code for rotate left with carry */
5392 /*-----------------------------------------------------------------*/
5399 /*-----------------------------------------------------------------*/
5400 /* genGetHbit - generates code get highest order bit */
5401 /*-----------------------------------------------------------------*/
5403 genGetHbit (iCode * ic)
5405 operand *left, *result;
5406 left = IC_LEFT (ic);
5407 result = IC_RESULT (ic);
5409 aopOp (left, ic, FALSE, FALSE);
5410 aopOp (result, ic, FALSE, FALSE);
5412 /* get the highest order byte into a */
5413 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5415 if (AOP_TYPE (result) == AOP_CRY)
5423 emit2 ("and a,!one");
5428 freeAsmop (left, NULL, ic);
5429 freeAsmop (result, NULL, ic);
5433 emitRsh2 (asmop *aop, int size, int is_signed)
5439 const char *l = aopGet (aop, size, FALSE);
5442 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5452 /*-----------------------------------------------------------------*/
5453 /* shiftR2Left2Result - shift right two bytes from left to result */
5454 /*-----------------------------------------------------------------*/
5456 shiftR2Left2Result (operand * left, int offl,
5457 operand * result, int offr,
5458 int shCount, int is_signed)
5461 symbol *tlbl, *tlbl1;
5463 movLeft2Result (left, offl, result, offr, 0);
5464 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5466 /* if (AOP(result)->type == AOP_REG) { */
5468 tlbl = newiTempLabel (NULL);
5469 tlbl1 = newiTempLabel (NULL);
5471 /* Left is already in result - so now do the shift */
5476 emitRsh2 (AOP (result), size, is_signed);
5481 emit2 ("ld a,!immedbyte+1", shCount);
5482 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5483 emitLabel (tlbl->key + 100);
5485 emitRsh2 (AOP (result), size, is_signed);
5487 emitLabel (tlbl1->key + 100);
5489 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5493 /*-----------------------------------------------------------------*/
5494 /* shiftL2Left2Result - shift left two bytes from left to result */
5495 /*-----------------------------------------------------------------*/
5497 shiftL2Left2Result (operand * left, int offl,
5498 operand * result, int offr, int shCount)
5500 if (sameRegs (AOP (result), AOP (left)) &&
5501 ((offl + MSB16) == offr))
5507 /* Copy left into result */
5508 movLeft2Result (left, offl, result, offr, 0);
5509 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5512 if (getPairId (AOP (result)) == PAIR_HL)
5516 emit2 ("add hl,hl");
5523 symbol *tlbl, *tlbl1;
5526 tlbl = newiTempLabel (NULL);
5527 tlbl1 = newiTempLabel (NULL);
5529 if (AOP (result)->type == AOP_REG)
5533 for (offset = 0; offset < size; offset++)
5535 l = aopGet (AOP (result), offset, FALSE);
5539 emit2 ("sla %s", l);
5550 /* Left is already in result - so now do the shift */
5553 emit2 ("ld a,!immedbyte+1", shCount);
5554 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5555 emitLabel (tlbl->key + 100);
5560 l = aopGet (AOP (result), offset, FALSE);
5564 emit2 ("sla %s", l);
5575 emitLabel (tlbl1->key + 100);
5577 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5583 /*-----------------------------------------------------------------*/
5584 /* AccRol - rotate left accumulator by known count */
5585 /*-----------------------------------------------------------------*/
5587 AccRol (int shCount)
5589 shCount &= 0x0007; // shCount : 0..7
5666 /*-----------------------------------------------------------------*/
5667 /* AccLsh - left shift accumulator by known count */
5668 /*-----------------------------------------------------------------*/
5670 AccLsh (int shCount)
5672 static const unsigned char SLMask[] =
5674 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5683 else if (shCount == 2)
5690 /* rotate left accumulator */
5692 /* and kill the lower order bits */
5693 emit2 ("and a,!immedbyte", SLMask[shCount]);
5698 /*-----------------------------------------------------------------*/
5699 /* shiftL1Left2Result - shift left one byte from left to result */
5700 /*-----------------------------------------------------------------*/
5702 shiftL1Left2Result (operand * left, int offl,
5703 operand * result, int offr, int shCount)
5706 l = aopGet (AOP (left), offl, FALSE);
5708 /* shift left accumulator */
5710 aopPut (AOP (result), "a", offr);
5714 /*-----------------------------------------------------------------*/
5715 /* genlshTwo - left shift two bytes by known amount != 0 */
5716 /*-----------------------------------------------------------------*/
5718 genlshTwo (operand * result, operand * left, int shCount)
5720 int size = AOP_SIZE (result);
5722 wassert (size == 2);
5724 /* if shCount >= 8 */
5732 movLeft2Result (left, LSB, result, MSB16, 0);
5733 aopPut (AOP (result), "!zero", 0);
5734 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
5738 movLeft2Result (left, LSB, result, MSB16, 0);
5739 aopPut (AOP (result), "!zero", 0);
5744 aopPut (AOP (result), "!zero", LSB);
5747 /* 1 <= shCount <= 7 */
5756 shiftL2Left2Result (left, LSB, result, LSB, shCount);
5761 /*-----------------------------------------------------------------*/
5762 /* genlshOne - left shift a one byte quantity by known count */
5763 /*-----------------------------------------------------------------*/
5765 genlshOne (operand * result, operand * left, int shCount)
5767 shiftL1Left2Result (left, LSB, result, LSB, shCount);
5770 /*-----------------------------------------------------------------*/
5771 /* genLeftShiftLiteral - left shifting by known count */
5772 /*-----------------------------------------------------------------*/
5774 genLeftShiftLiteral (operand * left,
5779 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5782 freeAsmop (right, NULL, ic);
5784 aopOp (left, ic, FALSE, FALSE);
5785 aopOp (result, ic, FALSE, FALSE);
5787 size = getSize (operandType (result));
5789 /* I suppose that the left size >= result size */
5795 else if (shCount >= (size * 8))
5799 aopPut (AOP (result), "!zero", size);
5807 genlshOne (result, left, shCount);
5810 genlshTwo (result, left, shCount);
5813 wassertl (0, "Shifting of longs is currently unsupported");
5819 freeAsmop (left, NULL, ic);
5820 freeAsmop (result, NULL, ic);
5823 /*-----------------------------------------------------------------*/
5824 /* genLeftShift - generates code for left shifting */
5825 /*-----------------------------------------------------------------*/
5827 genLeftShift (iCode * ic)
5831 symbol *tlbl, *tlbl1;
5832 operand *left, *right, *result;
5834 right = IC_RIGHT (ic);
5835 left = IC_LEFT (ic);
5836 result = IC_RESULT (ic);
5838 aopOp (right, ic, FALSE, FALSE);
5840 /* if the shift count is known then do it
5841 as efficiently as possible */
5842 if (AOP_TYPE (right) == AOP_LIT)
5844 genLeftShiftLiteral (left, right, result, ic);
5848 /* shift count is unknown then we have to form a loop get the loop
5849 count in B : Note: we take only the lower order byte since
5850 shifting more that 32 bits make no sense anyway, ( the largest
5851 size of an object can be only 32 bits ) */
5852 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5854 freeAsmop (right, NULL, ic);
5855 aopOp (left, ic, FALSE, FALSE);
5856 aopOp (result, ic, FALSE, FALSE);
5858 /* now move the left to the result if they are not the
5861 if (!sameRegs (AOP (left), AOP (result)))
5864 size = AOP_SIZE (result);
5868 l = aopGet (AOP (left), offset, FALSE);
5869 aopPut (AOP (result), l, offset);
5874 tlbl = newiTempLabel (NULL);
5875 size = AOP_SIZE (result);
5877 tlbl1 = newiTempLabel (NULL);
5879 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5880 emitLabel (tlbl->key + 100);
5881 l = aopGet (AOP (result), offset, FALSE);
5885 l = aopGet (AOP (result), offset, FALSE);
5889 emit2 ("sla %s", l);
5897 emitLabel (tlbl1->key + 100);
5899 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5901 freeAsmop (left, NULL, ic);
5902 freeAsmop (result, NULL, ic);
5905 /*-----------------------------------------------------------------*/
5906 /* genrshOne - left shift two bytes by known amount != 0 */
5907 /*-----------------------------------------------------------------*/
5909 genrshOne (operand * result, operand * left, int shCount, int is_signed)
5912 int size = AOP_SIZE (result);
5915 wassert (size == 1);
5916 wassert (shCount < 8);
5918 l = aopGet (AOP (left), 0, FALSE);
5920 if (AOP (result)->type == AOP_REG)
5922 aopPut (AOP (result), l, 0);
5923 l = aopGet (AOP (result), 0, FALSE);
5926 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5934 emit2 ("%s a", is_signed ? "sra" : "srl");
5936 aopPut (AOP (result), "a", 0);
5940 /*-----------------------------------------------------------------*/
5941 /* AccRsh - right shift accumulator by known count */
5942 /*-----------------------------------------------------------------*/
5944 AccRsh (int shCount)
5946 static const unsigned char SRMask[] =
5948 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
5953 /* rotate right accumulator */
5954 AccRol (8 - shCount);
5955 /* and kill the higher order bits */
5956 emit2 ("and a,!immedbyte", SRMask[shCount]);
5960 /*-----------------------------------------------------------------*/
5961 /* shiftR1Left2Result - shift right one byte from left to result */
5962 /*-----------------------------------------------------------------*/
5964 shiftR1Left2Result (operand * left, int offl,
5965 operand * result, int offr,
5966 int shCount, int sign)
5968 _moveA (aopGet (AOP (left), offl, FALSE));
5973 emit2 ("%s a", sign ? "sra" : "srl");
5980 aopPut (AOP (result), "a", offr);
5983 /*-----------------------------------------------------------------*/
5984 /* genrshTwo - right shift two bytes by known amount != 0 */
5985 /*-----------------------------------------------------------------*/
5987 genrshTwo (operand * result, operand * left,
5988 int shCount, int sign)
5990 /* if shCount >= 8 */
5996 shiftR1Left2Result (left, MSB16, result, LSB,
6001 movLeft2Result (left, MSB16, result, LSB, sign);
6005 /* Sign extend the result */
6006 _moveA(aopGet (AOP (result), 0, FALSE));
6010 aopPut (AOP (result), ACC_NAME, MSB16);
6014 aopPut (AOP (result), "!zero", 1);
6017 /* 1 <= shCount <= 7 */
6020 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
6024 /*-----------------------------------------------------------------*/
6025 /* genRightShiftLiteral - left shifting by known count */
6026 /*-----------------------------------------------------------------*/
6028 genRightShiftLiteral (operand * left,
6034 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6037 freeAsmop (right, NULL, ic);
6039 aopOp (left, ic, FALSE, FALSE);
6040 aopOp (result, ic, FALSE, FALSE);
6042 size = getSize (operandType (result));
6044 /* I suppose that the left size >= result size */
6050 else if (shCount >= (size * 8)) {
6052 if (!SPEC_USIGN(getSpec(operandType(left)))) {
6053 _moveA(aopGet (AOP (left), 0, FALSE));
6061 aopPut (AOP (result), s, size);
6068 genrshOne (result, left, shCount, sign);
6071 genrshTwo (result, left, shCount, sign);
6074 wassertl (0, "Asked to shift right a long which should be a function call");
6077 wassertl (0, "Entered default case in right shift delegate");
6080 freeAsmop (left, NULL, ic);
6081 freeAsmop (result, NULL, ic);
6084 /*-----------------------------------------------------------------*/
6085 /* genRightShift - generate code for right shifting */
6086 /*-----------------------------------------------------------------*/
6088 genRightShift (iCode * ic)
6090 operand *right, *left, *result;
6092 int size, offset, first = 1;
6096 symbol *tlbl, *tlbl1;
6098 /* if signed then we do it the hard way preserve the
6099 sign bit moving it inwards */
6100 retype = getSpec (operandType (IC_RESULT (ic)));
6102 is_signed = !SPEC_USIGN (retype);
6104 /* signed & unsigned types are treated the same : i.e. the
6105 signed is NOT propagated inwards : quoting from the
6106 ANSI - standard : "for E1 >> E2, is equivalent to division
6107 by 2**E2 if unsigned or if it has a non-negative value,
6108 otherwise the result is implementation defined ", MY definition
6109 is that the sign does not get propagated */
6111 right = IC_RIGHT (ic);
6112 left = IC_LEFT (ic);
6113 result = IC_RESULT (ic);
6115 aopOp (right, ic, FALSE, FALSE);
6117 /* if the shift count is known then do it
6118 as efficiently as possible */
6119 if (AOP_TYPE (right) == AOP_LIT)
6121 genRightShiftLiteral (left, right, result, ic, is_signed);
6125 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6127 freeAsmop (right, NULL, ic);
6129 aopOp (left, ic, FALSE, FALSE);
6130 aopOp (result, ic, FALSE, FALSE);
6132 /* now move the left to the result if they are not the
6134 if (!sameRegs (AOP (left), AOP (result)))
6137 size = AOP_SIZE (result);
6141 l = aopGet (AOP (left), offset, FALSE);
6142 aopPut (AOP (result), l, offset);
6147 tlbl = newiTempLabel (NULL);
6148 tlbl1 = newiTempLabel (NULL);
6149 size = AOP_SIZE (result);
6152 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6153 emitLabel (tlbl->key + 100);
6156 l = aopGet (AOP (result), offset--, FALSE);
6159 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6167 emitLabel (tlbl1->key + 100);
6169 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6171 freeAsmop (left, NULL, ic);
6172 freeAsmop (result, NULL, ic);
6176 /*-----------------------------------------------------------------*/
6177 /* genUnpackBits - generates code for unpacking bits */
6178 /*-----------------------------------------------------------------*/
6180 genUnpackBits (operand * result, int pair)
6182 int offset = 0; /* result byte offset */
6183 int rsize; /* result size */
6184 int rlen = 0; /* remaining bitfield length */
6185 sym_link *etype; /* bitfield type information */
6186 int blen; /* bitfield length */
6187 int bstr; /* bitfield starting bit within byte */
6189 emitDebug ("; genUnpackBits");
6191 etype = getSpec (operandType (result));
6192 rsize = getSize (operandType (result));
6193 blen = SPEC_BLEN (etype);
6194 bstr = SPEC_BSTR (etype);
6196 /* If the bitfield length is less than a byte */
6199 emit2 ("ld a,!*pair", _pairs[pair].name);
6201 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6202 aopPut (AOP (result), "a", offset++);
6206 /* TODO: what if pair == PAIR_DE ? */
6207 if (getPairId (AOP (result)) == PAIR_HL)
6209 wassertl (rsize == 2, "HL must be of size 2");
6210 emit2 ("ld a,!*hl");
6212 emit2 ("ld h,!*hl");
6215 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6217 spillPair (PAIR_HL);
6221 /* Bit field did not fit in a byte. Copy all
6222 but the partial byte at the end. */
6223 for (rlen=blen;rlen>=8;rlen-=8)
6225 emit2 ("ld a,!*pair", _pairs[pair].name);
6226 aopPut (AOP (result), "a", offset++);
6229 emit2 ("inc %s", _pairs[pair].name);
6230 _G.pairs[pair].offset++;
6234 /* Handle the partial byte at the end */
6237 emit2 ("ld a,!*pair", _pairs[pair].name);
6238 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6239 aopPut (AOP (result), "a", offset++);
6247 aopPut (AOP (result), "!zero", offset++);
6251 /*-----------------------------------------------------------------*/
6252 /* genGenPointerGet - get value from generic pointer space */
6253 /*-----------------------------------------------------------------*/
6255 genGenPointerGet (operand * left,
6256 operand * result, iCode * ic)
6259 sym_link *retype = getSpec (operandType (result));
6265 aopOp (left, ic, FALSE, FALSE);
6266 aopOp (result, ic, FALSE, FALSE);
6268 size = AOP_SIZE (result);
6270 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6273 if (isPtrPair (AOP (left)))
6275 tsprintf (buffer, sizeof(buffer),
6276 "!*pair", getPairName (AOP (left)));
6277 aopPut (AOP (result), buffer, 0);
6281 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6282 aopPut (AOP (result), "a", 0);
6284 freeAsmop (left, NULL, ic);
6288 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6295 tsprintf (at, sizeof(at), "!*iyx", offset);
6296 aopPut (AOP (result), at, offset);
6300 freeAsmop (left, NULL, ic);
6304 /* For now we always load into IY */
6305 /* if this is remateriazable */
6306 fetchPair (pair, AOP (left));
6308 /* if bit then unpack */
6309 if (IS_BITVAR (retype))
6311 genUnpackBits (result, pair);
6312 freeAsmop (left, NULL, ic);
6316 else if (getPairId (AOP (result)) == PAIR_HL)
6318 wassertl (size == 2, "HL must be of size 2");
6319 emit2 ("ld a,!*hl");
6321 emit2 ("ld h,!*hl");
6323 spillPair (PAIR_HL);
6325 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6327 size = AOP_SIZE (result);
6332 /* PENDING: make this better */
6333 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6335 aopPut (AOP (result), "!*hl", offset++);
6339 emit2 ("ld a,!*pair", _pairs[pair].name);
6340 aopPut (AOP (result), "a", offset++);
6344 emit2 ("inc %s", _pairs[pair].name);
6345 _G.pairs[pair].offset++;
6348 /* Fixup HL back down */
6349 for (size = AOP_SIZE (result)-1; size; size--)
6351 emit2 ("dec %s", _pairs[pair].name);
6356 size = AOP_SIZE (result);
6361 /* PENDING: make this better */
6363 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6365 aopPut (AOP (result), "!*hl", offset++);
6369 emit2 ("ld a,!*pair", _pairs[pair].name);
6370 aopPut (AOP (result), "a", offset++);
6374 emit2 ("inc %s", _pairs[pair].name);
6375 _G.pairs[pair].offset++;
6380 freeAsmop (left, NULL, ic);
6383 freeAsmop (result, NULL, ic);
6386 /*-----------------------------------------------------------------*/
6387 /* genPointerGet - generate code for pointer get */
6388 /*-----------------------------------------------------------------*/
6390 genPointerGet (iCode * ic)
6392 operand *left, *result;
6393 sym_link *type, *etype;
6395 left = IC_LEFT (ic);
6396 result = IC_RESULT (ic);
6398 /* depending on the type of pointer we need to
6399 move it to the correct pointer register */
6400 type = operandType (left);
6401 etype = getSpec (type);
6403 genGenPointerGet (left, result, ic);
6407 isRegOrLit (asmop * aop)
6409 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6415 /*-----------------------------------------------------------------*/
6416 /* genPackBits - generates code for packed bit storage */
6417 /*-----------------------------------------------------------------*/
6419 genPackBits (sym_link * etype,
6424 int offset = 0; /* source byte offset */
6425 int rlen = 0; /* remaining bitfield length */
6426 int blen; /* bitfield length */
6427 int bstr; /* bitfield starting bit within byte */
6428 int litval; /* source literal value (if AOP_LIT) */
6429 unsigned char mask; /* bitmask within current byte */
6430 int extraPair; /* a tempory register */
6431 bool needPopExtra=0; /* need to restore original value of temp reg */
6433 emitDebug ("; genPackBits","");
6435 blen = SPEC_BLEN (etype);
6436 bstr = SPEC_BSTR (etype);
6438 /* If the bitfield length is less than a byte */
6441 mask = ((unsigned char) (0xFF << (blen + bstr)) |
6442 (unsigned char) (0xFF >> (8 - bstr)));
6444 if (AOP_TYPE (right) == AOP_LIT)
6446 /* Case with a bitfield length <8 and literal source
6448 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6450 litval &= (~mask) & 0xff;
6451 emit2 ("ld a,!*pair", _pairs[pair].name);
6452 if ((mask|litval)!=0xff)
6453 emit2 ("and a,!immedbyte", mask);
6455 emit2 ("or a,!immedbyte", litval);
6456 emit2 ("ld !*pair,a", _pairs[pair].name);
6461 /* Case with a bitfield length <8 and arbitrary source
6463 _moveA (aopGet (AOP (right), 0, FALSE));
6464 /* shift and mask source value */
6466 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6468 extraPair = getFreePairId(ic);
6469 if (extraPair == PAIR_INVALID)
6471 extraPair = PAIR_BC;
6472 if (getPairId (AOP (right)) != PAIR_BC
6473 || !isLastUse (ic, right))
6479 emit2 ("ld %s,a", _pairs[extraPair].l);
6480 emit2 ("ld a,!*pair", _pairs[pair].name);
6482 emit2 ("and a,!immedbyte", mask);
6483 emit2 ("or a,%s", _pairs[extraPair].l);
6484 emit2 ("ld !*pair,a", _pairs[pair].name);
6491 /* Bit length is greater than 7 bits. In this case, copy */
6492 /* all except the partial byte at the end */
6493 for (rlen=blen;rlen>=8;rlen-=8)
6495 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
6496 emit2 ("ld !*pair,a", _pairs[pair].name);
6499 emit2 ("inc %s", _pairs[pair].name);
6500 _G.pairs[pair].offset++;
6504 /* If there was a partial byte at the end */
6507 mask = (((unsigned char) -1 << rlen) & 0xff);
6509 if (AOP_TYPE (right) == AOP_LIT)
6511 /* Case with partial byte and literal source
6513 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6514 litval >>= (blen-rlen);
6515 litval &= (~mask) & 0xff;
6516 emit2 ("ld a,!*pair", _pairs[pair].name);
6517 if ((mask|litval)!=0xff)
6518 emit2 ("and a,!immedbyte", mask);
6520 emit2 ("or a,!immedbyte", litval);
6524 /* Case with partial byte and arbitrary source
6526 _moveA (aopGet (AOP (right), offset++, FALSE));
6527 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6529 extraPair = getFreePairId(ic);
6530 if (extraPair == PAIR_INVALID)
6532 extraPair = getPairId (AOP (right));
6533 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
6534 extraPair = PAIR_BC;
6536 if (getPairId (AOP (right)) != PAIR_BC
6537 || !isLastUse (ic, right))
6543 emit2 ("ld %s,a", _pairs[extraPair].l);
6544 emit2 ("ld a,!*pair", _pairs[pair].name);
6546 emit2 ("and a,!immedbyte", mask);
6547 emit2 ("or a,%s", _pairs[extraPair].l);
6552 emit2 ("ld !*pair,a", _pairs[pair].name);
6557 /*-----------------------------------------------------------------*/
6558 /* genGenPointerSet - stores the value into a pointer location */
6559 /*-----------------------------------------------------------------*/
6561 genGenPointerSet (operand * right,
6562 operand * result, iCode * ic)
6565 sym_link *retype = getSpec (operandType (right));
6566 sym_link *letype = getSpec (operandType (result));
6567 PAIR_ID pairId = PAIR_HL;
6570 aopOp (result, ic, FALSE, FALSE);
6571 aopOp (right, ic, FALSE, FALSE);
6576 size = AOP_SIZE (right);
6578 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
6579 emitDebug("; isBitvar = %d", isBitvar);
6581 /* Handle the exceptions first */
6582 if (isPair (AOP (result)) && size == 1 && !isBitvar)
6585 const char *l = aopGet (AOP (right), 0, FALSE);
6586 const char *pair = getPairName (AOP (result));
6587 if (canAssignToPtr (l) && isPtr (pair))
6589 emit2 ("ld !*pair,%s", pair, l);
6594 emit2 ("ld !*pair,a", pair);
6599 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
6602 const char *l = aopGet (AOP (right), 0, FALSE);
6607 if (canAssignToPtr (l))
6609 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6613 _moveA (aopGet (AOP (right), offset, FALSE));
6614 emit2 ("ld !*iyx,a", offset);
6620 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
6627 const char *l = aopGet (AOP (right), offset, FALSE);
6628 if (isRegOrLit (AOP (right)) && !IS_GB)
6630 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
6635 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
6639 emit2 ("inc %s", _pairs[PAIR_HL].name);
6640 _G.pairs[PAIR_HL].offset++;
6645 /* Fixup HL back down */
6646 for (size = AOP_SIZE (right)-1; size; size--)
6648 emit2 ("dec %s", _pairs[PAIR_HL].name);
6653 /* if the operand is already in dptr
6654 then we do nothing else we move the value to dptr */
6655 if (AOP_TYPE (result) != AOP_STR)
6657 fetchPair (pairId, AOP (result));
6659 /* so hl know contains the address */
6660 freeAsmop (result, NULL, ic);
6662 /* if bit then unpack */
6665 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
6675 const char *l = aopGet (AOP (right), offset, FALSE);
6676 if (isRegOrLit (AOP (right)) && !IS_GB)
6678 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
6683 emit2 ("ld !*pair,a", _pairs[pairId].name);
6687 emit2 ("inc %s", _pairs[pairId].name);
6688 _G.pairs[pairId].offset++;
6694 freeAsmop (right, NULL, ic);
6697 /*-----------------------------------------------------------------*/
6698 /* genPointerSet - stores the value into a pointer location */
6699 /*-----------------------------------------------------------------*/
6701 genPointerSet (iCode * ic)
6703 operand *right, *result;
6704 sym_link *type, *etype;
6706 right = IC_RIGHT (ic);
6707 result = IC_RESULT (ic);
6709 /* depending on the type of pointer we need to
6710 move it to the correct pointer register */
6711 type = operandType (result);
6712 etype = getSpec (type);
6714 genGenPointerSet (right, result, ic);
6717 /*-----------------------------------------------------------------*/
6718 /* genIfx - generate code for Ifx statement */
6719 /*-----------------------------------------------------------------*/
6721 genIfx (iCode * ic, iCode * popIc)
6723 operand *cond = IC_COND (ic);
6726 aopOp (cond, ic, FALSE, TRUE);
6728 /* get the value into acc */
6729 if (AOP_TYPE (cond) != AOP_CRY)
6733 /* the result is now in the accumulator */
6734 freeAsmop (cond, NULL, ic);
6736 /* if there was something to be popped then do it */
6740 /* if the condition is a bit variable */
6741 if (isbit && IS_ITEMP (cond) &&
6743 genIfxJump (ic, SPIL_LOC (cond)->rname);
6744 else if (isbit && !IS_ITEMP (cond))
6745 genIfxJump (ic, OP_SYMBOL (cond)->rname);
6747 genIfxJump (ic, "a");
6752 /*-----------------------------------------------------------------*/
6753 /* genAddrOf - generates code for address of */
6754 /*-----------------------------------------------------------------*/
6756 genAddrOf (iCode * ic)
6758 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
6760 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6762 /* if the operand is on the stack then we
6763 need to get the stack offset of this
6770 if (sym->stack <= 0)
6772 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
6776 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6778 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6782 emit2 ("ld de,!hashedstr", sym->rname);
6783 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
6791 /* if it has an offset then we need to compute it */
6793 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6795 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
6796 emit2 ("add hl,sp");
6800 emit2 ("ld hl,!hashedstr", sym->rname);
6802 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6804 freeAsmop (IC_RESULT (ic), NULL, ic);
6807 /*-----------------------------------------------------------------*/
6808 /* genAssign - generate code for assignment */
6809 /*-----------------------------------------------------------------*/
6811 genAssign (iCode * ic)
6813 operand *result, *right;
6815 unsigned long lit = 0L;
6817 result = IC_RESULT (ic);
6818 right = IC_RIGHT (ic);
6820 /* Dont bother assigning if they are the same */
6821 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6823 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
6827 aopOp (right, ic, FALSE, FALSE);
6828 aopOp (result, ic, TRUE, FALSE);
6830 /* if they are the same registers */
6831 if (sameRegs (AOP (right), AOP (result)))
6833 emitDebug ("; (registers are the same)");
6837 /* if the result is a bit */
6838 if (AOP_TYPE (result) == AOP_CRY)
6840 wassertl (0, "Tried to assign to a bit");
6844 size = AOP_SIZE (result);
6847 if (AOP_TYPE (right) == AOP_LIT)
6849 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6852 if (isPair (AOP (result)))
6854 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
6856 else if ((size > 1) &&
6857 (AOP_TYPE (result) != AOP_REG) &&
6858 (AOP_TYPE (right) == AOP_LIT) &&
6859 !IS_FLOAT (operandType (right)) &&
6862 bool fXored = FALSE;
6864 /* Work from the top down.
6865 Done this way so that we can use the cached copy of 0
6866 in A for a fast clear */
6869 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
6871 if (!fXored && size > 1)
6878 aopPut (AOP (result), "a", offset);
6882 aopPut (AOP (result), "!zero", offset);
6886 aopPut (AOP (result),
6887 aopGet (AOP (right), offset, FALSE),
6892 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
6894 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
6895 aopPut (AOP (result), "l", LSB);
6896 aopPut (AOP (result), "h", MSB16);
6898 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6900 /* Special case. Load into a and d, then load out. */
6901 _moveA (aopGet (AOP (right), 0, FALSE));
6902 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
6903 aopPut (AOP (result), "a", 0);
6904 aopPut (AOP (result), "e", 1);
6906 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6908 /* Special case - simple memcpy */
6909 aopGet (AOP (right), LSB, FALSE);
6912 aopGet (AOP (result), LSB, FALSE);
6916 emit2 ("ld a,(de)");
6917 /* Peephole will optimise this. */
6918 emit2 ("ld (hl),a");
6926 spillPair (PAIR_HL);
6932 /* PENDING: do this check better */
6933 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
6935 _moveA (aopGet (AOP (right), offset, FALSE));
6936 aopPut (AOP (result), "a", offset);
6939 aopPut (AOP (result),
6940 aopGet (AOP (right), offset, FALSE),
6947 freeAsmop (right, NULL, ic);
6948 freeAsmop (result, NULL, ic);
6951 /*-----------------------------------------------------------------*/
6952 /* genJumpTab - genrates code for jump table */
6953 /*-----------------------------------------------------------------*/
6955 genJumpTab (iCode * ic)
6960 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
6961 /* get the condition into accumulator */
6962 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
6965 emit2 ("ld e,%s", l);
6966 emit2 ("ld d,!zero");
6967 jtab = newiTempLabel (NULL);
6969 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
6970 emit2 ("add hl,de");
6971 emit2 ("add hl,de");
6972 emit2 ("add hl,de");
6973 freeAsmop (IC_JTCOND (ic), NULL, ic);
6977 emitLabel (jtab->key + 100);
6978 /* now generate the jump labels */
6979 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
6980 jtab = setNextItem (IC_JTLABELS (ic)))
6981 emit2 ("jp !tlabel", jtab->key + 100);
6984 /*-----------------------------------------------------------------*/
6985 /* genCast - gen code for casting */
6986 /*-----------------------------------------------------------------*/
6988 genCast (iCode * ic)
6990 operand *result = IC_RESULT (ic);
6991 sym_link *rtype = operandType (IC_RIGHT (ic));
6992 operand *right = IC_RIGHT (ic);
6995 /* if they are equivalent then do nothing */
6996 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6999 aopOp (right, ic, FALSE, FALSE);
7000 aopOp (result, ic, FALSE, FALSE);
7002 /* if the result is a bit */
7003 if (AOP_TYPE (result) == AOP_CRY)
7005 wassertl (0, "Tried to cast to a bit");
7008 /* if they are the same size : or less */
7009 if (AOP_SIZE (result) <= AOP_SIZE (right))
7012 /* if they are in the same place */
7013 if (sameRegs (AOP (right), AOP (result)))
7016 /* if they in different places then copy */
7017 size = AOP_SIZE (result);
7021 aopPut (AOP (result),
7022 aopGet (AOP (right), offset, FALSE),
7029 /* So we now know that the size of destination is greater
7030 than the size of the source */
7031 /* we move to result for the size of source */
7032 size = AOP_SIZE (right);
7036 aopPut (AOP (result),
7037 aopGet (AOP (right), offset, FALSE),
7042 /* now depending on the sign of the destination */
7043 size = AOP_SIZE (result) - AOP_SIZE (right);
7044 /* Unsigned or not an integral type - right fill with zeros */
7045 if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
7048 aopPut (AOP (result), "!zero", offset++);
7052 /* we need to extend the sign :{ */
7053 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
7059 aopPut (AOP (result), "a", offset++);
7063 freeAsmop (right, NULL, ic);
7064 freeAsmop (result, NULL, ic);
7067 /*-----------------------------------------------------------------*/
7068 /* genReceive - generate code for a receive iCode */
7069 /*-----------------------------------------------------------------*/
7071 genReceive (iCode * ic)
7073 if (isOperandInFarSpace (IC_RESULT (ic)) &&
7074 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7075 IS_TRUE_SYMOP (IC_RESULT (ic))))
7085 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7086 size = AOP_SIZE(IC_RESULT(ic));
7088 for (i = 0; i < size; i++) {
7089 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7093 freeAsmop (IC_RESULT (ic), NULL, ic);
7096 /*-----------------------------------------------------------------*/
7097 /* genDummyRead - generate code for dummy read of volatiles */
7098 /*-----------------------------------------------------------------*/
7100 genDummyRead (iCode * ic)
7102 emit2 ("; genDummyRead not implemented");
7109 /** Maximum number of bytes to emit per line. */
7113 /** Context for the byte output chunker. */
7116 unsigned char buffer[DBEMIT_MAX_RUN];
7121 /** Flushes a byte chunker by writing out all in the buffer and
7125 _dbFlush(DBEMITCTX *self)
7132 sprintf(line, ".db 0x%02X", self->buffer[0]);
7134 for (i = 1; i < self->pos; i++)
7136 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7143 /** Write out another byte, buffering until a decent line is
7147 _dbEmit(DBEMITCTX *self, int c)
7149 if (self->pos == DBEMIT_MAX_RUN)
7153 self->buffer[self->pos++] = c;
7156 /** Context for a simple run length encoder. */
7160 unsigned char buffer[128];
7162 /** runLen may be equivalent to pos. */
7168 RLE_CHANGE_COST = 4,
7172 /** Flush the buffer of a run length encoder by writing out the run or
7173 data that it currently contains.
7176 _rleCommit(RLECTX *self)
7182 memset(&db, 0, sizeof(db));
7184 emit2(".db %u", self->pos);
7186 for (i = 0; i < self->pos; i++)
7188 _dbEmit(&db, self->buffer[i]);
7197 Can get either a run or a block of random stuff.
7198 Only want to change state if a good run comes in or a run ends.
7199 Detecting run end is easy.
7202 Say initial state is in run, len zero, last zero. Then if you get a
7203 few zeros then something else then a short run will be output.
7204 Seems OK. While in run mode, keep counting. While in random mode,
7205 keep a count of the run. If run hits margin, output all up to run,
7206 restart, enter run mode.
7209 /** Add another byte into the run length encoder, flushing as
7210 required. The run length encoder uses the Amiga IFF style, where
7211 a block is prefixed by its run length. A positive length means
7212 the next n bytes pass straight through. A negative length means
7213 that the next byte is repeated -n times. A zero terminates the
7217 _rleAppend(RLECTX *self, int c)
7221 if (c != self->last)
7223 /* The run has stopped. See if it is worthwhile writing it out
7224 as a run. Note that the random data comes in as runs of
7227 if (self->runLen > RLE_CHANGE_COST)
7229 /* Yes, worthwhile. */
7230 /* Commit whatever was in the buffer. */
7232 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7236 /* Not worthwhile. Append to the end of the random list. */
7237 for (i = 0; i < self->runLen; i++)
7239 if (self->pos >= RLE_MAX_BLOCK)
7244 self->buffer[self->pos++] = self->last;
7252 if (self->runLen >= RLE_MAX_BLOCK)
7254 /* Commit whatever was in the buffer. */
7257 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7265 _rleFlush(RLECTX *self)
7267 _rleAppend(self, -1);
7274 /** genArrayInit - Special code for initialising an array with constant
7278 genArrayInit (iCode * ic)
7282 int elementSize = 0, eIndex, i;
7283 unsigned val, lastVal;
7287 memset(&rle, 0, sizeof(rle));
7289 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7291 _saveRegsForCall(ic, 0);
7293 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7294 emit2 ("call __initrleblock");
7296 type = operandType(IC_LEFT(ic));
7298 if (type && type->next)
7300 elementSize = getSize(type->next);
7304 wassertl (0, "Can't determine element size in genArrayInit.");
7307 iLoop = IC_ARRAYILIST(ic);
7308 lastVal = (unsigned)-1;
7310 /* Feed all the bytes into the run length encoder which will handle
7312 This works well for mixed char data, and for random int and long
7321 for (i = 0; i < ix; i++)
7323 for (eIndex = 0; eIndex < elementSize; eIndex++)
7325 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7326 _rleAppend(&rle, val);
7331 iLoop = iLoop->next;
7335 /* Mark the end of the run. */
7338 _restoreRegsAfterCall();
7342 freeAsmop (IC_LEFT(ic), NULL, ic);
7346 _swap (PAIR_ID one, PAIR_ID two)
7348 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7354 emit2 ("ld a,%s", _pairs[one].l);
7355 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7356 emit2 ("ld %s,a", _pairs[two].l);
7357 emit2 ("ld a,%s", _pairs[one].h);
7358 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7359 emit2 ("ld %s,a", _pairs[two].h);
7363 /* The problem is that we may have all three pairs used and they may
7364 be needed in a different order.
7369 hl = hl => unity, fine
7373 hl = hl hl = hl, swap de <=> bc
7381 hl = bc de = de, swap bc <=> hl
7389 hl = de bc = bc, swap hl <=> de
7394 * Any pair = pair are done last
7395 * Any pair = iTemp are done last
7396 * Any swaps can be done any time
7404 So how do we detect the cases?
7405 How about a 3x3 matrix?
7409 x x x x (Fourth for iTemp/other)
7411 First determin which mode to use by counting the number of unity and
7414 Two - Assign the pair first, then the rest
7415 One - Swap the two, then the rest
7419 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7421 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7423 PAIR_BC, PAIR_HL, PAIR_DE
7425 int i, j, nunity = 0;
7426 memset (ids, PAIR_INVALID, sizeof (ids));
7429 wassert (nparams == 3);
7431 /* First save everything that needs to be saved. */
7432 _saveRegsForCall (ic, 0);
7434 /* Loading HL first means that DE is always fine. */
7435 for (i = 0; i < nparams; i++)
7437 aopOp (pparams[i], ic, FALSE, FALSE);
7438 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7441 /* Count the number of unity or iTemp assigns. */
7442 for (i = 0; i < 3; i++)
7444 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7452 /* Any order, fall through. */
7454 else if (nunity == 2)
7456 /* One is assigned. Pull it out and assign. */
7457 for (i = 0; i < 3; i++)
7459 for (j = 0; j < NUM_PAIRS; j++)
7461 if (ids[dest[i]][j] == TRUE)
7463 /* Found it. See if it's the right one. */
7464 if (j == PAIR_INVALID || j == dest[i])
7470 fetchPair(dest[i], AOP (pparams[i]));
7477 else if (nunity == 1)
7479 /* Find the pairs to swap. */
7480 for (i = 0; i < 3; i++)
7482 for (j = 0; j < NUM_PAIRS; j++)
7484 if (ids[dest[i]][j] == TRUE)
7486 if (j == PAIR_INVALID || j == dest[i])
7501 int next = getPairId (AOP (pparams[0]));
7502 emit2 ("push %s", _pairs[next].name);
7504 if (next == dest[1])
7506 fetchPair (dest[1], AOP (pparams[1]));
7507 fetchPair (dest[2], AOP (pparams[2]));
7511 fetchPair (dest[2], AOP (pparams[2]));
7512 fetchPair (dest[1], AOP (pparams[1]));
7514 emit2 ("pop %s", _pairs[dest[0]].name);
7517 /* Finally pull out all of the iTemps */
7518 for (i = 0; i < 3; i++)
7520 if (ids[dest[i]][PAIR_INVALID] == 1)
7522 fetchPair (dest[i], AOP (pparams[i]));
7528 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
7534 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
7538 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7540 setupForBuiltin3 (ic, nParams, pparams);
7542 label = newiTempLabel(NULL);
7544 emitLabel (label->key);
7545 emit2 ("ld a,(hl)");
7548 emit2 ("!shortjp nz,!tlabel ; 1", label->key);
7550 freeAsmop (from, NULL, ic->next);
7551 freeAsmop (to, NULL, ic);
7555 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
7557 operand *from, *to, *count;
7560 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
7565 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7567 setupForBuiltin3 (ic, nParams, pparams);
7571 freeAsmop (count, NULL, ic->next->next);
7572 freeAsmop (from, NULL, ic);
7574 _restoreRegsAfterCall();
7576 /* if we need assign a result value */
7577 if ((IS_ITEMP (IC_RESULT (ic)) &&
7578 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
7579 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
7580 IS_TRUE_SYMOP (IC_RESULT (ic)))
7582 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7583 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
7584 freeAsmop (IC_RESULT (ic), NULL, ic);
7587 freeAsmop (to, NULL, ic->next);
7590 /*-----------------------------------------------------------------*/
7591 /* genBuiltIn - calls the appropriate function to generating code */
7592 /* for a built in function */
7593 /*-----------------------------------------------------------------*/
7594 static void genBuiltIn (iCode *ic)
7596 operand *bi_parms[MAX_BUILTIN_ARGS];
7601 /* get all the arguments for a built in function */
7602 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
7604 /* which function is it */
7605 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
7607 if (strcmp(bif->name,"__builtin_strcpy")==0)
7609 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
7611 else if (strcmp(bif->name,"__builtin_memcpy")==0)
7613 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
7617 wassertl (0, "Unknown builtin function encountered");
7621 /*-----------------------------------------------------------------*/
7622 /* genZ80Code - generate code for Z80 based controllers */
7623 /*-----------------------------------------------------------------*/
7625 genZ80Code (iCode * lic)
7633 _fReturn = _gbz80_return;
7634 _fTmp = _gbz80_return;
7638 _fReturn = _z80_return;
7639 _fTmp = _z80_return;
7642 _G.lines.head = _G.lines.current = NULL;
7644 for (ic = lic; ic; ic = ic->next)
7646 _G.current_iCode = ic;
7648 if (cln != ic->lineno)
7650 if (!options.noCcodeInAsm) {
7651 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
7652 printCLine(ic->filename, ic->lineno));
7656 if (options.iCodeInAsm) {
7657 emit2 (";ic:%d: %s", ic->key, printILine(ic));
7659 /* if the result is marked as
7660 spilt and rematerializable or code for
7661 this has already been generated then
7663 if (resultRemat (ic) || ic->generated)
7666 /* depending on the operation */
7670 emitDebug ("; genNot");
7675 emitDebug ("; genCpl");
7680 emitDebug ("; genUminus");
7685 emitDebug ("; genIpush");
7690 /* IPOP happens only when trying to restore a
7691 spilt live range, if there is an ifx statement
7692 following this pop then the if statement might
7693 be using some of the registers being popped which
7694 would destory the contents of the register so
7695 we need to check for this condition and handle it */
7697 ic->next->op == IFX &&
7698 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
7700 emitDebug ("; genIfx");
7701 genIfx (ic->next, ic);
7705 emitDebug ("; genIpop");
7711 emitDebug ("; genCall");
7716 emitDebug ("; genPcall");
7721 emitDebug ("; genFunction");
7726 emitDebug ("; genEndFunction");
7727 genEndFunction (ic);
7731 emitDebug ("; genRet");
7736 emitDebug ("; genLabel");
7741 emitDebug ("; genGoto");
7746 emitDebug ("; genPlus");
7751 emitDebug ("; genMinus");
7756 emitDebug ("; genMult");
7761 emitDebug ("; genDiv");
7766 emitDebug ("; genMod");
7771 emitDebug ("; genCmpGt");
7772 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
7776 emitDebug ("; genCmpLt");
7777 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
7784 /* note these two are xlated by algebraic equivalence
7785 during parsing SDCC.y */
7786 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
7787 "got '>=' or '<=' shouldn't have come here");
7791 emitDebug ("; genCmpEq");
7792 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
7796 emitDebug ("; genAndOp");
7801 emitDebug ("; genOrOp");
7806 emitDebug ("; genXor");
7807 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
7811 emitDebug ("; genOr");
7812 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
7816 emitDebug ("; genAnd");
7817 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
7821 emitDebug ("; genInline");
7826 emitDebug ("; genRRC");
7831 emitDebug ("; genRLC");
7836 emitDebug ("; genGetHBIT");
7841 emitDebug ("; genLeftShift");
7846 emitDebug ("; genRightShift");
7850 case GET_VALUE_AT_ADDRESS:
7851 emitDebug ("; genPointerGet");
7857 if (POINTER_SET (ic))
7859 emitDebug ("; genAssign (pointer)");
7864 emitDebug ("; genAssign");
7870 emitDebug ("; genIfx");
7875 emitDebug ("; genAddrOf");
7880 emitDebug ("; genJumpTab");
7885 emitDebug ("; genCast");
7890 emitDebug ("; genReceive");
7895 if (ic->builtinSEND)
7897 emitDebug ("; genBuiltIn");
7902 emitDebug ("; addSet");
7903 addSet (&_G.sendSet, ic);
7908 emitDebug ("; genArrayInit");
7912 case DUMMY_READ_VOLATILE:
7922 /* now we are ready to call the
7923 peep hole optimizer */
7924 if (!options.nopeep)
7925 peepHole (&_G.lines.head);
7927 /* This is unfortunate */
7928 /* now do the actual printing */
7930 FILE *fp = codeOutFile;
7931 if (isInHome () && codeOutFile == code->oFile)
7932 codeOutFile = home->oFile;
7933 printLine (_G.lines.head, codeOutFile);
7934 if (_G.flushStatics)
7937 _G.flushStatics = 0;
7942 freeTrace(&_G.lines.trace);
7943 freeTrace(&_G.trace.aops);
7949 _isPairUsed (iCode * ic, PAIR_ID pairId)
7955 if (bitVectBitValue (ic->rMask, D_IDX))
7957 if (bitVectBitValue (ic->rMask, E_IDX))
7967 fetchLitSpecial (asmop * aop, bool negate, bool xor)
7970 value *val = aop->aopu.aop_lit;
7972 wassert (aop->type == AOP_LIT);
7973 wassert (!IS_FLOAT (val->type));
7975 v = (unsigned long) floatFromVal (val);
7983 tsprintf (buffer, sizeof(buffer), "!immedword", v);
7984 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));