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;
230 /** TRUE if the registers have already been saved. */
249 static const char *aopGet (asmop * aop, int offset, bool bit16);
251 static const char *aopNames[] = {
272 isLastUse (iCode *ic, operand *op)
274 bitVect *uses = bitVectCopy (OP_USES (op));
276 while (!bitVectIsZero (uses))
278 if (bitVectFirstBit (uses) == ic->key)
280 if (bitVectnBitsOn (uses) == 1)
289 bitVectUnSetBit (uses, bitVectFirstBit (uses));
309 _getTempPairName(void)
311 return _pairs[_getTempPairId()].name;
315 isPairInUse (PAIR_ID id, iCode *ic)
319 return bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
321 else if (id == PAIR_BC)
323 return bitVectBitValue (ic->rMask, B_IDX) || bitVectBitValue(ic->rMask, C_IDX);
327 wassertl (0, "Only implemented for DE and BC");
333 isPairInUseNotInRet(PAIR_ID id, iCode *ic)
337 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
341 return bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
345 wassertl (0, "Only implemented for DE");
351 getFreePairId (iCode *ic)
353 if (!isPairInUse (PAIR_BC, ic))
357 else if (IS_Z80 && !isPairInUse (PAIR_DE, ic))
370 /* Clean up the line so that it is 'prettier' */
371 if (strchr (buf, ':'))
373 /* Is a label - cant do anything */
376 /* Change the first (and probably only) ' ' to a tab so
391 _newLineNode (char *line)
395 pl = traceAlloc(&_G.lines.trace, Safe_alloc ( sizeof (lineNode)));
396 pl->line = traceAlloc(&_G.lines.trace, Safe_strdup (line));
402 _vemit2 (const char *szFormat, va_list ap)
404 char buffer[INITIAL_INLINEASM];
406 tvsprintf (buffer, sizeof(buffer), szFormat, ap);
409 _G.lines.current = (_G.lines.current ?
410 connectLine (_G.lines.current, _newLineNode (buffer)) :
411 (_G.lines.head = _newLineNode (buffer)));
413 _G.lines.current->isInline = _G.lines.isInline;
414 _G.lines.current->isDebug = _G.lines.isDebug;
415 _G.lines.current->ic = _G.current_iCode;
419 emit2 (const char *szFormat,...)
423 va_start (ap, szFormat);
425 _vemit2 (szFormat, ap);
431 emitDebug (const char *szFormat,...)
437 va_start (ap, szFormat);
439 _vemit2 (szFormat, ap);
445 /*-----------------------------------------------------------------*/
446 /* emit2 - writes the code into a file : for now it is simple */
447 /*-----------------------------------------------------------------*/
449 _emit2 (const char *inst, const char *fmt,...)
452 char lb[INITIAL_INLINEASM];
459 sprintf (lb, "%s\t", inst);
460 vsprintf (lb + (strlen (lb)), fmt, ap);
463 vsprintf (lb, fmt, ap);
465 while (isspace (*lbp))
470 _G.lines.current = (_G.lines.current ?
471 connectLine (_G.lines.current, _newLineNode (lb)) :
472 (_G.lines.head = _newLineNode (lb)));
474 _G.lines.current->isInline = _G.lines.isInline;
475 _G.lines.current->ic = _G.current_iCode;
480 _emitMove(const char *to, const char *from)
482 if (STRCASECMP(to, from) != 0)
484 emit2("ld %s,%s", to, from);
489 // Could leave this to the peephole, but sometimes the peephole is inhibited.
494 aopDump(const char *plabel, asmop *aop)
500 emitDebug("; Dump of %s: type %s size %u", plabel, aopNames[aop->type], aop->size);
505 emitDebug("; aop_stk %d", aop->aopu.aop_stk);
508 for (i=aop->size-1;i>=0;i--)
509 *rbp++ = *(aop->aopu.aop_reg[i]->name);
511 emitDebug("; reg = %s", regbuf);
514 emitDebug("; pairptr = (%s)", _pairs[aop->aopu.aop_pairId].name);
517 /* No information. */
523 _moveA(const char *moveFrom)
525 // Let the peephole optimiser take care of redundent loads
526 _emitMove(ACC_NAME, moveFrom);
536 getPairName (asmop * aop)
538 if (aop->type == AOP_REG)
540 switch (aop->aopu.aop_reg[0]->rIdx)
553 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
556 for (i = 0; i < NUM_PAIRS; i++)
558 if (strcmp(aop->aopu.aop_str[0], _pairs[i].l) == 0)
560 return _pairs[i].name;
564 wassertl (0, "Tried to get the pair name of something that isn't a pair");
569 getPairId (asmop * aop)
573 if (aop->type == AOP_REG)
575 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX) && (aop->aopu.aop_reg[1]->rIdx == B_IDX))
579 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX) && (aop->aopu.aop_reg[1]->rIdx == D_IDX))
583 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX) && (aop->aopu.aop_reg[1]->rIdx == H_IDX))
588 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
591 for (i = 0; i < NUM_PAIRS; i++)
593 if (!strcmp (aop->aopu.aop_str[0], _pairs[i].l) && !strcmp (aop->aopu.aop_str[1], _pairs[i].h))
603 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
607 return (getPairId (aop) != PAIR_INVALID);
610 /** Returns TRUE if the registers used in aop cannot be split into high
613 isUnsplitable (asmop * aop)
615 switch (getPairId (aop))
627 isPtrPair (asmop * aop)
629 PAIR_ID pairId = getPairId (aop);
642 spillPair (PAIR_ID pairId)
644 _G.pairs[pairId].last_type = AOP_INVALID;
645 _G.pairs[pairId].base = NULL;
648 /* Given a register name, spill the pair (if any) the register is part of */
650 spillPairReg (const char *regname)
652 if (strlen(regname)==1)
672 /** Push a register pair onto the stack */
674 genPairPush (asmop * aop)
676 emit2 ("push %s", getPairName (aop));
680 _push (PAIR_ID pairId)
682 emit2 ("push %s", _pairs[pairId].name);
683 _G.stack.pushed += 2;
687 _pop (PAIR_ID pairId)
689 emit2 ("pop %s", _pairs[pairId].name);
690 _G.stack.pushed -= 2;
695 genMovePairPair (PAIR_ID srcPair, PAIR_ID dstPair)
708 if (srcPair == PAIR_IX || srcPair == PAIR_IY)
715 emit2("ld %s,%s",_pairs[dstPair].l,_pairs[srcPair].l);
716 emit2("ld %s,%s",_pairs[dstPair].h,_pairs[srcPair].h);
719 wassertl (0, "Tried to move a nonphysical pair");
721 _G.pairs[dstPair].last_type = _G.pairs[srcPair].last_type;
722 _G.pairs[dstPair].base = _G.pairs[srcPair].base;
723 _G.pairs[dstPair].offset = _G.pairs[srcPair].offset;
727 /*-----------------------------------------------------------------*/
728 /* newAsmop - creates a new asmOp */
729 /*-----------------------------------------------------------------*/
731 newAsmop (short type)
735 aop = traceAlloc(&_G.trace.aops, Safe_alloc (sizeof (asmop)));
740 /*-----------------------------------------------------------------*/
741 /* aopForSym - for a true symbol */
742 /*-----------------------------------------------------------------*/
744 aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
751 wassert (sym->etype);
753 space = SPEC_OCLS (sym->etype);
755 /* if already has one */
761 /* Assign depending on the storage class */
762 if (sym->onStack || sym->iaccess)
764 /* The pointer that is used depends on how big the offset is.
765 Normally everything is AOP_STK, but for offsets of < -128 or
766 > 127 on the Z80 an extended stack pointer is used.
768 if (IS_Z80 && (_G.omitFramePtr || sym->stack < INT8MIN || sym->stack > (int)(INT8MAX-getSize (sym->type))))
770 emitDebug ("; AOP_EXSTK for %s", sym->rname);
771 sym->aop = aop = newAsmop (AOP_EXSTK);
775 emitDebug ("; AOP_STK for %s", sym->rname);
776 sym->aop = aop = newAsmop (AOP_STK);
779 aop->size = getSize (sym->type);
780 aop->aopu.aop_stk = sym->stack;
784 /* special case for a function */
785 if (IS_FUNC (sym->type))
787 sym->aop = aop = newAsmop (AOP_IMMD);
788 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup (sym->rname));
795 /* if it is in direct space */
796 if (IN_REGSP (space) && !requires_a)
798 sym->aop = aop = newAsmop (AOP_SFR);
799 aop->aopu.aop_dir = sym->rname;
800 aop->size = getSize (sym->type);
801 emitDebug ("; AOP_SFR for %s", sym->rname);
806 /* only remaining is far space */
807 /* in which case DPTR gets the address */
810 emitDebug ("; AOP_HL for %s", sym->rname);
811 sym->aop = aop = newAsmop (AOP_HL);
815 sym->aop = aop = newAsmop (AOP_IY);
817 aop->size = getSize (sym->type);
818 aop->aopu.aop_dir = sym->rname;
820 /* if it is in code space */
821 if (IN_CODESPACE (space))
827 /*-----------------------------------------------------------------*/
828 /* aopForRemat - rematerialzes an object */
829 /*-----------------------------------------------------------------*/
831 aopForRemat (symbol * sym)
834 iCode *ic = sym->rematiCode;
835 asmop *aop = newAsmop (AOP_IMMD);
839 /* if plus or minus print the right hand side */
840 if (ic->op == '+' || ic->op == '-')
842 /* PENDING: for re-target */
843 sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
846 ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
849 /* we reached the end */
850 sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
854 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
858 /*-----------------------------------------------------------------*/
859 /* regsInCommon - two operands have some registers in common */
860 /*-----------------------------------------------------------------*/
862 regsInCommon (operand * op1, operand * op2)
867 /* if they have registers in common */
868 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
871 sym1 = OP_SYMBOL (op1);
872 sym2 = OP_SYMBOL (op2);
874 if (sym1->nRegs == 0 || sym2->nRegs == 0)
877 for (i = 0; i < sym1->nRegs; i++)
883 for (j = 0; j < sym2->nRegs; j++)
888 if (sym2->regs[j] == sym1->regs[i])
896 /*-----------------------------------------------------------------*/
897 /* operandsEqu - equivalent */
898 /*-----------------------------------------------------------------*/
900 operandsEqu (operand * op1, operand * op2)
904 /* if they not symbols */
905 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
908 sym1 = OP_SYMBOL (op1);
909 sym2 = OP_SYMBOL (op2);
911 /* if both are itemps & one is spilt
912 and the other is not then false */
913 if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
914 sym1->isspilt != sym2->isspilt)
917 /* if they are the same */
921 if (strcmp (sym1->rname, sym2->rname) == 0)
925 /* if left is a tmp & right is not */
926 if (IS_ITEMP (op1) &&
929 (sym1->usl.spillLoc == sym2))
932 if (IS_ITEMP (op2) &&
936 (sym2->usl.spillLoc == sym1))
942 /*-----------------------------------------------------------------*/
943 /* sameRegs - two asmops have the same registers */
944 /*-----------------------------------------------------------------*/
946 sameRegs (asmop * aop1, asmop * aop2)
950 if (aop1->type == AOP_SFR ||
951 aop2->type == AOP_SFR)
957 if (aop1->type != AOP_REG ||
958 aop2->type != AOP_REG)
961 if (aop1->size != aop2->size)
964 for (i = 0; i < aop1->size; i++)
965 if (aop1->aopu.aop_reg[i] !=
966 aop2->aopu.aop_reg[i])
972 /*-----------------------------------------------------------------*/
973 /* aopOp - allocates an asmop for an operand : */
974 /*-----------------------------------------------------------------*/
976 aopOp (operand * op, iCode * ic, bool result, bool requires_a)
985 /* if this a literal */
986 if (IS_OP_LITERAL (op))
988 op->aop = aop = newAsmop (AOP_LIT);
989 aop->aopu.aop_lit = op->operand.valOperand;
990 aop->size = getSize (operandType (op));
994 /* if already has a asmop then continue */
1000 /* if the underlying symbol has a aop */
1001 if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
1003 op->aop = OP_SYMBOL (op)->aop;
1007 /* if this is a true symbol */
1008 if (IS_TRUE_SYMOP (op))
1010 op->aop = aopForSym (ic, OP_SYMBOL (op), result, requires_a);
1014 /* this is a temporary : this has
1020 e) can be a return use only */
1022 sym = OP_SYMBOL (op);
1024 /* if the type is a conditional */
1025 if (sym->regType == REG_CND)
1027 aop = op->aop = sym->aop = newAsmop (AOP_CRY);
1032 /* if it is spilt then two situations
1034 b) has a spill location */
1035 if (sym->isspilt || sym->nRegs == 0)
1037 /* rematerialize it NOW */
1040 sym->aop = op->aop = aop =
1042 aop->size = getSize (sym->type);
1049 aop = op->aop = sym->aop = newAsmop (AOP_STR);
1050 aop->size = getSize (sym->type);
1051 for (i = 0; i < 4; i++)
1052 aop->aopu.aop_str[i] = _fReturn[i];
1058 if (sym->accuse == ACCUSE_A)
1060 aop = op->aop = sym->aop = newAsmop (AOP_ACC);
1061 aop->size = getSize (sym->type);
1062 wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
1064 aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
1066 else if (sym->accuse == ACCUSE_SCRATCH)
1068 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
1069 aop->size = getSize (sym->type);
1070 wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
1071 aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
1072 aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
1074 else if (sym->accuse == ACCUSE_IY)
1076 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
1077 aop->size = getSize (sym->type);
1078 wassertl(aop->size <= 2, "Internal error: Caching in IY, but too big to fit in IY");
1079 aop->aopu.aop_str[0] = _pairs[PAIR_IY].l;
1080 aop->aopu.aop_str[1] = _pairs[PAIR_IY].h;
1084 wassertl (0, "Marked as being allocated into A or HL but is actually in neither");
1089 if (sym->usl.spillLoc)
1091 if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1093 /* force a new aop if sizes differ */
1094 sym->usl.spillLoc->aop = NULL;
1096 sym->aop = op->aop = aop =
1097 aopForSym (ic, sym->usl.spillLoc, result, requires_a);
1098 aop->size = getSize (sym->type);
1102 /* else must be a dummy iTemp */
1103 sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1104 aop->size = getSize (sym->type);
1108 /* must be in a register */
1109 sym->aop = op->aop = aop = newAsmop (AOP_REG);
1110 aop->size = sym->nRegs;
1111 for (i = 0; i < sym->nRegs; i++)
1112 aop->aopu.aop_reg[i] = sym->regs[i];
1115 /*-----------------------------------------------------------------*/
1116 /* freeAsmop - free up the asmop given to an operand */
1117 /*----------------------------------------------------------------*/
1119 freeAsmop (operand * op, asmop * aaop, iCode * ic)
1136 if (aop->type == AOP_PAIRPTR && IS_Z80 && aop->aopu.aop_pairId == PAIR_DE)
1138 _pop (aop->aopu.aop_pairId);
1141 if (getPairId (aop) == PAIR_HL)
1143 spillPair (PAIR_HL);
1147 /* all other cases just dealloc */
1153 OP_SYMBOL (op)->aop = NULL;
1154 /* if the symbol has a spill */
1156 SPIL_LOC (op)->aop = NULL;
1163 isLitWord (asmop * aop)
1165 /* if (aop->size != 2)
1178 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
1180 /* depending on type */
1186 /* PENDING: for re-target */
1189 tsprintf (buffer, sizeof(buffer),
1190 "!hashedstr + %d", aop->aopu.aop_immd, offset);
1192 else if (offset == 0)
1194 tsprintf (buffer, sizeof(buffer),
1195 "%s", aop->aopu.aop_immd);
1199 tsprintf (buffer, sizeof(buffer),
1200 "%s + %d", aop->aopu.aop_immd, offset);
1202 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1206 value *val = aop->aopu.aop_lit;
1207 /* if it is a float then it gets tricky */
1208 /* otherwise it is fairly simple */
1209 if (!IS_FLOAT (val->type))
1211 unsigned long v = (unsigned long) floatFromVal (val);
1217 else if (offset == 0)
1223 wassertl(0, "Encountered an invalid offset while fetching a literal");
1227 tsprintf (buffer, sizeof(buffer), "!immedword", v);
1229 tsprintf (buffer, sizeof(buffer), "!constword", v);
1231 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1242 /* it is type float */
1243 fl.f = (float) floatFromVal (val);
1245 #ifdef WORDS_BIGENDIAN
1246 i = fl.c[3-offset] | (fl.c[3-offset-1]<<8);
1248 i = fl.c[offset] | (fl.c[offset+1]<<8);
1251 tsprintf (buffer, sizeof(buffer), "!immedword", i);
1253 tsprintf (buffer, sizeof(buffer), "!constword", i);
1255 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1264 aopGetWord (asmop * aop, int offset)
1266 return aopGetLitWordLong (aop, offset, TRUE);
1270 isPtr (const char *s)
1272 if (!strcmp (s, "hl"))
1274 if (!strcmp (s, "ix"))
1276 if (!strcmp (s, "iy"))
1282 adjustPair (const char *pair, int *pold, int new)
1288 emit2 ("inc %s", pair);
1293 emit2 ("dec %s", pair);
1301 spillPair (PAIR_HL);
1302 spillPair (PAIR_IY);
1306 requiresHL (asmop * aop)
1322 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1324 const char *l, *base;
1325 const char *pair = _pairs[pairId].name;
1326 l = aopGetLitWordLong (left, offset, FALSE);
1327 base = aopGetLitWordLong (left, 0, FALSE);
1328 wassert (l && pair && base);
1332 if (pairId == PAIR_HL || pairId == PAIR_IY)
1334 if (_G.pairs[pairId].last_type == left->type)
1336 if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1338 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1340 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1343 if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
1350 _G.pairs[pairId].last_type = left->type;
1351 _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1352 _G.pairs[pairId].offset = offset;
1354 /* Both a lit on the right and a true symbol on the left */
1355 emit2 ("ld %s,!hashedstr", pair, l);
1359 makeFreePairId (iCode *ic, bool *pisUsed)
1365 if (!bitVectBitValue (ic->rMask, B_IDX) && !bitVectBitValue(ic->rMask, C_IDX))
1369 else if (IS_Z80 && !bitVectBitValue (ic->rMask, D_IDX) && !bitVectBitValue(ic->rMask, E_IDX))
1387 fetchPairLong (PAIR_ID pairId, asmop * aop, iCode *ic, int offset)
1389 /* if this is remateriazable */
1390 if (isLitWord (aop)) {
1391 fetchLitPair (pairId, aop, offset);
1395 if (getPairId (aop) == pairId)
1399 /* we need to get it byte by byte */
1400 else if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1401 aopGet (aop, offset, FALSE);
1402 switch (aop->size - offset) {
1404 emit2 ("ld l,!*hl");
1405 emit2 ("ld h,!immedbyte", 0);
1408 // PENDING: Requires that you are only fetching two bytes.
1411 emit2 ("ld h,!*hl");
1415 wassertl (0, "Attempted to fetch too much data into HL");
1419 else if (IS_Z80 && aop->type == AOP_IY) {
1420 /* Instead of fetching relative to IY, just grab directly
1421 from the address IY refers to */
1422 char *l = aopGetLitWordLong (aop, offset, FALSE);
1424 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1426 if (aop->size < 2) {
1427 emit2("ld %s,!zero", _pairs[pairId].h);
1430 else if (pairId == PAIR_IY)
1434 emit2 ("push %s", _pairs[getPairId(aop)].name);
1440 PAIR_ID id = makeFreePairId (ic, &isUsed);
1443 /* Can't load into parts, so load into HL then exchange. */
1444 emit2 ("ld %s,%s", _pairs[id].l, aopGet (aop, offset, FALSE));
1445 emit2 ("ld %s,%s", _pairs[id].h, aopGet (aop, offset + 1, FALSE));
1446 emit2 ("push %s", _pairs[id].name);
1452 else if (isUnsplitable(aop))
1454 emit2("push %s", _pairs[getPairId(aop)].name);
1455 emit2("pop %s", _pairs[pairId].name);
1459 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1460 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1462 /* PENDING: check? */
1463 if (pairId == PAIR_HL)
1464 spillPair (PAIR_HL);
1469 fetchPair (PAIR_ID pairId, asmop * aop)
1471 fetchPairLong (pairId, aop, NULL, 0);
1475 fetchHL (asmop * aop)
1477 fetchPair (PAIR_HL, aop);
1481 setupPairFromSP (PAIR_ID id, int offset)
1483 wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
1485 if (_G.preserveCarry)
1491 if (offset < INT8MIN || offset > INT8MAX)
1493 emit2 ("ld hl,!immedword", offset);
1494 emit2 ("add hl,sp");
1498 emit2 ("!ldahlsp", offset);
1501 if (_G.preserveCarry)
1509 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1514 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
1515 fetchLitPair (pairId, aop, 0);
1519 wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
1521 fetchLitPair (pairId, aop, offset);
1522 _G.pairs[pairId].offset = offset;
1526 wassertl (IS_Z80, "Only the Z80 has an extended stack");
1527 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
1530 int offset = aop->aopu.aop_stk + _G.stack.offset;
1532 if (_G.pairs[pairId].last_type == aop->type &&
1533 _G.pairs[pairId].offset == offset)
1539 /* PENDING: Do this better. */
1540 if (_G.preserveCarry)
1542 sprintf (buffer, "%d", offset + _G.stack.pushed);
1543 emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
1544 emit2 ("add %s,sp", _pairs[pairId].name);
1545 _G.pairs[pairId].last_type = aop->type;
1546 _G.pairs[pairId].offset = offset;
1547 if (_G.preserveCarry)
1555 /* Doesnt include _G.stack.pushed */
1556 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1558 if (aop->aopu.aop_stk > 0)
1560 abso += _G.stack.param_offset;
1562 assert (pairId == PAIR_HL);
1563 /* In some cases we can still inc or dec hl */
1564 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1566 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1570 setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
1572 _G.pairs[pairId].offset = abso;
1577 if (pairId != aop->aopu.aop_pairId)
1578 genMovePairPair(aop->aopu.aop_pairId, pairId);
1579 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
1585 _G.pairs[pairId].last_type = aop->type;
1591 emit2 ("!tlabeldef", key);
1595 /*-----------------------------------------------------------------*/
1596 /* aopGet - for fetching value of the aop */
1597 /*-----------------------------------------------------------------*/
1599 aopGet (asmop * aop, int offset, bool bit16)
1601 // char *s = buffer;
1603 /* offset is greater than size then zero */
1604 /* PENDING: this seems a bit screwed in some pointer cases. */
1605 if (offset > (aop->size - 1) &&
1606 aop->type != AOP_LIT)
1608 tsprintf (buffer, sizeof(buffer), "!zero");
1609 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1612 /* depending on type */
1616 tsprintf (buffer, sizeof(buffer), "!zero");
1617 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1620 /* PENDING: re-target */
1622 tsprintf (buffer, sizeof(buffer), "!immedwords", aop->aopu.aop_immd);
1627 tsprintf (buffer, sizeof(buffer), "!bankimmeds", aop->aopu.aop_immd);
1630 tsprintf (buffer, sizeof(buffer), "!msbimmeds", aop->aopu.aop_immd);
1633 tsprintf (buffer, sizeof(buffer), "!lsbimmeds", aop->aopu.aop_immd);
1636 wassertl (0, "Fetching from beyond the limits of an immediate value.");
1639 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1643 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1644 SNPRINTF (buffer, sizeof(buffer), "a");
1646 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1650 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1651 SNPRINTF (buffer, sizeof(buffer), "a");
1653 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1656 return aop->aopu.aop_reg[offset]->name;
1660 setupPair (PAIR_HL, aop, offset);
1661 tsprintf (buffer, sizeof(buffer), "!*hl");
1663 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
1667 setupPair (PAIR_IY, aop, offset);
1668 tsprintf (buffer, sizeof(buffer), "!*iyx", offset);
1670 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1674 setupPair (PAIR_IY, aop, offset);
1675 tsprintf (buffer, sizeof(buffer), "!*iyx", offset, offset);
1677 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1682 setupPair (PAIR_HL, aop, offset);
1683 tsprintf (buffer, sizeof(buffer), "!*hl");
1687 if (aop->aopu.aop_stk >= 0)
1688 offset += _G.stack.param_offset;
1689 tsprintf (buffer, sizeof(buffer),
1690 "!*ixx", aop->aopu.aop_stk + offset);
1693 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1696 wassertl (0, "Tried to fetch from a bit variable");
1705 tsprintf(buffer, sizeof(buffer), "!zero");
1706 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1710 wassert (offset < 2);
1711 return aop->aopu.aop_str[offset];
1714 return aopLiteral (aop->aopu.aop_lit, offset);
1718 unsigned long v = aop->aopu.aop_simplelit;
1721 tsprintf (buffer, sizeof(buffer),
1722 "!immedbyte", (unsigned int) v & 0xff);
1724 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1728 return aop->aopu.aop_str[offset];
1731 setupPair (aop->aopu.aop_pairId, aop, offset);
1732 if (aop->aopu.aop_pairId==PAIR_IX)
1733 SNPRINTF (buffer, sizeof(buffer),
1735 else if (aop->aopu.aop_pairId==PAIR_IY)
1736 SNPRINTF (buffer, sizeof(buffer),
1739 SNPRINTF (buffer, sizeof(buffer),
1740 "(%s)", _pairs[aop->aopu.aop_pairId].name);
1742 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1747 wassertl (0, "aopget got unsupported aop->type");
1752 isRegString (const char *s)
1754 if (!strcmp (s, "b") ||
1766 isConstant (const char *s)
1768 /* This is a bit of a hack... */
1769 return (*s == '#' || *s == '$');
1773 canAssignToPtr (const char *s)
1775 if (isRegString (s))
1782 /*-----------------------------------------------------------------*/
1783 /* aopPut - puts a string for a aop */
1784 /*-----------------------------------------------------------------*/
1786 aopPut (asmop * aop, const char *s, int offset)
1790 if (aop->size && offset > (aop->size - 1))
1792 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1793 "aopPut got offset > aop->size");
1798 tsprintf(buffer2, sizeof(buffer2), s);
1801 /* will assign value to value */
1802 /* depending on where it is ofcourse */
1806 _moveA (s); /* in case s is volatile */
1812 if (strcmp (s, "a"))
1813 emit2 ("ld a,%s", s);
1814 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1819 if (strcmp (s, "a"))
1820 emit2 ("ld a,%s", s);
1821 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1825 if (!strcmp (s, "!*hl"))
1826 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1829 aop->aopu.aop_reg[offset]->name, s);
1830 spillPairReg(aop->aopu.aop_reg[offset]->name);
1835 if (!canAssignToPtr (s))
1837 emit2 ("ld a,%s", s);
1838 setupPair (PAIR_IY, aop, offset);
1839 emit2 ("ld !*iyx,a", offset);
1843 setupPair (PAIR_IY, aop, offset);
1844 emit2 ("ld !*iyx,%s", offset, s);
1850 /* PENDING: for re-target */
1851 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1853 emit2 ("ld a,!*hl");
1856 setupPair (PAIR_HL, aop, offset);
1858 emit2 ("ld !*hl,%s", s);
1863 if (!canAssignToPtr (s))
1865 emit2 ("ld a,%s", s);
1866 setupPair (PAIR_IY, aop, offset);
1867 emit2 ("ld !*iyx,a", offset);
1871 setupPair (PAIR_IY, aop, offset);
1872 emit2 ("ld !*iyx,%s", offset, s);
1879 /* PENDING: re-target */
1880 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1882 emit2 ("ld a,!*hl");
1885 setupPair (PAIR_HL, aop, offset);
1886 if (!canAssignToPtr (s))
1888 emit2 ("ld a,%s", s);
1889 emit2 ("ld !*hl,a");
1892 emit2 ("ld !*hl,%s", s);
1896 if (aop->aopu.aop_stk >= 0)
1897 offset += _G.stack.param_offset;
1898 if (!canAssignToPtr (s))
1900 emit2 ("ld a,%s", s);
1901 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
1905 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
1911 /* if bit variable */
1912 if (!aop->aopu.aop_dir)
1914 emit2 ("ld a,!zero");
1919 /* In bit space but not in C - cant happen */
1920 wassertl (0, "Tried to write into a bit variable");
1926 if (strcmp (aop->aopu.aop_str[offset], s))
1928 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1930 spillPairReg(aop->aopu.aop_str[offset]);
1935 if (!offset && (strcmp (s, "acc") == 0))
1939 wassertl (0, "Tried to access past the end of A");
1943 if (strcmp (aop->aopu.aop_str[offset], s))
1945 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1946 spillPairReg(aop->aopu.aop_str[offset]);
1952 wassert (offset < 2);
1953 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1954 spillPairReg(aop->aopu.aop_str[offset]);
1958 setupPair (aop->aopu.aop_pairId, aop, offset);
1959 if (aop->aopu.aop_pairId==PAIR_IX)
1960 emit2 ("ld !*ixx,%s", 0, s);
1961 else if (aop->aopu.aop_pairId==PAIR_IY)
1962 emit2 ("ld !*ixy,%s", 0, s);
1964 emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
1968 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1969 "aopPut got unsupported aop->type");
1974 #define AOP(op) op->aop
1975 #define AOP_TYPE(op) AOP(op)->type
1976 #define AOP_SIZE(op) AOP(op)->size
1977 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
1980 commitPair (asmop * aop, PAIR_ID id)
1982 /* PENDING: Verify this. */
1983 if (id == PAIR_HL && requiresHL (aop) && IS_GB)
1987 aopPut (aop, "a", 0);
1988 aopPut (aop, "d", 1);
1993 if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
1995 char *l = aopGetLitWordLong (aop, 0, FALSE);
1998 emit2 ("ld (%s),%s", l, _pairs[id].name);
2002 aopPut (aop, _pairs[id].l, 0);
2003 aopPut (aop, _pairs[id].h, 1);
2008 /*-----------------------------------------------------------------*/
2009 /* getDataSize - get the operand data size */
2010 /*-----------------------------------------------------------------*/
2012 getDataSize (operand * op)
2015 size = AOP_SIZE (op);
2019 wassertl (0, "Somehow got a three byte data pointer");
2024 /*-----------------------------------------------------------------*/
2025 /* movLeft2Result - move byte from left to result */
2026 /*-----------------------------------------------------------------*/
2028 movLeft2Result (operand * left, int offl,
2029 operand * result, int offr, int sign)
2033 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
2035 l = aopGet (AOP (left), offl, FALSE);
2039 aopPut (AOP (result), l, offr);
2043 if (getDataSize (left) == offl + 1)
2045 emit2 ("ld a,%s", l);
2046 aopPut (AOP (result), "a", offr);
2053 movLeft2ResultLong (operand * left, int offl,
2054 operand * result, int offr, int sign,
2059 movLeft2Result (left, offl, result, offr, sign);
2063 wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
2064 wassertl (size == 2, "Only implemented for two bytes or one");
2066 if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
2068 emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
2069 emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
2071 spillPair (PAIR_HL);
2073 else if ( getPairId ( AOP (result)) == PAIR_IY)
2075 PAIR_ID id = getPairId (AOP (left));
2076 if (id != PAIR_INVALID)
2078 emit2("push %s", _pairs[id].name);
2089 movLeft2Result (left, offl, result, offr, sign);
2090 movLeft2Result (left, offl+1, result, offr+1, sign);
2095 /** Put Acc into a register set
2098 outAcc (operand * result)
2101 size = getDataSize (result);
2104 aopPut (AOP (result), "a", 0);
2107 /* unsigned or positive */
2110 aopPut (AOP (result), "!zero", offset++);
2115 /** Take the value in carry and put it into a register
2118 outBitCLong (operand * result, bool swap_sense)
2120 /* if the result is bit */
2121 if (AOP_TYPE (result) == AOP_CRY)
2123 wassertl (0, "Tried to write carry to a bit");
2127 emit2 ("ld a,!zero");
2130 emit2 ("xor a,!immedbyte", 1);
2136 outBitC (operand * result)
2138 outBitCLong (result, FALSE);
2141 /*-----------------------------------------------------------------*/
2142 /* toBoolean - emit code for orl a,operator(sizeop) */
2143 /*-----------------------------------------------------------------*/
2145 _toBoolean (operand * oper)
2147 int size = AOP_SIZE (oper);
2151 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
2154 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
2158 if (AOP (oper)->type != AOP_ACC)
2161 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
2167 /*-----------------------------------------------------------------*/
2168 /* genNot - generate code for ! operation */
2169 /*-----------------------------------------------------------------*/
2174 /* assign asmOps to operand & result */
2175 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
2176 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2178 /* if in bit space then a special case */
2179 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2181 wassertl (0, "Tried to negate a bit");
2184 _toBoolean (IC_LEFT (ic));
2189 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
2190 emit2 ("sub a,!one");
2191 outBitC (IC_RESULT (ic));
2193 /* release the aops */
2194 freeAsmop (IC_LEFT (ic), NULL, ic);
2195 freeAsmop (IC_RESULT (ic), NULL, ic);
2198 /*-----------------------------------------------------------------*/
2199 /* genCpl - generate code for complement */
2200 /*-----------------------------------------------------------------*/
2208 /* assign asmOps to operand & result */
2209 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2210 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2212 /* if both are in bit space then
2214 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2215 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2217 wassertl (0, "Left and the result are in bit space");
2220 size = AOP_SIZE (IC_RESULT (ic));
2223 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2226 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2229 /* release the aops */
2230 freeAsmop (IC_LEFT (ic), NULL, ic);
2231 freeAsmop (IC_RESULT (ic), NULL, ic);
2235 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
2242 store de into result
2247 store de into result
2249 const char *first = isAdd ? "add" : "sub";
2250 const char *later = isAdd ? "adc" : "sbc";
2252 wassertl (IS_GB, "Code is only relevent to the gbz80");
2253 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
2255 fetchPair (PAIR_DE, left);
2258 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
2261 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2264 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2265 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2267 fetchPairLong (PAIR_DE, left, NULL, MSB24);
2268 aopGet (right, MSB24, FALSE);
2272 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2275 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2277 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2278 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2282 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2284 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2287 /*-----------------------------------------------------------------*/
2288 /* genUminusFloat - unary minus for floating points */
2289 /*-----------------------------------------------------------------*/
2291 genUminusFloat (operand * op, operand * result)
2293 int size, offset = 0;
2295 emitDebug("; genUminusFloat");
2297 /* for this we just need to flip the
2298 first it then copy the rest in place */
2299 size = AOP_SIZE (op) - 1;
2301 _moveA(aopGet (AOP (op), MSB32, FALSE));
2303 emit2("xor a,!immedbyte", 0x80);
2304 aopPut (AOP (result), "a", MSB32);
2308 aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2313 /*-----------------------------------------------------------------*/
2314 /* genUminus - unary minus code generation */
2315 /*-----------------------------------------------------------------*/
2317 genUminus (iCode * ic)
2320 sym_link *optype, *rtype;
2323 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2324 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2326 /* if both in bit space then special
2328 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2329 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2331 wassertl (0, "Left and right are in bit space");
2335 optype = operandType (IC_LEFT (ic));
2336 rtype = operandType (IC_RESULT (ic));
2338 /* if float then do float stuff */
2339 if (IS_FLOAT (optype))
2341 genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2345 /* otherwise subtract from zero */
2346 size = AOP_SIZE (IC_LEFT (ic));
2348 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2350 /* Create a new asmop with value zero */
2351 asmop *azero = newAsmop (AOP_SIMPLELIT);
2352 azero->aopu.aop_simplelit = 0;
2354 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2362 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2363 emit2 ("ld a,!zero");
2364 emit2 ("sbc a,%s", l);
2365 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2368 /* if any remaining bytes in the result */
2369 /* we just need to propagate the sign */
2370 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2375 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2379 /* release the aops */
2380 freeAsmop (IC_LEFT (ic), NULL, ic);
2381 freeAsmop (IC_RESULT (ic), NULL, ic);
2384 /*-----------------------------------------------------------------*/
2385 /* assignResultValue - */
2386 /*-----------------------------------------------------------------*/
2388 assignResultValue (operand * oper)
2390 int size = AOP_SIZE (oper);
2393 wassertl (size <= 4, "Got a result that is bigger than four bytes");
2394 topInA = requiresHL (AOP (oper));
2396 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2398 /* We do it the hard way here. */
2400 aopPut (AOP (oper), _fReturn[0], 0);
2401 aopPut (AOP (oper), _fReturn[1], 1);
2403 aopPut (AOP (oper), _fReturn[0], 2);
2404 aopPut (AOP (oper), _fReturn[1], 3);
2410 aopPut (AOP (oper), _fReturn[size], size);
2415 /** Simple restore that doesn't take into account what is used in the
2419 _restoreRegsAfterCall(void)
2421 if (_G.stack.pushedDE)
2424 _G.stack.pushedDE = FALSE;
2426 if (_G.stack.pushedBC)
2429 _G.stack.pushedBC = FALSE;
2431 _G.saves.saved = FALSE;
2435 _saveRegsForCall(iCode *ic, int sendSetSize)
2438 o Stack parameters are pushed before this function enters
2439 o DE and BC may be used in this function.
2440 o HL and DE may be used to return the result.
2441 o HL and DE may be used to send variables.
2442 o DE and BC may be used to store the result value.
2443 o HL may be used in computing the sent value of DE
2444 o The iPushes for other parameters occur before any addSets
2446 Logic: (to be run inside the first iPush or if none, before sending)
2447 o Compute if DE and/or BC are in use over the call
2448 o Compute if DE is used in the send set
2449 o Compute if DE and/or BC are used to hold the result value
2450 o If (DE is used, or in the send set) and is not used in the result, push.
2451 o If BC is used and is not in the result, push
2453 o If DE is used in the send set, fetch
2454 o If HL is used in the send set, fetch
2458 if (_G.saves.saved == FALSE) {
2459 bool deInUse, bcInUse;
2461 bool bcInRet = FALSE, deInRet = FALSE;
2464 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask),
2465 z80_rUmaskForOp (IC_RESULT(ic)));
2467 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2468 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2470 deSending = (sendSetSize > 1);
2472 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2474 if (bcInUse && bcInRet == FALSE) {
2476 _G.stack.pushedBC = TRUE;
2478 if (deInUse && deInRet == FALSE) {
2480 _G.stack.pushedDE = TRUE;
2483 _G.saves.saved = TRUE;
2486 /* Already saved. */
2490 /*-----------------------------------------------------------------*/
2491 /* genIpush - genrate code for pushing this gets a little complex */
2492 /*-----------------------------------------------------------------*/
2494 genIpush (iCode * ic)
2496 int size, offset = 0;
2499 /* if this is not a parm push : ie. it is spill push
2500 and spill push is always done on the local stack */
2503 wassertl(0, "Encountered an unsupported spill push.");
2507 if (_G.saves.saved == FALSE) {
2508 /* Caller saves, and this is the first iPush. */
2509 /* Scan ahead until we find the function that we are pushing parameters to.
2510 Count the number of addSets on the way to figure out what registers
2511 are used in the send set.
2514 iCode *walk = ic->next;
2517 if (walk->op == SEND) {
2520 else if (walk->op == CALL || walk->op == PCALL) {
2529 _saveRegsForCall(walk, nAddSets);
2532 /* Already saved by another iPush. */
2535 /* then do the push */
2536 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2538 size = AOP_SIZE (IC_LEFT (ic));
2540 if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2542 _G.stack.pushed += 2;
2543 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2549 fetchHL (AOP (IC_LEFT (ic)));
2551 spillPair (PAIR_HL);
2552 _G.stack.pushed += 2;
2557 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
2559 spillPair (PAIR_HL);
2560 _G.stack.pushed += 2;
2561 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
2563 spillPair (PAIR_HL);
2564 _G.stack.pushed += 2;
2570 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2572 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2574 emit2 ("ld a,(%s)", l);
2578 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2579 emit2 ("ld a,%s", l);
2587 freeAsmop (IC_LEFT (ic), NULL, ic);
2590 /*-----------------------------------------------------------------*/
2591 /* genIpop - recover the registers: can happen only for spilling */
2592 /*-----------------------------------------------------------------*/
2594 genIpop (iCode * ic)
2599 /* if the temp was not pushed then */
2600 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2603 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2604 size = AOP_SIZE (IC_LEFT (ic));
2605 offset = (size - 1);
2606 if (isPair (AOP (IC_LEFT (ic))))
2608 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2616 spillPair (PAIR_HL);
2617 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2621 freeAsmop (IC_LEFT (ic), NULL, ic);
2624 /* This is quite unfortunate */
2626 setArea (int inHome)
2629 static int lastArea = 0;
2631 if (_G.in_home != inHome) {
2633 const char *sz = port->mem.code_name;
2634 port->mem.code_name = "HOME";
2635 emit2("!area", CODE_NAME);
2636 port->mem.code_name = sz;
2639 emit2("!area", CODE_NAME); */
2640 _G.in_home = inHome;
2651 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2655 symbol *sym = OP_SYMBOL (op);
2657 if (sym->isspilt || sym->nRegs == 0)
2660 aopOp (op, ic, FALSE, FALSE);
2663 if (aop->type == AOP_REG)
2666 for (i = 0; i < aop->size; i++)
2668 if (pairId == PAIR_DE)
2670 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2671 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2673 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2676 else if (pairId == PAIR_BC)
2678 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2679 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2681 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2691 freeAsmop (IC_LEFT (ic), NULL, ic);
2695 /** Emit the code for a call statement
2698 emitCall (iCode * ic, bool ispcall)
2700 bool bInRet, cInRet, dInRet, eInRet;
2701 sym_link *dtype = operandType (IC_LEFT (ic));
2703 /* if caller saves & we have not saved then */
2709 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2711 /* if send set is not empty then assign */
2716 int nSend = elementsInSet(_G.sendSet);
2717 bool swapped = FALSE;
2719 int _z80_sendOrder[] = {
2724 /* Check if the parameters are swapped. If so route through hl instead. */
2725 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2727 sic = setFirstItem(_G.sendSet);
2728 sic = setNextItem(_G.sendSet);
2730 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2731 /* The second send value is loaded from one the one that holds the first
2732 send, i.e. it is overwritten. */
2733 /* Cache the first in HL, and load the second from HL instead. */
2734 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2735 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2741 for (sic = setFirstItem (_G.sendSet); sic;
2742 sic = setNextItem (_G.sendSet))
2745 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2747 size = AOP_SIZE (IC_LEFT (sic));
2748 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2749 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2751 // PENDING: Mild hack
2752 if (swapped == TRUE && send == 1) {
2754 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2757 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2759 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2762 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2766 freeAsmop (IC_LEFT (sic), NULL, sic);
2773 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2775 werror (W_INDIR_BANKED);
2777 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2779 if (isLitWord (AOP (IC_LEFT (ic))))
2781 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2785 symbol *rlbl = newiTempLabel (NULL);
2786 spillPair (PAIR_HL);
2787 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2789 _G.stack.pushed += 2;
2791 fetchHL (AOP (IC_LEFT (ic)));
2793 emit2 ("!tlabeldef", (rlbl->key + 100));
2794 _G.stack.pushed -= 2;
2796 freeAsmop (IC_LEFT (ic), NULL, ic);
2800 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2801 OP_SYMBOL (IC_LEFT (ic))->rname :
2802 OP_SYMBOL (IC_LEFT (ic))->name;
2803 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2805 emit2 ("call banked_call");
2806 emit2 ("!dws", name);
2807 emit2 ("!dw !bankimmeds", name);
2812 emit2 ("call %s", name);
2817 /* Mark the regsiters as restored. */
2818 _G.saves.saved = FALSE;
2820 /* if we need assign a result value */
2821 if ((IS_ITEMP (IC_RESULT (ic)) &&
2822 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2823 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2824 IS_TRUE_SYMOP (IC_RESULT (ic)))
2827 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2829 assignResultValue (IC_RESULT (ic));
2831 freeAsmop (IC_RESULT (ic), NULL, ic);
2834 /* adjust the stack for parameters if required */
2837 int i = ic->parmBytes;
2839 _G.stack.pushed -= i;
2842 emit2 ("!ldaspsp", i);
2849 emit2 ("ld iy,!immedword", i);
2850 emit2 ("add iy,sp");
2871 bitVect *result = z80_rUmaskForOp (IC_RESULT (ic));
2872 bInRet = bitVectBitValue(result, B_IDX);
2873 cInRet = bitVectBitValue(result, C_IDX);
2874 dInRet = bitVectBitValue(result, D_IDX);
2875 eInRet = bitVectBitValue(result, E_IDX);
2885 if (_G.stack.pushedDE)
2887 if (dInRet && eInRet)
2889 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
2893 /* Only restore E */
2900 /* Only restore D */
2908 _G.stack.pushedDE = FALSE;
2911 if (_G.stack.pushedBC)
2913 if (bInRet && cInRet)
2915 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
2919 /* Only restore C */
2926 /* Only restore B */
2934 _G.stack.pushedBC = FALSE;
2938 /*-----------------------------------------------------------------*/
2939 /* genCall - generates a call statement */
2940 /*-----------------------------------------------------------------*/
2942 genCall (iCode * ic)
2944 emitCall (ic, FALSE);
2947 /*-----------------------------------------------------------------*/
2948 /* genPcall - generates a call by pointer statement */
2949 /*-----------------------------------------------------------------*/
2951 genPcall (iCode * ic)
2953 emitCall (ic, TRUE);
2956 /*-----------------------------------------------------------------*/
2957 /* resultRemat - result is rematerializable */
2958 /*-----------------------------------------------------------------*/
2960 resultRemat (iCode * ic)
2962 if (SKIP_IC (ic) || ic->op == IFX)
2965 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2967 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2968 if (sym->remat && !POINTER_SET (ic))
2975 extern set *publics;
2977 /*-----------------------------------------------------------------*/
2978 /* genFunction - generated code for function entry */
2979 /*-----------------------------------------------------------------*/
2981 genFunction (iCode * ic)
2985 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2988 bool bcInUse = FALSE;
2989 bool deInUse = FALSE;
2991 setArea (IFFUNC_NONBANKED (sym->type));
2993 /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
2996 _G.receiveOffset = 0;
2998 /* Record the last function name for debugging. */
2999 _G.lastFunctionName = sym->rname;
3001 /* Create the function header */
3002 emit2 ("!functionheader", sym->name);
3003 sprintf (buffer, "%s_start", sym->rname);
3004 emit2 ("!labeldef", buffer);
3005 emit2 ("!functionlabeldef", sym->rname);
3007 if (options.profile)
3009 emit2 ("!profileenter");
3012 ftype = operandType (IC_LEFT (ic));
3014 /* if critical function then turn interrupts off */
3015 if (IFFUNC_ISCRITICAL (ftype))
3018 /* if this is an interrupt service routine then save all potentially used registers. */
3019 if (IFFUNC_ISISR (sym->type))
3024 /* PENDING: callee-save etc */
3026 _G.stack.param_offset = 0;
3028 if (z80_opts.calleeSavesBC)
3033 /* Detect which registers are used. */
3034 if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
3037 for (i = 0; i < sym->regsUsed->size; i++)
3039 if (bitVectBitValue (sym->regsUsed, i))
3053 /* Other systems use DE as a temporary. */
3064 _G.stack.param_offset += 2;
3067 _G.calleeSaves.pushedBC = bcInUse;
3072 _G.stack.param_offset += 2;
3075 _G.calleeSaves.pushedDE = deInUse;
3077 /* adjust the stack for the function */
3078 _G.stack.last = sym->stack;
3081 for (sym = setFirstItem (istack->syms); sym;
3082 sym = setNextItem (istack->syms))
3084 if (sym->_isparm && !IS_REGPARM (sym->etype))
3090 sym = OP_SYMBOL (IC_LEFT (ic));
3092 _G.omitFramePtr = options.ommitFramePtr;
3093 if (IS_Z80 && !stackParm && !sym->stack)
3095 /* When the conflicts between AOP_EXSTK && AOP_HLREG are fixed, */
3096 /* the above !sym->stack condition can be removed. -- EEP */
3098 emit2 ("!ldaspsp", -sym->stack);
3099 _G.omitFramePtr = TRUE;
3101 else if (sym->stack && IS_GB && sym->stack > -INT8MIN)
3102 emit2 ("!enterxl", sym->stack);
3103 else if (sym->stack)
3104 emit2 ("!enterx", sym->stack);
3107 _G.stack.offset = sym->stack;
3110 /*-----------------------------------------------------------------*/
3111 /* genEndFunction - generates epilogue for functions */
3112 /*-----------------------------------------------------------------*/
3114 genEndFunction (iCode * ic)
3116 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3118 if (IFFUNC_ISISR (sym->type))
3120 wassertl (0, "Tried to close an interrupt support function");
3124 if (IFFUNC_ISCRITICAL (sym->type))
3127 /* PENDING: calleeSave */
3129 if (IS_Z80 && _G.omitFramePtr)
3131 if (_G.stack.offset)
3132 emit2 ("!ldaspsp", _G.stack.offset);
3134 else if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
3136 emit2 ("!leavexl", _G.stack.offset);
3138 else if (_G.stack.offset)
3140 emit2 ("!leavex", _G.stack.offset);
3147 if (_G.calleeSaves.pushedDE)
3150 _G.calleeSaves.pushedDE = FALSE;
3153 if (_G.calleeSaves.pushedBC)
3156 _G.calleeSaves.pushedBC = FALSE;
3159 if (options.profile)
3161 emit2 ("!profileexit");
3165 if (options.debug && currFunc)
3167 _G.lines.isDebug = 1;
3168 sprintf (buffer, "C$%s$%d$%d$%d",
3169 FileBaseName (ic->filename), currFunc->lastLine,
3170 ic->level, ic->block);
3171 emit2 ("!labeldef", buffer);
3172 if (IS_STATIC (currFunc->etype))
3173 sprintf (buffer, "XF%s$%s$0$0", moduleName, currFunc->name);
3175 sprintf (buffer, "XG$%s$0$0", currFunc->name);
3176 emit2 ("!labeldef", buffer);
3177 _G.lines.isDebug = 0;
3180 /* Both banked and non-banked just ret */
3183 sprintf (buffer, "%s_end", sym->rname);
3184 emit2 ("!labeldef", buffer);
3186 _G.flushStatics = 1;
3187 _G.stack.pushed = 0;
3188 _G.stack.offset = 0;
3191 /*-----------------------------------------------------------------*/
3192 /* genRet - generate code for return statement */
3193 /*-----------------------------------------------------------------*/
3198 /* Errk. This is a hack until I can figure out how
3199 to cause dehl to spill on a call */
3200 int size, offset = 0;
3202 /* if we have no return value then
3203 just generate the "ret" */
3207 /* we have something to return then
3208 move the return value into place */
3209 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3210 size = AOP_SIZE (IC_LEFT (ic));
3212 aopDump("IC_LEFT", AOP(IC_LEFT(ic)));
3215 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3219 emit2 ("ld de,%s", l);
3223 emit2 ("ld hl,%s", l);
3229 fetchPair(IS_GB ? PAIR_DE : PAIR_HL, AOP (IC_LEFT (ic)));
3233 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3235 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3236 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3242 l = aopGet (AOP (IC_LEFT (ic)), offset,
3244 if (strcmp (_fReturn[offset], l))
3245 emit2 ("ld %s,%s", _fReturn[offset], l);
3250 freeAsmop (IC_LEFT (ic), NULL, ic);
3253 /* generate a jump to the return label
3254 if the next is not the return statement */
3255 if (!(ic->next && ic->next->op == LABEL &&
3256 IC_LABEL (ic->next) == returnLabel))
3258 emit2 ("jp !tlabel", returnLabel->key + 100);
3261 /*-----------------------------------------------------------------*/
3262 /* genLabel - generates a label */
3263 /*-----------------------------------------------------------------*/
3265 genLabel (iCode * ic)
3267 /* special case never generate */
3268 if (IC_LABEL (ic) == entryLabel)
3271 emitLabel (IC_LABEL (ic)->key + 100);
3274 /*-----------------------------------------------------------------*/
3275 /* genGoto - generates a ljmp */
3276 /*-----------------------------------------------------------------*/
3278 genGoto (iCode * ic)
3280 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3283 /*-----------------------------------------------------------------*/
3284 /* genPlusIncr :- does addition with increment if possible */
3285 /*-----------------------------------------------------------------*/
3287 genPlusIncr (iCode * ic)
3289 unsigned int icount;
3290 unsigned int size = getDataSize (IC_RESULT (ic));
3291 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3293 /* will try to generate an increment */
3294 /* if the right side is not a literal
3296 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3299 emitDebug ("; genPlusIncr");
3301 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3303 /* If result is a pair */
3304 if (resultId != PAIR_INVALID)
3306 if (isLitWord (AOP (IC_LEFT (ic))))
3308 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3311 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3313 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3315 PAIR_ID freep = getFreePairId (ic);
3316 if (freep != PAIR_INVALID)
3318 fetchPair (freep, AOP (IC_RIGHT (ic)));
3319 emit2 ("add hl,%s", _pairs[freep].name);
3325 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3326 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3333 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3337 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3341 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3346 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3348 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3349 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3353 /* if the literal value of the right hand side
3354 is greater than 4 then it is not worth it */
3358 /* if increment 16 bits in register */
3359 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3365 symbol *tlbl = NULL;
3366 tlbl = newiTempLabel (NULL);
3369 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3372 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3375 emitLabel (tlbl->key + 100);
3379 /* if the sizes are greater than 1 then we cannot */
3380 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3381 AOP_SIZE (IC_LEFT (ic)) > 1)
3384 /* If the result is in a register then we can load then increment.
3386 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3388 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3391 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3396 /* we can if the aops of the left & result match or
3397 if they are in registers and the registers are the
3399 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3403 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3411 /*-----------------------------------------------------------------*/
3412 /* outBitAcc - output a bit in acc */
3413 /*-----------------------------------------------------------------*/
3415 outBitAcc (operand * result)
3417 symbol *tlbl = newiTempLabel (NULL);
3418 /* if the result is a bit */
3419 if (AOP_TYPE (result) == AOP_CRY)
3421 wassertl (0, "Tried to write A into a bit");
3425 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3426 emit2 ("ld a,!one");
3427 emitLabel (tlbl->key + 100);
3433 couldDestroyCarry (asmop *aop)
3437 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3446 shiftIntoPair (int idx, asmop *aop)
3448 PAIR_ID id = PAIR_INVALID;
3450 wassertl (IS_Z80, "Only implemented for the Z80");
3451 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3463 wassertl (0, "Internal error - hit default case");
3466 emitDebug ("; Shift into pair idx %u", idx);
3470 setupPair (PAIR_HL, aop, 0);
3474 setupPair (PAIR_IY, aop, 0);
3476 emit2 ("pop %s", _pairs[id].name);
3479 aop->type = AOP_PAIRPTR;
3480 aop->aopu.aop_pairId = id;
3481 _G.pairs[id].offset = 0;
3482 _G.pairs[id].last_type = aop->type;
3486 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
3488 wassert (left && right);
3492 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3494 shiftIntoPair (0, right);
3495 /* check result again, in case right == result */
3496 if (couldDestroyCarry (result))
3497 shiftIntoPair (1, result);
3499 else if (couldDestroyCarry (right))
3501 if (getPairId (result) == PAIR_HL)
3502 _G.preserveCarry = TRUE;
3504 shiftIntoPair (0, right);
3506 else if (couldDestroyCarry (result))
3508 shiftIntoPair (0, result);
3517 /*-----------------------------------------------------------------*/
3518 /* genPlus - generates code for addition */
3519 /*-----------------------------------------------------------------*/
3521 genPlus (iCode * ic)
3523 int size, offset = 0;
3525 /* special cases :- */
3527 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3528 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3529 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3531 /* Swap the left and right operands if:
3533 if literal, literal on the right or
3534 if left requires ACC or right is already
3537 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3538 (AOP_NEEDSACC (IC_LEFT (ic))) ||
3539 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3541 operand *t = IC_RIGHT (ic);
3542 IC_RIGHT (ic) = IC_LEFT (ic);
3546 /* if both left & right are in bit
3548 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3549 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3552 wassertl (0, "Tried to add two bits");
3555 /* if left in bit space & right literal */
3556 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3557 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3559 /* Can happen I guess */
3560 wassertl (0, "Tried to add a bit to a literal");
3563 /* if I can do an increment instead
3564 of add then GOOD for ME */
3565 if (genPlusIncr (ic) == TRUE)
3568 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3570 size = getDataSize (IC_RESULT (ic));
3572 /* Special case when left and right are constant */
3573 if (isPair (AOP (IC_RESULT (ic))))
3576 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3577 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3579 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3585 sprintf (buffer, "#(%s + %s)", left, right);
3586 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3591 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3593 /* Fetch into HL then do the add */
3594 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3595 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3597 spillPair (PAIR_HL);
3599 if (left == PAIR_HL && right != PAIR_INVALID)
3601 emit2 ("add hl,%s", _pairs[right].name);
3604 else if (right == PAIR_HL && left != PAIR_INVALID)
3606 emit2 ("add hl,%s", _pairs[left].name);
3609 else if (right != PAIR_INVALID && right != PAIR_HL)
3611 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3612 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3615 else if (left != PAIR_INVALID && left != PAIR_HL)
3617 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3618 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3627 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3629 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3630 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3632 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3637 ld hl,sp+n trashes C so we cant afford to do it during an
3638 add with stack based varibles. Worst case is:
3651 So you cant afford to load up hl if either left, right, or result
3652 is on the stack (*sigh*) The alt is:
3660 Combinations in here are:
3661 * If left or right are in bc then the loss is small - trap later
3662 * If the result is in bc then the loss is also small
3666 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3667 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3668 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3670 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3671 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3672 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3673 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3675 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3677 /* Swap left and right */
3678 operand *t = IC_RIGHT (ic);
3679 IC_RIGHT (ic) = IC_LEFT (ic);
3682 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3684 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3685 emit2 ("add hl,bc");
3689 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3690 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3691 emit2 ("add hl,de");
3693 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3699 /* Be paranoid on the GB with 4 byte variables due to how C
3700 can be trashed by lda hl,n(sp).
3702 _gbz80_emitAddSubLong (ic, TRUE);
3707 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3711 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3713 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3716 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3719 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3723 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3726 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3729 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3731 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3735 _G.preserveCarry = FALSE;
3736 freeAsmop (IC_LEFT (ic), NULL, ic);
3737 freeAsmop (IC_RIGHT (ic), NULL, ic);
3738 freeAsmop (IC_RESULT (ic), NULL, ic);
3742 /*-----------------------------------------------------------------*/
3743 /* genMinusDec :- does subtraction with deccrement if possible */
3744 /*-----------------------------------------------------------------*/
3746 genMinusDec (iCode * ic)
3748 unsigned int icount;
3749 unsigned int size = getDataSize (IC_RESULT (ic));
3751 /* will try to generate an increment */
3752 /* if the right side is not a literal we cannot */
3753 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3756 /* if the literal value of the right hand side
3757 is greater than 4 then it is not worth it */
3758 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3761 size = getDataSize (IC_RESULT (ic));
3763 /* if decrement 16 bits in register */
3764 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3765 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3768 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3772 /* If result is a pair */
3773 if (isPair (AOP (IC_RESULT (ic))))
3775 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3777 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3781 /* if increment 16 bits in register */
3782 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3786 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3789 emit2 ("dec %s", _getTempPairName());
3792 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3798 /* if the sizes are greater than 1 then we cannot */
3799 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3800 AOP_SIZE (IC_LEFT (ic)) > 1)
3803 /* we can if the aops of the left & result match or if they are in
3804 registers and the registers are the same */
3805 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3808 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3815 /*-----------------------------------------------------------------*/
3816 /* genMinus - generates code for subtraction */
3817 /*-----------------------------------------------------------------*/
3819 genMinus (iCode * ic)
3821 int size, offset = 0;
3822 unsigned long lit = 0L;
3824 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3825 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3826 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3828 /* special cases :- */
3829 /* if both left & right are in bit space */
3830 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3831 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3833 wassertl (0, "Tried to subtract two bits");
3837 /* if I can do an decrement instead of subtract then GOOD for ME */
3838 if (genMinusDec (ic) == TRUE)
3841 size = getDataSize (IC_RESULT (ic));
3843 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3848 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3852 /* Same logic as genPlus */
3855 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3856 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3857 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3859 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3860 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3861 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3862 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3864 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3865 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3867 if (left == PAIR_INVALID && right == PAIR_INVALID)
3872 else if (right == PAIR_INVALID)
3874 else if (left == PAIR_INVALID)
3877 fetchPair (left, AOP (IC_LEFT (ic)));
3878 /* Order is important. Right may be HL */
3879 fetchPair (right, AOP (IC_RIGHT (ic)));
3881 emit2 ("ld a,%s", _pairs[left].l);
3882 emit2 ("sub a,%s", _pairs[right].l);
3884 emit2 ("ld a,%s", _pairs[left].h);
3885 emit2 ("sbc a,%s", _pairs[right].h);
3887 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
3889 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3891 aopPut (AOP (IC_RESULT (ic)), "e", 0);
3897 /* Be paranoid on the GB with 4 byte variables due to how C
3898 can be trashed by lda hl,n(sp).
3900 _gbz80_emitAddSubLong (ic, FALSE);
3905 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3907 /* if literal, add a,#-lit, else normal subb */
3910 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3911 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3915 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3918 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3922 /* first add without previous c */
3924 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
3926 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3928 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3931 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3932 AOP_SIZE (IC_LEFT (ic)) == 3 &&
3933 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3935 wassertl (0, "Tried to subtract on a long pointer");
3939 _G.preserveCarry = FALSE;
3940 freeAsmop (IC_LEFT (ic), NULL, ic);
3941 freeAsmop (IC_RIGHT (ic), NULL, ic);
3942 freeAsmop (IC_RESULT (ic), NULL, ic);
3945 /*-----------------------------------------------------------------*/
3946 /* genMult - generates code for multiplication */
3947 /*-----------------------------------------------------------------*/
3949 genMult (iCode * ic)
3953 /* If true then the final operation should be a subtract */
3954 bool active = FALSE;
3956 /* Shouldn't occur - all done through function calls */
3957 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3958 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3959 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3961 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
3962 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
3963 AOP_SIZE (IC_RESULT (ic)) > 2)
3965 wassertl (0, "Multiplication is handled through support function calls");
3968 /* Swap left and right such that right is a literal */
3969 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
3971 operand *t = IC_RIGHT (ic);
3972 IC_RIGHT (ic) = IC_LEFT (ic);
3976 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
3978 val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
3979 // wassertl (val > 0, "Multiply must be positive");
3980 wassertl (val != 1, "Can't multiply by 1");
3982 if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
3984 _G.stack.pushedDE = TRUE;
3987 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
3989 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
3997 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
4002 /* Fully unroled version of mul.s. Not the most efficient.
4004 for (count = 0; count < 16; count++)
4006 if (count != 0 && active)
4008 emit2 ("add hl,hl");
4012 if (active == FALSE)
4019 emit2 ("add hl,de");
4028 if (IS_Z80 && _G.stack.pushedDE)
4031 _G.stack.pushedDE = FALSE;
4034 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
4036 freeAsmop (IC_LEFT (ic), NULL, ic);
4037 freeAsmop (IC_RIGHT (ic), NULL, ic);
4038 freeAsmop (IC_RESULT (ic), NULL, ic);
4041 /*-----------------------------------------------------------------*/
4042 /* genDiv - generates code for division */
4043 /*-----------------------------------------------------------------*/
4047 /* Shouldn't occur - all done through function calls */
4048 wassertl (0, "Division is handled through support function calls");
4051 /*-----------------------------------------------------------------*/
4052 /* genMod - generates code for division */
4053 /*-----------------------------------------------------------------*/
4057 /* Shouldn't occur - all done through function calls */
4061 /*-----------------------------------------------------------------*/
4062 /* genIfxJump :- will create a jump depending on the ifx */
4063 /*-----------------------------------------------------------------*/
4065 genIfxJump (iCode * ic, char *jval)
4070 /* if true label then we jump if condition
4074 jlbl = IC_TRUE (ic);
4075 if (!strcmp (jval, "a"))
4079 else if (!strcmp (jval, "c"))
4083 else if (!strcmp (jval, "nc"))
4087 else if (!strcmp (jval, "m"))
4091 else if (!strcmp (jval, "p"))
4097 /* The buffer contains the bit on A that we should test */
4103 /* false label is present */
4104 jlbl = IC_FALSE (ic);
4105 if (!strcmp (jval, "a"))
4109 else if (!strcmp (jval, "c"))
4113 else if (!strcmp (jval, "nc"))
4117 else if (!strcmp (jval, "m"))
4121 else if (!strcmp (jval, "p"))
4127 /* The buffer contains the bit on A that we should test */
4131 /* Z80 can do a conditional long jump */
4132 if (!strcmp (jval, "a"))
4136 else if (!strcmp (jval, "c"))
4139 else if (!strcmp (jval, "nc"))
4142 else if (!strcmp (jval, "m"))
4145 else if (!strcmp (jval, "p"))
4150 emit2 ("bit %s,a", jval);
4152 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
4154 /* mark the icode as generated */
4160 _getPairIdName (PAIR_ID id)
4162 return _pairs[id].name;
4167 /* if unsigned char cmp with lit, just compare */
4169 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4171 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4174 emit2 ("xor a,!immedbyte", 0x80);
4175 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4178 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4180 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4182 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4183 // Pull left into DE and right into HL
4184 aopGet (AOP(left), LSB, FALSE);
4187 aopGet (AOP(right), LSB, FALSE);
4191 if (size == 0 && sign)
4193 // Highest byte when signed needs the bits flipped
4196 emit2 ("ld a,(de)");
4197 emit2 ("xor !immedbyte", 0x80);
4199 emit2 ("ld a,(hl)");
4200 emit2 ("xor !immedbyte", 0x80);
4204 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4208 emit2 ("ld a,(de)");
4209 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4219 spillPair (PAIR_HL);
4221 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4223 setupPair (PAIR_HL, AOP (left), 0);
4224 aopGet (AOP(right), LSB, FALSE);
4228 if (size == 0 && sign)
4230 // Highest byte when signed needs the bits flipped
4233 emit2 ("ld a,(hl)");
4234 emit2 ("xor !immedbyte", 0x80);
4236 emit2 ("ld a,%d(iy)", offset);
4237 emit2 ("xor !immedbyte", 0x80);
4241 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4245 emit2 ("ld a,(hl)");
4246 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4255 spillPair (PAIR_HL);
4256 spillPair (PAIR_IY);
4260 if (AOP_TYPE (right) == AOP_LIT)
4262 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4263 /* optimize if(x < 0) or if(x >= 0) */
4268 /* No sign so it's always false */
4273 /* Just load in the top most bit */
4274 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4275 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4277 genIfxJump (ifx, "7");
4289 /* First setup h and l contaning the top most bytes XORed */
4290 bool fDidXor = FALSE;
4291 if (AOP_TYPE (left) == AOP_LIT)
4293 unsigned long lit = (unsigned long)
4294 floatFromVal (AOP (left)->aopu.aop_lit);
4295 emit2 ("ld %s,!immedbyte", _fTmp[0],
4296 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4300 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4301 emit2 ("xor a,!immedbyte", 0x80);
4302 emit2 ("ld %s,a", _fTmp[0]);
4305 if (AOP_TYPE (right) == AOP_LIT)
4307 unsigned long lit = (unsigned long)
4308 floatFromVal (AOP (right)->aopu.aop_lit);
4309 emit2 ("ld %s,!immedbyte", _fTmp[1],
4310 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4314 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4315 emit2 ("xor a,!immedbyte", 0x80);
4316 emit2 ("ld %s,a", _fTmp[1]);
4322 /* Do a long subtract */
4325 _moveA (aopGet (AOP (left), offset, FALSE));
4327 if (sign && size == 0)
4329 emit2 ("ld a,%s", _fTmp[0]);
4330 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4334 /* Subtract through, propagating the carry */
4335 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4343 /** Generic compare for > or <
4346 genCmp (operand * left, operand * right,
4347 operand * result, iCode * ifx, int sign)
4349 int size, offset = 0;
4350 unsigned long lit = 0L;
4351 bool swap_sense = FALSE;
4353 /* if left & right are bit variables */
4354 if (AOP_TYPE (left) == AOP_CRY &&
4355 AOP_TYPE (right) == AOP_CRY)
4357 /* Cant happen on the Z80 */
4358 wassertl (0, "Tried to compare two bits");
4362 /* Do a long subtract of right from left. */
4363 size = max (AOP_SIZE (left), AOP_SIZE (right));
4365 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4367 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4368 // Pull left into DE and right into HL
4369 aopGet (AOP(left), LSB, FALSE);
4372 aopGet (AOP(right), LSB, FALSE);
4376 emit2 ("ld a,(de)");
4377 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4386 spillPair (PAIR_HL);
4390 if (AOP_TYPE (right) == AOP_LIT)
4392 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4393 /* optimize if(x < 0) or if(x >= 0) */
4398 /* No sign so it's always false */
4403 /* Just load in the top most bit */
4404 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4405 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4407 genIfxJump (ifx, "7");
4418 genIfxJump (ifx, swap_sense ? "c" : "nc");
4429 _moveA (aopGet (AOP (left), offset, FALSE));
4430 /* Subtract through, propagating the carry */
4431 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4437 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4441 /* Shift the sign bit up into carry */
4444 outBitCLong (result, swap_sense);
4448 /* if the result is used in the next
4449 ifx conditional branch then generate
4450 code a little differently */
4458 genIfxJump (ifx, swap_sense ? "nc" : "c");
4462 genIfxJump (ifx, swap_sense ? "p" : "m");
4467 genIfxJump (ifx, swap_sense ? "nc" : "c");
4474 /* Shift the sign bit up into carry */
4477 outBitCLong (result, swap_sense);
4479 /* leave the result in acc */
4483 /*-----------------------------------------------------------------*/
4484 /* genCmpGt :- greater than comparison */
4485 /*-----------------------------------------------------------------*/
4487 genCmpGt (iCode * ic, iCode * ifx)
4489 operand *left, *right, *result;
4490 sym_link *letype, *retype;
4493 left = IC_LEFT (ic);
4494 right = IC_RIGHT (ic);
4495 result = IC_RESULT (ic);
4497 letype = getSpec (operandType (left));
4498 retype = getSpec (operandType (right));
4499 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4500 /* assign the amsops */
4501 aopOp (left, ic, FALSE, FALSE);
4502 aopOp (right, ic, FALSE, FALSE);
4503 aopOp (result, ic, TRUE, FALSE);
4505 genCmp (right, left, result, ifx, sign);
4507 freeAsmop (left, NULL, ic);
4508 freeAsmop (right, NULL, ic);
4509 freeAsmop (result, NULL, ic);
4512 /*-----------------------------------------------------------------*/
4513 /* genCmpLt - less than comparisons */
4514 /*-----------------------------------------------------------------*/
4516 genCmpLt (iCode * ic, iCode * ifx)
4518 operand *left, *right, *result;
4519 sym_link *letype, *retype;
4522 left = IC_LEFT (ic);
4523 right = IC_RIGHT (ic);
4524 result = IC_RESULT (ic);
4526 letype = getSpec (operandType (left));
4527 retype = getSpec (operandType (right));
4528 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4530 /* assign the amsops */
4531 aopOp (left, ic, FALSE, FALSE);
4532 aopOp (right, ic, FALSE, FALSE);
4533 aopOp (result, ic, TRUE, FALSE);
4535 genCmp (left, right, result, ifx, sign);
4537 freeAsmop (left, NULL, ic);
4538 freeAsmop (right, NULL, ic);
4539 freeAsmop (result, NULL, ic);
4542 /*-----------------------------------------------------------------*/
4543 /* gencjneshort - compare and jump if not equal */
4544 /*-----------------------------------------------------------------*/
4546 gencjneshort (operand * left, operand * right, symbol * lbl)
4548 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4550 unsigned long lit = 0L;
4552 /* Swap the left and right if it makes the computation easier */
4553 if (AOP_TYPE (left) == AOP_LIT)
4560 if (AOP_TYPE (right) == AOP_LIT)
4562 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4565 /* if the right side is a literal then anything goes */
4566 if (AOP_TYPE (right) == AOP_LIT &&
4567 AOP_TYPE (left) != AOP_DIR)
4571 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4576 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4583 emit2 ("jp nz,!tlabel", lbl->key + 100);
4589 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4590 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
4593 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
4594 emit2 ("jp nz,!tlabel", lbl->key + 100);
4599 /* if the right side is in a register or in direct space or
4600 if the left is a pointer register & right is not */
4601 else if (AOP_TYPE (right) == AOP_REG ||
4602 AOP_TYPE (right) == AOP_DIR ||
4603 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
4607 _moveA (aopGet (AOP (left), offset, FALSE));
4608 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
4609 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4611 emit2 ("jp nz,!tlabel", lbl->key + 100);
4614 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4615 emit2 ("jp nz,!tlabel", lbl->key + 100);
4622 /* right is a pointer reg need both a & b */
4623 /* PENDING: is this required? */
4626 _moveA (aopGet (AOP (right), offset, FALSE));
4627 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
4628 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
4634 /*-----------------------------------------------------------------*/
4635 /* gencjne - compare and jump if not equal */
4636 /*-----------------------------------------------------------------*/
4638 gencjne (operand * left, operand * right, symbol * lbl)
4640 symbol *tlbl = newiTempLabel (NULL);
4642 gencjneshort (left, right, lbl);
4645 emit2 ("ld a,!one");
4646 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4647 emitLabel (lbl->key + 100);
4649 emitLabel (tlbl->key + 100);
4652 /*-----------------------------------------------------------------*/
4653 /* genCmpEq - generates code for equal to */
4654 /*-----------------------------------------------------------------*/
4656 genCmpEq (iCode * ic, iCode * ifx)
4658 operand *left, *right, *result;
4660 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4661 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4662 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4664 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4666 /* Swap operands if it makes the operation easier. ie if:
4667 1. Left is a literal.
4669 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4671 operand *t = IC_RIGHT (ic);
4672 IC_RIGHT (ic) = IC_LEFT (ic);
4676 if (ifx && !AOP_SIZE (result))
4679 /* if they are both bit variables */
4680 if (AOP_TYPE (left) == AOP_CRY &&
4681 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4683 wassertl (0, "Tried to compare two bits");
4687 tlbl = newiTempLabel (NULL);
4688 gencjneshort (left, right, tlbl);
4691 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4692 emitLabel (tlbl->key + 100);
4696 /* PENDING: do this better */
4697 symbol *lbl = newiTempLabel (NULL);
4698 emit2 ("!shortjp !tlabel", lbl->key + 100);
4699 emitLabel (tlbl->key + 100);
4700 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4701 emitLabel (lbl->key + 100);
4704 /* mark the icode as generated */
4709 /* if they are both bit variables */
4710 if (AOP_TYPE (left) == AOP_CRY &&
4711 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4713 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4719 gencjne (left, right, newiTempLabel (NULL));
4720 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4727 genIfxJump (ifx, "a");
4730 /* if the result is used in an arithmetic operation
4731 then put the result in place */
4732 if (AOP_TYPE (result) != AOP_CRY)
4737 /* leave the result in acc */
4741 freeAsmop (left, NULL, ic);
4742 freeAsmop (right, NULL, ic);
4743 freeAsmop (result, NULL, ic);
4746 /*-----------------------------------------------------------------*/
4747 /* ifxForOp - returns the icode containing the ifx for operand */
4748 /*-----------------------------------------------------------------*/
4750 ifxForOp (operand * op, iCode * ic)
4752 /* if true symbol then needs to be assigned */
4753 if (IS_TRUE_SYMOP (op))
4756 /* if this has register type condition and
4757 the next instruction is ifx with the same operand
4758 and live to of the operand is upto the ifx only then */
4760 ic->next->op == IFX &&
4761 IC_COND (ic->next)->key == op->key &&
4762 OP_SYMBOL (op)->liveTo <= ic->next->seq)
4768 /*-----------------------------------------------------------------*/
4769 /* genAndOp - for && operation */
4770 /*-----------------------------------------------------------------*/
4772 genAndOp (iCode * ic)
4774 operand *left, *right, *result;
4777 /* note here that && operations that are in an if statement are
4778 taken away by backPatchLabels only those used in arthmetic
4779 operations remain */
4780 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4781 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4782 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4784 /* if both are bit variables */
4785 if (AOP_TYPE (left) == AOP_CRY &&
4786 AOP_TYPE (right) == AOP_CRY)
4788 wassertl (0, "Tried to and two bits");
4792 tlbl = newiTempLabel (NULL);
4794 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
4796 emitLabel (tlbl->key + 100);
4800 freeAsmop (left, NULL, ic);
4801 freeAsmop (right, NULL, ic);
4802 freeAsmop (result, NULL, ic);
4805 /*-----------------------------------------------------------------*/
4806 /* genOrOp - for || operation */
4807 /*-----------------------------------------------------------------*/
4809 genOrOp (iCode * ic)
4811 operand *left, *right, *result;
4814 /* note here that || operations that are in an
4815 if statement are taken away by backPatchLabels
4816 only those used in arthmetic operations remain */
4817 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4818 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4819 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4821 /* if both are bit variables */
4822 if (AOP_TYPE (left) == AOP_CRY &&
4823 AOP_TYPE (right) == AOP_CRY)
4825 wassertl (0, "Tried to OR two bits");
4829 tlbl = newiTempLabel (NULL);
4831 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4833 emitLabel (tlbl->key + 100);
4837 freeAsmop (left, NULL, ic);
4838 freeAsmop (right, NULL, ic);
4839 freeAsmop (result, NULL, ic);
4842 /*-----------------------------------------------------------------*/
4843 /* isLiteralBit - test if lit == 2^n */
4844 /*-----------------------------------------------------------------*/
4846 isLiteralBit (unsigned long lit)
4848 unsigned long pw[32] =
4849 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
4850 0x100L, 0x200L, 0x400L, 0x800L,
4851 0x1000L, 0x2000L, 0x4000L, 0x8000L,
4852 0x10000L, 0x20000L, 0x40000L, 0x80000L,
4853 0x100000L, 0x200000L, 0x400000L, 0x800000L,
4854 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
4855 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
4858 for (idx = 0; idx < 32; idx++)
4864 /*-----------------------------------------------------------------*/
4865 /* jmpTrueOrFalse - */
4866 /*-----------------------------------------------------------------*/
4868 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
4870 // ugly but optimized by peephole
4873 symbol *nlbl = newiTempLabel (NULL);
4874 emit2 ("jp !tlabel", nlbl->key + 100);
4875 emitLabel (tlbl->key + 100);
4876 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
4877 emitLabel (nlbl->key + 100);
4881 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
4882 emitLabel (tlbl->key + 100);
4887 /*-----------------------------------------------------------------*/
4888 /* genAnd - code for and */
4889 /*-----------------------------------------------------------------*/
4891 genAnd (iCode * ic, iCode * ifx)
4893 operand *left, *right, *result;
4894 int size, offset = 0;
4895 unsigned long lit = 0L;
4898 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4899 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4900 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4902 /* if left is a literal & right is not then exchange them */
4903 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4904 AOP_NEEDSACC (left))
4906 operand *tmp = right;
4911 /* if result = right then exchange them */
4912 if (sameRegs (AOP (result), AOP (right)))
4914 operand *tmp = right;
4919 /* if right is bit then exchange them */
4920 if (AOP_TYPE (right) == AOP_CRY &&
4921 AOP_TYPE (left) != AOP_CRY)
4923 operand *tmp = right;
4927 if (AOP_TYPE (right) == AOP_LIT)
4928 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4930 size = AOP_SIZE (result);
4932 if (AOP_TYPE (left) == AOP_CRY)
4934 wassertl (0, "Tried to perform an AND with a bit as an operand");
4938 // if(val & 0xZZ) - size = 0, ifx != FALSE -
4939 // bit = val & 0xZZ - size = 1, ifx = FALSE -
4940 if ((AOP_TYPE (right) == AOP_LIT) &&
4941 (AOP_TYPE (result) == AOP_CRY) &&
4942 (AOP_TYPE (left) != AOP_CRY))
4944 symbol *tlbl = newiTempLabel (NULL);
4945 int sizel = AOP_SIZE (left);
4948 /* PENDING: Test case for this. */
4953 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
4955 _moveA (aopGet (AOP (left), offset, FALSE));
4956 if (bytelit != 0x0FFL)
4958 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4965 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4969 // bit = left & literal
4973 emit2 ("!tlabeldef", tlbl->key + 100);
4975 // if(left & literal)
4980 jmpTrueOrFalse (ifx, tlbl);
4988 /* if left is same as result */
4989 if (sameRegs (AOP (result), AOP (left)))
4991 for (; size--; offset++)
4993 if (AOP_TYPE (right) == AOP_LIT)
4995 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5000 aopPut (AOP (result), "!zero", offset);
5003 _moveA (aopGet (AOP (left), offset, FALSE));
5005 aopGet (AOP (right), offset, FALSE));
5006 aopPut (AOP (left), "a", offset);
5013 if (AOP_TYPE (left) == AOP_ACC)
5015 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
5019 _moveA (aopGet (AOP (left), offset, FALSE));
5021 aopGet (AOP (right), offset, FALSE));
5022 aopPut (AOP (left), "a", offset);
5029 // left & result in different registers
5030 if (AOP_TYPE (result) == AOP_CRY)
5032 wassertl (0, "Tried to AND where the result is in carry");
5036 for (; (size--); offset++)
5039 // result = left & right
5040 if (AOP_TYPE (right) == AOP_LIT)
5042 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5044 aopPut (AOP (result),
5045 aopGet (AOP (left), offset, FALSE),
5049 else if (bytelit == 0)
5051 aopPut (AOP (result), "!zero", offset);
5055 // faster than result <- left, anl result,right
5056 // and better if result is SFR
5057 if (AOP_TYPE (left) == AOP_ACC)
5058 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
5061 _moveA (aopGet (AOP (left), offset, FALSE));
5063 aopGet (AOP (right), offset, FALSE));
5065 aopPut (AOP (result), "a", offset);
5072 freeAsmop (left, NULL, ic);
5073 freeAsmop (right, NULL, ic);
5074 freeAsmop (result, NULL, ic);
5077 /*-----------------------------------------------------------------*/
5078 /* genOr - code for or */
5079 /*-----------------------------------------------------------------*/
5081 genOr (iCode * ic, iCode * ifx)
5083 operand *left, *right, *result;
5084 int size, offset = 0;
5085 unsigned long lit = 0L;
5088 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5089 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5090 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5092 /* if left is a literal & right is not then exchange them */
5093 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5094 AOP_NEEDSACC (left))
5096 operand *tmp = right;
5101 /* if result = right then exchange them */
5102 if (sameRegs (AOP (result), AOP (right)))
5104 operand *tmp = right;
5109 /* if right is bit then exchange them */
5110 if (AOP_TYPE (right) == AOP_CRY &&
5111 AOP_TYPE (left) != AOP_CRY)
5113 operand *tmp = right;
5117 if (AOP_TYPE (right) == AOP_LIT)
5118 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5120 size = AOP_SIZE (result);
5122 if (AOP_TYPE (left) == AOP_CRY)
5124 wassertl (0, "Tried to OR where left is a bit");
5128 // if(val | 0xZZ) - size = 0, ifx != FALSE -
5129 // bit = val | 0xZZ - size = 1, ifx = FALSE -
5130 if ((AOP_TYPE (right) == AOP_LIT) &&
5131 (AOP_TYPE (result) == AOP_CRY) &&
5132 (AOP_TYPE (left) != AOP_CRY))
5134 symbol *tlbl = newiTempLabel (NULL);
5135 int sizel = AOP_SIZE (left);
5139 wassertl (0, "Result is assigned to a bit");
5141 /* PENDING: Modeled after the AND code which is inefficent. */
5144 bytelit = (lit >> (offset * 8)) & 0x0FFL;
5146 _moveA (aopGet (AOP (left), offset, FALSE));
5147 /* OR with any literal is the same as OR with itself. */
5149 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5155 jmpTrueOrFalse (ifx, tlbl);
5160 /* if left is same as result */
5161 if (sameRegs (AOP (result), AOP (left)))
5163 for (; size--; offset++)
5165 if (AOP_TYPE (right) == AOP_LIT)
5167 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5171 _moveA (aopGet (AOP (left), offset, FALSE));
5173 aopGet (AOP (right), offset, FALSE));
5174 aopPut (AOP (result), "a", offset);
5179 if (AOP_TYPE (left) == AOP_ACC)
5180 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5183 _moveA (aopGet (AOP (left), offset, FALSE));
5185 aopGet (AOP (right), offset, FALSE));
5186 aopPut (AOP (result), "a", offset);
5193 // left & result in different registers
5194 if (AOP_TYPE (result) == AOP_CRY)
5196 wassertl (0, "Result of OR is in a bit");
5199 for (; (size--); offset++)
5202 // result = left & right
5203 if (AOP_TYPE (right) == AOP_LIT)
5205 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5207 aopPut (AOP (result),
5208 aopGet (AOP (left), offset, FALSE),
5213 // faster than result <- left, anl result,right
5214 // and better if result is SFR
5215 if (AOP_TYPE (left) == AOP_ACC)
5216 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5219 _moveA (aopGet (AOP (left), offset, FALSE));
5221 aopGet (AOP (right), offset, FALSE));
5223 aopPut (AOP (result), "a", offset);
5224 /* PENDING: something weird is going on here. Add exception. */
5225 if (AOP_TYPE (result) == AOP_ACC)
5231 freeAsmop (left, NULL, ic);
5232 freeAsmop (right, NULL, ic);
5233 freeAsmop (result, NULL, ic);
5236 /*-----------------------------------------------------------------*/
5237 /* genXor - code for xclusive or */
5238 /*-----------------------------------------------------------------*/
5240 genXor (iCode * ic, iCode * ifx)
5242 operand *left, *right, *result;
5243 int size, offset = 0;
5244 unsigned long lit = 0L;
5246 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5247 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5248 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5250 /* if left is a literal & right is not then exchange them */
5251 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5252 AOP_NEEDSACC (left))
5254 operand *tmp = right;
5259 /* if result = right then exchange them */
5260 if (sameRegs (AOP (result), AOP (right)))
5262 operand *tmp = right;
5267 /* if right is bit then exchange them */
5268 if (AOP_TYPE (right) == AOP_CRY &&
5269 AOP_TYPE (left) != AOP_CRY)
5271 operand *tmp = right;
5275 if (AOP_TYPE (right) == AOP_LIT)
5276 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5278 size = AOP_SIZE (result);
5280 if (AOP_TYPE (left) == AOP_CRY)
5282 wassertl (0, "Tried to XOR a bit");
5286 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5287 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5288 if ((AOP_TYPE (right) == AOP_LIT) &&
5289 (AOP_TYPE (result) == AOP_CRY) &&
5290 (AOP_TYPE (left) != AOP_CRY))
5292 symbol *tlbl = newiTempLabel (NULL);
5293 int sizel = AOP_SIZE (left);
5297 /* PENDING: Test case for this. */
5298 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5302 _moveA (aopGet (AOP (left), offset, FALSE));
5303 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5304 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5309 jmpTrueOrFalse (ifx, tlbl);
5313 wassertl (0, "Result of XOR was destined for a bit");
5318 /* if left is same as result */
5319 if (sameRegs (AOP (result), AOP (left)))
5321 for (; size--; offset++)
5323 if (AOP_TYPE (right) == AOP_LIT)
5325 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5329 _moveA (aopGet (AOP (right), offset, FALSE));
5331 aopGet (AOP (left), offset, FALSE));
5332 aopPut (AOP (result), "a", offset);
5337 if (AOP_TYPE (left) == AOP_ACC)
5339 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5343 _moveA (aopGet (AOP (right), offset, FALSE));
5345 aopGet (AOP (left), offset, FALSE));
5346 aopPut (AOP (result), "a", offset);
5353 // left & result in different registers
5354 if (AOP_TYPE (result) == AOP_CRY)
5356 wassertl (0, "Result of XOR is in a bit");
5359 for (; (size--); offset++)
5362 // result = left & right
5363 if (AOP_TYPE (right) == AOP_LIT)
5365 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5367 aopPut (AOP (result),
5368 aopGet (AOP (left), offset, FALSE),
5373 // faster than result <- left, anl result,right
5374 // and better if result is SFR
5375 if (AOP_TYPE (left) == AOP_ACC)
5377 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5381 _moveA (aopGet (AOP (right), offset, FALSE));
5383 aopGet (AOP (left), offset, FALSE));
5385 aopPut (AOP (result), "a", offset);
5390 freeAsmop (left, NULL, ic);
5391 freeAsmop (right, NULL, ic);
5392 freeAsmop (result, NULL, ic);
5395 /*-----------------------------------------------------------------*/
5396 /* genInline - write the inline code out */
5397 /*-----------------------------------------------------------------*/
5399 genInline (iCode * ic)
5401 char *buffer, *bp, *bp1;
5403 _G.lines.isInline += (!options.asmpeep);
5405 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5406 strcpy (buffer, IC_INLINE (ic));
5408 /* emit each line as a code */
5433 _G.lines.isInline -= (!options.asmpeep);
5437 /*-----------------------------------------------------------------*/
5438 /* genRRC - rotate right with carry */
5439 /*-----------------------------------------------------------------*/
5446 /*-----------------------------------------------------------------*/
5447 /* genRLC - generate code for rotate left with carry */
5448 /*-----------------------------------------------------------------*/
5455 /*-----------------------------------------------------------------*/
5456 /* genGetHbit - generates code get highest order bit */
5457 /*-----------------------------------------------------------------*/
5459 genGetHbit (iCode * ic)
5461 operand *left, *result;
5462 left = IC_LEFT (ic);
5463 result = IC_RESULT (ic);
5465 aopOp (left, ic, FALSE, FALSE);
5466 aopOp (result, ic, FALSE, FALSE);
5468 /* get the highest order byte into a */
5469 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5471 if (AOP_TYPE (result) == AOP_CRY)
5479 emit2 ("and a,!one");
5484 freeAsmop (left, NULL, ic);
5485 freeAsmop (result, NULL, ic);
5489 emitRsh2 (asmop *aop, int size, int is_signed)
5495 const char *l = aopGet (aop, size, FALSE);
5498 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5508 /*-----------------------------------------------------------------*/
5509 /* shiftR2Left2Result - shift right two bytes from left to result */
5510 /*-----------------------------------------------------------------*/
5512 shiftR2Left2Result (operand * left, int offl,
5513 operand * result, int offr,
5514 int shCount, int is_signed)
5517 symbol *tlbl, *tlbl1;
5519 movLeft2Result (left, offl, result, offr, 0);
5520 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5522 /* if (AOP(result)->type == AOP_REG) { */
5524 tlbl = newiTempLabel (NULL);
5525 tlbl1 = newiTempLabel (NULL);
5527 /* Left is already in result - so now do the shift */
5532 emitRsh2 (AOP (result), size, is_signed);
5537 emit2 ("ld a,!immedbyte+1", shCount);
5538 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5539 emitLabel (tlbl->key + 100);
5541 emitRsh2 (AOP (result), size, is_signed);
5543 emitLabel (tlbl1->key + 100);
5545 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5549 /*-----------------------------------------------------------------*/
5550 /* shiftL2Left2Result - shift left two bytes from left to result */
5551 /*-----------------------------------------------------------------*/
5553 shiftL2Left2Result (operand * left, int offl,
5554 operand * result, int offr, int shCount)
5556 if (sameRegs (AOP (result), AOP (left)) &&
5557 ((offl + MSB16) == offr))
5563 /* Copy left into result */
5564 movLeft2Result (left, offl, result, offr, 0);
5565 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5568 if (getPairId (AOP (result)) == PAIR_HL)
5572 emit2 ("add hl,hl");
5579 symbol *tlbl, *tlbl1;
5582 tlbl = newiTempLabel (NULL);
5583 tlbl1 = newiTempLabel (NULL);
5585 if (AOP (result)->type == AOP_REG)
5589 for (offset = 0; offset < size; offset++)
5591 l = aopGet (AOP (result), offset, FALSE);
5595 emit2 ("sla %s", l);
5606 /* Left is already in result - so now do the shift */
5609 emit2 ("ld a,!immedbyte+1", shCount);
5610 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5611 emitLabel (tlbl->key + 100);
5616 l = aopGet (AOP (result), offset, FALSE);
5620 emit2 ("sla %s", l);
5631 emitLabel (tlbl1->key + 100);
5633 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5639 /*-----------------------------------------------------------------*/
5640 /* AccRol - rotate left accumulator by known count */
5641 /*-----------------------------------------------------------------*/
5643 AccRol (int shCount)
5645 shCount &= 0x0007; // shCount : 0..7
5722 /*-----------------------------------------------------------------*/
5723 /* AccLsh - left shift accumulator by known count */
5724 /*-----------------------------------------------------------------*/
5726 AccLsh (int shCount)
5728 static const unsigned char SLMask[] =
5730 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5739 else if (shCount == 2)
5746 /* rotate left accumulator */
5748 /* and kill the lower order bits */
5749 emit2 ("and a,!immedbyte", SLMask[shCount]);
5754 /*-----------------------------------------------------------------*/
5755 /* shiftL1Left2Result - shift left one byte from left to result */
5756 /*-----------------------------------------------------------------*/
5758 shiftL1Left2Result (operand * left, int offl,
5759 operand * result, int offr, int shCount)
5762 l = aopGet (AOP (left), offl, FALSE);
5764 /* shift left accumulator */
5766 aopPut (AOP (result), "a", offr);
5770 /*-----------------------------------------------------------------*/
5771 /* genlshTwo - left shift two bytes by known amount != 0 */
5772 /*-----------------------------------------------------------------*/
5774 genlshTwo (operand * result, operand * left, int shCount)
5776 int size = AOP_SIZE (result);
5778 wassert (size == 2);
5780 /* if shCount >= 8 */
5788 movLeft2Result (left, LSB, result, MSB16, 0);
5789 aopPut (AOP (result), "!zero", 0);
5790 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
5794 movLeft2Result (left, LSB, result, MSB16, 0);
5795 aopPut (AOP (result), "!zero", 0);
5800 aopPut (AOP (result), "!zero", LSB);
5803 /* 1 <= shCount <= 7 */
5812 shiftL2Left2Result (left, LSB, result, LSB, shCount);
5817 /*-----------------------------------------------------------------*/
5818 /* genlshOne - left shift a one byte quantity by known count */
5819 /*-----------------------------------------------------------------*/
5821 genlshOne (operand * result, operand * left, int shCount)
5823 shiftL1Left2Result (left, LSB, result, LSB, shCount);
5826 /*-----------------------------------------------------------------*/
5827 /* genLeftShiftLiteral - left shifting by known count */
5828 /*-----------------------------------------------------------------*/
5830 genLeftShiftLiteral (operand * left,
5835 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5838 freeAsmop (right, NULL, ic);
5840 aopOp (left, ic, FALSE, FALSE);
5841 aopOp (result, ic, FALSE, FALSE);
5843 size = getSize (operandType (result));
5845 /* I suppose that the left size >= result size */
5851 else if (shCount >= (size * 8))
5855 aopPut (AOP (result), "!zero", size);
5863 genlshOne (result, left, shCount);
5866 genlshTwo (result, left, shCount);
5869 wassertl (0, "Shifting of longs is currently unsupported");
5875 freeAsmop (left, NULL, ic);
5876 freeAsmop (result, NULL, ic);
5879 /*-----------------------------------------------------------------*/
5880 /* genLeftShift - generates code for left shifting */
5881 /*-----------------------------------------------------------------*/
5883 genLeftShift (iCode * ic)
5887 symbol *tlbl, *tlbl1;
5888 operand *left, *right, *result;
5890 right = IC_RIGHT (ic);
5891 left = IC_LEFT (ic);
5892 result = IC_RESULT (ic);
5894 aopOp (right, ic, FALSE, FALSE);
5896 /* if the shift count is known then do it
5897 as efficiently as possible */
5898 if (AOP_TYPE (right) == AOP_LIT)
5900 genLeftShiftLiteral (left, right, result, ic);
5904 /* shift count is unknown then we have to form a loop get the loop
5905 count in B : Note: we take only the lower order byte since
5906 shifting more that 32 bits make no sense anyway, ( the largest
5907 size of an object can be only 32 bits ) */
5908 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5910 freeAsmop (right, NULL, ic);
5911 aopOp (left, ic, FALSE, FALSE);
5912 aopOp (result, ic, FALSE, FALSE);
5914 /* now move the left to the result if they are not the
5917 if (!sameRegs (AOP (left), AOP (result)))
5920 size = AOP_SIZE (result);
5924 l = aopGet (AOP (left), offset, FALSE);
5925 aopPut (AOP (result), l, offset);
5930 tlbl = newiTempLabel (NULL);
5931 size = AOP_SIZE (result);
5933 tlbl1 = newiTempLabel (NULL);
5935 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5936 emitLabel (tlbl->key + 100);
5937 l = aopGet (AOP (result), offset, FALSE);
5941 l = aopGet (AOP (result), offset, FALSE);
5945 emit2 ("sla %s", l);
5953 emitLabel (tlbl1->key + 100);
5955 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5957 freeAsmop (left, NULL, ic);
5958 freeAsmop (result, NULL, ic);
5961 /*-----------------------------------------------------------------*/
5962 /* genrshOne - left shift two bytes by known amount != 0 */
5963 /*-----------------------------------------------------------------*/
5965 genrshOne (operand * result, operand * left, int shCount, int is_signed)
5968 int size = AOP_SIZE (result);
5971 wassert (size == 1);
5972 wassert (shCount < 8);
5974 l = aopGet (AOP (left), 0, FALSE);
5976 if (AOP (result)->type == AOP_REG)
5978 aopPut (AOP (result), l, 0);
5979 l = aopGet (AOP (result), 0, FALSE);
5982 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5990 emit2 ("%s a", is_signed ? "sra" : "srl");
5992 aopPut (AOP (result), "a", 0);
5996 /*-----------------------------------------------------------------*/
5997 /* AccRsh - right shift accumulator by known count */
5998 /*-----------------------------------------------------------------*/
6000 AccRsh (int shCount)
6002 static const unsigned char SRMask[] =
6004 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
6009 /* rotate right accumulator */
6010 AccRol (8 - shCount);
6011 /* and kill the higher order bits */
6012 emit2 ("and a,!immedbyte", SRMask[shCount]);
6016 /*-----------------------------------------------------------------*/
6017 /* shiftR1Left2Result - shift right one byte from left to result */
6018 /*-----------------------------------------------------------------*/
6020 shiftR1Left2Result (operand * left, int offl,
6021 operand * result, int offr,
6022 int shCount, int sign)
6024 _moveA (aopGet (AOP (left), offl, FALSE));
6029 emit2 ("%s a", sign ? "sra" : "srl");
6036 aopPut (AOP (result), "a", offr);
6039 /*-----------------------------------------------------------------*/
6040 /* genrshTwo - right shift two bytes by known amount != 0 */
6041 /*-----------------------------------------------------------------*/
6043 genrshTwo (operand * result, operand * left,
6044 int shCount, int sign)
6046 /* if shCount >= 8 */
6052 shiftR1Left2Result (left, MSB16, result, LSB,
6057 movLeft2Result (left, MSB16, result, LSB, sign);
6061 /* Sign extend the result */
6062 _moveA(aopGet (AOP (result), 0, FALSE));
6066 aopPut (AOP (result), ACC_NAME, MSB16);
6070 aopPut (AOP (result), "!zero", 1);
6073 /* 1 <= shCount <= 7 */
6076 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
6080 /*-----------------------------------------------------------------*/
6081 /* genRightShiftLiteral - left shifting by known count */
6082 /*-----------------------------------------------------------------*/
6084 genRightShiftLiteral (operand * left,
6090 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6093 freeAsmop (right, NULL, ic);
6095 aopOp (left, ic, FALSE, FALSE);
6096 aopOp (result, ic, FALSE, FALSE);
6098 size = getSize (operandType (result));
6100 /* I suppose that the left size >= result size */
6106 else if (shCount >= (size * 8)) {
6108 if (!SPEC_USIGN(getSpec(operandType(left)))) {
6109 _moveA(aopGet (AOP (left), 0, FALSE));
6117 aopPut (AOP (result), s, size);
6124 genrshOne (result, left, shCount, sign);
6127 genrshTwo (result, left, shCount, sign);
6130 wassertl (0, "Asked to shift right a long which should be a function call");
6133 wassertl (0, "Entered default case in right shift delegate");
6136 freeAsmop (left, NULL, ic);
6137 freeAsmop (result, NULL, ic);
6140 /*-----------------------------------------------------------------*/
6141 /* genRightShift - generate code for right shifting */
6142 /*-----------------------------------------------------------------*/
6144 genRightShift (iCode * ic)
6146 operand *right, *left, *result;
6148 int size, offset, first = 1;
6152 symbol *tlbl, *tlbl1;
6154 /* if signed then we do it the hard way preserve the
6155 sign bit moving it inwards */
6156 retype = getSpec (operandType (IC_RESULT (ic)));
6158 is_signed = !SPEC_USIGN (retype);
6160 /* signed & unsigned types are treated the same : i.e. the
6161 signed is NOT propagated inwards : quoting from the
6162 ANSI - standard : "for E1 >> E2, is equivalent to division
6163 by 2**E2 if unsigned or if it has a non-negative value,
6164 otherwise the result is implementation defined ", MY definition
6165 is that the sign does not get propagated */
6167 right = IC_RIGHT (ic);
6168 left = IC_LEFT (ic);
6169 result = IC_RESULT (ic);
6171 aopOp (right, ic, FALSE, FALSE);
6173 /* if the shift count is known then do it
6174 as efficiently as possible */
6175 if (AOP_TYPE (right) == AOP_LIT)
6177 genRightShiftLiteral (left, right, result, ic, is_signed);
6181 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6183 freeAsmop (right, NULL, ic);
6185 aopOp (left, ic, FALSE, FALSE);
6186 aopOp (result, ic, FALSE, FALSE);
6188 /* now move the left to the result if they are not the
6190 if (!sameRegs (AOP (left), AOP (result)))
6193 size = AOP_SIZE (result);
6197 l = aopGet (AOP (left), offset, FALSE);
6198 aopPut (AOP (result), l, offset);
6203 tlbl = newiTempLabel (NULL);
6204 tlbl1 = newiTempLabel (NULL);
6205 size = AOP_SIZE (result);
6208 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6209 emitLabel (tlbl->key + 100);
6212 l = aopGet (AOP (result), offset--, FALSE);
6215 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6223 emitLabel (tlbl1->key + 100);
6225 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6227 freeAsmop (left, NULL, ic);
6228 freeAsmop (result, NULL, ic);
6232 /*-----------------------------------------------------------------*/
6233 /* genUnpackBits - generates code for unpacking bits */
6234 /*-----------------------------------------------------------------*/
6236 genUnpackBits (operand * result, int pair)
6238 int offset = 0; /* result byte offset */
6239 int rsize; /* result size */
6240 int rlen = 0; /* remaining bitfield length */
6241 sym_link *etype; /* bitfield type information */
6242 int blen; /* bitfield length */
6243 int bstr; /* bitfield starting bit within byte */
6245 emitDebug ("; genUnpackBits");
6247 etype = getSpec (operandType (result));
6248 rsize = getSize (operandType (result));
6249 blen = SPEC_BLEN (etype);
6250 bstr = SPEC_BSTR (etype);
6252 /* If the bitfield length is less than a byte */
6255 emit2 ("ld a,!*pair", _pairs[pair].name);
6257 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6258 aopPut (AOP (result), "a", offset++);
6262 /* TODO: what if pair == PAIR_DE ? */
6263 if (getPairId (AOP (result)) == PAIR_HL)
6265 wassertl (rsize == 2, "HL must be of size 2");
6266 emit2 ("ld a,!*hl");
6268 emit2 ("ld h,!*hl");
6271 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6273 spillPair (PAIR_HL);
6277 /* Bit field did not fit in a byte. Copy all
6278 but the partial byte at the end. */
6279 for (rlen=blen;rlen>=8;rlen-=8)
6281 emit2 ("ld a,!*pair", _pairs[pair].name);
6282 aopPut (AOP (result), "a", offset++);
6285 emit2 ("inc %s", _pairs[pair].name);
6286 _G.pairs[pair].offset++;
6290 /* Handle the partial byte at the end */
6293 emit2 ("ld a,!*pair", _pairs[pair].name);
6294 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6295 aopPut (AOP (result), "a", offset++);
6303 aopPut (AOP (result), "!zero", offset++);
6307 /*-----------------------------------------------------------------*/
6308 /* genGenPointerGet - get value from generic pointer space */
6309 /*-----------------------------------------------------------------*/
6311 genGenPointerGet (operand * left,
6312 operand * result, iCode * ic)
6315 sym_link *retype = getSpec (operandType (result));
6321 aopOp (left, ic, FALSE, FALSE);
6322 aopOp (result, ic, FALSE, FALSE);
6324 size = AOP_SIZE (result);
6326 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6329 if (isPtrPair (AOP (left)))
6331 tsprintf (buffer, sizeof(buffer),
6332 "!*pair", getPairName (AOP (left)));
6333 aopPut (AOP (result), buffer, 0);
6337 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6338 aopPut (AOP (result), "a", 0);
6340 freeAsmop (left, NULL, ic);
6344 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6351 tsprintf (at, sizeof(at), "!*iyx", offset);
6352 aopPut (AOP (result), at, offset);
6356 freeAsmop (left, NULL, ic);
6360 /* For now we always load into IY */
6361 /* if this is remateriazable */
6362 fetchPair (pair, AOP (left));
6364 /* if bit then unpack */
6365 if (IS_BITVAR (retype))
6367 genUnpackBits (result, pair);
6368 freeAsmop (left, NULL, ic);
6372 else if (getPairId (AOP (result)) == PAIR_HL)
6374 wassertl (size == 2, "HL must be of size 2");
6375 emit2 ("ld a,!*hl");
6377 emit2 ("ld h,!*hl");
6379 spillPair (PAIR_HL);
6381 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6383 size = AOP_SIZE (result);
6388 /* PENDING: make this better */
6389 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6391 aopPut (AOP (result), "!*hl", offset++);
6395 emit2 ("ld a,!*pair", _pairs[pair].name);
6396 aopPut (AOP (result), "a", offset++);
6400 emit2 ("inc %s", _pairs[pair].name);
6401 _G.pairs[pair].offset++;
6404 /* Fixup HL back down */
6405 for (size = AOP_SIZE (result)-1; size; size--)
6407 emit2 ("dec %s", _pairs[pair].name);
6412 size = AOP_SIZE (result);
6417 /* PENDING: make this better */
6419 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6421 aopPut (AOP (result), "!*hl", offset++);
6425 emit2 ("ld a,!*pair", _pairs[pair].name);
6426 aopPut (AOP (result), "a", offset++);
6430 emit2 ("inc %s", _pairs[pair].name);
6431 _G.pairs[pair].offset++;
6436 freeAsmop (left, NULL, ic);
6439 freeAsmop (result, NULL, ic);
6442 /*-----------------------------------------------------------------*/
6443 /* genPointerGet - generate code for pointer get */
6444 /*-----------------------------------------------------------------*/
6446 genPointerGet (iCode * ic)
6448 operand *left, *result;
6449 sym_link *type, *etype;
6451 left = IC_LEFT (ic);
6452 result = IC_RESULT (ic);
6454 /* depending on the type of pointer we need to
6455 move it to the correct pointer register */
6456 type = operandType (left);
6457 etype = getSpec (type);
6459 genGenPointerGet (left, result, ic);
6463 isRegOrLit (asmop * aop)
6465 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6471 /*-----------------------------------------------------------------*/
6472 /* genPackBits - generates code for packed bit storage */
6473 /*-----------------------------------------------------------------*/
6475 genPackBits (sym_link * etype,
6480 int offset = 0; /* source byte offset */
6481 int rlen = 0; /* remaining bitfield length */
6482 int blen; /* bitfield length */
6483 int bstr; /* bitfield starting bit within byte */
6484 int litval; /* source literal value (if AOP_LIT) */
6485 unsigned char mask; /* bitmask within current byte */
6486 int extraPair; /* a tempory register */
6487 bool needPopExtra=0; /* need to restore original value of temp reg */
6489 emitDebug ("; genPackBits","");
6491 blen = SPEC_BLEN (etype);
6492 bstr = SPEC_BSTR (etype);
6494 /* If the bitfield length is less than a byte */
6497 mask = ((unsigned char) (0xFF << (blen + bstr)) |
6498 (unsigned char) (0xFF >> (8 - bstr)));
6500 if (AOP_TYPE (right) == AOP_LIT)
6502 /* Case with a bitfield length <8 and literal source
6504 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6506 litval &= (~mask) & 0xff;
6507 emit2 ("ld a,!*pair", _pairs[pair].name);
6508 if ((mask|litval)!=0xff)
6509 emit2 ("and a,!immedbyte", mask);
6511 emit2 ("or a,!immedbyte", litval);
6512 emit2 ("ld !*pair,a", _pairs[pair].name);
6517 /* Case with a bitfield length <8 and arbitrary source
6519 _moveA (aopGet (AOP (right), 0, FALSE));
6520 /* shift and mask source value */
6522 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6524 extraPair = getFreePairId(ic);
6525 if (extraPair == PAIR_INVALID)
6527 extraPair = PAIR_BC;
6528 if (getPairId (AOP (right)) != PAIR_BC
6529 || !isLastUse (ic, right))
6535 emit2 ("ld %s,a", _pairs[extraPair].l);
6536 emit2 ("ld a,!*pair", _pairs[pair].name);
6538 emit2 ("and a,!immedbyte", mask);
6539 emit2 ("or a,%s", _pairs[extraPair].l);
6540 emit2 ("ld !*pair,a", _pairs[pair].name);
6547 /* Bit length is greater than 7 bits. In this case, copy */
6548 /* all except the partial byte at the end */
6549 for (rlen=blen;rlen>=8;rlen-=8)
6551 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
6552 emit2 ("ld !*pair,a", _pairs[pair].name);
6555 emit2 ("inc %s", _pairs[pair].name);
6556 _G.pairs[pair].offset++;
6560 /* If there was a partial byte at the end */
6563 mask = (((unsigned char) -1 << rlen) & 0xff);
6565 if (AOP_TYPE (right) == AOP_LIT)
6567 /* Case with partial byte and literal source
6569 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6570 litval >>= (blen-rlen);
6571 litval &= (~mask) & 0xff;
6572 emit2 ("ld a,!*pair", _pairs[pair].name);
6573 if ((mask|litval)!=0xff)
6574 emit2 ("and a,!immedbyte", mask);
6576 emit2 ("or a,!immedbyte", litval);
6580 /* Case with partial byte and arbitrary source
6582 _moveA (aopGet (AOP (right), offset++, FALSE));
6583 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6585 extraPair = getFreePairId(ic);
6586 if (extraPair == PAIR_INVALID)
6588 extraPair = getPairId (AOP (right));
6589 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
6590 extraPair = PAIR_BC;
6592 if (getPairId (AOP (right)) != PAIR_BC
6593 || !isLastUse (ic, right))
6599 emit2 ("ld %s,a", _pairs[extraPair].l);
6600 emit2 ("ld a,!*pair", _pairs[pair].name);
6602 emit2 ("and a,!immedbyte", mask);
6603 emit2 ("or a,%s", _pairs[extraPair].l);
6608 emit2 ("ld !*pair,a", _pairs[pair].name);
6613 /*-----------------------------------------------------------------*/
6614 /* genGenPointerSet - stores the value into a pointer location */
6615 /*-----------------------------------------------------------------*/
6617 genGenPointerSet (operand * right,
6618 operand * result, iCode * ic)
6621 sym_link *retype = getSpec (operandType (right));
6622 sym_link *letype = getSpec (operandType (result));
6623 PAIR_ID pairId = PAIR_HL;
6626 aopOp (result, ic, FALSE, FALSE);
6627 aopOp (right, ic, FALSE, FALSE);
6632 size = AOP_SIZE (right);
6634 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
6635 emitDebug("; isBitvar = %d", isBitvar);
6637 /* Handle the exceptions first */
6638 if (isPair (AOP (result)) && size == 1 && !isBitvar)
6641 const char *l = aopGet (AOP (right), 0, FALSE);
6642 const char *pair = getPairName (AOP (result));
6643 if (canAssignToPtr (l) && isPtr (pair))
6645 emit2 ("ld !*pair,%s", pair, l);
6650 emit2 ("ld !*pair,a", pair);
6655 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
6658 const char *l = aopGet (AOP (right), 0, FALSE);
6663 if (canAssignToPtr (l))
6665 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6669 _moveA (aopGet (AOP (right), offset, FALSE));
6670 emit2 ("ld !*iyx,a", offset);
6676 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
6683 const char *l = aopGet (AOP (right), offset, FALSE);
6684 if (isRegOrLit (AOP (right)) && !IS_GB)
6686 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
6691 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
6695 emit2 ("inc %s", _pairs[PAIR_HL].name);
6696 _G.pairs[PAIR_HL].offset++;
6701 /* Fixup HL back down */
6702 for (size = AOP_SIZE (right)-1; size; size--)
6704 emit2 ("dec %s", _pairs[PAIR_HL].name);
6709 /* if the operand is already in dptr
6710 then we do nothing else we move the value to dptr */
6711 if (AOP_TYPE (result) != AOP_STR)
6713 fetchPair (pairId, AOP (result));
6715 /* so hl know contains the address */
6716 freeAsmop (result, NULL, ic);
6718 /* if bit then unpack */
6721 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
6731 const char *l = aopGet (AOP (right), offset, FALSE);
6732 if (isRegOrLit (AOP (right)) && !IS_GB)
6734 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
6739 emit2 ("ld !*pair,a", _pairs[pairId].name);
6743 emit2 ("inc %s", _pairs[pairId].name);
6744 _G.pairs[pairId].offset++;
6750 freeAsmop (right, NULL, ic);
6753 /*-----------------------------------------------------------------*/
6754 /* genPointerSet - stores the value into a pointer location */
6755 /*-----------------------------------------------------------------*/
6757 genPointerSet (iCode * ic)
6759 operand *right, *result;
6760 sym_link *type, *etype;
6762 right = IC_RIGHT (ic);
6763 result = IC_RESULT (ic);
6765 /* depending on the type of pointer we need to
6766 move it to the correct pointer register */
6767 type = operandType (result);
6768 etype = getSpec (type);
6770 genGenPointerSet (right, result, ic);
6773 /*-----------------------------------------------------------------*/
6774 /* genIfx - generate code for Ifx statement */
6775 /*-----------------------------------------------------------------*/
6777 genIfx (iCode * ic, iCode * popIc)
6779 operand *cond = IC_COND (ic);
6782 aopOp (cond, ic, FALSE, TRUE);
6784 /* get the value into acc */
6785 if (AOP_TYPE (cond) != AOP_CRY)
6789 /* the result is now in the accumulator */
6790 freeAsmop (cond, NULL, ic);
6792 /* if there was something to be popped then do it */
6796 /* if the condition is a bit variable */
6797 if (isbit && IS_ITEMP (cond) &&
6799 genIfxJump (ic, SPIL_LOC (cond)->rname);
6800 else if (isbit && !IS_ITEMP (cond))
6801 genIfxJump (ic, OP_SYMBOL (cond)->rname);
6803 genIfxJump (ic, "a");
6808 /*-----------------------------------------------------------------*/
6809 /* genAddrOf - generates code for address of */
6810 /*-----------------------------------------------------------------*/
6812 genAddrOf (iCode * ic)
6814 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
6816 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6818 /* if the operand is on the stack then we
6819 need to get the stack offset of this
6826 if (sym->stack <= 0)
6828 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
6832 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6834 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6838 emit2 ("ld de,!hashedstr", sym->rname);
6839 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
6847 /* if it has an offset then we need to compute it */
6849 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6851 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
6852 emit2 ("add hl,sp");
6856 emit2 ("ld hl,!hashedstr", sym->rname);
6858 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6860 freeAsmop (IC_RESULT (ic), NULL, ic);
6863 /*-----------------------------------------------------------------*/
6864 /* genAssign - generate code for assignment */
6865 /*-----------------------------------------------------------------*/
6867 genAssign (iCode * ic)
6869 operand *result, *right;
6871 unsigned long lit = 0L;
6873 result = IC_RESULT (ic);
6874 right = IC_RIGHT (ic);
6876 /* Dont bother assigning if they are the same */
6877 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6879 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
6883 aopOp (right, ic, FALSE, FALSE);
6884 aopOp (result, ic, TRUE, FALSE);
6886 /* if they are the same registers */
6887 if (sameRegs (AOP (right), AOP (result)))
6889 emitDebug ("; (registers are the same)");
6893 /* if the result is a bit */
6894 if (AOP_TYPE (result) == AOP_CRY)
6896 wassertl (0, "Tried to assign to a bit");
6900 size = AOP_SIZE (result);
6903 if (AOP_TYPE (right) == AOP_LIT)
6905 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6908 if (isPair (AOP (result)))
6910 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
6912 else if ((size > 1) &&
6913 (AOP_TYPE (result) != AOP_REG) &&
6914 (AOP_TYPE (right) == AOP_LIT) &&
6915 !IS_FLOAT (operandType (right)) &&
6918 bool fXored = FALSE;
6920 /* Work from the top down.
6921 Done this way so that we can use the cached copy of 0
6922 in A for a fast clear */
6925 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
6927 if (!fXored && size > 1)
6934 aopPut (AOP (result), "a", offset);
6938 aopPut (AOP (result), "!zero", offset);
6942 aopPut (AOP (result),
6943 aopGet (AOP (right), offset, FALSE),
6948 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
6950 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
6951 aopPut (AOP (result), "l", LSB);
6952 aopPut (AOP (result), "h", MSB16);
6954 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6956 /* Special case. Load into a and d, then load out. */
6957 _moveA (aopGet (AOP (right), 0, FALSE));
6958 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
6959 aopPut (AOP (result), "a", 0);
6960 aopPut (AOP (result), "e", 1);
6962 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6964 /* Special case - simple memcpy */
6965 aopGet (AOP (right), LSB, FALSE);
6968 aopGet (AOP (result), LSB, FALSE);
6972 emit2 ("ld a,(de)");
6973 /* Peephole will optimise this. */
6974 emit2 ("ld (hl),a");
6982 spillPair (PAIR_HL);
6988 /* PENDING: do this check better */
6989 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
6991 _moveA (aopGet (AOP (right), offset, FALSE));
6992 aopPut (AOP (result), "a", offset);
6995 aopPut (AOP (result),
6996 aopGet (AOP (right), offset, FALSE),
7003 freeAsmop (right, NULL, ic);
7004 freeAsmop (result, NULL, ic);
7007 /*-----------------------------------------------------------------*/
7008 /* genJumpTab - genrates code for jump table */
7009 /*-----------------------------------------------------------------*/
7011 genJumpTab (iCode * ic)
7016 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
7017 /* get the condition into accumulator */
7018 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
7021 emit2 ("ld e,%s", l);
7022 emit2 ("ld d,!zero");
7023 jtab = newiTempLabel (NULL);
7025 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
7026 emit2 ("add hl,de");
7027 emit2 ("add hl,de");
7028 emit2 ("add hl,de");
7029 freeAsmop (IC_JTCOND (ic), NULL, ic);
7033 emitLabel (jtab->key + 100);
7034 /* now generate the jump labels */
7035 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
7036 jtab = setNextItem (IC_JTLABELS (ic)))
7037 emit2 ("jp !tlabel", jtab->key + 100);
7040 /*-----------------------------------------------------------------*/
7041 /* genCast - gen code for casting */
7042 /*-----------------------------------------------------------------*/
7044 genCast (iCode * ic)
7046 operand *result = IC_RESULT (ic);
7047 sym_link *rtype = operandType (IC_RIGHT (ic));
7048 operand *right = IC_RIGHT (ic);
7051 /* if they are equivalent then do nothing */
7052 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
7055 aopOp (right, ic, FALSE, FALSE);
7056 aopOp (result, ic, FALSE, FALSE);
7058 /* if the result is a bit */
7059 if (AOP_TYPE (result) == AOP_CRY)
7061 wassertl (0, "Tried to cast to a bit");
7064 /* if they are the same size : or less */
7065 if (AOP_SIZE (result) <= AOP_SIZE (right))
7068 /* if they are in the same place */
7069 if (sameRegs (AOP (right), AOP (result)))
7072 /* if they in different places then copy */
7073 size = AOP_SIZE (result);
7077 aopPut (AOP (result),
7078 aopGet (AOP (right), offset, FALSE),
7085 /* So we now know that the size of destination is greater
7086 than the size of the source */
7087 /* we move to result for the size of source */
7088 size = AOP_SIZE (right);
7092 aopPut (AOP (result),
7093 aopGet (AOP (right), offset, FALSE),
7098 /* now depending on the sign of the destination */
7099 size = AOP_SIZE (result) - AOP_SIZE (right);
7100 /* Unsigned or not an integral type - right fill with zeros */
7101 if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
7104 aopPut (AOP (result), "!zero", offset++);
7108 /* we need to extend the sign :{ */
7109 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
7115 aopPut (AOP (result), "a", offset++);
7119 freeAsmop (right, NULL, ic);
7120 freeAsmop (result, NULL, ic);
7123 /*-----------------------------------------------------------------*/
7124 /* genReceive - generate code for a receive iCode */
7125 /*-----------------------------------------------------------------*/
7127 genReceive (iCode * ic)
7129 if (isOperandInFarSpace (IC_RESULT (ic)) &&
7130 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
7131 IS_TRUE_SYMOP (IC_RESULT (ic))))
7141 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7142 size = AOP_SIZE(IC_RESULT(ic));
7144 for (i = 0; i < size; i++) {
7145 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7149 freeAsmop (IC_RESULT (ic), NULL, ic);
7152 /*-----------------------------------------------------------------*/
7153 /* genDummyRead - generate code for dummy read of volatiles */
7154 /*-----------------------------------------------------------------*/
7156 genDummyRead (iCode * ic)
7161 right = IC_RIGHT (ic);
7162 aopOp (right, ic, FALSE, FALSE);
7165 size = AOP_SIZE (right);
7170 _moveA (aopGet (AOP (right), offset, FALSE));
7174 freeAsmop (right, NULL, ic);
7179 /** Maximum number of bytes to emit per line. */
7183 /** Context for the byte output chunker. */
7186 unsigned char buffer[DBEMIT_MAX_RUN];
7191 /** Flushes a byte chunker by writing out all in the buffer and
7195 _dbFlush(DBEMITCTX *self)
7202 sprintf(line, ".db 0x%02X", self->buffer[0]);
7204 for (i = 1; i < self->pos; i++)
7206 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7213 /** Write out another byte, buffering until a decent line is
7217 _dbEmit(DBEMITCTX *self, int c)
7219 if (self->pos == DBEMIT_MAX_RUN)
7223 self->buffer[self->pos++] = c;
7226 /** Context for a simple run length encoder. */
7230 unsigned char buffer[128];
7232 /** runLen may be equivalent to pos. */
7238 RLE_CHANGE_COST = 4,
7242 /** Flush the buffer of a run length encoder by writing out the run or
7243 data that it currently contains.
7246 _rleCommit(RLECTX *self)
7252 memset(&db, 0, sizeof(db));
7254 emit2(".db %u", self->pos);
7256 for (i = 0; i < self->pos; i++)
7258 _dbEmit(&db, self->buffer[i]);
7267 Can get either a run or a block of random stuff.
7268 Only want to change state if a good run comes in or a run ends.
7269 Detecting run end is easy.
7272 Say initial state is in run, len zero, last zero. Then if you get a
7273 few zeros then something else then a short run will be output.
7274 Seems OK. While in run mode, keep counting. While in random mode,
7275 keep a count of the run. If run hits margin, output all up to run,
7276 restart, enter run mode.
7279 /** Add another byte into the run length encoder, flushing as
7280 required. The run length encoder uses the Amiga IFF style, where
7281 a block is prefixed by its run length. A positive length means
7282 the next n bytes pass straight through. A negative length means
7283 that the next byte is repeated -n times. A zero terminates the
7287 _rleAppend(RLECTX *self, int c)
7291 if (c != self->last)
7293 /* The run has stopped. See if it is worthwhile writing it out
7294 as a run. Note that the random data comes in as runs of
7297 if (self->runLen > RLE_CHANGE_COST)
7299 /* Yes, worthwhile. */
7300 /* Commit whatever was in the buffer. */
7302 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7306 /* Not worthwhile. Append to the end of the random list. */
7307 for (i = 0; i < self->runLen; i++)
7309 if (self->pos >= RLE_MAX_BLOCK)
7314 self->buffer[self->pos++] = self->last;
7322 if (self->runLen >= RLE_MAX_BLOCK)
7324 /* Commit whatever was in the buffer. */
7327 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7335 _rleFlush(RLECTX *self)
7337 _rleAppend(self, -1);
7344 /** genArrayInit - Special code for initialising an array with constant
7348 genArrayInit (iCode * ic)
7352 int elementSize = 0, eIndex, i;
7353 unsigned val, lastVal;
7357 memset(&rle, 0, sizeof(rle));
7359 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7361 _saveRegsForCall(ic, 0);
7363 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7364 emit2 ("call __initrleblock");
7366 type = operandType(IC_LEFT(ic));
7368 if (type && type->next)
7370 elementSize = getSize(type->next);
7374 wassertl (0, "Can't determine element size in genArrayInit.");
7377 iLoop = IC_ARRAYILIST(ic);
7378 lastVal = (unsigned)-1;
7380 /* Feed all the bytes into the run length encoder which will handle
7382 This works well for mixed char data, and for random int and long
7391 for (i = 0; i < ix; i++)
7393 for (eIndex = 0; eIndex < elementSize; eIndex++)
7395 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7396 _rleAppend(&rle, val);
7401 iLoop = iLoop->next;
7405 /* Mark the end of the run. */
7408 _restoreRegsAfterCall();
7412 freeAsmop (IC_LEFT(ic), NULL, ic);
7416 _swap (PAIR_ID one, PAIR_ID two)
7418 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7424 emit2 ("ld a,%s", _pairs[one].l);
7425 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7426 emit2 ("ld %s,a", _pairs[two].l);
7427 emit2 ("ld a,%s", _pairs[one].h);
7428 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7429 emit2 ("ld %s,a", _pairs[two].h);
7433 /* The problem is that we may have all three pairs used and they may
7434 be needed in a different order.
7439 hl = hl => unity, fine
7443 hl = hl hl = hl, swap de <=> bc
7451 hl = bc de = de, swap bc <=> hl
7459 hl = de bc = bc, swap hl <=> de
7464 * Any pair = pair are done last
7465 * Any pair = iTemp are done last
7466 * Any swaps can be done any time
7474 So how do we detect the cases?
7475 How about a 3x3 matrix?
7479 x x x x (Fourth for iTemp/other)
7481 First determin which mode to use by counting the number of unity and
7484 Two - Assign the pair first, then the rest
7485 One - Swap the two, then the rest
7489 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7491 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7493 PAIR_BC, PAIR_HL, PAIR_DE
7495 int i, j, nunity = 0;
7496 memset (ids, PAIR_INVALID, sizeof (ids));
7499 wassert (nparams == 3);
7501 /* First save everything that needs to be saved. */
7502 _saveRegsForCall (ic, 0);
7504 /* Loading HL first means that DE is always fine. */
7505 for (i = 0; i < nparams; i++)
7507 aopOp (pparams[i], ic, FALSE, FALSE);
7508 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7511 /* Count the number of unity or iTemp assigns. */
7512 for (i = 0; i < 3; i++)
7514 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7522 /* Any order, fall through. */
7524 else if (nunity == 2)
7526 /* One is assigned. Pull it out and assign. */
7527 for (i = 0; i < 3; i++)
7529 for (j = 0; j < NUM_PAIRS; j++)
7531 if (ids[dest[i]][j] == TRUE)
7533 /* Found it. See if it's the right one. */
7534 if (j == PAIR_INVALID || j == dest[i])
7540 fetchPair(dest[i], AOP (pparams[i]));
7547 else if (nunity == 1)
7549 /* Find the pairs to swap. */
7550 for (i = 0; i < 3; i++)
7552 for (j = 0; j < NUM_PAIRS; j++)
7554 if (ids[dest[i]][j] == TRUE)
7556 if (j == PAIR_INVALID || j == dest[i])
7571 int next = getPairId (AOP (pparams[0]));
7572 emit2 ("push %s", _pairs[next].name);
7574 if (next == dest[1])
7576 fetchPair (dest[1], AOP (pparams[1]));
7577 fetchPair (dest[2], AOP (pparams[2]));
7581 fetchPair (dest[2], AOP (pparams[2]));
7582 fetchPair (dest[1], AOP (pparams[1]));
7584 emit2 ("pop %s", _pairs[dest[0]].name);
7587 /* Finally pull out all of the iTemps */
7588 for (i = 0; i < 3; i++)
7590 if (ids[dest[i]][PAIR_INVALID] == 1)
7592 fetchPair (dest[i], AOP (pparams[i]));
7598 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
7604 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
7608 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7610 setupForBuiltin3 (ic, nParams, pparams);
7612 label = newiTempLabel(NULL);
7614 emitLabel (label->key);
7615 emit2 ("ld a,(hl)");
7618 emit2 ("!shortjp nz,!tlabel ; 1", label->key);
7620 freeAsmop (from, NULL, ic->next);
7621 freeAsmop (to, NULL, ic);
7625 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
7627 operand *from, *to, *count;
7630 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
7635 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7637 setupForBuiltin3 (ic, nParams, pparams);
7641 freeAsmop (count, NULL, ic->next->next);
7642 freeAsmop (from, NULL, ic);
7644 _restoreRegsAfterCall();
7646 /* if we need assign a result value */
7647 if ((IS_ITEMP (IC_RESULT (ic)) &&
7648 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
7649 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
7650 IS_TRUE_SYMOP (IC_RESULT (ic)))
7652 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7653 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
7654 freeAsmop (IC_RESULT (ic), NULL, ic);
7657 freeAsmop (to, NULL, ic->next);
7660 /*-----------------------------------------------------------------*/
7661 /* genBuiltIn - calls the appropriate function to generating code */
7662 /* for a built in function */
7663 /*-----------------------------------------------------------------*/
7664 static void genBuiltIn (iCode *ic)
7666 operand *bi_parms[MAX_BUILTIN_ARGS];
7671 /* get all the arguments for a built in function */
7672 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
7674 /* which function is it */
7675 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
7677 if (strcmp(bif->name,"__builtin_strcpy")==0)
7679 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
7681 else if (strcmp(bif->name,"__builtin_memcpy")==0)
7683 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
7687 wassertl (0, "Unknown builtin function encountered");
7691 /*-----------------------------------------------------------------*/
7692 /* genZ80Code - generate code for Z80 based controllers */
7693 /*-----------------------------------------------------------------*/
7695 genZ80Code (iCode * lic)
7703 _fReturn = _gbz80_return;
7704 _fTmp = _gbz80_return;
7708 _fReturn = _z80_return;
7709 _fTmp = _z80_return;
7712 _G.lines.head = _G.lines.current = NULL;
7714 /* if debug information required */
7715 if (options.debug && currFunc)
7717 debugFile->writeFunction(currFunc);
7718 _G.lines.isDebug = 1;
7719 if (IS_STATIC (currFunc->etype))
7720 sprintf (buffer, "F%s$%s$0$0", moduleName, currFunc->name);
7722 sprintf (buffer, "G$%s$0$0", currFunc->name);
7723 emit2 ("!labeldef", buffer);
7724 _G.lines.isDebug = 0;
7727 for (ic = lic; ic; ic = ic->next)
7729 _G.current_iCode = ic;
7731 if (ic->lineno && cln != ic->lineno)
7735 _G.lines.isDebug = 1;
7736 sprintf (buffer, "C$%s$%d$%d$%d",
7737 FileBaseName (ic->filename), ic->lineno,
7738 ic->level, ic->block);
7739 emit2 ("%s !equ .", buffer);
7740 emit2 ("!global", buffer);
7741 _G.lines.isDebug = 0;
7743 if (!options.noCcodeInAsm) {
7744 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
7745 printCLine(ic->filename, ic->lineno));
7749 if (options.iCodeInAsm) {
7750 emit2 (";ic:%d: %s", ic->key, printILine(ic));
7752 /* if the result is marked as
7753 spilt and rematerializable or code for
7754 this has already been generated then
7756 if (resultRemat (ic) || ic->generated)
7759 /* depending on the operation */
7763 emitDebug ("; genNot");
7768 emitDebug ("; genCpl");
7773 emitDebug ("; genUminus");
7778 emitDebug ("; genIpush");
7783 /* IPOP happens only when trying to restore a
7784 spilt live range, if there is an ifx statement
7785 following this pop then the if statement might
7786 be using some of the registers being popped which
7787 would destory the contents of the register so
7788 we need to check for this condition and handle it */
7790 ic->next->op == IFX &&
7791 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
7793 emitDebug ("; genIfx");
7794 genIfx (ic->next, ic);
7798 emitDebug ("; genIpop");
7804 emitDebug ("; genCall");
7809 emitDebug ("; genPcall");
7814 emitDebug ("; genFunction");
7819 emitDebug ("; genEndFunction");
7820 genEndFunction (ic);
7824 emitDebug ("; genRet");
7829 emitDebug ("; genLabel");
7834 emitDebug ("; genGoto");
7839 emitDebug ("; genPlus");
7844 emitDebug ("; genMinus");
7849 emitDebug ("; genMult");
7854 emitDebug ("; genDiv");
7859 emitDebug ("; genMod");
7864 emitDebug ("; genCmpGt");
7865 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
7869 emitDebug ("; genCmpLt");
7870 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
7877 /* note these two are xlated by algebraic equivalence
7878 during parsing SDCC.y */
7879 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
7880 "got '>=' or '<=' shouldn't have come here");
7884 emitDebug ("; genCmpEq");
7885 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
7889 emitDebug ("; genAndOp");
7894 emitDebug ("; genOrOp");
7899 emitDebug ("; genXor");
7900 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
7904 emitDebug ("; genOr");
7905 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
7909 emitDebug ("; genAnd");
7910 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
7914 emitDebug ("; genInline");
7919 emitDebug ("; genRRC");
7924 emitDebug ("; genRLC");
7929 emitDebug ("; genGetHBIT");
7934 emitDebug ("; genLeftShift");
7939 emitDebug ("; genRightShift");
7943 case GET_VALUE_AT_ADDRESS:
7944 emitDebug ("; genPointerGet");
7950 if (POINTER_SET (ic))
7952 emitDebug ("; genAssign (pointer)");
7957 emitDebug ("; genAssign");
7963 emitDebug ("; genIfx");
7968 emitDebug ("; genAddrOf");
7973 emitDebug ("; genJumpTab");
7978 emitDebug ("; genCast");
7983 emitDebug ("; genReceive");
7988 if (ic->builtinSEND)
7990 emitDebug ("; genBuiltIn");
7995 emitDebug ("; addSet");
7996 addSet (&_G.sendSet, ic);
8001 emitDebug ("; genArrayInit");
8005 case DUMMY_READ_VOLATILE:
8006 emitDebug ("; genDummyRead");
8016 /* now we are ready to call the
8017 peep hole optimizer */
8018 if (!options.nopeep)
8019 peepHole (&_G.lines.head);
8021 /* This is unfortunate */
8022 /* now do the actual printing */
8024 FILE *fp = codeOutFile;
8025 if (isInHome () && codeOutFile == code->oFile)
8026 codeOutFile = home->oFile;
8027 printLine (_G.lines.head, codeOutFile);
8028 if (_G.flushStatics)
8031 _G.flushStatics = 0;
8036 freeTrace(&_G.lines.trace);
8037 freeTrace(&_G.trace.aops);
8043 _isPairUsed (iCode * ic, PAIR_ID pairId)
8049 if (bitVectBitValue (ic->rMask, D_IDX))
8051 if (bitVectBitValue (ic->rMask, E_IDX))
8061 fetchLitSpecial (asmop * aop, bool negate, bool xor)
8064 value *val = aop->aopu.aop_lit;
8066 wassert (aop->type == AOP_LIT);
8067 wassert (!IS_FLOAT (val->type));
8069 v = (unsigned long) floatFromVal (val);
8077 tsprintf (buffer, sizeof(buffer), "!immedword", v);
8078 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));