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 Apparent advantage of turning on regparams:
66 Decent case is push of a constant
67 - ld hl,#n; push hl: (10+11)*nargs
68 2. Cost of pull from stack
69 Using asm with ld hl, etc
70 - ld hl,#2; add hl,sp; (ld bc,(hl); hl+=2)*nargs
72 3. Cost of fixing stack
76 So cost is (10+11+7+6+7+10)*nargs+10+11
78 = 123 for mul, div, strcmp, strcpy
79 Saving of (98298+32766+32766+32766)*123 = 24181308
80 At 192 d/s for 682411768t, speed up to 199. Hmm.
88 #ifdef HAVE_SYS_ISA_DEFS_H
89 #include <sys/isa_defs.h>
93 #include "SDCCglobl.h"
94 #include "SDCCpeeph.h"
99 /* This is the down and dirty file with all kinds of kludgy & hacky
100 stuff. This is what it is all about CODE GENERATION for a specific MCU.
101 Some of the routines may be reusable, will have to see */
103 /* Z80 calling convention description.
104 Parameters are passed right to left. As the stack grows downwards,
105 the parameters are arranged in left to right in memory.
106 Parameters may be passed in the HL and DE registers with one
108 PENDING: What if the parameter is a long?
109 Everything is caller saves. i.e. the caller must save any registers
110 that it wants to preserve over the call.
111 GB: The return value is returned in DEHL. DE is normally used as a
112 working register pair. Caller saves allows it to be used for a
114 va args functions do not use register parameters. All arguments
115 are passed on the stack.
116 IX is used as an index register to the top of the local variable
117 area. ix-0 is the top most local variable.
122 /* Set to enable debugging trace statements in the output assembly code. */
126 static char *_z80_return[] =
127 {"l", "h", "e", "d"};
128 static char *_gbz80_return[] =
129 {"e", "d", "l", "h"};
130 static char *_fReceive[] =
131 { "c", "b", "e", "d" };
133 static char **_fReturn;
136 extern FILE *codeOutFile;
144 /** Enum covering all the possible register pairs.
163 } _pairs[NUM_PAIRS] = {
164 { "??1", "?2", "?3" },
169 { "iy", "iy.l?", "iy.h?" },
170 { "ix", "ix.l?", "ix.h?" }
174 #define ACC_NAME _pairs[PAIR_AF].h
184 /** Code generator persistent data.
188 /** Used to optimised setting up of a pair by remebering what it
189 contains and adjusting instead of reloading where possible.
210 const char *lastFunctionName;
216 /** TRUE if the registers have already been saved. */
234 static const char *aopGet (asmop * aop, int offset, bool bit16);
250 _getTempPairName(void)
252 return _pairs[_getTempPairId()].name;
258 /* Clean up the line so that it is 'prettier' */
259 if (strchr (buf, ':'))
261 /* Is a label - cant do anything */
264 /* Change the first (and probably only) ' ' to a tab so
279 _newLineNode (char *line)
283 pl = traceAlloc(&_G.lines.trace, Safe_alloc ( sizeof (lineNode)));
284 pl->line = traceAlloc(&_G.lines.trace, Safe_strdup (line));
290 _vemit2 (const char *szFormat, va_list ap)
294 tvsprintf (buffer, szFormat, ap);
297 _G.lines.current = (_G.lines.current ?
298 connectLine (_G.lines.current, _newLineNode (buffer)) :
299 (_G.lines.head = _newLineNode (buffer)));
301 _G.lines.current->isInline = _G.lines.isInline;
305 emit2 (const char *szFormat,...)
309 va_start (ap, szFormat);
311 _vemit2 (szFormat, ap);
317 emitDebug (const char *szFormat,...)
323 va_start (ap, szFormat);
325 _vemit2 (szFormat, ap);
331 /*-----------------------------------------------------------------*/
332 /* emit2 - writes the code into a file : for now it is simple */
333 /*-----------------------------------------------------------------*/
335 _emit2 (const char *inst, const char *fmt,...)
338 char lb[INITIAL_INLINEASM];
345 sprintf (lb, "%s\t", inst);
346 vsprintf (lb + (strlen (lb)), fmt, ap);
349 vsprintf (lb, fmt, ap);
351 while (isspace (*lbp))
356 _G.lines.current = (_G.lines.current ?
357 connectLine (_G.lines.current, _newLineNode (lb)) :
358 (_G.lines.head = _newLineNode (lb)));
360 _G.lines.current->isInline = _G.lines.isInline;
365 _emitMove(const char *to, const char *from)
367 if (strcasecmp(to, from) != 0)
369 emit2("ld %s,%s", to, from);
374 // Could leave this to the peephole, but sometimes the peephole is inhibited.
379 _moveA(const char *moveFrom)
381 // Let the peephole optimiser take care of redundent loads
382 _emitMove(ACC_NAME, moveFrom);
392 getPairName (asmop * aop)
394 if (aop->type == AOP_REG)
396 switch (aop->aopu.aop_reg[0]->rIdx)
409 else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
411 switch (*aop->aopu.aop_str[0])
424 wassertl (0, "Tried to get the pair name of something that isn't a pair");
429 getPairId (asmop * aop)
433 if (aop->type == AOP_REG)
435 if ((aop->aopu.aop_reg[0]->rIdx == C_IDX) && (aop->aopu.aop_reg[1]->rIdx == B_IDX))
439 if ((aop->aopu.aop_reg[0]->rIdx == E_IDX) && (aop->aopu.aop_reg[1]->rIdx == D_IDX))
443 if ((aop->aopu.aop_reg[0]->rIdx == L_IDX) && (aop->aopu.aop_reg[1]->rIdx == H_IDX))
448 if (aop->type == AOP_STR || aop->type == AOP_HLREG)
450 if (!strcmp (aop->aopu.aop_str[0], "c") && !strcmp (aop->aopu.aop_str[1], "b"))
454 if (!strcmp (aop->aopu.aop_str[0], "e") && !strcmp (aop->aopu.aop_str[1], "d"))
458 if (!strcmp (aop->aopu.aop_str[0], "l") && !strcmp (aop->aopu.aop_str[1], "h"))
467 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
471 return (getPairId (aop) != PAIR_INVALID);
475 isPtrPair (asmop * aop)
477 PAIR_ID pairId = getPairId (aop);
490 spillPair (PAIR_ID pairId)
492 _G.pairs[pairId].last_type = AOP_INVALID;
493 _G.pairs[pairId].base = NULL;
496 /** Push a register pair onto the stack */
498 genPairPush (asmop * aop)
500 emit2 ("push %s", getPairName (aop));
504 _push (PAIR_ID pairId)
506 emit2 ("push %s", _pairs[pairId].name);
507 _G.stack.pushed += 2;
511 _pop (PAIR_ID pairId)
513 emit2 ("pop %s", _pairs[pairId].name);
514 _G.stack.pushed -= 2;
518 /*-----------------------------------------------------------------*/
519 /* newAsmop - creates a new asmOp */
520 /*-----------------------------------------------------------------*/
522 newAsmop (short type)
526 aop = traceAlloc(&_G.trace.aops, Safe_alloc (sizeof (asmop)));
531 /*-----------------------------------------------------------------*/
532 /* aopForSym - for a true symbol */
533 /*-----------------------------------------------------------------*/
535 aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
542 wassert (sym->etype);
544 space = SPEC_OCLS (sym->etype);
546 /* if already has one */
550 /* Assign depending on the storage class */
551 if (sym->onStack || sym->iaccess)
553 /* The pointer that is used depends on how big the offset is.
554 Normally everything is AOP_STK, but for offsets of < -128 or
555 > 127 on the Z80 an extended stack pointer is used.
557 if (IS_Z80 && (options.ommitFramePtr || sym->stack < INT8MIN || sym->stack > (int)(INT8MAX-getSize (sym->type))))
559 emitDebug ("; AOP_EXSTK for %s", sym->rname);
560 sym->aop = aop = newAsmop (AOP_EXSTK);
564 emitDebug ("; AOP_STK for %s", sym->rname);
565 sym->aop = aop = newAsmop (AOP_STK);
568 aop->size = getSize (sym->type);
569 aop->aopu.aop_stk = sym->stack;
573 /* special case for a function */
574 if (IS_FUNC (sym->type))
576 sym->aop = aop = newAsmop (AOP_IMMD);
577 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup (sym->rname));
584 /* if it is in direct space */
585 if (IN_REGSP (space) && !requires_a)
587 sym->aop = aop = newAsmop (AOP_SFR);
588 aop->aopu.aop_dir = sym->rname;
589 aop->size = getSize (sym->type);
590 emitDebug ("; AOP_SFR for %s", sym->rname);
595 /* only remaining is far space */
596 /* in which case DPTR gets the address */
599 emitDebug ("; AOP_HL for %s", sym->rname);
600 sym->aop = aop = newAsmop (AOP_HL);
604 sym->aop = aop = newAsmop (AOP_IY);
606 aop->size = getSize (sym->type);
607 aop->aopu.aop_dir = sym->rname;
609 /* if it is in code space */
610 if (IN_CODESPACE (space))
616 /*-----------------------------------------------------------------*/
617 /* aopForRemat - rematerialzes an object */
618 /*-----------------------------------------------------------------*/
620 aopForRemat (symbol * sym)
623 iCode *ic = sym->rematiCode;
624 asmop *aop = newAsmop (AOP_IMMD);
628 /* if plus or minus print the right hand side */
629 if (ic->op == '+' || ic->op == '-')
631 /* PENDING: for re-target */
632 sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
635 ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
638 /* we reached the end */
639 sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
643 aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
647 /*-----------------------------------------------------------------*/
648 /* regsInCommon - two operands have some registers in common */
649 /*-----------------------------------------------------------------*/
651 regsInCommon (operand * op1, operand * op2)
656 /* if they have registers in common */
657 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
660 sym1 = OP_SYMBOL (op1);
661 sym2 = OP_SYMBOL (op2);
663 if (sym1->nRegs == 0 || sym2->nRegs == 0)
666 for (i = 0; i < sym1->nRegs; i++)
672 for (j = 0; j < sym2->nRegs; j++)
677 if (sym2->regs[j] == sym1->regs[i])
685 /*-----------------------------------------------------------------*/
686 /* operandsEqu - equivalent */
687 /*-----------------------------------------------------------------*/
689 operandsEqu (operand * op1, operand * op2)
693 /* if they not symbols */
694 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
697 sym1 = OP_SYMBOL (op1);
698 sym2 = OP_SYMBOL (op2);
700 /* if both are itemps & one is spilt
701 and the other is not then false */
702 if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
703 sym1->isspilt != sym2->isspilt)
706 /* if they are the same */
710 if (strcmp (sym1->rname, sym2->rname) == 0)
714 /* if left is a tmp & right is not */
715 if (IS_ITEMP (op1) &&
718 (sym1->usl.spillLoc == sym2))
721 if (IS_ITEMP (op2) &&
725 (sym2->usl.spillLoc == sym1))
731 /*-----------------------------------------------------------------*/
732 /* sameRegs - two asmops have the same registers */
733 /*-----------------------------------------------------------------*/
735 sameRegs (asmop * aop1, asmop * aop2)
739 if (aop1->type == AOP_SFR ||
740 aop2->type == AOP_SFR)
746 if (aop1->type != AOP_REG ||
747 aop2->type != AOP_REG)
750 if (aop1->size != aop2->size)
753 for (i = 0; i < aop1->size; i++)
754 if (aop1->aopu.aop_reg[i] !=
755 aop2->aopu.aop_reg[i])
761 /*-----------------------------------------------------------------*/
762 /* aopOp - allocates an asmop for an operand : */
763 /*-----------------------------------------------------------------*/
765 aopOp (operand * op, iCode * ic, bool result, bool requires_a)
774 /* if this a literal */
775 if (IS_OP_LITERAL (op))
777 op->aop = aop = newAsmop (AOP_LIT);
778 aop->aopu.aop_lit = op->operand.valOperand;
779 aop->size = getSize (operandType (op));
783 /* if already has a asmop then continue */
787 /* if the underlying symbol has a aop */
788 if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
790 op->aop = OP_SYMBOL (op)->aop;
794 /* if this is a true symbol */
795 if (IS_TRUE_SYMOP (op))
797 op->aop = aopForSym (ic, OP_SYMBOL (op), result, requires_a);
801 /* this is a temporary : this has
807 e) can be a return use only */
809 sym = OP_SYMBOL (op);
811 /* if the type is a conditional */
812 if (sym->regType == REG_CND)
814 aop = op->aop = sym->aop = newAsmop (AOP_CRY);
819 /* if it is spilt then two situations
821 b) has a spill location */
822 if (sym->isspilt || sym->nRegs == 0)
824 /* rematerialize it NOW */
827 sym->aop = op->aop = aop =
829 aop->size = getSize (sym->type);
835 if (sym->accuse == ACCUSE_A)
837 aop = op->aop = sym->aop = newAsmop (AOP_ACC);
838 aop->size = getSize (sym->type);
839 wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
841 aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
843 else if (sym->accuse == ACCUSE_SCRATCH)
845 aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
846 aop->size = getSize (sym->type);
847 wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
848 aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
849 aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
853 wassertl (0, "Marked as being allocated into A or HL but is actually in neither");
861 aop = op->aop = sym->aop = newAsmop (AOP_STR);
862 aop->size = getSize (sym->type);
863 for (i = 0; i < 4; i++)
864 aop->aopu.aop_str[i] = _fReturn[i];
868 /* else spill location */
869 sym->aop = op->aop = aop =
870 aopForSym (ic, sym->usl.spillLoc, result, requires_a);
871 aop->size = getSize (sym->type);
875 /* must be in a register */
876 sym->aop = op->aop = aop = newAsmop (AOP_REG);
877 aop->size = sym->nRegs;
878 for (i = 0; i < sym->nRegs; i++)
879 aop->aopu.aop_reg[i] = sym->regs[i];
882 /*-----------------------------------------------------------------*/
883 /* freeAsmop - free up the asmop given to an operand */
884 /*----------------------------------------------------------------*/
886 freeAsmop (operand * op, asmop * aaop, iCode * ic)
903 if (aop->type == AOP_PAIRPTR && IS_Z80 && aop->aopu.aop_pairId == PAIR_DE)
905 _pop (aop->aopu.aop_pairId);
909 /* all other cases just dealloc */
915 OP_SYMBOL (op)->aop = NULL;
916 /* if the symbol has a spill */
918 SPIL_LOC (op)->aop = NULL;
925 isLitWord (asmop * aop)
927 /* if (aop->size != 2)
940 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
944 /* depending on type */
950 /* PENDING: for re-target */
953 tsprintf (s, "!hashedstr + %d", aop->aopu.aop_immd, offset);
955 else if (offset == 0)
957 tsprintf (s, "%s", aop->aopu.aop_immd);
961 tsprintf (s, "%s + %d", aop->aopu.aop_immd, offset);
963 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
967 value *val = aop->aopu.aop_lit;
968 /* if it is a float then it gets tricky */
969 /* otherwise it is fairly simple */
970 if (!IS_FLOAT (val->type))
972 unsigned long v = (unsigned long) floatFromVal (val);
978 else if (offset == 0)
984 wassertl(0, "Encountered an invalid offset while fetching a literal");
988 tsprintf (buffer, "!immedword", v);
990 tsprintf (buffer, "!constword", v);
992 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1003 /* it is type float */
1004 fl.f = (float) floatFromVal (val);
1007 i = fl.c[3-offset] | (fl.c[3-offset-1]<<8);
1009 i = fl.c[offset] | (fl.c[offset+1]<<8);
1012 tsprintf (buffer, "!immedword", i);
1014 tsprintf (buffer, "!constword", i);
1016 return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1025 aopGetWord (asmop * aop, int offset)
1027 return aopGetLitWordLong (aop, offset, TRUE);
1031 isPtr (const char *s)
1033 if (!strcmp (s, "hl"))
1035 if (!strcmp (s, "ix"))
1037 if (!strcmp (s, "iy"))
1043 adjustPair (const char *pair, int *pold, int new)
1049 emit2 ("inc %s", pair);
1054 emit2 ("dec %s", pair);
1062 spillPair (PAIR_HL);
1063 spillPair (PAIR_IY);
1067 requiresHL (asmop * aop)
1083 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1085 const char *l, *base;
1086 const char *pair = _pairs[pairId].name;
1087 l = aopGetLitWordLong (left, offset, FALSE);
1088 base = aopGetLitWordLong (left, 0, FALSE);
1089 wassert (l && pair && base);
1093 if (pairId == PAIR_HL || pairId == PAIR_IY)
1095 if (_G.pairs[pairId].last_type == left->type)
1097 if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1099 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1101 adjustPair (pair, &_G.pairs[pairId].offset, offset);
1104 if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
1111 _G.pairs[pairId].last_type = left->type;
1112 _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1113 _G.pairs[pairId].offset = offset;
1115 /* Both a lit on the right and a true symbol on the left */
1116 emit2 ("ld %s,!hashedstr", pair, l);
1120 fetchPairLong (PAIR_ID pairId, asmop * aop, int offset)
1122 /* if this is remateriazable */
1123 if (isLitWord (aop)) {
1124 fetchLitPair (pairId, aop, offset);
1127 /* we need to get it byte by byte */
1128 if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1129 aopGet (aop, offset, FALSE);
1130 switch (aop->size - offset) {
1132 emit2 ("ld l,!*hl");
1133 emit2 ("ld h,!immedbyte", 0);
1136 // PENDING: Requires that you are only fetching two bytes.
1139 emit2 ("ld h,!*hl");
1143 wassertl (0, "Attempted to fetch too much data into HL");
1147 else if (IS_Z80 && aop->type == AOP_IY) {
1148 /* Instead of fetching relative to IY, just grab directly
1149 from the address IY refers to */
1150 char *l = aopGetLitWordLong (aop, offset, FALSE);
1152 emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1154 if (aop->size < 2) {
1155 emit2("ld %s,!zero", _pairs[pairId].h);
1159 emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1160 emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1162 /* PENDING: check? */
1163 if (pairId == PAIR_HL)
1164 spillPair (PAIR_HL);
1169 fetchPair (PAIR_ID pairId, asmop * aop)
1171 fetchPairLong (pairId, aop, 0);
1175 fetchHL (asmop * aop)
1177 fetchPair (PAIR_HL, aop);
1181 setupPairFromSP (PAIR_ID id, int offset)
1183 wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
1185 if (offset < INT8MIN || offset > INT8MAX)
1187 emit2 ("ld hl,!immedword", offset);
1188 emit2 ("add hl,sp");
1192 emit2 ("!ldahlsp", offset);
1197 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1202 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
1203 fetchLitPair (pairId, aop, 0);
1207 wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
1209 fetchLitPair (pairId, aop, offset);
1210 _G.pairs[pairId].offset = offset;
1214 wassertl (IS_Z80, "Only the Z80 has an extended stack");
1215 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
1218 int offset = aop->aopu.aop_stk + _G.stack.offset;
1220 if (_G.pairs[pairId].last_type == aop->type &&
1221 _G.pairs[pairId].offset == offset)
1227 /* PENDING: Do this better. */
1228 sprintf (buffer, "%d", offset + _G.stack.pushed);
1229 emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
1230 emit2 ("add %s,sp", _pairs[pairId].name);
1231 _G.pairs[pairId].last_type = aop->type;
1232 _G.pairs[pairId].offset = offset;
1239 /* Doesnt include _G.stack.pushed */
1240 int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1241 if (aop->aopu.aop_stk > 0)
1243 abso += _G.stack.param_offset;
1245 assert (pairId == PAIR_HL);
1246 /* In some cases we can still inc or dec hl */
1247 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1249 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1253 setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
1255 _G.pairs[pairId].offset = abso;
1260 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
1266 _G.pairs[pairId].last_type = aop->type;
1272 emit2 ("!tlabeldef", key);
1276 /*-----------------------------------------------------------------*/
1277 /* aopGet - for fetching value of the aop */
1278 /*-----------------------------------------------------------------*/
1280 aopGet (asmop * aop, int offset, bool bit16)
1284 /* offset is greater than size then zero */
1285 /* PENDING: this seems a bit screwed in some pointer cases. */
1286 if (offset > (aop->size - 1) &&
1287 aop->type != AOP_LIT)
1289 tsprintf (s, "!zero");
1290 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1293 /* depending on type */
1297 /* PENDING: re-target */
1299 tsprintf (s, "!immedwords", aop->aopu.aop_immd);
1304 tsprintf (s, "!bankimmeds", aop->aopu.aop_immd);
1307 tsprintf (s, "!msbimmeds", aop->aopu.aop_immd);
1310 tsprintf (s, "!lsbimmeds", aop->aopu.aop_immd);
1313 wassertl (0, "Fetching from beyond the limits of an immediate value.");
1316 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1320 emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1323 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1327 emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1330 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1333 return aop->aopu.aop_reg[offset]->name;
1337 setupPair (PAIR_HL, aop, offset);
1338 tsprintf (s, "!*hl");
1340 return traceAlloc(&_G.trace.aops, Safe_strdup (s));
1344 setupPair (PAIR_IY, aop, offset);
1345 tsprintf (s, "!*iyx", offset);
1347 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1351 setupPair (PAIR_IY, aop, offset);
1352 tsprintf (s, "!*iyx", offset, offset);
1354 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1359 setupPair (PAIR_HL, aop, offset);
1360 tsprintf (s, "!*hl");
1364 if (aop->aopu.aop_stk >= 0)
1365 offset += _G.stack.param_offset;
1366 tsprintf (s, "!*ixx", aop->aopu.aop_stk + offset);
1369 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1372 wassertl (0, "Tried to fetch from a bit variable");
1381 tsprintf(s, "!zero");
1382 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1386 wassert (offset < 2);
1387 return aop->aopu.aop_str[offset];
1390 return aopLiteral (aop->aopu.aop_lit, offset);
1394 unsigned long v = aop->aopu.aop_simplelit;
1397 tsprintf (s, "!immedbyte", (unsigned int) v & 0xff);
1399 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1403 return aop->aopu.aop_str[offset];
1406 setupPair (aop->aopu.aop_pairId, aop, offset);
1407 sprintf (s, "(%s)", _pairs[aop->aopu.aop_pairId].name);
1409 return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1414 wassertl (0, "aopget got unsupported aop->type");
1419 isRegString (const char *s)
1421 if (!strcmp (s, "b") ||
1433 isConstant (const char *s)
1435 /* This is a bit of a hack... */
1436 return (*s == '#' || *s == '$');
1440 canAssignToPtr (const char *s)
1442 if (isRegString (s))
1449 /*-----------------------------------------------------------------*/
1450 /* aopPut - puts a string for a aop */
1451 /*-----------------------------------------------------------------*/
1453 aopPut (asmop * aop, const char *s, int offset)
1457 if (aop->size && offset > (aop->size - 1))
1459 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1460 "aopPut got offset > aop->size");
1465 tsprintf(buffer2, s);
1468 /* will assign value to value */
1469 /* depending on where it is ofcourse */
1475 if (strcmp (s, "a"))
1476 emit2 ("ld a,%s", s);
1477 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1482 if (strcmp (s, "a"))
1483 emit2 ("ld a,%s", s);
1484 emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1488 if (!strcmp (s, "!*hl"))
1489 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1492 aop->aopu.aop_reg[offset]->name, s);
1497 if (!canAssignToPtr (s))
1499 emit2 ("ld a,%s", s);
1500 setupPair (PAIR_IY, aop, offset);
1501 emit2 ("ld !*iyx,a", offset);
1505 setupPair (PAIR_IY, aop, offset);
1506 emit2 ("ld !*iyx,%s", offset, s);
1512 /* PENDING: for re-target */
1513 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1515 emit2 ("ld a,!*hl");
1518 setupPair (PAIR_HL, aop, offset);
1520 emit2 ("ld !*hl,%s", s);
1525 if (!canAssignToPtr (s))
1527 emit2 ("ld a,%s", s);
1528 setupPair (PAIR_IY, aop, offset);
1529 emit2 ("ld !*iyx,a", offset);
1533 setupPair (PAIR_IY, aop, offset);
1534 emit2 ("ld !*iyx,%s", offset, s);
1541 /* PENDING: re-target */
1542 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1544 emit2 ("ld a,!*hl");
1547 setupPair (PAIR_HL, aop, offset);
1548 if (!canAssignToPtr (s))
1550 emit2 ("ld a,%s", s);
1551 emit2 ("ld !*hl,a");
1554 emit2 ("ld !*hl,%s", s);
1558 if (aop->aopu.aop_stk >= 0)
1559 offset += _G.stack.param_offset;
1560 if (!canAssignToPtr (s))
1562 emit2 ("ld a,%s", s);
1563 emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
1566 emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
1571 /* if bit variable */
1572 if (!aop->aopu.aop_dir)
1579 /* In bit space but not in C - cant happen */
1580 wassertl (0, "Tried to write into a bit variable");
1586 if (strcmp (aop->aopu.aop_str[offset], s))
1588 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1594 if (!offset && (strcmp (s, "acc") == 0))
1598 wassertl (0, "Tried to access past the end of A");
1602 if (strcmp (aop->aopu.aop_str[offset], s))
1603 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1608 wassert (offset < 2);
1609 emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1613 setupPair (aop->aopu.aop_pairId, aop, offset);
1614 emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
1618 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1619 "aopPut got unsupported aop->type");
1624 #define AOP(op) op->aop
1625 #define AOP_TYPE(op) AOP(op)->type
1626 #define AOP_SIZE(op) AOP(op)->size
1627 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
1630 commitPair (asmop * aop, PAIR_ID id)
1632 /* PENDING: Verify this. */
1633 if (id == PAIR_HL && requiresHL (aop) && IS_GB)
1637 aopPut (aop, "a", 0);
1638 aopPut (aop, "d", 1);
1643 if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
1645 char *l = aopGetLitWordLong (aop, 0, FALSE);
1648 emit2 ("ld (%s),%s", l, _pairs[id].name);
1652 aopPut (aop, _pairs[id].l, 0);
1653 aopPut (aop, _pairs[id].h, 1);
1658 /*-----------------------------------------------------------------*/
1659 /* getDataSize - get the operand data size */
1660 /*-----------------------------------------------------------------*/
1662 getDataSize (operand * op)
1665 size = AOP_SIZE (op);
1669 wassertl (0, "Somehow got a three byte data pointer");
1674 /*-----------------------------------------------------------------*/
1675 /* movLeft2Result - move byte from left to result */
1676 /*-----------------------------------------------------------------*/
1678 movLeft2Result (operand * left, int offl,
1679 operand * result, int offr, int sign)
1683 if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
1685 l = aopGet (AOP (left), offl, FALSE);
1689 aopPut (AOP (result), l, offr);
1693 if (getDataSize (left) == offl + 1)
1695 emit2 ("ld a,%s", l);
1696 aopPut (AOP (result), "a", offr);
1703 movLeft2ResultLong (operand * left, int offl,
1704 operand * result, int offr, int sign,
1709 movLeft2Result (left, offl, result, offr, sign);
1713 wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
1714 wassertl (size == 2, "Only implemented for two bytes or one");
1716 if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
1718 emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
1719 emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
1724 movLeft2Result (left, offl, result, offr, sign);
1725 movLeft2Result (left, offl+1, result, offr+1, sign);
1730 /** Put Acc into a register set
1733 outAcc (operand * result)
1736 size = getDataSize (result);
1739 aopPut (AOP (result), "a", 0);
1742 /* unsigned or positive */
1745 aopPut (AOP (result), "!zero", offset++);
1750 /** Take the value in carry and put it into a register
1753 outBitCLong (operand * result, bool swap_sense)
1755 /* if the result is bit */
1756 if (AOP_TYPE (result) == AOP_CRY)
1758 wassertl (0, "Tried to write carry to a bit");
1762 emit2 ("ld a,!zero");
1765 emit2 ("xor a,!immedbyte", 1);
1771 outBitC (operand * result)
1773 outBitCLong (result, FALSE);
1776 /*-----------------------------------------------------------------*/
1777 /* toBoolean - emit code for orl a,operator(sizeop) */
1778 /*-----------------------------------------------------------------*/
1780 _toBoolean (operand * oper)
1782 int size = AOP_SIZE (oper);
1786 emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
1789 emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
1793 if (AOP (oper)->type != AOP_ACC)
1796 emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
1801 /*-----------------------------------------------------------------*/
1802 /* genNotFloat - generates not for float operations */
1803 /*-----------------------------------------------------------------*/
1805 genNotFloat (operand * op, operand * res)
1810 emitDebug ("; genNotFloat");
1812 /* we will put 127 in the first byte of
1814 aopPut (AOP (res), "!immedbyte", 0x7F);
1815 size = AOP_SIZE (op) - 1;
1818 _moveA (aopGet (op->aop, offset++, FALSE));
1822 emit2 ("or a,%s", aopGet (op->aop, offset++, FALSE));
1825 tlbl = newiTempLabel (NULL);
1826 aopPut (res->aop, "!one", 1);
1827 emit2 ("!shortjp z !tlabel", tlbl->key + 100);
1828 aopPut (res->aop, "!zero", 1);
1830 emitLabel(tlbl->key + 100);
1832 size = res->aop->size - 2;
1834 /* put zeros in the rest */
1836 aopPut (res->aop, "!zero", offset++);
1839 /*-----------------------------------------------------------------*/
1840 /* genNot - generate code for ! operation */
1841 /*-----------------------------------------------------------------*/
1845 sym_link *optype = operandType (IC_LEFT (ic));
1847 /* assign asmOps to operand & result */
1848 aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
1849 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1851 /* if in bit space then a special case */
1852 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1854 wassertl (0, "Tried to negate a bit");
1857 /* if type float then do float */
1858 if (IS_FLOAT (optype))
1860 genNotFloat (IC_LEFT (ic), IC_RESULT (ic));
1864 _toBoolean (IC_LEFT (ic));
1869 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
1870 emit2 ("sub a,!one");
1871 outBitC (IC_RESULT (ic));
1874 /* release the aops */
1875 freeAsmop (IC_LEFT (ic), NULL, ic);
1876 freeAsmop (IC_RESULT (ic), NULL, ic);
1879 /*-----------------------------------------------------------------*/
1880 /* genCpl - generate code for complement */
1881 /*-----------------------------------------------------------------*/
1889 /* assign asmOps to operand & result */
1890 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1891 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1893 /* if both are in bit space then
1895 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1896 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1898 wassertl (0, "Left and the result are in bit space");
1901 size = AOP_SIZE (IC_RESULT (ic));
1904 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
1907 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1910 /* release the aops */
1911 freeAsmop (IC_LEFT (ic), NULL, ic);
1912 freeAsmop (IC_RESULT (ic), NULL, ic);
1916 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
1923 store de into result
1928 store de into result
1930 const char *first = isAdd ? "add" : "sub";
1931 const char *later = isAdd ? "adc" : "sbc";
1933 wassertl (IS_GB, "Code is only relevent to the gbz80");
1934 wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
1936 fetchPair (PAIR_DE, left);
1939 emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
1942 emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
1945 aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
1946 aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
1948 fetchPairLong (PAIR_DE, left, MSB24);
1949 aopGet (right, MSB24, FALSE);
1953 emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
1956 emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
1958 aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
1959 aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
1963 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
1965 _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
1968 /*-----------------------------------------------------------------*/
1969 /* genUminusFloat - unary minus for floating points */
1970 /*-----------------------------------------------------------------*/
1972 genUminusFloat (operand * op, operand * result)
1974 int size, offset = 0;
1976 emitDebug("; genUminusFloat");
1978 /* for this we just need to flip the
1979 first it then copy the rest in place */
1980 size = AOP_SIZE (op) - 1;
1982 _moveA(aopGet (AOP (op), MSB32, FALSE));
1984 emit2("xor a,!immedbyte", 0x80);
1985 aopPut (AOP (result), "a", MSB32);
1989 aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
1994 /*-----------------------------------------------------------------*/
1995 /* genUminus - unary minus code generation */
1996 /*-----------------------------------------------------------------*/
1998 genUminus (iCode * ic)
2001 sym_link *optype, *rtype;
2004 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2005 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2007 /* if both in bit space then special
2009 if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2010 AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2012 wassertl (0, "Left and right are in bit space");
2016 optype = operandType (IC_LEFT (ic));
2017 rtype = operandType (IC_RESULT (ic));
2019 /* if float then do float stuff */
2020 if (IS_FLOAT (optype))
2022 genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2026 /* otherwise subtract from zero */
2027 size = AOP_SIZE (IC_LEFT (ic));
2029 if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2031 /* Create a new asmop with value zero */
2032 asmop *azero = newAsmop (AOP_SIMPLELIT);
2033 azero->aopu.aop_simplelit = 0;
2035 _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2043 const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2044 emit2 ("ld a,!zero");
2045 emit2 ("sbc a,%s", l);
2046 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2049 /* if any remaining bytes in the result */
2050 /* we just need to propagate the sign */
2051 if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2056 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2060 /* release the aops */
2061 freeAsmop (IC_LEFT (ic), NULL, ic);
2062 freeAsmop (IC_RESULT (ic), NULL, ic);
2065 /*-----------------------------------------------------------------*/
2066 /* assignResultValue - */
2067 /*-----------------------------------------------------------------*/
2069 assignResultValue (operand * oper)
2071 int size = AOP_SIZE (oper);
2074 wassertl (size <= 4, "Got a result that is bigger than four bytes");
2075 topInA = requiresHL (AOP (oper));
2077 if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2079 /* We do it the hard way here. */
2081 aopPut (AOP (oper), _fReturn[0], 0);
2082 aopPut (AOP (oper), _fReturn[1], 1);
2084 aopPut (AOP (oper), _fReturn[0], 2);
2085 aopPut (AOP (oper), _fReturn[1], 3);
2091 aopPut (AOP (oper), _fReturn[size], size);
2096 /** Simple restore that doesn't take into account what is used in the
2100 _restoreRegsAfterCall(void)
2102 if (_G.stack.pushedDE)
2105 _G.stack.pushedDE = FALSE;
2107 if (_G.stack.pushedBC)
2110 _G.stack.pushedBC = FALSE;
2112 _G.saves.saved = FALSE;
2116 _saveRegsForCall(iCode *ic, int sendSetSize)
2119 o Stack parameters are pushed before this function enters
2120 o DE and BC may be used in this function.
2121 o HL and DE may be used to return the result.
2122 o HL and DE may be used to send variables.
2123 o DE and BC may be used to store the result value.
2124 o HL may be used in computing the sent value of DE
2125 o The iPushes for other parameters occur before any addSets
2127 Logic: (to be run inside the first iPush or if none, before sending)
2128 o Compute if DE and/or BC are in use over the call
2129 o Compute if DE is used in the send set
2130 o Compute if DE and/or BC are used to hold the result value
2131 o If (DE is used, or in the send set) and is not used in the result, push.
2132 o If BC is used and is not in the result, push
2134 o If DE is used in the send set, fetch
2135 o If HL is used in the send set, fetch
2139 if (_G.saves.saved == FALSE) {
2140 bool deInUse, bcInUse;
2142 bool bcInRet = FALSE, deInRet = FALSE;
2145 rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
2147 deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2148 bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2150 deSending = (sendSetSize > 1);
2152 emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2154 if (bcInUse && bcInRet == FALSE) {
2156 _G.stack.pushedBC = TRUE;
2158 if (deInUse && deInRet == FALSE) {
2160 _G.stack.pushedDE = TRUE;
2163 _G.saves.saved = TRUE;
2166 /* Already saved. */
2170 /*-----------------------------------------------------------------*/
2171 /* genIpush - genrate code for pushing this gets a little complex */
2172 /*-----------------------------------------------------------------*/
2174 genIpush (iCode * ic)
2176 int size, offset = 0;
2179 /* if this is not a parm push : ie. it is spill push
2180 and spill push is always done on the local stack */
2183 wassertl(0, "Encountered an unsupported spill push.");
2187 if (_G.saves.saved == FALSE) {
2188 /* Caller saves, and this is the first iPush. */
2189 /* Scan ahead until we find the function that we are pushing parameters to.
2190 Count the number of addSets on the way to figure out what registers
2191 are used in the send set.
2194 iCode *walk = ic->next;
2197 if (walk->op == SEND) {
2200 else if (walk->op == CALL || walk->op == PCALL) {
2209 _saveRegsForCall(walk, nAddSets);
2212 /* Already saved by another iPush. */
2215 /* then do the push */
2216 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2218 size = AOP_SIZE (IC_LEFT (ic));
2220 if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2222 _G.stack.pushed += 2;
2223 emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2229 fetchHL (AOP (IC_LEFT (ic)));
2231 spillPair (PAIR_HL);
2232 _G.stack.pushed += 2;
2237 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
2239 spillPair (PAIR_HL);
2240 _G.stack.pushed += 2;
2241 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 0);
2243 spillPair (PAIR_HL);
2244 _G.stack.pushed += 2;
2250 if (AOP (IC_LEFT (ic))->type == AOP_IY)
2252 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2254 emit2 ("ld a,(%s)", l);
2258 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2259 emit2 ("ld a,%s", l);
2267 freeAsmop (IC_LEFT (ic), NULL, ic);
2270 /*-----------------------------------------------------------------*/
2271 /* genIpop - recover the registers: can happen only for spilling */
2272 /*-----------------------------------------------------------------*/
2274 genIpop (iCode * ic)
2279 /* if the temp was not pushed then */
2280 if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2283 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2284 size = AOP_SIZE (IC_LEFT (ic));
2285 offset = (size - 1);
2286 if (isPair (AOP (IC_LEFT (ic))))
2288 emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2296 spillPair (PAIR_HL);
2297 aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2301 freeAsmop (IC_LEFT (ic), NULL, ic);
2304 /* This is quite unfortunate */
2306 setArea (int inHome)
2309 static int lastArea = 0;
2311 if (_G.in_home != inHome) {
2313 const char *sz = port->mem.code_name;
2314 port->mem.code_name = "HOME";
2315 emit2("!area", CODE_NAME);
2316 port->mem.code_name = sz;
2319 emit2("!area", CODE_NAME); */
2320 _G.in_home = inHome;
2331 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2335 symbol *sym = OP_SYMBOL (op);
2337 if (sym->isspilt || sym->nRegs == 0)
2340 aopOp (op, ic, FALSE, FALSE);
2343 if (aop->type == AOP_REG)
2346 for (i = 0; i < aop->size; i++)
2348 if (pairId == PAIR_DE)
2350 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2351 if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2353 if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2356 else if (pairId == PAIR_BC)
2358 emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2359 if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2361 if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2371 freeAsmop (IC_LEFT (ic), NULL, ic);
2375 /** Emit the code for a call statement
2378 emitCall (iCode * ic, bool ispcall)
2380 sym_link *dtype = operandType (IC_LEFT (ic));
2382 bitVect *rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
2384 /* if caller saves & we have not saved then */
2390 _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2392 /* if send set is not empty then assign */
2397 int nSend = elementsInSet(_G.sendSet);
2398 bool swapped = FALSE;
2400 int _z80_sendOrder[] = {
2405 /* Check if the parameters are swapped. If so route through hl instead. */
2406 wassertl (nSend == 2, "Pedantic check. Code only checks for the two send items case.");
2408 sic = setFirstItem(_G.sendSet);
2409 sic = setNextItem(_G.sendSet);
2411 if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2412 /* The second send value is loaded from one the one that holds the first
2413 send, i.e. it is overwritten. */
2414 /* Cache the first in HL, and load the second from HL instead. */
2415 emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2416 emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2422 for (sic = setFirstItem (_G.sendSet); sic;
2423 sic = setNextItem (_G.sendSet))
2426 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2428 size = AOP_SIZE (IC_LEFT (sic));
2429 wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2430 wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2432 // PENDING: Mild hack
2433 if (swapped == TRUE && send == 1) {
2435 emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2438 emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2440 emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2443 fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2447 freeAsmop (IC_LEFT (sic), NULL, sic);
2454 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2456 werror (W_INDIR_BANKED);
2458 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2460 if (isLitWord (AOP (IC_LEFT (ic))))
2462 emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2466 symbol *rlbl = newiTempLabel (NULL);
2467 spillPair (PAIR_HL);
2468 emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2470 _G.stack.pushed += 2;
2472 fetchHL (AOP (IC_LEFT (ic)));
2474 emit2 ("!tlabeldef", (rlbl->key + 100));
2475 _G.stack.pushed -= 2;
2477 freeAsmop (IC_LEFT (ic), NULL, ic);
2481 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2482 OP_SYMBOL (IC_LEFT (ic))->rname :
2483 OP_SYMBOL (IC_LEFT (ic))->name;
2484 if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2486 emit2 ("call banked_call");
2487 emit2 ("!dws", name);
2488 emit2 ("!dw !bankimmeds", name);
2493 emit2 ("call %s", name);
2498 /* Mark the regsiters as restored. */
2499 _G.saves.saved = FALSE;
2501 /* if we need assign a result value */
2502 if ((IS_ITEMP (IC_RESULT (ic)) &&
2503 (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2504 OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2505 IS_TRUE_SYMOP (IC_RESULT (ic)))
2508 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2510 assignResultValue (IC_RESULT (ic));
2512 freeAsmop (IC_RESULT (ic), NULL, ic);
2515 /* adjust the stack for parameters if required */
2518 int i = ic->parmBytes;
2520 _G.stack.pushed -= i;
2523 emit2 ("!ldaspsp", i);
2530 emit2 ("ld hl,#%d", i);
2531 emit2 ("add hl,sp");
2549 if (_G.stack.pushedDE)
2551 bool dInUse = bitVectBitValue(rInUse, D_IDX);
2552 bool eInUse = bitVectBitValue(rInUse, E_IDX);
2554 if (dInUse && eInUse)
2570 wassertl (0, "Neither D or E were in use but it was pushed.");
2572 _G.stack.pushedDE = FALSE;
2575 if (_G.stack.pushedBC)
2577 bool bInUse = bitVectBitValue(rInUse, B_IDX);
2578 bool cInUse = bitVectBitValue(rInUse, C_IDX);
2580 // If both B and C are used in the return value, then we won't get
2582 if (bInUse && cInUse)
2598 wassertl (0, "Neither B or C were in use but it was pushed.");
2600 _G.stack.pushedBC = FALSE;
2604 /*-----------------------------------------------------------------*/
2605 /* genCall - generates a call statement */
2606 /*-----------------------------------------------------------------*/
2608 genCall (iCode * ic)
2610 emitCall (ic, FALSE);
2613 /*-----------------------------------------------------------------*/
2614 /* genPcall - generates a call by pointer statement */
2615 /*-----------------------------------------------------------------*/
2617 genPcall (iCode * ic)
2619 emitCall (ic, TRUE);
2622 /*-----------------------------------------------------------------*/
2623 /* resultRemat - result is rematerializable */
2624 /*-----------------------------------------------------------------*/
2626 resultRemat (iCode * ic)
2628 if (SKIP_IC (ic) || ic->op == IFX)
2631 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2633 symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2634 if (sym->remat && !POINTER_SET (ic))
2641 extern set *publics;
2643 /*-----------------------------------------------------------------*/
2644 /* genFunction - generated code for function entry */
2645 /*-----------------------------------------------------------------*/
2647 genFunction (iCode * ic)
2649 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2653 bool bcInUse = FALSE;
2654 bool deInUse = FALSE;
2657 setArea (IFFUNC_NONBANKED (sym->type));
2659 /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
2662 _G.receiveOffset = 0;
2664 /* Record the last function name for debugging. */
2665 _G.lastFunctionName = sym->rname;
2667 /* Create the function header */
2668 emit2 ("!functionheader", sym->name);
2669 /* PENDING: portability. */
2670 emit2 ("__%s_start:", sym->rname);
2671 emit2 ("!functionlabeldef", sym->rname);
2673 if (options.profile)
2675 emit2 ("!profileenter");
2678 ftype = operandType (IC_LEFT (ic));
2680 /* if critical function then turn interrupts off */
2681 if (IFFUNC_ISCRITICAL (ftype))
2684 /* if this is an interrupt service routine then save all potentially used registers. */
2685 if (IFFUNC_ISISR (sym->type))
2690 /* PENDING: callee-save etc */
2692 _G.stack.param_offset = 0;
2695 /* Detect which registers are used. */
2699 for (i = 0; i < sym->regsUsed->size; i++)
2701 if (bitVectBitValue (sym->regsUsed, i))
2715 /* Other systems use DE as a temporary. */
2726 _G.stack.param_offset += 2;
2729 _G.stack.pushedBC = bcInUse;
2734 _G.stack.param_offset += 2;
2737 _G.stack.pushedDE = deInUse;
2740 /* adjust the stack for the function */
2741 _G.stack.last = sym->stack;
2743 if (sym->stack && IS_GB && sym->stack > -INT8MIN)
2744 emit2 ("!enterxl", sym->stack);
2745 else if (sym->stack)
2746 emit2 ("!enterx", sym->stack);
2749 _G.stack.offset = sym->stack;
2752 /*-----------------------------------------------------------------*/
2753 /* genEndFunction - generates epilogue for functions */
2754 /*-----------------------------------------------------------------*/
2756 genEndFunction (iCode * ic)
2758 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2760 if (IFFUNC_ISISR (sym->type))
2762 wassertl (0, "Tried to close an interrupt support function");
2766 if (IFFUNC_ISCRITICAL (sym->type))
2769 /* PENDING: calleeSave */
2771 if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
2773 emit2 ("!leavexl", _G.stack.offset);
2775 else if (_G.stack.offset)
2777 emit2 ("!leavex", _G.stack.offset);
2785 if (_G.stack.pushedDE)
2788 _G.stack.pushedDE = FALSE;
2791 if (_G.stack.pushedDE)
2794 _G.stack.pushedDE = FALSE;
2798 if (options.profile)
2800 emit2 ("!profileexit");
2804 /* Both baned and non-banked just ret */
2807 /* PENDING: portability. */
2808 emit2 ("__%s_end:", sym->rname);
2810 _G.flushStatics = 1;
2811 _G.stack.pushed = 0;
2812 _G.stack.offset = 0;
2815 /*-----------------------------------------------------------------*/
2816 /* genRet - generate code for return statement */
2817 /*-----------------------------------------------------------------*/
2822 /* Errk. This is a hack until I can figure out how
2823 to cause dehl to spill on a call */
2824 int size, offset = 0;
2826 /* if we have no return value then
2827 just generate the "ret" */
2831 /* we have something to return then
2832 move the return value into place */
2833 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2834 size = AOP_SIZE (IC_LEFT (ic));
2836 if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
2840 emit2 ("ld de,%s", l);
2844 emit2 ("ld hl,%s", l);
2849 if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
2851 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
2852 fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
2858 l = aopGet (AOP (IC_LEFT (ic)), offset,
2860 if (strcmp (_fReturn[offset], l))
2861 emit2 ("ld %s,%s", _fReturn[offset++], l);
2865 freeAsmop (IC_LEFT (ic), NULL, ic);
2868 /* generate a jump to the return label
2869 if the next is not the return statement */
2870 if (!(ic->next && ic->next->op == LABEL &&
2871 IC_LABEL (ic->next) == returnLabel))
2873 emit2 ("jp !tlabel", returnLabel->key + 100);
2876 /*-----------------------------------------------------------------*/
2877 /* genLabel - generates a label */
2878 /*-----------------------------------------------------------------*/
2880 genLabel (iCode * ic)
2882 /* special case never generate */
2883 if (IC_LABEL (ic) == entryLabel)
2886 emitLabel (IC_LABEL (ic)->key + 100);
2889 /*-----------------------------------------------------------------*/
2890 /* genGoto - generates a ljmp */
2891 /*-----------------------------------------------------------------*/
2893 genGoto (iCode * ic)
2895 emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
2898 /*-----------------------------------------------------------------*/
2899 /* genPlusIncr :- does addition with increment if possible */
2900 /*-----------------------------------------------------------------*/
2902 genPlusIncr (iCode * ic)
2904 unsigned int icount;
2905 unsigned int size = getDataSize (IC_RESULT (ic));
2906 PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
2908 /* will try to generate an increment */
2909 /* if the right side is not a literal
2911 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
2914 emitDebug ("; genPlusIncr");
2916 icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
2918 /* If result is a pair */
2919 if (resultId != PAIR_INVALID)
2921 if (isLitWord (AOP (IC_LEFT (ic))))
2923 fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
2926 if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
2928 fetchPair (resultId, AOP (IC_RIGHT (ic)));
2929 emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
2935 if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2939 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
2943 emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
2948 /* if the literal value of the right hand side
2949 is greater than 4 then it is not worth it */
2953 /* if increment 16 bits in register */
2954 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
2960 symbol *tlbl = NULL;
2961 tlbl = newiTempLabel (NULL);
2964 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
2967 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
2970 emitLabel (tlbl->key + 100);
2974 /* if the sizes are greater than 1 then we cannot */
2975 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
2976 AOP_SIZE (IC_LEFT (ic)) > 1)
2979 /* If the result is in a register then we can load then increment.
2981 if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
2983 aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
2986 emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
2991 /* we can if the aops of the left & result match or
2992 if they are in registers and the registers are the
2994 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2998 emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3006 /*-----------------------------------------------------------------*/
3007 /* outBitAcc - output a bit in acc */
3008 /*-----------------------------------------------------------------*/
3010 outBitAcc (operand * result)
3012 symbol *tlbl = newiTempLabel (NULL);
3013 /* if the result is a bit */
3014 if (AOP_TYPE (result) == AOP_CRY)
3016 wassertl (0, "Tried to write A into a bit");
3020 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3021 emit2 ("ld a,!one");
3022 emitLabel (tlbl->key + 100);
3028 couldDestroyCarry (asmop *aop)
3032 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3041 shiftIntoPair (int idx, asmop *aop)
3043 PAIR_ID id = PAIR_INVALID;
3045 wassertl (IS_Z80, "Only implemented for the Z80");
3046 // wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3058 wassertl (0, "Internal error - hit default case");
3061 emitDebug ("; Shift into pair idx %u", idx);
3065 setupPair (PAIR_HL, aop, 0);
3069 setupPair (PAIR_IY, aop, 0);
3071 emit2 ("pop %s", _pairs[id].name);
3074 aop->type = AOP_PAIRPTR;
3075 aop->aopu.aop_pairId = id;
3076 _G.pairs[id].offset = 0;
3077 _G.pairs[id].last_type = aop->type;
3081 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
3083 wassert (left && right);
3087 if (couldDestroyCarry (right) && couldDestroyCarry (result))
3089 shiftIntoPair (0, right);
3090 shiftIntoPair (1, result);
3092 else if (couldDestroyCarry (right))
3094 shiftIntoPair (0, right);
3096 else if (couldDestroyCarry (result))
3098 shiftIntoPair (0, result);
3107 /*-----------------------------------------------------------------*/
3108 /* genPlus - generates code for addition */
3109 /*-----------------------------------------------------------------*/
3111 genPlus (iCode * ic)
3113 int size, offset = 0;
3115 /* special cases :- */
3117 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3118 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3119 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3121 /* Swap the left and right operands if:
3123 if literal, literal on the right or
3124 if left requires ACC or right is already
3127 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3128 (AOP_NEEDSACC (IC_LEFT (ic))) ||
3129 AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3131 operand *t = IC_RIGHT (ic);
3132 IC_RIGHT (ic) = IC_LEFT (ic);
3136 /* if both left & right are in bit
3138 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3139 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3142 wassertl (0, "Tried to add two bits");
3145 /* if left in bit space & right literal */
3146 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3147 AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3149 /* Can happen I guess */
3150 wassertl (0, "Tried to add a bit to a literal");
3153 /* if I can do an increment instead
3154 of add then GOOD for ME */
3155 if (genPlusIncr (ic) == TRUE)
3158 emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3160 size = getDataSize (IC_RESULT (ic));
3162 /* Special case when left and right are constant */
3163 if (isPair (AOP (IC_RESULT (ic))))
3166 left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3167 right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3169 if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3175 sprintf (buffer, "#(%s + %s)", left, right);
3176 emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3181 if (isPair (AOP (IC_RIGHT (ic))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3183 /* Fetch into HL then do the add */
3184 spillPair (PAIR_HL);
3185 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3186 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3190 if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD)
3192 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3193 emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3195 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3200 ld hl,sp+n trashes C so we cant afford to do it during an
3201 add with stack based varibles. Worst case is:
3214 So you cant afford to load up hl if either left, right, or result
3215 is on the stack (*sigh*) The alt is:
3223 Combinations in here are:
3224 * If left or right are in bc then the loss is small - trap later
3225 * If the result is in bc then the loss is also small
3229 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3230 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3231 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3233 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3234 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3235 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3236 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3238 if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3240 /* Swap left and right */
3241 operand *t = IC_RIGHT (ic);
3242 IC_RIGHT (ic) = IC_LEFT (ic);
3245 if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3247 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3248 emit2 ("add hl,bc");
3252 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3253 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3254 emit2 ("add hl,de");
3256 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3262 /* Be paranoid on the GB with 4 byte variables due to how C
3263 can be trashed by lda hl,n(sp).
3265 _gbz80_emitAddSubLong (ic, TRUE);
3270 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3274 if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3276 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3279 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3282 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3286 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3289 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3292 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3294 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3298 freeAsmop (IC_LEFT (ic), NULL, ic);
3299 freeAsmop (IC_RIGHT (ic), NULL, ic);
3300 freeAsmop (IC_RESULT (ic), NULL, ic);
3304 /*-----------------------------------------------------------------*/
3305 /* genMinusDec :- does subtraction with deccrement if possible */
3306 /*-----------------------------------------------------------------*/
3308 genMinusDec (iCode * ic)
3310 unsigned int icount;
3311 unsigned int size = getDataSize (IC_RESULT (ic));
3313 /* will try to generate an increment */
3314 /* if the right side is not a literal we cannot */
3315 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3318 /* if the literal value of the right hand side
3319 is greater than 4 then it is not worth it */
3320 if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3323 size = getDataSize (IC_RESULT (ic));
3325 /* if decrement 16 bits in register */
3326 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3327 (size > 1) && isPair (AOP (IC_RESULT (ic))))
3330 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3334 /* If result is a pair */
3335 if (isPair (AOP (IC_RESULT (ic))))
3337 movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3339 emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3343 /* if increment 16 bits in register */
3344 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3348 fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3351 emit2 ("dec %s", _getTempPairName());
3354 commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3360 /* if the sizes are greater than 1 then we cannot */
3361 if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3362 AOP_SIZE (IC_LEFT (ic)) > 1)
3365 /* we can if the aops of the left & result match or if they are in
3366 registers and the registers are the same */
3367 if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3370 emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3377 /*-----------------------------------------------------------------*/
3378 /* genMinus - generates code for subtraction */
3379 /*-----------------------------------------------------------------*/
3381 genMinus (iCode * ic)
3383 int size, offset = 0;
3384 unsigned long lit = 0L;
3386 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3387 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3388 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3390 /* special cases :- */
3391 /* if both left & right are in bit space */
3392 if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3393 AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3395 wassertl (0, "Tried to subtract two bits");
3399 /* if I can do an decrement instead of subtract then GOOD for ME */
3400 if (genMinusDec (ic) == TRUE)
3403 size = getDataSize (IC_RESULT (ic));
3405 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3410 lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3414 /* Same logic as genPlus */
3417 if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3418 AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3419 AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3421 if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3422 AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3423 (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3424 AOP_SIZE (IC_RIGHT (ic)) <= 2))
3426 PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3427 PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3429 if (left == PAIR_INVALID && right == PAIR_INVALID)
3434 else if (right == PAIR_INVALID)
3436 else if (left == PAIR_INVALID)
3439 fetchPair (left, AOP (IC_LEFT (ic)));
3440 /* Order is important. Right may be HL */
3441 fetchPair (right, AOP (IC_RIGHT (ic)));
3443 emit2 ("ld a,%s", _pairs[left].l);
3444 emit2 ("sub a,%s", _pairs[right].l);
3446 emit2 ("ld a,%s", _pairs[left].h);
3447 emit2 ("sbc a,%s", _pairs[right].h);
3449 if ( AOP_SIZE (IC_RESULT (ic)) > 1)
3451 aopPut (AOP (IC_RESULT (ic)), "a", 1);
3453 aopPut (AOP (IC_RESULT (ic)), "e", 0);
3459 /* Be paranoid on the GB with 4 byte variables due to how C
3460 can be trashed by lda hl,n(sp).
3462 _gbz80_emitAddSubLong (ic, FALSE);
3467 setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3469 /* if literal, add a,#-lit, else normal subb */
3472 _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3473 if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3477 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3480 aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3484 /* first add without previous c */
3486 emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
3488 emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3490 aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3493 if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3494 AOP_SIZE (IC_LEFT (ic)) == 3 &&
3495 !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3497 wassertl (0, "Tried to subtract on a long pointer");
3501 freeAsmop (IC_LEFT (ic), NULL, ic);
3502 freeAsmop (IC_RIGHT (ic), NULL, ic);
3503 freeAsmop (IC_RESULT (ic), NULL, ic);
3506 /*-----------------------------------------------------------------*/
3507 /* genMult - generates code for multiplication */
3508 /*-----------------------------------------------------------------*/
3510 genMult (iCode * ic)
3514 /* If true then the final operation should be a subtract */
3515 bool active = FALSE;
3517 /* Shouldn't occur - all done through function calls */
3518 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3519 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3520 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3522 if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
3523 AOP_SIZE (IC_RIGHT (ic)) > 2 ||
3524 AOP_SIZE (IC_RESULT (ic)) > 2)
3526 wassertl (0, "Multiplication is handled through support function calls");
3529 /* Swap left and right such that right is a literal */
3530 if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
3532 operand *t = IC_RIGHT (ic);
3533 IC_RIGHT (ic) = IC_LEFT (ic);
3537 wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
3539 val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
3540 // wassertl (val > 0, "Multiply must be positive");
3541 wassertl (val != 1, "Can't multiply by 1");
3547 if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
3549 emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
3557 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3562 /* Fully unroled version of mul.s. Not the most efficient.
3564 for (count = 0; count < 16; count++)
3566 if (count != 0 && active)
3568 emit2 ("add hl,hl");
3572 if (active == FALSE)
3579 emit2 ("add hl,de");
3593 commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3595 freeAsmop (IC_LEFT (ic), NULL, ic);
3596 freeAsmop (IC_RIGHT (ic), NULL, ic);
3597 freeAsmop (IC_RESULT (ic), NULL, ic);
3600 /*-----------------------------------------------------------------*/
3601 /* genDiv - generates code for division */
3602 /*-----------------------------------------------------------------*/
3606 /* Shouldn't occur - all done through function calls */
3607 wassertl (0, "Division is handled through support function calls");
3610 /*-----------------------------------------------------------------*/
3611 /* genMod - generates code for division */
3612 /*-----------------------------------------------------------------*/
3616 /* Shouldn't occur - all done through function calls */
3620 /*-----------------------------------------------------------------*/
3621 /* genIfxJump :- will create a jump depending on the ifx */
3622 /*-----------------------------------------------------------------*/
3624 genIfxJump (iCode * ic, char *jval)
3629 /* if true label then we jump if condition
3633 jlbl = IC_TRUE (ic);
3634 if (!strcmp (jval, "a"))
3638 else if (!strcmp (jval, "c"))
3642 else if (!strcmp (jval, "nc"))
3648 /* The buffer contains the bit on A that we should test */
3654 /* false label is present */
3655 jlbl = IC_FALSE (ic);
3656 if (!strcmp (jval, "a"))
3660 else if (!strcmp (jval, "c"))
3664 else if (!strcmp (jval, "nc"))
3670 /* The buffer contains the bit on A that we should test */
3674 /* Z80 can do a conditional long jump */
3675 if (!strcmp (jval, "a"))
3679 else if (!strcmp (jval, "c"))
3682 else if (!strcmp (jval, "nc"))
3687 emit2 ("bit %s,a", jval);
3689 emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
3691 /* mark the icode as generated */
3697 _getPairIdName (PAIR_ID id)
3699 return _pairs[id].name;
3703 /** Generic compare for > or <
3706 genCmp (operand * left, operand * right,
3707 operand * result, iCode * ifx, int sign)
3709 int size, offset = 0;
3710 unsigned long lit = 0L;
3711 bool swap_sense = FALSE;
3713 /* if left & right are bit variables */
3714 if (AOP_TYPE (left) == AOP_CRY &&
3715 AOP_TYPE (right) == AOP_CRY)
3717 /* Cant happen on the Z80 */
3718 wassertl (0, "Tried to compare two bits");
3722 /* subtract right from left if at the
3723 end the carry flag is set then we know that
3724 left is greater than right */
3725 size = max (AOP_SIZE (left), AOP_SIZE (right));
3727 /* if unsigned char cmp with lit, just compare */
3729 (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
3731 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3734 emit2 ("xor a,!immedbyte", 0x80);
3735 emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
3738 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3740 else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
3742 // On the Gameboy we can't afford to adjust HL as it may trash the carry.
3743 // Pull left into DE and right into HL
3744 aopGet (AOP(left), LSB, FALSE);
3747 aopGet (AOP(right), LSB, FALSE);
3751 if (size == 0 && sign)
3753 // Highest byte when signed needs the bits flipped
3756 emit2 ("ld a,(de)");
3757 emit2 ("xor #0x80");
3759 emit2 ("ld a,(hl)");
3760 emit2 ("xor #0x80");
3764 emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
3768 emit2 ("ld a,(de)");
3769 emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
3779 spillPair (PAIR_HL);
3781 else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
3783 setupPair (PAIR_HL, AOP (left), 0);
3784 aopGet (AOP(right), LSB, FALSE);
3788 if (size == 0 && sign)
3790 // Highest byte when signed needs the bits flipped
3793 emit2 ("ld a,(hl)");
3794 emit2 ("xor #0x80");
3796 emit2 ("ld a,%d(iy)", offset);
3797 emit2 ("xor #0x80");
3801 emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
3805 emit2 ("ld a,(hl)");
3806 emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
3815 spillPair (PAIR_HL);
3816 spillPair (PAIR_IY);
3820 if (AOP_TYPE (right) == AOP_LIT)
3822 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3823 /* optimize if(x < 0) or if(x >= 0) */
3828 /* No sign so it's always false */
3833 /* Just load in the top most bit */
3834 _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
3835 if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
3837 genIfxJump (ifx, "7");
3849 /* First setup h and l contaning the top most bytes XORed */
3850 bool fDidXor = FALSE;
3851 if (AOP_TYPE (left) == AOP_LIT)
3853 unsigned long lit = (unsigned long)
3854 floatFromVal (AOP (left)->aopu.aop_lit);
3855 emit2 ("ld %s,!immedbyte", _fTmp[0],
3856 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3860 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
3861 emit2 ("xor a,!immedbyte", 0x80);
3862 emit2 ("ld %s,a", _fTmp[0]);
3865 if (AOP_TYPE (right) == AOP_LIT)
3867 unsigned long lit = (unsigned long)
3868 floatFromVal (AOP (right)->aopu.aop_lit);
3869 emit2 ("ld %s,!immedbyte", _fTmp[1],
3870 0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3874 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
3875 emit2 ("xor a,!immedbyte", 0x80);
3876 emit2 ("ld %s,a", _fTmp[1]);
3882 /* Do a long subtract */
3885 _moveA (aopGet (AOP (left), offset, FALSE));
3887 if (sign && size == 0)
3889 emit2 ("ld a,%s", _fTmp[0]);
3890 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
3894 /* Subtract through, propagating the carry */
3895 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
3903 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
3905 outBitCLong (result, swap_sense);
3909 /* if the result is used in the next
3910 ifx conditional branch then generate
3911 code a little differently */
3913 genIfxJump (ifx, swap_sense ? "nc" : "c");
3915 outBitCLong (result, swap_sense);
3916 /* leave the result in acc */
3920 /*-----------------------------------------------------------------*/
3921 /* genCmpGt :- greater than comparison */
3922 /*-----------------------------------------------------------------*/
3924 genCmpGt (iCode * ic, iCode * ifx)
3926 operand *left, *right, *result;
3927 sym_link *letype, *retype;
3930 left = IC_LEFT (ic);
3931 right = IC_RIGHT (ic);
3932 result = IC_RESULT (ic);
3934 letype = getSpec (operandType (left));
3935 retype = getSpec (operandType (right));
3936 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
3937 /* assign the amsops */
3938 aopOp (left, ic, FALSE, FALSE);
3939 aopOp (right, ic, FALSE, FALSE);
3940 aopOp (result, ic, TRUE, FALSE);
3942 genCmp (right, left, result, ifx, sign);
3944 freeAsmop (left, NULL, ic);
3945 freeAsmop (right, NULL, ic);
3946 freeAsmop (result, NULL, ic);
3949 /*-----------------------------------------------------------------*/
3950 /* genCmpLt - less than comparisons */
3951 /*-----------------------------------------------------------------*/
3953 genCmpLt (iCode * ic, iCode * ifx)
3955 operand *left, *right, *result;
3956 sym_link *letype, *retype;
3959 left = IC_LEFT (ic);
3960 right = IC_RIGHT (ic);
3961 result = IC_RESULT (ic);
3963 letype = getSpec (operandType (left));
3964 retype = getSpec (operandType (right));
3965 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
3967 /* assign the amsops */
3968 aopOp (left, ic, FALSE, FALSE);
3969 aopOp (right, ic, FALSE, FALSE);
3970 aopOp (result, ic, TRUE, FALSE);
3972 genCmp (left, right, result, ifx, sign);
3974 freeAsmop (left, NULL, ic);
3975 freeAsmop (right, NULL, ic);
3976 freeAsmop (result, NULL, ic);
3979 /*-----------------------------------------------------------------*/
3980 /* gencjneshort - compare and jump if not equal */
3981 /*-----------------------------------------------------------------*/
3983 gencjneshort (operand * left, operand * right, symbol * lbl)
3985 int size = max (AOP_SIZE (left), AOP_SIZE (right));
3987 unsigned long lit = 0L;
3989 /* Swap the left and right if it makes the computation easier */
3990 if (AOP_TYPE (left) == AOP_LIT)
3997 if (AOP_TYPE (right) == AOP_LIT)
3998 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4000 /* if the right side is a literal then anything goes */
4001 if (AOP_TYPE (right) == AOP_LIT &&
4002 AOP_TYPE (left) != AOP_DIR)
4006 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4011 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4018 emit2 ("jp nz,!tlabel", lbl->key + 100);
4024 emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4025 if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
4028 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
4029 emit2 ("jp nz,!tlabel", lbl->key + 100);
4034 /* if the right side is in a register or in direct space or
4035 if the left is a pointer register & right is not */
4036 else if (AOP_TYPE (right) == AOP_REG ||
4037 AOP_TYPE (right) == AOP_DIR ||
4038 (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
4042 _moveA (aopGet (AOP (left), offset, FALSE));
4043 if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
4044 ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4046 emit2 ("jp nz,!tlabel", lbl->key + 100);
4049 emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4050 emit2 ("jp nz,!tlabel", lbl->key + 100);
4057 /* right is a pointer reg need both a & b */
4058 /* PENDING: is this required? */
4061 _moveA (aopGet (AOP (right), offset, FALSE));
4062 emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
4063 emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
4069 /*-----------------------------------------------------------------*/
4070 /* gencjne - compare and jump if not equal */
4071 /*-----------------------------------------------------------------*/
4073 gencjne (operand * left, operand * right, symbol * lbl)
4075 symbol *tlbl = newiTempLabel (NULL);
4077 gencjneshort (left, right, lbl);
4080 emit2 ("ld a,!one");
4081 emit2 ("!shortjp !tlabel", tlbl->key + 100);
4082 emitLabel (lbl->key + 100);
4084 emitLabel (tlbl->key + 100);
4087 /*-----------------------------------------------------------------*/
4088 /* genCmpEq - generates code for equal to */
4089 /*-----------------------------------------------------------------*/
4091 genCmpEq (iCode * ic, iCode * ifx)
4093 operand *left, *right, *result;
4095 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4096 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4097 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4099 emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4101 /* Swap operands if it makes the operation easier. ie if:
4102 1. Left is a literal.
4104 if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4106 operand *t = IC_RIGHT (ic);
4107 IC_RIGHT (ic) = IC_LEFT (ic);
4111 if (ifx && !AOP_SIZE (result))
4114 /* if they are both bit variables */
4115 if (AOP_TYPE (left) == AOP_CRY &&
4116 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4118 wassertl (0, "Tried to compare two bits");
4122 tlbl = newiTempLabel (NULL);
4123 gencjneshort (left, right, tlbl);
4126 emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4127 emitLabel (tlbl->key + 100);
4131 /* PENDING: do this better */
4132 symbol *lbl = newiTempLabel (NULL);
4133 emit2 ("!shortjp !tlabel", lbl->key + 100);
4134 emitLabel (tlbl->key + 100);
4135 emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4136 emitLabel (lbl->key + 100);
4139 /* mark the icode as generated */
4144 /* if they are both bit variables */
4145 if (AOP_TYPE (left) == AOP_CRY &&
4146 ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4148 wassertl (0, "Tried to compare a bit to either a literal or another bit");
4152 gencjne (left, right, newiTempLabel (NULL));
4153 if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4159 genIfxJump (ifx, "a");
4162 /* if the result is used in an arithmetic operation
4163 then put the result in place */
4164 if (AOP_TYPE (result) != AOP_CRY)
4168 /* leave the result in acc */
4172 freeAsmop (left, NULL, ic);
4173 freeAsmop (right, NULL, ic);
4174 freeAsmop (result, NULL, ic);
4177 /*-----------------------------------------------------------------*/
4178 /* ifxForOp - returns the icode containing the ifx for operand */
4179 /*-----------------------------------------------------------------*/
4181 ifxForOp (operand * op, iCode * ic)
4183 /* if true symbol then needs to be assigned */
4184 if (IS_TRUE_SYMOP (op))
4187 /* if this has register type condition and
4188 the next instruction is ifx with the same operand
4189 and live to of the operand is upto the ifx only then */
4191 ic->next->op == IFX &&
4192 IC_COND (ic->next)->key == op->key &&
4193 OP_SYMBOL (op)->liveTo <= ic->next->seq)
4199 /*-----------------------------------------------------------------*/
4200 /* genAndOp - for && operation */
4201 /*-----------------------------------------------------------------*/
4203 genAndOp (iCode * ic)
4205 operand *left, *right, *result;
4208 /* note here that && operations that are in an if statement are
4209 taken away by backPatchLabels only those used in arthmetic
4210 operations remain */
4211 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4212 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4213 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4215 /* if both are bit variables */
4216 if (AOP_TYPE (left) == AOP_CRY &&
4217 AOP_TYPE (right) == AOP_CRY)
4219 wassertl (0, "Tried to and two bits");
4223 tlbl = newiTempLabel (NULL);
4225 emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
4227 emitLabel (tlbl->key + 100);
4231 freeAsmop (left, NULL, ic);
4232 freeAsmop (right, NULL, ic);
4233 freeAsmop (result, NULL, ic);
4236 /*-----------------------------------------------------------------*/
4237 /* genOrOp - for || operation */
4238 /*-----------------------------------------------------------------*/
4240 genOrOp (iCode * ic)
4242 operand *left, *right, *result;
4245 /* note here that || operations that are in an
4246 if statement are taken away by backPatchLabels
4247 only those used in arthmetic operations remain */
4248 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4249 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4250 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4252 /* if both are bit variables */
4253 if (AOP_TYPE (left) == AOP_CRY &&
4254 AOP_TYPE (right) == AOP_CRY)
4256 wassertl (0, "Tried to OR two bits");
4260 tlbl = newiTempLabel (NULL);
4262 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4264 emitLabel (tlbl->key + 100);
4268 freeAsmop (left, NULL, ic);
4269 freeAsmop (right, NULL, ic);
4270 freeAsmop (result, NULL, ic);
4273 /*-----------------------------------------------------------------*/
4274 /* isLiteralBit - test if lit == 2^n */
4275 /*-----------------------------------------------------------------*/
4277 isLiteralBit (unsigned long lit)
4279 unsigned long pw[32] =
4280 {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
4281 0x100L, 0x200L, 0x400L, 0x800L,
4282 0x1000L, 0x2000L, 0x4000L, 0x8000L,
4283 0x10000L, 0x20000L, 0x40000L, 0x80000L,
4284 0x100000L, 0x200000L, 0x400000L, 0x800000L,
4285 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
4286 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
4289 for (idx = 0; idx < 32; idx++)
4295 /*-----------------------------------------------------------------*/
4296 /* jmpTrueOrFalse - */
4297 /*-----------------------------------------------------------------*/
4299 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
4301 // ugly but optimized by peephole
4304 symbol *nlbl = newiTempLabel (NULL);
4305 emit2 ("jp !tlabel", nlbl->key + 100);
4306 emitLabel (tlbl->key + 100);
4307 emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
4308 emitLabel (nlbl->key + 100);
4312 emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
4313 emitLabel (tlbl->key + 100);
4318 /*-----------------------------------------------------------------*/
4319 /* genAnd - code for and */
4320 /*-----------------------------------------------------------------*/
4322 genAnd (iCode * ic, iCode * ifx)
4324 operand *left, *right, *result;
4325 int size, offset = 0;
4326 unsigned long lit = 0L;
4329 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4330 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4331 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4333 /* if left is a literal & right is not then exchange them */
4334 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4335 AOP_NEEDSACC (left))
4337 operand *tmp = right;
4342 /* if result = right then exchange them */
4343 if (sameRegs (AOP (result), AOP (right)))
4345 operand *tmp = right;
4350 /* if right is bit then exchange them */
4351 if (AOP_TYPE (right) == AOP_CRY &&
4352 AOP_TYPE (left) != AOP_CRY)
4354 operand *tmp = right;
4358 if (AOP_TYPE (right) == AOP_LIT)
4359 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4361 size = AOP_SIZE (result);
4363 if (AOP_TYPE (left) == AOP_CRY)
4365 wassertl (0, "Tried to perform an AND with a bit as an operand");
4369 // if(val & 0xZZ) - size = 0, ifx != FALSE -
4370 // bit = val & 0xZZ - size = 1, ifx = FALSE -
4371 if ((AOP_TYPE (right) == AOP_LIT) &&
4372 (AOP_TYPE (result) == AOP_CRY) &&
4373 (AOP_TYPE (left) != AOP_CRY))
4375 symbol *tlbl = newiTempLabel (NULL);
4376 int sizel = AOP_SIZE (left);
4379 /* PENDING: Test case for this. */
4384 if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
4386 _moveA (aopGet (AOP (left), offset, FALSE));
4387 if (bytelit != 0x0FFL)
4389 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4396 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4400 // bit = left & literal
4404 emit2 ("!tlabeldef", tlbl->key + 100);
4406 // if(left & literal)
4411 jmpTrueOrFalse (ifx, tlbl);
4419 /* if left is same as result */
4420 if (sameRegs (AOP (result), AOP (left)))
4422 for (; size--; offset++)
4424 if (AOP_TYPE (right) == AOP_LIT)
4426 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4431 aopPut (AOP (result), "!zero", offset);
4434 _moveA (aopGet (AOP (left), offset, FALSE));
4436 aopGet (AOP (right), offset, FALSE));
4437 aopPut (AOP (left), "a", offset);
4444 if (AOP_TYPE (left) == AOP_ACC)
4446 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
4450 _moveA (aopGet (AOP (left), offset, FALSE));
4452 aopGet (AOP (right), offset, FALSE));
4453 aopPut (AOP (left), "a", offset);
4460 // left & result in different registers
4461 if (AOP_TYPE (result) == AOP_CRY)
4463 wassertl (0, "Tried to AND where the result is in carry");
4467 for (; (size--); offset++)
4470 // result = left & right
4471 if (AOP_TYPE (right) == AOP_LIT)
4473 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4475 aopPut (AOP (result),
4476 aopGet (AOP (left), offset, FALSE),
4480 else if (bytelit == 0)
4482 aopPut (AOP (result), "!zero", offset);
4486 // faster than result <- left, anl result,right
4487 // and better if result is SFR
4488 if (AOP_TYPE (left) == AOP_ACC)
4489 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4492 _moveA (aopGet (AOP (left), offset, FALSE));
4494 aopGet (AOP (right), offset, FALSE));
4496 aopPut (AOP (result), "a", offset);
4503 freeAsmop (left, NULL, ic);
4504 freeAsmop (right, NULL, ic);
4505 freeAsmop (result, NULL, ic);
4508 /*-----------------------------------------------------------------*/
4509 /* genOr - code for or */
4510 /*-----------------------------------------------------------------*/
4512 genOr (iCode * ic, iCode * ifx)
4514 operand *left, *right, *result;
4515 int size, offset = 0;
4516 unsigned long lit = 0L;
4519 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4520 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4521 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4523 /* if left is a literal & right is not then exchange them */
4524 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4525 AOP_NEEDSACC (left))
4527 operand *tmp = right;
4532 /* if result = right then exchange them */
4533 if (sameRegs (AOP (result), AOP (right)))
4535 operand *tmp = right;
4540 /* if right is bit then exchange them */
4541 if (AOP_TYPE (right) == AOP_CRY &&
4542 AOP_TYPE (left) != AOP_CRY)
4544 operand *tmp = right;
4548 if (AOP_TYPE (right) == AOP_LIT)
4549 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4551 size = AOP_SIZE (result);
4553 if (AOP_TYPE (left) == AOP_CRY)
4555 wassertl (0, "Tried to OR where left is a bit");
4559 // if(val | 0xZZ) - size = 0, ifx != FALSE -
4560 // bit = val | 0xZZ - size = 1, ifx = FALSE -
4561 if ((AOP_TYPE (right) == AOP_LIT) &&
4562 (AOP_TYPE (result) == AOP_CRY) &&
4563 (AOP_TYPE (left) != AOP_CRY))
4565 symbol *tlbl = newiTempLabel (NULL);
4566 int sizel = AOP_SIZE (left);
4570 wassertl (0, "Result is assigned to a bit");
4572 /* PENDING: Modeled after the AND code which is inefficent. */
4575 bytelit = (lit >> (offset * 8)) & 0x0FFL;
4577 _moveA (aopGet (AOP (left), offset, FALSE));
4578 /* OR with any literal is the same as OR with itself. */
4580 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4586 jmpTrueOrFalse (ifx, tlbl);
4591 /* if left is same as result */
4592 if (sameRegs (AOP (result), AOP (left)))
4594 for (; size--; offset++)
4596 if (AOP_TYPE (right) == AOP_LIT)
4598 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4602 _moveA (aopGet (AOP (left), offset, FALSE));
4604 aopGet (AOP (right), offset, FALSE));
4605 aopPut (AOP (result), "a", offset);
4610 if (AOP_TYPE (left) == AOP_ACC)
4611 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4614 _moveA (aopGet (AOP (left), offset, FALSE));
4616 aopGet (AOP (right), offset, FALSE));
4617 aopPut (AOP (result), "a", offset);
4624 // left & result in different registers
4625 if (AOP_TYPE (result) == AOP_CRY)
4627 wassertl (0, "Result of OR is in a bit");
4630 for (; (size--); offset++)
4633 // result = left & right
4634 if (AOP_TYPE (right) == AOP_LIT)
4636 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4638 aopPut (AOP (result),
4639 aopGet (AOP (left), offset, FALSE),
4644 // faster than result <- left, anl result,right
4645 // and better if result is SFR
4646 if (AOP_TYPE (left) == AOP_ACC)
4647 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4650 _moveA (aopGet (AOP (left), offset, FALSE));
4652 aopGet (AOP (right), offset, FALSE));
4654 aopPut (AOP (result), "a", offset);
4655 /* PENDING: something weird is going on here. Add exception. */
4656 if (AOP_TYPE (result) == AOP_ACC)
4662 freeAsmop (left, NULL, ic);
4663 freeAsmop (right, NULL, ic);
4664 freeAsmop (result, NULL, ic);
4667 /*-----------------------------------------------------------------*/
4668 /* genXor - code for xclusive or */
4669 /*-----------------------------------------------------------------*/
4671 genXor (iCode * ic, iCode * ifx)
4673 operand *left, *right, *result;
4674 int size, offset = 0;
4675 unsigned long lit = 0L;
4677 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4678 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4679 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4681 /* if left is a literal & right is not then exchange them */
4682 if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4683 AOP_NEEDSACC (left))
4685 operand *tmp = right;
4690 /* if result = right then exchange them */
4691 if (sameRegs (AOP (result), AOP (right)))
4693 operand *tmp = right;
4698 /* if right is bit then exchange them */
4699 if (AOP_TYPE (right) == AOP_CRY &&
4700 AOP_TYPE (left) != AOP_CRY)
4702 operand *tmp = right;
4706 if (AOP_TYPE (right) == AOP_LIT)
4707 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4709 size = AOP_SIZE (result);
4711 if (AOP_TYPE (left) == AOP_CRY)
4713 wassertl (0, "Tried to XOR a bit");
4717 // if(val & 0xZZ) - size = 0, ifx != FALSE -
4718 // bit = val & 0xZZ - size = 1, ifx = FALSE -
4719 if ((AOP_TYPE (right) == AOP_LIT) &&
4720 (AOP_TYPE (result) == AOP_CRY) &&
4721 (AOP_TYPE (left) != AOP_CRY))
4723 symbol *tlbl = newiTempLabel (NULL);
4724 int sizel = AOP_SIZE (left);
4728 /* PENDING: Test case for this. */
4729 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
4733 _moveA (aopGet (AOP (left), offset, FALSE));
4734 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4735 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4740 jmpTrueOrFalse (ifx, tlbl);
4744 wassertl (0, "Result of XOR was destined for a bit");
4749 /* if left is same as result */
4750 if (sameRegs (AOP (result), AOP (left)))
4752 for (; size--; offset++)
4754 if (AOP_TYPE (right) == AOP_LIT)
4756 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4760 _moveA (aopGet (AOP (right), offset, FALSE));
4762 aopGet (AOP (left), offset, FALSE));
4763 aopPut (AOP (result), "a", offset);
4768 if (AOP_TYPE (left) == AOP_ACC)
4770 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4774 _moveA (aopGet (AOP (right), offset, FALSE));
4776 aopGet (AOP (left), offset, FALSE));
4777 aopPut (AOP (result), "a", 0);
4784 // left & result in different registers
4785 if (AOP_TYPE (result) == AOP_CRY)
4787 wassertl (0, "Result of XOR is in a bit");
4790 for (; (size--); offset++)
4793 // result = left & right
4794 if (AOP_TYPE (right) == AOP_LIT)
4796 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4798 aopPut (AOP (result),
4799 aopGet (AOP (left), offset, FALSE),
4804 // faster than result <- left, anl result,right
4805 // and better if result is SFR
4806 if (AOP_TYPE (left) == AOP_ACC)
4808 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4812 _moveA (aopGet (AOP (right), offset, FALSE));
4814 aopGet (AOP (left), offset, FALSE));
4816 aopPut (AOP (result), "a", offset);
4821 freeAsmop (left, NULL, ic);
4822 freeAsmop (right, NULL, ic);
4823 freeAsmop (result, NULL, ic);
4826 /*-----------------------------------------------------------------*/
4827 /* genInline - write the inline code out */
4828 /*-----------------------------------------------------------------*/
4830 genInline (iCode * ic)
4832 char *buffer, *bp, *bp1;
4834 _G.lines.isInline += (!options.asmpeep);
4836 buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
4837 strcpy (buffer, IC_INLINE (ic));
4839 /* emit each line as a code */
4864 _G.lines.isInline -= (!options.asmpeep);
4868 /*-----------------------------------------------------------------*/
4869 /* genRRC - rotate right with carry */
4870 /*-----------------------------------------------------------------*/
4877 /*-----------------------------------------------------------------*/
4878 /* genRLC - generate code for rotate left with carry */
4879 /*-----------------------------------------------------------------*/
4886 /*-----------------------------------------------------------------*/
4887 /* genGetHbit - generates code get highest order bit */
4888 /*-----------------------------------------------------------------*/
4890 genGetHbit (iCode * ic)
4892 operand *left, *result;
4893 left = IC_LEFT (ic);
4894 result = IC_RESULT (ic);
4895 aopOp (left, ic, FALSE, FALSE);
4896 aopOp (result, ic, FALSE, FALSE);
4898 /* get the highest order byte into a */
4899 emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4901 if (AOP_TYPE (result) == AOP_CRY)
4909 /* PENDING: For re-target. */
4915 freeAsmop (left, NULL, ic);
4916 freeAsmop (result, NULL, ic);
4920 emitRsh2 (asmop *aop, int size, int is_signed)
4926 const char *l = aopGet (aop, size, FALSE);
4929 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
4939 /*-----------------------------------------------------------------*/
4940 /* shiftR2Left2Result - shift right two bytes from left to result */
4941 /*-----------------------------------------------------------------*/
4943 shiftR2Left2Result (operand * left, int offl,
4944 operand * result, int offr,
4945 int shCount, int is_signed)
4948 symbol *tlbl, *tlbl1;
4950 movLeft2Result (left, offl, result, offr, 0);
4951 movLeft2Result (left, offl + 1, result, offr + 1, 0);
4953 /* if (AOP(result)->type == AOP_REG) { */
4955 tlbl = newiTempLabel (NULL);
4956 tlbl1 = newiTempLabel (NULL);
4958 /* Left is already in result - so now do the shift */
4963 emitRsh2 (AOP (result), size, is_signed);
4968 emit2 ("ld a,!immedbyte+1", shCount);
4969 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
4970 emitLabel (tlbl->key + 100);
4972 emitRsh2 (AOP (result), size, is_signed);
4974 emitLabel (tlbl1->key + 100);
4976 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4980 /*-----------------------------------------------------------------*/
4981 /* shiftL2Left2Result - shift left two bytes from left to result */
4982 /*-----------------------------------------------------------------*/
4984 shiftL2Left2Result (operand * left, int offl,
4985 operand * result, int offr, int shCount)
4987 if (sameRegs (AOP (result), AOP (left)) &&
4988 ((offl + MSB16) == offr))
4994 /* Copy left into result */
4995 movLeft2Result (left, offl, result, offr, 0);
4996 movLeft2Result (left, offl + 1, result, offr + 1, 0);
4998 /* PENDING: for now just see if it'll work. */
4999 /*if (AOP(result)->type == AOP_REG) { */
5003 symbol *tlbl, *tlbl1;
5006 tlbl = newiTempLabel (NULL);
5007 tlbl1 = newiTempLabel (NULL);
5009 /* Left is already in result - so now do the shift */
5012 emit2 ("ld a,!immedbyte+1", shCount);
5013 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5014 emitLabel (tlbl->key + 100);
5019 l = aopGet (AOP (result), offset, FALSE);
5023 emit2 ("sla %s", l);
5034 emitLabel (tlbl1->key + 100);
5036 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5041 /*-----------------------------------------------------------------*/
5042 /* AccRol - rotate left accumulator by known count */
5043 /*-----------------------------------------------------------------*/
5045 AccRol (int shCount)
5047 shCount &= 0x0007; // shCount : 0..7
5086 /*-----------------------------------------------------------------*/
5087 /* AccLsh - left shift accumulator by known count */
5088 /*-----------------------------------------------------------------*/
5090 AccLsh (int shCount)
5092 static const unsigned char SLMask[] =
5094 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5103 else if (shCount == 2)
5110 /* rotate left accumulator */
5112 /* and kill the lower order bits */
5113 emit2 ("and a,!immedbyte", SLMask[shCount]);
5118 /*-----------------------------------------------------------------*/
5119 /* shiftL1Left2Result - shift left one byte from left to result */
5120 /*-----------------------------------------------------------------*/
5122 shiftL1Left2Result (operand * left, int offl,
5123 operand * result, int offr, int shCount)
5126 l = aopGet (AOP (left), offl, FALSE);
5128 /* shift left accumulator */
5130 aopPut (AOP (result), "a", offr);
5134 /*-----------------------------------------------------------------*/
5135 /* genlshTwo - left shift two bytes by known amount != 0 */
5136 /*-----------------------------------------------------------------*/
5138 genlshTwo (operand * result, operand * left, int shCount)
5140 int size = AOP_SIZE (result);
5142 wassert (size == 2);
5144 /* if shCount >= 8 */
5152 movLeft2Result (left, LSB, result, MSB16, 0);
5153 aopPut (AOP (result), "!zero", 0);
5154 shiftL1Left2Result (left, LSB, result, MSB16, shCount);
5158 movLeft2Result (left, LSB, result, MSB16, 0);
5159 aopPut (AOP (result), "!zero", 0);
5164 aopPut (AOP (result), "!zero", LSB);
5167 /* 1 <= shCount <= 7 */
5176 shiftL2Left2Result (left, LSB, result, LSB, shCount);
5181 /*-----------------------------------------------------------------*/
5182 /* genlshOne - left shift a one byte quantity by known count */
5183 /*-----------------------------------------------------------------*/
5185 genlshOne (operand * result, operand * left, int shCount)
5187 shiftL1Left2Result (left, LSB, result, LSB, shCount);
5190 /*-----------------------------------------------------------------*/
5191 /* genLeftShiftLiteral - left shifting by known count */
5192 /*-----------------------------------------------------------------*/
5194 genLeftShiftLiteral (operand * left,
5199 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5202 freeAsmop (right, NULL, ic);
5204 aopOp (left, ic, FALSE, FALSE);
5205 aopOp (result, ic, FALSE, FALSE);
5207 size = getSize (operandType (result));
5209 /* I suppose that the left size >= result size */
5215 else if (shCount >= (size * 8))
5219 aopPut (AOP (result), "!zero", size);
5227 genlshOne (result, left, shCount);
5230 genlshTwo (result, left, shCount);
5233 wassertl (0, "Shifting of longs is currently unsupported");
5239 freeAsmop (left, NULL, ic);
5240 freeAsmop (result, NULL, ic);
5243 /*-----------------------------------------------------------------*/
5244 /* genLeftShift - generates code for left shifting */
5245 /*-----------------------------------------------------------------*/
5247 genLeftShift (iCode * ic)
5251 symbol *tlbl, *tlbl1;
5252 operand *left, *right, *result;
5254 right = IC_RIGHT (ic);
5255 left = IC_LEFT (ic);
5256 result = IC_RESULT (ic);
5258 aopOp (right, ic, FALSE, FALSE);
5260 /* if the shift count is known then do it
5261 as efficiently as possible */
5262 if (AOP_TYPE (right) == AOP_LIT)
5264 genLeftShiftLiteral (left, right, result, ic);
5268 /* shift count is unknown then we have to form a loop get the loop
5269 count in B : Note: we take only the lower order byte since
5270 shifting more that 32 bits make no sense anyway, ( the largest
5271 size of an object can be only 32 bits ) */
5272 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5274 freeAsmop (right, NULL, ic);
5275 aopOp (left, ic, FALSE, FALSE);
5276 aopOp (result, ic, FALSE, FALSE);
5278 /* now move the left to the result if they are not the
5281 if (!sameRegs (AOP (left), AOP (result)))
5284 size = AOP_SIZE (result);
5288 l = aopGet (AOP (left), offset, FALSE);
5289 aopPut (AOP (result), l, offset);
5294 tlbl = newiTempLabel (NULL);
5295 size = AOP_SIZE (result);
5297 tlbl1 = newiTempLabel (NULL);
5299 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5300 emitLabel (tlbl->key + 100);
5301 l = aopGet (AOP (result), offset, FALSE);
5305 l = aopGet (AOP (result), offset, FALSE);
5309 emit2 ("sla %s", l);
5317 emitLabel (tlbl1->key + 100);
5319 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5321 freeAsmop (left, NULL, ic);
5322 freeAsmop (result, NULL, ic);
5325 /*-----------------------------------------------------------------*/
5326 /* genrshOne - left shift two bytes by known amount != 0 */
5327 /*-----------------------------------------------------------------*/
5329 genrshOne (operand * result, operand * left, int shCount, int is_signed)
5332 int size = AOP_SIZE (result);
5335 wassert (size == 1);
5336 wassert (shCount < 8);
5338 l = aopGet (AOP (left), 0, FALSE);
5340 if (AOP (result)->type == AOP_REG)
5342 aopPut (AOP (result), l, 0);
5343 l = aopGet (AOP (result), 0, FALSE);
5346 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5354 emit2 ("%s a", is_signed ? "sra" : "srl");
5356 aopPut (AOP (result), "a", 0);
5360 /*-----------------------------------------------------------------*/
5361 /* AccRsh - right shift accumulator by known count */
5362 /*-----------------------------------------------------------------*/
5364 AccRsh (int shCount)
5366 static const unsigned char SRMask[] =
5368 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
5373 /* rotate right accumulator */
5374 AccRol (8 - shCount);
5375 /* and kill the higher order bits */
5376 emit2 ("and a,!immedbyte", SRMask[shCount]);
5380 /*-----------------------------------------------------------------*/
5381 /* shiftR1Left2Result - shift right one byte from left to result */
5382 /*-----------------------------------------------------------------*/
5384 shiftR1Left2Result (operand * left, int offl,
5385 operand * result, int offr,
5386 int shCount, int sign)
5388 _moveA (aopGet (AOP (left), offl, FALSE));
5393 emit2 ("%s a", sign ? "sra" : "srl");
5400 aopPut (AOP (result), "a", offr);
5403 /*-----------------------------------------------------------------*/
5404 /* genrshTwo - right shift two bytes by known amount != 0 */
5405 /*-----------------------------------------------------------------*/
5407 genrshTwo (operand * result, operand * left,
5408 int shCount, int sign)
5410 /* if shCount >= 8 */
5416 shiftR1Left2Result (left, MSB16, result, LSB,
5421 movLeft2Result (left, MSB16, result, LSB, sign);
5425 /* Sign extend the result */
5426 _moveA(aopGet (AOP (result), 0, FALSE));
5430 aopPut (AOP (result), ACC_NAME, MSB16);
5434 aopPut (AOP (result), "!zero", 1);
5437 /* 1 <= shCount <= 7 */
5440 shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
5444 /*-----------------------------------------------------------------*/
5445 /* genRightShiftLiteral - left shifting by known count */
5446 /*-----------------------------------------------------------------*/
5448 genRightShiftLiteral (operand * left,
5454 int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5457 freeAsmop (right, NULL, ic);
5459 aopOp (left, ic, FALSE, FALSE);
5460 aopOp (result, ic, FALSE, FALSE);
5462 size = getSize (operandType (result));
5464 /* I suppose that the left size >= result size */
5470 else if (shCount >= (size * 8))
5472 aopPut (AOP (result), "!zero", size);
5478 genrshOne (result, left, shCount, sign);
5481 genrshTwo (result, left, shCount, sign);
5484 wassertl (0, "Asked to shift right a long which should be a function call");
5487 wassertl (0, "Entered default case in right shift delegate");
5490 freeAsmop (left, NULL, ic);
5491 freeAsmop (result, NULL, ic);
5494 /*-----------------------------------------------------------------*/
5495 /* genRightShift - generate code for right shifting */
5496 /*-----------------------------------------------------------------*/
5498 genRightShift (iCode * ic)
5500 operand *right, *left, *result;
5502 int size, offset, first = 1;
5506 symbol *tlbl, *tlbl1;
5508 /* if signed then we do it the hard way preserve the
5509 sign bit moving it inwards */
5510 retype = getSpec (operandType (IC_RESULT (ic)));
5512 is_signed = !SPEC_USIGN (retype);
5514 /* signed & unsigned types are treated the same : i.e. the
5515 signed is NOT propagated inwards : quoting from the
5516 ANSI - standard : "for E1 >> E2, is equivalent to division
5517 by 2**E2 if unsigned or if it has a non-negative value,
5518 otherwise the result is implementation defined ", MY definition
5519 is that the sign does not get propagated */
5521 right = IC_RIGHT (ic);
5522 left = IC_LEFT (ic);
5523 result = IC_RESULT (ic);
5525 aopOp (right, ic, FALSE, FALSE);
5527 /* if the shift count is known then do it
5528 as efficiently as possible */
5529 if (AOP_TYPE (right) == AOP_LIT)
5531 genRightShiftLiteral (left, right, result, ic, is_signed);
5535 aopOp (left, ic, FALSE, FALSE);
5536 aopOp (result, ic, FALSE, FALSE);
5538 /* now move the left to the result if they are not the
5540 if (!sameRegs (AOP (left), AOP (result)) &&
5541 AOP_SIZE (result) > 1)
5544 size = AOP_SIZE (result);
5548 l = aopGet (AOP (left), offset, FALSE);
5549 aopPut (AOP (result), l, offset);
5554 emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5556 freeAsmop (right, NULL, ic);
5558 tlbl = newiTempLabel (NULL);
5559 tlbl1 = newiTempLabel (NULL);
5560 size = AOP_SIZE (result);
5563 emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5564 emitLabel (tlbl->key + 100);
5567 l = aopGet (AOP (result), offset--, FALSE);
5570 emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5578 emitLabel (tlbl1->key + 100);
5580 emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5582 freeAsmop (left, NULL, ic);
5583 freeAsmop (result, NULL, ic);
5586 /*-----------------------------------------------------------------*/
5587 /* genGenPointerGet - get value from generic pointer space */
5588 /*-----------------------------------------------------------------*/
5590 genGenPointerGet (operand * left,
5591 operand * result, iCode * ic)
5594 sym_link *retype = getSpec (operandType (result));
5600 aopOp (left, ic, FALSE, FALSE);
5601 aopOp (result, ic, FALSE, FALSE);
5603 if (isPair (AOP (left)) && AOP_SIZE (result) == 1)
5606 if (isPtrPair (AOP (left)))
5608 tsprintf (buffer, "!*pair", getPairName (AOP (left)));
5609 aopPut (AOP (result), buffer, 0);
5613 emit2 ("ld a,!*pair", getPairName (AOP (left)));
5614 aopPut (AOP (result), "a", 0);
5616 freeAsmop (left, NULL, ic);
5620 /* For now we always load into IY */
5621 /* if this is remateriazable */
5622 fetchPair (pair, AOP (left));
5624 /* so iy now contains the address */
5625 freeAsmop (left, NULL, ic);
5627 /* if bit then unpack */
5628 if (IS_BITVAR (retype))
5634 size = AOP_SIZE (result);
5639 /* PENDING: make this better */
5640 if (!IS_GB && AOP (result)->type == AOP_REG)
5642 aopPut (AOP (result), "!*hl", offset++);
5646 emit2 ("ld a,!*pair", _pairs[pair].name);
5647 aopPut (AOP (result), "a", offset++);
5651 emit2 ("inc %s", _pairs[pair].name);
5652 _G.pairs[pair].offset++;
5658 freeAsmop (result, NULL, ic);
5661 /*-----------------------------------------------------------------*/
5662 /* genPointerGet - generate code for pointer get */
5663 /*-----------------------------------------------------------------*/
5665 genPointerGet (iCode * ic)
5667 operand *left, *result;
5668 sym_link *type, *etype;
5670 left = IC_LEFT (ic);
5671 result = IC_RESULT (ic);
5673 /* depending on the type of pointer we need to
5674 move it to the correct pointer register */
5675 type = operandType (left);
5676 etype = getSpec (type);
5678 genGenPointerGet (left, result, ic);
5682 isRegOrLit (asmop * aop)
5684 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
5689 /*-----------------------------------------------------------------*/
5690 /* genGenPointerSet - stores the value into a pointer location */
5691 /*-----------------------------------------------------------------*/
5693 genGenPointerSet (operand * right,
5694 operand * result, iCode * ic)
5697 sym_link *retype = getSpec (operandType (right));
5698 PAIR_ID pairId = PAIR_HL;
5700 aopOp (result, ic, FALSE, FALSE);
5701 aopOp (right, ic, FALSE, FALSE);
5706 /* Handle the exceptions first */
5707 if (isPair (AOP (result)) && (AOP_SIZE (right) == 1))
5710 const char *l = aopGet (AOP (right), 0, FALSE);
5711 const char *pair = getPairName (AOP (result));
5712 if (canAssignToPtr (l) && isPtr (pair))
5714 emit2 ("ld !*pair,%s", pair, l);
5719 emit2 ("ld !*pair,a", pair);
5724 /* if the operand is already in dptr
5725 then we do nothing else we move the value to dptr */
5726 if (AOP_TYPE (result) != AOP_STR)
5728 fetchPair (pairId, AOP (result));
5730 /* so hl know contains the address */
5731 freeAsmop (result, NULL, ic);
5733 /* if bit then unpack */
5734 if (IS_BITVAR (retype))
5740 size = AOP_SIZE (right);
5745 const char *l = aopGet (AOP (right), offset, FALSE);
5746 if (isRegOrLit (AOP (right)) && !IS_GB)
5748 emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
5753 emit2 ("ld !*pair,a", _pairs[pairId].name);
5757 emit2 ("inc %s", _pairs[pairId].name);
5758 _G.pairs[pairId].offset++;
5764 freeAsmop (right, NULL, ic);
5767 /*-----------------------------------------------------------------*/
5768 /* genPointerSet - stores the value into a pointer location */
5769 /*-----------------------------------------------------------------*/
5771 genPointerSet (iCode * ic)
5773 operand *right, *result;
5774 sym_link *type, *etype;
5776 right = IC_RIGHT (ic);
5777 result = IC_RESULT (ic);
5779 /* depending on the type of pointer we need to
5780 move it to the correct pointer register */
5781 type = operandType (result);
5782 etype = getSpec (type);
5784 genGenPointerSet (right, result, ic);
5787 /*-----------------------------------------------------------------*/
5788 /* genIfx - generate code for Ifx statement */
5789 /*-----------------------------------------------------------------*/
5791 genIfx (iCode * ic, iCode * popIc)
5793 operand *cond = IC_COND (ic);
5796 aopOp (cond, ic, FALSE, TRUE);
5798 /* get the value into acc */
5799 if (AOP_TYPE (cond) != AOP_CRY)
5803 /* the result is now in the accumulator */
5804 freeAsmop (cond, NULL, ic);
5806 /* if there was something to be popped then do it */
5810 /* if the condition is a bit variable */
5811 if (isbit && IS_ITEMP (cond) &&
5813 genIfxJump (ic, SPIL_LOC (cond)->rname);
5814 else if (isbit && !IS_ITEMP (cond))
5815 genIfxJump (ic, OP_SYMBOL (cond)->rname);
5817 genIfxJump (ic, "a");
5822 /*-----------------------------------------------------------------*/
5823 /* genAddrOf - generates code for address of */
5824 /*-----------------------------------------------------------------*/
5826 genAddrOf (iCode * ic)
5828 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
5830 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
5832 /* if the operand is on the stack then we
5833 need to get the stack offset of this
5840 if (sym->stack <= 0)
5842 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
5846 setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
5848 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
5852 emit2 ("ld de,!hashedstr", sym->rname);
5853 commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
5861 /* if it has an offset then we need to compute it */
5863 emit2 ("ld hl,#%d+%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset, _G.stack.param_offset);
5865 emit2 ("ld hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
5866 emit2 ("add hl,sp");
5870 emit2 ("ld hl,#%s", sym->rname);
5872 commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
5874 freeAsmop (IC_RESULT (ic), NULL, ic);
5877 /*-----------------------------------------------------------------*/
5878 /* genAssign - generate code for assignment */
5879 /*-----------------------------------------------------------------*/
5881 genAssign (iCode * ic)
5883 operand *result, *right;
5885 unsigned long lit = 0L;
5887 result = IC_RESULT (ic);
5888 right = IC_RIGHT (ic);
5890 /* Dont bother assigning if they are the same */
5891 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
5893 emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
5897 aopOp (right, ic, FALSE, FALSE);
5898 aopOp (result, ic, TRUE, FALSE);
5900 /* if they are the same registers */
5901 if (sameRegs (AOP (right), AOP (result)))
5903 emitDebug ("; (registers are the same)");
5907 /* if the result is a bit */
5908 if (AOP_TYPE (result) == AOP_CRY)
5910 wassertl (0, "Tried to assign to a bit");
5914 size = AOP_SIZE (result);
5917 if (AOP_TYPE (right) == AOP_LIT)
5918 lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5919 if (isPair (AOP (result)))
5921 fetchPair (getPairId (AOP (result)), AOP (right));
5923 else if ((size > 1) &&
5924 (AOP_TYPE (result) != AOP_REG) &&
5925 (AOP_TYPE (right) == AOP_LIT) &&
5926 !IS_FLOAT (operandType (right)) &&
5929 bool fXored = FALSE;
5931 /* Work from the top down.
5932 Done this way so that we can use the cached copy of 0
5933 in A for a fast clear */
5936 if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
5938 if (!fXored && size > 1)
5945 aopPut (AOP (result), "a", offset);
5949 aopPut (AOP (result), "!zero", offset);
5953 aopPut (AOP (result),
5954 aopGet (AOP (right), offset, FALSE),
5959 else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
5961 /* Special case. Load into a and d, then load out. */
5962 _moveA (aopGet (AOP (right), 0, FALSE));
5963 emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
5964 aopPut (AOP (result), "a", 0);
5965 aopPut (AOP (result), "e", 1);
5967 else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
5969 /* Special case - simple memcpy */
5970 aopGet (AOP (right), LSB, FALSE);
5973 aopGet (AOP (result), LSB, FALSE);
5977 emit2 ("ld a,(de)");
5978 /* Peephole will optimise this. */
5979 emit2 ("ld (hl),a");
5987 spillPair (PAIR_HL);
5993 /* PENDING: do this check better */
5994 if (requiresHL (AOP (right)) && requiresHL (AOP (result)))
5996 _moveA (aopGet (AOP (right), offset, FALSE));
5997 aopPut (AOP (result), "a", offset);
6000 aopPut (AOP (result),
6001 aopGet (AOP (right), offset, FALSE),
6008 freeAsmop (right, NULL, ic);
6009 freeAsmop (result, NULL, ic);
6012 /*-----------------------------------------------------------------*/
6013 /* genJumpTab - genrates code for jump table */
6014 /*-----------------------------------------------------------------*/
6016 genJumpTab (iCode * ic)
6021 aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
6022 /* get the condition into accumulator */
6023 l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
6026 emit2 ("ld e,%s", l);
6027 emit2 ("ld d,!zero");
6028 jtab = newiTempLabel (NULL);
6030 emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
6031 emit2 ("add hl,de");
6032 emit2 ("add hl,de");
6033 emit2 ("add hl,de");
6034 freeAsmop (IC_JTCOND (ic), NULL, ic);
6038 emitLabel (jtab->key + 100);
6039 /* now generate the jump labels */
6040 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
6041 jtab = setNextItem (IC_JTLABELS (ic)))
6042 emit2 ("jp !tlabel", jtab->key + 100);
6045 /*-----------------------------------------------------------------*/
6046 /* genCast - gen code for casting */
6047 /*-----------------------------------------------------------------*/
6049 genCast (iCode * ic)
6051 operand *result = IC_RESULT (ic);
6052 sym_link *ctype = operandType (IC_LEFT (ic));
6053 operand *right = IC_RIGHT (ic);
6056 /* if they are equivalent then do nothing */
6057 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6060 aopOp (right, ic, FALSE, FALSE);
6061 aopOp (result, ic, FALSE, FALSE);
6063 /* if the result is a bit */
6064 if (AOP_TYPE (result) == AOP_CRY)
6066 wassertl (0, "Tried to cast to a bit");
6069 /* if they are the same size : or less */
6070 if (AOP_SIZE (result) <= AOP_SIZE (right))
6073 /* if they are in the same place */
6074 if (sameRegs (AOP (right), AOP (result)))
6077 /* if they in different places then copy */
6078 size = AOP_SIZE (result);
6082 aopPut (AOP (result),
6083 aopGet (AOP (right), offset, FALSE),
6090 /* So we now know that the size of destination is greater
6091 than the size of the source */
6092 /* we move to result for the size of source */
6093 size = AOP_SIZE (right);
6097 aopPut (AOP (result),
6098 aopGet (AOP (right), offset, FALSE),
6103 /* now depending on the sign of the destination */
6104 size = AOP_SIZE (result) - AOP_SIZE (right);
6105 /* Unsigned or not an integral type - right fill with zeros */
6106 if (SPEC_USIGN (ctype) || !IS_SPEC (ctype))
6109 aopPut (AOP (result), "!zero", offset++);
6113 /* we need to extend the sign :{ */
6114 const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
6120 aopPut (AOP (result), "a", offset++);
6124 freeAsmop (right, NULL, ic);
6125 freeAsmop (result, NULL, ic);
6128 /*-----------------------------------------------------------------*/
6129 /* genReceive - generate code for a receive iCode */
6130 /*-----------------------------------------------------------------*/
6132 genReceive (iCode * ic)
6134 if (isOperandInFarSpace (IC_RESULT (ic)) &&
6135 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
6136 IS_TRUE_SYMOP (IC_RESULT (ic))))
6146 aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6147 size = AOP_SIZE(IC_RESULT(ic));
6149 for (i = 0; i < size; i++) {
6150 aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
6154 freeAsmop (IC_RESULT (ic), NULL, ic);
6159 /** Maximum number of bytes to emit per line. */
6163 /** Context for the byte output chunker. */
6166 unsigned char buffer[DBEMIT_MAX_RUN];
6171 /** Flushes a byte chunker by writing out all in the buffer and
6175 _dbFlush(DBEMITCTX *self)
6182 sprintf(line, ".db 0x%02X", self->buffer[0]);
6184 for (i = 1; i < self->pos; i++)
6186 sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
6193 /** Write out another byte, buffering until a decent line is
6197 _dbEmit(DBEMITCTX *self, int c)
6199 if (self->pos == DBEMIT_MAX_RUN)
6203 self->buffer[self->pos++] = c;
6206 /** Context for a simple run length encoder. */
6210 unsigned char buffer[128];
6212 /** runLen may be equivalent to pos. */
6218 RLE_CHANGE_COST = 4,
6222 /** Flush the buffer of a run length encoder by writing out the run or
6223 data that it currently contains.
6226 _rleCommit(RLECTX *self)
6232 memset(&db, 0, sizeof(db));
6234 emit2(".db %u", self->pos);
6236 for (i = 0; i < self->pos; i++)
6238 _dbEmit(&db, self->buffer[i]);
6247 Can get either a run or a block of random stuff.
6248 Only want to change state if a good run comes in or a run ends.
6249 Detecting run end is easy.
6252 Say initial state is in run, len zero, last zero. Then if you get a
6253 few zeros then something else then a short run will be output.
6254 Seems OK. While in run mode, keep counting. While in random mode,
6255 keep a count of the run. If run hits margin, output all up to run,
6256 restart, enter run mode.
6259 /** Add another byte into the run length encoder, flushing as
6260 required. The run length encoder uses the Amiga IFF style, where
6261 a block is prefixed by its run length. A positive length means
6262 the next n bytes pass straight through. A negative length means
6263 that the next byte is repeated -n times. A zero terminates the
6267 _rleAppend(RLECTX *self, int c)
6271 if (c != self->last)
6273 /* The run has stopped. See if it is worthwhile writing it out
6274 as a run. Note that the random data comes in as runs of
6277 if (self->runLen > RLE_CHANGE_COST)
6279 /* Yes, worthwhile. */
6280 /* Commit whatever was in the buffer. */
6282 emit2(".db -%u,0x%02X", self->runLen, self->last);
6286 /* Not worthwhile. Append to the end of the random list. */
6287 for (i = 0; i < self->runLen; i++)
6289 if (self->pos >= RLE_MAX_BLOCK)
6294 self->buffer[self->pos++] = self->last;
6302 if (self->runLen >= RLE_MAX_BLOCK)
6304 /* Commit whatever was in the buffer. */
6307 emit2 (".db -%u,0x%02X", self->runLen, self->last);
6315 _rleFlush(RLECTX *self)
6317 _rleAppend(self, -1);
6324 /** genArrayInit - Special code for initialising an array with constant
6328 genArrayInit (iCode * ic)
6332 int elementSize = 0, eIndex, i;
6333 unsigned val, lastVal;
6337 memset(&rle, 0, sizeof(rle));
6339 aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
6341 _saveRegsForCall(ic, 0);
6343 fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
6344 emit2 ("call __initrleblock");
6346 type = operandType(IC_LEFT(ic));
6348 if (type && type->next)
6350 elementSize = getSize(type->next);
6354 wassertl (0, "Can't determine element size in genArrayInit.");
6357 iLoop = IC_ARRAYILIST(ic);
6358 lastVal = (unsigned)-1;
6360 /* Feed all the bytes into the run length encoder which will handle
6362 This works well for mixed char data, and for random int and long
6371 for (i = 0; i < ix; i++)
6373 for (eIndex = 0; eIndex < elementSize; eIndex++)
6375 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
6376 _rleAppend(&rle, val);
6381 iLoop = iLoop->next;
6385 /* Mark the end of the run. */
6388 _restoreRegsAfterCall();
6392 freeAsmop (IC_LEFT(ic), NULL, ic);
6395 /*-----------------------------------------------------------------*/
6396 /* genZ80Code - generate code for Z80 based controllers */
6397 /*-----------------------------------------------------------------*/
6399 genZ80Code (iCode * lic)
6407 _fReturn = _gbz80_return;
6408 _fTmp = _gbz80_return;
6412 _fReturn = _z80_return;
6413 _fTmp = _z80_return;
6416 _G.lines.head = _G.lines.current = NULL;
6418 for (ic = lic; ic; ic = ic->next)
6421 if (cln != ic->lineno)
6423 emit2 ("; %s %d", ic->filename, ic->lineno);
6426 /* if the result is marked as
6427 spilt and rematerializable or code for
6428 this has already been generated then
6430 if (resultRemat (ic) || ic->generated)
6433 /* depending on the operation */
6437 emitDebug ("; genNot");
6442 emitDebug ("; genCpl");
6447 emitDebug ("; genUminus");
6452 emitDebug ("; genIpush");
6457 /* IPOP happens only when trying to restore a
6458 spilt live range, if there is an ifx statement
6459 following this pop then the if statement might
6460 be using some of the registers being popped which
6461 would destory the contents of the register so
6462 we need to check for this condition and handle it */
6464 ic->next->op == IFX &&
6465 regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
6467 emitDebug ("; genIfx");
6468 genIfx (ic->next, ic);
6472 emitDebug ("; genIpop");
6478 emitDebug ("; genCall");
6483 emitDebug ("; genPcall");
6488 emitDebug ("; genFunction");
6493 emitDebug ("; genEndFunction");
6494 genEndFunction (ic);
6498 emitDebug ("; genRet");
6503 emitDebug ("; genLabel");
6508 emitDebug ("; genGoto");
6513 emitDebug ("; genPlus");
6518 emitDebug ("; genMinus");
6523 emitDebug ("; genMult");
6528 emitDebug ("; genDiv");
6533 emitDebug ("; genMod");
6538 emitDebug ("; genCmpGt");
6539 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
6543 emitDebug ("; genCmpLt");
6544 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
6551 /* note these two are xlated by algebraic equivalence
6552 during parsing SDCC.y */
6553 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
6554 "got '>=' or '<=' shouldn't have come here");
6558 emitDebug ("; genCmpEq");
6559 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
6563 emitDebug ("; genAndOp");
6568 emitDebug ("; genOrOp");
6573 emitDebug ("; genXor");
6574 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
6578 emitDebug ("; genOr");
6579 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
6583 emitDebug ("; genAnd");
6584 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
6588 emitDebug ("; genInline");
6593 emitDebug ("; genRRC");
6598 emitDebug ("; genRLC");
6603 emitDebug ("; genGetHBIT");
6608 emitDebug ("; genLeftShift");
6613 emitDebug ("; genRightShift");
6617 case GET_VALUE_AT_ADDRESS:
6618 emitDebug ("; genPointerGet");
6624 if (POINTER_SET (ic))
6626 emitDebug ("; genAssign (pointer)");
6631 emitDebug ("; genAssign");
6637 emitDebug ("; genIfx");
6642 emitDebug ("; genAddrOf");
6647 emitDebug ("; genJumpTab");
6652 emitDebug ("; genCast");
6657 emitDebug ("; genReceive");
6662 emitDebug ("; addSet");
6663 addSet (&_G.sendSet, ic);
6667 emitDebug ("; genArrayInit");
6677 /* now we are ready to call the
6678 peep hole optimizer */
6679 if (!options.nopeep)
6680 peepHole (&_G.lines.head);
6682 /* This is unfortunate */
6683 /* now do the actual printing */
6685 FILE *fp = codeOutFile;
6686 if (isInHome () && codeOutFile == code->oFile)
6687 codeOutFile = home->oFile;
6688 printLine (_G.lines.head, codeOutFile);
6689 if (_G.flushStatics)
6692 _G.flushStatics = 0;
6697 freeTrace(&_G.lines.trace);
6698 freeTrace(&_G.trace.aops);
6704 _isPairUsed (iCode * ic, PAIR_ID pairId)
6710 if (bitVectBitValue (ic->rMask, D_IDX))
6712 if (bitVectBitValue (ic->rMask, E_IDX))
6722 fetchLitSpecial (asmop * aop, bool negate, bool xor)
6725 value *val = aop->aopu.aop_lit;
6727 wassert (aop->type == AOP_LIT);
6728 wassert (!IS_FLOAT (val->type));
6730 v = (unsigned long) floatFromVal (val);
6738 tsprintf (buffer, "!immedword", v);
6739 return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));