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.
221 const char *lastFunctionName;
227 /** TRUE if the registers have already been saved. */
245 static const char *aopGet (asmop * aop, int offset, bool bit16);
247 static const char *aopNames[] = {
267 isLastUse (iCode *ic, operand *op)
269 bitVect *uses = bitVectCopy (OP_USES (op));
271 while (!bitVectIsZero (uses))
273 if (bitVectFirstBit (uses) == ic->key)
275 if (bitVectnBitsOn (uses) == 1)
284 bitVectUnSetBit (uses, bitVectFirstBit (uses));
304 _getTempPairName(void)
306 return _pairs[_getTempPairId()].name;
310 isPairInUse (PAIR_ID id, iCode *ic)
314 return bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
316 else if (id == PAIR_BC)
318 return bitVectBitValue (ic->rMask, B_IDX) || bitVectBitValue(ic->rMask, C_IDX);
322 wassertl (0, "Only implemented for DE and BC");
328 isPairInUseNotInRet(PAIR_ID id, iCode *ic)
332 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
336 return bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
340 wassertl (0, "Only implemented for DE");
346 getFreePairId (iCode *ic)
348 if (!isPairInUse (PAIR_BC, ic))
352 else if (IS_Z80 && !isPairInUse (PAIR_DE, ic))
365 /* Clean up the line so that it is 'prettier' */
366 if (strchr (buf, ':'))
368 /* Is a label - cant do anything */
371 /* Change the first (and probably only) ' ' to a tab so
386 _newLineNode (char *line)
390 pl = traceAlloc(&_G.lines.trace, Safe_alloc ( sizeof (lineNode)));
391 pl->line = traceAlloc(&_G.lines.trace, Safe_strdup (line));
397 _vemit2 (const char *szFormat, va_list ap)
401 tvsprintf (buffer, sizeof(buffer), szFormat, ap);
404 _G.lines.current = (_G.lines.current ?
405 connectLine (_G.lines.current, _newLineNode (buffer)) :
406 (_G.lines.head = _newLineNode (buffer)));
408 _G.lines.current->isInline = _G.lines.isInline;
412 emit2 (const char *szFormat,...)
416 va_start (ap, szFormat);
418 _vemit2 (szFormat, ap);
424 emitDebug (const char *szFormat,...)
430 va_start (ap, szFormat);
432 _vemit2 (szFormat, ap);
438 /*-----------------------------------------------------------------*/
439 /* emit2 - writes the code into a file : for now it is simple */
440 /*-----------------------------------------------------------------*/
442 _emit2 (const char *inst, const char *fmt,...)
445 char lb[INITIAL_INLINEASM];
452 sprintf (lb, "%s\t", inst);
453 vsprintf (lb + (strlen (lb)), fmt, ap);
456 vsprintf (lb, fmt, ap);
458 while (isspace (*lbp))
463 _G.lines.current = (_G.lines.current ?
464 connectLine (_G.lines.current, _newLineNode (lb)) :
465 (_G.lines.head = _newLineNode (lb)));
467 _G.lines.current->isInline = _G.lines.isInline;
472 _emitMove(const char *to, const char *from)
474 if (STRCASECMP(to, from) != 0)
476 emit2("ld %s,%s", to, from);
481 // Could leave this to the peephole, but sometimes the peephole is inhibited.
486 aopDump(const char *plabel, asmop *aop)
488 emitDebug("; Dump of %s: type %s size %u", plabel, aopNames[aop->type], aop->size);
492 emitDebug("; aop_stk %d", aop->aopu.aop_stk);
495 /* No information. */
501 _moveA(const char *moveFrom)
503 // Let the peephole optimiser take care of redundent loads
504 _emitMove(ACC_NAME, moveFrom);
514 getPairName (asmop * aop)
516 if (aop->type == AOP_REG)
518 switch (aop->aopu.aop_reg[0]->rIdx)
531 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
534 for (i = 0; i < NUM_PAIRS; i++)
536 if (strcmp(aop->aopu.aop_str[0], _pairs[i].l) == 0)
538 return _pairs[i].name;
542 wassertl (0, "Tried to get the pair name of something that isn't a pair");
547 getPairId (asmop * aop)
551 if (aop->type == AOP_REG)
553 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX) && (aop->aopu.aop_reg[1]->rIdx == B_IDX))
557 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX) && (aop->aopu.aop_reg[1]->rIdx == D_IDX))
561 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX) && (aop->aopu.aop_reg[1]->rIdx == H_IDX))
566 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
569 for (i = 0; i < NUM_PAIRS; i++)
571 if (!strcmp (aop->aopu.aop_str[0], _pairs[i].l) && !strcmp (aop->aopu.aop_str[1], _pairs[i].h))
581 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
585 return (getPairId (aop) != PAIR_INVALID);
589 isPtrPair (asmop * aop)
591 PAIR_ID pairId = getPairId (aop);
604 spillPair (PAIR_ID pairId)
606 _G.pairs[pairId].last_type = AOP_INVALID;
607 _G.pairs[pairId].base = NULL;
610 /** Push a register pair onto the stack */
612 genPairPush (asmop * aop)
614 emit2 ("push %s", getPairName (aop));
618 _push (PAIR_ID pairId)
620 emit2 ("push %s", _pairs[pairId].name);
621 _G.stack.pushed += 2;
625 _pop (PAIR_ID pairId)
627 emit2 ("pop %s", _pairs[pairId].name);
628 _G.stack.pushed -= 2;
632 /*-----------------------------------------------------------------*/
633 /* newAsmop - creates a new asmOp */
634 /*-----------------------------------------------------------------*/
636 newAsmop (short type)
640 aop = traceAlloc(&_G.trace.aops, Safe_alloc (sizeof (asmop)));
645 /*-----------------------------------------------------------------*/
646 /* aopForSym - for a true symbol */
647 /*-----------------------------------------------------------------*/
649 aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
656 wassert (sym->etype);
658 space = SPEC_OCLS (sym->etype);
660 /* if already has one */
666 /* Assign depending on the storage class */
667 if (sym->onStack || sym->iaccess)
669 /* The pointer that is used depends on how big the offset is.
670 Normally everything is AOP_STK, but for offsets of < -128 or
671 > 127 on the Z80 an extended stack pointer is used.
673 if (IS_Z80 && (options.ommitFramePtr || sym->stack < INT8MIN || sym->stack > (int)(INT8MAX-getSize (sym->type))))
675 emitDebug ("; AOP_EXSTK for %s", sym->rname);
676 sym->aop = aop = newAsmop (AOP_EXSTK);
680 emitDebug ("; AOP_STK for %s", sym->rname);
681 sym->aop = aop = newAsmop (AOP_STK);
684 aop->size = getSize (sym->type);
685 aop->aopu.aop_stk = sym->stack;
689 /* special case for a function */
690 if (IS_FUNC (sym->type))
692 sym->aop = aop = newAsmop (AOP_IMMD);
693 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup (sym->rname));
700 /* if it is in direct space */
701 if (IN_REGSP (space) && !requires_a)
703 sym->aop = aop = newAsmop (AOP_SFR);
704 aop->aopu.aop_dir = sym->rname;
705 aop->size = getSize (sym->type);
706 emitDebug ("; AOP_SFR for %s", sym->rname);
711 /* only remaining is far space */
712 /* in which case DPTR gets the address */
715 emitDebug ("; AOP_HL for %s", sym->rname);
716 sym->aop = aop = newAsmop (AOP_HL);
720 sym->aop = aop = newAsmop (AOP_IY);
722 aop->size = getSize (sym->type);
723 aop->aopu.aop_dir = sym->rname;
725 /* if it is in code space */
726 if (IN_CODESPACE (space))
732 /*-----------------------------------------------------------------*/
733 /* aopForRemat - rematerialzes an object */
734 /*-----------------------------------------------------------------*/
736 aopForRemat (symbol * sym)
739 iCode *ic = sym->rematiCode;
740 asmop *aop = newAsmop (AOP_IMMD);
744 /* if plus or minus print the right hand side */
745 if (ic->op == '+' || ic->op == '-')
747 /* PENDING: for re-target */
748 sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
751 ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
754 /* we reached the end */
755 sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
759 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
763 /*-----------------------------------------------------------------*/
764 /* regsInCommon - two operands have some registers in common */
765 /*-----------------------------------------------------------------*/
767 regsInCommon (operand * op1, operand * op2)
772 /* if they have registers in common */
773 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
776 sym1 = OP_SYMBOL (op1);
777 sym2 = OP_SYMBOL (op2);
779 if (sym1->nRegs == 0 || sym2->nRegs == 0)
782 for (i = 0; i < sym1->nRegs; i++)
788 for (j = 0; j < sym2->nRegs; j++)
793 if (sym2->regs[j] == sym1->regs[i])
801 /*-----------------------------------------------------------------*/
802 /* operandsEqu - equivalent */
803 /*-----------------------------------------------------------------*/
805 operandsEqu (operand * op1, operand * op2)
809 /* if they not symbols */
810 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
813 sym1 = OP_SYMBOL (op1);
814 sym2 = OP_SYMBOL (op2);
816 /* if both are itemps & one is spilt
817 and the other is not then false */
818 if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
819 sym1->isspilt != sym2->isspilt)
822 /* if they are the same */
826 if (strcmp (sym1->rname, sym2->rname) == 0)
830 /* if left is a tmp & right is not */
831 if (IS_ITEMP (op1) &&
834 (sym1->usl.spillLoc == sym2))
837 if (IS_ITEMP (op2) &&
841 (sym2->usl.spillLoc == sym1))
847 /*-----------------------------------------------------------------*/
848 /* sameRegs - two asmops have the same registers */
849 /*-----------------------------------------------------------------*/
851 sameRegs (asmop * aop1, asmop * aop2)
855 if (aop1->type == AOP_SFR ||
856 aop2->type == AOP_SFR)
862 if (aop1->type != AOP_REG ||
863 aop2->type != AOP_REG)
866 if (aop1->size != aop2->size)
869 for (i = 0; i < aop1->size; i++)
870 if (aop1->aopu.aop_reg[i] !=
871 aop2->aopu.aop_reg[i])
877 /*-----------------------------------------------------------------*/
878 /* aopOp - allocates an asmop for an operand : */
879 /*-----------------------------------------------------------------*/
881 aopOp (operand * op, iCode * ic, bool result, bool requires_a)
890 /* if this a literal */
891 if (IS_OP_LITERAL (op))
893 op->aop = aop = newAsmop (AOP_LIT);
894 aop->aopu.aop_lit = op->operand.valOperand;
895 aop->size = getSize (operandType (op));
899 /* if already has a asmop then continue */
905 /* if the underlying symbol has a aop */
906 if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
908 op->aop = OP_SYMBOL (op)->aop;
912 /* if this is a true symbol */
913 if (IS_TRUE_SYMOP (op))
915 op->aop = aopForSym (ic, OP_SYMBOL (op), result, requires_a);
919 /* this is a temporary : this has
925 e) can be a return use only */
927 sym = OP_SYMBOL (op);
929 /* if the type is a conditional */
930 if (sym->regType == REG_CND)
932 aop = op->aop = sym->aop = newAsmop (AOP_CRY);
937 /* if it is spilt then two situations
939 b) has a spill location */
940 if (sym->isspilt || sym->nRegs == 0)
942 /* rematerialize it NOW */
945 sym->aop = op->aop = aop =
947 aop->size = getSize (sym->type);
954 aop = op->aop = sym->aop = newAsmop (AOP_STR);
955 aop->size = getSize (sym->type);
956 for (i = 0; i < 4; i++)
957 aop->aopu.aop_str[i] = _fReturn[i];
963 if (sym->accuse == ACCUSE_A)
965 aop = op->aop = sym->aop = newAsmop (AOP_ACC);
966 aop->size = getSize (sym->type);
967 wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
969 aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
971 else if (sym->accuse == ACCUSE_SCRATCH)
973 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
974 aop->size = getSize (sym->type);
975 wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
976 aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
977 aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
979 else if (sym->accuse == ACCUSE_IY)
981 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
982 aop->size = getSize (sym->type);
983 wassertl(aop->size <= 2, "Internal error: Caching in IY, but too big to fit in IY");
984 aop->aopu.aop_str[0] = _pairs[PAIR_IY].l;
985 aop->aopu.aop_str[1] = _pairs[PAIR_IY].h;
989 wassertl (0, "Marked as being allocated into A or HL but is actually in neither");
994 /* else spill location */
995 if (sym->usl.spillLoc && getSize(sym->type) != getSize(sym->usl.spillLoc->type)) {
996 /* force a new aop if sizes differ */
997 sym->usl.spillLoc->aop = NULL;
999 sym->aop = op->aop = aop =
1000 aopForSym (ic, sym->usl.spillLoc, result, requires_a);
1001 wassertl (aop->size >= getSize (sym->type), "Operand doesn't fit in the spill location");
1002 aop->size = getSize (sym->type);
1006 /* must be in a register */
1007 sym->aop = op->aop = aop = newAsmop (AOP_REG);
1008 aop->size = sym->nRegs;
1009 for (i = 0; i < sym->nRegs; i++)
1010 aop->aopu.aop_reg[i] = sym->regs[i];
1013 /*-----------------------------------------------------------------*/
1014 /* freeAsmop - free up the asmop given to an operand */
1015 /*----------------------------------------------------------------*/
1017 freeAsmop (operand * op, asmop * aaop, iCode * ic)
1034 if (aop->type == AOP_PAIRPTR && IS_Z80 && aop->aopu.aop_pairId == PAIR_DE)
1036 _pop (aop->aopu.aop_pairId);
1039 if (getPairId (aop) == PAIR_HL)
1041 spillPair (PAIR_HL);
1045 /* all other cases just dealloc */
1051 OP_SYMBOL (op)->aop = NULL;
1052 /* if the symbol has a spill */
1054 SPIL_LOC (op)->aop = NULL;
1061 isLitWord (asmop * aop)
1063 /* if (aop->size != 2)
1076 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
1078 /* depending on type */
1084 /* PENDING: for re-target */
1087 tsprintf (buffer, sizeof(buffer),
1088 "!hashedstr + %d", aop->aopu.aop_immd, offset);
1090 else if (offset == 0)
1092 tsprintf (buffer, sizeof(buffer),
1093 "%s", aop->aopu.aop_immd);
1097 tsprintf (buffer, sizeof(buffer),
1098 "%s + %d", aop->aopu.aop_immd, offset);
1100 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1104 value *val = aop->aopu.aop_lit;
1105 /* if it is a float then it gets tricky */
1106 /* otherwise it is fairly simple */
1107 if (!IS_FLOAT (val->type))
1109 unsigned long v = (unsigned long) floatFromVal (val);
1115 else if (offset == 0)
1121 wassertl(0, "Encountered an invalid offset while fetching a literal");
1125 tsprintf (buffer, sizeof(buffer), "!immedword", v);
1127 tsprintf (buffer, sizeof(buffer), "!constword", v);
1129 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1140 /* it is type float */
1141 fl.f = (float) floatFromVal (val);
1143 #ifdef WORDS_BIGENDIAN
1144 i = fl.c[3-offset] | (fl.c[3-offset-1]<<8);
1146 i = fl.c[offset] | (fl.c[offset+1]<<8);
1149 tsprintf (buffer, sizeof(buffer), "!immedword", i);
1151 tsprintf (buffer, sizeof(buffer), "!constword", i);
1153 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1162 aopGetWord (asmop * aop, int offset)
1164 return aopGetLitWordLong (aop, offset, TRUE);
1168 isPtr (const char *s)
1170 if (!strcmp (s, "hl"))
1172 if (!strcmp (s, "ix"))
1174 if (!strcmp (s, "iy"))
1180 adjustPair (const char *pair, int *pold, int new)
1186 emit2 ("inc %s", pair);
1191 emit2 ("dec %s", pair);
1199 spillPair (PAIR_HL);
1200 spillPair (PAIR_IY);
1204 requiresHL (asmop * aop)
1220 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1222 const char *l, *base;
1223 const char *pair = _pairs[pairId].name;
1224 l = aopGetLitWordLong (left, offset, FALSE);
1225 base = aopGetLitWordLong (left, 0, FALSE);
1226 wassert (l && pair && base);
1230 if (pairId == PAIR_HL || pairId == PAIR_IY)
1232 if (_G.pairs[pairId].last_type == left->type)
1234 if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1236 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1238 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1241 if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
1248 _G.pairs[pairId].last_type = left->type;
1249 _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1250 _G.pairs[pairId].offset = offset;
1252 /* Both a lit on the right and a true symbol on the left */
1253 emit2 ("ld %s,!hashedstr", pair, l);
1257 makeFreePairId (iCode *ic, bool *pisUsed)
1263 if (!bitVectBitValue (ic->rMask, B_IDX) && !bitVectBitValue(ic->rMask, C_IDX))
1267 else if (IS_Z80 && !bitVectBitValue (ic->rMask, D_IDX) && !bitVectBitValue(ic->rMask, E_IDX))
1285 fetchPairLong (PAIR_ID pairId, asmop * aop, iCode *ic, int offset)
1287 /* if this is remateriazable */
1288 if (isLitWord (aop)) {
1289 fetchLitPair (pairId, aop, offset);
1293 if (getPairId (aop) == pairId)
1297 /* we need to get it byte by byte */
1298 else if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1299 aopGet (aop, offset, FALSE);
1300 switch (aop->size - offset) {
1302 emit2 ("ld l,!*hl");
1303 emit2 ("ld h,!immedbyte", 0);
1306 // PENDING: Requires that you are only fetching two bytes.
1309 emit2 ("ld h,!*hl");
1313 wassertl (0, "Attempted to fetch too much data into HL");
1317 else if (IS_Z80 && aop->type == AOP_IY) {
1318 /* Instead of fetching relative to IY, just grab directly
1319 from the address IY refers to */
1320 char *l = aopGetLitWordLong (aop, offset, FALSE);
1322 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1324 if (aop->size < 2) {
1325 emit2("ld %s,!zero", _pairs[pairId].h);
1328 else if (pairId == PAIR_IY)
1332 emit2 ("push %s", _pairs[getPairId(aop)].name);
1338 PAIR_ID id = makeFreePairId (ic, &isUsed);
1341 /* Can't load into parts, so load into HL then exchange. */
1342 emit2 ("ld %s,%s", _pairs[id].l, aopGet (aop, offset, FALSE));
1343 emit2 ("ld %s,%s", _pairs[id].h, aopGet (aop, offset + 1, FALSE));
1344 emit2 ("push %s", _pairs[id].name);
1352 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1353 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1355 /* PENDING: check? */
1356 if (pairId == PAIR_HL)
1357 spillPair (PAIR_HL);
1362 fetchPair (PAIR_ID pairId, asmop * aop)
1364 fetchPairLong (pairId, aop, NULL, 0);
1368 fetchHL (asmop * aop)
1370 fetchPair (PAIR_HL, aop);
1374 setupPairFromSP (PAIR_ID id, int offset)
1376 wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
1378 if (offset < INT8MIN || offset > INT8MAX)
1380 emit2 ("ld hl,!immedword", offset);
1381 emit2 ("add hl,sp");
1385 emit2 ("!ldahlsp", offset);
1390 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1395 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
1396 fetchLitPair (pairId, aop, 0);
1400 wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
1402 fetchLitPair (pairId, aop, offset);
1403 _G.pairs[pairId].offset = offset;
1407 wassertl (IS_Z80, "Only the Z80 has an extended stack");
1408 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
1411 int offset = aop->aopu.aop_stk + _G.stack.offset;
1413 if (_G.pairs[pairId].last_type == aop->type &&
1414 _G.pairs[pairId].offset == offset)
1420 /* PENDING: Do this better. */
1421 sprintf (buffer, "%d", offset + _G.stack.pushed);
1422 emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
1423 emit2 ("add %s,sp", _pairs[pairId].name);
1424 _G.pairs[pairId].last_type = aop->type;
1425 _G.pairs[pairId].offset = offset;
1432 /* Doesnt include _G.stack.pushed */
1433 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1435 if (aop->aopu.aop_stk > 0)
1437 abso += _G.stack.param_offset;
1439 assert (pairId == PAIR_HL);
1440 /* In some cases we can still inc or dec hl */
1441 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1443 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1447 setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
1449 _G.pairs[pairId].offset = abso;
1454 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
1460 _G.pairs[pairId].last_type = aop->type;
1466 emit2 ("!tlabeldef", key);
1470 /*-----------------------------------------------------------------*/
1471 /* aopGet - for fetching value of the aop */
1472 /*-----------------------------------------------------------------*/
1474 aopGet (asmop * aop, int offset, bool bit16)
1476 // char *s = buffer;
1478 /* offset is greater than size then zero */
1479 /* PENDING: this seems a bit screwed in some pointer cases. */
1480 if (offset > (aop->size - 1) &&
1481 aop->type != AOP_LIT)
1483 tsprintf (buffer, sizeof(buffer), "!zero");
1484 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1487 /* depending on type */
1491 /* PENDING: re-target */
1493 tsprintf (buffer, sizeof(buffer), "!immedwords", aop->aopu.aop_immd);
1498 tsprintf (buffer, sizeof(buffer), "!bankimmeds", aop->aopu.aop_immd);
1501 tsprintf (buffer, sizeof(buffer), "!msbimmeds", aop->aopu.aop_immd);
1504 tsprintf (buffer, sizeof(buffer), "!lsbimmeds", aop->aopu.aop_immd);
1507 wassertl (0, "Fetching from beyond the limits of an immediate value.");
1510 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1514 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1515 SNPRINTF (buffer, sizeof(buffer), "a");
1517 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1521 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1522 SNPRINTF (buffer, sizeof(buffer), "a");
1524 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1527 return aop->aopu.aop_reg[offset]->name;
1531 setupPair (PAIR_HL, aop, offset);
1532 tsprintf (buffer, sizeof(buffer), "!*hl");
1534 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
1538 setupPair (PAIR_IY, aop, offset);
1539 tsprintf (buffer, sizeof(buffer), "!*iyx", offset);
1541 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1545 setupPair (PAIR_IY, aop, offset);
1546 tsprintf (buffer, sizeof(buffer), "!*iyx", offset, offset);
1548 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1553 setupPair (PAIR_HL, aop, offset);
1554 tsprintf (buffer, sizeof(buffer), "!*hl");
1558 if (aop->aopu.aop_stk >= 0)
1559 offset += _G.stack.param_offset;
1560 tsprintf (buffer, sizeof(buffer),
1561 "!*ixx", aop->aopu.aop_stk + offset);
1564 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1567 wassertl (0, "Tried to fetch from a bit variable");
1576 tsprintf(buffer, sizeof(buffer), "!zero");
1577 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1581 wassert (offset < 2);
1582 return aop->aopu.aop_str[offset];
1585 return aopLiteral (aop->aopu.aop_lit, offset);
1589 unsigned long v = aop->aopu.aop_simplelit;
1592 tsprintf (buffer, sizeof(buffer),
1593 "!immedbyte", (unsigned int) v & 0xff);
1595 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1599 return aop->aopu.aop_str[offset];
1602 setupPair (aop->aopu.aop_pairId, aop, offset);
1603 SNPRINTF (buffer, sizeof(buffer),
1604 "(%s)", _pairs[aop->aopu.aop_pairId].name);
1606 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1611 wassertl (0, "aopget got unsupported aop->type");
1616 isRegString (const char *s)
1618 if (!strcmp (s, "b") ||
1630 isConstant (const char *s)
1632 /* This is a bit of a hack... */
1633 return (*s == '#' || *s == '$');
1637 canAssignToPtr (const char *s)
1639 if (isRegString (s))
1646 /*-----------------------------------------------------------------*/
1647 /* aopPut - puts a string for a aop */
1648 /*-----------------------------------------------------------------*/
1650 aopPut (asmop * aop, const char *s, int offset)
1654 if (aop->size && offset > (aop->size - 1))
1656 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1657 "aopPut got offset > aop->size");
1662 tsprintf(buffer2, sizeof(buffer2), s);
1665 /* will assign value to value */
1666 /* depending on where it is ofcourse */
1672 if (strcmp (s, "a"))
1673 emit2 ("ld a,%s", s);
1674 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1679 if (strcmp (s, "a"))
1680 emit2 ("ld a,%s", s);
1681 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1685 if (!strcmp (s, "!*hl"))
1686 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1689 aop->aopu.aop_reg[offset]->name, s);
1694 if (!canAssignToPtr (s))
1696 emit2 ("ld a,%s", s);
1697 setupPair (PAIR_IY, aop, offset);
1698 emit2 ("ld !*iyx,a", offset);
1702 setupPair (PAIR_IY, aop, offset);
1703 emit2 ("ld !*iyx,%s", offset, s);
1709 /* PENDING: for re-target */
1710 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1712 emit2 ("ld a,!*hl");
1715 setupPair (PAIR_HL, aop, offset);
1717 emit2 ("ld !*hl,%s", s);
1722 if (!canAssignToPtr (s))
1724 emit2 ("ld a,%s", s);
1725 setupPair (PAIR_IY, aop, offset);
1726 emit2 ("ld !*iyx,a", offset);
1730 setupPair (PAIR_IY, aop, offset);
1731 emit2 ("ld !*iyx,%s", offset, s);
1738 /* PENDING: re-target */
1739 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1741 emit2 ("ld a,!*hl");
1744 setupPair (PAIR_HL, aop, offset);
1745 if (!canAssignToPtr (s))
1747 emit2 ("ld a,%s", s);
1748 emit2 ("ld !*hl,a");
1751 emit2 ("ld !*hl,%s", s);
1755 if (aop->aopu.aop_stk >= 0)
1756 offset += _G.stack.param_offset;
1757 if (!canAssignToPtr (s))
1759 emit2 ("ld a,%s", s);
1760 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
1764 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
1770 /* if bit variable */
1771 if (!aop->aopu.aop_dir)
1773 emit2 ("ld a,!zero");
1778 /* In bit space but not in C - cant happen */
1779 wassertl (0, "Tried to write into a bit variable");
1785 if (strcmp (aop->aopu.aop_str[offset], s))
1787 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1793 if (!offset && (strcmp (s, "acc") == 0))
1797 wassertl (0, "Tried to access past the end of A");
1801 if (strcmp (aop->aopu.aop_str[offset], s))
1802 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1807 wassert (offset < 2);
1808 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1812 setupPair (aop->aopu.aop_pairId, aop, offset);
1813 emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
1817 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1818 "aopPut got unsupported aop->type");
1823 #define AOP(op) op->aop
1824 #define AOP_TYPE(op) AOP(op)->type
1825 #define AOP_SIZE(op) AOP(op)->size
1826 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
1829 commitPair (asmop * aop, PAIR_ID id)
1831 /* PENDING: Verify this. */
1832 if (id == PAIR_HL && requiresHL (aop) && IS_GB)
1836 aopPut (aop, "a", 0);
1837 aopPut (aop, "d", 1);
1842 if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
1844 char *l = aopGetLitWordLong (aop, 0, FALSE);
1847 emit2 ("ld (%s),%s", l, _pairs[id].name);
1851 aopPut (aop, _pairs[id].l, 0);
1852 aopPut (aop, _pairs[id].h, 1);
1857 /*-----------------------------------------------------------------*/
1858 /* getDataSize - get the operand data size */
1859 /*-----------------------------------------------------------------*/
1861 getDataSize (operand * op)
1864 size = AOP_SIZE (op);
1868 wassertl (0, "Somehow got a three byte data pointer");
1873 /*-----------------------------------------------------------------*/
1874 /* movLeft2Result - move byte from left to result */
1875 /*-----------------------------------------------------------------*/
1877 movLeft2Result (operand * left, int offl,
1878 operand * result, int offr, int sign)
1882 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
1884 l = aopGet (AOP (left), offl, FALSE);
1888 aopPut (AOP (result), l, offr);
1892 if (getDataSize (left) == offl + 1)
1894 emit2 ("ld a,%s", l);
1895 aopPut (AOP (result), "a", offr);
1902 movLeft2ResultLong (operand * left, int offl,
1903 operand * result, int offr, int sign,
1908 movLeft2Result (left, offl, result, offr, sign);
1912 wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
1913 wassertl (size == 2, "Only implemented for two bytes or one");
1915 if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
1917 emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
1918 emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
1920 spillPair (PAIR_HL);
1922 else if ( getPairId ( AOP (result)) == PAIR_IY)
1924 PAIR_ID id = getPairId (AOP (left));
1925 if (id != PAIR_INVALID)
1927 emit2("push %s", _pairs[id].name);
1938 movLeft2Result (left, offl, result, offr, sign);
1939 movLeft2Result (left, offl+1, result, offr+1, sign);
1944 /** Put Acc into a register set
1947 outAcc (operand * result)
1950 size = getDataSize (result);
1953 aopPut (AOP (result), "a", 0);
1956 /* unsigned or positive */
1959 aopPut (AOP (result), "!zero", offset++);
1964 /** Take the value in carry and put it into a register
1967 outBitCLong (operand * result, bool swap_sense)
1969 /* if the result is bit */
1970 if (AOP_TYPE (result) == AOP_CRY)
1972 wassertl (0, "Tried to write carry to a bit");
1976 emit2 ("ld a,!zero");
1979 emit2 ("xor a,!immedbyte", 1);
1985 outBitC (operand * result)
1987 outBitCLong (result, FALSE);
1990 /*-----------------------------------------------------------------*/
1991 /* toBoolean - emit code for orl a,operator(sizeop) */
1992 /*-----------------------------------------------------------------*/
1994 _toBoolean (operand * oper)
1996 int size = AOP_SIZE (oper);
2000 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
2003 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
2007 if (AOP (oper)->type != AOP_ACC)
2010 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
2015 /*-----------------------------------------------------------------*/
2016 /* genNotFloat - generates not for float operations */
2017 /*-----------------------------------------------------------------*/
2019 genNotFloat (operand * op, operand * res)
2024 emitDebug ("; genNotFloat");
2026 /* we will put 127 in the first byte of
2028 aopPut (AOP (res), "!immedbyte", 0x7F);
2029 size = AOP_SIZE (op) - 1;
2032 _moveA (aopGet (op->aop, offset++, FALSE));
2036 emit2 ("or a,%s", aopGet (op->aop, offset++, FALSE));
2039 tlbl = newiTempLabel (NULL);
2040 aopPut (res->aop, "!one", 1);
2041 emit2 ("!shortjp z !tlabel", tlbl->key + 100);
2042 aopPut (res->aop, "!zero", 1);
2044 emitLabel(tlbl->key + 100);
2046 size = res->aop->size - 2;
2048 /* put zeros in the rest */
2050 aopPut (res->aop, "!zero", offset++);
2053 /*-----------------------------------------------------------------*/
2054 /* genNot - generate code for ! operation */
2055 /*-----------------------------------------------------------------*/
2059 sym_link *optype = operandType (IC_LEFT (ic));
2061 /* assign asmOps to operand & result */
2062 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
2063 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2065 /* if in bit space then a special case */
2066 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2068 wassertl (0, "Tried to negate a bit");
2071 /* if type float then do float */
2072 if (IS_FLOAT (optype))
2074 genNotFloat (IC_LEFT (ic), IC_RESULT (ic));
2078 _toBoolean (IC_LEFT (ic));
2083 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
2084 emit2 ("sub a,!one");
2085 outBitC (IC_RESULT (ic));
2088 /* release the aops */
2089 freeAsmop (IC_LEFT (ic), NULL, ic);
2090 freeAsmop (IC_RESULT (ic), NULL, ic);
2093 /*-----------------------------------------------------------------*/
2094 /* genCpl - generate code for complement */
2095 /*-----------------------------------------------------------------*/
2103 /* assign asmOps to operand & result */
2104 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2105 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2107 /* if both are in bit space then
2109 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2110 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2112 wassertl (0, "Left and the result are in bit space");
2115 size = AOP_SIZE (IC_RESULT (ic));
2118 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2121 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2124 /* release the aops */
2125 freeAsmop (IC_LEFT (ic), NULL, ic);
2126 freeAsmop (IC_RESULT (ic), NULL, ic);
2130 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
2137 store de into result
2142 store de into result
2144 const char *first = isAdd ? "add" : "sub";
2145 const char *later = isAdd ? "adc" : "sbc";
2147 wassertl (IS_GB, "Code is only relevent to the gbz80");
2148 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
2150 fetchPair (PAIR_DE, left);
2153 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
2156 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2159 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2160 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2162 fetchPairLong (PAIR_DE, left, NULL, MSB24);
2163 aopGet (right, MSB24, FALSE);
2167 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2170 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2172 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2173 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2177 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2179 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2182 /*-----------------------------------------------------------------*/
2183 /* genUminusFloat - unary minus for floating points */
2184 /*-----------------------------------------------------------------*/
2186 genUminusFloat (operand * op, operand * result)
2188 int size, offset = 0;
2190 emitDebug("; genUminusFloat");
2192 /* for this we just need to flip the
2193 first it then copy the rest in place */
2194 size = AOP_SIZE (op) - 1;
2196 _moveA(aopGet (AOP (op), MSB32, FALSE));
2198 emit2("xor a,!immedbyte", 0x80);
2199 aopPut (AOP (result), "a", MSB32);
2203 aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2208 /*-----------------------------------------------------------------*/
2209 /* genUminus - unary minus code generation */
2210 /*-----------------------------------------------------------------*/
2212 genUminus (iCode * ic)
2215 sym_link *optype, *rtype;
2218 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2219 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2221 /* if both in bit space then special
2223 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2224 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2226 wassertl (0, "Left and right are in bit space");
2230 optype = operandType (IC_LEFT (ic));
2231 rtype = operandType (IC_RESULT (ic));
2233 /* if float then do float stuff */
2234 if (IS_FLOAT (optype))
2236 genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2240 /* otherwise subtract from zero */
2241 size = AOP_SIZE (IC_LEFT (ic));
2243 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2245 /* Create a new asmop with value zero */
2246 asmop *azero = newAsmop (AOP_SIMPLELIT);
2247 azero->aopu.aop_simplelit = 0;
2249 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2257 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2258 emit2 ("ld a,!zero");
2259 emit2 ("sbc a,%s", l);
2260 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2263 /* if any remaining bytes in the result */
2264 /* we just need to propagate the sign */
2265 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2270 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2274 /* release the aops */
2275 freeAsmop (IC_LEFT (ic), NULL, ic);
2276 freeAsmop (IC_RESULT (ic), NULL, ic);
2279 /*-----------------------------------------------------------------*/
2280 /* assignResultValue - */
2281 /*-----------------------------------------------------------------*/
2283 assignResultValue (operand * oper)
2285 int size = AOP_SIZE (oper);
2288 wassertl (size <= 4, "Got a result that is bigger than four bytes");
2289 topInA = requiresHL (AOP (oper));
2291 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2293 /* We do it the hard way here. */
2295 aopPut (AOP (oper), _fReturn[0], 0);
2296 aopPut (AOP (oper), _fReturn[1], 1);
2298 aopPut (AOP (oper), _fReturn[0], 2);
2299 aopPut (AOP (oper), _fReturn[1], 3);
2305 aopPut (AOP (oper), _fReturn[size], size);
2310 /** Simple restore that doesn't take into account what is used in the
2314 _restoreRegsAfterCall(void)
2316 if (_G.stack.pushedDE)
2319 _G.stack.pushedDE = FALSE;
2321 if (_G.stack.pushedBC)
2324 _G.stack.pushedBC = FALSE;
2326 _G.saves.saved = FALSE;
2330 _saveRegsForCall(iCode *ic, int sendSetSize)
2333 o Stack parameters are pushed before this function enters
2334 o DE and BC may be used in this function.
2335 o HL and DE may be used to return the result.
2336 o HL and DE may be used to send variables.
2337 o DE and BC may be used to store the result value.
2338 o HL may be used in computing the sent value of DE
2339 o The iPushes for other parameters occur before any addSets
2341 Logic: (to be run inside the first iPush or if none, before sending)
2342 o Compute if DE and/or BC are in use over the call
2343 o Compute if DE is used in the send set
2344 o Compute if DE and/or BC are used to hold the result value
2345 o If (DE is used, or in the send set) and is not used in the result, push.
2346 o If BC is used and is not in the result, push
2348 o If DE is used in the send set, fetch
2349 o If HL is used in the send set, fetch
2353 if (_G.saves.saved == FALSE) {
2354 bool deInUse, bcInUse;
2356 bool bcInRet = FALSE, deInRet = FALSE;
2359 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
2361 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2362 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2364 deSending = (sendSetSize > 1);
2366 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2368 if (bcInUse && bcInRet == FALSE) {
2370 _G.stack.pushedBC = TRUE;
2372 if (deInUse && deInRet == FALSE) {
2374 _G.stack.pushedDE = TRUE;
2377 _G.saves.saved = TRUE;
2380 /* Already saved. */
2384 /*-----------------------------------------------------------------*/
2385 /* genIpush - genrate code for pushing this gets a little complex */
2386 /*-----------------------------------------------------------------*/
2388 genIpush (iCode * ic)
2390 int size, offset = 0;
2393 /* if this is not a parm push : ie. it is spill push
2394 and spill push is always done on the local stack */
2397 wassertl(0, "Encountered an unsupported spill push.");
2401 if (_G.saves.saved == FALSE) {
2402 /* Caller saves, and this is the first iPush. */
2403 /* Scan ahead until we find the function that we are pushing parameters to.
2404 Count the number of addSets on the way to figure out what registers
2405 are used in the send set.
2408 iCode *walk = ic->next;
2411 if (walk->op == SEND) {
2414 else if (walk->op == CALL || walk->op == PCALL) {
2423 _saveRegsForCall(walk, nAddSets);
2426 /* Already saved by another iPush. */
2429 /* then do the push */
2430 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2432 size = AOP_SIZE (IC_LEFT (ic));
2434 if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2436 _G.stack.pushed += 2;
2437 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2443 fetchHL (AOP (IC_LEFT (ic)));
2445 spillPair (PAIR_HL);
2446 _G.stack.pushed += 2;
2451 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
2453 spillPair (PAIR_HL);
2454 _G.stack.pushed += 2;
2455 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
2457 spillPair (PAIR_HL);
2458 _G.stack.pushed += 2;
2464 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2466 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2468 emit2 ("ld a,(%s)", l);
2472 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2473 emit2 ("ld a,%s", l);
2481 freeAsmop (IC_LEFT (ic), NULL, ic);
2484 /*-----------------------------------------------------------------*/
2485 /* genIpop - recover the registers: can happen only for spilling */
2486 /*-----------------------------------------------------------------*/
2488 genIpop (iCode * ic)
2493 /* if the temp was not pushed then */
2494 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2497 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2498 size = AOP_SIZE (IC_LEFT (ic));
2499 offset = (size - 1);
2500 if (isPair (AOP (IC_LEFT (ic))))
2502 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2510 spillPair (PAIR_HL);
2511 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2515 freeAsmop (IC_LEFT (ic), NULL, ic);
2518 /* This is quite unfortunate */
2520 setArea (int inHome)
2523 static int lastArea = 0;
2525 if (_G.in_home != inHome) {
2527 const char *sz = port->mem.code_name;
2528 port->mem.code_name = "HOME";
2529 emit2("!area", CODE_NAME);
2530 port->mem.code_name = sz;
2533 emit2("!area", CODE_NAME); */
2534 _G.in_home = inHome;
2545 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2549 symbol *sym = OP_SYMBOL (op);
2551 if (sym->isspilt || sym->nRegs == 0)
2554 aopOp (op, ic, FALSE, FALSE);
2557 if (aop->type == AOP_REG)
2560 for (i = 0; i < aop->size; i++)
2562 if (pairId == PAIR_DE)
2564 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2565 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2567 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2570 else if (pairId == PAIR_BC)
2572 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2573 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2575 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2585 freeAsmop (IC_LEFT (ic), NULL, ic);
2589 /** Emit the code for a call statement
2592 emitCall (iCode * ic, bool ispcall)
2594 sym_link *dtype = operandType (IC_LEFT (ic));
2596 /* if caller saves & we have not saved then */
2602 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2604 /* if send set is not empty then assign */
2609 int nSend = elementsInSet(_G.sendSet);
2610 bool swapped = FALSE;
2612 int _z80_sendOrder[] = {
2617 /* Check if the parameters are swapped. If so route through hl instead. */
2618 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2620 sic = setFirstItem(_G.sendSet);
2621 sic = setNextItem(_G.sendSet);
2623 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2624 /* The second send value is loaded from one the one that holds the first
2625 send, i.e. it is overwritten. */
2626 /* Cache the first in HL, and load the second from HL instead. */
2627 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2628 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2634 for (sic = setFirstItem (_G.sendSet); sic;
2635 sic = setNextItem (_G.sendSet))
2638 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2640 size = AOP_SIZE (IC_LEFT (sic));
2641 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2642 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2644 // PENDING: Mild hack
2645 if (swapped == TRUE && send == 1) {
2647 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2650 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2652 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2655 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2659 freeAsmop (IC_LEFT (sic), NULL, sic);
2666 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2668 werror (W_INDIR_BANKED);
2670 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2672 if (isLitWord (AOP (IC_LEFT (ic))))
2674 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2678 symbol *rlbl = newiTempLabel (NULL);
2679 spillPair (PAIR_HL);
2680 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2682 _G.stack.pushed += 2;
2684 fetchHL (AOP (IC_LEFT (ic)));
2686 emit2 ("!tlabeldef", (rlbl->key + 100));
2687 _G.stack.pushed -= 2;
2689 freeAsmop (IC_LEFT (ic), NULL, ic);
2693 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2694 OP_SYMBOL (IC_LEFT (ic))->rname :
2695 OP_SYMBOL (IC_LEFT (ic))->name;
2696 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2698 emit2 ("call banked_call");
2699 emit2 ("!dws", name);
2700 emit2 ("!dw !bankimmeds", name);
2705 emit2 ("call %s", name);
2710 /* Mark the regsiters as restored. */
2711 _G.saves.saved = FALSE;
2713 /* if we need assign a result value */
2714 if ((IS_ITEMP (IC_RESULT (ic)) &&
2715 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2716 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2717 IS_TRUE_SYMOP (IC_RESULT (ic)))
2720 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2722 assignResultValue (IC_RESULT (ic));
2724 freeAsmop (IC_RESULT (ic), NULL, ic);
2727 /* adjust the stack for parameters if required */
2730 int i = ic->parmBytes;
2732 _G.stack.pushed -= i;
2735 emit2 ("!ldaspsp", i);
2742 emit2 ("ld iy,!immedword", i);
2743 emit2 ("add iy,sp");
2763 if (_G.stack.pushedDE)
2765 bool dInRet = bitVectBitValue(ic->rUsed, D_IDX);
2766 bool eInRet = bitVectBitValue(ic->rUsed, E_IDX);
2768 if (dInRet && eInRet)
2770 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
2774 /* Only restore E */
2781 /* Only restore D */
2789 _G.stack.pushedDE = FALSE;
2792 if (_G.stack.pushedBC)
2794 bool bInRet = bitVectBitValue(ic->rUsed, B_IDX);
2795 bool cInRet = bitVectBitValue(ic->rUsed, C_IDX);
2797 if (bInRet && cInRet)
2799 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
2803 /* Only restore C */
2810 /* Only restore B */
2818 _G.stack.pushedBC = FALSE;
2822 /*-----------------------------------------------------------------*/
2823 /* genCall - generates a call statement */
2824 /*-----------------------------------------------------------------*/
2826 genCall (iCode * ic)
2828 emitCall (ic, FALSE);
2831 /*-----------------------------------------------------------------*/
2832 /* genPcall - generates a call by pointer statement */
2833 /*-----------------------------------------------------------------*/
2835 genPcall (iCode * ic)
2837 emitCall (ic, TRUE);
2840 /*-----------------------------------------------------------------*/
2841 /* resultRemat - result is rematerializable */
2842 /*-----------------------------------------------------------------*/
2844 resultRemat (iCode * ic)
2846 if (SKIP_IC (ic) || ic->op == IFX)
2849 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2851 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2852 if (sym->remat && !POINTER_SET (ic))
2859 extern set *publics;
2861 /*-----------------------------------------------------------------*/
2862 /* genFunction - generated code for function entry */
2863 /*-----------------------------------------------------------------*/
2865 genFunction (iCode * ic)
2867 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2870 bool bcInUse = FALSE;
2871 bool deInUse = FALSE;
2873 setArea (IFFUNC_NONBANKED (sym->type));
2875 /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
2878 _G.receiveOffset = 0;
2880 /* Record the last function name for debugging. */
2881 _G.lastFunctionName = sym->rname;
2883 /* Create the function header */
2884 emit2 ("!functionheader", sym->name);
2885 sprintf (buffer, "%s_start", sym->rname);
2886 emit2 ("!labeldef", buffer);
2887 emit2 ("!functionlabeldef", sym->rname);
2889 if (options.profile)
2891 emit2 ("!profileenter");
2894 ftype = operandType (IC_LEFT (ic));
2896 /* if critical function then turn interrupts off */
2897 if (IFFUNC_ISCRITICAL (ftype))
2900 /* if this is an interrupt service routine then save all potentially used registers. */
2901 if (IFFUNC_ISISR (sym->type))
2906 /* PENDING: callee-save etc */
2908 _G.stack.param_offset = 0;
2910 if (z80_opts.calleeSavesBC)
2915 /* Detect which registers are used. */
2916 if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
2919 for (i = 0; i < sym->regsUsed->size; i++)
2921 if (bitVectBitValue (sym->regsUsed, i))
2935 /* Other systems use DE as a temporary. */
2946 _G.stack.param_offset += 2;
2949 _G.calleeSaves.pushedBC = bcInUse;
2954 _G.stack.param_offset += 2;
2957 _G.calleeSaves.pushedDE = deInUse;
2959 /* adjust the stack for the function */
2960 _G.stack.last = sym->stack;
2962 if (sym->stack && IS_GB && sym->stack > -INT8MIN)
2963 emit2 ("!enterxl", sym->stack);
2964 else if (sym->stack)
2965 emit2 ("!enterx", sym->stack);
2968 _G.stack.offset = sym->stack;
2971 /*-----------------------------------------------------------------*/
2972 /* genEndFunction - generates epilogue for functions */
2973 /*-----------------------------------------------------------------*/
2975 genEndFunction (iCode * ic)
2977 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2979 if (IFFUNC_ISISR (sym->type))
2981 wassertl (0, "Tried to close an interrupt support function");
2985 if (IFFUNC_ISCRITICAL (sym->type))
2988 /* PENDING: calleeSave */
2990 if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
2992 emit2 ("!leavexl", _G.stack.offset);
2994 else if (_G.stack.offset)
2996 emit2 ("!leavex", _G.stack.offset);
3003 if (_G.calleeSaves.pushedDE)
3006 _G.calleeSaves.pushedDE = FALSE;
3009 if (_G.calleeSaves.pushedBC)
3012 _G.calleeSaves.pushedBC = FALSE;
3015 if (options.profile)
3017 emit2 ("!profileexit");
3021 /* Both baned and non-banked just ret */
3024 sprintf (buffer, "%s_end", sym->rname);
3025 emit2 ("!labeldef", buffer);
3027 _G.flushStatics = 1;
3028 _G.stack.pushed = 0;
3029 _G.stack.offset = 0;
3032 /*-----------------------------------------------------------------*/
3033 /* genRet - generate code for return statement */
3034 /*-----------------------------------------------------------------*/
3039 /* Errk. This is a hack until I can figure out how
3040 to cause dehl to spill on a call */
3041 int size, offset = 0;
3043 /* if we have no return value then
3044 just generate the "ret" */
3048 /* we have something to return then
3049 move the return value into place */
3050 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3051 size = AOP_SIZE (IC_LEFT (ic));
3053 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3057 emit2 ("ld de,%s", l);
3061 emit2 ("ld hl,%s", l);
3066 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3068 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3069 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3075 l = aopGet (AOP (IC_LEFT (ic)), offset,
3077 if (strcmp (_fReturn[offset], l))
3078 emit2 ("ld %s,%s", _fReturn[offset++], l);
3082 freeAsmop (IC_LEFT (ic), NULL, ic);
3085 /* generate a jump to the return label
3086 if the next is not the return statement */
3087 if (!(ic->next && ic->next->op == LABEL &&
3088 IC_LABEL (ic->next) == returnLabel))
3090 emit2 ("jp !tlabel", returnLabel->key + 100);
3093 /*-----------------------------------------------------------------*/
3094 /* genLabel - generates a label */
3095 /*-----------------------------------------------------------------*/
3097 genLabel (iCode * ic)
3099 /* special case never generate */
3100 if (IC_LABEL (ic) == entryLabel)
3103 emitLabel (IC_LABEL (ic)->key + 100);
3106 /*-----------------------------------------------------------------*/
3107 /* genGoto - generates a ljmp */
3108 /*-----------------------------------------------------------------*/
3110 genGoto (iCode * ic)
3112 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3115 /*-----------------------------------------------------------------*/
3116 /* genPlusIncr :- does addition with increment if possible */
3117 /*-----------------------------------------------------------------*/
3119 genPlusIncr (iCode * ic)
3121 unsigned int icount;
3122 unsigned int size = getDataSize (IC_RESULT (ic));
3123 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3125 /* will try to generate an increment */
3126 /* if the right side is not a literal
3128 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3131 emitDebug ("; genPlusIncr");
3133 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3135 /* If result is a pair */
3136 if (resultId != PAIR_INVALID)
3138 if (isLitWord (AOP (IC_LEFT (ic))))
3140 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3143 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3145 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3147 PAIR_ID freep = getFreePairId (ic);
3148 if (freep != PAIR_INVALID)
3150 fetchPair (freep, AOP (IC_RIGHT (ic)));
3151 emit2 ("add hl,%s", _pairs[freep].name);
3157 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3158 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3165 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3169 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3173 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3178 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3180 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3181 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3185 /* if the literal value of the right hand side
3186 is greater than 4 then it is not worth it */
3190 /* if increment 16 bits in register */
3191 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3197 symbol *tlbl = NULL;
3198 tlbl = newiTempLabel (NULL);
3201 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3204 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3207 emitLabel (tlbl->key + 100);
3211 /* if the sizes are greater than 1 then we cannot */
3212 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3213 AOP_SIZE (IC_LEFT (ic)) > 1)
3216 /* If the result is in a register then we can load then increment.
3218 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3220 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3223 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3228 /* we can if the aops of the left & result match or
3229 if they are in registers and the registers are the
3231 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3235 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3243 /*-----------------------------------------------------------------*/
3244 /* outBitAcc - output a bit in acc */
3245 /*-----------------------------------------------------------------*/
3247 outBitAcc (operand * result)
3249 symbol *tlbl = newiTempLabel (NULL);
3250 /* if the result is a bit */
3251 if (AOP_TYPE (result) == AOP_CRY)
3253 wassertl (0, "Tried to write A into a bit");
3257 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3258 emit2 ("ld a,!one");
3259 emitLabel (tlbl->key + 100);
3265 couldDestroyCarry (asmop *aop)
3269 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3278 shiftIntoPair (int idx, asmop *aop)
3280 PAIR_ID id = PAIR_INVALID;
3282 wassertl (IS_Z80, "Only implemented for the Z80");
3283 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3295 wassertl (0, "Internal error - hit default case");
3298 emitDebug ("; Shift into pair idx %u", idx);
3302 setupPair (PAIR_HL, aop, 0);
3306 setupPair (PAIR_IY, aop, 0);
3308 emit2 ("pop %s", _pairs[id].name);
3311 aop->type = AOP_PAIRPTR;
3312 aop->aopu.aop_pairId = id;
3313 _G.pairs[id].offset = 0;
3314 _G.pairs[id].last_type = aop->type;
3318 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
3320 wassert (left && right);
3324 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3326 shiftIntoPair (0, right);
3327 shiftIntoPair (1, result);
3329 else if (couldDestroyCarry (right))
3331 shiftIntoPair (0, right);
3333 else if (couldDestroyCarry (result))
3335 shiftIntoPair (0, result);
3344 /*-----------------------------------------------------------------*/
3345 /* genPlus - generates code for addition */
3346 /*-----------------------------------------------------------------*/
3348 genPlus (iCode * ic)
3350 int size, offset = 0;
3352 /* special cases :- */
3354 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3355 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3356 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3358 /* Swap the left and right operands if:
3360 if literal, literal on the right or
3361 if left requires ACC or right is already
3364 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3365 (AOP_NEEDSACC (IC_LEFT (ic))) ||
3366 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3368 operand *t = IC_RIGHT (ic);
3369 IC_RIGHT (ic) = IC_LEFT (ic);
3373 /* if both left & right are in bit
3375 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3376 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3379 wassertl (0, "Tried to add two bits");
3382 /* if left in bit space & right literal */
3383 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3384 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3386 /* Can happen I guess */
3387 wassertl (0, "Tried to add a bit to a literal");
3390 /* if I can do an increment instead
3391 of add then GOOD for ME */
3392 if (genPlusIncr (ic) == TRUE)
3395 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3397 size = getDataSize (IC_RESULT (ic));
3399 /* Special case when left and right are constant */
3400 if (isPair (AOP (IC_RESULT (ic))))
3403 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3404 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3406 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3412 sprintf (buffer, "#(%s + %s)", left, right);
3413 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3418 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3420 /* Fetch into HL then do the add */
3421 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3422 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3424 spillPair (PAIR_HL);
3426 if (left == PAIR_HL && right != PAIR_INVALID)
3428 emit2 ("add hl,%s", _pairs[right].name);
3431 else if (right == PAIR_HL && left != PAIR_INVALID)
3433 emit2 ("add hl,%s", _pairs[left].name);
3436 else if (right != PAIR_INVALID && right != PAIR_HL)
3438 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3439 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3442 else if (left != PAIR_INVALID && left != PAIR_HL)
3444 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3445 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3454 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3456 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3457 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3459 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3464 ld hl,sp+n trashes C so we cant afford to do it during an
3465 add with stack based varibles. Worst case is:
3478 So you cant afford to load up hl if either left, right, or result
3479 is on the stack (*sigh*) The alt is:
3487 Combinations in here are:
3488 * If left or right are in bc then the loss is small - trap later
3489 * If the result is in bc then the loss is also small
3493 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3494 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3495 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3497 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3498 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3499 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3500 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3502 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3504 /* Swap left and right */
3505 operand *t = IC_RIGHT (ic);
3506 IC_RIGHT (ic) = IC_LEFT (ic);
3509 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3511 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3512 emit2 ("add hl,bc");
3516 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3517 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3518 emit2 ("add hl,de");
3520 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3526 /* Be paranoid on the GB with 4 byte variables due to how C
3527 can be trashed by lda hl,n(sp).
3529 _gbz80_emitAddSubLong (ic, TRUE);
3534 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3538 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3540 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3543 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3546 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3550 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3553 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3556 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3558 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3562 freeAsmop (IC_LEFT (ic), NULL, ic);
3563 freeAsmop (IC_RIGHT (ic), NULL, ic);
3564 freeAsmop (IC_RESULT (ic), NULL, ic);
3568 /*-----------------------------------------------------------------*/
3569 /* genMinusDec :- does subtraction with deccrement if possible */
3570 /*-----------------------------------------------------------------*/
3572 genMinusDec (iCode * ic)
3574 unsigned int icount;
3575 unsigned int size = getDataSize (IC_RESULT (ic));
3577 /* will try to generate an increment */
3578 /* if the right side is not a literal we cannot */
3579 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3582 /* if the literal value of the right hand side
3583 is greater than 4 then it is not worth it */
3584 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3587 size = getDataSize (IC_RESULT (ic));
3589 /* if decrement 16 bits in register */
3590 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3591 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3594 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3598 /* If result is a pair */
3599 if (isPair (AOP (IC_RESULT (ic))))
3601 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3603 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3607 /* if increment 16 bits in register */
3608 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3612 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3615 emit2 ("dec %s", _getTempPairName());
3618 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3624 /* if the sizes are greater than 1 then we cannot */
3625 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3626 AOP_SIZE (IC_LEFT (ic)) > 1)
3629 /* we can if the aops of the left & result match or if they are in
3630 registers and the registers are the same */
3631 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3634 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3641 /*-----------------------------------------------------------------*/
3642 /* genMinus - generates code for subtraction */
3643 /*-----------------------------------------------------------------*/
3645 genMinus (iCode * ic)
3647 int size, offset = 0;
3648 unsigned long lit = 0L;
3650 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3651 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3652 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3654 /* special cases :- */
3655 /* if both left & right are in bit space */
3656 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3657 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3659 wassertl (0, "Tried to subtract two bits");
3663 /* if I can do an decrement instead of subtract then GOOD for ME */
3664 if (genMinusDec (ic) == TRUE)
3667 size = getDataSize (IC_RESULT (ic));
3669 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3674 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3678 /* Same logic as genPlus */
3681 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3682 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3683 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3685 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3686 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3687 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3688 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3690 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3691 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3693 if (left == PAIR_INVALID && right == PAIR_INVALID)
3698 else if (right == PAIR_INVALID)
3700 else if (left == PAIR_INVALID)
3703 fetchPair (left, AOP (IC_LEFT (ic)));
3704 /* Order is important. Right may be HL */
3705 fetchPair (right, AOP (IC_RIGHT (ic)));
3707 emit2 ("ld a,%s", _pairs[left].l);
3708 emit2 ("sub a,%s", _pairs[right].l);
3710 emit2 ("ld a,%s", _pairs[left].h);
3711 emit2 ("sbc a,%s", _pairs[right].h);
3713 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
3715 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3717 aopPut (AOP (IC_RESULT (ic)), "e", 0);
3723 /* Be paranoid on the GB with 4 byte variables due to how C
3724 can be trashed by lda hl,n(sp).
3726 _gbz80_emitAddSubLong (ic, FALSE);
3731 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3733 /* if literal, add a,#-lit, else normal subb */
3736 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3737 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3741 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3744 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3748 /* first add without previous c */
3750 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
3752 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3754 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3757 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3758 AOP_SIZE (IC_LEFT (ic)) == 3 &&
3759 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3761 wassertl (0, "Tried to subtract on a long pointer");
3765 freeAsmop (IC_LEFT (ic), NULL, ic);
3766 freeAsmop (IC_RIGHT (ic), NULL, ic);
3767 freeAsmop (IC_RESULT (ic), NULL, ic);
3770 /*-----------------------------------------------------------------*/
3771 /* genMult - generates code for multiplication */
3772 /*-----------------------------------------------------------------*/
3774 genMult (iCode * ic)
3778 /* If true then the final operation should be a subtract */
3779 bool active = FALSE;
3781 /* Shouldn't occur - all done through function calls */
3782 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3783 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3784 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3786 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
3787 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
3788 AOP_SIZE (IC_RESULT (ic)) > 2)
3790 wassertl (0, "Multiplication is handled through support function calls");
3793 /* Swap left and right such that right is a literal */
3794 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
3796 operand *t = IC_RIGHT (ic);
3797 IC_RIGHT (ic) = IC_LEFT (ic);
3801 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
3803 val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
3804 // wassertl (val > 0, "Multiply must be positive");
3805 wassertl (val != 1, "Can't multiply by 1");
3807 if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
3809 _G.stack.pushedDE = TRUE;
3812 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
3814 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
3822 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3827 /* Fully unroled version of mul.s. Not the most efficient.
3829 for (count = 0; count < 16; count++)
3831 if (count != 0 && active)
3833 emit2 ("add hl,hl");
3837 if (active == FALSE)
3844 emit2 ("add hl,de");
3853 if (IS_Z80 && _G.stack.pushedDE)
3856 _G.stack.pushedDE = FALSE;
3859 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3861 freeAsmop (IC_LEFT (ic), NULL, ic);
3862 freeAsmop (IC_RIGHT (ic), NULL, ic);
3863 freeAsmop (IC_RESULT (ic), NULL, ic);
3866 /*-----------------------------------------------------------------*/
3867 /* genDiv - generates code for division */
3868 /*-----------------------------------------------------------------*/
3872 /* Shouldn't occur - all done through function calls */
3873 wassertl (0, "Division is handled through support function calls");
3876 /*-----------------------------------------------------------------*/
3877 /* genMod - generates code for division */
3878 /*-----------------------------------------------------------------*/
3882 /* Shouldn't occur - all done through function calls */
3886 /*-----------------------------------------------------------------*/
3887 /* genIfxJump :- will create a jump depending on the ifx */
3888 /*-----------------------------------------------------------------*/
3890 genIfxJump (iCode * ic, char *jval)
3895 /* if true label then we jump if condition
3899 jlbl = IC_TRUE (ic);
3900 if (!strcmp (jval, "a"))
3904 else if (!strcmp (jval, "c"))
3908 else if (!strcmp (jval, "nc"))
3912 else if (!strcmp (jval, "m"))
3916 else if (!strcmp (jval, "p"))
3922 /* The buffer contains the bit on A that we should test */
3928 /* false label is present */
3929 jlbl = IC_FALSE (ic);
3930 if (!strcmp (jval, "a"))
3934 else if (!strcmp (jval, "c"))
3938 else if (!strcmp (jval, "nc"))
3942 else if (!strcmp (jval, "m"))
3946 else if (!strcmp (jval, "p"))
3952 /* The buffer contains the bit on A that we should test */
3956 /* Z80 can do a conditional long jump */
3957 if (!strcmp (jval, "a"))
3961 else if (!strcmp (jval, "c"))
3964 else if (!strcmp (jval, "nc"))
3967 else if (!strcmp (jval, "m"))
3970 else if (!strcmp (jval, "p"))
3975 emit2 ("bit %s,a", jval);
3977 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
3979 /* mark the icode as generated */
3985 _getPairIdName (PAIR_ID id)
3987 return _pairs[id].name;
3992 /* if unsigned char cmp with lit, just compare */
3994 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
3996 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3999 emit2 ("xor a,!immedbyte", 0x80);
4000 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4003 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4005 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4007 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4008 // Pull left into DE and right into HL
4009 aopGet (AOP(left), LSB, FALSE);
4012 aopGet (AOP(right), LSB, FALSE);
4016 if (size == 0 && sign)
4018 // Highest byte when signed needs the bits flipped
4021 emit2 ("ld a,(de)");
4022 emit2 ("xor !immedbyte", 0x80);
4024 emit2 ("ld a,(hl)");
4025 emit2 ("xor !immedbyte", 0x80);
4029 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4033 emit2 ("ld a,(de)");
4034 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4044 spillPair (PAIR_HL);
4046 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4048 setupPair (PAIR_HL, AOP (left), 0);
4049 aopGet (AOP(right), LSB, FALSE);
4053 if (size == 0 && sign)
4055 // Highest byte when signed needs the bits flipped
4058 emit2 ("ld a,(hl)");
4059 emit2 ("xor !immedbyte", 0x80);
4061 emit2 ("ld a,%d(iy)", offset);
4062 emit2 ("xor !immedbyte", 0x80);
4066 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4070 emit2 ("ld a,(hl)");
4071 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4080 spillPair (PAIR_HL);
4081 spillPair (PAIR_IY);
4085 if (AOP_TYPE (right) == AOP_LIT)
4087 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4088 /* optimize if(x < 0) or if(x >= 0) */
4093 /* No sign so it's always false */
4098 /* Just load in the top most bit */
4099 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4100 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4102 genIfxJump (ifx, "7");
4114 /* First setup h and l contaning the top most bytes XORed */
4115 bool fDidXor = FALSE;
4116 if (AOP_TYPE (left) == AOP_LIT)
4118 unsigned long lit = (unsigned long)
4119 floatFromVal (AOP (left)->aopu.aop_lit);
4120 emit2 ("ld %s,!immedbyte", _fTmp[0],
4121 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4125 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4126 emit2 ("xor a,!immedbyte", 0x80);
4127 emit2 ("ld %s,a", _fTmp[0]);
4130 if (AOP_TYPE (right) == AOP_LIT)
4132 unsigned long lit = (unsigned long)
4133 floatFromVal (AOP (right)->aopu.aop_lit);
4134 emit2 ("ld %s,!immedbyte", _fTmp[1],
4135 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4139 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4140 emit2 ("xor a,!immedbyte", 0x80);
4141 emit2 ("ld %s,a", _fTmp[1]);
4147 /* Do a long subtract */
4150 _moveA (aopGet (AOP (left), offset, FALSE));
4152 if (sign && size == 0)
4154 emit2 ("ld a,%s", _fTmp[0]);
4155 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4159 /* Subtract through, propagating the carry */
4160 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4168 /** Generic compare for > or <
4171 genCmp (operand * left, operand * right,
4172 operand * result, iCode * ifx, int sign)
4174 int size, offset = 0;
4175 unsigned long lit = 0L;
4176 bool swap_sense = FALSE;
4178 /* if left & right are bit variables */
4179 if (AOP_TYPE (left) == AOP_CRY &&
4180 AOP_TYPE (right) == AOP_CRY)
4182 /* Cant happen on the Z80 */
4183 wassertl (0, "Tried to compare two bits");
4187 /* Do a long subtract of right from left. */
4188 size = max (AOP_SIZE (left), AOP_SIZE (right));
4190 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4192 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4193 // Pull left into DE and right into HL
4194 aopGet (AOP(left), LSB, FALSE);
4197 aopGet (AOP(right), LSB, FALSE);
4201 emit2 ("ld a,(de)");
4202 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4211 spillPair (PAIR_HL);
4215 if (AOP_TYPE (right) == AOP_LIT)
4217 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4218 /* optimize if(x < 0) or if(x >= 0) */
4223 /* No sign so it's always false */
4228 /* Just load in the top most bit */
4229 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4230 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4232 genIfxJump (ifx, "7");
4243 genIfxJump (ifx, swap_sense ? "c" : "nc");
4254 _moveA (aopGet (AOP (left), offset, FALSE));
4255 /* Subtract through, propagating the carry */
4256 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4262 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4266 /* Shift the sign bit up into carry */
4269 outBitCLong (result, swap_sense);
4273 /* if the result is used in the next
4274 ifx conditional branch then generate
4275 code a little differently */
4283 genIfxJump (ifx, swap_sense ? "nc" : "c");
4287 genIfxJump (ifx, swap_sense ? "p" : "m");
4292 genIfxJump (ifx, swap_sense ? "nc" : "c");
4299 /* Shift the sign bit up into carry */
4302 outBitCLong (result, swap_sense);
4304 /* leave the result in acc */
4308 /*-----------------------------------------------------------------*/
4309 /* genCmpGt :- greater than comparison */
4310 /*-----------------------------------------------------------------*/
4312 genCmpGt (iCode * ic, iCode * ifx)
4314 operand *left, *right, *result;
4315 sym_link *letype, *retype;
4318 left = IC_LEFT (ic);
4319 right = IC_RIGHT (ic);
4320 result = IC_RESULT (ic);
4322 letype = getSpec (operandType (left));
4323 retype = getSpec (operandType (right));
4324 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4325 /* assign the amsops */
4326 aopOp (left, ic, FALSE, FALSE);
4327 aopOp (right, ic, FALSE, FALSE);
4328 aopOp (result, ic, TRUE, FALSE);
4330 genCmp (right, left, result, ifx, sign);
4332 freeAsmop (left, NULL, ic);
4333 freeAsmop (right, NULL, ic);
4334 freeAsmop (result, NULL, ic);
4337 /*-----------------------------------------------------------------*/
4338 /* genCmpLt - less than comparisons */
4339 /*-----------------------------------------------------------------*/
4341 genCmpLt (iCode * ic, iCode * ifx)
4343 operand *left, *right, *result;
4344 sym_link *letype, *retype;
4347 left = IC_LEFT (ic);
4348 right = IC_RIGHT (ic);
4349 result = IC_RESULT (ic);
4351 letype = getSpec (operandType (left));
4352 retype = getSpec (operandType (right));
4353 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4355 /* assign the amsops */
4356 aopOp (left, ic, FALSE, FALSE);
4357 aopOp (right, ic, FALSE, FALSE);
4358 aopOp (result, ic, TRUE, FALSE);
4360 genCmp (left, right, result, ifx, sign);
4362 freeAsmop (left, NULL, ic);
4363 freeAsmop (right, NULL, ic);
4364 freeAsmop (result, NULL, ic);
4367 /*-----------------------------------------------------------------*/
4368 /* gencjneshort - compare and jump if not equal */
4369 /*-----------------------------------------------------------------*/
4371 gencjneshort (operand * left, operand * right, symbol * lbl)
4373 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4375 unsigned long lit = 0L;
4377 /* Swap the left and right if it makes the computation easier */
4378 if (AOP_TYPE (left) == AOP_LIT)
4385 if (AOP_TYPE (right) == AOP_LIT)
4387 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4390 /* if the right side is a literal then anything goes */
4391 if (AOP_TYPE (right) == AOP_LIT &&
4392 AOP_TYPE (left) != AOP_DIR)
4396 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4401 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4408 emit2 ("jp nz,!tlabel", lbl->key + 100);
4414 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4415 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
4418 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
4419 emit2 ("jp nz,!tlabel", lbl->key + 100);
4424 /* if the right side is in a register or in direct space or
4425 if the left is a pointer register & right is not */
4426 else if (AOP_TYPE (right) == AOP_REG ||
4427 AOP_TYPE (right) == AOP_DIR ||
4428 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
4432 _moveA (aopGet (AOP (left), offset, FALSE));
4433 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
4434 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4436 emit2 ("jp nz,!tlabel", lbl->key + 100);
4439 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4440 emit2 ("jp nz,!tlabel", lbl->key + 100);
4447 /* right is a pointer reg need both a & b */
4448 /* PENDING: is this required? */
4451 _moveA (aopGet (AOP (right), offset, FALSE));
4452 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
4453 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
4459 /*-----------------------------------------------------------------*/
4460 /* gencjne - compare and jump if not equal */
4461 /*-----------------------------------------------------------------*/
4463 gencjne (operand * left, operand * right, symbol * lbl)
4465 symbol *tlbl = newiTempLabel (NULL);
4467 gencjneshort (left, right, lbl);
4470 emit2 ("ld a,!one");
4471 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4472 emitLabel (lbl->key + 100);
4474 emitLabel (tlbl->key + 100);
4477 /*-----------------------------------------------------------------*/
4478 /* genCmpEq - generates code for equal to */
4479 /*-----------------------------------------------------------------*/
4481 genCmpEq (iCode * ic, iCode * ifx)
4483 operand *left, *right, *result;
4485 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4486 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4487 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4489 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4491 /* Swap operands if it makes the operation easier. ie if:
4492 1. Left is a literal.
4494 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4496 operand *t = IC_RIGHT (ic);
4497 IC_RIGHT (ic) = IC_LEFT (ic);
4501 if (ifx && !AOP_SIZE (result))
4504 /* if they are both bit variables */
4505 if (AOP_TYPE (left) == AOP_CRY &&
4506 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4508 wassertl (0, "Tried to compare two bits");
4512 tlbl = newiTempLabel (NULL);
4513 gencjneshort (left, right, tlbl);
4516 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4517 emitLabel (tlbl->key + 100);
4521 /* PENDING: do this better */
4522 symbol *lbl = newiTempLabel (NULL);
4523 emit2 ("!shortjp !tlabel", lbl->key + 100);
4524 emitLabel (tlbl->key + 100);
4525 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4526 emitLabel (lbl->key + 100);
4529 /* mark the icode as generated */
4534 /* if they are both bit variables */
4535 if (AOP_TYPE (left) == AOP_CRY &&
4536 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4538 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4544 gencjne (left, right, newiTempLabel (NULL));
4545 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4552 genIfxJump (ifx, "a");
4555 /* if the result is used in an arithmetic operation
4556 then put the result in place */
4557 if (AOP_TYPE (result) != AOP_CRY)
4562 /* leave the result in acc */
4566 freeAsmop (left, NULL, ic);
4567 freeAsmop (right, NULL, ic);
4568 freeAsmop (result, NULL, ic);
4571 /*-----------------------------------------------------------------*/
4572 /* ifxForOp - returns the icode containing the ifx for operand */
4573 /*-----------------------------------------------------------------*/
4575 ifxForOp (operand * op, iCode * ic)
4577 /* if true symbol then needs to be assigned */
4578 if (IS_TRUE_SYMOP (op))
4581 /* if this has register type condition and
4582 the next instruction is ifx with the same operand
4583 and live to of the operand is upto the ifx only then */
4585 ic->next->op == IFX &&
4586 IC_COND (ic->next)->key == op->key &&
4587 OP_SYMBOL (op)->liveTo <= ic->next->seq)
4593 /*-----------------------------------------------------------------*/
4594 /* genAndOp - for && operation */
4595 /*-----------------------------------------------------------------*/
4597 genAndOp (iCode * ic)
4599 operand *left, *right, *result;
4602 /* note here that && operations that are in an if statement are
4603 taken away by backPatchLabels only those used in arthmetic
4604 operations remain */
4605 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4606 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4607 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4609 /* if both are bit variables */
4610 if (AOP_TYPE (left) == AOP_CRY &&
4611 AOP_TYPE (right) == AOP_CRY)
4613 wassertl (0, "Tried to and two bits");
4617 tlbl = newiTempLabel (NULL);
4619 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
4621 emitLabel (tlbl->key + 100);
4625 freeAsmop (left, NULL, ic);
4626 freeAsmop (right, NULL, ic);
4627 freeAsmop (result, NULL, ic);
4630 /*-----------------------------------------------------------------*/
4631 /* genOrOp - for || operation */
4632 /*-----------------------------------------------------------------*/
4634 genOrOp (iCode * ic)
4636 operand *left, *right, *result;
4639 /* note here that || operations that are in an
4640 if statement are taken away by backPatchLabels
4641 only those used in arthmetic operations remain */
4642 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4643 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4644 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4646 /* if both are bit variables */
4647 if (AOP_TYPE (left) == AOP_CRY &&
4648 AOP_TYPE (right) == AOP_CRY)
4650 wassertl (0, "Tried to OR two bits");
4654 tlbl = newiTempLabel (NULL);
4656 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4658 emitLabel (tlbl->key + 100);
4662 freeAsmop (left, NULL, ic);
4663 freeAsmop (right, NULL, ic);
4664 freeAsmop (result, NULL, ic);
4667 /*-----------------------------------------------------------------*/
4668 /* isLiteralBit - test if lit == 2^n */
4669 /*-----------------------------------------------------------------*/
4671 isLiteralBit (unsigned long lit)
4673 unsigned long pw[32] =
4674 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
4675 0x100L, 0x200L, 0x400L, 0x800L,
4676 0x1000L, 0x2000L, 0x4000L, 0x8000L,
4677 0x10000L, 0x20000L, 0x40000L, 0x80000L,
4678 0x100000L, 0x200000L, 0x400000L, 0x800000L,
4679 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
4680 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
4683 for (idx = 0; idx < 32; idx++)
4689 /*-----------------------------------------------------------------*/
4690 /* jmpTrueOrFalse - */
4691 /*-----------------------------------------------------------------*/
4693 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
4695 // ugly but optimized by peephole
4698 symbol *nlbl = newiTempLabel (NULL);
4699 emit2 ("jp !tlabel", nlbl->key + 100);
4700 emitLabel (tlbl->key + 100);
4701 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
4702 emitLabel (nlbl->key + 100);
4706 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
4707 emitLabel (tlbl->key + 100);
4712 /*-----------------------------------------------------------------*/
4713 /* genAnd - code for and */
4714 /*-----------------------------------------------------------------*/
4716 genAnd (iCode * ic, iCode * ifx)
4718 operand *left, *right, *result;
4719 int size, offset = 0;
4720 unsigned long lit = 0L;
4723 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4724 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4725 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4727 /* if left is a literal & right is not then exchange them */
4728 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4729 AOP_NEEDSACC (left))
4731 operand *tmp = right;
4736 /* if result = right then exchange them */
4737 if (sameRegs (AOP (result), AOP (right)))
4739 operand *tmp = right;
4744 /* if right is bit then exchange them */
4745 if (AOP_TYPE (right) == AOP_CRY &&
4746 AOP_TYPE (left) != AOP_CRY)
4748 operand *tmp = right;
4752 if (AOP_TYPE (right) == AOP_LIT)
4753 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4755 size = AOP_SIZE (result);
4757 if (AOP_TYPE (left) == AOP_CRY)
4759 wassertl (0, "Tried to perform an AND with a bit as an operand");
4763 // if(val & 0xZZ) - size = 0, ifx != FALSE -
4764 // bit = val & 0xZZ - size = 1, ifx = FALSE -
4765 if ((AOP_TYPE (right) == AOP_LIT) &&
4766 (AOP_TYPE (result) == AOP_CRY) &&
4767 (AOP_TYPE (left) != AOP_CRY))
4769 symbol *tlbl = newiTempLabel (NULL);
4770 int sizel = AOP_SIZE (left);
4773 /* PENDING: Test case for this. */
4778 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
4780 _moveA (aopGet (AOP (left), offset, FALSE));
4781 if (bytelit != 0x0FFL)
4783 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4790 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4794 // bit = left & literal
4798 emit2 ("!tlabeldef", tlbl->key + 100);
4800 // if(left & literal)
4805 jmpTrueOrFalse (ifx, tlbl);
4813 /* if left is same as result */
4814 if (sameRegs (AOP (result), AOP (left)))
4816 for (; size--; offset++)
4818 if (AOP_TYPE (right) == AOP_LIT)
4820 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4825 aopPut (AOP (result), "!zero", offset);
4828 _moveA (aopGet (AOP (left), offset, FALSE));
4830 aopGet (AOP (right), offset, FALSE));
4831 aopPut (AOP (left), "a", offset);
4838 if (AOP_TYPE (left) == AOP_ACC)
4840 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
4844 _moveA (aopGet (AOP (left), offset, FALSE));
4846 aopGet (AOP (right), offset, FALSE));
4847 aopPut (AOP (left), "a", offset);
4854 // left & result in different registers
4855 if (AOP_TYPE (result) == AOP_CRY)
4857 wassertl (0, "Tried to AND where the result is in carry");
4861 for (; (size--); offset++)
4864 // result = left & right
4865 if (AOP_TYPE (right) == AOP_LIT)
4867 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4869 aopPut (AOP (result),
4870 aopGet (AOP (left), offset, FALSE),
4874 else if (bytelit == 0)
4876 aopPut (AOP (result), "!zero", offset);
4880 // faster than result <- left, anl result,right
4881 // and better if result is SFR
4882 if (AOP_TYPE (left) == AOP_ACC)
4883 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4886 _moveA (aopGet (AOP (left), offset, FALSE));
4888 aopGet (AOP (right), offset, FALSE));
4890 aopPut (AOP (result), "a", offset);
4897 freeAsmop (left, NULL, ic);
4898 freeAsmop (right, NULL, ic);
4899 freeAsmop (result, NULL, ic);
4902 /*-----------------------------------------------------------------*/
4903 /* genOr - code for or */
4904 /*-----------------------------------------------------------------*/
4906 genOr (iCode * ic, iCode * ifx)
4908 operand *left, *right, *result;
4909 int size, offset = 0;
4910 unsigned long lit = 0L;
4913 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4914 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4915 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4917 /* if left is a literal & right is not then exchange them */
4918 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4919 AOP_NEEDSACC (left))
4921 operand *tmp = right;
4926 /* if result = right then exchange them */
4927 if (sameRegs (AOP (result), AOP (right)))
4929 operand *tmp = right;
4934 /* if right is bit then exchange them */
4935 if (AOP_TYPE (right) == AOP_CRY &&
4936 AOP_TYPE (left) != AOP_CRY)
4938 operand *tmp = right;
4942 if (AOP_TYPE (right) == AOP_LIT)
4943 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4945 size = AOP_SIZE (result);
4947 if (AOP_TYPE (left) == AOP_CRY)
4949 wassertl (0, "Tried to OR where left is a bit");
4953 // if(val | 0xZZ) - size = 0, ifx != FALSE -
4954 // bit = val | 0xZZ - size = 1, ifx = FALSE -
4955 if ((AOP_TYPE (right) == AOP_LIT) &&
4956 (AOP_TYPE (result) == AOP_CRY) &&
4957 (AOP_TYPE (left) != AOP_CRY))
4959 symbol *tlbl = newiTempLabel (NULL);
4960 int sizel = AOP_SIZE (left);
4964 wassertl (0, "Result is assigned to a bit");
4966 /* PENDING: Modeled after the AND code which is inefficent. */
4969 bytelit = (lit >> (offset * 8)) & 0x0FFL;
4971 _moveA (aopGet (AOP (left), offset, FALSE));
4972 /* OR with any literal is the same as OR with itself. */
4974 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4980 jmpTrueOrFalse (ifx, tlbl);
4985 /* if left is same as result */
4986 if (sameRegs (AOP (result), AOP (left)))
4988 for (; size--; offset++)
4990 if (AOP_TYPE (right) == AOP_LIT)
4992 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4996 _moveA (aopGet (AOP (left), offset, FALSE));
4998 aopGet (AOP (right), offset, FALSE));
4999 aopPut (AOP (result), "a", offset);
5004 if (AOP_TYPE (left) == AOP_ACC)
5005 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5008 _moveA (aopGet (AOP (left), offset, FALSE));
5010 aopGet (AOP (right), offset, FALSE));
5011 aopPut (AOP (result), "a", offset);
5018 // left & result in different registers
5019 if (AOP_TYPE (result) == AOP_CRY)
5021 wassertl (0, "Result of OR is in a bit");
5024 for (; (size--); offset++)
5027 // result = left & right
5028 if (AOP_TYPE (right) == AOP_LIT)
5030 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5032 aopPut (AOP (result),
5033 aopGet (AOP (left), offset, FALSE),
5038 // faster than result <- left, anl result,right
5039 // and better if result is SFR
5040 if (AOP_TYPE (left) == AOP_ACC)
5041 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5044 _moveA (aopGet (AOP (left), offset, FALSE));
5046 aopGet (AOP (right), offset, FALSE));
5048 aopPut (AOP (result), "a", offset);
5049 /* PENDING: something weird is going on here. Add exception. */
5050 if (AOP_TYPE (result) == AOP_ACC)
5056 freeAsmop (left, NULL, ic);
5057 freeAsmop (right, NULL, ic);
5058 freeAsmop (result, NULL, ic);
5061 /*-----------------------------------------------------------------*/
5062 /* genXor - code for xclusive or */
5063 /*-----------------------------------------------------------------*/
5065 genXor (iCode * ic, iCode * ifx)
5067 operand *left, *right, *result;
5068 int size, offset = 0;
5069 unsigned long lit = 0L;
5071 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5072 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5073 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5075 /* if left is a literal & right is not then exchange them */
5076 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5077 AOP_NEEDSACC (left))
5079 operand *tmp = right;
5084 /* if result = right then exchange them */
5085 if (sameRegs (AOP (result), AOP (right)))
5087 operand *tmp = right;
5092 /* if right is bit then exchange them */
5093 if (AOP_TYPE (right) == AOP_CRY &&
5094 AOP_TYPE (left) != AOP_CRY)
5096 operand *tmp = right;
5100 if (AOP_TYPE (right) == AOP_LIT)
5101 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5103 size = AOP_SIZE (result);
5105 if (AOP_TYPE (left) == AOP_CRY)
5107 wassertl (0, "Tried to XOR a bit");
5111 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5112 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5113 if ((AOP_TYPE (right) == AOP_LIT) &&
5114 (AOP_TYPE (result) == AOP_CRY) &&
5115 (AOP_TYPE (left) != AOP_CRY))
5117 symbol *tlbl = newiTempLabel (NULL);
5118 int sizel = AOP_SIZE (left);
5122 /* PENDING: Test case for this. */
5123 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5127 _moveA (aopGet (AOP (left), offset, FALSE));
5128 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5129 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5134 jmpTrueOrFalse (ifx, tlbl);
5138 wassertl (0, "Result of XOR was destined for a bit");
5143 /* if left is same as result */
5144 if (sameRegs (AOP (result), AOP (left)))
5146 for (; size--; offset++)
5148 if (AOP_TYPE (right) == AOP_LIT)
5150 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5154 _moveA (aopGet (AOP (right), offset, FALSE));
5156 aopGet (AOP (left), offset, FALSE));
5157 aopPut (AOP (result), "a", offset);
5162 if (AOP_TYPE (left) == AOP_ACC)
5164 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5168 _moveA (aopGet (AOP (right), offset, FALSE));
5170 aopGet (AOP (left), offset, FALSE));
5171 aopPut (AOP (result), "a", 0);
5178 // left & result in different registers
5179 if (AOP_TYPE (result) == AOP_CRY)
5181 wassertl (0, "Result of XOR is in a bit");
5184 for (; (size--); offset++)
5187 // result = left & right
5188 if (AOP_TYPE (right) == AOP_LIT)
5190 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5192 aopPut (AOP (result),
5193 aopGet (AOP (left), offset, FALSE),
5198 // faster than result <- left, anl result,right
5199 // and better if result is SFR
5200 if (AOP_TYPE (left) == AOP_ACC)
5202 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5206 _moveA (aopGet (AOP (right), offset, FALSE));
5208 aopGet (AOP (left), offset, FALSE));
5210 aopPut (AOP (result), "a", offset);
5215 freeAsmop (left, NULL, ic);
5216 freeAsmop (right, NULL, ic);
5217 freeAsmop (result, NULL, ic);
5220 /*-----------------------------------------------------------------*/
5221 /* genInline - write the inline code out */
5222 /*-----------------------------------------------------------------*/
5224 genInline (iCode * ic)
5226 char *buffer, *bp, *bp1;
5228 _G.lines.isInline += (!options.asmpeep);
5230 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5231 strcpy (buffer, IC_INLINE (ic));
5233 /* emit each line as a code */
5258 _G.lines.isInline -= (!options.asmpeep);
5262 /*-----------------------------------------------------------------*/
5263 /* genRRC - rotate right with carry */
5264 /*-----------------------------------------------------------------*/
5271 /*-----------------------------------------------------------------*/
5272 /* genRLC - generate code for rotate left with carry */
5273 /*-----------------------------------------------------------------*/
5280 /*-----------------------------------------------------------------*/
5281 /* genGetHbit - generates code get highest order bit */
5282 /*-----------------------------------------------------------------*/
5284 genGetHbit (iCode * ic)
5286 operand *left, *result;
5287 left = IC_LEFT (ic);
5288 result = IC_RESULT (ic);
5290 aopOp (left, ic, FALSE, FALSE);
5291 aopOp (result, ic, FALSE, FALSE);
5293 /* get the highest order byte into a */
5294 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5296 if (AOP_TYPE (result) == AOP_CRY)
5304 emit2 ("and a,!one");
5309 freeAsmop (left, NULL, ic);
5310 freeAsmop (result, NULL, ic);
5314 emitRsh2 (asmop *aop, int size, int is_signed)
5320 const char *l = aopGet (aop, size, FALSE);
5323 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5333 /*-----------------------------------------------------------------*/
5334 /* shiftR2Left2Result - shift right two bytes from left to result */
5335 /*-----------------------------------------------------------------*/
5337 shiftR2Left2Result (operand * left, int offl,
5338 operand * result, int offr,
5339 int shCount, int is_signed)
5342 symbol *tlbl, *tlbl1;
5344 movLeft2Result (left, offl, result, offr, 0);
5345 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5347 /* if (AOP(result)->type == AOP_REG) { */
5349 tlbl = newiTempLabel (NULL);
5350 tlbl1 = newiTempLabel (NULL);
5352 /* Left is already in result - so now do the shift */
5357 emitRsh2 (AOP (result), size, is_signed);
5362 emit2 ("ld a,!immedbyte+1", shCount);
5363 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5364 emitLabel (tlbl->key + 100);
5366 emitRsh2 (AOP (result), size, is_signed);
5368 emitLabel (tlbl1->key + 100);
5370 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5374 /*-----------------------------------------------------------------*/
5375 /* shiftL2Left2Result - shift left two bytes from left to result */
5376 /*-----------------------------------------------------------------*/
5378 shiftL2Left2Result (operand * left, int offl,
5379 operand * result, int offr, int shCount)
5381 if (sameRegs (AOP (result), AOP (left)) &&
5382 ((offl + MSB16) == offr))
5388 /* Copy left into result */
5389 movLeft2Result (left, offl, result, offr, 0);
5390 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5393 if (getPairId (AOP (result)) == PAIR_HL)
5397 emit2 ("add hl,hl");
5404 symbol *tlbl, *tlbl1;
5407 tlbl = newiTempLabel (NULL);
5408 tlbl1 = newiTempLabel (NULL);
5410 if (AOP (result)->type == AOP_REG)
5414 for (offset = 0; offset < size; offset++)
5416 l = aopGet (AOP (result), offset, FALSE);
5420 emit2 ("sla %s", l);
5431 /* Left is already in result - so now do the shift */
5434 emit2 ("ld a,!immedbyte+1", shCount);
5435 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5436 emitLabel (tlbl->key + 100);
5441 l = aopGet (AOP (result), offset, FALSE);
5445 emit2 ("sla %s", l);
5456 emitLabel (tlbl1->key + 100);
5458 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5464 /*-----------------------------------------------------------------*/
5465 /* AccRol - rotate left accumulator by known count */
5466 /*-----------------------------------------------------------------*/
5468 AccRol (int shCount)
5470 shCount &= 0x0007; // shCount : 0..7
5547 /*-----------------------------------------------------------------*/
5548 /* AccLsh - left shift accumulator by known count */
5549 /*-----------------------------------------------------------------*/
5551 AccLsh (int shCount)
5553 static const unsigned char SLMask[] =
5555 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5564 else if (shCount == 2)
5571 /* rotate left accumulator */
5573 /* and kill the lower order bits */
5574 emit2 ("and a,!immedbyte", SLMask[shCount]);
5579 /*-----------------------------------------------------------------*/
5580 /* shiftL1Left2Result - shift left one byte from left to result */
5581 /*-----------------------------------------------------------------*/
5583 shiftL1Left2Result (operand * left, int offl,
5584 operand * result, int offr, int shCount)
5587 l = aopGet (AOP (left), offl, FALSE);
5589 /* shift left accumulator */
5591 aopPut (AOP (result), "a", offr);
5595 /*-----------------------------------------------------------------*/
5596 /* genlshTwo - left shift two bytes by known amount != 0 */
5597 /*-----------------------------------------------------------------*/
5599 genlshTwo (operand * result, operand * left, int shCount)
5601 int size = AOP_SIZE (result);
5603 wassert (size == 2);
5605 /* if shCount >= 8 */
5613 movLeft2Result (left, LSB, result, MSB16, 0);
5614 aopPut (AOP (result), "!zero", 0);
5615 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
5619 movLeft2Result (left, LSB, result, MSB16, 0);
5620 aopPut (AOP (result), "!zero", 0);
5625 aopPut (AOP (result), "!zero", LSB);
5628 /* 1 <= shCount <= 7 */
5637 shiftL2Left2Result (left, LSB, result, LSB, shCount);
5642 /*-----------------------------------------------------------------*/
5643 /* genlshOne - left shift a one byte quantity by known count */
5644 /*-----------------------------------------------------------------*/
5646 genlshOne (operand * result, operand * left, int shCount)
5648 shiftL1Left2Result (left, LSB, result, LSB, shCount);
5651 /*-----------------------------------------------------------------*/
5652 /* genLeftShiftLiteral - left shifting by known count */
5653 /*-----------------------------------------------------------------*/
5655 genLeftShiftLiteral (operand * left,
5660 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5663 freeAsmop (right, NULL, ic);
5665 aopOp (left, ic, FALSE, FALSE);
5666 aopOp (result, ic, FALSE, FALSE);
5668 size = getSize (operandType (result));
5670 /* I suppose that the left size >= result size */
5676 else if (shCount >= (size * 8))
5680 aopPut (AOP (result), "!zero", size);
5688 genlshOne (result, left, shCount);
5691 genlshTwo (result, left, shCount);
5694 wassertl (0, "Shifting of longs is currently unsupported");
5700 freeAsmop (left, NULL, ic);
5701 freeAsmop (result, NULL, ic);
5704 /*-----------------------------------------------------------------*/
5705 /* genLeftShift - generates code for left shifting */
5706 /*-----------------------------------------------------------------*/
5708 genLeftShift (iCode * ic)
5712 symbol *tlbl, *tlbl1;
5713 operand *left, *right, *result;
5715 right = IC_RIGHT (ic);
5716 left = IC_LEFT (ic);
5717 result = IC_RESULT (ic);
5719 aopOp (right, ic, FALSE, FALSE);
5721 /* if the shift count is known then do it
5722 as efficiently as possible */
5723 if (AOP_TYPE (right) == AOP_LIT)
5725 genLeftShiftLiteral (left, right, result, ic);
5729 /* shift count is unknown then we have to form a loop get the loop
5730 count in B : Note: we take only the lower order byte since
5731 shifting more that 32 bits make no sense anyway, ( the largest
5732 size of an object can be only 32 bits ) */
5733 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5735 freeAsmop (right, NULL, ic);
5736 aopOp (left, ic, FALSE, FALSE);
5737 aopOp (result, ic, FALSE, FALSE);
5739 /* now move the left to the result if they are not the
5742 if (!sameRegs (AOP (left), AOP (result)))
5745 size = AOP_SIZE (result);
5749 l = aopGet (AOP (left), offset, FALSE);
5750 aopPut (AOP (result), l, offset);
5755 tlbl = newiTempLabel (NULL);
5756 size = AOP_SIZE (result);
5758 tlbl1 = newiTempLabel (NULL);
5760 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5761 emitLabel (tlbl->key + 100);
5762 l = aopGet (AOP (result), offset, FALSE);
5766 l = aopGet (AOP (result), offset, FALSE);
5770 emit2 ("sla %s", l);
5778 emitLabel (tlbl1->key + 100);
5780 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5782 freeAsmop (left, NULL, ic);
5783 freeAsmop (result, NULL, ic);
5786 /*-----------------------------------------------------------------*/
5787 /* genrshOne - left shift two bytes by known amount != 0 */
5788 /*-----------------------------------------------------------------*/
5790 genrshOne (operand * result, operand * left, int shCount, int is_signed)
5793 int size = AOP_SIZE (result);
5796 wassert (size == 1);
5797 wassert (shCount < 8);
5799 l = aopGet (AOP (left), 0, FALSE);
5801 if (AOP (result)->type == AOP_REG)
5803 aopPut (AOP (result), l, 0);
5804 l = aopGet (AOP (result), 0, FALSE);
5807 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5815 emit2 ("%s a", is_signed ? "sra" : "srl");
5817 aopPut (AOP (result), "a", 0);
5821 /*-----------------------------------------------------------------*/
5822 /* AccRsh - right shift accumulator by known count */
5823 /*-----------------------------------------------------------------*/
5825 AccRsh (int shCount)
5827 static const unsigned char SRMask[] =
5829 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
5834 /* rotate right accumulator */
5835 AccRol (8 - shCount);
5836 /* and kill the higher order bits */
5837 emit2 ("and a,!immedbyte", SRMask[shCount]);
5841 /*-----------------------------------------------------------------*/
5842 /* shiftR1Left2Result - shift right one byte from left to result */
5843 /*-----------------------------------------------------------------*/
5845 shiftR1Left2Result (operand * left, int offl,
5846 operand * result, int offr,
5847 int shCount, int sign)
5849 _moveA (aopGet (AOP (left), offl, FALSE));
5854 emit2 ("%s a", sign ? "sra" : "srl");
5861 aopPut (AOP (result), "a", offr);
5864 /*-----------------------------------------------------------------*/
5865 /* genrshTwo - right shift two bytes by known amount != 0 */
5866 /*-----------------------------------------------------------------*/
5868 genrshTwo (operand * result, operand * left,
5869 int shCount, int sign)
5871 /* if shCount >= 8 */
5877 shiftR1Left2Result (left, MSB16, result, LSB,
5882 movLeft2Result (left, MSB16, result, LSB, sign);
5886 /* Sign extend the result */
5887 _moveA(aopGet (AOP (result), 0, FALSE));
5891 aopPut (AOP (result), ACC_NAME, MSB16);
5895 aopPut (AOP (result), "!zero", 1);
5898 /* 1 <= shCount <= 7 */
5901 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
5905 /*-----------------------------------------------------------------*/
5906 /* genRightShiftLiteral - left shifting by known count */
5907 /*-----------------------------------------------------------------*/
5909 genRightShiftLiteral (operand * left,
5915 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5918 freeAsmop (right, NULL, ic);
5920 aopOp (left, ic, FALSE, FALSE);
5921 aopOp (result, ic, FALSE, FALSE);
5923 size = getSize (operandType (result));
5925 /* I suppose that the left size >= result size */
5931 else if (shCount >= (size * 8)) {
5933 if (!SPEC_USIGN(getSpec(operandType(left)))) {
5934 _moveA(aopGet (AOP (left), 0, FALSE));
5942 aopPut (AOP (result), s, size);
5949 genrshOne (result, left, shCount, sign);
5952 genrshTwo (result, left, shCount, sign);
5955 wassertl (0, "Asked to shift right a long which should be a function call");
5958 wassertl (0, "Entered default case in right shift delegate");
5961 freeAsmop (left, NULL, ic);
5962 freeAsmop (result, NULL, ic);
5965 /*-----------------------------------------------------------------*/
5966 /* genRightShift - generate code for right shifting */
5967 /*-----------------------------------------------------------------*/
5969 genRightShift (iCode * ic)
5971 operand *right, *left, *result;
5973 int size, offset, first = 1;
5977 symbol *tlbl, *tlbl1;
5979 /* if signed then we do it the hard way preserve the
5980 sign bit moving it inwards */
5981 retype = getSpec (operandType (IC_RESULT (ic)));
5983 is_signed = !SPEC_USIGN (retype);
5985 /* signed & unsigned types are treated the same : i.e. the
5986 signed is NOT propagated inwards : quoting from the
5987 ANSI - standard : "for E1 >> E2, is equivalent to division
5988 by 2**E2 if unsigned or if it has a non-negative value,
5989 otherwise the result is implementation defined ", MY definition
5990 is that the sign does not get propagated */
5992 right = IC_RIGHT (ic);
5993 left = IC_LEFT (ic);
5994 result = IC_RESULT (ic);
5996 aopOp (right, ic, FALSE, FALSE);
5998 /* if the shift count is known then do it
5999 as efficiently as possible */
6000 if (AOP_TYPE (right) == AOP_LIT)
6002 genRightShiftLiteral (left, right, result, ic, is_signed);
6006 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6008 freeAsmop (right, NULL, ic);
6010 aopOp (left, ic, FALSE, FALSE);
6011 aopOp (result, ic, FALSE, FALSE);
6013 /* now move the left to the result if they are not the
6015 if (!sameRegs (AOP (left), AOP (result)))
6018 size = AOP_SIZE (result);
6022 l = aopGet (AOP (left), offset, FALSE);
6023 aopPut (AOP (result), l, offset);
6028 tlbl = newiTempLabel (NULL);
6029 tlbl1 = newiTempLabel (NULL);
6030 size = AOP_SIZE (result);
6033 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6034 emitLabel (tlbl->key + 100);
6037 l = aopGet (AOP (result), offset--, FALSE);
6040 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6048 emitLabel (tlbl1->key + 100);
6050 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6052 freeAsmop (left, NULL, ic);
6053 freeAsmop (result, NULL, ic);
6057 /*-----------------------------------------------------------------*/
6058 /* genUnpackBits - generates code for unpacking bits */
6059 /*-----------------------------------------------------------------*/
6061 genUnpackBits (operand * result, int pair)
6063 int offset = 0; /* result byte offset */
6064 int rsize; /* result size */
6065 int rlen = 0; /* remaining bitfield length */
6066 sym_link *etype; /* bitfield type information */
6067 int blen; /* bitfield length */
6068 int bstr; /* bitfield starting bit within byte */
6070 emitDebug ("; genUnpackBits");
6072 etype = getSpec (operandType (result));
6073 rsize = getSize (operandType (result));
6074 blen = SPEC_BLEN (etype);
6075 bstr = SPEC_BSTR (etype);
6077 /* If the bitfield length is less than a byte */
6080 emit2 ("ld a,!*pair", _pairs[pair].name);
6082 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6083 aopPut (AOP (result), "a", offset++);
6087 /* TODO: what if pair == PAIR_DE ? */
6088 if (getPairId (AOP (result)) == PAIR_HL)
6090 wassertl (rsize == 2, "HL must be of size 2");
6091 emit2 ("ld a,!*hl");
6093 emit2 ("ld h,!*hl");
6096 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6098 spillPair (PAIR_HL);
6102 /* Bit field did not fit in a byte. Copy all
6103 but the partial byte at the end. */
6104 for (rlen=blen;rlen>=8;rlen-=8)
6106 emit2 ("ld a,!*pair", _pairs[pair].name);
6107 aopPut (AOP (result), "a", offset++);
6110 emit2 ("inc %s", _pairs[pair].name);
6111 _G.pairs[pair].offset++;
6115 /* Handle the partial byte at the end */
6118 emit2 ("ld a,!*pair", _pairs[pair].name);
6119 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6120 aopPut (AOP (result), "a", offset++);
6128 aopPut (AOP (result), "!zero", offset++);
6132 /*-----------------------------------------------------------------*/
6133 /* genGenPointerGet - get value from generic pointer space */
6134 /*-----------------------------------------------------------------*/
6136 genGenPointerGet (operand * left,
6137 operand * result, iCode * ic)
6140 sym_link *retype = getSpec (operandType (result));
6146 aopOp (left, ic, FALSE, FALSE);
6147 aopOp (result, ic, FALSE, FALSE);
6149 size = AOP_SIZE (result);
6151 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6154 if (isPtrPair (AOP (left)))
6156 tsprintf (buffer, sizeof(buffer),
6157 "!*pair", getPairName (AOP (left)));
6158 aopPut (AOP (result), buffer, 0);
6162 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6163 aopPut (AOP (result), "a", 0);
6165 freeAsmop (left, NULL, ic);
6169 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6176 tsprintf (at, sizeof(at), "!*iyx", offset);
6177 aopPut (AOP (result), at, offset);
6181 freeAsmop (left, NULL, ic);
6185 /* For now we always load into IY */
6186 /* if this is remateriazable */
6187 fetchPair (pair, AOP (left));
6189 /* if bit then unpack */
6190 if (IS_BITVAR (retype))
6192 genUnpackBits (result, pair);
6193 freeAsmop (left, NULL, ic);
6197 else if (getPairId (AOP (result)) == PAIR_HL)
6199 wassertl (size == 2, "HL must be of size 2");
6200 emit2 ("ld a,!*hl");
6202 emit2 ("ld h,!*hl");
6204 spillPair (PAIR_HL);
6206 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6208 size = AOP_SIZE (result);
6213 /* PENDING: make this better */
6214 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6216 aopPut (AOP (result), "!*hl", offset++);
6220 emit2 ("ld a,!*pair", _pairs[pair].name);
6221 aopPut (AOP (result), "a", offset++);
6225 emit2 ("inc %s", _pairs[pair].name);
6226 _G.pairs[pair].offset++;
6229 /* Fixup HL back down */
6230 for (size = AOP_SIZE (result)-1; size; size--)
6232 emit2 ("dec %s", _pairs[pair].name);
6237 size = AOP_SIZE (result);
6242 /* PENDING: make this better */
6244 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6246 aopPut (AOP (result), "!*hl", offset++);
6250 emit2 ("ld a,!*pair", _pairs[pair].name);
6251 aopPut (AOP (result), "a", offset++);
6255 emit2 ("inc %s", _pairs[pair].name);
6256 _G.pairs[pair].offset++;
6261 freeAsmop (left, NULL, ic);
6264 freeAsmop (result, NULL, ic);
6267 /*-----------------------------------------------------------------*/
6268 /* genPointerGet - generate code for pointer get */
6269 /*-----------------------------------------------------------------*/
6271 genPointerGet (iCode * ic)
6273 operand *left, *result;
6274 sym_link *type, *etype;
6276 left = IC_LEFT (ic);
6277 result = IC_RESULT (ic);
6279 /* depending on the type of pointer we need to
6280 move it to the correct pointer register */
6281 type = operandType (left);
6282 etype = getSpec (type);
6284 genGenPointerGet (left, result, ic);
6288 isRegOrLit (asmop * aop)
6290 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6296 /*-----------------------------------------------------------------*/
6297 /* genPackBits - generates code for packed bit storage */
6298 /*-----------------------------------------------------------------*/
6300 genPackBits (sym_link * etype,
6305 int offset = 0; /* source byte offset */
6306 int rlen = 0; /* remaining bitfield length */
6307 int blen; /* bitfield length */
6308 int bstr; /* bitfield starting bit within byte */
6309 int litval; /* source literal value (if AOP_LIT) */
6310 unsigned char mask; /* bitmask within current byte */
6311 int extraPair; /* a tempory register */
6312 bool needPopExtra=0; /* need to restore original value of temp reg */
6314 emitDebug ("; genPackBits","");
6316 blen = SPEC_BLEN (etype);
6317 bstr = SPEC_BSTR (etype);
6319 /* If the bitfield length is less than a byte */
6322 mask = ((unsigned char) (0xFF << (blen + bstr)) |
6323 (unsigned char) (0xFF >> (8 - bstr)));
6325 if (AOP_TYPE (right) == AOP_LIT)
6327 /* Case with a bitfield length <8 and literal source
6329 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6331 litval &= (~mask) & 0xff;
6332 emit2 ("ld a,!*pair", _pairs[pair].name);
6333 if ((mask|litval)!=0xff)
6334 emit2 ("and a,!immedbyte", mask);
6336 emit2 ("or a,!immedbyte", litval);
6337 emit2 ("ld !*pair,a", _pairs[pair].name);
6342 /* Case with a bitfield length <8 and arbitrary source
6344 _moveA (aopGet (AOP (right), 0, FALSE));
6345 /* shift and mask source value */
6347 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6349 extraPair = getFreePairId(ic);
6350 if (extraPair == PAIR_INVALID)
6352 extraPair = PAIR_BC;
6353 if (getPairId (AOP (right)) != PAIR_BC
6354 || !isLastUse (ic, right))
6360 emit2 ("ld %s,a", _pairs[extraPair].l);
6361 emit2 ("ld a,!*pair", _pairs[pair].name);
6363 emit2 ("and a,!immedbyte", mask);
6364 emit2 ("or a,%s", _pairs[extraPair].l);
6365 emit2 ("ld !*pair,a", _pairs[pair].name);
6372 /* Bit length is greater than 7 bits. In this case, copy */
6373 /* all except the partial byte at the end */
6374 for (rlen=blen;rlen>=8;rlen-=8)
6376 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
6377 emit2 ("ld !*pair,a", _pairs[pair].name);
6380 emit2 ("inc %s", _pairs[pair].name);
6381 _G.pairs[pair].offset++;
6385 /* If there was a partial byte at the end */
6388 mask = (((unsigned char) -1 << rlen) & 0xff);
6390 if (AOP_TYPE (right) == AOP_LIT)
6392 /* Case with partial byte and literal source
6394 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6395 litval >>= (blen-rlen);
6396 litval &= (~mask) & 0xff;
6397 emit2 ("ld a,!*pair", _pairs[pair].name);
6398 if ((mask|litval)!=0xff)
6399 emit2 ("and a,!immedbyte", mask);
6401 emit2 ("or a,!immedbyte", litval);
6405 /* Case with partial byte and arbitrary source
6407 _moveA (aopGet (AOP (right), offset++, FALSE));
6408 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6410 extraPair = getFreePairId(ic);
6411 if (extraPair == PAIR_INVALID)
6413 extraPair = getPairId (AOP (right));
6414 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
6415 extraPair = PAIR_BC;
6417 if (getPairId (AOP (right)) != PAIR_BC
6418 || !isLastUse (ic, right))
6424 emit2 ("ld %s,a", _pairs[extraPair].l);
6425 emit2 ("ld a,!*pair", _pairs[pair].name);
6427 emit2 ("and a,!immedbyte", mask);
6428 emit2 ("or a,%s", _pairs[extraPair].l);
6433 emit2 ("ld !*pair,a", _pairs[pair].name);
6438 /*-----------------------------------------------------------------*/
6439 /* genGenPointerSet - stores the value into a pointer location */
6440 /*-----------------------------------------------------------------*/
6442 genGenPointerSet (operand * right,
6443 operand * result, iCode * ic)
6446 sym_link *retype = getSpec (operandType (right));
6447 sym_link *letype = getSpec (operandType (result));
6448 PAIR_ID pairId = PAIR_HL;
6451 aopOp (result, ic, FALSE, FALSE);
6452 aopOp (right, ic, FALSE, FALSE);
6457 size = AOP_SIZE (right);
6459 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
6460 emitDebug("; isBitvar = %d", isBitvar);
6462 /* Handle the exceptions first */
6463 if (isPair (AOP (result)) && size == 1 && !isBitvar)
6466 const char *l = aopGet (AOP (right), 0, FALSE);
6467 const char *pair = getPairName (AOP (result));
6468 if (canAssignToPtr (l) && isPtr (pair))
6470 emit2 ("ld !*pair,%s", pair, l);
6475 emit2 ("ld !*pair,a", pair);
6480 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
6483 const char *l = aopGet (AOP (right), 0, FALSE);
6488 if (canAssignToPtr (l))
6490 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6494 _moveA (aopGet (AOP (right), offset, FALSE));
6495 emit2 ("ld !*iyx,a", offset);
6501 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
6508 const char *l = aopGet (AOP (right), offset, FALSE);
6509 if (isRegOrLit (AOP (right)) && !IS_GB)
6511 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
6516 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
6520 emit2 ("inc %s", _pairs[PAIR_HL].name);
6521 _G.pairs[PAIR_HL].offset++;
6526 /* Fixup HL back down */
6527 for (size = AOP_SIZE (right)-1; size; size--)
6529 emit2 ("dec %s", _pairs[PAIR_HL].name);
6534 /* if the operand is already in dptr
6535 then we do nothing else we move the value to dptr */
6536 if (AOP_TYPE (result) != AOP_STR)
6538 fetchPair (pairId, AOP (result));
6540 /* so hl know contains the address */
6541 freeAsmop (result, NULL, ic);
6543 /* if bit then unpack */
6546 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
6556 const char *l = aopGet (AOP (right), offset, FALSE);
6557 if (isRegOrLit (AOP (right)) && !IS_GB)
6559 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
6564 emit2 ("ld !*pair,a", _pairs[pairId].name);
6568 emit2 ("inc %s", _pairs[pairId].name);
6569 _G.pairs[pairId].offset++;
6575 freeAsmop (right, NULL, ic);
6578 /*-----------------------------------------------------------------*/
6579 /* genPointerSet - stores the value into a pointer location */
6580 /*-----------------------------------------------------------------*/
6582 genPointerSet (iCode * ic)
6584 operand *right, *result;
6585 sym_link *type, *etype;
6587 right = IC_RIGHT (ic);
6588 result = IC_RESULT (ic);
6590 /* depending on the type of pointer we need to
6591 move it to the correct pointer register */
6592 type = operandType (result);
6593 etype = getSpec (type);
6595 genGenPointerSet (right, result, ic);
6598 /*-----------------------------------------------------------------*/
6599 /* genIfx - generate code for Ifx statement */
6600 /*-----------------------------------------------------------------*/
6602 genIfx (iCode * ic, iCode * popIc)
6604 operand *cond = IC_COND (ic);
6607 aopOp (cond, ic, FALSE, TRUE);
6609 /* get the value into acc */
6610 if (AOP_TYPE (cond) != AOP_CRY)
6614 /* the result is now in the accumulator */
6615 freeAsmop (cond, NULL, ic);
6617 /* if there was something to be popped then do it */
6621 /* if the condition is a bit variable */
6622 if (isbit && IS_ITEMP (cond) &&
6624 genIfxJump (ic, SPIL_LOC (cond)->rname);
6625 else if (isbit && !IS_ITEMP (cond))
6626 genIfxJump (ic, OP_SYMBOL (cond)->rname);
6628 genIfxJump (ic, "a");
6633 /*-----------------------------------------------------------------*/
6634 /* genAddrOf - generates code for address of */
6635 /*-----------------------------------------------------------------*/
6637 genAddrOf (iCode * ic)
6639 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
6641 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6643 /* if the operand is on the stack then we
6644 need to get the stack offset of this
6651 if (sym->stack <= 0)
6653 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
6657 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6659 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6663 emit2 ("ld de,!hashedstr", sym->rname);
6664 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
6672 /* if it has an offset then we need to compute it */
6674 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6676 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
6677 emit2 ("add hl,sp");
6681 emit2 ("ld hl,!hashedstr", sym->rname);
6683 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6685 freeAsmop (IC_RESULT (ic), NULL, ic);
6688 /*-----------------------------------------------------------------*/
6689 /* genAssign - generate code for assignment */
6690 /*-----------------------------------------------------------------*/
6692 genAssign (iCode * ic)
6694 operand *result, *right;
6696 unsigned long lit = 0L;
6698 result = IC_RESULT (ic);
6699 right = IC_RIGHT (ic);
6701 /* Dont bother assigning if they are the same */
6702 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6704 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
6708 aopOp (right, ic, FALSE, FALSE);
6709 aopOp (result, ic, TRUE, FALSE);
6711 /* if they are the same registers */
6712 if (sameRegs (AOP (right), AOP (result)))
6714 emitDebug ("; (registers are the same)");
6718 /* if the result is a bit */
6719 if (AOP_TYPE (result) == AOP_CRY)
6721 wassertl (0, "Tried to assign to a bit");
6725 size = AOP_SIZE (result);
6728 if (AOP_TYPE (right) == AOP_LIT)
6730 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6733 if (isPair (AOP (result)))
6735 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
6737 else if ((size > 1) &&
6738 (AOP_TYPE (result) != AOP_REG) &&
6739 (AOP_TYPE (right) == AOP_LIT) &&
6740 !IS_FLOAT (operandType (right)) &&
6743 bool fXored = FALSE;
6745 /* Work from the top down.
6746 Done this way so that we can use the cached copy of 0
6747 in A for a fast clear */
6750 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
6752 if (!fXored && size > 1)
6759 aopPut (AOP (result), "a", offset);
6763 aopPut (AOP (result), "!zero", offset);
6767 aopPut (AOP (result),
6768 aopGet (AOP (right), offset, FALSE),
6773 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
6775 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
6776 aopPut (AOP (result), "l", LSB);
6777 aopPut (AOP (result), "h", MSB16);
6779 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6781 /* Special case. Load into a and d, then load out. */
6782 _moveA (aopGet (AOP (right), 0, FALSE));
6783 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
6784 aopPut (AOP (result), "a", 0);
6785 aopPut (AOP (result), "e", 1);
6787 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6789 /* Special case - simple memcpy */
6790 aopGet (AOP (right), LSB, FALSE);
6793 aopGet (AOP (result), LSB, FALSE);
6797 emit2 ("ld a,(de)");
6798 /* Peephole will optimise this. */
6799 emit2 ("ld (hl),a");
6807 spillPair (PAIR_HL);
6813 /* PENDING: do this check better */
6814 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
6816 _moveA (aopGet (AOP (right), offset, FALSE));
6817 aopPut (AOP (result), "a", offset);
6820 aopPut (AOP (result),
6821 aopGet (AOP (right), offset, FALSE),
6828 freeAsmop (right, NULL, ic);
6829 freeAsmop (result, NULL, ic);
6832 /*-----------------------------------------------------------------*/
6833 /* genJumpTab - genrates code for jump table */
6834 /*-----------------------------------------------------------------*/
6836 genJumpTab (iCode * ic)
6841 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
6842 /* get the condition into accumulator */
6843 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
6846 emit2 ("ld e,%s", l);
6847 emit2 ("ld d,!zero");
6848 jtab = newiTempLabel (NULL);
6850 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
6851 emit2 ("add hl,de");
6852 emit2 ("add hl,de");
6853 emit2 ("add hl,de");
6854 freeAsmop (IC_JTCOND (ic), NULL, ic);
6858 emitLabel (jtab->key + 100);
6859 /* now generate the jump labels */
6860 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
6861 jtab = setNextItem (IC_JTLABELS (ic)))
6862 emit2 ("jp !tlabel", jtab->key + 100);
6865 /*-----------------------------------------------------------------*/
6866 /* genCast - gen code for casting */
6867 /*-----------------------------------------------------------------*/
6869 genCast (iCode * ic)
6871 operand *result = IC_RESULT (ic);
6872 sym_link *rtype = operandType (IC_RIGHT (ic));
6873 operand *right = IC_RIGHT (ic);
6876 /* if they are equivalent then do nothing */
6877 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6880 aopOp (right, ic, FALSE, FALSE);
6881 aopOp (result, ic, FALSE, FALSE);
6883 /* if the result is a bit */
6884 if (AOP_TYPE (result) == AOP_CRY)
6886 wassertl (0, "Tried to cast to a bit");
6889 /* if they are the same size : or less */
6890 if (AOP_SIZE (result) <= AOP_SIZE (right))
6893 /* if they are in the same place */
6894 if (sameRegs (AOP (right), AOP (result)))
6897 /* if they in different places then copy */
6898 size = AOP_SIZE (result);
6902 aopPut (AOP (result),
6903 aopGet (AOP (right), offset, FALSE),
6910 /* So we now know that the size of destination is greater
6911 than the size of the source */
6912 /* we move to result for the size of source */
6913 size = AOP_SIZE (right);
6917 aopPut (AOP (result),
6918 aopGet (AOP (right), offset, FALSE),
6923 /* now depending on the sign of the destination */
6924 size = AOP_SIZE (result) - AOP_SIZE (right);
6925 /* Unsigned or not an integral type - right fill with zeros */
6926 if (SPEC_USIGN (rtype) || !IS_SPEC (rtype) || AOP_TYPE(right)==AOP_CRY)
6929 aopPut (AOP (result), "!zero", offset++);
6933 /* we need to extend the sign :{ */
6934 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
6940 aopPut (AOP (result), "a", offset++);
6944 freeAsmop (right, NULL, ic);
6945 freeAsmop (result, NULL, ic);
6948 /*-----------------------------------------------------------------*/
6949 /* genReceive - generate code for a receive iCode */
6950 /*-----------------------------------------------------------------*/
6952 genReceive (iCode * ic)
6954 if (isOperandInFarSpace (IC_RESULT (ic)) &&
6955 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
6956 IS_TRUE_SYMOP (IC_RESULT (ic))))
6966 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6967 size = AOP_SIZE(IC_RESULT(ic));
6969 for (i = 0; i < size; i++) {
6970 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
6974 freeAsmop (IC_RESULT (ic), NULL, ic);
6977 /*-----------------------------------------------------------------*/
6978 /* genDummyRead - generate code for dummy read of volatiles */
6979 /*-----------------------------------------------------------------*/
6981 genDummyRead (iCode * ic)
6983 emit2 ("; genDummyRead not implemented");
6990 /** Maximum number of bytes to emit per line. */
6994 /** Context for the byte output chunker. */
6997 unsigned char buffer[DBEMIT_MAX_RUN];
7002 /** Flushes a byte chunker by writing out all in the buffer and
7006 _dbFlush(DBEMITCTX *self)
7013 sprintf(line, ".db 0x%02X", self->buffer[0]);
7015 for (i = 1; i < self->pos; i++)
7017 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7024 /** Write out another byte, buffering until a decent line is
7028 _dbEmit(DBEMITCTX *self, int c)
7030 if (self->pos == DBEMIT_MAX_RUN)
7034 self->buffer[self->pos++] = c;
7037 /** Context for a simple run length encoder. */
7041 unsigned char buffer[128];
7043 /** runLen may be equivalent to pos. */
7049 RLE_CHANGE_COST = 4,
7053 /** Flush the buffer of a run length encoder by writing out the run or
7054 data that it currently contains.
7057 _rleCommit(RLECTX *self)
7063 memset(&db, 0, sizeof(db));
7065 emit2(".db %u", self->pos);
7067 for (i = 0; i < self->pos; i++)
7069 _dbEmit(&db, self->buffer[i]);
7078 Can get either a run or a block of random stuff.
7079 Only want to change state if a good run comes in or a run ends.
7080 Detecting run end is easy.
7083 Say initial state is in run, len zero, last zero. Then if you get a
7084 few zeros then something else then a short run will be output.
7085 Seems OK. While in run mode, keep counting. While in random mode,
7086 keep a count of the run. If run hits margin, output all up to run,
7087 restart, enter run mode.
7090 /** Add another byte into the run length encoder, flushing as
7091 required. The run length encoder uses the Amiga IFF style, where
7092 a block is prefixed by its run length. A positive length means
7093 the next n bytes pass straight through. A negative length means
7094 that the next byte is repeated -n times. A zero terminates the
7098 _rleAppend(RLECTX *self, int c)
7102 if (c != self->last)
7104 /* The run has stopped. See if it is worthwhile writing it out
7105 as a run. Note that the random data comes in as runs of
7108 if (self->runLen > RLE_CHANGE_COST)
7110 /* Yes, worthwhile. */
7111 /* Commit whatever was in the buffer. */
7113 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7117 /* Not worthwhile. Append to the end of the random list. */
7118 for (i = 0; i < self->runLen; i++)
7120 if (self->pos >= RLE_MAX_BLOCK)
7125 self->buffer[self->pos++] = self->last;
7133 if (self->runLen >= RLE_MAX_BLOCK)
7135 /* Commit whatever was in the buffer. */
7138 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7146 _rleFlush(RLECTX *self)
7148 _rleAppend(self, -1);
7155 /** genArrayInit - Special code for initialising an array with constant
7159 genArrayInit (iCode * ic)
7163 int elementSize = 0, eIndex, i;
7164 unsigned val, lastVal;
7168 memset(&rle, 0, sizeof(rle));
7170 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7172 _saveRegsForCall(ic, 0);
7174 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7175 emit2 ("call __initrleblock");
7177 type = operandType(IC_LEFT(ic));
7179 if (type && type->next)
7181 elementSize = getSize(type->next);
7185 wassertl (0, "Can't determine element size in genArrayInit.");
7188 iLoop = IC_ARRAYILIST(ic);
7189 lastVal = (unsigned)-1;
7191 /* Feed all the bytes into the run length encoder which will handle
7193 This works well for mixed char data, and for random int and long
7202 for (i = 0; i < ix; i++)
7204 for (eIndex = 0; eIndex < elementSize; eIndex++)
7206 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7207 _rleAppend(&rle, val);
7212 iLoop = iLoop->next;
7216 /* Mark the end of the run. */
7219 _restoreRegsAfterCall();
7223 freeAsmop (IC_LEFT(ic), NULL, ic);
7227 _swap (PAIR_ID one, PAIR_ID two)
7229 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7235 emit2 ("ld a,%s", _pairs[one].l);
7236 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7237 emit2 ("ld %s,a", _pairs[two].l);
7238 emit2 ("ld a,%s", _pairs[one].h);
7239 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7240 emit2 ("ld %s,a", _pairs[two].h);
7244 /* The problem is that we may have all three pairs used and they may
7245 be needed in a different order.
7250 hl = hl => unity, fine
7254 hl = hl hl = hl, swap de <=> bc
7262 hl = bc de = de, swap bc <=> hl
7270 hl = de bc = bc, swap hl <=> de
7275 * Any pair = pair are done last
7276 * Any pair = iTemp are done last
7277 * Any swaps can be done any time
7285 So how do we detect the cases?
7286 How about a 3x3 matrix?
7290 x x x x (Fourth for iTemp/other)
7292 First determin which mode to use by counting the number of unity and
7295 Two - Assign the pair first, then the rest
7296 One - Swap the two, then the rest
7300 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7302 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7304 PAIR_BC, PAIR_HL, PAIR_DE
7306 int i, j, nunity = 0;
7307 memset (ids, PAIR_INVALID, sizeof (ids));
7310 wassert (nparams == 3);
7312 /* First save everything that needs to be saved. */
7313 _saveRegsForCall (ic, 0);
7315 /* Loading HL first means that DE is always fine. */
7316 for (i = 0; i < nparams; i++)
7318 aopOp (pparams[i], ic, FALSE, FALSE);
7319 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7322 /* Count the number of unity or iTemp assigns. */
7323 for (i = 0; i < 3; i++)
7325 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7333 /* Any order, fall through. */
7335 else if (nunity == 2)
7337 /* One is assigned. Pull it out and assign. */
7338 for (i = 0; i < 3; i++)
7340 for (j = 0; j < NUM_PAIRS; j++)
7342 if (ids[dest[i]][j] == TRUE)
7344 /* Found it. See if it's the right one. */
7345 if (j == PAIR_INVALID || j == dest[i])
7351 fetchPair(dest[i], AOP (pparams[i]));
7358 else if (nunity == 1)
7360 /* Find the pairs to swap. */
7361 for (i = 0; i < 3; i++)
7363 for (j = 0; j < NUM_PAIRS; j++)
7365 if (ids[dest[i]][j] == TRUE)
7367 if (j == PAIR_INVALID || j == dest[i])
7382 int next = getPairId (AOP (pparams[0]));
7383 emit2 ("push %s", _pairs[next].name);
7385 if (next == dest[1])
7387 fetchPair (dest[1], AOP (pparams[1]));
7388 fetchPair (dest[2], AOP (pparams[2]));
7392 fetchPair (dest[2], AOP (pparams[2]));
7393 fetchPair (dest[1], AOP (pparams[1]));
7395 emit2 ("pop %s", _pairs[dest[0]].name);
7398 /* Finally pull out all of the iTemps */
7399 for (i = 0; i < 3; i++)
7401 if (ids[dest[i]][PAIR_INVALID] == 1)
7403 fetchPair (dest[i], AOP (pparams[i]));
7409 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
7415 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
7419 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7421 setupForBuiltin3 (ic, nParams, pparams);
7423 label = newiTempLabel(NULL);
7425 emitLabel (label->key);
7426 emit2 ("ld a,(hl)");
7429 emit2 ("!shortjp nz,!tlabel ; 1", label->key);
7431 freeAsmop (from, NULL, ic->next);
7432 freeAsmop (to, NULL, ic);
7436 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
7438 operand *from, *to, *count;
7441 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
7446 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7448 setupForBuiltin3 (ic, nParams, pparams);
7452 freeAsmop (count, NULL, ic->next->next);
7453 freeAsmop (from, NULL, ic);
7455 _restoreRegsAfterCall();
7457 /* if we need assign a result value */
7458 if ((IS_ITEMP (IC_RESULT (ic)) &&
7459 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
7460 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
7461 IS_TRUE_SYMOP (IC_RESULT (ic)))
7463 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7464 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
7465 freeAsmop (IC_RESULT (ic), NULL, ic);
7468 freeAsmop (to, NULL, ic->next);
7471 /*-----------------------------------------------------------------*/
7472 /* genBuiltIn - calls the appropriate function to generating code */
7473 /* for a built in function */
7474 /*-----------------------------------------------------------------*/
7475 static void genBuiltIn (iCode *ic)
7477 operand *bi_parms[MAX_BUILTIN_ARGS];
7482 /* get all the arguments for a built in function */
7483 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
7485 /* which function is it */
7486 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
7488 if (strcmp(bif->name,"__builtin_strcpy")==0)
7490 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
7492 else if (strcmp(bif->name,"__builtin_memcpy")==0)
7494 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
7498 wassertl (0, "Unknown builtin function encountered");
7502 /*-----------------------------------------------------------------*/
7503 /* genZ80Code - generate code for Z80 based controllers */
7504 /*-----------------------------------------------------------------*/
7506 genZ80Code (iCode * lic)
7514 _fReturn = _gbz80_return;
7515 _fTmp = _gbz80_return;
7519 _fReturn = _z80_return;
7520 _fTmp = _z80_return;
7523 _G.lines.head = _G.lines.current = NULL;
7525 for (ic = lic; ic; ic = ic->next)
7528 if (cln != ic->lineno)
7530 if (!options.noCcodeInAsm) {
7531 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
7532 printCLine(ic->filename, ic->lineno));
7536 if (options.iCodeInAsm) {
7537 emit2 (";ic:%d: %s", ic->key, printILine(ic));
7539 /* if the result is marked as
7540 spilt and rematerializable or code for
7541 this has already been generated then
7543 if (resultRemat (ic) || ic->generated)
7546 /* depending on the operation */
7550 emitDebug ("; genNot");
7555 emitDebug ("; genCpl");
7560 emitDebug ("; genUminus");
7565 emitDebug ("; genIpush");
7570 /* IPOP happens only when trying to restore a
7571 spilt live range, if there is an ifx statement
7572 following this pop then the if statement might
7573 be using some of the registers being popped which
7574 would destory the contents of the register so
7575 we need to check for this condition and handle it */
7577 ic->next->op == IFX &&
7578 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
7580 emitDebug ("; genIfx");
7581 genIfx (ic->next, ic);
7585 emitDebug ("; genIpop");
7591 emitDebug ("; genCall");
7596 emitDebug ("; genPcall");
7601 emitDebug ("; genFunction");
7606 emitDebug ("; genEndFunction");
7607 genEndFunction (ic);
7611 emitDebug ("; genRet");
7616 emitDebug ("; genLabel");
7621 emitDebug ("; genGoto");
7626 emitDebug ("; genPlus");
7631 emitDebug ("; genMinus");
7636 emitDebug ("; genMult");
7641 emitDebug ("; genDiv");
7646 emitDebug ("; genMod");
7651 emitDebug ("; genCmpGt");
7652 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
7656 emitDebug ("; genCmpLt");
7657 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
7664 /* note these two are xlated by algebraic equivalence
7665 during parsing SDCC.y */
7666 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
7667 "got '>=' or '<=' shouldn't have come here");
7671 emitDebug ("; genCmpEq");
7672 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
7676 emitDebug ("; genAndOp");
7681 emitDebug ("; genOrOp");
7686 emitDebug ("; genXor");
7687 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
7691 emitDebug ("; genOr");
7692 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
7696 emitDebug ("; genAnd");
7697 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
7701 emitDebug ("; genInline");
7706 emitDebug ("; genRRC");
7711 emitDebug ("; genRLC");
7716 emitDebug ("; genGetHBIT");
7721 emitDebug ("; genLeftShift");
7726 emitDebug ("; genRightShift");
7730 case GET_VALUE_AT_ADDRESS:
7731 emitDebug ("; genPointerGet");
7737 if (POINTER_SET (ic))
7739 emitDebug ("; genAssign (pointer)");
7744 emitDebug ("; genAssign");
7750 emitDebug ("; genIfx");
7755 emitDebug ("; genAddrOf");
7760 emitDebug ("; genJumpTab");
7765 emitDebug ("; genCast");
7770 emitDebug ("; genReceive");
7775 if (ic->builtinSEND)
7777 emitDebug ("; genBuiltIn");
7782 emitDebug ("; addSet");
7783 addSet (&_G.sendSet, ic);
7788 emitDebug ("; genArrayInit");
7792 case DUMMY_READ_VOLATILE:
7802 /* now we are ready to call the
7803 peep hole optimizer */
7804 if (!options.nopeep)
7805 peepHole (&_G.lines.head);
7807 /* This is unfortunate */
7808 /* now do the actual printing */
7810 FILE *fp = codeOutFile;
7811 if (isInHome () && codeOutFile == code->oFile)
7812 codeOutFile = home->oFile;
7813 printLine (_G.lines.head, codeOutFile);
7814 if (_G.flushStatics)
7817 _G.flushStatics = 0;
7822 freeTrace(&_G.lines.trace);
7823 freeTrace(&_G.trace.aops);
7829 _isPairUsed (iCode * ic, PAIR_ID pairId)
7835 if (bitVectBitValue (ic->rMask, D_IDX))
7837 if (bitVectBitValue (ic->rMask, E_IDX))
7847 fetchLitSpecial (asmop * aop, bool negate, bool xor)
7850 value *val = aop->aopu.aop_lit;
7852 wassert (aop->type == AOP_LIT);
7853 wassert (!IS_FLOAT (val->type));
7855 v = (unsigned long) floatFromVal (val);
7863 tsprintf (buffer, sizeof(buffer), "!immedword", v);
7864 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));