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 #ifdef HAVE_SYS_ISA_DEFS_H
91 #include <sys/isa_defs.h>
95 #include "SDCCglobl.h"
96 #include "SDCCpeeph.h"
101 /* This is the down and dirty file with all kinds of kludgy & hacky
102 stuff. This is what it is all about CODE GENERATION for a specific MCU.
103 Some of the routines may be reusable, will have to see */
105 /* Z80 calling convention description.
106 Parameters are passed right to left. As the stack grows downwards,
107 the parameters are arranged in left to right in memory.
108 Parameters may be passed in the HL and DE registers with one
110 PENDING: What if the parameter is a long?
111 Everything is caller saves. i.e. the caller must save any registers
112 that it wants to preserve over the call.
113 GB: The return value is returned in DEHL. DE is normally used as a
114 working register pair. Caller saves allows it to be used for a
116 va args functions do not use register parameters. All arguments
117 are passed on the stack.
118 IX is used as an index register to the top of the local variable
119 area. ix-0 is the top most local variable.
124 /* Set to enable debugging trace statements in the output assembly code. */
128 static char *_z80_return[] =
129 {"l", "h", "e", "d"};
130 static char *_gbz80_return[] =
131 {"e", "d", "l", "h"};
132 static char *_fReceive[] =
133 { "c", "b", "e", "d" };
135 static char **_fReturn;
138 extern FILE *codeOutFile;
146 /** Enum covering all the possible register pairs.
165 } _pairs[NUM_PAIRS] = {
166 { "??1", "?2", "?3" },
171 { "iy", "iyl", "iyh" },
172 { "ix", "ixl", "ixh" }
176 #define ACC_NAME _pairs[PAIR_AF].h
186 /** Code generator persistent data.
190 /** Used to optimised setting up of a pair by remebering what it
191 contains and adjusting instead of reloading where possible.
212 const char *lastFunctionName;
218 /** TRUE if the registers have already been saved. */
236 static const char *aopGet (asmop * aop, int offset, bool bit16);
238 static const char *aopNames[] = {
258 isLastUse (iCode *ic, operand *op)
260 bitVect *uses = bitVectCopy (OP_USES (op));
262 while (!bitVectIsZero (uses))
264 if (bitVectFirstBit (uses) == ic->key)
266 if (bitVectnBitsOn (uses) == 1)
275 bitVectUnSetBit (uses, bitVectFirstBit (uses));
295 _getTempPairName(void)
297 return _pairs[_getTempPairId()].name;
301 isPairInUse (PAIR_ID id, iCode *ic)
305 return bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
307 else if (id == PAIR_BC)
309 return bitVectBitValue (ic->rMask, B_IDX) || bitVectBitValue(ic->rMask, C_IDX);
313 wassertl (0, "Only implemented for DE and BC");
319 isPairInUseNotInRet(PAIR_ID id, iCode *ic)
323 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
327 return bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
331 wassertl (0, "Only implemented for DE");
337 getFreePairId (iCode *ic)
339 if (!isPairInUse (PAIR_BC, ic))
343 else if (IS_Z80 && !isPairInUse (PAIR_DE, ic))
356 /* Clean up the line so that it is 'prettier' */
357 if (strchr (buf, ':'))
359 /* Is a label - cant do anything */
362 /* Change the first (and probably only) ' ' to a tab so
377 _newLineNode (char *line)
381 pl = traceAlloc(&_G.lines.trace, Safe_alloc ( sizeof (lineNode)));
382 pl->line = traceAlloc(&_G.lines.trace, Safe_strdup (line));
388 _vemit2 (const char *szFormat, va_list ap)
392 tvsprintf (buffer, szFormat, ap);
395 _G.lines.current = (_G.lines.current ?
396 connectLine (_G.lines.current, _newLineNode (buffer)) :
397 (_G.lines.head = _newLineNode (buffer)));
399 _G.lines.current->isInline = _G.lines.isInline;
403 emit2 (const char *szFormat,...)
407 va_start (ap, szFormat);
409 _vemit2 (szFormat, ap);
415 emitDebug (const char *szFormat,...)
421 va_start (ap, szFormat);
423 _vemit2 (szFormat, ap);
429 /*-----------------------------------------------------------------*/
430 /* emit2 - writes the code into a file : for now it is simple */
431 /*-----------------------------------------------------------------*/
433 _emit2 (const char *inst, const char *fmt,...)
436 char lb[INITIAL_INLINEASM];
443 sprintf (lb, "%s\t", inst);
444 vsprintf (lb + (strlen (lb)), fmt, ap);
447 vsprintf (lb, fmt, ap);
449 while (isspace (*lbp))
454 _G.lines.current = (_G.lines.current ?
455 connectLine (_G.lines.current, _newLineNode (lb)) :
456 (_G.lines.head = _newLineNode (lb)));
458 _G.lines.current->isInline = _G.lines.isInline;
463 _emitMove(const char *to, const char *from)
465 if (strcasecmp(to, from) != 0)
467 emit2("ld %s,%s", to, from);
472 // Could leave this to the peephole, but sometimes the peephole is inhibited.
477 aopDump(const char *plabel, asmop *aop)
479 emitDebug("; Dump of %s: type %s size %u", plabel, aopNames[aop->type], aop->size);
483 emitDebug("; aop_stk %d", aop->aopu.aop_stk);
486 /* No information. */
491 _moveA(const char *moveFrom)
493 // Let the peephole optimiser take care of redundent loads
494 _emitMove(ACC_NAME, moveFrom);
504 getPairName (asmop * aop)
506 if (aop->type == AOP_REG)
508 switch (aop->aopu.aop_reg[0]->rIdx)
521 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
524 for (i = 0; i < NUM_PAIRS; i++)
526 if (strcmp(aop->aopu.aop_str[0], _pairs[i].l) == 0)
528 return _pairs[i].name;
532 wassertl (0, "Tried to get the pair name of something that isn't a pair");
537 getPairId (asmop * aop)
541 if (aop->type == AOP_REG)
543 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX) && (aop->aopu.aop_reg[1]->rIdx == B_IDX))
547 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX) && (aop->aopu.aop_reg[1]->rIdx == D_IDX))
551 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX) && (aop->aopu.aop_reg[1]->rIdx == H_IDX))
556 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
559 for (i = 0; i < NUM_PAIRS; i++)
561 if (!strcmp (aop->aopu.aop_str[0], _pairs[i].l) && !strcmp (aop->aopu.aop_str[1], _pairs[i].h))
571 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
575 return (getPairId (aop) != PAIR_INVALID);
579 isPtrPair (asmop * aop)
581 PAIR_ID pairId = getPairId (aop);
594 spillPair (PAIR_ID pairId)
596 _G.pairs[pairId].last_type = AOP_INVALID;
597 _G.pairs[pairId].base = NULL;
600 /** Push a register pair onto the stack */
602 genPairPush (asmop * aop)
604 emit2 ("push %s", getPairName (aop));
608 _push (PAIR_ID pairId)
610 emit2 ("push %s", _pairs[pairId].name);
611 _G.stack.pushed += 2;
615 _pop (PAIR_ID pairId)
617 emit2 ("pop %s", _pairs[pairId].name);
618 _G.stack.pushed -= 2;
622 /*-----------------------------------------------------------------*/
623 /* newAsmop - creates a new asmOp */
624 /*-----------------------------------------------------------------*/
626 newAsmop (short type)
630 aop = traceAlloc(&_G.trace.aops, Safe_alloc (sizeof (asmop)));
635 /*-----------------------------------------------------------------*/
636 /* aopForSym - for a true symbol */
637 /*-----------------------------------------------------------------*/
639 aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
646 wassert (sym->etype);
648 space = SPEC_OCLS (sym->etype);
650 /* if already has one */
656 /* Assign depending on the storage class */
657 if (sym->onStack || sym->iaccess)
659 /* The pointer that is used depends on how big the offset is.
660 Normally everything is AOP_STK, but for offsets of < -128 or
661 > 127 on the Z80 an extended stack pointer is used.
663 if (IS_Z80 && (options.ommitFramePtr || sym->stack < INT8MIN || sym->stack > (int)(INT8MAX-getSize (sym->type))))
665 emitDebug ("; AOP_EXSTK for %s", sym->rname);
666 sym->aop = aop = newAsmop (AOP_EXSTK);
670 emitDebug ("; AOP_STK for %s", sym->rname);
671 sym->aop = aop = newAsmop (AOP_STK);
674 aop->size = getSize (sym->type);
675 aop->aopu.aop_stk = sym->stack;
679 /* special case for a function */
680 if (IS_FUNC (sym->type))
682 sym->aop = aop = newAsmop (AOP_IMMD);
683 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup (sym->rname));
690 /* if it is in direct space */
691 if (IN_REGSP (space) && !requires_a)
693 sym->aop = aop = newAsmop (AOP_SFR);
694 aop->aopu.aop_dir = sym->rname;
695 aop->size = getSize (sym->type);
696 emitDebug ("; AOP_SFR for %s", sym->rname);
701 /* only remaining is far space */
702 /* in which case DPTR gets the address */
705 emitDebug ("; AOP_HL for %s", sym->rname);
706 sym->aop = aop = newAsmop (AOP_HL);
710 sym->aop = aop = newAsmop (AOP_IY);
712 aop->size = getSize (sym->type);
713 aop->aopu.aop_dir = sym->rname;
715 /* if it is in code space */
716 if (IN_CODESPACE (space))
722 /*-----------------------------------------------------------------*/
723 /* aopForRemat - rematerialzes an object */
724 /*-----------------------------------------------------------------*/
726 aopForRemat (symbol * sym)
729 iCode *ic = sym->rematiCode;
730 asmop *aop = newAsmop (AOP_IMMD);
734 /* if plus or minus print the right hand side */
735 if (ic->op == '+' || ic->op == '-')
737 /* PENDING: for re-target */
738 sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
741 ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
744 /* we reached the end */
745 sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
749 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
753 /*-----------------------------------------------------------------*/
754 /* regsInCommon - two operands have some registers in common */
755 /*-----------------------------------------------------------------*/
757 regsInCommon (operand * op1, operand * op2)
762 /* if they have registers in common */
763 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
766 sym1 = OP_SYMBOL (op1);
767 sym2 = OP_SYMBOL (op2);
769 if (sym1->nRegs == 0 || sym2->nRegs == 0)
772 for (i = 0; i < sym1->nRegs; i++)
778 for (j = 0; j < sym2->nRegs; j++)
783 if (sym2->regs[j] == sym1->regs[i])
791 /*-----------------------------------------------------------------*/
792 /* operandsEqu - equivalent */
793 /*-----------------------------------------------------------------*/
795 operandsEqu (operand * op1, operand * op2)
799 /* if they not symbols */
800 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
803 sym1 = OP_SYMBOL (op1);
804 sym2 = OP_SYMBOL (op2);
806 /* if both are itemps & one is spilt
807 and the other is not then false */
808 if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
809 sym1->isspilt != sym2->isspilt)
812 /* if they are the same */
816 if (strcmp (sym1->rname, sym2->rname) == 0)
820 /* if left is a tmp & right is not */
821 if (IS_ITEMP (op1) &&
824 (sym1->usl.spillLoc == sym2))
827 if (IS_ITEMP (op2) &&
831 (sym2->usl.spillLoc == sym1))
837 /*-----------------------------------------------------------------*/
838 /* sameRegs - two asmops have the same registers */
839 /*-----------------------------------------------------------------*/
841 sameRegs (asmop * aop1, asmop * aop2)
845 if (aop1->type == AOP_SFR ||
846 aop2->type == AOP_SFR)
852 if (aop1->type != AOP_REG ||
853 aop2->type != AOP_REG)
856 if (aop1->size != aop2->size)
859 for (i = 0; i < aop1->size; i++)
860 if (aop1->aopu.aop_reg[i] !=
861 aop2->aopu.aop_reg[i])
867 /*-----------------------------------------------------------------*/
868 /* aopOp - allocates an asmop for an operand : */
869 /*-----------------------------------------------------------------*/
871 aopOp (operand * op, iCode * ic, bool result, bool requires_a)
880 /* if this a literal */
881 if (IS_OP_LITERAL (op))
883 op->aop = aop = newAsmop (AOP_LIT);
884 aop->aopu.aop_lit = op->operand.valOperand;
885 aop->size = getSize (operandType (op));
889 /* if already has a asmop then continue */
895 /* if the underlying symbol has a aop */
896 if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
898 op->aop = OP_SYMBOL (op)->aop;
902 /* if this is a true symbol */
903 if (IS_TRUE_SYMOP (op))
905 op->aop = aopForSym (ic, OP_SYMBOL (op), result, requires_a);
909 /* this is a temporary : this has
915 e) can be a return use only */
917 sym = OP_SYMBOL (op);
919 /* if the type is a conditional */
920 if (sym->regType == REG_CND)
922 aop = op->aop = sym->aop = newAsmop (AOP_CRY);
927 /* if it is spilt then two situations
929 b) has a spill location */
930 if (sym->isspilt || sym->nRegs == 0)
932 /* rematerialize it NOW */
935 sym->aop = op->aop = aop =
937 aop->size = getSize (sym->type);
944 aop = op->aop = sym->aop = newAsmop (AOP_STR);
945 aop->size = getSize (sym->type);
946 for (i = 0; i < 4; i++)
947 aop->aopu.aop_str[i] = _fReturn[i];
953 if (sym->accuse == ACCUSE_A)
955 aop = op->aop = sym->aop = newAsmop (AOP_ACC);
956 aop->size = getSize (sym->type);
957 wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
959 aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
961 else if (sym->accuse == ACCUSE_SCRATCH)
963 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
964 aop->size = getSize (sym->type);
965 wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
966 aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
967 aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
969 else if (sym->accuse == ACCUSE_IY)
971 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
972 aop->size = getSize (sym->type);
973 wassertl(aop->size <= 2, "Internal error: Caching in IY, but too big to fit in IY");
974 aop->aopu.aop_str[0] = _pairs[PAIR_IY].l;
975 aop->aopu.aop_str[1] = _pairs[PAIR_IY].h;
979 wassertl (0, "Marked as being allocated into A or HL but is actually in neither");
984 /* else spill location */
985 if (sym->usl.spillLoc && getSize(sym->type) != getSize(sym->usl.spillLoc->type)) {
986 /* force a new aop if sizes differ */
987 sym->usl.spillLoc->aop = NULL;
989 sym->aop = op->aop = aop =
990 aopForSym (ic, sym->usl.spillLoc, result, requires_a);
991 wassertl (aop->size >= getSize (sym->type), "Operand doesn't fit in the spill location");
992 aop->size = getSize (sym->type);
996 /* must be in a register */
997 sym->aop = op->aop = aop = newAsmop (AOP_REG);
998 aop->size = sym->nRegs;
999 for (i = 0; i < sym->nRegs; i++)
1000 aop->aopu.aop_reg[i] = sym->regs[i];
1003 /*-----------------------------------------------------------------*/
1004 /* freeAsmop - free up the asmop given to an operand */
1005 /*----------------------------------------------------------------*/
1007 freeAsmop (operand * op, asmop * aaop, iCode * ic)
1024 if (aop->type == AOP_PAIRPTR && IS_Z80 && aop->aopu.aop_pairId == PAIR_DE)
1026 _pop (aop->aopu.aop_pairId);
1030 /* all other cases just dealloc */
1036 OP_SYMBOL (op)->aop = NULL;
1037 /* if the symbol has a spill */
1039 SPIL_LOC (op)->aop = NULL;
1046 isLitWord (asmop * aop)
1048 /* if (aop->size != 2)
1061 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
1065 /* depending on type */
1071 /* PENDING: for re-target */
1074 tsprintf (s, "!hashedstr + %d", aop->aopu.aop_immd, offset);
1076 else if (offset == 0)
1078 tsprintf (s, "%s", aop->aopu.aop_immd);
1082 tsprintf (s, "%s + %d", aop->aopu.aop_immd, offset);
1084 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1088 value *val = aop->aopu.aop_lit;
1089 /* if it is a float then it gets tricky */
1090 /* otherwise it is fairly simple */
1091 if (!IS_FLOAT (val->type))
1093 unsigned long v = (unsigned long) floatFromVal (val);
1099 else if (offset == 0)
1105 wassertl(0, "Encountered an invalid offset while fetching a literal");
1109 tsprintf (buffer, "!immedword", v);
1111 tsprintf (buffer, "!constword", v);
1113 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1124 /* it is type float */
1125 fl.f = (float) floatFromVal (val);
1128 i = fl.c[3-offset] | (fl.c[3-offset-1]<<8);
1130 i = fl.c[offset] | (fl.c[offset+1]<<8);
1133 tsprintf (buffer, "!immedword", i);
1135 tsprintf (buffer, "!constword", i);
1137 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1146 aopGetWord (asmop * aop, int offset)
1148 return aopGetLitWordLong (aop, offset, TRUE);
1152 isPtr (const char *s)
1154 if (!strcmp (s, "hl"))
1156 if (!strcmp (s, "ix"))
1158 if (!strcmp (s, "iy"))
1164 adjustPair (const char *pair, int *pold, int new)
1170 emit2 ("inc %s", pair);
1175 emit2 ("dec %s", pair);
1183 spillPair (PAIR_HL);
1184 spillPair (PAIR_IY);
1188 requiresHL (asmop * aop)
1204 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1206 const char *l, *base;
1207 const char *pair = _pairs[pairId].name;
1208 l = aopGetLitWordLong (left, offset, FALSE);
1209 base = aopGetLitWordLong (left, 0, FALSE);
1210 wassert (l && pair && base);
1214 if (pairId == PAIR_HL || pairId == PAIR_IY)
1216 if (_G.pairs[pairId].last_type == left->type)
1218 if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1220 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1222 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1225 if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
1232 _G.pairs[pairId].last_type = left->type;
1233 _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1234 _G.pairs[pairId].offset = offset;
1236 /* Both a lit on the right and a true symbol on the left */
1237 emit2 ("ld %s,!hashedstr", pair, l);
1241 makeFreePairId (iCode *ic, bool *pisUsed)
1247 if (!bitVectBitValue (ic->rMask, B_IDX) && !bitVectBitValue(ic->rMask, C_IDX))
1251 else if (IS_Z80 && !bitVectBitValue (ic->rMask, D_IDX) && !bitVectBitValue(ic->rMask, E_IDX))
1269 fetchPairLong (PAIR_ID pairId, asmop * aop, iCode *ic, int offset)
1271 /* if this is remateriazable */
1272 if (isLitWord (aop)) {
1273 fetchLitPair (pairId, aop, offset);
1277 if (getPairId (aop) == pairId)
1281 /* we need to get it byte by byte */
1282 else if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1283 aopGet (aop, offset, FALSE);
1284 switch (aop->size - offset) {
1286 emit2 ("ld l,!*hl");
1287 emit2 ("ld h,!immedbyte", 0);
1290 // PENDING: Requires that you are only fetching two bytes.
1293 emit2 ("ld h,!*hl");
1297 wassertl (0, "Attempted to fetch too much data into HL");
1301 else if (IS_Z80 && aop->type == AOP_IY) {
1302 /* Instead of fetching relative to IY, just grab directly
1303 from the address IY refers to */
1304 char *l = aopGetLitWordLong (aop, offset, FALSE);
1306 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1308 if (aop->size < 2) {
1309 emit2("ld %s,!zero", _pairs[pairId].h);
1312 else if (pairId == PAIR_IY)
1316 emit2 ("push %s", _pairs[getPairId(aop)].name);
1322 PAIR_ID id = makeFreePairId (ic, &isUsed);
1325 /* Can't load into parts, so load into HL then exchange. */
1326 emit2 ("ld %s,%s", _pairs[id].l, aopGet (aop, offset, FALSE));
1327 emit2 ("ld %s,%s", _pairs[id].h, aopGet (aop, offset + 1, FALSE));
1328 emit2 ("push %s", _pairs[id].name);
1336 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1337 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1339 /* PENDING: check? */
1340 if (pairId == PAIR_HL)
1341 spillPair (PAIR_HL);
1346 fetchPair (PAIR_ID pairId, asmop * aop)
1348 fetchPairLong (pairId, aop, NULL, 0);
1352 fetchHL (asmop * aop)
1354 fetchPair (PAIR_HL, aop);
1358 setupPairFromSP (PAIR_ID id, int offset)
1360 wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
1362 if (offset < INT8MIN || offset > INT8MAX)
1364 emit2 ("ld hl,!immedword", offset);
1365 emit2 ("add hl,sp");
1369 emit2 ("!ldahlsp", offset);
1374 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1379 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
1380 fetchLitPair (pairId, aop, 0);
1384 wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
1386 fetchLitPair (pairId, aop, offset);
1387 _G.pairs[pairId].offset = offset;
1391 wassertl (IS_Z80, "Only the Z80 has an extended stack");
1392 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
1395 int offset = aop->aopu.aop_stk + _G.stack.offset;
1397 if (_G.pairs[pairId].last_type == aop->type &&
1398 _G.pairs[pairId].offset == offset)
1404 /* PENDING: Do this better. */
1405 sprintf (buffer, "%d", offset + _G.stack.pushed);
1406 emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
1407 emit2 ("add %s,sp", _pairs[pairId].name);
1408 _G.pairs[pairId].last_type = aop->type;
1409 _G.pairs[pairId].offset = offset;
1416 /* Doesnt include _G.stack.pushed */
1417 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1419 if (aop->aopu.aop_stk > 0)
1421 abso += _G.stack.param_offset;
1423 assert (pairId == PAIR_HL);
1424 /* In some cases we can still inc or dec hl */
1425 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1427 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1431 setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
1433 _G.pairs[pairId].offset = abso;
1438 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
1444 _G.pairs[pairId].last_type = aop->type;
1450 emit2 ("!tlabeldef", key);
1454 /*-----------------------------------------------------------------*/
1455 /* aopGet - for fetching value of the aop */
1456 /*-----------------------------------------------------------------*/
1458 aopGet (asmop * aop, int offset, bool bit16)
1462 /* offset is greater than size then zero */
1463 /* PENDING: this seems a bit screwed in some pointer cases. */
1464 if (offset > (aop->size - 1) &&
1465 aop->type != AOP_LIT)
1467 tsprintf (s, "!zero");
1468 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1471 /* depending on type */
1475 /* PENDING: re-target */
1477 tsprintf (s, "!immedwords", aop->aopu.aop_immd);
1482 tsprintf (s, "!bankimmeds", aop->aopu.aop_immd);
1485 tsprintf (s, "!msbimmeds", aop->aopu.aop_immd);
1488 tsprintf (s, "!lsbimmeds", aop->aopu.aop_immd);
1491 wassertl (0, "Fetching from beyond the limits of an immediate value.");
1494 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1498 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1501 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1505 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1508 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1511 return aop->aopu.aop_reg[offset]->name;
1515 setupPair (PAIR_HL, aop, offset);
1516 tsprintf (s, "!*hl");
1518 return traceAlloc(&_G.trace.aops, Safe_strdup (s));
1522 setupPair (PAIR_IY, aop, offset);
1523 tsprintf (s, "!*iyx", offset);
1525 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1529 setupPair (PAIR_IY, aop, offset);
1530 tsprintf (s, "!*iyx", offset, offset);
1532 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1537 setupPair (PAIR_HL, aop, offset);
1538 tsprintf (s, "!*hl");
1542 if (aop->aopu.aop_stk >= 0)
1543 offset += _G.stack.param_offset;
1544 tsprintf (s, "!*ixx", aop->aopu.aop_stk + offset);
1547 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1550 wassertl (0, "Tried to fetch from a bit variable");
1559 tsprintf(s, "!zero");
1560 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1564 wassert (offset < 2);
1565 return aop->aopu.aop_str[offset];
1568 return aopLiteral (aop->aopu.aop_lit, offset);
1572 unsigned long v = aop->aopu.aop_simplelit;
1575 tsprintf (s, "!immedbyte", (unsigned int) v & 0xff);
1577 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1581 return aop->aopu.aop_str[offset];
1584 setupPair (aop->aopu.aop_pairId, aop, offset);
1585 sprintf (s, "(%s)", _pairs[aop->aopu.aop_pairId].name);
1587 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1592 wassertl (0, "aopget got unsupported aop->type");
1597 isRegString (const char *s)
1599 if (!strcmp (s, "b") ||
1611 isConstant (const char *s)
1613 /* This is a bit of a hack... */
1614 return (*s == '#' || *s == '$');
1618 canAssignToPtr (const char *s)
1620 if (isRegString (s))
1627 /*-----------------------------------------------------------------*/
1628 /* aopPut - puts a string for a aop */
1629 /*-----------------------------------------------------------------*/
1631 aopPut (asmop * aop, const char *s, int offset)
1635 if (aop->size && offset > (aop->size - 1))
1637 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1638 "aopPut got offset > aop->size");
1643 tsprintf(buffer2, s);
1646 /* will assign value to value */
1647 /* depending on where it is ofcourse */
1653 if (strcmp (s, "a"))
1654 emit2 ("ld a,%s", s);
1655 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1660 if (strcmp (s, "a"))
1661 emit2 ("ld a,%s", s);
1662 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1666 if (!strcmp (s, "!*hl"))
1667 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1670 aop->aopu.aop_reg[offset]->name, s);
1675 if (!canAssignToPtr (s))
1677 emit2 ("ld a,%s", s);
1678 setupPair (PAIR_IY, aop, offset);
1679 emit2 ("ld !*iyx,a", offset);
1683 setupPair (PAIR_IY, aop, offset);
1684 emit2 ("ld !*iyx,%s", offset, s);
1690 /* PENDING: for re-target */
1691 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1693 emit2 ("ld a,!*hl");
1696 setupPair (PAIR_HL, aop, offset);
1698 emit2 ("ld !*hl,%s", s);
1703 if (!canAssignToPtr (s))
1705 emit2 ("ld a,%s", s);
1706 setupPair (PAIR_IY, aop, offset);
1707 emit2 ("ld !*iyx,a", offset);
1711 setupPair (PAIR_IY, aop, offset);
1712 emit2 ("ld !*iyx,%s", offset, s);
1719 /* PENDING: re-target */
1720 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1722 emit2 ("ld a,!*hl");
1725 setupPair (PAIR_HL, aop, offset);
1726 if (!canAssignToPtr (s))
1728 emit2 ("ld a,%s", s);
1729 emit2 ("ld !*hl,a");
1732 emit2 ("ld !*hl,%s", s);
1736 if (aop->aopu.aop_stk >= 0)
1737 offset += _G.stack.param_offset;
1738 if (!canAssignToPtr (s))
1740 emit2 ("ld a,%s", s);
1741 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
1745 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
1751 /* if bit variable */
1752 if (!aop->aopu.aop_dir)
1759 /* In bit space but not in C - cant happen */
1760 wassertl (0, "Tried to write into a bit variable");
1766 if (strcmp (aop->aopu.aop_str[offset], s))
1768 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1774 if (!offset && (strcmp (s, "acc") == 0))
1778 wassertl (0, "Tried to access past the end of A");
1782 if (strcmp (aop->aopu.aop_str[offset], s))
1783 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1788 wassert (offset < 2);
1789 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1793 setupPair (aop->aopu.aop_pairId, aop, offset);
1794 emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
1798 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1799 "aopPut got unsupported aop->type");
1804 #define AOP(op) op->aop
1805 #define AOP_TYPE(op) AOP(op)->type
1806 #define AOP_SIZE(op) AOP(op)->size
1807 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
1810 commitPair (asmop * aop, PAIR_ID id)
1812 /* PENDING: Verify this. */
1813 if (id == PAIR_HL && requiresHL (aop) && IS_GB)
1817 aopPut (aop, "a", 0);
1818 aopPut (aop, "d", 1);
1823 if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
1825 char *l = aopGetLitWordLong (aop, 0, FALSE);
1828 emit2 ("ld (%s),%s", l, _pairs[id].name);
1832 aopPut (aop, _pairs[id].l, 0);
1833 aopPut (aop, _pairs[id].h, 1);
1838 /*-----------------------------------------------------------------*/
1839 /* getDataSize - get the operand data size */
1840 /*-----------------------------------------------------------------*/
1842 getDataSize (operand * op)
1845 size = AOP_SIZE (op);
1849 wassertl (0, "Somehow got a three byte data pointer");
1854 /*-----------------------------------------------------------------*/
1855 /* movLeft2Result - move byte from left to result */
1856 /*-----------------------------------------------------------------*/
1858 movLeft2Result (operand * left, int offl,
1859 operand * result, int offr, int sign)
1863 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
1865 l = aopGet (AOP (left), offl, FALSE);
1869 aopPut (AOP (result), l, offr);
1873 if (getDataSize (left) == offl + 1)
1875 emit2 ("ld a,%s", l);
1876 aopPut (AOP (result), "a", offr);
1883 movLeft2ResultLong (operand * left, int offl,
1884 operand * result, int offr, int sign,
1889 movLeft2Result (left, offl, result, offr, sign);
1893 wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
1894 wassertl (size == 2, "Only implemented for two bytes or one");
1896 if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
1898 emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
1899 emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
1902 else if ( getPairId ( AOP (result)) == PAIR_IY)
1904 PAIR_ID id = getPairId (AOP (left));
1905 if (id != PAIR_INVALID)
1907 emit2("push %s", _pairs[id].name);
1918 movLeft2Result (left, offl, result, offr, sign);
1919 movLeft2Result (left, offl+1, result, offr+1, sign);
1924 /** Put Acc into a register set
1927 outAcc (operand * result)
1930 size = getDataSize (result);
1933 aopPut (AOP (result), "a", 0);
1936 /* unsigned or positive */
1939 aopPut (AOP (result), "!zero", offset++);
1944 /** Take the value in carry and put it into a register
1947 outBitCLong (operand * result, bool swap_sense)
1949 /* if the result is bit */
1950 if (AOP_TYPE (result) == AOP_CRY)
1952 wassertl (0, "Tried to write carry to a bit");
1956 emit2 ("ld a,!zero");
1959 emit2 ("xor a,!immedbyte", 1);
1965 outBitC (operand * result)
1967 outBitCLong (result, FALSE);
1970 /*-----------------------------------------------------------------*/
1971 /* toBoolean - emit code for orl a,operator(sizeop) */
1972 /*-----------------------------------------------------------------*/
1974 _toBoolean (operand * oper)
1976 int size = AOP_SIZE (oper);
1980 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
1983 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
1987 if (AOP (oper)->type != AOP_ACC)
1990 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
1995 /*-----------------------------------------------------------------*/
1996 /* genNotFloat - generates not for float operations */
1997 /*-----------------------------------------------------------------*/
1999 genNotFloat (operand * op, operand * res)
2004 emitDebug ("; genNotFloat");
2006 /* we will put 127 in the first byte of
2008 aopPut (AOP (res), "!immedbyte", 0x7F);
2009 size = AOP_SIZE (op) - 1;
2012 _moveA (aopGet (op->aop, offset++, FALSE));
2016 emit2 ("or a,%s", aopGet (op->aop, offset++, FALSE));
2019 tlbl = newiTempLabel (NULL);
2020 aopPut (res->aop, "!one", 1);
2021 emit2 ("!shortjp z !tlabel", tlbl->key + 100);
2022 aopPut (res->aop, "!zero", 1);
2024 emitLabel(tlbl->key + 100);
2026 size = res->aop->size - 2;
2028 /* put zeros in the rest */
2030 aopPut (res->aop, "!zero", offset++);
2033 /*-----------------------------------------------------------------*/
2034 /* genNot - generate code for ! operation */
2035 /*-----------------------------------------------------------------*/
2039 sym_link *optype = operandType (IC_LEFT (ic));
2041 /* assign asmOps to operand & result */
2042 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
2043 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2045 /* if in bit space then a special case */
2046 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2048 wassertl (0, "Tried to negate a bit");
2051 /* if type float then do float */
2052 if (IS_FLOAT (optype))
2054 genNotFloat (IC_LEFT (ic), IC_RESULT (ic));
2058 _toBoolean (IC_LEFT (ic));
2063 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
2064 emit2 ("sub a,!one");
2065 outBitC (IC_RESULT (ic));
2068 /* release the aops */
2069 freeAsmop (IC_LEFT (ic), NULL, ic);
2070 freeAsmop (IC_RESULT (ic), NULL, ic);
2073 /*-----------------------------------------------------------------*/
2074 /* genCpl - generate code for complement */
2075 /*-----------------------------------------------------------------*/
2083 /* assign asmOps to operand & result */
2084 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2085 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2087 /* if both are in bit space then
2089 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2090 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2092 wassertl (0, "Left and the result are in bit space");
2095 size = AOP_SIZE (IC_RESULT (ic));
2098 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2101 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2104 /* release the aops */
2105 freeAsmop (IC_LEFT (ic), NULL, ic);
2106 freeAsmop (IC_RESULT (ic), NULL, ic);
2110 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
2117 store de into result
2122 store de into result
2124 const char *first = isAdd ? "add" : "sub";
2125 const char *later = isAdd ? "adc" : "sbc";
2127 wassertl (IS_GB, "Code is only relevent to the gbz80");
2128 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
2130 fetchPair (PAIR_DE, left);
2133 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
2136 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2139 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2140 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2142 fetchPairLong (PAIR_DE, left, NULL, MSB24);
2143 aopGet (right, MSB24, FALSE);
2147 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2150 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2152 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2153 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2157 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2159 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2162 /*-----------------------------------------------------------------*/
2163 /* genUminusFloat - unary minus for floating points */
2164 /*-----------------------------------------------------------------*/
2166 genUminusFloat (operand * op, operand * result)
2168 int size, offset = 0;
2170 emitDebug("; genUminusFloat");
2172 /* for this we just need to flip the
2173 first it then copy the rest in place */
2174 size = AOP_SIZE (op) - 1;
2176 _moveA(aopGet (AOP (op), MSB32, FALSE));
2178 emit2("xor a,!immedbyte", 0x80);
2179 aopPut (AOP (result), "a", MSB32);
2183 aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2188 /*-----------------------------------------------------------------*/
2189 /* genUminus - unary minus code generation */
2190 /*-----------------------------------------------------------------*/
2192 genUminus (iCode * ic)
2195 sym_link *optype, *rtype;
2198 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2199 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2201 /* if both in bit space then special
2203 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2204 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2206 wassertl (0, "Left and right are in bit space");
2210 optype = operandType (IC_LEFT (ic));
2211 rtype = operandType (IC_RESULT (ic));
2213 /* if float then do float stuff */
2214 if (IS_FLOAT (optype))
2216 genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2220 /* otherwise subtract from zero */
2221 size = AOP_SIZE (IC_LEFT (ic));
2223 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2225 /* Create a new asmop with value zero */
2226 asmop *azero = newAsmop (AOP_SIMPLELIT);
2227 azero->aopu.aop_simplelit = 0;
2229 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2237 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2238 emit2 ("ld a,!zero");
2239 emit2 ("sbc a,%s", l);
2240 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2243 /* if any remaining bytes in the result */
2244 /* we just need to propagate the sign */
2245 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2250 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2254 /* release the aops */
2255 freeAsmop (IC_LEFT (ic), NULL, ic);
2256 freeAsmop (IC_RESULT (ic), NULL, ic);
2259 /*-----------------------------------------------------------------*/
2260 /* assignResultValue - */
2261 /*-----------------------------------------------------------------*/
2263 assignResultValue (operand * oper)
2265 int size = AOP_SIZE (oper);
2268 wassertl (size <= 4, "Got a result that is bigger than four bytes");
2269 topInA = requiresHL (AOP (oper));
2271 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2273 /* We do it the hard way here. */
2275 aopPut (AOP (oper), _fReturn[0], 0);
2276 aopPut (AOP (oper), _fReturn[1], 1);
2278 aopPut (AOP (oper), _fReturn[0], 2);
2279 aopPut (AOP (oper), _fReturn[1], 3);
2285 aopPut (AOP (oper), _fReturn[size], size);
2290 /** Simple restore that doesn't take into account what is used in the
2294 _restoreRegsAfterCall(void)
2296 if (_G.stack.pushedDE)
2299 _G.stack.pushedDE = FALSE;
2301 if (_G.stack.pushedBC)
2304 _G.stack.pushedBC = FALSE;
2306 _G.saves.saved = FALSE;
2310 _saveRegsForCall(iCode *ic, int sendSetSize)
2313 o Stack parameters are pushed before this function enters
2314 o DE and BC may be used in this function.
2315 o HL and DE may be used to return the result.
2316 o HL and DE may be used to send variables.
2317 o DE and BC may be used to store the result value.
2318 o HL may be used in computing the sent value of DE
2319 o The iPushes for other parameters occur before any addSets
2321 Logic: (to be run inside the first iPush or if none, before sending)
2322 o Compute if DE and/or BC are in use over the call
2323 o Compute if DE is used in the send set
2324 o Compute if DE and/or BC are used to hold the result value
2325 o If (DE is used, or in the send set) and is not used in the result, push.
2326 o If BC is used and is not in the result, push
2328 o If DE is used in the send set, fetch
2329 o If HL is used in the send set, fetch
2333 if (_G.saves.saved == FALSE) {
2334 bool deInUse, bcInUse;
2336 bool bcInRet = FALSE, deInRet = FALSE;
2339 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
2341 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2342 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2344 deSending = (sendSetSize > 1);
2346 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2348 if (bcInUse && bcInRet == FALSE) {
2350 _G.stack.pushedBC = TRUE;
2352 if (deInUse && deInRet == FALSE) {
2354 _G.stack.pushedDE = TRUE;
2357 _G.saves.saved = TRUE;
2360 /* Already saved. */
2364 /*-----------------------------------------------------------------*/
2365 /* genIpush - genrate code for pushing this gets a little complex */
2366 /*-----------------------------------------------------------------*/
2368 genIpush (iCode * ic)
2370 int size, offset = 0;
2373 /* if this is not a parm push : ie. it is spill push
2374 and spill push is always done on the local stack */
2377 wassertl(0, "Encountered an unsupported spill push.");
2381 if (_G.saves.saved == FALSE) {
2382 /* Caller saves, and this is the first iPush. */
2383 /* Scan ahead until we find the function that we are pushing parameters to.
2384 Count the number of addSets on the way to figure out what registers
2385 are used in the send set.
2388 iCode *walk = ic->next;
2391 if (walk->op == SEND) {
2394 else if (walk->op == CALL || walk->op == PCALL) {
2403 _saveRegsForCall(walk, nAddSets);
2406 /* Already saved by another iPush. */
2409 /* then do the push */
2410 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2412 size = AOP_SIZE (IC_LEFT (ic));
2414 if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2416 _G.stack.pushed += 2;
2417 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2423 fetchHL (AOP (IC_LEFT (ic)));
2425 spillPair (PAIR_HL);
2426 _G.stack.pushed += 2;
2431 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
2433 spillPair (PAIR_HL);
2434 _G.stack.pushed += 2;
2435 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
2437 spillPair (PAIR_HL);
2438 _G.stack.pushed += 2;
2444 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2446 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2448 emit2 ("ld a,(%s)", l);
2452 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2453 emit2 ("ld a,%s", l);
2461 freeAsmop (IC_LEFT (ic), NULL, ic);
2464 /*-----------------------------------------------------------------*/
2465 /* genIpop - recover the registers: can happen only for spilling */
2466 /*-----------------------------------------------------------------*/
2468 genIpop (iCode * ic)
2473 /* if the temp was not pushed then */
2474 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2477 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2478 size = AOP_SIZE (IC_LEFT (ic));
2479 offset = (size - 1);
2480 if (isPair (AOP (IC_LEFT (ic))))
2482 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2490 spillPair (PAIR_HL);
2491 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2495 freeAsmop (IC_LEFT (ic), NULL, ic);
2498 /* This is quite unfortunate */
2500 setArea (int inHome)
2503 static int lastArea = 0;
2505 if (_G.in_home != inHome) {
2507 const char *sz = port->mem.code_name;
2508 port->mem.code_name = "HOME";
2509 emit2("!area", CODE_NAME);
2510 port->mem.code_name = sz;
2513 emit2("!area", CODE_NAME); */
2514 _G.in_home = inHome;
2525 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2529 symbol *sym = OP_SYMBOL (op);
2531 if (sym->isspilt || sym->nRegs == 0)
2534 aopOp (op, ic, FALSE, FALSE);
2537 if (aop->type == AOP_REG)
2540 for (i = 0; i < aop->size; i++)
2542 if (pairId == PAIR_DE)
2544 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2545 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2547 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2550 else if (pairId == PAIR_BC)
2552 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2553 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2555 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2565 freeAsmop (IC_LEFT (ic), NULL, ic);
2569 /** Emit the code for a call statement
2572 emitCall (iCode * ic, bool ispcall)
2574 sym_link *dtype = operandType (IC_LEFT (ic));
2576 /* if caller saves & we have not saved then */
2582 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2584 /* if send set is not empty then assign */
2589 int nSend = elementsInSet(_G.sendSet);
2590 bool swapped = FALSE;
2592 int _z80_sendOrder[] = {
2597 /* Check if the parameters are swapped. If so route through hl instead. */
2598 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2600 sic = setFirstItem(_G.sendSet);
2601 sic = setNextItem(_G.sendSet);
2603 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2604 /* The second send value is loaded from one the one that holds the first
2605 send, i.e. it is overwritten. */
2606 /* Cache the first in HL, and load the second from HL instead. */
2607 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2608 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2614 for (sic = setFirstItem (_G.sendSet); sic;
2615 sic = setNextItem (_G.sendSet))
2618 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2620 size = AOP_SIZE (IC_LEFT (sic));
2621 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2622 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2624 // PENDING: Mild hack
2625 if (swapped == TRUE && send == 1) {
2627 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2630 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2632 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2635 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2639 freeAsmop (IC_LEFT (sic), NULL, sic);
2646 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2648 werror (W_INDIR_BANKED);
2650 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2652 if (isLitWord (AOP (IC_LEFT (ic))))
2654 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2658 symbol *rlbl = newiTempLabel (NULL);
2659 spillPair (PAIR_HL);
2660 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2662 _G.stack.pushed += 2;
2664 fetchHL (AOP (IC_LEFT (ic)));
2666 emit2 ("!tlabeldef", (rlbl->key + 100));
2667 _G.stack.pushed -= 2;
2669 freeAsmop (IC_LEFT (ic), NULL, ic);
2673 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2674 OP_SYMBOL (IC_LEFT (ic))->rname :
2675 OP_SYMBOL (IC_LEFT (ic))->name;
2676 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2678 emit2 ("call banked_call");
2679 emit2 ("!dws", name);
2680 emit2 ("!dw !bankimmeds", name);
2685 emit2 ("call %s", name);
2690 /* Mark the regsiters as restored. */
2691 _G.saves.saved = FALSE;
2693 /* if we need assign a result value */
2694 if ((IS_ITEMP (IC_RESULT (ic)) &&
2695 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2696 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2697 IS_TRUE_SYMOP (IC_RESULT (ic)))
2700 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2702 assignResultValue (IC_RESULT (ic));
2704 freeAsmop (IC_RESULT (ic), NULL, ic);
2707 /* adjust the stack for parameters if required */
2710 int i = ic->parmBytes;
2712 _G.stack.pushed -= i;
2715 emit2 ("!ldaspsp", i);
2722 emit2 ("ld iy,#%d", i);
2723 emit2 ("add iy,sp");
2743 if (_G.stack.pushedDE)
2745 bool dInRet = bitVectBitValue(ic->rUsed, D_IDX);
2746 bool eInRet = bitVectBitValue(ic->rUsed, E_IDX);
2748 if (dInRet && eInRet)
2750 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
2754 /* Only restore E */
2761 /* Only restore D */
2769 _G.stack.pushedDE = FALSE;
2772 if (_G.stack.pushedBC)
2774 bool bInRet = bitVectBitValue(ic->rUsed, B_IDX);
2775 bool cInRet = bitVectBitValue(ic->rUsed, C_IDX);
2777 if (bInRet && cInRet)
2779 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
2783 /* Only restore C */
2790 /* Only restore B */
2798 _G.stack.pushedBC = FALSE;
2802 /*-----------------------------------------------------------------*/
2803 /* genCall - generates a call statement */
2804 /*-----------------------------------------------------------------*/
2806 genCall (iCode * ic)
2808 emitCall (ic, FALSE);
2811 /*-----------------------------------------------------------------*/
2812 /* genPcall - generates a call by pointer statement */
2813 /*-----------------------------------------------------------------*/
2815 genPcall (iCode * ic)
2817 emitCall (ic, TRUE);
2820 /*-----------------------------------------------------------------*/
2821 /* resultRemat - result is rematerializable */
2822 /*-----------------------------------------------------------------*/
2824 resultRemat (iCode * ic)
2826 if (SKIP_IC (ic) || ic->op == IFX)
2829 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2831 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2832 if (sym->remat && !POINTER_SET (ic))
2839 extern set *publics;
2841 /*-----------------------------------------------------------------*/
2842 /* genFunction - generated code for function entry */
2843 /*-----------------------------------------------------------------*/
2845 genFunction (iCode * ic)
2847 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2851 bool bcInUse = FALSE;
2852 bool deInUse = FALSE;
2855 setArea (IFFUNC_NONBANKED (sym->type));
2857 /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
2860 _G.receiveOffset = 0;
2862 /* Record the last function name for debugging. */
2863 _G.lastFunctionName = sym->rname;
2865 /* Create the function header */
2866 emit2 ("!functionheader", sym->name);
2867 /* PENDING: portability. */
2868 emit2 ("__%s_start:", sym->rname);
2869 emit2 ("!functionlabeldef", sym->rname);
2871 if (options.profile)
2873 emit2 ("!profileenter");
2876 ftype = operandType (IC_LEFT (ic));
2878 /* if critical function then turn interrupts off */
2879 if (IFFUNC_ISCRITICAL (ftype))
2882 /* if this is an interrupt service routine then save all potentially used registers. */
2883 if (IFFUNC_ISISR (sym->type))
2888 /* PENDING: callee-save etc */
2890 _G.stack.param_offset = 0;
2893 /* Detect which registers are used. */
2897 for (i = 0; i < sym->regsUsed->size; i++)
2899 if (bitVectBitValue (sym->regsUsed, i))
2913 /* Other systems use DE as a temporary. */
2924 _G.stack.param_offset += 2;
2927 _G.stack.pushedBC = bcInUse;
2932 _G.stack.param_offset += 2;
2935 _G.stack.pushedDE = deInUse;
2938 /* adjust the stack for the function */
2939 _G.stack.last = sym->stack;
2941 if (sym->stack && IS_GB && sym->stack > -INT8MIN)
2942 emit2 ("!enterxl", sym->stack);
2943 else if (sym->stack)
2944 emit2 ("!enterx", sym->stack);
2947 _G.stack.offset = sym->stack;
2950 /*-----------------------------------------------------------------*/
2951 /* genEndFunction - generates epilogue for functions */
2952 /*-----------------------------------------------------------------*/
2954 genEndFunction (iCode * ic)
2956 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2958 if (IFFUNC_ISISR (sym->type))
2960 wassertl (0, "Tried to close an interrupt support function");
2964 if (IFFUNC_ISCRITICAL (sym->type))
2967 /* PENDING: calleeSave */
2969 if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
2971 emit2 ("!leavexl", _G.stack.offset);
2973 else if (_G.stack.offset)
2975 emit2 ("!leavex", _G.stack.offset);
2983 if (_G.stack.pushedDE)
2986 _G.stack.pushedDE = FALSE;
2989 if (_G.stack.pushedDE)
2992 _G.stack.pushedDE = FALSE;
2996 if (options.profile)
2998 emit2 ("!profileexit");
3002 /* Both baned and non-banked just ret */
3005 /* PENDING: portability. */
3006 emit2 ("__%s_end:", sym->rname);
3008 _G.flushStatics = 1;
3009 _G.stack.pushed = 0;
3010 _G.stack.offset = 0;
3013 /*-----------------------------------------------------------------*/
3014 /* genRet - generate code for return statement */
3015 /*-----------------------------------------------------------------*/
3020 /* Errk. This is a hack until I can figure out how
3021 to cause dehl to spill on a call */
3022 int size, offset = 0;
3024 /* if we have no return value then
3025 just generate the "ret" */
3029 /* we have something to return then
3030 move the return value into place */
3031 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3032 size = AOP_SIZE (IC_LEFT (ic));
3034 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3038 emit2 ("ld de,%s", l);
3042 emit2 ("ld hl,%s", l);
3047 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3049 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3050 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3056 l = aopGet (AOP (IC_LEFT (ic)), offset,
3058 if (strcmp (_fReturn[offset], l))
3059 emit2 ("ld %s,%s", _fReturn[offset++], l);
3063 freeAsmop (IC_LEFT (ic), NULL, ic);
3066 /* generate a jump to the return label
3067 if the next is not the return statement */
3068 if (!(ic->next && ic->next->op == LABEL &&
3069 IC_LABEL (ic->next) == returnLabel))
3071 emit2 ("jp !tlabel", returnLabel->key + 100);
3074 /*-----------------------------------------------------------------*/
3075 /* genLabel - generates a label */
3076 /*-----------------------------------------------------------------*/
3078 genLabel (iCode * ic)
3080 /* special case never generate */
3081 if (IC_LABEL (ic) == entryLabel)
3084 emitLabel (IC_LABEL (ic)->key + 100);
3087 /*-----------------------------------------------------------------*/
3088 /* genGoto - generates a ljmp */
3089 /*-----------------------------------------------------------------*/
3091 genGoto (iCode * ic)
3093 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3096 /*-----------------------------------------------------------------*/
3097 /* genPlusIncr :- does addition with increment if possible */
3098 /*-----------------------------------------------------------------*/
3100 genPlusIncr (iCode * ic)
3102 unsigned int icount;
3103 unsigned int size = getDataSize (IC_RESULT (ic));
3104 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3106 /* will try to generate an increment */
3107 /* if the right side is not a literal
3109 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3112 emitDebug ("; genPlusIncr");
3114 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3116 /* If result is a pair */
3117 if (resultId != PAIR_INVALID)
3119 if (isLitWord (AOP (IC_LEFT (ic))))
3121 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3124 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3126 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3128 PAIR_ID freep = getFreePairId (ic);
3129 if (freep != PAIR_INVALID)
3131 fetchPair (freep, AOP (IC_RIGHT (ic)));
3132 emit2 ("add hl,%s", _pairs[freep].name);
3138 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3139 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3146 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3150 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3154 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3159 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3161 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3162 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3166 /* if the literal value of the right hand side
3167 is greater than 4 then it is not worth it */
3171 /* if increment 16 bits in register */
3172 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3178 symbol *tlbl = NULL;
3179 tlbl = newiTempLabel (NULL);
3182 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3185 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3188 emitLabel (tlbl->key + 100);
3192 /* if the sizes are greater than 1 then we cannot */
3193 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3194 AOP_SIZE (IC_LEFT (ic)) > 1)
3197 /* If the result is in a register then we can load then increment.
3199 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3201 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3204 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3209 /* we can if the aops of the left & result match or
3210 if they are in registers and the registers are the
3212 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3216 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3224 /*-----------------------------------------------------------------*/
3225 /* outBitAcc - output a bit in acc */
3226 /*-----------------------------------------------------------------*/
3228 outBitAcc (operand * result)
3230 symbol *tlbl = newiTempLabel (NULL);
3231 /* if the result is a bit */
3232 if (AOP_TYPE (result) == AOP_CRY)
3234 wassertl (0, "Tried to write A into a bit");
3238 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3239 emit2 ("ld a,!one");
3240 emitLabel (tlbl->key + 100);
3246 couldDestroyCarry (asmop *aop)
3250 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3259 shiftIntoPair (int idx, asmop *aop)
3261 PAIR_ID id = PAIR_INVALID;
3263 wassertl (IS_Z80, "Only implemented for the Z80");
3264 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3276 wassertl (0, "Internal error - hit default case");
3279 emitDebug ("; Shift into pair idx %u", idx);
3283 setupPair (PAIR_HL, aop, 0);
3287 setupPair (PAIR_IY, aop, 0);
3289 emit2 ("pop %s", _pairs[id].name);
3292 aop->type = AOP_PAIRPTR;
3293 aop->aopu.aop_pairId = id;
3294 _G.pairs[id].offset = 0;
3295 _G.pairs[id].last_type = aop->type;
3299 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
3301 wassert (left && right);
3305 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3307 shiftIntoPair (0, right);
3308 shiftIntoPair (1, result);
3310 else if (couldDestroyCarry (right))
3312 shiftIntoPair (0, right);
3314 else if (couldDestroyCarry (result))
3316 shiftIntoPair (0, result);
3325 /*-----------------------------------------------------------------*/
3326 /* genPlus - generates code for addition */
3327 /*-----------------------------------------------------------------*/
3329 genPlus (iCode * ic)
3331 int size, offset = 0;
3333 /* special cases :- */
3335 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3336 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3337 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3339 /* Swap the left and right operands if:
3341 if literal, literal on the right or
3342 if left requires ACC or right is already
3345 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3346 (AOP_NEEDSACC (IC_LEFT (ic))) ||
3347 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3349 operand *t = IC_RIGHT (ic);
3350 IC_RIGHT (ic) = IC_LEFT (ic);
3354 /* if both left & right are in bit
3356 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3357 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3360 wassertl (0, "Tried to add two bits");
3363 /* if left in bit space & right literal */
3364 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3365 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3367 /* Can happen I guess */
3368 wassertl (0, "Tried to add a bit to a literal");
3371 /* if I can do an increment instead
3372 of add then GOOD for ME */
3373 if (genPlusIncr (ic) == TRUE)
3376 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3378 size = getDataSize (IC_RESULT (ic));
3380 /* Special case when left and right are constant */
3381 if (isPair (AOP (IC_RESULT (ic))))
3384 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3385 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3387 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3393 sprintf (buffer, "#(%s + %s)", left, right);
3394 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3399 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3401 /* Fetch into HL then do the add */
3402 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3403 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3405 spillPair (PAIR_HL);
3407 if (left == PAIR_HL && right != PAIR_INVALID)
3409 emit2 ("add hl,%s", _pairs[right].name);
3412 else if (right == PAIR_HL && left != PAIR_INVALID)
3414 emit2 ("add hl,%s", _pairs[left].name);
3417 else if (right != PAIR_INVALID && right != PAIR_HL)
3419 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3420 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3423 else if (left != PAIR_INVALID && left != PAIR_HL)
3425 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3426 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3435 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3437 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3438 emit2 ("add hl,%s ; 2", getPairName (AOP (IC_RIGHT (ic))));
3440 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3445 ld hl,sp+n trashes C so we cant afford to do it during an
3446 add with stack based varibles. Worst case is:
3459 So you cant afford to load up hl if either left, right, or result
3460 is on the stack (*sigh*) The alt is:
3468 Combinations in here are:
3469 * If left or right are in bc then the loss is small - trap later
3470 * If the result is in bc then the loss is also small
3474 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3475 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3476 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3478 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3479 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3480 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3481 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3483 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3485 /* Swap left and right */
3486 operand *t = IC_RIGHT (ic);
3487 IC_RIGHT (ic) = IC_LEFT (ic);
3490 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3492 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3493 emit2 ("add hl,bc");
3497 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3498 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3499 emit2 ("add hl,de");
3501 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3507 /* Be paranoid on the GB with 4 byte variables due to how C
3508 can be trashed by lda hl,n(sp).
3510 _gbz80_emitAddSubLong (ic, TRUE);
3515 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3519 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3521 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3524 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3527 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3531 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3534 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3537 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3539 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3543 freeAsmop (IC_LEFT (ic), NULL, ic);
3544 freeAsmop (IC_RIGHT (ic), NULL, ic);
3545 freeAsmop (IC_RESULT (ic), NULL, ic);
3549 /*-----------------------------------------------------------------*/
3550 /* genMinusDec :- does subtraction with deccrement if possible */
3551 /*-----------------------------------------------------------------*/
3553 genMinusDec (iCode * ic)
3555 unsigned int icount;
3556 unsigned int size = getDataSize (IC_RESULT (ic));
3558 /* will try to generate an increment */
3559 /* if the right side is not a literal we cannot */
3560 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3563 /* if the literal value of the right hand side
3564 is greater than 4 then it is not worth it */
3565 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3568 size = getDataSize (IC_RESULT (ic));
3570 /* if decrement 16 bits in register */
3571 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3572 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3575 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3579 /* If result is a pair */
3580 if (isPair (AOP (IC_RESULT (ic))))
3582 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3584 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3588 /* if increment 16 bits in register */
3589 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3593 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3596 emit2 ("dec %s", _getTempPairName());
3599 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3605 /* if the sizes are greater than 1 then we cannot */
3606 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3607 AOP_SIZE (IC_LEFT (ic)) > 1)
3610 /* we can if the aops of the left & result match or if they are in
3611 registers and the registers are the same */
3612 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3615 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3622 /*-----------------------------------------------------------------*/
3623 /* genMinus - generates code for subtraction */
3624 /*-----------------------------------------------------------------*/
3626 genMinus (iCode * ic)
3628 int size, offset = 0;
3629 unsigned long lit = 0L;
3631 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3632 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3633 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3635 /* special cases :- */
3636 /* if both left & right are in bit space */
3637 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3638 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3640 wassertl (0, "Tried to subtract two bits");
3644 /* if I can do an decrement instead of subtract then GOOD for ME */
3645 if (genMinusDec (ic) == TRUE)
3648 size = getDataSize (IC_RESULT (ic));
3650 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3655 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3659 /* Same logic as genPlus */
3662 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3663 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3664 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3666 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3667 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3668 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3669 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3671 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3672 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3674 if (left == PAIR_INVALID && right == PAIR_INVALID)
3679 else if (right == PAIR_INVALID)
3681 else if (left == PAIR_INVALID)
3684 fetchPair (left, AOP (IC_LEFT (ic)));
3685 /* Order is important. Right may be HL */
3686 fetchPair (right, AOP (IC_RIGHT (ic)));
3688 emit2 ("ld a,%s", _pairs[left].l);
3689 emit2 ("sub a,%s", _pairs[right].l);
3691 emit2 ("ld a,%s", _pairs[left].h);
3692 emit2 ("sbc a,%s", _pairs[right].h);
3694 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
3696 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3698 aopPut (AOP (IC_RESULT (ic)), "e", 0);
3704 /* Be paranoid on the GB with 4 byte variables due to how C
3705 can be trashed by lda hl,n(sp).
3707 _gbz80_emitAddSubLong (ic, FALSE);
3712 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3714 /* if literal, add a,#-lit, else normal subb */
3717 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3718 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3722 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3725 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3729 /* first add without previous c */
3731 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
3733 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3735 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3738 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3739 AOP_SIZE (IC_LEFT (ic)) == 3 &&
3740 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3742 wassertl (0, "Tried to subtract on a long pointer");
3746 freeAsmop (IC_LEFT (ic), NULL, ic);
3747 freeAsmop (IC_RIGHT (ic), NULL, ic);
3748 freeAsmop (IC_RESULT (ic), NULL, ic);
3751 /*-----------------------------------------------------------------*/
3752 /* genMult - generates code for multiplication */
3753 /*-----------------------------------------------------------------*/
3755 genMult (iCode * ic)
3759 /* If true then the final operation should be a subtract */
3760 bool active = FALSE;
3762 /* Shouldn't occur - all done through function calls */
3763 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3764 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3765 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3767 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
3768 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
3769 AOP_SIZE (IC_RESULT (ic)) > 2)
3771 wassertl (0, "Multiplication is handled through support function calls");
3774 /* Swap left and right such that right is a literal */
3775 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
3777 operand *t = IC_RIGHT (ic);
3778 IC_RIGHT (ic) = IC_LEFT (ic);
3782 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
3784 val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
3785 // wassertl (val > 0, "Multiply must be positive");
3786 wassertl (val != 1, "Can't multiply by 1");
3788 if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
3790 _G.stack.pushedDE = TRUE;
3793 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
3795 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
3803 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3808 /* Fully unroled version of mul.s. Not the most efficient.
3810 for (count = 0; count < 16; count++)
3812 if (count != 0 && active)
3814 emit2 ("add hl,hl");
3818 if (active == FALSE)
3825 emit2 ("add hl,de");
3834 if (IS_Z80 && _G.stack.pushedDE)
3837 _G.stack.pushedDE = FALSE;
3840 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3842 freeAsmop (IC_LEFT (ic), NULL, ic);
3843 freeAsmop (IC_RIGHT (ic), NULL, ic);
3844 freeAsmop (IC_RESULT (ic), NULL, ic);
3847 /*-----------------------------------------------------------------*/
3848 /* genDiv - generates code for division */
3849 /*-----------------------------------------------------------------*/
3853 /* Shouldn't occur - all done through function calls */
3854 wassertl (0, "Division is handled through support function calls");
3857 /*-----------------------------------------------------------------*/
3858 /* genMod - generates code for division */
3859 /*-----------------------------------------------------------------*/
3863 /* Shouldn't occur - all done through function calls */
3867 /*-----------------------------------------------------------------*/
3868 /* genIfxJump :- will create a jump depending on the ifx */
3869 /*-----------------------------------------------------------------*/
3871 genIfxJump (iCode * ic, char *jval)
3876 /* if true label then we jump if condition
3880 jlbl = IC_TRUE (ic);
3881 if (!strcmp (jval, "a"))
3885 else if (!strcmp (jval, "c"))
3889 else if (!strcmp (jval, "nc"))
3893 else if (!strcmp (jval, "m"))
3897 else if (!strcmp (jval, "p"))
3903 /* The buffer contains the bit on A that we should test */
3909 /* false label is present */
3910 jlbl = IC_FALSE (ic);
3911 if (!strcmp (jval, "a"))
3915 else if (!strcmp (jval, "c"))
3919 else if (!strcmp (jval, "nc"))
3923 else if (!strcmp (jval, "m"))
3927 else if (!strcmp (jval, "p"))
3933 /* The buffer contains the bit on A that we should test */
3937 /* Z80 can do a conditional long jump */
3938 if (!strcmp (jval, "a"))
3942 else if (!strcmp (jval, "c"))
3945 else if (!strcmp (jval, "nc"))
3948 else if (!strcmp (jval, "m"))
3951 else if (!strcmp (jval, "p"))
3956 emit2 ("bit %s,a", jval);
3958 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
3960 /* mark the icode as generated */
3966 _getPairIdName (PAIR_ID id)
3968 return _pairs[id].name;
3973 /* if unsigned char cmp with lit, just compare */
3975 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
3977 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3980 emit2 ("xor a,!immedbyte", 0x80);
3981 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
3984 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3986 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
3988 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
3989 // Pull left into DE and right into HL
3990 aopGet (AOP(left), LSB, FALSE);
3993 aopGet (AOP(right), LSB, FALSE);
3997 if (size == 0 && sign)
3999 // Highest byte when signed needs the bits flipped
4002 emit2 ("ld a,(de)");
4003 emit2 ("xor #0x80");
4005 emit2 ("ld a,(hl)");
4006 emit2 ("xor #0x80");
4010 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4014 emit2 ("ld a,(de)");
4015 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4025 spillPair (PAIR_HL);
4027 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4029 setupPair (PAIR_HL, AOP (left), 0);
4030 aopGet (AOP(right), LSB, FALSE);
4034 if (size == 0 && sign)
4036 // Highest byte when signed needs the bits flipped
4039 emit2 ("ld a,(hl)");
4040 emit2 ("xor #0x80");
4042 emit2 ("ld a,%d(iy)", offset);
4043 emit2 ("xor #0x80");
4047 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4051 emit2 ("ld a,(hl)");
4052 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4061 spillPair (PAIR_HL);
4062 spillPair (PAIR_IY);
4066 if (AOP_TYPE (right) == AOP_LIT)
4068 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4069 /* optimize if(x < 0) or if(x >= 0) */
4074 /* No sign so it's always false */
4079 /* Just load in the top most bit */
4080 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4081 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4083 genIfxJump (ifx, "7");
4095 /* First setup h and l contaning the top most bytes XORed */
4096 bool fDidXor = FALSE;
4097 if (AOP_TYPE (left) == AOP_LIT)
4099 unsigned long lit = (unsigned long)
4100 floatFromVal (AOP (left)->aopu.aop_lit);
4101 emit2 ("ld %s,!immedbyte", _fTmp[0],
4102 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4106 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4107 emit2 ("xor a,!immedbyte", 0x80);
4108 emit2 ("ld %s,a", _fTmp[0]);
4111 if (AOP_TYPE (right) == AOP_LIT)
4113 unsigned long lit = (unsigned long)
4114 floatFromVal (AOP (right)->aopu.aop_lit);
4115 emit2 ("ld %s,!immedbyte", _fTmp[1],
4116 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4120 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4121 emit2 ("xor a,!immedbyte", 0x80);
4122 emit2 ("ld %s,a", _fTmp[1]);
4128 /* Do a long subtract */
4131 _moveA (aopGet (AOP (left), offset, FALSE));
4133 if (sign && size == 0)
4135 emit2 ("ld a,%s", _fTmp[0]);
4136 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4140 /* Subtract through, propagating the carry */
4141 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4149 /** Generic compare for > or <
4152 genCmp (operand * left, operand * right,
4153 operand * result, iCode * ifx, int sign)
4155 int size, offset = 0;
4156 unsigned long lit = 0L;
4157 bool swap_sense = FALSE;
4159 /* if left & right are bit variables */
4160 if (AOP_TYPE (left) == AOP_CRY &&
4161 AOP_TYPE (right) == AOP_CRY)
4163 /* Cant happen on the Z80 */
4164 wassertl (0, "Tried to compare two bits");
4168 /* Do a long subtract of right from left. */
4169 size = max (AOP_SIZE (left), AOP_SIZE (right));
4171 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4173 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4174 // Pull left into DE and right into HL
4175 aopGet (AOP(left), LSB, FALSE);
4178 aopGet (AOP(right), LSB, FALSE);
4182 emit2 ("ld a,(de)");
4183 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4192 spillPair (PAIR_HL);
4196 if (AOP_TYPE (right) == AOP_LIT)
4198 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4199 /* optimize if(x < 0) or if(x >= 0) */
4204 /* No sign so it's always false */
4209 /* Just load in the top most bit */
4210 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4211 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4213 genIfxJump (ifx, "7");
4224 genIfxJump (ifx, swap_sense ? "c" : "nc");
4235 _moveA (aopGet (AOP (left), offset, FALSE));
4236 /* Subtract through, propagating the carry */
4237 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4243 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4247 /* Shift the sign bit up into carry */
4250 outBitCLong (result, swap_sense);
4254 /* if the result is used in the next
4255 ifx conditional branch then generate
4256 code a little differently */
4264 genIfxJump (ifx, swap_sense ? "nc" : "c");
4268 genIfxJump (ifx, swap_sense ? "p" : "m");
4273 genIfxJump (ifx, swap_sense ? "nc" : "c");
4280 /* Shift the sign bit up into carry */
4283 outBitCLong (result, swap_sense);
4285 /* leave the result in acc */
4289 /*-----------------------------------------------------------------*/
4290 /* genCmpGt :- greater than comparison */
4291 /*-----------------------------------------------------------------*/
4293 genCmpGt (iCode * ic, iCode * ifx)
4295 operand *left, *right, *result;
4296 sym_link *letype, *retype;
4299 left = IC_LEFT (ic);
4300 right = IC_RIGHT (ic);
4301 result = IC_RESULT (ic);
4303 letype = getSpec (operandType (left));
4304 retype = getSpec (operandType (right));
4305 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4306 /* assign the amsops */
4307 aopOp (left, ic, FALSE, FALSE);
4308 aopOp (right, ic, FALSE, FALSE);
4309 aopOp (result, ic, TRUE, FALSE);
4311 genCmp (right, left, result, ifx, sign);
4313 freeAsmop (left, NULL, ic);
4314 freeAsmop (right, NULL, ic);
4315 freeAsmop (result, NULL, ic);
4318 /*-----------------------------------------------------------------*/
4319 /* genCmpLt - less than comparisons */
4320 /*-----------------------------------------------------------------*/
4322 genCmpLt (iCode * ic, iCode * ifx)
4324 operand *left, *right, *result;
4325 sym_link *letype, *retype;
4328 left = IC_LEFT (ic);
4329 right = IC_RIGHT (ic);
4330 result = IC_RESULT (ic);
4332 letype = getSpec (operandType (left));
4333 retype = getSpec (operandType (right));
4334 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4336 /* assign the amsops */
4337 aopOp (left, ic, FALSE, FALSE);
4338 aopOp (right, ic, FALSE, FALSE);
4339 aopOp (result, ic, TRUE, FALSE);
4341 genCmp (left, right, result, ifx, sign);
4343 freeAsmop (left, NULL, ic);
4344 freeAsmop (right, NULL, ic);
4345 freeAsmop (result, NULL, ic);
4348 /*-----------------------------------------------------------------*/
4349 /* gencjneshort - compare and jump if not equal */
4350 /*-----------------------------------------------------------------*/
4352 gencjneshort (operand * left, operand * right, symbol * lbl)
4354 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4356 unsigned long lit = 0L;
4358 /* Swap the left and right if it makes the computation easier */
4359 if (AOP_TYPE (left) == AOP_LIT)
4366 if (AOP_TYPE (right) == AOP_LIT)
4368 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4371 /* if the right side is a literal then anything goes */
4372 if (AOP_TYPE (right) == AOP_LIT &&
4373 AOP_TYPE (left) != AOP_DIR)
4377 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4382 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4389 emit2 ("jp nz,!tlabel", lbl->key + 100);
4395 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4396 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
4399 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
4400 emit2 ("jp nz,!tlabel", lbl->key + 100);
4405 /* if the right side is in a register or in direct space or
4406 if the left is a pointer register & right is not */
4407 else if (AOP_TYPE (right) == AOP_REG ||
4408 AOP_TYPE (right) == AOP_DIR ||
4409 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
4413 _moveA (aopGet (AOP (left), offset, FALSE));
4414 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
4415 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4417 emit2 ("jp nz,!tlabel", lbl->key + 100);
4420 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4421 emit2 ("jp nz,!tlabel", lbl->key + 100);
4428 /* right is a pointer reg need both a & b */
4429 /* PENDING: is this required? */
4432 _moveA (aopGet (AOP (right), offset, FALSE));
4433 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
4434 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
4440 /*-----------------------------------------------------------------*/
4441 /* gencjne - compare and jump if not equal */
4442 /*-----------------------------------------------------------------*/
4444 gencjne (operand * left, operand * right, symbol * lbl)
4446 symbol *tlbl = newiTempLabel (NULL);
4448 gencjneshort (left, right, lbl);
4451 emit2 ("ld a,!one");
4452 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4453 emitLabel (lbl->key + 100);
4455 emitLabel (tlbl->key + 100);
4458 /*-----------------------------------------------------------------*/
4459 /* genCmpEq - generates code for equal to */
4460 /*-----------------------------------------------------------------*/
4462 genCmpEq (iCode * ic, iCode * ifx)
4464 operand *left, *right, *result;
4466 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4467 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4468 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4470 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4472 /* Swap operands if it makes the operation easier. ie if:
4473 1. Left is a literal.
4475 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4477 operand *t = IC_RIGHT (ic);
4478 IC_RIGHT (ic) = IC_LEFT (ic);
4482 if (ifx && !AOP_SIZE (result))
4485 /* if they are both bit variables */
4486 if (AOP_TYPE (left) == AOP_CRY &&
4487 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4489 wassertl (0, "Tried to compare two bits");
4493 tlbl = newiTempLabel (NULL);
4494 gencjneshort (left, right, tlbl);
4497 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4498 emitLabel (tlbl->key + 100);
4502 /* PENDING: do this better */
4503 symbol *lbl = newiTempLabel (NULL);
4504 emit2 ("!shortjp !tlabel", lbl->key + 100);
4505 emitLabel (tlbl->key + 100);
4506 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4507 emitLabel (lbl->key + 100);
4510 /* mark the icode as generated */
4515 /* if they are both bit variables */
4516 if (AOP_TYPE (left) == AOP_CRY &&
4517 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4519 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4525 gencjne (left, right, newiTempLabel (NULL));
4526 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4533 genIfxJump (ifx, "a");
4536 /* if the result is used in an arithmetic operation
4537 then put the result in place */
4538 if (AOP_TYPE (result) != AOP_CRY)
4543 /* leave the result in acc */
4547 freeAsmop (left, NULL, ic);
4548 freeAsmop (right, NULL, ic);
4549 freeAsmop (result, NULL, ic);
4552 /*-----------------------------------------------------------------*/
4553 /* ifxForOp - returns the icode containing the ifx for operand */
4554 /*-----------------------------------------------------------------*/
4556 ifxForOp (operand * op, iCode * ic)
4558 /* if true symbol then needs to be assigned */
4559 if (IS_TRUE_SYMOP (op))
4562 /* if this has register type condition and
4563 the next instruction is ifx with the same operand
4564 and live to of the operand is upto the ifx only then */
4566 ic->next->op == IFX &&
4567 IC_COND (ic->next)->key == op->key &&
4568 OP_SYMBOL (op)->liveTo <= ic->next->seq)
4574 /*-----------------------------------------------------------------*/
4575 /* genAndOp - for && operation */
4576 /*-----------------------------------------------------------------*/
4578 genAndOp (iCode * ic)
4580 operand *left, *right, *result;
4583 /* note here that && operations that are in an if statement are
4584 taken away by backPatchLabels only those used in arthmetic
4585 operations remain */
4586 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4587 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4588 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4590 /* if both are bit variables */
4591 if (AOP_TYPE (left) == AOP_CRY &&
4592 AOP_TYPE (right) == AOP_CRY)
4594 wassertl (0, "Tried to and two bits");
4598 tlbl = newiTempLabel (NULL);
4600 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
4602 emitLabel (tlbl->key + 100);
4606 freeAsmop (left, NULL, ic);
4607 freeAsmop (right, NULL, ic);
4608 freeAsmop (result, NULL, ic);
4611 /*-----------------------------------------------------------------*/
4612 /* genOrOp - for || operation */
4613 /*-----------------------------------------------------------------*/
4615 genOrOp (iCode * ic)
4617 operand *left, *right, *result;
4620 /* note here that || operations that are in an
4621 if statement are taken away by backPatchLabels
4622 only those used in arthmetic operations remain */
4623 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4624 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4625 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4627 /* if both are bit variables */
4628 if (AOP_TYPE (left) == AOP_CRY &&
4629 AOP_TYPE (right) == AOP_CRY)
4631 wassertl (0, "Tried to OR two bits");
4635 tlbl = newiTempLabel (NULL);
4637 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4639 emitLabel (tlbl->key + 100);
4643 freeAsmop (left, NULL, ic);
4644 freeAsmop (right, NULL, ic);
4645 freeAsmop (result, NULL, ic);
4648 /*-----------------------------------------------------------------*/
4649 /* isLiteralBit - test if lit == 2^n */
4650 /*-----------------------------------------------------------------*/
4652 isLiteralBit (unsigned long lit)
4654 unsigned long pw[32] =
4655 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
4656 0x100L, 0x200L, 0x400L, 0x800L,
4657 0x1000L, 0x2000L, 0x4000L, 0x8000L,
4658 0x10000L, 0x20000L, 0x40000L, 0x80000L,
4659 0x100000L, 0x200000L, 0x400000L, 0x800000L,
4660 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
4661 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
4664 for (idx = 0; idx < 32; idx++)
4670 /*-----------------------------------------------------------------*/
4671 /* jmpTrueOrFalse - */
4672 /*-----------------------------------------------------------------*/
4674 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
4676 // ugly but optimized by peephole
4679 symbol *nlbl = newiTempLabel (NULL);
4680 emit2 ("jp !tlabel", nlbl->key + 100);
4681 emitLabel (tlbl->key + 100);
4682 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
4683 emitLabel (nlbl->key + 100);
4687 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
4688 emitLabel (tlbl->key + 100);
4693 /*-----------------------------------------------------------------*/
4694 /* genAnd - code for and */
4695 /*-----------------------------------------------------------------*/
4697 genAnd (iCode * ic, iCode * ifx)
4699 operand *left, *right, *result;
4700 int size, offset = 0;
4701 unsigned long lit = 0L;
4704 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4705 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4706 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4708 /* if left is a literal & right is not then exchange them */
4709 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4710 AOP_NEEDSACC (left))
4712 operand *tmp = right;
4717 /* if result = right then exchange them */
4718 if (sameRegs (AOP (result), AOP (right)))
4720 operand *tmp = right;
4725 /* if right is bit then exchange them */
4726 if (AOP_TYPE (right) == AOP_CRY &&
4727 AOP_TYPE (left) != AOP_CRY)
4729 operand *tmp = right;
4733 if (AOP_TYPE (right) == AOP_LIT)
4734 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4736 size = AOP_SIZE (result);
4738 if (AOP_TYPE (left) == AOP_CRY)
4740 wassertl (0, "Tried to perform an AND with a bit as an operand");
4744 // if(val & 0xZZ) - size = 0, ifx != FALSE -
4745 // bit = val & 0xZZ - size = 1, ifx = FALSE -
4746 if ((AOP_TYPE (right) == AOP_LIT) &&
4747 (AOP_TYPE (result) == AOP_CRY) &&
4748 (AOP_TYPE (left) != AOP_CRY))
4750 symbol *tlbl = newiTempLabel (NULL);
4751 int sizel = AOP_SIZE (left);
4754 /* PENDING: Test case for this. */
4759 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
4761 _moveA (aopGet (AOP (left), offset, FALSE));
4762 if (bytelit != 0x0FFL)
4764 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4771 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4775 // bit = left & literal
4779 emit2 ("!tlabeldef", tlbl->key + 100);
4781 // if(left & literal)
4786 jmpTrueOrFalse (ifx, tlbl);
4794 /* if left is same as result */
4795 if (sameRegs (AOP (result), AOP (left)))
4797 for (; size--; offset++)
4799 if (AOP_TYPE (right) == AOP_LIT)
4801 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4806 aopPut (AOP (result), "!zero", offset);
4809 _moveA (aopGet (AOP (left), offset, FALSE));
4811 aopGet (AOP (right), offset, FALSE));
4812 aopPut (AOP (left), "a", offset);
4819 if (AOP_TYPE (left) == AOP_ACC)
4821 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
4825 _moveA (aopGet (AOP (left), offset, FALSE));
4827 aopGet (AOP (right), offset, FALSE));
4828 aopPut (AOP (left), "a", offset);
4835 // left & result in different registers
4836 if (AOP_TYPE (result) == AOP_CRY)
4838 wassertl (0, "Tried to AND where the result is in carry");
4842 for (; (size--); offset++)
4845 // result = left & right
4846 if (AOP_TYPE (right) == AOP_LIT)
4848 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4850 aopPut (AOP (result),
4851 aopGet (AOP (left), offset, FALSE),
4855 else if (bytelit == 0)
4857 aopPut (AOP (result), "!zero", offset);
4861 // faster than result <- left, anl result,right
4862 // and better if result is SFR
4863 if (AOP_TYPE (left) == AOP_ACC)
4864 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4867 _moveA (aopGet (AOP (left), offset, FALSE));
4869 aopGet (AOP (right), offset, FALSE));
4871 aopPut (AOP (result), "a", offset);
4878 freeAsmop (left, NULL, ic);
4879 freeAsmop (right, NULL, ic);
4880 freeAsmop (result, NULL, ic);
4883 /*-----------------------------------------------------------------*/
4884 /* genOr - code for or */
4885 /*-----------------------------------------------------------------*/
4887 genOr (iCode * ic, iCode * ifx)
4889 operand *left, *right, *result;
4890 int size, offset = 0;
4891 unsigned long lit = 0L;
4894 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4895 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4896 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4898 /* if left is a literal & right is not then exchange them */
4899 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4900 AOP_NEEDSACC (left))
4902 operand *tmp = right;
4907 /* if result = right then exchange them */
4908 if (sameRegs (AOP (result), AOP (right)))
4910 operand *tmp = right;
4915 /* if right is bit then exchange them */
4916 if (AOP_TYPE (right) == AOP_CRY &&
4917 AOP_TYPE (left) != AOP_CRY)
4919 operand *tmp = right;
4923 if (AOP_TYPE (right) == AOP_LIT)
4924 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4926 size = AOP_SIZE (result);
4928 if (AOP_TYPE (left) == AOP_CRY)
4930 wassertl (0, "Tried to OR where left is a bit");
4934 // if(val | 0xZZ) - size = 0, ifx != FALSE -
4935 // bit = val | 0xZZ - size = 1, ifx = FALSE -
4936 if ((AOP_TYPE (right) == AOP_LIT) &&
4937 (AOP_TYPE (result) == AOP_CRY) &&
4938 (AOP_TYPE (left) != AOP_CRY))
4940 symbol *tlbl = newiTempLabel (NULL);
4941 int sizel = AOP_SIZE (left);
4945 wassertl (0, "Result is assigned to a bit");
4947 /* PENDING: Modeled after the AND code which is inefficent. */
4950 bytelit = (lit >> (offset * 8)) & 0x0FFL;
4952 _moveA (aopGet (AOP (left), offset, FALSE));
4953 /* OR with any literal is the same as OR with itself. */
4955 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4961 jmpTrueOrFalse (ifx, tlbl);
4966 /* if left is same as result */
4967 if (sameRegs (AOP (result), AOP (left)))
4969 for (; size--; offset++)
4971 if (AOP_TYPE (right) == AOP_LIT)
4973 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4977 _moveA (aopGet (AOP (left), offset, FALSE));
4979 aopGet (AOP (right), offset, FALSE));
4980 aopPut (AOP (result), "a", offset);
4985 if (AOP_TYPE (left) == AOP_ACC)
4986 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4989 _moveA (aopGet (AOP (left), offset, FALSE));
4991 aopGet (AOP (right), offset, FALSE));
4992 aopPut (AOP (result), "a", offset);
4999 // left & result in different registers
5000 if (AOP_TYPE (result) == AOP_CRY)
5002 wassertl (0, "Result of OR is in a bit");
5005 for (; (size--); offset++)
5008 // result = left & right
5009 if (AOP_TYPE (right) == AOP_LIT)
5011 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5013 aopPut (AOP (result),
5014 aopGet (AOP (left), offset, FALSE),
5019 // faster than result <- left, anl result,right
5020 // and better if result is SFR
5021 if (AOP_TYPE (left) == AOP_ACC)
5022 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5025 _moveA (aopGet (AOP (left), offset, FALSE));
5027 aopGet (AOP (right), offset, FALSE));
5029 aopPut (AOP (result), "a", offset);
5030 /* PENDING: something weird is going on here. Add exception. */
5031 if (AOP_TYPE (result) == AOP_ACC)
5037 freeAsmop (left, NULL, ic);
5038 freeAsmop (right, NULL, ic);
5039 freeAsmop (result, NULL, ic);
5042 /*-----------------------------------------------------------------*/
5043 /* genXor - code for xclusive or */
5044 /*-----------------------------------------------------------------*/
5046 genXor (iCode * ic, iCode * ifx)
5048 operand *left, *right, *result;
5049 int size, offset = 0;
5050 unsigned long lit = 0L;
5052 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5053 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5054 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5056 /* if left is a literal & right is not then exchange them */
5057 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5058 AOP_NEEDSACC (left))
5060 operand *tmp = right;
5065 /* if result = right then exchange them */
5066 if (sameRegs (AOP (result), AOP (right)))
5068 operand *tmp = right;
5073 /* if right is bit then exchange them */
5074 if (AOP_TYPE (right) == AOP_CRY &&
5075 AOP_TYPE (left) != AOP_CRY)
5077 operand *tmp = right;
5081 if (AOP_TYPE (right) == AOP_LIT)
5082 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5084 size = AOP_SIZE (result);
5086 if (AOP_TYPE (left) == AOP_CRY)
5088 wassertl (0, "Tried to XOR a bit");
5092 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5093 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5094 if ((AOP_TYPE (right) == AOP_LIT) &&
5095 (AOP_TYPE (result) == AOP_CRY) &&
5096 (AOP_TYPE (left) != AOP_CRY))
5098 symbol *tlbl = newiTempLabel (NULL);
5099 int sizel = AOP_SIZE (left);
5103 /* PENDING: Test case for this. */
5104 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5108 _moveA (aopGet (AOP (left), offset, FALSE));
5109 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5110 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5115 jmpTrueOrFalse (ifx, tlbl);
5119 wassertl (0, "Result of XOR was destined for a bit");
5124 /* if left is same as result */
5125 if (sameRegs (AOP (result), AOP (left)))
5127 for (; size--; offset++)
5129 if (AOP_TYPE (right) == AOP_LIT)
5131 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5135 _moveA (aopGet (AOP (right), offset, FALSE));
5137 aopGet (AOP (left), offset, FALSE));
5138 aopPut (AOP (result), "a", offset);
5143 if (AOP_TYPE (left) == AOP_ACC)
5145 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5149 _moveA (aopGet (AOP (right), offset, FALSE));
5151 aopGet (AOP (left), offset, FALSE));
5152 aopPut (AOP (result), "a", 0);
5159 // left & result in different registers
5160 if (AOP_TYPE (result) == AOP_CRY)
5162 wassertl (0, "Result of XOR is in a bit");
5165 for (; (size--); offset++)
5168 // result = left & right
5169 if (AOP_TYPE (right) == AOP_LIT)
5171 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5173 aopPut (AOP (result),
5174 aopGet (AOP (left), offset, FALSE),
5179 // faster than result <- left, anl result,right
5180 // and better if result is SFR
5181 if (AOP_TYPE (left) == AOP_ACC)
5183 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5187 _moveA (aopGet (AOP (right), offset, FALSE));
5189 aopGet (AOP (left), offset, FALSE));
5191 aopPut (AOP (result), "a", offset);
5196 freeAsmop (left, NULL, ic);
5197 freeAsmop (right, NULL, ic);
5198 freeAsmop (result, NULL, ic);
5201 /*-----------------------------------------------------------------*/
5202 /* genInline - write the inline code out */
5203 /*-----------------------------------------------------------------*/
5205 genInline (iCode * ic)
5207 char *buffer, *bp, *bp1;
5209 _G.lines.isInline += (!options.asmpeep);
5211 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5212 strcpy (buffer, IC_INLINE (ic));
5214 /* emit each line as a code */
5239 _G.lines.isInline -= (!options.asmpeep);
5243 /*-----------------------------------------------------------------*/
5244 /* genRRC - rotate right with carry */
5245 /*-----------------------------------------------------------------*/
5252 /*-----------------------------------------------------------------*/
5253 /* genRLC - generate code for rotate left with carry */
5254 /*-----------------------------------------------------------------*/
5261 /*-----------------------------------------------------------------*/
5262 /* genGetHbit - generates code get highest order bit */
5263 /*-----------------------------------------------------------------*/
5265 genGetHbit (iCode * ic)
5267 operand *left, *result;
5268 left = IC_LEFT (ic);
5269 result = IC_RESULT (ic);
5271 aopOp (left, ic, FALSE, FALSE);
5272 aopOp (result, ic, FALSE, FALSE);
5274 /* get the highest order byte into a */
5275 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5277 if (AOP_TYPE (result) == AOP_CRY)
5285 emit2 ("and a,!one");
5290 freeAsmop (left, NULL, ic);
5291 freeAsmop (result, NULL, ic);
5295 emitRsh2 (asmop *aop, int size, int is_signed)
5301 const char *l = aopGet (aop, size, FALSE);
5304 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5314 /*-----------------------------------------------------------------*/
5315 /* shiftR2Left2Result - shift right two bytes from left to result */
5316 /*-----------------------------------------------------------------*/
5318 shiftR2Left2Result (operand * left, int offl,
5319 operand * result, int offr,
5320 int shCount, int is_signed)
5323 symbol *tlbl, *tlbl1;
5325 movLeft2Result (left, offl, result, offr, 0);
5326 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5328 /* if (AOP(result)->type == AOP_REG) { */
5330 tlbl = newiTempLabel (NULL);
5331 tlbl1 = newiTempLabel (NULL);
5333 /* Left is already in result - so now do the shift */
5338 emitRsh2 (AOP (result), size, is_signed);
5343 emit2 ("ld a,!immedbyte+1", shCount);
5344 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5345 emitLabel (tlbl->key + 100);
5347 emitRsh2 (AOP (result), size, is_signed);
5349 emitLabel (tlbl1->key + 100);
5351 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5355 /*-----------------------------------------------------------------*/
5356 /* shiftL2Left2Result - shift left two bytes from left to result */
5357 /*-----------------------------------------------------------------*/
5359 shiftL2Left2Result (operand * left, int offl,
5360 operand * result, int offr, int shCount)
5362 if (sameRegs (AOP (result), AOP (left)) &&
5363 ((offl + MSB16) == offr))
5369 /* Copy left into result */
5370 movLeft2Result (left, offl, result, offr, 0);
5371 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5374 if (shCount == 1 && getPairId (AOP (result)) == PAIR_HL)
5376 emit2 ("add hl,hl");
5382 symbol *tlbl, *tlbl1;
5385 tlbl = newiTempLabel (NULL);
5386 tlbl1 = newiTempLabel (NULL);
5388 /* Left is already in result - so now do the shift */
5391 emit2 ("ld a,!immedbyte+1", shCount);
5392 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5393 emitLabel (tlbl->key + 100);
5398 l = aopGet (AOP (result), offset, FALSE);
5402 emit2 ("sla %s", l);
5413 emitLabel (tlbl1->key + 100);
5415 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5420 /*-----------------------------------------------------------------*/
5421 /* AccRol - rotate left accumulator by known count */
5422 /*-----------------------------------------------------------------*/
5424 AccRol (int shCount)
5426 shCount &= 0x0007; // shCount : 0..7
5465 /*-----------------------------------------------------------------*/
5466 /* AccLsh - left shift accumulator by known count */
5467 /*-----------------------------------------------------------------*/
5469 AccLsh (int shCount)
5471 static const unsigned char SLMask[] =
5473 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5482 else if (shCount == 2)
5489 /* rotate left accumulator */
5491 /* and kill the lower order bits */
5492 emit2 ("and a,!immedbyte", SLMask[shCount]);
5497 /*-----------------------------------------------------------------*/
5498 /* shiftL1Left2Result - shift left one byte from left to result */
5499 /*-----------------------------------------------------------------*/
5501 shiftL1Left2Result (operand * left, int offl,
5502 operand * result, int offr, int shCount)
5505 l = aopGet (AOP (left), offl, FALSE);
5507 /* shift left accumulator */
5509 aopPut (AOP (result), "a", offr);
5513 /*-----------------------------------------------------------------*/
5514 /* genlshTwo - left shift two bytes by known amount != 0 */
5515 /*-----------------------------------------------------------------*/
5517 genlshTwo (operand * result, operand * left, int shCount)
5519 int size = AOP_SIZE (result);
5521 wassert (size == 2);
5523 /* if shCount >= 8 */
5531 movLeft2Result (left, LSB, result, MSB16, 0);
5532 aopPut (AOP (result), "!zero", 0);
5533 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
5537 movLeft2Result (left, LSB, result, MSB16, 0);
5538 aopPut (AOP (result), "!zero", 0);
5543 aopPut (AOP (result), "!zero", LSB);
5546 /* 1 <= shCount <= 7 */
5555 shiftL2Left2Result (left, LSB, result, LSB, shCount);
5560 /*-----------------------------------------------------------------*/
5561 /* genlshOne - left shift a one byte quantity by known count */
5562 /*-----------------------------------------------------------------*/
5564 genlshOne (operand * result, operand * left, int shCount)
5566 shiftL1Left2Result (left, LSB, result, LSB, shCount);
5569 /*-----------------------------------------------------------------*/
5570 /* genLeftShiftLiteral - left shifting by known count */
5571 /*-----------------------------------------------------------------*/
5573 genLeftShiftLiteral (operand * left,
5578 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5581 freeAsmop (right, NULL, ic);
5583 aopOp (left, ic, FALSE, FALSE);
5584 aopOp (result, ic, FALSE, FALSE);
5586 size = getSize (operandType (result));
5588 /* I suppose that the left size >= result size */
5594 else if (shCount >= (size * 8))
5598 aopPut (AOP (result), "!zero", size);
5606 genlshOne (result, left, shCount);
5609 genlshTwo (result, left, shCount);
5612 wassertl (0, "Shifting of longs is currently unsupported");
5618 freeAsmop (left, NULL, ic);
5619 freeAsmop (result, NULL, ic);
5622 /*-----------------------------------------------------------------*/
5623 /* genLeftShift - generates code for left shifting */
5624 /*-----------------------------------------------------------------*/
5626 genLeftShift (iCode * ic)
5630 symbol *tlbl, *tlbl1;
5631 operand *left, *right, *result;
5633 right = IC_RIGHT (ic);
5634 left = IC_LEFT (ic);
5635 result = IC_RESULT (ic);
5637 aopOp (right, ic, FALSE, FALSE);
5639 /* if the shift count is known then do it
5640 as efficiently as possible */
5641 if (AOP_TYPE (right) == AOP_LIT)
5643 genLeftShiftLiteral (left, right, result, ic);
5647 /* shift count is unknown then we have to form a loop get the loop
5648 count in B : Note: we take only the lower order byte since
5649 shifting more that 32 bits make no sense anyway, ( the largest
5650 size of an object can be only 32 bits ) */
5651 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5653 freeAsmop (right, NULL, ic);
5654 aopOp (left, ic, FALSE, FALSE);
5655 aopOp (result, ic, FALSE, FALSE);
5657 /* now move the left to the result if they are not the
5660 if (!sameRegs (AOP (left), AOP (result)))
5663 size = AOP_SIZE (result);
5667 l = aopGet (AOP (left), offset, FALSE);
5668 aopPut (AOP (result), l, offset);
5673 tlbl = newiTempLabel (NULL);
5674 size = AOP_SIZE (result);
5676 tlbl1 = newiTempLabel (NULL);
5678 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5679 emitLabel (tlbl->key + 100);
5680 l = aopGet (AOP (result), offset, FALSE);
5684 l = aopGet (AOP (result), offset, FALSE);
5688 emit2 ("sla %s", l);
5696 emitLabel (tlbl1->key + 100);
5698 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5700 freeAsmop (left, NULL, ic);
5701 freeAsmop (result, NULL, ic);
5704 /*-----------------------------------------------------------------*/
5705 /* genrshOne - left shift two bytes by known amount != 0 */
5706 /*-----------------------------------------------------------------*/
5708 genrshOne (operand * result, operand * left, int shCount, int is_signed)
5711 int size = AOP_SIZE (result);
5714 wassert (size == 1);
5715 wassert (shCount < 8);
5717 l = aopGet (AOP (left), 0, FALSE);
5719 if (AOP (result)->type == AOP_REG)
5721 aopPut (AOP (result), l, 0);
5722 l = aopGet (AOP (result), 0, FALSE);
5725 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5733 emit2 ("%s a", is_signed ? "sra" : "srl");
5735 aopPut (AOP (result), "a", 0);
5739 /*-----------------------------------------------------------------*/
5740 /* AccRsh - right shift accumulator by known count */
5741 /*-----------------------------------------------------------------*/
5743 AccRsh (int shCount)
5745 static const unsigned char SRMask[] =
5747 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
5752 /* rotate right accumulator */
5753 AccRol (8 - shCount);
5754 /* and kill the higher order bits */
5755 emit2 ("and a,!immedbyte", SRMask[shCount]);
5759 /*-----------------------------------------------------------------*/
5760 /* shiftR1Left2Result - shift right one byte from left to result */
5761 /*-----------------------------------------------------------------*/
5763 shiftR1Left2Result (operand * left, int offl,
5764 operand * result, int offr,
5765 int shCount, int sign)
5767 _moveA (aopGet (AOP (left), offl, FALSE));
5772 emit2 ("%s a", sign ? "sra" : "srl");
5779 aopPut (AOP (result), "a", offr);
5782 /*-----------------------------------------------------------------*/
5783 /* genrshTwo - right shift two bytes by known amount != 0 */
5784 /*-----------------------------------------------------------------*/
5786 genrshTwo (operand * result, operand * left,
5787 int shCount, int sign)
5789 /* if shCount >= 8 */
5795 shiftR1Left2Result (left, MSB16, result, LSB,
5800 movLeft2Result (left, MSB16, result, LSB, sign);
5804 /* Sign extend the result */
5805 _moveA(aopGet (AOP (result), 0, FALSE));
5809 aopPut (AOP (result), ACC_NAME, MSB16);
5813 aopPut (AOP (result), "!zero", 1);
5816 /* 1 <= shCount <= 7 */
5819 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
5823 /*-----------------------------------------------------------------*/
5824 /* genRightShiftLiteral - left shifting by known count */
5825 /*-----------------------------------------------------------------*/
5827 genRightShiftLiteral (operand * left,
5833 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5836 freeAsmop (right, NULL, ic);
5838 aopOp (left, ic, FALSE, FALSE);
5839 aopOp (result, ic, FALSE, FALSE);
5841 size = getSize (operandType (result));
5843 /* I suppose that the left size >= result size */
5849 else if (shCount >= (size * 8))
5851 aopPut (AOP (result), "!zero", size);
5857 genrshOne (result, left, shCount, sign);
5860 genrshTwo (result, left, shCount, sign);
5863 wassertl (0, "Asked to shift right a long which should be a function call");
5866 wassertl (0, "Entered default case in right shift delegate");
5869 freeAsmop (left, NULL, ic);
5870 freeAsmop (result, NULL, ic);
5873 /*-----------------------------------------------------------------*/
5874 /* genRightShift - generate code for right shifting */
5875 /*-----------------------------------------------------------------*/
5877 genRightShift (iCode * ic)
5879 operand *right, *left, *result;
5881 int size, offset, first = 1;
5885 symbol *tlbl, *tlbl1;
5887 /* if signed then we do it the hard way preserve the
5888 sign bit moving it inwards */
5889 retype = getSpec (operandType (IC_RESULT (ic)));
5891 is_signed = !SPEC_USIGN (retype);
5893 /* signed & unsigned types are treated the same : i.e. the
5894 signed is NOT propagated inwards : quoting from the
5895 ANSI - standard : "for E1 >> E2, is equivalent to division
5896 by 2**E2 if unsigned or if it has a non-negative value,
5897 otherwise the result is implementation defined ", MY definition
5898 is that the sign does not get propagated */
5900 right = IC_RIGHT (ic);
5901 left = IC_LEFT (ic);
5902 result = IC_RESULT (ic);
5904 aopOp (right, ic, FALSE, FALSE);
5906 /* if the shift count is known then do it
5907 as efficiently as possible */
5908 if (AOP_TYPE (right) == AOP_LIT)
5910 genRightShiftLiteral (left, right, result, ic, is_signed);
5914 aopOp (left, ic, FALSE, FALSE);
5915 aopOp (result, ic, FALSE, FALSE);
5917 /* now move the left to the result if they are not the
5919 if (!sameRegs (AOP (left), AOP (result)) &&
5920 AOP_SIZE (result) > 1)
5923 size = AOP_SIZE (result);
5927 l = aopGet (AOP (left), offset, FALSE);
5928 aopPut (AOP (result), l, offset);
5933 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5935 freeAsmop (right, NULL, ic);
5937 tlbl = newiTempLabel (NULL);
5938 tlbl1 = newiTempLabel (NULL);
5939 size = AOP_SIZE (result);
5942 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5943 emitLabel (tlbl->key + 100);
5946 l = aopGet (AOP (result), offset--, FALSE);
5949 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5957 emitLabel (tlbl1->key + 100);
5959 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5961 freeAsmop (left, NULL, ic);
5962 freeAsmop (result, NULL, ic);
5965 /*-----------------------------------------------------------------*/
5966 /* genGenPointerGet - get value from generic pointer space */
5967 /*-----------------------------------------------------------------*/
5969 genGenPointerGet (operand * left,
5970 operand * result, iCode * ic)
5973 sym_link *retype = getSpec (operandType (result));
5979 aopOp (left, ic, FALSE, FALSE);
5980 aopOp (result, ic, FALSE, FALSE);
5982 size = AOP_SIZE (result);
5984 if (isPair (AOP (left)) && size == 1)
5987 if (isPtrPair (AOP (left)))
5989 tsprintf (buffer, "!*pair", getPairName (AOP (left)));
5990 aopPut (AOP (result), buffer, 0);
5994 emit2 ("ld a,!*pair", getPairName (AOP (left)));
5995 aopPut (AOP (result), "a", 0);
5997 freeAsmop (left, NULL, ic);
6001 if (getPairId (AOP (left)) == PAIR_IY)
6008 tsprintf (at, "!*iyx", offset);
6009 aopPut (AOP (result), at, offset);
6013 freeAsmop (left, NULL, ic);
6017 /* For now we always load into IY */
6018 /* if this is remateriazable */
6019 fetchPair (pair, AOP (left));
6021 /* if bit then unpack */
6022 if (IS_BITVAR (retype))
6026 else if (getPairId (AOP (result)) == PAIR_HL)
6028 wassertl (size == 2, "HL must be of size 2");
6029 emit2 ("ld a,!*hl");
6031 emit2 ("ld h,!*hl");
6034 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6036 size = AOP_SIZE (result);
6041 /* PENDING: make this better */
6042 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6044 aopPut (AOP (result), "!*hl", offset++);
6048 emit2 ("ld a,!*pair", _pairs[pair].name);
6049 aopPut (AOP (result), "a", offset++);
6053 emit2 ("inc %s", _pairs[pair].name);
6054 _G.pairs[pair].offset++;
6057 /* Fixup HL back down */
6058 for (size = AOP_SIZE (result)-1; size; size--)
6060 emit2 ("dec %s", _pairs[pair].name);
6065 size = AOP_SIZE (result);
6070 /* PENDING: make this better */
6072 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6074 aopPut (AOP (result), "!*hl", offset++);
6078 emit2 ("ld a,!*pair", _pairs[pair].name);
6079 aopPut (AOP (result), "a", offset++);
6083 emit2 ("inc %s", _pairs[pair].name);
6084 _G.pairs[pair].offset++;
6089 freeAsmop (left, NULL, ic);
6092 freeAsmop (result, NULL, ic);
6095 /*-----------------------------------------------------------------*/
6096 /* genPointerGet - generate code for pointer get */
6097 /*-----------------------------------------------------------------*/
6099 genPointerGet (iCode * ic)
6101 operand *left, *result;
6102 sym_link *type, *etype;
6104 left = IC_LEFT (ic);
6105 result = IC_RESULT (ic);
6107 /* depending on the type of pointer we need to
6108 move it to the correct pointer register */
6109 type = operandType (left);
6110 etype = getSpec (type);
6112 genGenPointerGet (left, result, ic);
6116 isRegOrLit (asmop * aop)
6118 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6123 /*-----------------------------------------------------------------*/
6124 /* genGenPointerSet - stores the value into a pointer location */
6125 /*-----------------------------------------------------------------*/
6127 genGenPointerSet (operand * right,
6128 operand * result, iCode * ic)
6131 sym_link *retype = getSpec (operandType (right));
6132 PAIR_ID pairId = PAIR_HL;
6134 aopOp (result, ic, FALSE, FALSE);
6135 aopOp (right, ic, FALSE, FALSE);
6140 size = AOP_SIZE (right);
6142 /* Handle the exceptions first */
6143 if (isPair (AOP (result)) && size == 1)
6146 const char *l = aopGet (AOP (right), 0, FALSE);
6147 const char *pair = getPairName (AOP (result));
6148 if (canAssignToPtr (l) && isPtr (pair))
6150 emit2 ("ld !*pair,%s", pair, l);
6155 emit2 ("ld !*pair,a", pair);
6160 if ( getPairId( AOP (result)) == PAIR_IY)
6163 const char *l = aopGet (AOP (right), 0, FALSE);
6168 if (canAssignToPtr (l))
6170 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6174 _moveA (aopGet (AOP (right), offset, FALSE));
6175 emit2 ("ld !*iyx,a", offset);
6181 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result))
6187 const char *l = aopGet (AOP (right), offset, FALSE);
6188 if (isRegOrLit (AOP (right)) && !IS_GB)
6190 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
6195 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
6199 emit2 ("inc %s", _pairs[PAIR_HL].name);
6200 _G.pairs[PAIR_HL].offset++;
6205 /* Fixup HL back down */
6206 for (size = AOP_SIZE (right)-1; size; size--)
6208 emit2 ("dec %s", _pairs[PAIR_HL].name);
6213 /* if the operand is already in dptr
6214 then we do nothing else we move the value to dptr */
6215 if (AOP_TYPE (result) != AOP_STR)
6217 fetchPair (pairId, AOP (result));
6219 /* so hl know contains the address */
6220 freeAsmop (result, NULL, ic);
6222 /* if bit then unpack */
6223 if (IS_BITVAR (retype))
6233 const char *l = aopGet (AOP (right), offset, FALSE);
6234 if (isRegOrLit (AOP (right)) && !IS_GB)
6236 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
6241 emit2 ("ld !*pair,a", _pairs[pairId].name);
6245 emit2 ("inc %s", _pairs[pairId].name);
6246 _G.pairs[pairId].offset++;
6252 freeAsmop (right, NULL, ic);
6255 /*-----------------------------------------------------------------*/
6256 /* genPointerSet - stores the value into a pointer location */
6257 /*-----------------------------------------------------------------*/
6259 genPointerSet (iCode * ic)
6261 operand *right, *result;
6262 sym_link *type, *etype;
6264 right = IC_RIGHT (ic);
6265 result = IC_RESULT (ic);
6267 /* depending on the type of pointer we need to
6268 move it to the correct pointer register */
6269 type = operandType (result);
6270 etype = getSpec (type);
6272 genGenPointerSet (right, result, ic);
6275 /*-----------------------------------------------------------------*/
6276 /* genIfx - generate code for Ifx statement */
6277 /*-----------------------------------------------------------------*/
6279 genIfx (iCode * ic, iCode * popIc)
6281 operand *cond = IC_COND (ic);
6284 aopOp (cond, ic, FALSE, TRUE);
6286 /* get the value into acc */
6287 if (AOP_TYPE (cond) != AOP_CRY)
6291 /* the result is now in the accumulator */
6292 freeAsmop (cond, NULL, ic);
6294 /* if there was something to be popped then do it */
6298 /* if the condition is a bit variable */
6299 if (isbit && IS_ITEMP (cond) &&
6301 genIfxJump (ic, SPIL_LOC (cond)->rname);
6302 else if (isbit && !IS_ITEMP (cond))
6303 genIfxJump (ic, OP_SYMBOL (cond)->rname);
6305 genIfxJump (ic, "a");
6310 /*-----------------------------------------------------------------*/
6311 /* genAddrOf - generates code for address of */
6312 /*-----------------------------------------------------------------*/
6314 genAddrOf (iCode * ic)
6316 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
6318 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6320 /* if the operand is on the stack then we
6321 need to get the stack offset of this
6328 if (sym->stack <= 0)
6330 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
6334 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6336 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6340 emit2 ("ld de,!hashedstr", sym->rname);
6341 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
6349 /* if it has an offset then we need to compute it */
6351 emit2 ("ld hl,#%d+%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset, _G.stack.param_offset);
6353 emit2 ("ld hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
6354 emit2 ("add hl,sp");
6358 emit2 ("ld hl,#%s", sym->rname);
6360 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6362 freeAsmop (IC_RESULT (ic), NULL, ic);
6365 /*-----------------------------------------------------------------*/
6366 /* genAssign - generate code for assignment */
6367 /*-----------------------------------------------------------------*/
6369 genAssign (iCode * ic)
6371 operand *result, *right;
6373 unsigned long lit = 0L;
6375 result = IC_RESULT (ic);
6376 right = IC_RIGHT (ic);
6378 /* Dont bother assigning if they are the same */
6379 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6381 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
6385 aopOp (right, ic, FALSE, FALSE);
6386 aopOp (result, ic, TRUE, FALSE);
6388 /* if they are the same registers */
6389 if (sameRegs (AOP (right), AOP (result)))
6391 emitDebug ("; (registers are the same)");
6395 /* if the result is a bit */
6396 if (AOP_TYPE (result) == AOP_CRY)
6398 wassertl (0, "Tried to assign to a bit");
6402 size = AOP_SIZE (result);
6405 if (AOP_TYPE (right) == AOP_LIT)
6407 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6410 if (isPair (AOP (result)))
6412 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
6414 else if ((size > 1) &&
6415 (AOP_TYPE (result) != AOP_REG) &&
6416 (AOP_TYPE (right) == AOP_LIT) &&
6417 !IS_FLOAT (operandType (right)) &&
6420 bool fXored = FALSE;
6422 /* Work from the top down.
6423 Done this way so that we can use the cached copy of 0
6424 in A for a fast clear */
6427 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
6429 if (!fXored && size > 1)
6436 aopPut (AOP (result), "a", offset);
6440 aopPut (AOP (result), "!zero", offset);
6444 aopPut (AOP (result),
6445 aopGet (AOP (right), offset, FALSE),
6450 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
6452 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
6453 aopPut (AOP (result), "l", LSB);
6454 aopPut (AOP (result), "h", MSB16);
6456 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6458 /* Special case. Load into a and d, then load out. */
6459 _moveA (aopGet (AOP (right), 0, FALSE));
6460 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
6461 aopPut (AOP (result), "a", 0);
6462 aopPut (AOP (result), "e", 1);
6464 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6466 /* Special case - simple memcpy */
6467 aopGet (AOP (right), LSB, FALSE);
6470 aopGet (AOP (result), LSB, FALSE);
6474 emit2 ("ld a,(de)");
6475 /* Peephole will optimise this. */
6476 emit2 ("ld (hl),a");
6484 spillPair (PAIR_HL);
6490 /* PENDING: do this check better */
6491 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
6493 _moveA (aopGet (AOP (right), offset, FALSE));
6494 aopPut (AOP (result), "a", offset);
6497 aopPut (AOP (result),
6498 aopGet (AOP (right), offset, FALSE),
6505 freeAsmop (right, NULL, ic);
6506 freeAsmop (result, NULL, ic);
6509 /*-----------------------------------------------------------------*/
6510 /* genJumpTab - genrates code for jump table */
6511 /*-----------------------------------------------------------------*/
6513 genJumpTab (iCode * ic)
6518 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
6519 /* get the condition into accumulator */
6520 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
6523 emit2 ("ld e,%s", l);
6524 emit2 ("ld d,!zero");
6525 jtab = newiTempLabel (NULL);
6527 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
6528 emit2 ("add hl,de");
6529 emit2 ("add hl,de");
6530 emit2 ("add hl,de");
6531 freeAsmop (IC_JTCOND (ic), NULL, ic);
6535 emitLabel (jtab->key + 100);
6536 /* now generate the jump labels */
6537 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
6538 jtab = setNextItem (IC_JTLABELS (ic)))
6539 emit2 ("jp !tlabel", jtab->key + 100);
6542 /*-----------------------------------------------------------------*/
6543 /* genCast - gen code for casting */
6544 /*-----------------------------------------------------------------*/
6546 genCast (iCode * ic)
6548 operand *result = IC_RESULT (ic);
6549 sym_link *rtype = operandType (IC_RIGHT (ic));
6550 operand *right = IC_RIGHT (ic);
6553 /* if they are equivalent then do nothing */
6554 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6557 aopOp (right, ic, FALSE, FALSE);
6558 aopOp (result, ic, FALSE, FALSE);
6560 /* if the result is a bit */
6561 if (AOP_TYPE (result) == AOP_CRY)
6563 wassertl (0, "Tried to cast to a bit");
6566 /* if they are the same size : or less */
6567 if (AOP_SIZE (result) <= AOP_SIZE (right))
6570 /* if they are in the same place */
6571 if (sameRegs (AOP (right), AOP (result)))
6574 /* if they in different places then copy */
6575 size = AOP_SIZE (result);
6579 aopPut (AOP (result),
6580 aopGet (AOP (right), offset, FALSE),
6587 /* So we now know that the size of destination is greater
6588 than the size of the source */
6589 /* we move to result for the size of source */
6590 size = AOP_SIZE (right);
6594 aopPut (AOP (result),
6595 aopGet (AOP (right), offset, FALSE),
6600 /* now depending on the sign of the destination */
6601 size = AOP_SIZE (result) - AOP_SIZE (right);
6602 /* Unsigned or not an integral type - right fill with zeros */
6603 if (SPEC_USIGN (rtype) || !IS_SPEC (rtype) || AOP_TYPE(right)==AOP_CRY)
6606 aopPut (AOP (result), "!zero", offset++);
6610 /* we need to extend the sign :{ */
6611 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
6617 aopPut (AOP (result), "a", offset++);
6621 freeAsmop (right, NULL, ic);
6622 freeAsmop (result, NULL, ic);
6625 /*-----------------------------------------------------------------*/
6626 /* genReceive - generate code for a receive iCode */
6627 /*-----------------------------------------------------------------*/
6629 genReceive (iCode * ic)
6631 if (isOperandInFarSpace (IC_RESULT (ic)) &&
6632 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
6633 IS_TRUE_SYMOP (IC_RESULT (ic))))
6643 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6644 size = AOP_SIZE(IC_RESULT(ic));
6646 for (i = 0; i < size; i++) {
6647 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
6651 freeAsmop (IC_RESULT (ic), NULL, ic);
6656 /** Maximum number of bytes to emit per line. */
6660 /** Context for the byte output chunker. */
6663 unsigned char buffer[DBEMIT_MAX_RUN];
6668 /** Flushes a byte chunker by writing out all in the buffer and
6672 _dbFlush(DBEMITCTX *self)
6679 sprintf(line, ".db 0x%02X", self->buffer[0]);
6681 for (i = 1; i < self->pos; i++)
6683 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
6690 /** Write out another byte, buffering until a decent line is
6694 _dbEmit(DBEMITCTX *self, int c)
6696 if (self->pos == DBEMIT_MAX_RUN)
6700 self->buffer[self->pos++] = c;
6703 /** Context for a simple run length encoder. */
6707 unsigned char buffer[128];
6709 /** runLen may be equivalent to pos. */
6715 RLE_CHANGE_COST = 4,
6719 /** Flush the buffer of a run length encoder by writing out the run or
6720 data that it currently contains.
6723 _rleCommit(RLECTX *self)
6729 memset(&db, 0, sizeof(db));
6731 emit2(".db %u", self->pos);
6733 for (i = 0; i < self->pos; i++)
6735 _dbEmit(&db, self->buffer[i]);
6744 Can get either a run or a block of random stuff.
6745 Only want to change state if a good run comes in or a run ends.
6746 Detecting run end is easy.
6749 Say initial state is in run, len zero, last zero. Then if you get a
6750 few zeros then something else then a short run will be output.
6751 Seems OK. While in run mode, keep counting. While in random mode,
6752 keep a count of the run. If run hits margin, output all up to run,
6753 restart, enter run mode.
6756 /** Add another byte into the run length encoder, flushing as
6757 required. The run length encoder uses the Amiga IFF style, where
6758 a block is prefixed by its run length. A positive length means
6759 the next n bytes pass straight through. A negative length means
6760 that the next byte is repeated -n times. A zero terminates the
6764 _rleAppend(RLECTX *self, int c)
6768 if (c != self->last)
6770 /* The run has stopped. See if it is worthwhile writing it out
6771 as a run. Note that the random data comes in as runs of
6774 if (self->runLen > RLE_CHANGE_COST)
6776 /* Yes, worthwhile. */
6777 /* Commit whatever was in the buffer. */
6779 emit2(".db -%u,0x%02X", self->runLen, self->last);
6783 /* Not worthwhile. Append to the end of the random list. */
6784 for (i = 0; i < self->runLen; i++)
6786 if (self->pos >= RLE_MAX_BLOCK)
6791 self->buffer[self->pos++] = self->last;
6799 if (self->runLen >= RLE_MAX_BLOCK)
6801 /* Commit whatever was in the buffer. */
6804 emit2 (".db -%u,0x%02X", self->runLen, self->last);
6812 _rleFlush(RLECTX *self)
6814 _rleAppend(self, -1);
6821 /** genArrayInit - Special code for initialising an array with constant
6825 genArrayInit (iCode * ic)
6829 int elementSize = 0, eIndex, i;
6830 unsigned val, lastVal;
6834 memset(&rle, 0, sizeof(rle));
6836 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
6838 _saveRegsForCall(ic, 0);
6840 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
6841 emit2 ("call __initrleblock");
6843 type = operandType(IC_LEFT(ic));
6845 if (type && type->next)
6847 elementSize = getSize(type->next);
6851 wassertl (0, "Can't determine element size in genArrayInit.");
6854 iLoop = IC_ARRAYILIST(ic);
6855 lastVal = (unsigned)-1;
6857 /* Feed all the bytes into the run length encoder which will handle
6859 This works well for mixed char data, and for random int and long
6868 for (i = 0; i < ix; i++)
6870 for (eIndex = 0; eIndex < elementSize; eIndex++)
6872 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
6873 _rleAppend(&rle, val);
6878 iLoop = iLoop->next;
6882 /* Mark the end of the run. */
6885 _restoreRegsAfterCall();
6889 freeAsmop (IC_LEFT(ic), NULL, ic);
6893 _swap (PAIR_ID one, PAIR_ID two)
6895 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
6901 emit2 ("ld a,%s", _pairs[one].l);
6902 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
6903 emit2 ("ld %s,a", _pairs[two].l);
6904 emit2 ("ld a,%s", _pairs[one].h);
6905 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
6906 emit2 ("ld %s,a", _pairs[two].h);
6910 /* The problem is that we may have all three pairs used and they may
6911 be needed in a different order.
6916 hl = hl => unity, fine
6920 hl = hl hl = hl, swap de <=> bc
6928 hl = bc de = de, swap bc <=> hl
6936 hl = de bc = bc, swap hl <=> de
6941 * Any pair = pair are done last
6942 * Any pair = iTemp are done last
6943 * Any swaps can be done any time
6951 So how do we detect the cases?
6952 How about a 3x3 matrix?
6956 x x x x (Fourth for iTemp/other)
6958 First determin which mode to use by counting the number of unity and
6961 Two - Assign the pair first, then the rest
6962 One - Swap the two, then the rest
6966 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
6968 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
6970 PAIR_BC, PAIR_HL, PAIR_DE
6972 int i, j, nunity = 0;
6973 memset (ids, PAIR_INVALID, sizeof (ids));
6976 wassert (nparams == 3);
6978 /* First save everything that needs to be saved. */
6979 _saveRegsForCall (ic, 0);
6981 /* Loading HL first means that DE is always fine. */
6982 for (i = 0; i < nparams; i++)
6984 aopOp (pparams[i], ic, FALSE, FALSE);
6985 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
6988 /* Count the number of unity or iTemp assigns. */
6989 for (i = 0; i < 3; i++)
6991 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
6999 /* Any order, fall through. */
7001 else if (nunity == 2)
7003 /* One is assigned. Pull it out and assign. */
7004 for (i = 0; i < 3; i++)
7006 for (j = 0; j < NUM_PAIRS; j++)
7008 if (ids[dest[i]][j] == TRUE)
7010 /* Found it. See if it's the right one. */
7011 if (j == PAIR_INVALID || j == dest[i])
7017 fetchPair(dest[i], AOP (pparams[i]));
7024 else if (nunity == 1)
7026 /* Find the pairs to swap. */
7027 for (i = 0; i < 3; i++)
7029 for (j = 0; j < NUM_PAIRS; j++)
7031 if (ids[dest[i]][j] == TRUE)
7033 if (j == PAIR_INVALID || j == dest[i])
7048 int next = getPairId (AOP (pparams[0]));
7049 emit2 ("push %s", _pairs[next].name);
7051 if (next == dest[1])
7053 fetchPair (dest[1], AOP (pparams[1]));
7054 fetchPair (dest[2], AOP (pparams[2]));
7058 fetchPair (dest[2], AOP (pparams[2]));
7059 fetchPair (dest[1], AOP (pparams[1]));
7061 emit2 ("pop %s", _pairs[dest[0]].name);
7064 /* Finally pull out all of the iTemps */
7065 for (i = 0; i < 3; i++)
7067 if (ids[dest[i]][PAIR_INVALID] == 1)
7069 fetchPair (dest[i], AOP (pparams[i]));
7075 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
7081 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
7085 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7087 setupForBuiltin3 (ic, nParams, pparams);
7089 label = newiTempLabel(NULL);
7091 emitLabel (label->key);
7092 emit2 ("ld a,(hl)");
7095 emit2 ("!shortjp nz,!tlabel ; 1", label->key);
7097 freeAsmop (from, NULL, ic->next);
7098 freeAsmop (to, NULL, ic);
7102 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
7104 operand *from, *to, *count;
7107 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
7112 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7114 setupForBuiltin3 (ic, nParams, pparams);
7118 freeAsmop (count, NULL, ic->next->next);
7119 freeAsmop (from, NULL, ic);
7121 _restoreRegsAfterCall();
7123 /* if we need assign a result value */
7124 if ((IS_ITEMP (IC_RESULT (ic)) &&
7125 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
7126 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
7127 IS_TRUE_SYMOP (IC_RESULT (ic)))
7129 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7130 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
7131 freeAsmop (IC_RESULT (ic), NULL, ic);
7134 freeAsmop (to, NULL, ic->next);
7137 /*-----------------------------------------------------------------*/
7138 /* genBuiltIn - calls the appropriate function to generating code */
7139 /* for a built in function */
7140 /*-----------------------------------------------------------------*/
7141 static void genBuiltIn (iCode *ic)
7143 operand *bi_parms[MAX_BUILTIN_ARGS];
7148 /* get all the arguments for a built in function */
7149 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
7151 /* which function is it */
7152 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
7154 if (strcmp(bif->name,"__builtin_strcpy")==0)
7156 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
7158 else if (strcmp(bif->name,"__builtin_memcpy")==0)
7160 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
7164 wassertl (0, "Unknown builtin function encountered");
7168 /*-----------------------------------------------------------------*/
7169 /* genZ80Code - generate code for Z80 based controllers */
7170 /*-----------------------------------------------------------------*/
7172 genZ80Code (iCode * lic)
7180 _fReturn = _gbz80_return;
7181 _fTmp = _gbz80_return;
7185 _fReturn = _z80_return;
7186 _fTmp = _z80_return;
7189 _G.lines.head = _G.lines.current = NULL;
7191 for (ic = lic; ic; ic = ic->next)
7194 if (cln != ic->lineno)
7196 emit2 ("; %s %d", ic->filename, ic->lineno);
7199 /* if the result is marked as
7200 spilt and rematerializable or code for
7201 this has already been generated then
7203 if (resultRemat (ic) || ic->generated)
7206 /* depending on the operation */
7210 emitDebug ("; genNot");
7215 emitDebug ("; genCpl");
7220 emitDebug ("; genUminus");
7225 emitDebug ("; genIpush");
7230 /* IPOP happens only when trying to restore a
7231 spilt live range, if there is an ifx statement
7232 following this pop then the if statement might
7233 be using some of the registers being popped which
7234 would destory the contents of the register so
7235 we need to check for this condition and handle it */
7237 ic->next->op == IFX &&
7238 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
7240 emitDebug ("; genIfx");
7241 genIfx (ic->next, ic);
7245 emitDebug ("; genIpop");
7251 emitDebug ("; genCall");
7256 emitDebug ("; genPcall");
7261 emitDebug ("; genFunction");
7266 emitDebug ("; genEndFunction");
7267 genEndFunction (ic);
7271 emitDebug ("; genRet");
7276 emitDebug ("; genLabel");
7281 emitDebug ("; genGoto");
7286 emitDebug ("; genPlus");
7291 emitDebug ("; genMinus");
7296 emitDebug ("; genMult");
7301 emitDebug ("; genDiv");
7306 emitDebug ("; genMod");
7311 emitDebug ("; genCmpGt");
7312 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
7316 emitDebug ("; genCmpLt");
7317 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
7324 /* note these two are xlated by algebraic equivalence
7325 during parsing SDCC.y */
7326 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
7327 "got '>=' or '<=' shouldn't have come here");
7331 emitDebug ("; genCmpEq");
7332 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
7336 emitDebug ("; genAndOp");
7341 emitDebug ("; genOrOp");
7346 emitDebug ("; genXor");
7347 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
7351 emitDebug ("; genOr");
7352 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
7356 emitDebug ("; genAnd");
7357 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
7361 emitDebug ("; genInline");
7366 emitDebug ("; genRRC");
7371 emitDebug ("; genRLC");
7376 emitDebug ("; genGetHBIT");
7381 emitDebug ("; genLeftShift");
7386 emitDebug ("; genRightShift");
7390 case GET_VALUE_AT_ADDRESS:
7391 emitDebug ("; genPointerGet");
7397 if (POINTER_SET (ic))
7399 emitDebug ("; genAssign (pointer)");
7404 emitDebug ("; genAssign");
7410 emitDebug ("; genIfx");
7415 emitDebug ("; genAddrOf");
7420 emitDebug ("; genJumpTab");
7425 emitDebug ("; genCast");
7430 emitDebug ("; genReceive");
7435 if (ic->builtinSEND)
7437 emitDebug ("; genBuiltIn");
7442 emitDebug ("; addSet");
7443 addSet (&_G.sendSet, ic);
7448 emitDebug ("; genArrayInit");
7458 /* now we are ready to call the
7459 peep hole optimizer */
7460 if (!options.nopeep)
7461 peepHole (&_G.lines.head);
7463 /* This is unfortunate */
7464 /* now do the actual printing */
7466 FILE *fp = codeOutFile;
7467 if (isInHome () && codeOutFile == code->oFile)
7468 codeOutFile = home->oFile;
7469 printLine (_G.lines.head, codeOutFile);
7470 if (_G.flushStatics)
7473 _G.flushStatics = 0;
7478 freeTrace(&_G.lines.trace);
7479 freeTrace(&_G.trace.aops);
7485 _isPairUsed (iCode * ic, PAIR_ID pairId)
7491 if (bitVectBitValue (ic->rMask, D_IDX))
7493 if (bitVectBitValue (ic->rMask, E_IDX))
7503 fetchLitSpecial (asmop * aop, bool negate, bool xor)
7506 value *val = aop->aopu.aop_lit;
7508 wassert (aop->type == AOP_LIT);
7509 wassert (!IS_FLOAT (val->type));
7511 v = (unsigned long) floatFromVal (val);
7519 tsprintf (buffer, "!immedword", v);
7520 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));