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));
2037 /*-----------------------------------------------------------------*/
2038 /* genNot - generate code for ! operation */
2039 /*-----------------------------------------------------------------*/
2044 /* assign asmOps to operand & result */
2045 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
2046 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2048 /* if in bit space then a special case */
2049 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2051 wassertl (0, "Tried to negate a bit");
2054 _toBoolean (IC_LEFT (ic));
2059 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
2060 emit2 ("sub a,!one");
2061 outBitC (IC_RESULT (ic));
2063 /* release the aops */
2064 freeAsmop (IC_LEFT (ic), NULL, ic);
2065 freeAsmop (IC_RESULT (ic), NULL, ic);
2068 /*-----------------------------------------------------------------*/
2069 /* genCpl - generate code for complement */
2070 /*-----------------------------------------------------------------*/
2078 /* assign asmOps to operand & result */
2079 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2080 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2082 /* if both are in bit space then
2084 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2085 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2087 wassertl (0, "Left and the result are in bit space");
2090 size = AOP_SIZE (IC_RESULT (ic));
2093 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2096 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2099 /* release the aops */
2100 freeAsmop (IC_LEFT (ic), NULL, ic);
2101 freeAsmop (IC_RESULT (ic), NULL, ic);
2105 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
2112 store de into result
2117 store de into result
2119 const char *first = isAdd ? "add" : "sub";
2120 const char *later = isAdd ? "adc" : "sbc";
2122 wassertl (IS_GB, "Code is only relevent to the gbz80");
2123 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
2125 fetchPair (PAIR_DE, left);
2128 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
2131 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
2134 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2135 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2137 fetchPairLong (PAIR_DE, left, NULL, MSB24);
2138 aopGet (right, MSB24, FALSE);
2142 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2145 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2147 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2148 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2152 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2154 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2157 /*-----------------------------------------------------------------*/
2158 /* genUminusFloat - unary minus for floating points */
2159 /*-----------------------------------------------------------------*/
2161 genUminusFloat (operand * op, operand * result)
2163 int size, offset = 0;
2165 emitDebug("; genUminusFloat");
2167 /* for this we just need to flip the
2168 first it then copy the rest in place */
2169 size = AOP_SIZE (op) - 1;
2171 _moveA(aopGet (AOP (op), MSB32, FALSE));
2173 emit2("xor a,!immedbyte", 0x80);
2174 aopPut (AOP (result), "a", MSB32);
2178 aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2183 /*-----------------------------------------------------------------*/
2184 /* genUminus - unary minus code generation */
2185 /*-----------------------------------------------------------------*/
2187 genUminus (iCode * ic)
2190 sym_link *optype, *rtype;
2193 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2194 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2196 /* if both in bit space then special
2198 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2199 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2201 wassertl (0, "Left and right are in bit space");
2205 optype = operandType (IC_LEFT (ic));
2206 rtype = operandType (IC_RESULT (ic));
2208 /* if float then do float stuff */
2209 if (IS_FLOAT (optype))
2211 genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2215 /* otherwise subtract from zero */
2216 size = AOP_SIZE (IC_LEFT (ic));
2218 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2220 /* Create a new asmop with value zero */
2221 asmop *azero = newAsmop (AOP_SIMPLELIT);
2222 azero->aopu.aop_simplelit = 0;
2224 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2232 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2233 emit2 ("ld a,!zero");
2234 emit2 ("sbc a,%s", l);
2235 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2238 /* if any remaining bytes in the result */
2239 /* we just need to propagate the sign */
2240 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2245 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2249 /* release the aops */
2250 freeAsmop (IC_LEFT (ic), NULL, ic);
2251 freeAsmop (IC_RESULT (ic), NULL, ic);
2254 /*-----------------------------------------------------------------*/
2255 /* assignResultValue - */
2256 /*-----------------------------------------------------------------*/
2258 assignResultValue (operand * oper)
2260 int size = AOP_SIZE (oper);
2263 wassertl (size <= 4, "Got a result that is bigger than four bytes");
2264 topInA = requiresHL (AOP (oper));
2266 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2268 /* We do it the hard way here. */
2270 aopPut (AOP (oper), _fReturn[0], 0);
2271 aopPut (AOP (oper), _fReturn[1], 1);
2273 aopPut (AOP (oper), _fReturn[0], 2);
2274 aopPut (AOP (oper), _fReturn[1], 3);
2280 aopPut (AOP (oper), _fReturn[size], size);
2285 /** Simple restore that doesn't take into account what is used in the
2289 _restoreRegsAfterCall(void)
2291 if (_G.stack.pushedDE)
2294 _G.stack.pushedDE = FALSE;
2296 if (_G.stack.pushedBC)
2299 _G.stack.pushedBC = FALSE;
2301 _G.saves.saved = FALSE;
2305 _saveRegsForCall(iCode *ic, int sendSetSize)
2308 o Stack parameters are pushed before this function enters
2309 o DE and BC may be used in this function.
2310 o HL and DE may be used to return the result.
2311 o HL and DE may be used to send variables.
2312 o DE and BC may be used to store the result value.
2313 o HL may be used in computing the sent value of DE
2314 o The iPushes for other parameters occur before any addSets
2316 Logic: (to be run inside the first iPush or if none, before sending)
2317 o Compute if DE and/or BC are in use over the call
2318 o Compute if DE is used in the send set
2319 o Compute if DE and/or BC are used to hold the result value
2320 o If (DE is used, or in the send set) and is not used in the result, push.
2321 o If BC is used and is not in the result, push
2323 o If DE is used in the send set, fetch
2324 o If HL is used in the send set, fetch
2328 if (_G.saves.saved == FALSE) {
2329 bool deInUse, bcInUse;
2331 bool bcInRet = FALSE, deInRet = FALSE;
2334 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
2336 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2337 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2339 deSending = (sendSetSize > 1);
2341 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2343 if (bcInUse && bcInRet == FALSE) {
2345 _G.stack.pushedBC = TRUE;
2347 if (deInUse && deInRet == FALSE) {
2349 _G.stack.pushedDE = TRUE;
2352 _G.saves.saved = TRUE;
2355 /* Already saved. */
2359 /*-----------------------------------------------------------------*/
2360 /* genIpush - genrate code for pushing this gets a little complex */
2361 /*-----------------------------------------------------------------*/
2363 genIpush (iCode * ic)
2365 int size, offset = 0;
2368 /* if this is not a parm push : ie. it is spill push
2369 and spill push is always done on the local stack */
2372 wassertl(0, "Encountered an unsupported spill push.");
2376 if (_G.saves.saved == FALSE) {
2377 /* Caller saves, and this is the first iPush. */
2378 /* Scan ahead until we find the function that we are pushing parameters to.
2379 Count the number of addSets on the way to figure out what registers
2380 are used in the send set.
2383 iCode *walk = ic->next;
2386 if (walk->op == SEND) {
2389 else if (walk->op == CALL || walk->op == PCALL) {
2398 _saveRegsForCall(walk, nAddSets);
2401 /* Already saved by another iPush. */
2404 /* then do the push */
2405 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2407 size = AOP_SIZE (IC_LEFT (ic));
2409 if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2411 _G.stack.pushed += 2;
2412 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2418 fetchHL (AOP (IC_LEFT (ic)));
2420 spillPair (PAIR_HL);
2421 _G.stack.pushed += 2;
2426 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
2428 spillPair (PAIR_HL);
2429 _G.stack.pushed += 2;
2430 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
2432 spillPair (PAIR_HL);
2433 _G.stack.pushed += 2;
2439 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2441 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2443 emit2 ("ld a,(%s)", l);
2447 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2448 emit2 ("ld a,%s", l);
2456 freeAsmop (IC_LEFT (ic), NULL, ic);
2459 /*-----------------------------------------------------------------*/
2460 /* genIpop - recover the registers: can happen only for spilling */
2461 /*-----------------------------------------------------------------*/
2463 genIpop (iCode * ic)
2468 /* if the temp was not pushed then */
2469 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2472 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2473 size = AOP_SIZE (IC_LEFT (ic));
2474 offset = (size - 1);
2475 if (isPair (AOP (IC_LEFT (ic))))
2477 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2485 spillPair (PAIR_HL);
2486 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2490 freeAsmop (IC_LEFT (ic), NULL, ic);
2493 /* This is quite unfortunate */
2495 setArea (int inHome)
2498 static int lastArea = 0;
2500 if (_G.in_home != inHome) {
2502 const char *sz = port->mem.code_name;
2503 port->mem.code_name = "HOME";
2504 emit2("!area", CODE_NAME);
2505 port->mem.code_name = sz;
2508 emit2("!area", CODE_NAME); */
2509 _G.in_home = inHome;
2520 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2524 symbol *sym = OP_SYMBOL (op);
2526 if (sym->isspilt || sym->nRegs == 0)
2529 aopOp (op, ic, FALSE, FALSE);
2532 if (aop->type == AOP_REG)
2535 for (i = 0; i < aop->size; i++)
2537 if (pairId == PAIR_DE)
2539 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2540 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2542 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2545 else if (pairId == PAIR_BC)
2547 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2548 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2550 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2560 freeAsmop (IC_LEFT (ic), NULL, ic);
2564 /** Emit the code for a call statement
2567 emitCall (iCode * ic, bool ispcall)
2569 sym_link *dtype = operandType (IC_LEFT (ic));
2571 /* if caller saves & we have not saved then */
2577 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2579 /* if send set is not empty then assign */
2584 int nSend = elementsInSet(_G.sendSet);
2585 bool swapped = FALSE;
2587 int _z80_sendOrder[] = {
2592 /* Check if the parameters are swapped. If so route through hl instead. */
2593 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2595 sic = setFirstItem(_G.sendSet);
2596 sic = setNextItem(_G.sendSet);
2598 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2599 /* The second send value is loaded from one the one that holds the first
2600 send, i.e. it is overwritten. */
2601 /* Cache the first in HL, and load the second from HL instead. */
2602 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2603 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2609 for (sic = setFirstItem (_G.sendSet); sic;
2610 sic = setNextItem (_G.sendSet))
2613 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2615 size = AOP_SIZE (IC_LEFT (sic));
2616 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2617 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2619 // PENDING: Mild hack
2620 if (swapped == TRUE && send == 1) {
2622 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2625 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2627 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2630 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2634 freeAsmop (IC_LEFT (sic), NULL, sic);
2641 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2643 werror (W_INDIR_BANKED);
2645 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2647 if (isLitWord (AOP (IC_LEFT (ic))))
2649 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2653 symbol *rlbl = newiTempLabel (NULL);
2654 spillPair (PAIR_HL);
2655 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2657 _G.stack.pushed += 2;
2659 fetchHL (AOP (IC_LEFT (ic)));
2661 emit2 ("!tlabeldef", (rlbl->key + 100));
2662 _G.stack.pushed -= 2;
2664 freeAsmop (IC_LEFT (ic), NULL, ic);
2668 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2669 OP_SYMBOL (IC_LEFT (ic))->rname :
2670 OP_SYMBOL (IC_LEFT (ic))->name;
2671 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2673 emit2 ("call banked_call");
2674 emit2 ("!dws", name);
2675 emit2 ("!dw !bankimmeds", name);
2680 emit2 ("call %s", name);
2685 /* Mark the regsiters as restored. */
2686 _G.saves.saved = FALSE;
2688 /* if we need assign a result value */
2689 if ((IS_ITEMP (IC_RESULT (ic)) &&
2690 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2691 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2692 IS_TRUE_SYMOP (IC_RESULT (ic)))
2695 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2697 assignResultValue (IC_RESULT (ic));
2699 freeAsmop (IC_RESULT (ic), NULL, ic);
2702 /* adjust the stack for parameters if required */
2705 int i = ic->parmBytes;
2707 _G.stack.pushed -= i;
2710 emit2 ("!ldaspsp", i);
2717 emit2 ("ld iy,!immedword", i);
2718 emit2 ("add iy,sp");
2738 if (_G.stack.pushedDE)
2740 bool dInRet = bitVectBitValue(ic->rUsed, D_IDX);
2741 bool eInRet = bitVectBitValue(ic->rUsed, E_IDX);
2743 if (dInRet && eInRet)
2745 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
2749 /* Only restore E */
2756 /* Only restore D */
2764 _G.stack.pushedDE = FALSE;
2767 if (_G.stack.pushedBC)
2769 bool bInRet = bitVectBitValue(ic->rUsed, B_IDX);
2770 bool cInRet = bitVectBitValue(ic->rUsed, C_IDX);
2772 if (bInRet && cInRet)
2774 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
2778 /* Only restore C */
2785 /* Only restore B */
2793 _G.stack.pushedBC = FALSE;
2797 /*-----------------------------------------------------------------*/
2798 /* genCall - generates a call statement */
2799 /*-----------------------------------------------------------------*/
2801 genCall (iCode * ic)
2803 emitCall (ic, FALSE);
2806 /*-----------------------------------------------------------------*/
2807 /* genPcall - generates a call by pointer statement */
2808 /*-----------------------------------------------------------------*/
2810 genPcall (iCode * ic)
2812 emitCall (ic, TRUE);
2815 /*-----------------------------------------------------------------*/
2816 /* resultRemat - result is rematerializable */
2817 /*-----------------------------------------------------------------*/
2819 resultRemat (iCode * ic)
2821 if (SKIP_IC (ic) || ic->op == IFX)
2824 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2826 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2827 if (sym->remat && !POINTER_SET (ic))
2834 extern set *publics;
2836 /*-----------------------------------------------------------------*/
2837 /* genFunction - generated code for function entry */
2838 /*-----------------------------------------------------------------*/
2840 genFunction (iCode * ic)
2842 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2845 bool bcInUse = FALSE;
2846 bool deInUse = FALSE;
2848 setArea (IFFUNC_NONBANKED (sym->type));
2850 /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
2853 _G.receiveOffset = 0;
2855 /* Record the last function name for debugging. */
2856 _G.lastFunctionName = sym->rname;
2858 /* Create the function header */
2859 emit2 ("!functionheader", sym->name);
2860 sprintf (buffer, "%s_start", sym->rname);
2861 emit2 ("!labeldef", buffer);
2862 emit2 ("!functionlabeldef", sym->rname);
2864 if (options.profile)
2866 emit2 ("!profileenter");
2869 ftype = operandType (IC_LEFT (ic));
2871 /* if critical function then turn interrupts off */
2872 if (IFFUNC_ISCRITICAL (ftype))
2875 /* if this is an interrupt service routine then save all potentially used registers. */
2876 if (IFFUNC_ISISR (sym->type))
2881 /* PENDING: callee-save etc */
2883 _G.stack.param_offset = 0;
2885 if (z80_opts.calleeSavesBC)
2890 /* Detect which registers are used. */
2891 if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
2894 for (i = 0; i < sym->regsUsed->size; i++)
2896 if (bitVectBitValue (sym->regsUsed, i))
2910 /* Other systems use DE as a temporary. */
2921 _G.stack.param_offset += 2;
2924 _G.calleeSaves.pushedBC = bcInUse;
2929 _G.stack.param_offset += 2;
2932 _G.calleeSaves.pushedDE = deInUse;
2934 /* adjust the stack for the function */
2935 _G.stack.last = sym->stack;
2937 if (sym->stack && IS_GB && sym->stack > -INT8MIN)
2938 emit2 ("!enterxl", sym->stack);
2939 else if (sym->stack)
2940 emit2 ("!enterx", sym->stack);
2943 _G.stack.offset = sym->stack;
2946 /*-----------------------------------------------------------------*/
2947 /* genEndFunction - generates epilogue for functions */
2948 /*-----------------------------------------------------------------*/
2950 genEndFunction (iCode * ic)
2952 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2954 if (IFFUNC_ISISR (sym->type))
2956 wassertl (0, "Tried to close an interrupt support function");
2960 if (IFFUNC_ISCRITICAL (sym->type))
2963 /* PENDING: calleeSave */
2965 if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
2967 emit2 ("!leavexl", _G.stack.offset);
2969 else if (_G.stack.offset)
2971 emit2 ("!leavex", _G.stack.offset);
2978 if (_G.calleeSaves.pushedDE)
2981 _G.calleeSaves.pushedDE = FALSE;
2984 if (_G.calleeSaves.pushedBC)
2987 _G.calleeSaves.pushedBC = FALSE;
2990 if (options.profile)
2992 emit2 ("!profileexit");
2996 /* Both baned and non-banked just ret */
2999 sprintf (buffer, "%s_end", sym->rname);
3000 emit2 ("!labeldef", buffer);
3002 _G.flushStatics = 1;
3003 _G.stack.pushed = 0;
3004 _G.stack.offset = 0;
3007 /*-----------------------------------------------------------------*/
3008 /* genRet - generate code for return statement */
3009 /*-----------------------------------------------------------------*/
3014 /* Errk. This is a hack until I can figure out how
3015 to cause dehl to spill on a call */
3016 int size, offset = 0;
3018 /* if we have no return value then
3019 just generate the "ret" */
3023 /* we have something to return then
3024 move the return value into place */
3025 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3026 size = AOP_SIZE (IC_LEFT (ic));
3028 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
3032 emit2 ("ld de,%s", l);
3036 emit2 ("ld hl,%s", l);
3041 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
3043 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3044 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
3050 l = aopGet (AOP (IC_LEFT (ic)), offset,
3052 if (strcmp (_fReturn[offset], l))
3053 emit2 ("ld %s,%s", _fReturn[offset++], l);
3057 freeAsmop (IC_LEFT (ic), NULL, ic);
3060 /* generate a jump to the return label
3061 if the next is not the return statement */
3062 if (!(ic->next && ic->next->op == LABEL &&
3063 IC_LABEL (ic->next) == returnLabel))
3065 emit2 ("jp !tlabel", returnLabel->key + 100);
3068 /*-----------------------------------------------------------------*/
3069 /* genLabel - generates a label */
3070 /*-----------------------------------------------------------------*/
3072 genLabel (iCode * ic)
3074 /* special case never generate */
3075 if (IC_LABEL (ic) == entryLabel)
3078 emitLabel (IC_LABEL (ic)->key + 100);
3081 /*-----------------------------------------------------------------*/
3082 /* genGoto - generates a ljmp */
3083 /*-----------------------------------------------------------------*/
3085 genGoto (iCode * ic)
3087 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
3090 /*-----------------------------------------------------------------*/
3091 /* genPlusIncr :- does addition with increment if possible */
3092 /*-----------------------------------------------------------------*/
3094 genPlusIncr (iCode * ic)
3096 unsigned int icount;
3097 unsigned int size = getDataSize (IC_RESULT (ic));
3098 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
3100 /* will try to generate an increment */
3101 /* if the right side is not a literal
3103 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3106 emitDebug ("; genPlusIncr");
3108 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3110 /* If result is a pair */
3111 if (resultId != PAIR_INVALID)
3113 if (isLitWord (AOP (IC_LEFT (ic))))
3115 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
3118 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
3120 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
3122 PAIR_ID freep = getFreePairId (ic);
3123 if (freep != PAIR_INVALID)
3125 fetchPair (freep, AOP (IC_RIGHT (ic)));
3126 emit2 ("add hl,%s", _pairs[freep].name);
3132 fetchPair (resultId, AOP (IC_RIGHT (ic)));
3133 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3140 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3144 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3148 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3153 if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3155 fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3156 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3160 /* if the literal value of the right hand side
3161 is greater than 4 then it is not worth it */
3165 /* if increment 16 bits in register */
3166 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3172 symbol *tlbl = NULL;
3173 tlbl = newiTempLabel (NULL);
3176 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3179 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3182 emitLabel (tlbl->key + 100);
3186 /* if the sizes are greater than 1 then we cannot */
3187 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3188 AOP_SIZE (IC_LEFT (ic)) > 1)
3191 /* If the result is in a register then we can load then increment.
3193 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3195 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3198 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3203 /* we can if the aops of the left & result match or
3204 if they are in registers and the registers are the
3206 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3210 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3218 /*-----------------------------------------------------------------*/
3219 /* outBitAcc - output a bit in acc */
3220 /*-----------------------------------------------------------------*/
3222 outBitAcc (operand * result)
3224 symbol *tlbl = newiTempLabel (NULL);
3225 /* if the result is a bit */
3226 if (AOP_TYPE (result) == AOP_CRY)
3228 wassertl (0, "Tried to write A into a bit");
3232 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3233 emit2 ("ld a,!one");
3234 emitLabel (tlbl->key + 100);
3240 couldDestroyCarry (asmop *aop)
3244 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3253 shiftIntoPair (int idx, asmop *aop)
3255 PAIR_ID id = PAIR_INVALID;
3257 wassertl (IS_Z80, "Only implemented for the Z80");
3258 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3270 wassertl (0, "Internal error - hit default case");
3273 emitDebug ("; Shift into pair idx %u", idx);
3277 setupPair (PAIR_HL, aop, 0);
3281 setupPair (PAIR_IY, aop, 0);
3283 emit2 ("pop %s", _pairs[id].name);
3286 aop->type = AOP_PAIRPTR;
3287 aop->aopu.aop_pairId = id;
3288 _G.pairs[id].offset = 0;
3289 _G.pairs[id].last_type = aop->type;
3293 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
3295 wassert (left && right);
3299 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3301 shiftIntoPair (0, right);
3302 shiftIntoPair (1, result);
3304 else if (couldDestroyCarry (right))
3306 shiftIntoPair (0, right);
3308 else if (couldDestroyCarry (result))
3310 shiftIntoPair (0, result);
3319 /*-----------------------------------------------------------------*/
3320 /* genPlus - generates code for addition */
3321 /*-----------------------------------------------------------------*/
3323 genPlus (iCode * ic)
3325 int size, offset = 0;
3327 /* special cases :- */
3329 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3330 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3331 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3333 /* Swap the left and right operands if:
3335 if literal, literal on the right or
3336 if left requires ACC or right is already
3339 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3340 (AOP_NEEDSACC (IC_LEFT (ic))) ||
3341 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3343 operand *t = IC_RIGHT (ic);
3344 IC_RIGHT (ic) = IC_LEFT (ic);
3348 /* if both left & right are in bit
3350 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3351 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3354 wassertl (0, "Tried to add two bits");
3357 /* if left in bit space & right literal */
3358 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3359 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3361 /* Can happen I guess */
3362 wassertl (0, "Tried to add a bit to a literal");
3365 /* if I can do an increment instead
3366 of add then GOOD for ME */
3367 if (genPlusIncr (ic) == TRUE)
3370 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3372 size = getDataSize (IC_RESULT (ic));
3374 /* Special case when left and right are constant */
3375 if (isPair (AOP (IC_RESULT (ic))))
3378 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3379 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3381 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3387 sprintf (buffer, "#(%s + %s)", left, right);
3388 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3393 if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3395 /* Fetch into HL then do the add */
3396 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3397 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3399 spillPair (PAIR_HL);
3401 if (left == PAIR_HL && right != PAIR_INVALID)
3403 emit2 ("add hl,%s", _pairs[right].name);
3406 else if (right == PAIR_HL && left != PAIR_INVALID)
3408 emit2 ("add hl,%s", _pairs[left].name);
3411 else if (right != PAIR_INVALID && right != PAIR_HL)
3413 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3414 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3417 else if (left != PAIR_INVALID && left != PAIR_HL)
3419 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3420 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3429 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3431 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3432 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3434 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3439 ld hl,sp+n trashes C so we cant afford to do it during an
3440 add with stack based varibles. Worst case is:
3453 So you cant afford to load up hl if either left, right, or result
3454 is on the stack (*sigh*) The alt is:
3462 Combinations in here are:
3463 * If left or right are in bc then the loss is small - trap later
3464 * If the result is in bc then the loss is also small
3468 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3469 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3470 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3472 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3473 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3474 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3475 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3477 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3479 /* Swap left and right */
3480 operand *t = IC_RIGHT (ic);
3481 IC_RIGHT (ic) = IC_LEFT (ic);
3484 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3486 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3487 emit2 ("add hl,bc");
3491 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3492 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3493 emit2 ("add hl,de");
3495 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3501 /* Be paranoid on the GB with 4 byte variables due to how C
3502 can be trashed by lda hl,n(sp).
3504 _gbz80_emitAddSubLong (ic, TRUE);
3509 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3513 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3515 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3518 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3521 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3525 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3528 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3531 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3533 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3537 freeAsmop (IC_LEFT (ic), NULL, ic);
3538 freeAsmop (IC_RIGHT (ic), NULL, ic);
3539 freeAsmop (IC_RESULT (ic), NULL, ic);
3543 /*-----------------------------------------------------------------*/
3544 /* genMinusDec :- does subtraction with deccrement if possible */
3545 /*-----------------------------------------------------------------*/
3547 genMinusDec (iCode * ic)
3549 unsigned int icount;
3550 unsigned int size = getDataSize (IC_RESULT (ic));
3552 /* will try to generate an increment */
3553 /* if the right side is not a literal we cannot */
3554 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3557 /* if the literal value of the right hand side
3558 is greater than 4 then it is not worth it */
3559 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3562 size = getDataSize (IC_RESULT (ic));
3564 /* if decrement 16 bits in register */
3565 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3566 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3569 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3573 /* If result is a pair */
3574 if (isPair (AOP (IC_RESULT (ic))))
3576 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3578 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3582 /* if increment 16 bits in register */
3583 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3587 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3590 emit2 ("dec %s", _getTempPairName());
3593 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3599 /* if the sizes are greater than 1 then we cannot */
3600 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3601 AOP_SIZE (IC_LEFT (ic)) > 1)
3604 /* we can if the aops of the left & result match or if they are in
3605 registers and the registers are the same */
3606 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3609 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3616 /*-----------------------------------------------------------------*/
3617 /* genMinus - generates code for subtraction */
3618 /*-----------------------------------------------------------------*/
3620 genMinus (iCode * ic)
3622 int size, offset = 0;
3623 unsigned long lit = 0L;
3625 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3626 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3627 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3629 /* special cases :- */
3630 /* if both left & right are in bit space */
3631 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3632 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3634 wassertl (0, "Tried to subtract two bits");
3638 /* if I can do an decrement instead of subtract then GOOD for ME */
3639 if (genMinusDec (ic) == TRUE)
3642 size = getDataSize (IC_RESULT (ic));
3644 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3649 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3653 /* Same logic as genPlus */
3656 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3657 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3658 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3660 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3661 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3662 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3663 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3665 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3666 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3668 if (left == PAIR_INVALID && right == PAIR_INVALID)
3673 else if (right == PAIR_INVALID)
3675 else if (left == PAIR_INVALID)
3678 fetchPair (left, AOP (IC_LEFT (ic)));
3679 /* Order is important. Right may be HL */
3680 fetchPair (right, AOP (IC_RIGHT (ic)));
3682 emit2 ("ld a,%s", _pairs[left].l);
3683 emit2 ("sub a,%s", _pairs[right].l);
3685 emit2 ("ld a,%s", _pairs[left].h);
3686 emit2 ("sbc a,%s", _pairs[right].h);
3688 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
3690 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3692 aopPut (AOP (IC_RESULT (ic)), "e", 0);
3698 /* Be paranoid on the GB with 4 byte variables due to how C
3699 can be trashed by lda hl,n(sp).
3701 _gbz80_emitAddSubLong (ic, FALSE);
3706 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3708 /* if literal, add a,#-lit, else normal subb */
3711 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3712 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3716 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3719 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3723 /* first add without previous c */
3725 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
3727 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3729 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3732 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3733 AOP_SIZE (IC_LEFT (ic)) == 3 &&
3734 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3736 wassertl (0, "Tried to subtract on a long pointer");
3740 freeAsmop (IC_LEFT (ic), NULL, ic);
3741 freeAsmop (IC_RIGHT (ic), NULL, ic);
3742 freeAsmop (IC_RESULT (ic), NULL, ic);
3745 /*-----------------------------------------------------------------*/
3746 /* genMult - generates code for multiplication */
3747 /*-----------------------------------------------------------------*/
3749 genMult (iCode * ic)
3753 /* If true then the final operation should be a subtract */
3754 bool active = FALSE;
3756 /* Shouldn't occur - all done through function calls */
3757 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3758 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3759 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3761 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
3762 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
3763 AOP_SIZE (IC_RESULT (ic)) > 2)
3765 wassertl (0, "Multiplication is handled through support function calls");
3768 /* Swap left and right such that right is a literal */
3769 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
3771 operand *t = IC_RIGHT (ic);
3772 IC_RIGHT (ic) = IC_LEFT (ic);
3776 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
3778 val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
3779 // wassertl (val > 0, "Multiply must be positive");
3780 wassertl (val != 1, "Can't multiply by 1");
3782 if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
3784 _G.stack.pushedDE = TRUE;
3787 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
3789 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
3797 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3802 /* Fully unroled version of mul.s. Not the most efficient.
3804 for (count = 0; count < 16; count++)
3806 if (count != 0 && active)
3808 emit2 ("add hl,hl");
3812 if (active == FALSE)
3819 emit2 ("add hl,de");
3828 if (IS_Z80 && _G.stack.pushedDE)
3831 _G.stack.pushedDE = FALSE;
3834 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3836 freeAsmop (IC_LEFT (ic), NULL, ic);
3837 freeAsmop (IC_RIGHT (ic), NULL, ic);
3838 freeAsmop (IC_RESULT (ic), NULL, ic);
3841 /*-----------------------------------------------------------------*/
3842 /* genDiv - generates code for division */
3843 /*-----------------------------------------------------------------*/
3847 /* Shouldn't occur - all done through function calls */
3848 wassertl (0, "Division is handled through support function calls");
3851 /*-----------------------------------------------------------------*/
3852 /* genMod - generates code for division */
3853 /*-----------------------------------------------------------------*/
3857 /* Shouldn't occur - all done through function calls */
3861 /*-----------------------------------------------------------------*/
3862 /* genIfxJump :- will create a jump depending on the ifx */
3863 /*-----------------------------------------------------------------*/
3865 genIfxJump (iCode * ic, char *jval)
3870 /* if true label then we jump if condition
3874 jlbl = IC_TRUE (ic);
3875 if (!strcmp (jval, "a"))
3879 else if (!strcmp (jval, "c"))
3883 else if (!strcmp (jval, "nc"))
3887 else if (!strcmp (jval, "m"))
3891 else if (!strcmp (jval, "p"))
3897 /* The buffer contains the bit on A that we should test */
3903 /* false label is present */
3904 jlbl = IC_FALSE (ic);
3905 if (!strcmp (jval, "a"))
3909 else if (!strcmp (jval, "c"))
3913 else if (!strcmp (jval, "nc"))
3917 else if (!strcmp (jval, "m"))
3921 else if (!strcmp (jval, "p"))
3927 /* The buffer contains the bit on A that we should test */
3931 /* Z80 can do a conditional long jump */
3932 if (!strcmp (jval, "a"))
3936 else if (!strcmp (jval, "c"))
3939 else if (!strcmp (jval, "nc"))
3942 else if (!strcmp (jval, "m"))
3945 else if (!strcmp (jval, "p"))
3950 emit2 ("bit %s,a", jval);
3952 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
3954 /* mark the icode as generated */
3960 _getPairIdName (PAIR_ID id)
3962 return _pairs[id].name;
3967 /* if unsigned char cmp with lit, just compare */
3969 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
3971 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3974 emit2 ("xor a,!immedbyte", 0x80);
3975 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
3978 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3980 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
3982 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
3983 // Pull left into DE and right into HL
3984 aopGet (AOP(left), LSB, FALSE);
3987 aopGet (AOP(right), LSB, FALSE);
3991 if (size == 0 && sign)
3993 // Highest byte when signed needs the bits flipped
3996 emit2 ("ld a,(de)");
3997 emit2 ("xor !immedbyte", 0x80);
3999 emit2 ("ld a,(hl)");
4000 emit2 ("xor !immedbyte", 0x80);
4004 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
4008 emit2 ("ld a,(de)");
4009 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4019 spillPair (PAIR_HL);
4021 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
4023 setupPair (PAIR_HL, AOP (left), 0);
4024 aopGet (AOP(right), LSB, FALSE);
4028 if (size == 0 && sign)
4030 // Highest byte when signed needs the bits flipped
4033 emit2 ("ld a,(hl)");
4034 emit2 ("xor !immedbyte", 0x80);
4036 emit2 ("ld a,%d(iy)", offset);
4037 emit2 ("xor !immedbyte", 0x80);
4041 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
4045 emit2 ("ld a,(hl)");
4046 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
4055 spillPair (PAIR_HL);
4056 spillPair (PAIR_IY);
4060 if (AOP_TYPE (right) == AOP_LIT)
4062 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4063 /* optimize if(x < 0) or if(x >= 0) */
4068 /* No sign so it's always false */
4073 /* Just load in the top most bit */
4074 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4075 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4077 genIfxJump (ifx, "7");
4089 /* First setup h and l contaning the top most bytes XORed */
4090 bool fDidXor = FALSE;
4091 if (AOP_TYPE (left) == AOP_LIT)
4093 unsigned long lit = (unsigned long)
4094 floatFromVal (AOP (left)->aopu.aop_lit);
4095 emit2 ("ld %s,!immedbyte", _fTmp[0],
4096 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4100 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
4101 emit2 ("xor a,!immedbyte", 0x80);
4102 emit2 ("ld %s,a", _fTmp[0]);
4105 if (AOP_TYPE (right) == AOP_LIT)
4107 unsigned long lit = (unsigned long)
4108 floatFromVal (AOP (right)->aopu.aop_lit);
4109 emit2 ("ld %s,!immedbyte", _fTmp[1],
4110 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
4114 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
4115 emit2 ("xor a,!immedbyte", 0x80);
4116 emit2 ("ld %s,a", _fTmp[1]);
4122 /* Do a long subtract */
4125 _moveA (aopGet (AOP (left), offset, FALSE));
4127 if (sign && size == 0)
4129 emit2 ("ld a,%s", _fTmp[0]);
4130 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
4134 /* Subtract through, propagating the carry */
4135 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4143 /** Generic compare for > or <
4146 genCmp (operand * left, operand * right,
4147 operand * result, iCode * ifx, int sign)
4149 int size, offset = 0;
4150 unsigned long lit = 0L;
4151 bool swap_sense = FALSE;
4153 /* if left & right are bit variables */
4154 if (AOP_TYPE (left) == AOP_CRY &&
4155 AOP_TYPE (right) == AOP_CRY)
4157 /* Cant happen on the Z80 */
4158 wassertl (0, "Tried to compare two bits");
4162 /* Do a long subtract of right from left. */
4163 size = max (AOP_SIZE (left), AOP_SIZE (right));
4165 if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4167 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4168 // Pull left into DE and right into HL
4169 aopGet (AOP(left), LSB, FALSE);
4172 aopGet (AOP(right), LSB, FALSE);
4176 emit2 ("ld a,(de)");
4177 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4186 spillPair (PAIR_HL);
4190 if (AOP_TYPE (right) == AOP_LIT)
4192 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4193 /* optimize if(x < 0) or if(x >= 0) */
4198 /* No sign so it's always false */
4203 /* Just load in the top most bit */
4204 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4205 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4207 genIfxJump (ifx, "7");
4218 genIfxJump (ifx, swap_sense ? "c" : "nc");
4229 _moveA (aopGet (AOP (left), offset, FALSE));
4230 /* Subtract through, propagating the carry */
4231 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4237 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4241 /* Shift the sign bit up into carry */
4244 outBitCLong (result, swap_sense);
4248 /* if the result is used in the next
4249 ifx conditional branch then generate
4250 code a little differently */
4258 genIfxJump (ifx, swap_sense ? "nc" : "c");
4262 genIfxJump (ifx, swap_sense ? "p" : "m");
4267 genIfxJump (ifx, swap_sense ? "nc" : "c");
4274 /* Shift the sign bit up into carry */
4277 outBitCLong (result, swap_sense);
4279 /* leave the result in acc */
4283 /*-----------------------------------------------------------------*/
4284 /* genCmpGt :- greater than comparison */
4285 /*-----------------------------------------------------------------*/
4287 genCmpGt (iCode * ic, iCode * ifx)
4289 operand *left, *right, *result;
4290 sym_link *letype, *retype;
4293 left = IC_LEFT (ic);
4294 right = IC_RIGHT (ic);
4295 result = IC_RESULT (ic);
4297 letype = getSpec (operandType (left));
4298 retype = getSpec (operandType (right));
4299 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4300 /* assign the amsops */
4301 aopOp (left, ic, FALSE, FALSE);
4302 aopOp (right, ic, FALSE, FALSE);
4303 aopOp (result, ic, TRUE, FALSE);
4305 genCmp (right, left, result, ifx, sign);
4307 freeAsmop (left, NULL, ic);
4308 freeAsmop (right, NULL, ic);
4309 freeAsmop (result, NULL, ic);
4312 /*-----------------------------------------------------------------*/
4313 /* genCmpLt - less than comparisons */
4314 /*-----------------------------------------------------------------*/
4316 genCmpLt (iCode * ic, iCode * ifx)
4318 operand *left, *right, *result;
4319 sym_link *letype, *retype;
4322 left = IC_LEFT (ic);
4323 right = IC_RIGHT (ic);
4324 result = IC_RESULT (ic);
4326 letype = getSpec (operandType (left));
4327 retype = getSpec (operandType (right));
4328 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4330 /* assign the amsops */
4331 aopOp (left, ic, FALSE, FALSE);
4332 aopOp (right, ic, FALSE, FALSE);
4333 aopOp (result, ic, TRUE, FALSE);
4335 genCmp (left, right, result, ifx, sign);
4337 freeAsmop (left, NULL, ic);
4338 freeAsmop (right, NULL, ic);
4339 freeAsmop (result, NULL, ic);
4342 /*-----------------------------------------------------------------*/
4343 /* gencjneshort - compare and jump if not equal */
4344 /*-----------------------------------------------------------------*/
4346 gencjneshort (operand * left, operand * right, symbol * lbl)
4348 int size = max (AOP_SIZE (left), AOP_SIZE (right));
4350 unsigned long lit = 0L;
4352 /* Swap the left and right if it makes the computation easier */
4353 if (AOP_TYPE (left) == AOP_LIT)
4360 if (AOP_TYPE (right) == AOP_LIT)
4362 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4365 /* if the right side is a literal then anything goes */
4366 if (AOP_TYPE (right) == AOP_LIT &&
4367 AOP_TYPE (left) != AOP_DIR)
4371 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4376 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4383 emit2 ("jp nz,!tlabel", lbl->key + 100);
4389 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4390 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
4393 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
4394 emit2 ("jp nz,!tlabel", lbl->key + 100);
4399 /* if the right side is in a register or in direct space or
4400 if the left is a pointer register & right is not */
4401 else if (AOP_TYPE (right) == AOP_REG ||
4402 AOP_TYPE (right) == AOP_DIR ||
4403 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
4407 _moveA (aopGet (AOP (left), offset, FALSE));
4408 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
4409 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4411 emit2 ("jp nz,!tlabel", lbl->key + 100);
4414 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4415 emit2 ("jp nz,!tlabel", lbl->key + 100);
4422 /* right is a pointer reg need both a & b */
4423 /* PENDING: is this required? */
4426 _moveA (aopGet (AOP (right), offset, FALSE));
4427 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
4428 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
4434 /*-----------------------------------------------------------------*/
4435 /* gencjne - compare and jump if not equal */
4436 /*-----------------------------------------------------------------*/
4438 gencjne (operand * left, operand * right, symbol * lbl)
4440 symbol *tlbl = newiTempLabel (NULL);
4442 gencjneshort (left, right, lbl);
4445 emit2 ("ld a,!one");
4446 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4447 emitLabel (lbl->key + 100);
4449 emitLabel (tlbl->key + 100);
4452 /*-----------------------------------------------------------------*/
4453 /* genCmpEq - generates code for equal to */
4454 /*-----------------------------------------------------------------*/
4456 genCmpEq (iCode * ic, iCode * ifx)
4458 operand *left, *right, *result;
4460 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4461 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4462 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4464 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4466 /* Swap operands if it makes the operation easier. ie if:
4467 1. Left is a literal.
4469 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4471 operand *t = IC_RIGHT (ic);
4472 IC_RIGHT (ic) = IC_LEFT (ic);
4476 if (ifx && !AOP_SIZE (result))
4479 /* if they are both bit variables */
4480 if (AOP_TYPE (left) == AOP_CRY &&
4481 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4483 wassertl (0, "Tried to compare two bits");
4487 tlbl = newiTempLabel (NULL);
4488 gencjneshort (left, right, tlbl);
4491 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4492 emitLabel (tlbl->key + 100);
4496 /* PENDING: do this better */
4497 symbol *lbl = newiTempLabel (NULL);
4498 emit2 ("!shortjp !tlabel", lbl->key + 100);
4499 emitLabel (tlbl->key + 100);
4500 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4501 emitLabel (lbl->key + 100);
4504 /* mark the icode as generated */
4509 /* if they are both bit variables */
4510 if (AOP_TYPE (left) == AOP_CRY &&
4511 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4513 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4519 gencjne (left, right, newiTempLabel (NULL));
4520 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4527 genIfxJump (ifx, "a");
4530 /* if the result is used in an arithmetic operation
4531 then put the result in place */
4532 if (AOP_TYPE (result) != AOP_CRY)
4537 /* leave the result in acc */
4541 freeAsmop (left, NULL, ic);
4542 freeAsmop (right, NULL, ic);
4543 freeAsmop (result, NULL, ic);
4546 /*-----------------------------------------------------------------*/
4547 /* ifxForOp - returns the icode containing the ifx for operand */
4548 /*-----------------------------------------------------------------*/
4550 ifxForOp (operand * op, iCode * ic)
4552 /* if true symbol then needs to be assigned */
4553 if (IS_TRUE_SYMOP (op))
4556 /* if this has register type condition and
4557 the next instruction is ifx with the same operand
4558 and live to of the operand is upto the ifx only then */
4560 ic->next->op == IFX &&
4561 IC_COND (ic->next)->key == op->key &&
4562 OP_SYMBOL (op)->liveTo <= ic->next->seq)
4568 /*-----------------------------------------------------------------*/
4569 /* genAndOp - for && operation */
4570 /*-----------------------------------------------------------------*/
4572 genAndOp (iCode * ic)
4574 operand *left, *right, *result;
4577 /* note here that && operations that are in an if statement are
4578 taken away by backPatchLabels only those used in arthmetic
4579 operations remain */
4580 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4581 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4582 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4584 /* if both are bit variables */
4585 if (AOP_TYPE (left) == AOP_CRY &&
4586 AOP_TYPE (right) == AOP_CRY)
4588 wassertl (0, "Tried to and two bits");
4592 tlbl = newiTempLabel (NULL);
4594 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
4596 emitLabel (tlbl->key + 100);
4600 freeAsmop (left, NULL, ic);
4601 freeAsmop (right, NULL, ic);
4602 freeAsmop (result, NULL, ic);
4605 /*-----------------------------------------------------------------*/
4606 /* genOrOp - for || operation */
4607 /*-----------------------------------------------------------------*/
4609 genOrOp (iCode * ic)
4611 operand *left, *right, *result;
4614 /* note here that || operations that are in an
4615 if statement are taken away by backPatchLabels
4616 only those used in arthmetic operations remain */
4617 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4618 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4619 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4621 /* if both are bit variables */
4622 if (AOP_TYPE (left) == AOP_CRY &&
4623 AOP_TYPE (right) == AOP_CRY)
4625 wassertl (0, "Tried to OR two bits");
4629 tlbl = newiTempLabel (NULL);
4631 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4633 emitLabel (tlbl->key + 100);
4637 freeAsmop (left, NULL, ic);
4638 freeAsmop (right, NULL, ic);
4639 freeAsmop (result, NULL, ic);
4642 /*-----------------------------------------------------------------*/
4643 /* isLiteralBit - test if lit == 2^n */
4644 /*-----------------------------------------------------------------*/
4646 isLiteralBit (unsigned long lit)
4648 unsigned long pw[32] =
4649 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
4650 0x100L, 0x200L, 0x400L, 0x800L,
4651 0x1000L, 0x2000L, 0x4000L, 0x8000L,
4652 0x10000L, 0x20000L, 0x40000L, 0x80000L,
4653 0x100000L, 0x200000L, 0x400000L, 0x800000L,
4654 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
4655 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
4658 for (idx = 0; idx < 32; idx++)
4664 /*-----------------------------------------------------------------*/
4665 /* jmpTrueOrFalse - */
4666 /*-----------------------------------------------------------------*/
4668 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
4670 // ugly but optimized by peephole
4673 symbol *nlbl = newiTempLabel (NULL);
4674 emit2 ("jp !tlabel", nlbl->key + 100);
4675 emitLabel (tlbl->key + 100);
4676 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
4677 emitLabel (nlbl->key + 100);
4681 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
4682 emitLabel (tlbl->key + 100);
4687 /*-----------------------------------------------------------------*/
4688 /* genAnd - code for and */
4689 /*-----------------------------------------------------------------*/
4691 genAnd (iCode * ic, iCode * ifx)
4693 operand *left, *right, *result;
4694 int size, offset = 0;
4695 unsigned long lit = 0L;
4698 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4699 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4700 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4702 /* if left is a literal & right is not then exchange them */
4703 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4704 AOP_NEEDSACC (left))
4706 operand *tmp = right;
4711 /* if result = right then exchange them */
4712 if (sameRegs (AOP (result), AOP (right)))
4714 operand *tmp = right;
4719 /* if right is bit then exchange them */
4720 if (AOP_TYPE (right) == AOP_CRY &&
4721 AOP_TYPE (left) != AOP_CRY)
4723 operand *tmp = right;
4727 if (AOP_TYPE (right) == AOP_LIT)
4728 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4730 size = AOP_SIZE (result);
4732 if (AOP_TYPE (left) == AOP_CRY)
4734 wassertl (0, "Tried to perform an AND with a bit as an operand");
4738 // if(val & 0xZZ) - size = 0, ifx != FALSE -
4739 // bit = val & 0xZZ - size = 1, ifx = FALSE -
4740 if ((AOP_TYPE (right) == AOP_LIT) &&
4741 (AOP_TYPE (result) == AOP_CRY) &&
4742 (AOP_TYPE (left) != AOP_CRY))
4744 symbol *tlbl = newiTempLabel (NULL);
4745 int sizel = AOP_SIZE (left);
4748 /* PENDING: Test case for this. */
4753 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
4755 _moveA (aopGet (AOP (left), offset, FALSE));
4756 if (bytelit != 0x0FFL)
4758 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4765 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4769 // bit = left & literal
4773 emit2 ("!tlabeldef", tlbl->key + 100);
4775 // if(left & literal)
4780 jmpTrueOrFalse (ifx, tlbl);
4788 /* if left is same as result */
4789 if (sameRegs (AOP (result), AOP (left)))
4791 for (; size--; offset++)
4793 if (AOP_TYPE (right) == AOP_LIT)
4795 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4800 aopPut (AOP (result), "!zero", offset);
4803 _moveA (aopGet (AOP (left), offset, FALSE));
4805 aopGet (AOP (right), offset, FALSE));
4806 aopPut (AOP (left), "a", offset);
4813 if (AOP_TYPE (left) == AOP_ACC)
4815 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
4819 _moveA (aopGet (AOP (left), offset, FALSE));
4821 aopGet (AOP (right), offset, FALSE));
4822 aopPut (AOP (left), "a", offset);
4829 // left & result in different registers
4830 if (AOP_TYPE (result) == AOP_CRY)
4832 wassertl (0, "Tried to AND where the result is in carry");
4836 for (; (size--); offset++)
4839 // result = left & right
4840 if (AOP_TYPE (right) == AOP_LIT)
4842 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4844 aopPut (AOP (result),
4845 aopGet (AOP (left), offset, FALSE),
4849 else if (bytelit == 0)
4851 aopPut (AOP (result), "!zero", offset);
4855 // faster than result <- left, anl result,right
4856 // and better if result is SFR
4857 if (AOP_TYPE (left) == AOP_ACC)
4858 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4861 _moveA (aopGet (AOP (left), offset, FALSE));
4863 aopGet (AOP (right), offset, FALSE));
4865 aopPut (AOP (result), "a", offset);
4872 freeAsmop (left, NULL, ic);
4873 freeAsmop (right, NULL, ic);
4874 freeAsmop (result, NULL, ic);
4877 /*-----------------------------------------------------------------*/
4878 /* genOr - code for or */
4879 /*-----------------------------------------------------------------*/
4881 genOr (iCode * ic, iCode * ifx)
4883 operand *left, *right, *result;
4884 int size, offset = 0;
4885 unsigned long lit = 0L;
4888 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4889 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4890 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4892 /* if left is a literal & right is not then exchange them */
4893 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4894 AOP_NEEDSACC (left))
4896 operand *tmp = right;
4901 /* if result = right then exchange them */
4902 if (sameRegs (AOP (result), AOP (right)))
4904 operand *tmp = right;
4909 /* if right is bit then exchange them */
4910 if (AOP_TYPE (right) == AOP_CRY &&
4911 AOP_TYPE (left) != AOP_CRY)
4913 operand *tmp = right;
4917 if (AOP_TYPE (right) == AOP_LIT)
4918 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4920 size = AOP_SIZE (result);
4922 if (AOP_TYPE (left) == AOP_CRY)
4924 wassertl (0, "Tried to OR where left is a bit");
4928 // if(val | 0xZZ) - size = 0, ifx != FALSE -
4929 // bit = val | 0xZZ - size = 1, ifx = FALSE -
4930 if ((AOP_TYPE (right) == AOP_LIT) &&
4931 (AOP_TYPE (result) == AOP_CRY) &&
4932 (AOP_TYPE (left) != AOP_CRY))
4934 symbol *tlbl = newiTempLabel (NULL);
4935 int sizel = AOP_SIZE (left);
4939 wassertl (0, "Result is assigned to a bit");
4941 /* PENDING: Modeled after the AND code which is inefficent. */
4944 bytelit = (lit >> (offset * 8)) & 0x0FFL;
4946 _moveA (aopGet (AOP (left), offset, FALSE));
4947 /* OR with any literal is the same as OR with itself. */
4949 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4955 jmpTrueOrFalse (ifx, tlbl);
4960 /* if left is same as result */
4961 if (sameRegs (AOP (result), AOP (left)))
4963 for (; size--; offset++)
4965 if (AOP_TYPE (right) == AOP_LIT)
4967 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4971 _moveA (aopGet (AOP (left), offset, FALSE));
4973 aopGet (AOP (right), offset, FALSE));
4974 aopPut (AOP (result), "a", offset);
4979 if (AOP_TYPE (left) == AOP_ACC)
4980 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4983 _moveA (aopGet (AOP (left), offset, FALSE));
4985 aopGet (AOP (right), offset, FALSE));
4986 aopPut (AOP (result), "a", offset);
4993 // left & result in different registers
4994 if (AOP_TYPE (result) == AOP_CRY)
4996 wassertl (0, "Result of OR is in a bit");
4999 for (; (size--); offset++)
5002 // result = left & right
5003 if (AOP_TYPE (right) == AOP_LIT)
5005 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5007 aopPut (AOP (result),
5008 aopGet (AOP (left), offset, FALSE),
5013 // faster than result <- left, anl result,right
5014 // and better if result is SFR
5015 if (AOP_TYPE (left) == AOP_ACC)
5016 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
5019 _moveA (aopGet (AOP (left), offset, FALSE));
5021 aopGet (AOP (right), offset, FALSE));
5023 aopPut (AOP (result), "a", offset);
5024 /* PENDING: something weird is going on here. Add exception. */
5025 if (AOP_TYPE (result) == AOP_ACC)
5031 freeAsmop (left, NULL, ic);
5032 freeAsmop (right, NULL, ic);
5033 freeAsmop (result, NULL, ic);
5036 /*-----------------------------------------------------------------*/
5037 /* genXor - code for xclusive or */
5038 /*-----------------------------------------------------------------*/
5040 genXor (iCode * ic, iCode * ifx)
5042 operand *left, *right, *result;
5043 int size, offset = 0;
5044 unsigned long lit = 0L;
5046 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
5047 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
5048 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
5050 /* if left is a literal & right is not then exchange them */
5051 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5052 AOP_NEEDSACC (left))
5054 operand *tmp = right;
5059 /* if result = right then exchange them */
5060 if (sameRegs (AOP (result), AOP (right)))
5062 operand *tmp = right;
5067 /* if right is bit then exchange them */
5068 if (AOP_TYPE (right) == AOP_CRY &&
5069 AOP_TYPE (left) != AOP_CRY)
5071 operand *tmp = right;
5075 if (AOP_TYPE (right) == AOP_LIT)
5076 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5078 size = AOP_SIZE (result);
5080 if (AOP_TYPE (left) == AOP_CRY)
5082 wassertl (0, "Tried to XOR a bit");
5086 // if(val & 0xZZ) - size = 0, ifx != FALSE -
5087 // bit = val & 0xZZ - size = 1, ifx = FALSE -
5088 if ((AOP_TYPE (right) == AOP_LIT) &&
5089 (AOP_TYPE (result) == AOP_CRY) &&
5090 (AOP_TYPE (left) != AOP_CRY))
5092 symbol *tlbl = newiTempLabel (NULL);
5093 int sizel = AOP_SIZE (left);
5097 /* PENDING: Test case for this. */
5098 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
5102 _moveA (aopGet (AOP (left), offset, FALSE));
5103 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5104 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5109 jmpTrueOrFalse (ifx, tlbl);
5113 wassertl (0, "Result of XOR was destined for a bit");
5118 /* if left is same as result */
5119 if (sameRegs (AOP (result), AOP (left)))
5121 for (; size--; offset++)
5123 if (AOP_TYPE (right) == AOP_LIT)
5125 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5129 _moveA (aopGet (AOP (right), offset, FALSE));
5131 aopGet (AOP (left), offset, FALSE));
5132 aopPut (AOP (result), "a", offset);
5137 if (AOP_TYPE (left) == AOP_ACC)
5139 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5143 _moveA (aopGet (AOP (right), offset, FALSE));
5145 aopGet (AOP (left), offset, FALSE));
5146 aopPut (AOP (result), "a", 0);
5153 // left & result in different registers
5154 if (AOP_TYPE (result) == AOP_CRY)
5156 wassertl (0, "Result of XOR is in a bit");
5159 for (; (size--); offset++)
5162 // result = left & right
5163 if (AOP_TYPE (right) == AOP_LIT)
5165 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5167 aopPut (AOP (result),
5168 aopGet (AOP (left), offset, FALSE),
5173 // faster than result <- left, anl result,right
5174 // and better if result is SFR
5175 if (AOP_TYPE (left) == AOP_ACC)
5177 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5181 _moveA (aopGet (AOP (right), offset, FALSE));
5183 aopGet (AOP (left), offset, FALSE));
5185 aopPut (AOP (result), "a", offset);
5190 freeAsmop (left, NULL, ic);
5191 freeAsmop (right, NULL, ic);
5192 freeAsmop (result, NULL, ic);
5195 /*-----------------------------------------------------------------*/
5196 /* genInline - write the inline code out */
5197 /*-----------------------------------------------------------------*/
5199 genInline (iCode * ic)
5201 char *buffer, *bp, *bp1;
5203 _G.lines.isInline += (!options.asmpeep);
5205 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5206 strcpy (buffer, IC_INLINE (ic));
5208 /* emit each line as a code */
5233 _G.lines.isInline -= (!options.asmpeep);
5237 /*-----------------------------------------------------------------*/
5238 /* genRRC - rotate right with carry */
5239 /*-----------------------------------------------------------------*/
5246 /*-----------------------------------------------------------------*/
5247 /* genRLC - generate code for rotate left with carry */
5248 /*-----------------------------------------------------------------*/
5255 /*-----------------------------------------------------------------*/
5256 /* genGetHbit - generates code get highest order bit */
5257 /*-----------------------------------------------------------------*/
5259 genGetHbit (iCode * ic)
5261 operand *left, *result;
5262 left = IC_LEFT (ic);
5263 result = IC_RESULT (ic);
5265 aopOp (left, ic, FALSE, FALSE);
5266 aopOp (result, ic, FALSE, FALSE);
5268 /* get the highest order byte into a */
5269 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5271 if (AOP_TYPE (result) == AOP_CRY)
5279 emit2 ("and a,!one");
5284 freeAsmop (left, NULL, ic);
5285 freeAsmop (result, NULL, ic);
5289 emitRsh2 (asmop *aop, int size, int is_signed)
5295 const char *l = aopGet (aop, size, FALSE);
5298 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5308 /*-----------------------------------------------------------------*/
5309 /* shiftR2Left2Result - shift right two bytes from left to result */
5310 /*-----------------------------------------------------------------*/
5312 shiftR2Left2Result (operand * left, int offl,
5313 operand * result, int offr,
5314 int shCount, int is_signed)
5317 symbol *tlbl, *tlbl1;
5319 movLeft2Result (left, offl, result, offr, 0);
5320 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5322 /* if (AOP(result)->type == AOP_REG) { */
5324 tlbl = newiTempLabel (NULL);
5325 tlbl1 = newiTempLabel (NULL);
5327 /* Left is already in result - so now do the shift */
5332 emitRsh2 (AOP (result), size, is_signed);
5337 emit2 ("ld a,!immedbyte+1", shCount);
5338 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5339 emitLabel (tlbl->key + 100);
5341 emitRsh2 (AOP (result), size, is_signed);
5343 emitLabel (tlbl1->key + 100);
5345 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5349 /*-----------------------------------------------------------------*/
5350 /* shiftL2Left2Result - shift left two bytes from left to result */
5351 /*-----------------------------------------------------------------*/
5353 shiftL2Left2Result (operand * left, int offl,
5354 operand * result, int offr, int shCount)
5356 if (sameRegs (AOP (result), AOP (left)) &&
5357 ((offl + MSB16) == offr))
5363 /* Copy left into result */
5364 movLeft2Result (left, offl, result, offr, 0);
5365 movLeft2Result (left, offl + 1, result, offr + 1, 0);
5368 if (getPairId (AOP (result)) == PAIR_HL)
5372 emit2 ("add hl,hl");
5379 symbol *tlbl, *tlbl1;
5382 tlbl = newiTempLabel (NULL);
5383 tlbl1 = newiTempLabel (NULL);
5385 if (AOP (result)->type == AOP_REG)
5389 for (offset = 0; offset < size; offset++)
5391 l = aopGet (AOP (result), offset, FALSE);
5395 emit2 ("sla %s", l);
5406 /* Left is already in result - so now do the shift */
5409 emit2 ("ld a,!immedbyte+1", shCount);
5410 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5411 emitLabel (tlbl->key + 100);
5416 l = aopGet (AOP (result), offset, FALSE);
5420 emit2 ("sla %s", l);
5431 emitLabel (tlbl1->key + 100);
5433 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5439 /*-----------------------------------------------------------------*/
5440 /* AccRol - rotate left accumulator by known count */
5441 /*-----------------------------------------------------------------*/
5443 AccRol (int shCount)
5445 shCount &= 0x0007; // shCount : 0..7
5522 /*-----------------------------------------------------------------*/
5523 /* AccLsh - left shift accumulator by known count */
5524 /*-----------------------------------------------------------------*/
5526 AccLsh (int shCount)
5528 static const unsigned char SLMask[] =
5530 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5539 else if (shCount == 2)
5546 /* rotate left accumulator */
5548 /* and kill the lower order bits */
5549 emit2 ("and a,!immedbyte", SLMask[shCount]);
5554 /*-----------------------------------------------------------------*/
5555 /* shiftL1Left2Result - shift left one byte from left to result */
5556 /*-----------------------------------------------------------------*/
5558 shiftL1Left2Result (operand * left, int offl,
5559 operand * result, int offr, int shCount)
5562 l = aopGet (AOP (left), offl, FALSE);
5564 /* shift left accumulator */
5566 aopPut (AOP (result), "a", offr);
5570 /*-----------------------------------------------------------------*/
5571 /* genlshTwo - left shift two bytes by known amount != 0 */
5572 /*-----------------------------------------------------------------*/
5574 genlshTwo (operand * result, operand * left, int shCount)
5576 int size = AOP_SIZE (result);
5578 wassert (size == 2);
5580 /* if shCount >= 8 */
5588 movLeft2Result (left, LSB, result, MSB16, 0);
5589 aopPut (AOP (result), "!zero", 0);
5590 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
5594 movLeft2Result (left, LSB, result, MSB16, 0);
5595 aopPut (AOP (result), "!zero", 0);
5600 aopPut (AOP (result), "!zero", LSB);
5603 /* 1 <= shCount <= 7 */
5612 shiftL2Left2Result (left, LSB, result, LSB, shCount);
5617 /*-----------------------------------------------------------------*/
5618 /* genlshOne - left shift a one byte quantity by known count */
5619 /*-----------------------------------------------------------------*/
5621 genlshOne (operand * result, operand * left, int shCount)
5623 shiftL1Left2Result (left, LSB, result, LSB, shCount);
5626 /*-----------------------------------------------------------------*/
5627 /* genLeftShiftLiteral - left shifting by known count */
5628 /*-----------------------------------------------------------------*/
5630 genLeftShiftLiteral (operand * left,
5635 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5638 freeAsmop (right, NULL, ic);
5640 aopOp (left, ic, FALSE, FALSE);
5641 aopOp (result, ic, FALSE, FALSE);
5643 size = getSize (operandType (result));
5645 /* I suppose that the left size >= result size */
5651 else if (shCount >= (size * 8))
5655 aopPut (AOP (result), "!zero", size);
5663 genlshOne (result, left, shCount);
5666 genlshTwo (result, left, shCount);
5669 wassertl (0, "Shifting of longs is currently unsupported");
5675 freeAsmop (left, NULL, ic);
5676 freeAsmop (result, NULL, ic);
5679 /*-----------------------------------------------------------------*/
5680 /* genLeftShift - generates code for left shifting */
5681 /*-----------------------------------------------------------------*/
5683 genLeftShift (iCode * ic)
5687 symbol *tlbl, *tlbl1;
5688 operand *left, *right, *result;
5690 right = IC_RIGHT (ic);
5691 left = IC_LEFT (ic);
5692 result = IC_RESULT (ic);
5694 aopOp (right, ic, FALSE, FALSE);
5696 /* if the shift count is known then do it
5697 as efficiently as possible */
5698 if (AOP_TYPE (right) == AOP_LIT)
5700 genLeftShiftLiteral (left, right, result, ic);
5704 /* shift count is unknown then we have to form a loop get the loop
5705 count in B : Note: we take only the lower order byte since
5706 shifting more that 32 bits make no sense anyway, ( the largest
5707 size of an object can be only 32 bits ) */
5708 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5710 freeAsmop (right, NULL, ic);
5711 aopOp (left, ic, FALSE, FALSE);
5712 aopOp (result, ic, FALSE, FALSE);
5714 /* now move the left to the result if they are not the
5717 if (!sameRegs (AOP (left), AOP (result)))
5720 size = AOP_SIZE (result);
5724 l = aopGet (AOP (left), offset, FALSE);
5725 aopPut (AOP (result), l, offset);
5730 tlbl = newiTempLabel (NULL);
5731 size = AOP_SIZE (result);
5733 tlbl1 = newiTempLabel (NULL);
5735 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5736 emitLabel (tlbl->key + 100);
5737 l = aopGet (AOP (result), offset, FALSE);
5741 l = aopGet (AOP (result), offset, FALSE);
5745 emit2 ("sla %s", l);
5753 emitLabel (tlbl1->key + 100);
5755 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5757 freeAsmop (left, NULL, ic);
5758 freeAsmop (result, NULL, ic);
5761 /*-----------------------------------------------------------------*/
5762 /* genrshOne - left shift two bytes by known amount != 0 */
5763 /*-----------------------------------------------------------------*/
5765 genrshOne (operand * result, operand * left, int shCount, int is_signed)
5768 int size = AOP_SIZE (result);
5771 wassert (size == 1);
5772 wassert (shCount < 8);
5774 l = aopGet (AOP (left), 0, FALSE);
5776 if (AOP (result)->type == AOP_REG)
5778 aopPut (AOP (result), l, 0);
5779 l = aopGet (AOP (result), 0, FALSE);
5782 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5790 emit2 ("%s a", is_signed ? "sra" : "srl");
5792 aopPut (AOP (result), "a", 0);
5796 /*-----------------------------------------------------------------*/
5797 /* AccRsh - right shift accumulator by known count */
5798 /*-----------------------------------------------------------------*/
5800 AccRsh (int shCount)
5802 static const unsigned char SRMask[] =
5804 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
5809 /* rotate right accumulator */
5810 AccRol (8 - shCount);
5811 /* and kill the higher order bits */
5812 emit2 ("and a,!immedbyte", SRMask[shCount]);
5816 /*-----------------------------------------------------------------*/
5817 /* shiftR1Left2Result - shift right one byte from left to result */
5818 /*-----------------------------------------------------------------*/
5820 shiftR1Left2Result (operand * left, int offl,
5821 operand * result, int offr,
5822 int shCount, int sign)
5824 _moveA (aopGet (AOP (left), offl, FALSE));
5829 emit2 ("%s a", sign ? "sra" : "srl");
5836 aopPut (AOP (result), "a", offr);
5839 /*-----------------------------------------------------------------*/
5840 /* genrshTwo - right shift two bytes by known amount != 0 */
5841 /*-----------------------------------------------------------------*/
5843 genrshTwo (operand * result, operand * left,
5844 int shCount, int sign)
5846 /* if shCount >= 8 */
5852 shiftR1Left2Result (left, MSB16, result, LSB,
5857 movLeft2Result (left, MSB16, result, LSB, sign);
5861 /* Sign extend the result */
5862 _moveA(aopGet (AOP (result), 0, FALSE));
5866 aopPut (AOP (result), ACC_NAME, MSB16);
5870 aopPut (AOP (result), "!zero", 1);
5873 /* 1 <= shCount <= 7 */
5876 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
5880 /*-----------------------------------------------------------------*/
5881 /* genRightShiftLiteral - left shifting by known count */
5882 /*-----------------------------------------------------------------*/
5884 genRightShiftLiteral (operand * left,
5890 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5893 freeAsmop (right, NULL, ic);
5895 aopOp (left, ic, FALSE, FALSE);
5896 aopOp (result, ic, FALSE, FALSE);
5898 size = getSize (operandType (result));
5900 /* I suppose that the left size >= result size */
5906 else if (shCount >= (size * 8)) {
5908 if (!SPEC_USIGN(getSpec(operandType(left)))) {
5909 _moveA(aopGet (AOP (left), 0, FALSE));
5917 aopPut (AOP (result), s, size);
5924 genrshOne (result, left, shCount, sign);
5927 genrshTwo (result, left, shCount, sign);
5930 wassertl (0, "Asked to shift right a long which should be a function call");
5933 wassertl (0, "Entered default case in right shift delegate");
5936 freeAsmop (left, NULL, ic);
5937 freeAsmop (result, NULL, ic);
5940 /*-----------------------------------------------------------------*/
5941 /* genRightShift - generate code for right shifting */
5942 /*-----------------------------------------------------------------*/
5944 genRightShift (iCode * ic)
5946 operand *right, *left, *result;
5948 int size, offset, first = 1;
5952 symbol *tlbl, *tlbl1;
5954 /* if signed then we do it the hard way preserve the
5955 sign bit moving it inwards */
5956 retype = getSpec (operandType (IC_RESULT (ic)));
5958 is_signed = !SPEC_USIGN (retype);
5960 /* signed & unsigned types are treated the same : i.e. the
5961 signed is NOT propagated inwards : quoting from the
5962 ANSI - standard : "for E1 >> E2, is equivalent to division
5963 by 2**E2 if unsigned or if it has a non-negative value,
5964 otherwise the result is implementation defined ", MY definition
5965 is that the sign does not get propagated */
5967 right = IC_RIGHT (ic);
5968 left = IC_LEFT (ic);
5969 result = IC_RESULT (ic);
5971 aopOp (right, ic, FALSE, FALSE);
5973 /* if the shift count is known then do it
5974 as efficiently as possible */
5975 if (AOP_TYPE (right) == AOP_LIT)
5977 genRightShiftLiteral (left, right, result, ic, is_signed);
5981 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5983 freeAsmop (right, NULL, ic);
5985 aopOp (left, ic, FALSE, FALSE);
5986 aopOp (result, ic, FALSE, FALSE);
5988 /* now move the left to the result if they are not the
5990 if (!sameRegs (AOP (left), AOP (result)))
5993 size = AOP_SIZE (result);
5997 l = aopGet (AOP (left), offset, FALSE);
5998 aopPut (AOP (result), l, offset);
6003 tlbl = newiTempLabel (NULL);
6004 tlbl1 = newiTempLabel (NULL);
6005 size = AOP_SIZE (result);
6008 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
6009 emitLabel (tlbl->key + 100);
6012 l = aopGet (AOP (result), offset--, FALSE);
6015 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
6023 emitLabel (tlbl1->key + 100);
6025 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
6027 freeAsmop (left, NULL, ic);
6028 freeAsmop (result, NULL, ic);
6032 /*-----------------------------------------------------------------*/
6033 /* genUnpackBits - generates code for unpacking bits */
6034 /*-----------------------------------------------------------------*/
6036 genUnpackBits (operand * result, int pair)
6038 int offset = 0; /* result byte offset */
6039 int rsize; /* result size */
6040 int rlen = 0; /* remaining bitfield length */
6041 sym_link *etype; /* bitfield type information */
6042 int blen; /* bitfield length */
6043 int bstr; /* bitfield starting bit within byte */
6045 emitDebug ("; genUnpackBits");
6047 etype = getSpec (operandType (result));
6048 rsize = getSize (operandType (result));
6049 blen = SPEC_BLEN (etype);
6050 bstr = SPEC_BSTR (etype);
6052 /* If the bitfield length is less than a byte */
6055 emit2 ("ld a,!*pair", _pairs[pair].name);
6057 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
6058 aopPut (AOP (result), "a", offset++);
6062 /* TODO: what if pair == PAIR_DE ? */
6063 if (getPairId (AOP (result)) == PAIR_HL)
6065 wassertl (rsize == 2, "HL must be of size 2");
6066 emit2 ("ld a,!*hl");
6068 emit2 ("ld h,!*hl");
6071 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
6073 spillPair (PAIR_HL);
6077 /* Bit field did not fit in a byte. Copy all
6078 but the partial byte at the end. */
6079 for (rlen=blen;rlen>=8;rlen-=8)
6081 emit2 ("ld a,!*pair", _pairs[pair].name);
6082 aopPut (AOP (result), "a", offset++);
6085 emit2 ("inc %s", _pairs[pair].name);
6086 _G.pairs[pair].offset++;
6090 /* Handle the partial byte at the end */
6093 emit2 ("ld a,!*pair", _pairs[pair].name);
6094 emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
6095 aopPut (AOP (result), "a", offset++);
6103 aopPut (AOP (result), "!zero", offset++);
6107 /*-----------------------------------------------------------------*/
6108 /* genGenPointerGet - get value from generic pointer space */
6109 /*-----------------------------------------------------------------*/
6111 genGenPointerGet (operand * left,
6112 operand * result, iCode * ic)
6115 sym_link *retype = getSpec (operandType (result));
6121 aopOp (left, ic, FALSE, FALSE);
6122 aopOp (result, ic, FALSE, FALSE);
6124 size = AOP_SIZE (result);
6126 if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype))
6129 if (isPtrPair (AOP (left)))
6131 tsprintf (buffer, sizeof(buffer),
6132 "!*pair", getPairName (AOP (left)));
6133 aopPut (AOP (result), buffer, 0);
6137 emit2 ("ld a,!*pair", getPairName (AOP (left)));
6138 aopPut (AOP (result), "a", 0);
6140 freeAsmop (left, NULL, ic);
6144 if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
6151 tsprintf (at, sizeof(at), "!*iyx", offset);
6152 aopPut (AOP (result), at, offset);
6156 freeAsmop (left, NULL, ic);
6160 /* For now we always load into IY */
6161 /* if this is remateriazable */
6162 fetchPair (pair, AOP (left));
6164 /* if bit then unpack */
6165 if (IS_BITVAR (retype))
6167 genUnpackBits (result, pair);
6168 freeAsmop (left, NULL, ic);
6172 else if (getPairId (AOP (result)) == PAIR_HL)
6174 wassertl (size == 2, "HL must be of size 2");
6175 emit2 ("ld a,!*hl");
6177 emit2 ("ld h,!*hl");
6179 spillPair (PAIR_HL);
6181 else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
6183 size = AOP_SIZE (result);
6188 /* PENDING: make this better */
6189 if (!IS_GB && AOP_TYPE (result) == AOP_REG)
6191 aopPut (AOP (result), "!*hl", offset++);
6195 emit2 ("ld a,!*pair", _pairs[pair].name);
6196 aopPut (AOP (result), "a", offset++);
6200 emit2 ("inc %s", _pairs[pair].name);
6201 _G.pairs[pair].offset++;
6204 /* Fixup HL back down */
6205 for (size = AOP_SIZE (result)-1; size; size--)
6207 emit2 ("dec %s", _pairs[pair].name);
6212 size = AOP_SIZE (result);
6217 /* PENDING: make this better */
6219 (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
6221 aopPut (AOP (result), "!*hl", offset++);
6225 emit2 ("ld a,!*pair", _pairs[pair].name);
6226 aopPut (AOP (result), "a", offset++);
6230 emit2 ("inc %s", _pairs[pair].name);
6231 _G.pairs[pair].offset++;
6236 freeAsmop (left, NULL, ic);
6239 freeAsmop (result, NULL, ic);
6242 /*-----------------------------------------------------------------*/
6243 /* genPointerGet - generate code for pointer get */
6244 /*-----------------------------------------------------------------*/
6246 genPointerGet (iCode * ic)
6248 operand *left, *result;
6249 sym_link *type, *etype;
6251 left = IC_LEFT (ic);
6252 result = IC_RESULT (ic);
6254 /* depending on the type of pointer we need to
6255 move it to the correct pointer register */
6256 type = operandType (left);
6257 etype = getSpec (type);
6259 genGenPointerGet (left, result, ic);
6263 isRegOrLit (asmop * aop)
6265 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
6271 /*-----------------------------------------------------------------*/
6272 /* genPackBits - generates code for packed bit storage */
6273 /*-----------------------------------------------------------------*/
6275 genPackBits (sym_link * etype,
6280 int offset = 0; /* source byte offset */
6281 int rlen = 0; /* remaining bitfield length */
6282 int blen; /* bitfield length */
6283 int bstr; /* bitfield starting bit within byte */
6284 int litval; /* source literal value (if AOP_LIT) */
6285 unsigned char mask; /* bitmask within current byte */
6286 int extraPair; /* a tempory register */
6287 bool needPopExtra=0; /* need to restore original value of temp reg */
6289 emitDebug ("; genPackBits","");
6291 blen = SPEC_BLEN (etype);
6292 bstr = SPEC_BSTR (etype);
6294 /* If the bitfield length is less than a byte */
6297 mask = ((unsigned char) (0xFF << (blen + bstr)) |
6298 (unsigned char) (0xFF >> (8 - bstr)));
6300 if (AOP_TYPE (right) == AOP_LIT)
6302 /* Case with a bitfield length <8 and literal source
6304 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6306 litval &= (~mask) & 0xff;
6307 emit2 ("ld a,!*pair", _pairs[pair].name);
6308 if ((mask|litval)!=0xff)
6309 emit2 ("and a,!immedbyte", mask);
6311 emit2 ("or a,!immedbyte", litval);
6312 emit2 ("ld !*pair,a", _pairs[pair].name);
6317 /* Case with a bitfield length <8 and arbitrary source
6319 _moveA (aopGet (AOP (right), 0, FALSE));
6320 /* shift and mask source value */
6322 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6324 extraPair = getFreePairId(ic);
6325 if (extraPair == PAIR_INVALID)
6327 extraPair = PAIR_BC;
6328 if (getPairId (AOP (right)) != PAIR_BC
6329 || !isLastUse (ic, right))
6335 emit2 ("ld %s,a", _pairs[extraPair].l);
6336 emit2 ("ld a,!*pair", _pairs[pair].name);
6338 emit2 ("and a,!immedbyte", mask);
6339 emit2 ("or a,%s", _pairs[extraPair].l);
6340 emit2 ("ld !*pair,a", _pairs[pair].name);
6347 /* Bit length is greater than 7 bits. In this case, copy */
6348 /* all except the partial byte at the end */
6349 for (rlen=blen;rlen>=8;rlen-=8)
6351 emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
6352 emit2 ("ld !*pair,a", _pairs[pair].name);
6355 emit2 ("inc %s", _pairs[pair].name);
6356 _G.pairs[pair].offset++;
6360 /* If there was a partial byte at the end */
6363 mask = (((unsigned char) -1 << rlen) & 0xff);
6365 if (AOP_TYPE (right) == AOP_LIT)
6367 /* Case with partial byte and literal source
6369 litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
6370 litval >>= (blen-rlen);
6371 litval &= (~mask) & 0xff;
6372 emit2 ("ld a,!*pair", _pairs[pair].name);
6373 if ((mask|litval)!=0xff)
6374 emit2 ("and a,!immedbyte", mask);
6376 emit2 ("or a,!immedbyte", litval);
6380 /* Case with partial byte and arbitrary source
6382 _moveA (aopGet (AOP (right), offset++, FALSE));
6383 emit2 ("and a,!immedbyte", (~mask) & 0xff);
6385 extraPair = getFreePairId(ic);
6386 if (extraPair == PAIR_INVALID)
6388 extraPair = getPairId (AOP (right));
6389 if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
6390 extraPair = PAIR_BC;
6392 if (getPairId (AOP (right)) != PAIR_BC
6393 || !isLastUse (ic, right))
6399 emit2 ("ld %s,a", _pairs[extraPair].l);
6400 emit2 ("ld a,!*pair", _pairs[pair].name);
6402 emit2 ("and a,!immedbyte", mask);
6403 emit2 ("or a,%s", _pairs[extraPair].l);
6408 emit2 ("ld !*pair,a", _pairs[pair].name);
6413 /*-----------------------------------------------------------------*/
6414 /* genGenPointerSet - stores the value into a pointer location */
6415 /*-----------------------------------------------------------------*/
6417 genGenPointerSet (operand * right,
6418 operand * result, iCode * ic)
6421 sym_link *retype = getSpec (operandType (right));
6422 sym_link *letype = getSpec (operandType (result));
6423 PAIR_ID pairId = PAIR_HL;
6426 aopOp (result, ic, FALSE, FALSE);
6427 aopOp (right, ic, FALSE, FALSE);
6432 size = AOP_SIZE (right);
6434 isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
6435 emitDebug("; isBitvar = %d", isBitvar);
6437 /* Handle the exceptions first */
6438 if (isPair (AOP (result)) && size == 1 && !isBitvar)
6441 const char *l = aopGet (AOP (right), 0, FALSE);
6442 const char *pair = getPairName (AOP (result));
6443 if (canAssignToPtr (l) && isPtr (pair))
6445 emit2 ("ld !*pair,%s", pair, l);
6450 emit2 ("ld !*pair,a", pair);
6455 if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
6458 const char *l = aopGet (AOP (right), 0, FALSE);
6463 if (canAssignToPtr (l))
6465 emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
6469 _moveA (aopGet (AOP (right), offset, FALSE));
6470 emit2 ("ld !*iyx,a", offset);
6476 else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result)
6483 const char *l = aopGet (AOP (right), offset, FALSE);
6484 if (isRegOrLit (AOP (right)) && !IS_GB)
6486 emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
6491 emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
6495 emit2 ("inc %s", _pairs[PAIR_HL].name);
6496 _G.pairs[PAIR_HL].offset++;
6501 /* Fixup HL back down */
6502 for (size = AOP_SIZE (right)-1; size; size--)
6504 emit2 ("dec %s", _pairs[PAIR_HL].name);
6509 /* if the operand is already in dptr
6510 then we do nothing else we move the value to dptr */
6511 if (AOP_TYPE (result) != AOP_STR)
6513 fetchPair (pairId, AOP (result));
6515 /* so hl know contains the address */
6516 freeAsmop (result, NULL, ic);
6518 /* if bit then unpack */
6521 genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
6531 const char *l = aopGet (AOP (right), offset, FALSE);
6532 if (isRegOrLit (AOP (right)) && !IS_GB)
6534 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
6539 emit2 ("ld !*pair,a", _pairs[pairId].name);
6543 emit2 ("inc %s", _pairs[pairId].name);
6544 _G.pairs[pairId].offset++;
6550 freeAsmop (right, NULL, ic);
6553 /*-----------------------------------------------------------------*/
6554 /* genPointerSet - stores the value into a pointer location */
6555 /*-----------------------------------------------------------------*/
6557 genPointerSet (iCode * ic)
6559 operand *right, *result;
6560 sym_link *type, *etype;
6562 right = IC_RIGHT (ic);
6563 result = IC_RESULT (ic);
6565 /* depending on the type of pointer we need to
6566 move it to the correct pointer register */
6567 type = operandType (result);
6568 etype = getSpec (type);
6570 genGenPointerSet (right, result, ic);
6573 /*-----------------------------------------------------------------*/
6574 /* genIfx - generate code for Ifx statement */
6575 /*-----------------------------------------------------------------*/
6577 genIfx (iCode * ic, iCode * popIc)
6579 operand *cond = IC_COND (ic);
6582 aopOp (cond, ic, FALSE, TRUE);
6584 /* get the value into acc */
6585 if (AOP_TYPE (cond) != AOP_CRY)
6589 /* the result is now in the accumulator */
6590 freeAsmop (cond, NULL, ic);
6592 /* if there was something to be popped then do it */
6596 /* if the condition is a bit variable */
6597 if (isbit && IS_ITEMP (cond) &&
6599 genIfxJump (ic, SPIL_LOC (cond)->rname);
6600 else if (isbit && !IS_ITEMP (cond))
6601 genIfxJump (ic, OP_SYMBOL (cond)->rname);
6603 genIfxJump (ic, "a");
6608 /*-----------------------------------------------------------------*/
6609 /* genAddrOf - generates code for address of */
6610 /*-----------------------------------------------------------------*/
6612 genAddrOf (iCode * ic)
6614 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
6616 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6618 /* if the operand is on the stack then we
6619 need to get the stack offset of this
6626 if (sym->stack <= 0)
6628 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
6632 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6634 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6638 emit2 ("ld de,!hashedstr", sym->rname);
6639 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
6647 /* if it has an offset then we need to compute it */
6649 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6651 emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
6652 emit2 ("add hl,sp");
6656 emit2 ("ld hl,!hashedstr", sym->rname);
6658 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6660 freeAsmop (IC_RESULT (ic), NULL, ic);
6663 /*-----------------------------------------------------------------*/
6664 /* genAssign - generate code for assignment */
6665 /*-----------------------------------------------------------------*/
6667 genAssign (iCode * ic)
6669 operand *result, *right;
6671 unsigned long lit = 0L;
6673 result = IC_RESULT (ic);
6674 right = IC_RIGHT (ic);
6676 /* Dont bother assigning if they are the same */
6677 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6679 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
6683 aopOp (right, ic, FALSE, FALSE);
6684 aopOp (result, ic, TRUE, FALSE);
6686 /* if they are the same registers */
6687 if (sameRegs (AOP (right), AOP (result)))
6689 emitDebug ("; (registers are the same)");
6693 /* if the result is a bit */
6694 if (AOP_TYPE (result) == AOP_CRY)
6696 wassertl (0, "Tried to assign to a bit");
6700 size = AOP_SIZE (result);
6703 if (AOP_TYPE (right) == AOP_LIT)
6705 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6708 if (isPair (AOP (result)))
6710 fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
6712 else if ((size > 1) &&
6713 (AOP_TYPE (result) != AOP_REG) &&
6714 (AOP_TYPE (right) == AOP_LIT) &&
6715 !IS_FLOAT (operandType (right)) &&
6718 bool fXored = FALSE;
6720 /* Work from the top down.
6721 Done this way so that we can use the cached copy of 0
6722 in A for a fast clear */
6725 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
6727 if (!fXored && size > 1)
6734 aopPut (AOP (result), "a", offset);
6738 aopPut (AOP (result), "!zero", offset);
6742 aopPut (AOP (result),
6743 aopGet (AOP (right), offset, FALSE),
6748 else if (size == 2 && AOP_TYPE (right) == AOP_IY)
6750 emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
6751 aopPut (AOP (result), "l", LSB);
6752 aopPut (AOP (result), "h", MSB16);
6754 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6756 /* Special case. Load into a and d, then load out. */
6757 _moveA (aopGet (AOP (right), 0, FALSE));
6758 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
6759 aopPut (AOP (result), "a", 0);
6760 aopPut (AOP (result), "e", 1);
6762 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6764 /* Special case - simple memcpy */
6765 aopGet (AOP (right), LSB, FALSE);
6768 aopGet (AOP (result), LSB, FALSE);
6772 emit2 ("ld a,(de)");
6773 /* Peephole will optimise this. */
6774 emit2 ("ld (hl),a");
6782 spillPair (PAIR_HL);
6788 /* PENDING: do this check better */
6789 if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
6791 _moveA (aopGet (AOP (right), offset, FALSE));
6792 aopPut (AOP (result), "a", offset);
6795 aopPut (AOP (result),
6796 aopGet (AOP (right), offset, FALSE),
6803 freeAsmop (right, NULL, ic);
6804 freeAsmop (result, NULL, ic);
6807 /*-----------------------------------------------------------------*/
6808 /* genJumpTab - genrates code for jump table */
6809 /*-----------------------------------------------------------------*/
6811 genJumpTab (iCode * ic)
6816 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
6817 /* get the condition into accumulator */
6818 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
6821 emit2 ("ld e,%s", l);
6822 emit2 ("ld d,!zero");
6823 jtab = newiTempLabel (NULL);
6825 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
6826 emit2 ("add hl,de");
6827 emit2 ("add hl,de");
6828 emit2 ("add hl,de");
6829 freeAsmop (IC_JTCOND (ic), NULL, ic);
6833 emitLabel (jtab->key + 100);
6834 /* now generate the jump labels */
6835 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
6836 jtab = setNextItem (IC_JTLABELS (ic)))
6837 emit2 ("jp !tlabel", jtab->key + 100);
6840 /*-----------------------------------------------------------------*/
6841 /* genCast - gen code for casting */
6842 /*-----------------------------------------------------------------*/
6844 genCast (iCode * ic)
6846 operand *result = IC_RESULT (ic);
6847 sym_link *rtype = operandType (IC_RIGHT (ic));
6848 operand *right = IC_RIGHT (ic);
6851 /* if they are equivalent then do nothing */
6852 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6855 aopOp (right, ic, FALSE, FALSE);
6856 aopOp (result, ic, FALSE, FALSE);
6858 /* if the result is a bit */
6859 if (AOP_TYPE (result) == AOP_CRY)
6861 wassertl (0, "Tried to cast to a bit");
6864 /* if they are the same size : or less */
6865 if (AOP_SIZE (result) <= AOP_SIZE (right))
6868 /* if they are in the same place */
6869 if (sameRegs (AOP (right), AOP (result)))
6872 /* if they in different places then copy */
6873 size = AOP_SIZE (result);
6877 aopPut (AOP (result),
6878 aopGet (AOP (right), offset, FALSE),
6885 /* So we now know that the size of destination is greater
6886 than the size of the source */
6887 /* we move to result for the size of source */
6888 size = AOP_SIZE (right);
6892 aopPut (AOP (result),
6893 aopGet (AOP (right), offset, FALSE),
6898 /* now depending on the sign of the destination */
6899 size = AOP_SIZE (result) - AOP_SIZE (right);
6900 /* Unsigned or not an integral type - right fill with zeros */
6901 if (SPEC_USIGN (rtype) || !IS_SPEC (rtype) || AOP_TYPE(right)==AOP_CRY)
6904 aopPut (AOP (result), "!zero", offset++);
6908 /* we need to extend the sign :{ */
6909 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
6915 aopPut (AOP (result), "a", offset++);
6919 freeAsmop (right, NULL, ic);
6920 freeAsmop (result, NULL, ic);
6923 /*-----------------------------------------------------------------*/
6924 /* genReceive - generate code for a receive iCode */
6925 /*-----------------------------------------------------------------*/
6927 genReceive (iCode * ic)
6929 if (isOperandInFarSpace (IC_RESULT (ic)) &&
6930 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
6931 IS_TRUE_SYMOP (IC_RESULT (ic))))
6941 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6942 size = AOP_SIZE(IC_RESULT(ic));
6944 for (i = 0; i < size; i++) {
6945 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
6949 freeAsmop (IC_RESULT (ic), NULL, ic);
6952 /*-----------------------------------------------------------------*/
6953 /* genDummyRead - generate code for dummy read of volatiles */
6954 /*-----------------------------------------------------------------*/
6956 genDummyRead (iCode * ic)
6958 emit2 ("; genDummyRead not implemented");
6965 /** Maximum number of bytes to emit per line. */
6969 /** Context for the byte output chunker. */
6972 unsigned char buffer[DBEMIT_MAX_RUN];
6977 /** Flushes a byte chunker by writing out all in the buffer and
6981 _dbFlush(DBEMITCTX *self)
6988 sprintf(line, ".db 0x%02X", self->buffer[0]);
6990 for (i = 1; i < self->pos; i++)
6992 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
6999 /** Write out another byte, buffering until a decent line is
7003 _dbEmit(DBEMITCTX *self, int c)
7005 if (self->pos == DBEMIT_MAX_RUN)
7009 self->buffer[self->pos++] = c;
7012 /** Context for a simple run length encoder. */
7016 unsigned char buffer[128];
7018 /** runLen may be equivalent to pos. */
7024 RLE_CHANGE_COST = 4,
7028 /** Flush the buffer of a run length encoder by writing out the run or
7029 data that it currently contains.
7032 _rleCommit(RLECTX *self)
7038 memset(&db, 0, sizeof(db));
7040 emit2(".db %u", self->pos);
7042 for (i = 0; i < self->pos; i++)
7044 _dbEmit(&db, self->buffer[i]);
7053 Can get either a run or a block of random stuff.
7054 Only want to change state if a good run comes in or a run ends.
7055 Detecting run end is easy.
7058 Say initial state is in run, len zero, last zero. Then if you get a
7059 few zeros then something else then a short run will be output.
7060 Seems OK. While in run mode, keep counting. While in random mode,
7061 keep a count of the run. If run hits margin, output all up to run,
7062 restart, enter run mode.
7065 /** Add another byte into the run length encoder, flushing as
7066 required. The run length encoder uses the Amiga IFF style, where
7067 a block is prefixed by its run length. A positive length means
7068 the next n bytes pass straight through. A negative length means
7069 that the next byte is repeated -n times. A zero terminates the
7073 _rleAppend(RLECTX *self, int c)
7077 if (c != self->last)
7079 /* The run has stopped. See if it is worthwhile writing it out
7080 as a run. Note that the random data comes in as runs of
7083 if (self->runLen > RLE_CHANGE_COST)
7085 /* Yes, worthwhile. */
7086 /* Commit whatever was in the buffer. */
7088 emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
7092 /* Not worthwhile. Append to the end of the random list. */
7093 for (i = 0; i < self->runLen; i++)
7095 if (self->pos >= RLE_MAX_BLOCK)
7100 self->buffer[self->pos++] = self->last;
7108 if (self->runLen >= RLE_MAX_BLOCK)
7110 /* Commit whatever was in the buffer. */
7113 emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
7121 _rleFlush(RLECTX *self)
7123 _rleAppend(self, -1);
7130 /** genArrayInit - Special code for initialising an array with constant
7134 genArrayInit (iCode * ic)
7138 int elementSize = 0, eIndex, i;
7139 unsigned val, lastVal;
7143 memset(&rle, 0, sizeof(rle));
7145 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
7147 _saveRegsForCall(ic, 0);
7149 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
7150 emit2 ("call __initrleblock");
7152 type = operandType(IC_LEFT(ic));
7154 if (type && type->next)
7156 elementSize = getSize(type->next);
7160 wassertl (0, "Can't determine element size in genArrayInit.");
7163 iLoop = IC_ARRAYILIST(ic);
7164 lastVal = (unsigned)-1;
7166 /* Feed all the bytes into the run length encoder which will handle
7168 This works well for mixed char data, and for random int and long
7177 for (i = 0; i < ix; i++)
7179 for (eIndex = 0; eIndex < elementSize; eIndex++)
7181 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
7182 _rleAppend(&rle, val);
7187 iLoop = iLoop->next;
7191 /* Mark the end of the run. */
7194 _restoreRegsAfterCall();
7198 freeAsmop (IC_LEFT(ic), NULL, ic);
7202 _swap (PAIR_ID one, PAIR_ID two)
7204 if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
7210 emit2 ("ld a,%s", _pairs[one].l);
7211 emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
7212 emit2 ("ld %s,a", _pairs[two].l);
7213 emit2 ("ld a,%s", _pairs[one].h);
7214 emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
7215 emit2 ("ld %s,a", _pairs[two].h);
7219 /* The problem is that we may have all three pairs used and they may
7220 be needed in a different order.
7225 hl = hl => unity, fine
7229 hl = hl hl = hl, swap de <=> bc
7237 hl = bc de = de, swap bc <=> hl
7245 hl = de bc = bc, swap hl <=> de
7250 * Any pair = pair are done last
7251 * Any pair = iTemp are done last
7252 * Any swaps can be done any time
7260 So how do we detect the cases?
7261 How about a 3x3 matrix?
7265 x x x x (Fourth for iTemp/other)
7267 First determin which mode to use by counting the number of unity and
7270 Two - Assign the pair first, then the rest
7271 One - Swap the two, then the rest
7275 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
7277 PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
7279 PAIR_BC, PAIR_HL, PAIR_DE
7281 int i, j, nunity = 0;
7282 memset (ids, PAIR_INVALID, sizeof (ids));
7285 wassert (nparams == 3);
7287 /* First save everything that needs to be saved. */
7288 _saveRegsForCall (ic, 0);
7290 /* Loading HL first means that DE is always fine. */
7291 for (i = 0; i < nparams; i++)
7293 aopOp (pparams[i], ic, FALSE, FALSE);
7294 ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
7297 /* Count the number of unity or iTemp assigns. */
7298 for (i = 0; i < 3; i++)
7300 if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
7308 /* Any order, fall through. */
7310 else if (nunity == 2)
7312 /* One is assigned. Pull it out and assign. */
7313 for (i = 0; i < 3; i++)
7315 for (j = 0; j < NUM_PAIRS; j++)
7317 if (ids[dest[i]][j] == TRUE)
7319 /* Found it. See if it's the right one. */
7320 if (j == PAIR_INVALID || j == dest[i])
7326 fetchPair(dest[i], AOP (pparams[i]));
7333 else if (nunity == 1)
7335 /* Find the pairs to swap. */
7336 for (i = 0; i < 3; i++)
7338 for (j = 0; j < NUM_PAIRS; j++)
7340 if (ids[dest[i]][j] == TRUE)
7342 if (j == PAIR_INVALID || j == dest[i])
7357 int next = getPairId (AOP (pparams[0]));
7358 emit2 ("push %s", _pairs[next].name);
7360 if (next == dest[1])
7362 fetchPair (dest[1], AOP (pparams[1]));
7363 fetchPair (dest[2], AOP (pparams[2]));
7367 fetchPair (dest[2], AOP (pparams[2]));
7368 fetchPair (dest[1], AOP (pparams[1]));
7370 emit2 ("pop %s", _pairs[dest[0]].name);
7373 /* Finally pull out all of the iTemps */
7374 for (i = 0; i < 3; i++)
7376 if (ids[dest[i]][PAIR_INVALID] == 1)
7378 fetchPair (dest[i], AOP (pparams[i]));
7384 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
7390 wassertl (nParams == 2, "Built-in strcpy must have two parameters");
7394 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7396 setupForBuiltin3 (ic, nParams, pparams);
7398 label = newiTempLabel(NULL);
7400 emitLabel (label->key);
7401 emit2 ("ld a,(hl)");
7404 emit2 ("!shortjp nz,!tlabel ; 1", label->key);
7406 freeAsmop (from, NULL, ic->next);
7407 freeAsmop (to, NULL, ic);
7411 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
7413 operand *from, *to, *count;
7416 wassertl (nParams == 3, "Built-in memcpy must have two parameters");
7421 deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
7423 setupForBuiltin3 (ic, nParams, pparams);
7427 freeAsmop (count, NULL, ic->next->next);
7428 freeAsmop (from, NULL, ic);
7430 _restoreRegsAfterCall();
7432 /* if we need assign a result value */
7433 if ((IS_ITEMP (IC_RESULT (ic)) &&
7434 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
7435 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
7436 IS_TRUE_SYMOP (IC_RESULT (ic)))
7438 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
7439 movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
7440 freeAsmop (IC_RESULT (ic), NULL, ic);
7443 freeAsmop (to, NULL, ic->next);
7446 /*-----------------------------------------------------------------*/
7447 /* genBuiltIn - calls the appropriate function to generating code */
7448 /* for a built in function */
7449 /*-----------------------------------------------------------------*/
7450 static void genBuiltIn (iCode *ic)
7452 operand *bi_parms[MAX_BUILTIN_ARGS];
7457 /* get all the arguments for a built in function */
7458 bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
7460 /* which function is it */
7461 bif = OP_SYMBOL(IC_LEFT(bi_iCode));
7463 if (strcmp(bif->name,"__builtin_strcpy")==0)
7465 genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
7467 else if (strcmp(bif->name,"__builtin_memcpy")==0)
7469 genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
7473 wassertl (0, "Unknown builtin function encountered");
7477 /*-----------------------------------------------------------------*/
7478 /* genZ80Code - generate code for Z80 based controllers */
7479 /*-----------------------------------------------------------------*/
7481 genZ80Code (iCode * lic)
7489 _fReturn = _gbz80_return;
7490 _fTmp = _gbz80_return;
7494 _fReturn = _z80_return;
7495 _fTmp = _z80_return;
7498 _G.lines.head = _G.lines.current = NULL;
7500 for (ic = lic; ic; ic = ic->next)
7503 if (cln != ic->lineno)
7505 if (!options.noCcodeInAsm) {
7506 emit2 (";%s:%d: %s", ic->filename, ic->lineno,
7507 printCLine(ic->filename, ic->lineno));
7511 if (options.iCodeInAsm) {
7512 emit2 (";ic:%d: %s", ic->key, printILine(ic));
7514 /* if the result is marked as
7515 spilt and rematerializable or code for
7516 this has already been generated then
7518 if (resultRemat (ic) || ic->generated)
7521 /* depending on the operation */
7525 emitDebug ("; genNot");
7530 emitDebug ("; genCpl");
7535 emitDebug ("; genUminus");
7540 emitDebug ("; genIpush");
7545 /* IPOP happens only when trying to restore a
7546 spilt live range, if there is an ifx statement
7547 following this pop then the if statement might
7548 be using some of the registers being popped which
7549 would destory the contents of the register so
7550 we need to check for this condition and handle it */
7552 ic->next->op == IFX &&
7553 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
7555 emitDebug ("; genIfx");
7556 genIfx (ic->next, ic);
7560 emitDebug ("; genIpop");
7566 emitDebug ("; genCall");
7571 emitDebug ("; genPcall");
7576 emitDebug ("; genFunction");
7581 emitDebug ("; genEndFunction");
7582 genEndFunction (ic);
7586 emitDebug ("; genRet");
7591 emitDebug ("; genLabel");
7596 emitDebug ("; genGoto");
7601 emitDebug ("; genPlus");
7606 emitDebug ("; genMinus");
7611 emitDebug ("; genMult");
7616 emitDebug ("; genDiv");
7621 emitDebug ("; genMod");
7626 emitDebug ("; genCmpGt");
7627 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
7631 emitDebug ("; genCmpLt");
7632 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
7639 /* note these two are xlated by algebraic equivalence
7640 during parsing SDCC.y */
7641 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
7642 "got '>=' or '<=' shouldn't have come here");
7646 emitDebug ("; genCmpEq");
7647 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
7651 emitDebug ("; genAndOp");
7656 emitDebug ("; genOrOp");
7661 emitDebug ("; genXor");
7662 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
7666 emitDebug ("; genOr");
7667 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
7671 emitDebug ("; genAnd");
7672 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
7676 emitDebug ("; genInline");
7681 emitDebug ("; genRRC");
7686 emitDebug ("; genRLC");
7691 emitDebug ("; genGetHBIT");
7696 emitDebug ("; genLeftShift");
7701 emitDebug ("; genRightShift");
7705 case GET_VALUE_AT_ADDRESS:
7706 emitDebug ("; genPointerGet");
7712 if (POINTER_SET (ic))
7714 emitDebug ("; genAssign (pointer)");
7719 emitDebug ("; genAssign");
7725 emitDebug ("; genIfx");
7730 emitDebug ("; genAddrOf");
7735 emitDebug ("; genJumpTab");
7740 emitDebug ("; genCast");
7745 emitDebug ("; genReceive");
7750 if (ic->builtinSEND)
7752 emitDebug ("; genBuiltIn");
7757 emitDebug ("; addSet");
7758 addSet (&_G.sendSet, ic);
7763 emitDebug ("; genArrayInit");
7767 case DUMMY_READ_VOLATILE:
7777 /* now we are ready to call the
7778 peep hole optimizer */
7779 if (!options.nopeep)
7780 peepHole (&_G.lines.head);
7782 /* This is unfortunate */
7783 /* now do the actual printing */
7785 FILE *fp = codeOutFile;
7786 if (isInHome () && codeOutFile == code->oFile)
7787 codeOutFile = home->oFile;
7788 printLine (_G.lines.head, codeOutFile);
7789 if (_G.flushStatics)
7792 _G.flushStatics = 0;
7797 freeTrace(&_G.lines.trace);
7798 freeTrace(&_G.trace.aops);
7804 _isPairUsed (iCode * ic, PAIR_ID pairId)
7810 if (bitVectBitValue (ic->rMask, D_IDX))
7812 if (bitVectBitValue (ic->rMask, E_IDX))
7822 fetchLitSpecial (asmop * aop, bool negate, bool xor)
7825 value *val = aop->aopu.aop_lit;
7827 wassert (aop->type == AOP_LIT);
7828 wassert (!IS_FLOAT (val->type));
7830 v = (unsigned long) floatFromVal (val);
7838 tsprintf (buffer, sizeof(buffer), "!immedword", v);
7839 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));