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[] = {
270 isLastUse (iCode *ic, operand *op)
272 bitVect *uses = bitVectCopy (OP_USES (op));
274 while (!bitVectIsZero (uses))
276 if (bitVectFirstBit (uses) == ic->key)
278 if (bitVectnBitsOn (uses) == 1)
287 bitVectUnSetBit (uses, bitVectFirstBit (uses));
307 _getTempPairName(void)
309 return _pairs[_getTempPairId()].name;
313 isPairInUse (PAIR_ID id, iCode *ic)
317 return bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
319 else if (id == PAIR_BC)
321 return bitVectBitValue (ic->rMask, B_IDX) || bitVectBitValue(ic->rMask, C_IDX);
325 wassertl (0, "Only implemented for DE and BC");
331 isPairInUseNotInRet(PAIR_ID id, iCode *ic)
335 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
339 return bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
343 wassertl (0, "Only implemented for DE");
349 getFreePairId (iCode *ic)
351 if (!isPairInUse (PAIR_BC, ic))
355 else if (IS_Z80 && !isPairInUse (PAIR_DE, ic))
368 /* Clean up the line so that it is 'prettier' */
369 if (strchr (buf, ':'))
371 /* Is a label - cant do anything */
374 /* Change the first (and probably only) ' ' to a tab so
389 _newLineNode (char *line)
393 pl = traceAlloc(&_G.lines.trace, Safe_alloc ( sizeof (lineNode)));
394 pl->line = traceAlloc(&_G.lines.trace, Safe_strdup (line));
400 _vemit2 (const char *szFormat, va_list ap)
402 char buffer[INITIAL_INLINEASM];
404 tvsprintf (buffer, sizeof(buffer), szFormat, ap);
407 _G.lines.current = (_G.lines.current ?
408 connectLine (_G.lines.current, _newLineNode (buffer)) :
409 (_G.lines.head = _newLineNode (buffer)));
411 _G.lines.current->isInline = _G.lines.isInline;
412 _G.lines.current->ic = _G.current_iCode;
416 emit2 (const char *szFormat,...)
420 va_start (ap, szFormat);
422 _vemit2 (szFormat, ap);
428 emitDebug (const char *szFormat,...)
434 va_start (ap, szFormat);
436 _vemit2 (szFormat, ap);
442 /*-----------------------------------------------------------------*/
443 /* emit2 - writes the code into a file : for now it is simple */
444 /*-----------------------------------------------------------------*/
446 _emit2 (const char *inst, const char *fmt,...)
449 char lb[INITIAL_INLINEASM];
456 sprintf (lb, "%s\t", inst);
457 vsprintf (lb + (strlen (lb)), fmt, ap);
460 vsprintf (lb, fmt, ap);
462 while (isspace (*lbp))
467 _G.lines.current = (_G.lines.current ?
468 connectLine (_G.lines.current, _newLineNode (lb)) :
469 (_G.lines.head = _newLineNode (lb)));
471 _G.lines.current->isInline = _G.lines.isInline;
472 _G.lines.current->ic = _G.current_iCode;
477 _emitMove(const char *to, const char *from)
479 if (STRCASECMP(to, from) != 0)
481 emit2("ld %s,%s", to, from);
486 // Could leave this to the peephole, but sometimes the peephole is inhibited.
491 aopDump(const char *plabel, asmop *aop)
497 emitDebug("; Dump of %s: type %s size %u", plabel, aopNames[aop->type], aop->size);
502 emitDebug("; aop_stk %d", aop->aopu.aop_stk);
505 for (i=aop->size-1;i>=0;i--)
506 *rbp++ = *(aop->aopu.aop_reg[i]->name);
508 emitDebug("; reg = %s", regbuf);
511 emitDebug("; pairptr = (%s)", _pairs[aop->aopu.aop_pairId].name);
514 /* No information. */
520 _moveA(const char *moveFrom)
522 // Let the peephole optimiser take care of redundent loads
523 _emitMove(ACC_NAME, moveFrom);
533 getPairName (asmop * aop)
535 if (aop->type == AOP_REG)
537 switch (aop->aopu.aop_reg[0]->rIdx)
550 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
553 for (i = 0; i < NUM_PAIRS; i++)
555 if (strcmp(aop->aopu.aop_str[0], _pairs[i].l) == 0)
557 return _pairs[i].name;
561 wassertl (0, "Tried to get the pair name of something that isn't a pair");
566 getPairId (asmop * aop)
570 if (aop->type == AOP_REG)
572 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX) && (aop->aopu.aop_reg[1]->rIdx == B_IDX))
576 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX) && (aop->aopu.aop_reg[1]->rIdx == D_IDX))
580 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX) && (aop->aopu.aop_reg[1]->rIdx == H_IDX))
585 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
588 for (i = 0; i < NUM_PAIRS; i++)
590 if (!strcmp (aop->aopu.aop_str[0], _pairs[i].l) && !strcmp (aop->aopu.aop_str[1], _pairs[i].h))
600 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
604 return (getPairId (aop) != PAIR_INVALID);
607 /** Returns TRUE if the registers used in aop cannot be split into high
610 isUnsplitable (asmop * aop)
612 switch (getPairId (aop))
624 isPtrPair (asmop * aop)
626 PAIR_ID pairId = getPairId (aop);
639 spillPair (PAIR_ID pairId)
641 _G.pairs[pairId].last_type = AOP_INVALID;
642 _G.pairs[pairId].base = NULL;
645 /* Given a register name, spill the pair (if any) the register is part of */
647 spillPairReg (const char *regname)
649 if (strlen(regname)==1)
669 /** Push a register pair onto the stack */
671 genPairPush (asmop * aop)
673 emit2 ("push %s", getPairName (aop));
677 _push (PAIR_ID pairId)
679 emit2 ("push %s", _pairs[pairId].name);
680 _G.stack.pushed += 2;
684 _pop (PAIR_ID pairId)
686 emit2 ("pop %s", _pairs[pairId].name);
687 _G.stack.pushed -= 2;
692 genMovePairPair (PAIR_ID srcPair, PAIR_ID dstPair)
705 if (srcPair == PAIR_IX || srcPair == PAIR_IY)
712 emit2("ld %s,%s",_pairs[dstPair].l,_pairs[srcPair].l);
713 emit2("ld %s,%s",_pairs[dstPair].h,_pairs[srcPair].h);
716 wassertl (0, "Tried to move a nonphysical pair");
718 _G.pairs[dstPair].last_type = _G.pairs[srcPair].last_type;
719 _G.pairs[dstPair].base = _G.pairs[srcPair].base;
720 _G.pairs[dstPair].offset = _G.pairs[srcPair].offset;
724 /*-----------------------------------------------------------------*/
725 /* newAsmop - creates a new asmOp */
726 /*-----------------------------------------------------------------*/
728 newAsmop (short type)
732 aop = traceAlloc(&_G.trace.aops, Safe_alloc (sizeof (asmop)));
737 /*-----------------------------------------------------------------*/
738 /* aopForSym - for a true symbol */
739 /*-----------------------------------------------------------------*/
741 aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
748 wassert (sym->etype);
750 space = SPEC_OCLS (sym->etype);
752 /* if already has one */
758 /* Assign depending on the storage class */
759 if (sym->onStack || sym->iaccess)
761 /* The pointer that is used depends on how big the offset is.
762 Normally everything is AOP_STK, but for offsets of < -128 or
763 > 127 on the Z80 an extended stack pointer is used.
765 if (IS_Z80 && (_G.omitFramePtr || sym->stack < INT8MIN || sym->stack > (int)(INT8MAX-getSize (sym->type))))
767 emitDebug ("; AOP_EXSTK for %s", sym->rname);
768 sym->aop = aop = newAsmop (AOP_EXSTK);
772 emitDebug ("; AOP_STK for %s", sym->rname);
773 sym->aop = aop = newAsmop (AOP_STK);
776 aop->size = getSize (sym->type);
777 aop->aopu.aop_stk = sym->stack;
781 /* special case for a function */
782 if (IS_FUNC (sym->type))
784 sym->aop = aop = newAsmop (AOP_IMMD);
785 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup (sym->rname));
792 /* if it is in direct space */
793 if (IN_REGSP (space) && !requires_a)
795 sym->aop = aop = newAsmop (AOP_SFR);
796 aop->aopu.aop_dir = sym->rname;
797 aop->size = getSize (sym->type);
798 emitDebug ("; AOP_SFR for %s", sym->rname);
803 /* only remaining is far space */
804 /* in which case DPTR gets the address */
807 emitDebug ("; AOP_HL for %s", sym->rname);
808 sym->aop = aop = newAsmop (AOP_HL);
812 sym->aop = aop = newAsmop (AOP_IY);
814 aop->size = getSize (sym->type);
815 aop->aopu.aop_dir = sym->rname;
817 /* if it is in code space */
818 if (IN_CODESPACE (space))
824 /*-----------------------------------------------------------------*/
825 /* aopForRemat - rematerialzes an object */
826 /*-----------------------------------------------------------------*/
828 aopForRemat (symbol * sym)
831 iCode *ic = sym->rematiCode;
832 asmop *aop = newAsmop (AOP_IMMD);
836 /* if plus or minus print the right hand side */
837 if (ic->op == '+' || ic->op == '-')
839 /* PENDING: for re-target */
840 sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
843 ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
846 /* we reached the end */
847 sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
851 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
855 /*-----------------------------------------------------------------*/
856 /* regsInCommon - two operands have some registers in common */
857 /*-----------------------------------------------------------------*/
859 regsInCommon (operand * op1, operand * op2)
864 /* if they have registers in common */
865 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
868 sym1 = OP_SYMBOL (op1);
869 sym2 = OP_SYMBOL (op2);
871 if (sym1->nRegs == 0 || sym2->nRegs == 0)
874 for (i = 0; i < sym1->nRegs; i++)
880 for (j = 0; j < sym2->nRegs; j++)
885 if (sym2->regs[j] == sym1->regs[i])
893 /*-----------------------------------------------------------------*/
894 /* operandsEqu - equivalent */
895 /*-----------------------------------------------------------------*/
897 operandsEqu (operand * op1, operand * op2)
901 /* if they not symbols */
902 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
905 sym1 = OP_SYMBOL (op1);
906 sym2 = OP_SYMBOL (op2);
908 /* if both are itemps & one is spilt
909 and the other is not then false */
910 if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
911 sym1->isspilt != sym2->isspilt)
914 /* if they are the same */
918 if (strcmp (sym1->rname, sym2->rname) == 0)
922 /* if left is a tmp & right is not */
923 if (IS_ITEMP (op1) &&
926 (sym1->usl.spillLoc == sym2))
929 if (IS_ITEMP (op2) &&
933 (sym2->usl.spillLoc == sym1))
939 /*-----------------------------------------------------------------*/
940 /* sameRegs - two asmops have the same registers */
941 /*-----------------------------------------------------------------*/
943 sameRegs (asmop * aop1, asmop * aop2)
947 if (aop1->type == AOP_SFR ||
948 aop2->type == AOP_SFR)
954 if (aop1->type != AOP_REG ||
955 aop2->type != AOP_REG)
958 if (aop1->size != aop2->size)
961 for (i = 0; i < aop1->size; i++)
962 if (aop1->aopu.aop_reg[i] !=
963 aop2->aopu.aop_reg[i])
969 /*-----------------------------------------------------------------*/
970 /* aopOp - allocates an asmop for an operand : */
971 /*-----------------------------------------------------------------*/
973 aopOp (operand * op, iCode * ic, bool result, bool requires_a)
982 /* if this a literal */
983 if (IS_OP_LITERAL (op))
985 op->aop = aop = newAsmop (AOP_LIT);
986 aop->aopu.aop_lit = op->operand.valOperand;
987 aop->size = getSize (operandType (op));
991 /* if already has a asmop then continue */
997 /* if the underlying symbol has a aop */
998 if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
1000 op->aop = OP_SYMBOL (op)->aop;
1004 /* if this is a true symbol */
1005 if (IS_TRUE_SYMOP (op))
1007 op->aop = aopForSym (ic, OP_SYMBOL (op), result, requires_a);
1011 /* this is a temporary : this has
1017 e) can be a return use only */
1019 sym = OP_SYMBOL (op);
1021 /* if the type is a conditional */
1022 if (sym->regType == REG_CND)
1024 aop = op->aop = sym->aop = newAsmop (AOP_CRY);
1029 /* if it is spilt then two situations
1031 b) has a spill location */
1032 if (sym->isspilt || sym->nRegs == 0)
1034 /* rematerialize it NOW */
1037 sym->aop = op->aop = aop =
1039 aop->size = getSize (sym->type);
1046 aop = op->aop = sym->aop = newAsmop (AOP_STR);
1047 aop->size = getSize (sym->type);
1048 for (i = 0; i < 4; i++)
1049 aop->aopu.aop_str[i] = _fReturn[i];
1055 if (sym->accuse == ACCUSE_A)
1057 aop = op->aop = sym->aop = newAsmop (AOP_ACC);
1058 aop->size = getSize (sym->type);
1059 wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
1061 aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
1063 else if (sym->accuse == ACCUSE_SCRATCH)
1065 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
1066 aop->size = getSize (sym->type);
1067 wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
1068 aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
1069 aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
1071 else if (sym->accuse == ACCUSE_IY)
1073 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
1074 aop->size = getSize (sym->type);
1075 wassertl(aop->size <= 2, "Internal error: Caching in IY, but too big to fit in IY");
1076 aop->aopu.aop_str[0] = _pairs[PAIR_IY].l;
1077 aop->aopu.aop_str[1] = _pairs[PAIR_IY].h;
1081 wassertl (0, "Marked as being allocated into A or HL but is actually in neither");
1086 if (sym->usl.spillLoc)
1088 if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1090 /* force a new aop if sizes differ */
1091 sym->usl.spillLoc->aop = NULL;
1093 sym->aop = op->aop = aop =
1094 aopForSym (ic, sym->usl.spillLoc, result, requires_a);
1095 aop->size = getSize (sym->type);
1099 /* else must be a dummy iTemp */
1100 sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1101 aop->size = getSize (sym->type);
1105 /* must be in a register */
1106 sym->aop = op->aop = aop = newAsmop (AOP_REG);
1107 aop->size = sym->nRegs;
1108 for (i = 0; i < sym->nRegs; i++)
1109 aop->aopu.aop_reg[i] = sym->regs[i];
1112 /*-----------------------------------------------------------------*/
1113 /* freeAsmop - free up the asmop given to an operand */
1114 /*----------------------------------------------------------------*/
1116 freeAsmop (operand * op, asmop * aaop, iCode * ic)
1133 if (aop->type == AOP_PAIRPTR && IS_Z80 && aop->aopu.aop_pairId == PAIR_DE)
1135 _pop (aop->aopu.aop_pairId);
1138 if (getPairId (aop) == PAIR_HL)
1140 spillPair (PAIR_HL);
1144 /* all other cases just dealloc */
1150 OP_SYMBOL (op)->aop = NULL;
1151 /* if the symbol has a spill */
1153 SPIL_LOC (op)->aop = NULL;
1160 isLitWord (asmop * aop)
1162 /* if (aop->size != 2)
1175 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
1177 /* depending on type */
1183 /* PENDING: for re-target */
1186 tsprintf (buffer, sizeof(buffer),
1187 "!hashedstr + %d", aop->aopu.aop_immd, offset);
1189 else if (offset == 0)
1191 tsprintf (buffer, sizeof(buffer),
1192 "%s", aop->aopu.aop_immd);
1196 tsprintf (buffer, sizeof(buffer),
1197 "%s + %d", aop->aopu.aop_immd, offset);
1199 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1203 value *val = aop->aopu.aop_lit;
1204 /* if it is a float then it gets tricky */
1205 /* otherwise it is fairly simple */
1206 if (!IS_FLOAT (val->type))
1208 unsigned long v = (unsigned long) floatFromVal (val);
1214 else if (offset == 0)
1220 wassertl(0, "Encountered an invalid offset while fetching a literal");
1224 tsprintf (buffer, sizeof(buffer), "!immedword", v);
1226 tsprintf (buffer, sizeof(buffer), "!constword", v);
1228 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1239 /* it is type float */
1240 fl.f = (float) floatFromVal (val);
1242 #ifdef WORDS_BIGENDIAN
1243 i = fl.c[3-offset] | (fl.c[3-offset-1]<<8);
1245 i = fl.c[offset] | (fl.c[offset+1]<<8);
1248 tsprintf (buffer, sizeof(buffer), "!immedword", i);
1250 tsprintf (buffer, sizeof(buffer), "!constword", i);
1252 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1261 aopGetWord (asmop * aop, int offset)
1263 return aopGetLitWordLong (aop, offset, TRUE);
1267 isPtr (const char *s)
1269 if (!strcmp (s, "hl"))
1271 if (!strcmp (s, "ix"))
1273 if (!strcmp (s, "iy"))
1279 adjustPair (const char *pair, int *pold, int new)
1285 emit2 ("inc %s", pair);
1290 emit2 ("dec %s", pair);
1298 spillPair (PAIR_HL);
1299 spillPair (PAIR_IY);
1303 requiresHL (asmop * aop)
1319 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1321 const char *l, *base;
1322 const char *pair = _pairs[pairId].name;
1323 l = aopGetLitWordLong (left, offset, FALSE);
1324 base = aopGetLitWordLong (left, 0, FALSE);
1325 wassert (l && pair && base);
1329 if (pairId == PAIR_HL || pairId == PAIR_IY)
1331 if (_G.pairs[pairId].last_type == left->type)
1333 if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1335 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1337 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1340 if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
1347 _G.pairs[pairId].last_type = left->type;
1348 _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1349 _G.pairs[pairId].offset = offset;
1351 /* Both a lit on the right and a true symbol on the left */
1352 emit2 ("ld %s,!hashedstr", pair, l);
1356 makeFreePairId (iCode *ic, bool *pisUsed)
1362 if (!bitVectBitValue (ic->rMask, B_IDX) && !bitVectBitValue(ic->rMask, C_IDX))
1366 else if (IS_Z80 && !bitVectBitValue (ic->rMask, D_IDX) && !bitVectBitValue(ic->rMask, E_IDX))
1384 fetchPairLong (PAIR_ID pairId, asmop * aop, iCode *ic, int offset)
1386 /* if this is remateriazable */
1387 if (isLitWord (aop)) {
1388 fetchLitPair (pairId, aop, offset);
1392 if (getPairId (aop) == pairId)
1396 /* we need to get it byte by byte */
1397 else if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1398 aopGet (aop, offset, FALSE);
1399 switch (aop->size - offset) {
1401 emit2 ("ld l,!*hl");
1402 emit2 ("ld h,!immedbyte", 0);
1405 // PENDING: Requires that you are only fetching two bytes.
1408 emit2 ("ld h,!*hl");
1412 wassertl (0, "Attempted to fetch too much data into HL");
1416 else if (IS_Z80 && aop->type == AOP_IY) {
1417 /* Instead of fetching relative to IY, just grab directly
1418 from the address IY refers to */
1419 char *l = aopGetLitWordLong (aop, offset, FALSE);
1421 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1423 if (aop->size < 2) {
1424 emit2("ld %s,!zero", _pairs[pairId].h);
1427 else if (pairId == PAIR_IY)
1431 emit2 ("push %s", _pairs[getPairId(aop)].name);
1437 PAIR_ID id = makeFreePairId (ic, &isUsed);
1440 /* Can't load into parts, so load into HL then exchange. */
1441 emit2 ("ld %s,%s", _pairs[id].l, aopGet (aop, offset, FALSE));
1442 emit2 ("ld %s,%s", _pairs[id].h, aopGet (aop, offset + 1, FALSE));
1443 emit2 ("push %s", _pairs[id].name);
1449 else if (isUnsplitable(aop))
1451 emit2("push %s", _pairs[getPairId(aop)].name);
1452 emit2("pop %s", _pairs[pairId].name);
1456 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1457 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1459 /* PENDING: check? */
1460 if (pairId == PAIR_HL)
1461 spillPair (PAIR_HL);
1466 fetchPair (PAIR_ID pairId, asmop * aop)
1468 fetchPairLong (pairId, aop, NULL, 0);
1472 fetchHL (asmop * aop)
1474 fetchPair (PAIR_HL, aop);
1478 setupPairFromSP (PAIR_ID id, int offset)
1480 wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
1482 if (offset < INT8MIN || offset > INT8MAX)
1484 emit2 ("ld hl,!immedword", offset);
1485 emit2 ("add hl,sp");
1489 emit2 ("!ldahlsp", offset);
1494 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1499 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
1500 fetchLitPair (pairId, aop, 0);
1504 wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
1506 fetchLitPair (pairId, aop, offset);
1507 _G.pairs[pairId].offset = offset;
1511 wassertl (IS_Z80, "Only the Z80 has an extended stack");
1512 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
1515 int offset = aop->aopu.aop_stk + _G.stack.offset;
1517 if (_G.pairs[pairId].last_type == aop->type &&
1518 _G.pairs[pairId].offset == offset)
1524 /* PENDING: Do this better. */
1525 sprintf (buffer, "%d", offset + _G.stack.pushed);
1526 emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
1527 emit2 ("add %s,sp", _pairs[pairId].name);
1528 _G.pairs[pairId].last_type = aop->type;
1529 _G.pairs[pairId].offset = offset;
1536 /* Doesnt include _G.stack.pushed */
1537 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1539 if (aop->aopu.aop_stk > 0)
1541 abso += _G.stack.param_offset;
1543 assert (pairId == PAIR_HL);
1544 /* In some cases we can still inc or dec hl */
1545 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1547 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1551 setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
1553 _G.pairs[pairId].offset = abso;
1558 if (pairId != aop->aopu.aop_pairId)
1559 genMovePairPair(aop->aopu.aop_pairId, pairId);
1560 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
1566 _G.pairs[pairId].last_type = aop->type;
1572 emit2 ("!tlabeldef", key);
1576 /*-----------------------------------------------------------------*/
1577 /* aopGet - for fetching value of the aop */
1578 /*-----------------------------------------------------------------*/
1580 aopGet (asmop * aop, int offset, bool bit16)
1582 // char *s = buffer;
1584 /* offset is greater than size then zero */
1585 /* PENDING: this seems a bit screwed in some pointer cases. */
1586 if (offset > (aop->size - 1) &&
1587 aop->type != AOP_LIT)
1589 tsprintf (buffer, sizeof(buffer), "!zero");
1590 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1593 /* depending on type */
1597 tsprintf (buffer, sizeof(buffer), "!zero");
1598 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1601 /* PENDING: re-target */
1603 tsprintf (buffer, sizeof(buffer), "!immedwords", aop->aopu.aop_immd);
1608 tsprintf (buffer, sizeof(buffer), "!bankimmeds", aop->aopu.aop_immd);
1611 tsprintf (buffer, sizeof(buffer), "!msbimmeds", aop->aopu.aop_immd);
1614 tsprintf (buffer, sizeof(buffer), "!lsbimmeds", aop->aopu.aop_immd);
1617 wassertl (0, "Fetching from beyond the limits of an immediate value.");
1620 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1624 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1625 SNPRINTF (buffer, sizeof(buffer), "a");
1627 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1631 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1632 SNPRINTF (buffer, sizeof(buffer), "a");
1634 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1637 return aop->aopu.aop_reg[offset]->name;
1641 setupPair (PAIR_HL, aop, offset);
1642 tsprintf (buffer, sizeof(buffer), "!*hl");
1644 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
1648 setupPair (PAIR_IY, aop, offset);
1649 tsprintf (buffer, sizeof(buffer), "!*iyx", offset);
1651 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1655 setupPair (PAIR_IY, aop, offset);
1656 tsprintf (buffer, sizeof(buffer), "!*iyx", offset, offset);
1658 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1663 setupPair (PAIR_HL, aop, offset);
1664 tsprintf (buffer, sizeof(buffer), "!*hl");
1668 if (aop->aopu.aop_stk >= 0)
1669 offset += _G.stack.param_offset;
1670 tsprintf (buffer, sizeof(buffer),
1671 "!*ixx", aop->aopu.aop_stk + offset);
1674 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1677 wassertl (0, "Tried to fetch from a bit variable");
1686 tsprintf(buffer, sizeof(buffer), "!zero");
1687 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1691 wassert (offset < 2);
1692 return aop->aopu.aop_str[offset];
1695 return aopLiteral (aop->aopu.aop_lit, offset);
1699 unsigned long v = aop->aopu.aop_simplelit;
1702 tsprintf (buffer, sizeof(buffer),
1703 "!immedbyte", (unsigned int) v & 0xff);
1705 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1709 return aop->aopu.aop_str[offset];
1712 setupPair (aop->aopu.aop_pairId, aop, offset);
1713 if (aop->aopu.aop_pairId==PAIR_IX)
1714 SNPRINTF (buffer, sizeof(buffer),
1716 else if (aop->aopu.aop_pairId==PAIR_IY)
1717 SNPRINTF (buffer, sizeof(buffer),
1720 SNPRINTF (buffer, sizeof(buffer),
1721 "(%s)", _pairs[aop->aopu.aop_pairId].name);
1723 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1728 wassertl (0, "aopget got unsupported aop->type");
1733 isRegString (const char *s)
1735 if (!strcmp (s, "b") ||
1747 isConstant (const char *s)
1749 /* This is a bit of a hack... */
1750 return (*s == '#' || *s == '$');
1754 canAssignToPtr (const char *s)
1756 if (isRegString (s))
1763 /*-----------------------------------------------------------------*/
1764 /* aopPut - puts a string for a aop */
1765 /*-----------------------------------------------------------------*/
1767 aopPut (asmop * aop, const char *s, int offset)
1771 if (aop->size && offset > (aop->size - 1))
1773 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1774 "aopPut got offset > aop->size");
1779 tsprintf(buffer2, sizeof(buffer2), s);
1782 /* will assign value to value */
1783 /* depending on where it is ofcourse */
1787 _moveA (s); /* in case s is volatile */
1793 if (strcmp (s, "a"))
1794 emit2 ("ld a,%s", s);
1795 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1800 if (strcmp (s, "a"))
1801 emit2 ("ld a,%s", s);
1802 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1806 if (!strcmp (s, "!*hl"))
1807 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1810 aop->aopu.aop_reg[offset]->name, s);
1811 spillPairReg(aop->aopu.aop_reg[offset]->name);
1816 if (!canAssignToPtr (s))
1818 emit2 ("ld a,%s", s);
1819 setupPair (PAIR_IY, aop, offset);
1820 emit2 ("ld !*iyx,a", offset);
1824 setupPair (PAIR_IY, aop, offset);
1825 emit2 ("ld !*iyx,%s", offset, s);
1831 /* PENDING: for re-target */
1832 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1834 emit2 ("ld a,!*hl");
1837 setupPair (PAIR_HL, aop, offset);
1839 emit2 ("ld !*hl,%s", s);
1844 if (!canAssignToPtr (s))
1846 emit2 ("ld a,%s", s);
1847 setupPair (PAIR_IY, aop, offset);
1848 emit2 ("ld !*iyx,a", offset);
1852 setupPair (PAIR_IY, aop, offset);
1853 emit2 ("ld !*iyx,%s", offset, s);
1860 /* PENDING: re-target */
1861 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1863 emit2 ("ld a,!*hl");
1866 setupPair (PAIR_HL, aop, offset);
1867 if (!canAssignToPtr (s))
1869 emit2 ("ld a,%s", s);
1870 emit2 ("ld !*hl,a");
1873 emit2 ("ld !*hl,%s", s);
1877 if (aop->aopu.aop_stk >= 0)
1878 offset += _G.stack.param_offset;
1879 if (!canAssignToPtr (s))
1881 emit2 ("ld a,%s", s);
1882 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
1886 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
1892 /* if bit variable */
1893 if (!aop->aopu.aop_dir)
1895 emit2 ("ld a,!zero");
1900 /* In bit space but not in C - cant happen */
1901 wassertl (0, "Tried to write into a bit variable");
1907 if (strcmp (aop->aopu.aop_str[offset], s))
1909 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1911 spillPairReg(aop->aopu.aop_str[offset]);
1916 if (!offset && (strcmp (s, "acc") == 0))
1920 wassertl (0, "Tried to access past the end of A");
1924 if (strcmp (aop->aopu.aop_str[offset], s))
1926 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1927 spillPairReg(aop->aopu.aop_str[offset]);
1933 wassert (offset < 2);
1934 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1935 spillPairReg(aop->aopu.aop_str[offset]);
1939 setupPair (aop->aopu.aop_pairId, aop, offset);
1940 if (aop->aopu.aop_pairId==PAIR_IX)
1941 emit2 ("ld !*ixx,%s", 0, s);
1942 else if (aop->aopu.aop_pairId==PAIR_IY)
1943 emit2 ("ld !*ixy,%s", 0, s);
1945 emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
1949 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1950 "aopPut got unsupported aop->type");
1955 #define AOP(op) op->aop
1956 #define AOP_TYPE(op) AOP(op)->type
1957 #define AOP_SIZE(op) AOP(op)->size
1958 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
1961 commitPair (asmop * aop, PAIR_ID id)
1963 /* PENDING: Verify this. */
1964 if (id == PAIR_HL && requiresHL (aop) && IS_GB)
1968 aopPut (aop, "a", 0);
1969 aopPut (aop, "d", 1);
1974 if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
1976 char *l = aopGetLitWordLong (aop, 0, FALSE);
1979 emit2 ("ld (%s),%s", l, _pairs[id].name);
1983 aopPut (aop, _pairs[id].l, 0);
1984 aopPut (aop, _pairs[id].h, 1);
1989 /*-----------------------------------------------------------------*/
1990 /* getDataSize - get the operand data size */
1991 /*-----------------------------------------------------------------*/
1993 getDataSize (operand * op)
1996 size = AOP_SIZE (op);
2000 wassertl (0, "Somehow got a three byte data pointer");
2005 /*-----------------------------------------------------------------*/
2006 /* movLeft2Result - move byte from left to result */
2007 /*-----------------------------------------------------------------*/
2009 movLeft2Result (operand * left, int offl,
2010 operand * result, int offr, int sign)
2014 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
2016 l = aopGet (AOP (left), offl, FALSE);
2020 aopPut (AOP (result), l, offr);
2024 if (getDataSize (left) == offl + 1)
2026 emit2 ("ld a,%s", l);
2027 aopPut (AOP (result), "a", offr);
2034 movLeft2ResultLong (operand * left, int offl,
2035 operand * result, int offr, int sign,
2040 movLeft2Result (left, offl, result, offr, sign);
2044 wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
2045 wassertl (size == 2, "Only implemented for two bytes or one");
2047 if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
2049 emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
2050 emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
2052 spillPair (PAIR_HL);
2054 else if ( getPairId ( AOP (result)) == PAIR_IY)
2056 PAIR_ID id = getPairId (AOP (left));
2057 if (id != PAIR_INVALID)
2059 emit2("push %s", _pairs[id].name);
2070 movLeft2Result (left, offl, result, offr, sign);
2071 movLeft2Result (left, offl+1, result, offr+1, sign);
2076 /** Put Acc into a register set
2079 outAcc (operand * result)
2082 size = getDataSize (result);
2085 aopPut (AOP (result), "a", 0);
2088 /* unsigned or positive */
2091 aopPut (AOP (result), "!zero", offset++);
2096 /** Take the value in carry and put it into a register
2099 outBitCLong (operand * result, bool swap_sense)
2101 /* if the result is bit */
2102 if (AOP_TYPE (result) == AOP_CRY)
2104 wassertl (0, "Tried to write carry to a bit");
2108 emit2 ("ld a,!zero");
2111 emit2 ("xor a,!immedbyte", 1);
2117 outBitC (operand * result)
2119 outBitCLong (result, FALSE);
2122 /*-----------------------------------------------------------------*/
2123 /* toBoolean - emit code for orl a,operator(sizeop) */
2124 /*-----------------------------------------------------------------*/
2126 _toBoolean (operand * oper)
2128 int size = AOP_SIZE (oper);
2132 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
2135 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
2139 if (AOP (oper)->type != AOP_ACC)
2142 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
2148 /*-----------------------------------------------------------------*/
2149 /* genNot - generate code for ! operation */
2150 /*-----------------------------------------------------------------*/
2155 /* assign asmOps to operand & result */
2156 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
2157 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2159 /* if in bit space then a special case */
2160 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2162 wassertl (0, "Tried to negate a bit");
2165 _toBoolean (IC_LEFT (ic));
2170 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
2171 emit2 ("sub a,!one");
2172 outBitC (IC_RESULT (ic));
2174 /* release the aops */
2175 freeAsmop (IC_LEFT (ic), NULL, ic);
2176 freeAsmop (IC_RESULT (ic), NULL, ic);
2179 /*-----------------------------------------------------------------*/
2180 /* genCpl - generate code for complement */
2181 /*-----------------------------------------------------------------*/
2189 /* assign asmOps to operand & result */
2190 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2191 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2193 /* if both are in bit space then
2195 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2196 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2198 wassertl (0, "Left and the result are in bit space");
2201 size = AOP_SIZE (IC_RESULT (ic));
2204 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2207 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2210 /* release the aops */
2211 freeAsmop (IC_LEFT (ic), NULL, ic);
2212 freeAsmop (IC_RESULT (ic), NULL, ic);
2216 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
2223 store de into result
2228 store de into result
2230 const char *first = isAdd ? "add" : "sub";
2231 const char *later = isAdd ? "adc" : "sbc";
2233 wassertl (IS_GB, "Code is only relevent to the gbz80");
2234 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
2236 fetchPair (PAIR_DE, left);
2239 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
2242 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2245 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2246 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2248 fetchPairLong (PAIR_DE, left, NULL, MSB24);
2249 aopGet (right, MSB24, FALSE);
2253 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2256 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2258 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2259 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2263 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2265 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2268 /*-----------------------------------------------------------------*/
2269 /* genUminusFloat - unary minus for floating points */
2270 /*-----------------------------------------------------------------*/
2272 genUminusFloat (operand * op, operand * result)
2274 int size, offset = 0;
2276 emitDebug("; genUminusFloat");
2278 /* for this we just need to flip the
2279 first it then copy the rest in place */
2280 size = AOP_SIZE (op) - 1;
2282 _moveA(aopGet (AOP (op), MSB32, FALSE));
2284 emit2("xor a,!immedbyte", 0x80);
2285 aopPut (AOP (result), "a", MSB32);
2289 aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2294 /*-----------------------------------------------------------------*/
2295 /* genUminus - unary minus code generation */
2296 /*-----------------------------------------------------------------*/
2298 genUminus (iCode * ic)
2301 sym_link *optype, *rtype;
2304 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2305 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2307 /* if both in bit space then special
2309 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2310 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2312 wassertl (0, "Left and right are in bit space");
2316 optype = operandType (IC_LEFT (ic));
2317 rtype = operandType (IC_RESULT (ic));
2319 /* if float then do float stuff */
2320 if (IS_FLOAT (optype))
2322 genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2326 /* otherwise subtract from zero */
2327 size = AOP_SIZE (IC_LEFT (ic));
2329 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2331 /* Create a new asmop with value zero */
2332 asmop *azero = newAsmop (AOP_SIMPLELIT);
2333 azero->aopu.aop_simplelit = 0;
2335 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2343 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2344 emit2 ("ld a,!zero");
2345 emit2 ("sbc a,%s", l);
2346 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2349 /* if any remaining bytes in the result */
2350 /* we just need to propagate the sign */
2351 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2356 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2360 /* release the aops */
2361 freeAsmop (IC_LEFT (ic), NULL, ic);
2362 freeAsmop (IC_RESULT (ic), NULL, ic);
2365 /*-----------------------------------------------------------------*/
2366 /* assignResultValue - */
2367 /*-----------------------------------------------------------------*/
2369 assignResultValue (operand * oper)
2371 int size = AOP_SIZE (oper);
2374 wassertl (size <= 4, "Got a result that is bigger than four bytes");
2375 topInA = requiresHL (AOP (oper));
2377 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2379 /* We do it the hard way here. */
2381 aopPut (AOP (oper), _fReturn[0], 0);
2382 aopPut (AOP (oper), _fReturn[1], 1);
2384 aopPut (AOP (oper), _fReturn[0], 2);
2385 aopPut (AOP (oper), _fReturn[1], 3);
2391 aopPut (AOP (oper), _fReturn[size], size);
2396 /** Simple restore that doesn't take into account what is used in the
2400 _restoreRegsAfterCall(void)
2402 if (_G.stack.pushedDE)
2405 _G.stack.pushedDE = FALSE;
2407 if (_G.stack.pushedBC)
2410 _G.stack.pushedBC = FALSE;
2412 _G.saves.saved = FALSE;
2416 _saveRegsForCall(iCode *ic, int sendSetSize)
2419 o Stack parameters are pushed before this function enters
2420 o DE and BC may be used in this function.
2421 o HL and DE may be used to return the result.
2422 o HL and DE may be used to send variables.
2423 o DE and BC may be used to store the result value.
2424 o HL may be used in computing the sent value of DE
2425 o The iPushes for other parameters occur before any addSets
2427 Logic: (to be run inside the first iPush or if none, before sending)
2428 o Compute if DE and/or BC are in use over the call
2429 o Compute if DE is used in the send set
2430 o Compute if DE and/or BC are used to hold the result value
2431 o If (DE is used, or in the send set) and is not used in the result, push.
2432 o If BC is used and is not in the result, push
2434 o If DE is used in the send set, fetch
2435 o If HL is used in the send set, fetch
2439 if (_G.saves.saved == FALSE) {
2440 bool deInUse, bcInUse;
2442 bool bcInRet = FALSE, deInRet = FALSE;
2445 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask),
2446 z80_rUmaskForOp (IC_RESULT(ic)));
2448 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2449 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2451 deSending = (sendSetSize > 1);
2453 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2455 if (bcInUse && bcInRet == FALSE) {
2457 _G.stack.pushedBC = TRUE;
2459 if (deInUse && deInRet == FALSE) {
2461 _G.stack.pushedDE = TRUE;
2464 _G.saves.saved = TRUE;
2467 /* Already saved. */
2471 /*-----------------------------------------------------------------*/
2472 /* genIpush - genrate code for pushing this gets a little complex */
2473 /*-----------------------------------------------------------------*/
2475 genIpush (iCode * ic)
2477 int size, offset = 0;
2480 /* if this is not a parm push : ie. it is spill push
2481 and spill push is always done on the local stack */
2484 wassertl(0, "Encountered an unsupported spill push.");
2488 if (_G.saves.saved == FALSE) {
2489 /* Caller saves, and this is the first iPush. */
2490 /* Scan ahead until we find the function that we are pushing parameters to.
2491 Count the number of addSets on the way to figure out what registers
2492 are used in the send set.
2495 iCode *walk = ic->next;
2498 if (walk->op == SEND) {
2501 else if (walk->op == CALL || walk->op == PCALL) {
2510 _saveRegsForCall(walk, nAddSets);
2513 /* Already saved by another iPush. */
2516 /* then do the push */
2517 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2519 size = AOP_SIZE (IC_LEFT (ic));
2521 if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2523 _G.stack.pushed += 2;
2524 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2530 fetchHL (AOP (IC_LEFT (ic)));
2532 spillPair (PAIR_HL);
2533 _G.stack.pushed += 2;
2538 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
2540 spillPair (PAIR_HL);
2541 _G.stack.pushed += 2;
2542 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
2544 spillPair (PAIR_HL);
2545 _G.stack.pushed += 2;
2551 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2553 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2555 emit2 ("ld a,(%s)", l);
2559 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2560 emit2 ("ld a,%s", l);
2568 freeAsmop (IC_LEFT (ic), NULL, ic);
2571 /*-----------------------------------------------------------------*/
2572 /* genIpop - recover the registers: can happen only for spilling */
2573 /*-----------------------------------------------------------------*/
2575 genIpop (iCode * ic)
2580 /* if the temp was not pushed then */
2581 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2584 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2585 size = AOP_SIZE (IC_LEFT (ic));
2586 offset = (size - 1);
2587 if (isPair (AOP (IC_LEFT (ic))))
2589 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2597 spillPair (PAIR_HL);
2598 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2602 freeAsmop (IC_LEFT (ic), NULL, ic);
2605 /* This is quite unfortunate */
2607 setArea (int inHome)
2610 static int lastArea = 0;
2612 if (_G.in_home != inHome) {
2614 const char *sz = port->mem.code_name;
2615 port->mem.code_name = "HOME";
2616 emit2("!area", CODE_NAME);
2617 port->mem.code_name = sz;
2620 emit2("!area", CODE_NAME); */
2621 _G.in_home = inHome;
2632 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2636 symbol *sym = OP_SYMBOL (op);
2638 if (sym->isspilt || sym->nRegs == 0)
2641 aopOp (op, ic, FALSE, FALSE);
2644 if (aop->type == AOP_REG)
2647 for (i = 0; i < aop->size; i++)
2649 if (pairId == PAIR_DE)
2651 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2652 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2654 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2657 else if (pairId == PAIR_BC)
2659 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2660 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2662 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2672 freeAsmop (IC_LEFT (ic), NULL, ic);
2676 /** Emit the code for a call statement
2679 emitCall (iCode * ic, bool ispcall)
2681 bool bInRet, cInRet, dInRet, eInRet;
2682 sym_link *dtype = operandType (IC_LEFT (ic));
2684 /* if caller saves & we have not saved then */
2690 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2692 /* if send set is not empty then assign */
2697 int nSend = elementsInSet(_G.sendSet);
2698 bool swapped = FALSE;
2700 int _z80_sendOrder[] = {
2705 /* Check if the parameters are swapped. If so route through hl instead. */
2706 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2708 sic = setFirstItem(_G.sendSet);
2709 sic = setNextItem(_G.sendSet);
2711 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2712 /* The second send value is loaded from one the one that holds the first
2713 send, i.e. it is overwritten. */
2714 /* Cache the first in HL, and load the second from HL instead. */
2715 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2716 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2722 for (sic = setFirstItem (_G.sendSet); sic;
2723 sic = setNextItem (_G.sendSet))
2726 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2728 size = AOP_SIZE (IC_LEFT (sic));
2729 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2730 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2732 // PENDING: Mild hack
2733 if (swapped == TRUE && send == 1) {
2735 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2738 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2740 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2743 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2747 freeAsmop (IC_LEFT (sic), NULL, sic);
2754 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2756 werror (W_INDIR_BANKED);
2758 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2760 if (isLitWord (AOP (IC_LEFT (ic))))
2762 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2766 symbol *rlbl = newiTempLabel (NULL);
2767 spillPair (PAIR_HL);
2768 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2770 _G.stack.pushed += 2;
2772 fetchHL (AOP (IC_LEFT (ic)));
2774 emit2 ("!tlabeldef", (rlbl->key + 100));
2775 _G.stack.pushed -= 2;
2777 freeAsmop (IC_LEFT (ic), NULL, ic);
2781 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2782 OP_SYMBOL (IC_LEFT (ic))->rname :
2783 OP_SYMBOL (IC_LEFT (ic))->name;
2784 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2786 emit2 ("call banked_call");
2787 emit2 ("!dws", name);
2788 emit2 ("!dw !bankimmeds", name);
2793 emit2 ("call %s", name);
2798 /* Mark the regsiters as restored. */
2799 _G.saves.saved = FALSE;
2801 /* if we need assign a result value */
2802 if ((IS_ITEMP (IC_RESULT (ic)) &&
2803 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2804 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2805 IS_TRUE_SYMOP (IC_RESULT (ic)))
2808 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2810 assignResultValue (IC_RESULT (ic));
2812 freeAsmop (IC_RESULT (ic), NULL, ic);
2815 /* adjust the stack for parameters if required */
2818 int i = ic->parmBytes;
2820 _G.stack.pushed -= i;
2823 emit2 ("!ldaspsp", i);
2830 emit2 ("ld iy,!immedword", i);
2831 emit2 ("add iy,sp");
2852 bitVect *result = z80_rUmaskForOp (IC_RESULT (ic));
2853 bInRet = bitVectBitValue(result, B_IDX);
2854 cInRet = bitVectBitValue(result, C_IDX);
2855 dInRet = bitVectBitValue(result, D_IDX);
2856 eInRet = bitVectBitValue(result, E_IDX);
2866 if (_G.stack.pushedDE)
2868 if (dInRet && eInRet)
2870 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
2874 /* Only restore E */
2881 /* Only restore D */
2889 _G.stack.pushedDE = FALSE;
2892 if (_G.stack.pushedBC)
2894 if (bInRet && cInRet)
2896 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
2900 /* Only restore C */
2907 /* Only restore B */
2915 _G.stack.pushedBC = FALSE;
2919 /*-----------------------------------------------------------------*/
2920 /* genCall - generates a call statement */
2921 /*-----------------------------------------------------------------*/
2923 genCall (iCode * ic)
2925 emitCall (ic, FALSE);
2928 /*-----------------------------------------------------------------*/
2929 /* genPcall - generates a call by pointer statement */
2930 /*-----------------------------------------------------------------*/
2932 genPcall (iCode * ic)
2934 emitCall (ic, TRUE);
2937 /*-----------------------------------------------------------------*/
2938 /* resultRemat - result is rematerializable */
2939 /*-----------------------------------------------------------------*/
2941 resultRemat (iCode * ic)
2943 if (SKIP_IC (ic) || ic->op == IFX)
2946 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2948 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2949 if (sym->remat && !POINTER_SET (ic))
2956 extern set *publics;
2958 /*-----------------------------------------------------------------*/
2959 /* genFunction - generated code for function entry */
2960 /*-----------------------------------------------------------------*/
2962 genFunction (iCode * ic)
2966 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2969 bool bcInUse = FALSE;
2970 bool deInUse = FALSE;
2972 setArea (IFFUNC_NONBANKED (sym->type));
2974 /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
2977 _G.receiveOffset = 0;
2979 /* Record the last function name for debugging. */
2980 _G.lastFunctionName = sym->rname;
2982 /* Create the function header */
2983 emit2 ("!functionheader", sym->name);
2984 sprintf (buffer, "%s_start", sym->rname);
2985 emit2 ("!labeldef", buffer);
2986 emit2 ("!functionlabeldef", sym->rname);
2988 if (options.profile)
2990 emit2 ("!profileenter");
2993 ftype = operandType (IC_LEFT (ic));
2995 /* if critical function then turn interrupts off */
2996 if (IFFUNC_ISCRITICAL (ftype))
2999 /* if this is an interrupt service routine then save all potentially used registers. */
3000 if (IFFUNC_ISISR (sym->type))
3005 /* PENDING: callee-save etc */
3007 _G.stack.param_offset = 0;
3009 if (z80_opts.calleeSavesBC)
3014 /* Detect which registers are used. */
3015 if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
3018 for (i = 0; i < sym->regsUsed->size; i++)
3020 if (bitVectBitValue (sym->regsUsed, i))
3034 /* Other systems use DE as a temporary. */
3045 _G.stack.param_offset += 2;
3048 _G.calleeSaves.pushedBC = bcInUse;
3053 _G.stack.param_offset += 2;
3056 _G.calleeSaves.pushedDE = deInUse;
3058 /* adjust the stack for the function */
3059 _G.stack.last = sym->stack;
3062 for (sym = setFirstItem (istack->syms); sym;
3063 sym = setNextItem (istack->syms))
3065 if (sym->_isparm && !IS_REGPARM (sym->etype))
3071 sym = OP_SYMBOL (IC_LEFT (ic));
3073 _G.omitFramePtr = options.ommitFramePtr;
3074 if (IS_Z80 && !stackParm && !sym->stack)
3076 /* When the conflicts between AOP_EXSTK && AOP_HLREG are fixed, */
3077 /* the above !sym->stack condition can be removed. -- EEP */
3079 emit2 ("!ldaspsp", -sym->stack);
3080 _G.omitFramePtr = TRUE;
3082 else if (sym->stack && IS_GB && sym->stack > -INT8MIN)
3083 emit2 ("!enterxl", sym->stack);
3084 else if (sym->stack)
3085 emit2 ("!enterx", sym->stack);
3088 _G.stack.offset = sym->stack;
3091 /*-----------------------------------------------------------------*/
3092 /* genEndFunction - generates epilogue for functions */
3093 /*-----------------------------------------------------------------*/
3095 genEndFunction (iCode * ic)
3097 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3099 if (IFFUNC_ISISR (sym->type))
3101 wassertl (0, "Tried to close an interrupt support function");
3105 if (IFFUNC_ISCRITICAL (sym->type))
3108 /* PENDING: calleeSave */
3110 if (IS_Z80 && _G.omitFramePtr)
3112 if (_G.stack.offset)
3113 emit2 ("!ldaspsp", _G.stack.offset);
3115 else if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
3117 emit2 ("!leavexl", _G.stack.offset);
3119 else if (_G.stack.offset)
3121 emit2 ("!leavex", _G.stack.offset);
3128 if (_G.calleeSaves.pushedDE)
3131 _G.calleeSaves.pushedDE = FALSE;
3134 if (_G.calleeSaves.pushedBC)
3137 _G.calleeSaves.pushedBC = FALSE;
3140 if (options.profile)
3142 emit2 ("!profileexit");
3146 /* Both baned and non-banked just ret */
3149 sprintf (buffer, "%s_end", sym->rname);
3150 emit2 ("!labeldef", buffer);
3152 _G.flushStatics = 1;
3153 _G.stack.pushed = 0;
3154 _G.stack.offset = 0;
3157 /*-----------------------------------------------------------------*/
3158 /* genRet - generate code for return statement */
3159 /*-----------------------------------------------------------------*/
3164 /* Errk. This is a hack until I can figure out how
3165 to cause dehl to spill on a call */
3166 int size, offset = 0;
3168 /* if we have no return value then
3169 just generate the "ret" */
3173 /* we have something to return then
3174 move the return value into place */
3175 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3176 size = AOP_SIZE (IC_LEFT (ic));
3178 aopDump("IC_LEFT", AOP(IC_LEFT(ic)));
3181 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3185 emit2 ("ld de,%s", l);
3189 emit2 ("ld hl,%s", l);
3195 fetchPair(IS_GB ? PAIR_DE : PAIR_HL, AOP (IC_LEFT (ic)));
3199 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3201 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3202 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3208 l = aopGet (AOP (IC_LEFT (ic)), offset,
3210 if (strcmp (_fReturn[offset], l))
3211 emit2 ("ld %s,%s", _fReturn[offset], l);
3216 freeAsmop (IC_LEFT (ic), NULL, ic);
3219 /* generate a jump to the return label
3220 if the next is not the return statement */
3221 if (!(ic->next && ic->next->op == LABEL &&
3222 IC_LABEL (ic->next) == returnLabel))
3224 emit2 ("jp !tlabel", returnLabel->key + 100);
3227 /*-----------------------------------------------------------------*/
3228 /* genLabel - generates a label */
3229 /*-----------------------------------------------------------------*/
3231 genLabel (iCode * ic)
3233 /* special case never generate */
3234 if (IC_LABEL (ic) == entryLabel)
3237 emitLabel (IC_LABEL (ic)->key + 100);
3240 /*-----------------------------------------------------------------*/
3241 /* genGoto - generates a ljmp */
3242 /*-----------------------------------------------------------------*/
3244 genGoto (iCode * ic)
3246 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3249 /*-----------------------------------------------------------------*/
3250 /* genPlusIncr :- does addition with increment if possible */
3251 /*-----------------------------------------------------------------*/
3253 genPlusIncr (iCode * ic)
3255 unsigned int icount;
3256 unsigned int size = getDataSize (IC_RESULT (ic));
3257 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3259 /* will try to generate an increment */
3260 /* if the right side is not a literal
3262 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3265 emitDebug ("; genPlusIncr");
3267 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3269 /* If result is a pair */
3270 if (resultId != PAIR_INVALID)
3272 if (isLitWord (AOP (IC_LEFT (ic))))
3274 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3277 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3279 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3281 PAIR_ID freep = getFreePairId (ic);
3282 if (freep != PAIR_INVALID)
3284 fetchPair (freep, AOP (IC_RIGHT (ic)));
3285 emit2 ("add hl,%s", _pairs[freep].name);
3291 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3292 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3299 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3303 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3307 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3312 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3314 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3315 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3319 /* if the literal value of the right hand side
3320 is greater than 4 then it is not worth it */
3324 /* if increment 16 bits in register */
3325 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3331 symbol *tlbl = NULL;
3332 tlbl = newiTempLabel (NULL);
3335 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3338 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3341 emitLabel (tlbl->key + 100);
3345 /* if the sizes are greater than 1 then we cannot */
3346 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3347 AOP_SIZE (IC_LEFT (ic)) > 1)
3350 /* If the result is in a register then we can load then increment.
3352 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3354 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3357 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3362 /* we can if the aops of the left & result match or
3363 if they are in registers and the registers are the
3365 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3369 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3377 /*-----------------------------------------------------------------*/
3378 /* outBitAcc - output a bit in acc */
3379 /*-----------------------------------------------------------------*/
3381 outBitAcc (operand * result)
3383 symbol *tlbl = newiTempLabel (NULL);
3384 /* if the result is a bit */
3385 if (AOP_TYPE (result) == AOP_CRY)
3387 wassertl (0, "Tried to write A into a bit");
3391 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3392 emit2 ("ld a,!one");
3393 emitLabel (tlbl->key + 100);
3399 couldDestroyCarry (asmop *aop)
3403 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3412 shiftIntoPair (int idx, asmop *aop)
3414 PAIR_ID id = PAIR_INVALID;
3416 wassertl (IS_Z80, "Only implemented for the Z80");
3417 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3429 wassertl (0, "Internal error - hit default case");
3432 emitDebug ("; Shift into pair idx %u", idx);
3436 setupPair (PAIR_HL, aop, 0);
3440 setupPair (PAIR_IY, aop, 0);
3442 emit2 ("pop %s", _pairs[id].name);
3445 aop->type = AOP_PAIRPTR;
3446 aop->aopu.aop_pairId = id;
3447 _G.pairs[id].offset = 0;
3448 _G.pairs[id].last_type = aop->type;
3452 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
3454 wassert (left && right);
3458 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3460 shiftIntoPair (0, right);
3461 /* check result again, in case right == result */
3462 if (couldDestroyCarry (result))
3463 shiftIntoPair (1, result);
3465 else if (couldDestroyCarry (right))
3467 shiftIntoPair (0, right);
3469 else if (couldDestroyCarry (result))
3471 shiftIntoPair (0, result);
3480 /*-----------------------------------------------------------------*/
3481 /* genPlus - generates code for addition */
3482 /*-----------------------------------------------------------------*/
3484 genPlus (iCode * ic)
3486 int size, offset = 0;
3488 /* special cases :- */
3490 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3491 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3492 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3494 /* Swap the left and right operands if:
3496 if literal, literal on the right or
3497 if left requires ACC or right is already
3500 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3501 (AOP_NEEDSACC (IC_LEFT (ic))) ||
3502 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3504 operand *t = IC_RIGHT (ic);
3505 IC_RIGHT (ic) = IC_LEFT (ic);
3509 /* if both left & right are in bit
3511 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3512 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3515 wassertl (0, "Tried to add two bits");
3518 /* if left in bit space & right literal */
3519 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3520 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3522 /* Can happen I guess */
3523 wassertl (0, "Tried to add a bit to a literal");
3526 /* if I can do an increment instead
3527 of add then GOOD for ME */
3528 if (genPlusIncr (ic) == TRUE)
3531 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3533 size = getDataSize (IC_RESULT (ic));
3535 /* Special case when left and right are constant */
3536 if (isPair (AOP (IC_RESULT (ic))))
3539 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3540 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3542 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3548 sprintf (buffer, "#(%s + %s)", left, right);
3549 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3554 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3556 /* Fetch into HL then do the add */
3557 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3558 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3560 spillPair (PAIR_HL);
3562 if (left == PAIR_HL && right != PAIR_INVALID)
3564 emit2 ("add hl,%s", _pairs[right].name);
3567 else if (right == PAIR_HL && left != PAIR_INVALID)
3569 emit2 ("add hl,%s", _pairs[left].name);
3572 else if (right != PAIR_INVALID && right != PAIR_HL)
3574 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3575 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3578 else if (left != PAIR_INVALID && left != PAIR_HL)
3580 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3581 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3590 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3592 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3593 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3595 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3600 ld hl,sp+n trashes C so we cant afford to do it during an
3601 add with stack based varibles. Worst case is:
3614 So you cant afford to load up hl if either left, right, or result
3615 is on the stack (*sigh*) The alt is:
3623 Combinations in here are:
3624 * If left or right are in bc then the loss is small - trap later
3625 * If the result is in bc then the loss is also small
3629 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3630 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3631 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3633 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3634 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3635 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3636 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3638 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3640 /* Swap left and right */
3641 operand *t = IC_RIGHT (ic);
3642 IC_RIGHT (ic) = IC_LEFT (ic);
3645 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3647 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3648 emit2 ("add hl,bc");
3652 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3653 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3654 emit2 ("add hl,de");
3656 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3662 /* Be paranoid on the GB with 4 byte variables due to how C
3663 can be trashed by lda hl,n(sp).
3665 _gbz80_emitAddSubLong (ic, TRUE);
3670 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3674 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3676 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3679 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3682 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3686 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3689 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3692 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3694 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3698 freeAsmop (IC_LEFT (ic), NULL, ic);
3699 freeAsmop (IC_RIGHT (ic), NULL, ic);
3700 freeAsmop (IC_RESULT (ic), NULL, ic);
3704 /*-----------------------------------------------------------------*/
3705 /* genMinusDec :- does subtraction with deccrement if possible */
3706 /*-----------------------------------------------------------------*/
3708 genMinusDec (iCode * ic)
3710 unsigned int icount;
3711 unsigned int size = getDataSize (IC_RESULT (ic));
3713 /* will try to generate an increment */
3714 /* if the right side is not a literal we cannot */
3715 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3718 /* if the literal value of the right hand side
3719 is greater than 4 then it is not worth it */
3720 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3723 size = getDataSize (IC_RESULT (ic));
3725 /* if decrement 16 bits in register */
3726 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3727 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3730 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3734 /* If result is a pair */
3735 if (isPair (AOP (IC_RESULT (ic))))
3737 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3739 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3743 /* if increment 16 bits in register */
3744 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3748 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3751 emit2 ("dec %s", _getTempPairName());
3754 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3760 /* if the sizes are greater than 1 then we cannot */
3761 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3762 AOP_SIZE (IC_LEFT (ic)) > 1)
3765 /* we can if the aops of the left & result match or if they are in
3766 registers and the registers are the same */
3767 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3770 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3777 /*-----------------------------------------------------------------*/
3778 /* genMinus - generates code for subtraction */
3779 /*-----------------------------------------------------------------*/
3781 genMinus (iCode * ic)
3783 int size, offset = 0;
3784 unsigned long lit = 0L;
3786 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3787 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3788 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3790 /* special cases :- */
3791 /* if both left & right are in bit space */
3792 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3793 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3795 wassertl (0, "Tried to subtract two bits");
3799 /* if I can do an decrement instead of subtract then GOOD for ME */
3800 if (genMinusDec (ic) == TRUE)
3803 size = getDataSize (IC_RESULT (ic));
3805 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3810 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3814 /* Same logic as genPlus */
3817 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3818 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3819 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3821 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3822 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3823 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3824 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3826 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3827 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3829 if (left == PAIR_INVALID && right == PAIR_INVALID)
3834 else if (right == PAIR_INVALID)
3836 else if (left == PAIR_INVALID)
3839 fetchPair (left, AOP (IC_LEFT (ic)));
3840 /* Order is important. Right may be HL */
3841 fetchPair (right, AOP (IC_RIGHT (ic)));
3843 emit2 ("ld a,%s", _pairs[left].l);
3844 emit2 ("sub a,%s", _pairs[right].l);
3846 emit2 ("ld a,%s", _pairs[left].h);
3847 emit2 ("sbc a,%s", _pairs[right].h);
3849 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
3851 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3853 aopPut (AOP (IC_RESULT (ic)), "e", 0);
3859 /* Be paranoid on the GB with 4 byte variables due to how C
3860 can be trashed by lda hl,n(sp).
3862 _gbz80_emitAddSubLong (ic, FALSE);
3867 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3869 /* if literal, add a,#-lit, else normal subb */
3872 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3873 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3877 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3880 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3884 /* first add without previous c */
3886 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
3888 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3890 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3893 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3894 AOP_SIZE (IC_LEFT (ic)) == 3 &&
3895 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3897 wassertl (0, "Tried to subtract on a long pointer");
3901 freeAsmop (IC_LEFT (ic), NULL, ic);
3902 freeAsmop (IC_RIGHT (ic), NULL, ic);
3903 freeAsmop (IC_RESULT (ic), NULL, ic);
3906 /*-----------------------------------------------------------------*/
3907 /* genMult - generates code for multiplication */
3908 /*-----------------------------------------------------------------*/
3910 genMult (iCode * ic)
3914 /* If true then the final operation should be a subtract */
3915 bool active = FALSE;
3917 /* Shouldn't occur - all done through function calls */
3918 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3919 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3920 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3922 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
3923 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
3924 AOP_SIZE (IC_RESULT (ic)) > 2)
3926 wassertl (0, "Multiplication is handled through support function calls");
3929 /* Swap left and right such that right is a literal */
3930 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
3932 operand *t = IC_RIGHT (ic);
3933 IC_RIGHT (ic) = IC_LEFT (ic);
3937 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
3939 val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
3940 // wassertl (val > 0, "Multiply must be positive");
3941 wassertl (val != 1, "Can't multiply by 1");
3943 if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
3945 _G.stack.pushedDE = TRUE;
3948 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
3950 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
3958 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3963 /* Fully unroled version of mul.s. Not the most efficient.
3965 for (count = 0; count < 16; count++)
3967 if (count != 0 && active)
3969 emit2 ("add hl,hl");
3973 if (active == FALSE)
3980 emit2 ("add hl,de");
3989 if (IS_Z80 && _G.stack.pushedDE)
3992 _G.stack.pushedDE = FALSE;
3995 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3997 freeAsmop (IC_LEFT (ic), NULL, ic);
3998 freeAsmop (IC_RIGHT (ic), NULL, ic);
3999 freeAsmop (IC_RESULT (ic), NULL, ic);
4002 /*-----------------------------------------------------------------*/
4003 /* genDiv - generates code for division */
4004 /*-----------------------------------------------------------------*/
4008 /* Shouldn't occur - all done through function calls */
4009 wassertl (0, "Division is handled through support function calls");
4012 /*-----------------------------------------------------------------*/
4013 /* genMod - generates code for division */
4014 /*-----------------------------------------------------------------*/
4018 /* Shouldn't occur - all done through function calls */
4022 /*-----------------------------------------------------------------*/
4023 /* genIfxJump :- will create a jump depending on the ifx */
4024 /*-----------------------------------------------------------------*/
4026 genIfxJump (iCode * ic, char *jval)
4031 /* if true label then we jump if condition
4035 jlbl = IC_TRUE (ic);
4036 if (!strcmp (jval, "a"))
4040 else if (!strcmp (jval, "c"))
4044 else if (!strcmp (jval, "nc"))
4048 else if (!strcmp (jval, "m"))
4052 else if (!strcmp (jval, "p"))
4058 /* The buffer contains the bit on A that we should test */
4064 /* false label is present */
4065 jlbl = IC_FALSE (ic);
4066 if (!strcmp (jval, "a"))
4070 else if (!strcmp (jval, "c"))
4074 else if (!strcmp (jval, "nc"))
4078 else if (!strcmp (jval, "m"))
4082 else if (!strcmp (jval, "p"))
4088 /* The buffer contains the bit on A that we should test */
4092 /* Z80 can do a conditional long jump */
4093 if (!strcmp (jval, "a"))
4097 else if (!strcmp (jval, "c"))
4100 else if (!strcmp (jval, "nc"))
4103 else if (!strcmp (jval, "m"))
4106 else if (!strcmp (jval, "p"))
4111 emit2 ("bit %s,a", jval);
4113 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
4115 /* mark the icode as generated */
4121 _getPairIdName (PAIR_ID id)
4123 return _pairs[id].name;
4128 /* if unsigned char cmp with lit, just compare */
4130 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4132 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4135 emit2 ("xor a,!immedbyte", 0x80);
4136 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4139 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4141 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4143 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4144 // Pull left into DE and right into HL
4145 aopGet (AOP(left), LSB, FALSE);
4148 aopGet (AOP(right), LSB, FALSE);
4152 if (size == 0 && sign)
4154 // Highest byte when signed needs the bits flipped
4157 emit2 ("ld a,(de)");
4158 emit2 ("xor !immedbyte", 0x80);
4160 emit2 ("ld a,(hl)");
4161 emit2 ("xor !immedbyte", 0x80);
4165 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4169 emit2 ("ld a,(de)");
4170 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4180 spillPair (PAIR_HL);
4182 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4184 setupPair (PAIR_HL, AOP (left), 0);
4185 aopGet (AOP(right), LSB, FALSE);
4189 if (size == 0 && sign)
4191 // Highest byte when signed needs the bits flipped
4194 emit2 ("ld a,(hl)");
4195 emit2 ("xor !immedbyte", 0x80);
4197 emit2 ("ld a,%d(iy)", offset);
4198 emit2 ("xor !immedbyte", 0x80);
4202 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4206 emit2 ("ld a,(hl)");
4207 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4216 spillPair (PAIR_HL);
4217 spillPair (PAIR_IY);
4221 if (AOP_TYPE (right) == AOP_LIT)
4223 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4224 /* optimize if(x < 0) or if(x >= 0) */
4229 /* No sign so it's always false */
4234 /* Just load in the top most bit */
4235 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4236 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4238 genIfxJump (ifx, "7");
4250 /* First setup h and l contaning the top most bytes XORed */
4251 bool fDidXor = FALSE;
4252 if (AOP_TYPE (left) == AOP_LIT)
4254 unsigned long lit = (unsigned long)
4255 floatFromVal (AOP (left)->aopu.aop_lit);
4256 emit2 ("ld %s,!immedbyte", _fTmp[0],
4257 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4261 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4262 emit2 ("xor a,!immedbyte", 0x80);
4263 emit2 ("ld %s,a", _fTmp[0]);
4266 if (AOP_TYPE (right) == AOP_LIT)
4268 unsigned long lit = (unsigned long)
4269 floatFromVal (AOP (right)->aopu.aop_lit);
4270 emit2 ("ld %s,!immedbyte", _fTmp[1],
4271 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4275 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4276 emit2 ("xor a,!immedbyte", 0x80);
4277 emit2 ("ld %s,a", _fTmp[1]);
4283 /* Do a long subtract */
4286 _moveA (aopGet (AOP (left), offset, FALSE));
4288 if (sign && size == 0)
4290 emit2 ("ld a,%s", _fTmp[0]);
4291 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4295 /* Subtract through, propagating the carry */
4296 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4304 /** Generic compare for > or <
4307 genCmp (operand * left, operand * right,
4308 operand * result, iCode * ifx, int sign)
4310 int size, offset = 0;
4311 unsigned long lit = 0L;
4312 bool swap_sense = FALSE;
4314 /* if left & right are bit variables */
4315 if (AOP_TYPE (left) == AOP_CRY &&
4316 AOP_TYPE (right) == AOP_CRY)
4318 /* Cant happen on the Z80 */
4319 wassertl (0, "Tried to compare two bits");
4323 /* Do a long subtract of right from left. */
4324 size = max (AOP_SIZE (left), AOP_SIZE (right));
4326 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4328 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4329 // Pull left into DE and right into HL
4330 aopGet (AOP(left), LSB, FALSE);
4333 aopGet (AOP(right), LSB, FALSE);
4337 emit2 ("ld a,(de)");
4338 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4347 spillPair (PAIR_HL);
4351 if (AOP_TYPE (right) == AOP_LIT)
4353 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4354 /* optimize if(x < 0) or if(x >= 0) */
4359 /* No sign so it's always false */
4364 /* Just load in the top most bit */
4365 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4366 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4368 genIfxJump (ifx, "7");
4379 genIfxJump (ifx, swap_sense ? "c" : "nc");
4390 _moveA (aopGet (AOP (left), offset, FALSE));
4391 /* Subtract through, propagating the carry */
4392 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4398 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4402 /* Shift the sign bit up into carry */
4405 outBitCLong (result, swap_sense);
4409 /* if the result is used in the next
4410 ifx conditional branch then generate
4411 code a little differently */
4419 genIfxJump (ifx, swap_sense ? "nc" : "c");
4423 genIfxJump (ifx, swap_sense ? "p" : "m");
4428 genIfxJump (ifx, swap_sense ? "nc" : "c");
4435 /* Shift the sign bit up into carry */
4438 outBitCLong (result, swap_sense);
4440 /* leave the result in acc */
4444 /*-----------------------------------------------------------------*/
4445 /* genCmpGt :- greater than comparison */
4446 /*-----------------------------------------------------------------*/
4448 genCmpGt (iCode * ic, iCode * ifx)
4450 operand *left, *right, *result;
4451 sym_link *letype, *retype;
4454 left = IC_LEFT (ic);
4455 right = IC_RIGHT (ic);
4456 result = IC_RESULT (ic);
4458 letype = getSpec (operandType (left));
4459 retype = getSpec (operandType (right));
4460 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4461 /* assign the amsops */
4462 aopOp (left, ic, FALSE, FALSE);
4463 aopOp (right, ic, FALSE, FALSE);
4464 aopOp (result, ic, TRUE, FALSE);
4466 genCmp (right, left, result, ifx, sign);
4468 freeAsmop (left, NULL, ic);
4469 freeAsmop (right, NULL, ic);
4470 freeAsmop (result, NULL, ic);
4473 /*-----------------------------------------------------------------*/
4474 /* genCmpLt - less than comparisons */
4475 /*-----------------------------------------------------------------*/
4477 genCmpLt (iCode * ic, iCode * ifx)
4479 operand *left, *right, *result;
4480 sym_link *letype, *retype;
4483 left = IC_LEFT (ic);
4484 right = IC_RIGHT (ic);
4485 result = IC_RESULT (ic);
4487 letype = getSpec (operandType (left));
4488 retype = getSpec (operandType (right));
4489 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4491 /* assign the amsops */
4492 aopOp (left, ic, FALSE, FALSE);
4493 aopOp (right, ic, FALSE, FALSE);
4494 aopOp (result, ic, TRUE, FALSE);
4496 genCmp (left, right, result, ifx, sign);
4498 freeAsmop (left, NULL, ic);
4499 freeAsmop (right, NULL, ic);
4500 freeAsmop (result, NULL, ic);
4503 /*-----------------------------------------------------------------*/
4504 /* gencjneshort - compare and jump if not equal */
4505 /*-----------------------------------------------------------------*/
4507 gencjneshort (operand * left, operand * right, symbol * lbl)
4509 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4511 unsigned long lit = 0L;
4513 /* Swap the left and right if it makes the computation easier */
4514 if (AOP_TYPE (left) == AOP_LIT)
4521 if (AOP_TYPE (right) == AOP_LIT)
4523 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4526 /* if the right side is a literal then anything goes */
4527 if (AOP_TYPE (right) == AOP_LIT &&
4528 AOP_TYPE (left) != AOP_DIR)
4532 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4537 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4544 emit2 ("jp nz,!tlabel", lbl->key + 100);
4550 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4551 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
4554 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
4555 emit2 ("jp nz,!tlabel", lbl->key + 100);
4560 /* if the right side is in a register or in direct space or
4561 if the left is a pointer register & right is not */
4562 else if (AOP_TYPE (right) == AOP_REG ||
4563 AOP_TYPE (right) == AOP_DIR ||
4564 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
4568 _moveA (aopGet (AOP (left), offset, FALSE));
4569 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
4570 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4572 emit2 ("jp nz,!tlabel", lbl->key + 100);
4575 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4576 emit2 ("jp nz,!tlabel", lbl->key + 100);
4583 /* right is a pointer reg need both a & b */
4584 /* PENDING: is this required? */
4587 _moveA (aopGet (AOP (right), offset, FALSE));
4588 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
4589 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
4595 /*-----------------------------------------------------------------*/
4596 /* gencjne - compare and jump if not equal */
4597 /*-----------------------------------------------------------------*/
4599 gencjne (operand * left, operand * right, symbol * lbl)
4601 symbol *tlbl = newiTempLabel (NULL);
4603 gencjneshort (left, right, lbl);
4606 emit2 ("ld a,!one");
4607 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4608 emitLabel (lbl->key + 100);
4610 emitLabel (tlbl->key + 100);
4613 /*-----------------------------------------------------------------*/
4614 /* genCmpEq - generates code for equal to */
4615 /*-----------------------------------------------------------------*/
4617 genCmpEq (iCode * ic, iCode * ifx)
4619 operand *left, *right, *result;
4621 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4622 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4623 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4625 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4627 /* Swap operands if it makes the operation easier. ie if:
4628 1. Left is a literal.
4630 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4632 operand *t = IC_RIGHT (ic);
4633 IC_RIGHT (ic) = IC_LEFT (ic);
4637 if (ifx && !AOP_SIZE (result))
4640 /* if they are both bit variables */
4641 if (AOP_TYPE (left) == AOP_CRY &&
4642 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4644 wassertl (0, "Tried to compare two bits");
4648 tlbl = newiTempLabel (NULL);
4649 gencjneshort (left, right, tlbl);
4652 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4653 emitLabel (tlbl->key + 100);
4657 /* PENDING: do this better */
4658 symbol *lbl = newiTempLabel (NULL);
4659 emit2 ("!shortjp !tlabel", lbl->key + 100);
4660 emitLabel (tlbl->key + 100);
4661 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4662 emitLabel (lbl->key + 100);
4665 /* mark the icode as generated */
4670 /* if they are both bit variables */
4671 if (AOP_TYPE (left) == AOP_CRY &&
4672 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4674 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4680 gencjne (left, right, newiTempLabel (NULL));
4681 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4688 genIfxJump (ifx, "a");
4691 /* if the result is used in an arithmetic operation
4692 then put the result in place */
4693 if (AOP_TYPE (result) != AOP_CRY)
4698 /* leave the result in acc */
4702 freeAsmop (left, NULL, ic);
4703 freeAsmop (right, NULL, ic);
4704 freeAsmop (result, NULL, ic);
4707 /*-----------------------------------------------------------------*/
4708 /* ifxForOp - returns the icode containing the ifx for operand */
4709 /*-----------------------------------------------------------------*/
4711 ifxForOp (operand * op, iCode * ic)
4713 /* if true symbol then needs to be assigned */
4714 if (IS_TRUE_SYMOP (op))
4717 /* if this has register type condition and
4718 the next instruction is ifx with the same operand
4719 and live to of the operand is upto the ifx only then */
4721 ic->next->op == IFX &&
4722 IC_COND (ic->next)->key == op->key &&
4723 OP_SYMBOL (op)->liveTo <= ic->next->seq)
4729 /*-----------------------------------------------------------------*/
4730 /* genAndOp - for && operation */
4731 /*-----------------------------------------------------------------*/
4733 genAndOp (iCode * ic)
4735 operand *left, *right, *result;
4738 /* note here that && operations that are in an if statement are
4739 taken away by backPatchLabels only those used in arthmetic
4740 operations remain */
4741 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4742 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4743 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4745 /* if both are bit variables */
4746 if (AOP_TYPE (left) == AOP_CRY &&
4747 AOP_TYPE (right) == AOP_CRY)
4749 wassertl (0, "Tried to and two bits");
4753 tlbl = newiTempLabel (NULL);
4755 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
4757 emitLabel (tlbl->key + 100);
4761 freeAsmop (left, NULL, ic);
4762 freeAsmop (right, NULL, ic);
4763 freeAsmop (result, NULL, ic);
4766 /*-----------------------------------------------------------------*/
4767 /* genOrOp - for || operation */
4768 /*-----------------------------------------------------------------*/
4770 genOrOp (iCode * ic)
4772 operand *left, *right, *result;
4775 /* note here that || operations that are in an
4776 if statement are taken away by backPatchLabels
4777 only those used in arthmetic operations remain */
4778 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4779 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4780 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4782 /* if both are bit variables */
4783 if (AOP_TYPE (left) == AOP_CRY &&
4784 AOP_TYPE (right) == AOP_CRY)
4786 wassertl (0, "Tried to OR two bits");
4790 tlbl = newiTempLabel (NULL);
4792 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4794 emitLabel (tlbl->key + 100);
4798 freeAsmop (left, NULL, ic);
4799 freeAsmop (right, NULL, ic);
4800 freeAsmop (result, NULL, ic);
4803 /*-----------------------------------------------------------------*/
4804 /* isLiteralBit - test if lit == 2^n */
4805 /*-----------------------------------------------------------------*/
4807 isLiteralBit (unsigned long lit)
4809 unsigned long pw[32] =
4810 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
4811 0x100L, 0x200L, 0x400L, 0x800L,
4812 0x1000L, 0x2000L, 0x4000L, 0x8000L,
4813 0x10000L, 0x20000L, 0x40000L, 0x80000L,
4814 0x100000L, 0x200000L, 0x400000L, 0x800000L,
4815 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
4816 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
4819 for (idx = 0; idx < 32; idx++)
4825 /*-----------------------------------------------------------------*/
4826 /* jmpTrueOrFalse - */
4827 /*-----------------------------------------------------------------*/
4829 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
4831 // ugly but optimized by peephole
4834 symbol *nlbl = newiTempLabel (NULL);
4835 emit2 ("jp !tlabel", nlbl->key + 100);
4836 emitLabel (tlbl->key + 100);
4837 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
4838 emitLabel (nlbl->key + 100);
4842 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
4843 emitLabel (tlbl->key + 100);
4848 /*-----------------------------------------------------------------*/
4849 /* genAnd - code for and */
4850 /*-----------------------------------------------------------------*/
4852 genAnd (iCode * ic, iCode * ifx)
4854 operand *left, *right, *result;
4855 int size, offset = 0;
4856 unsigned long lit = 0L;
4859 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4860 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4861 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4863 /* if left is a literal & right is not then exchange them */
4864 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4865 AOP_NEEDSACC (left))
4867 operand *tmp = right;
4872 /* if result = right then exchange them */
4873 if (sameRegs (AOP (result), AOP (right)))
4875 operand *tmp = right;
4880 /* if right is bit then exchange them */
4881 if (AOP_TYPE (right) == AOP_CRY &&
4882 AOP_TYPE (left) != AOP_CRY)
4884 operand *tmp = right;
4888 if (AOP_TYPE (right) == AOP_LIT)
4889 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4891 size = AOP_SIZE (result);
4893 if (AOP_TYPE (left) == AOP_CRY)
4895 wassertl (0, "Tried to perform an AND with a bit as an operand");
4899 // if(val & 0xZZ) - size = 0, ifx != FALSE -
4900 // bit = val & 0xZZ - size = 1, ifx = FALSE -
4901 if ((AOP_TYPE (right) == AOP_LIT) &&
4902 (AOP_TYPE (result) == AOP_CRY) &&
4903 (AOP_TYPE (left) != AOP_CRY))
4905 symbol *tlbl = newiTempLabel (NULL);
4906 int sizel = AOP_SIZE (left);
4909 /* PENDING: Test case for this. */
4914 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
4916 _moveA (aopGet (AOP (left), offset, FALSE));
4917 if (bytelit != 0x0FFL)
4919 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4926 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4930 // bit = left & literal
4934 emit2 ("!tlabeldef", tlbl->key + 100);
4936 // if(left & literal)
4941 jmpTrueOrFalse (ifx, tlbl);
4949 /* if left is same as result */
4950 if (sameRegs (AOP (result), AOP (left)))
4952 for (; size--; offset++)
4954 if (AOP_TYPE (right) == AOP_LIT)
4956 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4961 aopPut (AOP (result), "!zero", offset);
4964 _moveA (aopGet (AOP (left), offset, FALSE));
4966 aopGet (AOP (right), offset, FALSE));
4967 aopPut (AOP (left), "a", offset);
4974 if (AOP_TYPE (left) == AOP_ACC)
4976 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
4980 _moveA (aopGet (AOP (left), offset, FALSE));
4982 aopGet (AOP (right), offset, FALSE));
4983 aopPut (AOP (left), "a", offset);
4990 // left & result in different registers
4991 if (AOP_TYPE (result) == AOP_CRY)
4993 wassertl (0, "Tried to AND where the result is in carry");
4997 for (; (size--); offset++)
5000 // result = left & right
5001 if (AOP_TYPE (right) == AOP_LIT)
5003 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5005 aopPut (AOP (result),
5006 aopGet (AOP (left), offset, FALSE),
5010 else if (bytelit == 0)
5012 aopPut (AOP (result), "!zero", offset);
5016 // faster than result <- left, anl result,right
5017 // and better if result is SFR
5018 if (AOP_TYPE (left) == AOP_ACC)
5019 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5022 _moveA (aopGet (AOP (left), offset, FALSE));
5024 aopGet (AOP (right), offset, FALSE));
5026 aopPut (AOP (result), "a", offset);
5033 freeAsmop (left, NULL, ic);
5034 freeAsmop (right, NULL, ic);
5035 freeAsmop (result, NULL, ic);
5038 /*-----------------------------------------------------------------*/
5039 /* genOr - code for or */
5040 /*-----------------------------------------------------------------*/
5042 genOr (iCode * ic, iCode * ifx)
5044 operand *left, *right, *result;
5045 int size, offset = 0;
5046 unsigned long lit = 0L;
5049 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5050 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5051 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5053 /* if left is a literal & right is not then exchange them */
5054 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5055 AOP_NEEDSACC (left))
5057 operand *tmp = right;
5062 /* if result = right then exchange them */
5063 if (sameRegs (AOP (result), AOP (right)))
5065 operand *tmp = right;
5070 /* if right is bit then exchange them */
5071 if (AOP_TYPE (right) == AOP_CRY &&
5072 AOP_TYPE (left) != AOP_CRY)
5074 operand *tmp = right;
5078 if (AOP_TYPE (right) == AOP_LIT)
5079 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5081 size = AOP_SIZE (result);
5083 if (AOP_TYPE (left) == AOP_CRY)
5085 wassertl (0, "Tried to OR where left is a bit");
5089 // if(val | 0xZZ) - size = 0, ifx != FALSE -
5090 // bit = val | 0xZZ - size = 1, ifx = FALSE -
5091 if ((AOP_TYPE (right) == AOP_LIT) &&
5092 (AOP_TYPE (result) == AOP_CRY) &&
5093 (AOP_TYPE (left) != AOP_CRY))
5095 symbol *tlbl = newiTempLabel (NULL);
5096 int sizel = AOP_SIZE (left);
5100 wassertl (0, "Result is assigned to a bit");
5102 /* PENDING: Modeled after the AND code which is inefficent. */
5105 bytelit = (lit >> (offset * 8)) & 0x0FFL;
5107 _moveA (aopGet (AOP (left), offset, FALSE));
5108 /* OR with any literal is the same as OR with itself. */
5110 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5116 jmpTrueOrFalse (ifx, tlbl);
5121 /* if left is same as result */
5122 if (sameRegs (AOP (result), AOP (left)))
5124 for (; size--; offset++)
5126 if (AOP_TYPE (right) == AOP_LIT)
5128 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5132 _moveA (aopGet (AOP (left), offset, FALSE));
5134 aopGet (AOP (right), offset, FALSE));
5135 aopPut (AOP (result), "a", offset);
5140 if (AOP_TYPE (left) == AOP_ACC)
5141 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5144 _moveA (aopGet (AOP (left), offset, FALSE));
5146 aopGet (AOP (right), offset, FALSE));
5147 aopPut (AOP (result), "a", offset);
5154 // left & result in different registers
5155 if (AOP_TYPE (result) == AOP_CRY)
5157 wassertl (0, "Result of OR is in a bit");
5160 for (; (size--); offset++)
5163 // result = left & right
5164 if (AOP_TYPE (right) == AOP_LIT)
5166 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5168 aopPut (AOP (result),
5169 aopGet (AOP (left), offset, FALSE),
5174 // faster than result <- left, anl result,right
5175 // and better if result is SFR
5176 if (AOP_TYPE (left) == AOP_ACC)
5177 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5180 _moveA (aopGet (AOP (left), offset, FALSE));
5182 aopGet (AOP (right), offset, FALSE));
5184 aopPut (AOP (result), "a", offset);
5185 /* PENDING: something weird is going on here. Add exception. */
5186 if (AOP_TYPE (result) == AOP_ACC)
5192 freeAsmop (left, NULL, ic);
5193 freeAsmop (right, NULL, ic);
5194 freeAsmop (result, NULL, ic);
5197 /*-----------------------------------------------------------------*/
5198 /* genXor - code for xclusive or */
5199 /*-----------------------------------------------------------------*/
5201 genXor (iCode * ic, iCode * ifx)
5203 operand *left, *right, *result;
5204 int size, offset = 0;
5205 unsigned long lit = 0L;
5207 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5208 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5209 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5211 /* if left is a literal & right is not then exchange them */
5212 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5213 AOP_NEEDSACC (left))
5215 operand *tmp = right;
5220 /* if result = right then exchange them */
5221 if (sameRegs (AOP (result), AOP (right)))
5223 operand *tmp = right;
5228 /* if right is bit then exchange them */
5229 if (AOP_TYPE (right) == AOP_CRY &&
5230 AOP_TYPE (left) != AOP_CRY)
5232 operand *tmp = right;
5236 if (AOP_TYPE (right) == AOP_LIT)
5237 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5239 size = AOP_SIZE (result);
5241 if (AOP_TYPE (left) == AOP_CRY)
5243 wassertl (0, "Tried to XOR a bit");
5247 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5248 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5249 if ((AOP_TYPE (right) == AOP_LIT) &&
5250 (AOP_TYPE (result) == AOP_CRY) &&
5251 (AOP_TYPE (left) != AOP_CRY))
5253 symbol *tlbl = newiTempLabel (NULL);
5254 int sizel = AOP_SIZE (left);
5258 /* PENDING: Test case for this. */
5259 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5263 _moveA (aopGet (AOP (left), offset, FALSE));
5264 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5265 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5270 jmpTrueOrFalse (ifx, tlbl);
5274 wassertl (0, "Result of XOR was destined for a bit");
5279 /* if left is same as result */
5280 if (sameRegs (AOP (result), AOP (left)))
5282 for (; size--; offset++)
5284 if (AOP_TYPE (right) == AOP_LIT)
5286 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5290 _moveA (aopGet (AOP (right), offset, FALSE));
5292 aopGet (AOP (left), offset, FALSE));
5293 aopPut (AOP (result), "a", offset);
5298 if (AOP_TYPE (left) == AOP_ACC)
5300 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5304 _moveA (aopGet (AOP (right), offset, FALSE));
5306 aopGet (AOP (left), offset, FALSE));
5307 aopPut (AOP (result), "a", offset);
5314 // left & result in different registers
5315 if (AOP_TYPE (result) == AOP_CRY)
5317 wassertl (0, "Result of XOR is in a bit");
5320 for (; (size--); offset++)
5323 // result = left & right
5324 if (AOP_TYPE (right) == AOP_LIT)
5326 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5328 aopPut (AOP (result),
5329 aopGet (AOP (left), offset, FALSE),
5334 // faster than result <- left, anl result,right
5335 // and better if result is SFR
5336 if (AOP_TYPE (left) == AOP_ACC)
5338 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5342 _moveA (aopGet (AOP (right), offset, FALSE));
5344 aopGet (AOP (left), offset, FALSE));
5346 aopPut (AOP (result), "a", offset);
5351 freeAsmop (left, NULL, ic);
5352 freeAsmop (right, NULL, ic);
5353 freeAsmop (result, NULL, ic);
5356 /*-----------------------------------------------------------------*/
5357 /* genInline - write the inline code out */
5358 /*-----------------------------------------------------------------*/
5360 genInline (iCode * ic)
5362 char *buffer, *bp, *bp1;
5364 _G.lines.isInline += (!options.asmpeep);
5366 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5367 strcpy (buffer, IC_INLINE (ic));
5369 /* emit each line as a code */
5394 _G.lines.isInline -= (!options.asmpeep);
5398 /*-----------------------------------------------------------------*/
5399 /* genRRC - rotate right with carry */
5400 /*-----------------------------------------------------------------*/
5407 /*-----------------------------------------------------------------*/
5408 /* genRLC - generate code for rotate left with carry */
5409 /*-----------------------------------------------------------------*/
5416 /*-----------------------------------------------------------------*/
5417 /* genGetHbit - generates code get highest order bit */
5418 /*-----------------------------------------------------------------*/
5420 genGetHbit (iCode * ic)
5422 operand *left, *result;
5423 left = IC_LEFT (ic);
5424 result = IC_RESULT (ic);
5426 aopOp (left, ic, FALSE, FALSE);
5427 aopOp (result, ic, FALSE, FALSE);
5429 /* get the highest order byte into a */
5430 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5432 if (AOP_TYPE (result) == AOP_CRY)
5440 emit2 ("and a,!one");
5445 freeAsmop (left, NULL, ic);
5446 freeAsmop (result, NULL, ic);
5450 emitRsh2 (asmop *aop, int size, int is_signed)
5456 const char *l = aopGet (aop, size, FALSE);
5459 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5469 /*-----------------------------------------------------------------*/
5470 /* shiftR2Left2Result - shift right two bytes from left to result */
5471 /*-----------------------------------------------------------------*/
5473 shiftR2Left2Result (operand * left, int offl,
5474 operand * result, int offr,
5475 int shCount, int is_signed)
5478 symbol *tlbl, *tlbl1;
5480 movLeft2Result (left, offl, result, offr, 0);
5481 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5483 /* if (AOP(result)->type == AOP_REG) { */
5485 tlbl = newiTempLabel (NULL);
5486 tlbl1 = newiTempLabel (NULL);
5488 /* Left is already in result - so now do the shift */
5493 emitRsh2 (AOP (result), size, is_signed);
5498 emit2 ("ld a,!immedbyte+1", shCount);
5499 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5500 emitLabel (tlbl->key + 100);
5502 emitRsh2 (AOP (result), size, is_signed);
5504 emitLabel (tlbl1->key + 100);
5506 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5510 /*-----------------------------------------------------------------*/
5511 /* shiftL2Left2Result - shift left two bytes from left to result */
5512 /*-----------------------------------------------------------------*/
5514 shiftL2Left2Result (operand * left, int offl,
5515 operand * result, int offr, int shCount)
5517 if (sameRegs (AOP (result), AOP (left)) &&
5518 ((offl + MSB16) == offr))
5524 /* Copy left into result */
5525 movLeft2Result (left, offl, result, offr, 0);
5526 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5529 if (getPairId (AOP (result)) == PAIR_HL)
5533 emit2 ("add hl,hl");
5540 symbol *tlbl, *tlbl1;
5543 tlbl = newiTempLabel (NULL);
5544 tlbl1 = newiTempLabel (NULL);
5546 if (AOP (result)->type == AOP_REG)
5550 for (offset = 0; offset < size; offset++)
5552 l = aopGet (AOP (result), offset, FALSE);
5556 emit2 ("sla %s", l);
5567 /* Left is already in result - so now do the shift */
5570 emit2 ("ld a,!immedbyte+1", shCount);
5571 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5572 emitLabel (tlbl->key + 100);
5577 l = aopGet (AOP (result), offset, FALSE);
5581 emit2 ("sla %s", l);
5592 emitLabel (tlbl1->key + 100);
5594 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5600 /*-----------------------------------------------------------------*/
5601 /* AccRol - rotate left accumulator by known count */
5602 /*-----------------------------------------------------------------*/
5604 AccRol (int shCount)
5606 shCount &= 0x0007; // shCount : 0..7
5683 /*-----------------------------------------------------------------*/
5684 /* AccLsh - left shift accumulator by known count */
5685 /*-----------------------------------------------------------------*/
5687 AccLsh (int shCount)
5689 static const unsigned char SLMask[] =
5691 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5700 else if (shCount == 2)
5707 /* rotate left accumulator */
5709 /* and kill the lower order bits */
5710 emit2 ("and a,!immedbyte", SLMask[shCount]);
5715 /*-----------------------------------------------------------------*/
5716 /* shiftL1Left2Result - shift left one byte from left to result */
5717 /*-----------------------------------------------------------------*/
5719 shiftL1Left2Result (operand * left, int offl,
5720 operand * result, int offr, int shCount)
5723 l = aopGet (AOP (left), offl, FALSE);
5725 /* shift left accumulator */
5727 aopPut (AOP (result), "a", offr);
5731 /*-----------------------------------------------------------------*/
5732 /* genlshTwo - left shift two bytes by known amount != 0 */
5733 /*-----------------------------------------------------------------*/
5735 genlshTwo (operand * result, operand * left, int shCount)
5737 int size = AOP_SIZE (result);
5739 wassert (size == 2);
5741 /* if shCount >= 8 */
5749 movLeft2Result (left, LSB, result, MSB16, 0);
5750 aopPut (AOP (result), "!zero", 0);
5751 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
5755 movLeft2Result (left, LSB, result, MSB16, 0);
5756 aopPut (AOP (result), "!zero", 0);
5761 aopPut (AOP (result), "!zero", LSB);
5764 /* 1 <= shCount <= 7 */
5773 shiftL2Left2Result (left, LSB, result, LSB, shCount);
5778 /*-----------------------------------------------------------------*/
5779 /* genlshOne - left shift a one byte quantity by known count */
5780 /*-----------------------------------------------------------------*/
5782 genlshOne (operand * result, operand * left, int shCount)
5784 shiftL1Left2Result (left, LSB, result, LSB, shCount);
5787 /*-----------------------------------------------------------------*/
5788 /* genLeftShiftLiteral - left shifting by known count */
5789 /*-----------------------------------------------------------------*/
5791 genLeftShiftLiteral (operand * left,
5796 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5799 freeAsmop (right, NULL, ic);
5801 aopOp (left, ic, FALSE, FALSE);
5802 aopOp (result, ic, FALSE, FALSE);
5804 size = getSize (operandType (result));
5806 /* I suppose that the left size >= result size */
5812 else if (shCount >= (size * 8))
5816 aopPut (AOP (result), "!zero", size);
5824 genlshOne (result, left, shCount);
5827 genlshTwo (result, left, shCount);
5830 wassertl (0, "Shifting of longs is currently unsupported");
5836 freeAsmop (left, NULL, ic);
5837 freeAsmop (result, NULL, ic);
5840 /*-----------------------------------------------------------------*/
5841 /* genLeftShift - generates code for left shifting */
5842 /*-----------------------------------------------------------------*/
5844 genLeftShift (iCode * ic)
5848 symbol *tlbl, *tlbl1;
5849 operand *left, *right, *result;
5851 right = IC_RIGHT (ic);
5852 left = IC_LEFT (ic);
5853 result = IC_RESULT (ic);
5855 aopOp (right, ic, FALSE, FALSE);
5857 /* if the shift count is known then do it
5858 as efficiently as possible */
5859 if (AOP_TYPE (right) == AOP_LIT)
5861 genLeftShiftLiteral (left, right, result, ic);
5865 /* shift count is unknown then we have to form a loop get the loop
5866 count in B : Note: we take only the lower order byte since
5867 shifting more that 32 bits make no sense anyway, ( the largest
5868 size of an object can be only 32 bits ) */
5869 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5871 freeAsmop (right, NULL, ic);
5872 aopOp (left, ic, FALSE, FALSE);
5873 aopOp (result, ic, FALSE, FALSE);
5875 /* now move the left to the result if they are not the
5878 if (!sameRegs (AOP (left), AOP (result)))
5881 size = AOP_SIZE (result);
5885 l = aopGet (AOP (left), offset, FALSE);
5886 aopPut (AOP (result), l, offset);
5891 tlbl = newiTempLabel (NULL);
5892 size = AOP_SIZE (result);
5894 tlbl1 = newiTempLabel (NULL);
5896 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5897 emitLabel (tlbl->key + 100);
5898 l = aopGet (AOP (result), offset, FALSE);
5902 l = aopGet (AOP (result), offset, FALSE);
5906 emit2 ("sla %s", l);
5914 emitLabel (tlbl1->key + 100);
5916 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5918 freeAsmop (left, NULL, ic);
5919 freeAsmop (result, NULL, ic);
5922 /*-----------------------------------------------------------------*/
5923 /* genrshOne - left shift two bytes by known amount != 0 */
5924 /*-----------------------------------------------------------------*/
5926 genrshOne (operand * result, operand * left, int shCount, int is_signed)
5929 int size = AOP_SIZE (result);
5932 wassert (size == 1);
5933 wassert (shCount < 8);
5935 l = aopGet (AOP (left), 0, FALSE);
5937 if (AOP (result)->type == AOP_REG)
5939 aopPut (AOP (result), l, 0);
5940 l = aopGet (AOP (result), 0, FALSE);
5943 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5951 emit2 ("%s a", is_signed ? "sra" : "srl");
5953 aopPut (AOP (result), "a", 0);
5957 /*-----------------------------------------------------------------*/
5958 /* AccRsh - right shift accumulator by known count */
5959 /*-----------------------------------------------------------------*/
5961 AccRsh (int shCount)
5963 static const unsigned char SRMask[] =
5965 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
5970 /* rotate right accumulator */
5971 AccRol (8 - shCount);
5972 /* and kill the higher order bits */
5973 emit2 ("and a,!immedbyte", SRMask[shCount]);
5977 /*-----------------------------------------------------------------*/
5978 /* shiftR1Left2Result - shift right one byte from left to result */
5979 /*-----------------------------------------------------------------*/
5981 shiftR1Left2Result (operand * left, int offl,
5982 operand * result, int offr,
5983 int shCount, int sign)
5985 _moveA (aopGet (AOP (left), offl, FALSE));
5990 emit2 ("%s a", sign ? "sra" : "srl");
5997 aopPut (AOP (result), "a", offr);
6000 /*-----------------------------------------------------------------*/
6001 /* genrshTwo - right shift two bytes by known amount != 0 */
6002 /*-----------------------------------------------------------------*/
6004 genrshTwo (operand * result, operand * left,
6005 int shCount, int sign)
6007 /* if shCount >= 8 */
6013 shiftR1Left2Result (left, MSB16, result, LSB,
6018 movLeft2Result (left, MSB16, result, LSB, sign);
6022 /* Sign extend the result */
6023 _moveA(aopGet (AOP (result), 0, FALSE));
6027 aopPut (AOP (result), ACC_NAME, MSB16);
6031 aopPut (AOP (result), "!zero", 1);
6034 /* 1 <= shCount <= 7 */
6037 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
6041 /*-----------------------------------------------------------------*/
6042 /* genRightShiftLiteral - left shifting by known count */
6043 /*-----------------------------------------------------------------*/
6045 genRightShiftLiteral (operand * left,
6051 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6054 freeAsmop (right, NULL, ic);
6056 aopOp (left, ic, FALSE, FALSE);
6057 aopOp (result, ic, FALSE, FALSE);
6059 size = getSize (operandType (result));
6061 /* I suppose that the left size >= result size */
6067 else if (shCount >= (size * 8)) {
6069 if (!SPEC_USIGN(getSpec(operandType(left)))) {
6070 _moveA(aopGet (AOP (left), 0, FALSE));
6078 aopPut (AOP (result), s, size);
6085 genrshOne (result, left, shCount, sign);
6088 genrshTwo (result, left, shCount, sign);
6091 wassertl (0, "Asked to shift right a long which should be a function call");
6094 wassertl (0, "Entered default case in right shift delegate");
6097 freeAsmop (left, NULL, ic);
6098 freeAsmop (result, NULL, ic);
6101 /*-----------------------------------------------------------------*/
6102 /* genRightShift - generate code for right shifting */
6103 /*-----------------------------------------------------------------*/
6105 genRightShift (iCode * ic)
6107 operand *right, *left, *result;
6109 int size, offset, first = 1;
6113 symbol *tlbl, *tlbl1;
6115 /* if signed then we do it the hard way preserve the
6116 sign bit moving it inwards */
6117 retype = getSpec (operandType (IC_RESULT (ic)));
6119 is_signed = !SPEC_USIGN (retype);
6121 /* signed & unsigned types are treated the same : i.e. the
6122 signed is NOT propagated inwards : quoting from the
6123 ANSI - standard : "for E1 >> E2, is equivalent to division
6124 by 2**E2 if unsigned or if it has a non-negative value,
6125 otherwise the result is implementation defined ", MY definition
6126 is that the sign does not get propagated */
6128 right = IC_RIGHT (ic);
6129 left = IC_LEFT (ic);
6130 result = IC_RESULT (ic);
6132 aopOp (right, ic, FALSE, FALSE);
6134 /* if the shift count is known then do it
6135 as efficiently as possible */
6136 if (AOP_TYPE (right) == AOP_LIT)
6138 genRightShiftLiteral (left, right, result, ic, is_signed);
6142 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6144 freeAsmop (right, NULL, ic);
6146 aopOp (left, ic, FALSE, FALSE);
6147 aopOp (result, ic, FALSE, FALSE);
6149 /* now move the left to the result if they are not the
6151 if (!sameRegs (AOP (left), AOP (result)))
6154 size = AOP_SIZE (result);
6158 l = aopGet (AOP (left), offset, FALSE);
6159 aopPut (AOP (result), l, offset);
6164 tlbl = newiTempLabel (NULL);
6165 tlbl1 = newiTempLabel (NULL);
6166 size = AOP_SIZE (result);
6169 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6170 emitLabel (tlbl->key + 100);
6173 l = aopGet (AOP (result), offset--, FALSE);
6176 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6184 emitLabel (tlbl1->key + 100);
6186 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6188 freeAsmop (left, NULL, ic);
6189 freeAsmop (result, NULL, ic);
6193 /*-----------------------------------------------------------------*/
6194 /* genUnpackBits - generates code for unpacking bits */
6195 /*-----------------------------------------------------------------*/
6197 genUnpackBits (operand * result, int pair)
6199 int offset = 0; /* result byte offset */
6200 int rsize; /* result size */
6201 int rlen = 0; /* remaining bitfield length */
6202 sym_link *etype; /* bitfield type information */
6203 int blen; /* bitfield length */
6204 int bstr; /* bitfield starting bit within byte */
6206 emitDebug ("; genUnpackBits");
6208 etype = getSpec (operandType (result));
6209 rsize = getSize (operandType (result));
6210 blen = SPEC_BLEN (etype);
6211 bstr = SPEC_BSTR (etype);
6213 /* If the bitfield length is less than a byte */
6216 emit2 ("ld a,!*pair", _pairs[pair].name);
6218 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6219 aopPut (AOP (result), "a", offset++);
6223 /* TODO: what if pair == PAIR_DE ? */
6224 if (getPairId (AOP (result)) == PAIR_HL)
6226 wassertl (rsize == 2, "HL must be of size 2");
6227 emit2 ("ld a,!*hl");
6229 emit2 ("ld h,!*hl");
6232 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6234 spillPair (PAIR_HL);
6238 /* Bit field did not fit in a byte. Copy all
6239 but the partial byte at the end. */
6240 for (rlen=blen;rlen>=8;rlen-=8)
6242 emit2 ("ld a,!*pair", _pairs[pair].name);
6243 aopPut (AOP (result), "a", offset++);
6246 emit2 ("inc %s", _pairs[pair].name);
6247 _G.pairs[pair].offset++;
6251 /* Handle the partial byte at the end */
6254 emit2 ("ld a,!*pair", _pairs[pair].name);
6255 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6256 aopPut (AOP (result), "a", offset++);
6264 aopPut (AOP (result), "!zero", offset++);
6268 /*-----------------------------------------------------------------*/
6269 /* genGenPointerGet - get value from generic pointer space */
6270 /*-----------------------------------------------------------------*/
6272 genGenPointerGet (operand * left,
6273 operand * result, iCode * ic)
6276 sym_link *retype = getSpec (operandType (result));
6282 aopOp (left, ic, FALSE, FALSE);
6283 aopOp (result, ic, FALSE, FALSE);
6285 size = AOP_SIZE (result);
6287 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6290 if (isPtrPair (AOP (left)))
6292 tsprintf (buffer, sizeof(buffer),
6293 "!*pair", getPairName (AOP (left)));
6294 aopPut (AOP (result), buffer, 0);
6298 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6299 aopPut (AOP (result), "a", 0);
6301 freeAsmop (left, NULL, ic);
6305 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6312 tsprintf (at, sizeof(at), "!*iyx", offset);
6313 aopPut (AOP (result), at, offset);
6317 freeAsmop (left, NULL, ic);
6321 /* For now we always load into IY */
6322 /* if this is remateriazable */
6323 fetchPair (pair, AOP (left));
6325 /* if bit then unpack */
6326 if (IS_BITVAR (retype))
6328 genUnpackBits (result, pair);
6329 freeAsmop (left, NULL, ic);
6333 else if (getPairId (AOP (result)) == PAIR_HL)
6335 wassertl (size == 2, "HL must be of size 2");
6336 emit2 ("ld a,!*hl");
6338 emit2 ("ld h,!*hl");
6340 spillPair (PAIR_HL);
6342 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6344 size = AOP_SIZE (result);
6349 /* PENDING: make this better */
6350 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6352 aopPut (AOP (result), "!*hl", offset++);
6356 emit2 ("ld a,!*pair", _pairs[pair].name);
6357 aopPut (AOP (result), "a", offset++);
6361 emit2 ("inc %s", _pairs[pair].name);
6362 _G.pairs[pair].offset++;
6365 /* Fixup HL back down */
6366 for (size = AOP_SIZE (result)-1; size; size--)
6368 emit2 ("dec %s", _pairs[pair].name);
6373 size = AOP_SIZE (result);
6378 /* PENDING: make this better */
6380 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6382 aopPut (AOP (result), "!*hl", offset++);
6386 emit2 ("ld a,!*pair", _pairs[pair].name);
6387 aopPut (AOP (result), "a", offset++);
6391 emit2 ("inc %s", _pairs[pair].name);
6392 _G.pairs[pair].offset++;
6397 freeAsmop (left, NULL, ic);
6400 freeAsmop (result, NULL, ic);
6403 /*-----------------------------------------------------------------*/
6404 /* genPointerGet - generate code for pointer get */
6405 /*-----------------------------------------------------------------*/
6407 genPointerGet (iCode * ic)
6409 operand *left, *result;
6410 sym_link *type, *etype;
6412 left = IC_LEFT (ic);
6413 result = IC_RESULT (ic);
6415 /* depending on the type of pointer we need to
6416 move it to the correct pointer register */
6417 type = operandType (left);
6418 etype = getSpec (type);
6420 genGenPointerGet (left, result, ic);
6424 isRegOrLit (asmop * aop)
6426 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6432 /*-----------------------------------------------------------------*/
6433 /* genPackBits - generates code for packed bit storage */
6434 /*-----------------------------------------------------------------*/
6436 genPackBits (sym_link * etype,
6441 int offset = 0; /* source byte offset */
6442 int rlen = 0; /* remaining bitfield length */
6443 int blen; /* bitfield length */
6444 int bstr; /* bitfield starting bit within byte */
6445 int litval; /* source literal value (if AOP_LIT) */
6446 unsigned char mask; /* bitmask within current byte */
6447 int extraPair; /* a tempory register */
6448 bool needPopExtra=0; /* need to restore original value of temp reg */
6450 emitDebug ("; genPackBits","");
6452 blen = SPEC_BLEN (etype);
6453 bstr = SPEC_BSTR (etype);
6455 /* If the bitfield length is less than a byte */
6458 mask = ((unsigned char) (0xFF << (blen + bstr)) |
6459 (unsigned char) (0xFF >> (8 - bstr)));
6461 if (AOP_TYPE (right) == AOP_LIT)
6463 /* Case with a bitfield length <8 and literal source
6465 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6467 litval &= (~mask) & 0xff;
6468 emit2 ("ld a,!*pair", _pairs[pair].name);
6469 if ((mask|litval)!=0xff)
6470 emit2 ("and a,!immedbyte", mask);
6472 emit2 ("or a,!immedbyte", litval);
6473 emit2 ("ld !*pair,a", _pairs[pair].name);
6478 /* Case with a bitfield length <8 and arbitrary source
6480 _moveA (aopGet (AOP (right), 0, FALSE));
6481 /* shift and mask source value */
6483 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6485 extraPair = getFreePairId(ic);
6486 if (extraPair == PAIR_INVALID)
6488 extraPair = PAIR_BC;
6489 if (getPairId (AOP (right)) != PAIR_BC
6490 || !isLastUse (ic, right))
6496 emit2 ("ld %s,a", _pairs[extraPair].l);
6497 emit2 ("ld a,!*pair", _pairs[pair].name);
6499 emit2 ("and a,!immedbyte", mask);
6500 emit2 ("or a,%s", _pairs[extraPair].l);
6501 emit2 ("ld !*pair,a", _pairs[pair].name);
6508 /* Bit length is greater than 7 bits. In this case, copy */
6509 /* all except the partial byte at the end */
6510 for (rlen=blen;rlen>=8;rlen-=8)
6512 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
6513 emit2 ("ld !*pair,a", _pairs[pair].name);
6516 emit2 ("inc %s", _pairs[pair].name);
6517 _G.pairs[pair].offset++;
6521 /* If there was a partial byte at the end */
6524 mask = (((unsigned char) -1 << rlen) & 0xff);
6526 if (AOP_TYPE (right) == AOP_LIT)
6528 /* Case with partial byte and literal source
6530 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6531 litval >>= (blen-rlen);
6532 litval &= (~mask) & 0xff;
6533 emit2 ("ld a,!*pair", _pairs[pair].name);
6534 if ((mask|litval)!=0xff)
6535 emit2 ("and a,!immedbyte", mask);
6537 emit2 ("or a,!immedbyte", litval);
6541 /* Case with partial byte and arbitrary source
6543 _moveA (aopGet (AOP (right), offset++, FALSE));
6544 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6546 extraPair = getFreePairId(ic);
6547 if (extraPair == PAIR_INVALID)
6549 extraPair = getPairId (AOP (right));
6550 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
6551 extraPair = PAIR_BC;
6553 if (getPairId (AOP (right)) != PAIR_BC
6554 || !isLastUse (ic, right))
6560 emit2 ("ld %s,a", _pairs[extraPair].l);
6561 emit2 ("ld a,!*pair", _pairs[pair].name);
6563 emit2 ("and a,!immedbyte", mask);
6564 emit2 ("or a,%s", _pairs[extraPair].l);
6569 emit2 ("ld !*pair,a", _pairs[pair].name);
6574 /*-----------------------------------------------------------------*/
6575 /* genGenPointerSet - stores the value into a pointer location */
6576 /*-----------------------------------------------------------------*/
6578 genGenPointerSet (operand * right,
6579 operand * result, iCode * ic)
6582 sym_link *retype = getSpec (operandType (right));
6583 sym_link *letype = getSpec (operandType (result));
6584 PAIR_ID pairId = PAIR_HL;
6587 aopOp (result, ic, FALSE, FALSE);
6588 aopOp (right, ic, FALSE, FALSE);
6593 size = AOP_SIZE (right);
6595 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
6596 emitDebug("; isBitvar = %d", isBitvar);
6598 /* Handle the exceptions first */
6599 if (isPair (AOP (result)) && size == 1 && !isBitvar)
6602 const char *l = aopGet (AOP (right), 0, FALSE);
6603 const char *pair = getPairName (AOP (result));
6604 if (canAssignToPtr (l) && isPtr (pair))
6606 emit2 ("ld !*pair,%s", pair, l);
6611 emit2 ("ld !*pair,a", pair);
6616 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
6619 const char *l = aopGet (AOP (right), 0, FALSE);
6624 if (canAssignToPtr (l))
6626 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6630 _moveA (aopGet (AOP (right), offset, FALSE));
6631 emit2 ("ld !*iyx,a", offset);
6637 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
6644 const char *l = aopGet (AOP (right), offset, FALSE);
6645 if (isRegOrLit (AOP (right)) && !IS_GB)
6647 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
6652 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
6656 emit2 ("inc %s", _pairs[PAIR_HL].name);
6657 _G.pairs[PAIR_HL].offset++;
6662 /* Fixup HL back down */
6663 for (size = AOP_SIZE (right)-1; size; size--)
6665 emit2 ("dec %s", _pairs[PAIR_HL].name);
6670 /* if the operand is already in dptr
6671 then we do nothing else we move the value to dptr */
6672 if (AOP_TYPE (result) != AOP_STR)
6674 fetchPair (pairId, AOP (result));
6676 /* so hl know contains the address */
6677 freeAsmop (result, NULL, ic);
6679 /* if bit then unpack */
6682 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
6692 const char *l = aopGet (AOP (right), offset, FALSE);
6693 if (isRegOrLit (AOP (right)) && !IS_GB)
6695 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
6700 emit2 ("ld !*pair,a", _pairs[pairId].name);
6704 emit2 ("inc %s", _pairs[pairId].name);
6705 _G.pairs[pairId].offset++;
6711 freeAsmop (right, NULL, ic);
6714 /*-----------------------------------------------------------------*/
6715 /* genPointerSet - stores the value into a pointer location */
6716 /*-----------------------------------------------------------------*/
6718 genPointerSet (iCode * ic)
6720 operand *right, *result;
6721 sym_link *type, *etype;
6723 right = IC_RIGHT (ic);
6724 result = IC_RESULT (ic);
6726 /* depending on the type of pointer we need to
6727 move it to the correct pointer register */
6728 type = operandType (result);
6729 etype = getSpec (type);
6731 genGenPointerSet (right, result, ic);
6734 /*-----------------------------------------------------------------*/
6735 /* genIfx - generate code for Ifx statement */
6736 /*-----------------------------------------------------------------*/
6738 genIfx (iCode * ic, iCode * popIc)
6740 operand *cond = IC_COND (ic);
6743 aopOp (cond, ic, FALSE, TRUE);
6745 /* get the value into acc */
6746 if (AOP_TYPE (cond) != AOP_CRY)
6750 /* the result is now in the accumulator */
6751 freeAsmop (cond, NULL, ic);
6753 /* if there was something to be popped then do it */
6757 /* if the condition is a bit variable */
6758 if (isbit && IS_ITEMP (cond) &&
6760 genIfxJump (ic, SPIL_LOC (cond)->rname);
6761 else if (isbit && !IS_ITEMP (cond))
6762 genIfxJump (ic, OP_SYMBOL (cond)->rname);
6764 genIfxJump (ic, "a");
6769 /*-----------------------------------------------------------------*/
6770 /* genAddrOf - generates code for address of */
6771 /*-----------------------------------------------------------------*/
6773 genAddrOf (iCode * ic)
6775 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
6777 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6779 /* if the operand is on the stack then we
6780 need to get the stack offset of this
6787 if (sym->stack <= 0)
6789 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
6793 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6795 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6799 emit2 ("ld de,!hashedstr", sym->rname);
6800 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
6808 /* if it has an offset then we need to compute it */
6810 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6812 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
6813 emit2 ("add hl,sp");
6817 emit2 ("ld hl,!hashedstr", sym->rname);
6819 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6821 freeAsmop (IC_RESULT (ic), NULL, ic);
6824 /*-----------------------------------------------------------------*/
6825 /* genAssign - generate code for assignment */
6826 /*-----------------------------------------------------------------*/
6828 genAssign (iCode * ic)
6830 operand *result, *right;
6832 unsigned long lit = 0L;
6834 result = IC_RESULT (ic);
6835 right = IC_RIGHT (ic);
6837 /* Dont bother assigning if they are the same */
6838 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6840 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
6844 aopOp (right, ic, FALSE, FALSE);
6845 aopOp (result, ic, TRUE, FALSE);
6847 /* if they are the same registers */
6848 if (sameRegs (AOP (right), AOP (result)))
6850 emitDebug ("; (registers are the same)");
6854 /* if the result is a bit */
6855 if (AOP_TYPE (result) == AOP_CRY)
6857 wassertl (0, "Tried to assign to a bit");
6861 size = AOP_SIZE (result);
6864 if (AOP_TYPE (right) == AOP_LIT)
6866 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6869 if (isPair (AOP (result)))
6871 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
6873 else if ((size > 1) &&
6874 (AOP_TYPE (result) != AOP_REG) &&
6875 (AOP_TYPE (right) == AOP_LIT) &&
6876 !IS_FLOAT (operandType (right)) &&
6879 bool fXored = FALSE;
6881 /* Work from the top down.
6882 Done this way so that we can use the cached copy of 0
6883 in A for a fast clear */
6886 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
6888 if (!fXored && size > 1)
6895 aopPut (AOP (result), "a", offset);
6899 aopPut (AOP (result), "!zero", offset);
6903 aopPut (AOP (result),
6904 aopGet (AOP (right), offset, FALSE),
6909 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
6911 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
6912 aopPut (AOP (result), "l", LSB);
6913 aopPut (AOP (result), "h", MSB16);
6915 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6917 /* Special case. Load into a and d, then load out. */
6918 _moveA (aopGet (AOP (right), 0, FALSE));
6919 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
6920 aopPut (AOP (result), "a", 0);
6921 aopPut (AOP (result), "e", 1);
6923 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6925 /* Special case - simple memcpy */
6926 aopGet (AOP (right), LSB, FALSE);
6929 aopGet (AOP (result), LSB, FALSE);
6933 emit2 ("ld a,(de)");
6934 /* Peephole will optimise this. */
6935 emit2 ("ld (hl),a");
6943 spillPair (PAIR_HL);
6949 /* PENDING: do this check better */
6950 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
6952 _moveA (aopGet (AOP (right), offset, FALSE));
6953 aopPut (AOP (result), "a", offset);
6956 aopPut (AOP (result),
6957 aopGet (AOP (right), offset, FALSE),
6964 freeAsmop (right, NULL, ic);
6965 freeAsmop (result, NULL, ic);
6968 /*-----------------------------------------------------------------*/
6969 /* genJumpTab - genrates code for jump table */
6970 /*-----------------------------------------------------------------*/
6972 genJumpTab (iCode * ic)
6977 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
6978 /* get the condition into accumulator */
6979 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
6982 emit2 ("ld e,%s", l);
6983 emit2 ("ld d,!zero");
6984 jtab = newiTempLabel (NULL);
6986 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
6987 emit2 ("add hl,de");
6988 emit2 ("add hl,de");
6989 emit2 ("add hl,de");
6990 freeAsmop (IC_JTCOND (ic), NULL, ic);
6994 emitLabel (jtab->key + 100);
6995 /* now generate the jump labels */
6996 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
6997 jtab = setNextItem (IC_JTLABELS (ic)))
6998 emit2 ("jp !tlabel", jtab->key + 100);
7001 /*-----------------------------------------------------------------*/
7002 /* genCast - gen code for casting */
7003 /*-----------------------------------------------------------------*/
7005 genCast (iCode * ic)
7007 operand *result = IC_RESULT (ic);
7008 sym_link *rtype = operandType (IC_RIGHT (ic));
7009 operand *right = IC_RIGHT (ic);
7012 /* if they are equivalent then do nothing */
7013 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7016 aopOp (right, ic, FALSE, FALSE);
7017 aopOp (result, ic, FALSE, FALSE);
7019 /* if the result is a bit */
7020 if (AOP_TYPE (result) == AOP_CRY)
7022 wassertl (0, "Tried to cast to a bit");
7025 /* if they are the same size : or less */
7026 if (AOP_SIZE (result) <= AOP_SIZE (right))
7029 /* if they are in the same place */
7030 if (sameRegs (AOP (right), AOP (result)))
7033 /* if they in different places then copy */
7034 size = AOP_SIZE (result);
7038 aopPut (AOP (result),
7039 aopGet (AOP (right), offset, FALSE),
7046 /* So we now know that the size of destination is greater
7047 than the size of the source */
7048 /* we move to result for the size of source */
7049 size = AOP_SIZE (right);
7053 aopPut (AOP (result),
7054 aopGet (AOP (right), offset, FALSE),
7059 /* now depending on the sign of the destination */
7060 size = AOP_SIZE (result) - AOP_SIZE (right);
7061 /* Unsigned or not an integral type - right fill with zeros */
7062 if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
7065 aopPut (AOP (result), "!zero", offset++);
7069 /* we need to extend the sign :{ */
7070 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
7076 aopPut (AOP (result), "a", offset++);
7080 freeAsmop (right, NULL, ic);
7081 freeAsmop (result, NULL, ic);
7084 /*-----------------------------------------------------------------*/
7085 /* genReceive - generate code for a receive iCode */
7086 /*-----------------------------------------------------------------*/
7088 genReceive (iCode * ic)
7090 if (isOperandInFarSpace (IC_RESULT (ic)) &&
7091 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7092 IS_TRUE_SYMOP (IC_RESULT (ic))))
7102 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7103 size = AOP_SIZE(IC_RESULT(ic));
7105 for (i = 0; i < size; i++) {
7106 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7110 freeAsmop (IC_RESULT (ic), NULL, ic);
7113 /*-----------------------------------------------------------------*/
7114 /* genDummyRead - generate code for dummy read of volatiles */
7115 /*-----------------------------------------------------------------*/
7117 genDummyRead (iCode * ic)
7122 right = IC_RIGHT (ic);
7123 aopOp (right, ic, FALSE, FALSE);
7126 size = AOP_SIZE (right);
7131 _moveA (aopGet (AOP (right), offset, FALSE));
7136 freeAsmop (right, NULL, ic);
7141 /** Maximum number of bytes to emit per line. */
7145 /** Context for the byte output chunker. */
7148 unsigned char buffer[DBEMIT_MAX_RUN];
7153 /** Flushes a byte chunker by writing out all in the buffer and
7157 _dbFlush(DBEMITCTX *self)
7164 sprintf(line, ".db 0x%02X", self->buffer[0]);
7166 for (i = 1; i < self->pos; i++)
7168 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7175 /** Write out another byte, buffering until a decent line is
7179 _dbEmit(DBEMITCTX *self, int c)
7181 if (self->pos == DBEMIT_MAX_RUN)
7185 self->buffer[self->pos++] = c;
7188 /** Context for a simple run length encoder. */
7192 unsigned char buffer[128];
7194 /** runLen may be equivalent to pos. */
7200 RLE_CHANGE_COST = 4,
7204 /** Flush the buffer of a run length encoder by writing out the run or
7205 data that it currently contains.
7208 _rleCommit(RLECTX *self)
7214 memset(&db, 0, sizeof(db));
7216 emit2(".db %u", self->pos);
7218 for (i = 0; i < self->pos; i++)
7220 _dbEmit(&db, self->buffer[i]);
7229 Can get either a run or a block of random stuff.
7230 Only want to change state if a good run comes in or a run ends.
7231 Detecting run end is easy.
7234 Say initial state is in run, len zero, last zero. Then if you get a
7235 few zeros then something else then a short run will be output.
7236 Seems OK. While in run mode, keep counting. While in random mode,
7237 keep a count of the run. If run hits margin, output all up to run,
7238 restart, enter run mode.
7241 /** Add another byte into the run length encoder, flushing as
7242 required. The run length encoder uses the Amiga IFF style, where
7243 a block is prefixed by its run length. A positive length means
7244 the next n bytes pass straight through. A negative length means
7245 that the next byte is repeated -n times. A zero terminates the
7249 _rleAppend(RLECTX *self, int c)
7253 if (c != self->last)
7255 /* The run has stopped. See if it is worthwhile writing it out
7256 as a run. Note that the random data comes in as runs of
7259 if (self->runLen > RLE_CHANGE_COST)
7261 /* Yes, worthwhile. */
7262 /* Commit whatever was in the buffer. */
7264 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7268 /* Not worthwhile. Append to the end of the random list. */
7269 for (i = 0; i < self->runLen; i++)
7271 if (self->pos >= RLE_MAX_BLOCK)
7276 self->buffer[self->pos++] = self->last;
7284 if (self->runLen >= RLE_MAX_BLOCK)
7286 /* Commit whatever was in the buffer. */
7289 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7297 _rleFlush(RLECTX *self)
7299 _rleAppend(self, -1);
7306 /** genArrayInit - Special code for initialising an array with constant
7310 genArrayInit (iCode * ic)
7314 int elementSize = 0, eIndex, i;
7315 unsigned val, lastVal;
7319 memset(&rle, 0, sizeof(rle));
7321 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7323 _saveRegsForCall(ic, 0);
7325 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7326 emit2 ("call __initrleblock");
7328 type = operandType(IC_LEFT(ic));
7330 if (type && type->next)
7332 elementSize = getSize(type->next);
7336 wassertl (0, "Can't determine element size in genArrayInit.");
7339 iLoop = IC_ARRAYILIST(ic);
7340 lastVal = (unsigned)-1;
7342 /* Feed all the bytes into the run length encoder which will handle
7344 This works well for mixed char data, and for random int and long
7353 for (i = 0; i < ix; i++)
7355 for (eIndex = 0; eIndex < elementSize; eIndex++)
7357 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7358 _rleAppend(&rle, val);
7363 iLoop = iLoop->next;
7367 /* Mark the end of the run. */
7370 _restoreRegsAfterCall();
7374 freeAsmop (IC_LEFT(ic), NULL, ic);
7378 _swap (PAIR_ID one, PAIR_ID two)
7380 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7386 emit2 ("ld a,%s", _pairs[one].l);
7387 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7388 emit2 ("ld %s,a", _pairs[two].l);
7389 emit2 ("ld a,%s", _pairs[one].h);
7390 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7391 emit2 ("ld %s,a", _pairs[two].h);
7395 /* The problem is that we may have all three pairs used and they may
7396 be needed in a different order.
7401 hl = hl => unity, fine
7405 hl = hl hl = hl, swap de <=> bc
7413 hl = bc de = de, swap bc <=> hl
7421 hl = de bc = bc, swap hl <=> de
7426 * Any pair = pair are done last
7427 * Any pair = iTemp are done last
7428 * Any swaps can be done any time
7436 So how do we detect the cases?
7437 How about a 3x3 matrix?
7441 x x x x (Fourth for iTemp/other)
7443 First determin which mode to use by counting the number of unity and
7446 Two - Assign the pair first, then the rest
7447 One - Swap the two, then the rest
7451 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7453 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7455 PAIR_BC, PAIR_HL, PAIR_DE
7457 int i, j, nunity = 0;
7458 memset (ids, PAIR_INVALID, sizeof (ids));
7461 wassert (nparams == 3);
7463 /* First save everything that needs to be saved. */
7464 _saveRegsForCall (ic, 0);
7466 /* Loading HL first means that DE is always fine. */
7467 for (i = 0; i < nparams; i++)
7469 aopOp (pparams[i], ic, FALSE, FALSE);
7470 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7473 /* Count the number of unity or iTemp assigns. */
7474 for (i = 0; i < 3; i++)
7476 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7484 /* Any order, fall through. */
7486 else if (nunity == 2)
7488 /* One is assigned. Pull it out and assign. */
7489 for (i = 0; i < 3; i++)
7491 for (j = 0; j < NUM_PAIRS; j++)
7493 if (ids[dest[i]][j] == TRUE)
7495 /* Found it. See if it's the right one. */
7496 if (j == PAIR_INVALID || j == dest[i])
7502 fetchPair(dest[i], AOP (pparams[i]));
7509 else if (nunity == 1)
7511 /* Find the pairs to swap. */
7512 for (i = 0; i < 3; i++)
7514 for (j = 0; j < NUM_PAIRS; j++)
7516 if (ids[dest[i]][j] == TRUE)
7518 if (j == PAIR_INVALID || j == dest[i])
7533 int next = getPairId (AOP (pparams[0]));
7534 emit2 ("push %s", _pairs[next].name);
7536 if (next == dest[1])
7538 fetchPair (dest[1], AOP (pparams[1]));
7539 fetchPair (dest[2], AOP (pparams[2]));
7543 fetchPair (dest[2], AOP (pparams[2]));
7544 fetchPair (dest[1], AOP (pparams[1]));
7546 emit2 ("pop %s", _pairs[dest[0]].name);
7549 /* Finally pull out all of the iTemps */
7550 for (i = 0; i < 3; i++)
7552 if (ids[dest[i]][PAIR_INVALID] == 1)
7554 fetchPair (dest[i], AOP (pparams[i]));
7560 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
7566 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
7570 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7572 setupForBuiltin3 (ic, nParams, pparams);
7574 label = newiTempLabel(NULL);
7576 emitLabel (label->key);
7577 emit2 ("ld a,(hl)");
7580 emit2 ("!shortjp nz,!tlabel ; 1", label->key);
7582 freeAsmop (from, NULL, ic->next);
7583 freeAsmop (to, NULL, ic);
7587 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
7589 operand *from, *to, *count;
7592 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
7597 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7599 setupForBuiltin3 (ic, nParams, pparams);
7603 freeAsmop (count, NULL, ic->next->next);
7604 freeAsmop (from, NULL, ic);
7606 _restoreRegsAfterCall();
7608 /* if we need assign a result value */
7609 if ((IS_ITEMP (IC_RESULT (ic)) &&
7610 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
7611 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
7612 IS_TRUE_SYMOP (IC_RESULT (ic)))
7614 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7615 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
7616 freeAsmop (IC_RESULT (ic), NULL, ic);
7619 freeAsmop (to, NULL, ic->next);
7622 /*-----------------------------------------------------------------*/
7623 /* genBuiltIn - calls the appropriate function to generating code */
7624 /* for a built in function */
7625 /*-----------------------------------------------------------------*/
7626 static void genBuiltIn (iCode *ic)
7628 operand *bi_parms[MAX_BUILTIN_ARGS];
7633 /* get all the arguments for a built in function */
7634 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
7636 /* which function is it */
7637 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
7639 if (strcmp(bif->name,"__builtin_strcpy")==0)
7641 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
7643 else if (strcmp(bif->name,"__builtin_memcpy")==0)
7645 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
7649 wassertl (0, "Unknown builtin function encountered");
7653 /*-----------------------------------------------------------------*/
7654 /* genZ80Code - generate code for Z80 based controllers */
7655 /*-----------------------------------------------------------------*/
7657 genZ80Code (iCode * lic)
7665 _fReturn = _gbz80_return;
7666 _fTmp = _gbz80_return;
7670 _fReturn = _z80_return;
7671 _fTmp = _z80_return;
7674 _G.lines.head = _G.lines.current = NULL;
7676 for (ic = lic; ic; ic = ic->next)
7678 _G.current_iCode = ic;
7680 if (cln != ic->lineno)
7682 if (!options.noCcodeInAsm) {
7683 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
7684 printCLine(ic->filename, ic->lineno));
7688 if (options.iCodeInAsm) {
7689 emit2 (";ic:%d: %s", ic->key, printILine(ic));
7691 /* if the result is marked as
7692 spilt and rematerializable or code for
7693 this has already been generated then
7695 if (resultRemat (ic) || ic->generated)
7698 /* depending on the operation */
7702 emitDebug ("; genNot");
7707 emitDebug ("; genCpl");
7712 emitDebug ("; genUminus");
7717 emitDebug ("; genIpush");
7722 /* IPOP happens only when trying to restore a
7723 spilt live range, if there is an ifx statement
7724 following this pop then the if statement might
7725 be using some of the registers being popped which
7726 would destory the contents of the register so
7727 we need to check for this condition and handle it */
7729 ic->next->op == IFX &&
7730 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
7732 emitDebug ("; genIfx");
7733 genIfx (ic->next, ic);
7737 emitDebug ("; genIpop");
7743 emitDebug ("; genCall");
7748 emitDebug ("; genPcall");
7753 emitDebug ("; genFunction");
7758 emitDebug ("; genEndFunction");
7759 genEndFunction (ic);
7763 emitDebug ("; genRet");
7768 emitDebug ("; genLabel");
7773 emitDebug ("; genGoto");
7778 emitDebug ("; genPlus");
7783 emitDebug ("; genMinus");
7788 emitDebug ("; genMult");
7793 emitDebug ("; genDiv");
7798 emitDebug ("; genMod");
7803 emitDebug ("; genCmpGt");
7804 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
7808 emitDebug ("; genCmpLt");
7809 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
7816 /* note these two are xlated by algebraic equivalence
7817 during parsing SDCC.y */
7818 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
7819 "got '>=' or '<=' shouldn't have come here");
7823 emitDebug ("; genCmpEq");
7824 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
7828 emitDebug ("; genAndOp");
7833 emitDebug ("; genOrOp");
7838 emitDebug ("; genXor");
7839 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
7843 emitDebug ("; genOr");
7844 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
7848 emitDebug ("; genAnd");
7849 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
7853 emitDebug ("; genInline");
7858 emitDebug ("; genRRC");
7863 emitDebug ("; genRLC");
7868 emitDebug ("; genGetHBIT");
7873 emitDebug ("; genLeftShift");
7878 emitDebug ("; genRightShift");
7882 case GET_VALUE_AT_ADDRESS:
7883 emitDebug ("; genPointerGet");
7889 if (POINTER_SET (ic))
7891 emitDebug ("; genAssign (pointer)");
7896 emitDebug ("; genAssign");
7902 emitDebug ("; genIfx");
7907 emitDebug ("; genAddrOf");
7912 emitDebug ("; genJumpTab");
7917 emitDebug ("; genCast");
7922 emitDebug ("; genReceive");
7927 if (ic->builtinSEND)
7929 emitDebug ("; genBuiltIn");
7934 emitDebug ("; addSet");
7935 addSet (&_G.sendSet, ic);
7940 emitDebug ("; genArrayInit");
7944 case DUMMY_READ_VOLATILE:
7945 emitDebug ("; genDummyRead");
7955 /* now we are ready to call the
7956 peep hole optimizer */
7957 if (!options.nopeep)
7958 peepHole (&_G.lines.head);
7960 /* This is unfortunate */
7961 /* now do the actual printing */
7963 FILE *fp = codeOutFile;
7964 if (isInHome () && codeOutFile == code->oFile)
7965 codeOutFile = home->oFile;
7966 printLine (_G.lines.head, codeOutFile);
7967 if (_G.flushStatics)
7970 _G.flushStatics = 0;
7975 freeTrace(&_G.lines.trace);
7976 freeTrace(&_G.trace.aops);
7982 _isPairUsed (iCode * ic, PAIR_ID pairId)
7988 if (bitVectBitValue (ic->rMask, D_IDX))
7990 if (bitVectBitValue (ic->rMask, E_IDX))
8000 fetchLitSpecial (asmop * aop, bool negate, bool xor)
8003 value *val = aop->aopu.aop_lit;
8005 wassert (aop->type == AOP_LIT);
8006 wassert (!IS_FLOAT (val->type));
8008 v = (unsigned long) floatFromVal (val);
8016 tsprintf (buffer, sizeof(buffer), "!immedword", v);
8017 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));