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
96 #ifdef HAVE_SYS_ISA_DEFS_H
97 #include <sys/isa_defs.h>
101 #include "SDCCglobl.h"
102 #include "SDCCpeeph.h"
104 #include "SDCCglue.h"
105 #include "newalloc.h"
107 /* This is the down and dirty file with all kinds of kludgy & hacky
108 stuff. This is what it is all about CODE GENERATION for a specific MCU.
109 Some of the routines may be reusable, will have to see */
111 /* Z80 calling convention description.
112 Parameters are passed right to left. As the stack grows downwards,
113 the parameters are arranged in left to right in memory.
114 Parameters may be passed in the HL and DE registers with one
116 PENDING: What if the parameter is a long?
117 Everything is caller saves. i.e. the caller must save any registers
118 that it wants to preserve over the call.
119 GB: The return value is returned in DEHL. DE is normally used as a
120 working register pair. Caller saves allows it to be used for a
122 va args functions do not use register parameters. All arguments
123 are passed on the stack.
124 IX is used as an index register to the top of the local variable
125 area. ix-0 is the top most local variable.
130 /* Set to enable debugging trace statements in the output assembly code. */
134 static char *_z80_return[] =
135 {"l", "h", "e", "d"};
136 static char *_gbz80_return[] =
137 {"e", "d", "l", "h"};
138 static char *_fReceive[] =
139 { "c", "b", "e", "d" };
141 static char **_fReturn;
144 extern FILE *codeOutFile;
152 /** Enum covering all the possible register pairs.
171 } _pairs[NUM_PAIRS] = {
172 { "??1", "?2", "?3" },
177 { "iy", "iyl", "iyh" },
178 { "ix", "ixl", "ixh" }
182 #define ACC_NAME _pairs[PAIR_AF].h
192 /** Code generator persistent data.
196 /** Used to optimised setting up of a pair by remebering what it
197 contains and adjusting instead of reloading where possible.
225 const char *lastFunctionName;
231 /** TRUE if the registers have already been saved. */
249 static const char *aopGet (asmop * aop, int offset, bool bit16);
251 static const char *aopNames[] = {
271 isLastUse (iCode *ic, operand *op)
273 bitVect *uses = bitVectCopy (OP_USES (op));
275 while (!bitVectIsZero (uses))
277 if (bitVectFirstBit (uses) == ic->key)
279 if (bitVectnBitsOn (uses) == 1)
288 bitVectUnSetBit (uses, bitVectFirstBit (uses));
308 _getTempPairName(void)
310 return _pairs[_getTempPairId()].name;
314 isPairInUse (PAIR_ID id, iCode *ic)
318 return bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
320 else if (id == PAIR_BC)
322 return bitVectBitValue (ic->rMask, B_IDX) || bitVectBitValue(ic->rMask, C_IDX);
326 wassertl (0, "Only implemented for DE and BC");
332 isPairInUseNotInRet(PAIR_ID id, iCode *ic)
336 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
340 return bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
344 wassertl (0, "Only implemented for DE");
350 getFreePairId (iCode *ic)
352 if (!isPairInUse (PAIR_BC, ic))
356 else if (IS_Z80 && !isPairInUse (PAIR_DE, ic))
369 /* Clean up the line so that it is 'prettier' */
370 if (strchr (buf, ':'))
372 /* Is a label - cant do anything */
375 /* Change the first (and probably only) ' ' to a tab so
390 _newLineNode (char *line)
394 pl = traceAlloc(&_G.lines.trace, Safe_alloc ( sizeof (lineNode)));
395 pl->line = traceAlloc(&_G.lines.trace, Safe_strdup (line));
401 _vemit2 (const char *szFormat, va_list ap)
405 tvsprintf (buffer, szFormat, ap);
408 _G.lines.current = (_G.lines.current ?
409 connectLine (_G.lines.current, _newLineNode (buffer)) :
410 (_G.lines.head = _newLineNode (buffer)));
412 _G.lines.current->isInline = _G.lines.isInline;
416 emit2 (const char *szFormat,...)
420 va_start (ap, szFormat);
422 _vemit2 (szFormat, ap);
428 emitDebug (const char *szFormat,...)
434 va_start (ap, szFormat);
436 _vemit2 (szFormat, ap);
442 /*-----------------------------------------------------------------*/
443 /* emit2 - writes the code into a file : for now it is simple */
444 /*-----------------------------------------------------------------*/
446 _emit2 (const char *inst, const char *fmt,...)
449 char lb[INITIAL_INLINEASM];
456 sprintf (lb, "%s\t", inst);
457 vsprintf (lb + (strlen (lb)), fmt, ap);
460 vsprintf (lb, fmt, ap);
462 while (isspace (*lbp))
467 _G.lines.current = (_G.lines.current ?
468 connectLine (_G.lines.current, _newLineNode (lb)) :
469 (_G.lines.head = _newLineNode (lb)));
471 _G.lines.current->isInline = _G.lines.isInline;
476 _emitMove(const char *to, const char *from)
478 if (STRCASECMP(to, from) != 0)
480 emit2("ld %s,%s", to, from);
485 // Could leave this to the peephole, but sometimes the peephole is inhibited.
490 aopDump(const char *plabel, asmop *aop)
492 emitDebug("; Dump of %s: type %s size %u", plabel, aopNames[aop->type], aop->size);
496 emitDebug("; aop_stk %d", aop->aopu.aop_stk);
499 /* No information. */
505 _moveA(const char *moveFrom)
507 // Let the peephole optimiser take care of redundent loads
508 _emitMove(ACC_NAME, moveFrom);
518 getPairName (asmop * aop)
520 if (aop->type == AOP_REG)
522 switch (aop->aopu.aop_reg[0]->rIdx)
535 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
538 for (i = 0; i < NUM_PAIRS; i++)
540 if (strcmp(aop->aopu.aop_str[0], _pairs[i].l) == 0)
542 return _pairs[i].name;
546 wassertl (0, "Tried to get the pair name of something that isn't a pair");
551 getPairId (asmop * aop)
555 if (aop->type == AOP_REG)
557 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX) && (aop->aopu.aop_reg[1]->rIdx == B_IDX))
561 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX) && (aop->aopu.aop_reg[1]->rIdx == D_IDX))
565 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX) && (aop->aopu.aop_reg[1]->rIdx == H_IDX))
570 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
573 for (i = 0; i < NUM_PAIRS; i++)
575 if (!strcmp (aop->aopu.aop_str[0], _pairs[i].l) && !strcmp (aop->aopu.aop_str[1], _pairs[i].h))
585 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
589 return (getPairId (aop) != PAIR_INVALID);
593 isPtrPair (asmop * aop)
595 PAIR_ID pairId = getPairId (aop);
608 spillPair (PAIR_ID pairId)
610 _G.pairs[pairId].last_type = AOP_INVALID;
611 _G.pairs[pairId].base = NULL;
614 /** Push a register pair onto the stack */
616 genPairPush (asmop * aop)
618 emit2 ("push %s", getPairName (aop));
622 _push (PAIR_ID pairId)
624 emit2 ("push %s", _pairs[pairId].name);
625 _G.stack.pushed += 2;
629 _pop (PAIR_ID pairId)
631 emit2 ("pop %s", _pairs[pairId].name);
632 _G.stack.pushed -= 2;
636 /*-----------------------------------------------------------------*/
637 /* newAsmop - creates a new asmOp */
638 /*-----------------------------------------------------------------*/
640 newAsmop (short type)
644 aop = traceAlloc(&_G.trace.aops, Safe_alloc (sizeof (asmop)));
649 /*-----------------------------------------------------------------*/
650 /* aopForSym - for a true symbol */
651 /*-----------------------------------------------------------------*/
653 aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
660 wassert (sym->etype);
662 space = SPEC_OCLS (sym->etype);
664 /* if already has one */
670 /* Assign depending on the storage class */
671 if (sym->onStack || sym->iaccess)
673 /* The pointer that is used depends on how big the offset is.
674 Normally everything is AOP_STK, but for offsets of < -128 or
675 > 127 on the Z80 an extended stack pointer is used.
677 if (IS_Z80 && (options.ommitFramePtr || sym->stack < INT8MIN || sym->stack > (int)(INT8MAX-getSize (sym->type))))
679 emitDebug ("; AOP_EXSTK for %s", sym->rname);
680 sym->aop = aop = newAsmop (AOP_EXSTK);
684 emitDebug ("; AOP_STK for %s", sym->rname);
685 sym->aop = aop = newAsmop (AOP_STK);
688 aop->size = getSize (sym->type);
689 aop->aopu.aop_stk = sym->stack;
693 /* special case for a function */
694 if (IS_FUNC (sym->type))
696 sym->aop = aop = newAsmop (AOP_IMMD);
697 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup (sym->rname));
704 /* if it is in direct space */
705 if (IN_REGSP (space) && !requires_a)
707 sym->aop = aop = newAsmop (AOP_SFR);
708 aop->aopu.aop_dir = sym->rname;
709 aop->size = getSize (sym->type);
710 emitDebug ("; AOP_SFR for %s", sym->rname);
715 /* only remaining is far space */
716 /* in which case DPTR gets the address */
719 emitDebug ("; AOP_HL for %s", sym->rname);
720 sym->aop = aop = newAsmop (AOP_HL);
724 sym->aop = aop = newAsmop (AOP_IY);
726 aop->size = getSize (sym->type);
727 aop->aopu.aop_dir = sym->rname;
729 /* if it is in code space */
730 if (IN_CODESPACE (space))
736 /*-----------------------------------------------------------------*/
737 /* aopForRemat - rematerialzes an object */
738 /*-----------------------------------------------------------------*/
740 aopForRemat (symbol * sym)
743 iCode *ic = sym->rematiCode;
744 asmop *aop = newAsmop (AOP_IMMD);
748 /* if plus or minus print the right hand side */
749 if (ic->op == '+' || ic->op == '-')
751 /* PENDING: for re-target */
752 sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
755 ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
758 /* we reached the end */
759 sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
763 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
767 /*-----------------------------------------------------------------*/
768 /* regsInCommon - two operands have some registers in common */
769 /*-----------------------------------------------------------------*/
771 regsInCommon (operand * op1, operand * op2)
776 /* if they have registers in common */
777 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
780 sym1 = OP_SYMBOL (op1);
781 sym2 = OP_SYMBOL (op2);
783 if (sym1->nRegs == 0 || sym2->nRegs == 0)
786 for (i = 0; i < sym1->nRegs; i++)
792 for (j = 0; j < sym2->nRegs; j++)
797 if (sym2->regs[j] == sym1->regs[i])
805 /*-----------------------------------------------------------------*/
806 /* operandsEqu - equivalent */
807 /*-----------------------------------------------------------------*/
809 operandsEqu (operand * op1, operand * op2)
813 /* if they not symbols */
814 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
817 sym1 = OP_SYMBOL (op1);
818 sym2 = OP_SYMBOL (op2);
820 /* if both are itemps & one is spilt
821 and the other is not then false */
822 if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
823 sym1->isspilt != sym2->isspilt)
826 /* if they are the same */
830 if (strcmp (sym1->rname, sym2->rname) == 0)
834 /* if left is a tmp & right is not */
835 if (IS_ITEMP (op1) &&
838 (sym1->usl.spillLoc == sym2))
841 if (IS_ITEMP (op2) &&
845 (sym2->usl.spillLoc == sym1))
851 /*-----------------------------------------------------------------*/
852 /* sameRegs - two asmops have the same registers */
853 /*-----------------------------------------------------------------*/
855 sameRegs (asmop * aop1, asmop * aop2)
859 if (aop1->type == AOP_SFR ||
860 aop2->type == AOP_SFR)
866 if (aop1->type != AOP_REG ||
867 aop2->type != AOP_REG)
870 if (aop1->size != aop2->size)
873 for (i = 0; i < aop1->size; i++)
874 if (aop1->aopu.aop_reg[i] !=
875 aop2->aopu.aop_reg[i])
881 /*-----------------------------------------------------------------*/
882 /* aopOp - allocates an asmop for an operand : */
883 /*-----------------------------------------------------------------*/
885 aopOp (operand * op, iCode * ic, bool result, bool requires_a)
894 /* if this a literal */
895 if (IS_OP_LITERAL (op))
897 op->aop = aop = newAsmop (AOP_LIT);
898 aop->aopu.aop_lit = op->operand.valOperand;
899 aop->size = getSize (operandType (op));
903 /* if already has a asmop then continue */
909 /* if the underlying symbol has a aop */
910 if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
912 op->aop = OP_SYMBOL (op)->aop;
916 /* if this is a true symbol */
917 if (IS_TRUE_SYMOP (op))
919 op->aop = aopForSym (ic, OP_SYMBOL (op), result, requires_a);
923 /* this is a temporary : this has
929 e) can be a return use only */
931 sym = OP_SYMBOL (op);
933 /* if the type is a conditional */
934 if (sym->regType == REG_CND)
936 aop = op->aop = sym->aop = newAsmop (AOP_CRY);
941 /* if it is spilt then two situations
943 b) has a spill location */
944 if (sym->isspilt || sym->nRegs == 0)
946 /* rematerialize it NOW */
949 sym->aop = op->aop = aop =
951 aop->size = getSize (sym->type);
958 aop = op->aop = sym->aop = newAsmop (AOP_STR);
959 aop->size = getSize (sym->type);
960 for (i = 0; i < 4; i++)
961 aop->aopu.aop_str[i] = _fReturn[i];
967 if (sym->accuse == ACCUSE_A)
969 aop = op->aop = sym->aop = newAsmop (AOP_ACC);
970 aop->size = getSize (sym->type);
971 wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
973 aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
975 else if (sym->accuse == ACCUSE_SCRATCH)
977 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
978 aop->size = getSize (sym->type);
979 wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
980 aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
981 aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
983 else if (sym->accuse == ACCUSE_IY)
985 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
986 aop->size = getSize (sym->type);
987 wassertl(aop->size <= 2, "Internal error: Caching in IY, but too big to fit in IY");
988 aop->aopu.aop_str[0] = _pairs[PAIR_IY].l;
989 aop->aopu.aop_str[1] = _pairs[PAIR_IY].h;
993 wassertl (0, "Marked as being allocated into A or HL but is actually in neither");
998 /* else spill location */
999 if (sym->usl.spillLoc && getSize(sym->type) != getSize(sym->usl.spillLoc->type)) {
1000 /* force a new aop if sizes differ */
1001 sym->usl.spillLoc->aop = NULL;
1003 sym->aop = op->aop = aop =
1004 aopForSym (ic, sym->usl.spillLoc, result, requires_a);
1005 wassertl (aop->size >= getSize (sym->type), "Operand doesn't fit in the spill location");
1006 aop->size = getSize (sym->type);
1010 /* must be in a register */
1011 sym->aop = op->aop = aop = newAsmop (AOP_REG);
1012 aop->size = sym->nRegs;
1013 for (i = 0; i < sym->nRegs; i++)
1014 aop->aopu.aop_reg[i] = sym->regs[i];
1017 /*-----------------------------------------------------------------*/
1018 /* freeAsmop - free up the asmop given to an operand */
1019 /*----------------------------------------------------------------*/
1021 freeAsmop (operand * op, asmop * aaop, iCode * ic)
1038 if (aop->type == AOP_PAIRPTR && IS_Z80 && aop->aopu.aop_pairId == PAIR_DE)
1040 _pop (aop->aopu.aop_pairId);
1043 if (getPairId (aop) == PAIR_HL)
1045 spillPair (PAIR_HL);
1049 /* all other cases just dealloc */
1055 OP_SYMBOL (op)->aop = NULL;
1056 /* if the symbol has a spill */
1058 SPIL_LOC (op)->aop = NULL;
1065 isLitWord (asmop * aop)
1067 /* if (aop->size != 2)
1080 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
1084 /* depending on type */
1090 /* PENDING: for re-target */
1093 tsprintf (s, "!hashedstr + %d", aop->aopu.aop_immd, offset);
1095 else if (offset == 0)
1097 tsprintf (s, "%s", aop->aopu.aop_immd);
1101 tsprintf (s, "%s + %d", aop->aopu.aop_immd, offset);
1103 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1107 value *val = aop->aopu.aop_lit;
1108 /* if it is a float then it gets tricky */
1109 /* otherwise it is fairly simple */
1110 if (!IS_FLOAT (val->type))
1112 unsigned long v = (unsigned long) floatFromVal (val);
1118 else if (offset == 0)
1124 wassertl(0, "Encountered an invalid offset while fetching a literal");
1128 tsprintf (buffer, "!immedword", v);
1130 tsprintf (buffer, "!constword", v);
1132 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1143 /* it is type float */
1144 fl.f = (float) floatFromVal (val);
1147 i = fl.c[3-offset] | (fl.c[3-offset-1]<<8);
1149 i = fl.c[offset] | (fl.c[offset+1]<<8);
1152 tsprintf (buffer, "!immedword", i);
1154 tsprintf (buffer, "!constword", i);
1156 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1165 aopGetWord (asmop * aop, int offset)
1167 return aopGetLitWordLong (aop, offset, TRUE);
1171 isPtr (const char *s)
1173 if (!strcmp (s, "hl"))
1175 if (!strcmp (s, "ix"))
1177 if (!strcmp (s, "iy"))
1183 adjustPair (const char *pair, int *pold, int new)
1189 emit2 ("inc %s", pair);
1194 emit2 ("dec %s", pair);
1202 spillPair (PAIR_HL);
1203 spillPair (PAIR_IY);
1207 requiresHL (asmop * aop)
1223 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1225 const char *l, *base;
1226 const char *pair = _pairs[pairId].name;
1227 l = aopGetLitWordLong (left, offset, FALSE);
1228 base = aopGetLitWordLong (left, 0, FALSE);
1229 wassert (l && pair && base);
1233 if (pairId == PAIR_HL || pairId == PAIR_IY)
1235 if (_G.pairs[pairId].last_type == left->type)
1237 if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1239 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1241 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1244 if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
1251 _G.pairs[pairId].last_type = left->type;
1252 _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1253 _G.pairs[pairId].offset = offset;
1255 /* Both a lit on the right and a true symbol on the left */
1256 emit2 ("ld %s,!hashedstr", pair, l);
1260 makeFreePairId (iCode *ic, bool *pisUsed)
1266 if (!bitVectBitValue (ic->rMask, B_IDX) && !bitVectBitValue(ic->rMask, C_IDX))
1270 else if (IS_Z80 && !bitVectBitValue (ic->rMask, D_IDX) && !bitVectBitValue(ic->rMask, E_IDX))
1288 fetchPairLong (PAIR_ID pairId, asmop * aop, iCode *ic, int offset)
1290 /* if this is remateriazable */
1291 if (isLitWord (aop)) {
1292 fetchLitPair (pairId, aop, offset);
1296 if (getPairId (aop) == pairId)
1300 /* we need to get it byte by byte */
1301 else if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1302 aopGet (aop, offset, FALSE);
1303 switch (aop->size - offset) {
1305 emit2 ("ld l,!*hl");
1306 emit2 ("ld h,!immedbyte", 0);
1309 // PENDING: Requires that you are only fetching two bytes.
1312 emit2 ("ld h,!*hl");
1316 wassertl (0, "Attempted to fetch too much data into HL");
1320 else if (IS_Z80 && aop->type == AOP_IY) {
1321 /* Instead of fetching relative to IY, just grab directly
1322 from the address IY refers to */
1323 char *l = aopGetLitWordLong (aop, offset, FALSE);
1325 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1327 if (aop->size < 2) {
1328 emit2("ld %s,!zero", _pairs[pairId].h);
1331 else if (pairId == PAIR_IY)
1335 emit2 ("push %s", _pairs[getPairId(aop)].name);
1341 PAIR_ID id = makeFreePairId (ic, &isUsed);
1344 /* Can't load into parts, so load into HL then exchange. */
1345 emit2 ("ld %s,%s", _pairs[id].l, aopGet (aop, offset, FALSE));
1346 emit2 ("ld %s,%s", _pairs[id].h, aopGet (aop, offset + 1, FALSE));
1347 emit2 ("push %s", _pairs[id].name);
1355 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1356 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1358 /* PENDING: check? */
1359 if (pairId == PAIR_HL)
1360 spillPair (PAIR_HL);
1365 fetchPair (PAIR_ID pairId, asmop * aop)
1367 fetchPairLong (pairId, aop, NULL, 0);
1371 fetchHL (asmop * aop)
1373 fetchPair (PAIR_HL, aop);
1377 setupPairFromSP (PAIR_ID id, int offset)
1379 wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
1381 if (offset < INT8MIN || offset > INT8MAX)
1383 emit2 ("ld hl,!immedword", offset);
1384 emit2 ("add hl,sp");
1388 emit2 ("!ldahlsp", offset);
1393 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1398 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
1399 fetchLitPair (pairId, aop, 0);
1403 wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
1405 fetchLitPair (pairId, aop, offset);
1406 _G.pairs[pairId].offset = offset;
1410 wassertl (IS_Z80, "Only the Z80 has an extended stack");
1411 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
1414 int offset = aop->aopu.aop_stk + _G.stack.offset;
1416 if (_G.pairs[pairId].last_type == aop->type &&
1417 _G.pairs[pairId].offset == offset)
1423 /* PENDING: Do this better. */
1424 sprintf (buffer, "%d", offset + _G.stack.pushed);
1425 emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
1426 emit2 ("add %s,sp", _pairs[pairId].name);
1427 _G.pairs[pairId].last_type = aop->type;
1428 _G.pairs[pairId].offset = offset;
1435 /* Doesnt include _G.stack.pushed */
1436 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1438 if (aop->aopu.aop_stk > 0)
1440 abso += _G.stack.param_offset;
1442 assert (pairId == PAIR_HL);
1443 /* In some cases we can still inc or dec hl */
1444 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1446 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1450 setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
1452 _G.pairs[pairId].offset = abso;
1457 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
1463 _G.pairs[pairId].last_type = aop->type;
1469 emit2 ("!tlabeldef", key);
1473 /*-----------------------------------------------------------------*/
1474 /* aopGet - for fetching value of the aop */
1475 /*-----------------------------------------------------------------*/
1477 aopGet (asmop * aop, int offset, bool bit16)
1481 /* offset is greater than size then zero */
1482 /* PENDING: this seems a bit screwed in some pointer cases. */
1483 if (offset > (aop->size - 1) &&
1484 aop->type != AOP_LIT)
1486 tsprintf (s, "!zero");
1487 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1490 /* depending on type */
1494 /* PENDING: re-target */
1496 tsprintf (s, "!immedwords", aop->aopu.aop_immd);
1501 tsprintf (s, "!bankimmeds", aop->aopu.aop_immd);
1504 tsprintf (s, "!msbimmeds", aop->aopu.aop_immd);
1507 tsprintf (s, "!lsbimmeds", aop->aopu.aop_immd);
1510 wassertl (0, "Fetching from beyond the limits of an immediate value.");
1513 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1517 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1520 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1524 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1527 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1530 return aop->aopu.aop_reg[offset]->name;
1534 setupPair (PAIR_HL, aop, offset);
1535 tsprintf (s, "!*hl");
1537 return traceAlloc(&_G.trace.aops, Safe_strdup (s));
1541 setupPair (PAIR_IY, aop, offset);
1542 tsprintf (s, "!*iyx", offset);
1544 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1548 setupPair (PAIR_IY, aop, offset);
1549 tsprintf (s, "!*iyx", offset, offset);
1551 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1556 setupPair (PAIR_HL, aop, offset);
1557 tsprintf (s, "!*hl");
1561 if (aop->aopu.aop_stk >= 0)
1562 offset += _G.stack.param_offset;
1563 tsprintf (s, "!*ixx", aop->aopu.aop_stk + offset);
1566 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1569 wassertl (0, "Tried to fetch from a bit variable");
1578 tsprintf(s, "!zero");
1579 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1583 wassert (offset < 2);
1584 return aop->aopu.aop_str[offset];
1587 return aopLiteral (aop->aopu.aop_lit, offset);
1591 unsigned long v = aop->aopu.aop_simplelit;
1594 tsprintf (s, "!immedbyte", (unsigned int) v & 0xff);
1596 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1600 return aop->aopu.aop_str[offset];
1603 setupPair (aop->aopu.aop_pairId, aop, offset);
1604 sprintf (s, "(%s)", _pairs[aop->aopu.aop_pairId].name);
1606 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1611 wassertl (0, "aopget got unsupported aop->type");
1616 isRegString (const char *s)
1618 if (!strcmp (s, "b") ||
1630 isConstant (const char *s)
1632 /* This is a bit of a hack... */
1633 return (*s == '#' || *s == '$');
1637 canAssignToPtr (const char *s)
1639 if (isRegString (s))
1646 /*-----------------------------------------------------------------*/
1647 /* aopPut - puts a string for a aop */
1648 /*-----------------------------------------------------------------*/
1650 aopPut (asmop * aop, const char *s, int offset)
1654 if (aop->size && offset > (aop->size - 1))
1656 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1657 "aopPut got offset > aop->size");
1662 tsprintf(buffer2, s);
1665 /* will assign value to value */
1666 /* depending on where it is ofcourse */
1672 if (strcmp (s, "a"))
1673 emit2 ("ld a,%s", s);
1674 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1679 if (strcmp (s, "a"))
1680 emit2 ("ld a,%s", s);
1681 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1685 if (!strcmp (s, "!*hl"))
1686 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1689 aop->aopu.aop_reg[offset]->name, s);
1694 if (!canAssignToPtr (s))
1696 emit2 ("ld a,%s", s);
1697 setupPair (PAIR_IY, aop, offset);
1698 emit2 ("ld !*iyx,a", offset);
1702 setupPair (PAIR_IY, aop, offset);
1703 emit2 ("ld !*iyx,%s", offset, s);
1709 /* PENDING: for re-target */
1710 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1712 emit2 ("ld a,!*hl");
1715 setupPair (PAIR_HL, aop, offset);
1717 emit2 ("ld !*hl,%s", s);
1722 if (!canAssignToPtr (s))
1724 emit2 ("ld a,%s", s);
1725 setupPair (PAIR_IY, aop, offset);
1726 emit2 ("ld !*iyx,a", offset);
1730 setupPair (PAIR_IY, aop, offset);
1731 emit2 ("ld !*iyx,%s", offset, s);
1738 /* PENDING: re-target */
1739 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1741 emit2 ("ld a,!*hl");
1744 setupPair (PAIR_HL, aop, offset);
1745 if (!canAssignToPtr (s))
1747 emit2 ("ld a,%s", s);
1748 emit2 ("ld !*hl,a");
1751 emit2 ("ld !*hl,%s", s);
1755 if (aop->aopu.aop_stk >= 0)
1756 offset += _G.stack.param_offset;
1757 if (!canAssignToPtr (s))
1759 emit2 ("ld a,%s", s);
1760 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
1764 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
1770 /* if bit variable */
1771 if (!aop->aopu.aop_dir)
1773 emit2 ("ld a,!zero");
1778 /* In bit space but not in C - cant happen */
1779 wassertl (0, "Tried to write into a bit variable");
1785 if (strcmp (aop->aopu.aop_str[offset], s))
1787 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1793 if (!offset && (strcmp (s, "acc") == 0))
1797 wassertl (0, "Tried to access past the end of A");
1801 if (strcmp (aop->aopu.aop_str[offset], s))
1802 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1807 wassert (offset < 2);
1808 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1812 setupPair (aop->aopu.aop_pairId, aop, offset);
1813 emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
1817 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1818 "aopPut got unsupported aop->type");
1823 #define AOP(op) op->aop
1824 #define AOP_TYPE(op) AOP(op)->type
1825 #define AOP_SIZE(op) AOP(op)->size
1826 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
1829 commitPair (asmop * aop, PAIR_ID id)
1831 /* PENDING: Verify this. */
1832 if (id == PAIR_HL && requiresHL (aop) && IS_GB)
1836 aopPut (aop, "a", 0);
1837 aopPut (aop, "d", 1);
1842 if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
1844 char *l = aopGetLitWordLong (aop, 0, FALSE);
1847 emit2 ("ld (%s),%s", l, _pairs[id].name);
1851 aopPut (aop, _pairs[id].l, 0);
1852 aopPut (aop, _pairs[id].h, 1);
1857 /*-----------------------------------------------------------------*/
1858 /* getDataSize - get the operand data size */
1859 /*-----------------------------------------------------------------*/
1861 getDataSize (operand * op)
1864 size = AOP_SIZE (op);
1868 wassertl (0, "Somehow got a three byte data pointer");
1873 /*-----------------------------------------------------------------*/
1874 /* movLeft2Result - move byte from left to result */
1875 /*-----------------------------------------------------------------*/
1877 movLeft2Result (operand * left, int offl,
1878 operand * result, int offr, int sign)
1882 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
1884 l = aopGet (AOP (left), offl, FALSE);
1888 aopPut (AOP (result), l, offr);
1892 if (getDataSize (left) == offl + 1)
1894 emit2 ("ld a,%s", l);
1895 aopPut (AOP (result), "a", offr);
1902 movLeft2ResultLong (operand * left, int offl,
1903 operand * result, int offr, int sign,
1908 movLeft2Result (left, offl, result, offr, sign);
1912 wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
1913 wassertl (size == 2, "Only implemented for two bytes or one");
1915 if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
1917 emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
1918 emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
1920 spillPair (PAIR_HL);
1922 else if ( getPairId ( AOP (result)) == PAIR_IY)
1924 PAIR_ID id = getPairId (AOP (left));
1925 if (id != PAIR_INVALID)
1927 emit2("push %s", _pairs[id].name);
1938 movLeft2Result (left, offl, result, offr, sign);
1939 movLeft2Result (left, offl+1, result, offr+1, sign);
1944 /** Put Acc into a register set
1947 outAcc (operand * result)
1950 size = getDataSize (result);
1953 aopPut (AOP (result), "a", 0);
1956 /* unsigned or positive */
1959 aopPut (AOP (result), "!zero", offset++);
1964 /** Take the value in carry and put it into a register
1967 outBitCLong (operand * result, bool swap_sense)
1969 /* if the result is bit */
1970 if (AOP_TYPE (result) == AOP_CRY)
1972 wassertl (0, "Tried to write carry to a bit");
1976 emit2 ("ld a,!zero");
1979 emit2 ("xor a,!immedbyte", 1);
1985 outBitC (operand * result)
1987 outBitCLong (result, FALSE);
1990 /*-----------------------------------------------------------------*/
1991 /* toBoolean - emit code for orl a,operator(sizeop) */
1992 /*-----------------------------------------------------------------*/
1994 _toBoolean (operand * oper)
1996 int size = AOP_SIZE (oper);
2000 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
2003 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
2007 if (AOP (oper)->type != AOP_ACC)
2010 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
2015 /*-----------------------------------------------------------------*/
2016 /* genNotFloat - generates not for float operations */
2017 /*-----------------------------------------------------------------*/
2019 genNotFloat (operand * op, operand * res)
2024 emitDebug ("; genNotFloat");
2026 /* we will put 127 in the first byte of
2028 aopPut (AOP (res), "!immedbyte", 0x7F);
2029 size = AOP_SIZE (op) - 1;
2032 _moveA (aopGet (op->aop, offset++, FALSE));
2036 emit2 ("or a,%s", aopGet (op->aop, offset++, FALSE));
2039 tlbl = newiTempLabel (NULL);
2040 aopPut (res->aop, "!one", 1);
2041 emit2 ("!shortjp z !tlabel", tlbl->key + 100);
2042 aopPut (res->aop, "!zero", 1);
2044 emitLabel(tlbl->key + 100);
2046 size = res->aop->size - 2;
2048 /* put zeros in the rest */
2050 aopPut (res->aop, "!zero", offset++);
2053 /*-----------------------------------------------------------------*/
2054 /* genNot - generate code for ! operation */
2055 /*-----------------------------------------------------------------*/
2059 sym_link *optype = operandType (IC_LEFT (ic));
2061 /* assign asmOps to operand & result */
2062 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
2063 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2065 /* if in bit space then a special case */
2066 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2068 wassertl (0, "Tried to negate a bit");
2071 /* if type float then do float */
2072 if (IS_FLOAT (optype))
2074 genNotFloat (IC_LEFT (ic), IC_RESULT (ic));
2078 _toBoolean (IC_LEFT (ic));
2083 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
2084 emit2 ("sub a,!one");
2085 outBitC (IC_RESULT (ic));
2088 /* release the aops */
2089 freeAsmop (IC_LEFT (ic), NULL, ic);
2090 freeAsmop (IC_RESULT (ic), NULL, ic);
2093 /*-----------------------------------------------------------------*/
2094 /* genCpl - generate code for complement */
2095 /*-----------------------------------------------------------------*/
2103 /* assign asmOps to operand & result */
2104 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2105 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2107 /* if both are in bit space then
2109 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2110 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2112 wassertl (0, "Left and the result are in bit space");
2115 size = AOP_SIZE (IC_RESULT (ic));
2118 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2121 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2124 /* release the aops */
2125 freeAsmop (IC_LEFT (ic), NULL, ic);
2126 freeAsmop (IC_RESULT (ic), NULL, ic);
2130 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
2137 store de into result
2142 store de into result
2144 const char *first = isAdd ? "add" : "sub";
2145 const char *later = isAdd ? "adc" : "sbc";
2147 wassertl (IS_GB, "Code is only relevent to the gbz80");
2148 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
2150 fetchPair (PAIR_DE, left);
2153 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
2156 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2159 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2160 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2162 fetchPairLong (PAIR_DE, left, NULL, MSB24);
2163 aopGet (right, MSB24, FALSE);
2167 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2170 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2172 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2173 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2177 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2179 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2182 /*-----------------------------------------------------------------*/
2183 /* genUminusFloat - unary minus for floating points */
2184 /*-----------------------------------------------------------------*/
2186 genUminusFloat (operand * op, operand * result)
2188 int size, offset = 0;
2190 emitDebug("; genUminusFloat");
2192 /* for this we just need to flip the
2193 first it then copy the rest in place */
2194 size = AOP_SIZE (op) - 1;
2196 _moveA(aopGet (AOP (op), MSB32, FALSE));
2198 emit2("xor a,!immedbyte", 0x80);
2199 aopPut (AOP (result), "a", MSB32);
2203 aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2208 /*-----------------------------------------------------------------*/
2209 /* genUminus - unary minus code generation */
2210 /*-----------------------------------------------------------------*/
2212 genUminus (iCode * ic)
2215 sym_link *optype, *rtype;
2218 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2219 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2221 /* if both in bit space then special
2223 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2224 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2226 wassertl (0, "Left and right are in bit space");
2230 optype = operandType (IC_LEFT (ic));
2231 rtype = operandType (IC_RESULT (ic));
2233 /* if float then do float stuff */
2234 if (IS_FLOAT (optype))
2236 genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2240 /* otherwise subtract from zero */
2241 size = AOP_SIZE (IC_LEFT (ic));
2243 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2245 /* Create a new asmop with value zero */
2246 asmop *azero = newAsmop (AOP_SIMPLELIT);
2247 azero->aopu.aop_simplelit = 0;
2249 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2257 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2258 emit2 ("ld a,!zero");
2259 emit2 ("sbc a,%s", l);
2260 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2263 /* if any remaining bytes in the result */
2264 /* we just need to propagate the sign */
2265 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2270 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2274 /* release the aops */
2275 freeAsmop (IC_LEFT (ic), NULL, ic);
2276 freeAsmop (IC_RESULT (ic), NULL, ic);
2279 /*-----------------------------------------------------------------*/
2280 /* assignResultValue - */
2281 /*-----------------------------------------------------------------*/
2283 assignResultValue (operand * oper)
2285 int size = AOP_SIZE (oper);
2288 wassertl (size <= 4, "Got a result that is bigger than four bytes");
2289 topInA = requiresHL (AOP (oper));
2291 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2293 /* We do it the hard way here. */
2295 aopPut (AOP (oper), _fReturn[0], 0);
2296 aopPut (AOP (oper), _fReturn[1], 1);
2298 aopPut (AOP (oper), _fReturn[0], 2);
2299 aopPut (AOP (oper), _fReturn[1], 3);
2305 aopPut (AOP (oper), _fReturn[size], size);
2310 /** Simple restore that doesn't take into account what is used in the
2314 _restoreRegsAfterCall(void)
2316 if (_G.stack.pushedDE)
2319 _G.stack.pushedDE = FALSE;
2321 if (_G.stack.pushedBC)
2324 _G.stack.pushedBC = FALSE;
2326 _G.saves.saved = FALSE;
2330 _saveRegsForCall(iCode *ic, int sendSetSize)
2333 o Stack parameters are pushed before this function enters
2334 o DE and BC may be used in this function.
2335 o HL and DE may be used to return the result.
2336 o HL and DE may be used to send variables.
2337 o DE and BC may be used to store the result value.
2338 o HL may be used in computing the sent value of DE
2339 o The iPushes for other parameters occur before any addSets
2341 Logic: (to be run inside the first iPush or if none, before sending)
2342 o Compute if DE and/or BC are in use over the call
2343 o Compute if DE is used in the send set
2344 o Compute if DE and/or BC are used to hold the result value
2345 o If (DE is used, or in the send set) and is not used in the result, push.
2346 o If BC is used and is not in the result, push
2348 o If DE is used in the send set, fetch
2349 o If HL is used in the send set, fetch
2353 if (_G.saves.saved == FALSE) {
2354 bool deInUse, bcInUse;
2356 bool bcInRet = FALSE, deInRet = FALSE;
2359 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
2361 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2362 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2364 deSending = (sendSetSize > 1);
2366 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2368 if (bcInUse && bcInRet == FALSE) {
2370 _G.stack.pushedBC = TRUE;
2372 if (deInUse && deInRet == FALSE) {
2374 _G.stack.pushedDE = TRUE;
2377 _G.saves.saved = TRUE;
2380 /* Already saved. */
2384 /*-----------------------------------------------------------------*/
2385 /* genIpush - genrate code for pushing this gets a little complex */
2386 /*-----------------------------------------------------------------*/
2388 genIpush (iCode * ic)
2390 int size, offset = 0;
2393 /* if this is not a parm push : ie. it is spill push
2394 and spill push is always done on the local stack */
2397 wassertl(0, "Encountered an unsupported spill push.");
2401 if (_G.saves.saved == FALSE) {
2402 /* Caller saves, and this is the first iPush. */
2403 /* Scan ahead until we find the function that we are pushing parameters to.
2404 Count the number of addSets on the way to figure out what registers
2405 are used in the send set.
2408 iCode *walk = ic->next;
2411 if (walk->op == SEND) {
2414 else if (walk->op == CALL || walk->op == PCALL) {
2423 _saveRegsForCall(walk, nAddSets);
2426 /* Already saved by another iPush. */
2429 /* then do the push */
2430 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2432 size = AOP_SIZE (IC_LEFT (ic));
2434 if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2436 _G.stack.pushed += 2;
2437 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2443 fetchHL (AOP (IC_LEFT (ic)));
2445 spillPair (PAIR_HL);
2446 _G.stack.pushed += 2;
2451 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
2453 spillPair (PAIR_HL);
2454 _G.stack.pushed += 2;
2455 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
2457 spillPair (PAIR_HL);
2458 _G.stack.pushed += 2;
2464 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2466 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2468 emit2 ("ld a,(%s)", l);
2472 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2473 emit2 ("ld a,%s", l);
2481 freeAsmop (IC_LEFT (ic), NULL, ic);
2484 /*-----------------------------------------------------------------*/
2485 /* genIpop - recover the registers: can happen only for spilling */
2486 /*-----------------------------------------------------------------*/
2488 genIpop (iCode * ic)
2493 /* if the temp was not pushed then */
2494 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2497 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2498 size = AOP_SIZE (IC_LEFT (ic));
2499 offset = (size - 1);
2500 if (isPair (AOP (IC_LEFT (ic))))
2502 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2510 spillPair (PAIR_HL);
2511 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2515 freeAsmop (IC_LEFT (ic), NULL, ic);
2518 /* This is quite unfortunate */
2520 setArea (int inHome)
2523 static int lastArea = 0;
2525 if (_G.in_home != inHome) {
2527 const char *sz = port->mem.code_name;
2528 port->mem.code_name = "HOME";
2529 emit2("!area", CODE_NAME);
2530 port->mem.code_name = sz;
2533 emit2("!area", CODE_NAME); */
2534 _G.in_home = inHome;
2545 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2549 symbol *sym = OP_SYMBOL (op);
2551 if (sym->isspilt || sym->nRegs == 0)
2554 aopOp (op, ic, FALSE, FALSE);
2557 if (aop->type == AOP_REG)
2560 for (i = 0; i < aop->size; i++)
2562 if (pairId == PAIR_DE)
2564 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2565 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2567 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2570 else if (pairId == PAIR_BC)
2572 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2573 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2575 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2585 freeAsmop (IC_LEFT (ic), NULL, ic);
2589 /** Emit the code for a call statement
2592 emitCall (iCode * ic, bool ispcall)
2594 sym_link *dtype = operandType (IC_LEFT (ic));
2596 /* if caller saves & we have not saved then */
2602 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2604 /* if send set is not empty then assign */
2609 int nSend = elementsInSet(_G.sendSet);
2610 bool swapped = FALSE;
2612 int _z80_sendOrder[] = {
2617 /* Check if the parameters are swapped. If so route through hl instead. */
2618 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2620 sic = setFirstItem(_G.sendSet);
2621 sic = setNextItem(_G.sendSet);
2623 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2624 /* The second send value is loaded from one the one that holds the first
2625 send, i.e. it is overwritten. */
2626 /* Cache the first in HL, and load the second from HL instead. */
2627 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2628 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2634 for (sic = setFirstItem (_G.sendSet); sic;
2635 sic = setNextItem (_G.sendSet))
2638 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2640 size = AOP_SIZE (IC_LEFT (sic));
2641 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2642 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2644 // PENDING: Mild hack
2645 if (swapped == TRUE && send == 1) {
2647 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2650 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2652 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2655 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2659 freeAsmop (IC_LEFT (sic), NULL, sic);
2666 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2668 werror (W_INDIR_BANKED);
2670 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2672 if (isLitWord (AOP (IC_LEFT (ic))))
2674 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2678 symbol *rlbl = newiTempLabel (NULL);
2679 spillPair (PAIR_HL);
2680 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2682 _G.stack.pushed += 2;
2684 fetchHL (AOP (IC_LEFT (ic)));
2686 emit2 ("!tlabeldef", (rlbl->key + 100));
2687 _G.stack.pushed -= 2;
2689 freeAsmop (IC_LEFT (ic), NULL, ic);
2693 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2694 OP_SYMBOL (IC_LEFT (ic))->rname :
2695 OP_SYMBOL (IC_LEFT (ic))->name;
2696 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2698 emit2 ("call banked_call");
2699 emit2 ("!dws", name);
2700 emit2 ("!dw !bankimmeds", name);
2705 emit2 ("call %s", name);
2710 /* Mark the regsiters as restored. */
2711 _G.saves.saved = FALSE;
2713 /* if we need assign a result value */
2714 if ((IS_ITEMP (IC_RESULT (ic)) &&
2715 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2716 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2717 IS_TRUE_SYMOP (IC_RESULT (ic)))
2720 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2722 assignResultValue (IC_RESULT (ic));
2724 freeAsmop (IC_RESULT (ic), NULL, ic);
2727 /* adjust the stack for parameters if required */
2730 int i = ic->parmBytes;
2732 _G.stack.pushed -= i;
2735 emit2 ("!ldaspsp", i);
2742 emit2 ("ld iy,!immedword", i);
2743 emit2 ("add iy,sp");
2763 if (_G.stack.pushedDE)
2765 bool dInRet = bitVectBitValue(ic->rUsed, D_IDX);
2766 bool eInRet = bitVectBitValue(ic->rUsed, E_IDX);
2768 if (dInRet && eInRet)
2770 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
2774 /* Only restore E */
2781 /* Only restore D */
2789 _G.stack.pushedDE = FALSE;
2792 if (_G.stack.pushedBC)
2794 bool bInRet = bitVectBitValue(ic->rUsed, B_IDX);
2795 bool cInRet = bitVectBitValue(ic->rUsed, C_IDX);
2797 if (bInRet && cInRet)
2799 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
2803 /* Only restore C */
2810 /* Only restore B */
2818 _G.stack.pushedBC = FALSE;
2822 /*-----------------------------------------------------------------*/
2823 /* genCall - generates a call statement */
2824 /*-----------------------------------------------------------------*/
2826 genCall (iCode * ic)
2828 emitCall (ic, FALSE);
2831 /*-----------------------------------------------------------------*/
2832 /* genPcall - generates a call by pointer statement */
2833 /*-----------------------------------------------------------------*/
2835 genPcall (iCode * ic)
2837 emitCall (ic, TRUE);
2840 /*-----------------------------------------------------------------*/
2841 /* resultRemat - result is rematerializable */
2842 /*-----------------------------------------------------------------*/
2844 resultRemat (iCode * ic)
2846 if (SKIP_IC (ic) || ic->op == IFX)
2849 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2851 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2852 if (sym->remat && !POINTER_SET (ic))
2859 extern set *publics;
2861 /*-----------------------------------------------------------------*/
2862 /* genFunction - generated code for function entry */
2863 /*-----------------------------------------------------------------*/
2865 genFunction (iCode * ic)
2867 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2870 bool bcInUse = FALSE;
2871 bool deInUse = FALSE;
2873 setArea (IFFUNC_NONBANKED (sym->type));
2875 /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
2878 _G.receiveOffset = 0;
2880 /* Record the last function name for debugging. */
2881 _G.lastFunctionName = sym->rname;
2883 /* Create the function header */
2884 emit2 ("!functionheader", sym->name);
2885 sprintf (buffer, "%s_start", sym->rname);
2886 emit2 ("!labeldef", buffer);
2887 emit2 ("!functionlabeldef", sym->rname);
2889 if (options.profile)
2891 emit2 ("!profileenter");
2894 ftype = operandType (IC_LEFT (ic));
2896 /* if critical function then turn interrupts off */
2897 if (IFFUNC_ISCRITICAL (ftype))
2900 /* if this is an interrupt service routine then save all potentially used registers. */
2901 if (IFFUNC_ISISR (sym->type))
2906 /* PENDING: callee-save etc */
2908 _G.stack.param_offset = 0;
2910 if (z80_opts.calleeSavesBC)
2915 /* Detect which registers are used. */
2916 if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
2919 for (i = 0; i < sym->regsUsed->size; i++)
2921 if (bitVectBitValue (sym->regsUsed, i))
2935 /* Other systems use DE as a temporary. */
2946 _G.stack.param_offset += 2;
2949 _G.calleeSaves.pushedBC = bcInUse;
2954 _G.stack.param_offset += 2;
2957 _G.calleeSaves.pushedDE = deInUse;
2959 /* adjust the stack for the function */
2960 _G.stack.last = sym->stack;
2962 if (sym->stack && IS_GB && sym->stack > -INT8MIN)
2963 emit2 ("!enterxl", sym->stack);
2964 else if (sym->stack)
2965 emit2 ("!enterx", sym->stack);
2968 _G.stack.offset = sym->stack;
2971 /*-----------------------------------------------------------------*/
2972 /* genEndFunction - generates epilogue for functions */
2973 /*-----------------------------------------------------------------*/
2975 genEndFunction (iCode * ic)
2977 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2979 if (IFFUNC_ISISR (sym->type))
2981 wassertl (0, "Tried to close an interrupt support function");
2985 if (IFFUNC_ISCRITICAL (sym->type))
2988 /* PENDING: calleeSave */
2990 if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
2992 emit2 ("!leavexl", _G.stack.offset);
2994 else if (_G.stack.offset)
2996 emit2 ("!leavex", _G.stack.offset);
3003 if (_G.calleeSaves.pushedDE)
3006 _G.calleeSaves.pushedDE = FALSE;
3009 if (_G.calleeSaves.pushedBC)
3012 _G.calleeSaves.pushedBC = FALSE;
3015 if (options.profile)
3017 emit2 ("!profileexit");
3021 /* Both baned and non-banked just ret */
3024 sprintf (buffer, "%s_end", sym->rname);
3025 emit2 ("!labeldef", buffer);
3027 _G.flushStatics = 1;
3028 _G.stack.pushed = 0;
3029 _G.stack.offset = 0;
3032 /*-----------------------------------------------------------------*/
3033 /* genRet - generate code for return statement */
3034 /*-----------------------------------------------------------------*/
3039 /* Errk. This is a hack until I can figure out how
3040 to cause dehl to spill on a call */
3041 int size, offset = 0;
3043 /* if we have no return value then
3044 just generate the "ret" */
3048 /* we have something to return then
3049 move the return value into place */
3050 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3051 size = AOP_SIZE (IC_LEFT (ic));
3053 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3057 emit2 ("ld de,%s", l);
3061 emit2 ("ld hl,%s", l);
3066 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3068 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3069 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3075 l = aopGet (AOP (IC_LEFT (ic)), offset,
3077 if (strcmp (_fReturn[offset], l))
3078 emit2 ("ld %s,%s", _fReturn[offset++], l);
3082 freeAsmop (IC_LEFT (ic), NULL, ic);
3085 /* generate a jump to the return label
3086 if the next is not the return statement */
3087 if (!(ic->next && ic->next->op == LABEL &&
3088 IC_LABEL (ic->next) == returnLabel))
3090 emit2 ("jp !tlabel", returnLabel->key + 100);
3093 /*-----------------------------------------------------------------*/
3094 /* genLabel - generates a label */
3095 /*-----------------------------------------------------------------*/
3097 genLabel (iCode * ic)
3099 /* special case never generate */
3100 if (IC_LABEL (ic) == entryLabel)
3103 emitLabel (IC_LABEL (ic)->key + 100);
3106 /*-----------------------------------------------------------------*/
3107 /* genGoto - generates a ljmp */
3108 /*-----------------------------------------------------------------*/
3110 genGoto (iCode * ic)
3112 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3115 /*-----------------------------------------------------------------*/
3116 /* genPlusIncr :- does addition with increment if possible */
3117 /*-----------------------------------------------------------------*/
3119 genPlusIncr (iCode * ic)
3121 unsigned int icount;
3122 unsigned int size = getDataSize (IC_RESULT (ic));
3123 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3125 /* will try to generate an increment */
3126 /* if the right side is not a literal
3128 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3131 emitDebug ("; genPlusIncr");
3133 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3135 /* If result is a pair */
3136 if (resultId != PAIR_INVALID)
3138 if (isLitWord (AOP (IC_LEFT (ic))))
3140 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3143 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3145 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3147 PAIR_ID freep = getFreePairId (ic);
3148 if (freep != PAIR_INVALID)
3150 fetchPair (freep, AOP (IC_RIGHT (ic)));
3151 emit2 ("add hl,%s", _pairs[freep].name);
3157 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3158 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3165 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3169 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3173 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3178 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3180 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3181 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3185 /* if the literal value of the right hand side
3186 is greater than 4 then it is not worth it */
3190 /* if increment 16 bits in register */
3191 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3197 symbol *tlbl = NULL;
3198 tlbl = newiTempLabel (NULL);
3201 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3204 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3207 emitLabel (tlbl->key + 100);
3211 /* if the sizes are greater than 1 then we cannot */
3212 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3213 AOP_SIZE (IC_LEFT (ic)) > 1)
3216 /* If the result is in a register then we can load then increment.
3218 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3220 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3223 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3228 /* we can if the aops of the left & result match or
3229 if they are in registers and the registers are the
3231 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3235 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3243 /*-----------------------------------------------------------------*/
3244 /* outBitAcc - output a bit in acc */
3245 /*-----------------------------------------------------------------*/
3247 outBitAcc (operand * result)
3249 symbol *tlbl = newiTempLabel (NULL);
3250 /* if the result is a bit */
3251 if (AOP_TYPE (result) == AOP_CRY)
3253 wassertl (0, "Tried to write A into a bit");
3257 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3258 emit2 ("ld a,!one");
3259 emitLabel (tlbl->key + 100);
3265 couldDestroyCarry (asmop *aop)
3269 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3278 shiftIntoPair (int idx, asmop *aop)
3280 PAIR_ID id = PAIR_INVALID;
3282 wassertl (IS_Z80, "Only implemented for the Z80");
3283 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3295 wassertl (0, "Internal error - hit default case");
3298 emitDebug ("; Shift into pair idx %u", idx);
3302 setupPair (PAIR_HL, aop, 0);
3306 setupPair (PAIR_IY, aop, 0);
3308 emit2 ("pop %s", _pairs[id].name);
3311 aop->type = AOP_PAIRPTR;
3312 aop->aopu.aop_pairId = id;
3313 _G.pairs[id].offset = 0;
3314 _G.pairs[id].last_type = aop->type;
3318 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
3320 wassert (left && right);
3324 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3326 shiftIntoPair (0, right);
3327 shiftIntoPair (1, result);
3329 else if (couldDestroyCarry (right))
3331 shiftIntoPair (0, right);
3333 else if (couldDestroyCarry (result))
3335 shiftIntoPair (0, result);
3344 /*-----------------------------------------------------------------*/
3345 /* genPlus - generates code for addition */
3346 /*-----------------------------------------------------------------*/
3348 genPlus (iCode * ic)
3350 int size, offset = 0;
3352 /* special cases :- */
3354 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3355 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3356 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3358 /* Swap the left and right operands if:
3360 if literal, literal on the right or
3361 if left requires ACC or right is already
3364 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3365 (AOP_NEEDSACC (IC_LEFT (ic))) ||
3366 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3368 operand *t = IC_RIGHT (ic);
3369 IC_RIGHT (ic) = IC_LEFT (ic);
3373 /* if both left & right are in bit
3375 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3376 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3379 wassertl (0, "Tried to add two bits");
3382 /* if left in bit space & right literal */
3383 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3384 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3386 /* Can happen I guess */
3387 wassertl (0, "Tried to add a bit to a literal");
3390 /* if I can do an increment instead
3391 of add then GOOD for ME */
3392 if (genPlusIncr (ic) == TRUE)
3395 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3397 size = getDataSize (IC_RESULT (ic));
3399 /* Special case when left and right are constant */
3400 if (isPair (AOP (IC_RESULT (ic))))
3403 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3404 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3406 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3412 sprintf (buffer, "#(%s + %s)", left, right);
3413 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3418 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3420 /* Fetch into HL then do the add */
3421 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3422 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3424 spillPair (PAIR_HL);
3426 if (left == PAIR_HL && right != PAIR_INVALID)
3428 emit2 ("add hl,%s", _pairs[right].name);
3431 else if (right == PAIR_HL && left != PAIR_INVALID)
3433 emit2 ("add hl,%s", _pairs[left].name);
3436 else if (right != PAIR_INVALID && right != PAIR_HL)
3438 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3439 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3442 else if (left != PAIR_INVALID && left != PAIR_HL)
3444 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3445 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3454 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3456 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3457 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3459 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3464 ld hl,sp+n trashes C so we cant afford to do it during an
3465 add with stack based varibles. Worst case is:
3478 So you cant afford to load up hl if either left, right, or result
3479 is on the stack (*sigh*) The alt is:
3487 Combinations in here are:
3488 * If left or right are in bc then the loss is small - trap later
3489 * If the result is in bc then the loss is also small
3493 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3494 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3495 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3497 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3498 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3499 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3500 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3502 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3504 /* Swap left and right */
3505 operand *t = IC_RIGHT (ic);
3506 IC_RIGHT (ic) = IC_LEFT (ic);
3509 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3511 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3512 emit2 ("add hl,bc");
3516 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3517 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3518 emit2 ("add hl,de");
3520 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3526 /* Be paranoid on the GB with 4 byte variables due to how C
3527 can be trashed by lda hl,n(sp).
3529 _gbz80_emitAddSubLong (ic, TRUE);
3534 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3538 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3540 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3543 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3546 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3550 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3553 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3556 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3558 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3562 freeAsmop (IC_LEFT (ic), NULL, ic);
3563 freeAsmop (IC_RIGHT (ic), NULL, ic);
3564 freeAsmop (IC_RESULT (ic), NULL, ic);
3568 /*-----------------------------------------------------------------*/
3569 /* genMinusDec :- does subtraction with deccrement if possible */
3570 /*-----------------------------------------------------------------*/
3572 genMinusDec (iCode * ic)
3574 unsigned int icount;
3575 unsigned int size = getDataSize (IC_RESULT (ic));
3577 /* will try to generate an increment */
3578 /* if the right side is not a literal we cannot */
3579 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3582 /* if the literal value of the right hand side
3583 is greater than 4 then it is not worth it */
3584 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3587 size = getDataSize (IC_RESULT (ic));
3589 /* if decrement 16 bits in register */
3590 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3591 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3594 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3598 /* If result is a pair */
3599 if (isPair (AOP (IC_RESULT (ic))))
3601 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3603 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3607 /* if increment 16 bits in register */
3608 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3612 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3615 emit2 ("dec %s", _getTempPairName());
3618 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3624 /* if the sizes are greater than 1 then we cannot */
3625 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3626 AOP_SIZE (IC_LEFT (ic)) > 1)
3629 /* we can if the aops of the left & result match or if they are in
3630 registers and the registers are the same */
3631 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3634 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3641 /*-----------------------------------------------------------------*/
3642 /* genMinus - generates code for subtraction */
3643 /*-----------------------------------------------------------------*/
3645 genMinus (iCode * ic)
3647 int size, offset = 0;
3648 unsigned long lit = 0L;
3650 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3651 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3652 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3654 /* special cases :- */
3655 /* if both left & right are in bit space */
3656 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3657 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3659 wassertl (0, "Tried to subtract two bits");
3663 /* if I can do an decrement instead of subtract then GOOD for ME */
3664 if (genMinusDec (ic) == TRUE)
3667 size = getDataSize (IC_RESULT (ic));
3669 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3674 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3678 /* Same logic as genPlus */
3681 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3682 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3683 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3685 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3686 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3687 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3688 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3690 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3691 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3693 if (left == PAIR_INVALID && right == PAIR_INVALID)
3698 else if (right == PAIR_INVALID)
3700 else if (left == PAIR_INVALID)
3703 fetchPair (left, AOP (IC_LEFT (ic)));
3704 /* Order is important. Right may be HL */
3705 fetchPair (right, AOP (IC_RIGHT (ic)));
3707 emit2 ("ld a,%s", _pairs[left].l);
3708 emit2 ("sub a,%s", _pairs[right].l);
3710 emit2 ("ld a,%s", _pairs[left].h);
3711 emit2 ("sbc a,%s", _pairs[right].h);
3713 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
3715 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3717 aopPut (AOP (IC_RESULT (ic)), "e", 0);
3723 /* Be paranoid on the GB with 4 byte variables due to how C
3724 can be trashed by lda hl,n(sp).
3726 _gbz80_emitAddSubLong (ic, FALSE);
3731 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3733 /* if literal, add a,#-lit, else normal subb */
3736 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3737 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3741 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3744 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3748 /* first add without previous c */
3750 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
3752 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3754 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3757 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3758 AOP_SIZE (IC_LEFT (ic)) == 3 &&
3759 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3761 wassertl (0, "Tried to subtract on a long pointer");
3765 freeAsmop (IC_LEFT (ic), NULL, ic);
3766 freeAsmop (IC_RIGHT (ic), NULL, ic);
3767 freeAsmop (IC_RESULT (ic), NULL, ic);
3770 /*-----------------------------------------------------------------*/
3771 /* genMult - generates code for multiplication */
3772 /*-----------------------------------------------------------------*/
3774 genMult (iCode * ic)
3778 /* If true then the final operation should be a subtract */
3779 bool active = FALSE;
3781 /* Shouldn't occur - all done through function calls */
3782 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3783 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3784 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3786 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
3787 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
3788 AOP_SIZE (IC_RESULT (ic)) > 2)
3790 wassertl (0, "Multiplication is handled through support function calls");
3793 /* Swap left and right such that right is a literal */
3794 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
3796 operand *t = IC_RIGHT (ic);
3797 IC_RIGHT (ic) = IC_LEFT (ic);
3801 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
3803 val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
3804 // wassertl (val > 0, "Multiply must be positive");
3805 wassertl (val != 1, "Can't multiply by 1");
3807 if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
3809 _G.stack.pushedDE = TRUE;
3812 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
3814 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
3822 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3827 /* Fully unroled version of mul.s. Not the most efficient.
3829 for (count = 0; count < 16; count++)
3831 if (count != 0 && active)
3833 emit2 ("add hl,hl");
3837 if (active == FALSE)
3844 emit2 ("add hl,de");
3853 if (IS_Z80 && _G.stack.pushedDE)
3856 _G.stack.pushedDE = FALSE;
3859 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3861 freeAsmop (IC_LEFT (ic), NULL, ic);
3862 freeAsmop (IC_RIGHT (ic), NULL, ic);
3863 freeAsmop (IC_RESULT (ic), NULL, ic);
3866 /*-----------------------------------------------------------------*/
3867 /* genDiv - generates code for division */
3868 /*-----------------------------------------------------------------*/
3872 /* Shouldn't occur - all done through function calls */
3873 wassertl (0, "Division is handled through support function calls");
3876 /*-----------------------------------------------------------------*/
3877 /* genMod - generates code for division */
3878 /*-----------------------------------------------------------------*/
3882 /* Shouldn't occur - all done through function calls */
3886 /*-----------------------------------------------------------------*/
3887 /* genIfxJump :- will create a jump depending on the ifx */
3888 /*-----------------------------------------------------------------*/
3890 genIfxJump (iCode * ic, char *jval)
3895 /* if true label then we jump if condition
3899 jlbl = IC_TRUE (ic);
3900 if (!strcmp (jval, "a"))
3904 else if (!strcmp (jval, "c"))
3908 else if (!strcmp (jval, "nc"))
3912 else if (!strcmp (jval, "m"))
3916 else if (!strcmp (jval, "p"))
3922 /* The buffer contains the bit on A that we should test */
3928 /* false label is present */
3929 jlbl = IC_FALSE (ic);
3930 if (!strcmp (jval, "a"))
3934 else if (!strcmp (jval, "c"))
3938 else if (!strcmp (jval, "nc"))
3942 else if (!strcmp (jval, "m"))
3946 else if (!strcmp (jval, "p"))
3952 /* The buffer contains the bit on A that we should test */
3956 /* Z80 can do a conditional long jump */
3957 if (!strcmp (jval, "a"))
3961 else if (!strcmp (jval, "c"))
3964 else if (!strcmp (jval, "nc"))
3967 else if (!strcmp (jval, "m"))
3970 else if (!strcmp (jval, "p"))
3975 emit2 ("bit %s,a", jval);
3977 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
3979 /* mark the icode as generated */
3985 _getPairIdName (PAIR_ID id)
3987 return _pairs[id].name;
3992 /* if unsigned char cmp with lit, just compare */
3994 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
3996 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3999 emit2 ("xor a,!immedbyte", 0x80);
4000 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4003 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4005 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4007 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4008 // Pull left into DE and right into HL
4009 aopGet (AOP(left), LSB, FALSE);
4012 aopGet (AOP(right), LSB, FALSE);
4016 if (size == 0 && sign)
4018 // Highest byte when signed needs the bits flipped
4021 emit2 ("ld a,(de)");
4022 emit2 ("xor !immedbyte", 0x80);
4024 emit2 ("ld a,(hl)");
4025 emit2 ("xor !immedbyte", 0x80);
4029 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4033 emit2 ("ld a,(de)");
4034 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4044 spillPair (PAIR_HL);
4046 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4048 setupPair (PAIR_HL, AOP (left), 0);
4049 aopGet (AOP(right), LSB, FALSE);
4053 if (size == 0 && sign)
4055 // Highest byte when signed needs the bits flipped
4058 emit2 ("ld a,(hl)");
4059 emit2 ("xor !immedbyte", 0x80);
4061 emit2 ("ld a,%d(iy)", offset);
4062 emit2 ("xor !immedbyte", 0x80);
4066 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4070 emit2 ("ld a,(hl)");
4071 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4080 spillPair (PAIR_HL);
4081 spillPair (PAIR_IY);
4085 if (AOP_TYPE (right) == AOP_LIT)
4087 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4088 /* optimize if(x < 0) or if(x >= 0) */
4093 /* No sign so it's always false */
4098 /* Just load in the top most bit */
4099 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4100 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4102 genIfxJump (ifx, "7");
4114 /* First setup h and l contaning the top most bytes XORed */
4115 bool fDidXor = FALSE;
4116 if (AOP_TYPE (left) == AOP_LIT)
4118 unsigned long lit = (unsigned long)
4119 floatFromVal (AOP (left)->aopu.aop_lit);
4120 emit2 ("ld %s,!immedbyte", _fTmp[0],
4121 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4125 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4126 emit2 ("xor a,!immedbyte", 0x80);
4127 emit2 ("ld %s,a", _fTmp[0]);
4130 if (AOP_TYPE (right) == AOP_LIT)
4132 unsigned long lit = (unsigned long)
4133 floatFromVal (AOP (right)->aopu.aop_lit);
4134 emit2 ("ld %s,!immedbyte", _fTmp[1],
4135 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4139 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4140 emit2 ("xor a,!immedbyte", 0x80);
4141 emit2 ("ld %s,a", _fTmp[1]);
4147 /* Do a long subtract */
4150 _moveA (aopGet (AOP (left), offset, FALSE));
4152 if (sign && size == 0)
4154 emit2 ("ld a,%s", _fTmp[0]);
4155 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4159 /* Subtract through, propagating the carry */
4160 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4168 /** Generic compare for > or <
4171 genCmp (operand * left, operand * right,
4172 operand * result, iCode * ifx, int sign)
4174 int size, offset = 0;
4175 unsigned long lit = 0L;
4176 bool swap_sense = FALSE;
4178 /* if left & right are bit variables */
4179 if (AOP_TYPE (left) == AOP_CRY &&
4180 AOP_TYPE (right) == AOP_CRY)
4182 /* Cant happen on the Z80 */
4183 wassertl (0, "Tried to compare two bits");
4187 /* Do a long subtract of right from left. */
4188 size = max (AOP_SIZE (left), AOP_SIZE (right));
4190 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4192 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4193 // Pull left into DE and right into HL
4194 aopGet (AOP(left), LSB, FALSE);
4197 aopGet (AOP(right), LSB, FALSE);
4201 emit2 ("ld a,(de)");
4202 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4211 spillPair (PAIR_HL);
4215 if (AOP_TYPE (right) == AOP_LIT)
4217 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4218 /* optimize if(x < 0) or if(x >= 0) */
4223 /* No sign so it's always false */
4228 /* Just load in the top most bit */
4229 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4230 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4232 genIfxJump (ifx, "7");
4243 genIfxJump (ifx, swap_sense ? "c" : "nc");
4254 _moveA (aopGet (AOP (left), offset, FALSE));
4255 /* Subtract through, propagating the carry */
4256 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4262 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4266 /* Shift the sign bit up into carry */
4269 outBitCLong (result, swap_sense);
4273 /* if the result is used in the next
4274 ifx conditional branch then generate
4275 code a little differently */
4283 genIfxJump (ifx, swap_sense ? "nc" : "c");
4287 genIfxJump (ifx, swap_sense ? "p" : "m");
4292 genIfxJump (ifx, swap_sense ? "nc" : "c");
4299 /* Shift the sign bit up into carry */
4302 outBitCLong (result, swap_sense);
4304 /* leave the result in acc */
4308 /*-----------------------------------------------------------------*/
4309 /* genCmpGt :- greater than comparison */
4310 /*-----------------------------------------------------------------*/
4312 genCmpGt (iCode * ic, iCode * ifx)
4314 operand *left, *right, *result;
4315 sym_link *letype, *retype;
4318 left = IC_LEFT (ic);
4319 right = IC_RIGHT (ic);
4320 result = IC_RESULT (ic);
4322 letype = getSpec (operandType (left));
4323 retype = getSpec (operandType (right));
4324 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4325 /* assign the amsops */
4326 aopOp (left, ic, FALSE, FALSE);
4327 aopOp (right, ic, FALSE, FALSE);
4328 aopOp (result, ic, TRUE, FALSE);
4330 genCmp (right, left, result, ifx, sign);
4332 freeAsmop (left, NULL, ic);
4333 freeAsmop (right, NULL, ic);
4334 freeAsmop (result, NULL, ic);
4337 /*-----------------------------------------------------------------*/
4338 /* genCmpLt - less than comparisons */
4339 /*-----------------------------------------------------------------*/
4341 genCmpLt (iCode * ic, iCode * ifx)
4343 operand *left, *right, *result;
4344 sym_link *letype, *retype;
4347 left = IC_LEFT (ic);
4348 right = IC_RIGHT (ic);
4349 result = IC_RESULT (ic);
4351 letype = getSpec (operandType (left));
4352 retype = getSpec (operandType (right));
4353 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4355 /* assign the amsops */
4356 aopOp (left, ic, FALSE, FALSE);
4357 aopOp (right, ic, FALSE, FALSE);
4358 aopOp (result, ic, TRUE, FALSE);
4360 genCmp (left, right, result, ifx, sign);
4362 freeAsmop (left, NULL, ic);
4363 freeAsmop (right, NULL, ic);
4364 freeAsmop (result, NULL, ic);
4367 /*-----------------------------------------------------------------*/
4368 /* gencjneshort - compare and jump if not equal */
4369 /*-----------------------------------------------------------------*/
4371 gencjneshort (operand * left, operand * right, symbol * lbl)
4373 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4375 unsigned long lit = 0L;
4377 /* Swap the left and right if it makes the computation easier */
4378 if (AOP_TYPE (left) == AOP_LIT)
4385 if (AOP_TYPE (right) == AOP_LIT)
4387 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4390 /* if the right side is a literal then anything goes */
4391 if (AOP_TYPE (right) == AOP_LIT &&
4392 AOP_TYPE (left) != AOP_DIR)
4396 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4401 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4408 emit2 ("jp nz,!tlabel", lbl->key + 100);
4414 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4415 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
4418 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
4419 emit2 ("jp nz,!tlabel", lbl->key + 100);
4424 /* if the right side is in a register or in direct space or
4425 if the left is a pointer register & right is not */
4426 else if (AOP_TYPE (right) == AOP_REG ||
4427 AOP_TYPE (right) == AOP_DIR ||
4428 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
4432 _moveA (aopGet (AOP (left), offset, FALSE));
4433 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
4434 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4436 emit2 ("jp nz,!tlabel", lbl->key + 100);
4439 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4440 emit2 ("jp nz,!tlabel", lbl->key + 100);
4447 /* right is a pointer reg need both a & b */
4448 /* PENDING: is this required? */
4451 _moveA (aopGet (AOP (right), offset, FALSE));
4452 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
4453 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
4459 /*-----------------------------------------------------------------*/
4460 /* gencjne - compare and jump if not equal */
4461 /*-----------------------------------------------------------------*/
4463 gencjne (operand * left, operand * right, symbol * lbl)
4465 symbol *tlbl = newiTempLabel (NULL);
4467 gencjneshort (left, right, lbl);
4470 emit2 ("ld a,!one");
4471 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4472 emitLabel (lbl->key + 100);
4474 emitLabel (tlbl->key + 100);
4477 /*-----------------------------------------------------------------*/
4478 /* genCmpEq - generates code for equal to */
4479 /*-----------------------------------------------------------------*/
4481 genCmpEq (iCode * ic, iCode * ifx)
4483 operand *left, *right, *result;
4485 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4486 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4487 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4489 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4491 /* Swap operands if it makes the operation easier. ie if:
4492 1. Left is a literal.
4494 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4496 operand *t = IC_RIGHT (ic);
4497 IC_RIGHT (ic) = IC_LEFT (ic);
4501 if (ifx && !AOP_SIZE (result))
4504 /* if they are both bit variables */
4505 if (AOP_TYPE (left) == AOP_CRY &&
4506 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4508 wassertl (0, "Tried to compare two bits");
4512 tlbl = newiTempLabel (NULL);
4513 gencjneshort (left, right, tlbl);
4516 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4517 emitLabel (tlbl->key + 100);
4521 /* PENDING: do this better */
4522 symbol *lbl = newiTempLabel (NULL);
4523 emit2 ("!shortjp !tlabel", lbl->key + 100);
4524 emitLabel (tlbl->key + 100);
4525 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4526 emitLabel (lbl->key + 100);
4529 /* mark the icode as generated */
4534 /* if they are both bit variables */
4535 if (AOP_TYPE (left) == AOP_CRY &&
4536 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4538 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4544 gencjne (left, right, newiTempLabel (NULL));
4545 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4552 genIfxJump (ifx, "a");
4555 /* if the result is used in an arithmetic operation
4556 then put the result in place */
4557 if (AOP_TYPE (result) != AOP_CRY)
4562 /* leave the result in acc */
4566 freeAsmop (left, NULL, ic);
4567 freeAsmop (right, NULL, ic);
4568 freeAsmop (result, NULL, ic);
4571 /*-----------------------------------------------------------------*/
4572 /* ifxForOp - returns the icode containing the ifx for operand */
4573 /*-----------------------------------------------------------------*/
4575 ifxForOp (operand * op, iCode * ic)
4577 /* if true symbol then needs to be assigned */
4578 if (IS_TRUE_SYMOP (op))
4581 /* if this has register type condition and
4582 the next instruction is ifx with the same operand
4583 and live to of the operand is upto the ifx only then */
4585 ic->next->op == IFX &&
4586 IC_COND (ic->next)->key == op->key &&
4587 OP_SYMBOL (op)->liveTo <= ic->next->seq)
4593 /*-----------------------------------------------------------------*/
4594 /* genAndOp - for && operation */
4595 /*-----------------------------------------------------------------*/
4597 genAndOp (iCode * ic)
4599 operand *left, *right, *result;
4602 /* note here that && operations that are in an if statement are
4603 taken away by backPatchLabels only those used in arthmetic
4604 operations remain */
4605 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4606 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4607 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4609 /* if both are bit variables */
4610 if (AOP_TYPE (left) == AOP_CRY &&
4611 AOP_TYPE (right) == AOP_CRY)
4613 wassertl (0, "Tried to and two bits");
4617 tlbl = newiTempLabel (NULL);
4619 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
4621 emitLabel (tlbl->key + 100);
4625 freeAsmop (left, NULL, ic);
4626 freeAsmop (right, NULL, ic);
4627 freeAsmop (result, NULL, ic);
4630 /*-----------------------------------------------------------------*/
4631 /* genOrOp - for || operation */
4632 /*-----------------------------------------------------------------*/
4634 genOrOp (iCode * ic)
4636 operand *left, *right, *result;
4639 /* note here that || operations that are in an
4640 if statement are taken away by backPatchLabels
4641 only those used in arthmetic operations remain */
4642 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4643 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4644 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4646 /* if both are bit variables */
4647 if (AOP_TYPE (left) == AOP_CRY &&
4648 AOP_TYPE (right) == AOP_CRY)
4650 wassertl (0, "Tried to OR two bits");
4654 tlbl = newiTempLabel (NULL);
4656 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4658 emitLabel (tlbl->key + 100);
4662 freeAsmop (left, NULL, ic);
4663 freeAsmop (right, NULL, ic);
4664 freeAsmop (result, NULL, ic);
4667 /*-----------------------------------------------------------------*/
4668 /* isLiteralBit - test if lit == 2^n */
4669 /*-----------------------------------------------------------------*/
4671 isLiteralBit (unsigned long lit)
4673 unsigned long pw[32] =
4674 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
4675 0x100L, 0x200L, 0x400L, 0x800L,
4676 0x1000L, 0x2000L, 0x4000L, 0x8000L,
4677 0x10000L, 0x20000L, 0x40000L, 0x80000L,
4678 0x100000L, 0x200000L, 0x400000L, 0x800000L,
4679 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
4680 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
4683 for (idx = 0; idx < 32; idx++)
4689 /*-----------------------------------------------------------------*/
4690 /* jmpTrueOrFalse - */
4691 /*-----------------------------------------------------------------*/
4693 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
4695 // ugly but optimized by peephole
4698 symbol *nlbl = newiTempLabel (NULL);
4699 emit2 ("jp !tlabel", nlbl->key + 100);
4700 emitLabel (tlbl->key + 100);
4701 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
4702 emitLabel (nlbl->key + 100);
4706 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
4707 emitLabel (tlbl->key + 100);
4712 /*-----------------------------------------------------------------*/
4713 /* genAnd - code for and */
4714 /*-----------------------------------------------------------------*/
4716 genAnd (iCode * ic, iCode * ifx)
4718 operand *left, *right, *result;
4719 int size, offset = 0;
4720 unsigned long lit = 0L;
4723 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4724 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4725 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4727 /* if left is a literal & right is not then exchange them */
4728 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4729 AOP_NEEDSACC (left))
4731 operand *tmp = right;
4736 /* if result = right then exchange them */
4737 if (sameRegs (AOP (result), AOP (right)))
4739 operand *tmp = right;
4744 /* if right is bit then exchange them */
4745 if (AOP_TYPE (right) == AOP_CRY &&
4746 AOP_TYPE (left) != AOP_CRY)
4748 operand *tmp = right;
4752 if (AOP_TYPE (right) == AOP_LIT)
4753 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4755 size = AOP_SIZE (result);
4757 if (AOP_TYPE (left) == AOP_CRY)
4759 wassertl (0, "Tried to perform an AND with a bit as an operand");
4763 // if(val & 0xZZ) - size = 0, ifx != FALSE -
4764 // bit = val & 0xZZ - size = 1, ifx = FALSE -
4765 if ((AOP_TYPE (right) == AOP_LIT) &&
4766 (AOP_TYPE (result) == AOP_CRY) &&
4767 (AOP_TYPE (left) != AOP_CRY))
4769 symbol *tlbl = newiTempLabel (NULL);
4770 int sizel = AOP_SIZE (left);
4773 /* PENDING: Test case for this. */
4778 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
4780 _moveA (aopGet (AOP (left), offset, FALSE));
4781 if (bytelit != 0x0FFL)
4783 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4790 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4794 // bit = left & literal
4798 emit2 ("!tlabeldef", tlbl->key + 100);
4800 // if(left & literal)
4805 jmpTrueOrFalse (ifx, tlbl);
4813 /* if left is same as result */
4814 if (sameRegs (AOP (result), AOP (left)))
4816 for (; size--; offset++)
4818 if (AOP_TYPE (right) == AOP_LIT)
4820 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4825 aopPut (AOP (result), "!zero", offset);
4828 _moveA (aopGet (AOP (left), offset, FALSE));
4830 aopGet (AOP (right), offset, FALSE));
4831 aopPut (AOP (left), "a", offset);
4838 if (AOP_TYPE (left) == AOP_ACC)
4840 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
4844 _moveA (aopGet (AOP (left), offset, FALSE));
4846 aopGet (AOP (right), offset, FALSE));
4847 aopPut (AOP (left), "a", offset);
4854 // left & result in different registers
4855 if (AOP_TYPE (result) == AOP_CRY)
4857 wassertl (0, "Tried to AND where the result is in carry");
4861 for (; (size--); offset++)
4864 // result = left & right
4865 if (AOP_TYPE (right) == AOP_LIT)
4867 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4869 aopPut (AOP (result),
4870 aopGet (AOP (left), offset, FALSE),
4874 else if (bytelit == 0)
4876 aopPut (AOP (result), "!zero", offset);
4880 // faster than result <- left, anl result,right
4881 // and better if result is SFR
4882 if (AOP_TYPE (left) == AOP_ACC)
4883 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4886 _moveA (aopGet (AOP (left), offset, FALSE));
4888 aopGet (AOP (right), offset, FALSE));
4890 aopPut (AOP (result), "a", offset);
4897 freeAsmop (left, NULL, ic);
4898 freeAsmop (right, NULL, ic);
4899 freeAsmop (result, NULL, ic);
4902 /*-----------------------------------------------------------------*/
4903 /* genOr - code for or */
4904 /*-----------------------------------------------------------------*/
4906 genOr (iCode * ic, iCode * ifx)
4908 operand *left, *right, *result;
4909 int size, offset = 0;
4910 unsigned long lit = 0L;
4913 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4914 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4915 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4917 /* if left is a literal & right is not then exchange them */
4918 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4919 AOP_NEEDSACC (left))
4921 operand *tmp = right;
4926 /* if result = right then exchange them */
4927 if (sameRegs (AOP (result), AOP (right)))
4929 operand *tmp = right;
4934 /* if right is bit then exchange them */
4935 if (AOP_TYPE (right) == AOP_CRY &&
4936 AOP_TYPE (left) != AOP_CRY)
4938 operand *tmp = right;
4942 if (AOP_TYPE (right) == AOP_LIT)
4943 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4945 size = AOP_SIZE (result);
4947 if (AOP_TYPE (left) == AOP_CRY)
4949 wassertl (0, "Tried to OR where left is a bit");
4953 // if(val | 0xZZ) - size = 0, ifx != FALSE -
4954 // bit = val | 0xZZ - size = 1, ifx = FALSE -
4955 if ((AOP_TYPE (right) == AOP_LIT) &&
4956 (AOP_TYPE (result) == AOP_CRY) &&
4957 (AOP_TYPE (left) != AOP_CRY))
4959 symbol *tlbl = newiTempLabel (NULL);
4960 int sizel = AOP_SIZE (left);
4964 wassertl (0, "Result is assigned to a bit");
4966 /* PENDING: Modeled after the AND code which is inefficent. */
4969 bytelit = (lit >> (offset * 8)) & 0x0FFL;
4971 _moveA (aopGet (AOP (left), offset, FALSE));
4972 /* OR with any literal is the same as OR with itself. */
4974 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4980 jmpTrueOrFalse (ifx, tlbl);
4985 /* if left is same as result */
4986 if (sameRegs (AOP (result), AOP (left)))
4988 for (; size--; offset++)
4990 if (AOP_TYPE (right) == AOP_LIT)
4992 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4996 _moveA (aopGet (AOP (left), offset, FALSE));
4998 aopGet (AOP (right), offset, FALSE));
4999 aopPut (AOP (result), "a", offset);
5004 if (AOP_TYPE (left) == AOP_ACC)
5005 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5008 _moveA (aopGet (AOP (left), offset, FALSE));
5010 aopGet (AOP (right), offset, FALSE));
5011 aopPut (AOP (result), "a", offset);
5018 // left & result in different registers
5019 if (AOP_TYPE (result) == AOP_CRY)
5021 wassertl (0, "Result of OR is in a bit");
5024 for (; (size--); offset++)
5027 // result = left & right
5028 if (AOP_TYPE (right) == AOP_LIT)
5030 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5032 aopPut (AOP (result),
5033 aopGet (AOP (left), offset, FALSE),
5038 // faster than result <- left, anl result,right
5039 // and better if result is SFR
5040 if (AOP_TYPE (left) == AOP_ACC)
5041 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5044 _moveA (aopGet (AOP (left), offset, FALSE));
5046 aopGet (AOP (right), offset, FALSE));
5048 aopPut (AOP (result), "a", offset);
5049 /* PENDING: something weird is going on here. Add exception. */
5050 if (AOP_TYPE (result) == AOP_ACC)
5056 freeAsmop (left, NULL, ic);
5057 freeAsmop (right, NULL, ic);
5058 freeAsmop (result, NULL, ic);
5061 /*-----------------------------------------------------------------*/
5062 /* genXor - code for xclusive or */
5063 /*-----------------------------------------------------------------*/
5065 genXor (iCode * ic, iCode * ifx)
5067 operand *left, *right, *result;
5068 int size, offset = 0;
5069 unsigned long lit = 0L;
5071 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5072 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5073 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5075 /* if left is a literal & right is not then exchange them */
5076 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5077 AOP_NEEDSACC (left))
5079 operand *tmp = right;
5084 /* if result = right then exchange them */
5085 if (sameRegs (AOP (result), AOP (right)))
5087 operand *tmp = right;
5092 /* if right is bit then exchange them */
5093 if (AOP_TYPE (right) == AOP_CRY &&
5094 AOP_TYPE (left) != AOP_CRY)
5096 operand *tmp = right;
5100 if (AOP_TYPE (right) == AOP_LIT)
5101 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5103 size = AOP_SIZE (result);
5105 if (AOP_TYPE (left) == AOP_CRY)
5107 wassertl (0, "Tried to XOR a bit");
5111 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5112 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5113 if ((AOP_TYPE (right) == AOP_LIT) &&
5114 (AOP_TYPE (result) == AOP_CRY) &&
5115 (AOP_TYPE (left) != AOP_CRY))
5117 symbol *tlbl = newiTempLabel (NULL);
5118 int sizel = AOP_SIZE (left);
5122 /* PENDING: Test case for this. */
5123 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5127 _moveA (aopGet (AOP (left), offset, FALSE));
5128 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5129 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5134 jmpTrueOrFalse (ifx, tlbl);
5138 wassertl (0, "Result of XOR was destined for a bit");
5143 /* if left is same as result */
5144 if (sameRegs (AOP (result), AOP (left)))
5146 for (; size--; offset++)
5148 if (AOP_TYPE (right) == AOP_LIT)
5150 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5154 _moveA (aopGet (AOP (right), offset, FALSE));
5156 aopGet (AOP (left), offset, FALSE));
5157 aopPut (AOP (result), "a", offset);
5162 if (AOP_TYPE (left) == AOP_ACC)
5164 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5168 _moveA (aopGet (AOP (right), offset, FALSE));
5170 aopGet (AOP (left), offset, FALSE));
5171 aopPut (AOP (result), "a", 0);
5178 // left & result in different registers
5179 if (AOP_TYPE (result) == AOP_CRY)
5181 wassertl (0, "Result of XOR is in a bit");
5184 for (; (size--); offset++)
5187 // result = left & right
5188 if (AOP_TYPE (right) == AOP_LIT)
5190 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5192 aopPut (AOP (result),
5193 aopGet (AOP (left), offset, FALSE),
5198 // faster than result <- left, anl result,right
5199 // and better if result is SFR
5200 if (AOP_TYPE (left) == AOP_ACC)
5202 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5206 _moveA (aopGet (AOP (right), offset, FALSE));
5208 aopGet (AOP (left), offset, FALSE));
5210 aopPut (AOP (result), "a", offset);
5215 freeAsmop (left, NULL, ic);
5216 freeAsmop (right, NULL, ic);
5217 freeAsmop (result, NULL, ic);
5220 /*-----------------------------------------------------------------*/
5221 /* genInline - write the inline code out */
5222 /*-----------------------------------------------------------------*/
5224 genInline (iCode * ic)
5226 char *buffer, *bp, *bp1;
5228 _G.lines.isInline += (!options.asmpeep);
5230 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5231 strcpy (buffer, IC_INLINE (ic));
5233 /* emit each line as a code */
5258 _G.lines.isInline -= (!options.asmpeep);
5262 /*-----------------------------------------------------------------*/
5263 /* genRRC - rotate right with carry */
5264 /*-----------------------------------------------------------------*/
5271 /*-----------------------------------------------------------------*/
5272 /* genRLC - generate code for rotate left with carry */
5273 /*-----------------------------------------------------------------*/
5280 /*-----------------------------------------------------------------*/
5281 /* genGetHbit - generates code get highest order bit */
5282 /*-----------------------------------------------------------------*/
5284 genGetHbit (iCode * ic)
5286 operand *left, *result;
5287 left = IC_LEFT (ic);
5288 result = IC_RESULT (ic);
5290 aopOp (left, ic, FALSE, FALSE);
5291 aopOp (result, ic, FALSE, FALSE);
5293 /* get the highest order byte into a */
5294 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5296 if (AOP_TYPE (result) == AOP_CRY)
5304 emit2 ("and a,!one");
5309 freeAsmop (left, NULL, ic);
5310 freeAsmop (result, NULL, ic);
5314 emitRsh2 (asmop *aop, int size, int is_signed)
5320 const char *l = aopGet (aop, size, FALSE);
5323 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5333 /*-----------------------------------------------------------------*/
5334 /* shiftR2Left2Result - shift right two bytes from left to result */
5335 /*-----------------------------------------------------------------*/
5337 shiftR2Left2Result (operand * left, int offl,
5338 operand * result, int offr,
5339 int shCount, int is_signed)
5342 symbol *tlbl, *tlbl1;
5344 movLeft2Result (left, offl, result, offr, 0);
5345 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5347 /* if (AOP(result)->type == AOP_REG) { */
5349 tlbl = newiTempLabel (NULL);
5350 tlbl1 = newiTempLabel (NULL);
5352 /* Left is already in result - so now do the shift */
5357 emitRsh2 (AOP (result), size, is_signed);
5362 emit2 ("ld a,!immedbyte+1", shCount);
5363 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5364 emitLabel (tlbl->key + 100);
5366 emitRsh2 (AOP (result), size, is_signed);
5368 emitLabel (tlbl1->key + 100);
5370 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5374 /*-----------------------------------------------------------------*/
5375 /* shiftL2Left2Result - shift left two bytes from left to result */
5376 /*-----------------------------------------------------------------*/
5378 shiftL2Left2Result (operand * left, int offl,
5379 operand * result, int offr, int shCount)
5381 if (sameRegs (AOP (result), AOP (left)) &&
5382 ((offl + MSB16) == offr))
5388 /* Copy left into result */
5389 movLeft2Result (left, offl, result, offr, 0);
5390 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5393 if (getPairId (AOP (result)) == PAIR_HL)
5397 emit2 ("add hl,hl");
5404 symbol *tlbl, *tlbl1;
5407 tlbl = newiTempLabel (NULL);
5408 tlbl1 = newiTempLabel (NULL);
5410 if (AOP (result)->type == AOP_REG)
5414 for (offset = 0; offset < size; offset++)
5416 l = aopGet (AOP (result), offset, FALSE);
5420 emit2 ("sla %s", l);
5431 /* Left is already in result - so now do the shift */
5434 emit2 ("ld a,!immedbyte+1", shCount);
5435 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5436 emitLabel (tlbl->key + 100);
5441 l = aopGet (AOP (result), offset, FALSE);
5445 emit2 ("sla %s", l);
5456 emitLabel (tlbl1->key + 100);
5458 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5464 /*-----------------------------------------------------------------*/
5465 /* AccRol - rotate left accumulator by known count */
5466 /*-----------------------------------------------------------------*/
5468 AccRol (int shCount)
5470 shCount &= 0x0007; // shCount : 0..7
5509 /*-----------------------------------------------------------------*/
5510 /* AccLsh - left shift accumulator by known count */
5511 /*-----------------------------------------------------------------*/
5513 AccLsh (int shCount)
5515 static const unsigned char SLMask[] =
5517 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5526 else if (shCount == 2)
5533 /* rotate left accumulator */
5535 /* and kill the lower order bits */
5536 emit2 ("and a,!immedbyte", SLMask[shCount]);
5541 /*-----------------------------------------------------------------*/
5542 /* shiftL1Left2Result - shift left one byte from left to result */
5543 /*-----------------------------------------------------------------*/
5545 shiftL1Left2Result (operand * left, int offl,
5546 operand * result, int offr, int shCount)
5549 l = aopGet (AOP (left), offl, FALSE);
5551 /* shift left accumulator */
5553 aopPut (AOP (result), "a", offr);
5557 /*-----------------------------------------------------------------*/
5558 /* genlshTwo - left shift two bytes by known amount != 0 */
5559 /*-----------------------------------------------------------------*/
5561 genlshTwo (operand * result, operand * left, int shCount)
5563 int size = AOP_SIZE (result);
5565 wassert (size == 2);
5567 /* if shCount >= 8 */
5575 movLeft2Result (left, LSB, result, MSB16, 0);
5576 aopPut (AOP (result), "!zero", 0);
5577 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
5581 movLeft2Result (left, LSB, result, MSB16, 0);
5582 aopPut (AOP (result), "!zero", 0);
5587 aopPut (AOP (result), "!zero", LSB);
5590 /* 1 <= shCount <= 7 */
5599 shiftL2Left2Result (left, LSB, result, LSB, shCount);
5604 /*-----------------------------------------------------------------*/
5605 /* genlshOne - left shift a one byte quantity by known count */
5606 /*-----------------------------------------------------------------*/
5608 genlshOne (operand * result, operand * left, int shCount)
5610 shiftL1Left2Result (left, LSB, result, LSB, shCount);
5613 /*-----------------------------------------------------------------*/
5614 /* genLeftShiftLiteral - left shifting by known count */
5615 /*-----------------------------------------------------------------*/
5617 genLeftShiftLiteral (operand * left,
5622 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5625 freeAsmop (right, NULL, ic);
5627 aopOp (left, ic, FALSE, FALSE);
5628 aopOp (result, ic, FALSE, FALSE);
5630 size = getSize (operandType (result));
5632 /* I suppose that the left size >= result size */
5638 else if (shCount >= (size * 8))
5642 aopPut (AOP (result), "!zero", size);
5650 genlshOne (result, left, shCount);
5653 genlshTwo (result, left, shCount);
5656 wassertl (0, "Shifting of longs is currently unsupported");
5662 freeAsmop (left, NULL, ic);
5663 freeAsmop (result, NULL, ic);
5666 /*-----------------------------------------------------------------*/
5667 /* genLeftShift - generates code for left shifting */
5668 /*-----------------------------------------------------------------*/
5670 genLeftShift (iCode * ic)
5674 symbol *tlbl, *tlbl1;
5675 operand *left, *right, *result;
5677 right = IC_RIGHT (ic);
5678 left = IC_LEFT (ic);
5679 result = IC_RESULT (ic);
5681 aopOp (right, ic, FALSE, FALSE);
5683 /* if the shift count is known then do it
5684 as efficiently as possible */
5685 if (AOP_TYPE (right) == AOP_LIT)
5687 genLeftShiftLiteral (left, right, result, ic);
5691 /* shift count is unknown then we have to form a loop get the loop
5692 count in B : Note: we take only the lower order byte since
5693 shifting more that 32 bits make no sense anyway, ( the largest
5694 size of an object can be only 32 bits ) */
5695 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5697 freeAsmop (right, NULL, ic);
5698 aopOp (left, ic, FALSE, FALSE);
5699 aopOp (result, ic, FALSE, FALSE);
5701 /* now move the left to the result if they are not the
5704 if (!sameRegs (AOP (left), AOP (result)))
5707 size = AOP_SIZE (result);
5711 l = aopGet (AOP (left), offset, FALSE);
5712 aopPut (AOP (result), l, offset);
5717 tlbl = newiTempLabel (NULL);
5718 size = AOP_SIZE (result);
5720 tlbl1 = newiTempLabel (NULL);
5722 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5723 emitLabel (tlbl->key + 100);
5724 l = aopGet (AOP (result), offset, FALSE);
5728 l = aopGet (AOP (result), offset, FALSE);
5732 emit2 ("sla %s", l);
5740 emitLabel (tlbl1->key + 100);
5742 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5744 freeAsmop (left, NULL, ic);
5745 freeAsmop (result, NULL, ic);
5748 /*-----------------------------------------------------------------*/
5749 /* genrshOne - left shift two bytes by known amount != 0 */
5750 /*-----------------------------------------------------------------*/
5752 genrshOne (operand * result, operand * left, int shCount, int is_signed)
5755 int size = AOP_SIZE (result);
5758 wassert (size == 1);
5759 wassert (shCount < 8);
5761 l = aopGet (AOP (left), 0, FALSE);
5763 if (AOP (result)->type == AOP_REG)
5765 aopPut (AOP (result), l, 0);
5766 l = aopGet (AOP (result), 0, FALSE);
5769 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5777 emit2 ("%s a", is_signed ? "sra" : "srl");
5779 aopPut (AOP (result), "a", 0);
5783 /*-----------------------------------------------------------------*/
5784 /* AccRsh - right shift accumulator by known count */
5785 /*-----------------------------------------------------------------*/
5787 AccRsh (int shCount)
5789 static const unsigned char SRMask[] =
5791 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
5796 /* rotate right accumulator */
5797 AccRol (8 - shCount);
5798 /* and kill the higher order bits */
5799 emit2 ("and a,!immedbyte", SRMask[shCount]);
5803 /*-----------------------------------------------------------------*/
5804 /* shiftR1Left2Result - shift right one byte from left to result */
5805 /*-----------------------------------------------------------------*/
5807 shiftR1Left2Result (operand * left, int offl,
5808 operand * result, int offr,
5809 int shCount, int sign)
5811 _moveA (aopGet (AOP (left), offl, FALSE));
5816 emit2 ("%s a", sign ? "sra" : "srl");
5823 aopPut (AOP (result), "a", offr);
5826 /*-----------------------------------------------------------------*/
5827 /* genrshTwo - right shift two bytes by known amount != 0 */
5828 /*-----------------------------------------------------------------*/
5830 genrshTwo (operand * result, operand * left,
5831 int shCount, int sign)
5833 /* if shCount >= 8 */
5839 shiftR1Left2Result (left, MSB16, result, LSB,
5844 movLeft2Result (left, MSB16, result, LSB, sign);
5848 /* Sign extend the result */
5849 _moveA(aopGet (AOP (result), 0, FALSE));
5853 aopPut (AOP (result), ACC_NAME, MSB16);
5857 aopPut (AOP (result), "!zero", 1);
5860 /* 1 <= shCount <= 7 */
5863 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
5867 /*-----------------------------------------------------------------*/
5868 /* genRightShiftLiteral - left shifting by known count */
5869 /*-----------------------------------------------------------------*/
5871 genRightShiftLiteral (operand * left,
5877 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5880 freeAsmop (right, NULL, ic);
5882 aopOp (left, ic, FALSE, FALSE);
5883 aopOp (result, ic, FALSE, FALSE);
5885 size = getSize (operandType (result));
5887 /* I suppose that the left size >= result size */
5893 else if (shCount >= (size * 8)) {
5895 if (!SPEC_USIGN(getSpec(operandType(left)))) {
5896 _moveA(aopGet (AOP (left), 0, FALSE));
5904 aopPut (AOP (result), s, size);
5911 genrshOne (result, left, shCount, sign);
5914 genrshTwo (result, left, shCount, sign);
5917 wassertl (0, "Asked to shift right a long which should be a function call");
5920 wassertl (0, "Entered default case in right shift delegate");
5923 freeAsmop (left, NULL, ic);
5924 freeAsmop (result, NULL, ic);
5927 /*-----------------------------------------------------------------*/
5928 /* genRightShift - generate code for right shifting */
5929 /*-----------------------------------------------------------------*/
5931 genRightShift (iCode * ic)
5933 operand *right, *left, *result;
5935 int size, offset, first = 1;
5939 symbol *tlbl, *tlbl1;
5941 /* if signed then we do it the hard way preserve the
5942 sign bit moving it inwards */
5943 retype = getSpec (operandType (IC_RESULT (ic)));
5945 is_signed = !SPEC_USIGN (retype);
5947 /* signed & unsigned types are treated the same : i.e. the
5948 signed is NOT propagated inwards : quoting from the
5949 ANSI - standard : "for E1 >> E2, is equivalent to division
5950 by 2**E2 if unsigned or if it has a non-negative value,
5951 otherwise the result is implementation defined ", MY definition
5952 is that the sign does not get propagated */
5954 right = IC_RIGHT (ic);
5955 left = IC_LEFT (ic);
5956 result = IC_RESULT (ic);
5958 aopOp (right, ic, FALSE, FALSE);
5960 /* if the shift count is known then do it
5961 as efficiently as possible */
5962 if (AOP_TYPE (right) == AOP_LIT)
5964 genRightShiftLiteral (left, right, result, ic, is_signed);
5968 aopOp (left, ic, FALSE, FALSE);
5969 aopOp (result, ic, FALSE, FALSE);
5971 /* now move the left to the result if they are not the
5973 if (!sameRegs (AOP (left), AOP (result)) &&
5974 AOP_SIZE (result) > 1)
5977 size = AOP_SIZE (result);
5981 l = aopGet (AOP (left), offset, FALSE);
5982 aopPut (AOP (result), l, offset);
5987 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5989 freeAsmop (right, NULL, ic);
5991 tlbl = newiTempLabel (NULL);
5992 tlbl1 = newiTempLabel (NULL);
5993 size = AOP_SIZE (result);
5996 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5997 emitLabel (tlbl->key + 100);
6000 l = aopGet (AOP (result), offset--, FALSE);
6003 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6011 emitLabel (tlbl1->key + 100);
6013 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6015 freeAsmop (left, NULL, ic);
6016 freeAsmop (result, NULL, ic);
6019 /*-----------------------------------------------------------------*/
6020 /* genGenPointerGet - get value from generic pointer space */
6021 /*-----------------------------------------------------------------*/
6023 genGenPointerGet (operand * left,
6024 operand * result, iCode * ic)
6027 sym_link *retype = getSpec (operandType (result));
6033 aopOp (left, ic, FALSE, FALSE);
6034 aopOp (result, ic, FALSE, FALSE);
6036 size = AOP_SIZE (result);
6038 if (isPair (AOP (left)) && size == 1)
6041 if (isPtrPair (AOP (left)))
6043 tsprintf (buffer, "!*pair", getPairName (AOP (left)));
6044 aopPut (AOP (result), buffer, 0);
6048 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6049 aopPut (AOP (result), "a", 0);
6051 freeAsmop (left, NULL, ic);
6055 if (getPairId (AOP (left)) == PAIR_IY)
6062 tsprintf (at, "!*iyx", offset);
6063 aopPut (AOP (result), at, offset);
6067 freeAsmop (left, NULL, ic);
6071 /* For now we always load into IY */
6072 /* if this is remateriazable */
6073 fetchPair (pair, AOP (left));
6075 /* if bit then unpack */
6076 if (IS_BITVAR (retype))
6080 else if (getPairId (AOP (result)) == PAIR_HL)
6082 wassertl (size == 2, "HL must be of size 2");
6083 emit2 ("ld a,!*hl");
6085 emit2 ("ld h,!*hl");
6087 spillPair (PAIR_HL);
6089 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6091 size = AOP_SIZE (result);
6096 /* PENDING: make this better */
6097 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6099 aopPut (AOP (result), "!*hl", offset++);
6103 emit2 ("ld a,!*pair", _pairs[pair].name);
6104 aopPut (AOP (result), "a", offset++);
6108 emit2 ("inc %s", _pairs[pair].name);
6109 _G.pairs[pair].offset++;
6112 /* Fixup HL back down */
6113 for (size = AOP_SIZE (result)-1; size; size--)
6115 emit2 ("dec %s", _pairs[pair].name);
6120 size = AOP_SIZE (result);
6125 /* PENDING: make this better */
6127 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6129 aopPut (AOP (result), "!*hl", offset++);
6133 emit2 ("ld a,!*pair", _pairs[pair].name);
6134 aopPut (AOP (result), "a", offset++);
6138 emit2 ("inc %s", _pairs[pair].name);
6139 _G.pairs[pair].offset++;
6144 freeAsmop (left, NULL, ic);
6147 freeAsmop (result, NULL, ic);
6150 /*-----------------------------------------------------------------*/
6151 /* genPointerGet - generate code for pointer get */
6152 /*-----------------------------------------------------------------*/
6154 genPointerGet (iCode * ic)
6156 operand *left, *result;
6157 sym_link *type, *etype;
6159 left = IC_LEFT (ic);
6160 result = IC_RESULT (ic);
6162 /* depending on the type of pointer we need to
6163 move it to the correct pointer register */
6164 type = operandType (left);
6165 etype = getSpec (type);
6167 genGenPointerGet (left, result, ic);
6171 isRegOrLit (asmop * aop)
6173 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6178 /*-----------------------------------------------------------------*/
6179 /* genGenPointerSet - stores the value into a pointer location */
6180 /*-----------------------------------------------------------------*/
6182 genGenPointerSet (operand * right,
6183 operand * result, iCode * ic)
6186 sym_link *retype = getSpec (operandType (right));
6187 PAIR_ID pairId = PAIR_HL;
6189 aopOp (result, ic, FALSE, FALSE);
6190 aopOp (right, ic, FALSE, FALSE);
6195 size = AOP_SIZE (right);
6197 /* Handle the exceptions first */
6198 if (isPair (AOP (result)) && size == 1)
6201 const char *l = aopGet (AOP (right), 0, FALSE);
6202 const char *pair = getPairName (AOP (result));
6203 if (canAssignToPtr (l) && isPtr (pair))
6205 emit2 ("ld !*pair,%s", pair, l);
6210 emit2 ("ld !*pair,a", pair);
6215 if ( getPairId( AOP (result)) == PAIR_IY)
6218 const char *l = aopGet (AOP (right), 0, FALSE);
6223 if (canAssignToPtr (l))
6225 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6229 _moveA (aopGet (AOP (right), offset, FALSE));
6230 emit2 ("ld !*iyx,a", offset);
6236 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result))
6242 const char *l = aopGet (AOP (right), offset, FALSE);
6243 if (isRegOrLit (AOP (right)) && !IS_GB)
6245 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
6250 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
6254 emit2 ("inc %s", _pairs[PAIR_HL].name);
6255 _G.pairs[PAIR_HL].offset++;
6260 /* Fixup HL back down */
6261 for (size = AOP_SIZE (right)-1; size; size--)
6263 emit2 ("dec %s", _pairs[PAIR_HL].name);
6268 /* if the operand is already in dptr
6269 then we do nothing else we move the value to dptr */
6270 if (AOP_TYPE (result) != AOP_STR)
6272 fetchPair (pairId, AOP (result));
6274 /* so hl know contains the address */
6275 freeAsmop (result, NULL, ic);
6277 /* if bit then unpack */
6278 if (IS_BITVAR (retype))
6288 const char *l = aopGet (AOP (right), offset, FALSE);
6289 if (isRegOrLit (AOP (right)) && !IS_GB)
6291 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
6296 emit2 ("ld !*pair,a", _pairs[pairId].name);
6300 emit2 ("inc %s", _pairs[pairId].name);
6301 _G.pairs[pairId].offset++;
6307 freeAsmop (right, NULL, ic);
6310 /*-----------------------------------------------------------------*/
6311 /* genPointerSet - stores the value into a pointer location */
6312 /*-----------------------------------------------------------------*/
6314 genPointerSet (iCode * ic)
6316 operand *right, *result;
6317 sym_link *type, *etype;
6319 right = IC_RIGHT (ic);
6320 result = IC_RESULT (ic);
6322 /* depending on the type of pointer we need to
6323 move it to the correct pointer register */
6324 type = operandType (result);
6325 etype = getSpec (type);
6327 genGenPointerSet (right, result, ic);
6330 /*-----------------------------------------------------------------*/
6331 /* genIfx - generate code for Ifx statement */
6332 /*-----------------------------------------------------------------*/
6334 genIfx (iCode * ic, iCode * popIc)
6336 operand *cond = IC_COND (ic);
6339 aopOp (cond, ic, FALSE, TRUE);
6341 /* get the value into acc */
6342 if (AOP_TYPE (cond) != AOP_CRY)
6346 /* the result is now in the accumulator */
6347 freeAsmop (cond, NULL, ic);
6349 /* if there was something to be popped then do it */
6353 /* if the condition is a bit variable */
6354 if (isbit && IS_ITEMP (cond) &&
6356 genIfxJump (ic, SPIL_LOC (cond)->rname);
6357 else if (isbit && !IS_ITEMP (cond))
6358 genIfxJump (ic, OP_SYMBOL (cond)->rname);
6360 genIfxJump (ic, "a");
6365 /*-----------------------------------------------------------------*/
6366 /* genAddrOf - generates code for address of */
6367 /*-----------------------------------------------------------------*/
6369 genAddrOf (iCode * ic)
6371 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
6373 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6375 /* if the operand is on the stack then we
6376 need to get the stack offset of this
6383 if (sym->stack <= 0)
6385 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
6389 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6391 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6395 emit2 ("ld de,!hashedstr", sym->rname);
6396 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
6404 /* if it has an offset then we need to compute it */
6406 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6408 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
6409 emit2 ("add hl,sp");
6413 emit2 ("ld hl,!hashedstr", sym->rname);
6415 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6417 freeAsmop (IC_RESULT (ic), NULL, ic);
6420 /*-----------------------------------------------------------------*/
6421 /* genAssign - generate code for assignment */
6422 /*-----------------------------------------------------------------*/
6424 genAssign (iCode * ic)
6426 operand *result, *right;
6428 unsigned long lit = 0L;
6430 result = IC_RESULT (ic);
6431 right = IC_RIGHT (ic);
6433 /* Dont bother assigning if they are the same */
6434 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6436 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
6440 aopOp (right, ic, FALSE, FALSE);
6441 aopOp (result, ic, TRUE, FALSE);
6443 /* if they are the same registers */
6444 if (sameRegs (AOP (right), AOP (result)))
6446 emitDebug ("; (registers are the same)");
6450 /* if the result is a bit */
6451 if (AOP_TYPE (result) == AOP_CRY)
6453 wassertl (0, "Tried to assign to a bit");
6457 size = AOP_SIZE (result);
6460 if (AOP_TYPE (right) == AOP_LIT)
6462 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6465 if (isPair (AOP (result)))
6467 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
6469 else if ((size > 1) &&
6470 (AOP_TYPE (result) != AOP_REG) &&
6471 (AOP_TYPE (right) == AOP_LIT) &&
6472 !IS_FLOAT (operandType (right)) &&
6475 bool fXored = FALSE;
6477 /* Work from the top down.
6478 Done this way so that we can use the cached copy of 0
6479 in A for a fast clear */
6482 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
6484 if (!fXored && size > 1)
6491 aopPut (AOP (result), "a", offset);
6495 aopPut (AOP (result), "!zero", offset);
6499 aopPut (AOP (result),
6500 aopGet (AOP (right), offset, FALSE),
6505 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
6507 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
6508 aopPut (AOP (result), "l", LSB);
6509 aopPut (AOP (result), "h", MSB16);
6511 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6513 /* Special case. Load into a and d, then load out. */
6514 _moveA (aopGet (AOP (right), 0, FALSE));
6515 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
6516 aopPut (AOP (result), "a", 0);
6517 aopPut (AOP (result), "e", 1);
6519 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6521 /* Special case - simple memcpy */
6522 aopGet (AOP (right), LSB, FALSE);
6525 aopGet (AOP (result), LSB, FALSE);
6529 emit2 ("ld a,(de)");
6530 /* Peephole will optimise this. */
6531 emit2 ("ld (hl),a");
6539 spillPair (PAIR_HL);
6545 /* PENDING: do this check better */
6546 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
6548 _moveA (aopGet (AOP (right), offset, FALSE));
6549 aopPut (AOP (result), "a", offset);
6552 aopPut (AOP (result),
6553 aopGet (AOP (right), offset, FALSE),
6560 freeAsmop (right, NULL, ic);
6561 freeAsmop (result, NULL, ic);
6564 /*-----------------------------------------------------------------*/
6565 /* genJumpTab - genrates code for jump table */
6566 /*-----------------------------------------------------------------*/
6568 genJumpTab (iCode * ic)
6573 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
6574 /* get the condition into accumulator */
6575 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
6578 emit2 ("ld e,%s", l);
6579 emit2 ("ld d,!zero");
6580 jtab = newiTempLabel (NULL);
6582 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
6583 emit2 ("add hl,de");
6584 emit2 ("add hl,de");
6585 emit2 ("add hl,de");
6586 freeAsmop (IC_JTCOND (ic), NULL, ic);
6590 emitLabel (jtab->key + 100);
6591 /* now generate the jump labels */
6592 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
6593 jtab = setNextItem (IC_JTLABELS (ic)))
6594 emit2 ("jp !tlabel", jtab->key + 100);
6597 /*-----------------------------------------------------------------*/
6598 /* genCast - gen code for casting */
6599 /*-----------------------------------------------------------------*/
6601 genCast (iCode * ic)
6603 operand *result = IC_RESULT (ic);
6604 sym_link *rtype = operandType (IC_RIGHT (ic));
6605 operand *right = IC_RIGHT (ic);
6608 /* if they are equivalent then do nothing */
6609 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6612 aopOp (right, ic, FALSE, FALSE);
6613 aopOp (result, ic, FALSE, FALSE);
6615 /* if the result is a bit */
6616 if (AOP_TYPE (result) == AOP_CRY)
6618 wassertl (0, "Tried to cast to a bit");
6621 /* if they are the same size : or less */
6622 if (AOP_SIZE (result) <= AOP_SIZE (right))
6625 /* if they are in the same place */
6626 if (sameRegs (AOP (right), AOP (result)))
6629 /* if they in different places then copy */
6630 size = AOP_SIZE (result);
6634 aopPut (AOP (result),
6635 aopGet (AOP (right), offset, FALSE),
6642 /* So we now know that the size of destination is greater
6643 than the size of the source */
6644 /* we move to result for the size of source */
6645 size = AOP_SIZE (right);
6649 aopPut (AOP (result),
6650 aopGet (AOP (right), offset, FALSE),
6655 /* now depending on the sign of the destination */
6656 size = AOP_SIZE (result) - AOP_SIZE (right);
6657 /* Unsigned or not an integral type - right fill with zeros */
6658 if (SPEC_USIGN (rtype) || !IS_SPEC (rtype) || AOP_TYPE(right)==AOP_CRY)
6661 aopPut (AOP (result), "!zero", offset++);
6665 /* we need to extend the sign :{ */
6666 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
6672 aopPut (AOP (result), "a", offset++);
6676 freeAsmop (right, NULL, ic);
6677 freeAsmop (result, NULL, ic);
6680 /*-----------------------------------------------------------------*/
6681 /* genReceive - generate code for a receive iCode */
6682 /*-----------------------------------------------------------------*/
6684 genReceive (iCode * ic)
6686 if (isOperandInFarSpace (IC_RESULT (ic)) &&
6687 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
6688 IS_TRUE_SYMOP (IC_RESULT (ic))))
6698 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6699 size = AOP_SIZE(IC_RESULT(ic));
6701 for (i = 0; i < size; i++) {
6702 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
6706 freeAsmop (IC_RESULT (ic), NULL, ic);
6711 /** Maximum number of bytes to emit per line. */
6715 /** Context for the byte output chunker. */
6718 unsigned char buffer[DBEMIT_MAX_RUN];
6723 /** Flushes a byte chunker by writing out all in the buffer and
6727 _dbFlush(DBEMITCTX *self)
6734 sprintf(line, ".db 0x%02X", self->buffer[0]);
6736 for (i = 1; i < self->pos; i++)
6738 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
6745 /** Write out another byte, buffering until a decent line is
6749 _dbEmit(DBEMITCTX *self, int c)
6751 if (self->pos == DBEMIT_MAX_RUN)
6755 self->buffer[self->pos++] = c;
6758 /** Context for a simple run length encoder. */
6762 unsigned char buffer[128];
6764 /** runLen may be equivalent to pos. */
6770 RLE_CHANGE_COST = 4,
6774 /** Flush the buffer of a run length encoder by writing out the run or
6775 data that it currently contains.
6778 _rleCommit(RLECTX *self)
6784 memset(&db, 0, sizeof(db));
6786 emit2(".db %u", self->pos);
6788 for (i = 0; i < self->pos; i++)
6790 _dbEmit(&db, self->buffer[i]);
6799 Can get either a run or a block of random stuff.
6800 Only want to change state if a good run comes in or a run ends.
6801 Detecting run end is easy.
6804 Say initial state is in run, len zero, last zero. Then if you get a
6805 few zeros then something else then a short run will be output.
6806 Seems OK. While in run mode, keep counting. While in random mode,
6807 keep a count of the run. If run hits margin, output all up to run,
6808 restart, enter run mode.
6811 /** Add another byte into the run length encoder, flushing as
6812 required. The run length encoder uses the Amiga IFF style, where
6813 a block is prefixed by its run length. A positive length means
6814 the next n bytes pass straight through. A negative length means
6815 that the next byte is repeated -n times. A zero terminates the
6819 _rleAppend(RLECTX *self, int c)
6823 if (c != self->last)
6825 /* The run has stopped. See if it is worthwhile writing it out
6826 as a run. Note that the random data comes in as runs of
6829 if (self->runLen > RLE_CHANGE_COST)
6831 /* Yes, worthwhile. */
6832 /* Commit whatever was in the buffer. */
6834 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
6838 /* Not worthwhile. Append to the end of the random list. */
6839 for (i = 0; i < self->runLen; i++)
6841 if (self->pos >= RLE_MAX_BLOCK)
6846 self->buffer[self->pos++] = self->last;
6854 if (self->runLen >= RLE_MAX_BLOCK)
6856 /* Commit whatever was in the buffer. */
6859 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
6867 _rleFlush(RLECTX *self)
6869 _rleAppend(self, -1);
6876 /** genArrayInit - Special code for initialising an array with constant
6880 genArrayInit (iCode * ic)
6884 int elementSize = 0, eIndex, i;
6885 unsigned val, lastVal;
6889 memset(&rle, 0, sizeof(rle));
6891 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
6893 _saveRegsForCall(ic, 0);
6895 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
6896 emit2 ("call __initrleblock");
6898 type = operandType(IC_LEFT(ic));
6900 if (type && type->next)
6902 elementSize = getSize(type->next);
6906 wassertl (0, "Can't determine element size in genArrayInit.");
6909 iLoop = IC_ARRAYILIST(ic);
6910 lastVal = (unsigned)-1;
6912 /* Feed all the bytes into the run length encoder which will handle
6914 This works well for mixed char data, and for random int and long
6923 for (i = 0; i < ix; i++)
6925 for (eIndex = 0; eIndex < elementSize; eIndex++)
6927 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
6928 _rleAppend(&rle, val);
6933 iLoop = iLoop->next;
6937 /* Mark the end of the run. */
6940 _restoreRegsAfterCall();
6944 freeAsmop (IC_LEFT(ic), NULL, ic);
6948 _swap (PAIR_ID one, PAIR_ID two)
6950 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
6956 emit2 ("ld a,%s", _pairs[one].l);
6957 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
6958 emit2 ("ld %s,a", _pairs[two].l);
6959 emit2 ("ld a,%s", _pairs[one].h);
6960 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
6961 emit2 ("ld %s,a", _pairs[two].h);
6965 /* The problem is that we may have all three pairs used and they may
6966 be needed in a different order.
6971 hl = hl => unity, fine
6975 hl = hl hl = hl, swap de <=> bc
6983 hl = bc de = de, swap bc <=> hl
6991 hl = de bc = bc, swap hl <=> de
6996 * Any pair = pair are done last
6997 * Any pair = iTemp are done last
6998 * Any swaps can be done any time
7006 So how do we detect the cases?
7007 How about a 3x3 matrix?
7011 x x x x (Fourth for iTemp/other)
7013 First determin which mode to use by counting the number of unity and
7016 Two - Assign the pair first, then the rest
7017 One - Swap the two, then the rest
7021 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7023 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7025 PAIR_BC, PAIR_HL, PAIR_DE
7027 int i, j, nunity = 0;
7028 memset (ids, PAIR_INVALID, sizeof (ids));
7031 wassert (nparams == 3);
7033 /* First save everything that needs to be saved. */
7034 _saveRegsForCall (ic, 0);
7036 /* Loading HL first means that DE is always fine. */
7037 for (i = 0; i < nparams; i++)
7039 aopOp (pparams[i], ic, FALSE, FALSE);
7040 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7043 /* Count the number of unity or iTemp assigns. */
7044 for (i = 0; i < 3; i++)
7046 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7054 /* Any order, fall through. */
7056 else if (nunity == 2)
7058 /* One is assigned. Pull it out and assign. */
7059 for (i = 0; i < 3; i++)
7061 for (j = 0; j < NUM_PAIRS; j++)
7063 if (ids[dest[i]][j] == TRUE)
7065 /* Found it. See if it's the right one. */
7066 if (j == PAIR_INVALID || j == dest[i])
7072 fetchPair(dest[i], AOP (pparams[i]));
7079 else if (nunity == 1)
7081 /* Find the pairs to swap. */
7082 for (i = 0; i < 3; i++)
7084 for (j = 0; j < NUM_PAIRS; j++)
7086 if (ids[dest[i]][j] == TRUE)
7088 if (j == PAIR_INVALID || j == dest[i])
7103 int next = getPairId (AOP (pparams[0]));
7104 emit2 ("push %s", _pairs[next].name);
7106 if (next == dest[1])
7108 fetchPair (dest[1], AOP (pparams[1]));
7109 fetchPair (dest[2], AOP (pparams[2]));
7113 fetchPair (dest[2], AOP (pparams[2]));
7114 fetchPair (dest[1], AOP (pparams[1]));
7116 emit2 ("pop %s", _pairs[dest[0]].name);
7119 /* Finally pull out all of the iTemps */
7120 for (i = 0; i < 3; i++)
7122 if (ids[dest[i]][PAIR_INVALID] == 1)
7124 fetchPair (dest[i], AOP (pparams[i]));
7130 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
7136 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
7140 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7142 setupForBuiltin3 (ic, nParams, pparams);
7144 label = newiTempLabel(NULL);
7146 emitLabel (label->key);
7147 emit2 ("ld a,(hl)");
7150 emit2 ("!shortjp nz,!tlabel ; 1", label->key);
7152 freeAsmop (from, NULL, ic->next);
7153 freeAsmop (to, NULL, ic);
7157 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
7159 operand *from, *to, *count;
7162 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
7167 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7169 setupForBuiltin3 (ic, nParams, pparams);
7173 freeAsmop (count, NULL, ic->next->next);
7174 freeAsmop (from, NULL, ic);
7176 _restoreRegsAfterCall();
7178 /* if we need assign a result value */
7179 if ((IS_ITEMP (IC_RESULT (ic)) &&
7180 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
7181 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
7182 IS_TRUE_SYMOP (IC_RESULT (ic)))
7184 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7185 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
7186 freeAsmop (IC_RESULT (ic), NULL, ic);
7189 freeAsmop (to, NULL, ic->next);
7192 /*-----------------------------------------------------------------*/
7193 /* genBuiltIn - calls the appropriate function to generating code */
7194 /* for a built in function */
7195 /*-----------------------------------------------------------------*/
7196 static void genBuiltIn (iCode *ic)
7198 operand *bi_parms[MAX_BUILTIN_ARGS];
7203 /* get all the arguments for a built in function */
7204 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
7206 /* which function is it */
7207 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
7209 if (strcmp(bif->name,"__builtin_strcpy")==0)
7211 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
7213 else if (strcmp(bif->name,"__builtin_memcpy")==0)
7215 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
7219 wassertl (0, "Unknown builtin function encountered");
7223 /*-----------------------------------------------------------------*/
7224 /* genZ80Code - generate code for Z80 based controllers */
7225 /*-----------------------------------------------------------------*/
7227 genZ80Code (iCode * lic)
7235 _fReturn = _gbz80_return;
7236 _fTmp = _gbz80_return;
7240 _fReturn = _z80_return;
7241 _fTmp = _z80_return;
7244 _G.lines.head = _G.lines.current = NULL;
7246 for (ic = lic; ic; ic = ic->next)
7249 if (cln != ic->lineno)
7251 emit2 ("; %s:%d: %s", ic->filename, ic->lineno,
7252 printCLine(ic->filename, ic->lineno));
7255 /* if the result is marked as
7256 spilt and rematerializable or code for
7257 this has already been generated then
7259 if (resultRemat (ic) || ic->generated)
7262 /* depending on the operation */
7266 emitDebug ("; genNot");
7271 emitDebug ("; genCpl");
7276 emitDebug ("; genUminus");
7281 emitDebug ("; genIpush");
7286 /* IPOP happens only when trying to restore a
7287 spilt live range, if there is an ifx statement
7288 following this pop then the if statement might
7289 be using some of the registers being popped which
7290 would destory the contents of the register so
7291 we need to check for this condition and handle it */
7293 ic->next->op == IFX &&
7294 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
7296 emitDebug ("; genIfx");
7297 genIfx (ic->next, ic);
7301 emitDebug ("; genIpop");
7307 emitDebug ("; genCall");
7312 emitDebug ("; genPcall");
7317 emitDebug ("; genFunction");
7322 emitDebug ("; genEndFunction");
7323 genEndFunction (ic);
7327 emitDebug ("; genRet");
7332 emitDebug ("; genLabel");
7337 emitDebug ("; genGoto");
7342 emitDebug ("; genPlus");
7347 emitDebug ("; genMinus");
7352 emitDebug ("; genMult");
7357 emitDebug ("; genDiv");
7362 emitDebug ("; genMod");
7367 emitDebug ("; genCmpGt");
7368 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
7372 emitDebug ("; genCmpLt");
7373 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
7380 /* note these two are xlated by algebraic equivalence
7381 during parsing SDCC.y */
7382 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
7383 "got '>=' or '<=' shouldn't have come here");
7387 emitDebug ("; genCmpEq");
7388 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
7392 emitDebug ("; genAndOp");
7397 emitDebug ("; genOrOp");
7402 emitDebug ("; genXor");
7403 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
7407 emitDebug ("; genOr");
7408 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
7412 emitDebug ("; genAnd");
7413 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
7417 emitDebug ("; genInline");
7422 emitDebug ("; genRRC");
7427 emitDebug ("; genRLC");
7432 emitDebug ("; genGetHBIT");
7437 emitDebug ("; genLeftShift");
7442 emitDebug ("; genRightShift");
7446 case GET_VALUE_AT_ADDRESS:
7447 emitDebug ("; genPointerGet");
7453 if (POINTER_SET (ic))
7455 emitDebug ("; genAssign (pointer)");
7460 emitDebug ("; genAssign");
7466 emitDebug ("; genIfx");
7471 emitDebug ("; genAddrOf");
7476 emitDebug ("; genJumpTab");
7481 emitDebug ("; genCast");
7486 emitDebug ("; genReceive");
7491 if (ic->builtinSEND)
7493 emitDebug ("; genBuiltIn");
7498 emitDebug ("; addSet");
7499 addSet (&_G.sendSet, ic);
7504 emitDebug ("; genArrayInit");
7514 /* now we are ready to call the
7515 peep hole optimizer */
7516 if (!options.nopeep)
7517 peepHole (&_G.lines.head);
7519 /* This is unfortunate */
7520 /* now do the actual printing */
7522 FILE *fp = codeOutFile;
7523 if (isInHome () && codeOutFile == code->oFile)
7524 codeOutFile = home->oFile;
7525 printLine (_G.lines.head, codeOutFile);
7526 if (_G.flushStatics)
7529 _G.flushStatics = 0;
7534 freeTrace(&_G.lines.trace);
7535 freeTrace(&_G.trace.aops);
7541 _isPairUsed (iCode * ic, PAIR_ID pairId)
7547 if (bitVectBitValue (ic->rMask, D_IDX))
7549 if (bitVectBitValue (ic->rMask, E_IDX))
7559 fetchLitSpecial (asmop * aop, bool negate, bool xor)
7562 value *val = aop->aopu.aop_lit;
7564 wassert (aop->type == AOP_LIT);
7565 wassert (!IS_FLOAT (val->type));
7567 v = (unsigned long) floatFromVal (val);
7575 tsprintf (buffer, "!immedword", v);
7576 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));