1 /*-------------------------------------------------------------------------
2 gen.c - Z80 specific code generator.
4 Michael Hope <michaelh@juju.net.nz> 2000
5 Based on the mcs51 generator -
6 Sandeep Dutta . sandeep.dutta@usa.net (1998)
7 and - Jean-Louis VERN.jlvern@writeme.com (1999)
9 This program is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 2, or (at your option) any
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 In other words, you are welcome to use, share and improve this program.
25 You are forbidden to forbid anyone else to use, share and improve
26 what you give them. Help stamp out software-hoarding!
28 -------------------------------------------------------------------------*/
31 Benchmarks on dhry.c 2.1 with 32766 loops and a 10ms clock:
33 Base with asm strcpy / strcmp / memcpy: 23198 141 1A14
34 Improved WORD push 22784 144 19AE
35 With label1 on 22694 144 197E
36 With label2 on 22743 144 198A
37 With label3 on 22776 144 1999
38 With label4 on 22776 144 1999
39 With all 'label' on 22661 144 196F
40 With loopInvariant on 20919 156 19AB
41 With loopInduction on Breaks 198B
42 With all working on 20796 158 196C
43 Slightly better genCmp(signed) 20597 159 195B
44 Better reg packing, first peephole 20038 163 1873
45 With assign packing 19281 165 1849
47 With reg params for mul and div 16234 202 162D
49 1. Starting again at 3 Aug 01 34965 93 219C
51 Includes long mul/div in code
52 2. Optimised memcpy for acc use 32102 102 226B
53 3. Optimised strcpy for acc use 27819 117 2237
54 3a Optimised memcpy fun
55 4. Optimised strcmp fun 21999 149 2294
56 5. Optimised strcmp further 21660 151 228C
57 6. Optimised memcpy by unroling 20885 157 2201
58 7. After turning loop induction on 19862 165 236D
59 8. Same as 7 but with more info
60 9. With asm optimised strings 17030 192 2223
62 10 and below are with asm strings off.
64 10 Mucho optimisations 13562 201 1FCC
66 Apparent advantage of turning on regparams:
68 Decent case is push of a constant
69 - ld hl,#n; push hl: (10+11)*nargs
70 2. Cost of pull from stack
71 Using asm with ld hl, etc
72 - ld hl,#2; add hl,sp; (ld bc,(hl); hl+=2)*nargs
74 3. Cost of fixing stack
78 So cost is (10+11+7+6+7+10)*nargs+10+11
80 = 123 for mul, div, strcmp, strcpy
81 Saving of (98298+32766+32766+32766)*123 = 24181308
82 At 192 d/s for 682411768t, speed up to 199. Hmm.
90 #if defined(__BORLANDC__) || defined(_MSC_VER)
91 #define STRCASECMP stricmp
93 #define STRCASECMP strcasecmp
97 #include "SDCCglobl.h"
98 #include "SDCCpeeph.h"
100 #include "SDCCglue.h"
101 #include "newalloc.h"
103 /* This is the down and dirty file with all kinds of kludgy & hacky
104 stuff. This is what it is all about CODE GENERATION for a specific MCU.
105 Some of the routines may be reusable, will have to see */
107 /* Z80 calling convention description.
108 Parameters are passed right to left. As the stack grows downwards,
109 the parameters are arranged in left to right in memory.
110 Parameters may be passed in the HL and DE registers with one
112 PENDING: What if the parameter is a long?
113 Everything is caller saves. i.e. the caller must save any registers
114 that it wants to preserve over the call.
115 GB: The return value is returned in DEHL. DE is normally used as a
116 working register pair. Caller saves allows it to be used for a
118 va args functions do not use register parameters. All arguments
119 are passed on the stack.
120 IX is used as an index register to the top of the local variable
121 area. ix-0 is the top most local variable.
126 /* Set to enable debugging trace statements in the output assembly code. */
130 static char *_z80_return[] =
131 {"l", "h", "e", "d"};
132 static char *_gbz80_return[] =
133 {"e", "d", "l", "h"};
134 static char *_fReceive[] =
135 { "c", "b", "e", "d" };
137 static char **_fReturn;
140 extern FILE *codeOutFile;
148 /** Enum covering all the possible register pairs.
167 } _pairs[NUM_PAIRS] = {
168 { "??1", "?2", "?3" },
173 { "iy", "iyl", "iyh" },
174 { "ix", "ixl", "ixh" }
178 #define ACC_NAME _pairs[PAIR_AF].h
188 /** Code generator persistent data.
192 /** Used to optimised setting up of a pair by remebering what it
193 contains and adjusting instead of reloading where possible.
222 const char *lastFunctionName;
228 /** TRUE if the registers have already been saved. */
246 static const char *aopGet (asmop * aop, int offset, bool bit16);
248 static const char *aopNames[] = {
268 isLastUse (iCode *ic, operand *op)
270 bitVect *uses = bitVectCopy (OP_USES (op));
272 while (!bitVectIsZero (uses))
274 if (bitVectFirstBit (uses) == ic->key)
276 if (bitVectnBitsOn (uses) == 1)
285 bitVectUnSetBit (uses, bitVectFirstBit (uses));
305 _getTempPairName(void)
307 return _pairs[_getTempPairId()].name;
311 isPairInUse (PAIR_ID id, iCode *ic)
315 return bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
317 else if (id == PAIR_BC)
319 return bitVectBitValue (ic->rMask, B_IDX) || bitVectBitValue(ic->rMask, C_IDX);
323 wassertl (0, "Only implemented for DE and BC");
329 isPairInUseNotInRet(PAIR_ID id, iCode *ic)
333 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
337 return bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
341 wassertl (0, "Only implemented for DE");
347 getFreePairId (iCode *ic)
349 if (!isPairInUse (PAIR_BC, ic))
353 else if (IS_Z80 && !isPairInUse (PAIR_DE, ic))
366 /* Clean up the line so that it is 'prettier' */
367 if (strchr (buf, ':'))
369 /* Is a label - cant do anything */
372 /* Change the first (and probably only) ' ' to a tab so
387 _newLineNode (char *line)
391 pl = traceAlloc(&_G.lines.trace, Safe_alloc ( sizeof (lineNode)));
392 pl->line = traceAlloc(&_G.lines.trace, Safe_strdup (line));
398 _vemit2 (const char *szFormat, va_list ap)
402 tvsprintf (buffer, sizeof(buffer), szFormat, ap);
405 _G.lines.current = (_G.lines.current ?
406 connectLine (_G.lines.current, _newLineNode (buffer)) :
407 (_G.lines.head = _newLineNode (buffer)));
409 _G.lines.current->isInline = _G.lines.isInline;
413 emit2 (const char *szFormat,...)
417 va_start (ap, szFormat);
419 _vemit2 (szFormat, ap);
425 emitDebug (const char *szFormat,...)
431 va_start (ap, szFormat);
433 _vemit2 (szFormat, ap);
439 /*-----------------------------------------------------------------*/
440 /* emit2 - writes the code into a file : for now it is simple */
441 /*-----------------------------------------------------------------*/
443 _emit2 (const char *inst, const char *fmt,...)
446 char lb[INITIAL_INLINEASM];
453 sprintf (lb, "%s\t", inst);
454 vsprintf (lb + (strlen (lb)), fmt, ap);
457 vsprintf (lb, fmt, ap);
459 while (isspace (*lbp))
464 _G.lines.current = (_G.lines.current ?
465 connectLine (_G.lines.current, _newLineNode (lb)) :
466 (_G.lines.head = _newLineNode (lb)));
468 _G.lines.current->isInline = _G.lines.isInline;
473 _emitMove(const char *to, const char *from)
475 if (STRCASECMP(to, from) != 0)
477 emit2("ld %s,%s", to, from);
482 // Could leave this to the peephole, but sometimes the peephole is inhibited.
487 aopDump(const char *plabel, asmop *aop)
489 emitDebug("; Dump of %s: type %s size %u", plabel, aopNames[aop->type], aop->size);
493 emitDebug("; aop_stk %d", aop->aopu.aop_stk);
496 /* No information. */
502 _moveA(const char *moveFrom)
504 // Let the peephole optimiser take care of redundent loads
505 _emitMove(ACC_NAME, moveFrom);
515 getPairName (asmop * aop)
517 if (aop->type == AOP_REG)
519 switch (aop->aopu.aop_reg[0]->rIdx)
532 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
535 for (i = 0; i < NUM_PAIRS; i++)
537 if (strcmp(aop->aopu.aop_str[0], _pairs[i].l) == 0)
539 return _pairs[i].name;
543 wassertl (0, "Tried to get the pair name of something that isn't a pair");
548 getPairId (asmop * aop)
552 if (aop->type == AOP_REG)
554 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX) && (aop->aopu.aop_reg[1]->rIdx == B_IDX))
558 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX) && (aop->aopu.aop_reg[1]->rIdx == D_IDX))
562 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX) && (aop->aopu.aop_reg[1]->rIdx == H_IDX))
567 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
570 for (i = 0; i < NUM_PAIRS; i++)
572 if (!strcmp (aop->aopu.aop_str[0], _pairs[i].l) && !strcmp (aop->aopu.aop_str[1], _pairs[i].h))
582 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
586 return (getPairId (aop) != PAIR_INVALID);
589 /** Returns TRUE if the registers used in aop cannot be split into high
592 isUnsplitable (asmop * aop)
594 switch (getPairId (aop))
606 isPtrPair (asmop * aop)
608 PAIR_ID pairId = getPairId (aop);
621 spillPair (PAIR_ID pairId)
623 _G.pairs[pairId].last_type = AOP_INVALID;
624 _G.pairs[pairId].base = NULL;
627 /* Given a register name, spill the pair (if any) the register is part of */
629 spillPairReg (const char *regname)
631 if (strlen(regname)==1)
651 /** Push a register pair onto the stack */
653 genPairPush (asmop * aop)
655 emit2 ("push %s", getPairName (aop));
659 _push (PAIR_ID pairId)
661 emit2 ("push %s", _pairs[pairId].name);
662 _G.stack.pushed += 2;
666 _pop (PAIR_ID pairId)
668 emit2 ("pop %s", _pairs[pairId].name);
669 _G.stack.pushed -= 2;
673 /*-----------------------------------------------------------------*/
674 /* newAsmop - creates a new asmOp */
675 /*-----------------------------------------------------------------*/
677 newAsmop (short type)
681 aop = traceAlloc(&_G.trace.aops, Safe_alloc (sizeof (asmop)));
686 /*-----------------------------------------------------------------*/
687 /* aopForSym - for a true symbol */
688 /*-----------------------------------------------------------------*/
690 aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
697 wassert (sym->etype);
699 space = SPEC_OCLS (sym->etype);
701 /* if already has one */
707 /* Assign depending on the storage class */
708 if (sym->onStack || sym->iaccess)
710 /* The pointer that is used depends on how big the offset is.
711 Normally everything is AOP_STK, but for offsets of < -128 or
712 > 127 on the Z80 an extended stack pointer is used.
714 if (IS_Z80 && (_G.omitFramePtr || sym->stack < INT8MIN || sym->stack > (int)(INT8MAX-getSize (sym->type))))
716 emitDebug ("; AOP_EXSTK for %s", sym->rname);
717 sym->aop = aop = newAsmop (AOP_EXSTK);
721 emitDebug ("; AOP_STK for %s", sym->rname);
722 sym->aop = aop = newAsmop (AOP_STK);
725 aop->size = getSize (sym->type);
726 aop->aopu.aop_stk = sym->stack;
730 /* special case for a function */
731 if (IS_FUNC (sym->type))
733 sym->aop = aop = newAsmop (AOP_IMMD);
734 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup (sym->rname));
741 /* if it is in direct space */
742 if (IN_REGSP (space) && !requires_a)
744 sym->aop = aop = newAsmop (AOP_SFR);
745 aop->aopu.aop_dir = sym->rname;
746 aop->size = getSize (sym->type);
747 emitDebug ("; AOP_SFR for %s", sym->rname);
752 /* only remaining is far space */
753 /* in which case DPTR gets the address */
756 emitDebug ("; AOP_HL for %s", sym->rname);
757 sym->aop = aop = newAsmop (AOP_HL);
761 sym->aop = aop = newAsmop (AOP_IY);
763 aop->size = getSize (sym->type);
764 aop->aopu.aop_dir = sym->rname;
766 /* if it is in code space */
767 if (IN_CODESPACE (space))
773 /*-----------------------------------------------------------------*/
774 /* aopForRemat - rematerialzes an object */
775 /*-----------------------------------------------------------------*/
777 aopForRemat (symbol * sym)
780 iCode *ic = sym->rematiCode;
781 asmop *aop = newAsmop (AOP_IMMD);
785 /* if plus or minus print the right hand side */
786 if (ic->op == '+' || ic->op == '-')
788 /* PENDING: for re-target */
789 sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
792 ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
795 /* we reached the end */
796 sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
800 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
804 /*-----------------------------------------------------------------*/
805 /* regsInCommon - two operands have some registers in common */
806 /*-----------------------------------------------------------------*/
808 regsInCommon (operand * op1, operand * op2)
813 /* if they have registers in common */
814 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
817 sym1 = OP_SYMBOL (op1);
818 sym2 = OP_SYMBOL (op2);
820 if (sym1->nRegs == 0 || sym2->nRegs == 0)
823 for (i = 0; i < sym1->nRegs; i++)
829 for (j = 0; j < sym2->nRegs; j++)
834 if (sym2->regs[j] == sym1->regs[i])
842 /*-----------------------------------------------------------------*/
843 /* operandsEqu - equivalent */
844 /*-----------------------------------------------------------------*/
846 operandsEqu (operand * op1, operand * op2)
850 /* if they not symbols */
851 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
854 sym1 = OP_SYMBOL (op1);
855 sym2 = OP_SYMBOL (op2);
857 /* if both are itemps & one is spilt
858 and the other is not then false */
859 if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
860 sym1->isspilt != sym2->isspilt)
863 /* if they are the same */
867 if (strcmp (sym1->rname, sym2->rname) == 0)
871 /* if left is a tmp & right is not */
872 if (IS_ITEMP (op1) &&
875 (sym1->usl.spillLoc == sym2))
878 if (IS_ITEMP (op2) &&
882 (sym2->usl.spillLoc == sym1))
888 /*-----------------------------------------------------------------*/
889 /* sameRegs - two asmops have the same registers */
890 /*-----------------------------------------------------------------*/
892 sameRegs (asmop * aop1, asmop * aop2)
896 if (aop1->type == AOP_SFR ||
897 aop2->type == AOP_SFR)
903 if (aop1->type != AOP_REG ||
904 aop2->type != AOP_REG)
907 if (aop1->size != aop2->size)
910 for (i = 0; i < aop1->size; i++)
911 if (aop1->aopu.aop_reg[i] !=
912 aop2->aopu.aop_reg[i])
918 /*-----------------------------------------------------------------*/
919 /* aopOp - allocates an asmop for an operand : */
920 /*-----------------------------------------------------------------*/
922 aopOp (operand * op, iCode * ic, bool result, bool requires_a)
931 /* if this a literal */
932 if (IS_OP_LITERAL (op))
934 op->aop = aop = newAsmop (AOP_LIT);
935 aop->aopu.aop_lit = op->operand.valOperand;
936 aop->size = getSize (operandType (op));
940 /* if already has a asmop then continue */
946 /* if the underlying symbol has a aop */
947 if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
949 op->aop = OP_SYMBOL (op)->aop;
953 /* if this is a true symbol */
954 if (IS_TRUE_SYMOP (op))
956 op->aop = aopForSym (ic, OP_SYMBOL (op), result, requires_a);
960 /* this is a temporary : this has
966 e) can be a return use only */
968 sym = OP_SYMBOL (op);
970 /* if the type is a conditional */
971 if (sym->regType == REG_CND)
973 aop = op->aop = sym->aop = newAsmop (AOP_CRY);
978 /* if it is spilt then two situations
980 b) has a spill location */
981 if (sym->isspilt || sym->nRegs == 0)
983 /* rematerialize it NOW */
986 sym->aop = op->aop = aop =
988 aop->size = getSize (sym->type);
995 aop = op->aop = sym->aop = newAsmop (AOP_STR);
996 aop->size = getSize (sym->type);
997 for (i = 0; i < 4; i++)
998 aop->aopu.aop_str[i] = _fReturn[i];
1004 if (sym->accuse == ACCUSE_A)
1006 aop = op->aop = sym->aop = newAsmop (AOP_ACC);
1007 aop->size = getSize (sym->type);
1008 wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
1010 aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
1012 else if (sym->accuse == ACCUSE_SCRATCH)
1014 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
1015 aop->size = getSize (sym->type);
1016 wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
1017 aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
1018 aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
1020 else if (sym->accuse == ACCUSE_IY)
1022 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
1023 aop->size = getSize (sym->type);
1024 wassertl(aop->size <= 2, "Internal error: Caching in IY, but too big to fit in IY");
1025 aop->aopu.aop_str[0] = _pairs[PAIR_IY].l;
1026 aop->aopu.aop_str[1] = _pairs[PAIR_IY].h;
1030 wassertl (0, "Marked as being allocated into A or HL but is actually in neither");
1035 /* else spill location */
1036 if (sym->usl.spillLoc && getSize(sym->type) != getSize(sym->usl.spillLoc->type)) {
1037 /* force a new aop if sizes differ */
1038 sym->usl.spillLoc->aop = NULL;
1040 sym->aop = op->aop = aop =
1041 aopForSym (ic, sym->usl.spillLoc, result, requires_a);
1042 wassertl (aop->size >= getSize (sym->type), "Operand doesn't fit in the spill location");
1043 aop->size = getSize (sym->type);
1047 /* must be in a register */
1048 sym->aop = op->aop = aop = newAsmop (AOP_REG);
1049 aop->size = sym->nRegs;
1050 for (i = 0; i < sym->nRegs; i++)
1051 aop->aopu.aop_reg[i] = sym->regs[i];
1054 /*-----------------------------------------------------------------*/
1055 /* freeAsmop - free up the asmop given to an operand */
1056 /*----------------------------------------------------------------*/
1058 freeAsmop (operand * op, asmop * aaop, iCode * ic)
1075 if (aop->type == AOP_PAIRPTR && IS_Z80 && aop->aopu.aop_pairId == PAIR_DE)
1077 _pop (aop->aopu.aop_pairId);
1080 if (getPairId (aop) == PAIR_HL)
1082 spillPair (PAIR_HL);
1086 /* all other cases just dealloc */
1092 OP_SYMBOL (op)->aop = NULL;
1093 /* if the symbol has a spill */
1095 SPIL_LOC (op)->aop = NULL;
1102 isLitWord (asmop * aop)
1104 /* if (aop->size != 2)
1117 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
1119 /* depending on type */
1125 /* PENDING: for re-target */
1128 tsprintf (buffer, sizeof(buffer),
1129 "!hashedstr + %d", aop->aopu.aop_immd, offset);
1131 else if (offset == 0)
1133 tsprintf (buffer, sizeof(buffer),
1134 "%s", aop->aopu.aop_immd);
1138 tsprintf (buffer, sizeof(buffer),
1139 "%s + %d", aop->aopu.aop_immd, offset);
1141 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1145 value *val = aop->aopu.aop_lit;
1146 /* if it is a float then it gets tricky */
1147 /* otherwise it is fairly simple */
1148 if (!IS_FLOAT (val->type))
1150 unsigned long v = (unsigned long) floatFromVal (val);
1156 else if (offset == 0)
1162 wassertl(0, "Encountered an invalid offset while fetching a literal");
1166 tsprintf (buffer, sizeof(buffer), "!immedword", v);
1168 tsprintf (buffer, sizeof(buffer), "!constword", v);
1170 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1181 /* it is type float */
1182 fl.f = (float) floatFromVal (val);
1184 #ifdef WORDS_BIGENDIAN
1185 i = fl.c[3-offset] | (fl.c[3-offset-1]<<8);
1187 i = fl.c[offset] | (fl.c[offset+1]<<8);
1190 tsprintf (buffer, sizeof(buffer), "!immedword", i);
1192 tsprintf (buffer, sizeof(buffer), "!constword", i);
1194 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1203 aopGetWord (asmop * aop, int offset)
1205 return aopGetLitWordLong (aop, offset, TRUE);
1209 isPtr (const char *s)
1211 if (!strcmp (s, "hl"))
1213 if (!strcmp (s, "ix"))
1215 if (!strcmp (s, "iy"))
1221 adjustPair (const char *pair, int *pold, int new)
1227 emit2 ("inc %s", pair);
1232 emit2 ("dec %s", pair);
1240 spillPair (PAIR_HL);
1241 spillPair (PAIR_IY);
1245 requiresHL (asmop * aop)
1261 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1263 const char *l, *base;
1264 const char *pair = _pairs[pairId].name;
1265 l = aopGetLitWordLong (left, offset, FALSE);
1266 base = aopGetLitWordLong (left, 0, FALSE);
1267 wassert (l && pair && base);
1271 if (pairId == PAIR_HL || pairId == PAIR_IY)
1273 if (_G.pairs[pairId].last_type == left->type)
1275 if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1277 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1279 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1282 if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
1289 _G.pairs[pairId].last_type = left->type;
1290 _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1291 _G.pairs[pairId].offset = offset;
1293 /* Both a lit on the right and a true symbol on the left */
1294 emit2 ("ld %s,!hashedstr", pair, l);
1298 makeFreePairId (iCode *ic, bool *pisUsed)
1304 if (!bitVectBitValue (ic->rMask, B_IDX) && !bitVectBitValue(ic->rMask, C_IDX))
1308 else if (IS_Z80 && !bitVectBitValue (ic->rMask, D_IDX) && !bitVectBitValue(ic->rMask, E_IDX))
1326 fetchPairLong (PAIR_ID pairId, asmop * aop, iCode *ic, int offset)
1328 /* if this is remateriazable */
1329 if (isLitWord (aop)) {
1330 fetchLitPair (pairId, aop, offset);
1334 if (getPairId (aop) == pairId)
1338 /* we need to get it byte by byte */
1339 else if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1340 aopGet (aop, offset, FALSE);
1341 switch (aop->size - offset) {
1343 emit2 ("ld l,!*hl");
1344 emit2 ("ld h,!immedbyte", 0);
1347 // PENDING: Requires that you are only fetching two bytes.
1350 emit2 ("ld h,!*hl");
1354 wassertl (0, "Attempted to fetch too much data into HL");
1358 else if (IS_Z80 && aop->type == AOP_IY) {
1359 /* Instead of fetching relative to IY, just grab directly
1360 from the address IY refers to */
1361 char *l = aopGetLitWordLong (aop, offset, FALSE);
1363 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1365 if (aop->size < 2) {
1366 emit2("ld %s,!zero", _pairs[pairId].h);
1369 else if (pairId == PAIR_IY)
1373 emit2 ("push %s", _pairs[getPairId(aop)].name);
1379 PAIR_ID id = makeFreePairId (ic, &isUsed);
1382 /* Can't load into parts, so load into HL then exchange. */
1383 emit2 ("ld %s,%s", _pairs[id].l, aopGet (aop, offset, FALSE));
1384 emit2 ("ld %s,%s", _pairs[id].h, aopGet (aop, offset + 1, FALSE));
1385 emit2 ("push %s", _pairs[id].name);
1391 else if (isUnsplitable(aop))
1393 emit2("push %s", _pairs[getPairId(aop)].name);
1394 emit2("pop %s", _pairs[pairId].name);
1398 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1399 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1401 /* PENDING: check? */
1402 if (pairId == PAIR_HL)
1403 spillPair (PAIR_HL);
1408 fetchPair (PAIR_ID pairId, asmop * aop)
1410 fetchPairLong (pairId, aop, NULL, 0);
1414 fetchHL (asmop * aop)
1416 fetchPair (PAIR_HL, aop);
1420 setupPairFromSP (PAIR_ID id, int offset)
1422 wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
1424 if (offset < INT8MIN || offset > INT8MAX)
1426 emit2 ("ld hl,!immedword", offset);
1427 emit2 ("add hl,sp");
1431 emit2 ("!ldahlsp", offset);
1436 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1441 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
1442 fetchLitPair (pairId, aop, 0);
1446 wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
1448 fetchLitPair (pairId, aop, offset);
1449 _G.pairs[pairId].offset = offset;
1453 wassertl (IS_Z80, "Only the Z80 has an extended stack");
1454 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
1457 int offset = aop->aopu.aop_stk + _G.stack.offset;
1459 if (_G.pairs[pairId].last_type == aop->type &&
1460 _G.pairs[pairId].offset == offset)
1466 /* PENDING: Do this better. */
1467 sprintf (buffer, "%d", offset + _G.stack.pushed);
1468 emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
1469 emit2 ("add %s,sp", _pairs[pairId].name);
1470 _G.pairs[pairId].last_type = aop->type;
1471 _G.pairs[pairId].offset = offset;
1478 /* Doesnt include _G.stack.pushed */
1479 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1481 if (aop->aopu.aop_stk > 0)
1483 abso += _G.stack.param_offset;
1485 assert (pairId == PAIR_HL);
1486 /* In some cases we can still inc or dec hl */
1487 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1489 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1493 setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
1495 _G.pairs[pairId].offset = abso;
1500 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
1506 _G.pairs[pairId].last_type = aop->type;
1512 emit2 ("!tlabeldef", key);
1516 /*-----------------------------------------------------------------*/
1517 /* aopGet - for fetching value of the aop */
1518 /*-----------------------------------------------------------------*/
1520 aopGet (asmop * aop, int offset, bool bit16)
1522 // char *s = buffer;
1524 /* offset is greater than size then zero */
1525 /* PENDING: this seems a bit screwed in some pointer cases. */
1526 if (offset > (aop->size - 1) &&
1527 aop->type != AOP_LIT)
1529 tsprintf (buffer, sizeof(buffer), "!zero");
1530 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1533 /* depending on type */
1537 /* PENDING: re-target */
1539 tsprintf (buffer, sizeof(buffer), "!immedwords", aop->aopu.aop_immd);
1544 tsprintf (buffer, sizeof(buffer), "!bankimmeds", aop->aopu.aop_immd);
1547 tsprintf (buffer, sizeof(buffer), "!msbimmeds", aop->aopu.aop_immd);
1550 tsprintf (buffer, sizeof(buffer), "!lsbimmeds", aop->aopu.aop_immd);
1553 wassertl (0, "Fetching from beyond the limits of an immediate value.");
1556 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1560 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1561 SNPRINTF (buffer, sizeof(buffer), "a");
1563 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1567 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1568 SNPRINTF (buffer, sizeof(buffer), "a");
1570 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1573 return aop->aopu.aop_reg[offset]->name;
1577 setupPair (PAIR_HL, aop, offset);
1578 tsprintf (buffer, sizeof(buffer), "!*hl");
1580 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
1584 setupPair (PAIR_IY, aop, offset);
1585 tsprintf (buffer, sizeof(buffer), "!*iyx", offset);
1587 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1591 setupPair (PAIR_IY, aop, offset);
1592 tsprintf (buffer, sizeof(buffer), "!*iyx", offset, offset);
1594 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1599 setupPair (PAIR_HL, aop, offset);
1600 tsprintf (buffer, sizeof(buffer), "!*hl");
1604 if (aop->aopu.aop_stk >= 0)
1605 offset += _G.stack.param_offset;
1606 tsprintf (buffer, sizeof(buffer),
1607 "!*ixx", aop->aopu.aop_stk + offset);
1610 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1613 wassertl (0, "Tried to fetch from a bit variable");
1622 tsprintf(buffer, sizeof(buffer), "!zero");
1623 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1627 wassert (offset < 2);
1628 return aop->aopu.aop_str[offset];
1631 return aopLiteral (aop->aopu.aop_lit, offset);
1635 unsigned long v = aop->aopu.aop_simplelit;
1638 tsprintf (buffer, sizeof(buffer),
1639 "!immedbyte", (unsigned int) v & 0xff);
1641 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1645 return aop->aopu.aop_str[offset];
1648 setupPair (aop->aopu.aop_pairId, aop, offset);
1649 SNPRINTF (buffer, sizeof(buffer),
1650 "(%s)", _pairs[aop->aopu.aop_pairId].name);
1652 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1657 wassertl (0, "aopget got unsupported aop->type");
1662 isRegString (const char *s)
1664 if (!strcmp (s, "b") ||
1676 isConstant (const char *s)
1678 /* This is a bit of a hack... */
1679 return (*s == '#' || *s == '$');
1683 canAssignToPtr (const char *s)
1685 if (isRegString (s))
1692 /*-----------------------------------------------------------------*/
1693 /* aopPut - puts a string for a aop */
1694 /*-----------------------------------------------------------------*/
1696 aopPut (asmop * aop, const char *s, int offset)
1700 if (aop->size && offset > (aop->size - 1))
1702 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1703 "aopPut got offset > aop->size");
1708 tsprintf(buffer2, sizeof(buffer2), s);
1711 /* will assign value to value */
1712 /* depending on where it is ofcourse */
1718 if (strcmp (s, "a"))
1719 emit2 ("ld a,%s", s);
1720 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1725 if (strcmp (s, "a"))
1726 emit2 ("ld a,%s", s);
1727 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1731 if (!strcmp (s, "!*hl"))
1732 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1735 aop->aopu.aop_reg[offset]->name, s);
1736 spillPairReg(aop->aopu.aop_reg[offset]->name);
1741 if (!canAssignToPtr (s))
1743 emit2 ("ld a,%s", s);
1744 setupPair (PAIR_IY, aop, offset);
1745 emit2 ("ld !*iyx,a", offset);
1749 setupPair (PAIR_IY, aop, offset);
1750 emit2 ("ld !*iyx,%s", offset, s);
1756 /* PENDING: for re-target */
1757 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1759 emit2 ("ld a,!*hl");
1762 setupPair (PAIR_HL, aop, offset);
1764 emit2 ("ld !*hl,%s", s);
1769 if (!canAssignToPtr (s))
1771 emit2 ("ld a,%s", s);
1772 setupPair (PAIR_IY, aop, offset);
1773 emit2 ("ld !*iyx,a", offset);
1777 setupPair (PAIR_IY, aop, offset);
1778 emit2 ("ld !*iyx,%s", offset, s);
1785 /* PENDING: re-target */
1786 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1788 emit2 ("ld a,!*hl");
1791 setupPair (PAIR_HL, aop, offset);
1792 if (!canAssignToPtr (s))
1794 emit2 ("ld a,%s", s);
1795 emit2 ("ld !*hl,a");
1798 emit2 ("ld !*hl,%s", s);
1802 if (aop->aopu.aop_stk >= 0)
1803 offset += _G.stack.param_offset;
1804 if (!canAssignToPtr (s))
1806 emit2 ("ld a,%s", s);
1807 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
1811 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
1817 /* if bit variable */
1818 if (!aop->aopu.aop_dir)
1820 emit2 ("ld a,!zero");
1825 /* In bit space but not in C - cant happen */
1826 wassertl (0, "Tried to write into a bit variable");
1832 if (strcmp (aop->aopu.aop_str[offset], s))
1834 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1836 spillPairReg(aop->aopu.aop_str[offset]);
1841 if (!offset && (strcmp (s, "acc") == 0))
1845 wassertl (0, "Tried to access past the end of A");
1849 if (strcmp (aop->aopu.aop_str[offset], s))
1851 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1852 spillPairReg(aop->aopu.aop_str[offset]);
1858 wassert (offset < 2);
1859 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1860 spillPairReg(aop->aopu.aop_str[offset]);
1864 setupPair (aop->aopu.aop_pairId, aop, offset);
1865 emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
1869 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1870 "aopPut got unsupported aop->type");
1875 #define AOP(op) op->aop
1876 #define AOP_TYPE(op) AOP(op)->type
1877 #define AOP_SIZE(op) AOP(op)->size
1878 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
1881 commitPair (asmop * aop, PAIR_ID id)
1883 /* PENDING: Verify this. */
1884 if (id == PAIR_HL && requiresHL (aop) && IS_GB)
1888 aopPut (aop, "a", 0);
1889 aopPut (aop, "d", 1);
1894 if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
1896 char *l = aopGetLitWordLong (aop, 0, FALSE);
1899 emit2 ("ld (%s),%s", l, _pairs[id].name);
1903 aopPut (aop, _pairs[id].l, 0);
1904 aopPut (aop, _pairs[id].h, 1);
1909 /*-----------------------------------------------------------------*/
1910 /* getDataSize - get the operand data size */
1911 /*-----------------------------------------------------------------*/
1913 getDataSize (operand * op)
1916 size = AOP_SIZE (op);
1920 wassertl (0, "Somehow got a three byte data pointer");
1925 /*-----------------------------------------------------------------*/
1926 /* movLeft2Result - move byte from left to result */
1927 /*-----------------------------------------------------------------*/
1929 movLeft2Result (operand * left, int offl,
1930 operand * result, int offr, int sign)
1934 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
1936 l = aopGet (AOP (left), offl, FALSE);
1940 aopPut (AOP (result), l, offr);
1944 if (getDataSize (left) == offl + 1)
1946 emit2 ("ld a,%s", l);
1947 aopPut (AOP (result), "a", offr);
1954 movLeft2ResultLong (operand * left, int offl,
1955 operand * result, int offr, int sign,
1960 movLeft2Result (left, offl, result, offr, sign);
1964 wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
1965 wassertl (size == 2, "Only implemented for two bytes or one");
1967 if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
1969 emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
1970 emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
1972 spillPair (PAIR_HL);
1974 else if ( getPairId ( AOP (result)) == PAIR_IY)
1976 PAIR_ID id = getPairId (AOP (left));
1977 if (id != PAIR_INVALID)
1979 emit2("push %s", _pairs[id].name);
1990 movLeft2Result (left, offl, result, offr, sign);
1991 movLeft2Result (left, offl+1, result, offr+1, sign);
1996 /** Put Acc into a register set
1999 outAcc (operand * result)
2002 size = getDataSize (result);
2005 aopPut (AOP (result), "a", 0);
2008 /* unsigned or positive */
2011 aopPut (AOP (result), "!zero", offset++);
2016 /** Take the value in carry and put it into a register
2019 outBitCLong (operand * result, bool swap_sense)
2021 /* if the result is bit */
2022 if (AOP_TYPE (result) == AOP_CRY)
2024 wassertl (0, "Tried to write carry to a bit");
2028 emit2 ("ld a,!zero");
2031 emit2 ("xor a,!immedbyte", 1);
2037 outBitC (operand * result)
2039 outBitCLong (result, FALSE);
2042 /*-----------------------------------------------------------------*/
2043 /* toBoolean - emit code for orl a,operator(sizeop) */
2044 /*-----------------------------------------------------------------*/
2046 _toBoolean (operand * oper)
2048 int size = AOP_SIZE (oper);
2052 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
2055 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
2059 if (AOP (oper)->type != AOP_ACC)
2062 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
2068 /*-----------------------------------------------------------------*/
2069 /* genNot - generate code for ! operation */
2070 /*-----------------------------------------------------------------*/
2075 /* assign asmOps to operand & result */
2076 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
2077 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2079 /* if in bit space then a special case */
2080 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2082 wassertl (0, "Tried to negate a bit");
2085 _toBoolean (IC_LEFT (ic));
2090 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
2091 emit2 ("sub a,!one");
2092 outBitC (IC_RESULT (ic));
2094 /* release the aops */
2095 freeAsmop (IC_LEFT (ic), NULL, ic);
2096 freeAsmop (IC_RESULT (ic), NULL, ic);
2099 /*-----------------------------------------------------------------*/
2100 /* genCpl - generate code for complement */
2101 /*-----------------------------------------------------------------*/
2109 /* assign asmOps to operand & result */
2110 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2111 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2113 /* if both are in bit space then
2115 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2116 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2118 wassertl (0, "Left and the result are in bit space");
2121 size = AOP_SIZE (IC_RESULT (ic));
2124 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2127 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2130 /* release the aops */
2131 freeAsmop (IC_LEFT (ic), NULL, ic);
2132 freeAsmop (IC_RESULT (ic), NULL, ic);
2136 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
2143 store de into result
2148 store de into result
2150 const char *first = isAdd ? "add" : "sub";
2151 const char *later = isAdd ? "adc" : "sbc";
2153 wassertl (IS_GB, "Code is only relevent to the gbz80");
2154 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
2156 fetchPair (PAIR_DE, left);
2159 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
2162 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2165 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2166 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2168 fetchPairLong (PAIR_DE, left, NULL, MSB24);
2169 aopGet (right, MSB24, FALSE);
2173 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2176 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2178 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2179 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2183 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2185 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2188 /*-----------------------------------------------------------------*/
2189 /* genUminusFloat - unary minus for floating points */
2190 /*-----------------------------------------------------------------*/
2192 genUminusFloat (operand * op, operand * result)
2194 int size, offset = 0;
2196 emitDebug("; genUminusFloat");
2198 /* for this we just need to flip the
2199 first it then copy the rest in place */
2200 size = AOP_SIZE (op) - 1;
2202 _moveA(aopGet (AOP (op), MSB32, FALSE));
2204 emit2("xor a,!immedbyte", 0x80);
2205 aopPut (AOP (result), "a", MSB32);
2209 aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2214 /*-----------------------------------------------------------------*/
2215 /* genUminus - unary minus code generation */
2216 /*-----------------------------------------------------------------*/
2218 genUminus (iCode * ic)
2221 sym_link *optype, *rtype;
2224 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2225 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2227 /* if both in bit space then special
2229 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2230 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2232 wassertl (0, "Left and right are in bit space");
2236 optype = operandType (IC_LEFT (ic));
2237 rtype = operandType (IC_RESULT (ic));
2239 /* if float then do float stuff */
2240 if (IS_FLOAT (optype))
2242 genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2246 /* otherwise subtract from zero */
2247 size = AOP_SIZE (IC_LEFT (ic));
2249 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2251 /* Create a new asmop with value zero */
2252 asmop *azero = newAsmop (AOP_SIMPLELIT);
2253 azero->aopu.aop_simplelit = 0;
2255 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2263 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2264 emit2 ("ld a,!zero");
2265 emit2 ("sbc a,%s", l);
2266 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2269 /* if any remaining bytes in the result */
2270 /* we just need to propagate the sign */
2271 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2276 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2280 /* release the aops */
2281 freeAsmop (IC_LEFT (ic), NULL, ic);
2282 freeAsmop (IC_RESULT (ic), NULL, ic);
2285 /*-----------------------------------------------------------------*/
2286 /* assignResultValue - */
2287 /*-----------------------------------------------------------------*/
2289 assignResultValue (operand * oper)
2291 int size = AOP_SIZE (oper);
2294 wassertl (size <= 4, "Got a result that is bigger than four bytes");
2295 topInA = requiresHL (AOP (oper));
2297 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2299 /* We do it the hard way here. */
2301 aopPut (AOP (oper), _fReturn[0], 0);
2302 aopPut (AOP (oper), _fReturn[1], 1);
2304 aopPut (AOP (oper), _fReturn[0], 2);
2305 aopPut (AOP (oper), _fReturn[1], 3);
2311 aopPut (AOP (oper), _fReturn[size], size);
2316 /** Simple restore that doesn't take into account what is used in the
2320 _restoreRegsAfterCall(void)
2322 if (_G.stack.pushedDE)
2325 _G.stack.pushedDE = FALSE;
2327 if (_G.stack.pushedBC)
2330 _G.stack.pushedBC = FALSE;
2332 _G.saves.saved = FALSE;
2336 _saveRegsForCall(iCode *ic, int sendSetSize)
2339 o Stack parameters are pushed before this function enters
2340 o DE and BC may be used in this function.
2341 o HL and DE may be used to return the result.
2342 o HL and DE may be used to send variables.
2343 o DE and BC may be used to store the result value.
2344 o HL may be used in computing the sent value of DE
2345 o The iPushes for other parameters occur before any addSets
2347 Logic: (to be run inside the first iPush or if none, before sending)
2348 o Compute if DE and/or BC are in use over the call
2349 o Compute if DE is used in the send set
2350 o Compute if DE and/or BC are used to hold the result value
2351 o If (DE is used, or in the send set) and is not used in the result, push.
2352 o If BC is used and is not in the result, push
2354 o If DE is used in the send set, fetch
2355 o If HL is used in the send set, fetch
2359 if (_G.saves.saved == FALSE) {
2360 bool deInUse, bcInUse;
2362 bool bcInRet = FALSE, deInRet = FALSE;
2365 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
2367 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2368 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2370 deSending = (sendSetSize > 1);
2372 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2374 if (bcInUse && bcInRet == FALSE) {
2376 _G.stack.pushedBC = TRUE;
2378 if (deInUse && deInRet == FALSE) {
2380 _G.stack.pushedDE = TRUE;
2383 _G.saves.saved = TRUE;
2386 /* Already saved. */
2390 /*-----------------------------------------------------------------*/
2391 /* genIpush - genrate code for pushing this gets a little complex */
2392 /*-----------------------------------------------------------------*/
2394 genIpush (iCode * ic)
2396 int size, offset = 0;
2399 /* if this is not a parm push : ie. it is spill push
2400 and spill push is always done on the local stack */
2403 wassertl(0, "Encountered an unsupported spill push.");
2407 if (_G.saves.saved == FALSE) {
2408 /* Caller saves, and this is the first iPush. */
2409 /* Scan ahead until we find the function that we are pushing parameters to.
2410 Count the number of addSets on the way to figure out what registers
2411 are used in the send set.
2414 iCode *walk = ic->next;
2417 if (walk->op == SEND) {
2420 else if (walk->op == CALL || walk->op == PCALL) {
2429 _saveRegsForCall(walk, nAddSets);
2432 /* Already saved by another iPush. */
2435 /* then do the push */
2436 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2438 size = AOP_SIZE (IC_LEFT (ic));
2440 if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2442 _G.stack.pushed += 2;
2443 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2449 fetchHL (AOP (IC_LEFT (ic)));
2451 spillPair (PAIR_HL);
2452 _G.stack.pushed += 2;
2457 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
2459 spillPair (PAIR_HL);
2460 _G.stack.pushed += 2;
2461 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
2463 spillPair (PAIR_HL);
2464 _G.stack.pushed += 2;
2470 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2472 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2474 emit2 ("ld a,(%s)", l);
2478 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2479 emit2 ("ld a,%s", l);
2487 freeAsmop (IC_LEFT (ic), NULL, ic);
2490 /*-----------------------------------------------------------------*/
2491 /* genIpop - recover the registers: can happen only for spilling */
2492 /*-----------------------------------------------------------------*/
2494 genIpop (iCode * ic)
2499 /* if the temp was not pushed then */
2500 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2503 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2504 size = AOP_SIZE (IC_LEFT (ic));
2505 offset = (size - 1);
2506 if (isPair (AOP (IC_LEFT (ic))))
2508 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2516 spillPair (PAIR_HL);
2517 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2521 freeAsmop (IC_LEFT (ic), NULL, ic);
2524 /* This is quite unfortunate */
2526 setArea (int inHome)
2529 static int lastArea = 0;
2531 if (_G.in_home != inHome) {
2533 const char *sz = port->mem.code_name;
2534 port->mem.code_name = "HOME";
2535 emit2("!area", CODE_NAME);
2536 port->mem.code_name = sz;
2539 emit2("!area", CODE_NAME); */
2540 _G.in_home = inHome;
2551 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2555 symbol *sym = OP_SYMBOL (op);
2557 if (sym->isspilt || sym->nRegs == 0)
2560 aopOp (op, ic, FALSE, FALSE);
2563 if (aop->type == AOP_REG)
2566 for (i = 0; i < aop->size; i++)
2568 if (pairId == PAIR_DE)
2570 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2571 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2573 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2576 else if (pairId == PAIR_BC)
2578 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2579 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2581 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2591 freeAsmop (IC_LEFT (ic), NULL, ic);
2595 /** Emit the code for a call statement
2598 emitCall (iCode * ic, bool ispcall)
2600 sym_link *dtype = operandType (IC_LEFT (ic));
2602 /* if caller saves & we have not saved then */
2608 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2610 /* if send set is not empty then assign */
2615 int nSend = elementsInSet(_G.sendSet);
2616 bool swapped = FALSE;
2618 int _z80_sendOrder[] = {
2623 /* Check if the parameters are swapped. If so route through hl instead. */
2624 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2626 sic = setFirstItem(_G.sendSet);
2627 sic = setNextItem(_G.sendSet);
2629 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2630 /* The second send value is loaded from one the one that holds the first
2631 send, i.e. it is overwritten. */
2632 /* Cache the first in HL, and load the second from HL instead. */
2633 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2634 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2640 for (sic = setFirstItem (_G.sendSet); sic;
2641 sic = setNextItem (_G.sendSet))
2644 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2646 size = AOP_SIZE (IC_LEFT (sic));
2647 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2648 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2650 // PENDING: Mild hack
2651 if (swapped == TRUE && send == 1) {
2653 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2656 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2658 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2661 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2665 freeAsmop (IC_LEFT (sic), NULL, sic);
2672 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2674 werror (W_INDIR_BANKED);
2676 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2678 if (isLitWord (AOP (IC_LEFT (ic))))
2680 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2684 symbol *rlbl = newiTempLabel (NULL);
2685 spillPair (PAIR_HL);
2686 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2688 _G.stack.pushed += 2;
2690 fetchHL (AOP (IC_LEFT (ic)));
2692 emit2 ("!tlabeldef", (rlbl->key + 100));
2693 _G.stack.pushed -= 2;
2695 freeAsmop (IC_LEFT (ic), NULL, ic);
2699 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2700 OP_SYMBOL (IC_LEFT (ic))->rname :
2701 OP_SYMBOL (IC_LEFT (ic))->name;
2702 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2704 emit2 ("call banked_call");
2705 emit2 ("!dws", name);
2706 emit2 ("!dw !bankimmeds", name);
2711 emit2 ("call %s", name);
2716 /* Mark the regsiters as restored. */
2717 _G.saves.saved = FALSE;
2719 /* if we need assign a result value */
2720 if ((IS_ITEMP (IC_RESULT (ic)) &&
2721 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2722 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2723 IS_TRUE_SYMOP (IC_RESULT (ic)))
2726 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2728 assignResultValue (IC_RESULT (ic));
2730 freeAsmop (IC_RESULT (ic), NULL, ic);
2733 /* adjust the stack for parameters if required */
2736 int i = ic->parmBytes;
2738 _G.stack.pushed -= i;
2741 emit2 ("!ldaspsp", i);
2748 emit2 ("ld iy,!immedword", i);
2749 emit2 ("add iy,sp");
2769 if (_G.stack.pushedDE)
2771 bool dInRet = bitVectBitValue(ic->rUsed, D_IDX);
2772 bool eInRet = bitVectBitValue(ic->rUsed, E_IDX);
2774 if (dInRet && eInRet)
2776 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
2780 /* Only restore E */
2787 /* Only restore D */
2795 _G.stack.pushedDE = FALSE;
2798 if (_G.stack.pushedBC)
2800 bool bInRet = bitVectBitValue(ic->rUsed, B_IDX);
2801 bool cInRet = bitVectBitValue(ic->rUsed, C_IDX);
2803 if (bInRet && cInRet)
2805 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
2809 /* Only restore C */
2816 /* Only restore B */
2824 _G.stack.pushedBC = FALSE;
2828 /*-----------------------------------------------------------------*/
2829 /* genCall - generates a call statement */
2830 /*-----------------------------------------------------------------*/
2832 genCall (iCode * ic)
2834 emitCall (ic, FALSE);
2837 /*-----------------------------------------------------------------*/
2838 /* genPcall - generates a call by pointer statement */
2839 /*-----------------------------------------------------------------*/
2841 genPcall (iCode * ic)
2843 emitCall (ic, TRUE);
2846 /*-----------------------------------------------------------------*/
2847 /* resultRemat - result is rematerializable */
2848 /*-----------------------------------------------------------------*/
2850 resultRemat (iCode * ic)
2852 if (SKIP_IC (ic) || ic->op == IFX)
2855 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2857 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2858 if (sym->remat && !POINTER_SET (ic))
2865 extern set *publics;
2867 /*-----------------------------------------------------------------*/
2868 /* genFunction - generated code for function entry */
2869 /*-----------------------------------------------------------------*/
2871 genFunction (iCode * ic)
2875 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2878 bool bcInUse = FALSE;
2879 bool deInUse = FALSE;
2881 setArea (IFFUNC_NONBANKED (sym->type));
2883 /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
2886 _G.receiveOffset = 0;
2888 /* Record the last function name for debugging. */
2889 _G.lastFunctionName = sym->rname;
2891 /* Create the function header */
2892 emit2 ("!functionheader", sym->name);
2893 sprintf (buffer, "%s_start", sym->rname);
2894 emit2 ("!labeldef", buffer);
2895 emit2 ("!functionlabeldef", sym->rname);
2897 if (options.profile)
2899 emit2 ("!profileenter");
2902 ftype = operandType (IC_LEFT (ic));
2904 /* if critical function then turn interrupts off */
2905 if (IFFUNC_ISCRITICAL (ftype))
2908 /* if this is an interrupt service routine then save all potentially used registers. */
2909 if (IFFUNC_ISISR (sym->type))
2914 /* PENDING: callee-save etc */
2916 _G.stack.param_offset = 0;
2918 if (z80_opts.calleeSavesBC)
2923 /* Detect which registers are used. */
2924 if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
2927 for (i = 0; i < sym->regsUsed->size; i++)
2929 if (bitVectBitValue (sym->regsUsed, i))
2943 /* Other systems use DE as a temporary. */
2954 _G.stack.param_offset += 2;
2957 _G.calleeSaves.pushedBC = bcInUse;
2962 _G.stack.param_offset += 2;
2965 _G.calleeSaves.pushedDE = deInUse;
2967 /* adjust the stack for the function */
2968 _G.stack.last = sym->stack;
2971 for (sym = setFirstItem (istack->syms); sym;
2972 sym = setNextItem (istack->syms))
2974 if (sym->_isparm && !IS_REGPARM (sym->etype))
2980 sym = OP_SYMBOL (IC_LEFT (ic));
2982 _G.omitFramePtr = options.ommitFramePtr;
2983 if (IS_Z80 && !stackParm && !sym->stack)
2985 /* When the conflicts between AOP_EXSTK && AOP_HLREG are fixed, */
2986 /* the above !sym->stack condition can be removed. -- EEP */
2988 emit2 ("!ldaspsp", -sym->stack);
2989 _G.omitFramePtr = TRUE;
2991 else if (sym->stack && IS_GB && sym->stack > -INT8MIN)
2992 emit2 ("!enterxl", sym->stack);
2993 else if (sym->stack)
2994 emit2 ("!enterx", sym->stack);
2997 _G.stack.offset = sym->stack;
3000 /*-----------------------------------------------------------------*/
3001 /* genEndFunction - generates epilogue for functions */
3002 /*-----------------------------------------------------------------*/
3004 genEndFunction (iCode * ic)
3006 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3008 if (IFFUNC_ISISR (sym->type))
3010 wassertl (0, "Tried to close an interrupt support function");
3014 if (IFFUNC_ISCRITICAL (sym->type))
3017 /* PENDING: calleeSave */
3019 if (IS_Z80 && _G.omitFramePtr)
3021 if (_G.stack.offset)
3022 emit2 ("!ldaspsp", _G.stack.offset);
3024 else if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
3026 emit2 ("!leavexl", _G.stack.offset);
3028 else if (_G.stack.offset)
3030 emit2 ("!leavex", _G.stack.offset);
3037 if (_G.calleeSaves.pushedDE)
3040 _G.calleeSaves.pushedDE = FALSE;
3043 if (_G.calleeSaves.pushedBC)
3046 _G.calleeSaves.pushedBC = FALSE;
3049 if (options.profile)
3051 emit2 ("!profileexit");
3055 /* Both baned and non-banked just ret */
3058 sprintf (buffer, "%s_end", sym->rname);
3059 emit2 ("!labeldef", buffer);
3061 _G.flushStatics = 1;
3062 _G.stack.pushed = 0;
3063 _G.stack.offset = 0;
3066 /*-----------------------------------------------------------------*/
3067 /* genRet - generate code for return statement */
3068 /*-----------------------------------------------------------------*/
3073 /* Errk. This is a hack until I can figure out how
3074 to cause dehl to spill on a call */
3075 int size, offset = 0;
3077 /* if we have no return value then
3078 just generate the "ret" */
3082 /* we have something to return then
3083 move the return value into place */
3084 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3085 size = AOP_SIZE (IC_LEFT (ic));
3087 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3091 emit2 ("ld de,%s", l);
3095 emit2 ("ld hl,%s", l);
3100 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3102 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3103 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3109 l = aopGet (AOP (IC_LEFT (ic)), offset,
3111 if (strcmp (_fReturn[offset], l))
3112 emit2 ("ld %s,%s", _fReturn[offset++], l);
3116 freeAsmop (IC_LEFT (ic), NULL, ic);
3119 /* generate a jump to the return label
3120 if the next is not the return statement */
3121 if (!(ic->next && ic->next->op == LABEL &&
3122 IC_LABEL (ic->next) == returnLabel))
3124 emit2 ("jp !tlabel", returnLabel->key + 100);
3127 /*-----------------------------------------------------------------*/
3128 /* genLabel - generates a label */
3129 /*-----------------------------------------------------------------*/
3131 genLabel (iCode * ic)
3133 /* special case never generate */
3134 if (IC_LABEL (ic) == entryLabel)
3137 emitLabel (IC_LABEL (ic)->key + 100);
3140 /*-----------------------------------------------------------------*/
3141 /* genGoto - generates a ljmp */
3142 /*-----------------------------------------------------------------*/
3144 genGoto (iCode * ic)
3146 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3149 /*-----------------------------------------------------------------*/
3150 /* genPlusIncr :- does addition with increment if possible */
3151 /*-----------------------------------------------------------------*/
3153 genPlusIncr (iCode * ic)
3155 unsigned int icount;
3156 unsigned int size = getDataSize (IC_RESULT (ic));
3157 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3159 /* will try to generate an increment */
3160 /* if the right side is not a literal
3162 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3165 emitDebug ("; genPlusIncr");
3167 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3169 /* If result is a pair */
3170 if (resultId != PAIR_INVALID)
3172 if (isLitWord (AOP (IC_LEFT (ic))))
3174 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3177 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3179 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3181 PAIR_ID freep = getFreePairId (ic);
3182 if (freep != PAIR_INVALID)
3184 fetchPair (freep, AOP (IC_RIGHT (ic)));
3185 emit2 ("add hl,%s", _pairs[freep].name);
3191 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3192 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3199 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3203 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3207 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3212 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3214 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3215 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3219 /* if the literal value of the right hand side
3220 is greater than 4 then it is not worth it */
3224 /* if increment 16 bits in register */
3225 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3231 symbol *tlbl = NULL;
3232 tlbl = newiTempLabel (NULL);
3235 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3238 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3241 emitLabel (tlbl->key + 100);
3245 /* if the sizes are greater than 1 then we cannot */
3246 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3247 AOP_SIZE (IC_LEFT (ic)) > 1)
3250 /* If the result is in a register then we can load then increment.
3252 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3254 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3257 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3262 /* we can if the aops of the left & result match or
3263 if they are in registers and the registers are the
3265 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3269 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3277 /*-----------------------------------------------------------------*/
3278 /* outBitAcc - output a bit in acc */
3279 /*-----------------------------------------------------------------*/
3281 outBitAcc (operand * result)
3283 symbol *tlbl = newiTempLabel (NULL);
3284 /* if the result is a bit */
3285 if (AOP_TYPE (result) == AOP_CRY)
3287 wassertl (0, "Tried to write A into a bit");
3291 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3292 emit2 ("ld a,!one");
3293 emitLabel (tlbl->key + 100);
3299 couldDestroyCarry (asmop *aop)
3303 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3312 shiftIntoPair (int idx, asmop *aop)
3314 PAIR_ID id = PAIR_INVALID;
3316 wassertl (IS_Z80, "Only implemented for the Z80");
3317 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3329 wassertl (0, "Internal error - hit default case");
3332 emitDebug ("; Shift into pair idx %u", idx);
3336 setupPair (PAIR_HL, aop, 0);
3340 setupPair (PAIR_IY, aop, 0);
3342 emit2 ("pop %s", _pairs[id].name);
3345 aop->type = AOP_PAIRPTR;
3346 aop->aopu.aop_pairId = id;
3347 _G.pairs[id].offset = 0;
3348 _G.pairs[id].last_type = aop->type;
3352 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
3354 wassert (left && right);
3358 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3360 shiftIntoPair (0, right);
3361 shiftIntoPair (1, result);
3363 else if (couldDestroyCarry (right))
3365 shiftIntoPair (0, right);
3367 else if (couldDestroyCarry (result))
3369 shiftIntoPair (0, result);
3378 /*-----------------------------------------------------------------*/
3379 /* genPlus - generates code for addition */
3380 /*-----------------------------------------------------------------*/
3382 genPlus (iCode * ic)
3384 int size, offset = 0;
3386 /* special cases :- */
3388 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3389 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3390 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3392 /* Swap the left and right operands if:
3394 if literal, literal on the right or
3395 if left requires ACC or right is already
3398 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3399 (AOP_NEEDSACC (IC_LEFT (ic))) ||
3400 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3402 operand *t = IC_RIGHT (ic);
3403 IC_RIGHT (ic) = IC_LEFT (ic);
3407 /* if both left & right are in bit
3409 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3410 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3413 wassertl (0, "Tried to add two bits");
3416 /* if left in bit space & right literal */
3417 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3418 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3420 /* Can happen I guess */
3421 wassertl (0, "Tried to add a bit to a literal");
3424 /* if I can do an increment instead
3425 of add then GOOD for ME */
3426 if (genPlusIncr (ic) == TRUE)
3429 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3431 size = getDataSize (IC_RESULT (ic));
3433 /* Special case when left and right are constant */
3434 if (isPair (AOP (IC_RESULT (ic))))
3437 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3438 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3440 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3446 sprintf (buffer, "#(%s + %s)", left, right);
3447 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3452 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3454 /* Fetch into HL then do the add */
3455 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3456 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3458 spillPair (PAIR_HL);
3460 if (left == PAIR_HL && right != PAIR_INVALID)
3462 emit2 ("add hl,%s", _pairs[right].name);
3465 else if (right == PAIR_HL && left != PAIR_INVALID)
3467 emit2 ("add hl,%s", _pairs[left].name);
3470 else if (right != PAIR_INVALID && right != PAIR_HL)
3472 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3473 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3476 else if (left != PAIR_INVALID && left != PAIR_HL)
3478 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3479 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3488 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3490 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3491 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3493 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3498 ld hl,sp+n trashes C so we cant afford to do it during an
3499 add with stack based varibles. Worst case is:
3512 So you cant afford to load up hl if either left, right, or result
3513 is on the stack (*sigh*) The alt is:
3521 Combinations in here are:
3522 * If left or right are in bc then the loss is small - trap later
3523 * If the result is in bc then the loss is also small
3527 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3528 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3529 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3531 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3532 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3533 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3534 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3536 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3538 /* Swap left and right */
3539 operand *t = IC_RIGHT (ic);
3540 IC_RIGHT (ic) = IC_LEFT (ic);
3543 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3545 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3546 emit2 ("add hl,bc");
3550 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3551 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3552 emit2 ("add hl,de");
3554 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3560 /* Be paranoid on the GB with 4 byte variables due to how C
3561 can be trashed by lda hl,n(sp).
3563 _gbz80_emitAddSubLong (ic, TRUE);
3568 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3572 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3574 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3577 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3580 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3584 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3587 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3590 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3592 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3596 freeAsmop (IC_LEFT (ic), NULL, ic);
3597 freeAsmop (IC_RIGHT (ic), NULL, ic);
3598 freeAsmop (IC_RESULT (ic), NULL, ic);
3602 /*-----------------------------------------------------------------*/
3603 /* genMinusDec :- does subtraction with deccrement if possible */
3604 /*-----------------------------------------------------------------*/
3606 genMinusDec (iCode * ic)
3608 unsigned int icount;
3609 unsigned int size = getDataSize (IC_RESULT (ic));
3611 /* will try to generate an increment */
3612 /* if the right side is not a literal we cannot */
3613 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3616 /* if the literal value of the right hand side
3617 is greater than 4 then it is not worth it */
3618 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3621 size = getDataSize (IC_RESULT (ic));
3623 /* if decrement 16 bits in register */
3624 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3625 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3628 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3632 /* If result is a pair */
3633 if (isPair (AOP (IC_RESULT (ic))))
3635 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3637 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3641 /* if increment 16 bits in register */
3642 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3646 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3649 emit2 ("dec %s", _getTempPairName());
3652 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3658 /* if the sizes are greater than 1 then we cannot */
3659 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3660 AOP_SIZE (IC_LEFT (ic)) > 1)
3663 /* we can if the aops of the left & result match or if they are in
3664 registers and the registers are the same */
3665 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3668 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3675 /*-----------------------------------------------------------------*/
3676 /* genMinus - generates code for subtraction */
3677 /*-----------------------------------------------------------------*/
3679 genMinus (iCode * ic)
3681 int size, offset = 0;
3682 unsigned long lit = 0L;
3684 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3685 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3686 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3688 /* special cases :- */
3689 /* if both left & right are in bit space */
3690 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3691 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3693 wassertl (0, "Tried to subtract two bits");
3697 /* if I can do an decrement instead of subtract then GOOD for ME */
3698 if (genMinusDec (ic) == TRUE)
3701 size = getDataSize (IC_RESULT (ic));
3703 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3708 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3712 /* Same logic as genPlus */
3715 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3716 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3717 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3719 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3720 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3721 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3722 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3724 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3725 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3727 if (left == PAIR_INVALID && right == PAIR_INVALID)
3732 else if (right == PAIR_INVALID)
3734 else if (left == PAIR_INVALID)
3737 fetchPair (left, AOP (IC_LEFT (ic)));
3738 /* Order is important. Right may be HL */
3739 fetchPair (right, AOP (IC_RIGHT (ic)));
3741 emit2 ("ld a,%s", _pairs[left].l);
3742 emit2 ("sub a,%s", _pairs[right].l);
3744 emit2 ("ld a,%s", _pairs[left].h);
3745 emit2 ("sbc a,%s", _pairs[right].h);
3747 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
3749 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3751 aopPut (AOP (IC_RESULT (ic)), "e", 0);
3757 /* Be paranoid on the GB with 4 byte variables due to how C
3758 can be trashed by lda hl,n(sp).
3760 _gbz80_emitAddSubLong (ic, FALSE);
3765 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3767 /* if literal, add a,#-lit, else normal subb */
3770 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3771 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3775 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3778 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3782 /* first add without previous c */
3784 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
3786 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3788 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3791 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3792 AOP_SIZE (IC_LEFT (ic)) == 3 &&
3793 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3795 wassertl (0, "Tried to subtract on a long pointer");
3799 freeAsmop (IC_LEFT (ic), NULL, ic);
3800 freeAsmop (IC_RIGHT (ic), NULL, ic);
3801 freeAsmop (IC_RESULT (ic), NULL, ic);
3804 /*-----------------------------------------------------------------*/
3805 /* genMult - generates code for multiplication */
3806 /*-----------------------------------------------------------------*/
3808 genMult (iCode * ic)
3812 /* If true then the final operation should be a subtract */
3813 bool active = FALSE;
3815 /* Shouldn't occur - all done through function calls */
3816 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3817 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3818 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3820 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
3821 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
3822 AOP_SIZE (IC_RESULT (ic)) > 2)
3824 wassertl (0, "Multiplication is handled through support function calls");
3827 /* Swap left and right such that right is a literal */
3828 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
3830 operand *t = IC_RIGHT (ic);
3831 IC_RIGHT (ic) = IC_LEFT (ic);
3835 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
3837 val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
3838 // wassertl (val > 0, "Multiply must be positive");
3839 wassertl (val != 1, "Can't multiply by 1");
3841 if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
3843 _G.stack.pushedDE = TRUE;
3846 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
3848 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
3856 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3861 /* Fully unroled version of mul.s. Not the most efficient.
3863 for (count = 0; count < 16; count++)
3865 if (count != 0 && active)
3867 emit2 ("add hl,hl");
3871 if (active == FALSE)
3878 emit2 ("add hl,de");
3887 if (IS_Z80 && _G.stack.pushedDE)
3890 _G.stack.pushedDE = FALSE;
3893 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3895 freeAsmop (IC_LEFT (ic), NULL, ic);
3896 freeAsmop (IC_RIGHT (ic), NULL, ic);
3897 freeAsmop (IC_RESULT (ic), NULL, ic);
3900 /*-----------------------------------------------------------------*/
3901 /* genDiv - generates code for division */
3902 /*-----------------------------------------------------------------*/
3906 /* Shouldn't occur - all done through function calls */
3907 wassertl (0, "Division is handled through support function calls");
3910 /*-----------------------------------------------------------------*/
3911 /* genMod - generates code for division */
3912 /*-----------------------------------------------------------------*/
3916 /* Shouldn't occur - all done through function calls */
3920 /*-----------------------------------------------------------------*/
3921 /* genIfxJump :- will create a jump depending on the ifx */
3922 /*-----------------------------------------------------------------*/
3924 genIfxJump (iCode * ic, char *jval)
3929 /* if true label then we jump if condition
3933 jlbl = IC_TRUE (ic);
3934 if (!strcmp (jval, "a"))
3938 else if (!strcmp (jval, "c"))
3942 else if (!strcmp (jval, "nc"))
3946 else if (!strcmp (jval, "m"))
3950 else if (!strcmp (jval, "p"))
3956 /* The buffer contains the bit on A that we should test */
3962 /* false label is present */
3963 jlbl = IC_FALSE (ic);
3964 if (!strcmp (jval, "a"))
3968 else if (!strcmp (jval, "c"))
3972 else if (!strcmp (jval, "nc"))
3976 else if (!strcmp (jval, "m"))
3980 else if (!strcmp (jval, "p"))
3986 /* The buffer contains the bit on A that we should test */
3990 /* Z80 can do a conditional long jump */
3991 if (!strcmp (jval, "a"))
3995 else if (!strcmp (jval, "c"))
3998 else if (!strcmp (jval, "nc"))
4001 else if (!strcmp (jval, "m"))
4004 else if (!strcmp (jval, "p"))
4009 emit2 ("bit %s,a", jval);
4011 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
4013 /* mark the icode as generated */
4019 _getPairIdName (PAIR_ID id)
4021 return _pairs[id].name;
4026 /* if unsigned char cmp with lit, just compare */
4028 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4030 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4033 emit2 ("xor a,!immedbyte", 0x80);
4034 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4037 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4039 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4041 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4042 // Pull left into DE and right into HL
4043 aopGet (AOP(left), LSB, FALSE);
4046 aopGet (AOP(right), LSB, FALSE);
4050 if (size == 0 && sign)
4052 // Highest byte when signed needs the bits flipped
4055 emit2 ("ld a,(de)");
4056 emit2 ("xor !immedbyte", 0x80);
4058 emit2 ("ld a,(hl)");
4059 emit2 ("xor !immedbyte", 0x80);
4063 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4067 emit2 ("ld a,(de)");
4068 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4078 spillPair (PAIR_HL);
4080 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4082 setupPair (PAIR_HL, AOP (left), 0);
4083 aopGet (AOP(right), LSB, FALSE);
4087 if (size == 0 && sign)
4089 // Highest byte when signed needs the bits flipped
4092 emit2 ("ld a,(hl)");
4093 emit2 ("xor !immedbyte", 0x80);
4095 emit2 ("ld a,%d(iy)", offset);
4096 emit2 ("xor !immedbyte", 0x80);
4100 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4104 emit2 ("ld a,(hl)");
4105 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4114 spillPair (PAIR_HL);
4115 spillPair (PAIR_IY);
4119 if (AOP_TYPE (right) == AOP_LIT)
4121 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4122 /* optimize if(x < 0) or if(x >= 0) */
4127 /* No sign so it's always false */
4132 /* Just load in the top most bit */
4133 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4134 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4136 genIfxJump (ifx, "7");
4148 /* First setup h and l contaning the top most bytes XORed */
4149 bool fDidXor = FALSE;
4150 if (AOP_TYPE (left) == AOP_LIT)
4152 unsigned long lit = (unsigned long)
4153 floatFromVal (AOP (left)->aopu.aop_lit);
4154 emit2 ("ld %s,!immedbyte", _fTmp[0],
4155 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4159 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4160 emit2 ("xor a,!immedbyte", 0x80);
4161 emit2 ("ld %s,a", _fTmp[0]);
4164 if (AOP_TYPE (right) == AOP_LIT)
4166 unsigned long lit = (unsigned long)
4167 floatFromVal (AOP (right)->aopu.aop_lit);
4168 emit2 ("ld %s,!immedbyte", _fTmp[1],
4169 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4173 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4174 emit2 ("xor a,!immedbyte", 0x80);
4175 emit2 ("ld %s,a", _fTmp[1]);
4181 /* Do a long subtract */
4184 _moveA (aopGet (AOP (left), offset, FALSE));
4186 if (sign && size == 0)
4188 emit2 ("ld a,%s", _fTmp[0]);
4189 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4193 /* Subtract through, propagating the carry */
4194 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4202 /** Generic compare for > or <
4205 genCmp (operand * left, operand * right,
4206 operand * result, iCode * ifx, int sign)
4208 int size, offset = 0;
4209 unsigned long lit = 0L;
4210 bool swap_sense = FALSE;
4212 /* if left & right are bit variables */
4213 if (AOP_TYPE (left) == AOP_CRY &&
4214 AOP_TYPE (right) == AOP_CRY)
4216 /* Cant happen on the Z80 */
4217 wassertl (0, "Tried to compare two bits");
4221 /* Do a long subtract of right from left. */
4222 size = max (AOP_SIZE (left), AOP_SIZE (right));
4224 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4226 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4227 // Pull left into DE and right into HL
4228 aopGet (AOP(left), LSB, FALSE);
4231 aopGet (AOP(right), LSB, FALSE);
4235 emit2 ("ld a,(de)");
4236 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4245 spillPair (PAIR_HL);
4249 if (AOP_TYPE (right) == AOP_LIT)
4251 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4252 /* optimize if(x < 0) or if(x >= 0) */
4257 /* No sign so it's always false */
4262 /* Just load in the top most bit */
4263 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4264 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4266 genIfxJump (ifx, "7");
4277 genIfxJump (ifx, swap_sense ? "c" : "nc");
4288 _moveA (aopGet (AOP (left), offset, FALSE));
4289 /* Subtract through, propagating the carry */
4290 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4296 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4300 /* Shift the sign bit up into carry */
4303 outBitCLong (result, swap_sense);
4307 /* if the result is used in the next
4308 ifx conditional branch then generate
4309 code a little differently */
4317 genIfxJump (ifx, swap_sense ? "nc" : "c");
4321 genIfxJump (ifx, swap_sense ? "p" : "m");
4326 genIfxJump (ifx, swap_sense ? "nc" : "c");
4333 /* Shift the sign bit up into carry */
4336 outBitCLong (result, swap_sense);
4338 /* leave the result in acc */
4342 /*-----------------------------------------------------------------*/
4343 /* genCmpGt :- greater than comparison */
4344 /*-----------------------------------------------------------------*/
4346 genCmpGt (iCode * ic, iCode * ifx)
4348 operand *left, *right, *result;
4349 sym_link *letype, *retype;
4352 left = IC_LEFT (ic);
4353 right = IC_RIGHT (ic);
4354 result = IC_RESULT (ic);
4356 letype = getSpec (operandType (left));
4357 retype = getSpec (operandType (right));
4358 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4359 /* assign the amsops */
4360 aopOp (left, ic, FALSE, FALSE);
4361 aopOp (right, ic, FALSE, FALSE);
4362 aopOp (result, ic, TRUE, FALSE);
4364 genCmp (right, left, result, ifx, sign);
4366 freeAsmop (left, NULL, ic);
4367 freeAsmop (right, NULL, ic);
4368 freeAsmop (result, NULL, ic);
4371 /*-----------------------------------------------------------------*/
4372 /* genCmpLt - less than comparisons */
4373 /*-----------------------------------------------------------------*/
4375 genCmpLt (iCode * ic, iCode * ifx)
4377 operand *left, *right, *result;
4378 sym_link *letype, *retype;
4381 left = IC_LEFT (ic);
4382 right = IC_RIGHT (ic);
4383 result = IC_RESULT (ic);
4385 letype = getSpec (operandType (left));
4386 retype = getSpec (operandType (right));
4387 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4389 /* assign the amsops */
4390 aopOp (left, ic, FALSE, FALSE);
4391 aopOp (right, ic, FALSE, FALSE);
4392 aopOp (result, ic, TRUE, FALSE);
4394 genCmp (left, right, result, ifx, sign);
4396 freeAsmop (left, NULL, ic);
4397 freeAsmop (right, NULL, ic);
4398 freeAsmop (result, NULL, ic);
4401 /*-----------------------------------------------------------------*/
4402 /* gencjneshort - compare and jump if not equal */
4403 /*-----------------------------------------------------------------*/
4405 gencjneshort (operand * left, operand * right, symbol * lbl)
4407 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4409 unsigned long lit = 0L;
4411 /* Swap the left and right if it makes the computation easier */
4412 if (AOP_TYPE (left) == AOP_LIT)
4419 if (AOP_TYPE (right) == AOP_LIT)
4421 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4424 /* if the right side is a literal then anything goes */
4425 if (AOP_TYPE (right) == AOP_LIT &&
4426 AOP_TYPE (left) != AOP_DIR)
4430 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4435 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4442 emit2 ("jp nz,!tlabel", lbl->key + 100);
4448 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4449 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
4452 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
4453 emit2 ("jp nz,!tlabel", lbl->key + 100);
4458 /* if the right side is in a register or in direct space or
4459 if the left is a pointer register & right is not */
4460 else if (AOP_TYPE (right) == AOP_REG ||
4461 AOP_TYPE (right) == AOP_DIR ||
4462 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
4466 _moveA (aopGet (AOP (left), offset, FALSE));
4467 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
4468 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4470 emit2 ("jp nz,!tlabel", lbl->key + 100);
4473 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4474 emit2 ("jp nz,!tlabel", lbl->key + 100);
4481 /* right is a pointer reg need both a & b */
4482 /* PENDING: is this required? */
4485 _moveA (aopGet (AOP (right), offset, FALSE));
4486 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
4487 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
4493 /*-----------------------------------------------------------------*/
4494 /* gencjne - compare and jump if not equal */
4495 /*-----------------------------------------------------------------*/
4497 gencjne (operand * left, operand * right, symbol * lbl)
4499 symbol *tlbl = newiTempLabel (NULL);
4501 gencjneshort (left, right, lbl);
4504 emit2 ("ld a,!one");
4505 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4506 emitLabel (lbl->key + 100);
4508 emitLabel (tlbl->key + 100);
4511 /*-----------------------------------------------------------------*/
4512 /* genCmpEq - generates code for equal to */
4513 /*-----------------------------------------------------------------*/
4515 genCmpEq (iCode * ic, iCode * ifx)
4517 operand *left, *right, *result;
4519 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4520 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4521 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4523 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4525 /* Swap operands if it makes the operation easier. ie if:
4526 1. Left is a literal.
4528 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4530 operand *t = IC_RIGHT (ic);
4531 IC_RIGHT (ic) = IC_LEFT (ic);
4535 if (ifx && !AOP_SIZE (result))
4538 /* if they are both bit variables */
4539 if (AOP_TYPE (left) == AOP_CRY &&
4540 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4542 wassertl (0, "Tried to compare two bits");
4546 tlbl = newiTempLabel (NULL);
4547 gencjneshort (left, right, tlbl);
4550 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4551 emitLabel (tlbl->key + 100);
4555 /* PENDING: do this better */
4556 symbol *lbl = newiTempLabel (NULL);
4557 emit2 ("!shortjp !tlabel", lbl->key + 100);
4558 emitLabel (tlbl->key + 100);
4559 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4560 emitLabel (lbl->key + 100);
4563 /* mark the icode as generated */
4568 /* if they are both bit variables */
4569 if (AOP_TYPE (left) == AOP_CRY &&
4570 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4572 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4578 gencjne (left, right, newiTempLabel (NULL));
4579 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4586 genIfxJump (ifx, "a");
4589 /* if the result is used in an arithmetic operation
4590 then put the result in place */
4591 if (AOP_TYPE (result) != AOP_CRY)
4596 /* leave the result in acc */
4600 freeAsmop (left, NULL, ic);
4601 freeAsmop (right, NULL, ic);
4602 freeAsmop (result, NULL, ic);
4605 /*-----------------------------------------------------------------*/
4606 /* ifxForOp - returns the icode containing the ifx for operand */
4607 /*-----------------------------------------------------------------*/
4609 ifxForOp (operand * op, iCode * ic)
4611 /* if true symbol then needs to be assigned */
4612 if (IS_TRUE_SYMOP (op))
4615 /* if this has register type condition and
4616 the next instruction is ifx with the same operand
4617 and live to of the operand is upto the ifx only then */
4619 ic->next->op == IFX &&
4620 IC_COND (ic->next)->key == op->key &&
4621 OP_SYMBOL (op)->liveTo <= ic->next->seq)
4627 /*-----------------------------------------------------------------*/
4628 /* genAndOp - for && operation */
4629 /*-----------------------------------------------------------------*/
4631 genAndOp (iCode * ic)
4633 operand *left, *right, *result;
4636 /* note here that && operations that are in an if statement are
4637 taken away by backPatchLabels only those used in arthmetic
4638 operations remain */
4639 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4640 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4641 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4643 /* if both are bit variables */
4644 if (AOP_TYPE (left) == AOP_CRY &&
4645 AOP_TYPE (right) == AOP_CRY)
4647 wassertl (0, "Tried to and two bits");
4651 tlbl = newiTempLabel (NULL);
4653 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
4655 emitLabel (tlbl->key + 100);
4659 freeAsmop (left, NULL, ic);
4660 freeAsmop (right, NULL, ic);
4661 freeAsmop (result, NULL, ic);
4664 /*-----------------------------------------------------------------*/
4665 /* genOrOp - for || operation */
4666 /*-----------------------------------------------------------------*/
4668 genOrOp (iCode * ic)
4670 operand *left, *right, *result;
4673 /* note here that || operations that are in an
4674 if statement are taken away by backPatchLabels
4675 only those used in arthmetic operations remain */
4676 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4677 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4678 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4680 /* if both are bit variables */
4681 if (AOP_TYPE (left) == AOP_CRY &&
4682 AOP_TYPE (right) == AOP_CRY)
4684 wassertl (0, "Tried to OR two bits");
4688 tlbl = newiTempLabel (NULL);
4690 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4692 emitLabel (tlbl->key + 100);
4696 freeAsmop (left, NULL, ic);
4697 freeAsmop (right, NULL, ic);
4698 freeAsmop (result, NULL, ic);
4701 /*-----------------------------------------------------------------*/
4702 /* isLiteralBit - test if lit == 2^n */
4703 /*-----------------------------------------------------------------*/
4705 isLiteralBit (unsigned long lit)
4707 unsigned long pw[32] =
4708 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
4709 0x100L, 0x200L, 0x400L, 0x800L,
4710 0x1000L, 0x2000L, 0x4000L, 0x8000L,
4711 0x10000L, 0x20000L, 0x40000L, 0x80000L,
4712 0x100000L, 0x200000L, 0x400000L, 0x800000L,
4713 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
4714 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
4717 for (idx = 0; idx < 32; idx++)
4723 /*-----------------------------------------------------------------*/
4724 /* jmpTrueOrFalse - */
4725 /*-----------------------------------------------------------------*/
4727 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
4729 // ugly but optimized by peephole
4732 symbol *nlbl = newiTempLabel (NULL);
4733 emit2 ("jp !tlabel", nlbl->key + 100);
4734 emitLabel (tlbl->key + 100);
4735 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
4736 emitLabel (nlbl->key + 100);
4740 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
4741 emitLabel (tlbl->key + 100);
4746 /*-----------------------------------------------------------------*/
4747 /* genAnd - code for and */
4748 /*-----------------------------------------------------------------*/
4750 genAnd (iCode * ic, iCode * ifx)
4752 operand *left, *right, *result;
4753 int size, offset = 0;
4754 unsigned long lit = 0L;
4757 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4758 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4759 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4761 /* if left is a literal & right is not then exchange them */
4762 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4763 AOP_NEEDSACC (left))
4765 operand *tmp = right;
4770 /* if result = right then exchange them */
4771 if (sameRegs (AOP (result), AOP (right)))
4773 operand *tmp = right;
4778 /* if right is bit then exchange them */
4779 if (AOP_TYPE (right) == AOP_CRY &&
4780 AOP_TYPE (left) != AOP_CRY)
4782 operand *tmp = right;
4786 if (AOP_TYPE (right) == AOP_LIT)
4787 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4789 size = AOP_SIZE (result);
4791 if (AOP_TYPE (left) == AOP_CRY)
4793 wassertl (0, "Tried to perform an AND with a bit as an operand");
4797 // if(val & 0xZZ) - size = 0, ifx != FALSE -
4798 // bit = val & 0xZZ - size = 1, ifx = FALSE -
4799 if ((AOP_TYPE (right) == AOP_LIT) &&
4800 (AOP_TYPE (result) == AOP_CRY) &&
4801 (AOP_TYPE (left) != AOP_CRY))
4803 symbol *tlbl = newiTempLabel (NULL);
4804 int sizel = AOP_SIZE (left);
4807 /* PENDING: Test case for this. */
4812 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
4814 _moveA (aopGet (AOP (left), offset, FALSE));
4815 if (bytelit != 0x0FFL)
4817 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4824 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4828 // bit = left & literal
4832 emit2 ("!tlabeldef", tlbl->key + 100);
4834 // if(left & literal)
4839 jmpTrueOrFalse (ifx, tlbl);
4847 /* if left is same as result */
4848 if (sameRegs (AOP (result), AOP (left)))
4850 for (; size--; offset++)
4852 if (AOP_TYPE (right) == AOP_LIT)
4854 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4859 aopPut (AOP (result), "!zero", offset);
4862 _moveA (aopGet (AOP (left), offset, FALSE));
4864 aopGet (AOP (right), offset, FALSE));
4865 aopPut (AOP (left), "a", offset);
4872 if (AOP_TYPE (left) == AOP_ACC)
4874 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
4878 _moveA (aopGet (AOP (left), offset, FALSE));
4880 aopGet (AOP (right), offset, FALSE));
4881 aopPut (AOP (left), "a", offset);
4888 // left & result in different registers
4889 if (AOP_TYPE (result) == AOP_CRY)
4891 wassertl (0, "Tried to AND where the result is in carry");
4895 for (; (size--); offset++)
4898 // result = left & right
4899 if (AOP_TYPE (right) == AOP_LIT)
4901 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4903 aopPut (AOP (result),
4904 aopGet (AOP (left), offset, FALSE),
4908 else if (bytelit == 0)
4910 aopPut (AOP (result), "!zero", offset);
4914 // faster than result <- left, anl result,right
4915 // and better if result is SFR
4916 if (AOP_TYPE (left) == AOP_ACC)
4917 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4920 _moveA (aopGet (AOP (left), offset, FALSE));
4922 aopGet (AOP (right), offset, FALSE));
4924 aopPut (AOP (result), "a", offset);
4931 freeAsmop (left, NULL, ic);
4932 freeAsmop (right, NULL, ic);
4933 freeAsmop (result, NULL, ic);
4936 /*-----------------------------------------------------------------*/
4937 /* genOr - code for or */
4938 /*-----------------------------------------------------------------*/
4940 genOr (iCode * ic, iCode * ifx)
4942 operand *left, *right, *result;
4943 int size, offset = 0;
4944 unsigned long lit = 0L;
4947 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4948 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4949 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4951 /* if left is a literal & right is not then exchange them */
4952 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4953 AOP_NEEDSACC (left))
4955 operand *tmp = right;
4960 /* if result = right then exchange them */
4961 if (sameRegs (AOP (result), AOP (right)))
4963 operand *tmp = right;
4968 /* if right is bit then exchange them */
4969 if (AOP_TYPE (right) == AOP_CRY &&
4970 AOP_TYPE (left) != AOP_CRY)
4972 operand *tmp = right;
4976 if (AOP_TYPE (right) == AOP_LIT)
4977 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4979 size = AOP_SIZE (result);
4981 if (AOP_TYPE (left) == AOP_CRY)
4983 wassertl (0, "Tried to OR where left is a bit");
4987 // if(val | 0xZZ) - size = 0, ifx != FALSE -
4988 // bit = val | 0xZZ - size = 1, ifx = FALSE -
4989 if ((AOP_TYPE (right) == AOP_LIT) &&
4990 (AOP_TYPE (result) == AOP_CRY) &&
4991 (AOP_TYPE (left) != AOP_CRY))
4993 symbol *tlbl = newiTempLabel (NULL);
4994 int sizel = AOP_SIZE (left);
4998 wassertl (0, "Result is assigned to a bit");
5000 /* PENDING: Modeled after the AND code which is inefficent. */
5003 bytelit = (lit >> (offset * 8)) & 0x0FFL;
5005 _moveA (aopGet (AOP (left), offset, FALSE));
5006 /* OR with any literal is the same as OR with itself. */
5008 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5014 jmpTrueOrFalse (ifx, tlbl);
5019 /* if left is same as result */
5020 if (sameRegs (AOP (result), AOP (left)))
5022 for (; size--; offset++)
5024 if (AOP_TYPE (right) == AOP_LIT)
5026 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5030 _moveA (aopGet (AOP (left), offset, FALSE));
5032 aopGet (AOP (right), offset, FALSE));
5033 aopPut (AOP (result), "a", offset);
5038 if (AOP_TYPE (left) == AOP_ACC)
5039 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5042 _moveA (aopGet (AOP (left), offset, FALSE));
5044 aopGet (AOP (right), offset, FALSE));
5045 aopPut (AOP (result), "a", offset);
5052 // left & result in different registers
5053 if (AOP_TYPE (result) == AOP_CRY)
5055 wassertl (0, "Result of OR is in a bit");
5058 for (; (size--); offset++)
5061 // result = left & right
5062 if (AOP_TYPE (right) == AOP_LIT)
5064 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5066 aopPut (AOP (result),
5067 aopGet (AOP (left), offset, FALSE),
5072 // faster than result <- left, anl result,right
5073 // and better if result is SFR
5074 if (AOP_TYPE (left) == AOP_ACC)
5075 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5078 _moveA (aopGet (AOP (left), offset, FALSE));
5080 aopGet (AOP (right), offset, FALSE));
5082 aopPut (AOP (result), "a", offset);
5083 /* PENDING: something weird is going on here. Add exception. */
5084 if (AOP_TYPE (result) == AOP_ACC)
5090 freeAsmop (left, NULL, ic);
5091 freeAsmop (right, NULL, ic);
5092 freeAsmop (result, NULL, ic);
5095 /*-----------------------------------------------------------------*/
5096 /* genXor - code for xclusive or */
5097 /*-----------------------------------------------------------------*/
5099 genXor (iCode * ic, iCode * ifx)
5101 operand *left, *right, *result;
5102 int size, offset = 0;
5103 unsigned long lit = 0L;
5105 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5106 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5107 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5109 /* if left is a literal & right is not then exchange them */
5110 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5111 AOP_NEEDSACC (left))
5113 operand *tmp = right;
5118 /* if result = right then exchange them */
5119 if (sameRegs (AOP (result), AOP (right)))
5121 operand *tmp = right;
5126 /* if right is bit then exchange them */
5127 if (AOP_TYPE (right) == AOP_CRY &&
5128 AOP_TYPE (left) != AOP_CRY)
5130 operand *tmp = right;
5134 if (AOP_TYPE (right) == AOP_LIT)
5135 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5137 size = AOP_SIZE (result);
5139 if (AOP_TYPE (left) == AOP_CRY)
5141 wassertl (0, "Tried to XOR a bit");
5145 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5146 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5147 if ((AOP_TYPE (right) == AOP_LIT) &&
5148 (AOP_TYPE (result) == AOP_CRY) &&
5149 (AOP_TYPE (left) != AOP_CRY))
5151 symbol *tlbl = newiTempLabel (NULL);
5152 int sizel = AOP_SIZE (left);
5156 /* PENDING: Test case for this. */
5157 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5161 _moveA (aopGet (AOP (left), offset, FALSE));
5162 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5163 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5168 jmpTrueOrFalse (ifx, tlbl);
5172 wassertl (0, "Result of XOR was destined for a bit");
5177 /* if left is same as result */
5178 if (sameRegs (AOP (result), AOP (left)))
5180 for (; size--; offset++)
5182 if (AOP_TYPE (right) == AOP_LIT)
5184 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5188 _moveA (aopGet (AOP (right), offset, FALSE));
5190 aopGet (AOP (left), offset, FALSE));
5191 aopPut (AOP (result), "a", offset);
5196 if (AOP_TYPE (left) == AOP_ACC)
5198 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5202 _moveA (aopGet (AOP (right), offset, FALSE));
5204 aopGet (AOP (left), offset, FALSE));
5205 aopPut (AOP (result), "a", offset);
5212 // left & result in different registers
5213 if (AOP_TYPE (result) == AOP_CRY)
5215 wassertl (0, "Result of XOR is in a bit");
5218 for (; (size--); offset++)
5221 // result = left & right
5222 if (AOP_TYPE (right) == AOP_LIT)
5224 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5226 aopPut (AOP (result),
5227 aopGet (AOP (left), offset, FALSE),
5232 // faster than result <- left, anl result,right
5233 // and better if result is SFR
5234 if (AOP_TYPE (left) == AOP_ACC)
5236 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5240 _moveA (aopGet (AOP (right), offset, FALSE));
5242 aopGet (AOP (left), offset, FALSE));
5244 aopPut (AOP (result), "a", offset);
5249 freeAsmop (left, NULL, ic);
5250 freeAsmop (right, NULL, ic);
5251 freeAsmop (result, NULL, ic);
5254 /*-----------------------------------------------------------------*/
5255 /* genInline - write the inline code out */
5256 /*-----------------------------------------------------------------*/
5258 genInline (iCode * ic)
5260 char *buffer, *bp, *bp1;
5262 _G.lines.isInline += (!options.asmpeep);
5264 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5265 strcpy (buffer, IC_INLINE (ic));
5267 /* emit each line as a code */
5292 _G.lines.isInline -= (!options.asmpeep);
5296 /*-----------------------------------------------------------------*/
5297 /* genRRC - rotate right with carry */
5298 /*-----------------------------------------------------------------*/
5305 /*-----------------------------------------------------------------*/
5306 /* genRLC - generate code for rotate left with carry */
5307 /*-----------------------------------------------------------------*/
5314 /*-----------------------------------------------------------------*/
5315 /* genGetHbit - generates code get highest order bit */
5316 /*-----------------------------------------------------------------*/
5318 genGetHbit (iCode * ic)
5320 operand *left, *result;
5321 left = IC_LEFT (ic);
5322 result = IC_RESULT (ic);
5324 aopOp (left, ic, FALSE, FALSE);
5325 aopOp (result, ic, FALSE, FALSE);
5327 /* get the highest order byte into a */
5328 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5330 if (AOP_TYPE (result) == AOP_CRY)
5338 emit2 ("and a,!one");
5343 freeAsmop (left, NULL, ic);
5344 freeAsmop (result, NULL, ic);
5348 emitRsh2 (asmop *aop, int size, int is_signed)
5354 const char *l = aopGet (aop, size, FALSE);
5357 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5367 /*-----------------------------------------------------------------*/
5368 /* shiftR2Left2Result - shift right two bytes from left to result */
5369 /*-----------------------------------------------------------------*/
5371 shiftR2Left2Result (operand * left, int offl,
5372 operand * result, int offr,
5373 int shCount, int is_signed)
5376 symbol *tlbl, *tlbl1;
5378 movLeft2Result (left, offl, result, offr, 0);
5379 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5381 /* if (AOP(result)->type == AOP_REG) { */
5383 tlbl = newiTempLabel (NULL);
5384 tlbl1 = newiTempLabel (NULL);
5386 /* Left is already in result - so now do the shift */
5391 emitRsh2 (AOP (result), size, is_signed);
5396 emit2 ("ld a,!immedbyte+1", shCount);
5397 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5398 emitLabel (tlbl->key + 100);
5400 emitRsh2 (AOP (result), size, is_signed);
5402 emitLabel (tlbl1->key + 100);
5404 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5408 /*-----------------------------------------------------------------*/
5409 /* shiftL2Left2Result - shift left two bytes from left to result */
5410 /*-----------------------------------------------------------------*/
5412 shiftL2Left2Result (operand * left, int offl,
5413 operand * result, int offr, int shCount)
5415 if (sameRegs (AOP (result), AOP (left)) &&
5416 ((offl + MSB16) == offr))
5422 /* Copy left into result */
5423 movLeft2Result (left, offl, result, offr, 0);
5424 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5427 if (getPairId (AOP (result)) == PAIR_HL)
5431 emit2 ("add hl,hl");
5438 symbol *tlbl, *tlbl1;
5441 tlbl = newiTempLabel (NULL);
5442 tlbl1 = newiTempLabel (NULL);
5444 if (AOP (result)->type == AOP_REG)
5448 for (offset = 0; offset < size; offset++)
5450 l = aopGet (AOP (result), offset, FALSE);
5454 emit2 ("sla %s", l);
5465 /* Left is already in result - so now do the shift */
5468 emit2 ("ld a,!immedbyte+1", shCount);
5469 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5470 emitLabel (tlbl->key + 100);
5475 l = aopGet (AOP (result), offset, FALSE);
5479 emit2 ("sla %s", l);
5490 emitLabel (tlbl1->key + 100);
5492 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5498 /*-----------------------------------------------------------------*/
5499 /* AccRol - rotate left accumulator by known count */
5500 /*-----------------------------------------------------------------*/
5502 AccRol (int shCount)
5504 shCount &= 0x0007; // shCount : 0..7
5581 /*-----------------------------------------------------------------*/
5582 /* AccLsh - left shift accumulator by known count */
5583 /*-----------------------------------------------------------------*/
5585 AccLsh (int shCount)
5587 static const unsigned char SLMask[] =
5589 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5598 else if (shCount == 2)
5605 /* rotate left accumulator */
5607 /* and kill the lower order bits */
5608 emit2 ("and a,!immedbyte", SLMask[shCount]);
5613 /*-----------------------------------------------------------------*/
5614 /* shiftL1Left2Result - shift left one byte from left to result */
5615 /*-----------------------------------------------------------------*/
5617 shiftL1Left2Result (operand * left, int offl,
5618 operand * result, int offr, int shCount)
5621 l = aopGet (AOP (left), offl, FALSE);
5623 /* shift left accumulator */
5625 aopPut (AOP (result), "a", offr);
5629 /*-----------------------------------------------------------------*/
5630 /* genlshTwo - left shift two bytes by known amount != 0 */
5631 /*-----------------------------------------------------------------*/
5633 genlshTwo (operand * result, operand * left, int shCount)
5635 int size = AOP_SIZE (result);
5637 wassert (size == 2);
5639 /* if shCount >= 8 */
5647 movLeft2Result (left, LSB, result, MSB16, 0);
5648 aopPut (AOP (result), "!zero", 0);
5649 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
5653 movLeft2Result (left, LSB, result, MSB16, 0);
5654 aopPut (AOP (result), "!zero", 0);
5659 aopPut (AOP (result), "!zero", LSB);
5662 /* 1 <= shCount <= 7 */
5671 shiftL2Left2Result (left, LSB, result, LSB, shCount);
5676 /*-----------------------------------------------------------------*/
5677 /* genlshOne - left shift a one byte quantity by known count */
5678 /*-----------------------------------------------------------------*/
5680 genlshOne (operand * result, operand * left, int shCount)
5682 shiftL1Left2Result (left, LSB, result, LSB, shCount);
5685 /*-----------------------------------------------------------------*/
5686 /* genLeftShiftLiteral - left shifting by known count */
5687 /*-----------------------------------------------------------------*/
5689 genLeftShiftLiteral (operand * left,
5694 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5697 freeAsmop (right, NULL, ic);
5699 aopOp (left, ic, FALSE, FALSE);
5700 aopOp (result, ic, FALSE, FALSE);
5702 size = getSize (operandType (result));
5704 /* I suppose that the left size >= result size */
5710 else if (shCount >= (size * 8))
5714 aopPut (AOP (result), "!zero", size);
5722 genlshOne (result, left, shCount);
5725 genlshTwo (result, left, shCount);
5728 wassertl (0, "Shifting of longs is currently unsupported");
5734 freeAsmop (left, NULL, ic);
5735 freeAsmop (result, NULL, ic);
5738 /*-----------------------------------------------------------------*/
5739 /* genLeftShift - generates code for left shifting */
5740 /*-----------------------------------------------------------------*/
5742 genLeftShift (iCode * ic)
5746 symbol *tlbl, *tlbl1;
5747 operand *left, *right, *result;
5749 right = IC_RIGHT (ic);
5750 left = IC_LEFT (ic);
5751 result = IC_RESULT (ic);
5753 aopOp (right, ic, FALSE, FALSE);
5755 /* if the shift count is known then do it
5756 as efficiently as possible */
5757 if (AOP_TYPE (right) == AOP_LIT)
5759 genLeftShiftLiteral (left, right, result, ic);
5763 /* shift count is unknown then we have to form a loop get the loop
5764 count in B : Note: we take only the lower order byte since
5765 shifting more that 32 bits make no sense anyway, ( the largest
5766 size of an object can be only 32 bits ) */
5767 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5769 freeAsmop (right, NULL, ic);
5770 aopOp (left, ic, FALSE, FALSE);
5771 aopOp (result, ic, FALSE, FALSE);
5773 /* now move the left to the result if they are not the
5776 if (!sameRegs (AOP (left), AOP (result)))
5779 size = AOP_SIZE (result);
5783 l = aopGet (AOP (left), offset, FALSE);
5784 aopPut (AOP (result), l, offset);
5789 tlbl = newiTempLabel (NULL);
5790 size = AOP_SIZE (result);
5792 tlbl1 = newiTempLabel (NULL);
5794 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5795 emitLabel (tlbl->key + 100);
5796 l = aopGet (AOP (result), offset, FALSE);
5800 l = aopGet (AOP (result), offset, FALSE);
5804 emit2 ("sla %s", l);
5812 emitLabel (tlbl1->key + 100);
5814 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5816 freeAsmop (left, NULL, ic);
5817 freeAsmop (result, NULL, ic);
5820 /*-----------------------------------------------------------------*/
5821 /* genrshOne - left shift two bytes by known amount != 0 */
5822 /*-----------------------------------------------------------------*/
5824 genrshOne (operand * result, operand * left, int shCount, int is_signed)
5827 int size = AOP_SIZE (result);
5830 wassert (size == 1);
5831 wassert (shCount < 8);
5833 l = aopGet (AOP (left), 0, FALSE);
5835 if (AOP (result)->type == AOP_REG)
5837 aopPut (AOP (result), l, 0);
5838 l = aopGet (AOP (result), 0, FALSE);
5841 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5849 emit2 ("%s a", is_signed ? "sra" : "srl");
5851 aopPut (AOP (result), "a", 0);
5855 /*-----------------------------------------------------------------*/
5856 /* AccRsh - right shift accumulator by known count */
5857 /*-----------------------------------------------------------------*/
5859 AccRsh (int shCount)
5861 static const unsigned char SRMask[] =
5863 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
5868 /* rotate right accumulator */
5869 AccRol (8 - shCount);
5870 /* and kill the higher order bits */
5871 emit2 ("and a,!immedbyte", SRMask[shCount]);
5875 /*-----------------------------------------------------------------*/
5876 /* shiftR1Left2Result - shift right one byte from left to result */
5877 /*-----------------------------------------------------------------*/
5879 shiftR1Left2Result (operand * left, int offl,
5880 operand * result, int offr,
5881 int shCount, int sign)
5883 _moveA (aopGet (AOP (left), offl, FALSE));
5888 emit2 ("%s a", sign ? "sra" : "srl");
5895 aopPut (AOP (result), "a", offr);
5898 /*-----------------------------------------------------------------*/
5899 /* genrshTwo - right shift two bytes by known amount != 0 */
5900 /*-----------------------------------------------------------------*/
5902 genrshTwo (operand * result, operand * left,
5903 int shCount, int sign)
5905 /* if shCount >= 8 */
5911 shiftR1Left2Result (left, MSB16, result, LSB,
5916 movLeft2Result (left, MSB16, result, LSB, sign);
5920 /* Sign extend the result */
5921 _moveA(aopGet (AOP (result), 0, FALSE));
5925 aopPut (AOP (result), ACC_NAME, MSB16);
5929 aopPut (AOP (result), "!zero", 1);
5932 /* 1 <= shCount <= 7 */
5935 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
5939 /*-----------------------------------------------------------------*/
5940 /* genRightShiftLiteral - left shifting by known count */
5941 /*-----------------------------------------------------------------*/
5943 genRightShiftLiteral (operand * left,
5949 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5952 freeAsmop (right, NULL, ic);
5954 aopOp (left, ic, FALSE, FALSE);
5955 aopOp (result, ic, FALSE, FALSE);
5957 size = getSize (operandType (result));
5959 /* I suppose that the left size >= result size */
5965 else if (shCount >= (size * 8)) {
5967 if (!SPEC_USIGN(getSpec(operandType(left)))) {
5968 _moveA(aopGet (AOP (left), 0, FALSE));
5976 aopPut (AOP (result), s, size);
5983 genrshOne (result, left, shCount, sign);
5986 genrshTwo (result, left, shCount, sign);
5989 wassertl (0, "Asked to shift right a long which should be a function call");
5992 wassertl (0, "Entered default case in right shift delegate");
5995 freeAsmop (left, NULL, ic);
5996 freeAsmop (result, NULL, ic);
5999 /*-----------------------------------------------------------------*/
6000 /* genRightShift - generate code for right shifting */
6001 /*-----------------------------------------------------------------*/
6003 genRightShift (iCode * ic)
6005 operand *right, *left, *result;
6007 int size, offset, first = 1;
6011 symbol *tlbl, *tlbl1;
6013 /* if signed then we do it the hard way preserve the
6014 sign bit moving it inwards */
6015 retype = getSpec (operandType (IC_RESULT (ic)));
6017 is_signed = !SPEC_USIGN (retype);
6019 /* signed & unsigned types are treated the same : i.e. the
6020 signed is NOT propagated inwards : quoting from the
6021 ANSI - standard : "for E1 >> E2, is equivalent to division
6022 by 2**E2 if unsigned or if it has a non-negative value,
6023 otherwise the result is implementation defined ", MY definition
6024 is that the sign does not get propagated */
6026 right = IC_RIGHT (ic);
6027 left = IC_LEFT (ic);
6028 result = IC_RESULT (ic);
6030 aopOp (right, ic, FALSE, FALSE);
6032 /* if the shift count is known then do it
6033 as efficiently as possible */
6034 if (AOP_TYPE (right) == AOP_LIT)
6036 genRightShiftLiteral (left, right, result, ic, is_signed);
6040 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6042 freeAsmop (right, NULL, ic);
6044 aopOp (left, ic, FALSE, FALSE);
6045 aopOp (result, ic, FALSE, FALSE);
6047 /* now move the left to the result if they are not the
6049 if (!sameRegs (AOP (left), AOP (result)))
6052 size = AOP_SIZE (result);
6056 l = aopGet (AOP (left), offset, FALSE);
6057 aopPut (AOP (result), l, offset);
6062 tlbl = newiTempLabel (NULL);
6063 tlbl1 = newiTempLabel (NULL);
6064 size = AOP_SIZE (result);
6067 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6068 emitLabel (tlbl->key + 100);
6071 l = aopGet (AOP (result), offset--, FALSE);
6074 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6082 emitLabel (tlbl1->key + 100);
6084 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6086 freeAsmop (left, NULL, ic);
6087 freeAsmop (result, NULL, ic);
6091 /*-----------------------------------------------------------------*/
6092 /* genUnpackBits - generates code for unpacking bits */
6093 /*-----------------------------------------------------------------*/
6095 genUnpackBits (operand * result, int pair)
6097 int offset = 0; /* result byte offset */
6098 int rsize; /* result size */
6099 int rlen = 0; /* remaining bitfield length */
6100 sym_link *etype; /* bitfield type information */
6101 int blen; /* bitfield length */
6102 int bstr; /* bitfield starting bit within byte */
6104 emitDebug ("; genUnpackBits");
6106 etype = getSpec (operandType (result));
6107 rsize = getSize (operandType (result));
6108 blen = SPEC_BLEN (etype);
6109 bstr = SPEC_BSTR (etype);
6111 /* If the bitfield length is less than a byte */
6114 emit2 ("ld a,!*pair", _pairs[pair].name);
6116 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6117 aopPut (AOP (result), "a", offset++);
6121 /* TODO: what if pair == PAIR_DE ? */
6122 if (getPairId (AOP (result)) == PAIR_HL)
6124 wassertl (rsize == 2, "HL must be of size 2");
6125 emit2 ("ld a,!*hl");
6127 emit2 ("ld h,!*hl");
6130 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6132 spillPair (PAIR_HL);
6136 /* Bit field did not fit in a byte. Copy all
6137 but the partial byte at the end. */
6138 for (rlen=blen;rlen>=8;rlen-=8)
6140 emit2 ("ld a,!*pair", _pairs[pair].name);
6141 aopPut (AOP (result), "a", offset++);
6144 emit2 ("inc %s", _pairs[pair].name);
6145 _G.pairs[pair].offset++;
6149 /* Handle the partial byte at the end */
6152 emit2 ("ld a,!*pair", _pairs[pair].name);
6153 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6154 aopPut (AOP (result), "a", offset++);
6162 aopPut (AOP (result), "!zero", offset++);
6166 /*-----------------------------------------------------------------*/
6167 /* genGenPointerGet - get value from generic pointer space */
6168 /*-----------------------------------------------------------------*/
6170 genGenPointerGet (operand * left,
6171 operand * result, iCode * ic)
6174 sym_link *retype = getSpec (operandType (result));
6180 aopOp (left, ic, FALSE, FALSE);
6181 aopOp (result, ic, FALSE, FALSE);
6183 size = AOP_SIZE (result);
6185 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6188 if (isPtrPair (AOP (left)))
6190 tsprintf (buffer, sizeof(buffer),
6191 "!*pair", getPairName (AOP (left)));
6192 aopPut (AOP (result), buffer, 0);
6196 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6197 aopPut (AOP (result), "a", 0);
6199 freeAsmop (left, NULL, ic);
6203 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6210 tsprintf (at, sizeof(at), "!*iyx", offset);
6211 aopPut (AOP (result), at, offset);
6215 freeAsmop (left, NULL, ic);
6219 /* For now we always load into IY */
6220 /* if this is remateriazable */
6221 fetchPair (pair, AOP (left));
6223 /* if bit then unpack */
6224 if (IS_BITVAR (retype))
6226 genUnpackBits (result, pair);
6227 freeAsmop (left, NULL, ic);
6231 else if (getPairId (AOP (result)) == PAIR_HL)
6233 wassertl (size == 2, "HL must be of size 2");
6234 emit2 ("ld a,!*hl");
6236 emit2 ("ld h,!*hl");
6238 spillPair (PAIR_HL);
6240 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6242 size = AOP_SIZE (result);
6247 /* PENDING: make this better */
6248 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6250 aopPut (AOP (result), "!*hl", offset++);
6254 emit2 ("ld a,!*pair", _pairs[pair].name);
6255 aopPut (AOP (result), "a", offset++);
6259 emit2 ("inc %s", _pairs[pair].name);
6260 _G.pairs[pair].offset++;
6263 /* Fixup HL back down */
6264 for (size = AOP_SIZE (result)-1; size; size--)
6266 emit2 ("dec %s", _pairs[pair].name);
6271 size = AOP_SIZE (result);
6276 /* PENDING: make this better */
6278 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6280 aopPut (AOP (result), "!*hl", offset++);
6284 emit2 ("ld a,!*pair", _pairs[pair].name);
6285 aopPut (AOP (result), "a", offset++);
6289 emit2 ("inc %s", _pairs[pair].name);
6290 _G.pairs[pair].offset++;
6295 freeAsmop (left, NULL, ic);
6298 freeAsmop (result, NULL, ic);
6301 /*-----------------------------------------------------------------*/
6302 /* genPointerGet - generate code for pointer get */
6303 /*-----------------------------------------------------------------*/
6305 genPointerGet (iCode * ic)
6307 operand *left, *result;
6308 sym_link *type, *etype;
6310 left = IC_LEFT (ic);
6311 result = IC_RESULT (ic);
6313 /* depending on the type of pointer we need to
6314 move it to the correct pointer register */
6315 type = operandType (left);
6316 etype = getSpec (type);
6318 genGenPointerGet (left, result, ic);
6322 isRegOrLit (asmop * aop)
6324 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6330 /*-----------------------------------------------------------------*/
6331 /* genPackBits - generates code for packed bit storage */
6332 /*-----------------------------------------------------------------*/
6334 genPackBits (sym_link * etype,
6339 int offset = 0; /* source byte offset */
6340 int rlen = 0; /* remaining bitfield length */
6341 int blen; /* bitfield length */
6342 int bstr; /* bitfield starting bit within byte */
6343 int litval; /* source literal value (if AOP_LIT) */
6344 unsigned char mask; /* bitmask within current byte */
6345 int extraPair; /* a tempory register */
6346 bool needPopExtra=0; /* need to restore original value of temp reg */
6348 emitDebug ("; genPackBits","");
6350 blen = SPEC_BLEN (etype);
6351 bstr = SPEC_BSTR (etype);
6353 /* If the bitfield length is less than a byte */
6356 mask = ((unsigned char) (0xFF << (blen + bstr)) |
6357 (unsigned char) (0xFF >> (8 - bstr)));
6359 if (AOP_TYPE (right) == AOP_LIT)
6361 /* Case with a bitfield length <8 and literal source
6363 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6365 litval &= (~mask) & 0xff;
6366 emit2 ("ld a,!*pair", _pairs[pair].name);
6367 if ((mask|litval)!=0xff)
6368 emit2 ("and a,!immedbyte", mask);
6370 emit2 ("or a,!immedbyte", litval);
6371 emit2 ("ld !*pair,a", _pairs[pair].name);
6376 /* Case with a bitfield length <8 and arbitrary source
6378 _moveA (aopGet (AOP (right), 0, FALSE));
6379 /* shift and mask source value */
6381 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6383 extraPair = getFreePairId(ic);
6384 if (extraPair == PAIR_INVALID)
6386 extraPair = PAIR_BC;
6387 if (getPairId (AOP (right)) != PAIR_BC
6388 || !isLastUse (ic, right))
6394 emit2 ("ld %s,a", _pairs[extraPair].l);
6395 emit2 ("ld a,!*pair", _pairs[pair].name);
6397 emit2 ("and a,!immedbyte", mask);
6398 emit2 ("or a,%s", _pairs[extraPair].l);
6399 emit2 ("ld !*pair,a", _pairs[pair].name);
6406 /* Bit length is greater than 7 bits. In this case, copy */
6407 /* all except the partial byte at the end */
6408 for (rlen=blen;rlen>=8;rlen-=8)
6410 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
6411 emit2 ("ld !*pair,a", _pairs[pair].name);
6414 emit2 ("inc %s", _pairs[pair].name);
6415 _G.pairs[pair].offset++;
6419 /* If there was a partial byte at the end */
6422 mask = (((unsigned char) -1 << rlen) & 0xff);
6424 if (AOP_TYPE (right) == AOP_LIT)
6426 /* Case with partial byte and literal source
6428 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6429 litval >>= (blen-rlen);
6430 litval &= (~mask) & 0xff;
6431 emit2 ("ld a,!*pair", _pairs[pair].name);
6432 if ((mask|litval)!=0xff)
6433 emit2 ("and a,!immedbyte", mask);
6435 emit2 ("or a,!immedbyte", litval);
6439 /* Case with partial byte and arbitrary source
6441 _moveA (aopGet (AOP (right), offset++, FALSE));
6442 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6444 extraPair = getFreePairId(ic);
6445 if (extraPair == PAIR_INVALID)
6447 extraPair = getPairId (AOP (right));
6448 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
6449 extraPair = PAIR_BC;
6451 if (getPairId (AOP (right)) != PAIR_BC
6452 || !isLastUse (ic, right))
6458 emit2 ("ld %s,a", _pairs[extraPair].l);
6459 emit2 ("ld a,!*pair", _pairs[pair].name);
6461 emit2 ("and a,!immedbyte", mask);
6462 emit2 ("or a,%s", _pairs[extraPair].l);
6467 emit2 ("ld !*pair,a", _pairs[pair].name);
6472 /*-----------------------------------------------------------------*/
6473 /* genGenPointerSet - stores the value into a pointer location */
6474 /*-----------------------------------------------------------------*/
6476 genGenPointerSet (operand * right,
6477 operand * result, iCode * ic)
6480 sym_link *retype = getSpec (operandType (right));
6481 sym_link *letype = getSpec (operandType (result));
6482 PAIR_ID pairId = PAIR_HL;
6485 aopOp (result, ic, FALSE, FALSE);
6486 aopOp (right, ic, FALSE, FALSE);
6491 size = AOP_SIZE (right);
6493 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
6494 emitDebug("; isBitvar = %d", isBitvar);
6496 /* Handle the exceptions first */
6497 if (isPair (AOP (result)) && size == 1 && !isBitvar)
6500 const char *l = aopGet (AOP (right), 0, FALSE);
6501 const char *pair = getPairName (AOP (result));
6502 if (canAssignToPtr (l) && isPtr (pair))
6504 emit2 ("ld !*pair,%s", pair, l);
6509 emit2 ("ld !*pair,a", pair);
6514 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
6517 const char *l = aopGet (AOP (right), 0, FALSE);
6522 if (canAssignToPtr (l))
6524 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6528 _moveA (aopGet (AOP (right), offset, FALSE));
6529 emit2 ("ld !*iyx,a", offset);
6535 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
6542 const char *l = aopGet (AOP (right), offset, FALSE);
6543 if (isRegOrLit (AOP (right)) && !IS_GB)
6545 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
6550 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
6554 emit2 ("inc %s", _pairs[PAIR_HL].name);
6555 _G.pairs[PAIR_HL].offset++;
6560 /* Fixup HL back down */
6561 for (size = AOP_SIZE (right)-1; size; size--)
6563 emit2 ("dec %s", _pairs[PAIR_HL].name);
6568 /* if the operand is already in dptr
6569 then we do nothing else we move the value to dptr */
6570 if (AOP_TYPE (result) != AOP_STR)
6572 fetchPair (pairId, AOP (result));
6574 /* so hl know contains the address */
6575 freeAsmop (result, NULL, ic);
6577 /* if bit then unpack */
6580 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
6590 const char *l = aopGet (AOP (right), offset, FALSE);
6591 if (isRegOrLit (AOP (right)) && !IS_GB)
6593 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
6598 emit2 ("ld !*pair,a", _pairs[pairId].name);
6602 emit2 ("inc %s", _pairs[pairId].name);
6603 _G.pairs[pairId].offset++;
6609 freeAsmop (right, NULL, ic);
6612 /*-----------------------------------------------------------------*/
6613 /* genPointerSet - stores the value into a pointer location */
6614 /*-----------------------------------------------------------------*/
6616 genPointerSet (iCode * ic)
6618 operand *right, *result;
6619 sym_link *type, *etype;
6621 right = IC_RIGHT (ic);
6622 result = IC_RESULT (ic);
6624 /* depending on the type of pointer we need to
6625 move it to the correct pointer register */
6626 type = operandType (result);
6627 etype = getSpec (type);
6629 genGenPointerSet (right, result, ic);
6632 /*-----------------------------------------------------------------*/
6633 /* genIfx - generate code for Ifx statement */
6634 /*-----------------------------------------------------------------*/
6636 genIfx (iCode * ic, iCode * popIc)
6638 operand *cond = IC_COND (ic);
6641 aopOp (cond, ic, FALSE, TRUE);
6643 /* get the value into acc */
6644 if (AOP_TYPE (cond) != AOP_CRY)
6648 /* the result is now in the accumulator */
6649 freeAsmop (cond, NULL, ic);
6651 /* if there was something to be popped then do it */
6655 /* if the condition is a bit variable */
6656 if (isbit && IS_ITEMP (cond) &&
6658 genIfxJump (ic, SPIL_LOC (cond)->rname);
6659 else if (isbit && !IS_ITEMP (cond))
6660 genIfxJump (ic, OP_SYMBOL (cond)->rname);
6662 genIfxJump (ic, "a");
6667 /*-----------------------------------------------------------------*/
6668 /* genAddrOf - generates code for address of */
6669 /*-----------------------------------------------------------------*/
6671 genAddrOf (iCode * ic)
6673 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
6675 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6677 /* if the operand is on the stack then we
6678 need to get the stack offset of this
6685 if (sym->stack <= 0)
6687 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
6691 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6693 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6697 emit2 ("ld de,!hashedstr", sym->rname);
6698 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
6706 /* if it has an offset then we need to compute it */
6708 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6710 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
6711 emit2 ("add hl,sp");
6715 emit2 ("ld hl,!hashedstr", sym->rname);
6717 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6719 freeAsmop (IC_RESULT (ic), NULL, ic);
6722 /*-----------------------------------------------------------------*/
6723 /* genAssign - generate code for assignment */
6724 /*-----------------------------------------------------------------*/
6726 genAssign (iCode * ic)
6728 operand *result, *right;
6730 unsigned long lit = 0L;
6732 result = IC_RESULT (ic);
6733 right = IC_RIGHT (ic);
6735 /* Dont bother assigning if they are the same */
6736 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6738 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
6742 aopOp (right, ic, FALSE, FALSE);
6743 aopOp (result, ic, TRUE, FALSE);
6745 /* if they are the same registers */
6746 if (sameRegs (AOP (right), AOP (result)))
6748 emitDebug ("; (registers are the same)");
6752 /* if the result is a bit */
6753 if (AOP_TYPE (result) == AOP_CRY)
6755 wassertl (0, "Tried to assign to a bit");
6759 size = AOP_SIZE (result);
6762 if (AOP_TYPE (right) == AOP_LIT)
6764 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6767 if (isPair (AOP (result)))
6769 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
6771 else if ((size > 1) &&
6772 (AOP_TYPE (result) != AOP_REG) &&
6773 (AOP_TYPE (right) == AOP_LIT) &&
6774 !IS_FLOAT (operandType (right)) &&
6777 bool fXored = FALSE;
6779 /* Work from the top down.
6780 Done this way so that we can use the cached copy of 0
6781 in A for a fast clear */
6784 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
6786 if (!fXored && size > 1)
6793 aopPut (AOP (result), "a", offset);
6797 aopPut (AOP (result), "!zero", offset);
6801 aopPut (AOP (result),
6802 aopGet (AOP (right), offset, FALSE),
6807 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
6809 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
6810 aopPut (AOP (result), "l", LSB);
6811 aopPut (AOP (result), "h", MSB16);
6813 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6815 /* Special case. Load into a and d, then load out. */
6816 _moveA (aopGet (AOP (right), 0, FALSE));
6817 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
6818 aopPut (AOP (result), "a", 0);
6819 aopPut (AOP (result), "e", 1);
6821 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6823 /* Special case - simple memcpy */
6824 aopGet (AOP (right), LSB, FALSE);
6827 aopGet (AOP (result), LSB, FALSE);
6831 emit2 ("ld a,(de)");
6832 /* Peephole will optimise this. */
6833 emit2 ("ld (hl),a");
6841 spillPair (PAIR_HL);
6847 /* PENDING: do this check better */
6848 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
6850 _moveA (aopGet (AOP (right), offset, FALSE));
6851 aopPut (AOP (result), "a", offset);
6854 aopPut (AOP (result),
6855 aopGet (AOP (right), offset, FALSE),
6862 freeAsmop (right, NULL, ic);
6863 freeAsmop (result, NULL, ic);
6866 /*-----------------------------------------------------------------*/
6867 /* genJumpTab - genrates code for jump table */
6868 /*-----------------------------------------------------------------*/
6870 genJumpTab (iCode * ic)
6875 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
6876 /* get the condition into accumulator */
6877 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
6880 emit2 ("ld e,%s", l);
6881 emit2 ("ld d,!zero");
6882 jtab = newiTempLabel (NULL);
6884 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
6885 emit2 ("add hl,de");
6886 emit2 ("add hl,de");
6887 emit2 ("add hl,de");
6888 freeAsmop (IC_JTCOND (ic), NULL, ic);
6892 emitLabel (jtab->key + 100);
6893 /* now generate the jump labels */
6894 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
6895 jtab = setNextItem (IC_JTLABELS (ic)))
6896 emit2 ("jp !tlabel", jtab->key + 100);
6899 /*-----------------------------------------------------------------*/
6900 /* genCast - gen code for casting */
6901 /*-----------------------------------------------------------------*/
6903 genCast (iCode * ic)
6905 operand *result = IC_RESULT (ic);
6906 sym_link *rtype = operandType (IC_RIGHT (ic));
6907 operand *right = IC_RIGHT (ic);
6910 /* if they are equivalent then do nothing */
6911 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6914 aopOp (right, ic, FALSE, FALSE);
6915 aopOp (result, ic, FALSE, FALSE);
6917 /* if the result is a bit */
6918 if (AOP_TYPE (result) == AOP_CRY)
6920 wassertl (0, "Tried to cast to a bit");
6923 /* if they are the same size : or less */
6924 if (AOP_SIZE (result) <= AOP_SIZE (right))
6927 /* if they are in the same place */
6928 if (sameRegs (AOP (right), AOP (result)))
6931 /* if they in different places then copy */
6932 size = AOP_SIZE (result);
6936 aopPut (AOP (result),
6937 aopGet (AOP (right), offset, FALSE),
6944 /* So we now know that the size of destination is greater
6945 than the size of the source */
6946 /* we move to result for the size of source */
6947 size = AOP_SIZE (right);
6951 aopPut (AOP (result),
6952 aopGet (AOP (right), offset, FALSE),
6957 /* now depending on the sign of the destination */
6958 size = AOP_SIZE (result) - AOP_SIZE (right);
6959 /* Unsigned or not an integral type - right fill with zeros */
6960 if (SPEC_USIGN (rtype) || !IS_SPEC (rtype) || AOP_TYPE(right)==AOP_CRY)
6963 aopPut (AOP (result), "!zero", offset++);
6967 /* we need to extend the sign :{ */
6968 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
6974 aopPut (AOP (result), "a", offset++);
6978 freeAsmop (right, NULL, ic);
6979 freeAsmop (result, NULL, ic);
6982 /*-----------------------------------------------------------------*/
6983 /* genReceive - generate code for a receive iCode */
6984 /*-----------------------------------------------------------------*/
6986 genReceive (iCode * ic)
6988 if (isOperandInFarSpace (IC_RESULT (ic)) &&
6989 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
6990 IS_TRUE_SYMOP (IC_RESULT (ic))))
7000 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7001 size = AOP_SIZE(IC_RESULT(ic));
7003 for (i = 0; i < size; i++) {
7004 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7008 freeAsmop (IC_RESULT (ic), NULL, ic);
7011 /*-----------------------------------------------------------------*/
7012 /* genDummyRead - generate code for dummy read of volatiles */
7013 /*-----------------------------------------------------------------*/
7015 genDummyRead (iCode * ic)
7017 emit2 ("; genDummyRead not implemented");
7024 /** Maximum number of bytes to emit per line. */
7028 /** Context for the byte output chunker. */
7031 unsigned char buffer[DBEMIT_MAX_RUN];
7036 /** Flushes a byte chunker by writing out all in the buffer and
7040 _dbFlush(DBEMITCTX *self)
7047 sprintf(line, ".db 0x%02X", self->buffer[0]);
7049 for (i = 1; i < self->pos; i++)
7051 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7058 /** Write out another byte, buffering until a decent line is
7062 _dbEmit(DBEMITCTX *self, int c)
7064 if (self->pos == DBEMIT_MAX_RUN)
7068 self->buffer[self->pos++] = c;
7071 /** Context for a simple run length encoder. */
7075 unsigned char buffer[128];
7077 /** runLen may be equivalent to pos. */
7083 RLE_CHANGE_COST = 4,
7087 /** Flush the buffer of a run length encoder by writing out the run or
7088 data that it currently contains.
7091 _rleCommit(RLECTX *self)
7097 memset(&db, 0, sizeof(db));
7099 emit2(".db %u", self->pos);
7101 for (i = 0; i < self->pos; i++)
7103 _dbEmit(&db, self->buffer[i]);
7112 Can get either a run or a block of random stuff.
7113 Only want to change state if a good run comes in or a run ends.
7114 Detecting run end is easy.
7117 Say initial state is in run, len zero, last zero. Then if you get a
7118 few zeros then something else then a short run will be output.
7119 Seems OK. While in run mode, keep counting. While in random mode,
7120 keep a count of the run. If run hits margin, output all up to run,
7121 restart, enter run mode.
7124 /** Add another byte into the run length encoder, flushing as
7125 required. The run length encoder uses the Amiga IFF style, where
7126 a block is prefixed by its run length. A positive length means
7127 the next n bytes pass straight through. A negative length means
7128 that the next byte is repeated -n times. A zero terminates the
7132 _rleAppend(RLECTX *self, int c)
7136 if (c != self->last)
7138 /* The run has stopped. See if it is worthwhile writing it out
7139 as a run. Note that the random data comes in as runs of
7142 if (self->runLen > RLE_CHANGE_COST)
7144 /* Yes, worthwhile. */
7145 /* Commit whatever was in the buffer. */
7147 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7151 /* Not worthwhile. Append to the end of the random list. */
7152 for (i = 0; i < self->runLen; i++)
7154 if (self->pos >= RLE_MAX_BLOCK)
7159 self->buffer[self->pos++] = self->last;
7167 if (self->runLen >= RLE_MAX_BLOCK)
7169 /* Commit whatever was in the buffer. */
7172 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7180 _rleFlush(RLECTX *self)
7182 _rleAppend(self, -1);
7189 /** genArrayInit - Special code for initialising an array with constant
7193 genArrayInit (iCode * ic)
7197 int elementSize = 0, eIndex, i;
7198 unsigned val, lastVal;
7202 memset(&rle, 0, sizeof(rle));
7204 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7206 _saveRegsForCall(ic, 0);
7208 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7209 emit2 ("call __initrleblock");
7211 type = operandType(IC_LEFT(ic));
7213 if (type && type->next)
7215 elementSize = getSize(type->next);
7219 wassertl (0, "Can't determine element size in genArrayInit.");
7222 iLoop = IC_ARRAYILIST(ic);
7223 lastVal = (unsigned)-1;
7225 /* Feed all the bytes into the run length encoder which will handle
7227 This works well for mixed char data, and for random int and long
7236 for (i = 0; i < ix; i++)
7238 for (eIndex = 0; eIndex < elementSize; eIndex++)
7240 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7241 _rleAppend(&rle, val);
7246 iLoop = iLoop->next;
7250 /* Mark the end of the run. */
7253 _restoreRegsAfterCall();
7257 freeAsmop (IC_LEFT(ic), NULL, ic);
7261 _swap (PAIR_ID one, PAIR_ID two)
7263 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7269 emit2 ("ld a,%s", _pairs[one].l);
7270 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7271 emit2 ("ld %s,a", _pairs[two].l);
7272 emit2 ("ld a,%s", _pairs[one].h);
7273 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7274 emit2 ("ld %s,a", _pairs[two].h);
7278 /* The problem is that we may have all three pairs used and they may
7279 be needed in a different order.
7284 hl = hl => unity, fine
7288 hl = hl hl = hl, swap de <=> bc
7296 hl = bc de = de, swap bc <=> hl
7304 hl = de bc = bc, swap hl <=> de
7309 * Any pair = pair are done last
7310 * Any pair = iTemp are done last
7311 * Any swaps can be done any time
7319 So how do we detect the cases?
7320 How about a 3x3 matrix?
7324 x x x x (Fourth for iTemp/other)
7326 First determin which mode to use by counting the number of unity and
7329 Two - Assign the pair first, then the rest
7330 One - Swap the two, then the rest
7334 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7336 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7338 PAIR_BC, PAIR_HL, PAIR_DE
7340 int i, j, nunity = 0;
7341 memset (ids, PAIR_INVALID, sizeof (ids));
7344 wassert (nparams == 3);
7346 /* First save everything that needs to be saved. */
7347 _saveRegsForCall (ic, 0);
7349 /* Loading HL first means that DE is always fine. */
7350 for (i = 0; i < nparams; i++)
7352 aopOp (pparams[i], ic, FALSE, FALSE);
7353 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7356 /* Count the number of unity or iTemp assigns. */
7357 for (i = 0; i < 3; i++)
7359 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7367 /* Any order, fall through. */
7369 else if (nunity == 2)
7371 /* One is assigned. Pull it out and assign. */
7372 for (i = 0; i < 3; i++)
7374 for (j = 0; j < NUM_PAIRS; j++)
7376 if (ids[dest[i]][j] == TRUE)
7378 /* Found it. See if it's the right one. */
7379 if (j == PAIR_INVALID || j == dest[i])
7385 fetchPair(dest[i], AOP (pparams[i]));
7392 else if (nunity == 1)
7394 /* Find the pairs to swap. */
7395 for (i = 0; i < 3; i++)
7397 for (j = 0; j < NUM_PAIRS; j++)
7399 if (ids[dest[i]][j] == TRUE)
7401 if (j == PAIR_INVALID || j == dest[i])
7416 int next = getPairId (AOP (pparams[0]));
7417 emit2 ("push %s", _pairs[next].name);
7419 if (next == dest[1])
7421 fetchPair (dest[1], AOP (pparams[1]));
7422 fetchPair (dest[2], AOP (pparams[2]));
7426 fetchPair (dest[2], AOP (pparams[2]));
7427 fetchPair (dest[1], AOP (pparams[1]));
7429 emit2 ("pop %s", _pairs[dest[0]].name);
7432 /* Finally pull out all of the iTemps */
7433 for (i = 0; i < 3; i++)
7435 if (ids[dest[i]][PAIR_INVALID] == 1)
7437 fetchPair (dest[i], AOP (pparams[i]));
7443 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
7449 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
7453 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7455 setupForBuiltin3 (ic, nParams, pparams);
7457 label = newiTempLabel(NULL);
7459 emitLabel (label->key);
7460 emit2 ("ld a,(hl)");
7463 emit2 ("!shortjp nz,!tlabel ; 1", label->key);
7465 freeAsmop (from, NULL, ic->next);
7466 freeAsmop (to, NULL, ic);
7470 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
7472 operand *from, *to, *count;
7475 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
7480 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7482 setupForBuiltin3 (ic, nParams, pparams);
7486 freeAsmop (count, NULL, ic->next->next);
7487 freeAsmop (from, NULL, ic);
7489 _restoreRegsAfterCall();
7491 /* if we need assign a result value */
7492 if ((IS_ITEMP (IC_RESULT (ic)) &&
7493 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
7494 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
7495 IS_TRUE_SYMOP (IC_RESULT (ic)))
7497 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7498 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
7499 freeAsmop (IC_RESULT (ic), NULL, ic);
7502 freeAsmop (to, NULL, ic->next);
7505 /*-----------------------------------------------------------------*/
7506 /* genBuiltIn - calls the appropriate function to generating code */
7507 /* for a built in function */
7508 /*-----------------------------------------------------------------*/
7509 static void genBuiltIn (iCode *ic)
7511 operand *bi_parms[MAX_BUILTIN_ARGS];
7516 /* get all the arguments for a built in function */
7517 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
7519 /* which function is it */
7520 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
7522 if (strcmp(bif->name,"__builtin_strcpy")==0)
7524 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
7526 else if (strcmp(bif->name,"__builtin_memcpy")==0)
7528 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
7532 wassertl (0, "Unknown builtin function encountered");
7536 /*-----------------------------------------------------------------*/
7537 /* genZ80Code - generate code for Z80 based controllers */
7538 /*-----------------------------------------------------------------*/
7540 genZ80Code (iCode * lic)
7548 _fReturn = _gbz80_return;
7549 _fTmp = _gbz80_return;
7553 _fReturn = _z80_return;
7554 _fTmp = _z80_return;
7557 _G.lines.head = _G.lines.current = NULL;
7559 for (ic = lic; ic; ic = ic->next)
7562 if (cln != ic->lineno)
7564 if (!options.noCcodeInAsm) {
7565 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
7566 printCLine(ic->filename, ic->lineno));
7570 if (options.iCodeInAsm) {
7571 emit2 (";ic:%d: %s", ic->key, printILine(ic));
7573 /* if the result is marked as
7574 spilt and rematerializable or code for
7575 this has already been generated then
7577 if (resultRemat (ic) || ic->generated)
7580 /* depending on the operation */
7584 emitDebug ("; genNot");
7589 emitDebug ("; genCpl");
7594 emitDebug ("; genUminus");
7599 emitDebug ("; genIpush");
7604 /* IPOP happens only when trying to restore a
7605 spilt live range, if there is an ifx statement
7606 following this pop then the if statement might
7607 be using some of the registers being popped which
7608 would destory the contents of the register so
7609 we need to check for this condition and handle it */
7611 ic->next->op == IFX &&
7612 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
7614 emitDebug ("; genIfx");
7615 genIfx (ic->next, ic);
7619 emitDebug ("; genIpop");
7625 emitDebug ("; genCall");
7630 emitDebug ("; genPcall");
7635 emitDebug ("; genFunction");
7640 emitDebug ("; genEndFunction");
7641 genEndFunction (ic);
7645 emitDebug ("; genRet");
7650 emitDebug ("; genLabel");
7655 emitDebug ("; genGoto");
7660 emitDebug ("; genPlus");
7665 emitDebug ("; genMinus");
7670 emitDebug ("; genMult");
7675 emitDebug ("; genDiv");
7680 emitDebug ("; genMod");
7685 emitDebug ("; genCmpGt");
7686 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
7690 emitDebug ("; genCmpLt");
7691 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
7698 /* note these two are xlated by algebraic equivalence
7699 during parsing SDCC.y */
7700 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
7701 "got '>=' or '<=' shouldn't have come here");
7705 emitDebug ("; genCmpEq");
7706 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
7710 emitDebug ("; genAndOp");
7715 emitDebug ("; genOrOp");
7720 emitDebug ("; genXor");
7721 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
7725 emitDebug ("; genOr");
7726 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
7730 emitDebug ("; genAnd");
7731 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
7735 emitDebug ("; genInline");
7740 emitDebug ("; genRRC");
7745 emitDebug ("; genRLC");
7750 emitDebug ("; genGetHBIT");
7755 emitDebug ("; genLeftShift");
7760 emitDebug ("; genRightShift");
7764 case GET_VALUE_AT_ADDRESS:
7765 emitDebug ("; genPointerGet");
7771 if (POINTER_SET (ic))
7773 emitDebug ("; genAssign (pointer)");
7778 emitDebug ("; genAssign");
7784 emitDebug ("; genIfx");
7789 emitDebug ("; genAddrOf");
7794 emitDebug ("; genJumpTab");
7799 emitDebug ("; genCast");
7804 emitDebug ("; genReceive");
7809 if (ic->builtinSEND)
7811 emitDebug ("; genBuiltIn");
7816 emitDebug ("; addSet");
7817 addSet (&_G.sendSet, ic);
7822 emitDebug ("; genArrayInit");
7826 case DUMMY_READ_VOLATILE:
7836 /* now we are ready to call the
7837 peep hole optimizer */
7838 if (!options.nopeep)
7839 peepHole (&_G.lines.head);
7841 /* This is unfortunate */
7842 /* now do the actual printing */
7844 FILE *fp = codeOutFile;
7845 if (isInHome () && codeOutFile == code->oFile)
7846 codeOutFile = home->oFile;
7847 printLine (_G.lines.head, codeOutFile);
7848 if (_G.flushStatics)
7851 _G.flushStatics = 0;
7856 freeTrace(&_G.lines.trace);
7857 freeTrace(&_G.trace.aops);
7863 _isPairUsed (iCode * ic, PAIR_ID pairId)
7869 if (bitVectBitValue (ic->rMask, D_IDX))
7871 if (bitVectBitValue (ic->rMask, E_IDX))
7881 fetchLitSpecial (asmop * aop, bool negate, bool xor)
7884 value *val = aop->aopu.aop_lit;
7886 wassert (aop->type == AOP_LIT);
7887 wassert (!IS_FLOAT (val->type));
7889 v = (unsigned long) floatFromVal (val);
7897 tsprintf (buffer, sizeof(buffer), "!immedword", v);
7898 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));