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)
400 char buffer[INITIAL_INLINEASM];
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 aop->size = getSize (sym->type);
1046 /* must be in a register */
1047 sym->aop = op->aop = aop = newAsmop (AOP_REG);
1048 aop->size = sym->nRegs;
1049 for (i = 0; i < sym->nRegs; i++)
1050 aop->aopu.aop_reg[i] = sym->regs[i];
1053 /*-----------------------------------------------------------------*/
1054 /* freeAsmop - free up the asmop given to an operand */
1055 /*----------------------------------------------------------------*/
1057 freeAsmop (operand * op, asmop * aaop, iCode * ic)
1074 if (aop->type == AOP_PAIRPTR && IS_Z80 && aop->aopu.aop_pairId == PAIR_DE)
1076 _pop (aop->aopu.aop_pairId);
1079 if (getPairId (aop) == PAIR_HL)
1081 spillPair (PAIR_HL);
1085 /* all other cases just dealloc */
1091 OP_SYMBOL (op)->aop = NULL;
1092 /* if the symbol has a spill */
1094 SPIL_LOC (op)->aop = NULL;
1101 isLitWord (asmop * aop)
1103 /* if (aop->size != 2)
1116 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
1118 /* depending on type */
1124 /* PENDING: for re-target */
1127 tsprintf (buffer, sizeof(buffer),
1128 "!hashedstr + %d", aop->aopu.aop_immd, offset);
1130 else if (offset == 0)
1132 tsprintf (buffer, sizeof(buffer),
1133 "%s", aop->aopu.aop_immd);
1137 tsprintf (buffer, sizeof(buffer),
1138 "%s + %d", aop->aopu.aop_immd, offset);
1140 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1144 value *val = aop->aopu.aop_lit;
1145 /* if it is a float then it gets tricky */
1146 /* otherwise it is fairly simple */
1147 if (!IS_FLOAT (val->type))
1149 unsigned long v = (unsigned long) floatFromVal (val);
1155 else if (offset == 0)
1161 wassertl(0, "Encountered an invalid offset while fetching a literal");
1165 tsprintf (buffer, sizeof(buffer), "!immedword", v);
1167 tsprintf (buffer, sizeof(buffer), "!constword", v);
1169 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1180 /* it is type float */
1181 fl.f = (float) floatFromVal (val);
1183 #ifdef WORDS_BIGENDIAN
1184 i = fl.c[3-offset] | (fl.c[3-offset-1]<<8);
1186 i = fl.c[offset] | (fl.c[offset+1]<<8);
1189 tsprintf (buffer, sizeof(buffer), "!immedword", i);
1191 tsprintf (buffer, sizeof(buffer), "!constword", i);
1193 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1202 aopGetWord (asmop * aop, int offset)
1204 return aopGetLitWordLong (aop, offset, TRUE);
1208 isPtr (const char *s)
1210 if (!strcmp (s, "hl"))
1212 if (!strcmp (s, "ix"))
1214 if (!strcmp (s, "iy"))
1220 adjustPair (const char *pair, int *pold, int new)
1226 emit2 ("inc %s", pair);
1231 emit2 ("dec %s", pair);
1239 spillPair (PAIR_HL);
1240 spillPair (PAIR_IY);
1244 requiresHL (asmop * aop)
1260 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1262 const char *l, *base;
1263 const char *pair = _pairs[pairId].name;
1264 l = aopGetLitWordLong (left, offset, FALSE);
1265 base = aopGetLitWordLong (left, 0, FALSE);
1266 wassert (l && pair && base);
1270 if (pairId == PAIR_HL || pairId == PAIR_IY)
1272 if (_G.pairs[pairId].last_type == left->type)
1274 if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1276 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1278 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1281 if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
1288 _G.pairs[pairId].last_type = left->type;
1289 _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1290 _G.pairs[pairId].offset = offset;
1292 /* Both a lit on the right and a true symbol on the left */
1293 emit2 ("ld %s,!hashedstr", pair, l);
1297 makeFreePairId (iCode *ic, bool *pisUsed)
1303 if (!bitVectBitValue (ic->rMask, B_IDX) && !bitVectBitValue(ic->rMask, C_IDX))
1307 else if (IS_Z80 && !bitVectBitValue (ic->rMask, D_IDX) && !bitVectBitValue(ic->rMask, E_IDX))
1325 fetchPairLong (PAIR_ID pairId, asmop * aop, iCode *ic, int offset)
1327 /* if this is remateriazable */
1328 if (isLitWord (aop)) {
1329 fetchLitPair (pairId, aop, offset);
1333 if (getPairId (aop) == pairId)
1337 /* we need to get it byte by byte */
1338 else if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1339 aopGet (aop, offset, FALSE);
1340 switch (aop->size - offset) {
1342 emit2 ("ld l,!*hl");
1343 emit2 ("ld h,!immedbyte", 0);
1346 // PENDING: Requires that you are only fetching two bytes.
1349 emit2 ("ld h,!*hl");
1353 wassertl (0, "Attempted to fetch too much data into HL");
1357 else if (IS_Z80 && aop->type == AOP_IY) {
1358 /* Instead of fetching relative to IY, just grab directly
1359 from the address IY refers to */
1360 char *l = aopGetLitWordLong (aop, offset, FALSE);
1362 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1364 if (aop->size < 2) {
1365 emit2("ld %s,!zero", _pairs[pairId].h);
1368 else if (pairId == PAIR_IY)
1372 emit2 ("push %s", _pairs[getPairId(aop)].name);
1378 PAIR_ID id = makeFreePairId (ic, &isUsed);
1381 /* Can't load into parts, so load into HL then exchange. */
1382 emit2 ("ld %s,%s", _pairs[id].l, aopGet (aop, offset, FALSE));
1383 emit2 ("ld %s,%s", _pairs[id].h, aopGet (aop, offset + 1, FALSE));
1384 emit2 ("push %s", _pairs[id].name);
1390 else if (isUnsplitable(aop))
1392 emit2("push %s", _pairs[getPairId(aop)].name);
1393 emit2("pop %s", _pairs[pairId].name);
1397 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1398 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1400 /* PENDING: check? */
1401 if (pairId == PAIR_HL)
1402 spillPair (PAIR_HL);
1407 fetchPair (PAIR_ID pairId, asmop * aop)
1409 fetchPairLong (pairId, aop, NULL, 0);
1413 fetchHL (asmop * aop)
1415 fetchPair (PAIR_HL, aop);
1419 setupPairFromSP (PAIR_ID id, int offset)
1421 wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
1423 if (offset < INT8MIN || offset > INT8MAX)
1425 emit2 ("ld hl,!immedword", offset);
1426 emit2 ("add hl,sp");
1430 emit2 ("!ldahlsp", offset);
1435 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1440 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
1441 fetchLitPair (pairId, aop, 0);
1445 wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
1447 fetchLitPair (pairId, aop, offset);
1448 _G.pairs[pairId].offset = offset;
1452 wassertl (IS_Z80, "Only the Z80 has an extended stack");
1453 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
1456 int offset = aop->aopu.aop_stk + _G.stack.offset;
1458 if (_G.pairs[pairId].last_type == aop->type &&
1459 _G.pairs[pairId].offset == offset)
1465 /* PENDING: Do this better. */
1466 sprintf (buffer, "%d", offset + _G.stack.pushed);
1467 emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
1468 emit2 ("add %s,sp", _pairs[pairId].name);
1469 _G.pairs[pairId].last_type = aop->type;
1470 _G.pairs[pairId].offset = offset;
1477 /* Doesnt include _G.stack.pushed */
1478 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1480 if (aop->aopu.aop_stk > 0)
1482 abso += _G.stack.param_offset;
1484 assert (pairId == PAIR_HL);
1485 /* In some cases we can still inc or dec hl */
1486 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1488 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1492 setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
1494 _G.pairs[pairId].offset = abso;
1499 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
1505 _G.pairs[pairId].last_type = aop->type;
1511 emit2 ("!tlabeldef", key);
1515 /*-----------------------------------------------------------------*/
1516 /* aopGet - for fetching value of the aop */
1517 /*-----------------------------------------------------------------*/
1519 aopGet (asmop * aop, int offset, bool bit16)
1521 // char *s = buffer;
1523 /* offset is greater than size then zero */
1524 /* PENDING: this seems a bit screwed in some pointer cases. */
1525 if (offset > (aop->size - 1) &&
1526 aop->type != AOP_LIT)
1528 tsprintf (buffer, sizeof(buffer), "!zero");
1529 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1532 /* depending on type */
1536 /* PENDING: re-target */
1538 tsprintf (buffer, sizeof(buffer), "!immedwords", aop->aopu.aop_immd);
1543 tsprintf (buffer, sizeof(buffer), "!bankimmeds", aop->aopu.aop_immd);
1546 tsprintf (buffer, sizeof(buffer), "!msbimmeds", aop->aopu.aop_immd);
1549 tsprintf (buffer, sizeof(buffer), "!lsbimmeds", aop->aopu.aop_immd);
1552 wassertl (0, "Fetching from beyond the limits of an immediate value.");
1555 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1559 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1560 SNPRINTF (buffer, sizeof(buffer), "a");
1562 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1566 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1567 SNPRINTF (buffer, sizeof(buffer), "a");
1569 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1572 return aop->aopu.aop_reg[offset]->name;
1576 setupPair (PAIR_HL, aop, offset);
1577 tsprintf (buffer, sizeof(buffer), "!*hl");
1579 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
1583 setupPair (PAIR_IY, aop, offset);
1584 tsprintf (buffer, sizeof(buffer), "!*iyx", offset);
1586 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1590 setupPair (PAIR_IY, aop, offset);
1591 tsprintf (buffer, sizeof(buffer), "!*iyx", offset, offset);
1593 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1598 setupPair (PAIR_HL, aop, offset);
1599 tsprintf (buffer, sizeof(buffer), "!*hl");
1603 if (aop->aopu.aop_stk >= 0)
1604 offset += _G.stack.param_offset;
1605 tsprintf (buffer, sizeof(buffer),
1606 "!*ixx", aop->aopu.aop_stk + offset);
1609 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1612 wassertl (0, "Tried to fetch from a bit variable");
1621 tsprintf(buffer, sizeof(buffer), "!zero");
1622 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1626 wassert (offset < 2);
1627 return aop->aopu.aop_str[offset];
1630 return aopLiteral (aop->aopu.aop_lit, offset);
1634 unsigned long v = aop->aopu.aop_simplelit;
1637 tsprintf (buffer, sizeof(buffer),
1638 "!immedbyte", (unsigned int) v & 0xff);
1640 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1644 return aop->aopu.aop_str[offset];
1647 setupPair (aop->aopu.aop_pairId, aop, offset);
1648 SNPRINTF (buffer, sizeof(buffer),
1649 "(%s)", _pairs[aop->aopu.aop_pairId].name);
1651 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1656 wassertl (0, "aopget got unsupported aop->type");
1661 isRegString (const char *s)
1663 if (!strcmp (s, "b") ||
1675 isConstant (const char *s)
1677 /* This is a bit of a hack... */
1678 return (*s == '#' || *s == '$');
1682 canAssignToPtr (const char *s)
1684 if (isRegString (s))
1691 /*-----------------------------------------------------------------*/
1692 /* aopPut - puts a string for a aop */
1693 /*-----------------------------------------------------------------*/
1695 aopPut (asmop * aop, const char *s, int offset)
1699 if (aop->size && offset > (aop->size - 1))
1701 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1702 "aopPut got offset > aop->size");
1707 tsprintf(buffer2, sizeof(buffer2), s);
1710 /* will assign value to value */
1711 /* depending on where it is ofcourse */
1717 if (strcmp (s, "a"))
1718 emit2 ("ld a,%s", s);
1719 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1724 if (strcmp (s, "a"))
1725 emit2 ("ld a,%s", s);
1726 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1730 if (!strcmp (s, "!*hl"))
1731 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1734 aop->aopu.aop_reg[offset]->name, s);
1735 spillPairReg(aop->aopu.aop_reg[offset]->name);
1740 if (!canAssignToPtr (s))
1742 emit2 ("ld a,%s", s);
1743 setupPair (PAIR_IY, aop, offset);
1744 emit2 ("ld !*iyx,a", offset);
1748 setupPair (PAIR_IY, aop, offset);
1749 emit2 ("ld !*iyx,%s", offset, s);
1755 /* PENDING: for re-target */
1756 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1758 emit2 ("ld a,!*hl");
1761 setupPair (PAIR_HL, aop, offset);
1763 emit2 ("ld !*hl,%s", s);
1768 if (!canAssignToPtr (s))
1770 emit2 ("ld a,%s", s);
1771 setupPair (PAIR_IY, aop, offset);
1772 emit2 ("ld !*iyx,a", offset);
1776 setupPair (PAIR_IY, aop, offset);
1777 emit2 ("ld !*iyx,%s", offset, s);
1784 /* PENDING: re-target */
1785 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1787 emit2 ("ld a,!*hl");
1790 setupPair (PAIR_HL, aop, offset);
1791 if (!canAssignToPtr (s))
1793 emit2 ("ld a,%s", s);
1794 emit2 ("ld !*hl,a");
1797 emit2 ("ld !*hl,%s", s);
1801 if (aop->aopu.aop_stk >= 0)
1802 offset += _G.stack.param_offset;
1803 if (!canAssignToPtr (s))
1805 emit2 ("ld a,%s", s);
1806 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
1810 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
1816 /* if bit variable */
1817 if (!aop->aopu.aop_dir)
1819 emit2 ("ld a,!zero");
1824 /* In bit space but not in C - cant happen */
1825 wassertl (0, "Tried to write into a bit variable");
1831 if (strcmp (aop->aopu.aop_str[offset], s))
1833 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1835 spillPairReg(aop->aopu.aop_str[offset]);
1840 if (!offset && (strcmp (s, "acc") == 0))
1844 wassertl (0, "Tried to access past the end of A");
1848 if (strcmp (aop->aopu.aop_str[offset], s))
1850 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1851 spillPairReg(aop->aopu.aop_str[offset]);
1857 wassert (offset < 2);
1858 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1859 spillPairReg(aop->aopu.aop_str[offset]);
1863 setupPair (aop->aopu.aop_pairId, aop, offset);
1864 emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
1868 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1869 "aopPut got unsupported aop->type");
1874 #define AOP(op) op->aop
1875 #define AOP_TYPE(op) AOP(op)->type
1876 #define AOP_SIZE(op) AOP(op)->size
1877 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
1880 commitPair (asmop * aop, PAIR_ID id)
1882 /* PENDING: Verify this. */
1883 if (id == PAIR_HL && requiresHL (aop) && IS_GB)
1887 aopPut (aop, "a", 0);
1888 aopPut (aop, "d", 1);
1893 if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
1895 char *l = aopGetLitWordLong (aop, 0, FALSE);
1898 emit2 ("ld (%s),%s", l, _pairs[id].name);
1902 aopPut (aop, _pairs[id].l, 0);
1903 aopPut (aop, _pairs[id].h, 1);
1908 /*-----------------------------------------------------------------*/
1909 /* getDataSize - get the operand data size */
1910 /*-----------------------------------------------------------------*/
1912 getDataSize (operand * op)
1915 size = AOP_SIZE (op);
1919 wassertl (0, "Somehow got a three byte data pointer");
1924 /*-----------------------------------------------------------------*/
1925 /* movLeft2Result - move byte from left to result */
1926 /*-----------------------------------------------------------------*/
1928 movLeft2Result (operand * left, int offl,
1929 operand * result, int offr, int sign)
1933 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
1935 l = aopGet (AOP (left), offl, FALSE);
1939 aopPut (AOP (result), l, offr);
1943 if (getDataSize (left) == offl + 1)
1945 emit2 ("ld a,%s", l);
1946 aopPut (AOP (result), "a", offr);
1953 movLeft2ResultLong (operand * left, int offl,
1954 operand * result, int offr, int sign,
1959 movLeft2Result (left, offl, result, offr, sign);
1963 wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
1964 wassertl (size == 2, "Only implemented for two bytes or one");
1966 if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
1968 emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
1969 emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
1971 spillPair (PAIR_HL);
1973 else if ( getPairId ( AOP (result)) == PAIR_IY)
1975 PAIR_ID id = getPairId (AOP (left));
1976 if (id != PAIR_INVALID)
1978 emit2("push %s", _pairs[id].name);
1989 movLeft2Result (left, offl, result, offr, sign);
1990 movLeft2Result (left, offl+1, result, offr+1, sign);
1995 /** Put Acc into a register set
1998 outAcc (operand * result)
2001 size = getDataSize (result);
2004 aopPut (AOP (result), "a", 0);
2007 /* unsigned or positive */
2010 aopPut (AOP (result), "!zero", offset++);
2015 /** Take the value in carry and put it into a register
2018 outBitCLong (operand * result, bool swap_sense)
2020 /* if the result is bit */
2021 if (AOP_TYPE (result) == AOP_CRY)
2023 wassertl (0, "Tried to write carry to a bit");
2027 emit2 ("ld a,!zero");
2030 emit2 ("xor a,!immedbyte", 1);
2036 outBitC (operand * result)
2038 outBitCLong (result, FALSE);
2041 /*-----------------------------------------------------------------*/
2042 /* toBoolean - emit code for orl a,operator(sizeop) */
2043 /*-----------------------------------------------------------------*/
2045 _toBoolean (operand * oper)
2047 int size = AOP_SIZE (oper);
2051 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
2054 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
2058 if (AOP (oper)->type != AOP_ACC)
2061 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
2067 /*-----------------------------------------------------------------*/
2068 /* genNot - generate code for ! operation */
2069 /*-----------------------------------------------------------------*/
2074 /* assign asmOps to operand & result */
2075 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
2076 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2078 /* if in bit space then a special case */
2079 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2081 wassertl (0, "Tried to negate a bit");
2084 _toBoolean (IC_LEFT (ic));
2089 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
2090 emit2 ("sub a,!one");
2091 outBitC (IC_RESULT (ic));
2093 /* release the aops */
2094 freeAsmop (IC_LEFT (ic), NULL, ic);
2095 freeAsmop (IC_RESULT (ic), NULL, ic);
2098 /*-----------------------------------------------------------------*/
2099 /* genCpl - generate code for complement */
2100 /*-----------------------------------------------------------------*/
2108 /* assign asmOps to operand & result */
2109 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2110 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2112 /* if both are in bit space then
2114 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2115 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2117 wassertl (0, "Left and the result are in bit space");
2120 size = AOP_SIZE (IC_RESULT (ic));
2123 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2126 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2129 /* release the aops */
2130 freeAsmop (IC_LEFT (ic), NULL, ic);
2131 freeAsmop (IC_RESULT (ic), NULL, ic);
2135 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
2142 store de into result
2147 store de into result
2149 const char *first = isAdd ? "add" : "sub";
2150 const char *later = isAdd ? "adc" : "sbc";
2152 wassertl (IS_GB, "Code is only relevent to the gbz80");
2153 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
2155 fetchPair (PAIR_DE, left);
2158 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
2161 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2164 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2165 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2167 fetchPairLong (PAIR_DE, left, NULL, MSB24);
2168 aopGet (right, MSB24, FALSE);
2172 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2175 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2177 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2178 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2182 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2184 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2187 /*-----------------------------------------------------------------*/
2188 /* genUminusFloat - unary minus for floating points */
2189 /*-----------------------------------------------------------------*/
2191 genUminusFloat (operand * op, operand * result)
2193 int size, offset = 0;
2195 emitDebug("; genUminusFloat");
2197 /* for this we just need to flip the
2198 first it then copy the rest in place */
2199 size = AOP_SIZE (op) - 1;
2201 _moveA(aopGet (AOP (op), MSB32, FALSE));
2203 emit2("xor a,!immedbyte", 0x80);
2204 aopPut (AOP (result), "a", MSB32);
2208 aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2213 /*-----------------------------------------------------------------*/
2214 /* genUminus - unary minus code generation */
2215 /*-----------------------------------------------------------------*/
2217 genUminus (iCode * ic)
2220 sym_link *optype, *rtype;
2223 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2224 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2226 /* if both in bit space then special
2228 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2229 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2231 wassertl (0, "Left and right are in bit space");
2235 optype = operandType (IC_LEFT (ic));
2236 rtype = operandType (IC_RESULT (ic));
2238 /* if float then do float stuff */
2239 if (IS_FLOAT (optype))
2241 genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2245 /* otherwise subtract from zero */
2246 size = AOP_SIZE (IC_LEFT (ic));
2248 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2250 /* Create a new asmop with value zero */
2251 asmop *azero = newAsmop (AOP_SIMPLELIT);
2252 azero->aopu.aop_simplelit = 0;
2254 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2262 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2263 emit2 ("ld a,!zero");
2264 emit2 ("sbc a,%s", l);
2265 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2268 /* if any remaining bytes in the result */
2269 /* we just need to propagate the sign */
2270 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2275 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2279 /* release the aops */
2280 freeAsmop (IC_LEFT (ic), NULL, ic);
2281 freeAsmop (IC_RESULT (ic), NULL, ic);
2284 /*-----------------------------------------------------------------*/
2285 /* assignResultValue - */
2286 /*-----------------------------------------------------------------*/
2288 assignResultValue (operand * oper)
2290 int size = AOP_SIZE (oper);
2293 wassertl (size <= 4, "Got a result that is bigger than four bytes");
2294 topInA = requiresHL (AOP (oper));
2296 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2298 /* We do it the hard way here. */
2300 aopPut (AOP (oper), _fReturn[0], 0);
2301 aopPut (AOP (oper), _fReturn[1], 1);
2303 aopPut (AOP (oper), _fReturn[0], 2);
2304 aopPut (AOP (oper), _fReturn[1], 3);
2310 aopPut (AOP (oper), _fReturn[size], size);
2315 /** Simple restore that doesn't take into account what is used in the
2319 _restoreRegsAfterCall(void)
2321 if (_G.stack.pushedDE)
2324 _G.stack.pushedDE = FALSE;
2326 if (_G.stack.pushedBC)
2329 _G.stack.pushedBC = FALSE;
2331 _G.saves.saved = FALSE;
2335 _saveRegsForCall(iCode *ic, int sendSetSize)
2338 o Stack parameters are pushed before this function enters
2339 o DE and BC may be used in this function.
2340 o HL and DE may be used to return the result.
2341 o HL and DE may be used to send variables.
2342 o DE and BC may be used to store the result value.
2343 o HL may be used in computing the sent value of DE
2344 o The iPushes for other parameters occur before any addSets
2346 Logic: (to be run inside the first iPush or if none, before sending)
2347 o Compute if DE and/or BC are in use over the call
2348 o Compute if DE is used in the send set
2349 o Compute if DE and/or BC are used to hold the result value
2350 o If (DE is used, or in the send set) and is not used in the result, push.
2351 o If BC is used and is not in the result, push
2353 o If DE is used in the send set, fetch
2354 o If HL is used in the send set, fetch
2358 if (_G.saves.saved == FALSE) {
2359 bool deInUse, bcInUse;
2361 bool bcInRet = FALSE, deInRet = FALSE;
2364 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
2366 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2367 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2369 deSending = (sendSetSize > 1);
2371 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2373 if (bcInUse && bcInRet == FALSE) {
2375 _G.stack.pushedBC = TRUE;
2377 if (deInUse && deInRet == FALSE) {
2379 _G.stack.pushedDE = TRUE;
2382 _G.saves.saved = TRUE;
2385 /* Already saved. */
2389 /*-----------------------------------------------------------------*/
2390 /* genIpush - genrate code for pushing this gets a little complex */
2391 /*-----------------------------------------------------------------*/
2393 genIpush (iCode * ic)
2395 int size, offset = 0;
2398 /* if this is not a parm push : ie. it is spill push
2399 and spill push is always done on the local stack */
2402 wassertl(0, "Encountered an unsupported spill push.");
2406 if (_G.saves.saved == FALSE) {
2407 /* Caller saves, and this is the first iPush. */
2408 /* Scan ahead until we find the function that we are pushing parameters to.
2409 Count the number of addSets on the way to figure out what registers
2410 are used in the send set.
2413 iCode *walk = ic->next;
2416 if (walk->op == SEND) {
2419 else if (walk->op == CALL || walk->op == PCALL) {
2428 _saveRegsForCall(walk, nAddSets);
2431 /* Already saved by another iPush. */
2434 /* then do the push */
2435 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2437 size = AOP_SIZE (IC_LEFT (ic));
2439 if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2441 _G.stack.pushed += 2;
2442 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2448 fetchHL (AOP (IC_LEFT (ic)));
2450 spillPair (PAIR_HL);
2451 _G.stack.pushed += 2;
2456 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
2458 spillPair (PAIR_HL);
2459 _G.stack.pushed += 2;
2460 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
2462 spillPair (PAIR_HL);
2463 _G.stack.pushed += 2;
2469 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2471 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2473 emit2 ("ld a,(%s)", l);
2477 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2478 emit2 ("ld a,%s", l);
2486 freeAsmop (IC_LEFT (ic), NULL, ic);
2489 /*-----------------------------------------------------------------*/
2490 /* genIpop - recover the registers: can happen only for spilling */
2491 /*-----------------------------------------------------------------*/
2493 genIpop (iCode * ic)
2498 /* if the temp was not pushed then */
2499 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2502 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2503 size = AOP_SIZE (IC_LEFT (ic));
2504 offset = (size - 1);
2505 if (isPair (AOP (IC_LEFT (ic))))
2507 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2515 spillPair (PAIR_HL);
2516 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2520 freeAsmop (IC_LEFT (ic), NULL, ic);
2523 /* This is quite unfortunate */
2525 setArea (int inHome)
2528 static int lastArea = 0;
2530 if (_G.in_home != inHome) {
2532 const char *sz = port->mem.code_name;
2533 port->mem.code_name = "HOME";
2534 emit2("!area", CODE_NAME);
2535 port->mem.code_name = sz;
2538 emit2("!area", CODE_NAME); */
2539 _G.in_home = inHome;
2550 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2554 symbol *sym = OP_SYMBOL (op);
2556 if (sym->isspilt || sym->nRegs == 0)
2559 aopOp (op, ic, FALSE, FALSE);
2562 if (aop->type == AOP_REG)
2565 for (i = 0; i < aop->size; i++)
2567 if (pairId == PAIR_DE)
2569 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2570 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2572 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2575 else if (pairId == PAIR_BC)
2577 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2578 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2580 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2590 freeAsmop (IC_LEFT (ic), NULL, ic);
2594 /** Emit the code for a call statement
2597 emitCall (iCode * ic, bool ispcall)
2599 sym_link *dtype = operandType (IC_LEFT (ic));
2601 /* if caller saves & we have not saved then */
2607 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2609 /* if send set is not empty then assign */
2614 int nSend = elementsInSet(_G.sendSet);
2615 bool swapped = FALSE;
2617 int _z80_sendOrder[] = {
2622 /* Check if the parameters are swapped. If so route through hl instead. */
2623 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2625 sic = setFirstItem(_G.sendSet);
2626 sic = setNextItem(_G.sendSet);
2628 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2629 /* The second send value is loaded from one the one that holds the first
2630 send, i.e. it is overwritten. */
2631 /* Cache the first in HL, and load the second from HL instead. */
2632 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2633 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2639 for (sic = setFirstItem (_G.sendSet); sic;
2640 sic = setNextItem (_G.sendSet))
2643 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2645 size = AOP_SIZE (IC_LEFT (sic));
2646 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2647 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2649 // PENDING: Mild hack
2650 if (swapped == TRUE && send == 1) {
2652 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2655 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2657 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2660 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2664 freeAsmop (IC_LEFT (sic), NULL, sic);
2671 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2673 werror (W_INDIR_BANKED);
2675 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2677 if (isLitWord (AOP (IC_LEFT (ic))))
2679 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2683 symbol *rlbl = newiTempLabel (NULL);
2684 spillPair (PAIR_HL);
2685 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2687 _G.stack.pushed += 2;
2689 fetchHL (AOP (IC_LEFT (ic)));
2691 emit2 ("!tlabeldef", (rlbl->key + 100));
2692 _G.stack.pushed -= 2;
2694 freeAsmop (IC_LEFT (ic), NULL, ic);
2698 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2699 OP_SYMBOL (IC_LEFT (ic))->rname :
2700 OP_SYMBOL (IC_LEFT (ic))->name;
2701 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2703 emit2 ("call banked_call");
2704 emit2 ("!dws", name);
2705 emit2 ("!dw !bankimmeds", name);
2710 emit2 ("call %s", name);
2715 /* Mark the regsiters as restored. */
2716 _G.saves.saved = FALSE;
2718 /* if we need assign a result value */
2719 if ((IS_ITEMP (IC_RESULT (ic)) &&
2720 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2721 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2722 IS_TRUE_SYMOP (IC_RESULT (ic)))
2725 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2727 assignResultValue (IC_RESULT (ic));
2729 freeAsmop (IC_RESULT (ic), NULL, ic);
2732 /* adjust the stack for parameters if required */
2735 int i = ic->parmBytes;
2737 _G.stack.pushed -= i;
2740 emit2 ("!ldaspsp", i);
2747 emit2 ("ld iy,!immedword", i);
2748 emit2 ("add iy,sp");
2768 if (_G.stack.pushedDE)
2770 bool dInRet = bitVectBitValue(ic->rUsed, D_IDX);
2771 bool eInRet = bitVectBitValue(ic->rUsed, E_IDX);
2773 if (dInRet && eInRet)
2775 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
2779 /* Only restore E */
2786 /* Only restore D */
2794 _G.stack.pushedDE = FALSE;
2797 if (_G.stack.pushedBC)
2799 bool bInRet = bitVectBitValue(ic->rUsed, B_IDX);
2800 bool cInRet = bitVectBitValue(ic->rUsed, C_IDX);
2802 if (bInRet && cInRet)
2804 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
2808 /* Only restore C */
2815 /* Only restore B */
2823 _G.stack.pushedBC = FALSE;
2827 /*-----------------------------------------------------------------*/
2828 /* genCall - generates a call statement */
2829 /*-----------------------------------------------------------------*/
2831 genCall (iCode * ic)
2833 emitCall (ic, FALSE);
2836 /*-----------------------------------------------------------------*/
2837 /* genPcall - generates a call by pointer statement */
2838 /*-----------------------------------------------------------------*/
2840 genPcall (iCode * ic)
2842 emitCall (ic, TRUE);
2845 /*-----------------------------------------------------------------*/
2846 /* resultRemat - result is rematerializable */
2847 /*-----------------------------------------------------------------*/
2849 resultRemat (iCode * ic)
2851 if (SKIP_IC (ic) || ic->op == IFX)
2854 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2856 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2857 if (sym->remat && !POINTER_SET (ic))
2864 extern set *publics;
2866 /*-----------------------------------------------------------------*/
2867 /* genFunction - generated code for function entry */
2868 /*-----------------------------------------------------------------*/
2870 genFunction (iCode * ic)
2874 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2877 bool bcInUse = FALSE;
2878 bool deInUse = FALSE;
2880 setArea (IFFUNC_NONBANKED (sym->type));
2882 /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
2885 _G.receiveOffset = 0;
2887 /* Record the last function name for debugging. */
2888 _G.lastFunctionName = sym->rname;
2890 /* Create the function header */
2891 emit2 ("!functionheader", sym->name);
2892 sprintf (buffer, "%s_start", sym->rname);
2893 emit2 ("!labeldef", buffer);
2894 emit2 ("!functionlabeldef", sym->rname);
2896 if (options.profile)
2898 emit2 ("!profileenter");
2901 ftype = operandType (IC_LEFT (ic));
2903 /* if critical function then turn interrupts off */
2904 if (IFFUNC_ISCRITICAL (ftype))
2907 /* if this is an interrupt service routine then save all potentially used registers. */
2908 if (IFFUNC_ISISR (sym->type))
2913 /* PENDING: callee-save etc */
2915 _G.stack.param_offset = 0;
2917 if (z80_opts.calleeSavesBC)
2922 /* Detect which registers are used. */
2923 if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
2926 for (i = 0; i < sym->regsUsed->size; i++)
2928 if (bitVectBitValue (sym->regsUsed, i))
2942 /* Other systems use DE as a temporary. */
2953 _G.stack.param_offset += 2;
2956 _G.calleeSaves.pushedBC = bcInUse;
2961 _G.stack.param_offset += 2;
2964 _G.calleeSaves.pushedDE = deInUse;
2966 /* adjust the stack for the function */
2967 _G.stack.last = sym->stack;
2970 for (sym = setFirstItem (istack->syms); sym;
2971 sym = setNextItem (istack->syms))
2973 if (sym->_isparm && !IS_REGPARM (sym->etype))
2979 sym = OP_SYMBOL (IC_LEFT (ic));
2981 _G.omitFramePtr = options.ommitFramePtr;
2982 if (IS_Z80 && !stackParm && !sym->stack)
2984 /* When the conflicts between AOP_EXSTK && AOP_HLREG are fixed, */
2985 /* the above !sym->stack condition can be removed. -- EEP */
2987 emit2 ("!ldaspsp", -sym->stack);
2988 _G.omitFramePtr = TRUE;
2990 else if (sym->stack && IS_GB && sym->stack > -INT8MIN)
2991 emit2 ("!enterxl", sym->stack);
2992 else if (sym->stack)
2993 emit2 ("!enterx", sym->stack);
2996 _G.stack.offset = sym->stack;
2999 /*-----------------------------------------------------------------*/
3000 /* genEndFunction - generates epilogue for functions */
3001 /*-----------------------------------------------------------------*/
3003 genEndFunction (iCode * ic)
3005 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3007 if (IFFUNC_ISISR (sym->type))
3009 wassertl (0, "Tried to close an interrupt support function");
3013 if (IFFUNC_ISCRITICAL (sym->type))
3016 /* PENDING: calleeSave */
3018 if (IS_Z80 && _G.omitFramePtr)
3020 if (_G.stack.offset)
3021 emit2 ("!ldaspsp", _G.stack.offset);
3023 else if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
3025 emit2 ("!leavexl", _G.stack.offset);
3027 else if (_G.stack.offset)
3029 emit2 ("!leavex", _G.stack.offset);
3036 if (_G.calleeSaves.pushedDE)
3039 _G.calleeSaves.pushedDE = FALSE;
3042 if (_G.calleeSaves.pushedBC)
3045 _G.calleeSaves.pushedBC = FALSE;
3048 if (options.profile)
3050 emit2 ("!profileexit");
3054 /* Both baned and non-banked just ret */
3057 sprintf (buffer, "%s_end", sym->rname);
3058 emit2 ("!labeldef", buffer);
3060 _G.flushStatics = 1;
3061 _G.stack.pushed = 0;
3062 _G.stack.offset = 0;
3065 /*-----------------------------------------------------------------*/
3066 /* genRet - generate code for return statement */
3067 /*-----------------------------------------------------------------*/
3072 /* Errk. This is a hack until I can figure out how
3073 to cause dehl to spill on a call */
3074 int size, offset = 0;
3076 /* if we have no return value then
3077 just generate the "ret" */
3081 /* we have something to return then
3082 move the return value into place */
3083 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3084 size = AOP_SIZE (IC_LEFT (ic));
3086 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3090 emit2 ("ld de,%s", l);
3094 emit2 ("ld hl,%s", l);
3099 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3101 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3102 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3108 l = aopGet (AOP (IC_LEFT (ic)), offset,
3110 if (strcmp (_fReturn[offset], l))
3111 emit2 ("ld %s,%s", _fReturn[offset++], l);
3115 freeAsmop (IC_LEFT (ic), NULL, ic);
3118 /* generate a jump to the return label
3119 if the next is not the return statement */
3120 if (!(ic->next && ic->next->op == LABEL &&
3121 IC_LABEL (ic->next) == returnLabel))
3123 emit2 ("jp !tlabel", returnLabel->key + 100);
3126 /*-----------------------------------------------------------------*/
3127 /* genLabel - generates a label */
3128 /*-----------------------------------------------------------------*/
3130 genLabel (iCode * ic)
3132 /* special case never generate */
3133 if (IC_LABEL (ic) == entryLabel)
3136 emitLabel (IC_LABEL (ic)->key + 100);
3139 /*-----------------------------------------------------------------*/
3140 /* genGoto - generates a ljmp */
3141 /*-----------------------------------------------------------------*/
3143 genGoto (iCode * ic)
3145 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3148 /*-----------------------------------------------------------------*/
3149 /* genPlusIncr :- does addition with increment if possible */
3150 /*-----------------------------------------------------------------*/
3152 genPlusIncr (iCode * ic)
3154 unsigned int icount;
3155 unsigned int size = getDataSize (IC_RESULT (ic));
3156 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3158 /* will try to generate an increment */
3159 /* if the right side is not a literal
3161 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3164 emitDebug ("; genPlusIncr");
3166 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3168 /* If result is a pair */
3169 if (resultId != PAIR_INVALID)
3171 if (isLitWord (AOP (IC_LEFT (ic))))
3173 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3176 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3178 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3180 PAIR_ID freep = getFreePairId (ic);
3181 if (freep != PAIR_INVALID)
3183 fetchPair (freep, AOP (IC_RIGHT (ic)));
3184 emit2 ("add hl,%s", _pairs[freep].name);
3190 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3191 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3198 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3202 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3206 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3211 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3213 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3214 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3218 /* if the literal value of the right hand side
3219 is greater than 4 then it is not worth it */
3223 /* if increment 16 bits in register */
3224 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3230 symbol *tlbl = NULL;
3231 tlbl = newiTempLabel (NULL);
3234 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3237 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3240 emitLabel (tlbl->key + 100);
3244 /* if the sizes are greater than 1 then we cannot */
3245 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3246 AOP_SIZE (IC_LEFT (ic)) > 1)
3249 /* If the result is in a register then we can load then increment.
3251 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3253 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3256 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3261 /* we can if the aops of the left & result match or
3262 if they are in registers and the registers are the
3264 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3268 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3276 /*-----------------------------------------------------------------*/
3277 /* outBitAcc - output a bit in acc */
3278 /*-----------------------------------------------------------------*/
3280 outBitAcc (operand * result)
3282 symbol *tlbl = newiTempLabel (NULL);
3283 /* if the result is a bit */
3284 if (AOP_TYPE (result) == AOP_CRY)
3286 wassertl (0, "Tried to write A into a bit");
3290 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3291 emit2 ("ld a,!one");
3292 emitLabel (tlbl->key + 100);
3298 couldDestroyCarry (asmop *aop)
3302 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3311 shiftIntoPair (int idx, asmop *aop)
3313 PAIR_ID id = PAIR_INVALID;
3315 wassertl (IS_Z80, "Only implemented for the Z80");
3316 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3328 wassertl (0, "Internal error - hit default case");
3331 emitDebug ("; Shift into pair idx %u", idx);
3335 setupPair (PAIR_HL, aop, 0);
3339 setupPair (PAIR_IY, aop, 0);
3341 emit2 ("pop %s", _pairs[id].name);
3344 aop->type = AOP_PAIRPTR;
3345 aop->aopu.aop_pairId = id;
3346 _G.pairs[id].offset = 0;
3347 _G.pairs[id].last_type = aop->type;
3351 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
3353 wassert (left && right);
3357 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3359 shiftIntoPair (0, right);
3360 shiftIntoPair (1, result);
3362 else if (couldDestroyCarry (right))
3364 shiftIntoPair (0, right);
3366 else if (couldDestroyCarry (result))
3368 shiftIntoPair (0, result);
3377 /*-----------------------------------------------------------------*/
3378 /* genPlus - generates code for addition */
3379 /*-----------------------------------------------------------------*/
3381 genPlus (iCode * ic)
3383 int size, offset = 0;
3385 /* special cases :- */
3387 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3388 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3389 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3391 /* Swap the left and right operands if:
3393 if literal, literal on the right or
3394 if left requires ACC or right is already
3397 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3398 (AOP_NEEDSACC (IC_LEFT (ic))) ||
3399 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3401 operand *t = IC_RIGHT (ic);
3402 IC_RIGHT (ic) = IC_LEFT (ic);
3406 /* if both left & right are in bit
3408 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3409 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3412 wassertl (0, "Tried to add two bits");
3415 /* if left in bit space & right literal */
3416 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3417 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3419 /* Can happen I guess */
3420 wassertl (0, "Tried to add a bit to a literal");
3423 /* if I can do an increment instead
3424 of add then GOOD for ME */
3425 if (genPlusIncr (ic) == TRUE)
3428 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3430 size = getDataSize (IC_RESULT (ic));
3432 /* Special case when left and right are constant */
3433 if (isPair (AOP (IC_RESULT (ic))))
3436 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3437 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3439 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3445 sprintf (buffer, "#(%s + %s)", left, right);
3446 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3451 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3453 /* Fetch into HL then do the add */
3454 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3455 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3457 spillPair (PAIR_HL);
3459 if (left == PAIR_HL && right != PAIR_INVALID)
3461 emit2 ("add hl,%s", _pairs[right].name);
3464 else if (right == PAIR_HL && left != PAIR_INVALID)
3466 emit2 ("add hl,%s", _pairs[left].name);
3469 else if (right != PAIR_INVALID && right != PAIR_HL)
3471 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3472 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3475 else if (left != PAIR_INVALID && left != PAIR_HL)
3477 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3478 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3487 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3489 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3490 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3492 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3497 ld hl,sp+n trashes C so we cant afford to do it during an
3498 add with stack based varibles. Worst case is:
3511 So you cant afford to load up hl if either left, right, or result
3512 is on the stack (*sigh*) The alt is:
3520 Combinations in here are:
3521 * If left or right are in bc then the loss is small - trap later
3522 * If the result is in bc then the loss is also small
3526 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3527 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3528 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3530 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3531 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3532 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3533 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3535 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3537 /* Swap left and right */
3538 operand *t = IC_RIGHT (ic);
3539 IC_RIGHT (ic) = IC_LEFT (ic);
3542 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3544 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3545 emit2 ("add hl,bc");
3549 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3550 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3551 emit2 ("add hl,de");
3553 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3559 /* Be paranoid on the GB with 4 byte variables due to how C
3560 can be trashed by lda hl,n(sp).
3562 _gbz80_emitAddSubLong (ic, TRUE);
3567 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3571 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3573 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3576 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3579 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3583 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3586 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3589 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3591 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3595 freeAsmop (IC_LEFT (ic), NULL, ic);
3596 freeAsmop (IC_RIGHT (ic), NULL, ic);
3597 freeAsmop (IC_RESULT (ic), NULL, ic);
3601 /*-----------------------------------------------------------------*/
3602 /* genMinusDec :- does subtraction with deccrement if possible */
3603 /*-----------------------------------------------------------------*/
3605 genMinusDec (iCode * ic)
3607 unsigned int icount;
3608 unsigned int size = getDataSize (IC_RESULT (ic));
3610 /* will try to generate an increment */
3611 /* if the right side is not a literal we cannot */
3612 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3615 /* if the literal value of the right hand side
3616 is greater than 4 then it is not worth it */
3617 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3620 size = getDataSize (IC_RESULT (ic));
3622 /* if decrement 16 bits in register */
3623 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3624 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3627 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3631 /* If result is a pair */
3632 if (isPair (AOP (IC_RESULT (ic))))
3634 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3636 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3640 /* if increment 16 bits in register */
3641 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3645 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3648 emit2 ("dec %s", _getTempPairName());
3651 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3657 /* if the sizes are greater than 1 then we cannot */
3658 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3659 AOP_SIZE (IC_LEFT (ic)) > 1)
3662 /* we can if the aops of the left & result match or if they are in
3663 registers and the registers are the same */
3664 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3667 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3674 /*-----------------------------------------------------------------*/
3675 /* genMinus - generates code for subtraction */
3676 /*-----------------------------------------------------------------*/
3678 genMinus (iCode * ic)
3680 int size, offset = 0;
3681 unsigned long lit = 0L;
3683 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3684 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3685 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3687 /* special cases :- */
3688 /* if both left & right are in bit space */
3689 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3690 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3692 wassertl (0, "Tried to subtract two bits");
3696 /* if I can do an decrement instead of subtract then GOOD for ME */
3697 if (genMinusDec (ic) == TRUE)
3700 size = getDataSize (IC_RESULT (ic));
3702 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3707 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3711 /* Same logic as genPlus */
3714 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3715 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3716 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3718 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3719 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3720 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3721 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3723 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3724 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3726 if (left == PAIR_INVALID && right == PAIR_INVALID)
3731 else if (right == PAIR_INVALID)
3733 else if (left == PAIR_INVALID)
3736 fetchPair (left, AOP (IC_LEFT (ic)));
3737 /* Order is important. Right may be HL */
3738 fetchPair (right, AOP (IC_RIGHT (ic)));
3740 emit2 ("ld a,%s", _pairs[left].l);
3741 emit2 ("sub a,%s", _pairs[right].l);
3743 emit2 ("ld a,%s", _pairs[left].h);
3744 emit2 ("sbc a,%s", _pairs[right].h);
3746 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
3748 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3750 aopPut (AOP (IC_RESULT (ic)), "e", 0);
3756 /* Be paranoid on the GB with 4 byte variables due to how C
3757 can be trashed by lda hl,n(sp).
3759 _gbz80_emitAddSubLong (ic, FALSE);
3764 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3766 /* if literal, add a,#-lit, else normal subb */
3769 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3770 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3774 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3777 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3781 /* first add without previous c */
3783 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
3785 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3787 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3790 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3791 AOP_SIZE (IC_LEFT (ic)) == 3 &&
3792 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3794 wassertl (0, "Tried to subtract on a long pointer");
3798 freeAsmop (IC_LEFT (ic), NULL, ic);
3799 freeAsmop (IC_RIGHT (ic), NULL, ic);
3800 freeAsmop (IC_RESULT (ic), NULL, ic);
3803 /*-----------------------------------------------------------------*/
3804 /* genMult - generates code for multiplication */
3805 /*-----------------------------------------------------------------*/
3807 genMult (iCode * ic)
3811 /* If true then the final operation should be a subtract */
3812 bool active = FALSE;
3814 /* Shouldn't occur - all done through function calls */
3815 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3816 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3817 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3819 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
3820 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
3821 AOP_SIZE (IC_RESULT (ic)) > 2)
3823 wassertl (0, "Multiplication is handled through support function calls");
3826 /* Swap left and right such that right is a literal */
3827 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
3829 operand *t = IC_RIGHT (ic);
3830 IC_RIGHT (ic) = IC_LEFT (ic);
3834 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
3836 val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
3837 // wassertl (val > 0, "Multiply must be positive");
3838 wassertl (val != 1, "Can't multiply by 1");
3840 if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
3842 _G.stack.pushedDE = TRUE;
3845 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
3847 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
3855 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3860 /* Fully unroled version of mul.s. Not the most efficient.
3862 for (count = 0; count < 16; count++)
3864 if (count != 0 && active)
3866 emit2 ("add hl,hl");
3870 if (active == FALSE)
3877 emit2 ("add hl,de");
3886 if (IS_Z80 && _G.stack.pushedDE)
3889 _G.stack.pushedDE = FALSE;
3892 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3894 freeAsmop (IC_LEFT (ic), NULL, ic);
3895 freeAsmop (IC_RIGHT (ic), NULL, ic);
3896 freeAsmop (IC_RESULT (ic), NULL, ic);
3899 /*-----------------------------------------------------------------*/
3900 /* genDiv - generates code for division */
3901 /*-----------------------------------------------------------------*/
3905 /* Shouldn't occur - all done through function calls */
3906 wassertl (0, "Division is handled through support function calls");
3909 /*-----------------------------------------------------------------*/
3910 /* genMod - generates code for division */
3911 /*-----------------------------------------------------------------*/
3915 /* Shouldn't occur - all done through function calls */
3919 /*-----------------------------------------------------------------*/
3920 /* genIfxJump :- will create a jump depending on the ifx */
3921 /*-----------------------------------------------------------------*/
3923 genIfxJump (iCode * ic, char *jval)
3928 /* if true label then we jump if condition
3932 jlbl = IC_TRUE (ic);
3933 if (!strcmp (jval, "a"))
3937 else if (!strcmp (jval, "c"))
3941 else if (!strcmp (jval, "nc"))
3945 else if (!strcmp (jval, "m"))
3949 else if (!strcmp (jval, "p"))
3955 /* The buffer contains the bit on A that we should test */
3961 /* false label is present */
3962 jlbl = IC_FALSE (ic);
3963 if (!strcmp (jval, "a"))
3967 else if (!strcmp (jval, "c"))
3971 else if (!strcmp (jval, "nc"))
3975 else if (!strcmp (jval, "m"))
3979 else if (!strcmp (jval, "p"))
3985 /* The buffer contains the bit on A that we should test */
3989 /* Z80 can do a conditional long jump */
3990 if (!strcmp (jval, "a"))
3994 else if (!strcmp (jval, "c"))
3997 else if (!strcmp (jval, "nc"))
4000 else if (!strcmp (jval, "m"))
4003 else if (!strcmp (jval, "p"))
4008 emit2 ("bit %s,a", jval);
4010 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
4012 /* mark the icode as generated */
4018 _getPairIdName (PAIR_ID id)
4020 return _pairs[id].name;
4025 /* if unsigned char cmp with lit, just compare */
4027 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4029 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4032 emit2 ("xor a,!immedbyte", 0x80);
4033 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4036 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4038 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4040 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4041 // Pull left into DE and right into HL
4042 aopGet (AOP(left), LSB, FALSE);
4045 aopGet (AOP(right), LSB, FALSE);
4049 if (size == 0 && sign)
4051 // Highest byte when signed needs the bits flipped
4054 emit2 ("ld a,(de)");
4055 emit2 ("xor !immedbyte", 0x80);
4057 emit2 ("ld a,(hl)");
4058 emit2 ("xor !immedbyte", 0x80);
4062 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4066 emit2 ("ld a,(de)");
4067 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4077 spillPair (PAIR_HL);
4079 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4081 setupPair (PAIR_HL, AOP (left), 0);
4082 aopGet (AOP(right), LSB, FALSE);
4086 if (size == 0 && sign)
4088 // Highest byte when signed needs the bits flipped
4091 emit2 ("ld a,(hl)");
4092 emit2 ("xor !immedbyte", 0x80);
4094 emit2 ("ld a,%d(iy)", offset);
4095 emit2 ("xor !immedbyte", 0x80);
4099 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4103 emit2 ("ld a,(hl)");
4104 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4113 spillPair (PAIR_HL);
4114 spillPair (PAIR_IY);
4118 if (AOP_TYPE (right) == AOP_LIT)
4120 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4121 /* optimize if(x < 0) or if(x >= 0) */
4126 /* No sign so it's always false */
4131 /* Just load in the top most bit */
4132 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4133 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4135 genIfxJump (ifx, "7");
4147 /* First setup h and l contaning the top most bytes XORed */
4148 bool fDidXor = FALSE;
4149 if (AOP_TYPE (left) == AOP_LIT)
4151 unsigned long lit = (unsigned long)
4152 floatFromVal (AOP (left)->aopu.aop_lit);
4153 emit2 ("ld %s,!immedbyte", _fTmp[0],
4154 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4158 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4159 emit2 ("xor a,!immedbyte", 0x80);
4160 emit2 ("ld %s,a", _fTmp[0]);
4163 if (AOP_TYPE (right) == AOP_LIT)
4165 unsigned long lit = (unsigned long)
4166 floatFromVal (AOP (right)->aopu.aop_lit);
4167 emit2 ("ld %s,!immedbyte", _fTmp[1],
4168 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4172 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4173 emit2 ("xor a,!immedbyte", 0x80);
4174 emit2 ("ld %s,a", _fTmp[1]);
4180 /* Do a long subtract */
4183 _moveA (aopGet (AOP (left), offset, FALSE));
4185 if (sign && size == 0)
4187 emit2 ("ld a,%s", _fTmp[0]);
4188 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4192 /* Subtract through, propagating the carry */
4193 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4201 /** Generic compare for > or <
4204 genCmp (operand * left, operand * right,
4205 operand * result, iCode * ifx, int sign)
4207 int size, offset = 0;
4208 unsigned long lit = 0L;
4209 bool swap_sense = FALSE;
4211 /* if left & right are bit variables */
4212 if (AOP_TYPE (left) == AOP_CRY &&
4213 AOP_TYPE (right) == AOP_CRY)
4215 /* Cant happen on the Z80 */
4216 wassertl (0, "Tried to compare two bits");
4220 /* Do a long subtract of right from left. */
4221 size = max (AOP_SIZE (left), AOP_SIZE (right));
4223 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4225 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4226 // Pull left into DE and right into HL
4227 aopGet (AOP(left), LSB, FALSE);
4230 aopGet (AOP(right), LSB, FALSE);
4234 emit2 ("ld a,(de)");
4235 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4244 spillPair (PAIR_HL);
4248 if (AOP_TYPE (right) == AOP_LIT)
4250 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4251 /* optimize if(x < 0) or if(x >= 0) */
4256 /* No sign so it's always false */
4261 /* Just load in the top most bit */
4262 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4263 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4265 genIfxJump (ifx, "7");
4276 genIfxJump (ifx, swap_sense ? "c" : "nc");
4287 _moveA (aopGet (AOP (left), offset, FALSE));
4288 /* Subtract through, propagating the carry */
4289 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4295 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4299 /* Shift the sign bit up into carry */
4302 outBitCLong (result, swap_sense);
4306 /* if the result is used in the next
4307 ifx conditional branch then generate
4308 code a little differently */
4316 genIfxJump (ifx, swap_sense ? "nc" : "c");
4320 genIfxJump (ifx, swap_sense ? "p" : "m");
4325 genIfxJump (ifx, swap_sense ? "nc" : "c");
4332 /* Shift the sign bit up into carry */
4335 outBitCLong (result, swap_sense);
4337 /* leave the result in acc */
4341 /*-----------------------------------------------------------------*/
4342 /* genCmpGt :- greater than comparison */
4343 /*-----------------------------------------------------------------*/
4345 genCmpGt (iCode * ic, iCode * ifx)
4347 operand *left, *right, *result;
4348 sym_link *letype, *retype;
4351 left = IC_LEFT (ic);
4352 right = IC_RIGHT (ic);
4353 result = IC_RESULT (ic);
4355 letype = getSpec (operandType (left));
4356 retype = getSpec (operandType (right));
4357 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4358 /* assign the amsops */
4359 aopOp (left, ic, FALSE, FALSE);
4360 aopOp (right, ic, FALSE, FALSE);
4361 aopOp (result, ic, TRUE, FALSE);
4363 genCmp (right, left, result, ifx, sign);
4365 freeAsmop (left, NULL, ic);
4366 freeAsmop (right, NULL, ic);
4367 freeAsmop (result, NULL, ic);
4370 /*-----------------------------------------------------------------*/
4371 /* genCmpLt - less than comparisons */
4372 /*-----------------------------------------------------------------*/
4374 genCmpLt (iCode * ic, iCode * ifx)
4376 operand *left, *right, *result;
4377 sym_link *letype, *retype;
4380 left = IC_LEFT (ic);
4381 right = IC_RIGHT (ic);
4382 result = IC_RESULT (ic);
4384 letype = getSpec (operandType (left));
4385 retype = getSpec (operandType (right));
4386 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4388 /* assign the amsops */
4389 aopOp (left, ic, FALSE, FALSE);
4390 aopOp (right, ic, FALSE, FALSE);
4391 aopOp (result, ic, TRUE, FALSE);
4393 genCmp (left, right, result, ifx, sign);
4395 freeAsmop (left, NULL, ic);
4396 freeAsmop (right, NULL, ic);
4397 freeAsmop (result, NULL, ic);
4400 /*-----------------------------------------------------------------*/
4401 /* gencjneshort - compare and jump if not equal */
4402 /*-----------------------------------------------------------------*/
4404 gencjneshort (operand * left, operand * right, symbol * lbl)
4406 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4408 unsigned long lit = 0L;
4410 /* Swap the left and right if it makes the computation easier */
4411 if (AOP_TYPE (left) == AOP_LIT)
4418 if (AOP_TYPE (right) == AOP_LIT)
4420 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4423 /* if the right side is a literal then anything goes */
4424 if (AOP_TYPE (right) == AOP_LIT &&
4425 AOP_TYPE (left) != AOP_DIR)
4429 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4434 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4441 emit2 ("jp nz,!tlabel", lbl->key + 100);
4447 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4448 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
4451 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
4452 emit2 ("jp nz,!tlabel", lbl->key + 100);
4457 /* if the right side is in a register or in direct space or
4458 if the left is a pointer register & right is not */
4459 else if (AOP_TYPE (right) == AOP_REG ||
4460 AOP_TYPE (right) == AOP_DIR ||
4461 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
4465 _moveA (aopGet (AOP (left), offset, FALSE));
4466 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
4467 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4469 emit2 ("jp nz,!tlabel", lbl->key + 100);
4472 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4473 emit2 ("jp nz,!tlabel", lbl->key + 100);
4480 /* right is a pointer reg need both a & b */
4481 /* PENDING: is this required? */
4484 _moveA (aopGet (AOP (right), offset, FALSE));
4485 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
4486 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
4492 /*-----------------------------------------------------------------*/
4493 /* gencjne - compare and jump if not equal */
4494 /*-----------------------------------------------------------------*/
4496 gencjne (operand * left, operand * right, symbol * lbl)
4498 symbol *tlbl = newiTempLabel (NULL);
4500 gencjneshort (left, right, lbl);
4503 emit2 ("ld a,!one");
4504 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4505 emitLabel (lbl->key + 100);
4507 emitLabel (tlbl->key + 100);
4510 /*-----------------------------------------------------------------*/
4511 /* genCmpEq - generates code for equal to */
4512 /*-----------------------------------------------------------------*/
4514 genCmpEq (iCode * ic, iCode * ifx)
4516 operand *left, *right, *result;
4518 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4519 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4520 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4522 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4524 /* Swap operands if it makes the operation easier. ie if:
4525 1. Left is a literal.
4527 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4529 operand *t = IC_RIGHT (ic);
4530 IC_RIGHT (ic) = IC_LEFT (ic);
4534 if (ifx && !AOP_SIZE (result))
4537 /* if they are both bit variables */
4538 if (AOP_TYPE (left) == AOP_CRY &&
4539 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4541 wassertl (0, "Tried to compare two bits");
4545 tlbl = newiTempLabel (NULL);
4546 gencjneshort (left, right, tlbl);
4549 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4550 emitLabel (tlbl->key + 100);
4554 /* PENDING: do this better */
4555 symbol *lbl = newiTempLabel (NULL);
4556 emit2 ("!shortjp !tlabel", lbl->key + 100);
4557 emitLabel (tlbl->key + 100);
4558 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4559 emitLabel (lbl->key + 100);
4562 /* mark the icode as generated */
4567 /* if they are both bit variables */
4568 if (AOP_TYPE (left) == AOP_CRY &&
4569 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4571 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4577 gencjne (left, right, newiTempLabel (NULL));
4578 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4585 genIfxJump (ifx, "a");
4588 /* if the result is used in an arithmetic operation
4589 then put the result in place */
4590 if (AOP_TYPE (result) != AOP_CRY)
4595 /* leave the result in acc */
4599 freeAsmop (left, NULL, ic);
4600 freeAsmop (right, NULL, ic);
4601 freeAsmop (result, NULL, ic);
4604 /*-----------------------------------------------------------------*/
4605 /* ifxForOp - returns the icode containing the ifx for operand */
4606 /*-----------------------------------------------------------------*/
4608 ifxForOp (operand * op, iCode * ic)
4610 /* if true symbol then needs to be assigned */
4611 if (IS_TRUE_SYMOP (op))
4614 /* if this has register type condition and
4615 the next instruction is ifx with the same operand
4616 and live to of the operand is upto the ifx only then */
4618 ic->next->op == IFX &&
4619 IC_COND (ic->next)->key == op->key &&
4620 OP_SYMBOL (op)->liveTo <= ic->next->seq)
4626 /*-----------------------------------------------------------------*/
4627 /* genAndOp - for && operation */
4628 /*-----------------------------------------------------------------*/
4630 genAndOp (iCode * ic)
4632 operand *left, *right, *result;
4635 /* note here that && operations that are in an if statement are
4636 taken away by backPatchLabels only those used in arthmetic
4637 operations remain */
4638 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4639 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4640 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4642 /* if both are bit variables */
4643 if (AOP_TYPE (left) == AOP_CRY &&
4644 AOP_TYPE (right) == AOP_CRY)
4646 wassertl (0, "Tried to and two bits");
4650 tlbl = newiTempLabel (NULL);
4652 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
4654 emitLabel (tlbl->key + 100);
4658 freeAsmop (left, NULL, ic);
4659 freeAsmop (right, NULL, ic);
4660 freeAsmop (result, NULL, ic);
4663 /*-----------------------------------------------------------------*/
4664 /* genOrOp - for || operation */
4665 /*-----------------------------------------------------------------*/
4667 genOrOp (iCode * ic)
4669 operand *left, *right, *result;
4672 /* note here that || operations that are in an
4673 if statement are taken away by backPatchLabels
4674 only those used in arthmetic operations remain */
4675 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4676 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4677 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4679 /* if both are bit variables */
4680 if (AOP_TYPE (left) == AOP_CRY &&
4681 AOP_TYPE (right) == AOP_CRY)
4683 wassertl (0, "Tried to OR two bits");
4687 tlbl = newiTempLabel (NULL);
4689 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4691 emitLabel (tlbl->key + 100);
4695 freeAsmop (left, NULL, ic);
4696 freeAsmop (right, NULL, ic);
4697 freeAsmop (result, NULL, ic);
4700 /*-----------------------------------------------------------------*/
4701 /* isLiteralBit - test if lit == 2^n */
4702 /*-----------------------------------------------------------------*/
4704 isLiteralBit (unsigned long lit)
4706 unsigned long pw[32] =
4707 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
4708 0x100L, 0x200L, 0x400L, 0x800L,
4709 0x1000L, 0x2000L, 0x4000L, 0x8000L,
4710 0x10000L, 0x20000L, 0x40000L, 0x80000L,
4711 0x100000L, 0x200000L, 0x400000L, 0x800000L,
4712 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
4713 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
4716 for (idx = 0; idx < 32; idx++)
4722 /*-----------------------------------------------------------------*/
4723 /* jmpTrueOrFalse - */
4724 /*-----------------------------------------------------------------*/
4726 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
4728 // ugly but optimized by peephole
4731 symbol *nlbl = newiTempLabel (NULL);
4732 emit2 ("jp !tlabel", nlbl->key + 100);
4733 emitLabel (tlbl->key + 100);
4734 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
4735 emitLabel (nlbl->key + 100);
4739 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
4740 emitLabel (tlbl->key + 100);
4745 /*-----------------------------------------------------------------*/
4746 /* genAnd - code for and */
4747 /*-----------------------------------------------------------------*/
4749 genAnd (iCode * ic, iCode * ifx)
4751 operand *left, *right, *result;
4752 int size, offset = 0;
4753 unsigned long lit = 0L;
4756 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4757 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4758 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4760 /* if left is a literal & right is not then exchange them */
4761 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4762 AOP_NEEDSACC (left))
4764 operand *tmp = right;
4769 /* if result = right then exchange them */
4770 if (sameRegs (AOP (result), AOP (right)))
4772 operand *tmp = right;
4777 /* if right is bit then exchange them */
4778 if (AOP_TYPE (right) == AOP_CRY &&
4779 AOP_TYPE (left) != AOP_CRY)
4781 operand *tmp = right;
4785 if (AOP_TYPE (right) == AOP_LIT)
4786 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4788 size = AOP_SIZE (result);
4790 if (AOP_TYPE (left) == AOP_CRY)
4792 wassertl (0, "Tried to perform an AND with a bit as an operand");
4796 // if(val & 0xZZ) - size = 0, ifx != FALSE -
4797 // bit = val & 0xZZ - size = 1, ifx = FALSE -
4798 if ((AOP_TYPE (right) == AOP_LIT) &&
4799 (AOP_TYPE (result) == AOP_CRY) &&
4800 (AOP_TYPE (left) != AOP_CRY))
4802 symbol *tlbl = newiTempLabel (NULL);
4803 int sizel = AOP_SIZE (left);
4806 /* PENDING: Test case for this. */
4811 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
4813 _moveA (aopGet (AOP (left), offset, FALSE));
4814 if (bytelit != 0x0FFL)
4816 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4823 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4827 // bit = left & literal
4831 emit2 ("!tlabeldef", tlbl->key + 100);
4833 // if(left & literal)
4838 jmpTrueOrFalse (ifx, tlbl);
4846 /* if left is same as result */
4847 if (sameRegs (AOP (result), AOP (left)))
4849 for (; size--; offset++)
4851 if (AOP_TYPE (right) == AOP_LIT)
4853 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4858 aopPut (AOP (result), "!zero", offset);
4861 _moveA (aopGet (AOP (left), offset, FALSE));
4863 aopGet (AOP (right), offset, FALSE));
4864 aopPut (AOP (left), "a", offset);
4871 if (AOP_TYPE (left) == AOP_ACC)
4873 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
4877 _moveA (aopGet (AOP (left), offset, FALSE));
4879 aopGet (AOP (right), offset, FALSE));
4880 aopPut (AOP (left), "a", offset);
4887 // left & result in different registers
4888 if (AOP_TYPE (result) == AOP_CRY)
4890 wassertl (0, "Tried to AND where the result is in carry");
4894 for (; (size--); offset++)
4897 // result = left & right
4898 if (AOP_TYPE (right) == AOP_LIT)
4900 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4902 aopPut (AOP (result),
4903 aopGet (AOP (left), offset, FALSE),
4907 else if (bytelit == 0)
4909 aopPut (AOP (result), "!zero", offset);
4913 // faster than result <- left, anl result,right
4914 // and better if result is SFR
4915 if (AOP_TYPE (left) == AOP_ACC)
4916 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4919 _moveA (aopGet (AOP (left), offset, FALSE));
4921 aopGet (AOP (right), offset, FALSE));
4923 aopPut (AOP (result), "a", offset);
4930 freeAsmop (left, NULL, ic);
4931 freeAsmop (right, NULL, ic);
4932 freeAsmop (result, NULL, ic);
4935 /*-----------------------------------------------------------------*/
4936 /* genOr - code for or */
4937 /*-----------------------------------------------------------------*/
4939 genOr (iCode * ic, iCode * ifx)
4941 operand *left, *right, *result;
4942 int size, offset = 0;
4943 unsigned long lit = 0L;
4946 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4947 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4948 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4950 /* if left is a literal & right is not then exchange them */
4951 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4952 AOP_NEEDSACC (left))
4954 operand *tmp = right;
4959 /* if result = right then exchange them */
4960 if (sameRegs (AOP (result), AOP (right)))
4962 operand *tmp = right;
4967 /* if right is bit then exchange them */
4968 if (AOP_TYPE (right) == AOP_CRY &&
4969 AOP_TYPE (left) != AOP_CRY)
4971 operand *tmp = right;
4975 if (AOP_TYPE (right) == AOP_LIT)
4976 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4978 size = AOP_SIZE (result);
4980 if (AOP_TYPE (left) == AOP_CRY)
4982 wassertl (0, "Tried to OR where left is a bit");
4986 // if(val | 0xZZ) - size = 0, ifx != FALSE -
4987 // bit = val | 0xZZ - size = 1, ifx = FALSE -
4988 if ((AOP_TYPE (right) == AOP_LIT) &&
4989 (AOP_TYPE (result) == AOP_CRY) &&
4990 (AOP_TYPE (left) != AOP_CRY))
4992 symbol *tlbl = newiTempLabel (NULL);
4993 int sizel = AOP_SIZE (left);
4997 wassertl (0, "Result is assigned to a bit");
4999 /* PENDING: Modeled after the AND code which is inefficent. */
5002 bytelit = (lit >> (offset * 8)) & 0x0FFL;
5004 _moveA (aopGet (AOP (left), offset, FALSE));
5005 /* OR with any literal is the same as OR with itself. */
5007 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5013 jmpTrueOrFalse (ifx, tlbl);
5018 /* if left is same as result */
5019 if (sameRegs (AOP (result), AOP (left)))
5021 for (; size--; offset++)
5023 if (AOP_TYPE (right) == AOP_LIT)
5025 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5029 _moveA (aopGet (AOP (left), offset, FALSE));
5031 aopGet (AOP (right), offset, FALSE));
5032 aopPut (AOP (result), "a", offset);
5037 if (AOP_TYPE (left) == AOP_ACC)
5038 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5041 _moveA (aopGet (AOP (left), offset, FALSE));
5043 aopGet (AOP (right), offset, FALSE));
5044 aopPut (AOP (result), "a", offset);
5051 // left & result in different registers
5052 if (AOP_TYPE (result) == AOP_CRY)
5054 wassertl (0, "Result of OR is in a bit");
5057 for (; (size--); offset++)
5060 // result = left & right
5061 if (AOP_TYPE (right) == AOP_LIT)
5063 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5065 aopPut (AOP (result),
5066 aopGet (AOP (left), offset, FALSE),
5071 // faster than result <- left, anl result,right
5072 // and better if result is SFR
5073 if (AOP_TYPE (left) == AOP_ACC)
5074 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5077 _moveA (aopGet (AOP (left), offset, FALSE));
5079 aopGet (AOP (right), offset, FALSE));
5081 aopPut (AOP (result), "a", offset);
5082 /* PENDING: something weird is going on here. Add exception. */
5083 if (AOP_TYPE (result) == AOP_ACC)
5089 freeAsmop (left, NULL, ic);
5090 freeAsmop (right, NULL, ic);
5091 freeAsmop (result, NULL, ic);
5094 /*-----------------------------------------------------------------*/
5095 /* genXor - code for xclusive or */
5096 /*-----------------------------------------------------------------*/
5098 genXor (iCode * ic, iCode * ifx)
5100 operand *left, *right, *result;
5101 int size, offset = 0;
5102 unsigned long lit = 0L;
5104 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5105 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5106 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5108 /* if left is a literal & right is not then exchange them */
5109 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5110 AOP_NEEDSACC (left))
5112 operand *tmp = right;
5117 /* if result = right then exchange them */
5118 if (sameRegs (AOP (result), AOP (right)))
5120 operand *tmp = right;
5125 /* if right is bit then exchange them */
5126 if (AOP_TYPE (right) == AOP_CRY &&
5127 AOP_TYPE (left) != AOP_CRY)
5129 operand *tmp = right;
5133 if (AOP_TYPE (right) == AOP_LIT)
5134 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5136 size = AOP_SIZE (result);
5138 if (AOP_TYPE (left) == AOP_CRY)
5140 wassertl (0, "Tried to XOR a bit");
5144 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5145 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5146 if ((AOP_TYPE (right) == AOP_LIT) &&
5147 (AOP_TYPE (result) == AOP_CRY) &&
5148 (AOP_TYPE (left) != AOP_CRY))
5150 symbol *tlbl = newiTempLabel (NULL);
5151 int sizel = AOP_SIZE (left);
5155 /* PENDING: Test case for this. */
5156 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5160 _moveA (aopGet (AOP (left), offset, FALSE));
5161 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5162 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5167 jmpTrueOrFalse (ifx, tlbl);
5171 wassertl (0, "Result of XOR was destined for a bit");
5176 /* if left is same as result */
5177 if (sameRegs (AOP (result), AOP (left)))
5179 for (; size--; offset++)
5181 if (AOP_TYPE (right) == AOP_LIT)
5183 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5187 _moveA (aopGet (AOP (right), offset, FALSE));
5189 aopGet (AOP (left), offset, FALSE));
5190 aopPut (AOP (result), "a", offset);
5195 if (AOP_TYPE (left) == AOP_ACC)
5197 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5201 _moveA (aopGet (AOP (right), offset, FALSE));
5203 aopGet (AOP (left), offset, FALSE));
5204 aopPut (AOP (result), "a", offset);
5211 // left & result in different registers
5212 if (AOP_TYPE (result) == AOP_CRY)
5214 wassertl (0, "Result of XOR is in a bit");
5217 for (; (size--); offset++)
5220 // result = left & right
5221 if (AOP_TYPE (right) == AOP_LIT)
5223 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5225 aopPut (AOP (result),
5226 aopGet (AOP (left), offset, FALSE),
5231 // faster than result <- left, anl result,right
5232 // and better if result is SFR
5233 if (AOP_TYPE (left) == AOP_ACC)
5235 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5239 _moveA (aopGet (AOP (right), offset, FALSE));
5241 aopGet (AOP (left), offset, FALSE));
5243 aopPut (AOP (result), "a", offset);
5248 freeAsmop (left, NULL, ic);
5249 freeAsmop (right, NULL, ic);
5250 freeAsmop (result, NULL, ic);
5253 /*-----------------------------------------------------------------*/
5254 /* genInline - write the inline code out */
5255 /*-----------------------------------------------------------------*/
5257 genInline (iCode * ic)
5259 char *buffer, *bp, *bp1;
5261 _G.lines.isInline += (!options.asmpeep);
5263 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5264 strcpy (buffer, IC_INLINE (ic));
5266 /* emit each line as a code */
5291 _G.lines.isInline -= (!options.asmpeep);
5295 /*-----------------------------------------------------------------*/
5296 /* genRRC - rotate right with carry */
5297 /*-----------------------------------------------------------------*/
5304 /*-----------------------------------------------------------------*/
5305 /* genRLC - generate code for rotate left with carry */
5306 /*-----------------------------------------------------------------*/
5313 /*-----------------------------------------------------------------*/
5314 /* genGetHbit - generates code get highest order bit */
5315 /*-----------------------------------------------------------------*/
5317 genGetHbit (iCode * ic)
5319 operand *left, *result;
5320 left = IC_LEFT (ic);
5321 result = IC_RESULT (ic);
5323 aopOp (left, ic, FALSE, FALSE);
5324 aopOp (result, ic, FALSE, FALSE);
5326 /* get the highest order byte into a */
5327 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5329 if (AOP_TYPE (result) == AOP_CRY)
5337 emit2 ("and a,!one");
5342 freeAsmop (left, NULL, ic);
5343 freeAsmop (result, NULL, ic);
5347 emitRsh2 (asmop *aop, int size, int is_signed)
5353 const char *l = aopGet (aop, size, FALSE);
5356 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5366 /*-----------------------------------------------------------------*/
5367 /* shiftR2Left2Result - shift right two bytes from left to result */
5368 /*-----------------------------------------------------------------*/
5370 shiftR2Left2Result (operand * left, int offl,
5371 operand * result, int offr,
5372 int shCount, int is_signed)
5375 symbol *tlbl, *tlbl1;
5377 movLeft2Result (left, offl, result, offr, 0);
5378 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5380 /* if (AOP(result)->type == AOP_REG) { */
5382 tlbl = newiTempLabel (NULL);
5383 tlbl1 = newiTempLabel (NULL);
5385 /* Left is already in result - so now do the shift */
5390 emitRsh2 (AOP (result), size, is_signed);
5395 emit2 ("ld a,!immedbyte+1", shCount);
5396 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5397 emitLabel (tlbl->key + 100);
5399 emitRsh2 (AOP (result), size, is_signed);
5401 emitLabel (tlbl1->key + 100);
5403 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5407 /*-----------------------------------------------------------------*/
5408 /* shiftL2Left2Result - shift left two bytes from left to result */
5409 /*-----------------------------------------------------------------*/
5411 shiftL2Left2Result (operand * left, int offl,
5412 operand * result, int offr, int shCount)
5414 if (sameRegs (AOP (result), AOP (left)) &&
5415 ((offl + MSB16) == offr))
5421 /* Copy left into result */
5422 movLeft2Result (left, offl, result, offr, 0);
5423 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5426 if (getPairId (AOP (result)) == PAIR_HL)
5430 emit2 ("add hl,hl");
5437 symbol *tlbl, *tlbl1;
5440 tlbl = newiTempLabel (NULL);
5441 tlbl1 = newiTempLabel (NULL);
5443 if (AOP (result)->type == AOP_REG)
5447 for (offset = 0; offset < size; offset++)
5449 l = aopGet (AOP (result), offset, FALSE);
5453 emit2 ("sla %s", l);
5464 /* Left is already in result - so now do the shift */
5467 emit2 ("ld a,!immedbyte+1", shCount);
5468 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5469 emitLabel (tlbl->key + 100);
5474 l = aopGet (AOP (result), offset, FALSE);
5478 emit2 ("sla %s", l);
5489 emitLabel (tlbl1->key + 100);
5491 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5497 /*-----------------------------------------------------------------*/
5498 /* AccRol - rotate left accumulator by known count */
5499 /*-----------------------------------------------------------------*/
5501 AccRol (int shCount)
5503 shCount &= 0x0007; // shCount : 0..7
5580 /*-----------------------------------------------------------------*/
5581 /* AccLsh - left shift accumulator by known count */
5582 /*-----------------------------------------------------------------*/
5584 AccLsh (int shCount)
5586 static const unsigned char SLMask[] =
5588 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5597 else if (shCount == 2)
5604 /* rotate left accumulator */
5606 /* and kill the lower order bits */
5607 emit2 ("and a,!immedbyte", SLMask[shCount]);
5612 /*-----------------------------------------------------------------*/
5613 /* shiftL1Left2Result - shift left one byte from left to result */
5614 /*-----------------------------------------------------------------*/
5616 shiftL1Left2Result (operand * left, int offl,
5617 operand * result, int offr, int shCount)
5620 l = aopGet (AOP (left), offl, FALSE);
5622 /* shift left accumulator */
5624 aopPut (AOP (result), "a", offr);
5628 /*-----------------------------------------------------------------*/
5629 /* genlshTwo - left shift two bytes by known amount != 0 */
5630 /*-----------------------------------------------------------------*/
5632 genlshTwo (operand * result, operand * left, int shCount)
5634 int size = AOP_SIZE (result);
5636 wassert (size == 2);
5638 /* if shCount >= 8 */
5646 movLeft2Result (left, LSB, result, MSB16, 0);
5647 aopPut (AOP (result), "!zero", 0);
5648 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
5652 movLeft2Result (left, LSB, result, MSB16, 0);
5653 aopPut (AOP (result), "!zero", 0);
5658 aopPut (AOP (result), "!zero", LSB);
5661 /* 1 <= shCount <= 7 */
5670 shiftL2Left2Result (left, LSB, result, LSB, shCount);
5675 /*-----------------------------------------------------------------*/
5676 /* genlshOne - left shift a one byte quantity by known count */
5677 /*-----------------------------------------------------------------*/
5679 genlshOne (operand * result, operand * left, int shCount)
5681 shiftL1Left2Result (left, LSB, result, LSB, shCount);
5684 /*-----------------------------------------------------------------*/
5685 /* genLeftShiftLiteral - left shifting by known count */
5686 /*-----------------------------------------------------------------*/
5688 genLeftShiftLiteral (operand * left,
5693 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5696 freeAsmop (right, NULL, ic);
5698 aopOp (left, ic, FALSE, FALSE);
5699 aopOp (result, ic, FALSE, FALSE);
5701 size = getSize (operandType (result));
5703 /* I suppose that the left size >= result size */
5709 else if (shCount >= (size * 8))
5713 aopPut (AOP (result), "!zero", size);
5721 genlshOne (result, left, shCount);
5724 genlshTwo (result, left, shCount);
5727 wassertl (0, "Shifting of longs is currently unsupported");
5733 freeAsmop (left, NULL, ic);
5734 freeAsmop (result, NULL, ic);
5737 /*-----------------------------------------------------------------*/
5738 /* genLeftShift - generates code for left shifting */
5739 /*-----------------------------------------------------------------*/
5741 genLeftShift (iCode * ic)
5745 symbol *tlbl, *tlbl1;
5746 operand *left, *right, *result;
5748 right = IC_RIGHT (ic);
5749 left = IC_LEFT (ic);
5750 result = IC_RESULT (ic);
5752 aopOp (right, ic, FALSE, FALSE);
5754 /* if the shift count is known then do it
5755 as efficiently as possible */
5756 if (AOP_TYPE (right) == AOP_LIT)
5758 genLeftShiftLiteral (left, right, result, ic);
5762 /* shift count is unknown then we have to form a loop get the loop
5763 count in B : Note: we take only the lower order byte since
5764 shifting more that 32 bits make no sense anyway, ( the largest
5765 size of an object can be only 32 bits ) */
5766 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5768 freeAsmop (right, NULL, ic);
5769 aopOp (left, ic, FALSE, FALSE);
5770 aopOp (result, ic, FALSE, FALSE);
5772 /* now move the left to the result if they are not the
5775 if (!sameRegs (AOP (left), AOP (result)))
5778 size = AOP_SIZE (result);
5782 l = aopGet (AOP (left), offset, FALSE);
5783 aopPut (AOP (result), l, offset);
5788 tlbl = newiTempLabel (NULL);
5789 size = AOP_SIZE (result);
5791 tlbl1 = newiTempLabel (NULL);
5793 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5794 emitLabel (tlbl->key + 100);
5795 l = aopGet (AOP (result), offset, FALSE);
5799 l = aopGet (AOP (result), offset, FALSE);
5803 emit2 ("sla %s", l);
5811 emitLabel (tlbl1->key + 100);
5813 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5815 freeAsmop (left, NULL, ic);
5816 freeAsmop (result, NULL, ic);
5819 /*-----------------------------------------------------------------*/
5820 /* genrshOne - left shift two bytes by known amount != 0 */
5821 /*-----------------------------------------------------------------*/
5823 genrshOne (operand * result, operand * left, int shCount, int is_signed)
5826 int size = AOP_SIZE (result);
5829 wassert (size == 1);
5830 wassert (shCount < 8);
5832 l = aopGet (AOP (left), 0, FALSE);
5834 if (AOP (result)->type == AOP_REG)
5836 aopPut (AOP (result), l, 0);
5837 l = aopGet (AOP (result), 0, FALSE);
5840 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5848 emit2 ("%s a", is_signed ? "sra" : "srl");
5850 aopPut (AOP (result), "a", 0);
5854 /*-----------------------------------------------------------------*/
5855 /* AccRsh - right shift accumulator by known count */
5856 /*-----------------------------------------------------------------*/
5858 AccRsh (int shCount)
5860 static const unsigned char SRMask[] =
5862 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
5867 /* rotate right accumulator */
5868 AccRol (8 - shCount);
5869 /* and kill the higher order bits */
5870 emit2 ("and a,!immedbyte", SRMask[shCount]);
5874 /*-----------------------------------------------------------------*/
5875 /* shiftR1Left2Result - shift right one byte from left to result */
5876 /*-----------------------------------------------------------------*/
5878 shiftR1Left2Result (operand * left, int offl,
5879 operand * result, int offr,
5880 int shCount, int sign)
5882 _moveA (aopGet (AOP (left), offl, FALSE));
5887 emit2 ("%s a", sign ? "sra" : "srl");
5894 aopPut (AOP (result), "a", offr);
5897 /*-----------------------------------------------------------------*/
5898 /* genrshTwo - right shift two bytes by known amount != 0 */
5899 /*-----------------------------------------------------------------*/
5901 genrshTwo (operand * result, operand * left,
5902 int shCount, int sign)
5904 /* if shCount >= 8 */
5910 shiftR1Left2Result (left, MSB16, result, LSB,
5915 movLeft2Result (left, MSB16, result, LSB, sign);
5919 /* Sign extend the result */
5920 _moveA(aopGet (AOP (result), 0, FALSE));
5924 aopPut (AOP (result), ACC_NAME, MSB16);
5928 aopPut (AOP (result), "!zero", 1);
5931 /* 1 <= shCount <= 7 */
5934 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
5938 /*-----------------------------------------------------------------*/
5939 /* genRightShiftLiteral - left shifting by known count */
5940 /*-----------------------------------------------------------------*/
5942 genRightShiftLiteral (operand * left,
5948 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5951 freeAsmop (right, NULL, ic);
5953 aopOp (left, ic, FALSE, FALSE);
5954 aopOp (result, ic, FALSE, FALSE);
5956 size = getSize (operandType (result));
5958 /* I suppose that the left size >= result size */
5964 else if (shCount >= (size * 8)) {
5966 if (!SPEC_USIGN(getSpec(operandType(left)))) {
5967 _moveA(aopGet (AOP (left), 0, FALSE));
5975 aopPut (AOP (result), s, size);
5982 genrshOne (result, left, shCount, sign);
5985 genrshTwo (result, left, shCount, sign);
5988 wassertl (0, "Asked to shift right a long which should be a function call");
5991 wassertl (0, "Entered default case in right shift delegate");
5994 freeAsmop (left, NULL, ic);
5995 freeAsmop (result, NULL, ic);
5998 /*-----------------------------------------------------------------*/
5999 /* genRightShift - generate code for right shifting */
6000 /*-----------------------------------------------------------------*/
6002 genRightShift (iCode * ic)
6004 operand *right, *left, *result;
6006 int size, offset, first = 1;
6010 symbol *tlbl, *tlbl1;
6012 /* if signed then we do it the hard way preserve the
6013 sign bit moving it inwards */
6014 retype = getSpec (operandType (IC_RESULT (ic)));
6016 is_signed = !SPEC_USIGN (retype);
6018 /* signed & unsigned types are treated the same : i.e. the
6019 signed is NOT propagated inwards : quoting from the
6020 ANSI - standard : "for E1 >> E2, is equivalent to division
6021 by 2**E2 if unsigned or if it has a non-negative value,
6022 otherwise the result is implementation defined ", MY definition
6023 is that the sign does not get propagated */
6025 right = IC_RIGHT (ic);
6026 left = IC_LEFT (ic);
6027 result = IC_RESULT (ic);
6029 aopOp (right, ic, FALSE, FALSE);
6031 /* if the shift count is known then do it
6032 as efficiently as possible */
6033 if (AOP_TYPE (right) == AOP_LIT)
6035 genRightShiftLiteral (left, right, result, ic, is_signed);
6039 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6041 freeAsmop (right, NULL, ic);
6043 aopOp (left, ic, FALSE, FALSE);
6044 aopOp (result, ic, FALSE, FALSE);
6046 /* now move the left to the result if they are not the
6048 if (!sameRegs (AOP (left), AOP (result)))
6051 size = AOP_SIZE (result);
6055 l = aopGet (AOP (left), offset, FALSE);
6056 aopPut (AOP (result), l, offset);
6061 tlbl = newiTempLabel (NULL);
6062 tlbl1 = newiTempLabel (NULL);
6063 size = AOP_SIZE (result);
6066 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6067 emitLabel (tlbl->key + 100);
6070 l = aopGet (AOP (result), offset--, FALSE);
6073 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6081 emitLabel (tlbl1->key + 100);
6083 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6085 freeAsmop (left, NULL, ic);
6086 freeAsmop (result, NULL, ic);
6090 /*-----------------------------------------------------------------*/
6091 /* genUnpackBits - generates code for unpacking bits */
6092 /*-----------------------------------------------------------------*/
6094 genUnpackBits (operand * result, int pair)
6096 int offset = 0; /* result byte offset */
6097 int rsize; /* result size */
6098 int rlen = 0; /* remaining bitfield length */
6099 sym_link *etype; /* bitfield type information */
6100 int blen; /* bitfield length */
6101 int bstr; /* bitfield starting bit within byte */
6103 emitDebug ("; genUnpackBits");
6105 etype = getSpec (operandType (result));
6106 rsize = getSize (operandType (result));
6107 blen = SPEC_BLEN (etype);
6108 bstr = SPEC_BSTR (etype);
6110 /* If the bitfield length is less than a byte */
6113 emit2 ("ld a,!*pair", _pairs[pair].name);
6115 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6116 aopPut (AOP (result), "a", offset++);
6120 /* TODO: what if pair == PAIR_DE ? */
6121 if (getPairId (AOP (result)) == PAIR_HL)
6123 wassertl (rsize == 2, "HL must be of size 2");
6124 emit2 ("ld a,!*hl");
6126 emit2 ("ld h,!*hl");
6129 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6131 spillPair (PAIR_HL);
6135 /* Bit field did not fit in a byte. Copy all
6136 but the partial byte at the end. */
6137 for (rlen=blen;rlen>=8;rlen-=8)
6139 emit2 ("ld a,!*pair", _pairs[pair].name);
6140 aopPut (AOP (result), "a", offset++);
6143 emit2 ("inc %s", _pairs[pair].name);
6144 _G.pairs[pair].offset++;
6148 /* Handle the partial byte at the end */
6151 emit2 ("ld a,!*pair", _pairs[pair].name);
6152 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6153 aopPut (AOP (result), "a", offset++);
6161 aopPut (AOP (result), "!zero", offset++);
6165 /*-----------------------------------------------------------------*/
6166 /* genGenPointerGet - get value from generic pointer space */
6167 /*-----------------------------------------------------------------*/
6169 genGenPointerGet (operand * left,
6170 operand * result, iCode * ic)
6173 sym_link *retype = getSpec (operandType (result));
6179 aopOp (left, ic, FALSE, FALSE);
6180 aopOp (result, ic, FALSE, FALSE);
6182 size = AOP_SIZE (result);
6184 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6187 if (isPtrPair (AOP (left)))
6189 tsprintf (buffer, sizeof(buffer),
6190 "!*pair", getPairName (AOP (left)));
6191 aopPut (AOP (result), buffer, 0);
6195 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6196 aopPut (AOP (result), "a", 0);
6198 freeAsmop (left, NULL, ic);
6202 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6209 tsprintf (at, sizeof(at), "!*iyx", offset);
6210 aopPut (AOP (result), at, offset);
6214 freeAsmop (left, NULL, ic);
6218 /* For now we always load into IY */
6219 /* if this is remateriazable */
6220 fetchPair (pair, AOP (left));
6222 /* if bit then unpack */
6223 if (IS_BITVAR (retype))
6225 genUnpackBits (result, pair);
6226 freeAsmop (left, NULL, ic);
6230 else if (getPairId (AOP (result)) == PAIR_HL)
6232 wassertl (size == 2, "HL must be of size 2");
6233 emit2 ("ld a,!*hl");
6235 emit2 ("ld h,!*hl");
6237 spillPair (PAIR_HL);
6239 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6241 size = AOP_SIZE (result);
6246 /* PENDING: make this better */
6247 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6249 aopPut (AOP (result), "!*hl", offset++);
6253 emit2 ("ld a,!*pair", _pairs[pair].name);
6254 aopPut (AOP (result), "a", offset++);
6258 emit2 ("inc %s", _pairs[pair].name);
6259 _G.pairs[pair].offset++;
6262 /* Fixup HL back down */
6263 for (size = AOP_SIZE (result)-1; size; size--)
6265 emit2 ("dec %s", _pairs[pair].name);
6270 size = AOP_SIZE (result);
6275 /* PENDING: make this better */
6277 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6279 aopPut (AOP (result), "!*hl", offset++);
6283 emit2 ("ld a,!*pair", _pairs[pair].name);
6284 aopPut (AOP (result), "a", offset++);
6288 emit2 ("inc %s", _pairs[pair].name);
6289 _G.pairs[pair].offset++;
6294 freeAsmop (left, NULL, ic);
6297 freeAsmop (result, NULL, ic);
6300 /*-----------------------------------------------------------------*/
6301 /* genPointerGet - generate code for pointer get */
6302 /*-----------------------------------------------------------------*/
6304 genPointerGet (iCode * ic)
6306 operand *left, *result;
6307 sym_link *type, *etype;
6309 left = IC_LEFT (ic);
6310 result = IC_RESULT (ic);
6312 /* depending on the type of pointer we need to
6313 move it to the correct pointer register */
6314 type = operandType (left);
6315 etype = getSpec (type);
6317 genGenPointerGet (left, result, ic);
6321 isRegOrLit (asmop * aop)
6323 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6329 /*-----------------------------------------------------------------*/
6330 /* genPackBits - generates code for packed bit storage */
6331 /*-----------------------------------------------------------------*/
6333 genPackBits (sym_link * etype,
6338 int offset = 0; /* source byte offset */
6339 int rlen = 0; /* remaining bitfield length */
6340 int blen; /* bitfield length */
6341 int bstr; /* bitfield starting bit within byte */
6342 int litval; /* source literal value (if AOP_LIT) */
6343 unsigned char mask; /* bitmask within current byte */
6344 int extraPair; /* a tempory register */
6345 bool needPopExtra=0; /* need to restore original value of temp reg */
6347 emitDebug ("; genPackBits","");
6349 blen = SPEC_BLEN (etype);
6350 bstr = SPEC_BSTR (etype);
6352 /* If the bitfield length is less than a byte */
6355 mask = ((unsigned char) (0xFF << (blen + bstr)) |
6356 (unsigned char) (0xFF >> (8 - bstr)));
6358 if (AOP_TYPE (right) == AOP_LIT)
6360 /* Case with a bitfield length <8 and literal source
6362 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6364 litval &= (~mask) & 0xff;
6365 emit2 ("ld a,!*pair", _pairs[pair].name);
6366 if ((mask|litval)!=0xff)
6367 emit2 ("and a,!immedbyte", mask);
6369 emit2 ("or a,!immedbyte", litval);
6370 emit2 ("ld !*pair,a", _pairs[pair].name);
6375 /* Case with a bitfield length <8 and arbitrary source
6377 _moveA (aopGet (AOP (right), 0, FALSE));
6378 /* shift and mask source value */
6380 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6382 extraPair = getFreePairId(ic);
6383 if (extraPair == PAIR_INVALID)
6385 extraPair = PAIR_BC;
6386 if (getPairId (AOP (right)) != PAIR_BC
6387 || !isLastUse (ic, right))
6393 emit2 ("ld %s,a", _pairs[extraPair].l);
6394 emit2 ("ld a,!*pair", _pairs[pair].name);
6396 emit2 ("and a,!immedbyte", mask);
6397 emit2 ("or a,%s", _pairs[extraPair].l);
6398 emit2 ("ld !*pair,a", _pairs[pair].name);
6405 /* Bit length is greater than 7 bits. In this case, copy */
6406 /* all except the partial byte at the end */
6407 for (rlen=blen;rlen>=8;rlen-=8)
6409 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
6410 emit2 ("ld !*pair,a", _pairs[pair].name);
6413 emit2 ("inc %s", _pairs[pair].name);
6414 _G.pairs[pair].offset++;
6418 /* If there was a partial byte at the end */
6421 mask = (((unsigned char) -1 << rlen) & 0xff);
6423 if (AOP_TYPE (right) == AOP_LIT)
6425 /* Case with partial byte and literal source
6427 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6428 litval >>= (blen-rlen);
6429 litval &= (~mask) & 0xff;
6430 emit2 ("ld a,!*pair", _pairs[pair].name);
6431 if ((mask|litval)!=0xff)
6432 emit2 ("and a,!immedbyte", mask);
6434 emit2 ("or a,!immedbyte", litval);
6438 /* Case with partial byte and arbitrary source
6440 _moveA (aopGet (AOP (right), offset++, FALSE));
6441 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6443 extraPair = getFreePairId(ic);
6444 if (extraPair == PAIR_INVALID)
6446 extraPair = getPairId (AOP (right));
6447 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
6448 extraPair = PAIR_BC;
6450 if (getPairId (AOP (right)) != PAIR_BC
6451 || !isLastUse (ic, right))
6457 emit2 ("ld %s,a", _pairs[extraPair].l);
6458 emit2 ("ld a,!*pair", _pairs[pair].name);
6460 emit2 ("and a,!immedbyte", mask);
6461 emit2 ("or a,%s", _pairs[extraPair].l);
6466 emit2 ("ld !*pair,a", _pairs[pair].name);
6471 /*-----------------------------------------------------------------*/
6472 /* genGenPointerSet - stores the value into a pointer location */
6473 /*-----------------------------------------------------------------*/
6475 genGenPointerSet (operand * right,
6476 operand * result, iCode * ic)
6479 sym_link *retype = getSpec (operandType (right));
6480 sym_link *letype = getSpec (operandType (result));
6481 PAIR_ID pairId = PAIR_HL;
6484 aopOp (result, ic, FALSE, FALSE);
6485 aopOp (right, ic, FALSE, FALSE);
6490 size = AOP_SIZE (right);
6492 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
6493 emitDebug("; isBitvar = %d", isBitvar);
6495 /* Handle the exceptions first */
6496 if (isPair (AOP (result)) && size == 1 && !isBitvar)
6499 const char *l = aopGet (AOP (right), 0, FALSE);
6500 const char *pair = getPairName (AOP (result));
6501 if (canAssignToPtr (l) && isPtr (pair))
6503 emit2 ("ld !*pair,%s", pair, l);
6508 emit2 ("ld !*pair,a", pair);
6513 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
6516 const char *l = aopGet (AOP (right), 0, FALSE);
6521 if (canAssignToPtr (l))
6523 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6527 _moveA (aopGet (AOP (right), offset, FALSE));
6528 emit2 ("ld !*iyx,a", offset);
6534 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
6541 const char *l = aopGet (AOP (right), offset, FALSE);
6542 if (isRegOrLit (AOP (right)) && !IS_GB)
6544 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
6549 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
6553 emit2 ("inc %s", _pairs[PAIR_HL].name);
6554 _G.pairs[PAIR_HL].offset++;
6559 /* Fixup HL back down */
6560 for (size = AOP_SIZE (right)-1; size; size--)
6562 emit2 ("dec %s", _pairs[PAIR_HL].name);
6567 /* if the operand is already in dptr
6568 then we do nothing else we move the value to dptr */
6569 if (AOP_TYPE (result) != AOP_STR)
6571 fetchPair (pairId, AOP (result));
6573 /* so hl know contains the address */
6574 freeAsmop (result, NULL, ic);
6576 /* if bit then unpack */
6579 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
6589 const char *l = aopGet (AOP (right), offset, FALSE);
6590 if (isRegOrLit (AOP (right)) && !IS_GB)
6592 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
6597 emit2 ("ld !*pair,a", _pairs[pairId].name);
6601 emit2 ("inc %s", _pairs[pairId].name);
6602 _G.pairs[pairId].offset++;
6608 freeAsmop (right, NULL, ic);
6611 /*-----------------------------------------------------------------*/
6612 /* genPointerSet - stores the value into a pointer location */
6613 /*-----------------------------------------------------------------*/
6615 genPointerSet (iCode * ic)
6617 operand *right, *result;
6618 sym_link *type, *etype;
6620 right = IC_RIGHT (ic);
6621 result = IC_RESULT (ic);
6623 /* depending on the type of pointer we need to
6624 move it to the correct pointer register */
6625 type = operandType (result);
6626 etype = getSpec (type);
6628 genGenPointerSet (right, result, ic);
6631 /*-----------------------------------------------------------------*/
6632 /* genIfx - generate code for Ifx statement */
6633 /*-----------------------------------------------------------------*/
6635 genIfx (iCode * ic, iCode * popIc)
6637 operand *cond = IC_COND (ic);
6640 aopOp (cond, ic, FALSE, TRUE);
6642 /* get the value into acc */
6643 if (AOP_TYPE (cond) != AOP_CRY)
6647 /* the result is now in the accumulator */
6648 freeAsmop (cond, NULL, ic);
6650 /* if there was something to be popped then do it */
6654 /* if the condition is a bit variable */
6655 if (isbit && IS_ITEMP (cond) &&
6657 genIfxJump (ic, SPIL_LOC (cond)->rname);
6658 else if (isbit && !IS_ITEMP (cond))
6659 genIfxJump (ic, OP_SYMBOL (cond)->rname);
6661 genIfxJump (ic, "a");
6666 /*-----------------------------------------------------------------*/
6667 /* genAddrOf - generates code for address of */
6668 /*-----------------------------------------------------------------*/
6670 genAddrOf (iCode * ic)
6672 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
6674 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6676 /* if the operand is on the stack then we
6677 need to get the stack offset of this
6684 if (sym->stack <= 0)
6686 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
6690 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6692 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6696 emit2 ("ld de,!hashedstr", sym->rname);
6697 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
6705 /* if it has an offset then we need to compute it */
6707 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6709 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
6710 emit2 ("add hl,sp");
6714 emit2 ("ld hl,!hashedstr", sym->rname);
6716 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6718 freeAsmop (IC_RESULT (ic), NULL, ic);
6721 /*-----------------------------------------------------------------*/
6722 /* genAssign - generate code for assignment */
6723 /*-----------------------------------------------------------------*/
6725 genAssign (iCode * ic)
6727 operand *result, *right;
6729 unsigned long lit = 0L;
6731 result = IC_RESULT (ic);
6732 right = IC_RIGHT (ic);
6734 /* Dont bother assigning if they are the same */
6735 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6737 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
6741 aopOp (right, ic, FALSE, FALSE);
6742 aopOp (result, ic, TRUE, FALSE);
6744 /* if they are the same registers */
6745 if (sameRegs (AOP (right), AOP (result)))
6747 emitDebug ("; (registers are the same)");
6751 /* if the result is a bit */
6752 if (AOP_TYPE (result) == AOP_CRY)
6754 wassertl (0, "Tried to assign to a bit");
6758 size = AOP_SIZE (result);
6761 if (AOP_TYPE (right) == AOP_LIT)
6763 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6766 if (isPair (AOP (result)))
6768 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
6770 else if ((size > 1) &&
6771 (AOP_TYPE (result) != AOP_REG) &&
6772 (AOP_TYPE (right) == AOP_LIT) &&
6773 !IS_FLOAT (operandType (right)) &&
6776 bool fXored = FALSE;
6778 /* Work from the top down.
6779 Done this way so that we can use the cached copy of 0
6780 in A for a fast clear */
6783 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
6785 if (!fXored && size > 1)
6792 aopPut (AOP (result), "a", offset);
6796 aopPut (AOP (result), "!zero", offset);
6800 aopPut (AOP (result),
6801 aopGet (AOP (right), offset, FALSE),
6806 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
6808 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
6809 aopPut (AOP (result), "l", LSB);
6810 aopPut (AOP (result), "h", MSB16);
6812 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6814 /* Special case. Load into a and d, then load out. */
6815 _moveA (aopGet (AOP (right), 0, FALSE));
6816 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
6817 aopPut (AOP (result), "a", 0);
6818 aopPut (AOP (result), "e", 1);
6820 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6822 /* Special case - simple memcpy */
6823 aopGet (AOP (right), LSB, FALSE);
6826 aopGet (AOP (result), LSB, FALSE);
6830 emit2 ("ld a,(de)");
6831 /* Peephole will optimise this. */
6832 emit2 ("ld (hl),a");
6840 spillPair (PAIR_HL);
6846 /* PENDING: do this check better */
6847 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
6849 _moveA (aopGet (AOP (right), offset, FALSE));
6850 aopPut (AOP (result), "a", offset);
6853 aopPut (AOP (result),
6854 aopGet (AOP (right), offset, FALSE),
6861 freeAsmop (right, NULL, ic);
6862 freeAsmop (result, NULL, ic);
6865 /*-----------------------------------------------------------------*/
6866 /* genJumpTab - genrates code for jump table */
6867 /*-----------------------------------------------------------------*/
6869 genJumpTab (iCode * ic)
6874 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
6875 /* get the condition into accumulator */
6876 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
6879 emit2 ("ld e,%s", l);
6880 emit2 ("ld d,!zero");
6881 jtab = newiTempLabel (NULL);
6883 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
6884 emit2 ("add hl,de");
6885 emit2 ("add hl,de");
6886 emit2 ("add hl,de");
6887 freeAsmop (IC_JTCOND (ic), NULL, ic);
6891 emitLabel (jtab->key + 100);
6892 /* now generate the jump labels */
6893 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
6894 jtab = setNextItem (IC_JTLABELS (ic)))
6895 emit2 ("jp !tlabel", jtab->key + 100);
6898 /*-----------------------------------------------------------------*/
6899 /* genCast - gen code for casting */
6900 /*-----------------------------------------------------------------*/
6902 genCast (iCode * ic)
6904 operand *result = IC_RESULT (ic);
6905 sym_link *rtype = operandType (IC_RIGHT (ic));
6906 operand *right = IC_RIGHT (ic);
6909 /* if they are equivalent then do nothing */
6910 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6913 aopOp (right, ic, FALSE, FALSE);
6914 aopOp (result, ic, FALSE, FALSE);
6916 /* if the result is a bit */
6917 if (AOP_TYPE (result) == AOP_CRY)
6919 wassertl (0, "Tried to cast to a bit");
6922 /* if they are the same size : or less */
6923 if (AOP_SIZE (result) <= AOP_SIZE (right))
6926 /* if they are in the same place */
6927 if (sameRegs (AOP (right), AOP (result)))
6930 /* if they in different places then copy */
6931 size = AOP_SIZE (result);
6935 aopPut (AOP (result),
6936 aopGet (AOP (right), offset, FALSE),
6943 /* So we now know that the size of destination is greater
6944 than the size of the source */
6945 /* we move to result for the size of source */
6946 size = AOP_SIZE (right);
6950 aopPut (AOP (result),
6951 aopGet (AOP (right), offset, FALSE),
6956 /* now depending on the sign of the destination */
6957 size = AOP_SIZE (result) - AOP_SIZE (right);
6958 /* Unsigned or not an integral type - right fill with zeros */
6959 if (SPEC_USIGN (rtype) || !IS_SPEC (rtype) || AOP_TYPE(right)==AOP_CRY)
6962 aopPut (AOP (result), "!zero", offset++);
6966 /* we need to extend the sign :{ */
6967 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
6973 aopPut (AOP (result), "a", offset++);
6977 freeAsmop (right, NULL, ic);
6978 freeAsmop (result, NULL, ic);
6981 /*-----------------------------------------------------------------*/
6982 /* genReceive - generate code for a receive iCode */
6983 /*-----------------------------------------------------------------*/
6985 genReceive (iCode * ic)
6987 if (isOperandInFarSpace (IC_RESULT (ic)) &&
6988 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
6989 IS_TRUE_SYMOP (IC_RESULT (ic))))
6999 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7000 size = AOP_SIZE(IC_RESULT(ic));
7002 for (i = 0; i < size; i++) {
7003 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
7007 freeAsmop (IC_RESULT (ic), NULL, ic);
7010 /*-----------------------------------------------------------------*/
7011 /* genDummyRead - generate code for dummy read of volatiles */
7012 /*-----------------------------------------------------------------*/
7014 genDummyRead (iCode * ic)
7016 emit2 ("; genDummyRead not implemented");
7023 /** Maximum number of bytes to emit per line. */
7027 /** Context for the byte output chunker. */
7030 unsigned char buffer[DBEMIT_MAX_RUN];
7035 /** Flushes a byte chunker by writing out all in the buffer and
7039 _dbFlush(DBEMITCTX *self)
7046 sprintf(line, ".db 0x%02X", self->buffer[0]);
7048 for (i = 1; i < self->pos; i++)
7050 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7057 /** Write out another byte, buffering until a decent line is
7061 _dbEmit(DBEMITCTX *self, int c)
7063 if (self->pos == DBEMIT_MAX_RUN)
7067 self->buffer[self->pos++] = c;
7070 /** Context for a simple run length encoder. */
7074 unsigned char buffer[128];
7076 /** runLen may be equivalent to pos. */
7082 RLE_CHANGE_COST = 4,
7086 /** Flush the buffer of a run length encoder by writing out the run or
7087 data that it currently contains.
7090 _rleCommit(RLECTX *self)
7096 memset(&db, 0, sizeof(db));
7098 emit2(".db %u", self->pos);
7100 for (i = 0; i < self->pos; i++)
7102 _dbEmit(&db, self->buffer[i]);
7111 Can get either a run or a block of random stuff.
7112 Only want to change state if a good run comes in or a run ends.
7113 Detecting run end is easy.
7116 Say initial state is in run, len zero, last zero. Then if you get a
7117 few zeros then something else then a short run will be output.
7118 Seems OK. While in run mode, keep counting. While in random mode,
7119 keep a count of the run. If run hits margin, output all up to run,
7120 restart, enter run mode.
7123 /** Add another byte into the run length encoder, flushing as
7124 required. The run length encoder uses the Amiga IFF style, where
7125 a block is prefixed by its run length. A positive length means
7126 the next n bytes pass straight through. A negative length means
7127 that the next byte is repeated -n times. A zero terminates the
7131 _rleAppend(RLECTX *self, int c)
7135 if (c != self->last)
7137 /* The run has stopped. See if it is worthwhile writing it out
7138 as a run. Note that the random data comes in as runs of
7141 if (self->runLen > RLE_CHANGE_COST)
7143 /* Yes, worthwhile. */
7144 /* Commit whatever was in the buffer. */
7146 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7150 /* Not worthwhile. Append to the end of the random list. */
7151 for (i = 0; i < self->runLen; i++)
7153 if (self->pos >= RLE_MAX_BLOCK)
7158 self->buffer[self->pos++] = self->last;
7166 if (self->runLen >= RLE_MAX_BLOCK)
7168 /* Commit whatever was in the buffer. */
7171 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7179 _rleFlush(RLECTX *self)
7181 _rleAppend(self, -1);
7188 /** genArrayInit - Special code for initialising an array with constant
7192 genArrayInit (iCode * ic)
7196 int elementSize = 0, eIndex, i;
7197 unsigned val, lastVal;
7201 memset(&rle, 0, sizeof(rle));
7203 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7205 _saveRegsForCall(ic, 0);
7207 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7208 emit2 ("call __initrleblock");
7210 type = operandType(IC_LEFT(ic));
7212 if (type && type->next)
7214 elementSize = getSize(type->next);
7218 wassertl (0, "Can't determine element size in genArrayInit.");
7221 iLoop = IC_ARRAYILIST(ic);
7222 lastVal = (unsigned)-1;
7224 /* Feed all the bytes into the run length encoder which will handle
7226 This works well for mixed char data, and for random int and long
7235 for (i = 0; i < ix; i++)
7237 for (eIndex = 0; eIndex < elementSize; eIndex++)
7239 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7240 _rleAppend(&rle, val);
7245 iLoop = iLoop->next;
7249 /* Mark the end of the run. */
7252 _restoreRegsAfterCall();
7256 freeAsmop (IC_LEFT(ic), NULL, ic);
7260 _swap (PAIR_ID one, PAIR_ID two)
7262 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7268 emit2 ("ld a,%s", _pairs[one].l);
7269 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7270 emit2 ("ld %s,a", _pairs[two].l);
7271 emit2 ("ld a,%s", _pairs[one].h);
7272 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7273 emit2 ("ld %s,a", _pairs[two].h);
7277 /* The problem is that we may have all three pairs used and they may
7278 be needed in a different order.
7283 hl = hl => unity, fine
7287 hl = hl hl = hl, swap de <=> bc
7295 hl = bc de = de, swap bc <=> hl
7303 hl = de bc = bc, swap hl <=> de
7308 * Any pair = pair are done last
7309 * Any pair = iTemp are done last
7310 * Any swaps can be done any time
7318 So how do we detect the cases?
7319 How about a 3x3 matrix?
7323 x x x x (Fourth for iTemp/other)
7325 First determin which mode to use by counting the number of unity and
7328 Two - Assign the pair first, then the rest
7329 One - Swap the two, then the rest
7333 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7335 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7337 PAIR_BC, PAIR_HL, PAIR_DE
7339 int i, j, nunity = 0;
7340 memset (ids, PAIR_INVALID, sizeof (ids));
7343 wassert (nparams == 3);
7345 /* First save everything that needs to be saved. */
7346 _saveRegsForCall (ic, 0);
7348 /* Loading HL first means that DE is always fine. */
7349 for (i = 0; i < nparams; i++)
7351 aopOp (pparams[i], ic, FALSE, FALSE);
7352 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7355 /* Count the number of unity or iTemp assigns. */
7356 for (i = 0; i < 3; i++)
7358 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7366 /* Any order, fall through. */
7368 else if (nunity == 2)
7370 /* One is assigned. Pull it out and assign. */
7371 for (i = 0; i < 3; i++)
7373 for (j = 0; j < NUM_PAIRS; j++)
7375 if (ids[dest[i]][j] == TRUE)
7377 /* Found it. See if it's the right one. */
7378 if (j == PAIR_INVALID || j == dest[i])
7384 fetchPair(dest[i], AOP (pparams[i]));
7391 else if (nunity == 1)
7393 /* Find the pairs to swap. */
7394 for (i = 0; i < 3; i++)
7396 for (j = 0; j < NUM_PAIRS; j++)
7398 if (ids[dest[i]][j] == TRUE)
7400 if (j == PAIR_INVALID || j == dest[i])
7415 int next = getPairId (AOP (pparams[0]));
7416 emit2 ("push %s", _pairs[next].name);
7418 if (next == dest[1])
7420 fetchPair (dest[1], AOP (pparams[1]));
7421 fetchPair (dest[2], AOP (pparams[2]));
7425 fetchPair (dest[2], AOP (pparams[2]));
7426 fetchPair (dest[1], AOP (pparams[1]));
7428 emit2 ("pop %s", _pairs[dest[0]].name);
7431 /* Finally pull out all of the iTemps */
7432 for (i = 0; i < 3; i++)
7434 if (ids[dest[i]][PAIR_INVALID] == 1)
7436 fetchPair (dest[i], AOP (pparams[i]));
7442 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
7448 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
7452 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7454 setupForBuiltin3 (ic, nParams, pparams);
7456 label = newiTempLabel(NULL);
7458 emitLabel (label->key);
7459 emit2 ("ld a,(hl)");
7462 emit2 ("!shortjp nz,!tlabel ; 1", label->key);
7464 freeAsmop (from, NULL, ic->next);
7465 freeAsmop (to, NULL, ic);
7469 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
7471 operand *from, *to, *count;
7474 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
7479 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7481 setupForBuiltin3 (ic, nParams, pparams);
7485 freeAsmop (count, NULL, ic->next->next);
7486 freeAsmop (from, NULL, ic);
7488 _restoreRegsAfterCall();
7490 /* if we need assign a result value */
7491 if ((IS_ITEMP (IC_RESULT (ic)) &&
7492 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
7493 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
7494 IS_TRUE_SYMOP (IC_RESULT (ic)))
7496 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7497 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
7498 freeAsmop (IC_RESULT (ic), NULL, ic);
7501 freeAsmop (to, NULL, ic->next);
7504 /*-----------------------------------------------------------------*/
7505 /* genBuiltIn - calls the appropriate function to generating code */
7506 /* for a built in function */
7507 /*-----------------------------------------------------------------*/
7508 static void genBuiltIn (iCode *ic)
7510 operand *bi_parms[MAX_BUILTIN_ARGS];
7515 /* get all the arguments for a built in function */
7516 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
7518 /* which function is it */
7519 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
7521 if (strcmp(bif->name,"__builtin_strcpy")==0)
7523 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
7525 else if (strcmp(bif->name,"__builtin_memcpy")==0)
7527 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
7531 wassertl (0, "Unknown builtin function encountered");
7535 /*-----------------------------------------------------------------*/
7536 /* genZ80Code - generate code for Z80 based controllers */
7537 /*-----------------------------------------------------------------*/
7539 genZ80Code (iCode * lic)
7547 _fReturn = _gbz80_return;
7548 _fTmp = _gbz80_return;
7552 _fReturn = _z80_return;
7553 _fTmp = _z80_return;
7556 _G.lines.head = _G.lines.current = NULL;
7558 for (ic = lic; ic; ic = ic->next)
7561 if (cln != ic->lineno)
7563 if (!options.noCcodeInAsm) {
7564 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
7565 printCLine(ic->filename, ic->lineno));
7569 if (options.iCodeInAsm) {
7570 emit2 (";ic:%d: %s", ic->key, printILine(ic));
7572 /* if the result is marked as
7573 spilt and rematerializable or code for
7574 this has already been generated then
7576 if (resultRemat (ic) || ic->generated)
7579 /* depending on the operation */
7583 emitDebug ("; genNot");
7588 emitDebug ("; genCpl");
7593 emitDebug ("; genUminus");
7598 emitDebug ("; genIpush");
7603 /* IPOP happens only when trying to restore a
7604 spilt live range, if there is an ifx statement
7605 following this pop then the if statement might
7606 be using some of the registers being popped which
7607 would destory the contents of the register so
7608 we need to check for this condition and handle it */
7610 ic->next->op == IFX &&
7611 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
7613 emitDebug ("; genIfx");
7614 genIfx (ic->next, ic);
7618 emitDebug ("; genIpop");
7624 emitDebug ("; genCall");
7629 emitDebug ("; genPcall");
7634 emitDebug ("; genFunction");
7639 emitDebug ("; genEndFunction");
7640 genEndFunction (ic);
7644 emitDebug ("; genRet");
7649 emitDebug ("; genLabel");
7654 emitDebug ("; genGoto");
7659 emitDebug ("; genPlus");
7664 emitDebug ("; genMinus");
7669 emitDebug ("; genMult");
7674 emitDebug ("; genDiv");
7679 emitDebug ("; genMod");
7684 emitDebug ("; genCmpGt");
7685 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
7689 emitDebug ("; genCmpLt");
7690 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
7697 /* note these two are xlated by algebraic equivalence
7698 during parsing SDCC.y */
7699 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
7700 "got '>=' or '<=' shouldn't have come here");
7704 emitDebug ("; genCmpEq");
7705 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
7709 emitDebug ("; genAndOp");
7714 emitDebug ("; genOrOp");
7719 emitDebug ("; genXor");
7720 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
7724 emitDebug ("; genOr");
7725 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
7729 emitDebug ("; genAnd");
7730 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
7734 emitDebug ("; genInline");
7739 emitDebug ("; genRRC");
7744 emitDebug ("; genRLC");
7749 emitDebug ("; genGetHBIT");
7754 emitDebug ("; genLeftShift");
7759 emitDebug ("; genRightShift");
7763 case GET_VALUE_AT_ADDRESS:
7764 emitDebug ("; genPointerGet");
7770 if (POINTER_SET (ic))
7772 emitDebug ("; genAssign (pointer)");
7777 emitDebug ("; genAssign");
7783 emitDebug ("; genIfx");
7788 emitDebug ("; genAddrOf");
7793 emitDebug ("; genJumpTab");
7798 emitDebug ("; genCast");
7803 emitDebug ("; genReceive");
7808 if (ic->builtinSEND)
7810 emitDebug ("; genBuiltIn");
7815 emitDebug ("; addSet");
7816 addSet (&_G.sendSet, ic);
7821 emitDebug ("; genArrayInit");
7825 case DUMMY_READ_VOLATILE:
7835 /* now we are ready to call the
7836 peep hole optimizer */
7837 if (!options.nopeep)
7838 peepHole (&_G.lines.head);
7840 /* This is unfortunate */
7841 /* now do the actual printing */
7843 FILE *fp = codeOutFile;
7844 if (isInHome () && codeOutFile == code->oFile)
7845 codeOutFile = home->oFile;
7846 printLine (_G.lines.head, codeOutFile);
7847 if (_G.flushStatics)
7850 _G.flushStatics = 0;
7855 freeTrace(&_G.lines.trace);
7856 freeTrace(&_G.trace.aops);
7862 _isPairUsed (iCode * ic, PAIR_ID pairId)
7868 if (bitVectBitValue (ic->rMask, D_IDX))
7870 if (bitVectBitValue (ic->rMask, E_IDX))
7880 fetchLitSpecial (asmop * aop, bool negate, bool xor)
7883 value *val = aop->aopu.aop_lit;
7885 wassert (aop->type == AOP_LIT);
7886 wassert (!IS_FLOAT (val->type));
7888 v = (unsigned long) floatFromVal (val);
7896 tsprintf (buffer, sizeof(buffer), "!immedword", v);
7897 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));