1 /*-------------------------------------------------------------------------
2 gen.c - Z80 specific code generator.
4 Michael Hope <michaelh@juju.net.nz> 2000
5 Based on the mcs51 generator -
6 Sandeep Dutta . sandeep.dutta@usa.net (1998)
7 and - Jean-Louis VERN.jlvern@writeme.com (1999)
9 This program is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 2, or (at your option) any
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 In other words, you are welcome to use, share and improve this program.
25 You are forbidden to forbid anyone else to use, share and improve
26 what you give them. Help stamp out software-hoarding!
28 -------------------------------------------------------------------------*/
31 Benchmarks on dhry.c 2.1 with 32766 loops and a 10ms clock:
33 Base with asm strcpy / strcmp / memcpy: 23198 141 1A14
34 Improved WORD push 22784 144 19AE
35 With label1 on 22694 144 197E
36 With label2 on 22743 144 198A
37 With label3 on 22776 144 1999
38 With label4 on 22776 144 1999
39 With all 'label' on 22661 144 196F
40 With loopInvariant on 20919 156 19AB
41 With loopInduction on Breaks 198B
42 With all working on 20796 158 196C
43 Slightly better genCmp(signed) 20597 159 195B
44 Better reg packing, first peephole 20038 163 1873
45 With assign packing 19281 165 1849
47 With reg params for mul and div 16234 202 162D
49 1. Starting again at 3 Aug 01 34965 93 219C
51 Includes long mul/div in code
52 2. Optimised memcpy for acc use 32102 102 226B
53 3. Optimised strcpy for acc use 27819 117 2237
54 3a Optimised memcpy fun
55 4. Optimised strcmp fun 21999 149 2294
56 5. Optimised strcmp further 21660 151 228C
57 6. Optimised memcpy by unroling 20885 157 2201
58 7. After turning loop induction on 19862 165 236D
59 8. Same as 7 but with more info
60 9. With asm optimised strings 17030 192 2223
62 10 and below are with asm strings off.
64 10 Mucho optimisations 13562 201 1FCC
66 Apparent advantage of turning on regparams:
68 Decent case is push of a constant
69 - ld hl,#n; push hl: (10+11)*nargs
70 2. Cost of pull from stack
71 Using asm with ld hl, etc
72 - ld hl,#2; add hl,sp; (ld bc,(hl); hl+=2)*nargs
74 3. Cost of fixing stack
78 So cost is (10+11+7+6+7+10)*nargs+10+11
80 = 123 for mul, div, strcmp, strcpy
81 Saving of (98298+32766+32766+32766)*123 = 24181308
82 At 192 d/s for 682411768t, speed up to 199. Hmm.
90 #if defined(__BORLANDC__) || defined(_MSC_VER)
91 #define STRCASECMP stricmp
93 #define STRCASECMP strcasecmp
97 #include "SDCCglobl.h"
98 #include "SDCCpeeph.h"
100 #include "SDCCglue.h"
101 #include "newalloc.h"
103 /* This is the down and dirty file with all kinds of kludgy & hacky
104 stuff. This is what it is all about CODE GENERATION for a specific MCU.
105 Some of the routines may be reusable, will have to see */
107 /* Z80 calling convention description.
108 Parameters are passed right to left. As the stack grows downwards,
109 the parameters are arranged in left to right in memory.
110 Parameters may be passed in the HL and DE registers with one
112 PENDING: What if the parameter is a long?
113 Everything is caller saves. i.e. the caller must save any registers
114 that it wants to preserve over the call.
115 GB: The return value is returned in DEHL. DE is normally used as a
116 working register pair. Caller saves allows it to be used for a
118 va args functions do not use register parameters. All arguments
119 are passed on the stack.
120 IX is used as an index register to the top of the local variable
121 area. ix-0 is the top most local variable.
126 /* Set to enable debugging trace statements in the output assembly code. */
130 static char *_z80_return[] =
131 {"l", "h", "e", "d"};
132 static char *_gbz80_return[] =
133 {"e", "d", "l", "h"};
134 static char *_fReceive[] =
135 { "c", "b", "e", "d" };
137 static char **_fReturn;
140 extern FILE *codeOutFile;
148 /** Enum covering all the possible register pairs.
167 } _pairs[NUM_PAIRS] = {
168 { "??1", "?2", "?3" },
173 { "iy", "iyl", "iyh" },
174 { "ix", "ixl", "ixh" }
178 #define ACC_NAME _pairs[PAIR_AF].h
188 /** Code generator persistent data.
192 /** Used to optimised setting up of a pair by remebering what it
193 contains and adjusting instead of reloading where possible.
221 const char *lastFunctionName;
227 /** TRUE if the registers have already been saved. */
245 static const char *aopGet (asmop * aop, int offset, bool bit16);
247 static const char *aopNames[] = {
267 isLastUse (iCode *ic, operand *op)
269 bitVect *uses = bitVectCopy (OP_USES (op));
271 while (!bitVectIsZero (uses))
273 if (bitVectFirstBit (uses) == ic->key)
275 if (bitVectnBitsOn (uses) == 1)
284 bitVectUnSetBit (uses, bitVectFirstBit (uses));
304 _getTempPairName(void)
306 return _pairs[_getTempPairId()].name;
310 isPairInUse (PAIR_ID id, iCode *ic)
314 return bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
316 else if (id == PAIR_BC)
318 return bitVectBitValue (ic->rMask, B_IDX) || bitVectBitValue(ic->rMask, C_IDX);
322 wassertl (0, "Only implemented for DE and BC");
328 isPairInUseNotInRet(PAIR_ID id, iCode *ic)
332 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
336 return bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
340 wassertl (0, "Only implemented for DE");
346 getFreePairId (iCode *ic)
348 if (!isPairInUse (PAIR_BC, ic))
352 else if (IS_Z80 && !isPairInUse (PAIR_DE, ic))
365 /* Clean up the line so that it is 'prettier' */
366 if (strchr (buf, ':'))
368 /* Is a label - cant do anything */
371 /* Change the first (and probably only) ' ' to a tab so
386 _newLineNode (char *line)
390 pl = traceAlloc(&_G.lines.trace, Safe_alloc ( sizeof (lineNode)));
391 pl->line = traceAlloc(&_G.lines.trace, Safe_strdup (line));
397 _vemit2 (const char *szFormat, va_list ap)
401 tvsprintf (buffer, sizeof(buffer), szFormat, ap);
404 _G.lines.current = (_G.lines.current ?
405 connectLine (_G.lines.current, _newLineNode (buffer)) :
406 (_G.lines.head = _newLineNode (buffer)));
408 _G.lines.current->isInline = _G.lines.isInline;
412 emit2 (const char *szFormat,...)
416 va_start (ap, szFormat);
418 _vemit2 (szFormat, ap);
424 emitDebug (const char *szFormat,...)
430 va_start (ap, szFormat);
432 _vemit2 (szFormat, ap);
438 /*-----------------------------------------------------------------*/
439 /* emit2 - writes the code into a file : for now it is simple */
440 /*-----------------------------------------------------------------*/
442 _emit2 (const char *inst, const char *fmt,...)
445 char lb[INITIAL_INLINEASM];
452 sprintf (lb, "%s\t", inst);
453 vsprintf (lb + (strlen (lb)), fmt, ap);
456 vsprintf (lb, fmt, ap);
458 while (isspace (*lbp))
463 _G.lines.current = (_G.lines.current ?
464 connectLine (_G.lines.current, _newLineNode (lb)) :
465 (_G.lines.head = _newLineNode (lb)));
467 _G.lines.current->isInline = _G.lines.isInline;
472 _emitMove(const char *to, const char *from)
474 if (STRCASECMP(to, from) != 0)
476 emit2("ld %s,%s", to, from);
481 // Could leave this to the peephole, but sometimes the peephole is inhibited.
486 aopDump(const char *plabel, asmop *aop)
488 emitDebug("; Dump of %s: type %s size %u", plabel, aopNames[aop->type], aop->size);
492 emitDebug("; aop_stk %d", aop->aopu.aop_stk);
495 /* No information. */
501 _moveA(const char *moveFrom)
503 // Let the peephole optimiser take care of redundent loads
504 _emitMove(ACC_NAME, moveFrom);
514 getPairName (asmop * aop)
516 if (aop->type == AOP_REG)
518 switch (aop->aopu.aop_reg[0]->rIdx)
531 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
534 for (i = 0; i < NUM_PAIRS; i++)
536 if (strcmp(aop->aopu.aop_str[0], _pairs[i].l) == 0)
538 return _pairs[i].name;
542 wassertl (0, "Tried to get the pair name of something that isn't a pair");
547 getPairId (asmop * aop)
551 if (aop->type == AOP_REG)
553 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX) && (aop->aopu.aop_reg[1]->rIdx == B_IDX))
557 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX) && (aop->aopu.aop_reg[1]->rIdx == D_IDX))
561 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX) && (aop->aopu.aop_reg[1]->rIdx == H_IDX))
566 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
569 for (i = 0; i < NUM_PAIRS; i++)
571 if (!strcmp (aop->aopu.aop_str[0], _pairs[i].l) && !strcmp (aop->aopu.aop_str[1], _pairs[i].h))
581 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
585 return (getPairId (aop) != PAIR_INVALID);
588 /** Returns TRUE if the registers used in aop cannot be split into high
591 isUnsplitable (asmop * aop)
593 switch (getPairId (aop))
605 isPtrPair (asmop * aop)
607 PAIR_ID pairId = getPairId (aop);
620 spillPair (PAIR_ID pairId)
622 _G.pairs[pairId].last_type = AOP_INVALID;
623 _G.pairs[pairId].base = NULL;
626 /** Push a register pair onto the stack */
628 genPairPush (asmop * aop)
630 emit2 ("push %s", getPairName (aop));
634 _push (PAIR_ID pairId)
636 emit2 ("push %s", _pairs[pairId].name);
637 _G.stack.pushed += 2;
641 _pop (PAIR_ID pairId)
643 emit2 ("pop %s", _pairs[pairId].name);
644 _G.stack.pushed -= 2;
648 /*-----------------------------------------------------------------*/
649 /* newAsmop - creates a new asmOp */
650 /*-----------------------------------------------------------------*/
652 newAsmop (short type)
656 aop = traceAlloc(&_G.trace.aops, Safe_alloc (sizeof (asmop)));
661 /*-----------------------------------------------------------------*/
662 /* aopForSym - for a true symbol */
663 /*-----------------------------------------------------------------*/
665 aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
672 wassert (sym->etype);
674 space = SPEC_OCLS (sym->etype);
676 /* if already has one */
682 /* Assign depending on the storage class */
683 if (sym->onStack || sym->iaccess)
685 /* The pointer that is used depends on how big the offset is.
686 Normally everything is AOP_STK, but for offsets of < -128 or
687 > 127 on the Z80 an extended stack pointer is used.
689 if (IS_Z80 && (options.ommitFramePtr || sym->stack < INT8MIN || sym->stack > (int)(INT8MAX-getSize (sym->type))))
691 emitDebug ("; AOP_EXSTK for %s", sym->rname);
692 sym->aop = aop = newAsmop (AOP_EXSTK);
696 emitDebug ("; AOP_STK for %s", sym->rname);
697 sym->aop = aop = newAsmop (AOP_STK);
700 aop->size = getSize (sym->type);
701 aop->aopu.aop_stk = sym->stack;
705 /* special case for a function */
706 if (IS_FUNC (sym->type))
708 sym->aop = aop = newAsmop (AOP_IMMD);
709 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup (sym->rname));
716 /* if it is in direct space */
717 if (IN_REGSP (space) && !requires_a)
719 sym->aop = aop = newAsmop (AOP_SFR);
720 aop->aopu.aop_dir = sym->rname;
721 aop->size = getSize (sym->type);
722 emitDebug ("; AOP_SFR for %s", sym->rname);
727 /* only remaining is far space */
728 /* in which case DPTR gets the address */
731 emitDebug ("; AOP_HL for %s", sym->rname);
732 sym->aop = aop = newAsmop (AOP_HL);
736 sym->aop = aop = newAsmop (AOP_IY);
738 aop->size = getSize (sym->type);
739 aop->aopu.aop_dir = sym->rname;
741 /* if it is in code space */
742 if (IN_CODESPACE (space))
748 /*-----------------------------------------------------------------*/
749 /* aopForRemat - rematerialzes an object */
750 /*-----------------------------------------------------------------*/
752 aopForRemat (symbol * sym)
755 iCode *ic = sym->rematiCode;
756 asmop *aop = newAsmop (AOP_IMMD);
760 /* if plus or minus print the right hand side */
761 if (ic->op == '+' || ic->op == '-')
763 /* PENDING: for re-target */
764 sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
767 ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
770 /* we reached the end */
771 sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
775 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
779 /*-----------------------------------------------------------------*/
780 /* regsInCommon - two operands have some registers in common */
781 /*-----------------------------------------------------------------*/
783 regsInCommon (operand * op1, operand * op2)
788 /* if they have registers in common */
789 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
792 sym1 = OP_SYMBOL (op1);
793 sym2 = OP_SYMBOL (op2);
795 if (sym1->nRegs == 0 || sym2->nRegs == 0)
798 for (i = 0; i < sym1->nRegs; i++)
804 for (j = 0; j < sym2->nRegs; j++)
809 if (sym2->regs[j] == sym1->regs[i])
817 /*-----------------------------------------------------------------*/
818 /* operandsEqu - equivalent */
819 /*-----------------------------------------------------------------*/
821 operandsEqu (operand * op1, operand * op2)
825 /* if they not symbols */
826 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
829 sym1 = OP_SYMBOL (op1);
830 sym2 = OP_SYMBOL (op2);
832 /* if both are itemps & one is spilt
833 and the other is not then false */
834 if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
835 sym1->isspilt != sym2->isspilt)
838 /* if they are the same */
842 if (strcmp (sym1->rname, sym2->rname) == 0)
846 /* if left is a tmp & right is not */
847 if (IS_ITEMP (op1) &&
850 (sym1->usl.spillLoc == sym2))
853 if (IS_ITEMP (op2) &&
857 (sym2->usl.spillLoc == sym1))
863 /*-----------------------------------------------------------------*/
864 /* sameRegs - two asmops have the same registers */
865 /*-----------------------------------------------------------------*/
867 sameRegs (asmop * aop1, asmop * aop2)
871 if (aop1->type == AOP_SFR ||
872 aop2->type == AOP_SFR)
878 if (aop1->type != AOP_REG ||
879 aop2->type != AOP_REG)
882 if (aop1->size != aop2->size)
885 for (i = 0; i < aop1->size; i++)
886 if (aop1->aopu.aop_reg[i] !=
887 aop2->aopu.aop_reg[i])
893 /*-----------------------------------------------------------------*/
894 /* aopOp - allocates an asmop for an operand : */
895 /*-----------------------------------------------------------------*/
897 aopOp (operand * op, iCode * ic, bool result, bool requires_a)
906 /* if this a literal */
907 if (IS_OP_LITERAL (op))
909 op->aop = aop = newAsmop (AOP_LIT);
910 aop->aopu.aop_lit = op->operand.valOperand;
911 aop->size = getSize (operandType (op));
915 /* if already has a asmop then continue */
921 /* if the underlying symbol has a aop */
922 if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
924 op->aop = OP_SYMBOL (op)->aop;
928 /* if this is a true symbol */
929 if (IS_TRUE_SYMOP (op))
931 op->aop = aopForSym (ic, OP_SYMBOL (op), result, requires_a);
935 /* this is a temporary : this has
941 e) can be a return use only */
943 sym = OP_SYMBOL (op);
945 /* if the type is a conditional */
946 if (sym->regType == REG_CND)
948 aop = op->aop = sym->aop = newAsmop (AOP_CRY);
953 /* if it is spilt then two situations
955 b) has a spill location */
956 if (sym->isspilt || sym->nRegs == 0)
958 /* rematerialize it NOW */
961 sym->aop = op->aop = aop =
963 aop->size = getSize (sym->type);
970 aop = op->aop = sym->aop = newAsmop (AOP_STR);
971 aop->size = getSize (sym->type);
972 for (i = 0; i < 4; i++)
973 aop->aopu.aop_str[i] = _fReturn[i];
979 if (sym->accuse == ACCUSE_A)
981 aop = op->aop = sym->aop = newAsmop (AOP_ACC);
982 aop->size = getSize (sym->type);
983 wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
985 aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
987 else if (sym->accuse == ACCUSE_SCRATCH)
989 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
990 aop->size = getSize (sym->type);
991 wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
992 aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
993 aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
995 else if (sym->accuse == ACCUSE_IY)
997 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
998 aop->size = getSize (sym->type);
999 wassertl(aop->size <= 2, "Internal error: Caching in IY, but too big to fit in IY");
1000 aop->aopu.aop_str[0] = _pairs[PAIR_IY].l;
1001 aop->aopu.aop_str[1] = _pairs[PAIR_IY].h;
1005 wassertl (0, "Marked as being allocated into A or HL but is actually in neither");
1010 /* else spill location */
1011 if (sym->usl.spillLoc && getSize(sym->type) != getSize(sym->usl.spillLoc->type)) {
1012 /* force a new aop if sizes differ */
1013 sym->usl.spillLoc->aop = NULL;
1015 sym->aop = op->aop = aop =
1016 aopForSym (ic, sym->usl.spillLoc, result, requires_a);
1017 wassertl (aop->size >= getSize (sym->type), "Operand doesn't fit in the spill location");
1018 aop->size = getSize (sym->type);
1022 /* must be in a register */
1023 sym->aop = op->aop = aop = newAsmop (AOP_REG);
1024 aop->size = sym->nRegs;
1025 for (i = 0; i < sym->nRegs; i++)
1026 aop->aopu.aop_reg[i] = sym->regs[i];
1029 /*-----------------------------------------------------------------*/
1030 /* freeAsmop - free up the asmop given to an operand */
1031 /*----------------------------------------------------------------*/
1033 freeAsmop (operand * op, asmop * aaop, iCode * ic)
1050 if (aop->type == AOP_PAIRPTR && IS_Z80 && aop->aopu.aop_pairId == PAIR_DE)
1052 _pop (aop->aopu.aop_pairId);
1055 if (getPairId (aop) == PAIR_HL)
1057 spillPair (PAIR_HL);
1061 /* all other cases just dealloc */
1067 OP_SYMBOL (op)->aop = NULL;
1068 /* if the symbol has a spill */
1070 SPIL_LOC (op)->aop = NULL;
1077 isLitWord (asmop * aop)
1079 /* if (aop->size != 2)
1092 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
1094 /* depending on type */
1100 /* PENDING: for re-target */
1103 tsprintf (buffer, sizeof(buffer),
1104 "!hashedstr + %d", aop->aopu.aop_immd, offset);
1106 else if (offset == 0)
1108 tsprintf (buffer, sizeof(buffer),
1109 "%s", aop->aopu.aop_immd);
1113 tsprintf (buffer, sizeof(buffer),
1114 "%s + %d", aop->aopu.aop_immd, offset);
1116 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1120 value *val = aop->aopu.aop_lit;
1121 /* if it is a float then it gets tricky */
1122 /* otherwise it is fairly simple */
1123 if (!IS_FLOAT (val->type))
1125 unsigned long v = (unsigned long) floatFromVal (val);
1131 else if (offset == 0)
1137 wassertl(0, "Encountered an invalid offset while fetching a literal");
1141 tsprintf (buffer, sizeof(buffer), "!immedword", v);
1143 tsprintf (buffer, sizeof(buffer), "!constword", v);
1145 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1156 /* it is type float */
1157 fl.f = (float) floatFromVal (val);
1159 #ifdef WORDS_BIGENDIAN
1160 i = fl.c[3-offset] | (fl.c[3-offset-1]<<8);
1162 i = fl.c[offset] | (fl.c[offset+1]<<8);
1165 tsprintf (buffer, sizeof(buffer), "!immedword", i);
1167 tsprintf (buffer, sizeof(buffer), "!constword", i);
1169 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1178 aopGetWord (asmop * aop, int offset)
1180 return aopGetLitWordLong (aop, offset, TRUE);
1184 isPtr (const char *s)
1186 if (!strcmp (s, "hl"))
1188 if (!strcmp (s, "ix"))
1190 if (!strcmp (s, "iy"))
1196 adjustPair (const char *pair, int *pold, int new)
1202 emit2 ("inc %s", pair);
1207 emit2 ("dec %s", pair);
1215 spillPair (PAIR_HL);
1216 spillPair (PAIR_IY);
1220 requiresHL (asmop * aop)
1236 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1238 const char *l, *base;
1239 const char *pair = _pairs[pairId].name;
1240 l = aopGetLitWordLong (left, offset, FALSE);
1241 base = aopGetLitWordLong (left, 0, FALSE);
1242 wassert (l && pair && base);
1246 if (pairId == PAIR_HL || pairId == PAIR_IY)
1248 if (_G.pairs[pairId].last_type == left->type)
1250 if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1252 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1254 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1257 if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
1264 _G.pairs[pairId].last_type = left->type;
1265 _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1266 _G.pairs[pairId].offset = offset;
1268 /* Both a lit on the right and a true symbol on the left */
1269 emit2 ("ld %s,!hashedstr", pair, l);
1273 makeFreePairId (iCode *ic, bool *pisUsed)
1279 if (!bitVectBitValue (ic->rMask, B_IDX) && !bitVectBitValue(ic->rMask, C_IDX))
1283 else if (IS_Z80 && !bitVectBitValue (ic->rMask, D_IDX) && !bitVectBitValue(ic->rMask, E_IDX))
1301 fetchPairLong (PAIR_ID pairId, asmop * aop, iCode *ic, int offset)
1303 /* if this is remateriazable */
1304 if (isLitWord (aop)) {
1305 fetchLitPair (pairId, aop, offset);
1309 if (getPairId (aop) == pairId)
1313 /* we need to get it byte by byte */
1314 else if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1315 aopGet (aop, offset, FALSE);
1316 switch (aop->size - offset) {
1318 emit2 ("ld l,!*hl");
1319 emit2 ("ld h,!immedbyte", 0);
1322 // PENDING: Requires that you are only fetching two bytes.
1325 emit2 ("ld h,!*hl");
1329 wassertl (0, "Attempted to fetch too much data into HL");
1333 else if (IS_Z80 && aop->type == AOP_IY) {
1334 /* Instead of fetching relative to IY, just grab directly
1335 from the address IY refers to */
1336 char *l = aopGetLitWordLong (aop, offset, FALSE);
1338 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1340 if (aop->size < 2) {
1341 emit2("ld %s,!zero", _pairs[pairId].h);
1344 else if (pairId == PAIR_IY)
1348 emit2 ("push %s", _pairs[getPairId(aop)].name);
1354 PAIR_ID id = makeFreePairId (ic, &isUsed);
1357 /* Can't load into parts, so load into HL then exchange. */
1358 emit2 ("ld %s,%s", _pairs[id].l, aopGet (aop, offset, FALSE));
1359 emit2 ("ld %s,%s", _pairs[id].h, aopGet (aop, offset + 1, FALSE));
1360 emit2 ("push %s", _pairs[id].name);
1366 else if (isUnsplitable(aop))
1368 emit2("push %s", _pairs[getPairId(aop)].name);
1369 emit2("pop %s", _pairs[pairId].name);
1373 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1374 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1376 /* PENDING: check? */
1377 if (pairId == PAIR_HL)
1378 spillPair (PAIR_HL);
1383 fetchPair (PAIR_ID pairId, asmop * aop)
1385 fetchPairLong (pairId, aop, NULL, 0);
1389 fetchHL (asmop * aop)
1391 fetchPair (PAIR_HL, aop);
1395 setupPairFromSP (PAIR_ID id, int offset)
1397 wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
1399 if (offset < INT8MIN || offset > INT8MAX)
1401 emit2 ("ld hl,!immedword", offset);
1402 emit2 ("add hl,sp");
1406 emit2 ("!ldahlsp", offset);
1411 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1416 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
1417 fetchLitPair (pairId, aop, 0);
1421 wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
1423 fetchLitPair (pairId, aop, offset);
1424 _G.pairs[pairId].offset = offset;
1428 wassertl (IS_Z80, "Only the Z80 has an extended stack");
1429 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
1432 int offset = aop->aopu.aop_stk + _G.stack.offset;
1434 if (_G.pairs[pairId].last_type == aop->type &&
1435 _G.pairs[pairId].offset == offset)
1441 /* PENDING: Do this better. */
1442 sprintf (buffer, "%d", offset + _G.stack.pushed);
1443 emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
1444 emit2 ("add %s,sp", _pairs[pairId].name);
1445 _G.pairs[pairId].last_type = aop->type;
1446 _G.pairs[pairId].offset = offset;
1453 /* Doesnt include _G.stack.pushed */
1454 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1456 if (aop->aopu.aop_stk > 0)
1458 abso += _G.stack.param_offset;
1460 assert (pairId == PAIR_HL);
1461 /* In some cases we can still inc or dec hl */
1462 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1464 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1468 setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
1470 _G.pairs[pairId].offset = abso;
1475 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
1481 _G.pairs[pairId].last_type = aop->type;
1487 emit2 ("!tlabeldef", key);
1491 /*-----------------------------------------------------------------*/
1492 /* aopGet - for fetching value of the aop */
1493 /*-----------------------------------------------------------------*/
1495 aopGet (asmop * aop, int offset, bool bit16)
1497 // char *s = buffer;
1499 /* offset is greater than size then zero */
1500 /* PENDING: this seems a bit screwed in some pointer cases. */
1501 if (offset > (aop->size - 1) &&
1502 aop->type != AOP_LIT)
1504 tsprintf (buffer, sizeof(buffer), "!zero");
1505 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1508 /* depending on type */
1512 /* PENDING: re-target */
1514 tsprintf (buffer, sizeof(buffer), "!immedwords", aop->aopu.aop_immd);
1519 tsprintf (buffer, sizeof(buffer), "!bankimmeds", aop->aopu.aop_immd);
1522 tsprintf (buffer, sizeof(buffer), "!msbimmeds", aop->aopu.aop_immd);
1525 tsprintf (buffer, sizeof(buffer), "!lsbimmeds", aop->aopu.aop_immd);
1528 wassertl (0, "Fetching from beyond the limits of an immediate value.");
1531 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1535 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1536 SNPRINTF (buffer, sizeof(buffer), "a");
1538 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1542 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1543 SNPRINTF (buffer, sizeof(buffer), "a");
1545 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1548 return aop->aopu.aop_reg[offset]->name;
1552 setupPair (PAIR_HL, aop, offset);
1553 tsprintf (buffer, sizeof(buffer), "!*hl");
1555 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
1559 setupPair (PAIR_IY, aop, offset);
1560 tsprintf (buffer, sizeof(buffer), "!*iyx", offset);
1562 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1566 setupPair (PAIR_IY, aop, offset);
1567 tsprintf (buffer, sizeof(buffer), "!*iyx", offset, offset);
1569 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1574 setupPair (PAIR_HL, aop, offset);
1575 tsprintf (buffer, sizeof(buffer), "!*hl");
1579 if (aop->aopu.aop_stk >= 0)
1580 offset += _G.stack.param_offset;
1581 tsprintf (buffer, sizeof(buffer),
1582 "!*ixx", aop->aopu.aop_stk + offset);
1585 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1588 wassertl (0, "Tried to fetch from a bit variable");
1597 tsprintf(buffer, sizeof(buffer), "!zero");
1598 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1602 wassert (offset < 2);
1603 return aop->aopu.aop_str[offset];
1606 return aopLiteral (aop->aopu.aop_lit, offset);
1610 unsigned long v = aop->aopu.aop_simplelit;
1613 tsprintf (buffer, sizeof(buffer),
1614 "!immedbyte", (unsigned int) v & 0xff);
1616 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1620 return aop->aopu.aop_str[offset];
1623 setupPair (aop->aopu.aop_pairId, aop, offset);
1624 SNPRINTF (buffer, sizeof(buffer),
1625 "(%s)", _pairs[aop->aopu.aop_pairId].name);
1627 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1632 wassertl (0, "aopget got unsupported aop->type");
1637 isRegString (const char *s)
1639 if (!strcmp (s, "b") ||
1651 isConstant (const char *s)
1653 /* This is a bit of a hack... */
1654 return (*s == '#' || *s == '$');
1658 canAssignToPtr (const char *s)
1660 if (isRegString (s))
1667 /*-----------------------------------------------------------------*/
1668 /* aopPut - puts a string for a aop */
1669 /*-----------------------------------------------------------------*/
1671 aopPut (asmop * aop, const char *s, int offset)
1675 if (aop->size && offset > (aop->size - 1))
1677 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1678 "aopPut got offset > aop->size");
1683 tsprintf(buffer2, sizeof(buffer2), s);
1686 /* will assign value to value */
1687 /* depending on where it is ofcourse */
1693 if (strcmp (s, "a"))
1694 emit2 ("ld a,%s", s);
1695 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1700 if (strcmp (s, "a"))
1701 emit2 ("ld a,%s", s);
1702 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1706 if (!strcmp (s, "!*hl"))
1707 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1710 aop->aopu.aop_reg[offset]->name, s);
1715 if (!canAssignToPtr (s))
1717 emit2 ("ld a,%s", s);
1718 setupPair (PAIR_IY, aop, offset);
1719 emit2 ("ld !*iyx,a", offset);
1723 setupPair (PAIR_IY, aop, offset);
1724 emit2 ("ld !*iyx,%s", offset, s);
1730 /* PENDING: for re-target */
1731 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1733 emit2 ("ld a,!*hl");
1736 setupPair (PAIR_HL, aop, offset);
1738 emit2 ("ld !*hl,%s", s);
1743 if (!canAssignToPtr (s))
1745 emit2 ("ld a,%s", s);
1746 setupPair (PAIR_IY, aop, offset);
1747 emit2 ("ld !*iyx,a", offset);
1751 setupPair (PAIR_IY, aop, offset);
1752 emit2 ("ld !*iyx,%s", offset, s);
1759 /* PENDING: re-target */
1760 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1762 emit2 ("ld a,!*hl");
1765 setupPair (PAIR_HL, aop, offset);
1766 if (!canAssignToPtr (s))
1768 emit2 ("ld a,%s", s);
1769 emit2 ("ld !*hl,a");
1772 emit2 ("ld !*hl,%s", s);
1776 if (aop->aopu.aop_stk >= 0)
1777 offset += _G.stack.param_offset;
1778 if (!canAssignToPtr (s))
1780 emit2 ("ld a,%s", s);
1781 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
1785 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
1791 /* if bit variable */
1792 if (!aop->aopu.aop_dir)
1794 emit2 ("ld a,!zero");
1799 /* In bit space but not in C - cant happen */
1800 wassertl (0, "Tried to write into a bit variable");
1806 if (strcmp (aop->aopu.aop_str[offset], s))
1808 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1814 if (!offset && (strcmp (s, "acc") == 0))
1818 wassertl (0, "Tried to access past the end of A");
1822 if (strcmp (aop->aopu.aop_str[offset], s))
1823 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1828 wassert (offset < 2);
1829 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1833 setupPair (aop->aopu.aop_pairId, aop, offset);
1834 emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
1838 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1839 "aopPut got unsupported aop->type");
1844 #define AOP(op) op->aop
1845 #define AOP_TYPE(op) AOP(op)->type
1846 #define AOP_SIZE(op) AOP(op)->size
1847 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
1850 commitPair (asmop * aop, PAIR_ID id)
1852 /* PENDING: Verify this. */
1853 if (id == PAIR_HL && requiresHL (aop) && IS_GB)
1857 aopPut (aop, "a", 0);
1858 aopPut (aop, "d", 1);
1863 if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
1865 char *l = aopGetLitWordLong (aop, 0, FALSE);
1868 emit2 ("ld (%s),%s", l, _pairs[id].name);
1872 aopPut (aop, _pairs[id].l, 0);
1873 aopPut (aop, _pairs[id].h, 1);
1878 /*-----------------------------------------------------------------*/
1879 /* getDataSize - get the operand data size */
1880 /*-----------------------------------------------------------------*/
1882 getDataSize (operand * op)
1885 size = AOP_SIZE (op);
1889 wassertl (0, "Somehow got a three byte data pointer");
1894 /*-----------------------------------------------------------------*/
1895 /* movLeft2Result - move byte from left to result */
1896 /*-----------------------------------------------------------------*/
1898 movLeft2Result (operand * left, int offl,
1899 operand * result, int offr, int sign)
1903 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
1905 l = aopGet (AOP (left), offl, FALSE);
1909 aopPut (AOP (result), l, offr);
1913 if (getDataSize (left) == offl + 1)
1915 emit2 ("ld a,%s", l);
1916 aopPut (AOP (result), "a", offr);
1923 movLeft2ResultLong (operand * left, int offl,
1924 operand * result, int offr, int sign,
1929 movLeft2Result (left, offl, result, offr, sign);
1933 wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
1934 wassertl (size == 2, "Only implemented for two bytes or one");
1936 if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
1938 emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
1939 emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
1941 spillPair (PAIR_HL);
1943 else if ( getPairId ( AOP (result)) == PAIR_IY)
1945 PAIR_ID id = getPairId (AOP (left));
1946 if (id != PAIR_INVALID)
1948 emit2("push %s", _pairs[id].name);
1959 movLeft2Result (left, offl, result, offr, sign);
1960 movLeft2Result (left, offl+1, result, offr+1, sign);
1965 /** Put Acc into a register set
1968 outAcc (operand * result)
1971 size = getDataSize (result);
1974 aopPut (AOP (result), "a", 0);
1977 /* unsigned or positive */
1980 aopPut (AOP (result), "!zero", offset++);
1985 /** Take the value in carry and put it into a register
1988 outBitCLong (operand * result, bool swap_sense)
1990 /* if the result is bit */
1991 if (AOP_TYPE (result) == AOP_CRY)
1993 wassertl (0, "Tried to write carry to a bit");
1997 emit2 ("ld a,!zero");
2000 emit2 ("xor a,!immedbyte", 1);
2006 outBitC (operand * result)
2008 outBitCLong (result, FALSE);
2011 /*-----------------------------------------------------------------*/
2012 /* toBoolean - emit code for orl a,operator(sizeop) */
2013 /*-----------------------------------------------------------------*/
2015 _toBoolean (operand * oper)
2017 int size = AOP_SIZE (oper);
2021 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
2024 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
2028 if (AOP (oper)->type != AOP_ACC)
2031 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
2036 /*-----------------------------------------------------------------*/
2037 /* genNotFloat - generates not for float operations */
2038 /*-----------------------------------------------------------------*/
2040 genNotFloat (operand * op, operand * res)
2045 emitDebug ("; genNotFloat");
2047 /* we will put 127 in the first byte of
2049 aopPut (AOP (res), "!immedbyte", 0x7F);
2050 size = AOP_SIZE (op) - 1;
2053 _moveA (aopGet (op->aop, offset++, FALSE));
2057 emit2 ("or a,%s", aopGet (op->aop, offset++, FALSE));
2060 tlbl = newiTempLabel (NULL);
2061 aopPut (res->aop, "!one", 1);
2062 emit2 ("!shortjp z !tlabel", tlbl->key + 100);
2063 aopPut (res->aop, "!zero", 1);
2065 emitLabel(tlbl->key + 100);
2067 size = res->aop->size - 2;
2069 /* put zeros in the rest */
2071 aopPut (res->aop, "!zero", offset++);
2074 /*-----------------------------------------------------------------*/
2075 /* genNot - generate code for ! operation */
2076 /*-----------------------------------------------------------------*/
2080 sym_link *optype = operandType (IC_LEFT (ic));
2082 /* assign asmOps to operand & result */
2083 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
2084 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2086 /* if in bit space then a special case */
2087 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2089 wassertl (0, "Tried to negate a bit");
2092 /* if type float then do float */
2093 if (IS_FLOAT (optype))
2095 genNotFloat (IC_LEFT (ic), IC_RESULT (ic));
2099 _toBoolean (IC_LEFT (ic));
2104 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
2105 emit2 ("sub a,!one");
2106 outBitC (IC_RESULT (ic));
2109 /* release the aops */
2110 freeAsmop (IC_LEFT (ic), NULL, ic);
2111 freeAsmop (IC_RESULT (ic), NULL, ic);
2114 /*-----------------------------------------------------------------*/
2115 /* genCpl - generate code for complement */
2116 /*-----------------------------------------------------------------*/
2124 /* assign asmOps to operand & result */
2125 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2126 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2128 /* if both are in bit space then
2130 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2131 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2133 wassertl (0, "Left and the result are in bit space");
2136 size = AOP_SIZE (IC_RESULT (ic));
2139 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2142 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2145 /* release the aops */
2146 freeAsmop (IC_LEFT (ic), NULL, ic);
2147 freeAsmop (IC_RESULT (ic), NULL, ic);
2151 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
2158 store de into result
2163 store de into result
2165 const char *first = isAdd ? "add" : "sub";
2166 const char *later = isAdd ? "adc" : "sbc";
2168 wassertl (IS_GB, "Code is only relevent to the gbz80");
2169 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
2171 fetchPair (PAIR_DE, left);
2174 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
2177 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2180 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2181 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2183 fetchPairLong (PAIR_DE, left, NULL, MSB24);
2184 aopGet (right, MSB24, FALSE);
2188 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2191 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2193 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2194 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2198 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2200 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2203 /*-----------------------------------------------------------------*/
2204 /* genUminusFloat - unary minus for floating points */
2205 /*-----------------------------------------------------------------*/
2207 genUminusFloat (operand * op, operand * result)
2209 int size, offset = 0;
2211 emitDebug("; genUminusFloat");
2213 /* for this we just need to flip the
2214 first it then copy the rest in place */
2215 size = AOP_SIZE (op) - 1;
2217 _moveA(aopGet (AOP (op), MSB32, FALSE));
2219 emit2("xor a,!immedbyte", 0x80);
2220 aopPut (AOP (result), "a", MSB32);
2224 aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2229 /*-----------------------------------------------------------------*/
2230 /* genUminus - unary minus code generation */
2231 /*-----------------------------------------------------------------*/
2233 genUminus (iCode * ic)
2236 sym_link *optype, *rtype;
2239 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2240 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2242 /* if both in bit space then special
2244 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2245 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2247 wassertl (0, "Left and right are in bit space");
2251 optype = operandType (IC_LEFT (ic));
2252 rtype = operandType (IC_RESULT (ic));
2254 /* if float then do float stuff */
2255 if (IS_FLOAT (optype))
2257 genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2261 /* otherwise subtract from zero */
2262 size = AOP_SIZE (IC_LEFT (ic));
2264 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2266 /* Create a new asmop with value zero */
2267 asmop *azero = newAsmop (AOP_SIMPLELIT);
2268 azero->aopu.aop_simplelit = 0;
2270 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2278 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2279 emit2 ("ld a,!zero");
2280 emit2 ("sbc a,%s", l);
2281 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2284 /* if any remaining bytes in the result */
2285 /* we just need to propagate the sign */
2286 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2291 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2295 /* release the aops */
2296 freeAsmop (IC_LEFT (ic), NULL, ic);
2297 freeAsmop (IC_RESULT (ic), NULL, ic);
2300 /*-----------------------------------------------------------------*/
2301 /* assignResultValue - */
2302 /*-----------------------------------------------------------------*/
2304 assignResultValue (operand * oper)
2306 int size = AOP_SIZE (oper);
2309 wassertl (size <= 4, "Got a result that is bigger than four bytes");
2310 topInA = requiresHL (AOP (oper));
2312 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2314 /* We do it the hard way here. */
2316 aopPut (AOP (oper), _fReturn[0], 0);
2317 aopPut (AOP (oper), _fReturn[1], 1);
2319 aopPut (AOP (oper), _fReturn[0], 2);
2320 aopPut (AOP (oper), _fReturn[1], 3);
2326 aopPut (AOP (oper), _fReturn[size], size);
2331 /** Simple restore that doesn't take into account what is used in the
2335 _restoreRegsAfterCall(void)
2337 if (_G.stack.pushedDE)
2340 _G.stack.pushedDE = FALSE;
2342 if (_G.stack.pushedBC)
2345 _G.stack.pushedBC = FALSE;
2347 _G.saves.saved = FALSE;
2351 _saveRegsForCall(iCode *ic, int sendSetSize)
2354 o Stack parameters are pushed before this function enters
2355 o DE and BC may be used in this function.
2356 o HL and DE may be used to return the result.
2357 o HL and DE may be used to send variables.
2358 o DE and BC may be used to store the result value.
2359 o HL may be used in computing the sent value of DE
2360 o The iPushes for other parameters occur before any addSets
2362 Logic: (to be run inside the first iPush or if none, before sending)
2363 o Compute if DE and/or BC are in use over the call
2364 o Compute if DE is used in the send set
2365 o Compute if DE and/or BC are used to hold the result value
2366 o If (DE is used, or in the send set) and is not used in the result, push.
2367 o If BC is used and is not in the result, push
2369 o If DE is used in the send set, fetch
2370 o If HL is used in the send set, fetch
2374 if (_G.saves.saved == FALSE) {
2375 bool deInUse, bcInUse;
2377 bool bcInRet = FALSE, deInRet = FALSE;
2380 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
2382 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2383 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2385 deSending = (sendSetSize > 1);
2387 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2389 if (bcInUse && bcInRet == FALSE) {
2391 _G.stack.pushedBC = TRUE;
2393 if (deInUse && deInRet == FALSE) {
2395 _G.stack.pushedDE = TRUE;
2398 _G.saves.saved = TRUE;
2401 /* Already saved. */
2405 /*-----------------------------------------------------------------*/
2406 /* genIpush - genrate code for pushing this gets a little complex */
2407 /*-----------------------------------------------------------------*/
2409 genIpush (iCode * ic)
2411 int size, offset = 0;
2414 /* if this is not a parm push : ie. it is spill push
2415 and spill push is always done on the local stack */
2418 wassertl(0, "Encountered an unsupported spill push.");
2422 if (_G.saves.saved == FALSE) {
2423 /* Caller saves, and this is the first iPush. */
2424 /* Scan ahead until we find the function that we are pushing parameters to.
2425 Count the number of addSets on the way to figure out what registers
2426 are used in the send set.
2429 iCode *walk = ic->next;
2432 if (walk->op == SEND) {
2435 else if (walk->op == CALL || walk->op == PCALL) {
2444 _saveRegsForCall(walk, nAddSets);
2447 /* Already saved by another iPush. */
2450 /* then do the push */
2451 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2453 size = AOP_SIZE (IC_LEFT (ic));
2455 if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2457 _G.stack.pushed += 2;
2458 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2464 fetchHL (AOP (IC_LEFT (ic)));
2466 spillPair (PAIR_HL);
2467 _G.stack.pushed += 2;
2472 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
2474 spillPair (PAIR_HL);
2475 _G.stack.pushed += 2;
2476 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
2478 spillPair (PAIR_HL);
2479 _G.stack.pushed += 2;
2485 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2487 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2489 emit2 ("ld a,(%s)", l);
2493 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2494 emit2 ("ld a,%s", l);
2502 freeAsmop (IC_LEFT (ic), NULL, ic);
2505 /*-----------------------------------------------------------------*/
2506 /* genIpop - recover the registers: can happen only for spilling */
2507 /*-----------------------------------------------------------------*/
2509 genIpop (iCode * ic)
2514 /* if the temp was not pushed then */
2515 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2518 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2519 size = AOP_SIZE (IC_LEFT (ic));
2520 offset = (size - 1);
2521 if (isPair (AOP (IC_LEFT (ic))))
2523 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2531 spillPair (PAIR_HL);
2532 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2536 freeAsmop (IC_LEFT (ic), NULL, ic);
2539 /* This is quite unfortunate */
2541 setArea (int inHome)
2544 static int lastArea = 0;
2546 if (_G.in_home != inHome) {
2548 const char *sz = port->mem.code_name;
2549 port->mem.code_name = "HOME";
2550 emit2("!area", CODE_NAME);
2551 port->mem.code_name = sz;
2554 emit2("!area", CODE_NAME); */
2555 _G.in_home = inHome;
2566 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2570 symbol *sym = OP_SYMBOL (op);
2572 if (sym->isspilt || sym->nRegs == 0)
2575 aopOp (op, ic, FALSE, FALSE);
2578 if (aop->type == AOP_REG)
2581 for (i = 0; i < aop->size; i++)
2583 if (pairId == PAIR_DE)
2585 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2586 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2588 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2591 else if (pairId == PAIR_BC)
2593 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2594 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2596 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2606 freeAsmop (IC_LEFT (ic), NULL, ic);
2610 /** Emit the code for a call statement
2613 emitCall (iCode * ic, bool ispcall)
2615 sym_link *dtype = operandType (IC_LEFT (ic));
2617 /* if caller saves & we have not saved then */
2623 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2625 /* if send set is not empty then assign */
2630 int nSend = elementsInSet(_G.sendSet);
2631 bool swapped = FALSE;
2633 int _z80_sendOrder[] = {
2638 /* Check if the parameters are swapped. If so route through hl instead. */
2639 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2641 sic = setFirstItem(_G.sendSet);
2642 sic = setNextItem(_G.sendSet);
2644 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2645 /* The second send value is loaded from one the one that holds the first
2646 send, i.e. it is overwritten. */
2647 /* Cache the first in HL, and load the second from HL instead. */
2648 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2649 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2655 for (sic = setFirstItem (_G.sendSet); sic;
2656 sic = setNextItem (_G.sendSet))
2659 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2661 size = AOP_SIZE (IC_LEFT (sic));
2662 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2663 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2665 // PENDING: Mild hack
2666 if (swapped == TRUE && send == 1) {
2668 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2671 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2673 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2676 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2680 freeAsmop (IC_LEFT (sic), NULL, sic);
2687 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2689 werror (W_INDIR_BANKED);
2691 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2693 if (isLitWord (AOP (IC_LEFT (ic))))
2695 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2699 symbol *rlbl = newiTempLabel (NULL);
2700 spillPair (PAIR_HL);
2701 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2703 _G.stack.pushed += 2;
2705 fetchHL (AOP (IC_LEFT (ic)));
2707 emit2 ("!tlabeldef", (rlbl->key + 100));
2708 _G.stack.pushed -= 2;
2710 freeAsmop (IC_LEFT (ic), NULL, ic);
2714 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2715 OP_SYMBOL (IC_LEFT (ic))->rname :
2716 OP_SYMBOL (IC_LEFT (ic))->name;
2717 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2719 emit2 ("call banked_call");
2720 emit2 ("!dws", name);
2721 emit2 ("!dw !bankimmeds", name);
2726 emit2 ("call %s", name);
2731 /* Mark the regsiters as restored. */
2732 _G.saves.saved = FALSE;
2734 /* if we need assign a result value */
2735 if ((IS_ITEMP (IC_RESULT (ic)) &&
2736 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2737 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2738 IS_TRUE_SYMOP (IC_RESULT (ic)))
2741 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2743 assignResultValue (IC_RESULT (ic));
2745 freeAsmop (IC_RESULT (ic), NULL, ic);
2748 /* adjust the stack for parameters if required */
2751 int i = ic->parmBytes;
2753 _G.stack.pushed -= i;
2756 emit2 ("!ldaspsp", i);
2763 emit2 ("ld iy,!immedword", i);
2764 emit2 ("add iy,sp");
2784 if (_G.stack.pushedDE)
2786 bool dInRet = bitVectBitValue(ic->rUsed, D_IDX);
2787 bool eInRet = bitVectBitValue(ic->rUsed, E_IDX);
2789 if (dInRet && eInRet)
2791 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
2795 /* Only restore E */
2802 /* Only restore D */
2810 _G.stack.pushedDE = FALSE;
2813 if (_G.stack.pushedBC)
2815 bool bInRet = bitVectBitValue(ic->rUsed, B_IDX);
2816 bool cInRet = bitVectBitValue(ic->rUsed, C_IDX);
2818 if (bInRet && cInRet)
2820 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
2824 /* Only restore C */
2831 /* Only restore B */
2839 _G.stack.pushedBC = FALSE;
2843 /*-----------------------------------------------------------------*/
2844 /* genCall - generates a call statement */
2845 /*-----------------------------------------------------------------*/
2847 genCall (iCode * ic)
2849 emitCall (ic, FALSE);
2852 /*-----------------------------------------------------------------*/
2853 /* genPcall - generates a call by pointer statement */
2854 /*-----------------------------------------------------------------*/
2856 genPcall (iCode * ic)
2858 emitCall (ic, TRUE);
2861 /*-----------------------------------------------------------------*/
2862 /* resultRemat - result is rematerializable */
2863 /*-----------------------------------------------------------------*/
2865 resultRemat (iCode * ic)
2867 if (SKIP_IC (ic) || ic->op == IFX)
2870 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2872 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2873 if (sym->remat && !POINTER_SET (ic))
2880 extern set *publics;
2882 /*-----------------------------------------------------------------*/
2883 /* genFunction - generated code for function entry */
2884 /*-----------------------------------------------------------------*/
2886 genFunction (iCode * ic)
2888 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2891 bool bcInUse = FALSE;
2892 bool deInUse = FALSE;
2894 setArea (IFFUNC_NONBANKED (sym->type));
2896 /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
2899 _G.receiveOffset = 0;
2901 /* Record the last function name for debugging. */
2902 _G.lastFunctionName = sym->rname;
2904 /* Create the function header */
2905 emit2 ("!functionheader", sym->name);
2906 sprintf (buffer, "%s_start", sym->rname);
2907 emit2 ("!labeldef", buffer);
2908 emit2 ("!functionlabeldef", sym->rname);
2910 if (options.profile)
2912 emit2 ("!profileenter");
2915 ftype = operandType (IC_LEFT (ic));
2917 /* if critical function then turn interrupts off */
2918 if (IFFUNC_ISCRITICAL (ftype))
2921 /* if this is an interrupt service routine then save all potentially used registers. */
2922 if (IFFUNC_ISISR (sym->type))
2927 /* PENDING: callee-save etc */
2929 _G.stack.param_offset = 0;
2931 if (z80_opts.calleeSavesBC)
2936 /* Detect which registers are used. */
2937 if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
2940 for (i = 0; i < sym->regsUsed->size; i++)
2942 if (bitVectBitValue (sym->regsUsed, i))
2956 /* Other systems use DE as a temporary. */
2967 _G.stack.param_offset += 2;
2970 _G.calleeSaves.pushedBC = bcInUse;
2975 _G.stack.param_offset += 2;
2978 _G.calleeSaves.pushedDE = deInUse;
2980 /* adjust the stack for the function */
2981 _G.stack.last = sym->stack;
2983 if (sym->stack && IS_GB && sym->stack > -INT8MIN)
2984 emit2 ("!enterxl", sym->stack);
2985 else if (sym->stack)
2986 emit2 ("!enterx", sym->stack);
2989 _G.stack.offset = sym->stack;
2992 /*-----------------------------------------------------------------*/
2993 /* genEndFunction - generates epilogue for functions */
2994 /*-----------------------------------------------------------------*/
2996 genEndFunction (iCode * ic)
2998 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3000 if (IFFUNC_ISISR (sym->type))
3002 wassertl (0, "Tried to close an interrupt support function");
3006 if (IFFUNC_ISCRITICAL (sym->type))
3009 /* PENDING: calleeSave */
3011 if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
3013 emit2 ("!leavexl", _G.stack.offset);
3015 else if (_G.stack.offset)
3017 emit2 ("!leavex", _G.stack.offset);
3024 if (_G.calleeSaves.pushedDE)
3027 _G.calleeSaves.pushedDE = FALSE;
3030 if (_G.calleeSaves.pushedBC)
3033 _G.calleeSaves.pushedBC = FALSE;
3036 if (options.profile)
3038 emit2 ("!profileexit");
3042 /* Both baned and non-banked just ret */
3045 sprintf (buffer, "%s_end", sym->rname);
3046 emit2 ("!labeldef", buffer);
3048 _G.flushStatics = 1;
3049 _G.stack.pushed = 0;
3050 _G.stack.offset = 0;
3053 /*-----------------------------------------------------------------*/
3054 /* genRet - generate code for return statement */
3055 /*-----------------------------------------------------------------*/
3060 /* Errk. This is a hack until I can figure out how
3061 to cause dehl to spill on a call */
3062 int size, offset = 0;
3064 /* if we have no return value then
3065 just generate the "ret" */
3069 /* we have something to return then
3070 move the return value into place */
3071 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3072 size = AOP_SIZE (IC_LEFT (ic));
3074 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3078 emit2 ("ld de,%s", l);
3082 emit2 ("ld hl,%s", l);
3087 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3089 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3090 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3096 l = aopGet (AOP (IC_LEFT (ic)), offset,
3098 if (strcmp (_fReturn[offset], l))
3099 emit2 ("ld %s,%s", _fReturn[offset++], l);
3103 freeAsmop (IC_LEFT (ic), NULL, ic);
3106 /* generate a jump to the return label
3107 if the next is not the return statement */
3108 if (!(ic->next && ic->next->op == LABEL &&
3109 IC_LABEL (ic->next) == returnLabel))
3111 emit2 ("jp !tlabel", returnLabel->key + 100);
3114 /*-----------------------------------------------------------------*/
3115 /* genLabel - generates a label */
3116 /*-----------------------------------------------------------------*/
3118 genLabel (iCode * ic)
3120 /* special case never generate */
3121 if (IC_LABEL (ic) == entryLabel)
3124 emitLabel (IC_LABEL (ic)->key + 100);
3127 /*-----------------------------------------------------------------*/
3128 /* genGoto - generates a ljmp */
3129 /*-----------------------------------------------------------------*/
3131 genGoto (iCode * ic)
3133 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3136 /*-----------------------------------------------------------------*/
3137 /* genPlusIncr :- does addition with increment if possible */
3138 /*-----------------------------------------------------------------*/
3140 genPlusIncr (iCode * ic)
3142 unsigned int icount;
3143 unsigned int size = getDataSize (IC_RESULT (ic));
3144 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3146 /* will try to generate an increment */
3147 /* if the right side is not a literal
3149 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3152 emitDebug ("; genPlusIncr");
3154 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3156 /* If result is a pair */
3157 if (resultId != PAIR_INVALID)
3159 if (isLitWord (AOP (IC_LEFT (ic))))
3161 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3164 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3166 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3168 PAIR_ID freep = getFreePairId (ic);
3169 if (freep != PAIR_INVALID)
3171 fetchPair (freep, AOP (IC_RIGHT (ic)));
3172 emit2 ("add hl,%s", _pairs[freep].name);
3178 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3179 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3186 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3190 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3194 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3199 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3201 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3202 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3206 /* if the literal value of the right hand side
3207 is greater than 4 then it is not worth it */
3211 /* if increment 16 bits in register */
3212 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3218 symbol *tlbl = NULL;
3219 tlbl = newiTempLabel (NULL);
3222 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3225 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3228 emitLabel (tlbl->key + 100);
3232 /* if the sizes are greater than 1 then we cannot */
3233 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3234 AOP_SIZE (IC_LEFT (ic)) > 1)
3237 /* If the result is in a register then we can load then increment.
3239 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3241 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3244 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3249 /* we can if the aops of the left & result match or
3250 if they are in registers and the registers are the
3252 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3256 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3264 /*-----------------------------------------------------------------*/
3265 /* outBitAcc - output a bit in acc */
3266 /*-----------------------------------------------------------------*/
3268 outBitAcc (operand * result)
3270 symbol *tlbl = newiTempLabel (NULL);
3271 /* if the result is a bit */
3272 if (AOP_TYPE (result) == AOP_CRY)
3274 wassertl (0, "Tried to write A into a bit");
3278 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3279 emit2 ("ld a,!one");
3280 emitLabel (tlbl->key + 100);
3286 couldDestroyCarry (asmop *aop)
3290 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3299 shiftIntoPair (int idx, asmop *aop)
3301 PAIR_ID id = PAIR_INVALID;
3303 wassertl (IS_Z80, "Only implemented for the Z80");
3304 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3316 wassertl (0, "Internal error - hit default case");
3319 emitDebug ("; Shift into pair idx %u", idx);
3323 setupPair (PAIR_HL, aop, 0);
3327 setupPair (PAIR_IY, aop, 0);
3329 emit2 ("pop %s", _pairs[id].name);
3332 aop->type = AOP_PAIRPTR;
3333 aop->aopu.aop_pairId = id;
3334 _G.pairs[id].offset = 0;
3335 _G.pairs[id].last_type = aop->type;
3339 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
3341 wassert (left && right);
3345 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3347 shiftIntoPair (0, right);
3348 shiftIntoPair (1, result);
3350 else if (couldDestroyCarry (right))
3352 shiftIntoPair (0, right);
3354 else if (couldDestroyCarry (result))
3356 shiftIntoPair (0, result);
3365 /*-----------------------------------------------------------------*/
3366 /* genPlus - generates code for addition */
3367 /*-----------------------------------------------------------------*/
3369 genPlus (iCode * ic)
3371 int size, offset = 0;
3373 /* special cases :- */
3375 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3376 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3377 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3379 /* Swap the left and right operands if:
3381 if literal, literal on the right or
3382 if left requires ACC or right is already
3385 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3386 (AOP_NEEDSACC (IC_LEFT (ic))) ||
3387 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3389 operand *t = IC_RIGHT (ic);
3390 IC_RIGHT (ic) = IC_LEFT (ic);
3394 /* if both left & right are in bit
3396 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3397 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3400 wassertl (0, "Tried to add two bits");
3403 /* if left in bit space & right literal */
3404 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3405 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3407 /* Can happen I guess */
3408 wassertl (0, "Tried to add a bit to a literal");
3411 /* if I can do an increment instead
3412 of add then GOOD for ME */
3413 if (genPlusIncr (ic) == TRUE)
3416 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3418 size = getDataSize (IC_RESULT (ic));
3420 /* Special case when left and right are constant */
3421 if (isPair (AOP (IC_RESULT (ic))))
3424 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3425 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3427 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3433 sprintf (buffer, "#(%s + %s)", left, right);
3434 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3439 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3441 /* Fetch into HL then do the add */
3442 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3443 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3445 spillPair (PAIR_HL);
3447 if (left == PAIR_HL && right != PAIR_INVALID)
3449 emit2 ("add hl,%s", _pairs[right].name);
3452 else if (right == PAIR_HL && left != PAIR_INVALID)
3454 emit2 ("add hl,%s", _pairs[left].name);
3457 else if (right != PAIR_INVALID && right != PAIR_HL)
3459 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3460 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3463 else if (left != PAIR_INVALID && left != PAIR_HL)
3465 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3466 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3475 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3477 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3478 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3480 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3485 ld hl,sp+n trashes C so we cant afford to do it during an
3486 add with stack based varibles. Worst case is:
3499 So you cant afford to load up hl if either left, right, or result
3500 is on the stack (*sigh*) The alt is:
3508 Combinations in here are:
3509 * If left or right are in bc then the loss is small - trap later
3510 * If the result is in bc then the loss is also small
3514 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3515 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3516 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3518 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3519 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3520 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3521 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3523 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3525 /* Swap left and right */
3526 operand *t = IC_RIGHT (ic);
3527 IC_RIGHT (ic) = IC_LEFT (ic);
3530 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3532 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3533 emit2 ("add hl,bc");
3537 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3538 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3539 emit2 ("add hl,de");
3541 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3547 /* Be paranoid on the GB with 4 byte variables due to how C
3548 can be trashed by lda hl,n(sp).
3550 _gbz80_emitAddSubLong (ic, TRUE);
3555 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3559 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3561 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3564 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3567 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3571 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3574 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3577 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3579 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3583 freeAsmop (IC_LEFT (ic), NULL, ic);
3584 freeAsmop (IC_RIGHT (ic), NULL, ic);
3585 freeAsmop (IC_RESULT (ic), NULL, ic);
3589 /*-----------------------------------------------------------------*/
3590 /* genMinusDec :- does subtraction with deccrement if possible */
3591 /*-----------------------------------------------------------------*/
3593 genMinusDec (iCode * ic)
3595 unsigned int icount;
3596 unsigned int size = getDataSize (IC_RESULT (ic));
3598 /* will try to generate an increment */
3599 /* if the right side is not a literal we cannot */
3600 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3603 /* if the literal value of the right hand side
3604 is greater than 4 then it is not worth it */
3605 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3608 size = getDataSize (IC_RESULT (ic));
3610 /* if decrement 16 bits in register */
3611 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3612 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3615 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3619 /* If result is a pair */
3620 if (isPair (AOP (IC_RESULT (ic))))
3622 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3624 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3628 /* if increment 16 bits in register */
3629 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3633 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3636 emit2 ("dec %s", _getTempPairName());
3639 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3645 /* if the sizes are greater than 1 then we cannot */
3646 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3647 AOP_SIZE (IC_LEFT (ic)) > 1)
3650 /* we can if the aops of the left & result match or if they are in
3651 registers and the registers are the same */
3652 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3655 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3662 /*-----------------------------------------------------------------*/
3663 /* genMinus - generates code for subtraction */
3664 /*-----------------------------------------------------------------*/
3666 genMinus (iCode * ic)
3668 int size, offset = 0;
3669 unsigned long lit = 0L;
3671 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3672 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3673 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3675 /* special cases :- */
3676 /* if both left & right are in bit space */
3677 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3678 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3680 wassertl (0, "Tried to subtract two bits");
3684 /* if I can do an decrement instead of subtract then GOOD for ME */
3685 if (genMinusDec (ic) == TRUE)
3688 size = getDataSize (IC_RESULT (ic));
3690 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3695 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3699 /* Same logic as genPlus */
3702 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3703 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3704 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3706 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3707 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3708 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3709 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3711 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3712 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3714 if (left == PAIR_INVALID && right == PAIR_INVALID)
3719 else if (right == PAIR_INVALID)
3721 else if (left == PAIR_INVALID)
3724 fetchPair (left, AOP (IC_LEFT (ic)));
3725 /* Order is important. Right may be HL */
3726 fetchPair (right, AOP (IC_RIGHT (ic)));
3728 emit2 ("ld a,%s", _pairs[left].l);
3729 emit2 ("sub a,%s", _pairs[right].l);
3731 emit2 ("ld a,%s", _pairs[left].h);
3732 emit2 ("sbc a,%s", _pairs[right].h);
3734 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
3736 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3738 aopPut (AOP (IC_RESULT (ic)), "e", 0);
3744 /* Be paranoid on the GB with 4 byte variables due to how C
3745 can be trashed by lda hl,n(sp).
3747 _gbz80_emitAddSubLong (ic, FALSE);
3752 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3754 /* if literal, add a,#-lit, else normal subb */
3757 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3758 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3762 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3765 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3769 /* first add without previous c */
3771 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
3773 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3775 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3778 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3779 AOP_SIZE (IC_LEFT (ic)) == 3 &&
3780 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3782 wassertl (0, "Tried to subtract on a long pointer");
3786 freeAsmop (IC_LEFT (ic), NULL, ic);
3787 freeAsmop (IC_RIGHT (ic), NULL, ic);
3788 freeAsmop (IC_RESULT (ic), NULL, ic);
3791 /*-----------------------------------------------------------------*/
3792 /* genMult - generates code for multiplication */
3793 /*-----------------------------------------------------------------*/
3795 genMult (iCode * ic)
3799 /* If true then the final operation should be a subtract */
3800 bool active = FALSE;
3802 /* Shouldn't occur - all done through function calls */
3803 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3804 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3805 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3807 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
3808 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
3809 AOP_SIZE (IC_RESULT (ic)) > 2)
3811 wassertl (0, "Multiplication is handled through support function calls");
3814 /* Swap left and right such that right is a literal */
3815 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
3817 operand *t = IC_RIGHT (ic);
3818 IC_RIGHT (ic) = IC_LEFT (ic);
3822 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
3824 val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
3825 // wassertl (val > 0, "Multiply must be positive");
3826 wassertl (val != 1, "Can't multiply by 1");
3828 if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
3830 _G.stack.pushedDE = TRUE;
3833 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
3835 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
3843 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3848 /* Fully unroled version of mul.s. Not the most efficient.
3850 for (count = 0; count < 16; count++)
3852 if (count != 0 && active)
3854 emit2 ("add hl,hl");
3858 if (active == FALSE)
3865 emit2 ("add hl,de");
3874 if (IS_Z80 && _G.stack.pushedDE)
3877 _G.stack.pushedDE = FALSE;
3880 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3882 freeAsmop (IC_LEFT (ic), NULL, ic);
3883 freeAsmop (IC_RIGHT (ic), NULL, ic);
3884 freeAsmop (IC_RESULT (ic), NULL, ic);
3887 /*-----------------------------------------------------------------*/
3888 /* genDiv - generates code for division */
3889 /*-----------------------------------------------------------------*/
3893 /* Shouldn't occur - all done through function calls */
3894 wassertl (0, "Division is handled through support function calls");
3897 /*-----------------------------------------------------------------*/
3898 /* genMod - generates code for division */
3899 /*-----------------------------------------------------------------*/
3903 /* Shouldn't occur - all done through function calls */
3907 /*-----------------------------------------------------------------*/
3908 /* genIfxJump :- will create a jump depending on the ifx */
3909 /*-----------------------------------------------------------------*/
3911 genIfxJump (iCode * ic, char *jval)
3916 /* if true label then we jump if condition
3920 jlbl = IC_TRUE (ic);
3921 if (!strcmp (jval, "a"))
3925 else if (!strcmp (jval, "c"))
3929 else if (!strcmp (jval, "nc"))
3933 else if (!strcmp (jval, "m"))
3937 else if (!strcmp (jval, "p"))
3943 /* The buffer contains the bit on A that we should test */
3949 /* false label is present */
3950 jlbl = IC_FALSE (ic);
3951 if (!strcmp (jval, "a"))
3955 else if (!strcmp (jval, "c"))
3959 else if (!strcmp (jval, "nc"))
3963 else if (!strcmp (jval, "m"))
3967 else if (!strcmp (jval, "p"))
3973 /* The buffer contains the bit on A that we should test */
3977 /* Z80 can do a conditional long jump */
3978 if (!strcmp (jval, "a"))
3982 else if (!strcmp (jval, "c"))
3985 else if (!strcmp (jval, "nc"))
3988 else if (!strcmp (jval, "m"))
3991 else if (!strcmp (jval, "p"))
3996 emit2 ("bit %s,a", jval);
3998 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
4000 /* mark the icode as generated */
4006 _getPairIdName (PAIR_ID id)
4008 return _pairs[id].name;
4013 /* if unsigned char cmp with lit, just compare */
4015 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4017 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4020 emit2 ("xor a,!immedbyte", 0x80);
4021 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
4024 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4026 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4028 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4029 // Pull left into DE and right into HL
4030 aopGet (AOP(left), LSB, FALSE);
4033 aopGet (AOP(right), LSB, FALSE);
4037 if (size == 0 && sign)
4039 // Highest byte when signed needs the bits flipped
4042 emit2 ("ld a,(de)");
4043 emit2 ("xor !immedbyte", 0x80);
4045 emit2 ("ld a,(hl)");
4046 emit2 ("xor !immedbyte", 0x80);
4050 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4054 emit2 ("ld a,(de)");
4055 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4065 spillPair (PAIR_HL);
4067 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4069 setupPair (PAIR_HL, AOP (left), 0);
4070 aopGet (AOP(right), LSB, FALSE);
4074 if (size == 0 && sign)
4076 // Highest byte when signed needs the bits flipped
4079 emit2 ("ld a,(hl)");
4080 emit2 ("xor !immedbyte", 0x80);
4082 emit2 ("ld a,%d(iy)", offset);
4083 emit2 ("xor !immedbyte", 0x80);
4087 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4091 emit2 ("ld a,(hl)");
4092 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4101 spillPair (PAIR_HL);
4102 spillPair (PAIR_IY);
4106 if (AOP_TYPE (right) == AOP_LIT)
4108 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4109 /* optimize if(x < 0) or if(x >= 0) */
4114 /* No sign so it's always false */
4119 /* Just load in the top most bit */
4120 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4121 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4123 genIfxJump (ifx, "7");
4135 /* First setup h and l contaning the top most bytes XORed */
4136 bool fDidXor = FALSE;
4137 if (AOP_TYPE (left) == AOP_LIT)
4139 unsigned long lit = (unsigned long)
4140 floatFromVal (AOP (left)->aopu.aop_lit);
4141 emit2 ("ld %s,!immedbyte", _fTmp[0],
4142 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4146 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4147 emit2 ("xor a,!immedbyte", 0x80);
4148 emit2 ("ld %s,a", _fTmp[0]);
4151 if (AOP_TYPE (right) == AOP_LIT)
4153 unsigned long lit = (unsigned long)
4154 floatFromVal (AOP (right)->aopu.aop_lit);
4155 emit2 ("ld %s,!immedbyte", _fTmp[1],
4156 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4160 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4161 emit2 ("xor a,!immedbyte", 0x80);
4162 emit2 ("ld %s,a", _fTmp[1]);
4168 /* Do a long subtract */
4171 _moveA (aopGet (AOP (left), offset, FALSE));
4173 if (sign && size == 0)
4175 emit2 ("ld a,%s", _fTmp[0]);
4176 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4180 /* Subtract through, propagating the carry */
4181 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4189 /** Generic compare for > or <
4192 genCmp (operand * left, operand * right,
4193 operand * result, iCode * ifx, int sign)
4195 int size, offset = 0;
4196 unsigned long lit = 0L;
4197 bool swap_sense = FALSE;
4199 /* if left & right are bit variables */
4200 if (AOP_TYPE (left) == AOP_CRY &&
4201 AOP_TYPE (right) == AOP_CRY)
4203 /* Cant happen on the Z80 */
4204 wassertl (0, "Tried to compare two bits");
4208 /* Do a long subtract of right from left. */
4209 size = max (AOP_SIZE (left), AOP_SIZE (right));
4211 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4213 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4214 // Pull left into DE and right into HL
4215 aopGet (AOP(left), LSB, FALSE);
4218 aopGet (AOP(right), LSB, FALSE);
4222 emit2 ("ld a,(de)");
4223 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4232 spillPair (PAIR_HL);
4236 if (AOP_TYPE (right) == AOP_LIT)
4238 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4239 /* optimize if(x < 0) or if(x >= 0) */
4244 /* No sign so it's always false */
4249 /* Just load in the top most bit */
4250 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4251 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4253 genIfxJump (ifx, "7");
4264 genIfxJump (ifx, swap_sense ? "c" : "nc");
4275 _moveA (aopGet (AOP (left), offset, FALSE));
4276 /* Subtract through, propagating the carry */
4277 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4283 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4287 /* Shift the sign bit up into carry */
4290 outBitCLong (result, swap_sense);
4294 /* if the result is used in the next
4295 ifx conditional branch then generate
4296 code a little differently */
4304 genIfxJump (ifx, swap_sense ? "nc" : "c");
4308 genIfxJump (ifx, swap_sense ? "p" : "m");
4313 genIfxJump (ifx, swap_sense ? "nc" : "c");
4320 /* Shift the sign bit up into carry */
4323 outBitCLong (result, swap_sense);
4325 /* leave the result in acc */
4329 /*-----------------------------------------------------------------*/
4330 /* genCmpGt :- greater than comparison */
4331 /*-----------------------------------------------------------------*/
4333 genCmpGt (iCode * ic, iCode * ifx)
4335 operand *left, *right, *result;
4336 sym_link *letype, *retype;
4339 left = IC_LEFT (ic);
4340 right = IC_RIGHT (ic);
4341 result = IC_RESULT (ic);
4343 letype = getSpec (operandType (left));
4344 retype = getSpec (operandType (right));
4345 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4346 /* assign the amsops */
4347 aopOp (left, ic, FALSE, FALSE);
4348 aopOp (right, ic, FALSE, FALSE);
4349 aopOp (result, ic, TRUE, FALSE);
4351 genCmp (right, left, result, ifx, sign);
4353 freeAsmop (left, NULL, ic);
4354 freeAsmop (right, NULL, ic);
4355 freeAsmop (result, NULL, ic);
4358 /*-----------------------------------------------------------------*/
4359 /* genCmpLt - less than comparisons */
4360 /*-----------------------------------------------------------------*/
4362 genCmpLt (iCode * ic, iCode * ifx)
4364 operand *left, *right, *result;
4365 sym_link *letype, *retype;
4368 left = IC_LEFT (ic);
4369 right = IC_RIGHT (ic);
4370 result = IC_RESULT (ic);
4372 letype = getSpec (operandType (left));
4373 retype = getSpec (operandType (right));
4374 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4376 /* assign the amsops */
4377 aopOp (left, ic, FALSE, FALSE);
4378 aopOp (right, ic, FALSE, FALSE);
4379 aopOp (result, ic, TRUE, FALSE);
4381 genCmp (left, right, result, ifx, sign);
4383 freeAsmop (left, NULL, ic);
4384 freeAsmop (right, NULL, ic);
4385 freeAsmop (result, NULL, ic);
4388 /*-----------------------------------------------------------------*/
4389 /* gencjneshort - compare and jump if not equal */
4390 /*-----------------------------------------------------------------*/
4392 gencjneshort (operand * left, operand * right, symbol * lbl)
4394 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4396 unsigned long lit = 0L;
4398 /* Swap the left and right if it makes the computation easier */
4399 if (AOP_TYPE (left) == AOP_LIT)
4406 if (AOP_TYPE (right) == AOP_LIT)
4408 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4411 /* if the right side is a literal then anything goes */
4412 if (AOP_TYPE (right) == AOP_LIT &&
4413 AOP_TYPE (left) != AOP_DIR)
4417 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4422 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4429 emit2 ("jp nz,!tlabel", lbl->key + 100);
4435 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4436 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
4439 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
4440 emit2 ("jp nz,!tlabel", lbl->key + 100);
4445 /* if the right side is in a register or in direct space or
4446 if the left is a pointer register & right is not */
4447 else if (AOP_TYPE (right) == AOP_REG ||
4448 AOP_TYPE (right) == AOP_DIR ||
4449 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
4453 _moveA (aopGet (AOP (left), offset, FALSE));
4454 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
4455 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4457 emit2 ("jp nz,!tlabel", lbl->key + 100);
4460 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4461 emit2 ("jp nz,!tlabel", lbl->key + 100);
4468 /* right is a pointer reg need both a & b */
4469 /* PENDING: is this required? */
4472 _moveA (aopGet (AOP (right), offset, FALSE));
4473 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
4474 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
4480 /*-----------------------------------------------------------------*/
4481 /* gencjne - compare and jump if not equal */
4482 /*-----------------------------------------------------------------*/
4484 gencjne (operand * left, operand * right, symbol * lbl)
4486 symbol *tlbl = newiTempLabel (NULL);
4488 gencjneshort (left, right, lbl);
4491 emit2 ("ld a,!one");
4492 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4493 emitLabel (lbl->key + 100);
4495 emitLabel (tlbl->key + 100);
4498 /*-----------------------------------------------------------------*/
4499 /* genCmpEq - generates code for equal to */
4500 /*-----------------------------------------------------------------*/
4502 genCmpEq (iCode * ic, iCode * ifx)
4504 operand *left, *right, *result;
4506 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4507 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4508 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4510 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4512 /* Swap operands if it makes the operation easier. ie if:
4513 1. Left is a literal.
4515 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4517 operand *t = IC_RIGHT (ic);
4518 IC_RIGHT (ic) = IC_LEFT (ic);
4522 if (ifx && !AOP_SIZE (result))
4525 /* if they are both bit variables */
4526 if (AOP_TYPE (left) == AOP_CRY &&
4527 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4529 wassertl (0, "Tried to compare two bits");
4533 tlbl = newiTempLabel (NULL);
4534 gencjneshort (left, right, tlbl);
4537 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4538 emitLabel (tlbl->key + 100);
4542 /* PENDING: do this better */
4543 symbol *lbl = newiTempLabel (NULL);
4544 emit2 ("!shortjp !tlabel", lbl->key + 100);
4545 emitLabel (tlbl->key + 100);
4546 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4547 emitLabel (lbl->key + 100);
4550 /* mark the icode as generated */
4555 /* if they are both bit variables */
4556 if (AOP_TYPE (left) == AOP_CRY &&
4557 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4559 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4565 gencjne (left, right, newiTempLabel (NULL));
4566 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4573 genIfxJump (ifx, "a");
4576 /* if the result is used in an arithmetic operation
4577 then put the result in place */
4578 if (AOP_TYPE (result) != AOP_CRY)
4583 /* leave the result in acc */
4587 freeAsmop (left, NULL, ic);
4588 freeAsmop (right, NULL, ic);
4589 freeAsmop (result, NULL, ic);
4592 /*-----------------------------------------------------------------*/
4593 /* ifxForOp - returns the icode containing the ifx for operand */
4594 /*-----------------------------------------------------------------*/
4596 ifxForOp (operand * op, iCode * ic)
4598 /* if true symbol then needs to be assigned */
4599 if (IS_TRUE_SYMOP (op))
4602 /* if this has register type condition and
4603 the next instruction is ifx with the same operand
4604 and live to of the operand is upto the ifx only then */
4606 ic->next->op == IFX &&
4607 IC_COND (ic->next)->key == op->key &&
4608 OP_SYMBOL (op)->liveTo <= ic->next->seq)
4614 /*-----------------------------------------------------------------*/
4615 /* genAndOp - for && operation */
4616 /*-----------------------------------------------------------------*/
4618 genAndOp (iCode * ic)
4620 operand *left, *right, *result;
4623 /* note here that && operations that are in an if statement are
4624 taken away by backPatchLabels only those used in arthmetic
4625 operations remain */
4626 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4627 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4628 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4630 /* if both are bit variables */
4631 if (AOP_TYPE (left) == AOP_CRY &&
4632 AOP_TYPE (right) == AOP_CRY)
4634 wassertl (0, "Tried to and two bits");
4638 tlbl = newiTempLabel (NULL);
4640 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
4642 emitLabel (tlbl->key + 100);
4646 freeAsmop (left, NULL, ic);
4647 freeAsmop (right, NULL, ic);
4648 freeAsmop (result, NULL, ic);
4651 /*-----------------------------------------------------------------*/
4652 /* genOrOp - for || operation */
4653 /*-----------------------------------------------------------------*/
4655 genOrOp (iCode * ic)
4657 operand *left, *right, *result;
4660 /* note here that || operations that are in an
4661 if statement are taken away by backPatchLabels
4662 only those used in arthmetic operations remain */
4663 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4664 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4665 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4667 /* if both are bit variables */
4668 if (AOP_TYPE (left) == AOP_CRY &&
4669 AOP_TYPE (right) == AOP_CRY)
4671 wassertl (0, "Tried to OR two bits");
4675 tlbl = newiTempLabel (NULL);
4677 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4679 emitLabel (tlbl->key + 100);
4683 freeAsmop (left, NULL, ic);
4684 freeAsmop (right, NULL, ic);
4685 freeAsmop (result, NULL, ic);
4688 /*-----------------------------------------------------------------*/
4689 /* isLiteralBit - test if lit == 2^n */
4690 /*-----------------------------------------------------------------*/
4692 isLiteralBit (unsigned long lit)
4694 unsigned long pw[32] =
4695 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
4696 0x100L, 0x200L, 0x400L, 0x800L,
4697 0x1000L, 0x2000L, 0x4000L, 0x8000L,
4698 0x10000L, 0x20000L, 0x40000L, 0x80000L,
4699 0x100000L, 0x200000L, 0x400000L, 0x800000L,
4700 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
4701 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
4704 for (idx = 0; idx < 32; idx++)
4710 /*-----------------------------------------------------------------*/
4711 /* jmpTrueOrFalse - */
4712 /*-----------------------------------------------------------------*/
4714 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
4716 // ugly but optimized by peephole
4719 symbol *nlbl = newiTempLabel (NULL);
4720 emit2 ("jp !tlabel", nlbl->key + 100);
4721 emitLabel (tlbl->key + 100);
4722 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
4723 emitLabel (nlbl->key + 100);
4727 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
4728 emitLabel (tlbl->key + 100);
4733 /*-----------------------------------------------------------------*/
4734 /* genAnd - code for and */
4735 /*-----------------------------------------------------------------*/
4737 genAnd (iCode * ic, iCode * ifx)
4739 operand *left, *right, *result;
4740 int size, offset = 0;
4741 unsigned long lit = 0L;
4744 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4745 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4746 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4748 /* if left is a literal & right is not then exchange them */
4749 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4750 AOP_NEEDSACC (left))
4752 operand *tmp = right;
4757 /* if result = right then exchange them */
4758 if (sameRegs (AOP (result), AOP (right)))
4760 operand *tmp = right;
4765 /* if right is bit then exchange them */
4766 if (AOP_TYPE (right) == AOP_CRY &&
4767 AOP_TYPE (left) != AOP_CRY)
4769 operand *tmp = right;
4773 if (AOP_TYPE (right) == AOP_LIT)
4774 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4776 size = AOP_SIZE (result);
4778 if (AOP_TYPE (left) == AOP_CRY)
4780 wassertl (0, "Tried to perform an AND with a bit as an operand");
4784 // if(val & 0xZZ) - size = 0, ifx != FALSE -
4785 // bit = val & 0xZZ - size = 1, ifx = FALSE -
4786 if ((AOP_TYPE (right) == AOP_LIT) &&
4787 (AOP_TYPE (result) == AOP_CRY) &&
4788 (AOP_TYPE (left) != AOP_CRY))
4790 symbol *tlbl = newiTempLabel (NULL);
4791 int sizel = AOP_SIZE (left);
4794 /* PENDING: Test case for this. */
4799 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
4801 _moveA (aopGet (AOP (left), offset, FALSE));
4802 if (bytelit != 0x0FFL)
4804 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4811 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4815 // bit = left & literal
4819 emit2 ("!tlabeldef", tlbl->key + 100);
4821 // if(left & literal)
4826 jmpTrueOrFalse (ifx, tlbl);
4834 /* if left is same as result */
4835 if (sameRegs (AOP (result), AOP (left)))
4837 for (; size--; offset++)
4839 if (AOP_TYPE (right) == AOP_LIT)
4841 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4846 aopPut (AOP (result), "!zero", offset);
4849 _moveA (aopGet (AOP (left), offset, FALSE));
4851 aopGet (AOP (right), offset, FALSE));
4852 aopPut (AOP (left), "a", offset);
4859 if (AOP_TYPE (left) == AOP_ACC)
4861 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
4865 _moveA (aopGet (AOP (left), offset, FALSE));
4867 aopGet (AOP (right), offset, FALSE));
4868 aopPut (AOP (left), "a", offset);
4875 // left & result in different registers
4876 if (AOP_TYPE (result) == AOP_CRY)
4878 wassertl (0, "Tried to AND where the result is in carry");
4882 for (; (size--); offset++)
4885 // result = left & right
4886 if (AOP_TYPE (right) == AOP_LIT)
4888 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4890 aopPut (AOP (result),
4891 aopGet (AOP (left), offset, FALSE),
4895 else if (bytelit == 0)
4897 aopPut (AOP (result), "!zero", offset);
4901 // faster than result <- left, anl result,right
4902 // and better if result is SFR
4903 if (AOP_TYPE (left) == AOP_ACC)
4904 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4907 _moveA (aopGet (AOP (left), offset, FALSE));
4909 aopGet (AOP (right), offset, FALSE));
4911 aopPut (AOP (result), "a", offset);
4918 freeAsmop (left, NULL, ic);
4919 freeAsmop (right, NULL, ic);
4920 freeAsmop (result, NULL, ic);
4923 /*-----------------------------------------------------------------*/
4924 /* genOr - code for or */
4925 /*-----------------------------------------------------------------*/
4927 genOr (iCode * ic, iCode * ifx)
4929 operand *left, *right, *result;
4930 int size, offset = 0;
4931 unsigned long lit = 0L;
4934 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4935 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4936 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4938 /* if left is a literal & right is not then exchange them */
4939 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4940 AOP_NEEDSACC (left))
4942 operand *tmp = right;
4947 /* if result = right then exchange them */
4948 if (sameRegs (AOP (result), AOP (right)))
4950 operand *tmp = right;
4955 /* if right is bit then exchange them */
4956 if (AOP_TYPE (right) == AOP_CRY &&
4957 AOP_TYPE (left) != AOP_CRY)
4959 operand *tmp = right;
4963 if (AOP_TYPE (right) == AOP_LIT)
4964 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4966 size = AOP_SIZE (result);
4968 if (AOP_TYPE (left) == AOP_CRY)
4970 wassertl (0, "Tried to OR where left is a bit");
4974 // if(val | 0xZZ) - size = 0, ifx != FALSE -
4975 // bit = val | 0xZZ - size = 1, ifx = FALSE -
4976 if ((AOP_TYPE (right) == AOP_LIT) &&
4977 (AOP_TYPE (result) == AOP_CRY) &&
4978 (AOP_TYPE (left) != AOP_CRY))
4980 symbol *tlbl = newiTempLabel (NULL);
4981 int sizel = AOP_SIZE (left);
4985 wassertl (0, "Result is assigned to a bit");
4987 /* PENDING: Modeled after the AND code which is inefficent. */
4990 bytelit = (lit >> (offset * 8)) & 0x0FFL;
4992 _moveA (aopGet (AOP (left), offset, FALSE));
4993 /* OR with any literal is the same as OR with itself. */
4995 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5001 jmpTrueOrFalse (ifx, tlbl);
5006 /* if left is same as result */
5007 if (sameRegs (AOP (result), AOP (left)))
5009 for (; size--; offset++)
5011 if (AOP_TYPE (right) == AOP_LIT)
5013 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5017 _moveA (aopGet (AOP (left), offset, FALSE));
5019 aopGet (AOP (right), offset, FALSE));
5020 aopPut (AOP (result), "a", offset);
5025 if (AOP_TYPE (left) == AOP_ACC)
5026 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5029 _moveA (aopGet (AOP (left), offset, FALSE));
5031 aopGet (AOP (right), offset, FALSE));
5032 aopPut (AOP (result), "a", offset);
5039 // left & result in different registers
5040 if (AOP_TYPE (result) == AOP_CRY)
5042 wassertl (0, "Result of OR is in a bit");
5045 for (; (size--); offset++)
5048 // result = left & right
5049 if (AOP_TYPE (right) == AOP_LIT)
5051 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5053 aopPut (AOP (result),
5054 aopGet (AOP (left), offset, FALSE),
5059 // faster than result <- left, anl result,right
5060 // and better if result is SFR
5061 if (AOP_TYPE (left) == AOP_ACC)
5062 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5065 _moveA (aopGet (AOP (left), offset, FALSE));
5067 aopGet (AOP (right), offset, FALSE));
5069 aopPut (AOP (result), "a", offset);
5070 /* PENDING: something weird is going on here. Add exception. */
5071 if (AOP_TYPE (result) == AOP_ACC)
5077 freeAsmop (left, NULL, ic);
5078 freeAsmop (right, NULL, ic);
5079 freeAsmop (result, NULL, ic);
5082 /*-----------------------------------------------------------------*/
5083 /* genXor - code for xclusive or */
5084 /*-----------------------------------------------------------------*/
5086 genXor (iCode * ic, iCode * ifx)
5088 operand *left, *right, *result;
5089 int size, offset = 0;
5090 unsigned long lit = 0L;
5092 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5093 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5094 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5096 /* if left is a literal & right is not then exchange them */
5097 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5098 AOP_NEEDSACC (left))
5100 operand *tmp = right;
5105 /* if result = right then exchange them */
5106 if (sameRegs (AOP (result), AOP (right)))
5108 operand *tmp = right;
5113 /* if right is bit then exchange them */
5114 if (AOP_TYPE (right) == AOP_CRY &&
5115 AOP_TYPE (left) != AOP_CRY)
5117 operand *tmp = right;
5121 if (AOP_TYPE (right) == AOP_LIT)
5122 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5124 size = AOP_SIZE (result);
5126 if (AOP_TYPE (left) == AOP_CRY)
5128 wassertl (0, "Tried to XOR a bit");
5132 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5133 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5134 if ((AOP_TYPE (right) == AOP_LIT) &&
5135 (AOP_TYPE (result) == AOP_CRY) &&
5136 (AOP_TYPE (left) != AOP_CRY))
5138 symbol *tlbl = newiTempLabel (NULL);
5139 int sizel = AOP_SIZE (left);
5143 /* PENDING: Test case for this. */
5144 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5148 _moveA (aopGet (AOP (left), offset, FALSE));
5149 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5150 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5155 jmpTrueOrFalse (ifx, tlbl);
5159 wassertl (0, "Result of XOR was destined for a bit");
5164 /* if left is same as result */
5165 if (sameRegs (AOP (result), AOP (left)))
5167 for (; size--; offset++)
5169 if (AOP_TYPE (right) == AOP_LIT)
5171 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5175 _moveA (aopGet (AOP (right), offset, FALSE));
5177 aopGet (AOP (left), offset, FALSE));
5178 aopPut (AOP (result), "a", offset);
5183 if (AOP_TYPE (left) == AOP_ACC)
5185 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5189 _moveA (aopGet (AOP (right), offset, FALSE));
5191 aopGet (AOP (left), offset, FALSE));
5192 aopPut (AOP (result), "a", 0);
5199 // left & result in different registers
5200 if (AOP_TYPE (result) == AOP_CRY)
5202 wassertl (0, "Result of XOR is in a bit");
5205 for (; (size--); offset++)
5208 // result = left & right
5209 if (AOP_TYPE (right) == AOP_LIT)
5211 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5213 aopPut (AOP (result),
5214 aopGet (AOP (left), offset, FALSE),
5219 // faster than result <- left, anl result,right
5220 // and better if result is SFR
5221 if (AOP_TYPE (left) == AOP_ACC)
5223 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5227 _moveA (aopGet (AOP (right), offset, FALSE));
5229 aopGet (AOP (left), offset, FALSE));
5231 aopPut (AOP (result), "a", offset);
5236 freeAsmop (left, NULL, ic);
5237 freeAsmop (right, NULL, ic);
5238 freeAsmop (result, NULL, ic);
5241 /*-----------------------------------------------------------------*/
5242 /* genInline - write the inline code out */
5243 /*-----------------------------------------------------------------*/
5245 genInline (iCode * ic)
5247 char *buffer, *bp, *bp1;
5249 _G.lines.isInline += (!options.asmpeep);
5251 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5252 strcpy (buffer, IC_INLINE (ic));
5254 /* emit each line as a code */
5279 _G.lines.isInline -= (!options.asmpeep);
5283 /*-----------------------------------------------------------------*/
5284 /* genRRC - rotate right with carry */
5285 /*-----------------------------------------------------------------*/
5292 /*-----------------------------------------------------------------*/
5293 /* genRLC - generate code for rotate left with carry */
5294 /*-----------------------------------------------------------------*/
5301 /*-----------------------------------------------------------------*/
5302 /* genGetHbit - generates code get highest order bit */
5303 /*-----------------------------------------------------------------*/
5305 genGetHbit (iCode * ic)
5307 operand *left, *result;
5308 left = IC_LEFT (ic);
5309 result = IC_RESULT (ic);
5311 aopOp (left, ic, FALSE, FALSE);
5312 aopOp (result, ic, FALSE, FALSE);
5314 /* get the highest order byte into a */
5315 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5317 if (AOP_TYPE (result) == AOP_CRY)
5325 emit2 ("and a,!one");
5330 freeAsmop (left, NULL, ic);
5331 freeAsmop (result, NULL, ic);
5335 emitRsh2 (asmop *aop, int size, int is_signed)
5341 const char *l = aopGet (aop, size, FALSE);
5344 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5354 /*-----------------------------------------------------------------*/
5355 /* shiftR2Left2Result - shift right two bytes from left to result */
5356 /*-----------------------------------------------------------------*/
5358 shiftR2Left2Result (operand * left, int offl,
5359 operand * result, int offr,
5360 int shCount, int is_signed)
5363 symbol *tlbl, *tlbl1;
5365 movLeft2Result (left, offl, result, offr, 0);
5366 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5368 /* if (AOP(result)->type == AOP_REG) { */
5370 tlbl = newiTempLabel (NULL);
5371 tlbl1 = newiTempLabel (NULL);
5373 /* Left is already in result - so now do the shift */
5378 emitRsh2 (AOP (result), size, is_signed);
5383 emit2 ("ld a,!immedbyte+1", shCount);
5384 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5385 emitLabel (tlbl->key + 100);
5387 emitRsh2 (AOP (result), size, is_signed);
5389 emitLabel (tlbl1->key + 100);
5391 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5395 /*-----------------------------------------------------------------*/
5396 /* shiftL2Left2Result - shift left two bytes from left to result */
5397 /*-----------------------------------------------------------------*/
5399 shiftL2Left2Result (operand * left, int offl,
5400 operand * result, int offr, int shCount)
5402 if (sameRegs (AOP (result), AOP (left)) &&
5403 ((offl + MSB16) == offr))
5409 /* Copy left into result */
5410 movLeft2Result (left, offl, result, offr, 0);
5411 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5414 if (getPairId (AOP (result)) == PAIR_HL)
5418 emit2 ("add hl,hl");
5425 symbol *tlbl, *tlbl1;
5428 tlbl = newiTempLabel (NULL);
5429 tlbl1 = newiTempLabel (NULL);
5431 if (AOP (result)->type == AOP_REG)
5435 for (offset = 0; offset < size; offset++)
5437 l = aopGet (AOP (result), offset, FALSE);
5441 emit2 ("sla %s", l);
5452 /* Left is already in result - so now do the shift */
5455 emit2 ("ld a,!immedbyte+1", shCount);
5456 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5457 emitLabel (tlbl->key + 100);
5462 l = aopGet (AOP (result), offset, FALSE);
5466 emit2 ("sla %s", l);
5477 emitLabel (tlbl1->key + 100);
5479 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5485 /*-----------------------------------------------------------------*/
5486 /* AccRol - rotate left accumulator by known count */
5487 /*-----------------------------------------------------------------*/
5489 AccRol (int shCount)
5491 shCount &= 0x0007; // shCount : 0..7
5568 /*-----------------------------------------------------------------*/
5569 /* AccLsh - left shift accumulator by known count */
5570 /*-----------------------------------------------------------------*/
5572 AccLsh (int shCount)
5574 static const unsigned char SLMask[] =
5576 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5585 else if (shCount == 2)
5592 /* rotate left accumulator */
5594 /* and kill the lower order bits */
5595 emit2 ("and a,!immedbyte", SLMask[shCount]);
5600 /*-----------------------------------------------------------------*/
5601 /* shiftL1Left2Result - shift left one byte from left to result */
5602 /*-----------------------------------------------------------------*/
5604 shiftL1Left2Result (operand * left, int offl,
5605 operand * result, int offr, int shCount)
5608 l = aopGet (AOP (left), offl, FALSE);
5610 /* shift left accumulator */
5612 aopPut (AOP (result), "a", offr);
5616 /*-----------------------------------------------------------------*/
5617 /* genlshTwo - left shift two bytes by known amount != 0 */
5618 /*-----------------------------------------------------------------*/
5620 genlshTwo (operand * result, operand * left, int shCount)
5622 int size = AOP_SIZE (result);
5624 wassert (size == 2);
5626 /* if shCount >= 8 */
5634 movLeft2Result (left, LSB, result, MSB16, 0);
5635 aopPut (AOP (result), "!zero", 0);
5636 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
5640 movLeft2Result (left, LSB, result, MSB16, 0);
5641 aopPut (AOP (result), "!zero", 0);
5646 aopPut (AOP (result), "!zero", LSB);
5649 /* 1 <= shCount <= 7 */
5658 shiftL2Left2Result (left, LSB, result, LSB, shCount);
5663 /*-----------------------------------------------------------------*/
5664 /* genlshOne - left shift a one byte quantity by known count */
5665 /*-----------------------------------------------------------------*/
5667 genlshOne (operand * result, operand * left, int shCount)
5669 shiftL1Left2Result (left, LSB, result, LSB, shCount);
5672 /*-----------------------------------------------------------------*/
5673 /* genLeftShiftLiteral - left shifting by known count */
5674 /*-----------------------------------------------------------------*/
5676 genLeftShiftLiteral (operand * left,
5681 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5684 freeAsmop (right, NULL, ic);
5686 aopOp (left, ic, FALSE, FALSE);
5687 aopOp (result, ic, FALSE, FALSE);
5689 size = getSize (operandType (result));
5691 /* I suppose that the left size >= result size */
5697 else if (shCount >= (size * 8))
5701 aopPut (AOP (result), "!zero", size);
5709 genlshOne (result, left, shCount);
5712 genlshTwo (result, left, shCount);
5715 wassertl (0, "Shifting of longs is currently unsupported");
5721 freeAsmop (left, NULL, ic);
5722 freeAsmop (result, NULL, ic);
5725 /*-----------------------------------------------------------------*/
5726 /* genLeftShift - generates code for left shifting */
5727 /*-----------------------------------------------------------------*/
5729 genLeftShift (iCode * ic)
5733 symbol *tlbl, *tlbl1;
5734 operand *left, *right, *result;
5736 right = IC_RIGHT (ic);
5737 left = IC_LEFT (ic);
5738 result = IC_RESULT (ic);
5740 aopOp (right, ic, FALSE, FALSE);
5742 /* if the shift count is known then do it
5743 as efficiently as possible */
5744 if (AOP_TYPE (right) == AOP_LIT)
5746 genLeftShiftLiteral (left, right, result, ic);
5750 /* shift count is unknown then we have to form a loop get the loop
5751 count in B : Note: we take only the lower order byte since
5752 shifting more that 32 bits make no sense anyway, ( the largest
5753 size of an object can be only 32 bits ) */
5754 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5756 freeAsmop (right, NULL, ic);
5757 aopOp (left, ic, FALSE, FALSE);
5758 aopOp (result, ic, FALSE, FALSE);
5760 /* now move the left to the result if they are not the
5763 if (!sameRegs (AOP (left), AOP (result)))
5766 size = AOP_SIZE (result);
5770 l = aopGet (AOP (left), offset, FALSE);
5771 aopPut (AOP (result), l, offset);
5776 tlbl = newiTempLabel (NULL);
5777 size = AOP_SIZE (result);
5779 tlbl1 = newiTempLabel (NULL);
5781 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5782 emitLabel (tlbl->key + 100);
5783 l = aopGet (AOP (result), offset, FALSE);
5787 l = aopGet (AOP (result), offset, FALSE);
5791 emit2 ("sla %s", l);
5799 emitLabel (tlbl1->key + 100);
5801 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5803 freeAsmop (left, NULL, ic);
5804 freeAsmop (result, NULL, ic);
5807 /*-----------------------------------------------------------------*/
5808 /* genrshOne - left shift two bytes by known amount != 0 */
5809 /*-----------------------------------------------------------------*/
5811 genrshOne (operand * result, operand * left, int shCount, int is_signed)
5814 int size = AOP_SIZE (result);
5817 wassert (size == 1);
5818 wassert (shCount < 8);
5820 l = aopGet (AOP (left), 0, FALSE);
5822 if (AOP (result)->type == AOP_REG)
5824 aopPut (AOP (result), l, 0);
5825 l = aopGet (AOP (result), 0, FALSE);
5828 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5836 emit2 ("%s a", is_signed ? "sra" : "srl");
5838 aopPut (AOP (result), "a", 0);
5842 /*-----------------------------------------------------------------*/
5843 /* AccRsh - right shift accumulator by known count */
5844 /*-----------------------------------------------------------------*/
5846 AccRsh (int shCount)
5848 static const unsigned char SRMask[] =
5850 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
5855 /* rotate right accumulator */
5856 AccRol (8 - shCount);
5857 /* and kill the higher order bits */
5858 emit2 ("and a,!immedbyte", SRMask[shCount]);
5862 /*-----------------------------------------------------------------*/
5863 /* shiftR1Left2Result - shift right one byte from left to result */
5864 /*-----------------------------------------------------------------*/
5866 shiftR1Left2Result (operand * left, int offl,
5867 operand * result, int offr,
5868 int shCount, int sign)
5870 _moveA (aopGet (AOP (left), offl, FALSE));
5875 emit2 ("%s a", sign ? "sra" : "srl");
5882 aopPut (AOP (result), "a", offr);
5885 /*-----------------------------------------------------------------*/
5886 /* genrshTwo - right shift two bytes by known amount != 0 */
5887 /*-----------------------------------------------------------------*/
5889 genrshTwo (operand * result, operand * left,
5890 int shCount, int sign)
5892 /* if shCount >= 8 */
5898 shiftR1Left2Result (left, MSB16, result, LSB,
5903 movLeft2Result (left, MSB16, result, LSB, sign);
5907 /* Sign extend the result */
5908 _moveA(aopGet (AOP (result), 0, FALSE));
5912 aopPut (AOP (result), ACC_NAME, MSB16);
5916 aopPut (AOP (result), "!zero", 1);
5919 /* 1 <= shCount <= 7 */
5922 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
5926 /*-----------------------------------------------------------------*/
5927 /* genRightShiftLiteral - left shifting by known count */
5928 /*-----------------------------------------------------------------*/
5930 genRightShiftLiteral (operand * left,
5936 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5939 freeAsmop (right, NULL, ic);
5941 aopOp (left, ic, FALSE, FALSE);
5942 aopOp (result, ic, FALSE, FALSE);
5944 size = getSize (operandType (result));
5946 /* I suppose that the left size >= result size */
5952 else if (shCount >= (size * 8)) {
5954 if (!SPEC_USIGN(getSpec(operandType(left)))) {
5955 _moveA(aopGet (AOP (left), 0, FALSE));
5963 aopPut (AOP (result), s, size);
5970 genrshOne (result, left, shCount, sign);
5973 genrshTwo (result, left, shCount, sign);
5976 wassertl (0, "Asked to shift right a long which should be a function call");
5979 wassertl (0, "Entered default case in right shift delegate");
5982 freeAsmop (left, NULL, ic);
5983 freeAsmop (result, NULL, ic);
5986 /*-----------------------------------------------------------------*/
5987 /* genRightShift - generate code for right shifting */
5988 /*-----------------------------------------------------------------*/
5990 genRightShift (iCode * ic)
5992 operand *right, *left, *result;
5994 int size, offset, first = 1;
5998 symbol *tlbl, *tlbl1;
6000 /* if signed then we do it the hard way preserve the
6001 sign bit moving it inwards */
6002 retype = getSpec (operandType (IC_RESULT (ic)));
6004 is_signed = !SPEC_USIGN (retype);
6006 /* signed & unsigned types are treated the same : i.e. the
6007 signed is NOT propagated inwards : quoting from the
6008 ANSI - standard : "for E1 >> E2, is equivalent to division
6009 by 2**E2 if unsigned or if it has a non-negative value,
6010 otherwise the result is implementation defined ", MY definition
6011 is that the sign does not get propagated */
6013 right = IC_RIGHT (ic);
6014 left = IC_LEFT (ic);
6015 result = IC_RESULT (ic);
6017 aopOp (right, ic, FALSE, FALSE);
6019 /* if the shift count is known then do it
6020 as efficiently as possible */
6021 if (AOP_TYPE (right) == AOP_LIT)
6023 genRightShiftLiteral (left, right, result, ic, is_signed);
6027 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
6029 freeAsmop (right, NULL, ic);
6031 aopOp (left, ic, FALSE, FALSE);
6032 aopOp (result, ic, FALSE, FALSE);
6034 /* now move the left to the result if they are not the
6036 if (!sameRegs (AOP (left), AOP (result)))
6039 size = AOP_SIZE (result);
6043 l = aopGet (AOP (left), offset, FALSE);
6044 aopPut (AOP (result), l, offset);
6049 tlbl = newiTempLabel (NULL);
6050 tlbl1 = newiTempLabel (NULL);
6051 size = AOP_SIZE (result);
6054 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6055 emitLabel (tlbl->key + 100);
6058 l = aopGet (AOP (result), offset--, FALSE);
6061 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6069 emitLabel (tlbl1->key + 100);
6071 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6073 freeAsmop (left, NULL, ic);
6074 freeAsmop (result, NULL, ic);
6078 /*-----------------------------------------------------------------*/
6079 /* genUnpackBits - generates code for unpacking bits */
6080 /*-----------------------------------------------------------------*/
6082 genUnpackBits (operand * result, int pair)
6084 int offset = 0; /* result byte offset */
6085 int rsize; /* result size */
6086 int rlen = 0; /* remaining bitfield length */
6087 sym_link *etype; /* bitfield type information */
6088 int blen; /* bitfield length */
6089 int bstr; /* bitfield starting bit within byte */
6091 emitDebug ("; genUnpackBits");
6093 etype = getSpec (operandType (result));
6094 rsize = getSize (operandType (result));
6095 blen = SPEC_BLEN (etype);
6096 bstr = SPEC_BSTR (etype);
6098 /* If the bitfield length is less than a byte */
6101 emit2 ("ld a,!*pair", _pairs[pair].name);
6103 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6104 aopPut (AOP (result), "a", offset++);
6108 /* TODO: what if pair == PAIR_DE ? */
6109 if (getPairId (AOP (result)) == PAIR_HL)
6111 wassertl (rsize == 2, "HL must be of size 2");
6112 emit2 ("ld a,!*hl");
6114 emit2 ("ld h,!*hl");
6117 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6119 spillPair (PAIR_HL);
6123 /* Bit field did not fit in a byte. Copy all
6124 but the partial byte at the end. */
6125 for (rlen=blen;rlen>=8;rlen-=8)
6127 emit2 ("ld a,!*pair", _pairs[pair].name);
6128 aopPut (AOP (result), "a", offset++);
6131 emit2 ("inc %s", _pairs[pair].name);
6132 _G.pairs[pair].offset++;
6136 /* Handle the partial byte at the end */
6139 emit2 ("ld a,!*pair", _pairs[pair].name);
6140 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6141 aopPut (AOP (result), "a", offset++);
6149 aopPut (AOP (result), "!zero", offset++);
6153 /*-----------------------------------------------------------------*/
6154 /* genGenPointerGet - get value from generic pointer space */
6155 /*-----------------------------------------------------------------*/
6157 genGenPointerGet (operand * left,
6158 operand * result, iCode * ic)
6161 sym_link *retype = getSpec (operandType (result));
6167 aopOp (left, ic, FALSE, FALSE);
6168 aopOp (result, ic, FALSE, FALSE);
6170 size = AOP_SIZE (result);
6172 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6175 if (isPtrPair (AOP (left)))
6177 tsprintf (buffer, sizeof(buffer),
6178 "!*pair", getPairName (AOP (left)));
6179 aopPut (AOP (result), buffer, 0);
6183 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6184 aopPut (AOP (result), "a", 0);
6186 freeAsmop (left, NULL, ic);
6190 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6197 tsprintf (at, sizeof(at), "!*iyx", offset);
6198 aopPut (AOP (result), at, offset);
6202 freeAsmop (left, NULL, ic);
6206 /* For now we always load into IY */
6207 /* if this is remateriazable */
6208 fetchPair (pair, AOP (left));
6210 /* if bit then unpack */
6211 if (IS_BITVAR (retype))
6213 genUnpackBits (result, pair);
6214 freeAsmop (left, NULL, ic);
6218 else if (getPairId (AOP (result)) == PAIR_HL)
6220 wassertl (size == 2, "HL must be of size 2");
6221 emit2 ("ld a,!*hl");
6223 emit2 ("ld h,!*hl");
6225 spillPair (PAIR_HL);
6227 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6229 size = AOP_SIZE (result);
6234 /* PENDING: make this better */
6235 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6237 aopPut (AOP (result), "!*hl", offset++);
6241 emit2 ("ld a,!*pair", _pairs[pair].name);
6242 aopPut (AOP (result), "a", offset++);
6246 emit2 ("inc %s", _pairs[pair].name);
6247 _G.pairs[pair].offset++;
6250 /* Fixup HL back down */
6251 for (size = AOP_SIZE (result)-1; size; size--)
6253 emit2 ("dec %s", _pairs[pair].name);
6258 size = AOP_SIZE (result);
6263 /* PENDING: make this better */
6265 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6267 aopPut (AOP (result), "!*hl", offset++);
6271 emit2 ("ld a,!*pair", _pairs[pair].name);
6272 aopPut (AOP (result), "a", offset++);
6276 emit2 ("inc %s", _pairs[pair].name);
6277 _G.pairs[pair].offset++;
6282 freeAsmop (left, NULL, ic);
6285 freeAsmop (result, NULL, ic);
6288 /*-----------------------------------------------------------------*/
6289 /* genPointerGet - generate code for pointer get */
6290 /*-----------------------------------------------------------------*/
6292 genPointerGet (iCode * ic)
6294 operand *left, *result;
6295 sym_link *type, *etype;
6297 left = IC_LEFT (ic);
6298 result = IC_RESULT (ic);
6300 /* depending on the type of pointer we need to
6301 move it to the correct pointer register */
6302 type = operandType (left);
6303 etype = getSpec (type);
6305 genGenPointerGet (left, result, ic);
6309 isRegOrLit (asmop * aop)
6311 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6317 /*-----------------------------------------------------------------*/
6318 /* genPackBits - generates code for packed bit storage */
6319 /*-----------------------------------------------------------------*/
6321 genPackBits (sym_link * etype,
6326 int offset = 0; /* source byte offset */
6327 int rlen = 0; /* remaining bitfield length */
6328 int blen; /* bitfield length */
6329 int bstr; /* bitfield starting bit within byte */
6330 int litval; /* source literal value (if AOP_LIT) */
6331 unsigned char mask; /* bitmask within current byte */
6332 int extraPair; /* a tempory register */
6333 bool needPopExtra=0; /* need to restore original value of temp reg */
6335 emitDebug ("; genPackBits","");
6337 blen = SPEC_BLEN (etype);
6338 bstr = SPEC_BSTR (etype);
6340 /* If the bitfield length is less than a byte */
6343 mask = ((unsigned char) (0xFF << (blen + bstr)) |
6344 (unsigned char) (0xFF >> (8 - bstr)));
6346 if (AOP_TYPE (right) == AOP_LIT)
6348 /* Case with a bitfield length <8 and literal source
6350 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6352 litval &= (~mask) & 0xff;
6353 emit2 ("ld a,!*pair", _pairs[pair].name);
6354 if ((mask|litval)!=0xff)
6355 emit2 ("and a,!immedbyte", mask);
6357 emit2 ("or a,!immedbyte", litval);
6358 emit2 ("ld !*pair,a", _pairs[pair].name);
6363 /* Case with a bitfield length <8 and arbitrary source
6365 _moveA (aopGet (AOP (right), 0, FALSE));
6366 /* shift and mask source value */
6368 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6370 extraPair = getFreePairId(ic);
6371 if (extraPair == PAIR_INVALID)
6373 extraPair = PAIR_BC;
6374 if (getPairId (AOP (right)) != PAIR_BC
6375 || !isLastUse (ic, right))
6381 emit2 ("ld %s,a", _pairs[extraPair].l);
6382 emit2 ("ld a,!*pair", _pairs[pair].name);
6384 emit2 ("and a,!immedbyte", mask);
6385 emit2 ("or a,%s", _pairs[extraPair].l);
6386 emit2 ("ld !*pair,a", _pairs[pair].name);
6393 /* Bit length is greater than 7 bits. In this case, copy */
6394 /* all except the partial byte at the end */
6395 for (rlen=blen;rlen>=8;rlen-=8)
6397 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
6398 emit2 ("ld !*pair,a", _pairs[pair].name);
6401 emit2 ("inc %s", _pairs[pair].name);
6402 _G.pairs[pair].offset++;
6406 /* If there was a partial byte at the end */
6409 mask = (((unsigned char) -1 << rlen) & 0xff);
6411 if (AOP_TYPE (right) == AOP_LIT)
6413 /* Case with partial byte and literal source
6415 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6416 litval >>= (blen-rlen);
6417 litval &= (~mask) & 0xff;
6418 emit2 ("ld a,!*pair", _pairs[pair].name);
6419 if ((mask|litval)!=0xff)
6420 emit2 ("and a,!immedbyte", mask);
6422 emit2 ("or a,!immedbyte", litval);
6426 /* Case with partial byte and arbitrary source
6428 _moveA (aopGet (AOP (right), offset++, FALSE));
6429 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6431 extraPair = getFreePairId(ic);
6432 if (extraPair == PAIR_INVALID)
6434 extraPair = getPairId (AOP (right));
6435 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
6436 extraPair = PAIR_BC;
6438 if (getPairId (AOP (right)) != PAIR_BC
6439 || !isLastUse (ic, right))
6445 emit2 ("ld %s,a", _pairs[extraPair].l);
6446 emit2 ("ld a,!*pair", _pairs[pair].name);
6448 emit2 ("and a,!immedbyte", mask);
6449 emit2 ("or a,%s", _pairs[extraPair].l);
6454 emit2 ("ld !*pair,a", _pairs[pair].name);
6459 /*-----------------------------------------------------------------*/
6460 /* genGenPointerSet - stores the value into a pointer location */
6461 /*-----------------------------------------------------------------*/
6463 genGenPointerSet (operand * right,
6464 operand * result, iCode * ic)
6467 sym_link *retype = getSpec (operandType (right));
6468 sym_link *letype = getSpec (operandType (result));
6469 PAIR_ID pairId = PAIR_HL;
6472 aopOp (result, ic, FALSE, FALSE);
6473 aopOp (right, ic, FALSE, FALSE);
6478 size = AOP_SIZE (right);
6480 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
6481 emitDebug("; isBitvar = %d", isBitvar);
6483 /* Handle the exceptions first */
6484 if (isPair (AOP (result)) && size == 1 && !isBitvar)
6487 const char *l = aopGet (AOP (right), 0, FALSE);
6488 const char *pair = getPairName (AOP (result));
6489 if (canAssignToPtr (l) && isPtr (pair))
6491 emit2 ("ld !*pair,%s", pair, l);
6496 emit2 ("ld !*pair,a", pair);
6501 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
6504 const char *l = aopGet (AOP (right), 0, FALSE);
6509 if (canAssignToPtr (l))
6511 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6515 _moveA (aopGet (AOP (right), offset, FALSE));
6516 emit2 ("ld !*iyx,a", offset);
6522 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
6529 const char *l = aopGet (AOP (right), offset, FALSE);
6530 if (isRegOrLit (AOP (right)) && !IS_GB)
6532 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
6537 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
6541 emit2 ("inc %s", _pairs[PAIR_HL].name);
6542 _G.pairs[PAIR_HL].offset++;
6547 /* Fixup HL back down */
6548 for (size = AOP_SIZE (right)-1; size; size--)
6550 emit2 ("dec %s", _pairs[PAIR_HL].name);
6555 /* if the operand is already in dptr
6556 then we do nothing else we move the value to dptr */
6557 if (AOP_TYPE (result) != AOP_STR)
6559 fetchPair (pairId, AOP (result));
6561 /* so hl know contains the address */
6562 freeAsmop (result, NULL, ic);
6564 /* if bit then unpack */
6567 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
6577 const char *l = aopGet (AOP (right), offset, FALSE);
6578 if (isRegOrLit (AOP (right)) && !IS_GB)
6580 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
6585 emit2 ("ld !*pair,a", _pairs[pairId].name);
6589 emit2 ("inc %s", _pairs[pairId].name);
6590 _G.pairs[pairId].offset++;
6596 freeAsmop (right, NULL, ic);
6599 /*-----------------------------------------------------------------*/
6600 /* genPointerSet - stores the value into a pointer location */
6601 /*-----------------------------------------------------------------*/
6603 genPointerSet (iCode * ic)
6605 operand *right, *result;
6606 sym_link *type, *etype;
6608 right = IC_RIGHT (ic);
6609 result = IC_RESULT (ic);
6611 /* depending on the type of pointer we need to
6612 move it to the correct pointer register */
6613 type = operandType (result);
6614 etype = getSpec (type);
6616 genGenPointerSet (right, result, ic);
6619 /*-----------------------------------------------------------------*/
6620 /* genIfx - generate code for Ifx statement */
6621 /*-----------------------------------------------------------------*/
6623 genIfx (iCode * ic, iCode * popIc)
6625 operand *cond = IC_COND (ic);
6628 aopOp (cond, ic, FALSE, TRUE);
6630 /* get the value into acc */
6631 if (AOP_TYPE (cond) != AOP_CRY)
6635 /* the result is now in the accumulator */
6636 freeAsmop (cond, NULL, ic);
6638 /* if there was something to be popped then do it */
6642 /* if the condition is a bit variable */
6643 if (isbit && IS_ITEMP (cond) &&
6645 genIfxJump (ic, SPIL_LOC (cond)->rname);
6646 else if (isbit && !IS_ITEMP (cond))
6647 genIfxJump (ic, OP_SYMBOL (cond)->rname);
6649 genIfxJump (ic, "a");
6654 /*-----------------------------------------------------------------*/
6655 /* genAddrOf - generates code for address of */
6656 /*-----------------------------------------------------------------*/
6658 genAddrOf (iCode * ic)
6660 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
6662 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6664 /* if the operand is on the stack then we
6665 need to get the stack offset of this
6672 if (sym->stack <= 0)
6674 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
6678 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6680 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6684 emit2 ("ld de,!hashedstr", sym->rname);
6685 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
6693 /* if it has an offset then we need to compute it */
6695 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6697 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
6698 emit2 ("add hl,sp");
6702 emit2 ("ld hl,!hashedstr", sym->rname);
6704 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6706 freeAsmop (IC_RESULT (ic), NULL, ic);
6709 /*-----------------------------------------------------------------*/
6710 /* genAssign - generate code for assignment */
6711 /*-----------------------------------------------------------------*/
6713 genAssign (iCode * ic)
6715 operand *result, *right;
6717 unsigned long lit = 0L;
6719 result = IC_RESULT (ic);
6720 right = IC_RIGHT (ic);
6722 /* Dont bother assigning if they are the same */
6723 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6725 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
6729 aopOp (right, ic, FALSE, FALSE);
6730 aopOp (result, ic, TRUE, FALSE);
6732 /* if they are the same registers */
6733 if (sameRegs (AOP (right), AOP (result)))
6735 emitDebug ("; (registers are the same)");
6739 /* if the result is a bit */
6740 if (AOP_TYPE (result) == AOP_CRY)
6742 wassertl (0, "Tried to assign to a bit");
6746 size = AOP_SIZE (result);
6749 if (AOP_TYPE (right) == AOP_LIT)
6751 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6754 if (isPair (AOP (result)))
6756 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
6758 else if ((size > 1) &&
6759 (AOP_TYPE (result) != AOP_REG) &&
6760 (AOP_TYPE (right) == AOP_LIT) &&
6761 !IS_FLOAT (operandType (right)) &&
6764 bool fXored = FALSE;
6766 /* Work from the top down.
6767 Done this way so that we can use the cached copy of 0
6768 in A for a fast clear */
6771 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
6773 if (!fXored && size > 1)
6780 aopPut (AOP (result), "a", offset);
6784 aopPut (AOP (result), "!zero", offset);
6788 aopPut (AOP (result),
6789 aopGet (AOP (right), offset, FALSE),
6794 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
6796 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
6797 aopPut (AOP (result), "l", LSB);
6798 aopPut (AOP (result), "h", MSB16);
6800 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6802 /* Special case. Load into a and d, then load out. */
6803 _moveA (aopGet (AOP (right), 0, FALSE));
6804 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
6805 aopPut (AOP (result), "a", 0);
6806 aopPut (AOP (result), "e", 1);
6808 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6810 /* Special case - simple memcpy */
6811 aopGet (AOP (right), LSB, FALSE);
6814 aopGet (AOP (result), LSB, FALSE);
6818 emit2 ("ld a,(de)");
6819 /* Peephole will optimise this. */
6820 emit2 ("ld (hl),a");
6828 spillPair (PAIR_HL);
6834 /* PENDING: do this check better */
6835 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
6837 _moveA (aopGet (AOP (right), offset, FALSE));
6838 aopPut (AOP (result), "a", offset);
6841 aopPut (AOP (result),
6842 aopGet (AOP (right), offset, FALSE),
6849 freeAsmop (right, NULL, ic);
6850 freeAsmop (result, NULL, ic);
6853 /*-----------------------------------------------------------------*/
6854 /* genJumpTab - genrates code for jump table */
6855 /*-----------------------------------------------------------------*/
6857 genJumpTab (iCode * ic)
6862 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
6863 /* get the condition into accumulator */
6864 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
6867 emit2 ("ld e,%s", l);
6868 emit2 ("ld d,!zero");
6869 jtab = newiTempLabel (NULL);
6871 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
6872 emit2 ("add hl,de");
6873 emit2 ("add hl,de");
6874 emit2 ("add hl,de");
6875 freeAsmop (IC_JTCOND (ic), NULL, ic);
6879 emitLabel (jtab->key + 100);
6880 /* now generate the jump labels */
6881 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
6882 jtab = setNextItem (IC_JTLABELS (ic)))
6883 emit2 ("jp !tlabel", jtab->key + 100);
6886 /*-----------------------------------------------------------------*/
6887 /* genCast - gen code for casting */
6888 /*-----------------------------------------------------------------*/
6890 genCast (iCode * ic)
6892 operand *result = IC_RESULT (ic);
6893 sym_link *rtype = operandType (IC_RIGHT (ic));
6894 operand *right = IC_RIGHT (ic);
6897 /* if they are equivalent then do nothing */
6898 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6901 aopOp (right, ic, FALSE, FALSE);
6902 aopOp (result, ic, FALSE, FALSE);
6904 /* if the result is a bit */
6905 if (AOP_TYPE (result) == AOP_CRY)
6907 wassertl (0, "Tried to cast to a bit");
6910 /* if they are the same size : or less */
6911 if (AOP_SIZE (result) <= AOP_SIZE (right))
6914 /* if they are in the same place */
6915 if (sameRegs (AOP (right), AOP (result)))
6918 /* if they in different places then copy */
6919 size = AOP_SIZE (result);
6923 aopPut (AOP (result),
6924 aopGet (AOP (right), offset, FALSE),
6931 /* So we now know that the size of destination is greater
6932 than the size of the source */
6933 /* we move to result for the size of source */
6934 size = AOP_SIZE (right);
6938 aopPut (AOP (result),
6939 aopGet (AOP (right), offset, FALSE),
6944 /* now depending on the sign of the destination */
6945 size = AOP_SIZE (result) - AOP_SIZE (right);
6946 /* Unsigned or not an integral type - right fill with zeros */
6947 if (SPEC_USIGN (rtype) || !IS_SPEC (rtype) || AOP_TYPE(right)==AOP_CRY)
6950 aopPut (AOP (result), "!zero", offset++);
6954 /* we need to extend the sign :{ */
6955 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
6961 aopPut (AOP (result), "a", offset++);
6965 freeAsmop (right, NULL, ic);
6966 freeAsmop (result, NULL, ic);
6969 /*-----------------------------------------------------------------*/
6970 /* genReceive - generate code for a receive iCode */
6971 /*-----------------------------------------------------------------*/
6973 genReceive (iCode * ic)
6975 if (isOperandInFarSpace (IC_RESULT (ic)) &&
6976 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
6977 IS_TRUE_SYMOP (IC_RESULT (ic))))
6987 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6988 size = AOP_SIZE(IC_RESULT(ic));
6990 for (i = 0; i < size; i++) {
6991 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
6995 freeAsmop (IC_RESULT (ic), NULL, ic);
6998 /*-----------------------------------------------------------------*/
6999 /* genDummyRead - generate code for dummy read of volatiles */
7000 /*-----------------------------------------------------------------*/
7002 genDummyRead (iCode * ic)
7004 emit2 ("; genDummyRead not implemented");
7011 /** Maximum number of bytes to emit per line. */
7015 /** Context for the byte output chunker. */
7018 unsigned char buffer[DBEMIT_MAX_RUN];
7023 /** Flushes a byte chunker by writing out all in the buffer and
7027 _dbFlush(DBEMITCTX *self)
7034 sprintf(line, ".db 0x%02X", self->buffer[0]);
7036 for (i = 1; i < self->pos; i++)
7038 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
7045 /** Write out another byte, buffering until a decent line is
7049 _dbEmit(DBEMITCTX *self, int c)
7051 if (self->pos == DBEMIT_MAX_RUN)
7055 self->buffer[self->pos++] = c;
7058 /** Context for a simple run length encoder. */
7062 unsigned char buffer[128];
7064 /** runLen may be equivalent to pos. */
7070 RLE_CHANGE_COST = 4,
7074 /** Flush the buffer of a run length encoder by writing out the run or
7075 data that it currently contains.
7078 _rleCommit(RLECTX *self)
7084 memset(&db, 0, sizeof(db));
7086 emit2(".db %u", self->pos);
7088 for (i = 0; i < self->pos; i++)
7090 _dbEmit(&db, self->buffer[i]);
7099 Can get either a run or a block of random stuff.
7100 Only want to change state if a good run comes in or a run ends.
7101 Detecting run end is easy.
7104 Say initial state is in run, len zero, last zero. Then if you get a
7105 few zeros then something else then a short run will be output.
7106 Seems OK. While in run mode, keep counting. While in random mode,
7107 keep a count of the run. If run hits margin, output all up to run,
7108 restart, enter run mode.
7111 /** Add another byte into the run length encoder, flushing as
7112 required. The run length encoder uses the Amiga IFF style, where
7113 a block is prefixed by its run length. A positive length means
7114 the next n bytes pass straight through. A negative length means
7115 that the next byte is repeated -n times. A zero terminates the
7119 _rleAppend(RLECTX *self, int c)
7123 if (c != self->last)
7125 /* The run has stopped. See if it is worthwhile writing it out
7126 as a run. Note that the random data comes in as runs of
7129 if (self->runLen > RLE_CHANGE_COST)
7131 /* Yes, worthwhile. */
7132 /* Commit whatever was in the buffer. */
7134 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7138 /* Not worthwhile. Append to the end of the random list. */
7139 for (i = 0; i < self->runLen; i++)
7141 if (self->pos >= RLE_MAX_BLOCK)
7146 self->buffer[self->pos++] = self->last;
7154 if (self->runLen >= RLE_MAX_BLOCK)
7156 /* Commit whatever was in the buffer. */
7159 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7167 _rleFlush(RLECTX *self)
7169 _rleAppend(self, -1);
7176 /** genArrayInit - Special code for initialising an array with constant
7180 genArrayInit (iCode * ic)
7184 int elementSize = 0, eIndex, i;
7185 unsigned val, lastVal;
7189 memset(&rle, 0, sizeof(rle));
7191 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7193 _saveRegsForCall(ic, 0);
7195 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7196 emit2 ("call __initrleblock");
7198 type = operandType(IC_LEFT(ic));
7200 if (type && type->next)
7202 elementSize = getSize(type->next);
7206 wassertl (0, "Can't determine element size in genArrayInit.");
7209 iLoop = IC_ARRAYILIST(ic);
7210 lastVal = (unsigned)-1;
7212 /* Feed all the bytes into the run length encoder which will handle
7214 This works well for mixed char data, and for random int and long
7223 for (i = 0; i < ix; i++)
7225 for (eIndex = 0; eIndex < elementSize; eIndex++)
7227 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7228 _rleAppend(&rle, val);
7233 iLoop = iLoop->next;
7237 /* Mark the end of the run. */
7240 _restoreRegsAfterCall();
7244 freeAsmop (IC_LEFT(ic), NULL, ic);
7248 _swap (PAIR_ID one, PAIR_ID two)
7250 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7256 emit2 ("ld a,%s", _pairs[one].l);
7257 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7258 emit2 ("ld %s,a", _pairs[two].l);
7259 emit2 ("ld a,%s", _pairs[one].h);
7260 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7261 emit2 ("ld %s,a", _pairs[two].h);
7265 /* The problem is that we may have all three pairs used and they may
7266 be needed in a different order.
7271 hl = hl => unity, fine
7275 hl = hl hl = hl, swap de <=> bc
7283 hl = bc de = de, swap bc <=> hl
7291 hl = de bc = bc, swap hl <=> de
7296 * Any pair = pair are done last
7297 * Any pair = iTemp are done last
7298 * Any swaps can be done any time
7306 So how do we detect the cases?
7307 How about a 3x3 matrix?
7311 x x x x (Fourth for iTemp/other)
7313 First determin which mode to use by counting the number of unity and
7316 Two - Assign the pair first, then the rest
7317 One - Swap the two, then the rest
7321 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7323 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7325 PAIR_BC, PAIR_HL, PAIR_DE
7327 int i, j, nunity = 0;
7328 memset (ids, PAIR_INVALID, sizeof (ids));
7331 wassert (nparams == 3);
7333 /* First save everything that needs to be saved. */
7334 _saveRegsForCall (ic, 0);
7336 /* Loading HL first means that DE is always fine. */
7337 for (i = 0; i < nparams; i++)
7339 aopOp (pparams[i], ic, FALSE, FALSE);
7340 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7343 /* Count the number of unity or iTemp assigns. */
7344 for (i = 0; i < 3; i++)
7346 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7354 /* Any order, fall through. */
7356 else if (nunity == 2)
7358 /* One is assigned. Pull it out and assign. */
7359 for (i = 0; i < 3; i++)
7361 for (j = 0; j < NUM_PAIRS; j++)
7363 if (ids[dest[i]][j] == TRUE)
7365 /* Found it. See if it's the right one. */
7366 if (j == PAIR_INVALID || j == dest[i])
7372 fetchPair(dest[i], AOP (pparams[i]));
7379 else if (nunity == 1)
7381 /* Find the pairs to swap. */
7382 for (i = 0; i < 3; i++)
7384 for (j = 0; j < NUM_PAIRS; j++)
7386 if (ids[dest[i]][j] == TRUE)
7388 if (j == PAIR_INVALID || j == dest[i])
7403 int next = getPairId (AOP (pparams[0]));
7404 emit2 ("push %s", _pairs[next].name);
7406 if (next == dest[1])
7408 fetchPair (dest[1], AOP (pparams[1]));
7409 fetchPair (dest[2], AOP (pparams[2]));
7413 fetchPair (dest[2], AOP (pparams[2]));
7414 fetchPair (dest[1], AOP (pparams[1]));
7416 emit2 ("pop %s", _pairs[dest[0]].name);
7419 /* Finally pull out all of the iTemps */
7420 for (i = 0; i < 3; i++)
7422 if (ids[dest[i]][PAIR_INVALID] == 1)
7424 fetchPair (dest[i], AOP (pparams[i]));
7430 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
7436 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
7440 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7442 setupForBuiltin3 (ic, nParams, pparams);
7444 label = newiTempLabel(NULL);
7446 emitLabel (label->key);
7447 emit2 ("ld a,(hl)");
7450 emit2 ("!shortjp nz,!tlabel ; 1", label->key);
7452 freeAsmop (from, NULL, ic->next);
7453 freeAsmop (to, NULL, ic);
7457 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
7459 operand *from, *to, *count;
7462 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
7467 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7469 setupForBuiltin3 (ic, nParams, pparams);
7473 freeAsmop (count, NULL, ic->next->next);
7474 freeAsmop (from, NULL, ic);
7476 _restoreRegsAfterCall();
7478 /* if we need assign a result value */
7479 if ((IS_ITEMP (IC_RESULT (ic)) &&
7480 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
7481 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
7482 IS_TRUE_SYMOP (IC_RESULT (ic)))
7484 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7485 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
7486 freeAsmop (IC_RESULT (ic), NULL, ic);
7489 freeAsmop (to, NULL, ic->next);
7492 /*-----------------------------------------------------------------*/
7493 /* genBuiltIn - calls the appropriate function to generating code */
7494 /* for a built in function */
7495 /*-----------------------------------------------------------------*/
7496 static void genBuiltIn (iCode *ic)
7498 operand *bi_parms[MAX_BUILTIN_ARGS];
7503 /* get all the arguments for a built in function */
7504 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
7506 /* which function is it */
7507 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
7509 if (strcmp(bif->name,"__builtin_strcpy")==0)
7511 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
7513 else if (strcmp(bif->name,"__builtin_memcpy")==0)
7515 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
7519 wassertl (0, "Unknown builtin function encountered");
7523 /*-----------------------------------------------------------------*/
7524 /* genZ80Code - generate code for Z80 based controllers */
7525 /*-----------------------------------------------------------------*/
7527 genZ80Code (iCode * lic)
7535 _fReturn = _gbz80_return;
7536 _fTmp = _gbz80_return;
7540 _fReturn = _z80_return;
7541 _fTmp = _z80_return;
7544 _G.lines.head = _G.lines.current = NULL;
7546 for (ic = lic; ic; ic = ic->next)
7549 if (cln != ic->lineno)
7551 if (!options.noCcodeInAsm) {
7552 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
7553 printCLine(ic->filename, ic->lineno));
7557 if (options.iCodeInAsm) {
7558 emit2 (";ic:%d: %s", ic->key, printILine(ic));
7560 /* if the result is marked as
7561 spilt and rematerializable or code for
7562 this has already been generated then
7564 if (resultRemat (ic) || ic->generated)
7567 /* depending on the operation */
7571 emitDebug ("; genNot");
7576 emitDebug ("; genCpl");
7581 emitDebug ("; genUminus");
7586 emitDebug ("; genIpush");
7591 /* IPOP happens only when trying to restore a
7592 spilt live range, if there is an ifx statement
7593 following this pop then the if statement might
7594 be using some of the registers being popped which
7595 would destory the contents of the register so
7596 we need to check for this condition and handle it */
7598 ic->next->op == IFX &&
7599 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
7601 emitDebug ("; genIfx");
7602 genIfx (ic->next, ic);
7606 emitDebug ("; genIpop");
7612 emitDebug ("; genCall");
7617 emitDebug ("; genPcall");
7622 emitDebug ("; genFunction");
7627 emitDebug ("; genEndFunction");
7628 genEndFunction (ic);
7632 emitDebug ("; genRet");
7637 emitDebug ("; genLabel");
7642 emitDebug ("; genGoto");
7647 emitDebug ("; genPlus");
7652 emitDebug ("; genMinus");
7657 emitDebug ("; genMult");
7662 emitDebug ("; genDiv");
7667 emitDebug ("; genMod");
7672 emitDebug ("; genCmpGt");
7673 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
7677 emitDebug ("; genCmpLt");
7678 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
7685 /* note these two are xlated by algebraic equivalence
7686 during parsing SDCC.y */
7687 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
7688 "got '>=' or '<=' shouldn't have come here");
7692 emitDebug ("; genCmpEq");
7693 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
7697 emitDebug ("; genAndOp");
7702 emitDebug ("; genOrOp");
7707 emitDebug ("; genXor");
7708 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
7712 emitDebug ("; genOr");
7713 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
7717 emitDebug ("; genAnd");
7718 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
7722 emitDebug ("; genInline");
7727 emitDebug ("; genRRC");
7732 emitDebug ("; genRLC");
7737 emitDebug ("; genGetHBIT");
7742 emitDebug ("; genLeftShift");
7747 emitDebug ("; genRightShift");
7751 case GET_VALUE_AT_ADDRESS:
7752 emitDebug ("; genPointerGet");
7758 if (POINTER_SET (ic))
7760 emitDebug ("; genAssign (pointer)");
7765 emitDebug ("; genAssign");
7771 emitDebug ("; genIfx");
7776 emitDebug ("; genAddrOf");
7781 emitDebug ("; genJumpTab");
7786 emitDebug ("; genCast");
7791 emitDebug ("; genReceive");
7796 if (ic->builtinSEND)
7798 emitDebug ("; genBuiltIn");
7803 emitDebug ("; addSet");
7804 addSet (&_G.sendSet, ic);
7809 emitDebug ("; genArrayInit");
7813 case DUMMY_READ_VOLATILE:
7823 /* now we are ready to call the
7824 peep hole optimizer */
7825 if (!options.nopeep)
7826 peepHole (&_G.lines.head);
7828 /* This is unfortunate */
7829 /* now do the actual printing */
7831 FILE *fp = codeOutFile;
7832 if (isInHome () && codeOutFile == code->oFile)
7833 codeOutFile = home->oFile;
7834 printLine (_G.lines.head, codeOutFile);
7835 if (_G.flushStatics)
7838 _G.flushStatics = 0;
7843 freeTrace(&_G.lines.trace);
7844 freeTrace(&_G.trace.aops);
7850 _isPairUsed (iCode * ic, PAIR_ID pairId)
7856 if (bitVectBitValue (ic->rMask, D_IDX))
7858 if (bitVectBitValue (ic->rMask, E_IDX))
7868 fetchLitSpecial (asmop * aop, bool negate, bool xor)
7871 value *val = aop->aopu.aop_lit;
7873 wassert (aop->type == AOP_LIT);
7874 wassert (!IS_FLOAT (val->type));
7876 v = (unsigned long) floatFromVal (val);
7884 tsprintf (buffer, sizeof(buffer), "!immedword", v);
7885 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));