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. */
248 static const char *aopGet (asmop * aop, int offset, bool bit16);
250 static const char *aopNames[] = {
271 isLastUse (iCode *ic, operand *op)
273 bitVect *uses = bitVectCopy (OP_USES (op));
275 while (!bitVectIsZero (uses))
277 if (bitVectFirstBit (uses) == ic->key)
279 if (bitVectnBitsOn (uses) == 1)
288 bitVectUnSetBit (uses, bitVectFirstBit (uses));
308 _getTempPairName(void)
310 return _pairs[_getTempPairId()].name;
314 isPairInUse (PAIR_ID id, iCode *ic)
318 return bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
320 else if (id == PAIR_BC)
322 return bitVectBitValue (ic->rMask, B_IDX) || bitVectBitValue(ic->rMask, C_IDX);
326 wassertl (0, "Only implemented for DE and BC");
332 isPairInUseNotInRet(PAIR_ID id, iCode *ic)
336 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
340 return bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
344 wassertl (0, "Only implemented for DE");
350 getFreePairId (iCode *ic)
352 if (!isPairInUse (PAIR_BC, ic))
356 else if (IS_Z80 && !isPairInUse (PAIR_DE, ic))
369 /* Clean up the line so that it is 'prettier' */
370 if (strchr (buf, ':'))
372 /* Is a label - cant do anything */
375 /* Change the first (and probably only) ' ' to a tab so
390 _newLineNode (char *line)
394 pl = traceAlloc(&_G.lines.trace, Safe_alloc ( sizeof (lineNode)));
395 pl->line = traceAlloc(&_G.lines.trace, Safe_strdup (line));
401 _vemit2 (const char *szFormat, va_list ap)
403 char buffer[INITIAL_INLINEASM];
405 tvsprintf (buffer, sizeof(buffer), szFormat, ap);
408 _G.lines.current = (_G.lines.current ?
409 connectLine (_G.lines.current, _newLineNode (buffer)) :
410 (_G.lines.head = _newLineNode (buffer)));
412 _G.lines.current->isInline = _G.lines.isInline;
413 _G.lines.current->isDebug = _G.lines.isDebug;
414 _G.lines.current->ic = _G.current_iCode;
418 emit2 (const char *szFormat,...)
422 va_start (ap, szFormat);
424 _vemit2 (szFormat, ap);
430 emitDebug (const char *szFormat,...)
436 va_start (ap, szFormat);
438 _vemit2 (szFormat, ap);
444 /*-----------------------------------------------------------------*/
445 /* emit2 - writes the code into a file : for now it is simple */
446 /*-----------------------------------------------------------------*/
448 _emit2 (const char *inst, const char *fmt,...)
451 char lb[INITIAL_INLINEASM];
458 sprintf (lb, "%s\t", inst);
459 vsprintf (lb + (strlen (lb)), fmt, ap);
462 vsprintf (lb, fmt, ap);
464 while (isspace (*lbp))
469 _G.lines.current = (_G.lines.current ?
470 connectLine (_G.lines.current, _newLineNode (lb)) :
471 (_G.lines.head = _newLineNode (lb)));
473 _G.lines.current->isInline = _G.lines.isInline;
474 _G.lines.current->ic = _G.current_iCode;
479 _emitMove(const char *to, const char *from)
481 if (STRCASECMP(to, from) != 0)
483 emit2("ld %s,%s", to, from);
488 // Could leave this to the peephole, but sometimes the peephole is inhibited.
493 aopDump(const char *plabel, asmop *aop)
499 emitDebug("; Dump of %s: type %s size %u", plabel, aopNames[aop->type], aop->size);
504 emitDebug("; aop_stk %d", aop->aopu.aop_stk);
507 for (i=aop->size-1;i>=0;i--)
508 *rbp++ = *(aop->aopu.aop_reg[i]->name);
510 emitDebug("; reg = %s", regbuf);
513 emitDebug("; pairptr = (%s)", _pairs[aop->aopu.aop_pairId].name);
516 /* No information. */
522 _moveA(const char *moveFrom)
524 // Let the peephole optimiser take care of redundent loads
525 _emitMove(ACC_NAME, moveFrom);
535 getPairName (asmop * aop)
537 if (aop->type == AOP_REG)
539 switch (aop->aopu.aop_reg[0]->rIdx)
552 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
555 for (i = 0; i < NUM_PAIRS; i++)
557 if (strcmp(aop->aopu.aop_str[0], _pairs[i].l) == 0)
559 return _pairs[i].name;
563 wassertl (0, "Tried to get the pair name of something that isn't a pair");
568 getPairId (asmop * aop)
572 if (aop->type == AOP_REG)
574 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX) && (aop->aopu.aop_reg[1]->rIdx == B_IDX))
578 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX) && (aop->aopu.aop_reg[1]->rIdx == D_IDX))
582 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX) && (aop->aopu.aop_reg[1]->rIdx == H_IDX))
587 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
590 for (i = 0; i < NUM_PAIRS; i++)
592 if (!strcmp (aop->aopu.aop_str[0], _pairs[i].l) && !strcmp (aop->aopu.aop_str[1], _pairs[i].h))
602 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
606 return (getPairId (aop) != PAIR_INVALID);
609 /** Returns TRUE if the registers used in aop cannot be split into high
612 isUnsplitable (asmop * aop)
614 switch (getPairId (aop))
626 isPtrPair (asmop * aop)
628 PAIR_ID pairId = getPairId (aop);
641 spillPair (PAIR_ID pairId)
643 _G.pairs[pairId].last_type = AOP_INVALID;
644 _G.pairs[pairId].base = NULL;
647 /* Given a register name, spill the pair (if any) the register is part of */
649 spillPairReg (const char *regname)
651 if (strlen(regname)==1)
671 /** Push a register pair onto the stack */
673 genPairPush (asmop * aop)
675 emit2 ("push %s", getPairName (aop));
679 _push (PAIR_ID pairId)
681 emit2 ("push %s", _pairs[pairId].name);
682 _G.stack.pushed += 2;
686 _pop (PAIR_ID pairId)
688 emit2 ("pop %s", _pairs[pairId].name);
689 _G.stack.pushed -= 2;
694 genMovePairPair (PAIR_ID srcPair, PAIR_ID dstPair)
707 if (srcPair == PAIR_IX || srcPair == PAIR_IY)
714 emit2("ld %s,%s",_pairs[dstPair].l,_pairs[srcPair].l);
715 emit2("ld %s,%s",_pairs[dstPair].h,_pairs[srcPair].h);
718 wassertl (0, "Tried to move a nonphysical pair");
720 _G.pairs[dstPair].last_type = _G.pairs[srcPair].last_type;
721 _G.pairs[dstPair].base = _G.pairs[srcPair].base;
722 _G.pairs[dstPair].offset = _G.pairs[srcPair].offset;
726 /*-----------------------------------------------------------------*/
727 /* newAsmop - creates a new asmOp */
728 /*-----------------------------------------------------------------*/
730 newAsmop (short type)
734 aop = traceAlloc(&_G.trace.aops, Safe_alloc (sizeof (asmop)));
739 /*-----------------------------------------------------------------*/
740 /* aopForSym - for a true symbol */
741 /*-----------------------------------------------------------------*/
743 aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
750 wassert (sym->etype);
752 space = SPEC_OCLS (sym->etype);
754 /* if already has one */
760 /* Assign depending on the storage class */
761 if (sym->onStack || sym->iaccess)
763 /* The pointer that is used depends on how big the offset is.
764 Normally everything is AOP_STK, but for offsets of < -128 or
765 > 127 on the Z80 an extended stack pointer is used.
767 if (IS_Z80 && (_G.omitFramePtr || sym->stack < INT8MIN || sym->stack > (int)(INT8MAX-getSize (sym->type))))
769 emitDebug ("; AOP_EXSTK for %s", sym->rname);
770 sym->aop = aop = newAsmop (AOP_EXSTK);
774 emitDebug ("; AOP_STK for %s", sym->rname);
775 sym->aop = aop = newAsmop (AOP_STK);
778 aop->size = getSize (sym->type);
779 aop->aopu.aop_stk = sym->stack;
783 /* special case for a function */
784 if (IS_FUNC (sym->type))
786 sym->aop = aop = newAsmop (AOP_IMMD);
787 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup (sym->rname));
794 /* if it is in direct space */
795 if (IN_REGSP (space) && !requires_a)
797 sym->aop = aop = newAsmop (AOP_SFR);
798 aop->aopu.aop_dir = sym->rname;
799 aop->size = getSize (sym->type);
800 emitDebug ("; AOP_SFR for %s", sym->rname);
805 /* only remaining is far space */
806 /* in which case DPTR gets the address */
809 emitDebug ("; AOP_HL for %s", sym->rname);
810 sym->aop = aop = newAsmop (AOP_HL);
814 sym->aop = aop = newAsmop (AOP_IY);
816 aop->size = getSize (sym->type);
817 aop->aopu.aop_dir = sym->rname;
819 /* if it is in code space */
820 if (IN_CODESPACE (space))
826 /*-----------------------------------------------------------------*/
827 /* aopForRemat - rematerialzes an object */
828 /*-----------------------------------------------------------------*/
830 aopForRemat (symbol * sym)
833 iCode *ic = sym->rematiCode;
834 asmop *aop = newAsmop (AOP_IMMD);
838 /* if plus or minus print the right hand side */
839 if (ic->op == '+' || ic->op == '-')
841 /* PENDING: for re-target */
842 sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
845 ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
848 /* we reached the end */
849 sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
853 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
857 /*-----------------------------------------------------------------*/
858 /* regsInCommon - two operands have some registers in common */
859 /*-----------------------------------------------------------------*/
861 regsInCommon (operand * op1, operand * op2)
866 /* if they have registers in common */
867 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
870 sym1 = OP_SYMBOL (op1);
871 sym2 = OP_SYMBOL (op2);
873 if (sym1->nRegs == 0 || sym2->nRegs == 0)
876 for (i = 0; i < sym1->nRegs; i++)
882 for (j = 0; j < sym2->nRegs; j++)
887 if (sym2->regs[j] == sym1->regs[i])
895 /*-----------------------------------------------------------------*/
896 /* operandsEqu - equivalent */
897 /*-----------------------------------------------------------------*/
899 operandsEqu (operand * op1, operand * op2)
903 /* if they not symbols */
904 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
907 sym1 = OP_SYMBOL (op1);
908 sym2 = OP_SYMBOL (op2);
910 /* if both are itemps & one is spilt
911 and the other is not then false */
912 if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
913 sym1->isspilt != sym2->isspilt)
916 /* if they are the same */
920 if (strcmp (sym1->rname, sym2->rname) == 0)
924 /* if left is a tmp & right is not */
925 if (IS_ITEMP (op1) &&
928 (sym1->usl.spillLoc == sym2))
931 if (IS_ITEMP (op2) &&
935 (sym2->usl.spillLoc == sym1))
941 /*-----------------------------------------------------------------*/
942 /* sameRegs - two asmops have the same registers */
943 /*-----------------------------------------------------------------*/
945 sameRegs (asmop * aop1, asmop * aop2)
949 if (aop1->type == AOP_SFR ||
950 aop2->type == AOP_SFR)
956 if (aop1->type != AOP_REG ||
957 aop2->type != AOP_REG)
960 if (aop1->size != aop2->size)
963 for (i = 0; i < aop1->size; i++)
964 if (aop1->aopu.aop_reg[i] !=
965 aop2->aopu.aop_reg[i])
971 /*-----------------------------------------------------------------*/
972 /* aopOp - allocates an asmop for an operand : */
973 /*-----------------------------------------------------------------*/
975 aopOp (operand * op, iCode * ic, bool result, bool requires_a)
984 /* if this a literal */
985 if (IS_OP_LITERAL (op))
987 op->aop = aop = newAsmop (AOP_LIT);
988 aop->aopu.aop_lit = op->operand.valOperand;
989 aop->size = getSize (operandType (op));
993 /* if already has a asmop then continue */
999 /* if the underlying symbol has a aop */
1000 if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
1002 op->aop = OP_SYMBOL (op)->aop;
1006 /* if this is a true symbol */
1007 if (IS_TRUE_SYMOP (op))
1009 op->aop = aopForSym (ic, OP_SYMBOL (op), result, requires_a);
1013 /* this is a temporary : this has
1019 e) can be a return use only */
1021 sym = OP_SYMBOL (op);
1023 /* if the type is a conditional */
1024 if (sym->regType == REG_CND)
1026 aop = op->aop = sym->aop = newAsmop (AOP_CRY);
1031 /* if it is spilt then two situations
1033 b) has a spill location */
1034 if (sym->isspilt || sym->nRegs == 0)
1036 /* rematerialize it NOW */
1039 sym->aop = op->aop = aop =
1041 aop->size = getSize (sym->type);
1048 aop = op->aop = sym->aop = newAsmop (AOP_STR);
1049 aop->size = getSize (sym->type);
1050 for (i = 0; i < 4; i++)
1051 aop->aopu.aop_str[i] = _fReturn[i];
1057 if (sym->accuse == ACCUSE_A)
1059 aop = op->aop = sym->aop = newAsmop (AOP_ACC);
1060 aop->size = getSize (sym->type);
1061 wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
1063 aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
1065 else if (sym->accuse == ACCUSE_SCRATCH)
1067 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
1068 aop->size = getSize (sym->type);
1069 wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
1070 aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
1071 aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
1073 else if (sym->accuse == ACCUSE_IY)
1075 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
1076 aop->size = getSize (sym->type);
1077 wassertl(aop->size <= 2, "Internal error: Caching in IY, but too big to fit in IY");
1078 aop->aopu.aop_str[0] = _pairs[PAIR_IY].l;
1079 aop->aopu.aop_str[1] = _pairs[PAIR_IY].h;
1083 wassertl (0, "Marked as being allocated into A or HL but is actually in neither");
1088 if (sym->usl.spillLoc)
1090 if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1092 /* force a new aop if sizes differ */
1093 sym->usl.spillLoc->aop = NULL;
1095 sym->aop = op->aop = aop =
1096 aopForSym (ic, sym->usl.spillLoc, result, requires_a);
1097 aop->size = getSize (sym->type);
1101 /* else must be a dummy iTemp */
1102 sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1103 aop->size = getSize (sym->type);
1107 /* must be in a register */
1108 sym->aop = op->aop = aop = newAsmop (AOP_REG);
1109 aop->size = sym->nRegs;
1110 for (i = 0; i < sym->nRegs; i++)
1111 aop->aopu.aop_reg[i] = sym->regs[i];
1114 /*-----------------------------------------------------------------*/
1115 /* freeAsmop - free up the asmop given to an operand */
1116 /*----------------------------------------------------------------*/
1118 freeAsmop (operand * op, asmop * aaop, iCode * ic)
1135 if (aop->type == AOP_PAIRPTR && IS_Z80 && aop->aopu.aop_pairId == PAIR_DE)
1137 _pop (aop->aopu.aop_pairId);
1140 if (getPairId (aop) == PAIR_HL)
1142 spillPair (PAIR_HL);
1146 /* all other cases just dealloc */
1152 OP_SYMBOL (op)->aop = NULL;
1153 /* if the symbol has a spill */
1155 SPIL_LOC (op)->aop = NULL;
1162 isLitWord (asmop * aop)
1164 /* if (aop->size != 2)
1177 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
1179 /* depending on type */
1185 /* PENDING: for re-target */
1188 tsprintf (buffer, sizeof(buffer),
1189 "!hashedstr + %d", aop->aopu.aop_immd, offset);
1191 else if (offset == 0)
1193 tsprintf (buffer, sizeof(buffer),
1194 "%s", aop->aopu.aop_immd);
1198 tsprintf (buffer, sizeof(buffer),
1199 "%s + %d", aop->aopu.aop_immd, offset);
1201 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1205 value *val = aop->aopu.aop_lit;
1206 /* if it is a float then it gets tricky */
1207 /* otherwise it is fairly simple */
1208 if (!IS_FLOAT (val->type))
1210 unsigned long v = (unsigned long) floatFromVal (val);
1216 else if (offset == 0)
1222 wassertl(0, "Encountered an invalid offset while fetching a literal");
1226 tsprintf (buffer, sizeof(buffer), "!immedword", v);
1228 tsprintf (buffer, sizeof(buffer), "!constword", v);
1230 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1241 /* it is type float */
1242 fl.f = (float) floatFromVal (val);
1244 #ifdef WORDS_BIGENDIAN
1245 i = fl.c[3-offset] | (fl.c[3-offset-1]<<8);
1247 i = fl.c[offset] | (fl.c[offset+1]<<8);
1250 tsprintf (buffer, sizeof(buffer), "!immedword", i);
1252 tsprintf (buffer, sizeof(buffer), "!constword", i);
1254 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1263 aopGetWord (asmop * aop, int offset)
1265 return aopGetLitWordLong (aop, offset, TRUE);
1269 isPtr (const char *s)
1271 if (!strcmp (s, "hl"))
1273 if (!strcmp (s, "ix"))
1275 if (!strcmp (s, "iy"))
1281 adjustPair (const char *pair, int *pold, int new)
1287 emit2 ("inc %s", pair);
1292 emit2 ("dec %s", pair);
1300 spillPair (PAIR_HL);
1301 spillPair (PAIR_IY);
1305 requiresHL (asmop * aop)
1321 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1323 const char *l, *base;
1324 const char *pair = _pairs[pairId].name;
1325 l = aopGetLitWordLong (left, offset, FALSE);
1326 base = aopGetLitWordLong (left, 0, FALSE);
1327 wassert (l && pair && base);
1331 if (pairId == PAIR_HL || pairId == PAIR_IY)
1333 if (_G.pairs[pairId].last_type == left->type)
1335 if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1337 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1339 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1342 if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
1349 _G.pairs[pairId].last_type = left->type;
1350 _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1351 _G.pairs[pairId].offset = offset;
1353 /* Both a lit on the right and a true symbol on the left */
1354 emit2 ("ld %s,!hashedstr", pair, l);
1358 makeFreePairId (iCode *ic, bool *pisUsed)
1364 if (!bitVectBitValue (ic->rMask, B_IDX) && !bitVectBitValue(ic->rMask, C_IDX))
1368 else if (IS_Z80 && !bitVectBitValue (ic->rMask, D_IDX) && !bitVectBitValue(ic->rMask, E_IDX))
1386 fetchPairLong (PAIR_ID pairId, asmop * aop, iCode *ic, int offset)
1388 /* if this is remateriazable */
1389 if (isLitWord (aop)) {
1390 fetchLitPair (pairId, aop, offset);
1394 if (getPairId (aop) == pairId)
1398 /* we need to get it byte by byte */
1399 else if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1400 aopGet (aop, offset, FALSE);
1401 switch (aop->size - offset) {
1403 emit2 ("ld l,!*hl");
1404 emit2 ("ld h,!immedbyte", 0);
1407 // PENDING: Requires that you are only fetching two bytes.
1410 emit2 ("ld h,!*hl");
1414 wassertl (0, "Attempted to fetch too much data into HL");
1418 else if (IS_Z80 && aop->type == AOP_IY) {
1419 /* Instead of fetching relative to IY, just grab directly
1420 from the address IY refers to */
1421 char *l = aopGetLitWordLong (aop, offset, FALSE);
1423 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1425 if (aop->size < 2) {
1426 emit2("ld %s,!zero", _pairs[pairId].h);
1429 else if (pairId == PAIR_IY)
1433 emit2 ("push %s", _pairs[getPairId(aop)].name);
1439 PAIR_ID id = makeFreePairId (ic, &isUsed);
1442 /* Can't load into parts, so load into HL then exchange. */
1443 emit2 ("ld %s,%s", _pairs[id].l, aopGet (aop, offset, FALSE));
1444 emit2 ("ld %s,%s", _pairs[id].h, aopGet (aop, offset + 1, FALSE));
1445 emit2 ("push %s", _pairs[id].name);
1451 else if (isUnsplitable(aop))
1453 emit2("push %s", _pairs[getPairId(aop)].name);
1454 emit2("pop %s", _pairs[pairId].name);
1458 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1459 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1461 /* PENDING: check? */
1462 if (pairId == PAIR_HL)
1463 spillPair (PAIR_HL);
1468 fetchPair (PAIR_ID pairId, asmop * aop)
1470 fetchPairLong (pairId, aop, NULL, 0);
1474 fetchHL (asmop * aop)
1476 fetchPair (PAIR_HL, aop);
1480 setupPairFromSP (PAIR_ID id, int offset)
1482 wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
1484 if (offset < INT8MIN || offset > INT8MAX)
1486 emit2 ("ld hl,!immedword", offset);
1487 emit2 ("add hl,sp");
1491 emit2 ("!ldahlsp", offset);
1496 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1501 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
1502 fetchLitPair (pairId, aop, 0);
1506 wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
1508 fetchLitPair (pairId, aop, offset);
1509 _G.pairs[pairId].offset = offset;
1513 wassertl (IS_Z80, "Only the Z80 has an extended stack");
1514 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
1517 int offset = aop->aopu.aop_stk + _G.stack.offset;
1519 if (_G.pairs[pairId].last_type == aop->type &&
1520 _G.pairs[pairId].offset == offset)
1526 /* PENDING: Do this better. */
1527 sprintf (buffer, "%d", offset + _G.stack.pushed);
1528 emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
1529 emit2 ("add %s,sp", _pairs[pairId].name);
1530 _G.pairs[pairId].last_type = aop->type;
1531 _G.pairs[pairId].offset = offset;
1538 /* Doesnt include _G.stack.pushed */
1539 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1541 if (aop->aopu.aop_stk > 0)
1543 abso += _G.stack.param_offset;
1545 assert (pairId == PAIR_HL);
1546 /* In some cases we can still inc or dec hl */
1547 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1549 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1553 setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
1555 _G.pairs[pairId].offset = abso;
1560 if (pairId != aop->aopu.aop_pairId)
1561 genMovePairPair(aop->aopu.aop_pairId, pairId);
1562 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
1568 _G.pairs[pairId].last_type = aop->type;
1574 emit2 ("!tlabeldef", key);
1578 /*-----------------------------------------------------------------*/
1579 /* aopGet - for fetching value of the aop */
1580 /*-----------------------------------------------------------------*/
1582 aopGet (asmop * aop, int offset, bool bit16)
1584 // char *s = buffer;
1586 /* offset is greater than size then zero */
1587 /* PENDING: this seems a bit screwed in some pointer cases. */
1588 if (offset > (aop->size - 1) &&
1589 aop->type != AOP_LIT)
1591 tsprintf (buffer, sizeof(buffer), "!zero");
1592 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1595 /* depending on type */
1599 tsprintf (buffer, sizeof(buffer), "!zero");
1600 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1603 /* PENDING: re-target */
1605 tsprintf (buffer, sizeof(buffer), "!immedwords", aop->aopu.aop_immd);
1610 tsprintf (buffer, sizeof(buffer), "!bankimmeds", aop->aopu.aop_immd);
1613 tsprintf (buffer, sizeof(buffer), "!msbimmeds", aop->aopu.aop_immd);
1616 tsprintf (buffer, sizeof(buffer), "!lsbimmeds", aop->aopu.aop_immd);
1619 wassertl (0, "Fetching from beyond the limits of an immediate value.");
1622 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1626 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1627 SNPRINTF (buffer, sizeof(buffer), "a");
1629 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1633 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1634 SNPRINTF (buffer, sizeof(buffer), "a");
1636 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1639 return aop->aopu.aop_reg[offset]->name;
1643 setupPair (PAIR_HL, aop, offset);
1644 tsprintf (buffer, sizeof(buffer), "!*hl");
1646 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
1650 setupPair (PAIR_IY, aop, offset);
1651 tsprintf (buffer, sizeof(buffer), "!*iyx", offset);
1653 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1657 setupPair (PAIR_IY, aop, offset);
1658 tsprintf (buffer, sizeof(buffer), "!*iyx", offset, offset);
1660 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1665 setupPair (PAIR_HL, aop, offset);
1666 tsprintf (buffer, sizeof(buffer), "!*hl");
1670 if (aop->aopu.aop_stk >= 0)
1671 offset += _G.stack.param_offset;
1672 tsprintf (buffer, sizeof(buffer),
1673 "!*ixx", aop->aopu.aop_stk + offset);
1676 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1679 wassertl (0, "Tried to fetch from a bit variable");
1688 tsprintf(buffer, sizeof(buffer), "!zero");
1689 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1693 wassert (offset < 2);
1694 return aop->aopu.aop_str[offset];
1697 return aopLiteral (aop->aopu.aop_lit, offset);
1701 unsigned long v = aop->aopu.aop_simplelit;
1704 tsprintf (buffer, sizeof(buffer),
1705 "!immedbyte", (unsigned int) v & 0xff);
1707 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1711 return aop->aopu.aop_str[offset];
1714 setupPair (aop->aopu.aop_pairId, aop, offset);
1715 if (aop->aopu.aop_pairId==PAIR_IX)
1716 SNPRINTF (buffer, sizeof(buffer),
1718 else if (aop->aopu.aop_pairId==PAIR_IY)
1719 SNPRINTF (buffer, sizeof(buffer),
1722 SNPRINTF (buffer, sizeof(buffer),
1723 "(%s)", _pairs[aop->aopu.aop_pairId].name);
1725 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1730 wassertl (0, "aopget got unsupported aop->type");
1735 isRegString (const char *s)
1737 if (!strcmp (s, "b") ||
1749 isConstant (const char *s)
1751 /* This is a bit of a hack... */
1752 return (*s == '#' || *s == '$');
1756 canAssignToPtr (const char *s)
1758 if (isRegString (s))
1765 /*-----------------------------------------------------------------*/
1766 /* aopPut - puts a string for a aop */
1767 /*-----------------------------------------------------------------*/
1769 aopPut (asmop * aop, const char *s, int offset)
1773 if (aop->size && offset > (aop->size - 1))
1775 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1776 "aopPut got offset > aop->size");
1781 tsprintf(buffer2, sizeof(buffer2), s);
1784 /* will assign value to value */
1785 /* depending on where it is ofcourse */
1789 _moveA (s); /* in case s is volatile */
1795 if (strcmp (s, "a"))
1796 emit2 ("ld a,%s", s);
1797 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1802 if (strcmp (s, "a"))
1803 emit2 ("ld a,%s", s);
1804 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1808 if (!strcmp (s, "!*hl"))
1809 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1812 aop->aopu.aop_reg[offset]->name, s);
1813 spillPairReg(aop->aopu.aop_reg[offset]->name);
1818 if (!canAssignToPtr (s))
1820 emit2 ("ld a,%s", s);
1821 setupPair (PAIR_IY, aop, offset);
1822 emit2 ("ld !*iyx,a", offset);
1826 setupPair (PAIR_IY, aop, offset);
1827 emit2 ("ld !*iyx,%s", offset, s);
1833 /* PENDING: for re-target */
1834 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1836 emit2 ("ld a,!*hl");
1839 setupPair (PAIR_HL, aop, offset);
1841 emit2 ("ld !*hl,%s", s);
1846 if (!canAssignToPtr (s))
1848 emit2 ("ld a,%s", s);
1849 setupPair (PAIR_IY, aop, offset);
1850 emit2 ("ld !*iyx,a", offset);
1854 setupPair (PAIR_IY, aop, offset);
1855 emit2 ("ld !*iyx,%s", offset, s);
1862 /* PENDING: re-target */
1863 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1865 emit2 ("ld a,!*hl");
1868 setupPair (PAIR_HL, aop, offset);
1869 if (!canAssignToPtr (s))
1871 emit2 ("ld a,%s", s);
1872 emit2 ("ld !*hl,a");
1875 emit2 ("ld !*hl,%s", s);
1879 if (aop->aopu.aop_stk >= 0)
1880 offset += _G.stack.param_offset;
1881 if (!canAssignToPtr (s))
1883 emit2 ("ld a,%s", s);
1884 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
1888 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
1894 /* if bit variable */
1895 if (!aop->aopu.aop_dir)
1897 emit2 ("ld a,!zero");
1902 /* In bit space but not in C - cant happen */
1903 wassertl (0, "Tried to write into a bit variable");
1909 if (strcmp (aop->aopu.aop_str[offset], s))
1911 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1913 spillPairReg(aop->aopu.aop_str[offset]);
1918 if (!offset && (strcmp (s, "acc") == 0))
1922 wassertl (0, "Tried to access past the end of A");
1926 if (strcmp (aop->aopu.aop_str[offset], s))
1928 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1929 spillPairReg(aop->aopu.aop_str[offset]);
1935 wassert (offset < 2);
1936 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1937 spillPairReg(aop->aopu.aop_str[offset]);
1941 setupPair (aop->aopu.aop_pairId, aop, offset);
1942 if (aop->aopu.aop_pairId==PAIR_IX)
1943 emit2 ("ld !*ixx,%s", 0, s);
1944 else if (aop->aopu.aop_pairId==PAIR_IY)
1945 emit2 ("ld !*ixy,%s", 0, s);
1947 emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
1951 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1952 "aopPut got unsupported aop->type");
1957 #define AOP(op) op->aop
1958 #define AOP_TYPE(op) AOP(op)->type
1959 #define AOP_SIZE(op) AOP(op)->size
1960 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
1963 commitPair (asmop * aop, PAIR_ID id)
1965 /* PENDING: Verify this. */
1966 if (id == PAIR_HL && requiresHL (aop) && IS_GB)
1970 aopPut (aop, "a", 0);
1971 aopPut (aop, "d", 1);
1976 if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
1978 char *l = aopGetLitWordLong (aop, 0, FALSE);
1981 emit2 ("ld (%s),%s", l, _pairs[id].name);
1985 aopPut (aop, _pairs[id].l, 0);
1986 aopPut (aop, _pairs[id].h, 1);
1991 /*-----------------------------------------------------------------*/
1992 /* getDataSize - get the operand data size */
1993 /*-----------------------------------------------------------------*/
1995 getDataSize (operand * op)
1998 size = AOP_SIZE (op);
2002 wassertl (0, "Somehow got a three byte data pointer");
2007 /*-----------------------------------------------------------------*/
2008 /* movLeft2Result - move byte from left to result */
2009 /*-----------------------------------------------------------------*/
2011 movLeft2Result (operand * left, int offl,
2012 operand * result, int offr, int sign)
2016 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
2018 l = aopGet (AOP (left), offl, FALSE);
2022 aopPut (AOP (result), l, offr);
2026 if (getDataSize (left) == offl + 1)
2028 emit2 ("ld a,%s", l);
2029 aopPut (AOP (result), "a", offr);
2036 movLeft2ResultLong (operand * left, int offl,
2037 operand * result, int offr, int sign,
2042 movLeft2Result (left, offl, result, offr, sign);
2046 wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
2047 wassertl (size == 2, "Only implemented for two bytes or one");
2049 if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
2051 emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
2052 emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
2054 spillPair (PAIR_HL);
2056 else if ( getPairId ( AOP (result)) == PAIR_IY)
2058 PAIR_ID id = getPairId (AOP (left));
2059 if (id != PAIR_INVALID)
2061 emit2("push %s", _pairs[id].name);
2072 movLeft2Result (left, offl, result, offr, sign);
2073 movLeft2Result (left, offl+1, result, offr+1, sign);
2078 /** Put Acc into a register set
2081 outAcc (operand * result)
2084 size = getDataSize (result);
2087 aopPut (AOP (result), "a", 0);
2090 /* unsigned or positive */
2093 aopPut (AOP (result), "!zero", offset++);
2098 /** Take the value in carry and put it into a register
2101 outBitCLong (operand * result, bool swap_sense)
2103 /* if the result is bit */
2104 if (AOP_TYPE (result) == AOP_CRY)
2106 wassertl (0, "Tried to write carry to a bit");
2110 emit2 ("ld a,!zero");
2113 emit2 ("xor a,!immedbyte", 1);
2119 outBitC (operand * result)
2121 outBitCLong (result, FALSE);
2124 /*-----------------------------------------------------------------*/
2125 /* toBoolean - emit code for orl a,operator(sizeop) */
2126 /*-----------------------------------------------------------------*/
2128 _toBoolean (operand * oper)
2130 int size = AOP_SIZE (oper);
2134 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
2137 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
2141 if (AOP (oper)->type != AOP_ACC)
2144 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
2150 /*-----------------------------------------------------------------*/
2151 /* genNot - generate code for ! operation */
2152 /*-----------------------------------------------------------------*/
2157 /* assign asmOps to operand & result */
2158 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
2159 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2161 /* if in bit space then a special case */
2162 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2164 wassertl (0, "Tried to negate a bit");
2167 _toBoolean (IC_LEFT (ic));
2172 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
2173 emit2 ("sub a,!one");
2174 outBitC (IC_RESULT (ic));
2176 /* release the aops */
2177 freeAsmop (IC_LEFT (ic), NULL, ic);
2178 freeAsmop (IC_RESULT (ic), NULL, ic);
2181 /*-----------------------------------------------------------------*/
2182 /* genCpl - generate code for complement */
2183 /*-----------------------------------------------------------------*/
2191 /* assign asmOps to operand & result */
2192 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2193 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2195 /* if both are in bit space then
2197 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2198 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2200 wassertl (0, "Left and the result are in bit space");
2203 size = AOP_SIZE (IC_RESULT (ic));
2206 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2209 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2212 /* release the aops */
2213 freeAsmop (IC_LEFT (ic), NULL, ic);
2214 freeAsmop (IC_RESULT (ic), NULL, ic);
2218 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
2225 store de into result
2230 store de into result
2232 const char *first = isAdd ? "add" : "sub";
2233 const char *later = isAdd ? "adc" : "sbc";
2235 wassertl (IS_GB, "Code is only relevent to the gbz80");
2236 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
2238 fetchPair (PAIR_DE, left);
2241 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
2244 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2247 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2248 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2250 fetchPairLong (PAIR_DE, left, NULL, MSB24);
2251 aopGet (right, MSB24, FALSE);
2255 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2258 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2260 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2261 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2265 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2267 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2270 /*-----------------------------------------------------------------*/
2271 /* genUminusFloat - unary minus for floating points */
2272 /*-----------------------------------------------------------------*/
2274 genUminusFloat (operand * op, operand * result)
2276 int size, offset = 0;
2278 emitDebug("; genUminusFloat");
2280 /* for this we just need to flip the
2281 first it then copy the rest in place */
2282 size = AOP_SIZE (op) - 1;
2284 _moveA(aopGet (AOP (op), MSB32, FALSE));
2286 emit2("xor a,!immedbyte", 0x80);
2287 aopPut (AOP (result), "a", MSB32);
2291 aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2296 /*-----------------------------------------------------------------*/
2297 /* genUminus - unary minus code generation */
2298 /*-----------------------------------------------------------------*/
2300 genUminus (iCode * ic)
2303 sym_link *optype, *rtype;
2306 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2307 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2309 /* if both in bit space then special
2311 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2312 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2314 wassertl (0, "Left and right are in bit space");
2318 optype = operandType (IC_LEFT (ic));
2319 rtype = operandType (IC_RESULT (ic));
2321 /* if float then do float stuff */
2322 if (IS_FLOAT (optype))
2324 genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2328 /* otherwise subtract from zero */
2329 size = AOP_SIZE (IC_LEFT (ic));
2331 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2333 /* Create a new asmop with value zero */
2334 asmop *azero = newAsmop (AOP_SIMPLELIT);
2335 azero->aopu.aop_simplelit = 0;
2337 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2345 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2346 emit2 ("ld a,!zero");
2347 emit2 ("sbc a,%s", l);
2348 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2351 /* if any remaining bytes in the result */
2352 /* we just need to propagate the sign */
2353 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2358 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2362 /* release the aops */
2363 freeAsmop (IC_LEFT (ic), NULL, ic);
2364 freeAsmop (IC_RESULT (ic), NULL, ic);
2367 /*-----------------------------------------------------------------*/
2368 /* assignResultValue - */
2369 /*-----------------------------------------------------------------*/
2371 assignResultValue (operand * oper)
2373 int size = AOP_SIZE (oper);
2376 wassertl (size <= 4, "Got a result that is bigger than four bytes");
2377 topInA = requiresHL (AOP (oper));
2379 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2381 /* We do it the hard way here. */
2383 aopPut (AOP (oper), _fReturn[0], 0);
2384 aopPut (AOP (oper), _fReturn[1], 1);
2386 aopPut (AOP (oper), _fReturn[0], 2);
2387 aopPut (AOP (oper), _fReturn[1], 3);
2393 aopPut (AOP (oper), _fReturn[size], size);
2398 /** Simple restore that doesn't take into account what is used in the
2402 _restoreRegsAfterCall(void)
2404 if (_G.stack.pushedDE)
2407 _G.stack.pushedDE = FALSE;
2409 if (_G.stack.pushedBC)
2412 _G.stack.pushedBC = FALSE;
2414 _G.saves.saved = FALSE;
2418 _saveRegsForCall(iCode *ic, int sendSetSize)
2421 o Stack parameters are pushed before this function enters
2422 o DE and BC may be used in this function.
2423 o HL and DE may be used to return the result.
2424 o HL and DE may be used to send variables.
2425 o DE and BC may be used to store the result value.
2426 o HL may be used in computing the sent value of DE
2427 o The iPushes for other parameters occur before any addSets
2429 Logic: (to be run inside the first iPush or if none, before sending)
2430 o Compute if DE and/or BC are in use over the call
2431 o Compute if DE is used in the send set
2432 o Compute if DE and/or BC are used to hold the result value
2433 o If (DE is used, or in the send set) and is not used in the result, push.
2434 o If BC is used and is not in the result, push
2436 o If DE is used in the send set, fetch
2437 o If HL is used in the send set, fetch
2441 if (_G.saves.saved == FALSE) {
2442 bool deInUse, bcInUse;
2444 bool bcInRet = FALSE, deInRet = FALSE;
2447 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask),
2448 z80_rUmaskForOp (IC_RESULT(ic)));
2450 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2451 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2453 deSending = (sendSetSize > 1);
2455 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2457 if (bcInUse && bcInRet == FALSE) {
2459 _G.stack.pushedBC = TRUE;
2461 if (deInUse && deInRet == FALSE) {
2463 _G.stack.pushedDE = TRUE;
2466 _G.saves.saved = TRUE;
2469 /* Already saved. */
2473 /*-----------------------------------------------------------------*/
2474 /* genIpush - genrate code for pushing this gets a little complex */
2475 /*-----------------------------------------------------------------*/
2477 genIpush (iCode * ic)
2479 int size, offset = 0;
2482 /* if this is not a parm push : ie. it is spill push
2483 and spill push is always done on the local stack */
2486 wassertl(0, "Encountered an unsupported spill push.");
2490 if (_G.saves.saved == FALSE) {
2491 /* Caller saves, and this is the first iPush. */
2492 /* Scan ahead until we find the function that we are pushing parameters to.
2493 Count the number of addSets on the way to figure out what registers
2494 are used in the send set.
2497 iCode *walk = ic->next;
2500 if (walk->op == SEND) {
2503 else if (walk->op == CALL || walk->op == PCALL) {
2512 _saveRegsForCall(walk, nAddSets);
2515 /* Already saved by another iPush. */
2518 /* then do the push */
2519 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2521 size = AOP_SIZE (IC_LEFT (ic));
2523 if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2525 _G.stack.pushed += 2;
2526 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2532 fetchHL (AOP (IC_LEFT (ic)));
2534 spillPair (PAIR_HL);
2535 _G.stack.pushed += 2;
2540 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
2542 spillPair (PAIR_HL);
2543 _G.stack.pushed += 2;
2544 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
2546 spillPair (PAIR_HL);
2547 _G.stack.pushed += 2;
2553 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2555 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2557 emit2 ("ld a,(%s)", l);
2561 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2562 emit2 ("ld a,%s", l);
2570 freeAsmop (IC_LEFT (ic), NULL, ic);
2573 /*-----------------------------------------------------------------*/
2574 /* genIpop - recover the registers: can happen only for spilling */
2575 /*-----------------------------------------------------------------*/
2577 genIpop (iCode * ic)
2582 /* if the temp was not pushed then */
2583 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2586 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2587 size = AOP_SIZE (IC_LEFT (ic));
2588 offset = (size - 1);
2589 if (isPair (AOP (IC_LEFT (ic))))
2591 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2599 spillPair (PAIR_HL);
2600 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2604 freeAsmop (IC_LEFT (ic), NULL, ic);
2607 /* This is quite unfortunate */
2609 setArea (int inHome)
2612 static int lastArea = 0;
2614 if (_G.in_home != inHome) {
2616 const char *sz = port->mem.code_name;
2617 port->mem.code_name = "HOME";
2618 emit2("!area", CODE_NAME);
2619 port->mem.code_name = sz;
2622 emit2("!area", CODE_NAME); */
2623 _G.in_home = inHome;
2634 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2638 symbol *sym = OP_SYMBOL (op);
2640 if (sym->isspilt || sym->nRegs == 0)
2643 aopOp (op, ic, FALSE, FALSE);
2646 if (aop->type == AOP_REG)
2649 for (i = 0; i < aop->size; i++)
2651 if (pairId == PAIR_DE)
2653 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2654 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2656 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2659 else if (pairId == PAIR_BC)
2661 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2662 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2664 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2674 freeAsmop (IC_LEFT (ic), NULL, ic);
2678 /** Emit the code for a call statement
2681 emitCall (iCode * ic, bool ispcall)
2683 bool bInRet, cInRet, dInRet, eInRet;
2684 sym_link *dtype = operandType (IC_LEFT (ic));
2686 /* if caller saves & we have not saved then */
2692 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2694 /* if send set is not empty then assign */
2699 int nSend = elementsInSet(_G.sendSet);
2700 bool swapped = FALSE;
2702 int _z80_sendOrder[] = {
2707 /* Check if the parameters are swapped. If so route through hl instead. */
2708 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2710 sic = setFirstItem(_G.sendSet);
2711 sic = setNextItem(_G.sendSet);
2713 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2714 /* The second send value is loaded from one the one that holds the first
2715 send, i.e. it is overwritten. */
2716 /* Cache the first in HL, and load the second from HL instead. */
2717 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2718 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2724 for (sic = setFirstItem (_G.sendSet); sic;
2725 sic = setNextItem (_G.sendSet))
2728 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2730 size = AOP_SIZE (IC_LEFT (sic));
2731 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2732 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2734 // PENDING: Mild hack
2735 if (swapped == TRUE && send == 1) {
2737 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2740 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2742 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2745 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2749 freeAsmop (IC_LEFT (sic), NULL, sic);
2756 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2758 werror (W_INDIR_BANKED);
2760 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2762 if (isLitWord (AOP (IC_LEFT (ic))))
2764 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2768 symbol *rlbl = newiTempLabel (NULL);
2769 spillPair (PAIR_HL);
2770 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2772 _G.stack.pushed += 2;
2774 fetchHL (AOP (IC_LEFT (ic)));
2776 emit2 ("!tlabeldef", (rlbl->key + 100));
2777 _G.stack.pushed -= 2;
2779 freeAsmop (IC_LEFT (ic), NULL, ic);
2783 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2784 OP_SYMBOL (IC_LEFT (ic))->rname :
2785 OP_SYMBOL (IC_LEFT (ic))->name;
2786 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2788 emit2 ("call banked_call");
2789 emit2 ("!dws", name);
2790 emit2 ("!dw !bankimmeds", name);
2795 emit2 ("call %s", name);
2800 /* Mark the regsiters as restored. */
2801 _G.saves.saved = FALSE;
2803 /* if we need assign a result value */
2804 if ((IS_ITEMP (IC_RESULT (ic)) &&
2805 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2806 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2807 IS_TRUE_SYMOP (IC_RESULT (ic)))
2810 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2812 assignResultValue (IC_RESULT (ic));
2814 freeAsmop (IC_RESULT (ic), NULL, ic);
2817 /* adjust the stack for parameters if required */
2820 int i = ic->parmBytes;
2822 _G.stack.pushed -= i;
2825 emit2 ("!ldaspsp", i);
2832 emit2 ("ld iy,!immedword", i);
2833 emit2 ("add iy,sp");
2854 bitVect *result = z80_rUmaskForOp (IC_RESULT (ic));
2855 bInRet = bitVectBitValue(result, B_IDX);
2856 cInRet = bitVectBitValue(result, C_IDX);
2857 dInRet = bitVectBitValue(result, D_IDX);
2858 eInRet = bitVectBitValue(result, E_IDX);
2868 if (_G.stack.pushedDE)
2870 if (dInRet && eInRet)
2872 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
2876 /* Only restore E */
2883 /* Only restore D */
2891 _G.stack.pushedDE = FALSE;
2894 if (_G.stack.pushedBC)
2896 if (bInRet && cInRet)
2898 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
2902 /* Only restore C */
2909 /* Only restore B */
2917 _G.stack.pushedBC = FALSE;
2921 /*-----------------------------------------------------------------*/
2922 /* genCall - generates a call statement */
2923 /*-----------------------------------------------------------------*/
2925 genCall (iCode * ic)
2927 emitCall (ic, FALSE);
2930 /*-----------------------------------------------------------------*/
2931 /* genPcall - generates a call by pointer statement */
2932 /*-----------------------------------------------------------------*/
2934 genPcall (iCode * ic)
2936 emitCall (ic, TRUE);
2939 /*-----------------------------------------------------------------*/
2940 /* resultRemat - result is rematerializable */
2941 /*-----------------------------------------------------------------*/
2943 resultRemat (iCode * ic)
2945 if (SKIP_IC (ic) || ic->op == IFX)
2948 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2950 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2951 if (sym->remat && !POINTER_SET (ic))
2958 extern set *publics;
2960 /*-----------------------------------------------------------------*/
2961 /* genFunction - generated code for function entry */
2962 /*-----------------------------------------------------------------*/
2964 genFunction (iCode * ic)
2968 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2971 bool bcInUse = FALSE;
2972 bool deInUse = FALSE;
2974 setArea (IFFUNC_NONBANKED (sym->type));
2976 /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
2979 _G.receiveOffset = 0;
2981 /* Record the last function name for debugging. */
2982 _G.lastFunctionName = sym->rname;
2984 /* Create the function header */
2985 emit2 ("!functionheader", sym->name);
2986 sprintf (buffer, "%s_start", sym->rname);
2987 emit2 ("!labeldef", buffer);
2988 emit2 ("!functionlabeldef", sym->rname);
2990 if (options.profile)
2992 emit2 ("!profileenter");
2995 ftype = operandType (IC_LEFT (ic));
2997 /* if critical function then turn interrupts off */
2998 if (IFFUNC_ISCRITICAL (ftype))
3001 /* if this is an interrupt service routine then save all potentially used registers. */
3002 if (IFFUNC_ISISR (sym->type))
3007 /* PENDING: callee-save etc */
3009 _G.stack.param_offset = 0;
3011 if (z80_opts.calleeSavesBC)
3016 /* Detect which registers are used. */
3017 if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
3020 for (i = 0; i < sym->regsUsed->size; i++)
3022 if (bitVectBitValue (sym->regsUsed, i))
3036 /* Other systems use DE as a temporary. */
3047 _G.stack.param_offset += 2;
3050 _G.calleeSaves.pushedBC = bcInUse;
3055 _G.stack.param_offset += 2;
3058 _G.calleeSaves.pushedDE = deInUse;
3060 /* adjust the stack for the function */
3061 _G.stack.last = sym->stack;
3064 for (sym = setFirstItem (istack->syms); sym;
3065 sym = setNextItem (istack->syms))
3067 if (sym->_isparm && !IS_REGPARM (sym->etype))
3073 sym = OP_SYMBOL (IC_LEFT (ic));
3075 _G.omitFramePtr = options.ommitFramePtr;
3076 if (IS_Z80 && !stackParm && !sym->stack)
3078 /* When the conflicts between AOP_EXSTK && AOP_HLREG are fixed, */
3079 /* the above !sym->stack condition can be removed. -- EEP */
3081 emit2 ("!ldaspsp", -sym->stack);
3082 _G.omitFramePtr = TRUE;
3084 else if (sym->stack && IS_GB && sym->stack > -INT8MIN)
3085 emit2 ("!enterxl", sym->stack);
3086 else if (sym->stack)
3087 emit2 ("!enterx", sym->stack);
3090 _G.stack.offset = sym->stack;
3093 /*-----------------------------------------------------------------*/
3094 /* genEndFunction - generates epilogue for functions */
3095 /*-----------------------------------------------------------------*/
3097 genEndFunction (iCode * ic)
3099 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3101 if (IFFUNC_ISISR (sym->type))
3103 wassertl (0, "Tried to close an interrupt support function");
3107 if (IFFUNC_ISCRITICAL (sym->type))
3110 /* PENDING: calleeSave */
3112 if (IS_Z80 && _G.omitFramePtr)
3114 if (_G.stack.offset)
3115 emit2 ("!ldaspsp", _G.stack.offset);
3117 else if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
3119 emit2 ("!leavexl", _G.stack.offset);
3121 else if (_G.stack.offset)
3123 emit2 ("!leavex", _G.stack.offset);
3130 if (_G.calleeSaves.pushedDE)
3133 _G.calleeSaves.pushedDE = FALSE;
3136 if (_G.calleeSaves.pushedBC)
3139 _G.calleeSaves.pushedBC = FALSE;
3142 if (options.profile)
3144 emit2 ("!profileexit");
3148 if (options.debug && currFunc)
3150 _G.lines.isDebug = 1;
3151 sprintf (buffer, "C$%s$%d$%d$%d",
3152 FileBaseName (ic->filename), currFunc->lastLine,
3153 ic->level, ic->block);
3154 emit2 ("!labeldef", buffer);
3155 if (IS_STATIC (currFunc->etype))
3156 sprintf (buffer, "XF%s$%s$0$0", moduleName, currFunc->name);
3158 sprintf (buffer, "XG$%s$0$0", currFunc->name);
3159 emit2 ("!labeldef", buffer);
3160 _G.lines.isDebug = 0;
3163 /* Both banked and non-banked just ret */
3166 sprintf (buffer, "%s_end", sym->rname);
3167 emit2 ("!labeldef", buffer);
3169 _G.flushStatics = 1;
3170 _G.stack.pushed = 0;
3171 _G.stack.offset = 0;
3174 /*-----------------------------------------------------------------*/
3175 /* genRet - generate code for return statement */
3176 /*-----------------------------------------------------------------*/
3181 /* Errk. This is a hack until I can figure out how
3182 to cause dehl to spill on a call */
3183 int size, offset = 0;
3185 /* if we have no return value then
3186 just generate the "ret" */
3190 /* we have something to return then
3191 move the return value into place */
3192 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3193 size = AOP_SIZE (IC_LEFT (ic));
3195 aopDump("IC_LEFT", AOP(IC_LEFT(ic)));
3198 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3202 emit2 ("ld de,%s", l);
3206 emit2 ("ld hl,%s", l);
3212 fetchPair(IS_GB ? PAIR_DE : PAIR_HL, AOP (IC_LEFT (ic)));
3216 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3218 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3219 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3225 l = aopGet (AOP (IC_LEFT (ic)), offset,
3227 if (strcmp (_fReturn[offset], l))
3228 emit2 ("ld %s,%s", _fReturn[offset], l);
3233 freeAsmop (IC_LEFT (ic), NULL, ic);
3236 /* generate a jump to the return label
3237 if the next is not the return statement */
3238 if (!(ic->next && ic->next->op == LABEL &&
3239 IC_LABEL (ic->next) == returnLabel))
3241 emit2 ("jp !tlabel", returnLabel->key + 100);
3244 /*-----------------------------------------------------------------*/
3245 /* genLabel - generates a label */
3246 /*-----------------------------------------------------------------*/
3248 genLabel (iCode * ic)
3250 /* special case never generate */
3251 if (IC_LABEL (ic) == entryLabel)
3254 emitLabel (IC_LABEL (ic)->key + 100);
3257 /*-----------------------------------------------------------------*/
3258 /* genGoto - generates a ljmp */
3259 /*-----------------------------------------------------------------*/
3261 genGoto (iCode * ic)
3263 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3266 /*-----------------------------------------------------------------*/
3267 /* genPlusIncr :- does addition with increment if possible */
3268 /*-----------------------------------------------------------------*/
3270 genPlusIncr (iCode * ic)
3272 unsigned int icount;
3273 unsigned int size = getDataSize (IC_RESULT (ic));
3274 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3276 /* will try to generate an increment */
3277 /* if the right side is not a literal
3279 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3282 emitDebug ("; genPlusIncr");
3284 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3286 /* If result is a pair */
3287 if (resultId != PAIR_INVALID)
3289 if (isLitWord (AOP (IC_LEFT (ic))))
3291 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3294 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3296 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3298 PAIR_ID freep = getFreePairId (ic);
3299 if (freep != PAIR_INVALID)
3301 fetchPair (freep, AOP (IC_RIGHT (ic)));
3302 emit2 ("add hl,%s", _pairs[freep].name);
3308 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3309 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3316 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3320 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3324 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3329 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3331 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3332 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3336 /* if the literal value of the right hand side
3337 is greater than 4 then it is not worth it */
3341 /* if increment 16 bits in register */
3342 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3348 symbol *tlbl = NULL;
3349 tlbl = newiTempLabel (NULL);
3352 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3355 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3358 emitLabel (tlbl->key + 100);
3362 /* if the sizes are greater than 1 then we cannot */
3363 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3364 AOP_SIZE (IC_LEFT (ic)) > 1)
3367 /* If the result is in a register then we can load then increment.
3369 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3371 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3374 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3379 /* we can if the aops of the left & result match or
3380 if they are in registers and the registers are the
3382 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3386 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3394 /*-----------------------------------------------------------------*/
3395 /* outBitAcc - output a bit in acc */
3396 /*-----------------------------------------------------------------*/
3398 outBitAcc (operand * result)
3400 symbol *tlbl = newiTempLabel (NULL);
3401 /* if the result is a bit */
3402 if (AOP_TYPE (result) == AOP_CRY)
3404 wassertl (0, "Tried to write A into a bit");
3408 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3409 emit2 ("ld a,!one");
3410 emitLabel (tlbl->key + 100);
3416 couldDestroyCarry (asmop *aop)
3420 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3429 shiftIntoPair (int idx, asmop *aop)
3431 PAIR_ID id = PAIR_INVALID;
3433 wassertl (IS_Z80, "Only implemented for the Z80");
3434 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3446 wassertl (0, "Internal error - hit default case");
3449 emitDebug ("; Shift into pair idx %u", idx);
3453 setupPair (PAIR_HL, aop, 0);
3457 setupPair (PAIR_IY, aop, 0);
3459 emit2 ("pop %s", _pairs[id].name);
3462 aop->type = AOP_PAIRPTR;
3463 aop->aopu.aop_pairId = id;
3464 _G.pairs[id].offset = 0;
3465 _G.pairs[id].last_type = aop->type;
3469 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
3471 wassert (left && right);
3475 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3477 shiftIntoPair (0, right);
3478 /* check result again, in case right == result */
3479 if (couldDestroyCarry (result))
3480 shiftIntoPair (1, result);
3482 else if (couldDestroyCarry (right))
3484 shiftIntoPair (0, right);
3486 else if (couldDestroyCarry (result))
3488 shiftIntoPair (0, result);
3497 /*-----------------------------------------------------------------*/
3498 /* genPlus - generates code for addition */
3499 /*-----------------------------------------------------------------*/
3501 genPlus (iCode * ic)
3503 int size, offset = 0;
3505 /* special cases :- */
3507 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3508 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3509 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3511 /* Swap the left and right operands if:
3513 if literal, literal on the right or
3514 if left requires ACC or right is already
3517 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3518 (AOP_NEEDSACC (IC_LEFT (ic))) ||
3519 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3521 operand *t = IC_RIGHT (ic);
3522 IC_RIGHT (ic) = IC_LEFT (ic);
3526 /* if both left & right are in bit
3528 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3529 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3532 wassertl (0, "Tried to add two bits");
3535 /* if left in bit space & right literal */
3536 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3537 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3539 /* Can happen I guess */
3540 wassertl (0, "Tried to add a bit to a literal");
3543 /* if I can do an increment instead
3544 of add then GOOD for ME */
3545 if (genPlusIncr (ic) == TRUE)
3548 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3550 size = getDataSize (IC_RESULT (ic));
3552 /* Special case when left and right are constant */
3553 if (isPair (AOP (IC_RESULT (ic))))
3556 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3557 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3559 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3565 sprintf (buffer, "#(%s + %s)", left, right);
3566 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3571 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3573 /* Fetch into HL then do the add */
3574 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3575 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3577 spillPair (PAIR_HL);
3579 if (left == PAIR_HL && right != PAIR_INVALID)
3581 emit2 ("add hl,%s", _pairs[right].name);
3584 else if (right == PAIR_HL && left != PAIR_INVALID)
3586 emit2 ("add hl,%s", _pairs[left].name);
3589 else if (right != PAIR_INVALID && right != PAIR_HL)
3591 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3592 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3595 else if (left != PAIR_INVALID && left != PAIR_HL)
3597 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3598 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3607 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3609 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3610 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3612 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3617 ld hl,sp+n trashes C so we cant afford to do it during an
3618 add with stack based varibles. Worst case is:
3631 So you cant afford to load up hl if either left, right, or result
3632 is on the stack (*sigh*) The alt is:
3640 Combinations in here are:
3641 * If left or right are in bc then the loss is small - trap later
3642 * If the result is in bc then the loss is also small
3646 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3647 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3648 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3650 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3651 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3652 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3653 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3655 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3657 /* Swap left and right */
3658 operand *t = IC_RIGHT (ic);
3659 IC_RIGHT (ic) = IC_LEFT (ic);
3662 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3664 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3665 emit2 ("add hl,bc");
3669 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3670 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3671 emit2 ("add hl,de");
3673 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3679 /* Be paranoid on the GB with 4 byte variables due to how C
3680 can be trashed by lda hl,n(sp).
3682 _gbz80_emitAddSubLong (ic, TRUE);
3687 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3691 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3693 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3696 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3699 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3703 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3706 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3709 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3711 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3715 freeAsmop (IC_LEFT (ic), NULL, ic);
3716 freeAsmop (IC_RIGHT (ic), NULL, ic);
3717 freeAsmop (IC_RESULT (ic), NULL, ic);
3721 /*-----------------------------------------------------------------*/
3722 /* genMinusDec :- does subtraction with deccrement if possible */
3723 /*-----------------------------------------------------------------*/
3725 genMinusDec (iCode * ic)
3727 unsigned int icount;
3728 unsigned int size = getDataSize (IC_RESULT (ic));
3730 /* will try to generate an increment */
3731 /* if the right side is not a literal we cannot */
3732 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3735 /* if the literal value of the right hand side
3736 is greater than 4 then it is not worth it */
3737 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3740 size = getDataSize (IC_RESULT (ic));
3742 /* if decrement 16 bits in register */
3743 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3744 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3747 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3751 /* If result is a pair */
3752 if (isPair (AOP (IC_RESULT (ic))))
3754 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3756 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3760 /* if increment 16 bits in register */
3761 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3765 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3768 emit2 ("dec %s", _getTempPairName());
3771 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3777 /* if the sizes are greater than 1 then we cannot */
3778 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3779 AOP_SIZE (IC_LEFT (ic)) > 1)
3782 /* we can if the aops of the left & result match or if they are in
3783 registers and the registers are the same */
3784 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3787 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3794 /*-----------------------------------------------------------------*/
3795 /* genMinus - generates code for subtraction */
3796 /*-----------------------------------------------------------------*/
3798 genMinus (iCode * ic)
3800 int size, offset = 0;
3801 unsigned long lit = 0L;
3803 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3804 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3805 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3807 /* special cases :- */
3808 /* if both left & right are in bit space */
3809 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3810 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3812 wassertl (0, "Tried to subtract two bits");
3816 /* if I can do an decrement instead of subtract then GOOD for ME */
3817 if (genMinusDec (ic) == TRUE)
3820 size = getDataSize (IC_RESULT (ic));
3822 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3827 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3831 /* Same logic as genPlus */
3834 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3835 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3836 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3838 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3839 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3840 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3841 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3843 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3844 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3846 if (left == PAIR_INVALID && right == PAIR_INVALID)
3851 else if (right == PAIR_INVALID)
3853 else if (left == PAIR_INVALID)
3856 fetchPair (left, AOP (IC_LEFT (ic)));
3857 /* Order is important. Right may be HL */
3858 fetchPair (right, AOP (IC_RIGHT (ic)));
3860 emit2 ("ld a,%s", _pairs[left].l);
3861 emit2 ("sub a,%s", _pairs[right].l);
3863 emit2 ("ld a,%s", _pairs[left].h);
3864 emit2 ("sbc a,%s", _pairs[right].h);
3866 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
3868 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3870 aopPut (AOP (IC_RESULT (ic)), "e", 0);
3876 /* Be paranoid on the GB with 4 byte variables due to how C
3877 can be trashed by lda hl,n(sp).
3879 _gbz80_emitAddSubLong (ic, FALSE);
3884 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3886 /* if literal, add a,#-lit, else normal subb */
3889 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3890 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3894 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3897 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3901 /* first add without previous c */
3903 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
3905 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3907 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3910 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3911 AOP_SIZE (IC_LEFT (ic)) == 3 &&
3912 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3914 wassertl (0, "Tried to subtract on a long pointer");
3918 freeAsmop (IC_LEFT (ic), NULL, ic);
3919 freeAsmop (IC_RIGHT (ic), NULL, ic);
3920 freeAsmop (IC_RESULT (ic), NULL, ic);
3923 /*-----------------------------------------------------------------*/
3924 /* genMult - generates code for multiplication */
3925 /*-----------------------------------------------------------------*/
3927 genMult (iCode * ic)
3931 /* If true then the final operation should be a subtract */
3932 bool active = FALSE;
3934 /* Shouldn't occur - all done through function calls */
3935 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3936 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3937 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3939 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
3940 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
3941 AOP_SIZE (IC_RESULT (ic)) > 2)
3943 wassertl (0, "Multiplication is handled through support function calls");
3946 /* Swap left and right such that right is a literal */
3947 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
3949 operand *t = IC_RIGHT (ic);
3950 IC_RIGHT (ic) = IC_LEFT (ic);
3954 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
3956 val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
3957 // wassertl (val > 0, "Multiply must be positive");
3958 wassertl (val != 1, "Can't multiply by 1");
3960 if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
3962 _G.stack.pushedDE = TRUE;
3965 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
3967 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
3975 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3980 /* Fully unroled version of mul.s. Not the most efficient.
3982 for (count = 0; count < 16; count++)
3984 if (count != 0 && active)
3986 emit2 ("add hl,hl");
3990 if (active == FALSE)
3997 emit2 ("add hl,de");
4006 if (IS_Z80 && _G.stack.pushedDE)
4009 _G.stack.pushedDE = FALSE;
4012 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
4014 freeAsmop (IC_LEFT (ic), NULL, ic);
4015 freeAsmop (IC_RIGHT (ic), NULL, ic);
4016 freeAsmop (IC_RESULT (ic), NULL, ic);
4019 /*-----------------------------------------------------------------*/
4020 /* genDiv - generates code for division */
4021 /*-----------------------------------------------------------------*/
4025 /* Shouldn't occur - all done through function calls */
4026 wassertl (0, "Division is handled through support function calls");
4029 /*-----------------------------------------------------------------*/
4030 /* genMod - generates code for division */
4031 /*-----------------------------------------------------------------*/
4035 /* Shouldn't occur - all done through function calls */
4039 /*-----------------------------------------------------------------*/
4040 /* genIfxJump :- will create a jump depending on the ifx */
4041 /*-----------------------------------------------------------------*/
4043 genIfxJump (iCode * ic, char *jval)
4048 /* if true label then we jump if condition
4052 jlbl = IC_TRUE (ic);
4053 if (!strcmp (jval, "a"))
4057 else if (!strcmp (jval, "c"))
4061 else if (!strcmp (jval, "nc"))
4065 else if (!strcmp (jval, "m"))
4069 else if (!strcmp (jval, "p"))
4075 /* The buffer contains the bit on A that we should test */
4081 /* false label is present */
4082 jlbl = IC_FALSE (ic);
4083 if (!strcmp (jval, "a"))
4087 else if (!strcmp (jval, "c"))
4091 else if (!strcmp (jval, "nc"))
4095 else if (!strcmp (jval, "m"))
4099 else if (!strcmp (jval, "p"))
4105 /* The buffer contains the bit on A that we should test */
4109 /* Z80 can do a conditional long jump */
4110 if (!strcmp (jval, "a"))
4114 else if (!strcmp (jval, "c"))
4117 else if (!strcmp (jval, "nc"))
4120 else if (!strcmp (jval, "m"))
4123 else if (!strcmp (jval, "p"))
4128 emit2 ("bit %s,a", jval);
4130 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
4132 /* mark the icode as generated */
4138 _getPairIdName (PAIR_ID id)
4140 return _pairs[id].name;
4145 /* if unsigned char cmp with lit, just compare */
4147 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4149 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4152 emit2 ("xor a,!immedbyte", 0x80);
4153 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4156 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4158 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4160 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4161 // Pull left into DE and right into HL
4162 aopGet (AOP(left), LSB, FALSE);
4165 aopGet (AOP(right), LSB, FALSE);
4169 if (size == 0 && sign)
4171 // Highest byte when signed needs the bits flipped
4174 emit2 ("ld a,(de)");
4175 emit2 ("xor !immedbyte", 0x80);
4177 emit2 ("ld a,(hl)");
4178 emit2 ("xor !immedbyte", 0x80);
4182 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4186 emit2 ("ld a,(de)");
4187 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4197 spillPair (PAIR_HL);
4199 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4201 setupPair (PAIR_HL, AOP (left), 0);
4202 aopGet (AOP(right), LSB, FALSE);
4206 if (size == 0 && sign)
4208 // Highest byte when signed needs the bits flipped
4211 emit2 ("ld a,(hl)");
4212 emit2 ("xor !immedbyte", 0x80);
4214 emit2 ("ld a,%d(iy)", offset);
4215 emit2 ("xor !immedbyte", 0x80);
4219 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4223 emit2 ("ld a,(hl)");
4224 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4233 spillPair (PAIR_HL);
4234 spillPair (PAIR_IY);
4238 if (AOP_TYPE (right) == AOP_LIT)
4240 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4241 /* optimize if(x < 0) or if(x >= 0) */
4246 /* No sign so it's always false */
4251 /* Just load in the top most bit */
4252 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4253 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4255 genIfxJump (ifx, "7");
4267 /* First setup h and l contaning the top most bytes XORed */
4268 bool fDidXor = FALSE;
4269 if (AOP_TYPE (left) == AOP_LIT)
4271 unsigned long lit = (unsigned long)
4272 floatFromVal (AOP (left)->aopu.aop_lit);
4273 emit2 ("ld %s,!immedbyte", _fTmp[0],
4274 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4278 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4279 emit2 ("xor a,!immedbyte", 0x80);
4280 emit2 ("ld %s,a", _fTmp[0]);
4283 if (AOP_TYPE (right) == AOP_LIT)
4285 unsigned long lit = (unsigned long)
4286 floatFromVal (AOP (right)->aopu.aop_lit);
4287 emit2 ("ld %s,!immedbyte", _fTmp[1],
4288 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4292 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4293 emit2 ("xor a,!immedbyte", 0x80);
4294 emit2 ("ld %s,a", _fTmp[1]);
4300 /* Do a long subtract */
4303 _moveA (aopGet (AOP (left), offset, FALSE));
4305 if (sign && size == 0)
4307 emit2 ("ld a,%s", _fTmp[0]);
4308 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4312 /* Subtract through, propagating the carry */
4313 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4321 /** Generic compare for > or <
4324 genCmp (operand * left, operand * right,
4325 operand * result, iCode * ifx, int sign)
4327 int size, offset = 0;
4328 unsigned long lit = 0L;
4329 bool swap_sense = FALSE;
4331 /* if left & right are bit variables */
4332 if (AOP_TYPE (left) == AOP_CRY &&
4333 AOP_TYPE (right) == AOP_CRY)
4335 /* Cant happen on the Z80 */
4336 wassertl (0, "Tried to compare two bits");
4340 /* Do a long subtract of right from left. */
4341 size = max (AOP_SIZE (left), AOP_SIZE (right));
4343 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4345 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4346 // Pull left into DE and right into HL
4347 aopGet (AOP(left), LSB, FALSE);
4350 aopGet (AOP(right), LSB, FALSE);
4354 emit2 ("ld a,(de)");
4355 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4364 spillPair (PAIR_HL);
4368 if (AOP_TYPE (right) == AOP_LIT)
4370 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4371 /* optimize if(x < 0) or if(x >= 0) */
4376 /* No sign so it's always false */
4381 /* Just load in the top most bit */
4382 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4383 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4385 genIfxJump (ifx, "7");
4396 genIfxJump (ifx, swap_sense ? "c" : "nc");
4407 _moveA (aopGet (AOP (left), offset, FALSE));
4408 /* Subtract through, propagating the carry */
4409 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4415 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4419 /* Shift the sign bit up into carry */
4422 outBitCLong (result, swap_sense);
4426 /* if the result is used in the next
4427 ifx conditional branch then generate
4428 code a little differently */
4436 genIfxJump (ifx, swap_sense ? "nc" : "c");
4440 genIfxJump (ifx, swap_sense ? "p" : "m");
4445 genIfxJump (ifx, swap_sense ? "nc" : "c");
4452 /* Shift the sign bit up into carry */
4455 outBitCLong (result, swap_sense);
4457 /* leave the result in acc */
4461 /*-----------------------------------------------------------------*/
4462 /* genCmpGt :- greater than comparison */
4463 /*-----------------------------------------------------------------*/
4465 genCmpGt (iCode * ic, iCode * ifx)
4467 operand *left, *right, *result;
4468 sym_link *letype, *retype;
4471 left = IC_LEFT (ic);
4472 right = IC_RIGHT (ic);
4473 result = IC_RESULT (ic);
4475 letype = getSpec (operandType (left));
4476 retype = getSpec (operandType (right));
4477 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4478 /* assign the amsops */
4479 aopOp (left, ic, FALSE, FALSE);
4480 aopOp (right, ic, FALSE, FALSE);
4481 aopOp (result, ic, TRUE, FALSE);
4483 genCmp (right, left, result, ifx, sign);
4485 freeAsmop (left, NULL, ic);
4486 freeAsmop (right, NULL, ic);
4487 freeAsmop (result, NULL, ic);
4490 /*-----------------------------------------------------------------*/
4491 /* genCmpLt - less than comparisons */
4492 /*-----------------------------------------------------------------*/
4494 genCmpLt (iCode * ic, iCode * ifx)
4496 operand *left, *right, *result;
4497 sym_link *letype, *retype;
4500 left = IC_LEFT (ic);
4501 right = IC_RIGHT (ic);
4502 result = IC_RESULT (ic);
4504 letype = getSpec (operandType (left));
4505 retype = getSpec (operandType (right));
4506 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4508 /* assign the amsops */
4509 aopOp (left, ic, FALSE, FALSE);
4510 aopOp (right, ic, FALSE, FALSE);
4511 aopOp (result, ic, TRUE, FALSE);
4513 genCmp (left, right, result, ifx, sign);
4515 freeAsmop (left, NULL, ic);
4516 freeAsmop (right, NULL, ic);
4517 freeAsmop (result, NULL, ic);
4520 /*-----------------------------------------------------------------*/
4521 /* gencjneshort - compare and jump if not equal */
4522 /*-----------------------------------------------------------------*/
4524 gencjneshort (operand * left, operand * right, symbol * lbl)
4526 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4528 unsigned long lit = 0L;
4530 /* Swap the left and right if it makes the computation easier */
4531 if (AOP_TYPE (left) == AOP_LIT)
4538 if (AOP_TYPE (right) == AOP_LIT)
4540 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4543 /* if the right side is a literal then anything goes */
4544 if (AOP_TYPE (right) == AOP_LIT &&
4545 AOP_TYPE (left) != AOP_DIR)
4549 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4554 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4561 emit2 ("jp nz,!tlabel", lbl->key + 100);
4567 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4568 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
4571 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
4572 emit2 ("jp nz,!tlabel", lbl->key + 100);
4577 /* if the right side is in a register or in direct space or
4578 if the left is a pointer register & right is not */
4579 else if (AOP_TYPE (right) == AOP_REG ||
4580 AOP_TYPE (right) == AOP_DIR ||
4581 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
4585 _moveA (aopGet (AOP (left), offset, FALSE));
4586 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
4587 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4589 emit2 ("jp nz,!tlabel", lbl->key + 100);
4592 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4593 emit2 ("jp nz,!tlabel", lbl->key + 100);
4600 /* right is a pointer reg need both a & b */
4601 /* PENDING: is this required? */
4604 _moveA (aopGet (AOP (right), offset, FALSE));
4605 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
4606 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
4612 /*-----------------------------------------------------------------*/
4613 /* gencjne - compare and jump if not equal */
4614 /*-----------------------------------------------------------------*/
4616 gencjne (operand * left, operand * right, symbol * lbl)
4618 symbol *tlbl = newiTempLabel (NULL);
4620 gencjneshort (left, right, lbl);
4623 emit2 ("ld a,!one");
4624 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4625 emitLabel (lbl->key + 100);
4627 emitLabel (tlbl->key + 100);
4630 /*-----------------------------------------------------------------*/
4631 /* genCmpEq - generates code for equal to */
4632 /*-----------------------------------------------------------------*/
4634 genCmpEq (iCode * ic, iCode * ifx)
4636 operand *left, *right, *result;
4638 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4639 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4640 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4642 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4644 /* Swap operands if it makes the operation easier. ie if:
4645 1. Left is a literal.
4647 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4649 operand *t = IC_RIGHT (ic);
4650 IC_RIGHT (ic) = IC_LEFT (ic);
4654 if (ifx && !AOP_SIZE (result))
4657 /* if they are both bit variables */
4658 if (AOP_TYPE (left) == AOP_CRY &&
4659 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4661 wassertl (0, "Tried to compare two bits");
4665 tlbl = newiTempLabel (NULL);
4666 gencjneshort (left, right, tlbl);
4669 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4670 emitLabel (tlbl->key + 100);
4674 /* PENDING: do this better */
4675 symbol *lbl = newiTempLabel (NULL);
4676 emit2 ("!shortjp !tlabel", lbl->key + 100);
4677 emitLabel (tlbl->key + 100);
4678 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4679 emitLabel (lbl->key + 100);
4682 /* mark the icode as generated */
4687 /* if they are both bit variables */
4688 if (AOP_TYPE (left) == AOP_CRY &&
4689 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4691 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4697 gencjne (left, right, newiTempLabel (NULL));
4698 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4705 genIfxJump (ifx, "a");
4708 /* if the result is used in an arithmetic operation
4709 then put the result in place */
4710 if (AOP_TYPE (result) != AOP_CRY)
4715 /* leave the result in acc */
4719 freeAsmop (left, NULL, ic);
4720 freeAsmop (right, NULL, ic);
4721 freeAsmop (result, NULL, ic);
4724 /*-----------------------------------------------------------------*/
4725 /* ifxForOp - returns the icode containing the ifx for operand */
4726 /*-----------------------------------------------------------------*/
4728 ifxForOp (operand * op, iCode * ic)
4730 /* if true symbol then needs to be assigned */
4731 if (IS_TRUE_SYMOP (op))
4734 /* if this has register type condition and
4735 the next instruction is ifx with the same operand
4736 and live to of the operand is upto the ifx only then */
4738 ic->next->op == IFX &&
4739 IC_COND (ic->next)->key == op->key &&
4740 OP_SYMBOL (op)->liveTo <= ic->next->seq)
4746 /*-----------------------------------------------------------------*/
4747 /* genAndOp - for && operation */
4748 /*-----------------------------------------------------------------*/
4750 genAndOp (iCode * ic)
4752 operand *left, *right, *result;
4755 /* note here that && operations that are in an if statement are
4756 taken away by backPatchLabels only those used in arthmetic
4757 operations remain */
4758 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4759 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4760 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4762 /* if both are bit variables */
4763 if (AOP_TYPE (left) == AOP_CRY &&
4764 AOP_TYPE (right) == AOP_CRY)
4766 wassertl (0, "Tried to and two bits");
4770 tlbl = newiTempLabel (NULL);
4772 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
4774 emitLabel (tlbl->key + 100);
4778 freeAsmop (left, NULL, ic);
4779 freeAsmop (right, NULL, ic);
4780 freeAsmop (result, NULL, ic);
4783 /*-----------------------------------------------------------------*/
4784 /* genOrOp - for || operation */
4785 /*-----------------------------------------------------------------*/
4787 genOrOp (iCode * ic)
4789 operand *left, *right, *result;
4792 /* note here that || operations that are in an
4793 if statement are taken away by backPatchLabels
4794 only those used in arthmetic operations remain */
4795 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4796 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4797 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4799 /* if both are bit variables */
4800 if (AOP_TYPE (left) == AOP_CRY &&
4801 AOP_TYPE (right) == AOP_CRY)
4803 wassertl (0, "Tried to OR two bits");
4807 tlbl = newiTempLabel (NULL);
4809 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4811 emitLabel (tlbl->key + 100);
4815 freeAsmop (left, NULL, ic);
4816 freeAsmop (right, NULL, ic);
4817 freeAsmop (result, NULL, ic);
4820 /*-----------------------------------------------------------------*/
4821 /* isLiteralBit - test if lit == 2^n */
4822 /*-----------------------------------------------------------------*/
4824 isLiteralBit (unsigned long lit)
4826 unsigned long pw[32] =
4827 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
4828 0x100L, 0x200L, 0x400L, 0x800L,
4829 0x1000L, 0x2000L, 0x4000L, 0x8000L,
4830 0x10000L, 0x20000L, 0x40000L, 0x80000L,
4831 0x100000L, 0x200000L, 0x400000L, 0x800000L,
4832 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
4833 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
4836 for (idx = 0; idx < 32; idx++)
4842 /*-----------------------------------------------------------------*/
4843 /* jmpTrueOrFalse - */
4844 /*-----------------------------------------------------------------*/
4846 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
4848 // ugly but optimized by peephole
4851 symbol *nlbl = newiTempLabel (NULL);
4852 emit2 ("jp !tlabel", nlbl->key + 100);
4853 emitLabel (tlbl->key + 100);
4854 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
4855 emitLabel (nlbl->key + 100);
4859 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
4860 emitLabel (tlbl->key + 100);
4865 /*-----------------------------------------------------------------*/
4866 /* genAnd - code for and */
4867 /*-----------------------------------------------------------------*/
4869 genAnd (iCode * ic, iCode * ifx)
4871 operand *left, *right, *result;
4872 int size, offset = 0;
4873 unsigned long lit = 0L;
4876 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4877 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4878 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4880 /* if left is a literal & right is not then exchange them */
4881 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4882 AOP_NEEDSACC (left))
4884 operand *tmp = right;
4889 /* if result = right then exchange them */
4890 if (sameRegs (AOP (result), AOP (right)))
4892 operand *tmp = right;
4897 /* if right is bit then exchange them */
4898 if (AOP_TYPE (right) == AOP_CRY &&
4899 AOP_TYPE (left) != AOP_CRY)
4901 operand *tmp = right;
4905 if (AOP_TYPE (right) == AOP_LIT)
4906 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4908 size = AOP_SIZE (result);
4910 if (AOP_TYPE (left) == AOP_CRY)
4912 wassertl (0, "Tried to perform an AND with a bit as an operand");
4916 // if(val & 0xZZ) - size = 0, ifx != FALSE -
4917 // bit = val & 0xZZ - size = 1, ifx = FALSE -
4918 if ((AOP_TYPE (right) == AOP_LIT) &&
4919 (AOP_TYPE (result) == AOP_CRY) &&
4920 (AOP_TYPE (left) != AOP_CRY))
4922 symbol *tlbl = newiTempLabel (NULL);
4923 int sizel = AOP_SIZE (left);
4926 /* PENDING: Test case for this. */
4931 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
4933 _moveA (aopGet (AOP (left), offset, FALSE));
4934 if (bytelit != 0x0FFL)
4936 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4943 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4947 // bit = left & literal
4951 emit2 ("!tlabeldef", tlbl->key + 100);
4953 // if(left & literal)
4958 jmpTrueOrFalse (ifx, tlbl);
4966 /* if left is same as result */
4967 if (sameRegs (AOP (result), AOP (left)))
4969 for (; size--; offset++)
4971 if (AOP_TYPE (right) == AOP_LIT)
4973 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4978 aopPut (AOP (result), "!zero", offset);
4981 _moveA (aopGet (AOP (left), offset, FALSE));
4983 aopGet (AOP (right), offset, FALSE));
4984 aopPut (AOP (left), "a", offset);
4991 if (AOP_TYPE (left) == AOP_ACC)
4993 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
4997 _moveA (aopGet (AOP (left), offset, FALSE));
4999 aopGet (AOP (right), offset, FALSE));
5000 aopPut (AOP (left), "a", offset);
5007 // left & result in different registers
5008 if (AOP_TYPE (result) == AOP_CRY)
5010 wassertl (0, "Tried to AND where the result is in carry");
5014 for (; (size--); offset++)
5017 // result = left & right
5018 if (AOP_TYPE (right) == AOP_LIT)
5020 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5022 aopPut (AOP (result),
5023 aopGet (AOP (left), offset, FALSE),
5027 else if (bytelit == 0)
5029 aopPut (AOP (result), "!zero", offset);
5033 // faster than result <- left, anl result,right
5034 // and better if result is SFR
5035 if (AOP_TYPE (left) == AOP_ACC)
5036 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5039 _moveA (aopGet (AOP (left), offset, FALSE));
5041 aopGet (AOP (right), offset, FALSE));
5043 aopPut (AOP (result), "a", offset);
5050 freeAsmop (left, NULL, ic);
5051 freeAsmop (right, NULL, ic);
5052 freeAsmop (result, NULL, ic);
5055 /*-----------------------------------------------------------------*/
5056 /* genOr - code for or */
5057 /*-----------------------------------------------------------------*/
5059 genOr (iCode * ic, iCode * ifx)
5061 operand *left, *right, *result;
5062 int size, offset = 0;
5063 unsigned long lit = 0L;
5066 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5067 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5068 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5070 /* if left is a literal & right is not then exchange them */
5071 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5072 AOP_NEEDSACC (left))
5074 operand *tmp = right;
5079 /* if result = right then exchange them */
5080 if (sameRegs (AOP (result), AOP (right)))
5082 operand *tmp = right;
5087 /* if right is bit then exchange them */
5088 if (AOP_TYPE (right) == AOP_CRY &&
5089 AOP_TYPE (left) != AOP_CRY)
5091 operand *tmp = right;
5095 if (AOP_TYPE (right) == AOP_LIT)
5096 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5098 size = AOP_SIZE (result);
5100 if (AOP_TYPE (left) == AOP_CRY)
5102 wassertl (0, "Tried to OR where left is a bit");
5106 // if(val | 0xZZ) - size = 0, ifx != FALSE -
5107 // bit = val | 0xZZ - size = 1, ifx = FALSE -
5108 if ((AOP_TYPE (right) == AOP_LIT) &&
5109 (AOP_TYPE (result) == AOP_CRY) &&
5110 (AOP_TYPE (left) != AOP_CRY))
5112 symbol *tlbl = newiTempLabel (NULL);
5113 int sizel = AOP_SIZE (left);
5117 wassertl (0, "Result is assigned to a bit");
5119 /* PENDING: Modeled after the AND code which is inefficent. */
5122 bytelit = (lit >> (offset * 8)) & 0x0FFL;
5124 _moveA (aopGet (AOP (left), offset, FALSE));
5125 /* OR with any literal is the same as OR with itself. */
5127 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5133 jmpTrueOrFalse (ifx, tlbl);
5138 /* if left is same as result */
5139 if (sameRegs (AOP (result), AOP (left)))
5141 for (; size--; offset++)
5143 if (AOP_TYPE (right) == AOP_LIT)
5145 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5149 _moveA (aopGet (AOP (left), offset, FALSE));
5151 aopGet (AOP (right), offset, FALSE));
5152 aopPut (AOP (result), "a", offset);
5157 if (AOP_TYPE (left) == AOP_ACC)
5158 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5161 _moveA (aopGet (AOP (left), offset, FALSE));
5163 aopGet (AOP (right), offset, FALSE));
5164 aopPut (AOP (result), "a", offset);
5171 // left & result in different registers
5172 if (AOP_TYPE (result) == AOP_CRY)
5174 wassertl (0, "Result of OR is in a bit");
5177 for (; (size--); offset++)
5180 // result = left & right
5181 if (AOP_TYPE (right) == AOP_LIT)
5183 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5185 aopPut (AOP (result),
5186 aopGet (AOP (left), offset, FALSE),
5191 // faster than result <- left, anl result,right
5192 // and better if result is SFR
5193 if (AOP_TYPE (left) == AOP_ACC)
5194 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5197 _moveA (aopGet (AOP (left), offset, FALSE));
5199 aopGet (AOP (right), offset, FALSE));
5201 aopPut (AOP (result), "a", offset);
5202 /* PENDING: something weird is going on here. Add exception. */
5203 if (AOP_TYPE (result) == AOP_ACC)
5209 freeAsmop (left, NULL, ic);
5210 freeAsmop (right, NULL, ic);
5211 freeAsmop (result, NULL, ic);
5214 /*-----------------------------------------------------------------*/
5215 /* genXor - code for xclusive or */
5216 /*-----------------------------------------------------------------*/
5218 genXor (iCode * ic, iCode * ifx)
5220 operand *left, *right, *result;
5221 int size, offset = 0;
5222 unsigned long lit = 0L;
5224 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5225 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5226 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5228 /* if left is a literal & right is not then exchange them */
5229 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5230 AOP_NEEDSACC (left))
5232 operand *tmp = right;
5237 /* if result = right then exchange them */
5238 if (sameRegs (AOP (result), AOP (right)))
5240 operand *tmp = right;
5245 /* if right is bit then exchange them */
5246 if (AOP_TYPE (right) == AOP_CRY &&
5247 AOP_TYPE (left) != AOP_CRY)
5249 operand *tmp = right;
5253 if (AOP_TYPE (right) == AOP_LIT)
5254 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5256 size = AOP_SIZE (result);
5258 if (AOP_TYPE (left) == AOP_CRY)
5260 wassertl (0, "Tried to XOR a bit");
5264 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5265 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5266 if ((AOP_TYPE (right) == AOP_LIT) &&
5267 (AOP_TYPE (result) == AOP_CRY) &&
5268 (AOP_TYPE (left) != AOP_CRY))
5270 symbol *tlbl = newiTempLabel (NULL);
5271 int sizel = AOP_SIZE (left);
5275 /* PENDING: Test case for this. */
5276 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5280 _moveA (aopGet (AOP (left), offset, FALSE));
5281 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5282 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5287 jmpTrueOrFalse (ifx, tlbl);
5291 wassertl (0, "Result of XOR was destined for a bit");
5296 /* if left is same as result */
5297 if (sameRegs (AOP (result), AOP (left)))
5299 for (; size--; offset++)
5301 if (AOP_TYPE (right) == AOP_LIT)
5303 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5307 _moveA (aopGet (AOP (right), offset, FALSE));
5309 aopGet (AOP (left), offset, FALSE));
5310 aopPut (AOP (result), "a", offset);
5315 if (AOP_TYPE (left) == AOP_ACC)
5317 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5321 _moveA (aopGet (AOP (right), offset, FALSE));
5323 aopGet (AOP (left), offset, FALSE));
5324 aopPut (AOP (result), "a", offset);
5331 // left & result in different registers
5332 if (AOP_TYPE (result) == AOP_CRY)
5334 wassertl (0, "Result of XOR is in a bit");
5337 for (; (size--); offset++)
5340 // result = left & right
5341 if (AOP_TYPE (right) == AOP_LIT)
5343 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5345 aopPut (AOP (result),
5346 aopGet (AOP (left), offset, FALSE),
5351 // faster than result <- left, anl result,right
5352 // and better if result is SFR
5353 if (AOP_TYPE (left) == AOP_ACC)
5355 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5359 _moveA (aopGet (AOP (right), offset, FALSE));
5361 aopGet (AOP (left), offset, FALSE));
5363 aopPut (AOP (result), "a", offset);
5368 freeAsmop (left, NULL, ic);
5369 freeAsmop (right, NULL, ic);
5370 freeAsmop (result, NULL, ic);
5373 /*-----------------------------------------------------------------*/
5374 /* genInline - write the inline code out */
5375 /*-----------------------------------------------------------------*/
5377 genInline (iCode * ic)
5379 char *buffer, *bp, *bp1;
5381 _G.lines.isInline += (!options.asmpeep);
5383 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5384 strcpy (buffer, IC_INLINE (ic));
5386 /* emit each line as a code */
5411 _G.lines.isInline -= (!options.asmpeep);
5415 /*-----------------------------------------------------------------*/
5416 /* genRRC - rotate right with carry */
5417 /*-----------------------------------------------------------------*/
5424 /*-----------------------------------------------------------------*/
5425 /* genRLC - generate code for rotate left with carry */
5426 /*-----------------------------------------------------------------*/
5433 /*-----------------------------------------------------------------*/
5434 /* genGetHbit - generates code get highest order bit */
5435 /*-----------------------------------------------------------------*/
5437 genGetHbit (iCode * ic)
5439 operand *left, *result;
5440 left = IC_LEFT (ic);
5441 result = IC_RESULT (ic);
5443 aopOp (left, ic, FALSE, FALSE);
5444 aopOp (result, ic, FALSE, FALSE);
5446 /* get the highest order byte into a */
5447 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5449 if (AOP_TYPE (result) == AOP_CRY)
5457 emit2 ("and a,!one");
5462 freeAsmop (left, NULL, ic);
5463 freeAsmop (result, NULL, ic);
5467 emitRsh2 (asmop *aop, int size, int is_signed)
5473 const char *l = aopGet (aop, size, FALSE);
5476 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5486 /*-----------------------------------------------------------------*/
5487 /* shiftR2Left2Result - shift right two bytes from left to result */
5488 /*-----------------------------------------------------------------*/
5490 shiftR2Left2Result (operand * left, int offl,
5491 operand * result, int offr,
5492 int shCount, int is_signed)
5495 symbol *tlbl, *tlbl1;
5497 movLeft2Result (left, offl, result, offr, 0);
5498 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5500 /* if (AOP(result)->type == AOP_REG) { */
5502 tlbl = newiTempLabel (NULL);
5503 tlbl1 = newiTempLabel (NULL);
5505 /* Left is already in result - so now do the shift */
5510 emitRsh2 (AOP (result), size, is_signed);
5515 emit2 ("ld a,!immedbyte+1", shCount);
5516 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5517 emitLabel (tlbl->key + 100);
5519 emitRsh2 (AOP (result), size, is_signed);
5521 emitLabel (tlbl1->key + 100);
5523 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5527 /*-----------------------------------------------------------------*/
5528 /* shiftL2Left2Result - shift left two bytes from left to result */
5529 /*-----------------------------------------------------------------*/
5531 shiftL2Left2Result (operand * left, int offl,
5532 operand * result, int offr, int shCount)
5534 if (sameRegs (AOP (result), AOP (left)) &&
5535 ((offl + MSB16) == offr))
5541 /* Copy left into result */
5542 movLeft2Result (left, offl, result, offr, 0);
5543 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5546 if (getPairId (AOP (result)) == PAIR_HL)
5550 emit2 ("add hl,hl");
5557 symbol *tlbl, *tlbl1;
5560 tlbl = newiTempLabel (NULL);
5561 tlbl1 = newiTempLabel (NULL);
5563 if (AOP (result)->type == AOP_REG)
5567 for (offset = 0; offset < size; offset++)
5569 l = aopGet (AOP (result), offset, FALSE);
5573 emit2 ("sla %s", l);
5584 /* Left is already in result - so now do the shift */
5587 emit2 ("ld a,!immedbyte+1", shCount);
5588 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5589 emitLabel (tlbl->key + 100);
5594 l = aopGet (AOP (result), offset, FALSE);
5598 emit2 ("sla %s", l);
5609 emitLabel (tlbl1->key + 100);
5611 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5617 /*-----------------------------------------------------------------*/
5618 /* AccRol - rotate left accumulator by known count */
5619 /*-----------------------------------------------------------------*/
5621 AccRol (int shCount)
5623 shCount &= 0x0007; // shCount : 0..7
5700 /*-----------------------------------------------------------------*/
5701 /* AccLsh - left shift accumulator by known count */
5702 /*-----------------------------------------------------------------*/
5704 AccLsh (int shCount)
5706 static const unsigned char SLMask[] =
5708 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5717 else if (shCount == 2)
5724 /* rotate left accumulator */
5726 /* and kill the lower order bits */
5727 emit2 ("and a,!immedbyte", SLMask[shCount]);
5732 /*-----------------------------------------------------------------*/
5733 /* shiftL1Left2Result - shift left one byte from left to result */
5734 /*-----------------------------------------------------------------*/
5736 shiftL1Left2Result (operand * left, int offl,
5737 operand * result, int offr, int shCount)
5740 l = aopGet (AOP (left), offl, FALSE);
5742 /* shift left accumulator */
5744 aopPut (AOP (result), "a", offr);
5748 /*-----------------------------------------------------------------*/
5749 /* genlshTwo - left shift two bytes by known amount != 0 */
5750 /*-----------------------------------------------------------------*/
5752 genlshTwo (operand * result, operand * left, int shCount)
5754 int size = AOP_SIZE (result);
5756 wassert (size == 2);
5758 /* if shCount >= 8 */
5766 movLeft2Result (left, LSB, result, MSB16, 0);
5767 aopPut (AOP (result), "!zero", 0);
5768 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
5772 movLeft2Result (left, LSB, result, MSB16, 0);
5773 aopPut (AOP (result), "!zero", 0);
5778 aopPut (AOP (result), "!zero", LSB);
5781 /* 1 <= shCount <= 7 */
5790 shiftL2Left2Result (left, LSB, result, LSB, shCount);
5795 /*-----------------------------------------------------------------*/
5796 /* genlshOne - left shift a one byte quantity by known count */
5797 /*-----------------------------------------------------------------*/
5799 genlshOne (operand * result, operand * left, int shCount)
5801 shiftL1Left2Result (left, LSB, result, LSB, shCount);
5804 /*-----------------------------------------------------------------*/
5805 /* genLeftShiftLiteral - left shifting by known count */
5806 /*-----------------------------------------------------------------*/
5808 genLeftShiftLiteral (operand * left,
5813 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5816 freeAsmop (right, NULL, ic);
5818 aopOp (left, ic, FALSE, FALSE);
5819 aopOp (result, ic, FALSE, FALSE);
5821 size = getSize (operandType (result));
5823 /* I suppose that the left size >= result size */
5829 else if (shCount >= (size * 8))
5833 aopPut (AOP (result), "!zero", size);
5841 genlshOne (result, left, shCount);
5844 genlshTwo (result, left, shCount);
5847 wassertl (0, "Shifting of longs is currently unsupported");
5853 freeAsmop (left, NULL, ic);
5854 freeAsmop (result, NULL, ic);
5857 /*-----------------------------------------------------------------*/
5858 /* genLeftShift - generates code for left shifting */
5859 /*-----------------------------------------------------------------*/
5861 genLeftShift (iCode * ic)
5865 symbol *tlbl, *tlbl1;
5866 operand *left, *right, *result;
5868 right = IC_RIGHT (ic);
5869 left = IC_LEFT (ic);
5870 result = IC_RESULT (ic);
5872 aopOp (right, ic, FALSE, FALSE);
5874 /* if the shift count is known then do it
5875 as efficiently as possible */
5876 if (AOP_TYPE (right) == AOP_LIT)
5878 genLeftShiftLiteral (left, right, result, ic);
5882 /* shift count is unknown then we have to form a loop get the loop
5883 count in B : Note: we take only the lower order byte since
5884 shifting more that 32 bits make no sense anyway, ( the largest
5885 size of an object can be only 32 bits ) */
5886 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5888 freeAsmop (right, NULL, ic);
5889 aopOp (left, ic, FALSE, FALSE);
5890 aopOp (result, ic, FALSE, FALSE);
5892 /* now move the left to the result if they are not the
5895 if (!sameRegs (AOP (left), AOP (result)))
5898 size = AOP_SIZE (result);
5902 l = aopGet (AOP (left), offset, FALSE);
5903 aopPut (AOP (result), l, offset);
5908 tlbl = newiTempLabel (NULL);
5909 size = AOP_SIZE (result);
5911 tlbl1 = newiTempLabel (NULL);
5913 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5914 emitLabel (tlbl->key + 100);
5915 l = aopGet (AOP (result), offset, FALSE);
5919 l = aopGet (AOP (result), offset, FALSE);
5923 emit2 ("sla %s", l);
5931 emitLabel (tlbl1->key + 100);
5933 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5935 freeAsmop (left, NULL, ic);
5936 freeAsmop (result, NULL, ic);
5939 /*-----------------------------------------------------------------*/
5940 /* genrshOne - left shift two bytes by known amount != 0 */
5941 /*-----------------------------------------------------------------*/
5943 genrshOne (operand * result, operand * left, int shCount, int is_signed)
5946 int size = AOP_SIZE (result);
5949 wassert (size == 1);
5950 wassert (shCount < 8);
5952 l = aopGet (AOP (left), 0, FALSE);
5954 if (AOP (result)->type == AOP_REG)
5956 aopPut (AOP (result), l, 0);
5957 l = aopGet (AOP (result), 0, FALSE);
5960 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5968 emit2 ("%s a", is_signed ? "sra" : "srl");
5970 aopPut (AOP (result), "a", 0);
5974 /*-----------------------------------------------------------------*/
5975 /* AccRsh - right shift accumulator by known count */
5976 /*-----------------------------------------------------------------*/
5978 AccRsh (int shCount)
5980 static const unsigned char SRMask[] =
5982 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
5987 /* rotate right accumulator */
5988 AccRol (8 - shCount);
5989 /* and kill the higher order bits */
5990 emit2 ("and a,!immedbyte", SRMask[shCount]);
5994 /*-----------------------------------------------------------------*/
5995 /* shiftR1Left2Result - shift right one byte from left to result */
5996 /*-----------------------------------------------------------------*/
5998 shiftR1Left2Result (operand * left, int offl,
5999 operand * result, int offr,
6000 int shCount, int sign)
6002 _moveA (aopGet (AOP (left), offl, FALSE));
6007 emit2 ("%s a", sign ? "sra" : "srl");
6014 aopPut (AOP (result), "a", offr);
6017 /*-----------------------------------------------------------------*/
6018 /* genrshTwo - right shift two bytes by known amount != 0 */
6019 /*-----------------------------------------------------------------*/
6021 genrshTwo (operand * result, operand * left,
6022 int shCount, int sign)
6024 /* if shCount >= 8 */
6030 shiftR1Left2Result (left, MSB16, result, LSB,
6035 movLeft2Result (left, MSB16, result, LSB, sign);
6039 /* Sign extend the result */
6040 _moveA(aopGet (AOP (result), 0, FALSE));
6044 aopPut (AOP (result), ACC_NAME, MSB16);
6048 aopPut (AOP (result), "!zero", 1);
6051 /* 1 <= shCount <= 7 */
6054 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
6058 /*-----------------------------------------------------------------*/
6059 /* genRightShiftLiteral - left shifting by known count */
6060 /*-----------------------------------------------------------------*/
6062 genRightShiftLiteral (operand * left,
6068 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6071 freeAsmop (right, NULL, ic);
6073 aopOp (left, ic, FALSE, FALSE);
6074 aopOp (result, ic, FALSE, FALSE);
6076 size = getSize (operandType (result));
6078 /* I suppose that the left size >= result size */
6084 else if (shCount >= (size * 8)) {
6086 if (!SPEC_USIGN(getSpec(operandType(left)))) {
6087 _moveA(aopGet (AOP (left), 0, FALSE));
6095 aopPut (AOP (result), s, size);
6102 genrshOne (result, left, shCount, sign);
6105 genrshTwo (result, left, shCount, sign);
6108 wassertl (0, "Asked to shift right a long which should be a function call");
6111 wassertl (0, "Entered default case in right shift delegate");
6114 freeAsmop (left, NULL, ic);
6115 freeAsmop (result, NULL, ic);
6118 /*-----------------------------------------------------------------*/
6119 /* genRightShift - generate code for right shifting */
6120 /*-----------------------------------------------------------------*/
6122 genRightShift (iCode * ic)
6124 operand *right, *left, *result;
6126 int size, offset, first = 1;
6130 symbol *tlbl, *tlbl1;
6132 /* if signed then we do it the hard way preserve the
6133 sign bit moving it inwards */
6134 retype = getSpec (operandType (IC_RESULT (ic)));
6136 is_signed = !SPEC_USIGN (retype);
6138 /* signed & unsigned types are treated the same : i.e. the
6139 signed is NOT propagated inwards : quoting from the
6140 ANSI - standard : "for E1 >> E2, is equivalent to division
6141 by 2**E2 if unsigned or if it has a non-negative value,
6142 otherwise the result is implementation defined ", MY definition
6143 is that the sign does not get propagated */
6145 right = IC_RIGHT (ic);
6146 left = IC_LEFT (ic);
6147 result = IC_RESULT (ic);
6149 aopOp (right, ic, FALSE, FALSE);
6151 /* if the shift count is known then do it
6152 as efficiently as possible */
6153 if (AOP_TYPE (right) == AOP_LIT)
6155 genRightShiftLiteral (left, right, result, ic, is_signed);
6159 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6161 freeAsmop (right, NULL, ic);
6163 aopOp (left, ic, FALSE, FALSE);
6164 aopOp (result, ic, FALSE, FALSE);
6166 /* now move the left to the result if they are not the
6168 if (!sameRegs (AOP (left), AOP (result)))
6171 size = AOP_SIZE (result);
6175 l = aopGet (AOP (left), offset, FALSE);
6176 aopPut (AOP (result), l, offset);
6181 tlbl = newiTempLabel (NULL);
6182 tlbl1 = newiTempLabel (NULL);
6183 size = AOP_SIZE (result);
6186 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6187 emitLabel (tlbl->key + 100);
6190 l = aopGet (AOP (result), offset--, FALSE);
6193 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6201 emitLabel (tlbl1->key + 100);
6203 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6205 freeAsmop (left, NULL, ic);
6206 freeAsmop (result, NULL, ic);
6210 /*-----------------------------------------------------------------*/
6211 /* genUnpackBits - generates code for unpacking bits */
6212 /*-----------------------------------------------------------------*/
6214 genUnpackBits (operand * result, int pair)
6216 int offset = 0; /* result byte offset */
6217 int rsize; /* result size */
6218 int rlen = 0; /* remaining bitfield length */
6219 sym_link *etype; /* bitfield type information */
6220 int blen; /* bitfield length */
6221 int bstr; /* bitfield starting bit within byte */
6223 emitDebug ("; genUnpackBits");
6225 etype = getSpec (operandType (result));
6226 rsize = getSize (operandType (result));
6227 blen = SPEC_BLEN (etype);
6228 bstr = SPEC_BSTR (etype);
6230 /* If the bitfield length is less than a byte */
6233 emit2 ("ld a,!*pair", _pairs[pair].name);
6235 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6236 aopPut (AOP (result), "a", offset++);
6240 /* TODO: what if pair == PAIR_DE ? */
6241 if (getPairId (AOP (result)) == PAIR_HL)
6243 wassertl (rsize == 2, "HL must be of size 2");
6244 emit2 ("ld a,!*hl");
6246 emit2 ("ld h,!*hl");
6249 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6251 spillPair (PAIR_HL);
6255 /* Bit field did not fit in a byte. Copy all
6256 but the partial byte at the end. */
6257 for (rlen=blen;rlen>=8;rlen-=8)
6259 emit2 ("ld a,!*pair", _pairs[pair].name);
6260 aopPut (AOP (result), "a", offset++);
6263 emit2 ("inc %s", _pairs[pair].name);
6264 _G.pairs[pair].offset++;
6268 /* Handle the partial byte at the end */
6271 emit2 ("ld a,!*pair", _pairs[pair].name);
6272 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6273 aopPut (AOP (result), "a", offset++);
6281 aopPut (AOP (result), "!zero", offset++);
6285 /*-----------------------------------------------------------------*/
6286 /* genGenPointerGet - get value from generic pointer space */
6287 /*-----------------------------------------------------------------*/
6289 genGenPointerGet (operand * left,
6290 operand * result, iCode * ic)
6293 sym_link *retype = getSpec (operandType (result));
6299 aopOp (left, ic, FALSE, FALSE);
6300 aopOp (result, ic, FALSE, FALSE);
6302 size = AOP_SIZE (result);
6304 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6307 if (isPtrPair (AOP (left)))
6309 tsprintf (buffer, sizeof(buffer),
6310 "!*pair", getPairName (AOP (left)));
6311 aopPut (AOP (result), buffer, 0);
6315 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6316 aopPut (AOP (result), "a", 0);
6318 freeAsmop (left, NULL, ic);
6322 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6329 tsprintf (at, sizeof(at), "!*iyx", offset);
6330 aopPut (AOP (result), at, offset);
6334 freeAsmop (left, NULL, ic);
6338 /* For now we always load into IY */
6339 /* if this is remateriazable */
6340 fetchPair (pair, AOP (left));
6342 /* if bit then unpack */
6343 if (IS_BITVAR (retype))
6345 genUnpackBits (result, pair);
6346 freeAsmop (left, NULL, ic);
6350 else if (getPairId (AOP (result)) == PAIR_HL)
6352 wassertl (size == 2, "HL must be of size 2");
6353 emit2 ("ld a,!*hl");
6355 emit2 ("ld h,!*hl");
6357 spillPair (PAIR_HL);
6359 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6361 size = AOP_SIZE (result);
6366 /* PENDING: make this better */
6367 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6369 aopPut (AOP (result), "!*hl", offset++);
6373 emit2 ("ld a,!*pair", _pairs[pair].name);
6374 aopPut (AOP (result), "a", offset++);
6378 emit2 ("inc %s", _pairs[pair].name);
6379 _G.pairs[pair].offset++;
6382 /* Fixup HL back down */
6383 for (size = AOP_SIZE (result)-1; size; size--)
6385 emit2 ("dec %s", _pairs[pair].name);
6390 size = AOP_SIZE (result);
6395 /* PENDING: make this better */
6397 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6399 aopPut (AOP (result), "!*hl", offset++);
6403 emit2 ("ld a,!*pair", _pairs[pair].name);
6404 aopPut (AOP (result), "a", offset++);
6408 emit2 ("inc %s", _pairs[pair].name);
6409 _G.pairs[pair].offset++;
6414 freeAsmop (left, NULL, ic);
6417 freeAsmop (result, NULL, ic);
6420 /*-----------------------------------------------------------------*/
6421 /* genPointerGet - generate code for pointer get */
6422 /*-----------------------------------------------------------------*/
6424 genPointerGet (iCode * ic)
6426 operand *left, *result;
6427 sym_link *type, *etype;
6429 left = IC_LEFT (ic);
6430 result = IC_RESULT (ic);
6432 /* depending on the type of pointer we need to
6433 move it to the correct pointer register */
6434 type = operandType (left);
6435 etype = getSpec (type);
6437 genGenPointerGet (left, result, ic);
6441 isRegOrLit (asmop * aop)
6443 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6449 /*-----------------------------------------------------------------*/
6450 /* genPackBits - generates code for packed bit storage */
6451 /*-----------------------------------------------------------------*/
6453 genPackBits (sym_link * etype,
6458 int offset = 0; /* source byte offset */
6459 int rlen = 0; /* remaining bitfield length */
6460 int blen; /* bitfield length */
6461 int bstr; /* bitfield starting bit within byte */
6462 int litval; /* source literal value (if AOP_LIT) */
6463 unsigned char mask; /* bitmask within current byte */
6464 int extraPair; /* a tempory register */
6465 bool needPopExtra=0; /* need to restore original value of temp reg */
6467 emitDebug ("; genPackBits","");
6469 blen = SPEC_BLEN (etype);
6470 bstr = SPEC_BSTR (etype);
6472 /* If the bitfield length is less than a byte */
6475 mask = ((unsigned char) (0xFF << (blen + bstr)) |
6476 (unsigned char) (0xFF >> (8 - bstr)));
6478 if (AOP_TYPE (right) == AOP_LIT)
6480 /* Case with a bitfield length <8 and literal source
6482 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6484 litval &= (~mask) & 0xff;
6485 emit2 ("ld a,!*pair", _pairs[pair].name);
6486 if ((mask|litval)!=0xff)
6487 emit2 ("and a,!immedbyte", mask);
6489 emit2 ("or a,!immedbyte", litval);
6490 emit2 ("ld !*pair,a", _pairs[pair].name);
6495 /* Case with a bitfield length <8 and arbitrary source
6497 _moveA (aopGet (AOP (right), 0, FALSE));
6498 /* shift and mask source value */
6500 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6502 extraPair = getFreePairId(ic);
6503 if (extraPair == PAIR_INVALID)
6505 extraPair = PAIR_BC;
6506 if (getPairId (AOP (right)) != PAIR_BC
6507 || !isLastUse (ic, right))
6513 emit2 ("ld %s,a", _pairs[extraPair].l);
6514 emit2 ("ld a,!*pair", _pairs[pair].name);
6516 emit2 ("and a,!immedbyte", mask);
6517 emit2 ("or a,%s", _pairs[extraPair].l);
6518 emit2 ("ld !*pair,a", _pairs[pair].name);
6525 /* Bit length is greater than 7 bits. In this case, copy */
6526 /* all except the partial byte at the end */
6527 for (rlen=blen;rlen>=8;rlen-=8)
6529 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
6530 emit2 ("ld !*pair,a", _pairs[pair].name);
6533 emit2 ("inc %s", _pairs[pair].name);
6534 _G.pairs[pair].offset++;
6538 /* If there was a partial byte at the end */
6541 mask = (((unsigned char) -1 << rlen) & 0xff);
6543 if (AOP_TYPE (right) == AOP_LIT)
6545 /* Case with partial byte and literal source
6547 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6548 litval >>= (blen-rlen);
6549 litval &= (~mask) & 0xff;
6550 emit2 ("ld a,!*pair", _pairs[pair].name);
6551 if ((mask|litval)!=0xff)
6552 emit2 ("and a,!immedbyte", mask);
6554 emit2 ("or a,!immedbyte", litval);
6558 /* Case with partial byte and arbitrary source
6560 _moveA (aopGet (AOP (right), offset++, FALSE));
6561 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6563 extraPair = getFreePairId(ic);
6564 if (extraPair == PAIR_INVALID)
6566 extraPair = getPairId (AOP (right));
6567 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
6568 extraPair = PAIR_BC;
6570 if (getPairId (AOP (right)) != PAIR_BC
6571 || !isLastUse (ic, right))
6577 emit2 ("ld %s,a", _pairs[extraPair].l);
6578 emit2 ("ld a,!*pair", _pairs[pair].name);
6580 emit2 ("and a,!immedbyte", mask);
6581 emit2 ("or a,%s", _pairs[extraPair].l);
6586 emit2 ("ld !*pair,a", _pairs[pair].name);
6591 /*-----------------------------------------------------------------*/
6592 /* genGenPointerSet - stores the value into a pointer location */
6593 /*-----------------------------------------------------------------*/
6595 genGenPointerSet (operand * right,
6596 operand * result, iCode * ic)
6599 sym_link *retype = getSpec (operandType (right));
6600 sym_link *letype = getSpec (operandType (result));
6601 PAIR_ID pairId = PAIR_HL;
6604 aopOp (result, ic, FALSE, FALSE);
6605 aopOp (right, ic, FALSE, FALSE);
6610 size = AOP_SIZE (right);
6612 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
6613 emitDebug("; isBitvar = %d", isBitvar);
6615 /* Handle the exceptions first */
6616 if (isPair (AOP (result)) && size == 1 && !isBitvar)
6619 const char *l = aopGet (AOP (right), 0, FALSE);
6620 const char *pair = getPairName (AOP (result));
6621 if (canAssignToPtr (l) && isPtr (pair))
6623 emit2 ("ld !*pair,%s", pair, l);
6628 emit2 ("ld !*pair,a", pair);
6633 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
6636 const char *l = aopGet (AOP (right), 0, FALSE);
6641 if (canAssignToPtr (l))
6643 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6647 _moveA (aopGet (AOP (right), offset, FALSE));
6648 emit2 ("ld !*iyx,a", offset);
6654 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
6661 const char *l = aopGet (AOP (right), offset, FALSE);
6662 if (isRegOrLit (AOP (right)) && !IS_GB)
6664 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
6669 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
6673 emit2 ("inc %s", _pairs[PAIR_HL].name);
6674 _G.pairs[PAIR_HL].offset++;
6679 /* Fixup HL back down */
6680 for (size = AOP_SIZE (right)-1; size; size--)
6682 emit2 ("dec %s", _pairs[PAIR_HL].name);
6687 /* if the operand is already in dptr
6688 then we do nothing else we move the value to dptr */
6689 if (AOP_TYPE (result) != AOP_STR)
6691 fetchPair (pairId, AOP (result));
6693 /* so hl know contains the address */
6694 freeAsmop (result, NULL, ic);
6696 /* if bit then unpack */
6699 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
6709 const char *l = aopGet (AOP (right), offset, FALSE);
6710 if (isRegOrLit (AOP (right)) && !IS_GB)
6712 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
6717 emit2 ("ld !*pair,a", _pairs[pairId].name);
6721 emit2 ("inc %s", _pairs[pairId].name);
6722 _G.pairs[pairId].offset++;
6728 freeAsmop (right, NULL, ic);
6731 /*-----------------------------------------------------------------*/
6732 /* genPointerSet - stores the value into a pointer location */
6733 /*-----------------------------------------------------------------*/
6735 genPointerSet (iCode * ic)
6737 operand *right, *result;
6738 sym_link *type, *etype;
6740 right = IC_RIGHT (ic);
6741 result = IC_RESULT (ic);
6743 /* depending on the type of pointer we need to
6744 move it to the correct pointer register */
6745 type = operandType (result);
6746 etype = getSpec (type);
6748 genGenPointerSet (right, result, ic);
6751 /*-----------------------------------------------------------------*/
6752 /* genIfx - generate code for Ifx statement */
6753 /*-----------------------------------------------------------------*/
6755 genIfx (iCode * ic, iCode * popIc)
6757 operand *cond = IC_COND (ic);
6760 aopOp (cond, ic, FALSE, TRUE);
6762 /* get the value into acc */
6763 if (AOP_TYPE (cond) != AOP_CRY)
6767 /* the result is now in the accumulator */
6768 freeAsmop (cond, NULL, ic);
6770 /* if there was something to be popped then do it */
6774 /* if the condition is a bit variable */
6775 if (isbit && IS_ITEMP (cond) &&
6777 genIfxJump (ic, SPIL_LOC (cond)->rname);
6778 else if (isbit && !IS_ITEMP (cond))
6779 genIfxJump (ic, OP_SYMBOL (cond)->rname);
6781 genIfxJump (ic, "a");
6786 /*-----------------------------------------------------------------*/
6787 /* genAddrOf - generates code for address of */
6788 /*-----------------------------------------------------------------*/
6790 genAddrOf (iCode * ic)
6792 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
6794 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6796 /* if the operand is on the stack then we
6797 need to get the stack offset of this
6804 if (sym->stack <= 0)
6806 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
6810 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6812 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6816 emit2 ("ld de,!hashedstr", sym->rname);
6817 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
6825 /* if it has an offset then we need to compute it */
6827 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6829 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
6830 emit2 ("add hl,sp");
6834 emit2 ("ld hl,!hashedstr", sym->rname);
6836 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6838 freeAsmop (IC_RESULT (ic), NULL, ic);
6841 /*-----------------------------------------------------------------*/
6842 /* genAssign - generate code for assignment */
6843 /*-----------------------------------------------------------------*/
6845 genAssign (iCode * ic)
6847 operand *result, *right;
6849 unsigned long lit = 0L;
6851 result = IC_RESULT (ic);
6852 right = IC_RIGHT (ic);
6854 /* Dont bother assigning if they are the same */
6855 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6857 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
6861 aopOp (right, ic, FALSE, FALSE);
6862 aopOp (result, ic, TRUE, FALSE);
6864 /* if they are the same registers */
6865 if (sameRegs (AOP (right), AOP (result)))
6867 emitDebug ("; (registers are the same)");
6871 /* if the result is a bit */
6872 if (AOP_TYPE (result) == AOP_CRY)
6874 wassertl (0, "Tried to assign to a bit");
6878 size = AOP_SIZE (result);
6881 if (AOP_TYPE (right) == AOP_LIT)
6883 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6886 if (isPair (AOP (result)))
6888 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
6890 else if ((size > 1) &&
6891 (AOP_TYPE (result) != AOP_REG) &&
6892 (AOP_TYPE (right) == AOP_LIT) &&
6893 !IS_FLOAT (operandType (right)) &&
6896 bool fXored = FALSE;
6898 /* Work from the top down.
6899 Done this way so that we can use the cached copy of 0
6900 in A for a fast clear */
6903 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
6905 if (!fXored && size > 1)
6912 aopPut (AOP (result), "a", offset);
6916 aopPut (AOP (result), "!zero", offset);
6920 aopPut (AOP (result),
6921 aopGet (AOP (right), offset, FALSE),
6926 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
6928 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
6929 aopPut (AOP (result), "l", LSB);
6930 aopPut (AOP (result), "h", MSB16);
6932 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6934 /* Special case. Load into a and d, then load out. */
6935 _moveA (aopGet (AOP (right), 0, FALSE));
6936 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
6937 aopPut (AOP (result), "a", 0);
6938 aopPut (AOP (result), "e", 1);
6940 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6942 /* Special case - simple memcpy */
6943 aopGet (AOP (right), LSB, FALSE);
6946 aopGet (AOP (result), LSB, FALSE);
6950 emit2 ("ld a,(de)");
6951 /* Peephole will optimise this. */
6952 emit2 ("ld (hl),a");
6960 spillPair (PAIR_HL);
6966 /* PENDING: do this check better */
6967 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
6969 _moveA (aopGet (AOP (right), offset, FALSE));
6970 aopPut (AOP (result), "a", offset);
6973 aopPut (AOP (result),
6974 aopGet (AOP (right), offset, FALSE),
6981 freeAsmop (right, NULL, ic);
6982 freeAsmop (result, NULL, ic);
6985 /*-----------------------------------------------------------------*/
6986 /* genJumpTab - genrates code for jump table */
6987 /*-----------------------------------------------------------------*/
6989 genJumpTab (iCode * ic)
6994 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
6995 /* get the condition into accumulator */
6996 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
6999 emit2 ("ld e,%s", l);
7000 emit2 ("ld d,!zero");
7001 jtab = newiTempLabel (NULL);
7003 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
7004 emit2 ("add hl,de");
7005 emit2 ("add hl,de");
7006 emit2 ("add hl,de");
7007 freeAsmop (IC_JTCOND (ic), NULL, ic);
7011 emitLabel (jtab->key + 100);
7012 /* now generate the jump labels */
7013 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
7014 jtab = setNextItem (IC_JTLABELS (ic)))
7015 emit2 ("jp !tlabel", jtab->key + 100);
7018 /*-----------------------------------------------------------------*/
7019 /* genCast - gen code for casting */
7020 /*-----------------------------------------------------------------*/
7022 genCast (iCode * ic)
7024 operand *result = IC_RESULT (ic);
7025 sym_link *rtype = operandType (IC_RIGHT (ic));
7026 operand *right = IC_RIGHT (ic);
7029 /* if they are equivalent then do nothing */
7030 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7033 aopOp (right, ic, FALSE, FALSE);
7034 aopOp (result, ic, FALSE, FALSE);
7036 /* if the result is a bit */
7037 if (AOP_TYPE (result) == AOP_CRY)
7039 wassertl (0, "Tried to cast to a bit");
7042 /* if they are the same size : or less */
7043 if (AOP_SIZE (result) <= AOP_SIZE (right))
7046 /* if they are in the same place */
7047 if (sameRegs (AOP (right), AOP (result)))
7050 /* if they in different places then copy */
7051 size = AOP_SIZE (result);
7055 aopPut (AOP (result),
7056 aopGet (AOP (right), offset, FALSE),
7063 /* So we now know that the size of destination is greater
7064 than the size of the source */
7065 /* we move to result for the size of source */
7066 size = AOP_SIZE (right);
7070 aopPut (AOP (result),
7071 aopGet (AOP (right), offset, FALSE),
7076 /* now depending on the sign of the destination */
7077 size = AOP_SIZE (result) - AOP_SIZE (right);
7078 /* Unsigned or not an integral type - right fill with zeros */
7079 if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
7082 aopPut (AOP (result), "!zero", offset++);
7086 /* we need to extend the sign :{ */
7087 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
7093 aopPut (AOP (result), "a", offset++);
7097 freeAsmop (right, NULL, ic);
7098 freeAsmop (result, NULL, ic);
7101 /*-----------------------------------------------------------------*/
7102 /* genReceive - generate code for a receive iCode */
7103 /*-----------------------------------------------------------------*/
7105 genReceive (iCode * ic)
7107 if (isOperandInFarSpace (IC_RESULT (ic)) &&
7108 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7109 IS_TRUE_SYMOP (IC_RESULT (ic))))
7119 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7120 size = AOP_SIZE(IC_RESULT(ic));
7122 for (i = 0; i < size; i++) {
7123 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7127 freeAsmop (IC_RESULT (ic), NULL, ic);
7130 /*-----------------------------------------------------------------*/
7131 /* genDummyRead - generate code for dummy read of volatiles */
7132 /*-----------------------------------------------------------------*/
7134 genDummyRead (iCode * ic)
7139 right = IC_RIGHT (ic);
7140 aopOp (right, ic, FALSE, FALSE);
7143 size = AOP_SIZE (right);
7148 _moveA (aopGet (AOP (right), offset, FALSE));
7152 freeAsmop (right, NULL, ic);
7157 /** Maximum number of bytes to emit per line. */
7161 /** Context for the byte output chunker. */
7164 unsigned char buffer[DBEMIT_MAX_RUN];
7169 /** Flushes a byte chunker by writing out all in the buffer and
7173 _dbFlush(DBEMITCTX *self)
7180 sprintf(line, ".db 0x%02X", self->buffer[0]);
7182 for (i = 1; i < self->pos; i++)
7184 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7191 /** Write out another byte, buffering until a decent line is
7195 _dbEmit(DBEMITCTX *self, int c)
7197 if (self->pos == DBEMIT_MAX_RUN)
7201 self->buffer[self->pos++] = c;
7204 /** Context for a simple run length encoder. */
7208 unsigned char buffer[128];
7210 /** runLen may be equivalent to pos. */
7216 RLE_CHANGE_COST = 4,
7220 /** Flush the buffer of a run length encoder by writing out the run or
7221 data that it currently contains.
7224 _rleCommit(RLECTX *self)
7230 memset(&db, 0, sizeof(db));
7232 emit2(".db %u", self->pos);
7234 for (i = 0; i < self->pos; i++)
7236 _dbEmit(&db, self->buffer[i]);
7245 Can get either a run or a block of random stuff.
7246 Only want to change state if a good run comes in or a run ends.
7247 Detecting run end is easy.
7250 Say initial state is in run, len zero, last zero. Then if you get a
7251 few zeros then something else then a short run will be output.
7252 Seems OK. While in run mode, keep counting. While in random mode,
7253 keep a count of the run. If run hits margin, output all up to run,
7254 restart, enter run mode.
7257 /** Add another byte into the run length encoder, flushing as
7258 required. The run length encoder uses the Amiga IFF style, where
7259 a block is prefixed by its run length. A positive length means
7260 the next n bytes pass straight through. A negative length means
7261 that the next byte is repeated -n times. A zero terminates the
7265 _rleAppend(RLECTX *self, int c)
7269 if (c != self->last)
7271 /* The run has stopped. See if it is worthwhile writing it out
7272 as a run. Note that the random data comes in as runs of
7275 if (self->runLen > RLE_CHANGE_COST)
7277 /* Yes, worthwhile. */
7278 /* Commit whatever was in the buffer. */
7280 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7284 /* Not worthwhile. Append to the end of the random list. */
7285 for (i = 0; i < self->runLen; i++)
7287 if (self->pos >= RLE_MAX_BLOCK)
7292 self->buffer[self->pos++] = self->last;
7300 if (self->runLen >= RLE_MAX_BLOCK)
7302 /* Commit whatever was in the buffer. */
7305 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7313 _rleFlush(RLECTX *self)
7315 _rleAppend(self, -1);
7322 /** genArrayInit - Special code for initialising an array with constant
7326 genArrayInit (iCode * ic)
7330 int elementSize = 0, eIndex, i;
7331 unsigned val, lastVal;
7335 memset(&rle, 0, sizeof(rle));
7337 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7339 _saveRegsForCall(ic, 0);
7341 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7342 emit2 ("call __initrleblock");
7344 type = operandType(IC_LEFT(ic));
7346 if (type && type->next)
7348 elementSize = getSize(type->next);
7352 wassertl (0, "Can't determine element size in genArrayInit.");
7355 iLoop = IC_ARRAYILIST(ic);
7356 lastVal = (unsigned)-1;
7358 /* Feed all the bytes into the run length encoder which will handle
7360 This works well for mixed char data, and for random int and long
7369 for (i = 0; i < ix; i++)
7371 for (eIndex = 0; eIndex < elementSize; eIndex++)
7373 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7374 _rleAppend(&rle, val);
7379 iLoop = iLoop->next;
7383 /* Mark the end of the run. */
7386 _restoreRegsAfterCall();
7390 freeAsmop (IC_LEFT(ic), NULL, ic);
7394 _swap (PAIR_ID one, PAIR_ID two)
7396 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7402 emit2 ("ld a,%s", _pairs[one].l);
7403 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7404 emit2 ("ld %s,a", _pairs[two].l);
7405 emit2 ("ld a,%s", _pairs[one].h);
7406 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7407 emit2 ("ld %s,a", _pairs[two].h);
7411 /* The problem is that we may have all three pairs used and they may
7412 be needed in a different order.
7417 hl = hl => unity, fine
7421 hl = hl hl = hl, swap de <=> bc
7429 hl = bc de = de, swap bc <=> hl
7437 hl = de bc = bc, swap hl <=> de
7442 * Any pair = pair are done last
7443 * Any pair = iTemp are done last
7444 * Any swaps can be done any time
7452 So how do we detect the cases?
7453 How about a 3x3 matrix?
7457 x x x x (Fourth for iTemp/other)
7459 First determin which mode to use by counting the number of unity and
7462 Two - Assign the pair first, then the rest
7463 One - Swap the two, then the rest
7467 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7469 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7471 PAIR_BC, PAIR_HL, PAIR_DE
7473 int i, j, nunity = 0;
7474 memset (ids, PAIR_INVALID, sizeof (ids));
7477 wassert (nparams == 3);
7479 /* First save everything that needs to be saved. */
7480 _saveRegsForCall (ic, 0);
7482 /* Loading HL first means that DE is always fine. */
7483 for (i = 0; i < nparams; i++)
7485 aopOp (pparams[i], ic, FALSE, FALSE);
7486 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7489 /* Count the number of unity or iTemp assigns. */
7490 for (i = 0; i < 3; i++)
7492 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7500 /* Any order, fall through. */
7502 else if (nunity == 2)
7504 /* One is assigned. Pull it out and assign. */
7505 for (i = 0; i < 3; i++)
7507 for (j = 0; j < NUM_PAIRS; j++)
7509 if (ids[dest[i]][j] == TRUE)
7511 /* Found it. See if it's the right one. */
7512 if (j == PAIR_INVALID || j == dest[i])
7518 fetchPair(dest[i], AOP (pparams[i]));
7525 else if (nunity == 1)
7527 /* Find the pairs to swap. */
7528 for (i = 0; i < 3; i++)
7530 for (j = 0; j < NUM_PAIRS; j++)
7532 if (ids[dest[i]][j] == TRUE)
7534 if (j == PAIR_INVALID || j == dest[i])
7549 int next = getPairId (AOP (pparams[0]));
7550 emit2 ("push %s", _pairs[next].name);
7552 if (next == dest[1])
7554 fetchPair (dest[1], AOP (pparams[1]));
7555 fetchPair (dest[2], AOP (pparams[2]));
7559 fetchPair (dest[2], AOP (pparams[2]));
7560 fetchPair (dest[1], AOP (pparams[1]));
7562 emit2 ("pop %s", _pairs[dest[0]].name);
7565 /* Finally pull out all of the iTemps */
7566 for (i = 0; i < 3; i++)
7568 if (ids[dest[i]][PAIR_INVALID] == 1)
7570 fetchPair (dest[i], AOP (pparams[i]));
7576 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
7582 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
7586 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7588 setupForBuiltin3 (ic, nParams, pparams);
7590 label = newiTempLabel(NULL);
7592 emitLabel (label->key);
7593 emit2 ("ld a,(hl)");
7596 emit2 ("!shortjp nz,!tlabel ; 1", label->key);
7598 freeAsmop (from, NULL, ic->next);
7599 freeAsmop (to, NULL, ic);
7603 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
7605 operand *from, *to, *count;
7608 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
7613 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7615 setupForBuiltin3 (ic, nParams, pparams);
7619 freeAsmop (count, NULL, ic->next->next);
7620 freeAsmop (from, NULL, ic);
7622 _restoreRegsAfterCall();
7624 /* if we need assign a result value */
7625 if ((IS_ITEMP (IC_RESULT (ic)) &&
7626 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
7627 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
7628 IS_TRUE_SYMOP (IC_RESULT (ic)))
7630 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7631 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
7632 freeAsmop (IC_RESULT (ic), NULL, ic);
7635 freeAsmop (to, NULL, ic->next);
7638 /*-----------------------------------------------------------------*/
7639 /* genBuiltIn - calls the appropriate function to generating code */
7640 /* for a built in function */
7641 /*-----------------------------------------------------------------*/
7642 static void genBuiltIn (iCode *ic)
7644 operand *bi_parms[MAX_BUILTIN_ARGS];
7649 /* get all the arguments for a built in function */
7650 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
7652 /* which function is it */
7653 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
7655 if (strcmp(bif->name,"__builtin_strcpy")==0)
7657 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
7659 else if (strcmp(bif->name,"__builtin_memcpy")==0)
7661 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
7665 wassertl (0, "Unknown builtin function encountered");
7669 /*-----------------------------------------------------------------*/
7670 /* genZ80Code - generate code for Z80 based controllers */
7671 /*-----------------------------------------------------------------*/
7673 genZ80Code (iCode * lic)
7681 _fReturn = _gbz80_return;
7682 _fTmp = _gbz80_return;
7686 _fReturn = _z80_return;
7687 _fTmp = _z80_return;
7690 _G.lines.head = _G.lines.current = NULL;
7692 /* if debug information required */
7693 if (options.debug && currFunc)
7695 debugFile->writeFunction(currFunc);
7696 _G.lines.isDebug = 1;
7697 if (IS_STATIC (currFunc->etype))
7698 sprintf (buffer, "F%s$%s$0$0", moduleName, currFunc->name);
7700 sprintf (buffer, "G$%s$0$0", currFunc->name);
7701 emit2 ("!labeldef", buffer);
7702 _G.lines.isDebug = 0;
7705 for (ic = lic; ic; ic = ic->next)
7707 _G.current_iCode = ic;
7709 if (ic->lineno && cln != ic->lineno)
7713 _G.lines.isDebug = 1;
7714 sprintf (buffer, "C$%s$%d$%d$%d",
7715 FileBaseName (ic->filename), ic->lineno,
7716 ic->level, ic->block);
7717 emit2 ("%s !equ .", buffer);
7718 emit2 ("!global", buffer);
7719 _G.lines.isDebug = 0;
7721 if (!options.noCcodeInAsm) {
7722 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
7723 printCLine(ic->filename, ic->lineno));
7727 if (options.iCodeInAsm) {
7728 emit2 (";ic:%d: %s", ic->key, printILine(ic));
7730 /* if the result is marked as
7731 spilt and rematerializable or code for
7732 this has already been generated then
7734 if (resultRemat (ic) || ic->generated)
7737 /* depending on the operation */
7741 emitDebug ("; genNot");
7746 emitDebug ("; genCpl");
7751 emitDebug ("; genUminus");
7756 emitDebug ("; genIpush");
7761 /* IPOP happens only when trying to restore a
7762 spilt live range, if there is an ifx statement
7763 following this pop then the if statement might
7764 be using some of the registers being popped which
7765 would destory the contents of the register so
7766 we need to check for this condition and handle it */
7768 ic->next->op == IFX &&
7769 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
7771 emitDebug ("; genIfx");
7772 genIfx (ic->next, ic);
7776 emitDebug ("; genIpop");
7782 emitDebug ("; genCall");
7787 emitDebug ("; genPcall");
7792 emitDebug ("; genFunction");
7797 emitDebug ("; genEndFunction");
7798 genEndFunction (ic);
7802 emitDebug ("; genRet");
7807 emitDebug ("; genLabel");
7812 emitDebug ("; genGoto");
7817 emitDebug ("; genPlus");
7822 emitDebug ("; genMinus");
7827 emitDebug ("; genMult");
7832 emitDebug ("; genDiv");
7837 emitDebug ("; genMod");
7842 emitDebug ("; genCmpGt");
7843 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
7847 emitDebug ("; genCmpLt");
7848 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
7855 /* note these two are xlated by algebraic equivalence
7856 during parsing SDCC.y */
7857 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
7858 "got '>=' or '<=' shouldn't have come here");
7862 emitDebug ("; genCmpEq");
7863 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
7867 emitDebug ("; genAndOp");
7872 emitDebug ("; genOrOp");
7877 emitDebug ("; genXor");
7878 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
7882 emitDebug ("; genOr");
7883 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
7887 emitDebug ("; genAnd");
7888 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
7892 emitDebug ("; genInline");
7897 emitDebug ("; genRRC");
7902 emitDebug ("; genRLC");
7907 emitDebug ("; genGetHBIT");
7912 emitDebug ("; genLeftShift");
7917 emitDebug ("; genRightShift");
7921 case GET_VALUE_AT_ADDRESS:
7922 emitDebug ("; genPointerGet");
7928 if (POINTER_SET (ic))
7930 emitDebug ("; genAssign (pointer)");
7935 emitDebug ("; genAssign");
7941 emitDebug ("; genIfx");
7946 emitDebug ("; genAddrOf");
7951 emitDebug ("; genJumpTab");
7956 emitDebug ("; genCast");
7961 emitDebug ("; genReceive");
7966 if (ic->builtinSEND)
7968 emitDebug ("; genBuiltIn");
7973 emitDebug ("; addSet");
7974 addSet (&_G.sendSet, ic);
7979 emitDebug ("; genArrayInit");
7983 case DUMMY_READ_VOLATILE:
7984 emitDebug ("; genDummyRead");
7994 /* now we are ready to call the
7995 peep hole optimizer */
7996 if (!options.nopeep)
7997 peepHole (&_G.lines.head);
7999 /* This is unfortunate */
8000 /* now do the actual printing */
8002 FILE *fp = codeOutFile;
8003 if (isInHome () && codeOutFile == code->oFile)
8004 codeOutFile = home->oFile;
8005 printLine (_G.lines.head, codeOutFile);
8006 if (_G.flushStatics)
8009 _G.flushStatics = 0;
8014 freeTrace(&_G.lines.trace);
8015 freeTrace(&_G.trace.aops);
8021 _isPairUsed (iCode * ic, PAIR_ID pairId)
8027 if (bitVectBitValue (ic->rMask, D_IDX))
8029 if (bitVectBitValue (ic->rMask, E_IDX))
8039 fetchLitSpecial (asmop * aop, bool negate, bool xor)
8042 value *val = aop->aopu.aop_lit;
8044 wassert (aop->type == AOP_LIT);
8045 wassert (!IS_FLOAT (val->type));
8047 v = (unsigned long) floatFromVal (val);
8055 tsprintf (buffer, sizeof(buffer), "!immedword", v);
8056 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));